/* * rofi * * MIT/X11 License * Copyright 2013-2023 Qball Cow * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ %option nodefault noyywrap %option nostdinit %option nounput %option never-interactive %option bison-locations %option bison-bridge %{ #include "config.h" #include "resources.h" #include #include #include #include #include #include #include "rofi.h" #include "theme.h" #include "theme-parser.h" #include "css-colors.h" #define LOG_DOMAIN "Parser" int last_state = 0; const char *rasi_theme_file_extensions[] = {".rasi", ".rasinc", NULL}; /** * Type of Object to parse. */ typedef enum { /** Parse a file */ PT_FILE, /** Parse a string */ PT_STRING, /** Parse a string */ PT_STRING_ALLOC, /** Parse environment */ PT_ENV } ParseType; /** * Parse object */ typedef struct _ParseObject { /** Type */ ParseType type; /** File pointer */ FILE *filein; char *filename; /** Length of string */ int str_len; /** String */ const char *input_str; /** For where we need to free at end. (PT_STRING_ALLOC); */ char *malloc_str; /** Position in file */ YYLTYPE location; } ParseObject; GQueue *file_queue = NULL; GQueue *queue = NULL; ParseObject *current = NULL; static double rofi_theme_parse_convert_hex ( char high, char low) { uint8_t retv = 0; int t = g_ascii_toupper ( high ); t = ( t > '9')? (t-'A'+10):(t-'0'); retv = t<<4; t = g_ascii_toupper ( low ); t = ( t > '9')? (t-'A'+10):(t-'0'); retv +=t; return retv/255.0; } %} %{ #define YY_INPUT(buf,result,max_size) \ {\ if ( current == NULL ) {\ result = 0;\ } else {\ switch ( current->type ) { \ case PT_FILE:\ {\ errno =0; \ while ( (result = (int) fread(buf, 1, max_size, current->filein))==0 && ferror(current->filein)) \ { \ if ( errno != EINTR ) \ { \ fprintf(stderr, "Failed to read input from file: %s\n", strerror(errno)); \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(current->filein); \ } \ break;\ }\ case PT_ENV:\ case PT_STRING_ALLOC:\ case PT_STRING:\ {\ yy_size_t len = MIN (max_size, current->str_len);\ if ( len > 0 ) {\ memcpy (buf, current->input_str, len);\ current->input_str+=len;\ current->str_len-=len;\ result = len;\ } else {\ result = 0;\ }\ break;\ }\ }\ }\ } #define YY_USER_ACTION {\ yylloc->last_column+= yyleng;\ } #define YY_LLOC_START {\ yylloc->first_line = yylloc->last_line;\ yylloc->first_column = yylloc->last_column;\ } %} ASC [\x00-\x7f] ASCN [\x00-\t\v-\x7f] ASCNP [\x00-\t\v-\x21\x23-\x7f] U [\x80-\xbf] U2 [\xc2-\xdf] U3 [\xe0-\xef] U4 [\xf0-\xf4] // UANY {ASC}|{U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U} UANYN {ASCN}|{U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U} // UONLY {U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U} UANYNP {ASCNP}|{U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U} WHITESPACE [[:blank:]] WSO [[:blank:]]* WORD [[:alnum:]-]+ WORD_ELEMENT [[:alpha:]][[:alnum:]-]* WORD_ENV [[:alpha:]_][[:alnum:]_]* COLOR_NAME [[:alpha:]]+ STRING \"{UANYN}*\" STRING_LIST \"{UANYNP}*\" CHAR \'({ASCN}|\\\\|\\\'|\\0)\' HEX [[:xdigit:]] NUMBER [[:digit:]]+ UNARYMIN - PX (px) MM (mm) EM (em) CH (ch) PERCENT (\%) INHERIT (inherit) ASTERIX \* ENV $\{[[:alpha:]_][[:alnum:]_]*\} MODIFIER_ADD \+ MODIFIER_MULTIPLY \* MODIFIER_MIN (min) MODIFIER_MAX (max) MODIFIER_ROUND (round) MODIFIER_FLOOR (floor) MODIFIER_CEIL (ceil) MODIFIER_MODULO (modulo) /* Position */ CENTER (?i:center) NORTH (?i:north) SOUTH (?i:south) EAST (?i:east) WEST (?i:west) /* Line Style */ NONE (?i:none) BOLD (?i:bold) UNDERLINE (?i:underline) ITALIC (?i:italic) STRIKETHROUGH (?i:strikethrough) UPPERCASE (?i:uppercase) LOWERCASE (?i:lowercase) CAPITALIZE (?i:capitalize) /* ANGLES */ ANGLE_DEG (?i:deg) ANGLE_GRAD (?i:grad) ANGLE_RAD (?i:rad) ANGLE_TURN (?i:turn) /* LINE STYLE */ LS_DASH (?i:dash) LS_SOLID (?i:solid) /* Orientation */ ORIENTATION_HORI (?i:horizontal) ORIENTATION_VERT (?i:vertical) /* Cursor */ CURSOR_DEF (?i:default) CURSOR_PTR (?i:pointer) CURSOR_TXT (?i:text) /* Color schema */ RGBA (?i:rgb[a]?) HWB (?i:hwb) CMYK (?i:cmyk) HSL (?i:hsl[a]?) /* Image type */ URL (?i:url?) LINEAR_GRADIENT (?i:linear-gradient?) WIDTH (?i:width?) HEIGHT (?i:height?) BOTH (?i:both?) TO (?i:to?) RIGHT (?i:right?) LEFT (?i:left?) TOP (?i:top?) BOTTOM (?i:bottom?) COLOR_TRANSPARENT (?i:transparent) S_T_PARENT_LEFT \( S_T_PARENT_RIGHT \) CALC (?i:calc) COMMA , FORWARD_SLASH \/ LIST_OPEN \[ LIST_CLOSE \] VAR_START "var" ENV_START "env" CPP_COMMENT "//" C_COMMENT_OPEN "/*" INCLUDE "@import" THEME "@theme" DEFAULT (?i:\"default\"?) MEDIA "@media" CONFIGURATION (?i:configuration) MEDIA_TYPES (monitor-id|(min|max)-(width|height|aspect-ratio)|enabled) %x INCLUDE %x PROPERTIES %x PROPERTIES_ENV %x PROPERTIES_VAR %x PROPERTIES_ENV_VAR %x PROPERTIES_VAR_DEFAULT %x PROPERTIES_ARRAY %x NAMESTR %x SECTION %x DEFAULTS /* Media section.*/ %x MEDIA %x MEDIA_CONTENT %x MEDIA_ENV_VAR %x MEDIA_ENV_VAR_CONTENT %x MEDIA_ENV_VAR_DEFAULT %% %{ YY_LLOC_START %} %{ if ( queue == NULL ) { queue = g_queue_new ( ); yylloc->filename = current->filename; // unsure why todo this. yylloc->first_line = yylloc->last_line = 1; yylloc->first_column = yylloc->last_column = 1; } %} /** * General code for handling comments. * Both C and C++ style comments, including nexting. */ <*>{CPP_COMMENT} { int c = input(); while ( c != 0 && c != EOF) { if ( c == '\n' ) { yylloc->last_column = 1; yylloc->last_line ++; break; } yylloc->last_column++; c = input(); } YY_LLOC_START } <*>{C_COMMENT_OPEN} { int c = 0, p; int nesting_depth = 1; while (nesting_depth) { p = c; c = input(); switch (c) { case '*': yylloc->last_column++; if ( p == '/' ) { c = 0; nesting_depth++; } break; case '/': yylloc->last_column++; if ( p == '*' ) { c = 0; nesting_depth--; } break; case '\n': { yylloc->last_column = 1; yylloc->last_line ++; break; } case 0: nesting_depth = 0; break; case EOF: nesting_depth = 0; break; default: yylloc->last_column++; ; } } YY_LLOC_START } /** * HANDLE INCLUDES */ {INCLUDE} { g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(INCLUDE); } {THEME} { g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(INCLUDE); return T_RESET_THEME; } /** Skip all whitespace */ {WHITESPACE} {} /** Parse path. Last element in this INCLUDE */ {DEFAULT} { ParseObject *top = g_queue_peek_head ( file_queue ); g_assert ( top != NULL ); GBytes *theme_data = g_resource_lookup_data( resources_get_resource(), "/org/qtools/rofi/default.rasi", G_RESOURCE_LOOKUP_FLAGS_NONE, NULL); if (theme_data) { const char *theme = g_bytes_get_data(theme_data, NULL); top->location = *yylloc; ParseObject *po = g_malloc0(sizeof(ParseObject)); po->type = PT_STRING_ALLOC; po->malloc_str = g_strdup(theme); po->input_str = po->malloc_str; po->str_len = strlen(po->malloc_str)-1; current = po; g_queue_push_head ( file_queue, po ); g_bytes_unref(theme_data); yypush_buffer_state (yy_create_buffer ( 0, YY_BUF_SIZE )); yylloc->first_line = yylloc->last_line = 1; yylloc->first_column = yylloc->last_column = 1; yylloc->filename = NULL;//"default theme"; } // Pop out of include. BEGIN(GPOINTER_TO_INT(g_queue_pop_head ( queue ))); } {STRING} { yytext[yyleng-1] = '\0'; ParseObject *top = g_queue_peek_head ( file_queue ); g_assert ( top != NULL ); char *file2 = helper_get_theme_path ( &yytext[1], rasi_theme_file_extensions, top->filename ); char *filename = rofi_theme_parse_prepare_file ( file2 ); g_free ( file2 ); FILE *f = fopen ( filename, "rb" ); if ( f ) { top->location = *yylloc; ParseObject *po = g_malloc0(sizeof(ParseObject)); po->type = PT_FILE; po->filename = filename; po->filein = f; current = po; g_queue_push_head ( file_queue, po ); yypush_buffer_state (yy_create_buffer ( 0, YY_BUF_SIZE )); yylloc->first_line = yylloc->last_line = 1; yylloc->first_column = yylloc->last_column = 1; yylloc->filename = current->filename; } else { char *str = g_markup_printf_escaped ( "Failed to open theme: %s\nError: %s", filename, strerror ( errno ) ); rofi_add_warning_message ( g_string_new ( str ) ); g_free ( str ); g_free(filename); } // Pop out of include. */ BEGIN(GPOINTER_TO_INT(g_queue_pop_head ( queue ))); } /** Everythin not yet parsed is an error. */ . { return T_ERROR_INCLUDE; } /** * END INCLUDES */ {CONFIGURATION} { g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(DEFAULTS); return T_CONFIGURATION; } /** * Handle defaults: * { ... } */ {ASTERIX} { g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(DEFAULTS); return T_PDEFAULTS; } /** Skip all whitespace */ {WHITESPACE} {} "\{" { g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(SECTION); return T_BOPEN; } /** Everything not yet parsed is an error. */ . { return T_ERROR_DEFAULTS; } "#" { g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(NAMESTR); return T_NAME_PREFIX; } /* Go into parsing a section. */ "\{" { g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(SECTION); return T_BOPEN; } /* Pop out of parsing a section. */
"\}" { g_queue_pop_head ( queue ); BEGIN(GPOINTER_TO_INT(g_queue_pop_head ( queue ))); return T_BCLOSE; } \.|{WHITESPACE} { return T_NSEP; } ,{WHITESPACE}* { return T_SSEP; } /* Alias color to text-color */
"color" { yylval->sval = g_strdup("text-color"); return T_PROP_NAME;}
{WORD} { yylval->sval = g_strdup(yytext); return T_PROP_NAME;} {WORD_ELEMENT} { yylval->sval = g_strdup(yytext); return T_NAME_ELEMENT;} /* After Namestr/Classstr we want to go to state str, then to { */ {WHITESPACE}+ ; // ignore all whitespace {WHITESPACE}+ ; // ignore all whitespace
":" { g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(PROPERTIES); return T_PSEP; } ";" { BEGIN(GPOINTER_TO_INT ( g_queue_pop_head ( queue ))); return T_PCLOSE;} (true|false) { yylval->bval= g_strcmp0(yytext, "true") == 0; return T_BOOLEAN;} {NUMBER}\.{NUMBER} { yylval->fval = g_ascii_strtod(yytext, NULL); return T_DOUBLE;} {NUMBER} { yylval->ival = (int)g_ascii_strtoll(yytext, NULL, 10); return T_INT;} {UNARYMIN} { return T_MIN; } {STRING} { yytext[yyleng-1] = '\0'; yylval->sval = g_strcompress(&yytext[1]); return T_STRING;} {STRING_LIST} { yytext[yyleng-1] = '\0'; yylval->sval = g_strcompress(&yytext[1]); return T_STRING;} {CHAR} { yytext[yyleng-1] = '\0'; yylval->cval = g_strcompress(&yytext[1])[0]; return T_CHAR;} @{WORD} { yylval->sval = g_strdup(yytext+1); return T_LINK; }
"\{" { // Double to fit in scheme. g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); g_queue_push_head ( queue, GINT_TO_POINTER (SECTION) ); BEGIN(SECTION); return T_BOPEN; } {EM} { return T_UNIT_EM; } {CH} { return T_UNIT_CH; } {PX} { return T_UNIT_PX; } {MM} { return T_UNIT_MM; } {PERCENT} { return T_PERCENT; } {LS_SOLID} { return T_SOLID; } {LS_DASH} { return T_DASH; } {INHERIT} { return T_INHERIT; } {MODIFIER_ADD} { return T_MODIFIER_ADD; } {MODIFIER_MULTIPLY} { return T_MODIFIER_MULTIPLY; } {MODIFIER_MIN} { return T_MODIFIER_MIN; } {MODIFIER_MAX} { return T_MODIFIER_MAX; } {MODIFIER_ROUND} { return T_MODIFIER_ROUND; } {MODIFIER_FLOOR} { return T_MODIFIER_FLOOR; } {MODIFIER_CEIL} { return T_MODIFIER_CEIL; } {MODIFIER_MODULO} { return T_MODIFIER_MODULO; } {CALC} { return T_CALC; } {ENV} { yytext[yyleng-1] = '\0'; const char *val = g_getenv(yytext+2); if ( val ) { ParseObject *top = g_queue_peek_head ( file_queue ); top->location = *yylloc; ParseObject *po = g_malloc0(sizeof(ParseObject)); po->type = PT_ENV; po->input_str = val; po->str_len = strlen(val); current = po; g_queue_push_head ( file_queue, po ); yypush_buffer_state (yy_create_buffer ( 0, YY_BUF_SIZE )); yylloc->first_line = yylloc->last_line = 1; yylloc->first_column = yylloc->last_column = 1; yylloc->filename = current->filename; g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(PROPERTIES_ENV); } } {WORD_ENV} { const char *val = g_getenv(yytext); if ( val ) { ParseObject *top = g_queue_peek_head ( file_queue ); top->location = *yylloc; ParseObject *po = g_malloc0(sizeof(ParseObject)); po->type = PT_ENV; po->input_str = val; po->str_len = strlen(val); current = po; g_queue_push_head ( file_queue, po ); yypush_buffer_state (yy_create_buffer ( 0, YY_BUF_SIZE )); yylloc->first_line = yylloc->last_line = 1; yylloc->first_column = yylloc->last_column = 1; yylloc->filename = current->filename; g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(PROPERTIES_ENV); } } {WORD_ENV} { const char *val = g_getenv(yytext); if ( val ) { ParseObject *top = g_queue_peek_head ( file_queue ); top->location = *yylloc; ParseObject *po = g_malloc0(sizeof(ParseObject)); po->type = PT_ENV; po->input_str = val; po->str_len = strlen(val); current = po; g_queue_push_head ( file_queue, po ); yypush_buffer_state (yy_create_buffer ( 0, YY_BUF_SIZE )); yylloc->first_line = yylloc->last_line = 1; yylloc->first_column = yylloc->last_column = 1; yylloc->filename = current->filename; g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(MEDIA_ENV_VAR_CONTENT); } } /** * Color parsing. It is easier to do this at lexer level. * Other schemes are done at yacc level. */ #{HEX}{8} { yylval->colorval.red = rofi_theme_parse_convert_hex(yytext[1],yytext[2]); yylval->colorval.green = rofi_theme_parse_convert_hex(yytext[3],yytext[4]); yylval->colorval.blue = rofi_theme_parse_convert_hex(yytext[5],yytext[6]); yylval->colorval.alpha = rofi_theme_parse_convert_hex(yytext[7],yytext[8]); return T_COLOR; } #{HEX}{6} { yylval->colorval.alpha = 1.0; yylval->colorval.red = rofi_theme_parse_convert_hex(yytext[1],yytext[2]); yylval->colorval.green = rofi_theme_parse_convert_hex(yytext[3],yytext[4]); yylval->colorval.blue = rofi_theme_parse_convert_hex(yytext[5],yytext[6]); return T_COLOR; } #{HEX}{3} { yylval->colorval.alpha = 1.0; yylval->colorval.red = rofi_theme_parse_convert_hex(yytext[1],yytext[1]); yylval->colorval.green = rofi_theme_parse_convert_hex(yytext[2],yytext[2]); yylval->colorval.blue = rofi_theme_parse_convert_hex(yytext[3],yytext[3]); return T_COLOR; } #{HEX}{4} { yylval->colorval.alpha = rofi_theme_parse_convert_hex(yytext[4],yytext[4]); yylval->colorval.red = rofi_theme_parse_convert_hex(yytext[1],yytext[1]); yylval->colorval.green = rofi_theme_parse_convert_hex(yytext[2],yytext[2]); yylval->colorval.blue = rofi_theme_parse_convert_hex(yytext[3],yytext[3]); return T_COLOR; } argb:{HEX}{8} { yylval->colorval.alpha = rofi_theme_parse_convert_hex(yytext[5],yytext[6]); yylval->colorval.red = rofi_theme_parse_convert_hex(yytext[7],yytext[8]); yylval->colorval.green = rofi_theme_parse_convert_hex(yytext[9],yytext[10]); yylval->colorval.blue = rofi_theme_parse_convert_hex(yytext[11],yytext[12]); return T_COLOR; } argb:{HEX}{7} { return T_ERROR_ARGB_SPEC; } {URL} { return T_URL; } {LINEAR_GRADIENT} { return T_LINEAR_GRADIENT; } {WIDTH} { return T_WIDTH; } {HEIGHT} { return T_HEIGHT; } {BOTH} { return T_BOTH; } {TO} { return T_TO; } {LEFT} { return T_LEFT; } {RIGHT} { return T_RIGHT; } {TOP} { return T_TOP; } {BOTTOM} { return T_BOTTOM; } /* Color schemes */ {RGBA} { return T_COL_RGBA; } {HSL} { return T_COL_HSL; } {HWB} { return T_COL_HWB; } {CMYK} { return T_COL_CMYK; } {S_T_PARENT_LEFT} { return T_PARENT_LEFT; } /* Fluff */ {VAR_START} { g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(PROPERTIES_VAR); return T_VAR_START; } {ENV_START} { g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(PROPERTIES_ENV_VAR); return T_ENV_START; } {ENV_START} { g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(MEDIA_ENV_VAR); return T_ENV_START; } {S_T_PARENT_RIGHT} { BEGIN(GPOINTER_TO_INT(g_queue_pop_head ( queue ))); return T_PARENT_RIGHT; } {COMMA} { g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(PROPERTIES_VAR_DEFAULT); return T_COMMA; } {COMMA} { g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(MEDIA_ENV_VAR_DEFAULT); return T_COMMA; } {S_T_PARENT_RIGHT} { // Pop 2. g_queue_pop_head ( queue ); BEGIN(GPOINTER_TO_INT(g_queue_pop_head ( queue ))); return T_PARENT_RIGHT; } {S_T_PARENT_LEFT} { return T_PARENT_LEFT; } {S_T_PARENT_RIGHT} { return T_PARENT_RIGHT; } {COMMA} { return T_COMMA; } {LIST_OPEN} { g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(PROPERTIES_ARRAY); return T_LIST_OPEN; } {LIST_CLOSE} { BEGIN(GPOINTER_TO_INT(g_queue_pop_head ( queue ))); return T_LIST_CLOSE; } {FORWARD_SLASH} { return T_FORWARD_SLASH; } /* Position */ {CENTER} { return T_POS_CENTER; } {EAST} { return T_POS_EAST; } {WEST} { return T_POS_WEST; } {SOUTH} { return T_POS_SOUTH; } {NORTH} { return T_POS_NORTH; } /* Highlight style */ {NONE} { return T_NONE; } {BOLD} { return T_BOLD; } {ITALIC} { return T_ITALIC; } {UNDERLINE} { return T_UNDERLINE; } {STRIKETHROUGH} { return T_STRIKETHROUGH; } {UPPERCASE} { return T_UPPERCASE; } {LOWERCASE} { return T_LOWERCASE; } {CAPITALIZE} { return T_CAPITALIZE; } {ANGLE_DEG} { return T_ANGLE_DEG; } {ANGLE_RAD} { return T_ANGLE_RAD; } {ANGLE_GRAD} { return T_ANGLE_GRAD; } {ANGLE_TURN} { return T_ANGLE_TURN; } {ORIENTATION_HORI} { return ORIENTATION_HORI; } {ORIENTATION_VERT} { return ORIENTATION_VERT; } {CURSOR_DEF} { return CURSOR_DEF; } {CURSOR_PTR} { return CURSOR_PTR; } {CURSOR_TXT} { return CURSOR_TXT; } {COLOR_TRANSPARENT} { return T_COLOR_TRANSPARENT; } {COLOR_NAME} { for ( unsigned int iter = 0; iter < num_CSSColors; iter++) { if ( strcasecmp(yytext, CSSColors[iter].name )== 0 ) { yylval->colorval.alpha = 1.0; yylval->colorval.red = CSSColors[iter].r/255.0; yylval->colorval.green = CSSColors[iter].g/255.0; yylval->colorval.blue = CSSColors[iter].b/255.0; return T_COLOR_NAME; } } REJECT; } <> { ParseObject *po = g_queue_pop_head ( file_queue ); if ( po ) { if ( po->type == PT_FILE ) { fclose ( po->filein ); } if ( po->type == PT_STRING_ALLOC ) { g_free( po->malloc_str); } g_free ( po->filename ); g_free ( po ); } po = g_queue_peek_head ( file_queue ); if ( po == NULL ) { g_queue_free ( queue ); // Reset pointer to NULL queue = NULL; yyterminate(); } else { yypop_buffer_state(); current = po; *yylloc = current->location; BEGIN(GPOINTER_TO_INT ( g_queue_pop_head ( queue ))); } } <*>\n { yylloc->last_column = 1; yylloc->last_line ++; }; <*>(\r\n) { yylloc->last_column = 1; yylloc->last_line ++; }; {MEDIA} { g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(MEDIA); return T_MEDIA; } "\}" { g_queue_pop_head ( queue ); BEGIN(GPOINTER_TO_INT(g_queue_pop_head ( queue ))); return T_BCLOSE; } {S_T_PARENT_LEFT} { g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(MEDIA_CONTENT); return T_PARENT_LEFT; } {MEDIA_TYPES} { yylval->sval = g_strdup(yytext); return T_MEDIA_TYPE; } ":" { return T_PSEP; } {S_T_PARENT_RIGHT} { int id = GPOINTER_TO_INT(g_queue_pop_head ( queue )); BEGIN(id); return T_PARENT_RIGHT; } "\{" { g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(INITIAL); return T_BOPEN; } /** * Media defaults. */ {WHITESPACE}+ ; // ignore all whitespace . { yytext[yyleng-1] = '\0'; return T_ERROR; } /** * If we just encounter a word, we assume it is a Widget name. * This makes include,theme, configuration a reserved keyword. */ {WORD_ELEMENT} { g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(NAMESTR); yylval->sval = g_strdup(yytext); return T_NAME_ELEMENT; } . { yytext[yyleng-1] = '\0'; return T_ERROR; }
. { yytext[yyleng-1] = '\0'; return T_ERROR_SECTION; } {WORD_ELEMENT} { yylval->sval = g_strdup(yytext); return T_ELEMENT; } . { yytext[yyleng-1] = '\0'; return T_ERROR_PROPERTY; } . { yytext[yyleng-1] = '\0'; return T_ERROR_NAMESTRING; } %% gboolean rofi_theme_parse_file ( const char *file ) { char *file2 = helper_get_theme_path ( file, rasi_theme_file_extensions, NULL ); char *filename = rofi_theme_parse_prepare_file ( file2 ); g_free ( file2 ); yyin = fopen ( filename, "rb" ); if ( yyin == NULL ) { char *str = g_markup_printf_escaped ( "Failed to open theme: %s\nError: %s", filename, strerror ( errno ) ); rofi_add_error_message ( g_string_new ( str ) ); g_free ( str ); g_free ( filename ); return TRUE; } /** Add Parse object */ file_queue = g_queue_new (); ParseObject *po = g_malloc0(sizeof(ParseObject)); po->type = PT_FILE; po->filename = filename; po->filein = yyin; current = po; g_queue_push_head ( file_queue, po ); g_debug ( "Parsing top file: '%s'", filename ); int parser_retv = yyparse ( file ); yylex_destroy (); yyin = NULL; while ( (po = g_queue_pop_head ( file_queue ) )) { if ( po->type == PT_FILE ) { fclose ( po->filein ); } if ( po->type == PT_STRING_ALLOC ) { g_free( po->malloc_str); } g_free ( po->filename ); g_free ( po ); } // Free up. g_queue_free ( file_queue ); file_queue = NULL; if ( parser_retv != 0 ) { return TRUE; } return FALSE; } gboolean rofi_theme_parse_string ( const char *string ) { yyin = NULL; /** Add Parse object */ file_queue = g_queue_new (); ParseObject *po = g_malloc0(sizeof(ParseObject)); po->type = PT_STRING; po->input_str = string; po->str_len = strlen(string); current = po; g_queue_push_head ( file_queue, po ); g_debug ( "Parsing string: '%s'", string ); int parser_retv = yyparse ( string ); yylex_destroy (); while ( (po = g_queue_pop_head ( file_queue ) )) { if ( po->type == PT_FILE ) { fclose ( po->filein ); } if ( po->type == PT_STRING_ALLOC ) { g_free( po->malloc_str); } g_free ( po->filename ); g_free ( po ); } // Free up. g_queue_free ( file_queue ); file_queue = NULL; if ( parser_retv != 0 ) { return TRUE; } return FALSE; }