]> andersk Git - moira.git/blame - gen/mailhub.dc
Diane Delgado's changes for a fixed table-locking order
[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
741abed8 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);
2796e83d 320 critical_alert("DCM", "Mailhub build encountered DATABASE ERROR %d",
bac4ceaa 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;
2796e83d 575 char str[8];
bac4ceaa 576
577 wwid = strlen(s);
578
579 if (!bol && awid + wwid + 2 > AL_MAX_WID) {
2796e83d 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);
bac4ceaa 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
492f333e 609put_fill(aliases, string)
610FILE *aliases;
611register 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
bac4ceaa 656do_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
667char *perm_malloc(size)
668unsigned 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;
cf813189 680 pool = (char *)(((unsigned) (pool + 3)) & ~3);
bac4ceaa 681 pool_size -= (pool - ret);
682 return(ret);
683}
684
685
686/*
687 * Make a (permenant) copy of a string.
688 */
689char *
690pstrsave(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
712struct hash *create_hash(size)
713int 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
734char *hash_lookup(h, key)
735struct hash *h;
736register 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
754int hash_update(h, key, value)
755struct hash *h;
756register int key;
757char *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
776int hash_store(h, key, value)
777struct hash *h;
778register int key;
779char *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
814hash_search(h, value, callback)
815struct hash *h;
816register char *value;
817void (*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
833hash_step(h, callback, hint)
834struct hash *h;
835void (*callback)();
836char *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
850hash_destroy(h)
851struct 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.11393 seconds and 5 git commands to generate.