crunchgen.c revision 29453
11722Sjkh/* 21722Sjkh * Copyright (c) 1994 University of Maryland 31722Sjkh * All Rights Reserved. 41722Sjkh * 51722Sjkh * Permission to use, copy, modify, distribute, and sell this software and its 61722Sjkh * documentation for any purpose is hereby granted without fee, provided that 71722Sjkh * the above copyright notice appear in all copies and that both that 81722Sjkh * copyright notice and this permission notice appear in supporting 91722Sjkh * documentation, and that the name of U.M. not be used in advertising or 101722Sjkh * publicity pertaining to distribution of the software without specific, 111722Sjkh * written prior permission. U.M. makes no representations about the 121722Sjkh * suitability of this software for any purpose. It is provided "as is" 131722Sjkh * without express or implied warranty. 141722Sjkh * 151722Sjkh * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 161722Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. 171722Sjkh * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 181722Sjkh * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 191722Sjkh * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 201722Sjkh * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 211722Sjkh * 221722Sjkh * Author: James da Silva, Systems Design and Analysis Group 231722Sjkh * Computer Science Department 241722Sjkh * University of Maryland at College Park 251722Sjkh */ 261722Sjkh/* 271722Sjkh * ======================================================================== 281722Sjkh * crunchgen.c 291722Sjkh * 301722Sjkh * Generates a Makefile and main C file for a crunched executable, 318857Srgrimes * from specs given in a .conf file. 321722Sjkh */ 3329453Scharnier#include <ctype.h> 3429453Scharnier#include <err.h> 3529453Scharnier#include <stdio.h> 361722Sjkh#include <stdlib.h> 3729453Scharnier#include <string.h> 381722Sjkh#include <unistd.h> 391722Sjkh 401722Sjkh#include <sys/types.h> 411722Sjkh#include <sys/stat.h> 421722Sjkh#include <sys/param.h> 431722Sjkh 441722Sjkh#define CRUNCH_VERSION "0.2" 451722Sjkh 461722Sjkh#define MAXLINELEN 16384 471722Sjkh#define MAXFIELDS 2048 481722Sjkh 491722Sjkh 501722Sjkh/* internal representation of conf file: */ 511722Sjkh 521722Sjkh/* simple lists of strings suffice for most parms */ 531722Sjkh 541722Sjkhtypedef struct strlst { 551722Sjkh struct strlst *next; 561722Sjkh char *str; 571722Sjkh} strlst_t; 581722Sjkh 591722Sjkh/* progs have structure, each field can be set with "special" or calculated */ 601722Sjkh 611722Sjkhtypedef struct prog { 621722Sjkh struct prog *next; 631722Sjkh char *name, *ident; 641722Sjkh char *srcdir, *objdir; 651722Sjkh strlst_t *objs, *objpaths; 661722Sjkh strlst_t *links; 671722Sjkh int goterror; 681722Sjkh} prog_t; 691722Sjkh 701722Sjkh 711722Sjkh/* global state */ 721722Sjkh 731722Sjkhstrlst_t *srcdirs = NULL; 741722Sjkhstrlst_t *libs = NULL; 751722Sjkhprog_t *progs = NULL; 761722Sjkh 771722Sjkhchar line[MAXLINELEN]; 781722Sjkh 791722Sjkhchar confname[MAXPATHLEN], infilename[MAXPATHLEN]; 801722Sjkhchar outmkname[MAXPATHLEN], outcfname[MAXPATHLEN], execfname[MAXPATHLEN]; 811722Sjkhchar tempfname[MAXPATHLEN], cachename[MAXPATHLEN], curfilename[MAXPATHLEN]; 821722Sjkhint linenum = -1; 831722Sjkhint goterror = 0; 841722Sjkh 851722Sjkhint verbose, readcache; /* options */ 861722Sjkhint reading_cache; 871722Sjkh 886696Sphkint list_mode; 896696Sphk 901722Sjkh/* general library routines */ 911722Sjkh 921722Sjkhvoid status(char *str); 931722Sjkhvoid out_of_memory(void); 941722Sjkhvoid add_string(strlst_t **listp, char *str); 951722Sjkhint is_dir(char *pathname); 961722Sjkhint is_nonempty_file(char *pathname); 971722Sjkh 981722Sjkh/* helper routines for main() */ 991722Sjkh 1008857Srgrimesvoid usage(void); 1011722Sjkhvoid parse_conf_file(void); 1021722Sjkhvoid gen_outputs(void); 1031722Sjkh 1041722Sjkh 1051722Sjkhint main(int argc, char **argv) 1061722Sjkh{ 1071722Sjkh char *p; 1081722Sjkh int optc; 1091722Sjkh 1101722Sjkh verbose = 1; 1111722Sjkh readcache = 1; 1121722Sjkh *outmkname = *outcfname = *execfname = '\0'; 1138857Srgrimes 1146696Sphk while((optc = getopt(argc, argv, "lm:c:e:fq")) != -1) { 1151722Sjkh switch(optc) { 1161722Sjkh case 'f': readcache = 0; break; 1171722Sjkh case 'q': verbose = 0; break; 1181722Sjkh 1191722Sjkh case 'm': strcpy(outmkname, optarg); break; 1201722Sjkh case 'c': strcpy(outcfname, optarg); break; 1211722Sjkh case 'e': strcpy(execfname, optarg); break; 1226696Sphk case 'l': list_mode++; verbose = 0; break; 1231722Sjkh 1241722Sjkh case '?': 1251722Sjkh default: usage(); 1261722Sjkh } 1271722Sjkh } 1281722Sjkh 1291722Sjkh argc -= optind; 1301722Sjkh argv += optind; 1311722Sjkh 1321722Sjkh if(argc != 1) usage(); 1331722Sjkh 1348857Srgrimes /* 1351722Sjkh * generate filenames 1361722Sjkh */ 1371722Sjkh 1381722Sjkh strcpy(infilename, argv[0]); 1391722Sjkh 1401722Sjkh /* confname = `basename infilename .conf` */ 1411722Sjkh 1421722Sjkh if((p=strrchr(infilename, '/')) != NULL) strcpy(confname, p+1); 1431722Sjkh else strcpy(confname, infilename); 1441722Sjkh if((p=strrchr(confname, '.')) != NULL && !strcmp(p, ".conf")) *p = '\0'; 1451722Sjkh 1461722Sjkh if(!*outmkname) sprintf(outmkname, "%s.mk", confname); 1471722Sjkh if(!*outcfname) sprintf(outcfname, "%s.c", confname); 1481722Sjkh if(!*execfname) sprintf(execfname, "%s", confname); 1491722Sjkh 1501722Sjkh sprintf(cachename, "%s.cache", confname); 1511722Sjkh sprintf(tempfname, ".tmp_%sXXXXXX", confname); 1521722Sjkh if(mktemp(tempfname) == NULL) { 1531722Sjkh perror(tempfname); 1541722Sjkh exit(1); 1551722Sjkh } 1561722Sjkh 1571722Sjkh parse_conf_file(); 1586696Sphk if (list_mode) 1596696Sphk exit(goterror); 1606696Sphk 1611722Sjkh gen_outputs(); 1621722Sjkh 1631722Sjkh exit(goterror); 1641722Sjkh} 1651722Sjkh 1661722Sjkh 1671722Sjkhvoid usage(void) 1681722Sjkh{ 16929453Scharnier fprintf(stderr, "%s\n%s\n", 17029453Scharnier "usage: crunchgen [-fq] [-m <makefile>] [-c <c file>]", 17129453Scharnier " [-e <exec file>] <conffile>"); 1721722Sjkh exit(1); 1731722Sjkh} 1741722Sjkh 1751722Sjkh 1761722Sjkh/* 1771722Sjkh * ======================================================================== 1781722Sjkh * parse_conf_file subsystem 1791722Sjkh * 1801722Sjkh */ 1811722Sjkh 1821722Sjkh/* helper routines for parse_conf_file */ 1831722Sjkh 1841722Sjkhvoid parse_one_file(char *filename); 1858857Srgrimesvoid parse_line(char *line, int *fc, char **fv, int nf); 1861722Sjkhvoid add_srcdirs(int argc, char **argv); 1871722Sjkhvoid add_progs(int argc, char **argv); 1881722Sjkhvoid add_link(int argc, char **argv); 1891722Sjkhvoid add_libs(int argc, char **argv); 1901722Sjkhvoid add_special(int argc, char **argv); 1911722Sjkh 1921722Sjkhprog_t *find_prog(char *str); 1931722Sjkhvoid add_prog(char *progname); 1941722Sjkh 1951722Sjkh 1961722Sjkhvoid parse_conf_file(void) 1971722Sjkh{ 19829453Scharnier if(!is_nonempty_file(infilename)) 19929453Scharnier errx(1, "fatal: input file \"%s\" not found", infilename); 2001722Sjkh parse_one_file(infilename); 2011722Sjkh if(readcache && is_nonempty_file(cachename)) { 2021722Sjkh reading_cache = 1; 2031722Sjkh parse_one_file(cachename); 2041722Sjkh } 2051722Sjkh} 2061722Sjkh 2071722Sjkh 2081722Sjkhvoid parse_one_file(char *filename) 2091722Sjkh{ 2101722Sjkh char *fieldv[MAXFIELDS]; 2111722Sjkh int fieldc; 2121722Sjkh void (*f)(int c, char **v); 2131722Sjkh FILE *cf; 2141722Sjkh 2151722Sjkh sprintf(line, "reading %s", filename); 2161722Sjkh status(line); 2171722Sjkh strcpy(curfilename, filename); 2181722Sjkh 2191722Sjkh if((cf = fopen(curfilename, "r")) == NULL) { 22029453Scharnier warn("%s", curfilename); 2211722Sjkh goterror = 1; 2221722Sjkh return; 2231722Sjkh } 2241722Sjkh 2251722Sjkh linenum = 0; 2261722Sjkh while(fgets(line, MAXLINELEN, cf) != NULL) { 2271722Sjkh linenum++; 2281722Sjkh parse_line(line, &fieldc, fieldv, MAXFIELDS); 2291722Sjkh if(fieldc < 1) continue; 2301722Sjkh if(!strcmp(fieldv[0], "srcdirs")) f = add_srcdirs; 2311722Sjkh else if(!strcmp(fieldv[0], "progs")) f = add_progs; 2321722Sjkh else if(!strcmp(fieldv[0], "ln")) f = add_link; 2331722Sjkh else if(!strcmp(fieldv[0], "libs")) f = add_libs; 2341722Sjkh else if(!strcmp(fieldv[0], "special")) f = add_special; 2351722Sjkh else { 23629453Scharnier warnx("%s:%d: skipping unknown command `%s'", 2371722Sjkh curfilename, linenum, fieldv[0]); 2381722Sjkh goterror = 1; 2391722Sjkh continue; 2401722Sjkh } 2411722Sjkh if(fieldc < 2) { 24229453Scharnier warnx("%s:%d: %s command needs at least 1 argument, skipping", 2431722Sjkh curfilename, linenum, fieldv[0]); 2441722Sjkh goterror = 1; 2451722Sjkh continue; 2461722Sjkh } 2471722Sjkh f(fieldc, fieldv); 2481722Sjkh } 2491722Sjkh 2501722Sjkh if(ferror(cf)) { 25129453Scharnier warn("%s", curfilename); 2521722Sjkh goterror = 1; 2531722Sjkh } 2541722Sjkh fclose(cf); 2551722Sjkh} 2561722Sjkh 2571722Sjkh 2581722Sjkhvoid parse_line(char *line, int *fc, char **fv, int nf) 2591722Sjkh{ 2601722Sjkh char *p; 2611722Sjkh 2621722Sjkh p = line; 2631722Sjkh *fc = 0; 2641722Sjkh while(1) { 2651722Sjkh while(isspace(*p)) p++; 2661722Sjkh if(*p == '\0' || *p == '#') break; 2671722Sjkh 2681722Sjkh if(*fc < nf) fv[(*fc)++] = p; 2691722Sjkh while(*p && !isspace(*p) && *p != '#') p++; 2701722Sjkh if(*p == '\0' || *p == '#') break; 2711722Sjkh *p++ = '\0'; 2721722Sjkh } 2731722Sjkh if(*p) *p = '\0'; /* needed for '#' case */ 2741722Sjkh} 2751722Sjkh 2761722Sjkh 2771722Sjkhvoid add_srcdirs(int argc, char **argv) 2781722Sjkh{ 2791722Sjkh int i; 2801722Sjkh 2811722Sjkh for(i=1;i<argc;i++) { 2821722Sjkh if(is_dir(argv[i])) 2831722Sjkh add_string(&srcdirs, argv[i]); 2841722Sjkh else { 28529453Scharnier warnx("%s:%d: `%s' is not a directory, skipping it", 2861722Sjkh curfilename, linenum, argv[i]); 2871722Sjkh goterror = 1; 2881722Sjkh } 2891722Sjkh } 2901722Sjkh} 2911722Sjkh 2921722Sjkh 2931722Sjkhvoid add_progs(int argc, char **argv) 2941722Sjkh{ 2951722Sjkh int i; 2961722Sjkh 2971722Sjkh for(i=1;i<argc;i++) 2981722Sjkh add_prog(argv[i]); 2991722Sjkh} 3001722Sjkh 3011722Sjkh 3021722Sjkhvoid add_prog(char *progname) 3031722Sjkh{ 3041722Sjkh prog_t *p1, *p2; 3051722Sjkh 3061722Sjkh /* add to end, but be smart about dups */ 3071722Sjkh 3081722Sjkh for(p1 = NULL, p2 = progs; p2 != NULL; p1 = p2, p2 = p2->next) 3091722Sjkh if(!strcmp(p2->name, progname)) return; 3101722Sjkh 3111722Sjkh p2 = malloc(sizeof(prog_t)); 31219822Sjoerg if(p2) { 31319822Sjoerg memset(p2, 0, sizeof(prog_t)); 31419822Sjoerg p2->name = strdup(progname); 31519822Sjoerg } 3168857Srgrimes if(!p2 || !p2->name) 3171722Sjkh out_of_memory(); 3181722Sjkh 3191722Sjkh p2->next = NULL; 3201722Sjkh if(p1 == NULL) progs = p2; 3211722Sjkh else p1->next = p2; 3221722Sjkh 3231722Sjkh p2->ident = p2->srcdir = p2->objdir = NULL; 3241722Sjkh p2->links = p2->objs = NULL; 3251722Sjkh p2->goterror = 0; 3266696Sphk if (list_mode) 3276696Sphk printf("%s\n",progname); 3281722Sjkh} 3291722Sjkh 3301722Sjkh 3311722Sjkhvoid add_link(int argc, char **argv) 3321722Sjkh{ 3331722Sjkh int i; 3341722Sjkh prog_t *p = find_prog(argv[1]); 3351722Sjkh 3361722Sjkh if(p == NULL) { 33729453Scharnier warnx("%s:%d: no prog %s previously declared, skipping link", 3381722Sjkh curfilename, linenum, argv[1]); 3391722Sjkh goterror = 1; 3401722Sjkh return; 3411722Sjkh } 3426696Sphk for(i=2;i<argc;i++) { 3436696Sphk if (list_mode) 3446696Sphk printf("%s\n",argv[i]); 3451722Sjkh add_string(&p->links, argv[i]); 3466696Sphk } 3471722Sjkh} 3481722Sjkh 3491722Sjkh 3501722Sjkhvoid add_libs(int argc, char **argv) 3511722Sjkh{ 3521722Sjkh int i; 3531722Sjkh 3541722Sjkh for(i=1;i<argc;i++) 3551722Sjkh add_string(&libs, argv[i]); 3561722Sjkh} 3571722Sjkh 3581722Sjkh 3591722Sjkhvoid add_special(int argc, char **argv) 3601722Sjkh{ 3611722Sjkh int i; 3621722Sjkh prog_t *p = find_prog(argv[1]); 3631722Sjkh 3641722Sjkh if(p == NULL) { 3651722Sjkh if(reading_cache) return; 36629453Scharnier warnx("%s:%d: no prog %s previously declared, skipping special", 3671722Sjkh curfilename, linenum, argv[1]); 3681722Sjkh goterror = 1; 3691722Sjkh return; 3701722Sjkh } 3711722Sjkh 3721722Sjkh if(!strcmp(argv[2], "ident")) { 3731722Sjkh if(argc != 4) goto argcount; 3741722Sjkh if((p->ident = strdup(argv[3])) == NULL) 3751722Sjkh out_of_memory(); 3761722Sjkh } 3771722Sjkh else if(!strcmp(argv[2], "srcdir")) { 3781722Sjkh if(argc != 4) goto argcount; 3791722Sjkh if((p->srcdir = strdup(argv[3])) == NULL) 3801722Sjkh out_of_memory(); 3811722Sjkh } 3821722Sjkh else if(!strcmp(argv[2], "objdir")) { 3831722Sjkh if(argc != 4) goto argcount; 3841722Sjkh if((p->objdir = strdup(argv[3])) == NULL) 3851722Sjkh out_of_memory(); 3861722Sjkh } 3871722Sjkh else if(!strcmp(argv[2], "objs")) { 3881722Sjkh p->objs = NULL; 3891722Sjkh for(i=3;i<argc;i++) 3901722Sjkh add_string(&p->objs, argv[i]); 3911722Sjkh } 3921722Sjkh else if(!strcmp(argv[2], "objpaths")) { 3931722Sjkh p->objpaths = NULL; 3941722Sjkh for(i=3;i<argc;i++) 3951722Sjkh add_string(&p->objpaths, argv[i]); 3961722Sjkh } 3971722Sjkh else { 39829453Scharnier warnx("%s:%d: bad parameter name `%s', skipping line", 3991722Sjkh curfilename, linenum, argv[2]); 4001722Sjkh goterror = 1; 4011722Sjkh } 4021722Sjkh return; 4031722Sjkh 4041722Sjkh 4051722Sjkh argcount: 40629453Scharnier warnx("%s:%d: too %s arguments, expected \"special %s %s <string>\"", 4071722Sjkh curfilename, linenum, argc < 4? "few" : "many", argv[1], argv[2]); 4081722Sjkh goterror = 1; 4091722Sjkh} 4101722Sjkh 4111722Sjkh 4121722Sjkhprog_t *find_prog(char *str) 4131722Sjkh{ 4141722Sjkh prog_t *p; 4151722Sjkh 4161722Sjkh for(p = progs; p != NULL; p = p->next) 4171722Sjkh if(!strcmp(p->name, str)) return p; 4181722Sjkh 4191722Sjkh return NULL; 4201722Sjkh} 4211722Sjkh 4221722Sjkh 4231722Sjkh/* 4241722Sjkh * ======================================================================== 4251722Sjkh * gen_outputs subsystem 4261722Sjkh * 4271722Sjkh */ 4281722Sjkh 4291722Sjkh/* helper subroutines */ 4301722Sjkh 4311722Sjkhvoid remove_error_progs(void); 4321722Sjkhvoid fillin_program(prog_t *p); 4331722Sjkhvoid gen_specials_cache(void); 4341722Sjkhvoid gen_output_makefile(void); 4351722Sjkhvoid gen_output_cfile(void); 4361722Sjkh 4371722Sjkhvoid fillin_program_objs(prog_t *p, char *path); 4381722Sjkhvoid top_makefile_rules(FILE *outmk); 4391722Sjkhvoid prog_makefile_rules(FILE *outmk, prog_t *p); 4401722Sjkhvoid output_strlst(FILE *outf, strlst_t *lst); 4411722Sjkhchar *genident(char *str); 4421722Sjkhchar *dir_search(char *progname); 4431722Sjkh 4441722Sjkh 4451722Sjkhvoid gen_outputs(void) 4461722Sjkh{ 4471722Sjkh prog_t *p; 4481722Sjkh 4491722Sjkh for(p = progs; p != NULL; p = p->next) 4501722Sjkh fillin_program(p); 4511722Sjkh 4521722Sjkh remove_error_progs(); 4531722Sjkh gen_specials_cache(); 4541722Sjkh gen_output_cfile(); 4551722Sjkh gen_output_makefile(); 4561722Sjkh status(""); 4578857Srgrimes fprintf(stderr, 4581722Sjkh "Run \"make -f %s objs exe\" to build crunched binary.\n", 4591722Sjkh outmkname); 4601722Sjkh} 4611722Sjkh 4621722Sjkh 4631722Sjkhvoid fillin_program(prog_t *p) 4641722Sjkh{ 4651722Sjkh char path[MAXPATHLEN]; 4661722Sjkh char *srcparent; 4671722Sjkh strlst_t *s; 4681722Sjkh 4691722Sjkh sprintf(line, "filling in parms for %s", p->name); 4701722Sjkh status(line); 4711722Sjkh 4728857Srgrimes if(!p->ident) 4731722Sjkh p->ident = genident(p->name); 4741722Sjkh if(!p->srcdir) { 4751722Sjkh srcparent = dir_search(p->name); 4761722Sjkh if(srcparent) 4771722Sjkh sprintf(path, "%s/%s", srcparent, p->name); 4781722Sjkh if(is_dir(path)) 4791722Sjkh p->srcdir = strdup(path); 4801722Sjkh } 4811722Sjkh if(!p->objdir && p->srcdir) { 48217430Sphk FILE *f; 48317430Sphk 48417430Sphk sprintf(path, "cd %s && echo -n /usr/obj/`pwd`", p->srcdir); 48517430Sphk p->objdir = p->srcdir; 48617430Sphk f = popen(path,"r"); 48717430Sphk if (f) { 48817430Sphk fgets(path,sizeof path, f); 48917430Sphk if (!pclose(f)) { 49017430Sphk if(is_dir(path)) 49117430Sphk p->objdir = strdup(path); 49217430Sphk } 49317430Sphk } 49417430Sphk 49517430Sphk 4961722Sjkh } 4971722Sjkh 4981722Sjkh if(p->srcdir) sprintf(path, "%s/Makefile", p->srcdir); 4991722Sjkh if(!p->objs && p->srcdir && is_nonempty_file(path)) 5001722Sjkh fillin_program_objs(p, path); 5011722Sjkh 5021722Sjkh if(!p->objpaths && p->objdir && p->objs) 5031722Sjkh for(s = p->objs; s != NULL; s = s->next) { 5041722Sjkh sprintf(line, "%s/%s", p->objdir, s->str); 5051722Sjkh add_string(&p->objpaths, line); 5061722Sjkh } 5071722Sjkh 5081722Sjkh if(!p->srcdir && verbose) 50929453Scharnier warnx("%s: %s: warning: could not find source directory", 5101722Sjkh infilename, p->name); 5111722Sjkh if(!p->objs && verbose) 51229453Scharnier warnx("%s: %s: warning: could not find any .o files", 5131722Sjkh infilename, p->name); 5141722Sjkh 5151722Sjkh if(!p->objpaths) { 51629453Scharnier warnx("%s: %s: error: no objpaths specified or calculated", 5171722Sjkh infilename, p->name); 5181722Sjkh p->goterror = goterror = 1; 5191722Sjkh } 5201722Sjkh} 5211722Sjkh 5221722Sjkhvoid fillin_program_objs(prog_t *p, char *path) 5231722Sjkh{ 5241722Sjkh char *obj, *cp; 5251722Sjkh int rc; 5261722Sjkh FILE *f; 5271722Sjkh 5281722Sjkh /* discover the objs from the srcdir Makefile */ 5291722Sjkh 5301722Sjkh if((f = fopen(tempfname, "w")) == NULL) { 53129453Scharnier warn("%s", tempfname); 5321722Sjkh goterror = 1; 5331722Sjkh return; 5341722Sjkh } 5358857Srgrimes 5361722Sjkh fprintf(f, ".include \"%s\"\n", path); 5371722Sjkh fprintf(f, ".if defined(PROG) && !defined(OBJS)\n"); 5381722Sjkh fprintf(f, "OBJS=${PROG}.o\n"); 5391722Sjkh fprintf(f, ".endif\n"); 5401722Sjkh fprintf(f, "crunchgen_objs:\n\t@echo 'OBJS= '${OBJS}\n"); 5411722Sjkh fclose(f); 5421722Sjkh 5431722Sjkh sprintf(line, "make -f %s crunchgen_objs 2>&1", tempfname); 5441722Sjkh if((f = popen(line, "r")) == NULL) { 54529453Scharnier warn("submake pipe"); 5461722Sjkh goterror = 1; 5471722Sjkh return; 5481722Sjkh } 5491722Sjkh 5501722Sjkh while(fgets(line, MAXLINELEN, f)) { 5511722Sjkh if(strncmp(line, "OBJS= ", 6)) { 55229453Scharnier warnx("make error: %s", line); 5538857Srgrimes goterror = 1; 5541722Sjkh continue; 5551722Sjkh } 5561722Sjkh cp = line + 6; 5571722Sjkh while(isspace(*cp)) cp++; 5581722Sjkh while(*cp) { 5591722Sjkh obj = cp; 5601722Sjkh while(*cp && !isspace(*cp)) cp++; 5611722Sjkh if(*cp) *cp++ = '\0'; 5621722Sjkh add_string(&p->objs, obj); 5631722Sjkh while(isspace(*cp)) cp++; 5641722Sjkh } 5651722Sjkh } 5661722Sjkh if((rc=pclose(f)) != 0) { 56729453Scharnier warnx("make error: make returned %d", rc); 5681722Sjkh goterror = 1; 5691722Sjkh } 5701722Sjkh unlink(tempfname); 5711722Sjkh} 5721722Sjkh 5731722Sjkhvoid remove_error_progs(void) 5741722Sjkh{ 5751722Sjkh prog_t *p1, *p2; 5761722Sjkh 5778857Srgrimes p1 = NULL; p2 = progs; 5788857Srgrimes while(p2 != NULL) { 5791722Sjkh if(!p2->goterror) 5801722Sjkh p1 = p2, p2 = p2->next; 5811722Sjkh else { 5821722Sjkh /* delete it from linked list */ 58329453Scharnier warnx("%s: %s: ignoring program because of errors", 5841722Sjkh infilename, p2->name); 5851722Sjkh if(p1) p1->next = p2->next; 5861722Sjkh else progs = p2->next; 5871722Sjkh p2 = p2->next; 5881722Sjkh } 5891722Sjkh } 5901722Sjkh} 5911722Sjkh 5921722Sjkhvoid gen_specials_cache(void) 5931722Sjkh{ 5941722Sjkh FILE *cachef; 5951722Sjkh prog_t *p; 5961722Sjkh 5971722Sjkh sprintf(line, "generating %s", cachename); 5981722Sjkh status(line); 5991722Sjkh 6001722Sjkh if((cachef = fopen(cachename, "w")) == NULL) { 60129453Scharnier warn("%s", cachename); 6021722Sjkh goterror = 1; 6031722Sjkh return; 6041722Sjkh } 6051722Sjkh 6061722Sjkh fprintf(cachef, "# %s - parm cache generated from %s by crunchgen %s\n\n", 6071722Sjkh cachename, infilename, CRUNCH_VERSION); 6081722Sjkh 6091722Sjkh for(p = progs; p != NULL; p = p->next) { 6101722Sjkh fprintf(cachef, "\n"); 6111722Sjkh if(p->srcdir) 6121722Sjkh fprintf(cachef, "special %s srcdir %s\n", p->name, p->srcdir); 6131722Sjkh if(p->objdir) 6141722Sjkh fprintf(cachef, "special %s objdir %s\n", p->name, p->objdir); 6151722Sjkh if(p->objs) { 6161722Sjkh fprintf(cachef, "special %s objs", p->name); 6171722Sjkh output_strlst(cachef, p->objs); 6181722Sjkh } 6191722Sjkh fprintf(cachef, "special %s objpaths", p->name); 6201722Sjkh output_strlst(cachef, p->objpaths); 6211722Sjkh } 6221722Sjkh fclose(cachef); 6231722Sjkh} 6241722Sjkh 6251722Sjkh 6261722Sjkhvoid gen_output_makefile(void) 6271722Sjkh{ 6281722Sjkh prog_t *p; 6291722Sjkh FILE *outmk; 6301722Sjkh 6311722Sjkh sprintf(line, "generating %s", outmkname); 6321722Sjkh status(line); 6331722Sjkh 6341722Sjkh if((outmk = fopen(outmkname, "w")) == NULL) { 63529453Scharnier warn("%s", outmkname); 6361722Sjkh goterror = 1; 6371722Sjkh return; 6381722Sjkh } 6391722Sjkh 6401722Sjkh fprintf(outmk, "# %s - generated from %s by crunchgen %s\n\n", 6411722Sjkh outmkname, infilename, CRUNCH_VERSION); 6421722Sjkh 6431722Sjkh top_makefile_rules(outmk); 6441722Sjkh 6451722Sjkh for(p = progs; p != NULL; p = p->next) 6468857Srgrimes prog_makefile_rules(outmk, p); 6471722Sjkh 6481722Sjkh fprintf(outmk, "\n# ========\n"); 6491722Sjkh fclose(outmk); 6501722Sjkh} 6511722Sjkh 6521722Sjkh 6531722Sjkhvoid gen_output_cfile(void) 6541722Sjkh{ 6551722Sjkh extern char *crunched_skel[]; 6561722Sjkh char **cp; 6571722Sjkh FILE *outcf; 6581722Sjkh prog_t *p; 6591722Sjkh strlst_t *s; 6601722Sjkh 6611722Sjkh sprintf(line, "generating %s", outcfname); 6621722Sjkh status(line); 6631722Sjkh 6641722Sjkh if((outcf = fopen(outcfname, "w")) == NULL) { 66529453Scharnier warn("%s", outcfname); 6661722Sjkh goterror = 1; 6671722Sjkh return; 6681722Sjkh } 6691722Sjkh 6708857Srgrimes fprintf(outcf, 6711722Sjkh "/* %s - generated from %s by crunchgen %s */\n", 6721722Sjkh outcfname, infilename, CRUNCH_VERSION); 6731722Sjkh 6741722Sjkh fprintf(outcf, "#define EXECNAME \"%s\"\n", execfname); 6751722Sjkh for(cp = crunched_skel; *cp != NULL; cp++) 6761722Sjkh fprintf(outcf, "%s\n", *cp); 6771722Sjkh 6781722Sjkh for(p = progs; p != NULL; p = p->next) 6791722Sjkh fprintf(outcf, "extern int _crunched_%s_stub();\n", p->ident); 6801722Sjkh 6811722Sjkh fprintf(outcf, "\nstruct stub entry_points[] = {\n"); 6821722Sjkh for(p = progs; p != NULL; p = p->next) { 6831722Sjkh fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n", 6841722Sjkh p->name, p->ident); 6851722Sjkh for(s = p->links; s != NULL; s = s->next) 6861722Sjkh fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n", 6871722Sjkh s->str, p->ident); 6881722Sjkh } 6898857Srgrimes 6901722Sjkh fprintf(outcf, "\t{ EXECNAME, crunched_main },\n"); 6911722Sjkh fprintf(outcf, "\t{ NULL, NULL }\n};\n"); 6921722Sjkh fclose(outcf); 6931722Sjkh} 6941722Sjkh 6951722Sjkh 6961722Sjkhchar *genident(char *str) 6971722Sjkh{ 6981722Sjkh char *n,*s,*d; 6991722Sjkh 7001722Sjkh /* 7011722Sjkh * generates a Makefile/C identifier from a program name, mapping '-' to 7021722Sjkh * '_' and ignoring all other non-identifier characters. This leads to 7031722Sjkh * programs named "foo.bar" and "foobar" to map to the same identifier. 7041722Sjkh */ 7051722Sjkh 7061722Sjkh if((n = strdup(str)) == NULL) 7071722Sjkh return NULL; 7081722Sjkh for(d = s = n; *s != '\0'; s++) { 7091722Sjkh if(*s == '-') *d++ = '_'; 7101722Sjkh else if(*s == '_' || isalnum(*s)) *d++ = *s; 7111722Sjkh } 7121722Sjkh *d = '\0'; 7131722Sjkh return n; 7141722Sjkh} 7151722Sjkh 7161722Sjkh 7171722Sjkhchar *dir_search(char *progname) 7181722Sjkh{ 7191722Sjkh char path[MAXPATHLEN]; 7201722Sjkh strlst_t *dir; 7211722Sjkh 7221722Sjkh for(dir=srcdirs; dir != NULL; dir=dir->next) { 7231722Sjkh sprintf(path, "%s/%s", dir->str, progname); 7241722Sjkh if(is_dir(path)) return dir->str; 7251722Sjkh } 7261722Sjkh return NULL; 7271722Sjkh} 7281722Sjkh 7291722Sjkh 7301722Sjkhvoid top_makefile_rules(FILE *outmk) 7311722Sjkh{ 7321722Sjkh prog_t *p; 7331722Sjkh 7341722Sjkh fprintf(outmk, "LIBS="); 7351722Sjkh output_strlst(outmk, libs); 7361722Sjkh 7371722Sjkh fprintf(outmk, "CRUNCHED_OBJS="); 7381722Sjkh for(p = progs; p != NULL; p = p->next) 7391722Sjkh fprintf(outmk, " %s.lo", p->name); 7401722Sjkh fprintf(outmk, "\n"); 7411722Sjkh 7421722Sjkh fprintf(outmk, "SUBMAKE_TARGETS="); 7431722Sjkh for(p = progs; p != NULL; p = p->next) 7441722Sjkh fprintf(outmk, " %s_make", p->ident); 7451722Sjkh fprintf(outmk, "\n\n"); 7461722Sjkh 7478857Srgrimes fprintf(outmk, "%s: %s.o $(CRUNCHED_OBJS)\n", 7481722Sjkh execfname, execfname); 7491722Sjkh fprintf(outmk, "\t$(CC) -static -o %s %s.o $(CRUNCHED_OBJS) $(LIBS)\n", 7501722Sjkh execfname, execfname); 7511722Sjkh fprintf(outmk, "\tstrip %s\n", execfname); 7521722Sjkh fprintf(outmk, "all: objs exe\nobjs: $(SUBMAKE_TARGETS)\n"); 7531722Sjkh fprintf(outmk, "exe: %s\n", execfname); 7541722Sjkh fprintf(outmk, "clean:\n\trm -f %s *.lo *.o *_stub.c\n", 7551722Sjkh execfname); 7561722Sjkh} 7571722Sjkh 7581722Sjkh 7591722Sjkhvoid prog_makefile_rules(FILE *outmk, prog_t *p) 7601722Sjkh{ 7611722Sjkh fprintf(outmk, "\n# -------- %s\n\n", p->name); 7621722Sjkh 7631722Sjkh if(p->srcdir && p->objs) { 7641722Sjkh fprintf(outmk, "%s_SRCDIR=%s\n", p->ident, p->srcdir); 7651722Sjkh fprintf(outmk, "%s_OBJS=", p->ident); 7661722Sjkh output_strlst(outmk, p->objs); 7671722Sjkh fprintf(outmk, "%s_make:\n", p->ident); 76817430Sphk fprintf(outmk, "\t(cd $(%s_SRCDIR) && make depend && make $(%s_OBJS))\n\n", 7691722Sjkh p->ident, p->ident); 7701722Sjkh } 7711722Sjkh else 7728857Srgrimes fprintf(outmk, "%s_make:\n\t@echo \"** cannot make objs for %s\"\n\n", 7731722Sjkh p->ident, p->name); 7741722Sjkh 7751722Sjkh fprintf(outmk, "%s_OBJPATHS=", p->ident); 7761722Sjkh output_strlst(outmk, p->objpaths); 7771722Sjkh 7781722Sjkh fprintf(outmk, "%s_stub.c:\n", p->name); 7791722Sjkh fprintf(outmk, "\techo \"" 7801722Sjkh "int _crunched_%s_stub(int argc, char **argv, char **envp)" 7811722Sjkh "{return main(argc,argv,envp);}\" >%s_stub.c\n", 7821722Sjkh p->ident, p->name); 7831722Sjkh fprintf(outmk, "%s.lo: %s_stub.o $(%s_OBJPATHS)\n", 7841722Sjkh p->name, p->name, p->ident); 7858857Srgrimes fprintf(outmk, "\tld -dc -r -o %s.lo %s_stub.o $(%s_OBJPATHS)\n", 7861722Sjkh p->name, p->name, p->ident); 7878857Srgrimes fprintf(outmk, "\tcrunchide -k __crunched_%s_stub %s.lo\n", 7881722Sjkh p->ident, p->name); 7891722Sjkh} 7901722Sjkh 7911722Sjkhvoid output_strlst(FILE *outf, strlst_t *lst) 7921722Sjkh{ 7931722Sjkh for(; lst != NULL; lst = lst->next) 7941722Sjkh fprintf(outf, " %s", lst->str); 7951722Sjkh fprintf(outf, "\n"); 7961722Sjkh} 7971722Sjkh 7981722Sjkh 7991722Sjkh/* 8001722Sjkh * ======================================================================== 8011722Sjkh * general library routines 8021722Sjkh * 8031722Sjkh */ 8041722Sjkh 8051722Sjkhvoid status(char *str) 8061722Sjkh{ 8071722Sjkh static int lastlen = 0; 8081722Sjkh int len, spaces; 8091722Sjkh 8101722Sjkh if(!verbose) return; 8111722Sjkh 8121722Sjkh len = strlen(str); 8131722Sjkh spaces = lastlen - len; 8141722Sjkh if(spaces < 1) spaces = 1; 8151722Sjkh 8161722Sjkh fprintf(stderr, " [%s]%*.*s\r", str, spaces, spaces, " "); 8171722Sjkh fflush(stderr); 8181722Sjkh lastlen = len; 8191722Sjkh} 8201722Sjkh 8211722Sjkh 8221722Sjkhvoid out_of_memory(void) 8231722Sjkh{ 82429453Scharnier errx(1, "%s: %d: out of memory, stopping", infilename, linenum); 8251722Sjkh} 8261722Sjkh 8271722Sjkh 8281722Sjkhvoid add_string(strlst_t **listp, char *str) 8291722Sjkh{ 8301722Sjkh strlst_t *p1, *p2; 8311722Sjkh 8321722Sjkh /* add to end, but be smart about dups */ 8331722Sjkh 8341722Sjkh for(p1 = NULL, p2 = *listp; p2 != NULL; p1 = p2, p2 = p2->next) 8351722Sjkh if(!strcmp(p2->str, str)) return; 8361722Sjkh 8371722Sjkh p2 = malloc(sizeof(strlst_t)); 83819822Sjoerg if(p2) { 83919822Sjoerg memset(p2, 0, sizeof(strlst_t)); 84019822Sjoerg p2->str = strdup(str); 84119822Sjoerg } 8421722Sjkh if(!p2 || !p2->str) 8431722Sjkh out_of_memory(); 8441722Sjkh 8451722Sjkh p2->next = NULL; 8461722Sjkh if(p1 == NULL) *listp = p2; 8471722Sjkh else p1->next = p2; 8481722Sjkh} 8491722Sjkh 8501722Sjkh 8511722Sjkhint is_dir(char *pathname) 8521722Sjkh{ 8531722Sjkh struct stat buf; 8541722Sjkh 8551722Sjkh if(stat(pathname, &buf) == -1) 8561722Sjkh return 0; 8571722Sjkh return S_ISDIR(buf.st_mode); 8581722Sjkh} 8591722Sjkh 8601722Sjkhint is_nonempty_file(char *pathname) 8611722Sjkh{ 8621722Sjkh struct stat buf; 8631722Sjkh 8641722Sjkh if(stat(pathname, &buf) == -1) 8651722Sjkh return 0; 8661722Sjkh 8671722Sjkh return S_ISREG(buf.st_mode) && buf.st_size > 0; 8681722Sjkh} 869