diff --git a/AUTHORS b/AUTHORS index 87b077c..ee38897 100644 --- a/AUTHORS +++ b/AUTHORS @@ -62,6 +62,7 @@ Other contributors: Ian Stewartson (Data Logic Limited) Ramon Garcia Fernandez David A. Wheeler + Sebastian Pipping With suggestions/comments/bug reports from a cast of ... well ... hundreds, anyway :) diff --git a/Makefile.am b/Makefile.am index c747ada..acac4dd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -43,12 +43,12 @@ endif make_SOURCES = ar.c arscan.c commands.c default.c dir.c expand.c file.c \ function.c getopt.c getopt1.c implicit.c job.c main.c \ misc.c read.c remake.c $(remote) rule.c signame.c \ - strcache.c variable.c version.c vpath.c hash.c + strcache.c variable.c version.c vpath.c hash.c output.c EXTRA_make_SOURCES = vmsjobs.c remote-stub.c remote-cstms.c noinst_HEADERS = commands.h dep.h filedef.h job.h make.h rule.h variable.h \ - debug.h getopt.h gettext.h hash.h + debug.h getopt.h gettext.h hash.h output.h make_LDADD = @LIBOBJS@ @ALLOCA@ $(GLOBLIB) @GETLOADAVG_LIBS@ @LIBINTL@ # Only process if target is MS-Windows diff --git a/Makefile.ami b/Makefile.ami index 8cc67df..e547fee 100644 --- a/Makefile.ami +++ b/Makefile.ami @@ -121,14 +121,14 @@ CTAGS = ctags -w objs = commands.o job.o dir.o file.o misc.o main.o read.o remake.o \ rule.o implicit.o default.o variable.o expand.o function.o \ vpath.o version.o ar.o arscan.o signame.o strcache.o hash.o \ - remote-$(REMOTE).o $(GETOPT) $(ALLOCA) $(extras) + output.o remote-$(REMOTE).o $(GETOPT) $(ALLOCA) $(extras) srcs = $(srcdir)commands.c $(srcdir)job.c $(srcdir)dir.c \ $(srcdir)file.c $(srcdir)getloadavg.c $(srcdir)misc.c \ $(srcdir)main.c $(srcdir)read.c $(srcdir)remake.c \ $(srcdir)rule.c $(srcdir)implicit.c $(srcdir)default.c \ $(srcdir)variable.c $(srcdir)expand.c $(srcdir)function.c \ $(srcdir)vpath.c $(srcdir)version.c $(srcdir)hash.c \ - $(srcdir)remote-$(REMOTE).c \ + $(srcdir)remote-$(REMOTE).c $(srcdir)output.c \ $(srcdir)ar.c $(srcdir)arscan.c $(srcdir)strcache.c \ $(srcdir)signame.c $(srcdir)signame.h $(GETOPT_SRC) \ $(srcdir)commands.h $(srcdir)dep.h $(srcdir)filedep.h \ @@ -294,6 +294,7 @@ variable.o: variable.c make.h dep.h filedef.h job.h commands.h \ expand.o: expand.c make.h filedef.h job.h commands.h variable.h function.o: function.c make.h filedef.h variable.h dep.h job.h \ commands.h amiga.h +output.o: output.c output.h vpath.o: vpath.c make.h filedef.h variable.h strcache.o: strcache.c make.h hash.h version.o: version.c diff --git a/SMakefile.template b/SMakefile.template index 7e9229e..73e3f81 100644 --- a/SMakefile.template +++ b/SMakefile.template @@ -127,14 +127,14 @@ CTAGS = ctags -w objs = commands.o job.o dir.o file.o misc.o main.o read.o remake.o \ rule.o implicit.o default.o variable.o expand.o function.o \ vpath.o version.o ar.o arscan.o signame.o strcache.o hash.o \ - remote-$(REMOTE).o $(GLOB) $(GETOPT) $(ALLOCA) $(extras) + remote-$(REMOTE).o output.o $(GLOB) $(GETOPT) $(ALLOCA) $(extras) srcs = $(srcdir)commands.c $(srcdir)job.c $(srcdir)dir.c \ $(srcdir)file.c $(srcdir)getloadavg.c $(srcdir)misc.c \ $(srcdir)main.c $(srcdir)read.c $(srcdir)remake.c \ $(srcdir)rule.c $(srcdir)implicit.c $(srcdir)default.c \ $(srcdir)variable.c $(srcdir)expand.c $(srcdir)function.c \ $(srcdir)vpath.c $(srcdir)version.c $(srcdir)hash.c \ - $(srcdir)remote-$(REMOTE).c \ + $(srcdir)remote-$(REMOTE).c output.c \ $(srcdir)ar.c $(srcdir)arscan.c $(srcdir)strcache.c \ $(srcdir)signame.c $(srcdir)signame.h $(GETOPT_SRC) \ $(srcdir)commands.h $(srcdir)dep.h $(srcdir)file.h \ diff --git a/build_w32.bat b/build_w32.bat index de758b0..ca94dcc 100644 --- a/build_w32.bat +++ b/build_w32.bat @@ -80,6 +80,8 @@ cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D echo WinDebug\ar.obj >>link.dbg cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c function.c echo WinDebug\function.obj >>link.dbg +cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c output.c +echo WinDebug\output.obj >>link.dbg cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c vpath.c echo WinDebug\vpath.obj >>link.dbg cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c implicit.c @@ -147,6 +149,8 @@ cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIND echo WinRel\ar.obj >>link.rel cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c function.c echo WinRel\function.obj >>link.rel +cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c output.c +echo WinRel\output.obj >>link.rel cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c vpath.c echo WinRel\vpath.obj >>link.rel cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c implicit.c @@ -193,6 +197,7 @@ gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 - gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c misc.c gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c ar.c gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c function.c +gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c output.c gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c vpath.c gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c implicit.c gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c ./glob/glob.c -o glob.o diff --git a/dosbuild.bat b/dosbuild.bat index c911e18..4a12bbb 100644 --- a/dosbuild.bat +++ b/dosbuild.bat @@ -34,6 +34,7 @@ gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g default.c -o default.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g variable.c -o variable.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g expand.c -o expand.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g function.c -o function.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g output.c -o output.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g vpath.c -o vpath.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g hash.c -o hash.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g strcache.c -o strcache.o @@ -53,7 +54,7 @@ ar rv libglob.a glob.o fnmatch.o cd .. echo commands.o > respf.$$$ for %%f in (job dir file misc main read remake rule implicit default variable) do echo %%f.o >> respf.$$$ -for %%f in (expand function vpath hash strcache version ar arscan signame remote-stub getopt getopt1) do echo %%f.o >> respf.$$$ +for %%f in (expand function output vpath hash strcache version ar arscan signame remote-stub getopt getopt1) do echo %%f.o >> respf.$$$ echo glob/libglob.a >> respf.$$$ @echo Linking... @echo on diff --git a/job.c b/job.c index c2ce84d..6b2b40e 100644 --- a/job.c +++ b/job.c @@ -1,7 +1,7 @@ /* Job execution and handling for GNU Make. Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, -2010 Free Software Foundation, Inc. +2010, 2011 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -26,6 +26,7 @@ this program. If not, see . */ #include "commands.h" #include "variable.h" #include "debug.h" +#include "output.h" #include @@ -1176,9 +1177,9 @@ start_job_command (struct child *child) can log the working directory before the command's own error messages appear. */ - message (0, (just_print_flag || trace_flag - || (!(flags & COMMANDS_SILENT) && !silent_flag)) - ? "%s" : (char *) 0, p); + if (just_print_flag || trace_flag + || (!(flags & COMMANDS_SILENT) && !silent_flag)) + outputf (OT_EXECUTION, 0, OF_APPEND_NEWLINE, "%s", p); /* Tell update_goal_chain that a command has been started on behalf of this target. It is important that this happens here and not in diff --git a/main.c b/main.c index 75eb494..4194155 100644 --- a/main.c +++ b/main.c @@ -1,7 +1,7 @@ /* Argument parsing and main program of GNU Make. Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, -2010 Free Software Foundation, Inc. +2010, 2011 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the @@ -25,6 +25,7 @@ this program. If not, see . */ #include "rule.h" #include "debug.h" #include "getopt.h" +#include "output.h" #include #ifdef _AMIGA @@ -266,6 +267,9 @@ static struct stringlist *new_files = 0; /* List of strings to be eval'd. */ static struct stringlist *eval_strings = 0; +/* List of strings passed as --color=. */ +static struct stringlist *color_strings = 0; + /* If nonzero, we should just print usage and exit. */ static int print_usage_flag = 0; @@ -309,6 +313,8 @@ static const char *const usage[] = -C DIRECTORY, --directory=DIRECTORY\n\ Change to DIRECTORY before doing anything.\n"), N_("\ + --color[=(yes|no)] Enable/disable colorization of output.\n"), + N_("\ -d Print lots of debugging information.\n"), N_("\ --debug[=FLAGS] Print various types of debugging information.\n"), @@ -425,6 +431,8 @@ static const struct command_switch switches[] = { CHAR_MAX+5, flag, &warn_undefined_variables_flag, 1, 1, 0, 0, 0, "warn-undefined-variables" }, { CHAR_MAX+6, string, &eval_strings, 1, 0, 0, 0, 0, "eval" }, + { CHAR_MAX+7, string, &color_strings, 1, 1, 0, "yes", 0, "color" }, + { CHAR_MAX+8, string, &color_strings, 1, 1, 0, "yes", 0, "colour" }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; @@ -1654,6 +1662,28 @@ main (int argc, char **argv, char **envp) define_variable_cname ("-*-eval-flags-*-", value, o_automatic, 0); } + if (color_strings) + { + /* Be strict: Check all occurances for invalid values */ + unsigned int i; + for (i = 0; i < color_strings->idx; ++i) + { + const char * request = color_strings->list[i]; + if (streq("yes", request) || streq("no", request)) + { + continue; + } + fatal (NILF, _("parameter error: --color=%s not supported. " + "Try --color, --color=yes, or --color=no, instead"), request); + } + + /* Enable/disable color based on the last request */ + color_flag = streq("yes", color_strings->list[color_strings->idx - 1]); + DB(DB_VERBOSE, ("Colorization %s\n", color_flag ? "enabled" : "disabled")); + + apply_make_colors (); + } + /* Read all the makefiles. */ read_makefiles @@ -3234,33 +3264,35 @@ log_working_directory (int entering) /* Use entire sentences to give the translators a fighting chance. */ + /* TODO can be strongly simplified using flag OF_PREPEND_PREFIX + * but that needs touching translation strings */ if (makelevel == 0) if (starting_directory == 0) if (entering) - printf (_("%s: Entering an unknown directory\n"), program); + outputf (OT_DIR_ENTER, 0, 0, _("%s: Entering an unknown directory\n"), program); else - printf (_("%s: Leaving an unknown directory\n"), program); + outputf (OT_DIR_LEAVE, 0, 0, _("%s: Leaving an unknown directory\n"), program); else if (entering) - printf (_("%s: Entering directory `%s'\n"), + outputf (OT_DIR_ENTER, 0, 0, _("%s: Entering directory `%s'\n"), program, starting_directory); else - printf (_("%s: Leaving directory `%s'\n"), + outputf (OT_DIR_LEAVE, 0, 0, _("%s: Leaving directory `%s'\n"), program, starting_directory); else if (starting_directory == 0) if (entering) - printf (_("%s[%u]: Entering an unknown directory\n"), + outputf (OT_DIR_ENTER, 0, 0, _("%s[%u]: Entering an unknown directory\n"), program, makelevel); else - printf (_("%s[%u]: Leaving an unknown directory\n"), + outputf (OT_DIR_LEAVE, 0, 0, _("%s[%u]: Leaving an unknown directory\n"), program, makelevel); else if (entering) - printf (_("%s[%u]: Entering directory `%s'\n"), + outputf (OT_DIR_ENTER, 0, 0, _("%s[%u]: Entering directory `%s'\n"), program, makelevel, starting_directory); else - printf (_("%s[%u]: Leaving directory `%s'\n"), + outputf (OT_DIR_LEAVE, 0, 0, _("%s[%u]: Leaving directory `%s'\n"), program, makelevel, starting_directory); /* Flush stdout to be sure this comes before any stderr output. */ diff --git a/make.1 b/make.1 index 5dade8f..2bebe18 100644 --- a/make.1 +++ b/make.1 @@ -113,6 +113,9 @@ is equivalent to This is typically used with recursive invocations of .BR make . .TP 0.5i +\fB\-\-color\fR[=(yes|no)] +Enable/disable colorization of output. +.TP 0.5i .B \-d Print debugging information in addition to normal processing. The debugging information says which files are being considered for diff --git a/make_msvc_net2003.vcproj b/make_msvc_net2003.vcproj index 357dfba..1317a99 100644 --- a/make_msvc_net2003.vcproj +++ b/make_msvc_net2003.vcproj @@ -173,6 +173,9 @@ RelativePath=".\misc.c"> + + + + . */ #include "make.h" #include "dep.h" #include "debug.h" +#include "output.h" /* Variadic functions. We go through contortions to allow proper function prototypes for both ANSI and pre-ANSI C compilers, and also for those @@ -229,23 +230,13 @@ message (prefix, fmt, va_alist) #endif log_working_directory (1); - if (fmt != 0) { - if (prefix) - { - if (makelevel == 0) - printf ("%s: ", program); - else - printf ("%s[%u]: ", program, makelevel); - } + const int flags = (prefix ? OF_PREPEND_PREFIX : 0) | OF_APPEND_NEWLINE|OF_FLUSH; VA_START (args, fmt); - VA_PRINTF (stdout, fmt, args); + voutputf (OT_MISC_MESSAGE, 0, flags, fmt, args); VA_END (args); - putchar ('\n'); } - - fflush (stdout); } /* Print an error message. */ @@ -266,19 +257,9 @@ error (flocp, fmt, va_alist) log_working_directory (1); - if (flocp && flocp->filenm) - fprintf (stderr, "%s:%lu: ", flocp->filenm, flocp->lineno); - else if (makelevel == 0) - fprintf (stderr, "%s: ", program); - else - fprintf (stderr, "%s[%u]: ", program, makelevel); - VA_START(args, fmt); - VA_PRINTF (stderr, fmt, args); + voutputf (OT_MISC_ERROR, flocp, OF_PREPEND_PREFIX|OF_APPEND_NEWLINE|OF_FLUSH, fmt, args); VA_END (args); - - putc ('\n', stderr); - fflush (stderr); } /* Print an error message and exit. */ @@ -299,19 +280,10 @@ fatal (flocp, fmt, va_alist) log_working_directory (1); - if (flocp && flocp->filenm) - fprintf (stderr, "%s:%lu: *** ", flocp->filenm, flocp->lineno); - else if (makelevel == 0) - fprintf (stderr, "%s: *** ", program); - else - fprintf (stderr, "%s[%u]: *** ", program, makelevel); - VA_START(args, fmt); - VA_PRINTF (stderr, fmt, args); + voutputf (OT_MISC_FATAL, flocp, OF_PREPEND_PREFIX|OF_APPEND_NEWLINE, fmt, args); VA_END (args); - fputs (_(". Stop.\n"), stderr); - die (2); } diff --git a/output.c b/output.c new file mode 100644 index 0000000..90a67eb --- /dev/null +++ b/output.c @@ -0,0 +1,283 @@ +/* Interface for all user interface output. +Copyright (C) 2011 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +#include "output.h" +#include "make.h" +#include "debug.h" +#include +#include + + +#define COLOR_BOLD_RED "1;31" +#define COLOR_CYAN "0;36" +#define COLOR_GREEN "0;32" +#define COLOR_BOLD_MAGENTA "1;35" + +#define ERASE_IN_LINE "\033[K" + + +/* TODO resolve use of "extern" */ + +/* Value of the MAKELEVEL variable at startup (or 0). */ +extern unsigned int makelevel; + +/* The name we were invoked with. */ +extern char *program; + +/* From misc.c. */ +extern char * xstrndup (const char *str, unsigned int length); + + +/* Nonzero means do colorize output. */ +int color_flag; + +/* Nonzero means do output "\033[K" after color open and close. */ +int erase_in_line_flag = 1; + +/* These colors are uses for output. Can be overridden from "MAKE_COLORS". */ +const char * color_dir_enter = COLOR_CYAN; +const char * color_dir_leave = COLOR_CYAN; +const char * color_misc_message = COLOR_GREEN; +const char * color_misc_error = COLOR_BOLD_RED; +const char * color_misc_fatal = COLOR_BOLD_RED; +const char * color_execution = COLOR_BOLD_MAGENTA; + + +#define PREVENT_NULL(s) ((s) ? (s) : "") + + +typedef struct _char_range_t { + const char * first; + const char * after_last; +} char_range_t; + +#define RANGE_LEN(range) (range.after_last - range.first) +#define RANGE_DUP(range) xstrndup(range.first, RANGE_LEN(range)) +#define RANGE_EQUALS(range, text) \ + ( ! strncmp(text, range.first, RANGE_LEN(range)) \ + && ((long)strlen(text) == RANGE_LEN(range))) +#define RANGE_SET(range, _first, _after_last) \ + do \ + { \ + range.first = _first; \ + range.after_last = _after_last; \ + } \ + while (0) +#define EMPTY_RANGE { 0, 0 } + + +typedef struct _mapping_def_t { + const char * key; + int * flag_destination; + const char ** color_destination; +} mapping_def_t; + +/* Find the index of a certain name in an array of mapping_def_t instances */ +#define FIND(haystack_array, member, needle_range, match_index) \ + do \ + { \ + size_t u = 0; \ + match_index = -1; \ + for (; u < sizeof(haystack_array) / sizeof(haystack_array[0]); u++) \ + { \ + const char * const key = haystack_array[u].member; \ + if (RANGE_EQUALS(needle_range, key)) \ + { \ + match_index = u; \ + break; \ + } \ + } \ + } \ + while(0) + + +void apply_make_colors() +{ + const mapping_def_t valid_names[] = { + {"enter", 0, &color_dir_enter}, + {"leave", 0, &color_dir_leave}, + {"message", 0, &color_misc_message}, + {"error", 0, &color_misc_error}, + {"fatal", 0, &color_misc_fatal}, + {"run", 0, &color_execution}, + {"erase", &erase_in_line_flag, 0}, + }; + + int name_index = -1; + const char * const MAKE_COLORS = getenv("MAKE_COLORS"); + const char * key_pos = MAKE_COLORS; + const char * colon_pos = NULL; + char_range_t name = EMPTY_RANGE; + char_range_t value = EMPTY_RANGE; + if (! MAKE_COLORS) + return; + + /* Example: MAKE_COLORS='erase=no:enter=0;42:leave=0;41:message=0' */ + for (; key_pos != 0; key_pos = colon_pos + 1) + { + const char * const assign_pos = strchr(key_pos, '='); + if (! assign_pos) { + fatal (0, "Assignment ('=') missing in MAKE_COLORS: \"%s\"", key_pos); + } + + colon_pos = strchr(assign_pos, ':'); + if (! colon_pos) + colon_pos = assign_pos + strlen(assign_pos); + + RANGE_SET(name, key_pos, assign_pos); + RANGE_SET(value, assign_pos + 1, colon_pos); + + if (RANGE_LEN(name) > 0) + { + FIND(valid_names, key, name, name_index); + if (name_index == -1) + { + char * const s = RANGE_DUP(name); + fatal (0, "Invalid name in MAKE_COLORS: \"%s\"", PREVENT_NULL(s)); + free(s); + } + } + else + fatal (0, "Empty name in MAKE_COLORS: \"%s\"", key_pos); + + /* Which kind of statement do we have? */ + if (valid_names[name_index].flag_destination) + { + /* Boolean statement */ + int * const destination = valid_names[name_index].flag_destination; + if (RANGE_LEN(value) <= 0) + { + const char * const switch_name = valid_names[name_index].key; + fatal (0, "Empty value for switch \"%s\" in MAKE_COLORS", switch_name); + } + else if (RANGE_EQUALS(value, "yes")) + { + DB(DB_VERBOSE, ("Erase in line enabled\n")); + *destination = 1; + } + else if (RANGE_EQUALS(value, "no")) + { + DB(DB_VERBOSE, ("Erase in line disabled\n")); + *destination = 0; + } + else + { + /* Invalid (i.e. neither "yes" nor "no") */ + const char * const switch_name = valid_names[name_index].key; + char * const guilty_part = RANGE_DUP(value); + fatal (0, "Invalid value for switch \"%s\" in MAKE_COLORS: \"%s\"", switch_name, PREVENT_NULL(guilty_part)); + free(guilty_part); + } + } + else + { + /* Colorization statement */ + const int value_is_valid = RANGE_LEN(value) > 0; + if (value_is_valid) + { + const char * const class_name = valid_names[name_index].key; + const char * const color = PREVENT_NULL(RANGE_DUP(value)); + const char ** const color_destination = valid_names[name_index].color_destination; + DB(DB_VERBOSE, ("Applying color \"%s\" to class \"%s\"\n", color, class_name)); + *color_destination = color; + } + else + { + const char_range_t guilty_range = { key_pos, colon_pos }; + char * const guilty_part = RANGE_DUP(guilty_range); + fatal (0, "Invalid color mapping in MAKE_COLORS: \"%s\"", PREVENT_NULL(guilty_part)); + free(guilty_part); + } + } + + /* Done? */ + if (colon_pos[0] == '\0') + break; + } +} + + +void voutputf(message_t type, const struct floc *flocp, int flags, const char * format, va_list args) +{ + FILE * target = NULL; + const char * color = NULL; + int colorize = color_flag; + const int append_newline = (flags & OF_APPEND_NEWLINE); + + if ((format == 0) || (format[0] == '\0')) + return; + + /* Determine target file (i.e. stdout or stderr) and color to pick */ + switch (type) + { + case OT_DIR_ENTER: target = stdout; color = color_dir_enter; break; + case OT_DIR_LEAVE: target = stdout; color = color_dir_leave; break; + case OT_MISC_MESSAGE: target = stdout; color = color_misc_message; break; + case OT_MISC_ERROR: target = stderr; color = color_misc_error; break; + case OT_MISC_FATAL: target = stderr; color = color_misc_fatal; break; + case OT_EXECUTION: target = stdout; color = color_execution; break; + default: target = stdout; color = ""; colorize = 0; break; + } + assert(target); + assert(color); + + /* Output color start */ + if (colorize) + fprintf (target, "\033[%sm%s", color, + erase_in_line_flag ? ERASE_IN_LINE : ""); + + /* Output prefix */ + if (flags & OF_PREPEND_PREFIX) + { + const char * catchy = (type == OT_MISC_FATAL) ? "*** " : ""; + if (flocp && flocp->filenm) + fprintf (target, "%s:%lu: %s", flocp->filenm, flocp->lineno, catchy); + else if (makelevel == 0) + fprintf (target, "%s: %s", program, catchy); + else + fprintf (target, "%s[%u]: %s", program, makelevel, catchy); + } + + /* Output actual message */ + /* TODO make more portabe, see misc.c */ + vfprintf (target, format, args); + + if (type == OT_MISC_FATAL) + fputs (_(". Stop."), target); + + /* Output finishing newline and color stop */ + if (colorize) + fprintf (target, "%s\033[m%s", + append_newline ? "\n" : "", + erase_in_line_flag ? ERASE_IN_LINE : ""); + else if (append_newline) + fputc ('\n', target); + + /* Flush */ + if (flags & OF_FLUSH) + fflush(target); +} + + +void outputf(message_t type, const struct floc *flocp, int flags, const char * format, ...) +{ + va_list args; + + /* TODO make more portabe, see misc.c */ + va_start (args, format); + voutputf(type, flocp, flags, format, args); + va_end (args); +} diff --git a/output.h b/output.h new file mode 100644 index 0000000..8e0956b --- /dev/null +++ b/output.h @@ -0,0 +1,52 @@ +/* Interface for all user interface output. +Copyright (C) 2011 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +#ifndef _output_h_ +#define _output_h_ + + +#include /* TODO make more portabe, see misc.c */ + + +/* Nonzero means do colorize output printed. */ +extern int color_flag; + + +typedef enum _message_t { + OT_DIR_ENTER, + OT_DIR_LEAVE, + OT_MISC_MESSAGE, + OT_MISC_ERROR, + OT_MISC_FATAL, + OT_EXECUTION +} message_t; + +enum { + OF_APPEND_NEWLINE = 0x1, + OF_PREPEND_PREFIX = 0x2, + OF_FLUSH = 0x4 +}; + + +struct floc; + +void outputf(message_t, const struct floc *, int, const char *, ...); +void voutputf(message_t, const struct floc *, int, const char *, va_list); + +void apply_make_colors(); + + +#endif /* not _output_h_ */ diff --git a/remake.c b/remake.c index 5526624..e4e7396 100644 --- a/remake.c +++ b/remake.c @@ -1,7 +1,7 @@ /* Basic dependency engine for GNU Make. Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, -2010 Free Software Foundation, Inc. +2010, 2011 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify it under the