}
static bool
-string_is_quoted_string (const char *s, struct string *content)
+unquote_string (const char *s, struct string *content)
{
struct string_lexer slex;
string_lexer_init (&slex, s, strlen (s), SEG_MODE_INTERACTIVE /* XXX */);
return true;
}
+static bool
+parse_integer (const char *s, int *np)
+{
+ errno = 0;
+
+ char *tail;
+ long int n = strtol (s, &tail, 10);
+ *np = n < INT_MIN ? INT_MIN : n > INT_MAX ? INT_MAX : n;
+ tail += strspn (tail, CC_SPACES);
+ return *tail == '\0' && errno != ERANGE && n == *np;
+}
+
static bool
expand_macro_function (struct parse_macro_function_ctx *ctx,
struct string *output,
else if (parse_macro_function (ctx, &args, ss_cstr ("!blanks"), 1, 1,
input_consumed))
{
- char *tail;
- errno = 0;
- int n = strtol (args.strings[0], &tail, 10);
- if (*tail != '\0' || n < 0 || errno == ERANGE)
+ int n;
+ if (!parse_integer (args.strings[0], &n))
{
printf ("argument to !BLANKS must be non-negative integer (not \"%s\")\n", args.strings[0]);
string_array_destroy (&args);
input_consumed))
{
for (size_t i = 0; i < args.n; i++)
- if (!string_is_quoted_string (args.strings[i], output))
+ if (!unquote_string (args.strings[i], output))
ds_put_cstr (output, args.strings[i]);
}
+ 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 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);
+ }
+ else if (parse_macro_function (ctx, &args, ss_cstr ("!index"), 2, 2,
+ input_consumed))
+ {
+ const char *haystack = args.strings[0];
+ const char *needle = strstr (haystack, args.strings[1]);
+ ds_put_format (output, "%zu", needle ? needle - haystack + 1 : 0);
+ }
else if (parse_macro_function (ctx, &args, ss_cstr ("!quote"), 1, 1,
input_consumed))
{
- if (string_is_quoted_string (args.strings[0], NULL))
+ if (unquote_string (args.strings[0], NULL))
ds_put_cstr (output, args.strings[0]);
else
{
ds_put_byte (output, '\'');
}
}
+ else if (parse_macro_function (ctx, &args, ss_cstr ("!substr"), 2, 3,
+ input_consumed))
+ {
+ int start;
+ if (!parse_integer (args.strings[1], &start) || start < 1)
+ {
+ printf ("second argument to !SUBSTR must be positive integer (not \"%s\")\n", args.strings[1]);
+ string_array_destroy (&args);
+ return false;
+ }
+
+ int count = INT_MAX;
+ if (args.n > 2 && (!parse_integer (args.strings[2], &count) || count < 0))
+ {
+ printf ("third argument to !SUBSTR must be non-negative integer (not \"%s\")\n", args.strings[1]);
+ string_array_destroy (&args);
+ return false;
+ }
+
+ struct substring s = ss_cstr (args.strings[0]);
+ ds_put_substring (output, ss_substr (s, start - 1, count));
+ }
+ 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 macro_tokens mts = { .n = 0 };
+ macro_tokens_from_string (&mts, ss_cstr (s), SEG_MODE_INTERACTIVE /* XXX */);
+ if (mts.n > 1)
+ {
+ struct macro_tokens tail = { .mts = mts.mts + 1, .n = mts.n - 1 };
+ macro_tokens_to_representation (&tail, output);
+ }
+ macro_tokens_uninit (&mts);
+ ds_destroy (&content);
+ }
else if (parse_macro_function (ctx, &args, ss_cstr ("!unquote"), 1, 1,
input_consumed))
{
- if (!string_is_quoted_string (args.strings[0], output))
+ if (!unquote_string (args.strings[0], output))
ds_put_cstr (output, args.strings[0]);
}
else if (ctx->n_input > 0