* SOFTWARE.
*/
#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
#include "gmqcc.h"
#include "lexer.h"
bool output_on;
ppcondition *conditions;
/*ppmacro **macros;*/
- ht macros; /* hashtable<string, ppmacro*> */
-
+ ht macros; /* hashtable<string, ppmacro*> */
char *output_string;
char *itemname;
static uint32_t ftepp_predef_randval = 0;
/* __DATE__ */
-char *ftepp_predef_date(lex_file *context) {
- struct tm *itime;
+static char *ftepp_predef_date(lex_file *context) {
+ struct tm *itime = NULL;
time_t rtime;
char *value = (char*)mem_a(82);
/* 82 is enough for strftime but we also have " " in our string */
/* get time */
time (&rtime);
+
+#ifdef _MSC_VER
+ localtime_s(itime, &rtime);
+#else
itime = localtime(&rtime);
+#endif
strftime(value, 82, "\"%b %d %Y\"", itime);
}
/* __TIME__ */
-char *ftepp_predef_time(lex_file *context) {
- struct tm *itime;
+static char *ftepp_predef_time(lex_file *context) {
+ struct tm *itime = NULL;
time_t rtime;
char *value = (char*)mem_a(82);
/* 82 is enough for strftime but we also have " " in our string */
/* get time */
time (&rtime);
+
+#ifdef _MSC_VER
+ localtime_s(itime, &rtime);
+#else
itime = localtime(&rtime);
+#endif
strftime(value, 82, "\"%X\"", itime);
}
/* __LINE__ */
-char *ftepp_predef_line(lex_file *context) {
+static char *ftepp_predef_line(lex_file *context) {
char *value;
util_asprintf(&value, "%d", (int)context->line);
return value;
}
/* __FILE__ */
-char *ftepp_predef_file(lex_file *context) {
+static char *ftepp_predef_file(lex_file *context) {
size_t length = strlen(context->name) + 3; /* two quotes and a terminator */
char *value = (char*)mem_a(length);
- snprintf(value, length, "\"%s\"", context->name);
+ util_snprintf(value, length, "\"%s\"", context->name);
return value;
}
/* __COUNTER_LAST__ */
-char *ftepp_predef_counterlast(lex_file *context) {
+static char *ftepp_predef_counterlast(lex_file *context) {
char *value;
util_asprintf(&value, "%u", ftepp_predef_countval);
return value;
}
/* __COUNTER__ */
-char *ftepp_predef_counter(lex_file *context) {
+static char *ftepp_predef_counter(lex_file *context) {
char *value;
ftepp_predef_countval ++;
util_asprintf(&value, "%u", ftepp_predef_countval);
return value;
}
/* __RANDOM__ */
-char *ftepp_predef_random(lex_file *context) {
+static char *ftepp_predef_random(lex_file *context) {
char *value;
ftepp_predef_randval = (util_rand() % 0xFF) + 1;
util_asprintf(&value, "%u", ftepp_predef_randval);
return value;
}
/* __RANDOM_LAST__ */
-char *ftepp_predef_randomlast(lex_file *context) {
+static char *ftepp_predef_randomlast(lex_file *context) {
char *value;
util_asprintf(&value, "%u", ftepp_predef_randval);
(void)context;
return value;
}
+/* __TIMESTAMP__ */
+static char *ftepp_predef_timestamp(lex_file *context) {
+ struct stat finfo;
+ char *find;
+ char *value;
+ size_t size;
+ if (stat(context->name, &finfo))
+ return util_strdup("\"<failed to determine timestamp>\"");
+
+ /*
+ * ctime and its fucking annoying newline char, no worries, we're
+ * professionals here.
+ */
+ find = ctime(&finfo.st_mtime);
+ value = (char*)mem_a(strlen(find) + 1);
+ memcpy(&value[1], find, (size = strlen(find)) - 1);
+
+ value[0] = '"';
+ value[size] = '"';
+
+ return value;
+}
+
+typedef struct {
+ const char *name;
+ char *(*func)(lex_file *);
+} ftepp_predef_t;
-const ftepp_predef_t ftepp_predefs[FTEPP_PREDEF_COUNT] = {
+static const ftepp_predef_t ftepp_predefs[] = {
{ "__LINE__", &ftepp_predef_line },
{ "__FILE__", &ftepp_predef_file },
{ "__COUNTER__", &ftepp_predef_counter },
{ "__RANDOM__", &ftepp_predef_random },
{ "__RANDOM_LAST__", &ftepp_predef_randomlast },
{ "__DATE__", &ftepp_predef_date },
- { "__TIME__", &ftepp_predef_time }
+ { "__TIME__", &ftepp_predef_time },
+ { "__TIME_STAMP__", &ftepp_predef_timestamp }
};
+static GMQCC_INLINE int ftepp_predef_index(const char *name) {
+ /* no hashtable here, we simply check for one to exist the naive way */
+ int i;
+ for(i = 0; i < (int)(sizeof(ftepp_predefs)/sizeof(*ftepp_predefs)); i++)
+ if (!strcmp(ftepp_predefs[i].name, name))
+ return i;
+ return -1;
+}
+
+bool ftepp_predef_exists(const char *name) {
+ return ftepp_predef_index(name) != -1;
+}
+
+/* singleton because we're allowed */
+static GMQCC_INLINE char *(*ftepp_predef(const char *name))(lex_file *context) {
+ int i = ftepp_predef_index(name);
+ return (i != -1) ? ftepp_predefs[i].func : NULL;
+}
+
#define ftepp_tokval(f) ((f)->lex->tok.value)
#define ftepp_ctx(f) ((f)->lex->tok.ctx)
mem_d(self);
}
-static ftepp_t* ftepp_new()
+static ftepp_t* ftepp_new(void)
{
ftepp_t *ftepp;
static GMQCC_INLINE void ftepp_macro_delete(ftepp_t *ftepp, const char *name)
{
- util_htrm(ftepp->macros, name, NULL);
+ util_htrm(ftepp->macros, name, (void (*)(void*))&ppmacro_delete);
}
static GMQCC_INLINE int ftepp_next(ftepp_t *ftepp)
return false;
}
-#if 0
- if (ftepp->output_on)
- vec_push(ftepp->macros, macro);
-#endif
if (ftepp->output_on)
util_htset(ftepp->macros, macro->name, (void*)macro);
else {
if (resetline && !ftepp->in_macro) {
char lineno[128];
- snprintf(lineno, 128, "\n#pragma line(%lu)\n", (unsigned long)(old_lexer->sline));
+ util_snprintf(lineno, 128, "\n#pragma line(%lu)\n", (unsigned long)(old_lexer->sline));
ftepp_out(ftepp, lineno, false);
}
ftepp_out(ftepp, "\n#pragma file(", false);
ftepp_out(ftepp, ctx.file, false);
- snprintf(lineno, sizeof(lineno), ")\n#pragma line(%lu)\n", (unsigned long)(ctx.line+1));
+ util_snprintf(lineno, sizeof(lineno), ")\n#pragma line(%lu)\n", (unsigned long)(ctx.line+1));
ftepp_out(ftepp, lineno, false);
/* skip the line */
/* predef stuff */
char *expand = NULL;
- size_t i;
ftepp->lex->flags.preprocessing = true;
ftepp->lex->flags.mergelines = false;
case TOKEN_TYPENAME:
/* is it a predef? */
if (OPTS_FLAG(FTEPP_PREDEFS)) {
- for (i = 0; i < sizeof(ftepp_predefs) / sizeof (*ftepp_predefs); i++) {
- if (!strcmp(ftepp_predefs[i].name, ftepp_tokval(ftepp))) {
- expand = ftepp_predefs[i].func(ftepp->lex);
- ftepp_out(ftepp, expand, false);
- ftepp_next(ftepp); /* skip */
-
- mem_d(expand); /* free memory */
- break;
- }
+ char *(*predef)(lex_file*) = ftepp_predef(ftepp_tokval(ftepp));
+ if (predef) {
+ expand = predef(ftepp->lex);
+ ftepp_out (ftepp, expand, false);
+ ftepp_next(ftepp);
+
+ mem_d(expand);
+ break;
}
}
minor[2] = '"';
} else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_GMQCC) {
ftepp_add_define(ftepp, NULL, "__STD_GMQCC__");
- snprintf(major, 32, "\"%d\"", GMQCC_VERSION_MAJOR);
- snprintf(minor, 32, "\"%d\"", GMQCC_VERSION_MINOR);
+ util_snprintf(major, 32, "\"%d\"", GMQCC_VERSION_MAJOR);
+ util_snprintf(minor, 32, "\"%d\"", GMQCC_VERSION_MINOR);
} else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCCX) {
ftepp_add_define(ftepp, NULL, "__STD_QCCX__");
- snprintf(major, 32, "\"%d\"", GMQCC_VERSION_MAJOR);
- snprintf(minor, 32, "\"%d\"", GMQCC_VERSION_MINOR);
+ util_snprintf(major, 32, "\"%d\"", GMQCC_VERSION_MAJOR);
+ util_snprintf(minor, 32, "\"%d\"", GMQCC_VERSION_MINOR);
} else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) {
ftepp_add_define(ftepp, NULL, "__STD_QCC__");
/* 1.0 */
ftepp_add_macro(ftepp, "__STD_VERSION_MINOR__", minor);
ftepp_add_macro(ftepp, "__STD_VERSION_MAJOR__", major);
+ /*
+ * We're going to just make __NULL__ nil, which works for 60% of the
+ * cases of __NULL_ for fteqcc.
+ */
+ ftepp_add_macro(ftepp, "__NULL__", "nil");
+
return ftepp;
}
void ftepp_add_define(ftepp_t *ftepp, const char *source, const char *name)
{
ppmacro *macro;
- lex_ctx ctx = { "__builtin__", 0 };
+ lex_ctx ctx = { "__builtin__", 0, 0 };
ctx.file = source;
macro = ppmacro_new(ctx, name);
/*vec_push(ftepp->macros, macro);*/