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