home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume19 / dmake / part09 < prev    next >
Encoding:
Text File  |  1991-05-11  |  40.2 KB  |  1,489 lines

  1. Newsgroups: comp.sources.misc
  2. From: Dennis Vadura <dvadura@watdragon.waterloo.edu>
  3. Subject:  v19i030:  dmake - dmake version 3.7, Part09/37
  4. Message-ID: <1991May10.185804.22590@sparky.IMD.Sterling.COM>
  5. Date: Fri, 10 May 1991 18:58:04 GMT
  6. Approved: kent@sparky.imd.sterling.com
  7.  
  8. Submitted-by: Dennis Vadura <dvadura@watdragon.waterloo.edu>
  9. Posting-number: Volume 19, Issue 30
  10. Archive-name: dmake/part09
  11. Supersedes: dmake-3.6: Volume 15, Issue 52-77
  12.  
  13. ---- Cut Here and feed the following to sh ----
  14. #!/bin/sh
  15. # this is dmake.shar.09 (part 9 of a multipart archive)
  16. # do not concatenate these parts, unpack them in order with /bin/sh
  17. # file dmake/expand.c continued
  18. #
  19. if test ! -r _shar_seq_.tmp; then
  20.     echo 'Please unpack part 1 first!'
  21.     exit 1
  22. fi
  23. (read Scheck
  24.  if test "$Scheck" != 9; then
  25.     echo Please unpack part "$Scheck" next!
  26.     exit 1
  27.  else
  28.     exit 0
  29.  fi
  30. ) < _shar_seq_.tmp || exit 1
  31. if test -f _shar_wnt_.tmp; then
  32. sed 's/^X//' << 'SHAR_EOF' >> 'dmake/expand.c' &&
  33. X   while( *(tok = Get_token( &tokens, "", FALSE )) != '\0' ) {
  34. X      DB_PRINT( "exp", ("Tokenizing [%s]", tok) );
  35. X
  36. X      if( first ) {
  37. X     FREE( res );
  38. X     res   = _strdup( tok );
  39. X     first = FALSE;
  40. X      }
  41. X      else {
  42. X           char *x;
  43. X     res = _strjoin(res, x =_strjoin(separator, tok, -1, FALSE), -1, TRUE);
  44. X     FREE( x );
  45. X      }
  46. X   }
  47. X
  48. X   FREE( src );
  49. X   DB_RETURN( res );
  50. }
  51. X
  52. X
  53. static char*
  54. _scan_token( s, ps )/*
  55. ======================
  56. X      This routine scans the token characters one at a time and identifies
  57. X      macros starting with $( and ${ and calls _scan_macro to expand their
  58. X      value.   the string1{ token_list }string2 expansion is also handled.
  59. X      In this case a temporary result is maintained so that we can take it's
  60. X      cross product with any other token_lists that may possibly appear. */
  61. X      
  62. char *s;        /* pointer to start of src string */
  63. char **ps;        /* pointer to start pointer      */
  64. {
  65. X   char *res;                 /* pointer to result          */
  66. X   char *start;               /* pointer to start of prefix */
  67. X   int  crossproduct = 0;     /* if 1 then computing X-prod */
  68. X
  69. X   start = s;
  70. X   res   = _strdup( "" );
  71. X   while( 1 )
  72. X      switch( *s ) {
  73. X         /* Termination, We halt at seeing a space or a tab or end of string.
  74. X          * We return the value of the result with any new macro's we scanned
  75. X          * or if we were computing cross_products then we return the new
  76. X          * cross_product.
  77. X          * NOTE:  Once we start computing cross products it is impossible to
  78. X          *        stop.  ie. the semantics are such that once a {} pair is
  79. X          *        seen we compute cross products until termination. */
  80. X
  81. X         case ' ':
  82. X         case '\t':
  83. X     case '\n':
  84. X         case '\0': 
  85. X     {
  86. X        char *tmp;
  87. X
  88. X        *ps = s;
  89. X        if( !crossproduct )
  90. X           tmp = _strjoin( res, start, (s-start), TRUE );
  91. X        else
  92. X        {
  93. X           tmp = _substr( start, s );
  94. X           tmp = _cross_prod( res, tmp );
  95. X        }
  96. X        return( tmp );
  97. X     }
  98. X         
  99. X         case '$':
  100. X         case '{':
  101. X     {
  102. X        /* Handle if it's a macro or if it's a {} construct.
  103. X         * The results of a macro expansion are handled differently based
  104. X         * on whether we have seen a {} beforehand. */
  105. X        
  106. X        char *tmp;
  107. X        tmp = _substr( start, s );          /* save the prefix */
  108. X
  109. X        if( *s == '$' ) {
  110. X           start = _scan_macro( s+1, &s );
  111. X
  112. X           if( crossproduct )
  113. X          res = _cross_prod( res, _strjoin( tmp, start, -1, TRUE ) );
  114. X           else {
  115. X          res = _strjoin(res,tmp = _strjoin(tmp,start,-1,TRUE),-1,TRUE);
  116. X          FREE( tmp );
  117. X           }
  118. X           FREE( start );
  119. X        }
  120. X        else if( strchr("{ \t",s[1]) == NIL(char) ){
  121. X           int ok;
  122. X           start = _scan_brace( s+1, &s, &ok );
  123. X          
  124. X           if( ok ) {
  125. X          res = _cross_prod( res, _cross_prod(tmp, start) );
  126. X          crossproduct = TRUE;
  127. X           }
  128. X           else {
  129. X          res =_strjoin(res,tmp=_strjoin(tmp,start,-1,TRUE),-1,TRUE);
  130. X          FREE( start );
  131. X          FREE( tmp   );
  132. X           }
  133. X        }
  134. X        else {    /* handle the {{ case */
  135. X           res = _strjoin( res, start, (s-start+1), TRUE );
  136. X           s  += (s[1]=='{')?2:1;
  137. X           FREE( tmp );
  138. X        }
  139. X
  140. X        start = s;
  141. X     }
  142. X     break;
  143. X
  144. X     case '}':
  145. X        if( s[1] != '}' ) {
  146. X           /* error malformed macro expansion */
  147. X           s++;
  148. X        }
  149. X        else {    /* handle the }} case */
  150. X           res = _strjoin( res, start, (s-start+1), TRUE );
  151. X           s += 2;
  152. X           start = s;
  153. X        }
  154. X        break;
  155. X         
  156. X         default: s++;
  157. X      }
  158. }
  159. X
  160. X
  161. static char*
  162. _scan_macro( s, ps )/*
  163. ======================
  164. X    This routine scans a macro use and expands it to the value.  It
  165. X    returns the macro's expanded value and modifies the pointer into the
  166. X    src string to point at the first character after the macro use.
  167. X    The types of uses recognized are:
  168. X
  169. X        $$        - expands to $
  170. X        $(name)        - expands to value of name
  171. X        ${name}        - same as above
  172. X        $($(name))    - recurses on macro names (any level)
  173. X    and
  174. X        $(func[,args ...] [data])
  175. X    and 
  176. X            $(name:modifier_list:modifier_list:...)
  177. X        
  178. X    see comment for Expand for description of valid modifiers.
  179. X
  180. X    NOTE that once a macro name bounded by ( or { is found only
  181. X    the appropriate terminator (ie. ( or } is searched for. */
  182. X
  183. char *s;        /* pointer to start of src string   */
  184. char **ps;        /* pointer to start pointer        */
  185. {
  186. X   char sdelim;         /* start of macro delimiter         */
  187. X   char edelim;         /* corresponding end macro delim    */
  188. X   char *start;         /* start of prefix                  */
  189. X   char *macro_name;    /* temporary macro name             */
  190. X   char *recurse_name;  /* recursive macro name             */
  191. X   char *result;    /* result for macro expansion        */
  192. X   int  bflag = 0;      /* brace flag, ==0 => $A type macro */
  193. X   int  done  = 0;      /* != 0 => done macro search        */
  194. X   int  lev   = 0;      /* brace level                      */
  195. X   int  mflag = 0;      /* != 0 => modifiers present in mac */
  196. X   int  fflag = 0;    /* != 0 => GNU style function         */
  197. X   HASHPTR hp;        /* hash table pointer for macros    */
  198. X   
  199. X   DB_ENTER( "_scan_macro" );
  200. X
  201. X   /* Check for the simple $ at end of line case */
  202. X   if( !*s ) {
  203. X      *ps = s;
  204. X      DB_RETURN( _strdup("") );
  205. X   }
  206. X
  207. X   if( *s == '$' ) {    /* Take care of the simple $$ case. */
  208. X      *ps = s+1;
  209. X      DB_RETURN( _strdup("$") );
  210. X   }
  211. X
  212. X   sdelim = *s;         /* set and remember start/end delim */
  213. X   if( sdelim == '(' )
  214. X      edelim = ')';
  215. X   else
  216. X      edelim = '}';
  217. X
  218. X   start = s;           /* build up macro name, find its end*/
  219. X   while( !done ) {
  220. X      switch( *s ) {
  221. X         case '(':                /* open macro brace */
  222. X         case '{':
  223. X        if( *s == sdelim ) {
  224. X           lev++;
  225. X           bflag++;
  226. X        }
  227. X        break;
  228. X         
  229. X         case ':':                              /* halt at modifier */
  230. X            if( lev == 1 ) {
  231. X               done = TRUE;
  232. X               mflag = 1;
  233. X            }
  234. X            break;
  235. X
  236. X     case ' ':
  237. X     case '\t':
  238. X     case '\n':
  239. X        fflag = 1;
  240. X        break;
  241. X            
  242. X     case '\0':                /* check for null */
  243. X        *ps = s;
  244. X        if( lev ) {
  245. X           done  = TRUE;
  246. X           bflag = 0;
  247. X           s     = start;
  248. X        }
  249. X        break;
  250. X         
  251. X         case ')':                /* close macro brace */
  252. X         case '}':
  253. X        if( *s == edelim && lev ) --lev;
  254. X        /*FALLTHROUGH*/
  255. X
  256. X         default:
  257. X        done = !lev;
  258. X      }
  259. X      s++;
  260. X   }
  261. X
  262. X   /* Check if this is a $A type macro.  If so then we have to
  263. X    * handle it a little differently. */
  264. X   if( bflag )
  265. X      macro_name = _substr( start+1, s-1 );
  266. X   else
  267. X      macro_name = _substr( start, s );
  268. X
  269. X   /* Check to see if the macro name contains spaces, if so then treat it
  270. X    * as a GNU style function invocation and call the function mapper to
  271. X    * deal with it. */
  272. X   if( fflag )
  273. X      result = Exec_function(macro_name);
  274. X   else {
  275. X      /* Check if the macro is a recursive macro name, if so then
  276. X       * EXPAND the name before expanding the value */
  277. X      if( strchr( macro_name, '$' ) != NIL(char) ) {
  278. X     recurse_name = Expand( macro_name );
  279. X     FREE( macro_name );
  280. X     macro_name = recurse_name;
  281. X      }
  282. X
  283. X      /* Code to do value expansion goes here, NOTE:  macros whose assign bit
  284. X     is one have been evaluated and assigned, they contain no further
  285. X     expansions and thus do not need their values expanded again. */
  286. X
  287. X      if( (hp = GET_MACRO( macro_name )) != NIL(HASH) ) {
  288. X     if( hp->ht_flag & M_MARK )
  289. X        Fatal( "Detected circular macro [%s]", hp->ht_name );
  290. X
  291. X     /* for M_MULTI macro variable assignments */
  292. X     If_multi = hp->ht_flag & M_MULTI;
  293. X
  294. X     if( !(hp->ht_flag & M_EXPANDED) ) {
  295. X        hp->ht_flag |= M_MARK;
  296. X        result = Expand( hp->ht_value );
  297. X        hp->ht_flag ^= M_MARK;
  298. X     }
  299. X     else if( hp->ht_value != NIL(char) )
  300. X        result = _strdup( hp->ht_value );
  301. X     else
  302. X        result = _strdup( "" );
  303. X
  304. X     /*
  305. X      * Mark macros as used only if we are not expanding them for
  306. X      * the purpose of a .IF test, so we can warn about redef after use*/
  307. X
  308. X     if( !If_expand ) hp->ht_flag |= M_USED;
  309. X      }
  310. X      else
  311. X     result = _strdup( "" );
  312. X   }
  313. X
  314. X   if( mflag ) {
  315. X      char separator;
  316. X      int  modifier_list = 0;
  317. X      int  aug_mod       = FALSE;
  318. X      char *pat1;
  319. X      char *pat2;
  320. X      char *p;
  321. X
  322. X      /* Yet another brain damaged AUGMAKE kludge.  We should accept the 
  323. X       * AUGMAKE bullshit of $(f:pat=sub) form of macro expansion.  In
  324. X       * order to do this we will forgo the normal processing if the
  325. X       * AUGMAKE solution pans out, otherwise we will try to process the
  326. X       * modifiers ala dmake.
  327. X       *
  328. X       * So we look for = in modifier string.
  329. X       * If found we process it and not do the normal stuff */
  330. X
  331. X      for( p=s; *p && *p != '=' && *p != edelim; p++ );
  332. X
  333. X      if( *p == '=' ) {
  334. X     pat1 = _substr( s, p );
  335. X     for( s=p=p+1; (*p != edelim); p++ );
  336. X
  337. X     pat2   = _substr( s, p );
  338. X     result = Apply_edit( result, pat1, pat2, TRUE, TRUE );
  339. X     FREE( pat1 );
  340. X     FREE( pat2 );
  341. X     s = p;
  342. X     aug_mod = TRUE;
  343. X      }
  344. X
  345. X      if( !aug_mod )
  346. X     while( *s && *s != edelim ) {        /* while not at end of macro */
  347. X        switch( *s++ ) {
  348. X           case 'b':
  349. X           case 'B': modifier_list |= FILE_FLAG;            break;
  350. X
  351. X           case 'd':
  352. X           case 'D': modifier_list |= DIRECTORY_FLAG;         break;
  353. X
  354. X           case 'f':
  355. X           case 'F': modifier_list |= FILE_FLAG | SUFFIX_FLAG; break;
  356. X
  357. X           case 'S':
  358. X           case 's':
  359. X          if( modifier_list ) {
  360. X             Warning( "Edit modifier must appear alone, ignored");
  361. X             modifier_list = 0;
  362. X          }
  363. X          else {
  364. X             separator = *s++;
  365. X             for( p=s; *p != separator && *p != edelim; p++ );
  366. X
  367. X             if( *p == edelim )
  368. X                Warning("Syntax error in edit pattern, ignored");
  369. X             else {
  370. X            char *t1, *t2;
  371. X            pat1 = _substr( s, p );
  372. X            for(s=p=p+1; (*p != separator) && (*p != edelim); p++ );
  373. X            pat2 = _substr( s, p );
  374. X            t1 = Expand(pat1); FREE(pat1);
  375. X            t2 = Expand(pat2); FREE(pat2);
  376. X            result = Apply_edit( result, t1, t2, TRUE, FALSE );
  377. X            FREE( t1 );
  378. X            FREE( t2 );
  379. X             }
  380. X             s = p;
  381. X          }
  382. X          /* find the end of the macro spec, or the start of a new
  383. X           * modifier list for further processing of the result */
  384. X
  385. X          for( ; (*s != edelim) && (*s != ':'); s++ );
  386. X          if( *s == ':' ) s++;
  387. X          break;
  388. X
  389. X           case 'T':
  390. X           case 't':
  391. X          if( modifier_list ) {
  392. X             Warning( "Tokenize modifier must appear alone, ignored");
  393. X             modifier_list = 0;
  394. X          }
  395. X          else {
  396. X             char *msg = "Separator string must be quoted";
  397. X
  398. X             separator = *s++;
  399. X
  400. X             if( separator != '\"' )
  401. X            Warning( msg );
  402. X             else {
  403. X            /* we change the semantics to allow $(v:t")") */
  404. X            for (p = s; *p && *p != separator; p++)
  405. X               if (*p == '\\')
  406. X                  if (p[1] == '\\' || p[1] == '"')
  407. X                 p++;
  408. X            if( *p == 0 )
  409. X               Fatal( "Unterminated separator string" );
  410. X            else {
  411. X               pat1 = _substr( s, p );
  412. X               result = Tokenize( result, pat1 );
  413. X               FREE( pat1 );
  414. X            }
  415. X            s = p;
  416. X             }
  417. X
  418. X             /* find the end of the macro spec, or the start of a new
  419. X              * modifier list for further processing of the result */
  420. X
  421. X             for( ; (*s != edelim) && (*s != ':'); s++ );
  422. X             if( *s == ':' ) s++;
  423. X          }
  424. X          break;
  425. X
  426. X           case ':':
  427. X          if( modifier_list ) {
  428. X             result = Apply_modifiers( modifier_list, result );
  429. X             modifier_list = 0;
  430. X          }
  431. X          break;
  432. X
  433. X           default:
  434. X          Warning( "Illegal modifier in macro, ignored" );
  435. X          break;
  436. X        }
  437. X     }
  438. X
  439. X      if( modifier_list ) /* apply modifier */
  440. X         result = Apply_modifiers( modifier_list, result );
  441. X      
  442. X      s++;
  443. X   }
  444. X
  445. X   *ps = s;
  446. X   FREE( macro_name );
  447. X   DB_RETURN( result );
  448. }
  449. X
  450. X
  451. static char*
  452. _scan_brace( s, ps, flag )/*
  453. ============================
  454. X      This routine scans for { token_list } pairs.  It expands the value of
  455. X      token_list by calling Expand on it.  Token_list may be anything at all.
  456. X      Note that the routine count's ballanced parentheses.  This means you
  457. X      cannot have something like { fred { joe }, if that is what you really
  458. X      need the write it as { fred {{ joe }, flag is set to 1 if all ok
  459. X      and to 0 if the braces were unballanced. */
  460. X      
  461. char *s;
  462. char **ps;
  463. int  *flag;
  464. {
  465. X   char *t;
  466. X   char *start;
  467. X   char *res;
  468. X   int  lev  = 1;
  469. X   int  done = 0;
  470. X   
  471. X   DB_ENTER( "_scan_brace" );
  472. X
  473. X   start = s;
  474. X   while( !done )
  475. X      switch( *s++ ) {
  476. X         case '{': 
  477. X            if( *s == '{' ) break;              /* ignore {{ */
  478. X            lev++;
  479. X            break;
  480. X            
  481. X         case '}': 
  482. X            if( *s == '}' ) break;              /* ignore }} */
  483. X        if( lev )
  484. X           if( --lev == 0 ) done = TRUE;
  485. X        break;
  486. X
  487. X     case '$':
  488. X        if( *s == '{' || *s == '}' ) {
  489. X          if( (t = strchr(s,'}')) != NIL(char) )
  490. X             s = t;
  491. X          s++;
  492. X        }
  493. X        break;
  494. X         
  495. X         case '\0':
  496. X        if( lev ) {
  497. X           done = TRUE;
  498. X           s--;
  499. X           /* error malformed macro expansion */
  500. X        }
  501. X        break;
  502. X      }
  503. X
  504. X   start = _substr( start, (lev) ? s : s-1 );
  505. X
  506. X   if( lev ) {
  507. X      /* Braces were not ballanced so just return the string.
  508. X       * Do not expand it. */
  509. X       
  510. X      res   = _strjoin( "{", start, -1, FALSE );
  511. X      *flag = 0;
  512. X   }
  513. X   else {
  514. X      *flag = 1;
  515. X      res   = Expand( start );
  516. X
  517. X      if( (t = _strspn( res, " \t" )) != res ) strcpy( res, t );
  518. X   }
  519. X
  520. X   FREE( start );       /* this is ok! start is assigned a _substr above */
  521. X   *ps = s;
  522. X
  523. X   DB_RETURN( res );
  524. }
  525. X
  526. X
  527. static char*
  528. _cross_prod( x, y )/*
  529. =====================
  530. X      Given two strings x and y compute the cross-product of the tokens found
  531. X      in each string.  ie. if x = "a b" and y = "c d" return "ac ad bc bd".
  532. X
  533. X         NOTE:  buf will continue to grow until it is big enough to handle
  534. X                all cross product requests.  It is never freed!  (maybe I
  535. X            will fix this someday) */
  536. X      
  537. char *x;
  538. char *y;
  539. {
  540. X   static char *buf;
  541. X   static int  buf_siz = 0;
  542. X   char *brkx;
  543. X   char *brky;
  544. X   char *cy;
  545. X   char *cx;
  546. X   char *res;
  547. X   int  i;
  548. X
  549. X   if( *x && *y ) {
  550. X      res = _strdup( "" ); cx = x;
  551. X      while( *cx ) {
  552. X     cy = y;
  553. X         brkx = _strpbrk( cx, " \t\n" );
  554. X     if( (brkx-cx == 2) && *cx == '\"' && *(cx+1) == '\"' ) cx = brkx;
  555. X
  556. X     while( *cy ) {
  557. X        brky = _strpbrk( cy, " \t\n" );
  558. X        if( (brky-cy == 2) && *cy == '\"' && *(cy+1) == '\"' ) cy = brky;
  559. X        i    = brkx-cx + brky-cy + 2;
  560. X
  561. X        if( i > buf_siz ) {        /* grow buf to the correct size */
  562. X           if( buf != NIL(char) ) FREE( buf );
  563. X           if( (buf = MALLOC( i, char )) == NIL(char))  No_ram();
  564. X           buf_siz = i;
  565. X        }
  566. X
  567. X        strncpy( buf, cx, (i = brkx-cx) );
  568. X        buf[i] = '\0';
  569. X        if (brky-cy > 0) strncat( buf, cy, brky-cy );
  570. X        buf[i+(brky-cy)] = '\0';
  571. X        strcat( buf, " " );
  572. X        res = _strjoin( res, buf, -1, TRUE );
  573. X        cy = _strspn( brky, " \t\n" );
  574. X     }
  575. X     cx = _strspn( brkx, " \t\n" );
  576. X      }
  577. X
  578. X      FREE( x );
  579. X      res[ strlen(res)-1 ] = '\0';
  580. X   }
  581. X   else
  582. X      res = _strjoin( x, y, -1, TRUE );
  583. X
  584. X   FREE( y );
  585. X   return( res );
  586. }
  587. SHAR_EOF
  588. chmod 0640 dmake/expand.c ||
  589. echo 'restore of dmake/expand.c failed'
  590. Wc_c="`wc -c < 'dmake/expand.c'`"
  591. test 25368 -eq "$Wc_c" ||
  592.     echo 'dmake/expand.c: original size 25368, current size' "$Wc_c"
  593. rm -f _shar_wnt_.tmp
  594. fi
  595. # ============= dmake/extern.h ==============
  596. if test -f 'dmake/extern.h' -a X"$1" != X"-c"; then
  597.     echo 'x - skipping dmake/extern.h (File already exists)'
  598.     rm -f _shar_wnt_.tmp
  599. else
  600. > _shar_wnt_.tmp
  601. sed 's/^X//' << 'SHAR_EOF' > 'dmake/extern.h' &&
  602. /* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/extern.h,v 1.1 91/05/06 15:23:13 dvadura Exp $
  603. -- SYNOPSIS -- external declarations for dmake functions.
  604. -- 
  605. -- DESCRIPTION
  606. --    ANSI is a macro that allows the proper handling of ANSI style
  607. --    function declarations.
  608. -- 
  609. -- AUTHOR
  610. --      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
  611. --      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
  612. --
  613. -- COPYRIGHT
  614. --      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
  615. -- 
  616. --      This program is free software; you can redistribute it and/or
  617. --      modify it under the terms of the GNU General Public License
  618. --      (version 1), as published by the Free Software Foundation, and
  619. --      found in the file 'LICENSE' included with this distribution.
  620. -- 
  621. --      This program is distributed in the hope that it will be useful,
  622. --      but WITHOUT ANY WARRANTY; without even the implied warrant of
  623. --      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  624. --      GNU General Public License for more details.
  625. -- 
  626. --      You should have received a copy of the GNU General Public License
  627. --      along with this program;  if not, write to the Free Software
  628. --      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  629. --
  630. -- LOG
  631. --     $Log:    extern.h,v $
  632. X * Revision 1.1  91/05/06  15:23:13  dvadura
  633. X * dmake Release Version 3.7
  634. X * 
  635. */
  636. X
  637. #ifndef EXTERN_h
  638. #define EXTERN_h
  639. X
  640. /* Define this for the RS/6000 if it breaks something then we have to put a
  641. X * #ifdef around it. */
  642. #if defined(rs6000)
  643. #define _POSIX_SOURCE
  644. #endif
  645. X
  646. #include <stdio.h>
  647. #include <string.h>
  648. #include <ctype.h>
  649. #include <stdlib.h>
  650. #include <stdarg.h>
  651. #include <sys/types.h>
  652. #include <sys/stat.h>
  653. #include <signal.h>
  654. #include "itypes.h"
  655. #include "stdmacs.h"
  656. #include "alloc.h"
  657. #include "db.h"
  658. #include "dmake.h"
  659. #include "struct.h"
  660. #include "vextern.h"
  661. #include "public.h"
  662. X
  663. /* Include this last as it invalidates some functions that are defined
  664. X * externally above and turns them into no-ops.  Have to do this after
  665. X * the extern declarations however. */
  666. #include "config.h"
  667. X
  668. #endif
  669. X
  670. SHAR_EOF
  671. chmod 0640 dmake/extern.h ||
  672. echo 'restore of dmake/extern.h failed'
  673. Wc_c="`wc -c < 'dmake/extern.h'`"
  674. test 2089 -eq "$Wc_c" ||
  675.     echo 'dmake/extern.h: original size 2089, current size' "$Wc_c"
  676. rm -f _shar_wnt_.tmp
  677. fi
  678. # ============= dmake/function.c ==============
  679. if test -f 'dmake/function.c' -a X"$1" != X"-c"; then
  680.     echo 'x - skipping dmake/function.c (File already exists)'
  681.     rm -f _shar_wnt_.tmp
  682. else
  683. > _shar_wnt_.tmp
  684. sed 's/^X//' << 'SHAR_EOF' > 'dmake/function.c' &&
  685. /* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/function.c,v 1.1 91/05/06 15:23:14 dvadura Exp $
  686. -- SYNOPSIS -- GNU style functions for dmake.
  687. -- 
  688. -- DESCRIPTION
  689. --     All GNU stule functions understood by dmake are implemented in this
  690. --    file.  Currently the only such function is $(mktmp ...) which is
  691. --    not part of GNU-make is an extension provided by dmake.
  692. --
  693. -- AUTHOR
  694. --      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
  695. --      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
  696. --
  697. -- COPYRIGHT
  698. --      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
  699. -- 
  700. --      This program is free software; you can redistribute it and/or
  701. --      modify it under the terms of the GNU General Public License
  702. --      (version 1), as published by the Free Software Foundation, and
  703. --      found in the file 'LICENSE' included with this distribution.
  704. -- 
  705. --      This program is distributed in the hope that it will be useful,
  706. --      but WITHOUT ANY WARRANTY; without even the implied warrant of
  707. --      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  708. --      GNU General Public License for more details.
  709. -- 
  710. --      You should have received a copy of the GNU General Public License
  711. --      along with this program;  if not, write to the Free Software
  712. --      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  713. --
  714. -- LOG
  715. --     $Log:    function.c,v $
  716. X * Revision 1.1  91/05/06  15:23:14  dvadura
  717. X * dmake Release Version 3.7
  718. X * 
  719. */
  720. X
  721. #include "extern.h"
  722. X
  723. static char *_exec_mktmp  ANSI((char *, char *, char *));
  724. static char *_exec_subst  ANSI((char *, char *, char *));
  725. static char *_exec_iseq   ANSI((char *, char *, char *, int));
  726. static char *_exec_sort   ANSI((char *));
  727. static char *_exec_shell  ANSI((char *));
  728. static int   _mystrcmp    ANSI((CONST void *, CONST void *));
  729. X
  730. X
  731. PUBLIC char *
  732. Exec_function(buf)/*
  733. ====================
  734. X   Execute the function given by the value of args.
  735. X
  736. X   So far mktmp is the only valid function, anything else elicits and error
  737. X   message.  It is my hope to support the GNU style functions in this portion
  738. X   of the code at some time in the future. */
  739. char *buf;
  740. {
  741. X   char *fname;
  742. X   char *args;
  743. X   char *mod1;
  744. X   char *mod2 = NIL(char);
  745. X   char *res  = NIL(char);
  746. X
  747. X   /* This must succeed since the presence of ' ', \t or \n is what
  748. X    * determines if this functions is called in the first place. */
  749. X   fname = _substr(buf, args=_strpbrk(buf," \t\n"));
  750. X
  751. X   if( (mod1 = strchr(fname,',')) != NIL(char) ){
  752. X      *mod1 = '\0';
  753. X      mod1++;
  754. X
  755. X      if( (mod2 = strchr(mod1,',')) != NIL(char) ){
  756. X     *mod2 = '\0';
  757. X     mod2++;
  758. X      }
  759. X   }
  760. X
  761. X   switch( *fname ) {
  762. X      case 'e':
  763. X     if(strncmp(fname,"eq",2) == 0) res = _exec_iseq(mod1,mod2,args,TRUE);
  764. X     break;
  765. X
  766. X      case 'm':
  767. X     if( strncmp(fname,"mktmp", 5) == 0 ) res = _exec_mktmp(mod1,mod2,args);
  768. X     break;
  769. X
  770. X      case 'n':
  771. X     if( strncmp(fname,"null", 4) == 0 )
  772. X        res = _exec_iseq(mod1,NIL(char),args,TRUE);
  773. X     break;
  774. X
  775. X      case '!':
  776. X     if(strncmp(fname,"!null",5) == 0)
  777. X        res = _exec_iseq(mod1,NIL(char),args,FALSE);
  778. X     if(strncmp(fname,"!eq",3) == 0) res = _exec_iseq(mod1,mod2,args,FALSE);
  779. X     break;
  780. X
  781. X      case 's':
  782. X     if(strncmp(fname,"sort",4) == 0) res = _exec_sort(args);
  783. X     else if(strncmp(fname,"shell",5)==0) res = _exec_shell(args);
  784. X     else if(strncmp(fname,"strip",5)==0) res = Tokenize(Expand(args)," ");
  785. X     else if(strncmp(fname,"subst",5)==0) res = _exec_subst(mod1,mod2,args);
  786. X     break;
  787. X
  788. X      default:
  789. X     Warning( "Function '%s' not implemented at this time", fname );
  790. X   }
  791. X
  792. X   if( res == NIL(char) ) res = _strdup("");
  793. X
  794. X   FREE(fname);
  795. X   return(res);
  796. }
  797. X
  798. X
  799. static char *
  800. _exec_mktmp( file, text, data )
  801. char *file;
  802. char *text;
  803. char *data;
  804. {
  805. X   register char *p;
  806. X   char *tmpname;
  807. X   char *name;
  808. X   FILE *tmpfile = NIL(FILE);
  809. X
  810. X   /* This is only a test of the recipe line so prevent the tempfile side
  811. X    * effects. */
  812. X   if( Suppress_temp_file ) return(NIL(char));
  813. X
  814. X   name = Current_target ? Current_target->CE_NAME:"makefile text";
  815. X
  816. X   if( file && *file ) {
  817. X      char *newtmp;
  818. X
  819. X      /* This call to Get_temp sets TMPFILE for subsequent expansion of file.
  820. X       * DO NOT DELETE IT! */
  821. X      Get_temp( &newtmp, "", FALSE ); FREE(newtmp);
  822. X      tmpname = Expand(file);
  823. X
  824. X      if( *tmpname ) {
  825. X     if( (tmpfile = fopen(tmpname, "w")) == NIL(FILE) )
  826. X        Open_temp_error( tmpname, name );
  827. X
  828. X     Def_macro("TMPFILE", tmpname, M_EXPANDED|M_MULTI);
  829. X     Link_temp( Current_target, tmpfile, tmpname );
  830. X      }
  831. X      else
  832. X     FREE(tmpname);
  833. X   }
  834. X
  835. X   if( !tmpfile )
  836. X      tmpfile = Start_temp( "", Current_target, &tmpname );
  837. X
  838. X   if( !text || !*text ) text = tmpname;
  839. X   data = Expand(_strspn(data, " \t\n"));
  840. X
  841. X   for(p=strchr(data,'\n'); p; p=strchr(p,'\n')) {
  842. X      char *q = _strspn(++p," \t");
  843. X      strcpy(p,q);
  844. X   }
  845. X
  846. X   Append_line( data, FALSE, tmpfile, name, FALSE, TRUE );
  847. X   Close_temp( Current_target, tmpfile );
  848. X   FREE(data);
  849. X
  850. X   return( Expand(text) );
  851. }
  852. X
  853. X
  854. static char *
  855. _exec_iseq( lhs, rhs, data, eq )
  856. char *lhs;
  857. char *rhs;
  858. char *data;
  859. int  eq;
  860. {
  861. X   char *l = Expand(lhs);
  862. X   char *r = Expand(rhs);
  863. X   char *i = _strspn(data, " \t\n");
  864. X   char *e = strchr(i, ' ');
  865. X   char *res = NIL(char);
  866. X   int  val = strcmp(l,r);
  867. X
  868. X   if( (!val && eq) || (val && !eq) ) {
  869. X      if( e != NIL(char) ) *e = '\0';
  870. X      res = Expand(i);
  871. X   }
  872. X   else if( e != NIL(char) ) {
  873. X      e = _strspn(e," \t\n");
  874. X      if( *e ) res = Expand(e);
  875. X   }
  876. X
  877. X   FREE(l);
  878. X   FREE(r);
  879. X   return(res);
  880. }
  881. X
  882. X
  883. static char *
  884. _exec_sort( args )
  885. char *args;
  886. {
  887. X   char *res  = NIL(char);
  888. X   char *data = Expand(args);
  889. X   char **tokens = NIL(char *);
  890. X   char *p;
  891. X   char *white = " \t\n";
  892. X   int  j;
  893. X   int  i = 0;
  894. X
  895. X   for( i=0,p=_strspn(data,white); *p; p=_strspn(_strpbrk(p,white),white),i++); 
  896. X
  897. X   if( i != 0 ) {
  898. X      TALLOC(tokens, i, char *);
  899. X
  900. X      for( i=0,p=_strspn(data,white); *p; p=_strspn(p,white),i++){
  901. X     tokens[i] = p;
  902. X     p = _strpbrk(p,white);
  903. X     if( *p ) *p++ = '\0';
  904. X      }
  905. X
  906. X      qsort( tokens, i-1, sizeof(char *), _mystrcmp );
  907. X
  908. X      for( j=0; j<i; j++ ) res = _strapp(res, tokens[j]);
  909. X      FREE(data);
  910. X      FREE(tokens);
  911. X   }
  912. X
  913. X   return(res);
  914. }
  915. X
  916. X
  917. static int
  918. _mystrcmp( p, q )
  919. CONST void *p;
  920. CONST void *q;
  921. {
  922. X   return(strcmp(*((CONST char **)p),*((CONST char **)q)));
  923. }
  924. X
  925. X
  926. static char *
  927. _exec_subst( pat, subst, data )
  928. char *pat;
  929. char *subst;
  930. char *data;
  931. {
  932. X   char *res;
  933. X
  934. X   pat = Expand(pat);
  935. X   subst = Expand(subst);
  936. X   res = Apply_edit( Expand(data), pat, subst, TRUE, FALSE );
  937. X   FREE(pat);
  938. X   FREE(subst);
  939. X
  940. X   return(res);
  941. }
  942. X
  943. X
  944. static char *
  945. _exec_shell( data )
  946. char *data;
  947. {
  948. X   extern char *tempnam();
  949. X   int wait  = Wait_for_completion;
  950. X   char *res = NIL(char);
  951. X   int free_buf = FALSE;
  952. X   char *buffer;
  953. X   int out;
  954. X   int err;
  955. X   FILE *tmp;
  956. X   char *tmpnm;
  957. X   CELL cell;
  958. X   STRING rcp;
  959. X   HASH   cname;
  960. X
  961. X   if( Suppress_temp_file ) return(NIL(char));
  962. X
  963. X   /* Set the temp CELL used for building prerequisite candidates to
  964. X    * all zero so that we don't have to keep initializing all the
  965. X    * fields. */
  966. X   {
  967. X      register char *s = (char *) &cell;
  968. X      register int   n = sizeof(CELL);
  969. X      while( n ) { *s++ = '\0'; n--; }
  970. X   }
  971. X   rcp.st_string  = _strspn(data, " \t+-%@");
  972. X   rcp.st_attr    = Rcp_attribute( data );
  973. X   rcp.st_next    = NIL(STRING);
  974. X   cname.ht_name  = "Shell escape";
  975. X   cell.ce_name   = &cname;
  976. X   cell.ce_fname  = cname.ht_name;
  977. X   cell.ce_recipe = &rcp;
  978. X   cell.ce_flag   = F_TARGET|F_RULES;
  979. X   cell.ce_attr   = A_PHONY|A_SILENT;
  980. X
  981. X   tmpnm = tempnam(NIL(char),"mk");
  982. X   out = dup( 1 );
  983. X   if( (tmp = fopen(tmpnm, "w")) == NIL(FILE) )
  984. X      Open_temp_error( tmpnm, cname.ht_name );
  985. X
  986. X   Wait_for_completion = TRUE;
  987. X   close( 1 );
  988. X   dup( fileno(tmp) );
  989. X   fclose( tmp );
  990. X   Exec_commands( &cell );
  991. X   close(1);
  992. X   dup(out);
  993. X   close(out);
  994. X
  995. X   /* Now we have to read the temporary file, get the tokens and return them
  996. X    * as a string. */
  997. X   if( (tmp = fopen(tmpnm, "r")) == NIL(FILE) )
  998. X      Open_temp_error( tmpnm, cname.ht_name );
  999. X
  1000. X   if( Buffer == NIL(char) ) {
  1001. X      Buffer_size = BUFSIZ-2;
  1002. X      buffer = MALLOC(BUFSIZ-2,char);
  1003. X      free_buf = TRUE;
  1004. X   }
  1005. X   else
  1006. X      buffer = Buffer;
  1007. X
  1008. X   while( fgets(buffer, Buffer_size, tmp) ) {
  1009. X      char *p = strchr(buffer, '\n');
  1010. X
  1011. X      if( p == NIL(char) )
  1012. X     res = _strjoin(res,buffer,-1,TRUE);
  1013. X      else {
  1014. X     *p = '\0';
  1015. X         res = _strapp(res,buffer);
  1016. X      }
  1017. X   }
  1018. X
  1019. X   fclose(tmp);
  1020. X   unlink(tmpnm);
  1021. X   FREE(tmpnm);
  1022. X   if( free_buf ) FREE(buffer);
  1023. X
  1024. X   Wait_for_completion = wait;
  1025. X   return(res);
  1026. }
  1027. SHAR_EOF
  1028. chmod 0640 dmake/function.c ||
  1029. echo 'restore of dmake/function.c failed'
  1030. Wc_c="`wc -c < 'dmake/function.c'`"
  1031. test 8398 -eq "$Wc_c" ||
  1032.     echo 'dmake/function.c: original size 8398, current size' "$Wc_c"
  1033. rm -f _shar_wnt_.tmp
  1034. fi
  1035. # ============= dmake/getinp.c ==============
  1036. if test -f 'dmake/getinp.c' -a X"$1" != X"-c"; then
  1037.     echo 'x - skipping dmake/getinp.c (File already exists)'
  1038.     rm -f _shar_wnt_.tmp
  1039. else
  1040. > _shar_wnt_.tmp
  1041. sed 's/^X//' << 'SHAR_EOF' > 'dmake/getinp.c' &&
  1042. /* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/getinp.c,v 1.1 91/05/06 15:23:15 dvadura Exp $
  1043. -- SYNOPSIS -- handle reading of input.
  1044. -- 
  1045. -- DESCRIPTION
  1046. --    The code in this file reads the input from the specified stream
  1047. --    into the provided buffer of size Buffer_size.  In doing so it deletes
  1048. --    comments.  Comments are delimited by the #, and
  1049. --    <nl> character sequences.  An exception is \# which
  1050. --    is replaced by # in the input.  Line continuations are signalled
  1051. --    at the end of a line and are recognized inside comments.
  1052. --    The line continuation is always  <\><nl>.
  1053. --
  1054. --    If the file to read is NIL(FILE) then the Get_line routine returns the
  1055. --    next rule from the builtin rule table if there is one.
  1056. --
  1057. -- AUTHOR
  1058. --      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
  1059. --      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
  1060. --
  1061. -- COPYRIGHT
  1062. --      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
  1063. -- 
  1064. --      This program is free software; you can redistribute it and/or
  1065. --      modify it under the terms of the GNU General Public License
  1066. --      (version 1), as published by the Free Software Foundation, and
  1067. --      found in the file 'LICENSE' included with this distribution.
  1068. -- 
  1069. --      This program is distributed in the hope that it will be useful,
  1070. --      but WITHOUT ANY WARRANTY; without even the implied warrant of
  1071. --      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1072. --      GNU General Public License for more details.
  1073. -- 
  1074. --      You should have received a copy of the GNU General Public License
  1075. --      along with this program;  if not, write to the Free Software
  1076. --      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  1077. --
  1078. -- LOG
  1079. --     $Log:    getinp.c,v $
  1080. X * Revision 1.1  91/05/06  15:23:15  dvadura
  1081. X * dmake Release Version 3.7
  1082. X * 
  1083. */
  1084. X
  1085. #include "extern.h"
  1086. X
  1087. #define IS_WHITE(A)  ((A == ' ') || (A == '\t') || (A == '\n') || (A == '\r'))
  1088. #define SCAN_WHITE(A) \
  1089. X    while( IS_WHITE(*A) ) A++;
  1090. X
  1091. static    int    _is_conditional ANSI((char*));
  1092. static    int    _handle_conditional ANSI((int, TKSTRPTR));
  1093. X
  1094. static int  rule_ind = 0;    /* index of rule when reading Rule_tab     */
  1095. static int  skip = FALSE;    /* if true the skip input         */
  1096. X
  1097. X
  1098. PUBLIC int
  1099. Get_line( buf, fil )/*
  1100. ======================
  1101. X        Read a line of input from the file stripping
  1102. X        off comments.  The routine returns TRUE if EOF */
  1103. char *buf;
  1104. FILE *fil;
  1105. {
  1106. X   extern   char **Rule_tab;
  1107. X   register char *p;
  1108. X   register char *c;
  1109. X   char      *q;
  1110. X   char             *buf_org;
  1111. X   static   int     ignore = FALSE;
  1112. X   int          cont   = FALSE;
  1113. X   int          pos    = 0;
  1114. X   int         res;
  1115. X
  1116. X   DB_ENTER( "Get_line" );
  1117. X
  1118. X   if( fil == NIL(FILE) ) {
  1119. X      /* Reading the internal rule table.  Set the rule_index to zero.
  1120. X       * This way ReadEnvironment works as expected every time. */
  1121. X
  1122. X      while( (p = Rule_tab[ rule_ind++ ]) != NIL(char) )
  1123. X     /* The last test in this if '*p != '~', handles the environment
  1124. X      * passing conventions used by MKS to pass arguments.  We want to
  1125. X      * skip those environment entries. */
  1126. X     if( !Readenv || (Readenv && (strchr(p,'=') != NIL(char)) && *p!='~')){
  1127. X        strcpy( buf, p );
  1128. X
  1129. X        DB_PRINT( "io", ("Returning [%s]", buf) );
  1130. X        DB_RETURN( FALSE );
  1131. X     }
  1132. X
  1133. X      rule_ind = 0;
  1134. X
  1135. X      DB_PRINT( "io", ("Done Ruletab") );
  1136. X      DB_RETURN( TRUE );
  1137. X   }
  1138. X
  1139. X   buf_org = buf;
  1140. X
  1141. do_again:
  1142. X   do {
  1143. X      p = buf+pos;
  1144. X      if(feof( fil ) || (fgets( p, Buffer_size-pos, fil ) == NIL(char)))
  1145. X     DB_RETURN( TRUE );
  1146. X
  1147. X      Line_number++;
  1148. X
  1149. X      /* ignore input if ignore flag set and line ends in a continuation
  1150. X     character. */
  1151. X
  1152. X      q = p+strlen(p)-2;
  1153. X      /* ignore each RETURN at the end of a line before any further
  1154. X       * processing */
  1155. X      if( q[0] == '\r' && q[1] == '\n' ) {
  1156. X     q[0] = '\n';
  1157. X     q[1] = '\0';
  1158. X     q--;
  1159. X      }
  1160. X      /* you also have to deal with END_OF_FILE chars to process raw
  1161. X       * DOS-Files. Normally they are the last chars in file, but after
  1162. X       * working on these file with vi, there is an additional NEWLINE
  1163. X       * after the last END_OF_FILE. So if the second last char in the
  1164. X       * actual line is END_OF_FILE, you can skip the last char. Then
  1165. X       * you can search the line back until you find no more END_OF_FILE
  1166. X       * and nuke each you found by string termination. */
  1167. X      if( q[0] == '\032' )
  1168. X     q--;
  1169. X      while( q[1] == '\032' ) {
  1170. X     q[1] = '\0';
  1171. X     q--;
  1172. X      }
  1173. X
  1174. X      if( ignore ) {
  1175. X     if( q[0] != CONTINUATION_CHAR || q[1] != '\n' )  ignore = FALSE;
  1176. X     *p = '\0';
  1177. X     continue;
  1178. X      }
  1179. X
  1180. X      c = Do_comment(p, &q, Group || (*buf == '\t'));
  1181. X      
  1182. X      /* Does the end of the line end in a continuation sequence? */
  1183. X      
  1184. X      if( (q[0] == CONTINUATION_CHAR) && (q[1] == '\n')) {
  1185. X     /* If the continuation was at the end of a comment then ignore the
  1186. X      * next input line, (or lines until we get one ending in just <nl>)
  1187. X      * else it's a continuation, so build the input line from several
  1188. X      * text lines on input.  The maximum size of this is governened by
  1189. X      * Buffer_size */
  1190. X     if( q != p && q[-1] == CONTINUATION_CHAR ) {
  1191. X        strcpy( q, q+1 );
  1192. X        q--;
  1193. X        cont = FALSE;
  1194. X     }
  1195. X     else if( c != NIL(char) )
  1196. X        ignore = TRUE;
  1197. X     else
  1198. X        cont   = TRUE;
  1199. X      }
  1200. X      else {
  1201. X     cont = FALSE;
  1202. X      }
  1203. X
  1204. X      q    = ( c == NIL(char) ) ? q+2 : c;
  1205. X      pos += q-p;
  1206. X   }
  1207. X   while( (cont || !*buf) && (pos <= Buffer_size) );
  1208. X
  1209. X   if( buf[ pos-1 ] == '\n' )
  1210. X      buf[ --pos ] = '\0';
  1211. X   else
  1212. X      if( pos == Buffer_size-1 )
  1213. X     Fatal( "Input line too long, increase MAXLINELENGTH" );
  1214. X
  1215. X
  1216. X   /* Now that we have the next line of input to make, we should check to
  1217. X    * see if it is a conditional expression.  If it is then process it,
  1218. X    * otherwise pass it on to the parser. */
  1219. X
  1220. X   if( *(p = _strspn(buf, " \t\r\n")) == CONDSTART ) {
  1221. X      TKSTR token;
  1222. X
  1223. X      SET_TOKEN( &token, p );
  1224. X
  1225. X      p = Get_token( &token, "", FALSE );
  1226. X
  1227. X      if( (res = _is_conditional( p )) )    /* ignore non control special */
  1228. X      {                        /* targets               */
  1229. X     res  = _handle_conditional( res, &token );
  1230. X     skip = TRUE;
  1231. X      }
  1232. X      else {
  1233. X     CLEAR_TOKEN( &token );
  1234. X     res  = TRUE;
  1235. X      }
  1236. X   }
  1237. X
  1238. X   if( skip ) {
  1239. X      buf  = buf_org;        /* ignore line just read in */
  1240. X      pos  = 0;
  1241. X      skip = res;
  1242. X      goto do_again;
  1243. X   }
  1244. X
  1245. X   DB_PRINT( "io", ("Returning [%s]", buf) );
  1246. X   DB_RETURN( FALSE );
  1247. }
  1248. X
  1249. X
  1250. PUBLIC char *
  1251. Do_comment(str, pend, keep)/*
  1252. =============================
  1253. X   Search the input string looking for comment chars.  If it contains
  1254. X   comment chars then NUKE the remainder of the line, if the comment
  1255. X   char is preceeded by \ then shift the remainder of the line left
  1256. X   by one char. */
  1257. char *str;
  1258. char **pend;
  1259. int  keep;
  1260. {
  1261. X   char *c = str;
  1262. X
  1263. X   while( (c = strchr(c, COMMENT_CHAR)) != NIL(char) ) {
  1264. X      if( Comment || State == NORMAL_SCAN )
  1265. X     if( c != str && c[-1] == ESCAPE_CHAR ) {
  1266. X        strcpy( c-1, c );        /* copy it left, due to \# */
  1267. X        if( pend ) (*pend)--;    /* shift tail pointer left */
  1268. X     }
  1269. X     else {
  1270. X        *c = '\0';               /* a true comment so break */
  1271. X        break;
  1272. X     }
  1273. X      else {
  1274. X         if( keep )
  1275. X        c = NIL(char);
  1276. X     else
  1277. X        *c = '\0';
  1278. X
  1279. X     break;
  1280. X      }
  1281. X   }
  1282. X
  1283. X   return(c);
  1284. }
  1285. X      
  1286. X
  1287. PUBLIC char *
  1288. Get_token( string, brk, anchor )/*
  1289. ==================================
  1290. X    Return the next token in string.
  1291. X    Returns empty string when no more tokens in string.
  1292. X    brk is a list of chars that also cause breaks in addition to space and
  1293. X    tab, but are themselves returned as tokens.  if brk is NULL then the
  1294. X    remainder of the line is returned as a single token.
  1295. X    
  1296. X    anchor if TRUE, says break on chars in the brk list, but only if
  1297. X    the entire token begins with the first char of the brk list, if
  1298. X    FALSE then any char of brk will cause a break to occurr. */
  1299. X
  1300. TKSTRPTR  string;
  1301. char      *brk;
  1302. int      anchor;
  1303. {
  1304. X   register char *s;
  1305. X   register char *curp;
  1306. X   register char *t;
  1307. X   int           done = FALSE;
  1308. X   char          space[10];
  1309. X
  1310. X   DB_ENTER( "Get_token" );
  1311. X
  1312. X   s  = string->tk_str;              /* Get string parameters    */
  1313. X   *s = string->tk_cchar;          /* ... and strip leading w/s    */
  1314. X
  1315. X   SCAN_WHITE( s );
  1316. X
  1317. X   DB_PRINT( "tok", ("What's left [%s]", s) );
  1318. X
  1319. X   if( !*s ) {
  1320. X      DB_PRINT( "tok", ("Returning NULL token") );
  1321. X      DB_RETURN( "" );
  1322. X   }
  1323. X
  1324. X
  1325. X   /* Build the space list.  space contains all those chars that may possibly
  1326. X    * cause breaks.  This includes the brk list as well as white space. */
  1327. X
  1328. X   if( brk != NIL(char) ) {
  1329. X      strcpy( space, " \t\r\n" );
  1330. X      strcat( space, brk   );
  1331. X   }
  1332. X   else {
  1333. X      space[0] = 0xff;            /* a char we know will not show up      */
  1334. X      space[1] = 0;
  1335. X   }
  1336. X
  1337. X
  1338. X   /* Handle processing of quoted tokens.  Note that this is disabled if
  1339. X    * brk is equal to NIL */
  1340. X
  1341. X   while( *s == '\"' && ((brk != NIL(char)) || !string->tk_quote) ) {
  1342. X      s++;
  1343. X      if( string->tk_quote ) {
  1344. X     curp = s-1;
  1345. X     do { curp = strchr( curp+1, '\"' ); }
  1346. X     while( (curp != NIL(char)) && (*(curp+1) == '\"'));
  1347. X
  1348. X         if( curp == NIL(char) ) Fatal( "Unmatched quote in token" );
  1349. X     string->tk_quote = !string->tk_quote;
  1350. X
  1351. X     /* Check for "" case, and if found ignore it */
  1352. X     if( curp == s ) continue;
  1353. X     goto found_token;
  1354. X      }
  1355. X      else
  1356. X     SCAN_WHITE( s );
  1357. X
  1358. X      string->tk_quote = !string->tk_quote;
  1359. X   }
  1360. X   
  1361. X
  1362. X   /* Check for a token break character at the beginning of the token.
  1363. X    * If found return the next set of break chars as a token. */
  1364. X
  1365. X   if( (brk != NIL(char)) && (strchr( brk, *s ) != NIL(char)) ) {
  1366. X      curp = _strspn( s, brk );
  1367. X      done = (anchor == 0) ? TRUE :
  1368. X         ((anchor == 1)?(*s == *brk) : (*brk == curp[-1]));
  1369. X   }
  1370. X
  1371. X
  1372. X   /* Scan for the next token in the list and return it less the break char
  1373. X    * that was used to terminate the token.  It will possibly be returned in
  1374. X    * the next call to Get_token */
  1375. X
  1376. X   if( !done ) {
  1377. X      SCAN_WHITE( s );
  1378. X
  1379. X      t = s;
  1380. X      do {
  1381. X     done = TRUE;
  1382. X     curp = _strpbrk(t, space);
  1383. X     
  1384. X     if( anchor && *curp && !IS_WHITE( *curp ) )
  1385. X        if( ((anchor == 1)?*curp:_strspn(curp,brk)[-1]) != *brk ) {
  1386. X           t++;
  1387. X           done = FALSE;
  1388. X        }
  1389. X      }
  1390. X      while( !done );
  1391. X
  1392. X      if( (curp == s) && (strchr(brk, *curp) != NIL(char)) ) curp++;
  1393. X   }
  1394. X
  1395. found_token:
  1396. X   string->tk_str   = curp;
  1397. X   string->tk_cchar = *curp;
  1398. X   *curp = '\0';
  1399. X
  1400. X   DB_PRINT( "tok", ("Returning [%s]", s) );
  1401. X   DB_RETURN( s );
  1402. }
  1403. X
  1404. X
  1405. static int
  1406. _is_conditional( tg )/*
  1407. =======================
  1408. X    Look at tg and return it's value if it is a conditional identifier
  1409. X    otherwise return 0. */
  1410. char *tg;
  1411. {
  1412. X   DB_ENTER( "_is_conditional" );
  1413. X   
  1414. X   tg++;
  1415. X   switch( *tg ) {
  1416. X      case 'I': if( !strcmp( tg, "IF" )) DB_RETURN( ST_IF   ); break;
  1417. X      
  1418. X      case 'E':
  1419. X         if( !strcmp( tg, "END" ))     DB_RETURN( ST_END  );
  1420. X         else if( !strcmp( tg, "ENDIF")) DB_RETURN( ST_END  );
  1421. X         else if( !strcmp( tg, "ELSE" )) DB_RETURN( ST_ELSE );
  1422. X         else if( !strcmp( tg, "ELIF" )) DB_RETURN( ST_ELIF );
  1423. X     break;
  1424. X   }
  1425. X   
  1426. X   DB_RETURN( 0 );
  1427. }
  1428. X
  1429. X
  1430. X
  1431. #define SEEN_END  0x00
  1432. #define SEEN_IF   0x01
  1433. #define SEEN_ELSE 0x02
  1434. X
  1435. static int
  1436. _handle_conditional( opcode, tg )/*
  1437. ===================================
  1438. X    Perform the necessary processing for .IF conditinal targets.
  1439. X    Someday this should be modified to do bracketted expressions ala
  1440. X    CPP... sigh */
  1441. int      opcode;
  1442. TKSTRPTR tg;
  1443. {
  1444. X   static short    action[MAX_COND_DEPTH];
  1445. X   static char  ifcntl[MAX_COND_DEPTH];
  1446. X   char     *tok, *lhs, *rhs, *op, *expr;
  1447. X   int      result;
  1448. X
  1449. X   DB_ENTER( "_handle_conditional" );
  1450. X
  1451. X   switch( opcode ) {
  1452. X      case ST_ELIF:
  1453. X         if( !(ifcntl[Nest_level] & SEEN_IF) || (ifcntl[Nest_level]&SEEN_ELSE) )
  1454. X        Fatal(".ELIF without a preceeding .IF" );
  1455. X     /* FALLTHROUGH */
  1456. X
  1457. X      case ST_IF:
  1458. X     if( opcode == ST_IF && (Nest_level+1) == MAX_COND_DEPTH )
  1459. X        Fatal( ".IF .ELSE ... .END nesting too deep" );
  1460. X
  1461. X     If_expand = TRUE;
  1462. X     expr = Expand( Get_token( tg, NIL(char), FALSE ));
  1463. X     If_expand = FALSE;
  1464. X     lhs = _strspn( expr, " \t" );
  1465. X     if( !*lhs ) lhs = NIL(char);
  1466. X
  1467. X     if( (op = _strstr( lhs, "==" )) == NIL(char) )
  1468. X        op = _strstr( lhs, "!=" );
  1469. X
  1470. X     if( op == NIL(char) )
  1471. X        result = (lhs != NIL(char));
  1472. X     else {
  1473. X        op[1] = op[0];
  1474. X        if( lhs != op ) {
  1475. X           for( tok = op-1; (tok != lhs) && ((*tok == ' ')||(*tok == '\t'));
  1476. SHAR_EOF
  1477. true || echo 'restore of dmake/getinp.c failed'
  1478. fi
  1479. echo 'End of part 9, continue with part 10'
  1480. echo 10 > _shar_seq_.tmp
  1481. exit 0
  1482.  
  1483. exit 0 # Just in case...
  1484. -- 
  1485. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1486. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1487. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1488. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1489.