2012-04-03 20:30:07 -07:00
/******************************************************************************
Copyright ( c ) 1993 - 2011 Daniel Stenberg
Permission is hereby granted , free of charge , to any person obtaining a copy
of this software and associated documentation files ( the " Software " ) , to deal
in the Software without restriction , including without limitation the rights
to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
copies of the Software , and to permit persons to whom the Software is
furnished to do so , subject to the following conditions :
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software .
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <stdio.h>
# include <ctype.h>
# include "cppdef.h"
# include "cpp.h"
# if defined(AMIGA)
# include <dos.h>
# if defined(SHARED)
int _OSERR = 0 ;
char * _ProgramName = " junk " ;
void __stdargs _XCEXIT ( long a ) { return ; }
# endif
# endif
FILE_LOCAL ReturnCode output ( struct Global * , int ) ; /* Output one character */
FILE_LOCAL void sharp ( struct Global * ) ;
INLINE FILE_LOCAL ReturnCode cppmain ( struct Global * ) ;
int fppPreProcess ( struct fppTag * tags )
{
2013-03-20 21:44:17 -07:00
size_t i = 0 ;
2012-04-03 20:30:07 -07:00
ReturnCode ret ; /* cpp return code */
struct Global * global ;
global = ( struct Global * ) malloc ( sizeof ( struct Global ) ) ;
if ( ! global )
return ( FPP_OUT_OF_MEMORY ) ;
memset ( global , 0 , sizeof ( struct Global ) ) ;
global - > infile = NULL ;
global - > line = 0 ;
global - > wrongline = 0 ;
global - > errors = 0 ;
global - > recursion = 0 ;
global - > rec_recover = TRUE ;
global - > instring = FALSE ;
global - > inmacro = FALSE ;
global - > workp = NULL ;
global - > keepcomments = FALSE ; /* Write out comments flag */
global - > cflag = FALSE ; /* -C option (keep comments) */
global - > eflag = FALSE ; /* -E option (never fail) */
global - > nflag = 0 ; /* -N option (no predefines) */
global - > wflag = FALSE ; /* -W option (write #defines) */
global - > ifstack [ 0 ] = TRUE ; /* #if information */
global - > ifptr = global - > ifstack ;
global - > incend = global - > incdir ;
/* names defined at cpp start */
global - > preset [ 0 ] = " frexxcpp " ; /* This is the Frexx cpp program */
# if defined( amiga )
global - > preset [ 1 ] = " amiga " ;
global - > preset [ 2 ] = " m68000 " ;
global - > preset [ 3 ] = " amigados " ;
global - > preset [ 4 ] = NULL ; /* Must be last */
# elif defined( unix )
global - > preset [ 1 ] = " unix " ;
global - > preset [ 2 ] = NULL ;
# endif
/* Note: order is important */
global - > magic [ 0 ] = " __LINE__ " ;
global - > magic [ 1 ] = " __FILE__ " ;
global - > magic [ 2 ] = " __FUNCTION__ " ;
global - > magic [ 3 ] = " __FUNC_LINE__ " ;
global - > magic [ 4 ] = NULL ; /* Must be last */
global - > funcline = 0 ;
global - > cplusplus = 1 ;
global - > sharpfilename = NULL ;
global - > parmp = NULL ;
global - > nargs = 0 ;
global - > macro = NULL ;
global - > evalue = 0 ;
2012-06-26 20:55:33 -07:00
global - > depends = NULL ;
2012-04-03 20:30:07 -07:00
global - > input = NULL ;
global - > output = NULL ;
global - > error = NULL ;
global - > first_file = NULL ;
global - > userdata = NULL ;
global - > linelines = TRUE ;
global - > warnillegalcpp = FALSE ;
global - > outputLINE = TRUE ;
global - > warnnoinclude = TRUE ;
global - > showversion = TRUE ;
global - > showincluded = FALSE ;
global - > showspace = FALSE ;
global - > nestcomments = FALSE ;
global - > warnnestcomments = FALSE ;
global - > outputfile = TRUE ;
global - > included = 0 ;
global - > comment = FALSE ;
global - > rightconcat = FALSE ;
global - > work [ 0 ] = ' \0 ' ;
global - > initialfunc = NULL ;
memset ( global - > symtab , 0 , SBSIZE * sizeof ( DEFBUF * ) ) ;
ret = initdefines ( global ) ; /* O.S. specific def's */
if ( ret )
return ( ret ) ;
dooptions ( global , tags ) ; /* Command line -flags */
ret = addfile ( global , stdin , global - > work ) ; /* "open" main input file */
global - > out = global - > outputfile ;
if ( ! ret )
ret = cppmain ( global ) ; /* Process main file */
if ( ( i = ( global - > ifptr - global - > ifstack ) ) ! = 0 ) {
# if OLD_PREPROCESSOR
cwarn ( global , ERROR_IFDEF_DEPTH , i ) ;
# else
cerror ( global , ERROR_IFDEF_DEPTH , i ) ;
# endif
}
fflush ( stdout ) ;
fclose ( stdout ) ;
if ( global - > errors > 0 & & ! global - > eflag )
return ( IO_ERROR ) ;
return ( IO_NORMAL ) ; /* No errors or -E option set */
}
INLINE FILE_LOCAL
ReturnCode cppmain ( struct Global * global )
{
/*
* Main process for cpp - - copies tokens from the current input
* stream ( main file , include file , or a macro ) to the output
* file .
*/
int c ; /* Current character */
int counter ; /* newlines and spaces */
ReturnCode ret ; /* return code variable type */
long bracelevel = 0 ;
long parenlevel = 0 ;
long bracketlevel = 0 ;
int fake = 0 ;
# define MAX_FUNC_LENGTH 50
char tempfunc [ MAX_FUNC_LENGTH + 1 ] ;
char tempfunc2 [ MAX_FUNC_LENGTH + 1 ] ;
char define = 0 ; /* probability of a function define phase in the program */
char prev = 0 ; /* previous type */
char go = 0 ;
char include = 0 ;
char initfunc = 0 ;
/* Initialize for reading tokens */
global - > tokenbsize = 50 ;
global - > tokenbuf = malloc ( global - > tokenbsize + 1 ) ;
if ( ! global - > tokenbuf )
return ( FPP_OUT_OF_MEMORY ) ;
global - > functionname = malloc ( global - > tokenbsize + 1 ) ;
if ( ! global - > functionname )
return ( FPP_OUT_OF_MEMORY ) ;
global - > functionname [ 0 ] = ' \0 ' ;
if ( global - > showspace ) {
global - > spacebuf = ( char * ) malloc ( MAX_SPACE_SIZE ) ;
if ( ! global - > spacebuf )
return ( FPP_OUT_OF_MEMORY ) ;
}
if ( global - > showversion )
Error ( global , VERSION_TEXT ) ;
/*
* Explicitly output a # line at the start of cpp output so
* that lint ( etc . ) knows the name of the original source
* file . If we don ' t do this explicitly , we may get
* the name of the first # include file instead .
*/
if ( global - > linelines ) /* if #line lines are wanted! */
sharp ( global ) ;
/*
* This loop is started " from the top " at the beginning of each line
* wrongline is set TRUE in many places if it is necessary to write
* a # line record . ( But we don ' t write them when expanding macros . )
*
* The counter variable has two different uses : at
* the start of a line , it counts the number of blank lines that
* have been skipped over . These are then either output via
* # line records or by outputting explicit blank lines .
* When expanding tokens within a line , the counter remembers
* whether a blank / tab has been output . These are dropped
* at the end of the line , and replaced by a single blank
* within lines .
*/
include = global - > included ;
while ( include - - ) {
openinclude ( global , global - > include [ include ] , TRUE ) ;
}
for ( ; ; ) {
counter = 0 ; /* Count empty lines */
for ( ; ; ) { /* For each line, ... */
global - > comment = FALSE ; /* No comment yet! */
global - > chpos = 0 ; /* Count whitespaces */
while ( type [ ( c = get ( global ) ) ] = = SPA ) /* Skip leading blanks */
if ( global - > showspace ) {
if ( global - > chpos < MAX_SPACE_SIZE - 1 )
/* we still have buffer to store this! */
global - > spacebuf [ global - > chpos + + ] = ( char ) c ;
}
if ( c = = ' \n ' ) { /* If line's all blank, */
if ( global - > comment ) {
/* A comment was output! */
Putchar ( global , ' \n ' ) ;
}
else
+ + counter ; /* Do nothing now */
}
else if ( c = = ' # ' ) { /* Is 1st non-space '#' */
global - > keepcomments = FALSE ; /* Don't pass comments */
ret = control ( global , & counter ) ; /* Yes, do a #command */
if ( ret )
return ( ret ) ;
global - > keepcomments = ( global - > cflag & & compiling ) ;
}
else if ( c = = EOF_CHAR ) /* At end of file? */
break ;
else if ( ! compiling ) { /* #ifdef false? */
skipnl ( global ) ; /* Skip to newline */
counter + + ; /* Count it, too. */
} else {
break ; /* Actual token */
}
}
if ( c = = EOF_CHAR ) /* Exit process at */
break ; /* End of file */
/*
* If the loop didn ' t terminate because of end of file , we
* know there is a token to compile . First , clean up after
* absorbing newlines . counter has the number we skipped .
*/
if ( global - > linelines ) { /* if #line lines are wanted! */
if ( ( global - > wrongline & & global - > infile - > fp ! = NULL ) | | counter > 4 )
sharp ( global ) ; /* Output # line number */
else { /* If just a few, stuff */
while ( - - counter > = 0 ) /* them out ourselves */
Putchar ( global , ( int ) ' \n ' ) ;
}
}
if ( global - > showspace ) {
/* Show all whitespaces! */
global - > spacebuf [ global - > chpos ] = ' \0 ' ;
Putstring ( global , global - > spacebuf ) ;
}
/*
* Process each token on this line .
*/
unget ( global ) ; /* Reread the char. */
for ( ; ; ) { /* For the whole line, */
do { /* Token concat. loop */
for ( global - > chpos = counter = 0 ; ( type [ ( c = get ( global ) ) ] = = SPA ) ; ) {
# if COMMENT_INVISIBLE
if ( c ! = COM_SEP )
counter + + ;
# else
if ( global - > showspace & & global - > chpos < MAX_SPACE_SIZE - 1 ) {
global - > spacebuf [ global - > chpos + + ] = ( char ) c ;
}
counter + + ; /* Skip over blanks */
# endif
}
if ( c = = EOF_CHAR | | c = = ' \n ' )
break ; /* Exit line loop */
else if ( counter > 0 ) { /* If we got any spaces */
if ( ! global - > showspace ) /* We don't output all spaces */
Putchar ( global , ( int ) ' ' ) ; /* Output one space */
else {
global - > spacebuf [ global - > chpos ] = ' \0 ' ;
Putstring ( global , global - > spacebuf ) ; /* Output all whitespaces */
}
}
if ( ret = macroid ( global , & c ) ) /* Grab the token */
return ( ret ) ;
} while ( type [ c ] = = LET & & catenate ( global , & ret ) & & ! ret ) ;
if ( ret )
/* If the loop was broken because of a fatal error! */
return ( ret ) ;
if ( c = = EOF_CHAR | | c = = ' \n ' ) /* From macro exp error */
break ; /* Exit line loop */
go + + ;
switch ( type [ c ] ) {
case LET :
go = 0 ;
/* Quite ordinary token */
Putstring ( global , global - > tokenbuf ) ;
if ( ! define ) {
/* Copy the name */
strncpy ( tempfunc , global - > tokenbuf , MAX_FUNC_LENGTH ) ;
tempfunc [ MAX_FUNC_LENGTH ] = 0 ;
}
/* fputs(global->tokenbuf, stdout); */
break ;
case DIG : /* Output a number */
case DOT : /* Dot may begin floats */
go = 0 ;
ret = scannumber ( global , c , ( ReturnCode ( * ) ( struct Global * , int ) ) output ) ;
if ( ret )
return ( ret ) ;
break ;
case QUO : /* char or string const */
go = 0 ;
/* Copy it to output */
if ( ! global - > webmode ) {
ret = scanstring ( global , c ,
( ReturnCode ( * ) ( struct Global * , int ) ) output ) ;
if ( ret )
return ( ret ) ;
break ;
}
/* FALLTHROUGH */
default : /* Some other character */
define + + ;
switch ( c ) {
case ' { ' :
if ( ! bracelevel + + & & define > 2 ) {
/*
* This is a starting brace . If there is a probability of a
* function defining , we copy the ` tempfunc ' function name to
* ` global - > functionname ' .
*/
strcpy ( global - > functionname , tempfunc2 ) ;
global - > funcline = global - > line ;
if ( global - > outputfunctions ) {
/*
* Output the discovered function name to stderr !
*/
Error ( global , " #> Function defined at line %d: %s <# \n " ,
global - > line ,
global - > functionname ) ;
}
if ( global - > initialfunc ) {
int a ;
for ( a = 0 ; a < global - > excluded ; a + + ) {
/* check for excluded functions */
if ( ! strcmp ( global - > functionname ,
global - > excludedinit [ a ] ) )
break ;
}
if ( a = = global - > excluded ) {
expstuff ( global , " __brace__ " , " { " ) ;
expstuff ( global , " __init_func__ " , global - > initialfunc ) ;
initfunc = TRUE ;
}
}
}
break ;
case ' } ' :
go = 0 ;
if ( ( - - bracelevel = = initfunc ) & &
strcmp ( global - > infile - > filename , " __init_func__ " ) ) {
/* we just stepped out of the function! */
global - > functionname [ 0 ] = ' \0 ' ;
global - > funcline = 0 ;
define = 1 ;
if ( initfunc ) {
Putchar ( global , ' } ' ) ;
bracelevel - - ;
initfunc = 0 ;
}
}
fake = 0 ;
break ;
case ' ; ' :
case ' , ' :
if ( go = = 2 ) {
define = 1 ;
fake = 0 ;
go - - ;
break ;
}
break ;
case ' ( ' :
if ( ! parenlevel + + & & ! bracelevel ) {
if ( go = = 2 ) {
/* foobar(text) -> "(" is found. This can't be a
function */
go - - ;
define = 1 ;
break ;
}
if ( define < 2 & & prev = = LET ) {
/* This is the first parenthesis on the ground brace
level , and we did previously not have a probable
function name */
strncpy ( tempfunc2 , global - > tokenbuf , MAX_FUNC_LENGTH ) ;
tempfunc2 [ MAX_FUNC_LENGTH ] = 0 ;
define + + ;
}
else {
/* we have a fake start */
fake + + ;
}
}
break ;
case ' ) ' :
if ( ! - - parenlevel & & ! bracelevel & & define > 1 & & ! fake ) {
/*
* The starting parentheses level and
* the starting brace level .
* This might be the start of a function defining coming
* up !
*/
define + + ; /* increase probability */
fake = 0 ;
go = 1 ;
}
break ;
case ' [ ' :
bracketlevel + + ;
break ;
case ' ] ' :
bracketlevel - - ;
break ;
}
define - - ; /* decrease function probability */
Putchar ( global , c ) ; /* Just output it */
break ;
} /* Switch ends */
prev = type [ c ] ;
} /* Line for loop */
if ( c = = ' \n ' ) { /* Compiling at EOL? */
Putchar ( global , ' \n ' ) ; /* Output newline, if */
if ( global - > infile - > fp = = NULL ) /* Expanding a macro, */
global - > wrongline = TRUE ; /* Output # line later */
}
} /* Continue until EOF */
if ( global - > showbalance ) {
if ( bracketlevel ) {
cwarn ( global , WARN_BRACKET_DEPTH , bracketlevel ) ;
}
if ( parenlevel ) {
cwarn ( global , WARN_PAREN_DEPTH , parenlevel ) ;
}
if ( bracelevel ) {
cwarn ( global , WARN_BRACE_DEPTH , bracelevel ) ;
}
}
if ( global - > wflag ) {
global - > out = TRUE ; /* enable output */
outdefines ( global ) ; /* Write out #defines */
}
return ( FPP_OK ) ;
}
FILE_LOCAL
ReturnCode output ( struct Global * global , int c )
{
/*
* Output one character to stdout - - output ( ) is passed as an
* argument to scanstring ( )
*/
# if COMMENT_INVISIBLE
if ( c ! = TOK_SEP & & c ! = COM_SEP )
# else
if ( c ! = TOK_SEP )
# endif
Putchar ( global , c ) ;
return ( FPP_OK ) ;
}
void Putchar ( struct Global * global , int c )
{
/*
* Output one character to stdout or to output function !
*/
if ( ! global - > out )
return ;
# if defined(UNIX)
if ( global - > output )
global - > output ( c , global - > userdata ) ;
else
putchar ( c ) ;
# else /* amiga */
global - > output ( c , global - > userdata ) ;
# endif
}
void Putstring ( struct Global * global , char * string )
{
/*
* Output a string ! One letter at a time to the Putchar routine !
*/
if ( ! string )
return ;
while ( * string )
Putchar ( global , * string + + ) ;
}
void Putint ( struct Global * global , int number )
{
/*
* Output the number as a string .
*/
char buffer [ 16 ] ; /* an integer can't be that big! */
char * point = buffer ;
sprintf ( buffer , " %d " , number ) ;
while ( * point )
Putchar ( global , * point + + ) ;
}
FILE_LOCAL
void sharp ( struct Global * global )
{
/*
* Output a line number line .
*/
char * name ;
if ( global - > keepcomments ) /* Make sure # comes on */
Putchar ( global , ' \n ' ) ; /* a fresh, new line. */
/* printf("#%s %d", LINE_PREFIX, global->line); */
Putchar ( global , ' # ' ) ;
if ( global - > outputLINE )
Putstring ( global , LINE_PREFIX ) ;
Putchar ( global , ' ' ) ;
Putint ( global , global - > line ) ;
if ( global - > infile - > fp ! = NULL ) {
name = ( global - > infile - > progname ! = NULL )
? global - > infile - > progname : global - > infile - > filename ;
if ( global - > sharpfilename = = NULL
| | ( global - > sharpfilename ! = NULL & & ! streq ( name , global - > sharpfilename ) ) ) {
if ( global - > sharpfilename ! = NULL )
free ( global - > sharpfilename ) ;
global - > sharpfilename = savestring ( global , name ) ;
/* printf(" \"%s\"", name); */
Putstring ( global , " \" " ) ;
Putstring ( global , name ) ;
Putchar ( global , ' \" ' ) ;
}
}
Putchar ( global , ' \n ' ) ;
global - > wrongline = FALSE ;
return ;
}