home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume14 / dmake / part05 < prev    next >
Encoding:
Text File  |  1990-07-26  |  39.4 KB  |  1,370 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v14i015: dmake version 3.5 part 5/21
  3. From: dvadura@watdragon.waterloo.edu (Dennis Vadura)
  4. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5.  
  6. Posting-number: Volume 14, Issue 15
  7. Submitted-by: dvadura@watdragon.waterloo.edu (Dennis Vadura)
  8. Archive-name: dmake/part05
  9.  
  10. #!/bin/sh
  11. # this is part 5 of a multipart archive
  12. # do not concatenate these parts, unpack them in order with /bin/sh
  13. # file rulparse.c continued
  14. #
  15. CurArch=5
  16. if test ! -r s2_seq_.tmp
  17. then echo "Please unpack part 1 first!"
  18.      exit 1; fi
  19. ( read Scheck
  20.   if test "$Scheck" != $CurArch
  21.   then echo "Please unpack part $Scheck next!"
  22.        exit 1;
  23.   else exit 0; fi
  24. ) < s2_seq_.tmp || exit 1
  25. echo "x - Continuing file rulparse.c"
  26. sed 's/^X//' << 'SHAR_EOF' >> rulparse.c
  27. X     for( cp=prereq; cp != NIL(CELL); cp = cp->ce_link ) {
  28. X        name = cp->CE_NAME;
  29. X        
  30. X        if( *name == '<' ) {
  31. X           /* We have a file name enclosed in <....>
  32. X            * so get rid of the <> arround the file name */
  33. X
  34. X           name++;
  35. X           if( (tmp = strrchr( name, '>' )) != NIL( char ) )
  36. X          *tmp = 0;
  37. X
  38. X           if( If_root_path( name ) )
  39. X              fil = Openfile( name, FALSE );
  40. X           else
  41. X          fil = NIL(FILE);
  42. X        }
  43. X        else
  44. X           fil = Openfile( name, FALSE );
  45. X           
  46. X        if( fil == NIL(FILE) ) {    /*if true ==> not found in current dir*/
  47. X           /* Now we must scan the list of prerequisites for .INCLUDEDIRS
  48. X            * looking for the file in each of the specified directories.
  49. X        * if we don't find it then we issue an error.  The error
  50. X        * message is suppressed if the .IGNORE attribute of attr is
  51. X        * set.  If a file is found we call Parse on the file to
  52. X        * perform the parse and then continue on from where we left
  53. X        * off.  */
  54. X
  55. X           if( (dp->CE_HOW != NIL(HOW)) &&
  56. X           ((lp = dp->CE_HOW->hw_prq) != NIL(LINK)) )
  57. X          for(; lp != NIL(LINK) && fil == NIL(FILE); lp=lp->cl_next) {
  58. X             dir  = lp->cl_prq->CE_NAME;
  59. X             if( strchr(dir, '$') ) dir = Expand(dir);
  60. X             path = Build_path( dir, name );
  61. X
  62. X             DB_PRINT( "par", ("Trying to include [%s]", path) );
  63. X
  64. X             fil = Openfile( path, FALSE );
  65. X             if( dir != lp->cl_prq->CE_NAME ) FREE(dir);
  66. X          }
  67. X        }
  68. X
  69. X        if( fil != NIL(FILE) )
  70. X           Parse( fil );
  71. X        else if( !((Glob_attr | attr) & A_IGNORE) )
  72. X           Fatal( "Include file %s, not found", name );
  73. X     }
  74. X
  75. X     if( pushed ) Pop_dir(FALSE);
  76. X     attr &= ~(A_IGNORE|A_SETDIR);
  77. X      }
  78. X      break;
  79. X     
  80. X      case ST_SOURCE:
  81. X      /* case ST_SUFFIXES: */
  82. X           if( prereq != NIL(CELL) )
  83. X        _do_targets( op & (R_OP_CL | R_OP_MI | R_OP_UP), attr, set_dir,
  84. X             target, prereq );
  85. X     else {
  86. X        /* The old semantics of .SOURCE were that an empty list of
  87. X         * prerequisites clears the .SOURCE list.  So we must implement
  88. X         * that here as a clearout prerequisite operation.  Since this is
  89. X         * a standard operation with the :- opcode we can simply call the
  90. X         * proper routine with the target cell and it should do the trick
  91. X         */
  92. X
  93. X        if( op == R_OP_CL || (op & R_OP_MI) )
  94. X           Clear_prerequisites( target->CE_HOW );
  95. X     }
  96. X
  97. X     op &= ~(R_OP_MI | R_OP_UP);
  98. X     break;
  99. X
  100. X      case ST_REST:
  101. X         /* The rest of the special targets can all take rules, as such they
  102. X      * must be able to affect the state of the parser. */
  103. X
  104. X     {
  105. X        int s_targ = Target;
  106. X
  107. X        Target     = TRUE;
  108. X        _sp_target = TRUE;
  109. X        *state     = _do_targets( op, attr, set_dir, target, prereq );
  110. X        Target     = s_targ;
  111. X
  112. X        set_dir = NIL( char );
  113. X        attr    = A_DEFAULT;
  114. X        op      = R_OP_CL;
  115. X     }
  116. X     break;
  117. X
  118. X      default:break;
  119. X   }
  120. X      
  121. X   if( set_dir != NIL(char) ) FREE( set_dir );
  122. X   if( op   != R_OP_CL   ) Warning( "Modifier(s) for operator ignored" );
  123. X   if( attr != A_DEFAULT ) Warning( "Extra attributes ignored" );
  124. X
  125. X   DB_VOID_RETURN;
  126. X}
  127. X
  128. X
  129. X
  130. Xstatic int
  131. X_do_targets( op, attr, set_dir, targets, prereq )/*
  132. X================================================= */
  133. Xint    op;
  134. Xint    attr;
  135. Xchar    *set_dir;
  136. XCELLPTR targets;
  137. XCELLPTR prereq;
  138. X{
  139. X   CELLPTR    tg1;        /* temporary target pointer        */
  140. X   CELLPTR    tp1;        /* temporary prerequisite pointer    */
  141. X   char        *p;        /* temporary char pointer        */
  142. X   CELLPTR      prev_cell;    /* pointer for .UPDATEALL processing    */
  143. X   int        update;        /* A_UPDATEALL attribute flag        */
  144. X   int        smagic = 0;    /* collective amount of magic :-)    */
  145. X
  146. X   DB_ENTER( "_do_targets" );
  147. X
  148. X   if( update = (attr & A_UPDATEALL) )
  149. X      if( targets == NIL(CELL) )
  150. X        Fatal( ".UPDATEALL attribute requires non-empty list of targets" );
  151. X
  152. X   prev_cell = NIL(CELL);
  153. X   for( tg1 = targets; tg1 != NIL(CELL); tg1 = tg1->ce_link ) {
  154. X      /* Check each target.  Check for inconsistencies between :: and : rule
  155. X       * sets.  :: may follow either : or :: but not the reverse.  We allocate
  156. X       * a HOW cell for each target that we see, if it already does not have
  157. X       * one.  If it has a HOW cell then we use it, unless the current
  158. X       * operator is ::, in which case we must allocate a new one. */
  159. X
  160. X      int magic  = (tg1->ce_flag & F_PERCENT) && !(tg1->ce_flag & F_MAGIC);
  161. X      smagic |= magic;
  162. X
  163. X      if( !(op & R_OP_DCL ) && (tg1->ce_flag & F_MULTI) && !magic )
  164. X     Fatal( "Inconsistency in inference rules for %s", tg1->CE_NAME );
  165. X
  166. X      if( magic )
  167. X         do {
  168. X        _build_graph( op, tg1, prereq );
  169. X        if( prereq != NIL(CELL) ) prereq = prereq->ce_link;
  170. X     } while( prereq != NIL(CELL) );
  171. X      else if( !(tg1->ce_flag & F_SPECIAL) && 
  172. X        (p = _is_magic( tg1->CE_NAME )) != NIL(char) )
  173. X         smagic |= _do_magic( op, p, tg1, prereq, attr, set_dir );
  174. X      else if( op & R_OP_DCL ) {
  175. X     HOWPTR hp;
  176. X
  177. X     TALLOC( hp, 1, HOW );
  178. X
  179. X     hp->hw_next   = tg1->CE_HOW;
  180. X     tg1->CE_HOW   = hp;
  181. X     tg1->ce_flag |= F_MULTI;
  182. X      }
  183. X      else if( tg1->CE_HOW == NIL(HOW) )
  184. X     TALLOC( tg1->CE_HOW, 1, HOW );
  185. X
  186. X      if( !magic ) _set_attributes( attr, set_dir, tg1 );
  187. X
  188. X      if( update ) {
  189. X     if( smagic ) Fatal( ".UPDATEALL attribute not legal in meta rule" );
  190. X
  191. X     /* Check this as it would break another cirlcular .UPATEALL list if
  192. X      * we blindly assign it and it is part of another list already. */
  193. X     if( tg1->ce_all != NIL(CELL) )
  194. X        Fatal( "Target [%s] appears on multiple .UPDATEALL lists" );
  195. X
  196. X     tg1->ce_all = prev_cell;
  197. X     prev_cell = tg1;
  198. X      }
  199. X
  200. X      /* Build the proper prerequisite list of the target.  If the `-',
  201. X       * modifier was used clear the prerequisite list before adding any
  202. X       * new prerequisites.  Else add them to the head/tail as appropriate.
  203. X       *
  204. X       * If the target has F_PERCENT set then no prerequisites are used. */
  205. X
  206. X      if( !(tg1->ce_flag & F_PERCENT) )
  207. X     if( tg1 == targets || !update ) {
  208. X        register HOWPTR  how  = tg1->CE_HOW;
  209. X
  210. X        if( op & R_OP_MI ) Clear_prerequisites( how );
  211. X
  212. X        if( (op & R_OP_UP) && (how->hw_prq != NIL(LINK)) )
  213. X           _stick_at_head( how, prereq );
  214. X        else
  215. X           for( tp1=prereq; tp1 != NIL(CELL); tp1 = tp1->ce_link )
  216. X          Add_prerequisite( how, tp1, FALSE );
  217. X     }
  218. X      else
  219. X         if( op & (R_OP_MI | R_OP_UP) )
  220. X        Warning( "Modifier(s) `^!' for ':' operator ignored" );
  221. X   }
  222. X
  223. X   if( targets != NIL(CELL) ) targets->ce_all = prev_cell;
  224. X
  225. X
  226. X   /* Check to see if we have NO targets but some attributes.  IF so then
  227. X    * apply all of the attributes to the complete list of prerequisites.
  228. X    * Cannot happen for F_PERCENT targets. (ie. in that case targets is always
  229. X    * not NIL) */
  230. X
  231. X   if( (targets == NIL(CELL)) && attr )
  232. X      if( prereq != NIL(CELL) )
  233. X     for( tp1=prereq; tp1 != NIL(CELL); tp1 = tp1->ce_link ) {
  234. X        if( tp1->CE_HOW == NIL(HOW) ) TALLOC( tp1->CE_HOW, 1, HOW );
  235. X        _set_attributes( attr, set_dir, tp1 );
  236. X     }
  237. X      else
  238. X     _set_global_attr( attr, set_dir );
  239. X
  240. X   /* Fix up the HOW pointers for the A_UPDATEALL case, they should all point
  241. X    * to the same cell (targets->CE_HOW), if the .UPDATEALL attribute is given
  242. X    */
  243. X   if( update && targets != NIL(CELL) )
  244. X      for( tg1=targets->ce_link; tg1 != NIL(CELL); tg1 = tg1->ce_link ) {
  245. X     FREE(tg1->CE_HOW);
  246. X     tg1->CE_HOW = targets->CE_HOW;
  247. X      }
  248. X
  249. X   /* Now that we have built the lists of targets, the parser must parse the
  250. X    * rules if there are any.  However we must start the rule list with the
  251. X    * rule specified as via the ; kludge, if there is one */
  252. X
  253. X   _sv_targets = targets;
  254. X   _sv_attr    = _sv_attro = attr;
  255. X   _sv_flag    = ((op & R_OP_BG) ? F_SINGLE : F_DEFAULT);
  256. X      
  257. X   DB_RETURN( RULE_SCAN );
  258. X}
  259. X
  260. X
  261. Xstatic int
  262. X_do_magic( op, dot, target, prereq, attr, set_dir )/*
  263. X=====================================================
  264. X   This function takes a magic target of the form .<chars>.<chars> or
  265. X   .<chars> and builds the appropriate % rules for that target.
  266. X   
  267. X   The function builds the % rule, `%.o : %.c'  from .c.o, and
  268. X   `%.a :' from .a */
  269. X
  270. Xint    op;
  271. Xchar    *dot;
  272. XCELLPTR target;
  273. XCELLPTR prereq;
  274. Xint     attr;
  275. Xchar    *set_dir;
  276. X{
  277. X   CELLPTR tg;
  278. X   CELLPTR prq;
  279. X   char    *tmp, *tmp2;
  280. X
  281. X   DB_ENTER( "_do_magic" );
  282. X
  283. X   if( prereq != NIL(CELL) )
  284. X      Warning( "Ignoring prerequisites of old style meta-target" );
  285. X
  286. X   op &= (R_OP_CL | R_OP_DCL);
  287. X
  288. X   if( dot == target->CE_NAME )    {        /* its of the form .a    */
  289. X      tg  = Def_cell( "%", NIL(CELL) );        /* ==> no prerequisite  */
  290. X      tmp = _build_meta( target->CE_NAME );
  291. X      prq = Def_cell( tmp, NIL(CELL) );
  292. X      FREE( tmp );
  293. X
  294. X      _build_graph( op, tg, prq );
  295. X   }
  296. X   else {
  297. X      tmp = _build_meta( dot );
  298. X      tg  = Def_cell( tmp, NIL(CELL) );
  299. X      FREE( tmp );
  300. X
  301. X      tmp = _build_meta( tmp2 = _substr( target->CE_NAME, dot ) );
  302. X      prq = Def_cell( tmp, NIL(CELL) );
  303. X      FREE( tmp  );
  304. X      FREE( tmp2 );
  305. X
  306. X      _build_graph( op, tg, prq );
  307. X   }
  308. X
  309. X   tg->ce_flag      |= F_PERCENT;
  310. X   target->ce_flag  |= (tg->ce_flag & (F_MULTI | F_PERCENT)) | F_MAGIC;
  311. X   target->CE_EDGES  = tg->CE_EDGES;
  312. X
  313. X   _set_attributes( attr, set_dir, tg );
  314. X
  315. X   DB_RETURN(1);
  316. X}
  317. X
  318. X
  319. X
  320. Xstatic char *
  321. X_build_meta( name )/*
  322. X=====================
  323. X   Check to see if the name is of the form .c~ if so and if Augmake
  324. X   translation is enabled then return s.%.c, else return %.suff, where if the
  325. X   suffix ends in '~' then leave it be.*/
  326. Xchar *name;
  327. X{
  328. X   char *tmp;
  329. X   int  test = Augmake ? name[strlen(name)-1] == '~' : 0;
  330. X
  331. X   tmp = _strjoin( test ? "s.%" : "%", name, -1, FALSE);
  332. X   if( test ) tmp[ strlen(tmp)-1 ] = '\0';
  333. X
  334. X   return(tmp);
  335. X}
  336. X
  337. X
  338. X
  339. Xstatic void
  340. X_build_graph( op, target, prereq )/*
  341. X====================================
  342. X   This function is called to build the graph for the % rule given by
  343. X   target : prereq cell combination.  This function assumes that target
  344. X   is a % target and that prereq is a single % prerequisite.  op can be
  345. X   either R_OP_CL or R_OP_DCL, all other operations are ignored.
  346. X   
  347. X   It also assumes that target cell has F_PERCENT set already. */
  348. Xint op;
  349. XCELLPTR target;
  350. XCELLPTR prereq;
  351. X{
  352. X   int      match;
  353. X   EDGEPTR  edge;
  354. X
  355. X   DB_ENTER( "_build_graph" );
  356. X   DB_PRINT( "%", ("Building graph for [%s : %s]", target->CE_NAME,
  357. X            (prereq == NIL(CELL)) ? "" : prereq->CE_NAME) );
  358. X
  359. X   if( prereq != NIL(CELL) ) {
  360. X      char *name = prereq->CE_NAME;
  361. X      int   len  = strlen(name);
  362. X
  363. X      if( *name == '\'' && name[len-1]=='\'' ){
  364. X     _add_global_prereq( prereq );
  365. X     name[len-1] = '\0';
  366. X     strcpy(name, name+1);
  367. X     DB_VOID_RETURN;
  368. X      }
  369. X   }
  370. X
  371. X   /* The list of edges is kept as a circular list.  Thus we must find the
  372. X    * last edge if we are to add a new edge.  Also we must check the list to
  373. X    * find out if a new edge needs to be added. */
  374. X
  375. X   match = FALSE;
  376. X   if( (edge = target->CE_EDGES) != NIL(EDGE) ) {
  377. X      EDGEPTR start;
  378. X
  379. X      start = edge;
  380. X      do {
  381. X     DB_PRINT( "%", ("Trying to match [%s]", edge->ed_prq->CE_NAME) );
  382. X
  383. X         if( edge->ed_prq == prereq )
  384. X        match = TRUE;
  385. X     else
  386. X        edge  = edge->ed_next;
  387. X      }
  388. X      while ( !match && start != edge );
  389. X   }
  390. X
  391. X   if( match ) {
  392. X      /* match is TRUE hence, we found an edge joining the target and the
  393. X       * prerequisite so set the current target's CE_EDGES pointer to point
  394. X       * at the edge we found and make sure the new edge has a valid HOW
  395. X       * pointer. */
  396. X
  397. X      DB_PRINT( "%", ("It's an old edge") );
  398. X
  399. X      target->CE_EDGES = edge;
  400. X
  401. X      if( op & R_OP_DCL ) {
  402. X         HOWPTR hp;
  403. X
  404. X     TALLOC( hp, 1, HOW );
  405. X
  406. X     hp->hw_next   = edge->ed_how;
  407. X     edge->ed_how  = hp;
  408. X      }
  409. X      else {
  410. X     HOWPTR hp = edge->ed_how;
  411. X
  412. X     hp->hw_flag = F_DEFAULT;
  413. X     hp->hw_attr = A_DEFAULT;
  414. X     target->ce_dir    = NIL(char);
  415. X     target->ce_flag  &= (F_PERCENT|F_MAGIC);
  416. X     target->ce_attr  &= A_NOINFER;
  417. X      }
  418. X    
  419. X   }
  420. X   else {
  421. X      EDGEPTR tedge;
  422. X
  423. X      TALLOC( tedge, 1, EDGE );
  424. X
  425. X      if( edge == NIL(EDGE) ) {
  426. X     DB_PRINT( "%", ("It's a new edge") );
  427. X     edge = tedge;
  428. X     target->CE_EDGES = edge->ed_next = edge;
  429. X      }
  430. X      else {
  431. X     DB_PRINT( "%", ("It's a new edge (non-empty edge list)") );
  432. X     tedge->ed_next   = edge->ed_next;
  433. X     edge->ed_next    = tedge;
  434. X     target->CE_EDGES = edge = tedge;
  435. X      }
  436. X
  437. X      /* This was a new edge so we must point it's prerequisite pointer at the
  438. X       * prerequisite, and add the first HOW cell.
  439. X       * Since this is also the first time we have seen the % target we
  440. X       * add it to the NFA we are building of % rule targets. */
  441. X
  442. X      TALLOC( edge->ed_how, 1, HOW );
  443. X
  444. X      edge->ed_prq = prereq;
  445. X      edge->ed_tg  = target;
  446. X
  447. X      if( !(target->ce_flag & F_DFA) ) {
  448. X     Add_dfa( target->CE_NAME );
  449. X     target->ce_flag |= F_DFA;
  450. X      }
  451. X
  452. X      if( op & R_OP_DCL ) target->ce_flag |= F_MULTI;
  453. X   }
  454. X
  455. X   edge->ed_link = _sv_edgel;
  456. X   _sv_edgel = edge;
  457. X   _sv_globprq_only = 0;
  458. X
  459. X   DB_VOID_RETURN;
  460. X}
  461. X
  462. X
  463. X
  464. Xstatic void
  465. X_add_global_prereq( pq )/*
  466. X==========================
  467. X    Prerequisite is a non-% prerequisite for a %-rule target, add it to
  468. X    the target's list of global prerequsites to add on match */
  469. XCELLPTR pq;
  470. X{
  471. X   register LINKPTR ln;
  472. X
  473. X   TALLOC( ln, 1, LINK );
  474. X   ln->cl_next = _sv_glb_prq;
  475. X   ln->cl_prq  = pq;
  476. X   _sv_glb_prq = ln;
  477. X}
  478. X
  479. X
  480. X
  481. Xstatic void
  482. X_set_attributes( attr, set_dir, cell )/*
  483. X=============================================
  484. X    Set the appropriate attributes for a cell */
  485. Xint    attr;
  486. Xchar    *set_dir;
  487. XCELLPTR cell;
  488. X{
  489. X   char   *dir;
  490. X
  491. X   DB_ENTER( "_set_attributes" );
  492. X
  493. X   /* If .SETDIR attribute is set then we have at least .SETDIR= in the
  494. X    * set_dir string.  So go and fishout what is at the end of the =.
  495. X    * If not set and not NULL then propagate it to the target cell. */
  496. X
  497. X   if( attr & A_SETDIR ) {
  498. X      dir = strchr( set_dir, '=' ) + 1;
  499. X
  500. X      if( cell->ce_attr & A_SETDIR )
  501. X     Warning( "Multiple .SETDIR for %s ignored", cell->CE_NAME );
  502. X      else
  503. X     if( *dir ) cell->ce_dir = dir;
  504. X   }
  505. X   cell->ce_attr |= attr;        /* set rest of attributes for target */
  506. X
  507. X   DB_VOID_RETURN;
  508. X}
  509. X
  510. X
  511. X
  512. Xstatic void
  513. X_set_global_attr( attr, dir )/*
  514. X===============================
  515. X    Handle the setting of the global attribute functions based on
  516. X    The attribute flags set in attr.  Note we set the dir path name
  517. X    to be the value of Start_dir.  If Start_dir is initially set
  518. X    Make will CD to that directory before making any targets. */
  519. Xint  attr;
  520. Xchar *dir;
  521. X{
  522. X   int flag;
  523. X
  524. X   for( flag = MAX_ATTR; flag; flag >>= 1 )
  525. X      switch( flag & attr )
  526. X      {
  527. X     case A_PRECIOUS: Def_macro(".PRECIOUS",  "y", M_EXPANDED); break;
  528. X     case A_SILENT:   Def_macro(".SILENT",    "y", M_EXPANDED); break;
  529. X     case A_IGNORE:   Def_macro(".IGNORE",    "y", M_EXPANDED); break;
  530. X     case A_EPILOG:   Def_macro(".EPILOG",    "y", M_EXPANDED); break;
  531. X     case A_PROLOG:   Def_macro(".PROLOG",    "y", M_EXPANDED); break;
  532. X     case A_NOINFER:  Def_macro(".NOINFER",   "y", M_EXPANDED); break;
  533. X     case A_SEQ:      Def_macro(".SEQUENTIAL","y",M_EXPANDED); break;
  534. X
  535. X     case A_SETDIR:
  536. X        dir = strchr( dir, '=' ) + 1;
  537. X        if( *dir ) Start_dir.ce_dir = dir;
  538. X        break;
  539. X      }
  540. X   
  541. X   attr &= ~(A_PRECIOUS | A_SETDIR | A_SILENT | A_IGNORE |
  542. X             A_EPILOG | A_PROLOG | A_NOINFER | A_SEQ);
  543. X
  544. X   if( attr )
  545. X      Warning( "Non global attribute(s) ignored" );
  546. X}
  547. X
  548. X
  549. X
  550. Xstatic void
  551. X_stick_at_head( how, pq )/*
  552. X===========================
  553. X    Add the prerequisite list to the head of the existing prerequisite
  554. X    list */
  555. X
  556. XHOWPTR  how;        /* HOW cell for target node    */
  557. XCELLPTR pq;        /* list of prerequisites to add */
  558. X{
  559. X   DB_ENTER( "_stick_at_head" );
  560. X
  561. X   if( pq->ce_link != NIL(CELL) ) _stick_at_head( how, pq->ce_link );
  562. X   Add_prerequisite( how, pq, TRUE );
  563. X
  564. X   DB_VOID_RETURN;
  565. X}
  566. X
  567. X
  568. X
  569. Xstatic int
  570. X_is_attribute( name )/*
  571. X=======================
  572. X   Check the passed name against the list of valid attributes and return the
  573. X   attribute index if it is, else return 0, indicating the name is not a valid
  574. X   attribute.  The present attributes are defined in dmake.h as A_xxx #defines,
  575. X   with the corresponding makefile specification:  (note they must be named
  576. X   exactly as defined below)
  577. X   
  578. X   Valid attributes are:  .IGNORE, .SETDIR=, .SILENT, .PRECIOUS, .LIBRARY,
  579. X                          .EPILOG, .PROLOG,  .LIBRARYM, .SYMBOL, .UPDATEALL,
  580. X              .NOINFER
  581. X
  582. X   NOTE:  The strcmp's are OK since at most three are ever executed for any
  583. X          one attribute check, and that happens only when we can be fairly
  584. X          certain we have an attribute.  */
  585. Xchar *name;
  586. X{
  587. X   int attr = 0;
  588. X   
  589. X   DB_ENTER( "_is_attribute" );
  590. X   
  591. X   if( *name++ == '.' )
  592. X      switch( *name )
  593. X      {
  594. X         case 'E': attr = (strcmp(name, "EPILOG"))   ? 0 : A_EPILOG;  break;
  595. X         case 'I': attr = (strcmp(name, "IGNORE"))   ? 0 : A_IGNORE;  break;
  596. X         case 'L': attr = (strcmp(name, "LIBRARY"))  ? 0 : A_LIBRARY; break;
  597. X         case 'N': attr = (strcmp(name, "NOINFER"))  ? 0 : A_NOINFER; break;
  598. X         case 'U': attr = (strcmp(name, "UPDATEALL"))? 0 : A_UPDATEALL;break;
  599. X
  600. X         case 'P':
  601. X            if( !strcmp(name, "PRECIOUS") )     attr = A_PRECIOUS;
  602. X            else if( !strcmp(name, "PROLOG") )  attr = A_PROLOG;
  603. X            else attr = 0;
  604. X            break;
  605. X
  606. X         case 'S':
  607. X            if( !strncmp(name, "SETDIR=", 7) )  attr = A_SETDIR;
  608. X            else if( !strcmp(name, "SILENT") )  attr = A_SILENT;
  609. X            else if( !strcmp(name, "SYMBOL") )  attr = A_SYMBOL;
  610. X            else if( !strcmp(name, "SEQUENTIAL")) attr = A_SEQ;
  611. X            else attr = 0;
  612. X            break;
  613. X      }
  614. X
  615. X   DB_RETURN( attr );
  616. X}
  617. X
  618. X
  619. X
  620. Xstatic int
  621. X_is_special( tg )/*
  622. X===================
  623. X   This function returns TRUE if the name passed in represents a special
  624. X   target, otherwise it returns false.  A special target is one that has
  625. X   a special meaning to dmake, and may require processing at the time that
  626. X   it is parsed.
  627. X   
  628. X   Current Special targets are:
  629. X    .GROUPPROLOG    .GROUPEPILOG    .INCLUDE    .IMPORT
  630. X    .EXPORT        .SOURCE     .SUFFIXES    .ERROR
  631. X    .INCLUDEDIRS    .MAKEFILES    .REMOVE
  632. X*/
  633. Xchar *tg;
  634. X{
  635. X   DB_ENTER( "_is_special" );
  636. X   
  637. X   if( *tg++ != '.' ) DB_RETURN( 0 );
  638. X   
  639. X   switch( *tg )
  640. X   {
  641. X      case 'I':
  642. X         if( !strcmp( tg, "IMPORT" ) )        DB_RETURN( ST_IMPORT   );
  643. X         else if( !strcmp( tg, "INCLUDE" ) )    DB_RETURN( ST_INCLUDE  );
  644. X     else if( !strcmp( tg, "INCLUDEDIRS" )) DB_RETURN( ST_REST     );
  645. X     break;
  646. X      
  647. X      case 'M':
  648. X         if( !strcmp( tg, "MAKEFILES" ) )    DB_RETURN( ST_REST     );
  649. X     break;
  650. X
  651. X      case 'E':
  652. X         if( !strcmp( tg, "ERROR" ) )        DB_RETURN( ST_REST     );
  653. X         else if( !strcmp( tg, "EXPORT" ) )    DB_RETURN( ST_EXPORT   );
  654. X     break;
  655. X
  656. X      case 'G':
  657. X     if( !strcmp( tg, "GROUPPROLOG" ))      DB_RETURN( ST_REST     );
  658. X     else if( !strcmp( tg, "GROUPEPILOG" )) DB_RETURN( ST_REST     );
  659. X     break;
  660. X
  661. X      case 'R':
  662. X         if( !strcmp( tg, "REMOVE" ) )        DB_RETURN( ST_REST     );
  663. X     break;
  664. X
  665. X      case 'S':
  666. X         if( !strncmp( tg, "SOURCE", 6 ) )    DB_RETURN( ST_SOURCE   );
  667. X         else if( !strncmp(tg, "SUFFIXES", 8 )) DB_RETURN( ST_SOURCE   );
  668. X     break;
  669. X   }
  670. X   
  671. X   DB_RETURN( 0 );
  672. X}
  673. X
  674. X
  675. X
  676. Xstatic int
  677. X_is_percent( np )/*
  678. X===================
  679. X    return TRUE if np points at a string containing a % sign */
  680. Xchar *np;
  681. X{
  682. X   return( (strchr(np,'%') && (*np != '\'' && np[strlen(np)-1] != '\'')) ?
  683. X       TRUE : FALSE );
  684. X}
  685. X
  686. X
  687. Xstatic char *
  688. X_is_magic( np )/*
  689. X=================
  690. X    return TRUE if np points at a string of the form
  691. X          .<chars>.<chars>  or  .<chars>
  692. X    where chars are only alpha characters.
  693. X
  694. X        NOTE:  reject target if it begins with ./ or ../ */
  695. Xchar *np;
  696. X{
  697. X   register char *n;
  698. X
  699. X   n = np;
  700. X   if( *n != '.' ) return( NIL(char) );
  701. X   if (strchr(DirBrkStr, *(n+1))!=NULL || *(n+1) == '.' )
  702. X      return (NIL(char));
  703. X
  704. X   for( n++; isgraph(*n) && (*n != '.'); n++ );
  705. X
  706. X   if( *n != '\0' ) {
  707. X      if( *n != '.' )  return( NIL(char) );
  708. X      for( np = n++; isgraph( *n ) && (*n != '.'); n++ );
  709. X      if( *n != '\0' ) return( NIL(char) );
  710. X   }
  711. X   else if( !Augmake )
  712. X      return( NIL(char) );
  713. X
  714. X   /* np points at the second . of .<chars>.<chars> string.
  715. X    * if the special target is of the form .<chars> then np points at the
  716. X    * first . in the token. */
  717. X
  718. X   return( np );
  719. X}
  720. X
  721. SHAR_EOF
  722. echo "File rulparse.c is complete"
  723. chmod 0440 rulparse.c || echo "restore of rulparse.c fails"
  724. echo "x - extracting quit.c (Text)"
  725. sed 's/^X//' << 'SHAR_EOF' > quit.c &&
  726. X/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/quit.c,v 1.1 90/07/19 13:53:29 dvadura Exp $
  727. X-- SYNOPSIS -- end the dmake session.
  728. X-- 
  729. X-- DESCRIPTION
  730. X--     Handles dmake termination.
  731. X--
  732. X-- AUTHOR
  733. X--      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
  734. X--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
  735. X--
  736. X-- COPYRIGHT
  737. X--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
  738. X-- 
  739. X--      This program is free software; you can redistribute it and/or
  740. X--      modify it under the terms of the GNU General Public License
  741. X--      (version 1), as published by the Free Software Foundation, and
  742. X--      found in the file 'LICENSE' included with this distribution.
  743. X-- 
  744. X--      This program is distributed in the hope that it will be useful,
  745. X--      but WITHOUT ANY WARRANTY; without even the implied warrant of
  746. X--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  747. X--      GNU General Public License for more details.
  748. X-- 
  749. X--      You should have received a copy of the GNU General Public License
  750. X--      along with this program;  if not, write to the Free Software
  751. X--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  752. X--
  753. X-- LOG
  754. X--     $Log:    quit.c,v $
  755. X * Revision 1.1  90/07/19  13:53:29  dvadura
  756. X * Initial Revision of Version 3.5
  757. X * 
  758. X*/
  759. X
  760. X#include "extern.h"
  761. X
  762. Xstatic    void    _handle_quit ANSI((char*));
  763. Xstatic    int    _dont_quit = 0;
  764. X
  765. X
  766. Xvoid
  767. XQuit()/*
  768. X======== Error or quit */
  769. X{
  770. X   if( _dont_quit ) return;
  771. X
  772. X   while( Closefile() != NIL( FILE ) );
  773. X   Clean_up_processes();
  774. X
  775. X   if( Current_target != NIL(HOW) )
  776. X      Unlink_temp_files(Current_target);
  777. X
  778. X   if( _dont_quit == 0 ) _handle_quit( ".ERROR" );
  779. X
  780. X   Set_dir( Makedir );        /* No Error message if we can't do it */
  781. X   Epilog( ERROR_EXIT_VALUE );
  782. X}
  783. X
  784. X
  785. Xstatic void
  786. X_handle_quit( err_target )/*
  787. X============================
  788. X   Called by quit and the others to handle the execution of termination code
  789. X   from within make */
  790. Xchar *err_target;
  791. X{
  792. X   HASHPTR hp;
  793. X   CELLPTR cp;
  794. X
  795. X   if( (hp = Get_name(err_target, Defs, FALSE, NIL(CELL))) != NIL(HASH) ) {
  796. X      cp = hp->CP_OWNR;
  797. X      Glob_attr |= A_IGNORE;
  798. X
  799. X      _dont_quit = 1;
  800. X      cp->ce_flag |= F_TARGET;
  801. X      Make( cp, cp->CE_HOW, NIL(CELL) );
  802. X   }
  803. X}
  804. SHAR_EOF
  805. chmod 0440 quit.c || echo "restore of quit.c fails"
  806. echo "x - extracting percent.c (Text)"
  807. sed 's/^X//' << 'SHAR_EOF' > percent.c &&
  808. X/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/percent.c,v 1.1 90/07/19 13:53:25 dvadura Exp $
  809. X-- SYNOPSIS -- handle building or %-rule meta-target nfa.
  810. X-- 
  811. X-- DESCRIPTION
  812. X--    Builds the NFA used by dmake to match targets against %-meta
  813. X--    rule constructs.  The NFA is built as a set of DFA's.
  814. X-- 
  815. X-- AUTHOR
  816. X--      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
  817. X--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
  818. X--
  819. X-- COPYRIGHT
  820. X--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
  821. X-- 
  822. X--      This program is free software; you can redistribute it and/or
  823. X--      modify it under the terms of the GNU General Public License
  824. X--      (version 1), as published by the Free Software Foundation, and
  825. X--      found in the file 'LICENSE' included with this distribution.
  826. X-- 
  827. X--      This program is distributed in the hope that it will be useful,
  828. X--      but WITHOUT ANY WARRANTY; without even the implied warrant of
  829. X--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  830. X--      GNU General Public License for more details.
  831. X-- 
  832. X--      You should have received a copy of the GNU General Public License
  833. X--      along with this program;  if not, write to the Free Software
  834. X--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  835. X--
  836. X-- LOG
  837. X--     $Log:    percent.c,v $
  838. X * Revision 1.1  90/07/19  13:53:25  dvadura
  839. X * Initial Revision of Version 3.5
  840. X * 
  841. X*/
  842. X
  843. X#include "extern.h"
  844. X#include "alloc.h"
  845. X#include "db.h"
  846. X
  847. X#define NO_ACTION    0
  848. X#define START_PERCENT    1
  849. X#define END_PERCENT    2
  850. X#define ACCEPT        4
  851. X#define EPSILON        8
  852. X#define FAIL        -1
  853. X
  854. Xstatic NFAPTR _nfa = NIL( NFA );
  855. X
  856. X
  857. XDFALINKPTR
  858. XMatch_dfa( buf )/*
  859. X==================
  860. X   This routines runs all DFA's in parrallel and selects the one that best
  861. X   matches the string.  If no match then it returns NIL( DFA ) */
  862. Xchar *buf;
  863. X{
  864. X   register NFAPTR nfa;
  865. X   int         adv;
  866. X   DFALINKPTR       dfa_list = NIL(DFALINK);
  867. X
  868. X   DB_ENTER( "Match_dfa" );
  869. X   DB_PRINT( "dfa", ("Matching %s", buf) );
  870. X
  871. X   /* Run each of the DFA's on the input string in parallel, we terminate
  872. X    * when all DFA's have either failed or ACCEPTED, if more than one DFA
  873. X    * accepts we build a list of all accepting DFA's sorted on states with
  874. X    * those matching in a higher numbered state heading the list. */
  875. X
  876. X   do {
  877. X      adv = FALSE;
  878. X
  879. X      for( nfa = _nfa; nfa != NIL( NFA ); nfa = nfa->next )
  880. X     if( nfa->status != (char) FAIL && nfa->status != (char) ACCEPT ) {
  881. X        adv++;
  882. X        nfa->status = Advance_dfa( nfa->dfa, buf );
  883. X
  884. X        /* Construct the list of matching DFA's */
  885. X        if( nfa->status == (char) ACCEPT ) {
  886. X           DFALINKPTR dl;
  887. X
  888. X           TALLOC( dl, 1, DFALINK );
  889. X           dl->dl_meta  = nfa->dfa->node;
  890. X           dl->dl_per   = _substr( nfa->dfa->pstart, nfa->dfa->pend );
  891. X           dl->dl_state = nfa->dfa->n_states;
  892. X
  893. X           if( dfa_list == NIL(DFALINK) )
  894. X              dfa_list = dl;
  895. X           else {
  896. X          DFALINKPTR tdli = dfa_list;
  897. X          DFALINKPTR tdlp = NIL(DFALINK);
  898. X
  899. X          for( ; tdli != NIL(DFALINK); tdli = tdli->dl_next ) {
  900. X             if( dl->dl_state >= tdli->dl_state )
  901. X            break;
  902. X             tdlp = tdli;
  903. X          }
  904. X
  905. X          if( tdli != NIL(DFALINK) ) {
  906. X             tdli->dl_prev = dl;
  907. X             dl->dl_next   = tdli;
  908. X          }
  909. X
  910. X          if( tdlp != NIL(DFALINK) ) {
  911. X             tdlp->dl_next = dl;
  912. X             dl->dl_prev   = tdlp;
  913. X          }
  914. X          else
  915. X             dfa_list = dl;
  916. X           }
  917. X
  918. X           DB_PRINT( "dfa", ("Matched [%s]", dl->dl_meta->CE_NAME) );
  919. X        }
  920. X     }
  921. X
  922. X      buf++;
  923. X   }
  924. X   while ( adv );
  925. X
  926. X   for( nfa = _nfa; nfa != NIL( NFA ); nfa = nfa->next )
  927. X      nfa->status = nfa->dfa->c_state = 0;
  928. X
  929. X   DB_RETURN( dfa_list );
  930. X}
  931. X
  932. X
  933. X
  934. Xvoid
  935. XAdd_dfa( buf )/*
  936. X================
  937. X   This function adds a DFA to the string of DFA's that form the NFA.
  938. X   The DFA is added at the head of the list because ordering is unimportant,
  939. X   when we do a match all DFA are run in parallel.  */
  940. Xchar *buf;
  941. X{
  942. X   NFAPTR nfa;
  943. X
  944. X   DB_ENTER( "Add_dfa" );
  945. X   DB_PRINT( "dfa", ("Adding dfa [%s]", buf) );
  946. X
  947. X   TALLOC( nfa, 1, NFA );
  948. X   nfa->dfa = Construct_dfa( buf );
  949. X
  950. X   if( _nfa != NIL(NFA) )
  951. X      nfa->next = _nfa;
  952. X
  953. X   _nfa = nfa;
  954. X
  955. X   DB_VOID_RETURN;
  956. X}
  957. X
  958. X
  959. X
  960. XDFAPTR
  961. XConstruct_dfa( pat )/*
  962. X======================
  963. X   This routine takes a string pattern which possibly contains a single %
  964. X   and returns a dfa which will recognize the string, treating the % as
  965. X   a token which accepts any char upto the next following char.  So for
  966. X   example:
  967. X    
  968. X        %.o  ==> accepts f.o  % = f, fred.o % = fred, fred.c FAILS
  969. X           f%.o  ==> accepts f.o  % =  , fred.o % = red,  fred.c FAILS
  970. X
  971. X   and so on.  The function constructs the DFA and returns a pointer to the
  972. X   DFA struct. */
  973. X
  974. Xchar *pat;
  975. X{
  976. X   register int     i;
  977. X   register DFAPTR     dfa;
  978. X   register STATEPTR    state;
  979. X   int            l = strlen( pat ) + 1;
  980. X   int            n;
  981. X   int            no_match = -1;
  982. X   int            pend = 0;
  983. X   char            *_strdup();
  984. X
  985. X   DB_ENTER( "Construct_dfa" );
  986. X   DB_PRINT( "dfa", ("Constructing dfa for %s", pat) );
  987. X
  988. X   n = l + 2;
  989. X
  990. X   TALLOC( dfa, 1, DFA );
  991. X   TALLOC( dfa->states, n, STATE );
  992. X
  993. X   dfa->n_states = n;
  994. X   dfa->node     = Def_cell( pat, NIL(CELL) );
  995. X
  996. X   for( i=0; i<l; i++, pat++ ) {
  997. X      state = dfa->states + i;
  998. X
  999. X      if( pend == 1 ) {
  1000. X         state->action |= END_PERCENT;
  1001. X     pend++;
  1002. X      }
  1003. X
  1004. X      switch( *pat ) {
  1005. X         case '%':                /* % start state    */
  1006. X        if( pend > 0 )
  1007. X           Error( "Only a single %% allowed in a target pattern" );
  1008. X        pend++;
  1009. X        state->symbol    = 0;
  1010. X        state->next      = i+1;
  1011. X        state->no_match  = no_match;
  1012. X        state->action   |= START_PERCENT | EPSILON;
  1013. X        no_match = i+1;
  1014. X        break;
  1015. X
  1016. X     case '\0':                 /* termination state    */
  1017. X        state->symbol    = *pat;
  1018. X        state->next      = -1;
  1019. X        state->no_match  = no_match;
  1020. X        state->action   |= ACCEPT;
  1021. X        break;
  1022. X        
  1023. X     default:                /* generate a new state    */
  1024. X        state->symbol   = *pat;
  1025. X        state->next     = i+1;
  1026. X        state->no_match = no_match;
  1027. X        break;
  1028. X      }
  1029. X   }
  1030. X
  1031. X   DB_RETURN( dfa );
  1032. X}
  1033. X
  1034. X
  1035. X
  1036. Xint
  1037. XAdvance_dfa( dfa, pch )/*
  1038. X=========================
  1039. X   This function takes the DFA that is provided and advances it to the next
  1040. X   states based on the value of *pch.  The function returns either 0 for
  1041. X   everything ok, -1 for fail, and ACCEPT if the dfa accepts the string. */
  1042. XDFAPTR dfa;
  1043. Xchar   *pch;
  1044. X{
  1045. X   STATEPTR s;
  1046. X   char     ch = *pch;
  1047. X   int      done = FALSE;
  1048. X   int      ret  = 0;
  1049. X
  1050. X   DB_ENTER( "Advance_dfa" );
  1051. X   DB_PRINT( "dfa", ("Advancing [%s] by %c", dfa->node->CE_NAME, *pch) );
  1052. X
  1053. X   while( !done ) {
  1054. X#ifdef DEBUG
  1055. X      if( dfa->c_state < 0 || dfa->c_state >= dfa->n_states )
  1056. X     Fatal( "Internal, bad current dfa state %d in [%s]",
  1057. X        dfa->c_state, dfa->node->CE_NAME );
  1058. X#endif
  1059. X
  1060. X      s = dfa->states + dfa->c_state;
  1061. X
  1062. X      if( ch == '\0' && s->symbol != '\0' ) {
  1063. X     done = TRUE;            /* FAIL string terminated first */
  1064. X     ret  = -1;
  1065. X      }
  1066. X      else if( s->action & EPSILON ) {    /* set the start of % string    */
  1067. X     if( s->action & START_PERCENT ) dfa->pstart = pch;
  1068. X     dfa->c_state = s->next;
  1069. X      }
  1070. X      else if( s->symbol == ch ) {    /* normal shift action        */
  1071. X     ret = s->action & ACCEPT;
  1072. X
  1073. X     if( s->action & END_PERCENT ) dfa->pend = pch;
  1074. X     dfa->c_state = s->next;
  1075. X     done = TRUE;
  1076. X      }
  1077. X      else {                /* non-match shift action    */
  1078. X     if( s->no_match == dfa->c_state || s->no_match == -1 ) {
  1079. X        done = TRUE;
  1080. X        if( s->no_match == -1 ) ret = -1;    /* FAIL */
  1081. X     }
  1082. X
  1083. X     dfa->c_state = s->no_match;
  1084. X      }
  1085. X   }
  1086. X
  1087. X   DB_RETURN( ret );
  1088. X}
  1089. X
  1090. X
  1091. Xvoid
  1092. XCheck_circle_dfa()/*
  1093. X====================
  1094. X   This function is called to test for circularities in the DFA lists
  1095. X   constructed from %-meta targets. */
  1096. X{
  1097. X   register NFAPTR nfa;
  1098. X
  1099. X   for( nfa = _nfa; nfa != NIL(NFA); nfa = nfa->next )
  1100. X      if( Test_circle( nfa->dfa->node, TRUE ) )
  1101. X     Fatal( "Detected circular dependency in inference graph at [%s]",
  1102. X        nfa->dfa->node->CE_NAME );
  1103. X}
  1104. SHAR_EOF
  1105. chmod 0440 percent.c || echo "restore of percent.c fails"
  1106. echo "x - extracting path.c (Text)"
  1107. sed 's/^X//' << 'SHAR_EOF' > path.c &&
  1108. X/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/path.c,v 1.1 90/07/19 13:53:25 dvadura Exp $
  1109. X-- SYNOPSIS -- pathname manipulation code
  1110. X-- 
  1111. X-- DESCRIPTION
  1112. X--    Pathname routines to handle building and pulling appart
  1113. X--    pathnames.
  1114. X-- 
  1115. X-- AUTHOR
  1116. X--      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
  1117. X--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
  1118. X--
  1119. X-- COPYRIGHT
  1120. X--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
  1121. X-- 
  1122. X--      This program is free software; you can redistribute it and/or
  1123. X--      modify it under the terms of the GNU General Public License
  1124. X--      (version 1), as published by the Free Software Foundation, and
  1125. X--      found in the file 'LICENSE' included with this distribution.
  1126. X-- 
  1127. X--      This program is distributed in the hope that it will be useful,
  1128. X--      but WITHOUT ANY WARRANTY; without even the implied warrant of
  1129. X--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1130. X--      GNU General Public License for more details.
  1131. X-- 
  1132. X--      You should have received a copy of the GNU General Public License
  1133. X--      along with this program;  if not, write to the Free Software
  1134. X--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  1135. X--
  1136. X-- LOG
  1137. X--     $Log:    path.c,v $
  1138. X * Revision 1.1  90/07/19  13:53:25  dvadura
  1139. X * Initial Revision of Version 3.5
  1140. X * 
  1141. X*/
  1142. X
  1143. X#include "extern.h"
  1144. X#include "alloc.h"
  1145. X#include <string.h>
  1146. X
  1147. X/*
  1148. X** Return the suffix portion of a filename, assumed to begin with a `.'.
  1149. X*/
  1150. Xchar *
  1151. XGet_suffix(name)
  1152. Xchar *name;
  1153. X{
  1154. X   char *suff;
  1155. X
  1156. X   if(name == NIL(char)  || (suff = strrchr(name, '.')) == NIL(char))
  1157. X      suff = ".NULL";
  1158. X
  1159. X   return (suff);
  1160. X}
  1161. X
  1162. X
  1163. X
  1164. X/*
  1165. X** Take dir and name, and return a path which has dir as the directory
  1166. X** and name afterwards.
  1167. X**
  1168. X** N.B. Assumes that the dir separator string is in DirSepStr.
  1169. X**      Return path is built in a static buffer, if you need to use it
  1170. X**      again you must _strdup the result returned by Build_path.
  1171. X*/
  1172. Xchar *
  1173. XBuild_path(dir, name)
  1174. Xchar *dir;
  1175. Xchar *name;
  1176. X{
  1177. X   static char     *path  = NIL(char);
  1178. X   static unsigned buflen = 0;
  1179. X   int  plen = 0;
  1180. X   int  dlen = 0;
  1181. X   int  len;
  1182. X
  1183. X   if( dir  != NIL(char) ) dlen = strlen( dir  );
  1184. X   if( name != NIL(char) ) plen = strlen( name );
  1185. X   len = plen+dlen+strlen(DirSepStr)+1;
  1186. X
  1187. X   if( len > buflen ) {
  1188. X      buflen = (len+16) & ~0xf;        /* buf is always multiple of 16 */
  1189. X
  1190. X      if( path == NIL(char) )
  1191. X         path = MALLOC( buflen, char );
  1192. X      else
  1193. X         path = realloc( path, (unsigned) (buflen*sizeof(char)) );
  1194. X   }
  1195. X   
  1196. X   *path = '\0';
  1197. X
  1198. X   if( dlen ) {
  1199. X      strcpy( path, dir );
  1200. X
  1201. X      if( strchr(DirSepStr, dir[dlen-1]) == NIL(char) )
  1202. X     strcat( path, DirSepStr );
  1203. X   }
  1204. X
  1205. X   strcat( path, name );
  1206. X   return( path );
  1207. X}
  1208. SHAR_EOF
  1209. chmod 0440 path.c || echo "restore of path.c fails"
  1210. echo "x - extracting patchlvl.h (Text)"
  1211. sed 's/^X//' << 'SHAR_EOF' > patchlvl.h &&
  1212. X/* dmake patch level, reset to 1 for each new version release. */
  1213. X
  1214. X#define PATCHLEVEL 1
  1215. SHAR_EOF
  1216. chmod 0440 patchlvl.h || echo "restore of patchlvl.h fails"
  1217. echo "x - extracting parse.c (Text)"
  1218. sed 's/^X//' << 'SHAR_EOF' > parse.c &&
  1219. X/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/parse.c,v 1.1 90/07/19 13:53:23 dvadura Exp $
  1220. X-- SYNOPSIS -- parse the input, and perform semantic analysis
  1221. X-- 
  1222. X-- DESCRIPTION
  1223. X--     This file contains the routines that parse the input makefile and
  1224. X--    call the appropriate routines to perform the semantic analysis and
  1225. X--    build the internal dag.
  1226. X--
  1227. X-- AUTHOR
  1228. X--      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
  1229. X--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
  1230. X--
  1231. X-- COPYRIGHT
  1232. X--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
  1233. X-- 
  1234. X--      This program is free software; you can redistribute it and/or
  1235. X--      modify it under the terms of the GNU General Public License
  1236. X--      (version 1), as published by the Free Software Foundation, and
  1237. X--      found in the file 'LICENSE' included with this distribution.
  1238. X-- 
  1239. X--      This program is distributed in the hope that it will be useful,
  1240. X--      but WITHOUT ANY WARRANTY; without even the implied warrant of
  1241. X--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1242. X--      GNU General Public License for more details.
  1243. X-- 
  1244. X--      You should have received a copy of the GNU General Public License
  1245. X--      along with this program;  if not, write to the Free Software
  1246. X--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  1247. X--
  1248. X-- LOG
  1249. X--     $Log:    parse.c,v $
  1250. X * Revision 1.1  90/07/19  13:53:23  dvadura
  1251. X * Initial Revision of Version 3.5
  1252. X * 
  1253. X*/
  1254. X
  1255. X#include <ctype.h>
  1256. X#include "extern.h"
  1257. X#include "alloc.h"
  1258. X#include "db.h"
  1259. X
  1260. X
  1261. Xvoid
  1262. XParse( fil )/*
  1263. X==============  Parse the makefile input */
  1264. XFILE *fil;
  1265. X{
  1266. X   int    state = NORMAL_SCAN;           /* indicates current parser state */
  1267. X   int  group = FALSE;                 /* true if scanning a group rcpe  */
  1268. X   int  rule  = FALSE;                 /* have seen a recipe line        */
  1269. X   char *p;                   /* termporary pointer into Buffer */
  1270. X
  1271. X   DB_ENTER( "Parse" );
  1272. X
  1273. X   while( TRUE ) {
  1274. X      if( Get_line( Buffer, fil ) ) {
  1275. X     if( fil != NIL( FILE ) )               /* end of parsable input */
  1276. X        Closefile();
  1277. X
  1278. X     Bind_rules_to_targets( F_DEFAULT );
  1279. X         if( group )  Fatal( "Incomplete rule recipe group detected" );
  1280. X
  1281. X     DB_VOID_RETURN;
  1282. X      }
  1283. X      else
  1284. X         switch( state ) {
  1285. X        case RULE_SCAN:
  1286. X
  1287. X           /* Check for the `[' that starts off a group rule definition.  It
  1288. X            * must appear as the first non-white space
  1289. X        * character in the line. */
  1290. X
  1291. X           p = _strspn( Buffer, " \t" );
  1292. X               if( Set_group_attributes( p ) ) {
  1293. X                  if( rule  && group )
  1294. X                     Fatal( "Cannot mix single and group recipe lines" );
  1295. X                  else
  1296. X                     group = TRUE;
  1297. X
  1298. X                  rule = TRUE;
  1299. X
  1300. X                  break;                     /* ignore the group start  */
  1301. X               }
  1302. X
  1303. X               if( group ) {
  1304. X                  if( *p != ']' ) {
  1305. X                     Add_recipe_to_list( Buffer, TRUE, TRUE );
  1306. X                     rule = TRUE;
  1307. X                  }
  1308. X                  else
  1309. X                     state = NORMAL_SCAN;
  1310. X               }
  1311. X               else {
  1312. X                  if( *Buffer == '\t' ) {
  1313. X                     Add_recipe_to_list( Buffer, FALSE, FALSE );
  1314. X                     rule = TRUE;
  1315. X                  }
  1316. X                  else if( *p == ']' )
  1317. X                     Fatal( "Found unmatched ']'" );
  1318. X                  else if( *Buffer )
  1319. X             state = NORMAL_SCAN;
  1320. X               }
  1321. X               if( state == RULE_SCAN ) break;     /* ie. keep going    */
  1322. X               
  1323. X           Bind_rules_to_targets( (group) ? F_GROUP: F_DEFAULT );
  1324. X
  1325. X               rule = FALSE;
  1326. X               if( group ) {
  1327. X                  group = FALSE;
  1328. X                  break;
  1329. X               }
  1330. X           /*FALLTRHOUGH*/
  1331. X
  1332. X               /* In this case we broke out of the rule scan because we do not
  1333. X                * have a recipe line that begins with a <TAB>, so lets
  1334. X        * try to scan the thing as a macro or rule definition. */
  1335. X               
  1336. X
  1337. X        case NORMAL_SCAN:
  1338. X           if( !*Buffer ) continue;         /* we have null input line */
  1339. X
  1340. X           /* STUPID AUGMAKE uses "include" at the start of a line as
  1341. X            * a signal to include a new file, so let's look for it.
  1342. X        * if we see it replace it by .INCLUDE: and stick this back
  1343. X        * into the buffer. */
  1344. X           if( !strncmp( "include", Buffer, 7 ) &&
  1345. X           (Buffer[7] == ' ' || Buffer[7] == '\t') )
  1346. X           {
  1347. X          char *tmp;
  1348. X
  1349. X          tmp = _strjoin( ".INCLUDE:", Buffer+7, -1, FALSE );
  1350. X          strcpy( Buffer, tmp );
  1351. X          FREE( tmp );
  1352. X           }
  1353. X
  1354. X               /* look for a macro definition, they all contain an = sign
  1355. X            * if we fail to recognize it as a legal macro op then try to
  1356. X        * parse the same line as a rule definition, it's one or the
  1357. X        * other */
  1358. X        
  1359. X           if( Parse_macro(Buffer, M_DEFAULT) ) break;/* it's a macro def */
  1360. X           if( Parse_rule_def( &state ) )         break;/* it's a rule def  */
  1361. X
  1362. X           /* if just blank line then ignore it */
  1363. SHAR_EOF
  1364. echo "End of part 5"
  1365. echo "File parse.c is continued in part 6"
  1366. echo "6" > s2_seq_.tmp
  1367. exit 0
  1368.  
  1369.