Print this page
2nd round review feedback from rmustacc.


  57         "/opt/gcc/4.4.4/bin/gcc",
  58         "/opt/sunstudio12.1/bin/cc",
  59         "/opt/sfw/bin/gcc",
  60         "/usr/local/bin/gcc",
  61         NULL
  62 };
  63 
  64 char *compiler = NULL;
  65 const char *c89flags = NULL;
  66 const char *c99flags = NULL;
  67 
  68 #define MAXENV  64      /* maximum number of environments (bitmask width) */
  69 #define MAXHDR  10      /* maximum # headers to require to access symbol */
  70 #define MAXARG  20      /* maximum # of arguments */
  71 
  72 #define WS      " \t"
  73 
  74 static int next_env = 0;
  75 
  76 struct compile_env {
  77         char            *name;
  78         char            *lang;
  79         char            *defs;
  80         int             index;
  81 };
  82 
  83 static struct compile_env compile_env[MAXENV];
  84 
  85 struct env_group {
  86         char                    *name;
  87         uint64_t                mask;
  88         struct env_group        *next;
  89 };
  90 
  91 typedef enum { SYM_TYPE, SYM_VALUE, SYM_FUNC } sym_type_t;
  92 
  93 struct sym_test {
  94         char                    *name;
  95         sym_type_t              type;
  96         char                    *hdrs[MAXHDR];
  97         char                    *rtype;
  98         char                    *atypes[MAXARG];
  99         uint64_t                test_mask;
 100         uint64_t                need_mask;
 101         char                    *prog;
 102         struct sym_test         *next;
 103 };
 104 
 105 struct env_group *env_groups = NULL;
 106 
 107 struct sym_test *sym_tests = NULL;
 108 struct sym_test **sym_insert = &sym_tests;
 109 
 110 static char *
 111 mystrdup(const char *s)
 112 {
 113         char *r;
 114         if ((r = strdup(s)) == NULL) {
 115                 perror("strdup");
 116                 exit(1);
 117         }
 118         return (r);
 119 }
 120 
 121 static void *
 122 myzalloc(size_t sz)


 130 }
 131 
 132 static void
 133 myasprintf(char **buf, const char *fmt, ...)
 134 {
 135         int rv;
 136         va_list va;
 137         va_start(va, fmt);
 138         rv = vasprintf(buf, fmt, va);
 139         va_end(va);
 140         if (rv < 0) {
 141                 perror("vasprintf");
 142                 exit(1);
 143         }
 144 }
 145 
 146 static void
 147 append_sym_test(struct sym_test *st)
 148 {
 149         *sym_insert = st;
 150         sym_insert = &st->next;
 151 }
 152 
 153 static int
 154 find_env_mask(const char *name, uint64_t *mask)
 155 {
 156         for (int i = 0; i < 64; i++) {
 157                 if (compile_env[i].name != NULL &&
 158                     strcmp(compile_env[i].name, name) == 0) {
 159                         *mask |= (1ULL << i);
 160                         return (0);
 161                 }
 162         }
 163 
 164         for (struct env_group *eg = env_groups; eg != NULL; eg = eg->next) {
 165                 if (strcmp(name, eg->name) == 0) {
 166                         *mask |= eg->mask;
 167                         return (0);
 168                 }
 169         }
 170         return (-1);
 171 }
 172 
 173 
 174 static int
 175 expand_env(char *list, uint64_t *mask, char **erritem)
 176 {
 177         char *item;
 178         for (item = strtok(list, WS); item != NULL; item = strtok(NULL, WS)) {
 179                 if (find_env_mask(item, mask) < 0) {
 180                         if (erritem != NULL) {
 181                                 *erritem = item;
 182                         }
 183                         return (-1);
 184                 }
 185         }
 186         return (0);


 228 do_env(char **fields, int nfields, char **err)
 229 {
 230         char *name;
 231         char *lang;
 232         char *defs;
 233 
 234         if (nfields != 3) {
 235                 myasprintf(err, "number of fields (%d) != 3", nfields);
 236                 return (-1);
 237         }
 238 
 239         if (next_env >= MAXENV) {
 240                 myasprintf(err, "too many environments");
 241                 return (-1);
 242         }
 243 
 244         name = fields[0];
 245         lang = fields[1];
 246         defs = fields[2];
 247 
 248         compile_env[next_env].name = mystrdup(name);
 249         compile_env[next_env].lang = mystrdup(lang);
 250         compile_env[next_env].defs = mystrdup(defs);
 251         compile_env[next_env].index = next_env;
 252         next_env++;
 253         return (0);
 254 }
 255 
 256 static int
 257 do_env_group(char **fields, int nfields, char **err)
 258 {
 259         char *name;
 260         char *list;
 261         struct env_group *eg;
 262         uint64_t mask;
 263         char *item;
 264 
 265         if (nfields != 2) {
 266                 myasprintf(err, "number of fields (%d) != 2", nfields);
 267                 return (-1);
 268         }
 269 
 270         name = fields[0];
 271         list = fields[1];
 272         mask = 0;
 273 
 274         if (expand_env(list, &mask, &item) < 0) {
 275                 myasprintf(err, "reference to undefined env %s", item);
 276                 return (-1);
 277         }
 278 
 279         eg = myzalloc(sizeof (*eg));
 280         eg->name = mystrdup(name);
 281         eg->mask = mask;
 282         eg->next = env_groups;
 283         env_groups = eg;
 284         return (0);
 285 }
 286 
 287 static char *progbuf = NULL;
 288 size_t proglen = 0;
 289 size_t progsiz = 0;
 290 
 291 static void 
 292 addprogch(char c)
 293 {
 294         while (progsiz <= (proglen + 1)) {
 295                 progbuf = realloc(progbuf, progsiz + 4096);
 296                 if (progbuf == NULL) {
 297                         perror("realloc");
 298                         exit(1);
 299                 }
 300                 progsiz += 1024;
 301         }
 302         progbuf[proglen++] = c;


 317 {
 318         va_list va;
 319         char *buf = NULL;
 320         va_start(va, fmt);
 321         if (vasprintf(&buf, fmt, va) < 0) {
 322                 perror("vasprintf");
 323                 exit(1);
 324         }
 325         va_end(va);
 326         addprogstr(buf);
 327         free(buf);
 328 }
 329 
 330 static void
 331 mkprog(struct sym_test *st)
 332 {
 333         char *s;
 334 
 335         proglen = 0;
 336 
 337         for (int i = 0; i < MAXHDR && st->hdrs[i] != NULL; i++) {
 338                 addprogfmt("#include <%s>\n", st->hdrs[i]);
 339         }
 340 
 341         for (s = st->rtype; *s; s++) {
 342                 addprogch(*s);
 343                 if (*s == '(') {
 344                         s++;
 345                         addprogch(*s);
 346                         s++;
 347                         break;
 348                 }
 349         }
 350         addprogch(' ');
 351 
 352         /* for function pointers, s is closing suffix, otherwise empty */
 353 
 354         switch (st->type) {
 355         case SYM_TYPE:
 356                 addprogstr("test_type;");
 357                 break;
 358 
 359         case SYM_VALUE:
 360                 addprogfmt("test_value%s;\n", s);       /* s usually empty */
 361                 addprogstr("void\ntest_func(void)\n{\n");
 362                 addprogfmt("\ttest_value = %s;\n}", st->name);
 363                 break;
 364 
 365         case SYM_FUNC:
 366                 addprogstr("\ntest_func(");
 367                 for (int i = 0; st->atypes[i] != NULL && i < MAXARG; i++) {
 368                         int didname = 0;
 369                         if (i > 0) {
 370                                 addprogstr(", ");
 371                         }
 372                         if (strcmp(st->atypes[i], "void") == 0) {
 373                                 didname = 1;
 374                         }
 375                         if (strcmp(st->atypes[i], "") == 0) {
 376                                 didname = 1;
 377                                 addprogstr("void");
 378                         }
 379 
 380                         /* print the argument list */
 381                         for (char *a = st->atypes[i]; *a; a++) {
 382                                 if (*a == '(' && a[1] == '*' && !didname) {
 383                                         addprogfmt("(*a%d", i);
 384                                         didname = 1;
 385                                         a++;
 386                                 } else if (*a == '[' && !didname) {
 387                                         addprogfmt("a%d[", i);
 388                                         didname = 1;
 389                                 } else {
 390                                         addprogch(*a);
 391                                 }
 392                         }
 393                         if (!didname) {
 394                                 addprogfmt(" a%d", i);
 395                         }
 396                 }
 397 
 398                 if (st->atypes[0] == NULL) {
 399                         addprogstr("void");
 400                 }
 401 
 402                 /* close argument list, and closing ")" for func ptrs */
 403                 addprogfmt(")%s\n{\n\t", s);    /* NB: s is normally empty */





 404 
 405                 if (strcmp(st->rtype, "") != 0 &&
 406                     strcmp(st->rtype, "void") != 0) {
 407                         addprogstr("return ");
 408                 }
 409 
 410                 /* add the function call */
 411                 addprogfmt("%s(", st->name);
 412                 for (int i = 0; st->atypes[i] != NULL && i < MAXARG; i++) {
 413                         if (strcmp(st->atypes[i], "") != 0 &&
 414                             strcmp(st->atypes[i], "void") != 0) {
 415                                 addprogfmt("%sa%d", i > 0 ? ", " : "", i);
 416                         }
 417                 }
 418 
 419                 addprogstr(");\n}");
 420                 break;
 421         }
 422 
 423         addprogch('\n');
 424 
 425         st->prog = progbuf;
 426 }
 427 
 428 static int
 429 add_envs(struct sym_test *st, char *envs, char **err)
 430 {
 431         char *item;
 432         if (expand_env_list(envs, &st->test_mask, &st->need_mask, &item) < 0) {

 433                 myasprintf(err, "bad env action %s", item);
 434                 return (-1);
 435         }
 436         return (0);
 437 }
 438 
 439 static int
 440 add_headers(struct sym_test *st, char *hdrs, char **err)
 441 {
 442         int i = 0;
 443 
 444         for (char *h = strsep(&hdrs, ";"); h != NULL; h = strsep(&hdrs, ";")) {
 445                 if (i >= MAXHDR) {
 446                         myasprintf(err, "too many headers");
 447                         return (-1);
 448                 }
 449                 test_trim(&h);
 450                 st->hdrs[i++] = mystrdup(h);
 451         }
 452 
 453         return (0);
 454 }
 455 
 456 static int
 457 add_arg_types(struct sym_test *st, char *atype, char **err)
 458 {
 459         int i = 0;
 460         char *a;
 461         for (a = strsep(&atype, ";"); a != NULL; a = strsep(&atype, ";")) {
 462                 if (i >= MAXARG) {
 463                         myasprintf(err, "too many arguments");
 464                         return (-1);
 465                 }
 466                 test_trim(&a);
 467                 st->atypes[i++] = mystrdup(a);
 468         }
 469 
 470         return (0);
 471 }
 472 
 473 static int
 474 do_type(char **fields, int nfields, char **err)
 475 {
 476         char *decl;
 477         char *hdrs;
 478         char *envs;
 479         struct sym_test *st;
 480 
 481         if (nfields != 3) {
 482                 myasprintf(err, "number of fields (%d) != 3", nfields);
 483                 return (-1);
 484         }
 485         decl = fields[0];
 486         hdrs = fields[1];
 487         envs = fields[2];
 488 
 489         st = myzalloc(sizeof (*st));
 490         st->type = SYM_TYPE;
 491         st->name = mystrdup(decl);
 492         st->rtype = mystrdup(decl);
 493 
 494         if ((add_envs(st, envs, err) < 0) ||
 495             (add_headers(st, hdrs, err) < 0)) {
 496                 return (-1);
 497         }
 498         append_sym_test(st);
 499 
 500         return (0);
 501 }
 502 
 503 static int
 504 do_value(char **fields, int nfields, char **err)
 505 {
 506         char *name;
 507         char *type;
 508         char *hdrs;
 509         char *envs;
 510         struct sym_test *st;
 511 
 512         if (nfields != 4) {
 513                 myasprintf(err, "number of fields (%d) != 4", nfields);
 514                 return (-1);
 515         }
 516         name = fields[0];
 517         type = fields[1];
 518         hdrs = fields[2];
 519         envs = fields[3];
 520 
 521         st = myzalloc(sizeof (*st));
 522         st->type = SYM_VALUE;
 523         st->name = mystrdup(name);
 524         st->rtype = mystrdup(type);
 525 
 526         if ((add_envs(st, envs, err) < 0) ||
 527             (add_headers(st, hdrs, err) < 0)) {
 528                 return (-1);
 529         }
 530         append_sym_test(st);
 531 
 532         return (0);
 533 }
 534 
 535 static int
 536 do_func(char **fields, int nfields, char **err)
 537 {
 538         char *name;
 539         char *rtype;
 540         char *atype;
 541         char *hdrs;
 542         char *envs;
 543         struct sym_test *st;
 544 
 545         if (nfields != 5) {
 546                 myasprintf(err, "number of fields (%d) != 5", nfields);
 547                 return (-1);
 548         }
 549         name = fields[0];
 550         rtype = fields[1];
 551         atype = fields[2];
 552         hdrs = fields[3];
 553         envs = fields[4];
 554 
 555         st = myzalloc(sizeof (*st));
 556         st->type = SYM_FUNC;
 557         st->name = mystrdup(name);
 558         st->rtype = mystrdup(rtype);
 559 
 560         if ((add_envs(st, envs, err) < 0) ||
 561             (add_headers(st, hdrs, err) < 0) ||
 562             (add_arg_types(st, atype, err) < 0)) {
 563                 return (-1);
 564         }
 565         append_sym_test(st);
 566 
 567         return (0);
 568 }
 569 
 570 struct sym_test *
 571 next_sym_test(struct sym_test *st)
 572 {
 573         return (st == NULL ? sym_tests : st->next);
 574 }
 575 
 576 const char *
 577 sym_test_prog(struct sym_test *st)
 578 {
 579         if (st->prog == NULL) {
 580                 mkprog(st);
 581         }
 582         return (st->prog);
 583 }
 584 
 585 const char *
 586 sym_test_name(struct sym_test *st)
 587 {
 588         return (st->name);
 589 }
 590 
 591 /*
 592  * Iterate through tests.  Pass in NULL for cenv to begin the iteration. For
 593  * subsequent iterations, use the return value from the previous iteration.
 594  * Returns NULL when there are no more environments.
 595  */
 596 struct compile_env *
 597 sym_test_env(struct sym_test *st, struct compile_env *cenv, int *need)
 598 {
 599         int i = cenv ? cenv->index + 1: 0;
 600         uint64_t b = 1ULL << i;
 601 
 602         while ((i < MAXENV) && (b != 0)) {
 603                 cenv = &compile_env[i];
 604                 if (b & st->test_mask) {
 605                         *need = (st->need_mask & b) ? 1 : 0;
 606                         return (cenv);
 607                 }
 608                 b <<= 1;
 609                 i++;
 610         }
 611         return (NULL);
 612 }
 613 
 614 const char *
 615 env_name(struct compile_env *cenv)
 616 {
 617         return (cenv->name);
 618 }
 619 
 620 const char *
 621 env_lang(struct compile_env *cenv)
 622 {
 623         return (cenv->lang);
 624 }
 625 
 626 const char *
 627 env_defs(struct compile_env *cenv)
 628 {
 629         return (cenv->defs);
 630 }
 631 
 632 static void
 633 show_file(test_t t, const char *path)
 634 {
 635         FILE *f;
 636         char *buf = NULL;
 637         size_t cap = 0;
 638         int line = 1;
 639 
 640         f = fopen(path, "r");
 641         if (f == NULL) {
 642                 test_debugf(t, "fopen(%s): %s", path, strerror(errno));
 643                 return;
 644         }
 645 
 646         test_debugf(t, "----->> begin (%s) <<------", path);
 647         while (getline(&buf, &cap, f) >= 0) {
 648                 (void) strtok(buf, "\r\n");
 649                 test_debugf(t, "%d: %s", line, buf);


 755                 case 51:        /* STUDIO */
 756                         test_debugf(t, "Found Studio C");
 757                         c89flags = "-Xc -errwarn=%all -v -xc99=%none " MFLAG;
 758                         c99flags = "-Xc -errwarn=%all -v -xc99=%all " MFLAG;
 759                         if (extra_debug) {
 760                                 test_debugf(t, "c89flags: %s", c89flags);
 761                                 test_debugf(t, "c99flags: %s", c99flags);
 762                         }
 763                         test_passed(t);
 764                         break;
 765                 case 52:        /* GCC */
 766                         test_debugf(t, "Found GNU C");
 767                         c89flags = "-Wall -Werror -std=c89 " MFLAG;
 768                         c99flags = "-Wall -Werror -std=c99 " MFLAG;
 769                         if (extra_debug) {
 770                                 test_debugf(t, "c89flags: %s", c89flags);
 771                                 test_debugf(t, "c99flags: %s", c99flags);
 772                         }
 773                         test_passed(t);
 774                         break;



 775                 default:
 776                         continue;
 777                 }
 778                 myasprintf(&compiler, "%s", compilers[i]);
 779                 test_debugf(t, "compiler: %s", compiler);
 780                 return;
 781         }
 782         test_failed(t, "No compiler found.");
 783 }
 784 
 785 int
 786 do_compile(test_t t, struct sym_test *st, struct compile_env *cenv, int need)
 787 {
 788         char *cmd;
 789         FILE *logf;
 790         FILE *dotc;
 791         const char *prog;
 792 
 793         full_count++;
 794 


 852         good_count++;
 853         return (0);
 854 }
 855 
 856 void
 857 test_compile(void)
 858 {
 859         struct sym_test *st;
 860         struct compile_env *cenv;
 861         test_t t;
 862         int need;
 863 
 864         for (st = next_sym_test(NULL); st; st = next_sym_test(st)) {
 865                 if ((sym != NULL) && strcmp(sym, sym_test_name(st))) {
 866                         continue;
 867                 }
 868                 /* XXX: we really want a sym_test_desc() */
 869                 for (cenv = sym_test_env(st, NULL, &need);
 870                     cenv != NULL;
 871                     cenv = sym_test_env(st, cenv, &need)) {
 872                         t = test_start("%s : %c%s", st->name,
 873                             need ? '+' : '-', env_name(cenv));
 874                         if (do_compile(t, st, cenv, need) == 0) {
 875                                 test_passed(t);
 876                         }
 877                 }
 878         }
 879 
 880         if (full_count > 0) {
 881                 test_summary();
 882         }
 883 }
 884 
 885 int
 886 main(int argc, char **argv)
 887 {
 888         int optc;
 889         int optC = 0;
 890 
 891         while ((optc = getopt(argc, argv, "DdfCs:c:")) != EOF) {
 892                 switch (optc) {




  57         "/opt/gcc/4.4.4/bin/gcc",
  58         "/opt/sunstudio12.1/bin/cc",
  59         "/opt/sfw/bin/gcc",
  60         "/usr/local/bin/gcc",
  61         NULL
  62 };
  63 
  64 char *compiler = NULL;
  65 const char *c89flags = NULL;
  66 const char *c99flags = NULL;
  67 
  68 #define MAXENV  64      /* maximum number of environments (bitmask width) */
  69 #define MAXHDR  10      /* maximum # headers to require to access symbol */
  70 #define MAXARG  20      /* maximum # of arguments */
  71 
  72 #define WS      " \t"
  73 
  74 static int next_env = 0;
  75 
  76 struct compile_env {
  77         char            *ce_name;
  78         char            *ce_lang;
  79         char            *ce_defs;
  80         int             ce_index;
  81 };
  82 
  83 static struct compile_env compile_env[MAXENV];
  84 
  85 struct env_group {
  86         char                    *eg_name;
  87         uint64_t                eg_mask;
  88         struct env_group        *eg_next;
  89 };
  90 
  91 typedef enum { SYM_TYPE, SYM_VALUE, SYM_FUNC } sym_type_t;
  92 
  93 struct sym_test {
  94         char                    *st_name;
  95         sym_type_t              st_type;
  96         char                    *st_hdrs[MAXHDR];
  97         char                    *st_rtype;
  98         char                    *st_atypes[MAXARG];
  99         uint64_t                st_test_mask;
 100         uint64_t                st_need_mask;
 101         char                    *st_prog;
 102         struct sym_test         *st_next;
 103 };
 104 
 105 struct env_group *env_groups = NULL;
 106 
 107 struct sym_test *sym_tests = NULL;
 108 struct sym_test **sym_insert = &sym_tests;
 109 
 110 static char *
 111 mystrdup(const char *s)
 112 {
 113         char *r;
 114         if ((r = strdup(s)) == NULL) {
 115                 perror("strdup");
 116                 exit(1);
 117         }
 118         return (r);
 119 }
 120 
 121 static void *
 122 myzalloc(size_t sz)


 130 }
 131 
 132 static void
 133 myasprintf(char **buf, const char *fmt, ...)
 134 {
 135         int rv;
 136         va_list va;
 137         va_start(va, fmt);
 138         rv = vasprintf(buf, fmt, va);
 139         va_end(va);
 140         if (rv < 0) {
 141                 perror("vasprintf");
 142                 exit(1);
 143         }
 144 }
 145 
 146 static void
 147 append_sym_test(struct sym_test *st)
 148 {
 149         *sym_insert = st;
 150         sym_insert = &st->st_next;
 151 }
 152 
 153 static int
 154 find_env_mask(const char *name, uint64_t *mask)
 155 {
 156         for (int i = 0; i < MAXENV; i++) {
 157                 if (compile_env[i].ce_name != NULL &&
 158                     strcmp(compile_env[i].ce_name, name) == 0) {
 159                         *mask |= (1ULL << i);
 160                         return (0);
 161                 }
 162         }
 163 
 164         for (struct env_group *eg = env_groups; eg != NULL; eg = eg->eg_next) {
 165                 if (strcmp(name, eg->eg_name) == 0) {
 166                         *mask |= eg->eg_mask;
 167                         return (0);
 168                 }
 169         }
 170         return (-1);
 171 }
 172 
 173 
 174 static int
 175 expand_env(char *list, uint64_t *mask, char **erritem)
 176 {
 177         char *item;
 178         for (item = strtok(list, WS); item != NULL; item = strtok(NULL, WS)) {
 179                 if (find_env_mask(item, mask) < 0) {
 180                         if (erritem != NULL) {
 181                                 *erritem = item;
 182                         }
 183                         return (-1);
 184                 }
 185         }
 186         return (0);


 228 do_env(char **fields, int nfields, char **err)
 229 {
 230         char *name;
 231         char *lang;
 232         char *defs;
 233 
 234         if (nfields != 3) {
 235                 myasprintf(err, "number of fields (%d) != 3", nfields);
 236                 return (-1);
 237         }
 238 
 239         if (next_env >= MAXENV) {
 240                 myasprintf(err, "too many environments");
 241                 return (-1);
 242         }
 243 
 244         name = fields[0];
 245         lang = fields[1];
 246         defs = fields[2];
 247 
 248         compile_env[next_env].ce_name = mystrdup(name);
 249         compile_env[next_env].ce_lang = mystrdup(lang);
 250         compile_env[next_env].ce_defs = mystrdup(defs);
 251         compile_env[next_env].ce_index = next_env;
 252         next_env++;
 253         return (0);
 254 }
 255 
 256 static int
 257 do_env_group(char **fields, int nfields, char **err)
 258 {
 259         char *name;
 260         char *list;
 261         struct env_group *eg;
 262         uint64_t mask;
 263         char *item;
 264 
 265         if (nfields != 2) {
 266                 myasprintf(err, "number of fields (%d) != 2", nfields);
 267                 return (-1);
 268         }
 269 
 270         name = fields[0];
 271         list = fields[1];
 272         mask = 0;
 273 
 274         if (expand_env(list, &mask, &item) < 0) {
 275                 myasprintf(err, "reference to undefined env %s", item);
 276                 return (-1);
 277         }
 278 
 279         eg = myzalloc(sizeof (*eg));
 280         eg->eg_name = mystrdup(name);
 281         eg->eg_mask = mask;
 282         eg->eg_next = env_groups;
 283         env_groups = eg;
 284         return (0);
 285 }
 286 
 287 static char *progbuf = NULL;
 288 size_t proglen = 0;
 289 size_t progsiz = 0;
 290 
 291 static void 
 292 addprogch(char c)
 293 {
 294         while (progsiz <= (proglen + 1)) {
 295                 progbuf = realloc(progbuf, progsiz + 4096);
 296                 if (progbuf == NULL) {
 297                         perror("realloc");
 298                         exit(1);
 299                 }
 300                 progsiz += 1024;
 301         }
 302         progbuf[proglen++] = c;


 317 {
 318         va_list va;
 319         char *buf = NULL;
 320         va_start(va, fmt);
 321         if (vasprintf(&buf, fmt, va) < 0) {
 322                 perror("vasprintf");
 323                 exit(1);
 324         }
 325         va_end(va);
 326         addprogstr(buf);
 327         free(buf);
 328 }
 329 
 330 static void
 331 mkprog(struct sym_test *st)
 332 {
 333         char *s;
 334 
 335         proglen = 0;
 336 
 337         for (int i = 0; i < MAXHDR && st->st_hdrs[i] != NULL; i++) {
 338                 addprogfmt("#include <%s>\n", st->st_hdrs[i]);
 339         }
 340 
 341         for (s = st->st_rtype; *s; s++) {
 342                 addprogch(*s);
 343                 if (*s == '(') {
 344                         s++;
 345                         addprogch(*s);
 346                         s++;
 347                         break;
 348                 }
 349         }
 350         addprogch(' ');
 351 
 352         /* for function pointers, s is closing suffix, otherwise empty */
 353 
 354         switch (st->st_type) {
 355         case SYM_TYPE:
 356                 addprogstr("test_type;");
 357                 break;
 358 
 359         case SYM_VALUE:
 360                 addprogfmt("test_value%s;\n", s);       /* s usually empty */
 361                 addprogstr("void\ntest_func(void)\n{\n");
 362                 addprogfmt("\ttest_value = %s;\n}", st->st_name);
 363                 break;
 364 
 365         case SYM_FUNC:
 366                 addprogstr("\ntest_func(");
 367                 for (int i = 0; st->st_atypes[i] != NULL && i < MAXARG; i++) {
 368                         int didname = 0;
 369                         if (i > 0) {
 370                                 addprogstr(", ");
 371                         }
 372                         if (strcmp(st->st_atypes[i], "void") == 0) {
 373                                 didname = 1;
 374                         }
 375                         if (strcmp(st->st_atypes[i], "") == 0) {
 376                                 didname = 1;
 377                                 addprogstr("void");
 378                         }
 379 
 380                         /* print the argument list */
 381                         for (char *a = st->st_atypes[i]; *a; a++) {
 382                                 if (*a == '(' && a[1] == '*' && !didname) {
 383                                         addprogfmt("(*a%d", i);
 384                                         didname = 1;
 385                                         a++;
 386                                 } else if (*a == '[' && !didname) {
 387                                         addprogfmt("a%d[", i);
 388                                         didname = 1;
 389                                 } else {
 390                                         addprogch(*a);
 391                                 }
 392                         }
 393                         if (!didname) {
 394                                 addprogfmt(" a%d", i);
 395                         }
 396                 }
 397 
 398                 if (st->st_atypes[0] == NULL) {
 399                         addprogstr("void");
 400                 }
 401 
 402                 /*
 403                  * Close argument list, and closing ")" for func ptrs.
 404                  * Note that for non-function pointers, s will be empty
 405                  * below, otherwise it points to the trailing argument
 406                  * list.
 407                  */
 408                 addprogfmt(")%s\n{\n\t", s);
 409 
 410                 if (strcmp(st->st_rtype, "") != 0 &&
 411                     strcmp(st->st_rtype, "void") != 0) {
 412                         addprogstr("return ");
 413                 }
 414 
 415                 /* add the function call */
 416                 addprogfmt("%s(", st->st_name);
 417                 for (int i = 0; st->st_atypes[i] != NULL && i < MAXARG; i++) {
 418                         if (strcmp(st->st_atypes[i], "") != 0 &&
 419                             strcmp(st->st_atypes[i], "void") != 0) {
 420                                 addprogfmt("%sa%d", i > 0 ? ", " : "", i);
 421                         }
 422                 }
 423 
 424                 addprogstr(");\n}");
 425                 break;
 426         }
 427 
 428         addprogch('\n');
 429 
 430         st->st_prog = progbuf;
 431 }
 432 
 433 static int
 434 add_envs(struct sym_test *st, char *envs, char **err)
 435 {
 436         char *item;
 437         if (expand_env_list(envs, &st->st_test_mask, &st->st_need_mask,
 438             &item) < 0) {
 439                 myasprintf(err, "bad env action %s", item);
 440                 return (-1);
 441         }
 442         return (0);
 443 }
 444 
 445 static int
 446 add_headers(struct sym_test *st, char *hdrs, char **err)
 447 {
 448         int i = 0;
 449 
 450         for (char *h = strsep(&hdrs, ";"); h != NULL; h = strsep(&hdrs, ";")) {
 451                 if (i >= MAXHDR) {
 452                         myasprintf(err, "too many headers");
 453                         return (-1);
 454                 }
 455                 test_trim(&h);
 456                 st->st_hdrs[i++] = mystrdup(h);
 457         }
 458 
 459         return (0);
 460 }
 461 
 462 static int
 463 add_arg_types(struct sym_test *st, char *atype, char **err)
 464 {
 465         int i = 0;
 466         char *a;
 467         for (a = strsep(&atype, ";"); a != NULL; a = strsep(&atype, ";")) {
 468                 if (i >= MAXARG) {
 469                         myasprintf(err, "too many arguments");
 470                         return (-1);
 471                 }
 472                 test_trim(&a);
 473                 st->st_atypes[i++] = mystrdup(a);
 474         }
 475 
 476         return (0);
 477 }
 478 
 479 static int
 480 do_type(char **fields, int nfields, char **err)
 481 {
 482         char *decl;
 483         char *hdrs;
 484         char *envs;
 485         struct sym_test *st;
 486 
 487         if (nfields != 3) {
 488                 myasprintf(err, "number of fields (%d) != 3", nfields);
 489                 return (-1);
 490         }
 491         decl = fields[0];
 492         hdrs = fields[1];
 493         envs = fields[2];
 494 
 495         st = myzalloc(sizeof (*st));
 496         st->st_type = SYM_TYPE;
 497         st->st_name = mystrdup(decl);
 498         st->st_rtype = mystrdup(decl);
 499 
 500         if ((add_envs(st, envs, err) < 0) ||
 501             (add_headers(st, hdrs, err) < 0)) {
 502                 return (-1);
 503         }
 504         append_sym_test(st);
 505 
 506         return (0);
 507 }
 508 
 509 static int
 510 do_value(char **fields, int nfields, char **err)
 511 {
 512         char *name;
 513         char *type;
 514         char *hdrs;
 515         char *envs;
 516         struct sym_test *st;
 517 
 518         if (nfields != 4) {
 519                 myasprintf(err, "number of fields (%d) != 4", nfields);
 520                 return (-1);
 521         }
 522         name = fields[0];
 523         type = fields[1];
 524         hdrs = fields[2];
 525         envs = fields[3];
 526 
 527         st = myzalloc(sizeof (*st));
 528         st->st_type = SYM_VALUE;
 529         st->st_name = mystrdup(name);
 530         st->st_rtype = mystrdup(type);
 531 
 532         if ((add_envs(st, envs, err) < 0) ||
 533             (add_headers(st, hdrs, err) < 0)) {
 534                 return (-1);
 535         }
 536         append_sym_test(st);
 537 
 538         return (0);
 539 }
 540 
 541 static int
 542 do_func(char **fields, int nfields, char **err)
 543 {
 544         char *name;
 545         char *rtype;
 546         char *atype;
 547         char *hdrs;
 548         char *envs;
 549         struct sym_test *st;
 550 
 551         if (nfields != 5) {
 552                 myasprintf(err, "number of fields (%d) != 5", nfields);
 553                 return (-1);
 554         }
 555         name = fields[0];
 556         rtype = fields[1];
 557         atype = fields[2];
 558         hdrs = fields[3];
 559         envs = fields[4];
 560 
 561         st = myzalloc(sizeof (*st));
 562         st->st_type = SYM_FUNC;
 563         st->st_name = mystrdup(name);
 564         st->st_rtype = mystrdup(rtype);
 565 
 566         if ((add_envs(st, envs, err) < 0) ||
 567             (add_headers(st, hdrs, err) < 0) ||
 568             (add_arg_types(st, atype, err) < 0)) {
 569                 return (-1);
 570         }
 571         append_sym_test(st);
 572 
 573         return (0);
 574 }
 575 
 576 struct sym_test *
 577 next_sym_test(struct sym_test *st)
 578 {
 579         return (st == NULL ? sym_tests : st->st_next);
 580 }
 581 
 582 const char *
 583 sym_test_prog(struct sym_test *st)
 584 {
 585         if (st->st_prog == NULL) {
 586                 mkprog(st);
 587         }
 588         return (st->st_prog);
 589 }
 590 
 591 const char *
 592 sym_test_name(struct sym_test *st)
 593 {
 594         return (st->st_name);
 595 }
 596 
 597 /*
 598  * Iterate through tests.  Pass in NULL for cenv to begin the iteration. For
 599  * subsequent iterations, use the return value from the previous iteration.
 600  * Returns NULL when there are no more environments.
 601  */
 602 struct compile_env *
 603 sym_test_env(struct sym_test *st, struct compile_env *cenv, int *need)
 604 {
 605         int i = cenv ? cenv->ce_index + 1: 0;
 606         uint64_t b = 1ULL << i;
 607 
 608         while ((i < MAXENV) && (b != 0)) {
 609                 cenv = &compile_env[i];
 610                 if (b & st->st_test_mask) {
 611                         *need = (st->st_need_mask & b) ? 1 : 0;
 612                         return (cenv);
 613                 }
 614                 b <<= 1;
 615                 i++;
 616         }
 617         return (NULL);
 618 }
 619 
 620 const char *
 621 env_name(struct compile_env *cenv)
 622 {
 623         return (cenv->ce_name);
 624 }
 625 
 626 const char *
 627 env_lang(struct compile_env *cenv)
 628 {
 629         return (cenv->ce_lang);
 630 }
 631 
 632 const char *
 633 env_defs(struct compile_env *cenv)
 634 {
 635         return (cenv->ce_defs);
 636 }
 637 
 638 static void
 639 show_file(test_t t, const char *path)
 640 {
 641         FILE *f;
 642         char *buf = NULL;
 643         size_t cap = 0;
 644         int line = 1;
 645 
 646         f = fopen(path, "r");
 647         if (f == NULL) {
 648                 test_debugf(t, "fopen(%s): %s", path, strerror(errno));
 649                 return;
 650         }
 651 
 652         test_debugf(t, "----->> begin (%s) <<------", path);
 653         while (getline(&buf, &cap, f) >= 0) {
 654                 (void) strtok(buf, "\r\n");
 655                 test_debugf(t, "%d: %s", line, buf);


 761                 case 51:        /* STUDIO */
 762                         test_debugf(t, "Found Studio C");
 763                         c89flags = "-Xc -errwarn=%all -v -xc99=%none " MFLAG;
 764                         c99flags = "-Xc -errwarn=%all -v -xc99=%all " MFLAG;
 765                         if (extra_debug) {
 766                                 test_debugf(t, "c89flags: %s", c89flags);
 767                                 test_debugf(t, "c99flags: %s", c99flags);
 768                         }
 769                         test_passed(t);
 770                         break;
 771                 case 52:        /* GCC */
 772                         test_debugf(t, "Found GNU C");
 773                         c89flags = "-Wall -Werror -std=c89 " MFLAG;
 774                         c99flags = "-Wall -Werror -std=c99 " MFLAG;
 775                         if (extra_debug) {
 776                                 test_debugf(t, "c89flags: %s", c89flags);
 777                                 test_debugf(t, "c99flags: %s", c99flags);
 778                         }
 779                         test_passed(t);
 780                         break;
 781                 case 99:
 782                         test_debugf(t, "Found unknown (unsupported) compiler");
 783                         continue;
 784                 default:
 785                         continue;
 786                 }
 787                 myasprintf(&compiler, "%s", compilers[i]);
 788                 test_debugf(t, "compiler: %s", compiler);
 789                 return;
 790         }
 791         test_failed(t, "No compiler found.");
 792 }
 793 
 794 int
 795 do_compile(test_t t, struct sym_test *st, struct compile_env *cenv, int need)
 796 {
 797         char *cmd;
 798         FILE *logf;
 799         FILE *dotc;
 800         const char *prog;
 801 
 802         full_count++;
 803 


 861         good_count++;
 862         return (0);
 863 }
 864 
 865 void
 866 test_compile(void)
 867 {
 868         struct sym_test *st;
 869         struct compile_env *cenv;
 870         test_t t;
 871         int need;
 872 
 873         for (st = next_sym_test(NULL); st; st = next_sym_test(st)) {
 874                 if ((sym != NULL) && strcmp(sym, sym_test_name(st))) {
 875                         continue;
 876                 }
 877                 /* XXX: we really want a sym_test_desc() */
 878                 for (cenv = sym_test_env(st, NULL, &need);
 879                     cenv != NULL;
 880                     cenv = sym_test_env(st, cenv, &need)) {
 881                         t = test_start("%s : %c%s", sym_test_name(st),
 882                             need ? '+' : '-', env_name(cenv));
 883                         if (do_compile(t, st, cenv, need) == 0) {
 884                                 test_passed(t);
 885                         }
 886                 }
 887         }
 888 
 889         if (full_count > 0) {
 890                 test_summary();
 891         }
 892 }
 893 
 894 int
 895 main(int argc, char **argv)
 896 {
 897         int optc;
 898         int optC = 0;
 899 
 900         while ((optc = getopt(argc, argv, "DdfCs:c:")) != EOF) {
 901                 switch (optc) {