chiark / gitweb /
New program to make fixed tables for universal hashing.
[mLib] / unihash-mkstatic.c
1 /* -*-c-*-
2  *
3  * $Id: unihash-mkstatic.c,v 1.1 2003/12/15 20:52:56 mdw Exp $
4  *
5  * Build static universal hash tables
6  *
7  * (c) 2003 Straylight/Edgeware
8  */
9
10 /*----- Licensing notice --------------------------------------------------* 
11  *
12  * This file is part of the mLib utilities library.
13  *
14  * mLib is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU Library General Public License as
16  * published by the Free Software Foundation; either version 2 of the
17  * License, or (at your option) any later version.
18  * 
19  * mLib is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU Library General Public License for more details.
23  * 
24  * You should have received a copy of the GNU Library General Public
25  * License along with mLib; if not, write to the Free
26  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27  * MA 02111-1307, USA.
28  */
29
30 /*----- Revision history --------------------------------------------------* 
31  *
32  * $Log: unihash-mkstatic.c,v $
33  * Revision 1.1  2003/12/15 20:52:56  mdw
34  * New program to make fixed tables for universal hashing.
35  *
36  */
37
38 /*----- Header files ------------------------------------------------------*/
39
40 #include <ctype.h>
41 #include <errno.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <stdlib.h>
45
46 #include "macros.h"
47 #include "mdwopt.h"
48 #include "quis.h"
49 #include "report.h"
50 #include "unihash.h"
51
52 /*----- Main code ---------------------------------------------------------*/
53
54 #define BSCOL 72
55
56 static unsigned long getint(const char *p, unsigned long max,
57                             const char *what)
58 {
59   char *pp;
60   unsigned long x = strtoul(p, &pp, 0);
61   if (*pp || (max && x > max))
62     die(EXIT_FAILURE, "bad %s `%s'", what, p);
63   return (x);
64 }
65
66 static void version(FILE *fp)
67 {
68   pquis(fp, "$, mLib version " VERSION "\n");
69 }
70
71 static void usage(FILE *fp)
72 {
73   pquis(fp, "Usage: $ [-c] [-o FILE] [-g GUARD] [-i HEADER] [-s SYM]\n\
74         [-k KEY]\n");
75 }
76
77 static void help(FILE *fp)
78 {
79   version(fp);
80   putc('\n', stdout);
81   usage(fp);
82   fputs("\n\
83 Emits a precomputed unihash_info structure for a given key.\n\
84 \n\
85 -h, --help              Show this help text.\n\
86 -v, --version           Show the program's version number.\n\
87 -u, --usage             Show a terse usage message.\n\
88 \n\
89 -c, --c-source          Emit a C source file rather than a header.\n\
90 -k, --key=KEY           Use KEY as the universal hashing key.\n\
91 -g, --guard=GUARD       Use GUARD as a multiple-inclusion guard constant.\n\
92 -i, --include=HEADER    Include HEADER at top of C source file.\n\
93 -s, --symbol=SYM        Name the generated table SYM.\n\
94 -o, --output=FILE       Write the output to FILE.\n\
95 ", stdout);
96 }
97
98 int main(int argc, char *argv[])
99 {
100   uint32 key = 0xe07e5bd1;
101   unsigned flags = 0;
102   const char *sym = 0;
103   const char *inc = 0;
104   const char *guard = 0;
105   const char *file = 0;
106   FILE *fp;
107   unihash_info u;
108   int i, j, k;
109
110 #define f_bogus 1u
111 #define f_ctab 2u
112
113   ego(argv[0]);
114
115   for (;;) {
116     static struct option opts[] = {
117       { "help",         0,              0,      'h' },
118       { "version",      0,              0,      'v' },
119       { "usage",        0,              0,      'u' },
120
121       { "output",       OPTF_ARGREQ,    0,      'o' },
122       { "c-source",     0,              0,      'c' },
123       { "key",          OPTF_ARGREQ,    0,      'k' },
124       { "symbol",       OPTF_ARGREQ,    0,      's' },
125       { "include",      OPTF_ARGREQ,    0,      'i' },
126       { "guard",        OPTF_ARGREQ,    0,      'g' },
127
128       { 0,              0,              0,      0 }
129     };
130     int i = mdwopt(argc, argv, "hvu o:ck:s:i:g:", opts, 0, 0, 0);
131
132     if (i < 0)
133       break;
134     switch (i) {
135       case 'h':
136         help(stdout);
137         exit(0);
138       case 'v':
139         version(stdout);
140         exit(0);
141       case 'u':
142         usage(stdout);
143         exit(0);
144
145       case 'o':
146         file = optarg;
147         break;
148       case 'c':
149         flags |= f_ctab;
150         break;
151       case 's':
152         sym = optarg;
153         break;
154       case 'i':
155         inc = optarg;
156         break;
157       case 'g':
158         guard = optarg;
159         break;
160       case 'k':
161         key = getint(optarg, 0xffffffff, "key");
162         break;
163
164       default:
165         flags |= f_bogus;
166         break;
167     }
168   }
169   if ((flags & f_bogus) || optind != argc) {
170     usage(stderr);
171     exit(EXIT_FAILURE);
172   }
173
174   /* --- Sort stuff out --- */
175
176   unihash_setkey(&u, key);
177   if (!sym)
178     sym = (flags & f_ctab) ? "uhi" : "UHI_INIT";
179   
180   /* --- Start output --- */
181
182   if (!file)
183     fp = stdout;
184   else {
185     if (!(flags & f_ctab) && !guard) {
186       char *p;
187       const char *q;
188       if ((p = malloc(strlen(file) + 1)) == 0)
189         die(EXIT_FAILURE, "not enough memory");
190       guard = p;
191       for (q = file; *q; p++, q++) {
192         if (isalnum((unsigned char)*q))
193           *p = toupper((unsigned char)*q);
194         else
195           *p = '_';
196       }
197       *p++ = 0;
198     }
199     if ((fp = fopen(file, "w")) == 0)
200       die(EXIT_FAILURE, "couldn't write `%s': %s", file, strerror(errno));
201   }
202
203   /* --- Dump out the first chunk of the file --- */
204
205   fprintf(fp, "\
206 /* -*-c-*-\n\
207  *\n\
208  * Unihash table (key = %08lx) [generated]\n\
209  */\n\
210 \n",
211           (unsigned long)key);
212
213   if (flags & f_ctab) {
214     if (inc)
215       fprintf(fp, "#include \"%s\"\n\n", inc);
216     else
217       fputs("#include <mLib/unihash.h>\n\n", fp);
218     fprintf(fp, "unihash_info %s = { {\n", sym);
219   } else {
220     int n;
221     if (guard)
222       fprintf(fp, "#ifndef %s\n#define %s\n\n", guard, guard);
223     n = fprintf(fp, "#define %s { {", sym);
224     while (n < BSCOL) {
225       fputc('\t', fp);
226       n = (n + 8) & ~7;
227     }
228     fputc('\n', fp);
229   }
230
231   /* --- Main output --- */
232
233   for (i = 0; i < N(u.s); i++) {
234     fputs("  {", fp);
235     for (j = 0; j < N(u.s[i]); j++) {
236       fputs(" {", fp);
237       for (k = 0; k < N(u.s[i][j]); k++) {
238         fprintf(fp, " 0x%08lx", (unsigned long)u.s[i][j][k]);
239         if (k < N(u.s[i][j]) - 1) {
240           fputc(',', fp);
241           if (k % 4 == 3)
242             fputs(flags & f_ctab ? "\n     " : "\t\t\t\\\n     ", fp);
243         }
244       }
245       if (j < N(u.s[i]) - 1) {
246         fputs(flags & f_ctab ? " },\n\n   " :
247                 " },\t\t\t\\\n\t\t\t\t\t\t\t\t\t\\\n   ", fp);
248       }
249     }
250     if (i < N(u.s) - 1) {
251       fputs(flags & f_ctab ? " } },\n\n" :
252             " } },\t\t\\\n\t\t\t\t\t\t\t\t\t\\\n", fp);
253     }
254   }
255
256   /* --- Done --- */
257
258   fputs(flags & f_ctab ? " } }\n} };\n" :
259         " } }\t\t\\\n} }\n", fp);
260   if (!(flags & f_ctab) && guard)
261     fputs("\n#endif\n", fp);
262
263   return (0);
264 }
265
266 /*----- That's all, folks -------------------------------------------------*/