home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d5xx / d523 / bmake.lha / BMake / source.lzh / expand.c < prev    next >
C/C++ Source or Header  |  1991-07-01  |  6KB  |  240 lines

  1. /*    expand.c
  2.  *    (c) Copyright 1991 by Ben Eng, All Rights Reserved
  3.  *
  4.  *    macro expansion
  5.  */
  6.  
  7. #include <clib/exec_protos.h>
  8.  
  9. #include <ctype.h>
  10.  
  11. #include "make.h"
  12. #include "depend.h"
  13.  
  14. static int expand_macros2( char *dest, char *src, int maxlen );
  15. static int expand_macros3( char *src, int maxlen );
  16.  
  17. /*    define the criterion for detecting infinitely recursive
  18.  *    macro expansions
  19.  */
  20. static int expand_level = 0;
  21. #define MAX_RECURSION    32
  22. #define MAX_ITERATION    256
  23.  
  24. static struct macro *
  25. expand_fncall( char *src, int maxlen )
  26. {
  27.     static struct macro *fnmac = NULL;
  28.     struct fncall *fc;
  29.     char fn[ 40 ], *next = src;
  30.     int addlen;
  31.  
  32.     if( fnmac) {
  33.         if( fnmac->expansion ) {
  34.             free( fnmac->expansion );
  35.             fnmac->expansion = NULL;
  36.         }
  37.     }
  38.     else if( fnmac = new_macro( NULL, NULL ))
  39.         fnmac->flags |= MF_SIMPLE;
  40.     else return( NULL );
  41.  
  42.     next = parse_str( fn, next, sizeof(fn));
  43.     if( fc = find_fncall( fn )) {
  44.         if( (*fc->call)( fnmac, next )) {
  45.             logprintf( "function call %s returned ERROR\n", fc->name );
  46.             return( NULL );
  47.         }
  48.         fnmac->flags |= MF_SIMPLE;
  49.         return( fnmac );
  50.     }
  51.     return( NULL );
  52. }
  53.  
  54. /*    expand a macro reference with only a single $(x) instance
  55.  *    handles recursive expansion
  56.  */
  57. static int
  58. expand_macros3( char *src, int maxlen )
  59. {
  60.     char *dest = NULL;
  61.     char *macroname = NULL;
  62.     char *dollar;
  63.  
  64.     dollar = strchr( src, '$' );
  65.     if( dollar ) {
  66.         struct macro *mac = NULL;
  67.         char *out, *next;
  68.          int outlen = 0;
  69.         char delimchar = (char)0;
  70.  
  71.         debugprintf( 6,( "expand_macros3(%s,%d)\n", src, maxlen ));
  72.  
  73.         /* could get away with only allocating maxlen to save memory */
  74.         macroname = (char *)malloc( Param.MaxLine );
  75.         dest = (char *)calloc( Param.MaxLine, 1 );
  76.         if( !macroname || !dest ) goto death;
  77.  
  78.         out = dest;
  79.  
  80.         memset( macroname, 0, Param.MaxLine);
  81.         for( next = src; next < dollar && outlen < maxlen; outlen++ )
  82.             *out++ = *next++;
  83.  
  84.         next = dollar + 1;
  85.         if( outlen >= maxlen ) goto death;
  86.  
  87.         if( *next == '(' ) delimchar = ')';
  88.         else if( *next == '{' ) delimchar = '}';
  89.  
  90.         if( delimchar ) { /* multi letter variable name */
  91.             char *n;
  92.             int i = 0;
  93.  
  94.             for( n = ++next; *n && i < Param.MaxLine-1; n++ ) {
  95.                 if( *n == delimchar ) break;
  96.                 macroname[ i++ ] = *n;
  97.             }
  98.             if( *n != delimchar ) {
  99.                 logprintf( "macro name is too long [%s]\n", macroname );
  100.                 logprintf( "macro names are limited to %d\n",
  101.                     Param.MaxLine );
  102.                 goto death;
  103.             }
  104.             next = n + 1;
  105.         }
  106.         else { /* single letter variable name */
  107.             macroname[ 0 ] = *next++; /* advance past the macroname */
  108.         }
  109.  
  110.         if( mac = expand_fncall( macroname, maxlen - outlen )) {
  111.             debugprintf( 4,( "fncall macro [%s] = %s\n", macroname,
  112.                 mac->expansion ));
  113.         }
  114.         else if( !(mac = find_macro( macroname )) && getenv( macroname )) {
  115.             /* use getenv() to assign a simple macro */
  116.             debugprintf( 4,( "getenv macro [%s]\n", macroname ));
  117.             if( mac = set_macro( macroname, getenv( macroname ))) {
  118.                 mac->flags |= MF_SIMPLE;
  119.             }
  120.         }
  121.         if( mac ) {
  122.             int cdrlen = maxlen - outlen;
  123.             if( mac->flags & MF_EXPANDED ) {
  124.                 logprintf( "infinitely recursive macro expansion: %s\n",
  125.                     macroname );
  126.                 goto death;
  127.             }
  128.             memset( out, 0, cdrlen );
  129.             if( mac->expansion) strncpy( out, mac->expansion, cdrlen );
  130.             cdrlen -= strlen( out );
  131.             if( cdrlen < 0 ) {
  132.                 logprintf( "expand_macros3 ERROR: cdrlen is %d\n",
  133.                     cdrlen );
  134.                 goto death;
  135.             }
  136.             strncpy( out + strlen(out), next, cdrlen );
  137.             if( !(mac->flags & MF_SIMPLE )) {
  138.                 /* recursively expand nested macro expansion */
  139.                 mac->flags |= MF_EXPANDED;
  140.                 if( expand_macros2( out, out, cdrlen )) goto death;
  141.                 mac->flags &= ~MF_EXPANDED;
  142.             }
  143.         }
  144.         else {
  145.             logprintf( "WARNING:  unknown macro [%s]\n", macroname );
  146.             strncpy( out + strlen(out), next, maxlen - outlen );
  147.         }
  148.         /* for next macro occurrence on the line */
  149.         outlen = min( strlen( dest ), maxlen );
  150.  
  151.         debugprintf( 6,( "expand_macros3 returns [%s] %d\n", dest, outlen ));
  152.  
  153.         strncpy( src, dest, outlen ); /* copy the expansion back */
  154.         src[ outlen  ] = (char)0;
  155.         free( macroname ); macroname = NULL;
  156.         free( dest ); dest = NULL;
  157.     } /* dollar */
  158.  
  159.     return( 0 );
  160. death:
  161.     if( macroname ) free( macroname );
  162.     if( dest ) free( dest );
  163.     return( 1 );
  164. }
  165.  
  166. /*    find the rightmost occurrence of the character tok
  167.  *    starting at prev in the string
  168.  */
  169. static char *
  170. strrlchr( char *string, char tok, char *prev )
  171. {
  172.     while( prev >= string ) {
  173.         if( *prev == tok ) return( prev );
  174.         prev--;
  175.     }
  176.     return( NULL );
  177. }
  178.  
  179. /*    expand a line with multiple $(x) instances
  180.  *    expand right to left to avoid recursion
  181.  */
  182. static int
  183. expand_macros2( char *dest, char *src, int maxlen )
  184. {
  185.     char *dollar, *prev;
  186.     int iteration = 0;
  187.  
  188.     /* increment the recursion level counter */
  189.     if( ++expand_level > MAX_RECURSION ){
  190.         logprintf( "Infinite Macro expansion aborted at %d recursions\n",
  191.             expand_level );
  192.         return( 1 );
  193.     }
  194.     debugprintf( 6,( "expand_macros2(%s,%d)\n", src, maxlen ));
  195.     if( src != dest ) strncpy( dest, src, maxlen );
  196.     prev = dest + strlen(dest);
  197.     while( dollar = strrlchr( dest, '$', prev )) {
  198.         if( ++iteration > MAX_ITERATION ) {
  199.             logprintf( "Infinite Macro expansion aborted at %d iterations\n",
  200.                 iteration );
  201.             return( 1 );
  202.         }
  203.         if( dollar[-1] == '$' || dollar[-1] == '\\' ) {
  204.             shift_string_left( dollar - 1, 1 );
  205.             --dollar;
  206.         }
  207.         else if( expand_macros3( dollar, maxlen - (int)(dollar - dest) ))
  208.             return( 1 );
  209.         prev = dollar - 1;
  210.     }
  211.     debugprintf( 6,( "expand_macros2 returns [%s]\n", dest ));
  212.     return( 0 );
  213. }
  214.  
  215. /*    to reset each variable's flags before expansion begins */
  216. static long
  217. reset_macroflag( struct macro *mac )
  218. {
  219.     mac->flags &= ~MF_EXPANDED;
  220.     return( 0 );
  221. }
  222.  
  223. /*    top level macro expansion call
  224.  *    this is the entry point called from the outside
  225.  */
  226. int
  227. expand_macros( char *dest, char *src, int maxlen )
  228. {
  229.     expand_level = 0;    /* reset the recursion level counter */
  230.     memset( dest, 0, maxlen );
  231.     for_list( &Global.macrolist, reset_macroflag );
  232.     if( expand_macros2( dest, src, maxlen - 1 )) {
  233.         logprintf( "Error expanding $(%s)\n", src );
  234.         return( 1 );
  235.     }
  236.  
  237.     debugprintf( 3,( "expand_macros [%s] to [%s]\n", src, dest ));
  238.     return( 0 );
  239. }
  240.