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