blob: babda0440e87c3e774cf7d1c8ad79253335757e6 [file] [log] [blame]
Peer Chen8d782ee2011-01-18 21:34:18 -05001/**
2 * Copyright (c) 2011 NVIDIA Corporation. All rights reserved.
3 *
4 * See file CREDITS for list of people who contributed to this
5 * project.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 * MA 02111-1307 USA
21 */
22
23/*
24 * parse.c - Parsing support for the cbootimage tool
25 */
26
27/*
28 * TODO / Notes
29 * - Add doxygen commentary
30 * - Do we have endian issues to deal with?
31 * - Add support for device configuration data
32 * - Add support for bad blocks
33 * - Add support for different allocation modes/strategies
34 * - Add support for multiple BCTs in journal block
35 * - Add support for other missing features.
36 */
37
38#include "parse.h"
39#include "cbootimage.h"
40#include "data_layout.h"
41#include "crypto.h"
42#include "set.h"
43
44/*
45 * Function prototypes
46 *
47 * ParseXXX() parses XXX in the input
48 * SetXXX() sets state based on the parsing results but does not perform
49 * any parsing of its own
50 * A ParseXXX() function may call other parse functions and set functions.
51 * A SetXXX() function may not call any parseing functions.
52 */
53
54static char *parse_u32(char *statement, u_int32_t *val);
Peer Chen7557d9b2011-02-24 09:29:23 -080055static char *parse_u8(char *statement, u_int32_t *val);
Peer Chen8d782ee2011-01-18 21:34:18 -050056static char *parse_filename(char *statement, char *name, int chars_remaining);
Peer Chen7557d9b2011-02-24 09:29:23 -080057static char *parse_enum(build_image_context *context,
58 char *statement,
59 enum_item *table,
60 u_int32_t *val);
61static char
62*parse_field_name(char *rest, field_item *field_table, field_item **field);
63static char
64*parse_field_value(build_image_context *context,
65 char *rest,
66 field_item *field,
67 u_int32_t *value);
Peer Chen8d782ee2011-01-18 21:34:18 -050068static int
69parse_array(build_image_context *context, parse_token token, char *rest);
70static int
71parse_bootloader(build_image_context *context, parse_token token, char *rest);
72static int
73parse_value_u32(build_image_context *context, parse_token token, char *rest);
74static int
75parse_bct_file(build_image_context *context, parse_token token, char *rest);
76static int
77parse_addon(build_image_context *context, parse_token token, char *rest);
78static char *parse_string(char *statement, char *uname, int chars_remaining);
79static char
80*parse_end_state(char *statement, char *uname, int chars_remaining);
Peer Chen7557d9b2011-02-24 09:29:23 -080081static int
82parse_dev_param(build_image_context *context, parse_token token, char *rest);
83
Peer Chen8d782ee2011-01-18 21:34:18 -050084static int process_statement(build_image_context *context, char *statement);
85
Peer Chen7557d9b2011-02-24 09:29:23 -080086static enum_item s_devtype_table[] =
87{
88 { "NvBootDevType_Sdmmc", nvbct_lib_id_dev_type_sdmmc },
89 { "NvBootDevType_Spi", nvbct_lib_id_dev_type_spi },
Peer Chen053d5782011-03-03 10:12:58 -080090 { "NvBootDevType_Nand", nvbct_lib_id_dev_type_nand },
Peer Chen7557d9b2011-02-24 09:29:23 -080091 { "Sdmmc", nvbct_lib_id_dev_type_sdmmc },
92 { "Spi", nvbct_lib_id_dev_type_spi },
Peer Chen053d5782011-03-03 10:12:58 -080093 { "Nand", nvbct_lib_id_dev_type_nand },
Peer Chen7557d9b2011-02-24 09:29:23 -080094
95 { NULL, 0 }
96};
97
98static enum_item s_sdmmc_data_width_table[] =
99{
100 {
101 "NvBootSdmmcDataWidth_4Bit",
102 nvbct_lib_id_sdmmc_data_width_4bit
103 },
104 {
105 "NvBootSdmmcDataWidth_8Bit",
106 nvbct_lib_id_sdmmc_data_width_8bit
107 },
108 { "4Bit", nvbct_lib_id_sdmmc_data_width_4bit },
109 { "8Bit", nvbct_lib_id_sdmmc_data_width_8bit },
110 { NULL, 0 }
111};
112
113static enum_item s_spi_clock_source_table[] =
114{
115 {
116 "NvBootSpiClockSource_PllPOut0",
117 nvbct_lib_id_spi_clock_source_pllp_out0
118 },
119 {
120 "NvBootSpiClockSource_PllCOut0",
121 nvbct_lib_id_spi_clock_source_pllc_out0
122 },
123 {
124 "NvBootSpiClockSource_PllMOut0",
125 nvbct_lib_id_spi_clock_source_pllm_out0
126 },
127 {
128 "NvBootSpiClockSource_ClockM",
129 nvbct_lib_id_spi_clock_source_clockm
130 },
131
132 { "ClockSource_PllPOut0", nvbct_lib_id_spi_clock_source_pllp_out0 },
133 { "ClockSource_PllCOut0", nvbct_lib_id_spi_clock_source_pllc_out0 },
134 { "ClockSource_PllMOut0", nvbct_lib_id_spi_clock_source_pllm_out0 },
135 { "ClockSource_ClockM", nvbct_lib_id_spi_clock_source_clockm },
136
137
138 { "PllPOut0", nvbct_lib_id_spi_clock_source_pllp_out0 },
139 { "PllCOut0", nvbct_lib_id_spi_clock_source_pllc_out0 },
140 { "PllMOut0", nvbct_lib_id_spi_clock_source_pllm_out0 },
141 { "ClockM", nvbct_lib_id_spi_clock_source_clockm },
142
143 { NULL, 0 }
144};
145
Peer Chen053d5782011-03-03 10:12:58 -0800146static field_item s_nand_table[] =
147{
148 { "ClockDivider", token_clock_divider, field_type_u32, NULL },
149 /* Note: NandTiming2 must appear before NandTiming, because NandTiming
150 * is a prefix of NandTiming2 and would otherwise match first.
151 */
152 { "NandTiming2", token_nand_timing2, field_type_u32, NULL },
153 { "NandTiming", token_nand_timing, field_type_u32, NULL },
154 { "BlockSizeLog2", token_block_size_log2, field_type_u32, NULL },
155 { "PageSizeLog2", token_page_size_log2, field_type_u32, NULL },
156 { NULL, 0, 0, NULL }
157};
158
Peer Chen7557d9b2011-02-24 09:29:23 -0800159static field_item s_sdmmc_table[] =
160{
161 { "ClockDivider", token_clock_divider, field_type_u32, NULL },
162 { "DataWidth", token_data_width,
163 field_type_enum, s_sdmmc_data_width_table },
164 { "MaxPowerClassSupported", token_max_power_class_supported,
165 field_type_u32, NULL },
166
167 { NULL, 0, 0, NULL }
168};
169
170static field_item s_spiflash_table[] =
171{
172 { "ReadCommandTypeFast", token_read_command_type_fast,
173 field_type_u8, NULL },
174 { "ClockDivider", token_clock_divider, field_type_u8, NULL },
175 { "ClockSource", token_clock_source,
176 field_type_enum, s_spi_clock_source_table },
177
178 { NULL, 0, 0, NULL }
179};
180
181static parse_subfield_item s_device_type_table[] =
182{
Peer Chen053d5782011-03-03 10:12:58 -0800183 { "NandParams.", token_nand_params,
184 s_nand_table, set_nand_param },
Peer Chen7557d9b2011-02-24 09:29:23 -0800185 { "SdmmcParams.", token_sdmmc_params,
186 s_sdmmc_table, set_sdmmc_param },
187 { "SpiFlashParams.", token_spiflash_params,
188 s_spiflash_table, set_spiflash_param },
189
190 { NULL, 0, NULL }
191};
192
Peer Chen8d782ee2011-01-18 21:34:18 -0500193static parse_item s_top_level_items[] =
194{
Peer Chen053d5782011-03-03 10:12:58 -0800195 { "Bctfile=", token_bct_file, parse_bct_file },
196 { "Attribute=", token_attribute, parse_value_u32 },
197 { "Attribute[", token_attribute, parse_array },
198 { "PageSize=", token_page_size, parse_value_u32 },
199 { "BlockSize=", token_block_size, parse_value_u32 },
200 { "PartitionSize=", token_partition_size, parse_value_u32 },
201 { "DevType[", token_dev_type, parse_array },
202 { "DeviceParam[", token_dev_param, parse_dev_param },
203 { "BootLoader=", token_bootloader, parse_bootloader },
204 { "Redundancy=", token_redundancy, parse_value_u32 },
205 { "Version=", token_version, parse_value_u32 },
206 { "AddOn[", token_addon, parse_addon },
Peer Chen8d782ee2011-01-18 21:34:18 -0500207 { NULL, 0, NULL } /* Must be last */
208};
209
210/* Macro to simplify parser code a bit. */
211#define PARSE_COMMA(x) if (*rest != ',') return (x); rest++
212
213/* This parsing code was initially borrowed from nvcamera_config_parse.c. */
214/* Returns the address of the character after the parsed data. */
215static char *
216parse_u32(char *statement, u_int32_t *val)
217{
218 u_int32_t value = 0;
219
220 while (*statement=='0') {
221 statement++;
222 }
223
224 if (*statement=='x' || *statement=='X') {
225 statement++;
226 while (((*statement >= '0') && (*statement <= '9')) ||
227 ((*statement >= 'a') && (*statement <= 'f')) ||
228 ((*statement >= 'A') && (*statement <= 'F'))) {
229 value *= 16;
230 if ((*statement >= '0') && (*statement <= '9')) {
231 value += (*statement - '0');
232 } else if ((*statement >= 'A') &&
233 (*statement <= 'F')) {
234 value += ((*statement - 'A')+10);
235 } else {
236 value += ((*statement - 'a')+10);
237 }
238 statement++;
239 }
240 } else {
241 while (*statement >= '0' && *statement <= '9') {
242 value = value*10 + (*statement - '0');
243 statement++;
244 }
245 }
246 *val = value;
247 return statement;
248}
249
Peer Chen7557d9b2011-02-24 09:29:23 -0800250char *
251parse_u8(char *statement, u_int32_t *val)
252{
253 char *retval;
254
255 retval = parse_u32(statement, val);
256
257 if (*val > 0xff) {
258 printf("Warning: Parsed 8-bit value that exceeded 8-bits.\n");
259 printf(" Parsed value = %d. Remaining text = %s\n",
260 *val, retval);
261 }
262
263 return retval;
264}
265
266
Peer Chen8d782ee2011-01-18 21:34:18 -0500267/* This parsing code was initially borrowed from nvcamera_config_parse.c. */
268/* Returns the address of the character after the parsed data. */
269static char *
270parse_filename(char *statement, char *name, int chars_remaining)
271{
272 while (((*statement >= '0') && (*statement <= '9')) ||
273 ((*statement >= 'a') && (*statement <= 'z')) ||
274 ((*statement >= 'A') && (*statement <= 'Z')) ||
275 (*statement == '\\') ||
276 (*statement == '/' ) ||
277 (*statement == '~' ) ||
278 (*statement == '_' ) ||
279 (*statement == '-' ) ||
280 (*statement == '+' ) ||
281 (*statement == ':' ) ||
282 (*statement == '.' )) {
283 /* Check if the filename buffer is out of space, preserving one
284 * character to null terminate the string.
285 */
286 chars_remaining--;
287
288 if (chars_remaining < 1)
289 return NULL;
290 *name++ = *statement++;
291 }
292
293 /* Null terminate the filename. */
294 *name = '\0';
295
296 return statement;
297}
298
Peer Chen7557d9b2011-02-24 09:29:23 -0800299static char
300*parse_field_name(char *rest, field_item *field_table, field_item **field)
301{
302 u_int32_t i;
303 u_int32_t field_name_len = 0;
304
305 assert(field_table != NULL);
306 assert(rest != NULL);
307 assert(field != NULL);
308
309 while(*(rest + field_name_len) != '=')
310 field_name_len++;
311
312 /* Parse the field name. */
313 for (i = 0; field_table[i].name != NULL; i++) {
314 if ((strlen(field_table[i].name) == field_name_len) &&
315 !strncmp(field_table[i].name,
316 rest,
317 field_name_len)) {
318
319 *field = &(field_table[i]);
320 rest = rest + field_name_len;
321 return rest;
322 }
323 }
324
325 /* Field wasn't found or a parse error occurred. */
326 return NULL;
327}
328
329static char
330*parse_field_value(build_image_context *context,
331 char *rest,
332 field_item *field,
333 u_int32_t *value)
334{
335 assert(rest != NULL);
336 assert(field != NULL);
337 assert((field->type != field_type_enum)
338 || (field->enum_table != NULL));
339
340 switch (field->type) {
341 case field_type_enum:
342 rest = parse_enum(context, rest, field->enum_table, value);
343 break;
344
345 case field_type_u32:
346 rest = parse_u32(rest, value);
347 break;
348
349 case field_type_u8:
350 rest = parse_u8(rest, value);
351 break;
352
353 default:
354 printf("Unexpected field type %d at line %d\n",
355 field->type, __LINE__);
356 rest = NULL;
357 break;
358 }
359
360 return rest;
361}
362
363static char *
364parse_enum(build_image_context *context,
365 char *statement,
366 enum_item *table,
367 u_int32_t *val)
368{
369 int i;
370 char *rest;
371 int e;
372
373 for (i = 0; table[i].name != NULL; i++) {
374 if (!strncmp(table[i].name, statement,
375 strlen(table[i].name))) {
376 /* Lookup the correct value for the token. */
377 e = context->bctlib.get_value(table[i].value,
378 val, context->bct);
379 if (e) {
380 printf("Error looking up token %d.\n", table[i].value);
381 printf("\"%s\" is not valid for this chip.\n",
382 table[i].name);
383 *val = -1;
384 }
385
386 rest = statement + strlen(table[i].name);
387 return rest;
388 }
389 }
390 return parse_u32(statement, val);
391
392}
Peer Chen8d782ee2011-01-18 21:34:18 -0500393/*
394 * parse_bootloader(): Processes commands to set a bootloader.
395 */
396static int parse_bootloader(build_image_context *context,
397 parse_token token,
398 char *rest)
399{
400 char filename[MAX_BUFFER];
401 char e_state[MAX_STR_LEN];
402 u_int32_t load_addr;
403 u_int32_t entry_point;
404
405 assert(context != NULL);
406 assert(rest != NULL);
407
Peer Chen7557d9b2011-02-24 09:29:23 -0800408 if (context->generate_bct != 0)
409 return 0;
Peer Chen8d782ee2011-01-18 21:34:18 -0500410 /* Parse the file name. */
411 rest = parse_filename(rest, filename, MAX_BUFFER);
412 if (rest == NULL)
413 return 1;
414
415 PARSE_COMMA(1);
416
417 /* Parse the load address. */
418 rest = parse_u32(rest, &load_addr);
419 if (rest == NULL)
420 return 1;
421
422 PARSE_COMMA(1);
423
424 /* Parse the entry point. */
425 rest = parse_u32(rest, &entry_point);
426 if (rest == NULL)
427 return 1;
428
429 PARSE_COMMA(1);
430
431 /* Parse the end state. */
432 rest = parse_end_state(rest, e_state, MAX_STR_LEN);
433 if (rest == NULL)
434 return 1;
435 if (strncmp(e_state, "Complete", strlen("Complete")))
436 return 1;
437
438 /* Parsing has finished - set the bootloader */
439 return set_bootloader(context, filename, load_addr, entry_point);
440}
441
442/*
443 * parse_array(): Processes commands to set an array value.
444 */
445static int
446parse_array(build_image_context *context, parse_token token, char *rest)
447{
448 u_int32_t index;
449 u_int32_t value;
450
451 assert(context != NULL);
452 assert(rest != NULL);
453
454 /* Parse the index. */
455 rest = parse_u32(rest, &index);
456 if (rest == NULL)
457 return 1;
458
459 /* Parse the closing bracket. */
460 if (*rest != ']')
461 return 1;
462 rest++;
463
464 /* Parse the equals sign.*/
465 if (*rest != '=')
466 return 1;
467 rest++;
468
469 /* Parse the value based on the field table. */
470 switch(token) {
Peer Chen7557d9b2011-02-24 09:29:23 -0800471 case token_attribute:
472 rest = parse_u32(rest, &value);
473 break;
474 case token_dev_type:
475 rest = parse_enum(context, rest, s_devtype_table, &value);
476 break;
Peer Chen8d782ee2011-01-18 21:34:18 -0500477
Peer Chen7557d9b2011-02-24 09:29:23 -0800478 default:
479 /* Unknown token */
480 return 1;
Peer Chen8d782ee2011-01-18 21:34:18 -0500481 }
482
483 if (rest == NULL)
484 return 1;
485
486 /* Store the result. */
487 return context_set_array(context, index, token, value);
488}
489
490/*
491 * parse_value_u32(): General handler for setting u_int32_t values in config files.
492 */
493static int parse_value_u32(build_image_context *context,
494 parse_token token,
495 char *rest)
496{
497 u_int32_t value;
498
499 assert(context != NULL);
500 assert(rest != NULL);
501
502 rest = parse_u32(rest, &value);
503 if (rest == NULL)
504 return 1;
505
506 return context_set_value(context, token, value);
507}
508
509static int
510parse_bct_file(build_image_context *context, parse_token token, char *rest)
511{
512 char filename[MAX_BUFFER];
513
514 assert(context != NULL);
515 assert(rest != NULL);
516
517 /* Parse the file name. */
518 rest = parse_filename(rest, filename, MAX_BUFFER);
519 if (rest == NULL)
520 return 1;
521
522 /* Parsing has finished - set the bctfile */
523 context->bct_filename = filename;
524 /* Read the bct file to buffer */
525 read_bct_file(context);
526 return 0;
527}
528
529static char *
530parse_string(char *statement, char *uname, int chars_remaining)
531{
532 memset(uname, 0, chars_remaining);
533 while (((*statement >= '0') && (*statement <= '9')) ||
534 ((*statement >= 'A') && (*statement <= 'Z')) ||
535 ((*statement >= 'a') && (*statement <= 'z'))) {
536
537 *uname++ = *statement++;
538 if (--chars_remaining < 0) {
539 printf("String length beyond the boundary!!!");
540 return NULL;
541 }
542 }
543 *uname = '\0';
544 return statement;
545}
546
547static char *
548parse_end_state(char *statement, char *uname, int chars_remaining)
549{
550 while (((*statement >= 'a') && (*statement <= 'z')) ||
551 ((*statement >= 'A') && (*statement <= 'Z'))) {
552
553 *uname++ = *statement++;
554 if (--chars_remaining < 0)
555 return NULL;
556 }
557 *uname = '\0';
558 return statement;
559}
560
561
562/* Parse the addon component */
563static int
564parse_addon(build_image_context *context, parse_token token, char *rest)
565{
566 char filename[MAX_BUFFER];
567 char u_name[4];
568 char e_state[MAX_STR_LEN];
569 u_int32_t index;
570 u_int32_t item_attr;
571 u_int32_t others;
572 char other_str[MAX_STR_LEN];
573
574 assert(context != NULL);
575 assert(rest != NULL);
576
577 /* Parse the index. */
578 rest = parse_u32(rest, &index);
579 if (rest == NULL)
580 return 1;
581
582 /* Parse the closing bracket. */
583 if (*rest != ']')
584 return 1;
585 rest++;
586
587 /* Parse the equals sign.*/
588 if (*rest != '=')
589 return 1;
590 rest++;
591
592 rest = parse_filename(rest, filename, MAX_BUFFER);
593 if (rest == NULL)
594 return 1;
595 if (set_addon_filename(context, filename, index) != 0)
596 return 1;
597
598 PARSE_COMMA(1);
599
600 rest = parse_string(rest, u_name, 3);
601 if (rest == NULL) {
602 printf("Unique name should be 3 characters.\n");
603 return 1;
604 }
605 if (set_unique_name(context, u_name, index) != 0)
606 return 1;
607
608 PARSE_COMMA(1);
609
610 rest = parse_u32(rest, &item_attr);
611 if (rest == NULL)
612 return 1;
613 if (set_addon_attr(context, item_attr, index) != 0)
614 return 1;
615
616 PARSE_COMMA(1);
617
618 if (*rest == '0' && (*(rest + 1) == 'x' ||*(rest + 1) == 'X')) {
619 rest = parse_u32(rest, &others);
620 if (set_other_field(context, NULL, others, index) != 0)
621 return 1;
622 } else {
623 rest = parse_string(rest, other_str, 16);
624 if (set_other_field(context, other_str, 0, index) != 0)
625 return 1;
626 }
627 if (rest == NULL)
628 return 1;
629
630 PARSE_COMMA(1);
631
632 rest = parse_end_state(rest, e_state, MAX_STR_LEN);
633 if (rest == NULL)
634 return 1;
635 if (strncmp(e_state, "Complete", strlen("Complete")))
636 return 1;
637 return 0;
638}
639
Peer Chen7557d9b2011-02-24 09:29:23 -0800640static int
641parse_dev_param(build_image_context *context, parse_token token, char *rest)
642{
643 u_int32_t i;
644 u_int32_t value;
645 field_item *field;
646 u_int32_t index;
647 parse_subfield_item *device_item = NULL;
648
649 assert(context != NULL);
650 assert(rest != NULL);
651
652 /* Parse the index. */
653 rest = parse_u32(rest, &index);
654 if (rest == NULL)
655 return 1;
656
657 /* Parse the closing bracket. */
658 if (*rest != ']')
659 return 1;
660 rest++;
661
662 /* Parse the following '.' */
663 if (*rest != '.')
664 return 1;
665 rest++;
666
667 /* Parse the device name. */
668 for (i = 0; s_device_type_table[i].prefix != NULL; i++) {
669 if (!strncmp(s_device_type_table[i].prefix,
670 rest, strlen(s_device_type_table[i].prefix))) {
671
672 device_item = &(s_device_type_table[i]);
673 rest = rest + strlen(s_device_type_table[i].prefix);
674
675 /* Parse the field name. */
676 rest = parse_field_name(rest,
677 s_device_type_table[i].field_table,
678 &field);
679 if (rest == NULL)
680 return 1;
681
682 /* Parse the equals sign.*/
683 if (*rest != '=')
684 return 1;
685 rest++;
686
687 /* Parse the value based on the field table. */
688 rest = parse_field_value(context, rest, field, &value);
689 if (rest == NULL)
690 return 1;
691 return device_item->process(context,
692 index, field->token, value);
693 }
694 }
695
696 return 1;
697
698}
Peer Chen8d782ee2011-01-18 21:34:18 -0500699/* Return 0 on success, 1 on error */
700static int
701process_statement(build_image_context *context, char *statement)
702{
703 int i;
704 char *rest;
705
706 for (i = 0; s_top_level_items[i].prefix != NULL; i++) {
707 if (!strncmp(s_top_level_items[i].prefix, statement,
708 strlen(s_top_level_items[i].prefix))) {
709 rest = statement + strlen(s_top_level_items[i].prefix);
710
711 return s_top_level_items[i].process(context,
712 s_top_level_items[i].token,
713 rest);
714 }
715 }
716
717 /* If this point was reached, there was a processing error. */
718 return 1;
719}
720
721/* Note: Basic parsing borrowed from nvcamera_config.c */
722void process_config_file(build_image_context *context)
723{
724 char buffer[MAX_BUFFER];
725 int space = 0;
726 char current;
727 u_int8_t c_eol_comment_start = 0; // True after first slash
728 u_int8_t comment = 0;
729 u_int8_t string = 0;
730 u_int8_t equal_encounter = 0;
731
732 assert(context != NULL);
733 assert(context->config_file != NULL);
734
735 while ((current = fgetc(context->config_file)) !=EOF) {
736 if (space >= (MAX_BUFFER-1)) {
737 /* if we exceeded the max buffer size, it is likely
738 due to a missing semi-colon at the end of a line */
739 printf("Config file parsing error!");
740 exit(1);
741 }
742
743 /* Handle failure to complete "//" comment token.
744 Insert the '/' into the busffer and proceed with
745 processing the current character. */
746 if (c_eol_comment_start && current != '/') {
747 c_eol_comment_start = 0;
748 buffer[space++] = '/';
749 }
750
751 switch (current) {
752 case '\"': /* " indicates start or end of a string */
753 if (!comment) {
754 string ^= 1;
755 buffer[space++] = current;
756 }
757 break;
758 case ';':
759 if (!string && !comment) {
760 buffer[space++] = '\0';
761
762 /* Process a statement. */
763 if (process_statement(context, buffer)) {
764 goto error;
765 }
766 space = 0;
767 equal_encounter = 0;
768 } else if (string) {
769 buffer[space++] = current;
770 }
771 break;
772
773 case '/':
774 if (!string && !comment) {
775 if (c_eol_comment_start) {
776 /* EOL comment started. */
777 comment = 1;
778 c_eol_comment_start = 0;
779 } else {
780 /* Potential start of eol comment. */
781 c_eol_comment_start = 1;
782 }
783 } else if (!comment) {
784 buffer[space++] = current;
785 }
786 break;
787
788 /* ignore whitespace. uses fallthrough */
789 case '\n':
790 case '\r': /* carriage returns end comments */
791 string = 0;
792 comment = 0;
793 c_eol_comment_start = 0;
794 case ' ':
795 case '\t':
796 if (string) {
797 buffer[space++] = current;
798 }
799 break;
800
801 case '#':
802 if (!string) {
803 comment = 1;
804 } else {
805 buffer[space++] = current;
806 }
807 break;
808
809 default:
810 if (!comment) {
811 buffer[space++] = current;
812 if (current == '=') {
813 if (!equal_encounter) {
814 equal_encounter = 1;
815 } else {
816 goto error;
817 }
818 }
819 }
820 break;
821 }
822 }
823
824 return;
825
826 error:
827 printf("Error parsing: %s\n", buffer);
828 exit(1);
829}