User Tools

Site Tools


project:kernel-autobuild:kconfig:printconf

kconfig / printconf

The point of origin was the zconf_dump() routine.

As it turned out this was nothing like a “lint” or “dump” tool. It reports errors just because it's not supporting the kconfig syntax completely . It's obviously not the thing to mess with.

Next try was to implement the printconf stuff.

printconf.c
/*
 * V 5c
 * Released under the terms of the GNU GPL v2.0.
 */
 
#include <stdio.h>
#include <stdlib.h>
 
#include "lkc.h"
 
void printconf(FILE *);
void printsym(FILE *, struct menu *);
 
int main(int ac, char **av)
{
	const char *name;
 
	if (ac != 2) exit(1);
 
	name = av[1];
	conf_parse(name);
	printconf(stdout);
	/*zconfdump(stdout);*/
	return 0;
}
 
void decodeflags (FILE *out, int flags);
void decodeflags (FILE *out, int flags) {
	/* taken from expr.h */
	int flaglist[] = 
	{ 
		SYMBOL_CONST    , /* 0x0001  symbol is const */
		SYMBOL_CHECK    , /* 0x0008  used during dependency checking */
		SYMBOL_CHOICE   , /* 0x0010  start of a choice block (null name) */
		SYMBOL_CHOICEVAL, /* 0x0020  used as a value in a choice block */
		SYMBOL_VALID    , /* 0x0080  set when symbol.curr is calculated */
		SYMBOL_OPTIONAL , /* 0x0100  choice is optional - values can be 'n' */
		SYMBOL_WRITE    , /* 0x0200  ? */
		SYMBOL_CHANGED  , /* 0x0400  ? */
		SYMBOL_AUTO     , /* 0x1000  value from environment variable */
		SYMBOL_CHECKED  , /* 0x2000  used during dependency checking */
		SYMBOL_WARNED   , /* 0x8000  warning has been issued */
		0x0
	};
	char *flagnames[] = {
		"CONST"    , /* 0x0001  symbol is const */
		"CHECK"    , /* 0x0008  used during dependency checking */
		"CHOICE"   , /* 0x0010  start of a choice block (null name) */
		"CHOICEVAL", /* 0x0020  used as a value in a choice block */
		"VALID"    , /* 0x0080  set when symbol.curr is calculated */
		"OPTIONAL" , /* 0x0100  choice is optional - values can be 'n' */
		"WRITE"    , /* 0x0200  ? */
		"CHANGED"  , /* 0x0400  ? */
		"AUTO"     , /* 0x1000  value from environment variable */
		"CHECKED"  , /* 0x2000  used during dependency checking */
		"WARNED"     /* 0x8000  warning has been issued */
	};
 
 
	fprintf(out,"\t");
	int i;
	for(i=0; flaglist[i]; i++) {
		if (flags & flaglist[i]) {
			fprintf(out,"<flag>%s</flag>",flagnames[i]);
		}
	}
	fprintf(out,"\n");
}
 
void decodeexpr_type(FILE *out, char* tagname,int val);
void decodeexpr_type(FILE *out, char* tagname,int val) {
	char *value;
	switch (val) {
		case E_NONE:
			value = "NONE";
			break;
		case E_OR:
			value = "OR";
			break;
		case E_AND:
			value = "AND";
			break;
		case E_NOT:
			value = "NOT";
			break;
		case E_EQUAL:
			value = "EQUAL";
			break;
		case E_UNEQUAL:
			value = "UNEQUAL";
			break;
		case E_LIST:
			value = "LIST";
			break;
		case E_SYMBOL:
			value = "SYMBOL";
			break;
		case E_RANGE:
			value = "RANGE";
			break;
		default:
			fprintf(stderr, "ERROR: decodeexpr_type() '%d': should never happen\n",val);
			exit(1);
	}
 
	fprintf(out, "\t<%s>%s</%s>\n", tagname, value, tagname);
}
 
void decodesym(FILE *out, char* tagname,struct symbol_value symval);
void decodesym(FILE *out, char* tagname,struct symbol_value symval) {
 
	fprintf(out, "\t<%s>%s</%s>\n", tagname, (char *)symval.val, tagname);
}
 
void printsym(FILE *out, struct menu *menu)
{
	struct property *prop;
	// int have_properties = 0;
	int open_menu = 0;
 
	fprintf(out, "<option>\n");
	if (menu->sym->name)
		fprintf(out, "\t<symbol>%s</symbol>\n", menu->sym->name);
	if (menu->prompt)
		fprintf(out, "\t<prompt><![CDATA[%s]]></prompt>\n", menu->prompt->text);
	if (menu->help)
		fprintf(out, "\t<help><![CDATA[%s]]></help>\n", menu->help);
	switch (menu->sym->type) {
		case S_UNKNOWN:
			fprintf(out, "\t<type>%s</type>\n", "unknown");
			break;
		case S_BOOLEAN:
			fprintf(out, "\t<type>%s</type>\n", "boolean");
			break;
		case S_TRISTATE:
			fprintf(out, "\t<type>%s</type>\n", "tristate");
			break;
		case S_INT:
			fprintf(out, "\t<type>%s</type>\n", "int");
			break;
		case S_HEX:
			fprintf(out, "\t<type>%s</type>\n", "hex");
			break;
		case S_STRING:
			fprintf(out, "\t<type>%s</type>\n", "string");
			break;
		case S_OTHER:
			fprintf(out, "\t<type>%s</type>\n", "other");
			break;
		default:
			fprintf(out, "\t<type>unknown=%d</type>\n", menu->sym->type);
	}
		for (prop = menu->sym->prop; prop; prop = prop->next) {
			if (prop->menu != menu)
				continue;
			switch (prop->type) {
			case P_PROMPT:
				fprintf(out, "\t<property.prompt>\n\t\t<value>");
 
				expr_fprint(prop->expr, out);
				fprintf(out, "</value>\n");
				if (!expr_is_yes(prop->visible.expr)) {
					fprintf(out, "\t\t<cond><![CDATA[");
					expr_fprint(prop->visible.expr, out);
					fprintf(out,"]]></cond>\n");
				}
				fprintf(out, "\t</property.prompt>\n");
				break;
			case P_DEFAULT:
				fprintf(out, "\t<property.default>\n");
				fprintf(out, "\t\t<value><![CDATA[");
				expr_fprint(prop->expr, out);
				fprintf(out, "]]></value>\n");
				if (!expr_is_yes(prop->visible.expr)) {
					fprintf(out, "\t\t<cond><![CDATA[");
					expr_fprint(prop->visible.expr, out);
					fprintf(out,"]]></cond>\n");
				}
				fprintf(out, "\t</property.default>\n");
				break;
			case P_CHOICE:
				fprintf(out, "\t<property.choice/>\n");
				break;
			case P_SELECT:
				fprintf(out, "\t<property.select>");
				expr_fprint(prop->expr, out);
				fprintf(out, "</property.select>\n");
				break;
			case P_RANGE:
				fprintf(out, "\t<property.range>");
				expr_fprint(prop->expr, out);
				fprintf(out, "</property.range>\n");
				break;
			case P_MENU:
				fprintf(out, "\t<property.menu>");
				expr_fprint(prop->expr, out);
				fprintf(out, "</property.menu>\n");
				open_menu = 1;
				break;
			case P_SYMBOL:
				fprintf(out, "\t<property.symbol/>\n");
				break;
			default:
				fprintf(stderr, "unknown property type: %d\n", prop->type);
			}
		}
	decodeflags(out,menu->sym->flags);
	fprintf(out, "\t<file>%s</file>\n", menu->sym->prop->file->name);
	fprintf(out, "\t<lineno>%d</lineno>\n", menu->sym->prop->lineno);
	fprintf(out, "\t<visible>%s</visible>\n", expr_is_yes(menu->sym->prop->visible.expr) ? "y" : "n");
	fprintf(out, "\t<flags>0x%x</flags>\n",menu->sym->flags);
 
	fprintf(out, "</option>\n");
	if (open_menu)
		// fprintf(out, "<menu><!--%s-->\n", menu->sym->name);
		fprintf(out, "<menu name=\"%s\" file=\"%s\" lineno=\"%d\">\n", menu->sym->name,menu->sym->prop->file->name,menu->sym->prop->lineno);
}
 
void tag (FILE *out, char *tagname, char *value);
void tag (FILE *out, char *tagname, char *value) {
	fprintf(out, "\t<%s>%s</%s>\n", tagname, value, tagname);
}
 
void printconf(FILE *out)
{
	/* struct property *prop; */
	struct menu *menu;
 
	fprintf(out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
	fprintf(out, "<kconfig formatversion=\"20140523-083928\" kernelversion=\"3.10.39\">\n");
	fprintf(out, "<menu><!--root menu-->\n");
 
	menu = rootmenu.list;
	while (menu) {
		if ( menu->prompt ) {
			switch (menu->prompt->type) {
				case P_UNKNOWN:
					fprintf(out, "\t<propertytype>%s</propertytype>\n", "unknown");
					break;
				case P_PROMPT:   /* prompt "foo prompt" or "BAZ Value" */
					 // fprintf(out, "\t<propertytype>%s</propertytype>\n", "prompt");
					break;
				case P_COMMENT:  /* text associated with a comment */
					// fprintf(out, "\t<propertytype>%s</propertytype>\n", "comment");
					break;
				case P_MENU:     /* prompt associated with a menuconfig option */
					// fprintf(out, "\t<propertytype>%s</propertytype>\n", "menu");
					break;
				case P_DEFAULT:  /* default y */
					fprintf(out, "\t<propertytype>%s</propertytype>\n", "default");
					break;
				case P_CHOICE:   /* choice value */
					fprintf(out, "\t<propertytype>%s</propertytype>\n", "choice");
					break;
				case P_SELECT:   /* select BAR */
					fprintf(out, "\t<propertytype>%s</propertytype>\n", "select");
					break;
				case P_RANGE:    /* range 7..100 (for a symbol) */
					fprintf(out, "\t<propertytype>%s</propertytype>\n", "range");
					break;
				case P_ENV:      /* value from environment variable */
					fprintf(out, "\t<propertytype>%s</propertytype>\n", "env");
					break;
				case P_SYMBOL:   /* where a symbol is defined */
					fprintf(out, "\t<propertytype>%s</propertytype>\n", "symbol");
					break;
				default:
					fprintf(stderr, "ERROR: menu->prompt->type '%d': should never happen\n",menu->prompt->type);
					exit(1);
			}
		}
		if (menu->sym) {
			printsym(out, menu);
		} else if (menu->prompt) {
			switch (menu->prompt->type) {
			case P_COMMENT:
				fprintf(out, "<comment>%s</comment>\n", menu->prompt->text);
				break;
			case  P_MENU:
				if ( menu->sym ) {
					fprintf(out, "<menu name=\"%s\" file=\"%s\" lineno=\"%d\">\n\t<symbol>%s</symbol>\n", menu->sym->name,    menu->sym->prop->file->name, menu->sym->prop->lineno, menu->prompt->text);
				} else {
					fprintf(out, "<menu name=\"%s\" file=\"%s\" lineno=\"%d\" f=\"3\">\n\t<symbol>%s</symbol>\n", menu->prompt->text, menu->prompt->file->name, menu->prompt->file->lineno, menu->prompt->text);
				}
				// fprintf(out, "<menu name=\"%s\" file=\"%s\" lineno=\"%d\">\n", menu->sym->name,menu->sym->prop->file->name,menu->sym->prop->lineno);
				break;
			case P_PROMPT:
				fprintf(out, "<prompt><![CDATA[%s]]></prompt>\n", menu->prompt->text);
				break;
			default:
				fprintf(stderr, "ERROR: menu->prompt->type '%d': should never happen\n",menu->prompt->type);
				exit(1);
			}
			if (menu->visibility) {
				decodeexpr_type(out,"visibility",menu->visibility->type);
			}
		}
		if (menu->list)
			menu = menu->list;
		else if (menu->next)
			menu = menu->next;
		else while ((menu = menu->parent)) {
			if (menu->prompt && menu->prompt->type == P_MENU)
				fprintf(out, "</menu><!--%s-->\n", menu->sym?menu->sym->name:menu->prompt->text);
			if (menu->next) {
				menu = menu->next;
				break;
			}
		}
	}
	fprintf(out, "</menu><!--root menu-->\n");
	fprintf(out, "</kconfig>\n");
}

Then there is an assertion to be thrown on empty values, even if they are perfectly legal. The following patch helps:

lkc.h.diff
--- lkc.h.orig	2014-05-21 11:35:33.210489800 +0200
+++ lkc.h	2014-05-21 11:35:33.210489800 +0200
@@ -90,7 +90,10 @@ struct conf_printer {
 /* confdata.c and expr.c */
 static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
 {
-	assert(len != 0);
+	/*assert(len != 0);*/
+	if (len==0) {
+		return;
+	}
 
 	if (fwrite(str, len, count, out) != count)
 		fprintf(stderr, "Error in writing or end of file.\n");

To do things more easily, there is a script. You may want to change the settings of BASEDIR and DIR.

genKconfigXml
#! /bin/sh
 
if [ -z "$1" ]; then
	echo "usage: $0 <kernel-source-version>"
	exit 1
fi
 
KVER=$1
BASEDIR=/home/chris/prog/C/kconfig
DIR=/home/chris/work/scratch/ssd01/kernels/linux-$KVER/scripts/kconfig
 
if [ ! -e "$DIR" ]; then
	echo "$DIR does not exist"
	exit 1
fi 
if [ -e "$DIR" -a ! -d "$DIR" ]; then 
	echo "$DIR exists but is not a directory"
	exit 1
fi
 
if [ ! -e "$BASEDIR" ]; then
	echo "basedir '$BASEDIR' does not exist"
	exit 1
fi 
if [ -e "$BASEDIR" -a ! -d "$DIR" ]; then 
	echo "basedir '$BASEDIR' exists but is not a directory"
	exit 1
fi
 
cd $BASEDIR
 
# ln -s jo/printconf.c-5a ./printconf.c
cp printconf.c $DIR
cp patches/lkc.h.diff $DIR
#cp data/Kconfig* $DIR
 
cd $DIR
 
#flex  --outfile zconf.lex.c zconf.l     
#gperf zconf.gperf --output-file zconf.hash.c
#bison zconf.y
cp zconf.hash.c_shipped zconf.hash.c 
cp zconf.lex.c_shipped  zconf.lex.c  
cp zconf.tab.c_shipped  zconf.tab.c  
 
patch < lkc.h.diff
 
make () {
gcc -Wp,-MD,.conf.o.d -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer   -I/usr/include/ncursesw -DCURSES_LOC="<ncursesw/curses.h>" -DLOCALE   -c -o printconf.o printconf.c
gcc -Wp,-MD,.zconf.tab.o.d -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer   -I/usr/include/ncursesw -DCURSES_LOC="<ncursesw/curses.h>" -DLOCALE  -I. -c -o zconf.tab.o zconf.tab.c
gcc  -o printconf printconf.o zconf.tab.o
}
make
 
cd ../..
SRCARCH=x86 ARCH=x86 KERNELVERSION=$KVER scripts/kconfig/printconf Kconfig > Kconfig.xml
 
cp -ax Kconfig.xml ../kconfig-$KVER.xml

current problems

  • if running on kernel 3.10 some 37 </menu> tags are missing. 3.4's just fine.
  • there are “entities” which are reflected as <option> but without a <symbol> (Name). They fail if being read as XML which show's something's not understood, wrong or whatever.
project/kernel-autobuild/kconfig/printconf.txt · Last modified: 2014/05/30 17:07 by 37.209.107.48