1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2015 Garrett D'Amore <garrett@damore.org> 14 */ 15 16 /* 17 * This program tests symbol visibility using the /usr/bin/c89 and 18 * /usr/bin/c99 programs. 19 */ 20 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <errno.h> 25 #include <err.h> 26 #include <unistd.h> 27 #include <sys/types.h> 28 #include <sys/stat.h> 29 #include <note.h> 30 #include <sys/wait.h> 31 #include "test_common.h" 32 33 char *dname; 34 char *cfile; 35 char *ofile; 36 char *lfile; 37 char *efile; 38 39 const char *sym = NULL; 40 41 static int good_count = 0; 42 static int fail_count = 0; 43 static int full_count = 0; 44 static int extra_debug = 0; 45 static char *compilation = "compilation.cfg"; 46 47 #if defined(_LP64) 48 #define MFLAG "-m64" 49 #elif defined(_ILP32) 50 #define MFLAG "-m32" 51 #endif 52 53 const char *compilers[] = { 54 "cc", 55 "gcc", 56 "/opt/SUNWspro/bin/cc", 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) 123 { 124 void *buf; 125 if ((buf = calloc(1, sz)) == NULL) { 126 perror("calloc"); 127 exit(1); 128 } 129 return (buf); 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); 187 } 188 189 static int 190 expand_env_list(char *list, uint64_t *test, uint64_t *need, char **erritem) 191 { 192 uint64_t mask = 0; 193 int act; 194 char *item; 195 for (item = strtok(list, WS); item != NULL; item = strtok(NULL, WS)) { 196 switch (item[0]) { 197 case '+': 198 act = 1; 199 item++; 200 break; 201 case '-': 202 act = 0; 203 item++; 204 break; 205 default: 206 act = 1; 207 break; 208 } 209 210 mask = 0; 211 if (find_env_mask(item, &mask) < 0) { 212 if (erritem != NULL) { 213 *erritem = item; 214 } 215 return (-1); 216 } 217 *test |= mask; 218 if (act) { 219 *need |= mask; 220 } else { 221 *need &= ~(mask); 222 } 223 } 224 return (0); 225 } 226 227 static int 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; 303 progbuf[proglen] = 0; 304 } 305 306 static void 307 addprogstr(char *s) 308 { 309 while (*s != NULL) { 310 addprogch(*s); 311 s++; 312 } 313 } 314 315 static void 316 addprogfmt(const char *fmt, ...) 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); 656 line++; 657 } 658 test_debugf(t, "----->> end (%s) <<------", path); 659 (void) fclose(f); 660 } 661 662 static void 663 cleanup(void) 664 { 665 if (ofile != NULL) { 666 (void) unlink(ofile); 667 free(ofile); 668 ofile = NULL; 669 } 670 if (lfile != NULL) { 671 (void) unlink(lfile); 672 free(lfile); 673 lfile = NULL; 674 } 675 if (cfile != NULL) { 676 (void) unlink(cfile); 677 free(cfile); 678 cfile = NULL; 679 } 680 if (efile != NULL) { 681 (void) unlink(efile); 682 free(efile); 683 efile = NULL; 684 } 685 if (dname) { 686 (void) rmdir(dname); 687 free(dname); 688 dname = NULL; 689 } 690 } 691 692 static int 693 mkworkdir(void) 694 { 695 char b[32]; 696 char *d; 697 698 cleanup(); 699 700 (void) strlcpy(b, "/tmp/symbols_testXXXXXX", sizeof (b)); 701 if ((d = mkdtemp(b)) == NULL) { 702 perror("mkdtemp"); 703 return (-1); 704 } 705 dname = mystrdup(d); 706 myasprintf(&cfile, "%s/compile_test.c", d); 707 myasprintf(&ofile, "%s/compile_test.o", d); 708 myasprintf(&lfile, "%s/compile_test.log", d); 709 myasprintf(&efile, "%s/compile_test.exe", d); 710 return (0); 711 } 712 713 void 714 find_compiler(void) 715 { 716 test_t t; 717 int i; 718 FILE *cf; 719 720 t = test_start("finding compiler"); 721 722 if ((cf = fopen(cfile, "w+")) == NULL) { 723 test_failed(t, "Unable to open %s for write: %s", cfile, 724 strerror(errno)); 725 return; 726 } 727 (void) fprintf(cf, "#include <stdio.h>\n"); 728 (void) fprintf(cf, "int main(int argc, char **argv) {\n"); 729 (void) fprintf(cf, "#if defined(__SUNPRO_C)\n"); 730 (void) fprintf(cf, "exit(51);\n"); 731 (void) fprintf(cf, "#elif defined(__GNUC__)\n"); 732 (void) fprintf(cf, "exit(52);\n"); 733 (void) fprintf(cf, "#else\n"); 734 (void) fprintf(cf, "exit(99)\n"); 735 (void) fprintf(cf, "#endif\n}\n"); 736 (void) fclose(cf); 737 738 for (i = 0; compilers[i] != NULL; i++) { 739 char cmd[256]; 740 int rv; 741 742 (void) snprintf(cmd, sizeof (cmd), 743 "%s %s %s -o %s >/dev/null 2>&1", 744 compilers[i], MFLAG, cfile, efile); 745 test_debugf(t, "trying %s", cmd); 746 rv = system(cmd); 747 748 test_debugf(t, "result: %d", rv); 749 750 if ((rv < 0) || !WIFEXITED(rv) || WEXITSTATUS(rv) != 0) 751 continue; 752 753 rv = system(efile); 754 if (rv >= 0 && WIFEXITED(rv)) { 755 rv = WEXITSTATUS(rv); 756 } else { 757 rv = -1; 758 } 759 760 switch (rv) { 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 -nostdinc " 774 "-isystem /usr/include " MFLAG; 775 c99flags = "-Wall -Werror -std=c99 -nostdinc " 776 "-isystem /usr/include " MFLAG; 777 if (extra_debug) { 778 test_debugf(t, "c89flags: %s", c89flags); 779 test_debugf(t, "c99flags: %s", c99flags); 780 } 781 test_passed(t); 782 break; 783 case 99: 784 test_debugf(t, "Found unknown (unsupported) compiler"); 785 continue; 786 default: 787 continue; 788 } 789 myasprintf(&compiler, "%s", compilers[i]); 790 test_debugf(t, "compiler: %s", compiler); 791 return; 792 } 793 test_failed(t, "No compiler found."); 794 } 795 796 int 797 do_compile(test_t t, struct sym_test *st, struct compile_env *cenv, int need) 798 { 799 char *cmd; 800 FILE *logf; 801 FILE *dotc; 802 const char *prog; 803 804 full_count++; 805 806 if ((dotc = fopen(cfile, "w+")) == NULL) { 807 test_failed(t, "fopen(%s): %s", cfile, strerror(errno)); 808 return (-1); 809 } 810 prog = sym_test_prog(st); 811 if (fwrite(prog, 1, strlen(prog), dotc) < strlen(prog)) { 812 test_failed(t, "fwrite: %s", strerror(errno)); 813 (void) fclose(dotc); 814 return (-1); 815 } 816 if (fclose(dotc) < 0) { 817 test_failed(t, "fclose: %s", strerror(errno)); 818 return (-1); 819 } 820 821 (void) unlink(ofile); 822 823 myasprintf(&cmd, "%s %s %s -c %s -o %s >>%s 2>&1", 824 compiler, strcmp(env_lang(cenv), "c99") == 0 ? c99flags : c89flags, 825 env_defs(cenv), cfile, ofile, lfile); 826 827 if (extra_debug) { 828 test_debugf(t, "command: %s", cmd); 829 } 830 831 if ((logf = fopen(lfile, "w+")) == NULL) { 832 test_failed(t, "fopen: %s", strerror(errno)); 833 return (-1); 834 } 835 (void) fprintf(logf, "===================\n"); 836 (void) fprintf(logf, "PROGRAM:\n%s\n", sym_test_prog(st)); 837 (void) fprintf(logf, "COMMAND: %s\n", cmd); 838 (void) fprintf(logf, "EXPECT: %s\n", need ? "OK" : "FAIL"); 839 (void) fclose(logf); 840 841 switch (system(cmd)) { 842 case -1: 843 test_failed(t, "error compiling in %s: %s", env_name(cenv), 844 strerror(errno)); 845 return (-1); 846 case 0: 847 if (!need) { 848 fail_count++; 849 show_file(t, lfile); 850 test_failed(t, "symbol visible in %s", env_name(cenv)); 851 return (-1); 852 } 853 break; 854 default: 855 if (need) { 856 fail_count++; 857 show_file(t, lfile); 858 test_failed(t, "error compiling in %s", env_name(cenv)); 859 return (-1); 860 } 861 break; 862 } 863 good_count++; 864 return (0); 865 } 866 867 void 868 test_compile(void) 869 { 870 struct sym_test *st; 871 struct compile_env *cenv; 872 test_t t; 873 int need; 874 875 for (st = next_sym_test(NULL); st; st = next_sym_test(st)) { 876 if ((sym != NULL) && strcmp(sym, sym_test_name(st))) { 877 continue; 878 } 879 /* XXX: we really want a sym_test_desc() */ 880 for (cenv = sym_test_env(st, NULL, &need); 881 cenv != NULL; 882 cenv = sym_test_env(st, cenv, &need)) { 883 t = test_start("%s : %c%s", sym_test_name(st), 884 need ? '+' : '-', env_name(cenv)); 885 if (do_compile(t, st, cenv, need) == 0) { 886 test_passed(t); 887 } 888 } 889 } 890 891 if (full_count > 0) { 892 test_summary(); 893 } 894 } 895 896 int 897 main(int argc, char **argv) 898 { 899 int optc; 900 int optC = 0; 901 902 while ((optc = getopt(argc, argv, "DdfCs:c:")) != EOF) { 903 switch (optc) { 904 case 'd': 905 test_set_debug(); 906 break; 907 case 'f': 908 test_set_force(); 909 break; 910 case 'D': 911 test_set_debug(); 912 extra_debug++; 913 break; 914 case 'c': 915 compilation = optarg; 916 break; 917 case 'C': 918 optC++; 919 break; 920 case 's': 921 sym = optarg; 922 break; 923 default: 924 (void) fprintf(stderr, "Usage: %s [-df]\n", argv[0]); 925 exit(1); 926 } 927 } 928 929 if (test_load_config(NULL, compilation, 930 "env", do_env, "env_group", do_env_group, NULL) < 0) { 931 exit(1); 932 } 933 934 while (optind < argc) { 935 if (test_load_config(NULL, argv[optind++], 936 "type", do_type, 937 "value", do_value, 938 "func", do_func, 939 NULL) < 0) { 940 exit(1); 941 } 942 } 943 944 if (atexit(cleanup) != 0) { 945 perror("atexit"); 946 exit(1); 947 } 948 949 if (mkworkdir() < 0) { 950 perror("mkdir"); 951 exit(1); 952 } 953 954 find_compiler(); 955 if (!optC) 956 test_compile(); 957 958 exit(0); 959 } 960