diff options
Diffstat (limited to 'dmake/dmake.c')
-rw-r--r-- | dmake/dmake.c | 959 |
1 files changed, 959 insertions, 0 deletions
diff --git a/dmake/dmake.c b/dmake/dmake.c new file mode 100644 index 000000000000..b96bf4ce3146 --- /dev/null +++ b/dmake/dmake.c @@ -0,0 +1,959 @@ +/* $RCSfile: dmake.c,v $ +-- $Revision: 1.13 $ +-- last change: $Author: kz $ $Date: 2008-03-05 18:28:04 $ +-- +-- SYNOPSIS +-- The main program. +-- +-- DESCRIPTION +-- +-- dmake [-#dbug_string] [ options ] +-- [ macro definitions ] [ target ... ] +-- +-- This file contains the main command line parser for the +-- make utility. The valid flags recognized are as follows: +-- +-- -f file - use file as the makefile +-- -C file - duplicate console output to file (MSDOS only) +-- -K file - .KEEP_STATE file +-- -#dbug_string - dump out debugging info, see below +-- -v[cdfimrtw] - verbose, print what we are doing, as we do it +-- -m[trae] - measure timing information +-- +-- options: (can be catenated, ie -irn == -i -r -n) +-- +-- -A - enable AUGMAKE special target mapping +-- -B - enable non-use of TABS to start recipe lines +-- -c - use non-standard comment scanning +-- -d - do not use directory cache +-- -i - ignore errors +-- -n - trace and print, do not execute commands +-- -t - touch, update dates without executing commands +-- -T - do not apply transitive closure on inference rules +-- -r - don't use internal rules +-- -s - do your work silently +-- -S - force Sequential make, overrides -P +-- -q - check if target is up to date. Does not +-- do anything. Returns 0 if up to date, -1 +-- otherwise. +-- -p - print out a version of the makefile +-- -P# - set value of MAXPROCESS +-- -E - define environment strings as macros +-- -e - as -E but done after parsing makefile +-- -u - force unconditional update of target +-- -k - make all independent targets even if errors +-- -V - print out this make version number +-- -M - Microsoft make compatibility, (* disabled *) +-- -h - print out usage info +-- -x - export macro defs to environment +-- -X - ignore #! lines found in makefile +-- +-- NOTE: - #ddbug_string is only availabe for versions of dmake that +-- have been compiled with -DDBUG switch on. Not the case for +-- distributed versions. Any such versions must be linked +-- together with a version of Fred Fish's debug code. +-- +-- NOTE: - in order to compile the code the include file stddef.h +-- must be shipped with the bundled code. +-- +-- AUTHOR +-- Dennis Vadura, dvadura@dmake.wticorp.com +-- +-- WWW +-- http://dmake.wticorp.com/ +-- +-- COPYRIGHT +-- Copyright (c) 1996,1997 by WTI Corp. All rights reserved. +-- +-- This program is NOT free software; you can redistribute it and/or +-- modify it under the terms of the Software License Agreement Provided +-- in the file <distribution-root>/readme/license.txt. +-- +-- LOG +-- Use cvs log to obtain detailed change logs. +*/ + +/* Set this flag to one, and the global variables in vextern.h will not + * be defined as 'extern', instead they will be defined as global vars + * when this module is compiled. */ +#define _DEFINE_GLOBALS_ 1 + +#include "extern.h" /* this includes config.h */ +#include "sysintf.h" + +#ifndef MSDOS +#define USAGE \ +"Usage:\n%s [-P#] [-{f|K} file] [-{w|W} target ...] [macro[!][[*][+][:]]=value ...]\n" +#define USAGE2 \ +"%s [-v[cdfimrtw]] [-m[trae]] [-ABcdeEghiknpqrsStTuVxX] [target ...]\n" +#else +#define USAGE \ +"Usage:\n%s [-P#] [-{f|C|K} file] [-{w|W} target ...] [macro[!][[*][+][:]]=value ...]\n" +#define USAGE2 \ +"%s [-v[cdfimrtw]] [-m[trae]] [-ABcdeEghiknpqrsStTuVxX] [target ...]\n" +#endif + +/* We don't use va_end at all, so define it out so that it doesn't produce + * lots of "Value not used" warnings. */ +#ifdef va_end +#undef va_end +#endif +#define va_end(expand_to_null) + +/* Make certain that ARG macro is correctly defined. */ +#ifdef ARG +#undef ARG +#endif +#define ARG(a,b) a b + +static char *sccid = "Copyright (c) 1990,...,1997 by WTI Corp."; +static char _warn = TRUE; /* warnings on by default */ + +static void _do_VPATH(); +static void _do_ReadEnvironment(); +#if !defined(__GNUC__) && !defined(__IBMC__) +static void _do_f_flag ANSI((char, char *, char **)); +#else +static void _do_f_flag ANSI((int, char *, char **)); +#endif + +PUBLIC int +main(argc, argv) +int argc; +char **argv; +{ +#ifdef MSDOS + char* std_fil_name = NIL(char); +#endif + + char* fil_name = NIL(char); + char* state_name = NIL(char); + char* whatif = NIL(char); + char* cmdmacs; + char* targets; + STRINGPTR cltarget = NIL(STRING); /* list of targets from command line. */ + STRINGPTR cltarget_first = NIL(STRING); /* Pointer to first element. */ + FILE* mkfil; + int ex_val; + int m_export; + + /* Uncomment the following line to pass commands to the DBUG engine + * before the command line switches (-#..) are evaluated. */ + /* + DB_PUSH("d,path"); + */ + DB_ENTER("main"); + + /* Initialize Global variables to their default values */ + Prolog(argc, argv); + /* Set internal macros to their initial values, some are changed + * later again by Make_rules() that parses the values from ruletab.c. */ + Create_macro_vars(); + Catch_signals(Quit); + + /* This macro is only defined for some OSs, see sysintf.c for details * + * and NULL if undefined. */ + Def_macro("ABSMAKECMD", AbsPname, M_PRECIOUS|M_NOEXPORT|M_EXPANDED ); + + Def_macro( "MAKECMD", Pname, M_PRECIOUS|M_NOEXPORT|M_EXPANDED ); + Pname = Basename(Pname); + + DB_PROCESS(Pname); + (void) setvbuf(stdout, NULL, _IOLBF, BUFSIZ); /* stdout line buffered */ + + Continue = FALSE; + Comment = FALSE; + Get_env = FALSE; + Force = FALSE; + Target = FALSE; + If_expand = FALSE; + Listing = FALSE; + Readenv = FALSE; + Rules = TRUE; + Trace = FALSE; + Touch = FALSE; + Check = FALSE; + Microsoft = FALSE; + Makemkf = FALSE; + UseWinpath= FALSE; + No_exec = FALSE; + m_export = FALSE; + cmdmacs = NIL(char); + targets = NIL(char); + Is_exec_shell = FALSE; + Shell_exec_target = NIL(CELL); + stdout_redir = NIL(FILE); + + /* Get fd for for @@-recipe silencing. */ + if( (zerofd = open(NULLDEV, O_WRONLY)) == -1 ) + Fatal( "Error opening %s !", NULLDEV ); + + Verbose = V_NOFLAG; + Measure = M_NOFLAG; + Transitive = TRUE; + Nest_level = 0; + Line_number = 0; + Suppress_temp_file = FALSE; + Skip_to_eof = FALSE; + + while( --argc > 0 ) { + register char *p; + char *q; + + if( *(p = *++argv) == '-' ) { + if( p[1] == '\0' ) Fatal("Missing option letter"); + + /* copy options to Buffer for $(MFLAGS), strip 'f' and 'C'*/ + q = strchr(Buffer, '\0'); + while (*p != '\0') { + char c = (*q++ = *p++); + if( c == 'f' || c == 'C' ) q--; + } + + if( *(q-1) == '-' ) + q--; + else + *q++ = ' '; + + *q = '\0'; + + for( p = *argv+1; *p; p++) switch (*p) { + case 'f': + _do_f_flag( 'f', *++argv, &fil_name ); argc--; + break; + +#if defined(MSDOS) && !defined(OS2) + case 'C': + _do_f_flag( 'C', *++argv, &std_fil_name ); argc--; + Hook_std_writes( std_fil_name ); + break; +#endif + + case 'K': + _do_f_flag( 'K', *++argv, &state_name ); argc--; + Def_macro(".KEEP_STATE", state_name, M_EXPANDED|M_PRECIOUS); + break; + + case 'W': + case 'w': { + CELLPTR wif; + _do_f_flag( 'w', *++argv, &whatif ); argc--; + wif = Def_cell(whatif); + wif->ce_attr |= A_WHATIF; + whatif = NIL(char); + + if ( *p == 'W') + break; + } + /*FALLTHRU*/ + + case 'n': + Trace = TRUE; + break; + + case 'k': Continue = TRUE; break; + case 'c': Comment = TRUE; break; + case 'p': Listing = TRUE; break; + case 'r': Rules = FALSE; break; + case 't': Touch = TRUE; break; + case 'q': Check = TRUE; break; + case 'u': Force = TRUE; break; + case 'x': m_export = TRUE; break; + case 'X': No_exec = TRUE; break; + case 'T': Transitive = FALSE; break; + case 'e': Get_env = 'e'; break; + case 'E': Get_env = 'E'; break; + + case 'V': Version(); Quit(0); break; + case 'A': Def_macro("AUGMAKE", "y", M_EXPANDED); break; + case 'B': Def_macro(".NOTABS", "y", M_EXPANDED); break; + case 'i': Def_macro(".IGNORE", "y", M_EXPANDED); break; + case 's': Def_macro(".SILENT", "y", M_EXPANDED); break; + case 'S': Def_macro(".SEQUENTIAL", "y", M_EXPANDED); break; + case 'g': Def_macro(".IGNOREGROUP","y", M_EXPANDED); break; + case 'd': Def_macro(".DIRCACHE",NIL(char),M_EXPANDED); break; + + case 'v': + if( p[-1] != '-' ) Usage(TRUE); + while( p[1] ) switch( *++p ) { + case 'c': Verbose |= V_DIR_CACHE; break; + case 'd': Verbose |= V_DIR_SET; break; + case 'f': Verbose |= V_FILE_IO; break; + case 'i': Verbose |= V_INFER; break; + case 'm': Verbose |= V_MAKE; break; + case 'r': Verbose |= V_FORCEECHO; break; + case 't': Verbose |= V_LEAVE_TMP; break; + case 'w': Verbose |= V_WARNALL; break; + + default: Usage(TRUE); break; + } + if( !Verbose ) Verbose = V_ALL; + if( Verbose & V_FORCEECHO ) { + HASHPTR hp; + /* This cleans the .SILENT setting */ + hp = Def_macro(".SILENT", "", M_EXPANDED); + /* This overrides the bitmask for further occurences of + * .SILENT to "no bits allowed", see bit variables in the + * set_macro_value() definition in dag.c. + * The bitmask is already set by Create_macro_vars() in + * imacs.c and is overridden for the V_FORCEECHO case. */ + hp->MV_MASK = A_DEFAULT; + } + break; + + case 'm': + if( p[-1] != '-' ) Usage(TRUE); + while( p[1] ) switch( *++p ) { + case 't': Measure |= M_TARGET; break; + case 'r': Measure |= M_RECIPE; break; + case 'a': Measure |= M_ABSPATH; break; + case 'e': Measure |= M_SHELLESC; break; + + default: Usage(TRUE); break; + } + if( !Measure ) Measure = M_TARGET; + break; + + case 'P': + if( p[1] ) { + /* Only set MAXPROCESS if -S flag is *not* used. */ + if( !(Glob_attr & A_SEQ) ) { + Def_macro( "MAXPROCESS", p+1, M_MULTI|M_EXPANDED ); + } + p += strlen(p)-1; + } + else + Fatal( "Missing number for -P flag" ); + break; + +#ifdef DBUG + case '#': + DB_PUSH(p+1); + p += strlen(p)-1; + break; +#endif + + case 'h': Usage(FALSE); break; + case 0: break; /* lone - */ + default: Usage(TRUE); break; + } + } + else if( (q = strchr(p, '=')) != NIL(char) ) { + cmdmacs = DmStrAdd( cmdmacs, DmStrDup2(p), TRUE ); + /* Macros defined on the command line are marked precious. + * FIXME: The exception for += appears to be bogus. */ + Parse_macro( p, (q[-1]!='+')?M_PRECIOUS:M_DEFAULT ); + } + else { + /* Remember the targets from the command line. */ + register STRINGPTR nsp; + + targets = DmStrAdd( targets, DmStrDup(p), TRUE ); + + TALLOC(nsp, 1, STRING); + nsp->st_string = DmStrDup( p ); + nsp->st_next = NIL(STRING); + + if(cltarget != NIL(STRING) ) + cltarget->st_next = nsp; + else + cltarget_first = nsp; + + cltarget = nsp; + } + } + + Def_macro( "MAKEMACROS", cmdmacs, M_PRECIOUS|M_NOEXPORT ); + Def_macro( "MAKETARGETS", targets, M_PRECIOUS|M_NOEXPORT ); + if( cmdmacs != NIL(char) ) FREE(cmdmacs); + if( targets != NIL(char) ) FREE(targets); + + Def_macro( "MFLAGS", Buffer, M_PRECIOUS|M_NOEXPORT ); + Def_macro( "%", "$@", M_PRECIOUS|M_NOEXPORT ); + + if( *Buffer ) Def_macro( "MAKEFLAGS", Buffer+1, M_PRECIOUS|M_NOEXPORT ); + + _warn = FALSE; /* disable warnings for builtin rules */ + Target = TRUE; /* make sure we don't mark any of the default rules as + * potential targets. */ + Make_rules(); /* Parse the strings stored in Rule_tab. */ + _warn = TRUE; + + /* If -r was not given find and parse startup-makefile. */ + if( Rules ) { + char *fname; + + /* Search_file() also checks the environment variable. */ + if( (mkfil=Search_file("MAKESTARTUP", &fname)) != NIL(FILE) ) { + Parse(mkfil); + Def_macro( "MAKESTARTUP", fname, M_EXPANDED|M_MULTI|M_FORCE ); + } + else + Fatal( "Configuration file `%s' not found", fname ); + } + + /* Define the targets set on the command line now. */ + Target = FALSE; /* Will be set to TRUE when the default targets are set. */ + for( cltarget = cltarget_first; cltarget != NIL(STRING); ) { + CELLPTR cp; + STRINGPTR nta = cltarget->st_next; + + Add_prerequisite(Targets, cp = Def_cell(cltarget->st_string), + FALSE, FALSE); + cp->ce_flag |= F_TARGET; + cp->ce_attr |= A_FRINGE; + Target = TRUE; + + FREE(cltarget->st_string); + FREE(cltarget); + cltarget = nta; + } + + if( Get_env == 'E' ) _do_ReadEnvironment(); + + /* Search for and parse user makefile. */ + if( fil_name != NIL(char) ) + mkfil = Openfile( fil_name, FALSE, TRUE ); + else { + /* Search .MAKEFILES dependent list looking for a makefile. + */ + register CELLPTR cp; + + cp = Def_cell( ".MAKEFILES" ); + mkfil = TryFiles(cp->CE_PRQ); + } + + if( mkfil != NIL(FILE) ) { + char *f = Filename(); + char *p; + + if( strcmp(f, "stdin") == 0 ) f = "-"; + p = DmStrAdd( "-f", f, FALSE ); + Def_macro( "MAKEFILE", p, M_PRECIOUS|M_NOEXPORT ); + Parse( mkfil ); + } + else if( !Rules ) + Fatal( "No `makefile' present" ); + + if( Nest_level ) Fatal( "Missing .END for .IF" ); + if( Get_env == 'e' ) _do_ReadEnvironment(); + + _do_VPATH(); /* kludge it up with .SOURCE */ + + if( Listing ) Dump(); /* print out the structures */ + if( Trace ) Glob_attr &= ~A_SILENT; /* make sure we see the trace */ + + if( !Target ) + Fatal( "No target" ); + else { + Test_circle( Root, TRUE ); + Check_circle_dfa(); + } + + if( m_export ) { + int i; + + for( i=0; i<HASH_TABLE_SIZE; ++i ) { + HASHPTR hp = Macs[i]; + + while( hp ) { + if( !(hp->ht_flag & M_NOEXPORT) && hp->ht_value != NIL(char) ) + if( Write_env_string(hp->ht_name, hp->ht_value) != 0 ) + Warning( "Could not export %s", hp->ht_name ); + hp = hp->ht_next; + } + } + } + + if( Buffer != NIL(char) ) {FREE( Buffer ); Buffer = NIL(char);} + if( Trace ) Def_macro(".SEQUENTIAL", "y", M_EXPANDED); + + ex_val = Make_targets(); + + Clear_signals(); + + /* Close fd for for @@-recipe silencing. */ + if( close(zerofd) ) + Fatal( "Error closing %s !", NULLDEV ); + Epilog(ex_val); /* Does not return -- EVER */ + return 0; +} + + +static void +_do_f_flag( flag, name, fname ) +char flag; +char *name; +char **fname; +{ + if( *fname == NIL(char) ) { + if( name != NIL(char) ) { + *fname = name; + } else + Fatal("No file name for -%c", flag); + } else + Fatal("Only one `-%c file' allowed", flag); +} + + +static void +_do_ReadEnvironment() +{ + t_attr saveattr = Glob_attr; + + Glob_attr |= A_SILENT; + ReadEnvironment(); + Glob_attr = saveattr; +} + + +static void +_do_VPATH() +{ + HASHPTR hp; + char *_rl[2]; + extern char **Rule_tab; + + hp = GET_MACRO("VPATH"); + if( hp == NIL(HASH) ) return; + + _rl[0] = ".SOURCE :^ $(VPATH:s/:/ /)"; + _rl[1] = NIL(char); + + Rule_tab = _rl; + Parse( NIL(FILE) ); +} + + +/* The file table and pointer to the next FREE slot for use by both + Openfile and Closefile. Each open stacks the new file onto the open + file stack, and a corresponding close will close the passed file, and + return the next file on the stack. The maximum number of nested + include files is limited by the value of MAX_INC_DEPTH */ + +static struct { + FILE *file; /* file pointer */ + char *name; /* name of file */ + int numb; /* line number */ +} ftab[ MAX_INC_DEPTH ]; + +static int next_file_slot = 0; + +/* Set the proper macro value to reflect the depth of the .INCLUDE directives + * and the name of the file we are reading. + */ +static void +_set_inc_depth() +{ + char buf[10]; + sprintf( buf, "%d", next_file_slot ); + Def_macro( "INCDEPTH", buf, M_MULTI|M_NOEXPORT ); + Def_macro( "INCFILENAME", + next_file_slot ? ftab[next_file_slot-1].name : "", + M_MULTI|M_NOEXPORT|M_EXPANDED ); +} + + +PUBLIC FILE * +Openfile(name, mode, err)/* +=========================== + This routine opens a file for input or output depending on mode. + If the file name is `-' then it returns standard input. + The file is pushed onto the open file stack. */ +char *name; +int mode; +int err; +{ + FILE *fil; + + DB_ENTER("Openfile"); + + if( name == NIL(char) || !*name ) { + if( !err ) + DB_RETURN(NIL(FILE)); + else + Fatal( "Openfile: NIL filename" ); + } + + if( next_file_slot == MAX_INC_DEPTH ) + Fatal( "Too many open files. Max nesting level is %d.", MAX_INC_DEPTH); + + DB_PRINT( "io", ("Opening file [%s], in slot %d", name, next_file_slot) ); + + if( strcmp("-", name) == 0 ) { + name = "stdin"; + fil = stdin; + } + else + fil = fopen( name, mode ? "w":"r" ); + + if( Verbose & V_FILE_IO ) + printf( "%s: Openning [%s] for %s", Pname, name, mode?"write":"read" ); + + if( fil == NIL(FILE) ) { + if( Verbose & V_FILE_IO ) printf( " (fail)\n" ); + if( err ) + Fatal( mode ? "Cannot open file %s for write" : "File %s not found", + name ); + } + else { + if( Verbose & V_FILE_IO ) printf( " (success)\n" ); + ftab[next_file_slot].file = fil; + ftab[next_file_slot].numb = Line_number; + ftab[next_file_slot++].name = DmStrDup(name); + Line_number = 0; + _set_inc_depth(); + } + + DB_RETURN(fil); +} + + +PUBLIC FILE * +Closefile()/* +============= + This routine is used to close the last file opened. This forces make + to open files in a last open first close fashion. It returns the + file pointer to the next file on the stack, and NULL if the stack is empty.*/ +{ + DB_ENTER("Closefile"); + + if( !next_file_slot ) + DB_RETURN( NIL(FILE) ); + + if( ftab[--next_file_slot].file != stdin ) { + DB_PRINT( "io", ("Closing file in slot %d", next_file_slot) ); + + if( Verbose & V_FILE_IO ) + printf( "%s: Closing [%s]\n", Pname, ftab[next_file_slot].name ); + + fclose( ftab[next_file_slot].file ); + FREE( ftab[next_file_slot].name ); + } + + _set_inc_depth(); + + if( next_file_slot > 0 ) { + Line_number = ftab[next_file_slot].numb; + DB_RETURN( ftab[next_file_slot-1].file ); + } + else + Line_number = 0; + + DB_RETURN( NIL(FILE) ); +} + + +PUBLIC FILE * +Search_file( macname, rname ) +char *macname; +char **rname; +{ + HASHPTR hp; + FILE *fil = NIL(FILE); + char *fname = NIL(char); + char *ename = NIL(char); + + /* order of precedence is: + * + * MACNAME from command line (precious is marked) + * ... via MACNAME:=filename definition. + * MACNAME from environment + * MACNAME from builtin rules (not precious) + */ + + if( (hp = GET_MACRO(macname)) != NIL(HASH) ) { + /* Only expand if needed. */ + if( hp->ht_flag & M_EXPANDED ) { + ename = fname = DmStrDup(hp->ht_value); + } else { + ename = fname = Expand(hp->ht_value); + } + + if( hp->ht_flag & M_PRECIOUS ) fil = Openfile(fname, FALSE, FALSE); + } + + if( fil == NIL(FILE) ) { + fname=Expand(Read_env_string(macname)); + if( (fil = Openfile(fname, FALSE, FALSE)) != NIL(FILE) ) FREE(ename); + } + + if( fil == NIL(FILE) && hp != NIL(HASH) ) + fil = Openfile(fname=ename, FALSE, FALSE); + + if( rname ) *rname = fname; + + return(fil); +} + + +PUBLIC char * +Filename()/* +============ + Return name of file on top of stack */ +{ + return( next_file_slot==0 ? NIL(char) : ftab[next_file_slot-1].name ); +} + + +PUBLIC int +Nestlevel()/* +============= + Return the file nesting level */ +{ + return( next_file_slot ); +} + + +PUBLIC FILE * +TryFiles(lp)/* +============== + Try to open a makefile, try to make it if needed and return a + filepointer to the first successful found or generated file. + The function returns NIL(FILE) if nothing was found. */ +LINKPTR lp; +{ + FILE *mkfil = NIL(FILE); + + if( lp != NIL(LINK) ) { + int s_n, s_t, s_q; + + s_n = Trace; + s_t = Touch; + s_q = Check; + + Trace = Touch = Check = FALSE; + /* We are making a makefile. Wait for it. */ + Makemkf = Wait_for_completion = TRUE; + mkfil = NIL(FILE); + + for(; lp != NIL(LINK) && mkfil == NIL(FILE); lp=lp->cl_next) { + if( lp->cl_prq->ce_attr & A_FRINGE ) continue; + + mkfil = Openfile( lp->cl_prq->CE_NAME, FALSE, FALSE ); + + /* Note that no error handling for failed Make() calls is possible + * as expected errors (no rule to make the makefile) or unexpected + * errors both return -1. */ + if( mkfil == NIL(FILE) && Make(lp->cl_prq, NIL(CELL)) != -1 ) { + mkfil = Openfile( lp->cl_prq->CE_NAME, FALSE, FALSE ); + /* Remove flags that indicate that the target was already made. + * This is also needed to avoid conflicts with the circular + * dependency check in rulparse(), see issues 62118 and 81296 + * for details. */ + Unmake(lp->cl_prq); + } + } + + Trace = s_n; + Touch = s_t; + Check = s_q; + Makemkf = Wait_for_completion = FALSE; + } + + return(mkfil); +} + + +/* +** print error message from variable arg list +*/ + +static int errflg = TRUE; +static int warnflg = FALSE; + +static void +errargs(fmt, args) +char *fmt; +va_list args; +{ + int warn = _warn && warnflg && !(Glob_attr & A_SILENT); + + if( errflg || warn ) { + char *f = Filename(); + + fprintf( stderr, "%s: ", Pname ); + if( f != NIL(char) ) fprintf(stderr, "%s: line %d: ", f, Line_number); + + if( errflg ) + fprintf(stderr, "Error: -- "); + else if( warn ) + fprintf(stderr, "Warning: -- "); + + vfprintf( stderr, fmt, args ); + putc( '\n', stderr ); + if( errflg && !Continue ) Quit(0); + } +} + + +/* +** Print error message and abort +*/ +PUBLIC void +#ifndef __MWERKS__ +Fatal(ARG(char *,fmt), ARG(va_alist_type,va_alist)) +#else +Fatal(char * fmt, ...) +#endif +DARG(char *,fmt) +DARG(va_alist_type,va_alist) +{ + va_list args; + + va_start(args, fmt); + Continue = FALSE; + errargs(fmt, args); + va_end(args); +} + +/* +** error message and exit (unless -k) +*/ +PUBLIC void +#ifndef __MWERKS__ +Error(ARG(char *,fmt), ARG(va_alist_type,va_alist)) +#else +Error(char * fmt, ...) +#endif +DARG(char *,fmt) +DARG(va_alist_type,va_alist) +{ + va_list args; + + va_start(args, fmt); + errargs(fmt, args); + va_end(args); +} + + +/* +** non-fatal message +*/ +PUBLIC void +#ifndef __MWERKS__ +Warning(ARG(char *,fmt), ARG(va_alist_type,va_alist)) +#else +Warning(char * fmt , ...) +#endif +DARG(char *,fmt) +DARG(va_alist_type,va_alist) +{ + va_list args; + + va_start(args, fmt); + warnflg = TRUE; + errflg = FALSE; + errargs(fmt, args); + errflg = TRUE; + warnflg = FALSE; + va_end(args); +} + + +PUBLIC void +No_ram() +{ + Fatal( "No more memory" ); +} + + +PUBLIC void +Usage( eflag ) +int eflag; +{ + register char *p; + char *fill; + + fill = DmStrDup(Pname); + for(p=fill; *p; p++) *p=' '; + + if( eflag ) { + fprintf(stderr, USAGE, Pname); + fprintf(stderr, USAGE2, fill); + } + else { + printf(USAGE, Pname); + printf(USAGE2, fill); + puts(" -P# - set max number of child processes for parallel make"); + puts(" -f file - use file as the makefile"); +#ifdef MSDOS + puts(" -C [+]file - duplicate console output to file, ('+' => append)"); +#endif + puts(" -K file - use file as the .KEEP_STATE file"); + puts(" -w target - show what you would do if 'target' were out of date"); + puts(" -W target - rebuild pretending that 'target' is out of date"); + puts(" -v[cdfimrtw] - verbose, indicate what we are doing, (-v => -vcdfimrtw)"); + puts(" c => dump directory cache info only" ); + puts(" d => dump change of directory info only" ); + puts(" f => dump file open/close info only" ); + puts(" i => dump inference information only" ); + puts(" m => dump make of target information only" ); + puts(" r => Force output of recipe lines and warnings," ); + puts(" overrides -s" ); + puts(" t => keep temporary files when done" ); + puts(" w => issue non-essential warnings\n" ); + + puts(" -m[trae] - Measure timing information, (-m => -mt)"); + puts(" t => display the start and end time of each target" ); + puts(" r => display the start and end time of each recipe" ); + puts(" a => display the target as an absolute path" ); + puts(" e => display the timing of shell escape macros\n" ); + + puts("Options: (can be catenated, ie -irn == -i -r -n)"); + puts(" -A - enable AUGMAKE special target mapping"); + puts(" -B - enable the use of spaces instead of tabs to start recipes"); + puts(" -c - use non standard comment scanning"); + puts(" -d - do not use directory cache"); + puts(" -E - define environment strings as macros"); + puts(" -e - same as -E but done after parsing makefile"); + puts(" -g - disable the special meaning of [ ... ] for group recipes"); + puts(" -h - print out usage info"); + puts(" -i - ignore errors"); + puts(" -k - make independent targets, even if errors"); + puts(" -n - trace and print, do not execute commands"); + puts(" -p - print out a version of the makefile"); + puts(" -q - check if target is up to date. Does not do"); + puts(" anything. Returns 0 if up to date, 1 otherwise"); + puts(" -r - don't use internal rules"); + puts(" -s - do your work silently"); + puts(" -S - disable parallel (force sequential) make, overrides -P"); + puts(" -t - touch, update time stamps without executing commands"); + puts(" -T - do not apply transitive closure on inference rules"); + puts(" -u - force unconditional update of target"); + puts(" -V - print out version number"); + puts(" -x - export macro values to environment"); + puts(" -X - ignore #! lines at start of makefile"); + } + + Quit(0); +} + + +PUBLIC void +Version() +{ + extern char **Rule_tab; + char **p; + + printf("%s - Version %s (%s)\n", Pname, VERSION, BUILDINFO); + printf("%s\n\n", sccid); + + puts("Default Configuration:"); + for (p=Rule_tab; *p != NIL(char); p++) + printf("\t%s\n", *p); + + printf("\n"); + +#if defined(HAVE_SPAWN_H) || defined(__CYGWIN__) + /* Only systems that have spawn ar concerned whether spawn or fork/exec + * are used. */ +#if ENABLE_SPAWN + printf("Subprocesses are executed using: spawn.\n\n"); +#else + printf("Subprocesses are executed using: fork/exec.\n\n"); +#endif +#endif + + printf("Please read the NEWS file for the latest release notes.\n"); +} |