crunchgen.c revision 6696
1145519Sdarrenr/* 2145510Sdarrenr * Copyright (c) 1994 University of Maryland 3145510Sdarrenr * All Rights Reserved. 4170268Sdarrenr * 5145510Sdarrenr * Permission to use, copy, modify, distribute, and sell this software and its 6145510Sdarrenr * documentation for any purpose is hereby granted without fee, provided that 7145510Sdarrenr * the above copyright notice appear in all copies and that both that 8145510Sdarrenr * copyright notice and this permission notice appear in supporting 9145510Sdarrenr * documentation, and that the name of U.M. not be used in advertising or 10145510Sdarrenr * publicity pertaining to distribution of the software without specific, 11145510Sdarrenr * written prior permission. U.M. makes no representations about the 12145510Sdarrenr * suitability of this software for any purpose. It is provided "as is" 13145510Sdarrenr * without express or implied warranty. 14145510Sdarrenr * 15145510Sdarrenr * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 16145510Sdarrenr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. 17145510Sdarrenr * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18145510Sdarrenr * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 19145510Sdarrenr * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 20145510Sdarrenr * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21145510Sdarrenr * 22145510Sdarrenr * Author: James da Silva, Systems Design and Analysis Group 23145510Sdarrenr * Computer Science Department 24145510Sdarrenr * University of Maryland at College Park 25145510Sdarrenr */ 26145510Sdarrenr/* 27145510Sdarrenr * ======================================================================== 28145510Sdarrenr * crunchgen.c 29145510Sdarrenr * 30145510Sdarrenr * Generates a Makefile and main C file for a crunched executable, 31145510Sdarrenr * from specs given in a .conf file. 32170268Sdarrenr */ 33170268Sdarrenr#include <stdlib.h> 34170268Sdarrenr#include <unistd.h> 35170268Sdarrenr#include <stdio.h> 36170268Sdarrenr#include <ctype.h> 37145510Sdarrenr#include <string.h> 38145510Sdarrenr 39170268Sdarrenr#include <sys/types.h> 40145510Sdarrenr#include <sys/stat.h> 41145510Sdarrenr#include <sys/param.h> 42145510Sdarrenr 43145510Sdarrenr#define CRUNCH_VERSION "0.2" 44145510Sdarrenr 45145510Sdarrenr#define MAXLINELEN 16384 46145510Sdarrenr#define MAXFIELDS 2048 47145510Sdarrenr 48145510Sdarrenr 49145510Sdarrenr/* internal representation of conf file: */ 50145510Sdarrenr 51145510Sdarrenr/* simple lists of strings suffice for most parms */ 52145510Sdarrenr 53145510Sdarrenrtypedef struct strlst { 54145510Sdarrenr struct strlst *next; 55145510Sdarrenr char *str; 56145510Sdarrenr} strlst_t; 57145510Sdarrenr 58170268Sdarrenr/* progs have structure, each field can be set with "special" or calculated */ 59170268Sdarrenr 60145510Sdarrenrtypedef struct prog { 61145510Sdarrenr struct prog *next; 62145510Sdarrenr char *name, *ident; 63145510Sdarrenr char *srcdir, *objdir; 64170268Sdarrenr strlst_t *objs, *objpaths; 65170268Sdarrenr strlst_t *links; 66170268Sdarrenr int goterror; 67145510Sdarrenr} prog_t; 68145510Sdarrenr 69145510Sdarrenr 70145510Sdarrenr/* global state */ 71145510Sdarrenr 72145510Sdarrenrstrlst_t *srcdirs = NULL; 73145510Sdarrenrstrlst_t *libs = NULL; 74145510Sdarrenrprog_t *progs = NULL; 75145510Sdarrenr 76145510Sdarrenrchar line[MAXLINELEN]; 77145510Sdarrenr 78145510Sdarrenrchar confname[MAXPATHLEN], infilename[MAXPATHLEN]; 79145510Sdarrenrchar outmkname[MAXPATHLEN], outcfname[MAXPATHLEN], execfname[MAXPATHLEN]; 80145510Sdarrenrchar tempfname[MAXPATHLEN], cachename[MAXPATHLEN], curfilename[MAXPATHLEN]; 81145510Sdarrenrint linenum = -1; 82145510Sdarrenrint goterror = 0; 83145510Sdarrenr 84145510Sdarrenrchar *pname = "crunchgen"; 85145510Sdarrenr 86145510Sdarrenrint verbose, readcache; /* options */ 87145510Sdarrenrint reading_cache; 88145510Sdarrenr 89145510Sdarrenrint list_mode; 90145510Sdarrenr 91145510Sdarrenr/* general library routines */ 92145510Sdarrenr 93145510Sdarrenrvoid status(char *str); 94145510Sdarrenrvoid out_of_memory(void); 95145510Sdarrenrvoid add_string(strlst_t **listp, char *str); 96145510Sdarrenrint is_dir(char *pathname); 97145510Sdarrenrint is_nonempty_file(char *pathname); 98145510Sdarrenr 99145510Sdarrenr/* helper routines for main() */ 100145510Sdarrenr 101145510Sdarrenrvoid usage(void); 102145510Sdarrenrvoid parse_conf_file(void); 103145510Sdarrenrvoid gen_outputs(void); 104145510Sdarrenr 105145510Sdarrenr 106145510Sdarrenrint main(int argc, char **argv) 107145510Sdarrenr{ 108145510Sdarrenr char *p; 109145510Sdarrenr int optc; 110145510Sdarrenr extern int optind; 111145510Sdarrenr extern char *optarg; 112145510Sdarrenr 113145510Sdarrenr verbose = 1; 114145510Sdarrenr readcache = 1; 115145510Sdarrenr *outmkname = *outcfname = *execfname = '\0'; 116145510Sdarrenr 117145510Sdarrenr if(argc > 0) pname = argv[0]; 118145510Sdarrenr 119145510Sdarrenr while((optc = getopt(argc, argv, "lm:c:e:fq")) != -1) { 120145510Sdarrenr switch(optc) { 121145510Sdarrenr case 'f': readcache = 0; break; 122145510Sdarrenr case 'q': verbose = 0; break; 123145510Sdarrenr 124145510Sdarrenr case 'm': strcpy(outmkname, optarg); break; 125145510Sdarrenr case 'c': strcpy(outcfname, optarg); break; 126145510Sdarrenr case 'e': strcpy(execfname, optarg); break; 127145510Sdarrenr case 'l': list_mode++; verbose = 0; break; 128170268Sdarrenr 129170268Sdarrenr case '?': 130170268Sdarrenr default: usage(); 131145510Sdarrenr } 132145510Sdarrenr } 133145510Sdarrenr 134145510Sdarrenr argc -= optind; 135145510Sdarrenr argv += optind; 136145510Sdarrenr 137145510Sdarrenr if(argc != 1) usage(); 138145510Sdarrenr 139170268Sdarrenr /* 140145510Sdarrenr * generate filenames 141145510Sdarrenr */ 142145510Sdarrenr 143145510Sdarrenr strcpy(infilename, argv[0]); 144145510Sdarrenr 145145510Sdarrenr /* confname = `basename infilename .conf` */ 146145510Sdarrenr 147145510Sdarrenr if((p=strrchr(infilename, '/')) != NULL) strcpy(confname, p+1); 148145510Sdarrenr else strcpy(confname, infilename); 149145510Sdarrenr if((p=strrchr(confname, '.')) != NULL && !strcmp(p, ".conf")) *p = '\0'; 150145510Sdarrenr 151145510Sdarrenr if(!*outmkname) sprintf(outmkname, "%s.mk", confname); 152145510Sdarrenr if(!*outcfname) sprintf(outcfname, "%s.c", confname); 153145510Sdarrenr if(!*execfname) sprintf(execfname, "%s", confname); 154170268Sdarrenr 155170268Sdarrenr sprintf(cachename, "%s.cache", confname); 156145510Sdarrenr sprintf(tempfname, ".tmp_%sXXXXXX", confname); 157145510Sdarrenr if(mktemp(tempfname) == NULL) { 158145510Sdarrenr perror(tempfname); 159145510Sdarrenr exit(1); 160145510Sdarrenr } 161145510Sdarrenr 162145510Sdarrenr parse_conf_file(); 163145510Sdarrenr if (list_mode) 164145510Sdarrenr exit(goterror); 165145510Sdarrenr 166145510Sdarrenr gen_outputs(); 167145510Sdarrenr 168145510Sdarrenr exit(goterror); 169145510Sdarrenr} 170145510Sdarrenr 171145510Sdarrenr 172145510Sdarrenrvoid usage(void) 173145510Sdarrenr{ 174145510Sdarrenr fprintf(stderr, 175145510Sdarrenr "%s [-fq] [-m <makefile>] [-c <c file>] [-e <exec file>] <conffile>\n", 176170268Sdarrenr pname); 177170268Sdarrenr exit(1); 178170268Sdarrenr} 179170268Sdarrenr 180170268Sdarrenr 181145510Sdarrenr/* 182145510Sdarrenr * ======================================================================== 183145510Sdarrenr * parse_conf_file subsystem 184170268Sdarrenr * 185170268Sdarrenr */ 186145510Sdarrenr 187170268Sdarrenr/* helper routines for parse_conf_file */ 188170268Sdarrenr 189145510Sdarrenrvoid parse_one_file(char *filename); 190145510Sdarrenrvoid parse_line(char *line, int *fc, char **fv, int nf); 191145510Sdarrenrvoid add_srcdirs(int argc, char **argv); 192145510Sdarrenrvoid add_progs(int argc, char **argv); 193145510Sdarrenrvoid add_link(int argc, char **argv); 194145510Sdarrenrvoid add_libs(int argc, char **argv); 195145510Sdarrenrvoid add_special(int argc, char **argv); 196145510Sdarrenr 197145510Sdarrenrprog_t *find_prog(char *str); 198145510Sdarrenrvoid add_prog(char *progname); 199145510Sdarrenr 200145510Sdarrenr 201145510Sdarrenrvoid parse_conf_file(void) 202145510Sdarrenr{ 203145510Sdarrenr if(!is_nonempty_file(infilename)) { 204145510Sdarrenr fprintf(stderr, "%s: fatal: input file \"%s\" not found.\n", 205145510Sdarrenr pname, infilename); 206145510Sdarrenr exit(1); 207145510Sdarrenr } 208145510Sdarrenr parse_one_file(infilename); 209145510Sdarrenr if(readcache && is_nonempty_file(cachename)) { 210145510Sdarrenr reading_cache = 1; 211145510Sdarrenr parse_one_file(cachename); 212145510Sdarrenr } 213145510Sdarrenr} 214145510Sdarrenr 215145510Sdarrenr 216145510Sdarrenrvoid parse_one_file(char *filename) 217145510Sdarrenr{ 218145510Sdarrenr char *fieldv[MAXFIELDS]; 219145510Sdarrenr int fieldc; 220145510Sdarrenr void (*f)(int c, char **v); 221145510Sdarrenr FILE *cf; 222145510Sdarrenr 223145510Sdarrenr sprintf(line, "reading %s", filename); 224145510Sdarrenr status(line); 225145510Sdarrenr strcpy(curfilename, filename); 226145510Sdarrenr 227145510Sdarrenr if((cf = fopen(curfilename, "r")) == NULL) { 228145510Sdarrenr perror(curfilename); 229145510Sdarrenr goterror = 1; 230145510Sdarrenr return; 231145510Sdarrenr } 232145510Sdarrenr 233145510Sdarrenr linenum = 0; 234145510Sdarrenr while(fgets(line, MAXLINELEN, cf) != NULL) { 235145510Sdarrenr linenum++; 236145510Sdarrenr parse_line(line, &fieldc, fieldv, MAXFIELDS); 237145510Sdarrenr if(fieldc < 1) continue; 238145510Sdarrenr if(!strcmp(fieldv[0], "srcdirs")) f = add_srcdirs; 239145510Sdarrenr else if(!strcmp(fieldv[0], "progs")) f = add_progs; 240145510Sdarrenr else if(!strcmp(fieldv[0], "ln")) f = add_link; 241145510Sdarrenr else if(!strcmp(fieldv[0], "libs")) f = add_libs; 242145510Sdarrenr else if(!strcmp(fieldv[0], "special")) f = add_special; 243145510Sdarrenr else { 244145510Sdarrenr fprintf(stderr, "%s:%d: skipping unknown command `%s'.\n", 245145510Sdarrenr curfilename, linenum, fieldv[0]); 246145510Sdarrenr goterror = 1; 247145510Sdarrenr continue; 248145510Sdarrenr } 249145510Sdarrenr if(fieldc < 2) { 250145510Sdarrenr fprintf(stderr, 251145510Sdarrenr "%s:%d: %s command needs at least 1 argument, skipping.\n", 252145510Sdarrenr curfilename, linenum, fieldv[0]); 253145510Sdarrenr goterror = 1; 254145510Sdarrenr continue; 255145510Sdarrenr } 256145510Sdarrenr f(fieldc, fieldv); 257145510Sdarrenr } 258145510Sdarrenr 259145510Sdarrenr if(ferror(cf)) { 260145510Sdarrenr perror(curfilename); 261145510Sdarrenr goterror = 1; 262145510Sdarrenr } 263145510Sdarrenr fclose(cf); 264145510Sdarrenr} 265145510Sdarrenr 266145510Sdarrenr 267145510Sdarrenrvoid parse_line(char *line, int *fc, char **fv, int nf) 268145510Sdarrenr{ 269145510Sdarrenr char *p; 270145510Sdarrenr 271145510Sdarrenr p = line; 272145510Sdarrenr *fc = 0; 273145510Sdarrenr while(1) { 274145510Sdarrenr while(isspace(*p)) p++; 275145510Sdarrenr if(*p == '\0' || *p == '#') break; 276145510Sdarrenr 277145510Sdarrenr if(*fc < nf) fv[(*fc)++] = p; 278145510Sdarrenr while(*p && !isspace(*p) && *p != '#') p++; 279145510Sdarrenr if(*p == '\0' || *p == '#') break; 280145510Sdarrenr *p++ = '\0'; 281145510Sdarrenr } 282145510Sdarrenr if(*p) *p = '\0'; /* needed for '#' case */ 283145510Sdarrenr} 284145510Sdarrenr 285145510Sdarrenr 286145510Sdarrenrvoid add_srcdirs(int argc, char **argv) 287145510Sdarrenr{ 288145510Sdarrenr int i; 289145510Sdarrenr 290145510Sdarrenr for(i=1;i<argc;i++) { 291145510Sdarrenr if(is_dir(argv[i])) 292145510Sdarrenr add_string(&srcdirs, argv[i]); 293145510Sdarrenr else { 294145510Sdarrenr fprintf(stderr, "%s:%d: `%s' is not a directory, skipping it.\n", 295145510Sdarrenr curfilename, linenum, argv[i]); 296145510Sdarrenr goterror = 1; 297145510Sdarrenr } 298145510Sdarrenr } 299145510Sdarrenr} 300145510Sdarrenr 301145510Sdarrenr 302145510Sdarrenrvoid add_progs(int argc, char **argv) 303145510Sdarrenr{ 304145510Sdarrenr int i; 305145510Sdarrenr 306145510Sdarrenr for(i=1;i<argc;i++) 307145510Sdarrenr add_prog(argv[i]); 308145510Sdarrenr} 309145510Sdarrenr 310145510Sdarrenr 311145510Sdarrenrvoid add_prog(char *progname) 312145510Sdarrenr{ 313145510Sdarrenr prog_t *p1, *p2; 314145510Sdarrenr 315145510Sdarrenr /* add to end, but be smart about dups */ 316145510Sdarrenr 317145510Sdarrenr for(p1 = NULL, p2 = progs; p2 != NULL; p1 = p2, p2 = p2->next) 318145510Sdarrenr if(!strcmp(p2->name, progname)) return; 319145510Sdarrenr 320145510Sdarrenr p2 = malloc(sizeof(prog_t)); 321145510Sdarrenr if(p2) p2->name = strdup(progname); 322145510Sdarrenr if(!p2 || !p2->name) 323145510Sdarrenr out_of_memory(); 324145510Sdarrenr 325145510Sdarrenr p2->next = NULL; 326145510Sdarrenr if(p1 == NULL) progs = p2; 327145510Sdarrenr else p1->next = p2; 328145510Sdarrenr 329145510Sdarrenr p2->ident = p2->srcdir = p2->objdir = NULL; 330145510Sdarrenr p2->links = p2->objs = NULL; 331145510Sdarrenr p2->goterror = 0; 332145510Sdarrenr if (list_mode) 333145510Sdarrenr printf("%s\n",progname); 334145510Sdarrenr} 335145510Sdarrenr 336145510Sdarrenr 337145510Sdarrenrvoid add_link(int argc, char **argv) 338145510Sdarrenr{ 339145510Sdarrenr int i; 340145510Sdarrenr prog_t *p = find_prog(argv[1]); 341145510Sdarrenr 342145510Sdarrenr if(p == NULL) { 343145510Sdarrenr fprintf(stderr, 344145510Sdarrenr "%s:%d: no prog %s previously declared, skipping link.\n", 345145510Sdarrenr curfilename, linenum, argv[1]); 346145510Sdarrenr goterror = 1; 347145510Sdarrenr return; 348145510Sdarrenr } 349145510Sdarrenr for(i=2;i<argc;i++) { 350145510Sdarrenr if (list_mode) 351145510Sdarrenr printf("%s\n",argv[i]); 352145510Sdarrenr add_string(&p->links, argv[i]); 353145510Sdarrenr } 354145510Sdarrenr} 355145510Sdarrenr 356145510Sdarrenr 357145510Sdarrenrvoid add_libs(int argc, char **argv) 358145510Sdarrenr{ 359145510Sdarrenr int i; 360145510Sdarrenr 361145510Sdarrenr for(i=1;i<argc;i++) 362145510Sdarrenr add_string(&libs, argv[i]); 363145510Sdarrenr} 364145510Sdarrenr 365145510Sdarrenr 366145510Sdarrenrvoid add_special(int argc, char **argv) 367145510Sdarrenr{ 368145510Sdarrenr int i; 369145510Sdarrenr prog_t *p = find_prog(argv[1]); 370145510Sdarrenr 371145510Sdarrenr if(p == NULL) { 372145510Sdarrenr if(reading_cache) return; 373145510Sdarrenr fprintf(stderr, 374145510Sdarrenr "%s:%d: no prog %s previously declared, skipping special.\n", 375145510Sdarrenr curfilename, linenum, argv[1]); 376145510Sdarrenr goterror = 1; 377145510Sdarrenr return; 378145510Sdarrenr } 379145510Sdarrenr 380145510Sdarrenr if(!strcmp(argv[2], "ident")) { 381145510Sdarrenr if(argc != 4) goto argcount; 382145510Sdarrenr if((p->ident = strdup(argv[3])) == NULL) 383145510Sdarrenr out_of_memory(); 384145510Sdarrenr } 385145510Sdarrenr else if(!strcmp(argv[2], "srcdir")) { 386145510Sdarrenr if(argc != 4) goto argcount; 387145510Sdarrenr if((p->srcdir = strdup(argv[3])) == NULL) 388145510Sdarrenr out_of_memory(); 389145510Sdarrenr } 390145510Sdarrenr else if(!strcmp(argv[2], "objdir")) { 391145510Sdarrenr if(argc != 4) goto argcount; 392145510Sdarrenr if((p->objdir = strdup(argv[3])) == NULL) 393145510Sdarrenr out_of_memory(); 394145510Sdarrenr } 395145510Sdarrenr else if(!strcmp(argv[2], "objs")) { 396145510Sdarrenr p->objs = NULL; 397145510Sdarrenr for(i=3;i<argc;i++) 398145510Sdarrenr add_string(&p->objs, argv[i]); 399145510Sdarrenr } 400145510Sdarrenr else if(!strcmp(argv[2], "objpaths")) { 401145510Sdarrenr p->objpaths = NULL; 402145510Sdarrenr for(i=3;i<argc;i++) 403145510Sdarrenr add_string(&p->objpaths, argv[i]); 404145510Sdarrenr } 405145510Sdarrenr else { 406145510Sdarrenr fprintf(stderr, "%s:%d: bad parameter name `%s', skipping line.\n", 407145510Sdarrenr curfilename, linenum, argv[2]); 408145510Sdarrenr goterror = 1; 409145510Sdarrenr } 410145510Sdarrenr return; 411145510Sdarrenr 412145510Sdarrenr 413145510Sdarrenr argcount: 414145510Sdarrenr fprintf(stderr, 415145510Sdarrenr "%s:%d: too %s arguments, expected \"special %s %s <string>\".\n", 416145510Sdarrenr curfilename, linenum, argc < 4? "few" : "many", argv[1], argv[2]); 417145510Sdarrenr goterror = 1; 418145510Sdarrenr} 419145510Sdarrenr 420145510Sdarrenr 421145510Sdarrenrprog_t *find_prog(char *str) 422145510Sdarrenr{ 423145510Sdarrenr prog_t *p; 424145510Sdarrenr 425145510Sdarrenr for(p = progs; p != NULL; p = p->next) 426145510Sdarrenr if(!strcmp(p->name, str)) return p; 427145510Sdarrenr 428145510Sdarrenr return NULL; 429145510Sdarrenr} 430145510Sdarrenr 431145510Sdarrenr 432145510Sdarrenr/* 433145510Sdarrenr * ======================================================================== 434145510Sdarrenr * gen_outputs subsystem 435145510Sdarrenr * 436145510Sdarrenr */ 437145510Sdarrenr 438145510Sdarrenr/* helper subroutines */ 439145510Sdarrenr 440145510Sdarrenrvoid remove_error_progs(void); 441145510Sdarrenrvoid fillin_program(prog_t *p); 442145510Sdarrenrvoid gen_specials_cache(void); 443145510Sdarrenrvoid gen_output_makefile(void); 444145510Sdarrenrvoid gen_output_cfile(void); 445145510Sdarrenr 446145510Sdarrenrvoid fillin_program_objs(prog_t *p, char *path); 447145510Sdarrenrvoid top_makefile_rules(FILE *outmk); 448145510Sdarrenrvoid prog_makefile_rules(FILE *outmk, prog_t *p); 449145510Sdarrenrvoid output_strlst(FILE *outf, strlst_t *lst); 450145510Sdarrenrchar *genident(char *str); 451145510Sdarrenrchar *dir_search(char *progname); 452145510Sdarrenr 453145510Sdarrenr 454145510Sdarrenrvoid gen_outputs(void) 455145510Sdarrenr{ 456145510Sdarrenr prog_t *p; 457145510Sdarrenr 458145510Sdarrenr for(p = progs; p != NULL; p = p->next) 459145510Sdarrenr fillin_program(p); 460145510Sdarrenr 461145510Sdarrenr remove_error_progs(); 462145510Sdarrenr gen_specials_cache(); 463145510Sdarrenr gen_output_cfile(); 464145510Sdarrenr gen_output_makefile(); 465145510Sdarrenr status(""); 466145510Sdarrenr fprintf(stderr, 467145510Sdarrenr "Run \"make -f %s objs exe\" to build crunched binary.\n", 468145510Sdarrenr outmkname); 469145510Sdarrenr} 470145510Sdarrenr 471145510Sdarrenr 472145510Sdarrenrvoid fillin_program(prog_t *p) 473145510Sdarrenr{ 474145510Sdarrenr char path[MAXPATHLEN]; 475145510Sdarrenr char *srcparent; 476145510Sdarrenr strlst_t *s; 477145510Sdarrenr 478145510Sdarrenr sprintf(line, "filling in parms for %s", p->name); 479145510Sdarrenr status(line); 480145510Sdarrenr 481145510Sdarrenr if(!p->ident) 482145510Sdarrenr p->ident = genident(p->name); 483145510Sdarrenr if(!p->srcdir) { 484145510Sdarrenr srcparent = dir_search(p->name); 485145510Sdarrenr if(srcparent) 486145510Sdarrenr sprintf(path, "%s/%s", srcparent, p->name); 487145510Sdarrenr if(is_dir(path)) 488145510Sdarrenr p->srcdir = strdup(path); 489145510Sdarrenr } 490145510Sdarrenr if(!p->objdir && p->srcdir) { 491145510Sdarrenr sprintf(path, "%s/obj", p->srcdir); 492145510Sdarrenr if(is_dir(path)) 493145510Sdarrenr p->objdir = strdup(path); 494145510Sdarrenr else 495145510Sdarrenr p->objdir = p->srcdir; 496145510Sdarrenr } 497145510Sdarrenr 498145510Sdarrenr if(p->srcdir) sprintf(path, "%s/Makefile", p->srcdir); 499145510Sdarrenr if(!p->objs && p->srcdir && is_nonempty_file(path)) 500145510Sdarrenr fillin_program_objs(p, path); 501145510Sdarrenr 502145630Sdarrenr if(!p->objpaths && p->objdir && p->objs) 503145510Sdarrenr for(s = p->objs; s != NULL; s = s->next) { 504145510Sdarrenr sprintf(line, "%s/%s", p->objdir, s->str); 505145510Sdarrenr add_string(&p->objpaths, line); 506145510Sdarrenr } 507145510Sdarrenr 508145510Sdarrenr if(!p->srcdir && verbose) 509145510Sdarrenr fprintf(stderr, "%s: %s: warning: could not find source directory.\n", 510145510Sdarrenr infilename, p->name); 511145510Sdarrenr if(!p->objs && verbose) 512145510Sdarrenr fprintf(stderr, "%s: %s: warning: could not find any .o files.\n", 513145510Sdarrenr infilename, p->name); 514145510Sdarrenr 515145510Sdarrenr if(!p->objpaths) { 516145510Sdarrenr fprintf(stderr, 517145510Sdarrenr "%s: %s: error: no objpaths specified or calculated.\n", 518145510Sdarrenr infilename, p->name); 519145510Sdarrenr p->goterror = goterror = 1; 520145510Sdarrenr } 521145510Sdarrenr} 522145510Sdarrenr 523145510Sdarrenrvoid fillin_program_objs(prog_t *p, char *path) 524145510Sdarrenr{ 525145510Sdarrenr char *obj, *cp; 526145510Sdarrenr int rc; 527145510Sdarrenr FILE *f; 528145510Sdarrenr 529145510Sdarrenr /* discover the objs from the srcdir Makefile */ 530145510Sdarrenr 531145510Sdarrenr if((f = fopen(tempfname, "w")) == NULL) { 532145510Sdarrenr perror(tempfname); 533145510Sdarrenr goterror = 1; 534145510Sdarrenr return; 535145510Sdarrenr } 536145510Sdarrenr 537145510Sdarrenr fprintf(f, ".include \"%s\"\n", path); 538145510Sdarrenr fprintf(f, ".if defined(PROG) && !defined(OBJS)\n"); 539145510Sdarrenr fprintf(f, "OBJS=${PROG}.o\n"); 540145510Sdarrenr fprintf(f, ".endif\n"); 541145510Sdarrenr fprintf(f, "crunchgen_objs:\n\t@echo 'OBJS= '${OBJS}\n"); 542145510Sdarrenr fclose(f); 543145510Sdarrenr 544145510Sdarrenr sprintf(line, "make -f %s crunchgen_objs 2>&1", tempfname); 545145510Sdarrenr if((f = popen(line, "r")) == NULL) { 546170268Sdarrenr perror("submake pipe"); 547145510Sdarrenr goterror = 1; 548145510Sdarrenr return; 549145510Sdarrenr } 550145510Sdarrenr 551145510Sdarrenr while(fgets(line, MAXLINELEN, f)) { 552145510Sdarrenr if(strncmp(line, "OBJS= ", 6)) { 553145510Sdarrenr fprintf(stderr, "make error: %s", line); 554145510Sdarrenr goterror = 1; 555145510Sdarrenr continue; 556145510Sdarrenr } 557145510Sdarrenr cp = line + 6; 558145510Sdarrenr while(isspace(*cp)) cp++; 559145510Sdarrenr while(*cp) { 560145510Sdarrenr obj = cp; 561170268Sdarrenr while(*cp && !isspace(*cp)) cp++; 562170268Sdarrenr if(*cp) *cp++ = '\0'; 563170268Sdarrenr add_string(&p->objs, obj); 564170268Sdarrenr while(isspace(*cp)) cp++; 565170268Sdarrenr } 566170268Sdarrenr } 567170268Sdarrenr if((rc=pclose(f)) != 0) { 568170268Sdarrenr fprintf(stderr, "make error: make returned %d\n", rc); 569170268Sdarrenr goterror = 1; 570170268Sdarrenr } 571170268Sdarrenr unlink(tempfname); 572170268Sdarrenr} 573170268Sdarrenr 574170268Sdarrenrvoid remove_error_progs(void) 575170268Sdarrenr{ 576170268Sdarrenr prog_t *p1, *p2; 577170268Sdarrenr 578170268Sdarrenr p1 = NULL; p2 = progs; 579170268Sdarrenr while(p2 != NULL) { 580170268Sdarrenr if(!p2->goterror) 581170268Sdarrenr p1 = p2, p2 = p2->next; 582170268Sdarrenr else { 583170268Sdarrenr /* delete it from linked list */ 584170268Sdarrenr fprintf(stderr, "%s: %s: ignoring program because of errors.\n", 585170268Sdarrenr infilename, p2->name); 586170268Sdarrenr if(p1) p1->next = p2->next; 587170268Sdarrenr else progs = p2->next; 588170268Sdarrenr p2 = p2->next; 589170268Sdarrenr } 590170268Sdarrenr } 591170268Sdarrenr} 592170268Sdarrenr 593170268Sdarrenrvoid gen_specials_cache(void) 594170268Sdarrenr{ 595170268Sdarrenr FILE *cachef; 596170268Sdarrenr prog_t *p; 597170268Sdarrenr 598170268Sdarrenr sprintf(line, "generating %s", cachename); 599170268Sdarrenr status(line); 600170268Sdarrenr 601170268Sdarrenr if((cachef = fopen(cachename, "w")) == NULL) { 602170268Sdarrenr perror(cachename); 603170268Sdarrenr goterror = 1; 604170268Sdarrenr return; 605170268Sdarrenr } 606170268Sdarrenr 607170268Sdarrenr fprintf(cachef, "# %s - parm cache generated from %s by crunchgen %s\n\n", 608170268Sdarrenr cachename, infilename, CRUNCH_VERSION); 609170268Sdarrenr 610170268Sdarrenr for(p = progs; p != NULL; p = p->next) { 611170268Sdarrenr fprintf(cachef, "\n"); 612170268Sdarrenr if(p->srcdir) 613170268Sdarrenr fprintf(cachef, "special %s srcdir %s\n", p->name, p->srcdir); 614170268Sdarrenr if(p->objdir) 615170268Sdarrenr fprintf(cachef, "special %s objdir %s\n", p->name, p->objdir); 616170268Sdarrenr if(p->objs) { 617170268Sdarrenr fprintf(cachef, "special %s objs", p->name); 618170268Sdarrenr output_strlst(cachef, p->objs); 619170268Sdarrenr } 620170268Sdarrenr fprintf(cachef, "special %s objpaths", p->name); 621170268Sdarrenr output_strlst(cachef, p->objpaths); 622170268Sdarrenr } 623170268Sdarrenr fclose(cachef); 624170268Sdarrenr} 625170268Sdarrenr 626170268Sdarrenr 627170268Sdarrenrvoid gen_output_makefile(void) 628170268Sdarrenr{ 629170268Sdarrenr prog_t *p; 630170268Sdarrenr FILE *outmk; 631170268Sdarrenr 632170268Sdarrenr sprintf(line, "generating %s", outmkname); 633170268Sdarrenr status(line); 634170268Sdarrenr 635170268Sdarrenr if((outmk = fopen(outmkname, "w")) == NULL) { 636170268Sdarrenr perror(outmkname); 637170268Sdarrenr goterror = 1; 638170268Sdarrenr return; 639170268Sdarrenr } 640170268Sdarrenr 641170268Sdarrenr fprintf(outmk, "# %s - generated from %s by crunchgen %s\n\n", 642170268Sdarrenr outmkname, infilename, CRUNCH_VERSION); 643170268Sdarrenr 644170268Sdarrenr top_makefile_rules(outmk); 645170268Sdarrenr 646170268Sdarrenr for(p = progs; p != NULL; p = p->next) 647170268Sdarrenr prog_makefile_rules(outmk, p); 648170268Sdarrenr 649170268Sdarrenr fprintf(outmk, "\n# ========\n"); 650170268Sdarrenr fclose(outmk); 651170268Sdarrenr} 652170268Sdarrenr 653170268Sdarrenr 654170268Sdarrenrvoid gen_output_cfile(void) 655170268Sdarrenr{ 656170268Sdarrenr extern char *crunched_skel[]; 657170268Sdarrenr char **cp; 658170268Sdarrenr FILE *outcf; 659170268Sdarrenr prog_t *p; 660170268Sdarrenr strlst_t *s; 661170268Sdarrenr 662170268Sdarrenr sprintf(line, "generating %s", outcfname); 663170268Sdarrenr status(line); 664170268Sdarrenr 665170268Sdarrenr if((outcf = fopen(outcfname, "w")) == NULL) { 666170268Sdarrenr perror(outcfname); 667170268Sdarrenr goterror = 1; 668170268Sdarrenr return; 669170268Sdarrenr } 670170268Sdarrenr 671170268Sdarrenr fprintf(outcf, 672170268Sdarrenr "/* %s - generated from %s by crunchgen %s */\n", 673170268Sdarrenr outcfname, infilename, CRUNCH_VERSION); 674170268Sdarrenr 675170268Sdarrenr fprintf(outcf, "#define EXECNAME \"%s\"\n", execfname); 676170268Sdarrenr for(cp = crunched_skel; *cp != NULL; cp++) 677170268Sdarrenr fprintf(outcf, "%s\n", *cp); 678170268Sdarrenr 679170268Sdarrenr for(p = progs; p != NULL; p = p->next) 680170268Sdarrenr fprintf(outcf, "extern int _crunched_%s_stub();\n", p->ident); 681170268Sdarrenr 682170268Sdarrenr fprintf(outcf, "\nstruct stub entry_points[] = {\n"); 683170268Sdarrenr for(p = progs; p != NULL; p = p->next) { 684170268Sdarrenr fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n", 685170268Sdarrenr p->name, p->ident); 686170268Sdarrenr for(s = p->links; s != NULL; s = s->next) 687170268Sdarrenr fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n", 688170268Sdarrenr s->str, p->ident); 689170268Sdarrenr } 690170268Sdarrenr 691170268Sdarrenr fprintf(outcf, "\t{ EXECNAME, crunched_main },\n"); 692170268Sdarrenr fprintf(outcf, "\t{ NULL, NULL }\n};\n"); 693170268Sdarrenr fclose(outcf); 694170268Sdarrenr} 695170268Sdarrenr 696170268Sdarrenr 697170268Sdarrenrchar *genident(char *str) 698170268Sdarrenr{ 699170268Sdarrenr char *n,*s,*d; 700170268Sdarrenr 701170268Sdarrenr /* 702170268Sdarrenr * generates a Makefile/C identifier from a program name, mapping '-' to 703170268Sdarrenr * '_' and ignoring all other non-identifier characters. This leads to 704170268Sdarrenr * programs named "foo.bar" and "foobar" to map to the same identifier. 705170268Sdarrenr */ 706170268Sdarrenr 707170268Sdarrenr if((n = strdup(str)) == NULL) 708170268Sdarrenr return NULL; 709170268Sdarrenr for(d = s = n; *s != '\0'; s++) { 710170268Sdarrenr if(*s == '-') *d++ = '_'; 711170268Sdarrenr else if(*s == '_' || isalnum(*s)) *d++ = *s; 712170268Sdarrenr } 713170268Sdarrenr *d = '\0'; 714170268Sdarrenr return n; 715170268Sdarrenr} 716170268Sdarrenr 717170268Sdarrenr 718170268Sdarrenrchar *dir_search(char *progname) 719170268Sdarrenr{ 720170268Sdarrenr char path[MAXPATHLEN]; 721170268Sdarrenr strlst_t *dir; 722170268Sdarrenr 723170268Sdarrenr for(dir=srcdirs; dir != NULL; dir=dir->next) { 724170268Sdarrenr sprintf(path, "%s/%s", dir->str, progname); 725170268Sdarrenr if(is_dir(path)) return dir->str; 726170268Sdarrenr } 727170268Sdarrenr return NULL; 728170268Sdarrenr} 729170268Sdarrenr 730170268Sdarrenr 731170268Sdarrenrvoid top_makefile_rules(FILE *outmk) 732170268Sdarrenr{ 733170268Sdarrenr prog_t *p; 734170268Sdarrenr 735170268Sdarrenr fprintf(outmk, "LIBS="); 736170268Sdarrenr output_strlst(outmk, libs); 737170268Sdarrenr 738170268Sdarrenr fprintf(outmk, "CRUNCHED_OBJS="); 739170268Sdarrenr for(p = progs; p != NULL; p = p->next) 740170268Sdarrenr fprintf(outmk, " %s.lo", p->name); 741170268Sdarrenr fprintf(outmk, "\n"); 742170268Sdarrenr 743170268Sdarrenr fprintf(outmk, "SUBMAKE_TARGETS="); 744170268Sdarrenr for(p = progs; p != NULL; p = p->next) 745170268Sdarrenr fprintf(outmk, " %s_make", p->ident); 746170268Sdarrenr fprintf(outmk, "\n\n"); 747170268Sdarrenr 748170268Sdarrenr fprintf(outmk, "%s: %s.o $(CRUNCHED_OBJS)\n", 749170268Sdarrenr execfname, execfname); 750170268Sdarrenr fprintf(outmk, "\t$(CC) -static -o %s %s.o $(CRUNCHED_OBJS) $(LIBS)\n", 751170268Sdarrenr execfname, execfname); 752170268Sdarrenr fprintf(outmk, "\tstrip %s\n", execfname); 753170268Sdarrenr fprintf(outmk, "all: objs exe\nobjs: $(SUBMAKE_TARGETS)\n"); 754170268Sdarrenr fprintf(outmk, "exe: %s\n", execfname); 755170268Sdarrenr fprintf(outmk, "clean:\n\trm -f %s *.lo *.o *_stub.c\n", 756170268Sdarrenr execfname); 757170268Sdarrenr} 758170268Sdarrenr 759170268Sdarrenr 760170268Sdarrenrvoid prog_makefile_rules(FILE *outmk, prog_t *p) 761170268Sdarrenr{ 762170268Sdarrenr fprintf(outmk, "\n# -------- %s\n\n", p->name); 763170268Sdarrenr 764170268Sdarrenr if(p->srcdir && p->objs) { 765170268Sdarrenr fprintf(outmk, "%s_SRCDIR=%s\n", p->ident, p->srcdir); 766170268Sdarrenr fprintf(outmk, "%s_OBJS=", p->ident); 767170268Sdarrenr output_strlst(outmk, p->objs); 768170268Sdarrenr fprintf(outmk, "%s_make:\n", p->ident); 769170268Sdarrenr fprintf(outmk, "\t(cd $(%s_SRCDIR); make $(%s_OBJS))\n\n", 770170268Sdarrenr p->ident, p->ident); 771170268Sdarrenr } 772170268Sdarrenr else 773170268Sdarrenr fprintf(outmk, "%s_make:\n\t@echo \"** cannot make objs for %s\"\n\n", 774170268Sdarrenr p->ident, p->name); 775170268Sdarrenr 776170268Sdarrenr fprintf(outmk, "%s_OBJPATHS=", p->ident); 777170268Sdarrenr output_strlst(outmk, p->objpaths); 778170268Sdarrenr 779170268Sdarrenr fprintf(outmk, "%s_stub.c:\n", p->name); 780170268Sdarrenr fprintf(outmk, "\techo \"" 781170268Sdarrenr "int _crunched_%s_stub(int argc, char **argv, char **envp)" 782170268Sdarrenr "{return main(argc,argv,envp);}\" >%s_stub.c\n", 783170268Sdarrenr p->ident, p->name); 784170268Sdarrenr fprintf(outmk, "%s.lo: %s_stub.o $(%s_OBJPATHS)\n", 785170268Sdarrenr p->name, p->name, p->ident); 786170268Sdarrenr fprintf(outmk, "\tld -dc -r -o %s.lo %s_stub.o $(%s_OBJPATHS)\n", 787170268Sdarrenr p->name, p->name, p->ident); 788170268Sdarrenr fprintf(outmk, "\tcrunchide -k __crunched_%s_stub %s.lo\n", 789170268Sdarrenr p->ident, p->name); 790170268Sdarrenr} 791170268Sdarrenr 792170268Sdarrenrvoid output_strlst(FILE *outf, strlst_t *lst) 793170268Sdarrenr{ 794170268Sdarrenr for(; lst != NULL; lst = lst->next) 795170268Sdarrenr fprintf(outf, " %s", lst->str); 796170268Sdarrenr fprintf(outf, "\n"); 797170268Sdarrenr} 798170268Sdarrenr 799170268Sdarrenr 800170268Sdarrenr/* 801170268Sdarrenr * ======================================================================== 802170268Sdarrenr * general library routines 803170268Sdarrenr * 804170268Sdarrenr */ 805170268Sdarrenr 806170268Sdarrenrvoid status(char *str) 807170268Sdarrenr{ 808170268Sdarrenr static int lastlen = 0; 809170268Sdarrenr int len, spaces; 810170268Sdarrenr 811170268Sdarrenr if(!verbose) return; 812170268Sdarrenr 813170268Sdarrenr len = strlen(str); 814170268Sdarrenr spaces = lastlen - len; 815170268Sdarrenr if(spaces < 1) spaces = 1; 816170268Sdarrenr 817170268Sdarrenr fprintf(stderr, " [%s]%*.*s\r", str, spaces, spaces, " "); 818170268Sdarrenr fflush(stderr); 819170268Sdarrenr lastlen = len; 820170268Sdarrenr} 821170268Sdarrenr 822170268Sdarrenr 823170268Sdarrenrvoid out_of_memory(void) 824170268Sdarrenr{ 825170268Sdarrenr fprintf(stderr, "%s: %d: out of memory, stopping.\n", infilename, linenum); 826170268Sdarrenr exit(1); 827170268Sdarrenr} 828170268Sdarrenr 829170268Sdarrenr 830170268Sdarrenrvoid add_string(strlst_t **listp, char *str) 831170268Sdarrenr{ 832170268Sdarrenr strlst_t *p1, *p2; 833170268Sdarrenr 834170268Sdarrenr /* add to end, but be smart about dups */ 835170268Sdarrenr 836170268Sdarrenr for(p1 = NULL, p2 = *listp; p2 != NULL; p1 = p2, p2 = p2->next) 837170268Sdarrenr if(!strcmp(p2->str, str)) return; 838170268Sdarrenr 839170268Sdarrenr p2 = malloc(sizeof(strlst_t)); 840170268Sdarrenr if(p2) p2->str = strdup(str); 841170268Sdarrenr if(!p2 || !p2->str) 842170268Sdarrenr out_of_memory(); 843170268Sdarrenr 844170268Sdarrenr p2->next = NULL; 845170268Sdarrenr if(p1 == NULL) *listp = p2; 846170268Sdarrenr else p1->next = p2; 847170268Sdarrenr} 848170268Sdarrenr 849170268Sdarrenr 850170268Sdarrenrint is_dir(char *pathname) 851170268Sdarrenr{ 852170268Sdarrenr struct stat buf; 853170268Sdarrenr 854170268Sdarrenr if(stat(pathname, &buf) == -1) 855170268Sdarrenr return 0; 856170268Sdarrenr return S_ISDIR(buf.st_mode); 857170268Sdarrenr} 858170268Sdarrenr 859170268Sdarrenrint is_nonempty_file(char *pathname) 860170268Sdarrenr{ 861170268Sdarrenr struct stat buf; 862170268Sdarrenr 863170268Sdarrenr if(stat(pathname, &buf) == -1) 864170268Sdarrenr return 0; 865170268Sdarrenr 866170268Sdarrenr return S_ISREG(buf.st_mode) && buf.st_size > 0; 867170268Sdarrenr} 868170268Sdarrenr