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