Support -g option to dump value string only (no key string, no quotes, no newline).

Added filter for exporting. Also added an export type for exporting value only.

Refined some comments too.

Change-Id: I97fdd408bd444094ccc3378564b37c252fcf213e

R=hungte@chromium.org,dhendrix@chromium.org
BUG=no bug id
TEST=Compile okay on Z600 and x86-*. Tested on Z600 machine:
vpd -f test  -s ABC=DEF -s DEF=GHI -s IJK=ABC
vpd -f test -l  # all show up
vpd -f test -g abc  # nothing shows up
vpd -f test -g ABC  # DEF is showed.
vpd -f test -l -g  # error check: need an argument for -g
vpd -f test -l -g XXX  # error check: -g and -l must be mutually exclusive.

Review URL: http://codereview.chromium.org/6849018
diff --git a/include/lib/lib_vpd.h b/include/lib/lib_vpd.h
index 91621ff..55f5ae6 100644
--- a/include/lib/lib_vpd.h
+++ b/include/lib/lib_vpd.h
@@ -37,8 +37,9 @@
   VPD_AS_LONG_AS = -1,
 };
 
-enum {
+enum {  /* export_type */
   VPD_EXPORT_KEY_VALUE = 1,
+  VPD_EXPORT_VALUE,
   VPD_EXPORT_AS_PARAMETER,
 };
 
@@ -47,6 +48,7 @@
   unsigned char *key;
   unsigned char *value;
   int pad_len;
+  int filter_out;  /* TRUE means not exported. */
   struct StringPair *next;
 };
 
@@ -172,6 +174,12 @@
                     unsigned char *buf,
                     int *generated);
 
+/* Set filter for exporting functions.
+ * If filter is NULL, resets the filter so that everything can be exported.
+ */
+int setContainerFilter(struct PairContainer *container,
+                       const uint8_t *filter);
+
 /*
  * Export the container content with human-readable text.
  *
diff --git a/lib/lib_vpd.c b/lib/lib_vpd.c
index 5eaedab..fa447aa 100644
--- a/lib/lib_vpd.c
+++ b/lib/lib_vpd.c
@@ -284,6 +284,7 @@
   } else {
     struct StringPair *new_pair = malloc(sizeof(struct StringPair));
     assert(new_pair);
+    memset(new_pair, 0, sizeof(struct StringPair));
 
     fillStringPair(new_pair, key, value, pad_len);
 
@@ -329,6 +330,27 @@
   return VPD_OK;
 }
 
+int setContainerFilter(struct PairContainer *container,
+                       const uint8_t *filter) {
+  struct StringPair *str;
+
+  for (str = container->first; str; str = str->next) {
+    if (filter) {
+      /*
+       * TODO(yjlou):
+       * Now, we treat the inputing filter string as plain string.
+       * Will support regular expression syntax in future if needed.
+       */
+      if (strcmp(str->key, filter)) {
+        str->filter_out = 1;
+      }
+    } else {
+      str->filter_out = 0;
+    }
+  }
+  return VPD_OK;
+}
+
 /* Export the container content with human-readable text. */
 int exportContainer(const int export_type,
                     const struct PairContainer *container,
@@ -344,6 +366,9 @@
   for (str = container->first; str; str = str->next) {
     int copy_len;
 
+    if (str->filter_out)
+      continue;
+
     if (export_type == VPD_EXPORT_AS_PARAMETER) {
       char pad_str[32];
       int pad_len;
@@ -355,26 +380,28 @@
       index += pad_len;
     }
 
-    /* double quote */
-    if ((index + 1 > max_buf_len)) return VPD_FAIL;
-    buf[index++] = '"';
+    if (export_type != VPD_EXPORT_VALUE) {
+      /* double quote */
+      if ((index + 1 > max_buf_len)) return VPD_FAIL;
+      buf[index++] = '"';
 
-    /* output key */
-    if ((index + strlen(str->key)) > max_buf_len) return VPD_FAIL;
-    strcpy(&buf[index], str->key);
-    index += strlen(str->key);
+      /* output key */
+      if ((index + strlen(str->key)) > max_buf_len) return VPD_FAIL;
+      strcpy(&buf[index], str->key);
+      index += strlen(str->key);
 
-    /* double quote */
-    if ((index + 1 > max_buf_len)) return VPD_FAIL;
-    buf[index++] = '"';
+      /* double quote */
+      if ((index + 1 > max_buf_len)) return VPD_FAIL;
+      buf[index++] = '"';
 
-    /* equal sign */
-    if ((index + 1 > max_buf_len)) return VPD_FAIL;
-    buf[index++] = '=';
+      /* equal sign */
+      if ((index + 1 > max_buf_len)) return VPD_FAIL;
+      buf[index++] = '=';
 
-    /* double quote */
-    if ((index + 1 > max_buf_len)) return VPD_FAIL;
-    buf[index++] = '"';
+      /* double quote */
+      if ((index + 1 > max_buf_len)) return VPD_FAIL;
+      buf[index++] = '"';
+    }
 
     /* output value */
     if (str->pad_len != VPD_AS_LONG_AS)
@@ -385,13 +412,15 @@
     memcpy(&buf[index], str->value, copy_len);
     index += copy_len;
 
-    /* double quote */
-    if ((index + 1 > max_buf_len)) return VPD_FAIL;
-    buf[index++] = '"';
+    if (export_type != VPD_EXPORT_VALUE) {
+      /* double quote */
+      if ((index + 1 > max_buf_len)) return VPD_FAIL;
+      buf[index++] = '"';
 
-    /* new line */
-    if ((index + 1 > max_buf_len)) return VPD_FAIL;
-    buf[index++] = '\n';
+      /* new line */
+      if ((index + 1 > max_buf_len)) return VPD_FAIL;
+      buf[index++] = '\n';
+    }
   }
 
   /* null terminator */
diff --git a/vpd.c b/vpd.c
index 90aca89..103d79a 100644
--- a/vpd.c
+++ b/vpd.c
@@ -548,6 +548,7 @@
   printf("      -i <partition>   Specify VPD partition name in fmap.\n");
   printf("      -l               List content in the file.\n");
   printf("      -O               Overwrite and re-format VPD partition.\n");
+  printf("      -g <key>         Print value string only.\n");
   printf("\n");
 }
 
@@ -555,7 +556,7 @@
   int opt;
   int option_index = 0;
   int retval = 0;
-  const char *optstring = "hf:E:s:p:i:lO";
+  const char *optstring = "hf:E:s:p:i:lOg:";
   static struct option long_options[] = {
     {"help", 0, 0, 'h'},
     {"file", 0, 0, 'f'},
@@ -565,9 +566,11 @@
     {"partition", 0, 0, 'i'},
     {"list", 0, 0, 'l'},
     {"overwrite", 0, 0, 'O'},
+    {"filter", 0, 0, 'g'},
     {0, 0, 0, 0}
   };
   char *filename = NULL;
+  char *filter_str = NULL;
   int write_back_to_flash = 0;
   int list_it = 0;
   int overwrite_it = 0;
@@ -640,8 +643,12 @@
                         * no new pair is given. */
         break;
 
+      case 'g':
+        filter_str = strdup(optarg);
+        break;
+
       default:
-        fprintf(stderr, "Invalid option, use --help for usage.\n");
+        fprintf(stderr, "Invalid option (%s), use --help for usage.\n", optarg);
         retval = 1;
         goto teardown;
         break;
@@ -656,6 +663,13 @@
   }
 
   if (generateTempFilenames() < 0) {
+    fprintf(stderr, "[ERROR] generateTempFilenames() returns failed.\n");
+    retval = 1;
+    goto teardown;
+  }
+
+  if (list_it && filter_str) {
+    fprintf(stderr, "[ERROR] -l and -g must be mutually exclusive.\n");
     retval = 1;
     goto teardown;
   }
@@ -682,14 +696,16 @@
 
   mergeContainer(&file, &argument);
 
-  if (list_it) {
+  if (list_it || filter_str) {
     /* Reserve larger size because the exporting generates longer string than
      * the encoded data. */
     uint8_t list_buf[BUF_LEN * 2];
     int list_len = 0;
 
-    if (VPD_OK != exportContainer(VPD_EXPORT_KEY_VALUE, &file,
-                                  sizeof(list_buf), list_buf, &list_len)) {
+    if (filter_str) setContainerFilter(&file, filter_str);
+    if (VPD_OK != exportContainer(
+          (filter_str) ? VPD_EXPORT_VALUE : VPD_EXPORT_KEY_VALUE,
+          &file, sizeof(list_buf), list_buf, &list_len)) {
       fprintf(stderr, "exportContainer(): Cannot generate string.\n");
       retval = 1;
       goto teardown;
@@ -716,6 +732,7 @@
 teardown:
   if (spd_data) free(spd_data);
   if (filename) free(filename);
+  if (filter_str) free(filter_str);
   destroyContainer(&file);
   destroyContainer(&argument);