macro: Fix memory leak with keyword "enclose" arguments.
[pspp] / src / language / lexer / macro.c
index 270cae50fabf9c586898eebad17e9adbad0e015e..62d060aad2ce21bc6320c0f05960f46051993cd4 100644 (file)
@@ -498,9 +498,6 @@ macro_set_add (struct macro_set *set, struct macro *m)
 
 enum mc_state
   {
-    /* Error state. */
-    MC_ERROR,
-
     /* Accumulating tokens in mc->params toward the end of any type of
        argument. */
     MC_ARG,
@@ -696,22 +693,22 @@ mc_expected (struct macro_call *mc, const struct macro_token *actual,
             mc->param->name, mc->macro->name);
   free (expected_s);
 
-  mc->state = MC_ERROR;
-  return -1;
+  return mc_finished (mc);
 }
 
 static int
 mc_enclose (struct macro_call *mc, const struct macro_token *mt,
             const struct msg_location *loc)
 {
-  mc->n_tokens++;
-
   const struct token *token = &mt->token;
   const struct macro_param *p = mc->param;
   if (token_equal (&p->start, token))
     {
+      mc->n_tokens++;
+
       struct macro_tokens **argp = &mc->args[p - mc->macro->params];
-      *argp = xzalloc (sizeof **argp);
+      if (!*argp)
+        *argp = xzalloc (sizeof **argp);
       mc->state = MC_ARG;
       return 0;
     }
@@ -754,13 +751,9 @@ mc_keyword (struct macro_call *mc, const struct macro_token *mt,
     {
       struct macro_tokens **argp = &mc->args[p - mc->macro->params];
       if (*argp)
-        {
-          mc_error (mc, loc,
-                    _("Argument %s multiply specified in call to macro %s."),
-                    p->name, mc->macro->name);
-          mc->state = MC_ERROR;
-          return -1;
-        }
+        mc_error (mc, loc,
+                  _("Argument %s multiply specified in call to macro %s."),
+                  p->name, mc->macro->name);
 
       *argp = xzalloc (sizeof **argp);
       mc->param = p;
@@ -776,11 +769,9 @@ static int
 mc_equals (struct macro_call *mc, const struct macro_token *mt,
            const struct msg_location *loc)
 {
-  const struct token *token = &mt->token;
-  mc->n_tokens++;
-
-  if (token->type == T_EQUALS)
+  if (mt->token.type == T_EQUALS)
     {
+      mc->n_tokens++;
       mc->state = mc->param->arg_type == ARG_ENCLOSE ? MC_ENCLOSE : MC_ARG;
       return 0;
     }
@@ -879,9 +870,6 @@ macro_call_add (struct macro_call *mc, const struct macro_token *mt,
 {
   switch (mc->state)
     {
-    case MC_ERROR:
-      return -1;
-
     case MC_ARG:
       return mc_add_arg (mc, mt, loc);
 
@@ -999,12 +987,7 @@ parse_function_args (const struct macro_expander *me,
                      const char *function,
                      struct string_array *args)
 {
-  if (n < 2 || mts[1].token.type != T_LPAREN)
-    {
-      macro_error (me->stack, n > 1 ? &mts[1] : NULL,
-                   _("`(' expected following %s."), function);
-      return 0;
-    }
+  assert (n >= 2 && mts[1].token.type == T_LPAREN);
 
   for (size_t i = 2; i < n; )
     {
@@ -1056,7 +1039,8 @@ unquote_string (const char *s, enum segmenter_mode segmenter_mode,
       return false;
     }
 
-  ds_put_substring (content, token1.string);
+  if (content)
+    ds_put_substring (content, token1.string);
   token_uninit (&token1);
   return true;
 }
@@ -1103,7 +1087,6 @@ expand_macro_function (const struct macro_expander *me,
       MF_HEAD,
       MF_INDEX,
       MF_LENGTH,
-      MF_NULL,
       MF_QUOTE,
       MF_SUBSTR,
       MF_TAIL,
@@ -1117,7 +1100,6 @@ expand_macro_function (const struct macro_expander *me,
     [MF_HEAD]    = { "!HEAD",    1, 1 },
     [MF_INDEX]   = { "!INDEX",   2, 2 },
     [MF_LENGTH]  = { "!LENGTH",  1, 1 },
-    [MF_NULL]    = { "!NULL",    0, 0 },
     [MF_QUOTE]   = { "!QUOTE",   1, 1 },
     [MF_SUBSTR]  = { "!SUBSTR",  2, 3 },
     [MF_TAIL]    = { "!TAIL",    1, 1 },
@@ -1125,7 +1107,16 @@ expand_macro_function (const struct macro_expander *me,
     [MF_UPCASE]  = { "!UPCASE",  1, 1 },
   };
 
-  /* Is this a macro function? */
+  if (lex_id_match_n (ss_cstr ("!NULL"), input[0].token.string, 4))
+    return 1;
+
+  if (n_input < 2 || input[1].token.type != T_LPAREN)
+    {
+      /* Only consider macro functions when the name is followed by '('. */
+      return 0;
+    }
+
+  /* Is this a macro function name? */
   const struct macro_function *mf;
   for (mf = mfs; ; mf++)
     {
@@ -1140,8 +1131,6 @@ expand_macro_function (const struct macro_expander *me,
     }
 
   enum macro_function_id id = mf - mfs;
-  if (id == MF_NULL)
-    return 1;
 
   struct string_array args = STRING_ARRAY_INITIALIZER;
   size_t n_consumed = parse_function_args (me, input, n_input, mf->name, &args);