dvadura@watdragon.waterloo.edu (Dennis Vadura) (07/27/90)
Posting-number: Volume 14, Issue 15 Submitted-by: dvadura@watdragon.waterloo.edu (Dennis Vadura) Archive-name: dmake/part05 #!/bin/sh # this is part 5 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file rulparse.c continued # CurArch=5 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 rulparse.c" sed 's/^X//' << 'SHAR_EOF' >> rulparse.c X for( cp=prereq; cp != NIL(CELL); cp = cp->ce_link ) { X name = cp->CE_NAME; X X if( *name == '<' ) { X /* We have a file name enclosed in <....> X * so get rid of the <> arround the file name */ X X name++; X if( (tmp = strrchr( name, '>' )) != NIL( char ) ) X *tmp = 0; X X if( If_root_path( name ) ) X fil = Openfile( name, FALSE ); X else X fil = NIL(FILE); X } X else X fil = Openfile( name, FALSE ); X X if( fil == NIL(FILE) ) { /*if true ==> not found in current dir*/ X /* Now we must scan the list of prerequisites for .INCLUDEDIRS X * looking for the file in each of the specified directories. X * if we don't find it then we issue an error. The error X * message is suppressed if the .IGNORE attribute of attr is X * set. If a file is found we call Parse on the file to X * perform the parse and then continue on from where we left X * off. */ X X if( (dp->CE_HOW != NIL(HOW)) && X ((lp = dp->CE_HOW->hw_prq) != NIL(LINK)) ) X for(; lp != NIL(LINK) && fil == NIL(FILE); lp=lp->cl_next) { X dir = lp->cl_prq->CE_NAME; X if( strchr(dir, '$') ) dir = Expand(dir); X path = Build_path( dir, name ); X X DB_PRINT( "par", ("Trying to include [%s]", path) ); X X fil = Openfile( path, FALSE ); X if( dir != lp->cl_prq->CE_NAME ) FREE(dir); X } X } X X if( fil != NIL(FILE) ) X Parse( fil ); X else if( !((Glob_attr | attr) & A_IGNORE) ) X Fatal( "Include file %s, not found", name ); X } X X if( pushed ) Pop_dir(FALSE); X attr &= ~(A_IGNORE|A_SETDIR); X } X break; X X case ST_SOURCE: X /* case ST_SUFFIXES: */ X if( prereq != NIL(CELL) ) X _do_targets( op & (R_OP_CL | R_OP_MI | R_OP_UP), attr, set_dir, X target, prereq ); X else { X /* The old semantics of .SOURCE were that an empty list of X * prerequisites clears the .SOURCE list. So we must implement X * that here as a clearout prerequisite operation. Since this is X * a standard operation with the :- opcode we can simply call the X * proper routine with the target cell and it should do the trick X */ X X if( op == R_OP_CL || (op & R_OP_MI) ) X Clear_prerequisites( target->CE_HOW ); X } X X op &= ~(R_OP_MI | R_OP_UP); X break; X X case ST_REST: X /* The rest of the special targets can all take rules, as such they X * must be able to affect the state of the parser. */ X X { X int s_targ = Target; X X Target = TRUE; X _sp_target = TRUE; X *state = _do_targets( op, attr, set_dir, target, prereq ); X Target = s_targ; X X set_dir = NIL( char ); X attr = A_DEFAULT; X op = R_OP_CL; X } X break; X X default:break; X } X X if( set_dir != NIL(char) ) FREE( set_dir ); X if( op != R_OP_CL ) Warning( "Modifier(s) for operator ignored" ); X if( attr != A_DEFAULT ) Warning( "Extra attributes ignored" ); X X DB_VOID_RETURN; X} X X X Xstatic int X_do_targets( op, attr, set_dir, targets, prereq )/* X================================================= */ Xint op; Xint attr; Xchar *set_dir; XCELLPTR targets; XCELLPTR prereq; X{ X CELLPTR tg1; /* temporary target pointer */ X CELLPTR tp1; /* temporary prerequisite pointer */ X char *p; /* temporary char pointer */ X CELLPTR prev_cell; /* pointer for .UPDATEALL processing */ X int update; /* A_UPDATEALL attribute flag */ X int smagic = 0; /* collective amount of magic :-) */ X X DB_ENTER( "_do_targets" ); X X if( update = (attr & A_UPDATEALL) ) X if( targets == NIL(CELL) ) X Fatal( ".UPDATEALL attribute requires non-empty list of targets" ); X X prev_cell = NIL(CELL); X for( tg1 = targets; tg1 != NIL(CELL); tg1 = tg1->ce_link ) { X /* Check each target. Check for inconsistencies between :: and : rule X * sets. :: may follow either : or :: but not the reverse. We allocate X * a HOW cell for each target that we see, if it already does not have X * one. If it has a HOW cell then we use it, unless the current X * operator is ::, in which case we must allocate a new one. */ X X int magic = (tg1->ce_flag & F_PERCENT) && !(tg1->ce_flag & F_MAGIC); X smagic |= magic; X X if( !(op & R_OP_DCL ) && (tg1->ce_flag & F_MULTI) && !magic ) X Fatal( "Inconsistency in inference rules for %s", tg1->CE_NAME ); X X if( magic ) X do { X _build_graph( op, tg1, prereq ); X if( prereq != NIL(CELL) ) prereq = prereq->ce_link; X } while( prereq != NIL(CELL) ); X else if( !(tg1->ce_flag & F_SPECIAL) && X (p = _is_magic( tg1->CE_NAME )) != NIL(char) ) X smagic |= _do_magic( op, p, tg1, prereq, attr, set_dir ); X else if( op & R_OP_DCL ) { X HOWPTR hp; X X TALLOC( hp, 1, HOW ); X X hp->hw_next = tg1->CE_HOW; X tg1->CE_HOW = hp; X tg1->ce_flag |= F_MULTI; X } X else if( tg1->CE_HOW == NIL(HOW) ) X TALLOC( tg1->CE_HOW, 1, HOW ); X X if( !magic ) _set_attributes( attr, set_dir, tg1 ); X X if( update ) { X if( smagic ) Fatal( ".UPDATEALL attribute not legal in meta rule" ); X X /* Check this as it would break another cirlcular .UPATEALL list if X * we blindly assign it and it is part of another list already. */ X if( tg1->ce_all != NIL(CELL) ) X Fatal( "Target [%s] appears on multiple .UPDATEALL lists" ); X X tg1->ce_all = prev_cell; X prev_cell = tg1; X } X X /* Build the proper prerequisite list of the target. If the `-', X * modifier was used clear the prerequisite list before adding any X * new prerequisites. Else add them to the head/tail as appropriate. X * X * If the target has F_PERCENT set then no prerequisites are used. */ X X if( !(tg1->ce_flag & F_PERCENT) ) X if( tg1 == targets || !update ) { X register HOWPTR how = tg1->CE_HOW; X X if( op & R_OP_MI ) Clear_prerequisites( how ); X X if( (op & R_OP_UP) && (how->hw_prq != NIL(LINK)) ) X _stick_at_head( how, prereq ); X else X for( tp1=prereq; tp1 != NIL(CELL); tp1 = tp1->ce_link ) X Add_prerequisite( how, tp1, FALSE ); X } X else X if( op & (R_OP_MI | R_OP_UP) ) X Warning( "Modifier(s) `^!' for ':' operator ignored" ); X } X X if( targets != NIL(CELL) ) targets->ce_all = prev_cell; X X X /* Check to see if we have NO targets but some attributes. IF so then X * apply all of the attributes to the complete list of prerequisites. X * Cannot happen for F_PERCENT targets. (ie. in that case targets is always X * not NIL) */ X X if( (targets == NIL(CELL)) && attr ) X if( prereq != NIL(CELL) ) X for( tp1=prereq; tp1 != NIL(CELL); tp1 = tp1->ce_link ) { X if( tp1->CE_HOW == NIL(HOW) ) TALLOC( tp1->CE_HOW, 1, HOW ); X _set_attributes( attr, set_dir, tp1 ); X } X else X _set_global_attr( attr, set_dir ); X X /* Fix up the HOW pointers for the A_UPDATEALL case, they should all point X * to the same cell (targets->CE_HOW), if the .UPDATEALL attribute is given X */ X if( update && targets != NIL(CELL) ) X for( tg1=targets->ce_link; tg1 != NIL(CELL); tg1 = tg1->ce_link ) { X FREE(tg1->CE_HOW); X tg1->CE_HOW = targets->CE_HOW; X } X X /* Now that we have built the lists of targets, the parser must parse the X * rules if there are any. However we must start the rule list with the X * rule specified as via the ; kludge, if there is one */ X X _sv_targets = targets; X _sv_attr = _sv_attro = attr; X _sv_flag = ((op & R_OP_BG) ? F_SINGLE : F_DEFAULT); X X DB_RETURN( RULE_SCAN ); X} X X Xstatic int X_do_magic( op, dot, target, prereq, attr, set_dir )/* X===================================================== X This function takes a magic target of the form .<chars>.<chars> or X .<chars> and builds the appropriate % rules for that target. X X The function builds the % rule, `%.o : %.c' from .c.o, and X `%.a :' from .a */ X Xint op; Xchar *dot; XCELLPTR target; XCELLPTR prereq; Xint attr; Xchar *set_dir; X{ X CELLPTR tg; X CELLPTR prq; X char *tmp, *tmp2; X X DB_ENTER( "_do_magic" ); X X if( prereq != NIL(CELL) ) X Warning( "Ignoring prerequisites of old style meta-target" ); X X op &= (R_OP_CL | R_OP_DCL); X X if( dot == target->CE_NAME ) { /* its of the form .a */ X tg = Def_cell( "%", NIL(CELL) ); /* ==> no prerequisite */ X tmp = _build_meta( target->CE_NAME ); X prq = Def_cell( tmp, NIL(CELL) ); X FREE( tmp ); X X _build_graph( op, tg, prq ); X } X else { X tmp = _build_meta( dot ); X tg = Def_cell( tmp, NIL(CELL) ); X FREE( tmp ); X X tmp = _build_meta( tmp2 = _substr( target->CE_NAME, dot ) ); X prq = Def_cell( tmp, NIL(CELL) ); X FREE( tmp ); X FREE( tmp2 ); X X _build_graph( op, tg, prq ); X } X X tg->ce_flag |= F_PERCENT; X target->ce_flag |= (tg->ce_flag & (F_MULTI | F_PERCENT)) | F_MAGIC; X target->CE_EDGES = tg->CE_EDGES; X X _set_attributes( attr, set_dir, tg ); X X DB_RETURN(1); X} X X X Xstatic char * X_build_meta( name )/* X===================== X Check to see if the name is of the form .c~ if so and if Augmake X translation is enabled then return s.%.c, else return %.suff, where if the X suffix ends in '~' then leave it be.*/ Xchar *name; X{ X char *tmp; X int test = Augmake ? name[strlen(name)-1] == '~' : 0; X X tmp = _strjoin( test ? "s.%" : "%", name, -1, FALSE); X if( test ) tmp[ strlen(tmp)-1 ] = '\0'; X X return(tmp); X} X X X Xstatic void X_build_graph( op, target, prereq )/* X==================================== X This function is called to build the graph for the % rule given by X target : prereq cell combination. This function assumes that target X is a % target and that prereq is a single % prerequisite. op can be X either R_OP_CL or R_OP_DCL, all other operations are ignored. X X It also assumes that target cell has F_PERCENT set already. */ Xint op; XCELLPTR target; XCELLPTR prereq; X{ X int match; X EDGEPTR edge; X X DB_ENTER( "_build_graph" ); X DB_PRINT( "%", ("Building graph for [%s : %s]", target->CE_NAME, X (prereq == NIL(CELL)) ? "" : prereq->CE_NAME) ); X X if( prereq != NIL(CELL) ) { X char *name = prereq->CE_NAME; X int len = strlen(name); X X if( *name == '\'' && name[len-1]=='\'' ){ X _add_global_prereq( prereq ); X name[len-1] = '\0'; X strcpy(name, name+1); X DB_VOID_RETURN; X } X } X X /* The list of edges is kept as a circular list. Thus we must find the X * last edge if we are to add a new edge. Also we must check the list to X * find out if a new edge needs to be added. */ X X match = FALSE; X if( (edge = target->CE_EDGES) != NIL(EDGE) ) { X EDGEPTR start; X X start = edge; X do { X DB_PRINT( "%", ("Trying to match [%s]", edge->ed_prq->CE_NAME) ); X X if( edge->ed_prq == prereq ) X match = TRUE; X else X edge = edge->ed_next; X } X while ( !match && start != edge ); X } X X if( match ) { X /* match is TRUE hence, we found an edge joining the target and the X * prerequisite so set the current target's CE_EDGES pointer to point X * at the edge we found and make sure the new edge has a valid HOW X * pointer. */ X X DB_PRINT( "%", ("It's an old edge") ); X X target->CE_EDGES = edge; X X if( op & R_OP_DCL ) { X HOWPTR hp; X X TALLOC( hp, 1, HOW ); X X hp->hw_next = edge->ed_how; X edge->ed_how = hp; X } X else { X HOWPTR hp = edge->ed_how; X X hp->hw_flag = F_DEFAULT; X hp->hw_attr = A_DEFAULT; X target->ce_dir = NIL(char); X target->ce_flag &= (F_PERCENT|F_MAGIC); X target->ce_attr &= A_NOINFER; X } X X } X else { X EDGEPTR tedge; X X TALLOC( tedge, 1, EDGE ); X X if( edge == NIL(EDGE) ) { X DB_PRINT( "%", ("It's a new edge") ); X edge = tedge; X target->CE_EDGES = edge->ed_next = edge; X } X else { X DB_PRINT( "%", ("It's a new edge (non-empty edge list)") ); X tedge->ed_next = edge->ed_next; X edge->ed_next = tedge; X target->CE_EDGES = edge = tedge; X } X X /* This was a new edge so we must point it's prerequisite pointer at the X * prerequisite, and add the first HOW cell. X * Since this is also the first time we have seen the % target we X * add it to the NFA we are building of % rule targets. */ X X TALLOC( edge->ed_how, 1, HOW ); X X edge->ed_prq = prereq; X edge->ed_tg = target; X X if( !(target->ce_flag & F_DFA) ) { X Add_dfa( target->CE_NAME ); X target->ce_flag |= F_DFA; X } X X if( op & R_OP_DCL ) target->ce_flag |= F_MULTI; X } X X edge->ed_link = _sv_edgel; X _sv_edgel = edge; X _sv_globprq_only = 0; X X DB_VOID_RETURN; X} X X X Xstatic void X_add_global_prereq( pq )/* X========================== X Prerequisite is a non-% prerequisite for a %-rule target, add it to X the target's list of global prerequsites to add on match */ XCELLPTR pq; X{ X register LINKPTR ln; X X TALLOC( ln, 1, LINK ); X ln->cl_next = _sv_glb_prq; X ln->cl_prq = pq; X _sv_glb_prq = ln; X} X X X Xstatic void X_set_attributes( attr, set_dir, cell )/* X============================================= X Set the appropriate attributes for a cell */ Xint attr; Xchar *set_dir; XCELLPTR cell; X{ X char *dir; X X DB_ENTER( "_set_attributes" ); X X /* If .SETDIR attribute is set then we have at least .SETDIR= in the X * set_dir string. So go and fishout what is at the end of the =. X * If not set and not NULL then propagate it to the target cell. */ X X if( attr & A_SETDIR ) { X dir = strchr( set_dir, '=' ) + 1; X X if( cell->ce_attr & A_SETDIR ) X Warning( "Multiple .SETDIR for %s ignored", cell->CE_NAME ); X else X if( *dir ) cell->ce_dir = dir; X } X cell->ce_attr |= attr; /* set rest of attributes for target */ X X DB_VOID_RETURN; X} X X X Xstatic void X_set_global_attr( attr, dir )/* X=============================== X Handle the setting of the global attribute functions based on X The attribute flags set in attr. Note we set the dir path name X to be the value of Start_dir. If Start_dir is initially set X Make will CD to that directory before making any targets. */ Xint attr; Xchar *dir; X{ X int flag; X X for( flag = MAX_ATTR; flag; flag >>= 1 ) X switch( flag & attr ) X { X case A_PRECIOUS: Def_macro(".PRECIOUS", "y", M_EXPANDED); break; X case A_SILENT: Def_macro(".SILENT", "y", M_EXPANDED); break; X case A_IGNORE: Def_macro(".IGNORE", "y", M_EXPANDED); break; X case A_EPILOG: Def_macro(".EPILOG", "y", M_EXPANDED); break; X case A_PROLOG: Def_macro(".PROLOG", "y", M_EXPANDED); break; X case A_NOINFER: Def_macro(".NOINFER", "y", M_EXPANDED); break; X case A_SEQ: Def_macro(".SEQUENTIAL","y",M_EXPANDED); break; X X case A_SETDIR: X dir = strchr( dir, '=' ) + 1; X if( *dir ) Start_dir.ce_dir = dir; X break; X } X X attr &= ~(A_PRECIOUS | A_SETDIR | A_SILENT | A_IGNORE | X A_EPILOG | A_PROLOG | A_NOINFER | A_SEQ); X X if( attr ) X Warning( "Non global attribute(s) ignored" ); X} X X X Xstatic void X_stick_at_head( how, pq )/* X=========================== X Add the prerequisite list to the head of the existing prerequisite X list */ X XHOWPTR how; /* HOW cell for target node */ XCELLPTR pq; /* list of prerequisites to add */ X{ X DB_ENTER( "_stick_at_head" ); X X if( pq->ce_link != NIL(CELL) ) _stick_at_head( how, pq->ce_link ); X Add_prerequisite( how, pq, TRUE ); X X DB_VOID_RETURN; X} X X X Xstatic int X_is_attribute( name )/* X======================= X Check the passed name against the list of valid attributes and return the X attribute index if it is, else return 0, indicating the name is not a valid X attribute. The present attributes are defined in dmake.h as A_xxx #defines, X with the corresponding makefile specification: (note they must be named X exactly as defined below) X X Valid attributes are: .IGNORE, .SETDIR=, .SILENT, .PRECIOUS, .LIBRARY, X .EPILOG, .PROLOG, .LIBRARYM, .SYMBOL, .UPDATEALL, X .NOINFER X X NOTE: The strcmp's are OK since at most three are ever executed for any X one attribute check, and that happens only when we can be fairly X certain we have an attribute. */ Xchar *name; X{ X int attr = 0; X X DB_ENTER( "_is_attribute" ); X X if( *name++ == '.' ) X switch( *name ) X { X case 'E': attr = (strcmp(name, "EPILOG")) ? 0 : A_EPILOG; break; X case 'I': attr = (strcmp(name, "IGNORE")) ? 0 : A_IGNORE; break; X case 'L': attr = (strcmp(name, "LIBRARY")) ? 0 : A_LIBRARY; break; X case 'N': attr = (strcmp(name, "NOINFER")) ? 0 : A_NOINFER; break; X case 'U': attr = (strcmp(name, "UPDATEALL"))? 0 : A_UPDATEALL;break; X X case 'P': X if( !strcmp(name, "PRECIOUS") ) attr = A_PRECIOUS; X else if( !strcmp(name, "PROLOG") ) attr = A_PROLOG; X else attr = 0; X break; X X case 'S': X if( !strncmp(name, "SETDIR=", 7) ) attr = A_SETDIR; X else if( !strcmp(name, "SILENT") ) attr = A_SILENT; X else if( !strcmp(name, "SYMBOL") ) attr = A_SYMBOL; X else if( !strcmp(name, "SEQUENTIAL")) attr = A_SEQ; X else attr = 0; X break; X } X X DB_RETURN( attr ); X} X X X Xstatic int X_is_special( tg )/* X=================== X This function returns TRUE if the name passed in represents a special X target, otherwise it returns false. A special target is one that has X a special meaning to dmake, and may require processing at the time that X it is parsed. X X Current Special targets are: X .GROUPPROLOG .GROUPEPILOG .INCLUDE .IMPORT X .EXPORT .SOURCE .SUFFIXES .ERROR X .INCLUDEDIRS .MAKEFILES .REMOVE X*/ Xchar *tg; X{ X DB_ENTER( "_is_special" ); X X if( *tg++ != '.' ) DB_RETURN( 0 ); X X switch( *tg ) X { X case 'I': X if( !strcmp( tg, "IMPORT" ) ) DB_RETURN( ST_IMPORT ); X else if( !strcmp( tg, "INCLUDE" ) ) DB_RETURN( ST_INCLUDE ); X else if( !strcmp( tg, "INCLUDEDIRS" )) DB_RETURN( ST_REST ); X break; X X case 'M': X if( !strcmp( tg, "MAKEFILES" ) ) DB_RETURN( ST_REST ); X break; X X case 'E': X if( !strcmp( tg, "ERROR" ) ) DB_RETURN( ST_REST ); X else if( !strcmp( tg, "EXPORT" ) ) DB_RETURN( ST_EXPORT ); X break; X X case 'G': X if( !strcmp( tg, "GROUPPROLOG" )) DB_RETURN( ST_REST ); X else if( !strcmp( tg, "GROUPEPILOG" )) DB_RETURN( ST_REST ); X break; X X case 'R': X if( !strcmp( tg, "REMOVE" ) ) DB_RETURN( ST_REST ); X break; X X case 'S': X if( !strncmp( tg, "SOURCE", 6 ) ) DB_RETURN( ST_SOURCE ); X else if( !strncmp(tg, "SUFFIXES", 8 )) DB_RETURN( ST_SOURCE ); X break; X } X X DB_RETURN( 0 ); X} X X X Xstatic int X_is_percent( np )/* X=================== X return TRUE if np points at a string containing a % sign */ Xchar *np; X{ X return( (strchr(np,'%') && (*np != '\'' && np[strlen(np)-1] != '\'')) ? X TRUE : FALSE ); X} X X Xstatic char * X_is_magic( np )/* X================= X return TRUE if np points at a string of the form X .<chars>.<chars> or .<chars> X where chars are only alpha characters. X X NOTE: reject target if it begins with ./ or ../ */ Xchar *np; X{ X register char *n; X X n = np; X if( *n != '.' ) return( NIL(char) ); X if (strchr(DirBrkStr, *(n+1))!=NULL || *(n+1) == '.' ) X return (NIL(char)); X X for( n++; isgraph(*n) && (*n != '.'); n++ ); X X if( *n != '\0' ) { X if( *n != '.' ) return( NIL(char) ); X for( np = n++; isgraph( *n ) && (*n != '.'); n++ ); X if( *n != '\0' ) return( NIL(char) ); X } X else if( !Augmake ) X return( NIL(char) ); X X /* np points at the second . of .<chars>.<chars> string. X * if the special target is of the form .<chars> then np points at the X * first . in the token. */ X X return( np ); X} X SHAR_EOF echo "File rulparse.c is complete" chmod 0440 rulparse.c || echo "restore of rulparse.c fails" echo "x - extracting quit.c (Text)" sed 's/^X//' << 'SHAR_EOF' > quit.c && X/* RCS -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/quit.c,v 1.1 90/07/19 13:53:29 dvadura Exp $ X-- SYNOPSIS -- end the dmake session. X-- X-- DESCRIPTION X-- Handles dmake termination. 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: quit.c,v $ X * Revision 1.1 90/07/19 13:53:29 dvadura X * Initial Revision of Version 3.5 X * X*/ X X#include "extern.h" X Xstatic void _handle_quit ANSI((char*)); Xstatic int _dont_quit = 0; X X Xvoid XQuit()/* X======== Error or quit */ X{ X if( _dont_quit ) return; X X while( Closefile() != NIL( FILE ) ); X Clean_up_processes(); X X if( Current_target != NIL(HOW) ) X Unlink_temp_files(Current_target); X X if( _dont_quit == 0 ) _handle_quit( ".ERROR" ); X X Set_dir( Makedir ); /* No Error message if we can't do it */ X Epilog( ERROR_EXIT_VALUE ); X} X X Xstatic void X_handle_quit( err_target )/* X============================ X Called by quit and the others to handle the execution of termination code X from within make */ Xchar *err_target; X{ X HASHPTR hp; X CELLPTR cp; X X if( (hp = Get_name(err_target, Defs, FALSE, NIL(CELL))) != NIL(HASH) ) { X cp = hp->CP_OWNR; X Glob_attr |= A_IGNORE; X X _dont_quit = 1; X cp->ce_flag |= F_TARGET; X Make( cp, cp->CE_HOW, NIL(CELL) ); X } X} SHAR_EOF chmod 0440 quit.c || echo "restore of quit.c fails" echo "x - extracting percent.c (Text)" sed 's/^X//' << 'SHAR_EOF' > percent.c && X/* RCS -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/percent.c,v 1.1 90/07/19 13:53:25 dvadura Exp $ X-- SYNOPSIS -- handle building or %-rule meta-target nfa. X-- X-- DESCRIPTION X-- Builds the NFA used by dmake to match targets against %-meta X-- rule constructs. The NFA is built as a set of DFA's. 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: percent.c,v $ X * Revision 1.1 90/07/19 13:53:25 dvadura X * Initial Revision of Version 3.5 X * X*/ X X#include "extern.h" X#include "alloc.h" X#include "db.h" X X#define NO_ACTION 0 X#define START_PERCENT 1 X#define END_PERCENT 2 X#define ACCEPT 4 X#define EPSILON 8 X#define FAIL -1 X Xstatic NFAPTR _nfa = NIL( NFA ); X X XDFALINKPTR XMatch_dfa( buf )/* X================== X This routines runs all DFA's in parrallel and selects the one that best X matches the string. If no match then it returns NIL( DFA ) */ Xchar *buf; X{ X register NFAPTR nfa; X int adv; X DFALINKPTR dfa_list = NIL(DFALINK); X X DB_ENTER( "Match_dfa" ); X DB_PRINT( "dfa", ("Matching %s", buf) ); X X /* Run each of the DFA's on the input string in parallel, we terminate X * when all DFA's have either failed or ACCEPTED, if more than one DFA X * accepts we build a list of all accepting DFA's sorted on states with X * those matching in a higher numbered state heading the list. */ X X do { X adv = FALSE; X X for( nfa = _nfa; nfa != NIL( NFA ); nfa = nfa->next ) X if( nfa->status != (char) FAIL && nfa->status != (char) ACCEPT ) { X adv++; X nfa->status = Advance_dfa( nfa->dfa, buf ); X X /* Construct the list of matching DFA's */ X if( nfa->status == (char) ACCEPT ) { X DFALINKPTR dl; X X TALLOC( dl, 1, DFALINK ); X dl->dl_meta = nfa->dfa->node; X dl->dl_per = _substr( nfa->dfa->pstart, nfa->dfa->pend ); X dl->dl_state = nfa->dfa->n_states; X X if( dfa_list == NIL(DFALINK) ) X dfa_list = dl; X else { X DFALINKPTR tdli = dfa_list; X DFALINKPTR tdlp = NIL(DFALINK); X X for( ; tdli != NIL(DFALINK); tdli = tdli->dl_next ) { X if( dl->dl_state >= tdli->dl_state ) X break; X tdlp = tdli; X } X X if( tdli != NIL(DFALINK) ) { X tdli->dl_prev = dl; X dl->dl_next = tdli; X } X X if( tdlp != NIL(DFALINK) ) { X tdlp->dl_next = dl; X dl->dl_prev = tdlp; X } X else X dfa_list = dl; X } X X DB_PRINT( "dfa", ("Matched [%s]", dl->dl_meta->CE_NAME) ); X } X } X X buf++; X } X while ( adv ); X X for( nfa = _nfa; nfa != NIL( NFA ); nfa = nfa->next ) X nfa->status = nfa->dfa->c_state = 0; X X DB_RETURN( dfa_list ); X} X X X Xvoid XAdd_dfa( buf )/* X================ X This function adds a DFA to the string of DFA's that form the NFA. X The DFA is added at the head of the list because ordering is unimportant, X when we do a match all DFA are run in parallel. */ Xchar *buf; X{ X NFAPTR nfa; X X DB_ENTER( "Add_dfa" ); X DB_PRINT( "dfa", ("Adding dfa [%s]", buf) ); X X TALLOC( nfa, 1, NFA ); X nfa->dfa = Construct_dfa( buf ); X X if( _nfa != NIL(NFA) ) X nfa->next = _nfa; X X _nfa = nfa; X X DB_VOID_RETURN; X} X X X XDFAPTR XConstruct_dfa( pat )/* X====================== X This routine takes a string pattern which possibly contains a single % X and returns a dfa which will recognize the string, treating the % as X a token which accepts any char upto the next following char. So for X example: X X %.o ==> accepts f.o % = f, fred.o % = fred, fred.c FAILS X f%.o ==> accepts f.o % = , fred.o % = red, fred.c FAILS X X and so on. The function constructs the DFA and returns a pointer to the X DFA struct. */ X Xchar *pat; X{ X register int i; X register DFAPTR dfa; X register STATEPTR state; X int l = strlen( pat ) + 1; X int n; X int no_match = -1; X int pend = 0; X char *_strdup(); X X DB_ENTER( "Construct_dfa" ); X DB_PRINT( "dfa", ("Constructing dfa for %s", pat) ); X X n = l + 2; X X TALLOC( dfa, 1, DFA ); X TALLOC( dfa->states, n, STATE ); X X dfa->n_states = n; X dfa->node = Def_cell( pat, NIL(CELL) ); X X for( i=0; i<l; i++, pat++ ) { X state = dfa->states + i; X X if( pend == 1 ) { X state->action |= END_PERCENT; X pend++; X } X X switch( *pat ) { X case '%': /* % start state */ X if( pend > 0 ) X Error( "Only a single %% allowed in a target pattern" ); X pend++; X state->symbol = 0; X state->next = i+1; X state->no_match = no_match; X state->action |= START_PERCENT | EPSILON; X no_match = i+1; X break; X X case '\0': /* termination state */ X state->symbol = *pat; X state->next = -1; X state->no_match = no_match; X state->action |= ACCEPT; X break; X X default: /* generate a new state */ X state->symbol = *pat; X state->next = i+1; X state->no_match = no_match; X break; X } X } X X DB_RETURN( dfa ); X} X X X Xint XAdvance_dfa( dfa, pch )/* X========================= X This function takes the DFA that is provided and advances it to the next X states based on the value of *pch. The function returns either 0 for X everything ok, -1 for fail, and ACCEPT if the dfa accepts the string. */ XDFAPTR dfa; Xchar *pch; X{ X STATEPTR s; X char ch = *pch; X int done = FALSE; X int ret = 0; X X DB_ENTER( "Advance_dfa" ); X DB_PRINT( "dfa", ("Advancing [%s] by %c", dfa->node->CE_NAME, *pch) ); X X while( !done ) { X#ifdef DEBUG X if( dfa->c_state < 0 || dfa->c_state >= dfa->n_states ) X Fatal( "Internal, bad current dfa state %d in [%s]", X dfa->c_state, dfa->node->CE_NAME ); X#endif X X s = dfa->states + dfa->c_state; X X if( ch == '\0' && s->symbol != '\0' ) { X done = TRUE; /* FAIL string terminated first */ X ret = -1; X } X else if( s->action & EPSILON ) { /* set the start of % string */ X if( s->action & START_PERCENT ) dfa->pstart = pch; X dfa->c_state = s->next; X } X else if( s->symbol == ch ) { /* normal shift action */ X ret = s->action & ACCEPT; X X if( s->action & END_PERCENT ) dfa->pend = pch; X dfa->c_state = s->next; X done = TRUE; X } X else { /* non-match shift action */ X if( s->no_match == dfa->c_state || s->no_match == -1 ) { X done = TRUE; X if( s->no_match == -1 ) ret = -1; /* FAIL */ X } X X dfa->c_state = s->no_match; X } X } X X DB_RETURN( ret ); X} X X Xvoid XCheck_circle_dfa()/* X==================== X This function is called to test for circularities in the DFA lists X constructed from %-meta targets. */ X{ X register NFAPTR nfa; X X for( nfa = _nfa; nfa != NIL(NFA); nfa = nfa->next ) X if( Test_circle( nfa->dfa->node, TRUE ) ) X Fatal( "Detected circular dependency in inference graph at [%s]", X nfa->dfa->node->CE_NAME ); X} SHAR_EOF chmod 0440 percent.c || echo "restore of percent.c fails" echo "x - extracting path.c (Text)" sed 's/^X//' << 'SHAR_EOF' > path.c && X/* RCS -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/path.c,v 1.1 90/07/19 13:53:25 dvadura Exp $ X-- SYNOPSIS -- pathname manipulation code X-- X-- DESCRIPTION X-- Pathname routines to handle building and pulling appart X-- pathnames. 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: path.c,v $ X * Revision 1.1 90/07/19 13:53:25 dvadura X * Initial Revision of Version 3.5 X * X*/ X X#include "extern.h" X#include "alloc.h" X#include <string.h> X X/* X** Return the suffix portion of a filename, assumed to begin with a `.'. X*/ Xchar * XGet_suffix(name) Xchar *name; X{ X char *suff; X X if(name == NIL(char) || (suff = strrchr(name, '.')) == NIL(char)) X suff = ".NULL"; X X return (suff); X} X X X X/* X** Take dir and name, and return a path which has dir as the directory X** and name afterwards. X** X** N.B. Assumes that the dir separator string is in DirSepStr. X** Return path is built in a static buffer, if you need to use it X** again you must _strdup the result returned by Build_path. X*/ Xchar * XBuild_path(dir, name) Xchar *dir; Xchar *name; X{ X static char *path = NIL(char); X static unsigned buflen = 0; X int plen = 0; X int dlen = 0; X int len; X X if( dir != NIL(char) ) dlen = strlen( dir ); X if( name != NIL(char) ) plen = strlen( name ); X len = plen+dlen+strlen(DirSepStr)+1; X X if( len > buflen ) { X buflen = (len+16) & ~0xf; /* buf is always multiple of 16 */ X X if( path == NIL(char) ) X path = MALLOC( buflen, char ); X else X path = realloc( path, (unsigned) (buflen*sizeof(char)) ); X } X X *path = '\0'; X X if( dlen ) { X strcpy( path, dir ); X X if( strchr(DirSepStr, dir[dlen-1]) == NIL(char) ) X strcat( path, DirSepStr ); X } X X strcat( path, name ); X return( path ); X} SHAR_EOF chmod 0440 path.c || echo "restore of path.c fails" echo "x - extracting patchlvl.h (Text)" sed 's/^X//' << 'SHAR_EOF' > patchlvl.h && X/* dmake patch level, reset to 1 for each new version release. */ X X#define PATCHLEVEL 1 SHAR_EOF chmod 0440 patchlvl.h || echo "restore of patchlvl.h fails" echo "x - extracting parse.c (Text)" sed 's/^X//' << 'SHAR_EOF' > parse.c && X/* RCS -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/parse.c,v 1.1 90/07/19 13:53:23 dvadura Exp $ X-- SYNOPSIS -- parse the input, and perform semantic analysis X-- X-- DESCRIPTION X-- This file contains the routines that parse the input makefile and X-- call the appropriate routines to perform the semantic analysis and X-- build the internal dag. 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: parse.c,v $ X * Revision 1.1 90/07/19 13:53:23 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 Xvoid XParse( fil )/* X============== Parse the makefile input */ XFILE *fil; X{ X int state = NORMAL_SCAN; /* indicates current parser state */ X int group = FALSE; /* true if scanning a group rcpe */ X int rule = FALSE; /* have seen a recipe line */ X char *p; /* termporary pointer into Buffer */ X X DB_ENTER( "Parse" ); X X while( TRUE ) { X if( Get_line( Buffer, fil ) ) { X if( fil != NIL( FILE ) ) /* end of parsable input */ X Closefile(); X X Bind_rules_to_targets( F_DEFAULT ); X if( group ) Fatal( "Incomplete rule recipe group detected" ); X X DB_VOID_RETURN; X } X else X switch( state ) { X case RULE_SCAN: X X /* Check for the `[' that starts off a group rule definition. It X * must appear as the first non-white space X * character in the line. */ X X p = _strspn( Buffer, " \t" ); X if( Set_group_attributes( p ) ) { X if( rule && group ) X Fatal( "Cannot mix single and group recipe lines" ); X else X group = TRUE; X X rule = TRUE; X X break; /* ignore the group start */ X } X X if( group ) { X if( *p != ']' ) { X Add_recipe_to_list( Buffer, TRUE, TRUE ); X rule = TRUE; X } X else X state = NORMAL_SCAN; X } X else { X if( *Buffer == '\t' ) { X Add_recipe_to_list( Buffer, FALSE, FALSE ); X rule = TRUE; X } X else if( *p == ']' ) X Fatal( "Found unmatched ']'" ); X else if( *Buffer ) X state = NORMAL_SCAN; X } X X if( state == RULE_SCAN ) break; /* ie. keep going */ X X Bind_rules_to_targets( (group) ? F_GROUP: F_DEFAULT ); X X rule = FALSE; X if( group ) { X group = FALSE; X break; X } X /*FALLTRHOUGH*/ X X /* In this case we broke out of the rule scan because we do not X * have a recipe line that begins with a <TAB>, so lets X * try to scan the thing as a macro or rule definition. */ X X X case NORMAL_SCAN: X if( !*Buffer ) continue; /* we have null input line */ X X /* STUPID AUGMAKE uses "include" at the start of a line as X * a signal to include a new file, so let's look for it. X * if we see it replace it by .INCLUDE: and stick this back X * into the buffer. */ X if( !strncmp( "include", Buffer, 7 ) && X (Buffer[7] == ' ' || Buffer[7] == '\t') ) X { X char *tmp; X X tmp = _strjoin( ".INCLUDE:", Buffer+7, -1, FALSE ); X strcpy( Buffer, tmp ); X FREE( tmp ); X } X X /* look for a macro definition, they all contain an = sign X * if we fail to recognize it as a legal macro op then try to X * parse the same line as a rule definition, it's one or the X * other */ X X if( Parse_macro(Buffer, M_DEFAULT) ) break;/* it's a macro def */ X if( Parse_rule_def( &state ) ) break;/* it's a rule def */ X X /* if just blank line then ignore it */ SHAR_EOF echo "End of part 5" echo "File parse.c is continued in part 6" echo "6" > s2_seq_.tmp exit 0