2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996-2009 Oracle. All rights reserved.
17 char *name; /* API name */
19 u_int used_mask; /* Bits used. */
21 API **api_list, **api_end;
24 char *name; /* Flag name */
26 int api_cnt; /* APIs that use this flag. */
29 u_int value; /* Bit value */
31 FLAG **flag_list, **flag_end;
36 int add_entry(char *, char *);
37 void define_print(char *, u_int);
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);
44 void print_api_mask(void);
45 void print_api_remainder(void);
46 void print_flag_value(void);
51 main(int argc, char *argv[])
53 enum { API_MASK, API_REMAINDER, FLAG_VALUE } output;
56 if ((progname = strrchr(argv[0], '/')) == NULL)
62 while ((ch = getopt(argc, argv, "mrv")) != EOF)
68 output = API_REMAINDER;
80 if (parse() || generate_flags())
81 return (EXIT_FAILURE);
88 print_api_remainder();
100 return (EXIT_SUCCESS);
107 char *p, *api, buf[256];
112 * Read the method name/flag pairs.
114 for (lc = 1; fgets(buf, sizeof(buf), stdin) != NULL; ++lc) {
115 if ((p = strchr(buf, '\n')) != NULL)
119 stderr, "%s: %d: line too long\n", progname, lc);
123 /* Ignore any empty line or hash mark. */
124 if (buf[0] == '\0' || buf[0] == '#')
128 * A line without leading whitespace is an API name, a line
129 * with leading whitespace is a flag name.
131 if (isspace(buf[0])) {
132 if ((p = strtok(buf, " \t")) == NULL || *p == '#')
135 /* A flag without an API makes no sense. */
139 /* Enter the pair into the array. */
140 if (add_entry(api, p))
143 if ((p = strtok(buf, " \t")) == NULL)
147 if ((api = strdup(p)) == NULL)
150 if ((p = strtok(NULL, " \t")) != NULL && *p != '#')
156 format: fprintf(stderr, "%s: format error: line %d\n", progname, lc);
161 add_entry(char *api_name, char *flag_name)
167 /* Search for this api's API structure. */
169 app != NULL && *app != NULL && app < api_end; ++app)
170 if (strcmp(api_name, (*app)->name) == 0)
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)
178 api_end = api_list + cnt;
179 app = api_list + (cnt - 100);
180 memset(app, 0, (u_int)(api_end - app) * sizeof(API *));
183 /* Allocate a new API structure and fill in the name if necessary. */
185 ((*app = calloc(sizeof(API), 1)) == NULL ||
186 ((*app)->name = strdup(api_name)) == NULL))
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.
196 if (strncmp(flag_name, "__MASK=", sizeof("__MASK=") - 1) == 0) {
198 strtoul(flag_name + sizeof("__MASK=") - 1, NULL, 0);
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)
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;
212 realloc(flag_list, sizeof(FLAG *) * cnt)) == NULL)
214 flag_end = flag_list + cnt;
215 fpp = flag_list + (cnt - 100);
216 memset(fpp, 0, (u_int)(flag_end - fpp) * sizeof(FLAG *));
219 /* Allocate a new FLAG structure and fill in the name if necessary. */
221 ((*fpp = calloc(sizeof(FLAG), 1)) == NULL ||
222 ((*fpp)->name = strdup(flag_name)) == NULL))
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) {
232 "duplicate entry: %s / %s\n", api_name, flag_name);
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)
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 *));
255 printf("=============================\nAPI:\n");
256 for (app = api_list; *app != NULL; ++app)
257 printf("%s (%#x)\n", (*app)->name, (*app)->used_mask);
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);
272 for (api = (*fpp)->api; *api != NULL; ++api) {
273 printf("%s%s", sep, (*api)->name);
281 flag_cmp_api_cnt(const void *a, const void *b)
298 if (af->api_cnt > bf->api_cnt)
300 if (af->api_cnt < bf->api_cnt)
302 return (strcmp(af->name, bf->name));
312 /* Sort the FLAGS array by reference count, in reverse order. */
314 (u_int)(flag_end - flag_list), sizeof(FLAG *), flag_cmp_api_cnt);
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.
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 */
326 fprintf(stderr, "%s: ran out of bits at flag %s\n",
327 progname, (*fpp)->name);
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 */
339 flag_cmp_alpha(const void *a, const void *b)
356 return (strcmp(af->name, bf->name));
365 /* Output a mask for the API. */
366 for (app = api_list; *app != NULL; ++app) {
368 buf, sizeof(buf), "_%s_API_MASK", (*app)->name);
369 for (p = buf; *p != '\0'; ++p)
372 else if (!isalpha(*p))
374 define_print(buf, (*app)->used_mask);
379 print_api_remainder()
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)))
389 printf("%s: %d bits unused\n", (*app)->name, unused);
398 /* Sort the FLAGS array in alphabetical order. */
400 (u_int)(flag_end - flag_list), sizeof(FLAG *), flag_cmp_alpha);
402 /* Output each flag's value. */
403 for (fpp = flag_list; *fpp != NULL; ++fpp)
404 define_print((*fpp)->name, (*fpp)->value);
408 define_print(char *name, u_int value)
412 switch (strlen(name) / 8) {
429 printf("#define\t%s%s%#010x\n", name, sep, value);
435 fprintf(stderr, "%s: %s\n", progname, strerror(errno));
442 (void)fprintf(stderr, "usage: %s [-mrv]\n", progname);
443 return (EXIT_FAILURE);