diff options
Diffstat (limited to 'ACE/TAO/TAO_IDL/contrib/mcpp/support.cpp')
-rw-r--r-- | ACE/TAO/TAO_IDL/contrib/mcpp/support.cpp | 2824 |
1 files changed, 2824 insertions, 0 deletions
diff --git a/ACE/TAO/TAO_IDL/contrib/mcpp/support.cpp b/ACE/TAO/TAO_IDL/contrib/mcpp/support.cpp new file mode 100644 index 00000000000..6bcf975de3e --- /dev/null +++ b/ACE/TAO/TAO_IDL/contrib/mcpp/support.cpp @@ -0,0 +1,2824 @@ +/*- $Id$ + * Copyright (c) 1998, 2002-2008 Kiyoshi Matsui <kmatsui@t3.rim.or.jp> + * All rights reserved. + * + * Some parts of this code are derived from the public domain software + * DECUS cpp (1984,1985) written by Martin Minow. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * S U P P O R T . C + * S u p p o r t R o u t i n e s + * + * The common routines used by several source files are placed here. + */ + +/* + * The following are global functions. + * + * get_unexpandable() Gets the next unexpandable token in the line, expanding + * macros. + * Called from #if, #line and #include processing routines. + * skip_nl() Skips over a line. + * skip_ws() Skips over white spaces but not skip over the end of the line. + * skip_ws() skips also COM_SEP and TOK_SEP. + * scan_token() Reads the next token of any type into the specified output + * pointer, advances the pointer, returns the type of token. + * scan_quote() Reads a string literal, character constant or header-name from + * the input stream, writes out to the specified buffer and + * returns the advanced output pointer. + * get_ch() Reads the next byte from the current input stream, handling + * end of (macro/file) input and embedded comments appropriately. + * cnv_trigraph() Maps trigraph sequence to C character. + * cnv_digraph() Maps digraph sequence to C character. + * id_operator() See whether the identifier is an operator in C++. + * unget_ch() Pushs last gotten character back on the input stream. + * unget_string() Pushs sequence on the input stream. + * save_string() Saves a string in malloc() memory. + * get_file() Initializes a new FILEINFO structure, called when #include + * opens a new file, or from unget_string(). + * ACE_OS::malloc() Gets a specified number of bytes from heap memory. + * If malloc() returns NULL, exits with a message. + * ACE_OS::realloc() realloc(). If it fails, exits with a message. + * get_src_location() Trace back line-column datum into pre-line-splicing + * phase. A function for -K option. + * cfatal(), cerror(), cwarn() + * These routines format print messages to the user. + * mcpp_fputc(), mcpp_fputs(), mcpp_fprintf() + * Wrap library functions to support alternate output to memory + * buffer. + */ + +#if PREPROCESSED +#include "mcpp.H" +#error "Unsupportred configuration" +#else +#include "system.H" +#include "internal.H" +#endif + +static void scan_id( int c); +/* Scan an identifier */ +static char * scan_number( int c, char * out, char * out_end); +/* Scan a preprocessing number */ +static char * scan_number_prestd( int c, char * out, char * out_end); +/* scan_number() for pre-Standard mode */ +#if OK_UCN +static char * scan_ucn( int cnt, char * out); +/* Scan an UCN sequence */ +#endif +static char * scan_op( int c, char * out); +/* Scan an operator or a punctuator */ +static char * parse_line( void); +/* Parse a logical line and convert comments */ +static char * read_a_comment( char * sp, size_t * sizp); +/* Read over a comment */ +static char * get_line( int in_comment); +/* Get a logical line from file, handle line-splicing */ +static char * at_eof( int in_comment); +/* Check erroneous end of file */ +static void do_msg( const char * severity, const char * format + , const char * arg1, long arg2, const char * arg3); +/* Putout diagnostic message */ +static char * cat_line( int del_bsl); +/* Splice the line */ +static void put_line( char * out, FILE * fp); +/* Put out a logical line */ +static void dump_token( int token_type, const char * cp); +/* Dump a token and its type */ + +#define EXP_MAC_IND_MAX 16 +/* Information of current expanding macros for diagnostic */ +static struct { + const char * name; /* Name of the macro just expanded */ + int to_be_freed; /* Name should be freed later */ +} expanding_macro[ EXP_MAC_IND_MAX]; +static int exp_mac_ind = 0; /* Index into expanding_macro[] */ + +static int in_token = FALSE; /* For token scanning functions */ +static int in_string = FALSE; /* For get_ch() and parse_line()*/ +static int squeezews = FALSE; + +#define MAX_CAT_LINE 256 +/* Information on line catenated by <backslash><newline> */ +/* and by line-crossing comment. This is for -K option. */ +typedef struct catenated_line { + long start_line; /* Starting line of catenation */ + long last_line; /* Ending line of catanation */ + size_t len[ MAX_CAT_LINE + 1]; + /* Length of successively catenated lines */ +} CAT_LINE; +static CAT_LINE bsl_cat_line; +/* Datum on the last catenated line by <backslash><newline> */ +static CAT_LINE com_cat_line; +/* Datum on the last catenated line by a line-crossing comment */ + +#ifdef MCPP_LIB +static int use_mem_buffers = FALSE; + +void init_support( void) +{ + in_token = in_string = squeezews = FALSE; + bsl_cat_line.len[ 0] = com_cat_line.len[ 0] = 0; + clear_exp_mac(); +} + +typedef struct mem_buf { + char * buffer; + char * entry_pt; + size_t size; + size_t bytes_avail; + + mem_buf () + : buffer (0), + entry_pt (0), + size (0), + bytes_avail (0) + {} +} MEMBUF; + +static MEMBUF mem_buffers[ NUM_OUTDEST]; + +void mcpp_use_mem_buffers( + int tf + ) +{ + int i; + + use_mem_buffers = tf ? TRUE : FALSE; + + for (i = 0; i < NUM_OUTDEST; ++i) { + if (mem_buffers[ i].buffer != 0) + /* Free previously allocated memory buffer */ + ACE_OS::free( mem_buffers[ i].buffer); + mem_buffers[i].buffer = 0; + if (use_mem_buffers) { + /* Output to memory buffers instead of files */ + mem_buffers[ i].buffer = 0; + mem_buffers[ i].entry_pt = 0; + mem_buffers[ i].size = 0; + mem_buffers[ i].bytes_avail = 0; + } + } +} + +int using_mem_buffers( void) +{ + return use_mem_buffers; +} + +#define BUF_INCR_SIZE (NWORK * 2) +#ifdef MAX +#undef MAX +#endif +#define MAX( a, b) (((a) > (b)) ? (a) : (b)) + +static char * append_to_buffer( + MEMBUF * mem_buf_p, + const char * string, + size_t length + ) +{ + if (mem_buf_p->bytes_avail < length) { /* Need to allocate more memory */ + size_t size = MAX( BUF_INCR_SIZE, length); + + if (mem_buf_p->buffer == 0) { /* 1st append */ + mem_buf_p->size = size; + mem_buf_p->bytes_avail = size; + mem_buf_p->buffer = (char *) ACE_OS::malloc( mem_buf_p->size); + mem_buf_p->entry_pt = mem_buf_p->buffer; + } else { + mem_buf_p->size += size; + mem_buf_p->bytes_avail += size; + mem_buf_p->buffer = (char *) ACE_OS::realloc( mem_buf_p->buffer, mem_buf_p->size); + mem_buf_p->entry_pt = mem_buf_p->buffer + mem_buf_p->size + - mem_buf_p->bytes_avail; + } + } + + /* Append the string to the tail of the buffer */ + ACE_OS::memcpy( mem_buf_p->entry_pt, string, length); + mem_buf_p->entry_pt += length; + mem_buf_p->entry_pt[ 0] = '\0'; /* Terminate the string buffer */ + mem_buf_p->bytes_avail -= length; + + return mem_buf_p->buffer; +} + +static int mem_putc( + int c, + OUTDEST od + ) +{ + char string[ 1]; + + string[ 0] = (char) c; + + if (append_to_buffer( &(mem_buffers[ od]), string, 1) != 0) + return 0; + else + return !0; +} + +static int mem_puts( + const char * s, + OUTDEST od + ) +{ + if (append_to_buffer( &(mem_buffers[od]), s, ACE_OS::strlen(s)) != 0) + return 0; + else + return !0; +} + +char * mcpp_get_mem_buffer( + OUTDEST od + ) +{ + char *retval = mem_buffers[ od].buffer; + mem_buffers[ od].buffer = 0; + return retval; +} + +#endif /* MCPP_LIB */ + +#define DEST2FP(od) \ + (od == OUT) ? fp_out : \ + ((od == ERR) ? fp_err : \ + ((od == DBG) ? fp_debug : \ + (0))) + +/* + * The following mcpp_*() wrapper functions are intended to centralize + * the output generated by MCPP. They support memory buffer alternates to + * each of the primary output streams: out, err, debug. The memory buffer + * output option would be used in a setup where MCPP has been built as a + * function call - i.e. mcpp_lib_main(). + */ + +int mcpp_lib_fputc( + int c, + OUTDEST od + ) +{ +#ifdef MCPP_LIB + if (use_mem_buffers) { + return mem_putc( c, od); + } else { +#endif + FILE * stream = DEST2FP( od); + + return (stream != 0) ? ACE_OS::fputc( c, stream) : EOF; +#ifdef MCPP_LIB + } +#endif +} + +int (* mcpp_fputc)( int c, OUTDEST od) = mcpp_lib_fputc; + +int mcpp_lib_fputs( + const char * s, + OUTDEST od + ) +{ +#ifdef MCPP_LIB + if (use_mem_buffers) { + return mem_puts( s, od); + } else { +#endif + FILE * stream = DEST2FP( od); + + return (stream != 0) ? ACE_OS::fputs( s, stream) : EOF; +#ifdef MCPP_LIB + } +#endif +} + +int (* mcpp_fputs)( const char * s, OUTDEST od) = mcpp_lib_fputs; + +#include <stdarg.h> + +int mcpp_lib_fprintf( + OUTDEST od, + const char * format, + ... + ) +{ + va_list ap; + FILE * stream = DEST2FP( od); + + if (stream != 0) { + int rc; + + va_start( ap, format); +#ifdef MCPP_LIB + if (use_mem_buffers) { + static char mem_buffer[ NWORK]; + + rc = ACE_OS::vsprintf( mem_buffer, format, ap); + + if (rc != 0) { + rc = mem_puts( mem_buffer, od); + } + } else { +#endif + rc = ACE_OS::vfprintf( stream, format, ap); +#ifdef MCPP_LIB + } +#endif + va_end( ap); + + return rc; + + } else { + return EOF; + } +} + +int (* mcpp_fprintf)( OUTDEST od, const char * format, ...) = mcpp_lib_fprintf; + +#ifdef MCPP_LIB +void mcpp_reset_def_out_func( void) +{ + mcpp_fputc = mcpp_lib_fputc; + mcpp_fputs = mcpp_lib_fputs; + mcpp_fprintf = mcpp_lib_fprintf; +} + +void mcpp_set_out_func( + int (* func_fputc)( int c, OUTDEST od), + int (* func_fputs)( const char * s, OUTDEST od), + int (* func_fprintf)( OUTDEST od, const char * format, ...) + ) +{ + mcpp_fputc = func_fputc; + mcpp_fputs = func_fputs; + mcpp_fprintf = func_fprintf; +} +#endif + +int get_unexpandable( + int c, /* First char of token */ + int diag /* Flag of diagnosis */ + ) +/* + * Get the next unexpandable token in the line, expanding macros. + * Return the token type. The token is written in work_buf[]. + * The once expanded macro is never expanded again. + * Called only from the routines processing #if (#elif, #assert), #line and + * #include directives in order to diagnose some subtle macro expansions. + */ +{ + DEFBUF * defp = 0; + FILEINFO * file; + FILE * fp = 0; + LINE_COL line_col = { 0L, 0}; + int token_type = NO_TOKEN; + int has_pragma; + + while (c != EOS && c != '\n' /* In a line */ + && (fp = infile->fp /* Preserve current state */ + , (token_type + = scan_token( c, (workp = work_buf, &workp), work_end)) + == NAM) /* Identifier */ + && fp != 0 /* In source ! */ + && (defp = is_macro( 0)) != 0) { /* Macro */ + expand_macro( defp, work_buf, work_end, line_col, & has_pragma); + /* Expand macro */ + if (has_pragma) + cerror( "_Pragma operator found in directive line" /* _E_ */ + , 0, 0L, 0); + file = unget_string( work_buf, defp->name); /* Stack to re-read */ + c = skip_ws(); /* Skip TOK_SEP */ + if (file != infile && macro_line != MACRO_ERROR && (warn_level & 1)) { + /* This diagnostic is issued even if "diag" is FALSE. */ + cwarn( "Macro \"%s\" is expanded to 0 token" /* _W1_ */ + , defp->name, 0L, 0); + if (! option_flags.no_source_line) + dump_a_def( " macro", defp, FALSE, TRUE, fp_err); + } + } + + if (c == '\n' || c == EOS) { + unget_ch(); + return NO_TOKEN; + } + + if (diag && fp == 0 && defp && (warn_level & 1)) { + char tmp[ NWORK + 16]; + char * tmp_end = tmp + NWORK; + char * tmp_p; + file = unget_string( infile->buffer, defp->name); /* To diagnose */ + c = get_ch(); + while (file == infile) { /* Search the expanded macro */ + if (scan_token( c, (tmp_p = tmp, &tmp_p), tmp_end) != NAM) { + c = get_ch(); + continue; + } + if (standard && str_eq( identifier, "defined")) { + cwarn( "Macro \"%s\" is expanded to \"defined\"" /* _W1_ */ + , defp->name, 0L, 0); + break; + } + if (! standard && str_eq( identifier, "sizeof")) { + cwarn( "Macro \"%s\" is expanded to \"sizeof\"" /* _W1_ */ + , defp->name, 0L, 0); + break; + } + c = get_ch(); + } + if (file == infile) { + infile->bptr += ACE_OS::strlen( infile->bptr); + get_ch(); + } + unget_ch(); + if (token_type == OPE) { + unget_string( work_buf, 0); /* Set again 'openum' */ + scan_token( get_ch(), (workp = work_buf, &workp), work_end); + } + } + + return token_type; +} + +void skip_nl( void) +/* + * Skip to the end of the current input line. + */ +{ + insert_sep = NO_SEP; + while (infile && infile->fp == 0) { /* Stacked text */ + infile->bptr += ACE_OS::strlen( infile->bptr); + get_ch(); /* To the parent */ + } + if (infile) + infile->bptr += ACE_OS::strlen( infile->bptr); /* Source line */ +} + +int skip_ws( void) +/* + * Skip over horizontal whitespaces. + */ +{ + int c; + + do { + c = get_ch(); + } while (char_type[ c] & HSP); + + return c; +} + +#define MBMASK 0xFF /* Mask to hide multibyte char */ + +int scan_token( + int c, /* The first character of the token */ + char ** out_pp, /* Pointer to pointer to output buf */ + char * out_end /* End of output buffer */ + ) +/* + * Scan the next token of any type. + * The token is written out to the specified buffer and the output pointer + * is advanced. Token is terminated by EOS. Return the type of token. + * If the token is an identifier, the token is also in identifier[]. + * If the token is a operator or punctuator, return OPE. + * If 'c' is token separator, then return SEP. + * If 'c' is not the first character of any known token and not a token + * separator, return SPE. + * In POST_STD mode, inserts token separator (a space) between any tokens of + * source. + */ +{ + char * out = *out_pp; /* Output pointer */ + int ch_type; /* Type of character */ + int token_type = 0; /* Type of token */ + int ch; + + if (standard) + in_token = TRUE; /* While a token is scanned */ + c = c & UCHARMAX; + ch_type = char_type[ c] & MBMASK; + + switch (ch_type) { + case LET: /* Probably an identifier */ + switch (c) { + case 'L': + if (! standard) + goto ident; + ch = get_ch(); + if (char_type[ ch] & QUO) { /* char_type[ ch] == QUO */ + if (ch == '"') + token_type = WSTR; /* Wide-char string literal */ + else + token_type = WCHR; /* Wide-char constant */ + c = ch; + *out++ = 'L'; + break; /* Fall down to "case QUO:" */ + } else { + unget_ch(); + } /* Fall through */ + default: /* An identifier */ + ident: + scan_id( c); + out = mcpp_stpcpy( out, identifier); + token_type = NAM; + break; + } + if (token_type == NAM) + break; + /* Else fall through -- i.e. WSTR, WCHR */ + case QUO: /* String or character constant */ + out = scan_quote( c, out, out_end, FALSE); + if (token_type == 0) { /* Without prefix L */ + if (c == '"') + token_type = STR; + else + token_type = CHR; + } /* Else WSTR or WCHR */ + break; + case DOT: + ch = get_ch(); + unget_ch(); + if ((char_type[ ch] & DIG) == 0) /* Operator '.' or '...' */ + goto operat; + /* Else fall through */ + case DIG: /* Preprocessing number */ + out = (standard ? scan_number( c, out, out_end) + : scan_number_prestd( c, out, out_end)); + token_type = NUM; + break; + case PUNC: + operat: out = scan_op( c, out); /* Operator or punctuator */ + token_type = OPE; /* Number is set in global "openum" */ + break; + default: /* Special tokens or special characters */ +#if OK_UCN + if (mcpp_mode == STD && c == '\\' && stdc2) { + ch = get_ch(); + unget_ch(); + if (ch == 'U' || ch == 'u') + goto ident; /* Universal-Characte-Name */ + } +#endif +#if OK_MBIDENT + if (mcpp_mode == STD && (char_type[ c] & mbchk) && stdc3) { + char * bptr = infile->bptr; + mb_read( c, &infile->bptr, &out); + infile->bptr = bptr; + out = *out_pp; + goto ident; /* An identifier with multi-byte characters */ + /* Mbchar cheking has been done in scan_quote() and others. */ + } +#endif + if ((standard && (c == CAT || c == ST_QUOTE)) || (char_type[ c] & SPA)) + token_type = SEP; /* Token separator or magic char*/ + else + token_type = SPE; + /* Unkown token ($, @, multi-byte character or Latin */ + *out++ = c; + *out = EOS; + break; + } + + if (out_end < out) + cfatal( "Buffer overflow scanning token \"%s\"" /* _F_ */ + , *out_pp, 0L, 0); + if (mcpp_debug & TOKEN) + dump_token( token_type, *out_pp); + if (mcpp_mode == POST_STD && token_type != SEP && infile->fp != 0 + && (char_type[ *infile->bptr & UCHARMAX] & SPA) == 0) + insert_sep = INSERT_SEP; /* Insert token separator */ + *out_pp = out; + + in_token = FALSE; /* Token scanning has been done */ + return token_type; +} + +static void scan_id( + int c /* First char of id */ + ) +/* + * Reads the next identifier and put it into identifier[]. + * The caller has already read the first character of the identifier. + */ +{ + static char * const limit = &identifier[ IDMAX]; + static int dollar_diagnosed = FALSE; /* Flag of diagnosing '$' */ +#if OK_UCN + int uc2 = 0, uc4 = 0; /* Count of UCN16, UCN32 */ +#endif +#if OK_MBIDENT + int mb = 0; /* Count of MBCHAR */ +#endif + size_t len; /* Length of identifier */ + char * bp = identifier; + + if (c == IN_SRC) { /* Magic character */ + *bp++ = c; + if ((mcpp_debug & MACRO_CALL) && ! in_directive) { + *bp++ = get_ch(); /* Its 2-bytes */ + *bp++ = get_ch(); /* argument */ + } + c = get_ch(); + } + + do { + if (bp < limit) + *bp++ = c; +#if OK_UCN + if (mcpp_mode == STD && c == '\\' && stdc2) { + int cnt; + char * tp = bp; + + if ((c = get_ch()) == 'u') { + cnt = 4; + } else if (c == 'U') { + cnt = 8; + } else { + unget_ch(); + bp--; + break; + } + *bp++ = c; + if ((bp = scan_ucn( cnt, bp)) == 0) /* Error */ + return; + if (cnt == 4) + uc2++; + else if (cnt == 8) + uc4++; + if (limit <= tp) /* Too long identifier */ + bp = tp; /* Back the pointer */ + goto next_c; + } +#endif /* OK_UCN */ +#if OK_MBIDENT + if (mcpp_mode == STD && (char_type[ c] & mbchk) && stdc3) { + len = mb_read( c, &infile->bptr, &bp); + if (len & MB_ERROR) { + if (infile->fp) + cerror( + "Illegal multi-byte character sequence." /* _E_ */ + , 0, 0L, 0); + } else { + mb += len; + } + } +#endif /* OK_MBIDENT */ +#if OK_UCN + next_c: +#endif + c = get_ch(); + } while ((char_type[ c] & (LET | DIG)) /* Letter or digit */ +#if OK_UCN + || (mcpp_mode == STD && c == '\\' && stdc2) +#endif +#if OK_MBIDENT + || (mcpp_mode == STD && (char_type[ c] & mbchk) && stdc3) +#endif + ); + + unget_ch(); + *bp = EOS; + + if (bp >= limit && (warn_level & 1)) /* Limit of token */ + cwarn( "Too long identifier truncated to \"%s\"" /* _W1_ */ + , identifier, 0L, 0); + + len = bp - identifier; +#if IDMAX > IDLEN90MIN + /* UCN16, UCN32, MBCHAR are counted as one character for each. */ +#if OK_UCN + if (mcpp_mode == STD) + len -= (uc2 * 5) - (uc4 * 9); +#endif +#if OK_MBIDENT + if (mcpp_mode == STD) + len -= mb; +#endif + if (standard && infile->fp && len > std_limits.id_len && (warn_level & 4)) + cwarn( "Identifier longer than %.0s%ld characters \"%s\"" /* _W4_ */ + , 0, (long) std_limits.id_len, identifier); +#endif /* IDMAX > IDLEN90MIN */ + + if (option_flags.dollar_in_name && dollar_diagnosed == FALSE + && (warn_level & 2) && ACE_OS::strchr( identifier, '$') != 0) { + cwarn( "'$' in identifier \"%s\"", identifier, 0L, 0); /* _W2_ */ + dollar_diagnosed = TRUE; /* Diagnose only once */ + } +} + +char * scan_quote( + int delim, /* ', " or < (header-name) */ + char * out, /* Output buffer */ + char * out_end, /* End of output buffer */ + int diag /* Diagnostic should be output */ + ) +/* + * Scan off a string literal or character constant to the output buffer. + * Report diagnosis if the quotation is terminated by newline or character + * constant is empty (provided 'diag' is TRUE). + * Return the next output pointer or 0 (on error). + */ +{ + const char * const skip_line = ", skipped the line"; /* _E_ */ + const char * const unterm_string + = "Unterminated string literal%s"; + const char * const unterm_char + = "Unterminated character constant %s%.0ld%s"; + const char * const empty_const + = "Empty character constant %s%.0ld%s"; + const char * skip; + size_t len; + int c; + char * out_p = out; + + /* Set again in case of called from routines other than scan_token(). */ + if (standard) + in_token = TRUE; + *out_p++ = delim; + if (delim == '<') + delim = '>'; + + scan: + while ((c = get_ch()) != EOS) { + +#if MBCHAR + if (char_type[ c] & mbchk) { + /* First of multi-byte character (or shift-sequence) */ + char * bptr = infile->bptr; + len = mb_read( c, &infile->bptr, (*out_p++ = c, &out_p)); + if (len & MB_ERROR) { + if (infile->fp != 0 && compiling && diag) { + if (warn_level & 1) { + char * buf; + size_t chlen; + buf = (char *) ACE_OS::malloc( chlen = infile->bptr - bptr + 2); + ACE_OS::memcpy( buf, bptr, chlen - 1); + buf[ chlen - 1] = EOS; + cwarn( + "Illegal multi-byte character sequence \"%s\" in quotation", /* _W1_ */ + buf, 0L, 0); + ACE_OS::free( buf); + } + } + continue; + } else { /* Valid multi-byte character (or sequence) */ + goto chk_limit; + } + } +#endif + if (c == delim) { + break; + } else if (c == '\\' && delim != '>') { /* In string literal */ +#if OK_UCN + if (mcpp_mode == STD && stdc2) { + int cnt; + char * tp; + + *out_p++ = c; + if ((c = get_ch()) == 'u') { + cnt = 4; + } else if (c == 'U') { + cnt = 8; + } else { + goto escape; + } + *out_p++ = c; + if ((tp = scan_ucn( cnt, out_p)) != 0) + out_p = tp; + /* Else error */ + continue; /* Error or not, anyway continue */ + } +#endif /* OK_UCN */ + *out_p++ = c; /* Escape sequence */ + c = get_ch(); + escape: +#if MBCHAR + if (char_type[ c] & mbchk) { + /* '\\' followed by multi-byte char */ + unget_ch(); + continue; + } +#endif + if (! standard && c == '\n') { /* <backslash><newline> */ + out_p--; /* Splice the lines */ + if (cat_line( TRUE) == 0) /* End of file */ + break; + c = get_ch(); + } + } else if (mcpp_mode == POST_STD && c == ' ' && delim == '>' + && infile->fp == 0) { + continue; /* Skip space possibly inserted by macro expansion */ + } else if (c == '\n') { + break; + } + if (diag && iscntrl( c) && ((char_type[ c] & SPA) == 0) + && (warn_level & 1)) + cwarn( + "Illegal control character %.0s0lx%02x in quotation" /* _W1_ */ + , 0, (long) c, 0); + *out_p++ = c; + chk_limit: + if (out_end < out_p) { + *out_end = EOS; + cfatal( "Too long quotation", 0, 0L, 0); /* _F_ */ + } + } + + if (c == '\n' || c == EOS) + unget_ch(); + if (c == delim) + *out_p++ = delim; + *out_p = EOS; + if (diag) { /* At translation phase 3 */ + skip = (infile->fp == 0) ? 0 : skip_line; + if (c != delim) { + if (mcpp_mode == OLD_PREP /* Implicit closing of quote*/ + && (delim == '"' || delim == '\'')) + goto done; + if (delim == '"') { + if (mcpp_mode != POST_STD && option_flags.lang_asm) { + /* STD, KR */ + /* Concatenate the unterminated string to the next line */ + if (warn_level & 1) + cwarn( unterm_string + , ", catenated to the next line" /* _W1_ */ + , 0L, 0); + if (cat_line( FALSE) != 0) + goto scan; /* Splice the lines */ + /* Else end of file */ + } else { + cerror( unterm_string, skip, 0L, 0); /* _E_ */ + } + } else if (delim == '\'') { + if (mcpp_mode != POST_STD && option_flags.lang_asm) { + /* STD, KR */ + if (warn_level & 1) + cwarn( unterm_char, out, 0L, 0); /* _W1_ */ + goto done; + } else { + cerror( unterm_char, out, 0L, skip); /* _E_ */ + } + } else { + cerror( "Unterminated header name %s%.0ld%s" /* _E_ */ + , out, 0L, skip); + } + out_p = 0; + } else if (delim == '\'' && out_p - out <= 2) { + if (mcpp_mode != POST_STD && option_flags.lang_asm) { + /* STD, KR */ + if (warn_level & 1) + cwarn( empty_const, out, 0L, skip); /* _W1_ */ + } else { + cerror( empty_const, out, 0L, skip); /* _E_ */ + out_p = 0; + goto done; + } + } else if (mcpp_mode == POST_STD && delim == '>' && (warn_level & 2)) { + cwarn( + "Header-name enclosed by <, > is an obsolescent feature %s" /* _W2_ */ + , out, 0L, skip); + } +#if NWORK-2 > SLEN90MIN + if (standard && out_p - out > std_limits.str_len && (warn_level & 4)) + cwarn( "Quotation longer than %.0s%ld bytes" /* _W4_ */ + , 0, std_limits.str_len, 0); +#endif + } + + done: + in_token = FALSE; + return out_p; +} + +static char * cat_line( + int del_bsl /* Delete the <backslash><newline> ? */ + ) +/* + * If del_bsl == TRUE: + * Delete <backslash><newline> sequence in string literal. + * FALSE: Overwrite the <newline> with <backslash>'n'. + * Return 0 on end of file. Called only from scan_quote(). + * This routine is never called in POST_STD mode. + */ +{ + size_t len; + char * save1, * save2; + + if (del_bsl) { /* Delete the <backslash><newline> */ + infile->bptr -= 2; + len = infile->bptr - infile->buffer; + } else { /* Overwrite the <newline> with <backslash>'n' */ + ACE_OS::strcpy( infile->bptr, "\\n"); + len = ACE_OS::strlen( infile->buffer); + } + save1 = save_string( infile->buffer); + save2 = get_line( FALSE); /* infile->buffer is overwritten */ + if (save2 == 0) { + ACE_OS::free( save1); + return 0; + } + save2 = save_string( infile->buffer); + ACE_OS::memcpy( infile->buffer, save1, len); + ACE_OS::strcpy( infile->buffer + len, save2); /* Catenate */ + ACE_OS::free( save1); + ACE_OS::free( save2); + if (! del_bsl) + len -= 2; + infile->bptr = infile->buffer + len; + return infile->bptr; +} + +static char * scan_number( + int c, /* First char of number */ + char * out, /* Output buffer */ + char * out_end /* Limit of output buffer */ + ) +/* + * Read a preprocessing number. + * By scan_token() we know already that the first c is from 0 to 9 or dot, + * and if c is dot then the second character is digit. + * Returns the advanced output pointer. + * Note: preprocessing number permits non-numeric forms such as 3E+xy, + * which are used in stringization or token-concatenation. + */ +{ + char * out_p = out; /* Current output pointer */ + + do { + *out_p++ = c; + if (c == 'E' || c == 'e' /* Sign should follow 'E', 'e', */ + || (stdc3 && (c == 'P' || c == 'p')) + /* 'P' or 'p'. */ + ) { + c = get_ch(); + if (c == '+' || c == '-') { + *out_p++ = c; + c = get_ch(); + } +#if OK_UCN + } else if (mcpp_mode == STD && c == '\\' && stdc3) { + int cnt; + char * tp; + + if ((c = get_ch()) == 'u') { + cnt = 4; + } else if (c == 'U') { + cnt = 8; + } else { + unget_ch(); + out_p--; + break; + } + *out_p++ = c; + if ((tp = scan_ucn( cnt, out_p)) == 0) /* Error */ + break; + else + out_p = tp; + c = get_ch(); +#endif /* OK_UCN */ +#if OK_MBIDENT + } else if (mcpp_mode == STD && (char_type[ c] & mbchk) && stdc3) { + len = mb_read( c, &infile->bptr, &out_p); + if (len & MB_ERROR) { + if (infile->fp) + cerror( + "Illegal multi-byte character sequence." /* _E_ */ + , 0, 0L, 0); + } +#endif /* OK_MBIDENT */ + } else { + c = get_ch(); + } + } while ((char_type[ c] & (DIG | DOT | LET)) /* Digit, dot or letter */ +#if OK_UCN + || (mcpp_mode == STD && c == '\\' && stdc3) +#endif +#if OK_MBIDENT + || (mcpp_mode == STD && (char_type[ c] & mbchk) && stdc3) +#endif + ); + + *out_p = EOS; + if (out_end < out_p) + cfatal( "Too long pp-number token \"%s\"" /* _F_ */ + , out, 0L, 0); + unget_ch(); + return out_p; +} + +/* Original version of DECUS CPP with slight modifications, */ +/* too exact for Standard preprocessing. */ +static char * scan_number_prestd( + int c, /* First char of number */ + char * out, /* Output buffer */ + char * out_end /* Limit of output buffer */ + ) +/* + * Process a number. We know that c is from 0 to 9 or dot. + * Algorithm from Dave Conroy's Decus C. + * Returns the advanced output pointer. + */ +{ + char * const out_s = out; /* For diagnostics */ + int radix; /* 8, 10, or 16 */ + int expseen; /* 'e' seen in floater */ + int octal89; /* For bad octal test */ + int dotflag; /* TRUE if '.' was seen */ + + expseen = FALSE; /* No exponent seen yet */ + octal89 = FALSE; /* No bad octal yet */ + radix = 10; /* Assume decimal */ + if ((dotflag = (c == '.')) != FALSE) { /* . something? */ + *out++ = '.'; /* Always out the dot */ + if ((char_type[(c = get_ch())] & DIG) == 0) { + /* If not a float numb, */ + goto nomore; /* All done for now */ + } + } /* End of float test */ + else if (c == '0') { /* Octal or hex? */ + *out++ = c; /* Stuff initial zero */ + radix = 8; /* Assume it's octal */ + c = get_ch(); /* Look for an 'x' */ + if (c == 'x' || c == 'X') { /* Did we get one? */ + radix = 16; /* Remember new radix */ + *out++ = c; /* Stuff the 'x' */ + c = get_ch(); /* Get next character */ + } + } + while (1) { /* Process curr. char. */ + /* + * Note that this algorithm accepts "012e4" and "03.4" + * as legitimate floating-point numbers. + */ + if (radix != 16 && (c == 'e' || c == 'E')) { + if (expseen) /* Already saw 'E'? */ + break; /* Exit loop, bad nbr. */ + expseen = TRUE; /* Set exponent seen */ + radix = 10; /* Decimal exponent */ + *out++ = c; /* Output the 'e' */ + if ((c = get_ch()) != '+' && c != '-') + continue; + } + else if (radix != 16 && c == '.') { + if (dotflag) /* Saw dot already? */ + break; /* Exit loop, two dots */ + dotflag = TRUE; /* Remember the dot */ + radix = 10; /* Decimal fraction */ + } + else { /* Check the digit */ + switch (c) { + case '8': case '9': /* Sometimes wrong */ + octal89 = TRUE; /* Do check later */ + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + break; /* Always ok */ + + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + if (radix == 16) /* Alpha's are ok only */ + break; /* if reading hex. */ + default: /* At number end */ + goto done; /* Break from for loop */ + } /* End of switch */ + } /* End general case */ + *out++ = c; /* Accept the character */ + c = get_ch(); /* Read another char */ + } /* End of scan loop */ + + if (out_end < out) /* Buffer overflow */ + goto nomore; + /* + * When we break out of the scan loop, c contains the first + * character (maybe) not in the number. If the number is an + * integer, allow a trailing 'L' for long. If not those, push + * the trailing character back on the input stream. + * Floating point numbers accept a trailing 'L' for "long double". + */ + done: + if (! (dotflag || expseen)) { /* Not floating point */ + /* + * We know that dotflag and expseen are both zero, now: + * dotflag signals "saw 'L'". + */ + for (;;) { + switch (c) { + case 'l': + case 'L': + if (dotflag) + goto nomore; + dotflag = TRUE; + break; + default: + goto nomore; + } + *out++ = c; /* Got 'L' . */ + c = get_ch(); /* Look at next, too. */ + } + } + + nomore: *out = EOS; + if (out_end < out) + goto overflow; + unget_ch(); /* Not part of a number */ + if (octal89 && radix == 8 && (warn_level & 1)) + cwarn( "Illegal digit in octal number \"%s\"" /* _W1_ */ + , out_s, 0L, 0); + return out; + + overflow: + cfatal( "Too long number token \"%s\"", out_s, 0L, 0); /* _F_ */ + return out; +} + +#if OK_UCN +static char * scan_ucn( + int cnt, /* Bytes of sequence */ + char * out /* Output buffer */ + ) +/* + * Scan an UCN sequence and put the sequence to 'out'. + * Return the advanced pointer or 0 on failure. + * This routine is never called in POST_STD mode. + */ +{ + uexpr_t value; /* Value of UCN */ + int i, c; + + value = 0L; + for (i = 0; i < cnt; i++) { + c = get_ch(); + if (! isxdigit( c)) { + if (infile->fp) + cerror( "Illegal UCN sequence" /* _E_ */ + , 0, 0L, 0); + *out = EOS; + unget_ch(); + return 0; + } + c = tolower( c); + *out++ = c; + c = (isdigit( c) ? (c - '0') : (c - 'a' + 10)); + value = (value << 4) | c; + } + if (infile->fp /* In source */ + && ((value <= 0x9FL + && value != 0x24L && value != 0x40L && value != 0x60L) + /* Basic source character */ + || (stdc3 && (value >= 0xD800L && value <= 0xDFFFL)))) + /* Reserved for special chars */ + cerror( "UCN cannot specify the value %.0s\"%08lx\"" /* _E_ */ + , 0, (long) value, 0); + return out; +} +#endif /* OK_UCN */ + +static char * scan_op( + int c, /* First char of the token */ + char * out /* Output buffer */ + ) +/* + * Scan C operator or punctuator into the specified buffer. + * Return the advanced output pointer. + * The code-number of the operator is stored to global variable 'openum'. + * Note: '#' is not an operator nor a punctuator in other than directive line, + * nevertheless is handled as a punctuator in this cpp for convenience. + */ +{ + int c2, c3, c4; + + *out++ = c; + + switch (c) { + case '~': openum = OP_COM; break; + case '(': openum = OP_LPA; break; + case ')': openum = OP_RPA; break; + case '?': openum = OP_QUE; break; + case ';': case '[': case ']': case '{': + case '}': case ',': + openum = OP_1; + break; + default: + openum = OP_2; /* Tentative guess */ + } + + if (openum != OP_2) { /* Single byte operators */ + *out = EOS; + return out; + } + + c2 = get_ch(); /* Possibly two bytes ops */ + *out++ = c2; + + switch (c) { + case '=': + openum = ((c2 == '=') ? OP_EQ : OP_1); /* ==, = */ + break; + case '!': + openum = ((c2 == '=') ? OP_NE : OP_NOT); /* !=, ! */ + break; + case '&': + switch (c2) { + case '&': openum = OP_ANA; break; /* && */ + case '=': /* openum = OP_2; */ break; /* &= */ + default : openum = OP_AND; break; /* & */ + } + break; + case '|': + switch (c2) { + case '|': openum = OP_ORO; break; /* || */ + case '=': /* openum = OP_2; */ break; /* |= */ + default : openum = OP_OR; break; /* | */ + } + break; + case '<': + switch (c2) { + case '<': c3 = get_ch(); + if (c3 == '=') { + openum = OP_3; /* <<= */ + *out++ = c3; + } else { + openum = OP_SL; /* << */ + unget_ch(); + } + break; + case '=': openum = OP_LE; break; /* <= */ + case ':': /* <: i.e. [ */ + if (mcpp_mode == STD && option_flags.dig) + openum = OP_LBRCK_D; + else + openum = OP_LT; + break; + case '%': /* <% i.e. { */ + if (mcpp_mode == STD && option_flags.dig) + openum = OP_LBRACE_D; + else + openum = OP_LT; + break; + default : openum = OP_LT; break; /* < */ + } + break; + case '>': + switch (c2) { + case '>': c3 = get_ch(); + if (c3 == '=') { + openum = OP_3; /* >>= */ + *out++ = c3; + } else { + openum = OP_SR; /* >> */ + unget_ch(); + } + break; + case '=': openum = OP_GE; break; /* >= */ + default : openum = OP_GT; break; /* > */ + } + break; + case '#': + if (standard && (in_define || macro_line)) /* in #define or macro */ + openum = ((c2 == '#') ? OP_CAT : OP_STR); /* ##, # */ + else + openum = OP_1; /* # */ + break; + case '+': + switch (c2) { + case '+': /* ++ */ + case '=': /* openum = OP_2; */ break; /* += */ + default : openum = OP_ADD; break; /* + */ + } + break; + case '-': + switch (c2) { + case '-': /* -- */ + case '=': /* -= */ + /* openum = OP_2; */ + break; + case '>': + if (cplus_val) { + if ((c3 = get_ch()) == '*') { /* ->* */ + openum = OP_3; + *out++ = c3; + } else { + /* openum = OP_2; */ + unget_ch(); + } + } /* else openum = OP_2; */ /* -> */ + /* else openum = OP_2; */ + break; + default : openum = OP_SUB; break; /* - */ + } + break; + case '%': + switch (c2) { + case '=': break; /* %= */ + case '>': /* %> i.e. } */ + if (mcpp_mode == STD && option_flags.dig) + openum = OP_RBRACE_D; + else + openum = OP_MOD; + break; + case ':': + if (mcpp_mode == STD && option_flags.dig) { + if ((c3 = get_ch()) == '%') { + if ((c4 = get_ch()) == ':') { /* %:%: i.e. ## */ + openum = OP_DSHARP_D; + *out++ = c3; + *out++ = c4; + } else { + unget_ch(); + unget_ch(); + openum = OP_SHARP_D; /* %: i.e. # */ + } + } else { + unget_ch(); + openum = OP_SHARP_D; /* %: i.e. # */ + } + if (in_define) { /* in #define */ + if (openum == OP_DSHARP_D) + openum = OP_CAT; + else + openum = OP_STR; + } + } else { + openum = OP_MOD; + } + break; + default : openum = OP_MOD; break; /* % */ + } + break; + case '*': + if (c2 != '=') /* * */ + openum = OP_MUL; + /* else openum = OP_2; */ /* *= */ + break; + case '/': + if (c2 != '=') /* / */ + openum = OP_DIV; + /* else openum = OP_2; */ /* /= */ + break; + case '^': + if (c2 != '=') /* ^ */ + openum = OP_XOR; + /* else openum = OP_2; */ /* ^= */ + break; + case '.': + if (standard) { + if (c2 == '.') { + c3 = get_ch(); + if (c3 == '.') { + openum = OP_ELL; /* ... */ + *out++ = c3; + break; + } else { + unget_ch(); + openum = OP_1; + } + } else if (cplus_val && c2 == '*') { /* .* */ + /* openum = OP_2 */ ; + } else { /* . */ + openum = OP_1; + } + } else { + openum = OP_1; + } + break; + case ':': + if (cplus_val && c2 == ':') /* :: */ + /* openum = OP_2 */ ; + else if (mcpp_mode == STD && c2 == '>' && option_flags.dig) + openum = OP_RBRCK_D; /* :> i.e. ] */ + else /* : */ + openum = OP_COL; + break; + default: /* Never reach here */ + cfatal( "Bug: Punctuator is mis-implemented %.0s0lx%x" /* _F_ */ + , 0, (long) c, 0); + openum = OP_1; + break; + } + + switch (openum) { + case OP_STR: + if (mcpp_mode == STD && c == '%') break; /* %: */ + case OP_1: + case OP_NOT: case OP_AND: case OP_OR: case OP_LT: + case OP_GT: case OP_ADD: case OP_SUB: case OP_MOD: + case OP_MUL: case OP_DIV: case OP_XOR: case OP_COM: + case OP_COL: /* Any single byte operator or punctuator */ + unget_ch(); + out--; + break; + default: /* Two or more bytes operators or punctuators */ + break; + } + + *out = EOS; + return out; +} + +int id_operator( + const char * name + ) +/* + * Check whether the name is identifier-like operator in C++. + * Return the operator number if matched, return 0 if not matched. + * Note: these identifiers are defined as macros in <iso646.h> in C95. + * This routine is never called in POST_STD mode. + */ +{ + typedef struct id_op { + const char * name; + int op_num; + } ID_OP; + + ID_OP id_ops[] = { + { "and", OP_ANA}, + { "and_eq", OP_2}, + { "bitand", OP_AND}, + { "bitor", OP_OR}, + { "compl", OP_COM}, + { "not", OP_NOT}, + { "not_eq", OP_NE}, + { "or", OP_ORO}, + { "or_eq", OP_2}, + { "xor", OP_XOR}, + { "xor_eq", OP_2}, + { 0, 0}, + }; + + ID_OP * id_p = id_ops; + + while (id_p->name != 0) { + if (str_eq( name, id_p->name)) + return id_p->op_num; + id_p++; + } + return 0; +} + +void expanding( + const char * name, /* The name of (nested) macro just expanded. */ + int to_be_freed /* The name should be freed later. */ + ) +/* + * Remember used macro name for diagnostic. + */ +{ + if (exp_mac_ind < EXP_MAC_IND_MAX - 1) { + exp_mac_ind++; + } else { + clear_exp_mac(); + exp_mac_ind++; + } + expanding_macro[ exp_mac_ind].name = name; + expanding_macro[ exp_mac_ind].to_be_freed = to_be_freed; +} + +void clear_exp_mac( void) +/* + * Initialize expanding_macro[] freeing names registered in + * name_to_be_freed[]. + */ +{ + int i; + + for (i = 1; i < EXP_MAC_IND_MAX; i++) { + if (expanding_macro[ i].to_be_freed) { + ACE_OS::free( (void *) expanding_macro[ i].name); + expanding_macro[ i].to_be_freed = FALSE; + } + } + exp_mac_ind = 0; +} + +int get_ch( void) +/* + * Return the next character from a macro or the current file. + * Always return the value representable by unsigned char. + */ +{ + int len; + int c; + FILEINFO * file; + + /* + * 'in_token' is set to TRUE while scan_token() is executed (and + * scan_id(), scan_quote(), scan_number(), scan_ucn() and scan_op() + * via scan_token()) in Standard mode to simplify tokenization. + * Any token cannot cross "file"s. + */ + if (in_token) + return (*infile->bptr++ & UCHARMAX); + + if ((file = infile) == 0) + return CHAR_EOF; /* End of all input */ + + if (mcpp_mode == POST_STD && file->fp) { /* In a source file */ + switch (insert_sep) { + case NO_SEP: + break; + case INSERT_SEP: /* Insert a token separator */ + insert_sep = INSERTED_SEP; /* Remember this fact */ + return ' '; /* for unget_ch(). */ + case INSERTED_SEP: /* Has just inserted */ + insert_sep = NO_SEP; /* Clear the flag */ + break; + } + } + if (! standard && squeezews) { + if (*file->bptr == ' ') + file->bptr++; /* Squeeze white spaces */ + squeezews = FALSE; + } + + if (mcpp_debug & GETC) { + mcpp_fprintf( DBG, "get_ch(%s) '%c' line %ld, bptr = %d, buffer" + , file->fp ? cur_fullname : file->real_fname ? file->real_fname + : file->filename ? file->filename : "0" + , *file->bptr & UCHARMAX + , src_line, (int) (file->bptr - file->buffer)); + dump_string( 0, file->buffer); + dump_unget( "get entrance"); + } + + /* + * Read a character from the current input logical line or macro. + * At EOS, either finish the current macro (freeing temporary storage) + * or get another logical line by parse_line(). + * At EOF, exit the current file (#included) or, at EOF from the MCPP input + * file, return CHAR_EOF to finish processing. + * The character is converted to int with no sign-extension. + */ + if ((c = (*file->bptr++ & UCHARMAX)) != EOS) { + if (standard) + return c; /* Just a character */ + if (! in_string && c == '\\' && *file->bptr == '\n' + && in_define /* '\\''\n' is deleted in #define line, */ + /* provided the '\\' is not the 2nd byte of mbchar. */ + && ! last_is_mbchar( file->buffer, ACE_OS::strlen( file->buffer) - 2 + && ! keep_spaces) + ) { + if (*(file->bptr - 2) == ' ') + squeezews = TRUE; + } else { + return c; + } + } + + /* + * Nothing in current line or macro. Get next line (if input from a + * file), or do end of file/macro processing, and reenter get_ch() to + * restart from the top. + */ + if (file->fp && /* In source file */ + parse_line() != 0) /* Get line from file */ + return get_ch(); + /* + * Free up space used by the (finished) file or macro and restart + * input from the parent file/macro, if any. + */ + infile = file->parent; /* Unwind file chain */ + ACE_OS::free( file->buffer); /* Free buffer */ + if (infile == 0) { /* If at end of input */ + ACE_OS::free( file->filename); + ACE_OS::free( const_cast<char *> (file->src_dir)); + ACE_OS::free( file); /* full_fname is the same with filename for main file*/ + return CHAR_EOF; /* Return end of file */ + } + if (file->fp) { /* Source file included */ + ACE_OS::free( file->filename); /* Free filename */ + ACE_OS::free( const_cast <char *> (file->src_dir)); /* Free src_dir */ + ACE_OS::fclose( file->fp); /* Close finished file */ + /* Do not free file->real_fname and file->full_fname */ + cur_fullname = const_cast <char *> (infile->full_fname); + cur_fname = infile->full_fname; /* Restore current fname*/ + + if (infile->pos != 0L) { /* Includer was closed */ + infile->fp = ACE_OS::fopen( cur_fullname, "r"); + ACE_OS::fseek( infile->fp, infile->pos, SEEK_SET); + } /* Re-open the includer and restore the file-position */ + len = (int) (infile->bptr - infile->buffer); + infile->buffer = (char *) ACE_OS::realloc( infile->buffer, NBUFF); + /* Restore full size buffer to get the next line */ + infile->bptr = infile->buffer + len; + src_line = infile->line; /* Reset line number */ + inc_dirp = infile->dirp; /* Includer's directory */ +#ifdef MCPP_LIB + mcpp_set_out_func( infile->last_fputc, infile->last_fputs, + infile->last_fprintf); +#endif + include_nest--; + src_line++; /* Next line to #include*/ + sharp( 0, infile->include_opt ? 1 : (file->include_opt ? 0 : 2)); + /* Need a #line now. Marker depends on include_opt. */ + /* The file of include_opt should be marked as 1. */ + /* Else if returned from include_opt file, it is the */ + /* main input file, and should not be marked. */ + /* Else, it is normal includer file, and marked as 2. */ + src_line--; + newlines = 0; /* Clear the blank lines*/ + if (mcpp_debug & MACRO_CALL) /* Should be re-initialized */ + com_cat_line.last_line = bsl_cat_line.last_line = 0L; + } else if (file->filename) { /* Expanding macro */ + if (macro_name) /* file->filename should be freed later */ + expanding( file->filename, TRUE); + else + ACE_OS::free( file->filename); + } + ACE_OS::free( file); /* Free file space */ + return get_ch(); /* Get from the parent */ +} + +static char * parse_line( void) +/* + * ANSI (ISO) C: translation phase 3. + * Parse a logical line. + * Check illegal control characters. + * Check unterminated string literal, character constant or comment. + * Convert each comment to one space (or spaces of the comment length on + * 'keep_spaces' mode).. + * Squeeze succeding white spaces other than <newline> (including comments) to + * one space (unless keep_spaces == TRUE). + * The lines might be spliced by comments which cross the lines. + */ +{ + char * temp; /* Temporary buffer */ + char * limit; /* Buffer end */ + char * tp; /* Current pointer into temporary buffer */ + char * sp; /* Pointer into input buffer */ + size_t com_size = 0; + int c; + + if ((sp = get_line( FALSE)) == 0) /* Next logical line */ + return 0; /* End of a file */ + if (in_asm) { /* In #asm block */ + while (char_type[ *sp++ & UCHARMAX] & SPA) + ; + if (*--sp == '#') /* Directive line */ + infile->bptr = sp; + return infile->bptr; /* Don't tokenize */ + } + tp = temp = (char *) ACE_OS::malloc( (size_t) NBUFF); + limit = temp + NBUFF - 2; + + while (char_type[ c = *sp++ & UCHARMAX] & HSP) { + if (mcpp_mode != POST_STD) + /* Preserve line top horizontal white spaces */ + /* as they are for human-readability */ + *tp++ = c; + /* Else skip the line top spaces */ + } + sp--; + + while ((c = *sp++ & UCHARMAX) != '\n') { + + switch (c) { + case '/': + switch (*sp++) { + case '*': /* Start of a comment */ + //com_start: + if ((sp = read_a_comment( sp, &com_size)) == 0) { + ACE_OS::free( temp); /* End of file with un- */ + return 0; /* terminated comment */ + } + if (keep_spaces && mcpp_mode != OLD_PREP) { + if (tp + com_size >= limit - 1) /* Too long comment */ + com_size = limit - tp - 1; /* Truncate */ + while (com_size--) + *tp++ = ' '; /* Spaces of the comment length */ + break; + } + switch (mcpp_mode) { + case POST_STD: + if (temp < tp && *(tp - 1) != ' ') + *tp++ = ' '; /* Squeeze white spaces */ + break; + case OLD_PREP: + if (temp == tp + || ! (char_type[ *(tp - 1) & UCHARMAX] & HSP)) + *tp++ = COM_SEP; /* Convert to magic character */ + break; + default: + if (temp == tp || + ! (char_type[ *(tp - 1) & UCHARMAX] & HSP)) + *tp++ = ' '; /* Squeeze white spaces */ + break; + } + break; + case '/': /* // */ + if (! standard) + goto not_comment; + /* Comment when C++ or __STDC_VERSION__ >= 199901L */ + /* Need not to convert to a space because '\n' follows */ + if (! stdc2 && (warn_level & 2)) + cwarn( "Parsed \"//\" as comment" /* _W2_ */ + , 0, 0L, 0); + if (keep_comments) { + sp -= 2; + while (*sp != '\n') /* Until end of line */ + mcpp_fputc( *sp++, OUT); + } + goto end_line; + default: /* Not a comment */ + not_comment: + *tp++ = '/'; + sp--; /* To re-read */ + break; + } + break; + case '\r': /* Vertical white spaces*/ + /* Note that [CR+LF] is already converted to [LF]. */ + case '\f': + case '\v': + if (warn_level & 4) + cwarn( "Converted %.0s0x%02lx to a space" /* _W4_ */ + , 0, (long) c, 0); + case '\t': /* Horizontal space */ + case ' ': + if (keep_spaces) { + if (c == '\t') + *tp++ = '\t'; + else + *tp++ = ' '; /* Convert to ' ' */ + } else if (! (char_type[ *(tp - 1) & UCHARMAX] & HSP)) { + *tp++ = ' '; /* Squeeze white spaces */ + } else if (mcpp_mode == OLD_PREP && *(tp - 1) == COM_SEP) { + *(tp - 1) = ' '; /* Replace COM_SEP with ' ' */ + } + break; + case '"': /* String literal */ + case '\'': /* Character constant */ + infile->bptr = sp; + if (standard) { + tp = scan_quote( c, tp, limit, TRUE); + } else { + in_string = TRUE; /* Enable line splicing by scan_quote() */ + tp = scan_quote( c, tp, limit, TRUE); /* (not by get_ch())*/ + in_string = FALSE; + } + if (tp == 0) { + ACE_OS::free( temp); /* Unbalanced quotation */ + return parse_line(); /* Skip the line */ + } + sp = infile->bptr; + break; + default: + if (iscntrl( c)) { + cerror( /* Skip the control character */ + "Illegal control character %.0s0x%lx, skipped the character" /* _E_ */ + , 0, (long) c, 0); + } else { /* Any valid character */ + *tp++ = c; + } + break; + } + + if (limit < tp) { + *tp = EOS; + cfatal( "Too long line spliced by comments" /* _F_ */ + , 0, 0L, 0); + } + } + + end_line: + if (temp < tp && (char_type[ *(tp - 1) & UCHARMAX] & HSP)) + tp--; /* Remove trailing white space */ + *tp++ = '\n'; + *tp = EOS; + infile->bptr = ACE_OS::strcpy( infile->buffer, temp); /* Write back to buffer */ + ACE_OS::free( temp); + if (macro_line != 0 && macro_line != MACRO_ERROR) { /* Expanding macro */ + temp = infile->buffer; + while (char_type[ *temp & UCHARMAX] & HSP) + temp++; + if (*temp == '#' /* This line starts with # token */ + || (mcpp_mode == STD && *temp == '%' && *(temp + 1) == ':')) + if (warn_level & 1) + cwarn( + "Macro started at line %.0s%ld swallowed directive-like line" /* _W1_ */ + , 0, macro_line, 0); + } + return infile->buffer; +} + +static char * read_a_comment( + char * sp, /* Source */ + size_t * sizp /* Size of the comment */ + ) +/* + * Read over a comment (which may cross the lines). + */ +{ + int c; + char * saved_sp = 0; + int cat_line = 0; /* Number of catenated lines */ + + if (keep_spaces) { + saved_sp = sp - 2; /* '-2' for beginning / and * */ + *sizp = 0; + } + if (keep_comments) /* If writing comments */ + mcpp_fputs( "/*", OUT); /* Write the initializer*/ + c = *sp++; + + while (1) { /* Eat a comment */ + if (keep_comments) + mcpp_fputc( c, OUT); + + switch (c) { + case '/': + if ((c = *sp++) != '*') /* Don't let comments */ + continue; /* nest. */ + if (warn_level & 1) + cwarn( "\"/*\" within comment", 0, 0L, 0); /* _W1_ */ + if (keep_comments) + mcpp_fputc( c, OUT); + /* Fall into * stuff */ + case '*': + if ((c = *sp++) != '/') /* If comment doesn't */ + continue; /* end, look at next. */ + if (keep_comments) { /* Put out comment */ + mcpp_fputc( c, OUT); /* terminator, too. */ + mcpp_fputc( '\n', OUT); /* Append '\n' to avoid */ + /* trouble on some other tools such as rpcgen. */ + wrong_line = TRUE; + } + if (keep_spaces) /* Save the length */ + *sizp = *sizp + (sp - saved_sp); + if ((mcpp_debug & MACRO_CALL) && compiling) { + if (cat_line) { + cat_line++; + com_cat_line.len[ cat_line] /* Catenated length */ + = com_cat_line.len[ cat_line - 1] + + ACE_OS::strlen( infile->buffer) - 1; + /* '-1' for '\n' */ + com_cat_line.last_line = src_line; + } + } + return sp; /* End of comment */ + case '\n': /* Line-crossing comment*/ + if (keep_spaces) /* Save the length */ + *sizp = *sizp + (sp - saved_sp) - 1; /* '-1' for '\n' */ + if ((mcpp_debug & MACRO_CALL) && compiling) { + /* Save location informations */ + if (cat_line == 0) /* First line of catenation */ + com_cat_line.start_line = src_line; + if (cat_line >= MAX_CAT_LINE - 1) { + *sizp = 0; /* Discard the too long comment */ + cat_line = 0; + if (warn_level & 4) + cwarn( + "Too long comment, discarded up to here" /* _W4_ */ + , 0, 0L, 0); + } + cat_line++; + com_cat_line.len[ cat_line] + = com_cat_line.len[ cat_line - 1] + + ACE_OS::strlen( infile->buffer) - 1; + } + if ((saved_sp = sp = get_line( TRUE)) == 0) + return 0; /* End of file within comment */ + /* Never happen, because at_eof() supplement closing*/ + wrong_line = TRUE; /* We'll need a #line later */ + break; + default: /* Anything else is */ + break; /* just a character */ + } /* End switch */ + + c = *sp++; + } /* End comment loop */ + + return sp; /* Never reach here */ +} + +static char * mcpp_fgets( + char * s, + int size, + FILE * stream + ) +{ + return ACE_OS::fgets( s, size, stream); +} + +static char * get_line( + int in_comment + ) +/* + * ANSI (ISO) C: translation phase 1, 2. + * Get the next logical line from source file. + * Convert [CR+LF] to [LF]. + */ +{ +#if COMPILER == INDEPENDENT +#define cr_warn_level 1 +#else +#define cr_warn_level 2 +#endif + static int cr_converted; + int converted = FALSE; + int len; /* Line length - alpha */ + char * ptr; + int cat_line = 0; /* Number of catenated lines */ + + if (infile == 0) /* End of a source file */ + return 0; + ptr = infile->bptr = infile->buffer; + if ((mcpp_debug & MACRO_CALL) && src_line == 0) /* Initialize */ + com_cat_line.last_line = bsl_cat_line.last_line = 0L; + + while (mcpp_fgets( ptr, (int) (infile->buffer + NBUFF - ptr), infile->fp) + != 0) { + /* Translation phase 1 */ + src_line++; /* Gotten next physical line */ + if (standard && src_line == std_limits.line_num + 1 + && (warn_level & 1)) + cwarn( "Line number %.0s\"%ld\" got beyond range" /* _W1_ */ + , 0, src_line, 0); + if (mcpp_debug & (TOKEN | GETC)) { /* Dump it to DBG */ + mcpp_fprintf( DBG, "\n#line %ld (%s)", src_line, cur_fullname); + dump_string( 0, ptr); + } + len = ACE_OS::strlen( ptr); + if (NBUFF - 1 <= ptr - infile->buffer + len + && *(ptr + len - 1) != '\n') { + /* The line does not yet end, though the buffer is full. */ + if (NBUFF - 1 <= len) + cfatal( "Too long source line" /* _F_ */ + , 0, 0L, 0); + else + cfatal( "Too long logical line" /* _F_ */ + , 0, 0L, 0); + } + if (*(ptr + len - 1) != '\n') /* Unterminated source line */ + break; + if (len >= 2 && *(ptr + len - 2) == '\r') { /* [CR+LF] */ + *(ptr + len - 2) = '\n'; + *(ptr + --len) = EOS; + if (! cr_converted && (warn_level & cr_warn_level)) { + cwarn( "Converted [CR+LF] to [LF]" /* _W1_ _W2_ */ + , 0, 0L, 0); + cr_converted = TRUE; + } + } + if (standard) { + if (option_flags.trig) + converted = cnv_trigraph( ptr); + if (mcpp_mode == POST_STD && option_flags.dig) + converted += cnv_digraph( ptr); + if (converted) + len = ACE_OS::strlen( ptr); + /* Translation phase 2 */ + len -= 2; + if (len >= 0) { + if ((*(ptr + len) == '\\') && ! last_is_mbchar( ptr, len)) { + /* <backslash><newline> (not MBCHAR) */ + ptr = infile->bptr += len; /* Splice the lines */ + wrong_line = TRUE; + if ((mcpp_debug & MACRO_CALL) && compiling) { + /* Save location informations */ + if (cat_line == 0) /* First line of catenation */ + bsl_cat_line.start_line = src_line; + if (cat_line < MAX_CAT_LINE) + /* Record the catenated length */ + bsl_cat_line.len[ ++cat_line] + = ACE_OS::strlen( infile->buffer) - 2; + /* Else ignore */ + } + continue; + } + } +#if NBUFF-2 > SLEN90MIN + if (ptr - infile->buffer + len + 2 > std_limits.str_len + 1 + && (warn_level & 4)) /* +1 for '\n' */ + cwarn( "Logical source line longer than %.0s%ld bytes" /* _W4_ */ + , 0, std_limits.str_len, 0); +#endif + } + if ((mcpp_debug & MACRO_CALL) && compiling) { + if (cat_line && cat_line < MAX_CAT_LINE) { + bsl_cat_line.len[ ++cat_line] = ACE_OS::strlen( infile->buffer) - 1; + /* Catenated length: '-1' for '\n' */ + bsl_cat_line.last_line = src_line; + } + } + return infile->bptr = infile->buffer; /* Logical line */ + } + + /* End of a (possibly included) source file */ + if (ferror( infile->fp)) + cfatal( "File read error", 0, 0L, 0); /* _F_ */ + if ((ptr = at_eof( in_comment)) != 0) /* Check at end of file */ + return ptr; /* Partial line supplemented */ + if (option_flags.z) { + no_output--; /* End of included file */ + keep_comments = option_flags.c && compiling && !no_output; + } + return 0; +} + +#define TRIOFFSET 10 + +int cnv_trigraph( + char * in + ) +/* + * Perform in-place trigraph replacement on a physical line. This was added + * to the C90. In an input text line, the sequence ??[something] is + * transformed to a character (which might not appear on the input keyboard). + */ +{ + const char * const tritext = "=(/)'<!>-\0#[\\]^{|}~"; + /* ^ ^ + * +----------+ + * this becomes this + */ + int count = 0; + const char * tp; + + while ((in = ACE_OS::strchr( in, '?')) != 0) { + if (*++in != '?') + continue; + while (*++in == '?') + ; + if ((tp = ACE_OS::strchr( tritext, *in)) == 0) + continue; + *(in - 2) = *(tp + TRIOFFSET); + in--; + ACE_OS::memmove( in, in + 2, ACE_OS::strlen( in + 1)); + count++; + } + + if (count && (warn_level & 16)) + cwarn( "%.0s%ld trigraph(s) converted" /* _W16_ */ + , 0, (long) count, 0); + return count; +} + +int cnv_digraph( + char * in + ) +/* + * Perform in-place digraph replacement on a physical line. + * Called only in POST_STD mode. + */ +{ + int count = 0; + int i; + int c1, c2; + + while ((i = ACE_OS::strcspn( in, "%:<")), (c1 = *(in + i)) != '\0') { + in += i + 1; + c2 = *in; + switch (c1) { + case '%' : + switch (c2) { + case ':' : *(in - 1) = '#'; break; + case '>' : *(in - 1) = '}'; break; + default : continue; + } + break; + case ':' : + switch (c2) { + case '>' : *(in - 1) = ']'; break; + default : continue; + } + break; + case '<' : + switch (c2) { + case '%' : *(in - 1) = '{'; break; + case ':' : *(in - 1) = '['; break; + default : continue; + } + break; + } + ACE_OS::memmove( in, in + 1, ACE_OS::strlen( in)); + count++; + } + + if (count && (warn_level & 16)) + cwarn( "%.0s%ld digraph(s) converted" /* _W16_ */ + , 0, (long) count, 0); + return count; +} + +static char * at_eof( + int in_comment + ) +/* + * Check the partial line, unterminated comment, unbalanced #if block, + * uncompleted macro call at end of a file or at end of input. + * Supplement the line terminator, if possible. + * Return the supplemented line or 0 on unrecoverable error. + */ +{ + const char * const format + = "End of %s with %.0ld%s"; /* _E_ _W1_ */ + const char * const unterm_if_format + = "End of %s within #if (#ifdef) section started at line %ld"; /* _E_ _W1_ */ + const char * const unterm_macro_format + = "End of %s within macro call started at line %ld";/* _E_ _W1_ */ + const char * const input + = infile->parent ? "file" : "input"; /* _E_ _W1_ */ + const char * const no_newline + = "no newline, supplemented newline"; /* _W1_ */ + const char * const unterm_com + = "unterminated comment, terminated the comment"; /* _W1_ */ + const char * const backsl = "\\, deleted the \\"; /* _W1_ */ + const char * const unterm_asm_format + = "End of %s with unterminated #asm block started at line %ld"; /* _E_ _W1_ */ + size_t len; + char * cp; + + cp = infile->buffer; + len = ACE_OS::strlen( cp); + if (len && *(cp += (len - 1)) != '\n') { + *++cp = '\n'; /* Supplement <newline> */ + *++cp = EOS; + if (mcpp_mode != OLD_PREP && (warn_level & 1)) + cwarn( format, input, 0L, no_newline); + return infile->bptr = infile->buffer; + } + if (standard && infile->buffer < infile->bptr) { + /* No line after <backslash><newline> */ + cp = infile->bptr; + *cp++ = '\n'; /* Delete the \\ */ + *cp = EOS; + if (warn_level & 1) + cwarn( format, input, 0L, backsl); + return infile->bptr = infile->buffer; + } + if (in_comment) { /* End of file within a comment */ + if (mcpp_mode != OLD_PREP && (warn_level & 1)) + cwarn( format, input, 0L, unterm_com); + /* The partial comment line has been already read by */ + /* read_a_comment(), so supplement the next line. */ + ACE_OS::strcpy( infile->buffer, "*/\n"); + return infile->bptr = infile->buffer; + } + + if (infile->initif < ifptr) { + IFINFO * ifp = infile->initif + 1; + if (standard) { + cerror( unterm_if_format, input, ifp->ifline, 0); + ifptr = infile->initif; /* Clear information of */ + compiling = ifptr->stat; /* erroneous grouping */ + } else if (mcpp_mode == KR && (warn_level & 1)) { + cwarn( unterm_if_format, input, ifp->ifline, 0); + } + } + + if (macro_line != 0 && macro_line != MACRO_ERROR + && ((mcpp_mode == STD && in_getarg) || ! standard)) { + if (standard) { + cerror( unterm_macro_format, input, macro_line, 0); + macro_line = MACRO_ERROR; + } else if (warn_level & 1) { + cwarn( unterm_macro_format, input, macro_line, 0); + } + } + + if (in_asm && mcpp_mode == KR && (warn_level & 1)) + cwarn( unterm_asm_format, input, in_asm, 0); + + return 0; +} + +void unget_ch( void) +/* + * Back the pointer to reread the last character. Fatal error (code bug) + * if we back too far. unget_ch() may be called, without problems, at end of + * file. Only one character may be ungotten. If you need to unget more, + * call unget_string(). + */ +{ + if (in_token) { + infile->bptr--; + return; + } + + if (infile != 0) { + if (mcpp_mode == POST_STD && infile->fp) { + switch (insert_sep) { + case INSERTED_SEP: /* Have just read an inserted separator */ + insert_sep = INSERT_SEP; + return; + case INSERT_SEP: + cfatal( "Bug: unget_ch() just after scan_token()" /* _F_ */ + , 0, 0L, 0); + break; + default: + break; + } + } + --infile->bptr; + if (infile->bptr < infile->buffer) /* Shouldn't happen */ + cfatal( "Bug: Too much pushback", 0, 0L, 0); /* _F_ */ + } + + if (mcpp_debug & GETC) + dump_unget( "after unget"); +} + +FILEINFO * unget_string( + const char * text, /* Text to unget */ + const char * name /* Name of the macro, if any*/ + ) +/* + * Push a string back on the input stream. This is done by treating + * the text as if it were a macro or a file. + */ +{ + FILEINFO * file; + size_t size; + + if (text) + size = ACE_OS::strlen( text) + 1; + else + size = 1; + file = get_file( name, 0, 0, size, FALSE); + if (text) + ACE_OS::memcpy( file->buffer, text, size); + else + *file->buffer = EOS; + return file; +} + +char * save_string( + const char * text + ) +/* + * Store a string into free memory. + */ +{ + char * result; + size_t size; + + size = ACE_OS::strlen( text) + 1; + result = (char *) ACE_OS::malloc( size); + ACE_OS::memcpy( result, text, size); + return result; +} + +FILEINFO * get_file( + const char * name, /* File or macro name */ + const char * src_dir, /* Source file directory*/ + const char * fullname, /* Full path list */ + size_t bufsize, /* Line buffer size */ + int include_opt /* Specified by -include opt (for GCC) */ + ) +/* + * Common FILEINFO buffer initialization for a new file or macro. + */ +{ + FILEINFO * file; + + file = (FILEINFO *) ACE_OS::malloc( sizeof (FILEINFO)); + file->buffer = (char *) ACE_OS::malloc( bufsize); + file->bptr = file->buffer; /* Initialize line ptr */ + file->buffer[ 0] = EOS; /* Force first read */ + file->line = 0L; /* (Not used just yet) */ + file->fp = 0; /* No file yet */ + file->pos = 0L; /* No pos to remember */ + file->parent = infile; /* Chain files together */ + file->initif = ifptr; /* Initial ifstack */ + file->include_opt = include_opt; /* Specified by -include*/ + file->dirp = 0; /* No include dir yet */ + file->real_fname = name; /* Save file/macro name */ + file->full_fname = fullname; /* Full path list */ + if (name) { + file->filename = (char *) ACE_OS::malloc( ACE_OS::strlen( name) + 1); + ACE_OS::strcpy( file->filename, name); /* Copy for #line */ + } else { + file->filename = 0; + } + if (src_dir) { + file->src_dir = (char *) ACE_OS::malloc( ACE_OS::strlen( src_dir) + 1); + ACE_OS::strcpy( const_cast <char *> (file->src_dir), src_dir); + } else { + file->src_dir = 0; + } +#ifdef MCPP_LIB + file->last_fputc = mcpp_lib_fputc; + file->last_fputs = mcpp_lib_fputs; + file->last_fprintf = mcpp_lib_fprintf; +#endif + if (infile != 0) { /* If #include file */ + infile->line = src_line; /* Save current line */ +#ifdef MCPP_LIB + infile->last_fputc = mcpp_fputc; + infile->last_fputs = mcpp_fputs; + infile->last_fprintf = mcpp_fprintf; +#endif + } + infile = file; /* New current file */ + + return file; /* All done. */ +} + +static const char * const out_of_memory += "Out of memory (required size is %.0s0x%lx bytes)"; /* _F_ */ + +// char * +// malloc( +// size_t size +// ) +// /* +// * Get a block of free memory. +// */ +// { +// char * result; + +// if ((result = (char *) ACE_OS::malloc( size)) == 0) { +// if (mcpp_debug & MEMORY) +// print_heap(); +// cfatal( out_of_memory, 0, (long) size, 0); +// } +// return result; +// } + +// char * (ACE_OS::realloc)( +// char * ptr, +// size_t size +// ) +// /* +// * Reallocate ACE_OS::malloc()ed memory. +// */ +// { +// char * result; + +// if ((result = (char *) ACE_OS::realloc( ptr, size)) == 0 && size != 0) { +// /* 'size != 0' is necessary to cope with some */ +// /* implementation of realloc( ptr, 0) which returns 0. */ +// if (mcpp_debug & MEMORY) +// print_heap(); +// cfatal( out_of_memory, 0, (long) size, 0); +// } +// return result; +// } + +LINE_COL * get_src_location( + LINE_COL * p_line_col /* Line and column on phase 4 */ + ) +/* + * Convert line-column datum of just after translation phase 3 into that of + * phase 2, tracing back line splicing by a comment and <backslash><newline>. + * Note: This conversion does not give correct datum on a line catenated by + * both of <backslash><newline> and line-crossing-comment at the same time. + * + * com_cat_line and bsl_cat_line have data only on last catenated line. + * com_cat_line.len[] and bsl_cat_line.len[] have the length of catenated + * line, and len[ 0] is always 0, followed by len[ 1], len[ 2], ..., as + * accumulated length of successively catenated lines. + */ +{ + long line; + size_t col; + size_t * cols; + CAT_LINE * l_col_p; + int i; + + line = p_line_col->line; + col = p_line_col->col; + + for (i = 0; i <= 1; i++) { + l_col_p = i ? & bsl_cat_line : & com_cat_line; + if (l_col_p->last_line != line) + continue; + /* Else just catenated line */ + cols = l_col_p->len + 1; + while (*cols < col) + cols++; + if (col <= *cols) { + cols--; + col -= *cols; + } + line = l_col_p->start_line + (cols - l_col_p->len); + } + + p_line_col->line = line; + p_line_col->col = col + 1; + /* col internally start at 0, output start at 1 */ + + return p_line_col; +} + +static void put_line( + char * out, + FILE * fp + ) +/* + * Put out a logical source line. + * This routine is called only in OLD_PREP mode. + */ +{ + int c; + + while ((c = *out++) != EOS) { + if (c != COM_SEP) /* Skip 0-length comment */ + mcpp_fputc( c, FP2DEST( fp)); + } +} + +static void do_msg( + const char * severity, /* "fatal", "error", "warning" */ + const char * format, /* Format for the error message */ + const char * arg1, /* String arg. for the message */ + long arg2, /* Integer argument */ + const char * arg3 /* Second string argument */ + ) +/* + * Print filenames, macro names, line numbers and error messages. + * Also print macro definitions on macro expansion problems. + */ +{ + FILEINFO * file; + DEFBUF * defp; + int i; + size_t slen; + const char * arg_s[ 2]; + char * arg_t[ 2]; + char * tp; + const char * sp; + int c; + int ind; + + ACE_OS::fflush( fp_out); /* Synchronize output and diagnostics */ + arg_s[ 0] = arg1; arg_s[ 1] = arg3; + + for (i = 0; i < 2; i++) { /* Convert special characters to visible */ + sp = arg_s[ i]; + if (sp != 0) + slen = ACE_OS::strlen( sp) + 1; + else + slen = 1; + tp = arg_t[ i] = (char *) ACE_OS::malloc( slen); + /* Don't use ACE_OS::malloc() so as not to cause infinite recursion */ + if (sp == 0 || *sp == EOS) { + *tp = EOS; + continue; + } + + while ((c = *sp++) != EOS) { + switch (c) { + case TOK_SEP: + if (mcpp_mode == OLD_PREP) /* COM_SEP */ + break; /* Skip magic characters */ + /* Else fall through */ + case RT_END: + case CAT: + case ST_QUOTE: + case DEF_MAGIC: + if (! standard) + *tp++ = ' '; + break; /* Skip the magic characters*/ + case IN_SRC: + if (! standard) + *tp++ = ' '; + if ((mcpp_debug & MACRO_CALL) && ! in_directive) + sp += 2; /* Skip two more bytes */ + break; + case MAC_INF: + if (mcpp_mode != STD) { + *tp++ = ' '; + /* Illegal control character, convert to a space*/ + } else { + switch (*sp++) { /* Skip the magic characters*/ + case MAC_ARG_START : + sp++; + /* Fall through */ + case MAC_CALL_START : + sp += 2; + break; + case MAC_ARG_END : + if (! option_flags.v) + break; + else + sp++; + /* Fall through */ + case MAC_CALL_END : + if (option_flags.v) + sp += 2; + break; + } + } + break; + case '\n': + *tp++ = ' '; /* Convert '\n' to a space */ + break; + default: + *tp++ = c; + break; + } + } + + if (*(sp - 2) == '\n') + tp--; + *tp = EOS; + } + + /* Print source location and diagnostic */ + file = infile; + while (file != 0 && (file->fp == 0 || file->fp == (FILE *)-1)) + file = file->parent; /* Skip macro */ + if (file != 0) { + file->line = src_line; + mcpp_fprintf( ERR, "%s:%ld: %s: ", cur_fullname, src_line, severity); + } + mcpp_fprintf( ERR, format, arg_t[ 0], arg2, arg_t[ 1]); + mcpp_fputc( '\n', ERR); + if (option_flags.no_source_line) + goto free_arg; + + /* Print source line, includers and expanding macros */ + file = infile; + if (file != 0 && file->fp != 0) { + if (mcpp_mode == OLD_PREP) { + mcpp_fputs( " ", ERR); + put_line( file->buffer, fp_err); + } else { + mcpp_fprintf( ERR, " %s", file->buffer); + /* Current source line */ + } + file = file->parent; + } + while (file != 0) { /* Print #includes, too */ + if (file->fp == 0) { /* Macro */ + if (file->filename) { + defp = look_id( file->filename); + if ((defp->nargs > DEF_NOARGS_STANDARD) + && ! (file->parent && file->parent->filename + && str_eq( file->filename, file->parent->filename))) + /* If the name is not duplicate of parent */ + dump_a_def( " macro", defp, FALSE, TRUE, fp_err); + } + } else { /* Source file */ + if (file->buffer[ 0] == '\0') + ACE_OS::strcpy( file->buffer, "\n"); + if (mcpp_mode != OLD_PREP) { + mcpp_fprintf( ERR, " from %s: %ld: %s", + file->line ? file->full_fname /* Full-path-list */ + : "<stdin>", /* Included by -include */ + file->line, /* Current line number */ + file->buffer); /* The source line */ + } else { + mcpp_fprintf( ERR, " from %s: %ld: ", file->full_fname + , file->line); + put_line( file->buffer, fp_err); + } + } + file = file->parent; + } + + if (! macro_name) + goto free_arg; + /* Additional information of macro definitions */ + expanding_macro[ 0].name = macro_name; + for (ind = 0; ind <= exp_mac_ind; ind++) { + int ind_done; + + for (ind_done = 0; ind_done < ind; ind_done++) + if (str_eq( expanding_macro[ ind].name + , expanding_macro[ ind_done].name)) + break; /* Already reported */ + if (ind_done < ind) + continue; + for (file = infile; file; file = file->parent) + if (file->fp == 0 && file->filename + && str_eq( expanding_macro[ ind].name, file->filename)) + break; /* Already reported */ + if (file) + continue; + if ((defp = look_id( expanding_macro[ ind].name)) != 0) { + if (defp->nargs <= DEF_NOARGS_STANDARD) + continue; /* Standard predefined */ + dump_a_def( " macro", defp, FALSE, TRUE, fp_err); + /* Macro already read over */ + } + } + + free_arg: + for (i = 0; i < 2; i++) + ACE_OS::free( arg_t[ i]); +} + +void cfatal( + const char * format, + const char * arg1, + long arg2, + const char * arg3 + ) +/* + * A real disaster. + */ +{ + do_msg( "fatal error", format, arg1, arg2, arg3); + longjmp( error_exit, -1); +} + +void cerror( + const char * format, + const char * arg1, + long arg2, + const char * arg3 + ) +/* + * Print a error message. + */ +{ + do_msg( "error", format, arg1, arg2, arg3); + errors++; +} + +void cwarn( + const char * format, + const char * arg1, + long arg2, + const char * arg3 + ) +/* + * Maybe an error. + */ +{ + do_msg( "warning", format, arg1, arg2, arg3); +} + +void dump_string( + const char * why, + const char * text + ) +/* + * Dump text readably. + * Bug: macro argument number may be putout as a control character or any + * other character, just after MAC_PARM has been read away. + */ +{ + const char * cp; + const char * chr; + int c, c1, c2; + + if (why != 0) + mcpp_fprintf( DBG, " (%s)", why); + mcpp_fputs( " => ", DBG); + + if (text == 0) { + mcpp_fputs( "0", DBG); + return; + } + + for (cp = text; (c = *cp++ & UCHARMAX) != EOS; ) { + chr = 0; + + switch (c) { + case MAC_PARM: + c = *cp++ & UCHARMAX; /* Macro parameter number */ + mcpp_fprintf( DBG, "<%d>", c); + break; + case MAC_INF: + if (! (mcpp_mode == STD && (mcpp_debug & MACRO_CALL))) + goto no_magic; + /* Macro informations inserted by -K option */ + c2 = *cp++ & UCHARMAX; + if (option_flags.v || c2 == MAC_CALL_START + || c2 == MAC_ARG_START) { + c = ((*cp++ & UCHARMAX) - 1) * UCHARMAX; + c += (*cp++ & UCHARMAX) - 1; + } + switch (c2) { + case MAC_CALL_START: + mcpp_fprintf( DBG, "<MAC%d>", c); + break; + case MAC_CALL_END: + if (option_flags.v) + mcpp_fprintf( DBG, "<MAC_END%d>", c); + else + chr = "<MAC_END>"; + break; + case MAC_ARG_START: + c1 = *cp++ & UCHARMAX; + mcpp_fprintf( DBG, "<MAC%d:ARG%d>", c, c1 - 1); + break; + case MAC_ARG_END: + if (option_flags.v) { + c1 = *cp++ & UCHARMAX; + mcpp_fprintf( DBG, "<ARG_END%d-%d>", c, c1 - 1); + } else { + chr = "<ARG_END>"; + } + break; + } + break; + case DEF_MAGIC: + if (standard) { + chr = "<MAGIC>"; + break; + } /* Else fall through */ + case CAT: + if (standard) { + chr = "##"; + break; + } /* Else fall through */ + case ST_QUOTE: + if (standard) { + chr = "#"; + break; + } /* Else fall through */ + case RT_END: + if (standard) { + chr = "<RT_END>"; + break; + } /* Else fall through */ + case IN_SRC: + if (standard) { + if ((mcpp_debug & MACRO_CALL) && ! in_directive) { + int num; + num = ((*cp++ & UCHARMAX) - 1) * UCHARMAX; + num += (*cp++ & UCHARMAX) - 1; + mcpp_fprintf( DBG, "<SRC%d>", num); + } else { + chr = "<SRC>"; + } + } else { /* Control character */ + mcpp_fprintf( DBG, "<^%c>", c + '@'); + } + break; + case TOK_SEP: + if (mcpp_mode == STD) { + chr = "<TSEP>"; + break; + } else if (mcpp_mode == OLD_PREP) { /* COM_SEP */ + chr = "<CSEP>"; + break; + } /* Else fall through */ + default: + no_magic: + if (c < ' ') + mcpp_fprintf( DBG, "<^%c>", c + '@'); + else + mcpp_fputc( c, DBG); + break; + } + + if (chr) + mcpp_fputs( chr, DBG); + } + + mcpp_fputc( '\n', DBG); +} + +void dump_unget( + const char * why + ) +/* + * Dump all ungotten junk (pending macros and current input lines). + */ +{ + const FILEINFO * file; + + mcpp_fputs( "dump of pending input text", DBG); + if (why != 0) { + mcpp_fputs( "-- ", DBG); + mcpp_fputs( why, DBG); + } + mcpp_fputc( '\n', DBG); + + for (file = infile; file != 0; file = file->parent) + dump_string( file->real_fname ? file->real_fname + : file->filename ? file->filename : "0", file->bptr); +} + +static void dump_token( + int token_type, + const char * cp /* Token */ + ) +/* + * Dump a token. + */ +{ + static const char * const t_type[] + = { "NAM", "NUM", "STR", "WSTR", "CHR", "WCHR", "OPE", "SPE" + , "SEP", }; + + mcpp_fputs( "token", DBG); + dump_string( t_type[ token_type - NAM], cp); +} + |