home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / C / DMAKE37S.ZIP / DMAKE / RULPARSE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-06  |  38.4 KB  |  1,310 lines

  1. /* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/rulparse.c,v 1.1 91/05/06 15:23:26 dvadura Exp $
  2. -- SYNOPSIS -- perform semantic analysis on input
  3. -- 
  4. -- DESCRIPTION
  5. --    This code performs semantic analysis on the input, and builds
  6. --    the complex internal datastructure that is used to represent
  7. --    the user makefile.
  8. -- 
  9. -- AUTHOR
  10. --      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
  11. --      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
  12. --
  13. -- COPYRIGHT
  14. --      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
  15. -- 
  16. --      This program is free software; you can redistribute it and/or
  17. --      modify it under the terms of the GNU General Public License
  18. --      (version 1), as published by the Free Software Foundation, and
  19. --      found in the file 'LICENSE' included with this distribution.
  20. -- 
  21. --      This program is distributed in the hope that it will be useful,
  22. --      but WITHOUT ANY WARRANTY; without even the implied warrant of
  23. --      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24. --      GNU General Public License for more details.
  25. -- 
  26. --      You should have received a copy of the GNU General Public License
  27. --      along with this program;  if not, write to the Free Software
  28. --      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  29. --
  30. -- LOG
  31. --     $Log:    rulparse.c,v $
  32.  * Revision 1.1  91/05/06  15:23:26  dvadura
  33.  * dmake Release Version 3.7
  34.  * 
  35. */
  36.  
  37. #include "extern.h"
  38.  
  39. /* prototypes for local functions */
  40. static  void    _add_global_prereq ANSI((CELLPTR));
  41. static    void    _build_graph ANSI((int, CELLPTR, CELLPTR));
  42. static    char*    _build_meta ANSI((char*));
  43. static    int    _do_magic ANSI((int, char*, CELLPTR, CELLPTR, t_attr, char*));
  44. static    void    _do_special ANSI((int, int, t_attr,char*,CELLPTR,CELLPTR,int*));
  45. static    int    _do_targets ANSI((int, t_attr, char*, CELLPTR, CELLPTR));
  46. static    t_attr    _is_attribute ANSI((char*));
  47. static    int    _is_special ANSI((char*));
  48. static    char*    _is_magic ANSI((char*));
  49. static    int    _is_percent ANSI((char*));
  50. static  CELLPTR _make_multi ANSI((CELLPTR));
  51. static  CELLPTR _replace_cell ANSI((CELLPTR,CELLPTR,CELLPTR));
  52. static    void    _set_attributes ANSI((t_attr, char*, CELLPTR ));
  53. static    void    _stick_at_head ANSI((CELLPTR, CELLPTR));
  54. static    void    _set_global_attr ANSI((t_attr));
  55.  
  56. /* static variables that must persist across invocation of Parse_rule_def */
  57. static CELLPTR    _sv_targets = NIL(CELL);
  58. static STRINGPTR  _sv_rules   = NIL(STRING);
  59. static STRINGPTR  _sv_crule   = NIL(STRING);
  60. static CELLPTR    _sv_edgel   = NIL(CELL);
  61. static LINKPTR    _sv_glb_prq = NIL(LINK);
  62. static int      _sp_target  = FALSE;
  63. static t_attr     _sv_attr;
  64. static t_attr     _sv_attro;
  65. static int        _sv_flag;
  66. static int      _sv_op;
  67. static char      *_sv_setdir;
  68. static char      _sv_globprq_only = 0;
  69.  
  70. /* Define for global attribute mask */
  71. #define A_GLOB     (A_PRECIOUS | A_SILENT | A_IGNORE | A_EPILOG | A_SWAP |\
  72.           A_SHELL | A_PROLOG | A_NOINFER | A_SEQ | A_MKSARGS )
  73.  
  74.  
  75. PUBLIC int
  76. Parse_rule_def( state )/*
  77. =========================
  78.    Parse the rule definition contained in Buffer, and modify the state 
  79.    if appropriate.  The function returns 0, if the definition is found to
  80.    be an illegal rule definition, and it returns 1 if it is a rule definition.
  81.    */
  82. int *state;
  83. {
  84.    TKSTR     input;        /* input string struct for token search      */
  85.    CELLPTR    targets;    /* list of targets if any          */
  86.    CELLPTR    prereq;        /* list of prereq if any          */
  87.    CELLPTR    prereqtail;    /* tail of prerequisite list          */
  88.    CELLPTR    cp;        /* temporary cell pointer for list making */
  89.    char     *result;    /* temporary storage for result            */
  90.    char        *tok;        /* temporary pointer for tokens          */
  91.    char         *set_dir;       /* value of setdir attribute              */
  92.    char        *brk;        /* break char list for Get_token      */
  93.    char         *firstrcp;      /* first recipe line, from ; in rule line */
  94.    t_attr       attr;           /* sum of attribute flags for current tgts*/
  95.    t_attr    at;        /* temp place to keep an attribute code      */
  96.    int        op;        /* rule operator              */
  97.    int        special;    /* indicate special targets in rule      */
  98.    int        percent;    /* indicate percent rule target          */
  99.    int        mixed_glob_prq; /* indicate mixed %-rule prereq possible  */
  100.  
  101.    DB_ENTER( "Parse_rule_def" );
  102.  
  103.    op          = 0;
  104.    attr       = 0;
  105.    special    = 0;
  106.    percent    = 0;
  107.    set_dir    = NIL( char );
  108.    targets    = NIL(CELL);
  109.    prereq     = NIL(CELL);
  110.    prereqtail = NIL(CELL);
  111.    mixed_glob_prq = 0;
  112.  
  113.    /* Check to see if the line is of the form:
  114.     *    targets : prerequisites; first recipe line
  115.     * If so remember the first_recipe part of the line. */
  116.  
  117.    firstrcp = strchr( Buffer, ';' );
  118.    if( firstrcp != NIL( char ) ) {
  119.       *firstrcp++ = 0;
  120.       firstrcp = _strspn( firstrcp, " \t" );
  121.    }
  122.  
  123.    result = Expand( Buffer );
  124.    for( brk=strchr(result,'\\'); brk != NIL(char); brk=strchr(brk,'\\') )
  125.       if( brk[1] == '\n' )
  126.      *brk = ' ';
  127.       else
  128.          brk++;
  129.  
  130.    DB_PRINT( "par", ("Scanning: [%s]", result) );
  131.  
  132.    SET_TOKEN( &input, result );
  133.    brk = ":-^!";
  134.    Def_targets = TRUE;
  135.    
  136.    /* Scan the input rule line collecting targets, the operator, and any
  137.     * prerequisites.  Stop when we run out of targets and prerequisites. */
  138.  
  139.    while( *(tok = Get_token( &input, brk, TRUE )) != '\0' )
  140.       if( !op ) {
  141.      /* we are scanning targets and attributes
  142.       * check to see if token is an operator.  */
  143.  
  144.      op = Rule_op( tok );
  145.  
  146.      if( !op ) {
  147.         /* define a new cell, or get old cell  */
  148.         cp = Def_cell( tok );
  149.         DB_PRINT( "par", ("tg_cell [%s]", tok) );
  150.         
  151.         if( at = _is_attribute( tok ) ) {
  152.            /* Logically OR the attributes specified into one main
  153.             * ATTRIBUTE mask. */
  154.  
  155.            if( at == A_SETDIR )
  156.               if( set_dir != NIL( char ) )
  157.                  Warning( "Multiple .SETDIR attribute ignored" );
  158.               else
  159.                  set_dir = _strdup( tok );
  160.  
  161.            attr |= at;
  162.         }
  163.         else {
  164.            int tmp;
  165.            
  166.            tmp = _is_special( tok );
  167.            if( _is_percent( tok ) ) percent++;
  168.  
  169.            if( percent )
  170.               if( targets != NIL(CELL) )
  171.              Fatal( "Multiple targets are not allowed in %% rules" );
  172.           else
  173.              cp->ce_flag |= F_PERCENT;
  174.  
  175.            if( special )
  176.               Fatal( "Special target must appear alone", tok );
  177.            else if( !(cp->ce_flag & F_MARK) ) {
  178.           cp->ce_link  = targets;  /* targets are stacked in this list*/
  179.           cp->ce_flag |= F_MARK | F_EXPLICIT;
  180.           targets      = cp;
  181.  
  182.           special = tmp;
  183.            }
  184.            else if( !(cp->ce_attr & A_LIBRARY) )
  185.           Warning("Duplicate entry [%s] in target list",cp->CE_NAME);
  186.         }
  187.      }
  188.      else {
  189.         /* found an operator so empty out break list
  190.          * and clear mark bits on target list, setting them all to F_USED */
  191.  
  192.         brk  = "";
  193.         for( cp=targets; cp != NIL(CELL); cp=cp->ce_link ) {
  194.            cp->ce_flag ^= F_MARK;
  195.            cp->ce_flag |= F_USED;
  196.         }
  197.  
  198.         Def_targets = FALSE;
  199.      }
  200.       }
  201.       else {
  202.          /* Scanning prerequisites so build the prerequisite list.  We use
  203.           * F_MARK flag to make certain we have only a single copy of the
  204.           * prerequisite in the list */
  205.  
  206.      cp = Def_cell( tok );
  207.  
  208.      if( _is_percent( tok ) ) {
  209.         if( !percent && !attr )
  210.            Fatal( "Syntax error in %% rule, missing %% target");
  211.         mixed_glob_prq = 1;
  212.      }
  213.  
  214.      if( cp->ce_flag & F_USED ) {
  215.         if( cp->ce_attr & A_COMPOSITE )
  216.            continue;
  217.         else
  218.            Fatal( "Detected circular dependency in graph at [%s]",
  219.               cp->CE_NAME );
  220.      }
  221.          else if( !(cp->ce_flag & F_MARK) ) {
  222.         DB_PRINT( "par", ("pq_cell [%s]", tok) );
  223.         cp->ce_flag |= F_MARK;
  224.  
  225.         if( prereqtail == NIL(CELL) )    /* keep prereq's in order */
  226.            prereq = cp;
  227.         else
  228.            prereqtail->ce_link = cp;
  229.  
  230.         prereqtail = cp;
  231.         cp->ce_link = NIL(CELL);
  232.      }
  233.      else if( !(cp->ce_attr & A_LIBRARY) )
  234.         Warning("Duplicate entry [%s] in prerequisite list",cp->CE_NAME);
  235.       }
  236.       
  237.    /* Check to see if we have a percent rule that has only global
  238.     * prerequisites.  If so then set the flag so that later on, we don't issue
  239.     * an error if such targets supply an empty set of rules. */
  240.  
  241.    if( percent && !mixed_glob_prq && (prereq != NIL(CELL)) )
  242.       _sv_globprq_only = 1;
  243.  
  244.    /* It's ok to have targets with attributes, and no prerequisites, but it's
  245.     * not ok to have no targets and no attributes, or no operator */
  246.  
  247.    if( !op ) {
  248.       CLEAR_TOKEN( &input );
  249.       DB_PRINT( "par", ("Not a rule [%s]", Buffer) );
  250.       DB_RETURN( 0 );
  251.    }
  252.  
  253.    if( !attr && targets == NIL(CELL) ) {
  254.       Fatal( "Missing targets or attributes in rule" );
  255.       if( set_dir != NIL( char )) FREE( set_dir );
  256.       DB_RETURN( 0 );
  257.    }
  258.  
  259.    /* We have established we have a legal rules line, so we must process it.
  260.     * In doing so we must handle any special targets.  Special targets must
  261.     * appear alone possibly accompanied by attributes.
  262.     * NOTE:  special != 0  ==> targets != NIL(CELL) */
  263.     
  264.    if( prereqtail != NIL(CELL) ) prereqtail->ce_link = NIL(CELL);
  265.  
  266.    /* Clear out MARK bits used in duplicate checking.  I originally wanted
  267.     * to do this as the lists get processed but that got too error prone
  268.     * so I bit the bullit and added these two loops. */
  269.  
  270.    for( cp=prereq;  cp != NIL(CELL); cp=cp->ce_link ) cp->ce_flag &= ~F_MARK;
  271.    for( cp=targets; cp != NIL(CELL); cp=cp->ce_link ) cp->ce_flag &= ~F_USED;
  272.  
  273.    /* Check to see if the previous rule line was bound if, not the call
  274.     * Bind_rules_to_targets to go and bind the line */
  275.  
  276.    if( _sv_rules != NIL(STRING) ) Bind_rules_to_targets( F_DEFAULT );
  277.  
  278.    /* Add the first recipe line to the list */
  279.    if( firstrcp != NIL( char ) )
  280.       Add_recipe_to_list( firstrcp, TRUE, FALSE );
  281.  
  282.    /* Save these prior to calling _do_targets, since _build_graph needs the
  283.     * _sv_setdir value for matching edges. */
  284.    _sv_op     = op;
  285.    _sv_setdir = set_dir;
  286.  
  287.    if( special )
  288.       _do_special( special, op, attr, set_dir, targets, prereq, state );
  289.    else
  290.       *state = _do_targets( op, attr, set_dir, targets, prereq );
  291.  
  292.    DB_RETURN( 1 );
  293. }
  294.  
  295.  
  296. PUBLIC int
  297. Rule_op( op )/*
  298. ================
  299.    Check the passed in op string and map it to one of the rule operators */
  300. char *op;
  301. {
  302.    int ret = 0;
  303.  
  304.    DB_ENTER( "rule_op" );
  305.    
  306.    if( *op == TGT_DEP_SEP ) {
  307.       ret = R_OP_CL;
  308.       op++;
  309.  
  310.       /* All rule operations begin with a :, but may include any one of the
  311.        * four modifiers.  In order for the rule to be properly mapped we must
  312.        * check for each of the modifiers in turn, building up our return bit
  313.        * string. */
  314.  
  315.       while( *op && ret )
  316.          switch( *op ) {
  317.         case ':': ret |= R_OP_DCL; op++; break;
  318.         case '!': ret |= R_OP_BG;  op++; break;
  319.         case '^': ret |= R_OP_UP;  op++; break;
  320.         case '-': ret |= R_OP_MI;  op++; break;
  321.  
  322.         default : ret  = 0;  /* an invalid modifier, chuck whole string */
  323.          }
  324.  
  325.       if( *op != '\0' ) ret = 0;
  326.    }
  327.  
  328.    DB_RETURN( ret );
  329. }
  330.  
  331.  
  332. PUBLIC void
  333. Add_recipe_to_list( rule, white_too, no_check )/*
  334. =================================================
  335.         Take the provided string and add it to the list of recipe lines
  336.     we are saving to be added to the list of targets we have built
  337.     previously.  If white_too == TRUE add the rule EVEN IF it contains only
  338.         whitespace. */
  339. char *rule;
  340. int  white_too;
  341. int  no_check;
  342. {
  343.    DB_ENTER( "Add_recipe_to_list" );
  344.  
  345.    if( rule != NIL( char ) && (*rule != '\0' || white_too) ) {
  346.       DB_PRINT( "par", ("Adding recipe [%s]", rule) );
  347.       _sv_crule = Def_recipe( rule, _sv_crule, white_too, no_check );
  348.  
  349.       if( _sv_rules == NIL(STRING) )
  350.          _sv_rules = _sv_crule;
  351.    }
  352.  
  353.    DB_VOID_RETURN;
  354. }
  355.  
  356.  
  357. PUBLIC void
  358. Bind_rules_to_targets( flag )/*
  359. ===============================
  360.         Take the rules we have defined and bind them with proper attributes
  361.         to the targets that were previously defined in the parse.  The
  362.         attributes that get passed here are merged with those that are were
  363.         previously defined.  (namely F_SINGLE) */
  364. int flag;
  365. {
  366.    CELLPTR tg;             /* pointer to current target in list */
  367.    LINKPTR lp;           /* pointer to link cell        */
  368.    int     magic;          /* TRUE if target is .xxx.yyy form   */
  369.    int     tflag;          /* TRUE if we assigned targets here  */
  370.  
  371.    DB_ENTER( "Bind_rules_to_targets" );
  372.  
  373.    /* This line is needed since Parse may call us twice when the last
  374.     * GROUP rule appears at the end of file.  In this case the rules
  375.     * have already been bound and we want to ignore them. */
  376.  
  377.    if( _sv_targets == NIL(CELL) ) { DB_VOID_RETURN; }
  378.  
  379.    tflag  = FALSE;
  380.    flag  |= (_sv_flag & F_SINGLE);
  381.  
  382.    for( tg = _sv_targets; tg != NIL(CELL); tg = tg->ce_link ) {
  383.       DB_PRINT( "par", ("Binding to %s, %04x", tg->CE_NAME, tg->ce_flag) );
  384.       magic = tg->ce_flag & F_PERCENT;
  385.  
  386.       /* Check to see if we had a rule of the form '%.o : a.h b.h ; xxx'
  387.        * In which case we must build a NULL prq node to hold the recipe */
  388.       if( _sv_globprq_only && (_sv_rules != NIL(STRING)) )
  389.      _build_graph( _sv_op, tg, NIL(CELL) );
  390.  
  391.       /* NOTE:  For targets that are magic we ignore any previously defined
  392.        *        rules.  ie. We throw away the old definition and use the new. */
  393.       if( !(tg->ce_flag & F_MULTI) && !magic && (tg->CE_RECIPE != NIL(STRING))
  394.       && !_sp_target && (_sv_rules != NIL(STRING)) )
  395.          Fatal( "Multiply defined recipe for target %s", tg->CE_NAME );
  396.  
  397.       if( (magic || _sp_target) && (_sv_rules == NIL(STRING)) &&
  398.       !(tg->ce_flag & F_SPECIAL) && !_sv_globprq_only )
  399.          Warning( "Empty recipe for special target %s", tg->CE_NAME );
  400.  
  401.       if( magic ) {
  402.      CELLPTR ep;
  403.  
  404.      for( ep=_sv_edgel; ep != NIL(CELL); ep=ep->ce_link ) {
  405.         _set_attributes( _sv_attro, _sv_setdir, ep );
  406.         ep->ce_flag |= (F_TARGET|flag);
  407.  
  408.         if( _sv_rules != NIL(STRING) ) {
  409.            ep->ce_recipe  = _sv_rules;
  410.            ep->ce_indprq  = _sv_glb_prq;
  411.         }
  412.      }
  413.       }
  414.       else {
  415.      tg->ce_attr |= _sv_attr;
  416.      tg->ce_flag |= flag;
  417.  
  418.      if( _sv_rules != NIL(STRING) ) {
  419.         tg->ce_recipe  = _sv_rules;
  420.         tg->ce_flag   |= F_RULES | F_TARGET;
  421.  
  422.         /* Bind the current set of prerequisites as belonging to the
  423.          * original recipe given for the target */
  424.         for( lp=tg->ce_prq; lp != NIL(LINK); lp = lp->cl_next )
  425.           if( !(lp->cl_flag & F_USED) ) lp->cl_flag |= F_TARGET;
  426.          }
  427.      else for( lp=tg->ce_prq; lp != NIL(LINK); lp = lp->cl_next )
  428.         lp->cl_flag |= F_USED;
  429.       }
  430.  
  431.       if( !Target && !magic && !(tg->ce_flag & F_SPECIAL) ) {
  432.      Add_prerequisite( Root, tg, FALSE, TRUE );
  433.  
  434.      tg->ce_flag |= F_TARGET;
  435.      tg->ce_attr |= A_FRINGE;
  436.      tflag        = TRUE;
  437.       }
  438.    }
  439.  
  440.    if( tflag ) Target = TRUE;
  441.    if( _sv_setdir ) FREE(_sv_setdir);
  442.    _sv_rules   = NIL(STRING);
  443.    _sv_crule   = NIL(STRING);
  444.    _sv_targets = NIL(CELL);
  445.    _sv_glb_prq = NIL(LINK);
  446.    _sv_edgel   = NIL(CELL);
  447.    _sp_target  = FALSE;
  448.    _sv_globprq_only = 0;
  449.  
  450.    DB_VOID_RETURN;
  451. }
  452.  
  453.  
  454.  
  455. PUBLIC int
  456. Set_group_attributes( list )/*
  457. ==============================
  458.     Scan list looking for the standard @ and - (as in recipe line defs)
  459.     and set the flags accordingly so that they apply when we bind the
  460.     rules to the appropriate targets. */
  461. char *list;
  462. {
  463.    int res = (*_strspn(list,"@-%+ \t") == '[');
  464.    if( res ) _sv_attr |= Rcp_attribute(list);
  465.    return(res);
  466. }
  467.  
  468.  
  469. static void
  470. _do_special( special, op, attr, set_dir, target, prereq, state )/*
  471. ==================================================================
  472.    Process a special target.  So far the only special targets we have
  473.    are those recognized by the _is_special function.
  474.  
  475.    target is always only a single special target.
  476.    
  477.    NOTE:  For the cases of .IMPORT, and .INCLUDE, the cells created by the
  478.          parser are never freed.  This is due to the fact that it is too much
  479.       trouble to get them out of the hash table once they are defined, and
  480.       if they are per chance used again it will be ok, anyway, since the
  481.       cell is not really used by the code below.  */
  482.  
  483. int    special;
  484. int    op;
  485. t_attr    attr;
  486. char    *set_dir;
  487. CELLPTR target;
  488. CELLPTR prereq;
  489. int     *state;
  490. {
  491.    HASHPTR    hp;        /* pointer to macro def cell        */
  492.    CELLPTR    cp;        /* temporary pointer into cells list    */
  493.    CELLPTR     dp;        /* pointer to directory dir cell    */
  494.    LINKPTR     lp;        /* pointer at prerequisite list     */
  495.    char        *dir;        /* current dir to prepend        */
  496.    char        *path;        /* resulting path to try to read    */
  497.    char     *name;        /* File name for processing a .INCLUDE    */
  498.    char        *tmp;        /* temporary string pointer        */
  499.    FILE     *fil;        /* File descriptor returned by Openfile    */
  500.  
  501.    DB_ENTER( "_do_special" );
  502.  
  503.    target->ce_flag = F_SPECIAL;    /* mark the target as special */
  504.  
  505.    switch( special ) {
  506.       case ST_EXPORT:
  507.      for( ; prereq != NIL(CELL); prereq = prereq->ce_link ) {
  508.         DB_PRINT( "par", ("Exporting [%s]", prereq->CE_NAME) );
  509.         hp = GET_MACRO( prereq->CE_NAME );
  510.  
  511.         if( hp != NIL(HASH) ) {
  512.            char *tmpstr = hp->ht_value;
  513.  
  514.            if( tmpstr == NIL(char) ) tmpstr = "";
  515.  
  516.            if( Write_env_string( prereq->CE_NAME, tmpstr ) != 0 )
  517.           Warning( "Could not export %s", prereq->CE_NAME );
  518.         }
  519.      }
  520.      break;
  521.  
  522.       case ST_IMPORT:
  523.      for( ; prereq != NIL(CELL); prereq = prereq->ce_link ) {
  524.         char *tmpstr;
  525.  
  526.         DB_PRINT( "par", ("Importing [%s]", prereq->CE_NAME) );
  527.  
  528.         if( strcmp(prereq->CE_NAME, ".EVERYTHING") == 0 ) {
  529.            t_attr sattr = Glob_attr;
  530.            Glob_attr |= A_SILENT;
  531.  
  532.            ReadEnvironment();
  533.  
  534.            Glob_attr = sattr;
  535.         }
  536.         else {
  537.            tmpstr = Read_env_string( prereq->CE_NAME );
  538.  
  539.            if( tmpstr != NIL(char) )
  540.           Def_macro( prereq->CE_NAME,tmpstr,M_EXPANDED | M_LITERAL);
  541.            else
  542.           if( !((Glob_attr | attr) & A_IGNORE) )
  543.              Fatal("Imported macro `%s' not found",prereq->CE_NAME);
  544.         }
  545.      }
  546.  
  547.      attr &= ~A_IGNORE;
  548.      break;
  549.  
  550.       case ST_INCLUDE:
  551.       {
  552.      int ignore     = (((Glob_attr | attr) & A_IGNORE) != 0);
  553.      int pushed     = FALSE;
  554.      LINKPTR prqlnk = NIL(LINK);
  555.      LINKPTR prqlst = NIL(LINK);
  556.  
  557.      if( prereq == NIL(CELL) )  Fatal( "No .INCLUDE file(s) specified" );
  558.  
  559.      dp = Def_cell( ".INCLUDEDIRS" );
  560.  
  561.      if( (attr & A_SETDIR) && *(dir = strchr(set_dir, '=')+1) )
  562.         pushed = Push_dir( dir, ".INCLUDE", ignore );
  563.  
  564.      for( cp=prereq; cp != NIL(CELL); cp = cp->ce_link ) {
  565.         LINKPTR ltmp;
  566.         TALLOC(ltmp, 1, LINK);
  567.         ltmp->cl_prq = cp;
  568.  
  569.         if( prqlnk == NIL(LINK) )
  570.            prqlst = ltmp;
  571.         else
  572.            prqlnk->cl_next = ltmp;
  573.  
  574.         prqlnk = ltmp;
  575.      }
  576.  
  577.      for( ; prqlst != NIL(LINK); FREE(prqlst), prqlst=prqlnk ) {
  578.         prqlnk = prqlst->cl_next;
  579.         cp     = prqlst->cl_prq;
  580.         name   = cp->CE_NAME;
  581.         
  582.         if( *name == '<' ) {
  583.            /* We have a file name enclosed in <....>
  584.             * so get rid of the <> arround the file name */
  585.  
  586.            name++;
  587.            if( (tmp = strrchr( name, '>' )) != NIL( char ) )
  588.           *tmp = 0;
  589.  
  590.            if( If_root_path( name ) )
  591.               fil = Openfile( name, FALSE, FALSE );
  592.            else
  593.           fil = NIL(FILE);
  594.         }
  595.         else
  596.            fil = Openfile( name, FALSE, FALSE );
  597.            
  598.         if( fil == NIL(FILE) ) {    /*if true ==> not found in current dir*/
  599.            /* Now we must scan the list of prerequisites for .INCLUDEDIRS
  600.             * looking for the file in each of the specified directories.
  601.         * if we don't find it then we issue an error.  The error
  602.         * message is suppressed if the .IGNORE attribute of attr is
  603.         * set.  If a file is found we call Parse on the file to
  604.         * perform the parse and then continue on from where we left
  605.         * off.  */
  606.  
  607.            for(lp=dp->CE_PRQ; lp && fil == NIL(FILE); lp=lp->cl_next) {
  608.           dir  = lp->cl_prq->CE_NAME;
  609.           if( strchr(dir, '$') ) dir = Expand(dir);
  610.           path = Build_path( dir, name );
  611.  
  612.           DB_PRINT( "par", ("Trying to include [%s]", path) );
  613.  
  614.           fil = Openfile( path, FALSE, FALSE );
  615.           if( dir != lp->cl_prq->CE_NAME ) FREE(dir);
  616.            }
  617.         }
  618.  
  619.         if( fil != NIL(FILE) )
  620.            Parse( fil );
  621.         else if( !((Glob_attr | attr) & A_IGNORE) )
  622.            Fatal( "Include file %s, not found", name );
  623.      }
  624.  
  625.      if( pushed ) Pop_dir(FALSE);
  626.      attr &= ~(A_IGNORE|A_SETDIR);
  627.       }
  628.       break;
  629.      
  630.       case ST_SOURCE:
  631.       /* case ST_SUFFIXES: */
  632.            if( prereq != NIL(CELL) )
  633.         _do_targets( op & (R_OP_CL | R_OP_MI | R_OP_UP), attr, set_dir,
  634.              target, prereq );
  635.      else {
  636.         /* The old semantics of .SOURCE were that an empty list of
  637.          * prerequisites clears the .SOURCE list.  So we must implement
  638.          * that here as a clearout prerequisite operation.  Since this is
  639.          * a standard operation with the :- opcode we can simply call the
  640.          * proper routine with the target cell and it should do the trick
  641.          */
  642.  
  643.         if( op == R_OP_CL || (op & R_OP_MI) )
  644.            Clear_prerequisites( target );
  645.      }
  646.  
  647.      op &= ~(R_OP_MI | R_OP_UP);
  648.      break;
  649.  
  650.       case ST_KEEP:
  651.      if( Keep_state != NIL(char) ) break;
  652.      Def_macro( ".KEEP_STATE", "_state.mk", M_EXPANDED );
  653.      break;
  654.  
  655.       case ST_REST:
  656.          /* The rest of the special targets can all take rules, as such they
  657.       * must be able to affect the state of the parser. */
  658.  
  659.      {
  660.         int s_targ = Target;
  661.  
  662.         Target     = TRUE;
  663.         _sp_target = TRUE;
  664.         *state     = _do_targets( op, attr, set_dir, target, prereq );
  665.         Target     = s_targ;
  666.  
  667.         target->ce_flag |= F_TARGET;
  668.  
  669.         attr    = A_DEFAULT;
  670.         op      = R_OP_CL;
  671.      }
  672.      break;
  673.  
  674.       default:break;
  675.    }
  676.       
  677.    if( op   != R_OP_CL   ) Warning( "Modifier(s) for operator ignored" );
  678.    if( attr != A_DEFAULT ) Warning( "Extra attributes ignored" );
  679.  
  680.    DB_VOID_RETURN;
  681. }
  682.  
  683.  
  684.  
  685. static int
  686. _do_targets( op, attr, set_dir, targets, prereq )/*
  687. ================================================= */
  688. int    op;
  689. t_attr    attr;
  690. char    *set_dir;
  691. CELLPTR targets;
  692. CELLPTR prereq;
  693. {
  694.    CELLPTR    tg1;        /* temporary target pointer        */
  695.    CELLPTR    tp1;        /* temporary prerequisite pointer    */
  696.    char        *p;        /* temporary char pointer        */
  697.    CELLPTR      prev_cell;    /* pointer for .UPDATEALL processing    */
  698.    CELLPTR      first_cell;    /* pointer for .UPDATEALL processing    */
  699.    int        update;        /* A_UPDATEALL attribute flag        */
  700.    int        smagic = 0;    /* collective amount of magic :-)    */
  701.  
  702.    DB_ENTER( "_do_targets" );
  703.  
  704.    if( update = ((attr & A_UPDATEALL) != 0) )
  705.       if( targets == NIL(CELL) )
  706.      Fatal( ".UPDATEALL attribute requires non-empty list of targets" );
  707.  
  708.    first_cell = prev_cell = NIL(CELL);
  709.    for( tg1 = targets; tg1 != NIL(CELL); tg1 = tg1->ce_link ) {
  710.       /* Check each target.  Check for inconsistencies between :: and : rule
  711.        * sets.  :: may follow either : or :: but not the reverse.
  712.        *
  713.        * Any targets that contain :: rules are represented by a prerequisite
  714.        * list hanging off the main target cell where each of the prerequisites
  715.        * is a copy of the target cell but is not entered into the hash table.
  716.        */
  717.       int magic  = (tg1->ce_flag & F_PERCENT) && !(tg1->ce_flag & F_MAGIC);
  718.       smagic |= magic;
  719.  
  720.       if( !(op & R_OP_DCL ) && (tg1->ce_flag & F_MULTI) && !magic )
  721.      Fatal( "Inconsistency in inference rules for %s", tg1->CE_NAME );
  722.  
  723.       if( magic )
  724.          do {
  725.         _build_graph( op, tg1, prereq );
  726.         if( prereq != NIL(CELL) ) prereq = prereq->ce_link;
  727.      } while( prereq != NIL(CELL) );
  728.       else if( !(tg1->ce_flag & F_SPECIAL) && 
  729.         (prereq == NIL(CELL)) &&
  730.         (p = _is_magic( tg1->CE_NAME )) != NIL(char))
  731.          smagic |= _do_magic( op, p, tg1, prereq, attr, set_dir );
  732.       else if( op & R_OP_DCL ) {
  733.      CELLPTR tmp_cell = _make_multi(tg1);
  734.      targets = _replace_cell( targets, tg1, tmp_cell );
  735.      tg1 = tmp_cell;
  736.       }
  737.  
  738.       if( !magic ) _set_attributes( attr, set_dir, tg1 );
  739.  
  740.       if( update ) {
  741.      if( smagic ) Fatal( ".UPDATEALL attribute not legal in meta rule" );
  742.  
  743.      /* Check this as it would break another circular .UPATEALL list if
  744.       * we blindly assign it and it is part of another list already. */
  745.      if( tg1->ce_all != NIL(CELL) )
  746.         Fatal( "Target [%s] appears on multiple .UPDATEALL lists" );
  747.  
  748.      tg1->ce_all = prev_cell;
  749.      if( prev_cell == NIL(CELL) ) first_cell = tg1;
  750.      prev_cell = tg1;
  751.       }
  752.  
  753.       /* Build the proper prerequisite list of the target.  If the `-',
  754.        * modifier was used clear the prerequisite list before adding any
  755.        * new prerequisites.  Else add them to the head/tail as appropriate.
  756.        *
  757.        * If the target has F_PERCENT set then no prerequisites are used. */
  758.  
  759.       if( !(tg1->ce_flag & F_PERCENT) ) {
  760.      if( op & R_OP_MI ) Clear_prerequisites( tg1 );
  761.  
  762.      if( (op & R_OP_UP) && (tg1->ce_prq != NIL(LINK)) )
  763.         _stick_at_head( tg1, prereq );
  764.      else for( tp1=prereq; tp1 != NIL(CELL); tp1 = tp1->ce_link )
  765.         Add_prerequisite( tg1, tp1, FALSE, FALSE );
  766.       }
  767.       else if( op & (R_OP_MI | R_OP_UP) )
  768.      Warning( "Modifier(s) `^!' for %-meta target ignored" );
  769.    }
  770.  
  771.    if( first_cell != NIL(CELL) ) first_cell->ce_all = prev_cell;
  772.  
  773.  
  774.    /* Check to see if we have NO targets but some attributes.  IF so then
  775.     * apply all of the attributes to the complete list of prerequisites.
  776.     * Cannot happen for F_PERCENT targets. (ie. in that case targets is always
  777.     * not NIL) */
  778.  
  779.    if( (targets == NIL(CELL)) && attr )
  780.       if( prereq != NIL(CELL) )
  781.      for( tp1=prereq; tp1 != NIL(CELL); tp1 = tp1->ce_link )
  782.         _set_attributes( attr, set_dir, tp1 );
  783.       else
  784.      _set_global_attr( attr );
  785.  
  786.    /* Fix up the ce_link pointers so that when we go to attach a recipe in
  787.     * Bind_targets to rules we get the right thing if it's an .UPDATEALL ::
  788.     * recipe */
  789.    if( update ) {
  790.       for( tp1=NIL(CELL),tg1=prev_cell; tg1!=first_cell; tg1=tg1->ce_all ) {
  791.      tg1->ce_link = tp1;
  792.      tp1 = tg1;
  793.       }
  794.       tg1->ce_link = tp1;
  795.       targets = first_cell;
  796.    }
  797.  
  798.    /* Now that we have built the lists of targets, the parser must parse the
  799.     * rules if there are any.  However we must start the rule list with the
  800.     * rule specified as via the ; kludge, if there is one */
  801.    _sv_targets = targets;
  802.    _sv_attr    = _sv_attro = attr;
  803.    _sv_flag    = ((op & R_OP_BG) ? F_SINGLE : F_DEFAULT);
  804.       
  805.    DB_RETURN( RULE_SCAN );
  806. }
  807.  
  808.  
  809. static int
  810. _do_magic( op, dot, target, prereq, attr, set_dir )/*
  811. =====================================================
  812.    This function takes a magic target of the form .<chars>.<chars> or
  813.    .<chars> and builds the appropriate % rules for that target.
  814.    
  815.    The function builds the % rule, `%.o : %.c'  from .c.o, and
  816.    `%.a :' from .a */
  817.  
  818. int    op;
  819. char    *dot;
  820. CELLPTR target;
  821. CELLPTR prereq;
  822. t_attr  attr;
  823. char    *set_dir;
  824. {
  825.    CELLPTR tg;
  826.    CELLPTR prq;
  827.    char    *tmp, *tmp2;
  828.  
  829.    DB_ENTER( "_do_magic" );
  830.  
  831.    if( prereq != NIL(CELL) )
  832.       Warning( "Ignoring prerequisites of old style meta-target" );
  833.  
  834.    if( dot == target->CE_NAME )    {        /* its of the form .a    */
  835.       tg  = Def_cell( "%" );            /* ==> no prerequisite  */
  836.       tmp = _build_meta( target->CE_NAME );
  837.       prq = Def_cell( tmp );
  838.       FREE( tmp );
  839.  
  840.       _build_graph( op, tg, prq );
  841.    }
  842.    else {
  843.       tmp = _build_meta( dot );
  844.       tg  = Def_cell( tmp );
  845.       FREE( tmp );
  846.  
  847.       tmp = _build_meta( tmp2 = _substr( target->CE_NAME, dot ) );
  848.       prq = Def_cell( tmp );
  849.       FREE( tmp  );
  850.       FREE( tmp2 );
  851.  
  852.       _build_graph( op, tg, prq );
  853.    }
  854.  
  855.    tg->ce_flag      |= F_PERCENT;
  856.    target->ce_flag  |= (F_MAGIC|F_PERCENT);
  857.  
  858.    _set_attributes( attr, set_dir, tg );
  859.  
  860.    DB_RETURN(1);
  861. }
  862.  
  863.  
  864. static CELLPTR
  865. _replace_cell( lst, cell, rep )
  866. CELLPTR lst;
  867. CELLPTR cell;
  868. CELLPTR rep;
  869. {
  870.    register CELLPTR tp;
  871.    
  872.    if( lst == cell ) {
  873.       rep->ce_link = lst->ce_link;
  874.       lst = rep;
  875.    }
  876.    else {
  877.       for( tp=lst; tp->ce_link != cell; tp=tp->ce_link );
  878.       rep->ce_link = tp->ce_link->ce_link;
  879.       tp->ce_link = rep;
  880.    }
  881.  
  882.    return(lst);
  883. }
  884.  
  885.  
  886. static char *
  887. _build_meta( name )/*
  888. =====================
  889.    Check to see if the name is of the form .c~ if so and if Augmake
  890.    translation is enabled then return s.%.c, else return %.suff, where if the
  891.    suffix ends in '~' then leave it be.*/
  892. char *name;
  893. {
  894.    char *tmp;
  895.    int  test = Augmake ? name[strlen(name)-1] == '~' : 0;
  896.  
  897.    tmp = _strjoin( test ? "s.%" : "%", name, -1, FALSE);
  898.    if( test ) tmp[ strlen(tmp)-1 ] = '\0';
  899.  
  900.    return(tmp);
  901. }
  902.  
  903.  
  904.  
  905. static void
  906. _build_graph( op, target, prereq )/*
  907. ====================================
  908.    This function is called to build the graph for the % rule given by
  909.    target : prereq cell combination.  This function assumes that target
  910.    is a % target and that prereq is a single % prerequisite.  R_OP_CL
  911.    rules replace existing rules if any, only R_OP_CL works for meta-rules.
  912.    %.o :: %.c is meaningless. 
  913.    
  914.    It also assumes that target cell has F_PERCENT set already. */
  915. int op;
  916. CELLPTR target;
  917. CELLPTR prereq;
  918. {
  919.    LINKPTR edl;
  920.    CELLPTR edge;
  921.    int match;
  922.  
  923.    DB_ENTER( "_build_graph" );
  924.    DB_PRINT( "%", ("Building graph for [%s : %s]", target->CE_NAME,
  925.             (prereq == NIL(CELL)) ? "" : prereq->CE_NAME) );
  926.  
  927.    if( prereq != NIL(CELL) ) {
  928.       char *name = prereq->CE_NAME;
  929.       int   len  = strlen(name);
  930.  
  931.       if( *name == '\'' && name[len-1]=='\'' ){
  932.      _add_global_prereq( prereq );
  933.      name[len-1] = '\0';
  934.      strcpy(name, name+1);
  935.      DB_VOID_RETURN;
  936.       }
  937.    }
  938.  
  939.    /* Search the list of prerequisites for the current target and see if
  940.     * any of them match the current %-meta : prereq pair.  NOTE that %-metas
  941.     * are built as if they were F_MULTI targets. */
  942.  
  943.    match = FALSE;
  944.    for( edl=target->ce_prq; edl != NIL(LINK); edl=edl->cl_next ) {
  945.       edge = edl->cl_prq;
  946.  
  947.       DB_PRINT( "%", ("Trying to match [%s]", edge?edge->CE_NAME:"(nil)") );
  948.  
  949.       if(    (!edge->ce_prq && !prereq)
  950.       || (   edge->ce_prq->cl_prq == prereq
  951.           && (   edge->ce_dir == _sv_setdir
  952.           || (   edge->ce_dir
  953.               && _sv_setdir
  954.               && !strcmp(edge->ce_dir,strchr(_sv_setdir,'=')+1)
  955.              )
  956.          )
  957.          )
  958.     ) {
  959.      match = TRUE;
  960.      break;
  961.       }
  962.    }
  963.  
  964.    if( match ) {
  965.       /* match is TRUE hence, we found an edge joining the target and the
  966.        * prerequisite so reset the new edge's how values to reflect the new
  967.        * recipe etc. */
  968.       DB_PRINT( "%", ("It's an old edge") );
  969.  
  970.       edge->ce_dir    = NIL(char);
  971.       edge->ce_flag  &= (F_PERCENT|F_MAGIC|F_DFA);
  972.       edge->ce_attr  &= A_NOINFER;
  973.    }
  974.    else {
  975.       DB_PRINT( "%", ("Adding a new edge") );
  976.  
  977.       if( !(target->ce_flag & F_DFA) ) {
  978.      Add_nfa( target->CE_NAME );
  979.      target->ce_flag |= F_DFA;
  980.       }
  981.       edge = _make_multi(target);
  982.       if( prereq ) Add_prerequisite(edge, prereq, FALSE, TRUE);
  983.    }
  984.  
  985.    if( op & R_OP_DCL )
  986.    Warning( "'::' operator for meta-target '%s' ignored, ':' operator assumed.",
  987.            target->CE_NAME );
  988.  
  989.    edge->ce_link = _sv_edgel;
  990.    _sv_edgel = edge;
  991.    _sv_globprq_only = 0;
  992.  
  993.    DB_VOID_RETURN;
  994. }
  995.  
  996.  
  997. static CELLPTR
  998. _make_multi( tg )
  999. CELLPTR tg;
  1000. {
  1001.    CELLPTR cp;
  1002.  
  1003.    /* This first handle the case when a : foo ; exists prior to seeing
  1004.     * a :: fee; */
  1005.    if( !(tg->ce_flag & F_MULTI) && (tg->ce_prq || tg->ce_recipe) ) {
  1006.       TALLOC(cp, 1, CELL);
  1007.       *cp = *tg;
  1008.  
  1009.       tg->ce_prq    = NIL(LINK);
  1010.       tg->ce_flag  |= F_RULES|F_MULTI|F_TARGET;
  1011.       tg->ce_attr  |= A_SEQ;
  1012.       tg->ce_recipe = NIL(STRING);
  1013.       tg->ce_dir    = NIL(char);
  1014.       cp->ce_count  = ++tg->ce_index;
  1015.  
  1016.       Add_prerequisite(tg, cp, FALSE, TRUE);
  1017.    }
  1018.  
  1019.    TALLOC(cp, 1, CELL);
  1020.    *cp = *tg;
  1021.  
  1022.    if( !(tg->ce_flag & F_MULTI) ) {
  1023.       tg->ce_prq    = NIL(LINK);
  1024.       tg->ce_flag  |= F_RULES|F_MULTI|F_TARGET;
  1025.       tg->ce_attr  |= A_SEQ;
  1026.       tg->ce_recipe = NIL(STRING);
  1027.       tg->ce_dir    = NIL(char);
  1028.    }
  1029.    else {
  1030.       cp->ce_flag  &= ~(F_RULES|F_MULTI);
  1031.       cp->ce_attr  &= ~A_SEQ;
  1032.       cp->ce_prq    = NIL(LINK);
  1033.       cp->ce_index  = 0;
  1034.    }
  1035.    cp->ce_count = ++tg->ce_index;
  1036.    cp->ce_flag |= F_TARGET;
  1037.  
  1038.    Add_prerequisite(tg, cp, FALSE, TRUE);
  1039.    return(cp);
  1040. }
  1041.  
  1042.  
  1043. static void
  1044. _add_global_prereq( pq )/*
  1045. ==========================
  1046.     Prerequisite is a non-% prerequisite for a %-rule target, add it to
  1047.     the target's list of global prerequsites to add on match */
  1048. CELLPTR pq;
  1049. {
  1050.    register LINKPTR ln;
  1051.  
  1052.    TALLOC( ln, 1, LINK );
  1053.    ln->cl_next = _sv_glb_prq;
  1054.    ln->cl_prq  = pq;
  1055.    _sv_glb_prq = ln;
  1056. }
  1057.  
  1058.  
  1059.  
  1060. static void
  1061. _set_attributes( attr, set_dir, cp )/*
  1062. ======================================
  1063.     Set the appropriate attributes for a cell */
  1064. t_attr    attr;
  1065. char    *set_dir;
  1066. CELLPTR cp;
  1067. {
  1068.    char   *dir;
  1069.  
  1070.    DB_ENTER( "_set_attributes" );
  1071.  
  1072.    /* If .SETDIR attribute is set then we have at least .SETDIR= in the
  1073.     * set_dir string.  So go and fishout what is at the end of the =.
  1074.     * If not set and not NULL then propagate it to the target cell. */
  1075.  
  1076.    if( attr & A_SETDIR ) {
  1077.       dir = strchr( set_dir, '=' ) + 1;
  1078.  
  1079.       if( cp->ce_dir )
  1080.      Warning( "Multiple .SETDIR for %s ignored", cp->CE_NAME );
  1081.       else
  1082.      if( *dir ) cp->ce_dir = _strdup(dir);
  1083.    }
  1084.    cp->ce_attr |= attr;        /* set rest of attributes for target */
  1085.  
  1086.    DB_VOID_RETURN;
  1087. }
  1088.  
  1089.  
  1090.  
  1091. static void
  1092. _set_global_attr( attr )/*
  1093. ==========================
  1094.     Handle the setting of the global attribute functions based on
  1095.     The attribute flags set in attr. */
  1096. t_attr attr;
  1097. {
  1098.    int flag;
  1099.  
  1100.    /* Some compilers can't handle a switch on a long, and t_attr is now a long
  1101.     * integer on some systems.  foey! */
  1102.    for( flag = MAX_ATTR; flag; flag >>= 1 )
  1103.       if( flag & attr )
  1104.      if( flag == A_PRECIOUS)      Def_macro(".PRECIOUS",  "y", M_EXPANDED);
  1105.      else if( flag == A_SILENT)   Def_macro(".SILENT",    "y", M_EXPANDED);
  1106.      else if( flag == A_IGNORE )  Def_macro(".IGNORE",    "y", M_EXPANDED);
  1107.      else if( flag == A_EPILOG )  Def_macro(".EPILOG",    "y", M_EXPANDED);
  1108.      else if( flag == A_PROLOG )  Def_macro(".PROLOG",    "y", M_EXPANDED);
  1109.      else if( flag == A_NOINFER ) Def_macro(".NOINFER",   "y", M_EXPANDED);
  1110.      else if( flag == A_SEQ )     Def_macro(".SEQUENTIAL","y", M_EXPANDED);
  1111.      else if( flag == A_SHELL )   Def_macro(".USESHELL",  "y", M_EXPANDED);
  1112.      else if( flag == A_MKSARGS ) Def_macro(".MKSARGS",   "y", M_EXPANDED);
  1113.      else if( flag == A_SWAP )    Def_macro(".SWAP",      "y", M_EXPANDED);
  1114.  
  1115.    attr &= ~A_GLOB;
  1116.    if( attr ) Warning( "Non global attribute(s) ignored" );
  1117. }
  1118.  
  1119.  
  1120.  
  1121. static void
  1122. _stick_at_head( cp, pq )/*
  1123. ==========================
  1124.     Add the prerequisite list to the head of the existing prerequisite
  1125.     list */
  1126.  
  1127. CELLPTR cp;          /* cell for target node    */
  1128. CELLPTR pq;        /* list of prerequisites to add */
  1129. {
  1130.    DB_ENTER( "_stick_at_head" );
  1131.  
  1132.    if( pq->ce_link != NIL(CELL) ) _stick_at_head( cp, pq->ce_link );
  1133.    Add_prerequisite( cp, pq, TRUE, FALSE );
  1134.  
  1135.    DB_VOID_RETURN;
  1136. }
  1137.  
  1138.  
  1139.  
  1140. static t_attr
  1141. _is_attribute( name )/*
  1142. =======================
  1143.    Check the passed name against the list of valid attributes and return the
  1144.    attribute index if it is, else return 0, indicating the name is not a valid
  1145.    attribute.  The present attributes are defined in dmake.h as A_xxx #defines,
  1146.    with the corresponding makefile specification:  (note they must be named
  1147.    exactly as defined below)
  1148.    
  1149.    Valid attributes are:  .IGNORE, .SETDIR=, .SILENT, .PRECIOUS, .LIBRARY,
  1150.                           .EPILOG, .PROLOG,  .LIBRARYM, .SYMBOL, .UPDATEALL,
  1151.               .USESHELL, .NOINFER, .PHONY, .SWAP, .SEQUENTIAL
  1152.               .NOSTATE,  .MKSARGS
  1153.  
  1154.    NOTE:  The strcmp's are OK since at most three are ever executed for any
  1155.           one attribute check, and that happens only when we can be fairly
  1156.           certain we have an attribute.  */
  1157. char *name;
  1158. {
  1159.    t_attr attr = 0;
  1160.    
  1161.    DB_ENTER( "_is_attribute" );
  1162.    
  1163.    if( *name++ == '.' )
  1164.       switch( *name )
  1165.       {
  1166.          case 'E': attr = (strcmp(name, "EPILOG"))   ? 0 : A_EPILOG;  break;
  1167.          case 'I': attr = (strcmp(name, "IGNORE"))   ? 0 : A_IGNORE;  break;
  1168.          case 'L': attr = (strcmp(name, "LIBRARY"))  ? 0 : A_LIBRARY; break;
  1169.          case 'M': attr = (strcmp(name, "MKSARGS"))  ? 0 : A_MKSARGS; break;
  1170.  
  1171.          case 'N':
  1172.         if( !strcmp(name, "NOINFER") )      attr = A_NOINFER;
  1173.         else if( !strcmp(name, "NOSTATE"))  attr = A_NOSTATE;
  1174.         else attr = 0;
  1175.         break;
  1176.  
  1177.          case 'U':
  1178.         if( !strcmp(name, "UPDATEALL") )    attr = A_UPDATEALL;
  1179.         else if( !strcmp(name, "USESHELL")) attr = A_SHELL;
  1180.         else attr = 0;
  1181.         break;
  1182.  
  1183.          case 'P':
  1184.             if( !strcmp(name, "PRECIOUS") )     attr = A_PRECIOUS;
  1185.             else if( !strcmp(name, "PROLOG") )  attr = A_PROLOG;
  1186.             else if( !strcmp(name, "PHONY") )   attr = A_PHONY;
  1187.             else attr = 0;
  1188.             break;
  1189.  
  1190.          case 'S':
  1191.             if( !strncmp(name, "SETDIR=", 7) )    attr = A_SETDIR;
  1192.             else if( !strcmp(name, "SILENT") )    attr = A_SILENT;
  1193.             else if( !strcmp(name, "SYMBOL") )    attr = A_SYMBOL;
  1194.             else if( !strcmp(name, "SEQUENTIAL")) attr = A_SEQ;
  1195.             else if( !strcmp(name, "SWAP"))       attr = A_SWAP;
  1196.             else attr = 0;
  1197.             break;
  1198.       }
  1199.  
  1200.    DB_RETURN( attr );
  1201. }
  1202.  
  1203.  
  1204.  
  1205. static int
  1206. _is_special( tg )/*
  1207. ===================
  1208.    This function returns TRUE if the name passed in represents a special
  1209.    target, otherwise it returns false.  A special target is one that has
  1210.    a special meaning to dmake, and may require processing at the time that
  1211.    it is parsed.
  1212.    
  1213.    Current Special targets are:
  1214.     .GROUPPROLOG    .GROUPEPILOG    .INCLUDE    .IMPORT
  1215.     .EXPORT        .SOURCE     .SUFFIXES    .ERROR
  1216.     .INCLUDEDIRS    .MAKEFILES    .REMOVE        .KEEP_STATE
  1217. */
  1218. char *tg;
  1219. {
  1220.    DB_ENTER( "_is_special" );
  1221.    
  1222.    if( *tg++ != '.' ) DB_RETURN( 0 );
  1223.    
  1224.    switch( *tg )
  1225.    {
  1226.       case 'I':
  1227.          if( !strcmp( tg, "IMPORT" ) )        DB_RETURN( ST_IMPORT   );
  1228.          else if( !strcmp( tg, "INCLUDE" ) )    DB_RETURN( ST_INCLUDE  );
  1229.      else if( !strcmp( tg, "INCLUDEDIRS" )) DB_RETURN( ST_REST     );
  1230.      break;
  1231.       
  1232.       case 'M':
  1233.          if( !strcmp( tg, "MAKEFILES" ) )    DB_RETURN( ST_REST     );
  1234.      break;
  1235.  
  1236.       case 'E':
  1237.          if( !strcmp( tg, "ERROR" ) )        DB_RETURN( ST_REST     );
  1238.          else if( !strcmp( tg, "EXPORT" ) )    DB_RETURN( ST_EXPORT   );
  1239.      break;
  1240.  
  1241.       case 'G':
  1242.      if( !strcmp( tg, "GROUPPROLOG" ))      DB_RETURN( ST_REST     );
  1243.      else if( !strcmp( tg, "GROUPEPILOG" )) DB_RETURN( ST_REST     );
  1244.      break;
  1245.  
  1246.       case 'K':
  1247.          if( !strcmp( tg, "KEEP_STATE" ) )    DB_RETURN( ST_KEEP     );
  1248.      break;
  1249.  
  1250.       case 'R':
  1251.          if( !strcmp( tg, "REMOVE" ) )        DB_RETURN( ST_REST     );
  1252.      break;
  1253.  
  1254.       case 'S':
  1255.          if( !strncmp( tg, "SOURCE", 6 ) )    DB_RETURN( ST_SOURCE   );
  1256.          else if( !strncmp(tg, "SUFFIXES", 8 )) DB_RETURN( ST_SOURCE   );
  1257.      break;
  1258.    }
  1259.    
  1260.    DB_RETURN( 0 );
  1261. }
  1262.  
  1263.  
  1264.  
  1265. static int
  1266. _is_percent( np )/*
  1267. ===================
  1268.     return TRUE if np points at a string containing a % sign */
  1269. char *np;
  1270. {
  1271.    return( (strchr(np,'%') && (*np != '\'' && np[strlen(np)-1] != '\'')) ?
  1272.        TRUE : FALSE );
  1273. }
  1274.  
  1275.  
  1276. static char *
  1277. _is_magic( np )/*
  1278. =================
  1279.     return TRUE if np points at a string of the form
  1280.           .<chars>.<chars>  or  .<chars>
  1281.     where chars are only alpha characters.
  1282.  
  1283.         NOTE:  reject target if it begins with ./ or ../ */
  1284. char *np;
  1285. {
  1286.    register char *n;
  1287.  
  1288.    n = np;
  1289.    if( *n != '.' ) return( NIL(char) );
  1290.    if (strchr(DirBrkStr, *(n+1))!=NULL || *(n+1) == '.' )
  1291.       return (NIL(char));
  1292.  
  1293.    for( n++; isgraph(*n) && (*n != '.'); n++ );
  1294.  
  1295.    if( *n != '\0' ) {
  1296.       if( *n != '.' )  return( NIL(char) );
  1297.       for( np = n++; isgraph( *n ) && (*n != '.'); n++ );
  1298.       if( *n != '\0' ) return( NIL(char) );
  1299.    }
  1300.    else if( !Augmake )
  1301.       return( NIL(char) );
  1302.  
  1303.    /* np points at the second . of .<chars>.<chars> string.
  1304.     * if the special target is of the form .<chars> then np points at the
  1305.     * first . in the token. */
  1306.  
  1307.    return( np );
  1308. }
  1309.  
  1310.