xref: /aoo42x/main/rsc/source/rscpp/cpp4.c (revision cdf0e10c)
1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir #include        <stdio.h>
29*cdf0e10cSrcweir #include        <ctype.h>
30*cdf0e10cSrcweir #include        "cppdef.h"
31*cdf0e10cSrcweir #include        "cpp.h"
32*cdf0e10cSrcweir /*
33*cdf0e10cSrcweir  * parm[], parmp, and parlist[] are used to store #define() argument
34*cdf0e10cSrcweir  * lists.  nargs contains the actual number of parameters stored.
35*cdf0e10cSrcweir  */
36*cdf0e10cSrcweir static char     parm[NPARMWORK + 1];    /* define param work buffer     */
37*cdf0e10cSrcweir static char     *parmp;                 /* Free space in parm           */
38*cdf0e10cSrcweir static char     *parlist[LASTPARM];     /* -> start of each parameter   */
39*cdf0e10cSrcweir static int      nargs;                  /* Parameters for this macro    */
40*cdf0e10cSrcweir 
41*cdf0e10cSrcweir void InitCpp4()
42*cdf0e10cSrcweir {
43*cdf0e10cSrcweir     int i;
44*cdf0e10cSrcweir     for( i = 0; i < NPARMWORK; i++ )
45*cdf0e10cSrcweir         parm[ i ] = 0;
46*cdf0e10cSrcweir     for( i = 0; i < LASTPARM; i++ )
47*cdf0e10cSrcweir         parlist[ i ] = NULL;
48*cdf0e10cSrcweir 
49*cdf0e10cSrcweir     nargs = 0;
50*cdf0e10cSrcweir }
51*cdf0e10cSrcweir 
52*cdf0e10cSrcweir 
53*cdf0e10cSrcweir void dodefine()
54*cdf0e10cSrcweir /*
55*cdf0e10cSrcweir  * Called from control when a #define is scanned.  This module
56*cdf0e10cSrcweir  * parses formal parameters and the replacement string.  When
57*cdf0e10cSrcweir  * the formal parameter name is encountered in the replacement
58*cdf0e10cSrcweir  * string, it is replaced by a character in the range 128 to
59*cdf0e10cSrcweir  * 128+NPARAM (this allows up to 32 parameters within the
60*cdf0e10cSrcweir  * Dec Multinational range).  If cpp is ported to an EBCDIC
61*cdf0e10cSrcweir  * machine, you will have to make other arrangements.
62*cdf0e10cSrcweir  *
63*cdf0e10cSrcweir  * There is some special case code to distinguish
64*cdf0e10cSrcweir  *      #define foo     bar
65*cdf0e10cSrcweir  * from #define foo()   bar
66*cdf0e10cSrcweir  *
67*cdf0e10cSrcweir  * Also, we make sure that
68*cdf0e10cSrcweir  *      #define foo     foo
69*cdf0e10cSrcweir  * expands to "foo" but doesn't put cpp into an infinite loop.
70*cdf0e10cSrcweir  *
71*cdf0e10cSrcweir  * A warning message is printed if you redefine a symbol to a
72*cdf0e10cSrcweir  * different text.  I.e,
73*cdf0e10cSrcweir  *      #define foo     123
74*cdf0e10cSrcweir  *      #define foo     123
75*cdf0e10cSrcweir  * is ok, but
76*cdf0e10cSrcweir  *      #define foo     123
77*cdf0e10cSrcweir  *      #define foo     +123
78*cdf0e10cSrcweir  * is not.
79*cdf0e10cSrcweir  *
80*cdf0e10cSrcweir  * The following subroutines are called from define():
81*cdf0e10cSrcweir  * checkparm    called when a token is scanned.  It checks through the
82*cdf0e10cSrcweir  *              array of formal parameters.  If a match is found, the
83*cdf0e10cSrcweir  *              token is replaced by a control byte which will be used
84*cdf0e10cSrcweir  *              to locate the parameter when the macro is expanded.
85*cdf0e10cSrcweir  * textput      puts a string in the macro work area (parm[]), updating
86*cdf0e10cSrcweir  *              parmp to point to the first free byte in parm[].
87*cdf0e10cSrcweir  *              textput() tests for work buffer overflow.
88*cdf0e10cSrcweir  * charput      puts a single character in the macro work area (parm[])
89*cdf0e10cSrcweir  *              in a manner analogous to textput().
90*cdf0e10cSrcweir  */
91*cdf0e10cSrcweir {
92*cdf0e10cSrcweir         register int            c;
93*cdf0e10cSrcweir         register DEFBUF         *dp;            /* -> new definition    */
94*cdf0e10cSrcweir         int                     isredefine;     /* TRUE if redefined    */
95*cdf0e10cSrcweir         char                    *old = 0;       /* Remember redefined   */
96*cdf0e10cSrcweir 
97*cdf0e10cSrcweir         if (type[(c = skipws())] != LET)
98*cdf0e10cSrcweir             goto bad_define;
99*cdf0e10cSrcweir         isredefine = FALSE;                     /* Set if redefining    */
100*cdf0e10cSrcweir         if ((dp = lookid(c)) == NULL)           /* If not known now     */
101*cdf0e10cSrcweir             dp = defendel(token, FALSE);        /* Save the name        */
102*cdf0e10cSrcweir         else {                                  /* It's known:          */
103*cdf0e10cSrcweir             isredefine = TRUE;                  /* Remember this fact   */
104*cdf0e10cSrcweir             old = dp->repl;                     /* Remember replacement */
105*cdf0e10cSrcweir             dp->repl = NULL;                    /* No replacement now   */
106*cdf0e10cSrcweir         }
107*cdf0e10cSrcweir         parlist[0] = parmp = parm;              /* Setup parm buffer    */
108*cdf0e10cSrcweir         if ((c = get()) == '(') {               /* With arguments?      */
109*cdf0e10cSrcweir             nargs = 0;                          /* Init formals counter */
110*cdf0e10cSrcweir             do {                                /* Collect formal parms */
111*cdf0e10cSrcweir                 if (nargs >= LASTPARM)
112*cdf0e10cSrcweir                     cfatal("Too many arguments for macro", NULLST);
113*cdf0e10cSrcweir                 else if ((c = skipws()) == ')')
114*cdf0e10cSrcweir                     break;                      /* Got them all         */
115*cdf0e10cSrcweir                 else if (type[c] != LET)        /* Bad formal syntax    */
116*cdf0e10cSrcweir                     goto bad_define;
117*cdf0e10cSrcweir                 scanid(c);                      /* Get the formal param */
118*cdf0e10cSrcweir                 parlist[nargs++] = parmp;       /* Save its start       */
119*cdf0e10cSrcweir                 textput(token);                 /* Save text in parm[]  */
120*cdf0e10cSrcweir             } while ((c = skipws()) == ',');    /* Get another argument */
121*cdf0e10cSrcweir             if (c != ')')                       /* Must end at )        */
122*cdf0e10cSrcweir                 goto bad_define;
123*cdf0e10cSrcweir             c = ' ';                            /* Will skip to body    */
124*cdf0e10cSrcweir         }
125*cdf0e10cSrcweir         else {
126*cdf0e10cSrcweir             /*
127*cdf0e10cSrcweir              * DEF_NOARGS is needed to distinguish between
128*cdf0e10cSrcweir              * "#define foo" and "#define foo()".
129*cdf0e10cSrcweir              */
130*cdf0e10cSrcweir             nargs = DEF_NOARGS;                 /* No () parameters     */
131*cdf0e10cSrcweir         }
132*cdf0e10cSrcweir         if (type[c] == SPA)                     /* At whitespace?       */
133*cdf0e10cSrcweir             c = skipws();                       /* Not any more.        */
134*cdf0e10cSrcweir         workp = work;                           /* Replacement put here */
135*cdf0e10cSrcweir         inmacro = TRUE;                         /* Keep \<newline> now  */
136*cdf0e10cSrcweir         while (c != EOF_CHAR && c != '\n') {    /* Compile macro body   */
137*cdf0e10cSrcweir #if OK_CONCAT
138*cdf0e10cSrcweir #if COMMENT_INVISIBLE
139*cdf0e10cSrcweir             if (c == COM_SEP) {                 /* Token concatenation? */
140*cdf0e10cSrcweir                 save(TOK_SEP);                  /* Stuff a delimiter    */
141*cdf0e10cSrcweir                 c = get();
142*cdf0e10cSrcweir #else
143*cdf0e10cSrcweir             if (c == '#') {                     /* Token concatenation? */
144*cdf0e10cSrcweir                 while (workp > work && type[(int)workp[-1]] == SPA)
145*cdf0e10cSrcweir                     --workp;                    /* Erase leading spaces */
146*cdf0e10cSrcweir                 save(TOK_SEP);                  /* Stuff a delimiter    */
147*cdf0e10cSrcweir                 c = skipws();                   /* Eat whitespace       */
148*cdf0e10cSrcweir #endif
149*cdf0e10cSrcweir                 if (type[c] == LET)             /* Another token here?  */
150*cdf0e10cSrcweir                     ;                           /* Stuff it normally    */
151*cdf0e10cSrcweir                 else if (type[c] == DIG) {      /* Digit string after?  */
152*cdf0e10cSrcweir                     while (type[c] == DIG) {    /* Stuff the digits     */
153*cdf0e10cSrcweir                         save(c);
154*cdf0e10cSrcweir                         c = get();
155*cdf0e10cSrcweir                     }
156*cdf0e10cSrcweir                     save(TOK_SEP);              /* Delimit 2nd token    */
157*cdf0e10cSrcweir                 }
158*cdf0e10cSrcweir                 else {
159*cdf0e10cSrcweir #if ! COMMENT_INVISIBLE
160*cdf0e10cSrcweir                     ciwarn("Strange character after # (%d.)", c);
161*cdf0e10cSrcweir #endif
162*cdf0e10cSrcweir                 }
163*cdf0e10cSrcweir                 continue;
164*cdf0e10cSrcweir             }
165*cdf0e10cSrcweir #endif
166*cdf0e10cSrcweir             switch (type[c]) {
167*cdf0e10cSrcweir             case LET:
168*cdf0e10cSrcweir                 checkparm(c, dp);               /* Might be a formal    */
169*cdf0e10cSrcweir                 break;
170*cdf0e10cSrcweir 
171*cdf0e10cSrcweir             case DIG:                           /* Number in mac. body  */
172*cdf0e10cSrcweir             case DOT:                           /* Maybe a float number */
173*cdf0e10cSrcweir                 scannumber(c, save);            /* Scan it off          */
174*cdf0e10cSrcweir                 break;
175*cdf0e10cSrcweir 
176*cdf0e10cSrcweir             case QUO:                           /* String in mac. body  */
177*cdf0e10cSrcweir #if STRING_FORMAL
178*cdf0e10cSrcweir                 stparmscan(c, dp);              /* Do string magic      */
179*cdf0e10cSrcweir #else
180*cdf0e10cSrcweir                 stparmscan(c);
181*cdf0e10cSrcweir #endif
182*cdf0e10cSrcweir                 break;
183*cdf0e10cSrcweir 
184*cdf0e10cSrcweir             case BSH:                           /* Backslash            */
185*cdf0e10cSrcweir                 save('\\');
186*cdf0e10cSrcweir                 if ((c = get()) == '\n')
187*cdf0e10cSrcweir                     wrongline = TRUE;
188*cdf0e10cSrcweir                 save(c);
189*cdf0e10cSrcweir                 break;
190*cdf0e10cSrcweir 
191*cdf0e10cSrcweir             case SPA:                           /* Absorb whitespace    */
192*cdf0e10cSrcweir                 /*
193*cdf0e10cSrcweir                  * Note: the "end of comment" marker is passed on
194*cdf0e10cSrcweir                  * to allow comments to separate tokens.
195*cdf0e10cSrcweir                  */
196*cdf0e10cSrcweir                 if (workp[-1] == ' ')           /* Absorb multiple      */
197*cdf0e10cSrcweir                     break;                      /* spaces               */
198*cdf0e10cSrcweir                 else if (c == '\t')
199*cdf0e10cSrcweir                     c = ' ';                    /* Normalize tabs       */
200*cdf0e10cSrcweir                 /* Fall through to store character                      */
201*cdf0e10cSrcweir             default:                            /* Other character      */
202*cdf0e10cSrcweir                 save(c);
203*cdf0e10cSrcweir                 break;
204*cdf0e10cSrcweir             }
205*cdf0e10cSrcweir             c = get();
206*cdf0e10cSrcweir         }
207*cdf0e10cSrcweir         inmacro = FALSE;                        /* Stop newline hack    */
208*cdf0e10cSrcweir         unget();                                /* For control check    */
209*cdf0e10cSrcweir         if (workp > work && workp[-1] == ' ')   /* Drop trailing blank  */
210*cdf0e10cSrcweir             workp--;
211*cdf0e10cSrcweir         *workp = EOS;                           /* Terminate work       */
212*cdf0e10cSrcweir         dp->repl = savestring(work);            /* Save the string      */
213*cdf0e10cSrcweir         dp->nargs = nargs;                      /* Save arg count       */
214*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
215*cdf0e10cSrcweir         if (debug)
216*cdf0e10cSrcweir             dumpadef("macro definition", dp);
217*cdf0e10cSrcweir 		else if (bDumpDefs)
218*cdf0e10cSrcweir             dumpadef(NULL, dp);
219*cdf0e10cSrcweir #endif
220*cdf0e10cSrcweir         if (isredefine) {                       /* Error if redefined   */
221*cdf0e10cSrcweir             if ((old != NULL && dp->repl != NULL && !streq(old, dp->repl))
222*cdf0e10cSrcweir              || (old == NULL && dp->repl != NULL)
223*cdf0e10cSrcweir              || (old != NULL && dp->repl == NULL)) {
224*cdf0e10cSrcweir #ifdef STRICT_UNDEF
225*cdf0e10cSrcweir                 cerror("Redefining defined variable \"%s\"", dp->name);
226*cdf0e10cSrcweir #else
227*cdf0e10cSrcweir                 cwarn("Redefining defined variable \"%s\"", dp->name);
228*cdf0e10cSrcweir #endif
229*cdf0e10cSrcweir             }
230*cdf0e10cSrcweir             if (old != NULL)                    /* We don't need the    */
231*cdf0e10cSrcweir                 free(old);                      /* old definition now.  */
232*cdf0e10cSrcweir         }
233*cdf0e10cSrcweir         return;
234*cdf0e10cSrcweir 
235*cdf0e10cSrcweir bad_define:
236*cdf0e10cSrcweir         cerror("#define syntax error", NULLST);
237*cdf0e10cSrcweir         inmacro = FALSE;                        /* Stop <newline> hack  */
238*cdf0e10cSrcweir }
239*cdf0e10cSrcweir 
240*cdf0e10cSrcweir void checkparm(int c, DEFBUF* dp)
241*cdf0e10cSrcweir /*
242*cdf0e10cSrcweir  * Replace this param if it's defined.  Note that the macro name is a
243*cdf0e10cSrcweir  * possible replacement token.  We stuff DEF_MAGIC in front of the token
244*cdf0e10cSrcweir  * which is treated as a LETTER by the token scanner and eaten by
245*cdf0e10cSrcweir  * the output routine.  This prevents the macro expander from
246*cdf0e10cSrcweir  * looping if someone writes "#define foo foo".
247*cdf0e10cSrcweir  */
248*cdf0e10cSrcweir {
249*cdf0e10cSrcweir         register int            i;
250*cdf0e10cSrcweir         register char           *cp;
251*cdf0e10cSrcweir 
252*cdf0e10cSrcweir         scanid(c);                              /* Get parm to token[]  */
253*cdf0e10cSrcweir         for (i = 0; i < nargs; i++) {           /* For each argument    */
254*cdf0e10cSrcweir             if (streq(parlist[i], token)) {     /* If it's known        */
255*cdf0e10cSrcweir #ifdef SOLAR
256*cdf0e10cSrcweir                 save(DEL);
257*cdf0e10cSrcweir #endif
258*cdf0e10cSrcweir                 save(i + MAC_PARM);             /* Save a magic cookie  */
259*cdf0e10cSrcweir                 return;                         /* And exit the search  */
260*cdf0e10cSrcweir             }
261*cdf0e10cSrcweir         }
262*cdf0e10cSrcweir         if (streq(dp->name, token))             /* Macro name in body?  */
263*cdf0e10cSrcweir             save(DEF_MAGIC);                    /* Save magic marker    */
264*cdf0e10cSrcweir         for (cp = token; *cp != EOS;)           /* And save             */
265*cdf0e10cSrcweir             save(*cp++);                        /* The token itself     */
266*cdf0e10cSrcweir }
267*cdf0e10cSrcweir 
268*cdf0e10cSrcweir #if STRING_FORMAL
269*cdf0e10cSrcweir void stparmscan(delim, dp)
270*cdf0e10cSrcweir int             delim;
271*cdf0e10cSrcweir register DEFBUF *dp;
272*cdf0e10cSrcweir /*
273*cdf0e10cSrcweir  * Scan the string (starting with the given delimiter).
274*cdf0e10cSrcweir  * The token is replaced if it is the only text in this string or
275*cdf0e10cSrcweir  * character constant.  The algorithm follows checkparm() above.
276*cdf0e10cSrcweir  * Note that scanstring() has approved of the string.
277*cdf0e10cSrcweir  */
278*cdf0e10cSrcweir {
279*cdf0e10cSrcweir         register int            c;
280*cdf0e10cSrcweir 
281*cdf0e10cSrcweir         /*
282*cdf0e10cSrcweir          * Warning -- this code hasn't been tested for a while.
283*cdf0e10cSrcweir          * It exists only to preserve compatibility with earlier
284*cdf0e10cSrcweir          * implementations of cpp.  It is not part of the Draft
285*cdf0e10cSrcweir          * ANSI Standard C language.
286*cdf0e10cSrcweir          */
287*cdf0e10cSrcweir         save(delim);
288*cdf0e10cSrcweir         instring = TRUE;
289*cdf0e10cSrcweir         while ((c = get()) != delim
290*cdf0e10cSrcweir              && c != '\n'
291*cdf0e10cSrcweir              && c != EOF_CHAR) {
292*cdf0e10cSrcweir             if (type[c] == LET)                 /* Maybe formal parm    */
293*cdf0e10cSrcweir                 checkparm(c, dp);
294*cdf0e10cSrcweir             else {
295*cdf0e10cSrcweir                 save(c);
296*cdf0e10cSrcweir                 if (c == '\\')
297*cdf0e10cSrcweir                     save(get());
298*cdf0e10cSrcweir             }
299*cdf0e10cSrcweir         }
300*cdf0e10cSrcweir         instring = FALSE;
301*cdf0e10cSrcweir         if (c != delim)
302*cdf0e10cSrcweir             cerror("Unterminated string in macro body", NULLST);
303*cdf0e10cSrcweir         save(c);
304*cdf0e10cSrcweir }
305*cdf0e10cSrcweir #else
306*cdf0e10cSrcweir void stparmscan(int delim)
307*cdf0e10cSrcweir /*
308*cdf0e10cSrcweir  * Normal string parameter scan.
309*cdf0e10cSrcweir  */
310*cdf0e10cSrcweir {
311*cdf0e10cSrcweir         register char           *wp;
312*cdf0e10cSrcweir         register int            i;
313*cdf0e10cSrcweir 
314*cdf0e10cSrcweir         wp = workp;                     /* Here's where it starts       */
315*cdf0e10cSrcweir         if (!scanstring(delim, save))
316*cdf0e10cSrcweir             return;                     /* Exit on scanstring error     */
317*cdf0e10cSrcweir         workp[-1] = EOS;                /* Erase trailing quote         */
318*cdf0e10cSrcweir         wp++;                           /* -> first string content byte */
319*cdf0e10cSrcweir         for (i = 0; i < nargs; i++) {
320*cdf0e10cSrcweir             if (streq(parlist[i], wp)) {
321*cdf0e10cSrcweir #ifdef SOLAR
322*cdf0e10cSrcweir                 *wp++ = DEL;
323*cdf0e10cSrcweir                 *wp++ = MAC_PARM + PAR_MAC;     /* Stuff a magic marker */
324*cdf0e10cSrcweir                 *wp++ = (char)(i + MAC_PARM);   /* Make a formal marker */
325*cdf0e10cSrcweir                 *wp = wp[-4];                   /* Add on closing quote */
326*cdf0e10cSrcweir                 workp = wp + 1;                 /* Reset string end     */
327*cdf0e10cSrcweir #else
328*cdf0e10cSrcweir                 *wp++ = MAC_PARM + PAR_MAC;     /* Stuff a magic marker */
329*cdf0e10cSrcweir                 *wp++ = (i + MAC_PARM);         /* Make a formal marker */
330*cdf0e10cSrcweir                 *wp = wp[-3];                   /* Add on closing quote */
331*cdf0e10cSrcweir                 workp = wp + 1;                 /* Reset string end     */
332*cdf0e10cSrcweir #endif
333*cdf0e10cSrcweir                 return;
334*cdf0e10cSrcweir             }
335*cdf0e10cSrcweir         }
336*cdf0e10cSrcweir         workp[-1] = wp[-1];             /* Nope, reset end quote.       */
337*cdf0e10cSrcweir }
338*cdf0e10cSrcweir #endif
339*cdf0e10cSrcweir 
340*cdf0e10cSrcweir void doundef()
341*cdf0e10cSrcweir /*
342*cdf0e10cSrcweir  * Remove the symbol from the defined list.
343*cdf0e10cSrcweir  * Called from the #control processor.
344*cdf0e10cSrcweir  */
345*cdf0e10cSrcweir {
346*cdf0e10cSrcweir         register int            c;
347*cdf0e10cSrcweir 
348*cdf0e10cSrcweir         if (type[(c = skipws())] != LET)
349*cdf0e10cSrcweir             cerror("Illegal #undef argument", NULLST);
350*cdf0e10cSrcweir         else {
351*cdf0e10cSrcweir             scanid(c);                          /* Get name to token[]  */
352*cdf0e10cSrcweir             if (defendel(token, TRUE) == NULL) {
353*cdf0e10cSrcweir #ifdef STRICT_UNDEF
354*cdf0e10cSrcweir                 cwarn("Symbol \"%s\" not defined in #undef", token);
355*cdf0e10cSrcweir #endif
356*cdf0e10cSrcweir             }
357*cdf0e10cSrcweir         }
358*cdf0e10cSrcweir }
359*cdf0e10cSrcweir 
360*cdf0e10cSrcweir void textput(char* text)
361*cdf0e10cSrcweir /*
362*cdf0e10cSrcweir  * Put the string in the parm[] buffer.
363*cdf0e10cSrcweir  */
364*cdf0e10cSrcweir {
365*cdf0e10cSrcweir         register int    size;
366*cdf0e10cSrcweir 
367*cdf0e10cSrcweir         size = strlen(text) + 1;
368*cdf0e10cSrcweir         if ((parmp + size) >= &parm[NPARMWORK])
369*cdf0e10cSrcweir             cfatal("Macro work area overflow", NULLST);
370*cdf0e10cSrcweir         else {
371*cdf0e10cSrcweir             strcpy(parmp, text);
372*cdf0e10cSrcweir             parmp += size;
373*cdf0e10cSrcweir         }
374*cdf0e10cSrcweir }
375*cdf0e10cSrcweir 
376*cdf0e10cSrcweir void charput(int c)
377*cdf0e10cSrcweir /*
378*cdf0e10cSrcweir  * Put the byte in the parm[] buffer.
379*cdf0e10cSrcweir  */
380*cdf0e10cSrcweir {
381*cdf0e10cSrcweir         if (parmp >= &parm[NPARMWORK])
382*cdf0e10cSrcweir             cfatal("Macro work area overflow", NULLST);
383*cdf0e10cSrcweir         else {
384*cdf0e10cSrcweir             *parmp++ = (char)c;
385*cdf0e10cSrcweir         }
386*cdf0e10cSrcweir }
387*cdf0e10cSrcweir 
388*cdf0e10cSrcweir /*
389*cdf0e10cSrcweir  *              M a c r o   E x p a n s i o n
390*cdf0e10cSrcweir  */
391*cdf0e10cSrcweir 
392*cdf0e10cSrcweir static DEFBUF   *macro;         /* Catches start of infinite macro      */
393*cdf0e10cSrcweir 
394*cdf0e10cSrcweir void expand(DEFBUF* tokenp)
395*cdf0e10cSrcweir /*
396*cdf0e10cSrcweir  * Expand a macro.  Called from the cpp mainline routine (via subroutine
397*cdf0e10cSrcweir  * macroid()) when a token is found in the symbol table.  It calls
398*cdf0e10cSrcweir  * expcollect() to parse actual parameters, checking for the correct number.
399*cdf0e10cSrcweir  * It then creates a "file" containing a single line containing the
400*cdf0e10cSrcweir  * macro with actual parameters inserted appropriately.  This is
401*cdf0e10cSrcweir  * "pushed back" onto the input stream.  (When the get() routine runs
402*cdf0e10cSrcweir  * off the end of the macro line, it will dismiss the macro itself.)
403*cdf0e10cSrcweir  */
404*cdf0e10cSrcweir {
405*cdf0e10cSrcweir         register int            c;
406*cdf0e10cSrcweir         register FILEINFO       *file;
407*cdf0e10cSrcweir #ifndef ZTC  /* BP */
408*cdf0e10cSrcweir     extern FILEINFO     *getfile();
409*cdf0e10cSrcweir #endif
410*cdf0e10cSrcweir 
411*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
412*cdf0e10cSrcweir         if (debug)
413*cdf0e10cSrcweir             dumpadef("expand entry", tokenp);
414*cdf0e10cSrcweir #endif
415*cdf0e10cSrcweir         /*
416*cdf0e10cSrcweir          * If no macro is pending, save the name of this macro
417*cdf0e10cSrcweir          * for an eventual error message.
418*cdf0e10cSrcweir          */
419*cdf0e10cSrcweir         if (recursion++ == 0)
420*cdf0e10cSrcweir             macro = tokenp;
421*cdf0e10cSrcweir         else if (recursion == RECURSION_LIMIT) {
422*cdf0e10cSrcweir             cerror("Recursive macro definition of \"%s\"", tokenp->name);
423*cdf0e10cSrcweir             fprintf(stderr, "(Defined by \"%s\")\n", macro->name);
424*cdf0e10cSrcweir             if (rec_recover) {
425*cdf0e10cSrcweir                 do {
426*cdf0e10cSrcweir                     c = get();
427*cdf0e10cSrcweir                 } while (infile != NULL && infile->fp == NULL);
428*cdf0e10cSrcweir                 unget();
429*cdf0e10cSrcweir                 recursion = 0;
430*cdf0e10cSrcweir                 return;
431*cdf0e10cSrcweir             }
432*cdf0e10cSrcweir         }
433*cdf0e10cSrcweir         /*
434*cdf0e10cSrcweir          * Here's a macro to expand.
435*cdf0e10cSrcweir          */
436*cdf0e10cSrcweir         nargs = 0;                              /* Formals counter      */
437*cdf0e10cSrcweir         parmp = parm;                           /* Setup parm buffer    */
438*cdf0e10cSrcweir         switch (tokenp->nargs) {
439*cdf0e10cSrcweir         case (-2):                              /* __LINE__             */
440*cdf0e10cSrcweir             sprintf(work, "%d", line);
441*cdf0e10cSrcweir             ungetstring(work);
442*cdf0e10cSrcweir             break;
443*cdf0e10cSrcweir 
444*cdf0e10cSrcweir         case (-3):                              /* __FILE__             */
445*cdf0e10cSrcweir             for (file = infile; file != NULL; file = file->parent) {
446*cdf0e10cSrcweir                 if (file->fp != NULL) {
447*cdf0e10cSrcweir                     sprintf(work, "\"%s\"", (file->progname != NULL)
448*cdf0e10cSrcweir                         ? file->progname : file->filename);
449*cdf0e10cSrcweir                     ungetstring(work);
450*cdf0e10cSrcweir                     break;
451*cdf0e10cSrcweir                 }
452*cdf0e10cSrcweir             }
453*cdf0e10cSrcweir             break;
454*cdf0e10cSrcweir 
455*cdf0e10cSrcweir         default:
456*cdf0e10cSrcweir             /*
457*cdf0e10cSrcweir              * Nothing funny about this macro.
458*cdf0e10cSrcweir              */
459*cdf0e10cSrcweir             if (tokenp->nargs < 0)
460*cdf0e10cSrcweir                 cfatal("Bug: Illegal __ macro \"%s\"", tokenp->name);
461*cdf0e10cSrcweir             while ((c = skipws()) == '\n')      /* Look for (, skipping */
462*cdf0e10cSrcweir                 wrongline = TRUE;               /* spaces and newlines  */
463*cdf0e10cSrcweir             if (c != '(') {
464*cdf0e10cSrcweir                 /*
465*cdf0e10cSrcweir                  * If the programmer writes
466*cdf0e10cSrcweir                  *      #define foo() ...
467*cdf0e10cSrcweir                  *      ...
468*cdf0e10cSrcweir                  *      foo [no ()]
469*cdf0e10cSrcweir                  * just write foo to the output stream.
470*cdf0e10cSrcweir                  */
471*cdf0e10cSrcweir                 unget();
472*cdf0e10cSrcweir                 cwarn("Macro \"%s\" needs arguments", tokenp->name);
473*cdf0e10cSrcweir 		        fputs(tokenp->name, pCppOut );
474*cdf0e10cSrcweir                 return;
475*cdf0e10cSrcweir             }
476*cdf0e10cSrcweir             else if (expcollect()) {            /* Collect arguments    */
477*cdf0e10cSrcweir                 if (tokenp->nargs != nargs) {   /* Should be an error?  */
478*cdf0e10cSrcweir                     cwarn("Wrong number of macro arguments for \"%s\"",
479*cdf0e10cSrcweir                         tokenp->name);
480*cdf0e10cSrcweir                 }
481*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
482*cdf0e10cSrcweir                 if (debug)
483*cdf0e10cSrcweir                     dumpparm("expand");
484*cdf0e10cSrcweir #endif
485*cdf0e10cSrcweir             }                           /* Collect arguments            */
486*cdf0e10cSrcweir         case DEF_NOARGS:                /* No parameters just stuffs    */
487*cdf0e10cSrcweir             expstuff(tokenp);           /* Do actual parameters         */
488*cdf0e10cSrcweir         }                               /* nargs switch                 */
489*cdf0e10cSrcweir }
490*cdf0e10cSrcweir 
491*cdf0e10cSrcweir FILE_LOCAL int
492*cdf0e10cSrcweir expcollect()
493*cdf0e10cSrcweir /*
494*cdf0e10cSrcweir  * Collect the actual parameters for this macro.  TRUE if ok.
495*cdf0e10cSrcweir  */
496*cdf0e10cSrcweir {
497*cdf0e10cSrcweir         register int    c;
498*cdf0e10cSrcweir         register int    paren;                  /* For embedded ()'s    */
499*cdf0e10cSrcweir         for (;;) {
500*cdf0e10cSrcweir             paren = 0;                          /* Collect next arg.    */
501*cdf0e10cSrcweir             while ((c = skipws()) == '\n')      /* Skip over whitespace */
502*cdf0e10cSrcweir                 wrongline = TRUE;               /* and newlines.        */
503*cdf0e10cSrcweir             if (c == ')') {                     /* At end of all args?  */
504*cdf0e10cSrcweir                 /*
505*cdf0e10cSrcweir                  * Note that there is a guard byte in parm[]
506*cdf0e10cSrcweir                  * so we don't have to check for overflow here.
507*cdf0e10cSrcweir                  */
508*cdf0e10cSrcweir                 *parmp = EOS;                   /* Make sure terminated */
509*cdf0e10cSrcweir                 break;                          /* Exit collection loop */
510*cdf0e10cSrcweir             }
511*cdf0e10cSrcweir             else if (nargs >= LASTPARM)
512*cdf0e10cSrcweir                 cfatal("Too many arguments in macro expansion", NULLST);
513*cdf0e10cSrcweir             parlist[nargs++] = parmp;           /* At start of new arg  */
514*cdf0e10cSrcweir             for (;; c = cget()) {               /* Collect arg's bytes  */
515*cdf0e10cSrcweir                 if (c == EOF_CHAR) {
516*cdf0e10cSrcweir                     cerror("end of file within macro argument", NULLST);
517*cdf0e10cSrcweir                     return (FALSE);             /* Sorry.               */
518*cdf0e10cSrcweir                 }
519*cdf0e10cSrcweir                 else if (c == '\\') {           /* Quote next character */
520*cdf0e10cSrcweir                     charput(c);                 /* Save the \ for later */
521*cdf0e10cSrcweir                     charput(cget());            /* Save the next char.  */
522*cdf0e10cSrcweir                     continue;                   /* And go get another   */
523*cdf0e10cSrcweir                 }
524*cdf0e10cSrcweir                 else if (type[c] == QUO) {      /* Start of string?     */
525*cdf0e10cSrcweir                     scanstring(c, charput);     /* Scan it off          */
526*cdf0e10cSrcweir                     continue;                   /* Go get next char     */
527*cdf0e10cSrcweir                 }
528*cdf0e10cSrcweir                 else if (c == '(')              /* Worry about balance  */
529*cdf0e10cSrcweir                     paren++;                    /* To know about commas */
530*cdf0e10cSrcweir                 else if (c == ')') {            /* Other side too       */
531*cdf0e10cSrcweir                     if (paren == 0) {           /* At the end?          */
532*cdf0e10cSrcweir                         unget();                /* Look at it later     */
533*cdf0e10cSrcweir                         break;                  /* Exit arg getter.     */
534*cdf0e10cSrcweir                     }
535*cdf0e10cSrcweir                     paren--;                    /* More to come.        */
536*cdf0e10cSrcweir                 }
537*cdf0e10cSrcweir                 else if (c == ',' && paren == 0) /* Comma delimits args */
538*cdf0e10cSrcweir                     break;
539*cdf0e10cSrcweir                 else if (c == '\n')             /* Newline inside arg?  */
540*cdf0e10cSrcweir                     wrongline = TRUE;           /* We'll need a #line   */
541*cdf0e10cSrcweir                 charput(c);                     /* Store this one       */
542*cdf0e10cSrcweir             }                                   /* Collect an argument  */
543*cdf0e10cSrcweir             charput(EOS);                       /* Terminate argument   */
544*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
545*cdf0e10cSrcweir             if (debug)
546*cdf0e10cSrcweir             fprintf( pCppOut, "parm[%d] = \"%s\"\n", nargs, parlist[nargs - 1]);
547*cdf0e10cSrcweir #endif
548*cdf0e10cSrcweir         }                                       /* Collect all args.    */
549*cdf0e10cSrcweir         return (TRUE);                          /* Normal return        */
550*cdf0e10cSrcweir }
551*cdf0e10cSrcweir 
552*cdf0e10cSrcweir FILE_LOCAL
553*cdf0e10cSrcweir void expstuff(DEFBUF* tokenp)
554*cdf0e10cSrcweir /*
555*cdf0e10cSrcweir  * Stuff the macro body, replacing formal parameters by actual parameters.
556*cdf0e10cSrcweir  */
557*cdf0e10cSrcweir {
558*cdf0e10cSrcweir         register int    c;                      /* Current character    */
559*cdf0e10cSrcweir         register char   *inp;                   /* -> repl string       */
560*cdf0e10cSrcweir         register char   *defp;                  /* -> macro output buff */
561*cdf0e10cSrcweir         int             size;                   /* Actual parm. size    */
562*cdf0e10cSrcweir         char            *defend;                /* -> output buff end   */
563*cdf0e10cSrcweir         int             string_magic;           /* String formal hack   */
564*cdf0e10cSrcweir         FILEINFO        *file;                  /* Funny #include       */
565*cdf0e10cSrcweir #ifndef ZTC  /* BP */
566*cdf0e10cSrcweir     extern FILEINFO *getfile();
567*cdf0e10cSrcweir #endif
568*cdf0e10cSrcweir 
569*cdf0e10cSrcweir         file = getfile(NBUFF, tokenp->name);
570*cdf0e10cSrcweir         inp = tokenp->repl;                     /* -> macro replacement */
571*cdf0e10cSrcweir         defp = file->buffer;                    /* -> output buffer     */
572*cdf0e10cSrcweir         defend = defp + (NBUFF - 1);            /* Note its end         */
573*cdf0e10cSrcweir         if (inp != NULL) {
574*cdf0e10cSrcweir             while ((c = (*inp++ & 0xFF)) != EOS) {
575*cdf0e10cSrcweir #ifdef SOLAR
576*cdf0e10cSrcweir                 if (c == DEL) {
577*cdf0e10cSrcweir                     c = (*inp++ & 0xFF);
578*cdf0e10cSrcweir #else
579*cdf0e10cSrcweir                 if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC)) {
580*cdf0e10cSrcweir #endif
581*cdf0e10cSrcweir                     string_magic = (c == (MAC_PARM + PAR_MAC));
582*cdf0e10cSrcweir                     if (string_magic)
583*cdf0e10cSrcweir                         c = (*inp++ & 0xFF);
584*cdf0e10cSrcweir                     /*
585*cdf0e10cSrcweir                      * Replace formal parameter by actual parameter string.
586*cdf0e10cSrcweir                      */
587*cdf0e10cSrcweir                     if ((c -= MAC_PARM) < nargs) {
588*cdf0e10cSrcweir                         size = strlen(parlist[c]);
589*cdf0e10cSrcweir                         if ((defp + size) >= defend)
590*cdf0e10cSrcweir                             goto nospace;
591*cdf0e10cSrcweir                         /*
592*cdf0e10cSrcweir                          * Erase the extra set of quotes.
593*cdf0e10cSrcweir                          */
594*cdf0e10cSrcweir                         if (string_magic && defp[-1] == parlist[c][0]) {
595*cdf0e10cSrcweir                             strcpy(defp-1, parlist[c]);
596*cdf0e10cSrcweir                             defp += (size - 2);
597*cdf0e10cSrcweir                         }
598*cdf0e10cSrcweir                         else {
599*cdf0e10cSrcweir                             strcpy(defp, parlist[c]);
600*cdf0e10cSrcweir                             defp += size;
601*cdf0e10cSrcweir                         }
602*cdf0e10cSrcweir                     }
603*cdf0e10cSrcweir                 }
604*cdf0e10cSrcweir                 else if (defp >= defend) {
605*cdf0e10cSrcweir nospace:            cfatal("Out of space in macro \"%s\" arg expansion",
606*cdf0e10cSrcweir                         tokenp->name);
607*cdf0e10cSrcweir                 }
608*cdf0e10cSrcweir                 else {
609*cdf0e10cSrcweir                     *defp++ = (char)c;
610*cdf0e10cSrcweir                 }
611*cdf0e10cSrcweir             }
612*cdf0e10cSrcweir         }
613*cdf0e10cSrcweir         *defp = EOS;
614*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
615*cdf0e10cSrcweir         if (debug > 1)
616*cdf0e10cSrcweir             fprintf( pCppOut, "macroline: \"%s\"\n", file->buffer);
617*cdf0e10cSrcweir #endif
618*cdf0e10cSrcweir }
619*cdf0e10cSrcweir 
620*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
621*cdf0e10cSrcweir void dumpparm(char* why)
622*cdf0e10cSrcweir /*
623*cdf0e10cSrcweir  * Dump parameter list.
624*cdf0e10cSrcweir  */
625*cdf0e10cSrcweir {
626*cdf0e10cSrcweir         register int    i;
627*cdf0e10cSrcweir 
628*cdf0e10cSrcweir     fprintf( pCppOut, "dump of %d parameters (%d bytes total) %s\n",
629*cdf0e10cSrcweir             nargs, parmp - parm, why);
630*cdf0e10cSrcweir         for (i = 0; i < nargs; i++) {
631*cdf0e10cSrcweir         fprintf( pCppOut, "parm[%d] (%d) = \"%s\"\n",
632*cdf0e10cSrcweir                 i + 1, (int)strlen(parlist[i]), parlist[i]);
633*cdf0e10cSrcweir         }
634*cdf0e10cSrcweir }
635*cdf0e10cSrcweir #endif
636