/* lexer.c - The scripting lexer. */ /* * VAS_EBOOT -- GRand Unified Bootloader * Copyright (C) 2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. * * VAS_EBOOT is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * VAS_EBOOT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with VAS_EBOOT. If not, see . */ #include #include #include #include #include #include #include #define yytext_ptr char * #include "VasEBoot_script.tab.h" #include "VasEBoot_script.yy.h" void VasEBoot_script_lexer_ref (struct VasEBoot_lexer_param *state) { state->refs++; } void VasEBoot_script_lexer_deref (struct VasEBoot_lexer_param *state) { state->refs--; } /* Start recording all characters passing through the lexer. */ unsigned VasEBoot_script_lexer_record_start (struct VasEBoot_parser_param *parser) { struct VasEBoot_lexer_param *lexer = parser->lexerstate; lexer->record++; if (lexer->recording) return lexer->recordpos; lexer->recordpos = 0; lexer->recordlen = VAS_EBOOT_LEXER_INITIAL_RECORD_SIZE; lexer->recording = VasEBoot_malloc (lexer->recordlen); if (!lexer->recording) { VasEBoot_script_yyerror (parser, 0); lexer->recordlen = 0; } return lexer->recordpos; } char * VasEBoot_script_lexer_record_stop (struct VasEBoot_parser_param *parser, unsigned offset) { int count; char *result; struct VasEBoot_lexer_param *lexer = parser->lexerstate; if (!lexer->record) return 0; lexer->record--; if (!lexer->recording) return 0; count = lexer->recordpos - offset; result = VasEBoot_script_malloc (parser, count + 1); if (result) { VasEBoot_strncpy (result, lexer->recording + offset, count); result[count] = '\0'; } if (lexer->record == 0) { VasEBoot_free (lexer->recording); lexer->recording = 0; lexer->recordlen = 0; lexer->recordpos = 0; } return result; } /* Record STR if input recording is enabled. */ void VasEBoot_script_lexer_record (struct VasEBoot_parser_param *parser, char *str) { int len; char *old; struct VasEBoot_lexer_param *lexer = parser->lexerstate; if (!lexer->record || !lexer->recording) return; len = VasEBoot_strlen (str); if (lexer->recordpos + len + 1 > lexer->recordlen) { old = lexer->recording; if (lexer->recordlen < len) lexer->recordlen = len; if (VasEBoot_mul (lexer->recordlen, 2, &lexer->recordlen)) goto fail; lexer->recording = VasEBoot_realloc (lexer->recording, lexer->recordlen); if (!lexer->recording) { fail: VasEBoot_free (old); lexer->recordpos = 0; lexer->recordlen = 0; VasEBoot_script_yyerror (parser, 0); return; } } VasEBoot_strcpy (lexer->recording + lexer->recordpos, str); lexer->recordpos += len; } /* Read next line of input if necessary, and set yyscanner buffers. */ int VasEBoot_script_lexer_yywrap (struct VasEBoot_parser_param *parserstate, const char *input) { VasEBoot_size_t len = 0, sz; char *p = 0; char *line = 0; YY_BUFFER_STATE buffer; struct VasEBoot_lexer_param *lexerstate = parserstate->lexerstate; if (! lexerstate->refs && ! lexerstate->prefix && ! input) return 1; if (! lexerstate->getline && ! input) { VasEBoot_script_yyerror (parserstate, N_("unexpected end of file")); return 1; } line = 0; if (! input) lexerstate->getline (&line, 1, lexerstate->getline_data); else line = VasEBoot_strdup (input); if (! line) { VasEBoot_script_yyerror (parserstate, N_("out of memory")); return 1; } len = VasEBoot_strlen (line); /* Ensure '\n' at the end. */ if (line[0] == '\0') { VasEBoot_free (line); line = VasEBoot_strdup ("\n"); len = 1; } else if (len && line[len - 1] != '\n') { if (VasEBoot_add (len, 2, &sz)) { VasEBoot_free (line); VasEBoot_script_yyerror (parserstate, N_("overflow is detected")); return 1; } p = VasEBoot_realloc (line, sz); if (p) { p[len++] = '\n'; p[len] = '\0'; } else VasEBoot_free (line); line = p; } if (! line) { VasEBoot_script_yyerror (parserstate, N_("out of memory")); return 1; } /* Prepend any left over unput-text. */ if (lexerstate->prefix) { int plen = VasEBoot_strlen (lexerstate->prefix); p = VasEBoot_malloc (len + plen + 1); if (! p) { VasEBoot_free (line); return 1; } VasEBoot_strcpy (p, lexerstate->prefix); lexerstate->prefix = 0; VasEBoot_strcpy (p + plen, line); VasEBoot_free (line); line = p; len = len + plen; } buffer = yy_scan_string (line, lexerstate->yyscanner); VasEBoot_free (line); if (! buffer) { VasEBoot_script_yyerror (parserstate, 0); return 1; } return 0; } struct VasEBoot_lexer_param * VasEBoot_script_lexer_init (struct VasEBoot_parser_param *parser, char *script, VasEBoot_reader_getline_t arg_getline, void *getline_data) { struct VasEBoot_lexer_param *lexerstate; lexerstate = VasEBoot_zalloc (sizeof (*lexerstate)); if (!lexerstate) return 0; lexerstate->size = VAS_EBOOT_LEXER_INITIAL_TEXT_SIZE; lexerstate->text = VasEBoot_malloc (lexerstate->size); if (!lexerstate->text) { VasEBoot_free (lexerstate); return 0; } lexerstate->getline = arg_getline; lexerstate->getline_data = getline_data; /* The other elements of lexerstate are all zeros already. */ if (yylex_init (&lexerstate->yyscanner)) { VasEBoot_free (lexerstate->text); VasEBoot_free (lexerstate); return 0; } yyset_extra (parser, lexerstate->yyscanner); parser->lexerstate = lexerstate; if (VasEBoot_script_lexer_yywrap (parser, script ?: "\n")) { parser->lexerstate = 0; yylex_destroy (lexerstate->yyscanner); VasEBoot_free (lexerstate->text); VasEBoot_free (lexerstate); return 0; } return lexerstate; } void VasEBoot_script_lexer_fini (struct VasEBoot_lexer_param *lexerstate) { if (!lexerstate) return; yylex_destroy (lexerstate->yyscanner); VasEBoot_free (lexerstate->recording); VasEBoot_free (lexerstate->text); VasEBoot_free (lexerstate); } int VasEBoot_script_yylex (union YYSTYPE *value, struct VasEBoot_parser_param *parserstate) { char *str; int token; VasEBoot_script_arg_type_t type; struct VasEBoot_lexer_param *lexerstate = parserstate->lexerstate; value->arg = 0; if (parserstate->err) return VAS_EBOOT_PARSER_TOKEN_BAD; if (lexerstate->eof) return VAS_EBOOT_PARSER_TOKEN_EOF; /* * Words with environment variables, like foo${bar}baz needs * multiple tokens to be merged into a single VasEBoot_script_arg. We * use two variables to achieve this: lexerstate->merge_start and * lexerstate->merge_end */ lexerstate->merge_start = 0; lexerstate->merge_end = 0; do { /* Empty lexerstate->text. */ lexerstate->used = 1; lexerstate->text[0] = '\0'; token = yylex (value, lexerstate->yyscanner); if (token == VAS_EBOOT_PARSER_TOKEN_BAD) break; /* Merging feature uses lexerstate->text instead of yytext. */ if (lexerstate->merge_start) { str = lexerstate->text; type = lexerstate->type; } else { str = yyget_text (lexerstate->yyscanner); type = VAS_EBOOT_SCRIPT_ARG_TYPE_TEXT; } VasEBoot_dprintf("lexer", "token %u text [%s]\n", token, str); value->arg = VasEBoot_script_arg_add (parserstate, value->arg, type, str); } while (lexerstate->merge_start && !lexerstate->merge_end); if (!value->arg || parserstate->err) return VAS_EBOOT_PARSER_TOKEN_BAD; return token; } void VasEBoot_script_yyerror (struct VasEBoot_parser_param *state, const char *err) { if (err) VasEBoot_error (VAS_EBOOT_ERR_INVALID_COMMAND, "%s", err); VasEBoot_print_error (); state->err++; }