1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
30 #if OSL_DEBUG_LEVEL > 1
31 FILE* pDefOut
= NULL
; /* ER evtl. #define's dump */
35 /* einzige Moeglichkeit unter BC Stack und Heap festzusetzen */
36 extern unsigned _stklen
= 24000;
37 extern unsigned _heaplen
= 30000;
43 * Commonly used global variables:
44 * line is the current input line number.
45 * wrongline is set in many places when the actual output
46 * line is out of sync with the numbering, e.g,
47 * when expanding a macro with an embedded newline.
49 * token holds the last identifier scanned (which might
50 * be a candidate for macro expansion).
51 * errors is the running cpp error counter.
52 * infile is the head of a linked list of input files (extended by
53 * #include and macros being expanded). infile always points
54 * to the current file/macro. infile->parent to the includer,
55 * etc. infile->fd is NULL if this input stream is a macro.
57 int line
; /* Current line number */
58 int wrongline
; /* Force #line to compiler */
59 char token
[IDMAX
+ 1]; /* Current input token */
60 int errors
; /* cpp error counter */
61 FILEINFO
* infile
= NULL
; /* Current input file */
62 #if OSL_DEBUG_LEVEL > 1
63 int debug
; /* TRUE if debugging now */
64 int bDumpDefs
; /* TRUE if #define's dump req. */
66 int bIsInEval
; /* TRUE if #define eval now */
67 char EvalBuf
[NEVALBUF
+ 1]; /* evaluation buffer */
68 int nEvalOff
= 0; /* offset to free buffer pos */
72 * This counter is incremented when a macro expansion is initiated.
73 * If it exceeds a built-in value, the expansion stops -- this tests
74 * for a runaway condition:
78 * This can be disabled by falsifying rec_recover. (Nothing does this
79 * currently: it is a hook for an eventual invocation flag.)
81 int recursion
; /* Infinite recursion counter */
82 int rec_recover
= TRUE
; /* Unwind recursive macros */
85 * instring is set TRUE when a string is scanned. It modifies the
86 * behavior of the "get next character" routine, causing all characters
87 * to be passed to the caller (except <DEF_MAGIC>). Note especially that
88 * comments and \<newline> are not removed from the source. (This
89 * prevents cpp output lines from being arbitrarily long).
91 * inmacro is set by #define -- it absorbs comments and converts
92 * form-feed and vertical-tab to space, but returns \<newline>
93 * to the caller. Strictly speaking, this is a bug as \<newline>
94 * shouldn't delimit tokens, but we'll worry about that some other
95 * time -- it is more important to prevent infinitly long output lines.
97 * instring and inmarcor are parameters to the get() routine which
98 * were made global for speed.
100 int instring
= FALSE
; /* TRUE if scanning string */
101 int inmacro
= FALSE
; /* TRUE if #defining a macro */
104 * work[] and workp are used to store one piece of text in a temporay
105 * buffer. To initialize storage, set workp = work. To store one
106 * character, call save(c); (This will fatally exit if there isn't
107 * room.) To terminate the string, call save(EOS). Note that
108 * the work buffer is used by several subroutines -- be sure your
109 * data won't be overwritten. The extra byte in the allocation is
110 * needed for string formal replacement.
112 char work
[NWORK
+ 1]; /* Work buffer */
113 char* workp
; /* Work buffer pointer */
116 * keepcomments is set TRUE by the -C option. If TRUE, comments
117 * are written directly to the output stream. This is needed if
118 * the output from cpp is to be passed to lint (which uses commands
119 * embedded in comments). cflag contains the permanent state of the
120 * -C flag. keepcomments is always falsified when processing #control
121 * commands and when compilation is suppressed by a false #if
123 * If eflag is set, CPP returns "success" even if non-fatal errors
126 * If nflag is non-zero, no symbols are predefined except __LINE__.
127 * __FILE__, and __DATE__. If nflag > 1, absolutely no symbols
130 int keepcomments
= FALSE
; /* Write out comments flag */
131 int cflag
= FALSE
; /* -C option (keep comments) */
132 int eflag
= FALSE
; /* -E option (never fail) */
133 int nflag
= 0; /* -N option (no predefines) */
136 * ifstack[] holds information about nested #if's. It is always
137 * accessed via *ifptr. The information is as follows:
138 * WAS_COMPILING state of compiling flag at outer level.
139 * ELSE_SEEN set TRUE when #else seen to prevent 2nd #else.
140 * TRUE_SEEN set TRUE when #if or #elif succeeds
141 * ifstack[0] holds the compiling flag. It is TRUE if compilation
142 * is currently enabled. Note that this must be initialized TRUE.
144 char ifstack
[BLK_NEST
] = { TRUE
}; /* #if information */
145 char* ifptr
= ifstack
; /* -> current ifstack[] */
148 * incdir[] stores the -i directories (and the system-specific
149 * #include <...> directories.
151 char* incdir
[NINCLUDE
]; /* -i directories */
152 char** incend
= incdir
; /* -> free space in incdir[] */
155 * This is the table used to predefine target machine and operating
156 * system designators. It may need hacking for specific circumstances.
157 * Note: it is not clear that this is part of the Ansi Standard.
158 * The -N option suppresses preset definitions.
161 { /* names defined at cpp start */
171 #if OSL_DEBUG_LEVEL > 1
172 "decus_cpp", /* Ourselves! */
174 NULL
/* Must be last */
178 * The value of these predefined symbols must be recomputed whenever
179 * they are evaluated. The order must not be changed.
182 { /* Note: order is important */
185 NULL
/* Must be last */
188 static char* sharpfilename
= NULL
;
195 /* in der LIB-Version muessen alle Variablen initialisiert werden */
197 line
= wrongline
= errors
= recursion
= 0;
198 for( i
= 0; i
< IDMAX
; i
++ )
201 for( i
= 0; i
< NWORK
; i
++ )
204 for( i
= 0; i
< NINCLUDE
; i
++ )
208 for( i
= 0; i
< BLK_NEST
; i
++ )
214 #if OSL_DEBUG_LEVEL > 1
220 for( i
= 0; i
< NEVALBUF
; i
++ )
227 instring
= inmacro
= keepcomments
= cflag
= eflag
= FALSE
;
230 sharpfilename
= NULL
;
233 int MAIN(int argc
, char** argv
)
237 char** pfargv
= NULL
;
250 initdefines(); /* O.S. specific def's */
251 if ( argv
[argc
-1][0] == '@' )
253 i
= readoptions( argv
[1], &pfargv
); /* Command file */
258 i
= dooptions(argc
, argv
); /* Command line -flags */
263 #if OSL_DEBUG_LEVEL > 1
268 * Get defBase file, "-" means use stdout.
270 if (!streq(useargv
[3], "-"))
272 pDefOut
= fopen( useargv
[3], "w" );
273 if( pDefOut
== NULL
)
276 cerror("Can't open output file \"%s\"", useargv
[3]);
279 } /* Continue by opening output */
284 * Get output file, "-" means use stdout.
286 if (!streq(useargv
[2], "-"))
288 pCppOut
= fopen( useargv
[2], "w" );
289 if( pCppOut
== NULL
)
292 cerror("Can't open output file \"%s\"", useargv
[2]);
295 } /* Continue by opening input */
296 case 2: /* One file -> stdin */
298 * Open input file, "-" means use stdin.
300 if (!streq(useargv
[1], "-"))
302 pCppIn
= fopen( useargv
[1], "r" );
306 cerror("Can't open input file \"%s\"", useargv
[1]);
309 strncpy(work
, useargv
[1], NWORK
); /* Remember input filename */
311 } /* Else, just get stdin */
312 case 0: /* No args? */
313 case 1: /* No files, stdin -> stdout */
314 work
[0] = EOS
; /* Unix can't find stdin name */
318 exit(IO_ERROR
); /* Can't happen */
321 setincdirs(); /* Setup -I include directories */
322 addfile( pCppIn
, work
); /* "open" main input file */
323 #if OSL_DEBUG_LEVEL > 1
324 if (debug
> 0 || bDumpDefs
)
325 dumpdef("preset #define symbols");
327 if( pCppIn
!= stdin
)
330 cppmain(); /* Process main file */
332 if ((i
= (ifptr
- &ifstack
[0])) != 0)
334 cierror("Inside #ifdef block at end of input, depth = %d", i
);
336 #if OSL_DEBUG_LEVEL > 1
337 if( pDefOut
!= stdout
&& pDefOut
!= stderr
)
340 if( pCppOut
!= stdout
&& pCppOut
!= stderr
)
345 fprintf(stderr
, (errors
== 1)
346 ? "%d error in preprocessor\n"
347 : "%d errors in preprocessor\n", errors
);
358 * Main process for cpp -- copies tokens from the current input
359 * stream (main file, include file, or a macro) to the output
364 int c
; /* Current character */
365 int counter
; /* newlines and spaces */
368 * Explicitly output a #line at the start of cpp output so
369 * that lint (etc.) knows the name of the original source
370 * file. If we don't do this explicitly, we may get
371 * the name of the first #include file instead.
372 * We also seem to need a blank line following that first #line.
382 * This loop is started "from the top" at the beginning of each line
383 * wrongline is set TRUE in many places if it is necessary to write
384 * a #line record. (But we don't write them when expanding macros.)
386 * The counter variable has two different uses: at
387 * the start of a line, it counts the number of blank lines that
388 * have been skipped over. These are then either output via
389 * #line records or by outputting explicit blank lines.
390 * When expanding tokens within a line, the counter remembers
391 * whether a blank/tab has been output. These are dropped
392 * at the end of the line, and replaced by a single blank
397 counter
= 0; /* Count empty lines */
399 { /* For each line, ... */
400 while (type
[(c
= get())] == SPA
) /* Skip leading blanks */
401 ; /* in this line. */
402 if (c
== '\n') /* If line's all blank, */
403 ++counter
; /* Do nothing now */
405 { /* Is 1st non-space '#' */
406 keepcomments
= FALSE
; /* Don't pass comments */
407 counter
= control(counter
); /* Yes, do a #command */
408 keepcomments
= (cflag
&& compiling
);
410 else if (c
== EOF_CHAR
) /* At end of file? */
415 { /* #ifdef false? */
416 skipnl(); /* Skip to newline */
417 counter
++; /* Count it, too. */
421 break; /* Actual token */
424 if (c
== EOF_CHAR
) /* Exit process at */
425 break; /* End of file */
427 * If the loop didn't terminate because of end of file, we
428 * know there is a token to compile. First, clean up after
429 * absorbing newlines. counter has the number we skipped.
431 if ((wrongline
&& infile
->fp
!= NULL
) || counter
> 4)
432 sharp(); /* Output # line number */
434 { /* If just a few, stuff */
435 while (--counter
>= 0) /* them out ourselves */
439 * Process each token on this line.
441 unget(); /* Reread the char. */
443 { /* For the whole line, */
445 { /* Token concat. loop */
446 for (counter
= 0; type
[(c
= get())] == SPA
;)
448 counter
++; /* Skip over blanks */
451 if (c
== EOF_CHAR
|| c
== '\n')
452 goto end_line
; /* Exit line loop */
453 else if (counter
> 0) /* If we got any spaces */
454 PUTCHAR(' '); /* Output one space */
455 c
= macroid(c
); /* Grab the token */
457 while (type
[c
] == LET
&& catenate());
459 if (c
== EOF_CHAR
|| c
== '\n') /* From macro exp error */
460 goto end_line
; /* Exit line loop */
465 fputs(token
, pCppOut
); /* Quite ordinary token */
470 && nEvalOff
+ (len
=strlen(token
)) < NEVALBUF
)
472 strcpy( &EvalBuf
[nEvalOff
], token
);
480 case DIG
: /* Output a number */
481 case DOT
: /* Dot may begin floats */
484 scannumber(c
, outputEval
);
486 scannumber(c
, output
);
488 scannumber(c
, output
);
492 case QUO
: /* char or string const */
493 scanstring(c
, output
); /* Copy it to output */
496 default: /* Some other character */
497 cput(c
); /* Just output it */
499 if ( bIsInEval
&& nEvalOff
< NEVALBUF
)
500 EvalBuf
[nEvalOff
++] = c
;
504 } /* Line for loop */
507 { /* Compiling at EOL? */
508 PUTCHAR('\n'); /* Output newline, if */
509 if (infile
->fp
== NULL
) /* Expanding a macro, */
510 wrongline
= TRUE
; /* Output # line later */
512 } /* Continue until EOF */
515 EvalBuf
[nEvalOff
++] = '\0';
520 * Output one character to stdout -- output() is passed as an
521 * argument to scanstring()
531 * Output one character to stdout -- output() is passed as an
532 * argument to scanstring()
534 int outputEval(int c
)
539 if ( bIsInEval
&& nEvalOff
< NEVALBUF
)
540 EvalBuf
[nEvalOff
++] = c
;
547 * Output a line number line.
553 if (keepcomments
) /* Make sure # comes on */
554 PUTCHAR('\n'); /* a fresh, new line. */
556 fprintf( pCppOut
, "#%s %d", LINE_PREFIX
, line
);
557 if (infile
->fp
!= NULL
)
559 name
= (infile
->progname
!= NULL
) ? infile
->progname
: infile
->filename
;
560 if (sharpfilename
== NULL
||
561 (sharpfilename
!= NULL
&& !streq(name
, sharpfilename
)))
563 if (sharpfilename
!= NULL
)
565 sharpfilename
= savestring(name
);
566 fprintf( pCppOut
, " \"%s\"", name
);
573 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */