Implement libvirt calls.
[virt-kernel-info.git] / src / output.c
1 /* Kernel info for virtual domains.
2  * (C) Copyright 2008-2010 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 /* Generic output routines which can write either plain
20  * text tables or CSV files.
21  */
22
23 #include <config.h>
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <stdarg.h>
28 #include <string.h>
29
30 #include "internal.h"
31
32 static char *convert_fs_to_strings (const char *fs);
33 static void output_to_csv (int to_strings, const char *fs, va_list args);
34
35 void
36 output_heading (const char *fs, ...)
37 {
38   va_list args;
39
40   va_start (args, fs);
41
42   if (!csv) {
43     /* Convert each %..x in the format string into %..s */
44     char *fs2 = convert_fs_to_strings (fs);
45     vprintf (fs2, args);
46     free (fs2);
47     printf ("\n");
48   } else
49     output_to_csv (1, fs, args);
50
51   va_end (args);
52 }
53
54 void
55 output_row (const char *fs, ...)
56 {
57   va_list args;
58
59   va_start (args, fs);
60
61   if (!csv) {
62     vprintf (fs, args);
63     printf ("\n");
64   }
65   else
66     output_to_csv (0, fs, args);
67
68   va_end (args);
69 }
70
71 /* Return a newly allocated format string with each '%..x' sequence
72  * converted to '%..s'.  We only attempt to parse simple format
73  * strings, and we assume the length of the format string won't
74  * change.
75  */
76 static const char *end_of_specifier = "diouxXeEfFgGaAcsp%";
77
78 static char *
79 convert_fs_to_strings (const char *fs)
80 {
81   char *fs2;
82   int i, len;
83
84   len = strlen (fs);
85   fs2 = strdup (fs);
86   for (i = 0; i < len; ++i) {
87     if (fs2[i] == '%') {
88       /* Search for the end of the %-sequence. */
89       do { i++; }
90       while (i < len && strchr (end_of_specifier, fs2[i]) == NULL);
91
92       if (i == len)
93         internal_error (_("unrecognized format string in output_heading function"));
94
95       fs2[i] = 's';
96     }
97   }
98
99   return fs2; /* caller frees */
100 }
101
102 /* Output a row to a CSV file.  The format string is just used to
103  * get the correct types for each parameter - any non-%-specifiers
104  * in the format string are ignored.  If to_strings is true, then
105  * each parameter is assumed to be a string.
106  *
107  * The CSV output is very conservative, designed to be correct
108  * rather than concise.
109  */
110 static void
111 output_to_csv (int to_strings, const char *fs, va_list args)
112 {
113   int i, j, len, comma = 0;
114   char fs2[16];
115
116   len = strlen (fs);
117
118   for (i = 0; i < len; ++i) {
119     /* Look for the next %-specifier. */
120     if (fs[i] == '%') {
121       j = 0;
122       do { fs2[j++] = fs[i++]; }
123       while (j < sizeof (fs2) - 1 &&
124              i < len &&
125              strchr (end_of_specifier, fs[i]) == NULL);
126
127       if (j == sizeof (fs2) - 1 || i == len)
128         internal_error (_("unrecognized format string in output_* function"));
129
130       fs2[j] = fs[i++];
131       fs2[j+1] = '\0';
132     }
133
134     if (fs2[j] != '%') {
135       char *str;
136       int len2;
137
138       if (to_strings)
139         fs2[j] = 's';
140
141       /* Convert the next parameter into a string. */
142       if (vasprintf (&str, fs2, args) == -1)
143         internal_error (_("unable to convert next argument to string using '%s'"),
144                         fs2);
145       len2 = strlen (str);
146
147       /* Output the next parameter as a CSV field. */
148       if (comma)
149         putchar (',');
150       comma = 1;
151
152       putchar ('"');
153       for (j = 0; j < len2; ++j) {
154         switch (str[j]) {
155         case '"':
156           putchar ('"');
157           putchar ('"');
158           break;
159         case '\0':
160           putchar ('"');
161           putchar ('0');
162           break;
163         default:
164           putchar (str[j]);
165         }
166       }
167       putchar ('"');
168
169       free (str);
170     }
171   }
172
173   putchar ('\n');
174 }