v14i028: dmake version 3.5 part 18/21
Dennis Vadura
dvadura at watdragon.waterloo.edu
Fri Jul 27 09:48:03 AEST 1990
Posting-number: Volume 14, Issue 28
Submitted-by: dvadura at 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 at 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 at -" );
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 at 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
More information about the Comp.sources.misc
mailing list