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