]> andersk Git - moira.git/blob - gen/mailhub.dc
find makedepend during initial compile
[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(10);
161
162     EXEC SQL DECLARE m_cursor CURSOR FOR
163       SELECT mach_id, name
164       FROM machine
165       ORDER BY mach_id;
166     EXEC SQL OPEN m_cursor;
167     while (1) {
168         EXEC SQL FETCH m_cursor INTO :id, :name;
169         if (sqlca.sqlcode != 0) break;
170         if (s = index(name, '.'))
171           *s = 0;
172         else
173           strtrim(name);
174 #ifdef ATHENA
175         strcat(name, ".LOCAL");
176 #endif
177         if (hash_store(machines, id, pstrsave(name)) < 0) {
178             fprintf(stderr, "Out of memory!\n");
179             exit(MR_NO_MEM);
180         }
181         cnt++;
182     }
183     EXEC SQL CLOSE m_cursor;
184
185     fprintf(stderr, "Loaded %d machines\n", cnt);
186
187     cnt = 0;
188     strings = create_hash(11001);
189
190     EXEC SQL DECLARE s_cursor CURSOR FOR
191       SELECT string_id, trim(string)
192       FROM strings
193       ORDER BY string_id;
194     EXEC SQL OPEN s_cursor;
195     while (1) {
196         EXEC SQL FETCH s_cursor INTO :id, :name;
197         if (sqlca.sqlcode != 0) break;
198         if (hash_store(strings, id, pstrsave(name)) < 0) {
199             fprintf(stderr, "Out of memory!\n");
200             exit(MR_NO_MEM);
201         }
202         cnt++;
203     }
204     EXEC SQL CLOSE s_cursor;
205
206     fprintf(stderr, "Loaded %d strings\n", cnt);
207
208     cnt = 0;
209     users = create_hash(13001);
210
211     EXEC SQL DECLARE u_cursor CURSOR FOR
212       SELECT users_id, login, first, middle, last, potype, pop_id, box_id
213       FROM users
214       WHERE status != 3
215       ORDER BY users_id;
216     EXEC SQL OPEN u_cursor;
217     while (1) {
218         EXEC SQL FETCH u_cursor INTO :id, :name, :fname, :mname, :lname,
219                                    :type, :pid, :bid;
220         if (sqlca.sqlcode != 0) break;
221         u = (struct user *) perm_malloc(sizeof(struct user));
222         u->login = pstrsave(strtrim(name));
223         u->first = pstrsave(strtrim(fname));
224         u->last  = pstrsave(strtrim(lname));
225         if (mname[0] != ' ')
226           u->mi = mname[0];
227         else
228           u->mi = 0;
229
230         if (type[0] == 'P' && (s = hash_lookup(machines, pid))) {
231             sprintf(buf, "%s@%s", u->login, s);
232             u->pobox = pstrsave(buf);
233         } else if (type[0] ==  'S') {
234             u->pobox = hash_lookup(strings, bid);
235         } else
236           u->pobox = (char *) NULL;
237         if (hash_store(users, id, u) < 0) {
238             fprintf(stderr, "Out of memory!\n");
239             exit(MR_NO_MEM);
240         }
241         cnt++;
242     }
243     EXEC SQL CLOSE u_cursor;
244     EXEC SQL COMMIT;
245     fprintf(stderr, "Loaded %d users\n", cnt);
246
247     cnt = 0;
248     lists = create_hash(15000);
249
250     EXEC SQL DECLARE l_cursor CURSOR FOR
251       SELECT list_id, name, maillist, description, acl_type, acl_id
252       FROM list
253       WHERE active != 0
254       ORDER BY list_id;
255     EXEC SQL OPEN l_cursor;
256     while (1) {
257         EXEC SQL FETCH l_cursor INTO :id, :name, :maillistp, :buf, :type, :acl;
258         if (sqlca.sqlcode != 0) break;
259         l = (struct list *) perm_malloc(sizeof(struct list));
260         l->name = pstrsave(strtrim(name));
261         l->maillist = maillistp;
262         l->description = pstrsave(strtrim(buf));
263         l->acl_t = type[0];
264         l->acl_id = acl;
265         l->m = (struct member *) NULL;
266         if (hash_store(lists, id, l) < 0) {
267             fprintf(stderr, "Out of memory!\n");
268             exit(MR_NO_MEM);
269         }
270         cnt++;
271     }
272     EXEC SQL CLOSE l_cursor;
273     EXEC SQL COMMIT;
274     fprintf(stderr, "Loaded %d lists\n", cnt);
275
276     cnt = 0;
277
278     EXEC SQL DECLARE m_cursor2 CURSOR FOR
279       SELECT list_id, member_type, member_id
280       FROM imembers
281       WHERE direct = 1
282       ORDER BY list_id;
283     EXEC SQL OPEN m_cursor2;
284     while (1) {
285         EXEC SQL FETCH m_cursor2 INTO :id, :type, :mid;
286         if (sqlca.sqlcode != 0) break;
287         cnt++;
288         if (l = (struct list *) hash_lookup(lists, id)) {
289             m = (struct member *) perm_malloc(sizeof(struct member));
290             if (type[0] == 'U' &&
291                 (u = (struct user *) hash_lookup(users, mid))) {
292                 m->list_id = 0;
293                 m->name = u->login;
294                 m->next = l->m;
295                 l->m = m;
296             } else if (type[0] == 'L' && 
297                        (memberlist = (struct list *) hash_lookup(lists, mid))) {
298                 m->list_id = mid;
299                 m->name = memberlist->name;
300                 m->next = l->m;
301                 l->m = m;
302             } else if (type[0] == 'S' &&
303                        (s = hash_lookup(strings, mid))) {
304                 m->list_id = 0;
305                 m->next = l->m;
306                 l->m = m;
307                 m->name = s;
308             }
309         }
310     }
311     EXEC SQL CLOSE m_cursor2;
312     fprintf(stderr, "Loaded %d members\n", cnt);
313     return;
314  sqlerr:
315     com_err(whoami, MR_INGRES_ERR, " code %d\n", sqlca.sqlcode);
316     critical_alert("DCM", "Hesiod build encountered DATABASE ERROR %d",
317                    sqlca.sqlcode);
318     exit(MR_INGRES_ERR);
319 }
320
321
322 save_mlist(id, l, force)
323 int id;
324 struct list *l;
325 int force;
326 {
327     register struct member *m;
328     register struct list *l1;
329
330     if (l->maillist > 1 ||
331         (l->maillist == 0 && !force))
332       return;
333
334     if (l->m && l->m->next == NULL &&
335         !strcasecmp(l->name, l->m->name)) {
336         l->maillist = 3;
337         return;
338     }
339     l->maillist = 2;
340     insert_name(l->name, -1, TRUE, FALSE);
341     output_mlist(id, l);
342
343     if (l->acl_t == 'L' && (l1 = (struct list *)hash_lookup(lists, l->acl_id)))
344       save_mlist(0, l1, TRUE);
345     
346     for (m = l->m; m; m = m->next) {
347         if (m->list_id && (l1 = (struct list *)hash_lookup(lists, m->list_id)))
348           save_mlist(0, l1, TRUE);
349     }
350 }
351
352
353 insert_login(id, u, dummy)
354 int id;
355 struct user *u;
356 int dummy;
357 {
358     if (u->pobox && u->login[0] != '#')
359       insert_name(u->login, id, TRUE, FALSE);
360 }
361
362 void insert_names(id, u, dummy)
363 int id;
364 struct user *u;
365 int dummy;
366 {
367     char buffer[256];
368
369     insert_name(u->last, id, FALSE, FALSE);
370     sprintf(buffer, "%s_%s", u->first, u->last);
371     insert_name(buffer, id, FALSE, TRUE);
372 /*    sprintf(buffer, "%c_%s", u->first[0], u->last);
373     insert_name(buffer, id, FALSE, TRUE); */
374     if (u->mi) {
375         sprintf(buffer, "%s_%c_%s", u->first, u->mi, u->last);
376         insert_name(buffer, id, FALSE, TRUE);
377     }
378 }
379
380 int incount = 0;
381
382 insert_name(s, id, nodups, copy)
383 char *s;
384 int id;
385 int nodups;
386 int copy;
387 {
388     int code;
389     register struct names *ns;
390
391     incount++;
392     code = hashstr(s);
393     ns = (struct names *) hash_lookup(names, code);
394     if (ns == NULL) {
395         if ((ns = (struct names *) perm_malloc(sizeof(struct names))) == NULL) {
396             fprintf(stderr, "ran out of memory inserting name (sorting)\n");
397             exit(MR_NO_MEM);
398         }
399         if (copy)
400           ns->name = pstrsave(s);
401         else
402           ns->name = s;
403         ns->keep = nodups;
404         ns->id = id;
405         ns->next = NULL;
406         if (hash_store(names, code, ns) < 0) {
407             fprintf(stderr, "Out of memory!\n");
408             exit(MR_NO_MEM);
409         }
410         return;
411     }
412     if (strcasecmp(ns->name, s)) {
413         while (ns->next) {
414             ns = ns->next;
415             if (!strcasecmp(ns->name, s))
416               goto foundns;
417         }
418         if ((ns->next = (struct names *) perm_malloc(sizeof(struct names)))
419                 == NULL) {
420             fprintf(stderr, "ran out of memory insterting name (sorting)\n");
421             exit(MR_NO_MEM);
422         }
423         ns = ns->next;
424         if (copy)
425           ns->name = pstrsave(s);
426         else
427           ns->name = s;
428         ns->keep = nodups;
429         ns->id = id;
430         ns->next = NULL;
431         return;
432     }
433  foundns:
434     if (nodups || ns->keep) {
435         if (nodups && ns->keep)
436           fprintf(stderr, "duplicated name: %s\n", s);
437         return;
438     }
439     ns->id = 0;
440 }
441
442
443 /* Illegal chars: ! " % ( ) , / : ; < = > @ [ \ ] ^ { | } */
444
445 static int illegalchars[] = {
446     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
447     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
448     0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, /* SPACE - / */
449     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, /* 0 - ? */
450     1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
451     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, /* P - _ */
452     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
453     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
454     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
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 };
463
464
465 /* While hashing the string, punt any illegal characters */
466
467 int hashstr(s)
468 register char *s;
469 {
470     register int result;
471     register int c;
472
473     for (result = 0; c = *s; s++) {
474         if (illegalchars[c]) {
475             register char *p;
476             for (p = s; *p; p++)
477               *p = p[1];
478             continue;
479         }
480         if (isupper(c))
481           c = *s = tolower(c);
482 /*      result = result * 31 + *s; */
483         result = (result << 5) - result + c - '`';
484     }
485     return(result < 0 ? -result : result);
486 }
487
488
489 sort_info()
490 {
491     names = create_hash(20001);
492     hash_step(users, insert_login, NULL);
493     incount = 0;
494     fprintf(out, "\n%s\n# Mailing lists\n%s\n", divide, divide);
495     hash_step(lists, save_mlist, FALSE);
496     fprintf(stderr, "Output %d lists\n", incount);
497     hash_step(users, insert_names, NULL);
498     fprintf(stderr, "Inserted %d names\n", incount);
499 }
500
501
502 output_data(dummy, nms, out)
503 int dummy;
504 struct names *nms;
505 FILE *out;
506 {
507     register struct names *ns;
508     register struct user *u;
509
510     incount++;
511     for (ns = nms; ns; ns = ns->next) {
512         if (ns->name[0] == 0 || ns->name[1] == 0) {
513             fprintf(stderr, "punting %s due to short name\n", ns->name);
514             continue;
515         }
516         if (ns->id > 0) {
517             u = (struct user *) hash_lookup(users, ns->id);
518             if (u->pobox) {
519                 fprintf(out, "%s: %s\n", ns->name, u->pobox);
520             } else {
521                 fprintf(out, "%s: =%s=@nobox\n", ns->name, ns->name);
522             }
523         } else if (ns->id == 0) {
524             fprintf(out, "%s: =%s=@ambig\n", ns->name, ns->name);
525         }
526     }
527 }
528
529
530 int lwid, bol, awid;
531
532 output_mlist(id, l)
533 int id;
534 register struct list *l;
535 {
536     struct list *l1;
537     register struct member *m;
538     register struct user *u;
539
540     put_fill(out, l->description);
541     if (l->acl_t ==  'L' &&
542         (l1 = (struct list *) hash_lookup(lists, l->acl_id)))
543       fprintf(out, "owner-%s: %s\n%s: ", l->name, l1->name, l->name);
544     else if (l->acl_t ==  'U' &&
545              (u = (struct user *) hash_lookup(users, l->acl_id)))
546       fprintf(out, "owner-%s: %s\n%s: ", l->name, u->login, l->name);
547     else
548       fprintf(out, "%s: ", l->name);
549       
550
551     lwid = strlen(l->name) + 2;
552     bol = 1;
553     for (m = l->m; m; m = m->next) {
554         do_member(out, m->name);
555     }
556     if (l->m == (struct member *)NULL)
557       fprintf(out, "/dev/null");
558     fprintf(out, "\n\n");
559     incount++;
560 }
561
562
563 /* print out strings separated by commas, doing line breaks as appropriate */
564
565 do_member(out, s)
566 FILE *out;
567 register char *s;
568 {
569     register wwid;
570     static int cont = 1;
571
572     wwid = strlen(s);
573
574     if (!bol && awid + wwid + 2 > AL_MAX_WID) {
575         fprintf(out, ",\n\tcontinuation-%d\ncontinuation-%d: ", cont, cont);
576         cont++;
577         awid = lwid = 17 + wwid;
578         fputs(s, out);
579         return;
580     }
581
582     if (bol) {
583         lwid += wwid;
584         awid = lwid;
585         fputs(s, out);
586         bol = 0;
587         return;
588     }
589     if (lwid + wwid + 2 > ML_WID) {
590         fprintf(out, ",\n\t%s", s);
591         awid += lwid + wwid + 2;
592         lwid = wwid + 8;
593         return;
594     }
595     lwid += wwid + 2;
596     fprintf(out, ", %s", s);
597 }
598
599
600 put_fill(aliases, string)
601 FILE *aliases;
602 register char *string;
603 {
604     register char *c;
605     register int lwid;
606     register int wwid;
607
608     if (string == 0 || *string == 0) return;
609     fputs("#  ", aliases);
610     lwid = 3;
611
612     while (1) {
613         while (*string && *string == ' ') string++;
614         c = (char *)index(string, ' ');
615         if (c == 0) {
616             wwid = strlen(string);
617         } else {
618             wwid = c - string;
619             *c = 0;
620         }
621
622         if ((lwid + wwid) > ML_WID) {
623             fputs("\n#  ", aliases);
624             lwid = 3;
625             fputs(string, aliases);
626         } else {
627             fputs(string, aliases);
628         }
629
630         if (c == (char *)0) break;
631         /* add a space after the word */
632         (void) fputc(' ', aliases);
633         wwid++;
634         lwid += wwid;
635         string += wwid;
636         /* add another if after a period */
637         if (*--c == '.') {
638             (void) fputc(' ', aliases);
639             lwid++;
640         }
641     }
642
643     (void) fputc('\n', aliases);
644 }
645
646
647 do_people()
648 {
649     incount = 0;
650     fprintf(out, "\n%s\n# People\n%s\n", divide, divide);
651     hash_step(names, output_data, out);
652     fprintf(stderr, "Output %d entries\n", incount);
653 }
654
655
656 #define chunk_size      102400
657
658 char *perm_malloc(size)
659 unsigned size;
660 {
661     static char *pool = NULL;
662     static unsigned pool_size = 0;
663     register char *ret;
664
665     if (size > pool_size) {
666         pool = (char *) malloc(chunk_size);
667         pool_size = chunk_size;
668     }
669     ret = pool;
670     pool += size;
671     pool = (char *)(((unsigned) (pool + 3)) & ~3);
672     pool_size -= (pool - ret);
673     return(ret);
674 }
675
676
677 /*
678  * Make a (permenant) copy of a string.
679  */
680 char *
681 pstrsave(s)
682     char *s;
683 {
684     register int len;
685     register char *p;
686     /* Kludge for sloppy string semantics */
687     if (!s) {
688             printf("NULL != \"\" !!!!\r\n");
689             p = perm_malloc(1);
690             *p = '\0';
691             return p;
692     }
693     len = strlen(s) + 1;
694     p = perm_malloc((u_int)len);
695     if (p) bcopy(s, p, len);
696     return p;
697 }
698
699 #define hash_func(h, key) (key >= 0 ? (key % h->size) : (-key % h->size))
700
701 /* Create a hash table.  The size is just a hint, not a maximum. */
702
703 struct hash *create_hash(size)
704 int size;
705 {
706     struct hash *h;
707
708     h = (struct hash *) perm_malloc(sizeof(struct hash));
709     if (h == (struct hash *) NULL)
710       return((struct hash *) NULL);
711     h->size = size;
712     h->data = (struct bucket **) perm_malloc(size * sizeof(char *));
713     if (h->data == (struct bucket **) NULL) {
714         free(h);
715         return((struct hash *) NULL);
716     }
717     bzero(h->data, size * sizeof(char *));
718     return(h);
719 }
720
721 /* Lookup an object in the hash table.  Returns the value associated with
722  * the key, or NULL (thus NULL is not a very good value to store...)
723  */
724
725 char *hash_lookup(h, key)
726 struct hash *h;
727 register int key;
728 {
729     register struct bucket *b;
730
731     b = h->data[hash_func(h, key)];
732     while (b && b->key != key)
733       b = b->next;
734     if (b && b->key == key)
735       return(b->data);
736     else
737       return(NULL);
738 }
739
740
741 /* Update an existing object in the hash table.  Returns 1 if the object
742  * existed, or 0 if not.
743  */
744
745 int hash_update(h, key, value)
746 struct hash *h;
747 register int key;
748 char *value;
749 {
750     register struct bucket *b;
751
752     b = h->data[hash_func(h, key)];
753     while (b && b->key != key)
754       b = b->next;
755     if (b && b->key == key) {
756         b->data = value;
757         return(1);
758     } else
759       return(0);
760 }
761
762
763 /* Store an item in the hash table.  Returns 0 if the key was not previously
764  * there, 1 if it was, or -1 if we ran out of memory.
765  */
766
767 int hash_store(h, key, value)
768 struct hash *h;
769 register int key;
770 char *value;
771 {
772     register struct bucket *b, **p;
773
774     p = &(h->data[hash_func(h, key)]);
775     if (*p == NULL) {
776         b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
777         if (b == (struct bucket *) NULL)
778           return(-1);
779         b->next = NULL;
780         b->key = key;
781         b->data = value;
782         return(0);
783     }
784
785     for (b = *p; b && b->key != key; b = *p)
786       p = (struct bucket **) *p;
787     if (b && b->key == key) {
788         b->data = value;
789         return(1);
790     }
791     b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
792     if (b == (struct bucket *) NULL)
793       return(-1);
794     b->next = NULL;
795     b->key = key;
796     b->data = value;
797     return(0);
798 }
799
800
801 /* Search through the hash table for a given value.  For each piece of
802  * data with that value, call the callback proc with the corresponding key.
803  */
804
805 hash_search(h, value, callback)
806 struct hash *h;
807 register char *value;
808 void (*callback)();
809 {
810     register struct bucket *b, **p;
811
812     for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
813         for (b = *p; b; b = b->next) {
814             if (b->data == value)
815               (*callback)(b->key);
816         }
817     }
818 }
819
820
821 /* Step through the hash table, calling the callback proc with each key.
822  */
823
824 hash_step(h, callback, hint)
825 struct hash *h;
826 void (*callback)();
827 char *hint;
828 {
829     register struct bucket *b, **p;
830
831     for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
832         for (b = *p; b; b = b->next) {
833             (*callback)(b->key, b->data, hint);
834         }
835     }
836 }
837
838
839 /* Deallocate all of the memory associated with a table */
840
841 hash_destroy(h)
842 struct hash *h;
843 {
844     register struct bucket *b, **p, *b1;
845
846     for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
847         for (b = *p; b; b = b1) {
848             b1 = b->next;
849             free(b);
850         }
851     }
852 }
This page took 0.182652 seconds and 5 git commands to generate.