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