bump product version to 5.0.4.1
[LibreOffice.git] / rsc / source / rscpp / cpp4.c
blobdaa91735f6cca266e81ef902aaeb6249d90cdcf0
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/types.h>
21 #include <stdio.h>
22 #include <ctype.h>
23 #include "cppdef.h"
24 #include "cpp.h"
26 * parm[], parmp, and parlist[] are used to store #define() argument
27 * lists. nargs contains the actual number of parameters stored.
29 static char parm[NPARMWORK + 1]; /* define param work buffer */
30 static char* parmp; /* Free space in parm */
31 static char* parlist[LASTPARM]; /* -> start of each parameter */
32 static int nargs; /* Parameters for this macro */
34 void InitCpp4()
36 int i;
37 for( i = 0; i < NPARMWORK; i++ )
38 parm[ i ] = 0;
39 for( i = 0; i < LASTPARM; i++ )
40 parlist[ i ] = NULL;
42 nargs = 0;
47 * Called from control when a #define is scanned. This module
48 * parses formal parameters and the replacement string. When
49 * the formal parameter name is encountered in the replacement
50 * string, it is replaced by a character in the range 128 to
51 * 128+NPARAM (this allows up to 32 parameters within the
52 * Dec Multinational range).
54 * There is some special case code to distinguish
55 * #define foo bar
56 * from #define foo() bar
58 * Also, we make sure that
59 * #define foo foo
60 * expands to "foo" but doesn't put cpp into an infinite loop.
62 * A warning message is printed if you redefine a symbol to a
63 * different text. I.e,
64 * #define foo 123
65 * #define foo 123
66 * is ok, but
67 * #define foo 123
68 * #define foo +123
69 * is not.
71 * The following subroutines are called from define():
72 * checkparm called when a token is scanned. It checks through the
73 * array of formal parameters. If a match is found, the
74 * token is replaced by a control byte which will be used
75 * to locate the parameter when the macro is expanded.
76 * textput puts a string in the macro work area (parm[]), updating
77 * parmp to point to the first free byte in parm[].
78 * textput() tests for work buffer overflow.
79 * charput puts a single character in the macro work area (parm[])
80 * in a manner analogous to textput().
82 void dodefine()
84 int c;
85 DEFBUF* dp; /* -> new definition */
86 int isredefine; /* TRUE if redefined */
87 char* old = 0; /* Remember redefined */
89 if (type[(c = skipws())] != LET)
90 goto bad_define;
91 isredefine = FALSE; /* Set if redefining */
92 if ((dp = lookid(c)) == NULL) /* If not known now */
93 dp = defendel(token, FALSE); /* Save the name */
94 else /* It's known: */
96 isredefine = TRUE; /* Remember this fact */
97 old = dp->repl; /* Remember replacement */
98 dp->repl = NULL; /* No replacement now */
100 parlist[0] = parmp = parm; /* Setup parm buffer */
101 if ((c = get()) == '(') /* With arguments? */
103 nargs = 0; /* Init formals counter */
104 do /* Collect formal parms */
106 if (nargs >= LASTPARM)
107 cfatal("Too many arguments for macro", NULLST);
108 else if ((c = skipws()) == ')')
109 break; /* Got them all */
110 else if (type[c] != LET) /* Bad formal syntax */
111 goto bad_define;
112 scanid(c); /* Get the formal param */
113 parlist[nargs++] = parmp; /* Save its start */
114 textput(token); /* Save text in parm[] */
116 while ((c = skipws()) == ','); /* Get another argument */
117 if (c != ')') /* Must end at ) */
118 goto bad_define;
119 c = ' '; /* Will skip to body */
121 else
124 * DEF_NOARGS is needed to distinguish between
125 * "#define foo" and "#define foo()".
127 nargs = DEF_NOARGS; /* No () parameters */
129 if (type[c] == SPA) /* At whitespace? */
130 c = skipws(); /* Not any more. */
131 workp = work; /* Replacement put here */
132 inmacro = TRUE; /* Keep \<newline> now */
133 while (c != EOF_CHAR && c != '\n') /* Compile macro body */
135 if (c == '#') /* Token concatenation? */
137 while (workp > work && type[(int)workp[-1]] == SPA)
138 --workp; /* Erase leading spaces */
139 save(TOK_SEP); /* Stuff a delimiter */
140 c = skipws(); /* Eat whitespace */
141 if (type[c] == LET) /* Another token here? */
142 ; /* Stuff it normally */
143 else if (type[c] == DIG) /* Digit string after? */
145 while (type[c] == DIG) /* Stuff the digits */
147 save(c);
148 c = get();
150 save(TOK_SEP); /* Delimit 2nd token */
152 else
154 ciwarn("Strange character after # (%d.)", c);
156 continue;
158 switch (type[c])
160 case LET:
161 checkparm(c, dp); /* Might be a formal */
162 break;
164 case DIG: /* Number in mac. body */
165 case DOT: /* Maybe a float number */
166 scannumber(c, save); /* Scan it off */
167 break;
169 case QUO: /* String in mac. body */
170 stparmscan(c);
171 break;
173 case BSH: /* Backslash */
174 save('\\');
175 if ((c = get()) == '\n')
176 wrongline = TRUE;
177 save(c);
178 break;
180 case SPA: /* Absorb whitespace */
182 * Note: the "end of comment" marker is passed on
183 * to allow comments to separate tokens.
185 if (workp[-1] == ' ') /* Absorb multiple */
186 break; /* spaces */
187 else if (c == '\t')
188 c = ' '; /* Normalize tabs */
189 /* Fall through to store character */
190 default: /* Other character */
191 save(c);
192 break;
194 c = get();
196 inmacro = FALSE; /* Stop newline hack */
197 unget(); /* For control check */
198 if (workp > work && workp[-1] == ' ') /* Drop trailing blank */
199 workp--;
200 *workp = EOS; /* Terminate work */
201 dp->repl = savestring(work); /* Save the string */
202 dp->nargs = nargs; /* Save arg count */
203 #if OSL_DEBUG_LEVEL > 1
204 if (debug)
205 dumpadef("macro definition", dp);
206 else if (bDumpDefs)
207 dumpadef(NULL, dp);
208 #endif
209 if (isredefine) /* Error if redefined */
211 if ((old != NULL && dp->repl != NULL && !streq(old, dp->repl)) ||
212 (old == NULL && dp->repl != NULL) ||
213 (old != NULL && dp->repl == NULL))
215 #ifdef STRICT_UNDEF
216 cerror("Redefining defined variable \"%s\"", dp->name);
217 #else
218 cwarn("Redefining defined variable \"%s\"", dp->name);
219 #endif
221 if (old != NULL) /* We don't need the */
222 free(old); /* old definition now. */
224 return;
226 bad_define:
227 cerror("#define syntax error", NULLST);
228 inmacro = FALSE; /* Stop <newline> hack */
232 * Replace this param if it's defined. Note that the macro name is a
233 * possible replacement token. We stuff DEF_MAGIC in front of the token
234 * which is treated as a LETTER by the token scanner and eaten by
235 * the output routine. This prevents the macro expander from
236 * looping if someone writes "#define foo foo".
238 void checkparm(int c, DEFBUF* dp)
240 int i;
241 char* cp;
243 scanid(c); /* Get parm to token[] */
244 for (i = 0; i < nargs; i++) /* For each argument */
246 if (streq(parlist[i], token)) /* If it's known */
248 #ifdef SOLAR
249 save(DEL);
250 #endif
251 save(i + MAC_PARM); /* Save a magic cookie */
252 return; /* And exit the search */
255 if (streq(dp->name, token)) /* Macro name in body? */
256 save(DEF_MAGIC); /* Save magic marker */
257 for (cp = token; *cp != EOS;) /* And save */
258 save(*cp++); /* The token itself */
262 * Normal string parameter scan.
264 void stparmscan(int delim)
266 char* wp;
267 int i;
269 wp = workp; /* Here's where it starts */
270 if (!scanstring(delim, save))
271 return; /* Exit on scanstring error */
272 workp[-1] = EOS; /* Erase trailing quote */
273 wp++; /* -> first string content byte */
274 for (i = 0; i < nargs; i++)
276 if (streq(parlist[i], wp))
278 #ifdef SOLAR
279 *wp++ = DEL;
280 *wp++ = MAC_PARM + PAR_MAC; /* Stuff a magic marker */
281 *wp++ = (char)(i + MAC_PARM); /* Make a formal marker */
282 *wp = wp[-4]; /* Add on closing quote */
283 workp = wp + 1; /* Reset string end */
284 #else
285 *wp++ = MAC_PARM + PAR_MAC; /* Stuff a magic marker */
286 *wp++ = (i + MAC_PARM); /* Make a formal marker */
287 *wp = wp[-3]; /* Add on closing quote */
288 workp = wp + 1; /* Reset string end */
289 #endif
290 return;
293 workp[-1] = wp[-1]; /* Nope, reset end quote. */
297 * Remove the symbol from the defined list.
298 * Called from the #control processor.
300 void doundef()
302 int c;
304 if (type[(c = skipws())] != LET)
305 cerror("Illegal #undef argument", NULLST);
306 else
308 scanid(c); /* Get name to token[] */
309 if (defendel(token, TRUE) == NULL)
311 #ifdef STRICT_UNDEF
312 cwarn("Symbol \"%s\" not defined in #undef", token);
313 #endif
319 * Put the string in the parm[] buffer.
321 void textput(char* text)
323 size_t size;
325 size = strlen(text) + 1;
326 if ((parmp + size) >= &parm[NPARMWORK])
327 cfatal("Macro work area overflow", NULLST);
328 else
330 strcpy(parmp, text);
331 parmp += size;
336 * Put the byte in the parm[] buffer.
338 void charput(int c)
340 if (parmp >= &parm[NPARMWORK])
341 cfatal("Macro work area overflow", NULLST);
342 else
344 *parmp++ = (char)c;
349 * M a c r o E x p a n s i o n
352 static DEFBUF* macro; /* Catches start of infinite macro */
355 * Expand a macro. Called from the cpp mainline routine (via subroutine
356 * macroid()) when a token is found in the symbol table. It calls
357 * expcollect() to parse actual parameters, checking for the correct number.
358 * It then creates a "file" containing a single line containing the
359 * macro with actual parameters inserted appropriately. This is
360 * "pushed back" onto the input stream. (When the get() routine runs
361 * off the end of the macro line, it will dismiss the macro itself.)
363 void expand(DEFBUF* tokenp)
365 int c;
366 FILEINFO* file;
368 #if OSL_DEBUG_LEVEL > 1
369 if (debug)
370 dumpadef("expand entry", tokenp);
371 #endif
373 * If no macro is pending, save the name of this macro
374 * for an eventual error message.
376 if (recursion++ == 0)
377 macro = tokenp;
378 else if (recursion == RECURSION_LIMIT)
380 cerror("Recursive macro definition of \"%s\"", tokenp->name);
381 fprintf(stderr, "(Defined by \"%s\")\n", macro->name);
382 if (rec_recover)
386 c = get();
388 while (infile != NULL && infile->fp == NULL);
389 unget();
390 recursion = 0;
391 return;
395 * Here's a macro to expand.
397 nargs = 0; /* Formals counter */
398 parmp = parm; /* Setup parm buffer */
399 switch (tokenp->nargs)
401 case (-2): /* __LINE__ */
402 sprintf(work, "%d", line);
403 ungetstring(work);
404 break;
406 case (-3): /* __FILE__ */
407 for (file = infile; file != NULL; file = file->parent)
409 if (file->fp != NULL)
411 sprintf(work, "\"%s\"", (file->progname != NULL)
412 ? file->progname : file->filename);
413 ungetstring(work);
414 break;
417 break;
419 default:
421 * Nothing funny about this macro.
423 if (tokenp->nargs < 0)
424 cfatal("Bug: Illegal __ macro \"%s\"", tokenp->name);
425 while ((c = skipws()) == '\n') /* Look for (, skipping */
426 wrongline = TRUE; /* spaces and newlines */
427 if (c != '(')
430 * If the programmer writes
431 * #define foo() ...
432 * ...
433 * foo [no ()]
434 * just write foo to the output stream.
436 unget();
437 cwarn("Macro \"%s\" needs arguments", tokenp->name);
438 fputs(tokenp->name, pCppOut );
439 return;
441 else if (expcollect()) /* Collect arguments */
443 if (tokenp->nargs != nargs) /* Should be an error? */
445 cwarn("Wrong number of macro arguments for \"%s\"",
446 tokenp->name);
448 #if OSL_DEBUG_LEVEL > 1
449 if (debug)
450 dumpparm("expand");
451 #endif
452 } /* Collect arguments */
453 case DEF_NOARGS: /* No parameters just stuffs */
454 expstuff(tokenp); /* Do actual parameters */
455 } /* nargs switch */
459 * Collect the actual parameters for this macro. TRUE if ok.
461 FILE_LOCAL int expcollect()
463 int c;
464 int paren; /* For embedded ()'s */
465 for (;;)
467 paren = 0; /* Collect next arg. */
468 while ((c = skipws()) == '\n') /* Skip over whitespace */
469 wrongline = TRUE; /* and newlines. */
470 if (c == ')') /* At end of all args? */
473 * Note that there is a guard byte in parm[]
474 * so we don't have to check for overflow here.
476 *parmp = EOS; /* Make sure terminated */
477 break; /* Exit collection loop */
479 else if (nargs >= LASTPARM)
480 cfatal("Too many arguments in macro expansion", NULLST);
481 parlist[nargs++] = parmp; /* At start of new arg */
482 for (;; c = cget()) /* Collect arg's bytes */
484 if (c == EOF_CHAR)
486 cerror("end of file within macro argument", NULLST);
487 return FALSE; /* Sorry. */
489 else if (c == '\\') /* Quote next character */
491 charput(c); /* Save the \ for later */
492 charput(cget()); /* Save the next char. */
493 continue; /* And go get another */
495 else if (type[c] == QUO) /* Start of string? */
497 scanstring(c, charput); /* Scan it off */
498 continue; /* Go get next char */
500 else if (c == '(') /* Worry about balance */
501 paren++; /* To know about commas */
502 else if (c == ')') /* Other side too */
504 if (paren == 0) /* At the end? */
506 unget(); /* Look at it later */
507 break; /* Exit arg getter. */
509 paren--; /* More to come. */
511 else if (c == ',' && paren == 0) /* Comma delimits args */
512 break;
513 else if (c == '\n') /* Newline inside arg? */
514 wrongline = TRUE; /* We'll need a #line */
515 charput(c); /* Store this one */
516 } /* Collect an argument */
517 charput(EOS); /* Terminate argument */
518 #if OSL_DEBUG_LEVEL > 1
519 if (debug)
520 fprintf( pCppOut, "parm[%d] = \"%s\"\n", nargs, parlist[nargs - 1]);
521 #endif
522 } /* Collect all args. */
523 return TRUE; /* Normal return */
527 * Stuff the macro body, replacing formal parameters by actual parameters.
529 FILE_LOCAL void expstuff(DEFBUF* tokenp)
531 int c; /* Current character */
532 char* inp; /* -> repl string */
533 char* defp; /* -> macro output buff */
534 size_t size; /* Actual parm. size */
535 char* defend; /* -> output buff end */
536 int string_magic; /* String formal hack */
537 FILEINFO* file; /* Funny #include */
539 file = getfile(NBUFF, tokenp->name);
540 inp = tokenp->repl; /* -> macro replacement */
541 defp = file->buffer; /* -> output buffer */
542 defend = defp + (NBUFF - 1); /* Note its end */
543 if (inp != NULL)
545 while ((c = (*inp++ & 0xFF)) != EOS)
547 #ifdef SOLAR
548 if (c == DEL)
550 c = (*inp++ & 0xFF);
551 #else
552 if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC))
554 #endif
555 string_magic = (c == (MAC_PARM + PAR_MAC));
556 if (string_magic)
557 c = (*inp++ & 0xFF);
559 * Replace formal parameter by actual parameter string.
561 if ((c -= MAC_PARM) < nargs)
563 size = strlen(parlist[c]);
564 if ((defp + size) >= defend)
565 goto nospace;
567 * Erase the extra set of quotes.
569 if (string_magic && defp[-1] == parlist[c][0])
571 strcpy(defp-1, parlist[c]);
572 defp += (size - 2);
574 else
576 strcpy(defp, parlist[c]);
577 defp += size;
581 else if (defp >= defend)
583 nospace:
584 cfatal("Out of space in macro \"%s\" arg expansion",
585 tokenp->name);
587 else
589 *defp++ = (char)c;
593 *defp = EOS;
594 #if OSL_DEBUG_LEVEL > 1
595 if (debug > 1)
596 fprintf( pCppOut, "macroline: \"%s\"\n", file->buffer);
597 #endif
600 #if OSL_DEBUG_LEVEL > 1
603 * Dump parameter list.
605 void dumpparm(char* why)
607 int i;
609 fprintf( pCppOut, "dump of %d parameters (%" SAL_PRI_SIZET "u bytes total) %s\n",
610 nargs, parmp - parm, why);
611 for (i = 0; i < nargs; i++)
613 fprintf( pCppOut, "parm[%d] (%d) = \"%s\"\n",
614 i + 1, (int)strlen(parlist[i]), parlist[i]);
617 #endif
619 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */