Import old 'virt-mem-new' program.
[virt-kernel-info.git] / src / output.c
diff --git a/src/output.c b/src/output.c
new file mode 100644 (file)
index 0000000..0c15472
--- /dev/null
@@ -0,0 +1,174 @@
+/* Kernel info for virtual domains.
+ * (C) Copyright 2008-2010 Red Hat Inc.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Generic output routines which can write either plain
+ * text tables or CSV files.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "internal.h"
+
+static char *convert_fs_to_strings (const char *fs);
+static void output_to_csv (int to_strings, const char *fs, va_list args);
+
+void
+output_heading (const char *fs, ...)
+{
+  va_list args;
+
+  va_start (args, fs);
+
+  if (!csv) {
+    /* Convert each %..x in the format string into %..s */
+    char *fs2 = convert_fs_to_strings (fs);
+    vprintf (fs2, args);
+    free (fs2);
+    printf ("\n");
+  } else
+    output_to_csv (1, fs, args);
+
+  va_end (args);
+}
+
+void
+output_row (const char *fs, ...)
+{
+  va_list args;
+
+  va_start (args, fs);
+
+  if (!csv) {
+    vprintf (fs, args);
+    printf ("\n");
+  }
+  else
+    output_to_csv (0, fs, args);
+
+  va_end (args);
+}
+
+/* Return a newly allocated format string with each '%..x' sequence
+ * converted to '%..s'.  We only attempt to parse simple format
+ * strings, and we assume the length of the format string won't
+ * change.
+ */
+static const char *end_of_specifier = "diouxXeEfFgGaAcsp%";
+
+static char *
+convert_fs_to_strings (const char *fs)
+{
+  char *fs2;
+  int i, len;
+
+  len = strlen (fs);
+  fs2 = strdup (fs);
+  for (i = 0; i < len; ++i) {
+    if (fs2[i] == '%') {
+      /* Search for the end of the %-sequence. */
+      do { i++; }
+      while (i < len && strchr (end_of_specifier, fs2[i]) == NULL);
+
+      if (i == len)
+       internal_error (_("unrecognized format string in output_heading function"));
+
+      fs2[i] = 's';
+    }
+  }
+
+  return fs2; /* caller frees */
+}
+
+/* Output a row to a CSV file.  The format string is just used to
+ * get the correct types for each parameter - any non-%-specifiers
+ * in the format string are ignored.  If to_strings is true, then
+ * each parameter is assumed to be a string.
+ *
+ * The CSV output is very conservative, designed to be correct
+ * rather than concise.
+ */
+static void
+output_to_csv (int to_strings, const char *fs, va_list args)
+{
+  int i, j, len, comma = 0;
+  char fs2[16];
+
+  len = strlen (fs);
+
+  for (i = 0; i < len; ++i) {
+    /* Look for the next %-specifier. */
+    if (fs[i] == '%') {
+      j = 0;
+      do { fs2[j++] = fs[i++]; }
+      while (j < sizeof (fs2) - 1 &&
+            i < len &&
+            strchr (end_of_specifier, fs[i]) == NULL);
+
+      if (j == sizeof (fs2) - 1 || i == len)
+       internal_error (_("unrecognized format string in output_* function"));
+
+      fs2[j] = fs[i++];
+      fs2[j+1] = '\0';
+    }
+
+    if (fs2[j] != '%') {
+      char *str;
+      int len2;
+
+      if (to_strings)
+       fs2[j] = 's';
+
+      /* Convert the next parameter into a string. */
+      if (vasprintf (&str, fs2, args) == -1)
+       internal_error (_("unable to convert next argument to string using '%s'"),
+                       fs2);
+      len2 = strlen (str);
+
+      /* Output the next parameter as a CSV field. */
+      if (comma)
+       putchar (',');
+      comma = 1;
+
+      putchar ('"');
+      for (j = 0; j < len2; ++j) {
+       switch (str[j]) {
+       case '"':
+         putchar ('"');
+         putchar ('"');
+         break;
+       case '\0':
+         putchar ('"');
+         putchar ('0');
+         break;
+       default:
+         putchar (str[j]);
+       }
+      }
+      putchar ('"');
+
+      free (str);
+    }
+  }
+
+  putchar ('\n');
+}