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