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 c5fe0bf..3a665ef 100644 --- a/job.c +++ b/job.c @@ -26,6 +26,7 @@ this program. If not, see . */ #include "commands.h" #include "variable.h" #include "debug.h" +#include "output.h" #include @@ -1204,9 +1205,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, "%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 86a89ad..e484e14 100644 --- a/main.c +++ b/main.c @@ -25,6 +25,7 @@ this program. If not, see . */ #include "rule.h" #include "debug.h" #include "getopt.h" +#include "output.h" #include #ifdef _AMIGA @@ -268,6 +269,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 --format=. */ +static struct stringlist *format_strings = 0; + /* If nonzero, we should just print usage and exit. */ static int print_usage_flag = 0; @@ -323,6 +327,9 @@ static const char *const usage[] = -f FILE, --file=FILE, --makefile=FILE\n\ Read FILE as a makefile.\n"), N_("\ + --format=(plain|color|colour)]\n\ + Enable/disable colorization of output.\n"), + N_("\ -h, --help Print this message and exit.\n"), N_("\ -i, --ignore-errors Ignore errors from recipes.\n"), @@ -427,6 +434,7 @@ 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, &format_strings, 1, 1, 0, 0, 0, "format" }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; @@ -1656,6 +1664,29 @@ main (int argc, char **argv, char **envp) define_variable_cname ("-*-eval-flags-*-", value, o_automatic, 0); } + if (format_strings) + { + /* Be strict: Check all occurances for invalid values */ + unsigned int i; + const char * last_string = format_strings->list[format_strings->idx - 1]; + for (i = 0; i < format_strings->idx; ++i) + { + const char * request = format_strings->list[i]; + if (streq("plain", request) || streq("color", request) || streq("colour", request)) + { + continue; + } + fatal (NILF, _("parameter error: format '%s' not supported. " + "Valid formats are 'plain' and 'color'/'colour'"), request); + } + + /* Enable/disable color based on the last request */ + color_flag = streq("color", last_string) || streq("colour", last_string); + DB(DB_VERBOSE, ("Colorization %s\n", color_flag ? "enabled" : "disabled")); + + apply_make_colors (); + } + /* Read all the makefiles. */ read_makefiles @@ -3299,33 +3330,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, _("%s: Entering an unknown directory\n"), program); else - printf (_("%s: Leaving an unknown directory\n"), program); + outputf (OT_DIR_LEAVE, 0, _("%s: Leaving an unknown directory\n"), program); else if (entering) - printf (_("%s: Entering directory `%s'\n"), + outputf (OT_DIR_ENTER, 0, _("%s: Entering directory `%s'\n"), program, starting_directory); else - printf (_("%s: Leaving directory `%s'\n"), + outputf (OT_DIR_LEAVE, 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, _("%s[%u]: Entering an unknown directory\n"), program, makelevel); else - printf (_("%s[%u]: Leaving an unknown directory\n"), + outputf (OT_DIR_LEAVE, 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, _("%s[%u]: Entering directory `%s'\n"), program, makelevel, starting_directory); else - printf (_("%s[%u]: Leaving directory `%s'\n"), + outputf (OT_DIR_LEAVE, 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) | OT_MISC_MESSAGE; VA_START (args, fmt); - VA_PRINTF (stdout, fmt, args); + voutputf (flags, 0, 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|OF_PREPEND_PREFIX, flocp, 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|OF_PREPEND_PREFIX, flocp, 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..f0e28a0 --- /dev/null +++ b/output.c @@ -0,0 +1,285 @@ +/* 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 +#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(int flags, const struct floc *flocp, const char * format, va_list args) +{ + FILE * target = NULL; + const char * color = NULL; + int colorize = color_flag; + int append_newline; + + if ((format == 0) || (format[0] == '\0')) + return; + + append_newline = (format[strlen(format) - 1] != '\n'); + + /* Determine target file (i.e. stdout or stderr) and color to pick */ + switch (flags & OT_MASK) + { + 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 = ((flags & OT_MASK) == 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 ((flags & OT_MASK) == 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 */ + fflush(target); +} + + +void outputf(int flags, const struct floc *flocp, const char * format, ...) +{ + va_list args; + + /* TODO make more portabe, see misc.c */ + va_start (args, format); + voutputf(flags, flocp, format, args); + va_end (args); +} diff --git a/output.h b/output.h new file mode 100644 index 0000000..ae4bbeb --- /dev/null +++ b/output.h @@ -0,0 +1,49 @@ +/* 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 _output_config_t { + OT_MASK = 0xff, + OT_DIR_ENTER = 0x01, + OT_DIR_LEAVE = 0x02, + OT_MISC_MESSAGE = 0x03, + OT_MISC_ERROR = 0x04, + OT_MISC_FATAL = 0x05, + OT_EXECUTION = 0x06, + + OF_PREPEND_PREFIX = 0x100 +} output_config_t; + + +struct floc; + +void outputf(int, const struct floc *, const char *, ...); +void voutputf(int, const struct floc *, const char *, va_list); + +void apply_make_colors(); + + +#endif /* not _output_h_ */