home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume27 / dmake / part08 < prev    next >
Encoding:
Text File  |  1992-01-29  |  39.9 KB  |  1,482 lines

  1. Newsgroups: comp.sources.misc
  2. From: dvadura@plg.waterloo.edu (Dennis Vadura)
  3. Subject:  v27i109:  dmake - dmake Version 3.8, Part08/41
  4. Message-ID: <1992Jan28.031422.7223@sparky.imd.sterling.com>
  5. X-Md4-Signature: 2a00c738fc4bef1e39ec5c5d81319c5c
  6. Date: Tue, 28 Jan 1992 03:14:22 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: dvadura@plg.waterloo.edu (Dennis Vadura)
  10. Posting-number: Volume 27, Issue 109
  11. Archive-name: dmake/part08
  12. Environment: Atari-ST, Coherent, Mac, MSDOS, OS/2, UNIX
  13. Supersedes: dmake: Volume 19, Issue 22-58
  14.  
  15. ---- Cut Here and feed the following to sh ----
  16. # this is dmake.shar.08 (part 8 of a multipart archive)
  17. # do not concatenate these parts, unpack them in order with /bin/sh
  18. # file dmake/dmdump.c continued
  19. #
  20. if test ! -r _shar_seq_.tmp; then
  21.     echo 'Please unpack part 1 first!'
  22.     exit 1
  23. fi
  24. (read Scheck
  25.  if test "$Scheck" != 8; then
  26.     echo Please unpack part "$Scheck" next!
  27.     exit 1
  28.  else
  29.     exit 0
  30.  fi
  31. ) < _shar_seq_.tmp || exit 1
  32. if test -f _shar_wnt_.tmp; then
  33. sed 's/^X//' << 'SHAR_EOF' >> 'dmake/dmdump.c' &&
  34. -- SYNOPSIS -- dump the internal dag to stdout.
  35. -- 
  36. -- DESCRIPTION
  37. --    This file contains the routine that is called to dump a version of
  38. --    the digested makefile to the standard output.  May be useful perhaps
  39. --    to the ordinary user, and invaluable for debugging make.
  40. -- 
  41. -- AUTHOR
  42. --      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
  43. --      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
  44. --
  45. -- COPYRIGHT
  46. --      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
  47. -- 
  48. --      This program is free software; you can redistribute it and/or
  49. --      modify it under the terms of the GNU General Public License
  50. --      (version 1), as published by the Free Software Foundation, and
  51. --      found in the file 'LICENSE' included with this distribution.
  52. -- 
  53. --      This program is distributed in the hope that it will be useful,
  54. --      but WITHOUT ANY WARRANTY; without even the implied warrant of
  55. --      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  56. --      GNU General Public License for more details.
  57. -- 
  58. --      You should have received a copy of the GNU General Public License
  59. --      along with this program;  if not, write to the Free Software
  60. --      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  61. --
  62. -- LOG
  63. --     $Log: dmdump.c,v $
  64. X * Revision 1.1  1992/01/24  03:28:51  dvadura
  65. X * dmake Version 3.8, Initial revision
  66. X *
  67. */
  68. X
  69. #include "extern.h"
  70. X
  71. #define M_TEST    (M_PRECIOUS | M_VAR_MASK)
  72. X
  73. static    void    dump_name ANSI((HASHPTR, int));
  74. static    void    dump_normal_target ANSI((CELLPTR, int));
  75. static  void    dump_prerequisites ANSI((LINKPTR, int, int, int));
  76. X
  77. X
  78. PUBLIC void
  79. Dump()/*
  80. ========  Dump onto standard output the digested makefile.  Note that
  81. X      the form of the dump is not representative of the contents
  82. X      of the original makefile contents at all */
  83. {
  84. X   HASHPTR      hp;
  85. X   int          i;
  86. X
  87. X   DB_ENTER( "Dump" );
  88. X
  89. X   puts( "# Dump of dmake macro variables:" );
  90. X   for( i=0; i<HASH_TABLE_SIZE; i++)
  91. X      for( hp=Macs[i]; hp != NIL(HASH); hp = hp->ht_next ) {
  92. X     int flag = hp->ht_flag;
  93. X
  94. X     printf( "%s ", hp->ht_name );
  95. X     if( flag & M_EXPANDED ) putchar( ':' );
  96. X     printf( "= " );
  97. X     if( hp->ht_value != NIL(char) ) printf( "%s",hp->ht_value );
  98. X     if( flag & M_PRECIOUS )
  99. X        printf( "\t # PRECIOUS " );
  100. X     putchar( '\n' );
  101. X      }
  102. X
  103. X   puts( "\n#====================================" );
  104. X   puts( "# Dump of targets:\n" );
  105. X
  106. X   for( i=0; i<HASH_TABLE_SIZE; i++ )
  107. X      for( hp = Defs[i]; hp != NIL(HASH); hp = hp->ht_next )
  108. X         if( !(hp->CP_OWNR->ce_flag & F_PERCENT) ) {
  109. X        if( Root->ce_prq && hp->CP_OWNR == Root->ce_prq->cl_prq )
  110. X           puts( "# ******* FIRST TARGET ********" );
  111. X        dump_normal_target( hp->CP_OWNR, hp->CP_OWNR->ce_flag );
  112. X     }
  113. X
  114. X   puts( "\n#====================================" );
  115. X   puts( "# Dump of inference graph\n" );
  116. X
  117. X   for( i=0; i<HASH_TABLE_SIZE; i++ )
  118. X      for( hp = Defs[i]; hp != NIL(HASH); hp = hp->ht_next )
  119. X         if( (hp->CP_OWNR->ce_flag & F_PERCENT) &&
  120. X        !(hp->CP_OWNR->ce_flag & F_MAGIC) )
  121. X        dump_normal_target( hp->CP_OWNR, hp->CP_OWNR->ce_flag );
  122. X
  123. X   DB_VOID_RETURN;
  124. }
  125. X
  126. X
  127. X
  128. PUBLIC void
  129. Dump_recipe( sp )/*
  130. ===================
  131. X   Given a string pointer print the recipe line out */
  132. STRINGPTR sp;
  133. {
  134. X   char *st;
  135. X   char *nl;
  136. X
  137. X   if( sp == NIL(STRING) ) return;
  138. X
  139. X   putchar( '\t' );
  140. X   if( sp->st_attr & A_SILENT ) putchar( '@' );
  141. X   if( sp->st_attr & A_IGNORE ) putchar( '-' );
  142. X   if( sp->st_attr & A_SHELL  ) putchar( '+' );
  143. X   if( sp->st_attr & A_SWAP   ) putchar( '%' );
  144. X
  145. X   st = sp->st_string;
  146. X   for( nl=strchr(st,'\n'); nl != NIL( char); nl=strchr(st,'\n') ) {
  147. X      *nl = '\0';
  148. X      printf( "%s\\\n", st );
  149. X      *nl = '\n';
  150. X      st  = nl+1;
  151. X   }
  152. X   printf( "%s\n", st );
  153. }
  154. X
  155. X
  156. static char *_attrs[] = { ".PRECIOUS", ".SILENT", ".LIBRARY",
  157. X   ".EPILOG", ".PROLOG", ".IGNORE", ".SYMBOL", ".NOINFER",
  158. X   ".UPDATEALL", ".SEQUENTIAL", ".SETDIR=", ".USESHELL", ".SWAP", ".MKSARGS",
  159. X   ".PHONY", ".NOSTATE" };
  160. X
  161. static void
  162. dump_normal_target( cp, flag )/*
  163. ================================
  164. X    Dump in makefile like format the dag information */
  165. CELLPTR cp;
  166. int     flag;
  167. {
  168. X   register LINKPTR   lp;
  169. X   register STRINGPTR sp;
  170. X   t_attr          attr;
  171. X   unsigned int          k;
  172. X
  173. X   DB_ENTER( "dump_normal_target" );
  174. X
  175. X   if( !(cp->ce_flag & F_TARGET) && !cp->ce_attr ) { DB_VOID_RETURN; }
  176. X
  177. X   if( cp->ce_flag & F_MULTI ) {
  178. X      int tflag = cp->ce_prq->cl_prq->ce_flag;
  179. X      if( !(cp->ce_flag & F_PERCENT) ) tflag |= F_MULTI;
  180. X      dump_prerequisites(cp->ce_prq, FALSE, TRUE, tflag);
  181. X   }
  182. X   else {
  183. X      dump_name( cp->ce_name, FALSE );
  184. X
  185. X      for( k=0, attr=1; attr <= MAX_ATTR; attr <<= 1, k++ )
  186. X     if( cp->ce_attr & attr ) {
  187. X        printf( "%s%s ", _attrs[k],
  188. X            (attr != A_SETDIR) ? "" : (cp->ce_dir?cp->ce_dir:"") );
  189. X     }
  190. X        
  191. X      putchar( ':' );
  192. X
  193. X      if( flag & F_MULTI )  putchar( ':' );
  194. X      if( flag & F_SINGLE ) putchar( '!' );
  195. X      putchar( ' ' );
  196. X
  197. X      dump_prerequisites( cp->ce_prq, FALSE, FALSE, F_DEFAULT);
  198. X      dump_prerequisites( cp->ce_indprq, TRUE, FALSE, F_DEFAULT);
  199. X
  200. X      putchar( '\n' );
  201. X      if( cp->ce_flag & F_GROUP ) puts( "[" );
  202. X      for( sp = cp->ce_recipe; sp != NIL(STRING); sp = sp->st_next )
  203. X     Dump_recipe( sp );
  204. X      if( cp->ce_flag & F_GROUP ) puts( "]" );
  205. X
  206. X      putchar( '\n' );
  207. X   }
  208. X
  209. X   DB_VOID_RETURN;
  210. }
  211. X
  212. X
  213. static void
  214. dump_prerequisites( lp, quote, recurse, flag )
  215. LINKPTR lp;
  216. int     quote;
  217. int     recurse;
  218. int     flag;
  219. {
  220. X   for( ; lp; lp=lp->cl_next )
  221. X      if( recurse )
  222. X     dump_normal_target(lp->cl_prq, flag);
  223. X      else if( lp->cl_prq )
  224. X     dump_name(lp->cl_prq->ce_name, quote);
  225. }
  226. X
  227. X
  228. static void
  229. dump_name( hp, quote )/*
  230. ========================
  231. X    print out a name */
  232. HASHPTR hp;
  233. int     quote;
  234. {
  235. X   if( quote ) putchar('\'');
  236. X   printf( "%s", hp->ht_name );
  237. X   if( quote ) putchar('\'');
  238. X   putchar(' ');
  239. }
  240. SHAR_EOF
  241. chmod 0640 dmake/dmdump.c ||
  242. echo 'restore of dmake/dmdump.c failed'
  243. Wc_c="`wc -c < 'dmake/dmdump.c'`"
  244. test 5875 -eq "$Wc_c" ||
  245.     echo 'dmake/dmdump.c: original size 5875, current size' "$Wc_c"
  246. rm -f _shar_wnt_.tmp
  247. fi
  248. # ============= dmake/dmstring.c ==============
  249. if test -f 'dmake/dmstring.c' -a X"$1" != X"-c"; then
  250.     echo 'x - skipping dmake/dmstring.c (File already exists)'
  251.     rm -f _shar_wnt_.tmp
  252. else
  253. > _shar_wnt_.tmp
  254. sed 's/^X//' << 'SHAR_EOF' > 'dmake/dmstring.c' &&
  255. /* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/dmstring.c,v 1.1 1992/01/24 03:29:38 dvadura Exp $
  256. -- SYNOPSIS -- string handling code
  257. -- 
  258. -- DESCRIPTION
  259. --    Routines to handle string manipulation.  This code is not specific
  260. --    to dmake and has/and will be used in other programs.  The string
  261. --    "" is considered the NULL string, if NIL(char) is received instead
  262. --    undefined results may occurr.  (In reality NIL(char) is checked for
  263. --    but in general it is not safe to assume NIL(char) ==  NULL)
  264. -- 
  265. -- AUTHOR
  266. --      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
  267. --      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
  268. --
  269. -- COPYRIGHT
  270. --      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
  271. -- 
  272. --      This program is free software; you can redistribute it and/or
  273. --      modify it under the terms of the GNU General Public License
  274. --      (version 1), as published by the Free Software Foundation, and
  275. --      found in the file 'LICENSE' included with this distribution.
  276. -- 
  277. --      This program is distributed in the hope that it will be useful,
  278. --      but WITHOUT ANY WARRANTY; without even the implied warrant of
  279. --      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  280. --      GNU General Public License for more details.
  281. -- 
  282. --      You should have received a copy of the GNU General Public License
  283. --      along with this program;  if not, write to the Free Software
  284. --      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  285. --
  286. -- LOG
  287. --     $Log: dmstring.c,v $
  288. X * Revision 1.1  1992/01/24  03:29:38  dvadura
  289. X * dmake Version 3.8, Initial revision
  290. X *
  291. */
  292. X
  293. #include "extern.h"
  294. X
  295. PUBLIC char *
  296. _strjoin( src, data, n, fr )/*
  297. ==============================
  298. X   Join data to src according to value of n.
  299. X
  300. X      n = -1   - return strcat( src, data )
  301. X      n >= 0   - return strncat( src, data, n )
  302. X
  303. X   FREE original src if fr == TRUE, else leave it alone */
  304. X
  305. char *src;
  306. char *data;
  307. int  n;
  308. int  fr;
  309. {
  310. X   char *t;
  311. X   int  l;
  312. X   int  flag = FALSE;
  313. X
  314. X   DB_ENTER( "_strjoin" );
  315. X   
  316. X   if( src  == NIL(char) ) { src = ""; flag = TRUE; }
  317. X   if( data == NIL(char) ) data = "";
  318. X   DB_PRINT( "str", ("Joining [%s] [%s] %d", src, data, n) );
  319. X
  320. X   if( n == -1 )  n = strlen( data );
  321. X
  322. X   l = strlen( src ) + n + 1;
  323. X   if( (t = MALLOC( l, char )) == NIL(char) ) No_ram();
  324. X
  325. X   strcpy( t, src );
  326. X   if (n) strncat( t, data, n );
  327. X   t[ l-1 ] = '\0';
  328. X
  329. X   if( !flag && fr ) FREE( src );
  330. X
  331. X   DB_PRINT( "str", ("Result  [%s]", t) );
  332. X   DB_RETURN( t );
  333. }
  334. X
  335. X
  336. X
  337. X
  338. PUBLIC char *
  339. _stradd( src, data, fr )/*
  340. ==========================
  341. X   append data to src with space in between if src is not NIL(char) or ""
  342. X   and free both src and data if fr == TRUE, otherwise leave them be */
  343. X
  344. char *src;
  345. char *data;
  346. int  fr;
  347. {
  348. X   char *t;
  349. X   int  l;
  350. X   int  sflag;
  351. X   int  dflag;
  352. X
  353. X   DB_ENTER( "_stradd" );
  354. X
  355. X   sflag = dflag = fr;
  356. X
  357. X   if( src  == NIL(char) ) { src  = ""; sflag = FALSE; }
  358. X   if( data == NIL(char) ) { data = ""; dflag = FALSE; }
  359. X   DB_PRINT( "str", ("Adding [%s] [%s] %d", src, data, fr) );
  360. X
  361. X   l = strlen(src) + strlen(data) + 1;
  362. X   if( *src ) l++;
  363. X
  364. X   if( (t = MALLOC( l, char )) == NIL(char) ) No_ram();
  365. X
  366. X   strcpy( t, src );
  367. X   
  368. X   if( *data )
  369. X   {
  370. X      if( *src ) strcat( t,  " " );
  371. X      strcat( t, data );
  372. X   }
  373. X
  374. X   if( sflag )  FREE( src  );
  375. X   if( dflag )  FREE( data );
  376. X
  377. X   DB_PRINT( "str", ("Result  [%s]", t) );
  378. X   DB_RETURN( t );
  379. }
  380. X
  381. X
  382. X
  383. PUBLIC char *
  384. _strapp( src1, src2 )/*
  385. =======================
  386. X   Append two strings together, and return the result with a space between
  387. X   the two strings.  FREE the first string if it is not NIL and always
  388. X   leave the second string be. */
  389. char *src1;
  390. char *src2;
  391. {
  392. X   src2 = _stradd( src1, src2, FALSE );
  393. X   if( src1 != NIL(char) ) FREE( src1 );
  394. X   return( src2 );
  395. }
  396. X
  397. X
  398. X
  399. #ifdef DBUG
  400. #ifdef _strdup
  401. #undef _strdup
  402. #endif
  403. #endif
  404. PUBLIC char *
  405. _strdup( str )/*
  406. ================  Duplicate the contents of a string, by using malloc */
  407. char *str;
  408. {
  409. X   char *t;
  410. X
  411. X   if( str == NIL(char) ) return( NIL(char) );
  412. X   
  413. X   if( (t = MALLOC( strlen( str )+1, char )) == NIL(char) ) No_ram();
  414. X   strcpy( t, str );
  415. X
  416. X   return( t );
  417. }
  418. X
  419. X
  420. X
  421. PUBLIC char *
  422. _strdup2( str )/*
  423. =================
  424. X   This function is used solely to properly quote command line arguments when
  425. X   they are reinserted int MAKEMACROS so that they can be used further in
  426. X   a processing line. */
  427. char *str;
  428. {
  429. X   char *t;
  430. X   size_t size;
  431. X   size_t alloced;
  432. X   char *tmp;
  433. X   char *dest;
  434. X   int seen_equal = 0;
  435. X
  436. X   if(str == NIL(char)) return(NIL(char));
  437. X   size = strlen(str) + 1;
  438. X   alloced = size + 2;        /* for two quotes */
  439. X
  440. X   for(tmp = str; *tmp; tmp++)
  441. X      if(*tmp == '"')
  442. X         alloced++;
  443. X
  444. X   if((t = MALLOC(alloced, char)) == NIL(char)) No_ram();
  445. X
  446. X   for(tmp = str, dest = t; *tmp; tmp++, dest++) {
  447. X      if(*tmp == '=' && !seen_equal) {
  448. X     seen_equal = 1;
  449. X     *dest++ = *tmp;
  450. X     *dest = '"';
  451. X     continue;
  452. X      }
  453. X      if(*tmp == '"')
  454. X     *dest++ = '\\';
  455. X      *dest = *tmp;
  456. X   }
  457. X
  458. X   if(!seen_equal)
  459. X      Fatal("_strdup2 invoked without argument of form x=y\n");
  460. X
  461. X   *dest++ = '"';
  462. X   *dest = 0;
  463. X
  464. X   return t;
  465. }
  466. X
  467. X
  468. X
  469. PUBLIC char *
  470. _strpbrk( s1, s2 )/*
  471. ====================
  472. X   find first occurence of char in s2 in string s1.
  473. X   Returns a pointer to the first occurrence.  NOTE '\0' is considered part
  474. X   of s2 and a pointer to it is returned if no other chars match. */
  475. X
  476. char *s1;
  477. char *s2;
  478. {
  479. X   register char *t;
  480. X
  481. X   if( s1 == NIL(char) || s2 == NIL(char) ) return( "" );
  482. X
  483. X   for( t=s1; *t && (strchr( s2, *t ) == NIL(char)); t++ );
  484. X   return( t );
  485. }
  486. X
  487. X
  488. X
  489. X
  490. PUBLIC char *
  491. _strspn( s1, s2 )/*
  492. ===================
  493. X   return pointer to first char in s1 that does not belong to s2.
  494. X   Returns the pointer if match found, else returns pointer to null char
  495. X   in s1. (ie. "" ) */
  496. X   
  497. char *s1;
  498. char *s2;
  499. {
  500. X   register char *t;
  501. X
  502. X   if( s1 == NIL(char) || s2 == NIL(char) ) return( "" );
  503. X
  504. X   for( t=s1; *t && (strchr( s2, *t ) != NIL(char)); t++ );
  505. X   return( t );
  506. }
  507. X
  508. X
  509. X
  510. X
  511. PUBLIC char *
  512. _strstr( s1, s2 )/*
  513. ==================  find first occurrence in s1 of s2 */
  514. char *s1;
  515. char *s2;
  516. {
  517. X   register char *s;
  518. X   register char *p;
  519. X   register char *r;
  520. X
  521. X   if( s1 != NIL(char) && s2 != NIL(char) )
  522. X      for( s=s1; *s; s++ )
  523. X     if( *s == *s2 )
  524. X     {
  525. X        for( r=s+1, p = s2+1; *p && (*r == *p); r++, p++ );
  526. X        if( !*p ) return( s );
  527. X     }
  528. X   
  529. X   return( NIL(char) );
  530. }
  531. X
  532. X
  533. X
  534. PUBLIC char *
  535. _substr( s, e )/*
  536. =================
  537. X      Return the string between the two pointers s and e, not including the
  538. X      char that e points to.  NOTE:  This routine assumes that s and e point
  539. X      into the same string. */
  540. X
  541. char *s;
  542. char *e;
  543. {
  544. X   char save;
  545. X   int  len = e-s;
  546. X
  547. X   if( len < 0 || len > strlen(s) )
  548. X      Fatal( "Internal Error:  _substr fails consistency test" );
  549. X
  550. X   save = *e;
  551. X   *e   = '\0';
  552. X   s    = _strdup( s );
  553. X   *e   = save;
  554. X
  555. X   return( s );
  556. }
  557. SHAR_EOF
  558. chmod 0640 dmake/dmstring.c ||
  559. echo 'restore of dmake/dmstring.c failed'
  560. Wc_c="`wc -c < 'dmake/dmstring.c'`"
  561. test 6772 -eq "$Wc_c" ||
  562.     echo 'dmake/dmstring.c: original size 6772, current size' "$Wc_c"
  563. rm -f _shar_wnt_.tmp
  564. fi
  565. # ============= dmake/expand.c ==============
  566. if test -f 'dmake/expand.c' -a X"$1" != X"-c"; then
  567.     echo 'x - skipping dmake/expand.c (File already exists)'
  568.     rm -f _shar_wnt_.tmp
  569. else
  570. > _shar_wnt_.tmp
  571. sed 's/^X//' << 'SHAR_EOF' > 'dmake/expand.c' &&
  572. /* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/expand.c,v 1.1 1992/01/24 03:27:03 dvadura Exp $
  573. -- SYNOPSIS -- macro expansion code.
  574. -- 
  575. -- DESCRIPTION
  576. --
  577. --    This routine handles all the necessary junk that deals with macro
  578. --    expansion.  It understands the following syntax.  If a macro is
  579. --    not defined it expands to NULL, and {} are synonyms for ().
  580. --
  581. --        $$      - expands to $
  582. --        {{      - expands to {
  583. --            }}      - expands to }
  584. --        $A      - expands to whatever the macro A is defined as
  585. --        $(AA)   - expands to whatever the macro AA is defined as
  586. --        $($(A)) - represents macro indirection
  587. --        <+...+> - get mapped to $(mktmp ...)
  588. --    
  589. --        following macro is recognized
  590. --        
  591. --                string1{ token_list }string2
  592. --                
  593. --        and expands to string1 prepended to each element of token_list and
  594. --        string2 appended to each of the resulting tokens from the first
  595. --        operation.  If string2 is of the form above then the result is
  596. --        the cross product of the specified (possibly modified) token_lists.
  597. --        
  598. --        The folowing macro modifiers are defined and expanded:
  599. --        
  600. --               $(macro:modifier_list:modifier_list:...)
  601. --               
  602. --        where modifier_list a combination of:
  603. --        
  604. --               D or d      - Directory portion of token including separator
  605. --               F or f      - File portion of token including suffix
  606. --               B or b      - basename portion of token not including suffix
  607. --         T or t      - for tokenization
  608. --
  609. --      or a single
  610. --               S or s      - pattern substitution (simple)
  611. --               
  612. --        NOTE:  Modifiers are applied once the macro value has been found.
  613. --               Thus the construct $($(test):s/joe/mary/) is defined and
  614. --               modifies the value of $($(test))
  615. --
  616. --           Also the construct $(m:d:f) is not the same as $(m:df)
  617. --           the first applies d to the value of $(m) and then
  618. --           applies f to the value of that whereas the second form
  619. --           applies df to the value of $(m).
  620. --
  621. -- AUTHOR
  622. --      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
  623. --      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
  624. --
  625. -- COPYRIGHT
  626. --      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
  627. -- 
  628. --      This program is free software; you can redistribute it and/or
  629. --      modify it under the terms of the GNU General Public License
  630. --      (version 1), as published by the Free Software Foundation, and
  631. --      found in the file 'LICENSE' included with this distribution.
  632. -- 
  633. --      This program is distributed in the hope that it will be useful,
  634. --      but WITHOUT ANY WARRANTY; without even the implied warrant of
  635. --      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  636. --      GNU General Public License for more details.
  637. -- 
  638. --      You should have received a copy of the GNU General Public License
  639. --      along with this program;  if not, write to the Free Software
  640. --      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  641. --
  642. -- LOG
  643. --     $Log: expand.c,v $
  644. X * Revision 1.1  1992/01/24  03:27:03  dvadura
  645. X * dmake Version 3.8, Initial revision
  646. X *
  647. */
  648. X
  649. #include "extern.h"
  650. X
  651. /* Microsoft BRAINDAMAGE ALERT!!!!
  652. X * This #ifdef is here only to satisfy stupid bugs in MSC5.0 and MSC5.1
  653. X * it isn't needed for anything else.  It turns loop optimization off. */
  654. #if defined(_MSC_VER)
  655. #include "optoff.h"
  656. #endif
  657. X
  658. static    char*    _scan_token ANSI((char*, char**));
  659. static    char*    _scan_macro ANSI((char*, char**));
  660. static    char*    _scan_brace ANSI((char*, char**, int*));
  661. static    char*    _cross_prod ANSI((char*, char*));
  662. X
  663. X
  664. PUBLIC char *
  665. Expand( src )/*
  666. ===============
  667. X      This is the driver routine for the expansion, it identifies non-white
  668. X      space tokens and gets the _scan_token routine to figure out if they should
  669. X      be treated in a special way. */
  670. X
  671. char *src;                    /* pointer to source string  */
  672. {
  673. X   char  *tmp;              /* pointer to temporary str  */
  674. X   char  *res;                /* pointer to result string  */
  675. X   char  *start;              /* pointer to start of token */
  676. X   
  677. X   DB_ENTER( "Expand" );
  678. X   DB_PRINT( "exp", ("Expanding [%s]", src) );
  679. X
  680. X   res = _strdup( "" );
  681. X   if( src == NIL(char) ) DB_RETURN( res );
  682. X
  683. X   while( *src ) {
  684. X      char *ks, *ke;
  685. X
  686. X      /* Here we find the next non white space token in the string
  687. X       * and find it's end, with respect to non-significant white space. */
  688. X      
  689. X      start = _strspn( src, " \t\n" );
  690. X      res   = _strjoin( res, src, start-src, TRUE );
  691. X      if( !(*start) ) break;
  692. X
  693. X      /* START <+...+> KLUDGE */
  694. X      if( (ks=_strstr(start,"<+")) && (ke=_strstr(ks,"+>")) ){
  695. X     char *t1, *t2;
  696. X
  697. X     res = _strjoin( res, t2=Expand(t1=_substr(start,ks)), -1, TRUE);
  698. X     FREE(t1); FREE(t2);
  699. X
  700. X     t1 = _substr(ks+2, ke+1); t1[ke-ks-2] = ')';
  701. X     t2 = _strjoin( "$(mktmp ", t1, -1,FALSE);
  702. X     FREE(t1);
  703. X     res = _strjoin( res, t2=Expand(t2), -1, TRUE);
  704. X     FREE(t2);
  705. X     src = ke+2;
  706. X      }
  707. X      /* END <+...+> KLUDGE */
  708. X      else {
  709. X     res   = _strjoin( res, tmp = _scan_token( start, &src ), -1, TRUE );
  710. X     FREE( tmp );
  711. X      }
  712. X   }
  713. X   
  714. X   DB_PRINT( "exp", ("Returning [%s]", res) );
  715. X   DB_RETURN( res );
  716. }
  717. X
  718. X
  719. PUBLIC char *
  720. Apply_edit( src, pat, subst, fr, anchor )/*
  721. ===========================================
  722. X   Take the src string and apply the pattern substitution.  ie. look for
  723. X   occurrences of pat in src and replace each occurrence with subst.  This is
  724. X   NOT a regular expressions pattern substitution, it's just not worth it.
  725. X   
  726. X   if anchor == TRUE then the src pattern match must be at the end of a token.
  727. X   ie. this is for SYSV compatibility and is only used for substitutions of
  728. X   the caused by $(macro:pat=sub).  So if src = "fre.o.k june.o" then
  729. X   $(src:.o=.a) results in "fre.o.k june.a", and $(src:s/.o/.a) results in
  730. X   "fre.a.k june.a" */
  731. X
  732. char *src;            /* the source string */
  733. char *pat;            /* pattern to find   */
  734. char *subst;            /* substitute string */
  735. int   fr;            /* if TRUE free src  */
  736. int   anchor;            /* if TRUE anchor    */
  737. {
  738. X   char *res;
  739. X   char *p;
  740. X   char *s;
  741. X   int   l;
  742. X
  743. X   DB_ENTER( "Apply_edit" );
  744. X   
  745. X   if( !*pat ) DB_RETURN( src );        /* do nothing if pat is NULL */
  746. X
  747. X   DB_PRINT( "mod", ("Source str:  [%s]", src) );
  748. X   DB_PRINT( "mod", ("Replacing [%s], with [%s]", pat, subst) );
  749. X
  750. X   s   = src;
  751. X   l   = strlen( pat );
  752. X   if( (p = _strstr( s, pat )) != NIL(char) ) {
  753. X      res = _strdup( "" );
  754. X      do {
  755. X     if( anchor )
  756. X        if( !*(p+l) || (strchr(" \t", *(p+l)) != NIL(char)) )
  757. X           res = _strjoin( _strjoin( res, s, p-s, TRUE ), subst, -1, TRUE );
  758. X        else
  759. X           res = _strjoin( res, s, p+l-s, TRUE );
  760. X     else
  761. X        res = _strjoin( _strjoin( res, s, p-s, TRUE ), subst, -1, TRUE );
  762. X
  763. X     s   = p + l;
  764. X      }
  765. X      while( (p = _strstr( s, pat )) != NIL(char) );
  766. X
  767. X      res = _strjoin( res, s, -1, TRUE );
  768. X      if( fr ) FREE( src );
  769. X   }
  770. X   else
  771. X      res = src;
  772. X
  773. X
  774. X   DB_PRINT( "mod", ("Result [%s]", res) );
  775. X   DB_RETURN( res );
  776. }
  777. X
  778. X
  779. PUBLIC void
  780. Map_esc( tok )/*
  781. ================
  782. X   Map an escape sequence and replace it by it's corresponding character
  783. X   value.  It is assumed that tok points at the initial \, the esc
  784. X   sequence in the original string is replaced and the value of tok
  785. X   is not modified. */
  786. char *tok;
  787. {
  788. X   if( strchr( "\"\\vantbrf01234567", tok[1] ) ) {
  789. X      switch( tok[1] ) {
  790. X     case 'a' : *tok = 0x07; break;
  791. X     case 'b' : *tok = '\b'; break;
  792. X     case 'f' : *tok = '\f'; break;
  793. X     case 'n' : *tok = '\n'; break;
  794. X     case 'r' : *tok = '\r'; break;
  795. X     case 't' : *tok = '\t'; break;
  796. X     case 'v' : *tok = 0x0b; break;
  797. X     case '\\': *tok = '\\'; break;
  798. X     case '\"': *tok = '\"'; break;
  799. X
  800. X     default: {
  801. X        register int i = 0;
  802. X        register int j = 0;
  803. X        for( ; i<2 && isdigit(tok[2]); i++ ) {
  804. X           j = (j << 3) + (tok[1] - '0');
  805. X           strcpy( tok+1, tok+2 );
  806. X        }
  807. X        j = (j << 3) + (tok[1] - '0');
  808. X        *tok = j;
  809. X     }
  810. X      }
  811. X      strcpy( tok+1, tok+2 );
  812. X   }
  813. }
  814. X
  815. X
  816. PUBLIC char*
  817. Apply_modifiers( mod, src )/*
  818. =============================
  819. X   This routine applies the appropriate modifiers to the string src
  820. X   and returns the proper result string */
  821. X
  822. int  mod;
  823. char *src;
  824. {
  825. X   char       *s;
  826. X   char    *e;
  827. X   TKSTR   str;
  828. X
  829. X   DB_ENTER( "Apply_modifiers" );
  830. X
  831. X   if( mod == (SUFFIX_FLAG | DIRECTORY_FLAG | FILE_FLAG) )
  832. X      DB_RETURN( src );
  833. X
  834. X   SET_TOKEN( &str, src );
  835. X   DB_PRINT( "mod", ("Source string [%s]", src) );
  836. X
  837. X   while( *(s = Get_token( &str, "", FALSE )) != '\0' ) {
  838. X      /* search for the directory portion of the filename.  If the
  839. X       * DIRECTORY_FLAG is set, then we want to keep the directory portion
  840. X       * othewise throw it away and blank out to the end of the token */
  841. X
  842. X      if( (e = basename(s)) != s)
  843. X     if( !(mod & DIRECTORY_FLAG) ) {
  844. X        strcpy(s, e);
  845. X        e = s+(str.tk_str-e);
  846. X        for(; e != str.tk_str; e++)
  847. X               *e = ' ';
  848. X     }
  849. X     else
  850. X        s = e;
  851. X
  852. X      /* search for the suffix, if there is none, treat it as a NULL suffix.
  853. X       * if no file name treat it as a NULL file name.  same copy op as
  854. X       * for directory case above */
  855. X
  856. X      e = strrchr( s, '.' );            /* NULL suffix if e=0 */
  857. X      if( e == NIL(char) ) e = s+strlen(s);
  858. X
  859. X      if( !(mod & FILE_FLAG) ) {
  860. X     strcpy( s, e );
  861. X     e = s+(str.tk_str-e);
  862. X     for( ; e != str.tk_str; e++ ) *e = ' ';
  863. X      }
  864. X      else
  865. X     s = e;
  866. X
  867. X      /* The last and final part.  This is the suffix case, if we don't want
  868. X       * it then just erase to the end of the token. */
  869. X
  870. X      if( s != NIL(char) )
  871. X     if( !(mod & SUFFIX_FLAG) )
  872. X        for( ; s != str.tk_str; s++ ) *s = ' ';
  873. X   }
  874. X
  875. X   /* delete the extra white space, it looks ugly */
  876. X   for( s = src, e = NIL(char); *s; s++ )
  877. X      if( *s == ' ' || *s == '\t' || *s == '\n' ) {
  878. X     if( e == NIL(char) )
  879. X        e = s;
  880. X      }
  881. X      else {
  882. X     if( e != NIL(char) ) {
  883. X        if( e+1 < s ) {
  884. X           strcpy( e+1, s );
  885. X           s = e+1;
  886. X           *e = ' ';
  887. X        }
  888. X        e = NIL(char);
  889. X     }
  890. X      }
  891. X
  892. X   if( e != NIL(char) )
  893. X      if( e < s )
  894. X     strcpy( e, s );
  895. X
  896. X   DB_PRINT( "mod", ("Result string [%s]", src) );
  897. X   DB_RETURN( src );
  898. }
  899. X
  900. X
  901. PUBLIC char*
  902. Tokenize( src, separator )/*
  903. ============================
  904. X    Tokenize the input of src and join each token found together with
  905. X    the next token separated by the separator string.
  906. X
  907. X    When doing the tokenization, <sp>, <tab>, <nl>, and \<nl> all
  908. X    constitute white space. */
  909. X
  910. char *src;
  911. char *separator;
  912. {
  913. X   TKSTR    tokens;
  914. X   char        *tok;
  915. X   char        *res;
  916. X   int        first = TRUE;
  917. X
  918. X   DB_ENTER( "Tokenize" );
  919. X
  920. X   SET_TOKEN( &tokens, src );
  921. X
  922. X
  923. X   /* map the escape codes in the separator string first */
  924. X
  925. X   for(tok=separator; (tok = strchr(tok,ESCAPE_CHAR)) != NIL(char); tok++)
  926. X      Map_esc( tok );
  927. X
  928. X   DB_PRINT( "exp", ("Separator [%s]", separator) );
  929. X
  930. X   /* Build the token list */
  931. X   res = _strdup( "" );
  932. X   while( *(tok = Get_token( &tokens, "", FALSE )) != '\0' ) {
  933. X      DB_PRINT( "exp", ("Tokenizing [%s]", tok) );
  934. X
  935. X      if( first ) {
  936. X     FREE( res );
  937. X     res   = _strdup( tok );
  938. X     first = FALSE;
  939. X      }
  940. X      else {
  941. X           char *x;
  942. X     res = _strjoin(res, x =_strjoin(separator, tok, -1, FALSE), -1, TRUE);
  943. X     FREE( x );
  944. X      }
  945. X   }
  946. X
  947. X   FREE( src );
  948. X   DB_RETURN( res );
  949. }
  950. X
  951. X
  952. static char*
  953. _scan_token( s, ps )/*
  954. ======================
  955. X      This routine scans the token characters one at a time and identifies
  956. X      macros starting with $( and ${ and calls _scan_macro to expand their
  957. X      value.   the string1{ token_list }string2 expansion is also handled.
  958. X      In this case a temporary result is maintained so that we can take it's
  959. X      cross product with any other token_lists that may possibly appear. */
  960. X      
  961. char *s;        /* pointer to start of src string */
  962. char **ps;        /* pointer to start pointer      */
  963. {
  964. X   char *res;                 /* pointer to result          */
  965. X   char *start;               /* pointer to start of prefix */
  966. X   int  crossproduct = 0;     /* if 1 then computing X-prod */
  967. X
  968. X   start = s;
  969. X   res   = _strdup( "" );
  970. X   while( 1 )
  971. X      switch( *s ) {
  972. X         /* Termination, We halt at seeing a space or a tab or end of string.
  973. X          * We return the value of the result with any new macro's we scanned
  974. X          * or if we were computing cross_products then we return the new
  975. X          * cross_product.
  976. X          * NOTE:  Once we start computing cross products it is impossible to
  977. X          *        stop.  ie. the semantics are such that once a {} pair is
  978. X          *        seen we compute cross products until termination. */
  979. X
  980. X         case ' ':
  981. X         case '\t':
  982. X     case '\n':
  983. X         case '\0': 
  984. X     {
  985. X        char *tmp;
  986. X
  987. X        *ps = s;
  988. X        if( !crossproduct )
  989. X           tmp = _strjoin( res, start, (s-start), TRUE );
  990. X        else
  991. X        {
  992. X           tmp = _substr( start, s );
  993. X           tmp = _cross_prod( res, tmp );
  994. X        }
  995. X        return( tmp );
  996. X     }
  997. X         
  998. X         case '$':
  999. X         case '{':
  1000. X     {
  1001. X        /* Handle if it's a macro or if it's a {} construct.
  1002. X         * The results of a macro expansion are handled differently based
  1003. X         * on whether we have seen a {} beforehand. */
  1004. X        
  1005. X        char *tmp;
  1006. X        tmp = _substr( start, s );          /* save the prefix */
  1007. X
  1008. X        if( *s == '$' ) {
  1009. X           start = _scan_macro( s+1, &s );
  1010. X
  1011. X           if( crossproduct )
  1012. X          res = _cross_prod( res, _strjoin( tmp, start, -1, TRUE ) );
  1013. X           else {
  1014. X          res = _strjoin(res,tmp = _strjoin(tmp,start,-1,TRUE),-1,TRUE);
  1015. X          FREE( tmp );
  1016. X           }
  1017. X           FREE( start );
  1018. X        }
  1019. X        else if( strchr("{ \t",s[1]) == NIL(char) ){
  1020. X           int ok;
  1021. X           start = _scan_brace( s+1, &s, &ok );
  1022. X          
  1023. X           if( ok ) {
  1024. X          res = _cross_prod( res, _cross_prod(tmp, start) );
  1025. X          crossproduct = TRUE;
  1026. X           }
  1027. X           else {
  1028. X          res =_strjoin(res,tmp=_strjoin(tmp,start,-1,TRUE),-1,TRUE);
  1029. X          FREE( start );
  1030. X          FREE( tmp   );
  1031. X           }
  1032. X        }
  1033. X        else {    /* handle the {{ case */
  1034. X           res = _strjoin( res, start, (s-start+1), TRUE );
  1035. X           s  += (s[1]=='{')?2:1;
  1036. X           FREE( tmp );
  1037. X        }
  1038. X
  1039. X        start = s;
  1040. X     }
  1041. X     break;
  1042. X
  1043. X     case '}':
  1044. X        if( s[1] != '}' ) {
  1045. X           /* error malformed macro expansion */
  1046. X           s++;
  1047. X        }
  1048. X        else {    /* handle the }} case */
  1049. X           res = _strjoin( res, start, (s-start+1), TRUE );
  1050. X           s += 2;
  1051. X           start = s;
  1052. X        }
  1053. X        break;
  1054. X         
  1055. X         default: s++;
  1056. X      }
  1057. }
  1058. X
  1059. X
  1060. static char*
  1061. _scan_macro( s, ps )/*
  1062. ======================
  1063. X    This routine scans a macro use and expands it to the value.  It
  1064. X    returns the macro's expanded value and modifies the pointer into the
  1065. X    src string to point at the first character after the macro use.
  1066. X    The types of uses recognized are:
  1067. X
  1068. X        $$        - expands to $
  1069. X        $(name)        - expands to value of name
  1070. X        ${name}        - same as above
  1071. X        $($(name))    - recurses on macro names (any level)
  1072. X    and
  1073. X        $(func[,args ...] [data])
  1074. X    and 
  1075. X            $(name:modifier_list:modifier_list:...)
  1076. X        
  1077. X    see comment for Expand for description of valid modifiers.
  1078. X
  1079. X    NOTE that once a macro name bounded by ( or { is found only
  1080. X    the appropriate terminator (ie. ( or } is searched for. */
  1081. X
  1082. char *s;        /* pointer to start of src string   */
  1083. char **ps;        /* pointer to start pointer        */
  1084. {
  1085. X   char sdelim;         /* start of macro delimiter         */
  1086. X   char edelim;         /* corresponding end macro delim    */
  1087. X   char *start;         /* start of prefix                  */
  1088. X   char *macro_name;    /* temporary macro name             */
  1089. X   char *recurse_name;  /* recursive macro name             */
  1090. X   char *result;    /* result for macro expansion        */
  1091. X   int  bflag = 0;      /* brace flag, ==0 => $A type macro */
  1092. X   int  done  = 0;      /* != 0 => done macro search        */
  1093. X   int  lev   = 0;      /* brace level                      */
  1094. X   int  mflag = 0;      /* != 0 => modifiers present in mac */
  1095. X   int  fflag = 0;    /* != 0 => GNU style function         */
  1096. X   HASHPTR hp;        /* hash table pointer for macros    */
  1097. X   
  1098. X   DB_ENTER( "_scan_macro" );
  1099. X
  1100. X   /* Check for the simple $ at end of line case */
  1101. X   if( !*s ) {
  1102. X      *ps = s;
  1103. X      DB_RETURN( _strdup("") );
  1104. X   }
  1105. X
  1106. X   if( *s == '$' ) {    /* Take care of the simple $$ case. */
  1107. X      *ps = s+1;
  1108. X      DB_RETURN( _strdup("$") );
  1109. X   }
  1110. X
  1111. X   sdelim = *s;         /* set and remember start/end delim */
  1112. X   if( sdelim == '(' )
  1113. X      edelim = ')';
  1114. X   else
  1115. X      edelim = '}';
  1116. X
  1117. X   start = s;           /* build up macro name, find its end*/
  1118. X   while( !done ) {
  1119. X      switch( *s ) {
  1120. X         case '(':                /* open macro brace */
  1121. X         case '{':
  1122. X        if( *s == sdelim ) {
  1123. X           lev++;
  1124. X           bflag++;
  1125. X        }
  1126. X        break;
  1127. X         
  1128. X         case ':':                              /* halt at modifier */
  1129. X            if( lev == 1 ) {
  1130. X               done = TRUE;
  1131. X               mflag = 1;
  1132. X            }
  1133. X            break;
  1134. X
  1135. X     case ' ':
  1136. X     case '\t':
  1137. X     case '\n':
  1138. X        fflag = 1;
  1139. X        break;
  1140. X            
  1141. X     case '\0':                /* check for null */
  1142. X        *ps = s;
  1143. X        if( lev ) {
  1144. X           done  = TRUE;
  1145. X           bflag = 0;
  1146. X           s     = start;
  1147. X        }
  1148. X        break;
  1149. X         
  1150. X         case ')':                /* close macro brace */
  1151. X         case '}':
  1152. X        if( *s == edelim && lev ) --lev;
  1153. X        /*FALLTHROUGH*/
  1154. X
  1155. X         default:
  1156. X        done = !lev;
  1157. X      }
  1158. X      s++;
  1159. X   }
  1160. X
  1161. X   /* Check if this is a $A type macro.  If so then we have to
  1162. X    * handle it a little differently. */
  1163. X   if( bflag )
  1164. X      macro_name = _substr( start+1, s-1 );
  1165. X   else
  1166. X      macro_name = _substr( start, s );
  1167. X
  1168. X   /* Check to see if the macro name contains spaces, if so then treat it
  1169. X    * as a GNU style function invocation and call the function mapper to
  1170. X    * deal with it. */
  1171. X   if( fflag )
  1172. X      result = Exec_function(macro_name);
  1173. X   else {
  1174. X      /* Check if the macro is a recursive macro name, if so then
  1175. X       * EXPAND the name before expanding the value */
  1176. X      if( strchr( macro_name, '$' ) != NIL(char) ) {
  1177. X     recurse_name = Expand( macro_name );
  1178. X     FREE( macro_name );
  1179. X     macro_name = recurse_name;
  1180. X      }
  1181. X
  1182. X      /* Code to do value expansion goes here, NOTE:  macros whose assign bit
  1183. X     is one have been evaluated and assigned, they contain no further
  1184. X     expansions and thus do not need their values expanded again. */
  1185. X
  1186. X      if( (hp = GET_MACRO( macro_name )) != NIL(HASH) ) {
  1187. X     if( hp->ht_flag & M_MARK )
  1188. X        Fatal( "Detected circular macro [%s]", hp->ht_name );
  1189. X
  1190. X     /* for M_MULTI macro variable assignments */
  1191. X     If_multi = hp->ht_flag & M_MULTI;
  1192. X
  1193. X     if( !(hp->ht_flag & M_EXPANDED) ) {
  1194. X        hp->ht_flag |= M_MARK;
  1195. X        result = Expand( hp->ht_value );
  1196. X        hp->ht_flag ^= M_MARK;
  1197. X     }
  1198. X     else if( hp->ht_value != NIL(char) )
  1199. X        result = _strdup( hp->ht_value );
  1200. X     else
  1201. X        result = _strdup( "" );
  1202. X
  1203. X     /*
  1204. X      * Mark macros as used only if we are not expanding them for
  1205. X      * the purpose of a .IF test, so we can warn about redef after use*/
  1206. X
  1207. X     if( !If_expand ) hp->ht_flag |= M_USED;
  1208. X      }
  1209. X      else
  1210. X     result = _strdup( "" );
  1211. X   }
  1212. X
  1213. X   if( mflag ) {
  1214. X      char separator;
  1215. X      int  modifier_list = 0;
  1216. X      int  aug_mod       = FALSE;
  1217. X      char *pat1;
  1218. X      char *pat2;
  1219. X      char *p;
  1220. X
  1221. X      /* Yet another brain damaged AUGMAKE kludge.  We should accept the 
  1222. X       * AUGMAKE bullshit of $(f:pat=sub) form of macro expansion.  In
  1223. X       * order to do this we will forgo the normal processing if the
  1224. X       * AUGMAKE solution pans out, otherwise we will try to process the
  1225. X       * modifiers ala dmake.
  1226. X       *
  1227. X       * So we look for = in modifier string.
  1228. X       * If found we process it and not do the normal stuff */
  1229. X
  1230. X      for( p=s; *p && *p != '=' && *p != edelim; p++ );
  1231. X
  1232. X      if( *p == '=' ) {
  1233. X     pat1 = _substr( s, p );
  1234. X     for( s=p=p+1; (*p != edelim); p++ );
  1235. X
  1236. X     pat2 = _substr( s, p );
  1237. X
  1238. X     if( !Augmake ) {
  1239. X        char *tmp = pat2;
  1240. X        pat2 = Expand(pat2);
  1241. X        FREE(tmp);
  1242. X     }
  1243. X
  1244. X     result = Apply_edit( result, pat1, pat2, TRUE, TRUE );
  1245. X     FREE( pat1 );
  1246. X     FREE( pat2 );
  1247. X     s = p;
  1248. X     aug_mod = TRUE;
  1249. X      }
  1250. X
  1251. X      if( !aug_mod )
  1252. X     while( *s && *s != edelim ) {        /* while not at end of macro */
  1253. X        switch( *s++ ) {
  1254. X           case 'b':
  1255. X           case 'B': modifier_list |= FILE_FLAG;            break;
  1256. X
  1257. X           case 'd':
  1258. X           case 'D': modifier_list |= DIRECTORY_FLAG;         break;
  1259. X
  1260. X           case 'f':
  1261. X           case 'F': modifier_list |= FILE_FLAG | SUFFIX_FLAG; break;
  1262. X
  1263. X           case 'S':
  1264. X           case 's':
  1265. X          if( modifier_list ) {
  1266. X             Warning( "Edit modifier must appear alone, ignored");
  1267. X             modifier_list = 0;
  1268. X          }
  1269. X          else {
  1270. X             separator = *s++;
  1271. X             for( p=s; *p != separator && *p != edelim; p++ );
  1272. X
  1273. X             if( *p == edelim )
  1274. X                Warning("Syntax error in edit pattern, ignored");
  1275. X             else {
  1276. X            char *t1, *t2;
  1277. X            pat1 = _substr( s, p );
  1278. X            for(s=p=p+1; (*p != separator) && (*p != edelim); p++ );
  1279. X            pat2 = _substr( s, p );
  1280. X            t1 = Expand(pat1); FREE(pat1);
  1281. X            t2 = Expand(pat2); FREE(pat2);
  1282. X            result = Apply_edit( result, t1, t2, TRUE, FALSE );
  1283. X            FREE( t1 );
  1284. X            FREE( t2 );
  1285. X             }
  1286. X             s = p;
  1287. X          }
  1288. X          /* find the end of the macro spec, or the start of a new
  1289. X           * modifier list for further processing of the result */
  1290. X
  1291. X          for( ; (*s != edelim) && (*s != ':'); s++ );
  1292. X          if( *s == ':' ) s++;
  1293. X          break;
  1294. X
  1295. X           case 'T':
  1296. X           case 't':
  1297. X          if( modifier_list ) {
  1298. X             Warning( "Tokenize modifier must appear alone, ignored");
  1299. X             modifier_list = 0;
  1300. X          }
  1301. X          else {
  1302. X             char *msg = "Separator string must be quoted";
  1303. X
  1304. X             separator = *s++;
  1305. X
  1306. X             if( separator != '\"' )
  1307. X            Warning( msg );
  1308. X             else {
  1309. X            /* we change the semantics to allow $(v:t")") */
  1310. X            for (p = s; *p && *p != separator; p++)
  1311. X               if (*p == '\\')
  1312. X                  if (p[1] == '\\' || p[1] == '"')
  1313. X                 p++;
  1314. X            if( *p == 0 )
  1315. X               Fatal( "Unterminated separator string" );
  1316. X            else {
  1317. X               pat1 = _substr( s, p );
  1318. X               result = Tokenize( result, pat1 );
  1319. X               FREE( pat1 );
  1320. X            }
  1321. X            s = p;
  1322. X             }
  1323. X
  1324. X             /* find the end of the macro spec, or the start of a new
  1325. X              * modifier list for further processing of the result */
  1326. X
  1327. X             for( ; (*s != edelim) && (*s != ':'); s++ );
  1328. X             if( *s == ':' ) s++;
  1329. X          }
  1330. X          break;
  1331. X
  1332. X           case ':':
  1333. X          if( modifier_list ) {
  1334. X             result = Apply_modifiers( modifier_list, result );
  1335. X             modifier_list = 0;
  1336. X          }
  1337. X          break;
  1338. X
  1339. X           default:
  1340. X          Warning( "Illegal modifier in macro, ignored" );
  1341. X          break;
  1342. X        }
  1343. X     }
  1344. X
  1345. X      if( modifier_list ) /* apply modifier */
  1346. X         result = Apply_modifiers( modifier_list, result );
  1347. X      
  1348. X      s++;
  1349. X   }
  1350. X
  1351. X   *ps = s;
  1352. X   FREE( macro_name );
  1353. X   DB_RETURN( result );
  1354. }
  1355. X
  1356. X
  1357. static char*
  1358. _scan_brace( s, ps, flag )/*
  1359. ============================
  1360. X      This routine scans for { token_list } pairs.  It expands the value of
  1361. X      token_list by calling Expand on it.  Token_list may be anything at all.
  1362. X      Note that the routine count's ballanced parentheses.  This means you
  1363. X      cannot have something like { fred { joe }, if that is what you really
  1364. X      need the write it as { fred {{ joe }, flag is set to 1 if all ok
  1365. X      and to 0 if the braces were unballanced. */
  1366. X      
  1367. char *s;
  1368. char **ps;
  1369. int  *flag;
  1370. {
  1371. X   char *t;
  1372. X   char *start;
  1373. X   char *res;
  1374. X   int  lev  = 1;
  1375. X   int  done = 0;
  1376. X   
  1377. X   DB_ENTER( "_scan_brace" );
  1378. X
  1379. X   start = s;
  1380. X   while( !done )
  1381. X      switch( *s++ ) {
  1382. X         case '{': 
  1383. X            if( *s == '{' ) break;              /* ignore {{ */
  1384. X            lev++;
  1385. X            break;
  1386. X            
  1387. X         case '}': 
  1388. X            if( *s == '}' ) break;              /* ignore }} */
  1389. X        if( lev )
  1390. X           if( --lev == 0 ) done = TRUE;
  1391. X        break;
  1392. X
  1393. X     case '$':
  1394. X        if( *s == '{' || *s == '}' ) {
  1395. X          if( (t = strchr(s,'}')) != NIL(char) )
  1396. X             s = t;
  1397. X          s++;
  1398. X        }
  1399. X        break;
  1400. X         
  1401. X         case '\0':
  1402. X        if( lev ) {
  1403. X           done = TRUE;
  1404. X           s--;
  1405. X           /* error malformed macro expansion */
  1406. X        }
  1407. X        break;
  1408. X      }
  1409. X
  1410. X   start = _substr( start, (lev) ? s : s-1 );
  1411. X
  1412. X   if( lev ) {
  1413. X      /* Braces were not ballanced so just return the string.
  1414. X       * Do not expand it. */
  1415. X       
  1416. X      res   = _strjoin( "{", start, -1, FALSE );
  1417. X      *flag = 0;
  1418. X   }
  1419. X   else {
  1420. X      *flag = 1;
  1421. X      res   = Expand( start );
  1422. X
  1423. X      if( (t = _strspn( res, " \t" )) != res ) strcpy( res, t );
  1424. X   }
  1425. X
  1426. X   FREE( start );       /* this is ok! start is assigned a _substr above */
  1427. X   *ps = s;
  1428. X
  1429. X   DB_RETURN( res );
  1430. }
  1431. X
  1432. X
  1433. static char*
  1434. _cross_prod( x, y )/*
  1435. =====================
  1436. X      Given two strings x and y compute the cross-product of the tokens found
  1437. X      in each string.  ie. if x = "a b" and y = "c d" return "ac ad bc bd".
  1438. X
  1439. X         NOTE:  buf will continue to grow until it is big enough to handle
  1440. X                all cross product requests.  It is never freed!  (maybe I
  1441. X            will fix this someday) */
  1442. X      
  1443. char *x;
  1444. char *y;
  1445. {
  1446. X   static char *buf;
  1447. X   static int  buf_siz = 0;
  1448. X   char *brkx;
  1449. X   char *brky;
  1450. X   char *cy;
  1451. X   char *cx;
  1452. X   char *res;
  1453. X   int  i;
  1454. X
  1455. X   if( *x && *y ) {
  1456. X      res = _strdup( "" ); cx = x;
  1457. X      while( *cx ) {
  1458. X     cy = y;
  1459. X         brkx = _strpbrk( cx, " \t\n" );
  1460. X     if( (brkx-cx == 2) && *cx == '\"' && *(cx+1) == '\"' ) cx = brkx;
  1461. X
  1462. X     while( *cy ) {
  1463. X        brky = _strpbrk( cy, " \t\n" );
  1464. X        if( (brky-cy == 2) && *cy == '\"' && *(cy+1) == '\"' ) cy = brky;
  1465. X        i    = brkx-cx + brky-cy + 2;
  1466. X
  1467. X        if( i > buf_siz ) {        /* grow buf to the correct size */
  1468. X           if( buf != NIL(char) ) FREE( buf );
  1469. X           if( (buf = MALLOC( i, char )) == NIL(char))  No_ram();
  1470. X           buf_siz = i;
  1471. X        }
  1472. X
  1473. X        strncpy( buf, cx, (i = brkx-cx) );
  1474. X        buf[i] = '\0';
  1475. SHAR_EOF
  1476. true || echo 'restore of dmake/expand.c failed'
  1477. fi
  1478. echo 'End of part 8, continue with part 9'
  1479. echo 9 > _shar_seq_.tmp
  1480. exit 0
  1481. exit 0 # Just in case...
  1482.