From e9ca911e346a70666a9cf39d9fc47f3cb2aeb4db Mon Sep 17 00:00:00 2001 From: Brian Koropoff Date: Sat, 16 Mar 2002 21:17:01 +0000 Subject: [PATCH] Added the ability to use curly braces to enclose tokens. Tokens in braces won't be processed except for escape characters, so that escaped braces can be used within. If an uneven number of curly braces are within a token, it will be misparsed, so escaped braces are important if you don't want them to be considered in the parsing of the token. Ideally, braces within quotes within braces should not need to be escaped, but this would require a redesign of the parser to be recursive. Maybe I will do this later. --- libs/util/cmd.c | 80 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 25 deletions(-) diff --git a/libs/util/cmd.c b/libs/util/cmd.c index 5a2342cf9..c15816e42 100644 --- a/libs/util/cmd.c +++ b/libs/util/cmd.c @@ -177,15 +177,19 @@ Cbuf_InsertText (const char *text) void extract_line (dstring_t *buffer, dstring_t *line) { - int i, squotes = 0, dquotes = 0; + int i, squotes = 0, dquotes = 0, braces = 0; for (i = 0; buffer->str[i]; i++) { - if (buffer->str[i] == '\'' && !escaped(buffer->str,i) && !dquotes) + if (buffer->str[i] == '\'' && !escaped(buffer->str,i) && !dquotes && !braces) squotes^=1; - if (buffer->str[i] == '"' && !escaped(buffer->str,i) && !squotes) + if (buffer->str[i] == '"' && !escaped(buffer->str,i) && !squotes && !braces) dquotes^=1; - if (buffer->str[i] == ';' && !escaped(buffer->str,i) && !squotes && !dquotes) + if (buffer->str[i] == ';' && !escaped(buffer->str,i) && !squotes && !dquotes && !braces) break; + if (buffer->str[i] == '{' && !escaped(buffer->str,i) && !squotes && !dquotes) + braces++; + if (buffer->str[i] == '}' && !escaped(buffer->str,i) && !squotes && !dquotes) + braces--; if (buffer->str[i] == '\n' || buffer->str[i] == '\r') break; } @@ -495,42 +499,64 @@ Cmd_Args (int start) return cmd_argbuf->str + cmd_args[start]; } -int Cmd_GetToken (const char *str) { - int i, squote, dquote; - +/* This function is a bit messy, so it will be commented in detail */ + +int +Cmd_GetToken (const char *str) { + int i, squote = 0, dquote = 0, braces = 0, n; /* Only stop on comments at the beginning of tokens */ if (!strncmp(str, "//", 2)) return 0; - for (i = 0, squote = 0, dquote = 0; i <= strlen(str); i++) { + for (i = 0; i <= strlen(str); i++) { /* If we find a comment in the middle of a token, end the token so it will be picked up on the next call */ - if (!strncmp(str+i, "//", 2) && !dquote && !squote) + if (!strncmp(str+i, "//", 2) && !dquote && !squote && !braces) break; - if (str[i] == 0) { - if (dquote) { // We never found another quote, backtrack + if (str[i] == 0) { // At the end of the string... + if (dquote) { // We never found another quote, backtrack and continue as if it was escaped for (; str[i] != '"'; i--); dquote = 0; continue; } - else if (squote) { + else if (squote) { // Same for single quotes for (; str[i] != '\''; i--); squote = 0; continue; } + /* Unmatched braces will simply result in the entire thing being one token. + There is no good reason not to have matched braces */ else // End of string, this token is done break; } - else if (str[i] == '\'' && !escaped(str,i) && !dquote) { + else if (str[i] == '$' && !escaped(str,i) && str[i+1] == '{') { // We should skip past variable substitution + for (n = i; str[i] != '}'; i++) { // n = i to save start position + if (str[i] == 0) { // If a var sub string was invalid, give up and go back + i = n; + continue; + } + } + } + else if (str[i] == '{' && !escaped(str,i) && !dquote && !squote) { // Open brace + if (i && !braces) // If this isn't the first open brace we found, but we are in middle of string... + break; // Stop, a new token is beginning + braces++; + } + else if (str[i] == '}' && !escaped(str,i) && !dquote && !squote && braces) { // Close brace + braces--; + if (!braces) // If we just closed the opening brace, the token is done + break; + } + else if (str[i] == '\'' && !escaped(str,i) && !dquote) { // Single quotes if (i) // If not at start of string, we must be at the end of a token break; squote = 1; } - else if (str[i] == '"' && !escaped(str,i) && !squote) { + else if (str[i] == '"' && !escaped(str,i) && !squote) { // Double quotes if (i) // Start new token break; dquote = 1; } - else if (isspace(str[i]) && !dquote && !squote) { + else if (isspace(str[i]) && !dquote && !squote && !braces) { // Token ends at white space as well break; } } @@ -724,8 +750,6 @@ void Cmd_ProcessPercents (dstring_t *dstr) { num = strtol(dstr->str+i+1, 0, 10); dstring_snip (dstr, i, n); dstring_insertstr (dstr, Cmd_Argv(num), i); - Sys_DPrintf("Cmd_ProcessPercents: Replaced %%%i with %s\n", (int)num, Cmd_Argv(num)); - Sys_DPrintf("Cmd_ProcessPercents: New line: %s\n", dstr->str); } } } @@ -752,13 +776,11 @@ void Cmd_ProcessPercents (dstring_t *dstr) { void Cmd_TokenizeString (const char *text, qboolean filter) { - int i = 0, n, len = 0, quotes = 0, space; + int i = 0, n, len = 0, quotes, braces, space; const char *str = text; cmd_argc = 0; - Sys_DPrintf("Cmd_TokenizeString: Received line: %s\n", text); - /* Turn off tags at the beginning of a command. This causes tags to continue past token boundaries. */ tag_shift = 0; @@ -790,20 +812,29 @@ Cmd_TokenizeString (const char *text, qboolean filter) } dstring_clearstr(cmd_argv[cmd_argc-1]); cmd_argspace[cmd_argc-1] = space; - /* Remove surrounding quotes or double quotes */ + /* Remove surrounding quotes or double quotes or braces*/ quotes = 0; + braces = 0; if ((str[i] == '\'' && str[i+len] == '\'') || (str[i] == '"' && str[i+len] == '"')) { i++; len-=1; quotes = 1; } + if (str[i] == '{' && str[i+len] == '}') { + i++; + len-=1; + braces = 1; + } dstring_insert(cmd_argv[cmd_argc-1], str + i, len, 0); if (filter && text[0] != '|') { - Cmd_ProcessTags(cmd_argv[cmd_argc-1]); - Cmd_ProcessVariables(cmd_argv[cmd_argc-1]); + if (!braces) { + Cmd_ProcessTags(cmd_argv[cmd_argc-1]); + Cmd_ProcessVariables(cmd_argv[cmd_argc-1]); + } Cmd_ProcessEscapes(cmd_argv[cmd_argc-1]); } - i += len + quotes; /* If we ended on a quote, skip it */ + + i += len + quotes + braces; /* If we ended on a quote or brace, skip it */ } /* Now we must reconstruct cmd_args */ dstring_clearstr (cmd_argbuf); @@ -813,7 +844,6 @@ Cmd_TokenizeString (const char *text, qboolean filter) cmd_args[i] = strlen(cmd_argbuf->str); dstring_appendstr (cmd_argbuf, cmd_argv[i]->str); } - Sys_DPrintf("Cmd_TokenizeString: Reconstructed line: %s\n", cmd_argbuf->str); } void