]> andersk Git - moira.git/blob - gen/mailhub.dc
b1af6661887eb09871b346962fdad7585923df8f
[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", "Hesiod 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
576     wwid = strlen(s);
577
578     if (!bol && awid + wwid + 2 > AL_MAX_WID) {
579         fprintf(out, ",\n\tcontinuation%d\ncontinuation%d: ", cont, cont);
580         cont++;
581         awid = lwid = 17 + wwid;
582         fputs(s, out);
583         return;
584     }
585
586     if (bol) {
587         lwid += wwid;
588         awid = lwid;
589         fputs(s, out);
590         bol = 0;
591         return;
592     }
593     if (lwid + wwid + 2 > ML_WID) {
594         fprintf(out, ",\n\t%s", s);
595         awid += lwid + wwid + 2;
596         lwid = wwid + 8;
597         return;
598     }
599     lwid += wwid + 2;
600     fprintf(out, ", %s", s);
601 }
602
603
604 put_fill(aliases, string)
605 FILE *aliases;
606 register char *string;
607 {
608     register char *c;
609     register int lwid;
610     register int wwid;
611
612     if (string == 0 || *string == 0) return;
613     fputs("#  ", aliases);
614     lwid = 3;
615
616     while (1) {
617         while (*string && *string == ' ') string++;
618         c = (char *)index(string, ' ');
619         if (c == 0) {
620             wwid = strlen(string);
621         } else {
622             wwid = c - string;
623             *c = 0;
624         }
625
626         if ((lwid + wwid) > ML_WID) {
627             fputs("\n#  ", aliases);
628             lwid = 3;
629             fputs(string, aliases);
630         } else {
631             fputs(string, aliases);
632         }
633
634         if (c == (char *)0) break;
635         /* add a space after the word */
636         (void) fputc(' ', aliases);
637         wwid++;
638         lwid += wwid;
639         string += wwid;
640         /* add another if after a period */
641         if (*--c == '.') {
642             (void) fputc(' ', aliases);
643             lwid++;
644         }
645     }
646
647     (void) fputc('\n', aliases);
648 }
649
650
651 do_people()
652 {
653     incount = 0;
654     fprintf(out, "\n%s\n# People\n%s\n", divide, divide);
655     hash_step(names, output_data, out);
656     fprintf(stderr, "Output %d entries\n", incount);
657 }
658
659
660 #define chunk_size      102400
661
662 char *perm_malloc(size)
663 unsigned size;
664 {
665     static char *pool = NULL;
666     static unsigned pool_size = 0;
667     register char *ret;
668
669     if (size > pool_size) {
670         pool = (char *) malloc(chunk_size);
671         pool_size = chunk_size;
672     }
673     ret = pool;
674     pool += size;
675     pool = (char *)(((unsigned) (pool + 3)) & ~3);
676     pool_size -= (pool - ret);
677     return(ret);
678 }
679
680
681 /*
682  * Make a (permenant) copy of a string.
683  */
684 char *
685 pstrsave(s)
686     char *s;
687 {
688     register int len;
689     register char *p;
690     /* Kludge for sloppy string semantics */
691     if (!s) {
692             printf("NULL != \"\" !!!!\r\n");
693             p = perm_malloc(1);
694             *p = '\0';
695             return p;
696     }
697     len = strlen(s) + 1;
698     p = perm_malloc((u_int)len);
699     if (p) bcopy(s, p, len);
700     return p;
701 }
702
703 #define hash_func(h, key) (key >= 0 ? (key % h->size) : (-key % h->size))
704
705 /* Create a hash table.  The size is just a hint, not a maximum. */
706
707 struct hash *create_hash(size)
708 int size;
709 {
710     struct hash *h;
711
712     h = (struct hash *) perm_malloc(sizeof(struct hash));
713     if (h == (struct hash *) NULL)
714       return((struct hash *) NULL);
715     h->size = size;
716     h->data = (struct bucket **) perm_malloc(size * sizeof(char *));
717     if (h->data == (struct bucket **) NULL) {
718         free(h);
719         return((struct hash *) NULL);
720     }
721     bzero(h->data, size * sizeof(char *));
722     return(h);
723 }
724
725 /* Lookup an object in the hash table.  Returns the value associated with
726  * the key, or NULL (thus NULL is not a very good value to store...)
727  */
728
729 char *hash_lookup(h, key)
730 struct hash *h;
731 register int key;
732 {
733     register struct bucket *b;
734
735     b = h->data[hash_func(h, key)];
736     while (b && b->key != key)
737       b = b->next;
738     if (b && b->key == key)
739       return(b->data);
740     else
741       return(NULL);
742 }
743
744
745 /* Update an existing object in the hash table.  Returns 1 if the object
746  * existed, or 0 if not.
747  */
748
749 int hash_update(h, key, value)
750 struct hash *h;
751 register int key;
752 char *value;
753 {
754     register struct bucket *b;
755
756     b = h->data[hash_func(h, key)];
757     while (b && b->key != key)
758       b = b->next;
759     if (b && b->key == key) {
760         b->data = value;
761         return(1);
762     } else
763       return(0);
764 }
765
766
767 /* Store an item in the hash table.  Returns 0 if the key was not previously
768  * there, 1 if it was, or -1 if we ran out of memory.
769  */
770
771 int hash_store(h, key, value)
772 struct hash *h;
773 register int key;
774 char *value;
775 {
776     register struct bucket *b, **p;
777
778     p = &(h->data[hash_func(h, key)]);
779     if (*p == NULL) {
780         b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
781         if (b == (struct bucket *) NULL)
782           return(-1);
783         b->next = NULL;
784         b->key = key;
785         b->data = value;
786         return(0);
787     }
788
789     for (b = *p; b && b->key != key; b = *p)
790       p = (struct bucket **) *p;
791     if (b && b->key == key) {
792         b->data = value;
793         return(1);
794     }
795     b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
796     if (b == (struct bucket *) NULL)
797       return(-1);
798     b->next = NULL;
799     b->key = key;
800     b->data = value;
801     return(0);
802 }
803
804
805 /* Search through the hash table for a given value.  For each piece of
806  * data with that value, call the callback proc with the corresponding key.
807  */
808
809 hash_search(h, value, callback)
810 struct hash *h;
811 register char *value;
812 void (*callback)();
813 {
814     register struct bucket *b, **p;
815
816     for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
817         for (b = *p; b; b = b->next) {
818             if (b->data == value)
819               (*callback)(b->key);
820         }
821     }
822 }
823
824
825 /* Step through the hash table, calling the callback proc with each key.
826  */
827
828 hash_step(h, callback, hint)
829 struct hash *h;
830 void (*callback)();
831 char *hint;
832 {
833     register struct bucket *b, **p;
834
835     for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
836         for (b = *p; b; b = b->next) {
837             (*callback)(b->key, b->data, hint);
838         }
839     }
840 }
841
842
843 /* Deallocate all of the memory associated with a table */
844
845 hash_destroy(h)
846 struct hash *h;
847 {
848     register struct bucket *b, **p, *b1;
849
850     for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
851         for (b = *p; b; b = b1) {
852             b1 = b->next;
853             free(b);
854         }
855     }
856 }
This page took 0.092953 seconds and 3 git commands to generate.