--- /dev/null
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <simgear/props/props.hxx>
+#include <simgear/props/props_io.hxx>
+#include <simgear/structure/exception.hxx>
+
+
+unsigned int _fcount = 0;
+char **_filenames = 0;
+char *_element = 0;
+char *_value = 0;
+char *_root = 0;
+char *_print = 0;
+
+int print_filenames = 0;
+
+#define DEBUG 0
+
+void free_and_exit(int i);
+
+
+#define SHOW_NOVAL(opt) \
+{ \
+ printf("option '%s' requires a value\n\n", (opt)); \
+ free_and_exit(-1); \
+}
+
+void show_help ()
+{
+ printf("usage: xmlgrep [options] [file ...]\n\n");
+ printf("Options:\n");
+ printf("\t-h\t\tshow this help message\n");
+ printf("\t-e <id>\t\tshow sections that contain this element\n");
+ printf("\t-p <id>\t\tprint this element as the output\n");
+ printf("\t-r <path>\tspecify the XML search root\n");
+ printf("\t-v <string>\tshow sections where on of the elements has this value \n");
+ printf("\n");
+ printf(" To print the contents of the 'type' element of the XML section ");
+ printf("that begins\n at '/printer/output' one would use the following ");
+ printf("syntax:\n\n\txmlgrep -r /printer/output -p type sample.xml\n\n");
+ printf(" To filter out sections that contain the 'driver' element with ");
+ printf("'generic' as\n it's value one would issue the following command:\n");
+ printf("\n\txmlgrep -r /printer/output -e driver -v generic -p type ");
+ printf("sample.xml\n\n");
+ free_and_exit(0);
+}
+
+void free_and_exit(int i)
+{
+ if (_root) free(_root);
+ if (_value) free(_value);
+ if (_element) free(_element);
+ if (_filenames)
+ {
+ for (i=0; i < _fcount; i++) {
+ if (_filenames[i]) {
+ if (print_filenames) printf("%s\n", _filenames[i]);
+ free(_filenames[i]);
+ }
+ }
+ free(_filenames);
+ }
+
+ exit(i);
+}
+
+int parse_option(char **args, int n, int max) {
+ char *opt, *arg = 0;
+ int sz;
+
+ opt = args[n];
+ if (opt[0] == '-' && opt[1] == '-')
+ opt++;
+
+ if ((arg = strchr(opt, '=')) != NULL)
+ *arg++ = 0;
+
+ else if (++n < max)
+ {
+ arg = args[n];
+ if (arg && arg[0] == '-')
+ arg = 0;
+ }
+
+#if DEBUG
+ fprintf(stderr, "processing '%s'='%s'\n", opt, arg ? arg : "NULL");
+#endif
+
+ sz = strlen(opt);
+ if (strncmp(opt, "-help", sz) == 0) {
+ show_help();
+ }
+
+ else if (strncmp(opt, "-root", sz) == 0) {
+ if (arg == 0) SHOW_NOVAL(opt);
+ _root = strdup(arg);
+#if DEBUG
+ fprintf(stderr, "\troot=%s\n", _root);
+#endif
+ return 2;
+ }
+
+ else if (strncmp(opt, "-element", sz) == 0) {
+ if (arg == 0) SHOW_NOVAL(opt);
+ _element = strdup(arg);
+#if DEBUG
+ fprintf(stderr, "\telement=%s\n", _element);
+#endif
+ return 2;
+ }
+
+ else if (strncmp(opt, "-value", sz) == 0) {
+ if (arg == 0) SHOW_NOVAL(opt);
+ _value = strdup(arg);
+#if DEBUG
+ fprintf(stderr, "\tvalue=%s\n", _value);
+#endif
+ return 2;
+ }
+
+ else if (strncmp(opt, "-print", sz) == 0) {
+ if (arg == 0) SHOW_NOVAL(opt);
+ _print = strdup(arg);
+#if DEBUG
+ fprintf(stderr, "\tprint=%s\n", _print);
+#endif
+ return 2;
+ }
+
+
+ /* undocumented test argument */
+ else if (strncmp(opt, "-list-filenames", sz) == 0) {
+ print_filenames = 1;
+ return 1;
+ }
+
+ else if (opt[0] == '-') {
+ printf("Unknown option %s\n", opt);
+ free_and_exit(-1);
+ }
+
+ else {
+ int pos = _fcount++;
+ if (_filenames == 0)
+ _filenames = (char **)malloc(sizeof(char*));
+ else {
+ char **ptr = (char **)realloc(_filenames, _fcount*sizeof(char*));
+ if (ptr == 0) {
+ printf("Out of memory.\n\n");
+ free_and_exit(-1);
+ }
+ _filenames = ptr;
+ }
+
+ _filenames[pos] = strdup(opt);
+#if DEBUG
+ fprintf(stderr, "\tadding filenames[%i]='%s'\n", pos, _filenames[pos]);
+#endif
+ }
+
+ return 1;
+}
+
+void grep_file(unsigned num)
+{
+ SGPropertyNode root, *path;
+
+#if DEBUG
+ fprintf(stderr, "Reading filenames[%i]: %s ... ", num, _filenames[num]);
+#endif
+ try {
+ readProperties(_filenames[num], &root);
+ } catch (const sg_exception &e) {
+ fprintf(stderr, "Error reading file '%s'\n", _filenames[num]);
+ // free_and_exit(-1);
+ return;
+ }
+#if DEBUG
+ fprintf(stderr, "done.\n");
+#endif
+
+ if ((path = root.getNode(_root, false)) != NULL)
+ {
+ SGPropertyNode *elem;
+
+ if (_element && _value)
+ {
+ if ((elem = path->getNode(_element, false)) != NULL)
+ {
+ if (strcmp(elem->getStringValue(), _value) == NULL)
+ {
+ SGPropertyNode *print = path->getNode(_print, false);
+ if (print)
+ {
+ printf("%s: <%s>%s</%s>\n", _filenames[num],
+ _print, print->getStringValue(), _print);
+ }
+ }
+ }
+ }
+ else if (_element)
+ {
+ }
+ else if (_value)
+ {
+ }
+ }
+#if DEBUG
+ else
+ fprintf(stderr," No root node specified.\n");
+#endif
+}
+
+inline void grep_files()
+{
+#if DEBUG
+ fprintf(stderr, "Reading files ...\n");
+#endif
+ for (int i=0; i<_fcount; i++)
+ grep_file(i);
+}
+
+int
+main (int argc, char **argv)
+{
+ int i;
+
+ if (argc == 1)
+ show_help();
+
+ for (i=1; i<argc;)
+ {
+ int ret = parse_option(argv, i, argc);
+ i += ret;
+#if DEBUG
+ fprintf(stderr, "%i arguments processed.\n", ret);
+#endif
+ }
+
+
+ grep_files();
+
+ free_and_exit(0);
+
+ return 0;
+}