crunchgen.c revision 70880
154359Sroberto/* 254359Sroberto * Copyright (c) 1994 University of Maryland 354359Sroberto * All Rights Reserved. 4285612Sdelphij * 5182007Sroberto * Permission to use, copy, modify, distribute, and sell this software and its 6182007Sroberto * documentation for any purpose is hereby granted without fee, provided that 7182007Sroberto * the above copyright notice appear in all copies and that both that 8330567Sgordon * copyright notice and this permission notice appear in supporting 9330567Sgordon * documentation, and that the name of U.M. not be used in advertising or 10182007Sroberto * publicity pertaining to distribution of the software without specific, 11182007Sroberto * written prior permission. U.M. makes no representations about the 12285612Sdelphij * suitability of this software for any purpose. It is provided "as is" 13285612Sdelphij * without express or implied warranty. 14285612Sdelphij * 15285612Sdelphij * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 16285612Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. 17285612Sdelphij * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18285612Sdelphij * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 19285612Sdelphij * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 20285612Sdelphij * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21285612Sdelphij * 22285612Sdelphij * Author: James da Silva, Systems Design and Analysis Group 23182007Sroberto * Computer Science Department 2482498Sroberto * University of Maryland at College Park 25285612Sdelphij * 26285612Sdelphij * $FreeBSD: head/usr.sbin/crunch/crunchgen/crunchgen.c 70880 2001-01-10 13:27:38Z joe $ 2782498Sroberto */ 2882498Sroberto/* 2982498Sroberto * ======================================================================== 30285612Sdelphij * crunchgen.c 31285612Sdelphij * 32285612Sdelphij * Generates a Makefile and main C file for a crunched executable, 33285612Sdelphij * from specs given in a .conf file. 34285612Sdelphij */ 35285612Sdelphij#include <ctype.h> 36285612Sdelphij#include <err.h> 37285612Sdelphij#include <paths.h> 38330567Sgordon#include <stdio.h> 39330567Sgordon#include <stdlib.h> 40330567Sgordon#include <string.h> 41330567Sgordon#include <unistd.h> 42330567Sgordon 43330567Sgordon#include <sys/types.h> 44310419Sdelphij#include <sys/stat.h> 45330567Sgordon#include <sys/param.h> 46330567Sgordon 47285612Sdelphij#define CRUNCH_VERSION "0.2" 48285612Sdelphij 4982498Sroberto#define MAXLINELEN 16384 50285612Sdelphij#define MAXFIELDS 2048 51293650Sglebius 52182007Sroberto 53285612Sdelphij/* internal representation of conf file: */ 54182007Sroberto 55182007Sroberto/* simple lists of strings suffice for most parms */ 5654359Sroberto 5754359Srobertotypedef struct strlst { 58182007Sroberto struct strlst *next; 59182007Sroberto char *str; 60182007Sroberto} strlst_t; 61182007Sroberto 62182007Sroberto/* progs have structure, each field can be set with "special" or calculated */ 6354359Sroberto 6454359Srobertotypedef struct prog { 6554359Sroberto struct prog *next; /* link field */ 6654359Sroberto char *name; /* program name */ 6754359Sroberto char *ident; /* C identifier for the program name */ 6854359Sroberto char *srcdir; 6954359Sroberto char *realsrcdir; 70285612Sdelphij char *objdir; 71285612Sdelphij char *objvar; /* Makefile variable to replace OBJS */ 72285612Sdelphij strlst_t *objs, *objpaths; 73285612Sdelphij strlst_t *buildopts; 74285612Sdelphij strlst_t *keeplist; 75285612Sdelphij strlst_t *links; 76285612Sdelphij int goterror; 77285612Sdelphij} prog_t; 7854359Sroberto 79298770Sdelphij 80298770Sdelphij/* global state */ 81298770Sdelphij 82298770Sdelphijstrlst_t *buildopts = NULL; 83298770Sdelphijstrlst_t *srcdirs = NULL; 84285612Sdelphijstrlst_t *libs = NULL; 8554359Srobertoprog_t *progs = NULL; 86182007Sroberto 87182007Srobertochar confname[MAXPATHLEN], infilename[MAXPATHLEN]; 88182007Srobertochar outmkname[MAXPATHLEN], outcfname[MAXPATHLEN], execfname[MAXPATHLEN]; 89182007Srobertochar tempfname[MAXPATHLEN], cachename[MAXPATHLEN], curfilename[MAXPATHLEN]; 90182007Srobertochar outhdrname[MAXPATHLEN] ; /* user-supplied header for *.mk */ 9154359Srobertochar *objprefix; /* where are the objects ? */ 9254359Srobertoint linenum = -1; 93132451Srobertoint goterror = 0; 9454359Sroberto 95285612Sdelphijint verbose, readcache; /* options */ 96285612Sdelphijint reading_cache; 9754359Srobertoint makeobj = 0; /* add 'make obj' rules to the makefile */ 9854359Sroberto 9954359Srobertoint list_mode; 10054359Sroberto 10154359Sroberto/* general library routines */ 10254359Sroberto 10354359Srobertovoid status(char *str); 10454359Srobertovoid out_of_memory(void); 10554359Srobertovoid add_string(strlst_t **listp, char *str); 10654359Srobertoint is_dir(char *pathname); 10754359Srobertoint is_nonempty_file(char *pathname); 10854359Sroberto 10954359Sroberto/* helper routines for main() */ 11054359Sroberto 11154359Srobertovoid usage(void); 11254359Srobertovoid parse_conf_file(void); 11354359Srobertovoid gen_outputs(void); 11454359Sroberto 11554359Sroberto 11654359Srobertoint main(int argc, char **argv) 11754359Sroberto{ 11854359Sroberto char *p; 11954359Sroberto int optc; 12054359Sroberto 12154359Sroberto verbose = 1; 12254359Sroberto readcache = 1; 123285612Sdelphij *outmkname = *outcfname = *execfname = '\0'; 124285612Sdelphij 125285612Sdelphij p = getenv("MAKEOBJDIRPREFIX"); 126285612Sdelphij if (p == NULL || *p == '\0') 127285612Sdelphij objprefix = "/usr/obj"; /* default */ 128285612Sdelphij else 129285612Sdelphij if ((objprefix = strdup(p)) == NULL) 130285612Sdelphij out_of_memory(); 13154359Sroberto 13254359Sroberto while((optc = getopt(argc, argv, "lh:m:c:e:p:foq")) != -1) { 13354359Sroberto switch(optc) { 134285612Sdelphij case 'f': readcache = 0; break; 135285612Sdelphij case 'o': makeobj = 1; break; 136285612Sdelphij case 'q': verbose = 0; break; 13754359Sroberto 138285612Sdelphij case 'm': strlcpy(outmkname, optarg, sizeof(outmkname)); break; 139285612Sdelphij case 'p': if ((objprefix = strdup(optarg)) == NULL) 140285612Sdelphij out_of_memory(); 141285612Sdelphij break; 142285612Sdelphij case 'h': strlcpy(outhdrname, optarg, sizeof(outhdrname)); break; 143285612Sdelphij case 'c': strlcpy(outcfname, optarg, sizeof(outcfname)); break; 144285612Sdelphij case 'e': strlcpy(execfname, optarg, sizeof(execfname)); break; 145285612Sdelphij case 'l': list_mode++; verbose = 0; break; 146285612Sdelphij 147285612Sdelphij case '?': 148285612Sdelphij default: usage(); 149285612Sdelphij } 150285612Sdelphij } 151285612Sdelphij 152285612Sdelphij argc -= optind; 153285612Sdelphij argv += optind; 154285612Sdelphij 15554359Sroberto if(argc != 1) usage(); 15654359Sroberto 15754359Sroberto /* 15854359Sroberto * generate filenames 15954359Sroberto */ 16054359Sroberto 16154359Sroberto strlcpy(infilename, argv[0], sizeof(infilename)); 16254359Sroberto 163182007Sroberto /* confname = `basename infilename .conf` */ 164182007Sroberto 165285612Sdelphij if((p=strrchr(infilename, '/')) != NULL) 166182007Sroberto strlcpy(confname, p+1, sizeof(confname)); 167182007Sroberto else 168285612Sdelphij strlcpy(confname, infilename, sizeof(confname)); 169285612Sdelphij if((p=strrchr(confname, '.')) != NULL && !strcmp(p, ".conf")) *p = '\0'; 170182007Sroberto 171182007Sroberto if(!*outmkname) snprintf(outmkname, sizeof(outmkname), "%s.mk", confname); 172182007Sroberto if(!*outcfname) snprintf(outcfname, sizeof(outcfname), "%s.c", confname); 173182007Sroberto if(!*execfname) snprintf(execfname, sizeof(execfname), "%s", confname); 174182007Sroberto 175285612Sdelphij snprintf(cachename, sizeof(cachename), "%s.cache", confname); 17654359Sroberto snprintf(tempfname, sizeof(tempfname), "%s/crunchgen_%sXXXXXX", 17754359Sroberto getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP, confname); 17854359Sroberto 179285612Sdelphij parse_conf_file(); 18054359Sroberto if (list_mode) 18154359Sroberto exit(goterror); 18254359Sroberto 183285612Sdelphij gen_outputs(); 184285612Sdelphij 185285612Sdelphij exit(goterror); 186293650Sglebius} 187293650Sglebius 188285612Sdelphij 189285612Sdelphijvoid usage(void) 190285612Sdelphij{ 191285612Sdelphij fprintf(stderr, "%s\n%s\n", 192293650Sglebius "usage: crunchgen [-foq] [-h <makefile-header-name>] [-m <makefile>]", 193285612Sdelphij " [-p <obj-prefix>] [-c <c-file-name>] [-e <exec-file>] <conffile>"); 194285612Sdelphij exit(1); 195285612Sdelphij} 196285612Sdelphij 197285612Sdelphij 198285612Sdelphij/* 199285612Sdelphij * ======================================================================== 200285612Sdelphij * parse_conf_file subsystem 201330567Sgordon * 202285612Sdelphij */ 203285612Sdelphij 204285612Sdelphij/* helper routines for parse_conf_file */ 205285612Sdelphij 206285612Sdelphijvoid parse_one_file(char *filename); 207285612Sdelphijvoid parse_line(char *line, int *fc, char **fv, int nf); 208285612Sdelphijvoid add_srcdirs(int argc, char **argv); 209285612Sdelphijvoid add_progs(int argc, char **argv); 210285612Sdelphijvoid add_link(int argc, char **argv); 211285612Sdelphijvoid add_libs(int argc, char **argv); 212285612Sdelphijvoid add_buildopts(int argc, char **argv); 213285612Sdelphijvoid add_special(int argc, char **argv); 214285612Sdelphij 215298770Sdelphijprog_t *find_prog(char *str); 216285612Sdelphijvoid add_prog(char *progname); 217285612Sdelphij 218285612Sdelphij 219285612Sdelphijvoid parse_conf_file(void) 220285612Sdelphij{ 221285612Sdelphij if(!is_nonempty_file(infilename)) 222285612Sdelphij errx(1, "fatal: input file \"%s\" not found", infilename); 223285612Sdelphij parse_one_file(infilename); 224285612Sdelphij if(readcache && is_nonempty_file(cachename)) { 225285612Sdelphij reading_cache = 1; 226285612Sdelphij parse_one_file(cachename); 227293650Sglebius } 228293650Sglebius} 229285612Sdelphij 230285612Sdelphij 231285612Sdelphijvoid parse_one_file(char *filename) 232285612Sdelphij{ 233285612Sdelphij char *fieldv[MAXFIELDS]; 234293650Sglebius int fieldc; 235285612Sdelphij void (*f)(int c, char **v); 236294569Sdelphij FILE *cf; 237285612Sdelphij char line[MAXLINELEN]; 238285612Sdelphij 239330567Sgordon snprintf(line, sizeof(line), "reading %s", filename); 240330567Sgordon status(line); 241330567Sgordon strlcpy(curfilename, filename, sizeof(curfilename)); 242330567Sgordon 243330567Sgordon if((cf = fopen(curfilename, "r")) == NULL) { 244330567Sgordon warn("%s", curfilename); 245330567Sgordon goterror = 1; 246330567Sgordon return; 247330567Sgordon } 248330567Sgordon 249285612Sdelphij linenum = 0; 250285612Sdelphij while(fgets(line, MAXLINELEN, cf) != NULL) { 251285612Sdelphij linenum++; 252285612Sdelphij parse_line(line, &fieldc, fieldv, MAXFIELDS); 253285612Sdelphij if(fieldc < 1) continue; 25454359Sroberto if(!strcmp(fieldv[0], "srcdirs")) f = add_srcdirs; 255330567Sgordon else if(!strcmp(fieldv[0], "progs")) f = add_progs; 256285612Sdelphij else if(!strcmp(fieldv[0], "ln")) f = add_link; 25754359Sroberto else if(!strcmp(fieldv[0], "libs")) f = add_libs; 25854359Sroberto else if(!strcmp(fieldv[0], "buildopts")) f = add_buildopts; 25954359Sroberto else if(!strcmp(fieldv[0], "special")) f = add_special; 26054359Sroberto else { 26154359Sroberto warnx("%s:%d: skipping unknown command `%s'", 262182007Sroberto curfilename, linenum, fieldv[0]); 26354359Sroberto goterror = 1; 26454359Sroberto continue; 265182007Sroberto } 26654359Sroberto if(fieldc < 2) { 26754359Sroberto warnx("%s:%d: %s command needs at least 1 argument, skipping", 268182007Sroberto curfilename, linenum, fieldv[0]); 26954359Sroberto goterror = 1; 27054359Sroberto continue; 271182007Sroberto } 27254359Sroberto f(fieldc, fieldv); 27354359Sroberto } 274182007Sroberto 275132451Sroberto if(ferror(cf)) { 27654359Sroberto warn("%s", curfilename); 277182007Sroberto goterror = 1; 27854359Sroberto } 27954359Sroberto fclose(cf); 280285612Sdelphij} 28154359Sroberto 28254359Sroberto 283182007Srobertovoid parse_line(char *line, int *fc, char **fv, int nf) 28454359Sroberto{ 28554359Sroberto char *p; 286182007Sroberto 28754359Sroberto p = line; 28854359Sroberto *fc = 0; 28954359Sroberto while(1) { 29054359Sroberto while(isspace(*p)) p++; 29154359Sroberto if(*p == '\0' || *p == '#') break; 29254359Sroberto 29354359Sroberto if(*fc < nf) fv[(*fc)++] = p; 29454359Sroberto while(*p && !isspace(*p) && *p != '#') p++; 295182007Sroberto if(*p == '\0' || *p == '#') break; 29654359Sroberto *p++ = '\0'; 29754359Sroberto } 298298770Sdelphij if(*p) *p = '\0'; /* needed for '#' case */ 299298770Sdelphij} 300298770Sdelphij 30154359Sroberto 30254359Srobertovoid add_srcdirs(int argc, char **argv) 30354359Sroberto{ 30454359Sroberto int i; 30554359Sroberto 30654359Sroberto for(i=1;i<argc;i++) { 30754359Sroberto if(is_dir(argv[i])) 30854359Sroberto add_string(&srcdirs, argv[i]); 30954359Sroberto else { 310182007Sroberto warnx("%s:%d: `%s' is not a directory, skipping it", 31154359Sroberto curfilename, linenum, argv[i]); 31254359Sroberto goterror = 1; 313182007Sroberto } 31454359Sroberto } 31554359Sroberto} 316182007Sroberto 317285612Sdelphij 318285612Sdelphijvoid add_progs(int argc, char **argv) 31954359Sroberto{ 32054359Sroberto int i; 32154359Sroberto 32254359Sroberto for(i=1;i<argc;i++) 32354359Sroberto add_prog(argv[i]); 32454359Sroberto} 32554359Sroberto 32654359Sroberto 327285612Sdelphijvoid add_prog(char *progname) 328285612Sdelphij{ 329285612Sdelphij prog_t *p1, *p2; 330285612Sdelphij 331285612Sdelphij /* add to end, but be smart about dups */ 332285612Sdelphij 333285612Sdelphij for(p1 = NULL, p2 = progs; p2 != NULL; p1 = p2, p2 = p2->next) 334285612Sdelphij if(!strcmp(p2->name, progname)) return; 335285612Sdelphij 336285612Sdelphij p2 = malloc(sizeof(prog_t)); 337285612Sdelphij if(p2) { 338285612Sdelphij memset(p2, 0, sizeof(prog_t)); 339285612Sdelphij p2->name = strdup(progname); 34054359Sroberto } 34154359Sroberto if(!p2 || !p2->name) 34254359Sroberto out_of_memory(); 34354359Sroberto 34454359Sroberto p2->next = NULL; 34554359Sroberto if(p1 == NULL) progs = p2; 34654359Sroberto else p1->next = p2; 347285612Sdelphij 34854359Sroberto p2->ident = p2->srcdir = p2->realsrcdir = p2->objdir = NULL; 349285612Sdelphij p2->links = p2->objs = p2->keeplist = NULL; 35054359Sroberto p2->buildopts = NULL; 35154359Sroberto p2->goterror = 0; 35254359Sroberto if (list_mode) 35354359Sroberto printf("%s\n",progname); 354285612Sdelphij} 355285612Sdelphij 35654359Sroberto 35754359Srobertovoid add_link(int argc, char **argv) 358285612Sdelphij{ 359285612Sdelphij int i; 36054359Sroberto prog_t *p = find_prog(argv[1]); 361285612Sdelphij 36254359Sroberto if(p == NULL) { 363132451Sroberto warnx("%s:%d: no prog %s previously declared, skipping link", 364132451Sroberto curfilename, linenum, argv[1]); 365132451Sroberto goterror = 1; 36654359Sroberto return; 367132451Sroberto } 36854359Sroberto for(i=2;i<argc;i++) { 36954359Sroberto if (list_mode) 37054359Sroberto printf("%s\n",argv[i]); 37154359Sroberto add_string(&p->links, argv[i]); 37254359Sroberto } 37354359Sroberto} 37454359Sroberto 37554359Sroberto 37654359Srobertovoid add_libs(int argc, char **argv) 37754359Sroberto{ 37854359Sroberto int i; 37954359Sroberto 38054359Sroberto for(i=1;i<argc;i++) 38154359Sroberto add_string(&libs, argv[i]); 38254359Sroberto} 38354359Sroberto 38454359Sroberto 385285612Sdelphijvoid add_buildopts(int argc, char **argv) 386285612Sdelphij{ 387285612Sdelphij int i; 388285612Sdelphij 38954359Sroberto for (i = 1; i < argc; i++) 390285612Sdelphij add_string(&buildopts, argv[i]); 391285612Sdelphij} 392285612Sdelphij 39354359Sroberto 39454359Srobertovoid add_special(int argc, char **argv) 39554359Sroberto{ 39654359Sroberto int i; 397316722Sdelphij prog_t *p = find_prog(argv[1]); 39854359Sroberto 39954359Sroberto if(p == NULL) { 40054359Sroberto if(reading_cache) return; 40154359Sroberto warnx("%s:%d: no prog %s previously declared, skipping special", 40254359Sroberto curfilename, linenum, argv[1]); 40354359Sroberto goterror = 1; 40454359Sroberto return; 405285612Sdelphij } 40654359Sroberto 407285612Sdelphij if(!strcmp(argv[2], "ident")) { 408285612Sdelphij if(argc != 4) goto argcount; 409285612Sdelphij if((p->ident = strdup(argv[3])) == NULL) 410285612Sdelphij out_of_memory(); 411285612Sdelphij } 412285612Sdelphij else if(!strcmp(argv[2], "srcdir")) { 413285612Sdelphij if(argc != 4) goto argcount; 414285612Sdelphij if((p->srcdir = strdup(argv[3])) == NULL) 415285612Sdelphij out_of_memory(); 416285612Sdelphij } 41754359Sroberto else if(!strcmp(argv[2], "objdir")) { 41854359Sroberto if(argc != 4) goto argcount; 41954359Sroberto if((p->objdir = strdup(argv[3])) == NULL) 42054359Sroberto out_of_memory(); 42154359Sroberto } 42254359Sroberto else if(!strcmp(argv[2], "objs")) { 42354359Sroberto p->objs = NULL; 42454359Sroberto for(i=3;i<argc;i++) 42554359Sroberto add_string(&p->objs, argv[i]); 42654359Sroberto } 42754359Sroberto else if(!strcmp(argv[2], "objpaths")) { 42854359Sroberto p->objpaths = NULL; 42954359Sroberto for(i=3;i<argc;i++) 43054359Sroberto add_string(&p->objpaths, argv[i]); 43154359Sroberto } 43254359Sroberto else if(!strcmp(argv[2], "keep")) { 43354359Sroberto p->keeplist = NULL; 43454359Sroberto for(i=3;i<argc;i++) 43554359Sroberto add_string(&p->keeplist, argv[i]); 43654359Sroberto } 43754359Sroberto else if(!strcmp(argv[2], "objvar")) { 43854359Sroberto if(argc != 4) 439289997Sglebius goto argcount; 44054359Sroberto if((p->objvar = strdup(argv[3])) == NULL) 44154359Sroberto out_of_memory(); 442285612Sdelphij } 44354359Sroberto else if (!strcmp(argv[2], "buildopts")) { 44454359Sroberto p->buildopts = NULL; 44554359Sroberto for (i = 3; i < argc; i++) 44654359Sroberto add_string(&p->buildopts, argv[i]); 447285612Sdelphij } 448285612Sdelphij else { 449285612Sdelphij warnx("%s:%d: bad parameter name `%s', skipping line", 450285612Sdelphij curfilename, linenum, argv[2]); 451285612Sdelphij goterror = 1; 452285612Sdelphij } 453285612Sdelphij return; 454285612Sdelphij 45554359Sroberto 456285612Sdelphij argcount: 457285612Sdelphij warnx("%s:%d: too %s arguments, expected \"special %s %s <string>\"", 45854359Sroberto curfilename, linenum, argc < 4? "few" : "many", argv[1], argv[2]); 45954359Sroberto goterror = 1; 46054359Sroberto} 46154359Sroberto 46254359Sroberto 46354359Srobertoprog_t *find_prog(char *str) 46454359Sroberto{ 46554359Sroberto prog_t *p; 46654359Sroberto 46754359Sroberto for(p = progs; p != NULL; p = p->next) 46854359Sroberto if(!strcmp(p->name, str)) return p; 46954359Sroberto 47054359Sroberto return NULL; 47154359Sroberto} 47254359Sroberto 473330567Sgordon 474285612Sdelphij/* 47554359Sroberto * ======================================================================== 47654359Sroberto * gen_outputs subsystem 47754359Sroberto * 47854359Sroberto */ 47954359Sroberto 48054359Sroberto/* helper subroutines */ 481285612Sdelphij 482316722Sdelphijvoid remove_error_progs(void); 48354359Srobertovoid fillin_program(prog_t *p); 484285612Sdelphijvoid gen_specials_cache(void); 485182007Srobertovoid gen_output_makefile(void); 486182007Srobertovoid gen_output_cfile(void); 487182007Sroberto 48854359Srobertovoid fillin_program_objs(prog_t *p, char *path); 489182007Srobertovoid top_makefile_rules(FILE *outmk); 49054359Srobertovoid prog_makefile_rules(FILE *outmk, prog_t *p); 49154359Srobertovoid output_strlst(FILE *outf, strlst_t *lst); 49254359Srobertochar *genident(char *str); 493285612Sdelphijchar *dir_search(char *progname); 494285612Sdelphij 495285612Sdelphij 496285612Sdelphijvoid gen_outputs(void) 497285612Sdelphij{ 498285612Sdelphij prog_t *p; 499285612Sdelphij 500285612Sdelphij for(p = progs; p != NULL; p = p->next) 501285612Sdelphij fillin_program(p); 502285612Sdelphij 503132451Sroberto remove_error_progs(); 504285612Sdelphij gen_specials_cache(); 505294569Sdelphij gen_output_cfile(); 506132451Sroberto gen_output_makefile(); 507285612Sdelphij status(""); 508330567Sgordon fprintf(stderr, 509330567Sgordon "Run \"make -f %s\" to build crunched binary.\n", outmkname); 510330567Sgordon} 511285612Sdelphij 512330567Sgordon/* 513285612Sdelphij * run the makefile for the program to find which objects are necessary 514285612Sdelphij */ 515285612Sdelphijvoid fillin_program(prog_t *p) 516285612Sdelphij{ 517330567Sgordon char path[MAXPATHLEN]; 518285612Sdelphij char line[MAXLINELEN]; 519285612Sdelphij FILE *f; 520285612Sdelphij 521294569Sdelphij snprintf(line, MAXLINELEN, "filling in parms for %s", p->name); 522294569Sdelphij status(line); 523294569Sdelphij 524285612Sdelphij if(!p->ident) 525285612Sdelphij p->ident = genident(p->name); 526294569Sdelphij 527294569Sdelphij /* look for the source directory if one wasn't specified by a special */ 528294569Sdelphij if(!p->srcdir) { 529285612Sdelphij p->srcdir = dir_search(p->name); 530285612Sdelphij } 531285612Sdelphij 532132451Sroberto /* Determine the actual srcdir (maybe symlinked). */ 533132451Sroberto if (p->srcdir) { 53454359Sroberto snprintf(line, MAXLINELEN, "cd %s && echo -n `/bin/pwd`", p->srcdir); 535182007Sroberto f = popen(line,"r"); 536182007Sroberto if (!f) 537285612Sdelphij errx(1, "Can't execute: %s\n", line); 538182007Sroberto 539182007Sroberto path[0] = '\0'; 540182007Sroberto fgets(path, sizeof path, f); 541182007Sroberto if (pclose(f)) 542285612Sdelphij errx(1, "Can't execute: %s\n", line); 543285612Sdelphij 544285612Sdelphij if (!*path) 545285612Sdelphij errx(1, "Can't perform pwd on: %s\n", p->srcdir); 546285612Sdelphij 547285612Sdelphij p->realsrcdir = strdup(path); 548285612Sdelphij } 549285612Sdelphij 550182007Sroberto /* Unless the option to make object files was specified the 551285612Sdelphij * the objects will be built in the source directory unless 552182007Sroberto * an object directory already exists. 553285612Sdelphij */ 554182007Sroberto if(!makeobj && !p->objdir && p->srcdir) { 555182007Sroberto snprintf(line, sizeof line, "%s/%s", objprefix, p->realsrcdir); 556285612Sdelphij if (is_dir(line)) { 557182007Sroberto if ((p->objdir = strdup(line)) == NULL) 558182007Sroberto out_of_memory(); 559285612Sdelphij } else 560182007Sroberto p->objdir = p->realsrcdir; 561182007Sroberto } 562285612Sdelphij/* 563285612Sdelphij * XXX look for a Makefile.{name} in local directory first. 564182007Sroberto * This lets us override the original Makefile. 565285612Sdelphij */ 566285612Sdelphij snprintf(path, sizeof(path), "Makefile.%s", p->name); 567298770Sdelphij if (is_nonempty_file(path)) { 568298770Sdelphij snprintf(line, MAXLINELEN, "Using %s for %s", path, p->name); 569285612Sdelphij status(line); 57054359Sroberto } else 57154359Sroberto if(p->srcdir) snprintf(path, sizeof(path), "%s/Makefile", p->srcdir); 572285612Sdelphij if(!p->objs && p->srcdir && is_nonempty_file(path)) 573285612Sdelphij fillin_program_objs(p, path); 574285612Sdelphij 575285612Sdelphij if(!p->srcdir && verbose) 576285612Sdelphij warnx("%s: %s: warning: could not find source directory", 577285612Sdelphij infilename, p->name); 578285612Sdelphij if(!p->objs && verbose) 579285612Sdelphij warnx("%s: %s: warning: could not find any .o files", 580285612Sdelphij infilename, p->name); 581285612Sdelphij 582285612Sdelphij if(!p->srcdir || !p->objs) 583285612Sdelphij p->goterror = 1; 584285612Sdelphij} 585285612Sdelphij 586285612Sdelphijvoid fillin_program_objs(prog_t *p, char *path) 587285612Sdelphij{ 588285612Sdelphij char *obj, *cp; 589285612Sdelphij int fd, rc; 590285612Sdelphij FILE *f; 591285612Sdelphij char *objvar="OBJS"; 59254359Sroberto strlst_t *s; 59354359Sroberto char line[MAXLINELEN]; 59454359Sroberto 59554359Sroberto /* discover the objs from the srcdir Makefile */ 59654359Sroberto 59754359Sroberto if((fd = mkstemp(tempfname)) == -1) { 59854359Sroberto perror(tempfname); 599293650Sglebius exit(1); 60054359Sroberto } 60154359Sroberto if((f = fdopen(fd, "w")) == NULL) { 602293650Sglebius warn("%s", tempfname); 60354359Sroberto goterror = 1; 60454359Sroberto return; 60554359Sroberto } 606285612Sdelphij if (p->objvar) 60754359Sroberto objvar = p->objvar ; 60854359Sroberto 60954359Sroberto /* 610330567Sgordon * XXX include outhdrname (e.g. to contain Make variables) 611330567Sgordon */ 612330567Sgordon if (outhdrname[0] != '\0') 613330567Sgordon fprintf(f, ".include \"%s\"\n", outhdrname); 614330567Sgordon fprintf(f, ".include \"%s\"\n", path); 615330567Sgordon if (buildopts) { 616285612Sdelphij fprintf(f, "BUILDOPTS+="); 617330567Sgordon output_strlst(f, buildopts); 618330567Sgordon } 61954359Sroberto fprintf(f, ".if defined(PROG) && !defined(%s)\n", objvar); 62054359Sroberto fprintf(f, "%s=${PROG}.o\n", objvar); 62154359Sroberto fprintf(f, ".endif\n"); 62254359Sroberto fprintf(f, "loop:\n\t@echo 'OBJS= '${%s}\n", objvar); 62354359Sroberto 62454359Sroberto fprintf(f, "crunchgen_objs:\n\t@make -f %s $(BUILDOPTS) $(%s_OPTS)", 62554359Sroberto tempfname, p->ident); 626285612Sdelphij for (s = p->buildopts; s != NULL; s = s->next) 62754359Sroberto fprintf(f, " %s", s->str); 62854359Sroberto fprintf(f, " loop\n"); 62954359Sroberto 63054359Sroberto fclose(f); 631285612Sdelphij 63254359Sroberto snprintf(line, MAXLINELEN, "make -f %s crunchgen_objs 2>&1", tempfname); 633285612Sdelphij if((f = popen(line, "r")) == NULL) { 634285612Sdelphij warn("submake pipe"); 63554359Sroberto goterror = 1; 63654359Sroberto return; 637285612Sdelphij } 63854359Sroberto 639132451Sroberto while(fgets(line, MAXLINELEN, f)) { 640285612Sdelphij if(strncmp(line, "OBJS= ", 6)) { 641285612Sdelphij warnx("make error: %s", line); 642285612Sdelphij goterror = 1; 643132451Sroberto continue; 644132451Sroberto } 64554359Sroberto cp = line + 6; 646132451Sroberto while(isspace(*cp)) cp++; 647132451Sroberto while(*cp) { 648132451Sroberto obj = cp; 649285612Sdelphij while(*cp && !isspace(*cp)) cp++; 650132451Sroberto if(*cp) *cp++ = '\0'; 651285612Sdelphij add_string(&p->objs, obj); 652285612Sdelphij while(isspace(*cp)) cp++; 653132451Sroberto } 654285612Sdelphij } 655132451Sroberto if((rc=pclose(f)) != 0) { 656285612Sdelphij warnx("make error: make returned %d", rc); 657285612Sdelphij goterror = 1; 658285612Sdelphij } 659285612Sdelphij unlink(tempfname); 660285612Sdelphij} 661285612Sdelphij 66254359Srobertovoid remove_error_progs(void) 66354359Sroberto{ 664132451Sroberto prog_t *p1, *p2; 665132451Sroberto 666132451Sroberto p1 = NULL; p2 = progs; 667132451Sroberto while(p2 != NULL) { 668132451Sroberto if(!p2->goterror) 669132451Sroberto p1 = p2, p2 = p2->next; 670132451Sroberto else { 671285612Sdelphij /* delete it from linked list */ 672285612Sdelphij warnx("%s: %s: ignoring program because of errors", 673132451Sroberto infilename, p2->name); 674132451Sroberto if(p1) p1->next = p2->next; 675285612Sdelphij else progs = p2->next; 676285612Sdelphij p2 = p2->next; 677132451Sroberto } 678285612Sdelphij } 679182007Sroberto} 680182007Sroberto 681182007Srobertovoid gen_specials_cache(void) 682182007Sroberto{ 683182007Sroberto FILE *cachef; 684132451Sroberto prog_t *p; 685132451Sroberto char line[MAXLINELEN]; 686132451Sroberto 687132451Sroberto snprintf(line, MAXLINELEN, "generating %s", cachename); 688285612Sdelphij status(line); 689132451Sroberto 690285612Sdelphij if((cachef = fopen(cachename, "w")) == NULL) { 691132451Sroberto warn("%s", cachename); 692132451Sroberto goterror = 1; 693285612Sdelphij return; 694285612Sdelphij } 695132451Sroberto 696285612Sdelphij fprintf(cachef, "# %s - parm cache generated from %s by crunchgen %s\n\n", 697132451Sroberto cachename, infilename, CRUNCH_VERSION); 698285612Sdelphij 699132451Sroberto for(p = progs; p != NULL; p = p->next) { 700132451Sroberto fprintf(cachef, "\n"); 701132451Sroberto if(p->srcdir) 702285612Sdelphij fprintf(cachef, "special %s srcdir %s\n", p->name, p->srcdir); 703285612Sdelphij if(p->objdir) 704285612Sdelphij fprintf(cachef, "special %s objdir %s\n", p->name, p->objdir); 705285612Sdelphij if(p->objs) { 706285612Sdelphij fprintf(cachef, "special %s objs", p->name); 707132451Sroberto output_strlst(cachef, p->objs); 708285612Sdelphij } 709285612Sdelphij if(p->objpaths) { 710132451Sroberto fprintf(cachef, "special %s objpaths", p->name); 711285612Sdelphij output_strlst(cachef, p->objpaths); 712285612Sdelphij } 713132451Sroberto } 714132451Sroberto fclose(cachef); 71554359Sroberto} 716285612Sdelphij 717285612Sdelphij 718285612Sdelphijvoid gen_output_makefile(void) 719285612Sdelphij{ 720285612Sdelphij prog_t *p; 721285612Sdelphij FILE *outmk; 722285612Sdelphij char line[MAXLINELEN]; 723285612Sdelphij 72454359Sroberto snprintf(line, MAXLINELEN, "generating %s", outmkname); 72554359Sroberto status(line); 72654359Sroberto 727285612Sdelphij if((outmk = fopen(outmkname, "w")) == NULL) { 728285612Sdelphij warn("%s", outmkname); 72954359Sroberto goterror = 1; 73054359Sroberto return; 731285612Sdelphij } 73254359Sroberto 733132451Sroberto fprintf(outmk, "# %s - generated from %s by crunchgen %s\n\n", 734285612Sdelphij outmkname, infilename, CRUNCH_VERSION); 735132451Sroberto if (outhdrname[0] != '\0') 736132451Sroberto fprintf(outmk, ".include \"%s\"\n", outhdrname); 737132451Sroberto 738132451Sroberto top_makefile_rules(outmk); 739132451Sroberto for(p = progs; p != NULL; p = p->next) 740132451Sroberto prog_makefile_rules(outmk, p); 741132451Sroberto 742132451Sroberto fprintf(outmk, "\n# ========\n"); 743132451Sroberto fclose(outmk); 74454359Sroberto} 74554359Sroberto 74654359Sroberto 74754359Srobertovoid gen_output_cfile(void) 74854359Sroberto{ 749182007Sroberto extern char *crunched_skel[]; 750285612Sdelphij char **cp; 751330567Sgordon FILE *outcf; 752285612Sdelphij prog_t *p; 753285612Sdelphij strlst_t *s; 754285612Sdelphij char line[MAXLINELEN]; 755285612Sdelphij 756285612Sdelphij snprintf(line, MAXLINELEN, "generating %s", outcfname); 75754359Sroberto status(line); 75854359Sroberto 75954359Sroberto if((outcf = fopen(outcfname, "w")) == NULL) { 760132451Sroberto warn("%s", outcfname); 76154359Sroberto goterror = 1; 762285612Sdelphij return; 763285612Sdelphij } 76454359Sroberto 765285612Sdelphij fprintf(outcf, 766285612Sdelphij "/* %s - generated from %s by crunchgen %s */\n", 767285612Sdelphij outcfname, infilename, CRUNCH_VERSION); 76854359Sroberto 76954359Sroberto fprintf(outcf, "#define EXECNAME \"%s\"\n", execfname); 770285612Sdelphij for(cp = crunched_skel; *cp != NULL; cp++) 77154359Sroberto fprintf(outcf, "%s\n", *cp); 77254359Sroberto 77354359Sroberto for(p = progs; p != NULL; p = p->next) 77454359Sroberto fprintf(outcf, "extern int _crunched_%s_stub();\n", p->ident); 775330567Sgordon 776285612Sdelphij fprintf(outcf, "\nstruct stub entry_points[] = {\n"); 77754359Sroberto for(p = progs; p != NULL; p = p->next) { 77854359Sroberto fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n", 77954359Sroberto p->name, p->ident); 78054359Sroberto for(s = p->links; s != NULL; s = s->next) 781285612Sdelphij fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n", 782132451Sroberto s->str, p->ident); 783285612Sdelphij } 78454359Sroberto 785132451Sroberto fprintf(outcf, "\t{ EXECNAME, crunched_main },\n"); 786285612Sdelphij fprintf(outcf, "\t{ NULL, NULL }\n};\n"); 787293650Sglebius fclose(outcf); 788132451Sroberto} 789293650Sglebius 790285612Sdelphij 791132451Srobertochar *genident(char *str) 792285612Sdelphij{ 793285612Sdelphij char *n,*s,*d; 794285612Sdelphij 79554359Sroberto /* 796285612Sdelphij * generates a Makefile/C identifier from a program name, mapping '-' to 797285612Sdelphij * '_' and ignoring all other non-identifier characters. This leads to 79854359Sroberto * programs named "foo.bar" and "foobar" to map to the same identifier. 79954359Sroberto */ 80054359Sroberto 80154359Sroberto if((n = strdup(str)) == NULL) 802285612Sdelphij return NULL; 803285612Sdelphij for(d = s = n; *s != '\0'; s++) { 804285612Sdelphij if(*s == '-') *d++ = '_'; 805285612Sdelphij else if(*s == '_' || isalnum(*s)) *d++ = *s; 806285612Sdelphij } 807285612Sdelphij *d = '\0'; 808316722Sdelphij return n; 809316722Sdelphij} 810316722Sdelphij 811316722Sdelphij 812316722Sdelphijchar *dir_search(char *progname) 813316722Sdelphij{ 814316722Sdelphij char path[MAXPATHLEN]; 815316722Sdelphij strlst_t *dir; 816285612Sdelphij char *srcdir; 817316722Sdelphij 818316722Sdelphij for(dir=srcdirs; dir != NULL; dir=dir->next) { 819316722Sdelphij snprintf(path, MAXPATHLEN, "%s/%s", dir->str, progname); 820316722Sdelphij if (!is_dir(path)) { 821316722Sdelphij continue; 822316722Sdelphij } 823316722Sdelphij 824316722Sdelphij if ((srcdir = strdup(path)) == NULL) 825316722Sdelphij out_of_memory(); 826316722Sdelphij return srcdir; 827316722Sdelphij } 828285612Sdelphij return NULL; 829316722Sdelphij} 830316722Sdelphij 831316722Sdelphij 832316722Sdelphijvoid top_makefile_rules(FILE *outmk) 833316722Sdelphij{ 834316722Sdelphij prog_t *p; 835316722Sdelphij 836316722Sdelphij fprintf(outmk, "LIBS="); 837316722Sdelphij output_strlst(outmk, libs); 838316722Sdelphij 839316722Sdelphij if (makeobj) { 840316722Sdelphij fprintf(outmk, "MAKEOBJDIRPREFIX?=%s\n", objprefix); 841316722Sdelphij fprintf(outmk, "MAKE=env MAKEOBJDIRPREFIX=$(MAKEOBJDIRPREFIX) make\n"); 842316722Sdelphij } else { 843316722Sdelphij fprintf(outmk, "MAKE=make\n"); 844285612Sdelphij } 845285612Sdelphij 846285612Sdelphij if (buildopts) { 847285612Sdelphij fprintf(outmk, "BUILDOPTS+="); 84854359Sroberto output_strlst(outmk, buildopts); 84954359Sroberto } 85054359Sroberto 85154359Sroberto fprintf(outmk, "CRUNCHED_OBJS="); 85254359Sroberto for(p = progs; p != NULL; p = p->next) 85354359Sroberto fprintf(outmk, " %s.lo", p->name); 854285612Sdelphij fprintf(outmk, "\n"); 855285612Sdelphij 85654359Sroberto fprintf(outmk, "SUBMAKE_TARGETS="); 85754359Sroberto for(p = progs; p != NULL; p = p->next) 85854359Sroberto fprintf(outmk, " %s_make", p->ident); 859285612Sdelphij fprintf(outmk, "\nSUBCLEAN_TARGETS="); 86054359Sroberto for(p = progs; p != NULL; p = p->next) 861293650Sglebius fprintf(outmk, " %s_clean", p->ident); 862285612Sdelphij fprintf(outmk, "\n\n"); 86354359Sroberto 86454359Sroberto fprintf(outmk, "all: objs exe\nobjs: $(SUBMAKE_TARGETS)\n"); 86554359Sroberto fprintf(outmk, "exe: %s\n", execfname); 86654359Sroberto fprintf(outmk, "%s: %s.o $(CRUNCHED_OBJS)\n", 867285612Sdelphij execfname, execfname); 868285612Sdelphij fprintf(outmk, "\t$(CC) -static -o %s %s.o $(CRUNCHED_OBJS) $(LIBS)\n", 86954359Sroberto execfname, execfname); 87054359Sroberto fprintf(outmk, "\tstrip %s\n", execfname); 87154359Sroberto fprintf(outmk, "realclean: clean subclean\n"); 87254359Sroberto fprintf(outmk, "clean:\n\trm -f %s *.lo *.o *_stub.c\n", 87354359Sroberto execfname); 87454359Sroberto fprintf(outmk, "subclean: $(SUBCLEAN_TARGETS)\n"); 87554359Sroberto} 87654359Sroberto 87754359Sroberto 87854359Srobertovoid prog_makefile_rules(FILE *outmk, prog_t *p) 87954359Sroberto{ 88054359Sroberto strlst_t *lst; 881293650Sglebius 882285612Sdelphij fprintf(outmk, "\n# -------- %s\n\n", p->name); 88354359Sroberto 88454359Sroberto if(p->srcdir && p->objs) { 88554359Sroberto fprintf(outmk, "%s_SRCDIR=%s\n", p->ident, p->srcdir); 88654359Sroberto fprintf(outmk, "%s_REALSRCDIR=%s\n", p->ident, p->realsrcdir); 887285612Sdelphij 88854359Sroberto fprintf(outmk, "%s_OBJDIR=", p->ident); 88954359Sroberto if (p->objdir) 89054359Sroberto fprintf(outmk, "%s", p->objdir); 89154359Sroberto else 892285612Sdelphij fprintf(outmk, "$(MAKEOBJDIRPREFIX)/$(%s_REALSRCDIR)\n", 893285612Sdelphij p->ident); 894285612Sdelphij fprintf(outmk, "\n"); 89554359Sroberto 896285612Sdelphij fprintf(outmk, "%s_OBJS=", p->ident); 89754359Sroberto output_strlst(outmk, p->objs); 89854359Sroberto if (p->buildopts != NULL) { 899285612Sdelphij fprintf(outmk, "%s_OPTS+=", p->ident); 900294569Sdelphij output_strlst(outmk, p->buildopts); 901294569Sdelphij } 902294569Sdelphij fprintf(outmk, "%s_make:\n", p->ident); 903294569Sdelphij fprintf(outmk, "\t(cd $(%s_SRCDIR) && ", p->ident); 90454359Sroberto if (makeobj) 905316722Sdelphij fprintf(outmk, "$(MAKE) obj && "); 906316722Sdelphij fprintf(outmk, "\\\n"); 907316722Sdelphij fprintf(outmk, "\t\t$(MAKE) $(BUILDOPTS) $(%s_OPTS) depend && \\\n" 90854359Sroberto "\t\t$(MAKE) $(BUILDOPTS) $(%s_OPTS) $(%s_OBJS))\n", 90954359Sroberto p->ident, p->ident, p->ident); 91054359Sroberto fprintf(outmk, "%s_clean:\n", p->ident); 91154359Sroberto fprintf(outmk, "\t(cd $(%s_SRCDIR) && $(MAKE) clean)\n\n", p->ident); 91254359Sroberto } 91354359Sroberto else 91454359Sroberto fprintf(outmk, "%s_make:\n\t@echo \"** cannot make objs for %s\"\n\n", 91554359Sroberto p->ident, p->name); 91654359Sroberto 917285612Sdelphij fprintf(outmk, "%s_OBJPATHS=", p->ident); 91854359Sroberto if (p->objpaths) 91954359Sroberto output_strlst(outmk, p->objpaths); 92054359Sroberto else { 92154359Sroberto for (lst = p->objs; lst != NULL; lst = lst->next) { 92254359Sroberto fprintf(outmk, " $(%s_OBJDIR)/%s", p->ident, lst->str); 923294569Sdelphij } 924294569Sdelphij fprintf(outmk, "\n"); 92554359Sroberto } 92654359Sroberto 927285612Sdelphij fprintf(outmk, "%s_stub.c:\n", p->name); 928285612Sdelphij fprintf(outmk, "\techo \"" 929285612Sdelphij "int _crunched_%s_stub(int argc, char **argv, char **envp)" 930285612Sdelphij "{return main(argc,argv,envp);}\" >%s_stub.c\n", 931285612Sdelphij p->ident, p->name); 93254359Sroberto fprintf(outmk, "%s.lo: %s_stub.o $(%s_OBJPATHS)\n", 933285612Sdelphij p->name, p->name, p->ident); 934285612Sdelphij fprintf(outmk, "\tld -dc -r -o %s.lo %s_stub.o $(%s_OBJPATHS)\n", 935285612Sdelphij p->name, p->name, p->ident); 936285612Sdelphij fprintf(outmk, "\tcrunchide -k _crunched_%s_stub ", p->ident); 937294569Sdelphij for(lst = p->keeplist; lst != NULL; lst = lst->next) 93854359Sroberto fprintf(outmk, "-k _%s ", lst->str); 939285612Sdelphij fprintf(outmk, "%s.lo\n", p->name); 940293650Sglebius} 941285612Sdelphij 942294569Sdelphijvoid output_strlst(FILE *outf, strlst_t *lst) 943294569Sdelphij{ 944294569Sdelphij for(; lst != NULL; lst = lst->next) 945294569Sdelphij fprintf(outf, " %s", lst->str); 946294569Sdelphij fprintf(outf, "\n"); 947294569Sdelphij} 948294569Sdelphij 949294569Sdelphij 950294569Sdelphij/* 951294569Sdelphij * ======================================================================== 952294569Sdelphij * general library routines 953294569Sdelphij * 954294569Sdelphij */ 955294569Sdelphij 956294569Sdelphijvoid status(char *str) 957285612Sdelphij{ 958285612Sdelphij static int lastlen = 0; 959285612Sdelphij int len, spaces; 960294569Sdelphij 961294569Sdelphij if(!verbose) return; 962294569Sdelphij 963294569Sdelphij len = strlen(str); 964294569Sdelphij spaces = lastlen - len; 965294569Sdelphij if(spaces < 1) spaces = 1; 966294569Sdelphij 967294569Sdelphij fprintf(stderr, " [%s]%*.*s\r", str, spaces, spaces, " "); 968316722Sdelphij fflush(stderr); 969316722Sdelphij lastlen = len; 970316722Sdelphij} 971294569Sdelphij 972294569Sdelphij 973316722Sdelphijvoid out_of_memory(void) 974285612Sdelphij{ 975285612Sdelphij err(1, "%s: %d: out of memory, stopping", infilename, linenum); 976285612Sdelphij} 977285612Sdelphij 978285612Sdelphij 979285612Sdelphijvoid add_string(strlst_t **listp, char *str) 980285612Sdelphij{ 981285612Sdelphij strlst_t *p1, *p2; 982285612Sdelphij 983285612Sdelphij /* add to end, but be smart about dups */ 98454359Sroberto 985285612Sdelphij for(p1 = NULL, p2 = *listp; p2 != NULL; p1 = p2, p2 = p2->next) 986285612Sdelphij if(!strcmp(p2->str, str)) return; 987285612Sdelphij 98854359Sroberto p2 = malloc(sizeof(strlst_t)); 989285612Sdelphij if(p2) { 990285612Sdelphij p2->next = NULL ; 991285612Sdelphij p2->str = strdup(str); 992285612Sdelphij } 993285612Sdelphij if(!p2 || !p2->str) 994285612Sdelphij out_of_memory(); 995285612Sdelphij 996285612Sdelphij if(p1 == NULL) *listp = p2; 997285612Sdelphij else p1->next = p2; 998285612Sdelphij} 999285612Sdelphij 1000285612Sdelphij 1001285612Sdelphijint is_dir(char *pathname) 1002285612Sdelphij{ 100354359Sroberto struct stat buf; 100454359Sroberto 100554359Sroberto if(stat(pathname, &buf) == -1) 100654359Sroberto return 0; 1007285612Sdelphij return S_ISDIR(buf.st_mode); 1008316722Sdelphij} 1009285612Sdelphij 1010285612Sdelphijint is_nonempty_file(char *pathname) 1011285612Sdelphij{ 101254359Sroberto struct stat buf; 1013285612Sdelphij 1014285612Sdelphij if(stat(pathname, &buf) == -1) 1015285612Sdelphij return 0; 1016285612Sdelphij 101754359Sroberto return S_ISREG(buf.st_mode) && buf.st_size > 0; 1018285612Sdelphij} 1019285612Sdelphij