1 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include "layout-text.h"
6 #include "cmos_lowlevel.h"
9 static void process_layout_file(FILE * f
);
10 static void skip_past_start(FILE * f
);
11 static int process_entry(FILE * f
, int skip_add
);
12 static int process_enum(FILE * f
, int skip_add
);
13 static void process_checksum_info(FILE * f
);
14 static void skip_remaining_lines(FILE * f
);
15 static void create_entry(cmos_entry_t
* cmos_entry
,
16 const char start_bit_str
[], const char length_str
[],
17 const char config_str
[], const char config_id_str
[],
18 const char name_str
[]);
19 static void try_add_layout_file_entry(const cmos_entry_t
* cmos_entry
);
20 static void create_enum(cmos_enum_t
* cmos_enum
, const char id_str
[],
21 const char value_str
[], const char text_str
[]);
22 static void try_add_cmos_enum(const cmos_enum_t
* cmos_enum
);
23 static void set_checksum_info(const char start_str
[], const char end_str
[],
24 const char index_str
[]);
25 static char cmos_entry_char_value(cmos_entry_config_t config
);
26 static int get_layout_file_line(FILE * f
, char line
[], int line_buf_size
);
27 static unsigned string_to_unsigned(const char str
[], const char str_name
[]);
28 static unsigned long string_to_unsigned_long(const char str
[],
29 const char str_name
[]);
30 static unsigned long do_string_to_unsigned_long(const char str
[],
31 const char str_name
[],
34 /* matches either a blank line or a comment line */
35 static const char blank_or_comment_regex
[] =
37 "(^[[:space:]]+$)" "|" /* or ... */
38 /* a line consisting of: optional whitespace followed by */
40 /* a '#' character and optionally, additional characters */
43 static regex_t blank_or_comment_expr
;
45 /* matches the line in a CMOS layout file indicating the start of the
48 static const char start_entries_regex
[] =
49 /* optional whitespace */
51 /* followed by "entries" */
53 /* followed by optional whitespace */
56 static regex_t start_entries_expr
;
58 /* matches the line in a CMOS layout file indicating the start of the
59 * "enumerations" section
61 static const char start_enums_regex
[] =
62 /* optional whitespace */
64 /* followed by "enumerations" */
66 /* followed by optional whitespace */
69 static regex_t start_enums_expr
;
71 /* matches the line in a CMOS layout file indicating the start of the
74 static const char start_checksums_regex
[] =
75 /* optional whitespace */
77 /* followed by "checksums" */
79 /* followed by optional whitespace */
82 static regex_t start_checksums_expr
;
84 /* matches a line in a CMOS layout file specifying a CMOS entry */
85 static const char entries_line_regex
[] =
86 /* optional whitespace */
88 /* followed by a chunk of nonwhitespace for start-bit field */
90 /* followed by one or more whitespace characters */
92 /* followed by a chunk of nonwhitespace for length field */
94 /* followed by one or more whitespace characters */
96 /* followed by a chunk of nonwhitespace for config field */
98 /* followed by one or more whitespace characters */
100 /* followed by a chunk of nonwhitespace for config-ID field */
102 /* followed by one or more whitespace characters */
104 /* followed by a chunk of nonwhitespace for name field */
106 /* followed by optional whitespace */
109 static regex_t entries_line_expr
;
111 /* matches a line in a CMOS layout file specifying a CMOS enumeration */
112 static const char enums_line_regex
[] =
113 /* optional whitespace */
115 /* followed by a chunk of nonwhitespace for ID field */
117 /* followed by one or more whitespace characters */
119 /* followed by a chunk of nonwhitespace for value field */
121 /* followed by one or more whitespace characters */
123 /* followed by a chunk of nonwhitespace for text field */
124 "([[:print:]]*[^[:space:]])"
125 /* followed by optional whitespace */
128 static regex_t enums_line_expr
;
130 /* matches the line in a CMOS layout file specifying CMOS checksum
133 static const char checksum_line_regex
[] =
134 /* optional whitespace */
136 /* followed by "checksum" */
138 /* followed by one or more whitespace characters */
140 /* followed by a chunk of nonwhitespace for first bit of summed area */
142 /* followed by one or more whitespace characters */
144 /* followed by a chunk of nonwhitespace for last bit of summed area */
146 /* followed by one or more whitespace characters */
148 /* followed by a chunk of nonwhitespace for checksum location bit */
150 /* followed by optional whitespace */
153 static regex_t checksum_line_expr
;
155 static const int LINE_BUF_SIZE
= 256;
159 static const char *layout_filename
= NULL
;
161 /****************************************************************************
162 * set_layout_filename
164 * Set the name of the file we will obtain CMOS layout information from.
165 ****************************************************************************/
166 void set_layout_filename(const char filename
[])
168 layout_filename
= filename
;
171 /****************************************************************************
172 * get_layout_from_file
174 * Read CMOS layout information from the user-specified CMOS layout file.
175 ****************************************************************************/
176 void get_layout_from_file(void)
180 assert(layout_filename
!= NULL
);
182 if ((f
= fopen(layout_filename
, "r")) == NULL
) {
184 "%s: Can not open CMOS layout file %s for reading: "
185 "%s\n", prog_name
, layout_filename
, strerror(errno
));
189 process_layout_file(f
);
193 void write_cmos_layout_header(const char *header_filename
)
196 const cmos_entry_t
*cmos_entry
;
197 cmos_checksum_layout_t layout
;
199 if ((fp
= fopen(header_filename
, "w+")) == NULL
) {
201 "%s: Can't open file %s for writing: %s\n",
202 prog_name
, header_filename
, strerror(errno
));
206 fprintf(fp
, "/**\n * This is an autogenerated file. Do not EDIT.\n"
207 " * All changes made to this file will be lost.\n"
208 " * See mainboard's cmos.layout file.\n */\n"
209 "\n#ifndef __OPTION_TABLE_H\n"
210 "#define __OPTION_TABLE_H\n\n");
212 for (cmos_entry
= first_cmos_entry(); cmos_entry
!= NULL
;
213 cmos_entry
= next_cmos_entry(cmos_entry
)) {
215 if (!is_ident((char *)cmos_entry
->name
)) {
217 "Error - Name %s is an invalid identifier\n",
223 fprintf(fp
, "#define CMOS_VSTART_%s\t%d\n",
224 cmos_entry
->name
, cmos_entry
->bit
);
225 fprintf(fp
, "#define CMOS_VLEN_%s\t%d\n",
226 cmos_entry
->name
, cmos_entry
->length
);
229 layout
.summed_area_start
= cmos_checksum_start
;
230 layout
.summed_area_end
= cmos_checksum_end
;
231 layout
.checksum_at
= cmos_checksum_index
;
232 checksum_layout_to_bits(&layout
);
234 fprintf(fp
, "\n#define LB_CKS_RANGE_START %d\n",
235 layout
.summed_area_start
/ 8);
236 fprintf(fp
, "#define LB_CKS_RANGE_END %d\n",
237 layout
.summed_area_end
/ 8);
238 fprintf(fp
, "#define LB_CKS_LOC %d\n",
239 layout
.checksum_at
/ 8);
240 fprintf(fp
, "\n#endif /* __OPTION_TABLE_H */\n");
244 /****************************************************************************
247 * Write CMOS layout information to file 'f'. The output is written in the
248 * format that CMOS layout files adhere to.
249 ****************************************************************************/
250 void write_cmos_layout(FILE * f
)
252 const cmos_entry_t
*cmos_entry
;
253 const cmos_enum_t
*cmos_enum
;
254 cmos_checksum_layout_t layout
;
256 fprintf(f
, "entries\n");
258 for (cmos_entry
= first_cmos_entry();
259 cmos_entry
!= NULL
; cmos_entry
= next_cmos_entry(cmos_entry
))
260 fprintf(f
, "%u %u %c %u %s\n", cmos_entry
->bit
,
262 cmos_entry_char_value(cmos_entry
->config
),
263 cmos_entry
->config_id
, cmos_entry
->name
);
265 fprintf(f
, "\nenumerations\n");
267 for (cmos_enum
= first_cmos_enum();
268 cmos_enum
!= NULL
; cmos_enum
= next_cmos_enum(cmos_enum
))
269 fprintf(f
, "%u %llu %s\n", cmos_enum
->config_id
,
270 cmos_enum
->value
, cmos_enum
->text
);
272 layout
.summed_area_start
= cmos_checksum_start
;
273 layout
.summed_area_end
= cmos_checksum_end
;
274 layout
.checksum_at
= cmos_checksum_index
;
275 checksum_layout_to_bits(&layout
);
276 fprintf(f
, "\nchecksums\nchecksum %u %u %u\n", layout
.summed_area_start
,
277 layout
.summed_area_end
, layout
.checksum_at
);
280 /****************************************************************************
281 * process_layout_file
283 * Read CMOS layout information from file 'f' and add it to our internal
285 ****************************************************************************/
286 static void process_layout_file(FILE * f
)
288 compile_reg_expr(REG_EXTENDED
| REG_NEWLINE
, blank_or_comment_regex
, &blank_or_comment_expr
);
289 compile_reg_expr(REG_EXTENDED
| REG_NEWLINE
, start_entries_regex
, &start_entries_expr
);
290 compile_reg_expr(REG_EXTENDED
| REG_NEWLINE
, entries_line_regex
, &entries_line_expr
);
291 compile_reg_expr(REG_EXTENDED
| REG_NEWLINE
, start_enums_regex
, &start_enums_expr
);
292 compile_reg_expr(REG_EXTENDED
| REG_NEWLINE
, enums_line_regex
, &enums_line_expr
);
293 compile_reg_expr(REG_EXTENDED
| REG_NEWLINE
, start_checksums_regex
, &start_checksums_expr
);
294 compile_reg_expr(REG_EXTENDED
| REG_NEWLINE
, checksum_line_regex
, &checksum_line_expr
);
298 /* Skip past all entries. We will process these later when we
299 * make a second pass through the file.
301 while (!process_entry(f
, 1)) ;
303 /* Process all enums, adding them to our internal repository as
306 if (process_enum(f
, 0)) {
307 fprintf(stderr
, "%s: Error: CMOS layout file contains no "
308 "enumerations.\n", prog_name
);
312 while (!process_enum(f
, 0)) ;
314 /* Go back to start of file. */
316 fseek(f
, 0, SEEK_SET
);
320 /* Process all entries, adding them to the repository as we go.
321 * We must add the entries after the enums, even though they
322 * appear in the layout file before the enums. This is because
323 * the entries are sanity checked against the enums as they are
327 if (process_entry(f
, 0)) {
329 "%s: Error: CMOS layout file contains no entries.\n",
334 while (!process_entry(f
, 0)) ;
336 /* Skip past all enums. They have already been processed. */
337 while (!process_enum(f
, 1)) ;
339 /* Process CMOS checksum info. */
340 process_checksum_info(f
);
342 /* See if there are any lines left to process. If so, verify
343 * that they are all either blank lines or comments.
345 skip_remaining_lines(f
);
347 regfree(&blank_or_comment_expr
);
348 regfree(&start_entries_expr
);
349 regfree(&entries_line_expr
);
350 regfree(&start_enums_expr
);
351 regfree(&enums_line_expr
);
352 regfree(&start_checksums_expr
);
353 regfree(&checksum_line_expr
);
356 /****************************************************************************
359 * Skip past the line that marks the start of the "entries" section.
360 ****************************************************************************/
361 static void skip_past_start(FILE * f
)
363 char line
[LINE_BUF_SIZE
];
365 for (;; line_num
++) {
366 if (get_layout_file_line(f
, line
, LINE_BUF_SIZE
)) {
368 "%s: \"entries\" line not found in CMOS layout file.\n",
373 if (!regexec(&blank_or_comment_expr
, line
, 0, NULL
, 0))
376 if (!regexec(&start_entries_expr
, line
, 0, NULL
, 0))
380 "%s: Syntax error on line %d of CMOS layout file. "
381 "\"entries\" line expected.\n", prog_name
, line_num
);
388 /****************************************************************************
391 * Get an entry from "entries" section of file and add it to our repository
392 * of layout information. Return 0 if an entry was found and processed.
393 * Return 1 if there are no more entries.
394 ****************************************************************************/
395 static int process_entry(FILE * f
, int skip_add
)
397 static const size_t N_MATCHES
= 6;
398 char line
[LINE_BUF_SIZE
];
399 regmatch_t match
[N_MATCHES
];
400 cmos_entry_t cmos_entry
;
405 for (;; line_num
++) {
406 if (get_layout_file_line(f
, line
, LINE_BUF_SIZE
)) {
408 "%s: Unexpected end of CMOS layout file reached while "
409 "reading \"entries\" section.\n", prog_name
);
413 if (!regexec(&blank_or_comment_expr
, line
, 0, NULL
, 0))
416 if (regexec(&entries_line_expr
, line
, N_MATCHES
, match
, 0)) {
417 if (regexec(&start_enums_expr
, line
, 0, NULL
, 0)) {
419 "%s: Syntax error on line %d of CMOS layout "
420 "file.\n", prog_name
, line_num
);
424 break; /* start of enumerations reached: no more entries */
427 result
= 0; /* next layout entry found */
432 line
[match
[1].rm_eo
] = '\0';
433 line
[match
[2].rm_eo
] = '\0';
434 line
[match
[3].rm_eo
] = '\0';
435 line
[match
[4].rm_eo
] = '\0';
436 line
[match
[5].rm_eo
] = '\0';
437 create_entry(&cmos_entry
, &line
[match
[1].rm_so
],
438 &line
[match
[2].rm_so
], &line
[match
[3].rm_so
],
439 &line
[match
[4].rm_so
], &line
[match
[5].rm_so
]);
440 try_add_layout_file_entry(&cmos_entry
);
448 /****************************************************************************
451 * Get an enuneration from "enumerations" section of file and add it to our
452 * repository of layout information. Return 0 if an enumeration was found
453 * and processed. Return 1 if there are no more enumerations.
454 ****************************************************************************/
455 static int process_enum(FILE * f
, int skip_add
)
457 static const size_t N_MATCHES
= 4;
458 char line
[LINE_BUF_SIZE
];
459 regmatch_t match
[N_MATCHES
];
460 cmos_enum_t cmos_enum
;
465 for (;; line_num
++) {
466 if (get_layout_file_line(f
, line
, LINE_BUF_SIZE
)) {
468 "%s: Unexpected end of CMOS layout file reached while "
469 "reading \"enumerations\" section.\n",
474 if (!regexec(&blank_or_comment_expr
, line
, 0, NULL
, 0))
477 if (regexec(&enums_line_expr
, line
, N_MATCHES
, match
, 0)) {
478 if (regexec(&start_checksums_expr
, line
, 0, NULL
, 0)) {
480 "%s: Syntax error on line %d of CMOS layout "
481 "file.\n", prog_name
, line_num
);
485 break; /* start of checksums reached: no more enumerations */
488 result
= 0; /* next layout enumeration found */
493 line
[match
[1].rm_eo
] = '\0';
494 line
[match
[2].rm_eo
] = '\0';
495 line
[match
[3].rm_eo
] = '\0';
496 create_enum(&cmos_enum
, &line
[match
[1].rm_so
],
497 &line
[match
[2].rm_so
], &line
[match
[3].rm_so
]);
498 try_add_cmos_enum(&cmos_enum
);
506 /****************************************************************************
507 * process_checksum_info
509 * Get line containing CMOS checksum information.
510 ****************************************************************************/
511 static void process_checksum_info(FILE * f
)
513 static const size_t N_MATCHES
= 4;
514 char line
[LINE_BUF_SIZE
];
515 regmatch_t match
[N_MATCHES
];
517 for (;; line_num
++) {
518 if (get_layout_file_line(f
, line
, LINE_BUF_SIZE
)) {
520 "%s: Unexpected end of CMOS layout file reached while "
521 "reading \"checksums\" section.\n", prog_name
);
525 if (!regexec(&blank_or_comment_expr
, line
, 0, NULL
, 0))
528 if (regexec(&checksum_line_expr
, line
, N_MATCHES
, match
, 0)) {
530 "%s: Syntax error on line %d of CMOS layout "
531 "file. \"checksum\" line expected.\n",
532 prog_name
, line_num
);
536 /* checksum line found */
537 line
[match
[1].rm_eo
] = '\0';
538 line
[match
[2].rm_eo
] = '\0';
539 line
[match
[3].rm_eo
] = '\0';
540 set_checksum_info(&line
[match
[1].rm_so
], &line
[match
[2].rm_so
],
541 &line
[match
[3].rm_so
]);
546 /****************************************************************************
547 * skip_remaining_lines
549 * Get any remaining lines of unprocessed input. Complain if we find a line
550 * that contains anything other than comments and whitespace.
551 ****************************************************************************/
552 static void skip_remaining_lines(FILE * f
)
554 char line
[LINE_BUF_SIZE
];
557 get_layout_file_line(f
, line
, LINE_BUF_SIZE
) == OK
; line_num
++) {
558 if (regexec(&blank_or_comment_expr
, line
, 0, NULL
, 0)) {
560 "%s: Syntax error on line %d of CMOS layout file: "
561 "Only comments and/or whitespace allowed after "
562 "\"checksum\" line.\n", prog_name
, line_num
);
568 /****************************************************************************
571 * Create a CMOS entry structure representing the given information. Perform
572 * sanity checking on input parameters.
573 ****************************************************************************/
574 static void create_entry(cmos_entry_t
* cmos_entry
,
575 const char start_bit_str
[], const char length_str
[],
576 const char config_str
[], const char config_id_str
[],
577 const char name_str
[])
579 cmos_entry
->bit
= string_to_unsigned(start_bit_str
, "start-bit");
580 cmos_entry
->length
= string_to_unsigned(length_str
, "length");
582 if (config_str
[1] != '\0')
585 switch (config_str
[0]) {
587 cmos_entry
->config
= CMOS_ENTRY_ENUM
;
591 cmos_entry
->config
= CMOS_ENTRY_HEX
;
595 cmos_entry
->config
= CMOS_ENTRY_STRING
;
599 cmos_entry
->config
= CMOS_ENTRY_RESERVED
;
606 cmos_entry
->config_id
= string_to_unsigned(config_id_str
, "config-ID");
608 if (strlen(name_str
) >= CMOS_MAX_NAME_LENGTH
) {
610 "%s: Error on line %d of CMOS layout file: name too "
611 "long (max length is %d).\n", prog_name
, line_num
,
612 CMOS_MAX_NAME_LENGTH
- 1);
616 strcpy(cmos_entry
->name
, name_str
);
621 "%s: Error on line %d of CMOS layout file: 'e', 'h', or "
622 "'r' expected for config value.\n", prog_name
, line_num
);
626 /****************************************************************************
627 * try_add_layout_file_entry
629 * Attempt to add the given CMOS entry to our internal repository. Exit with
630 * an error message on failure.
631 ****************************************************************************/
632 static void try_add_layout_file_entry(const cmos_entry_t
* cmos_entry
)
634 const cmos_entry_t
*conflict
;
636 switch (add_cmos_entry(cmos_entry
, &conflict
)) {
640 case CMOS_AREA_OUT_OF_RANGE
:
642 "%s: Error on line %d of CMOS layout file. Area "
643 "covered by entry %s is out of range.\n", prog_name
,
644 line_num
, cmos_entry
->name
);
647 case CMOS_AREA_TOO_WIDE
:
649 "%s: Error on line %d of CMOS layout file. Area "
650 "covered by entry %s is too wide.\n", prog_name
,
651 line_num
, cmos_entry
->name
);
654 case LAYOUT_ENTRY_OVERLAP
:
656 "%s: Error on line %d of CMOS layout file. Layouts "
657 "overlap for entries %s and %s.\n", prog_name
, line_num
,
658 cmos_entry
->name
, conflict
->name
);
661 case LAYOUT_ENTRY_BAD_LENGTH
:
662 /* Silently ignore entries with zero length. Although this should
663 * never happen in practice, we should handle the case in a
664 * reasonable manner just to be safe.
668 case LAYOUT_MULTIBYTE_ENTRY_NOT_ALIGNED
:
670 "%s: Unaligned CMOS option table entry %s "
671 "spans multiple bytes.\n", prog_name
, cmos_entry
->name
);
681 /****************************************************************************
684 * Create a CMOS enumeration structure representing the given information.
685 * Perform sanity checking on input parameters.
686 ****************************************************************************/
687 static void create_enum(cmos_enum_t
* cmos_enum
, const char id_str
[],
688 const char value_str
[], const char text_str
[])
690 cmos_enum
->config_id
= string_to_unsigned(id_str
, "ID");
691 cmos_enum
->value
= string_to_unsigned_long(value_str
, "value");
693 if (strlen(text_str
) >= CMOS_MAX_TEXT_LENGTH
) {
695 "%s: Error on line %d of CMOS layout file: text too "
696 "long (max length is %d).\n", prog_name
, line_num
,
697 CMOS_MAX_TEXT_LENGTH
- 1);
701 strcpy(cmos_enum
->text
, text_str
);
704 /****************************************************************************
707 * Attempt to add the given CMOS enum to our internal repository. Exit with
708 * an error message on failure.
709 ****************************************************************************/
710 static void try_add_cmos_enum(const cmos_enum_t
* cmos_enum
)
712 switch (add_cmos_enum(cmos_enum
)) {
716 case LAYOUT_DUPLICATE_ENUM
:
717 fprintf(stderr
, "%s: Error on line %d of CMOS layout file: "
718 "Enumeration found with duplicate ID/value combination.\n",
719 prog_name
, line_num
);
729 /****************************************************************************
732 * Set CMOS checksum information according to input parameters and perform
733 * sanity checking on input parameters.
734 ****************************************************************************/
735 static void set_checksum_info(const char start_str
[], const char end_str
[],
736 const char index_str
[])
738 cmos_checksum_layout_t layout
;
740 /* These are bit positions that we want to convert to byte positions. */
741 layout
.summed_area_start
=
742 string_to_unsigned(start_str
, "CMOS checksummed area start");
743 layout
.summed_area_end
=
744 string_to_unsigned(end_str
, "CMOS checksummed area end");
746 string_to_unsigned(index_str
, "CMOS checksum location");
748 switch (checksum_layout_to_bytes(&layout
)) {
752 case LAYOUT_SUMMED_AREA_START_NOT_ALIGNED
:
754 "%s: Error on line %d of CMOS layout file. CMOS "
755 "checksummed area start is not byte-aligned.\n",
756 prog_name
, line_num
);
759 case LAYOUT_SUMMED_AREA_END_NOT_ALIGNED
:
761 "%s: Error on line %d of CMOS layout file. CMOS "
762 "checksummed area end is not byte-aligned.\n",
763 prog_name
, line_num
);
766 case LAYOUT_CHECKSUM_LOCATION_NOT_ALIGNED
:
768 "%s: Error on line %d of CMOS layout file. CMOS "
769 "checksum location is not byte-aligned.\n", prog_name
,
773 case LAYOUT_INVALID_SUMMED_AREA
:
775 "%s: Error on line %d of CMOS layout file. CMOS "
776 "checksummed area end must be greater than CMOS checksummed "
777 "area start.\n", prog_name
, line_num
);
780 case LAYOUT_CHECKSUM_OVERLAPS_SUMMED_AREA
:
782 "%s: Error on line %d of CMOS layout file. CMOS "
783 "checksum overlaps checksummed area.\n", prog_name
,
787 case LAYOUT_SUMMED_AREA_OUT_OF_RANGE
:
789 "%s: Error on line %d of CMOS layout file. CMOS "
790 "checksummed area out of range.\n", prog_name
,
794 case LAYOUT_CHECKSUM_LOCATION_OUT_OF_RANGE
:
796 "%s: Error on line %d of CMOS layout file. CMOS "
797 "checksum location out of range.\n", prog_name
,
805 cmos_checksum_start
= layout
.summed_area_start
;
806 cmos_checksum_end
= layout
.summed_area_end
;
807 cmos_checksum_index
= layout
.checksum_at
;
814 /****************************************************************************
815 * cmos_entry_char_value
817 * Return the character representation of 'config'.
818 ****************************************************************************/
819 static char cmos_entry_char_value(cmos_entry_config_t config
)
822 case CMOS_ENTRY_ENUM
:
828 case CMOS_ENTRY_RESERVED
:
831 case CMOS_ENTRY_STRING
:
838 return 0; /* not reached */
841 /****************************************************************************
842 * get_layout_file_line
844 * Get a line of input from file 'f'. Store result in 'line' which is an
845 * array of 'line_buf_size' bytes. Return OK on success or an error code on
847 ****************************************************************************/
848 static int get_layout_file_line(FILE * f
, char line
[], int line_buf_size
)
850 switch (get_line_from_file(f
, line
, line_buf_size
)) {
859 "%s: Error on line %d of CMOS layout file: Maximum "
860 "line length exceeded. Max is %d characters.\n",
861 prog_name
, line_num
, line_buf_size
- 2);
866 return 1; /* keep compiler happy */
869 /****************************************************************************
872 * Convert the string 'str' to an unsigned and return the result.
873 ****************************************************************************/
874 static unsigned string_to_unsigned(const char str
[], const char str_name
[])
879 n
= do_string_to_unsigned_long(str
, str_name
, "");
881 if ((z
= (unsigned)n
) != n
) {
882 /* This could happen on an architecture in which
883 * sizeof(unsigned) < sizeof(unsigned long).
886 "%s: Error on line %d of CMOS layout file: %s value is "
887 "out of range.\n", prog_name
, line_num
, str_name
);
894 /****************************************************************************
895 * string_to_unsigned_long
897 * Convert the string 'str' to an unsigned long and return the result.
898 ****************************************************************************/
899 static unsigned long string_to_unsigned_long(const char str
[],
900 const char str_name
[])
902 return do_string_to_unsigned_long(str
, str_name
, " long");
905 /****************************************************************************
906 * do_string_to_unsigned_long
908 * Convert the string 'str' to an unsigned long and return the result. Exit
909 * with an appropriate error message on failure.
910 ****************************************************************************/
911 static unsigned long do_string_to_unsigned_long(const char str
[],
912 const char str_name
[],
918 n
= strtoul(str
, &p
, 0);
922 "%s: Error on line %d of CMOS layout file: %s is not a "
923 "valid unsigned%s integer.\n", prog_name
, line_num
,