From 810ebcb31d066280120f2980c42ef8c2bdc081e5 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 9 Apr 2006 19:39:07 +0000 Subject: [PATCH] Updated to Chris's latest cbuild. SVN r22 (trunk) --- cbuild.c | 3730 ++++++++++++++++++++++++++++++++++++++------------- default.cbd | 550 +++++--- 2 files changed, 3116 insertions(+), 1164 deletions(-) diff --git a/cbuild.c b/cbuild.c index 1ab8f7e8d..045a1dcac 100644 --- a/cbuild.c +++ b/cbuild.c @@ -1,7 +1,7 @@ #define foobarbaz /* # A shell script within a source file. Ugly, but it works... -TRGT='cbuild' +TRGT=${0/.c/.exe} for i in $@ ; do if [ "$i" = "--make-compiled" ] ; then echo "Compiling '$TRGT', please wait..." @@ -10,11 +10,29 @@ for i in $@ ; do fi done -gcc -W -Wall -Werror -o /tmp/$TRGT "$0" && { "/tmp/$TRGT" `for i in $@ ; do echo "$i" ; done` ; RET=$? ; rm -f "/tmp/$TRGT" ; exit $RET ; } +gcc -W -Wall -Werror -o /tmp/$TRGT "$0" && { "/tmp/$TRGT" $@ ; RET=$? ; rm -f "/tmp/$TRGT" ; exit $RET ; } exit $? - */ +/* CBuild written by Chris Robinson, copyright 2005-2006 + * + * Notice of Terms of Use + * + * CBuild is provided as-is for personal use. You may use and redistribute it + * in any manner, with the following terms and conditions: + * + * * You MAY NOT sell it, or otherwise redistribute it for profit, unless it is + * bundled with a seperate commercial product and is used to build said + * product. + * * You MAY modify it without recompense or notification to the author, as + * long as it is clearly marked as a derivitive work. + * * You MAY NOT claim it as your own sole work. + * * You MAY NOT remove or modify this notice. + */ + +/* Despite what some people may think, no, the name CBuild did not come from my + * first name. I got the name from the fact that it uses pure C, and only C. ;) + */ #include #include @@ -22,38 +40,163 @@ exit $? #include #include #include -#include #include #include +#include + +#ifdef __unix__ +#include +#endif +#if defined(__unix__) || defined(__GNUC__) +#include +#include +#endif #ifdef _WIN32 -static void setenv(const char *env, const char *val, int overwrite) -{ - static char buf[128]; - if(!overwrite && getenv(env)) - return; - - snprintf(buf, sizeof(buf), "%s=%s", env, val); - _putenv(buf); -} - -static void unsetenv(const char *env) -{ - setenv(env, "", 1); -} +#include #ifdef _MSC_VER +// MSVC Sucks #define strcasecmp stricmp #define strncasecmp strnicmp #define snprintf _snprintf -#endif + +#define PATH_MAX _MAX_PATH +#define lstat slat +#define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR) +#define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG) +#define S_IRUSR _S_IREAD +#define S_IWUSR _S_IWRITE +#define S_IXUSR _S_IEXEC +#define S_IRWXU (_S_IREAD | _S_IWRITE | _S_IEXEC) + +struct dirent { + char *d_name; +}; + +typedef struct { + long handle; /* -1 for failed rewind */ + struct _finddata_t info; + struct dirent result; /* d_name null iff first time */ + char *name; /* null-terminated char string */ +} DIR; + +DIR *opendir(const char *name) +{ + DIR *dir = 0; + + if(name && name[0]) + { + /* search pattern must end with suitable wildcard */ + size_t base_length = strlen(name); + const char *all = strchr("/\\", name[base_length - 1]) ? "*" : "/*"; + + if((dir=(DIR*)malloc(sizeof(*dir))) != 0 && + (dir->name=(char*)malloc(base_length+strlen(all)+1)) != 0) + { + strcat(strcpy(dir->name, name), all); + + if((dir->handle = (long) _findfirst(dir->name, &dir->info)) != -1) + { + dir->result.d_name = 0; + } + else /* rollback */ + { + free(dir->name); + free(dir); + dir = NULL; + } + } + else /* rollback */ + { + free(dir); + dir = NULL; + errno = ENOMEM; + } + } + else + errno = EINVAL; + + return dir; +} + +int closedir(DIR *dir) +{ + int result = -1; + + if(dir) + { + if(dir->handle != -1) + result = _findclose(dir->handle); + + free(dir->name); + free(dir); + } + + if(result == -1) /* map all errors to EBADF */ + errno = EBADF; + + return result; +} + +struct dirent *readdir(DIR *dir) +{ + struct dirent *result = 0; + + if(dir && dir->handle != -1) + { + if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) + { + result = &dir->result; + result->d_name = dir->info.name; + } + } + else + errno = EBADF; + + return result; +} + +void rewinddir(DIR *dir) +{ + if(dir && dir->handle != -1) + { + _findclose(dir->handle); + dir->handle = (long)_findfirst(dir->name, &dir->info); + dir->result.d_name = 0; + } + else + errno = EBADF; +} + +#endif /* _MSC_VER */ + + +static int setenv(const char *env, const char *val, int overwrite) +{ + static char buf[64*1024]; + if(!overwrite && getenv(env)) + return 0; + + if(val && *val) + snprintf(buf, sizeof(buf), "%s=%s", env, val); + else + snprintf(buf, sizeof(buf), "%s", env); + return _putenv(buf); +} + +static int unsetenv(const char *env) +{ + return setenv(env, "", 1); +} #endif /* Win32 */ #define INVOKE_BKP_SIZE 16 struct { FILE *f; + char *fname; char *bkp_lbuf; char *bkp_nextline; int bkp_line; @@ -62,22 +205,36 @@ struct { int bkp_do_level; } invoke_backup[INVOKE_BKP_SIZE]; +static char **argv; +static int argc; +static FILE *infile; + +static FILE *f; +static char *fname; static struct stat statbuf; static char linebuf[64*1024]; static char buffer[64*1024]; static char *loaded_files; static char *sources; -static char obj[64]; +static char obj[PATH_MAX]; #define SRC_PATH_SIZE 32 static char *src_paths[SRC_PATH_SIZE]; +static int curr_line = 0; +static char *nextline; + +static jmp_buf jmpbuf; + + +static int libify_name(char *buf, size_t buflen, char *name); + + /* getvar: Safely gets an environment variable, returning an empty string * instead of NULL */ static const char *getvar(const char *env) { - const char *var; - var = getenv(env); + const char *var = getenv(env); return (var?var:""); } @@ -87,7 +244,7 @@ static const char *getvar(const char *env) */ static char *find_src(char *src) { - static char buf[64]; + static char buf[PATH_MAX]; struct stat statbuf; int i; @@ -103,37 +260,1222 @@ static char *find_src(char *src) return src; } + +/* grab_word: Gets a word starting at the string pointed to by 'str'. If + * the word begins with a ' or " character, everything until that same + * character will be considered part of the word. Otherwise, the word ends at + * the first encountered whitespace. Returns the beginning of the next word, + * or the end of the string. + */ +static char *grab_word(char **str, char *term) +{ + char *end; + char c; + + c = **str; + if(!c) + { + if(term) + *term = 0; + return *str; + } + + if(c == '\'' || c == '"') + { + ++(*str); + end = *str; + while(*end && *end != c) + ++end; + } + else + { + end = *str; + while(!isspace(*end) && *end) + ++end; + } + + if(term) + *term = *end; + + if(*end) *(end++) = 0; + while(isspace(*end) && *end) + ++end; + + return end; +} + +#define BUF_SIZE (64*1024) +/* + */ +static char *expand_string(char *str, const char *stp, size_t len, + int fillmore) +{ + char *buf, *ptr, *last_pos; + int in_quotes = 0; + int use_hard_quotes = 0; + char *end; + int i; + + if(!(*str) && !fillmore) + return str; + + buf = malloc(BUF_SIZE); + if(!buf) + { + strcpy(linebuf, "exit -1\n"); + longjmp(jmpbuf, 1); + } + + last_pos = str; + do { + ptr = last_pos; + while(1) + { + if(!(*ptr)) + { + if(fillmore) + { + if(fgets(ptr, len+str-ptr, f) == NULL) + { + free(buf); + fprintf(stderr, "\n\n!!! Premature EOF !!!\n%s\n", + (in_quotes?"!!! Unterminated string !!!\n": + "")); + strcpy(linebuf, "exit -1\n"); + longjmp(jmpbuf, 1); + } + ++curr_line; + } + } + + if(!in_quotes) + { + i = 0; + do { + if((stp[i] == ' ' && isspace(*ptr)) || + (stp[i] == '^' && !isalpha(*ptr)) || + *ptr == stp[i]) + { + free(buf); + return ptr; + } + } while(stp[i++]); + } + + + if(*ptr == '$') + { + if(in_quotes != '\'') + break; + } + else if(*ptr == '#') + { + if(!in_quotes) + { + char *next = strchr(ptr, '\n'); + if(!next) next = ""; + memmove(ptr, next, strlen(next)+1); + continue; + } + } + else if(*ptr == '&') + { + if(in_quotes != '\'') + { + unsigned long val = '?'; + + end = NULL; + + if(ptr[1] != '#') + { + static struct { + char *name; + unsigned long val; + } val_tab[] = { + { "Aacute", 0x00C1 }, { "aacute", 0x00E1 }, + { "Acirc", 0x00C2 }, { "acirc", 0x00E2 }, + { "acute", 0x00B4 }, { "AElig", 0x00C6 }, + { "aelig", 0x00E6 }, { "Agrave", 0x00C0 }, + { "agrave", 0x00E0 }, { "alefsym", 0x2135 }, + { "Alpha", 0x0391 }, { "alpha", 0x03B1 }, + { "amp", 0x0026 }, { "and", 0x2227 }, + { "ang", 0x2220 }, { "Aring", 0x00C5 }, + { "aring", 0x00E5 }, { "asymp", 0x2248 }, + { "Atilde", 0x00C3 }, { "atilde", 0x00E3 }, + { "Auml", 0x00C4 }, { "auml", 0x00E4 }, + { "bdquo", 0x201E }, { "Beta", 0x0392 }, + { "beta", 0x03B2 }, { "brvbar", 0x00A6 }, + { "bull", 0x2022 }, { "cap", 0x2229 }, + { "Ccedil", 0x00C7 }, { "ccedil", 0x00E7 }, + { "cedil", 0x00B8 }, { "cent", 0x00A2 }, + { "Chi", 0x03A7 }, { "chi", 0x03C7 }, + { "circ", 0x02C6 }, { "clubs", 0x2663 }, + { "cong", 0x2245 }, { "copy", 0x00A9 }, + { "crarr", 0x21B5 }, { "cup", 0x222A }, + { "curren", 0x00A4 }, { "Dagger", 0x2021 }, + { "dagger", 0x2020 }, { "dArr", 0x21D3 }, + { "darr", 0x2193 }, { "deg", 0x00B0 }, + { "Delta", 0x0394 }, { "delta", 0x03B4 }, + { "diams", 0x2666 }, { "divide", 0x00F7 }, + { "Eacute", 0x00C9 }, { "eacute", 0x00E9 }, + { "Ecirc", 0x00CA }, { "ecirc", 0x00EA }, + { "Egrave", 0x00C8 }, { "egrave", 0x00E8 }, + { "empty", 0x2205 }, { "emsp", 0x2003 }, + { "ensp", 0x2002 }, { "Epsilon", 0x0395 }, + { "epsilon", 0x03B5 }, { "equiv", 0x2261 }, + { "Eta", 0x0397 }, { "eta", 0x03B7 }, + { "ETH", 0x00D0 }, { "eth", 0x00F0 }, + { "Euml", 0x00CB }, { "euml", 0x00EB }, + { "euro", 0x20AC }, { "exist", 0x2203 }, + { "fnof", 0x0192 }, { "forall", 0x2200 }, + { "frac12", 0x00BD }, { "frac14", 0x00BC }, + { "frac34", 0x00BE }, { "frasl", 0x2044 }, + { "Gamma", 0x0393 }, { "gamma", 0x03B3 }, + { "ge", 0x2265 }, { "gt", 0x003E }, + { "hArr", 0x21D4 }, { "harr", 0x2194 }, + { "hearts", 0x2665 }, { "hellip", 0x2026 }, + { "Iacute", 0x00CD }, { "iacute", 0x00ED }, + { "Icirc", 0x00CE }, { "icirc", 0x00EE }, + { "iexcl", 0x00A1 }, { "Igrave", 0x00CC }, + { "igrave", 0x00EC }, { "image", 0x2111 }, + { "infin", 0x221E }, { "int", 0x222B }, + { "Iota", 0x0399 }, { "iota", 0x03B9 }, + { "iquest", 0x00BF }, { "isin", 0x2208 }, + { "Iuml", 0x00CF }, { "iuml", 0x00EF }, + { "Kappa", 0x039A }, { "kappa", 0x03BA }, + { "Lambda", 0x039B }, { "lambda", 0x03BB }, + { "lang", 0x2329 }, { "laquo", 0x00AB }, + { "lArr", 0x21D0 }, { "larr", 0x2190 }, + { "lceil", 0x2308 }, { "ldquo", 0x201C }, + { "le", 0x2264 }, { "lfloor", 0x230A }, + { "lowast", 0x2217 }, { "loz", 0x25CA }, + { "lrm", 0x200E }, { "lsaquo", 0x2039 }, + { "lsquo", 0x2018 }, { "lt", 0x003C }, + { "macr", 0x00AF }, { "mdash", 0x2014 }, + { "micro", 0x00B5 }, { "middot", 0x00B7 }, + { "minus", 0x2212 }, { "Mu", 0x039C }, + { "mu", 0x03BC }, { "nabla", 0x2207 }, + { "nbsp", 0x00A0 }, { "ndash", 0x2013 }, + { "ne", 0x2260 }, { "ni", 0x220B }, + { "not", 0x00AC }, { "notin", 0x2209 }, + { "nsub", 0x2284 }, { "Ntilde", 0x00D1 }, + { "ntilde", 0x00F1 }, { "Nu", 0x039D }, + { "nu", 0x03BD }, { "Oacute", 0x00D3 }, + { "oacute", 0x00F3 }, { "Ocirc", 0x00D4 }, + { "ocirc", 0x00F4 }, { "OElig", 0x0152 }, + { "oelig", 0x0153 }, { "Ograve", 0x00D2 }, + { "ograve", 0x00F2 }, { "oline", 0x203E }, + { "Omega", 0x03A9 }, { "omega", 0x03C9 }, + { "Omicron", 0x039F }, { "omicron", 0x03BF }, + { "oplus", 0x2295 }, { "or", 0x2228 }, + { "ordf", 0x00AA }, { "ordm", 0x00BA }, + { "Oslash", 0x00D8 }, { "oslash", 0x00F8 }, + { "Otilde", 0x00D5 }, { "otilde", 0x00F5 }, + { "otimes", 0x2297 }, { "Ouml", 0x00D6 }, + { "ouml", 0x00F6 }, { "para", 0x00B6 }, + { "part", 0x2202 }, { "permil", 0x2030 }, + { "perp", 0x22A5 }, { "Phi", 0x03A6 }, + { "phi", 0x03C6 }, { "Pi", 0x03A0 }, + { "pi", 0x03C0 }, { "piv", 0x03D6 }, + { "plusmn", 0x00B1 }, { "pound", 0x00A3 }, + { "Prime", 0x2033 }, { "prime", 0x2032 }, + { "prod", 0x220F }, { "prop", 0x221D }, + { "Psi", 0x03A8 }, { "psi", 0x03C8 }, + { "quot", 0x0022 }, { "radic", 0x221A }, + { "rang", 0x232A }, { "raquo", 0x00BB }, + { "rArr", 0x21D2 }, { "rarr", 0x2192 }, + { "rceil", 0x2309 }, { "rdquo", 0x201D }, + { "real", 0x211C }, { "reg", 0x00AE }, + { "rfloor", 0x230B }, { "Rho", 0x03A1 }, + { "rho", 0x03C1 }, { "rlm", 0x200F }, + { "rsaquo", 0x203A }, { "rsquo", 0x2019 }, + { "sbquo", 0x201A }, { "Scaron", 0x0160 }, + { "scaron", 0x0161 }, { "sdot", 0x22C5 }, + { "sect", 0x00A7 }, { "shy", 0x00AD }, + { "Sigma", 0x03A3 }, { "sigma", 0x03C3 }, + { "sigmaf", 0x03C2 }, { "sim", 0x223C }, + { "spades", 0x2660 }, { "sub", 0x2282 }, + { "sube", 0x2286 }, { "sum", 0x2211 }, + { "sup", 0x2283 }, { "sup1", 0x00B9 }, + { "sup2", 0x00B2 }, { "sup3", 0x00B3 }, + { "supe", 0x2287 }, { "szlig", 0x00DF }, + { "Tau", 0x03A4 }, { "tau", 0x03C4 }, + { "there4", 0x2234 }, { "Theta", 0x0398 }, + { "theta", 0x03B8 }, { "thetasym", 0x03D1 }, + { "thinsp", 0x2009 }, { "THORN", 0x00DE }, + { "thorn", 0x00FE }, { "tilde", 0x02DC }, + { "times", 0x00D7 }, { "trade", 0x2122 }, + { "Uacute", 0x00DA }, { "uacute", 0x00FA }, + { "uArr", 0x21D1 }, { "uarr", 0x2191 }, + { "Ucirc", 0x00DB }, { "ucirc", 0x00FB }, + { "Ugrave", 0x00D9 }, { "ugrave", 0x00F9 }, + { "uml", 0x00A8 }, { "upsih", 0x03D2 }, + { "Upsilon", 0x03A5 }, { "upsilon", 0x03C5 }, + { "Uuml", 0x00DC }, { "uuml", 0x00FC }, + { "weierp", 0x2118 }, { "Xi", 0x039E }, + { "xi", 0x03BE }, { "Yacute", 0x00DD }, + { "yacute", 0x00FD }, { "yen", 0x00A5 }, + { "Yuml", 0x0178 }, { "yuml", 0x00FF }, + { "Zeta", 0x0396 }, { "zeta", 0x03B6 }, + { "zwj", 0x200D }, { "zwnj", 0x200C }, + { NULL, '?' } + }; + int i; + + end = expand_string(ptr+1, " ;", len+str-ptr-1, + fillmore); + if(*end == ';') + *(end++) = 0; + + for(i = 0;val_tab[i].name;++i) + { + if(strncmp(val_tab[i].name, ptr+1, end-ptr-1) == 0) + break; + } + val = val_tab[i].val; + } + else + { + val = strtoul(ptr+2, &end, 0); + if(*end == ';') + ++end; + if(end == ptr+2) + val = '?'; + } + + if(val <= 0x7F) + { + if(val > 0) + *(ptr++) = val; + } + else if(val <= 0x7FF) + { + *(ptr++) = 0xC0 | (val>>6); + *(ptr++) = 0x80 | (val&0x3F); + } + else if(val <= 0xFFFF) + { + *(ptr++) = 0xE0 | (val>>12); + *(ptr++) = 0x80 | ((val>>6)&0x3F); + *(ptr++) = 0x80 | (val&0x3F); + } + else if(val <= 0x10FFFF) + { + *(ptr++) = 0xF0 | (val>>18); + *(ptr++) = 0x80 | ((val>>12)&0x3F); + *(ptr++) = 0x80 | ((val>>6)&0x3F); + *(ptr++) = 0x80 | (val&0x3F); + } + + if(end != ptr) + memmove(ptr, end, strlen(end)+1); + continue; + } + } + else if(*ptr == '"' || *ptr == '\'') + { + if(!in_quotes || in_quotes == *ptr) + { + in_quotes = *ptr ^ in_quotes; + memmove(ptr, ptr+1, strlen(ptr)); + continue; + } + } + else if(*ptr == '\\') + memmove(ptr, ptr+1, strlen(ptr)); + + if(*ptr) ++ptr; + } + + last_pos = ptr; + *(ptr++) = 0; + + use_hard_quotes = 0; + + /* Run a special command, replacing the section */ + if(*ptr == '(') + { + char *next = NULL; + char *opt; + + ++ptr; + + if(*ptr == '*') + { + use_hard_quotes = 1; + ++ptr; + } + + opt = expand_string(ptr, " )", len+str-ptr, fillmore); + if(!(*opt) || !isspace(*opt)) + { + *opt = 0; + printf("\n\n!!! %s error, line %d !!!\n" + "Malformed '%s' sub-command!\n\n", fname, + curr_line, ptr); + free(buf); + strcpy(linebuf, "exit -1\n"); + longjmp(jmpbuf, 1); + } + *(opt++) = 0; + while(isspace(*opt) && *opt) + ++opt; + + if(use_hard_quotes) + i = snprintf(buf, BUF_SIZE, "%s'", str); + else + i = snprintf(buf, BUF_SIZE, "%s", str); + + /* Replaces the section with the specified command line + * option's value (in the format 'option=value') */ + if(strcasecmp(ptr, "getoptval") == 0) + { + const char *val = ""; + int optlen, idx; + + next = expand_string(opt, ")", len+str-opt, fillmore); + if(*next) *(next++) = 0; + + optlen = strlen(opt); + for(idx = 1;idx < argc;++idx) + { + if(strncasecmp(opt, argv[idx], optlen) == 0) + { + if(argv[idx][optlen] == '=') + val = argv[idx]+optlen+1; + else if(argv[idx][optlen] == 0) + val = argv[idx+1]; + else + continue; + break; + } + } + snprintf(buf+i, BUF_SIZE-i, "%s", val); + } + + else if(strcasecmp(ptr, "word") == 0) + { + unsigned long val; + char *sep = expand_string(opt, ",)", len+str-opt, fillmore); + if(*sep != ',') + { + printf("\n\n!!! %s error, line %d !!!\n" + "Malformed '%s' sub-command!\n\n", fname, + curr_line, ptr); + free(buf); + strcpy(linebuf, "exit -1\n"); + longjmp(jmpbuf, 1); + } + *(sep++) = 0; + val = strtoul(opt, NULL, 0); + + opt = sep; + while(isspace(*opt)) + ++opt; + + while(1) + { + char *next_word = expand_string(opt, " )", len+str-opt, + fillmore); + --val; + if(isspace(*next_word) && *next_word) + { + *(next_word++) = 0; + while(isspace(*next_word) && *next_word) + ++next_word; + } + else + { + next = next_word; + if(*next) *(next++) = 0; + if(val == 0) + snprintf(buf+i, BUF_SIZE-i, "%s", opt); + break; + } + + if(val == 0) + { + snprintf(buf+i, BUF_SIZE-i, "%s", opt); + opt = next_word; + next = expand_string(opt, ")", len+str-opt, fillmore); + if(*next) *(next++) = 0; + break; + } + opt = next_word; + } + } + +/* else if(strcasecmp(ptr, "popfront") == 0) + { + char *front_word; + char *varstr; + + next = expand_string(opt, ")", len+str-opt, fillmore); + if(*next) *(next++) = 0; + + varstr = malloc(65536); + if(!varstr) + { + free(buf); + exit(-1); + } + strncpy(varstr, getvar(opt), 65536); + front_word = varstr; + while(*varstr && isspace(*varstr)) + ++varstr; + if(front_word != varstr) + memmove(front_word, varstr, strlen(varstr)+1); + + varstr = expand_string(front_word, " ", 65536, 0); + if(*varstr) *(varstr++) = 0; + while(*varstr && isspace(*varstr)) + ++varstr; + + snprintf(buf+i, BUF_SIZE-i, "%s", front_word); + setenv(opt, varstr, 1); + + free(front_word); + }*/ + + else if(strcasecmp(ptr, "add")==0 || strcasecmp(ptr, "sub") == 0 || + strcasecmp(ptr, "mult")==0 || strcasecmp(ptr, "div") == 0) + { + long val1, val2; + char *sep = expand_string(opt, ",)", len+str-opt, fillmore); + if(*sep != ',') + { + printf("\n\n!!! %s error, line %d !!!\n" + "Malformed '%s' sub-command!\n\n", fname, + curr_line, ptr); + free(buf); + strcpy(linebuf, "exit -1\n"); + longjmp(jmpbuf, 1); + } + *(sep++) = 0; + + next = expand_string(sep, ")", len+str-sep, fillmore); + if(*next) *(next++) = 0; + + val1 = atoi(opt); + val2 = atoi(sep); + + if(strcasecmp(ptr, "add") == 0) + val1 += val2; + else if(strcasecmp(ptr, "sub") == 0) + val1 -= val2; + else if(strcasecmp(ptr, "mult") == 0) + val1 *= val2; + else if(strcasecmp(ptr, "div") == 0) + { + if(!val2) + { + printf("\n\n!!! %s error, line %d !!!\n" + "Divide-by-0 attempted!\n\n", fname, + curr_line); + free(buf); + strcpy(linebuf, "exit -1\n"); + longjmp(jmpbuf, 1); + } + val1 /= val2; + } + + snprintf(buf+i, BUF_SIZE-i, "%ld", val1); + } + + /* Returns a library-style name from the specified + * filename */ + else if(strcasecmp(ptr, "libname") == 0) + { + next = expand_string(opt, ")", len+str-opt, fillmore); + if(*next) *(next++) = 0; + + libify_name(obj, sizeof(obj), opt); + snprintf(buf+i, BUF_SIZE-i, "%s", obj); + } + + /* Returns the full filename for the specified source file by + * searching src_path */ + else if(strcasecmp(ptr, "findsrc") == 0) + { + int inc = i; + int loop = 1; + + while(loop) + { + char *next_word = expand_string(opt, " )", len+str-opt, + fillmore); + if(isspace(*next_word) && *next_word) + { + *(next_word++) = 0; + while(isspace(*next_word) && *next_word) + ++next_word; + } + else + { + if(*next_word) *(next_word++) = 0; + loop = 0; + } + + inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ", + find_src(opt)); + + opt = next_word; + } + if(inc > i) buf[inc-1] = 0; + next = opt; + } + + /* Returns the string, lower-cased */ + else if(strcasecmp(ptr, "tolower") == 0) + { + int inc = i; + + next = expand_string(opt, ")", len+str-opt, fillmore); + if(*next) *(next++) = 0; + + snprintf(buf+i, BUF_SIZE-i, "%s", opt); + while(buf[inc]) + { + buf[inc] = tolower(buf[inc]); + ++inc; + } + } + + /* Returns the string, upper-cased */ + else if(strcasecmp(ptr, "toupper") == 0) + { + int inc = i; + + next = expand_string(opt, ")", len+str-opt, fillmore); + if(*next) *(next++) = 0; + + snprintf(buf+i, BUF_SIZE-i, "%s", opt); + while(buf[inc]) + { + buf[inc] = toupper(buf[inc]); + ++inc; + } + } + + + else if(strcasecmp("ifeq", ptr) == 0) + { + char *var2; + char *val; + + var2 = expand_string(opt, ",)", len+str-opt, fillmore); + if(*var2 != ',') + { + printf("\n\n!!! %s error, line %d !!!\n" + "Malformed 'ifeq' sub-command!\n\n", + fname, curr_line); + free(buf); + strcpy(linebuf, "exit -1\n"); + longjmp(jmpbuf, 1); + } + *(var2++) = 0; + val = expand_string(var2, ",)", len+str-var2, fillmore); + if(*val != ',') + { + printf("\n\n!!! %s error, line %d !!!\n" + "Malformed 'ifeq' sub-command!\n\n", + fname, curr_line); + free(buf); + strcpy(linebuf, "exit -1\n"); + longjmp(jmpbuf, 1); + } + *(val++) = 0; + if(strcmp(opt, var2) == 0) + { + char *sep = expand_string(val, ",)", len+str-val, + fillmore); + if(*sep) *(sep++) = 0; + next = expand_string(sep, ")", len+str-sep, fillmore); + if(*next) *(next++) = 0; + } + else + { + val = expand_string(val, ",)", len+str-val, fillmore); + if(*val == ',') ++val; + next = expand_string(val, ")", len+str-val, fillmore); + if(*next) *(next++) = 0; + } + + if(val) + snprintf(buf+i, BUF_SIZE-i, "%s", val); + } + + else if(strcasecmp("suffix", ptr) == 0) + { + char *val; + int inc = i; + int loop = 1; + + while(loop) + { + char *next_word = expand_string(opt, " )", len+str-opt, + fillmore); + if(isspace(*next_word) && *next_word) + { + *(next_word++) = 0; + while(isspace(*next_word) && *next_word) + ++next_word; + } + else + { + if(*next_word) *(next_word++) = 0; + loop = 0; + } + + val = strrchr(opt, '/'); + if(!val) + val = opt; + val = strrchr(val, '.'); + if(val) + inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ", val); + opt = next_word; + } + if(inc > i) buf[inc-1] = 0; + next = opt; + } + + else if(strcasecmp("basename", ptr) == 0) + { + char *val; + int inc = i; + int loop = 1; + + while(loop) + { + char *next_word = expand_string(opt, " )", len+str-opt, + fillmore); + if(isspace(*next_word) && *next_word) + { + *(next_word++) = 0; + while(isspace(*next_word) && *next_word) + ++next_word; + } + else + { + if(*next_word) *(next_word++) = 0; + loop = 0; + } + + val = strrchr(opt, '/'); + if(!val) + val = opt; + val = strrchr(val, '.'); + if(val) *val = 0; + inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ", opt); + + opt = next_word; + } + if(inc > i) buf[inc-1] = 0; + next = opt; + } + + + else if(strcasecmp("addprefix", ptr) == 0) + { + char *val; + int inc = i; + int loop = 1; + + val = opt; + opt = expand_string(opt, ",)", len+str-opt, fillmore); + if(*opt != ',') + { + printf("\n\n!!! %s error, line %d !!!\n" + "Malformed 'addprefix' sub-command!\n\n", + fname, curr_line); + free(buf); + strcpy(linebuf, "exit -1\n"); + longjmp(jmpbuf, 1); + } + *(opt++) = 0; + while(isspace(*opt) && *opt) + ++opt; + + while(loop) + { + char *next_word = expand_string(opt, " )", len+str-opt, + fillmore); + if(isspace(*next_word) && *next_word) + { + *(next_word++) = 0; + while(isspace(*next_word) && *next_word) + ++next_word; + } + else + { + if(*next_word) *(next_word++) = 0; + loop = 0; + } + + inc += snprintf(buf+inc, BUF_SIZE-inc, "%s%s ", val, + opt); + + opt = next_word; + } + if(inc > i) buf[inc-1] = 0; + next = opt; + } + + else if(strcasecmp("addsuffix", ptr) == 0) + { + char *val; + int inc = i; + int loop = 1; + + val = opt; + opt = expand_string(opt, ",)", len+str-opt, fillmore); + if(*opt != ',') + { + printf("\n\n!!! %s error, line %d !!!\n" + "Malformed 'addprefix' sub-command!\n\n", + fname, curr_line); + free(buf); + strcpy(linebuf, "exit -1\n"); + longjmp(jmpbuf, 1); + } + *(opt++) = 0; + while(isspace(*opt) && *opt) + ++opt; + + while(loop) + { + char *next_word = expand_string(opt, " )", len+str-opt, + fillmore); + if(isspace(*next_word) && *next_word) + { + *(next_word++) = 0; + while(isspace(*next_word) && *next_word) + ++next_word; + } + else + { + if(*next_word) *(next_word++) = 0; + loop = 0; + } + + inc += snprintf(buf+inc, BUF_SIZE-inc, "%s%s ", opt, + val); + + opt = next_word; + } + if(inc > i) buf[inc-1] = 0; + next = opt; + } + +/* else if(strcasecmp("join", ptr) == 0) + { + char *val; + int inc = i; + + val = opt; + opt = strchr(val, ','); + if(!opt) + { + printf("\n\n!!! %s error, line %d !!!\n" + "Malformed 'addprefix' sub-command!\n\n", + fname, curr_line); + free(buf); + strcpy(linebuf, "exit -1\n"); + longjmp(jmpbuf, 1); + } + *(opt++) = 0; + while(isspace(*opt) && *opt) + ++opt; + + while(*opt || *val) + { + char *next_word = grab_word(&opt, NULL); + char *next_word2 = grab_word(&val, NULL); + + inc += snprintf(buf+inc, BUF_SIZE-inc, "%s%s ", val, + opt); + + opt = next_word; + val = next_word2; + } + if(inc > i) buf[inc-1] = 0; + + next = expand_string(opt, ")", len+str-opt, fillmore); + if(*next) *(next++) = 0; + }*/ + + else if(strcasecmp("dir", ptr) == 0) + { + char *val; + int inc = i; + int loop = 1; + + while(loop) + { + char *next_word = expand_string(opt, " )", len+str-opt, + fillmore); + if(isspace(*next_word) && *next_word) + { + *(next_word++) = 0; + while(isspace(*next_word) && *next_word) + ++next_word; + } + else + { + if(*next_word) *(next_word++) = 0; + loop = 0; + } + + val = strrchr(opt, '/'); + if(val) + { + val[1] = 0; + inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ", opt); + } + else + inc += snprintf(buf+inc, BUF_SIZE-inc, "./ "); + + opt = next_word; + } + if(inc > i) buf[inc-1] = 0; + next = opt; + } + + else if(strcasecmp("notdir", ptr) == 0) + { + char *val; + int inc = i; + int loop = 1; + + while(loop) + { + char *next_word = expand_string(opt, " )", len+str-opt, + fillmore); + if(isspace(*next_word) && *next_word) + { + *(next_word++) = 0; + while(isspace(*next_word) && *next_word) + ++next_word; + } + else + { + if(*next_word) *(next_word++) = 0; + loop = 0; + } + + val = strrchr(opt, '/'); + if(!val) + val = opt; + else + ++val; + opt = next_word; + if(val[0]) + inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ", val); + } + if(inc > i) buf[inc-1] = 0; + next = opt; + } + + /* Finds an executable command by searching the PATH and + returns the full absolute path plus the filename, or an + empty string if it can't be found */ + else if(strcasecmp(ptr, "which") == 0) + { + char *path = strdup(getvar("PATH")); + char *direc; + char sep = ':'; + + next = expand_string(opt, ")", len+str-opt, fillmore); + if(*next) *(next++) = 0; + + if(strchr(path, ';') != NULL || (tolower(path[0]) >= 'a' && + tolower(path[0]) <= 'z' && + path[1] == ':')) + sep = ';'; + + + if(*opt) + { + direc = path; + while(direc && *direc) + { + struct stat statbuf; + char *slash; + char *next = strchr(direc, sep); + if(next) *(next++) = 0; + + snprintf(buf+i, BUF_SIZE-i, "%s/%s", direc, opt); + while((slash=strchr(buf+i, '\\')) != NULL) + *slash = '/'; + if(stat(buf+i, &statbuf) == 0) + break; + buf[i] = 0; + + direc = next; + } + } + + free(path); + } + + else if(strcasecmp("ls", ptr) == 0 || strcasecmp("lsa", ptr) == 0) + { + struct stat st; + int inc = i; + int show_hidden = 0; + int loop = 1; + + if(strcasecmp("lsa", ptr) == 0) + show_hidden = 1; + + while(loop) + { + DIR *dp; + char *next_word = expand_string(opt, " )", len+str-opt, + fillmore); + if(isspace(*next_word) && *next_word) + { + *(next_word++) = 0; + while(isspace(*next_word) && *next_word) + ++next_word; + } + else + { + if(*next_word) *(next_word++) = 0; + loop = 0; + } + + dp = opendir(opt); + if(dp) + { + struct dirent *ent; + char *slash = strrchr(opt, '/'); + if(slash && !slash[1]) *slash = 0; + + while((ent=readdir(dp)) != NULL) + { + int i; + + if(!show_hidden && ent->d_name[0] == '.') + continue; + + i = snprintf(buf+inc, BUF_SIZE-inc, "%s/%s", + opt, ent->d_name); + + if(stat(buf+inc, &st) == 0 && + S_ISDIR(st.st_mode)) + i += snprintf(buf+inc+i, BUF_SIZE-inc-i, + "/ "); + else + i += snprintf(buf+inc+i, BUF_SIZE-inc-i, + " "); + inc += i; + } + closedir(dp); + } + else + { + if(show_hidden || opt[0] != '.') + { + if(stat(opt, &st) == 0) + inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ", + opt); + } + } + opt = next_word; + } + if(inc > i) buf[inc-1] = 0; + next = opt; + } + + else + { + printf("\n\n!!! %s error, line %d !!!\n" + "Unknown sub-command '%s'\n\n", fname, curr_line, ptr); + free(buf); + strcpy(linebuf, "exit -1\n"); + longjmp(jmpbuf, 1); + } + + end = next; + } + else + { + /* Insert the named environment var (in the form $FOO or ${FOO}) */ + if(*ptr == '{') + { + ++ptr; + + if(*ptr == '\'') + { + use_hard_quotes = 1; + ++ptr; + end = "'}"; + } + else + end = "}"; + + end = expand_string(ptr, end, len+str-ptr, fillmore); + if(*end == '\'') + { + *(end++) = 0; + end = expand_string(end, "}", len+str-ptr, fillmore); + } + if(*end) + *(end++) = 0; + } + else + end = expand_string(ptr, "^", len+str-ptr, fillmore); + + if(use_hard_quotes) + i = snprintf(buf, BUF_SIZE, "%s'", str); + else + i = snprintf(buf, BUF_SIZE, "%s", str); + + if(*ptr >= '0' && *ptr <= '9') + { + const char *val = ""; + int idx = atoi(ptr); + if(idx < argc && idx >= 0) + val = argv[idx]; + snprintf(buf+i, BUF_SIZE-i, "%s", val); + } + else if(strncmp("*", ptr, end-ptr) == 0 || + (use_hard_quotes && strncmp("@", ptr, end-ptr) == 0)) + { + int idx = 1; + int inc = i; + while(idx < argc) + { + inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ", argv[idx]); + ++idx; + } + if(inc > i) buf[inc-1] = 0; + } + else if(strncmp("@", ptr, end-ptr) == 0) + { + int idx = 1; + while(idx < argc) + { + i += snprintf(buf+i, BUF_SIZE-i, "${'%d'}", idx); + + ++idx; + if(idx < argc) + i += snprintf(buf+i, BUF_SIZE-i, " "); + } + snprintf(buf+i, BUF_SIZE-i, "%s", end); + strcpy(str, buf); + continue; + } + else + { + char c = *end; + *end = 0; + snprintf(buf+i, BUF_SIZE-i, "%s", getvar(ptr)); + *end = c; + } + } + + while(buf[i]) + { + if(buf[i] == '&' || buf[i] == '\'' || buf[i] == '"' || + buf[i] == '\\') + { + memmove(buf+i+1, buf+i, BUF_SIZE-i-1); + buf[i] = '\\'; + ++i; + } + ++i; + } + + if(use_hard_quotes) + snprintf(buf+i, BUF_SIZE-i, "'%s", end); + else + snprintf(buf+i, BUF_SIZE-i, "%s", end); + strcpy(str, buf); + } while(1); +} + + +/* extract_word: Extract a word starting at the string pointed to by 'str'. If + * the word begins with a ' or " character, everything until that same + * character will be considered part of the word. Otherwise, the word ends at + * the first encountered whitespace. Returns the beginning of the next word, + * or the end of the string. + */ +static char *extract_word(char *str, size_t len) +{ + char *end = str; + + if(!(*end)) + return end; + + end = expand_string(end, " \n", len+str-end, 1); + + if(*end && *end != '\n') + *(end++) = 0; + + while(*end && isspace(*end)) + { + if(*end == '\n') + { + if(end[1] != 0) + nextline = strdup(end+1); + *end = 0; + break; + } + ++end; + } + + return end; +} + + +static void extract_line(char *str, size_t len) +{ + char *end = str; + + if(!(*end)) + return; + + end = expand_string(end, "\n", len+str-end, 1); + + if(end[0] == '\n' && end[1] != 0) + nextline = strdup(end+1); + *end = 0; +} + + /* check_obj_deps: Checks a file's dependancy list. The dependancy file is a * file expected to be in dep_dir and with the same name, but with a different - * extension. The format of the file is simply: 'file.o: dependancies...' where - * a '\' at the end of the line can be used as a next-line continuation. If the + * extension. The format of the file is simply: 'file.o: dependancy list...'. A + * '\' at the end of the line can be used as a next-line continuation. If the * dependancy file exists, none of the dependancies are missing, and none have * a modification time after 'obj_time', the function will return 0. Otherwise * 1 is returned denoting a rebuild may be required. */ -static int check_obj_deps(char *src, time_t obj_time) +static int check_obj_deps(char *base, char *src, time_t obj_time) { - static char dep[64]; + static char dep[PATH_MAX]; char *buf; int bufsize; struct stat statbuf; char *ptr = obj; FILE *df; - size_t i; - ptr = strrchr(src, '/'); - if(!ptr) ptr = src; + ptr = strrchr(base, '/'); + if(!ptr) ptr = base; ptr = strrchr(ptr, '.'); if(ptr) *ptr = 0; - snprintf(dep, sizeof(dep), "%s/%s%s", getvar("DEP_DIR"), src, - getvar("DEP_EXT")); + snprintf(dep, sizeof(dep), "${DEP_DIR}/'%s'${DEP_EXT}", base); + expand_string(dep, "", sizeof(dep), 0); if(ptr) *ptr = '.'; df = fopen(dep, "r"); if(!df) { - if(stat(src, &statbuf) != 0 || statbuf.st_mtime > obj_time) + if(stat(src, &statbuf) != 0 || statbuf.st_mtime-obj_time > 0) return 1; return 0; } @@ -146,15 +1488,10 @@ static int check_obj_deps(char *src, time_t obj_time) fclose(df); return 1; } - fseek(df, 0, SEEK_SET); - i = 0; - while(fgets(buf+i, bufsize-i, df) != NULL) - { - i = strlen(buf); - if(buf[i-1] != '\\') - break; - } + fseek(df, 0, SEEK_SET); + fread(buf, 1, bufsize, df); + buf[bufsize-1] = 0; fclose(df); @@ -164,33 +1501,24 @@ static int check_obj_deps(char *src, time_t obj_time) free(buf); return 1; } - ++ptr; - while(1) - { - char *stp; - while(*ptr && isspace(*ptr)) - { - if(*ptr == '\n') - { - free(buf); - return 0; - } - ++ptr; - } - if(!(*ptr)) - { - free(buf); - return 0; - } - stp = ptr; + ++ptr; + while(*ptr && *ptr != '\n' && isspace(*ptr)) + ++ptr; + + while(*ptr) + { + char *stp = ptr; + while(*stp && !isspace(*stp)) { if(*stp == '\\') memmove(stp, stp+1, strlen(stp)); - ++stp; + if(*stp) ++stp; } - *(stp++) = 0; + if(*stp) *(stp++) = 0; + while(*stp && isspace(*stp)) + ++stp; if(strcmp(ptr, "\n") != 0 && (stat(ptr, &statbuf) != 0 || statbuf.st_mtime > obj_time)) @@ -198,11 +1526,42 @@ static int check_obj_deps(char *src, time_t obj_time) free(buf); return 1; } + ptr = stp; } + free(buf); + + buf = (char*)getvar("EXTRA_SRC_DEPS"); + if(*buf) + { + char *ptr = malloc(BUF_SIZE); + strncpy(ptr, buf, BUF_SIZE); + buf = ptr; + + while(*ptr) + { + char *next = expand_string(ptr, " ", BUF_SIZE+ptr-buf, 0); + if(*next) *(next++) = 0; + while(*next && isspace(*next)) + ++next; + + if(strcmp(ptr, "\n") != 0 && (stat(ptr, &statbuf) != 0 || + statbuf.st_mtime > obj_time)) + { + free(buf); + return 1; + } + + ptr = next; + } + + free(buf); + } + + return 0; } -/* copy_file: Copies the source file 'sf' to 'df', preserving the source's +/* copy_file: Copies the source file 'sf' to 'df', preserving the source's * file mode and permissions, if possible. */ static int copy_file(const char *sf, const char *df) @@ -215,7 +1574,11 @@ static int copy_file(const char *sf, const char *df) if(stat(sf, &statbuf) != 0) return 1; +#ifdef O_BINARY + fd = open(df, O_WRONLY|O_BINARY|O_TRUNC|O_CREAT, statbuf.st_mode); +#else fd = open(df, O_WRONLY|O_TRUNC|O_CREAT, statbuf.st_mode); +#endif if(fd < 0) return 1; dst = fdopen(fd, "wb"); @@ -246,40 +1609,115 @@ static int copy_file(const char *sf, const char *df) return ret; } -/* extract_word: Extract a word starting at the string pointed to by 'str'. If - * the word begins with a ' or " character, everything until that same - * character will be considered part of the word. Otherwise, the word ends at - * the first encountered whitespace. Returns the beginning of the next word, - * or the end of the string. - */ -static char *extract_word(char **str) -{ - char *end; - char c; - c = **str; - if(c == '"' || c == '\'') +static int libify_name(char *buf, size_t buflen, char *name) +{ + int i; + char *curr = strrchr(name, '/'); + if(curr) { - ++(*str); - end = *str; - while(*end) - { - if(*end == c) - break; - ++end; - } + *curr = 0; + i = snprintf(buf, buflen, "'%s'/${LIB_PRE}'%s'${LIB_EXT}", name, + curr+1); + *curr = '/'; } else - { - end = *str; - while(!isspace(*end) && *end) - ++end; - } - if(*end) *(end++) = 0; - while(isspace(*end) && *end) - ++end; + i = snprintf(buf, buflen, "${LIB_PRE}'%s'${LIB_EXT}", name); + expand_string(buf, "", buflen, 0); + return i; +} - return end; + +static struct { + char *ext; + char *cmd; +} *associations; +static size_t num_assocs; + +static void add_association(const char *ext, const char *cmd) +{ + size_t i; + for(i = 0;i < num_assocs;++i) + { + if(associations[i].cmd[0] == 0 || + strcasecmp(ext, associations[i].ext) == 0) + break; + } + if(i == num_assocs) + { + void *tmp = realloc(associations, (i+1)*sizeof(*associations)); + if(!tmp) + { + strcpy(linebuf, "exit -1\n"); + longjmp(jmpbuf, 1); + } + + associations = tmp; + associations[i].ext = NULL; + associations[i].cmd = NULL; + + ++num_assocs; + } + free(associations[i].ext); + free(associations[i].cmd); + associations[i].ext = strdup(ext); + associations[i].cmd = strdup(cmd); + if(!associations[i].ext || !associations[i].cmd) + { + strcpy(linebuf, "exit -1\n"); + longjmp(jmpbuf, 1); + } +} + +static int build_command(char *buffer, size_t bufsize, char *barename, + const char *srcname, const char *objname) +{ + char dummy[2] = "."; + const char *ptr; + char *ext; + size_t i; + + ext = strrchr(barename, '.'); + if(strchr(ext, '/') || !ext) + ext = dummy; + + for(i = 0;i < num_assocs;++i) + { + if(strcasecmp(ext+1, associations[i].ext) == 0) + break; + } + if(i == num_assocs) + return 1; + + *ext = 0; + ptr = associations[i].cmd; + while(*ptr && i+1 < bufsize) + { + if(strncasecmp(ptr, "<*>", 3) == 0) + { + i += snprintf(buffer+i, bufsize-i, "'%s'", barename); + ptr += 3; + } + else if(strncasecmp(ptr, "", 3) == 0) + { + i += snprintf(buffer+i, bufsize-i, "\\\"'%s'\\\"", srcname); + ptr += 3; + } + else if(strncasecmp(ptr, "<@>", 3) == 0) + { + i += snprintf(buffer+i, bufsize-i, "\\\"'%s'\\\"", objname); + ptr += 3; + } + else + { + if(ptr[0] == '\\' && ptr[1] != 0 && i+2 < bufsize) + buffer[i++] = *(ptr++); + buffer[i++] = *(ptr++); + buffer[i] = 0; + } + } + *ext = '.'; + return 0; } @@ -290,7 +1728,7 @@ static char *extract_word(char **str) static int build_obj_list(char *buffer, size_t bufsize, time_t base_time, int *do_link) { - static char buf[64]; + static char buf[PATH_MAX]; struct stat statbuf; char *next = sources; @@ -300,30 +1738,27 @@ static int build_obj_list(char *buffer, size_t bufsize, time_t base_time, while(*(ptr=next)) { char *ext; - char c = ' '; + char c; - next = extract_word(&ptr); - if(ptr > sources) - { - c = *(ptr-1); - if(c != '"' && c != '\'') - c = ' '; - } + next = grab_word(&ptr, &c); ext = strrchr(ptr, '/'); if(!ext) ext = ptr; ext = strrchr(ext, '.'); if(ext) *ext = 0; - snprintf(buf, sizeof(buf), "%s/%s%s", getvar("OBJ_DIR"), ptr, - getvar("OBJ_EXT")); + snprintf(buf, sizeof(buf), "${OBJ_DIR}/'%s'${OBJ_EXT}", ptr); + expand_string(buf, "", sizeof(buf), 0); if(ext) *ext = '.'; if(!(*do_link) && (stat(buf, &statbuf) != 0 || base_time < statbuf.st_mtime)) *do_link = 1; - i += snprintf(buffer+i, bufsize-i, " \"%s\"", buf); + if(ext) *ext = 0; + i += snprintf(buffer+i, bufsize-i, + " \\\"${OBJ_DIR}/'%s'${OBJ_EXT}\\\"", ptr); + if(ext) *ext = '.'; ptr += strlen(ptr); if(next > ptr) @@ -332,53 +1767,82 @@ static int build_obj_list(char *buffer, size_t bufsize, time_t base_time, return i; } -static int libify_name(char *buf, size_t buflen, char *name) + +static struct { + char *name; + char *val; +} *defines; +static size_t num_defines; + +#define MAX_CMD_ARGC 32 +static char *cmd_argv[MAX_CMD_ARGC+1]; +static size_t cmd_argc; + + +void cleanup(void) { + size_t i; + + fflush(stdout); + + for(i = 0;i < cmd_argc;++i) + { + free(cmd_argv[i]); + cmd_argv[i] = NULL; + } + cmd_argc = 0; + + for(i = 0;i < num_defines;++i) + { + free(defines[i].name); + free(defines[i].val); + } + free(defines); + defines = NULL; + + i = 0; + while(i < SRC_PATH_SIZE && src_paths[i]) + free(src_paths[i++]); + i = 0; + while(i < INVOKE_BKP_SIZE && invoke_backup[i].f) + { + fclose(invoke_backup[i].f); + free(invoke_backup[i].fname); + free(invoke_backup[i].bkp_lbuf); + free(invoke_backup[i].bkp_nextline); + ++i; + } + for(i = 0;i < num_assocs;++i) + { + free(associations[i].ext); + free(associations[i].cmd); + } + free(associations); + free(loaded_files); + free(nextline); + free(sources); + free(fname); + if(f) + fclose(f); + if(infile && infile != stdin) + fclose(infile); +} + + +unsigned int do_level = 0; +unsigned int did_cmds = 0, did_else = 0; +unsigned int wait_for_done = 0; +int ret = 0, tmp = 0; +int ignored_errors = 0; +int verbose = 0; +int shh = 0; +int ignore_err = 0; +int has_do = 0; + +int main(int _argc, char **_argv) +{ + char *ptr; int i; - char *curr = strrchr(name, '/'); - if(curr) - { - *curr = 0; - i = snprintf(buf, buflen, "%s/%s%s%s", name, getvar("LIB_PRE"), - curr+1, getvar("LIB_EXT")); - *curr = '/'; - } - else - i = snprintf(buf, buflen, "%s%s%s", getvar("LIB_PRE"), name, - getvar("LIB_EXT")); - return i; -} - - -static char *strrpbrk(char *str, char *brk, int len) -{ - char *ptr = str+len; - - while((--ptr) >= str) - { - char *c = brk; - while(*c) - { - if(*(c++) == *ptr) - return ptr; - } - } - - return NULL; -} - - -int main(int argc, char **argv) -{ - FILE *f; - int do_level = 0, wait_for_done = 0; - int did_cmds = 0, did_else = 0; - int curr_line = 0; - char *ptr, *nextline = NULL, *nextcmd = NULL; - int ret = 0, tmp = 0, i; - int ignored_errors = 0; - int verbose = 0; - int shh; setenv("CC", "gcc", 0); setenv("CXX", "g++", 0); @@ -390,7 +1854,7 @@ int main(int argc, char **argv) setenv("OBJ_DIR", ".", 0); setenv("DEP_EXT", ".d", 0); setenv("DEP_DIR", ".", 0); -#ifdef _WIN32 +#if (defined __WIN32__ || defined __DOS__) setenv("EXE_EXT", ".exe", 0); #else setenv("EXE_EXT", "", 0); @@ -405,35 +1869,40 @@ int main(int argc, char **argv) setenv("LDFLAGS", "", 0); /* Open the default file */ - f = fopen("default.cbd", "r"); + fname = strdup("default.cbd"); + f = fopen(fname, "r"); if(!f) { fprintf(stderr, "\n\n\n*** Critical Error ***\n" - "Could not open 'default.cbd'!\n\n"); + "Could not open default.cbd!\n\n"); exit(1); } + argc = _argc; + argv = _argv; + infile = stdin; + + atexit(cleanup); + + if(setjmp(jmpbuf)) + { + free(nextline); + nextline = NULL; + goto reparse; + } + main_loop_start: while(1) { - int line_count, len; - int ignore_err = 0; - int in_quote = 0; - int has_do = 0; int reverse; + ignore_err = 0; + has_do = 0; - /* If we already have the next line set, go do it */ - if(nextcmd) - { - memmove(linebuf, nextcmd, strlen(nextcmd)+1); - nextcmd = NULL; - goto reparse; - } - - /* If we already have the next line set, go do it */ if(nextline) { - memmove(linebuf, nextline, strlen(nextline)+1); + /* If we already have the next line set, go do it */ + strncpy(linebuf, nextline, strlen(nextline)+1); + free(nextline); nextline = NULL; goto reparse; } @@ -441,349 +1910,16 @@ main_loop_start: /* Grab the next line and increment the line count */ if(fgets(linebuf, sizeof(linebuf), f) == NULL) { - if(!invoke_backup[0].f) - break; - /* If end of file, check if we should uninvoke and continue */ - for(i = 1;i <= INVOKE_BKP_SIZE;++i) - { - if(i == INVOKE_BKP_SIZE || !invoke_backup[i].f) - { - --i; - fclose(f); - f = invoke_backup[i].f; - invoke_backup[i].f = NULL; - - strcpy(linebuf, invoke_backup[i].bkp_lbuf); - free(invoke_backup[i].bkp_lbuf); - - if(invoke_backup[i].bkp_nextline) - { - nextline = linebuf+strlen(linebuf)+1; - strcpy(nextline, invoke_backup[i].bkp_nextline); - free(invoke_backup[i].bkp_nextline); - } - - curr_line = invoke_backup[i].bkp_line; - did_else = invoke_backup[i].bkp_did_else; - did_cmds = invoke_backup[i].bkp_did_cmds; - do_level = invoke_backup[i].bkp_do_level; - - goto main_loop_start; - } - } - break; + snprintf(linebuf, sizeof(linebuf), "uninvoke 0\n"); + goto reparse; } ++curr_line; - line_count = 0; - ptr = linebuf; - do { - while((ptr=strpbrk(ptr, "$'\"#")) != NULL) - { - /* Enter in-quote mode (disables ''-quoting and #-comments) */ - if(*ptr == '\"') - { - in_quote ^= 1; - ++ptr; - continue; - } - - /* A '#' kills the rest of the line */ - if(*ptr == '#' && !in_quote) - { - char *next = strchr(ptr, '\n'); - if(next) - memmove(ptr, next, strlen(next)+1); - else - *ptr = 0; - continue; - } - - /* Jump past a hard quote (don't expand anything) */ - if(*ptr == '\'' && !in_quote) - { - int add_count = 0; - char *next = strchr(ptr+1, '\''); - /* Find the closing '. If it's not found, assume it's a - * multi-line quote */ - while(!next) - { - next = ptr+strlen(ptr); - if(sizeof(linebuf) == next-linebuf) - { - printf("!!! Error, line %d !!!\n" - "Unterminated hard quote!", curr_line); - ret = -1; - goto end; - } - - if(fgets(next, sizeof(linebuf)-(next-linebuf), f) == - NULL) - break; - next = strchr(ptr+1, '\''); - ++add_count; - } - ptr = next; - curr_line += add_count; - ++ptr; - continue; - } - - /* Apend the next line to this one */ - if(strcmp(ptr, "$\n") == 0) - { - ptr += 2; - if(fgets(ptr, sizeof(linebuf)-(ptr-linebuf), f) == NULL) - break; - ++curr_line; - continue; - } - - ++ptr; - } - if(!in_quote) - break; - ptr = linebuf+strlen(linebuf); - if(fgets(ptr, sizeof(linebuf)-(ptr-linebuf), f) == NULL) - { - printf("!!! Error, line %d !!!\n" - "Unterminated quote!", curr_line); - ret = -1; - goto end; - } - ++line_count; - } while(1); - curr_line += line_count; - - /* Check for the special '$' char, expanding variables as needed */ - do { - len = strlen(linebuf); - in_quote = 0; - tmp = 0; - ptr = linebuf; - - while((ptr=strrpbrk(linebuf, "$'\"", len)) != NULL) - { - len = ptr-linebuf; - - /* Enter in-quote mode (disables ''-quoting and #-comments) */ - if(*ptr == '\"') - { - in_quote ^= 1; - continue; - } - - /* A '#' kills the rest of the line */ - if(*ptr == '#' && !in_quote) - { - char *next = strchr(ptr, '\n'); - if(next) - memmove(ptr, next, strlen(next)+1); - else - *ptr = 0; - continue; - } - - /* Jump past a hard quote (don't expand anything) */ - if(*ptr == '\'' && !in_quote) - { - char *next; - - *ptr = 0; - next = strrchr(linebuf, '\''); - if(!next) - { - printf("!!! Error, line %d !!!\n" - "Unterminated hard quote!", curr_line); - ret = -1; - goto end; - } - *ptr = '\''; - - len = next-linebuf; - continue; - } - - ++ptr; - - /* Insert the environment var named between the {} */ - if(*ptr == '{') - { - char *end = strchr(ptr, '}'); - if(!end) - end = ptr+strlen(ptr); - else - *(end++) = 0; - *(--ptr) = 0; - snprintf(buffer, sizeof(buffer), "%s%s%s", linebuf, - getvar(ptr+2), end); - strcpy(linebuf, buffer); - tmp = 1; - continue; - } - - /* Run a special command, replacing the section */ - if(*ptr == '(') - { - char *next = strchr(ptr, ')'), *opt; - if(!next) - continue; - - tmp = 1; - *(ptr-1) = 0; - *(next++) = 0; - - ++ptr; - opt = extract_word(&ptr); - - /* Replaces the section with the specified command line - * option's value (in the format 'option=value') */ - if(strcasecmp(ptr, "getoptval") == 0) - { - const char *val = ""; - int len; - len = snprintf(buffer, sizeof(buffer), "%s=", opt); - for(i = 1;i < argc;++i) - { - if(strncasecmp(buffer, argv[i], len) == 0) - { - val = argv[i]+len; - break; - } - } - snprintf(buffer, sizeof(buffer), "%s%s%s", linebuf, - val, next); - strcpy(linebuf, buffer); - continue; - } - - /* Returns a library-style name from the specified - * filename */ - if(strcasecmp(ptr, "libname") == 0) - { - libify_name(obj, sizeof(obj), opt); - snprintf(buffer, sizeof(buffer), "%s%s%s", linebuf, - obj, next); - strcpy(linebuf, buffer); - continue; - } - - if(strcasecmp("ifeq", ptr) == 0) - { - char *var2; - char *val; - - var2 = strchr(opt, ','); - if(!var2) - { - printf("\n\n!!! Error, line %d !!!\n" - "Malformed 'ifeq' sub-command!\n\n", - curr_line); - ret = 1; - goto end; - } - *(var2++) = 0; - val = strchr(var2, ','); - if(!val) - { - printf("\n\n!!! Error, line %d !!!\n" - "Malformed 'ifeq' sub-command!\n\n", - curr_line); - ret = 1; - goto end; - } - *(val++) = 0; - if(strcmp(opt, var2) == 0) - { - char *sep = strchr(val, ','); - if(sep) *sep = 0; - } - else - { - val = strchr(val, ','); - if(val) ++val; - } - - snprintf(buffer, sizeof(buffer), "%s%s%s", linebuf, - (val?val:""), next); - strcpy(linebuf, buffer); - continue; - } - - printf("\n\n!!! Error, line %d !!!\n" - "Unknown sub-command '%s'\n\n", curr_line, ptr); - goto end; - } - } - } while(tmp); - - /* Now check for '$'-escapes */ - ptr = linebuf; - while((ptr=strpbrk(ptr, "$'\"")) != NULL) - { - if(*ptr == '"') - { - ptr = strchr(ptr+1, '"'); - if(!ptr) - break; - continue; - } - - if(*ptr == '\'' && !in_quote) - { - ptr = strchr(ptr+1, '\''); - if(!ptr) - break; - continue; - } - - ++ptr; - - /* Just a normal "escaped" character, pull the rest of the line - * back one. '$\n' will be handled later */ - if(*ptr != '\n') - memmove(ptr-1, ptr, strlen(ptr)+1); - else - ++ptr; - } - reparse: reverse = 0; shh = 0; - /* Get the next line */ - if(!nextline) - { - int in_quotes = 0; - - nextline = linebuf; - while(*nextline && *nextline != '\n') - { - if(*nextline == '"') - in_quotes ^= 1; - if(!in_quotes) - { - if(*nextline == '\'') - { - nextline = strchr(nextline+1, '\''); - if(!nextline) - break; - } - if(nextline[0] == '$' && nextline[1] == '\n') - memmove(nextline, nextline+1, strlen(nextline)); - } - ++nextline; - } - if(nextline) - { - if(*nextline) - *(nextline++) = 0; - if(!(*nextline)) - nextline = NULL; - } - } - /* Chew up leading whitespace */ for(i = 0;linebuf[i];++i) { @@ -800,28 +1936,45 @@ reparse: if(!linebuf[i]) continue; - /* Find the end of the command name */ - ptr = linebuf; - while(*ptr && !isspace(*ptr)) - ++ptr; + ptr = expand_string(linebuf, " =\n", sizeof(linebuf), 1); + if(isspace(linebuf[0])) + goto reparse; - if(*ptr) + if(!linebuf[0] || ptr == linebuf || linebuf[0] == ':') { - /* If found, NULL it and get the beginning of the option */ - tmp = *ptr; - *(ptr++) = 0; - while(isspace(*ptr) && *ptr) - ++ptr; + extract_line(linebuf, sizeof(linebuf)); + continue; } - /* Check for special 'level'ing commands */ + while(*ptr && isspace(*ptr)) + { + if(*ptr == '\n') + { + *ptr = 0; + if(ptr[1] != 0) + nextline = strdup(ptr+1); + break; + } + *(ptr++) = 0; + } + + /* Check for special 'leveling' commands */ + /* The 'do' command pushes us up a level, and checks for the next * if-type command, which itself will let us know if we should start * ignoring commands */ if(strcasecmp("do", linebuf) == 0) { - has_do = 1; ++do_level; + if(do_level >= sizeof(int)*8) + { + printf("\n\n!!! %s error, line %d !!!\n" + "Too many 'do' commands enountered (max: %ud)!\n\n", + fname, curr_line, sizeof(int)*8 - 1); + snprintf(linebuf, sizeof(linebuf), "exit -1\n"); + goto reparse; + } + has_do = 1; memmove(linebuf, ptr, strlen(ptr)+1); goto reparse; } @@ -829,15 +1982,10 @@ reparse: if(strcasecmp("else", linebuf) == 0) { if(do_level <= 0) - { - fprintf(stderr, "\n\n!!! Error, line %d !!!\n" - "'else' statement encountered without 'do'!\n", - curr_line); - goto end; - } + do_level = 1; - /* TODO: allow another if-type command to follow an else on the - * same level */ + /* allow another if-type command to follow an else on the same + * level */ if(!(wait_for_done & (1<<(do_level-1)))) { wait_for_done |= 1<<(do_level-1); @@ -857,51 +2005,420 @@ reparse: /* 'done' takes us down a level */ if(strcasecmp("done", linebuf) == 0) { - if(do_level <= 0) + if(do_level > 0) { - fprintf(stderr, "\n\n!!! Error, line %d !!!\n" - "'done' statement encountered without 'do'!\n", - curr_line); - goto end; + wait_for_done &= ~(1<<(--do_level)); + did_else &= ~(1< 300) + else if(strcasecmp("i386", ptr) == 0) + pass = 1; +#endif +#if defined(__ia64__) || defined(_M_IA64) + else if(strcasecmp("ia64", ptr) == 0) + pass = 1; +#endif +#if defined(__powerpc__) || defined(_M_PPC) + else if(strcasecmp("powerpc", ptr) == 0) + pass = 1; +#endif +#if defined(__sparc__) || defined(__sparc) + else if(strcasecmp("sparc", ptr) == 0) + pass = 1; +#endif + + if((pass != 0) != !!reverse) + { + memmove(linebuf, next, strlen(next)+1); + goto reparse; + } + + if(has_do) + wait_for_done |= 1 << (do_level-1); + extract_line(next, sizeof(linebuf)+linebuf-next); + continue; + } + if(strcasecmp("ifnplat", linebuf) == 0) + { + reverse = 1; + goto platform_check; + } + + /* Checks if the supplied option name was specified on the command + * line */ + if(strcasecmp("ifopt", linebuf) == 0) +option_check: + { + char *next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); + int pass = 0; + + for(i = 1;i < argc;++i) + { + size_t len = strlen(ptr); + char *eq = strrchr(argv[i], '='); + + if(eq && (size_t)(eq-argv[i]) != len) + continue; + + if(strncasecmp(ptr, argv[i], len) == 0) + { + pass = 1; + break; + } + } + + if((pass != 0) != !!reverse) + { + memmove(linebuf, next, strlen(next)+1); + goto reparse; + } + + if(has_do) + wait_for_done |= 1 << (do_level-1); + extract_line(next, sizeof(linebuf)+linebuf-next); + continue; + } + if(strcasecmp("ifnopt", linebuf) == 0) + { + reverse = 1; + goto option_check; + } + + /* Checks if a file or directory exists */ + if(strcasecmp("ifexist", linebuf) == 0) +file_dir_check: + { + struct stat statbuf; + char *next; + + next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); + if((stat(ptr, &statbuf) == 0) != !!reverse) + { + memmove(linebuf, next, strlen(next)+1); + goto reparse; + } + + if(has_do) + wait_for_done |= 1 << (do_level-1); + extract_line(next, sizeof(linebuf)+linebuf-next); + continue; + } + if(strcasecmp("ifnexist", linebuf) == 0) + { + reverse = 1; + goto file_dir_check; + } + + /* Checks if we have write permissions to the specified file or + * directory */ + if(strcasecmp("ifwrite", linebuf) == 0) +dir_write_check: + { + char *next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); + int val = 1; + +#ifdef __unix__ + { + struct stat stbuf; + val = 0; + if(stat(ptr, &stbuf) == 0) + { + if(stbuf.st_uid == getuid()) + { + if((stbuf.st_mode&S_IWUSR)) + val = 1; + } + else if(stbuf.st_gid == getgid()) + { + if((stbuf.st_mode&S_IWGRP)) + val = 1; + } + else if((stbuf.st_mode&S_IWOTH)) + val = 1; + } + } +#endif + + if((val != 0) != !!reverse) + { + memmove(linebuf, next, strlen(next)+1); + goto reparse; + } + + if(has_do) + wait_for_done |= 1 << (do_level-1); + extract_line(next, sizeof(linebuf)+linebuf-next); + continue; + } + if(strcasecmp("ifnwrite", linebuf) == 0) + { + reverse = 1; + goto dir_write_check; + } + + /* Set an environment variable. The value is space sensitive, so if you * wish to use spaces, encapsulate the value in ''s. Using '?=' instead * of '=' will only set the variable if it isn't already set. */ - if(strchr(linebuf, '=') > linebuf || strncmp(ptr, "+=", 2) == 0 || - strncmp(ptr, "-=", 2) == 0 || strncmp(ptr, "?=", 2) == 0 || - ptr[0] == '=') + if(strncmp(ptr, "+=", 2) == 0 || strncmp(ptr, "-=", 2) == 0 || + strncmp(ptr, "?=", 2) == 0 || ptr[0] == '=') { - char *val = strchr(linebuf, '='); + char *val = ptr; int ovr = 1; - if(!val) - { - val = ptr; - if(val[0] != '=') - ++val; - } + if(val[0] != '=') + ++val; ptr = linebuf; - /* Restore stolen space */ - ptr[strlen(ptr)] = tmp; - if(*(val-1) == '+') { *(val-1) = 0; ++val; while(*val && isspace(*val)) ++val; - extract_word(&ptr); - extract_word(&val); + extract_line(val, sizeof(linebuf)+linebuf-val); if(*val) { snprintf(buffer, sizeof(buffer), "%s%s", getvar(ptr), val); @@ -920,10 +2437,12 @@ reparse: while(*val && isspace(*val)) ++val; - extract_word(&ptr); - extract_word(&val); + extract_line(val, sizeof(linebuf)+val-linebuf); len = strlen(val); + if(len <= 0) + continue; + snprintf(buffer, sizeof(buffer), "%s", getvar(ptr)); while((pos=strstr(buffer, val)) != NULL) { @@ -937,19 +2456,16 @@ reparse: if(*(val-1) == '?') { *(val-1) = 0; - ++val; - extract_word(&ptr); if(*getvar(ptr)) ovr = 0; } else - { - *(val++) = 0; - extract_word(&ptr); - } + *val = 0; + + ++val; while(*val && isspace(*val)) ++val; - extract_word(&val); + extract_line(val, sizeof(linebuf)+linebuf-val); if(*val) setenv(ptr, val, ovr); else if(ovr) @@ -957,158 +2473,10 @@ reparse: continue; } - if(!(*ptr)) - { - fprintf(stderr, "Malformed command, line #%d: '%s'\n", curr_line, - linebuf); - continue; - } - - /* The if command checks if 'val1 = val2' is true and processes the - * rest of the line if so. */ - if(strcasecmp("if", linebuf) == 0) -value_check: - { - char *next, *var2 = ptr; - - var2 = extract_word(&ptr); - var2 = strchr(var2, '='); - if(!var2) - { - printf("\n\n!!! Error, line %d !!!\n" - "Malformed 'if' command!\n\n", curr_line); - ret = 1; - goto end; - } - *(var2++) = 0; - while(*var2 && isspace(*var2)) - ++var2; - extract_word(&ptr); - next = extract_word(&var2); - if(strcmp(ptr, var2) == 0) - nextcmd = next; - - if(reverse) - nextcmd = (char*)((long)nextcmd ^ (long)next); - if(has_do) - wait_for_done |= (nextcmd?0:1)<<(do_level-1); - continue; - } - /* Same as above, except if the comparison is false or it equates 0 */ - if(strcasecmp("ifnot", linebuf) == 0) - { - reverse = 1; - goto value_check; - } - - /* Checks the last command's return value against the supplied value, - * and runs the rest of the line if they're equal */ - if(strcasecmp("ifret", linebuf) == 0) -retval_check: - { - char *next; - next = extract_word(&ptr); - - if(atoi(ptr) == ret) - nextcmd = next; - - if(reverse) - nextcmd = (char*)((long)nextcmd ^ (long)next); - if(has_do) - wait_for_done |= (nextcmd?0:1)<<(do_level-1); - continue; - } - if(strcasecmp("ifnret", linebuf) == 0 ) - { - reverse = 1; - goto retval_check; - } - - /* Checks the platform we're running on against the user supplied - * value */ - if(strcasecmp("ifplat", linebuf) == 0) -platform_check: - { - char *next; - next = extract_word(&ptr); -#ifdef _WIN32 - if(strcasecmp("win32", ptr) == 0) - nextcmd = next; -#endif -#ifdef __unix__ - if(strcasecmp("unix", ptr) == 0) - nextcmd = next; -#endif - if(reverse) - nextcmd = (char*)((long)nextcmd ^ (long)next); - if(has_do) - wait_for_done |= (nextcmd?0:1)<<(do_level-1); - continue; - } - if(strcasecmp("ifnplat", linebuf) == 0) - { - reverse = 1; - goto platform_check; - } - - /* Checks if the supplied option name was specified on the command - * line */ - if(strcasecmp("ifopt", linebuf) == 0) -option_check: - { - char *next; - next = extract_word(&ptr); - - for(i = 1;i < argc;++i) - { - if(strcasecmp(ptr, argv[i]) == 0) - { - nextcmd = next; - break; - } - } - - if(reverse) - nextcmd = (char*)((long)nextcmd ^ (long)next); - if(has_do) - wait_for_done |= (nextcmd?0:1)<<(do_level-1); - continue; - } - if(strcasecmp("ifnopt", linebuf) == 0) - { - reverse = 1; - goto option_check; - } - - /* Checks if a file or directory exists */ - if(strcasecmp("ifexist", linebuf) == 0) -file_dir_check: - { - struct stat statbuf; - char *next; - - next = extract_word(&ptr); - if(stat(ptr, &statbuf) == 0) - nextcmd = next; - - if(reverse) - nextcmd = (char*)((long)nextcmd ^ (long)next); - if(has_do) - wait_for_done |= (nextcmd?0:1)<<(do_level-1); - continue; - } - if(strcasecmp("ifnexist", linebuf) == 0) - { - reverse = 1; - goto file_dir_check; - } - - if((wait_for_done & ((1< 0) + { + memmove(sources, sources+i, strlen(sources+i)+1); + ptr -= i; + } + goto compile_more_sources; } @@ -1377,16 +2878,27 @@ next_src_file: if(!sources) { - fprintf(stderr, "\n\n!!! Error, line %d !!!\n" - "Trying to build %s with undefined " - "sources!\n\n", curr_line, ptr); ret = 1; - goto end; + if(ignore_err < 2) + fprintf(stderr, "\n\n!!! %s error, line %d !!!\n" + "Trying to build %s with undefined " + "sources!\n\n", fname, curr_line, ptr); + if(!ignore_err) + { + snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); + goto reparse; + } + if(ignore_err < 2) + printf("--- Error %d ignored. ---\n\n", ++ignored_errors); + fflush(stdout); + continue; } + ret = 0; - extract_word(&ptr); + extract_line(ptr, sizeof(linebuf)+linebuf-ptr); - snprintf(obj, sizeof(obj), "%s%s", ptr, getvar("EXE_EXT")); + snprintf(obj, sizeof(obj), "'%s'${EXE_EXT}", ptr); + expand_string(obj, "", sizeof(obj), 0); if(stat(obj, &statbuf) == 0) { exe_time = statbuf.st_mtime; @@ -1394,31 +2906,67 @@ next_src_file: } i = 0; - i += snprintf(buffer+i, sizeof(buffer)-i, "%s", getvar("LD")); - i += snprintf(buffer+i, sizeof(buffer)-i, " %s\"%s\"", - getvar("OUT_OPT"), obj); + i += snprintf(buffer+i, sizeof(buffer)-i, "${LD}"); + i += snprintf(buffer+i, sizeof(buffer)-i, " ${OUT_OPT}'\"%s\"'", + obj); i += build_obj_list(buffer+i, sizeof(buffer)-i, exe_time, &do_link); if(!do_link) - continue; + { + char *buf = (char*)getvar("EXTRA_LD_DEPS"); + if(*buf) + { + char *ptr = malloc(BUF_SIZE); + strncpy(ptr, buf, BUF_SIZE); + buf = ptr; - i += snprintf(buffer+i, sizeof(buffer)-i, " %s", - getvar("LDFLAGS")); + while(*ptr) + { + char *next = expand_string(ptr, " ", BUF_SIZE+ptr-buf, 0); + if(*next) *(next++) = 0; + while(*next && isspace(*next)) + ++next; + + if(strcmp(ptr, "\n") != 0 && (stat(ptr, &statbuf) != 0 || + statbuf.st_mtime > exe_time)) + { + free(buf); + buf = NULL; + + do_link = 1; + break; + } + + ptr = next; + } + + free(buf); + } + + if(!do_link) + continue; + } + + i += snprintf(buffer+i, sizeof(buffer)-i, " ${LDFLAGS}"); + expand_string(buffer, "", sizeof(buffer), 0); if(!shh) { if(verbose) printf("%s\n", buffer); else - printf("Linking %s%s...\n", ptr, getvar("EXE_EXT")); + printf("Linking %s...\n", obj); fflush(stdout); } if((ret=system(buffer)) != 0) { if(!ignore_err) - goto end; + { + snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); + goto reparse; + } if(ignore_err < 2) { printf("--- Error %d ignored. ---\n\n", ++ignored_errors); @@ -1440,14 +2988,24 @@ next_src_file: if(!sources) { - fprintf(stderr, "\n\n!!! Error, line %d !!!\n" - "Trying to build %s with undefined " - "sources!\n\n", curr_line, ptr); ret = 1; - goto end; + if(ignore_err < 2) + fprintf(stderr, "\n\n!!! %s error, line %d !!!\n" + "Trying to build %s with undefined " + "sources!\n\n", fname, curr_line, ptr); + if(!ignore_err) + { + snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); + goto reparse; + } + if(ignore_err < 2) + printf("--- Error %d ignored. ---\n\n", ++ignored_errors); + fflush(stdout); + continue; } + ret = 0; - extract_word(&ptr); + extract_line(ptr, sizeof(linebuf)+linebuf-ptr); libify_name(obj, sizeof(obj), ptr); if(stat(obj, &statbuf) == 0) @@ -1457,9 +3015,8 @@ next_src_file: } i = 0; - i += snprintf(buffer+i, sizeof(buffer)-i, "%s %s", getvar("AR"), - getvar("AR_OPT")); - i += snprintf(buffer+i, sizeof(buffer)-i, " \"%s\"", obj); + i += snprintf(buffer+i, sizeof(buffer)-i, "${AR} ${AR_OPT}"); + i += snprintf(buffer+i, sizeof(buffer)-i, " '\"%s\"'", obj); i += build_obj_list(buffer+i, sizeof(buffer)-i, lib_time, &do_link); @@ -1467,8 +3024,8 @@ next_src_file: if(!do_link) continue; - libify_name(obj, sizeof(obj), ptr); remove(obj); + expand_string(buffer, "", sizeof(buffer), 0); if(!shh) { @@ -1481,7 +3038,10 @@ next_src_file: if((ret=system(buffer)) != 0) { if(!ignore_err) - goto end; + { + snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); + goto reparse; + } if(ignore_err < 2) { printf("--- Error %d ignored. ---\n\n", ++ignored_errors); @@ -1496,6 +3056,7 @@ next_src_file: * them */ if(strcasecmp("loadlist", linebuf) == 0) { + extract_line(ptr, sizeof(linebuf)+linebuf-ptr); free(loaded_files); loaded_files = strdup(ptr); if(!loaded_files) @@ -1503,8 +3064,8 @@ next_src_file: fprintf(stderr, "\n\n\n** Critical Error **\n" "Out of memory duplicating string '%s'\n\n", ptr); - ret = -1; - goto end; + snprintf(linebuf, sizeof(linebuf), "exit -1\n"); + goto reparse; } continue; } @@ -1513,53 +3074,56 @@ next_src_file: if(strcasecmp("execlist", linebuf) == 0) { char *curr, *next; + if(!loaded_files) { ret = 1; if(ignore_err < 2) - printf("\n\n!!! Error, line %d !!!\n" - "'loadexec' called with no files!\n\n", curr_line); + printf("\n\n!!! %s error, line %d !!!\n" + "'loadexec' called with no list!\n\n", fname, + curr_line); if(!ignore_err) - goto end; + { + snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); + goto reparse; + } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); continue; } + ret = 0; - curr = loaded_files; + next = loaded_files; tmp = 0; - while(*curr) + extract_line(ptr, sizeof(linebuf)+linebuf-ptr); + + while(*(curr=next)) { char *cmd_ptr = ptr; - char *nuller; - char c = ' '; + char c; + int i; - next = extract_word(&curr); - if(curr > loaded_files && (*(curr-1) == '\'' || - *(curr-1) == '"')) - c = *(curr-1); + next = grab_word(&curr, &c); i = 0; - while(*cmd_ptr) + while(*cmd_ptr && i+1 < (signed)sizeof(buffer)) { - do { - nuller = strchr(cmd_ptr, '<'); - if(!nuller || (nuller[1] == '@' && nuller[2] == '>')) - break; - cmd_ptr = nuller+1; - } while(1); - if(!nuller) - break; - *nuller = 0; - - i += snprintf(buffer+i, sizeof(buffer)-i, "%s%s", cmd_ptr, - curr); - - *nuller = '<'; - cmd_ptr = nuller+3; + if(strncasecmp(cmd_ptr, "<@>", 3) == 0) + { + i += snprintf(buffer+i, sizeof(buffer)-i, "%s", + curr); + cmd_ptr += 3; + } + else + { + if(cmd_ptr[0] == '\\' && cmd_ptr[1] != 0 && + i+2 < (signed)sizeof(buffer)) + buffer[i++] = *(cmd_ptr++); + buffer[i++] = *(cmd_ptr++); + buffer[i] = 0; + } } - i += snprintf(buffer+i, sizeof(buffer)-i, "%s", cmd_ptr); if(!shh) { @@ -1568,23 +3132,24 @@ next_src_file: } if((ret=system(buffer)) != 0) { - tmp = 1; + tmp = ret; if(!ignore_err) - goto end; + { + snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); + goto reparse; + } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); } + curr += strlen(curr); - if(*next) - { - *(curr++) = c; - if(curr < next) - memmove(curr, next, strlen(next)+1); - } + if(next > curr) + *curr = c; } + ret = tmp; continue; } @@ -1593,8 +3158,7 @@ next_src_file: * beginning of string, it will be skipped */ if(strcasecmp("echo", linebuf) == 0) { - if(ptr[0] == '.') - ++ptr; + extract_line(ptr, sizeof(linebuf)+linebuf-ptr); printf("%s\n", ptr); fflush(stdout); continue; @@ -1604,8 +3168,7 @@ next_src_file: * used at the beginning of string, it will be skipped */ if(strcasecmp("put", linebuf) == 0) { - if(ptr[0] == '.') - ++ptr; + extract_line(ptr, sizeof(linebuf)+linebuf-ptr); printf("%s", ptr); fflush(stdout); continue; @@ -1617,7 +3180,7 @@ next_src_file: char *str; FILE *o; - str = extract_word(&ptr); + str = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); o = fopen(ptr, "w"); if(!o) { @@ -1625,7 +3188,8 @@ next_src_file: if(!ignore_err) { printf("Could not create file '%s'!\n", ptr); - goto end; + snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); + goto reparse; } if(ignore_err < 2) { @@ -1636,9 +3200,9 @@ next_src_file: } continue; } + ret = 0; - if(str[0] == '.') - ++str; + extract_line(str, sizeof(linebuf)+linebuf-str); fprintf(o, "%s\n", str); fclose(o); continue; @@ -1650,7 +3214,7 @@ next_src_file: char *str; FILE *o; - str = extract_word(&ptr); + str = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); o = fopen(ptr, "a"); if(!o) { @@ -1658,7 +3222,8 @@ next_src_file: if(!ignore_err) { printf("Could not create file '%s'!\n", ptr); - goto end; + snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); + goto reparse; } if(ignore_err < 2) { @@ -1669,9 +3234,9 @@ next_src_file: } continue; } + ret = 0; - if(str[0] == '.') - ++str; + extract_line(str, sizeof(linebuf)+linebuf-str); fprintf(o, "%s\n", str); fclose(o); continue; @@ -1683,39 +3248,55 @@ next_src_file: { int src_line; char *lbl; + + lbl = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); + extract_line(lbl, sizeof(linebuf)+linebuf-ptr); lbl = strdup(ptr); if(!lbl) { fprintf(stderr, "\n\n\n** Critical Error **\n" "Out of memory duplicating string '%s'\n\n", lbl); - ret = -1; - goto end; + snprintf(linebuf, sizeof(linebuf), "exit -1\n"); + goto reparse; } rewind(f); src_line = curr_line; curr_line = 0; + wait_for_done = 0; + did_else = 0; + did_cmds = 0; + do_level = 0; while(fgets(linebuf, sizeof(linebuf), f) != NULL) { ++curr_line; - if(linebuf[0] == '#' && linebuf[1] == ':') + while(linebuf[0]) { - ptr = strpbrk(linebuf, "\r\n"); - if(ptr) *ptr = 0; - if(strcasecmp(linebuf+2, lbl) == 0) + int i; + extract_line(linebuf, sizeof(linebuf)); + + for(i = 0;isspace(linebuf[i]);++i) + ; + memmove(linebuf, &linebuf[i], strlen(&linebuf[i])+1); + if(linebuf[0] == ':' && strcasecmp(linebuf+1, lbl) == 0) { free(lbl); - nextline = NULL; goto main_loop_start; } + if(!nextline) + break; + strcpy(linebuf, nextline); + free(nextline); + nextline = NULL; } } - fprintf(stderr, "\n\n!!! Error, line %d !!!\n" - "Label target '%s' not found!\n\n", src_line, lbl); + fprintf(stderr, "\n\n!!! %s error, line %d !!!\n" + "Label target '%s' not found!\n\n", fname, + src_line, lbl); free(lbl); - ret = -1; - goto end; + snprintf(linebuf, sizeof(linebuf), "exit 1\n"); + goto reparse; } @@ -1726,38 +3307,39 @@ next_src_file: unsigned int count = 0; char *next; - while(src_paths[count] && count < SRC_PATH_SIZE) + while(count < SRC_PATH_SIZE && src_paths[count]) { free(src_paths[count]); src_paths[count] = NULL; ++count; } - if(strcmp(ptr, ".") == 0) - continue; - count = 0; while(*ptr) { if(count >= SRC_PATH_SIZE) { - printf("\n\n!!! Error, line %d !!!\n" - "Too many source paths specified!\n\n", - ++curr_line); - ret = -1; - goto end; + printf("\n\n!!! %s error, line %d !!!\n" + "Too many source paths specified!\n\n", fname, + curr_line); + snprintf(linebuf, sizeof(linebuf), "exit 1\n"); + goto reparse; } - next = extract_word(&ptr); + next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); + if(count == 0 && (strcmp(ptr, ".") == 0 || strlen(ptr) == 0)) + break; + src_paths[count] = strdup(ptr); - if(!src_paths[count++]) + if(!src_paths[count]) { fprintf(stderr, "\n\n\n** Critical Error **\n" "Out of memory duplicating string " "'%s'\n\n", ptr); - ret = -1; - goto end; + snprintf(linebuf, sizeof(linebuf), "exit -1\n"); + goto reparse; } + ++count; ptr = next; } continue; @@ -1767,11 +3349,12 @@ next_src_file: * as needed */ if(strcasecmp("rmexec", linebuf) == 0) { - char *next; - do { - next = extract_word(&ptr); - snprintf(buffer, sizeof(buffer), "%s%s", ptr, - getvar("EXE_EXT")); + char *next = ptr; + while(*(ptr=next)) + { + next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); + snprintf(buffer, sizeof(buffer), "'%s'${EXE_EXT}", ptr); + expand_string(buffer, "", sizeof(buffer), 0); if(stat(buffer, &statbuf) == -1 && errno == ENOENT) continue; @@ -1787,13 +3370,16 @@ next_src_file: if(ignore_err < 2) printf("!!! Could not delete file !!!\n"); if(!ignore_err) - goto end; + { + snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); + goto reparse; + } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); } - } while(*(ptr=next)); + } continue; } @@ -1802,9 +3388,10 @@ next_src_file: * filename portions and appending with 'LIB_EXT' */ if(strcasecmp("rmlib", linebuf) == 0) { - char *next; - do { - next = extract_word(&ptr); + char *next = ptr; + while(*(ptr=next)) + { + next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); libify_name(buffer, sizeof(buffer), ptr); if(stat(buffer, &statbuf) == -1 && errno == ENOENT) @@ -1821,7 +3408,10 @@ next_src_file: if(ignore_err < 2) printf("!!! Could not delete file !!!\n"); if(!ignore_err) - goto end; + { + snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); + goto reparse; + } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); @@ -1836,17 +3426,19 @@ next_src_file: if(strcasecmp("rmobj", linebuf) == 0) { char *ext; - char *next; - do { - next = extract_word(&ptr); + char *next = ptr; + while(*(ptr=next)) + { + next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); ext = strrchr(ptr, '/'); if(!ext) ext = ptr; ext = strrchr(ext, '.'); if(ext) *ext = 0; - snprintf(buffer, sizeof(buffer), "%s/%s%s", getvar("OBJ_DIR"), - ptr, getvar("OBJ_EXT")); + snprintf(buffer, sizeof(buffer), "${OBJ_DIR}/'%s'${OBJ_EXT}", + ptr); + expand_string(buffer, "", sizeof(buffer), 0); if(ext) *ext = '.'; if(stat(buffer, &statbuf) == 0 || errno != ENOENT) @@ -1862,7 +3454,10 @@ next_src_file: if(ignore_err < 2) printf("!!! Could not delete file !!!\n"); if(!ignore_err) - goto end; + { + snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); + goto reparse; + } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); @@ -1870,8 +3465,9 @@ next_src_file: } if(ext) *ext = 0; - snprintf(buffer, sizeof(buffer), "%s/%s%s", getvar("DEP_DIR"), - ptr, getvar("DEP_EXT")); + snprintf(buffer, sizeof(buffer), "${DEP_DIR}/'%s'${DEP_EXT}", + ptr); + expand_string(buffer, "", sizeof(buffer), 0); if(ext) *ext = '.'; if(stat(buffer, &statbuf) == -1 && errno == ENOENT) @@ -1888,22 +3484,26 @@ next_src_file: if(ignore_err < 2) printf("!!! Could not delete file !!!\n"); if(!ignore_err) - goto end; + { + snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); + goto reparse; + } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); } - } while(*(ptr=next)); + } continue; } /* Removes a list of files or empty directories */ if(strcasecmp("rm", linebuf) == 0) { - char *next; - do { - next = extract_word(&ptr); + char *next = ptr; + while(*(ptr=next)) + { + next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); if(stat(ptr, &statbuf) == -1 && errno == ENOENT) continue; @@ -1919,25 +3519,28 @@ next_src_file: if(ignore_err < 2) printf("!!! Could not delete !!!\n"); if(!ignore_err) - goto end; + { + snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); + goto reparse; + } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); } - } while(*(ptr=next)); + } continue; } /* Creates a directory (with mode 700 in Unix) */ if(strcasecmp("mkdir", linebuf) == 0) { - extract_word(&ptr); + extract_line(ptr, sizeof(linebuf)+linebuf-ptr); if(!shh) { if(!verbose) printf("Creating directory %s/...\n", ptr); -#ifdef _WIN32 +#if defined(_WIN32) else printf("mkdir(\"%s\");\n", ptr); fflush(stdout); } @@ -1952,7 +3555,10 @@ next_src_file: if(ignore_err < 2) printf("!!! Could not create directory !!!\n"); if(!ignore_err) - goto end; + { + snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); + goto reparse; + } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); @@ -1963,7 +3569,9 @@ next_src_file: /* Enables/disables command verboseness */ if(strcasecmp("verbose", linebuf) == 0) { - verbose = (atoi(ptr) != 0); + extract_line(ptr, sizeof(linebuf)+linebuf-ptr); + if(*ptr) + verbose = atoi(ptr); continue; } @@ -1972,9 +3580,13 @@ next_src_file: * like exit */ if(strcasecmp("uninvoke", linebuf) == 0) { + extract_line(ptr, sizeof(linebuf)+linebuf-ptr); ret = atoi(ptr); if(!invoke_backup[0].f) - goto end; + { + snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); + goto reparse; + } for(i = 1;i <= INVOKE_BKP_SIZE;++i) { @@ -1985,15 +3597,14 @@ next_src_file: f = invoke_backup[i].f; invoke_backup[i].f = NULL; + free(fname); + fname = invoke_backup[i].fname; + strcpy(linebuf, invoke_backup[i].bkp_lbuf); free(invoke_backup[i].bkp_lbuf); - if(invoke_backup[i].bkp_nextline) - { - nextline = linebuf+strlen(linebuf)+1; - strcpy(nextline, invoke_backup[i].bkp_nextline); - free(invoke_backup[i].bkp_nextline); - } + free(nextline); + nextline = invoke_backup[i].bkp_nextline; curr_line = invoke_backup[i].bkp_line; did_else = invoke_backup[i].bkp_did_else; @@ -2007,7 +3618,10 @@ next_src_file: if(ret != 0) { if(!ignore_err) - goto end; + { + snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); + goto reparse; + } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); @@ -2019,26 +3633,36 @@ next_src_file: /* Copies a file */ if(strcasecmp("copy", linebuf) == 0) { - char *dfile; + char *dfile, *end; + struct stat st; - dfile = extract_word(&ptr); + dfile = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); if(!(*dfile)) { + ret = 1; if(ignore_err < 2) - printf("\n\n!!! Error, line %d !!! \n" - "Improper arguments to 'copy'!\n", curr_line); + printf("\n\n!!! %s error, line %d !!! \n" + "Improper arguments to 'copy'!\n", fname, + curr_line); if(!ignore_err) - goto end; + { + snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); + goto reparse; + } if(ignore_err < 2) printf("--- Error %d ignored. ---\n", ++ignored_errors); fflush(stdout); continue; } - extract_word(&dfile); - if(dfile[strlen(dfile)-1] == '/') + ret = 0; + end = extract_word(dfile, sizeof(linebuf)+linebuf-dfile); + if(dfile[strlen(dfile)-1] == '/' || (stat(dfile, &st) == 0 && + S_ISDIR(st.st_mode))) { char *fn = strrchr(ptr, '/'); - snprintf(obj, sizeof(obj), "%s%s", dfile, (fn?(fn+1):ptr)); + snprintf(obj, sizeof(obj), "%s%s%s", dfile, + ((dfile[strlen(dfile)-1]=='/')?"":"/"), + (fn?(fn+1):ptr)); dfile = obj; } if(!shh) @@ -2047,16 +3671,20 @@ next_src_file: else printf("Copying '%s' to '%s'...\n", ptr, dfile); fflush(stdout); } - if(copy_file(ptr, dfile) != 0) + if((ret=copy_file(ptr, dfile)) != 0) { if(ignore_err < 2) printf("!!! Could not copy !!!\n"); if(!ignore_err) - goto end; + { + snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); + goto reparse; + } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); } + extract_line(end, sizeof(linebuf)+linebuf-end); continue; } @@ -2064,22 +3692,28 @@ next_src_file: * necesarry */ if(strcasecmp("copylib", linebuf) == 0) { - char *dfile; + char *dfile, *end; - dfile = extract_word(&ptr); + dfile = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); if(!(*dfile)) { + ret = 1; if(ignore_err < 2) - printf("\n\n!!! Error, line %d !!! \n" - "Improper arguments to 'copylib'!\n", curr_line); + printf("\n\n!!! %s error, line %d !!! \n" + "Improper arguments to 'copylib'!\n", fname, + curr_line); if(!ignore_err) - goto end; + { + snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); + goto reparse; + } if(ignore_err < 2) printf("--- Error %d ignored. ---\n", ++ignored_errors); fflush(stdout); continue; } - extract_word(&dfile); + ret = 0; + end = extract_word(dfile, sizeof(linebuf)+linebuf-dfile); if(dfile[strlen(dfile)-1] == '/') { char *fn = strrchr(ptr, '/'); @@ -2097,64 +3731,42 @@ next_src_file: else printf("Copying '%s' to '%s'...\n", obj, buffer); fflush(stdout); } - if(copy_file(obj, buffer) != 0) + if((ret=copy_file(obj, buffer)) != 0) { if(ignore_err < 2) printf("!!! Could not copy !!!\n"); if(!ignore_err) - goto end; + { + snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); + goto reparse; + } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); } + extract_line(end, sizeof(linebuf)+linebuf-end); continue; } - /* Copies an executable file, appending the names as necesarry */ - if(strcasecmp("copyexec", linebuf) == 0) + if(strcasecmp("chdir", linebuf) == 0) { - char *dfile; - - dfile = extract_word(&ptr); - if(!(*dfile)) - { - if(ignore_err < 2) - printf("\n\n!!! Error, line %d !!! \n" - "Improper arguments to 'copyexec'!\n", curr_line); - if(!ignore_err) - goto end; - if(ignore_err < 2) - printf("--- Error %d ignored. ---\n", ++ignored_errors); - fflush(stdout); - continue; - } - extract_word(&dfile); - if(dfile[strlen(dfile)-1] == '/') - { - char *fn = strrchr(ptr, '/'); - snprintf(obj, sizeof(obj), "%s%s", dfile, (fn?(fn+1):ptr)); - snprintf(buffer, sizeof(buffer), "%s%s", obj, - getvar("EXE_EXT")); - } - else - snprintf(buffer, sizeof(buffer), "%s%s", dfile, - getvar("EXE_EXT")); - - libify_name(obj, sizeof(obj), ptr); - snprintf(obj, sizeof(obj), "%s%s", ptr, getvar("EXE_EXT")); + extract_line(ptr, sizeof(linebuf)+linebuf-ptr); if(!shh) { - if(verbose) printf("copy_file(\"%s\", \"%s\");\n", obj, buffer); - else printf("Copying '%s' to '%s'...\n", obj, buffer); + if(verbose) printf("chdir(\"%s\");\n", ptr); + else printf("Moving to directory '%s'\n", ptr); fflush(stdout); } - if(copy_file(obj, buffer) != 0) + if((ret=chdir(ptr)) != 0) { if(ignore_err < 2) - printf("!!! Could not copy !!!\n"); + printf("!!! Could not change directory !!!\n"); if(!ignore_err) - goto end; + { + snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); + goto reparse; + } if(ignore_err < 2) printf("--- Error %d ignored. ---\n\n", ++ignored_errors); fflush(stdout); @@ -2162,33 +3774,215 @@ next_src_file: continue; } + /* Creates an association between a file extension and a command to + * compile files with that association via the compile command */ + if(strcasecmp("associate", linebuf) == 0) + { + char *cmd = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); + extract_line(cmd, sizeof(linebuf)+linebuf-cmd); + + add_association(ptr, cmd); + continue; + } + + /* Yay for DOS/Windows allowing \ as a directory seperator. Modify the + * named environment variable to replace \ with / */ + if(strcasecmp("fixpath", linebuf) == 0) + { + char *str, *val; + char *end = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); + extract_line(end, sizeof(linebuf)+linebuf-ptr); + + val = strdup(getvar(ptr)); + str = val; + + while((str=strchr(str, '\\')) != NULL) + *(str++) = '/'; + + setenv(ptr, val, 1); + free(val); + + continue; + } + + /* Our "special" rem command. Using this, you can make a cbuild script + * double as a DOS/Windows .bat file. */ + if(strcasecmp("rem", linebuf) == 0) + { + memmove(linebuf, ptr, strlen(ptr)+1); + goto reparse; + } + + /* Changes the file to read input from. Pass nothing to switch to + * stdin. */ + if(strcasecmp("setinput", linebuf) == 0) + { + extract_line(ptr, sizeof(linebuf)+linebuf-ptr); + + if(infile != stdin) + fclose(infile); + + ret = 0; + if(*ptr) + { + infile = fopen(ptr, "r"); + if(!infile) + { + ret = 1; + if(ignore_err < 2) + printf("!!! Could not open file '%s' to read !!!\n", + ptr); + if(!ignore_err) + { + snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); + goto reparse; + } + if(ignore_err < 2) + printf("--- Error %d ignored. ---\n\n", + ++ignored_errors); + fflush(stdout); + } + } + else + infile = stdin; + + continue; + } + + /* Reads keyboard input and stores the string in the named var. The + * trailing newline is stripped. */ + if(strcasecmp("read", linebuf) == 0) + { + extract_line(ptr, sizeof(linebuf)+linebuf-ptr); + if(!(*ptr)) + { + ret = 1; + if(ignore_err < 2) + printf("!!! No storage specified for read (line %d) !!!\n", + curr_line); + if(!ignore_err) + { + snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret); + goto reparse; + } + if(ignore_err < 2) + printf("--- Error %d ignored. ---\n\n", ++ignored_errors); + fflush(stdout); + } + ret = 0; + + buffer[0] = 0; + if(!infile || fgets(buffer, sizeof(buffer), infile) == NULL) + ret = 1; + + while(strlen(buffer) > 0 && (buffer[strlen(buffer)-1] == '\n' || + buffer[strlen(buffer)-1] == '\r')) + buffer[strlen(buffer)-1] = 0; + + if(!strlen(buffer)) + ret |= unsetenv(ptr); + else + ret |= setenv(ptr, buffer, 1); + + continue; + } + + /* Exits the script with the specified exitcode */ if(strcasecmp("exit", linebuf) == 0) { - ret = atoi(ptr); - goto end; + static int already_exited = 0; + int inc = 0; + int retval; + + if(already_exited) + { + printf("\n\n*** Critical error ***\n" + "Recursive exit call, aborting now!\n\n"); + exit(-1); + } + already_exited = 1; + + extract_line(ptr, sizeof(linebuf)+linebuf-ptr); + retval = atoi(ptr); + + for(i = num_defines-1;(size_t)i < num_defines;--i) + { + if(strncasecmp(defines[i].name, "atexit_", 7) == 0) + inc += snprintf(linebuf+inc, sizeof(linebuf)-inc, "%s\n", + defines[i].val); + } + snprintf(linebuf+inc, sizeof(linebuf)-inc, "__really_exit %d\n", + retval); + + free(nextline); + nextline = NULL; + goto reparse; } - printf("\n\n!!! Error, line %d !!!\n" - "Unknown command '%s'\n\n", curr_line, linebuf); + + /* Does nothing. Ignores the line */ + if(strcasecmp("noop", linebuf) == 0) + { + extract_line(ptr, sizeof(linebuf)+linebuf-ptr); + continue; + } + + + if(strcasecmp("__reset_cmd_args__", linebuf) == 0) + { + extract_line(ptr, sizeof(linebuf)+linebuf-ptr); + + for(i = 0;(size_t)i < cmd_argc;++i) + { + free(cmd_argv[i]); + cmd_argv[i] = NULL; + } + cmd_argc = 0; + argv = _argv; + argc = _argc; + continue; + } + + /* Exits the script with the specified exitcode */ + if(strcasecmp("__really_exit", linebuf) == 0) + { + extract_line(ptr, sizeof(linebuf)+linebuf-ptr); + exit(atoi(ptr)); + } + + + for(i = 0;(size_t)i < num_defines;++i) + { + char *next; + + if(strcasecmp(defines[i].name, linebuf) != 0) + continue; + + cmd_argv[cmd_argc++] = strdup(linebuf); + while(*ptr != 0) + { + next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr); + cmd_argv[cmd_argc++] = strdup(ptr); + ptr = next; + } + cmd_argv[cmd_argc] = NULL; + + argv = cmd_argv; + argc = cmd_argc; + + snprintf(linebuf, sizeof(linebuf), "%s\n__reset_cmd_args__\n%s\n", + defines[i].val, (nextline?nextline:"")); + free(nextline); + nextline = NULL; + goto reparse; + } + + + printf("\n\n!!! %s error, line %d !!!\n" + "Unknown command '%s'\n\n", fname, curr_line, linebuf); break; } -end: - fflush(stdout); - i = 0; - while(src_paths[i] && i < SRC_PATH_SIZE) - free(src_paths[i++]); - i = 0; - while(i < INVOKE_BKP_SIZE && invoke_backup[i].f) - { - fclose(invoke_backup[i].f); - free(invoke_backup[i].bkp_lbuf); - free(invoke_backup[i].bkp_nextline); - ++i; - } - free(loaded_files); - free(sources); - fclose(f); return ret; } diff --git a/default.cbd b/default.cbd index ac368ef41..dc272d2b7 100644 --- a/default.cbd +++ b/default.cbd @@ -1,224 +1,382 @@ -do ifopt help - echo Available options are: - echo . debug - Build debug instead of release - echo . verbose - Show system commands instead of decorated messages - echo . clean - Clean temp files (use with debug to clean debug files) - echo . zdoom.wad - (Re)build just zdoom.wad, even if it already exists - echo . - echo To use with MinGW, compile cbuild.c into an executable using: - echo gcc -O2 -W -Wall -Werror -o cbuild.exe cbuild.c - echo . - echo Or if you have a sh-compatible shell, you can run the cbuild.c file - echo directly or have it automatically compile itself with GCC by passing - echo --make-compiled - echo . - exit 0 -done +# Example cbuild script file, which can be used to build itself with GCC. +# Note: This is a comparitively simple example, and in no way showcases +# CBuild's extensive capabilities. For more in-depth information, please see +# the AWiki entry at -# Here's the main script. All commands are case in-sensitive. +# Everything past the first '#' character in a line is ignored. To put a '#' +# character in a line, escape it like '\#', or put it in quotes. +# Use ${var} to dereference the environment variable 'var', and $(cmd) to +# replace text using sub-command 'cmd'. +# &#xxxx; will give you the character the given number value represents, in +# UTF-8 (ie. © or �xA9; will give you the copyright symbol on a UTF-8 +# compatible console). In addition, the standard HTML entity names are also +# valid (ie. © will also give you the copyright symbol). -# 'Ifopt' will check if the following word was passed on the command line, and execute the -# rest of the line if so. The reverse, 'ifnopt', also exists. +# All whitespace between a command and its option(s) are eaten by the parser. + + +# You can use 'echo' to print a line to the console. Use 'put' to print a +# line without a trailing newline +echo "CBuild © 2006" +echo "" + + +# 'ifopt' checks the command line for the specified option. The rest of the +# line will only be processed if it was passed. Whitespace between the option +# name and next command is ignored. If the command line opt has a =, it will +# be treated as an opt=val pair and only the portion before the = needs to +# match. +# 'verbose' causes cbuild to display the commands being run for a number of +# commands, in place of the cleaner, more readable output. ifopt verbose verbose 1 -ifopt debug CONFIG = Debug - -# VAR?=foo will only set the var if it's unset. Note that if you want spaces, put '' or "" -# quotes around the value. VAR+=foo will append foo to the very end of the existing var. -# And, VAR-=foo will remove all occurences of foo from the var. -CONFIG ?= Release - -OPTLEVEL ?= 2 -ARCH_TYPE ?= pentium -TUNE_TYPE ?= athlon-xp - -RELEASETARGET ?= zdoomgcc -DEBUGTARGET ?= zdoomgccd - -DEBUGOBJDIR = debugobj -RELEASEOBJDIR = releaseobj -CPPFLAGS = "-DHAVE_FILELENGTH -D__forceinline=inline -Izlib -IFLAC -Isrc -Isrc/sdl -Isrc/g_doom -Isrc/g_heretic -Isrc/g_hexen -Isrc/g_raven -Isrc/g_strife -Isrc/g_shared -Isrc/oplsynth -Isrc/sound" -LDFLAGS = "-lFLAC++ -lFLAC -lz -lfmod `sdl-config --libs`" -CFLAGS = "`sdl-config --cflags` " +# To keep the main directory clean, it's usually best to put the temporary +# object and dependancy files into subdirectories. Changing the variables +# OBJ_DIR and DEP_DIR will do just this. -do ifopt debug - OBJDIR = "${DEBUGOBJDIR}" - CFLAGS += "-Wall -Wno-unused -g3" - CPPFLAGS += " -D_DEBUG" - CXXFLAGS = "${CFLAGS}" - TARGET = "${DEBUGTARGET}" -else - OBJDIR = "${RELEASEOBJDIR}" - CFLAGS += "-march=${ARCH_TYPE} -mtune=${TUNE_TYPE} -Wall -Wno-unused -O${OPTLEVEL} -fomit-frame-pointer" - CPPFLAGS += " -DNDEBUG" - CXXFLAGS = "${CFLAGS}" - LDFLAGS += " -Wl,-Map=zdoomgcc.map" - TARGET = "${RELEASETARGET}" +OBJ_DIR = obj +DEP_DIR = dep + + +# The 'do' command allows cbuild to execute a block if the following if-type +# check passes. End the block with 'done' or use 'else' (which can also be +# followed by an if-type command) to make another block to run if the initial +# check failed. Indentation is unimportant. + +do ifopt help + echo " +CBuild - a platform-independant build system using (mostly) ANSI C. + +Available options: + verbose - Enable more verbose command printing + clean - Clean a previously compiled build + --install path - Installs the optimized executable to the specified path + --disable-gui - Disables using the GUI for installation on some platforms + help - Display this help message + +For advanced scripting information, please see CBuild's AWiki entry at + +To report bugs, please email me at or +. +" + + # 'exit' returns from the script, and cbuild will return with the specified + # number as the exit code + + exit 0 done -ifnplat win32 CPPFLAGS += " -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp" -# This is where the object and dependancy files go when compiled -OBJ_DIR = "${OBJDIR}" -DEP_DIR = "${OBJDIR}" +# 'goto' jumps to the specified label (prepended with ':') which can be ahead +# of or behind the current line. -do ifnopt clean - EVILCLEAN = 0 - ifnexist "${OBJ_DIR}" mkdir "${OBJ_DIR}" +ifopt clean goto clean - ifopt zdoom.wad goto makewad - do if "${NOASM}"="" -# 'Loadlist' stores a list of words, and 'execlist' executes a command on each one, -# replacing <@> with the word. Unfortuantely this doesn't do dependancy checking. - loadlist 'a' 'blocks' 'misc' 'tmap' 'tmap2' 'tmap3' - do ifplat win32 execlist nasmw -o "${OBJ_DIR}/<@>${OBJ_EXT}" -f win32 "src/<@>.nas" - else ifplat unix execlist nasm -o "${OBJ_DIR}/<@>${OBJ_EXT}" -f elf -DM_TARGET_LINUX "src/<@>.nas" - else - echo . - echo Unsupported platform! - echo . - exit 1 - done - CPPFLAGS = "-DUSEASM ${CPPFLAGS}" - else - CPPFLAGS = "-DNOASM ${CPPFLAGS}" - done +# Here we set some standard optimizing C flags. This only persists until +# another line is encountered that sets them differently. You can use ?= +# instead of = to set a variable only if its not already set. If you wish +# to start with spaces, encapsulate the value in ''s or ""s, or escape +# the first whitespace character with \ -# Set the compile and link commands. 'Compile' will compile the list of sourcefiles and -# store their names until another Compile is encountered (if you wish to add to a previous -# list, use 'Compileadd'). -# -# C sources are compiled with: -# ${CC} ${CPPFLAGS} ${CFLAGS} ${DEP_OPT}${DEP_DIR}/file-sans-ext${DEP_EXT} ${OUT_OPT}${OBJ_DIR}/file-sans-ext${OBJ_EXT} ${SRC_OPT}detected-source-path/file-with-ext -# -# and for C++ sources: -# ${CXX} ${CPPFLAGS} ${CXXFLAGS} ${DEP_OPT}${DEP_DIR}/file-sans-ext${DEP_EXT} ${OUT_OPT}${OBJ_DIR}/file-sans-ext${OBJ_EXT} ${SRC_OPT}detected-source-path/file-with-ext -# -# A source file will not be compiled if the object file exists and is newer than the source. -# Or if the associated dependancy file exists, all of the object's dependancies are older -# than the object. -# -# If DEP_OPT is unset, the whole DEP_* section will be removed from the command line. Files -# with unknown extensions are silently ignored (but will still be passed to Linkexec with -# their name "object-ified"). -# -# 'Linkexec' executes: -# ${LD} ${OUT_OPT}file${EXE_EXT} ${LDFLAGS} -# -# It will not link if the target executable exists and is newer than all of the objects it's -# linking with. +CFLAGS ?= "-O2 -W -Wall" - COMPILE = Compile - LINK = Linkexec -# This is where it can find the sources. - src_paths src src/g_doom src/g_heretic src/g_hexen src/g_raven src/g_strife $ - src/g_shared src/oplsynth src/sound src/sdl +# Create the object and dependancy file directories. 'ifnexist' will run the +# following command if the specified file or directory doesn't exist. Testing +# "name/." will make sure "name" is actually a directory. +ifnexist "${OBJ_DIR}/." mkdir ${OBJ_DIR} +ifnexist "${DEP_DIR}/." mkdir ${DEP_DIR} + + +# There be a lot of funky magic in here. Only advanced users will want to worry +# about this. +define dialog 'noop' +define dcop 'noop' +do ifnopt --disable-gui + + # Locate dcop and make sure it's running. Also, look for kdialog. + DCOP = $(*which dcop) + do ifnot ${'DCOP'}='' + @!call ${'DCOP'} >/dev/null + do ifret 0 + DIALOG = $(*which kdialog) + if ${'DIALOG'}='' DCOP = '' + else + DCOP = '' + done + done + + # If KDE's not available, bail out and go console-only + if ${'DCOP'}='' goto build_it + + # Make sure we can write to a temporary file, where kdialog's talkback will + # be stored. + do ifnwrite /tmp/cbtmpxyz.txt + do ifnwrite /tmp/. + @!call ${'DIALOG'} --title "\"CBuild install error\"" --error "\"Unable to write to /tmp/cbtmpxyz.txt! +Install aborted!\"" 2>/dev/null + + DCOP = '' + DIALOG = '' + goto build_it + done + done + + # Set up a 4-part progress bar. The dcop reference will be stored in a temp + # file + @!call ${'DIALOG'} --title \"Building CBuild\" --progressbar \"Building CBuild, please wait...\" 4 >/tmp/cbtmpxyz.txt 2>/dev/null + ifnret 0 goto build_it + + # Read in from the temp file + setinput /tmp/cbtmpxyz.txt + read DCOP_REF + + # If reading failed, alert the user and continue without the GUI + do ifnret 0 + @!call ${'DIALOG'} --title "\"CBuild install error\"" --warning "\"Unable to read DCOP reference from /tmp/cbtmpxyz.txt!\"" 2>/dev/null + + DCOP = '' + DIALOG = '' + setinput + goto build_it + done + + # Restore normal input and delete the temp file + setinput + @-rm /tmp/cbtmpxyz.txt + + define dialog @!call \'${'DIALOG'}\' '"${@}"' >/tmp/cbtmpxyz.txt 2>/dev/null + define dcop @!call \'${'DCOP'}\' '\'${\'DCOP_REF\'}\'' '"${@}"' 2>/dev/null + + # Setup an exit command, to make sure the progress bar is removed on exit + define atexit_dcop dclop close else - -# Override the compile and link commands with rmobj and rmexec. A quick way to delete -# the objects and executables while dealing with only one list. No, rmobj will not -# delete the specified source file, but rather the object and dependancy files that would -# result from compiling the specified source. - EVILCLEAN = 1 - COMPILE = -rmobj - LINK = -rmexec - + DCOP = '' done -${COMPILE} autostart.cpp a.nas blocks.nas misc.nas tmap.nas tmap2.nas tmap3.nas $ - am_map.cpp b_bot.cpp b_func.cpp b_game.cpp b_move.cpp b_think.cpp bbannouncer.cpp $ - c_bind.cpp c_cmds.cpp c_console.cpp c_cvars.cpp c_dispatch.cpp c_expr.cpp $ - cmdlib.cpp colormatcher.cpp configfile.cpp ct_chat.cpp d_dehacked.cpp d_main.cpp $ - d_net.cpp d_netinfo.cpp d_protocol.cpp decallib.cpp decorations.cpp dobject.cpp $ - doomdef.cpp doomstat.cpp dsectoreffect.cpp dthinker.cpp empty.cpp f_finale.cpp $ - f_wipe.cpp farchive.cpp files.cpp g_game.cpp g_level.cpp gameconfigfile.cpp $ - gi.cpp hu_scores.cpp info.cpp infodefaults.cpp lumpconfigfile.cpp m_alloc.cpp $ - m_argv.cpp m_bbox.cpp m_cheat.cpp m_fixed.cpp m_menu.cpp m_misc.cpp m_options.cpp $ - m_png.cpp m_random.cpp mus2midi.cpp nodebuild.cpp nodebuild_events.cpp $ - nodebuild_extract.cpp nodebuild_gl.cpp nodebuild_utility.cpp p_acs.cpp $ - p_buildmap.cpp p_ceiling.cpp p_conversation.cpp p_doors.cpp p_effect.cpp $ - p_enemy.cpp p_floor.cpp p_interaction.cpp p_lights.cpp p_lnspec.cpp p_map.cpp $ - p_maputl.cpp p_mobj.cpp p_pillar.cpp p_plats.cpp p_pspr.cpp p_saveg.cpp $ - p_sectors.cpp p_setup.cpp p_sight.cpp p_spec.cpp p_switch.cpp p_teleport.cpp $ - p_terrain.cpp p_things.cpp p_tick.cpp p_trace.cpp p_user.cpp p_writemap.cpp $ - p_xlat.cpp po_man.cpp r_bsp.cpp r_data.cpp r_draw.cpp r_drawt.cpp r_main.cpp $ - r_plane.cpp r_segs.cpp r_sky.cpp r_things.cpp r_polymost.cpp s_advsound.cpp $ - s_environment.cpp s_playlist.cpp s_sndseq.cpp s_sound.cpp sc_man.cpp skins.cpp $ - st_stuff.cpp stats.cpp stringtable.cpp tables.cpp tempfiles.cpp thingdef.cpp thingdef_codeptr.cpp $ - v_collection.cpp v_draw.cpp v_font.cpp v_palette.cpp v_pfx.cpp v_text.cpp $ - v_video.cpp vectors.cpp name.cpp zstring.cpp zstringpool.cpp zstrformat.cpp $ - w_wad.cpp wi_stuff.cpp a_arachnotron.cpp a_archvile.cpp a_bossbrain.cpp $ - a_bruiser.cpp a_cacodemon.cpp a_cyberdemon.cpp a_demon.cpp $ - a_doomarmor.cpp a_doomartifacts.cpp a_doomdecorations.cpp a_doomhealth.cpp $ - a_doomimp.cpp a_doomkeys.cpp a_doommisc.cpp a_doomplayer.cpp a_doomweaps.cpp $ - a_fatso.cpp a_keen.cpp a_lostsoul.cpp a_painelemental.cpp a_possessed.cpp $ - a_revenant.cpp a_scriptedmarine.cpp a_spidermaster.cpp doom_sbar.cpp a_beast.cpp $ - a_chicken.cpp a_clink.cpp a_dsparil.cpp a_hereticambience.cpp a_hereticarmor.cpp $ - a_hereticartifacts.cpp a_hereticdecorations.cpp a_hereticimp.cpp a_heretickeys.cpp $ - a_hereticmisc.cpp a_hereticplayer.cpp a_hereticweaps.cpp a_ironlich.cpp $ - a_knight.cpp a_mummy.cpp a_snake.cpp a_wizard.cpp heretic_sbar.cpp a_bats.cpp $ - a_bishop.cpp a_blastradius.cpp a_boostarmor.cpp a_centaur.cpp a_clericboss.cpp $ - a_clericflame.cpp a_clericholy.cpp a_clericmace.cpp a_clericplayer.cpp $ - a_clericstaff.cpp a_demons.cpp a_dragon.cpp a_ettin.cpp a_fighteraxe.cpp $ - a_fighterboss.cpp a_fighterhammer.cpp a_fighterplayer.cpp a_fighterquietus.cpp $ - a_firedemon.cpp a_flame.cpp a_flechette.cpp a_fog.cpp a_healingradius.cpp $ - a_heresiarch.cpp a_hexenarmor.cpp a_hexendecorations.cpp a_hexenkeys.cpp $ - a_hexenspecialdecs.cpp a_iceguy.cpp a_korax.cpp a_mageboss.cpp a_magecone.cpp $ - a_magelightning.cpp a_mageplayer.cpp a_magestaff.cpp a_magewand.cpp a_mana.cpp $ - a_pig.cpp a_puzzleitems.cpp a_scriptprojectiles.cpp a_serpent.cpp a_speedboots.cpp $ - a_spike.cpp a_summon.cpp a_teleportother.cpp a_weaponpiece.cpp a_wraith.cpp $ - hexen_sbar.cpp a_artiegg.cpp a_artitele.cpp a_minotaur.cpp a_ravenambient.cpp $ - a_ravenartifacts.cpp a_ravenhealth.cpp a_acolyte.cpp a_alienspectres.cpp $ - a_beggars.cpp a_coin.cpp a_crusader.cpp a_entityboss.cpp a_inquisitor.cpp $ - a_loremaster.cpp a_macil.cpp a_merchants.cpp a_oracle.cpp a_peasant.cpp $ - a_programmer.cpp a_questitems.cpp a_ratbuddy.cpp a_reaver.cpp a_rebels.cpp $ - a_sentinel.cpp a_spectral.cpp a_stalker.cpp a_strifeammo.cpp a_strifearmor.cpp $ - a_strifebishop.cpp a_strifeitems.cpp a_strifekeys.cpp a_strifeplayer.cpp $ - a_strifestuff.cpp a_strifeweapons.cpp a_templar.cpp a_thingstoblowup.cpp $ - a_zombie.cpp strife_sbar.cpp a_action.cpp a_artifacts.cpp a_bridge.cpp $ - a_camera.cpp a_debris.cpp a_decals.cpp a_flashfader.cpp a_fountain.cpp $ - a_hatetarget.cpp a_keys.cpp a_lightning.cpp a_movingcamera.cpp a_pickups.cpp $ - a_quake.cpp a_secrettrigger.cpp a_sectoraction.cpp a_sharedmisc.cpp a_skies.cpp $ - a_soundenvironment.cpp a_spark.cpp a_splashes.cpp a_waterzone.cpp a_weapons.cpp $ - hudmessages.cpp shared_sbar.cpp fmopl.cpp mlkernel.cpp mlopl.cpp mlopl_io.cpp $ - opl_mus_player.cpp fmodsound.cpp i_music.cpp i_sound.cpp music_cd.cpp $ - music_flac.cpp music_midi_midiout.cpp music_midi_stream.cpp music_midi_timidity.cpp $ - music_mod.cpp music_mus_midiout.cpp music_mus_opl.cpp music_stream.cpp $ - sample_flac.cpp crashcatcher.c i_input.cpp i_net.cpp i_cd.cpp i_main.cpp $ - i_system.cpp hardware.cpp i_movie.cpp sdlvideo.cpp autozend.cpp -${LINK} "${TARGET}" +:build_it +echo "- Building optimized version -" -# If we're not cleaning and zdoom.wad exists, exit now. -if "${EVILCLEAN}"="0" ifexist zdoom.wad exit 0 -#:makewad -LDFLAGS = '' -CFLAGS = '-Os -Wall -fomit-frame-pointer' +# This compiles a list of source files, one at a time. Files with the '.c' +# extension are compiled using the program specified in 'CC' (default: 'gcc'). +# The source files will have their extension changed to 'OBJ_EXT' (default +# value: '.o') when compiled, and be placed in 'OBJ_DIR'. 'CFLAGS' and +# 'CPPFLAGS' will be applied to the command line for C files. -src_paths tools/makewad -${COMPILE} makewad.c -${LINK} tools/makewad/makewad +dcop setLabel "Compiling cbuild.c..." +compile cbuild.c +dcop setProgress 1 -src_paths tools/xlatcc -${COMPILE} xlat-parse.tab.c gen.c -${LINK} tools/xlatcc/xlatcc -src_paths tools/dehsupp -${COMPILE} parse.tab.c -${LINK} tools/dehsupp/dehsupp +# linkexec will link the previously-compiled objects into the named file with +# the command named in 'LD' (default: 'gcc'). LDFLAGS will be applied to the +# end of the command line. The specified output file will have 'EXE_EXT' +# (default: '.exe' in Win32/DOS, nothing elsewhere) appended. -do if "${EVILCLEAN}"="1" - -rm "${OBJ_DIR}" - -rm "${DEP_DIR}" - -rm zdoomgcc.map - -rm zdoom.wad -else - call cd wadsrc && ../tools/makewad/makewad zdoom.lst - copy wadsrc/zdoom.wad ./ +dcop setLabel "Linking cbuild"${'EXE_EXT'}"..." +linkexec cbuild +dcop setProgress 2 + + +echo "" +echo "- Building debug version -" + +# This sets some debug cflags and sets the object extension to '-dbg.o', causing +# the source file to compile as 'cbuild-dbg.o' + +CFLAGS = "-MMD -g3" +OBJ_EXT = "-dbg.o" + +dcop setLabel "Compiling cbuild.c..." +compile cbuild.c +dcop setProgress 3 +dcop setLabel "Linking cbuild-dbg"${'EXE_EXT'}"..." +linkexec cbuild-dbg +dcop setProgress 4 + +echo "" + +# The getoptval directive gives the value of an option passed to the command +# line in the form of 'option=value' or 'option value'. Prefixing the command +# name with * causes the returned string to be encapsulated in 'hard quotes' +# (important for dealing with user input which may contain $ characters). + +INSTALL_PATH = $(*getoptval --install) + +define atexit_dcop +dcop close +ifnot ${'DCOP'}='' goto kde_install + + +# 'ifnot' will run the following command(s) if the two values (in the form x=y) +# are not equal. Putting the variable name in 'hard quotes' causes the expanded +# string to be encapsulated similarly (important when dealing with unknown +# input which may contain $ characters) + +do ifnot ${'INSTALL_PATH'}='' + INPUT = ${'INSTALL_PATH'} + goto check_dir done + +put "Do you wish to install CBuild? [y/N] " + +# 'read' will read user keyboard input until enter/return is pressed +read INPUT + +# 'ifnret' will execute the follow command if the previous command's return +# value is not the specified value. A return value of 0 typically indicates +# success (and non-0 is failure). +ifnret 0 exit 1 + + +if ${'INPUT'}='' exit 0 +if $(*tolower ${'INPUT'})='n' exit 0 +if $(*tolower ${'INPUT'})='no' exit 0 +if $(*tolower ${'INPUT'})='y' goto input_ok +if $(*tolower ${'INPUT'})='yes' goto input_ok + +echo "Invalid response '"${'INPUT'}"'" +echo "Aborting installation" +exit 0 + +:input_ok +do ifplat win32 + INSTALL_PATH = ${'WINDIR'} +else ifplat dos + INSTALL_PATH = C:/DOS +else + INSTALL_PATH = /usr/local/bin +done + +# 'fixpath' converts \ directory seperators to / in the specified var. This +# is required for CBuild to behave properly with directories +fixpath INSTALL_PATH + + +echo "" +echo "CBuild will install to '"${'INSTALL_PATH'}"'." +echo "If you wish to use a different location, please specify it below (press enter" +echo "for the default, type 'abort' to abort installation)" +put "-> " + +:get_path +read INPUT +ifnret 0 exit 1 + +fixpath INPUT + +do ifnot ${'INPUT'}='' + if $(*tolower ${'INPUT'})='abort' exit 0 +:check_dir + do ifnexist ${'INPUT'}/. + echo "" + echo "The directory '"${'INPUT'}"/' doesn't appear to be valid." + echo "Please specify a valid path, or 'abort' to abort installation." + put "-> " + goto get_path + done + INSTALL_PATH = ${'INPUT'} +done + +:copy_files +copy cbuild${EXE_EXT} ${'INSTALL_PATH'}/ +echo "" + +exit 0 + + +:clean + +# Here's the cleanup area, accessible if you pass "clean" to cbuild. "rmexec" +# deletes the specified executables (prepending 'EXE_EXT' to the filenames), +# and "rmobj" deletes the object and dependancy files that would be generated +# by compiling the specified file. Prepending a command with "-" will cause +# cbuild to continue even if the command fails, while prepending with '!' will +# cause cbuild to continue without any error messages. + +-rmexec cbuild cbuild-dbg + +-rmobj cbuild +OBJ_EXT = "-dbg.o" +-rmobj cbuild + +-rm "${OBJ_DIR}" "${DEP_DIR}" + +exit 0 + + +:kde_install + +# This portion is used to install using KDE's kdialog program for user +# interaction. Much nicer than needing to use the keyboard. + +# Ask if the user wants to install, if they didn't previously specify to +do if ${'INSTALL_PATH'}='' + dialog --title "Install CBuild?" --yesno "Do you wish to install CBuild?" + do ifnret 0 + @-rm /tmp/cbtmpxyz.txt + exit 0 + done + + INSTALL_PATH = /usr/local/bin + +:kde_get_path + # Get the install path from the user + dialog --title "Install CBuild in..." --getexistingdirectory ${'INSTALL_PATH'} + + # Read the specified path + setinput /tmp/cbtmpxyz.txt + read INSTALL_PATH + setinput + @-rm /tmp/cbtmpxyz.txt + + do ifnexist ${'INSTALL_PATH'} + dialog --title "CBuild install error" --error "Could not read install directory from kdialog! +Install aborted!" + + echo "Install failed!" + @-rm /tmp/cbtmpxyz.txt + exit 1 + done +done + + +# If we don't have write permissions, we'll need to use kdesu to try and get +# them. For larger projects, where you need to do much more than a simple copy, +# you can put the commands you need potential root access for into a seperate +# script, then call cbuild (with ${0}) using that script. + +do ifwrite ${'INSTALL_PATH'}/. + @!call cp cbuild${'EXE_EXT'} ${'INSTALL_PATH'}/ +else + @!call kdesu -t -c \"cp cbuild${'EXE_EXT'} ${'INSTALL_PATH'}/\" 2>/dev/null +done + + +# Make sure the copy succeeded + +do ifnret 0 + dialog --title "Error installing CBuild" --warningyesno "Could not copy cbuild to "${'INSTALL_PATH'}"! +This may be due to invalid permissions. Please check with your system administrator. +Select a different location?" + + ifret 0 goto kde_get_path + + echo "Install failed!" + @-rm /tmp/cbtmpxyz.txt + exit 1 +done + + +dialog --title "Install succeeded" --msgbox "Installation was successful! +CBuild has been installed in "${'INSTALL_PATH'} + +echo "Install succeeded!" +@-rm /tmp/cbtmpxyz.txt +exit 0