diff options
Diffstat (limited to 'scripts')
41 files changed, 2818 insertions, 369 deletions
diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 0b94d2f..e4deb73 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -82,7 +82,7 @@ ifneq ($(strip $(lib-y) $(lib-m) $(lib-n) $(lib-)),) lib-target := $(obj)/lib.a endif -ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(lib-target)),) +ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(subdir-m) $(lib-target)),) builtin-target := $(obj)/built-in.o endif diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index cbcd654..54fd1b7 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -241,7 +241,7 @@ cmd_lzma = (cat $(filter-out FORCE,$^) | \ lzma -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ (rm -f $@ ; false) -quiet_cmd_lzo = LZO $@ +quiet_cmd_lzo = LZO $@ cmd_lzo = (cat $(filter-out FORCE,$^) | \ lzop -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ (rm -f $@ ; false) diff --git a/scripts/checkincludes.pl b/scripts/checkincludes.pl index 676ddc0..97b2c61 100755 --- a/scripts/checkincludes.pl +++ b/scripts/checkincludes.pl @@ -11,6 +11,8 @@ # you do have real dups and do not have them under #ifdef's. You # could also just review the results. +use strict; + sub usage { print "Usage: checkincludes.pl [-r]\n"; print "By default we just warn of duplicates\n"; @@ -35,23 +37,24 @@ if ($#ARGV >= 1) { } } -foreach $file (@ARGV) { - open(FILE, $file) or die "Cannot open $file: $!.\n"; +foreach my $file (@ARGV) { + open(my $f, '<', $file) + or die "Cannot open $file: $!.\n"; my %includedfiles = (); my @file_lines = (); - while (<FILE>) { + while (<$f>) { if (m/^\s*#\s*include\s*[<"](\S*)[>"]/o) { ++$includedfiles{$1}; } push(@file_lines, $_); } - close(FILE); + close($f); if (!$remove) { - foreach $filename (keys %includedfiles) { + foreach my $filename (keys %includedfiles) { if ($includedfiles{$filename} > 1) { print "$file: $filename is included more than once.\n"; } @@ -59,27 +62,28 @@ foreach $file (@ARGV) { next; } - open(FILE,">$file") || die("Cannot write to $file: $!"); + open($f, '>', $file) + or die("Cannot write to $file: $!"); my $dups = 0; foreach (@file_lines) { if (m/^\s*#\s*include\s*[<"](\S*)[>"]/o) { - foreach $filename (keys %includedfiles) { + foreach my $filename (keys %includedfiles) { if ($1 eq $filename) { if ($includedfiles{$filename} > 1) { $includedfiles{$filename}--; $dups++; } else { - print FILE $_; + print {$f} $_; } } } } else { - print FILE $_; + print {$f} $_; } } if ($dups > 0) { print "$file: removed $dups duplicate includes\n"; } - close(FILE); + close($f); } diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl index 14ee68e..1afff66 100755 --- a/scripts/checkstack.pl +++ b/scripts/checkstack.pl @@ -21,6 +21,8 @@ # # TODO : Port to all architectures (one regex per arch) +use strict; + # check for arch # # $re is used for two matches: @@ -104,19 +106,11 @@ my (@stack, $re, $dre, $x, $xs); } } -sub bysize($) { - my ($asize, $bsize); - ($asize = $a) =~ s/.*: *(.*)$/$1/; - ($bsize = $b) =~ s/.*: *(.*)$/$1/; - $bsize <=> $asize -} - # # main() # my $funcre = qr/^$x* <(.*)>:$/; -my $func; -my $file, $lastslash; +my ($func, $file, $lastslash); while (my $line = <STDIN>) { if ($line =~ m/$funcre/) { @@ -173,4 +167,6 @@ while (my $line = <STDIN>) { } } -print sort bysize @stack; +# Sort output by size (last field) +print sort { ($b =~ /:\t*(\d+)$/)[0] <=> ($a =~ /:\t*(\d+)$/)[0] } @stack; + diff --git a/scripts/checkversion.pl b/scripts/checkversion.pl index ec7d211..b444e89 100755 --- a/scripts/checkversion.pl +++ b/scripts/checkversion.pl @@ -5,23 +5,22 @@ # including <linux/version.h> that don't need it. # Copyright (C) 2003, Randy Dunlap <rdunlap@xenotime.net> +use strict; + $| = 1; -my $debugging = 0; +my $debugging; -foreach $file (@ARGV) -{ +foreach my $file (@ARGV) { # Open this file. - open(FILE, $file) || die "Can't open $file: $!\n"; + open( my $f, '<', $file ) + or die "Can't open $file: $!\n"; # Initialize variables. - my $fInComment = 0; - my $fInString = 0; - my $fUseVersion = 0; + my ($fInComment, $fInString, $fUseVersion); my $iLinuxVersion = 0; - LINE: while ( <FILE> ) - { + while (<$f>) { # Strip comments. $fInComment && (s+^.*?\*/+ +o ? ($fInComment = 0) : next); m+/\*+o && (s+/\*.*?\*/+ +go, (s+/\*.*$+ +o && ($fInComment = 1))); @@ -43,8 +42,8 @@ foreach $file (@ARGV) # Look for uses: LINUX_VERSION_CODE, KERNEL_VERSION, UTS_RELEASE if (($_ =~ /LINUX_VERSION_CODE/) || ($_ =~ /\WKERNEL_VERSION/)) { $fUseVersion = 1; - last LINE if $iLinuxVersion; - } + last if $iLinuxVersion; + } } # Report used version IDs without include? @@ -67,5 +66,5 @@ foreach $file (@ARGV) } } - close(FILE); + close($f); } diff --git a/scripts/decodecode b/scripts/decodecode index 4b00647..8b30cc3 100755 --- a/scripts/decodecode +++ b/scripts/decodecode @@ -7,7 +7,7 @@ # AFLAGS=--32 decodecode < 386.oops cleanup() { - rm -f $T $T.s $T.o $T.oo $T.aa $T.aaa + rm -f $T $T.s $T.o $T.oo $T.aa $T.dis exit 1 } @@ -39,6 +39,29 @@ fi echo $code code=`echo $code | sed -e 's/.*Code: //'` +width=`expr index "$code" ' '` +width=$[($width-1)/2] +case $width in +1) type=byte ;; +2) type=2byte ;; +4) type=4byte ;; +esac + +disas() { + ${CROSS_COMPILE}as $AFLAGS -o $1.o $1.s &> /dev/null + + if [ "$ARCH" == "arm" ]; then + if [ $width == 2 ]; then + OBJDUMPFLAGS="-M force-thumb" + fi + + ${CROSS_COMPILE}strip $1.o + fi + + ${CROSS_COMPILE}objdump $OBJDUMPFLAGS -S $1.o | \ + grep -v "/tmp\|Disassembly\|\.text\|^$" &> $1.dis +} + marker=`expr index "$code" "\<"` if [ $marker -eq 0 ]; then marker=`expr index "$code" "\("` @@ -49,26 +72,25 @@ if [ $marker -ne 0 ]; then echo All code >> $T.oo echo ======== >> $T.oo beforemark=`echo "$code"` - echo -n " .byte 0x" > $T.s - echo $beforemark | sed -e 's/ /,0x/g' | sed -e 's/<//g' | sed -e 's/>//g' >> $T.s - as $AFLAGS -o $T.o $T.s &> /dev/null - objdump -S $T.o | grep -v "/tmp" | grep -v "Disassembly" | grep -v "\.text" | grep -v "^$" &> $T.ooo - cat $T.ooo >> $T.oo - rm -f $T.o $T.s $T.ooo + echo -n " .$type 0x" > $T.s + echo $beforemark | sed -e 's/ /,0x/g; s/[<>()]//g' >> $T.s + disas $T + cat $T.dis >> $T.oo + rm -f $T.o $T.s $T.dis # and fix code at-and-after marker code=`echo "$code" | cut -c$((${marker} + 1))-` fi echo Code starting with the faulting instruction > $T.aa echo =========================================== >> $T.aa -code=`echo $code | sed -e 's/ [<(]/ /;s/[>)] / /;s/ /,0x/g'` -echo -n " .byte 0x" > $T.s +code=`echo $code | sed -e 's/ [<(]/ /;s/[>)] / /;s/ /,0x/g; s/[>)]$//'` +echo -n " .$type 0x" > $T.s echo $code >> $T.s -as $AFLAGS -o $T.o $T.s &> /dev/null -objdump -S $T.o | grep -v "Disassembly" | grep -v "/tmp" | grep -v "\.text" | grep -v "^$" &> $T.aaa -cat $T.aaa >> $T.aa +disas $T +cat $T.dis >> $T.aa -faultline=`cat $T.aaa | head -1 | cut -d":" -f2` +faultline=`cat $T.dis | head -1 | cut -d":" -f2` +faultline=`echo "$faultline" | sed -e 's/\[/\\\[/g; s/\]/\\\]/g'` cat $T.oo | sed -e "s/\($faultline\)/\*\1 <-- trapping instruction/g" echo diff --git a/scripts/export_report.pl b/scripts/export_report.pl index 705b5ba..04dce7c 100644 --- a/scripts/export_report.pl +++ b/scripts/export_report.pl @@ -49,10 +49,10 @@ sub usage { } sub collectcfiles { - my @file = `cat .tmp_versions/*.mod | grep '.*\.ko\$'`; - @file = grep {s/\.ko/.mod.c/} @file; - chomp @file; - return @file; + my @file + = `cat .tmp_versions/*.mod | grep '.*\.ko\$' | sed s/\.ko$/.mod.c/`; + chomp @file; + return @file; } my (%SYMBOL, %MODULE, %opt, @allcfiles); @@ -71,37 +71,40 @@ if (not defined $opt{'k'}) { $opt{'k'} = "Module.symvers"; } -unless (open(MODULE_SYMVERS, $opt{'k'})) { - die "Sorry, cannot open $opt{'k'}: $!\n"; -} +open (my $module_symvers, '<', $opt{'k'}) + or die "Sorry, cannot open $opt{'k'}: $!\n"; if (defined $opt{'o'}) { - unless (open(OUTPUT_HANDLE, ">$opt{'o'}")) { - die "Sorry, cannot open $opt{'o'} $!\n"; - } - select OUTPUT_HANDLE; + open (my $out, '>', $opt{'o'}) + or die "Sorry, cannot open $opt{'o'} $!\n"; + + select $out; } + # # collect all the symbols and their attributes from the # Module.symvers file # -while ( <MODULE_SYMVERS> ) { +while ( <$module_symvers> ) { chomp; my (undef, $symbol, $module, $gpl) = split; $SYMBOL { $symbol } = [ $module , "0" , $symbol, $gpl]; } -close(MODULE_SYMVERS); +close($module_symvers); # # collect the usage count of each symbol. # foreach my $thismod (@allcfiles) { - unless (open(MODULE_MODULE, $thismod)) { - print "Sorry, cannot open $thismod: $!\n"; + my $module; + + unless (open ($module, '<', $thismod)) { + warn "Sorry, cannot open $thismod: $!\n"; next; } + my $state=0; - while ( <MODULE_MODULE> ) { + while ( <$module> ) { chomp; if ($state == 0) { $state = 1 if ($_ =~ /static const struct modversion_info/); @@ -124,7 +127,7 @@ foreach my $thismod (@allcfiles) { if ($state != 2) { print "WARNING:$thismod is not built with CONFIG_MODVERSION enabled\n"; } - close(MODULE_MODULE); + close($module); } print "\tThis file reports the exported symbols usage patterns by in-tree\n", diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh index a932ae5..5958fff 100644 --- a/scripts/gen_initramfs_list.sh +++ b/scripts/gen_initramfs_list.sh @@ -202,6 +202,7 @@ input_file() { print_mtime "$1" >> ${output} cat "$1" >> ${output} else + echo "$1 \\" cat "$1" | while read type dir file perm ; do if [ "$type" == "file" ]; then echo "$file \\"; @@ -231,7 +232,7 @@ arg="$1" case "$arg" in "-l") # files included in initramfs - used by kbuild dep_list="list_" - echo "deps_initramfs := \\" + echo "deps_initramfs := $0 \\" shift ;; "-o") # generate compressed cpio image named $1 diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c index af6b836..f99115e 100644 --- a/scripts/genksyms/genksyms.c +++ b/scripts/genksyms/genksyms.c @@ -758,8 +758,10 @@ int main(int argc, char **argv) /* setlinebuf(debugfile); */ } - if (flag_reference) + if (flag_reference) { read_reference(ref_file); + fclose(ref_file); + } yyparse(); diff --git a/scripts/headerdep.pl b/scripts/headerdep.pl index b7f6c56..8dd019b 100755 --- a/scripts/headerdep.pl +++ b/scripts/headerdep.pl @@ -80,8 +80,7 @@ sub search { my $path = "$i/$filename"; return $path if -f $path; } - - return undef; + return; } sub parse_all { diff --git a/scripts/headers_check.pl b/scripts/headers_check.pl index db1dd7a..50d6cfd 100644 --- a/scripts/headers_check.pl +++ b/scripts/headers_check.pl @@ -28,11 +28,12 @@ my $lineno = 0; my $filename; foreach my $file (@files) { - local *FH; $filename = $file; - open(FH, "<$filename") or die "$filename: $!\n"; + + open(my $fh, '<', $filename) + or die "$filename: $!\n"; $lineno = 0; - while ($line = <FH>) { + while ($line = <$fh>) { $lineno++; &check_include(); &check_asm_types(); @@ -40,7 +41,7 @@ foreach my $file (@files) { &check_declarations(); # Dropped for now. Too much noise &check_config(); } - close FH; + close $fh; } exit $ret; @@ -78,7 +79,7 @@ sub check_config } my $linux_asm_types; -sub check_asm_types() +sub check_asm_types { if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) { return; diff --git a/scripts/headers_install.pl b/scripts/headers_install.pl index b89ca2c..4ca3be3 100644 --- a/scripts/headers_install.pl +++ b/scripts/headers_install.pl @@ -23,13 +23,13 @@ my ($readdir, $installdir, $arch, @files) = @ARGV; my $unifdef = "scripts/unifdef -U__KERNEL__ -D__EXPORTED_HEADERS__"; foreach my $file (@files) { - local *INFILE; - local *OUTFILE; my $tmpfile = "$installdir/$file.tmp"; - open(INFILE, "<$readdir/$file") - or die "$readdir/$file: $!\n"; - open(OUTFILE, ">$tmpfile") or die "$tmpfile: $!\n"; - while (my $line = <INFILE>) { + + open(my $in, '<', "$readdir/$file") + or die "$readdir/$file: $!\n"; + open(my $out, '>', $tmpfile) + or die "$tmpfile: $!\n"; + while (my $line = <$in>) { $line =~ s/([\s(])__user\s/$1/g; $line =~ s/([\s(])__force\s/$1/g; $line =~ s/([\s(])__iomem\s/$1/g; @@ -39,10 +39,11 @@ foreach my $file (@files) { $line =~ s/(^|\s)(inline)\b/$1__$2__/g; $line =~ s/(^|\s)(asm)\b(\s|[(]|$)/$1__$2__$3/g; $line =~ s/(^|\s|[(])(volatile)\b(\s|[(]|$)/$1__$2__$3/g; - printf OUTFILE "%s", $line; + printf {$out} "%s", $line; } - close OUTFILE; - close INFILE; + close $out; + close $in; + system $unifdef . " $tmpfile > $installdir/$file"; unlink $tmpfile; } diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c index 86c3896..e3902fb 100644 --- a/scripts/kallsyms.c +++ b/scripts/kallsyms.c @@ -108,8 +108,10 @@ static int read_symbol(FILE *in, struct sym_entry *s) rc = fscanf(in, "%llx %c %499s\n", &s->addr, &stype, str); if (rc != 3) { if (rc != EOF) { - /* skip line */ - fgets(str, 500, in); + /* skip line. sym is used as dummy to + * shut of "warn_unused_result" warning. + */ + sym = fgets(str, 500, in); } return -1; } diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 186c466..7cdae39 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -23,6 +23,9 @@ menuconfig: $(obj)/mconf config: $(obj)/conf $< $(Kconfig) +nconfig: $(obj)/nconf + $< $(Kconfig) + oldconfig: $(obj)/conf $< -o $(Kconfig) @@ -120,6 +123,7 @@ endif # Help text used by make help help: @echo ' config - Update current config utilising a line-oriented program' + @echo ' nconfig - Update current config utilising a ncurses menu based program' @echo ' menuconfig - Update current config utilising a menu based program' @echo ' xconfig - Update current config utilising a QT based front-end' @echo ' gconfig - Update current config utilising a GTK based front-end' @@ -147,6 +151,8 @@ HOST_EXTRACFLAGS += -DLOCALE # =========================================================================== # Shared Makefile for the various kconfig executables: # conf: Used for defconfig, oldconfig and related targets +# nconf: Used for the nconfig target. +# Utilizes ncurses # mconf: Used for the menuconfig target # Utilizes the lxdialog package # qconf: Used for the xconfig target @@ -159,11 +165,16 @@ lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o conf-objs := conf.o zconf.tab.o -mconf-objs := mconf.o zconf.tab.o $(lxdialog) +mconf-objs := mconf.o zconf.tab.o $(lxdialog) +nconf-objs := nconf.o zconf.tab.o nconf.gui.o kxgettext-objs := kxgettext.o zconf.tab.o hostprogs-y := conf qconf gconf kxgettext +ifeq ($(MAKECMDGOALS),nconfig) + hostprogs-y += nconf +endif + ifeq ($(MAKECMDGOALS),menuconfig) hostprogs-y += mconf endif @@ -187,7 +198,7 @@ endif clean-files := lkc_defs.h qconf.moc .tmp_qtcheck \ .tmp_gtkcheck zconf.tab.c lex.zconf.c zconf.hash.c gconf.glade.h -clean-files += mconf qconf gconf +clean-files += mconf qconf gconf nconf clean-files += config.pot linux.pot # Check that we have the required ncurses stuff installed for lxdialog (menuconfig) @@ -212,6 +223,7 @@ HOSTLOADLIBES_gconf = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0` HOSTCFLAGS_gconf.o = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \ -D LKC_DIRECT_LINK +HOSTLOADLIBES_nconf = -lmenu -lpanel -lncurses $(obj)/qconf.o: $(obj)/.tmp_qtcheck ifeq ($(qconf-target),1) diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c index edd3f39..d83f232 100644 --- a/scripts/kconfig/expr.c +++ b/scripts/kconfig/expr.c @@ -1097,9 +1097,32 @@ void expr_fprint(struct expr *e, FILE *out) static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str) { - str_append((struct gstr*)data, str); + struct gstr *gs = (struct gstr*)data; + const char *sym_str = NULL; + + if (sym) + sym_str = sym_get_string_value(sym); + + if (gs->max_width) { + unsigned extra_length = strlen(str); + const char *last_cr = strrchr(gs->s, '\n'); + unsigned last_line_length; + + if (sym_str) + extra_length += 4 + strlen(sym_str); + + if (!last_cr) + last_cr = gs->s; + + last_line_length = strlen(gs->s) - (last_cr - gs->s); + + if ((last_line_length + extra_length) > gs->max_width) + str_append(gs, "\\\n"); + } + + str_append(gs, str); if (sym) - str_printf((struct gstr*)data, " [=%s]", sym_get_string_value(sym)); + str_printf(gs, " [=%s]", sym_str); } void expr_gstr_print(struct expr *e, struct gstr *gs) diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index 6408fef..891cd9c 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -86,7 +86,7 @@ struct symbol { struct expr_value rev_dep; }; -#define for_all_symbols(i, sym) for (i = 0; i < 257; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER) +#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER) #define SYMBOL_CONST 0x0001 /* symbol is const */ #define SYMBOL_CHECK 0x0008 /* used during dependency checking */ @@ -108,8 +108,7 @@ struct symbol { #define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */ #define SYMBOL_MAXLENGTH 256 -#define SYMBOL_HASHSIZE 257 -#define SYMBOL_HASHMASK 0xff +#define SYMBOL_HASHSIZE 9973 /* A property represent the config options that can be associated * with a config "symbol". diff --git a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c index 6546436..bef1041 100644 --- a/scripts/kconfig/gconf.c +++ b/scripts/kconfig/gconf.c @@ -30,13 +30,16 @@ enum { SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW }; +enum { + OPT_NORMAL, OPT_ALL, OPT_PROMPT +}; + static gint view_mode = FULL_VIEW; static gboolean show_name = TRUE; static gboolean show_range = TRUE; static gboolean show_value = TRUE; -static gboolean show_all = FALSE; -static gboolean show_debug = FALSE; static gboolean resizeable = FALSE; +static int opt_mode = OPT_NORMAL; GtkWidget *main_wnd = NULL; GtkWidget *tree1_w = NULL; // left frame @@ -76,36 +79,7 @@ static void conf_changed(void); /* Helping/Debugging Functions */ - -const char *dbg_print_stype(int val) -{ - static char buf[256]; - - bzero(buf, 256); - - if (val == S_UNKNOWN) - strcpy(buf, "unknown"); - if (val == S_BOOLEAN) - strcpy(buf, "boolean"); - if (val == S_TRISTATE) - strcpy(buf, "tristate"); - if (val == S_INT) - strcpy(buf, "int"); - if (val == S_HEX) - strcpy(buf, "hex"); - if (val == S_STRING) - strcpy(buf, "string"); - if (val == S_OTHER) - strcpy(buf, "other"); - -#ifdef DEBUG - printf("%s", buf); -#endif - - return buf; -} - -const char *dbg_print_flags(int val) +const char *dbg_sym_flags(int val) { static char buf[256]; @@ -131,40 +105,10 @@ const char *dbg_print_flags(int val) strcat(buf, "auto/"); buf[strlen(buf) - 1] = '\0'; -#ifdef DEBUG - printf("%s", buf); -#endif - - return buf; -} - -const char *dbg_print_ptype(int val) -{ - static char buf[256]; - - bzero(buf, 256); - - if (val == P_UNKNOWN) - strcpy(buf, "unknown"); - if (val == P_PROMPT) - strcpy(buf, "prompt"); - if (val == P_COMMENT) - strcpy(buf, "comment"); - if (val == P_MENU) - strcpy(buf, "menu"); - if (val == P_DEFAULT) - strcpy(buf, "default"); - if (val == P_CHOICE) - strcpy(buf, "choice"); - -#ifdef DEBUG - printf("%s", buf); -#endif return buf; } - void replace_button_icon(GladeXML * xml, GdkDrawable * window, GtkStyle * style, gchar * btn_name, gchar ** xpm) { @@ -697,20 +641,29 @@ void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data) void -on_show_all_options1_activate(GtkMenuItem * menuitem, gpointer user_data) +on_set_option_mode1_activate(GtkMenuItem *menuitem, gpointer user_data) { - show_all = GTK_CHECK_MENU_ITEM(menuitem)->active; + opt_mode = OPT_NORMAL; + gtk_tree_store_clear(tree2); + display_tree(&rootmenu); /* instead of update_tree to speed-up */ +} + +void +on_set_option_mode2_activate(GtkMenuItem *menuitem, gpointer user_data) +{ + opt_mode = OPT_ALL; gtk_tree_store_clear(tree2); - display_tree(&rootmenu); // instead of update_tree to speed-up + display_tree(&rootmenu); /* instead of update_tree to speed-up */ } void -on_show_debug_info1_activate(GtkMenuItem * menuitem, gpointer user_data) +on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data) { - show_debug = GTK_CHECK_MENU_ITEM(menuitem)->active; - update_tree(&rootmenu, NULL); + opt_mode = OPT_PROMPT; + gtk_tree_store_clear(tree2); + display_tree(&rootmenu); /* instead of update_tree to speed-up */ } @@ -1163,7 +1116,10 @@ static gchar **fill_row(struct menu *menu) g_strdup_printf("%s %s", _(menu_get_prompt(menu)), sym && sym_has_value(sym) ? "(NEW)" : ""); - if (show_all && !menu_is_visible(menu)) + if (opt_mode == OPT_ALL && !menu_is_visible(menu)) + row[COL_COLOR] = g_strdup("DarkGray"); + else if (opt_mode == OPT_PROMPT && + menu_has_prompt(menu) && !menu_is_visible(menu)) row[COL_COLOR] = g_strdup("DarkGray"); else row[COL_COLOR] = g_strdup("Black"); @@ -1386,16 +1342,19 @@ static void update_tree(struct menu *src, GtkTreeIter * dst) menu2 ? menu_get_prompt(menu2) : "nil"); #endif - if (!menu_is_visible(child1) && !show_all) { // remove node + if ((opt_mode == OPT_NORMAL && !menu_is_visible(child1)) || + (opt_mode == OPT_PROMPT && !menu_has_prompt(child1))) { + + /* remove node */ if (gtktree_iter_find_node(dst, menu1) != NULL) { memcpy(&tmp, child2, sizeof(GtkTreeIter)); valid = gtk_tree_model_iter_next(model2, child2); gtk_tree_store_remove(tree2, &tmp); if (!valid) - return; // next parent + return; /* next parent */ else - goto reparse; // next child + goto reparse; /* next child */ } else continue; } @@ -1464,17 +1423,19 @@ static void display_tree(struct menu *menu) && (tree == tree2)) continue; - if (menu_is_visible(child) || show_all) + if ((opt_mode == OPT_NORMAL && menu_is_visible(child)) || + (opt_mode == OPT_PROMPT && menu_has_prompt(child)) || + (opt_mode == OPT_ALL)) place_node(child, fill_row(child)); #ifdef DEBUG printf("%*c%s: ", indent, ' ', menu_get_prompt(child)); printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : ""); - dbg_print_ptype(ptype); + printf("%s", prop_get_type_name(ptype)); printf(" | "); if (sym) { - dbg_print_stype(sym->type); + printf("%s", sym_type_name(sym->type)); printf(" | "); - dbg_print_flags(sym->flags); + printf("%s", dbg_sym_flags(sym->flags)); printf("\n"); } else printf("\n"); diff --git a/scripts/kconfig/gconf.glade b/scripts/kconfig/gconf.glade index b1c86c1..d52b0a7 100644 --- a/scripts/kconfig/gconf.glade +++ b/scripts/kconfig/gconf.glade @@ -190,26 +190,40 @@ </child> <child> - <widget class="GtkCheckMenuItem" id="show_all_options1"> + <widget class="GtkRadioMenuItem" id="set_option_mode1"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Show normal options</property> + <property name="label" translatable="yes">Show normal options</property> + <property name="use_underline">True</property> + <property name="active">True</property> + <signal name="activate" handler="on_set_option_mode1_activate"/> + </widget> + </child> + + <child> + <widget class="GtkRadioMenuItem" id="set_option_mode2"> <property name="visible">True</property> <property name="tooltip" translatable="yes">Show all options</property> <property name="label" translatable="yes">Show all _options</property> <property name="use_underline">True</property> <property name="active">False</property> - <signal name="activate" handler="on_show_all_options1_activate"/> + <property name="group">set_option_mode1</property> + <signal name="activate" handler="on_set_option_mode2_activate"/> </widget> </child> <child> - <widget class="GtkCheckMenuItem" id="show_debug_info1"> + <widget class="GtkRadioMenuItem" id="set_option_mode3"> <property name="visible">True</property> - <property name="tooltip" translatable="yes">Show masked options</property> - <property name="label" translatable="yes">Show _debug info</property> + <property name="tooltip" translatable="yes">Show all options with prompts</property> + <property name="label" translatable="yes">Show all prompt options</property> <property name="use_underline">True</property> <property name="active">False</property> - <signal name="activate" handler="on_show_debug_info1_activate"/> + <property name="group">set_option_mode1</property> + <signal name="activate" handler="on_set_option_mode3_activate"/> </widget> </child> + </widget> </child> </widget> diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index f379b0b..ce6549c 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -84,7 +84,7 @@ void conf_set_all_new_symbols(enum conf_def_mode mode); void kconfig_load(void); /* menu.c */ -void menu_init(void); +void _menu_init(void); void menu_warn(struct menu *menu, const char *fmt, ...); struct menu *menu_add_menu(void); void menu_end_menu(void); @@ -106,6 +106,11 @@ int file_write_dep(const char *name); struct gstr { size_t len; char *s; + /* + * when max_width is not zero long lines in string s (if any) get + * wrapped not to exceed the max_width value + */ + int max_width; }; struct gstr str_new(void); struct gstr str_assign(const char *s); diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h index ffeb532..7cadcad 100644 --- a/scripts/kconfig/lkc_proto.h +++ b/scripts/kconfig/lkc_proto.h @@ -11,13 +11,15 @@ P(conf_set_changed_callback, void,(void (*fn)(void))); /* menu.c */ P(rootmenu,struct menu,); -P(menu_is_visible,bool,(struct menu *menu)); +P(menu_is_visible, bool, (struct menu *menu)); +P(menu_has_prompt, bool, (struct menu *menu)); P(menu_get_prompt,const char *,(struct menu *menu)); P(menu_get_root_menu,struct menu *,(struct menu *menu)); P(menu_get_parent_menu,struct menu *,(struct menu *menu)); P(menu_has_help,bool,(struct menu *menu)); P(menu_get_help,const char *,(struct menu *menu)); -P(get_symbol_str,void,(struct gstr *r, struct symbol *sym)); +P(get_symbol_str, void, (struct gstr *r, struct symbol *sym)); +P(get_relations_str, struct gstr, (struct symbol **sym_arr)); P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help)); /* symbol.c */ diff --git a/scripts/kconfig/lxdialog/inputbox.c b/scripts/kconfig/lxdialog/inputbox.c index 616c601..dd8e587 100644 --- a/scripts/kconfig/lxdialog/inputbox.c +++ b/scripts/kconfig/lxdialog/inputbox.c @@ -180,7 +180,7 @@ do_resize: case KEY_LEFT: switch (button) { case -1: - button = 1; /* Indicates "Cancel" button is selected */ + button = 1; /* Indicates "Help" button is selected */ print_buttons(dialog, height, width, 1); break; case 0: @@ -204,7 +204,7 @@ do_resize: print_buttons(dialog, height, width, 0); break; case 0: - button = 1; /* Indicates "Cancel" button is selected */ + button = 1; /* Indicates "Help" button is selected */ print_buttons(dialog, height, width, 1); break; case 1: diff --git a/scripts/kconfig/lxdialog/menubox.c b/scripts/kconfig/lxdialog/menubox.c index fa9d633..1d60473 100644 --- a/scripts/kconfig/lxdialog/menubox.c +++ b/scripts/kconfig/lxdialog/menubox.c @@ -383,6 +383,10 @@ do_resize: case 'n': case 'm': case '/': + case 'h': + case '?': + case 'z': + case '\n': /* save scroll info */ *s_scroll = scroll; delwin(menu); @@ -390,8 +394,10 @@ do_resize: item_set(scroll + choice); item_set_selected(1); switch (key) { + case 'h': + case '?': + return 2; case 's': - return 3; case 'y': return 3; case 'n': @@ -402,18 +408,12 @@ do_resize: return 6; case '/': return 7; + case 'z': + return 8; + case '\n': + return button; } return 0; - case 'h': - case '?': - button = 2; - case '\n': - *s_scroll = scroll; - delwin(menu); - delwin(dialog); - item_set(scroll + choice); - item_set_selected(1); - return button; case 'e': case 'x': key = KEY_ESC; diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index 8413cf3..2c83d32 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -67,13 +67,15 @@ static const char mconf_readme[] = N_( " there is a delayed response which you may find annoying.\n" "\n" " Also, the <TAB> and cursor keys will cycle between <Select>,\n" -" <Exit> and <Help>\n" +" <Exit> and <Help>.\n" "\n" "o To get help with an item, use the cursor keys to highlight <Help>\n" -" and Press <ENTER>.\n" +" and press <ENTER>.\n" "\n" " Shortcut: Press <H> or <?>.\n" "\n" +"o To show hidden options, press <Z>.\n" +"\n" "\n" "Radiolists (Choice lists)\n" "-----------\n" @@ -272,6 +274,7 @@ static int indent; static struct menu *current_menu; static int child_count; static int single_menu_mode; +static int show_all_options; static void conf(struct menu *menu); static void conf_choice(struct menu *menu); @@ -282,19 +285,6 @@ static void show_textbox(const char *title, const char *text, int r, int c); static void show_helptext(const char *title, const char *text); static void show_help(struct menu *menu); -static struct gstr get_relations_str(struct symbol **sym_arr) -{ - struct symbol *sym; - struct gstr res = str_new(); - int i; - - for (i = 0; sym_arr && (sym = sym_arr[i]); i++) - get_symbol_str(&res, sym); - if (!i) - str_append(&res, _("No matches found.\n")); - return res; -} - static char filename[PATH_MAX+1]; static void set_config_filename(const char *config_filename) { @@ -359,8 +349,16 @@ static void build_conf(struct menu *menu) int type, tmp, doint = 2; tristate val; char ch; - - if (!menu_is_visible(menu)) + bool visible; + + /* + * note: menu_is_visible() has side effect that it will + * recalc the value of the symbol. + */ + visible = menu_is_visible(menu); + if (show_all_options && !menu_has_prompt(menu)) + return; + else if (!show_all_options && !visible) return; sym = menu->sym; @@ -619,6 +617,9 @@ static void conf(struct menu *menu) case 7: search_conf(); break; + case 8: + show_all_options = !show_all_options; + break; } } } @@ -638,6 +639,7 @@ static void show_help(struct menu *menu) { struct gstr help = str_new(); + help.max_width = getmaxx(stdscr) - 10; menu_get_ext_help(menu, &help); show_helptext(_(menu_get_prompt(menu)), str_get(&help)); diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 059a246..203632c 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -38,7 +38,7 @@ static void prop_warn(struct property *prop, const char *fmt, ...) va_end(ap); } -void menu_init(void) +void _menu_init(void) { current_entry = current_menu = &rootmenu; last_entry_ptr = &rootmenu.list; @@ -197,7 +197,7 @@ static void sym_check_prop(struct symbol *sym) if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) && prop->expr->type != E_SYMBOL) prop_warn(prop, - "default for config symbol '%'" + "default for config symbol '%s'" " must be a single symbol", sym->name); break; case P_SELECT: @@ -390,6 +390,13 @@ void menu_finalize(struct menu *parent) } } +bool menu_has_prompt(struct menu *menu) +{ + if (!menu->prompt) + return false; + return true; +} + bool menu_is_visible(struct menu *menu) { struct menu *child; @@ -398,6 +405,7 @@ bool menu_is_visible(struct menu *menu) if (!menu->prompt) return false; + sym = menu->sym; if (sym) { sym_calc_value(sym); @@ -407,12 +415,14 @@ bool menu_is_visible(struct menu *menu) if (visible != no) return true; + if (!sym || sym_get_tristate_value(menu->sym) == no) return false; for (child = menu->list; child; child = child->next) if (menu_is_visible(child)) return true; + return false; } @@ -515,6 +525,20 @@ void get_symbol_str(struct gstr *r, struct symbol *sym) str_append(r, "\n\n"); } +struct gstr get_relations_str(struct symbol **sym_arr) +{ + struct symbol *sym; + struct gstr res = str_new(); + int i; + + for (i = 0; sym_arr && (sym = sym_arr[i]); i++) + get_symbol_str(&res, sym); + if (!i) + str_append(&res, _("No matches found.\n")); + return res; +} + + void menu_get_ext_help(struct menu *menu, struct gstr *help) { struct symbol *sym = menu->sym; diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c new file mode 100644 index 0000000..762caf8 --- /dev/null +++ b/scripts/kconfig/nconf.c @@ -0,0 +1,1568 @@ +/* + * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com? + * Released under the terms of the GNU GPL v2.0. + * + * Derived from menuconfig. + * + */ +#define LKC_DIRECT_LINK +#include "lkc.h" +#include "nconf.h" + +static const char nconf_readme[] = N_( +"Overview\n" +"--------\n" +"Some kernel features may be built directly into the kernel.\n" +"Some may be made into loadable runtime modules. Some features\n" +"may be completely removed altogether. There are also certain\n" +"kernel parameters which are not really features, but must be\n" +"entered in as decimal or hexadecimal numbers or possibly text.\n" +"\n" +"Menu items beginning with following braces represent features that\n" +" [ ] can be built in or removed\n" +" < > can be built in, modularized or removed\n" +" { } can be built in or modularized (selected by other feature)\n" +" - - are selected by other feature,\n" +" XXX cannot be selected. use Symbol Info to find out why,\n" +"while *, M or whitespace inside braces means to build in, build as\n" +"a module or to exclude the feature respectively.\n" +"\n" +"To change any of these features, highlight it with the cursor\n" +"keys and press <Y> to build it in, <M> to make it a module or\n" +"<N> to removed it. You may also press the <Space Bar> to cycle\n" +"through the available options (ie. Y->N->M->Y).\n" +"\n" +"Some additional keyboard hints:\n" +"\n" +"Menus\n" +"----------\n" +"o Use the Up/Down arrow keys (cursor keys) to highlight the item\n" +" you wish to change use <Enter> or <Space>. Goto submenu by \n" +" pressing <Enter> of <right-arrow>. Use <Esc> or <left-arrow> to go back.\n" +" Submenus are designated by \"--->\".\n" +"\n" +" Shortcut: Press the option's highlighted letter (hotkey).\n" +" Pressing a hotkey more than once will sequence\n" +" through all visible items which use that hotkey.\n" +"\n" +" You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n" +" unseen options into view.\n" +"\n" +"o To exit a menu use the just press <ESC> <F5> <F8> or <left-arrow>.\n" +"\n" +"o To get help with an item, press <F1>\n" +" Shortcut: Press <h> or <?>.\n" +"\n" +"\n" +"Radiolists (Choice lists)\n" +"-----------\n" +"o Use the cursor keys to select the option you wish to set and press\n" +" <S> or the <SPACE BAR>.\n" +"\n" +" Shortcut: Press the first letter of the option you wish to set then\n" +" press <S> or <SPACE BAR>.\n" +"\n" +"o To see available help for the item, press <F1>\n" +" Shortcut: Press <H> or <?>.\n" +"\n" +"\n" +"Data Entry\n" +"-----------\n" +"o Enter the requested information and press <ENTER>\n" +" If you are entering hexadecimal values, it is not necessary to\n" +" add the '0x' prefix to the entry.\n" +"\n" +"o For help, press <F1>.\n" +"\n" +"\n" +"Text Box (Help Window)\n" +"--------\n" +"o Use the cursor keys to scroll up/down/left/right. The VI editor\n" +" keys h,j,k,l function here as do <SPACE BAR> for those\n" +" who are familiar with less and lynx.\n" +"\n" +"o Press <Enter>, <F1>, <F5>, <F7> or <Esc> to exit.\n" +"\n" +"\n" +"Alternate Configuration Files\n" +"-----------------------------\n" +"nconfig supports the use of alternate configuration files for\n" +"those who, for various reasons, find it necessary to switch\n" +"between different kernel configurations.\n" +"\n" +"At the end of the main menu you will find two options. One is\n" +"for saving the current configuration to a file of your choosing.\n" +"The other option is for loading a previously saved alternate\n" +"configuration.\n" +"\n" +"Even if you don't use alternate configuration files, but you\n" +"find during a nconfig session that you have completely messed\n" +"up your settings, you may use the \"Load Alternate...\" option to\n" +"restore your previously saved settings from \".config\" without\n" +"restarting nconfig.\n" +"\n" +"Other information\n" +"-----------------\n" +"If you use nconfig in an XTERM window make sure you have your\n" +"$TERM variable set to point to a xterm definition which supports color.\n" +"Otherwise, nconfig will look rather bad. nconfig will not\n" +"display correctly in a RXVT window because rxvt displays only one\n" +"intensity of color, bright.\n" +"\n" +"nconfig will display larger menus on screens or xterms which are\n" +"set to display more than the standard 25 row by 80 column geometry.\n" +"In order for this to work, the \"stty size\" command must be able to\n" +"display the screen's current row and column geometry. I STRONGLY\n" +"RECOMMEND that you make sure you do NOT have the shell variables\n" +"LINES and COLUMNS exported into your environment. Some distributions\n" +"export those variables via /etc/profile. Some ncurses programs can\n" +"become confused when those variables (LINES & COLUMNS) don't reflect\n" +"the true screen size.\n" +"\n" +"Optional personality available\n" +"------------------------------\n" +"If you prefer to have all of the kernel options listed in a single\n" +"menu, rather than the default multimenu hierarchy, run the nconfig\n" +"with NCONFIG_MODE environment variable set to single_menu. Example:\n" +"\n" +"make NCONFIG_MODE=single_menu nconfig\n" +"\n" +"<Enter> will then unroll the appropriate category, or enfold it if it\n" +"is already unrolled.\n" +"\n" +"Note that this mode can eventually be a little more CPU expensive\n" +"(especially with a larger number of unrolled categories) than the\n" +"default mode.\n" +"\n"), +menu_no_f_instructions[] = N_( +" You do not have function keys support. Please follow the\n" +" following instructions:\n" +" Arrow keys navigate the menu.\n" +" <Enter> or <right-arrow> selects submenus --->.\n" +" Capital Letters are hotkeys.\n" +" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n" +" Pressing SpaceBar toggles between the above options\n" +" Press <Esc> or <left-arrow> to go back one menu, \n" +" <?> or <h> for Help, </> for Search.\n" +" <1> is interchangable with <F1>, <2> with <F2>, etc.\n" +" Legend: [*] built-in [ ] excluded <M> module < > module capable.\n" +" <Esc> always leaves the current window\n"), +menu_instructions[] = N_( +" Arrow keys navigate the menu.\n" +" <Enter> or <right-arrow> selects submenus --->.\n" +" Capital Letters are hotkeys.\n" +" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n" +" Pressing SpaceBar toggles between the above options\n" +" Press <Esc>, <F3> or <left-arrow> to go back one menu, \n" +" <?>, <F1> or <h> for Help, </> for Search.\n" +" <1> is interchangable with <F1>, <2> with <F2>, etc.\n" +" Legend: [*] built-in [ ] excluded <M> module < > module capable.\n" +" <Esc> always leaves the current window\n"), +radiolist_instructions[] = N_( +" Use the arrow keys to navigate this window or\n" +" press the hotkey of the item you wish to select\n" +" followed by the <SPACE BAR>.\n" +" Press <?>, <F1> or <h> for additional information about this option.\n"), +inputbox_instructions_int[] = N_( +"Please enter a decimal value.\n" +"Fractions will not be accepted.\n" +"Press <RETURN> to accept, <ESC> to cancel."), +inputbox_instructions_hex[] = N_( +"Please enter a hexadecimal value.\n" +"Press <RETURN> to accept, <ESC> to cancel."), +inputbox_instructions_string[] = N_( +"Please enter a string value.\n" +"Press <RETURN> to accept, <ESC> to cancel."), +setmod_text[] = N_( +"This feature depends on another which\n" +"has been configured as a module.\n" +"As a result, this feature will be built as a module."), +nohelp_text[] = N_( +"There is no help available for this kernel option.\n"), +load_config_text[] = N_( +"Enter the name of the configuration file you wish to load.\n" +"Accept the name shown to restore the configuration you\n" +"last retrieved. Leave blank to abort."), +load_config_help[] = N_( +"\n" +"For various reasons, one may wish to keep several different kernel\n" +"configurations available on a single machine.\n" +"\n" +"If you have saved a previous configuration in a file other than the\n" +"kernel's default, entering the name of the file here will allow you\n" +"to modify that configuration.\n" +"\n" +"If you are uncertain, then you have probably never used alternate\n" +"configuration files. You should therefor leave this blank to abort.\n"), +save_config_text[] = N_( +"Enter a filename to which this configuration should be saved\n" +"as an alternate. Leave blank to abort."), +save_config_help[] = N_( +"\n" +"For various reasons, one may wish to keep different kernel\n" +"configurations available on a single machine.\n" +"\n" +"Entering a file name here will allow you to later retrieve, modify\n" +"and use the current configuration as an alternate to whatever\n" +"configuration options you have selected at that time.\n" +"\n" +"If you are uncertain what all this means then you should probably\n" +"leave this blank.\n"), +search_help[] = N_( +"\n" +"Search for CONFIG_ symbols and display their relations.\n" +"Regular expressions are allowed.\n" +"Example: search for \"^FOO\"\n" +"Result:\n" +"-----------------------------------------------------------------\n" +"Symbol: FOO [ = m]\n" +"Prompt: Foo bus is used to drive the bar HW\n" +"Defined at drivers/pci/Kconfig:47\n" +"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" +"Location:\n" +" -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n" +" -> PCI support (PCI [ = y])\n" +" -> PCI access mode (<choice> [ = y])\n" +"Selects: LIBCRC32\n" +"Selected by: BAR\n" +"-----------------------------------------------------------------\n" +"o The line 'Prompt:' shows the text used in the menu structure for\n" +" this CONFIG_ symbol\n" +"o The 'Defined at' line tell at what file / line number the symbol\n" +" is defined\n" +"o The 'Depends on:' line tell what symbols needs to be defined for\n" +" this symbol to be visible in the menu (selectable)\n" +"o The 'Location:' lines tell where in the menu structure this symbol\n" +" is located\n" +" A location followed by a [ = y] indicate that this is a selectable\n" +" menu item - and current value is displayed inside brackets.\n" +"o The 'Selects:' line tell what symbol will be automatically\n" +" selected if this symbol is selected (y or m)\n" +"o The 'Selected by' line tell what symbol has selected this symbol\n" +"\n" +"Only relevant lines are shown.\n" +"\n\n" +"Search examples:\n" +"Examples: USB = > find all CONFIG_ symbols containing USB\n" +" ^USB => find all CONFIG_ symbols starting with USB\n" +" USB$ => find all CONFIG_ symbols ending with USB\n" +"\n"); + +struct mitem { + char str[256]; + char tag; + void *usrptr; + int is_hot; + int is_visible; +}; + +#define MAX_MENU_ITEMS 4096 +static int show_all_items; +static int indent; +static struct menu *current_menu; +static int child_count; +static int single_menu_mode; +/* the window in which all information appears */ +static WINDOW *main_window; +/* the largest size of the menu window */ +static int mwin_max_lines; +static int mwin_max_cols; +/* the window in which we show option buttons */ +static MENU *curses_menu; +static ITEM *curses_menu_items[MAX_MENU_ITEMS]; +static struct mitem k_menu_items[MAX_MENU_ITEMS]; +static int items_num; +static int global_exit; +/* the currently selected button */ +const char *current_instructions = menu_instructions; +/* this array is used to implement hot keys. it is updated in item_make and + * resetted in clean_items. It would be better to use a hash, but lets keep it + * simple... */ +#define MAX_SAME_KEY MAX_MENU_ITEMS +struct { + int count; + int ptrs[MAX_MENU_ITEMS]; +} hotkeys[1<<(sizeof(char)*8)]; + +static void conf(struct menu *menu); +static void conf_choice(struct menu *menu); +static void conf_string(struct menu *menu); +static void conf_load(void); +static void conf_save(void); +static void show_help(struct menu *menu); +static int do_exit(void); +static void setup_windows(void); + +typedef void (*function_key_handler_t)(int *key, struct menu *menu); +static void handle_f1(int *key, struct menu *current_item); +static void handle_f2(int *key, struct menu *current_item); +static void handle_f3(int *key, struct menu *current_item); +static void handle_f4(int *key, struct menu *current_item); +static void handle_f5(int *key, struct menu *current_item); +static void handle_f6(int *key, struct menu *current_item); +static void handle_f7(int *key, struct menu *current_item); +static void handle_f8(int *key, struct menu *current_item); + +struct function_keys { + const char *key_str; + const char *func; + function_key key; + function_key_handler_t handler; +}; + +static const int function_keys_num = 8; +struct function_keys function_keys[] = { + { + .key_str = "F1", + .func = "Help", + .key = F_HELP, + .handler = handle_f1, + }, + { + .key_str = "F2", + .func = "Symbol Info", + .key = F_SYMBOL, + .handler = handle_f2, + }, + { + .key_str = "F3", + .func = "Instructions", + .key = F_INSTS, + .handler = handle_f3, + }, + { + .key_str = "F4", + .func = "Config", + .key = F_CONF, + .handler = handle_f4, + }, + { + .key_str = "F5", + .func = "Back", + .key = F_BACK, + .handler = handle_f5, + }, + { + .key_str = "F6", + .func = "Save", + .key = F_SAVE, + .handler = handle_f6, + }, + { + .key_str = "F7", + .func = "Load", + .key = F_LOAD, + .handler = handle_f7, + }, + { + .key_str = "F8", + .func = "Exit", + .key = F_EXIT, + .handler = handle_f8, + }, +}; + +static void print_function_line(void) +{ + int i; + int offset = 1; + const int skip = 1; + + for (i = 0; i < function_keys_num; i++) { + wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]); + mvwprintw(main_window, LINES-3, offset, + "%s", + function_keys[i].key_str); + wattrset(main_window, attributes[FUNCTION_TEXT]); + offset += strlen(function_keys[i].key_str); + mvwprintw(main_window, LINES-3, + offset, "%s", + function_keys[i].func); + offset += strlen(function_keys[i].func) + skip; + } + wattrset(main_window, attributes[NORMAL]); +} + +/* help */ +static void handle_f1(int *key, struct menu *current_item) +{ + show_scroll_win(main_window, + _("README"), _(nconf_readme)); + return; +} + +/* symbole help */ +static void handle_f2(int *key, struct menu *current_item) +{ + show_help(current_item); + return; +} + +/* instructions */ +static void handle_f3(int *key, struct menu *current_item) +{ + show_scroll_win(main_window, + _("Instructions"), + _(current_instructions)); + return; +} + +/* config */ +static void handle_f4(int *key, struct menu *current_item) +{ + int res = btn_dialog(main_window, + _("Show all symbols?"), + 2, + " <Show All> ", + "<Don't show all>"); + if (res == 0) + show_all_items = 1; + else if (res == 1) + show_all_items = 0; + + return; +} + +/* back */ +static void handle_f5(int *key, struct menu *current_item) +{ + *key = KEY_LEFT; + return; +} + +/* save */ +static void handle_f6(int *key, struct menu *current_item) +{ + conf_save(); + return; +} + +/* load */ +static void handle_f7(int *key, struct menu *current_item) +{ + conf_load(); + return; +} + +/* exit */ +static void handle_f8(int *key, struct menu *current_item) +{ + do_exit(); + return; +} + +/* return != 0 to indicate the key was handles */ +static int process_special_keys(int *key, struct menu *menu) +{ + int i; + + if (*key == KEY_RESIZE) { + setup_windows(); + return 1; + } + + for (i = 0; i < function_keys_num; i++) { + if (*key == KEY_F(function_keys[i].key) || + *key == '0' + function_keys[i].key){ + function_keys[i].handler(key, menu); + return 1; + } + } + + return 0; +} + +static void clean_items(void) +{ + int i; + for (i = 0; curses_menu_items[i]; i++) + free_item(curses_menu_items[i]); + bzero(curses_menu_items, sizeof(curses_menu_items)); + bzero(k_menu_items, sizeof(k_menu_items)); + bzero(hotkeys, sizeof(hotkeys)); + items_num = 0; +} + +/* return the index of the next hot item, or -1 if no such item exists */ +static int get_next_hot(int c) +{ + static int hot_index; + static int hot_char; + + if (c < 0 || c > 255 || hotkeys[c].count <= 0) + return -1; + + if (hot_char == c) { + hot_index = (hot_index+1)%hotkeys[c].count; + return hotkeys[c].ptrs[hot_index]; + } else { + hot_char = c; + hot_index = 0; + return hotkeys[c].ptrs[0]; + } +} + +/* can the char c be a hot key? no, if c is a common shortcut used elsewhere */ +static int canbhot(char c) +{ + c = tolower(c); + return isalnum(c) && c != 'y' && c != 'm' && c != 'h' && + c != 'n' && c != '?'; +} + +/* check if str already contains a hot key. */ +static int is_hot(int index) +{ + return k_menu_items[index].is_hot; +} + +/* find the first possible hot key, and mark it. + * index is the index of the item in the menu + * return 0 on success*/ +static int make_hot(char *dest, int len, const char *org, int index) +{ + int position = -1; + int i; + int tmp; + int c; + int org_len = strlen(org); + + if (org == NULL || is_hot(index)) + return 1; + + /* make sure not to make hot keys out of markers. + * find where to start looking for a hot key + */ + i = 0; + /* skip white space */ + while (i < org_len && org[i] == ' ') + i++; + if (i == org_len) + return -1; + /* if encountering '(' or '<' or '[', find the match and look from there + **/ + if (org[i] == '[' || org[i] == '<' || org[i] == '(') { + i++; + for (; i < org_len; i++) + if (org[i] == ']' || org[i] == '>' || org[i] == ')') + break; + } + if (i == org_len) + return -1; + for (; i < org_len; i++) { + if (canbhot(org[i]) && org[i-1] != '<' && org[i-1] != '(') { + position = i; + break; + } + } + if (position == -1) + return 1; + + /* ok, char at org[position] should be a hot key to this item */ + c = tolower(org[position]); + tmp = hotkeys[c].count; + hotkeys[c].ptrs[tmp] = index; + hotkeys[c].count++; + /* + snprintf(dest, len, "%.*s(%c)%s", position, org, org[position], + &org[position+1]); + */ + /* make org[position] uppercase, and all leading letter small case */ + strncpy(dest, org, len); + for (i = 0; i < position; i++) + dest[i] = tolower(dest[i]); + dest[position] = toupper(dest[position]); + k_menu_items[index].is_hot = 1; + return 0; +} + +/* Make a new item. Add a hotkey mark in the first possible letter. + * As ncurses does not allow any attributes inside menue item, we mark the + * hot key as the first capitalized letter in the string */ +static void item_make(struct menu *menu, char tag, const char *fmt, ...) +{ + va_list ap; + char tmp_str[256]; + + if (items_num > MAX_MENU_ITEMS-1) + return; + + bzero(&k_menu_items[items_num], sizeof(k_menu_items[0])); + k_menu_items[items_num].tag = tag; + k_menu_items[items_num].usrptr = menu; + if (menu != NULL) + k_menu_items[items_num].is_visible = + menu_is_visible(menu); + else + k_menu_items[items_num].is_visible = 1; + + va_start(ap, fmt); + vsnprintf(tmp_str, sizeof(tmp_str), fmt, ap); + if (!k_menu_items[items_num].is_visible) + memcpy(tmp_str, "XXX", 3); + va_end(ap); + if (make_hot( + k_menu_items[items_num].str, + sizeof(k_menu_items[items_num].str), tmp_str, items_num) != 0) + strncpy(k_menu_items[items_num].str, + tmp_str, + sizeof(k_menu_items[items_num].str)); + + curses_menu_items[items_num] = new_item( + k_menu_items[items_num].str, + k_menu_items[items_num].str); + set_item_userptr(curses_menu_items[items_num], + &k_menu_items[items_num]); + /* + if (!k_menu_items[items_num].is_visible) + item_opts_off(curses_menu_items[items_num], O_SELECTABLE); + */ + + items_num++; + curses_menu_items[items_num] = NULL; +} + +/* very hackish. adds a string to the last item added */ +static void item_add_str(const char *fmt, ...) +{ + va_list ap; + int index = items_num-1; + char new_str[256]; + char tmp_str[256]; + + if (index < 0) + return; + + va_start(ap, fmt); + vsnprintf(new_str, sizeof(new_str), fmt, ap); + va_end(ap); + snprintf(tmp_str, sizeof(tmp_str), "%s%s", + k_menu_items[index].str, new_str); + if (make_hot(k_menu_items[index].str, + sizeof(k_menu_items[index].str), tmp_str, index) != 0) + strncpy(k_menu_items[index].str, + tmp_str, + sizeof(k_menu_items[index].str)); + + free_item(curses_menu_items[index]); + curses_menu_items[index] = new_item( + k_menu_items[index].str, + k_menu_items[index].str); + set_item_userptr(curses_menu_items[index], + &k_menu_items[index]); +} + +/* get the tag of the currently selected item */ +static char item_tag(void) +{ + ITEM *cur; + struct mitem *mcur; + + cur = current_item(curses_menu); + if (cur == NULL) + return 0; + mcur = (struct mitem *) item_userptr(cur); + return mcur->tag; +} + +static int curses_item_index(void) +{ + return item_index(current_item(curses_menu)); +} + +static void *item_data(void) +{ + ITEM *cur; + struct mitem *mcur; + + cur = current_item(curses_menu); + mcur = (struct mitem *) item_userptr(cur); + return mcur->usrptr; + +} + +static int item_is_tag(char tag) +{ + return item_tag() == tag; +} + +static char filename[PATH_MAX+1]; +static char menu_backtitle[PATH_MAX+128]; +static const char *set_config_filename(const char *config_filename) +{ + int size; + struct symbol *sym; + + sym = sym_lookup("KERNELVERSION", 0); + sym_calc_value(sym); + size = snprintf(menu_backtitle, sizeof(menu_backtitle), + _("%s - Linux Kernel v%s Configuration"), + config_filename, sym_get_string_value(sym)); + if (size >= sizeof(menu_backtitle)) + menu_backtitle[sizeof(menu_backtitle)-1] = '\0'; + + size = snprintf(filename, sizeof(filename), "%s", config_filename); + if (size >= sizeof(filename)) + filename[sizeof(filename)-1] = '\0'; + return menu_backtitle; +} + +/* command = 0 is supress, 1 is restore */ +static void supress_stdout(int command) +{ + static FILE *org_stdout; + static FILE *org_stderr; + + if (command == 0) { + org_stdout = stdout; + org_stderr = stderr; + stdout = fopen("/dev/null", "a"); + stderr = fopen("/dev/null", "a"); + } else { + fclose(stdout); + fclose(stderr); + stdout = org_stdout; + stderr = org_stderr; + } +} + +/* return = 0 means we are successful. + * -1 means go on doing what you were doing + */ +static int do_exit(void) +{ + int res; + if (!conf_get_changed()) { + global_exit = 1; + return 0; + } + res = btn_dialog(main_window, + _("Do you wish to save your " + "new kernel configuration?\n" + "<ESC> to cancel and resume nconfig."), + 2, + " <save> ", + "<don't save>"); + if (res == KEY_EXIT) { + global_exit = 0; + return -1; + } + + /* if we got here, the user really wants to exit */ + switch (res) { + case 0: + supress_stdout(0); + res = conf_write(filename); + supress_stdout(1); + if (res) + btn_dialog( + main_window, + _("Error during writing of the kernel " + "configuration.\n" + "Your kernel configuration " + "changes were NOT saved."), + 1, + "<OK>"); + else { + char buf[1024]; + snprintf(buf, 1024, + _("Configuration written to %s\n" + "End of Linux kernel configuration.\n" + "Execute 'make' to build the kernel or try" + " 'make help'."), filename); + btn_dialog( + main_window, + buf, + 1, + "<OK>"); + } + break; + default: + btn_dialog( + main_window, + _("Your kernel configuration changes were NOT saved."), + 1, + "<OK>"); + break; + } + global_exit = 1; + return 0; +} + + +static void search_conf(void) +{ + struct symbol **sym_arr; + struct gstr res; + char dialog_input_result[100]; + char *dialog_input; + int dres; +again: + dres = dialog_inputbox(main_window, + _("Search Configuration Parameter"), + _("Enter CONFIG_ (sub)string to search for " + "(with or without \"CONFIG\")"), + "", dialog_input_result, 99); + switch (dres) { + case 0: + break; + case 1: + show_scroll_win(main_window, + _("Search Configuration"), search_help); + goto again; + default: + return; + } + + /* strip CONFIG_ if necessary */ + dialog_input = dialog_input_result; + if (strncasecmp(dialog_input_result, "CONFIG_", 7) == 0) + dialog_input += 7; + + sym_arr = sym_re_search(dialog_input); + res = get_relations_str(sym_arr); + free(sym_arr); + show_scroll_win(main_window, + _("Search Results"), str_get(&res)); + str_free(&res); +} + + +static void build_conf(struct menu *menu) +{ + struct symbol *sym; + struct property *prop; + struct menu *child; + int type, tmp, doint = 2; + tristate val; + char ch; + + if (!menu || (!show_all_items && !menu_is_visible(menu))) + return; + + sym = menu->sym; + prop = menu->prompt; + if (!sym) { + if (prop && menu != current_menu) { + const char *prompt = menu_get_prompt(menu); + enum prop_type ptype; + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + switch (ptype) { + case P_MENU: + child_count++; + prompt = _(prompt); + if (single_menu_mode) { + item_make(menu, 'm', + "%s%*c%s", + menu->data ? "-->" : "++>", + indent + 1, ' ', prompt); + } else + item_make(menu, 'm', + " %*c%s --->", + indent + 1, + ' ', prompt); + + if (single_menu_mode && menu->data) + goto conf_childs; + return; + case P_COMMENT: + if (prompt) { + child_count++; + item_make(menu, ':', + " %*c*** %s ***", + indent + 1, ' ', + _(prompt)); + } + break; + default: + if (prompt) { + child_count++; + item_make(menu, ':', "---%*c%s", + indent + 1, ' ', + _(prompt)); + } + } + } else + doint = 0; + goto conf_childs; + } + + type = sym_get_type(sym); + if (sym_is_choice(sym)) { + struct symbol *def_sym = sym_get_choice_value(sym); + struct menu *def_menu = NULL; + + child_count++; + for (child = menu->list; child; child = child->next) { + if (menu_is_visible(child) && child->sym == def_sym) + def_menu = child; + } + + val = sym_get_tristate_value(sym); + if (sym_is_changable(sym)) { + switch (type) { + case S_BOOLEAN: + item_make(menu, 't', "[%c]", + val == no ? ' ' : '*'); + break; + case S_TRISTATE: + switch (val) { + case yes: + ch = '*'; + break; + case mod: + ch = 'M'; + break; + default: + ch = ' '; + break; + } + item_make(menu, 't', "<%c>", ch); + break; + } + } else { + item_make(menu, def_menu ? 't' : ':', " "); + } + + item_add_str("%*c%s", indent + 1, + ' ', _(menu_get_prompt(menu))); + if (val == yes) { + if (def_menu) { + item_add_str(" (%s)", + _(menu_get_prompt(def_menu))); + item_add_str(" --->"); + if (def_menu->list) { + indent += 2; + build_conf(def_menu); + indent -= 2; + } + } + return; + } + } else { + if (menu == current_menu) { + item_make(menu, ':', + "---%*c%s", indent + 1, + ' ', _(menu_get_prompt(menu))); + goto conf_childs; + } + child_count++; + val = sym_get_tristate_value(sym); + if (sym_is_choice_value(sym) && val == yes) { + item_make(menu, ':', " "); + } else { + switch (type) { + case S_BOOLEAN: + if (sym_is_changable(sym)) + item_make(menu, 't', "[%c]", + val == no ? ' ' : '*'); + else + item_make(menu, 't', "-%c-", + val == no ? ' ' : '*'); + break; + case S_TRISTATE: + switch (val) { + case yes: + ch = '*'; + break; + case mod: + ch = 'M'; + break; + default: + ch = ' '; + break; + } + if (sym_is_changable(sym)) { + if (sym->rev_dep.tri == mod) + item_make(menu, + 't', "{%c}", ch); + else + item_make(menu, + 't', "<%c>", ch); + } else + item_make(menu, 't', "-%c-", ch); + break; + default: + tmp = 2 + strlen(sym_get_string_value(sym)); + item_make(menu, 's', " (%s)", + sym_get_string_value(sym)); + tmp = indent - tmp + 4; + if (tmp < 0) + tmp = 0; + item_add_str("%*c%s%s", tmp, ' ', + _(menu_get_prompt(menu)), + (sym_has_value(sym) || + !sym_is_changable(sym)) ? "" : + _(" (NEW)")); + goto conf_childs; + } + } + item_add_str("%*c%s%s", indent + 1, ' ', + _(menu_get_prompt(menu)), + (sym_has_value(sym) || !sym_is_changable(sym)) ? + "" : _(" (NEW)")); + if (menu->prompt && menu->prompt->type == P_MENU) { + item_add_str(" --->"); + return; + } + } + +conf_childs: + indent += doint; + for (child = menu->list; child; child = child->next) + build_conf(child); + indent -= doint; +} + +static void reset_menu(void) +{ + unpost_menu(curses_menu); + clean_items(); +} + +/* adjust the menu to show this item. + * prefer not to scroll the menu if possible*/ +static void center_item(int selected_index, int *last_top_row) +{ + int toprow; + int maxy, maxx; + + scale_menu(curses_menu, &maxy, &maxx); + set_top_row(curses_menu, *last_top_row); + toprow = top_row(curses_menu); + if (selected_index >= toprow && selected_index < toprow+maxy) { + /* we can only move the selected item. no need to scroll */ + set_current_item(curses_menu, + curses_menu_items[selected_index]); + } else { + toprow = max(selected_index-maxy/2, 0); + if (toprow >= item_count(curses_menu)-maxy) + toprow = item_count(curses_menu)-mwin_max_lines; + set_top_row(curses_menu, toprow); + set_current_item(curses_menu, + curses_menu_items[selected_index]); + } + *last_top_row = toprow; + post_menu(curses_menu); + refresh_all_windows(main_window); +} + +/* this function assumes reset_menu has been called before */ +static void show_menu(const char *prompt, const char *instructions, + int selected_index, int *last_top_row) +{ + int maxx, maxy; + WINDOW *menu_window; + + current_instructions = instructions; + + clear(); + wattrset(main_window, attributes[NORMAL]); + print_in_middle(stdscr, 1, 0, COLS, + menu_backtitle, + attributes[MAIN_HEADING]); + + wattrset(main_window, attributes[MAIN_MENU_BOX]); + box(main_window, 0, 0); + wattrset(main_window, attributes[MAIN_MENU_HEADING]); + mvwprintw(main_window, 0, 3, " %s ", prompt); + wattrset(main_window, attributes[NORMAL]); + + set_menu_items(curses_menu, curses_menu_items); + + /* position the menu at the middle of the screen */ + scale_menu(curses_menu, &maxy, &maxx); + maxx = min(maxx, mwin_max_cols-2); + maxy = mwin_max_lines-2; + menu_window = derwin(main_window, + maxy, + maxx, + 2, + (mwin_max_cols-maxx)/2); + keypad(menu_window, TRUE); + set_menu_win(curses_menu, menu_window); + set_menu_sub(curses_menu, menu_window); + + /* must reassert this after changing items, otherwise returns to a + * default of 16 + */ + set_menu_format(curses_menu, maxy, 1); + center_item(selected_index, last_top_row); + set_menu_format(curses_menu, maxy, 1); + + print_function_line(); + + /* Post the menu */ + post_menu(curses_menu); + refresh_all_windows(main_window); +} + + +static void conf(struct menu *menu) +{ + char pattern[256]; + struct menu *submenu = 0; + const char *prompt = menu_get_prompt(menu); + struct symbol *sym; + struct menu *active_menu = NULL; + int res; + int current_index = 0; + int last_top_row = 0; + + bzero(pattern, sizeof(pattern)); + + while (!global_exit) { + reset_menu(); + current_menu = menu; + build_conf(menu); + if (!child_count) + break; + + show_menu(prompt ? _(prompt) : _("Main Menu"), + _(menu_instructions), + current_index, &last_top_row); + keypad((menu_win(curses_menu)), TRUE); + while (!global_exit && (res = wgetch(menu_win(curses_menu)))) { + if (process_special_keys(&res, + (struct menu *) item_data())) + break; + switch (res) { + case KEY_DOWN: + menu_driver(curses_menu, REQ_DOWN_ITEM); + break; + case KEY_UP: + menu_driver(curses_menu, REQ_UP_ITEM); + break; + case KEY_NPAGE: + menu_driver(curses_menu, REQ_SCR_DPAGE); + break; + case KEY_PPAGE: + menu_driver(curses_menu, REQ_SCR_UPAGE); + break; + case KEY_HOME: + menu_driver(curses_menu, REQ_FIRST_ITEM); + break; + case KEY_END: + menu_driver(curses_menu, REQ_LAST_ITEM); + break; + case 'h': + case '?': + show_help((struct menu *) item_data()); + break; + } + if (res == 10 || res == 27 || + res == 32 || res == 'n' || res == 'y' || + res == KEY_LEFT || res == KEY_RIGHT || + res == 'm' || res == '/') + break; + else if (canbhot(res)) { + /* check for hot keys: */ + int tmp = get_next_hot(res); + if (tmp != -1) + center_item(tmp, &last_top_row); + } + refresh_all_windows(main_window); + } + + refresh_all_windows(main_window); + /* if ESC or left*/ + if (res == 27 || (menu != &rootmenu && res == KEY_LEFT)) + break; + + /* remember location in the menu */ + last_top_row = top_row(curses_menu); + current_index = curses_item_index(); + + if (!item_tag()) + continue; + + submenu = (struct menu *) item_data(); + active_menu = (struct menu *)item_data(); + if (!submenu || !menu_is_visible(submenu)) + continue; + if (submenu) + sym = submenu->sym; + else + sym = NULL; + + switch (res) { + case ' ': + if (item_is_tag('t')) + sym_toggle_tristate_value(sym); + else if (item_is_tag('m')) + conf(submenu); + break; + case KEY_RIGHT: + case 10: /* ENTER WAS PRESSED */ + switch (item_tag()) { + case 'm': + if (single_menu_mode) + submenu->data = + (void *) (long) !submenu->data; + else + conf(submenu); + break; + case 't': + if (sym_is_choice(sym) && + sym_get_tristate_value(sym) == yes) + conf_choice(submenu); + else if (submenu->prompt && + submenu->prompt->type == P_MENU) + conf(submenu); + else if (res == 10) + sym_toggle_tristate_value(sym); + break; + case 's': + conf_string(submenu); + break; + } + break; + case 'y': + if (item_is_tag('t')) { + if (sym_set_tristate_value(sym, yes)) + break; + if (sym_set_tristate_value(sym, mod)) + btn_dialog(main_window, setmod_text, 0); + } + break; + case 'n': + if (item_is_tag('t')) + sym_set_tristate_value(sym, no); + break; + case 'm': + if (item_is_tag('t')) + sym_set_tristate_value(sym, mod); + break; + case '/': + search_conf(); + break; + } + } +} + +static void show_help(struct menu *menu) +{ + struct gstr help = str_new(); + + if (menu && menu->sym && menu_has_help(menu)) { + if (menu->sym->name) { + str_printf(&help, "CONFIG_%s:\n\n", menu->sym->name); + str_append(&help, _(menu_get_help(menu))); + str_append(&help, "\n"); + get_symbol_str(&help, menu->sym); + } + } else { + str_append(&help, nohelp_text); + } + show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help)); + str_free(&help); +} + +static void conf_choice(struct menu *menu) +{ + const char *prompt = _(menu_get_prompt(menu)); + struct menu *child = 0; + struct symbol *active; + int selected_index = 0; + int last_top_row = 0; + int res, i = 0; + + active = sym_get_choice_value(menu->sym); + /* this is mostly duplicated from the conf() function. */ + while (!global_exit) { + reset_menu(); + + for (i = 0, child = menu->list; child; child = child->next) { + if (!show_all_items && !menu_is_visible(child)) + continue; + + if (child->sym == sym_get_choice_value(menu->sym)) + item_make(child, ':', "<X> %s", + _(menu_get_prompt(child))); + else + item_make(child, ':', " %s", + _(menu_get_prompt(child))); + if (child->sym == active){ + last_top_row = top_row(curses_menu); + selected_index = i; + } + i++; + } + show_menu(prompt ? _(prompt) : _("Choice Menu"), + _(radiolist_instructions), + selected_index, + &last_top_row); + while (!global_exit && (res = wgetch(menu_win(curses_menu)))) { + if (process_special_keys( + &res, + (struct menu *) item_data())) + break; + switch (res) { + case KEY_DOWN: + menu_driver(curses_menu, REQ_DOWN_ITEM); + break; + case KEY_UP: + menu_driver(curses_menu, REQ_UP_ITEM); + break; + case KEY_NPAGE: + menu_driver(curses_menu, REQ_SCR_DPAGE); + break; + case KEY_PPAGE: + menu_driver(curses_menu, REQ_SCR_UPAGE); + break; + case KEY_HOME: + menu_driver(curses_menu, REQ_FIRST_ITEM); + break; + case KEY_END: + menu_driver(curses_menu, REQ_LAST_ITEM); + break; + case 'h': + case '?': + show_help((struct menu *) item_data()); + break; + } + if (res == 10 || res == 27 || res == ' ' || + res == KEY_LEFT) + break; + else if (canbhot(res)) { + /* check for hot keys: */ + int tmp = get_next_hot(res); + if (tmp != -1) + center_item(tmp, &last_top_row); + } + refresh_all_windows(main_window); + } + /* if ESC or left */ + if (res == 27 || res == KEY_LEFT) + break; + + child = item_data(); + if (!child || !menu_is_visible(child)) + continue; + switch (res) { + case ' ': + case 10: + case KEY_RIGHT: + sym_set_tristate_value(child->sym, yes); + return; + case 'h': + case '?': + show_help(child); + active = child->sym; + break; + case KEY_EXIT: + return; + } + } +} + +static void conf_string(struct menu *menu) +{ + const char *prompt = menu_get_prompt(menu); + char dialog_input_result[256]; + + while (1) { + int res; + const char *heading; + + switch (sym_get_type(menu->sym)) { + case S_INT: + heading = _(inputbox_instructions_int); + break; + case S_HEX: + heading = _(inputbox_instructions_hex); + break; + case S_STRING: + heading = _(inputbox_instructions_string); + break; + default: + heading = _("Internal nconf error!"); + } + res = dialog_inputbox(main_window, + prompt ? _(prompt) : _("Main Menu"), + heading, + sym_get_string_value(menu->sym), + dialog_input_result, + sizeof(dialog_input_result)); + switch (res) { + case 0: + if (sym_set_string_value(menu->sym, + dialog_input_result)) + return; + btn_dialog(main_window, + _("You have made an invalid entry."), 0); + break; + case 1: + show_help(menu); + break; + case KEY_EXIT: + return; + } + } +} + +static void conf_load(void) +{ + char dialog_input_result[256]; + while (1) { + int res; + res = dialog_inputbox(main_window, + NULL, load_config_text, + filename, + dialog_input_result, + sizeof(dialog_input_result)); + switch (res) { + case 0: + if (!dialog_input_result[0]) + return; + if (!conf_read(dialog_input_result)) { + set_config_filename(dialog_input_result); + sym_set_change_count(1); + return; + } + btn_dialog(main_window, _("File does not exist!"), 0); + break; + case 1: + show_scroll_win(main_window, + _("Load Alternate Configuration"), + load_config_help); + break; + case KEY_EXIT: + return; + } + } +} + +static void conf_save(void) +{ + char dialog_input_result[256]; + while (1) { + int res; + res = dialog_inputbox(main_window, + NULL, save_config_text, + filename, + dialog_input_result, + sizeof(dialog_input_result)); + switch (res) { + case 0: + if (!dialog_input_result[0]) + return; + supress_stdout(0); + res = conf_write(dialog_input_result); + supress_stdout(1); + if (!res) { + char buf[1024]; + sprintf(buf, "%s %s", + _("configuration file saved to: "), + dialog_input_result); + btn_dialog(main_window, + buf, 1, "<OK>"); + set_config_filename(dialog_input_result); + return; + } + btn_dialog(main_window, _("Can't create file! " + "Probably a nonexistent directory."), + 1, "<OK>"); + break; + case 1: + show_scroll_win(main_window, + _("Save Alternate Configuration"), + save_config_help); + break; + case KEY_EXIT: + return; + } + } +} + +void setup_windows(void) +{ + if (main_window != NULL) + delwin(main_window); + + /* set up the menu and menu window */ + main_window = newwin(LINES-2, COLS-2, 2, 1); + keypad(main_window, TRUE); + mwin_max_lines = LINES-6; + mwin_max_cols = COLS-6; + + /* panels order is from bottom to top */ + new_panel(main_window); +} + +int main(int ac, char **av) +{ + char *mode; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + conf_parse(av[1]); + conf_read(NULL); + + mode = getenv("NCONFIG_MODE"); + if (mode) { + if (!strcasecmp(mode, "single_menu")) + single_menu_mode = 1; + } + + /* Initialize curses */ + initscr(); + /* set color theme */ + set_colors(); + + cbreak(); + noecho(); + keypad(stdscr, TRUE); + curs_set(0); + + if (COLS < 75 || LINES < 20) { + endwin(); + printf("Your terminal should have at " + "least 20 lines and 75 columns\n"); + return 1; + } + + notimeout(stdscr, FALSE); + ESCDELAY = 1; + + /* set btns menu */ + curses_menu = new_menu(curses_menu_items); + menu_opts_off(curses_menu, O_SHOWDESC); + menu_opts_off(curses_menu, O_SHOWMATCH); + menu_opts_on(curses_menu, O_ONEVALUE); + menu_opts_on(curses_menu, O_NONCYCLIC); + set_menu_mark(curses_menu, " "); + set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]); + set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]); + set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]); + + set_config_filename(conf_get_configname()); + setup_windows(); + + /* check for KEY_FUNC(1) */ + if (has_key(KEY_F(1)) == FALSE) { + show_scroll_win(main_window, + _("Instructions"), + _(menu_no_f_instructions)); + } + + + + /* do the work */ + while (!global_exit) { + conf(&rootmenu); + if (!global_exit && do_exit() == 0) + break; + } + /* ok, we are done */ + unpost_menu(curses_menu); + free_menu(curses_menu); + delwin(main_window); + clear(); + refresh(); + endwin(); + return 0; +} + diff --git a/scripts/kconfig/nconf.gui.c b/scripts/kconfig/nconf.gui.c new file mode 100644 index 0000000..115edb4 --- /dev/null +++ b/scripts/kconfig/nconf.gui.c @@ -0,0 +1,617 @@ +/* + * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com? + * Released under the terms of the GNU GPL v2.0. + * + * Derived from menuconfig. + * + */ +#include "nconf.h" + +/* a list of all the different widgets we use */ +attributes_t attributes[ATTR_MAX+1] = {0}; + +/* available colors: + COLOR_BLACK 0 + COLOR_RED 1 + COLOR_GREEN 2 + COLOR_YELLOW 3 + COLOR_BLUE 4 + COLOR_MAGENTA 5 + COLOR_CYAN 6 + COLOR_WHITE 7 + */ +static void set_normal_colors(void) +{ + init_pair(NORMAL, -1, -1); + init_pair(MAIN_HEADING, COLOR_MAGENTA, -1); + + /* FORE is for the selected item */ + init_pair(MAIN_MENU_FORE, -1, -1); + /* BACK for all the rest */ + init_pair(MAIN_MENU_BACK, -1, -1); + init_pair(MAIN_MENU_GREY, -1, -1); + init_pair(MAIN_MENU_HEADING, COLOR_GREEN, -1); + init_pair(MAIN_MENU_BOX, COLOR_YELLOW, -1); + + init_pair(SCROLLWIN_TEXT, -1, -1); + init_pair(SCROLLWIN_HEADING, COLOR_GREEN, -1); + init_pair(SCROLLWIN_BOX, COLOR_YELLOW, -1); + + init_pair(DIALOG_TEXT, -1, -1); + init_pair(DIALOG_BOX, COLOR_YELLOW, -1); + init_pair(DIALOG_MENU_BACK, COLOR_YELLOW, -1); + init_pair(DIALOG_MENU_FORE, COLOR_RED, -1); + + init_pair(INPUT_BOX, COLOR_YELLOW, -1); + init_pair(INPUT_HEADING, COLOR_GREEN, -1); + init_pair(INPUT_TEXT, -1, -1); + init_pair(INPUT_FIELD, -1, -1); + + init_pair(FUNCTION_HIGHLIGHT, -1, -1); + init_pair(FUNCTION_TEXT, COLOR_BLUE, -1); +} + +/* available attributes: + A_NORMAL Normal display (no highlight) + A_STANDOUT Best highlighting mode of the terminal. + A_UNDERLINE Underlining + A_REVERSE Reverse video + A_BLINK Blinking + A_DIM Half bright + A_BOLD Extra bright or bold + A_PROTECT Protected mode + A_INVIS Invisible or blank mode + A_ALTCHARSET Alternate character set + A_CHARTEXT Bit-mask to extract a character + COLOR_PAIR(n) Color-pair number n + */ +static void normal_color_theme(void) +{ + /* automatically add color... */ +#define mkattr(name, attr) do { \ +attributes[name] = attr | COLOR_PAIR(name); } while (0) + mkattr(NORMAL, NORMAL); + mkattr(MAIN_HEADING, A_BOLD | A_UNDERLINE); + + mkattr(MAIN_MENU_FORE, A_REVERSE); + mkattr(MAIN_MENU_BACK, A_NORMAL); + mkattr(MAIN_MENU_GREY, A_NORMAL); + mkattr(MAIN_MENU_HEADING, A_BOLD); + mkattr(MAIN_MENU_BOX, A_NORMAL); + + mkattr(SCROLLWIN_TEXT, A_NORMAL); + mkattr(SCROLLWIN_HEADING, A_BOLD); + mkattr(SCROLLWIN_BOX, A_BOLD); + + mkattr(DIALOG_TEXT, A_BOLD); + mkattr(DIALOG_BOX, A_BOLD); + mkattr(DIALOG_MENU_FORE, A_STANDOUT); + mkattr(DIALOG_MENU_BACK, A_NORMAL); + + mkattr(INPUT_BOX, A_NORMAL); + mkattr(INPUT_HEADING, A_BOLD); + mkattr(INPUT_TEXT, A_NORMAL); + mkattr(INPUT_FIELD, A_UNDERLINE); + + mkattr(FUNCTION_HIGHLIGHT, A_BOLD); + mkattr(FUNCTION_TEXT, A_REVERSE); +} + +static void no_colors_theme(void) +{ + /* automatically add highlight, no color */ +#define mkattrn(name, attr) { attributes[name] = attr; } + + mkattrn(NORMAL, NORMAL); + mkattrn(MAIN_HEADING, A_BOLD | A_UNDERLINE); + + mkattrn(MAIN_MENU_FORE, A_STANDOUT); + mkattrn(MAIN_MENU_BACK, A_NORMAL); + mkattrn(MAIN_MENU_GREY, A_NORMAL); + mkattrn(MAIN_MENU_HEADING, A_BOLD); + mkattrn(MAIN_MENU_BOX, A_NORMAL); + + mkattrn(SCROLLWIN_TEXT, A_NORMAL); + mkattrn(SCROLLWIN_HEADING, A_BOLD); + mkattrn(SCROLLWIN_BOX, A_BOLD); + + mkattrn(DIALOG_TEXT, A_NORMAL); + mkattrn(DIALOG_BOX, A_BOLD); + mkattrn(DIALOG_MENU_FORE, A_STANDOUT); + mkattrn(DIALOG_MENU_BACK, A_NORMAL); + + mkattrn(INPUT_BOX, A_BOLD); + mkattrn(INPUT_HEADING, A_BOLD); + mkattrn(INPUT_TEXT, A_NORMAL); + mkattrn(INPUT_FIELD, A_UNDERLINE); + + mkattrn(FUNCTION_HIGHLIGHT, A_BOLD); + mkattrn(FUNCTION_TEXT, A_REVERSE); +} + +void set_colors() +{ + start_color(); + use_default_colors(); + set_normal_colors(); + if (has_colors()) { + normal_color_theme(); + } else { + /* give deafults */ + no_colors_theme(); + } +} + + +/* this changes the windows attributes !!! */ +void print_in_middle(WINDOW *win, + int starty, + int startx, + int width, + const char *string, + chtype color) +{ int length, x, y; + float temp; + + + if (win == NULL) + win = stdscr; + getyx(win, y, x); + if (startx != 0) + x = startx; + if (starty != 0) + y = starty; + if (width == 0) + width = 80; + + length = strlen(string); + temp = (width - length) / 2; + x = startx + (int)temp; + wattrset(win, color); + mvwprintw(win, y, x, "%s", string); + refresh(); +} + +int get_line_no(const char *text) +{ + int i; + int total = 1; + + if (!text) + return 0; + + for (i = 0; text[i] != '\0'; i++) + if (text[i] == '\n') + total++; + return total; +} + +const char *get_line(const char *text, int line_no) +{ + int i; + int lines = 0; + + if (!text) + return 0; + + for (i = 0; text[i] != '\0' && lines < line_no; i++) + if (text[i] == '\n') + lines++; + return text+i; +} + +int get_line_length(const char *line) +{ + int res = 0; + while (*line != '\0' && *line != '\n') { + line++; + res++; + } + return res; +} + +/* print all lines to the window. */ +void fill_window(WINDOW *win, const char *text) +{ + int x, y; + int total_lines = get_line_no(text); + int i; + + getmaxyx(win, y, x); + /* do not go over end of line */ + total_lines = min(total_lines, y); + for (i = 0; i < total_lines; i++) { + char tmp[x+10]; + const char *line = get_line(text, i); + int len = get_line_length(line); + strncpy(tmp, line, min(len, x)); + tmp[len] = '\0'; + mvwprintw(win, i, 0, tmp); + } +} + +/* get the message, and buttons. + * each button must be a char* + * return the selected button + * + * this dialog is used for 2 different things: + * 1) show a text box, no buttons. + * 2) show a dialog, with horizontal buttons + */ +int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...) +{ + va_list ap; + char *btn; + int btns_width = 0; + int msg_lines = 0; + int msg_width = 0; + int total_width; + int win_rows = 0; + WINDOW *win; + WINDOW *msg_win; + WINDOW *menu_win; + MENU *menu; + ITEM *btns[btn_num+1]; + int i, x, y; + int res = -1; + + + va_start(ap, btn_num); + for (i = 0; i < btn_num; i++) { + btn = va_arg(ap, char *); + btns[i] = new_item(btn, ""); + btns_width += strlen(btn)+1; + } + va_end(ap); + btns[btn_num] = NULL; + + /* find the widest line of msg: */ + msg_lines = get_line_no(msg); + for (i = 0; i < msg_lines; i++) { + const char *line = get_line(msg, i); + int len = get_line_length(line); + if (msg_width < len) + msg_width = len; + } + + total_width = max(msg_width, btns_width); + /* place dialog in middle of screen */ + y = (LINES-(msg_lines+4))/2; + x = (COLS-(total_width+4))/2; + + + /* create the windows */ + if (btn_num > 0) + win_rows = msg_lines+4; + else + win_rows = msg_lines+2; + + win = newwin(win_rows, total_width+4, y, x); + keypad(win, TRUE); + menu_win = derwin(win, 1, btns_width, win_rows-2, + 1+(total_width+2-btns_width)/2); + menu = new_menu(btns); + msg_win = derwin(win, win_rows-2, msg_width, 1, + 1+(total_width+2-msg_width)/2); + + set_menu_fore(menu, attributes[DIALOG_MENU_FORE]); + set_menu_back(menu, attributes[DIALOG_MENU_BACK]); + + wattrset(win, attributes[DIALOG_BOX]); + box(win, 0, 0); + + /* print message */ + wattrset(msg_win, attributes[DIALOG_TEXT]); + fill_window(msg_win, msg); + + set_menu_win(menu, win); + set_menu_sub(menu, menu_win); + set_menu_format(menu, 1, btn_num); + menu_opts_off(menu, O_SHOWDESC); + menu_opts_off(menu, O_SHOWMATCH); + menu_opts_on(menu, O_ONEVALUE); + menu_opts_on(menu, O_NONCYCLIC); + set_menu_mark(menu, ""); + post_menu(menu); + + + touchwin(win); + refresh_all_windows(main_window); + while ((res = wgetch(win))) { + switch (res) { + case KEY_LEFT: + menu_driver(menu, REQ_LEFT_ITEM); + break; + case KEY_RIGHT: + menu_driver(menu, REQ_RIGHT_ITEM); + break; + case 10: /* ENTER */ + case 27: /* ESCAPE */ + case ' ': + case KEY_F(F_BACK): + case KEY_F(F_EXIT): + break; + } + touchwin(win); + refresh_all_windows(main_window); + + if (res == 10 || res == ' ') { + res = item_index(current_item(menu)); + break; + } else if (res == 27 || res == KEY_F(F_BACK) || + res == KEY_F(F_EXIT)) { + res = KEY_EXIT; + break; + } + } + + unpost_menu(menu); + free_menu(menu); + for (i = 0; i < btn_num; i++) + free_item(btns[i]); + + delwin(win); + return res; +} + +int dialog_inputbox(WINDOW *main_window, + const char *title, const char *prompt, + const char *init, char *result, int result_len) +{ + int prompt_lines = 0; + int prompt_width = 0; + WINDOW *win; + WINDOW *prompt_win; + WINDOW *form_win; + PANEL *panel; + int i, x, y; + int res = -1; + int cursor_position = strlen(init); + + + /* find the widest line of msg: */ + prompt_lines = get_line_no(prompt); + for (i = 0; i < prompt_lines; i++) { + const char *line = get_line(prompt, i); + int len = get_line_length(line); + prompt_width = max(prompt_width, len); + } + + if (title) + prompt_width = max(prompt_width, strlen(title)); + + /* place dialog in middle of screen */ + y = (LINES-(prompt_lines+4))/2; + x = (COLS-(prompt_width+4))/2; + + strncpy(result, init, result_len); + + /* create the windows */ + win = newwin(prompt_lines+6, prompt_width+7, y, x); + prompt_win = derwin(win, prompt_lines+1, prompt_width, 2, 2); + form_win = derwin(win, 1, prompt_width, prompt_lines+3, 2); + keypad(form_win, TRUE); + + wattrset(form_win, attributes[INPUT_FIELD]); + + wattrset(win, attributes[INPUT_BOX]); + box(win, 0, 0); + wattrset(win, attributes[INPUT_HEADING]); + if (title) + mvwprintw(win, 0, 3, "%s", title); + + /* print message */ + wattrset(prompt_win, attributes[INPUT_TEXT]); + fill_window(prompt_win, prompt); + + mvwprintw(form_win, 0, 0, "%*s", prompt_width, " "); + mvwprintw(form_win, 0, 0, "%s", result); + + /* create panels */ + panel = new_panel(win); + + /* show the cursor */ + curs_set(1); + + touchwin(win); + refresh_all_windows(main_window); + while ((res = wgetch(form_win))) { + int len = strlen(result); + switch (res) { + case 10: /* ENTER */ + case 27: /* ESCAPE */ + case KEY_F(F_HELP): + case KEY_F(F_EXIT): + case KEY_F(F_BACK): + break; + case 127: + case KEY_BACKSPACE: + if (cursor_position > 0) { + memmove(&result[cursor_position-1], + &result[cursor_position], + len-cursor_position+1); + cursor_position--; + } + break; + case KEY_DC: + if (cursor_position >= 0 && cursor_position < len) { + memmove(&result[cursor_position], + &result[cursor_position+1], + len-cursor_position+1); + } + break; + case KEY_UP: + case KEY_RIGHT: + if (cursor_position < len && + cursor_position < min(result_len, prompt_width)) + cursor_position++; + break; + case KEY_DOWN: + case KEY_LEFT: + if (cursor_position > 0) + cursor_position--; + break; + default: + if ((isgraph(res) || isspace(res)) && + len-2 < result_len) { + /* insert the char at the proper position */ + memmove(&result[cursor_position+1], + &result[cursor_position], + len+1); + result[cursor_position] = res; + cursor_position++; + } else { + mvprintw(0, 0, "unknow key: %d\n", res); + } + break; + } + wmove(form_win, 0, 0); + wclrtoeol(form_win); + mvwprintw(form_win, 0, 0, "%*s", prompt_width, " "); + mvwprintw(form_win, 0, 0, "%s", result); + wmove(form_win, 0, cursor_position); + touchwin(win); + refresh_all_windows(main_window); + + if (res == 10) { + res = 0; + break; + } else if (res == 27 || res == KEY_F(F_BACK) || + res == KEY_F(F_EXIT)) { + res = KEY_EXIT; + break; + } else if (res == KEY_F(F_HELP)) { + res = 1; + break; + } + } + + /* hide the cursor */ + curs_set(0); + del_panel(panel); + delwin(prompt_win); + delwin(form_win); + delwin(win); + return res; +} + +/* refresh all windows in the correct order */ +void refresh_all_windows(WINDOW *main_window) +{ + update_panels(); + touchwin(main_window); + refresh(); +} + +/* layman's scrollable window... */ +void show_scroll_win(WINDOW *main_window, + const char *title, + const char *text) +{ + int res; + int total_lines = get_line_no(text); + int x, y; + int start_x = 0, start_y = 0; + int text_lines = 0, text_cols = 0; + int total_cols = 0; + int win_cols = 0; + int win_lines = 0; + int i = 0; + WINDOW *win; + WINDOW *pad; + PANEL *panel; + + /* find the widest line of msg: */ + total_lines = get_line_no(text); + for (i = 0; i < total_lines; i++) { + const char *line = get_line(text, i); + int len = get_line_length(line); + total_cols = max(total_cols, len+2); + } + + /* create the pad */ + pad = newpad(total_lines+10, total_cols+10); + wattrset(pad, attributes[SCROLLWIN_TEXT]); + fill_window(pad, text); + + win_lines = min(total_lines+4, LINES-2); + win_cols = min(total_cols+2, COLS-2); + text_lines = max(win_lines-4, 0); + text_cols = max(win_cols-2, 0); + + /* place window in middle of screen */ + y = (LINES-win_lines)/2; + x = (COLS-win_cols)/2; + + win = newwin(win_lines, win_cols, y, x); + keypad(win, TRUE); + /* show the help in the help window, and show the help panel */ + wattrset(win, attributes[SCROLLWIN_BOX]); + box(win, 0, 0); + wattrset(win, attributes[SCROLLWIN_HEADING]); + mvwprintw(win, 0, 3, " %s ", title); + panel = new_panel(win); + + /* handle scrolling */ + do { + + copywin(pad, win, start_y, start_x, 2, 2, text_lines, + text_cols, 0); + print_in_middle(win, + text_lines+2, + 0, + text_cols, + "<OK>", + attributes[DIALOG_MENU_FORE]); + wrefresh(win); + + res = wgetch(win); + switch (res) { + case KEY_NPAGE: + case ' ': + start_y += text_lines-2; + break; + case KEY_PPAGE: + start_y -= text_lines+2; + break; + case KEY_HOME: + start_y = 0; + break; + case KEY_END: + start_y = total_lines-text_lines; + break; + case KEY_DOWN: + case 'j': + start_y++; + break; + case KEY_UP: + case 'k': + start_y--; + break; + case KEY_LEFT: + case 'h': + start_x--; + break; + case KEY_RIGHT: + case 'l': + start_x++; + break; + } + if (res == 10 || res == 27 || res == 'q' + || res == KEY_F(F_BACK) || res == KEY_F(F_EXIT)) { + break; + } + if (start_y < 0) + start_y = 0; + if (start_y >= total_lines-text_lines) + start_y = total_lines-text_lines; + if (start_x < 0) + start_x = 0; + if (start_x >= total_cols-text_cols) + start_x = total_cols-text_cols; + } while (res); + + del_panel(panel); + delwin(win); + refresh_all_windows(main_window); +} diff --git a/scripts/kconfig/nconf.h b/scripts/kconfig/nconf.h new file mode 100644 index 0000000..fb42966 --- /dev/null +++ b/scripts/kconfig/nconf.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com? + * Released under the terms of the GNU GPL v2.0. + * + * Derived from menuconfig. + * + */ + +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <locale.h> +#include <curses.h> +#include <menu.h> +#include <panel.h> +#include <form.h> + +#include <stdio.h> +#include <time.h> +#include <sys/time.h> + +#include "ncurses.h" + +#define max(a, b) ({\ + typeof(a) _a = a;\ + typeof(b) _b = b;\ + _a > _b ? _a : _b; }) + +#define min(a, b) ({\ + typeof(a) _a = a;\ + typeof(b) _b = b;\ + _a < _b ? _a : _b; }) + +typedef enum { + NORMAL = 1, + MAIN_HEADING, + MAIN_MENU_BOX, + MAIN_MENU_FORE, + MAIN_MENU_BACK, + MAIN_MENU_GREY, + MAIN_MENU_HEADING, + SCROLLWIN_TEXT, + SCROLLWIN_HEADING, + SCROLLWIN_BOX, + DIALOG_TEXT, + DIALOG_MENU_FORE, + DIALOG_MENU_BACK, + DIALOG_BOX, + INPUT_BOX, + INPUT_HEADING, + INPUT_TEXT, + INPUT_FIELD, + FUNCTION_TEXT, + FUNCTION_HIGHLIGHT, + ATTR_MAX +} attributes_t; +extern attributes_t attributes[]; + +typedef enum { + F_HELP = 1, + F_SYMBOL = 2, + F_INSTS = 3, + F_CONF = 4, + F_BACK = 5, + F_SAVE = 6, + F_LOAD = 7, + F_EXIT = 8 +} function_key; + +void set_colors(void); + +/* this changes the windows attributes !!! */ +void print_in_middle(WINDOW *win, + int starty, + int startx, + int width, + const char *string, + chtype color); +int get_line_length(const char *line); +int get_line_no(const char *text); +const char *get_line(const char *text, int line_no); +void fill_window(WINDOW *win, const char *text); +int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...); +int dialog_inputbox(WINDOW *main_window, + const char *title, const char *prompt, + const char *init, char *result, int result_len); +void refresh_all_windows(WINDOW *main_window); +void show_scroll_win(WINDOW *main_window, + const char *title, + const char *text); diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index 6c8fbbb..2e7a048 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -651,12 +651,20 @@ bool sym_is_changable(struct symbol *sym) return sym->visible > sym->rev_dep.tri; } +static unsigned strhash(const char *s) +{ + /* fnv32 hash */ + unsigned hash = 2166136261U; + for (; *s; s++) + hash = (hash ^ *s) * 0x01000193; + return hash; +} + struct symbol *sym_lookup(const char *name, int flags) { struct symbol *symbol; - const char *ptr; char *new_name; - int hash = 0; + int hash; if (name) { if (name[0] && !name[1]) { @@ -666,12 +674,11 @@ struct symbol *sym_lookup(const char *name, int flags) case 'n': return &symbol_no; } } - for (ptr = name; *ptr; ptr++) - hash += *ptr; - hash &= 0xff; + hash = strhash(name) % SYMBOL_HASHSIZE; for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { - if (!strcmp(symbol->name, name) && + if (symbol->name && + !strcmp(symbol->name, name) && (flags ? symbol->flags & flags : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE)))) return symbol; @@ -679,7 +686,7 @@ struct symbol *sym_lookup(const char *name, int flags) new_name = strdup(name); } else { new_name = NULL; - hash = 256; + hash = 0; } symbol = malloc(sizeof(*symbol)); @@ -697,7 +704,6 @@ struct symbol *sym_lookup(const char *name, int flags) struct symbol *sym_find(const char *name) { struct symbol *symbol = NULL; - const char *ptr; int hash = 0; if (!name) @@ -710,12 +716,11 @@ struct symbol *sym_find(const char *name) case 'n': return &symbol_no; } } - for (ptr = name; *ptr; ptr++) - hash += *ptr; - hash &= 0xff; + hash = strhash(name) % SYMBOL_HASHSIZE; for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { - if (!strcmp(symbol->name, name) && + if (symbol->name && + !strcmp(symbol->name, name) && !(symbol->flags & SYMBOL_CONST)) break; } @@ -750,6 +755,7 @@ struct symbol **sym_re_search(const char *pattern) return NULL; } } + sym_calc_value(sym); sym_arr[cnt++] = sym; } if (sym_arr) diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c index 25d1ec4..78b5c04 100644 --- a/scripts/kconfig/util.c +++ b/scripts/kconfig/util.c @@ -78,6 +78,7 @@ struct gstr str_new(void) struct gstr gs; gs.s = malloc(sizeof(char) * 64); gs.len = 64; + gs.max_width = 0; strcpy(gs.s, "\0"); return gs; } @@ -88,6 +89,7 @@ struct gstr str_assign(const char *s) struct gstr gs; gs.s = strdup(s); gs.len = strlen(s) + 1; + gs.max_width = 0; return gs; } diff --git a/scripts/kconfig/zconf.tab.c_shipped b/scripts/kconfig/zconf.tab.c_shipped index 6e9dcd5..32a9eef 100644 --- a/scripts/kconfig/zconf.tab.c_shipped +++ b/scripts/kconfig/zconf.tab.c_shipped @@ -104,7 +104,7 @@ static void zconf_error(const char *err, ...); static void zconferror(const char *err); static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken); -struct symbol *symbol_hash[257]; +struct symbol *symbol_hash[SYMBOL_HASHSIZE]; static struct menu *current_menu, *current_entry; @@ -2220,7 +2220,7 @@ void conf_parse(const char *name) zconf_initscan(name); sym_init(); - menu_init(); + _menu_init(); modules_sym = sym_lookup(NULL, 0); modules_sym->type = S_BOOLEAN; modules_sym->flags |= SYMBOL_AUTO; @@ -2336,9 +2336,9 @@ static void print_symbol(FILE *out, struct menu *menu) struct property *prop; if (sym_is_choice(sym)) - fprintf(out, "choice\n"); + fprintf(out, "\nchoice\n"); else - fprintf(out, "config %s\n", sym->name); + fprintf(out, "\nconfig %s\n", sym->name); switch (sym->type) { case S_BOOLEAN: fputs(" boolean\n", out); @@ -2384,6 +2384,21 @@ static void print_symbol(FILE *out, struct menu *menu) case P_CHOICE: fputs(" #choice value\n", out); break; + case P_SELECT: + fputs( " select ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; + case P_RANGE: + fputs( " range ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; + case P_MENU: + fputs( " menu ", out); + print_quoted_string(out, prop->text); + fputc('\n', out); + break; default: fprintf(out, " unknown prop %d!\n", prop->type); break; @@ -2395,7 +2410,6 @@ static void print_symbol(FILE *out, struct menu *menu) menu->help[len] = 0; fprintf(out, " help\n%s\n", menu->help); } - fputc('\n', out); } void zconfdump(FILE *out) @@ -2428,7 +2442,6 @@ void zconfdump(FILE *out) expr_fprint(prop->visible.expr, out); fputc('\n', out); } - fputs("\n", out); } if (menu->list) diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y index 8c43491..23dfd3b 100644 --- a/scripts/kconfig/zconf.y +++ b/scripts/kconfig/zconf.y @@ -27,7 +27,7 @@ static void zconf_error(const char *err, ...); static void zconferror(const char *err); static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken); -struct symbol *symbol_hash[257]; +struct symbol *symbol_hash[SYMBOL_HASHSIZE]; static struct menu *current_menu, *current_entry; @@ -475,7 +475,7 @@ void conf_parse(const char *name) zconf_initscan(name); sym_init(); - menu_init(); + _menu_init(); modules_sym = sym_lookup(NULL, 0); modules_sym->type = S_BOOLEAN; modules_sym->flags |= SYMBOL_AUTO; @@ -591,9 +591,9 @@ static void print_symbol(FILE *out, struct menu *menu) struct property *prop; if (sym_is_choice(sym)) - fprintf(out, "choice\n"); + fprintf(out, "\nchoice\n"); else - fprintf(out, "config %s\n", sym->name); + fprintf(out, "\nconfig %s\n", sym->name); switch (sym->type) { case S_BOOLEAN: fputs(" boolean\n", out); @@ -639,6 +639,21 @@ static void print_symbol(FILE *out, struct menu *menu) case P_CHOICE: fputs(" #choice value\n", out); break; + case P_SELECT: + fputs( " select ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; + case P_RANGE: + fputs( " range ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; + case P_MENU: + fputs( " menu ", out); + print_quoted_string(out, prop->text); + fputc('\n', out); + break; default: fprintf(out, " unknown prop %d!\n", prop->type); break; @@ -650,7 +665,6 @@ static void print_symbol(FILE *out, struct menu *menu) menu->help[len] = 0; fprintf(out, " help\n%s\n", menu->help); } - fputc('\n', out); } void zconfdump(FILE *out) @@ -683,7 +697,6 @@ void zconfdump(FILE *out) expr_fprint(prop->visible.expr, out); fputc('\n', out); } - fputs("\n", out); } if (menu->list) diff --git a/scripts/markup_oops.pl b/scripts/markup_oops.pl index e950f9c..827896f 100644 --- a/scripts/markup_oops.pl +++ b/scripts/markup_oops.pl @@ -2,6 +2,7 @@ use File::Basename; use Math::BigInt; +use Getopt::Long; # Copyright 2008, Intel Corporation # @@ -15,6 +16,16 @@ use Math::BigInt; # Arjan van de Ven <arjan@linux.intel.com> +my $cross_compile = ""; +my $vmlinux_name = ""; +my $modulefile = ""; + +# Get options +Getopt::Long::GetOptions( + 'cross-compile|c=s' => \$cross_compile, + 'module|m=s' => \$modulefile, + 'help|h' => \&usage, +) || usage (); my $vmlinux_name = $ARGV[0]; if (!defined($vmlinux_name)) { my $kerver = `uname -r`; @@ -23,9 +34,8 @@ if (!defined($vmlinux_name)) { print "No vmlinux specified, assuming $vmlinux_name\n"; } my $filename = $vmlinux_name; -# -# Step 1: Parse the oops to find the EIP value -# + +# Parse the oops to find the EIP value my $target = "0"; my $function; @@ -177,26 +187,26 @@ my $decodestart = Math::BigInt->from_hex("0x$target") - Math::BigInt->from_hex(" my $decodestop = Math::BigInt->from_hex("0x$target") + 8192; if ($target eq "0") { print "No oops found!\n"; - print "Usage: \n"; - print " dmesg | perl scripts/markup_oops.pl vmlinux\n"; - exit; + usage(); } # if it's a module, we need to find the .ko file and calculate a load offset if ($module ne "") { - my $modulefile = `modinfo $module | grep '^filename:' | awk '{ print \$2 }'`; - chomp($modulefile); + if ($modulefile eq "") { + $modulefile = `modinfo -F filename $module`; + chomp($modulefile); + } $filename = $modulefile; if ($filename eq "") { print "Module .ko file for $module not found. Aborting\n"; exit; } # ok so we found the module, now we need to calculate the vma offset - open(FILE, "objdump -dS $filename |") || die "Cannot start objdump"; + open(FILE, $cross_compile."objdump -dS $filename |") || die "Cannot start objdump"; while (<FILE>) { if ($_ =~ /^([0-9a-f]+) \<$function\>\:/) { my $fu = $1; - $vmaoffset = hex($target) - hex($fu) - hex($func_offset); + $vmaoffset = Math::BigInt->from_hex("0x$target") - Math::BigInt->from_hex("0x$fu") - Math::BigInt->from_hex("0x$func_offset"); } } close(FILE); @@ -204,7 +214,7 @@ if ($module ne "") { my $counter = 0; my $state = 0; -my $center = 0; +my $center = -1; my @lines; my @reglines; @@ -212,7 +222,7 @@ sub InRange { my ($address, $target) = @_; my $ad = "0x".$address; my $ta = "0x".$target; - my $delta = hex($ad) - hex($ta); + my $delta = Math::BigInt->from_hex($ad) - Math::BigInt->from_hex($ta); if (($delta > -4096) && ($delta < 4096)) { return 1; @@ -225,7 +235,7 @@ sub InRange { # first, parse the input into the lines array, but to keep size down, # we only do this for 4Kb around the sweet spot -open(FILE, "objdump -dS --adjust-vma=$vmaoffset --start-address=$decodestart --stop-address=$decodestop $filename |") || die "Cannot start objdump"; +open(FILE, $cross_compile."objdump -dS --adjust-vma=$vmaoffset --start-address=$decodestart --stop-address=$decodestop $filename |") || die "Cannot start objdump"; while (<FILE>) { my $line = $_; @@ -236,7 +246,8 @@ while (<FILE>) { $state = 1; } } - } else { + } + if ($state == 1) { if ($line =~ /^([a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9]+)\:/) { my $val = $1; if (!InRange($val, $target)) { @@ -259,7 +270,7 @@ if ($counter == 0) { exit; } -if ($center == 0) { +if ($center == -1) { print "No matching code found \n"; exit; } @@ -344,3 +355,16 @@ while ($i < $finish) { $i = $i +1; } +sub usage { + print <<EOT; +Usage: + dmesg | perl $0 [OPTION] [VMLINUX] + +OPTION: + -c, --cross-compile CROSS_COMPILE Specify the prefix used for toolchain. + -m, --module MODULE_DIRNAME Specify the module filename. + -h, --help Help. +EOT + exit; +} + diff --git a/scripts/mkcompile_h b/scripts/mkcompile_h index 23dbad8..50ad317 100755 --- a/scripts/mkcompile_h +++ b/scripts/mkcompile_h @@ -67,9 +67,8 @@ UTS_TRUNCATE="cut -b -$UTS_LEN" echo \#define LINUX_COMPILE_BY \"`whoami`\" echo \#define LINUX_COMPILE_HOST \"`hostname | $UTS_TRUNCATE`\" - if [ -x /bin/dnsdomainname ]; then - domain=`dnsdomainname 2> /dev/null` - elif [ -x /bin/domainname ]; then + domain=`dnsdomainname 2> /dev/null` + if [ -z "$domain" ]; then domain=`domainname 2> /dev/null` fi diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 2092361..3318692 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -781,10 +781,13 @@ static void check_section(const char *modname, struct elf_info *elf, #define ALL_EXIT_TEXT_SECTIONS \ ".exit.text$", ".devexit.text$", ".cpuexit.text$", ".memexit.text$" -#define ALL_INIT_SECTIONS INIT_SECTIONS, DEV_INIT_SECTIONS, \ - CPU_INIT_SECTIONS, MEM_INIT_SECTIONS -#define ALL_EXIT_SECTIONS EXIT_SECTIONS, DEV_EXIT_SECTIONS, \ - CPU_EXIT_SECTIONS, MEM_EXIT_SECTIONS +#define ALL_XXXINIT_SECTIONS DEV_INIT_SECTIONS, CPU_INIT_SECTIONS, \ + MEM_INIT_SECTIONS +#define ALL_XXXEXIT_SECTIONS DEV_EXIT_SECTIONS, CPU_EXIT_SECTIONS, \ + MEM_EXIT_SECTIONS + +#define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS +#define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS #define DATA_SECTIONS ".data$", ".data.rel$" #define TEXT_SECTIONS ".text$" @@ -814,33 +817,29 @@ static const char *data_sections[] = { DATA_SECTIONS, NULL }; /* symbols in .data that may refer to init/exit sections */ -static const char *symbol_white_list[] = -{ - "*driver", - "*_template", /* scsi uses *_template a lot */ - "*_timer", /* arm uses ops structures named _timer a lot */ - "*_sht", /* scsi also used *_sht to some extent */ - "*_ops", - "*_probe", - "*_probe_one", - "*_console", - NULL -}; +#define DEFAULT_SYMBOL_WHITE_LIST \ + "*driver", \ + "*_template", /* scsi uses *_template a lot */ \ + "*_timer", /* arm uses ops structures named _timer a lot */ \ + "*_sht", /* scsi also used *_sht to some extent */ \ + "*_ops", \ + "*_probe", \ + "*_probe_one", \ + "*_console" static const char *head_sections[] = { ".head.text*", NULL }; static const char *linker_symbols[] = { "__init_begin", "_sinittext", "_einittext", NULL }; enum mismatch { - NO_MISMATCH, - TEXT_TO_INIT, - DATA_TO_INIT, - TEXT_TO_EXIT, - DATA_TO_EXIT, - XXXINIT_TO_INIT, - XXXEXIT_TO_EXIT, - INIT_TO_EXIT, - EXIT_TO_INIT, + TEXT_TO_ANY_INIT, + DATA_TO_ANY_INIT, + TEXT_TO_ANY_EXIT, + DATA_TO_ANY_EXIT, + XXXINIT_TO_SOME_INIT, + XXXEXIT_TO_SOME_EXIT, + ANY_INIT_TO_ANY_EXIT, + ANY_EXIT_TO_ANY_INIT, EXPORT_TO_INIT_EXIT, }; @@ -848,6 +847,7 @@ struct sectioncheck { const char *fromsec[20]; const char *tosec[20]; enum mismatch mismatch; + const char *symbol_white_list[20]; }; const struct sectioncheck sectioncheck[] = { @@ -857,80 +857,103 @@ const struct sectioncheck sectioncheck[] = { { .fromsec = { TEXT_SECTIONS, NULL }, .tosec = { ALL_INIT_SECTIONS, NULL }, - .mismatch = TEXT_TO_INIT, + .mismatch = TEXT_TO_ANY_INIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, { .fromsec = { DATA_SECTIONS, NULL }, - .tosec = { ALL_INIT_SECTIONS, NULL }, - .mismatch = DATA_TO_INIT, + .tosec = { ALL_XXXINIT_SECTIONS, NULL }, + .mismatch = DATA_TO_ANY_INIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, +}, +{ + .fromsec = { DATA_SECTIONS, NULL }, + .tosec = { INIT_SECTIONS, NULL }, + .mismatch = DATA_TO_ANY_INIT, + .symbol_white_list = { + "*_template", "*_timer", "*_sht", "*_ops", + "*_probe", "*_probe_one", "*_console", NULL + }, }, { .fromsec = { TEXT_SECTIONS, NULL }, .tosec = { ALL_EXIT_SECTIONS, NULL }, - .mismatch = TEXT_TO_EXIT, + .mismatch = TEXT_TO_ANY_EXIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, { .fromsec = { DATA_SECTIONS, NULL }, .tosec = { ALL_EXIT_SECTIONS, NULL }, - .mismatch = DATA_TO_EXIT, + .mismatch = DATA_TO_ANY_EXIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not reference init code/data from devinit/cpuinit/meminit code/data */ { - .fromsec = { DEV_INIT_SECTIONS, CPU_INIT_SECTIONS, MEM_INIT_SECTIONS, NULL }, + .fromsec = { ALL_XXXINIT_SECTIONS, NULL }, .tosec = { INIT_SECTIONS, NULL }, - .mismatch = XXXINIT_TO_INIT, + .mismatch = XXXINIT_TO_SOME_INIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not reference cpuinit code/data from meminit code/data */ { .fromsec = { MEM_INIT_SECTIONS, NULL }, .tosec = { CPU_INIT_SECTIONS, NULL }, - .mismatch = XXXINIT_TO_INIT, + .mismatch = XXXINIT_TO_SOME_INIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not reference meminit code/data from cpuinit code/data */ { .fromsec = { CPU_INIT_SECTIONS, NULL }, .tosec = { MEM_INIT_SECTIONS, NULL }, - .mismatch = XXXINIT_TO_INIT, + .mismatch = XXXINIT_TO_SOME_INIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not reference exit code/data from devexit/cpuexit/memexit code/data */ { - .fromsec = { DEV_EXIT_SECTIONS, CPU_EXIT_SECTIONS, MEM_EXIT_SECTIONS, NULL }, + .fromsec = { ALL_XXXEXIT_SECTIONS, NULL }, .tosec = { EXIT_SECTIONS, NULL }, - .mismatch = XXXEXIT_TO_EXIT, + .mismatch = XXXEXIT_TO_SOME_EXIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not reference cpuexit code/data from memexit code/data */ { .fromsec = { MEM_EXIT_SECTIONS, NULL }, .tosec = { CPU_EXIT_SECTIONS, NULL }, - .mismatch = XXXEXIT_TO_EXIT, + .mismatch = XXXEXIT_TO_SOME_EXIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not reference memexit code/data from cpuexit code/data */ { .fromsec = { CPU_EXIT_SECTIONS, NULL }, .tosec = { MEM_EXIT_SECTIONS, NULL }, - .mismatch = XXXEXIT_TO_EXIT, + .mismatch = XXXEXIT_TO_SOME_EXIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not use exit code/data from init code */ { .fromsec = { ALL_INIT_SECTIONS, NULL }, .tosec = { ALL_EXIT_SECTIONS, NULL }, - .mismatch = INIT_TO_EXIT, + .mismatch = ANY_INIT_TO_ANY_EXIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not use init code/data from exit code */ { .fromsec = { ALL_EXIT_SECTIONS, NULL }, .tosec = { ALL_INIT_SECTIONS, NULL }, - .mismatch = EXIT_TO_INIT, + .mismatch = ANY_EXIT_TO_ANY_INIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not export init/exit functions or data */ { .fromsec = { "__ksymtab*", NULL }, .tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL }, - .mismatch = EXPORT_TO_INIT_EXIT + .mismatch = EXPORT_TO_INIT_EXIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, } }; -static int section_mismatch(const char *fromsec, const char *tosec) +static const struct sectioncheck *section_mismatch( + const char *fromsec, const char *tosec) { int i; int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck); @@ -939,10 +962,10 @@ static int section_mismatch(const char *fromsec, const char *tosec) for (i = 0; i < elems; i++) { if (match(fromsec, check->fromsec) && match(tosec, check->tosec)) - return check->mismatch; + return check; check++; } - return NO_MISMATCH; + return NULL; } /** @@ -961,7 +984,7 @@ static int section_mismatch(const char *fromsec, const char *tosec) * Pattern 2: * Many drivers utilise a *driver container with references to * add, remove, probe functions etc. - * These functions may often be marked __init and we do not want to + * These functions may often be marked __devinit and we do not want to * warn here. * the pattern is identified by: * tosec = init or exit section @@ -982,7 +1005,8 @@ static int section_mismatch(const char *fromsec, const char *tosec) * refsymname = __init_begin, _sinittext, _einittext * **/ -static int secref_whitelist(const char *fromsec, const char *fromsym, +static int secref_whitelist(const struct sectioncheck *mismatch, + const char *fromsec, const char *fromsym, const char *tosec, const char *tosym) { /* Check for pattern 1 */ @@ -994,7 +1018,7 @@ static int secref_whitelist(const char *fromsec, const char *fromsym, /* Check for pattern 2 */ if (match(tosec, init_exit_sections) && match(fromsec, data_sections) && - match(fromsym, symbol_white_list)) + match(fromsym, mismatch->symbol_white_list)) return 0; /* Check for pattern 3 */ @@ -1155,7 +1179,8 @@ static int is_function(Elf_Sym *sym) * Try to find symbols near it so user can find it. * Check whitelist before warning - it may be a false positive. */ -static void report_sec_mismatch(const char *modname, enum mismatch mismatch, +static void report_sec_mismatch(const char *modname, + const struct sectioncheck *mismatch, const char *fromsec, unsigned long long fromaddr, const char *fromsym, @@ -1186,8 +1211,8 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch, modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec, tosym, to_p); - switch (mismatch) { - case TEXT_TO_INIT: + switch (mismatch->mismatch) { + case TEXT_TO_ANY_INIT: fprintf(stderr, "The function %s%s() references\n" "the %s %s%s%s.\n" @@ -1197,8 +1222,8 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch, to, sec2annotation(tosec), tosym, to_p, fromsym, sec2annotation(tosec), tosym); break; - case DATA_TO_INIT: { - const char **s = symbol_white_list; + case DATA_TO_ANY_INIT: { + const char *const *s = mismatch->symbol_white_list; fprintf(stderr, "The variable %s references\n" "the %s %s%s%s\n" @@ -1211,15 +1236,15 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch, fprintf(stderr, "\n"); break; } - case TEXT_TO_EXIT: + case TEXT_TO_ANY_EXIT: fprintf(stderr, "The function %s() references a %s in an exit section.\n" "Often the %s %s%s has valid usage outside the exit section\n" "and the fix is to remove the %sannotation of %s.\n", fromsym, to, to, tosym, to_p, sec2annotation(tosec), tosym); break; - case DATA_TO_EXIT: { - const char **s = symbol_white_list; + case DATA_TO_ANY_EXIT: { + const char *const *s = mismatch->symbol_white_list; fprintf(stderr, "The variable %s references\n" "the %s %s%s%s\n" @@ -1232,8 +1257,8 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch, fprintf(stderr, "\n"); break; } - case XXXINIT_TO_INIT: - case XXXEXIT_TO_EXIT: + case XXXINIT_TO_SOME_INIT: + case XXXEXIT_TO_SOME_EXIT: fprintf(stderr, "The %s %s%s%s references\n" "a %s %s%s%s.\n" @@ -1243,7 +1268,7 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch, to, sec2annotation(tosec), tosym, to_p, tosym, fromsym, tosym); break; - case INIT_TO_EXIT: + case ANY_INIT_TO_ANY_EXIT: fprintf(stderr, "The %s %s%s%s references\n" "a %s %s%s%s.\n" @@ -1256,7 +1281,7 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch, to, sec2annotation(tosec), tosym, to_p, sec2annotation(tosec), tosym, to_p); break; - case EXIT_TO_INIT: + case ANY_EXIT_TO_ANY_INIT: fprintf(stderr, "The %s %s%s%s references\n" "a %s %s%s%s.\n" @@ -1275,8 +1300,6 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch, "Fix this by removing the %sannotation of %s " "or drop the export.\n", tosym, sec2annotation(tosec), sec2annotation(tosec), tosym); - case NO_MISMATCH: - /* To get warnings on missing members */ break; } fprintf(stderr, "\n"); @@ -1286,11 +1309,11 @@ static void check_section_mismatch(const char *modname, struct elf_info *elf, Elf_Rela *r, Elf_Sym *sym, const char *fromsec) { const char *tosec; - enum mismatch mismatch; + const struct sectioncheck *mismatch; tosec = sec_name(elf, sym->st_shndx); mismatch = section_mismatch(fromsec, tosec); - if (mismatch != NO_MISMATCH) { + if (mismatch) { Elf_Sym *to; Elf_Sym *from; const char *tosym; @@ -1302,7 +1325,8 @@ static void check_section_mismatch(const char *modname, struct elf_info *elf, tosym = sym_name(elf, to); /* check whitelist - we may ignore it */ - if (secref_whitelist(fromsec, fromsym, tosec, tosym)) { + if (secref_whitelist(mismatch, + fromsec, fromsym, tosec, tosym)) { report_sec_mismatch(modname, mismatch, fromsec, r->r_offset, fromsym, is_function(from), tosec, tosym, diff --git a/scripts/namespace.pl b/scripts/namespace.pl index c6e88c6..361d0f7 100755 --- a/scripts/namespace.pl +++ b/scripts/namespace.pl @@ -175,12 +175,11 @@ sub do_nm } if (! -e "$source.c" && ! -e "$source.S") { # No obvious source, exclude the object if it is conglomerate - if (! open(OBJDUMPDATA, "$objdump $basename|")) { - printf STDERR "$objdump $fullname failed $!\n"; - return; - } + open(my $objdumpdata, "$objdump $basename|") + or die "$objdump $fullname failed $!\n"; + my $comment; - while (<OBJDUMPDATA>) { + while (<$objdumpdata>) { chomp(); if (/^In archive/) { # Archives are always conglomerate @@ -190,18 +189,18 @@ sub do_nm next if (! /^[ 0-9a-f]{5,} /); $comment .= substr($_, 43); } - close(OBJDUMPDATA); + close($objdumpdata); + if (!defined($comment) || $comment !~ /GCC\:.*GCC\:/m) { printf STDERR "No source file found for $fullname\n"; } return; } - if (! open(NMDATA, "$nm $basename|")) { - printf STDERR "$nm $fullname failed $!\n"; - return; - } + open (my $nmdata, "$nm $basename|") + or die "$nm $fullname failed $!\n"; + my @nmdata; - while (<NMDATA>) { + while (<$nmdata>) { chop; ($type, $name) = (split(/ +/, $_, 3))[1..2]; # Expected types @@ -268,7 +267,8 @@ sub do_nm } } } - close(NMDATA); + close($nmdata); + if ($#nmdata < 0) { if ( $fullname ne "lib/brlock.o" @@ -316,8 +316,7 @@ sub drop_def sub list_multiply_defined { - my ($name, $module); - foreach $name (keys(%def)) { + foreach my $name (keys(%def)) { if ($#{$def{$name}} > 0) { # Special case for cond_syscall if ($#{$def{$name}} == 1 && $name =~ /^sys_/ && @@ -333,8 +332,9 @@ sub list_multiply_defined &drop_def("arch/x86/kernel/vsyscall-sysenter_32.o", $name); next; } + printf "$name is multiply defined in :-\n"; - foreach $module (@{$def{$name}}) { + foreach my $module (@{$def{$name}}) { printf "\t$module\n"; } } @@ -343,12 +343,13 @@ sub list_multiply_defined sub resolve_external_references { - my ($object, $type, $name, $i, $j, $kstrtab, $ksymtab, $export); + my ($kstrtab, $ksymtab, $export); + printf "\n"; - foreach $object (keys(%nmdata)) { + foreach my $object (keys(%nmdata)) { my $nmdata = $nmdata{$object}; - for ($i = 0; $i <= $#{$nmdata}; ++$i) { - ($type, $name) = split(' ', $nmdata->[$i], 2); + for (my $i = 0; $i <= $#{$nmdata}; ++$i) { + my ($type, $name) = split(' ', $nmdata->[$i], 2); if ($type eq "U" || $type eq "w") { if (exists($def{$name}) || exists($ksymtab{$name})) { # add the owning object to the nmdata @@ -357,7 +358,7 @@ sub resolve_external_references $kstrtab = "R __kstrtab_$name"; $ksymtab = "R __ksymtab_$name"; $export = 0; - for ($j = 0; $j <= $#{$nmdata}; ++$j) { + for (my $j = 0; $j <= $#{$nmdata}; ++$j) { if ($nmdata->[$j] eq $kstrtab || $nmdata->[$j] eq $ksymtab) { $export = 1; @@ -424,11 +425,11 @@ sub resolve_external_references sub list_extra_externals { my %noref = (); - my ($name, @module, $module, $export); - foreach $name (keys(%def)) { + + foreach my $name (keys(%def)) { if (! exists($ref{$name})) { - @module = @{$def{$name}}; - foreach $module (@module) { + my @module = @{$def{$name}}; + foreach my $module (@module) { if (! exists($noref{$module})) { $noref{$module} = []; } @@ -438,16 +439,16 @@ sub list_extra_externals } if (%noref) { printf "\nExternally defined symbols with no external references\n"; - foreach $module (sort(keys(%noref))) { + foreach my $module (sort(keys(%noref))) { printf " $module\n"; foreach (sort(@{$noref{$module}})) { - if (exists($export{$_})) { - $export = " (export only)"; - } - else { - $export = ""; - } - printf " $_$export\n"; + my $export; + if (exists($export{$_})) { + $export = " (export only)"; + } else { + $export = ""; + } + printf " $_$export\n"; } } } diff --git a/scripts/package/builddeb b/scripts/package/builddeb index 8b357b0..07f2fbd 100644 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -18,6 +18,8 @@ create_package() { cp debian/copyright "$pdir/usr/share/doc/$pname/" cp debian/changelog "$pdir/usr/share/doc/$pname/changelog.Debian" gzip -9 "$pdir/usr/share/doc/$pname/changelog.Debian" + sh -c "cd '$pdir'; find . -type f ! -path './DEBIAN/*' -printf '%P\0' \ + | xargs -r0 md5sum > DEBIAN/md5sums" # Fix ownership and permissions chown -R root:root "$pdir" diff --git a/scripts/package/mkspec b/scripts/package/mkspec index fa27f3d..15440f5 100755 --- a/scripts/package/mkspec +++ b/scripts/package/mkspec @@ -39,7 +39,7 @@ if ! $PREBUILT; then echo "Source: kernel-$__KERNELRELEASE.tar.gz" fi -echo "BuildRoot: /var/tmp/%{name}-%{PACKAGE_VERSION}-root" +echo "BuildRoot: %{_tmppath}/%{name}-%{PACKAGE_VERSION}-root" echo "Provides: $PROVIDES" echo "%define __spec_install_post /usr/lib/rpm/brp-compress || :" echo "%define debug_package %{nil}" diff --git a/scripts/profile2linkerlist.pl b/scripts/profile2linkerlist.pl index cb4260e..6943fa7 100644 --- a/scripts/profile2linkerlist.pl +++ b/scripts/profile2linkerlist.pl @@ -7,15 +7,13 @@ # usage: # readprofile | sort -rn | perl profile2linkerlist.pl > functionlist # +use strict; while (<>) { my $line = $_; $_ =~ /\W*[0-9]+\W*([a-zA-Z\_0-9]+)\W*[0-9]+/; - if ( ($line =~ /unknown/) || ($line =~ /total/)) { - - } else { - print "*(.text.$1)\n"; - } + print "*(.text.$1)\n" + unless ($line =~ /unknown/) || ($line =~ /total/); } diff --git a/scripts/rt-tester/rt-tester.py b/scripts/rt-tester/rt-tester.py index 4c79660..44423b4 100644 --- a/scripts/rt-tester/rt-tester.py +++ b/scripts/rt-tester/rt-tester.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/python # # rt-mutex tester # diff --git a/scripts/show_delta b/scripts/show_delta index 48a706a..17df305 100755 --- a/scripts/show_delta +++ b/scripts/show_delta @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/python # # show_deltas: Read list of printk messages instrumented with # time data, and format with time deltas. diff --git a/scripts/tags.sh b/scripts/tags.sh index 1a0c44d..8509bb5 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -5,7 +5,7 @@ # mode may be any of: tags, TAGS, cscope # # Uses the following environment variables: -# ARCH, SUBARCH, srctree, src, obj +# ARCH, SUBARCH, SRCARCH, srctree, src, obj if [ "$KBUILD_VERBOSE" = "1" ]; then set -x @@ -17,28 +17,48 @@ ignore="( -name SCCS -o -name BitKeeper -o -name .svn -o \ -name .git ) \ -prune -o" -# Do not use full path is we do not use O=.. builds +# Do not use full path if we do not use O=.. builds +# Use make O=. {tags|cscope} +# to force full paths for a non-O= build if [ "${KBUILD_SRC}" = "" ]; then tree= else tree=${srctree}/ fi +# Find all available archs +find_all_archs() +{ + ALLSOURCE_ARCHS="" + for arch in `ls ${tree}arch`; do + ALLSOURCE_ARCHS="${ALLSOURCE_ARCHS} "${arch##\/} + done +} + # Detect if ALLSOURCE_ARCHS is set. If not, we assume SRCARCH if [ "${ALLSOURCE_ARCHS}" = "" ]; then ALLSOURCE_ARCHS=${SRCARCH} +elif [ "${ALLSOURCE_ARCHS}" = "all" ]; then + find_all_archs fi # find sources in arch/$ARCH find_arch_sources() { - find ${tree}arch/$1 $ignore -name "$2" -print; + for i in $archincludedir; do + prune="$prune -wholename $i -prune -o" + done + find ${tree}arch/$1 $ignore $prune -name "$2" -print; } # find sources in arch/$1/include find_arch_include_sources() { - find ${tree}arch/$1/include $ignore -name "$2" -print; + include=$(find ${tree}arch/$1/ -name include -type d); + if [ -n "$include" ]; then + archincludedir="$archincludedir $include" + find $include $ignore -name "$2" -print; + fi } # find sources in include/ @@ -63,14 +83,15 @@ find_sources() all_sources() { - for arch in $ALLSOURCE_ARCHS - do - find_sources $arch '*.[chS]' - done + find_arch_include_sources ${SRCARCH} '*.[chS]' if [ ! -z "$archinclude" ]; then find_arch_include_sources $archinclude '*.[chS]' fi find_include_sources '*.[chS]' + for arch in $ALLSOURCE_ARCHS + do + find_sources $arch '*.[chS]' + done find_other_sources '*.[chS]' } @@ -89,13 +110,7 @@ all_defconfigs() docscope() { - # always use absolute paths for cscope, as recommended by cscope - # upstream - case "$tree" in - /*) ;; - *) tree=$PWD/$tree ;; - esac - (cd /; echo \-k; echo \-q; all_sources) > cscope.files + (echo \-k; echo \-q; all_sources) > cscope.files cscope -b -f cscope.out } |