home *** CD-ROM | disk | FTP | other *** search
- /* expand.c
- * (c) Copyright 1991 by Ben Eng, All Rights Reserved
- *
- * macro expansion
- */
-
- #include <clib/exec_protos.h>
-
- #include <ctype.h>
-
- #include "make.h"
- #include "depend.h"
-
- static int expand_macros2( char *dest, char *src, int maxlen );
- static int expand_macros3( char *src, int maxlen );
-
- /* define the criterion for detecting infinitely recursive
- * macro expansions
- */
- static int expand_level = 0;
- #define MAX_RECURSION 32
- #define MAX_ITERATION 256
-
- static struct macro *
- expand_fncall( char *src, int maxlen )
- {
- static struct macro *fnmac = NULL;
- struct fncall *fc;
- char fn[ 40 ], *next = src;
- int addlen;
-
- if( fnmac) {
- if( fnmac->expansion ) {
- free( fnmac->expansion );
- fnmac->expansion = NULL;
- }
- }
- else if( fnmac = new_macro( NULL, NULL ))
- fnmac->flags |= MF_SIMPLE;
- else return( NULL );
-
- next = parse_str( fn, next, sizeof(fn));
- if( fc = find_fncall( fn )) {
- if( (*fc->call)( fnmac, next )) {
- logprintf( "function call %s returned ERROR\n", fc->name );
- return( NULL );
- }
- fnmac->flags |= MF_SIMPLE;
- return( fnmac );
- }
- return( NULL );
- }
-
- /* expand a macro reference with only a single $(x) instance
- * handles recursive expansion
- */
- static int
- expand_macros3( char *src, int maxlen )
- {
- char *dest = NULL;
- char *macroname = NULL;
- char *dollar;
-
- dollar = strchr( src, '$' );
- if( dollar ) {
- struct macro *mac = NULL;
- char *out, *next;
- int outlen = 0;
- char delimchar = (char)0;
-
- debugprintf( 6,( "expand_macros3(%s,%d)\n", src, maxlen ));
-
- /* could get away with only allocating maxlen to save memory */
- macroname = (char *)malloc( Param.MaxLine );
- dest = (char *)calloc( Param.MaxLine, 1 );
- if( !macroname || !dest )
- goto death;
-
- out = dest;
-
- memset( macroname, 0, Param.MaxLine);
- for( next = src; next < dollar && outlen < maxlen; outlen++ )
- *out++ = *next++;
-
- next = dollar + 1;
- if( outlen >= maxlen )
- goto death;
-
- if( *next == '(' )
- delimchar = ')';
- else if( *next == '{' )
- delimchar = '}';
-
- if( delimchar ) { /* multi letter variable name */
- char *n;
- int i = 0;
-
- for( n = ++next; *n && i < Param.MaxLine-1; n++ ) {
- if( *n == delimchar ) break;
- macroname[ i++ ] = *n;
- }
- if( *n != delimchar ) {
- logprintf( "macro name is too long [%s]\n", macroname );
- logprintf( "macro names are limited to %d\n",
- Param.MaxLine );
- goto death;
- }
- next = n + 1;
- }
- else { /* single letter variable name */
- macroname[ 0 ] = *next++; /* advance past the macroname */
- }
-
- if( mac = expand_fncall( macroname, maxlen - outlen )) {
- debugprintf( 4,( "fncall macro [%s] = %s\n", macroname,
- mac->expansion ));
- }
- else if( !(mac = find_macro( macroname )) && getenv( macroname )) {
- /* use getenv() to assign a simple macro */
- debugprintf( 4,( "getenv macro [%s]\n", macroname ));
- if( mac = set_macro( macroname, getenv( macroname ))) {
- mac->flags |= MF_SIMPLE;
- }
- }
- if( mac ) {
- int cdrlen = maxlen - outlen;
- if( mac->flags & MF_EXPANDED ) {
- logprintf( "infinitely recursive macro expansion: %s\n",
- macroname );
- goto death;
- }
- memset( out, 0, cdrlen );
- if( mac->expansion)
- strncpy( out, mac->expansion, cdrlen );
- cdrlen -= strlen( out );
- if( cdrlen < 0 ) {
- logprintf( "expand_macros3 ERROR: cdrlen is %d\n",
- cdrlen );
- goto death;
- }
- strncpy( out + strlen(out), next, cdrlen );
- if( !(mac->flags & MF_SIMPLE )) {
- /* recursively expand nested macro expansion */
- mac->flags |= MF_EXPANDED;
- if( expand_macros2( out, out, cdrlen )) goto death;
- mac->flags &= ~MF_EXPANDED;
- }
- }
- else {
- logprintf( "WARNING: unknown macro [%s]\n", macroname );
- strncpy( out + strlen(out), next, maxlen - outlen );
- }
- /* for next macro occurrence on the line */
- outlen = min( strlen( dest ), maxlen );
-
- debugprintf( 6,( "expand_macros3 returns [%s] %d\n", dest, outlen ));
-
- strncpy( src, dest, outlen ); /* copy the expansion back */
- src[ outlen ] = (char)0;
- free( macroname ); macroname = NULL;
- free( dest ); dest = NULL;
- } /* dollar */
-
- return( 0 );
- death:
- if( macroname )
- free( macroname );
- if( dest )
- free( dest );
- return( 1 );
- }
-
- /* find the rightmost occurrence of the character tok
- * starting at prev in the string
- */
- static char *
- strrlchr( char *string, char tok, char *prev )
- {
- while( prev >= string ) {
- if( *prev == tok ) return( prev );
- prev--;
- }
- return( NULL );
- }
-
- /* expand a line with multiple $(x) instances
- * expand right to left to avoid recursion
- */
- static int
- expand_macros2( char *dest, char *src, int maxlen )
- {
- char *dollar, *prev;
- int iteration = 0;
-
- /* increment the recursion level counter */
- if( ++expand_level > MAX_RECURSION ){
- logprintf( "Infinite Macro expansion aborted at %d recursions\n",
- expand_level );
- return( 1 );
- }
- debugprintf( 6,( "expand_macros2(%s,%d)\n", src, maxlen ));
- if( src != dest ) strncpy( dest, src, maxlen );
- prev = dest + strlen(dest);
- while( dollar = strrlchr( dest, '$', prev )) {
- if( ++iteration > MAX_ITERATION ) {
- logprintf( "Infinite Macro expansion aborted at %d iterations\n",
- iteration );
- return( 1 );
- }
- if( dollar[-1] == '$' || dollar[-1] == '\\' ) {
- shift_string_left( dollar - 1, 1 );
- --dollar;
- }
- else if( expand_macros3( dollar, maxlen - (int)(dollar - dest) ))
- return( 1 );
- prev = dollar - 1;
- }
- debugprintf( 6,( "expand_macros2 returns [%s]\n", dest ));
- return( 0 );
- }
-
- /* to reset each variable's flags before expansion begins */
- static long
- reset_macroflag( struct macro *mac )
- {
- mac->flags &= ~MF_EXPANDED;
- return( 0 );
- }
-
- /* top level macro expansion call
- * this is the entry point called from the outside
- */
- int
- expand_macros( char *dest, char *src, int maxlen )
- {
- expand_level = 0; /* reset the recursion level counter */
- memset( dest, 0, maxlen );
- for_list( &Global.macrolist, reset_macroflag );
- if( expand_macros2( dest, src, maxlen - 1 )) {
- logprintf( "Error expanding $(%s)\n", src );
- return( 1 );
- }
-
- debugprintf( 3,( "expand_macros [%s] to [%s]\n", src, dest ));
- return( 0 );
- }
-