]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - ftepp.c
gitignore: add gmqcc, gmqpak, qmcvm, testsuite, pak.
[xonotic/gmqcc.git] / ftepp.c
diff --git a/ftepp.c b/ftepp.c
index 803466598e83b883858ad563e6c7a7f177f92adf..595b520fec5439f34a1614f737f9f83f7ef3c150 100644 (file)
--- a/ftepp.c
+++ b/ftepp.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2012, 2013
  *     Wolfgang Bumiller
- *     Dale Weiler 
+ *     Dale Weiler
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy of
  * this software and associated documentation files (the "Software"), to deal in
@@ -22,6 +22,7 @@
  * SOFTWARE.
  */
 #include <time.h>
+#include <sys/stat.h>
 #include "gmqcc.h"
 #include "lexer.h"
 
@@ -64,8 +65,7 @@ typedef struct ftepp_s {
     bool         output_on;
     ppcondition *conditions;
     /*ppmacro    **macros;*/
-    ht           macros; /* hashtable<string, ppmacro*> */
-
+    ht           macros;  /* hashtable<string, ppmacro*> */
     char        *output_string;
 
     char        *itemname;
@@ -76,13 +76,13 @@ typedef struct ftepp_s {
 /*
  * Implement the predef subsystem now.  We can do this safely with the
  * help of lexer contexts.
- */  
+ */
 static uint32_t ftepp_predef_countval = 0;
 static uint32_t ftepp_predef_randval  = 0;
 
 /* __DATE__ */
 char *ftepp_predef_date(lex_file *context) {
-    struct tm *itime;
+    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 */
@@ -91,7 +91,12 @@ char *ftepp_predef_date(lex_file *context) {
 
     /* get time */
     time (&rtime);
+
+#ifdef _MSC_VER
+    localtime_s(itime, &rtime);
+#else
     itime = localtime(&rtime);
+#endif
 
     strftime(value, 82, "\"%b %d %Y\"", itime);
 
@@ -100,7 +105,7 @@ char *ftepp_predef_date(lex_file *context) {
 
 /* __TIME__ */
 char *ftepp_predef_time(lex_file *context) {
-    struct tm *itime;
+    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 */
@@ -109,7 +114,12 @@ char *ftepp_predef_time(lex_file *context) {
 
     /* get time */
     time (&rtime);
+
+#ifdef _MSC_VER
+    localtime_s(itime, &rtime);
+#else
     itime = localtime(&rtime);
+#endif
 
     strftime(value, 82, "\"%X\"", itime);
 
@@ -126,7 +136,7 @@ char *ftepp_predef_line(lex_file *context) {
 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;
 }
@@ -164,8 +174,35 @@ char *ftepp_predef_randomlast(lex_file *context) {
     (void)context;
     return value;
 }
+/* __TIMESTAMP__ */
+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;
+}
 
-const ftepp_predef_t ftepp_predefs[FTEPP_PREDEF_COUNT] = {
+typedef struct {
+    const char   *name;
+    char       *(*func)(lex_file *);
+} ftepp_predef_t;
+
+static const ftepp_predef_t ftepp_predefs[] = {
     { "__LINE__",         &ftepp_predef_line        },
     { "__FILE__",         &ftepp_predef_file        },
     { "__COUNTER__",      &ftepp_predef_counter     },
@@ -173,9 +210,29 @@ const ftepp_predef_t ftepp_predefs[FTEPP_PREDEF_COUNT] = {
     { "__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)
 
@@ -312,7 +369,7 @@ static GMQCC_INLINE void ftepp_update_output_condition(ftepp_t *ftepp)
 
 static GMQCC_INLINE ppmacro* ftepp_macro_find(ftepp_t *ftepp, const char *name)
 {
-    return util_htget(ftepp->macros, name);
+    return (ppmacro*)util_htget(ftepp->macros, name);
 }
 
 static GMQCC_INLINE void ftepp_macro_delete(ftepp_t *ftepp, const char *name)
@@ -832,7 +889,7 @@ static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *param
 
     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);
     }
 
@@ -1432,7 +1489,7 @@ static bool ftepp_include(ftepp_t *ftepp)
 
     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 */
@@ -1618,7 +1675,6 @@ static bool ftepp_preprocess(ftepp_t *ftepp)
 
     /* predef stuff */
     char    *expand  = NULL;
-    size_t   i;
 
     ftepp->lex->flags.preprocessing = true;
     ftepp->lex->flags.mergelines    = false;
@@ -1639,15 +1695,14 @@ static bool ftepp_preprocess(ftepp_t *ftepp)
             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;
                     }
                 }
 
@@ -1797,12 +1852,12 @@ ftepp_t *ftepp_create()
         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 */
@@ -1818,6 +1873,12 @@ ftepp_t *ftepp_create()
     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;
 }