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