!UPCASE
authorBen Pfaff <blp@cs.stanford.edu>
Fri, 11 Jun 2021 05:34:12 +0000 (22:34 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Fri, 11 Jun 2021 05:34:12 +0000 (22:34 -0700)
src/language/lexer/macro.c
tests/language/control/define.at

index b17d467faab6506649c7e8e62325a07e8035332c..95d86a6e9643adfec2030db68fc9bfdd15e0de41 100644 (file)
@@ -854,6 +854,13 @@ unquote_string (const char *s, struct string *content)
   return true;
 }
 
+static const char *
+unquote_string_in_place (const char *s, struct string *tmp)
+{
+  ds_init_empty (tmp);
+  return unquote_string (s, tmp) ? ds_cstr (tmp) : s;
+}
+
 static bool
 parse_integer (const char *s, int *np)
 {
@@ -899,16 +906,15 @@ expand_macro_function (struct parse_macro_function_ctx *ctx,
   else if (parse_macro_function (ctx, &args, ss_cstr ("!head"), 1, 1,
                                  input_consumed))
     {
-      struct string content = DS_EMPTY_INITIALIZER;
-      const char *s = (unquote_string (args.strings[0], &content)
-                       ? ds_cstr (&content) : args.strings[0]);
+      struct string tmp;
+      const char *s = unquote_string_in_place (args.strings[0], &tmp);
 
       struct macro_tokens mts = { .n = 0 };
       macro_tokens_from_string (&mts, ss_cstr (s), SEG_MODE_INTERACTIVE /* XXX */);
       if (mts.n > 0)
         ds_put_substring (output, mts.mts[0].representation);
       macro_tokens_uninit (&mts);
-      ds_destroy (&content);
+      ds_destroy (&tmp);
     }
   else if (parse_macro_function (ctx, &args, ss_cstr ("!index"), 2, 2,
                                  input_consumed))
@@ -960,9 +966,8 @@ expand_macro_function (struct parse_macro_function_ctx *ctx,
   else if (parse_macro_function (ctx, &args, ss_cstr ("!tail"), 1, 1,
                                  input_consumed))
     {
-      struct string content = DS_EMPTY_INITIALIZER;
-      const char *s = (unquote_string (args.strings[0], &content)
-                       ? ds_cstr (&content) : args.strings[0]);
+      struct string tmp;
+      const char *s = unquote_string_in_place (args.strings[0], &tmp);
 
       struct macro_tokens mts = { .n = 0 };
       macro_tokens_from_string (&mts, ss_cstr (s), SEG_MODE_INTERACTIVE /* XXX */);
@@ -972,7 +977,7 @@ expand_macro_function (struct parse_macro_function_ctx *ctx,
           macro_tokens_to_representation (&tail, output);
         }
       macro_tokens_uninit (&mts);
-      ds_destroy (&content);
+      ds_destroy (&tmp);
     }
   else if (parse_macro_function (ctx, &args, ss_cstr ("!unquote"), 1, 1,
                                  input_consumed))
@@ -980,6 +985,16 @@ expand_macro_function (struct parse_macro_function_ctx *ctx,
       if (!unquote_string (args.strings[0], output))
         ds_put_cstr (output, args.strings[0]);
     }
+  else if (parse_macro_function (ctx, &args, ss_cstr ("!upcase"), 1, 1,
+                                 input_consumed))
+    {
+      struct string tmp;
+      const char *s = unquote_string_in_place (args.strings[0], &tmp);
+      char *upper = utf8_to_upper (s);
+      ds_put_cstr (output, upper);
+      free (upper);
+      ds_destroy (&tmp);
+    }
   else if (ctx->n_input > 0
            && ctx->input[0].token.type == T_MACRO_ID
            && ss_equals_case (ctx->input[0].token.string, ss_cstr ("!null")))
index 9a13ea45cde5796062422467eb4b5aabda1c524d..fce0e3f832ee2172f28a3a7f5fd54e77f42c9c58 100644 (file)
@@ -491,3 +491,17 @@ ana.
 nana.
 .])
 
+dnl Keep this test in sync with the examples for !UPCASE in the manual.
+PSPP_CHECK_MACRO_EXPANSION([!UPCASE],
+  [DEFINE !u()
+!UPCASE(freckle).
+!UPCASE('freckle').
+!UPCASE('a b c').
+!UPCASE('A B C').
+!ENDDEFINE.],
+  [!u.],
+  [FRECKLE.
+FRECKLE.
+A B C.
+A B C.])
+