]> andersk Git - moira.git/blame - gen/mailhub.pc
eliminate use of the `register' keyword: let the compiler decide
[moira.git] / gen / mailhub.pc
CommitLineData
bac4ceaa 1
2/* $Header$
3 *
4 * This generates the /usr/lib/aliases file for the mailhub.
5 *
6 * (c) Copyright 1988, 1990 by the Massachusetts Institute of Technology.
7 * For copying and distribution information, please see the file
8 * <mit-copyright.h>.
9 */
10
11#include <mit-copyright.h>
12#include <stdio.h>
5eaef520 13#include <stdlib.h>
bac4ceaa 14#include <string.h>
15#include <ctype.h>
5eaef520 16#include <errno.h>
bac4ceaa 17#include <moira.h>
18#include <moira_site.h>
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <sys/time.h>
22EXEC SQL INCLUDE sqlca;
23
bac4ceaa 24char *whoami = "mailhub.gen";
9c04b191 25char *db = "moira/moira";
bac4ceaa 26char *perm_malloc();
27char *pstrsave();
28char *divide = "##############################################################";
29
30#define ML_WID 72
9e1513ae 31#define AL_MAX_WID 592
bac4ceaa 32
33#define FALSE 0
34#define TRUE (!FALSE)
35
5eaef520 36FILE *out = stdout;
bac4ceaa 37
5eaef520 38int main(int argc, char **argv)
bac4ceaa 39{
5eaef520 40 long tm = time(NULL);
41 char filename[64], *targetfile;
42 struct stat sb;
43 EXEC SQL BEGIN DECLARE SECTION;
44 int flag;
45 EXEC SQL END DECLARE SECTION;
46
47 EXEC SQL CONNECT :db;
48
49 if (argc == 2)
50 {
51 if (stat(argv[1], &sb) == 0)
52 {
53 if (ModDiff (&flag, "users", sb.st_mtime))
54 exit(MR_DATE);
55 if (flag < 0)
56 {
57 fprintf(stderr, "File %s does not need to be rebuilt.\n",
58 argv[1]);
59 exit(MR_NO_CHANGE);
bac4ceaa 60 }
61 }
5eaef520 62 targetfile = argv[1];
63 sprintf(filename, "%s~", targetfile);
64 if (!(out = fopen(filename, "w")))
65 {
66 fprintf(stderr, "unable to open %s for output\n", filename);
67 exit(MR_OCONFIG);
bac4ceaa 68 }
5eaef520 69 }
70 else if (argc != 1)
71 {
72 fprintf(stderr, "usage: %s [outfile]\n", argv[0]);
73 exit(MR_ARGS);
bac4ceaa 74 }
75
5eaef520 76 fprintf(out, "%s\n# Aliases File Extract of %s", divide, ctime(&tm));
77 fprintf(out, "# This file is automatically generated, "
78 "do not edit it directly.\n%s\n\n", divide);
bac4ceaa 79
5eaef520 80 get_info();
bac4ceaa 81
5eaef520 82 EXEC SQL COMMIT;
bac4ceaa 83
5eaef520 84 fprintf(stderr, "Sorting Info\n");
85 sort_info();
bac4ceaa 86
5eaef520 87 fprintf(stderr, "Dumping information\n");
88 do_people();
bac4ceaa 89
5eaef520 90 fprintf(out, "\n%s\n# End of aliases file\n", divide);
bac4ceaa 91
5eaef520 92 if (fclose(out))
93 {
94 perror("close failed");
95 exit(MR_CCONFIG);
bac4ceaa 96 }
97
5eaef520 98 if (argc == 2)
99 fix_file(targetfile);
100 exit(MR_SUCCESS);
bac4ceaa 101}
102
103
104
105struct hash *users, *machines, *strings, *lists, *names;
106struct user {
5eaef520 107 char *login;
108 char *first;
109 char *last;
110 char mi;
111 char *pobox;
bac4ceaa 112};
113struct member {
5eaef520 114 struct member *next;
115 char *name;
116 int list_id;
bac4ceaa 117};
118struct list {
5eaef520 119 char *name;
120 char maillist;
121 char *description;
122 char acl_t;
123 int acl_id;
124 struct member *m;
bac4ceaa 125};
126struct names {
5eaef520 127 char *name;
128 struct names *next;
129 int keep;
130 int id;
bac4ceaa 131};
132
133
5eaef520 134get_info(void)
bac4ceaa 135{
5eaef520 136 EXEC SQL BEGIN DECLARE SECTION;
137 int id, pid, bid, cnt, maillistp, acl, mid;
138 char name[129], type[9], fname[17], mname[17], lname[17], buf[257];
139 EXEC SQL END DECLARE SECTION;
140 char *s;
44d12d58 141 struct user *u;
5eaef520 142 struct list *l, *memberlist;
44d12d58 143 struct member *m;
5eaef520 144
145 /* The following is declarative, not executed,
146 * and so is dependent on where it is in the file,
147 * not in the order of execution of statements.
148 */
149 EXEC SQL WHENEVER SQLERROR GOTO sqlerr;
150
151 cnt = 0;
152 machines = create_hash(1000);
153
154 EXEC SQL DECLARE m_cursor CURSOR FOR
155 SELECT mach_id, name
156 FROM machine
157 WHERE status = 1
158 ORDER BY mach_id;
159 EXEC SQL OPEN m_cursor;
160 while (1)
161 {
162 EXEC SQL FETCH m_cursor INTO :id, :name;
163 if (sqlca.sqlcode)
164 break;
165 if (s = strchr(name, '.'))
166 *s = '\0';
167 else
168 strtrim(name);
bac4ceaa 169#ifdef ATHENA
5eaef520 170 strcat(name, ".LOCAL");
bac4ceaa 171#endif
5eaef520 172 if (hash_store(machines, id, pstrsave(name)) < 0)
173 {
174 fprintf(stderr, "Out of memory!\n");
175 exit(MR_NO_MEM);
bac4ceaa 176 }
5eaef520 177 cnt++;
bac4ceaa 178 }
5eaef520 179 EXEC SQL CLOSE m_cursor;
180
181 fprintf(stderr, "Loaded %d machines\n", cnt);
182
183 cnt = 0;
184 strings = create_hash(11001);
185
186 EXEC SQL DECLARE s_cursor CURSOR FOR
187 SELECT string_id, string
188 FROM strings
189 ORDER BY string_id;
190 EXEC SQL OPEN s_cursor;
191 while (1)
192 {
193 EXEC SQL FETCH s_cursor INTO :id, :name;
194 if (sqlca.sqlcode)
195 break;
196 if (hash_store(strings, id, pstrsave(strtrim(name))) < 0)
197 {
198 fprintf(stderr, "Out of memory!\n");
199 exit(MR_NO_MEM);
bac4ceaa 200 }
5eaef520 201 cnt++;
bac4ceaa 202 }
5eaef520 203 EXEC SQL CLOSE s_cursor;
204
205 fprintf(stderr, "Loaded %d strings\n", cnt);
206
207 cnt = 0;
208 users = create_hash(13001);
209
210 EXEC SQL DECLARE u_cursor CURSOR FOR
211 SELECT users_id, login, first, middle, last, potype, pop_id, box_id
212 FROM users
213 WHERE status != 3
214 ORDER BY users_id;
215 EXEC SQL OPEN u_cursor;
216 while (1)
217 {
218 EXEC SQL FETCH u_cursor INTO :id, :name, :fname, :mname, :lname,
219 :type, :pid, :bid;
220 if (sqlca.sqlcode)
221 break;
222 u = (struct user *) perm_malloc(sizeof(struct user));
223 u->login = pstrsave(strtrim(name));
224 u->first = pstrsave(strtrim(fname));
225 u->last = pstrsave(strtrim(lname));
226 if (mname[0] != ' ')
227 u->mi = mname[0];
228 else
229 u->mi = 0;
230
231 if (type[0] == 'P' && (s = hash_lookup(machines, pid)))
232 {
233 sprintf(buf, "%s@%s", u->login, s);
234 u->pobox = pstrsave(buf);
235 }
236 else if (type[0] == 'S')
237 u->pobox = hash_lookup(strings, bid);
238 else
239 u->pobox = NULL;
240 if (hash_store(users, id, u) < 0)
241 {
242 fprintf(stderr, "Out of memory!\n");
243 exit(MR_NO_MEM);
bac4ceaa 244 }
5eaef520 245 cnt++;
bac4ceaa 246 }
5eaef520 247 EXEC SQL CLOSE u_cursor;
248 fprintf(stderr, "Loaded %d users\n", cnt);
249
250 cnt = 0;
251 lists = create_hash(15000);
252
253 EXEC SQL DECLARE l_cursor CURSOR FOR
254 SELECT list_id, name, maillist, description, acl_type, acl_id
255 FROM list
256 WHERE active != 0
257 ORDER BY list_id;
258 EXEC SQL OPEN l_cursor;
259 while (1)
260 {
261 EXEC SQL FETCH l_cursor INTO :id, :name, :maillistp, :buf, :type, :acl;
262 if (sqlca.sqlcode)
263 break;
264 l = (struct list *) perm_malloc(sizeof(struct list));
265 l->name = pstrsave(strtrim(name));
266 l->maillist = maillistp;
267 l->description = pstrsave(strtrim(buf));
268 l->acl_t = type[0];
269 l->acl_id = acl;
270 l->m = NULL;
271 if (hash_store(lists, id, l) < 0)
272 {
273 fprintf(stderr, "Out of memory!\n");
274 exit(MR_NO_MEM);
bac4ceaa 275 }
5eaef520 276 cnt++;
bac4ceaa 277 }
5eaef520 278 EXEC SQL CLOSE l_cursor;
279 fprintf(stderr, "Loaded %d lists\n", cnt);
280
281 cnt = 0;
282
283 EXEC SQL DECLARE m_cursor2 CURSOR FOR
284 SELECT list_id, member_type, member_id
285 FROM imembers
286 WHERE direct = 1
287 ORDER BY list_id;
288 EXEC SQL OPEN m_cursor2;
289 while (1)
290 {
291 EXEC SQL FETCH m_cursor2 INTO :id, :type, :mid;
292 if (sqlca.sqlcode)
293 break;
294 cnt++;
295 if ((l = (struct list *) hash_lookup(lists, id)))
296 {
297 m = (struct member *) perm_malloc(sizeof(struct member));
298 if (type[0] == 'U' && (u = (struct user *) hash_lookup(users, mid)))
299 {
300 m->list_id = 0;
301 m->name = u->login;
302 m->next = l->m;
303 l->m = m;
304 }
305 else if (type[0] == 'L' &&
306 (memberlist = (struct list *) hash_lookup(lists, mid)))
307 {
308 m->list_id = mid;
309 m->name = memberlist->name;
310 m->next = l->m;
311 l->m = m;
312 }
313 else if (type[0] == 'S' && (s = hash_lookup(strings, mid)))
314 {
315 m->list_id = 0;
316 m->next = l->m;
317 l->m = m;
318 m->name = s;
bac4ceaa 319 }
320 }
321 }
5eaef520 322 EXEC SQL CLOSE m_cursor2;
323 fprintf(stderr, "Loaded %d members\n", cnt);
324
325 EXEC SQL COMMIT;
326 return;
327sqlerr:
328 db_error(sqlca.sqlcode);
329 exit(MR_DBMS_ERR);
bac4ceaa 330}
331
332
5eaef520 333save_mlist(int id, struct list *l, int force)
bac4ceaa 334{
44d12d58 335 struct member *m;
336 struct list *l1;
bac4ceaa 337
5eaef520 338 if (l->maillist > 1 || (l->maillist == 0 && !force))
339 return;
bac4ceaa 340
5eaef520 341 if (l->m && l->m->next == NULL && !strcasecmp(l->name, l->m->name))
342 {
343 l->maillist = 3;
344 return;
bac4ceaa 345 }
5eaef520 346 l->maillist = 2;
347 insert_name(l->name, -1, TRUE, FALSE);
348 output_mlist(id, l);
349
350 if (l->acl_t == 'L' && (l1 = (struct list *)hash_lookup(lists, l->acl_id)))
351 save_mlist(0, l1, TRUE);
352
353 for (m = l->m; m; m = m->next)
354 {
355 if (m->list_id && (l1 = (struct list *)hash_lookup(lists, m->list_id)))
356 save_mlist(0, l1, TRUE);
bac4ceaa 357 }
358}
359
360
5eaef520 361insert_login(int id, struct user *u, int dummy)
bac4ceaa 362{
5eaef520 363 if (u->pobox && u->login[0] != '#')
364 insert_name(u->login, id, TRUE, FALSE);
bac4ceaa 365}
366
5eaef520 367void insert_names(int id, struct user *u, int dummy)
bac4ceaa 368{
5eaef520 369 char buffer[256];
370
371 insert_name(u->last, id, FALSE, FALSE);
372 sprintf(buffer, "%s_%s", u->first, u->last);
373 insert_name(buffer, id, FALSE, TRUE);
374#if 0
375 sprintf(buffer, "%c_%s", u->first[0], u->last);
376 insert_name(buffer, id, FALSE, TRUE);
377#endif
378 if (u->mi)
379 {
380 sprintf(buffer, "%s_%c_%s", u->first, u->mi, u->last);
381 insert_name(buffer, id, FALSE, TRUE);
bac4ceaa 382 }
383}
384
385int incount = 0;
386
5eaef520 387insert_name(char *s, int id, int nodups, int copy)
bac4ceaa 388{
5eaef520 389 int code;
44d12d58 390 struct names *ns;
5eaef520 391
392 incount++;
393 code = hashstr(s);
394 ns = (struct names *) hash_lookup(names, code);
395 if (!ns)
396 {
397 if (!(ns = (struct names *) perm_malloc(sizeof(struct names))))
398 {
399 fprintf(stderr, "ran out of memory inserting name (sorting)\n");
400 exit(MR_NO_MEM);
bac4ceaa 401 }
5eaef520 402 if (copy)
403 ns->name = pstrsave(s);
404 else
405 ns->name = s;
406 ns->keep = nodups;
407 ns->id = id;
408 ns->next = NULL;
409 if (hash_store(names, code, ns) < 0)
410 {
411 fprintf(stderr, "Out of memory!\n");
412 exit(MR_NO_MEM);
bac4ceaa 413 }
5eaef520 414 return;
bac4ceaa 415 }
5eaef520 416 if (strcasecmp(ns->name, s))
417 {
418 while (ns->next)
419 {
420 ns = ns->next;
421 if (!strcasecmp(ns->name, s))
422 goto foundns;
bac4ceaa 423 }
5eaef520 424 if (!(ns->next = (struct names *) perm_malloc(sizeof(struct names))))
425 {
426 fprintf(stderr, "ran out of memory insterting name (sorting)\n");
427 exit(MR_NO_MEM);
bac4ceaa 428 }
5eaef520 429 ns = ns->next;
430 if (copy)
431 ns->name = pstrsave(s);
432 else
433 ns->name = s;
434 ns->keep = nodups;
435 ns->id = id;
436 ns->next = NULL;
437 return;
bac4ceaa 438 }
5eaef520 439foundns:
440 if (nodups || ns->keep)
441 {
442 if (nodups && ns->keep)
443 fprintf(stderr, "duplicated name: %s\n", s);
444 return;
bac4ceaa 445 }
5eaef520 446 ns->id = 0;
bac4ceaa 447}
448
449
3ce369ab 450/* Illegal chars: ! " % ( ) , / : ; < = > @ [ \ ] ^ { | } */
bac4ceaa 451
452static int illegalchars[] = {
5eaef520 453 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
454 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
455 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, /* SPACE - / */
456 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, /* 0 - ? */
457 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
458 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, /* P - _ */
459 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
460 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
461 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
462 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
463 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
464 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
465 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
466 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
467 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
468 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
bac4ceaa 469};
470
471
472/* While hashing the string, punt any illegal characters */
473
44d12d58 474int hashstr(char *s)
bac4ceaa 475{
44d12d58 476 int result;
477 int c;
5eaef520 478
479 for (result = 0; c = *s; s++)
480 {
481 if (illegalchars[c])
482 {
44d12d58 483 char *p;
5eaef520 484 for (p = s; *p; p++)
485 *p = p[1];
486 continue;
bac4ceaa 487 }
5eaef520 488 if (isupper(c))
489 c = *s = tolower(c);
490 result = (result << 5) - result + c - '`';
bac4ceaa 491 }
5eaef520 492 return result < 0 ? -result : result;
bac4ceaa 493}
494
495
5eaef520 496sort_info(void)
bac4ceaa 497{
5eaef520 498 names = create_hash(20001);
499 hash_step(users, insert_login, NULL);
500 incount = 0;
501 fprintf(out, "\n%s\n# Mailing lists\n%s\n", divide, divide);
502 hash_step(lists, save_mlist, FALSE);
503 fprintf(stderr, "Output %d lists\n", incount);
504 hash_step(users, insert_names, NULL);
505 fprintf(stderr, "Inserted %d names\n", incount);
bac4ceaa 506}
507
508
5eaef520 509output_data(int dummy, struct names *nms, FILE *out)
bac4ceaa 510{
44d12d58 511 struct names *ns;
512 struct user *u;
5eaef520 513
514 incount++;
515 for (ns = nms; ns; ns = ns->next)
516 {
517 if (!ns->name[0] || !ns->name[1])
518 {
519 fprintf(stderr, "punting %s due to short name\n", ns->name);
520 continue;
bac4ceaa 521 }
5eaef520 522 if (ns->id > 0)
523 {
524 u = (struct user *) hash_lookup(users, ns->id);
525 if (u->pobox)
526 fprintf(out, "%s: %s\n", ns->name, u->pobox);
527 else
528 fprintf(out, "%s: =%s=@nobox\n", ns->name, ns->name);
bac4ceaa 529 }
5eaef520 530 else if (ns->id == 0)
531 fprintf(out, "%s: =%s=@ambig\n", ns->name, ns->name);
bac4ceaa 532 }
533}
534
535
536int lwid, bol, awid;
537
44d12d58 538output_mlist(int id, struct list *l)
bac4ceaa 539{
5eaef520 540 struct list *l1;
44d12d58 541 struct member *m;
542 struct user *u;
5eaef520 543
544 put_fill(out, l->description);
545 if (l->acl_t == 'L' && (l1 = (struct list *) hash_lookup(lists, l->acl_id)))
546 fprintf(out, "owner-%s: %s\n%s: ", l->name, l1->name, l->name);
547 else if (l->acl_t == 'U' &&
bac4ceaa 548 (u = (struct user *) hash_lookup(users, l->acl_id)))
5eaef520 549 fprintf(out, "owner-%s: %s\n%s: ", l->name, u->login, l->name);
550 else
551 fprintf(out, "%s: ", l->name);
552
553 lwid = strlen(l->name) + 2;
554 bol = 1;
555 for (m = l->m; m; m = m->next)
556 do_member(out, m->name);
557 if (!l->m)
558 fprintf(out, "/dev/null");
559 fprintf(out, "\n\n");
560 incount++;
bac4ceaa 561}
562
563
564/* print out strings separated by commas, doing line breaks as appropriate */
565
44d12d58 566do_member(FILE *out, char *s)
bac4ceaa 567{
44d12d58 568 wwid;
5eaef520 569 static int cont = 1;
570 char str[8];
571
572 wwid = strlen(s);
573
574 if (!bol && awid + wwid + 2 > AL_MAX_WID)
575 {
576 sprintf(str, "%c%c%c%c%c%c", rand() % 26 + 97, rand() % 26 + 97,
577 rand() % 26 + 97, rand() % 26 + 97,
578 rand() % 26 + 97, rand() % 26 + 97);
579 str[6] = '\0';
580 fprintf(out, ",\n\tcont%d-%s\ncont%d-%s: ", cont, str, cont, str);
581 cont++;
582 awid = lwid = 17 + wwid;
583 fputs(s, out);
584 return;
bac4ceaa 585 }
586
5eaef520 587 if (bol)
588 {
589 lwid += wwid;
590 awid = lwid;
591 fputs(s, out);
592 bol = 0;
593 return;
bac4ceaa 594 }
5eaef520 595 if (lwid + wwid + 2 > ML_WID)
596 {
597 fprintf(out, ",\n\t%s", s);
598 awid += lwid + wwid + 2;
599 lwid = wwid + 8;
600 return;
bac4ceaa 601 }
5eaef520 602 lwid += wwid + 2;
603 fprintf(out, ", %s", s);
bac4ceaa 604}
605
606
44d12d58 607put_fill(FILE *aliases, char *string)
492f333e 608{
44d12d58 609 char *c;
610 int lwid;
611 int wwid;
492f333e 612
5eaef520 613 if (!string || !*string)
614 return;
615 fputs("# ", aliases);
616 lwid = 3;
617
618 while (1)
619 {
620 while (*string == ' ')
621 string++;
622 c = strchr(string, ' ');
623 if (!c)
624 wwid = strlen(string);
625 else
626 {
627 wwid = c - string;
628 *c = '\0';
492f333e 629 }
630
5eaef520 631 if ((lwid + wwid) > ML_WID)
632 {
633 fputs("\n# ", aliases);
634 lwid = 3;
635 fputs(string, aliases);
636 }
637 else
638 fputs(string, aliases);
639
640 if (!c)
641 break;
642 /* add a space after the word */
643 fputc(' ', aliases);
644 wwid++;
645 lwid += wwid;
646 string += wwid;
647 /* add another if after a period */
648 if (*--c == '.')
649 {
650 fputc(' ', aliases);
651 lwid++;
492f333e 652 }
653 }
654
5eaef520 655 fputc('\n', aliases);
492f333e 656}
657
658
5eaef520 659do_people(void)
bac4ceaa 660{
5eaef520 661 incount = 0;
662 fprintf(out, "\n%s\n# People\n%s\n", divide, divide);
663 hash_step(names, output_data, out);
664 fprintf(stderr, "Output %d entries\n", incount);
bac4ceaa 665}
666
667
668#define chunk_size 102400
669
5eaef520 670char *perm_malloc(unsigned size)
bac4ceaa 671{
5eaef520 672 static char *pool = NULL;
673 static unsigned pool_size = 0;
44d12d58 674 char *ret;
5eaef520 675
676 if (size > pool_size)
677 {
678 pool = malloc(chunk_size);
679 pool_size = chunk_size;
bac4ceaa 680 }
5eaef520 681 ret = pool;
682 pool += size;
683 pool = (char *)(((unsigned) (pool + 3)) & ~3);
684 pool_size -= (pool - ret);
685 return ret;
bac4ceaa 686}
687
688
689/*
690 * Make a (permenant) copy of a string.
691 */
5eaef520 692char *pstrsave(char *s)
bac4ceaa 693{
44d12d58 694 int len;
695 char *p;
5eaef520 696 /* Kludge for sloppy string semantics */
697 if (!s)
698 {
699 printf("NULL != \"\" !!!!\r\n");
700 p = perm_malloc(1);
701 *p = '\0';
702 return p;
bac4ceaa 703 }
5eaef520 704 len = strlen(s) + 1;
705 p = perm_malloc((u_int)len);
706 if (p)
707 memcpy(p, s, len);
708 return p;
bac4ceaa 709}
710
711#define hash_func(h, key) (key >= 0 ? (key % h->size) : (-key % h->size))
712
713/* Create a hash table. The size is just a hint, not a maximum. */
714
5eaef520 715struct hash *create_hash(int size)
bac4ceaa 716{
5eaef520 717 struct hash *h;
718
719 h = (struct hash *) perm_malloc(sizeof(struct hash));
720 if (!h)
721 return NULL;
722 h->size = size;
723 h->data = (struct bucket **) perm_malloc(size * sizeof(char *));
724 if (!h->data)
725 return NULL;
726 memset(h->data, 0, size * sizeof(char *));
727 return h;
bac4ceaa 728}
729
730/* Lookup an object in the hash table. Returns the value associated with
731 * the key, or NULL (thus NULL is not a very good value to store...)
732 */
733
44d12d58 734char *hash_lookup(struct hash *h, int key)
bac4ceaa 735{
44d12d58 736 struct bucket *b;
5eaef520 737
738 b = h->data[hash_func(h, key)];
739 while (b && b->key != key)
740 b = b->next;
741 if (b && b->key == key)
742 return b->data;
743 else
744 return NULL;
bac4ceaa 745}
746
747
748/* Update an existing object in the hash table. Returns 1 if the object
749 * existed, or 0 if not.
750 */
751
44d12d58 752int hash_update(struct hash *h, int key, char *value)
bac4ceaa 753{
44d12d58 754 struct bucket *b;
5eaef520 755
756 b = h->data[hash_func(h, key)];
757 while (b && b->key != key)
758 b = b->next;
759 if (b && b->key == key)
760 {
761 b->data = value;
762 return 1;
763 }
764 else
765 return 0;
bac4ceaa 766}
767
768
769/* Store an item in the hash table. Returns 0 if the key was not previously
770 * there, 1 if it was, or -1 if we ran out of memory.
771 */
772
44d12d58 773int hash_store(struct hash *h, int key, char *value)
bac4ceaa 774{
44d12d58 775 struct bucket *b, **p;
5eaef520 776
777 p = &(h->data[hash_func(h, key)]);
778 if (!*p)
779 {
780 b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
781 if (!b)
782 return -1;
783 b->next = NULL;
784 b->key = key;
785 b->data = value;
786 return 0;
bac4ceaa 787 }
788
5eaef520 789 for (b = *p; b && b->key != key; b = *p)
790 p = (struct bucket **) *p;
791 if (b && b->key == key)
792 {
793 b->data = value;
794 return 1;
bac4ceaa 795 }
5eaef520 796 b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
797 if (!b)
798 return -1;
799 b->next = NULL;
800 b->key = key;
801 b->data = value;
802 return 0;
bac4ceaa 803}
804
805
806/* Search through the hash table for a given value. For each piece of
807 * data with that value, call the callback proc with the corresponding key.
808 */
809
44d12d58 810hash_search(struct hash *h, char *value, void (*callback)())
bac4ceaa 811{
44d12d58 812 struct bucket *b, **p;
5eaef520 813
814 for (p = &(h->data[h->size - 1]); p >= h->data; p--)
815 {
816 for (b = *p; b; b = b->next)
817 {
818 if (b->data == value)
819 (*callback)(b->key);
bac4ceaa 820 }
821 }
822}
823
824
825/* Step through the hash table, calling the callback proc with each key.
826 */
827
5eaef520 828hash_step(struct hash *h, void (*callback)(), char *hint)
bac4ceaa 829{
44d12d58 830 struct bucket *b, **p;
bac4ceaa 831
5eaef520 832 for (p = &(h->data[h->size - 1]); p >= h->data; p--)
833 {
834 for (b = *p; b; b = b->next)
835 (*callback)(b->key, b->data, hint);
bac4ceaa 836 }
837}
This page took 0.20019 seconds and 5 git commands to generate.