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