]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - ftepp.c
Rename
[xonotic/gmqcc.git] / ftepp.c
diff --git a/ftepp.c b/ftepp.c
index 84c17199e104bb840496829d461e8a6ca1089853..34eec593bc8754019c635a4ddf1accc604cb54cb 100644 (file)
--- a/ftepp.c
+++ b/ftepp.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012
+ * Copyright (C) 2012, 2013
  *     Wolfgang Bumiller
  *     Dale Weiler 
  *
@@ -21,6 +21,7 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
+#include <time.h>
 #include "gmqcc.h"
 #include "lexer.h"
 
@@ -49,6 +50,7 @@ typedef struct {
     char  **params;
     /* yes we need an extra flag since `#define FOO x` is not the same as `#define FOO() x` */
     bool    has_params;
+    bool    variadic;
 
     pptoken **output;
 } ppmacro;
@@ -66,8 +68,113 @@ typedef struct {
 
     char        *itemname;
     char        *includename;
+    bool         in_macro;
 } ftepp_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;
+
+/* __DATE__ */
+char *ftepp_predef_date(lex_file *context) {
+    struct tm *itime;
+    time_t     rtime;
+    char      *value = mem_a(82);
+    /* 82 is enough for strftime but we also have " " in our string */
+
+    (void)context;
+
+    /* get time */
+    time (&rtime);
+    itime = localtime(&rtime);
+
+    strftime(value, 82, "\"%b %d %Y\"", itime);
+
+    return value;
+}
+
+/* __TIME__ */
+char *ftepp_predef_time(lex_file *context) {
+    struct tm *itime;
+    time_t     rtime;
+    char      *value = mem_a(82);
+    /* 82 is enough for strftime but we also have " " in our string */
+
+    (void)context;
+
+    /* get time */
+    time (&rtime);
+    itime = localtime(&rtime);
+
+    strftime(value, 82, "\"%X\"", itime);
+
+    return value;
+}
+
+/* __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;
+}
+
+const ftepp_predef_t ftepp_predefs[FTEPP_PREDEF_COUNT] = {
+    { "__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  },
+    { "__DATE__",         &ftepp_predef_date        },
+    { "__TIME__",         &ftepp_predef_time        }
+};
+
 #define ftepp_tokval(f) ((f)->lex->tok.value)
 #define ftepp_ctx(f)    ((f)->lex->tok.ctx)
 
@@ -95,21 +202,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)
@@ -168,9 +267,15 @@ static ftepp_t* ftepp_new()
     return ftepp;
 }
 
+static void ftepp_flush_do(ftepp_t *self)
+{
+    vec_free(self->output_string);
+}
+
 static void ftepp_delete(ftepp_t *self)
 {
     size_t i;
+    ftepp_flush_do(self);
     if (self->itemname)
         mem_d(self->itemname);
     if (self->includename)
@@ -225,7 +330,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));
 }
@@ -273,15 +378,22 @@ static bool ftepp_define_params(ftepp_t *ftepp, ppmacro *macro)
             case TOKEN_IDENT:
             case TOKEN_TYPENAME:
             case TOKEN_KEYWORD:
+                vec_push(macro->params, util_strdup(ftepp_tokval(ftepp)));
+                break;
+            case TOKEN_DOTS:
+                macro->variadic = true;
                 break;
             default:
                 ftepp_error(ftepp, "unexpected token in parameter list");
                 return false;
         }
-        vec_push(macro->params, util_strdup(ftepp_tokval(ftepp)));
         ftepp_next(ftepp);
         if (!ftepp_skipspace(ftepp))
             return false;
+        if (macro->variadic && ftepp->token != ')') {
+            ftepp_error(ftepp, "cannot have parameters after the variadic parameters");
+            return false;
+        }
     } while (ftepp->token == ',');
     if (ftepp->token != ')') {
         ftepp_error(ftepp, "expected closing paren after macro parameter list");
@@ -296,9 +408,55 @@ static bool ftepp_define_body(ftepp_t *ftepp, ppmacro *macro)
 {
     pptoken *ptok;
     while (ftepp->token != TOKEN_EOL && ftepp->token < TOKEN_EOF) {
-        ptok = pptoken_make(ftepp);
-        vec_push(macro->output, ptok);
-        ftepp_next(ftepp);
+        bool   subscript = false;
+        size_t index     = 0;
+        if (macro->variadic && !strcmp(ftepp_tokval(ftepp), "__VA_ARGS__")) {
+            subscript = !!(ftepp_next(ftepp) == '#');
+
+            if (subscript && ftepp_next(ftepp) != '#') {
+                ftepp_error(ftepp, "expected `##` in __VA_ARGS__ for subscripting");
+                return false;
+            } else if (subscript) {
+                if (ftepp_next(ftepp) == '[') {
+                    if (ftepp_next(ftepp) != TOKEN_INTCONST) {
+                        ftepp_error(ftepp, "expected index for __VA_ARGS__ subscript");
+                        return false;
+                    }
+
+                    index = atoi(ftepp_tokval(ftepp));
+
+                    if (ftepp_next(ftepp) != ']') {
+                        ftepp_error(ftepp, "expected `]` in __VA_ARGS__ subscript");
+                        return false;
+                    }
+
+                    /*
+                     * mark it as an array to be handled later as such and not
+                     * as traditional __VA_ARGS__
+                     */
+                    ftepp->token = TOKEN_VA_ARGS_ARRAY;
+                    ptok = pptoken_make(ftepp);
+                    ptok->constval.i = index;
+                    vec_push(macro->output, ptok);
+                    ftepp_next(ftepp);
+                } else {
+                    ftepp_error(ftepp, "expected `[` for subscripting of __VA_ARGS__");
+                    return false;
+                }
+            } else {
+                int old = ftepp->token;
+                ftepp->token = TOKEN_VA_ARGS;
+                ptok = pptoken_make(ftepp);
+                vec_push(macro->output, ptok);
+                ftepp->token = old;
+            }
+        }
+        else
+        {
+            ptok = pptoken_make(ftepp);
+            vec_push(macro->output, ptok);
+            ftepp_next(ftepp);
+        }
     }
     /* recursive expansion can cause EOFs here */
     if (ftepp->token != TOKEN_EOL && ftepp->token != TOKEN_EOF) {
@@ -323,7 +481,7 @@ static bool ftepp_define(ftepp_t *ftepp)
         case TOKEN_KEYWORD:
             macro = ftepp_macro_find(ftepp, ftepp_tokval(ftepp));
             if (macro && ftepp->output_on) {
-                if (ftepp_warn(ftepp, WARN_PREPROCESSOR, "redefining `%s`", ftepp_tokval(ftepp)))
+                if (ftepp_warn(ftepp, WARN_CPP, "redefining `%s`", ftepp_tokval(ftepp)))
                     return false;
                 ftepp_macro_delete(ftepp, ftepp_tokval(ftepp));
             }
@@ -507,18 +665,42 @@ static void ftepp_recursion_footer(ftepp_t *ftepp)
     ftepp_out(ftepp, "\n#pragma pop(line)\n", false);
 }
 
-static bool ftepp_preprocess(ftepp_t *ftepp);
-static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *params)
+static void ftepp_param_out(ftepp_t *ftepp, macroparam *param)
 {
-    char     *old_string = ftepp->output_string;
-    lex_file *old_lexer = ftepp->lex;
-    bool retval = true;
+    size_t   i;
+    pptoken *out;
+    for (i = 0; i < vec_size(param->tokens); ++i) {
+        out = param->tokens[i];
+        if (out->token == TOKEN_EOL)
+            ftepp_out(ftepp, "\n", false);
+        else
+            ftepp_out(ftepp, out->value, false);
+    }
+}
 
-    size_t    o, pi, pv;
+static bool ftepp_preprocess(ftepp_t *ftepp);
+static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *params, bool resetline)
+{
+    char     *old_string   = ftepp->output_string;
+    char     *inner_string;
+    lex_file *old_lexer    = ftepp->lex;
+    size_t    vararg_start = vec_size(macro->params);
+    bool      retval       = true;
+    bool      has_newlines;
+    size_t    varargs;
+
+    size_t    o, pi;
     lex_file *inlex;
 
+    bool      old_inmacro;
+
     int nextok;
 
+    if (vararg_start < vec_size(params))
+        varargs = vec_size(params) - vararg_start;
+    else
+        varargs = 0;
+
     /* really ... */
     if (!vec_size(macro->output))
         return true;
@@ -527,21 +709,41 @@ static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *param
     for (o = 0; o < vec_size(macro->output); ++o) {
         pptoken *out = macro->output[o];
         switch (out->token) {
+            case TOKEN_VA_ARGS:
+                if (!macro->variadic) {
+                    ftepp_error(ftepp, "internal preprocessor error: TOKEN_VA_ARGS in non-variadic macro");
+                    vec_free(old_string);
+                    return false;
+                }
+                if (!varargs)
+                    break;
+
+                pi = 0;
+                ftepp_param_out(ftepp, &params[pi + vararg_start]);
+                for (++pi; pi < varargs; ++pi) {
+                    ftepp_out(ftepp, ", ", false);
+                    ftepp_param_out(ftepp, &params[pi + vararg_start]);
+                }
+                break;
+
+            case TOKEN_VA_ARGS_ARRAY:
+                if ((size_t)out->constval.i >= varargs) {
+                    ftepp_error(ftepp, "subscript of `[%u]` is out of bounds for `__VA_ARGS__`", out->constval.i);
+                    vec_free(old_string);
+                    return false;
+                }
+
+                ftepp_param_out(ftepp, &params[out->constval.i + vararg_start]);
+                break;
+
             case TOKEN_IDENT:
             case TOKEN_TYPENAME:
             case TOKEN_KEYWORD:
                 if (!macro_params_find(macro, out->value, &pi)) {
                     ftepp_out(ftepp, out->value, false);
                     break;
-                } else {
-                    for (pv = 0; pv < vec_size(params[pi].tokens); ++pv) {
-                        out = params[pi].tokens[pv];
-                        if (out->token == TOKEN_EOL)
-                            ftepp_out(ftepp, "\n", false);
-                        else
-                            ftepp_out(ftepp, out->value, false);
-                    }
-                }
+                } else
+                    ftepp_param_out(ftepp, &params[pi]);
                 break;
             case '#':
                 if (o + 1 < vec_size(macro->output)) {
@@ -582,17 +784,47 @@ static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *param
         retval = false;
         goto cleanup;
     }
-    ftepp->output_string = old_string;
-    ftepp->lex = inlex;
-    ftepp_recursion_header(ftepp);
+
+    inlex->line  = ftepp->lex->line;
+    inlex->sline = ftepp->lex->sline;
+    ftepp->lex   = inlex;
+
+    old_inmacro     = ftepp->in_macro;
+    ftepp->in_macro = true;
+    ftepp->output_string = NULL;
     if (!ftepp_preprocess(ftepp)) {
+        ftepp->in_macro = old_inmacro;
+        vec_free(ftepp->lex->open_string);
+        vec_free(ftepp->output_string);
         lex_close(ftepp->lex);
         retval = false;
         goto cleanup;
     }
-    ftepp_recursion_footer(ftepp);
-    old_string = ftepp->output_string;
+    ftepp->in_macro = old_inmacro;
+    vec_free(ftepp->lex->open_string);
+    lex_close(ftepp->lex);
+
+    inner_string = ftepp->output_string;
+    ftepp->output_string = old_string;
+
+    has_newlines = (strchr(inner_string, '\n') != NULL);
 
+    if (has_newlines && !old_inmacro)
+        ftepp_recursion_header(ftepp);
+
+    vec_append(ftepp->output_string, vec_size(inner_string), inner_string);
+    vec_free(inner_string);
+
+    if (has_newlines && !old_inmacro)
+        ftepp_recursion_footer(ftepp);
+
+    if (resetline && !ftepp->in_macro) {
+        char lineno[128];
+        sprintf(lineno, "\n#pragma line(%lu)\n", (unsigned long)(old_lexer->sline));
+        ftepp_out(ftepp, lineno, false);
+    }
+
+    old_string = ftepp->output_string;
 cleanup:
     ftepp->lex           = old_lexer;
     ftepp->output_string = old_string;
@@ -604,9 +836,10 @@ static bool ftepp_macro_call(ftepp_t *ftepp, ppmacro *macro)
     size_t     o;
     macroparam *params = NULL;
     bool        retval = true;
+    size_t      paramline;
 
     if (!macro->has_params) {
-        if (!ftepp_macro_expand(ftepp, macro, NULL))
+        if (!ftepp_macro_expand(ftepp, macro, NULL, false))
             return false;
         ftepp_next(ftepp);
         return true;
@@ -622,18 +855,22 @@ static bool ftepp_macro_call(ftepp_t *ftepp, ppmacro *macro)
     }
 
     ftepp_next(ftepp);
+    paramline = ftepp->lex->sline;
     if (!ftepp_macro_call_params(ftepp, &params))
         return false;
 
-    if (vec_size(params) != vec_size(macro->params)) {
-        ftepp_error(ftepp, "macro %s expects %u paramteters, %u provided", macro->name,
+    if ( vec_size(params) < vec_size(macro->params) ||
+        (vec_size(params) > vec_size(macro->params) && !macro->variadic) )
+    {
+        ftepp_error(ftepp, "macro %s expects%s %u paramteters, %u provided", macro->name,
+                    (macro->variadic ? " at least" : ""),
                     (unsigned int)vec_size(macro->params),
                     (unsigned int)vec_size(params));
         retval = false;
         goto cleanup;
     }
 
-    if (!ftepp_macro_expand(ftepp, macro, params))
+    if (!ftepp_macro_expand(ftepp, macro, params, (paramline != ftepp->lex->sline)))
         retval = false;
     ftepp_next(ftepp);
 
@@ -674,6 +911,7 @@ static bool ftepp_if_value(ftepp_t *ftepp, bool *out, double *value_out)
 {
     ppmacro *macro;
     bool     wasnot = false;
+    bool     wasneg = false;
 
     if (!ftepp_skipspace(ftepp))
         return false;
@@ -685,6 +923,14 @@ static bool ftepp_if_value(ftepp_t *ftepp, bool *out, double *value_out)
             return false;
     }
 
+    if (ftepp->token == TOKEN_OPERATOR && !strcmp(ftepp_tokval(ftepp), "-"))
+    {
+        wasneg = true;
+        ftepp_next(ftepp);
+        if (!ftepp_skipspace(ftepp))
+            return false;
+    }
+
     switch (ftepp->token) {
         case TOKEN_IDENT:
         case TOKEN_TYPENAME:
@@ -741,6 +987,7 @@ static bool ftepp_if_value(ftepp_t *ftepp, bool *out, double *value_out)
             }
             break;
         case TOKEN_STRINGCONST:
+            *value_out = 0;
             *out = false;
             break;
         case TOKEN_INTCONST:
@@ -764,8 +1011,12 @@ static bool ftepp_if_value(ftepp_t *ftepp, bool *out, double *value_out)
 
         default:
             ftepp_error(ftepp, "junk in #if: `%s` ...", ftepp_tokval(ftepp));
+            if (OPTS_OPTION_BOOL(OPTION_DEBUG))
+                ftepp_error(ftepp, "internal: token %i\n", ftepp->token);
             return false;
     }
+    if (wasneg)
+        *value_out = -*value_out;
     if (wasnot) {
         *out = !*out;
         *value_out = (*out ? 1 : 0);
@@ -999,9 +1250,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);
@@ -1249,6 +1500,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 +1521,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);
@@ -1301,7 +1571,7 @@ static bool ftepp_preprocess(ftepp_t *ftepp)
                 break;
             case TOKEN_WHITE:
                 /* same as default but don't set newline=false */
-                ftepp_out(ftepp, ftepp_tokval(ftepp), false);
+                ftepp_out(ftepp, ftepp_tokval(ftepp), true);
                 ftepp_next(ftepp);
                 break;
             default:
@@ -1366,12 +1636,30 @@ bool ftepp_preprocess_string(const char *name, const char *str)
     return ftepp_preprocess_done();
 }
 
+
+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, ' ');
+    vec_upload(create, value, strlen(value));
+    vec_push  (create, 0);
+
+    ftepp_preprocess_string("__builtin__", create);
+    vec_free  (create);
+}
+
 bool ftepp_init()
 {
     char minor[32];
     char major[32];
-    char *verminor = NULL;
-    char *vermajor = NULL;
 
     ftepp = ftepp_new();
     if (!ftepp)
@@ -1382,34 +1670,39 @@ bool ftepp_init()
 
     /* set the right macro based on the selected standard */
     ftepp_add_define(NULL, "GMQCC");
-    if (opts_standard == COMPILER_FTEQCC) {
+    if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_FTEQCC) {
         ftepp_add_define(NULL, "__STD_FTEQCC__");
         /* 1.00 */
-        major[0] = '1';
-        minor[0] = '0';
-    } else if (opts_standard == COMPILER_GMQCC) {
+        major[0] = '"';
+        major[1] = '1';
+        major[2] = '"';
+
+        minor[0] = '"';
+        minor[1] = '0';
+        minor[2] = '"';
+    } else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_GMQCC) {
         ftepp_add_define(NULL, "__STD_GMQCC__");
-        sprintf(major, "%d", GMQCC_VERSION_MAJOR);
-        sprintf(minor, "%d", GMQCC_VERSION_MINOR);
-    } else if (opts_standard == COMPILER_QCC) {
+        sprintf(major, "\"%d\"", GMQCC_VERSION_MAJOR);
+        sprintf(minor, "\"%d\"", GMQCC_VERSION_MINOR);
+    } else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCCX) {
+        ftepp_add_define(NULL, "__STD_QCCX__");
+        sprintf(major, "\"%d\"", GMQCC_VERSION_MAJOR);
+        sprintf(minor, "\"%d\"", GMQCC_VERSION_MINOR);
+    } else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) {
         ftepp_add_define(NULL, "__STD_QCC__");
         /* 1.0 */
-        major[0] = '1';
-        minor[0] = '0';
-    }
+        major[0] = '"';
+        major[1] = '1';
+        major[2] = '"';
 
-    vec_upload(verminor, "#define __STD_VERSION_MINOR__ \"", 31);
-    vec_upload(vermajor, "#define __STD_VERSION_MAJOR__ \"", 31);
-    vec_upload(verminor, minor, strlen(minor));
-    vec_upload(vermajor, major, strlen(major));
-    vec_push  (verminor, '"');
-    vec_push  (vermajor, '"');
+        minor[0] = '"';
+        minor[1] = '0';
+        minor[2] = '"';
+    }
 
-    ftepp_preprocess_string("__builtin__", verminor);
-    ftepp_preprocess_string("__builtin__", vermajor);
+    ftepp_add_macro("__STD_VERSION_MINOR__", minor);
+    ftepp_add_macro("__STD_VERSION_MAJOR__", major);
 
-    vec_free(verminor);
-    vec_free(vermajor);
     return true;
 }
 
@@ -1429,7 +1722,7 @@ const char *ftepp_get()
 
 void ftepp_flush()
 {
-    vec_free(ftepp->output_string);
+    ftepp_flush_do(ftepp);
 }
 
 void ftepp_finish()