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