Update ooo320-m1
[ooovba.git] / rsc / source / rscpp / cpp1.c
blobcc8142f1592a52fa2f6708473d592f274399e64a
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: cpp1.c,v $
10 * $Revision: 1.11 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include <stdio.h>
32 #include <ctype.h>
33 #include "cppdef.h"
34 #include "cpp.h"
36 FILE *pCppOut = NULL;
37 FILE *pCppIn = NULL;
39 #if OSL_DEBUG_LEVEL > 1
40 FILE *pDefOut = NULL; /* ER evtl. #define's dump */
41 #endif
43 #ifdef B200
44 /* BP, 25.07.91, einzige Moeglichkeit unter BC Stack und Heap festzusetzen */
45 extern unsigned _stklen = 24000;
46 extern unsigned _heaplen = 30000;
47 #endif
52 * Commonly used global variables:
53 * line is the current input line number.
54 * wrongline is set in many places when the actual output
55 * line is out of sync with the numbering, e.g,
56 * when expanding a macro with an embedded newline.
58 * token holds the last identifier scanned (which might
59 * be a candidate for macro expansion).
60 * errors is the running cpp error counter.
61 * infile is the head of a linked list of input files (extended by
62 * #include and macros being expanded). infile always points
63 * to the current file/macro. infile->parent to the includer,
64 * etc. infile->fd is NULL if this input stream is a macro.
66 int line; /* Current line number */
67 int wrongline; /* Force #line to compiler */
68 char token[IDMAX + 1]; /* Current input token */
69 int errors; /* cpp error counter */
70 FILEINFO *infile = NULL; /* Current input file */
71 #if OSL_DEBUG_LEVEL > 1
72 int debug; /* TRUE if debugging now */
73 int bDumpDefs; /* TRUE if #define's dump req. */
74 #ifdef EVALDEFS
75 int bIsInEval; /* TRUE if #define eval now */
76 char EvalBuf[NEVALBUF + 1]; /* evaluation buffer */
77 int nEvalOff = 0; /* offset to free buffer pos */
78 #endif
79 #endif
81 * This counter is incremented when a macro expansion is initiated.
82 * If it exceeds a built-in value, the expansion stops -- this tests
83 * for a runaway condition:
84 * #define X Y
85 * #define Y X
86 * X
87 * This can be disabled by falsifying rec_recover. (Nothing does this
88 * currently: it is a hook for an eventual invocation flag.)
90 int recursion; /* Infinite recursion counter */
91 int rec_recover = TRUE; /* Unwind recursive macros */
94 * instring is set TRUE when a string is scanned. It modifies the
95 * behavior of the "get next character" routine, causing all characters
96 * to be passed to the caller (except <DEF_MAGIC>). Note especially that
97 * comments and \<newline> are not removed from the source. (This
98 * prevents cpp output lines from being arbitrarily long).
100 * inmacro is set by #define -- it absorbs comments and converts
101 * form-feed and vertical-tab to space, but returns \<newline>
102 * to the caller. Strictly speaking, this is a bug as \<newline>
103 * shouldn't delimit tokens, but we'll worry about that some other
104 * time -- it is more important to prevent infinitly long output lines.
106 * instring and inmarcor are parameters to the get() routine which
107 * were made global for speed.
109 int instring = FALSE; /* TRUE if scanning string */
110 int inmacro = FALSE; /* TRUE if #defining a macro */
113 * work[] and workp are used to store one piece of text in a temporay
114 * buffer. To initialize storage, set workp = work. To store one
115 * character, call save(c); (This will fatally exit if there isn't
116 * room.) To terminate the string, call save(EOS). Note that
117 * the work buffer is used by several subroutines -- be sure your
118 * data won't be overwritten. The extra byte in the allocation is
119 * needed for string formal replacement.
121 char work[NWORK + 1]; /* Work buffer */
122 char *workp; /* Work buffer pointer */
125 * keepcomments is set TRUE by the -C option. If TRUE, comments
126 * are written directly to the output stream. This is needed if
127 * the output from cpp is to be passed to lint (which uses commands
128 * embedded in comments). cflag contains the permanent state of the
129 * -C flag. keepcomments is always falsified when processing #control
130 * commands and when compilation is supressed by a false #if
132 * If eflag is set, CPP returns "success" even if non-fatal errors
133 * were detected.
135 * If nflag is non-zero, no symbols are predefined except __LINE__.
136 * __FILE__, and __DATE__. If nflag > 1, absolutely no symbols
137 * are predefined.
139 int keepcomments = FALSE; /* Write out comments flag */
140 int cflag = FALSE; /* -C option (keep comments) */
141 int eflag = FALSE; /* -E option (never fail) */
142 int nflag = 0; /* -N option (no predefines) */
145 * ifstack[] holds information about nested #if's. It is always
146 * accessed via *ifptr. The information is as follows:
147 * WAS_COMPILING state of compiling flag at outer level.
148 * ELSE_SEEN set TRUE when #else seen to prevent 2nd #else.
149 * TRUE_SEEN set TRUE when #if or #elif succeeds
150 * ifstack[0] holds the compiling flag. It is TRUE if compilation
151 * is currently enabled. Note that this must be initialized TRUE.
153 char ifstack[BLK_NEST] = { TRUE }; /* #if information */
154 char *ifptr = ifstack; /* -> current ifstack[] */
157 * incdir[] stores the -i directories (and the system-specific
158 * #include <...> directories.
160 char *incdir[NINCLUDE]; /* -i directories */
161 char **incend = incdir; /* -> free space in incdir[] */
164 * This is the table used to predefine target machine and operating
165 * system designators. It may need hacking for specific circumstances.
166 * Note: it is not clear that this is part of the Ansi Standard.
167 * The -N option supresses preset definitions.
169 char *preset[] = { /* names defined at cpp start */
170 #ifdef MACHINE
171 MACHINE,
172 #endif
173 #ifdef SYSTEM
174 SYSTEM,
175 #endif
176 #ifdef COMPILER
177 COMPILER,
178 #endif
179 #if OSL_DEBUG_LEVEL > 1
180 "decus_cpp", /* Ourselves! */
181 #endif
182 NULL /* Must be last */
186 * The value of these predefined symbols must be recomputed whenever
187 * they are evaluated. The order must not be changed.
189 char *magic[] = { /* Note: order is important */
190 "__LINE__",
191 "__FILE__",
192 NULL /* Must be last */
195 static char *sharpfilename = NULL;
197 int nRunde = 0;
199 void InitCpp1()
201 int i;
202 /* BP */
203 /* in der LIB-Version muessen alle Variablen initialisiert werden */
205 line = wrongline = errors = recursion = 0;
206 for( i = 0; i < IDMAX; i++ )
207 token[ i ] = 0;
209 for( i = 0; i < NWORK; i++ )
210 work[ i ] = 0;
212 for( i = 0; i < NINCLUDE; i++ )
213 incdir[ i ] = NULL;
215 workp = NULL;
216 for( i = 0; i < BLK_NEST; i++ )
217 ifstack[ i ] = TRUE;
218 ifptr = ifstack;
220 pCppOut = stdout;
221 pCppIn = stdin;
222 #if OSL_DEBUG_LEVEL > 1
223 debug = 0;
224 bDumpDefs = 0;
225 pDefOut = stdout;
226 #ifdef EVALDEFS
227 bIsInEval = 0;
228 for( i = 0; i < NEVALBUF; i++ )
229 EvalBuf[ i ] = 0;
230 nEvalOff = 0;
231 #endif
232 #endif
233 rec_recover = TRUE;
234 infile = NULL;
235 instring = inmacro = keepcomments = cflag = eflag = FALSE;
236 nflag = 0;
237 incend = incdir;
238 sharpfilename = NULL;
239 /* BP */
242 int MAIN(int argc, char** argv)
244 register int i;
245 char **useargv, **pfargv;
248 if( nRunde == 0 )
250 pCppIn = stdin;
251 pCppOut = stdout;
254 nRunde++;
255 InitCpp1();
256 InitCpp2();
257 InitCpp3();
258 InitCpp4();
259 InitCpp5();
260 InitCpp6();
262 #if HOST == SYS_VMS
263 argc = getredirection(argc, argv); /* vms >file and <file */
264 #endif
265 initdefines(); /* O.S. specific def's */
266 if ( argv[argc-1][0] == '@' )
268 i = readoptions( argv[1], &pfargv ); /* Command file */
269 useargv=pfargv;
271 else
273 i = dooptions(argc, argv); /* Command line -flags */
274 useargv=argv;
276 switch (i) {
277 #if OSL_DEBUG_LEVEL > 1
278 case 4:
279 if ( bDumpDefs )
282 * Get defBase file, "-" means use stdout.
284 if (!streq(useargv[3], "-")) {
285 #if HOST == SYS_VMS
287 * On vms, reopen stdout with "vanilla rms" attributes.
289 if ((i = creat(useargv[3], 0, "rat=cr", "rfm=var")) == -1
290 || dup2(i, fileno(stdout)) == -1) {
291 #else
292 /* alt if (freopen(useargv[3], "w", stdout) == NULL) { */
294 pDefOut = fopen( useargv[3], "w" );
295 if( pDefOut == NULL ) {
296 #endif
297 perror(useargv[3]);
298 cerror("Can't open output file \"%s\"", useargv[3]);
299 exit(IO_ERROR);
301 } /* Continue by opening output */
303 /* OSL_DEBUG_LEVEL > 1 */
304 #endif
305 case 3:
307 * Get output file, "-" means use stdout.
309 if (!streq(useargv[2], "-")) {
310 #if HOST == SYS_VMS
312 * On vms, reopen stdout with "vanilla rms" attributes.
314 if ((i = creat(useargv[2], 0, "rat=cr", "rfm=var")) == -1
315 || dup2(i, fileno(stdout)) == -1) {
316 #else
317 /* alt if (freopen(useargv[2], "w", stdout) == NULL) { */
319 pCppOut = fopen( useargv[2], "w" );
320 if( pCppOut == NULL ) {
321 #endif
322 perror(useargv[2]);
323 cerror("Can't open output file \"%s\"", useargv[2]);
324 exit(IO_ERROR);
326 } /* Continue by opening input */
327 case 2: /* One file -> stdin */
329 * Open input file, "-" means use stdin.
331 if (!streq(useargv[1], "-")) {
332 /* alt: if (freopen(useargv[1], "r", stdin) == NULL) { */
333 pCppIn = fopen( useargv[1], "r" );
334 if( pCppIn == NULL) {
335 perror(useargv[1]);
336 cerror("Can't open input file \"%s\"", useargv[1]);
337 exit(IO_ERROR);
339 strcpy(work, useargv[1]); /* Remember input filename */
340 break;
341 } /* Else, just get stdin */
342 case 0: /* No args? */
343 case 1: /* No files, stdin -> stdout */
344 #if (HOST == SYS_UNIX) || (HOST == SYS_UNKNOWN)
345 work[0] = EOS; /* Unix can't find stdin name */
346 #else
347 fgetname(stdin, work); /* Vax-11C, Decus C know name */
348 #endif
349 break;
351 default:
352 exit(IO_ERROR); /* Can't happen */
354 /* if ( pfargv )
356 for ( j=0;j++;j < PARALIMIT )
358 if (pfargv[j]!=0)
359 free(pfargv[j]);
361 free(pfargv);
365 setincdirs(); /* Setup -I include directories */
366 addfile( pCppIn, work); /* "open" main input file */
367 #if OSL_DEBUG_LEVEL > 1
368 if (debug > 0 || bDumpDefs)
369 dumpdef("preset #define symbols");
370 #endif
371 if( pCppIn != stdin )
372 rewind( pCppIn );
374 cppmain(); /* Process main file */
376 if ((i = (ifptr - &ifstack[0])) != 0) {
377 #if OLD_PREPROCESSOR
378 ciwarn("Inside #ifdef block at end of input, depth = %d", i);
379 #else
380 cierror("Inside #ifdef block at end of input, depth = %d", i);
381 #endif
383 #if OSL_DEBUG_LEVEL > 1
384 if( pDefOut != stdout && pDefOut != stderr )
385 fclose( pDefOut );
386 #endif
387 if( pCppOut != stdout && pCppOut != stderr )
388 fclose( pCppOut );
390 if (errors > 0) {
391 fprintf(stderr, (errors == 1)
392 ? "%d error in preprocessor\n"
393 : "%d errors in preprocessor\n", errors);
394 if (!eflag)
395 exit(IO_ERROR);
397 #ifdef NOMAIN /* BP */ /* kein exit im der LIB-Version */
398 return( IO_NORMAL );
399 #else
400 exit(IO_NORMAL); /* No errors or -E option set */
401 #endif
405 FILE_LOCAL
406 void cppmain()
408 * Main process for cpp -- copies tokens from the current input
409 * stream (main file, include file, or a macro) to the output
410 * file.
413 register int c; /* Current character */
414 register int counter; /* newlines and spaces */
417 * Explicitly output a #line at the start of cpp output so
418 * that lint (etc.) knows the name of the original source
419 * file. If we don't do this explicitly, we may get
420 * the name of the first #include file instead.
421 * We also seem to need a blank line following that first #line.
423 #ifdef EVALDEFS
424 if ( !bIsInEval )
425 #endif
427 sharp();
428 PUTCHAR('\n');
431 * This loop is started "from the top" at the beginning of each line
432 * wrongline is set TRUE in many places if it is necessary to write
433 * a #line record. (But we don't write them when expanding macros.)
435 * The counter variable has two different uses: at
436 * the start of a line, it counts the number of blank lines that
437 * have been skipped over. These are then either output via
438 * #line records or by outputting explicit blank lines.
439 * When expanding tokens within a line, the counter remembers
440 * whether a blank/tab has been output. These are dropped
441 * at the end of the line, and replaced by a single blank
442 * within lines.
444 for (;;) {
445 counter = 0; /* Count empty lines */
446 for (;;) { /* For each line, ... */
447 while (type[(c = get())] == SPA) /* Skip leading blanks */
448 ; /* in this line. */
449 if (c == '\n') /* If line's all blank, */
450 ++counter; /* Do nothing now */
451 else if (c == '#') { /* Is 1st non-space '#' */
452 keepcomments = FALSE; /* Don't pass comments */
453 counter = control(counter); /* Yes, do a #command */
454 keepcomments = (cflag && compiling);
456 else if (c == EOF_CHAR) /* At end of file? */
458 break;
460 else if (!compiling) { /* #ifdef false? */
461 skipnl(); /* Skip to newline */
462 counter++; /* Count it, too. */
464 else {
465 break; /* Actual token */
468 if (c == EOF_CHAR) /* Exit process at */
469 break; /* End of file */
471 * If the loop didn't terminate because of end of file, we
472 * know there is a token to compile. First, clean up after
473 * absorbing newlines. counter has the number we skipped.
475 if ((wrongline && infile->fp != NULL) || counter > 4)
476 sharp(); /* Output # line number */
477 else { /* If just a few, stuff */
478 while (--counter >= 0) /* them out ourselves */
479 PUTCHAR('\n');
482 * Process each token on this line.
484 unget(); /* Reread the char. */
485 for (;;) { /* For the whole line, */
486 do { /* Token concat. loop */
487 for (counter = 0; (type[(c = get())] == SPA);) {
488 #if COMMENT_INVISIBLE
489 if (c != COM_SEP)
490 counter++;
491 #else
492 counter++; /* Skip over blanks */
493 #endif
495 if (c == EOF_CHAR || c == '\n')
496 goto end_line; /* Exit line loop */
497 else if (counter > 0) /* If we got any spaces */
498 PUTCHAR(' '); /* Output one space */
499 c = macroid(c); /* Grab the token */
500 } while (type[c] == LET && catenate());
501 if (c == EOF_CHAR || c == '\n') /* From macro exp error */
502 goto end_line; /* Exit line loop */
503 switch (type[c]) {
504 case LET:
505 fputs(token, pCppOut); /* Quite ordinary token */
506 #ifdef EVALDEFS
508 int len;
509 if ( bIsInEval
510 && nEvalOff + (len=strlen(token)) < NEVALBUF )
512 strcpy( &EvalBuf[nEvalOff], token );
513 nEvalOff += len;
516 #endif
517 break;
520 case DIG: /* Output a number */
521 case DOT: /* Dot may begin floats */
522 #ifdef EVALDEFS
523 if ( bIsInEval )
524 scannumber(c, outputEval);
525 else
526 scannumber(c, output);
527 #else
528 scannumber(c, output);
529 #endif
530 break;
532 case QUO: /* char or string const */
533 scanstring(c, output); /* Copy it to output */
534 break;
536 default: /* Some other character */
537 cput(c); /* Just output it */
538 #ifdef EVALDEFS
539 if ( bIsInEval && nEvalOff < NEVALBUF )
540 EvalBuf[nEvalOff++] = c;
541 #endif
542 break;
543 } /* Switch ends */
544 } /* Line for loop */
545 end_line: if (c == '\n') { /* Compiling at EOL? */
546 PUTCHAR('\n'); /* Output newline, if */
547 if (infile->fp == NULL) /* Expanding a macro, */
548 wrongline = TRUE; /* Output # line later */
550 } /* Continue until EOF */
551 #ifdef EVALDEFS
552 if ( bIsInEval )
553 EvalBuf[nEvalOff++] = '\0';
554 #endif
557 void output(int c)
559 * Output one character to stdout -- output() is passed as an
560 * argument to scanstring()
563 #if COMMENT_INVISIBLE
564 if (c != TOK_SEP && c != COM_SEP)
565 #else
566 if (c != TOK_SEP)
567 #endif
568 /* alt: PUTCHAR(c); */
569 PUTCHAR(c);
572 #ifdef EVALDEFS
573 outputEval(c)
574 int c;
576 * Output one character to stdout -- output() is passed as an
577 * argument to scanstring()
580 #if COMMENT_INVISIBLE
581 if (c != TOK_SEP && c != COM_SEP)
582 #else
583 if (c != TOK_SEP)
584 #endif
585 /* alt: PUTCHAR(c); */
587 PUTCHAR(c);
588 if ( bIsInEval && nEvalOff < NEVALBUF )
589 EvalBuf[nEvalOff++] = c;
592 #endif
595 FILE_LOCAL
596 void sharp()
598 * Output a line number line.
601 register char *name;
603 if (keepcomments) /* Make sure # comes on */
604 PUTCHAR('\n'); /* a fresh, new line. */
605 fprintf( pCppOut, "#%s %d", LINE_PREFIX, line);
606 if (infile->fp != NULL) {
607 name = (infile->progname != NULL)
608 ? infile->progname : infile->filename;
609 if (sharpfilename == NULL
610 || (sharpfilename != NULL && !streq(name, sharpfilename)) ) {
611 if (sharpfilename != NULL)
612 free(sharpfilename);
613 sharpfilename = savestring(name);
614 fprintf( pCppOut, " \"%s\"", name);
617 PUTCHAR('\n');
618 wrongline = FALSE;