LCOV - code coverage report
Current view: top level - libreoffice/dmake - rulparse.c (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 420 652 64.4 %
Date: 2012-12-17 Functions: 15 21 71.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             : --
       3             : -- SYNOPSIS
       4             : --      Perform semantic analysis on input
       5             : --
       6             : -- DESCRIPTION
       7             : --  This code performs semantic analysis on the input, and builds
       8             : --  the complex internal datastructure that is used to represent
       9             : --  the user makefile.
      10             : --
      11             : -- AUTHOR
      12             : --      Dennis Vadura, dvadura@dmake.wticorp.com
      13             : --
      14             : -- WWW
      15             : --      http://dmake.wticorp.com/
      16             : --
      17             : -- COPYRIGHT
      18             : --      Copyright (c) 1996,1997 by WTI Corp.  All rights reserved.
      19             : --
      20             : --      This program is NOT free software; you can redistribute it and/or
      21             : --      modify it under the terms of the Software License Agreement Provided
      22             : --      in the file <distribution-root>/readme/license.txt.
      23             : --
      24             : -- LOG
      25             : --      Use cvs log to obtain detailed change logs.
      26             : */
      27             : 
      28             : #include "extern.h"
      29             : 
      30             : /* prototypes for local functions */
      31             : static  void    _add_indirect_prereq ANSI((CELLPTR));
      32             : static  int     _add_root ANSI((CELLPTR));
      33             : static  CELLPTR _build_graph ANSI((int, CELLPTR, CELLPTR));
      34             : static  char*   _build_meta ANSI((char*));
      35             : static  int _do_magic ANSI((int, char*, CELLPTR, CELLPTR, t_attr, char*));
      36             : static  void    _do_special ANSI((int, int, t_attr,char*,CELLPTR,CELLPTR,int*));
      37             : static  int _do_targets ANSI((int, t_attr, char*, CELLPTR, CELLPTR));
      38             : static  t_attr  _is_attribute ANSI((char*));
      39             : static  int _is_special ANSI((char*));
      40             : static  char*   _is_magic ANSI((char*));
      41             : static  int _is_percent ANSI((char*));
      42             : static  CELLPTR _make_multi ANSI((CELLPTR));
      43             : static  CELLPTR _replace_cell ANSI((CELLPTR,CELLPTR,CELLPTR));
      44             : static  void    _set_attributes ANSI((t_attr, char*, CELLPTR ));
      45             : static  void    _stick_at_head ANSI((CELLPTR, CELLPTR));
      46             : static  void    _set_global_attr ANSI((t_attr));
      47             : 
      48             : 
      49             : /* static variables that must persist across invocation of Parse_rule_def */
      50             : static CELLPTR    _sv_targets = NIL(CELL);
      51             : static STRINGPTR  _sv_rules   = NIL(STRING); /* first recipe element. */
      52             : static STRINGPTR  _sv_crule   = NIL(STRING); /* current/last recipe element. */
      53             : static CELLPTR    _sv_edgel   = NIL(CELL);
      54             : static LINKPTR    _sv_ind_prq = NIL(LINK);   /* indirect prerequisites for % cell */
      55             : static int    _sp_target  = FALSE;
      56             : static t_attr     _sv_attr;
      57             : static int        _sv_flag;
      58             : static int    _sv_op;
      59             : static char      *_sv_setdir;
      60             : static char   _sv_globprq_only = 0;
      61             : 
      62             : /* Define for global attribute mask (A_SWAP == A_WINPATH) */
      63             : #define A_GLOB   (A_PRECIOUS | A_SILENT | A_IGNORE | A_EPILOG | A_SWAP |\
      64             :           A_SHELL | A_PROLOG | A_NOINFER | A_SEQ | A_MKSARGS )
      65             : 
      66             : 
      67             : PUBLIC int
      68       27336 : Parse_rule_def( state )/*
      69             : =========================
      70             :    Parse the rule definition contained in Buffer, and modify the state
      71             :    if appropriate.  The function returns 0, if the definition is found to
      72             :    be an illegal rule definition, and it returns 1 if it is a rule definition.
      73             :    */
      74             : int *state;
      75             : {
      76             :   TKSTR     input;      /* input string struct for token search   */
      77             :   CELLPTR   targets;    /* list of targets if any         */
      78             :   CELLPTR   prereq;     /* list of prereq if any          */
      79             :   CELLPTR   prereqtail; /* tail of prerequisite list          */
      80             :   CELLPTR   cp;     /* temporary cell pointer for list making */
      81             :   char  *result;    /* temporary storage for result       */
      82             :   char      *tok;       /* temporary pointer for tokens       */
      83             :   char         *set_dir;       /* value of setdir attribute              */
      84             :   char      *brk;       /* break char list for Get_token      */
      85             :   char         *firstrcp;      /* first recipe line, from ; in rule line */
      86             :   t_attr       attr;           /* sum of attribute flags for current tgts*/
      87             :   t_attr    at;     /* temp place to keep an attribute code   */
      88             :   int       op;     /* rule operator              */
      89             :   int       special;    /* indicate special targets in rule   */
      90             :   int       augmeta;    /* indicate .<suffix> like target     */
      91             :   int       percent;    /* indicate percent rule target       */
      92             :   int       percent_prq;    /* indicate mixed %-rule prereq possible  */
      93             : 
      94             :   DB_ENTER( "Parse_rule_def" );
      95             : 
      96       27336 :   op          = 0;
      97       27336 :   attr       = 0;
      98       27336 :   special    = 0;
      99       27336 :   augmeta    = 0;
     100       27336 :   percent    = 0;
     101       27336 :   set_dir    = NIL( char );
     102       27336 :   targets    = NIL(CELL);
     103       27336 :   prereq     = NIL(CELL);
     104       27336 :   prereqtail = NIL(CELL);
     105       27336 :   percent_prq = 0;
     106             : 
     107             :   /* Check to see if the line is of the form:
     108             :    *    targets : prerequisites; first recipe line
     109             :    * If so remember the first_recipe part of the line. */
     110             : 
     111       27336 :   firstrcp = strchr( Buffer, ';' );
     112       27336 :   if( firstrcp != NIL( char ) ) {
     113        3312 :     *firstrcp++ = 0;
     114        3312 :     firstrcp = DmStrSpn( firstrcp, " \t" );
     115             :   }
     116             : 
     117       27336 :   result = Expand( Buffer );
     118             :   /* Remove CONTINUATION_CHAR, keep the <nl> */
     119       51868 :   for( brk=strchr(result,CONTINUATION_CHAR); brk != NIL(char); brk=strchr(brk,CONTINUATION_CHAR) )
     120       24532 :     if( brk[1] == '\n' )
     121       24532 :       *brk = ' ';
     122             :     else
     123           0 :       brk++;
     124             : 
     125             :   DB_PRINT( "par", ("Scanning: [%s]", result) );
     126             : 
     127       27336 :   SET_TOKEN( &input, result );
     128       27336 :   brk = ":-^!|";
     129       27336 :   Def_targets = TRUE;
     130             : 
     131             :   /* Scan the input rule line collecting targets, the operator, and any
     132             :    * prerequisites.  Stop when we run out of targets and prerequisites. */
     133             : 
     134      169588 :   while( *(tok = Get_token( &input, brk, TRUE )) != '\0' )
     135      114916 :     if( !op ) {
     136             :       /* we are scanning targets and attributes
     137             :        * check to see if token is an operator.  */
     138             : 
     139       59940 :       op = Rule_op( tok );
     140             : 
     141       59940 :       if( !op ) {
     142             :         /* Define a new cell, or get pointer to pre-existing cell.  */
     143             :         /* Do we need cells for attributes? If not move the definition
     144             :          * to the target part.  */
     145       33646 :         cp = Def_cell( tok );
     146             :         /* A $ character indicates either a literal $ in the pathname (this
     147             :          * was broken before) or a dynamic macro (this is a syntax error).
     148             :          * FIXME: Here would be the place to add a sanity check. */
     149             :         DB_PRINT( "par", ("tg_cell [%s]", tok) );
     150             : 
     151       33646 :         if( (at = _is_attribute(tok)) != 0 ) {
     152             :           /* Ignore .SILENT when -vr is active. */
     153        2592 :           if( (Verbose & V_FORCEECHO) && (at == A_SILENT) )
     154           0 :             at = 0;
     155             : 
     156             :           /* Logically OR the attributes specified into one main
     157             :            * ATTRIBUTE mask. */
     158             : 
     159        2592 :           if( at == A_SETDIR ) {
     160           0 :             if( set_dir != NIL( char ) )
     161           0 :               Warning( "Multiple .SETDIR attribute ignored" );
     162             :             else
     163           0 :               set_dir = DmStrDup( tok );
     164             :           }
     165             : 
     166        2592 :           attr |= at;
     167             :         }
     168             :         else {
     169             :           /* Not an attribute, this must be a target. */
     170             :           int tmp;
     171             : 
     172       31054 :           tmp = _is_special( tok );
     173             : 
     174       31054 :           if( _is_percent( tok ) ) {
     175             :             /* First %-target checks if there were non-%-targets before. */
     176       11512 :             if( !percent && targets != NIL(CELL) )
     177           0 :               Fatal( "A %%-target must not be mixed with non-%%-targets, offending target [%s]", tok );
     178             : 
     179       11512 :             percent++;
     180       11512 :             cp->ce_flag |= F_PERCENT;
     181             :           } else {
     182       19542 :             if( percent )
     183           0 :               Fatal( "A non-%%-target must not be mixed with %%-targets, offending target [%s]", tok );
     184             :           }
     185             : 
     186       31054 :           if( _is_magic( tok ) ) {
     187             :             /* Check that AUGMAKE targets are not mixed with other
     188             :              * targets. The return value of _is_magic() is discarded and
     189             :              * calculated again in _do_targets() if this rule definition
     190             :              * really is a .<suffix> like target.
     191             :              * If we would allow only one target per line we could easily
     192             :              * store the result for later, but for multiple .<suffix>
     193             :              * targets this creates too much overhead.
     194             :              * These targets should be rare (obsolete?) anyway. */
     195        8830 :             if( !augmeta && targets != NIL(CELL) )
     196           0 :               Fatal( "An AUGMAKE meta target must not be mixed with non AUGMAKE meta targets, offending target [%s]", tok );
     197             : 
     198        8830 :             augmeta++;
     199        8830 :             cp->ce_flag |= F_MAGIC; /* do_magic will also add F_PERCENT later. */
     200             :           } else {
     201       22224 :             if( augmeta )
     202           0 :               Fatal( "A non AUGMAKE meta target must not be mixed with AUGMAKE meta targets, offending target [%s]", tok );
     203             :           }
     204             : 
     205       31054 :           if( special )
     206           0 :             Fatal( "Special target must appear alone, found [%s]", tok );
     207       31054 :           else if( !(cp->ce_flag & F_MARK) ) {
     208             :             /* Targets are kept in this list in lexically sorted order.
     209             :              * This allows for easy equality comparison of target
     210             :              * sets.*/
     211             :             CELLPTR prev,cur;
     212      358136 :             for(prev=NIL(CELL),cur=targets;cur;prev=cur,cur=cur->ce_link)
     213      327304 :               if(strcmp(cur->CE_NAME,cp->CE_NAME) > 0)
     214         222 :                 break;
     215             : 
     216       31054 :             cp->ce_link = cur;
     217             : 
     218       31054 :             if (!prev)
     219       26492 :               targets = cp;
     220             :             else
     221        4562 :               prev->ce_link = cp;
     222             : 
     223       31054 :             cp->ce_flag |= F_MARK | F_EXPLICIT;
     224       31054 :             special = tmp;
     225             :           }
     226             :           else
     227           0 :             Warning( "Duplicate target [%s]", cp->CE_NAME );
     228             :         }
     229             :       }
     230             :       else {
     231             :         /* found an operator so empty out break list and clear mark
     232             :          * bits on target list, setting them all to F_VISITED*/
     233             : 
     234       26294 :         brk  = "";
     235       57348 :         for( cp=targets; cp != NIL(CELL); cp=cp->ce_link ) {
     236       31054 :           cp->ce_flag ^= F_MARK;
     237       31054 :           cp->ce_flag |= F_VISITED;
     238             :         }
     239             : 
     240       26294 :         Def_targets = FALSE;
     241             :       }
     242             :     }
     243             :     else {
     244             :       /* Scanning prerequisites so build the prerequisite list.  We use
     245             :        * F_MARK flag to make certain we have only a single copy of the
     246             :        * prerequisite in the list */
     247             : 
     248       54976 :       cp = Def_cell( tok );
     249             : 
     250             :       /* %-prerequisits require eiter a %-target or this might be a rule of
     251             :        * the "ATTRIBUTE_LIST : targets" form. */
     252       54976 :       if( _is_percent( tok ) ) {
     253        9162 :         if( percent || ((targets == NIL(CELL)) && attr) )
     254        9162 :           percent_prq = 1;
     255             :         else
     256           0 :           Fatal( "Syntax error in %% rule, missing %% target");
     257             :       }
     258             : 
     259       54976 :       if( cp->ce_flag & F_VISITED ) {
     260           0 :         if( cp->ce_attr & A_COMPOSITE )
     261           0 :           continue;
     262             :         else
     263           0 :           Fatal( "Detected circular dependency in graph at [%s]",
     264           0 :                  cp->CE_NAME );
     265             :       }
     266       54976 :       else if( !(cp->ce_flag & F_MARK) ) {
     267             :         DB_PRINT( "par", ("pq_cell [%s]", tok) );
     268       54976 :         cp->ce_flag |= F_MARK;
     269             : 
     270       54976 :         if( prereqtail == NIL(CELL) )   /* keep prereq's in order */
     271       20320 :           prereq = cp;
     272             :         else
     273       34656 :           prereqtail->ce_link = cp;
     274             : 
     275       54976 :         prereqtail = cp;
     276       54976 :         cp->ce_link = NIL(CELL);
     277             :       }
     278           0 :       else if( !(cp->ce_attr & A_LIBRARY) && (Verbose & V_WARNALL))
     279           0 :         Warning("Duplicate entry [%s] in prerequisite list",cp->CE_NAME);
     280             :     }
     281             : 
     282             :   /* Check to see if we have a percent rule that has only global
     283             :    * prerequisites, i.e. they are of the form: "%.a : foo".
     284             :    * If so then set the flag so that later on, we don't issue
     285             :    * an error if such targets supply an empty set of rules. */
     286             : 
     287       27336 :   if( percent && !percent_prq && (prereq != NIL(CELL)) )
     288         730 :     _sv_globprq_only = 1;
     289             : 
     290             :   /* It's ok to have targets with attributes, and no prerequisites, but it's
     291             :    * not ok to have no targets and no attributes, or no operator */
     292             : 
     293       27336 :   CLEAR_TOKEN( &input ); FREE(result); result = NIL(char);
     294       27336 :   if( !op ) {
     295             :     DB_PRINT( "par", ("Not a rule [%s]", Buffer) );
     296        1042 :     DB_RETURN( 0 );
     297             :   }
     298             : 
     299             :   /* More than one percent target didn't work with prior versions. */
     300             : #if 0
     301             :   if( (percent > 1) && !(op & R_OP_OR) )
     302             :     Warning( "Prior to dmake 4.5 only one\n"
     303             :              "%%-target per target-definition worked reliably. Check your makefiles.\n" );
     304             : #endif
     305             : 
     306       26294 :   if( !attr && targets == NIL(CELL) ) {
     307           0 :     Fatal( "Missing targets or attributes in rule" );
     308           0 :     if( set_dir != NIL( char )) FREE( set_dir );
     309           0 :     DB_RETURN( 0 );
     310             :   }
     311             : 
     312             :   /* We have established we have a legal rules line, so we must process it.
     313             :    * In doing so we must handle any special targets.  Special targets must
     314             :    * appear alone possibly accompanied by attributes.
     315             :    * NOTE:  special != 0  ==> targets != NIL(CELL) */
     316             : 
     317       26294 :   if( prereqtail != NIL(CELL) ) prereqtail->ce_link = NIL(CELL);
     318             : 
     319             :   /* Clear out MARK bits used in duplicate checking.  I originally wanted
     320             :    * to do this as the lists get processed but that got too error prone
     321             :    * so I bit the bullit and added these two loops. */
     322             : 
     323       26294 :   for( cp=prereq;  cp != NIL(CELL); cp=cp->ce_link ) cp->ce_flag &= ~F_MARK;
     324       26294 :   for( cp=targets; cp != NIL(CELL); cp=cp->ce_link ) cp->ce_flag &= ~F_VISITED;
     325             : 
     326             :   /* Check to see if the previous recipe was bound, if not the call
     327             :    * Bind_rules_to_targets() to bind the recipe (_sv_rules) to the
     328             :    * target(s) (_sv_targets). */
     329             :   /* was:  if( _sv_rules != NIL(STRING) ) Bind_rules_to_targets( F_DEFAULT );*/
     330             :   /* Only Add_recipe_to_list() sets _sv_rules and Bind_rules_to_targets()
     331             :    * clears the (static) variables again.  Bind_rules_to_targets() is
     332             :    * (should be) called after State is leaving RULE_SCAN in Parse().
     333             :    * Abort if there are unbound recipes. FIXME: Remove this paragraph
     334             :    * if this never occurs.  */
     335       26294 :   if( _sv_rules != NIL(STRING) )
     336           0 :     Fatal( "Internal Error: _sv_rules not empty." );
     337             : 
     338             :   /* Add the first recipe line to the list */
     339       26294 :   if( firstrcp != NIL( char ) )
     340        3312 :     Add_recipe_to_list( firstrcp, TRUE, FALSE );
     341             : 
     342             :   /* Save these prior to calling _do_targets, since _build_graph needs the
     343             :    * _sv_setdir value for matching edges. */
     344       26294 :   _sv_op     = op;
     345       26294 :   _sv_setdir = set_dir;
     346             : 
     347       26294 :   if( special )
     348             :     /* _do_special() can alter *state */
     349        8830 :     _do_special( special, op, attr, set_dir, targets, prereq, state );
     350             :   else
     351       17464 :     *state = _do_targets( op, attr, set_dir, targets, prereq );
     352             : 
     353       26294 :   if( (*state != RULE_SCAN) && (_sv_rules != NIL(STRING)) )
     354           0 :     Fatal( "Unexpected recipe found." );
     355             : 
     356       26294 :   DB_RETURN( 1 );
     357             : }
     358             : 
     359             : 
     360             : PUBLIC int
     361       59940 : Rule_op( op )/*
     362             : ================
     363             :    Check the passed in op string and map it to one of the rule operators */
     364             : char *op;
     365             : {
     366       59940 :    int ret = 0;
     367             : 
     368             :    DB_ENTER( "rule_op" );
     369             : 
     370       59940 :    if( *op == TGT_DEP_SEP ) {
     371       26294 :       ret = R_OP_CL;
     372       26294 :       op++;
     373             : 
     374             :       /* All rule operations begin with a :, but may include any one of the
     375             :        * four modifiers.  In order for the rule to be properly mapped we must
     376             :        * check for each of the modifiers in turn, building up our return bit
     377             :        * string. */
     378             : 
     379       53060 :       while( *op && ret )
     380         472 :          switch( *op ) {
     381           0 :         case ':': ret |= R_OP_DCL; op++; break;
     382           0 :         case '!': ret |= R_OP_BG;  op++; break;
     383           0 :         case '^': ret |= R_OP_UP;  op++; break;
     384         368 :         case '-': ret |= R_OP_MI;  op++; break;
     385         104 :         case '|': ret |= R_OP_OR;  op++; break;
     386             : 
     387           0 :         default : ret  = 0;  /* an invalid modifier, chuck whole string */
     388             :          }
     389             : 
     390       26294 :       if( *op != '\0' ) ret = 0;
     391             :    }
     392             : 
     393       59940 :    DB_RETURN( ret );
     394             : }
     395             : 
     396             : 
     397             : PUBLIC void
     398       44922 : Add_recipe_to_list( rule, white_too, no_check )/*
     399             : =================================================
     400             :         Take the provided string and add it to the list of recipe lines
     401             :     we are saving to be added to the list of targets we have built
     402             :     previously.  If white_too == TRUE add the rule EVEN IF it contains only
     403             :         an empty string (whitespace is handled by Def_recipe()). */
     404             : char *rule;
     405             : int  white_too;
     406             : int  no_check;
     407             : {
     408             :    DB_ENTER( "Add_recipe_to_list" );
     409             : 
     410       44922 :    if( rule != NIL( char ) && (*rule != '\0' || white_too) ) {
     411             :       DB_PRINT( "par", ("Adding recipe [%s]", rule) );
     412       44922 :       _sv_crule = Def_recipe( rule, _sv_crule, white_too, no_check );
     413             : 
     414             :       /* If _sv_rules is not yet set this must be the first recipe line,
     415             :        * remember it. */
     416       44922 :       if( _sv_rules == NIL(STRING) )
     417       15920 :          _sv_rules = _sv_crule;
     418             :    }
     419             : 
     420       44922 :    DB_VOID_RETURN;
     421             : }
     422             : 
     423             : 
     424             : PUBLIC void
     425       18878 : Bind_rules_to_targets( flag )/*
     426             : ===============================
     427             :         Take the recipe lines we have defined and bind them with proper attributes
     428             :         to the targets that were previously defined in the parse.  The
     429             :         attributes that get passed here are merged with those that are were
     430             :         previously defined.  (namely attribute F_SINGLE) */
     431             : int flag;
     432             : {
     433             :    CELLPTR tg;             /* pointer to current target in list */
     434             :    LINKPTR lp;         /* pointer to link cell      */
     435             :    int     magic;          /* TRUE if target of % or .xxx.yyy form */
     436             :    int     tflag;          /* TRUE if we assigned targets here  */
     437             : 
     438             :    DB_ENTER( "Bind_rules_to_targets" );
     439             : 
     440             :    /* This line is needed since Parse may call us twice when the last
     441             :     * GROUP rule appears at the end of file.  In this case the rules
     442             :     * have already been bound and we want to ignore them. */
     443             : 
     444       18878 :    if( _sv_targets == NIL(CELL) ) { DB_VOID_RETURN; }
     445             : 
     446       18566 :    tflag  = FALSE;
     447       18566 :    flag  |= (_sv_flag & F_SINGLE);
     448       18566 :    flag  |= ((_sv_attr & A_GROUP) ? F_GROUP : 0);
     449             : 
     450       41894 :    for( tg = _sv_targets; tg != NIL(CELL); tg = tg->ce_link ) {
     451             :       DB_PRINT( "par", ("Binding to %s, %04x", tg->CE_NAME, tg->ce_flag) );
     452       23328 :       magic = tg->ce_flag & F_PERCENT;
     453             : 
     454             : 
     455             :       /* NOTE:  For targets that are magic or special we ignore any
     456             :        * previously defined rules, ie. We throw away the old definition
     457             :        * and use the new, otherwise we complain. */
     458       23328 :       if( !(tg->ce_flag & F_MULTI) && !magic && (tg->CE_RECIPE != NIL(STRING))
     459         314 :       && !_sp_target && (_sv_rules != NIL(STRING)) )
     460           0 :          Fatal( "Multiply defined recipe for target %s", tg->CE_NAME );
     461             : 
     462       23880 :       if( (magic || _sp_target) && (_sv_rules == NIL(STRING)) &&
     463         552 :       !(tg->ce_flag & F_SPECIAL) && !_sv_globprq_only )
     464           0 :          Warning( "Empty recipe for special or meta target %s", tg->CE_NAME );
     465             : 
     466       23328 :       if( magic ) {
     467             :      CELLPTR ep;
     468             : 
     469       23032 :      for( ep=_sv_edgel; ep != NIL(CELL); ep=ep->ce_link ) {
     470             :         DB_PRINT( "par", ("ep address: %#x", ep) );
     471             :         /* %.xx :| '%.yy' abc xx '%.tt' ; touch $@
     472             :          * loops here ... */
     473       11520 :         _set_attributes( _sv_attr, _sv_setdir, ep );
     474       11520 :         ep->ce_flag |= (F_TARGET|flag);
     475             : 
     476       11520 :         if( _sv_rules != NIL(STRING) ) {
     477       11520 :            ep->ce_recipe  = _sv_rules;
     478       11520 :            ep->ce_indprq  = _sv_ind_prq;
     479             :         }
     480             :      }
     481             :       }
     482             :       else {
     483       11816 :      tg->ce_attr |= _sv_attr;
     484       11816 :      tg->ce_flag |= flag;
     485             : 
     486       11816 :      if( _sv_rules != NIL(STRING) ) {
     487        4664 :         tg->ce_recipe  = _sv_rules;
     488        4664 :         tg->ce_flag   |= F_RULES | F_TARGET;
     489             : 
     490             :         /* Bind the current set of prerequisites as belonging to the
     491             :          * original recipe given for the target */
     492       35466 :         for( lp=tg->ce_prq; lp != NIL(LINK); lp = lp->cl_next )
     493       30802 :           if( !(lp->cl_flag & F_VISITED) ) lp->cl_flag |= F_TARGET;
     494             :          }
     495       25906 :      else for( lp=tg->ce_prq; lp != NIL(LINK); lp = lp->cl_next )
     496       18754 :         lp->cl_flag |= F_VISITED;
     497             :       }
     498             : 
     499       23328 :       tflag |= _add_root(tg);
     500             :    }
     501             : 
     502       18566 :    if( tflag ) Target = TRUE;
     503       18566 :    if( _sv_setdir ) FREE(_sv_setdir);
     504       18566 :    _sv_rules   = NIL(STRING);
     505       18566 :    _sv_crule   = NIL(STRING);
     506       18566 :    _sv_targets = NIL(CELL);
     507       18566 :    _sv_ind_prq = NIL(LINK);
     508       18566 :    _sv_edgel   = NIL(CELL);
     509       18566 :    _sp_target  = FALSE;
     510       18566 :    _sv_globprq_only = 0;
     511             : 
     512       18566 :    DB_VOID_RETURN;
     513             : }
     514             : 
     515             : 
     516             : 
     517             : PUBLIC int
     518       88910 : Set_group_attributes( list )/*
     519             : ==============================
     520             :     Scan list looking for the standard @,-,% and + (as in recipe line
     521             :     defs) (+ is set but ignored for group recipes)
     522             :     and set the flags accordingly so that they apply when we bind the
     523             :     rules to the appropriate targets.
     524             :     Return TRUE if group recipe start '[' was found, otherwise FALSE.  */
     525             : char *list;
     526             : {
     527       88910 :    int res = FALSE;
     528             :    char *s;
     529             : 
     530       88910 :    if ( !((_sv_attr|Glob_attr)&A_IGNOREGROUP) ) {
     531       88910 :       s = DmStrSpn(list,"@-%+ \t");
     532       88910 :       res = (*s == '[');
     533       88910 :       if( res ) {
     534             :      /* Check for non-white space characters after the [. */
     535           0 :      for( s++; *s && iswhite(*s) ; s++ )
     536             :         ;
     537           0 :      if( *s )
     538           0 :         Warning("Found non-white space character after '[' in [%s].", list);
     539             : 
     540           0 :      _sv_attr |= Rcp_attribute(list);
     541             :       }
     542             :    }
     543             : 
     544       88910 :    return(res);
     545             : }
     546             : 
     547             : 
     548             : static void
     549        8830 : _do_special( special, op, attr, set_dir, target, prereq, state )/*
     550             : ==================================================================
     551             :    Process a special target (always only a single target).  So far the only
     552             :    special targets we have are those recognized by the _is_special function.
     553             :    Some of the special targets can take recipes, they call _do_targets()
     554             :    and (implicitly) set *state to to RULE_SCAN. Otherwise *state remains
     555             :    unaffected, i.e. NORMAL_SCAN.
     556             : 
     557             :    target is always only a single special target.
     558             : 
     559             :    NOTE:  For the cases of .IMPORT, and .INCLUDE, the cells created by the
     560             :          parser are never freed.  This is due to the fact that it is too much
     561             :       trouble to get them out of the hash table once they are defined, and
     562             :       if they are per chance used again it will be ok, anyway, since the
     563             :       cell is not really used by the code below.  */
     564             : 
     565             : int special;
     566             : int op;
     567             : t_attr  attr;
     568             : char    *set_dir;
     569             : CELLPTR target;
     570             : CELLPTR prereq;
     571             : int     *state;
     572             : {
     573             :   HASHPTR   hp;     /* pointer to macro def cell        */
     574             :   CELLPTR   cp;     /* temporary pointer into cells list    */
     575             :   CELLPTR   dp;     /* pointer to directory dir cell    */
     576             :   LINKPTR   lp;     /* pointer at prerequisite list     */
     577             :   char      *dir;       /* current dir to prepend       */
     578             :   char      *path;      /* resulting path to try to read    */
     579             :   char  *name;      /* File name for processing a .INCLUDE  */
     580             :   char      *tmp;       /* temporary string pointer     */
     581             :   FILE  *fil;       /* File descriptor returned by Openfile */
     582             : 
     583             :   DB_ENTER( "_do_special" );
     584             : 
     585        8830 :   target->ce_flag = F_SPECIAL;  /* mark the target as special */
     586             : 
     587        8830 :   switch( special ) {
     588             :   case ST_EXPORT:
     589        4984 :     for( ; prereq != NIL(CELL); prereq = prereq->ce_link ) {
     590             :       DB_PRINT( "par", ("Exporting [%s]", prereq->CE_NAME) );
     591        2774 :       hp = GET_MACRO( prereq->CE_NAME );
     592             : 
     593        2774 :       if( hp != NIL(HASH) ) {
     594        2600 :         char *tmpstr = hp->ht_value;
     595             : 
     596        2600 :         if( tmpstr == NIL(char) ) tmpstr = "";
     597             : 
     598        2600 :         if( Write_env_string( prereq->CE_NAME, tmpstr ) != 0 )
     599           0 :           Warning( "Could not export %s", prereq->CE_NAME );
     600             :       }
     601             :     }
     602        2210 :     break;
     603             : 
     604             :     /* Simply cause the parser to fail on the next input read */
     605             :   case ST_EXIT:
     606           0 :     Skip_to_eof = TRUE;
     607           0 :     break;
     608             : 
     609             :   case ST_IMPORT:
     610         736 :     for( ; prereq != NIL(CELL); prereq = prereq->ce_link ) {
     611             :       char *tmpstr;
     612             : 
     613             :       DB_PRINT( "par", ("Importing [%s]", prereq->CE_NAME) );
     614             : 
     615         368 :       if( strcmp(prereq->CE_NAME, ".EVERYTHING") == 0 ) {
     616         184 :         t_attr sattr = Glob_attr;
     617         184 :         Glob_attr |= A_SILENT;
     618             : 
     619         184 :         ReadEnvironment();
     620             : 
     621         184 :         Glob_attr = sattr;
     622             :       }
     623             :       else {
     624         184 :         tmpstr = Read_env_string( prereq->CE_NAME );
     625             : 
     626         184 :         if( tmpstr != NIL(char) )
     627         184 :           Def_macro(prereq->CE_NAME, tmpstr, M_EXPANDED|M_LITERAL);
     628             :         else
     629           0 :           if( !((Glob_attr | attr) & A_IGNORE) )
     630           0 :             Fatal("Imported macro `%s' not found",prereq->CE_NAME);
     631             :       }
     632             :     }
     633             : 
     634         368 :     attr &= ~A_IGNORE;
     635         368 :     break;
     636             : 
     637             :   case ST_INCLUDE:
     638             :     {
     639        4964 :       int pushed     = FALSE;
     640        4964 :       int first      = (attr & A_FIRST);
     641        4964 :       int ignore     = (((Glob_attr | attr) & A_IGNORE) != 0);
     642        4964 :       int found      = FALSE;
     643        4964 :       int noinf      = (attr & A_NOINFER);
     644        4964 :       LINKPTR prqlnk = NIL(LINK);
     645        4964 :       LINKPTR prqlst = NIL(LINK);
     646             : 
     647        4964 :       if( prereq == NIL(CELL) )  Fatal( "No .INCLUDE file(s) specified" );
     648             : 
     649        4964 :       dp = Def_cell( ".INCLUDEDIRS" );
     650             : 
     651        4964 :       if( (attr & A_SETDIR) && *(dir = strchr(set_dir, '=')+1) )
     652           0 :         pushed = Push_dir( dir, ".INCLUDE", ignore );
     653             : 
     654        9928 :       for( cp=prereq; cp != NIL(CELL); cp = cp->ce_link ) {
     655             :         LINKPTR ltmp;
     656        4964 :         TALLOC(ltmp, 1, LINK);
     657        4964 :         ltmp->cl_prq = cp;
     658             : 
     659        4964 :         if( prqlnk == NIL(LINK) )
     660        4964 :           prqlst = ltmp;
     661             :         else
     662           0 :           prqlnk->cl_next = ltmp;
     663             : 
     664        4964 :         prqlnk = ltmp;
     665             :       }
     666             : 
     667        9928 :       for( ; prqlst != NIL(LINK); FREE(prqlst), prqlst=prqlnk ) {
     668        4964 :         prqlnk = prqlst->cl_next;
     669        4964 :         cp     = prqlst->cl_prq;
     670        4964 :         name   = cp->CE_NAME;
     671             : 
     672             :         /* Leave this here, it ensures that prqlst gets propely free'd */
     673        4964 :         if ( first && found )
     674           0 :           continue;
     675             : 
     676        4964 :         if( *name == '<' ) {
     677             :           /* We have a file name enclosed in <....>
     678             :            * so get rid of the <> arround the file name */
     679             : 
     680           0 :           name++;
     681           0 :           if( (tmp = strrchr( name, '>' )) != NIL( char ) )
     682           0 :             *tmp = 0;
     683             : 
     684           0 :           if( If_root_path( name ) )
     685           0 :             fil = Openfile( name, FALSE, FALSE );
     686             :           else
     687           0 :             fil = NIL(FILE);
     688             :         }
     689             :         else
     690        4964 :           fil = Openfile( name, FALSE, FALSE );
     691             : 
     692        4964 :         if( fil == NIL(FILE) && !If_root_path( name ) ) { /*if true ==> not found in current dir*/
     693             : 
     694             :           /* Now we must scan the list of prerequisites for .INCLUDEDIRS
     695             :            * looking for the file in each of the specified directories.
     696             :            * if we don't find it then we issue an error.  The error
     697             :            * message is suppressed if the .IGNORE attribute of attr is
     698             :            * set.  If a file is found we call Parse on the file to
     699             :            * perform the parse and then continue on from where we left
     700             :            * off.  */
     701             : 
     702       11934 :           for(lp=dp->CE_PRQ; lp && fil == NIL(FILE); lp=lp->cl_next) {
     703        7956 :             dir  = lp->cl_prq->CE_NAME;
     704        7956 :             if( strchr(dir, '$') ) dir = Expand(dir);
     705        7956 :             path = Build_path( dir, name );
     706             : 
     707             :             DB_PRINT( "par", ("Trying to include [%s]", path) );
     708             : 
     709        7956 :             fil = Openfile( path, FALSE, FALSE );
     710        7956 :             if( dir != lp->cl_prq->CE_NAME ) FREE(dir);
     711             :           }
     712             :         }
     713             : 
     714        4964 :         if (!noinf && fil == NIL(FILE)) {
     715         556 :           t_attr glob = Glob_attr;
     716         556 :           t_attr cattr = prqlst->cl_prq->ce_attr;
     717             : 
     718         556 :           prqlst->cl_next = NIL(LINK);
     719         556 :           Glob_attr |= (attr&A_IGNORE);
     720         556 :           prqlst->cl_prq->ce_attr &= ~A_FRINGE;
     721             : 
     722         556 :           if( Verbose & V_FILE_IO )
     723           0 :             printf( "%s:  Inferring include file [%s].\n",
     724             :                     Pname, name );
     725         556 :           fil = TryFiles(prqlst);
     726             : 
     727         556 :           Glob_attr = glob;
     728         556 :           prqlst->cl_prq->ce_attr |= (cattr & A_FRINGE);
     729             :         }
     730             : 
     731        4964 :         if( fil != NIL(FILE) ) {
     732        4224 :           if( Verbose & V_FILE_IO )
     733           0 :             printf( "%s:  Parsing include file [%s].\n",
     734             :                     Pname, name );
     735        4224 :           Parse( fil );
     736        4224 :           found = TRUE;
     737             :         }
     738         740 :         else if( !(ignore || first) )
     739           0 :           Fatal( "Include file %s, not found", name );
     740         740 :         else if( Verbose & V_FILE_IO )
     741           0 :           printf( "%s:  Include file [%s] was not found.\n",
     742             :                   Pname, name );
     743             :       }
     744             : 
     745        4964 :       if ( !ignore && first && !found )
     746           0 :         Fatal( "No include file was found" );
     747             : 
     748        4964 :       if( pushed ) Pop_dir(FALSE);
     749        4964 :       attr &= ~(A_IGNORE|A_SETDIR|A_FIRST|A_NOINFER);
     750             :     }
     751        4964 :     break;
     752             : 
     753             :   case ST_SOURCE:
     754         184 :     if( prereq != NIL(CELL) )
     755         184 :       _do_targets( op & (R_OP_CL | R_OP_MI | R_OP_UP), attr, set_dir,
     756             :                    target, prereq );
     757             :     else {
     758             :       /* The old semantics of .SOURCE were that an empty list of
     759             :        * prerequisites clears the .SOURCE list.  So we must implement
     760             :        * that here as a clearout prerequisite operation.  Since this is
     761             :        * a standard operation with the :- opcode we can simply call the
     762             :        * proper routine with the target cell and it should do the trick
     763             :        */
     764             : 
     765           0 :       if( op == R_OP_CL || (op & R_OP_MI) )
     766           0 :         Clear_prerequisites( target );
     767             :     }
     768             : 
     769         184 :     op &= ~(R_OP_MI | R_OP_UP);
     770         184 :     break;
     771             : 
     772             :   case ST_KEEP:
     773           0 :     if( Keep_state != NIL(char) ) break;
     774           0 :     Def_macro( ".KEEP_STATE", "_state.mk", M_EXPANDED );
     775           0 :     break;
     776             : 
     777             :   case ST_REST:
     778             :     /* The rest of the special targets can all take recipes, as such they
     779             :      * must be able to affect the state of the parser. */
     780             : 
     781             :     {
     782        1104 :       int s_targ = Target;
     783             : 
     784        1104 :       Target     = TRUE;
     785        1104 :       _sp_target = TRUE;
     786        1104 :       *state     = _do_targets( op, attr, set_dir, target, prereq );
     787        1104 :       Target     = s_targ;
     788             : 
     789        1104 :       target->ce_flag |= F_TARGET;
     790             : 
     791        1104 :       attr    = A_DEFAULT;
     792        1104 :       op      = R_OP_CL;
     793             :     }
     794        1104 :     break;
     795             : 
     796           0 :   default:break;
     797             :   }
     798             : 
     799        8830 :   if( op   != R_OP_CL   ) Warning( "Modifier(s) for operator ignored" );
     800        8830 :   if( attr != A_DEFAULT ) Warning( "Extra attributes ignored" );
     801             : 
     802        8830 :   DB_VOID_RETURN;
     803             : }
     804             : 
     805             : 
     806             : static int
     807       18752 : _do_targets( op, attr, set_dir, targets, prereq )/*
     808             : ===================================================
     809             :    Evaluate the values derived from the current target definition
     810             :    line. Helper functions _build_graph(), _do_magic(), _make_multi(),
     811             :    _add_root(), _replace_cell(), _set_attributes(), Clear_prerequisites()
     812             :    _stick_at_head(), Add_prerequisite() and _set_global_attr() are used.
     813             :    If successfull "_sv_targets" is set to "targets".
     814             :    Return RULE_SCAN if a recipe is expected to follow, otherwise
     815             :    NORMAL_SCAN. */
     816             : int op;     /* rule operator                           */
     817             : t_attr  attr;       /* attribute flags for current targets     */
     818             : char    *set_dir;   /* value of setdir attribute               */
     819             : CELLPTR targets;    /* list of targets (each cell maybe already
     820             :              * defined by a previous target definition
     821             :              * line.  */
     822             : CELLPTR prereq;     /* list of prerequisites                   */
     823             : {
     824             :    CELLPTR  tg1;        /* temporary target pointer     */
     825             :    CELLPTR  tp1;        /* temporary prerequisite pointer   */
     826             :    LINKPTR      prev_cell;  /* pointer for .UPDATEALL processing    */
     827             :    char     *p;     /* temporary char pointer       */
     828       18752 :    int          tflag = FALSE;  /* set to TRUE if we add target to root */
     829       18752 :    int          ret_state = RULE_SCAN;  /* Return state */
     830             : 
     831             :    DB_ENTER( "_do_targets" );
     832             : 
     833             :    /* If .UPDATEALL is set sort the target list that was temporary linked
     834             :     * with ce_link into a list using ce_link with ce_set pointing to the first
     835             :     * element. */
     836             :    /* FIXME: Check that .UPDATEALL and %-targets on one line work together. */
     837       18752 :    if( attr & A_UPDATEALL ) {
     838           0 :       if( targets == NIL(CELL) )
     839           0 :      Fatal( ".UPDATEALL attribute requires non-empty list of targets" );
     840             : 
     841           0 :       if (targets->ce_set == NIL(CELL)) {
     842           0 :      for(
     843           0 :         prev_cell=CeMeToo(targets),tg1=targets->ce_link;
     844             :         tg1 != NIL(CELL);
     845           0 :         tg1=tg1->ce_link
     846             :      ) {
     847           0 :         if (tg1->ce_set)
     848           0 :            Fatal( "Target [%s] appears on multiple .UPDATEALL lists",
     849           0 :               tg1->CE_NAME);
     850           0 :         tg1->ce_set = targets;
     851           0 :         TALLOC(prev_cell->cl_next, 1, LINK);
     852           0 :         prev_cell = prev_cell->cl_next;
     853           0 :         prev_cell->cl_prq = tg1;
     854             :      }
     855           0 :      targets->ce_set = targets;
     856             :       }
     857             :       else {
     858             :      LINKPTR ap;
     859             :      CELLPTR tp;
     860             : 
     861           0 :      tp = targets;
     862           0 :      ap = CeMeToo(targets);
     863           0 :      while (ap && tp && ap->cl_prq == tp && tp->ce_set == targets) {
     864           0 :         ap = ap->cl_next;
     865           0 :         tp = tp->ce_link;
     866             :      }
     867           0 :      if (ap || tp)
     868           0 :         Fatal("Inconsistent .UPDATEALL lists for target [%s]",
     869           0 :           targets->CE_NAME);
     870             :       }
     871           0 :       targets->ce_link = NIL(CELL);
     872             :    }
     873             : 
     874       42264 :    for( tg1 = targets; tg1 != NIL(CELL); tg1 = tg1->ce_link ) {
     875             :       /* Check if tg1 is already marked as a %-target, but not a magic
     876             :        * (.xxx.yyy) target.  */
     877       23512 :       int purepercent = (tg1->ce_flag & F_PERCENT) && !(tg1->ce_flag & F_MAGIC);
     878             : 
     879             :       /* Check each target.  Check for inconsistencies between :: and : rule
     880             :        * sets.  :: may follow either : or :: but not the reverse.
     881             :        *
     882             :        * Any F_MULTI target (contains :: rules) is represented by a prerequisite
     883             :        * list hanging off the main target cell where each of the prerequisites
     884             :        * is a copy of the target cell but is not entered into the hash table.
     885             :        */
     886       23512 :       if( !(op & R_OP_DCL ) && (tg1->ce_flag & F_MULTI) && !purepercent )
     887           0 :      Fatal( "':' vs '::' inconsistency in rules for %s", tg1->CE_NAME );
     888             : 
     889       23512 :       if( purepercent ) {
     890             :      /* Handle %-targets. */
     891             :      CELLPTR cur;
     892       11512 :      CELLPTR tpq = NIL(CELL);
     893       11512 :      CELLPTR nprq = NULL;
     894             : 
     895             : #ifdef DBUG
     896             :      DB_PRINT( "%", ("Handling %%-target [%s : : <prerequisites follow, maybe empty>]",
     897             :              tg1->CE_NAME) );
     898             :      for(cur=prereq;cur;cur=cur->ce_link) {
     899             :         DB_PRINT( "%", ("         %%-prerequisites : %s ",
     900             :                 cur->CE_NAME ? cur->CE_NAME : "<empty>") );
     901             :      }
     902             : #endif
     903             : 
     904             :      /* Handle indirect (global) prerequisites first. */
     905       21404 :      for(cur=prereq;cur;cur=cur->ce_link) {
     906        9892 :         char *name = cur->CE_NAME;
     907        9892 :         int   len  = strlen(name);
     908             : 
     909        9892 :         if( *name == '\'' && name[len-1]=='\'' ){
     910           0 :            name[len-1] = '\0';
     911           0 :            len = strlen(name+1)+1;
     912           0 :            memmove(name,name+1,len);
     913             :            /* add indirect prerequisite */
     914           0 :            _add_indirect_prereq( cur );
     915             :         }
     916             :         else {
     917             :            /* Sort all "other" prerequisits into tpq, with nprq
     918             :         * pointing to the first element. */
     919        9892 :            if (tpq)
     920           0 :           tpq->ce_link = cur;
     921             :            else
     922        9892 :           nprq = cur;
     923        9892 :            tpq = cur;
     924             :         }
     925             :      }
     926             :      /* Mark the last element of nprq. */
     927       11512 :      if(tpq)
     928        9892 :         tpq->ce_link=NIL(CELL);
     929             :      else
     930        1620 :         nprq = NIL(CELL);
     931             : 
     932             :      /* Handle "normal" prerequisites now. */
     933             : 
     934       11512 :      if ( op & R_OP_OR ) {
     935             :         /* for op == ':|' transform:
     936             :          * <%-target> :| <prereq_1> ... <prereq_n> ; <recipe>
     937             :          * into:
     938             :          * <%-target> : <prereq_1> ; <recipe>
     939             :          * ..
     940             :          * <%-target> : <prereq_n> ; <recipe>
     941             :          */
     942         208 :         for(tp1=nprq; tp1; tp1=tp1->ce_link) {
     943         104 :            CELLPTR tmpcell = tp1->ce_link;
     944         104 :            tp1->ce_link = NIL(CELL);
     945         104 :            _build_graph(op,tg1,tp1);
     946         104 :            tp1->ce_link = tmpcell;
     947             :         }
     948             :      }
     949             :      else {
     950             :         /* The inference mechanism for %-targets limits the number of
     951             :          * (non-indirect) prerequisite to one, but an unlimited number
     952             :          * of indirect prerequisites is possible. */
     953       11408 :         if ( nprq && nprq->ce_link && !(op & R_OP_OR))
     954           0 :            Warning("More than one prerequisite\n"
     955             :            "for %%-target. Use :| ruleop or indirect prerequisites.");
     956             : 
     957       11408 :         _build_graph(op,tg1,nprq);
     958             :      }
     959             :       }
     960       12000 :       else if( tg1->ce_flag & F_MAGIC &&
     961           0 :            (p = _is_magic( tg1->CE_NAME )) != NIL(char) &&
     962           0 :            _do_magic( op, p, tg1, prereq, attr, set_dir ) )
     963             :     ; /* _do_magic() does all that is needed (if return value is TRUE). */
     964       12000 :       else if( op & R_OP_DCL ) {  /* op == :: */
     965           0 :      CELLPTR tmp_cell = _make_multi(tg1);
     966             : 
     967             :      /* Add the F_MULTI master to .TARGETS (If not set already).
     968             :       * Do this here so that the member cell is not added instead
     969             :       * when the recipies are bound in Bind_rules_to_targets(). */
     970           0 :      tflag |= _add_root(tg1);
     971             : 
     972             :      /* Replace the F_MULTI master with the member cell. */
     973           0 :      targets = _replace_cell( targets, tg1, tmp_cell );
     974             : 
     975             :     /* We have to set (add) the attributes also for the F_MULTI master
     976             :      * target cell. As there is no recipe the setdir value is not
     977             :      * needed. _set_attributes() that follows in approx. 8 lines
     978             :      * will set the attributes for the F_MULTI member cell.  */
     979           0 :      tg1->ce_attr |= (attr & ~A_SETDIR);
     980             : 
     981             :      /* Now switch tg1 to the current (F_MULTI prereq.) target.
     982             :       * All recipes have to be added to that cell and not to the
     983             :       * F_MULTI master.  */
     984           0 :      tg1 = tmp_cell;
     985             :       }
     986             : 
     987       23512 :       if( !purepercent ) _set_attributes( attr, set_dir, tg1 );
     988             : 
     989             :       /* Build the proper prerequisite list of the target.  If the `-',
     990             :        * modifier was used clear the prerequisite list before adding any
     991             :        * new prerequisites.  Else add them to the head/tail as appropriate.
     992             :        *
     993             :        * If the target has F_PERCENT set then no prerequisites are used. */
     994             : 
     995       23512 :       if( !(tg1->ce_flag & F_PERCENT) ) {
     996       12000 :      if( op & R_OP_MI ) Clear_prerequisites( tg1 ); /* op == :- */
     997             : 
     998       12000 :      if( (op & R_OP_UP) && (tg1->ce_prq != NIL(LINK)) ) /* op == :^ */
     999           0 :         _stick_at_head( tg1, prereq );
    1000       55146 :      else for( tp1=prereq; tp1 != NIL(CELL); tp1 = tp1->ce_link )
    1001       43146 :         Add_prerequisite( tg1, tp1, FALSE, FALSE );
    1002             :       }
    1003       11512 :       else if( op & (R_OP_MI | R_OP_UP) )
    1004           0 :      Warning( "Modifier(s) `^-' for %-meta target ignored" );
    1005             :    }
    1006             : 
    1007             :    /* In case a F_MULTI member that was the first prerequisite of .TARGETS */
    1008       18752 :    if(tflag)
    1009           0 :       Target = TRUE;
    1010             : 
    1011             :    /* Check to see if we have NO targets but some attributes, i.e. an
    1012             :     * Attribute-Definition.  If so then apply all of the attributes to the
    1013             :     * complete list of prerequisites.  No recipes are allowed to follow. */
    1014             : 
    1015       18752 :    if( (targets == NIL(CELL)) && attr ) {
    1016           2 :       ret_state = NORMAL_SCAN;
    1017           2 :       if( prereq != NIL(CELL) )
    1018           4 :      for( tp1=prereq; tp1 != NIL(CELL); tp1 = tp1->ce_link )
    1019           2 :         _set_attributes( attr, set_dir, tp1 );
    1020             :       else
    1021           0 :      _set_global_attr( attr );
    1022             :    }
    1023             : 
    1024             :    /* Now that we have built the lists of targets, the parser must parse the
    1025             :     * recipes if there are any.  However we must start the recipe list with the
    1026             :     * recipe specified as via the ; kludge, if there is one */
    1027       18752 :    _sv_targets = targets;
    1028       18752 :    _sv_attr    = attr;
    1029       18752 :    _sv_flag    = ((op & R_OP_BG) ? F_SINGLE : F_DEFAULT);
    1030             : 
    1031       18752 :    DB_RETURN( ret_state );
    1032             : }
    1033             : 
    1034             : 
    1035             : static int
    1036           0 : _do_magic( op, dot, target, prereq, attr, set_dir )/*
    1037             : =====================================================
    1038             :    This function investigates dot for being a magic target of the form
    1039             :    .<chars>.<chars> or .<chars> and creates the appropriate % rules for
    1040             :    that target.
    1041             :    If the target is given with an undefined syntax, i.e. with prerequisites,
    1042             :    then this function terminates early without creating % rules and
    1043             :    returns 0.
    1044             :    If successful the function returns 1.
    1045             : 
    1046             :    The function builds the % rule, `%.o : %.c'  from .c.o, and
    1047             :    `% : %.a' from .a */
    1048             : 
    1049             : int op;
    1050             : char    *dot;
    1051             : CELLPTR target;
    1052             : CELLPTR prereq;
    1053             : t_attr  attr;
    1054             : char    *set_dir;
    1055             : {
    1056             :    CELLPTR tg;
    1057             :    CELLPTR prq;
    1058             :    char    *tmp, *tmp2;
    1059             : 
    1060             :    DB_ENTER( "_do_magic" );
    1061             : 
    1062             :    DB_PRINT("%", ("Analysing magic target [%s]", target->CE_NAME));
    1063             : 
    1064           0 :    if( prereq != NIL(CELL) ) {
    1065           0 :       Warning( "Ignoring AUGMAKE meta-target [%s] because prerequisites are present.", target->CE_NAME );
    1066           0 :       DB_RETURN(0);
    1067             :    }
    1068             : 
    1069           0 :    if( dot == target->CE_NAME ) {    /* its of the form .a */
    1070           0 :       tg  = Def_cell( "%" );
    1071           0 :       tmp = _build_meta( target->CE_NAME );
    1072           0 :       prq = Def_cell( tmp );
    1073           0 :       FREE( tmp );
    1074             : 
    1075           0 :       _build_graph( op, tg, prq );
    1076             :    }
    1077             :    else {
    1078           0 :       tmp = _build_meta( dot );
    1079           0 :       tg  = Def_cell( tmp );
    1080           0 :       FREE( tmp );
    1081             : 
    1082           0 :       tmp = _build_meta( tmp2 = DmSubStr( target->CE_NAME, dot ) );
    1083           0 :       prq = Def_cell( tmp );
    1084           0 :       FREE( tmp  );
    1085           0 :       FREE( tmp2 );
    1086             : 
    1087           0 :       _build_graph( op, tg, prq );
    1088             :    }
    1089             : 
    1090           0 :    tg->ce_flag      |= F_PERCENT;
    1091           0 :    target->ce_flag  |= (F_MAGIC|F_PERCENT);
    1092             : 
    1093           0 :    _set_attributes( attr, set_dir, tg );
    1094             : 
    1095           0 :    DB_RETURN(1);
    1096             : }
    1097             : 
    1098             : 
    1099             : static CELLPTR
    1100           0 : _replace_cell( lst, cell, rep )/*
    1101             : =================================
    1102             :    Replace cell with rep in lst. Note if cell is not part of lst we are in
    1103             :    real trouble. */
    1104             : CELLPTR lst;
    1105             : CELLPTR cell;
    1106             : CELLPTR rep;
    1107             : {
    1108             :    register CELLPTR tp;
    1109             : 
    1110           0 :    if( lst == cell ) {
    1111           0 :       rep->ce_link = lst->ce_link;
    1112           0 :       lst = rep;
    1113             :    }
    1114             :    else {
    1115           0 :       for( tp=lst; tp->ce_link != cell && tp ; tp=tp->ce_link );
    1116           0 :       if( !tp )
    1117           0 :      Fatal( "Internal Error: cell not part of lst." );
    1118           0 :       rep->ce_link = tp->ce_link->ce_link;
    1119           0 :       tp->ce_link = rep;
    1120             :    }
    1121             : 
    1122           0 :    return(lst);
    1123             : }
    1124             : 
    1125             : 
    1126             : static char *
    1127           0 : _build_meta( name )/*
    1128             : =====================
    1129             :    Check to see if the name is of the form .c~ if so and if Augmake
    1130             :    translation is enabled then return s.%.c, else return %.suff, where if the
    1131             :    suffix ends in '~' then leave it be.*/
    1132             : char *name;
    1133             : {
    1134             :    char *tmp;
    1135           0 :    int  test = (STOBOOL(Augmake) ? name[strlen(name)-1] == '~' : 0);
    1136             : 
    1137           0 :    tmp = DmStrJoin( test ? "s.%" : "%", name, -1, FALSE);
    1138           0 :    if( test ) tmp[ strlen(tmp)-1 ] = '\0';
    1139             : 
    1140           0 :    return(tmp);
    1141             : }
    1142             : 
    1143             : 
    1144             : static CELLPTR
    1145       11512 : _build_graph( op, target, prereq )/*
    1146             : ====================================
    1147             :    This function is called to build the graph for the % rule given by
    1148             :    target : prereq cell combination.  This function assumes that target
    1149             :    is a % target and that prereq is one or multiple non-indirect prerequisite.
    1150             :    It also assumes that target cell has F_PERCENT set already.
    1151             : 
    1152             :    NOTE: If more than one prerequisite is present this function handles them
    1153             :    correctly but the lookup still only uses the first (BUG!).
    1154             : 
    1155             :    R_OP_CL (:) rules replace existing rules if any, %.o :: %.c is meaningless.
    1156             : 
    1157             :    The function always returns NIL(CELL). */
    1158             : int op;
    1159             : CELLPTR target;
    1160             : CELLPTR prereq;
    1161             : {
    1162             :    LINKPTR edl;
    1163       11512 :    CELLPTR edge = 0;
    1164             :    CELLPTR tpq,cur;
    1165             :    int match;
    1166             : 
    1167             : #ifdef DBUG
    1168             :    DB_ENTER( "_build_graph" );
    1169             :    DB_PRINT( "%", ("Building graph for [%s : <prerequisites follow, maybe empty>]",
    1170             :            target->CE_NAME) );
    1171             :    for(tpq=prereq;tpq;tpq=tpq->ce_link) {
    1172             :       DB_PRINT( "%", ("         %%-prerequisites : %s ",
    1173             :               tpq->CE_NAME ? tpq->CE_NAME : "<empty>") );
    1174             :    }
    1175             : #endif
    1176             : 
    1177             :    /* Currently multiple prerequisites are not (yet) handled correctly.
    1178             :     * We already issue a warning in _do_targets(), don't issue it here
    1179             :     * again.
    1180             :    if ( prereq && prereq->ce_link )
    1181             :       Warning( "Internal Error: more than one prerequisite in _build_graph." );
    1182             :     */
    1183             : 
    1184             :    /* There cannot be more than one target name ( linked with
    1185             :     * (CeMeToo(target))->cl_next ) per %-target master.
    1186             :     * FIXME: remove this check after verifying that it never triggers. */
    1187       11512 :    if ( (CeMeToo(target))->cl_next )
    1188           0 :       Fatal( "Internal Error: more than one target name in _build_graph." );
    1189             : 
    1190             :    /* Search the list of prerequisites for the current target and see if
    1191             :     * any of them match the current %-meta's : prereq's pair.  NOTE that
    1192             :     * %-metas are built as if they were F_MULTI targets, i.e. the target
    1193             :     * definitions for the %-target members are stored in the prerequisites
    1194             :     * list of the master target. */
    1195             :    /* This relies on target->ce_prq being NULL if this is the first
    1196             :     * occurrence of this %-target and therefore not yet having a %-target
    1197             :     * master. */
    1198       11512 :    match = FALSE;
    1199       41280 :    for(edl=target->ce_prq; !match && edl != NIL(LINK); edl=edl->cl_next) {
    1200             :       LINKPTR l1,l2;
    1201       29768 :       edge = edl->cl_prq;
    1202             : 
    1203             :       DB_PRINT("%", ("Trying to match [%s]",edge?edge->CE_NAME:"(nil)"));
    1204             : 
    1205             :       /* First we match the target sets, if this fails then we don't have to
    1206             :        * bother with the prerequisite sets.  The targets sets are sorted.
    1207             :        * this makes life very simple. */
    1208             :       /* ce_dir is handled per member target, no check needed for the
    1209             :        * master target. */
    1210             : 
    1211             :       /* FIXME: We already checked above that there is only one target
    1212             :        * name. Remove the comparisons for following names. */
    1213       29768 :       l1 = CeMeToo(target); /* Used by .UPDATEALL !!! */
    1214       29768 :       l2 = CeMeToo(edge);
    1215       89304 :       while(l1 && l2 && l1->cl_prq == l2->cl_prq) {
    1216       29768 :      l1=l1->cl_next;
    1217       29768 :      l2=l2->cl_next;
    1218             :       }
    1219             :       /* If both l1 and l2 are NULL we had a match. */
    1220       29768 :       if (l1 || l2)
    1221           0 :      continue;
    1222             : 
    1223             :       /* target sets match, so check prerequisites. */
    1224       29768 :       if(    (!edge->ce_prq && !prereq) /* matches both empty - separate this. */
    1225       29768 :       || (   edge->ce_prq
    1226       29768 :           && (   edge->ce_dir == _sv_setdir
    1227           0 :           || (   edge->ce_dir
    1228           0 :               && _sv_setdir
    1229           0 :               && !strcmp(edge->ce_dir,strchr(_sv_setdir,'=')+1)
    1230             :              )
    1231             :          )
    1232             :          )
    1233             :       ) {
    1234             :      LINKPTR prql;
    1235             : 
    1236             :      /* this is a really gross way to compare two sets, it's n^2 but
    1237             :       * since the sets are assumed to always be tiny, it should be ok. */
    1238       29768 :      for(tpq=prereq; tpq; tpq=tpq->ce_link) {
    1239       59536 :         for(prql=edge->ce_prq;prql;prql=prql->cl_next)
    1240       29768 :            if (prql->cl_prq == tpq)
    1241           0 :           break;
    1242             : 
    1243       29768 :         if(prql == NIL(LINK))
    1244       29768 :            break;
    1245             : 
    1246           0 :         prql->cl_prq->ce_flag |= F_MARK;
    1247             :      }
    1248             : 
    1249       29768 :      if (tpq == NIL(CELL)) {
    1250           0 :         for(prql=edge->ce_prq;prql;prql=prql->cl_next)
    1251           0 :            if(!(prql->cl_prq->ce_flag & F_MARK))
    1252           0 :           break;
    1253             : 
    1254           0 :         if(prql == NIL(LINK))
    1255           0 :         match = TRUE;
    1256             :      }
    1257             : 
    1258             :      /* clean up the mark bits. */
    1259       59536 :      for(prql=edge->ce_prq;prql;prql=prql->cl_next)
    1260       29768 :         prql->cl_prq->ce_flag &= ~F_MARK;
    1261             :       }
    1262             :    }
    1263             : 
    1264       11512 :    if( match ) {
    1265             :       /* match is TRUE hence, we found an edge joining the target and the
    1266             :        * prerequisite so reset the new edge so that new values replace it. */
    1267             :       DB_PRINT( "%", ("It's an old edge") );
    1268             : 
    1269           0 :       edge->ce_dir    = NIL(char);
    1270           0 :       edge->ce_flag  &= (F_PERCENT|F_MAGIC|F_DFA);
    1271           0 :       edge->ce_attr  &= A_NOINFER;
    1272             :    }
    1273             :    else {
    1274             :       DB_PRINT( "%", ("Adding a new edge") );
    1275             : 
    1276       11512 :       edge = _make_multi(target);
    1277             : 
    1278             :       /* FIXME: There can be only one %-target. */
    1279       23024 :       for(edl=CeMeToo(target);edl;edl=edl->cl_next) {
    1280       11512 :      if( !((tpq=edl->cl_prq)->ce_flag & F_DFA) ) {
    1281        4672 :         Add_nfa( tpq->CE_NAME );
    1282        4672 :         tpq->ce_flag |= F_DFA;
    1283             :      }
    1284             : 
    1285       11512 :      edl->cl_prq->ce_set = edge;
    1286             :       }
    1287             : 
    1288       11512 :       edge->ce_all = target->ce_all;
    1289       11512 :       target->ce_all.cl_next = NIL(LINK);
    1290       11512 :       target->ce_set = NIL(CELL);
    1291             : 
    1292             :       /* Add all prerequisites to edge. */
    1293       21404 :       for(tpq=prereq; tpq; tpq=tpq->ce_link)
    1294        9892 :          Add_prerequisite(edge, tpq, FALSE, TRUE);
    1295             :    }
    1296             : 
    1297       11512 :    if( op & R_OP_DCL )
    1298           0 :    Warning("'::' operator for meta-target '%s' ignored, ':' operator assumed.",
    1299           0 :        target->CE_NAME );
    1300             : 
    1301             :    /* If edge was already added we're in BIG trouble. */
    1302             :    /* Re-use cur as temporary variable. */
    1303       11516 :    for( cur=_sv_edgel; cur != NIL(CELL); cur=cur->ce_link ) {
    1304           4 :       if( cur == edge )
    1305           0 :      Fatal( "Internal Error: edge already in _sv_edgel." );
    1306             :    }
    1307             : 
    1308       11512 :    edge->ce_link = _sv_edgel;
    1309       11512 :    _sv_edgel = edge;
    1310       11512 :    _sv_globprq_only = 0;
    1311             : 
    1312       11512 :    DB_RETURN(NIL(CELL));
    1313             : }
    1314             : 
    1315             : 
    1316             : static CELLPTR
    1317       11512 : _make_multi( tg )/*
    1318             : ===================
    1319             :    This function is called to convert tg into an F_MULTI target.
    1320             :    Return a pointer to the new member cell.
    1321             :    I don't know what the author intended but the ce_index entry is only
    1322             :    used in this function (set to 0 for added targets) and undefined otherwise!
    1323             :    The undefined value is hopefully set to 0 by the C compiler as each added
    1324             :    target sets its ce_count to ++ce_index (==1). (FIXME) */
    1325             : CELLPTR tg;
    1326             : {
    1327             :    CELLPTR cp;
    1328             : 
    1329             :    /* This creates a new master F_MULTI target if tg existed before as a normal
    1330             :     * target with prerequisites or recipes. */
    1331       11512 :    if( !(tg->ce_flag & F_MULTI) && (tg->ce_prq || tg->ce_recipe) ) {
    1332             :       /* Allocate a new master cell. */
    1333           0 :       TALLOC(cp, 1, CELL);
    1334           0 :       *cp = *tg;
    1335             : 
    1336             :       /* F_MULTI master */
    1337           0 :       tg->ce_prq    = NIL(LINK);
    1338           0 :       tg->ce_flag  |= F_RULES|F_MULTI|F_TARGET;
    1339           0 :       tg->ce_attr  |= A_SEQ;
    1340           0 :       tg->ce_recipe = NIL(STRING);
    1341           0 :       tg->ce_dir    = NIL(char);
    1342             : 
    1343             :       /* F_MULTI member for preexisting elements */
    1344           0 :       cp->ce_count  = ++tg->ce_index;
    1345           0 :       cp->ce_cond   = NIL(STRING);
    1346           0 :       cp->ce_set    = NIL(CELL);
    1347           0 :       cp->ce_all.cl_prq = cp;
    1348           0 :       CeNotMe(cp)   = NIL(LINK);
    1349             : 
    1350           0 :       Add_prerequisite(tg, cp, FALSE, TRUE);
    1351             :    }
    1352             : 
    1353             :    /* Alocate memory for new member of F_MULTI target */
    1354       11512 :    TALLOC(cp, 1, CELL);
    1355       11512 :    *cp = *tg;
    1356             : 
    1357             :    /* This is reached if the target already exists, but without having
    1358             :     * prerequisites or recepies. Morph it into a F_MULTI master cell. */
    1359       11512 :    if( !(tg->ce_flag & F_MULTI) ) {
    1360        4672 :       tg->ce_prq    = NIL(LINK);
    1361        4672 :       tg->ce_flag  |= F_RULES|F_MULTI|F_TARGET;
    1362        4672 :       tg->ce_attr  |= A_SEQ;
    1363        4672 :       tg->ce_recipe = NIL(STRING);
    1364        4672 :       tg->ce_dir    = NIL(char);
    1365        4672 :       cp->ce_cond   = NIL(STRING);
    1366             :    }
    1367             :    /* This handles the case of adding an additional target as a
    1368             :     * prerequisite to a F_MULTI target. */
    1369             :    else {
    1370        6840 :       cp->ce_flag  &= ~(F_RULES|F_MULTI);
    1371        6840 :       cp->ce_attr  &= ~A_SEQ;
    1372        6840 :       cp->ce_prq    = NIL(LINK);
    1373        6840 :       cp->ce_index  = 0;
    1374        6840 :       cp->ce_cond   = NIL(STRING);
    1375             :    }
    1376       11512 :    cp->ce_count = ++tg->ce_index;
    1377       11512 :    cp->ce_flag |= F_TARGET;
    1378       11512 :    cp->ce_set   = NIL(CELL);
    1379       11512 :    cp->ce_all.cl_prq = cp;
    1380       11512 :    CeNotMe(cp)  = NIL(LINK);
    1381             : 
    1382       11512 :    Add_prerequisite(tg, cp, FALSE, TRUE);
    1383       11512 :    return(cp);
    1384             : }
    1385             : 
    1386             : 
    1387             : static void
    1388           0 : _add_indirect_prereq( pq )/*
    1389             : ==========================
    1390             :    Prerequisite is an indirect prerequisite for a %-target, add it to
    1391             :    the target's list of indirect prerequsites to add on match. */
    1392             : CELLPTR pq;
    1393             : {
    1394             :    register LINKPTR ln;
    1395             : 
    1396             :    /* Only add to list of indirect prerequsites if it is not in already. */
    1397           0 :    for(ln=_sv_ind_prq; ln; ln=ln->cl_next)
    1398           0 :       if(strcmp(ln->cl_prq->CE_NAME,pq->CE_NAME) == 0)
    1399           0 :      return;
    1400             : 
    1401             :    /* Not in, add it. */
    1402           0 :    TALLOC( ln, 1, LINK );
    1403           0 :    ln->cl_next = _sv_ind_prq;
    1404           0 :    ln->cl_prq  = pq;
    1405           0 :    _sv_ind_prq = ln;
    1406             : }
    1407             : 
    1408             : 
    1409             : 
    1410             : static void
    1411       23522 : _set_attributes( attr, set_dir, cp )/*
    1412             : ======================================
    1413             :     Set the appropriate attributes for a cell */
    1414             : t_attr  attr;
    1415             : char    *set_dir;
    1416             : CELLPTR cp;
    1417             : {
    1418       23522 :    char   *dir = 0;
    1419             : 
    1420             :    DB_ENTER( "_set_attributes" );
    1421             : 
    1422             :    /* If .SETDIR attribute is set then we have at least .SETDIR= in the
    1423             :     * set_dir string.  So go and fishout what is at the end of the =.
    1424             :     * If not set and not NULL then propagate it to the target cell. */
    1425             : 
    1426       23522 :    if( attr & A_SETDIR ) {
    1427             :       char *p;
    1428           0 :       if( (p = strchr( set_dir, '=' )) != NULL )
    1429           0 :          dir = p + 1;
    1430             : 
    1431           0 :       if( cp->ce_dir )
    1432           0 :      Warning( "Multiple .SETDIR for %s ignored", cp->CE_NAME );
    1433           0 :       else if( *dir )
    1434           0 :          cp->ce_dir = DmStrDup(dir);
    1435             :    }
    1436       23522 :    cp->ce_attr |= attr;     /* set rest of attributes for target */
    1437             : 
    1438       23522 :    DB_VOID_RETURN;
    1439             : }
    1440             : 
    1441             : 
    1442             : 
    1443             : static void
    1444           0 : _set_global_attr( attr )/*
    1445             : ==========================
    1446             :     Handle the setting of the global attribute functions based on
    1447             :     The attribute flags set in attr. */
    1448             : t_attr attr;
    1449             : {
    1450             :    t_attr flag;
    1451             : 
    1452             :    /* Some compilers can't handle a switch on a long, and t_attr is now a long
    1453             :     * integer on some systems.  foey! */
    1454           0 :    for( flag = MAX_ATTR; flag; flag >>= 1 )
    1455           0 :       if( flag & attr ) {
    1456           0 :      if( flag == A_PRECIOUS)      Def_macro(".PRECIOUS",  "y", M_EXPANDED);
    1457           0 :      else if( flag == A_SILENT)   Def_macro(".SILENT",    "y", M_EXPANDED);
    1458           0 :      else if( flag == A_IGNORE )  Def_macro(".IGNORE",    "y", M_EXPANDED);
    1459           0 :      else if( flag == A_EPILOG )  Def_macro(".EPILOG",    "y", M_EXPANDED);
    1460           0 :      else if( flag == A_PROLOG )  Def_macro(".PROLOG",    "y", M_EXPANDED);
    1461           0 :      else if( flag == A_NOINFER ) Def_macro(".NOINFER",   "y", M_EXPANDED);
    1462           0 :      else if( flag == A_SEQ )     Def_macro(".SEQUENTIAL","y", M_EXPANDED);
    1463           0 :      else if( flag == A_SHELL )   Def_macro(".USESHELL",  "y", M_EXPANDED);
    1464           0 :      else if( flag == A_MKSARGS ) Def_macro(".MKSARGS",   "y", M_EXPANDED);
    1465             : #if !defined(__CYGWIN__)
    1466           0 :      else if( flag == A_SWAP )    Def_macro(".SWAP",      "y", M_EXPANDED);
    1467             : #else
    1468             :      else if( flag == A_WINPATH ) Def_macro(".WINPATH",   "y", M_EXPANDED);
    1469             : #endif
    1470             :       }
    1471             : 
    1472           0 :    attr &= ~A_GLOB;
    1473           0 :    if( attr ) Warning( "Non global attribute(s) ignored" );
    1474           0 : }
    1475             : 
    1476             : 
    1477             : 
    1478             : static void
    1479           0 : _stick_at_head( cp, pq )/*
    1480             : ==========================
    1481             :     Add the prerequisite list to the head of the existing prerequisite
    1482             :     list */
    1483             : 
    1484             : CELLPTR cp;         /* cell for target node */
    1485             : CELLPTR pq;     /* list of prerequisites to add */
    1486             : {
    1487             :    DB_ENTER( "_stick_at_head" );
    1488             : 
    1489           0 :    if( pq->ce_link != NIL(CELL) ) _stick_at_head( cp, pq->ce_link );
    1490           0 :    Add_prerequisite( cp, pq, TRUE, FALSE );
    1491             : 
    1492           0 :    DB_VOID_RETURN;
    1493             : }
    1494             : 
    1495             : 
    1496             : 
    1497             : static t_attr
    1498       33646 : _is_attribute( name )/*
    1499             : =======================
    1500             :    Check the passed name against the list of valid attributes and return the
    1501             :    attribute index if it is, else return 0, indicating the name is not a valid
    1502             :    attribute.  The present attributes are defined in dmake.h as A_xxx #defines,
    1503             :    with the corresponding makefile specification:  (note they must be named
    1504             :    exactly as defined below)
    1505             : 
    1506             :    Valid attributes are:  .IGNORE, .SETDIR=, .SILENT, .PRECIOUS, .LIBRARY,
    1507             :                           .EPILOG, .PROLOG,  .LIBRARYM, .SYMBOL, .UPDATEALL,
    1508             :               .USESHELL, .NOINFER, .PHONY, .SWAP/.WINPATH, .SEQUENTIAL
    1509             :               .NOSTATE,  .MKSARGS, .IGNOREGROUP, .GROUP, .FIRST
    1510             :               .EXECUTE, .ERRREMOVE
    1511             : 
    1512             :    NOTE:  The strcmp's are OK since at most three are ever executed for any
    1513             :           one attribute check, and that happens only when we can be fairly
    1514             :           certain we have an attribute.  */
    1515             : char *name;
    1516             : {
    1517       33646 :    t_attr attr = 0;
    1518             : 
    1519             :    DB_ENTER( "_is_attribute" );
    1520             : 
    1521       33646 :    if( *name++ == '.' )
    1522       26300 :       switch( *name )
    1523             :       {
    1524             :          case 'E':
    1525        2404 :         if( !strcmp(name, "EPILOG") )           attr = A_EPILOG;
    1526        2404 :         else if( !strcmp(name, "EXECUTE"))      attr = A_EXECUTE;
    1527        2404 :         else if( !strcmp(name, "ERRREMOVE"))    attr = A_ERRREMOVE;
    1528        2394 :         else attr = 0;
    1529        2404 :         break;
    1530             : 
    1531             :      /* A_FIRST implies A_IGNORE, handled in ST_INCLUDE */
    1532             :          case 'F':
    1533           0 :         attr = (strcmp(name, "FIRST")) ? 0 : A_FIRST;
    1534           0 :         break;
    1535             : 
    1536           0 :      case 'G': attr = (strcmp(name, "GROUP"))    ? 0 : A_GROUP;   break;
    1537           0 :          case 'L': attr = (strcmp(name, "LIBRARY"))  ? 0 : A_LIBRARY; break;
    1538         368 :          case 'M': attr = (strcmp(name, "MKSARGS"))  ? 0 : A_MKSARGS; break;
    1539             : 
    1540             :          case 'I':
    1541        7164 :         if( !strcmp(name, "IGNORE") )           attr = A_IGNORE;
    1542        5872 :         else if( !strcmp(name, "IGNOREGROUP"))  attr = A_IGNOREGROUP;
    1543        5872 :         else attr = 0;
    1544        7164 :         break;
    1545             : 
    1546             :          case 'N':
    1547         368 :         if( !strcmp(name, "NOINFER") )      attr = A_NOINFER;
    1548         184 :         else if( !strcmp(name, "NOSTATE"))  attr = A_NOSTATE;
    1549           0 :         else attr = 0;
    1550         368 :         break;
    1551             : 
    1552             :          case 'U':
    1553           0 :         if( !strcmp(name, "UPDATEALL") )    attr = A_UPDATEALL;
    1554           0 :         else if( !strcmp(name, "USESHELL")) attr = A_SHELL;
    1555           0 :         else attr = 0;
    1556           0 :         break;
    1557             : 
    1558             :          case 'P':
    1559         566 :             if( !strcmp(name, "PRECIOUS") )     attr = A_PRECIOUS;
    1560         566 :             else if( !strcmp(name, "PROLOG") )  attr = A_PROLOG;
    1561         566 :             else if( !strcmp(name, "PHONY") )   attr = A_PHONY;
    1562           0 :             else attr = 0;
    1563         566 :             break;
    1564             : 
    1565             :          case 'S':
    1566         540 :             if( !strncmp(name, "SETDIR=", 7) )    attr = A_SETDIR;
    1567         540 :             else if( !strcmp(name, "SILENT") )    attr = A_SILENT;
    1568         540 :             else if( !strcmp(name, "SYMBOL") )    attr = A_SYMBOL;
    1569         540 :             else if( !strcmp(name, "SEQUENTIAL")) attr = A_SEQ;
    1570             :         /* A_SWAP has no meaning except for MSDOS. */
    1571         184 :             else if( !strcmp(name, "SWAP"))       attr = A_SWAP;
    1572         184 :             else attr = 0;
    1573         540 :             break;
    1574             : 
    1575           0 :          case 'W': attr = (strcmp(name, "WINPATH"))  ? 0 : A_WINPATH; break;
    1576             :       }
    1577             : 
    1578       33646 :    DB_RETURN( attr );
    1579             : }
    1580             : 
    1581             : 
    1582             : 
    1583             : static int
    1584       31054 : _is_special( tg )/*
    1585             : ===================
    1586             :    This function returns TRUE if the name passed in represents a special
    1587             :    target, otherwise it returns false.  A special target is one that has
    1588             :    a special meaning to dmake, and may require processing at the time that
    1589             :    it is parsed.
    1590             : 
    1591             :    Current Special targets are:
    1592             :     .GROUPPROLOG    .GROUPEPILOG    .INCLUDE    .IMPORT
    1593             :     .EXPORT     .SOURCE     .SUFFIXES   .ERROR        .EXIT
    1594             :     .INCLUDEDIRS    .MAKEFILES  .REMOVE     .KEEP_STATE
    1595             :     .TARGETS    .ROOT
    1596             : */
    1597             : char *tg;
    1598             : {
    1599             :    DB_ENTER( "_is_special" );
    1600             : 
    1601       31054 :    if( *tg++ != '.' ) DB_RETURN( 0 );
    1602             : 
    1603       23708 :    switch( *tg )
    1604             :    {
    1605             :       case 'E':
    1606        2394 :          if( !strcmp( tg, "ERROR" ) )       DB_RETURN( ST_REST     );
    1607        2210 :          else if( !strcmp( tg, "EXPORT" ) ) DB_RETURN( ST_EXPORT   );
    1608           0 :          else if( !strcmp( tg, "EXIT" ) )   DB_RETURN( ST_EXIT     );
    1609           0 :      break;
    1610             : 
    1611             :       case 'G':
    1612           0 :      if( !strcmp( tg, "GROUPPROLOG" ))      DB_RETURN( ST_REST     );
    1613           0 :      else if( !strcmp( tg, "GROUPEPILOG" )) DB_RETURN( ST_REST     );
    1614           0 :      break;
    1615             : 
    1616             :       case 'I':
    1617        5872 :          if( !strcmp( tg, "IMPORT" ) )      DB_RETURN( ST_IMPORT   );
    1618        5504 :          else if( !strcmp( tg, "INCLUDE" ) )    DB_RETURN( ST_INCLUDE  );
    1619         540 :      else if( !strcmp( tg, "INCLUDEDIRS" )) DB_RETURN( ST_REST     );
    1620         356 :      break;
    1621             : 
    1622             :       case 'K':
    1623           0 :          if( !strcmp( tg, "KEEP_STATE" ) )  DB_RETURN( ST_KEEP     );
    1624           0 :      break;
    1625             : 
    1626             :       case 'M':
    1627         368 :          if( !strcmp( tg, "MAKEFILES" ) )   DB_RETURN( ST_REST     );
    1628           0 :      break;
    1629             : 
    1630             :       case 'R':
    1631         368 :          if( !strcmp( tg, "REMOVE" ) )      DB_RETURN( ST_REST     );
    1632         184 :          else if( !strcmp( tg, "ROOT" ) )   DB_RETURN( ST_REST     );
    1633           0 :      break;
    1634             : 
    1635             :       case 'S':
    1636         184 :          if( !strncmp( tg, "SOURCE", 6 ) )  DB_RETURN( ST_SOURCE   );
    1637           0 :          else if( !strncmp(tg, "SUFFIXES", 8 )) {
    1638           0 :             if  (Verbose & V_WARNALL)
    1639           0 :                Warning( "The .SUFFIXES target has no special meaning and is deprecated." );
    1640           0 :             DB_RETURN( ST_SOURCE   );
    1641             :      }
    1642           0 :      break;
    1643             : 
    1644             :       case 'T':
    1645           0 :          if( !strcmp( tg, "TARGETS" ) )     DB_RETURN( ST_REST     );
    1646           0 :      break;
    1647             :    }
    1648             : 
    1649       14878 :    DB_RETURN( 0 );
    1650             : }
    1651             : 
    1652             : 
    1653             : 
    1654             : static int
    1655       86030 : _is_percent( np )/*
    1656             : ===================
    1657             :     return TRUE if np points at a string containing a % sign */
    1658             : char *np;
    1659             : {
    1660      213408 :    return( (strchr(np,'%') && (*np != '\'' && np[strlen(np)-1] != '\'')) ?
    1661      127378 :        TRUE : FALSE );
    1662             : }
    1663             : 
    1664             : 
    1665             : static char *
    1666       31054 : _is_magic( np )/*
    1667             : =================
    1668             :    return NULL if np does not points at a string of the form
    1669             :       .<chars>.<chars>  or  .<chars>
    1670             :    where chars are "visible characters" for the current locale. If np is of the
    1671             :    first form we return a pointer to the second '.' and for the second form we
    1672             :    return a pointer to the '.'.
    1673             : 
    1674             :    NOTE:  reject target if it contains / or begins with ..
    1675             :           reject also .INIT and .DONE because they are mentioned in the
    1676             :           man page. */
    1677             : char *np;
    1678             : {
    1679             :    register char *n;
    1680             : 
    1681       31054 :    n = np;
    1682       31054 :    if( *n != '.' ) return( NIL(char) );
    1683       23708 :    if (strchr(DirBrkStr, *(n+1))!=NULL || *(n+1) == '.' )
    1684       14338 :       return (NIL(char));
    1685        9370 :    if( !strcmp( n+1, "INIT" ) || !strcmp( n+1, "DONE" ) )
    1686         540 :       return (NIL(char));
    1687             : 
    1688        8830 :    for( n++; isgraph(*n) && (*n != '.'); n++ );
    1689             : 
    1690        8830 :    if( *n != '\0' ) {
    1691           0 :       if( *n != '.' )  return( NIL(char) );
    1692           0 :       for( np = n++; isgraph( *n ) && (*n != '.'); n++ );
    1693           0 :       if( *n != '\0' ) return( NIL(char) );
    1694             :    }
    1695             :    /* Until dmake 4.5 a .<suffix> target was ignored when AUGMAKE was
    1696             :     * set and evaluated as a meta target if unset (also for -A).
    1697             :     * To keep maximum compatibility accept this regardles of the AUGMAKE
    1698             :     * status. */
    1699             : 
    1700             :    /* np points at the second . of .<chars>.<chars> string.
    1701             :     * if the special target is of the form .<chars> then np points at the
    1702             :     * first . in the token. */
    1703             : 
    1704        8830 :    return( np );
    1705             : }
    1706             : 
    1707             : 
    1708             : static int
    1709       23328 : _add_root(tg)/*
    1710             : ===============
    1711             :    Adds "tg" to the prerequisits list of "Targets" if "Target" is not TRUE,
    1712             :    i.e. to the list of targets that are to be build.
    1713             :    Instead io setting "Target" to TRUE, TRUE is returned as more targets
    1714             :    might be defined in the current makefile line and they all have to be
    1715             :    add to "Targets" in this case.  */
    1716             : 
    1717             : CELLPTR tg;
    1718             : {
    1719       23328 :    int res = FALSE;
    1720             : 
    1721       23328 :    if(tg == Targets)
    1722           0 :       return(TRUE);
    1723             : 
    1724       23328 :    if( !Target && !(tg->ce_flag & (F_SPECIAL|F_PERCENT)) ) {
    1725         184 :       Add_prerequisite(Targets, tg, FALSE, TRUE);
    1726             : 
    1727         184 :       tg->ce_flag |= F_TARGET;
    1728         184 :       tg->ce_attr |= A_FRINGE;
    1729         184 :       res          = TRUE;
    1730             :    }
    1731             : 
    1732       23328 :    return(res);
    1733             : }

Generated by: LCOV version 1.10