From 3f1bae2aa3d7ac6129e03fec9b983fe228427b7d Mon Sep 17 00:00:00 2001
From: Mathias Hasselmann <mathias.hasselmann@gmx.de>
Date: Wed, 5 Sep 2007 23:59:40 +0200
Subject: [PATCH] c2xml: Implement support for command line options, but this time

without conflicting with the builtin options of sparse.

Signed-off-by: Mathias Hasselmann <mathias.hasselmann@gmx.de>
---
 c2xml.c |  186 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 166 insertions(+), 20 deletions(-)

diff --git a/c2xml.c b/c2xml.c
index 0833b2c..f477361 100644
--- a/c2xml.c
+++ b/c2xml.c
@@ -11,6 +11,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <libgen.h>
 #include <fcntl.h>
 #include <assert.h>
 #include <libxml/parser.h>
@@ -21,6 +22,12 @@
 #include "scope.h"
 #include "symbol.h"
 
+#define DOCTYPE_URI "http://www.kernel.org/pub/software/devel/sparse/parse.dtd"
+
+static const char *target_filename = "-";
+static int include_positions = 1;
+static int include_doctype = 0;
+
 static xmlDocPtr doc = NULL;       /* document pointer */
 static xmlNodePtr root_node = NULL;/* root node pointer */
 static int idcount = 0;
@@ -50,18 +57,20 @@ static void newPositionProps(xmlNodePtr node, struct position pos, struct positi
 {
 	newProp(node, "file", stream_name(pos.stream));
 
-	newNumProp(node, "start-line", pos.line);
-	newNumProp(node, "start-col", pos.pos);
-
-	if (endpos.type
-            && (pos.line != endpos.line
-            ||  pos.pos != endpos.pos
-            ||  pos.stream != endpos.stream)) {
-		newNumProp(node, "end-line", endpos.line);
-		newNumProp(node, "end-col", endpos.pos);
-		if (pos.stream != endpos.stream)
-			newProp(node, "end-file", stream_name(endpos.stream));
-        }
+	if (include_positions) {
+		newNumProp(node, "start-line", pos.line);
+		newNumProp(node, "start-col", pos.pos);
+
+		if (endpos.type
+		    && (pos.line != endpos.line
+		    ||  pos.pos != endpos.pos
+		    ||  pos.stream != endpos.stream)) {
+			newNumProp(node, "end-line", endpos.line);
+			newNumProp(node, "end-col", endpos.pos);
+			if (pos.stream != endpos.stream)
+				newProp(node, "end-file", stream_name(endpos.stream));
+		}
+	}
 }
 
 static xmlNodePtr new_sym_node(struct ident *ident, const char *type,
@@ -463,24 +472,160 @@ static void initialize_attributes(void)
 	init_keyword_table (-1, attribute_table, sizeof attribute_table/sizeof attribute_table[0]);
 }
 
+static int set_filename(char *filename)
+{
+	target_filename = filename;
+	return 1;
+}
+
+static int set_option(char *name)
+{
+	int value = 1;
+
+	if (!strncmp(name, "no-", 3)) {
+		name += 3;
+		value = 0;
+	}
+
+	if (!strcmp(name, "positions")) {
+		include_positions = value;
+	} else if (!strcmp(name, "doctype")) {
+		include_doctype = value;
+	} else {
+		return -1;
+	}
+
+	return 0;
+}
+
+static int print_usage(char *arg0);
+
+static const struct {
+	const char name;
+	int (*parse)(char *arg);
+	const char *value_name;
+	const char *description;
+} options[] = {
+	{ 'o', set_filename, "FILENAME", "write the document to FILENAME" },
+	{ 'f', set_option,   "OPTION",   "enables an option, prefix `no-' disables" },
+	{ 'h', print_usage,   NULL,      "display this usage information" },
+	{ 0, NULL }
+};
+
+static int print_usage(char *arg0)
+{
+	size_t maxlen;
+	int i;
+
+	printf("Usage: %s [OPTION]... [FILE]...\n"
+	       "Parses C code and outputs the results as XML document.\n\n"
+	       "Options:\n", basename(arg0));
+
+	for (i = 0, maxlen = 0; options[i].name; ++i) {
+		if (options[i].value_name) {
+			size_t len = strlen(options[i].value_name);
+			maxlen = (len > maxlen ? len : maxlen);
+		}
+	}
+
+	for (i = 0; options[i].name; ++i) {
+		printf("  -%c %*s  %s\n", options[i].name, -maxlen,
+		       options[i].value_name ? options[i].value_name : "",
+		       options[i].description);
+	}
+
+	printf("\nReport bugs to <linux-sparse@vger.kernel.org>\n");
+
+	exit(0);
+}
+
+static int parse_switch(char *arg0, char **args)
+{
+	int i;
+
+	for (i = 0; options[i].name; ++i) {
+		if (options[i].name == args[0][1])
+			break;
+	}
+
+	if (options[i].name) {
+		char *value = NULL;
+		int offset = 0;
+
+		if (options[i].value_name) {
+			if (args[0][2]) {
+				value = args[0] + 2;
+				offset = 1;
+			} else if (args[1]) {
+				value = args[1];
+				offset = 2;
+			} else {
+				return -1;
+			}
+		} else {
+			if (args[0][2])
+				return -1;
+
+			value = arg0;
+			offset = 1;
+		}
+
+		if (!options[i].parse(value))
+			return offset;
+	}
+
+	return 0;
+}
+
+static int parse_options(int *argc, char ***argv)
+{
+	char **args = *argv + 1;
+	char *arg0 = *argv[0];
+
+	while (*args) {
+		if ('-' == args[0][0] && args[0][1]) {
+			int offset = parse_switch(arg0, args);
+
+			if (-1 == offset) {
+				fprintf (stderr, "Invalid option: %c\n", *args[1]);
+				return 2;
+			} else if (offset > 0)  {
+				char **next = args + offset;
+				int count = *argc - (next - *argv) + 1;
+
+				memmove(args, next, count * sizeof(char*));
+				*argc -= offset;
+
+				continue;
+			}
+		}
+
+		++args;
+	}
+
+	return 0;
+}
+
 int main(int argc, char **argv)
 {
 	struct string_list *filelist = NULL;
 	struct symbol_list *symlist = NULL;
+
 	char *file;
+	int rc;
+
+	if (0 != (rc = parse_options(&argc, &argv)))
+		return rc;
 
 	doc = xmlNewDoc(BAD_CAST "1.0");
 	root_node = xmlNewNode(NULL, BAD_CAST "parse");
 	xmlDocSetRootElement(doc, root_node);
 
-/* - A DTD is probably unnecessary for something like this
-
-	dtd = xmlCreateIntSubset(doc, "parse", "http://www.kernel.org/pub/software/devel/sparse/parse.dtd" NULL, "parse.dtd");
-
-	ns = xmlNewNs (root_node, "http://www.kernel.org/pub/software/devel/sparse/parse.dtd", NULL);
+	if (include_doctype) {
+		xmlCreateIntSubset(doc, BAD_CAST "parse", BAD_CAST DOCTYPE_URI, BAD_CAST "parse.dtd");
+		xmlSetNs(root_node, xmlNewNs (root_node, BAD_CAST DOCTYPE_URI, NULL));
+	}
 
-	xmlSetNs(root_node, ns);
-*/
 	symlist = sparse_initialize(argc, argv, &filelist);
 	initialize_attributes();
 
@@ -492,7 +637,8 @@ int main(int argc, char **argv)
 	} END_FOR_EACH_PTR_NOTAG(file);
 
 
-	xmlSaveFormatFileEnc("-", doc, "UTF-8", 1);
+	xmlSaveFormatFileEnc(target_filename, doc, "UTF-8", 1);
+
 	xmlFreeDoc(doc);
 	xmlCleanupParser();
 
-- 
1.5.2.3

