Fix compilation error due to non-unix style line endings in cmos.layout file while...
[coreboot.git] / util / options / build_opt_tbl.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2003 Eric Biederman (ebiederm@xmission.com)
5  * Copyright (C) 2007-2010 coresystems GmbH
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; version 2 of the License.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #include <libgen.h>
28 #define UTIL_BUILD_OPTION_TABLE
29 #include "../../src/include/pc80/mc146818rtc.h"
30 #include "../../src/include/boot/coreboot_tables.h"
31
32 #define CMOS_IMAGE_BUFFER_SIZE 256
33 #define INPUT_LINE_MAX 256
34 #define MAX_VALUE_BYTE_LENGTH 64
35
36 #define TMPFILE_LEN 25600
37 #define TMPFILE_TEMPLATE "/build_opt_tbl_XXXXXX"
38
39 static unsigned char cmos_table[4096];
40
41 /* This array is used to isolate bits that are to be changed in a byte */
42 static unsigned char clip[9]={0,1,3,7,0x0f,0x1f,0x3f,0x7f,0xff};
43
44 #ifdef WIN32
45 #include <fcntl.h>
46 char *mkstemp(char* name)
47 {
48         static char val='0';
49         char *c=name;
50         while (*c!='X') c++;
51         *c=val++;
52         return open(name,O_CREAT | O_RDWR);
53 }
54 #define UNLINK_IF_NECESSARY(x) unlink(x)
55 #else
56 #define UNLINK_IF_NECESSARY(x)
57 #endif
58
59 /**
60  * This routine loops through the entried and tests if any of the fields
61  * overlap.
62  * If there is an overlap, the routine exits, otherwise it returns.
63  *
64  * @param entry_start memory pointer to the start of the entries.
65  * @param entry_end   memory pointer to the byte past the entries.
66  */
67 static void test_for_entry_overlaps(void *entry_start, void *entry_end)
68 {
69         int ptr;
70         char *cptr;
71         int buffer_bit_size;
72         int offset;
73         int byte;
74         int byte_length;
75         struct cmos_entries *ce;
76         unsigned char test[CMOS_IMAGE_BUFFER_SIZE];
77         unsigned char set;
78
79         /* calculate the size of the cmos buffer in bits */
80         buffer_bit_size=(CMOS_IMAGE_BUFFER_SIZE*8);
81         /* clear the temporary test buffer */
82         for(ptr=0; ptr < CMOS_IMAGE_BUFFER_SIZE; ptr++)
83                 test[ptr]=0;
84
85         /* loop through each entry in the table testing for errors */
86         for(cptr = entry_start; cptr < (char *)entry_end; cptr += ce->size) {
87                 ce=(struct cmos_entries *)cptr;
88                 /* test if entry goes past the end of the buffer */
89                 if((int)(ce->bit+ce->length) > buffer_bit_size) {
90                         printf("Error - Entry %s start bit + length must be less than %d\n",
91                                 ce->name,buffer_bit_size);
92                         exit(1);
93                 }
94                 byte=ce->bit/8;
95                 offset=ce->bit%8;
96                 byte_length=ce->length/8;
97                 if(byte_length) {       /* entry is 8 bits long or more */
98                         if(offset) { /* if 8 bits or more long, it must be byte aligned */
99                                 printf("Error - Entry %s length over 8 must be byte aligned\n",
100                                         ce->name);
101                                 exit(1);
102                         }
103                         /* test if entries 8 or more in length are even bytes */
104                         if(ce->length%8){
105                                 printf("Error - Entry %s length over 8 must be a multiple of 8\n",
106                                         ce->name);
107                                 exit(1);
108                         }
109                         /* test if any of the bits have been previously used */
110                         for(;byte_length;byte_length--,byte++) {
111                                 if(test[byte]) {
112                                         printf("Error - Entry %s uses same bits previously used\n",
113                                                 ce->name);
114                                         exit(1);
115                                 }
116                                 test[byte]=clip[8]; /* set the bits defined in test */
117                         }
118                 } else {
119                         /* test if bits overlap byte boundaries */
120                         if((int)ce->length > (8-offset)) {
121                                 printf("Error - Entry %s length overlaps a byte boundry\n",
122                                         ce->name);
123                                 exit(1);
124                         }
125                         /* test for bits previously used */
126                         set=(clip[ce->length]<<offset);
127                         if(test[byte]&set) {
128                                 printf("Error - Entry %s uses same bits previously used\n",
129                                                 ce->name);
130                                 exit(1);
131                         }
132                         test[byte]|=set;  /* set the bits defined in test */
133                 }
134         }
135         return;
136 }
137
138 /* This routine displays the usage options */
139 static void display_usage(char *name)
140 {
141         printf("Usage: %s [--config filename]\n", name);
142         printf("                       [--option filename]\n");
143         printf("                       [--header filename]\n\n");
144         printf("--config = Build the definitions table from the given file.\n");
145         printf("--binary = Output a binary file with the definitions.\n");
146         printf("--option = Output a C source file with the definitions.\n");
147         printf("--header = Output a C header file with the definitions.\n");
148         exit(1);
149 }
150
151 static void skip_spaces(char *line, char **ptr)
152 {
153         if (!isspace(**ptr)) {
154                 printf("Error missing whitespace in line\n%s\n", line);
155                 exit(1);
156         }
157         while(isspace(**ptr)) {
158                 (*ptr)++;
159         }
160         return;
161 }
162
163 static unsigned long get_number(char *line, char **ptr, int base)
164 {
165         unsigned long value;
166         char *ptr2;
167         value = strtoul(*ptr, &ptr2, base);
168         if (ptr2 == *ptr) {
169                 printf("Error missing digits at: \n%s\n in line:\n%s\n",
170                         *ptr, line);
171                 exit(1);
172         }
173         *ptr = ptr2;
174         return value;
175 }
176
177 static int is_ident_digit(int c)
178 {
179         int result;
180         switch(c) {
181         case '0':       case '1':       case '2':       case '3':
182         case '4':       case '5':       case '6':       case '7':
183         case '8':       case '9':
184                 result = 1;
185                 break;
186         default:
187                 result = 0;
188                 break;
189         }
190         return result;
191 }
192
193 static int is_ident_nondigit(int c)
194 {
195         int result;
196         switch(c) {
197         case 'A':       case 'B':       case 'C':       case 'D':
198         case 'E':       case 'F':       case 'G':       case 'H':
199         case 'I':       case 'J':       case 'K':       case 'L':
200         case 'M':       case 'N':       case 'O':       case 'P':
201         case 'Q':       case 'R':       case 'S':       case 'T':
202         case 'U':       case 'V':       case 'W':       case 'X':
203         case 'Y':       case 'Z':
204         case 'a':       case 'b':       case 'c':       case 'd':
205         case 'e':       case 'f':       case 'g':       case 'h':
206         case 'i':       case 'j':       case 'k':       case 'l':
207         case 'm':       case 'n':       case 'o':       case 'p':
208         case 'q':       case 'r':       case 's':       case 't':
209         case 'u':       case 'v':       case 'w':       case 'x':
210         case 'y':       case 'z':
211         case '_':
212                 result = 1;
213                 break;
214         default:
215                 result = 0;
216                 break;
217         }
218         return result;
219 }
220
221 static int is_ident(char *str)
222 {
223         int result;
224         int ch;
225         ch = *str;
226         result = 0;
227         if (is_ident_nondigit(ch)) {
228                 do {
229                         str++;
230                         ch = *str;
231                 } while(ch && (is_ident_nondigit(ch) || (is_ident_digit(ch))));
232                 result = (ch == '\0');
233         }
234         return result;
235 }
236
237 /**
238  * This routine builds the cmos definition table from the cmos layout file
239  *
240  * The input comes from the configuration file which contains two parts
241  * entries and enumerations.  Each section is started with the key words
242  * entries and enumerations.  Records then follow in their respective
243  * formats.
244  *
245  * The output of this program is the cmos definitions table.  It is stored
246  * in the cmos_table array. If this module is called, and the global
247  * table_file has been implimented by the user, the table is also written
248  * to the specified file.
249  *
250  * This program exits with a return code of 1 on error.  It returns 0 on
251  * successful completion
252  */
253 int main(int argc, char **argv)
254 {
255         int i;
256         char *config=0;
257         char *binary=0;
258         char *option=0;
259         char *header=0;
260         FILE *fp;
261         int tempfile;
262         char tempfilename[TMPFILE_LEN];
263         struct cmos_option_table *ct;
264         struct cmos_entries *ce;
265         struct cmos_enums *c_enums, *c_enums_start;
266         struct cmos_checksum *cs, *new_cs;
267         char line[INPUT_LINE_MAX];
268         unsigned char uc;
269         int entry_mode=0;
270         int enum_mode=0;
271         int checksum_mode=0;
272         int cnt;
273         char *cptr;
274         void *entry_start, *entry_end;
275         int entries_length;
276         int enum_length;
277         int len;
278         char buf[16];
279         char val;
280
281         for(i=1;i<argc;i++) {
282                 if(argv[i][0]!='-') {
283                         display_usage(argv[0]);
284                 }
285                 switch(argv[i][1]) {
286                         case '-':       /* data is requested from a file */
287                                 switch(argv[i][2]) {
288                                         case 'c':  /* use a configuration file */
289                                                 if(strcmp(&argv[i][2],"config")) {
290                                                         display_usage(argv[0]);
291                                                 }
292                                                 config=argv[++i];
293                                                 break;
294                                         case 'b':  /* Emit a binary file */
295                                                 if(strcmp(&argv[i][2],"binary")) {
296                                                         display_usage(argv[0]);
297                                                 }
298                                                 binary=argv[++i];
299                                                 break;
300                                         case 'o':  /* use a cmos definitions table file */
301                                                 if(strcmp(&argv[i][2],"option")) {
302                                                         display_usage(argv[0]);
303                                                 }
304                                                 option=argv[++i];
305                                                 break;
306                                         case 'h': /* Output a header file */
307                                                 if (strcmp(&argv[i][2], "header") != 0) {
308                                                         display_usage(argv[0]);
309                                                 }
310                                                 header=argv[++i];
311                                                 break;
312                                         default:
313                                                 display_usage(argv[0]);
314                                                 break;
315                                 }
316                                 break;
317
318                         default:
319                                 display_usage(argv[0]);
320                                 break;
321                 }
322         }
323
324
325         /* Has the user specified a configuration file */
326         if(config) {    /* if yes, open it */
327                 if((fp=fopen(config,"r"))==NULL){
328                         fprintf(stderr, "Error - Can not open config file %s\n",config);
329                         exit(1);  /* exit if it can not be opened */
330                 }
331         }
332         else {  /* no configuration file specified, so try the default */
333                 if((fp=fopen("cmos.layout","r"))==NULL){
334                         fprintf(stderr, "Error - Can not open cmos.layout\n");
335                         exit(1);  /* end of no configuration file is found */
336                 }
337         }
338         /* type cast a pointer, so we can us the structure */
339         ct=(struct cmos_option_table*)cmos_table;
340         /* start the table with the type signature */
341         ct->tag = LB_TAG_CMOS_OPTION_TABLE;
342         /* put in the header length */
343         ct->header_length=sizeof(*ct);
344
345         /* Get the entry records */
346         ce=(struct cmos_entries*)(cmos_table+(ct->header_length));
347         cptr = (char*)ce;
348         for(;;){  /* this section loops through the entry records */
349                 if(fgets(line,INPUT_LINE_MAX,fp)==NULL)
350                         break; /* end if no more input */
351                 // FIXME mode should be a single enum.
352                 if(!entry_mode) {  /* skip input until the entries key word */
353                         if (strstr(line,"entries") != 0) {
354                                 entry_mode=1;
355                                 enum_mode=0;
356                                 checksum_mode=0;
357                                 continue;
358                         }
359                 } else {  /* Test if we are done with entries and starting enumerations */
360                         if (strstr(line,"enumerations") != 0){
361                                 entry_mode=0;
362                                 enum_mode=1;
363                                 checksum_mode=0;
364                                 break;
365                         }
366                         if (strstr(line, "checksums") != 0) {
367                                 entry_mode=0;
368                                 enum_mode=0;
369                                 checksum_mode=1;
370                                 break;
371                         }
372                 }
373
374                 /* skip commented and blank lines */
375                 val = line[strspn(line," ")];
376                 /* takes care of *nix, Mac and Windows line ending formats */
377                 if (val=='#' || val=='\n' || val=='\r') continue;
378                 /* scan in the input data */
379                 sscanf(line,"%d %d %c %d %s",
380                         &ce->bit,&ce->length,&uc,&ce->config_id,&ce->name[0]);
381                 ce->config=(int)uc;
382                 /* check bit and length ranges */
383                 if(ce->bit>(CMOS_IMAGE_BUFFER_SIZE*8)) {
384                         fprintf(stderr, "Error - bit is to big in line \n%s\n",line);
385                         exit(1);
386                 }
387                 if((ce->length>(MAX_VALUE_BYTE_LENGTH*8))&&(uc!='r')) {
388                         fprintf(stderr, "Error - Length is to long in line \n%s\n",line);
389                         exit(1);
390                 }
391                 if (!is_ident((char *)ce->name)) {
392                         fprintf(stderr,
393                                 "Error - Name %s is an invalid identifier in line\n %s\n",
394                                 ce->name, line);
395                         exit(1);
396                 }
397                 /* put in the record type */
398                 ce->tag=LB_TAG_OPTION;
399                 /* calculate and save the record length */
400                 len=strlen((char *)ce->name)+1;
401                 /* make the record int aligned */
402                 if(len%4)
403                         len+=(4-(len%4));
404                 ce->size=sizeof(struct cmos_entries)-32+len;
405                 cptr = (char*)ce;
406                 cptr += ce->size;  /* increment to the next table position */
407                 ce = (struct cmos_entries*) cptr;
408         }
409
410         /* put the length of the entries into the header section */
411         entries_length = (cptr - (char *)&cmos_table) - ct->header_length;
412
413         /* compute the start of the enumerations section */
414         entry_start = ((char*)&cmos_table) + ct->header_length;
415         entry_end   = ((char *)entry_start) + entries_length;
416         c_enums_start = c_enums = (struct cmos_enums*)entry_end;
417         /* test for overlaps in the entry records */
418         test_for_entry_overlaps(entry_start, entry_end);
419
420         for(;enum_mode;){ /* loop to build the enumerations section */
421                 long ptr;
422                 if(fgets(line,INPUT_LINE_MAX,fp)==NULL)
423                         break; /* go till end of input */
424
425                 if (strstr(line, "checksums") != 0) {
426                         enum_mode=0;
427                         checksum_mode=1;
428                         break;
429                 }
430
431                 /* skip commented and blank lines */
432                 if(line[0]=='#') continue;
433                 if(line[strspn(line," ")]=='\n') continue;
434
435                 /* scan in the data */
436                 for(ptr=0;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
437                 c_enums->config_id=strtol(&line[ptr],(char**)NULL,10);
438                 for(;(line[ptr]!=' ')&&(line[ptr]!='\t');ptr++);
439                 for(;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
440                 c_enums->value=strtol(&line[ptr],(char**)NULL,10);
441                 for(;(line[ptr]!=' ')&&(line[ptr]!='\t');ptr++);
442                 for(;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
443                 for(cnt=0;(line[ptr]!='\n')&&(cnt<31);ptr++,cnt++)
444                         c_enums->text[cnt]=line[ptr];
445                 c_enums->text[cnt]=0;
446
447                 /* make the record int aligned */
448                 cnt++;
449                 if(cnt%4)
450                         cnt+=4-(cnt%4);
451                 /* store the record length */
452                 c_enums->size=((char *)&c_enums->text[cnt]) - (char *)c_enums;
453                 /* store the record type */
454                 c_enums->tag=LB_TAG_OPTION_ENUM;
455                 /* increment to the next record */
456                 c_enums=(struct cmos_enums*)&c_enums->text[cnt];
457         }
458         /* save the enumerations length */
459         enum_length= (char *)c_enums - (char *)c_enums_start;
460         ct->size=ct->header_length+enum_length+entries_length;
461
462         /* Get the checksum records */
463         new_cs = (struct cmos_checksum *)(cmos_table+(ct->size));
464         for(;checksum_mode;) { /* This section finds the checksums */
465                 char *ptr;
466                 if(fgets(line, INPUT_LINE_MAX,fp)==NULL)
467                         break; /* end if no more input */
468
469                 /* skip commented and blank lines */
470                 if (line[0]=='#') continue;
471                 if (line[strspn(line, " ")]=='\n') continue;
472                 if (memcmp(line, "checksum", 8) != 0) continue;
473
474                 /* We actually found a new cmos checksum entry */
475                 cs = new_cs;
476
477                 /* get the information */
478                 ptr = line + 8;
479                 skip_spaces(line, &ptr);
480                 cs->range_start = get_number(line, &ptr, 10);
481
482                 skip_spaces(line, &ptr);
483                 cs->range_end = get_number(line, &ptr, 10);
484
485                 skip_spaces(line, &ptr);
486                 cs->location = get_number(line, &ptr, 10);
487
488                 /* Make certain there are spaces until the end of the line */
489                 skip_spaces(line, &ptr);
490
491                 if ((cs->range_start%8) != 0) {
492                         fprintf(stderr, "Error - range start is not byte aligned in line\n%s\n", line);
493                         exit(1);
494                 }
495                 if (cs->range_start >= (CMOS_IMAGE_BUFFER_SIZE*8)) {
496                         fprintf(stderr, "Error - range start is to big in line\n%s\n", line);
497                         exit(1);
498                 }
499                 if ((cs->range_end%8) != 7) {
500                         fprintf(stderr, "Error - range end is not byte aligned in line\n%s\n", line);
501                         exit(1);
502                 }
503                 if ((cs->range_end) >= (CMOS_IMAGE_BUFFER_SIZE*8)) {
504                         fprintf(stderr, "Error - range end is to long in line\n%s\n", line);
505                         exit(1);
506                 }
507                 if ((cs->location%8) != 0) {
508                         fprintf(stderr, "Error - location is not byte aligned in line\n%s\n", line);
509                         exit(1);
510                 }
511                 if ((cs->location >= (CMOS_IMAGE_BUFFER_SIZE*8)) ||
512                         ((cs->location + 16) > (CMOS_IMAGE_BUFFER_SIZE*8)))
513                 {
514                         fprintf(stderr, "Error - location is to big in line\n%s\n", line);
515                         exit(1);
516                 }
517
518                 cs->tag = LB_TAG_OPTION_CHECKSUM;
519                 cs->size = sizeof(*cs);
520                 cs->type = CHECKSUM_PCBIOS;
521
522                 cptr = (char *)cs;
523                 cptr += cs->size;
524                 new_cs = (struct cmos_checksum *)cptr;
525         }
526         ct->size += (cptr - (char *)(cmos_table + ct->size));
527         fclose(fp);
528
529         /* See if we want to output a C source file */
530         if(option) {
531                 int err=0;
532                 snprintf(tempfilename, TMPFILE_LEN, "%s%s", dirname(strdup(option)), TMPFILE_TEMPLATE);
533                 tempfile = mkstemp(tempfilename);
534                 if(tempfile == -1) {
535                         perror("Error - Could not create temporary file");
536                         exit(1);
537                 }
538
539                 if((fp=fdopen(tempfile,"w"))==NULL){
540                         perror("Error - Could not open temporary file");
541                         unlink(tempfilename);
542                         exit(1);
543                 }
544
545                 /* write the header */
546                 if(fwrite("unsigned char option_table[] = {",1,32,fp) != 32) {
547                         perror("Error - Could not write image file");
548                         fclose(fp);
549                         unlink(tempfilename);
550                         exit(1);
551                 }
552                 /* write the array values */
553                 for(i=0; i<(int)(ct->size-1); i++) {
554                         if(!(i%10) && !err) err=(fwrite("\n\t",1,2,fp) != 2);
555                         sprintf(buf,"0x%02x,",cmos_table[i]);
556                         if(!err) err=(fwrite(buf,1,5,fp) != 5);
557                 }
558                 /* write the end */
559                 sprintf(buf,"0x%02x\n",cmos_table[i]);
560                 if(!err) err=(fwrite(buf,1,4,fp) != 4);
561                 if(fwrite("};\n",1,3,fp) != 3) {
562                         perror("Error - Could not write image file");
563                         fclose(fp);
564                         unlink(tempfilename);
565                         exit(1);
566                 }
567
568                 fclose(fp);
569                 UNLINK_IF_NECESSARY(option);
570                 if (rename(tempfilename, option)) {
571                         fprintf(stderr, "Error - Could not write %s: ", option);
572                         perror(NULL);
573                         unlink(tempfilename);
574                         exit(1);
575                 }
576         }
577
578         /* See if we also want to output a binary file */
579         if(binary) {
580                 int err=0;
581                 snprintf(tempfilename, TMPFILE_LEN, "%s%s", dirname(strdup(binary)), TMPFILE_TEMPLATE);
582                 tempfile = mkstemp(tempfilename);
583                 if(tempfile == -1) {
584                         perror("Error - Could not create temporary file");
585                         exit(1);
586                 }
587
588                 if((fp=fdopen(tempfile,"wb"))==NULL){
589                         perror("Error - Could not open temporary file");
590                         unlink(tempfilename);
591                         exit(1);
592                 }
593
594                 /* write the array values */
595                 if(fwrite(cmos_table, (int)(ct->size-1), 1, fp) != 1) {
596                         perror("Error - Could not write image file");
597                         fclose(fp);
598                         unlink(tempfilename);
599                         exit(1);
600                 }
601
602                 fclose(fp);
603                 UNLINK_IF_NECESSARY(binary);
604                 if (rename(tempfilename, binary)) {
605                         fprintf(stderr, "Error - Could not write %s: ", binary);
606                         perror(NULL);
607                         unlink(tempfilename);
608                         exit(1);
609                 }
610         }
611
612         /* See if we also want to output a C header file */
613         if (header) {
614                 struct cmos_option_table *hdr;
615                 struct lb_record *ptr, *end;
616
617                 snprintf(tempfilename, TMPFILE_LEN, "%s%s", dirname(strdup(header)), TMPFILE_TEMPLATE);
618                 tempfile = mkstemp(tempfilename);
619                 if(tempfile == -1) {
620                         perror("Error - Could not create temporary file");
621                         exit(1);
622                 }
623
624                 fp = fdopen(tempfile, "w");
625                 if (!fp) {
626                         perror("Error - Could not open temporary file");
627                         unlink(tempfilename);
628                         exit(1);
629                 }
630
631                 /* Get the cmos table header */
632                 hdr = (struct cmos_option_table *)cmos_table;
633                 /* Walk through the entry records */
634                 ptr = (struct lb_record *)(cmos_table + hdr->header_length);
635                 end = (struct lb_record *)(cmos_table + hdr->size);
636                 fprintf(fp, "/* This file is autogenerated.\n"
637                             " * See mainboard's cmos.layout file.\n */\n\n"
638                             "#ifndef __OPTION_TABLE_H\n#define __OPTION_TABLE_H\n\n");
639
640                 for(;ptr < end; ptr = (struct lb_record *)(((char *)ptr) + ptr->size)) {
641                         if (ptr->tag != LB_TAG_OPTION) {
642                                 continue;
643                         }
644                         ce = (struct cmos_entries *)ptr;
645
646                         if (!is_ident((char *)ce->name)) {
647                                 fprintf(stderr, "Invalid identifier: %s\n",
648                                         ce->name);
649                                 fclose(fp);
650                                 unlink(tempfilename);
651                                 exit(1);
652                         }
653                         fprintf(fp, "#define CMOS_VSTART_%s %d\n",
654                                 ce->name, ce->bit);
655                         fprintf(fp, "#define CMOS_VLEN_%s %d\n",
656                                 ce->name, ce->length);
657                 }
658
659                 if (cs != NULL) {
660                         fprintf(fp, "\n#define LB_CKS_RANGE_START %d\n", cs->range_start / 8);
661                         fprintf(fp, "#define LB_CKS_RANGE_END %d\n", cs->range_end / 8);
662                         fprintf(fp, "#define LB_CKS_LOC %d\n", cs->location / 8);
663                 } else {
664                         fprintf(stderr, "Error - No checksums defined.\n");
665                         fclose(fp);
666                         unlink(tempfilename);
667                         exit(1);
668                 }
669                 fprintf(fp, "\n#endif // __OPTION_TABLE_H\n");
670                 fclose(fp);
671
672                 UNLINK_IF_NECESSARY(header);
673                 if (rename(tempfilename, header)) {
674                         fprintf(stderr, "Error - Could not write %s: ", header);
675                         perror(NULL);
676                         unlink(tempfilename);
677                         exit(1);
678                 }
679         }
680
681         return 0;
682 }
683
684