Add BSD license file
[platform/upstream/db4.git] / dist / api_flags.c
1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 1996-2009 Oracle.  All rights reserved.
5  */
6
7 #include <sys/types.h>
8
9 #include <ctype.h>
10 #include <errno.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15
16 typedef struct {
17         char    *name;                  /* API name */
18
19         u_int   used_mask;              /* Bits used. */
20 } API;
21 API     **api_list, **api_end;
22
23 typedef struct {
24         char     *name;                 /* Flag name */
25
26         int     api_cnt;                /* APIs that use this flag. */
27         API     **api, **api_end;
28
29         u_int   value;                  /* Bit value */
30 } FLAG;
31 FLAG    **flag_list, **flag_end;
32
33 int     verbose;
34 char    *progname;
35
36 int     add_entry(char *, char *);
37 void    define_print(char *, u_int);
38 void    dump_api(void);
39 void    dump_flags(void);
40 int     flag_cmp_alpha(const void *, const void *);
41 int     flag_cmp_api_cnt(const void *, const void *);
42 int     generate_flags(void);
43 int     parse(void);
44 void    print_api_mask(void);
45 void    print_api_remainder(void);
46 void    print_flag_value(void);
47 int     syserr(void);
48 int     usage(void);
49
50 int
51 main(int argc, char *argv[])
52 {
53         enum { API_MASK, API_REMAINDER, FLAG_VALUE } output;
54         int ch;
55
56         if ((progname = strrchr(argv[0], '/')) == NULL)
57                 progname = argv[0];
58         else
59                 ++progname;
60
61         output = FLAG_VALUE;
62         while ((ch = getopt(argc, argv, "mrv")) != EOF)
63                 switch (ch) {
64                 case 'm':
65                         output = API_MASK;
66                         break;
67                 case 'r':
68                         output = API_REMAINDER;
69                         break;
70                 case 'v':
71                         verbose = 1;
72                         break;
73                 case '?':
74                 default:
75                         return (usage());
76                 }
77         argc -= optind;
78         argv += optind;
79
80         if (parse() || generate_flags())
81                 return (EXIT_FAILURE);
82
83         switch (output) {
84         case API_MASK:
85                 print_api_mask();
86                 break;
87         case API_REMAINDER:
88                 print_api_remainder();
89                 break;
90         case FLAG_VALUE:
91                 print_flag_value();
92                 break;
93         }
94
95         if (verbose) {
96                 dump_api();
97                 dump_flags();
98         }
99
100         return (EXIT_SUCCESS);
101 }
102
103 int
104 parse()
105 {
106         int lc;
107         char *p, *api, buf[256];
108
109         api = NULL;
110
111         /*
112          * Read the method name/flag pairs.
113          */
114         for (lc = 1; fgets(buf, sizeof(buf), stdin) != NULL; ++lc) {
115                 if ((p = strchr(buf, '\n')) != NULL)
116                         *p = '\0';
117                 else {
118                         fprintf(
119                             stderr, "%s: %d: line too long\n", progname, lc);
120                         return (1);
121                 }
122
123                 /* Ignore any empty line or hash mark. */
124                 if (buf[0] == '\0' || buf[0] == '#')
125                         continue;
126
127                 /*
128                  * A line without leading whitespace is an API name, a line
129                  * with leading whitespace is a flag name.
130                  */
131                 if (isspace(buf[0])) {
132                         if ((p = strtok(buf, " \t")) == NULL || *p == '#')
133                                 continue;
134
135                         /* A flag without an API makes no sense. */
136                         if (api == NULL)
137                                 goto format;
138
139                         /* Enter the pair into the array. */
140                         if (add_entry(api, p))
141                                 return (1);
142                 } else {
143                         if ((p = strtok(buf, " \t")) == NULL)
144                                 continue;
145                         if (api != NULL)
146                                 free(api);
147                         if ((api = strdup(p)) == NULL)
148                                 return (syserr());
149                 }
150                 if ((p = strtok(NULL, " \t")) != NULL && *p != '#')
151                         goto format;
152         }
153
154         return (0);
155
156 format: fprintf(stderr, "%s: format error: line %d\n", progname, lc);
157         return (1);
158 }
159
160 int
161 add_entry(char *api_name, char *flag_name)
162 {
163         FLAG **fpp, *fp;
164         API **app, *ap, **p;
165         u_int cnt;
166
167         /* Search for this api's API structure. */
168         for (app = api_list;
169             app != NULL && *app != NULL && app < api_end; ++app)
170                 if (strcmp(api_name, (*app)->name) == 0)
171                         break;
172
173         /* Allocate new space in the API array if necessary. */
174         if (app == NULL || app == api_end) {
175                 cnt = app == NULL ? 100 : (u_int)(api_end - api_list) + 100;
176                 if ((api_list = realloc(api_list, sizeof(API *) * cnt)) == NULL)
177                         return (syserr());
178                 api_end = api_list + cnt;
179                 app = api_list + (cnt - 100);
180                 memset(app, 0, (u_int)(api_end - app) * sizeof(API *));
181         }
182
183         /* Allocate a new API structure and fill in the name if necessary. */
184         if (*app == NULL &&
185             ((*app = calloc(sizeof(API), 1)) == NULL ||
186             ((*app)->name = strdup(api_name)) == NULL))
187                 return (syserr());
188
189         ap = *app;
190
191         /*
192          * There's a special keyword, "__MASK=<value>" that sets the initial
193          * flags value for an API, and so prevents those flag bits from being
194          * chosen for that API's flags.
195          */
196         if (strncmp(flag_name, "__MASK=", sizeof("__MASK=") - 1) == 0) {
197                 ap->used_mask |=
198                     strtoul(flag_name + sizeof("__MASK=") - 1, NULL, 0);
199                 return (0);
200         }
201
202         /* Search for this flag's FLAG structure. */
203         for (fpp = flag_list;
204             fpp != NULL && *fpp != NULL && fpp < flag_end; ++fpp)
205                 if (strcmp(flag_name, (*fpp)->name) == 0)
206                         break;
207
208         /* Realloc space in the FLAG array if necessary. */
209         if (fpp == NULL || fpp == flag_end) {
210                 cnt = fpp == NULL ? 100 : (u_int)(flag_end - flag_list) + 100;
211                 if ((flag_list =
212                     realloc(flag_list, sizeof(FLAG *) * cnt)) == NULL)
213                         return (syserr());
214                 flag_end = flag_list + cnt;
215                 fpp = flag_list + (cnt - 100);
216                 memset(fpp, 0, (u_int)(flag_end - fpp) * sizeof(FLAG *));
217         }
218
219         /* Allocate a new FLAG structure and fill in the name if necessary. */
220         if (*fpp == NULL &&
221             ((*fpp = calloc(sizeof(FLAG), 1)) == NULL ||
222             ((*fpp)->name = strdup(flag_name)) == NULL))
223                 return (syserr());
224
225         fp = *fpp;
226         ++fp->api_cnt;
227
228         /* Check to see if this API is already listed for this flag. */
229         for (p = fp->api; p != NULL && *p != NULL && p < fp->api_end; ++p)
230                 if (strcmp(api_name, (*p)->name) == 0) {
231                         fprintf(stderr,
232                             "duplicate entry: %s / %s\n", api_name, flag_name);
233                         return (1);
234                 }
235
236         /* Realloc space in the FLAG's API array if necessary. */
237         if (p == NULL || p == fp->api_end) {
238                 cnt = p == NULL ? 20 : (u_int)(fp->api_end - fp->api) + 20;
239                 if ((fp->api = realloc(fp->api, sizeof(API *) * cnt)) == NULL)
240                         return (syserr());
241                 fp->api_end = fp->api + cnt;
242                 p = fp->api + (cnt - 20);
243                 memset(p, 0, (u_int)(fp->api_end - fp->api) * sizeof(API *));
244         }
245         *p = ap;
246
247         return (0);
248 }
249
250 void
251 dump_api()
252 {
253         API **app;
254
255         printf("=============================\nAPI:\n");
256         for (app = api_list; *app != NULL; ++app)
257                 printf("%s (%#x)\n", (*app)->name, (*app)->used_mask);
258 }
259
260 void
261 dump_flags()
262 {
263         FLAG **fpp;
264         API **api;
265         char *sep;
266
267         printf("=============================\nFLAGS:\n");
268         for (fpp = flag_list; *fpp != NULL; ++fpp) {
269                 printf("%s (%#x, %d): ",
270                     (*fpp)->name, (*fpp)->value, (*fpp)->api_cnt);
271                 sep = "";
272                 for (api = (*fpp)->api; *api != NULL; ++api) {
273                         printf("%s%s", sep, (*api)->name);
274                         sep = ", ";
275                 }
276                 printf("\n");
277         }
278 }
279
280 int
281 flag_cmp_api_cnt(const void *a, const void *b)
282 {
283         FLAG *af, *bf;
284
285         af = *(FLAG **)a;
286         bf = *(FLAG **)b;
287
288         if (af == NULL) {
289                 if (bf == NULL)
290                         return (0);
291                 return (1);
292         }
293         if (bf == NULL) {
294                 if (af == NULL)
295                         return (0);
296                 return (-1);
297         }
298         if (af->api_cnt > bf->api_cnt)
299                 return (-1);
300         if (af->api_cnt < bf->api_cnt)
301                 return (1);
302         return (strcmp(af->name, bf->name));
303 }
304
305 int
306 generate_flags()
307 {
308         FLAG **fpp;
309         API **api;
310         u_int mask;
311
312         /* Sort the FLAGS array by reference count, in reverse order. */
313         qsort(flag_list,
314             (u_int)(flag_end - flag_list), sizeof(FLAG *), flag_cmp_api_cnt);
315
316         /*
317          * Here's the plan: walk the list of flags, allocating bits.  For
318          * each flag, we walk the list of APIs that use it and find a bit
319          * none of them are using.  That bit becomes the flag's value.
320          */
321         for (fpp = flag_list; *fpp != NULL; ++fpp) {
322                 mask = 0xffffffff;                      /* Set to all 1's */
323                 for (api = (*fpp)->api; *api != NULL; ++api)
324                         mask &= ~(*api)->used_mask;     /* Clear API's bits */
325                 if (mask == 0) {
326                         fprintf(stderr, "%s: ran out of bits at flag %s\n",
327                            progname, (*fpp)->name);
328                         return (1);
329                 }
330                 (*fpp)->value = mask = 1 << (ffs(mask) - 1);
331                 for (api = (*fpp)->api; *api != NULL; ++api)
332                         (*api)->used_mask |= mask;      /* Set bit for API */
333         }
334
335         return (0);
336 }
337
338 int
339 flag_cmp_alpha(const void *a, const void *b)
340 {
341         FLAG *af, *bf;
342
343         af = *(FLAG **)a;
344         bf = *(FLAG **)b;
345
346         if (af == NULL) {
347                 if (bf == NULL)
348                         return (0);
349                 return (1);
350         }
351         if (bf == NULL) {
352                 if (af == NULL)
353                         return (0);
354                 return (-1);
355         }
356         return (strcmp(af->name, bf->name));
357 }
358
359 void
360 print_api_mask()
361 {
362         API **app;
363         char *p, buf[256];
364
365         /* Output a mask for the API. */
366         for (app = api_list; *app != NULL; ++app) {
367                 (void)snprintf(
368                     buf, sizeof(buf), "_%s_API_MASK", (*app)->name);
369                 for (p = buf; *p != '\0'; ++p)
370                         if (islower(*p))
371                                 *p = toupper(*p);
372                         else if (!isalpha(*p))
373                                 *p = '_';
374                 define_print(buf, (*app)->used_mask);
375         }
376 }
377
378 void
379 print_api_remainder()
380 {
381         API **app;
382         int unused, i;
383
384         /* Output the bits remaining for the API. */
385         for (app = api_list; *app != NULL; ++app) {
386                 for (i = unused = 0; i < 32; ++i)
387                         if (!((*app)->used_mask & (1 << i)))
388                                 ++unused;
389                 printf("%s: %d bits unused\n", (*app)->name, unused);
390         }
391 }
392
393 void
394 print_flag_value()
395 {
396         FLAG **fpp;
397
398         /* Sort the FLAGS array in alphabetical order. */
399         qsort(flag_list,
400             (u_int)(flag_end - flag_list), sizeof(FLAG *), flag_cmp_alpha);
401
402         /* Output each flag's value. */
403         for (fpp = flag_list; *fpp != NULL; ++fpp)
404                 define_print((*fpp)->name, (*fpp)->value);
405 }
406
407 void
408 define_print(char *name, u_int value)
409 {
410         char *sep;
411
412         switch (strlen(name) / 8) {
413         case 0:
414                 sep = "\t\t\t\t\t";
415                 break;
416         case 1:
417                 sep = "\t\t\t\t";
418                 break;
419         case 2:
420                 sep = "\t\t\t";
421                 break;
422         case 3:
423                 sep = "\t\t";
424                 break;
425         default:
426                 sep = "\t";
427                 break;
428         }
429         printf("#define\t%s%s%#010x\n", name, sep, value);
430 }
431
432 int
433 syserr(void)
434 {
435         fprintf(stderr, "%s: %s\n", progname, strerror(errno));
436         return (1);
437 }
438
439 int
440 usage()
441 {
442         (void)fprintf(stderr, "usage: %s [-mrv]\n", progname);
443         return (EXIT_FAILURE);
444 }