| /* |
| * Copyright (c) 2012-2014, NVIDIA CORPORATION. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms and conditions of the GNU General Public License, |
| * version 2, as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope 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 this program. If not, see <http://www.gnu.org/licenses/>. |
| * |
| * See file CREDITS for list of people who contributed to this |
| * project. |
| */ |
| |
| /* |
| * parse.c - Parsing support for the cbootimage tool |
| */ |
| |
| #include <ctype.h> |
| #include "parse.h" |
| #include "cbootimage.h" |
| #include "data_layout.h" |
| #include "crypto.h" |
| #include "set.h" |
| |
| /* |
| * Function prototypes |
| * |
| * ParseXXX() parses XXX in the input |
| * SetXXX() sets state based on the parsing results but does not perform |
| * any parsing of its own |
| * A ParseXXX() function may call other parse functions and set functions. |
| * A SetXXX() function may not call any parseing functions. |
| */ |
| |
| static int |
| set_array(build_image_context *context, |
| u_int32_t index, |
| parse_token token, |
| u_int32_t value); |
| static char *parse_u32(char *str, u_int32_t *val); |
| static char *parse_u8(char *str, u_int32_t *val); |
| static char *parse_chipuid(char *str, u_int8_t *val); |
| static char *parse_filename(char *str, char *name, int chars_remaining); |
| static char *parse_enum(build_image_context *context, |
| char *str, |
| enum_item *table, |
| u_int32_t *val); |
| static char |
| *parse_field_name(char *rest, field_item *field_table, field_item **field); |
| static char |
| *parse_field_value(build_image_context *context, |
| char *rest, |
| field_item *field, |
| u_int32_t *value); |
| static int |
| parse_array(build_image_context *context, parse_token token, char *rest); |
| static int |
| parse_bootloader(build_image_context *context, parse_token token, char *rest); |
| static int |
| parse_mts_image(build_image_context *context, parse_token token, char *rest); |
| static int |
| parse_value_u32(build_image_context *context, parse_token token, char *rest); |
| static int |
| parse_value_chipuid(build_image_context *context, |
| parse_token token, |
| char *rest); |
| static int |
| parse_bct_file(build_image_context *context, parse_token token, char *rest); |
| static char |
| *parse_end_state(char *str, char *uname, int chars_remaining); |
| static int |
| parse_dev_param(build_image_context *context, parse_token token, char *rest); |
| static int |
| parse_sdram_param(build_image_context *context, parse_token token, char *rest); |
| |
| static int process_statement(build_image_context *context, |
| char *str, |
| u_int8_t simple_parse); |
| |
| static parse_item parse_simple_items[] = |
| { |
| { "Bctfile=", token_bct_file, parse_bct_file }, |
| { "BootLoader=", token_bootloader, parse_bootloader }, |
| { "Redundancy=", token_redundancy, parse_value_u32 }, |
| { "Bctcopy=", token_bct_copy, parse_value_u32 }, |
| { "MtsPreboot=", token_mts_preboot, parse_mts_image}, |
| { "Mts=", token_mts, parse_mts_image}, |
| { "Version=", token_version, parse_value_u32 }, |
| { "PreBctPadBlocks=", token_pre_bct_pad_blocks, parse_value_u32 }, |
| { NULL, 0, NULL } /* Must be last */ |
| }; |
| |
| static parse_item s_top_level_items[] = { |
| { "Bctfile=", token_bct_file, parse_bct_file }, |
| { "Attribute=", token_attribute, parse_value_u32 }, |
| { "Attribute[", token_attribute, parse_array }, |
| { "PageSize=", token_page_size, parse_value_u32 }, |
| { "BlockSize=", token_block_size, parse_value_u32 }, |
| { "PartitionSize=", token_partition_size, parse_value_u32 }, |
| { "DevType[", token_dev_type, parse_array }, |
| { "DeviceParam[", token_dev_param, parse_dev_param }, |
| { "SDRAM[", token_sdram, parse_sdram_param }, |
| { "BootLoader=", token_bootloader, parse_bootloader }, |
| { "Redundancy=", token_redundancy, parse_value_u32 }, |
| { "Bctcopy=", token_bct_copy, parse_value_u32 }, |
| { "MtsPreboot=", token_mts_preboot, parse_mts_image}, |
| { "Mts=", token_mts, parse_mts_image}, |
| { "Version=", token_version, parse_value_u32 }, |
| { "OdmData=", token_odm_data, parse_value_u32 }, |
| { "ChipUid=", token_unique_chip_id, parse_value_chipuid }, |
| { "JtagCtrl=", token_secure_jtag_control, parse_value_u32 }, |
| { "DebugCtrl=", token_secure_debug_control, parse_value_u32 }, |
| { NULL, 0, NULL } /* Must be last */ |
| }; |
| |
| /* Macro to simplify parser code a bit. */ |
| #define PARSE_COMMA(x) if (*rest != ',') return (x); rest++ |
| |
| /* |
| * Parse the given string and find the u32 dec/hex number. |
| * |
| * @param str String to parse |
| * @param val Returns value that was parsed |
| * @return the remainder of the string after the number was parsed |
| */ |
| static char * |
| parse_u32(char *str, u_int32_t *val) |
| { |
| u_int32_t value = 0; |
| u_int32_t digit; |
| |
| while (*str == '0') |
| str++; |
| |
| if (tolower(*str) == 'x') { |
| str++; |
| while (isxdigit(*str)) { |
| value *= 16; |
| digit = tolower(*str); |
| value += digit <= '9' ? digit - '0' : digit - 'a' + 10; |
| str++; |
| } |
| } else { |
| while (*str >= '0' && *str <= '9') { |
| value = value*10 + (*str - '0'); |
| str++; |
| } |
| } |
| *val = value; |
| return str; |
| } |
| |
| /* |
| * Parse the given string and find the u8 dec/hex number. |
| * |
| * @param str String to parse |
| * @param val Returns value that was parsed |
| * @return the remainder of the string after the number was parsed |
| */ |
| static char * |
| parse_u8(char *str, u_int32_t *val) |
| { |
| char *retval; |
| |
| retval = parse_u32(str, val); |
| |
| if (*val > 0xff) { |
| printf("Warning: Parsed 8-bit value that exceeded 8-bits.\n"); |
| printf(" Parsed value = %d. Remaining text = %s\n", |
| *val, retval); |
| } |
| |
| return retval; |
| } |
| |
| /* |
| * Parse the given string and transfer to chip uid. |
| * |
| * @param str String to parse |
| * @param chipuid Returns chip uid that was parsed |
| * @return the remainder of the string after the number was parsed |
| */ |
| static char * |
| parse_chipuid(char *str, u_int8_t *chipuid) |
| { |
| int byte_index = 0; |
| int paddings = 0; |
| char byte_str[3]; |
| |
| if (*str++ != '0') |
| return NULL; |
| |
| if (*str++ != 'x') |
| return NULL; |
| |
| paddings = strlen(str) % 2; |
| byte_index = strlen(str) / 2 + paddings; |
| |
| if (byte_index > 16) |
| return NULL; |
| |
| memset(chipuid, 0, 16); |
| |
| while (*str != '\0' && byte_index > 0) { |
| char *endptr; |
| |
| strncpy(byte_str, str, 2 - paddings); |
| byte_str[2 - paddings] = '\0'; |
| str += 2 - paddings; |
| |
| chipuid[byte_index - 1] = strtoul(byte_str, &endptr, 16); |
| if (*endptr) |
| return NULL; |
| |
| byte_index--; |
| paddings = 0; |
| } |
| |
| return str; |
| } |
| |
| /* |
| * Parse the given string and find the file name then |
| * return the rest of the string. |
| * |
| * @param str String to parse |
| * @param name Returns the filename that was parsed |
| * @param chars_remaining The maximum length of filename |
| * @return the remainder of the string after the name was parsed |
| */ |
| static char * |
| parse_filename(char *str, char *name, int chars_remaining) |
| { |
| /* |
| * Check if the filename buffer is out of space, preserving one |
| * character to null terminate the string. |
| */ |
| while (isalnum(*str) || strchr("\\/~_-+:.", *str)) { |
| |
| chars_remaining--; |
| |
| if (chars_remaining < 1) |
| return NULL; |
| *name++ = *str++; |
| } |
| |
| /* Null terminate the filename. */ |
| *name = '\0'; |
| |
| return str; |
| } |
| |
| /* |
| * Parse the given string and find the match field name listed |
| * in field table. |
| * |
| * @param rest String to parse |
| * @param field_table The field table to parse |
| * @param field Returns the field item that was parsed |
| * @return NULL or the remainder of the string after the field item was parsed |
| */ |
| static char |
| *parse_field_name(char *rest, field_item *field_table, field_item **field) |
| { |
| u_int32_t i; |
| u_int32_t field_name_len = 0; |
| |
| assert(field_table != NULL); |
| assert(rest != NULL); |
| assert(field != NULL); |
| |
| while (rest[field_name_len] != '=') |
| field_name_len++; |
| |
| /* Parse the field name. */ |
| for (i = 0; field_table[i].name != NULL; i++) { |
| if ((strlen(field_table[i].name) == field_name_len) && |
| !strncmp(field_table[i].name, |
| rest, |
| field_name_len)) { |
| |
| *field = &(field_table[i]); |
| rest = rest + field_name_len; |
| return rest; |
| } |
| } |
| |
| /* Field wasn't found or a parse error occurred. */ |
| return NULL; |
| } |
| |
| /* |
| * Parse the value based on the field table |
| * |
| * @param context The main context pointer |
| * @param rest String to parse |
| * @param field Field item to parse |
| * @param value Returns the value that was parsed |
| * @return the remainder of the string after the value was parsed |
| */ |
| static char |
| *parse_field_value(build_image_context *context, |
| char *rest, |
| field_item *field, |
| u_int32_t *value) |
| { |
| assert(rest != NULL); |
| assert(field != NULL); |
| assert((field->type != field_type_enum) |
| || (field->enum_table != NULL)); |
| |
| switch (field->type) { |
| case field_type_enum: |
| rest = parse_enum(context, rest, field->enum_table, value); |
| break; |
| |
| case field_type_u32: |
| rest = parse_u32(rest, value); |
| break; |
| |
| case field_type_u8: |
| rest = parse_u8(rest, value); |
| break; |
| |
| default: |
| printf("Unexpected field type %d at line %d\n", |
| field->type, __LINE__); |
| rest = NULL; |
| break; |
| } |
| |
| return rest; |
| } |
| |
| /* |
| * Parse the given string and find the match enum item listed |
| * in table. |
| * |
| * @param context The main context pointer |
| * @param str String to parse |
| * @param table Enum item table to parse |
| * @param value Returns the value that was parsed |
| * @return the remainder of the string after the item was parsed |
| */ |
| static char * |
| parse_enum(build_image_context *context, |
| char *str, |
| enum_item *table, |
| u_int32_t *val) |
| { |
| int i; |
| char *rest; |
| |
| for (i = 0; table[i].name != NULL; i++) { |
| if (!strncmp(table[i].name, str, |
| strlen(table[i].name))) { |
| *val = table[i].value; |
| rest = str + strlen(table[i].name); |
| return rest; |
| } |
| } |
| return parse_u32(str, val); |
| |
| } |
| |
| /* |
| * Parse the given string and find the bootloader file name, load address and |
| * entry point information then call set_bootloader function. |
| * |
| * @param context The main context pointer |
| * @param token The parse token value |
| * @param rest String to parse |
| * @return 0 and 1 for success and failure |
| */ |
| static int parse_bootloader(build_image_context *context, |
| parse_token token, |
| char *rest) |
| { |
| char filename[MAX_BUFFER]; |
| char e_state[MAX_STR_LEN]; |
| u_int32_t load_addr; |
| u_int32_t entry_point; |
| |
| assert(context != NULL); |
| assert(rest != NULL); |
| |
| if (context->generate_bct != 0) |
| return 0; |
| /* Parse the file name. */ |
| rest = parse_filename(rest, filename, MAX_BUFFER); |
| if (rest == NULL) |
| return 1; |
| |
| PARSE_COMMA(1); |
| |
| /* Parse the load address. */ |
| rest = parse_u32(rest, &load_addr); |
| if (rest == NULL) |
| return 1; |
| |
| PARSE_COMMA(1); |
| |
| /* Parse the entry point. */ |
| rest = parse_u32(rest, &entry_point); |
| if (rest == NULL) |
| return 1; |
| |
| PARSE_COMMA(1); |
| |
| /* Parse the end state. */ |
| rest = parse_end_state(rest, e_state, MAX_STR_LEN); |
| if (rest == NULL) |
| return 1; |
| if (strncmp(e_state, "Complete", strlen("Complete"))) |
| return 1; |
| |
| /* Parsing has finished - set the bootloader */ |
| return set_bootloader(context, filename, load_addr, entry_point); |
| } |
| |
| /* |
| * Parse the given string and find the MTS file name, load address and |
| * entry point information then call set_mts_image function. |
| * |
| * @param context The main context pointer |
| * @param token The parse token value |
| * @param rest String to parse |
| * @return 0 and 1 for success and failure |
| */ |
| static int parse_mts_image(build_image_context *context, |
| parse_token token, |
| char *rest) |
| { |
| char filename[MAX_BUFFER]; |
| char e_state[MAX_STR_LEN]; |
| u_int32_t load_addr; |
| u_int32_t entry_point; |
| |
| assert(context != NULL); |
| assert(rest != NULL); |
| |
| if (context->generate_bct != 0) |
| return 0; |
| /* Parse the file name. */ |
| rest = parse_filename(rest, filename, MAX_BUFFER); |
| if (rest == NULL) |
| return 1; |
| |
| PARSE_COMMA(1); |
| |
| /* Parse the load address. */ |
| rest = parse_u32(rest, &load_addr); |
| if (rest == NULL) |
| return 1; |
| |
| PARSE_COMMA(1); |
| |
| /* Parse the entry point. */ |
| rest = parse_u32(rest, &entry_point); |
| if (rest == NULL) |
| return 1; |
| |
| PARSE_COMMA(1); |
| |
| /* Parse the end state. */ |
| rest = parse_end_state(rest, e_state, MAX_STR_LEN); |
| if (rest == NULL) |
| return 1; |
| if (strncmp(e_state, "Complete", strlen("Complete"))) |
| return 1; |
| |
| /* Parsing has finished - set the bootloader */ |
| return set_mts_image(context, filename, load_addr, entry_point); |
| } |
| |
| /* |
| * Parse the given string and find the array items in config file. |
| * |
| * @param context The main context pointer |
| * @param token The parse token value |
| * @param rest String to parse |
| * @return 0 and 1 for success and failure |
| */ |
| static int |
| parse_array(build_image_context *context, parse_token token, char *rest) |
| { |
| u_int32_t index; |
| u_int32_t value; |
| |
| assert(context != NULL); |
| assert(rest != NULL); |
| |
| /* Parse the index. */ |
| rest = parse_u32(rest, &index); |
| if (rest == NULL) |
| return 1; |
| |
| /* Parse the closing bracket. */ |
| if (*rest != ']') |
| return 1; |
| rest++; |
| |
| /* Parse the equals sign.*/ |
| if (*rest != '=') |
| return 1; |
| rest++; |
| |
| /* Parse the value based on the field table. */ |
| switch (token) { |
| case token_attribute: |
| rest = parse_u32(rest, &value); |
| break; |
| case token_dev_type: |
| rest = parse_enum(context, |
| rest, |
| g_soc_config->devtype_table, |
| &value); |
| break; |
| |
| default: |
| /* Unknown token */ |
| return 1; |
| } |
| |
| if (rest == NULL) |
| return 1; |
| |
| /* Store the result. */ |
| return set_array(context, index, token, value); |
| } |
| |
| /* |
| * Call hw interface to set the value for array item in bct such as device |
| * type and bootloader attribute. |
| * |
| * @param context The main context pointer |
| * @param index The index for array |
| * @param token The parse token value |
| * @param value The value to set |
| * @return 0 and -ENODATA for success and failure |
| */ |
| |
| static int |
| set_array(build_image_context *context, |
| u_int32_t index, |
| parse_token token, |
| u_int32_t value) |
| { |
| int err = 0; |
| |
| assert(context != NULL); |
| |
| switch (token) { |
| case token_attribute: |
| err = g_soc_config->setbl_param(index, |
| token_bl_attribute, |
| &value, |
| context->bct); |
| break; |
| case token_dev_type: |
| err = g_soc_config->set_dev_param(context, |
| index, |
| token_dev_type, |
| value); |
| break; |
| default: |
| break; |
| } |
| return err; |
| } |
| |
| /* |
| * General handler for setting u_int32_t values in config files. |
| * |
| * @param context The main context pointer |
| * @param token The parse token value |
| * @param rest String to parse |
| * @return 0 and 1 for success and failure |
| */ |
| static int parse_value_u32(build_image_context *context, |
| parse_token token, |
| char *rest) |
| { |
| u_int32_t value; |
| |
| assert(context != NULL); |
| assert(rest != NULL); |
| |
| rest = parse_u32(rest, &value); |
| if (rest == NULL) |
| return 1; |
| |
| return context_set_value(context, token, &value); |
| } |
| |
| /* |
| * General handler for setting chip uid in config files. |
| * |
| * @param context The main context pointer |
| * @param token The parse token value |
| * @param rest String to parse |
| * @return 0 and 1 for success and failure |
| */ |
| static int parse_value_chipuid(build_image_context *context, |
| parse_token token, |
| char *rest) |
| { |
| u_int8_t value[16]; |
| |
| assert(context != NULL); |
| assert(rest != NULL); |
| |
| rest = parse_chipuid(rest, value); |
| if (rest == NULL) |
| return 1; |
| |
| return context_set_value(context, token, value); |
| } |
| |
| /* |
| * Parse the given string and find the bct file name. |
| * |
| * @param context The main context pointer |
| * @param token The parse token value |
| * @param rest String to parse |
| * @return 0 and 1 for success and failure |
| */ |
| static int |
| parse_bct_file(build_image_context *context, parse_token token, char *rest) |
| { |
| char filename[MAX_BUFFER]; |
| |
| assert(context != NULL); |
| assert(rest != NULL); |
| |
| /* Parse the file name. */ |
| rest = parse_filename(rest, filename, MAX_BUFFER); |
| if (rest == NULL) |
| return 1; |
| |
| /* Parsing has finished - set the bctfile */ |
| context->bct_filename = filename; |
| /* Read the bct file to buffer */ |
| if (read_bct_file(context)) |
| return 1; |
| |
| update_context(context); |
| return 0; |
| } |
| |
| static char * |
| parse_end_state(char *str, char *uname, int chars_remaining) |
| { |
| while (isalpha(*str)) { |
| |
| *uname++ = *str++; |
| if (--chars_remaining < 0) |
| return NULL; |
| } |
| *uname = '\0'; |
| return str; |
| } |
| |
| /* |
| * Parse the given string and find device parameter listed in device table |
| * and value for this device parameter. If match, call the corresponding |
| * function in the table to set device parameter. |
| * |
| * @param context The main context pointer |
| * @param token The parse token value |
| * @param rest String to parse |
| * @return 0 and 1 for success and failure |
| */ |
| static int |
| parse_dev_param(build_image_context *context, parse_token token, char *rest) |
| { |
| u_int32_t i; |
| u_int32_t value; |
| field_item *field; |
| u_int32_t index; |
| parse_subfield_item *device_item = NULL; |
| |
| assert(context != NULL); |
| assert(rest != NULL); |
| |
| /* Parse the index. */ |
| rest = parse_u32(rest, &index); |
| if (rest == NULL) |
| return 1; |
| |
| /* Parse the closing bracket. */ |
| if (*rest != ']') |
| return 1; |
| rest++; |
| |
| /* Parse the following '.' */ |
| if (*rest != '.') |
| return 1; |
| rest++; |
| |
| /* Parse the device name. */ |
| for (i = 0; g_soc_config->device_type_table[i].prefix != NULL; i++) { |
| if (!strncmp(g_soc_config->device_type_table[i].prefix, |
| rest, strlen(g_soc_config->device_type_table[i].prefix))) { |
| |
| device_item = &(g_soc_config->device_type_table[i]); |
| rest = rest + strlen(g_soc_config->device_type_table[i].prefix); |
| |
| /* Parse the field name. */ |
| rest = parse_field_name(rest, |
| g_soc_config->device_type_table[i].field_table, |
| &field); |
| if (rest == NULL) |
| return 1; |
| |
| /* Parse the equals sign.*/ |
| if (*rest != '=') |
| return 1; |
| rest++; |
| |
| /* Parse the value based on the field table. */ |
| rest = parse_field_value(context, rest, field, &value); |
| if (rest == NULL) |
| return 1; |
| return device_item->process(context, |
| index, field->token, value); |
| } |
| } |
| return 1; |
| } |
| |
| /* |
| * Parse the given string and find sdram parameter and value in config |
| * file. If match, call the corresponding function set the sdram parameter. |
| * |
| * @param context The main context pointer |
| * @param token The parse token value |
| * @param rest String to parse |
| * @return 0 and 1 for success and failure |
| */ |
| static int |
| parse_sdram_param(build_image_context *context, parse_token token, char *rest) |
| { |
| u_int32_t value; |
| field_item *field; |
| u_int32_t index; |
| |
| assert(context != NULL); |
| assert(rest != NULL); |
| |
| /* Parse the index. */ |
| rest = parse_u32(rest, &index); |
| if (rest == NULL) |
| return 1; |
| |
| /* Parse the closing bracket. */ |
| if (*rest != ']') |
| return 1; |
| rest++; |
| |
| /* Parse the following '.' */ |
| if (*rest != '.') |
| return 1; |
| rest++; |
| |
| /* Parse the field name. */ |
| rest = parse_field_name(rest, g_soc_config->sdram_field_table, &field); |
| |
| if (rest == NULL) |
| return 1; |
| |
| /* Parse the equals sign.*/ |
| if (*rest != '=') |
| return 1; |
| rest++; |
| |
| /* Parse the value based on the field table. */ |
| rest = parse_field_value(context, rest, field, &value); |
| if (rest == NULL) |
| return 1; |
| |
| /* Store the result. */ |
| return g_soc_config->set_sdram_param(context, |
| index, |
| field->token, |
| value); |
| } |
| |
| /* |
| * Compare the given string with item listed in table. |
| * Execute the proper process function if match. |
| * |
| * @param context The main context pointer |
| * @param str String to parse |
| * @param simple_parse Simple parse flag |
| * @return 0 and 1 for success and failure |
| */ |
| static int |
| process_statement(build_image_context *context, |
| char *str, |
| u_int8_t simple_parse) |
| { |
| int i; |
| char *rest; |
| parse_item *cfg_parse_item; |
| |
| if (simple_parse == 0) |
| cfg_parse_item = s_top_level_items; |
| else |
| cfg_parse_item = parse_simple_items; |
| |
| for (i = 0; cfg_parse_item[i].prefix != NULL; i++) { |
| if (!strncmp(cfg_parse_item[i].prefix, str, |
| strlen(cfg_parse_item[i].prefix))) { |
| rest = str + strlen(cfg_parse_item[i].prefix); |
| |
| return cfg_parse_item[i].process(context, |
| cfg_parse_item[i].token, |
| rest); |
| } |
| } |
| |
| /* If this point was reached, there was a processing error. */ |
| return 1; |
| } |
| |
| /* |
| * The main function parse the config file. |
| * |
| * @param context The main context pointer |
| * @param simple_parse Simple parse flag |
| */ |
| void process_config_file(build_image_context *context, u_int8_t simple_parse) |
| { |
| char buffer[MAX_BUFFER]; |
| int space = 0; |
| int current; |
| u_int8_t c_eol_comment_start = 0; /* True after first slash */ |
| u_int8_t comment = 0; |
| u_int8_t string = 0; |
| u_int8_t equal_encounter = 0; |
| |
| assert(context != NULL); |
| assert(context->config_file != NULL); |
| |
| while ((current = fgetc(context->config_file)) != EOF) { |
| if (space >= (MAX_BUFFER-1)) { |
| /* if we exceeded the max buffer size, it is likely |
| due to a missing semi-colon at the end of a line */ |
| printf("Config file parsing error!"); |
| exit(1); |
| } |
| |
| /* Handle failure to complete "//" comment token. |
| Insert the '/' into the busffer and proceed with |
| processing the current character. */ |
| if (c_eol_comment_start && current != '/') { |
| c_eol_comment_start = 0; |
| buffer[space++] = '/'; |
| } |
| |
| switch (current) { |
| case '\"': /* " indicates start or end of a string */ |
| if (!comment) { |
| string ^= 1; |
| buffer[space++] = current; |
| } |
| break; |
| case ';': |
| if (!string && !comment) { |
| buffer[space++] = '\0'; |
| |
| if (process_statement(context, |
| buffer, |
| simple_parse)) |
| goto error; |
| space = 0; |
| equal_encounter = 0; |
| } else if (string) |
| buffer[space++] = current; |
| break; |
| |
| case '/': |
| if (!string && !comment) { |
| if (c_eol_comment_start) { |
| /* EOL comment started. */ |
| comment = 1; |
| c_eol_comment_start = 0; |
| } else { |
| /* Potential start of eol comment. */ |
| c_eol_comment_start = 1; |
| } |
| } else if (!comment) |
| buffer[space++] = current; |
| break; |
| |
| /* ignore whitespace. uses fallthrough */ |
| case '\n': |
| case '\r': /* carriage returns end comments */ |
| string = 0; |
| comment = 0; |
| c_eol_comment_start = 0; |
| case ' ': |
| case '\t': |
| if (string) |
| buffer[space++] = current; |
| break; |
| |
| case '#': |
| if (!string) |
| comment = 1; |
| else |
| buffer[space++] = current; |
| break; |
| |
| default: |
| if (!comment) { |
| buffer[space++] = current; |
| if (current == '=') { |
| if (!equal_encounter) |
| equal_encounter = 1; |
| else |
| goto error; |
| } |
| } |
| break; |
| } |
| } |
| |
| return; |
| |
| error: |
| printf("Error parsing: %s\n", buffer); |
| exit(1); |
| } |