[comp.sources.misc] v14i028: dmake version 3.5 part 18/21

dvadura@watdragon.waterloo.edu (Dennis Vadura) (07/27/90)

Posting-number: Volume 14, Issue 28
Submitted-by: dvadura@watdragon.waterloo.edu (Dennis Vadura)
Archive-name: dmake/part18

#!/bin/sh
# this is part 18 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file dmake.c continued
#
CurArch=18
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.c"
sed 's/^X//' << 'SHAR_EOF' >> dmake.c
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 );
X   Clear_signals();
X   Epilog(ex_val);      /* Does not return -- EVER */
X}
X
X
Xstatic void
X_do_ReadEnvironment()
X{
X   int 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   /*** The feature below is disabled for now */
X   /*puts("    -M   - Microsoft MAKE compatibility");*/
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
echo "File dmake.c is complete"
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/07/19 13:53:02 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/07/19  13:53:02  dvadura
X * Initial Revision of Version 3.5
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   int                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
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/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/07/19 13:31:06 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/07/19  13:31:06  dvadura
X * Initial Revision of Version 3.5
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" );
X
X   free( ptr );
X}
X
X
Xchar *
XMy_malloc( n, fil, line )/*
X===========================
X   A routine that check alloc */
Xunsigned int n;
Xchar *fil;
Xint  line;
X{
X#ifdef DB_MALLOC
X   _malldstr( "alloc: file:" );
X   _malldstr( fil );
X   _malldstr( " line: " );
X   _dbdumpint( line );
X   _malldstr( " ::  " );
X#endif
X
X   return( malloc( n ));
X}
X
X
X
Xchar *
XMy_calloc( n, size, fil, line )/*
X=================================
X   A routine that check alloc */
Xunsigned int n;
Xunsigned int size;
Xchar *fil;
Xint  line;
X{
X#ifdef DB_MALLOC
X   _malldstr( "alloc: file:" );
X   _malldstr( fil );
X   _malldstr( " line: " );
X   _dbdumpint( line );
X   _malldstr( " ::  " );
X#endif
X
X   return( calloc( n, size ));
X}
X
X
X
X#ifdef DB_MALLOC
X
Xstruct _Dmi {
X	struct _Dmi *m_next;
X	struct _Dmi *m_prev;
X	long m_size;
X	char m_blk[1];
X};
X
Xstatic struct _Dmi *_fab = (struct _Dmi *) 0;
Xstatic struct _Dmi *_ffb = (struct _Dmi *) 0;
Xstatic char *_xbrk = 0;
Xstatic int _in_malloc = 0;
Xstatic int _st_malloc = 0;
Xint _mall_opt = 1;
X
X/*
X * initialize stuff, we want to _malldmp() on a bus/seg error
X */
X
Xstatic _mall_sig(sig) {
X	if (sig == SIGSEGV)
X		_malldstr("\nsegmentation violation\n\n");
X	else if (sig == SIGBUS)
X		_malldstr("\nbus error\n\n");
X	else if (sig == SIGSYS)
X		_malldstr("\ninvalid syscall arg\n\n");
X	else {
X		_malldstr("\nsignal ");
X		_malldptr(sig);
X		_malldstr("\n\n");
X	}
X	_malldmp();
X	kill(getpid(), sig);
X}
X
Xstatic _mall_init() {
X	if (_st_malloc)
X		return;
X	signal(SIGSEGV, _mall_sig);
X	signal(SIGBUS, _mall_sig);
X	_st_malloc = 1;
X}
X
X/*
X * figure out which allocation block this pointer came from
X * return NULL if none
X */
X
Xstatic struct _Dmi *_mallgb(s)
Xchar *s; {
X	register struct _Dmi *blk;
X
X	for (blk = _fab; blk != (struct _Dmi *) 0; blk = blk->m_next)
X		if (blk->m_blk == s)
X			break;
X	return blk;
X}
X
X
X/*
X * internal: write a pointer in hex without using stdio
X */
X
Xstatic _malldptr(x)
Xregister long x; {
X	char buf[20];
X	static char hex[] = "0123456789abcdef";
X	register long dx;
X	register char *p;
X
X	if (x == 0)
X		return _malldstr("0x0(0)");
X	_malldstr("0x");
X	p = buf;
X	dx = x;
X	while (x > 0)
X		*p++ = hex[x % 16], x = x / 16;
X	while (p != buf)
X		write(2, --p, 1);
X	_malldstr("(");
X	p = buf;
X	x = dx;
X	while (x > 0)
X		*p++ = hex[x % 10], x /= 10;
X	while (p != buf)
X		write(2, --p, 1);
X	_malldstr(")");
X}
X
X/*
X * internal: dump a string
X */
X
Xstatic _malldstr(s)
Xregister char *s; {
X	register int len;
X
X	for (len = 0; s[len] != '\0'; len++)
X		;
X	write(2, s, len);
X}
X
X
Xstatic _dbdumpint(x)
Xregister int x; {
X	char buf[20];
X	static char hex[] = "0123456789abcdef";
X	register long dx;
X	register char *p;
X
X	if (x == 0) return _malldstr("0");
X	p = buf;
X	while (x > 0)
X		*p++ = hex[x % 10], x /= 10;
X	while (p != buf)
X		write(2, --p, 1);
X}
X
X
X/*
X * dump arena; can be called externally, and is non-destructive
X */
X
X_malldmp() {
X	register struct _Dmi *blk;
X	int oldf;
X
X	oldf = _in_malloc;
X	_in_malloc = 0;
X	_malldstr("brk = ");
X	_malldptr(sbrk(0));
X	_malldstr("  xbrk = ");
X	_malldptr(_xbrk);
X	_malldstr("\n_fab = ");
X	_malldptr(_fab);
X	_malldstr("  _ffb = ");
X	_malldptr(_ffb);
X	_malldstr("  blksiz = ");
X	_malldptr(sizeof (struct _Dmi));
X	_malldstr("\netext = ");
X	_malldptr(etext);
X	_malldstr("  edata = ");
X	_malldptr(edata);
X	_malldstr("  end = ");
X	_malldptr(end);
X	_malldstr("\n\nallocated blocks\n\n");
X	if (_fab == (struct _Dmi *) 0)
X		_malldstr("(none)\n");
X	else {
X		for (blk = _fab; blk != (struct _Dmi *) 0 && (char *) blk >= _xbrk && (char *) blk < sbrk(0); blk = blk->m_next) {
X			_malldstr("(");
X			_malldptr(blk);
X			_malldstr(")  ");
X			_malldptr(blk->m_prev);
X			_malldstr("<  ");
X			_malldptr(blk->m_size);
X			_malldstr("  >");
X			_malldptr(blk->m_next);
X			_malldstr("\n");
X		}
X		if (blk != (struct _Dmi *) 0)
X			_malldstr("(subsequent block pointers corrupted)\n");
X	}
X	_malldstr("\nfree blocks\n\n");
X	if (_ffb == (struct _Dmi *) 0)
X		_malldstr("(none)\n");
X	else {
X		for (blk = _ffb; blk != (struct _Dmi *) 0 && (char *) blk >= _xbrk && (char *) blk < sbrk(0); blk = blk->m_next) {
X			_malldstr("(");
X			_malldptr(blk);
X			_malldstr(")  ");
X			_malldptr(blk->m_prev);
X			_malldstr("<  ");
X			_malldptr(blk->m_size);
X			_malldstr("  >");
X			_malldptr(blk->m_next);
X			_malldstr("\n");
X		}
X		if (blk != (struct _Dmi *) 0)
X			_malldstr("(subsequent block pointers corrupted)\n");
X	}
X	_in_malloc = oldf;
X}
X
X/*
X * internal error routine: print error message (without using stdio) and
X * drop core
X */
X
Xstatic _mallerr(fn, s, ptr)
Xchar *fn, *s;
Xlong ptr; {
X	_malldstr(fn);
X	_malldstr(": ");
X	_malldstr(s);
X	_malldptr(ptr);
X	_malldstr("\n");
X	_malldmp();
X	signal(SIGQUIT, SIG_DFL);
X	kill(getpid(), SIGQUIT);
X}
X	
Xchar *malloc(n )
Xregister unsigned n;
X{
X	register struct _Dmi *blk;
X
X	_in_malloc = 1;
X	_mall_init();
X	if (_mall_opt)
X	{
X	     _malldstr("malloc: size: " );
X	     _malldptr(n);
X	     _malldstr("\n");
X	}
X	_mallchk("malloc");
X	if (n == 0) {
X		_malldstr("malloc(0) is illegal!\n");
X		_mall_sig(SIGSYS);
X	}
X	for (blk = _ffb; blk != (struct _Dmi *) 0; blk = blk->m_next)
X		if (blk->m_size >= n) {
X			if (blk->m_next != (struct _Dmi *) 0)
X				blk->m_next->m_prev = blk->m_prev;
X			if (blk->m_prev != (struct _Dmi *) 0)
X				blk->m_prev->m_next = blk->m_next;
X			if (blk == _ffb)
X				_ffb = blk->m_next;
X			blk->m_next = _fab;
X			blk->m_prev = (struct _Dmi *) 0;
X			if (_fab != (struct _Dmi *) 0)
X				_fab->m_prev = blk;
X			_fab = blk;
X			_in_malloc = 0;
X			return blk->m_blk;
X		}
X	if ((blk = (struct _Dmi *) sbrk(sizeof (struct _Dmi) + n - 1)) == (struct _Dmi *) -1) {
X		_in_malloc = 0;
X		return (char *) 0;	/* no space */
X	}
X	if (_xbrk == (char *) 0)
X		_xbrk = (char *) blk;
X	blk->m_next = _fab;
X	blk->m_prev = (struct _Dmi *) 0;
X	if (_fab != (struct _Dmi *) 0)
X		_fab->m_prev = blk;
X	_fab = blk;
X	blk->m_size = n;
X	_in_malloc = 0;
X	return blk->m_blk;
X}
X
X/* The free-block list is sorted in size order */
X
Xfree(s)
Xregister char *s;
X{
X	register struct _Dmi *blk, *fblk;
X	int didit;
X
X	_in_malloc = 1;
X	_mall_init();
X	if (_mall_opt)
X	{
X	     _malldstr("free: ptr: ");
X	     _malldptr(s);
X	     _malldstr("\n");
X	}
X	_mallchk("free");
X	if (s == (char *) 0) {
X		_malldstr("free((char *) 0) is illegal!\n");
X		_mall_sig(SIGSYS);
X	}
X	if ((blk = _mallgb(s)) == (struct _Dmi *) 0)
X		_mallerr("non-allocated pointer passed to free(): ", s);
X	if (blk->m_prev != (struct _Dmi *) 0)
X		blk->m_prev->m_next = blk->m_next;
X	if (blk->m_next != (struct _Dmi *) 0)
X		blk->m_next->m_prev = blk->m_prev;
X	if (blk == _fab)
X		_fab = blk->m_next;
X	if (_ffb == (struct _Dmi *) 0) {
X		_ffb = blk;
X		blk->m_next = (struct _Dmi *) 0;
X		blk->m_prev = (struct _Dmi *) 0;
X		goto crunch;
X	}
X	for (fblk = _ffb; fblk->m_next != (struct _Dmi *) 0; fblk = fblk->m_next)
X		if (fblk->m_next->m_size >= blk->m_size)
X			break;
X	blk->m_next = fblk->m_next;
X	if (fblk->m_next != (struct _Dmi *) 0)
X		fblk->m_next->m_prev = blk;
X	blk->m_prev = fblk;
X	fblk->m_next = blk;
X
X/*
X * crunch the free list by dropping consecutive end-of-brk until we hit xbrk
X * or a "hole" (i.e. allocated block).  coalescing is possible but not supp-
X * orted in malloc, so we don't bother here.
X */
X
Xcrunch:
X	didit = 1;
X	while (_ffb != (struct _Dmi *) 0 && didit) {
X		didit = 0;
X		for (fblk = _ffb; fblk != (struct _Dmi *) 0; fblk = fblk->m_next)
X			if ((char *) fblk + sizeof *fblk + fblk->m_size - 1 == sbrk(0)) {
X				didit = 1;
X				if (fblk->m_next != (struct _Dmi *) 0)
X					fblk->m_next->m_prev = fblk->m_prev;
X				if (fblk->m_prev != (struct _Dmi *) 0)
X					fblk->m_prev->m_next = fblk->m_next;
X				if (fblk == _ffb)
X					_ffb = fblk->m_next;
X				sbrk(- fblk->m_size);
X				break;
X			}
X	}
X	_in_malloc = 0;
X}
X
Xchar *realloc(s, n)
Xregister char *s;
Xregister unsigned n; {
X	register char *s1, *d, *d1;
X	register struct _Dmi *blk;
X
X	if (_mall_opt)
X		_malldstr("called realloc("), _malldptr(s), _malldstr(", "), _malldptr(n), _malldstr(")\n");
X	_mallchk("realloc");
X	if (s == (char *) 0) {
X		_malldstr("realloc((char *) 0, size) is illegal!\n");
X		_mall_sig(SIGSYS);
X	}
X	if (n == 0) {
X		_malldstr("realloc(ptr, 0) is illegal!\n");
X		_mall_sig(SIGSYS);
X	}
X	if ((blk = _mallgb(s)) == (struct _Dmi *) 0)
X		_mallerr("non-allocated pointer passed to realloc(): ", s);
X	if ((s1 = malloc(n)) == (char *) 0)
X		return (char *) 0;
X	if (blk->m_size < n)
X		n = blk->m_size;
X	d1 = s1;
X	d = s;
X	while (n-- != 0)
X		*d1++ = *d++;
X	free(s);
X	return s1;
X}
X
X/*
X * _mallchk() is global, so external routines can do discreet checks on the
X * arena.  If the arena is detectibly corrupted, it will abort().
X */
X
X_mallchk(fn)
Xchar *fn; {
X	register struct _Dmi *blk, *cblk;
X	register char *send;
X	register int cnt;
X
X	send = sbrk(0);
X	cblk = (struct _Dmi *) 0;
X	for (blk = _fab; blk != (struct _Dmi *) 0; cblk = blk, blk = blk->m_next) {
X		if ((char *) blk < _xbrk || (char *) blk >= send)
X			_mallerr(fn, "allocated block list corrupted: blkptr = ", blk);
X		if (blk->m_prev != cblk)
X			_mallerr(fn, "allocated block list corrupted: back pointer incorrect blk ", blk);
X		if (blk->m_size < 0)
X			_mallerr(fn, "allocated block list corrupted: blk->m_size = ", blk->m_size);
X	}
X	cblk = (struct _Dmi *) 0;
X	for (blk = _ffb; blk != (struct _Dmi *) 0; cblk = blk, blk = blk->m_next) {
X		if ((char *) blk < _xbrk || (char *) blk >= sbrk(0))
X			_mallerr(fn, "free block list corrupted: blkptr = ", blk);
X		if (blk->m_prev != cblk)
X			_mallerr(fn, "free block list corrupted: back pointer incorrect blk ", blk);
X		if (blk->m_size < 0)
X			_mallerr(fn, "free block list corrupted: blk->m_size = ", blk->m_size);
SHAR_EOF
echo "End of part 18"
echo "File common/malloc.c is continued in part 19"
echo "19" > s2_seq_.tmp
exit 0