Line # Revision Author
1 1 kittycat #define foobarbaz /*
2 24 kittycat
3 1 kittycat # A shell script within a source file. Ugly, but it works...
4 23 moose
5 4 kittycat TRGT=`basename ${0/.c/.exe}`
6 1 kittycat for i in $@ ; do
7 if [ "$i" = "--make-compiled" ] ; then
8 echo "Compiling '$TRGT', please wait..."
9 gcc -W -Wall -O2 -o $TRGT $0
10 exit $?
11 fi
12 done
13
14 gcc -W -Wall -Werror -o /tmp/$TRGT "$0" && { "/tmp/$TRGT" $@ ; RET=$? ; rm -f "/tmp/$TRGT" ; exit $RET ; }
15 exit $?
16 24 kittycat
17 1 kittycat */
18
19 /* CBuild written by Chris Robinson, copyright 2005-2006
20 *
21 * Notice of Terms of Use
22 *
23 * CBuild is provided as-is for personal use. You may use and redistribute it
24 * in any manner, with the following terms and conditions:
25 *
26 * * You MAY NOT sell it, or otherwise redistribute it for profit, unless it is
27 * bundled with a seperate commercial product and is used to build said
28 * product.
29 * * You MAY modify it without recompense or notification to the author, as
30 * long as it is clearly marked as a derivitive work.
31 * * You MAY NOT claim it as your own sole work.
32 * * You MAY NOT remove or modify this notice.
33 */
34
35 /* Despite what some people may think, no, the name CBuild did not come from my
36 * first name. I got the name from the fact that it uses pure C, and only C. ;)
37 */
38
39 #include <stdio.h>
40 #include <ctype.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <fcntl.h>
46 #include <errno.h>
47 #include <setjmp.h>
48
49 28 kittycat #if defined(__unix__) || defined(__MACH__)
50 27 kittycat #include <sys/wait.h>
51 1 kittycat #include <unistd.h>
52 27 kittycat #else
53 #define WIFEXITED(x) (1)
54 #define WEXITSTATUS(x) (x)
55 1 kittycat #endif
56
57 #if defined(__unix__) || defined(__GNUC__)
58 #include <sys/param.h>
59 #include <dirent.h>
60 #endif
61
62 #ifdef _WIN32
63
64 #include <io.h>
65 #include <windows.h>
66
67 #ifdef _MSC_VER
68 // MSVC Sucks
69 #define strcasecmp stricmp
70 #define strncasecmp strnicmp
71 #define snprintf _snprintf
72 3 kittycat #define fileno _fileno
73 1 kittycat
74 #define PATH_MAX _MAX_PATH
75 #define lstat slat
76 #define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
77 #define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
78 #define S_IRUSR _S_IREAD
79 #define S_IWUSR _S_IWRITE
80 #define S_IXUSR _S_IEXEC
81 #define S_IRWXU (_S_IREAD | _S_IWRITE | _S_IEXEC)
82
83 21 kittycat #define STDIN_FILENO 0
84 #define STDOUT_FILENO 1
85 #define STDERR_FILENO 2
86
87 1 kittycat struct dirent {
88 char *d_name;
89 };
90
91 typedef struct {
92 long handle; /* -1 for failed rewind */
93 struct _finddata_t info;
94 struct dirent result; /* d_name null iff first time */
95 char *name; /* null-terminated char string */
96 } DIR;
97
98 DIR *opendir(const char *name)
99 {
100 DIR *dir = 0;
101
102 if(name && name[0])
103 {
104 /* search pattern must end with suitable wildcard */
105 size_t base_length = strlen(name);
106 const char *all = strchr("/\\", name[base_length - 1]) ? "*" : "/*";
107
108 if((dir=(DIR*)malloc(sizeof(*dir))) != 0 &&
109 (dir->name=(char*)malloc(base_length+strlen(all)+1)) != 0)
110 {
111 strcat(strcpy(dir->name, name), all);
112
113 if((dir->handle = (long) _findfirst(dir->name, &dir->info)) != -1)
114 {
115 dir->result.d_name = 0;
116 }
117 else /* rollback */
118 {
119 free(dir->name);
120 free(dir);
121 dir = NULL;
122 }
123 }
124 else /* rollback */
125 {
126 free(dir);
127 dir = NULL;
128 errno = ENOMEM;
129 }
130 }
131 else
132 errno = EINVAL;
133
134 return dir;
135 }
136
137 int closedir(DIR *dir)
138 {
139 int result = -1;
140
141 if(dir)
142 {
143 if(dir->handle != -1)
144 result = _findclose(dir->handle);
145
146 free(dir->name);
147 free(dir);
148 }
149
150 if(result == -1) /* map all errors to EBADF */
151 errno = EBADF;
152
153 return result;
154 }
155
156 struct dirent *readdir(DIR *dir)
157 {
158 struct dirent *result = 0;
159
160 if(dir && dir->handle != -1)
161 {
162 if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1)
163 {
164 result = &dir->result;
165 result->d_name = dir->info.name;
166 }
167 }
168 else
169 errno = EBADF;
170
171 return result;
172 }
173
174 void rewinddir(DIR *dir)
175 {
176 if(dir && dir->handle != -1)
177 {
178 _findclose(dir->handle);
179 dir->handle = (long)_findfirst(dir->name, &dir->info);
180 dir->result.d_name = 0;
181 }
182 else
183 errno = EBADF;
184 }
185
186 #endif /* _MSC_VER */
187
188
189 static int setenv(const char *env, const char *val, int overwrite)
190 {
191 3 kittycat #if 0
192 4 kittycat /* This doesn't set anything? */
193 1 kittycat if(!overwrite)
194 {
195 char buf[2];
196 if(GetEnvironmentVariable(env, buf, sizeof(buf)) != 0 ||
197 GetLastError() != ERROR_ENVVAR_NOT_FOUND)
198 return 0;
199 }
200 return (!SetEnvironmentVariable(env, (val&&*val)?val:NULL)) * -1;
201 3 kittycat #else
202 static char buf[64*1024];
203 if(!overwrite && getenv(env))
204 return 0;
205
206 snprintf(buf, sizeof(buf), "%s=%s", env, (val?val:""));
207 return _putenv(buf);
208 #endif
209 1 kittycat }
210
211 static int unsetenv(const char *env)
212 {
213 return setenv(env, "", 1);
214 }
215
216 #endif /* Win32 */
217
218
219 #define DECL_LIST(type, name) \
220 type (*name) = NULL; \
221 size_t name##_size = 0; \
222 size_t name##_len = 0
223
224 #define DECL_STATIC_LIST(type, name) \
225 static type (*name) = NULL; \
226 static size_t name##_size = 0; \
227 static size_t name##_len = 0
228
229 #define CLEAR_LIST(name) \
230 { \
231 name##_size = 0; \
232 name##_len = 0; \
233 free(name); \
234 name = NULL; \
235 }
236
237
238
239 typedef struct {
240 FILE *f;
241 char *fname;
242 char *bkp_lbuf;
243 char *bkp_nextline;
244 int bkp_line;
245 int bkp_did_else;
246 int bkp_did_cmds;
247 int bkp_do_level;
248 } INVOKE_BKP;
249 DECL_STATIC_LIST(INVOKE_BKP, invoke_backup);
250
251 typedef struct {
252 char **argv;
253 size_t argc;
254 } ARGS;
255 DECL_STATIC_LIST(ARGS, arg_backup);
256 static size_t argc;
257 DECL_STATIC_LIST(char*, argv);
258
259
260 static FILE *f;
261 static char *fname;
262 static struct stat statbuf;
263 static char linebuf[64*1024];
264 static char buffer[64*1024];
265 static char obj[PATH_MAX];
266
267 DECL_STATIC_LIST(char*, src_paths);
268
269 DECL_STATIC_LIST(char*, loaded_files);
270 DECL_STATIC_LIST(char*, sources);
271
272 static int curr_line = 0;
273 static char *nextline;
274
275 static jmp_buf jmpbuf;
276
277
278 4 kittycat static int stdi_bak = -1;
279 1 kittycat static int stdo_bak = -1;
280 static int stde_bak = -1;
281 static FILE *stde_stream = NULL;
282 // Make a define so we'll always have access to the real stderr
283 #define USEABLE_ERR ((stde_stream)?stde_stream:stderr)
284
285 4 kittycat
286 1 kittycat typedef struct {
287 char *name;
288 char *val;
289 } DEF;
290 DECL_STATIC_LIST(DEF, defines);
291
292
293
294
295 static inline void resize_list(void **ptr, size_t count, size_t type_size,
296 size_t *len, size_t *size)
297 {
298 15 kittycat if(count == 0)
299 {
300 *size = 0;
301 *len = 0;
302 free(*ptr);
303 *ptr = NULL;
304 return;
305 }
306
307 1 kittycat if(count < (*len)/2 || count > *len)
308 {
309 void *tmp;
310 size_t newlen = count-1;
311 size_t i;
312
313 for(i = 1;i < sizeof(size_t)*8;i*=2)
314 newlen |= newlen>>i;
315 ++newlen;
316
317 tmp = realloc(*ptr, type_size*newlen);
318 if(!tmp)
319 {
320 fprintf(USEABLE_ERR, "\n\n*** Critical Error ***\n"
321 "Out of memory allocating %u bytes!\n",
322 26 kittycat (unsigned int)(type_size*newlen));
323 1 kittycat strcpy(linebuf, "exit -1\n");
324 longjmp(jmpbuf, 1);
325 }
326 *ptr = tmp;
327 *len = newlen;
328 }
329 *size = count;
330 }
331 #define RESIZE_LIST(name, count) \
332 20 kittycat { \
333 void *vptr = name; \
334 resize_list(&vptr, count, sizeof(*name), &name##_len, &name##_size); \
335 name = vptr; \
336 }
337 1 kittycat
338
339 static int libify_name(char *buf, size_t buflen, char *name);
340
341
342 /* getvar: Safely gets an environment variable, returning an empty string
343 * instead of NULL
344 */
345 static const char *getvar(const char *env)
346 {
347 const char *var = getenv(env);
348 return (var?var:"");
349 }
350
351 /* find_src: Attempts to find the named sourcefile by searching the paths
352 * listed in src_paths. It returns the passed string if the file exists as-is,
353 * or if it couldn't be found.
354 */
355 static char *find_src(char *src)
356 {
357 static char buf[PATH_MAX];
358 struct stat statbuf;
359 size_t i;
360
361 if(stat(src, &statbuf) == 0 || src_paths_size == 0)
362 return src;
363
364 for(i = 0;i < src_paths_size;++i)
365 {
366 snprintf(buf, sizeof(buf), "%s/%s", src_paths[i], src);
367 if(stat(buf, &statbuf) == 0)
368 return buf;
369 }
370 return src;
371 }
372
373
374 #define BUF_SIZE (64*1024)
375 /* expand_string:
376 * The meat of the parser. Reads a string buffer of len bytes, expanding
377 * sub-commands and variables, filling in &entity;'s, and dealing with
378 * escaped characters, until one of the characters denoted in 'stp' is
379 * encountered, non-escaped and outside of quotes, and return a pointer to
380 * that location. If fillmore is non-0, it'll read more data from disk as
381 * needed.
382 */
383 static char *expand_string(char *str, const char *stp, size_t len,
384 int fillmore)
385 {
386 char *buf, *ptr, *last_pos;
387 int in_quotes = 0;
388 int use_hard_quotes = 0;
389 char *end;
390 int i;
391
392 if(!(*str) && !fillmore)
393 return str;
394
395 buf = malloc(BUF_SIZE);
396 if(!buf)
397 {
398 strcpy(linebuf, "exit -1\n");
399 longjmp(jmpbuf, 1);
400 }
401
402 last_pos = str;
403 do {
404 ptr = last_pos;
405 while(1)
406 {
407 4 kittycat if(fillmore)
408 1 kittycat {
409 4 kittycat if(!(*ptr))
410 1 kittycat {
411 17 kittycat if(nextline)
412 1 kittycat {
413 17 kittycat snprintf(ptr, len+str-ptr, "\n%s", nextline);
414 free(nextline);
415 nextline = NULL;
416 1 kittycat }
417 17 kittycat else
418 {
419 if(fgets(ptr, len+str-ptr, f) == NULL)
420 {
421 free(buf);
422 return ptr;
423 }
424 ++curr_line;
425 }
426 1 kittycat }
427 }
428
429
430 if(*ptr == '$')
431 {
432 if(in_quotes != '\'')
433 break;
434 }
435 else if(*ptr == '#')
436 {
437 if(!in_quotes)
438 {
439 char *next = strchr(ptr, '\n');
440 if(!next) next = "";
441 memmove(ptr, next, strlen(next)+1);
442 continue;
443 }
444 }
445
446
447 if(!in_quotes)
448 {
449 i = 0;
450 do {
451 if((stp[i] == ' ' && isspace(*ptr)) ||
452 (stp[i] == '!' && !isspace(*ptr)) ||
453 (stp[i] == '^' && !isalpha(*ptr)) ||
454 *ptr == stp[i])
455 {
456 free(buf);
457 return ptr;
458 }
459 } while(stp[i++]);
460 }
461
462
463 if(*ptr == '&')
464 {
465 if(in_quotes != '\'')
466 {
467 unsigned int val = '?';
468
469 end = NULL;
470
471 if(ptr[1] != '#')
472 {
473 static struct {
474 char *name;
475 unsigned int val;
476 } val_tab[] = {
477 { "Aacute", 0x00C1 }, { "aacute", 0x00E1 },
478 { "Acirc", 0x00C2 }, { "acirc", 0x00E2 },
479 { "acute", 0x00B4 }, { "AElig", 0x00C6 },
480 { "aelig", 0x00E6 }, { "Agrave", 0x00C0 },
481 { "agrave", 0x00E0 }, { "alefsym", 0x2135 },
482 { "Alpha", 0x0391 }, { "alpha", 0x03B1 },
483 { "amp", 0x0026 }, { "and", 0x2227 },
484 { "ang", 0x2220 }, { "Aring", 0x00C5 },
485 { "aring", 0x00E5 }, { "asymp", 0x2248 },
486 { "Atilde", 0x00C3 }, { "atilde", 0x00E3 },
487 { "Auml", 0x00C4 }, { "auml", 0x00E4 },
488 { "bdquo", 0x201E }, { "Beta", 0x0392 },
489 { "beta", 0x03B2 }, { "brvbar", 0x00A6 },
490 { "bull", 0x2022 }, { "cap", 0x2229 },
491 { "Ccedil", 0x00C7 }, { "ccedil", 0x00E7 },
492 { "cedil", 0x00B8 }, { "cent", 0x00A2 },
493 { "Chi", 0x03A7 }, { "chi", 0x03C7 },
494 { "circ", 0x02C6 }, { "clubs", 0x2663 },
495 { "cong", 0x2245 }, { "copy", 0x00A9 },
496 { "crarr", 0x21B5 }, { "cup", 0x222A },
497 { "curren", 0x00A4 }, { "Dagger", 0x2021 },
498 { "dagger", 0x2020 }, { "dArr", 0x21D3 },
499 { "darr", 0x2193 }, { "deg", 0x00B0 },
500 { "Delta", 0x0394 }, { "delta", 0x03B4 },
501 { "diams", 0x2666 }, { "divide", 0x00F7 },
502 { "Eacute", 0x00C9 }, { "eacute", 0x00E9 },
503 { "Ecirc", 0x00CA }, { "ecirc", 0x00EA },
504 { "Egrave", 0x00C8 }, { "egrave", 0x00E8 },
505 { "empty", 0x2205 }, { "emsp", 0x2003 },
506 { "ensp", 0x2002 }, { "Epsilon", 0x0395 },
507 { "epsilon", 0x03B5 }, { "equiv", 0x2261 },
508 { "Eta", 0x0397 }, { "eta", 0x03B7 },
509 { "ETH", 0x00D0 }, { "eth", 0x00F0 },
510 { "Euml", 0x00CB }, { "euml", 0x00EB },
511 { "euro", 0x20AC }, { "exist", 0x2203 },
512 { "fnof", 0x0192 }, { "forall", 0x2200 },
513 { "frac12", 0x00BD }, { "frac14", 0x00BC },
514 { "frac34", 0x00BE }, { "frasl", 0x2044 },
515 { "Gamma", 0x0393 }, { "gamma", 0x03B3 },
516 { "ge", 0x2265 }, { "gt", 0x003E },
517 { "hArr", 0x21D4 }, { "harr", 0x2194 },
518 { "hearts", 0x2665 }, { "hellip", 0x2026 },
519 { "Iacute", 0x00CD }, { "iacute", 0x00ED },
520 { "Icirc", 0x00CE }, { "icirc", 0x00EE },
521 { "iexcl", 0x00A1 }, { "Igrave", 0x00CC },
522 { "igrave", 0x00EC }, { "image", 0x2111 },
523 { "infin", 0x221E }, { "int", 0x222B },
524 { "Iota", 0x0399 }, { "iota", 0x03B9 },
525 { "iquest", 0x00BF }, { "isin", 0x2208 },
526 { "Iuml", 0x00CF }, { "iuml", 0x00EF },
527 { "Kappa", 0x039A }, { "kappa", 0x03BA },
528 { "Lambda", 0x039B }, { "lambda", 0x03BB },
529 { "lang", 0x2329 }, { "laquo", 0x00AB },
530 { "lArr", 0x21D0 }, { "larr", 0x2190 },
531 { "lceil", 0x2308 }, { "ldquo", 0x201C },
532 { "le", 0x2264 }, { "lfloor", 0x230A },
533 { "lowast", 0x2217 }, { "loz", 0x25CA },
534 { "lrm", 0x200E }, { "lsaquo", 0x2039 },
535 { "lsquo", 0x2018 }, { "lt", 0x003C },
536 { "macr", 0x00AF }, { "mdash", 0x2014 },
537 { "micro", 0x00B5 }, { "middot", 0x00B7 },
538 { "minus", 0x2212 }, { "Mu", 0x039C },
539 { "mu", 0x03BC }, { "nabla", 0x2207 },
540 { "nbsp", 0x00A0 }, { "ndash", 0x2013 },
541 { "ne", 0x2260 }, { "ni", 0x220B },
542 { "not", 0x00AC }, { "notin", 0x2209 },
543 { "nsub", 0x2284 }, { "Ntilde", 0x00D1 },
544 { "ntilde", 0x00F1 }, { "Nu", 0x039D },
545 { "nu", 0x03BD }, { "Oacute", 0x00D3 },
546 { "oacute", 0x00F3 }, { "Ocirc", 0x00D4 },
547 { "ocirc", 0x00F4 }, { "OElig", 0x0152 },
548 { "oelig", 0x0153 }, { "Ograve", 0x00D2 },
549 { "ograve", 0x00F2 }, { "oline", 0x203E },
550 { "Omega", 0x03A9 }, { "omega", 0x03C9 },
551 { "Omicron", 0x039F }, { "omicron", 0x03BF },
552 { "oplus", 0x2295 }, { "or", 0x2228 },
553 { "ordf", 0x00AA }, { "ordm", 0x00BA },
554 { "Oslash", 0x00D8 }, { "oslash", 0x00F8 },
555 { "Otilde", 0x00D5 }, { "otilde", 0x00F5 },
556 { "otimes", 0x2297 }, { "Ouml", 0x00D6 },
557 { "ouml", 0x00F6 }, { "para", 0x00B6 },
558 { "part", 0x2202 }, { "permil", 0x2030 },
559 { "perp", 0x22A5 }, { "Phi", 0x03A6 },
560 { "phi", 0x03C6 }, { "Pi", 0x03A0 },
561 { "pi", 0x03C0 }, { "piv", 0x03D6 },
562 { "plusmn", 0x00B1 }, { "pound", 0x00A3 },
563 { "Prime", 0x2033 }, { "prime", 0x2032 },
564 { "prod", 0x220F }, { "prop", 0x221D },
565 { "Psi", 0x03A8 }, { "psi", 0x03C8 },
566 { "quot", 0x0022 }, { "radic", 0x221A },
567 { "rang", 0x232A }, { "raquo", 0x00BB },
568 { "rArr", 0x21D2 }, { "rarr", 0x2192 },
569 { "rceil", 0x2309 }, { "rdquo", 0x201D },
570 { "real", 0x211C }, { "reg", 0x00AE },
571 { "rfloor", 0x230B }, { "Rho", 0x03A1 },
572 { "rho", 0x03C1 }, { "rlm", 0x200F },
573 { "rsaquo", 0x203A }, { "rsquo", 0x2019 },
574 { "sbquo", 0x201A }, { "Scaron", 0x0160 },
575 { "scaron", 0x0161 }, { "sdot", 0x22C5 },
576 { "sect", 0x00A7 }, { "shy", 0x00AD },
577 { "Sigma", 0x03A3 }, { "sigma", 0x03C3 },
578 { "sigmaf", 0x03C2 }, { "sim", 0x223C },
579 { "spades", 0x2660 }, { "sub", 0x2282 },
580 { "sube", 0x2286 }, { "sum", 0x2211 },
581 { "sup", 0x2283 }, { "sup1", 0x00B9 },
582 { "sup2", 0x00B2 }, { "sup3", 0x00B3 },
583 { "supe", 0x2287 }, { "szlig", 0x00DF },
584 { "Tau", 0x03A4 }, { "tau", 0x03C4 },
585 { "there4", 0x2234 }, { "Theta", 0x0398 },
586 { "theta", 0x03B8 }, { "thetasym", 0x03D1 },
587 { "thinsp", 0x2009 }, { "THORN", 0x00DE },
588 { "thorn", 0x00FE }, { "tilde", 0x02DC },
589 { "times", 0x00D7 }, { "trade", 0x2122 },
590 { "Uacute", 0x00DA }, { "uacute", 0x00FA },
591 { "uArr", 0x21D1 }, { "uarr", 0x2191 },
592 { "Ucirc", 0x00DB }, { "ucirc", 0x00FB },
593 { "Ugrave", 0x00D9 }, { "ugrave", 0x00F9 },
594 { "uml", 0x00A8 }, { "upsih", 0x03D2 },
595 { "Upsilon", 0x03A5 }, { "upsilon", 0x03C5 },
596 { "Uuml", 0x00DC }, { "uuml", 0x00FC },
597 { "weierp", 0x2118 }, { "Xi", 0x039E },
598 { "xi", 0x03BE }, { "Yacute", 0x00DD },
599 { "yacute", 0x00FD }, { "yen", 0x00A5 },
600 { "Yuml", 0x0178 }, { "yuml", 0x00FF },
601 { "Zeta", 0x0396 }, { "zeta", 0x03B6 },
602 { "zwj", 0x200D }, { "zwnj", 0x200C },
603 { NULL, '?' }
604 };
605 int i;
606
607 end = expand_string(ptr+1, " ;", len+str-ptr-1,
608 fillmore);
609 if(*end == ';')
610 *(end++) = 0;
611
612 for(i = 0;val_tab[i].name;++i)
613 {
614 if(strncmp(val_tab[i].name, ptr+1, end-ptr-1) == 0)
615 break;
616 }
617 val = val_tab[i].val;
618 }
619 else
620 {
621 val = strtoul(ptr+2, &end, 0);
622 if(*end == ';')
623 ++end;
624 if(end == ptr+2)
625 val = '?';
626 }
627
628 if(val <= 0x7F)
629 {
630 if(val > 0)
631 *(ptr++) = val;
632 }
633 else if(val <= 0x7FF)
634 {
635 *(ptr++) = 0xC0 | (val>>6);
636 *(ptr++) = 0x80 | (val&0x3F);
637 }
638 else if(val <= 0xFFFF)
639 {
640 *(ptr++) = 0xE0 | (val>>12);
641 *(ptr++) = 0x80 | ((val>>6)&0x3F);
642 *(ptr++) = 0x80 | (val&0x3F);
643 }
644 else if(val <= 0x10FFFF)
645 {
646 *(ptr++) = 0xF0 | (val>>18);
647 *(ptr++) = 0x80 | ((val>>12)&0x3F);
648 *(ptr++) = 0x80 | ((val>>6)&0x3F);
649 *(ptr++) = 0x80 | (val&0x3F);
650 }
651
652 if(end != ptr)
653 memmove(ptr, end, strlen(end)+1);
654 continue;
655 }
656 }
657 else if(*ptr == '"' || *ptr == '\'')
658 {
659 if(!in_quotes || in_quotes == *ptr)
660 {
661 in_quotes ^= *ptr;
662 memmove(ptr, ptr+1, strlen(ptr));
663 continue;
664 }
665 }
666 else if(*ptr == '\\')
667 memmove(ptr, ptr+1, strlen(ptr));
668
669 if(*ptr) ++ptr;
670 }
671
672 last_pos = ptr;
673 *(ptr++) = 0;
674
675 use_hard_quotes = 0;
676
677 /* Run a special command, replacing the section */
678 if(*ptr == '(')
679 {
680 char *next = NULL;
681 char *opt;
682
683 ++ptr;
684
685 if(*ptr == '*')
686 {
687 use_hard_quotes = 1;
688 ++ptr;
689 }
690
691 opt = expand_string(ptr, " )", len+str-ptr, fillmore);
692 if(!(*opt) || !isspace(*opt))
693 {
694 *opt = 0;
695 fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n"
696 "Malformed '%s' sub-command!\n\n", fname,
697 curr_line, ptr);
698 free(buf);
699 strcpy(linebuf, "exit -1\n");
700 longjmp(jmpbuf, 1);
701 }
702 *(opt++) = 0;
703 opt = expand_string(opt, "!", len+str-opt, fillmore);
704
705 if(use_hard_quotes)
706 i = snprintf(buf, BUF_SIZE, "%s'", str);
707 else
708 i = snprintf(buf, BUF_SIZE, "%s", str);
709
710 /* Replaces the section with the specified command line
711 * option's value (in the format 'option=value') */
712 if(strcasecmp(ptr, "getoptval") == 0)
713 {
714 const char *val = "";
715 size_t optlen, idx;
716
717 next = expand_string(opt, ")", len+str-opt, fillmore);
718 if(*next) *(next++) = 0;
719
720 optlen = strlen(opt);
721 for(idx = 1;idx < argc;++idx)
722 {
723 if(strncasecmp(opt, argv[idx], optlen) == 0)
724 {
725 if(argv[idx][optlen] == '=')
726 val = argv[idx]+optlen+1;
727 else if(argv[idx][optlen] == 0)
728 val = argv[idx+1];
729 else
730 continue;
731 break;
732 }
733 }
734 snprintf(buf+i, BUF_SIZE-i, "%s", val);
735 }
736
737 else if(strcasecmp(ptr, "word") == 0)
738 {
739 unsigned long val;
740 char *sep = expand_string(opt, ",)", len+str-opt, fillmore);
741 if(*sep != ',')
742 {
743 fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n"
744 "Malformed '%s' sub-command!\n\n", fname,
745 curr_line, ptr);
746 free(buf);
747 strcpy(linebuf, "exit -1\n");
748 longjmp(jmpbuf, 1);
749 }
750 *(sep++) = 0;
751 val = strtoul(opt, NULL, 0);
752
753 opt = expand_string(sep, "!", len+str-sep, fillmore);
754
755 while(1)
756 {
757 char *next_word = expand_string(opt, " )", len+str-opt,
758 fillmore);
759 11 kittycat if(next_word == opt)
760 1 kittycat {
761 11 kittycat if(isspace(*opt))
762 {
763 opt = expand_string(opt, "!", len+str-opt,
764 fillmore);
765 continue;
766 }
767 12 kittycat *(next_word++) = 0;
768 19 kittycat next = next_word;
769 11 kittycat break;
770 1 kittycat }
771 11 kittycat if(isspace(*next_word))
772 1 kittycat {
773 *(next_word++) = 0;
774 next_word = expand_string(next_word, "!",
775 len+str-next_word, fillmore);
776 }
777 else
778 {
779 next = next_word;
780 if(*next) *(next++) = 0;
781 if(val == 1)
782 snprintf(buf+i, BUF_SIZE-i, "%s", opt);
783 break;
784 }
785 --val;
786
787 if(val == 0)
788 {
789 snprintf(buf+i, BUF_SIZE-i, "%s", opt);
790 opt = next_word;
791 next = expand_string(opt, ")", len+str-opt, fillmore);
792 if(*next) *(next++) = 0;
793 break;
794 }
795 opt = next_word;
796 }
797 }
798
799 else if(strcasecmp(ptr, "add")==0 || strcasecmp(ptr, "sub") == 0 ||
800 strcasecmp(ptr, "mult")==0 || strcasecmp(ptr, "div") == 0)
801 {
802 long val1, val2;
803 char *sep = expand_string(opt, ",)", len+str-opt, fillmore);
804 if(*sep != ',')
805 {
806 fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n"
807 "Malformed '%s' sub-command!\n\n", fname,
808 curr_line, ptr);
809 free(buf);
810 strcpy(linebuf, "exit -1\n");
811 longjmp(jmpbuf, 1);
812 }
813 *(sep++) = 0;
814
815 next = expand_string(sep, ")", len+str-sep, fillmore);
816 if(*next) *(next++) = 0;
817
818 val1 = atoi(opt);
819 val2 = atoi(sep);
820
821 if(strcasecmp(ptr, "add") == 0)
822 val1 += val2;
823 else if(strcasecmp(ptr, "sub") == 0)
824 val1 -= val2;
825 else if(strcasecmp(ptr, "mult") == 0)
826 val1 *= val2;
827 else if(strcasecmp(ptr, "div") == 0)
828 {
829 if(!val2)
830 {
831 fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n"
832 "Divide-by-0 attempted!\n\n", fname,
833 curr_line);
834 free(buf);
835 strcpy(linebuf, "exit -1\n");
836 longjmp(jmpbuf, 1);
837 }
838 val1 /= val2;
839 }
840
841 snprintf(buf+i, BUF_SIZE-i, "%ld", val1);
842 }
843
844 /* Returns a library-style name from the specified
845 * filename */
846 else if(strcasecmp(ptr, "libname") == 0)
847 {
848 next = expand_string(opt, ")", len+str-opt, fillmore);
849 if(*next) *(next++) = 0;
850
851 libify_name(obj, sizeof(obj), opt);
852 snprintf(buf+i, BUF_SIZE-i, "%s", obj);
853 }
854
855 /* Returns the full filename for the specified source file by
856 * searching src_path */
857 else if(strcasecmp(ptr, "findsrc") == 0)
858 {
859 int inc = i;
860 12 kittycat int loop = 1;
861 1 kittycat
862 12 kittycat while(loop)
863 1 kittycat {
864 char *next_word = expand_string(opt, " )", len+str-opt,
865 fillmore);
866 11 kittycat if(next_word == opt)
867 1 kittycat {
868 11 kittycat if(isspace(*opt))
869 {
870 opt = expand_string(opt, "!", len+str-opt,
871 fillmore);
872 continue;
873 }
874 12 kittycat *(next_word++) = 0;
875 13 kittycat opt = next_word;
876 11 kittycat break;
877 1 kittycat }
878 if(isspace(*next_word))
879 {
880 *(next_word++) = 0;
881 next_word = expand_string(next_word, "!",
882 len+str-next_word, fillmore);
883 }
884 12 kittycat else
885 {
886 *(next_word++) = 0;
887 loop = 0;
888 }
889 1 kittycat
890 inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ",
891 find_src(opt));
892
893 opt = next_word;
894 }
895 if(inc > i) buf[inc-1] = 0;
896 next = opt;
897 }
898
899 /* Returns the string, lower-cased */
900 else if(strcasecmp(ptr, "tolower") == 0)
901 {
902 int inc = i;
903
904 next = expand_string(opt, ")", len+str-opt, fillmore);
905 if(*next) *(next++) = 0;
906
907 snprintf(buf+i, BUF_SIZE-i, "%s", opt);
908 while(buf[inc])
909 {
910 buf[inc] = tolower(buf[inc]);
911 ++inc;
912 }
913 }
914
915 /* Returns the string, upper-cased */
916 else if(strcasecmp(ptr, "toupper") == 0)
917 {
918 int inc = i;
919
920 next = expand_string(opt, ")", len+str-opt, fillmore);
921 if(*next) *(next++) = 0;
922
923 snprintf(buf+i, BUF_SIZE-i, "%s", opt);
924 while(buf[inc])
925 {
926 buf[inc] = toupper(buf[inc]);
927 ++inc;
928 }
929 }
930
931
932 else if(strcasecmp("ifeq", ptr) == 0)
933 {
934 char *var2;
935 char *val;
936
937 var2 = expand_string(opt, ",)", len+str-opt, fillmore);
938 if(*var2 != ',')
939 {
940 fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n"
941 "Malformed 'ifeq' sub-command!\n\n",
942 fname, curr_line);
943 free(buf);
944 strcpy(linebuf, "exit -1\n");
945 longjmp(jmpbuf, 1);
946 }
947 *(var2++) = 0;
948 val = expand_string(var2, ",)", len+str-var2, fillmore);
949 if(*val != ',')
950 {
951 fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n"
952 "Malformed 'ifeq' sub-command!\n\n",
953 fname, curr_line);
954 free(buf);
955 strcpy(linebuf, "exit -1\n");
956 longjmp(jmpbuf, 1);
957 }
958 *(val++) = 0;
959 if(strcmp(opt, var2) == 0)
960 {
961 char *sep = expand_string(val, ",)", len+str-val,
962 fillmore);
963 if(*sep) *(sep++) = 0;
964 next = expand_string(sep, ")", len+str-sep, fillmore);
965 if(*next) *(next++) = 0;
966 }
967 else
968 {
969 val = expand_string(val, ",)", len+str-val, fillmore);
970 if(*val == ',') ++val;
971 next = expand_string(val, ")", len+str-val, fillmore);
972 if(*next) *(next++) = 0;
973 }
974
975 if(val)
976 snprintf(buf+i, BUF_SIZE-i, "%s", val);
977 }
978
979 else if(strcasecmp("suffix", ptr) == 0)
980 {
981 char *val;
982 int inc = i;
983 12 kittycat int loop = 1;
984 1 kittycat
985 12 kittycat while(loop)
986 1 kittycat {
987 char *next_word = expand_string(opt, " )", len+str-opt,
988 fillmore);
989 11 kittycat if(next_word == opt)
990 1 kittycat {
991 11 kittycat if(isspace(*opt))
992 {
993 opt = expand_string(opt, "!", len+str-opt,
994 fillmore);
995 continue;
996 }
997 12 kittycat *(next_word++) = 0;
998 13 kittycat opt = next_word;
999 11 kittycat break;
1000 1 kittycat }
1001 11 kittycat if(isspace(*next_word))
1002 1 kittycat {
1003 *(next_word++) = 0;
1004 next_word = expand_string(next_word, "!",
1005 len+str-next_word, fillmore);
1006 }
1007 12 kittycat else
1008 {
1009 *(next_word++) = 0;
1010 loop = 0;
1011 }
1012 1 kittycat
1013 val = strrchr(opt, '/');
1014 if(!val)
1015 val = opt;
1016 val = strrchr(val, '.');
1017 if(val)
1018 inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ", val);
1019 opt = next_word;
1020 }
1021 if(inc > i) buf[inc-1] = 0;
1022 next = opt;
1023 }
1024
1025 else if(strcasecmp("basename", ptr) == 0)
1026 {
1027 char *val;
1028 int inc = i;
1029 12 kittycat int loop = 1;
1030 1 kittycat
1031 12 kittycat while(loop)
1032 1 kittycat {
1033 char *next_word = expand_string(opt, " )", len+str-opt,
1034 fillmore);
1035 11 kittycat if(next_word == opt)
1036 1 kittycat {
1037 11 kittycat if(isspace(*opt))
1038 {
1039 opt = expand_string(opt, "!", len+str-opt,
1040 fillmore);
1041 continue;
1042 }
1043 12 kittycat *(next_word++) = 0;
1044 13 kittycat opt = next_word;
1045 11 kittycat break;
1046 1 kittycat }
1047 11 kittycat if(isspace(*next_word))
1048 1 kittycat {
1049 *(next_word++) = 0;
1050 next_word = expand_string(next_word, "!",
1051 len+str-next_word, fillmore);
1052 }
1053 12 kittycat else
1054 {
1055 *(next_word++) = 0;
1056 loop = 0;
1057 }
1058 1 kittycat
1059 val = strrchr(opt, '/');
1060 if(!val)
1061 val = opt;
1062 val = strrchr(val, '.');
1063 if(val) *val = 0;
1064 inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ", opt);
1065
1066 opt = next_word;
1067 }
1068 if(inc > i) buf[inc-1] = 0;
1069 next = opt;
1070 }
1071
1072
1073 else if(strcasecmp("addprefix", ptr) == 0)
1074 {
1075 char *val;
1076 int inc = i;
1077 12 kittycat int loop = 1;
1078 1 kittycat
1079 val = opt;
1080 opt = expand_string(opt, ",)", len+str-opt, fillmore);
1081 if(*opt != ',')
1082 {
1083 fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n"
1084 "Malformed 'addprefix' sub-command!\n\n",
1085 fname, curr_line);
1086 free(buf);
1087 strcpy(linebuf, "exit -1\n");
1088 longjmp(jmpbuf, 1);
1089 }
1090 *(opt++) = 0;
1091 opt = expand_string(opt, "!", len+str-opt, fillmore);
1092
1093 12 kittycat while(loop)
1094 1 kittycat {
1095 char *next_word = expand_string(opt, " )", len+str-opt,
1096 fillmore);
1097 11 kittycat if(next_word == opt)
1098 1 kittycat {
1099 11 kittycat if(isspace(*opt))
1100 {
1101 opt = expand_string(opt, "!", len+str-opt,
1102 fillmore);
1103 continue;
1104 }
1105 12 kittycat *(next_word++) = 0;
1106 13 kittycat opt = next_word;
1107 11 kittycat break;
1108 1 kittycat }
1109 11 kittycat if(isspace(*next_word))
1110 1 kittycat {
1111 *(next_word++) = 0;
1112 next_word = expand_string(next_word, "!",
1113 len+str-next_word, fillmore);
1114 }
1115 12 kittycat else
1116 {
1117 *(next_word++) = 0;
1118 loop = 0;
1119 }
1120 1 kittycat
1121 inc += snprintf(buf+inc, BUF_SIZE-inc, "%s%s ", val,
1122 opt);
1123
1124 opt = next_word;
1125 }
1126 if(inc > i) buf[inc-1] = 0;
1127 next = opt;
1128 }
1129
1130 else if(strcasecmp("addsuffix", ptr) == 0)
1131 {
1132 char *val;
1133 int inc = i;
1134 12 kittycat int loop = 1;
1135 1 kittycat
1136 val = opt;
1137 opt = expand_string(opt, ",)", len+str-opt, fillmore);
1138 if(*opt != ',')
1139 {
1140 fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n"
1141 "Malformed 'addprefix' sub-command!\n\n",
1142 fname, curr_line);
1143 free(buf);
1144 strcpy(linebuf, "exit -1\n");
1145 longjmp(jmpbuf, 1);
1146 }
1147 *(opt++) = 0;
1148 opt = expand_string(opt, "!", len+str-opt, fillmore);
1149
1150 12 kittycat while(loop)
1151 1 kittycat {
1152 char *next_word = expand_string(opt, " )", len+str-opt,
1153 fillmore);
1154 11 kittycat if(next_word == opt)
1155 1 kittycat {
1156 11 kittycat if(isspace(*opt))
1157 {
1158 opt = expand_string(opt, "!", len+str-opt,
1159 fillmore);
1160 continue;
1161 }
1162 12 kittycat *(next_word++) = 0;
1163 13 kittycat opt = next_word;
1164 11 kittycat break;
1165 1 kittycat }
1166 11 kittycat if(isspace(*next_word))
1167 1 kittycat {
1168 *(next_word++) = 0;
1169 next_word = expand_string(next_word, "!",
1170 len+str-next_word, fillmore);
1171 }
1172 12 kittycat else
1173 {
1174 *(next_word++) = 0;
1175 loop = 0;
1176 }
1177 1 kittycat
1178 inc += snprintf(buf+inc, BUF_SIZE-inc, "%s%s ", opt,
1179 val);
1180
1181 opt = next_word;
1182 }
1183 if(inc > i) buf[inc-1] = 0;
1184 next = opt;
1185 }
1186
1187 else if(strcasecmp("join", ptr) == 0)
1188 {
1189 int inc = i;
1190 size_t p;
1191 DECL_LIST(char*, words);
1192
1193 do {
1194 char *next_word = expand_string(opt, " ,)", len+str-opt,
1195 fillmore);
1196 if(*next_word == ')')
1197 {
1198 fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n"
1199 "Malformed 'join' sub-command!\n\n",
1200 fname, curr_line);
1201 free(buf);
1202 strcpy(linebuf, "exit -1\n");
1203 longjmp(jmpbuf, 1);
1204 }
1205 RESIZE_LIST(words, words_size+1);
1206 if(*next_word == ',')
1207 {
1208 *(next_word++) = 0;
1209 words[words_size-1] = opt;
1210 opt = expand_string(next_word, "!",
1211 len+str-next_word, fillmore);
1212 break;
1213 }
1214
1215 *(next_word++) = 0;
1216 words[words_size-1] = opt;
1217
1218 opt = expand_string(next_word, "!", len+str-next_word,
1219 fillmore);
1220 if(*opt == ',')
1221 {
1222 ++opt;
1223 break;
1224 }
1225 } while(1);
1226
1227 opt = expand_string(opt, "!", len+str-opt, fillmore);
1228 p = 0;
1229 do {
1230 char *next_word = expand_string(opt, " )", len+str-opt,
1231 fillmore);
1232 if(*next_word == ')')
1233 {
1234 *(next_word++) = 0;
1235 if(p < words_size || *opt)
1236 {
1237 inc += snprintf(buf+inc, BUF_SIZE-inc, "%s%s ",
1238 ((p<words_size)?words[p++]:""),
1239 opt);
1240 while(p < words_size)
1241 inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ",
1242 words[p++]);
1243 }
1244 13 kittycat *(next_word++) = 0;
1245 1 kittycat opt = next_word;
1246 break;
1247 }
1248
1249 *(next_word++) = 0;
1250 inc += snprintf(buf+inc, BUF_SIZE-inc, "%s%s ",
1251 ((p<words_size)?words[p++]:""), opt);
1252
1253 opt = expand_string(next_word, "!", len+str-next_word,
1254 fillmore);
1255 if(*opt == ')')
1256 {
1257 ++opt;
1258 break;
1259 }
1260 } while(1);
1261 if(inc > i) buf[inc-1] = 0;
1262 CLEAR_LIST(words);
1263 next = opt;
1264 }
1265
1266 else if(strcasecmp("dir", ptr) == 0)
1267 {
1268 char *val;
1269 int inc = i;
1270 12 kittycat int loop = 1;
1271 1 kittycat
1272 12 kittycat while(loop)
1273 1 kittycat {
1274 char *next_word = expand_string(opt, " )", len+str-opt,
1275 fillmore);
1276 11 kittycat if(next_word == opt)
1277 1 kittycat {
1278 11 kittycat if(isspace(*opt))
1279 {
1280 opt = expand_string(opt, "!", len+str-opt,
1281 fillmore);
1282 continue;
1283 }
1284 12 kittycat *(next_word++) = 0;
1285 13 kittycat opt = next_word;
1286 11 kittycat break;
1287 1 kittycat }
1288 11 kittycat if(isspace(*next_word))
1289 1 kittycat {
1290 *(next_word++) = 0;
1291 next_word = expand_string(next_word, "!",
1292 len+str-next_word, fillmore);
1293 }
1294 12 kittycat else
1295 {
1296 *(next_word++) = 0;
1297 loop = 0;
1298 }
1299 1 kittycat
1300 val = strrchr(opt, '/');
1301 if(val)
1302 {
1303 val[1] = 0;
1304 inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ", opt);
1305 }
1306 else
1307 inc += snprintf(buf+inc, BUF_SIZE-inc, "./ ");
1308
1309 opt = next_word;
1310 }
1311 if(inc > i) buf[inc-1] = 0;
1312 next = opt;
1313 }
1314
1315 else if(strcasecmp("notdir", ptr) == 0)
1316 {
1317 char *val;
1318 int inc = i;
1319 12 kittycat int loop = 1;
1320 1 kittycat
1321 12 kittycat while(loop)
1322 1 kittycat {
1323 char *next_word = expand_string(opt, " )", len+str-opt,
1324 fillmore);
1325 11 kittycat if(next_word == opt)
1326 1 kittycat {
1327 11 kittycat if(isspace(*opt))
1328 {
1329 opt = expand_string(opt, "!", len+str-opt,
1330 fillmore);
1331 continue;
1332 }
1333 12 kittycat *(next_word++) = 0;
1334 13 kittycat opt = next_word;
1335 11 kittycat break;
1336 1 kittycat }
1337 11 kittycat if(isspace(*next_word))
1338 1 kittycat {
1339 *(next_word++) = 0;
1340 next_word = expand_string(next_word, "!",
1341 len+str-next_word, fillmore);
1342 }
1343 12 kittycat else
1344 {
1345 *(next_word++) = 0;
1346 loop = 0;
1347 }
1348 1 kittycat
1349 val = strrchr(opt, '/');
1350 if(!val)
1351 val = opt;
1352 else
1353 ++val;
1354 opt = next_word;
1355 if(val[0])
1356 inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ", val);
1357 }
1358 if(inc > i) buf[inc-1] = 0;
1359 next = opt;
1360 }
1361
1362 /* Finds an executable command by searching the PATH and
1363 returns the full absolute path plus the filename, or an
1364 empty string if it can't be found */
1365 else if(strcasecmp(ptr, "which") == 0)
1366 {
1367 char *path = strdup(getvar("PATH"));
1368 char *direc;
1369 char sep = ':';
1370
1371 next = expand_string(opt, ")", len+str-opt, fillmore);
1372 if(*next) *(next++) = 0;
1373
1374 if(strchr(path, ';') != NULL || (tolower(path[0]) >= 'a' &&
1375 tolower(path[0]) <= 'z' &&
1376 path[1] == ':'))
1377 sep = ';';
1378
1379
1380 if(*opt)
1381 {
1382 direc = path;
1383 while(direc && *direc)
1384 {
1385 struct stat statbuf;
1386 char *slash;
1387 char *next = strchr(direc, sep);
1388 if(next) *(next++) = 0;
1389
1390 snprintf(buf+i, BUF_SIZE-i, "%s/%s", direc, opt);
1391 while((slash=strchr(buf+i, '\\')) != NULL)
1392 *slash = '/';
1393 if(stat(buf+i, &statbuf) == 0)
1394 break;
1395 buf[i] = 0;
1396
1397 direc = next;
1398 }
1399 }
1400
1401 free(path);
1402 }
1403
1404 else if(strcasecmp("ls", ptr) == 0 || strcasecmp("lsa", ptr) == 0)
1405 {
1406 struct stat st;
1407 int inc = i;
1408 int show_hidden = 0;
1409 12 kittycat int loop = 1;
1410 1 kittycat
1411 if(strcasecmp("lsa", ptr) == 0)
1412 show_hidden = 1;
1413
1414 12 kittycat while(loop)
1415 1 kittycat {
1416 DIR *dp;
1417 char *next_word = expand_string(opt, " )", len+str-opt,
1418 fillmore);
1419 11 kittycat if(next_word == opt)
1420 1 kittycat {
1421 11 kittycat if(isspace(*opt))
1422 {
1423 opt = expand_string(opt, "!", len+str-opt,
1424 fillmore);
1425 continue;
1426 }
1427 12 kittycat *(next_word++) = 0;
1428 13 kittycat opt = next_word;
1429 11 kittycat break;
1430 1 kittycat }
1431 11 kittycat if(isspace(*next_word))
1432 1 kittycat {
1433 *(next_word++) = 0;
1434 next_word = expand_string(next_word, "!",
1435 len+str-next_word, fillmore);
1436 }
1437 12 kittycat else
1438 {
1439 *(next_word++) = 0;
1440 loop = 0;
1441 }
1442 1 kittycat
1443 dp = opendir(opt);
1444 if(dp)
1445 {
1446 struct dirent *ent;
1447 char *slash = strrchr(opt, '/');
1448 if(slash && !slash[1]) *slash = 0;
1449
1450 while((ent=readdir(dp)) != NULL)
1451 {
1452 int i;
1453
1454 if(!show_hidden && ent->d_name[0] == '.')
1455 continue;
1456
1457 i = snprintf(buf+inc, BUF_SIZE-inc, "%s/%s",
1458 opt, ent->d_name);
1459
1460 if(stat(buf+inc, &st) == 0 &&
1461 S_ISDIR(st.st_mode))
1462 i += snprintf(buf+inc+i, BUF_SIZE-inc-i,
1463 "/ ");
1464 else
1465 i += snprintf(buf+inc+i, BUF_SIZE-inc-i,
1466 " ");
1467 inc += i;
1468 }
1469 closedir(dp);
1470 }
1471 else
1472 {
1473 if(show_hidden || opt[0] != '.')
1474 {
1475 if(stat(opt, &st) == 0)
1476 inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ",
1477 opt);
1478 }
1479 }
1480 opt = next_word;
1481 }
1482 if(inc > i) buf[inc-1] = 0;
1483 next = opt;
1484 }
1485
1486 4 kittycat else if(strcasecmp("isdir", ptr) == 0)
1487 {
1488 struct stat st;
1489 int inc = i;
1490 12 kittycat int loop = 1;
1491 4 kittycat
1492 12 kittycat while(loop)
1493 4 kittycat {
1494 char *next_word = expand_string(opt, " )", len+str-opt,
1495 fillmore);
1496 11 kittycat if(next_word == opt)
1497 4 kittycat {
1498 11 kittycat if(isspace(*opt))
1499 {
1500 opt = expand_string(opt, "!", len+str-opt,
1501 fillmore);
1502 continue;
1503 }
1504 12 kittycat *(next_word++) = 0;
1505 13 kittycat opt = next_word;
1506 11 kittycat break;
1507 4 kittycat }
1508 11 kittycat if(isspace(*next_word))
1509 4 kittycat {
1510 *(next_word++) = 0;
1511 next_word = expand_string(next_word, "!",
1512 len+str-next_word, fillmore);
1513 }
1514 12 kittycat else
1515 {
1516 *(next_word++) = 0;
1517 loop = 0;
1518 }
1519 4 kittycat
1520 if(stat(opt, &st) == 0 && S_ISDIR(st.st_mode))
1521 inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ",
1522 opt);
1523
1524 opt = next_word;
1525 }
1526 if(inc > i) buf[inc-1] = 0;
1527 next = opt;
1528 }
1529
1530 else if(strcasecmp("isfile", ptr) == 0)
1531 {
1532 struct stat st;
1533 int inc = i;
1534 12 kittycat int loop = 1;
1535 4 kittycat
1536 12 kittycat while(loop)
1537 4 kittycat {
1538 char *next_word = expand_string(opt, " )", len+str-opt,
1539 fillmore);
1540 11 kittycat if(next_word == opt)
1541 4 kittycat {
1542 11 kittycat if(isspace(*opt))
1543 {
1544 opt = expand_string(opt, "!", len+str-opt,
1545 fillmore);
1546 continue;
1547 }
1548 12 kittycat *(next_word++) = 0;
1549 13 kittycat opt = next_word;
1550 11 kittycat break;
1551 4 kittycat }
1552 11 kittycat if(isspace(*next_word))
1553 4 kittycat {
1554 *(next_word++) = 0;
1555 next_word = expand_string(next_word, "!",
1556 len+str-next_word, fillmore);
1557 }
1558 12 kittycat else
1559 {
1560 *(next_word++) = 0;
1561 loop = 0;
1562 }
1563 4 kittycat
1564 if(stat(opt, &st) == 0 && !S_ISDIR(st.st_mode))
1565 inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ",
1566 opt);
1567
1568 opt = next_word;
1569 }
1570 if(inc > i) buf[inc-1] = 0;
1571 next = opt;
1572 }
1573
1574 1 kittycat else
1575 {
1576 fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n"
1577 "Unknown sub-command '%s'\n\n", fname, curr_line, ptr);
1578 free(buf);
1579 strcpy(linebuf, "exit -1\n");
1580 longjmp(jmpbuf, 1);
1581 }
1582
1583 end = next;
1584 }
1585 else
1586 {
1587 /* Insert the named environment var (in the form $FOO or ${FOO}) */
1588 if(*ptr == '{')
1589 {
1590 ++ptr;
1591
1592 if(*ptr == '\'')
1593 {
1594 use_hard_quotes = 1;
1595 ++ptr;
1596 end = "'}";
1597 }
1598 else
1599 end = "}";
1600
1601 end = expand_string(ptr, end, len+str-ptr, fillmore);
1602 if(*end == '\'')
1603 {
1604 *(end++) = 0;
1605 end = expand_string(end, "}", len+str-ptr, fillmore);
1606 }
1607 if(*end)
1608 *(end++) = 0;
1609 }
1610 else
1611 end = expand_string(ptr, "^", len+str-ptr, fillmore);
1612
1613 if(use_hard_quotes)
1614 i = snprintf(buf, BUF_SIZE, "%s'", str);
1615 else
1616 i = snprintf(buf, BUF_SIZE, "%s", str);
1617
1618 if(*ptr >= '0' && *ptr <= '9')
1619 {
1620 const char *val = "";
1621 size_t idx = atoi(ptr);
1622 if(idx < argc)
1623 val = argv[idx];
1624 snprintf(buf+i, BUF_SIZE-i, "%s", val);
1625 }
1626 else if(*ptr == '*' || (use_hard_quotes && *ptr == '@'))
1627 {
1628 size_t idx = ((ptr+1 >= end || !ptr[1]) ? 1 : atoi(ptr+1));
1629 int inc = i;
1630 while(idx < argc)
1631 {
1632 inc += snprintf(buf+inc, BUF_SIZE-inc, "%s ", argv[idx]);
1633 ++idx;
1634 }
1635 if(inc > i) buf[inc-1] = 0;
1636 }
1637 else if(*ptr == '@')
1638 {
1639 size_t idx = ((ptr+1 >= end || !ptr[1]) ? 1 : atoi(ptr+1));
1640 while(idx < argc)
1641 {
1642 25 kittycat i += snprintf(buf+i, BUF_SIZE-i, "${'%u'}", (unsigned int)idx);
1643 1 kittycat
1644 ++idx;
1645 if(idx < argc)
1646 i += snprintf(buf+i, BUF_SIZE-i, " ");
1647 }
1648 snprintf(buf+i, BUF_SIZE-i, "%s", end);
1649 strcpy(str, buf);
1650 continue;
1651 }
1652 else
1653 {
1654 char c = *end;
1655 *end = 0;
1656 snprintf(buf+i, BUF_SIZE-i, "%s", getvar(ptr));
1657 *end = c;
1658 }
1659 }
1660
1661 while(buf[i])
1662 {
1663 if(buf[i] == '&' || buf[i] == '\'' || buf[i] == '"' ||
1664 29 kittycat buf[i] == '\\' || buf[i] == '#')
1665 1 kittycat {
1666 memmove(buf+i+1, buf+i, BUF_SIZE-i-1);
1667 buf[i] = '\\';
1668 ++i;
1669 }
1670 ++i;
1671 }
1672
1673 if(use_hard_quotes)
1674 snprintf(buf+i, BUF_SIZE-i, "'%s", end);
1675 else
1676 snprintf(buf+i, BUF_SIZE-i, "%s", end);
1677 strcpy(str, buf);
1678 } while(1);
1679 }
1680
1681
1682 /* extract_word: Extract a word starting at the string pointed to by 'str'. If
1683 * the word begins with a ' or " character, everything until that same
1684 * character will be considered part of the word. Otherwise, the word ends at
1685 * the first encountered whitespace. Returns the beginning of the next word,
1686 * or the end of the string.
1687 */
1688 static char *extract_word(char *str, size_t len)
1689 {
1690 char *end = str;
1691
1692 if(!(*end))
1693 return end;
1694
1695 end = expand_string(end, " \n", len+str-end, 1);
1696 if(*end && *end != '\n')
1697 *(end++) = 0;
1698
1699 if(*end != '\n')
1700 end = expand_string(end, "!\n", len+str-end, 1);
1701 if(*end == '\n')
1702 {
1703 if(end[1] != 0)
1704 nextline = strdup(end+1);
1705 *end = 0;
1706 }
1707
1708 return end;
1709 }
1710
1711
1712 static void extract_line(char *str, size_t len)
1713 {
1714 char *end = str;
1715
1716 if(!(*end))
1717 return;
1718
1719 end = expand_string(end, "\n", len+str-end, 1);
1720
1721 if(end[0] == '\n' && end[1] != 0)
1722 nextline = strdup(end+1);
1723 *end = 0;
1724 }
1725
1726
1727 /* check_obj_deps: Checks a file's dependancy list. The dependancy file is a
1728 * file expected to be in dep_dir and with the same name, but with a different
1729 * extension. The format of the file is simply: 'file.o: dependancy list...'. A
1730 * '\' at the end of the line can be used as a next-line continuation. If the
1731 * dependancy file exists, none of the dependancies are missing, and none have
1732 * a modification time after 'obj_time', the function will return 0. Otherwise
1733 * 1 is returned denoting a rebuild may be required.
1734 */
1735 static int check_obj_deps(char *base, char *src, time_t obj_time)
1736 {
1737 static char dep[PATH_MAX];
1738 char *buf;
1739 int bufsize;
1740
1741 struct stat statbuf;
1742 char *ptr = obj;
1743 FILE *df;
1744
1745 ptr = strrchr(base, '/');
1746 if(!ptr) ptr = base;
1747 ptr = strrchr(ptr, '.');
1748 if(ptr) *ptr = 0;
1749 snprintf(dep, sizeof(dep), "${DEP_DIR}/'%s'${DEP_EXT}", base);
1750 expand_string(dep, "", sizeof(dep), 0);
1751 if(ptr) *ptr = '.';
1752
1753 df = fopen(dep, "r");
1754 if(!df)
1755 {
1756 if(stat(src, &statbuf) != 0 || statbuf.st_mtime-obj_time > 0)
1757 return 1;
1758 return 0;
1759 }
1760
1761 fseek(df, 0, SEEK_END);
1762 bufsize = ftell(df)+1;
1763 buf = malloc(bufsize);
1764 if(!buf)
1765 {
1766 fclose(df);
1767 return 1;
1768 }
1769
1770 fseek(df, 0, SEEK_SET);
1771 bufsize = fread(buf, 1, bufsize, df);
1772 if(bufsize >= 0)
1773 buf[bufsize] = 0;
1774
1775 fclose(df);
1776
1777 ptr = strchr(buf, ':');
1778 if(!ptr)
1779 {
1780 free(buf);
1781 return 1;
1782 }
1783
1784 ++ptr;
1785 while(*ptr && *ptr != '\n' && isspace(*ptr))
1786 ++ptr;
1787
1788 while(*ptr)
1789 {
1790 char *stp = ptr;
1791
1792 while(*stp && !isspace(*stp))
1793 {
1794 if(*stp == '\\')
1795 memmove(stp, stp+1, strlen(stp));
1796 if(*stp) ++stp;
1797 }
1798 if(*stp) *(stp++) = 0;
1799 while(*stp && isspace(*stp))
1800 ++stp;
1801
1802 if(strcmp(ptr, "\n") != 0 && (stat(ptr, &statbuf) != 0 ||
1803 statbuf.st_mtime > obj_time))
1804 {
1805 free(buf);
1806 return 1;
1807 }
1808
1809 ptr = stp;
1810 }
1811 free(buf);
1812
1813 buf = (char*)getvar("EXTRA_SRC_DEPS");
1814 if(*buf)
1815 {
1816 char *ptr = malloc(BUF_SIZE);
1817 strncpy(ptr, buf, BUF_SIZE);
1818 buf = ptr;
1819
1820 while(*ptr)
1821 {
1822 char *next = expand_string(ptr, " ", BUF_SIZE+buf-ptr, 0);
1823 if(*next) *(next++) = 0;
1824 next = expand_string(next, "!", BUF_SIZE+buf-next, 0);
1825
1826 if(stat(ptr, &statbuf) != 0 || statbuf.st_mtime > obj_time)
1827 {
1828 free(buf);
1829 return 1;
1830 }
1831
1832 ptr = next;
1833 }
1834
1835 free(buf);
1836 }
1837
1838 return 0;
1839 }
1840
1841 /* copy_file: Copies the source file 'sf' to 'df', preserving the source's
1842 * file mode and permissions, if possible.
1843 */
1844 static int copy_file(const char *sf, const char *df)
1845 {
1846 struct stat statbuf;
1847 FILE *src, *dst;
1848 int ret, i;
1849 int fd;
1850
1851 if(stat(sf, &statbuf) != 0)
1852 return 1;
1853
1854 #ifdef O_BINARY
1855 fd = open(df, O_WRONLY|O_BINARY|O_TRUNC|O_CREAT, statbuf.st_mode);
1856 #else
1857 fd = open(df, O_WRONLY|O_TRUNC|O_CREAT, statbuf.st_mode);
1858 #endif
1859 if(fd < 0)
1860 return 1;
1861 dst = fdopen(fd, "wb");
1862 if(!dst)
1863 {
1864 close(fd);
1865 return 1;
1866 }
1867
1868 src = fopen(sf, "rb");
1869 if(!src)
1870 {
1871 fclose(dst);
1872 return 1;
1873 }
1874
1875 ret = 0;
1876 do {
1877 i = fread(buffer, 1, sizeof(buffer), src);
1878 if(i > 0)
1879 i = fwrite(buffer, 1, i, dst);
1880 if(i < 0)
1881 ret = 1;
1882 } while(i > 0);
1883
1884 fclose(src);
1885 fclose(dst);
1886 return ret;
1887 }
1888
1889
1890 static int libify_name(char *buf, size_t buflen, char *name)
1891 {
1892 int i;
1893 char *curr = strrchr(name, '/');
1894 if(curr)
1895 {
1896 *curr = 0;
1897 i = snprintf(buf, buflen, "'%s'/${LIB_PRE}'%s'${LIB_EXT}", name,
1898 curr+1);
1899 *curr = '/';
1900 }
1901 else
1902 i = snprintf(buf, buflen, "${LIB_PRE}'%s'${LIB_EXT}", name);
1903 expand_string(buf, "", buflen, 0);
1904 return i;
1905 }
1906
1907
1908 typedef struct {
1909 char *ext;
1910 char *cmd;
1911 } ASSOC;
1912 DECL_LIST(static ASSOC, associations);
1913
1914 static void add_association(const char *ext, const char *cmd)
1915 {
1916 size_t i;
1917 for(i = 0;i < associations_size;++i)
1918 {
1919 if(associations[i].cmd[0] == 0 ||
1920 strcasecmp(ext, associations[i].ext) == 0)
1921 break;
1922 }
1923 if(i == associations_size)
1924 {
1925 RESIZE_LIST(associations, i+1);
1926
1927 associations[i].ext = NULL;
1928 associations[i].cmd = NULL;
1929 }
1930 free(associations[i].ext);
1931 free(associations[i].cmd);
1932 associations[i].ext = strdup(ext);
1933 associations[i].cmd = strdup(cmd);
1934 if(!associations[i].ext || !associations[i].cmd)
1935 {
1936 strcpy(linebuf, "exit -1\n");
1937 longjmp(jmpbuf, 1);
1938 }
1939 }
1940
1941 static int build_command(char *buffer, size_t bufsize, char *barename,
1942 const char *srcname, const char *objname)
1943 {
1944 char dummy[2] = ".";
1945 const char *ptr;
1946 char *ext;
1947 size_t i;
1948
1949 ext = strrchr(barename, '.');
1950 if(strchr(ext, '/') || !ext)
1951 ext = dummy;
1952
1953 for(i = 0;i < associations_size;++i)
1954 {
1955 if(strcasecmp(ext+1, associations[i].ext) == 0)
1956 break;
1957 }
1958 if(i == associations_size)
1959 return 1;
1960
1961 ptr = associations[i].cmd;
1962 9 kittycat i = 0;
1963 1 kittycat while(*ptr && i+1 < bufsize)
1964 {
1965 if(strncasecmp(ptr, "<*>", 3) == 0)
1966 {
1967 6 kittycat *ext = 0;
1968 1 kittycat i += snprintf(buffer+i, bufsize-i, "'%s'", barename);
1969 6 kittycat *ext = '.';
1970 1 kittycat ptr += 3;
1971 }
1972 else if(strncasecmp(ptr, "<!>", 3) == 0)
1973 {
1974 i += snprintf(buffer+i, bufsize-i, "'%s'", srcname);
1975 ptr += 3;
1976 }
1977 else if(strncasecmp(ptr, "<@>", 3) == 0)
1978 {
1979 i += snprintf(buffer+i, bufsize-i, "'%s'", objname);
1980 ptr += 3;
1981 }
1982 else
1983 {
1984 if(ptr[0] == '\\' && ptr[1] != 0 && i+2 < bufsize)
1985 9 kittycat ptr++;
1986 1 kittycat buffer[i++] = *(ptr++);
1987 buffer[i] = 0;
1988 }
1989 }
1990 return 0;
1991 }
1992
1993
1994 /* build_obj_list: Builds a list of object files from the list of sources. If
1995 * any of the objects don't exist or have a modification time later than
1996 * 'base_time', the variable pointed to by 'do_link' will be set non-zero.
1997 */
1998 static int build_obj_list(char *buffer, size_t bufsize, time_t base_time,
1999 int *do_link)
2000 {
2001 static char buf[PATH_MAX];
2002
2003 struct stat statbuf;
2004 char *ptr;
2005 int i = 0;
2006 size_t p;
2007
2008 for(p = 0;p < sources_size;++p)
2009 {
2010 char *ext;
2011 ptr = sources[p];
2012
2013 ext = strrchr(ptr, '/');
2014 if(!ext) ext = ptr;
2015 ext = strrchr(ext, '.');
2016
2017 if(ext) *ext = 0;
2018 snprintf(buf, sizeof(buf), "${OBJ_DIR}/'%s'${OBJ_EXT}", ptr);
2019 expand_string(buf, "", sizeof(buf), 0);
2020 if(ext) *ext = '.';
2021
2022 if(!(*do_link) && (stat(buf, &statbuf) != 0 ||
2023 base_time < statbuf.st_mtime))
2024 *do_link = 1;
2025
2026 if(ext) *ext = 0;
2027 i += snprintf(buffer+i, bufsize-i,
2028 " \\\"${OBJ_DIR}/'%s'${OBJ_EXT}\\\"", ptr);
2029 if(ext) *ext = '.';
2030 }
2031 return i;
2032 }
2033
2034
2035 void cleanup(void)
2036 {
2037 size_t i;
2038
2039 fflush(stdout);
2040
2041 for(i = 1;i < arg_backup_size;++i)
2042 {
2043 size_t i2;
2044 argv = arg_backup[i].argv;
2045 for(i2 = 0;i2 < arg_backup[i].argc;++i2)
2046 free(argv[i2]);
2047 CLEAR_LIST(argv);
2048 }
2049 CLEAR_LIST(arg_backup);
2050
2051 for(i = 0;i < defines_size;++i)
2052 {
2053 free(defines[i].name);
2054 free(defines[i].val);
2055 }
2056 CLEAR_LIST(defines);
2057
2058 for(i = 0;i < src_paths_size;++i)
2059 free(src_paths[i]);
2060 CLEAR_LIST(src_paths);
2061
2062 for(i = 0;i < invoke_backup_size;++i)
2063 {
2064 fclose(invoke_backup[i].f);
2065 free(invoke_backup[i].fname);
2066 free(invoke_backup[i].bkp_lbuf);
2067 free(invoke_backup[i].bkp_nextline);
2068 }
2069 CLEAR_LIST(invoke_backup);
2070
2071 for(i = 0;i < associations_size;++i)
2072 {
2073 free(associations[i].ext);
2074 free(associations[i].cmd);
2075 }
2076 CLEAR_LIST(associations);
2077
2078 for(i = 0;i < sources_size;++i)
2079 free(sources[i]);
2080 CLEAR_LIST(sources);
2081
2082 for(i = 0;i < loaded_files_size;++i)
2083 free(loaded_files[i]);
2084 CLEAR_LIST(loaded_files);
2085
2086 free(nextline);
2087 nextline = NULL;
2088 free(fname);
2089 fname = NULL;
2090
2091 if(f)
2092 fclose(f);
2093 f = NULL;
2094 }
2095
2096
2097 unsigned int do_level = 0;
2098 unsigned int did_cmds = 0, did_else = 0;
2099 unsigned int wait_for_done = 0;
2100 int ret = 0, tmp = 0;
2101 int ignored_errors = 0;
2102 int verbose = 0;
2103 int shh = 0;
2104 int ignore_err = 0;
2105 int has_do = 0;
2106
2107 int main(int _argc, char **_argv)
2108 {
2109 char *ptr;
2110 int i;
2111
2112 setenv("CC", "gcc", 0);
2113 setenv("CXX", "g++", 0);
2114 setenv("LD", "gcc", 0);
2115 setenv("OUT_OPT", "-o ", 0);
2116 setenv("SRC_OPT", "-c ", 0);
2117 setenv("DEP_OPT", "-MMD -MF ", 0);
2118 setenv("OBJ_EXT", ".o", 0);
2119 setenv("OBJ_DIR", ".", 0);
2120 setenv("DEP_EXT", ".d", 0);
2121 setenv("DEP_DIR", ".", 0);
2122 #if (defined __WIN32__ || defined __DOS__)
2123 setenv("EXE_EXT", ".exe", 0);
2124 #else
2125 setenv("EXE_EXT", "", 0);
2126 #endif
2127 setenv("AR", "ar", 0);
2128 setenv("AR_OPT", "", 0);
2129 setenv("LIB_PRE", "lib", 0);
2130 setenv("LIB_EXT", ".a", 0);
2131 setenv("CPPFLAGS", "", 0);
2132 setenv("CFLAGS", "", 0);
2133 setenv("CXXFLAGS", "", 0);
2134 setenv("LDFLAGS", "", 0);
2135
2136 atexit(cleanup);
2137
2138 /* Check to see if there may be a user-specified script to open */
2139 if(_argc > 1)
2140 {
2141 char *ext = strrchr(_argv[1], '.');
2142 /* Only files with the .cbd extension are allowed (to reduce chances of
2143 * accidently swiping filenames a script may want) */
2144 if(ext && strcasecmp(ext, ".cbd") == 0)
2145 {
2146 fname = strdup(_argv[1]);
2147 f = fopen(fname, "r");
2148 if(!f)
2149 {
2150 fprintf(USEABLE_ERR, "\n\n*** Critical Error ***\n"
2151 "Could not open %s!\n\n", fname);
2152 exit(1);
2153 }
2154
2155 i = 1;
2156 while((_argv[i]=_argv[i+1]) != NULL)
2157 ++i;
2158 --_argc;
2159 }
2160 }
2161
2162 /* Open the default file */
2163 if(!fname)
2164 {
2165 fname = strdup("default.cbd");
2166 f = fopen(fname, "r");
2167 if(!f)
2168 {
2169 fprintf(USEABLE_ERR, "\n\n*** Critical Error ***\n"
2170 "Could not open %s!\n\n", fname);
2171 exit(1);
2172 }
2173 }
2174
2175 setvbuf(stdin, NULL, _IOLBF, 0);
2176 argc = _argc;
2177 argv = _argv;
2178
2179 if(setjmp(jmpbuf))
2180 {
2181 free(nextline);
2182 nextline = NULL;
2183 goto reparse;
2184 }
2185
2186 main_loop_start:
2187 while(1)
2188 {
2189 int reverse;
2190 ignore_err = 0;
2191 has_do = 0;
2192
2193 if(nextline)
2194 {
2195 /* If we already have the next line set, go do it */
2196 strncpy(linebuf, nextline, strlen(nextline)+1);
2197 free(nextline);
2198 nextline = NULL;
2199 goto reparse;
2200 }
2201
2202 /* Grab the next line and increment the line count */
2203 if(fgets(linebuf, sizeof(linebuf), f) == NULL)
2204 {
2205 /* If end of file, implicitly uninvoke and continue */
2206 snprintf(linebuf, sizeof(linebuf), "uninvoke 0\n");
2207 7 kittycat
2208 if(do_level > 0)
2209 {
2210 fprintf(USEABLE_ERR, "\n\n!!! %s error !!!\n"
2211 "Unbalanced do/done pair!\n\n", fname);
2212 wait_for_done = 0;
2213 did_else = 0;
2214 did_cmds = 0;
2215 do_level = 0;
2216 }
2217
2218 1 kittycat goto reparse;
2219 }
2220 ++curr_line;
2221
2222 reparse:
2223 reverse = 0;
2224 shh = 0;
2225
2226 /* Chew up leading whitespace */
2227 ptr = expand_string(linebuf, "!", sizeof(linebuf), 1);
2228 if(!*ptr)
2229 continue;
2230 if(ptr > linebuf)
2231 memmove(linebuf, ptr, strlen(ptr)+1);
2232
2233 ptr = expand_string(linebuf, " =\n", sizeof(linebuf), 1);
2234 if(!linebuf[0] || ptr == linebuf || linebuf[0] == ':')
2235 {
2236 extract_line(ptr, sizeof(linebuf)+linebuf-ptr);
2237 continue;
2238 }
2239
2240 if(isspace(*ptr))
2241 {
2242 if(*ptr != '\n')
2243 {
2244 *(ptr++) = 0;
2245 ptr = expand_string(ptr, "!\n", sizeof(linebuf)+linebuf-ptr, 1);
2246 }
2247 if(*ptr == '\n')
2248 {
2249 *ptr = 0;
2250 if(ptr[1] != 0)
2251 nextline = strdup(ptr+1);
2252 }
2253 }
2254
2255 /* Check for special 'leveling' commands */
2256
2257 /* The 'do' command pushes us up a level, and checks for the next
2258 * if-type command, which itself will let us know if we should start
2259 * ignoring commands */
2260 if(strcasecmp("do", linebuf) == 0)
2261 {
2262 ++do_level;
2263 if(do_level >= sizeof(int)*8)
2264 {
2265 fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n"
2266 "Too many 'do' commands enountered (max: %u)!\n\n",
2267 25 kittycat fname, curr_line, (unsigned int)sizeof(int)*8 - 1);
2268 1 kittycat snprintf(linebuf, sizeof(linebuf), "exit -1\n");
2269 goto reparse;
2270 }
2271 4 kittycat if(!*ptr)
2272 continue;
2273 1 kittycat has_do = 1;
2274 memmove(linebuf, ptr, strlen(ptr)+1);
2275 goto reparse;
2276 }
2277 /* 'else' toggles ignoring commands at the current level */
2278 if(strcasecmp("else", linebuf) == 0)
2279 {
2280 if(do_level <= 0)
2281 do_level = 1;
2282
2283 /* allow another if-type command to follow an else on the same
2284 * level */
2285 if(!(wait_for_done & (1<<(do_level-1))))
2286 {
2287 wait_for_done |= 1<<(do_level-1);
2288 did_cmds |= 1<<(do_level-1);
2289 has_do = 0;
2290 }
2291
2292 if(!(did_cmds & (1<<(do_level-1))))
2293 {
2294 wait_for_done &= ~(1<<(do_level-1));
2295 has_do = 1;
2296 }
2297
2298 4 kittycat if(!*ptr)
2299 continue;
2300 1 kittycat memmove(linebuf, ptr, strlen(ptr)+1);
2301 goto reparse;
2302 }
2303 /* 'done' takes us down a level */
2304 if(strcasecmp("done", linebuf) == 0)
2305 {
2306 if(do_level > 0)
2307 {
2308 wait_for_done &= ~(1<<(--do_level));
2309 did_else &= ~(1<<do_level);
2310 did_cmds &= ~(1<<do_level);
2311 }
2312 4 kittycat extract_line(ptr, sizeof(linebuf)+linebuf-ptr);
2313 1 kittycat continue;
2314 }
2315
2316 if((wait_for_done & ((1<<do_level)-1)))
2317 {
2318 extract_line(ptr, sizeof(linebuf)+linebuf-ptr);
2319 continue;
2320 }
2321
2322
2323 /* The if command checks if 'val1 = val2' is true and processes the
2324 * rest of the line if so. */
2325 if(strcasecmp("if", linebuf) == 0)
2326 value_check:
2327 {
2328 char *next, *var2;
2329
2330 var2 = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
2331 if(*var2 != '=')
2332 {
2333 next = var2;
2334 var2 = strchr(ptr, '=');
2335 if(!var2)
2336 {
2337 fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n"
2338 "Malformed 'if' command!\n\n", fname, curr_line);
2339 snprintf(linebuf, sizeof(linebuf), "exit 1\n");
2340 goto reparse;
2341 }
2342 *(var2++) = 0;
2343 while(*var2 && isspace(*var2))
2344 ++var2;
2345 }
2346 else
2347 next = extract_word(var2, sizeof(linebuf)+linebuf-var2);
2348
2349 if((strcmp(ptr, var2) == 0) != !!reverse)
2350 {
2351 memmove(linebuf, next, strlen(next)+1);
2352 goto reparse;
2353 }
2354
2355 if(has_do)
2356 wait_for_done |= 1 << (do_level-1);
2357 extract_line(next, sizeof(linebuf)+linebuf-next);
2358 continue;
2359 }
2360 /* Same as above, except if the comparison is false or it equates 0 */
2361 if(strcasecmp("ifnot", linebuf) == 0)
2362 {
2363 reverse = 1;
2364 goto value_check;
2365 }
2366
2367 /* Checks the last command's return value against the supplied value,
2368 * and runs the rest of the line if they're equal */
2369 if(strcasecmp("ifret", linebuf) == 0)
2370 retval_check:
2371 {
2372 char *next;
2373 next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
2374
2375 if((atoi(ptr) == ret) != !!reverse)
2376 {
2377 memmove(linebuf, next, strlen(next)+1);
2378 goto reparse;
2379 }
2380
2381 if(has_do)
2382 wait_for_done |= 1 << (do_level-1);
2383 extract_line(next, sizeof(linebuf)+linebuf-next);
2384 continue;
2385 }
2386 if(strcasecmp("ifnret", linebuf) == 0 )
2387 {
2388 reverse = 1;
2389 goto retval_check;
2390 }
2391
2392 /* Checks the platform we're running on against the user supplied
2393 * value */
2394 if(strcasecmp("ifplat", linebuf) == 0)
2395 platform_check:
2396 {
2397 char *next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
2398 int pass = 0;
2399
2400 /* Throw in a dummy if() so the following ifs can use else if and
2401 * avoid multiple checks for platforms where multiple targets apply
2402 */
2403 if(0 == 1)
2404 pass = 0;
2405
2406 #if defined(_AIX) || defined(__TOS_AIX__)
2407 else if(strcasecmp("aix", ptr) == 0)
2408 pass = 1;
2409 #endif
2410 #if defined(AMIGA) || defined(__amigaos__)
2411 else if(strcasecmp("amigaos", ptr) == 0)
2412 pass = 1;
2413 #endif
2414 #if defined(__BEOS__)
2415 else if(strcasecmp("beos", ptr) == 0)
2416 pass = 1;
2417 #endif
2418 #if defined(_UNICOS)
2419 else if(strcasecmp("unicos", ptr) == 0)
2420 pass = 1;
2421 #endif
2422 #if defined(DGUX) || defined(__DGUX__) || defined(__dgux__)
2423 else if(strcasecmp("dgux", ptr) == 0)
2424 pass = 1;
2425 #endif
2426 #if defined(_SEQUENT_) || defined(sequent)
2427 else if(strcasecmp("dynix", ptr) == 0)
2428 pass = 1;
2429 #endif
2430 #ifdef __FreeBSD__
2431 else if(strcasecmp("freebsd", ptr) == 0)
2432 pass = 1;
2433 #endif
2434 #if defined(__GNU__)
2435 else if(strcasecmp("gnuhurd", ptr) == 0)
2436 pass = 1;
2437 #endif
2438 #if defined(hpux) || defined (_hpux) || defined(_HPUX_SOURCE)
2439 else if(strcasecmp("hpux", ptr) == 0)
2440 pass = 1;
2441 #endif
2442 #if defined(sgi) || defined(__sgi) || defined(mips) || defined(_SGI_SOURCE)
2443 else if(strcasecmp("irix", ptr) == 0)
2444 pass = 1;
2445 #endif
2446 #if defined(linux) || defined(__linux)
2447 else if(strcasecmp("linux", ptr) == 0)
2448 pass = 1;
2449 #endif
2450 #if defined(__MACOSX__) || defined(__APPLE__)
2451 else if(strcasecmp("macosx", ptr) == 0)
2452 pass = 1;
2453 #endif
2454 #if defined(mpeix) || defined(__mpexl)
2455 else if(strcasecmp("mpeix", ptr) == 0)
2456 pass = 1;
2457 #endif
2458 #if defined(MSDOS) || defined(__MSDOS__) || defined(_MSDOS) || defined(__DOS__)
2459 else if(strcasecmp("msdos", ptr) == 0)
2460 pass = 1;
2461 #endif
2462 #if defined(__NetBSD__)
2463 else if(strcasecmp("netbsd", ptr) == 0)
2464 pass = 1;
2465 #endif
2466 #if defined(__OpenBSD__)
2467 else if(strcasecmp("openbsd", ptr) == 0)
2468 pass = 1;
2469 #endif
2470 #if defined(OS2) || defined(_OS2) || defined(__OS2__) || defined(__TOS_OS2__)
2471 else if(strcasecmp("os2", ptr) == 0)
2472 pass = 1;
2473 #endif
2474 #if defined(pyr)
2475 else if(strcasecmp("pyramiddc", ptr) == 0)
2476 pass = 1;
2477 #endif
2478 #if defined(__QNX__)
2479 else if(strcasecmp("qnx4", ptr) == 0)
2480 pass = 1;
2481 #endif
2482 #if defined(__QNXNTO__)
2483 else if(strcasecmp("qnx6", ptr) == 0)
2484 pass = 1;
2485 #endif
2486 #if defined(sinix)
2487 else if(strcasecmp("reliantunix", ptr) == 0)
2488 pass = 1;
2489 #endif
2490 #if defined(M_I386) || defined(M_XENIX) || defined(_SCO_DS) || defined(_SCO_C_DIALECT)
2491 else if(strcasecmp("scoopenserver", ptr) == 0)
2492 pass = 1;
2493 #endif
2494 #if defined(sun) || defined(__sun)
2495 # if defined(__SVR4) || defined(__svr4__)
2496 else if(strcasecmp("solaris", ptr) == 0)
2497 pass = 1;
2498 # else
2499 else if(strcasecmp("sunos", ptr) == 0)
2500 pass = 1;
2501 # endif
2502 #elif defined(__SUNPRO_C)
2503 else if(strcasecmp("solaris", ptr) == 0)
2504 pass = 1;
2505 #endif
2506 #if defined(__SYMBIAN32__)
2507 else if(strcasecmp("symbian", ptr) == 0)
2508 pass = 1;
2509 #endif
2510 #if defined(__osf__) || defined(__osf)
2511 else if(strcasecmp("osf1", ptr) == 0 ||
2512 strcasecmp("tru64", ptr) == 0)
2513 pass = 1;
2514 #endif
2515 #if defined(ultrix) || defined(__ultrix) || defined(__ultrix__) || (defined(unix) && defined(vax))
2516 else if(strcasecmp("ultrix", ptr) == 0)
2517 pass = 1;
2518 #endif
2519 #if defined(sco) || defined(_UNIXWARE7)
2520 else if(strcasecmp("unixware", ptr) == 0)
2521 pass = 1;
2522 #endif
2523 #if defined(VMS) || defined(__VMS)
2524 else if(strcasecmp("vms", ptr) == 0)
2525 pass = 1;
2526 #endif
2527 #if defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN32__)
2528 else if(strcasecmp("win32", ptr) == 0)
2529 pass = 1;
2530 #endif
2531
2532 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(_SYSTYPE_BSD)
2533 else if(strcasecmp("bsd", ptr) == 0)
2534 pass = 1;
2535 #endif
2536 #if defined(__sysv__) || defined(__SVR4) || defined(__svr4__) || defined(_SYSTYPE_SVR4)
2537 else if(strcasecmp("svr4", ptr) == 0)
2538 pass = 1;
2539 #endif
2540 #if defined(unix) || defined(__unix) || defined(__unix__)
2541 else if(strcasecmp("unix", ptr) == 0)
2542 pass = 1;
2543 #endif
2544 #if defined(_UWIN)
2545 else if(strcasecmp("uwin", ptr) == 0)
2546 pass = 1;
2547 #endif
2548 #if defined(_WINDU_SOURCE)
2549 else if(strcasecmp("windu", ptr) == 0)
2550 pass = 1;
2551 #endif
2552
2553 #if defined(__i386__) || defined(__i386) || (_M_IX86 > 300)
2554 else if(strcasecmp("i386", ptr) == 0)
2555 pass = 1;
2556 #endif
2557 #if defined(__ia64__) || defined(_M_IA64)
2558 else if(strcasecmp("ia64", ptr) == 0)
2559 pass = 1;
2560 #endif
2561 #if defined(__powerpc__) || defined(_M_PPC)
2562 else if(strcasecmp("powerpc", ptr) == 0)
2563 pass = 1;
2564 #endif
2565 #if defined(__sparc__) || defined(__sparc)
2566 else if(strcasecmp("sparc", ptr) == 0)
2567 pass = 1;
2568 #endif
2569
2570 if((pass != 0) != !!reverse)
2571 {
2572 memmove(linebuf, next, strlen(next)+1);
2573 goto reparse;
2574 }
2575
2576 if(has_do)
2577 wait_for_done |= 1 << (do_level-1);
2578 extract_line(next, sizeof(linebuf)+linebuf-next);
2579 continue;
2580 }
2581 if(strcasecmp("ifnplat", linebuf) == 0)
2582 {
2583 reverse = 1;
2584 goto platform_check;
2585 }
2586
2587 /* Checks if the supplied option name was specified on the command
2588 * line */
2589 if(strcasecmp("ifopt", linebuf) == 0)
2590 option_check:
2591 {
2592 char *next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
2593 int pass = 0;
2594 size_t i;
2595
2596 for(i = 1;i < argc;++i)
2597 {
2598 30 size_t len = strlen(argv[i]);
2599 1 kittycat char *eq = strrchr(argv[i], '=');
2600
2601 30 if(eq)
2602 len = (size_t)(eq-argv[i]);
2603 1 kittycat
2604 if(strncasecmp(ptr, argv[i], len) == 0)
2605 {
2606 pass = 1;
2607 break;
2608 }
2609 }
2610
2611 if((pass != 0) != !!reverse)
2612 {
2613 memmove(linebuf, next, strlen(next)+1);
2614 goto reparse;
2615 }
2616
2617 if(has_do)
2618 wait_for_done |= 1 << (do_level-1);
2619 extract_line(next, sizeof(linebuf)+linebuf-next);
2620 continue;
2621 }
2622 if(strcasecmp("ifnopt", linebuf) == 0)
2623 {
2624 reverse = 1;
2625 goto option_check;
2626 }
2627
2628 /* Checks if a file or directory exists */
2629 if(strcasecmp("ifexist", linebuf) == 0)
2630 file_dir_check:
2631 {
2632 struct stat statbuf;
2633 char *next;
2634
2635 next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
2636 if((stat(ptr, &statbuf) == 0) != !!reverse)
2637 {
2638 memmove(linebuf, next, strlen(next)+1);
2639 goto reparse;
2640 }
2641
2642 if(has_do)
2643 wait_for_done |= 1 << (do_level-1);
2644 extract_line(next, sizeof(linebuf)+linebuf-next);
2645 continue;
2646 }
2647 if(strcasecmp("ifnexist", linebuf) == 0)
2648 {
2649 reverse = 1;
2650 goto file_dir_check;
2651 }
2652
2653 /* Checks if we have write permissions to the specified file or
2654 * directory */
2655 if(strcasecmp("ifwrite", linebuf) == 0)
2656 dir_write_check:
2657 {
2658 char *next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
2659 int val = 1;
2660
2661 #ifdef __unix__
2662 {
2663 struct stat stbuf;
2664 val = 0;
2665 if(stat(ptr, &stbuf) == 0)
2666 {
2667 if(stbuf.st_uid == getuid())
2668 {
2669 if((stbuf.st_mode&S_IWUSR))
2670 val = 1;
2671 }
2672 else if(stbuf.st_gid == getgid())
2673 {
2674 if((stbuf.st_mode&S_IWGRP))
2675 val = 1;
2676 }
2677 else if((stbuf.st_mode&S_IWOTH))
2678 val = 1;
2679 }
2680 }
2681 #endif
2682
2683 if((val != 0) != !!reverse)
2684 {
2685 memmove(linebuf, next, strlen(next)+1);
2686 goto reparse;
2687 }
2688
2689 if(has_do)
2690 wait_for_done |= 1 << (do_level-1);
2691 extract_line(next, sizeof(linebuf)+linebuf-next);
2692 continue;
2693 }
2694 if(strcasecmp("ifnwrite", linebuf) == 0)
2695 {
2696 reverse = 1;
2697 goto dir_write_check;
2698 }
2699
2700
2701
2702 /* Set an environment variable. The value is space sensitive, so if you
2703 * wish to use spaces, encapsulate the value in ''s. Using '?=' instead
2704 * of '=' will only set the variable if it isn't already set. */
2705 if(strncmp(ptr, "+=", 2) == 0 || strncmp(ptr, "-=", 2) == 0 ||
2706 strncmp(ptr, "?=", 2) == 0 || ptr[0] == '=')
2707 {
2708 char *val = ptr;
2709 int ovr = 1;
2710
2711 if(val[0] != '=')
2712 ++val;
2713 ptr = linebuf;
2714 14 kittycat buffer[0] = 0;
2715 1 kittycat
2716 if(*(val-1) == '+')
2717 {
2718 int i;
2719
2720 *(val-1) = 0;
2721 18 kittycat if(isspace(*(++val)))
2722 val = extract_word(val, sizeof(linebuf)+linebuf-val);
2723 14 kittycat
2724 1 kittycat i = snprintf(buffer, sizeof(buffer), "%s", getvar(ptr));
2725 if(*val)
2726 {
2727 do {
2728 char *next_word = extract_word(val, sizeof(linebuf)+
2729 linebuf-val);
2730 i += snprintf(buffer+i, sizeof(buffer)-i, "%s ", val);
2731 val = next_word;
2732 } while(*val);
2733 16 kittycat if(i > 0) buffer[i-1] = 0;
2734 1 kittycat }
2735 setenv(ptr, buffer, 1);
2736 continue;
2737 }
2738
2739 if(*(val-1) == '-')
2740 {
2741 char *pos;
2742 int len;
2743
2744 *(val-1) = 0;
2745 18 kittycat if(isspace(*(++val)))
2746 val = extract_word(val, sizeof(linebuf)+linebuf-val);
2747 1 kittycat
2748 14 kittycat extract_line(val, sizeof(linebuf)+linebuf-val);
2749 1 kittycat len = strlen(val);
2750
2751 if(len <= 0)
2752 continue;
2753
2754 snprintf(buffer, sizeof(buffer), "%s", getvar(ptr));
2755 while((pos=strstr(buffer, val)) != NULL)
2756 {
2757 int len = strlen(val);
2758 memmove(pos, pos+len, strlen(pos+len)+1);
2759 }
2760 setenv(ptr, buffer, 1);
2761 continue;
2762 }
2763
2764 20 kittycat if(*(val-1) == '?')
2765 1 kittycat {
2766 20 kittycat *(val-1) = 0;
2767 if(*getvar(ptr))
2768 ovr = 0;
2769 1 kittycat }
2770 20 kittycat *(val++) = 0;
2771 if(isspace(*val))
2772 val = extract_word(val, sizeof(linebuf)+linebuf-val);
2773 1 kittycat
2774 if(*val)
2775 {
2776 int i = 0;
2777 do {
2778 char *next_word = extract_word(val, sizeof(linebuf)+
2779 linebuf-val);
2780 i += snprintf(buffer+i, sizeof(buffer)-i, "%s ", val);
2781 val = next_word;
2782 } while(*val);
2783 if(i > 0) buffer[i-1] = 0;
2784 }
2785 if(buffer[0])
2786 setenv(ptr, buffer, ovr);
2787 else if(ovr)
2788 unsetenv(ptr);
2789 continue;
2790 }
2791
2792
2793 /* Reset the return value and 'do' status */
2794 has_do = 0;
2795 // ret = 0;
2796
2797 /* Don't display normal output */
2798 if(linebuf[0] == '@')
2799 {
2800 shh = 1;
2801 memmove(linebuf, linebuf+1, strlen(linebuf));
2802 }
2803
2804 /* Set error suppression level */
2805 if(linebuf[0] == '!')
2806 {
2807 ignore_err = 2;
2808 memmove(linebuf, linebuf+1, strlen(linebuf));
2809 }
2810 else if(linebuf[0] == '-')
2811 {
2812 ignore_err = 1;
2813 memmove(linebuf, linebuf+1, strlen(linebuf));
2814 }
2815
2816
2817 /* Call an external program via the system() function. Parameters are
2818 * passed along as-is. */
2819 if(strcasecmp("call", linebuf) == 0)
2820 {
2821 unsigned int i = 0;
2822 char *wrd = ptr;
2823 while(*wrd)
2824 {
2825 char *next = extract_word(wrd, linebuf+sizeof(linebuf)-wrd);
2826 #define CHARS_TO_ESC "\\\"%$"
2827 #define CHARS_TO_QUOTE "' \t\n()[]<>;&|"
2828 if(strpbrk(wrd, CHARS_TO_ESC))
2829 {
2830 while(*wrd)
2831 {
2832 if(strchr(CHARS_TO_ESC CHARS_TO_QUOTE, *wrd) &&
2833 i < sizeof(buffer)-2)
2834 buffer[i++] = '\\';
2835 if(i < sizeof(buffer)-1)
2836 buffer[i++] = *(wrd++);
2837 }
2838 if(i < sizeof(buffer)-1)
2839 buffer[i++] = ' ';
2840 buffer[i] = 0;
2841 }
2842 else if(strpbrk(wrd, CHARS_TO_QUOTE))
2843 i += snprintf(buffer+i, sizeof(buffer)-i, "\"%s\" ", wrd);
2844 else
2845 i += snprintf(buffer+i, sizeof(buffer)-i, "%s ", wrd);
2846 wrd = next;
2847 }
2848 if(i > 0) buffer[i-1] = 0;
2849
2850 if(!shh)
2851 {
2852 printf("%s\n", buffer);
2853 fflush(stdout);
2854 }
2855 27 kittycat ret = system(buffer);
2856 if(WIFEXITED(ret))
2857 ret = WEXITSTATUS(ret);
2858 else
2859 ret = -1;
2860 if(ret != 0)
2861 1 kittycat {
2862 if(!ignore_err)
2863 {
2864 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
2865 goto reparse;
2866 }
2867 if(ignore_err < 2)
2868 {
2869 printf("--- Error %d ignored. ---\n\n", ++ignored_errors);
2870 fflush(stdout);
2871 }
2872 }
2873
2874 continue;
2875 }
2876
2877 /* Invokes an alternate script within the same context, and returns
2878 * control when it exits. All variables and command-line options will
2879 * persists into and out of invoked scripts. Errors and exit calls will
2880 * cause all scripts to abort. To safely exit from an invoked script
2881 * before the end of the file, and continue the previous, use
2882 * 'uninvoke' */
2883 if(strcasecmp("invoke", linebuf) == 0)
2884 {
2885 size_t i;
2886 FILE *f2;
2887 char *fname2;
2888
2889 extract_line(ptr, sizeof(linebuf)+linebuf-ptr);
2890 f2 = f;
2891 fname2 = fname;
2892 f = fopen(ptr, "r");
2893 if(!f)
2894 {
2895 f = f2;
2896 ret = 1;
2897 if(ignore_err < 2)
2898 printf("Could not open script '%s'!\n", ptr);
2899 if(!ignore_err)
2900 {
2901 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
2902 goto reparse;
2903 }
2904 if(ignore_err < 2)
2905 printf("--- Error %d ignored. ---\n\n", ++ignored_errors);
2906 fflush(stdout);
2907 continue;
2908 }
2909 ret = 0;
2910 fname = strdup(ptr);
2911
2912 i = invoke_backup_size;
2913 RESIZE_LIST(invoke_backup, i+1);
2914
2915 invoke_backup[i].f = f2;
2916 invoke_backup[i].fname = fname2;
2917
2918 invoke_backup[i].bkp_lbuf = strdup(linebuf);
2919 invoke_backup[i].bkp_nextline = nextline;
2920
2921 invoke_backup[i].bkp_line = curr_line;
2922 invoke_backup[i].bkp_did_else = did_else;
2923 invoke_backup[i].bkp_did_cmds = did_cmds;
2924 invoke_backup[i].bkp_do_level = do_level;
2925
2926
2927 nextline = NULL;
2928
2929 curr_line = 0;
2930 did_else = 0;
2931 did_cmds = 0;
2932 do_level = 0;
2933
2934 continue;
2935 }
2936
2937 if(strcasecmp(linebuf, "popfront") == 0)
2938 {
2939 char *front_word;
2940 char *varstr;
2941 char *next;
2942
2943 next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
2944 extract_word(next, sizeof(linebuf)+linebuf-next);
2945
2946 varstr = malloc(65536);
2947 if(!varstr)
2948 {
2949 snprintf(linebuf, sizeof(linebuf), "exit -1\n");
2950 goto reparse;
2951 }
2952 strncpy(varstr, getvar(ptr), 65536);
2953 front_word = varstr;
2954 while(*varstr && isspace(*varstr))
2955 ++varstr;
2956 if(front_word != varstr)
2957 memmove(front_word, varstr, strlen(varstr)+1);
2958
2959 varstr = expand_string(front_word, " ", 65536, 0);
2960 while(isspace(*varstr))
2961 ++varstr;
2962
2963 setenv(ptr, varstr, 1);
2964
2965 free(front_word);
2966 continue;
2967 }
2968
2969
2970 if(strcasecmp("define", linebuf) == 0)
2971 {
2972 char *val = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
2973 extract_line(val, sizeof(linebuf)+linebuf-val);
2974
2975 if(*val == 0)
2976 {
2977 for(i = 0;(size_t)i < defines_size;++i)
2978 {
2979 if(strcasecmp(ptr, defines[i].name) != 0)
2980 continue;
2981
2982 free(defines[i].name);
2983 free(defines[i].val);
2984 if((size_t)i < defines_size)
2985 memmove(&defines[i], &defines[i+1], sizeof(defines[0])*
2986 (defines_size-i-1));
2987
2988 RESIZE_LIST(defines, defines_size-1);
2989 break;
2990 }
2991 }
2992 else
2993 {
2994 for(i = 0;(size_t)i < defines_size;++i)
2995 {
2996 if(strcasecmp(ptr, defines[i].name) == 0)
2997 break;
2998 }
2999 if((size_t)i == defines_size)
3000 {
3001 RESIZE_LIST(defines, i+1);
3002
3003 defines[i].val = NULL;
3004 defines[i].name = strdup(ptr);
3005 if(!defines[i].name)
3006 {
3007 fprintf(USEABLE_ERR, "\n\n*** Critical Error ***\n"
3008 "Out of memory duplicating string "
3009 "'%s'!!\n\n", ptr);
3010 snprintf(linebuf, sizeof(linebuf), "exit -1\n");
3011 goto reparse;
3012 }
3013 }
3014
3015 free(defines[i].val);
3016 defines[i].val = strdup(val);
3017 if(!defines[i].val)
3018 {
3019 fprintf(USEABLE_ERR, "\n\n*** Critical Error ***\n"
3020 "Out of memory duplicating string "
3021 "'%s'!!\n\n", val);
3022 snprintf(linebuf, sizeof(linebuf), "exit -1\n");
3023 goto reparse;
3024 }
3025 }
3026
3027 continue;
3028 }
3029
3030 /* Compiles a list of source files, and stores them in a list to be
3031 * linked later. Compiled files are placed in the 'OBJ_DIR' with the
3032 * extension changed to 'OBJ_EXT'. C and C++ files are compiled by the
3033 * programs stored in 'CC' and 'CXX' respectively, using the flags
3034 * stored in 'CPPFLAGS', 'CFLAGS', and 'CXXFLAGS' as expected. Unknown
3035 * file types are silently ignored. */
3036 if(strcasecmp("compile", linebuf) == 0)
3037 {
3038 size_t i;
3039
3040 for(i = 0;i < sources_size;++i)
3041 free(sources[i]);
3042 CLEAR_LIST(sources);
3043
3044 goto compile_more_sources;
3045 }
3046
3047 /* Adds more source files to the list, and compiles them as above */
3048 if(strcasecmp("compileadd", linebuf) == 0)
3049 {
3050 compile_more_sources:
3051 tmp = 0;
3052 while(*ptr)
3053 {
3054 char *src, *ext, *next;
3055 struct stat statbuf;
3056
3057 next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
3058 RESIZE_LIST(sources, sources_size+1);
3059 sources[sources_size-1] = strdup(ptr);
3060
3061 ext = strrchr(ptr, '/');
3062 if(!ext) ext = ptr;
3063 ext = strrchr(ext, '.');
3064 if(!ext)
3065 goto next_src_file;
3066
3067 *ext = 0;
3068 snprintf(obj, sizeof(obj), "${OBJ_DIR}/'%s'${OBJ_EXT}", ptr);
3069 expand_string(obj, "", sizeof(obj), 0);
3070 *ext = '.';
3071
3072 src = find_src(ptr);
3073
3074 if(stat(obj, &statbuf) == 0)
3075 {
3076 if(!check_obj_deps(ptr, src, statbuf.st_mtime))
3077 goto next_src_file;
3078 }
3079
3080 i = 0;
3081 if(build_command(buffer, sizeof(buffer), ptr, src, obj) == 0)
3082 goto compile_it;
3083
3084 if(strcasecmp(ext+1, "c") == 0)
3085 i += snprintf(buffer+i, sizeof(buffer)-i,
3086 "${CC} ${CPPFLAGS} ${CFLAGS}");
3087 else if(strcasecmp(ext+1, "cc") == 0 ||
3088 strcasecmp(ext+1, "cpp") == 0 ||
3089 strcasecmp(ext+1, "cxx") == 0)
3090 i += snprintf(buffer+i, sizeof(buffer)-i,
3091 "${CXX} ${CPPFLAGS} ${CXXFLAGS}");
3092 else
3093 goto next_src_file;
3094
3095 *ext = 0;
3096 if(*getvar("DEP_OPT"))
3097 i += snprintf(buffer+i, sizeof(buffer)-i,
3098 " ${DEP_OPT}\\\"${DEP_DIR}/'%s'${DEP_EXT}\\\"",
3099 ptr);
3100 i += snprintf(buffer+i, sizeof(buffer)-i,
3101 " ${OUT_OPT}\\\"${OBJ_DIR}/'%s'${OBJ_EXT}\\\"",
3102 ptr);
3103 *ext = '.';
3104
3105 i += snprintf(buffer+i, sizeof(buffer)-i,
3106 " ${SRC_OPT}'\"%s\"'", src);
3107
3108 compile_it:
3109 expand_string(buffer, "", sizeof(buffer), 0);
3110 if(!shh)
3111 {
3112 if(verbose)
3113 printf("%s\n", buffer);
3114 else
3115 printf("Compiling %s...\n", src);
3116 fflush(stdout);
3117 }
3118
3119 27 kittycat ret = system(buffer);
3120 if(WIFEXITED(ret))
3121 ret = WEXITSTATUS(ret);
3122 else
3123 ret = -1;
3124 if(ret != 0)
3125 1 kittycat {
3126 tmp = ret;
3127 if(!ignore_err)
3128 {
3129 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
3130 goto reparse;
3131 }
3132 if(ignore_err < 2)
3133 {
3134 printf("--- Error %d ignored. ---\n\n",
3135 ++ignored_errors);
3136 fflush(stdout);
3137 }
3138 }
3139
3140 next_src_file:
3141 ptr = next;
3142 }
3143 ret = tmp;
3144 continue;
3145 }
3146
3147 /* Links an executable file, using the previously-compiled source
3148 * files. The executable will have 'EXE_EXT' appended. */
3149 if(strcasecmp("linkexec", linebuf) == 0)
3150 {
3151 struct stat statbuf;
3152 time_t exe_time = 0;
3153 int do_link = 1;
3154
3155 if(sources_size == 0)
3156 {
3157 ret = 1;
3158 if(ignore_err < 2)
3159 printf("\n!!! %s error, line %d !!!\n"
3160 "Trying to build %s with undefined sources!\n\n",
3161 fname, curr_line, ptr);
3162 if(!ignore_err)
3163 {
3164 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
3165 goto reparse;
3166 }
3167 if(ignore_err < 2)
3168 printf("--- Error %d ignored. ---\n\n", ++ignored_errors);
3169 fflush(stdout);
3170 continue;
3171 }
3172 ret = 0;
3173
3174 extract_line(ptr, sizeof(linebuf)+linebuf-ptr);
3175
3176 snprintf(obj, sizeof(obj), "'%s'${EXE_EXT}", ptr);
3177 expand_string(obj, "", sizeof(obj), 0);
3178 if(stat(obj, &statbuf) == 0)
3179 {
3180 exe_time = statbuf.st_mtime;
3181 do_link = 0;
3182 }
3183
3184 i = 0;
3185 i += snprintf(buffer+i, sizeof(buffer)-i, "${LD}");
3186 i += snprintf(buffer+i, sizeof(buffer)-i, " ${OUT_OPT}'\"%s\"'",
3187 obj);
3188
3189 i += build_obj_list(buffer+i, sizeof(buffer)-i, exe_time,
3190 &do_link);
3191
3192 if(!do_link)
3193 {
3194 char *buf = (char*)getvar("EXTRA_LD_DEPS");
3195 if(*buf)
3196 {
3197 char *ptr = malloc(BUF_SIZE);
3198 strncpy(ptr, buf, BUF_SIZE);
3199 buf = ptr;
3200
3201 while(*ptr)
3202 {
3203 char *next = expand_string(ptr, " ", BUF_SIZE+ptr-buf, 0);
3204 if(*next) *(next++) = 0;
3205 next = expand_string(next, "!", BUF_SIZE+ptr-next, 0);
3206
3207 if(stat(ptr, &statbuf) != 0 ||
3208 statbuf.st_mtime > exe_time)
3209 {
3210 free(buf);
3211 buf = NULL;
3212
3213 do_link = 1;
3214 break;
3215 }
3216
3217 ptr = next;
3218 }
3219
3220 free(buf);
3221 }
3222
3223 if(!do_link)
3224 continue;
3225 }
3226
3227 i += snprintf(buffer+i, sizeof(buffer)-i, " ${LDFLAGS}");
3228 expand_string(buffer, "", sizeof(buffer), 0);
3229
3230 if(!shh)
3231 {
3232 if(verbose)
3233 printf("%s\n", buffer);
3234 else
3235 printf("Linking %s...\n", obj);
3236 fflush(stdout);
3237 }
3238 27 kittycat ret = system(buffer);
3239 if(WIFEXITED(ret))
3240 ret = WEXITSTATUS(ret);
3241 else
3242 ret = -1;
3243 if(ret != 0)
3244 1 kittycat {
3245 if(!ignore_err)
3246 {
3247 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
3248 goto reparse;
3249 }
3250 if(ignore_err < 2)
3251 {
3252 printf("--- Error %d ignored. ---\n\n", ++ignored_errors);
3253 fflush(stdout);
3254 }
3255 }
3256
3257 continue;
3258 }
3259
3260 /* Links a standard archive library, using the previously-compiled
3261 * source files. The file will have 'LIB_PRE' prepended, and is
3262 * sub-directory-aware, as well as have 'LIB_EXT' appended. */
3263 if(strcasecmp("linklib", linebuf) == 0)
3264 {
3265 struct stat statbuf;
3266 time_t lib_time = 0;
3267 int do_link = 1;
3268
3269 if(sources_size == 0)
3270 {
3271 ret = 1;
3272 if(ignore_err < 2)
3273 printf("!!! %s error, line %d !!!\n"
3274 "Trying to build %s with undefined sources!\n",
3275 fname, curr_line, ptr);
3276 if(!ignore_err)
3277 {
3278 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
3279 goto reparse;
3280 }
3281 if(ignore_err < 2)
3282 printf("--- Error %d ignored. ---\n\n", ++ignored_errors);
3283 fflush(stdout);
3284 continue;
3285 }
3286 ret = 0;
3287
3288 extract_line(ptr, sizeof(linebuf)+linebuf-ptr);
3289
3290 libify_name(obj, sizeof(obj), ptr);
3291 if(stat(obj, &statbuf) == 0)
3292 {
3293 lib_time = statbuf.st_mtime;
3294 do_link = 0;
3295 }
3296
3297 i = 0;
3298 i += snprintf(buffer+i, sizeof(buffer)-i, "${AR} ${AR_OPT}");
3299 i += snprintf(buffer+i, sizeof(buffer)-i, " '\"%s\"'", obj);
3300
3301 i += build_obj_list(buffer+i, sizeof(buffer)-i, lib_time,
3302 &do_link);
3303
3304 if(!do_link)
3305 continue;
3306
3307 remove(obj);
3308 expand_string(buffer, "", sizeof(buffer), 0);
3309
3310 if(!shh)
3311 {
3312 if(verbose)
3313 printf("%s\n", buffer);
3314 else
3315 printf("Linking %s...\n", obj);
3316 fflush(stdout);
3317 }
3318 27 kittycat ret = system(buffer);
3319 if(WIFEXITED(ret))
3320 ret = WEXITSTATUS(ret);
3321 else
3322 ret = -1;
3323 if(ret != 0)
3324 1 kittycat {
3325 if(!ignore_err)
3326 {
3327 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
3328 goto reparse;
3329 }
3330 if(ignore_err < 2)
3331 {
3332 printf("--- Error %d ignored. ---\n\n", ++ignored_errors);
3333 fflush(stdout);
3334 }
3335 }
3336
3337 continue;
3338 }
3339
3340 /* Loads a list of words into a buffer, to later execute an action on
3341 * them */
3342 if(strcasecmp("loadlist", linebuf) == 0)
3343 {
3344 size_t i;
3345 for(i = 0;i < loaded_files_size;++i)
3346 free(loaded_files[i]);
3347 CLEAR_LIST(loaded_files);
3348
3349 while(*ptr)
3350 {
3351 char *next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
3352
3353 i = loaded_files_size;
3354 RESIZE_LIST(loaded_files, i+1);
3355 loaded_files[i] = strdup(ptr);
3356
3357 ptr = next;
3358 }
3359
3360 continue;
3361 }
3362
3363 /* Executes a command on the loaded file list */
3364 if(strcasecmp("execlist", linebuf) == 0)
3365 {
3366 size_t p = 0;
3367
3368 if(loaded_files_size == 0)
3369 {
3370 ret = 1;
3371 if(ignore_err < 2)
3372 printf("\n\n!!! %s error, line %d !!!\n"
3373 "'loadexec' called with no list!\n\n", fname,
3374 curr_line);
3375 if(!ignore_err)
3376 {
3377 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
3378 goto reparse;
3379 }
3380 if(ignore_err < 2)
3381 printf("--- Error %d ignored. ---\n\n", ++ignored_errors);
3382 fflush(stdout);
3383 continue;
3384 }
3385 ret = 0;
3386
3387 tmp = 0;
3388 extract_line(ptr, sizeof(linebuf)+linebuf-ptr);
3389
3390 8 kittycat while(p < loaded_files_size)
3391 1 kittycat {
3392 8 kittycat char *curr = loaded_files[p++];
3393 1 kittycat char *cmd_ptr = ptr;
3394 int i;
3395
3396 i = 0;
3397 while(*cmd_ptr && (size_t)i+1 < sizeof(buffer))
3398 {
3399 if(strncasecmp(cmd_ptr, "<@>", 3) == 0)
3400 {
3401 i += snprintf(buffer+i, sizeof(buffer)-i, "%s",
3402 curr);
3403 cmd_ptr += 3;
3404 }
3405 else
3406 {
3407 if(cmd_ptr[0] == '\\' && cmd_ptr[1] != 0 &&
3408 (size_t)i+2 < sizeof(buffer))
3409 7 kittycat cmd_ptr++;
3410 1 kittycat buffer[i++] = *(cmd_ptr++);
3411 buffer[i] = 0;
3412 }
3413 }
3414
3415 if(!shh)
3416 {
3417 printf("%s\n", buffer);
3418 fflush(stdout);
3419 }
3420 27 kittycat ret = system(buffer);
3421 if(WIFEXITED(ret))
3422 ret = WEXITSTATUS(ret);
3423 else
3424 ret = -1;
3425 if(ret != 0)
3426 1 kittycat {
3427 tmp = ret;
3428 if(!ignore_err)
3429 {
3430 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
3431 goto reparse;
3432 }
3433 if(ignore_err < 2)
3434 printf("--- Error %d ignored. ---\n\n",
3435 ++ignored_errors);
3436 fflush(stdout);
3437 }
3438 }
3439
3440 ret = tmp;
3441 continue;
3442 }
3443
3444 /* Prints a string to the console. If a '.' char is used at the
3445 * beginning of string, it will be skipped */
3446 if(strcasecmp("echo", linebuf) == 0)
3447 {
3448 extract_line(ptr, sizeof(linebuf)+linebuf-ptr);
3449 printf("%s\n", ptr);
3450 fflush(stdout);
3451 continue;
3452 }
3453
3454 /* Prints a string to the console without a newline. If a '.' char is
3455 * used at the beginning of string, it will be skipped */
3456 if(strcasecmp("put", linebuf) == 0)
3457 {
3458 extract_line(ptr, sizeof(linebuf)+linebuf-ptr);
3459 printf("%s", ptr);
3460 fflush(stdout);
3461 continue;
3462 }
3463
3464 /* Creates/truncates a file and writes a string to it */
3465 if(strcasecmp("writefile", linebuf) == 0)
3466 {
3467 char *str;
3468 FILE *o;
3469
3470 str = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
3471 o = fopen(ptr, "w");
3472 if(!o)
3473 {
3474 ret = 1;
3475 if(ignore_err < 2)
3476 printf("Could not create file '%s'!\n", ptr);
3477 if(!ignore_err)
3478 {
3479 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
3480 goto reparse;
3481 }
3482 if(ignore_err < 2)
3483 printf("--- Error %d ignored. ---\n\n", ++ignored_errors);
3484 fflush(stdout);
3485 continue;
3486 }
3487 ret = 0;
3488
3489 extract_line(str, sizeof(linebuf)+linebuf-str);
3490 fprintf(o, "%s\n", str);
3491 fclose(o);
3492 continue;
3493 }
3494
3495 /* Appends a string to a file */
3496 if(strcasecmp("appendfile", linebuf) == 0)
3497 {
3498 char *str;
3499 FILE *o;
3500
3501 str = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
3502 o = fopen(ptr, "a");
3503 if(!o)
3504 {
3505 ret = 1;
3506 if(ignore_err < 2)
3507 printf("Could not create file '%s'!\n", ptr);
3508 if(!ignore_err)
3509 {
3510 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
3511 goto reparse;
3512 }
3513 if(ignore_err < 2)
3514 printf("--- Error %d ignored. ---\n\n", ++ignored_errors);
3515 fflush(stdout);
3516 continue;
3517 }
3518 ret = 0;
3519
3520 extract_line(str, sizeof(linebuf)+linebuf-str);
3521 fprintf(o, "%s\n", str);
3522 fclose(o);
3523 continue;
3524 }
3525
3526 /* Jumps to the specified label. A label is denoted by a ':' prepended
3527 * to it at the beginning of a line */
3528 if(strcasecmp("goto", linebuf) == 0)
3529 {
3530 int src_line;
3531 char *lbl;
3532
3533 extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
3534 lbl = strdup(ptr);
3535 if(!lbl)
3536 {
3537 fprintf(USEABLE_ERR, "\n\n** Critical Error **\n"
3538 "Out of memory duplicating string "
3539 "'%s'\n\n", lbl);
3540 snprintf(linebuf, sizeof(linebuf), "exit -1\n");
3541 goto reparse;
3542 }
3543
3544 rewind(f);
3545 src_line = curr_line;
3546 curr_line = 0;
3547 wait_for_done = 0;
3548 did_else = 0;
3549 did_cmds = 0;
3550 do_level = 0;
3551 while(fgets(linebuf, sizeof(linebuf), f) != NULL)
3552 {
3553 ++curr_line;
3554 while(linebuf[0])
3555 {
3556 int i;
3557 extract_line(linebuf, sizeof(linebuf));
3558
3559 for(i = 0;isspace(linebuf[i]);++i)
3560 ;
3561 memmove(linebuf, &linebuf[i], strlen(&linebuf[i])+1);
3562 if(linebuf[0] == ':' && strcasecmp(linebuf+1, lbl) == 0)
3563 {
3564 free(lbl);
3565 goto main_loop_start;
3566 }
3567 if(!nextline)
3568 break;
3569 strcpy(linebuf, nextline);
3570 free(nextline);
3571 nextline = NULL;
3572 }
3573 }
3574 fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n"
3575 "Label '%s' not found!\n\n", fname,
3576 src_line, lbl);
3577 free(lbl);
3578 snprintf(linebuf, sizeof(linebuf), "exit 1\n");
3579 goto reparse;
3580 }
3581
3582
3583 /* Stores a list of paths to look for source files in. Passing only
3584 * '.' clears the list. */
3585 if(strcasecmp("src_paths", linebuf) == 0)
3586 {
3587 unsigned int count = 0;
3588 char *next;
3589
3590 while(count < src_paths_size)
3591 {
3592 free(src_paths[count]);
3593 ++count;
3594 }
3595 CLEAR_LIST(src_paths);
3596
3597 count = 0;
3598 while(*ptr)
3599 {
3600 next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
3601 if(count == 0 && !*next && (strcmp(ptr, ".") == 0 ||
3602 strlen(ptr) == 0))
3603 break;
3604
3605 RESIZE_LIST(src_paths, count+1);
3606
3607 src_paths[count] = strdup(ptr);
3608 if(!src_paths[count])
3609 {
3610 fprintf(USEABLE_ERR, "\n\n** Critical Error **\n"
3611 "Out of memory duplicating string "
3612 "'%s'\n\n", ptr);
3613 snprintf(linebuf, sizeof(linebuf), "exit -1\n");
3614 goto reparse;
3615 }
3616 ++count;
3617 ptr = next;
3618 }
3619 continue;
3620 }
3621
3622 /* Deletes the specified executables, appending 'EXE_EXT' to the names
3623 * as needed */
3624 if(strcasecmp("rmexec", linebuf) == 0)
3625 {
3626 char *next = ptr;
3627 while(*(ptr=next))
3628 {
3629 next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
3630 snprintf(buffer, sizeof(buffer), "'%s'${EXE_EXT}", ptr);
3631 expand_string(buffer, "", sizeof(buffer), 0);
3632
3633 if(stat(buffer, &statbuf) == -1 && errno == ENOENT)
3634 continue;
3635
3636 if(!shh)
3637 {
3638 if(verbose) printf("remove(\"%s\");\n", buffer);
3639 else printf("Deleting %s...\n", buffer);
3640 fflush(stdout);
3641 }
3642 if((ret=remove(buffer)) != 0)
3643 {
3644 if(ignore_err < 2)
3645 printf("!!! Could not delete '%s' !!!\n", buffer);
3646 if(!ignore_err)
3647 {
3648 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
3649 goto reparse;
3650 }
3651 if(ignore_err < 2)
3652 printf("--- Error %d ignored. ---\n\n",
3653 ++ignored_errors);
3654 fflush(stdout);
3655 }
3656 }
3657
3658 continue;
3659 }
3660
3661 /* Deletes the specified libraries, prepending 'LIB_PRE' to the
3662 * filename portions and appending with 'LIB_EXT' */
3663 if(strcasecmp("rmlib", linebuf) == 0)
3664 {
3665 char *next = ptr;
3666 while(*(ptr=next))
3667 {
3668 next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
3669 libify_name(buffer, sizeof(buffer), ptr);
3670
3671 if(stat(buffer, &statbuf) == -1 && errno == ENOENT)
3672 continue;
3673
3674 if(!shh)
3675 {
3676 if(verbose) printf("remove(\"%s\");\n", buffer);
3677 else printf("Deleting %s...\n", buffer);
3678 fflush(stdout);
3679 }
3680 if((ret=remove(buffer)) != 0)
3681 {
3682 if(ignore_err < 2)
3683 printf("!!! Could not delete '%s' !!!\n", buffer);
3684 if(!ignore_err)
3685 {
3686 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
3687 goto reparse;
3688 }
3689 if(ignore_err < 2)
3690 printf("--- Error %d ignored. ---\n\n",
3691 ++ignored_errors);
3692 fflush(stdout);
3693 }
3694 } while(*(ptr=next));
3695 continue;
3696 }
3697
3698 /* Removes a list of object files and their associated dependancy
3699 * files, replacing the extension of the named file as necesarry */
3700 if(strcasecmp("rmobj", linebuf) == 0)
3701 {
3702 char *ext;
3703 char *next = ptr;
3704 while(*(ptr=next))
3705 {
3706 next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
3707
3708 ext = strrchr(ptr, '/');
3709 if(!ext) ext = ptr;
3710 ext = strrchr(ext, '.');
3711
3712 if(ext) *ext = 0;
3713 snprintf(buffer, sizeof(buffer), "${OBJ_DIR}/'%s'${OBJ_EXT}",
3714 ptr);
3715 expand_string(buffer, "", sizeof(buffer), 0);
3716 if(ext) *ext = '.';
3717
3718 if(stat(buffer, &statbuf) == 0 || errno != ENOENT)
3719 {
3720 if(!shh)
3721 {
3722 if(verbose) printf("remove(\"%s\");\n", buffer);
3723 else printf("Deleting %s...\n", buffer);
3724 fflush(stdout);
3725 }
3726 if((ret=remove(buffer)) != 0)
3727 {
3728 if(ignore_err < 2)
3729 printf("!!! Could not delete '%s' !!!\n", buffer);
3730 if(!ignore_err)
3731 {
3732 snprintf(linebuf, sizeof(linebuf), "exit %d\n",
3733 ret);
3734 goto reparse;
3735 }
3736 if(ignore_err < 2)
3737 printf("--- Error %d ignored. ---\n\n",
3738 ++ignored_errors);
3739 }
3740 }
3741
3742 if(ext) *ext = 0;
3743 snprintf(buffer, sizeof(buffer), "${DEP_DIR}/'%s'${DEP_EXT}",
3744 ptr);
3745 expand_string(buffer, "", sizeof(buffer), 0);
3746 if(ext) *ext = '.';
3747
3748 if(stat(buffer, &statbuf) == -1 && errno == ENOENT)
3749 continue;
3750
3751 if(!shh)
3752 {
3753 if(verbose) printf("remove(\"%s\");\n", buffer);
3754 else printf("Deleting %s...\n", buffer);
3755 fflush(stdout);
3756 }
3757 if((ret=remove(buffer)) != 0)
3758 {
3759 if(ignore_err < 2)
3760 printf("!!! Could not delete '%s' !!!\n", buffer);
3761 if(!ignore_err)
3762 {
3763 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
3764 goto reparse;
3765 }
3766 if(ignore_err < 2)
3767 printf("--- Error %d ignored. ---\n\n",
3768 ++ignored_errors);
3769 fflush(stdout);
3770 }
3771 }
3772 continue;
3773 }
3774
3775 /* Removes a list of files or empty directories */
3776 if(strcasecmp("rm", linebuf) == 0)
3777 {
3778 #ifdef _WIN32
3779 struct stat sbuf;
3780 #endif
3781 char *next = ptr;
3782 while(*(ptr=next))
3783 {
3784 next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
3785
3786 if(stat(ptr, &statbuf) == -1 && errno == ENOENT)
3787 continue;
3788
3789 if(!shh)
3790 {
3791 if(verbose) printf("remove(\"%s\");\n", ptr);
3792 else printf("Deleting %s...\n", ptr);
3793 fflush(stdout);
3794 }
3795 #ifdef _WIN32
3796 if(stat(ptr, &sbuf) == 0 && S_ISDIR(sbuf.st_mode))
3797 ret = rmdir(ptr);
3798 else
3799 #endif
3800 ret = remove(ptr);
3801 if(ret != 0)
3802 {
3803 if(ignore_err < 2)
3804 printf("!!! Could not delete '%s' !!!\n", ptr);
3805 if(!ignore_err)
3806 {
3807 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
3808 goto reparse;
3809 }
3810 if(ignore_err < 2)
3811 printf("--- Error %d ignored. ---\n\n",
3812 ++ignored_errors);
3813 fflush(stdout);
3814 }
3815 }
3816 continue;
3817 }
3818
3819 /* Creates a directory (with mode 700 in Unix) */
3820 if(strcasecmp("mkdir", linebuf) == 0)
3821 {
3822 extract_line(ptr, sizeof(linebuf)+linebuf-ptr);
3823
3824 if(!shh)
3825 {
3826 if(!verbose) printf("Creating directory %s/...\n", ptr);
3827 #ifdef _WIN32
3828 else printf("mkdir(\"%s\");\n", ptr);
3829 fflush(stdout);
3830 }
3831 if((ret=mkdir(ptr)) != 0)
3832 #else
3833 else printf("mkdir(\"%s\", S_IRWXU);\n", ptr);
3834 fflush(stdout);
3835 }
3836 if((ret=mkdir(ptr, S_IRWXU)) != 0)
3837 #endif
3838 {
3839 if(ignore_err < 2)
3840 printf("!!! Could not create directory !!!\n");
3841 if(!ignore_err)
3842 {
3843 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
3844 goto reparse;
3845 }
3846 if(ignore_err < 2)
3847 printf("--- Error %d ignored. ---\n\n", ++ignored_errors);
3848 fflush(stdout);
3849 }
3850 continue;
3851 }
3852
3853 /* Enables/disables command verboseness */
3854 if(strcasecmp("verbose", linebuf) == 0)
3855 {
3856 extract_line(ptr, sizeof(linebuf)+linebuf-ptr);
3857 if(*ptr)
3858 verbose = atoi(ptr);
3859 continue;
3860 }
3861
3862 /* Leaves the current script, falling back to the previous if the
3863 * current was started with the invoke command. Otherwise, it behaves
3864 * like exit */
3865 if(strcasecmp("uninvoke", linebuf) == 0)
3866 {
3867 size_t i = invoke_backup_size-1;
3868 extract_line(ptr, sizeof(linebuf)+linebuf-ptr);
3869
3870 ret = atoi(ptr);
3871 if(invoke_backup_size == 0)
3872 {
3873 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
3874 goto reparse;
3875 }
3876
3877 fclose(f);
3878 f = invoke_backup[i].f;
3879 invoke_backup[i].f = NULL;
3880
3881 free(fname);
3882 fname = invoke_backup[i].fname;
3883
3884 strcpy(linebuf, invoke_backup[i].bkp_lbuf);
3885 free(invoke_backup[i].bkp_lbuf);
3886
3887 free(nextline);
3888 nextline = invoke_backup[i].bkp_nextline;
3889
3890 curr_line = invoke_backup[i].bkp_line;
3891 did_else = invoke_backup[i].bkp_did_else;
3892 did_cmds = invoke_backup[i].bkp_did_cmds;
3893 do_level = invoke_backup[i].bkp_do_level;
3894
3895 RESIZE_LIST(invoke_backup, i);
3896
3897 continue;
3898 }
3899
3900 /* Copies a file */
3901 if(strcasecmp("copy", linebuf) == 0)
3902 {
3903 char *dfile, *end;
3904 struct stat st;
3905
3906 dfile = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
3907 if(!*ptr || !*dfile)
3908 {
3909 ret = 1;
3910 if(ignore_err < 2)
3911 printf("\n\n!!! %s error, line %d !!!\n"
3912 "Improper arguments to 'copy'!\n", fname,
3913 curr_line);
3914 if(!ignore_err)
3915 {
3916 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
3917 goto reparse;
3918 }
3919 if(ignore_err < 2)
3920 printf("--- Error %d ignored. ---\n", ++ignored_errors);
3921 fflush(stdout);
3922 continue;
3923 }
3924 ret = 0;
3925 end = extract_word(dfile, sizeof(linebuf)+linebuf-dfile);
3926 if(dfile[strlen(dfile)-1] == '/' || (stat(dfile, &st) == 0 &&
3927 S_ISDIR(st.st_mode)))
3928 {
3929 char *fn = strrchr(ptr, '/');
3930 snprintf(obj, sizeof(obj), "%s%s%s", dfile,
3931 ((dfile[strlen(dfile)-1]=='/')?"":"/"),
3932 (fn?(fn+1):ptr));
3933 dfile = obj;
3934 }
3935 if(!shh)
3936 {
3937 if(verbose) printf("copy_file(\"%s\", \"%s\");\n", ptr, dfile);
3938 else printf("Copying '%s' to '%s'...\n", ptr, dfile);
3939 fflush(stdout);
3940 }
3941 if((ret=copy_file(ptr, dfile)) != 0)
3942 {
3943 if(ignore_err < 2)
3944 printf("!!! Could not copy !!!\n");
3945 if(!ignore_err)
3946 {
3947 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
3948 goto reparse;
3949 }
3950 if(ignore_err < 2)
3951 printf("--- Error %d ignored. ---\n\n", ++ignored_errors);
3952 fflush(stdout);
3953 }
3954 extract_line(end, sizeof(linebuf)+linebuf-end);
3955 continue;
3956 }
3957
3958 /* Copies a library file, prepending and appending the names as
3959 * necesarry */
3960 if(strcasecmp("copylib", linebuf) == 0)
3961 {
3962 char *dfile, *end;
3963
3964 dfile = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
3965 if(!*ptr || !*dfile)
3966 {
3967 ret = 1;
3968 if(ignore_err < 2)
3969 printf("\n\n!!! %s error, line %d !!!\n"
3970 "Improper arguments to 'copylib'!\n", fname,
3971 curr_line);
3972 if(!ignore_err)
3973 {
3974 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
3975 goto reparse;
3976 }
3977 if(ignore_err < 2)
3978 printf("--- Error %d ignored. ---\n", ++ignored_errors);
3979 fflush(stdout);
3980 continue;
3981 }
3982 ret = 0;
3983 end = extract_word(dfile, sizeof(linebuf)+linebuf-dfile);
3984 if(dfile[strlen(dfile)-1] == '/')
3985 {
3986 char *fn = strrchr(ptr, '/');
3987 snprintf(obj, sizeof(obj), "%s%s", dfile, (fn?(fn+1):ptr));
3988 libify_name(buffer, sizeof(buffer), obj);
3989 }
3990 else
3991 libify_name(buffer, sizeof(buffer), dfile);
3992
3993 libify_name(obj, sizeof(obj), ptr);
3994
3995 if(!shh)
3996 {
3997 if(verbose) printf("copy_file(\"%s\", \"%s\");\n", obj,
3998 buffer);
3999 else printf("Copying '%s' to '%s'...\n", obj, buffer);
4000 fflush(stdout);
4001 }
4002 if((ret=copy_file(obj, buffer)) != 0)
4003 {
4004 if(ignore_err < 2)
4005 printf("!!! Could not copy !!!\n");
4006 if(!ignore_err)
4007 {
4008 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
4009 goto reparse;
4010 }
4011 if(ignore_err < 2)
4012 printf("--- Error %d ignored. ---\n\n", ++ignored_errors);
4013 fflush(stdout);
4014 }
4015 extract_line(end, sizeof(linebuf)+linebuf-end);
4016 continue;
4017 }
4018
4019 if(strcasecmp("chdir", linebuf) == 0)
4020 {
4021 extract_line(ptr, sizeof(linebuf)+linebuf-ptr);
4022
4023 if(!shh)
4024 {
4025 if(verbose) printf("chdir(\"%s\");\n", ptr);
4026 else printf("Moving to directory '%s'\n", ptr);
4027 fflush(stdout);
4028 }
4029 if((ret=chdir(ptr)) != 0)
4030 {
4031 if(ignore_err < 2)
4032 printf("!!! Could not change directory !!!\n");
4033 if(!ignore_err)
4034 {
4035 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
4036 goto reparse;
4037 }
4038 if(ignore_err < 2)
4039 printf("--- Error %d ignored. ---\n\n", ++ignored_errors);
4040 fflush(stdout);
4041 }
4042 continue;
4043 }
4044
4045 /* Creates an association between a file extension and a command to
4046 * compile files with that association via the compile command */
4047 if(strcasecmp("associate", linebuf) == 0)
4048 {
4049 char *cmd = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
4050 extract_line(cmd, sizeof(linebuf)+linebuf-cmd);
4051
4052 add_association(ptr, cmd);
4053 continue;
4054 }
4055
4056 /* Yay for DOS/Windows allowing \ as a directory seperator. Modify the
4057 * named environment variable to replace \ with / */
4058 if(strcasecmp("fixpath", linebuf) == 0)
4059 {
4060 char *str, *val;
4061 char *end = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
4062 extract_line(end, sizeof(linebuf)+linebuf-ptr);
4063
4064 val = strdup(getvar(ptr));
4065 str = val;
4066
4067 while((str=strchr(str, '\\')) != NULL)
4068 *(str++) = '/';
4069
4070 setenv(ptr, val, 1);
4071 free(val);
4072
4073 continue;
4074 }
4075
4076 /* Sets an alternate file for normal output (stdout) */
4077 if(strcasecmp("setoutput", linebuf) == 0)
4078 {
4079 char *end = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
4080 extract_line(end, sizeof(linebuf)+linebuf-end);
4081
4082 ret = 0;
4083 if(*ptr)
4084 {
4085 int fp = open(ptr, O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, S_IRWXU);
4086 if(fp == -1)
4087 {
4088 ret = 1;
4089 if(ignore_err < 2)
4090 printf("!!! Could not open %s !!!\n", ptr);
4091 if(!ignore_err)
4092 {
4093 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
4094 goto reparse;
4095 }
4096 if(ignore_err < 2)
4097 printf("--- Error %d ignored. ---\n\n",
4098 ++ignored_errors);
4099 fflush(stdout);
4100 continue;
4101 }
4102 fflush(stdout);
4103
4104 if(stdo_bak == -1)
4105 stdo_bak = dup(STDOUT_FILENO);
4106
4107 close(STDOUT_FILENO);
4108 dup2(fp, STDOUT_FILENO);
4109
4110 close(fp);
4111 continue;
4112 }
4113
4114 fflush(stdout);
4115 if(stdo_bak == -1)
4116 continue;
4117
4118 close(STDOUT_FILENO);
4119 dup2(stdo_bak, STDOUT_FILENO);
4120
4121 close(stdo_bak);
4122 stdo_bak = -1;
4123 continue;
4124 }
4125
4126 /* Sets an alternate file for error output (stderr) */
4127 if(strcasecmp("seterror", linebuf) == 0)
4128 {
4129 char *end = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
4130 extract_line(end, sizeof(linebuf)+linebuf-end);
4131
4132 ret = 0;
4133 if(*ptr)
4134 {
4135 int fd = open(ptr, O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, S_IRWXU);
4136 if(fd == -1)
4137 {
4138 ret = 1;
4139 if(ignore_err < 2)
4140 printf("!!! Could not open %s !!!\n", ptr);
4141 if(!ignore_err)
4142 {
4143 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
4144 goto reparse;
4145 }
4146 if(ignore_err < 2)
4147 printf("--- Error %d ignored. ---\n\n",
4148 ++ignored_errors);
4149 fflush(stdout);
4150 continue;
4151 }
4152 fflush(stderr);
4153
4154 if(stde_bak == -1)
4155 {
4156 stde_bak = dup(STDERR_FILENO);
4157 stde_stream = fdopen(stde_bak, "w");
4158 }
4159
4160 close(STDERR_FILENO);
4161 dup2(fd, STDERR_FILENO);
4162
4163 close(fd);
4164 continue;
4165 }
4166
4167 fflush(stderr);
4168 if(stde_bak == -1)
4169 continue;
4170
4171 close(STDERR_FILENO);
4172 dup2(stde_bak, STDERR_FILENO);
4173
4174 fclose(stde_stream);
4175 stde_stream = NULL;
4176 stde_bak = -1;
4177 continue;
4178 }
4179
4180
4181 /* Changes the file to read input from. Pass nothing to switch to
4182 * stdin. */
4183 if(strcasecmp("setinput", linebuf) == 0)
4184 {
4185 4 kittycat char *end = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
4186 extract_line(end, sizeof(linebuf)+linebuf-end);
4187 1 kittycat
4188 ret = 0;
4189 if(*ptr)
4190 {
4191 4 kittycat int fp = open(ptr, O_RDONLY, 0);
4192 if(fp == -1)
4193 1 kittycat {
4194 ret = 1;
4195 if(ignore_err < 2)
4196 4 kittycat printf("!!! Could not open %s !!!\n", ptr);
4197 1 kittycat if(!ignore_err)
4198 {
4199 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
4200 goto reparse;
4201 }
4202 if(ignore_err < 2)
4203 printf("--- Error %d ignored. ---\n\n",
4204 ++ignored_errors);
4205 fflush(stdout);
4206 4 kittycat continue;
4207 1 kittycat }
4208 4 kittycat fflush(stdin);
4209
4210 if(stdi_bak == -1)
4211 stdi_bak = dup(STDIN_FILENO);
4212
4213 close(STDIN_FILENO);
4214 dup2(fp, STDIN_FILENO);
4215
4216 close(fp);
4217 continue;
4218 1 kittycat }
4219
4220 4 kittycat fflush(stdin);
4221 if(stdi_bak == -1)
4222 continue;
4223
4224 close(STDIN_FILENO);
4225 dup2(stdi_bak, STDIN_FILENO);
4226
4227 close(stdi_bak);
4228 stdi_bak = -1;
4229 1 kittycat continue;
4230 }
4231
4232 /* Reads input and stores the string in the named var. The trailing
4233 * newline is stripped. */
4234 if(strcasecmp("read", linebuf) == 0)
4235 {
4236 char *end = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
4237 extract_line(end, sizeof(linebuf)+linebuf-end);
4238 if(!(*ptr))
4239 {
4240 ret = 1;
4241 if(ignore_err < 2)
4242 printf("!!! No storage specified for read (line %d) !!!\n",
4243 curr_line);
4244 if(!ignore_err)
4245 {
4246 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
4247 goto reparse;
4248 }
4249 if(ignore_err < 2)
4250 printf("--- Error %d ignored. ---\n\n", ++ignored_errors);
4251 fflush(stdout);
4252 continue;
4253 }
4254 ret = 0;
4255
4256 buffer[0] = 0;
4257 4 kittycat if(fgets(buffer, sizeof(buffer), stdin) == NULL)
4258 1 kittycat ret = 1;
4259
4260 if(buffer[0] && buffer[strlen(buffer)-1] == '\n')
4261 buffer[strlen(buffer)-1] = 0;
4262
4263 if(!strlen(buffer))
4264 unsetenv(ptr);
4265 else
4266 ret |= setenv(ptr, buffer, 1);
4267
4268 continue;
4269 }
4270
4271
4272 /* Executes a command via the system shell and redirects its output to
4273 * a temp file, which is then read into the named variable. All
4274 * trailing new-lines are stripped. */
4275 if(strcasecmp("readexec", linebuf) == 0)
4276 {
4277 int fd, old_stdout;
4278 char *bufptr, *cmd;
4279 size_t len;
4280 FILE *tf;
4281
4282 ret = 0;
4283
4284 /* Create a temp file and get its file descriptor (and for Win32,
4285 * change it to text mode) */
4286 tf = tmpfile();
4287 if(!tf)
4288 {
4289 ret = 1;
4290 if(ignore_err < 2)
4291 printf("!!! Could not create temp file !!!\n");
4292 if(!ignore_err)
4293 {
4294 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
4295 goto reparse;
4296 }
4297 if(ignore_err < 2)
4298 printf("--- Error %d ignored. ---\n\n",
4299 ++ignored_errors);
4300 fflush(stdout);
4301 continue;
4302 }
4303 fd = fileno(tf);
4304 #ifdef _WIN32
4305 _setmode(fd, _O_TEXT);
4306 #endif
4307
4308 /* Get the var name, and build the command */
4309 len = 0;
4310 cmd = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
4311 while(*cmd)
4312 {
4313 char *next = extract_word(cmd, sizeof(linebuf)+linebuf-cmd);
4314 if(strpbrk(cmd, CHARS_TO_ESC))
4315 {
4316 while(*cmd)
4317 {
4318 if(strchr(CHARS_TO_ESC CHARS_TO_QUOTE, *cmd) &&
4319 len < sizeof(buffer)-2)
4320 buffer[len++] = '\\';
4321 if(len < sizeof(buffer)-1)
4322 buffer[len++] = *(cmd++);
4323 }
4324 if(len < sizeof(buffer)-1)
4325 buffer[len++] = ' ';
4326 buffer[len] = 0;
4327 }
4328 else if(strpbrk(cmd, CHARS_TO_QUOTE))
4329 len += snprintf(buffer+len, sizeof(buffer)-len, "\"%s\" ",
4330 cmd);
4331 else
4332 len += snprintf(buffer+len, sizeof(buffer)-len, "%s ",
4333 cmd);
4334 cmd = next;
4335 }
4336 if(len > 0) buffer[len-1] = 0;
4337
4338 if(!shh)
4339 printf("%s\n", buffer);
4340 fflush(stdout);
4341
4342 /* Save stdout, close it, reopen it with the temp file's
4343 * descriptor, then run the command */
4344 old_stdout = dup(STDOUT_FILENO);
4345
4346 close(STDOUT_FILENO);
4347 dup2(fd, STDOUT_FILENO);
4348
4349 27 kittycat ret = system(buffer);
4350 if(WIFEXITED(ret))
4351 ret = WEXITSTATUS(ret);
4352 else
4353 ret = -1;
4354 1 kittycat if(ret != 0)
4355 {
4356 if(!ignore_err)
4357 {
4358 close(fd);
4359 close(STDOUT_FILENO);
4360 remove(fname);
4361
4362 dup2(old_stdout, STDOUT_FILENO);
4363 close(old_stdout);
4364
4365 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
4366 goto reparse;
4367 }
4368 }
4369
4370 /* Get the size of the out put and read it in */
4371 len = lseek(fd, 0, SEEK_END);
4372 lseek(fd, 0, SEEK_SET);
4373 bufptr = buffer;
4374 len = ((len >= sizeof(buffer)) ? sizeof(buffer)-1 : len);
4375 while(len > 0)
4376 {
4377 size_t b = read(fd, bufptr, len);
4378 if(b <= 0)
4379 break;
4380 len -= b;
4381 bufptr += b;
4382 }
4383 *(bufptr++) = 0;
4384
4385 /* Close the temp file, restore stdout, remove trailing newlines
4386 * from the program's output, then save it to the var */
4387 fclose(tf);
4388 close(STDOUT_FILENO);
4389
4390 dup2(old_stdout, STDOUT_FILENO);
4391 close(old_stdout);
4392
4393 if(buffer[0] && buffer[strlen(buffer)-1] == '\n')
4394 buffer[strlen(buffer)-1] = 0;
4395
4396 if(*ptr)
4397 ret |= setenv(ptr, buffer, 1);
4398 if(ret != 0)
4399 {
4400 if(!ignore_err)
4401 {
4402 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
4403 goto reparse;
4404 }
4405 continue;
4406 }
4407
4408 continue;
4409 }
4410
4411 /* Exits the script with the specified exitcode */
4412 if(strcasecmp("exit", linebuf) == 0)
4413 {
4414 static int already_exited = 0;
4415 int inc = 0;
4416 int retval;
4417
4418 if(already_exited)
4419 {
4420 fprintf(USEABLE_ERR, "\n\n*** Critical error ***\n"
4421 "Recursive exit call, aborting now!\n\n");
4422 exit(-1);
4423 }
4424 already_exited = 1;
4425
4426 extract_line(ptr, sizeof(linebuf)+linebuf-ptr);
4427 retval = atoi(ptr);
4428
4429 for(i = defines_size-1;(size_t)i < defines_size;--i)
4430 {
4431 if(strncasecmp(defines[i].name, "atexit_", 7) == 0)
4432 inc += snprintf(linebuf+inc, sizeof(linebuf)-inc, "%s\n",
4433 defines[i].name);
4434 }
4435 snprintf(linebuf+inc, sizeof(linebuf)-inc, "__really_exit %d\n",
4436 retval);
4437
4438 free(nextline);
4439 nextline = NULL;
4440 goto reparse;
4441 }
4442
4443
4444 /* Does nothing. Ignores the line */
4445 if(strcasecmp("noop", linebuf) == 0)
4446 {
4447 extract_line(ptr, sizeof(linebuf)+linebuf-ptr);
4448 continue;
4449 }
4450
4451
4452 if(strcasecmp("__reset_cmd_args__", linebuf) == 0)
4453 {
4454 size_t i = arg_backup_size-1;
4455 size_t i2;
4456
4457 if(i == ~0u)
4458 {
4459 fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n"
4460 "__reset_cmd_args__ called too many times!\n"
4461 "You didn't call it yourself, did you?", fname,
4462 curr_line);
4463 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
4464 goto reparse;
4465 }
4466
4467 extract_line(ptr, sizeof(linebuf)+linebuf-ptr);
4468
4469 for(i2 = 0;i2 < argc;++i2)
4470 free(argv[i2]);
4471 free(argv);
4472
4473 argc = arg_backup[i].argc;
4474 argv = arg_backup[i].argv;
4475 argv_len = 0;
4476 argv_size = argc-1;
4477
4478 RESIZE_LIST(arg_backup, i);
4479 /* If i == 0, then argv is the _argv given to main. We don't want
4480 * to be realloc'ing that. */
4481 if(i > 0)
4482 17 kittycat RESIZE_LIST(argv, argc+1);
4483 1 kittycat continue;
4484 }
4485
4486 /* Exits the script with the specified exitcode */
4487 if(strcasecmp("__really_exit", linebuf) == 0)
4488 {
4489 extract_line(ptr, sizeof(linebuf)+linebuf-ptr);
4490 exit(atoi(ptr));
4491 }
4492
4493
4494 for(i = 0;(size_t)i < defines_size;++i)
4495 {
4496 char *next;
4497 size_t i2;
4498
4499 if(strcasecmp(defines[i].name, linebuf) != 0)
4500 continue;
4501
4502 i2 = arg_backup_size;
4503 RESIZE_LIST(arg_backup, i2+1);
4504 arg_backup[i2].argv = argv;
4505 arg_backup[i2].argc = argc;
4506
4507 argc = 0;
4508 argv = NULL;
4509 argv_len = 0;
4510 RESIZE_LIST(argv, 2);
4511 argv[argc++] = strdup(linebuf);
4512 while(*ptr)
4513 {
4514 next = extract_word(ptr, sizeof(linebuf)+linebuf-ptr);
4515 RESIZE_LIST(argv, argc+2);
4516 argv[argc++] = strdup(ptr);
4517 ptr = next;
4518 }
4519 argv[argc] = NULL;
4520
4521 snprintf(linebuf, sizeof(linebuf), "%s\n__reset_cmd_args__\n%s\n",
4522 defines[i].val, (nextline?nextline:""));
4523 free(nextline);
4524 nextline = NULL;
4525 goto reparse;
4526 }
4527
4528
4529 fprintf(USEABLE_ERR, "\n\n!!! %s error, line %d !!!\n"
4530 "Unknown command '%s'\n\n", fname, curr_line, linebuf);
4531 snprintf(linebuf, sizeof(linebuf), "exit %d\n", ret);
4532 goto reparse;
4533 }
4534
4535 return ret;
4536 }