#include #include #include #include #include #include #include #include #include "stone.h" struct ff_time { unsigned int sec:5, min:6, hour:5; } __attribute__ ((__packed__)); struct ff_date { unsigned int day:5, mon:4, year:7; } __attribute__ ((__packed__)); struct obj_load_include { struct ffblk ff; char *name; /* Filename */ int pass; /* Set when searched for entries */ }; static struct obj_load_include *find_file (char *file); static int ff_early (struct ffblk *fa, struct ffblk *fb); static int search_file (struct obj_load_include *inc); static int check_include (char *file, struct ffblk *cmp); static struct obj_load_include **inc = NULL; static int ninc = 0; static char *djdir = NULL; /* Setup only the subdirectories */ int stone_load_subdir (char *base) { struct ffblk ff; char buf [1024]; int done; if (base == NULL) return 0; sprintf (buf, "%s/*", base); done = findfirst (buf, &ff, FA_RDONLY | FA_HIDDEN | FA_DIREC | FA_SYSTEM); while (!done) { if (ff.ff_name [0] != '.' && ff.ff_attrib & FA_DIREC) { sprintf (buf, "%s/%s", base, ff.ff_name); if (!stone_load_dir (buf)) return 0; } done = findnext (&ff); } return 1; } /* Returns: 0 - equal time. +1 - fb is newer than fa. -1 - fa is newer than fb. */ static int ff_early (struct ffblk *fa, struct ffblk *fb) { struct ff_date *da = (void *) &fa->ff_fdate, *db = (void *) &fb->ff_fdate; struct ff_time *ta = (void *) &fa->ff_ftime, *tb = (void *) &fb->ff_ftime; if (da->year == db->year) { if (da->mon == db->mon) { if (da->day == db->day) { if (ta->hour == tb->hour) { if (ta->min == tb->min) { if (ta->sec == tb->sec) return 0; else if (ta->sec > tb->sec) return -1; else if (ta->sec < tb->sec) return 1; } else if (ta->min > tb->min) return -1; else if (ta->min < tb->min) return 1; } else if (ta->hour > tb->hour) return -1; else if (ta->hour < tb->hour) return 1; } else if (da->day > db->day) return -1; else if (da->day < db->day) return 1; } else if (da->mon > db->mon) return -1; else if (da->mon < db->mon) return 1; } else if (da->year > db->year) return -1; else if (da->year < db->year) return 1; return 0; } static struct obj_load_include *find_file (char *file) { struct ffblk ff; int i; if (file == NULL) return NULL; for (i = 0; file [i]; i ++) file [i] = (file [i] == '\\' || file [i] == '/') ? '/' : file [i]; for (i = 0; i < ninc; i ++) if (strcasecmp (inc [i]->name, file) == 0) break; if (i < ninc) return inc [i]; if (findfirst (file, &ff, FA_RDONLY | FA_HIDDEN | FA_SYSTEM | FA_ARCH)) return NULL; stone_resize (inc, ninc + 1); stone_allot (inc [ninc], 1); inc [ninc]->ff = ff; inc [ninc]->name = strdup (file); inc [ninc]->pass = 0; return inc [ninc ++]; } static int search_file (struct obj_load_include *inc) { char *buf = NULL; int len = 0, maxlen = 0; int i, j; int comment = 0; int string = 0; int start = 0; FILE *fd; int reply = 0; void put (int c) { if (len >= maxlen) { maxlen += 64; buf = realloc (buf, maxlen); } buf [len ++] = c; } int readline (void) { int c; len = 0; while (1) { c = fgetc (fd); if (c == '\n' || c == '\r') { put (0); return 1; } if (c == EOF) { put (0); return len - 1; } if (isspace (c)) { if (len && !isspace (buf [len - 1])) put (c); } else put (c); } } if (inc == NULL) return 0; if (djdir == NULL) djdir = getenv ("DJDIR"); fd = fopen (inc->name, "rt"); if (!fd) return reply; while (readline ()) for (i = 0, start = 0; i < len - 1; i ++) if (!string && !comment && buf [i] == '/' && buf [i + 1] == '*') comment = 1, i ++; else if (!string && comment && buf [i] == '*' && buf [i + 1] == '/') comment = 0, i ++; else if (!comment && buf [i] == '\"') string = !string; else if (string && buf [i] == '\\') i ++; else if (!comment && buf [i] != '#') start = 1; else if (!start && !comment && buf [i] == '#') { for (i ++; buf [i] && isspace (buf [i]); i ++); if (strncasecmp (&buf [i], "include", 7) == 0) { i += 7; for (i ++; buf [i] && isspace (buf [i]); i ++); if (buf [i] == '\"') /* #include "file.h" */ { struct obj_load_include *minc; int filelen = strlen (inc->name); char copy [len - i + filelen + 32], *ptr; int k = -1; for (j = 0; j < filelen; j ++) { copy [j] = inc->name [j]; if (inc->name [j] == '/' || inc->name [j] == '\\') k = j; } for (i ++, j = k + 1; buf [i] && buf [i] != '\"'; copy [j] = buf [i], j ++, i ++); copy [j] = 0; i ++; ptr = copy; minc = find_file (ptr); if (!minc) { ptr += k + 1; minc = find_file (ptr); } if (minc) { if (ff_early (&inc->ff, &minc->ff) > 0) reply = 1; if (minc->pass == 0) { int ret = search_file (minc); if (ff_early (&inc->ff, &minc->ff) > 0) { inc->ff = minc->ff; reply = 1; } else if (ret) reply = 1; } } } else if (buf [i] == '<') /* #include */ { /* Todo */ } } } free (buf); fclose (fd); inc->pass = 1; return reply; } static int check_include (char *file, struct ffblk *cmp) { struct obj_load_include *minc; if (file == NULL || cmp == NULL) return 0; minc = find_file (file); if (minc) return ff_early (&minc->ff, cmp); return 0; } int stone_load_dir (char *dir) { struct ffblk fa, fb; char buf [1024]; int done; if (dir == NULL) return 0; sprintf (buf, "%s/*", dir); done = findfirst (buf, &fa, FA_RDONLY | FA_HIDDEN | FA_SYSTEM | FA_ARCH | FA_DIREC); while (!done) { stone_compiler *comp; int len, flen, clen; flen = strlen (fa.ff_name); len = sprintf (buf, "%s/%s", dir, fa.ff_name); if (fa.ff_name [0] == '.') goto skip; if (fa.ff_attrib & FA_DIREC) /* Directory */ { if (!stone_load_dir (buf)) return 0; } else for (comp = stone_compiler_list; comp != NULL; comp = comp->next) if (flen > (clen = strlen (comp->srcext)) && !strcasecmp (&fa.ff_name [flen - clen], comp->srcext)) { int update = 0; strcpy (&buf [len - clen], comp->objext); if (!findfirst (buf, &fb, FA_RDONLY | FA_HIDDEN | FA_SYSTEM | FA_ARCH)) { update = ff_early (&fa, &fb) < 0 ? 1 : 0; if (!update) { struct obj_load_include *inc; sprintf (buf, "%s/%s", dir, fa.ff_name); inc = find_file (buf); inc->ff = fb; update = search_file (inc); } } else update = 1; if (update) { char name [256], extname [256]; char *ptr = NULL; int len = 0; int d; strcpy (name, fa.ff_name); strlwr (name); strcpy (extname, name); strcpy (&extname [strlen (extname) - clen], comp->objext); for (d = 0; d < comp->nstep; d ++) { ptr = comp->step [d]; while (*ptr != '\0' && len < (signed) sizeof (buf) - 1) if (*ptr == '&') { #define doadd(ID, IDLEN, FMT, ARG...) \ if (!strncasecmp (ptr, ID, IDLEN)) \ { \ ptr += IDLEN; \ addlen = sprintf (add, FMT ,##ARG ); \ } char add [1024]; int addlen = 0; doadd ("&&", 2, "&") else doadd ("&dir;", 5, "%s", dir) else doadd ("&obj;", 5, "%s", extname) else doadd ("&obj-dir;", 9, "%s/%s", dir, extname) else doadd ("&option;", 8, "%s", "") else doadd ("&prefix;", 8, "%s", "") else doadd ("&src;", 5, "%s", name) else doadd ("&src-dir;", 9, "%s/%s", dir, name) else doadd ("&suffix;", 8, "%s", "") else if (!strncasecmp (ptr, "&include", 8)) { stone_search *search; char *end; ptr += 8; end = ptr; while (*end ++ != ';'); for (search = stone_search_list; search != NULL; search = search->next) addlen += sprintf (&add [addlen], "%.*s%s", (int) end - (int) ptr - 1, ptr, search->path); ptr = end; } else { stone_report ("Unknown markup in stone_compile\n"); return 0; } if (sizeof (buf) - len - addlen < 1) len = sizeof (buf) - 1; else { memmove (&buf [len], add, addlen); len += addlen; } #undef doadd } else buf [len ++] = *ptr ++; if (len > (signed) sizeof (buf)) len = sizeof (buf) - 1; buf [len] = '\0'; if (len >= (signed) sizeof (buf)) { stone_report ("Ran out of buffer space creating compilation string\n"); return 0; } else { char tmpfile [L_tmpnam]; int temp; int old; int result; tmpnam (tmpfile); temp = open (tmpfile, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, 0666); old = dup (STDERR_FILENO); if (old < 0 || temp < 0 || dup2 (temp, STDERR_FILENO) < 0) { stone_report ("Attempt to redirect stderr to %s failed", tmpfile); return 0; } result = system (buf); close (temp); dup2 (old, STDERR_FILENO); close (old); if (result > 0) { FILE *file = fopen (tmpfile, "rt"); stone_report ("GCC returned error on %s/%s:", dir, fa.ff_name); while (fgets (buf, 1024, file) != NULL) { buf [strlen (buf) - 1] = '\0'; stone_report (" %s", buf); } fclose (file); remove (tmpfile); return 0; } remove (tmpfile); } } sprintf (buf, "%s/%s", dir, fa.ff_name); strcpy (&buf [strlen (buf) - clen], comp->objext); if (!__file_exists (buf)) { stone_report ("Compiled file doesn't exist"); return 0; } } break; } skip: done = findnext (&fa); } /* Object-file pass, more restricted */ sprintf (buf, "%s/*", dir); done = findfirst (buf, &fa, FA_RDONLY | FA_HIDDEN | FA_SYSTEM | FA_ARCH); while (!done) { stone_compiler *comp; int flen; int clen; flen = strlen (fa.ff_name); if (*fa.ff_name != '.') for (comp = stone_compiler_list; comp != NULL; comp = comp->next) if (flen > (clen = strlen (comp->objext)) && !strcasecmp (&fa.ff_name [flen - clen], comp->objext)) { sprintf (buf, "%s/%s", dir, fa.ff_name); if (stone_load (buf) < 0) { stone_report ("Error while reading %s", buf); return 0; } break; } done = findnext (&fa); } return 1; }