aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/kbuild/kbuild.txt5
-rw-r--r--Makefile7
-rw-r--r--lib/Kconfig.debug4
-rw-r--r--scripts/Makefile5
-rw-r--r--scripts/Makefile.build35
-rw-r--r--scripts/mod/modpost.c23
-rw-r--r--scripts/unifdef.c247
7 files changed, 249 insertions, 77 deletions
diff --git a/Documentation/kbuild/kbuild.txt b/Documentation/kbuild/kbuild.txt
index 4a990317b84a..376538c984ce 100644
--- a/Documentation/kbuild/kbuild.txt
+++ b/Documentation/kbuild/kbuild.txt
@@ -196,3 +196,8 @@ to be included in the databases, separated by blank space. E.g.:
196To get all available archs you can also specify all. E.g.: 196To get all available archs you can also specify all. E.g.:
197 197
198 $ make ALLSOURCE_ARCHS=all tags 198 $ make ALLSOURCE_ARCHS=all tags
199
200KBUILD_ENABLE_EXTRA_GCC_CHECKS
201--------------------------------------------------
202If enabled over the make command line with "W=1", it turns on additional
203gcc -W... options for more extensive build-time checking.
diff --git a/Makefile b/Makefile
index abb49bf8596e..0bf29dcc66fc 100644
--- a/Makefile
+++ b/Makefile
@@ -102,6 +102,10 @@ ifeq ("$(origin O)", "command line")
102 KBUILD_OUTPUT := $(O) 102 KBUILD_OUTPUT := $(O)
103endif 103endif
104 104
105ifeq ("$(origin W)", "command line")
106 export KBUILD_ENABLE_EXTRA_GCC_CHECKS := 1
107endif
108
105# That's our default target when none is given on the command line 109# That's our default target when none is given on the command line
106PHONY := _all 110PHONY := _all
107_all: 111_all:
@@ -1018,7 +1022,7 @@ hdr-dst = $(if $(KBUILD_HEADERS), dst=include/asm-$(hdr-arch), dst=include/asm)
1018 1022
1019PHONY += __headers 1023PHONY += __headers
1020__headers: include/linux/version.h scripts_basic FORCE 1024__headers: include/linux/version.h scripts_basic FORCE
1021 $(Q)$(MAKE) $(build)=scripts scripts/unifdef 1025 $(Q)$(MAKE) $(build)=scripts build_unifdef
1022 1026
1023PHONY += headers_install_all 1027PHONY += headers_install_all
1024headers_install_all: 1028headers_install_all:
@@ -1262,6 +1266,7 @@ help:
1262 @echo ' make O=dir [targets] Locate all output files in "dir", including .config' 1266 @echo ' make O=dir [targets] Locate all output files in "dir", including .config'
1263 @echo ' make C=1 [targets] Check all c source with $$CHECK (sparse by default)' 1267 @echo ' make C=1 [targets] Check all c source with $$CHECK (sparse by default)'
1264 @echo ' make C=2 [targets] Force check of all c source with $$CHECK' 1268 @echo ' make C=2 [targets] Force check of all c source with $$CHECK'
1269 @echo ' make W=1 [targets] Enable extra gcc checks'
1265 @echo '' 1270 @echo ''
1266 @echo 'Execute "make" or "make all" to build all targets marked with [*] ' 1271 @echo 'Execute "make" or "make all" to build all targets marked with [*] '
1267 @echo 'For further info see the ./README file' 1272 @echo 'For further info see the ./README file'
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 2d05adb98401..8b6a4f13946f 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -102,11 +102,7 @@ config HEADERS_CHECK
102 102
103config DEBUG_SECTION_MISMATCH 103config DEBUG_SECTION_MISMATCH
104 bool "Enable full Section mismatch analysis" 104 bool "Enable full Section mismatch analysis"
105 depends on UNDEFINED || (BLACKFIN)
106 default y 105 default y
107 # This option is on purpose disabled for now.
108 # It will be enabled when we are down to a reasonable number
109 # of section mismatch warnings (< 10 for an allyesconfig build)
110 help 106 help
111 The section mismatch analysis checks if there are illegal 107 The section mismatch analysis checks if there are illegal
112 references from one section to another section. 108 references from one section to another section.
diff --git a/scripts/Makefile b/scripts/Makefile
index 2e088109fbd5..fcea26168bca 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -18,6 +18,11 @@ always := $(hostprogs-y) $(hostprogs-m)
18# The following hostprogs-y programs are only build on demand 18# The following hostprogs-y programs are only build on demand
19hostprogs-y += unifdef 19hostprogs-y += unifdef
20 20
21# This target is used internally to avoid "is up to date" messages
22PHONY += build_unifdef
23build_unifdef: scripts/unifdef FORCE
24 @:
25
21subdir-$(CONFIG_MODVERSIONS) += genksyms 26subdir-$(CONFIG_MODVERSIONS) += genksyms
22subdir-y += mod 27subdir-y += mod
23subdir-$(CONFIG_SECURITY_SELINUX) += selinux 28subdir-$(CONFIG_SECURITY_SELINUX) += selinux
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 4eb99ab34053..d5f925abe4d2 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -49,6 +49,40 @@ ifeq ($(KBUILD_NOPEDANTIC),)
49 $(error CFLAGS was changed in "$(kbuild-file)". Fix it to use EXTRA_CFLAGS) 49 $(error CFLAGS was changed in "$(kbuild-file)". Fix it to use EXTRA_CFLAGS)
50 endif 50 endif
51endif 51endif
52
53#
54# make W=1 settings
55#
56# $(call cc-option... ) handles gcc -W.. options which
57# are not supported by all versions of the compiler
58ifdef KBUILD_ENABLE_EXTRA_GCC_CHECKS
59KBUILD_EXTRA_WARNINGS := -Wextra
60KBUILD_EXTRA_WARNINGS += -Wunused -Wno-unused-parameter
61KBUILD_EXTRA_WARNINGS += -Waggregate-return
62KBUILD_EXTRA_WARNINGS += -Wbad-function-cast
63KBUILD_EXTRA_WARNINGS += -Wcast-qual
64KBUILD_EXTRA_WARNINGS += -Wcast-align
65KBUILD_EXTRA_WARNINGS += -Wconversion
66KBUILD_EXTRA_WARNINGS += -Wdisabled-optimization
67KBUILD_EXTRA_WARNINGS += -Wlogical-op
68KBUILD_EXTRA_WARNINGS += -Wmissing-declarations
69KBUILD_EXTRA_WARNINGS += -Wmissing-format-attribute
70KBUILD_EXTRA_WARNINGS += $(call cc-option, -Wmissing-include-dirs,)
71KBUILD_EXTRA_WARNINGS += -Wmissing-prototypes
72KBUILD_EXTRA_WARNINGS += -Wnested-externs
73KBUILD_EXTRA_WARNINGS += -Wold-style-definition
74KBUILD_EXTRA_WARNINGS += $(call cc-option, -Woverlength-strings,)
75KBUILD_EXTRA_WARNINGS += -Wpacked
76KBUILD_EXTRA_WARNINGS += -Wpacked-bitfield-compat
77KBUILD_EXTRA_WARNINGS += -Wpadded
78KBUILD_EXTRA_WARNINGS += -Wpointer-arith
79KBUILD_EXTRA_WARNINGS += -Wredundant-decls
80KBUILD_EXTRA_WARNINGS += -Wshadow
81KBUILD_EXTRA_WARNINGS += -Wswitch-default
82KBUILD_EXTRA_WARNINGS += $(call cc-option, -Wvla,)
83KBUILD_CFLAGS += $(KBUILD_EXTRA_WARNINGS)
84endif
85
52include scripts/Makefile.lib 86include scripts/Makefile.lib
53 87
54ifdef host-progs 88ifdef host-progs
@@ -403,7 +437,6 @@ ifneq ($(cmd_files),)
403 include $(cmd_files) 437 include $(cmd_files)
404endif 438endif
405 439
406
407# Declare the contents of the .PHONY variable as phony. We keep that 440# Declare the contents of the .PHONY variable as phony. We keep that
408# information in a variable se we can use it in if_changed and friends. 441# information in a variable se we can use it in if_changed and friends.
409 442
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index e8fba959fffb..cd104afcc5f2 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -1248,6 +1248,19 @@ static int is_function(Elf_Sym *sym)
1248 return -1; 1248 return -1;
1249} 1249}
1250 1250
1251static void print_section_list(const char * const list[20])
1252{
1253 const char *const *s = list;
1254
1255 while (*s) {
1256 fprintf(stderr, "%s", *s);
1257 s++;
1258 if (*s)
1259 fprintf(stderr, ", ");
1260 }
1261 fprintf(stderr, "\n");
1262}
1263
1251/* 1264/*
1252 * Print a warning about a section mismatch. 1265 * Print a warning about a section mismatch.
1253 * Try to find symbols near it so user can find it. 1266 * Try to find symbols near it so user can find it.
@@ -1304,7 +1317,6 @@ static void report_sec_mismatch(const char *modname,
1304 break; 1317 break;
1305 case DATA_TO_ANY_INIT: { 1318 case DATA_TO_ANY_INIT: {
1306 prl_to = sec2annotation(tosec); 1319 prl_to = sec2annotation(tosec);
1307 const char *const *s = mismatch->symbol_white_list;
1308 fprintf(stderr, 1320 fprintf(stderr,
1309 "The variable %s references\n" 1321 "The variable %s references\n"
1310 "the %s %s%s%s\n" 1322 "the %s %s%s%s\n"
@@ -1312,9 +1324,7 @@ static void report_sec_mismatch(const char *modname,
1312 "variable with __init* or __refdata (see linux/init.h) " 1324 "variable with __init* or __refdata (see linux/init.h) "
1313 "or name the variable:\n", 1325 "or name the variable:\n",
1314 fromsym, to, prl_to, tosym, to_p); 1326 fromsym, to, prl_to, tosym, to_p);
1315 while (*s) 1327 print_section_list(mismatch->symbol_white_list);
1316 fprintf(stderr, "%s, ", *s++);
1317 fprintf(stderr, "\n");
1318 free(prl_to); 1328 free(prl_to);
1319 break; 1329 break;
1320 } 1330 }
@@ -1329,7 +1339,6 @@ static void report_sec_mismatch(const char *modname,
1329 break; 1339 break;
1330 case DATA_TO_ANY_EXIT: { 1340 case DATA_TO_ANY_EXIT: {
1331 prl_to = sec2annotation(tosec); 1341 prl_to = sec2annotation(tosec);
1332 const char *const *s = mismatch->symbol_white_list;
1333 fprintf(stderr, 1342 fprintf(stderr,
1334 "The variable %s references\n" 1343 "The variable %s references\n"
1335 "the %s %s%s%s\n" 1344 "the %s %s%s%s\n"
@@ -1337,9 +1346,7 @@ static void report_sec_mismatch(const char *modname,
1337 "variable with __exit* (see linux/init.h) or " 1346 "variable with __exit* (see linux/init.h) or "
1338 "name the variable:\n", 1347 "name the variable:\n",
1339 fromsym, to, prl_to, tosym, to_p); 1348 fromsym, to, prl_to, tosym, to_p);
1340 while (*s) 1349 print_section_list(mismatch->symbol_white_list);
1341 fprintf(stderr, "%s, ", *s++);
1342 fprintf(stderr, "\n");
1343 free(prl_to); 1350 free(prl_to);
1344 break; 1351 break;
1345 } 1352 }
diff --git a/scripts/unifdef.c b/scripts/unifdef.c
index 44d39785e50d..7493c0ee51cc 100644
--- a/scripts/unifdef.c
+++ b/scripts/unifdef.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2002 - 2009 Tony Finch <dot@dotat.at> 2 * Copyright (c) 2002 - 2011 Tony Finch <dot@dotat.at>
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
@@ -24,23 +24,14 @@
24 */ 24 */
25 25
26/* 26/*
27 * unifdef - remove ifdef'ed lines
28 *
27 * This code was derived from software contributed to Berkeley by Dave Yost. 29 * This code was derived from software contributed to Berkeley by Dave Yost.
28 * It was rewritten to support ANSI C by Tony Finch. The original version 30 * It was rewritten to support ANSI C by Tony Finch. The original version
29 * of unifdef carried the 4-clause BSD copyright licence. None of its code 31 * of unifdef carried the 4-clause BSD copyright licence. None of its code
30 * remains in this version (though some of the names remain) so it now 32 * remains in this version (though some of the names remain) so it now
31 * carries a more liberal licence. 33 * carries a more liberal licence.
32 * 34 *
33 * The latest version is available from http://dotat.at/prog/unifdef
34 */
35
36static const char * const copyright[] = {
37 "@(#) Copyright (c) 2002 - 2009 Tony Finch <dot@dotat.at>\n",
38 "$dotat: unifdef/unifdef.c,v 1.190 2009/11/27 17:21:26 fanf2 Exp $",
39};
40
41/*
42 * unifdef - remove ifdef'ed lines
43 *
44 * Wishlist: 35 * Wishlist:
45 * provide an option which will append the name of the 36 * provide an option which will append the name of the
46 * appropriate symbol after #else's and #endif's 37 * appropriate symbol after #else's and #endif's
@@ -48,12 +39,16 @@ static const char * const copyright[] = {
48 * #else's and #endif's to see that they match their 39 * #else's and #endif's to see that they match their
49 * corresponding #ifdef or #ifndef 40 * corresponding #ifdef or #ifndef
50 * 41 *
51 * The first two items above require better buffer handling, which would 42 * These require better buffer handling, which would also make
52 * also make it possible to handle all "dodgy" directives correctly. 43 * it possible to handle all "dodgy" directives correctly.
53 */ 44 */
54 45
46#include <sys/types.h>
47#include <sys/stat.h>
48
55#include <ctype.h> 49#include <ctype.h>
56#include <err.h> 50#include <err.h>
51#include <errno.h>
57#include <stdarg.h> 52#include <stdarg.h>
58#include <stdbool.h> 53#include <stdbool.h>
59#include <stdio.h> 54#include <stdio.h>
@@ -61,6 +56,12 @@ static const char * const copyright[] = {
61#include <string.h> 56#include <string.h>
62#include <unistd.h> 57#include <unistd.h>
63 58
59const char copyright[] =
60 "@(#) $Version: unifdef-2.5 $\n"
61 "@(#) $Author: Tony Finch (dot@dotat.at) $\n"
62 "@(#) $URL: http://dotat.at/prog/unifdef $\n"
63;
64
64/* types of input lines: */ 65/* types of input lines: */
65typedef enum { 66typedef enum {
66 LT_TRUEI, /* a true #if with ignore flag */ 67 LT_TRUEI, /* a true #if with ignore flag */
@@ -153,6 +154,11 @@ static char const * const linestate_name[] = {
153#define EDITSLOP 10 154#define EDITSLOP 10
154 155
155/* 156/*
157 * For temporary filenames
158 */
159#define TEMPLATE "unifdef.XXXXXX"
160
161/*
156 * Globals. 162 * Globals.
157 */ 163 */
158 164
@@ -165,6 +171,7 @@ static bool strictlogic; /* -K: keep ambiguous #ifs */
165static bool killconsts; /* -k: eval constant #ifs */ 171static bool killconsts; /* -k: eval constant #ifs */
166static bool lnnum; /* -n: add #line directives */ 172static bool lnnum; /* -n: add #line directives */
167static bool symlist; /* -s: output symbol list */ 173static bool symlist; /* -s: output symbol list */
174static bool symdepth; /* -S: output symbol depth */
168static bool text; /* -t: this is a text file */ 175static bool text; /* -t: this is a text file */
169 176
170static const char *symname[MAXSYMS]; /* symbol name */ 177static const char *symname[MAXSYMS]; /* symbol name */
@@ -175,10 +182,18 @@ static int nsyms; /* number of symbols */
175static FILE *input; /* input file pointer */ 182static FILE *input; /* input file pointer */
176static const char *filename; /* input file name */ 183static const char *filename; /* input file name */
177static int linenum; /* current line number */ 184static int linenum; /* current line number */
185static FILE *output; /* output file pointer */
186static const char *ofilename; /* output file name */
187static bool overwriting; /* output overwrites input */
188static char tempname[FILENAME_MAX]; /* used when overwriting */
178 189
179static char tline[MAXLINE+EDITSLOP];/* input buffer plus space */ 190static char tline[MAXLINE+EDITSLOP];/* input buffer plus space */
180static char *keyword; /* used for editing #elif's */ 191static char *keyword; /* used for editing #elif's */
181 192
193static const char *newline; /* input file format */
194static const char newline_unix[] = "\n";
195static const char newline_crlf[] = "\r\n";
196
182static Comment_state incomment; /* comment parser state */ 197static Comment_state incomment; /* comment parser state */
183static Line_state linestate; /* #if line parser state */ 198static Line_state linestate; /* #if line parser state */
184static Ifstate ifstate[MAXDEPTH]; /* #if processor state */ 199static Ifstate ifstate[MAXDEPTH]; /* #if processor state */
@@ -189,10 +204,13 @@ static int delcount; /* count of deleted lines */
189static unsigned blankcount; /* count of blank lines */ 204static unsigned blankcount; /* count of blank lines */
190static unsigned blankmax; /* maximum recent blankcount */ 205static unsigned blankmax; /* maximum recent blankcount */
191static bool constexpr; /* constant #if expression */ 206static bool constexpr; /* constant #if expression */
207static bool zerosyms = true; /* to format symdepth output */
208static bool firstsym; /* ditto */
192 209
193static int exitstat; /* program exit status */ 210static int exitstat; /* program exit status */
194 211
195static void addsym(bool, bool, char *); 212static void addsym(bool, bool, char *);
213static void closeout(void);
196static void debug(const char *, ...); 214static void debug(const char *, ...);
197static void done(void); 215static void done(void);
198static void error(const char *); 216static void error(const char *);
@@ -212,6 +230,7 @@ static void state(Ifstate);
212static int strlcmp(const char *, const char *, size_t); 230static int strlcmp(const char *, const char *, size_t);
213static void unnest(void); 231static void unnest(void);
214static void usage(void); 232static void usage(void);
233static void version(void);
215 234
216#define endsym(c) (!isalnum((unsigned char)c) && c != '_') 235#define endsym(c) (!isalnum((unsigned char)c) && c != '_')
217 236
@@ -223,7 +242,7 @@ main(int argc, char *argv[])
223{ 242{
224 int opt; 243 int opt;
225 244
226 while ((opt = getopt(argc, argv, "i:D:U:I:BbcdeKklnst")) != -1) 245 while ((opt = getopt(argc, argv, "i:D:U:I:o:bBcdeKklnsStV")) != -1)
227 switch (opt) { 246 switch (opt) {
228 case 'i': /* treat stuff controlled by these symbols as text */ 247 case 'i': /* treat stuff controlled by these symbols as text */
229 /* 248 /*
@@ -245,16 +264,15 @@ main(int argc, char *argv[])
245 case 'U': /* undef a symbol */ 264 case 'U': /* undef a symbol */
246 addsym(false, false, optarg); 265 addsym(false, false, optarg);
247 break; 266 break;
248 case 'I': 267 case 'I': /* no-op for compatibility with cpp */
249 /* no-op for compatibility with cpp */
250 break;
251 case 'B': /* compress blank lines around removed section */
252 compblank = true;
253 break; 268 break;
254 case 'b': /* blank deleted lines instead of omitting them */ 269 case 'b': /* blank deleted lines instead of omitting them */
255 case 'l': /* backwards compatibility */ 270 case 'l': /* backwards compatibility */
256 lnblank = true; 271 lnblank = true;
257 break; 272 break;
273 case 'B': /* compress blank lines around removed section */
274 compblank = true;
275 break;
258 case 'c': /* treat -D as -U and vice versa */ 276 case 'c': /* treat -D as -U and vice versa */
259 complement = true; 277 complement = true;
260 break; 278 break;
@@ -273,12 +291,20 @@ main(int argc, char *argv[])
273 case 'n': /* add #line directive after deleted lines */ 291 case 'n': /* add #line directive after deleted lines */
274 lnnum = true; 292 lnnum = true;
275 break; 293 break;
294 case 'o': /* output to a file */
295 ofilename = optarg;
296 break;
276 case 's': /* only output list of symbols that control #ifs */ 297 case 's': /* only output list of symbols that control #ifs */
277 symlist = true; 298 symlist = true;
278 break; 299 break;
300 case 'S': /* list symbols with their nesting depth */
301 symlist = symdepth = true;
302 break;
279 case 't': /* don't parse C comments */ 303 case 't': /* don't parse C comments */
280 text = true; 304 text = true;
281 break; 305 break;
306 case 'V': /* print version */
307 version();
282 default: 308 default:
283 usage(); 309 usage();
284 } 310 }
@@ -290,21 +316,68 @@ main(int argc, char *argv[])
290 errx(2, "can only do one file"); 316 errx(2, "can only do one file");
291 } else if (argc == 1 && strcmp(*argv, "-") != 0) { 317 } else if (argc == 1 && strcmp(*argv, "-") != 0) {
292 filename = *argv; 318 filename = *argv;
293 input = fopen(filename, "r"); 319 input = fopen(filename, "rb");
294 if (input == NULL) 320 if (input == NULL)
295 err(2, "can't open %s", filename); 321 err(2, "can't open %s", filename);
296 } else { 322 } else {
297 filename = "[stdin]"; 323 filename = "[stdin]";
298 input = stdin; 324 input = stdin;
299 } 325 }
326 if (ofilename == NULL) {
327 ofilename = "[stdout]";
328 output = stdout;
329 } else {
330 struct stat ist, ost;
331 if (stat(ofilename, &ost) == 0 &&
332 fstat(fileno(input), &ist) == 0)
333 overwriting = (ist.st_dev == ost.st_dev
334 && ist.st_ino == ost.st_ino);
335 if (overwriting) {
336 const char *dirsep;
337 int ofd;
338
339 dirsep = strrchr(ofilename, '/');
340 if (dirsep != NULL)
341 snprintf(tempname, sizeof(tempname),
342 "%.*s/" TEMPLATE,
343 (int)(dirsep - ofilename), ofilename);
344 else
345 snprintf(tempname, sizeof(tempname),
346 TEMPLATE);
347 ofd = mkstemp(tempname);
348 if (ofd != -1)
349 output = fdopen(ofd, "wb+");
350 if (output == NULL)
351 err(2, "can't create temporary file");
352 fchmod(ofd, ist.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO));
353 } else {
354 output = fopen(ofilename, "wb");
355 if (output == NULL)
356 err(2, "can't open %s", ofilename);
357 }
358 }
300 process(); 359 process();
301 abort(); /* bug */ 360 abort(); /* bug */
302} 361}
303 362
304static void 363static void
364version(void)
365{
366 const char *c = copyright;
367 for (;;) {
368 while (*++c != '$')
369 if (*c == '\0')
370 exit(0);
371 while (*++c != '$')
372 putc(*c, stderr);
373 putc('\n', stderr);
374 }
375}
376
377static void
305usage(void) 378usage(void)
306{ 379{
307 fprintf(stderr, "usage: unifdef [-BbcdeKknst] [-Ipath]" 380 fprintf(stderr, "usage: unifdef [-bBcdeKknsStV] [-Ipath]"
308 " [-Dsym[=val]] [-Usym] [-iDsym[=val]] [-iUsym] ... [file]\n"); 381 " [-Dsym[=val]] [-Usym] [-iDsym[=val]] [-iUsym] ... [file]\n");
309 exit(2); 382 exit(2);
310} 383}
@@ -322,7 +395,8 @@ usage(void)
322 * When we have processed a group that starts off with a known-false 395 * When we have processed a group that starts off with a known-false
323 * #if/#elif sequence (which has therefore been deleted) followed by a 396 * #if/#elif sequence (which has therefore been deleted) followed by a
324 * #elif that we don't understand and therefore must keep, we edit the 397 * #elif that we don't understand and therefore must keep, we edit the
325 * latter into a #if to keep the nesting correct. 398 * latter into a #if to keep the nesting correct. We use strncpy() to
399 * overwrite the 4 byte token "elif" with "if " without a '\0' byte.
326 * 400 *
327 * When we find a true #elif in a group, the following block will 401 * When we find a true #elif in a group, the following block will
328 * always be kept and the rest of the sequence after the next #elif or 402 * always be kept and the rest of the sequence after the next #elif or
@@ -375,11 +449,11 @@ static void Oelif (void) { if (!iocccok) Eioccc(); Pelif(); }
375static void Idrop (void) { Fdrop(); ignoreon(); } 449static void Idrop (void) { Fdrop(); ignoreon(); }
376static void Itrue (void) { Ftrue(); ignoreon(); } 450static void Itrue (void) { Ftrue(); ignoreon(); }
377static void Ifalse(void) { Ffalse(); ignoreon(); } 451static void Ifalse(void) { Ffalse(); ignoreon(); }
378/* edit this line */ 452/* modify this line */
379static void Mpass (void) { strncpy(keyword, "if ", 4); Pelif(); } 453static void Mpass (void) { strncpy(keyword, "if ", 4); Pelif(); }
380static void Mtrue (void) { keywordedit("else\n"); state(IS_TRUE_MIDDLE); } 454static void Mtrue (void) { keywordedit("else"); state(IS_TRUE_MIDDLE); }
381static void Melif (void) { keywordedit("endif\n"); state(IS_FALSE_TRAILER); } 455static void Melif (void) { keywordedit("endif"); state(IS_FALSE_TRAILER); }
382static void Melse (void) { keywordedit("endif\n"); state(IS_FALSE_ELSE); } 456static void Melse (void) { keywordedit("endif"); state(IS_FALSE_ELSE); }
383 457
384static state_fn * const trans_table[IS_COUNT][LT_COUNT] = { 458static state_fn * const trans_table[IS_COUNT][LT_COUNT] = {
385/* IS_OUTSIDE */ 459/* IS_OUTSIDE */
@@ -431,13 +505,6 @@ static state_fn * const trans_table[IS_COUNT][LT_COUNT] = {
431 * State machine utility functions 505 * State machine utility functions
432 */ 506 */
433static void 507static void
434done(void)
435{
436 if (incomment)
437 error("EOF in comment");
438 exit(exitstat);
439}
440static void
441ignoreoff(void) 508ignoreoff(void)
442{ 509{
443 if (depth == 0) 510 if (depth == 0)
@@ -452,14 +519,8 @@ ignoreon(void)
452static void 519static void
453keywordedit(const char *replacement) 520keywordedit(const char *replacement)
454{ 521{
455 size_t size = tline + sizeof(tline) - keyword; 522 snprintf(keyword, tline + sizeof(tline) - keyword,
456 char *dst = keyword; 523 "%s%s", replacement, newline);
457 const char *src = replacement;
458 if (size != 0) {
459 while ((--size != 0) && (*src != '\0'))
460 *dst++ = *src++;
461 *dst = '\0';
462 }
463 print(); 524 print();
464} 525}
465static void 526static void
@@ -494,24 +555,26 @@ flushline(bool keep)
494 if (symlist) 555 if (symlist)
495 return; 556 return;
496 if (keep ^ complement) { 557 if (keep ^ complement) {
497 bool blankline = tline[strspn(tline, " \t\n")] == '\0'; 558 bool blankline = tline[strspn(tline, " \t\r\n")] == '\0';
498 if (blankline && compblank && blankcount != blankmax) { 559 if (blankline && compblank && blankcount != blankmax) {
499 delcount += 1; 560 delcount += 1;
500 blankcount += 1; 561 blankcount += 1;
501 } else { 562 } else {
502 if (lnnum && delcount > 0) 563 if (lnnum && delcount > 0)
503 printf("#line %d\n", linenum); 564 printf("#line %d%s", linenum, newline);
504 fputs(tline, stdout); 565 fputs(tline, output);
505 delcount = 0; 566 delcount = 0;
506 blankmax = blankcount = blankline ? blankcount + 1 : 0; 567 blankmax = blankcount = blankline ? blankcount + 1 : 0;
507 } 568 }
508 } else { 569 } else {
509 if (lnblank) 570 if (lnblank)
510 putc('\n', stdout); 571 fputs(newline, output);
511 exitstat = 1; 572 exitstat = 1;
512 delcount += 1; 573 delcount += 1;
513 blankcount = 0; 574 blankcount = 0;
514 } 575 }
576 if (debugging)
577 fflush(output);
515} 578}
516 579
517/* 580/*
@@ -520,22 +583,55 @@ flushline(bool keep)
520static void 583static void
521process(void) 584process(void)
522{ 585{
523 Linetype lineval;
524
525 /* When compressing blank lines, act as if the file 586 /* When compressing blank lines, act as if the file
526 is preceded by a large number of blank lines. */ 587 is preceded by a large number of blank lines. */
527 blankmax = blankcount = 1000; 588 blankmax = blankcount = 1000;
528 for (;;) { 589 for (;;) {
529 linenum++; 590 Linetype lineval = parseline();
530 lineval = parseline();
531 trans_table[ifstate[depth]][lineval](); 591 trans_table[ifstate[depth]][lineval]();
532 debug("process %s -> %s depth %d", 592 debug("process line %d %s -> %s depth %d",
533 linetype_name[lineval], 593 linenum, linetype_name[lineval],
534 ifstate_name[ifstate[depth]], depth); 594 ifstate_name[ifstate[depth]], depth);
535 } 595 }
536} 596}
537 597
538/* 598/*
599 * Flush the output and handle errors.
600 */
601static void
602closeout(void)
603{
604 if (symdepth && !zerosyms)
605 printf("\n");
606 if (fclose(output) == EOF) {
607 warn("couldn't write to %s", ofilename);
608 if (overwriting) {
609 unlink(tempname);
610 errx(2, "%s unchanged", filename);
611 } else {
612 exit(2);
613 }
614 }
615}
616
617/*
618 * Clean up and exit.
619 */
620static void
621done(void)
622{
623 if (incomment)
624 error("EOF in comment");
625 closeout();
626 if (overwriting && rename(tempname, ofilename) == -1) {
627 warn("couldn't rename temporary file");
628 unlink(tempname);
629 errx(2, "%s unchanged", ofilename);
630 }
631 exit(exitstat);
632}
633
634/*
539 * Parse a line and determine its type. We keep the preprocessor line 635 * Parse a line and determine its type. We keep the preprocessor line
540 * parser state between calls in the global variable linestate, with 636 * parser state between calls in the global variable linestate, with
541 * help from skipcomment(). 637 * help from skipcomment().
@@ -549,14 +645,22 @@ parseline(void)
549 Linetype retval; 645 Linetype retval;
550 Comment_state wascomment; 646 Comment_state wascomment;
551 647
648 linenum++;
552 if (fgets(tline, MAXLINE, input) == NULL) 649 if (fgets(tline, MAXLINE, input) == NULL)
553 return (LT_EOF); 650 return (LT_EOF);
651 if (newline == NULL) {
652 if (strrchr(tline, '\n') == strrchr(tline, '\r') + 1)
653 newline = newline_crlf;
654 else
655 newline = newline_unix;
656 }
554 retval = LT_PLAIN; 657 retval = LT_PLAIN;
555 wascomment = incomment; 658 wascomment = incomment;
556 cp = skipcomment(tline); 659 cp = skipcomment(tline);
557 if (linestate == LS_START) { 660 if (linestate == LS_START) {
558 if (*cp == '#') { 661 if (*cp == '#') {
559 linestate = LS_HASH; 662 linestate = LS_HASH;
663 firstsym = true;
560 cp = skipcomment(cp + 1); 664 cp = skipcomment(cp + 1);
561 } else if (*cp != '\0') 665 } else if (*cp != '\0')
562 linestate = LS_DIRTY; 666 linestate = LS_DIRTY;
@@ -566,7 +670,8 @@ parseline(void)
566 cp = skipsym(cp); 670 cp = skipsym(cp);
567 kwlen = cp - keyword; 671 kwlen = cp - keyword;
568 /* no way can we deal with a continuation inside a keyword */ 672 /* no way can we deal with a continuation inside a keyword */
569 if (strncmp(cp, "\\\n", 2) == 0) 673 if (strncmp(cp, "\\\r\n", 3) == 0 ||
674 strncmp(cp, "\\\n", 2) == 0)
570 Eioccc(); 675 Eioccc();
571 if (strlcmp("ifdef", keyword, kwlen) == 0 || 676 if (strlcmp("ifdef", keyword, kwlen) == 0 ||
572 strlcmp("ifndef", keyword, kwlen) == 0) { 677 strlcmp("ifndef", keyword, kwlen) == 0) {
@@ -617,9 +722,8 @@ parseline(void)
617 size_t len = cp - tline; 722 size_t len = cp - tline;
618 if (fgets(tline + len, MAXLINE - len, input) == NULL) { 723 if (fgets(tline + len, MAXLINE - len, input) == NULL) {
619 /* append the missing newline */ 724 /* append the missing newline */
620 tline[len+0] = '\n'; 725 strcpy(tline + len, newline);
621 tline[len+1] = '\0'; 726 cp += strlen(newline);
622 cp++;
623 linestate = LS_START; 727 linestate = LS_START;
624 } else { 728 } else {
625 linestate = LS_DIRTY; 729 linestate = LS_DIRTY;
@@ -630,7 +734,7 @@ parseline(void)
630 while (*cp != '\0') 734 while (*cp != '\0')
631 cp = skipcomment(cp + 1); 735 cp = skipcomment(cp + 1);
632 } 736 }
633 debug("parser %s comment %s line", 737 debug("parser line %d state %s comment %s line", linenum,
634 comment_name[incomment], linestate_name[linestate]); 738 comment_name[incomment], linestate_name[linestate]);
635 return (retval); 739 return (retval);
636} 740}
@@ -875,11 +979,16 @@ skipcomment(const char *cp)
875 } 979 }
876 while (*cp != '\0') 980 while (*cp != '\0')
877 /* don't reset to LS_START after a line continuation */ 981 /* don't reset to LS_START after a line continuation */
878 if (strncmp(cp, "\\\n", 2) == 0) 982 if (strncmp(cp, "\\\r\n", 3) == 0)
983 cp += 3;
984 else if (strncmp(cp, "\\\n", 2) == 0)
879 cp += 2; 985 cp += 2;
880 else switch (incomment) { 986 else switch (incomment) {
881 case NO_COMMENT: 987 case NO_COMMENT:
882 if (strncmp(cp, "/\\\n", 3) == 0) { 988 if (strncmp(cp, "/\\\r\n", 4) == 0) {
989 incomment = STARTING_COMMENT;
990 cp += 4;
991 } else if (strncmp(cp, "/\\\n", 3) == 0) {
883 incomment = STARTING_COMMENT; 992 incomment = STARTING_COMMENT;
884 cp += 3; 993 cp += 3;
885 } else if (strncmp(cp, "/*", 2) == 0) { 994 } else if (strncmp(cp, "/*", 2) == 0) {
@@ -899,7 +1008,7 @@ skipcomment(const char *cp)
899 } else if (strncmp(cp, "\n", 1) == 0) { 1008 } else if (strncmp(cp, "\n", 1) == 0) {
900 linestate = LS_START; 1009 linestate = LS_START;
901 cp += 1; 1010 cp += 1;
902 } else if (strchr(" \t", *cp) != NULL) { 1011 } else if (strchr(" \r\t", *cp) != NULL) {
903 cp += 1; 1012 cp += 1;
904 } else 1013 } else
905 return (cp); 1014 return (cp);
@@ -931,7 +1040,10 @@ skipcomment(const char *cp)
931 cp += 1; 1040 cp += 1;
932 continue; 1041 continue;
933 case C_COMMENT: 1042 case C_COMMENT:
934 if (strncmp(cp, "*\\\n", 3) == 0) { 1043 if (strncmp(cp, "*\\\r\n", 4) == 0) {
1044 incomment = FINISHING_COMMENT;
1045 cp += 4;
1046 } else if (strncmp(cp, "*\\\n", 3) == 0) {
935 incomment = FINISHING_COMMENT; 1047 incomment = FINISHING_COMMENT;
936 cp += 3; 1048 cp += 3;
937 } else if (strncmp(cp, "*/", 2) == 0) { 1049 } else if (strncmp(cp, "*/", 2) == 0) {
@@ -1015,7 +1127,13 @@ findsym(const char *str)
1015 if (cp == str) 1127 if (cp == str)
1016 return (-1); 1128 return (-1);
1017 if (symlist) { 1129 if (symlist) {
1018 printf("%.*s\n", (int)(cp-str), str); 1130 if (symdepth && firstsym)
1131 printf("%s%3d", zerosyms ? "" : "\n", depth);
1132 firstsym = zerosyms = false;
1133 printf("%s%.*s%s",
1134 symdepth ? " " : "",
1135 (int)(cp-str), str,
1136 symdepth ? "" : "\n");
1019 /* we don't care about the value of the symbol */ 1137 /* we don't care about the value of the symbol */
1020 return (0); 1138 return (0);
1021 } 1139 }
@@ -1052,7 +1170,7 @@ addsym(bool ignorethis, bool definethis, char *sym)
1052 value[symind] = val+1; 1170 value[symind] = val+1;
1053 *val = '\0'; 1171 *val = '\0';
1054 } else if (*val == '\0') 1172 } else if (*val == '\0')
1055 value[symind] = ""; 1173 value[symind] = "1";
1056 else 1174 else
1057 usage(); 1175 usage();
1058 } else { 1176 } else {
@@ -1060,6 +1178,8 @@ addsym(bool ignorethis, bool definethis, char *sym)
1060 usage(); 1178 usage();
1061 value[symind] = NULL; 1179 value[symind] = NULL;
1062 } 1180 }
1181 debug("addsym %s=%s", symname[symind],
1182 value[symind] ? value[symind] : "undef");
1063} 1183}
1064 1184
1065/* 1185/*
@@ -1100,5 +1220,6 @@ error(const char *msg)
1100 else 1220 else
1101 warnx("%s: %d: %s (#if line %d depth %d)", 1221 warnx("%s: %d: %s (#if line %d depth %d)",
1102 filename, linenum, msg, stifline[depth], depth); 1222 filename, linenum, msg, stifline[depth], depth);
1223 closeout();
1103 errx(2, "output may be truncated"); 1224 errx(2, "output may be truncated");
1104} 1225}