[BACK]Return to expand.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib2 / windows / mcpp

Annotation of OpenXM_contrib2/windows/mcpp/expand.c, Revision 1.1

1.1     ! ohara       1: /* $OpenXM$ */
        !             2: /*-
        !             3:  * Copyright (c) 1998, 2002-2008 Kiyoshi Matsui <kmatsui@t3.rim.or.jp>
        !             4:  * All rights reserved.
        !             5:  *
        !             6:  * Some parts of this code are derived from the public domain software
        !             7:  * DECUS cpp (1984,1985) written by Martin Minow.
        !             8:  *
        !             9:  * Redistribution and use in source and binary forms, with or without
        !            10:  * modification, are permitted provided that the following conditions
        !            11:  * are met:
        !            12:  * 1. Redistributions of source code must retain the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer.
        !            14:  * 2. Redistributions in binary form must reproduce the above copyright
        !            15:  *    notice, this list of conditions and the following disclaimer in the
        !            16:  *    documentation and/or other materials provided with the distribution.
        !            17:  *
        !            18:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
        !            19:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            20:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            21:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
        !            22:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            23:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            24:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            25:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            26:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            27:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            28:  * SUCH DAMAGE.
        !            29:  */
        !            30:
        !            31: /*
        !            32:  *                          E X P A N D . C
        !            33:  *                  M a c r o   E x p a n s i o n
        !            34:  *
        !            35:  * The macro expansion routines are placed here.
        !            36:  */
        !            37:
        !            38: #if PREPROCESSED
        !            39: #include    "mcpp.H"
        !            40: #else
        !            41: #include    "system.H"
        !            42: #include    "internal.H"
        !            43: #endif
        !            44:
        !            45: #define ARG_ERROR   (-255)
        !            46: #define CERROR      1
        !            47: #define CWARN       2
        !            48:
        !            49: typedef struct location {           /* Where macro or arg locate    */
        !            50:     long            start_line;                 /* Beginning at 1   */
        !            51:     size_t          start_col;                  /* Beginning at 0   */
        !            52:     long            end_line;
        !            53:     size_t          end_col;
        !            54: } LOCATION;
        !            55: typedef struct magic_seq {  /* Data of a sequence inserted between tokens   */
        !            56:     char *          magic_start;        /* First MAC_INF sequence   */
        !            57:     char *          magic_end;          /* End of last MAC_INF seq  */
        !            58:     int             space;              /* Space succeeds or not    */
        !            59: } MAGIC_SEQ;
        !            60:
        !            61: static int      compat_mode;
        !            62: /* Expand recursive macro more than Standard (for compatibility with GNUC)  */
        !            63: #if COMPILER == GNUC
        !            64: static int      ansi;                   /* __STRICT_ANSI__ flag     */
        !            65: #endif
        !            66:
        !            67: static char *   expand_std( DEFBUF * defp, char * out, char * out_end
        !            68:         , LINE_COL line_col, int * pragma_op);
        !            69:                 /* Expand a macro completely (for Standard modes)   */
        !            70: static char *   expand_prestd( DEFBUF * defp, char * out, char * out_end
        !            71:         , LINE_COL line_col, int * pragma_op);
        !            72:                 /* Expand a macro completely (for pre-Standard modes)       */
        !            73: static DEFBUF * is_macro_call( DEFBUF * defp, char ** cp, char ** endf
        !            74:         , MAGIC_SEQ * mgc_seq);         /* Is this really a macro call ?    */
        !            75: static int      collect_args( const DEFBUF * defp, char ** arglist, int m_num);
        !            76:                 /* Collect arguments of a macro call*/
        !            77: static int      get_an_arg( int c, char ** argpp, char * arg_end
        !            78:         , char ** seqp, int var_arg, int nargs, LOCATION ** locp, int m_num
        !            79:         , MAGIC_SEQ * mgc_prefix);      /* Get an argument          */
        !            80: static int      squeeze_ws( char ** out, char ** endf, MAGIC_SEQ * mgc_seq);
        !            81:                 /* Squeeze white spaces to a space  */
        !            82: static void     skip_macro( void);
        !            83:                 /* Skip the rest of macro call      */
        !            84: static void     diag_macro( int severity, const char * format
        !            85:         , const char * arg1, long arg2, const char * arg3, const DEFBUF * defp1
        !            86:         , const DEFBUF * defp2) ;
        !            87:                 /* Supplement diagnostic information*/
        !            88: static void     dump_args( const char * why, int nargs, const char ** arglist);
        !            89:                 /* Dump arguments list              */
        !            90:
        !            91: static int      rescan_level;           /* Times of macro rescan    */
        !            92:
        !            93: static const char * const   macbuf_overflow
        !            94:         = "Buffer overflow expanding macro \"%s\" at %.0ld\"%s\"";  /* _E_  */
        !            95: static const char * const   empty_arg
        !            96:         = "Empty argument in macro call \"%s\"";            /* _W2_ */
        !            97: static const char * const   unterm_macro
        !            98:         = "Unterminated macro call \"%s\"";                 /* _E_  */
        !            99: static const char * const   narg_error
        !           100:     = "%s than necessary %ld argument(s) in macro call \"%s\""; /* _E_ _W1_ */
        !           101: static const char * const   only_name
        !           102:         = "Macro \"%s\" needs arguments";                   /* _W8_ */
        !           103:
        !           104: void     expand_init(
        !           105:     int     compat,     /* "Compatible" to GNUC expansion of recursive macro*/
        !           106:     int     strict_ansi         /* __STRICT_ANSI__ flag for GNUC    */
        !           107: )
        !           108: /* Set expand_macro() function  */
        !           109: {
        !           110:     expand_macro = standard ? expand_std : expand_prestd;
        !           111:     compat_mode = compat;
        !           112: #if COMPILER == GNUC
        !           113:     ansi = strict_ansi;
        !           114: #endif
        !           115: }
        !           116:
        !           117: DEFBUF *    is_macro(
        !           118:     char **     cp
        !           119: )
        !           120: /*
        !           121:  * The name is already in 'identifier', the next token is not yet read.
        !           122:  * Return the definition info if the name is a macro call, else return NULL.
        !           123:  */
        !           124: {
        !           125:     DEFBUF *    defp;
        !           126:
        !           127:     if ((defp = look_id( identifier)) != NULL)  /* Is a macro name  */
        !           128:         return  is_macro_call( defp, cp, NULL, NULL);
        !           129:     else
        !           130:         return  NULL;
        !           131: }
        !           132:
        !           133: static DEFBUF * is_macro_call(
        !           134:     DEFBUF *    defp,
        !           135:     char **     cp,                     /* Pointer to output buffer */
        !           136:     char **     endf,   /* Pointer to indicate end of infile buffer */
        !           137:     MAGIC_SEQ * mgc_seq /* Infs on MAC_INF sequences and space      */
        !           138: )
        !           139: /*
        !           140:  * Return DEFBUF if the defp->name is a macro call, else return NULL.
        !           141:  */
        !           142: {
        !           143:     int     c;
        !           144:
        !           145:     if (defp->nargs >= 0                    /* Function-like macro  */
        !           146:             || defp->nargs == DEF_PRAGMA) { /* _Pragma() pseudo-macro       */
        !           147:         c = squeeze_ws( cp, endf, mgc_seq); /* See the next char.   */
        !           148:         if (c == CHAR_EOF)                  /* End of file          */
        !           149:             unget_string( "\n", NULL);      /* Restore skipped '\n' */
        !           150:         else if (! standard || c != RT_END)
        !           151:                         /* Still in the file and rescan boundary ?  */
        !           152:             unget_ch();                     /* To see it again      */
        !           153:         if (c != '(') {     /* Only the name of function-like macro */
        !           154:             if (! standard && warn_level & 8)
        !           155:                 cwarn( only_name, defp->name, 0L, NULL);
        !           156:             return  NULL;
        !           157:         }
        !           158:     }
        !           159:     return  defp;                           /* Really a macro call  */
        !           160: }
        !           161:
        !           162: /*
        !           163:  * expand_macro()   expands a macro call completely, and writes out the result
        !           164:  *      to the specified output buffer and returns the advanced pointer.
        !           165:  */
        !           166:
        !           167:
        !           168: /*
        !           169:  *          T h e   S T A N D A R D   C o n f o r m i n g   M o d e
        !           170:  *                  o f   M a c r o   E x p a n s i o n
        !           171:  *
        !           172:  * 1998/08      First released.     kmatsui
        !           173:  */
        !           174:
        !           175: /* For debug of -K option: should be turned off on release version. */
        !           176: #define DEBUG_MACRO_ANN     FALSE
        !           177:
        !           178: /* Return value of is_able_repl()   */
        !           179: #define NO          0               /* "Blue-painted"               */
        !           180: #define YES         1               /* Not blue-painted             */
        !           181: #define READ_OVER   2
        !           182:             /* Still "blue-painted", yet has read over repl-list    */
        !           183:
        !           184: /*
        !           185:  * Macros related to macro notification mode.
        !           186:  * The macro notification routines are hacks on the normal processing
        !           187:  * routines, and very complicated and cumbersome.  Be sure to keep symmetry
        !           188:  * of starting and closing magic sequences.  Enable the routines enclosed
        !           189:  * by #if 0 - #endif for debugging.
        !           190:  * Any byte in the sequences beginning with MAC_INF can coincide with any
        !           191:  * other character.  Hence, the data stream should be read from the top,
        !           192:  * not from the tail, in principle.
        !           193:  */
        !           194: /* Length of sequence of MAC_INF, MAC_CALL_START, mac_num-1, mac_num-2  */
        !           195: #define MAC_S_LEN   4
        !           196: /* Length of sequence of MAC_INF, MAC_ARG_START, mac_num1, mac_num2, arg-num*/
        !           197: #define ARG_S_LEN   5
        !           198: #define MAC_E_LEN   2   /* Length of MAC_INF, MAC_CALL_END sequence */
        !           199: #define ARG_E_LEN   MAC_E_LEN   /* Lenght of MAC_INF, MAC_ARG_END sequence  */
        !           200: #define MAC_E_LEN_V 4   /* Length of macro closing sequence in verbose mode */
        !           201:                         /* MAC_INF, MAC_CALL_END, mac_num1, mac_num2        */
        !           202: #define ARG_E_LEN_V 5   /* Length of argument closing sequence in verbose   */
        !           203:                     /* MAC_INF, MAC_ARG_END, mac_num1, mac_num2, arg_num    */
        !           204: #define IN_SRC_LEN  3   /* Length of sequence of IN_SRC, num-1, num-2   */
        !           205: #define INIT_MAC_INF        0x100   /* Initial num of elements in mac_inf[] */
        !           206: #define MAX_MAC_INF         0x1000  /* Maximum num of elements in mac_inf[] */
        !           207: #define INIT_IN_SRC_NUM     0x100   /* Initial num of elements in in_src[]  */
        !           208: #define MAX_IN_SRC_NUM      0x1000  /* Maximum num of elements in in_src[]  */
        !           209:
        !           210: /* Variables for macro notification mode    */
        !           211: typedef struct macro_inf {              /* Informations of a macro  */
        !           212:     const DEFBUF *  defp;               /* Definition of the macro  */
        !           213:     char *          args;               /* Arguments, if any        */
        !           214:     int             num_args;           /* Number of real arguments */
        !           215:     int             recur;              /* Recurrence of this macro */
        !           216:     LOCATION        locs;               /* Location of macro call   */
        !           217:     LOCATION *      loc_args;           /* Location of arguments    */
        !           218: } MACRO_INF;
        !           219: static MACRO_INF *  mac_inf;
        !           220: static int      max_mac_num;        /* Current num of elements in mac_inf[] */
        !           221: static int      mac_num;                /* Index into mac_inf[]     */
        !           222: static LOCATION *   in_src; /* Location of identifiers in macro arguments   */
        !           223: static int      max_in_src_num;     /* Current num of elements in in_src[]  */
        !           224: static int      in_src_num;             /* Index into in_src[]      */
        !           225: static int      trace_macro;        /* Enable to trace macro infs   */
        !           226:
        !           227: static struct {
        !           228:     const DEFBUF *  def;            /* Macro definition             */
        !           229:     int             read_over;      /* Has read over repl-list      */
        !           230:     /* 'read_over' is never used in POST_STD mode and in compat_mode*/
        !           231: } replacing[ RESCAN_LIMIT];         /* Macros currently replacing   */
        !           232: static int      has_pragma = FALSE;     /* Flag of _Pragma() operator       */
        !           233:
        !           234: static int      print_macro_inf( int c, char ** cpp, char ** opp);
        !           235:                 /* Embed macro infs into comments   */
        !           236: static char *   print_macro_arg( char *out, MACRO_INF * m_inf, int argn
        !           237:         , int real_arg, int start);
        !           238:                 /* Embed macro arg inf into comments*/
        !           239: static char *   chk_magic_balance( char * buf, char * buf_end, int move
        !           240:         , int diag);    /* Check imbalance of magics        */
        !           241: static char *   replace( DEFBUF * defp, char * out, char * out_end
        !           242:         , const DEFBUF * outer, FILEINFO * rt_file, LINE_COL line_col
        !           243:         , int in_src_n);
        !           244:                 /* Replace a macro recursively      */
        !           245: static char *   close_macro_inf( char *  out_p, int m_num, int in_src_n);
        !           246:                 /* Put closing mark for a macro call*/
        !           247: static DEFBUF * def_special( DEFBUF * defp);
        !           248:                 /* Re-define __LINE__, __FILE__     */
        !           249: static int      prescan( const DEFBUF * defp, const char ** arglist
        !           250:         , char * out, char * out_end);
        !           251:                 /* Process #, ## operator           */
        !           252: static char *   catenate( const DEFBUF * defp, const char ** arglist
        !           253:         , char * out, char * out_end, char ** token_p);
        !           254:                 /* Catenate tokens                  */
        !           255: static const char * remove_magics( const char * argp, int from_last);
        !           256:                 /* Remove pair of magic characters  */
        !           257: #if DEBUG_MACRO_ANN
        !           258: static void     chk_symmetry( char *  start_id, char *  end_id, size_t  len);
        !           259:                 /* Check if a pair of magics are symmetrical    */
        !           260: #endif
        !           261: static char *   stringize( const DEFBUF * defp, const char * argp, char * out);
        !           262:                 /* Stringize an argument            */
        !           263: static char *   substitute( const DEFBUF * defp, const char ** arglist
        !           264:         , const char * in, char * out, char * out_end);
        !           265:                 /* Substitute parms with arguments  */
        !           266: static char *   rescan( const DEFBUF * outer, const char * in, char * out
        !           267:         , char * out_end);
        !           268:                 /* Rescan once replaced sequences   */
        !           269: static int      disable_repl( const DEFBUF * defp);
        !           270:                 /* Disable the macro once replaced  */
        !           271: static void     enable_repl( const DEFBUF * defp, int done);
        !           272:                 /* Enable the macro for later use   */
        !           273: static int      is_able_repl( const DEFBUF * defp);
        !           274:                 /* Is the macro allowed to replace? */
        !           275: static char *   insert_to_bptr( char * ins, size_t len);
        !           276:                 /* Insert a sequence into infile->bptr  */
        !           277:
        !           278: static char *   expand_std(
        !           279:     DEFBUF *    defp,                       /* Macro definition     */
        !           280:     char *  out,                            /* Output buffer        */
        !           281:     char *  out_end,                        /* End of output buffer */
        !           282:     LINE_COL    line_col,                   /* Location of macro    */
        !           283:     int *   pragma_op                       /* _Pragma() is found ? */
        !           284: )
        !           285: /*
        !           286:  * Expand a macro call completely, write the results to the specified buffer
        !           287:  * and return the advanced output pointer.
        !           288:  */
        !           289: {
        !           290:     char    macrobuf[ NMACWORK + IDMAX];    /* Buffer for replace() */
        !           291:     char *  out_p = out;
        !           292:     size_t  len;
        !           293:     int     c, c1;
        !           294:     char *  cp;
        !           295:
        !           296:     has_pragma = FALSE;                     /* Have to re-initialize*/
        !           297:     macro_line = src_line;                  /* Line number for diag */
        !           298:     macro_name = defp->name;
        !           299:     rescan_level = 0;
        !           300:     trace_macro = (mcpp_mode == STD) && (mcpp_debug & MACRO_CALL)
        !           301:             && ! in_directive;
        !           302:     if (trace_macro) {
        !           303:         max_mac_num = INIT_MAC_INF;
        !           304:         mac_inf = (MACRO_INF *) xmalloc( sizeof (MACRO_INF) * max_mac_num);
        !           305:         memset( mac_inf, 0, sizeof (MACRO_INF) * max_mac_num);
        !           306:         max_in_src_num = INIT_IN_SRC_NUM;
        !           307:         in_src = (LOCATION *) xmalloc( sizeof (LOCATION) * max_in_src_num);
        !           308:         memset( in_src, 0, sizeof (LOCATION) * max_in_src_num);
        !           309:         mac_num = in_src_num = 0;           /* Initialize           */
        !           310:     }
        !           311:     if (replace( defp, macrobuf, macrobuf + NMACWORK, NULL, infile, line_col
        !           312:             , 0) == NULL) {                 /* Illegal macro call   */
        !           313:         skip_macro();
        !           314:         macro_line = MACRO_ERROR;
        !           315:         goto  exp_end;
        !           316:     }
        !           317:     len = (size_t) (out_end - out);
        !           318:     if (strlen( macrobuf) > len) {
        !           319:         cerror( macbuf_overflow, macro_name, 0, macrobuf);
        !           320:         memcpy( out, macrobuf, len);
        !           321:         out_p = out + len;
        !           322:         macro_line = MACRO_ERROR;
        !           323:         goto  exp_end;
        !           324:     }
        !           325:
        !           326: #if DEBUG_MACRO_ANN
        !           327:     chk_magic_balance( macrobuf, macrobuf + strlen( macrobuf), FALSE, TRUE);
        !           328: #endif
        !           329:     cp = macrobuf;
        !           330:     c1 = '\0';                          /* The char previous to 'c' */
        !           331:     while ((c = *cp++) != EOS) {
        !           332:         if (c == DEF_MAGIC)
        !           333:             continue;                       /* Skip DEF_MAGIC       */
        !           334:         if (mcpp_mode == STD) {
        !           335:             if (c == IN_SRC) {              /* Skip IN_SRC          */
        !           336:                 if (trace_macro)
        !           337:                     cp += 2;    /* Skip also the number (coded in 2 bytes)  */
        !           338:                 continue;
        !           339:             } else if (c == TOK_SEP) {
        !           340:                 /* Remove redundant token separator */
        !           341:                 if ((char_type[ c1 & UCHARMAX] & HSP)
        !           342:                         || (char_type[ *cp & UCHARMAX] & HSP)
        !           343:                         || in_include || option_flags.lang_asm
        !           344:                         || (*cp == MAC_INF && *(cp + 1) == MAC_CALL_END)
        !           345:                         || (!option_flags.v && c1 == MAC_CALL_END)
        !           346:                         || (option_flags.v
        !           347:                             && *(cp - MAC_E_LEN_V - 1) == MAC_INF
        !           348:                             && *(cp - MAC_E_LEN_V) == MAC_CALL_END))
        !           349:                     continue;
        !           350:                     /* Skip separator just after ' ', '\t'          */
        !           351:                     /* and just after MAC_CALL_END.                 */
        !           352:                     /* Also skip this in lang_asm mode, #include    */
        !           353:                     /* Skip just before another TOK_SEP, ' ', '\t'  */
        !           354:                     /* Skip just before MAC_INF,MAC_CALL_END seq too*/
        !           355:                 else
        !           356:                     c = ' ';                /* Else convert to ' '  */
        !           357:             } else if (trace_macro && (c == MAC_INF)) {
        !           358:                 /* Embed macro expansion informations into comments */
        !           359:                 c = *cp++;
        !           360:                 c1 = print_macro_inf( c, &cp, &out_p);
        !           361:                 if (out_end <= out_p) {
        !           362:                     cerror( macbuf_overflow, macro_name, 0, out);
        !           363:                     macro_line = MACRO_ERROR;
        !           364:                     goto  exp_end;
        !           365:                 }
        !           366:                 continue;
        !           367:             }
        !           368:         }
        !           369:         *out_p++ = c1 = c;
        !           370:     }
        !           371:
        !           372:     macro_line = 0;
        !           373: exp_end:
        !           374:     *out_p = EOS;
        !           375:     if (mcpp_debug & EXPAND)
        !           376:         dump_string( "expand_std exit", out);
        !           377:     macro_name = NULL;
        !           378:     clear_exp_mac();        /* Clear the information for diagnostic */
        !           379:     if (trace_macro) {                  /* Clear macro informations */
        !           380:         int     num;
        !           381:         for (num = 1; num < mac_num; num++) {   /* 'num' start at 1 */
        !           382:             if (mac_inf[ num].num_args >= 0) {  /* Macro with args  */
        !           383:                 free( mac_inf[ num].args);      /* Saved arguments  */
        !           384:                 free( mac_inf[ num].loc_args);  /* Location of args */
        !           385:             }
        !           386:         }
        !           387:         free( mac_inf);
        !           388:         free( in_src);
        !           389:     }
        !           390:     *pragma_op = has_pragma;
        !           391:
        !           392:     return  out_p;
        !           393: }
        !           394:
        !           395: static int  print_macro_inf(
        !           396:     int     c,
        !           397:     char ** cpp,                    /* Magic character sequence     */
        !           398:     char ** opp                     /* Output for macro information */
        !           399: )
        !           400: /*
        !           401:  * Embed macro expansion information into comments.
        !           402:  * Enabled by '#pragma MCPP debug macro_call' or -K option in STD mode.
        !           403:  */
        !           404: {
        !           405:     MACRO_INF *     m_inf;
        !           406:     int     num;
        !           407:     int     num_args;   /* Number of actual args (maybe less than expected) */
        !           408:     int     i;
        !           409:
        !           410:     if (*((*opp) - 1) == '/' && *((*opp) - 2) != '*')
        !           411:                     /* Immediately preceding token is '/' (not '*' and '/') */
        !           412:         *((*opp)++) = ' ';
        !           413:                 /* Insert a space to separate with following '/' and '*'    */
        !           414:     if (option_flags.v || c == MAC_CALL_START || c == MAC_ARG_START) {
        !           415:         num = ((*(*cpp)++ & UCHARMAX) - 1) * UCHARMAX;
        !           416:         num += (*(*cpp)++ & UCHARMAX) - 1;
        !           417:         m_inf = & mac_inf[ num];            /* Saved information    */
        !           418:     }
        !           419:     switch (c) {
        !           420:     case MAC_CALL_START :           /* Start of a macro expansion   */
        !           421:         *opp += sprintf( *opp, "/*<%s", m_inf->defp->name); /* Macro name   */
        !           422:         if (m_inf->locs.start_line) {
        !           423:             /* Location of the macro call in source file        */
        !           424:             *opp += sprintf( *opp, " %ld:%d-%ld:%d"
        !           425:                     , m_inf->locs.start_line, (int) m_inf->locs.start_col
        !           426:                     , m_inf->locs.end_line, (int) m_inf->locs.end_col);
        !           427:         }
        !           428:         *opp = stpcpy( *opp, "*/");
        !           429:         if ((num_args = m_inf->num_args) >= 1) {
        !           430:             /* The macro has arguments.  Show the locations.    */
        !           431:             for (i = 0; i < num_args; i++)  /* Arg num begins at 0  */
        !           432:                 *opp = print_macro_arg( *opp, m_inf, i, TRUE, TRUE);
        !           433:         }
        !           434:         break;
        !           435:     case MAC_ARG_START  :                   /* Start of an argument */
        !           436:         i = (*(*cpp)++ & UCHARMAX) - 1;     /* Argument number      */
        !           437:         *opp = print_macro_arg( *opp, m_inf, i, FALSE, TRUE);
        !           438:         break;
        !           439:     case MAC_CALL_END   :               /* End of a macro expansion */
        !           440:         if (option_flags.v) {               /* Verbose mode         */
        !           441:             *opp += sprintf( *opp, "/*%s>*/", m_inf->defp->name);
        !           442:             break;
        !           443:         }
        !           444:         /* Else fall through    */
        !           445:     case MAC_ARG_END    :               /* End of an argument       */
        !           446:         if (option_flags.v) {
        !           447:             i = (*(*cpp)++ & UCHARMAX) - 1;
        !           448:            /* Output verbose infs symmetrical to start of the arg infs  */
        !           449:             *opp = print_macro_arg( *opp, m_inf, i, FALSE, FALSE);
        !           450:         } else {
        !           451:             *opp = stpcpy( *opp, "/*>*/");
        !           452:         }
        !           453:         break;
        !           454:     }
        !           455:
        !           456:     return  **cpp & UCHARMAX;
        !           457: }
        !           458:
        !           459: static char *   print_macro_arg(
        !           460:     char *  out,                                /* Output buffer    */
        !           461:     MACRO_INF *     m_inf,                      /* &mac_inf[ m_num] */
        !           462:     int     argn,                               /* Argument number  */
        !           463:     int     real_arg,       /* Real argument or expanded argument ? */
        !           464:     int     start           /* Start of an argument or end ?        */
        !           465: )
        !           466: /*
        !           467:  * Embed an argument information into a comment.
        !           468:  * This routine is only called from above print_macro_inf().
        !           469:  */
        !           470: {
        !           471:     LOCATION *  loc = m_inf->loc_args + argn;
        !           472:
        !           473:     out += sprintf( out, "/*%s%s:%d-%d", real_arg ? "!" : (start ? "<" : "")
        !           474:             , m_inf->defp->name, m_inf->recur, argn);
        !           475:
        !           476:     if (real_arg && m_inf->loc_args && loc->start_line) {
        !           477:         /* Location of the argument in source file  */
        !           478:         out += sprintf( out, " %ld:%d-%ld:%d", loc->start_line
        !           479:                 , (int) loc->start_col, loc->end_line, (int) loc->end_col);
        !           480:     }
        !           481:     if (! start)            /* End of an argument in verbose mode   */
        !           482:         out = stpcpy( out, ">");
        !           483:     out = stpcpy( out, "*/");
        !           484:
        !           485:     return out;
        !           486: }
        !           487:
        !           488: static char *   chk_magic_balance(
        !           489:     char *  buf,                            /* Sequence to check    */
        !           490:     char *  buf_end,                        /* End of the sequence  */
        !           491:     int     move,                   /* Move a straying magic ?      */
        !           492:     int     diag                            /* Output a diagnostic? */
        !           493: )
        !           494: /*
        !           495:  * Check imbalance of macro information magics and warn it.
        !           496:  * get_an_arg() calls this routine setting 'move' argument on, hence a stray
        !           497:  * magic is moved to an edge if found.
        !           498:  * This routine does not do token parsing.  Yet it will do fine practically.
        !           499:  */
        !           500: {
        !           501: #define MAX_NEST_MAGICS 255
        !           502:     char    mac_id[ MAX_NEST_MAGICS][ MAC_E_LEN_V - 2];
        !           503:     char    arg_id[ MAX_NEST_MAGICS][ ARG_E_LEN_V - 2];
        !           504:     char *  mac_loc[ MAX_NEST_MAGICS];
        !           505:     char *  arg_loc[ MAX_NEST_MAGICS];
        !           506:     char *  mesg = "%s %ld %s-closing-comment(s) in tracing macro";
        !           507:     int     mac, arg;
        !           508:     int     mac_s_n, mac_e_n, arg_s_n, arg_e_n;
        !           509:     char *  buf_p = buf;        /* Save 'buf' for debugging purpose */
        !           510:
        !           511:     mac = arg = 0;
        !           512:
        !           513:     while (buf_p < buf_end) {
        !           514:         if (*buf_p++ != MAC_INF)
        !           515:             continue;
        !           516:         switch (*buf_p++) {
        !           517:         case MAC_CALL_START :
        !           518:             if (option_flags.v) {
        !           519:                 mac_loc[ mac] = buf_p - 2;
        !           520:                 memcpy( mac_id[ mac], buf_p, MAC_S_LEN - 2);
        !           521:             }
        !           522:             mac++;
        !           523:             buf_p += MAC_S_LEN - 2;
        !           524:             break;
        !           525:         case MAC_ARG_START  :
        !           526:             if (option_flags.v) {
        !           527:                 arg_loc[ arg] = buf_p - 2;
        !           528:                 memcpy( arg_id[ arg], buf_p, ARG_S_LEN - 2);
        !           529:             }
        !           530:             arg++;
        !           531:             buf_p += ARG_S_LEN - 2;
        !           532:             break;
        !           533:         case MAC_ARG_END    :
        !           534:             arg--;
        !           535:             if (option_flags.v) {
        !           536:                 if (arg < 0) {          /* Perhaps moved magic  */
        !           537:                     if (diag)
        !           538:                         cwarn( mesg, "Redundant", (long) -arg, "argument");
        !           539:                 } else if (memcmp( arg_id[ arg], buf_p, ARG_E_LEN_V - 2) != 0)
        !           540:                 {
        !           541:                     char *      to_be_edge = NULL;
        !           542:                     char *      cur_edge;
        !           543:
        !           544:                     if (arg >= 1 && memcmp( arg_id[ 0], buf_p, ARG_E_LEN_V - 2)
        !           545:                             == 0) {
        !           546:                         to_be_edge = arg_loc[ arg];
        !           547:                                             /* To be moved to top   */
        !           548:                         cur_edge = arg_loc[ 0];     /* Current top  */
        !           549:                     } else if (arg == 0) {
        !           550:                         char    arg_end_magic[ 2] = { MAC_INF, MAC_ARG_END};
        !           551:                         cur_edge = buf_end - ARG_E_LEN_V;
        !           552:                         /* Search the last magic    */
        !           553:                         /* Sequence from get_an_arg() is always     */
        !           554:                         /* surrounded by starting of an arg magic   */
        !           555:                         /* and its corresponding closing magic.     */
        !           556:                         while (buf_p + (ARG_E_LEN_V - 2) <= cur_edge
        !           557:                                 && memcmp( cur_edge, arg_end_magic, 2) != 0)
        !           558:                             cur_edge--;
        !           559:                         if (buf_p + (ARG_E_LEN_V - 2) <= cur_edge
        !           560:                                 && memcmp( arg_id[ 0], cur_edge + 2
        !           561:                                         , ARG_E_LEN_V - 2) == 0) {
        !           562:                             to_be_edge = buf_p - 2; /* To be moved to end   */
        !           563:                         }
        !           564:                     }
        !           565:                     if (to_be_edge) {   /* Appropriate place found  */
        !           566:                         if (diag) {
        !           567:                             mac_s_n = ((to_be_edge[ 2] & UCHARMAX) - 1)
        !           568:                                     * UCHARMAX;
        !           569:                             mac_s_n += (to_be_edge[ 3] & UCHARMAX) - 1;
        !           570:                             arg_s_n = (to_be_edge[ 4] & UCHARMAX) - 1;
        !           571:                             mcpp_fprintf( ERR,
        !           572:                                 "Stray arg inf of macro: %d:%d at line:%d\n"
        !           573:                                             , mac_s_n, arg_s_n, src_line);
        !           574:                         }
        !           575:                         if (move) {
        !           576:                             /* Move a stray magic to outside of sequences   */
        !           577:                             char    magic[ ARG_E_LEN_V];
        !           578:                             size_t  len = ARG_E_LEN_V;
        !           579:                             memcpy( magic, cur_edge, len);
        !           580:                                 /* Save current edge    */
        !           581:                             if (to_be_edge == arg_loc[ arg])
        !           582:                                 /* Shift followings to cur_edge */
        !           583:                                 memmove( cur_edge, cur_edge + len
        !           584:                                         , to_be_edge - cur_edge);
        !           585:                             else        /* Shift precedents to cur_edge */
        !           586:                                 memmove( to_be_edge + len, to_be_edge
        !           587:                                         , cur_edge - to_be_edge);
        !           588:                             memcpy( to_be_edge, magic, len);
        !           589:                             /* Restore old 'cur_edge' into old 'to_be_edge' */
        !           590:                         }
        !           591:                     } else {        /* Serious imbalance, just warn */
        !           592:                         char *      arg_p = arg_id[ arg];
        !           593:                         arg_s_n = ((arg_p[ 0] & UCHARMAX) - 1) * UCHARMAX;
        !           594:                         arg_s_n += (arg_p[ 1] & UCHARMAX) - 1;
        !           595:                         arg_e_n = ((buf_p[ 0] & UCHARMAX) - 1) * UCHARMAX;
        !           596:                         arg_e_n += (buf_p[ 1] & UCHARMAX) - 1;
        !           597:                         mcpp_fprintf( ERR,
        !           598:                 "Asymmetry of arg inf found: start %d, end %d at line:%d\n"
        !           599:                                 , arg_s_n, arg_e_n, src_line);
        !           600:                     }
        !           601:                 }
        !           602:                 buf_p += ARG_E_LEN_V - 2;
        !           603:             }
        !           604:             break;
        !           605:         case MAC_CALL_END   :
        !           606:             mac--;
        !           607:             if (option_flags.v) {
        !           608:                 if (mac < 0) {
        !           609:                     if (diag)
        !           610:                         cwarn( mesg, "Redundant", (long) -mac, "macro");
        !           611:                 } else if (memcmp( mac_id[ mac], buf_p, MAC_E_LEN_V - 2) != 0)
        !           612:                 {
        !           613:                     char *      mac_p = mac_id[ mac];
        !           614:                     mac_s_n = ((mac_p[ 0] & UCHARMAX) - 1) * UCHARMAX;
        !           615:                     mac_s_n += (mac_p[ 1] & UCHARMAX) - 1;
        !           616:                     mac_e_n = ((buf_p[ 0] & UCHARMAX) - 1) * UCHARMAX;
        !           617:                     mac_e_n += (buf_p[ 1] & UCHARMAX) - 1;
        !           618:                     mcpp_fprintf( ERR,
        !           619:                 "Asymmetry of macro inf found: start %d, end %d at line:%d\n"
        !           620:                             , mac_s_n, mac_e_n, src_line);
        !           621:                 }
        !           622:                 buf_p += MAC_E_LEN_V - 2;
        !           623:             }
        !           624:             break;
        !           625:         default :                       /* Not a MAC_INF sequence   */
        !           626:             break;                                  /* Continue     */
        !           627:         }
        !           628:     }
        !           629:
        !           630:     if (diag && (warn_level & 1)) {
        !           631:         if (mac > 0)
        !           632:             cwarn( mesg, "Lacking", (long) mac, "macro");
        !           633:         if (arg > 0)
        !           634:             cwarn( mesg, "Lacking", (long) arg, "argument");
        !           635:         if ((mac || arg) && (mcpp_debug & EXPAND))
        !           636:             mcpp_fputs(
        !           637: "Imbalance of magics occurred (perhaps a moved magic), see <expand_std exit> and diagnostics.\n"
        !           638:                     , DBG);
        !           639:     }
        !           640:
        !           641:     return  buf;
        !           642: }
        !           643:
        !           644: static char *   replace(
        !           645:     DEFBUF *    defp,                       /* Macro to be replaced */
        !           646:     char *      out,                        /* Output Buffer        */
        !           647:     char *      out_end,                    /* End of output buffer */
        !           648:     const DEFBUF *    outer,                /* Outer macro replacing*/
        !           649:     FILEINFO *  rt_file,                    /* Repl-text "file"     */
        !           650:     LINE_COL    line_col,                   /* Location of macro    */
        !           651:     int         in_src_n                    /* Index into in_src[]  */
        !           652: )
        !           653: /*
        !           654:  * Replace a possibly nested macro recursively.
        !           655:  * replace() and rescan() call each other recursively.
        !           656:  * Return the advanced output pointer or NULL on error.
        !           657:  */
        !           658: {
        !           659:     char ** arglist = NULL;                 /* Pointers to arguments*/
        !           660:     int     nargs;                  /* Number of arguments expected */
        !           661:     char *  catbuf;                         /* Buffer for prescan() */
        !           662:     char *  expbuf;                 /* Buffer for  substitute()     */
        !           663:     char *  out_p;                          /* Output pointer       */
        !           664:     char *  cur_out = out;          /* One more output pointer      */
        !           665:     int     num_args;
        !           666:         /* Number of actual arguments (maybe less than expected)    */
        !           667:     int     enable_trace_macro;     /* To exclude _Pragma() pseudo macro    */
        !           668:     int     m_num = 0;              /* 'mac_num' of current macro   */
        !           669:     MACRO_INF *     m_inf;          /* Pointer into mac_inf[]       */
        !           670:
        !           671:     if (mcpp_debug & EXPAND) {
        !           672:         dump_a_def( "replace entry", defp, FALSE, TRUE, fp_debug);
        !           673:         dump_unget( "replace entry");
        !           674:     }
        !           675:     if ((mcpp_debug & MACRO_CALL) && in_if)
        !           676:         mcpp_fprintf( OUT, "/*%s*/", defp->name);
        !           677:
        !           678:     enable_trace_macro = trace_macro && defp->nargs != DEF_PRAGMA;
        !           679:     if (enable_trace_macro) {
        !           680:         int     num;
        !           681:         int     recurs;
        !           682:
        !           683:         if (mac_num >= MAX_MAC_INF - 1) {
        !           684:             cerror( "Too many nested macros in tracing %s"  /* _E_  */
        !           685:                     , defp->name, 0L, NULL);
        !           686:             return  NULL;
        !           687:         } else if (mac_num >= max_mac_num - 1) {
        !           688:             size_t  len = sizeof (MACRO_INF) * max_mac_num;
        !           689:             /* Enlarge the array    */
        !           690:             mac_inf = (MACRO_INF *) xrealloc( (char *) mac_inf, len * 2);
        !           691:             memset( mac_inf + max_mac_num, 0, len);
        !           692:                                         /* Clear the latter half    */
        !           693:             max_mac_num *= 2;
        !           694:         }
        !           695:         m_num = ++mac_num;                  /* Remember this number */
        !           696:                                     /* Note 'mac_num' starts at 1   */
        !           697:         *cur_out++ = MAC_INF;               /* Embed a magic char   */
        !           698:         *cur_out++ = MAC_CALL_START;        /* A macro call         */
        !           699:         /* Its index number, can be greater than UCHARMAX           */
        !           700:         /* We represent the number by 2 bytes where each byte is not '\0'   */
        !           701:         *cur_out++ = (m_num / UCHARMAX) + 1;
        !           702:         *cur_out++ = (m_num % UCHARMAX) + 1;
        !           703:         *cur_out = EOS;
        !           704:         m_inf = & mac_inf[ m_num];
        !           705:         m_inf->defp = defp;                 /* The macro definition */
        !           706:         m_inf->num_args = 0;                /* Default num of args  */
        !           707:         if (line_col.line) {
        !           708:             get_src_location( & line_col);
        !           709:             m_inf->locs.start_line = line_col.line;
        !           710:             m_inf->locs.start_col = line_col.col;
        !           711:         } else {
        !           712:             m_inf->locs.start_col = m_inf->locs.start_line = 0L;
        !           713:         }
        !           714:         m_inf->args = m_inf->loc_args = NULL;       /* Default args */
        !           715:         for (num = 1, recurs = 0; num < m_num; num++)
        !           716:             if (mac_inf[ num].defp == defp)
        !           717:                 recurs++;           /* Recursively nested macro     */
        !           718:         m_inf->recur = recurs;
        !           719:     }
        !           720:
        !           721:     nargs = (defp->nargs == DEF_PRAGMA) ? 1 : (defp->nargs & ~AVA_ARGS);
        !           722:
        !           723:     if (nargs < DEF_NOARGS_DYNAMIC) {       /* __FILE__, __LINE__   */
        !           724:         defp = def_special( defp);      /* These are redefined dynamically  */
        !           725:         if (mcpp_mode == STD) {
        !           726:         /* Wrap repl-text with token separators to prevent token merging    */
        !           727:             *cur_out++ = TOK_SEP;
        !           728:             cur_out = stpcpy( cur_out, defp->repl);
        !           729:             *cur_out++ = TOK_SEP;
        !           730:             *cur_out = EOS;
        !           731:         } else {
        !           732:             cur_out = stpcpy( cur_out, defp->repl);
        !           733:         }
        !           734:         if (enable_trace_macro) {
        !           735:             m_inf->defp = defp;             /* Redefined dynamically*/
        !           736:             cur_out = close_macro_inf( cur_out, m_num, in_src_n);
        !           737:         }
        !           738:         return  cur_out;
        !           739:     } else if (nargs == DEF_NOARGS_PREDEF_OLD && standard
        !           740:             && (warn_level & 1)) {          /* Some macros on GCC   */
        !           741:         cwarn( "Old style predefined macro \"%s\" is used", /* _W2_ */
        !           742:                 defp->name, 0L, NULL);
        !           743:     } else if (nargs >= 0) {                /* Function-like macro  */
        !           744:         squeeze_ws( NULL, NULL, NULL);      /* Skip to '('          */
        !           745:             /* Magic sequences are already read over by is_macro_call() */
        !           746:         arglist = (char **) xmalloc( (nargs + 1) * sizeof (char *));
        !           747:         arglist[ 0] = xmalloc( (size_t) (NMACWORK + IDMAX * 2));
        !           748:                             /* Note: arglist[ n] may be reallocated */
        !           749:                             /*   and re-written by collect_args()   */
        !           750:         if ((num_args = collect_args( defp, arglist, m_num)) == ARG_ERROR) {
        !           751:             free( arglist[ 0]);             /* Syntax error         */
        !           752:             free( arglist);
        !           753:             return  NULL;
        !           754:         }
        !           755:         if (enable_trace_macro) {
        !           756:             /* Save the arglist for later informations  */
        !           757:             m_inf->args = arglist[ 0];
        !           758:             m_inf->num_args = num_args;     /* Number of actual args*/
        !           759:         }
        !           760:         if (mcpp_mode == STD && outer && rt_file != infile) {
        !           761:                                  /* Has read over replacement-text  */
        !           762:             if (compat_mode) {
        !           763:                 enable_repl( outer, FALSE); /* Enable re-expansion  */
        !           764:                 if (mcpp_debug & EXPAND)
        !           765:                     dump_string( "enabled re-expansion"
        !           766:                             , outer ? outer->name : "<arg>");
        !           767:             } else {
        !           768:                 replacing[ rescan_level-1].read_over = READ_OVER;
        !           769:             }
        !           770:         }
        !           771:     }
        !           772:
        !           773:     catbuf = xmalloc( (size_t) (NMACWORK + IDMAX));
        !           774:     if (mcpp_debug & EXPAND) {
        !           775:         mcpp_fprintf( DBG, "(%s)", defp->name);
        !           776:         dump_string( "prescan entry", defp->repl);
        !           777:     }
        !           778:     if (prescan( defp, (const char **) arglist, catbuf, catbuf + NMACWORK)
        !           779:             == FALSE) {             /* Process #, ## operators      */
        !           780:         diag_macro( CERROR, macbuf_overflow, defp->name, 0L, catbuf, defp
        !           781:                 , NULL);
        !           782:         if (nargs >= 0) {
        !           783:             if (! enable_trace_macro)
        !           784:                 /* arglist[0] is needed for macro infs  */
        !           785:                 free( arglist[ 0]);
        !           786:             free( arglist);
        !           787:         }
        !           788:         free( catbuf);
        !           789:         return  NULL;
        !           790:     }
        !           791:     catbuf = xrealloc( catbuf, strlen( catbuf) + 1);
        !           792:                                             /* Use memory sparingly */
        !           793:     if (mcpp_debug & EXPAND) {
        !           794:         mcpp_fprintf( DBG, "(%s)", defp->name);
        !           795:         dump_string( "prescan exit", catbuf);
        !           796:     }
        !           797:
        !           798:     if (nargs > 0) {    /* Function-like macro with any argument    */
        !           799:         expbuf = xmalloc( (size_t) (NMACWORK + IDMAX));
        !           800:         if (mcpp_debug & EXPAND) {
        !           801:             mcpp_fprintf( DBG, "(%s)", defp->name);
        !           802:             dump_string( "substitute entry", catbuf);
        !           803:         }
        !           804:         out_p = substitute( defp, (const char **) arglist, catbuf, expbuf
        !           805:                 , expbuf + NMACWORK);   /* Expand each arguments    */
        !           806:         if (! enable_trace_macro)
        !           807:             free( arglist[ 0]);
        !           808:         free( arglist);
        !           809:         free( catbuf);
        !           810:         expbuf = xrealloc( expbuf, strlen( expbuf) + 1);
        !           811:                                             /* Use memory sparingly */
        !           812:         if (mcpp_debug & EXPAND) {
        !           813:             mcpp_fprintf( DBG, "(%s)", defp->name);
        !           814:             dump_string( "substitute exit", expbuf);
        !           815:         }
        !           816:     } else {                                /* Object-like macro or */
        !           817:         if (nargs == 0 && ! enable_trace_macro)
        !           818:                             /* Function-like macro with no argument */
        !           819:             free( arglist[ 0]);
        !           820:         free( arglist);
        !           821:         out_p = expbuf = catbuf;
        !           822:     }
        !           823:
        !           824:     if (out_p)
        !           825:         out_p = rescan( defp, expbuf, cur_out, out_end);
        !           826:     if (out_p && defp->nargs == DEF_PRAGMA)
        !           827:         has_pragma = TRUE;
        !           828:                     /* Inform mcpp_main() that _Pragma() was found  */
        !           829:     free( expbuf);
        !           830:     if (enable_trace_macro && out_p)
        !           831:         out_p = close_macro_inf( out_p, m_num, in_src_n);
        !           832:     if (mcpp_debug & EXPAND)
        !           833:         dump_string( "replace exit", out);
        !           834:
        !           835:     if (trace_macro && defp->nargs == DEF_PRAGMA) {
        !           836:         /* Remove intervening magics if the macro is _Pragma pseudo-macro   */
        !           837:         /* These magics have been inserted by macros in _Pragma()'s args    */
        !           838:         int     c;
        !           839:         cur_out = out_p = out;
        !           840:         while ((c = *cur_out++) != EOS) {
        !           841:             if (c == MAC_INF) {
        !           842:                 if (! option_flags.v) {
        !           843:                     switch (*cur_out) {
        !           844:                     case MAC_ARG_START  :
        !           845:                         cur_out++;
        !           846:                         /* Fall through */
        !           847:                     case MAC_CALL_START :
        !           848:                         cur_out++;
        !           849:                         cur_out++;
        !           850:                         /* Fall through */
        !           851:                     default:
        !           852:                         cur_out++;
        !           853:                         break;
        !           854:                     }
        !           855:                 } else {
        !           856:                     switch (*cur_out) {
        !           857:                     case MAC_ARG_START  :
        !           858:                     case MAC_ARG_END    :
        !           859:                         cur_out++;
        !           860:                         /* Fall through */
        !           861:                     default:
        !           862:                         cur_out += 3;
        !           863:                         break;
        !           864:                     }
        !           865:                 }
        !           866:             } else {
        !           867:                 *out_p++ = c;
        !           868:             }
        !           869:         }
        !           870:         *out_p = EOS;
        !           871:     }
        !           872:
        !           873:     return  out_p;
        !           874: }
        !           875:
        !           876: static char *   close_macro_inf(
        !           877:     char *  out_p,                      /* Current output pointer   */
        !           878:     int     m_num,                      /* 'mac_num' of this macro  */
        !           879:     int     in_src_n                    /* Location of macro in arg */
        !           880: )
        !           881: /*
        !           882:  * Mark up closing of a macro expansion.
        !           883:  * Note that 'm_num' argument is necessary rather than 'm_inf' from replace(),
        !           884:  * because mac_inf[] may have been reallocated while rescanning.
        !           885:  */
        !           886: {
        !           887:     MACRO_INF * m_inf;
        !           888:     LINE_COL    e_line_col;
        !           889:
        !           890:     m_inf = & mac_inf[ m_num];
        !           891:     *out_p++ = MAC_INF;         /* Magic for end of macro expansion */
        !           892:     *out_p++ = MAC_CALL_END;
        !           893:     if (option_flags.v) {
        !           894:         *out_p++ = (m_num / UCHARMAX) + 1;
        !           895:         *out_p++ = (m_num % UCHARMAX) + 1;
        !           896:     }
        !           897:     *out_p = EOS;
        !           898:     get_ch();                               /* Clear the garbage    */
        !           899:     unget_ch();
        !           900:     if (infile->fp || in_src_n) {
        !           901:         if (infile->fp) {           /* Macro call on source file    */
        !           902:             e_line_col.line = src_line;
        !           903:             e_line_col.col = infile->bptr - infile->buffer;
        !           904:         } else {    /* Macro in argument of parent macro and from source    */
        !           905:             e_line_col.line = in_src[ in_src_n].end_line;
        !           906:             e_line_col.col = in_src[ in_src_n].end_col;
        !           907:         }
        !           908:         /* Get the location before line splicing by <backslash><newline>    */
        !           909:         /*      or by a line-crossing comment                       */
        !           910:         get_src_location( & e_line_col);
        !           911:         m_inf->locs.end_line = e_line_col.line;
        !           912:         m_inf->locs.end_col = e_line_col.col;
        !           913:     } else {
        !           914:         m_inf->locs.end_col = m_inf->locs.end_line = 0L;
        !           915:     }
        !           916:
        !           917:     return  out_p;
        !           918: }
        !           919:
        !           920: static DEFBUF * def_special(
        !           921:     DEFBUF *    defp                        /* Macro definition     */
        !           922: )
        !           923: /*
        !           924:  * Re-define __LINE__, __FILE__.
        !           925:  * Return the new definition.
        !           926:  */
        !           927: {
        !           928:     const FILEINFO *    file;
        !           929:     DEFBUF **   prevp;
        !           930:     int         cmp;
        !           931:
        !           932:     switch (defp->nargs) {
        !           933:     case DEF_NOARGS_DYNAMIC - 1:            /* __LINE__             */
        !           934:         if ((src_line > std_limits.line_num || src_line <= 0)
        !           935:                 && (warn_level & 1))
        !           936:             diag_macro( CWARN
        !           937:                     , "Line number %.0s\"%ld\" is out of range"     /* _W1_ */
        !           938:                     , NULL, src_line, NULL, defp, NULL);
        !           939:         sprintf( defp->repl, "%ld", src_line);      /* Re-define    */
        !           940:         break;
        !           941:     case DEF_NOARGS_DYNAMIC - 2:            /* __FILE__             */
        !           942:         for (file = infile; file != NULL; file = file->parent) {
        !           943:             if (file->fp != NULL) {
        !           944:                 sprintf( work_buf, "\"%s\"", file->filename);
        !           945:                 if (str_eq( work_buf, defp->repl))
        !           946:                     break;                          /* No change    */
        !           947:                 defp->nargs = DEF_NOARGS;   /* Enable to redefine   */
        !           948:                 prevp = look_prev( defp->name, &cmp);
        !           949:                 defp = install_macro( "__FILE__", DEF_NOARGS_DYNAMIC - 2, ""
        !           950:                         , work_buf, prevp, cmp, 0); /* Re-define    */
        !           951:                 break;
        !           952:             }
        !           953:         }
        !           954:         break;
        !           955:     }
        !           956:     return  defp;
        !           957: }
        !           958:
        !           959: static int  prescan(
        !           960:     const DEFBUF *  defp,           /* Definition of the macro      */
        !           961:     const char **   arglist,        /* Pointers to actual arguments */
        !           962:     char *      out,                /* Output buffer                */
        !           963:     char *      out_end             /* End of output buffer         */
        !           964: )
        !           965: /*
        !           966:  * Concatenate the tokens surounding ## by catenate(), and stringize the
        !           967:  * argument following # by stringize().
        !           968:  */
        !           969: {
        !           970:     FILEINFO *  file;
        !           971:     char *      prev_token = NULL;  /* Preceding token              */
        !           972:     char *      horiz_space = NULL; /* Horizontal white space       */
        !           973:     int         c;                  /* Value of a character         */
        !           974:     /*
        !           975:      * The replacement lists are --
        !           976:      *          stuff1<SEP>stuff2
        !           977:      *      or  stuff1<SEP>stuff2<SEP>stuff3...
        !           978:      * where <SEP> is CAT, maybe with preceding space and following space,
        !           979:      * stuff might be
        !           980:      *          ordinary-token
        !           981:      *          MAC_PARM<n>
        !           982:      *      or  <QUO>MAC_PARM<n>
        !           983:      * where <QUO> is ST_QUO, possibly with following space.
        !           984:      *
        !           985:      * DEF_MAGIC may has been inserted sometimes.
        !           986:      * In other than POST_STD modes, TOK_SEP and IN_SRC may have been
        !           987:      * inserted, and TOK_SEPs are inserted also in this routine.
        !           988:      * In trace_macro mode, many magic character sequences may have been
        !           989:      * inserted here and there.
        !           990:      */
        !           991:
        !           992:     if (mcpp_mode == POST_STD) {
        !           993:         file = unget_string( defp->repl, defp->name);
        !           994:     } else {
        !           995:         *out++ = TOK_SEP;                   /* Wrap replacement     */
        !           996:         workp = work_buf;                   /*  text with token     */
        !           997:         workp = stpcpy( workp, defp->repl); /*   separators to      */
        !           998:         *workp++ = TOK_SEP;                 /*    prevent unintended*/
        !           999:         *workp = EOS;                       /*     token merging.   */
        !          1000:         file = unget_string( work_buf, defp->name);
        !          1001:     }
        !          1002:
        !          1003:     while (c = get_ch(), file == infile) {  /* To the end of repl   */
        !          1004:
        !          1005:         switch (c) {
        !          1006:         case ST_QUOTE:
        !          1007:             skip_ws();      /* Skip spaces and the returned MAC_PARM*/
        !          1008:             c = get_ch() - 1;               /* Parameter number     */
        !          1009:             prev_token = out;               /* Remember the token   */
        !          1010:             out = stringize( defp, arglist[ c], out);
        !          1011:                                     /* Stringize without expansion  */
        !          1012:             horiz_space = NULL;
        !          1013:             break;
        !          1014:         case CAT:
        !          1015:             if (*prev_token == DEF_MAGIC || *prev_token == IN_SRC) {
        !          1016:                 /* Rare case yet possible after catenate()  */
        !          1017:                 size_t  len = 1;
        !          1018:                 /* Remove trailing white space prior to removing DEF_MAGIC  */
        !          1019:                 if (horiz_space == out - 1) {
        !          1020:                     *--out = EOS;
        !          1021:                     horiz_space = NULL;
        !          1022:                 }
        !          1023:                 if (*prev_token == IN_SRC && trace_macro)
        !          1024:                     len = IN_SRC_LEN;
        !          1025:                 memmove( prev_token, prev_token + len
        !          1026:                         , strlen( prev_token + len));
        !          1027:                 out -= len;
        !          1028:                 *out = EOS;             /* Remove DEF_MAGIC, IN_SRC */
        !          1029:             }
        !          1030: #if COMPILER == GNUC
        !          1031:             if (*prev_token == ',')
        !          1032:                 break;      /* ', ##' sequence (peculiar to GCC)    */
        !          1033: #endif
        !          1034:             if (horiz_space == out - 1) {
        !          1035:                 *--out = EOS;       /* Remove trailing white space  */
        !          1036:                 horiz_space = NULL;
        !          1037:             }
        !          1038:             out = catenate( defp, arglist, out, out_end, &prev_token);
        !          1039:             if (char_type[ *(out - 1) & UCHARMAX] & HSP)
        !          1040:                 horiz_space = out - 1;      /* TOK_SEP has been appended    */
        !          1041:             break;
        !          1042:         case MAC_PARM:
        !          1043:             prev_token = out;
        !          1044:             *out++ = MAC_PARM;
        !          1045:             *out++ = get_ch();              /* Parameter number     */
        !          1046:             break;
        !          1047:         case TOK_SEP:
        !          1048:         case ' ':
        !          1049:         case '\t'   :
        !          1050:             if (out - 1 == horiz_space)
        !          1051:                 continue;                   /* Squeeze white spaces */
        !          1052:             horiz_space = out;
        !          1053:             *out++ = c;
        !          1054:             break;
        !          1055:         default:
        !          1056:             prev_token = out;
        !          1057:             scan_token( c, &out, out_end);  /* Ordinary token       */
        !          1058:             break;
        !          1059:         }
        !          1060:
        !          1061:         *out = EOS;                         /* Ensure termination   */
        !          1062:         if (out_end <= out)                 /* Buffer overflow      */
        !          1063:             return  FALSE;
        !          1064:     }
        !          1065:
        !          1066:     *out = EOS;         /* Ensure terminatation in case of no token */
        !          1067:     unget_ch();
        !          1068:     return  TRUE;
        !          1069: }
        !          1070:
        !          1071: static char *   catenate(
        !          1072:     const DEFBUF *  defp,           /* The macro definition         */
        !          1073:     const char **   arglist,        /* Pointers to actual arguments */
        !          1074:     char *  out,                    /* Output buffer                */
        !          1075:     char *  out_end,                /* End of output buffer         */
        !          1076:     char ** token_p         /* Address of preceding token pointer   */
        !          1077: )
        !          1078: /*
        !          1079:  * Concatenate the previous and the following tokens.
        !          1080:  *   Note: The parameter codes may coincide with white spaces or any
        !          1081:  * other characters.
        !          1082:  */
        !          1083: {
        !          1084:     FILEINFO *      file;
        !          1085:     char *  prev_prev_token = NULL;
        !          1086:     const char *    invalid_token
        !          1087:     = "Not a valid preprocessing token \"%s\"";     /* _E_ _W2_     */
        !          1088:     const char *    argp;           /* Pointer to an actual argument*/
        !          1089:     char *  prev_token = *token_p;  /* Preceding token              */
        !          1090:     int     in_arg = FALSE;
        !          1091:     int     c;                      /* Value of a character         */
        !          1092:
        !          1093:     /* Get the previous token   */
        !          1094:     if (*prev_token == MAC_PARM) {          /* Formal parameter     */
        !          1095:         c = (*(prev_token + 1) & UCHARMAX) - 1;     /* Parm number  */
        !          1096:         argp = arglist[ c];                 /* Actual argument      */
        !          1097:         out = prev_token;                   /* To overwrite         */
        !          1098:         if (trace_macro)
        !          1099:             argp = remove_magics( argp, TRUE);  /* Remove pair of magics    */
        !          1100:         if ((mcpp_mode == POST_STD && *argp == EOS)
        !          1101:                 || (mcpp_mode == STD && *argp == RT_END)) {
        !          1102:             *out = EOS;                     /* An empty argument    */
        !          1103:         } else {
        !          1104:             if (mcpp_mode == POST_STD) {
        !          1105:                 file = unget_string( argp, NULL);
        !          1106:                 while (c = get_ch(), file == infile) {
        !          1107:                     prev_token = out;   /* Remember the last token  */
        !          1108:                     scan_token( c, &out, out_end);
        !          1109:                 }       /* Copy actual argument without expansion   */
        !          1110:                 unget_ch();
        !          1111:             } else {
        !          1112:                 unget_string( argp, NULL);
        !          1113:                 if (trace_macro)
        !          1114:                     free( (char *) argp);
        !          1115:                     /* malloc()ed in remove_magics()    */
        !          1116:                 while ((c = get_ch()) != RT_END) {
        !          1117:                     prev_prev_token = prev_token;
        !          1118:                     prev_token = out;   /* Remember the last token  */
        !          1119:                     scan_token( c, &out, out_end);
        !          1120:                 }       /* Copy actual argument without expansion   */
        !          1121:                 if (*prev_token == TOK_SEP) {
        !          1122:                     out = prev_token;
        !          1123:                     prev_token = prev_prev_token;       /* Skip separator   */
        !          1124:                 }
        !          1125:             }
        !          1126:             if (*prev_token == DEF_MAGIC
        !          1127:                     || (mcpp_mode == STD && *prev_token == IN_SRC)) {
        !          1128:                 size_t  len = 1;
        !          1129:                 if (trace_macro && *prev_token == IN_SRC)
        !          1130:                     len = IN_SRC_LEN;
        !          1131:                 memmove( prev_token, prev_token + len
        !          1132:                         , (size_t) ((out -= len) - prev_token));
        !          1133:                 /* Remove DEF_MAGIC enabling the name to replace later      */
        !          1134:             }
        !          1135:         }
        !          1136:     }   /* Else the previous token is an ordinary token, not an argument    */
        !          1137:
        !          1138:     c = skip_ws();
        !          1139:
        !          1140:     /* Catenate */
        !          1141:     switch (c) {
        !          1142:     case ST_QUOTE:          /* First stringize and then catenate    */
        !          1143:         skip_ws();                  /* Skip MAC_PARM, ST_QUOTE      */
        !          1144:         c = get_ch() - 1;
        !          1145:         out = stringize( defp, arglist[ c], out);
        !          1146:         break;
        !          1147:     case MAC_PARM:
        !          1148:         c = get_ch() - 1;                   /* Parameter number     */
        !          1149:         argp = arglist[ c];                 /* Actual argument      */
        !          1150:         if (trace_macro)
        !          1151:             argp = remove_magics( argp, FALSE); /* Remove pair of magics    */
        !          1152:         if ((mcpp_mode == POST_STD && *argp == EOS)
        !          1153:                 || (mcpp_mode == STD && *argp == RT_END)) {
        !          1154:             *out = EOS;                     /* An empty argument    */
        !          1155:         } else {
        !          1156:             unget_string( argp, NULL);
        !          1157:             if (trace_macro)
        !          1158:                 free( (char *) argp);
        !          1159:             if ((c = get_ch()) == DEF_MAGIC) {  /* Remove DEF_MAGIC */
        !          1160:                 c = get_ch();               /*  enabling to replace */
        !          1161:             } else if (c == IN_SRC) {       /* Remove IN_SRC        */
        !          1162:                 if (trace_macro) {
        !          1163:                     get_ch();               /* Also its number      */
        !          1164:                     get_ch();
        !          1165:                 }
        !          1166:                 c = get_ch();
        !          1167:             }
        !          1168:             scan_token( c, &out, out_end);  /* The first token      */
        !          1169:             if (*infile->bptr)              /* There are more tokens*/
        !          1170:                 in_arg = TRUE;
        !          1171:         }
        !          1172:         break;
        !          1173:     case IN_SRC:
        !          1174:         if (trace_macro) {
        !          1175:             get_ch();
        !          1176:             get_ch();
        !          1177:         }
        !          1178:         /* Fall through */
        !          1179:     case DEF_MAGIC:
        !          1180:         c = get_ch();                   /* Skip DEF_MAGIC, IN_SRC   */
        !          1181:         /* Fall through */
        !          1182:     default:
        !          1183:         scan_token( c, &out, out_end);      /* Copy the token       */
        !          1184:         break;
        !          1185:     }
        !          1186:
        !          1187:     /* The generated sequence is a valid preprocessing-token ?      */
        !          1188:     if (*prev_token) {                      /* There is any token   */
        !          1189:         unget_string( prev_token, NULL);    /* Scan once more       */
        !          1190:         c = get_ch();  /* This line should be before the next line. */
        !          1191:         infile->fp = (FILE *)-1;            /* To check token length*/
        !          1192:         if (mcpp_debug & EXPAND)
        !          1193:             dump_string( "checking generated token", infile->buffer);
        !          1194:         scan_token( c, (workp = work_buf, &workp), work_end);
        !          1195:         infile->fp = NULL;
        !          1196:         if (*infile->bptr != EOS) {         /* More than a token    */
        !          1197:             if (option_flags.lang_asm) {    /* Assembler source     */
        !          1198:                 if (warn_level & 2)
        !          1199:                     diag_macro( CWARN, invalid_token, prev_token, 0L, NULL
        !          1200:                             , defp, NULL);
        !          1201:             } else {
        !          1202:                 diag_macro( CERROR, invalid_token, prev_token, 0L, NULL, defp
        !          1203:                        , NULL);
        !          1204:             }
        !          1205:             infile->bptr += strlen( infile->bptr);
        !          1206:         }
        !          1207:         get_ch();                           /* To the parent "file" */
        !          1208:         unget_ch();
        !          1209:     }
        !          1210:
        !          1211:     if (mcpp_mode == STD && ! option_flags.lang_asm) {
        !          1212:         *out++ = TOK_SEP;                   /* Prevent token merging*/
        !          1213:         *out = EOS;
        !          1214:     }
        !          1215:     if (in_arg) {       /* There are more tokens after the generated one    */
        !          1216:         if (mcpp_mode == POST_STD) {
        !          1217:             file = infile;
        !          1218:             while (c = get_ch(), file == infile) {
        !          1219:                 prev_token = out;       /* Remember the last token  */
        !          1220:                 scan_token( c, &out, out_end);
        !          1221:             }           /* Copy rest of argument without expansion  */
        !          1222:             unget_ch();
        !          1223:         } else {
        !          1224:             while ((c = get_ch()) != RT_END) {
        !          1225:                 if (c == TOK_SEP)
        !          1226:                     continue;           /* Skip separator           */
        !          1227:                 prev_token = out;       /* Remember the last token  */
        !          1228:                 scan_token( c, &out, out_end);
        !          1229:             }           /* Copy rest of argument without expansion  */
        !          1230:         }
        !          1231:     }
        !          1232:     *token_p = prev_token;          /* Report back the last token   */
        !          1233:
        !          1234:     return  out;
        !          1235: }
        !          1236:
        !          1237: static const char *     remove_magics(
        !          1238:     const char *    argp,       /* The argument list    */
        !          1239:     int     from_last           /* token is the last or first?  */
        !          1240: )
        !          1241: /*
        !          1242:  * Remove pair of magic character sequences in an argument in order to catenate
        !          1243:  * the last or first token to another.
        !          1244:  * Or remove pair of magic character sequences surrounding an argument in order
        !          1245:  * to keep symmetry of magics.
        !          1246:  */
        !          1247: {
        !          1248: #define INIT_MAGICS     128
        !          1249:
        !          1250:     char    (* mac_id)[ MAC_S_LEN];
        !          1251:     char    (* arg_id)[ ARG_S_LEN];
        !          1252:     char ** mac_loc;
        !          1253:     char ** arg_loc;
        !          1254:     char *  mgc_index;
        !          1255:     size_t  max_magics;
        !          1256:     int     mac_n, arg_n, ind, n;
        !          1257:     char *  first = NULL;
        !          1258:     char *  last = NULL;
        !          1259:     char *  token;
        !          1260:     char *  arg_p;
        !          1261:     char *  ap;
        !          1262:     char *  ep;
        !          1263:     char *  tp;
        !          1264:     char *  space = NULL;
        !          1265:     int     with_rtend;
        !          1266:     int     c;
        !          1267:     FILEINFO *  file;
        !          1268:
        !          1269:     mac_id = (char (*)[ MAC_S_LEN]) xmalloc( MAC_S_LEN * INIT_MAGICS);
        !          1270:     arg_id = (char (*)[ ARG_S_LEN]) xmalloc( ARG_S_LEN * INIT_MAGICS * 2);
        !          1271:     mac_loc = (char **) xmalloc( sizeof (char *) * INIT_MAGICS);
        !          1272:     arg_loc = (char **) xmalloc( sizeof (char *) * INIT_MAGICS * 2);
        !          1273:     mgc_index = xmalloc( INIT_MAGICS * 3);
        !          1274:     max_magics = INIT_MAGICS;
        !          1275:
        !          1276:     mac_n = arg_n = ind = 0;
        !          1277:     ap = arg_p = xmalloc( strlen( argp) + 1);
        !          1278:     strcpy( arg_p, argp);
        !          1279:     ep = arg_p + strlen( arg_p);
        !          1280:     if (*(ep - 1) == RT_END) {
        !          1281:         with_rtend = TRUE;
        !          1282:         ep--;                               /* Point to RT_END      */
        !          1283:     } else {
        !          1284:         with_rtend = FALSE;
        !          1285:     }
        !          1286:     file = unget_string( arg_p, NULL);  /* Stack to "file" for token parsing*/
        !          1287:
        !          1288:     /* Search all the magics in argument, as well as first and last token   */
        !          1289:     /* Read stacked arg_p and write it to arg_p as a dummy buffer   */
        !          1290:     while ((*ap++ = c = get_ch()) != RT_END && file == infile) {
        !          1291:         if (c == MAC_INF) {
        !          1292:             if (mac_n >= max_magics || arg_n >= max_magics * 2) {
        !          1293:                 max_magics *= 2;
        !          1294:                 mac_id = (char (*)[ MAC_S_LEN]) xrealloc( (void *) mac_id
        !          1295:                         , MAC_S_LEN * max_magics);
        !          1296:                 arg_id = (char (*)[ ARG_S_LEN]) xrealloc( (void *) arg_id
        !          1297:                         , ARG_S_LEN * max_magics * 2);
        !          1298:                 mac_loc = (char **) xrealloc( (void *) mac_loc
        !          1299:                         , sizeof (char *) * max_magics);
        !          1300:                 arg_loc = (char **) xrealloc( (void *) arg_loc
        !          1301:                         , sizeof (char *) * max_magics * 2);
        !          1302:                 mgc_index = xrealloc( mgc_index, max_magics * 3);
        !          1303:             }
        !          1304:             *ap++ = c = get_ch();
        !          1305:             switch (c) {
        !          1306:             case MAC_CALL_START :
        !          1307:                 *ap++ = get_ch();
        !          1308:                 *ap++ = get_ch();
        !          1309:                 mac_loc[ mac_n] = ap - MAC_S_LEN;   /* Location of the seq  */
        !          1310:                 memcpy( mac_id[ mac_n], ap - (MAC_S_LEN - 1), MAC_S_LEN - 1);
        !          1311:                         /* Copy the sequence from its second byte   */
        !          1312:                 mac_id[ mac_n++][ MAC_S_LEN - 1] = FALSE;
        !          1313:                                     /* Mark of to-be-removed or not */
        !          1314:                 break;
        !          1315:             case MAC_ARG_START  :
        !          1316:                 *ap++ = get_ch();
        !          1317:                 *ap++ = get_ch();
        !          1318:                 *ap++ = get_ch();
        !          1319:                 arg_loc[ arg_n] = ap - ARG_S_LEN;
        !          1320:                 memcpy( arg_id[ arg_n], ap - (ARG_S_LEN - 1), ARG_S_LEN - 1);
        !          1321:                 arg_id[ arg_n++][ ARG_S_LEN - 1] = FALSE;
        !          1322:                 break;
        !          1323:             case MAC_CALL_END   :
        !          1324:                 mac_loc[ mac_n] = ap - MAC_E_LEN;
        !          1325:                 mac_id[ mac_n][ 0] = c;
        !          1326:                 mac_id[ mac_n++][ MAC_E_LEN_V - 1] = FALSE;
        !          1327:                 break;
        !          1328:             case MAC_ARG_END    :
        !          1329:                 arg_loc[ arg_n] = ap - ARG_E_LEN;
        !          1330:                 arg_id[ arg_n][ 0] = c;
        !          1331:                 arg_id[ arg_n++][ ARG_E_LEN_V - 1] = FALSE;
        !          1332:                 break;
        !          1333:             }
        !          1334:             if (option_flags.v) {
        !          1335:                 switch (c) {
        !          1336:                 case MAC_CALL_END   :
        !          1337:                     mac_id[ mac_n - 1][ 1] = *ap++ = get_ch();
        !          1338:                     mac_id[ mac_n - 1][ 2] = *ap++ = get_ch();
        !          1339:                     break;
        !          1340:                 case MAC_ARG_END    :
        !          1341:                     arg_id[ arg_n - 1][ 1] = *ap++ = get_ch();
        !          1342:                     arg_id[ arg_n - 1][ 2] = *ap++ = get_ch();
        !          1343:                     arg_id[ arg_n - 1][ 3] = *ap++ = get_ch();
        !          1344:                     break;
        !          1345:                 }
        !          1346:             }
        !          1347:             mgc_index[ ind++] = c;      /* Index to mac_id[] and arg_id[]   */
        !          1348:             continue;
        !          1349:         } else if (char_type[ c & UCHARMAX] & HSP) {
        !          1350:             if (! first) {
        !          1351:                 ap--;   /* Skip white space on top of the argument  */
        !          1352:                 ep--;
        !          1353:             }
        !          1354:             continue;
        !          1355:         }
        !          1356:         last = --ap;
        !          1357:         if (! first)
        !          1358:             first = ap;
        !          1359:         if (char_type[ c & UCHARMAX] & HSP)
        !          1360:             space = ap;         /* Remember the last white space    */
        !          1361:         scan_token( c, &ap, ep);
        !          1362:     }
        !          1363:     if (file == infile)
        !          1364:         get_ch();                               /* Clear the "file" */
        !          1365:     unget_ch();
        !          1366:     if (space == ep - 1)
        !          1367:         ep--;                       /* Remove trailing white space  */
        !          1368:     if (with_rtend)
        !          1369:         *ep++ = RT_END;
        !          1370:     *ep = EOS;
        !          1371:     if ((from_last && !last) || (!from_last && !first))
        !          1372:         return  arg_p;
        !          1373:     if (mac_n == 0 && arg_n == 0)           /* No magic sequence    */
        !          1374:         return  arg_p;
        !          1375:     token = from_last ? last : first;
        !          1376:
        !          1377:     /* Remove pair of magics surrounding the last (or first) token  */
        !          1378:     if (mac_n) {
        !          1379:         /* Remove pair of macro magics surrounding the token    */
        !          1380:         int     magic, mac_s, mac_e;
        !          1381:         int     nest_s, nest_e;
        !          1382:
        !          1383:         nest_s = 0;
        !          1384:         for (mac_s = 0; mac_loc[ mac_s] < token; mac_s++) {
        !          1385:             magic = mac_id[ mac_s][ 0];
        !          1386:             if (magic == MAC_CALL_START) {      /* Starting magic   */
        !          1387:                 nest_e = ++nest_s;
        !          1388:                 /* Search the corresponding closing magic   */
        !          1389:                 for (mac_e = mac_s + 1; mac_e < mac_n; mac_e++) {
        !          1390:                     magic = mac_id[ mac_e][ 0];
        !          1391:                     if (magic == MAC_CALL_START) {
        !          1392:                         nest_e++;
        !          1393:                     } else {       /* MAC_CALL_END: Closing magic   */
        !          1394:                         nest_e--;
        !          1395:                         /* Search after the token   */
        !          1396:                         if (token < mac_loc[ mac_e] && nest_e == nest_s - 1) {
        !          1397: #if DEBUG_MACRO_ANN
        !          1398:                             if (option_flags.v)
        !          1399:                                 chk_symmetry( mac_id[ mac_s], mac_id[ mac_e]
        !          1400:                                         , MAC_E_LEN - 2);
        !          1401: #endif
        !          1402:                             mac_id[ mac_e][ MAC_S_LEN - 1] = TRUE;
        !          1403:                                                 /* To be removed    */
        !          1404:                             break;          /* Done for this mac_s  */
        !          1405:                         }
        !          1406:                     }
        !          1407:                 }
        !          1408:                 if (mac_e < mac_n)  /* Found corresponding magic    */
        !          1409:                     mac_id[ mac_s][ MAC_S_LEN - 1] = TRUE;  /* To be removed*/
        !          1410:                 else                                /* Not found    */
        !          1411:                     break;
        !          1412:             } else {
        !          1413:                 nest_s--;           /* MAC_CALL_END: Closing magic  */
        !          1414:             }
        !          1415:         }
        !          1416:     }
        !          1417:     if (arg_n) {
        !          1418:         /* Remove pair of arg magics surrounding the token  */
        !          1419:         int     magic, arg_s, arg_e;
        !          1420:         int     nest_s, nest_e;
        !          1421:
        !          1422:         nest_s = 0;
        !          1423:         for (arg_s = 0; arg_loc[ arg_s] < token; arg_s++) {
        !          1424:             magic = arg_id[ arg_s][ 0];
        !          1425:             if (magic == MAC_ARG_START) {
        !          1426:                 nest_e = ++nest_s;
        !          1427:                 for (arg_e = arg_s + 1; arg_e < arg_n; arg_e++) {
        !          1428:                     magic = arg_id[ arg_e][ 0];
        !          1429:                     if (magic == MAC_ARG_START) {
        !          1430:                         nest_e++;
        !          1431:                     } else {
        !          1432:                         nest_e--;
        !          1433:                         if (token < arg_loc[ arg_e] && nest_e == nest_s - 1) {
        !          1434: #if DEBUG_MACRO_ANN
        !          1435:                             if (option_flags.v)
        !          1436:                                 chk_symmetry( arg_id[ arg_s], arg_id[ arg_e]
        !          1437:                                         , ARG_E_LEN_V - 2);
        !          1438: #endif
        !          1439:                             arg_id[ arg_e][ ARG_S_LEN - 1] = TRUE;
        !          1440:                             break;
        !          1441:                         }
        !          1442:                     }
        !          1443:                 }
        !          1444:                 if (arg_e < arg_n)
        !          1445:                     arg_id[ arg_s][ ARG_S_LEN - 1] = TRUE;
        !          1446:                 else
        !          1447:                     break;
        !          1448:             } else {
        !          1449:                 nest_s--;
        !          1450:             }
        !          1451:         }
        !          1452:     }
        !          1453:
        !          1454:     /* Copy the sequences skipping the to-be-removed magic seqs */
        !          1455:     file = unget_string( arg_p, NULL);  /* Stack to "file" for token parsing*/
        !          1456:     tp = arg_p;
        !          1457:     ep = arg_p + strlen( arg_p);
        !          1458:     mac_n = arg_n = n = 0;
        !          1459:
        !          1460:     while ((*tp++ = c = get_ch()) != RT_END && file == infile) {
        !          1461:         char ** loc_tab;
        !          1462:         int     num, mark, rm, magic;
        !          1463:         size_t  len;
        !          1464:
        !          1465:         if (c != MAC_INF) {
        !          1466:             scan_token( c, (--tp, &tp), ep);
        !          1467:             continue;
        !          1468:         }
        !          1469:         unget_ch();                             /* Pushback MAC_INF */
        !          1470:         tp--;
        !          1471:
        !          1472:         switch (magic = mgc_index[ n++]) {
        !          1473:         case MAC_CALL_START :
        !          1474:             len = MAC_S_LEN;
        !          1475:             mark = MAC_S_LEN - 1;
        !          1476:             break;
        !          1477:         case MAC_CALL_END   :
        !          1478:             len = option_flags.v ? MAC_E_LEN_V : MAC_E_LEN;
        !          1479:             mark = MAC_E_LEN_V - 1;
        !          1480:             break;
        !          1481:         case MAC_ARG_START  :
        !          1482:             len = ARG_S_LEN;
        !          1483:             mark = ARG_S_LEN - 1;
        !          1484:             break;
        !          1485:         case MAC_ARG_END    :
        !          1486:             len = option_flags.v ? ARG_E_LEN_V : ARG_E_LEN;
        !          1487:             mark = ARG_E_LEN_V - 1;
        !          1488:             break;
        !          1489:         }
        !          1490:         switch (magic) {
        !          1491:         case MAC_CALL_START :
        !          1492:         case MAC_CALL_END   :
        !          1493:             loc_tab = mac_loc;
        !          1494:             num = mac_n;
        !          1495:             rm = mac_id[ mac_n++][ mark];
        !          1496:             break;
        !          1497:         case MAC_ARG_START  :
        !          1498:         case MAC_ARG_END    :
        !          1499:             loc_tab = arg_loc;
        !          1500:             num = arg_n;
        !          1501:             rm = arg_id[ arg_n++][ mark];
        !          1502:             break;
        !          1503:         }
        !          1504:         if (rm == FALSE) {                  /* Not to be removed    */
        !          1505:             memmove( tp, loc_tab[ num], len);
        !          1506:                     /* Copy it (from arg_p buffer for convenience)  */
        !          1507:             tp += len;
        !          1508:         }
        !          1509:         infile->bptr += len;
        !          1510:     }
        !          1511:     if (! with_rtend)
        !          1512:         tp--;
        !          1513:     *tp = EOS;
        !          1514:     if (file == infile)
        !          1515:         get_ch();                               /* Clear the "file" */
        !          1516:     unget_ch();
        !          1517:
        !          1518:     return  arg_p;
        !          1519: }
        !          1520:
        !          1521: #if DEBUG_MACRO_ANN
        !          1522: static void     chk_symmetry(
        !          1523:     char *  start_id,   /* Sequence of macro (or arg) starting inf  */
        !          1524:     char *  end_id,     /* Sequence of macro (or arg) closing inf   */
        !          1525:     size_t  len                         /* Length of the sequence   */
        !          1526: )
        !          1527: /*
        !          1528:  * Check whether starting sequence and corresponding closing sequence is the
        !          1529:  * same.
        !          1530:  */
        !          1531: {
        !          1532:     int     s_id, e_id, arg_s_n, arg_e_n;
        !          1533:
        !          1534:     if (memcmp( start_id + 1, end_id + 1, len) == 0)
        !          1535:         return;                     /* The sequences are the same   */
        !          1536:     s_id = ((start_id[ 1] & UCHARMAX) - 1) * UCHARMAX;
        !          1537:     s_id += (start_id[ 2] & UCHARMAX) - 1;
        !          1538:     e_id = ((end_id[ 1] & UCHARMAX) - 1) * UCHARMAX;
        !          1539:     e_id += (end_id[ 2] & UCHARMAX) - 1;
        !          1540:     if (len >= 3) {
        !          1541:         arg_s_n = (start_id[ 3] & UCHARMAX) - 1;
        !          1542:         arg_e_n = (end_id[ 3] & UCHARMAX) - 1;
        !          1543:         mcpp_fprintf( ERR,
        !          1544: "Asymmetry of arg inf found removing magics: start %d:%d, end: %d:%d at line:%d\n"
        !          1545:                 , s_id, arg_s_n, e_id, arg_e_n, src_line);
        !          1546:     } else {
        !          1547:         mcpp_fprintf( ERR,
        !          1548: "Asymmetry of macro inf found removing magics: start %d, end: %d at line:%d\n"
        !          1549:                 , s_id, e_id, src_line);
        !          1550:     }
        !          1551: }
        !          1552: #endif
        !          1553:
        !          1554: static char *   stringize(
        !          1555:     const DEFBUF *  defp,                   /* The macro definition */
        !          1556:     const char *    argp,                   /* Pointer to argument  */
        !          1557:     char *      out                         /* Output buffer        */
        !          1558: )
        !          1559: /*
        !          1560:  * Make a string literal from an argument.
        !          1561:  */
        !          1562: {
        !          1563:     char        arg_end_inf[ 8][ ARG_E_LEN_V - 1];
        !          1564:                         /* Verbose information of macro arguments   */
        !          1565:     FILEINFO *  file;
        !          1566:     int         stray_bsl = FALSE;          /* '\\' not in literal  */
        !          1567:     char *      out_p = out;
        !          1568:     int         token_type;
        !          1569:     int         num_arg_magic = 0;
        !          1570:     size_t      len;
        !          1571:     size_t      arg_e_len = option_flags.v ? ARG_E_LEN_V : ARG_E_LEN;
        !          1572:     int         c;
        !          1573:
        !          1574:     if (trace_macro) {
        !          1575:         while ((*argp == MAC_INF && *(argp + 1) == MAC_ARG_START)
        !          1576:             /* Argument is prefixed with macro tracing magics   */
        !          1577:                 || (char_type[ *argp & UCHARMAX] & HSP)) {
        !          1578:             if (*argp == MAC_INF) {     /* Move magics to outside of string */
        !          1579:                 memcpy( out_p, argp, ARG_S_LEN);
        !          1580:                 out_p += ARG_S_LEN;
        !          1581:                 argp += ARG_S_LEN;
        !          1582:                 num_arg_magic++;
        !          1583:             } else {                        /* Skip white spaces    */
        !          1584:                 argp++;
        !          1585:             }
        !          1586:         }
        !          1587:     }
        !          1588:
        !          1589:     file = unget_string( argp, NULL);
        !          1590:     len = strlen( infile->buffer);  /* Sequence ends with RT_END    */
        !          1591:     if (trace_macro) {          /* Remove suffixed argument closing magics  */
        !          1592:         /* There are 0 or more argument closing magic sequences and */
        !          1593:         /* 0 or more TOK_SEPs and no space at the end of argp.      */
        !          1594:         /* This is assured by get_an_arg().                         */
        !          1595:         int         nmagic = 0;
        !          1596:         while (len > arg_e_len
        !          1597:             && (((*(infile->buffer + len - arg_e_len - 1) == MAC_INF
        !          1598:                     && *(infile->buffer + len - arg_e_len) == MAC_ARG_END)
        !          1599:                 || *(infile->buffer + len - 2) == TOK_SEP))) {
        !          1600:             if (*(infile->buffer + len - arg_e_len - 1) == MAC_INF
        !          1601:                     && *(infile->buffer + len - arg_e_len) == MAC_ARG_END) {
        !          1602:                 if (option_flags.v) {
        !          1603:                     memcpy( arg_end_inf[ nmagic]
        !          1604:                             , infile->buffer + len - arg_e_len + 1
        !          1605:                             , arg_e_len - 2);
        !          1606:                     arg_end_inf[ nmagic][ arg_e_len - 2] = EOS;
        !          1607:                 }
        !          1608:                 nmagic++;
        !          1609:                 len -= arg_e_len;
        !          1610:                 *(infile->buffer + len - 1) = RT_END;
        !          1611:                 *(infile->buffer + len) = EOS;
        !          1612:             } else if (*(infile->buffer + len - 2) == TOK_SEP) {
        !          1613:                 len--;
        !          1614:                 *(infile->buffer + len - 1) = RT_END;
        !          1615:                 *(infile->buffer + len) = EOS;
        !          1616:             }
        !          1617:         }
        !          1618:         if (nmagic != num_arg_magic) {  /* There are some imbalances    */
        !          1619:             /* Some surrounding magics correspond to intervening ones.  */
        !          1620:             /* So, unmatched surrounding magics should be removed.      */
        !          1621:             if (num_arg_magic > nmagic) {
        !          1622:                 num_arg_magic = nmagic;     /* Ignore the surplus   */
        !          1623:                 out_p = out + ARG_S_LEN * num_arg_magic;
        !          1624:             }   /* Else simply ignore the surplus nmagic    */
        !          1625:         }
        !          1626:     }
        !          1627:     *out_p++ = '"';                         /* Starting quote       */
        !          1628:
        !          1629:     while ((c = get_ch()), ((mcpp_mode == POST_STD && file == infile)
        !          1630:             || (mcpp_mode == STD && c != RT_END))) {
        !          1631:         if (c == ' ' || c == '\t') {
        !          1632:             *out_p++ = c;
        !          1633:             continue;
        !          1634:         } else if (c == TOK_SEP) {
        !          1635:             continue;                   /* Skip inserted separator  */
        !          1636:         } else if (c == IN_SRC) {           /* Skip magics          */
        !          1637:             if (trace_macro) {
        !          1638:                 get_ch();
        !          1639:                 get_ch();
        !          1640:             }
        !          1641:             continue;
        !          1642:         } else if (c == '\\') {
        !          1643:             stray_bsl = TRUE;               /* May cause a trouble  */
        !          1644:         } else if (c == MAC_INF) {  /* Remove intervening magics    */
        !          1645:             switch (c = get_ch()) {
        !          1646:             case MAC_ARG_START  :
        !          1647:                 get_ch();
        !          1648:                 /* Fall through */
        !          1649:             case MAC_CALL_START :
        !          1650:                 get_ch();
        !          1651:                 get_ch();
        !          1652:                 break;
        !          1653:             }
        !          1654:             if (option_flags.v) {
        !          1655:                 switch (c) {
        !          1656:                 case MAC_ARG_END    :
        !          1657:                     get_ch();
        !          1658:                     /* Fall through */
        !          1659:                 case MAC_CALL_END   :
        !          1660:                     get_ch();
        !          1661:                     get_ch();
        !          1662:                     break;
        !          1663:                 }
        !          1664:             }
        !          1665:             continue;
        !          1666:         }
        !          1667:         token_type = scan_token( c, (workp = work_buf, &workp), work_end);
        !          1668:
        !          1669:         switch (token_type) {
        !          1670:         case WSTR:
        !          1671:         case WCHR:
        !          1672:         case STR:
        !          1673:         case CHR:
        !          1674:             workp = work_buf;
        !          1675:             while ((c = *workp++ & UCHARMAX) != EOS) {
        !          1676:                 if (char_type[ c] & mbchk) {        /* Multi-byte character */
        !          1677:                     mb_read( c, &workp, (*out_p++ = c, &out_p));
        !          1678:                                             /* Copy as it is        */
        !          1679:                     continue;
        !          1680:                 } else if (c == '"') {
        !          1681:                     *out_p++ = '\\';        /* Insert '\\'          */
        !          1682:                 } else if (c == '\\') {
        !          1683: #if OK_UCN
        !          1684:                     if (mcpp_mode == POST_STD || ! stdc3
        !          1685:                             || (*workp != 'u' && *workp != 'U'))
        !          1686:                                             /* Not UCN              */
        !          1687: #endif
        !          1688:                         *out_p++ = '\\';
        !          1689:                 }
        !          1690:                 *out_p++ = c;
        !          1691:             }
        !          1692:             *out_p = EOS;
        !          1693:             break;
        !          1694:         default:
        !          1695:             out_p = stpcpy( out_p, work_buf);
        !          1696:             break;
        !          1697:         }
        !          1698:     }
        !          1699:
        !          1700:     if (mcpp_mode == POST_STD)
        !          1701:         unget_ch();
        !          1702:     *out_p++ = '"';                         /* Closing quote        */
        !          1703:     if (trace_macro) {
        !          1704:         while (num_arg_magic--) {
        !          1705:             *out_p++ = MAC_INF;             /* Restore removed magic*/
        !          1706:             *out_p++ = MAC_ARG_END;
        !          1707:             if (option_flags.v)
        !          1708:                 out_p = stpcpy( out_p, arg_end_inf[ num_arg_magic]);
        !          1709:         }
        !          1710:     }
        !          1711:     *out_p = EOS;
        !          1712:
        !          1713:     if (stray_bsl) {    /* '\\' outside of quotation has been found */
        !          1714:         int     invalid = FALSE;
        !          1715:         unget_string( out, defp->name);
        !          1716:         if (mcpp_debug & EXPAND)
        !          1717:             dump_string( "checking generated token", infile->buffer);
        !          1718:         scan_quote( get_ch(), work_buf, work_end, TRUE);
        !          1719:             /* Unterminated or too long string will be diagnosed    */
        !          1720:         if (*infile->bptr != EOS)           /* More than a token    */
        !          1721:             invalid = TRUE; /* Diagnose after clearing the "file"   */
        !          1722:         infile->bptr += strlen( infile->bptr);
        !          1723:         get_ch();                           /* Clear the "file"     */
        !          1724:         unget_ch();
        !          1725:         if (invalid)
        !          1726:             diag_macro( CERROR
        !          1727:                     , "Not a valid string literal %s"       /* _E_  */
        !          1728:                     , out, 0L, NULL, defp, NULL);
        !          1729:     }
        !          1730: #if NWORK-2 > SLEN90MIN
        !          1731:     else if ((warn_level & 4) && out_p - out > std_limits.str_len)
        !          1732:         diag_macro( CWARN
        !          1733:                 , "String literal longer than %.0s%ld bytes %s"     /* _W4_ */
        !          1734:                 , NULL , (long) std_limits.str_len, out, defp, NULL);
        !          1735: #endif
        !          1736:     return  out_p;
        !          1737: }
        !          1738:
        !          1739: static char *   substitute(
        !          1740:     const DEFBUF *  defp,           /* The macro getting arguments  */
        !          1741:     const char **   arglist,    /* Pointers to actual arguments     */
        !          1742:     const char *    in,                     /* Replacement text     */
        !          1743:     char *      out,                        /* Output buffer        */
        !          1744:     char *      out_end                     /* End of output buffer */
        !          1745: )
        !          1746: /*
        !          1747:  * Replace completely each actual arguments of the macro, and substitute for
        !          1748:  * the formal parameters in the replacement list.
        !          1749:  */
        !          1750: {
        !          1751:     char *  out_start = out;
        !          1752:     const char *    arg;
        !          1753:     int     c;
        !          1754:     int     gvar_arg;   /* gvar_arg'th argument is GCC variable argument    */
        !          1755:
        !          1756:     gvar_arg = (defp->nargs & GVA_ARGS) ? (defp->nargs & ~AVA_ARGS) : 0;
        !          1757:     *out = EOS;                             /* Ensure to termanate  */
        !          1758:
        !          1759:     while ((c = *in++) != EOS) {
        !          1760:         if (c == MAC_PARM) {                /* Formal parameter     */
        !          1761:             c = *in++ & UCHARMAX;           /* Parameter number     */
        !          1762:             if (mcpp_debug & EXPAND) {
        !          1763:                 mcpp_fprintf( DBG, " (expanding arg[%d])", c);
        !          1764:                 dump_string( NULL, arglist[ c - 1]);
        !          1765:             }
        !          1766: #if COMPILER == GNUC || COMPILER == MSC
        !          1767:             arg = arglist[ c - 1];
        !          1768:             if (trace_macro) {
        !          1769:                 if (*arg == MAC_INF) {
        !          1770:                     if (*++arg == MAC_ARG_START)
        !          1771:                         arg += ARG_S_LEN - 1;       /* Next to magic chars  */
        !          1772:                 }
        !          1773:             }
        !          1774: #if COMPILER == GNUC
        !          1775:             if (c == gvar_arg && *arg == RT_END && ! ansi) {
        !          1776:                 /*
        !          1777:                  * GCC variadic macro and its variable argument is absent.
        !          1778:                  * Note that in its "strict-ansi" mode GCC does not remove
        !          1779:                  * ',', nevertheless it ignores '##' (inconsistent
        !          1780:                  * behavior).  Though GCC2 changes behavior depending the
        !          1781:                  * ',' is preceded by space or not, we only count on the
        !          1782:                  * "strict-ansi" flag.
        !          1783:                  */
        !          1784: #else
        !          1785:             if ((defp->nargs & VA_ARGS) && c == (defp->nargs & ~VA_ARGS)
        !          1786:                     && *arg == RT_END && mcpp_mode == STD) {
        !          1787:                 /* Visual C 2005 also removes ',' immediately preceding     */
        !          1788:                 /* absent variable arguments.  It does not use '##' though. */
        !          1789: #endif
        !          1790:                 char *  tmp;
        !          1791:                 tmp = out - 1;
        !          1792:                 while (char_type[ *tmp & UCHARMAX] & HSP)
        !          1793:                     tmp--;
        !          1794:                 if (*tmp == ',') {
        !          1795:                     out = tmp;      /* Remove the immediately preceding ',' */
        !          1796:                     if (warn_level & 1) {
        !          1797:                         *out = EOS;
        !          1798:                         diag_macro( CWARN,
        !          1799:         "Removed ',' preceding the absent variable argument: %s"    /* _W1_ */
        !          1800:                                 , out_start, 0L, NULL, defp, NULL);
        !          1801:                     }
        !          1802:                 }
        !          1803:             } else
        !          1804: #endif
        !          1805:             if ((out = rescan( NULL, arglist[ c - 1], out, out_end))
        !          1806:                     == NULL) {              /* Replace completely   */
        !          1807:                 return  NULL;               /* Error                */
        !          1808:             }
        !          1809:         } else {
        !          1810:             *out++ = c;                     /* Copy the character   */
        !          1811:         }
        !          1812:     }
        !          1813:     *out = EOS;
        !          1814:     return  out;
        !          1815: }
        !          1816:
        !          1817: static char *   rescan(
        !          1818:     const DEFBUF *  outer,          /* Outer macro just replacing   */
        !          1819:     const char *    in,             /* Sequences to be rescanned    */
        !          1820:     char *  out,                            /* Output buffer        */
        !          1821:     char *  out_end                         /* End of output buffer */
        !          1822: )
        !          1823: /*
        !          1824:  * Re-scan the once replaced sequences to replace the remaining macros
        !          1825:  * completely.
        !          1826:  * rescan() and replace() call each other recursively.
        !          1827:  *
        !          1828:  * Note: POST_STD mode does not use IN_SRC nor TOK_SEP and seldom uses RT_END.
        !          1829:  * Checking of those are unnecessary overhead for POST_STD mode.  To integrate
        !          1830:  * the code for POST_STD with STD mode, however, we use these checkings
        !          1831:  * commonly.
        !          1832:  * Also compat_mode does not use IN_SRC unless in trace_macro mode.
        !          1833:  * STD mode has macro notification mode (trace_macro mode), too.  Its routines
        !          1834:  * are complicated and not easy to understand.
        !          1835:  */
        !          1836: {
        !          1837:     char *  cur_cp = NULL;
        !          1838:     char *  tp = NULL;              /* Temporary pointer into buffer*/
        !          1839:     char *  out_p = out;            /* Current output pointer       */
        !          1840:     FILEINFO *  file;       /* Input sequences stacked on a "file"  */
        !          1841:     DEFBUF *    inner;              /* Inner macro to replace       */
        !          1842:     int     c;                      /* First character of token     */
        !          1843:     int     token_type;
        !          1844:     char *  mac_arg_start = NULL;
        !          1845: #if COMPILER == GNUC
        !          1846:     int     within_defined = FALSE;
        !          1847:     int     within_defined_arg_depth = 0;
        !          1848: #endif
        !          1849:
        !          1850:     if (mcpp_debug & EXPAND) {
        !          1851:         mcpp_fprintf( DBG, "rescan_level--%d (%s) "
        !          1852:                 , rescan_level + 1, outer ? outer->name : "<arg>");
        !          1853:         dump_string( "rescan entry", in);
        !          1854:     }
        !          1855:     if (! disable_repl( outer)) /* Don't re-replace replacing macro */
        !          1856:         return  NULL;               /* Too deeply nested macro call */
        !          1857:     if (mcpp_mode == STD) {
        !          1858:         get_ch();                   /* Clear empty "file"s          */
        !          1859:         unget_ch();                 /*      for diagnostic          */
        !          1860:         cur_cp = infile->bptr;      /* Remember current location    */
        !          1861:     }
        !          1862:     file = unget_string( in, outer ? outer->name : NULL);
        !          1863:                                     /* Stack input on a "file"      */
        !          1864:
        !          1865:     while ((c = get_ch()), file == infile
        !          1866:         /* Rescanning is limited to the "file"  */
        !          1867:             && c != RT_END) {
        !          1868:             /*
        !          1869:              * This is the trick of STD mode.  collect_args() via replace()
        !          1870:              * may read over to file->parent (provided the "file" is macro)
        !          1871:              * unless stopped by RT_END.
        !          1872:              */
        !          1873:         size_t  len = 0;
        !          1874:
        !          1875:         if (char_type[ c] & HSP) {
        !          1876:             *out_p++ = c;
        !          1877:             continue;
        !          1878:         } else if (c == MAC_INF) {              /* Only in STD mode */
        !          1879:             *out_p++ = c;
        !          1880:             *out_p++ = c = get_ch();
        !          1881:             switch (c) {
        !          1882:             case MAC_ARG_START  :
        !          1883:                 mac_arg_start = out_p - 2;      /* Remember the position    */
        !          1884:                 *out_p++ = get_ch();
        !          1885:                 /* Fall through */
        !          1886:             case MAC_CALL_START :
        !          1887:                 *out_p++ = get_ch();
        !          1888:                 *out_p++ = get_ch();
        !          1889:                 break;
        !          1890:             case MAC_ARG_END    :
        !          1891:                 if (! option_flags.v)
        !          1892:                     break;
        !          1893:                 else
        !          1894:                     *out_p++ = get_ch();
        !          1895:                     /* Fall through */
        !          1896:             case MAC_CALL_END   :
        !          1897:                 if (option_flags.v) {
        !          1898:                     *out_p++ = get_ch();
        !          1899:                     *out_p++ = get_ch();
        !          1900:                 }
        !          1901:                 break;
        !          1902:             }               /* Pass these characters as they are    */
        !          1903:             continue;
        !          1904:         }
        !          1905:         token_type = scan_token( c, (tp = out_p, &out_p), out_end);
        !          1906: #if COMPILER == GNUC
        !          1907:         if (mcpp_mode == STD) {
        !          1908:             /* Pass stuff within defined() as they are, if in_directive */
        !          1909:             if ((within_defined || within_defined_arg_depth)) {
        !          1910:                 if (c == '(') {
        !          1911:                     within_defined_arg_depth++;
        !          1912:                     within_defined = FALSE;
        !          1913:                 } else if (within_defined_arg_depth && c == ')') {
        !          1914:                     within_defined_arg_depth--;
        !          1915:                 }       /* Else should be a name (possibly macro)   */
        !          1916:                 continue;
        !          1917:             } else if (token_type == NAM && in_directive
        !          1918:                         && str_eq(identifier, "defined")) {
        !          1919:                 within_defined = TRUE;
        !          1920:                             /* 'defined' token in directive line    */
        !          1921:                 continue;
        !          1922:             }
        !          1923:         }
        !          1924: #endif
        !          1925:         if (mcpp_mode == STD && c == IN_SRC)
        !          1926:             len = trace_macro ? IN_SRC_LEN : 1;
        !          1927:         if (token_type == NAM && c != DEF_MAGIC
        !          1928:                 && (inner = look_id( tp + len)) != NULL) {  /* A macro name */
        !          1929:             int     is_able;        /* Macro is not "blue-painted"  */
        !          1930:             char *  endf = NULL;    /* Output stream at end of infile       */
        !          1931:             MAGIC_SEQ   mgc_seq;    /* Magics between macro name and '('    */
        !          1932:
        !          1933:             if (trace_macro)
        !          1934:                 memset( &mgc_seq, 0, sizeof (MAGIC_SEQ));
        !          1935:             if (is_macro_call( inner, &out_p, &endf
        !          1936:                         , trace_macro ? &mgc_seq : NULL)
        !          1937:                     && ((mcpp_mode == POST_STD && is_able_repl( inner))
        !          1938:                         || (mcpp_mode == STD
        !          1939:                             && (((is_able = is_able_repl( inner)) == YES)
        !          1940:                                 || (is_able == READ_OVER
        !          1941:                                     && (c == IN_SRC || compat_mode)))))) {
        !          1942:                                             /* Really a macro call  */
        !          1943:                 LINE_COL    in_src_line_col = { 0L, 0};
        !          1944:                 int     in_src_n = 0;
        !          1945:
        !          1946:                 if (trace_macro) {
        !          1947:                     if (c == IN_SRC) {  /* Macro in argument from source    */
        !          1948:                         /* Get the location in source   */
        !          1949:                         in_src_n = ((*(tp + 1) & UCHARMAX) - 1) * UCHARMAX;
        !          1950:                         in_src_n += (*(tp + 2) & UCHARMAX) - 1;
        !          1951:                         in_src_line_col.line = in_src[ in_src_n].start_line;
        !          1952:                         in_src_line_col.col = in_src[ in_src_n].start_col;
        !          1953:                     }
        !          1954:                     if (inner->nargs >= 0 && mgc_seq.magic_start) {
        !          1955:                         /* Magic sequence is found between macro */
        !          1956:                         /* name and '('.  This is a nuisance.    */
        !          1957:                         char *      mgc_cleared;
        !          1958:                         size_t      seq_len;
        !          1959:                         size_t      arg_elen = option_flags.v ? ARG_E_LEN_V
        !          1960:                                             : ARG_E_LEN;
        !          1961:                         if ((tp - ARG_S_LEN) == mac_arg_start
        !          1962:                                 && *mgc_seq.magic_start == MAC_INF
        !          1963:                                 && *(mgc_seq.magic_start + 1) == MAC_ARG_END) {
        !          1964:                             /* Name of function-like macro is surrounded by */
        !          1965:                             /* magics, which were inserted by outer macro.  */
        !          1966:                             /* Remove the starting magic. (The closing magic*/
        !          1967:                             /* has already been removed by is_macro_call(). */
        !          1968:                             tp -= ARG_S_LEN;
        !          1969:                             mgc_seq.magic_start += arg_elen;    /* Next seq */
        !          1970:                         }
        !          1971:                         /* Restore once skipped magic sequences,    */
        !          1972:                         /* then remove "pair"s of sequences.        */
        !          1973:                         seq_len = mgc_seq.magic_end - mgc_seq.magic_start;
        !          1974:                         if (seq_len) {
        !          1975:                             insert_to_bptr( mgc_seq.magic_start, seq_len);
        !          1976:                             mgc_cleared = remove_magics(
        !          1977:                                     (const char *) infile->bptr, FALSE);
        !          1978:                                         /* Remove pair of magics    */
        !          1979:                             strcpy( infile->bptr, mgc_cleared);
        !          1980:                             free( mgc_cleared);
        !          1981:                         }
        !          1982:                     }
        !          1983:                 }
        !          1984:                 if ((out_p = replace( inner, tp, out_end, outer, file
        !          1985:                         , in_src_line_col, in_src_n)) == NULL)
        !          1986:                     break;                  /* Error of macro call  */
        !          1987:             } else {
        !          1988:                 if (endf && strlen( endf)) {
        !          1989:                     /* Has read over to parent file: another nuisance.      */
        !          1990:                     /* Restore the read-over sequence into current buffer.  */
        !          1991:                     /* Don't use unget_string() here.                       */
        !          1992:                     insert_to_bptr( endf, out_p - endf);
        !          1993:                     out_p = endf;
        !          1994:                     *out_p = EOS;
        !          1995:                 }
        !          1996:                 if ((is_able = is_able_repl( inner)) == NO
        !          1997:                         || (mcpp_mode == STD && is_able == READ_OVER
        !          1998:                                 && c != IN_SRC && ! compat_mode)) {
        !          1999:                     if (mcpp_mode == POST_STD || c != IN_SRC)
        !          2000:                         memmove( tp + 1, tp, (size_t) (out_p++ - tp));
        !          2001:                     *tp = DEF_MAGIC;        /* Mark not to replace  */
        !          2002:                 }                           /* Else not a macro call*/
        !          2003:             }
        !          2004:         }
        !          2005:         if (out_end <= out_p) {
        !          2006:             *out_p = EOS;
        !          2007:             diag_macro( CERROR, macbuf_overflow, outer ? outer->name : in, 0L
        !          2008:                     , out, outer, inner);
        !          2009:             out_p = NULL;
        !          2010:             break;
        !          2011:         }
        !          2012:     }
        !          2013:
        !          2014:     if (out_p) {
        !          2015:         *out_p = EOS;
        !          2016:         if (mcpp_mode == STD) {
        !          2017:             if  (c != RT_END) {
        !          2018:                 unget_ch();
        !          2019:                 if (outer != NULL) {    /* outer isn't a macro in argument  */
        !          2020:                     if (infile && infile->bptr != cur_cp
        !          2021:                                     /* Have overrun replacement list*/
        !          2022:                             && !(tp && *tp == DEF_MAGIC)
        !          2023:                                                 /* Macro is enabled */
        !          2024:                             && ((!compat_mode && (warn_level & 1))
        !          2025:                                 || (compat_mode && (warn_level & 8)))) {
        !          2026:                         diag_macro( CWARN,
        !          2027: "Replacement text \"%s\" of macro %.0ld\"%s\" involved subsequent text" /* _W1_ */
        !          2028:                             , in, 0L, outer->name, outer, inner);
        !          2029:                     }
        !          2030:                 }
        !          2031:             }                       /* Else remove RT_END           */
        !          2032:         } else {
        !          2033:             unget_ch();
        !          2034:         }
        !          2035:     }
        !          2036:     enable_repl( outer, TRUE);      /* Enable macro for later text  */
        !          2037:     if (mcpp_debug & EXPAND) {
        !          2038:         mcpp_fprintf( DBG, "rescan_level--%d (%s) "
        !          2039:                 , rescan_level + 1, outer ? outer->name : "<arg>");
        !          2040:         dump_string( "rescan exit", out);
        !          2041:     }
        !          2042:     return  out_p;
        !          2043: }
        !          2044:
        !          2045: static int  disable_repl(
        !          2046:     const DEFBUF *  defp
        !          2047: )
        !          2048: /*
        !          2049:  * Register the macro name currently replacing.
        !          2050:  */
        !          2051: {
        !          2052:     if (defp == NULL)
        !          2053:         return  TRUE;
        !          2054:     if (rescan_level >= RESCAN_LIMIT) {
        !          2055:         diag_macro( CERROR,
        !          2056:             "Rescanning macro \"%s\" more than %ld times at \"%s\"" /* _E_  */
        !          2057:                 , macro_name, (long) RESCAN_LIMIT, defp->name, defp, NULL);
        !          2058:         return  FALSE;
        !          2059:     }
        !          2060:     replacing[ rescan_level].def = defp;
        !          2061:     replacing[ rescan_level++].read_over = NO;
        !          2062:     return  TRUE;
        !          2063: }
        !          2064:
        !          2065: static void enable_repl(
        !          2066:     const DEFBUF *  defp,
        !          2067:     int         done
        !          2068: )
        !          2069: /*
        !          2070:  * Un-register the macro name just replaced for later text.
        !          2071:  */
        !          2072: {
        !          2073:     if (defp == NULL)
        !          2074:         return;
        !          2075:     replacing[ rescan_level - 1].def = NULL;
        !          2076:     if (done && rescan_level)
        !          2077:         rescan_level--;
        !          2078: }
        !          2079:
        !          2080: static int  is_able_repl(
        !          2081:     const DEFBUF *  defp
        !          2082: )
        !          2083: /*
        !          2084:  * The macro is permitted to replace ?
        !          2085:  */
        !          2086: {
        !          2087:     int     i;
        !          2088:
        !          2089:     if (defp == NULL)
        !          2090:         return  YES;
        !          2091:     for (i = rescan_level-1; i >= 0; i--) {
        !          2092:         if (defp == replacing[ i].def)
        !          2093:             return  replacing[ i].read_over;
        !          2094:     }
        !          2095:     return  YES;
        !          2096: }
        !          2097:
        !          2098: static char *   insert_to_bptr(
        !          2099:     char *  ins,            /* Sequence to be inserted  */
        !          2100:     size_t  len             /* Byte to be inserted      */
        !          2101: )
        !          2102: /*
        !          2103:  * Insert a sequence into infile->bptr.
        !          2104:  * infile->buffer is reallocated to ensure buffer size.
        !          2105:  * This routine changes absolute address of infile->bptr, hence rescan() emits
        !          2106:  * a "Replacement text ... involved subsequent text" warning.  Anyway,
        !          2107:  * a macro which needs this routine deserves that warning.
        !          2108:  */
        !          2109: {
        !          2110:     size_t  bptr_offset = infile->bptr - infile->buffer;
        !          2111:
        !          2112:     if (infile->fp == NULL) {               /* Not source file      */
        !          2113:         infile->buffer = xrealloc( infile->buffer
        !          2114:                 , strlen( infile->buffer) + len + 1);
        !          2115:         infile->bptr = infile->buffer + bptr_offset;
        !          2116:     }
        !          2117:     memmove( infile->bptr + len, infile->bptr, strlen( infile->bptr) + 1);
        !          2118:     memcpy( infile->bptr, ins, len);
        !          2119:
        !          2120:     return  infile->buffer;
        !          2121: }
        !          2122:
        !          2123: /*
        !          2124:  *  M a c r o   E x p a n s i o n   i n   P R E - S T A N D A R D   M o d e
        !          2125:  */
        !          2126:
        !          2127: #include    "setjmp.h"
        !          2128:
        !          2129: static jmp_buf  jump;
        !          2130:
        !          2131: static char *   arglist_pre[ NMACPARS];     /* Pointers to args     */
        !          2132:
        !          2133: static int      rescan_pre( int c, char * mp, char * mac_end);
        !          2134:                 /* Replace a macro repeatedly   */
        !          2135: static int      replace_pre( DEFBUF * defp);
        !          2136:                 /* Replace a macro once         */
        !          2137: static void     substitute_pre( DEFBUF * defp);
        !          2138:                 /* Substitute parms with args   */
        !          2139:
        !          2140: static char *   expand_prestd(
        !          2141:     DEFBUF *    defp,                       /* Macro definition     */
        !          2142:     char *  out,                            /* Output buffer        */
        !          2143:     char *  out_end,                        /* End of output buffer */
        !          2144:     LINE_COL    line_col,       /* Location of macro (not used in prestd)   */
        !          2145:     int *   pragma_op           /* Flag of _Pragma (not used in prestd)     */
        !          2146: )
        !          2147: /*
        !          2148:  * Expand a macro call completely, write the results to the specified buffer
        !          2149:  * and return the advanced pointer.
        !          2150:  */
        !          2151: {
        !          2152:     char    macrobuf[ NMACWORK + IDMAX];    /* Buffer for rescan_pre()      */
        !          2153:     char *  mac_end = &macrobuf[ NMACWORK]; /* End of macrobuf[]    */
        !          2154:     char *  out_p;                          /* Pointer into out[]   */
        !          2155:     char *  mp = macrobuf;                  /* Pointer into macrobuf*/
        !          2156:     int     len;                            /* Length of a token    */
        !          2157:     int     token_type;                     /* Type of token        */
        !          2158:     int     c;
        !          2159:
        !          2160:     macro_line = src_line;                  /* Line number for diag.*/
        !          2161:     unget_string( identifier, identifier);  /* To re-read           */
        !          2162:     macro_name = defp->name;
        !          2163:     rescan_level = 0;
        !          2164:     if (setjmp( jump) == 1) {
        !          2165:         skip_macro();
        !          2166:         mp = macrobuf;
        !          2167:         *mp = EOS;
        !          2168:         macro_line = MACRO_ERROR;
        !          2169:         goto  err_end;
        !          2170:     }
        !          2171:
        !          2172:     while ((c = get_ch()) != CHAR_EOF && infile->fp == NULL) {
        !          2173:                             /* While the input stream is a macro    */
        !          2174:         while (c == ' ' || c == '\t') {     /* Output the spaces    */
        !          2175:             *mp++ = c;
        !          2176:             c = get_ch();
        !          2177:             if (infile == NULL || infile->fp != NULL)
        !          2178:                 goto  exp_end;
        !          2179:         }
        !          2180:         token_type = rescan_pre( c, mp, mac_end);   /* Scan token   */
        !          2181:             /*  and expand.  Result of expansion is written at mp.  */
        !          2182:
        !          2183:         switch (token_type) {
        !          2184:         case STR:                           /* String literal       */
        !          2185:         case CHR:                           /* Character constant   */
        !          2186:         case NUM:                           /* Number token         */
        !          2187:         case OPE:                           /* Operator or punct.   */
        !          2188:         case NAM:                           /* Identifier           */
        !          2189:             len = strlen( mp);
        !          2190:             mp += len;
        !          2191:             break;
        !          2192:         case SEP:                           /* Special character    */
        !          2193:             switch( *mp) {
        !          2194:             case COM_SEP:
        !          2195:                 if (mcpp_mode == OLD_PREP)
        !          2196:                     break;  /* Zero-length comment is removed now   */
        !          2197:                 /* Else fall through    */
        !          2198:             default:                        /* Who knows ?          */
        !          2199:                 mp++;                       /* Copy the character   */
        !          2200:                 break;
        !          2201:             }
        !          2202:             break;
        !          2203:         case NO_TOKEN:  break;              /* End of file          */
        !          2204:         default:                            /* Unkown token char.   */
        !          2205:             mp++;                           /* Copy the character   */
        !          2206:             break;
        !          2207:         }
        !          2208:
        !          2209:         if (mac_end <= mp) {
        !          2210:             *mp = EOS;
        !          2211:             cerror( macbuf_overflow, macro_name, 0L, macrobuf);
        !          2212:             longjmp( jump, 1);
        !          2213:         }
        !          2214:         if (mcpp_debug & GETC) {
        !          2215:             *mp = EOS;
        !          2216:             dump_string( "macrobuf", macrobuf);
        !          2217:         }
        !          2218:     }
        !          2219:
        !          2220: exp_end:
        !          2221:     unget_ch();
        !          2222:     while (macrobuf < mp && (*(mp - 1) == ' ' || *(mp - 1) == '\t'))
        !          2223:         mp--;                           /* Remove trailing blank    */
        !          2224:     macro_line = 0;
        !          2225:     *mp = EOS;
        !          2226:     if (mp - macrobuf > out_end - out) {
        !          2227:         cerror( macbuf_overflow, macro_name, 0L, macrobuf);
        !          2228:         macro_line = MACRO_ERROR;
        !          2229:     }
        !          2230: err_end:
        !          2231:     out_p = stpcpy( out, macrobuf);
        !          2232:     if (mcpp_debug & EXPAND) {
        !          2233:         dump_string( "expand_prestd exit", out);
        !          2234:     }
        !          2235:     macro_name = NULL;
        !          2236:     clear_exp_mac();
        !          2237:     *pragma_op = FALSE;
        !          2238:     return  out_p;
        !          2239: }
        !          2240:
        !          2241: static int  rescan_pre(
        !          2242:     int     c,                      /* First character of token     */
        !          2243:     char *  mp,                     /* Output buffer                */
        !          2244:     char *  mac_end                 /* End of output buffer         */
        !          2245: )
        !          2246: /*
        !          2247:  * If the token is a macro name, replace the macro repeatedly until the first
        !          2248:  * token becomes a non-macro and return the type of token after expansion.
        !          2249:  */
        !          2250: {
        !          2251:     int     token_type;             /* Type of token                */
        !          2252:     char *  cp = mp;        /* Value of mp should not be changed    */
        !          2253:     DEFBUF *    defp;
        !          2254:     FILEINFO *  file;
        !          2255:
        !          2256:     while ((token_type = scan_token( c, &cp, mac_end)) == NAM
        !          2257:             && (defp = look_id( identifier)) != NULL) { /* Macro    */
        !          2258:         if (replace_pre( defp) == FALSE)
        !          2259:             break;                  /* Macro name with no argument  */
        !          2260:         file = infile;
        !          2261:         c = get_ch();
        !          2262:         if (file != infile) {       /* Replaced to 0 token          */
        !          2263:             unget_ch();
        !          2264:             token_type = NO_TOKEN;
        !          2265:             break;
        !          2266:         }
        !          2267:         cp = mp;                    /* Overwrite on the macro call  */
        !          2268:     }                               /* The macro call is replaced   */
        !          2269:     return  token_type;
        !          2270: }
        !          2271:
        !          2272: static int  replace_pre(
        !          2273:     DEFBUF *    defp                /* Definition of the macro      */
        !          2274: )
        !          2275: /*
        !          2276:  * Replace a macro one level.  Called from expand_prestd() (via rescan_pre())
        !          2277:  * when an identifier is found in the macro table.  It calls collect_args()
        !          2278:  * to parse actual arguments, checking for the correct number.  It then
        !          2279:  * creates a "file" containing single line containing the replacement text
        !          2280:  * with the actual arguments inserted appropriately.  This is "pushed back"
        !          2281:  * onto the input stream.  (When get_ch() routine runs off the end of the macro
        !          2282:  * line, it will dismiss the macro itself.)
        !          2283:  */
        !          2284: {
        !          2285:     int         arg_len;
        !          2286:     int         c;
        !          2287:
        !          2288:     if (mcpp_debug & EXPAND) {
        !          2289:         dump_a_def( "replace_pre entry", defp, FALSE, TRUE, fp_debug);
        !          2290:         dump_unget( "replace_pre entry");
        !          2291:     }
        !          2292:     if (++rescan_level >= PRESTD_RESCAN_LIMIT) {
        !          2293:         diag_macro( CERROR
        !          2294:                 , "Recursive macro definition of \"%s\""    /* _E_  */
        !          2295:                 , defp->name, 0L, NULL, defp, NULL);
        !          2296:         longjmp( jump, 1);
        !          2297:     }
        !          2298:
        !          2299:     /*
        !          2300:      * Here's a macro to replace.
        !          2301:      */
        !          2302:     switch (defp->nargs) {
        !          2303:     case DEF_NOARGS:                /* No argument just stuffs      */
        !          2304:     case DEF_NOARGS_PREDEF_OLD:     /* Compiler-specific predef without '_' */
        !          2305:     case DEF_NOARGS_PREDEF:         /* Compiler-specific predef     */
        !          2306:         break;
        !          2307:     default:                                /* defp->nargs >= 0     */
        !          2308:         c = squeeze_ws( NULL, NULL, NULL);  /* Look for and skip '('*/
        !          2309:         if (c != '(') {         /* Macro name without following '(' */
        !          2310:             unget_ch();
        !          2311:             if (warn_level & 8)
        !          2312:                 diag_macro( CWARN, only_name, defp->name, 0L, NULL, defp, NULL);
        !          2313:             return  FALSE;
        !          2314:         } else {
        !          2315:             arglist_pre[ 0] = xmalloc( (size_t) (NMACWORK + IDMAX * 2));
        !          2316:             arg_len = collect_args( defp, arglist_pre, 0);
        !          2317:                                             /* Collect arguments    */
        !          2318:             if (arg_len == ARG_ERROR) {     /* End of input         */
        !          2319:                 free( arglist_pre[ 0]);
        !          2320:                 longjmp( jump, 1);
        !          2321:             }
        !          2322:         }
        !          2323:         break;
        !          2324:     }
        !          2325:
        !          2326:     if (defp->nargs > 0)
        !          2327:         substitute_pre( defp);              /* Do actual arguments  */
        !          2328:     else
        !          2329:         unget_string( defp->repl, defp->name);
        !          2330:
        !          2331:     if (mcpp_debug & EXPAND)
        !          2332:         dump_unget( "replace_pre exit");
        !          2333:     if (defp->nargs >= 0)
        !          2334:         free( arglist_pre[ 0]);
        !          2335:     return  TRUE;
        !          2336: }
        !          2337:
        !          2338: static void substitute_pre(
        !          2339:     DEFBUF *        defp            /* Current macro being replaced */
        !          2340: )
        !          2341: /*
        !          2342:  * Stuff the macro body, substituting formal parameters with actual arguments.
        !          2343:  */
        !          2344: {
        !          2345:     int         c;                          /* Current character    */
        !          2346:     FILEINFO *  file;                       /* Funny #include       */
        !          2347:     char *      out_end;                    /* -> output buffer end */
        !          2348:     char *      in_p;                       /* -> replacement text  */
        !          2349:     char *      out_p;                      /* -> macro output buff */
        !          2350:
        !          2351:     file = get_file( defp->name, NULL, NULL, (size_t) (NMACWORK + 1), FALSE);
        !          2352:                                             /* file == infile       */
        !          2353:     in_p = defp->repl;                      /* -> macro replacement */
        !          2354:     out_p = file->buffer;                   /* -> output buffer     */
        !          2355:     out_end = file->buffer + NMACWORK;      /* -> buffer end        */
        !          2356:
        !          2357:     while ((c = *in_p++) != EOS) {
        !          2358:         if (c == MAC_PARM) {
        !          2359:             c = (*in_p++ & UCHARMAX) - 1;   /* Parm number          */
        !          2360:             /*
        !          2361:              * Substitute formal parameter with actual argument.
        !          2362:              */
        !          2363:             if (out_end <= (out_p + strlen( arglist_pre[ c])))
        !          2364:                 goto nospace;
        !          2365:             out_p = stpcpy( out_p, arglist_pre[ c]);
        !          2366:         } else {
        !          2367:             *out_p++ = c;
        !          2368:         }
        !          2369:         if (out_end <= out_p)
        !          2370:             goto  nospace;
        !          2371:     }
        !          2372:
        !          2373:     *out_p = EOS;
        !          2374:     file->buffer = xrealloc( file->buffer, strlen( file->buffer) + 1);
        !          2375:     file->bptr = file->buffer;              /* Truncate buffer      */
        !          2376:     if (mcpp_debug & EXPAND)
        !          2377:         dump_string( "substitute_pre macroline", file->buffer);
        !          2378:     return;
        !          2379:
        !          2380: nospace:
        !          2381:     *out_p = EOS;
        !          2382:     diag_macro( CERROR, macbuf_overflow, defp->name, 0L, file->buffer, defp
        !          2383:             , NULL);
        !          2384:     longjmp( jump, 1);
        !          2385: }
        !          2386:
        !          2387:
        !          2388: /*
        !          2389:  *                  C O M M O N   R O U T I N E S
        !          2390:  *  f o r   S T A N D A R D   a n d   p r e - S T A N D A R D   M o d e s
        !          2391:  */
        !          2392:
        !          2393: static int  collect_args(
        !          2394:     const DEFBUF *  defp,       /* Definition of the macro          */
        !          2395:     char **     arglist,        /* Pointers to actual arguments     */
        !          2396:     int         m_num           /* Index into mac_inf[]             */
        !          2397: )
        !          2398: /*
        !          2399:  *   Collect the actual arguments for the macro, checking for correct number
        !          2400:  * of arguments.
        !          2401:  *   Variable arguments (on Standard modes) are read as a merged argument.
        !          2402:  *   Return number of real arguments, or ARG_ERROR on error of unterminated
        !          2403:  * macro.
        !          2404:  *   collect_args() may read over to the next line unless 'in_directive' is
        !          2405:  * set to TRUE.
        !          2406:  *   collect_args() may read over into file->parent to complete a macro call
        !          2407:  * unless stopped by RT_END (provided the "file" is macro).  This is a key
        !          2408:  * trick of STD mode macro expansion.  Meanwhile, POST_STD mode limits the
        !          2409:  * arguments in the "file" (macro or not).
        !          2410:  *   Note: arglist[ n] may be reallocated by collect_args().
        !          2411:  */
        !          2412: {
        !          2413:     const char *    name = defp->name;
        !          2414:     char *  argp = arglist[ 0];         /* Pointer to an argument   */
        !          2415:     char *  arg_end;                    /* End of arguments buffer  */
        !          2416:     char *  valid_argp = NULL;          /* End of valid arguments   */
        !          2417:     char *  sequence;           /* Token sequence for diagnostics   */
        !          2418:     char *  seq;                /* Current pointer into 'sequence'  */
        !          2419:     char *  seq_end;                            /* Limit of buffer  */
        !          2420:     int     args;               /* Number of arguments expected     */
        !          2421:     int     nargs = 0;                  /* Number of collected args */
        !          2422:     int     var_arg = defp->nargs & VA_ARGS;    /* Variable args    */
        !          2423:     int     more_to_come = FALSE;       /* Next argument is expected*/
        !          2424:     LOCATION *  locs;           /* Location of args in source file  */
        !          2425:     LOCATION *  loc;                            /* Current locs     */
        !          2426:     MAGIC_SEQ   mgc_prefix;     /* MAC_INF seqs and spaces preceding an arg */
        !          2427:     int     c;
        !          2428:
        !          2429:     if (mcpp_debug & EXPAND)
        !          2430:         dump_unget( "collect_args entry");
        !          2431:     args = (defp->nargs == DEF_PRAGMA) ? 1 : (defp->nargs & ~AVA_ARGS);
        !          2432:     if (args == 0)                      /* Need no argument         */
        !          2433:         valid_argp = argp;
        !          2434:     *argp = EOS;                        /* Make sure termination    */
        !          2435:     arg_end = argp + NMACWORK/2;
        !          2436:     seq = sequence = arg_end + IDMAX;   /* Use latter half of argp  */
        !          2437:     seq_end = seq + NMACWORK/2;
        !          2438:     seq = stpcpy( seq, name);
        !          2439:     *seq++ = '(';
        !          2440:     if (mcpp_mode == STD) {
        !          2441:         /*
        !          2442:          * in_getarg is set TRUE while getting macro arguments, for the sake
        !          2443:          * of diagnostic's convenience.  in_getarg is used only in STD mode.
        !          2444:          */
        !          2445:         in_getarg = TRUE;
        !          2446:         if (trace_macro && m_num) {
        !          2447:             /* #pragma MCPP debug macro_call, and the macro is on source    */
        !          2448:             mac_inf[ m_num].loc_args = loc = locs
        !          2449:                     = (LOCATION *) xmalloc( (sizeof (LOCATION)) * UCHARMAX);
        !          2450:             memset( loc, 0, (sizeof (LOCATION)) * UCHARMAX);
        !          2451:                     /* 0-clear for default values, including empty argument */
        !          2452:         }
        !          2453:     }
        !          2454:
        !          2455:     while (1) {
        !          2456:         memset( &mgc_prefix, 0, sizeof (MAGIC_SEQ));
        !          2457:         c = squeeze_ws( &seq, NULL
        !          2458:                 , (trace_macro && m_num) ? &mgc_prefix : NULL);
        !          2459:             /* Skip MAC_INF seqs and white spaces, still remember   */
        !          2460:             /* the sequence in buffer, if necessary.                */
        !          2461:         if (c == ')' || c == ',')
        !          2462:             scan_token( c, &seq, seq_end);  /* Ensure token parsing */
        !          2463:         else
        !          2464:             *seq = EOS;
        !          2465:
        !          2466:         switch (c) {                    /* First character of token */
        !          2467:         case ')':
        !          2468:             if (! more_to_come) {       /* Zero argument            */
        !          2469:                 if (trace_macro && m_num)
        !          2470:                     loc++;
        !          2471:                 break;
        !          2472:             }                           /* Else fall through        */
        !          2473:         case ',':                       /* Empty argument           */
        !          2474:             if (trace_macro && m_num)
        !          2475:                 loc++;                  /* Advance pointer to infs  */
        !          2476:             if (warn_level & 2)
        !          2477:                 diag_macro( CWARN, empty_arg, sequence, 0L, NULL, defp, NULL);
        !          2478:             if (standard && var_arg && nargs == args - 1) {
        !          2479:                 /* Variable arguments begin with an empty argument  */
        !          2480:                 c = get_an_arg( c, &argp, arg_end, &seq, 1, nargs, &loc
        !          2481:                         , m_num, (trace_macro && m_num) ? &mgc_prefix : NULL);
        !          2482:             } else {
        !          2483:                 if (mcpp_mode == STD)
        !          2484:                     *argp++ = RT_END;
        !          2485:                 *argp++ = EOS;
        !          2486:             }
        !          2487:             if (++nargs == args)
        !          2488:                 valid_argp = argp;
        !          2489:             if (c == ',') {
        !          2490:                 more_to_come = TRUE;
        !          2491:                 continue;
        !          2492:             } else {                    /* ')'                      */
        !          2493:                 break;
        !          2494:             }
        !          2495:         case '\n':      /* Unterminated macro call in directive line*/
        !          2496:             unget_ch();                 /* Fall through             */
        !          2497:         case RT_END:                    /* Error of missing ')'     */
        !          2498:             diag_macro( CERROR, unterm_macro, sequence, 0L, NULL, defp, NULL);
        !          2499:                                         /* Fall through             */
        !          2500:         case CHAR_EOF:                  /* End of file in macro call*/
        !          2501:             nargs = ARG_ERROR;
        !          2502:             goto  arg_ret;              /* Diagnosed by at_eof()    */
        !          2503:         default:                        /* Nomal argument           */
        !          2504:             break;
        !          2505:         }
        !          2506:
        !          2507:         if (c == ')')                   /* At end of all args       */
        !          2508:             break;
        !          2509:
        !          2510:         c = get_an_arg( c, &argp, arg_end, &seq
        !          2511:                 , (var_arg && nargs == args - 1) ? 1 : 0, nargs, &loc
        !          2512:                 , m_num, (trace_macro && m_num) ? &mgc_prefix : NULL);
        !          2513:
        !          2514:         if (++nargs == args)
        !          2515:             valid_argp = argp;          /* End of valid arguments   */
        !          2516:         if (c == ')')
        !          2517:             break;
        !          2518:         if (c == 0) {                   /* End of file              */
        !          2519:             nargs = ARG_ERROR;
        !          2520:             goto  arg_ret;              /* Diagnosed by at_eof()    */
        !          2521:         }
        !          2522:         if (c == -1) {                  /* Untermanated macro call  */
        !          2523:             diag_macro( CERROR, unterm_macro, sequence, 0L, NULL, defp, NULL);
        !          2524:             nargs = ARG_ERROR;
        !          2525:             goto  arg_ret;
        !          2526:         }
        !          2527:         more_to_come = (c == ',');
        !          2528:     }                                   /* Collected all arguments  */
        !          2529:
        !          2530:     if (nargs == 0 && args == 1) {      /* Only and empty argument  */
        !          2531:         if (warn_level & 2)
        !          2532:             diag_macro( CWARN, empty_arg, sequence, 0L, NULL, defp, NULL);
        !          2533:     } else if (nargs != args) {         /* Wrong number of arguments*/
        !          2534:         if (mcpp_mode != OLD_PREP || (warn_level & 1)) {
        !          2535:             if ((standard && var_arg && (nargs == args - 1))
        !          2536:                                 /* Absence of variable arguments    */
        !          2537:                         || (mcpp_mode == OLD_PREP)) {
        !          2538:                 if (warn_level & 1)
        !          2539:                     diag_macro( CWARN, narg_error, nargs < args ? "Less"
        !          2540:                             : "More", (long) args, sequence, defp, NULL);
        !          2541:             } else {
        !          2542:                 diag_macro( CERROR, narg_error, nargs < args ? "Less" : "More"
        !          2543:                         , (long) args, sequence, defp, NULL);
        !          2544:             }
        !          2545:         }
        !          2546:     }
        !          2547:     if (args < nargs) {
        !          2548:         argp = valid_argp;              /* Truncate excess arguments*/
        !          2549:     } else {
        !          2550:         for (c = nargs; c < args; c++) {
        !          2551:             if (mcpp_mode == STD)
        !          2552:                 *argp++ = RT_END;       /* For rescan()             */
        !          2553:             *argp++ = EOS;              /* Missing arguments        */
        !          2554:         }
        !          2555:         if (c == 0)
        !          2556:             argp++;                     /* Ensure positive length   */
        !          2557:     }
        !          2558:     arglist[ 0] = argp
        !          2559:             = xrealloc( arglist[ 0], (size_t) (argp - arglist[ 0]));
        !          2560:                                         /* Use memory sparingly     */
        !          2561:     for (c = 1; c < args; c++)
        !          2562:         arglist[ c] = argp += strlen( argp) + 1;
        !          2563:     if (trace_macro && m_num)
        !          2564:         mac_inf[ m_num].loc_args        /* Truncate excess memory   */
        !          2565:                 = (LOCATION *) xrealloc( (char *) locs
        !          2566:                         , (loc - locs) * sizeof (LOCATION));
        !          2567:
        !          2568:     if (mcpp_debug & EXPAND) {
        !          2569:         if (nargs > 0) {
        !          2570:             if (nargs > args)
        !          2571:                 nargs = args;
        !          2572:             dump_args( "collect_args exit", nargs, (const char **) arglist);
        !          2573:         }
        !          2574:         dump_unget( "collect_args exit");
        !          2575:     }
        !          2576: arg_ret:
        !          2577:     if (mcpp_mode == STD)
        !          2578:         in_getarg = FALSE;
        !          2579:     /* Return number of found arguments for function-like macro at most */
        !          2580:     /* defp->nargs, or return defp->nargs for object-like macro.        */
        !          2581:     return  defp->nargs <= DEF_NOARGS ? defp->nargs : nargs;
        !          2582: }
        !          2583:
        !          2584: static int  get_an_arg(
        !          2585:     int     c,
        !          2586:     char ** argpp,      /* Address of pointer into argument list    */
        !          2587:     char *  arg_end,                /* End of argument list buffer  */
        !          2588:     char ** seqp,                   /* Buffer for diagnostics       */
        !          2589:     int     var_arg,                /* 1 on __VA_ARGS__, 0 on others*/
        !          2590:     int     nargs,                  /* Argument number              */
        !          2591:     LOCATION **     locp,           /* Where to save location infs  */
        !          2592:     int     m_num,                  /* Macro number to trace        */
        !          2593:     MAGIC_SEQ * mgc_prefix  /* White space and magics leading to argument   */
        !          2594: )
        !          2595: /*
        !          2596:  * Get an argument of macro into '*argpp', return the next punctuator.
        !          2597:  * Variable arguments are read as a merged argument.
        !          2598:  * Note: nargs, locp and m_num are used only in macro trace mode of
        !          2599:  * '#pragma MCPP debug macro_call' or -K option.
        !          2600:  */
        !          2601: {
        !          2602:     struct {
        !          2603:         int     n_par;
        !          2604:         int     n_in_src;
        !          2605:     } n_paren[ 16];
        !          2606:     int     num_paren = 0;
        !          2607:     int     end_an_arg = FALSE;             /* End-of-an-arg flag   */
        !          2608:     int     paren = var_arg;                /* For embedded ()'s    */
        !          2609:     int     token_type;
        !          2610:     char *  prevp;
        !          2611:     char *  argp = *argpp;
        !          2612:     int     trace_arg = 0;                  /* Enable tracing arg   */
        !          2613:     LINE_COL    s_line_col, e_line_col; /* Location of macro in an argument */
        !          2614:     MAGIC_SEQ   mgc_seq;        /* Magic seqs and spaces succeeding an arg  */
        !          2615:     size_t  len;
        !          2616:
        !          2617:     if (trace_macro) {
        !          2618:         trace_arg = m_num && infile->fp;
        !          2619:         if (m_num) {
        !          2620:             if (trace_arg) {        /* The macro call is in source  */
        !          2621:                 s_line_col.line = src_line;
        !          2622:                 s_line_col.col = infile->bptr - infile->buffer - 1;
        !          2623:                     /* '-1': bptr is one byte passed beginning of the token */
        !          2624:                 get_src_location( & s_line_col);
        !          2625:                 (*locp)->start_line = s_line_col.line;
        !          2626:                 (*locp)->start_col = s_line_col.col;
        !          2627:                 e_line_col = s_line_col;
        !          2628:                     /* Save the location,   */
        !          2629:                     /*      also for end of arg in case of empty arg*/
        !          2630:                 memset( n_paren, 0, sizeof (n_paren));
        !          2631:             }
        !          2632:             *argp++ = MAC_INF;
        !          2633:             *argp++ = MAC_ARG_START;
        !          2634:             *argp++ = (m_num / UCHARMAX) + 1;
        !          2635:             *argp++ = (m_num % UCHARMAX) + 1;
        !          2636:             *argp++ = nargs + 1;
        !          2637:                     /* Argument number internally starts at 1       */
        !          2638:             if (mgc_prefix->magic_start) {
        !          2639:                 /* Copy the preceding magics, if any    */
        !          2640:                 len = mgc_prefix->magic_end - mgc_prefix->magic_start;
        !          2641:                 memcpy( argp, mgc_prefix->magic_start, len);
        !          2642:                 argp += len;
        !          2643:             }
        !          2644:         }
        !          2645:         memset( &mgc_seq, 0, sizeof (MAGIC_SEQ));
        !          2646:     }
        !          2647:
        !          2648:     while (1) {
        !          2649:         if (c == '\n'                       /* In control line      */
        !          2650:                 || c == RT_END) {       /* Boundary of rescan (in STD mode) */
        !          2651:             if (c == '\n')
        !          2652:                 unget_ch();
        !          2653:             break;
        !          2654:         }
        !          2655:         if (trace_arg) {                    /* Save the location    */
        !          2656:             s_line_col.line = src_line;     /*      of the token    */
        !          2657:             s_line_col.col = infile->bptr - infile->buffer - 1;
        !          2658:         }
        !          2659:         token_type = scan_token( c, (prevp = argp, &argp), arg_end);
        !          2660:                                             /* Scan the next token  */
        !          2661:         switch (c) {
        !          2662:         case '(':                           /* Worry about balance  */
        !          2663:             paren++;                        /* To know about commas */
        !          2664:             break;
        !          2665:         case ')':                           /* Other side too       */
        !          2666:             if (paren-- == var_arg)         /* At the end?          */
        !          2667:                 end_an_arg = TRUE;          /* Else more to come    */
        !          2668:             if (trace_arg) {
        !          2669:                 if (num_paren && paren == n_paren[ num_paren].n_par) {
        !          2670:                     /* Maybe corresponding parentheses for the macro in arg */
        !          2671:                     int     src_n;
        !          2672:                     src_n = n_paren[ num_paren].n_in_src;
        !          2673:                     in_src[ src_n].end_line = s_line_col.line;
        !          2674:                     in_src[ src_n].end_col = s_line_col.col + 1;
        !          2675:                     num_paren--;
        !          2676:                 }
        !          2677:             }
        !          2678:             break;
        !          2679:         case ',':
        !          2680:             if (paren == 0)                 /* Comma delimits arg   */
        !          2681:                 end_an_arg = TRUE;
        !          2682:             break;
        !          2683:         case MAC_INF    :               /* Copy magics as they are  */
        !          2684:             switch (*argp++ = get_ch()) {
        !          2685:             case MAC_ARG_START  :
        !          2686:                 *argp++ = get_ch();
        !          2687:                 /* Fall through */
        !          2688:             case MAC_CALL_START :
        !          2689:                 *argp++ = get_ch();
        !          2690:                 *argp++ = get_ch();
        !          2691:                 break;
        !          2692:             case MAC_ARG_END    :
        !          2693:                 if (! option_flags.v)
        !          2694:                     break;
        !          2695:                 else
        !          2696:                     *argp++ = get_ch();
        !          2697:                     /* Fall through */
        !          2698:             case MAC_CALL_END   :
        !          2699:                 if (option_flags.v) {
        !          2700:                     *argp++ = get_ch();
        !          2701:                     *argp++ = get_ch();
        !          2702:                 }
        !          2703:                 break;
        !          2704:             }
        !          2705:             break;
        !          2706:         case CHAR_EOF   :                   /* Unexpected EOF       */
        !          2707:             return  0;
        !          2708:         default :                           /* Any token            */
        !          2709:             if (mcpp_mode == STD && token_type == NAM
        !          2710:                     && c != IN_SRC && c != DEF_MAGIC && infile->fp) {
        !          2711:                 len = trace_arg ? IN_SRC_LEN : 1;
        !          2712:                 memmove( prevp + len, prevp, (size_t) (argp - prevp));
        !          2713:                 argp += len;
        !          2714:                 *prevp = IN_SRC;
        !          2715:                     /* Mark that the name is read from source file  */
        !          2716:                 if (trace_arg) {
        !          2717:                     DEFBUF *    defp;
        !          2718:
        !          2719:                     defp = look_id( prevp + IN_SRC_LEN);
        !          2720:                     if (in_src_num >= MAX_IN_SRC_NUM - 1) {
        !          2721:                         cerror(
        !          2722:                         "Too many names in arguments tracing %s"    /* _E_  */
        !          2723:                                 , defp ? defp->name : null, 0L, NULL);
        !          2724:                         return  0;
        !          2725:                     } else if (++in_src_num > max_in_src_num) {
        !          2726:                         size_t  old_len;
        !          2727:                         old_len = sizeof (LOCATION) * max_in_src_num;
        !          2728:                         /* Enlarge the array    */
        !          2729:                         in_src = (LOCATION *) xrealloc( (char *) in_src
        !          2730:                                 , old_len * 2);
        !          2731:                         /* Have to initialize the enlarged area     */
        !          2732:                         memset( in_src + max_in_src_num, 0, old_len);
        !          2733:                         max_in_src_num *= 2;
        !          2734:                     }
        !          2735:                     /* Insert the identifier number in 2-bytes-encoding     */
        !          2736:                     *(prevp + 1) = (in_src_num / UCHARMAX) + 1;
        !          2737:                     *(prevp + 2) = (in_src_num % UCHARMAX) + 1;
        !          2738:                     if (defp) {             /* Macro name in arg    */
        !          2739:                         in_src[ in_src_num].start_line = s_line_col.line;
        !          2740:                         in_src[ in_src_num].start_col = s_line_col.col;
        !          2741:                         /* For object-like macro, also for function-like    */
        !          2742:                         /* macro in case of parens are not found.           */
        !          2743:                         in_src[ in_src_num].end_line = s_line_col.line;
        !          2744:                         in_src[ in_src_num].end_col
        !          2745:                                 = infile->bptr - infile->buffer;
        !          2746:                         if (defp->nargs >= 0) {
        !          2747:                             /* Function-like macro: search parentheses  */
        !          2748:                             n_paren[ ++num_paren].n_par = paren;
        !          2749:                             n_paren[ num_paren].n_in_src = in_src_num;
        !          2750:                         }
        !          2751:                     }   /* Else in_src[ in_src_num].* are 0L        */
        !          2752:                 }
        !          2753:             }
        !          2754:             break;
        !          2755:         }                                   /* End of switch        */
        !          2756:
        !          2757:         if (end_an_arg)                     /* End of an argument   */
        !          2758:             break;
        !          2759:         if (trace_arg) {                    /* Save the location    */
        !          2760:             e_line_col.line = src_line;     /*      before spaces   */
        !          2761:             e_line_col.col = infile->bptr - infile->buffer;
        !          2762:         }
        !          2763:         memset( &mgc_seq, 0, sizeof (MAGIC_SEQ));
        !          2764:         c = squeeze_ws( &argp, NULL, &mgc_seq);
        !          2765:                                             /* To the next token    */
        !          2766:     }                                       /* Collected an argument*/
        !          2767:
        !          2768:     *argp = EOS;
        !          2769:     *seqp = stpcpy( *seqp, *argpp);         /* Save the sequence    */
        !          2770:     if (c == '\n' || c == RT_END)
        !          2771:         return  -1;                         /* Unterminated macro   */
        !          2772:     argp--;                                 /* Remove the punctuator*/
        !          2773:     if (mgc_seq.space)
        !          2774:         --argp;                     /* Remove trailing space        */
        !          2775:     if (mcpp_mode == STD) {
        !          2776:         if (trace_macro && m_num) {
        !          2777:             if (trace_arg) {        /* Location of end of an arg    */
        !          2778:                 get_src_location( & e_line_col);
        !          2779:                 (*locp)->end_line = e_line_col.line;
        !          2780:                 (*locp)->end_col = e_line_col.col;
        !          2781:             }
        !          2782:             (*locp)++;      /* Advance pointer even if !trace_arg   */
        !          2783:             *argp++ = MAC_INF;
        !          2784:             *argp++ = MAC_ARG_END;
        !          2785:             if (option_flags.v) {
        !          2786:                 *argp++ = (m_num / UCHARMAX) + 1;
        !          2787:                 *argp++ = (m_num % UCHARMAX) + 1;
        !          2788:                 *argp++ = nargs + 1;
        !          2789:                 *argp = EOS;
        !          2790:                 *argpp = chk_magic_balance( *argpp, argp, TRUE, FALSE);
        !          2791:                     /* Check a stray magic caused by abnormal macro */
        !          2792:                     /* and move it to an edge if found.             */
        !          2793:             }
        !          2794:         }
        !          2795:         *argp++ = RT_END;                   /* For rescan()         */
        !          2796:     }
        !          2797:     *argp++ = EOS;                          /* Terminate an argument*/
        !          2798:     *argpp = argp;
        !          2799:     return  c;
        !          2800: }
        !          2801:
        !          2802: static int  squeeze_ws(
        !          2803:     char **     out,                /* Pointer to output pointer    */
        !          2804:     char **     endf,               /* Pointer to end of infile data*/
        !          2805:     MAGIC_SEQ * mgc_seq         /* Sequence of MAC_INFs and space   */
        !          2806:             /* mgc_seq should be initialized in the calling routine */
        !          2807: )
        !          2808: /*
        !          2809:  * Squeeze white spaces to one space.
        !          2810:  * White spaces are ' ' (and possibly '\t', when keep_spaces == TRUE.  Note
        !          2811:  * that '\r', '\v', '\f' have been already converted to ' ' by get_ch()),
        !          2812:  * and '\n' unless in_directive is set.
        !          2813:  * COM_SEP is skipped.  TOK_SEPs are squeezed to one TOK_SEP.
        !          2814:  * Copy MAC_INF and its sequences as they are.
        !          2815:  * If white spaces are found and 'out' is not NULL, write a space to *out and
        !          2816:  * increment *out.
        !          2817:  * Record start and end of MAC_INF sequences and whether space is found or
        !          2818:  * not for a convenience of get_an_arg().
        !          2819:  * Return the next character.
        !          2820:  */
        !          2821: {
        !          2822:     int     c;
        !          2823:     int     space = 0;
        !          2824:     int     tsep = 0;
        !          2825:     FILEINFO *      file = infile;
        !          2826:     FILE *  fp = infile->fp;
        !          2827:     int     end_of_file = (out && endf) ? FALSE : TRUE;
        !          2828:
        !          2829:     while (((char_type[ c = get_ch()] & SPA) && (! standard
        !          2830:                 || (mcpp_mode == POST_STD && file == infile)
        !          2831:                 || (mcpp_mode == STD
        !          2832:                     && ((macro_line != 0 && macro_line != MACRO_ERROR)
        !          2833:                         || file == infile))))
        !          2834:             || c == MAC_INF) {
        !          2835:         if (! end_of_file && file != infile) {  /* Infile has been read over*/
        !          2836:             *endf = *out;               /* Remember the location    */
        !          2837:             end_of_file = TRUE;
        !          2838:         }
        !          2839:         if (c == '\n' && in_directive)  /* If scanning control line */
        !          2840:             break;                      /*   do not skip newline.   */
        !          2841:         switch (c) {
        !          2842:         case '\n':
        !          2843:             space++;
        !          2844:             wrong_line = TRUE;
        !          2845:             break;
        !          2846:         case TOK_SEP:
        !          2847:             if (mcpp_mode == STD)
        !          2848:                 tsep++;
        !          2849:             continue;           /* Skip COM_SEP in OLD_PREP mode    */
        !          2850:         case MAC_INF    :       /* Copy magics as they are, or skip */
        !          2851:             if (mgc_seq && ! mgc_seq->magic_start)
        !          2852:                 mgc_seq->magic_start = *out;
        !          2853:                                     /* First occurence of magic seq */
        !          2854:             if (out)
        !          2855:                 *(*out)++ = c;
        !          2856:             c = get_ch();
        !          2857:             if (out)
        !          2858:                 *(*out)++ = c;
        !          2859:             switch (c) {
        !          2860:             case MAC_ARG_START  :
        !          2861:                 c = get_ch();
        !          2862:                 if (out)
        !          2863:                     *(*out)++ = c;
        !          2864:                 /* Fall through */
        !          2865:             case MAC_CALL_START :
        !          2866:                 c = get_ch();
        !          2867:                 if (out)
        !          2868:                     *(*out)++ = c;
        !          2869:                 c = get_ch();
        !          2870:                 if (out)
        !          2871:                     *(*out)++ = c;
        !          2872:                 break;
        !          2873:             case MAC_ARG_END    :
        !          2874:                 if (! option_flags.v) {
        !          2875:                     break;
        !          2876:                 } else {
        !          2877:                     c = get_ch();
        !          2878:                     if (out)
        !          2879:                         *(*out)++ = c;
        !          2880:                     /* Fall through */
        !          2881:                 }
        !          2882:             case MAC_CALL_END   :
        !          2883:                 if (option_flags.v) {
        !          2884:                     c = get_ch();
        !          2885:                     if (out)
        !          2886:                         *(*out)++ = c;
        !          2887:                     c = get_ch();
        !          2888:                     if (out)
        !          2889:                         *(*out)++ = c;
        !          2890:                 }
        !          2891:                 break;
        !          2892:             }
        !          2893:             if (mgc_seq)        /* Remember end of last magic seq   */
        !          2894:                 mgc_seq->magic_end = *out;
        !          2895:             break;
        !          2896:         default:
        !          2897:             space++;
        !          2898:             break;
        !          2899:         }
        !          2900:     }
        !          2901:
        !          2902:     if (out) {
        !          2903:         if (space) {            /* Write a space to output pointer  */
        !          2904:             *(*out)++ = ' ';    /*   and increment the pointer.     */
        !          2905:             if (mgc_seq)
        !          2906:                 mgc_seq->space = TRUE;
        !          2907:         }
        !          2908:         if (tsep && !space)     /* Needs to preserve token separator*/
        !          2909:             *(*out)++ = TOK_SEP;
        !          2910:         **out = EOS;
        !          2911:     }
        !          2912:     if (mcpp_mode == POST_STD && file != infile) {
        !          2913:         unget_ch();             /* Arguments cannot cross "file"s   */
        !          2914:         c = fp ? CHAR_EOF : RT_END; /* EOF is diagnosed by at_eof() */
        !          2915:     } else if (mcpp_mode == STD && macro_line == MACRO_ERROR
        !          2916:             && file != infile) {            /* EOF                  */
        !          2917:         unget_ch();             /*   diagnosed by at_eof() or only  */
        !          2918:         c = CHAR_EOF;           /*   name of a function-like macro. */
        !          2919:     }                       /* at_eof() resets macro_line on error  */
        !          2920:     return  c;                  /* Return the next character        */
        !          2921: }
        !          2922:
        !          2923: static void skip_macro( void)
        !          2924: /*
        !          2925:  * Clear the stacked (i.e. half-expanded) macro, called on macro error.
        !          2926:  */
        !          2927: {
        !          2928:     if (infile == NULL)                     /* End of input         */
        !          2929:         return;
        !          2930:     if (infile->fp)                         /* Source file          */
        !          2931:         return;
        !          2932:     while (infile->fp == NULL) {            /* Stacked stuff        */
        !          2933:         infile->bptr += strlen( infile->bptr);
        !          2934:         get_ch();                           /* To the parent "file" */
        !          2935:     }
        !          2936:     unget_ch();
        !          2937: }
        !          2938:
        !          2939: static void diag_macro(
        !          2940:     int     severity,                       /* Error or warning     */
        !          2941:     const char *    format,
        !          2942:     const char *    arg1,
        !          2943:     long            arg2,
        !          2944:     const char *    arg3,
        !          2945:     const DEFBUF *  defp1,          /* Macro causing the problem 1  */
        !          2946:     const DEFBUF *  defp2                                   /*   2  */
        !          2947: )
        !          2948: /*
        !          2949:  * Supplement macro information for diagnostic.
        !          2950:  */
        !          2951: {
        !          2952:
        !          2953:     if (defp1 && defp1->name != macro_name)
        !          2954:         expanding( defp1->name, FALSE);
        !          2955:                             /* Inform of the problematic macro call */
        !          2956:     if (defp2 && defp2->name != macro_name)
        !          2957:         expanding( defp2->name, FALSE);
        !          2958:     if (severity == CERROR)
        !          2959:         cerror( format, arg1, arg2, arg3);
        !          2960:     else
        !          2961:         cwarn( format, arg1, arg2, arg3);
        !          2962: }
        !          2963:
        !          2964: static void dump_args(
        !          2965:     const char *    why,
        !          2966:     int             nargs,
        !          2967:     const char **   arglist
        !          2968: )
        !          2969: /*
        !          2970:  * Dump arguments list.
        !          2971:  */
        !          2972: {
        !          2973:     int     i;
        !          2974:
        !          2975:     mcpp_fprintf( DBG, "dump of %d actual arguments %s\n", nargs, why);
        !          2976:     for (i = 0; i < nargs; i++) {
        !          2977:         mcpp_fprintf( DBG, "arg[%d]", i + 1);
        !          2978:         dump_string( NULL, arglist[ i]);
        !          2979:     }
        !          2980: }
        !          2981:

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>