A complete rewrite of the layout file parser:
 - safe (unlike before)
 - support for comments
 - supports including/sourcing of other layout files (relative to the including
   file as well as via absolute paths) up to predefined nesting level
 - checks for duplicate region names
 - can handle region names and layout file names with spaces etc correctly
 - way better diagnostics
 - no more character arrays in struct romentry_t but pointers only

To help with migrating legacy layout files add a script for converting them
to format 2.

Also, document the whole layout handling including the new features a bit better
and refine wording regarding files, images, layouts and regions as discussed.

Signed-off-by: Stefan Tauner <[email protected]>
---
 flashrom.8.tmpl                 | 130 ++++++++++------
 layout.c                        | 332 +++++++++++++++++++++++++++++++++-------
 util/convert_layout_v1_to_v2.sh |  79 ++++++++++
 3 files changed, 437 insertions(+), 104 deletions(-)
 create mode 100755 util/convert_layout_v1_to_v2.sh

diff --git a/flashrom.8.tmpl b/flashrom.8.tmpl
index b507a97..06282f6 100644
--- a/flashrom.8.tmpl
+++ b/flashrom.8.tmpl
@@ -3,10 +3,10 @@
 flashrom \- detect, read, write, verify and erase flash chips
 .SH SYNOPSIS
 .B flashrom \fR[\fB\-h\fR|\fB\-R\fR|\fB\-L\fR|\fB\-z\fR|\
-\fB\-p\fR <programmername>[:<parameters>]
-               [\fB\-E\fR|\fB\-r\fR <file>|\fB\-w\fR <file>|\fB\-v\fR <file>] \
+\fB\-p\fR <programmername>[:<parameter>[,<parameter>]...]]
+               [\fB\-E\fR|\fB\-r\fR <imagefile>|\fB\-w\fR 
<imagefile>|\fB\-v\fR <imagefile>] \
 [\fB\-c\fR <chipname>]
-               [\fB\-l\fR <file> [\fB\-i\fR <image>]] [\fB\-n\fR] [\fB\-f\fR]]
+               [\fB\-l\fR <layoutfile> [\fB\-i\fR 
<regionname>[:<regionfile>]]...] [\fB\-n\fR] [\fB\-f\fR]]
          [\fB\-V\fR[\fBV\fR[\fBV\fR]]] [\fB-o\fR <logfile>]
 .SH DESCRIPTION
 .B flashrom
@@ -38,14 +38,14 @@ before you try to write a new image. All operations 
involving any chip access (p
 .B -p/--programmer
 option to be used (please see below).
 .TP
-.B "\-r, \-\-read <file>"
+.B "\-r, \-\-read <imagefile>"
 Read flash ROM contents and save them into the given
-.BR <file> .
+.BR <imagefile> .
 If the file already exists, it will be overwritten.
 .TP
-.B "\-w, \-\-write <file>"
+.B "\-w, \-\-write <imagefile>"
 Write
-.B <file>
+.B <imagefile>
 into flash ROM. This will first automatically
 .B erase
 the chip, then write to it.
@@ -65,14 +65,14 @@ recommended, you should only use it if you know what you 
are doing and if you
 feel that the time for verification takes too long.
 .sp
 Typical usage is:
-.B "flashrom \-p prog \-n \-w <file>"
+.B "flashrom \-p prog \-n \-w <imagefile>"
 .sp
 This option is only useful in combination with
 .BR \-\-write .
 .TP
-.B "\-v, \-\-verify <file>"
+.B "\-v, \-\-verify <imagefile>"
 Verify the flash ROM contents against the given
-.BR <file> .
+.BR <imagefile> .
 .TP
 .B "\-E, \-\-erase"
 Erase the flash ROM chip.
@@ -102,46 +102,6 @@ size for the flash bus.
 .sp
 * Force write even if write is known bad.
 .TP
-.B "\-l, \-\-layout <file>"
-Read ROM layout from
-.BR <file> .
-.sp
-flashrom supports ROM layouts. This allows you to flash certain parts of
-the flash chip only. A ROM layout file contains multiple lines with the
-following syntax:
-.sp
-.B "  startaddr:endaddr imagename"
-.sp
-.BR "startaddr " "and " "endaddr "
-are hexadecimal addresses within the ROM file and do not refer to any
-physical address. Please note that using a 0x prefix for those hexadecimal
-numbers is not necessary, but you can't specify decimal/octal numbers.
-.BR "imagename " "is an arbitrary name for the region/image from"
-.BR " startaddr " "to " "endaddr " "(both addresses included)."
-.sp
-Example:
-.sp
-  00000000:00008fff gfxrom
-  00009000:0003ffff normal
-  00040000:0007ffff fallback
-.sp
-If you only want to update the image named
-.BR "normal " "in a ROM based on the layout above, run"
-.sp
-.B "  flashrom \-p prog \-\-layout rom.layout \-\-image normal \-w some.rom"
-.sp
-To update only the images named
-.BR "normal " "and " "fallback" ", run:"
-.sp
-.B "  flashrom \-p prog \-l rom.layout \-i normal -i fallback \-w some.rom"
-.sp
-Overlapping sections are not supported.
-.TP
-.B "\-i, \-\-image <imagename>"
-Only flash region/image
-.B <imagename>
-from flash layout.
-.TP
 .B "\-L, \-\-list\-supported"
 List the flash chips, chipsets, mainboards, and external programmers
 (including PCI, USB, parallel port, and serial port based devices)
@@ -226,6 +186,76 @@ Some programmers have optional or mandatory parameters 
which are described
 in detail in the
 .B PROGRAMMER SPECIFIC INFO
 section. Support for some programmers can be disabled at compile time.
+.TP
+flashrom supports reading/writing/erasing/verifying flash chips in whole 
(default) or in part. To access only \
+parts of a chip one has to use layout files and respective arguments described 
below.
+.TP
+.B "\-l, \-\-layout <layoutfile>"
+Read layout entries from
+.BR <layoutfile> .
+.sp
+A layout file can contain comments which are
+started by a pound sign (#) and causes all following characters on the same 
line to be ignored with one
+exception: Every layout file
+.B must
+start with a comment in the following form to define the version of the file. 
Example for the current version 2:
+.sp
+.B "  # flashrom layout v2"
+.sp
+Every other line may contain either a command to include another layout file, 
a layout entry or white space
+(and an optional comment at the end).
+.sp
+To include another file you can use the
+.sp
+.B "  source <path>"
+.sp
+syntax where
+.B path
+specifies the absolute or relative path to the file to be included. Relative 
paths are interpreted to be
+relative to the file containing the include command. If the path contains 
spaces it has to be written in double
+quotes, or else only the part before the first space will be recognized.
+.sp
+Each layout entry describes an address region of the flash chip and gives it a 
name (hereinafter referred to as
+a region). One entry per line is allowed with the following syntax:
+.sp
+.B "  startaddr:endaddr regionname"
+.sp
+.BR "startaddr " "and " "endaddr "
+are addresses within the ROM image representing the flash ROM contents. They 
are interpreted in the 'usual' form
+i.e.\ a leading 0 means octal, leading 0x or 0X means hexadecimal, everything 
else is just decimal.
+.BR "regionname " "is the name for the region from " "startaddr " "to " 
"endaddr " "(both addresses included)."
+If the name contains spaces it has to be written in double quotes, or else 
only the part before the first space
+will be used.
+.sp
+Example content of file rom.layout:
+.sp
+  # flashrom layout v2
+  source /home/flashrom/include.layout
+  0x00000000:0x00008fff "gfx rom"
+  0x00009000:0x0003ffff normal
+  0x00040000:0x0007ffff fallback
+.sp
+.TP
+.B "\-i, \-\-include <name>[:<regionfile>]"
+Work on the flash region
+.B name
+instead of the full address space if a layout file is given and parsed 
correctly.
+Multiple such include parameters can be used to work on the union of different 
regions.
+.sp
+The optional
+.B regionfile
+parameter specifies the name of a file that is used to map the contents of 
that very region only.
+The optional file parameter causes the contents of this region to be replaced 
by the contents of the file
+specified here.
+.sp
+If you only want to update the regions named
+.BR "normal " "and " "gfx rom " "in a ROM based on the layout mentioned above, 
run"
+.sp
+.B "  flashrom \-p prog \-l rom.layout \-i normal -i ""gfx rom"" \-w some.rom"
+.sp
+Overlapping regions are resolved in an implementation-dependent manner (or may 
even yield an error) - do
+.BR "not " "rely on it."
+.sp
 .B "flashrom \-h"
 lists all supported programmers.
 .TP
diff --git a/layout.c b/layout.c
index 7e2e904..6150e7e 100644
--- a/layout.c
+++ b/layout.c
@@ -22,17 +22,23 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
+#include <errno.h>
 #include <limits.h>
 #include "flash.h"
 #include "programmer.h"
 
 #define MAX_ROMLAYOUT  32
+#define MAX_ENTRY_LEN  1024
+#define WHITESPACE_CHARS " \t"
+#define INCLUDE_INSTR "source"
+#define MAX_NESTING_LVL 5
 
 typedef struct {
        chipoff_t start;
        chipoff_t end;
-       unsigned int included;
-       char name[256];
+       bool included;
+       char *name;
        char *file;
 } romentry_t;
 
@@ -45,58 +51,289 @@ static int num_rom_entries = 0; /* the number of 
successfully parsed rom_entries
 static char *include_args[MAX_ROMLAYOUT];
 static int num_include_args = 0; /* the number of valid include_args. */
 
-#ifndef __LIBPAYLOAD__
-int read_romlayout(char *name)
+/* returns the index of the entry (or a negative value if it is not found) */
+static int find_romentry(char *name)
 {
-       FILE *romlayout;
-       char tempstr[256];
        int i;
+       msg_gspew("Looking for region \"%s\"... ", name);
+       for (i = 0; i < num_rom_entries; i++) {
+               if (strcmp(rom_entries[i].name, name) == 0) {
+                       msg_gspew("found.\n");
+                       return i;
+               }
+       }
+       msg_gspew("not found.\n");
+       return -1;
+}
+
+/* FIXME: While libpayload has no file I/O itself, code using libflashrom 
could still provide layout information
+ * obtained by other means like user input or by fetching it from somewhere 
else. Therefore the parsing code
+ * should be separated from the file reading code eventually. */
+#ifndef __LIBPAYLOAD__
+/** Parse one line in a layout file.
+ * @param      file_name The name of the file this line originates from.
+ * @param      linecnt Line number the input string originates from.
+ * @param      entry If not NULL fill it with the parsed data, else just 
detect errors and print diagnostics.
+ * @return     -1 on error,
+ *             0 if the line could be parsed into a layout entry succesfully,
+ *             1 if a file was successfully sourced.
+ */
+static int parse_entry(char *file_name, unsigned int linecnt, char *buf, 
romentry_t *entry)
+{
+       msg_gdbg2("String to parse: \"%s\".\n", buf);
+
+       /* Skip all white space in the beginning. */
+       char *tmp_str = buf + strspn(buf, WHITESPACE_CHARS);
+       char *endptr;
+
+       /* Check for include command. */
+       if (strncmp(tmp_str, INCLUDE_INSTR, strlen(INCLUDE_INSTR)) == 0) {
+               tmp_str += strlen(INCLUDE_INSTR);
+               tmp_str += strspn(tmp_str, WHITESPACE_CHARS);
+               if (unquote_string(&tmp_str, NULL, WHITESPACE_CHARS) != 0) {
+                       msg_gerr("Error parsing version 2 layout entry in file 
\"%s\" at line %d:\n"
+                                "Could not find file name in \"%s\".\n",
+                                file_name, linecnt, buf);
+                               return -1;
+               }
+               msg_gspew("Source command found with filename \"%s\".\n", 
tmp_str);
+
+               static unsigned int nesting_lvl = 0;
+               if (nesting_lvl >= MAX_NESTING_LVL) {
+                       msg_gerr("Error: Nesting level exeeded limit of %u.\n", 
MAX_NESTING_LVL);
+                       msg_gerr("Unable to import \"%s\" in layout file 
\"%s\".\n", tmp_str, file_name);
+                       return -1;
+               }
+
+               nesting_lvl++;
+               int ret;
+               /* If a relative path is given, append it to the dirname of the 
current file. */
+               if (*tmp_str != '/') {
+                       /* We need space for: dirname of file_name, '/' , the 
file name in tmp_strand and '\0'.
+                        * Since the dirname of file_name is shorter than 
file_name this is more than enough: */
+                       char *path = malloc(strlen(file_name) + strlen(tmp_str) 
+ 2);
+                       if (path == NULL) {
+                               msg_gerr("Out of memory!\n");
+                               return -1;
+                       }
+                       strcpy(path, file_name);
+
+                       /* A less insane but incomplete dirname 
implementation... */
+                       endptr = strrchr(path, '/');
+                       if (endptr != NULL) {
+                               endptr[0] = '/';
+                               endptr[1] = '\0';
+                       } else {
+                               /* This is safe because the original file name 
was at least one char. */
+                               path[0] = '.';
+                               path[1] = '/';
+                               path[2] = '\0';
+                       }
+                       strcat(path, tmp_str);
+                       ret = read_romlayout(path);
+                       free(path);
+               } else
+                       ret = read_romlayout(tmp_str);
+               nesting_lvl--;
+               return ret >= 0 ? 1 : -1; /* Only return values < 0 are errors. 
*/
+       }
 
-       romlayout = fopen(name, "r");
+       /* Parse start address. */
+       errno = 0;
+       long long tmp_addr = strtoll(tmp_str, &endptr, 0);
+       if (errno != 0 || endptr == tmp_str) {
+               msg_gerr("Error parsing version 2 layout entry in file \"%s\" 
at line %d:\n"
+                        "Could not convert start address in \"%s\".\n", 
file_name, linecnt, buf);
+               return -1;
+       }
+       if (tmp_addr < 0 || tmp_addr > FL_MAX_CHIPADDR) {
+               msg_gerr("Error parsing version 2 layout entry in file \"%s\" 
at line %d:\n"
+                        "Start address (%s0x%llx) in \"%s\" is beyond the 
supported range (max 0x%"
+                        PRIxCHIPADDR ").\n", file_name, linecnt, (tmp_addr < 
0) ? "-" : "",
+                        llabs(tmp_addr), buf, FL_MAX_CHIPADDR);
+               return -1;
+       }
+       chipoff_t start = (chipoff_t)tmp_addr;
 
-       if (!romlayout) {
-               msg_gerr("ERROR: Could not open layout file (%s).\n",
-                       name);
+       tmp_str = endptr + strspn(endptr, WHITESPACE_CHARS);
+       if (*tmp_str != ':') {
+               msg_gerr("Error parsing version 2 layout entry in file \"%s\" 
at line %d:\n"
+                        "Address separator does not follow start address in 
\"%s\".\n",
+                        file_name, linecnt, buf);
                return -1;
        }
+       tmp_str++;
+
+       /* Parse end address. */
+       errno = 0;
+       tmp_addr = strtoll(tmp_str, &endptr, 0);
+       if (errno != 0 || endptr == tmp_str) {
+               msg_gerr("Error parsing version 2 layout entry in file \"%s\" 
at line %d:\n"
+                        "Could not convert end address in \"%s\".\n", 
file_name, linecnt, buf);
+               return -1;
+       }
+       if (tmp_addr < 0 || tmp_addr > FL_MAX_CHIPADDR) {
+               msg_gerr("Error parsing version 2 layout entry in file \"%s\" 
at line %d:\n"
+                        "End address (%s0x%llx) in \"%s\" is beyond the 
supported range (max 0x%"
+                        PRIxCHIPADDR ").\n", file_name, linecnt, (tmp_addr < 
0) ? "-" : "",
+                        llabs(tmp_addr), buf, FL_MAX_CHIPADDR);
+               return -1;
+       }
+       chipoff_t end = (chipoff_t)tmp_addr;
 
-       while (!feof(romlayout)) {
-               char *tstr1, *tstr2;
+       size_t skip = strspn(endptr, WHITESPACE_CHARS);
+       if (skip == 0) {
+               msg_gerr("Error parsing version 2 layout entry in file \"%s\" 
at line %d:\n"
+                        "End address is not followed by white space in 
\"%s\"\n", file_name, linecnt, buf);
+               return -1;
+       }
 
-               if (num_rom_entries >= MAX_ROMLAYOUT) {
-                       msg_gerr("Maximum number of entries (%i) in layout file 
reached.\n", MAX_ROMLAYOUT);
-                       return 1;
+       /* Parse region name. */
+       tmp_str = endptr + skip;
+       /* The region name is either enclosed by quotes or ends with the first 
whitespace. */
+       if (unquote_string(&tmp_str, &endptr, WHITESPACE_CHARS) != 0) {
+               msg_gerr("Error parsing version 2 layout entry in file \"%s\" 
at line %d:\n"
+                        "Could not find region name in \"%s\".\n", file_name, 
linecnt, buf);
+               return -1;
+       }
+
+       msg_gdbg2("Parsed entry: 0x%" PRIxCHIPADDR " - 0x%" PRIxCHIPADDR " 
named \"%s\"\n",
+                 start, end, tmp_str);
+
+       if (start >= end) {
+               msg_gerr("Error parsing version 2 layout entry in file \"%s\" 
at line %d:\n"
+                        "Length of region \"%s\" is not positive.\n", 
file_name, linecnt, tmp_str);
+               return -1;
+       }
+
+       if (find_romentry(tmp_str) >= 0) {
+               msg_gerr("Error parsing version 2 layout entry in file \"%s\" 
at line %d:\n"
+                        "Region name \"%s\" used multiple times.\n", 
file_name, linecnt, tmp_str);
+               return -1;
+       }
+
+       endptr += strspn(endptr, WHITESPACE_CHARS);
+       if (strlen(endptr) != 0)
+               msg_gwarn("Warning parsing version 2 layout entry in file 
\"%s\" at line %d:\n"
+                         "Region name \"%s\" is not followed by white space 
only.\n",
+                         file_name, linecnt, tmp_str);
+
+       if (entry != NULL) {
+               entry->name = strdup(tmp_str);
+               if (entry->name == NULL) {
+                       msg_gerr("Out of memory!\n");
+                       return -1;
                }
-               if (2 != fscanf(romlayout, "%s %s\n", tempstr, 
rom_entries[num_rom_entries].name))
-                       continue;
-#if 0
-               // fscanf does not like arbitrary comments like that :( later
-               if (tempstr[0] == '#') {
-                       continue;
+
+               entry->start = start;
+               entry->end = end;
+               entry->included = 0;
+               entry->file = NULL;
+       }
+       return 0;
+}
+
+/* Scan the first line for the determinant version comment and parse it, or 
assume it is version 1. */
+static int detect_layout_version(FILE *romlayout)
+{
+       int c;
+       do { /* Skip white space */
+               c = fgetc(romlayout);
+               if (c == EOF)
+                       return -1;
+       } while (isblank(c));
+       ungetc(c, romlayout);
+
+       const char* vcomment = "# flashrom layout v";
+       char buf[strlen(vcomment) + 1]; /* comment + \0 */
+       if (fgets(buf, sizeof(buf), romlayout) == NULL)
+               return -1;
+       if (strcmp(vcomment, buf) != 0)
+               return 1;
+       int version;
+       if (fscanf(romlayout, "%d", &version) != 1)
+               return -1;
+       if (version < 2) {
+               msg_gwarn("Warning: Layout file declares itself to be version 
%d, but self declaration has\n"
+                         "only been possible since version 2. Continuing 
anyway.\n", version);
+       }
+       return version;
+}
+
+int read_romlayout(char *name)
+{
+       FILE *romlayout = fopen(name, "r");
+       if (romlayout == NULL) {
+               msg_gerr("ERROR: Could not open layout file \"%s\".\n", name);
+               return -1;
+       }
+
+       const int version = detect_layout_version(romlayout);
+       if (version < 0) {
+               msg_gerr("Could not determine version of layout file 
\"%s\".\n", name);
+               fclose(romlayout);
+               return 1;
+       }
+       if (version != 2) {
+               msg_gerr("Layout file version %d is not supported in this 
version of flashrom.\n", version);
+               fclose(romlayout);
+               return 1;
+       }
+       rewind(romlayout);
+
+       msg_gdbg("Parsing layout file \"%s\" according to version %d.\n", name, 
version);
+       unsigned int linecnt = 0;
+       while (!feof(romlayout)) {
+               char buf[MAX_ENTRY_LEN];
+               char *curchar = buf;
+
+               while (true) {
+                       /* Make sure that we ignore various newline sequences 
by checking for \r too.
+                        * NB: This might introduce empty lines. */
+                       char c = fgetc(romlayout);
+                       if (c == '#') {
+                               do { /* Skip characters in comments */
+                                       c = fgetc(romlayout);
+                               } while (c != EOF && c != '\n' && c != '\r');
+                               linecnt++;
+                               continue;
+                       }
+                       if (c == EOF || c == '\n' || c == '\r') {
+                               *curchar = '\0';
+                               linecnt++;
+                               break;
+                       }
+                       if (curchar == &buf[MAX_ENTRY_LEN - 1]) {
+                               msg_gerr("Line %d of layout file \"%s\" is 
longer than the allowed %d chars.\n",
+                                        linecnt, name, MAX_ENTRY_LEN);
+                               fclose(romlayout);
+                               return 1;
+                       }
+                       *curchar = c;
+                       curchar++;
                }
-#endif
-               tstr1 = strtok(tempstr, ":");
-               tstr2 = strtok(NULL, ":");
-               if (!tstr1 || !tstr2) {
-                       msg_gerr("Error parsing layout file. Offending string: 
\"%s\"\n", tempstr);
+               msg_gspew("Parsing line %d of \"%s\".\n", linecnt, name);
+
+               /* Skip all whitespace or empty lines */
+               if (strspn(buf, WHITESPACE_CHARS) == strlen(buf))
+                       continue;
+
+               romentry_t *entry = (num_rom_entries >= MAX_ROMLAYOUT) ? NULL : 
&rom_entries[num_rom_entries];
+               int ret = parse_entry(name, linecnt, buf, entry);
+               if (ret < 0) {
                        fclose(romlayout);
                        return 1;
                }
-               rom_entries[num_rom_entries].start = strtol(tstr1, (char 
**)NULL, 16);
-               rom_entries[num_rom_entries].end = strtol(tstr2, (char **)NULL, 
16);
-               rom_entries[num_rom_entries].included = 0;
-               rom_entries[num_rom_entries].file = NULL;
-               num_rom_entries++;
+               /* Only 0 indicates the successfully parsing of an entry, 
others are errors or imports. */
+               if (ret == 0)
+                       num_rom_entries++;
        }
-
-       for (i = 0; i < num_rom_entries; i++) {
-               msg_gdbg("romlayout %08x - %08x named %s\n",
-                            rom_entries[i].start,
-                            rom_entries[i].end, rom_entries[i].name);
-       }
-
        fclose(romlayout);
-
+       if (num_rom_entries >= MAX_ROMLAYOUT) {
+               msg_gerr("Found %d entries in layout file which is more than 
the %i allowed.\n",
+                        num_rom_entries + 1, MAX_ROMLAYOUT);
+               return 1;
+       }
        return 0;
 }
 #endif
@@ -135,21 +372,6 @@ int register_include_arg(char *name)
        return 0;
 }
 
-/* returns the index of the entry (or a negative value if it is not found) */
-static int find_romentry(char *name)
-{
-       int i;
-       msg_gspew("Looking for region \"%s\"... ", name);
-       for (i = 0; i < num_rom_entries; i++) {
-               if (strcmp(rom_entries[i].name, name) == 0) {
-                       msg_gspew("found.\n");
-                       return i;
-               }
-       }
-       msg_gspew("not found.\n");
-       return -1;
-}
-
 /* process -i arguments
  * returns 0 to indicate success, >0 to indicate failure
  */
@@ -230,6 +452,8 @@ void layout_cleanup(void)
        num_include_args = 0;
 
        for (i = 0; i < num_rom_entries; i++) {
+               free(rom_entries[i].name);
+               rom_entries[i].name = NULL;
                free(rom_entries[i].file);
                rom_entries[i].file = NULL;
                rom_entries[i].included = 0;
diff --git a/util/convert_layout_v1_to_v2.sh b/util/convert_layout_v1_to_v2.sh
new file mode 100755
index 0000000..712de87
--- /dev/null
+++ b/util/convert_layout_v1_to_v2.sh
@@ -0,0 +1,79 @@
+#!/bin/sh
+#
+#  Copyright 2013 Stefan Tauner
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+#  MA 02110-1301, USA.
+#
+#
+#
+# This script converts legacy layout files as understood by flashrom up to 
version 0.9.7 to format version 2.
+# It converts all files given as parameters in place and creates backups (with 
the suffix ".old") of the old
+# contents unless --nobackup is given.
+#
+# It does...
+# - check if the file exists and if its format is already in v2 format
+# - prefix addresses with 0x if they have not been already
+# - remove superfluous white space (i.e. more than one consecutive space)
+# - remove white space from otherwise empty lines
+
+usage ()
+{
+       echo "Usage: $0 [--nobackup] FILE..."
+       exit 1
+}
+
+if [ $# -eq 0 ]; then
+       usage
+fi
+
+if [ $1 = "--nobackup" ]; then
+       sed_opt="-i"
+       shift
+       if [ $# -eq 0 ]; then
+               usage
+       fi
+else
+       sed_opt="-i.old"
+fi
+
+# Test if all files are really there before starting conversion
+ret=0
+for f in "$@" ; do
+       if [ ! -e "$f" ]; then
+               echo "File not found: $f">&2
+               ret=1
+       fi
+done
+if [ "$ret" -ne 0 ]; then
+       echo "Aborting"
+       return 1
+fi
+
+for f in "$@" ; do
+       if grep -q 'flashrom layout v2\b' "$f" ; then
+               echo "File already in new format: $f"
+               continue
+       fi
+
+       sed $sed_opt -e "
+               1i # flashrom layout v2
+               s/ *\(0x\|\)\([0-9a-fA-F][0-9a-fA-F]*\) *: 
*\(0x\|\)\([0-9a-fA-F][0-9a-fA-F]*\) */0x\2:0x\4 /
+               s/   */ /
+               s/^ *$//
+               " "$f"
+       echo "$f done"
+done
+echo "Done!"
-- 
Kind regards, Stefan Tauner


_______________________________________________
flashrom mailing list
[email protected]
http://www.flashrom.org/mailman/listinfo/flashrom

Reply via email to