home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / proglang / dmake38a.arj / DMAKE.C < prev    next >
C/C++ Source or Header  |  1992-01-23  |  21KB  |  787 lines

  1. /* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/dmake.c,v 1.1 1992/01/24 03:26:58 dvadura Exp $
  2. -- SYNOPSIS -- The main program.
  3. -- 
  4. -- DESCRIPTION
  5. -- 
  6. --     dmake [-#dbug_string] [ options ]
  7. --             [ macro definitions ] [ target ... ]
  8. -- 
  9. --     This file contains the main command line parser for the
  10. --     make utility.  The valid flags recognized are as follows:
  11. -- 
  12. --     -f file         - use file as the makefile
  13. --    -C file        - duplicate console output to file (MSDOS only)
  14. --    -K file        - .KEEP_STATE file
  15. --     -#dbug_string   - dump out debugging info, see below
  16. --     -v{dfimt}    - verbose, print what we are doing, as we do it.
  17. -- 
  18. --      options: (can be catenated, ie -irn == -i -r -n)
  19. -- 
  20. --    -A        - enable AUGMAKE special target mapping
  21. --    -B        - enable non-use of TABS to start recipe lines
  22. --    -c        - use non-standard comment scanning
  23. --     -i              - ignore errors
  24. --     -n              - trace and print, do not execute commands
  25. --     -t              - touch, update dates without executing commands
  26. --     -T              - do not apply transitive closure on inference rules
  27. --     -r              - don't use internal rules
  28. --     -s              - do your work silently
  29. --    -S        - force Sequential make, overrides -P
  30. --     -q              - check if target is up to date.  Does not
  31. --               do anything.  Returns 0 if up to date, -1
  32. --               otherwise.
  33. --     -p              - print out a version of the makefile
  34. --    -P#        - set value of MAXPROCESS
  35. --     -E              - define environment strings as macros
  36. --     -e              - as -E but done after parsing makefile
  37. --     -u              - force unconditional update of target
  38. --     -k              - make all independent targets even if errors
  39. --     -V              - print out this make version number
  40. --     -M        - Microsoft make compatibility, (* disabled *)
  41. --     -h              - print out usage info
  42. --     -x        - export macro defs to environment
  43. -- 
  44. --     NOTE:  - #ddbug_string is only availabe for versions of dmake that
  45. --         have been compiled with -DDBUG switch on.  Not the case for
  46. --         distributed versions.  Any such versions must be linked
  47. --         together with a version of Fred Fish's debug code.
  48. --              
  49. --     NOTE:  - in order to compile the code the include file stddef.h
  50. --         must be shipped with the bundled code.
  51. -- 
  52. -- AUTHOR
  53. --      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
  54. --      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
  55. --
  56. -- COPYRIGHT
  57. --      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
  58. -- 
  59. --      This program is free software; you can redistribute it and/or
  60. --      modify it under the terms of the GNU General Public License
  61. --      (version 1), as published by the Free Software Foundation, and
  62. --      found in the file 'LICENSE' included with this distribution.
  63. -- 
  64. --      This program is distributed in the hope that it will be useful,
  65. --      but WITHOUT ANY WARRANTY; without even the implied warrant of
  66. --      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  67. --      GNU General Public License for more details.
  68. -- 
  69. --      You should have received a copy of the GNU General Public License
  70. --      along with this program;  if not, write to the Free Software
  71. --      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  72. --
  73. -- LOG
  74. --     $Log: dmake.c,v $
  75.  * Revision 1.1  1992/01/24  03:26:58  dvadura
  76.  * dmake Version 3.8, Initial revision
  77.  *
  78. */
  79.  
  80. /* Set this flag to one, and the global variables in vextern.h will not
  81.  * be defined as 'extern', instead they will be defined as global vars
  82.  * when this module is compiled. */
  83. #define _DEFINE_GLOBALS_ 1
  84.  
  85. #include "extern.h"
  86. #include "patchlvl.h"
  87. #include "version.h"
  88.  
  89. #ifndef MSDOS
  90. #define USAGE \
  91. "Usage:\n%s [-ABceEhiknpqrsStTuVx] [-v{dfimt}] [-P#] [-{f|K} file] [macro[*][+][:]=value ...] [target ...]\n"
  92. #else
  93. #define USAGE \
  94. "Usage:\n%s [-ABceEhiknpqrsStTuVx] [-v{dfimt}] [-P#] [-{f|C|K} file] [macro[*][+][:]=value ...] [target ...]\n"
  95. #endif
  96.  
  97. #if __STDC__ == 1
  98. void Fatal(char *fmt, ...);
  99. void Warning(char *fmt, ...);
  100. #endif
  101.  
  102. static char *sccid = "Copyright (c) 1990,1991 by Dennis Vadura";
  103. static char _warn  = TRUE;        /* warnings on by default */
  104.  
  105. static    void    _do_VPATH();
  106. static    void    _do_ReadEnvironment();
  107. static  void    _do_f_flag ANSI((char, char *, char **));
  108.  
  109. PUBLIC int
  110. main(argc, argv)
  111. int  argc;
  112. char **argv;
  113. {
  114. #ifdef MSDOS
  115.    char*   std_fil_name = NIL(char);
  116. #endif
  117.  
  118.    char*   fil_name = NIL(char);
  119.    char*   state_name = NIL(char);
  120.    char*   cmdmacs;
  121.    char*   targets;
  122.    FILE*   mkfil;
  123.    int     ex_val;
  124.    int     m_export;
  125.  
  126.    DB_ENTER("main");
  127.  
  128.    /* Initialize Global variables to their default values       */
  129.    Prolog(argc, argv);
  130.    Create_macro_vars();
  131.    Catch_signals(Quit);
  132.  
  133.    Def_macro( "MAKECMD", Pname, M_PRECIOUS|M_NOEXPORT );
  134.    Pname = basename(Pname);
  135.  
  136.    DB_PROCESS(Pname);
  137.    (void) setvbuf(stdout, NULL, _IOLBF, BUFSIZ); /* stdout line buffered */
  138.  
  139.    Continue  = FALSE;
  140.    Comment   = FALSE;
  141.    Get_env   = FALSE;
  142.    Force     = FALSE;
  143.    Target    = FALSE;
  144.    If_expand = FALSE;
  145.    Listing   = FALSE;
  146.    Readenv   = FALSE;
  147.    Rules     = TRUE;
  148.    Trace     = FALSE;
  149.    Touch     = FALSE;
  150.    Check     = FALSE;
  151.    Microsoft = FALSE;
  152.    Makemkf   = FALSE;
  153.    m_export  = FALSE;
  154.    cmdmacs   = NIL(char);
  155.    targets   = NIL(char);
  156.  
  157.    Verbose     = V_NONE;
  158.    Transitive  = TRUE;
  159.    Nest_level  = 0;
  160.    Line_number = 0;
  161.    Suppress_temp_file = FALSE;
  162.  
  163.    while( --argc > 0 ) {
  164.       register char *p;
  165.       char *q;
  166.  
  167.       if( *(p = *++argv) == '-' ) {
  168.          if( p[1] == '\0' ) Fatal("Missing option letter");
  169.  
  170.          /* copy options to Buffer for $(MFLAGS), strip 'f' and 'C'*/
  171.          q = strchr(Buffer, '\0');
  172.          while (*p != '\0') {
  173.         char c = (*q++ = *p++);
  174.             if( c == 'f' || c == 'C' ) q--;
  175.      }
  176.  
  177.      if( *(q-1) == '-' )
  178.         q--;
  179.      else
  180.             *q++ = ' ';
  181.  
  182.      *q = '\0';
  183.  
  184.          for( p = *argv+1; *p; p++) switch (*p) {
  185.         case 'f':
  186.            _do_f_flag( 'f', *++argv, &fil_name ); argc--;
  187.            break;
  188.  
  189. #if defined(MSDOS) && !defined(OS2)
  190.         case 'C':
  191.            _do_f_flag( 'C', *++argv, &std_fil_name ); argc--;
  192.            Hook_std_writes( std_fil_name );
  193.            break;
  194. #endif
  195.  
  196.         case 'K':
  197.            _do_f_flag( 'K', *++argv, &state_name ); argc--;
  198.            Def_macro(".KEEP_STATE", state_name, M_EXPANDED|M_PRECIOUS);
  199.            break;
  200.  
  201.         case 'k': Continue   = TRUE;  break;
  202.         case 'c': Comment    = TRUE;  break;
  203.         case 'p': Listing    = TRUE;  break;
  204.         case 'r': Rules      = FALSE; break;
  205.         case 'n': Trace      = TRUE;  break;
  206.         case 't': Touch      = TRUE;  break;
  207.         case 'q': Check      = TRUE;  break;
  208.         case 'u': Force      = TRUE;  break;
  209.         case 'x': m_export   = TRUE;  break;
  210.         case 'T': Transitive = FALSE; break;
  211.         case 'e': Get_env    = 'e';   break;
  212.         case 'E': Get_env    = 'E';   break;
  213.  
  214.         case 'V': Version();  Quit(NIL(CELL));  break;
  215.         case 'A': Def_macro("AUGMAKE", "y", M_EXPANDED); break;
  216.         case 'B': Def_macro(".NOTABS", "y", M_EXPANDED); break;
  217.         case 'i': Def_macro(".IGNORE", "y", M_EXPANDED); break;
  218.         case 's': Def_macro(".SILENT", "y", M_EXPANDED); break;
  219.         case 'S': Def_macro(".SEQUENTIAL", "y", M_EXPANDED); break;
  220.  
  221.         case 'v':
  222.            if( p[-1] != '-' ) Usage(TRUE);
  223.            while( p[1] ) switch( *++p ) {
  224.           case 'd': Verbose |= V_PRINT_DIR; break;
  225.           case 'f': Verbose |= V_FILE_IO;   break;
  226.           case 'i': Verbose |= V_INFER;     break;
  227.           case 'm': Verbose |= V_MAKE;      break;
  228.           case 't': Verbose |= V_LEAVE_TMP; break;
  229.  
  230.           default: Usage(TRUE); break;
  231.            }
  232.            if( !Verbose ) Verbose = V_ALL;
  233.            break;
  234.  
  235.         case 'P':
  236.            if( p[1] ) {
  237.           Def_macro( "MAXPROCESS", p+1, M_MULTI|M_EXPANDED );
  238.           p += strlen(p)-1;
  239.            }
  240.            else
  241.           Fatal( "Missing number for -P flag" );
  242.            break;
  243.  
  244. #ifdef DBUG
  245.         case '#':
  246.            DB_PUSH(p+1);
  247.            p += strlen(p)-1;
  248.            break;
  249. #endif
  250.  
  251.         case 'h': Usage(FALSE); break;
  252.         case 0:   break;    /* lone - */
  253.         default:  Usage(TRUE);  break;
  254.      }
  255.       }
  256.       else if( (q = strchr(p, '=')) != NIL(char) ) {
  257.      cmdmacs = _stradd( cmdmacs, _strdup2(p), TRUE );
  258.      Parse_macro( p, (q[-1]!='+')?M_PRECIOUS:M_DEFAULT );
  259.       }
  260.       else {
  261.      register CELLPTR cp;
  262.      targets = _stradd( targets, _strdup(p), TRUE );
  263.      Add_prerequisite(Root, cp = Def_cell(p), FALSE, FALSE);
  264.      cp->ce_flag |= F_TARGET;
  265.      cp->ce_attr |= A_FRINGE;
  266.      Target = TRUE;
  267.       }
  268.    }
  269.  
  270.    Def_macro( "MAKEMACROS",  cmdmacs, M_PRECIOUS|M_NOEXPORT );
  271.    Def_macro( "MAKETARGETS", targets, M_PRECIOUS|M_NOEXPORT );
  272.    if( cmdmacs != NIL(char) ) FREE(cmdmacs);
  273.    if( targets != NIL(char) ) FREE(targets);
  274.  
  275.    Def_macro( "MFLAGS", Buffer, M_PRECIOUS|M_NOEXPORT );
  276.    Def_macro( "%", "$@", M_PRECIOUS|M_NOEXPORT );
  277.  
  278.    if( *Buffer ) Def_macro( "MAKEFLAGS", Buffer+1, M_PRECIOUS|M_NOEXPORT );
  279.  
  280.    _warn  = FALSE;      /* disable warnings for builtin rules */
  281.    ex_val = Target;     /* make sure we don't mark any        */
  282.    Target = TRUE;       /* of the default rules as            */
  283.    Make_rules();        /* potential targets                  */
  284.    _warn = TRUE;
  285.  
  286.    if( Rules ) {
  287.       char *fname;
  288.  
  289.       if( (mkfil=Search_file("MAKESTARTUP", &fname)) != NIL(FILE) ) {
  290.          Parse(mkfil);
  291.      Def_macro( "MAKESTARTUP", fname, M_EXPANDED|M_MULTI );
  292.          mkfil = NIL(FILE);
  293.       }
  294.       else
  295.          Fatal( "Configuration file `%s' not found", fname );
  296.    }
  297.  
  298.    Target = ex_val;
  299.  
  300.    if( Get_env == 'E' ) _do_ReadEnvironment();
  301.  
  302.    if( fil_name != NIL(char) )
  303.       mkfil = Openfile( fil_name, FALSE, TRUE );
  304.    else {
  305.       /* Search .MAKEFILES dependent list looking for a makefile.
  306.        */
  307.       register CELLPTR cp;
  308.       register LINKPTR lp;
  309.  
  310.       cp = Def_cell( ".MAKEFILES" );
  311.  
  312.       if( (lp = cp->CE_PRQ) != NIL(LINK) ) {
  313.          int s_n, s_t, s_q;
  314.  
  315.          s_n = Trace;
  316.          s_t = Touch;
  317.          s_q = Check;
  318.  
  319.          Trace = Touch = Check = FALSE;
  320.          Makemkf = Wait_for_completion = TRUE;
  321.          mkfil = NIL(FILE);
  322.  
  323.          for(;  lp != NIL(LINK) && mkfil == NIL(FILE); lp=lp->cl_next) {
  324.         if( lp->cl_prq->ce_attr & A_FRINGE ) continue;
  325.  
  326.             mkfil = Openfile( lp->cl_prq->CE_NAME, FALSE, FALSE );
  327.  
  328.             if( mkfil == NIL(FILE) &&
  329.         Make(lp->cl_prq, NIL(CELL)) != -1 )
  330.                mkfil = Openfile( lp->cl_prq->CE_NAME, FALSE, FALSE );
  331.          }
  332.  
  333.          Trace = s_n;
  334.          Touch = s_t;
  335.          Check = s_q;
  336.          Makemkf = Wait_for_completion = FALSE;
  337.       }
  338.    }
  339.  
  340.    if( mkfil != NIL(FILE) ) {
  341.       char *f = Filename();
  342.       char *p;
  343.  
  344.       if( strcmp(f, "stdin") == 0 ) f = "-";
  345.       p = _stradd( "-f", f, FALSE );
  346.       Def_macro( "MAKEFILE", p, M_PRECIOUS|M_NOEXPORT );
  347.       Parse( mkfil );
  348.    }
  349.    else if( !Rules )
  350.       Fatal( "No `makefile' present" );
  351.  
  352.    if( Nest_level     ) Fatal( "Missing .END for .IF" );
  353.    if( Get_env == 'e' ) _do_ReadEnvironment();
  354.  
  355.    _do_VPATH();                  /* kludge it up with .SOURCE    */
  356.  
  357.    if( Listing ) Dump();        /* print out the structures     */
  358.    if( Trace ) Glob_attr &= ~A_SILENT;    /* make sure we see the trace   */
  359.  
  360.    if( !Target )
  361.       Fatal( "No target" );
  362.    else {
  363.       Test_circle( Root, TRUE );
  364.       Check_circle_dfa();
  365.    }
  366.  
  367.    Push_dir( Start_dir, ".SETDIR", (int)(Glob_attr & A_IGNORE ));
  368.  
  369.    if( m_export ) {
  370.       int i;
  371.  
  372.       for( i=0; i<HASH_TABLE_SIZE; ++i ) {
  373.      HASHPTR hp = Macs[i];
  374.  
  375.      while( hp ) {
  376.         if( !(hp->ht_flag & M_NOEXPORT) && hp->ht_value != NIL(char) )
  377.            if( Write_env_string(hp->ht_name, hp->ht_value) != 0 )
  378.            Warning( "Could not export %s", hp->ht_name );
  379.         hp = hp->ht_next;
  380.      }
  381.       }
  382.    }
  383.  
  384.    if( Buffer != NIL(char) ) {FREE( Buffer ); Buffer = NIL(char);}
  385.    if( Trace ) Def_macro(".SEQUENTIAL", "y", M_EXPANDED);
  386.    if( Glob_attr & A_SEQ ) Def_macro( "MAXPROCESS", "1", M_EXPANDED|M_FORCE );
  387.  
  388.    ex_val = Make_targets();
  389.  
  390.    Pop_dir( (Glob_attr & A_IGNORE) != 0 );
  391.    Clear_signals();
  392.    Epilog(ex_val);      /* Does not return -- EVER */
  393. }
  394.  
  395.  
  396. static void
  397. _do_f_flag( flag, name, fname )
  398. char  flag;
  399. char *name;
  400. char **fname;
  401. {
  402.    if( *fname == NIL(char) ) {
  403.       if( name != NIL(char) ) {
  404.      *fname = name;
  405.       } else
  406.      Fatal("No file name for -%c", flag);
  407.    } else
  408.       Fatal("Only one `-%c file' allowed", flag);
  409. }
  410.  
  411.  
  412. static void
  413. _do_ReadEnvironment()
  414. {
  415.    t_attr saveattr = Glob_attr;
  416.  
  417.    Glob_attr |= A_SILENT;
  418.    ReadEnvironment();
  419.    Glob_attr = saveattr;
  420. }
  421.  
  422.  
  423. static void
  424. _do_VPATH()
  425. {
  426.    HASHPTR hp;
  427.    char    *_rl[2];
  428.    extern char **Rule_tab;
  429.  
  430.    hp = GET_MACRO("VPATH");
  431.    if( hp == NIL(HASH) ) return;
  432.  
  433.    _rl[0] = ".SOURCE :^ $(VPATH:s/:/ /)";
  434.    _rl[1] = NIL(char);
  435.  
  436.    Rule_tab = _rl;
  437.    Parse( NIL(FILE) );
  438. }
  439.  
  440.  
  441. /*  The file table and pointer to the next FREE slot for use by both
  442.     Openfile and Closefile.  Each open stacks the new file onto the open
  443.     file stack, and a corresponding close will close the passed file, and
  444.     return the next file on the stack.  The maximum number of nested
  445.     include files is limited by the value of MAX_INC_DEPTH */
  446.  
  447. static struct {
  448.    FILE         *file;      /* file pointer                 */
  449.    char         *name;      /* name of file                 */
  450.    int          numb;       /* line number                  */
  451. } ftab[ MAX_INC_DEPTH ];
  452.  
  453. static int next_file_slot = 0;
  454.  
  455. /* Set the proper macro value to reflect the depth of the .INCLUDE directives.
  456.  */
  457. static void
  458. _set_inc_depth()
  459. {
  460.    char buf[10];
  461.    sprintf( buf, "%d", next_file_slot );
  462.    Def_macro( "INCDEPTH", buf, M_MULTI|M_NOEXPORT );
  463. }
  464.  
  465.  
  466. PUBLIC FILE *
  467. Openfile(name, mode, err)/*
  468. ===========================
  469.    This routine opens a file for input or output depending on mode.
  470.    If the file name is `-' then it returns standard input.
  471.    The file is pushed onto the open file stack.  */
  472. char *name;
  473. int  mode;
  474. int  err;
  475. {
  476.    FILE *fil;
  477.  
  478.    DB_ENTER("Openfile");
  479.  
  480.    if( name == NIL(char) || !*name )
  481.       if( !err )
  482.          DB_RETURN(NIL(FILE));
  483.       else
  484.          Fatal( "Openfile:  NIL filename" );
  485.    
  486.    if( next_file_slot == MAX_INC_DEPTH )
  487.       Fatal( "Too many open files. Max nesting level is %d.", MAX_INC_DEPTH);
  488.  
  489.    DB_PRINT( "io", ("Opening file [%s], in slot %d", name, next_file_slot) );
  490.  
  491.    if( strcmp("-", name) == 0 ) {
  492.       name = "stdin";
  493.       fil = stdin;
  494.    }
  495.    else
  496.       fil = fopen( name, mode ? "w":"r" );
  497.  
  498.    if( Verbose & V_FILE_IO )
  499.       printf( "%s:  Openning [%s] for %s", Pname, name, mode?"write":"read" );
  500.  
  501.    if( fil == NIL(FILE) ) {
  502.       if( Verbose & V_FILE_IO ) printf( " (fail)\n" );
  503.       if( err )
  504.          Fatal( mode ? "Cannot open file %s for write" : "File %s not found",
  505.         name );
  506.    }
  507.    else {
  508.       if( Verbose & V_FILE_IO ) printf( " (success)\n" );
  509.       ftab[next_file_slot].file   = fil;
  510.       ftab[next_file_slot].numb   = Line_number;
  511.       ftab[next_file_slot++].name = _strdup(name);
  512.       Line_number = 0;
  513.       _set_inc_depth();
  514.    }
  515.  
  516.    DB_RETURN(fil);
  517. }
  518.  
  519.  
  520. PUBLIC FILE *
  521. Closefile()/*
  522. =============
  523.    This routine is used to close the last file opened.  This forces make
  524.    to open files in a last open first close fashion.  It returns the
  525.    file pointer to the next file on the stack, and NULL if the stack is empty.*/
  526. {
  527.    DB_ENTER("Closefile");
  528.  
  529.    if( !next_file_slot )
  530.       DB_RETURN( NIL(FILE) );
  531.  
  532.    if( ftab[--next_file_slot].file != stdin ) {
  533.       DB_PRINT( "io", ("Closing file in slot %d", next_file_slot) );
  534.  
  535.       if( Verbose & V_FILE_IO )
  536.      printf( "%s:  Closing [%s]\n", Pname, ftab[next_file_slot].name );
  537.  
  538.       fclose( ftab[next_file_slot].file );
  539.       FREE( ftab[next_file_slot].name );
  540.    }
  541.  
  542.    _set_inc_depth();
  543.  
  544.    if( next_file_slot > 0 ) {
  545.       Line_number = ftab[next_file_slot].numb;
  546.       DB_RETURN( ftab[next_file_slot-1].file );
  547.    }
  548.    else
  549.       Line_number = 0;
  550.  
  551.    DB_RETURN( NIL(FILE) );
  552. }
  553.  
  554.  
  555. PUBLIC FILE *
  556. Search_file( macname, rname )
  557. char *macname;
  558. char **rname;
  559. {
  560.    HASHPTR hp;
  561.    FILE *fil = NIL(FILE);
  562.    char *fname;
  563.    char *ename = NIL(char);
  564.  
  565.    /* order of precedence is:
  566.     *
  567.     *   MACNAME  from command line (precious is marked)
  568.     *         ... via MACNAME:=filename definition.
  569.     *   MACNAME  from environment
  570.     *   MACNAME  from builtin rules (not precious)
  571.     */
  572.  
  573.    if( (hp = GET_MACRO(macname)) != NIL(HASH) )
  574.       ename = fname = Expand(hp->ht_value);
  575.  
  576.    if( hp->ht_flag & M_PRECIOUS ) fil = Openfile(fname, FALSE, FALSE);
  577.  
  578.    if( fil == NIL(FILE) ) {
  579.       fname=Expand(Read_env_string(macname));
  580.       if( fil = Openfile(fname, FALSE, FALSE) ) FREE(ename);
  581.    }
  582.  
  583.    if( fil == NIL(FILE) && hp != NIL(HASH) )
  584.       fil = Openfile(fname=ename, FALSE, FALSE);
  585.  
  586.    if( rname ) *rname = fname;
  587.  
  588.    return(fil);
  589. }
  590.  
  591.  
  592. PUBLIC char *
  593. Filename()/*
  594. ============
  595.    Return name of file on top of stack */
  596. {
  597.    return( next_file_slot==0 ? NIL(char) : ftab[next_file_slot-1].name );
  598. }
  599.  
  600.  
  601. PUBLIC int
  602. Nestlevel()/*
  603. =============
  604.    Return the file nesting level */
  605. {
  606.    return( next_file_slot );
  607. }
  608.  
  609.  
  610. /*
  611. ** print error message from variable arg list
  612. */
  613.  
  614. static int errflg = TRUE;
  615. static int warnflg = FALSE;
  616.  
  617. static void
  618. errargs(fmt, args)
  619. char    *fmt;
  620. va_list  args;
  621. {
  622.    int warn = _warn && warnflg && !(Glob_attr & A_SILENT);
  623.  
  624.    if( errflg || warn ) {
  625.       char *f = Filename();
  626.  
  627.       fprintf( stderr, "%s:  ", Pname );
  628.       if( f != NIL(char) ) fprintf(stderr, "%s:  line %d:  ", f, Line_number);
  629.  
  630.       if( errflg )
  631.          fprintf(stderr, "Error -- ");
  632.       else if( warn )
  633.          fprintf(stderr, "Warning -- ");
  634.  
  635.       vfprintf( stderr, fmt, args );
  636.       putc( '\n', stderr );
  637.       if( errflg && !Continue ) Quit( NIL(CELL) );
  638.    }
  639. }
  640.  
  641. /*
  642. ** Print error message and abort
  643. */
  644. #if __STDC__ == 1
  645. void
  646. Fatal(char *fmt, ...)
  647. #elif defined(_MPW)
  648. Fatal(char *fmt, va_alist)
  649. va_dcl
  650. #else
  651. int
  652. Fatal(fmt, va_alist)
  653. char *fmt;
  654. va_dcl;
  655. #endif
  656. {
  657.    va_list args;
  658.  
  659.    va_start(args, fmt);
  660.    Continue = FALSE;
  661.    errargs(fmt, args);
  662.    va_end(args);
  663. }
  664.  
  665. /*
  666. ** error message and exit (unless -k)
  667. */
  668. #if __STDC__ == 1
  669. void
  670. Error (char *fmt, ...)
  671. #elif defined(_MPW)
  672. Error(char *fmt, va_alist)
  673. va_dcl
  674. #else
  675. int
  676. Error(fmt, va_alist)
  677. char*   fmt;
  678. va_dcl;
  679. #endif
  680. {
  681.    va_list args;
  682.  
  683.    va_start(args, fmt);
  684.    errargs(fmt, args);
  685.    va_end(args);
  686. }
  687.  
  688.  
  689. /*
  690. ** non-fatal message
  691. */
  692. #if __STDC__ == 1
  693. void
  694. Warning(char *fmt, ...)
  695. #elif defined(_MPW)
  696. Error(char *fmt, va_alist)
  697. va_dcl
  698. #else
  699. int
  700. Warning(fmt, va_alist)
  701. char *fmt;
  702. va_dcl;
  703. #endif
  704. {
  705.    va_list args;
  706.  
  707.    va_start(args, fmt);
  708.    warnflg = TRUE;
  709.    errflg = FALSE;
  710.    errargs(fmt, args);
  711.    errflg = TRUE;
  712.    warnflg = FALSE;
  713.    va_end(args);
  714. }
  715.  
  716.  
  717. PUBLIC void
  718. No_ram()
  719. {
  720.    Fatal( "No more memory" );
  721. }
  722.  
  723.  
  724. PUBLIC
  725.  
  726. Usage( eflag )
  727. int eflag;
  728. {
  729.    if( eflag ) {
  730.       fprintf(stderr, USAGE, Pname);
  731.    }
  732.    else {
  733.    printf(USAGE, Pname);
  734.    puts("    -P#        - set max number of child processes for parallel make");
  735.    puts("    -f file    - use file as the makefile");
  736. #ifdef MSDOS
  737.    puts("    -C [+]file - duplicate console output to file, ('+' => append)");
  738. #endif
  739.    puts("    -K file    - use file as the .KEEP_STATE file");
  740.    puts("    -v{dfimt}  - verbose, indicate what we are doing, (-v => -vdimt)");
  741.    puts("                   d => dump change of directory info only" );
  742.    puts("                   f => dump file open/close info only" );
  743.    puts("                   i => dump inference information only" );
  744.    puts("                   m => dump make of target information only" );
  745.    puts("                   t => keep temporary files when done\n" );
  746.  
  747.    puts("Options: (can be catenated, ie -irn == -i -r -n)");
  748.    puts("    -A   - enable AUGMAKE special target mapping");
  749.    puts("    -B   - enable the use of spaces instead of tabs to start recipes");
  750.    puts("    -c   - use non standard comment scanning");
  751.    puts("    -E   - define environment strings as macros");
  752.    puts("    -e   - same as -E but done after parsing makefile");
  753.    puts("    -h   - print out usage info");
  754.    puts("    -i   - ignore errors");
  755.    puts("    -k   - make independent targets, even if errors");
  756.    puts("    -n   - trace and print, do not execute commands");
  757.    puts("    -p   - print out a version of the makefile");
  758.    puts("    -q   - check if target is up to date.  Does not do");
  759.    puts("           anything.  Returns 0 if up to date, 1 otherwise");
  760.    puts("    -r   - don't use internal rules");
  761.    puts("    -s   - do your work silently");
  762.    puts("    -S   - disable parallel (force sequential) make, overrides -P");
  763.    puts("    -t   - touch, update time stamps without executing commands");
  764.    puts("    -T   - do not apply transitive closure on inference rules");
  765.    puts("    -u   - force unconditional update of target");
  766.    puts("    -V   - print out version number");
  767.    puts("    -x   - export macro values to environment");
  768.    }
  769.  
  770.    Quit(NIL(CELL));
  771. }
  772.  
  773.  
  774. PUBLIC
  775. Version()
  776. {
  777.    extern char **Rule_tab;
  778.    char **p;
  779.    
  780.    printf("%s - %s, ", Pname, sccid);
  781.    printf("Version %s, PL %d\n\n", VERSION, PATCHLEVEL);
  782.  
  783.    puts("Default Configuration:");
  784.    for (p=Rule_tab;  *p != NIL(char);  p++)
  785.       printf("\t%s\n", *p);
  786. }
  787.