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