/* * "makemake" Copyright (C) 1994-9, Codemist Ltd * * Used to build system-specific makefiles from a common base file * * * Usage: * makemake key* [-f prototype] [-o newmakefile] * [-ddata1] [-ddata2] ... * * The default prototype file is called "makebase" and the default * file created is called just "makenew" (note that both those are * spelt in lower case letters). The "keys" passed as arguments * should match the options declared at the head of the makebase file. * Data given after "-d" is used where otherwise interactive input would be * requested. */ /* Signature: 55907f19 10-Feb-1999 */ /* * The base file is a prototype "makefile", but with extra decorations so * that it can contain information relating to several systems. Lines * starting "@ " are comment and are ignored. Apart from such comments * the file should start with a section: * @menu * @item(key1) description * @item(key2) description * @endmenu * (the "@" signs should be in column 1, ie no whitespace before them) * This declares the valid keys. A key can be written as * @item(key>extra1>extra2) description * and then if the key is specified the given extra symbols will be defined * while processing the makebase file. An example use for this might be * @item(dos386>msdos) Intel 386/486 running DOS * @item(dos286>msdos>sixteenbit) Intel 286 running DOS * where subsequent items in the file may test msdos or sixteenbit. * * After the menu the makebase file is processed subject to directives * @if(key) * @ifnot(key) * @else * @elif(key) * @elifnot(key) * @endif * (again no whitespace is permitted, and the "@" must be in column 1) * which provide for conditional inclusion of text. A condition is TRUE if * it was either the key specified to mmake, or was set up by a ">" * in a menu item that matched the key. * @error (while not skipping) * terminates processing. * */ #include #include #include #include #ifndef SEEK_SET #define SEEK_SET 0 #endif #ifndef EXIT_FAILURE #define EXIT_FAILURE 1 #endif static int flags; static char *special_words[] = { "backslash", #define FLAG_BACKSLASH (flags & 0x001) "watcom", #define FLAG_WATCOM (flags & 0x002) "obj", #define FLAG_OBJ (flags & 0x004) "acorn", #define FLAG_ACORN (flags & 0x008) "escapequote", #define FLAG_ESCAPEQUOTE (flags & 0x010) "blank", #define FLAG_BLANK (flags & 0x020) "unix", #define FLAG_UNIX (flags & 0x040) "blank1", #define FLAG_BLANK1 (flags & 0x080) 0 }; #define N_SPECIAL_WORDS 7 #define LINE_LENGTH 1024 static char line[LINE_LENGTH]; static int EOF_seen = 0; int line_number, last_live_line; #define MAX_WORDS 100 static char *defined_words[MAX_WORDS]; static int in_makebase[MAX_WORDS]; static int n_user_words = 0, n_defined_words = 0; static FILE *fmakebase, *fmakefile; static int get_line() /* Read one line from makebase into line buffer, return 1 if OK */ { int i = 0, c; if (EOF_seen) return 0; line_number++; while ((c = getc(fmakebase)) != '\n' && c != EOF) if (i < LINE_LENGTH-2) line[i++] = c; /* I lose trailing blanks from all input lines */ while (i > 0 && (line[i-1] == ' ' || line[i-1] == '\t')) i--; /* * If the file ended with a line that was not terminated by '\n' I * insert a '\n' here. */ if (c == EOF) { EOF_seen = 1; if (i != 0) { line[i++] = '\n'; line[i] = 0; return 1; } else return 0; } line[i++] = '\n'; line[i] = 0; return 1; } static int process_item(int show) { char menuitem[LINE_LENGTH], *extra_defines[16]; int i, p, n_extra_defines = 0; for (i=0, p=6; line[p] != ')' && line[p] != '\n'; ) { if (line[p] == '>') { menuitem[i++] = 0; extra_defines[n_extra_defines++] = &menuitem[i]; p++; } else menuitem[i++] = line[p++]; } menuitem[i] = 0; if (line[p] != ')') return 0; else p++; while (line[p] == ' ' || line[p] == '\t') p++; if (show) { int len = (256 - strlen(menuitem)) % 8; printf(" %s:%*s %s", menuitem, len, "", &line[p]); return 1; } for (i=0; i= n_defined_words) return 0; for (i=0; i= 0 && raw_filename[j] != '.') j--; extension[0] = 0; if (j > 0 & raw_filename[j] == '.' && strlen(&raw_filename[j]) < 16) { strcpy(extension, &raw_filename[j+1]); raw_filename[j] = 0; } for (j=0; extension[j]!=0; j++) { c = extension[j]; if (isupper(c)) c = tolower(c); lc_extension[j] = c; } lc_extension[j] = 0; for (j=0; implicit_dirs[j]!=NULL; j++) if (strcmp(implicit_dirs[j], extension) == 0) break; if (implicit_dirs[j] != NULL) /* Match found - flip around */ { j = strlen(raw_filename)-1; while (j >= 0 && raw_filename[j] != '.') j--; if (j > 0) { raw_filename[j] = 0; fprintf(fmakefile, "%s.%s.%s", raw_filename, extension, &raw_filename[j+1]); } else fprintf(fmakefile, "%s.%s", extension, raw_filename); } else if (extension[0] == 0) fprintf(fmakefile, "%s", raw_filename); else fprintf(fmakefile, "%s.%s", raw_filename, extension); return i-1; } #endif /* SUPPORT_ACORN */ static void put_filename(char *filename) { int i, c; if (FLAG_OBJ) { i = strlen(filename) - 2; if (i > 0 && strcmp(&filename[i], ".o") == 0) strcpy(&filename[i], ".obj"); } if (FLAG_UNIX) { i = strlen(filename) - 4; if (i > 0 && strcmp(&filename[i], ".exe") == 0) filename[i] = 0; } if (FLAG_BACKSLASH) { for (i=0; (c=filename[i])!=0; i++) if (c == '/') filename[i] = '\\'; } for (i=0; (c=filename[i])!=0; i++) putc(c, fmakefile); } static char userinput[256]; static char **data; static int data_available; static void put_line() { int i = 0, c; char filename[256], *p; /* * A typical problem with expanded files is that blank lines accumulate * beyond reason. Here I will lose any excessive blank blocks. */ if (line[0] == '\n') { if (blank_lines++ > 3) return; } else blank_lines = 0; while ((c = line[i++]) != 0) { /* * The line buffer here has a newline character at its end, but no (other) * trailing whitespace. For the Watcom "make" utility I need to convert * any trailing "\" into a "&". */ if (c == '\\' && FLAG_WATCOM && line[i] == '\n') { putc('&', fmakefile); putc('\n', fmakefile); break; } if (c == '@') { c = line[i++]; switch (c) { case '@': putc(c, fmakefile); continue; case '~': if (FLAG_BLANK) putc(' ', fmakefile); continue; case '=': if (FLAG_BLANK1) putc(' ', fmakefile); continue; case '"': if (FLAG_ESCAPEQUOTE) putc('\\', fmakefile); putc(c, fmakefile); continue; case '?': c = line[i++]; if (c != '(') i--; p = userinput; while ((c = line[i++]) != ')' && c != 0 && c != '\n') putchar(c); if (data_available != 0) { char *q = *data++; data_available--; while ((c = *q++) != 0) *p++ = c, putc(c, fmakefile); *p = 0; printf("\n%s\n", userinput); } else { printf("\nPlease enter value as described above,\n"); printf("file-names to use \"/\" as directory separator: "); while ((c = getchar()) != '\n' && c != EOF) *p++ = c, putc(c, fmakefile); *p = 0; } continue; case '!': put_filename(userinput); continue; default: p = filename; i--; while ((c = line[i++]) != ' ' && c != 0 && c != '\n' && c != '\\' && c != ',' && !(c == ':' && isspace(line[i]))) *p++ = c; *p = 0; i--; /* unread the character that ended the filename */ put_filename(filename); continue; } } else putc(c, fmakefile); } } static int eval_condition(char *s) { char word[LINE_LENGTH]; int i = 0; while (s[i] != ')' && s[i] != 0) { int c = s[i]; if (c == '\n') return 0; /* bad syntax - treat as condition false */ word[i++] = c; } word[i] = 0; for (i=0; i 0) nesting--; else skipping = 0; } else if (memcmp(line, "@error", 6) == 0) { if (skipping == 0) { printf("\nError line detected...\n"); printf("%s", line); exit(EXIT_FAILURE); } } else if (skipping == 0) put_line(); } if (skipping != 0) { printf("Still skipping at end of file after line %d\n", last_live_line); } printf("\"%s\" created as makefile for", makefile); for (i=0; i= DATA_SIZE) printf("Too many \"-d\" options. Ignore this one\n"); else data[data_available++] = q; } continue; default: printf("Unknown option \"%s\" ignored\n", arg); continue; } else defined_words[n_defined_words++] = arg; } if (usage) return 0; if (makebase == NULL) makebase = "makebase"; if (makefile == NULL) makefile = "makenew"; if ((fmakebase = fopen(makebase, "r")) == NULL) { printf("Unable to read \"%s\"\n", makebase); return 0; } if (n_defined_words == 0) process_menu(1, makebase); else { if ((fmakefile = fopen(makefile, "w")) == NULL) { printf("Unable to write to file \"%s\"\n", makefile); fclose(fmakebase); return 0; } n_user_words = n_defined_words; create_makefile(makebase, makefile); fclose(fmakefile); } fclose(fmakebase); return 0; } /* end of makemake.c */