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