2011-09-13 17:48:33 +00:00
|
|
|
/*-
|
|
|
|
* See the file LICENSE for redistribution information.
|
|
|
|
*
|
2012-11-14 20:13:24 +00:00
|
|
|
* Copyright (c) 1996, 2012 Oracle and/or its affiliates. All rights reserved.
|
2011-09-13 17:48:33 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
char *name; /* API name */
|
|
|
|
|
|
|
|
u_int used_mask; /* Bits used. */
|
|
|
|
} API;
|
|
|
|
API **api_list, **api_end;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
char *name; /* Flag name */
|
|
|
|
|
|
|
|
int api_cnt; /* APIs that use this flag. */
|
|
|
|
API **api, **api_end;
|
|
|
|
|
|
|
|
u_int value; /* Bit value */
|
|
|
|
} FLAG;
|
|
|
|
FLAG **flag_list, **flag_end;
|
|
|
|
|
|
|
|
int verbose;
|
|
|
|
char *progname;
|
|
|
|
|
|
|
|
int add_entry(char *, char *);
|
|
|
|
void define_print(char *, u_int);
|
|
|
|
void dump_api(void);
|
|
|
|
void dump_flags(void);
|
|
|
|
int flag_cmp_alpha(const void *, const void *);
|
|
|
|
int flag_cmp_api_cnt(const void *, const void *);
|
|
|
|
int generate_flags(void);
|
|
|
|
int parse(void);
|
|
|
|
void print_api_mask(void);
|
|
|
|
void print_api_remainder(void);
|
|
|
|
void print_flag_value(void);
|
|
|
|
int syserr(void);
|
|
|
|
int usage(void);
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
enum { API_MASK, API_REMAINDER, FLAG_VALUE } output;
|
|
|
|
int ch;
|
|
|
|
|
|
|
|
if ((progname = strrchr(argv[0], '/')) == NULL)
|
|
|
|
progname = argv[0];
|
|
|
|
else
|
|
|
|
++progname;
|
|
|
|
|
|
|
|
output = FLAG_VALUE;
|
|
|
|
while ((ch = getopt(argc, argv, "mrv")) != EOF)
|
|
|
|
switch (ch) {
|
|
|
|
case 'm':
|
|
|
|
output = API_MASK;
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
output = API_REMAINDER;
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
verbose = 1;
|
|
|
|
break;
|
|
|
|
case '?':
|
|
|
|
default:
|
|
|
|
return (usage());
|
|
|
|
}
|
|
|
|
argc -= optind;
|
|
|
|
argv += optind;
|
|
|
|
|
|
|
|
if (parse() || generate_flags())
|
|
|
|
return (EXIT_FAILURE);
|
|
|
|
|
|
|
|
switch (output) {
|
|
|
|
case API_MASK:
|
|
|
|
print_api_mask();
|
|
|
|
break;
|
|
|
|
case API_REMAINDER:
|
|
|
|
print_api_remainder();
|
|
|
|
break;
|
|
|
|
case FLAG_VALUE:
|
|
|
|
print_flag_value();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (verbose) {
|
|
|
|
dump_api();
|
|
|
|
dump_flags();
|
|
|
|
}
|
|
|
|
|
|
|
|
return (EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
parse()
|
|
|
|
{
|
|
|
|
int lc;
|
|
|
|
char *p, *api, buf[256];
|
|
|
|
|
|
|
|
api = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read the method name/flag pairs.
|
|
|
|
*/
|
|
|
|
for (lc = 1; fgets(buf, sizeof(buf), stdin) != NULL; ++lc) {
|
|
|
|
if ((p = strchr(buf, '\n')) != NULL)
|
|
|
|
*p = '\0';
|
|
|
|
else {
|
|
|
|
fprintf(
|
|
|
|
stderr, "%s: %d: line too long\n", progname, lc);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Ignore any empty line or hash mark. */
|
|
|
|
if (buf[0] == '\0' || buf[0] == '#')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A line without leading whitespace is an API name, a line
|
|
|
|
* with leading whitespace is a flag name.
|
|
|
|
*/
|
|
|
|
if (isspace(buf[0])) {
|
|
|
|
if ((p = strtok(buf, " \t")) == NULL || *p == '#')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* A flag without an API makes no sense. */
|
|
|
|
if (api == NULL)
|
|
|
|
goto format;
|
|
|
|
|
|
|
|
/* Enter the pair into the array. */
|
|
|
|
if (add_entry(api, p))
|
|
|
|
return (1);
|
|
|
|
} else {
|
|
|
|
if ((p = strtok(buf, " \t")) == NULL)
|
|
|
|
continue;
|
|
|
|
if (api != NULL)
|
|
|
|
free(api);
|
|
|
|
if ((api = strdup(p)) == NULL)
|
|
|
|
return (syserr());
|
|
|
|
}
|
|
|
|
if ((p = strtok(NULL, " \t")) != NULL && *p != '#')
|
|
|
|
goto format;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
format: fprintf(stderr, "%s: format error: line %d\n", progname, lc);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
add_entry(char *api_name, char *flag_name)
|
|
|
|
{
|
|
|
|
FLAG **fpp, *fp;
|
|
|
|
API **app, *ap, **p;
|
|
|
|
u_int cnt;
|
|
|
|
|
|
|
|
/* Search for this api's API structure. */
|
|
|
|
for (app = api_list;
|
|
|
|
app != NULL && *app != NULL && app < api_end; ++app)
|
|
|
|
if (strcmp(api_name, (*app)->name) == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Allocate new space in the API array if necessary. */
|
|
|
|
if (app == NULL || app == api_end) {
|
|
|
|
cnt = app == NULL ? 100 : (u_int)(api_end - api_list) + 100;
|
|
|
|
if ((api_list = realloc(api_list, sizeof(API *) * cnt)) == NULL)
|
|
|
|
return (syserr());
|
|
|
|
api_end = api_list + cnt;
|
|
|
|
app = api_list + (cnt - 100);
|
|
|
|
memset(app, 0, (u_int)(api_end - app) * sizeof(API *));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate a new API structure and fill in the name if necessary. */
|
|
|
|
if (*app == NULL &&
|
|
|
|
((*app = calloc(sizeof(API), 1)) == NULL ||
|
|
|
|
((*app)->name = strdup(api_name)) == NULL))
|
|
|
|
return (syserr());
|
|
|
|
|
|
|
|
ap = *app;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* There's a special keyword, "__MASK=<value>" that sets the initial
|
|
|
|
* flags value for an API, and so prevents those flag bits from being
|
|
|
|
* chosen for that API's flags.
|
|
|
|
*/
|
|
|
|
if (strncmp(flag_name, "__MASK=", sizeof("__MASK=") - 1) == 0) {
|
|
|
|
ap->used_mask |=
|
|
|
|
strtoul(flag_name + sizeof("__MASK=") - 1, NULL, 0);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Search for this flag's FLAG structure. */
|
|
|
|
for (fpp = flag_list;
|
|
|
|
fpp != NULL && *fpp != NULL && fpp < flag_end; ++fpp)
|
|
|
|
if (strcmp(flag_name, (*fpp)->name) == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Realloc space in the FLAG array if necessary. */
|
|
|
|
if (fpp == NULL || fpp == flag_end) {
|
|
|
|
cnt = fpp == NULL ? 100 : (u_int)(flag_end - flag_list) + 100;
|
|
|
|
if ((flag_list =
|
|
|
|
realloc(flag_list, sizeof(FLAG *) * cnt)) == NULL)
|
|
|
|
return (syserr());
|
|
|
|
flag_end = flag_list + cnt;
|
|
|
|
fpp = flag_list + (cnt - 100);
|
|
|
|
memset(fpp, 0, (u_int)(flag_end - fpp) * sizeof(FLAG *));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate a new FLAG structure and fill in the name if necessary. */
|
|
|
|
if (*fpp == NULL &&
|
|
|
|
((*fpp = calloc(sizeof(FLAG), 1)) == NULL ||
|
|
|
|
((*fpp)->name = strdup(flag_name)) == NULL))
|
|
|
|
return (syserr());
|
|
|
|
|
|
|
|
fp = *fpp;
|
|
|
|
++fp->api_cnt;
|
|
|
|
|
|
|
|
/* Check to see if this API is already listed for this flag. */
|
|
|
|
for (p = fp->api; p != NULL && *p != NULL && p < fp->api_end; ++p)
|
|
|
|
if (strcmp(api_name, (*p)->name) == 0) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"duplicate entry: %s / %s\n", api_name, flag_name);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Realloc space in the FLAG's API array if necessary. */
|
|
|
|
if (p == NULL || p == fp->api_end) {
|
|
|
|
cnt = p == NULL ? 20 : (u_int)(fp->api_end - fp->api) + 20;
|
|
|
|
if ((fp->api = realloc(fp->api, sizeof(API *) * cnt)) == NULL)
|
|
|
|
return (syserr());
|
|
|
|
fp->api_end = fp->api + cnt;
|
|
|
|
p = fp->api + (cnt - 20);
|
|
|
|
memset(p, 0, (u_int)(fp->api_end - fp->api) * sizeof(API *));
|
|
|
|
}
|
|
|
|
*p = ap;
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dump_api()
|
|
|
|
{
|
|
|
|
API **app;
|
|
|
|
|
|
|
|
printf("=============================\nAPI:\n");
|
|
|
|
for (app = api_list; *app != NULL; ++app)
|
|
|
|
printf("%s (%#x)\n", (*app)->name, (*app)->used_mask);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dump_flags()
|
|
|
|
{
|
|
|
|
FLAG **fpp;
|
|
|
|
API **api;
|
|
|
|
char *sep;
|
|
|
|
|
|
|
|
printf("=============================\nFLAGS:\n");
|
|
|
|
for (fpp = flag_list; *fpp != NULL; ++fpp) {
|
|
|
|
printf("%s (%#x, %d): ",
|
|
|
|
(*fpp)->name, (*fpp)->value, (*fpp)->api_cnt);
|
|
|
|
sep = "";
|
|
|
|
for (api = (*fpp)->api; *api != NULL; ++api) {
|
|
|
|
printf("%s%s", sep, (*api)->name);
|
|
|
|
sep = ", ";
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
flag_cmp_api_cnt(const void *a, const void *b)
|
|
|
|
{
|
|
|
|
FLAG *af, *bf;
|
|
|
|
|
|
|
|
af = *(FLAG **)a;
|
|
|
|
bf = *(FLAG **)b;
|
|
|
|
|
|
|
|
if (af == NULL) {
|
|
|
|
if (bf == NULL)
|
|
|
|
return (0);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
if (bf == NULL) {
|
|
|
|
if (af == NULL)
|
|
|
|
return (0);
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
if (af->api_cnt > bf->api_cnt)
|
|
|
|
return (-1);
|
|
|
|
if (af->api_cnt < bf->api_cnt)
|
|
|
|
return (1);
|
|
|
|
return (strcmp(af->name, bf->name));
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
generate_flags()
|
|
|
|
{
|
|
|
|
FLAG **fpp;
|
|
|
|
API **api;
|
|
|
|
u_int mask;
|
|
|
|
|
|
|
|
/* Sort the FLAGS array by reference count, in reverse order. */
|
|
|
|
qsort(flag_list,
|
|
|
|
(u_int)(flag_end - flag_list), sizeof(FLAG *), flag_cmp_api_cnt);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Here's the plan: walk the list of flags, allocating bits. For
|
|
|
|
* each flag, we walk the list of APIs that use it and find a bit
|
|
|
|
* none of them are using. That bit becomes the flag's value.
|
|
|
|
*/
|
|
|
|
for (fpp = flag_list; *fpp != NULL; ++fpp) {
|
|
|
|
mask = 0xffffffff; /* Set to all 1's */
|
|
|
|
for (api = (*fpp)->api; *api != NULL; ++api)
|
|
|
|
mask &= ~(*api)->used_mask; /* Clear API's bits */
|
|
|
|
if (mask == 0) {
|
|
|
|
fprintf(stderr, "%s: ran out of bits at flag %s\n",
|
|
|
|
progname, (*fpp)->name);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
(*fpp)->value = mask = 1 << (ffs(mask) - 1);
|
|
|
|
for (api = (*fpp)->api; *api != NULL; ++api)
|
|
|
|
(*api)->used_mask |= mask; /* Set bit for API */
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
flag_cmp_alpha(const void *a, const void *b)
|
|
|
|
{
|
|
|
|
FLAG *af, *bf;
|
|
|
|
|
|
|
|
af = *(FLAG **)a;
|
|
|
|
bf = *(FLAG **)b;
|
|
|
|
|
|
|
|
if (af == NULL) {
|
|
|
|
if (bf == NULL)
|
|
|
|
return (0);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
if (bf == NULL) {
|
|
|
|
if (af == NULL)
|
|
|
|
return (0);
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
return (strcmp(af->name, bf->name));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
print_api_mask()
|
|
|
|
{
|
|
|
|
API **app;
|
|
|
|
char *p, buf[256];
|
|
|
|
|
|
|
|
/* Output a mask for the API. */
|
|
|
|
for (app = api_list; *app != NULL; ++app) {
|
|
|
|
(void)snprintf(
|
|
|
|
buf, sizeof(buf), "_%s_API_MASK", (*app)->name);
|
|
|
|
for (p = buf; *p != '\0'; ++p)
|
|
|
|
if (islower(*p))
|
|
|
|
*p = toupper(*p);
|
|
|
|
else if (!isalpha(*p))
|
|
|
|
*p = '_';
|
|
|
|
define_print(buf, (*app)->used_mask);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
print_api_remainder()
|
|
|
|
{
|
|
|
|
API **app;
|
|
|
|
int unused, i;
|
|
|
|
|
|
|
|
/* Output the bits remaining for the API. */
|
|
|
|
for (app = api_list; *app != NULL; ++app) {
|
|
|
|
for (i = unused = 0; i < 32; ++i)
|
|
|
|
if (!((*app)->used_mask & (1 << i)))
|
|
|
|
++unused;
|
|
|
|
printf("%s: %d bits unused\n", (*app)->name, unused);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
print_flag_value()
|
|
|
|
{
|
|
|
|
FLAG **fpp;
|
|
|
|
|
|
|
|
/* Sort the FLAGS array in alphabetical order. */
|
|
|
|
qsort(flag_list,
|
|
|
|
(u_int)(flag_end - flag_list), sizeof(FLAG *), flag_cmp_alpha);
|
|
|
|
|
|
|
|
/* Output each flag's value. */
|
|
|
|
for (fpp = flag_list; *fpp != NULL; ++fpp)
|
|
|
|
define_print((*fpp)->name, (*fpp)->value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
define_print(char *name, u_int value)
|
|
|
|
{
|
|
|
|
char *sep;
|
|
|
|
|
|
|
|
switch (strlen(name) / 8) {
|
|
|
|
case 0:
|
|
|
|
sep = "\t\t\t\t\t";
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
sep = "\t\t\t\t";
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
sep = "\t\t\t";
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
sep = "\t\t";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
sep = "\t";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
printf("#define\t%s%s%#010x\n", name, sep, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
syserr(void)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "%s: %s\n", progname, strerror(errno));
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
usage()
|
|
|
|
{
|
|
|
|
(void)fprintf(stderr, "usage: %s [-mrv]\n", progname);
|
|
|
|
return (EXIT_FAILURE);
|
|
|
|
}
|