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