]> de.git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - ftepp.c
when recursinve into macros copy the previous line number; fixes macros showing line...
[xonotic/gmqcc.git] / ftepp.c
diff --git a/ftepp.c b/ftepp.c
index 6fff6e09be19b8db25064aea5fa88cb243d31c9e..21669a8aa6a492910c23b12dcb3d8482c4fb09a8 100644 (file)
--- a/ftepp.c
+++ b/ftepp.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012
+ * Copyright (C) 2012, 2013
  *     Wolfgang Bumiller
  *     Dale Weiler 
  *
@@ -68,6 +68,77 @@ typedef struct {
     char        *includename;
 } ftepp_t;
 
+typedef struct {
+    const char  *name;
+    char      *(*func)(lex_file *);
+} predef_t;
+
+/*
+ * 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;
+
+/* __LINE__ */
+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) {
+    size_t  length = strlen(context->name) + 3; /* two quotes and a terminator */
+    char   *value  = (char*)mem_a(length);
+    memset (value, 0, length);
+    sprintf(value, "\"%s\"", context->name);
+
+    return value;
+}
+/* __COUNTER_LAST__ */
+char *ftepp_predef_counterlast(lex_file *context) {
+    char   *value;
+    util_asprintf(&value, "%u", ftepp_predef_countval);
+
+    (void)context;
+    return value;
+}
+/* __COUNTER__ */
+char *ftepp_predef_counter(lex_file *context) {
+    char   *value;
+    ftepp_predef_countval ++;
+    util_asprintf(&value, "%u", ftepp_predef_countval);
+    (void)context;
+
+    return value;
+}
+/* __RANDOM__ */
+char *ftepp_predef_random(lex_file *context) {
+    char  *value;
+    ftepp_predef_randval = (util_rand() % 0xFF) + 1;
+    util_asprintf(&value, "%u", ftepp_predef_randval);
+
+    (void)context;
+    return value;
+}
+/* __RANDOM_LAST__ */
+char *ftepp_predef_randomlast(lex_file *context) {
+    char   *value;
+    util_asprintf(&value, "%u", ftepp_predef_randval);
+
+    (void)context;
+    return value;
+}
+
+static const predef_t ftepp_predefs[] = {
+    { "__LINE__",         &ftepp_predef_line        },
+    { "__FILE__",         &ftepp_predef_file        },
+    { "__COUNTER__",      &ftepp_predef_counter     },
+    { "__COUNTER_LAST__", &ftepp_predef_counterlast },
+    { "__RANDOM__",       &ftepp_predef_random      },
+    { "__RANDOM_LAST__",  &ftepp_predef_randomlast  },
+};
+
 #define ftepp_tokval(f) ((f)->lex->tok.value)
 #define ftepp_ctx(f)    ((f)->lex->tok.ctx)
 
@@ -95,21 +166,13 @@ static void ftepp_error(ftepp_t *ftepp, const char *fmt, ...)
 
 static bool GMQCC_WARN ftepp_warn(ftepp_t *ftepp, int warntype, const char *fmt, ...)
 {
+    bool    r;
     va_list ap;
-    int lvl = LVL_WARNING;
-
-    if (!OPTS_WARN(warntype))
-        return false;
-
-    if (opts.werror) {
-           lvl = LVL_ERROR;
-        ftepp->errors++;
-    }
 
     va_start(ap, fmt);
-    con_cvprintmsg((void*)&ftepp->lex->tok.ctx, lvl, "error", fmt, ap);
+    r = vcompile_warning(ftepp->lex->tok.ctx, warntype, fmt, ap);
     va_end(ap);
-    return opts.werror;
+    return r;
 }
 
 static pptoken *pptoken_make(ftepp_t *ftepp)
@@ -171,6 +234,7 @@ static ftepp_t* ftepp_new()
 static void ftepp_delete(ftepp_t *self)
 {
     size_t i;
+    ftepp_flush(self);
     if (self->itemname)
         mem_d(self->itemname);
     if (self->includename)
@@ -225,7 +289,7 @@ static void ftepp_macro_delete(ftepp_t *ftepp, const char *name)
     }
 }
 
-static inline int ftepp_next(ftepp_t *ftepp)
+static GMQCC_INLINE int ftepp_next(ftepp_t *ftepp)
 {
     return (ftepp->token = lex_do(ftepp->lex));
 }
@@ -583,6 +647,8 @@ static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *param
         goto cleanup;
     }
     ftepp->output_string = old_string;
+    inlex->line = ftepp->lex->line;
+    inlex->sline = ftepp->lex->sline;
     ftepp->lex = inlex;
     ftepp_recursion_header(ftepp);
     if (!ftepp_preprocess(ftepp)) {
@@ -999,9 +1065,9 @@ static char *ftepp_include_find_path(const char *file, const char *pathfile)
     memcpy(vec_add(filename, len+1), file, len);
     vec_last(filename) = 0;
 
-    fp = util_fopen(filename, "rb");
+    fp = file_open(filename, "rb");
     if (fp) {
-        fclose(fp);
+        file_close(fp);
         return filename;
     }
     vec_free(filename);
@@ -1018,6 +1084,55 @@ static char *ftepp_include_find(ftepp_t *ftepp, const char *file)
     return filename;
 }
 
+static bool ftepp_directive_warning(ftepp_t *ftepp) {
+    char *message = NULL;
+
+    if (!ftepp_skipspace(ftepp))
+        return false;
+
+    /* handle the odd non string constant case so it works like C */
+    if (ftepp->token != TOKEN_STRINGCONST) {
+        bool  store   = false;
+        vec_upload(message, "#warning", 8);
+        ftepp_next(ftepp);
+        while (ftepp->token != TOKEN_EOL) {
+            vec_upload(message, ftepp_tokval(ftepp), strlen(ftepp_tokval(ftepp)));
+            ftepp_next(ftepp);
+        }
+        vec_push(message, '\0');
+        store = ftepp_warn(ftepp, WARN_CPP, message);
+        vec_free(message);
+        return store;
+    }
+
+    unescape  (ftepp_tokval(ftepp), ftepp_tokval(ftepp));
+    return ftepp_warn(ftepp, WARN_CPP, "#warning %s", ftepp_tokval(ftepp));
+}
+
+static void ftepp_directive_error(ftepp_t *ftepp) {
+    char *message = NULL;
+
+    if (!ftepp_skipspace(ftepp))
+        return;
+
+    /* handle the odd non string constant case so it works like C */
+    if (ftepp->token != TOKEN_STRINGCONST) {
+        vec_upload(message, "#error", 6);
+        ftepp_next(ftepp);
+        while (ftepp->token != TOKEN_EOL) {
+            vec_upload(message, ftepp_tokval(ftepp), strlen(ftepp_tokval(ftepp)));
+            ftepp_next(ftepp);
+        }
+        vec_push(message, '\0');
+        ftepp_error(ftepp, message);
+        vec_free(message);
+        return;
+    }
+
+    unescape  (ftepp_tokval(ftepp), ftepp_tokval(ftepp));
+    ftepp_error(ftepp, "#error %s", ftepp_tokval(ftepp));
+}
+
 /**
  * Include a file.
  * FIXME: do we need/want a -I option?
@@ -1213,6 +1328,14 @@ static bool ftepp_hash(ftepp_t *ftepp)
                 ftepp_out(ftepp, "#", false);
                 break;
             }
+            else if (!strcmp(ftepp_tokval(ftepp), "warning")) {
+                ftepp_directive_warning(ftepp);
+                break;
+            }
+            else if (!strcmp(ftepp_tokval(ftepp), "error")) {
+                ftepp_directive_error(ftepp);
+                break;
+            }
             else {
                 if (ftepp->output_on) {
                     ftepp_error(ftepp, "unrecognized preprocessor directive: `%s`", ftepp_tokval(ftepp));
@@ -1249,6 +1372,10 @@ static bool ftepp_preprocess(ftepp_t *ftepp)
     ppmacro *macro;
     bool     newline = true;
 
+    /* predef stuff */
+    char    *expand  = NULL;
+    size_t   i;
+
     ftepp->lex->flags.preprocessing = true;
     ftepp->lex->flags.mergelines    = false;
     ftepp->lex->flags.noops         = true;
@@ -1266,10 +1393,25 @@ static bool ftepp_preprocess(ftepp_t *ftepp)
             case TOKEN_KEYWORD:
             case TOKEN_IDENT:
             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;
+                        }
+                    }
+                }
+
                 if (ftepp->output_on)
                     macro = ftepp_macro_find(ftepp, ftepp_tokval(ftepp));
                 else
                     macro = NULL;
+
                 if (!macro) {
                     ftepp_out(ftepp, ftepp_tokval(ftepp), false);
                     ftepp_next(ftepp);
@@ -1369,6 +1511,13 @@ bool ftepp_preprocess_string(const char *name, const char *str)
 
 void ftepp_add_macro(const char *name, const char *value) {
     char *create = NULL;
+
+    /* use saner path for empty macros */
+    if (!value) {
+        ftepp_add_define("__builtin__", name);
+        return;
+    }
+
     vec_upload(create, "#define ", 8);
     vec_upload(create, name,  strlen(name));
     vec_push  (create, ' ');