blob: bea3b3e9ecce6a3afe0d38945ce3001136f98a09 [file] [log] [blame]
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001/*****************************************************************************\
Patrick Georgi49a74432011-01-28 07:50:33 +00002 * layout-text.c
Stefan Reinauer6540ae52007-07-12 16:35:42 +00003 *****************************************************************************
Vikram Narayanana8111cf2012-04-14 15:25:13 +05304 * Copyright (C) 2012, Vikram Narayanan
5 * Unified build_opt_tbl and nvramtool
6 * build_opt_tbl.c
7 * Copyright (C) 2003 Eric Biederman (ebiederm@xmission.com)
8 * Copyright (C) 2007-2010 coresystems GmbH
9 *
Stefan Reinauer6540ae52007-07-12 16:35:42 +000010 * Copyright (C) 2002-2005 The Regents of the University of California.
11 * Produced at the Lawrence Livermore National Laboratory.
12 * Written by Dave Peterson <dsp@llnl.gov> <dave_peterson@pobox.com>.
13 * UCRL-CODE-2003-012
14 * All rights reserved.
15 *
Uwe Hermann6e565942008-03-01 19:06:32 +000016 * This file is part of nvramtool, a utility for reading/writing coreboot
Stefan Reinauerf527e702008-01-18 15:33:49 +000017 * parameters and displaying information from the coreboot table.
Uwe Hermann6e565942008-03-01 19:06:32 +000018 * For details, see http://coreboot.org/nvramtool.
Stefan Reinauer6540ae52007-07-12 16:35:42 +000019 *
20 * Please also read the file DISCLAIMER which is included in this software
21 * distribution.
22 *
23 * This program is free software; you can redistribute it and/or modify it
24 * under the terms of the GNU General Public License (as published by the
25 * Free Software Foundation) version 2, dated June 1991.
26 *
27 * This program is distributed in the hope that it will be useful, but
28 * WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
30 * conditions of the GNU General Public License for more details.
Stefan Reinauer6540ae52007-07-12 16:35:42 +000031\*****************************************************************************/
32
33#include "common.h"
Patrick Georgi49a74432011-01-28 07:50:33 +000034#include "layout-text.h"
Stefan Reinauer6540ae52007-07-12 16:35:42 +000035#include "layout.h"
36#include "cmos_lowlevel.h"
37#include "reg_expr.h"
38
Stefan Reinauer90b96b62010-01-13 21:00:23 +000039static void process_layout_file(FILE * f);
40static void skip_past_start(FILE * f);
41static int process_entry(FILE * f, int skip_add);
42static int process_enum(FILE * f, int skip_add);
43static void process_checksum_info(FILE * f);
44static void skip_remaining_lines(FILE * f);
45static void create_entry(cmos_entry_t * cmos_entry,
46 const char start_bit_str[], const char length_str[],
47 const char config_str[], const char config_id_str[],
48 const char name_str[]);
49static void try_add_layout_file_entry(const cmos_entry_t * cmos_entry);
50static void create_enum(cmos_enum_t * cmos_enum, const char id_str[],
51 const char value_str[], const char text_str[]);
52static void try_add_cmos_enum(const cmos_enum_t * cmos_enum);
53static void set_checksum_info(const char start_str[], const char end_str[],
54 const char index_str[]);
55static char cmos_entry_char_value(cmos_entry_config_t config);
56static int get_layout_file_line(FILE * f, char line[], int line_buf_size);
57static unsigned string_to_unsigned(const char str[], const char str_name[]);
58static unsigned long string_to_unsigned_long(const char str[],
59 const char str_name[]);
60static unsigned long do_string_to_unsigned_long(const char str[],
61 const char str_name[],
62 const char blurb[]);
Stefan Reinauer6540ae52007-07-12 16:35:42 +000063
64/* matches either a blank line or a comment line */
65static const char blank_or_comment_regex[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +000066 /* a blank line */
67 "(^[[:space:]]+$)" "|" /* or ... */
68 /* a line consisting of: optional whitespace followed by */
69 "(^[[:space:]]*"
70 /* a '#' character and optionally, additional characters */
71 "#.*$)";
Stefan Reinauer6540ae52007-07-12 16:35:42 +000072
73static regex_t blank_or_comment_expr;
74
75/* matches the line in a CMOS layout file indicating the start of the
76 * "entries" section.
77 */
78static const char start_entries_regex[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +000079 /* optional whitespace */
80 "^[[:space:]]*"
81 /* followed by "entries" */
82 "entries"
83 /* followed by optional whitespace */
84 "[[:space:]]*$";
Stefan Reinauer6540ae52007-07-12 16:35:42 +000085
86static regex_t start_entries_expr;
87
88/* matches the line in a CMOS layout file indicating the start of the
89 * "enumerations" section
90 */
91static const char start_enums_regex[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +000092 /* optional whitespace */
93 "^[[:space:]]*"
94 /* followed by "enumerations" */
95 "enumerations"
96 /* followed by optional whitespace */
97 "[[:space:]]*$";
Stefan Reinauer6540ae52007-07-12 16:35:42 +000098
99static regex_t start_enums_expr;
100
101/* matches the line in a CMOS layout file indicating the start of the
102 * "checksums" section
103 */
104static const char start_checksums_regex[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000105 /* optional whitespace */
106 "^[[:space:]]*"
107 /* followed by "checksums" */
108 "checksums"
109 /* followed by optional whitespace */
110 "[[:space:]]*$";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000111
112static regex_t start_checksums_expr;
113
114/* matches a line in a CMOS layout file specifying a CMOS entry */
115static const char entries_line_regex[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000116 /* optional whitespace */
117 "^[[:space:]]*"
118 /* followed by a chunk of nonwhitespace for start-bit field */
119 "([^[:space:]]+)"
120 /* followed by one or more whitespace characters */
121 "[[:space:]]+"
122 /* followed by a chunk of nonwhitespace for length field */
123 "([^[:space:]]+)"
124 /* followed by one or more whitespace characters */
125 "[[:space:]]+"
126 /* followed by a chunk of nonwhitespace for config field */
127 "([^[:space:]]+)"
128 /* followed by one or more whitespace characters */
129 "[[:space:]]+"
130 /* followed by a chunk of nonwhitespace for config-ID field */
131 "([^[:space:]]+)"
132 /* followed by one or more whitespace characters */
133 "[[:space:]]+"
134 /* followed by a chunk of nonwhitespace for name field */
135 "([^[:space:]]+)"
136 /* followed by optional whitespace */
137 "[[:space:]]*$";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000138
139static regex_t entries_line_expr;
140
141/* matches a line in a CMOS layout file specifying a CMOS enumeration */
142static const char enums_line_regex[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000143 /* optional whitespace */
144 "^[[:space:]]*"
145 /* followed by a chunk of nonwhitespace for ID field */
146 "([^[:space:]]+)"
147 /* followed by one or more whitespace characters */
148 "[[:space:]]+"
149 /* followed by a chunk of nonwhitespace for value field */
150 "([^[:space:]]+)"
151 /* followed by one or more whitespace characters */
152 "[[:space:]]+"
153 /* followed by a chunk of nonwhitespace for text field */
Patrick Georgic3fc4b92012-04-14 16:21:39 +0200154 "([[:print:]]*[^[:space:]])"
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000155 /* followed by optional whitespace */
156 "[[:space:]]*$";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000157
158static regex_t enums_line_expr;
159
160/* matches the line in a CMOS layout file specifying CMOS checksum
161 * information
162 */
163static const char checksum_line_regex[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000164 /* optional whitespace */
165 "^[[:space:]]*"
166 /* followed by "checksum" */
167 "checksum"
168 /* followed by one or more whitespace characters */
169 "[[:space:]]+"
170 /* followed by a chunk of nonwhitespace for first bit of summed area */
171 "([^[:space:]]+)"
172 /* followed by one or more whitespace characters */
173 "[[:space:]]+"
174 /* followed by a chunk of nonwhitespace for last bit of summed area */
175 "([^[:space:]]+)"
176 /* followed by one or more whitespace characters */
177 "[[:space:]]+"
178 /* followed by a chunk of nonwhitespace for checksum location bit */
179 "([^[:space:]]+)"
180 /* followed by optional whitespace */
181 "[[:space:]]*$";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000182
183static regex_t checksum_line_expr;
184
185static const int LINE_BUF_SIZE = 256;
186
187static int line_num;
188
189static const char *layout_filename = NULL;
190
191/****************************************************************************
192 * set_layout_filename
193 *
194 * Set the name of the file we will obtain CMOS layout information from.
195 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000196void set_layout_filename(const char filename[])
197{
198 layout_filename = filename;
199}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000200
201/****************************************************************************
202 * get_layout_from_file
203 *
204 * Read CMOS layout information from the user-specified CMOS layout file.
205 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000206void get_layout_from_file(void)
207{
208 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000209
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000210 assert(layout_filename != NULL);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000211
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000212 if ((f = fopen(layout_filename, "r")) == NULL) {
213 fprintf(stderr,
214 "%s: Can not open CMOS layout file %s for reading: "
215 "%s\n", prog_name, layout_filename, strerror(errno));
216 exit(1);
217 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000218
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000219 process_layout_file(f);
220 fclose(f);
221}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000222
Vikram Narayanana8111cf2012-04-14 15:25:13 +0530223void write_cmos_layout_header(const char *header_filename)
224{
225 FILE *fp;
226 const cmos_entry_t *cmos_entry;
227 cmos_checksum_layout_t layout;
228
229 if ((fp = fopen(header_filename, "w+")) == NULL) {
230 fprintf(stderr,
231 "%s: Can't open file %s for writing: %s\n",
232 prog_name, header_filename, strerror(errno));
233 exit(1);
234 }
235
236 fprintf(fp, "/**\n * This is an autogenerated file. Do not EDIT.\n"
237 " * All changes made to this file will be lost.\n"
238 " * See mainboard's cmos.layout file.\n */\n"
239 "\n#ifndef __OPTION_TABLE_H\n"
240 "#define __OPTION_TABLE_H\n\n");
241
242 for (cmos_entry = first_cmos_entry(); cmos_entry != NULL;
243 cmos_entry = next_cmos_entry(cmos_entry)) {
244
245 if (!is_ident((char *)cmos_entry->name)) {
246 fprintf(stderr,
247 "Error - Name %s is an invalid identifier\n",
248 cmos_entry->name);
249 fclose(fp);
250 exit(1);
251 }
252
253 fprintf(fp, "#define CMOS_VSTART_%s\t%d\n",
254 cmos_entry->name, cmos_entry->bit);
255 fprintf(fp, "#define CMOS_VLEN_%s\t%d\n",
256 cmos_entry->name, cmos_entry->length);
257 }
258
259 layout.summed_area_start = cmos_checksum_start;
260 layout.summed_area_end = cmos_checksum_end;
261 layout.checksum_at = cmos_checksum_index;
262 checksum_layout_to_bits(&layout);
263
264 fprintf(fp, "\n#define LB_CKS_RANGE_START %d\n",
265 layout.summed_area_start / 8);
266 fprintf(fp, "#define LB_CKS_RANGE_END %d\n",
267 layout.summed_area_end / 8);
268 fprintf(fp, "#define LB_CKS_LOC %d\n",
269 layout.checksum_at / 8);
270 fprintf(fp, "\n#endif /* __OPTION_TABLE_H */\n");
271
272 fclose(fp);
273}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000274/****************************************************************************
275 * write_cmos_layout
276 *
277 * Write CMOS layout information to file 'f'. The output is written in the
278 * format that CMOS layout files adhere to.
279 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000280void write_cmos_layout(FILE * f)
281{
282 const cmos_entry_t *cmos_entry;
283 const cmos_enum_t *cmos_enum;
284 cmos_checksum_layout_t layout;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000285
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000286 fprintf(f, "entries\n");
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000287
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000288 for (cmos_entry = first_cmos_entry();
289 cmos_entry != NULL; cmos_entry = next_cmos_entry(cmos_entry))
290 fprintf(f, "%u %u %c %u %s\n", cmos_entry->bit,
291 cmos_entry->length,
292 cmos_entry_char_value(cmos_entry->config),
293 cmos_entry->config_id, cmos_entry->name);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000294
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000295 fprintf(f, "\nenumerations\n");
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000296
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000297 for (cmos_enum = first_cmos_enum();
298 cmos_enum != NULL; cmos_enum = next_cmos_enum(cmos_enum))
299 fprintf(f, "%u %llu %s\n", cmos_enum->config_id,
300 cmos_enum->value, cmos_enum->text);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000301
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000302 layout.summed_area_start = cmos_checksum_start;
303 layout.summed_area_end = cmos_checksum_end;
304 layout.checksum_at = cmos_checksum_index;
305 checksum_layout_to_bits(&layout);
306 fprintf(f, "\nchecksums\nchecksum %u %u %u\n", layout.summed_area_start,
307 layout.summed_area_end, layout.checksum_at);
308}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000309
310/****************************************************************************
311 * process_layout_file
312 *
313 * Read CMOS layout information from file 'f' and add it to our internal
314 * repository.
315 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000316static void process_layout_file(FILE * f)
317{
Patrick Georgibf649852011-01-28 07:40:08 +0000318 compile_reg_expr(REG_EXTENDED | REG_NEWLINE, blank_or_comment_regex, &blank_or_comment_expr);
319 compile_reg_expr(REG_EXTENDED | REG_NEWLINE, start_entries_regex, &start_entries_expr);
320 compile_reg_expr(REG_EXTENDED | REG_NEWLINE, entries_line_regex, &entries_line_expr);
321 compile_reg_expr(REG_EXTENDED | REG_NEWLINE, start_enums_regex, &start_enums_expr);
322 compile_reg_expr(REG_EXTENDED | REG_NEWLINE, enums_line_regex, &enums_line_expr);
323 compile_reg_expr(REG_EXTENDED | REG_NEWLINE, start_checksums_regex, &start_checksums_expr);
324 compile_reg_expr(REG_EXTENDED | REG_NEWLINE, checksum_line_regex, &checksum_line_expr);
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000325 line_num = 1;
326 skip_past_start(f);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000327
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000328 /* Skip past all entries. We will process these later when we
329 * make a second pass through the file.
330 */
331 while (!process_entry(f, 1)) ;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000332
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000333 /* Process all enums, adding them to our internal repository as
334 * we go. */
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000335
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000336 if (process_enum(f, 0)) {
337 fprintf(stderr, "%s: Error: CMOS layout file contains no "
338 "enumerations.\n", prog_name);
339 exit(1);
340 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000341
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000342 while (!process_enum(f, 0)) ;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000343
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000344 /* Go back to start of file. */
345 line_num = 1;
346 fseek(f, 0, SEEK_SET);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000347
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000348 skip_past_start(f);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000349
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000350 /* Process all entries, adding them to the repository as we go.
351 * We must add the entries after the enums, even though they
352 * appear in the layout file before the enums. This is because
353 * the entries are sanity checked against the enums as they are
354 * added.
355 */
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000356
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000357 if (process_entry(f, 0)) {
358 fprintf(stderr,
359 "%s: Error: CMOS layout file contains no entries.\n",
360 prog_name);
361 exit(1);
362 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000363
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000364 while (!process_entry(f, 0)) ;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000365
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000366 /* Skip past all enums. They have already been processed. */
367 while (!process_enum(f, 1)) ;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000368
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000369 /* Process CMOS checksum info. */
370 process_checksum_info(f);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000371
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000372 /* See if there are any lines left to process. If so, verify
373 * that they are all either blank lines or comments.
374 */
375 skip_remaining_lines(f);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000376
Patrick Georgibf649852011-01-28 07:40:08 +0000377 regfree(&blank_or_comment_expr);
378 regfree(&start_entries_expr);
379 regfree(&entries_line_expr);
380 regfree(&start_enums_expr);
381 regfree(&enums_line_expr);
382 regfree(&start_checksums_expr);
383 regfree(&checksum_line_expr);
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000384}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000385
386/****************************************************************************
387 * skip_past_start
388 *
389 * Skip past the line that marks the start of the "entries" section.
390 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000391static void skip_past_start(FILE * f)
392{
393 char line[LINE_BUF_SIZE];
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000394
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000395 for (;; line_num++) {
396 if (get_layout_file_line(f, line, LINE_BUF_SIZE)) {
397 fprintf(stderr,
398 "%s: \"entries\" line not found in CMOS layout file.\n",
399 prog_name);
400 exit(1);
401 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000402
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000403 if (!regexec(&blank_or_comment_expr, line, 0, NULL, 0))
404 continue;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000405
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000406 if (!regexec(&start_entries_expr, line, 0, NULL, 0))
407 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000408
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000409 fprintf(stderr,
410 "%s: Syntax error on line %d of CMOS layout file. "
411 "\"entries\" line expected.\n", prog_name, line_num);
412 exit(1);
413 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000414
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000415 line_num++;
416}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000417
418/****************************************************************************
419 * process_entry
420 *
421 * Get an entry from "entries" section of file and add it to our repository
422 * of layout information. Return 0 if an entry was found and processed.
423 * Return 1 if there are no more entries.
424 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000425static int process_entry(FILE * f, int skip_add)
426{
427 static const size_t N_MATCHES = 6;
428 char line[LINE_BUF_SIZE];
429 regmatch_t match[N_MATCHES];
430 cmos_entry_t cmos_entry;
431 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000432
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000433 result = 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000434
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000435 for (;; line_num++) {
436 if (get_layout_file_line(f, line, LINE_BUF_SIZE)) {
437 fprintf(stderr,
438 "%s: Unexpected end of CMOS layout file reached while "
439 "reading \"entries\" section.\n", prog_name);
440 exit(1);
441 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000442
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000443 if (!regexec(&blank_or_comment_expr, line, 0, NULL, 0))
444 continue;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000445
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000446 if (regexec(&entries_line_expr, line, N_MATCHES, match, 0)) {
447 if (regexec(&start_enums_expr, line, 0, NULL, 0)) {
448 fprintf(stderr,
449 "%s: Syntax error on line %d of CMOS layout "
450 "file.\n", prog_name, line_num);
451 exit(1);
452 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000453
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000454 break; /* start of enumerations reached: no more entries */
455 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000456
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000457 result = 0; /* next layout entry found */
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000458
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000459 if (skip_add)
460 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000461
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000462 line[match[1].rm_eo] = '\0';
463 line[match[2].rm_eo] = '\0';
464 line[match[3].rm_eo] = '\0';
465 line[match[4].rm_eo] = '\0';
466 line[match[5].rm_eo] = '\0';
467 create_entry(&cmos_entry, &line[match[1].rm_so],
468 &line[match[2].rm_so], &line[match[3].rm_so],
469 &line[match[4].rm_so], &line[match[5].rm_so]);
470 try_add_layout_file_entry(&cmos_entry);
471 break;
472 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000473
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000474 line_num++;
475 return result;
476}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000477
478/****************************************************************************
479 * process_enum
480 *
481 * Get an enuneration from "enumerations" section of file and add it to our
482 * repository of layout information. Return 0 if an enumeration was found
483 * and processed. Return 1 if there are no more enumerations.
484 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000485static int process_enum(FILE * f, int skip_add)
486{
487 static const size_t N_MATCHES = 4;
488 char line[LINE_BUF_SIZE];
489 regmatch_t match[N_MATCHES];
490 cmos_enum_t cmos_enum;
491 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000492
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000493 result = 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000494
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000495 for (;; line_num++) {
496 if (get_layout_file_line(f, line, LINE_BUF_SIZE)) {
497 fprintf(stderr,
498 "%s: Unexpected end of CMOS layout file reached while "
499 "reading \"enumerations\" section.\n",
500 prog_name);
501 exit(1);
502 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000503
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000504 if (!regexec(&blank_or_comment_expr, line, 0, NULL, 0))
505 continue;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000506
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000507 if (regexec(&enums_line_expr, line, N_MATCHES, match, 0)) {
508 if (regexec(&start_checksums_expr, line, 0, NULL, 0)) {
509 fprintf(stderr,
510 "%s: Syntax error on line %d of CMOS layout "
511 "file.\n", prog_name, line_num);
512 exit(1);
513 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000514
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000515 break; /* start of checksums reached: no more enumerations */
516 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000517
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000518 result = 0; /* next layout enumeration found */
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000519
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000520 if (skip_add)
521 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000522
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000523 line[match[1].rm_eo] = '\0';
524 line[match[2].rm_eo] = '\0';
525 line[match[3].rm_eo] = '\0';
526 create_enum(&cmos_enum, &line[match[1].rm_so],
527 &line[match[2].rm_so], &line[match[3].rm_so]);
528 try_add_cmos_enum(&cmos_enum);
529 break;
530 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000531
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000532 line_num++;
533 return result;
534}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000535
536/****************************************************************************
537 * process_checksum_info
538 *
539 * Get line conatining CMOS checksum information.
540 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000541static void process_checksum_info(FILE * f)
542{
543 static const size_t N_MATCHES = 4;
544 char line[LINE_BUF_SIZE];
545 regmatch_t match[N_MATCHES];
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000546
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000547 for (;; line_num++) {
548 if (get_layout_file_line(f, line, LINE_BUF_SIZE)) {
549 fprintf(stderr,
550 "%s: Unexpected end of CMOS layout file reached while "
551 "reading \"checksums\" section.\n", prog_name);
552 exit(1);
553 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000554
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000555 if (!regexec(&blank_or_comment_expr, line, 0, NULL, 0))
556 continue;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000557
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000558 if (regexec(&checksum_line_expr, line, N_MATCHES, match, 0)) {
559 fprintf(stderr,
560 "%s: Syntax error on line %d of CMOS layout "
561 "file. \"checksum\" line expected.\n",
562 prog_name, line_num);
563 exit(1);
564 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000565
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000566 /* checksum line found */
567 line[match[1].rm_eo] = '\0';
568 line[match[2].rm_eo] = '\0';
569 line[match[3].rm_eo] = '\0';
570 set_checksum_info(&line[match[1].rm_so], &line[match[2].rm_so],
571 &line[match[3].rm_so]);
572 break;
573 }
574}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000575
576/****************************************************************************
577 * skip_remaining_lines
578 *
579 * Get any remaining lines of unprocessed input. Complain if we find a line
580 * that contains anything other than comments and whitespace.
581 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000582static void skip_remaining_lines(FILE * f)
583{
584 char line[LINE_BUF_SIZE];
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000585
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000586 for (line_num++;
587 get_layout_file_line(f, line, LINE_BUF_SIZE) == OK; line_num++) {
588 if (regexec(&blank_or_comment_expr, line, 0, NULL, 0)) {
589 fprintf(stderr,
590 "%s: Syntax error on line %d of CMOS layout file: "
591 "Only comments and/or whitespace allowed after "
592 "\"checksum\" line.\n", prog_name, line_num);
593 exit(1);
594 }
595 }
596}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000597
598/****************************************************************************
599 * create_entry
600 *
601 * Create a CMOS entry structure representing the given information. Perform
602 * sanity checking on input parameters.
603 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000604static void create_entry(cmos_entry_t * cmos_entry,
605 const char start_bit_str[], const char length_str[],
606 const char config_str[], const char config_id_str[],
607 const char name_str[])
608{
609 cmos_entry->bit = string_to_unsigned(start_bit_str, "start-bit");
610 cmos_entry->length = string_to_unsigned(length_str, "length");
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000611
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000612 if (config_str[1] != '\0')
613 goto bad_config_str;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000614
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000615 switch (config_str[0]) {
616 case 'e':
617 cmos_entry->config = CMOS_ENTRY_ENUM;
618 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000619
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000620 case 'h':
621 cmos_entry->config = CMOS_ENTRY_HEX;
622 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000623
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000624 case 's':
625 cmos_entry->config = CMOS_ENTRY_STRING;
626 break;
Stefan Reinauera67aab72008-09-27 10:08:28 +0000627
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000628 case 'r':
629 cmos_entry->config = CMOS_ENTRY_RESERVED;
630 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000631
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000632 default:
633 goto bad_config_str;
634 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000635
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000636 cmos_entry->config_id = string_to_unsigned(config_id_str, "config-ID");
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000637
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000638 if (strlen(name_str) >= CMOS_MAX_NAME_LENGTH) {
639 fprintf(stderr,
640 "%s: Error on line %d of CMOS layout file: name too "
641 "long (max length is %d).\n", prog_name, line_num,
642 CMOS_MAX_NAME_LENGTH - 1);
643 exit(1);
644 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000645
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000646 strcpy(cmos_entry->name, name_str);
647 return;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000648
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000649 bad_config_str:
650 fprintf(stderr,
651 "%s: Error on line %d of CMOS layout file: 'e', 'h', or "
652 "'r' expected for config value.\n", prog_name, line_num);
653 exit(1);
654}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000655
656/****************************************************************************
657 * try_add_layout_file_entry
658 *
659 * Attempt to add the given CMOS entry to our internal repository. Exit with
660 * an error message on failure.
661 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000662static void try_add_layout_file_entry(const cmos_entry_t * cmos_entry)
663{
664 const cmos_entry_t *conflict;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000665
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000666 switch (add_cmos_entry(cmos_entry, &conflict)) {
667 case OK:
668 return;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000669
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000670 case CMOS_AREA_OUT_OF_RANGE:
671 fprintf(stderr,
672 "%s: Error on line %d of CMOS layout file. Area "
673 "covered by entry %s is out of range.\n", prog_name,
674 line_num, cmos_entry->name);
675 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000676
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000677 case CMOS_AREA_TOO_WIDE:
678 fprintf(stderr,
679 "%s: Error on line %d of CMOS layout file. Area "
680 "covered by entry %s is too wide.\n", prog_name,
681 line_num, cmos_entry->name);
682 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000683
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000684 case LAYOUT_ENTRY_OVERLAP:
685 fprintf(stderr,
686 "%s: Error on line %d of CMOS layout file. Layouts "
687 "overlap for entries %s and %s.\n", prog_name, line_num,
688 cmos_entry->name, conflict->name);
689 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000690
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000691 case LAYOUT_ENTRY_BAD_LENGTH:
692 /* Silently ignore entries with zero length. Although this should
693 * never happen in practice, we should handle the case in a
694 * reasonable manner just to be safe.
695 */
696 return;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000697
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000698 default:
699 BUG();
700 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000701
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000702 exit(1);
703}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000704
705/****************************************************************************
706 * create_enum
707 *
708 * Create a CMOS enumeration structure representing the given information.
709 * Perform sanity checking on input parameters.
710 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000711static void create_enum(cmos_enum_t * cmos_enum, const char id_str[],
712 const char value_str[], const char text_str[])
713{
714 cmos_enum->config_id = string_to_unsigned(id_str, "ID");
715 cmos_enum->value = string_to_unsigned_long(value_str, "value");
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000716
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000717 if (strlen(text_str) >= CMOS_MAX_TEXT_LENGTH) {
718 fprintf(stderr,
719 "%s: Error on line %d of CMOS layout file: text too "
720 "long (max length is %d).\n", prog_name, line_num,
721 CMOS_MAX_TEXT_LENGTH - 1);
722 exit(1);
723 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000724
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000725 strcpy(cmos_enum->text, text_str);
726}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000727
728/****************************************************************************
729 * try_add_cmos_enum
730 *
731 * Attempt to add the given CMOS enum to our internal repository. Exit with
732 * an error message on failure.
733 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000734static void try_add_cmos_enum(const cmos_enum_t * cmos_enum)
735{
736 switch (add_cmos_enum(cmos_enum)) {
737 case OK:
738 return;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000739
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000740 case LAYOUT_DUPLICATE_ENUM:
741 fprintf(stderr, "%s: Error on line %d of CMOS layout file: "
742 "Enumeration found with duplicate ID/value combination.\n",
743 prog_name, line_num);
744 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000745
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000746 default:
747 BUG();
748 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000749
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000750 exit(1);
751}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000752
753/****************************************************************************
754 * set_checksum_info
755 *
756 * Set CMOS checksum information according to input parameters and perform
757 * sanity checking on input parameters.
758 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000759static void set_checksum_info(const char start_str[], const char end_str[],
760 const char index_str[])
761{
762 cmos_checksum_layout_t layout;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000763
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000764 /* These are bit positions that we want to convert to byte positions. */
765 layout.summed_area_start =
766 string_to_unsigned(start_str, "CMOS checksummed area start");
767 layout.summed_area_end =
768 string_to_unsigned(end_str, "CMOS checksummed area end");
769 layout.checksum_at =
770 string_to_unsigned(index_str, "CMOS checksum location");
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000771
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000772 switch (checksum_layout_to_bytes(&layout)) {
773 case OK:
774 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000775
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000776 case LAYOUT_SUMMED_AREA_START_NOT_ALIGNED:
777 fprintf(stderr,
778 "%s: Error on line %d of CMOS layout file. CMOS "
779 "checksummed area start is not byte-aligned.\n",
780 prog_name, line_num);
781 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000782
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000783 case LAYOUT_SUMMED_AREA_END_NOT_ALIGNED:
784 fprintf(stderr,
785 "%s: Error on line %d of CMOS layout file. CMOS "
786 "checksummed area end is not byte-aligned.\n",
787 prog_name, line_num);
788 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000789
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000790 case LAYOUT_CHECKSUM_LOCATION_NOT_ALIGNED:
791 fprintf(stderr,
792 "%s: Error on line %d of CMOS layout file. CMOS "
793 "checksum location is not byte-aligned.\n", prog_name,
794 line_num);
795 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000796
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000797 case LAYOUT_INVALID_SUMMED_AREA:
798 fprintf(stderr,
799 "%s: Error on line %d of CMOS layout file. CMOS "
800 "checksummed area end must be greater than CMOS checksummed "
801 "area start.\n", prog_name, line_num);
802 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000803
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000804 case LAYOUT_CHECKSUM_OVERLAPS_SUMMED_AREA:
805 fprintf(stderr,
806 "%s: Error on line %d of CMOS layout file. CMOS "
807 "checksum overlaps checksummed area.\n", prog_name,
808 line_num);
809 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000810
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000811 case LAYOUT_SUMMED_AREA_OUT_OF_RANGE:
812 fprintf(stderr,
813 "%s: Error on line %d of CMOS layout file. CMOS "
814 "checksummed area out of range.\n", prog_name,
815 line_num);
816 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000817
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000818 case LAYOUT_CHECKSUM_LOCATION_OUT_OF_RANGE:
819 fprintf(stderr,
820 "%s: Error on line %d of CMOS layout file. CMOS "
821 "checksum location out of range.\n", prog_name,
822 line_num);
823 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000824
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000825 default:
826 BUG();
827 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000828
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000829 cmos_checksum_start = layout.summed_area_start;
830 cmos_checksum_end = layout.summed_area_end;
831 cmos_checksum_index = layout.checksum_at;
832 return;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000833
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000834 fail:
835 exit(1);
836}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000837
838/****************************************************************************
839 * cmos_entry_char_value
840 *
841 * Return the character representation of 'config'.
842 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000843static char cmos_entry_char_value(cmos_entry_config_t config)
844{
845 switch (config) {
846 case CMOS_ENTRY_ENUM:
847 return 'e';
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000848
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000849 case CMOS_ENTRY_HEX:
850 return 'h';
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000851
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000852 case CMOS_ENTRY_RESERVED:
853 return 'r';
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000854
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000855 case CMOS_ENTRY_STRING:
856 return 's';
Stefan Reinauera67aab72008-09-27 10:08:28 +0000857
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000858 default:
859 BUG();
860 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000861
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000862 return 0; /* not reached */
863}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000864
865/****************************************************************************
866 * get_layout_file_line
867 *
868 * Get a line of input from file 'f'. Store result in 'line' which is an
869 * array of 'line_buf_size' bytes. Return OK on success or an error code on
870 * failure.
871 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000872static int get_layout_file_line(FILE * f, char line[], int line_buf_size)
873{
874 switch (get_line_from_file(f, line, line_buf_size)) {
875 case OK:
876 return OK;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000877
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000878 case LINE_EOF:
879 return LINE_EOF;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000880
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000881 case LINE_TOO_LONG:
882 fprintf(stderr,
883 "%s: Error on line %d of CMOS layout file: Maximum "
884 "line length exceeded. Max is %d characters.\n",
885 prog_name, line_num, line_buf_size - 2);
886 break;
887 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000888
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000889 exit(1);
890 return 1; /* keep compiler happy */
891}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000892
893/****************************************************************************
894 * string_to_unsigned
895 *
896 * Convert the string 'str' to an unsigned and return the result.
897 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000898static unsigned string_to_unsigned(const char str[], const char str_name[])
899{
900 unsigned long n;
901 unsigned z;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000902
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000903 n = do_string_to_unsigned_long(str, str_name, "");
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000904
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000905 if ((z = (unsigned)n) != n) {
906 /* This could happen on an architecture in which
907 * sizeof(unsigned) < sizeof(unsigned long).
908 */
909 fprintf(stderr,
910 "%s: Error on line %d of CMOS layout file: %s value is "
911 "out of range.\n", prog_name, line_num, str_name);
912 exit(1);
913 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000914
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000915 return z;
916}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000917
918/****************************************************************************
919 * string_to_unsigned_long
920 *
921 * Convert the string 'str' to an unsigned long and return the result.
922 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000923static unsigned long string_to_unsigned_long(const char str[],
924 const char str_name[])
925{
926 return do_string_to_unsigned_long(str, str_name, " long");
927}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000928
929/****************************************************************************
930 * do_string_to_unsigned_long
931 *
932 * Convert the string 'str' to an unsigned long and return the result. Exit
933 * with an appropriate error message on failure.
934 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000935static unsigned long do_string_to_unsigned_long(const char str[],
936 const char str_name[],
937 const char blurb[])
938{
939 unsigned long n;
940 char *p;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000941
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000942 n = strtoul(str, &p, 0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000943
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000944 if (*p != '\0') {
945 fprintf(stderr,
946 "%s: Error on line %d of CMOS layout file: %s is not a "
947 "valid unsigned%s integer.\n", prog_name, line_num,
948 str_name, blurb);
949 exit(1);
950 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000951
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000952 return n;
953}