]> andersk Git - moira.git/blame - gen/mailhub.dc
Enforce table locking hierarchy
[moira.git] / gen / mailhub.dc
CommitLineData
bac4ceaa 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>
20EXEC SQL INCLUDE sqlca;
21
22
23extern int errno;
24char *whoami = "mailhub.gen";
25char *perm_malloc();
26char *pstrsave();
27char *divide = "##############################################################";
28
29#define ML_WID 72
9e1513ae 30#define AL_MAX_WID 592
bac4ceaa 31
32#define FALSE 0
33#define TRUE (!FALSE)
34
35FILE *out= stdout;
36
37
38main(argc, argv)
39int argc;
40char **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
9e1513ae 50 EXEC SQL CONNECT moira;
51 EXEC SQL SET LOCKMODE SESSION WHERE LEVEL=TABLE, READLOCK=SHARED;
bac4ceaa 52#endsql
53#ifsql INFORMIX
9e1513ae 54 EXEC SQL DATABASE moira;
bac4ceaa 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
110struct hash *users, *machines, *strings, *lists, *names;
111struct user {
112 char *login;
113 char *first;
114 char *last;
115 char mi;
116 char *pobox;
117};
118struct member {
119 struct member *next;
120 char *name;
121 int list_id;
122};
123struct list {
124 char *name;
125 char maillist;
492f333e 126 char *description;
bac4ceaa 127 char acl_t;
128 int acl_id;
129 struct member *m;
130};
131struct names {
132 char *name;
133 struct names *next;
134 int keep:1;
135 int id:31;
136};
137
138
139get_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
9e1513ae 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 */
bac4ceaa 154 EXEC SQL WHENEVER SQLERROR GOTO sqlerr;
155
b188943c 156 /* Get Locks */
157
158 EXEC SQL SELECT modtime INTO :buf FROM imembers WHERE list_id = 0;
bac4ceaa 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;
4534b281 163 machines = create_hash(1000);
bac4ceaa 164
165 EXEC SQL DECLARE m_cursor CURSOR FOR
9e1513ae 166 SELECT mach_id, name
167 FROM machine
4534b281 168 WHERE status=1
9e1513ae 169 ORDER BY mach_id;
bac4ceaa 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;
9e1513ae 192 strings = create_hash(11001);
bac4ceaa 193
194 EXEC SQL DECLARE s_cursor CURSOR FOR
9e1513ae 195 SELECT string_id, trim(string)
196 FROM strings
197 ORDER BY string_id;
bac4ceaa 198 EXEC SQL OPEN s_cursor;
199 while (1) {
200 EXEC SQL FETCH s_cursor INTO :id, :name;
201 if (sqlca.sqlcode != 0) break;
9e1513ae 202 if (hash_store(strings, id, pstrsave(name)) < 0) {
bac4ceaa 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;
9e1513ae 213 users = create_hash(13001);
bac4ceaa 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
9e1513ae 218 WHERE status != 3
219 ORDER BY users_id;
bac4ceaa 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;
9e1513ae 248 EXEC SQL COMMIT;
bac4ceaa 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
492f333e 255 SELECT list_id, name, maillist, description, acl_type, acl_id
bac4ceaa 256 FROM list
9e1513ae 257 WHERE active != 0
258 ORDER BY list_id;
bac4ceaa 259 EXEC SQL OPEN l_cursor;
260 while (1) {
492f333e 261 EXEC SQL FETCH l_cursor INTO :id, :name, :maillistp, :buf, :type, :acl;
bac4ceaa 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;
492f333e 266 l->description = pstrsave(strtrim(buf));
bac4ceaa 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;
9e1513ae 277 EXEC SQL COMMIT;
bac4ceaa 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
9e1513ae 285 WHERE direct = 1
286 ORDER BY list_id;
bac4ceaa 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
326save_mlist(id, l, force)
327int id;
328struct list *l;
329int 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;
566f0499 344 insert_name(l->name, -1, TRUE, FALSE);
9e1513ae 345 output_mlist(id, l);
bac4ceaa 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
357insert_login(id, u, dummy)
358int id;
359struct user *u;
360int dummy;
361{
362 if (u->pobox && u->login[0] != '#')
363 insert_name(u->login, id, TRUE, FALSE);
364}
365
366void insert_names(id, u, dummy)
367int id;
368struct user *u;
369int 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
384int incount = 0;
385
386insert_name(s, id, nodups, copy)
387char *s;
388int id;
389int nodups;
390int 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
3ce369ab 447/* Illegal chars: ! " % ( ) , / : ; < = > @ [ \ ] ^ { | } */
bac4ceaa 448
449static 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 - ^_ */
3ce369ab 452 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, /* SPACE - / */
bac4ceaa 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
471int hashstr(s)
472register 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
493sort_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
506output_data(dummy, nms, out)
507int dummy;
508struct names *nms;
509FILE *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
534int lwid, bol, awid;
535
536output_mlist(id, l)
537int id;
538register struct list *l;
539{
540 struct list *l1;
541 register struct member *m;
542 register struct user *u;
543
492f333e 544 put_fill(out, l->description);
bac4ceaa 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
569do_member(out, s)
570FILE *out;
571register 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) {
ac5e3058 579 fprintf(out, ",\n\tcontinuation%d\ncontinuation%d: ", cont, cont);
bac4ceaa 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
492f333e 604put_fill(aliases, string)
605FILE *aliases;
606register 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
bac4ceaa 651do_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
662char *perm_malloc(size)
663unsigned 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;
cf813189 675 pool = (char *)(((unsigned) (pool + 3)) & ~3);
bac4ceaa 676 pool_size -= (pool - ret);
677 return(ret);
678}
679
680
681/*
682 * Make a (permenant) copy of a string.
683 */
684char *
685pstrsave(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
707struct hash *create_hash(size)
708int 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
729char *hash_lookup(h, key)
730struct hash *h;
731register 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
749int hash_update(h, key, value)
750struct hash *h;
751register int key;
752char *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
771int hash_store(h, key, value)
772struct hash *h;
773register int key;
774char *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
809hash_search(h, value, callback)
810struct hash *h;
811register char *value;
812void (*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
828hash_step(h, callback, hint)
829struct hash *h;
830void (*callback)();
831char *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
845hash_destroy(h)
846struct 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 3.751947 seconds and 5 git commands to generate.