From e04ca3c004f450d0eae2c92b9ac40598d1f3b717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20Soul=C3=A9?= Date: Mon, 13 Feb 2023 23:09:53 +0100 Subject: [PATCH] Introduce multiline strings using triple double-quoting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maxime Soulé --- doc/manual/ctwm.1.adoc | 20 ++++++++++++++++++-- gram.y | 3 ++- lex.l | 2 ++ parse_menu.c | 15 +++++++++++++-- parse_yacc.c | 14 ++++++++++++++ parse_yacc.h | 1 + 6 files changed, 50 insertions(+), 5 deletions(-) diff --git a/doc/manual/ctwm.1.adoc b/doc/manual/ctwm.1.adoc index 14f9912d..6558e749 100644 --- a/doc/manual/ctwm.1.adoc +++ b/doc/manual/ctwm.1.adoc @@ -208,8 +208,24 @@ user-defined menus (containing functions to be invoked or commands to be executed). Variable names and keywords are case-insensitive. Strings must be -surrounded by double quote characters (e.g. ``blue'') and are -case-sensitive. A pound sign (#) outside of a string causes the +surrounded by double quote characters (e.g. "blue") and are +case-sensitive. A string can contain newline characters (useful for +`f.exec` or `f.dynmenu`), but multiline strings are better achieved +using triple quoting as in: +------ +f.dynmenu """ +cat < MONITOR_LAYOUT %token RPLAY_SOUNDS %token FORCE_FOCUS -%token STRING +%token STRING MLSTRING %type string %type action button number signed_number keyaction full fullkey @@ -1129,6 +1129,7 @@ string : STRING { char *ptr = strdup($1); RemoveDQuote(ptr); $$ = ptr; } + | MLSTRING { $$ = DupUnquoteMultilineString($1); } ; number : NUMBER { $$ = $1; } diff --git a/lex.l b/lex.l index d53ddb16..560477ee 100644 --- a/lex.l +++ b/lex.l @@ -49,6 +49,7 @@ %} string \"([^"]|\\.)*\" +mlstring \"\"\"([^\"]+|\"[^\"]+|\"\"[^\"]+)*\"\"\" number [0-9]+ /* Requires flex 2.5.1 (28Mar95) */ @@ -82,6 +83,7 @@ number [0-9]+ "!" { yylval.num = F_EXEC; return FSKEYWORD; } {string} { yylval.ptr = yytext; return STRING; } +{mlstring} { yylval.ptr = yytext; return MLSTRING; } {number} { sscanf(yytext, "%d", &yylval.num); return NUMBER; } \#[^\n]*\n {;} diff --git a/parse_menu.c b/parse_menu.c index 45fa36e7..5a279531 100644 --- a/parse_menu.c +++ b/parse_menu.c @@ -14,6 +14,17 @@ extern int (*twmInputFunc)(void); extern int yylex(void); extern char *yytext; +static char * +strdupunquote(char *s, bool multiline) +{ + if(multiline) { + return DupUnquoteMultilineString(s); + } + s = strdup(s); + RemoveDQuote(s); + return s; +} + static bool ParseMenuEntry(MenuRoot *menu) { @@ -50,9 +61,9 @@ ParseMenuEntry(MenuRoot *menu) step = STEP_ERROR; break; + case MLSTRING: case STRING: - str = strdup(yylval.ptr); - RemoveDQuote(str); + str = strdupunquote(yylval.ptr, token == MLSTRING); switch(step) { case STEP_START: label = str; diff --git a/parse_yacc.c b/parse_yacc.c index 5363b33d..635bf632 100644 --- a/parse_yacc.c +++ b/parse_yacc.c @@ -8,6 +8,7 @@ #include "ctwm.h" #include +#include #include #include @@ -132,6 +133,19 @@ void RemoveDQuote(char *str) *o = '\0'; } +char *DupUnquoteMultilineString(char *str) +{ + char *ret; + int len; + + str += 3; + len = strlen(str) - 3; + ret = malloc(len + 1); + memcpy(ret, str, len); + ret[len] = '\0'; + return ret; +} + MenuRoot *GetRoot(char *name, char *fore, char *back, bool dynamic) { MenuRoot *tmp; diff --git a/parse_yacc.h b/parse_yacc.h index 3a638c4a..991e8eae 100644 --- a/parse_yacc.h +++ b/parse_yacc.h @@ -8,6 +8,7 @@ void yyerror(char *s); void InitGramVariables(void); void RemoveDQuote(char *str); +char *DupUnquoteMultilineString(char *str); MenuRoot *GetRoot(char *name, char *fore, char *back, bool dynamic);