1 /* gen_tables.c -- Generator of lookup tables.
2 * Copyright 2008 Red Hat Inc., Durham, North Carolina.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Miloslav Trmač <mitr@redhat.com>
28 #include <linux/net.h>
34 #include <sys/personality.h>
35 #include <sys/mount.h>
39 #include "gen_tables.h"
41 #include "interpret.h"
43 /* This is from asm/ipc.h. Copying it for now as some platforms
44 * * have broken headers. */
59 /* The ratio of table size to number of non-empty elements allowed for a
60 "direct" s2i table; if the ratio would be bigger, bsearch tables are used
63 2 looks like a lot at a first glance, but the bsearch tables need twice as
64 much space per element, so with the ratio equal to 2 the direct table uses
65 no more memory and is faster. */
66 #define DIRECT_THRESHOLD 2
68 /* Allow more than one string defined for a single integer value */
69 static bool allow_duplicate_ints; /* = false; */
78 /* The mapping to store. */
79 static struct value values[] = {
80 #define _S(VAL, S) { (VAL), (S), 0, 0 },
85 #define NUM_VALUES (sizeof(values) / sizeof(*values))
87 /* Compare two "struct value" members by name. */
89 cmp_value_strings(const void *xa, const void *xb)
91 const struct value *a, *b;
95 return strcmp(a->s, b->s);
98 /* Compare two "struct value" members by value. */
100 cmp_value_vals(const void *xa, const void *xb)
102 const struct value *a, *b;
110 /* Preserve the original order if there is an ambiguity, to always use
111 the first specified value. */
112 if (a->orig_index > b->orig_index)
114 if (a->orig_index < b->orig_index)
119 /* Compare two "struct value" members by orig_index. */
121 cmp_value_orig_index(const void *xa, const void *xb)
123 const struct value *a, *b;
127 if (a->orig_index > b->orig_index)
129 if (a->orig_index < b->orig_index)
134 /* Output the string table, initialize values[*]->s_offset. */
136 output_strings(const char *prefix)
141 for (i = 0; i < NUM_VALUES; i++) {
142 values[i].s_offset = offset;
143 offset += strlen(values[i].s) + 1;
145 printf("static const char %s_strings[] = \"", prefix);
146 assert(NUM_VALUES > 0);
147 for (i = 0; i < NUM_VALUES; i++) {
150 if (i != 0 && i % 10 == 0)
153 for (c = values[i].s; *c != '\0'; c++) {
154 assert(*c != '"' && *c != '\\'
155 && isprint((unsigned char)*c));
158 if (i != NUM_VALUES - 1)
159 fputs("\\0", stdout);
161 fputs("\";\n", stdout);
164 /* Output the string to integer mapping code.
165 Assume strings are all uppsercase or all lowercase if specified by
166 parameters; in that case, make the search case-insensitive.
167 values must be sorted by strings. */
169 output_s2i(const char *prefix, bool uppercase, bool lowercase)
173 for (i = 0; i < NUM_VALUES - 1; i++) {
174 assert(strcmp(values[i].s, values[i + 1].s) <= 0);
175 if (strcmp(values[i].s, values[i + 1].s) == 0) {
176 fprintf(stderr, "Duplicate value `%s': %d, %d\n",
177 values[i].s, values[i].val, values[i + 1].val);
181 printf("static const unsigned %s_s2i_s[] = {", prefix);
182 for (i = 0; i < NUM_VALUES; i++) {
184 fputs("\n\t", stdout);
185 assert(values[i].s_offset <= UINT_MAX);
186 printf("%zu,", values[i].s_offset);
190 "static const int %s_s2i_i[] = {", prefix);
191 for (i = 0; i < NUM_VALUES; i++) {
193 fputs("\n\t", stdout);
194 printf("%d,", values[i].val);
198 assert(!(uppercase && lowercase));
200 for (i = 0; i < NUM_VALUES; i++) {
203 for (c = values[i].s; *c != '\0'; c++)
204 assert(isascii((unsigned char)*c)
207 } else if (lowercase) {
208 for (i = 0; i < NUM_VALUES; i++) {
211 for (c = values[i].s; *c != '\0'; c++)
212 assert(isascii((unsigned char)*c)
216 if (uppercase || lowercase) {
217 printf("static int %s_s2i(const char *s, int *value) {\n"
219 "\tlen = strlen(s);\n"
220 "\t{ char copy[len + 1];\n"
221 "\tfor (i = 0; i < len; i++) {\n"
222 "\t\tchar c = s[i];\n", prefix);
224 fputs("\t\tcopy[i] = GT_ISLOWER(c) ? c - 'a' + 'A' "
227 fputs("\t\tcopy[i] = GT_ISUPPER(c) ? c - 'A' + 'a' "
231 "\treturn s2i__(%s_strings, %s_s2i_s, %s_s2i_i, %zu, "
234 "}\n", prefix, prefix, prefix, NUM_VALUES);
236 printf("static int %s_s2i(const char *s, int *value) {\n"
237 "\treturn s2i__(%s_strings, %s_s2i_s, %s_s2i_i, %zu, s, "
239 "}\n", prefix, prefix, prefix, prefix, NUM_VALUES);
242 /* Output the string to integer mapping table.
243 values must be sorted by strings. */
245 output_i2s(const char *prefix)
247 struct value *unique_values;
248 int min_val, max_val;
251 assert(NUM_VALUES > 0);
252 for (i = 0; i < NUM_VALUES - 1; i++) {
253 assert(values[i].val <= values[i + 1].val);
254 if (!allow_duplicate_ints
255 && values[i].val == values[i + 1].val) {
256 fprintf(stderr, "Duplicate value %d: `%s', `%s'\n",
257 values[i].val, values[i].s, values[i + 1].s);
262 unique_values = malloc(NUM_VALUES * sizeof(*unique_values));
263 assert(unique_values != NULL);
265 for (i = 0; i < NUM_VALUES; i++) {
266 if (n == 0 || unique_values[n - 1].val != values[i].val) {
267 unique_values[n] = values[i];
272 min_val = unique_values[0].val;
273 max_val = unique_values[n - 1].val;
274 if (((double)max_val - (double)min_val) / n <= DIRECT_THRESHOLD) {
277 printf("static const unsigned %s_i2s_direct[] = {", prefix);
278 next_index = min_val;
281 if ((next_index - min_val) % 10 == 0)
282 fputs("\n\t", stdout);
283 while (unique_values[i].val < next_index)
284 /* This can happen if (allow_duplicate_ints) */
286 if (unique_values[i].val == next_index) {
287 assert(unique_values[i].s_offset <= UINT_MAX);
288 printf("%zu,", unique_values[i].s_offset);
290 fputs("-1u,", stdout);
291 if (next_index == max_val)
292 /* Done like this to avoid integer overflow */
298 "static const char *%s_i2s(int v) {\n"
299 "\treturn i2s_direct__(%s_strings, %s_i2s_direct, %d, "
301 "}\n", prefix, prefix, prefix, min_val, max_val);
303 printf("static const int %s_i2s_i[] = {", prefix);
304 for (i = 0; i < n; i++) {
306 fputs("\n\t", stdout);
307 printf("%d,", unique_values[i].val);
311 "static const unsigned %s_i2s_s[] = {", prefix);
312 for (i = 0; i < n; i++) {
314 fputs("\n\t", stdout);
315 assert(unique_values[i].s_offset <= UINT_MAX);
316 printf("%zu,", unique_values[i].s_offset);
320 "static const char *%s_i2s(int v) {\n"
321 "\treturn i2s_bsearch__(%s_strings, %s_i2s_i, %s_i2s_s, "
323 "}\n", prefix, prefix, prefix, prefix, n);
328 /* Output the string to integer mapping table as a transtab[].
329 values must be sorted in the desired order. */
331 output_i2s_transtab(const char *prefix)
336 printf("static const struct transtab %s_table[] = {", prefix);
337 for (i = 0; i < NUM_VALUES; i++) {
339 fputs("\n\t", stdout);
340 printf("{%d,%zu},", values[i].val, values[i].s_offset);
342 uc_prefix = strdup(prefix);
343 assert(uc_prefix != NULL);
344 for (i = 0; uc_prefix[i] != '\0'; i++)
345 uc_prefix[i] = toupper((unsigned char)uc_prefix[i]);
348 "#define %s_NUM_ENTRIES "
349 "(sizeof(%s_table) / sizeof(*%s_table))\n", uc_prefix, prefix,
355 main(int argc, char **argv)
357 bool gen_i2s, gen_i2s_transtab, gen_s2i, uppercase, lowercase;
361 /* This is required by gen_tables.h */
362 assert(NUM_VALUES <= (SSIZE_MAX / 2 + 1));
364 /* To make sure GT_ISUPPER and GT_ISLOWER work. */
365 assert('Z' == 'A' + 25 && 'z' == 'a' + 25);
367 gen_i2s_transtab = false;
373 for (i = 1; i < (size_t)argc; i++) {
374 if (strcmp(argv[i], "--i2s") == 0)
376 else if (strcmp(argv[i], "--i2s-transtab") == 0)
377 gen_i2s_transtab = true;
378 else if (strcmp(argv[i], "--s2i") == 0)
380 else if (strcmp(argv[i], "--uppercase") == 0)
382 else if (strcmp(argv[i], "--lowercase") == 0)
384 else if (strcmp(argv[i], "--duplicate-ints") == 0)
385 allow_duplicate_ints = true;
387 assert(*argv[i] != '-');
388 assert(prefix == NULL);
392 assert(prefix != NULL);
393 assert(!(uppercase && lowercase));
395 printf("/* This is a generated file, see Makefile.am for its "
397 for (i = 0; i < NUM_VALUES; i++)
398 values[i].orig_index = i;
399 qsort(values, NUM_VALUES, sizeof(*values), cmp_value_strings);
400 /* FIXME? if (gen_s2i), sort the strings in some other order
401 (e.g. "first 4 nodes in BFS of the bsearch tree first") to use the
403 /* FIXME? If the only thing generated is a transtab, keep the strings
404 in the original order to use the cache better. */
405 output_strings(prefix);
407 output_s2i(prefix, uppercase, lowercase);
409 qsort(values, NUM_VALUES, sizeof(*values), cmp_value_vals);
412 if (gen_i2s_transtab) {
413 qsort(values, NUM_VALUES, sizeof(*values),
414 cmp_value_orig_index);
415 output_i2s_transtab(prefix);