crunchgen.c revision 17430
1/* 2 * Copyright (c) 1994 University of Maryland 3 * All Rights Reserved. 4 * 5 * Permission to use, copy, modify, distribute, and sell this software and its 6 * documentation for any purpose is hereby granted without fee, provided that 7 * the above copyright notice appear in all copies and that both that 8 * copyright notice and this permission notice appear in supporting 9 * documentation, and that the name of U.M. not be used in advertising or 10 * publicity pertaining to distribution of the software without specific, 11 * written prior permission. U.M. makes no representations about the 12 * suitability of this software for any purpose. It is provided "as is" 13 * without express or implied warranty. 14 * 15 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. 17 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 19 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21 * 22 * Author: James da Silva, Systems Design and Analysis Group 23 * Computer Science Department 24 * University of Maryland at College Park 25 */ 26/* 27 * ======================================================================== 28 * crunchgen.c 29 * 30 * Generates a Makefile and main C file for a crunched executable, 31 * from specs given in a .conf file. 32 */ 33#include <stdlib.h> 34#include <unistd.h> 35#include <stdio.h> 36#include <ctype.h> 37#include <string.h> 38 39#include <sys/types.h> 40#include <sys/stat.h> 41#include <sys/param.h> 42 43#define CRUNCH_VERSION "0.2" 44 45#define MAXLINELEN 16384 46#define MAXFIELDS 2048 47 48 49/* internal representation of conf file: */ 50 51/* simple lists of strings suffice for most parms */ 52 53typedef struct strlst { 54 struct strlst *next; 55 char *str; 56} strlst_t; 57 58/* progs have structure, each field can be set with "special" or calculated */ 59 60typedef struct prog { 61 struct prog *next; 62 char *name, *ident; 63 char *srcdir, *objdir; 64 strlst_t *objs, *objpaths; 65 strlst_t *links; 66 int goterror; 67} prog_t; 68 69 70/* global state */ 71 72strlst_t *srcdirs = NULL; 73strlst_t *libs = NULL; 74prog_t *progs = NULL; 75 76char line[MAXLINELEN]; 77 78char confname[MAXPATHLEN], infilename[MAXPATHLEN]; 79char outmkname[MAXPATHLEN], outcfname[MAXPATHLEN], execfname[MAXPATHLEN]; 80char tempfname[MAXPATHLEN], cachename[MAXPATHLEN], curfilename[MAXPATHLEN]; 81int linenum = -1; 82int goterror = 0; 83 84char *pname = "crunchgen"; 85 86int verbose, readcache; /* options */ 87int reading_cache; 88 89int list_mode; 90 91/* general library routines */ 92 93void status(char *str); 94void out_of_memory(void); 95void add_string(strlst_t **listp, char *str); 96int is_dir(char *pathname); 97int is_nonempty_file(char *pathname); 98 99/* helper routines for main() */ 100 101void usage(void); 102void parse_conf_file(void); 103void gen_outputs(void); 104 105 106int main(int argc, char **argv) 107{ 108 char *p; 109 int optc; 110 extern int optind; 111 extern char *optarg; 112 113 verbose = 1; 114 readcache = 1; 115 *outmkname = *outcfname = *execfname = '\0'; 116 117 if(argc > 0) pname = argv[0]; 118 119 while((optc = getopt(argc, argv, "lm:c:e:fq")) != -1) { 120 switch(optc) { 121 case 'f': readcache = 0; break; 122 case 'q': verbose = 0; break; 123 124 case 'm': strcpy(outmkname, optarg); break; 125 case 'c': strcpy(outcfname, optarg); break; 126 case 'e': strcpy(execfname, optarg); break; 127 case 'l': list_mode++; verbose = 0; break; 128 129 case '?': 130 default: usage(); 131 } 132 } 133 134 argc -= optind; 135 argv += optind; 136 137 if(argc != 1) usage(); 138 139 /* 140 * generate filenames 141 */ 142 143 strcpy(infilename, argv[0]); 144 145 /* confname = `basename infilename .conf` */ 146 147 if((p=strrchr(infilename, '/')) != NULL) strcpy(confname, p+1); 148 else strcpy(confname, infilename); 149 if((p=strrchr(confname, '.')) != NULL && !strcmp(p, ".conf")) *p = '\0'; 150 151 if(!*outmkname) sprintf(outmkname, "%s.mk", confname); 152 if(!*outcfname) sprintf(outcfname, "%s.c", confname); 153 if(!*execfname) sprintf(execfname, "%s", confname); 154 155 sprintf(cachename, "%s.cache", confname); 156 sprintf(tempfname, ".tmp_%sXXXXXX", confname); 157 if(mktemp(tempfname) == NULL) { 158 perror(tempfname); 159 exit(1); 160 } 161 162 parse_conf_file(); 163 if (list_mode) 164 exit(goterror); 165 166 gen_outputs(); 167 168 exit(goterror); 169} 170 171 172void usage(void) 173{ 174 fprintf(stderr, 175 "%s [-fq] [-m <makefile>] [-c <c file>] [-e <exec file>] <conffile>\n", 176 pname); 177 exit(1); 178} 179 180 181/* 182 * ======================================================================== 183 * parse_conf_file subsystem 184 * 185 */ 186 187/* helper routines for parse_conf_file */ 188 189void parse_one_file(char *filename); 190void parse_line(char *line, int *fc, char **fv, int nf); 191void add_srcdirs(int argc, char **argv); 192void add_progs(int argc, char **argv); 193void add_link(int argc, char **argv); 194void add_libs(int argc, char **argv); 195void add_special(int argc, char **argv); 196 197prog_t *find_prog(char *str); 198void add_prog(char *progname); 199 200 201void parse_conf_file(void) 202{ 203 if(!is_nonempty_file(infilename)) { 204 fprintf(stderr, "%s: fatal: input file \"%s\" not found.\n", 205 pname, infilename); 206 exit(1); 207 } 208 parse_one_file(infilename); 209 if(readcache && is_nonempty_file(cachename)) { 210 reading_cache = 1; 211 parse_one_file(cachename); 212 } 213} 214 215 216void parse_one_file(char *filename) 217{ 218 char *fieldv[MAXFIELDS]; 219 int fieldc; 220 void (*f)(int c, char **v); 221 FILE *cf; 222 223 sprintf(line, "reading %s", filename); 224 status(line); 225 strcpy(curfilename, filename); 226 227 if((cf = fopen(curfilename, "r")) == NULL) { 228 perror(curfilename); 229 goterror = 1; 230 return; 231 } 232 233 linenum = 0; 234 while(fgets(line, MAXLINELEN, cf) != NULL) { 235 linenum++; 236 parse_line(line, &fieldc, fieldv, MAXFIELDS); 237 if(fieldc < 1) continue; 238 if(!strcmp(fieldv[0], "srcdirs")) f = add_srcdirs; 239 else if(!strcmp(fieldv[0], "progs")) f = add_progs; 240 else if(!strcmp(fieldv[0], "ln")) f = add_link; 241 else if(!strcmp(fieldv[0], "libs")) f = add_libs; 242 else if(!strcmp(fieldv[0], "special")) f = add_special; 243 else { 244 fprintf(stderr, "%s:%d: skipping unknown command `%s'.\n", 245 curfilename, linenum, fieldv[0]); 246 goterror = 1; 247 continue; 248 } 249 if(fieldc < 2) { 250 fprintf(stderr, 251 "%s:%d: %s command needs at least 1 argument, skipping.\n", 252 curfilename, linenum, fieldv[0]); 253 goterror = 1; 254 continue; 255 } 256 f(fieldc, fieldv); 257 } 258 259 if(ferror(cf)) { 260 perror(curfilename); 261 goterror = 1; 262 } 263 fclose(cf); 264} 265 266 267void parse_line(char *line, int *fc, char **fv, int nf) 268{ 269 char *p; 270 271 p = line; 272 *fc = 0; 273 while(1) { 274 while(isspace(*p)) p++; 275 if(*p == '\0' || *p == '#') break; 276 277 if(*fc < nf) fv[(*fc)++] = p; 278 while(*p && !isspace(*p) && *p != '#') p++; 279 if(*p == '\0' || *p == '#') break; 280 *p++ = '\0'; 281 } 282 if(*p) *p = '\0'; /* needed for '#' case */ 283} 284 285 286void add_srcdirs(int argc, char **argv) 287{ 288 int i; 289 290 for(i=1;i<argc;i++) { 291 if(is_dir(argv[i])) 292 add_string(&srcdirs, argv[i]); 293 else { 294 fprintf(stderr, "%s:%d: `%s' is not a directory, skipping it.\n", 295 curfilename, linenum, argv[i]); 296 goterror = 1; 297 } 298 } 299} 300 301 302void add_progs(int argc, char **argv) 303{ 304 int i; 305 306 for(i=1;i<argc;i++) 307 add_prog(argv[i]); 308} 309 310 311void add_prog(char *progname) 312{ 313 prog_t *p1, *p2; 314 315 /* add to end, but be smart about dups */ 316 317 for(p1 = NULL, p2 = progs; p2 != NULL; p1 = p2, p2 = p2->next) 318 if(!strcmp(p2->name, progname)) return; 319 320 p2 = malloc(sizeof(prog_t)); 321 if(p2) p2->name = strdup(progname); 322 if(!p2 || !p2->name) 323 out_of_memory(); 324 325 p2->next = NULL; 326 if(p1 == NULL) progs = p2; 327 else p1->next = p2; 328 329 p2->ident = p2->srcdir = p2->objdir = NULL; 330 p2->links = p2->objs = NULL; 331 p2->goterror = 0; 332 if (list_mode) 333 printf("%s\n",progname); 334} 335 336 337void add_link(int argc, char **argv) 338{ 339 int i; 340 prog_t *p = find_prog(argv[1]); 341 342 if(p == NULL) { 343 fprintf(stderr, 344 "%s:%d: no prog %s previously declared, skipping link.\n", 345 curfilename, linenum, argv[1]); 346 goterror = 1; 347 return; 348 } 349 for(i=2;i<argc;i++) { 350 if (list_mode) 351 printf("%s\n",argv[i]); 352 add_string(&p->links, argv[i]); 353 } 354} 355 356 357void add_libs(int argc, char **argv) 358{ 359 int i; 360 361 for(i=1;i<argc;i++) 362 add_string(&libs, argv[i]); 363} 364 365 366void add_special(int argc, char **argv) 367{ 368 int i; 369 prog_t *p = find_prog(argv[1]); 370 371 if(p == NULL) { 372 if(reading_cache) return; 373 fprintf(stderr, 374 "%s:%d: no prog %s previously declared, skipping special.\n", 375 curfilename, linenum, argv[1]); 376 goterror = 1; 377 return; 378 } 379 380 if(!strcmp(argv[2], "ident")) { 381 if(argc != 4) goto argcount; 382 if((p->ident = strdup(argv[3])) == NULL) 383 out_of_memory(); 384 } 385 else if(!strcmp(argv[2], "srcdir")) { 386 if(argc != 4) goto argcount; 387 if((p->srcdir = strdup(argv[3])) == NULL) 388 out_of_memory(); 389 } 390 else if(!strcmp(argv[2], "objdir")) { 391 if(argc != 4) goto argcount; 392 if((p->objdir = strdup(argv[3])) == NULL) 393 out_of_memory(); 394 } 395 else if(!strcmp(argv[2], "objs")) { 396 p->objs = NULL; 397 for(i=3;i<argc;i++) 398 add_string(&p->objs, argv[i]); 399 } 400 else if(!strcmp(argv[2], "objpaths")) { 401 p->objpaths = NULL; 402 for(i=3;i<argc;i++) 403 add_string(&p->objpaths, argv[i]); 404 } 405 else { 406 fprintf(stderr, "%s:%d: bad parameter name `%s', skipping line.\n", 407 curfilename, linenum, argv[2]); 408 goterror = 1; 409 } 410 return; 411 412 413 argcount: 414 fprintf(stderr, 415 "%s:%d: too %s arguments, expected \"special %s %s <string>\".\n", 416 curfilename, linenum, argc < 4? "few" : "many", argv[1], argv[2]); 417 goterror = 1; 418} 419 420 421prog_t *find_prog(char *str) 422{ 423 prog_t *p; 424 425 for(p = progs; p != NULL; p = p->next) 426 if(!strcmp(p->name, str)) return p; 427 428 return NULL; 429} 430 431 432/* 433 * ======================================================================== 434 * gen_outputs subsystem 435 * 436 */ 437 438/* helper subroutines */ 439 440void remove_error_progs(void); 441void fillin_program(prog_t *p); 442void gen_specials_cache(void); 443void gen_output_makefile(void); 444void gen_output_cfile(void); 445 446void fillin_program_objs(prog_t *p, char *path); 447void top_makefile_rules(FILE *outmk); 448void prog_makefile_rules(FILE *outmk, prog_t *p); 449void output_strlst(FILE *outf, strlst_t *lst); 450char *genident(char *str); 451char *dir_search(char *progname); 452 453 454void gen_outputs(void) 455{ 456 prog_t *p; 457 458 for(p = progs; p != NULL; p = p->next) 459 fillin_program(p); 460 461 remove_error_progs(); 462 gen_specials_cache(); 463 gen_output_cfile(); 464 gen_output_makefile(); 465 status(""); 466 fprintf(stderr, 467 "Run \"make -f %s objs exe\" to build crunched binary.\n", 468 outmkname); 469} 470 471 472void fillin_program(prog_t *p) 473{ 474 char path[MAXPATHLEN]; 475 char *srcparent; 476 strlst_t *s; 477 478 sprintf(line, "filling in parms for %s", p->name); 479 status(line); 480 481 if(!p->ident) 482 p->ident = genident(p->name); 483 if(!p->srcdir) { 484 srcparent = dir_search(p->name); 485 if(srcparent) 486 sprintf(path, "%s/%s", srcparent, p->name); 487 if(is_dir(path)) 488 p->srcdir = strdup(path); 489 } 490 if(!p->objdir && p->srcdir) { 491 FILE *f; 492 493 sprintf(path, "cd %s && echo -n /usr/obj/`pwd`", p->srcdir); 494 p->objdir = p->srcdir; 495 f = popen(path,"r"); 496 if (f) { 497 fgets(path,sizeof path, f); 498 if (!pclose(f)) { 499 if(is_dir(path)) 500 p->objdir = strdup(path); 501 } 502 } 503 504 505 } 506 507 if(p->srcdir) sprintf(path, "%s/Makefile", p->srcdir); 508 if(!p->objs && p->srcdir && is_nonempty_file(path)) 509 fillin_program_objs(p, path); 510 511 if(!p->objpaths && p->objdir && p->objs) 512 for(s = p->objs; s != NULL; s = s->next) { 513 sprintf(line, "%s/%s", p->objdir, s->str); 514 add_string(&p->objpaths, line); 515 } 516 517 if(!p->srcdir && verbose) 518 fprintf(stderr, "%s: %s: warning: could not find source directory.\n", 519 infilename, p->name); 520 if(!p->objs && verbose) 521 fprintf(stderr, "%s: %s: warning: could not find any .o files.\n", 522 infilename, p->name); 523 524 if(!p->objpaths) { 525 fprintf(stderr, 526 "%s: %s: error: no objpaths specified or calculated.\n", 527 infilename, p->name); 528 p->goterror = goterror = 1; 529 } 530} 531 532void fillin_program_objs(prog_t *p, char *path) 533{ 534 char *obj, *cp; 535 int rc; 536 FILE *f; 537 538 /* discover the objs from the srcdir Makefile */ 539 540 if((f = fopen(tempfname, "w")) == NULL) { 541 perror(tempfname); 542 goterror = 1; 543 return; 544 } 545 546 fprintf(f, ".include \"%s\"\n", path); 547 fprintf(f, ".if defined(PROG) && !defined(OBJS)\n"); 548 fprintf(f, "OBJS=${PROG}.o\n"); 549 fprintf(f, ".endif\n"); 550 fprintf(f, "crunchgen_objs:\n\t@echo 'OBJS= '${OBJS}\n"); 551 fclose(f); 552 553 sprintf(line, "make -f %s crunchgen_objs 2>&1", tempfname); 554 if((f = popen(line, "r")) == NULL) { 555 perror("submake pipe"); 556 goterror = 1; 557 return; 558 } 559 560 while(fgets(line, MAXLINELEN, f)) { 561 if(strncmp(line, "OBJS= ", 6)) { 562 fprintf(stderr, "make error: %s", line); 563 goterror = 1; 564 continue; 565 } 566 cp = line + 6; 567 while(isspace(*cp)) cp++; 568 while(*cp) { 569 obj = cp; 570 while(*cp && !isspace(*cp)) cp++; 571 if(*cp) *cp++ = '\0'; 572 add_string(&p->objs, obj); 573 while(isspace(*cp)) cp++; 574 } 575 } 576 if((rc=pclose(f)) != 0) { 577 fprintf(stderr, "make error: make returned %d\n", rc); 578 goterror = 1; 579 } 580 unlink(tempfname); 581} 582 583void remove_error_progs(void) 584{ 585 prog_t *p1, *p2; 586 587 p1 = NULL; p2 = progs; 588 while(p2 != NULL) { 589 if(!p2->goterror) 590 p1 = p2, p2 = p2->next; 591 else { 592 /* delete it from linked list */ 593 fprintf(stderr, "%s: %s: ignoring program because of errors.\n", 594 infilename, p2->name); 595 if(p1) p1->next = p2->next; 596 else progs = p2->next; 597 p2 = p2->next; 598 } 599 } 600} 601 602void gen_specials_cache(void) 603{ 604 FILE *cachef; 605 prog_t *p; 606 607 sprintf(line, "generating %s", cachename); 608 status(line); 609 610 if((cachef = fopen(cachename, "w")) == NULL) { 611 perror(cachename); 612 goterror = 1; 613 return; 614 } 615 616 fprintf(cachef, "# %s - parm cache generated from %s by crunchgen %s\n\n", 617 cachename, infilename, CRUNCH_VERSION); 618 619 for(p = progs; p != NULL; p = p->next) { 620 fprintf(cachef, "\n"); 621 if(p->srcdir) 622 fprintf(cachef, "special %s srcdir %s\n", p->name, p->srcdir); 623 if(p->objdir) 624 fprintf(cachef, "special %s objdir %s\n", p->name, p->objdir); 625 if(p->objs) { 626 fprintf(cachef, "special %s objs", p->name); 627 output_strlst(cachef, p->objs); 628 } 629 fprintf(cachef, "special %s objpaths", p->name); 630 output_strlst(cachef, p->objpaths); 631 } 632 fclose(cachef); 633} 634 635 636void gen_output_makefile(void) 637{ 638 prog_t *p; 639 FILE *outmk; 640 641 sprintf(line, "generating %s", outmkname); 642 status(line); 643 644 if((outmk = fopen(outmkname, "w")) == NULL) { 645 perror(outmkname); 646 goterror = 1; 647 return; 648 } 649 650 fprintf(outmk, "# %s - generated from %s by crunchgen %s\n\n", 651 outmkname, infilename, CRUNCH_VERSION); 652 653 top_makefile_rules(outmk); 654 655 for(p = progs; p != NULL; p = p->next) 656 prog_makefile_rules(outmk, p); 657 658 fprintf(outmk, "\n# ========\n"); 659 fclose(outmk); 660} 661 662 663void gen_output_cfile(void) 664{ 665 extern char *crunched_skel[]; 666 char **cp; 667 FILE *outcf; 668 prog_t *p; 669 strlst_t *s; 670 671 sprintf(line, "generating %s", outcfname); 672 status(line); 673 674 if((outcf = fopen(outcfname, "w")) == NULL) { 675 perror(outcfname); 676 goterror = 1; 677 return; 678 } 679 680 fprintf(outcf, 681 "/* %s - generated from %s by crunchgen %s */\n", 682 outcfname, infilename, CRUNCH_VERSION); 683 684 fprintf(outcf, "#define EXECNAME \"%s\"\n", execfname); 685 for(cp = crunched_skel; *cp != NULL; cp++) 686 fprintf(outcf, "%s\n", *cp); 687 688 for(p = progs; p != NULL; p = p->next) 689 fprintf(outcf, "extern int _crunched_%s_stub();\n", p->ident); 690 691 fprintf(outcf, "\nstruct stub entry_points[] = {\n"); 692 for(p = progs; p != NULL; p = p->next) { 693 fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n", 694 p->name, p->ident); 695 for(s = p->links; s != NULL; s = s->next) 696 fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n", 697 s->str, p->ident); 698 } 699 700 fprintf(outcf, "\t{ EXECNAME, crunched_main },\n"); 701 fprintf(outcf, "\t{ NULL, NULL }\n};\n"); 702 fclose(outcf); 703} 704 705 706char *genident(char *str) 707{ 708 char *n,*s,*d; 709 710 /* 711 * generates a Makefile/C identifier from a program name, mapping '-' to 712 * '_' and ignoring all other non-identifier characters. This leads to 713 * programs named "foo.bar" and "foobar" to map to the same identifier. 714 */ 715 716 if((n = strdup(str)) == NULL) 717 return NULL; 718 for(d = s = n; *s != '\0'; s++) { 719 if(*s == '-') *d++ = '_'; 720 else if(*s == '_' || isalnum(*s)) *d++ = *s; 721 } 722 *d = '\0'; 723 return n; 724} 725 726 727char *dir_search(char *progname) 728{ 729 char path[MAXPATHLEN]; 730 strlst_t *dir; 731 732 for(dir=srcdirs; dir != NULL; dir=dir->next) { 733 sprintf(path, "%s/%s", dir->str, progname); 734 if(is_dir(path)) return dir->str; 735 } 736 return NULL; 737} 738 739 740void top_makefile_rules(FILE *outmk) 741{ 742 prog_t *p; 743 744 fprintf(outmk, "LIBS="); 745 output_strlst(outmk, libs); 746 747 fprintf(outmk, "CRUNCHED_OBJS="); 748 for(p = progs; p != NULL; p = p->next) 749 fprintf(outmk, " %s.lo", p->name); 750 fprintf(outmk, "\n"); 751 752 fprintf(outmk, "SUBMAKE_TARGETS="); 753 for(p = progs; p != NULL; p = p->next) 754 fprintf(outmk, " %s_make", p->ident); 755 fprintf(outmk, "\n\n"); 756 757 fprintf(outmk, "%s: %s.o $(CRUNCHED_OBJS)\n", 758 execfname, execfname); 759 fprintf(outmk, "\t$(CC) -static -o %s %s.o $(CRUNCHED_OBJS) $(LIBS)\n", 760 execfname, execfname); 761 fprintf(outmk, "\tstrip %s\n", execfname); 762 fprintf(outmk, "all: objs exe\nobjs: $(SUBMAKE_TARGETS)\n"); 763 fprintf(outmk, "exe: %s\n", execfname); 764 fprintf(outmk, "clean:\n\trm -f %s *.lo *.o *_stub.c\n", 765 execfname); 766} 767 768 769void prog_makefile_rules(FILE *outmk, prog_t *p) 770{ 771 fprintf(outmk, "\n# -------- %s\n\n", p->name); 772 773 if(p->srcdir && p->objs) { 774 fprintf(outmk, "%s_SRCDIR=%s\n", p->ident, p->srcdir); 775 fprintf(outmk, "%s_OBJS=", p->ident); 776 output_strlst(outmk, p->objs); 777 fprintf(outmk, "%s_make:\n", p->ident); 778 fprintf(outmk, "\t(cd $(%s_SRCDIR) && make depend && make $(%s_OBJS))\n\n", 779 p->ident, p->ident); 780 } 781 else 782 fprintf(outmk, "%s_make:\n\t@echo \"** cannot make objs for %s\"\n\n", 783 p->ident, p->name); 784 785 fprintf(outmk, "%s_OBJPATHS=", p->ident); 786 output_strlst(outmk, p->objpaths); 787 788 fprintf(outmk, "%s_stub.c:\n", p->name); 789 fprintf(outmk, "\techo \"" 790 "int _crunched_%s_stub(int argc, char **argv, char **envp)" 791 "{return main(argc,argv,envp);}\" >%s_stub.c\n", 792 p->ident, p->name); 793 fprintf(outmk, "%s.lo: %s_stub.o $(%s_OBJPATHS)\n", 794 p->name, p->name, p->ident); 795 fprintf(outmk, "\tld -dc -r -o %s.lo %s_stub.o $(%s_OBJPATHS)\n", 796 p->name, p->name, p->ident); 797 fprintf(outmk, "\tcrunchide -k __crunched_%s_stub %s.lo\n", 798 p->ident, p->name); 799} 800 801void output_strlst(FILE *outf, strlst_t *lst) 802{ 803 for(; lst != NULL; lst = lst->next) 804 fprintf(outf, " %s", lst->str); 805 fprintf(outf, "\n"); 806} 807 808 809/* 810 * ======================================================================== 811 * general library routines 812 * 813 */ 814 815void status(char *str) 816{ 817 static int lastlen = 0; 818 int len, spaces; 819 820 if(!verbose) return; 821 822 len = strlen(str); 823 spaces = lastlen - len; 824 if(spaces < 1) spaces = 1; 825 826 fprintf(stderr, " [%s]%*.*s\r", str, spaces, spaces, " "); 827 fflush(stderr); 828 lastlen = len; 829} 830 831 832void out_of_memory(void) 833{ 834 fprintf(stderr, "%s: %d: out of memory, stopping.\n", infilename, linenum); 835 exit(1); 836} 837 838 839void add_string(strlst_t **listp, char *str) 840{ 841 strlst_t *p1, *p2; 842 843 /* add to end, but be smart about dups */ 844 845 for(p1 = NULL, p2 = *listp; p2 != NULL; p1 = p2, p2 = p2->next) 846 if(!strcmp(p2->str, str)) return; 847 848 p2 = malloc(sizeof(strlst_t)); 849 if(p2) p2->str = strdup(str); 850 if(!p2 || !p2->str) 851 out_of_memory(); 852 853 p2->next = NULL; 854 if(p1 == NULL) *listp = p2; 855 else p1->next = p2; 856} 857 858 859int is_dir(char *pathname) 860{ 861 struct stat buf; 862 863 if(stat(pathname, &buf) == -1) 864 return 0; 865 return S_ISDIR(buf.st_mode); 866} 867 868int is_nonempty_file(char *pathname) 869{ 870 struct stat buf; 871 872 if(stat(pathname, &buf) == -1) 873 return 0; 874 875 return S_ISREG(buf.st_mode) && buf.st_size > 0; 876} 877