[comp.sources.misc] v15i074: dmake version 3.6

dvadura@watdragon.waterloo.edu (Dennis Vadura) (10/15/90)

Posting-number: Volume 15, Issue 74
Submitted-by: Dennis Vadura <dvadura@watdragon.waterloo.edu>
Archive-name: dmake-3.6/part22

#!/bin/sh
# this is part 22 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file dmake.h continued
#
CurArch=22
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
     exit 1; fi
( read Scheck
  if test "$Scheck" != $CurArch
  then echo "Please unpack part $Scheck next!"
       exit 1;
  else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file dmake.h"
sed 's/^X//' << 'SHAR_EOF' >> dmake.h
X#define ST_IMPORT	9
X
X/* Macro definitions for use inside dmake */
X#define SET_TOKEN(A, B)  (A)->tk_str = (B); (A)->tk_cchar = *(B);\
X			 (A)->tk_quote = 1;
X#define CLEAR_TOKEN(A)   *(A)->tk_str = (A)->tk_cchar
X#define GET_MACRO(A)	 Get_name(A, Macs, FALSE, NIL(CELL))
X#define iswhite(C)     ((C == ' ') || (C == '\t'))
X
X#endif
X
SHAR_EOF
echo "File dmake.h is complete"
chmod 0440 dmake.h || echo "restore of dmake.h fails"
echo "x - extracting dmake.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > dmake.c &&
X/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/dmake.c,v 1.1 90/10/06 12:03:35 dvadura Exp $
X-- SYNOPSIS -- The main program.
X-- 
X-- DESCRIPTION
X-- 
X-- 	dmake [-#dbug_string] [ options ]
X-- 			[ macro definitions ] [ target ... ]
X-- 
X-- 	This file contains the main command line parser for the
X-- 	make utility.  The valid flags recognized are as follows:
X-- 
X-- 	-f file         - use file as the makefile
X-- 	-#dbug_string   - dump out debugging info, see below
X-- 
X-- 	 options: (can be catenated, ie -irn == -i -r -n)
X-- 
X--	-A		- enable AUGMAKE special target mapping
X-- 	-i              - ignore errors
X-- 	-n              - trace and print, do not execute commands
X-- 	-t              - touch, update dates without executing commands
X-- 	-T              - do not apply transitive closure
X-- 	-r              - don't use internal rules
X-- 	-s              - do your work silently
X--	-S		- force Sequential make, overrides -P
X-- 	-q              - check if target is up to date.  Does not
X-- 			  do anything.  Returns 0 if up to date, -1
X-- 			  otherwise.
X-- 	-p              - print out a version of the makefile
X--	-P#		- set value of MAXPROCESS
X-- 	-e              - define environment strings as macros
X-- 	-E              - as -e but done after parsing makefile
X-- 	-u              - force unconditional update of target
X-- 	-k              - make all independent targets even if errors
X-- 	-V              - print out this make version number
X-- 	-v		- verbose, print what we are doing, as we do it.
X-- 	-M		- Microsoft make compatibility, (* disabled *)
X-- 	-h              - print out usage info
X-- 	-x		- export macro defs to environment
X-- 
X-- 	NOTE:  - #ddbug_string is only availabe for versions of dmake that
X-- 		have been compiled with -DDBUG switch on.  Not the case for
X-- 		distributed versions.  Any such versions must be linked
X-- 		together with a version of Fred Fish's debug code.
X-- 			 
X-- 	NOTE:  - in order to compile the code the include file stddef.h
X-- 		must be shipped with the bundled code.
X-- 
X-- AUTHOR
X--      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
X--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
X--
X-- COPYRIGHT
X--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
X-- 
X--      This program is free software; you can redistribute it and/or
X--      modify it under the terms of the GNU General Public License
X--      (version 1), as published by the Free Software Foundation, and
X--      found in the file 'LICENSE' included with this distribution.
X-- 
X--      This program is distributed in the hope that it will be useful,
X--      but WITHOUT ANY WARRANTY; without even the implied warrant of
X--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X--      GNU General Public License for more details.
X-- 
X--      You should have received a copy of the GNU General Public License
X--      along with this program;  if not, write to the Free Software
X--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X--
X-- LOG
X--     $Log:	dmake.c,v $
X * Revision 1.1  90/10/06  12:03:35  dvadura
X * dmake Release, Version 3.6
X * 
X*/
X
X/* Set this flag to one, and the global variables in vextern.h will not
X * be defined as 'extern', instead they will be defined as global vars
X * when this module is compiled. */
X#define _DEFINE_GLOBALS_ 1
X
X#include <ctype.h>
X#include <stdarg.h>
X#include "extern.h"
X#include "alloc.h"
X#include "db.h"
X#include "patchlvl.h"
X#include "version.h"
X
X#ifdef HELP
X#define USAGE \
X"Usage:\n%s [-AeEhiknpqrsStTuvVx] [-P#] [-f file] [macro[*][+][:]=value ...] [target ...]\n"
X#define COPYRIGHT "Copyright (c) 1990 by Dennis Vadura"
X#endif
X
Xstatic char *sccid = COPYRIGHT;
Xstatic char _warn  = TRUE;		/* warnings on by default */
X
Xstatic	void	_do_VPATH();
Xstatic	void	_do_ReadEnvironment();
X
Xmain(argc, argv)
Xint  argc;
Xchar **argv;
X{
X   char*   fil_name = NIL(char);
X   char*   cmdmacs;
X   char*   targets;
X   FILE*   mkfil;
X   int     ex_val;
X   int     m_export;
X   HASHPTR hp;
X
X   DB_ENTER("main");
X
X   /* Initialize Global variables to their default values       */
X   Prolog(argc, argv);
X   Create_macro_vars();
X   Catch_signals(Quit);
X
X   Def_macro( "MAKECMD", Pname, M_PRECIOUS|M_NOEXPORT );
X   Pname = basename(Pname);
X
X   DB_PROCESS(Pname);
X   (void) setvbuf(stdout, NULL, _IOLBF, BUFSIZ); /* stdout line buffered */
X
X   Continue  = FALSE;
X   Get_env   = FALSE;
X   Force     = FALSE;
X   Target    = FALSE;
X   If_expand = FALSE;
X   Listing   = FALSE;
X   Readenv   = FALSE;
X   Rules     = TRUE;
X   Trace     = FALSE;
X   Touch     = FALSE;
X   Check     = FALSE;
X   Microsoft = FALSE;
X   Verbose   = FALSE;
X   Makemkf   = FALSE;
X   m_export  = FALSE;
X   cmdmacs   = NIL(char);
X   targets   = NIL(char);
X
X   Transitive     = TRUE;
X   Nest_level     = 0;
X   Line_number    = 0;
X
X   while( --argc > 0 ) {
X      register char *p;
X      char *q;
X
X      if( *(p = *++argv) == '-' ) {
X         if( p[1] == '\0' ) Fatal("Missing option letter");
X
X         /* copy options to Buffer for $(MFLAGS), strip 'f' */
X         q = strchr(Buffer, 0);
X         while (*p != 0)
X            if( (*q++ = *p++) == 'f' ) q--;
X
X	 if( *(q-1) == '-' )
X	    q--;
X	 else
X            *q++ = ' ';
X
X	 *q = 0;
X
X         for( p = *argv+1; *p; p++) switch (*p) {
X	    case 'f':
X	       if( fil_name == NIL(char) ) {
X		  if( *++argv != NIL(char) ) {
X		     fil_name = *argv;
X		     argc--;
X		  } else
X		     Fatal("No file name for -f");
X	       } else
X		  Fatal("Only one `-f file' allowed");
X	       break;
X
X	    case 'k': Continue   = TRUE;  break;
X	    case 'p': Listing    = TRUE;  break;
X	    case 'r': Rules      = FALSE; break;
X	    case 'n': Trace      = TRUE;  break;
X	    case 't': Touch      = TRUE;  break;
X	    case 'q': Check      = TRUE;  break;
X	    case 'u': Force      = TRUE;  break;
X	    case 'v': Verbose    = TRUE;  break;
X	    case 'x': m_export   = TRUE;  break;
X	    case 'T': Transitive = FALSE; break;
X	    case 'e': Get_env    = 'e';   break;
X	    case 'E': Get_env    = 'E';   break;
X
X	    case 'V': Version();  Quit(NIL(CELL));  break;
X	    case 'A': Def_macro("AUGMAKE", "y", M_EXPANDED); break;
X	    case 'i': Def_macro(".IGNORE", "y", M_EXPANDED); break;
X	    case 's': Def_macro(".SILENT", "y", M_EXPANDED); break;
X	    case 'S': Def_macro(".SEQUENTIAL", "y", M_EXPANDED); break;
X
X	    case 'P':
X	       if( p[1] ) {
X		  Def_macro( "MAXPROCESS", p+1, M_MULTI|M_EXPANDED );
X		  p += strlen(p)-1;
X	       }
X	       else
X		  Fatal( "Missing number for -P flag" );
X	       break;
X
X#ifdef HELP
X	    case 'h': Usage();  Quit(NIL(CELL));  break;
X#endif
X#ifdef DBUG
X	    case '#':
X	       DB_PUSH(p+1);
X	       p += strlen(p)-1;
X	       break;
X#endif
X
X	    default:
X	       fprintf(stderr, USAGE, Pname);
X	       Quit(NIL(CELL));
X	       break;
X	 }
X      }
X      else if( (q = strchr(p, '=')) != NIL(char) ) {
X	 cmdmacs = _stradd( cmdmacs, _strdup(p), TRUE );
X	 Parse_macro( p, (strchr(p,'+')==NIL(char))?M_PRECIOUS:M_DEFAULT );
X      }
X      else {
X	 register CELLPTR cp;
X	 targets = _stradd( targets, _strdup(p), TRUE );
X	 Add_fringe(cp = Def_cell(p, NIL(CELL)));
X	 cp->ce_flag |= F_TARGET;
X	 Target = TRUE;
X      }
X   }
X
X   Def_macro( "MAKEMACROS",  cmdmacs, M_PRECIOUS|M_NOEXPORT );
X   Def_macro( "MAKETARGETS", targets, M_PRECIOUS|M_NOEXPORT );
X   if( cmdmacs != NIL(char) ) FREE(cmdmacs);
X   if( targets != NIL(char) ) FREE(targets);
X
X   Def_macro( "MFLAGS", Buffer, M_PRECIOUS|M_NOEXPORT );
X   Def_macro( "%", "$@", M_PRECIOUS|M_NOEXPORT );
X
X   if( *Buffer ) Def_macro( "MAKEFLAGS", Buffer+1, M_PRECIOUS|M_NOEXPORT );
X
X   _warn  = FALSE;      /* disable warnings for builtin rules */
X   ex_val = Target;     /* make sure we don't mark any        */
X   Target = TRUE;       /* of the default rules as            */
X   Make_rules();        /* potential targets                  */
X   _warn = TRUE;
X
X   if( Rules ) {
X      /* order of precedence is:
X       *
X       *   MAKESTARTUP  from command line (precious is marked)
X       *   MAKESTARTUP  from environment
X       *   MAKESTARTUP  from builtin rules (not precious)
X       */
X      char *fname;
X
X      if( ((hp = GET_MACRO("MAKESTARTUP")) != NIL(HASH)) &&
X	  (hp->ht_flag & M_PRECIOUS) &&
X	  (mkfil=Openfile(fname=hp->ht_value, FALSE)) != NIL(FILE) ||
X	  (mkfil=Openfile(fname=Read_env_string("MAKESTARTUP"), FALSE)) != NIL(FILE) ||
X	  hp != NIL(HASH) &&
X	  (mkfil=Openfile(fname=hp->ht_value, FALSE)) != NIL(FILE) )
X      {
X         Parse(mkfil);
X         mkfil = NIL(FILE);
X      }
X      else
X         Fatal( "configuration file `%s' not found", fname );
X   }
X
X   Target = ex_val;
X
X   if( Get_env == 'e' ) _do_ReadEnvironment();
X
X   if( fil_name != NIL(char) )
X      mkfil = Openfile( fil_name, TRUE );
X   else {
X      /* Search .MAKEFILES dependent list looking for a makefile.
X       */
X      register CELLPTR cp;
X      register LINKPTR lp;
X
X      cp = Def_cell( ".MAKEFILES", NIL(CELL) );
X
X      if( (lp = cp->CE_PRQ) != NIL(LINK) ) {
X         int s_n, s_t, s_q;
X
X         s_n = Trace;
X         s_t = Touch;
X         s_q = Check;
X
X         Trace = Touch = Check = FALSE;
X         Makemkf = Wait_for_completion = TRUE;
X         mkfil = NIL(FILE);
X
X         for(;  lp != NIL(LINK) && mkfil == NIL(FILE); lp=lp->cl_next) {
X            mkfil = Openfile( lp->cl_prq->CE_NAME, FALSE );
X
X            if( mkfil == NIL(FILE) &&
X		Make(lp->cl_prq, lp->cl_prq->CE_HOW, NIL(CELL)) != -1 )
X               mkfil = Openfile( lp->cl_prq->CE_NAME, FALSE );
X         }
X
X         Trace = s_n;
X         Touch = s_t;
X         Check = s_q;
X         Makemkf = Wait_for_completion = FALSE;
X      }
X   }
X
X   if( mkfil != NIL(FILE) ) {
X      char *f = Filename();
X      char *p;
X
X      if( strcmp(f, "stdin") == 0 ) f = "-";
X      p = _stradd( "-f", f, FALSE );
X      Def_macro( "MAKEFILE", p, M_PRECIOUS|M_NOEXPORT );
X      Parse( mkfil );
X   }
X   else if( !Rules )
X      Fatal( "No `makefile' present" );
X
X   if( Nest_level     ) Fatal( "Missing .END for .IF" );
X   if( Get_env == 'E' ) _do_ReadEnvironment();
X
X   _do_VPATH();      			/* kludge it up with .SOURCE    */
X
X   if( Listing ) Dump();		/* print out the structures     */
X   if( Trace ) Glob_attr &= ~A_SILENT;	/* make sure we see the trace   */
X
X   if( !Target )
X      Fatal( "No target" );
X   else {
X      Check_circle( Fringe_hd );
X      Check_circle_dfa();
X   }
X
X   TALLOC( Start_dir.ce_name, 1, HASH );
X   Start_dir.CE_NAME = ".SETDIR";
X   Push_dir( &Start_dir, Glob_attr & A_IGNORE );
X
X   if( m_export ) {
X      int i;
X
X      for( i=0; i<HASH_TABLE_SIZE; ++i ) {
X         char *tmpstr = hp->ht_value;
X
X         if( tmpstr == NIL(char) ) tmpstr = "";
X         if( !(hp->ht_flag & M_NOEXPORT) &&
X	     Write_env_string(hp->ht_name, tmpstr) != 0 )
X            Warning( "Could not export %s", hp->ht_name );
X      }
X   }
X 
X   if( Buffer != NIL(char) ) FREE( Buffer );
X   if( Trace ) Def_macro(".SEQUENTIAL", "y", M_EXPANDED);
X   if( Glob_attr & A_SEQ ) Def_macro( "MAXPROCESS", "1", M_EXPANDED|M_FORCE );
X
X   ex_val = Make_targets();
X
X   Pop_dir( (Glob_attr & A_IGNORE) != 0 );
X   Clear_signals();
X   Epilog(ex_val);      /* Does not return -- EVER */
X}
X
X
Xstatic void
X_do_ReadEnvironment()
X{
X   t_attr saveattr = Glob_attr;
X
X   Glob_attr |= A_SILENT;
X   ReadEnvironment();
X   Glob_attr = saveattr;
X}
X
X
Xstatic void
X_do_VPATH()
X{
X   HASHPTR hp;
X   char    *_rl[2];
X   extern char **Rule_tab;
X
X   hp = GET_MACRO("VPATH");
X   if( hp == NIL(HASH) ) return;
X
X   _rl[0] = ".SOURCE :^ $(VPATH:s/:/ /)";
X   _rl[1] = NIL(char);
X
X   Rule_tab = _rl;
X   Parse( NIL(FILE) );
X}
X
X
X/*  The file table and pointer to the next FREE slot for use by both
X    Openfile and Closefile.  Each open stacks the new file onto the open
X    file stack, and a corresponding close will close the passed file, and
X    return the next file on the stack.  The maximum number of nested
X    include files is limited by the value of MAX_INC_DEPTH */
X
Xstatic struct {
X   FILE         *file;  	/* file pointer                 */
X   char         *name;  	/* name of file                 */
X   int          numb;   	/* line number                  */
X} ftab[ MAX_INC_DEPTH ];
X
Xstatic int next_file_slot = 0;
X
X/* Set the proper macro value to reflect the depth of the .INCLUDE directives.
X */
Xstatic void
X_set_inc_depth()
X{
X   char buf[10];
X   sprintf( buf, "%d", next_file_slot-1 );
X   Def_macro( "INCDEPTH", buf, M_MULTI|M_NOEXPORT );
X}
X
X
XFILE *
XOpenfile(name, err)/*
X=====================
X   This routine opens a file for input.
X   If the file name is `-' then it returns standard input.
X   The file is pushed onto the open file stack.  */
Xchar *name;
Xint  err;
X{
X   FILE *fil;
X
X   DB_ENTER("Openfile");
X
X   if( name == NIL(char) || !*name )
X      if( !err )
X         DB_RETURN(NIL(FILE));
X      else
X         Fatal( "Openfile:  NIL filename" );
X   
X   if( next_file_slot == MAX_INC_DEPTH )
X      Fatal( "Too many open files. Max nesting level is %d.", MAX_INC_DEPTH);
X
X   DB_PRINT( "io", ("Opening file [%s], in slot %d", name, next_file_slot) );
X
X   if( strcmp("-", name) == 0 ) {
X      name = "stdin";
X      fil = stdin;
X   }
X   else
X      fil = fopen( name, "r" );
X
X   if( fil == NIL(FILE) ) {
X      if( err )
X         Fatal( "File %s not found", name );
X   }
X   else {
X      ftab[next_file_slot].file   = fil;
X      ftab[next_file_slot].numb   = Line_number;
X      ftab[next_file_slot++].name = _strdup(name);
X      Line_number = 0;
X      _set_inc_depth();
X   }
X
X   DB_RETURN(fil);
X}
X
XFILE *
XClosefile()/*
X=============
X   This routine is used to close the last file opened.  This forces make
X   to open files in a last open first close fashion.  It returns the
X   file pointer to the next file on the stack, and NULL if the stack is empty.*/
X{
X   DB_ENTER("Closefile");
X
X   if( !next_file_slot )
X      DB_RETURN( NIL(FILE) );
X
X   if( ftab[--next_file_slot].file != stdin ) {
X      DB_PRINT( "io", ("Closing file in slot %d", next_file_slot) );
X      fclose( ftab[next_file_slot].file );
X      FREE( ftab[next_file_slot].name );
X      _set_inc_depth();
X   }
X
X   if( next_file_slot > 0 ) {
X      Line_number = ftab[next_file_slot].numb;
X      DB_RETURN( ftab[next_file_slot-1].file );
X   }
X   else
X      Line_number = 0;
X
X   DB_RETURN( NIL(FILE) );
X}
X
X
Xchar *
XFilename()/*
X============
X   Return name of file on top of stack */
X{
X   return( next_file_slot==0 ? NIL(char) : ftab[next_file_slot-1].name );
X}
X
X/*
X** print error message from variable arg list
X*/
X
Xstatic int errflg = TRUE;
Xstatic int warnflg = FALSE;
X
Xstatic void
Xerrargs(fmt, args)
Xchar    *fmt;
Xva_list  args;
X{
X   int warn = _warn && warnflg && !(Glob_attr & A_SILENT);
X
X   if( errflg || warn ) {
X      char *f = Filename();
X
X      fprintf( stderr, "%s:  ", Pname );
X      if( f != NIL(char) ) fprintf(stderr, "%s:  line %d:  ", f, Line_number);
X
X      if( errflg )
X         fprintf(stderr, "Error -- ");
X      else if( warn )
X         fprintf(stderr, "Warning -- ");
X
X      vfprintf( stderr, fmt, args );
X      putc( '\n', stderr );
X      if( errflg && !Continue ) Quit( NIL(CELL) );
X   }
X}
X
X/*
X** Print error message and abort
X*/
Xint
XFatal(fmt, va_alist)
Xchar *fmt;
Xva_dcl;
X{
X   va_list args;
X
X   va_start(args, fmt);
X   Continue = FALSE;
X   errargs(fmt, args);
X   va_end(args);
X}
X
X/*
X** error message and exit (unless -k)
X*/
Xint
XError(fmt, va_alist)
Xchar*   fmt;
Xva_dcl;
X{
X   va_list args;
X
X   va_start(args, fmt);
X   errargs(fmt, args);
X   va_end(args);
X}
X
X
X/*
X** non-fatal message
X*/
Xint
XWarning(fmt, va_alist)
Xchar *fmt;
Xva_dcl;
X{
X   va_list args;
X
X   va_start(args, fmt);
X   warnflg = TRUE;
X   errflg = FALSE;
X   errargs(fmt, args);
X   errflg = TRUE;
X   warnflg = FALSE;
X   va_end(args);
X}
X
X
Xvoid
XNo_ram()
X{
X   Fatal( "No more memory" );
X}
X
X
X#ifdef HELP
XUsage()
X{
X   printf(USAGE, Pname);
X   puts("    -P#       - set max number of child processes for parallel make");
X   puts("    -f file   - use file as the makefile\n");
X
X   puts("Options: (can be catenated, ie -irn == -i -r -n)");
X   puts("    -A   - enable AUGMAKE special target mapping");
X   puts("    -e   - define environment strings as macros");
X   puts("    -E   - same as -e but done after parsing makefile");
X   puts("    -h   - print out usage info");
X   puts("    -i   - ignore errors");
X   puts("    -k   - make independent targets, even if errors");
X   puts("    -n   - trace and print, do not execute commands");
X   puts("    -p   - print out a version of the makefile");
X   puts("    -q   - check if target is up to date.  Does not do");
X   puts("           anything.  Returns 0 if up to date, 1 otherwise");
X   puts("    -r   - don't use internal rules");
X   puts("    -s   - do your work silently");
X   puts("    -S   - disable parallel (force sequential) make, overrides -P");
X   puts("    -t   - touch, update time stamps without executing commands");
X   puts("    -T   - do not apply transitive closure");
X   puts("    -u   - force unconditional update of target");
X   puts("    -v   - verbose, print out what we are doing");
X   puts("    -V   - print out version number");
X   puts("    -x   - export macro values to environment");
X}
X#endif
X
X
XVersion()
X{
X   extern char **Rule_tab;
X   char **p;
X   
X   printf("%s - %s, ", Pname, COPYRIGHT);
X   printf("Version %s, Patch Level %d\n\n", VERSION, PATCHLEVEL);
X
X   puts("Default Configuration:");
X   for (p=Rule_tab;  *p != NIL(char);  p++)
X      printf("\t%s\n", *p);
X}
SHAR_EOF
chmod 0440 dmake.c || echo "restore of dmake.c fails"
echo "x - extracting dag.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > dag.c &&
X/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/dag.c,v 1.1 90/10/06 12:03:33 dvadura Exp $
X-- SYNOPSIS -- Routines to construct the internal dag.
X-- 
X-- DESCRIPTION
X--	This file contains all the routines that are responsible for
X--	defining and manipulating all objects used by the make facility.
X-- 
X-- AUTHOR
X--      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
X--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
X--
X-- COPYRIGHT
X--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
X-- 
X--      This program is free software; you can redistribute it and/or
X--      modify it under the terms of the GNU General Public License
X--      (version 1), as published by the Free Software Foundation, and
X--      found in the file 'LICENSE' included with this distribution.
X-- 
X--      This program is distributed in the hope that it will be useful,
X--      but WITHOUT ANY WARRANTY; without even the implied warrant of
X--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X--      GNU General Public License for more details.
X-- 
X--      You should have received a copy of the GNU General Public License
X--      along with this program;  if not, write to the Free Software
X--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X--
X-- LOG
X--     $Log:	dag.c,v $
X * Revision 1.1  90/10/06  12:03:33  dvadura
X * dmake Release, Version 3.6
X * 
X*/
X
X#include <ctype.h>
X#include "extern.h"
X#include "alloc.h"
X#include "db.h"
X
X
XHASHPTR
XGet_name( name, tab, define, dir )/*
X====================================
X	Look to see if the name is defined, if it is then return
X	a pointer to its node, if not return NIL(HASH).
X	If define is TRUE and the name is not found it will be added. */
X
Xchar    *name;			/* name we are looking for   */
XHASHPTR *tab;			/* the hash table to look in */
Xint	define;			/* TRUE => add to table      */
XCELLPTR dir;
X{
X   register HASHPTR hp;
X   register char    *p;
X   uint16           hv;
X   uint32           hash_key;
X
X   DB_ENTER( "Get_name" );
X   DB_PRINT( "name", ("Looking for %s", name) );
X
X   hv = Hash( name, &hash_key );
X
X   for( hp = tab[ hv ]; hp != NIL(HASH); hp = hp->ht_next )
X      if( hp->ht_hash == hash_key &&
X	  (tab != Defs || ((tab == Defs) && (hp->CP_ROOT == dir))) &&
X	  !strcmp(hp->ht_name, name) )
X         break;
X
X   if( hp == NIL(HASH) && define ) {
X      /* Check to make sure that CELL name contains only printable chars */
X      for( p=name; *p; p++ )
X	 if( !isprint(*p) )
X	    Fatal( "Name contains non-printable character [0x%02x]", *p );
X
X      TALLOC( hp, 1, HASH );		/* allocate a cell and add it in */
X
X      if( tab == Defs ) hp->CP_ROOT = dir;
X      hp->ht_name  = _strdup( name );
X      hp->ht_hash  = hash_key;
X      hp->ht_next  = tab[ hv ];
X      tab[ hv ]    = hp;
X
X      DB_PRINT( "name", ("Adding %s", name) );
X   }
X
X   DB_PRINT( "name",("Returning: [%s,%lu]",
X	     (hp == NIL(HASH)) ? "":hp->ht_name, hv) );
X   DB_RETURN( hp );
X}
X
X
X
XHASHPTR
XDef_macro( name, value, flags )/*
X=================================
X   This routine is used to define a macro, and it's value.
X   The flags indicates if it is a permanent macro or if it's value
X   can be redefined.  A flags of M_PRECIOUS means it is a precious
X   macro and cannot be further redefined.  If the flags flag also
X   contains the M_MULTI bit it means that the macro can be redefined
X   multiple times and no warning of the redefinitions should be issued.
X   Once a macro's VAR flags are set they are preserved through all future
X   macro definitions.
X   
X   Macro definitions that have one of the variable bits set are treated
X   specially.  In each case the hash table entry var field points at the
X   global variable that can be set by assigning to the macro.
X   
X   bit valued global vars must be computed when the macro value is changed.
X   char valued global vars must have the first char of ht_value copied to
X   them.  string valued global vars have the same value as ht_value and should
X   just have the new value of ht_value copied to them.  */
X
Xchar    *name;			/* macro name to define	*/
Xchar    *value;			/* macro value to set	*/
Xint     flags;			/* initial ht_flags	*/
X{
X   register HASHPTR   hp;
X   register char      *p, *q;
X
X   DB_ENTER( "Def_macro" );
X   DB_PRINT( "mac", ("Defining macro %s = %s, %x", name, value, flags) );
X
X   /* check to see if name is in the table, if so then just overwrite
X      the previous definition.  Otherwise allocate a new node, and
X      stuff it in the hash table, at the front of any linked list */
X
X   if( Readenv ) flags |= M_LITERAL;
X
X   hp = Get_name( name, Macs, TRUE, NIL(CELL) );
X
X   if( (hp->ht_flag & M_PRECIOUS) && !(flags & M_FORCE) ) {
X      Warning( "Macro `%s' cannot be redefined", name );
X      DB_RETURN( hp );
X   }
X
X   if( hp->ht_value != NIL(char) ) FREE( hp->ht_value );
X
X   if( (hp->ht_flag & M_USED) && !((flags | hp->ht_flag) & M_MULTI) )
X      Warning( "Macro `%s' redefined after use", name );
X
X   if( (value != NIL(char)) && (*value) ) {
X      /* strip out any \<nl> combinations where \ is the current CONTINUATION
X       * char */
X
X      for( p = value; (p = strchr(p, CONTINUATION_CHAR)) != NIL(char); )
X         if( p[1] == '\n' )
X	    strcpy( p, p+2 );
X	 else
X	    p++;
X
X      if( !(flags & M_LITERAL) ) {
X	 p = _strdup( _strspn( value, " \t" ) ); /* strip white space before */
X						 /* ... and after value	     */
X	 if( *p ) {
X	    for(q=p+strlen(p)-1; ((*q == ' ')||(*q == '\t')); q--);
X	    *++q = '\0';
X	 }
X	 flags &= ~M_LITERAL;
X      }
X      else
X	 p = _strdup( value );	   		/* take string literally   */
X      
X      if( !*p )	{				/* check if result is ""   */
X         FREE( p );
X         p = NIL(char);
X	 flags |= M_EXPANDED;
X      }
X      else if( *_strpbrk( p, "${}" ) == '\0' )
X	 flags |= M_EXPANDED;
X
X      hp->ht_value = p;
X   }
X   else
X      hp->ht_value = NIL(char);
X
X   /* Assign the hash table flag less the M_MULTI flag, it is used only
X    * to silence the warning.  But carry it over if it was previously
X    * defined in ht_flag, as this is a permanent M_MULTI variable. */
X
X   hp->ht_flag = (flags & ~(M_MULTI|M_FORCE)) |
X		 (hp->ht_flag & (M_VAR_MASK | M_MULTI));
X   
X   /* Check for macro variables and make the necessary adjustment in the
X    * corresponding global variables */
X    
X   if( hp->ht_flag & M_VAR_MASK )
X      if( !(flags & M_EXPANDED) )
X	 Error( "Macro variables must be assigned with :=" );
X      else switch( hp->ht_flag & M_VAR_MASK )	/* only one var type per var */
X      {
X	 case M_VAR_STRING:
X	    *hp->MV_SVAR = hp->ht_value;
X	    break;
X
X	 case M_VAR_CHAR:
X	    *hp->MV_CVAR = (hp->ht_value == NIL(char)) ? '\0':*hp->ht_value;
X	    break;
X  
X	 case M_VAR_INT: {
X	    int tvalue;
X	    if( hp->MV_IVAR == NIL(int) ) break;	/* first time */
X
X	    tvalue = atoi(hp->ht_value);
X	    if( hp->MV_IVAR == &Buffer_size ) {
X	       /* If Buffer_size is modified then make sure you change the
X	        * size of the real buffer as well. */
X	       tvalue = (tvalue < (BUFSIZ-2)) ? BUFSIZ : tvalue+2;
X	       if( Buffer_size == tvalue ) break;
X	       if( Buffer ) FREE(Buffer);
X	       if((Buffer=MALLOC(tvalue, char)) == NIL(char)) No_ram();
X	       *Buffer = '\0';
X	    }
X	    *hp->MV_IVAR = tvalue;
X
X	    if( hp->MV_IVAR == &Max_proc || hp->MV_IVAR == &Max_proclmt ) {
X	       if( tvalue < 1 )
X		  Fatal( "Process limit value must be > 1" );
X
X	       if( Max_proc > Max_proclmt )
X		  Fatal( "Specified # of processes exceeds limit of [%d]",
X			 Max_proclmt );
X	    }
X	 } break;
X 
X	 case M_VAR_BIT:
X	    /* Bit variables are set to 1 if ht_value is not NULL and 0
X	     * otherwise */
X         
X	    if( hp->ht_value == NIL(char) )
X	       *hp->MV_BVAR &= ~hp->MV_MASK;
X	    else
X	       *hp->MV_BVAR |= hp->MV_MASK;
X	    break;
X      }
X   
X   DB_RETURN( hp );
X}
X
X
X
XCELLPTR
XDef_cell( name, dir )/*
X=======================
X   Take a string passed in and define it as a cell
X   If the cell exists then return a pointer to it. */
Xchar    *name;
XCELLPTR dir;
X{
X   register HASHPTR  hp;
X   register CELLPTR  cp;
X   register CELLPTR  lib;
X   char		     *member;
X   char		     *end;
X
X   DB_ENTER( "Def_cell" );
X
X   /* Check to see if the cell is a member of the form lib(member) or
X    * lib((symbol)) and handle the cases appropriately.
X    * What we do is we look at the target, if it is of the above two
X    * forms we get the lib, and add the member/symbol to the list of
X    * prerequisites for the library.  If this is a symbol name def'n
X    * we additionally add the attribute A_SYMBOL, so that stat can
X    * try to do the right thing.  */
X
X   if( ((member = strchr(name, '('))     != NIL(char)) &&
X       ((end    = strrchr(member,  ')')) != NIL(char)) &&
X       (member > name) && (member[-1] != '$') &&
X       (end > member+1)  && (end[1] == '\0') )
X   {
X      *member++ = *end = '\0';
X
X      if( (*member == '(') && (member[strlen(member)-1] == ')') ) {
X	 member[ strlen(member)-1 ] = '\0';
X	 cp = Def_cell( member+1, dir );
X	 cp->ce_attr |= A_SYMBOL;
X      }
X      else
X	 cp = Def_cell( member, dir );
X
X      lib  = Def_cell( name, dir );
X
X      if( lib->CE_HOW == NIL(HOW) ) TALLOC( lib->CE_HOW, 1, HOW );
X
X      Add_prerequisite( lib->CE_HOW, cp, FALSE );
X      lib->ce_attr |= A_LIBRARY | A_COMPOSITE;
X
X      if( !Def_targets ) cp = lib;
X   }
X   else {
X      hp = Get_name( name, Defs, TRUE, dir );/* get the name from hash table */
X
X      if( hp->CP_OWNR == NIL(CELL) )	/* was it previously defined    */
X      {					/* NO, so define a new cell	*/
X	 DB_PRINT( "cell", ("Defining cell [%s]", name) );
X
X	 TALLOC( cp, 1, CELL );
X	 hp->CP_OWNR = cp;
X	 cp->ce_name = hp;
X      }
X      else 				/* YES, so return the old cell	*/
X      {
X	 DB_PRINT( "cell", ("Getting cell [%s]", hp->ht_name) );
X	 cp = hp->CP_OWNR;
X      }
X   }
X
X   DB_RETURN( cp );
X}
X
X
X
X
XLINKPTR
XAdd_prerequisite( how, cell, head )/*
X=====================================
X	Add a dependency node to the dag.  It adds it to the prerequisites,
X	if any, of the cell and makes certain they are in linear order.
X	If head == 1, then add to head of the prerequisite list, else
X	add to tail. */
X
XHOWPTR  how;
XCELLPTR cell;
Xint     head;
X{
X   register LINKPTR lp, tlp;
X
X   DB_ENTER( "Add_prerequisite" );
X   DB_PRINT( "cell", ("Defining prerequisite %s", cell->CE_NAME) );
X
X   if( (cell->ce_flag & (F_MAGIC | F_PERCENT)) )
X      Fatal( "Special target [%s] cannot be a prerequisite",
X             cell->CE_NAME );
X
X   if( how->hw_prq == NIL(LINK) ) {	/* it's the first one	*/
X      TALLOC( lp, 1, LINK );
X      lp->cl_prq    = cell;
X      how->hw_prq   = lp;
X   }
X   else	{	/* search the list, checking for duplicates	*/
X      for( lp = how->hw_prq;
X	   (lp->cl_next != NIL(LINK)) && (lp->cl_prq != cell);
X	   lp = lp->cl_next );
X
X      /* If the cell is not found and we are at the last cell in the list,
X       * allocate a new cell and place it into the list, insert it at the
X       * head if head == 1, else we add it to the end. */
X
X      if( (lp->cl_prq != cell) ) {
X	 TALLOC( tlp, 1, LINK );
X	 tlp->cl_prq = cell;
X
X	 if( head ) {
X	    tlp->cl_next = how->hw_prq;
X	    how->hw_prq  = tlp;
X	 }
X	 else
X	    lp->cl_next  = tlp;
X
X	 lp = tlp;
X      }
X   }
X
X   DB_RETURN( lp );
X}
X
X
X
Xvoid
XClear_prerequisites( how )/*
X============================
X	Clear out the list of prerequisites, freeing all of the LINK nodes,
X	and setting the list to NULL */
XHOWPTR how;
X{
X   LINKPTR lp, tlp;
X
X   DB_ENTER( "Clear_prerequisites" );
X   DB_PRINT( "cell", ("Nuking prerequisites") );
X
X   if( how == NIL(HOW) ) { DB_VOID_RETURN; }
X
X   for( lp=how->hw_prq; lp != NIL(LINK); lp=tlp ) {
X      tlp=lp->cl_next;
X      FREE( lp );
X   }
X
X   how->hw_prq = NIL(LINK);
X
X   DB_VOID_RETURN;
X}
X
X
X
Xvoid
XAdd_fringe( cp )/*
X================== Take the cell pointed to by cp and put it at the end
X		   of the fringe of targets */
XCELLPTR cp;
X{
X   DB_ENTER( "Add_fringe" );
X
X   if( !(cp->ce_attr & A_FRINGE) ) {
X      DB_PRINT( "cell", ("Adding to fringe %s", cp->ce_name->ht_name) );
X
X      if( Fringe_hd == NIL(LINK) ) {
X	 TALLOC( Fringe_hd, 1, LINK );
X	 Fringe_tl = Fringe_hd;
X      }
X      else if( Fringe_tl != NIL(LINK) ) {
X	 TALLOC( Fringe_tl->cl_next, 1, LINK );
X	 Fringe_tl = Fringe_tl->cl_next;
X      }
X
X      Fringe_tl->cl_prq = cp;
X      cp->ce_attr |= A_FRINGE;
X   }
X
X   DB_VOID_RETURN;
X}
X
X
X
X
Xvoid
XCheck_circle( lp )/*
X====================
X	Check for circular definitions in the make graph */
XLINKPTR lp;
X{
X   for( ; lp != NIL(LINK); lp = lp->cl_next )
X      if( Test_circle( lp->cl_prq, FALSE ) )
X	 Fatal( "Detected circular dependency in graph at [%s]",
X		lp->cl_prq->CE_NAME );
X}
X
X
X
X
Xint
XTest_circle( cp, meta )/*
X=========================
X	Actually run through the graph */
XCELLPTR cp;
Xint     meta;
X{
X   int res = 0;
X   DB_ENTER( "Test_circle" );
X   DB_PRINT( "tc", ("checking [%s]", cp->CE_NAME) );
X
X   if( cp->ce_flag & F_MARK )
X      DB_RETURN( (cp->ce_attr & A_LIBRARY) ? 0 : 1 );
X
X   cp->ce_flag |= F_MARK;
X
X   if( meta ) {
X      register EDGEPTR ep;
X
X      if( cp->CE_EDGES != NIL(EDGE) ) {
X	 EDGEPTR es;
X
X	 ep = es = cp->CE_EDGES;
X	 do {
X	    if( ep->ed_prq != NIL(CELL) && ep->ed_prq->ce_flag & F_DFA )
X	       res = Test_circle( ep->ed_prq, TRUE );
X	    ep = ep->ed_next;
X	 }
X	 while( ep != es && !res );
X      }
X   }
X   else {
X      register LINKPTR tcp;
X
X      if( cp->CE_HOW != NIL(HOW) )
X	 for( tcp = cp->CE_HOW->hw_prq; !res && tcp != NIL(LINK);
X	      tcp = tcp->cl_next )
X	    if( tcp->cl_prq != cp ) res = Test_circle( tcp->cl_prq, FALSE );
X   }
X
X   cp->ce_flag ^= F_MARK;
X   DB_RETURN( res );
X}
X
X
X
X
XSTRINGPTR
XDef_recipe( rcp, sp, white_too, no_check )/*
X=============================================
X	Take the recipe and add it to the list of recipes
X	pointed to by sp.  sp points to the last element.
X	return a pointer to the new recipe.  If white_too == TRUE add the
X	recipe even if it contains only white space.
X	If no_check is true then don't look for -@ at the start of the
X	recipe line. */
Xchar      *rcp;
XSTRINGPTR sp;
Xint       white_too;
Xint       no_check;
X{
X   register STRINGPTR nsp;
X   register char      *rp;
X   t_attr             flag;
X   int                done;
X
X   DB_ENTER( "Def_recipe" );
X   DB_PRINT( "rul", ("Defining recipe %s", rcp) );
X
X   if( !white_too ) rcp = _strspn( rcp, " \t" );
X   if( (rcp == NIL(char)) || (*rcp == 0 && !white_too) )
X      DB_RETURN( sp );	     /* return last recipe when new recipe not added */
X
X   rp = no_check ? rcp : _strspn( rcp, " \t@-+%" );
X
X   TALLOC( nsp, 1, STRING );
X   nsp->st_string = _strdup( rp );
X
X   if( sp != NIL(STRING) ) sp->st_next = nsp;
X   nsp->st_next = NIL(STRING);
X
X   if( no_check ) DB_RETURN( nsp );
X
X   for( flag = A_DEFAULT, rp = rcp, done = FALSE; !done; )
X      switch( *rp++ )
X      {
X	 case '@' : flag |= A_SILENT; break;
X	 case '-' : flag |= A_IGNORE; break;
X	 case '+' : flag |= A_SHELL;  break;
X	 case '%' : flag |= A_SWAP;   break;
X
X	 case ' ' :
X	 case '\t': break;
X
X	 default: done = TRUE; break;
X      }
X
X   nsp->st_attr |= flag;
X
X   DB_RETURN( nsp );
X}
SHAR_EOF
chmod 0440 dag.c || echo "restore of dag.c fails"
echo mkdir - common
mkdir common
echo "x - extracting common/stdmacs.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > common/stdmacs.h &&
X/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/common/RCS/stdmacs.h,v 1.1 90/10/06 12:04:47 dvadura Exp $
X-- SYNOPSIS -- general use macros.
X-- 
X-- DESCRIPTION
X-- 	ANSI macro relies on the fact that it can be replaced by (), or by
X--	its value, where the value is one value due to the preprocessors
X--	handling of arguments that are surrounded by ()'s as a single
X--	argument.
X--
X-- AUTHOR
X--      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
X--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
X--
X-- COPYRIGHT
X--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
X-- 
X--      This program is free software; you can redistribute it and/or
X--      modify it under the terms of the GNU General Public License
X--      (version 1), as published by the Free Software Foundation, and
X--      found in the file 'LICENSE' included with this distribution.
X-- 
X--      This program is distributed in the hope that it will be useful,
X--      but WITHOUT ANY WARRANTY; without even the implied warrant of
X--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X--      GNU General Public License for more details.
X-- 
X--      You should have received a copy of the GNU General Public License
X--      along with this program;  if not, write to the Free Software
X--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X--
X-- LOG
X--     $Log:	stdmacs.h,v $
X * Revision 1.1  90/10/06  12:04:47  dvadura
X * dmake Release, Version 3.6
X * 
X*/
X
X#ifndef	MACROS_h
X#define	MACROS_h
X
X#if defined(__STDC__) || defined(__TURBOC__)
X#define	ANSI(x)	x
X#else
X#define	ANSI(x)	()
X#endif
X
X#define	NIL(p)	((p*)NULL)
X#define	offsetof(type,id) ((size_t)&((type*)NULL)->id)
X
X#define	FALSE	0
X#define	TRUE	1
X
X#endif
X
SHAR_EOF
chmod 0440 common/stdmacs.h || echo "restore of common/stdmacs.h fails"
echo "x - extracting common/print.mk (Text)"
sed 's/^X//' << 'SHAR_EOF' > common/print.mk &&
X# Make a listing of either everything so far, or just the stuff that has
X# been updated since the last time a printout was made.
X# The targets are:
X#	print		- to print only updated files.
X#	printall	- to print entire tree.
X#
X# MACROS are:
X#	PRINTER		- printer name on which to put output, output
X#			  goes to a file if no printer name is given.
X#	PRINTFLAGS	- flags to pass to the printer.
X#	PRINTEXCLUDE	- substrings in file names not to include in output.
X
XGROUPFLAGS  :=
XSEDLIST = _sed_e_flag_'/{ $(PRINTEXCLUDE) }/d'
XFILIST  = $(TMPDIR)/pr$$$$
XOFILE   = $(TMPDIR)/pr$$$$.out
X
X.IF $(PRINTEXCLUDE)
X   SEDARGS = $(SEDLIST:s/_sed_e_flag_/-e /)
X.END
X
Xprintall : print_remove_ctl print;
Xprint_remove_ctl:;@-$(RM) control/print
X
Xprint:
X@[
X   if [ -f control/print ]; then
X      find . -type f -newer control/print -print |\
X      sort -t. +2 +1 -2 |\
X      sed $(SEDARGS) >$(FILIST);
X      if [ -s $(FILIST) ]; then
X	 find . -type f -print | sort -t. +2 +1 -2 |\
X	 sed $(SEDARGS) >$(FILIST).full;
X	 cpr -c -T control/title -N -C `cat $(FILIST).full` >$(OFILE);
X	 cpr -c -N `cat $(FILIST)` >> $(OFILE);
X	 $(RM) $(FILIST).full;
X      else
X	 echo "No modified files since last printing";
X      fi
X   else
X      find . -type f -print | sort -t. +2 +1 -2 |\
X      sed $(SEDARGS) >$(FILIST);
X      if [ -s $(FILIST) ]; then
X	 cpr -c -T control/title -N `cat $(FILIST)` >$(OFILE);
X      fi
X   fi
X
X   if [ -s $(OFILE) ]; then
X.IF $(PRINTER)
X      $(PRINT) $(PRINTFLAGS) $(OFILE);
X      echo "Listing printed on $(PRINTER)";
X.IF $(PRINTKEEPTMP) == $(NULL)
X      $(RM) $(OFILE);
X.END
X.ELSE
X      echo "Listing can be temporarily found in $(OFILE)";
X.END
X   fi
X.IF $(PRINTKEEPTMP) == $(NULL)
X   $(RM) $(FILIST)
X.END
X   touch control/print;
X   exit 0
X]
SHAR_EOF
chmod 0662 common/print.mk || echo "restore of common/print.mk fails"
echo "x - extracting common/malloc.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > common/malloc.c &&
X/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/common/RCS/malloc.c,v 1.1 90/10/06 12:04:56 dvadura Exp $
X-- SYNOPSIS -- debugging version of malloc
X-- 
X-- DESCRIPTION
X-- 	malloc for debugging -- allocates via sbrk and tracks stuff, does diag
X-- 	dump if things appear to be screwed up.  This code is taken from a
X--	malloc package off the net.  By the time I got it the original authors
X--	name had disappeared.   This file can be used by anyone for any
X--	purpose, since it is originally from usenet, hence the missing
X--	copyright notice.
X-- 
X-- AUTHOR
X--      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
X--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
X--
X-- LOG
X--     $Log:	malloc.c,v $
X * Revision 1.1  90/10/06  12:04:56  dvadura
X * dmake Release, Version 3.6
X * 
X*/
X
X#ifdef DBUG
X
X#include <signal.h>
X#include "extern.h"
X#include "alloc.h"
X#include "db.h"
X
Xextern char *sbrk();
Xextern char etext[];
Xextern char edata[];
Xextern char end[];
X
Xvoid
XMy_free( ptr, fil, line )/*
X===========================
X   A routine that check the freeing of NULL pointers. */
Xchar *ptr;
Xchar *fil;
Xint  line;
X{
X#ifdef DB_MALLOC
X   _malldstr( "free: file:" );
X   _malldstr( fil );
X   _malldstr( " line: " );
X   _dbdumpint( line );
X   _malldstr( " ::  " );
X#endif
X
X   if( ptr == NIL( char ) )
X      Fatal( "Freeing NIL pointer" );
SHAR_EOF
echo "End of part 22"
echo "File common/malloc.c is continued in part 23"
echo "23" > s2_seq_.tmp
exit 0