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