]> git.mxchange.org Git - flightgear.git/blob - utils/xmlgrep/xmlgrep.c
b428504b204d28fe03519fb7736a1504af0362dc
[flightgear.git] / utils / xmlgrep / xmlgrep.c
1 #include <stdio.h>
2
3 #define _GNU_SOURCE
4 #include <stdlib.h>
5 #include <string.h>
6 #ifndef _MSC_VER
7 # include <strings.h>
8 #else
9 # define strncasecmp strnicmp
10 # include <stdlib.h>
11 #endif
12 #include <assert.h>
13
14 #include "xml.h"
15
16 static const char *_static_root = "/";
17 static const char *_static_element = "*";
18 static unsigned int _fcount = 0;
19 static char **_filenames = 0;
20 static char *_element = 0;
21 static char *_value = 0;
22 static char *_root = 0;
23 static char *_print = 0;
24 static char *_attribute = 0;
25 static int print_filenames = 0;
26
27 static void free_and_exit(int i);
28
29 #define NODE_NAME_LEN           256
30 #define STRING_LEN              2048
31
32 #define SHOW_NOVAL(opt) \
33 { \
34     printf("option '%s' requires a value\n\n", (opt)); \
35     free_and_exit(-1); \
36 }
37
38 void
39 show_help ()
40 {
41     printf("usage: xmlgrep [options] [file ...]\n\n");
42     printf("Options:\n");
43     printf("\t-h\t\tshow this help message\n");
44     printf("\t-a <string>\tprint this attribute as the output\n");
45     printf("\t-e <id>\t\tshow sections that contain this element\n");
46     printf("\t-p <id>\t\tprint this element as the output\n");
47     printf("\t-r <path>\tspecify the XML search root\n");
48     printf("\t-v <string>\tfilter sections that contain this vale\n\n");
49     printf(" To print the contents of the 'type' element of the XML section ");
50     printf("that begins\n at '/printer/output' use the following command:\n\n");
51     printf("\txmlgrep -r /printer/output -p type sample.xml\n\n");
52     printf(" To filter 'output' elements under '/printer' that have attribute");
53     printf(" 'n' set to '1'\n use the following command:\n\n");
54     printf("\txmlgrep -r /printer -p output -a n -v 1 sample.xml\n\n");
55     printf(" To filter out sections that contain the 'driver' element with ");
56     printf("'generic' as\n it's value use the following command:");
57     printf("\n\n\txmlgrep -r /printer/output -e driver -v generic sample.xml");
58     printf("\n\n");
59     free_and_exit(0);
60 }
61
62 void
63 free_and_exit(int ret)
64 {
65     if (_root && _root != _static_root) free(_root);
66     if (_element && _element != _static_element) free(_element);
67     if (_value) free(_value);
68     if (_print) free(_print);
69     if (_attribute) free(_attribute);
70     if (_filenames)
71     {
72         unsigned int i;
73         for (i=0; i < _fcount; i++)
74         {
75             if (_filenames[i])
76             {
77                 if (print_filenames) printf("%s\n", _filenames[i]);
78                 free(_filenames[i]);
79             }
80         }
81         free(_filenames);
82     }
83  
84     exit(ret);
85 }
86
87 int
88 parse_option(char **args, int n, int max)
89 {
90     char *opt, *arg = 0;
91     unsigned int alen = 0;
92     unsigned int olen;
93
94     opt = args[n];
95     if (strncmp(opt, "--", 2) == 0)
96         opt++;
97
98     if ((arg = strchr(opt, '=')) != NULL)
99     {
100         *arg++ = 0;
101     }
102     else if (++n < max)
103     {
104         arg = args[n];
105 #if 0
106         if (arg && arg[0] == '-')
107             arg = 0;
108 #endif
109     }
110
111     olen = strlen(opt);
112     if (strncmp(opt, "-help", olen) == 0)
113     {
114         show_help();
115     }
116     else if (strncmp(opt, "-root", olen) == 0)
117     {
118         if (arg == 0) SHOW_NOVAL(opt);
119         alen = strlen(arg)+1;
120         _root = malloc(alen);
121         memcpy(_root, arg, alen);
122         return 2;
123     }
124     else if (strncmp(opt, "-element", olen) == 0)
125     {
126         if (arg == 0) SHOW_NOVAL(opt);
127         alen = strlen(arg)+1;
128         _element = malloc(alen);
129         memcpy(_element, arg, alen);
130         return 2;
131     }
132     else if (strncmp(opt, "-value", olen) == 0)
133     {
134         if (arg == 0) SHOW_NOVAL(opt);
135         alen = strlen(arg)+1;
136         _value = malloc(alen);
137         memcpy(_value, arg, alen);
138         return 2;
139     }
140     else if (strncmp(opt, "-print", olen) == 0)
141     {
142         if (arg == 0) SHOW_NOVAL(opt);
143         alen = strlen(arg)+1;
144         _print = malloc(alen);
145         memcpy(_print, arg, alen);
146         return 2;
147     }
148     else if (strncmp(opt, "-attribute", olen) == 0)
149     {
150         if (arg == 0) SHOW_NOVAL(opt);
151         alen = strlen(arg)+1;
152         _attribute = malloc(alen);
153         memcpy(_attribute, arg, alen);
154         return 2;
155     }
156     else if (strncmp(opt, "-list-filenames", olen) == 0)
157     { /* undocumented test argument */
158         print_filenames = 1;
159         return 1;
160     }
161     else if (opt[0] == '-')
162     {
163         printf("Unknown option %s\n", opt);
164         free_and_exit(-1);
165     }
166     else
167     {
168         int pos = _fcount++;
169         if (_filenames == 0)
170         {
171             _filenames = (char **)malloc(sizeof(char*));
172         }
173         else
174         {
175             char **ptr = (char **)realloc(_filenames, _fcount*sizeof(char*));
176             if (ptr == 0)
177             {
178                 printf("Out of memory.\n\n");
179                 free_and_exit(-1);
180             }
181            _filenames = ptr;
182         }
183
184         alen = strlen(opt)+1;
185         _filenames[pos] = malloc(alen);
186         memcpy(_filenames[pos], opt, alen);
187     }
188
189     return 1;
190 }
191
192 void walk_the_tree(size_t num, void *xid, char *tree)
193 {
194     unsigned int i, no_elements;
195
196     if (!tree)                                  /* last node from the tree */
197     {
198         void *xmid = xmlMarkId(xid);
199         if (xmid && _print)
200         {
201             no_elements = xmlNodeGetNum(xid, _print);
202             for (i=0; i<no_elements; i++)
203             {
204                 if (xmlNodeGetPos(xid, xmid, _print, i) != 0)
205                 {
206                     char value[STRING_LEN];
207
208                     xmlCopyString(xmid, (char *)&value, STRING_LEN);
209                     if (_value && _attribute)
210                     {
211                        if (!xmlAttributeCompareString(xmid, _attribute, _value))
212                        {
213                           printf("%s: <%s %s=\"%s\">%s</%s>\n",
214                                  _filenames[num], _print, _attribute, _value,
215                                                   value, _print);
216                        }
217                     }
218                     else
219                     {
220                        printf("%s: <%s>%s</%s>\n",
221                               _filenames[num], _print, value, _print);
222                     }
223                 }
224             }
225             free(xmid);
226         }
227         else if (xmid && _value)
228         {
229             no_elements = xmlNodeGetNum(xmid, _element);
230             for (i=0; i<no_elements; i++)
231             {
232                 if (xmlNodeGetPos(xid, xmid, _element, i) != 0)
233                 {
234                     char nodename[NODE_NAME_LEN];
235
236                     xmlNodeCopyName(xmid, (char *)&nodename, NODE_NAME_LEN);
237                     if (xmlCompareString(xmid, _value) == 0)
238                     {
239                         printf("%s: <%s>%s</%s>\n",
240                                _filenames[num], nodename, _value, nodename);
241                     }
242                 }
243             }
244             free(xmid);
245         }
246         else if (xmid && _element)
247         {
248             char parentname[NODE_NAME_LEN];
249
250             xmlNodeCopyName(xid, (char *)&parentname, NODE_NAME_LEN);
251
252             no_elements = xmlNodeGetNum(xmid, _element);
253             for (i=0; i<no_elements; i++)
254             {
255                 if (xmlNodeGetPos(xid, xmid, _element, i) != 0)
256                 {
257                     char nodename[NODE_NAME_LEN];
258
259                     xmlNodeCopyName(xmid, (char *)&nodename, NODE_NAME_LEN);
260                     if (!strncasecmp((char*)&nodename, _element, NODE_NAME_LEN))
261                     {
262                         char value[NODE_NAME_LEN];
263                         xmlCopyString(xmid, (char *)&value, NODE_NAME_LEN);
264                         printf("%s: <%s> <%s>%s</%s> </%s>\n",
265                                 _filenames[num], parentname, nodename, value,
266                                                  nodename, parentname);
267                     }
268                 }
269             }
270         }
271         else printf("Error executing xmlMarkId\n");
272     }
273     else if (xid)                        /* walk the rest of the tree */
274     {
275         char *elem, *next;
276         void *xmid;
277
278         elem = tree;
279         if (*elem == '/') elem++;
280
281         next = strchr(elem, '/');
282         
283         xmid = xmlMarkId(xid);
284         if (xmid)
285         {
286             if (next)
287             {
288                *next++ = 0;
289             }
290
291             no_elements = xmlNodeGetNum(xid, elem);
292             for (i=0; i<no_elements; i++)
293             {
294                 if (xmlNodeGetPos(xid, xmid, elem, i) != 0)
295                     walk_the_tree(num, xmid, next);
296             }
297
298             if (next)
299             {
300                *--next = '/';
301             }
302
303             free(xmid);
304         }
305         else printf("Error executing xmlMarkId\n");
306     }
307 }
308
309
310 void grep_file(unsigned num)
311 {
312     void *xid;
313
314     xid = xmlOpen(_filenames[num]);
315     if (xid)
316     {
317        void *xrid = xmlMarkId(xid);
318        int r = 0;
319
320        walk_the_tree(num, xrid, _root);
321
322        r = xmlErrorGetNo(xrid, 0);
323        if (r)
324        {
325             size_t n = xmlErrorGetLineNo(xrid, 0);
326             size_t c = xmlErrorGetColumnNo(xrid, 0);
327             char *s = xmlErrorGetString(xrid, 1); /* clear the error */
328             printf("%s: at line %u, column %u: '%s'\n",_filenames[num], n,c, s);
329        }
330
331        free(xrid);
332     }
333     else
334     {
335         fprintf(stderr, "Error reading file '%s'\n", _filenames[num]);
336     }
337
338     xmlClose(xid);
339 }
340
341 int
342 main (int argc, char **argv)
343 {
344     int i;
345
346     if (argc == 1)
347         show_help();
348
349     for (i=1; i<argc;)
350     {
351         int ret = parse_option(argv, i, argc);
352         i += ret;
353     }
354
355     if (_root == 0) _root = (char *)_static_root;
356     if (_element == 0) _element = (char *)_static_element;
357
358     for (i=0; i<_fcount; i++)
359         grep_file(i);
360
361     free_and_exit(0);
362
363     return 0;
364 }