fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / rsc / source / rscpp / cpp1.c
blobe1688f0dadbb19a66918c633975102619fffc540
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 #define NOMAIN
22 #include <stdio.h>
23 #include <ctype.h>
24 #include "cppdef.h"
25 #include "cpp.h"
27 FILE *pCppOut = NULL;
28 FILE *pCppIn = NULL;
30 #if OSL_DEBUG_LEVEL > 1
31 FILE *pDefOut = NULL; /* ER evtl. #define's dump */
32 #endif
34 #ifdef B200
35 /* einzige Moeglichkeit unter BC Stack und Heap festzusetzen */
36 extern unsigned _stklen = 24000;
37 extern unsigned _heaplen = 30000;
38 #endif
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. */
65 #ifdef EVALDEFS
66 int bIsInEval; /* TRUE if #define eval now */
67 char EvalBuf[NEVALBUF + 1]; /* evaluation buffer */
68 int nEvalOff = 0; /* offset to free buffer pos */
69 #endif
70 #endif
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:
75 * #define X Y
76 * #define Y X
77 * X
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 supressed by a false #if
123 * If eflag is set, CPP returns "success" even if non-fatal errors
124 * were detected.
126 * If nflag is non-zero, no symbols are predefined except __LINE__.
127 * __FILE__, and __DATE__. If nflag > 1, absolutely no symbols
128 * are predefined.
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 supresses preset definitions.
160 char *preset[] = { /* names defined at cpp start */
161 #ifdef MACHINE
162 MACHINE,
163 #endif
164 #ifdef SYSTEM
165 SYSTEM,
166 #endif
167 #ifdef COMPILER
168 COMPILER,
169 #endif
170 #if OSL_DEBUG_LEVEL > 1
171 "decus_cpp", /* Ourselves! */
172 #endif
173 NULL /* Must be last */
177 * The value of these predefined symbols must be recomputed whenever
178 * they are evaluated. The order must not be changed.
180 char *magic[] = { /* Note: order is important */
181 "__LINE__",
182 "__FILE__",
183 NULL /* Must be last */
186 static char *sharpfilename = NULL;
188 int nRunde = 0;
190 void InitCpp1()
192 int i;
193 /* in der LIB-Version muessen alle Variablen initialisiert werden */
195 line = wrongline = errors = recursion = 0;
196 for( i = 0; i < IDMAX; i++ )
197 token[ i ] = 0;
199 for( i = 0; i < NWORK; i++ )
200 work[ i ] = 0;
202 for( i = 0; i < NINCLUDE; i++ )
203 incdir[ i ] = NULL;
205 workp = NULL;
206 for( i = 0; i < BLK_NEST; i++ )
207 ifstack[ i ] = TRUE;
208 ifptr = ifstack;
210 pCppOut = stdout;
211 pCppIn = stdin;
212 #if OSL_DEBUG_LEVEL > 1
213 debug = 0;
214 bDumpDefs = 0;
215 pDefOut = stdout;
216 #ifdef EVALDEFS
217 bIsInEval = 0;
218 for( i = 0; i < NEVALBUF; i++ )
219 EvalBuf[ i ] = 0;
220 nEvalOff = 0;
221 #endif
222 #endif
223 rec_recover = TRUE;
224 infile = NULL;
225 instring = inmacro = keepcomments = cflag = eflag = FALSE;
226 nflag = 0;
227 incend = incdir;
228 sharpfilename = NULL;
231 int MAIN(int argc, char** argv)
233 register int i;
234 char **useargv, **pfargv;
237 if( nRunde == 0 )
239 pCppIn = stdin;
240 pCppOut = stdout;
243 nRunde++;
244 InitCpp1();
245 InitCpp2();
246 InitCpp3();
247 InitCpp4();
248 InitCpp5();
249 InitCpp6();
251 #if HOST == SYS_VMS
252 argc = getredirection(argc, argv); /* vms >file and <file */
253 #endif
254 initdefines(); /* O.S. specific def's */
255 if ( argv[argc-1][0] == '@' )
257 i = readoptions( argv[1], &pfargv ); /* Command file */
258 useargv=pfargv;
260 else
262 i = dooptions(argc, argv); /* Command line -flags */
263 useargv=argv;
265 switch (i) {
266 #if OSL_DEBUG_LEVEL > 1
267 case 4:
268 if ( bDumpDefs )
271 * Get defBase file, "-" means use stdout.
273 if (!streq(useargv[3], "-")) {
274 #if HOST == SYS_VMS
276 * On vms, reopen stdout with "vanilla rms" attributes.
278 if ((i = creat(useargv[3], 0, "rat=cr", "rfm=var")) == -1
279 || dup2(i, fileno(stdout)) == -1) {
280 #else
281 pDefOut = fopen( useargv[3], "w" );
282 if( pDefOut == NULL ) {
283 #endif
284 perror(useargv[3]);
285 cerror("Can't open output file \"%s\"", useargv[3]);
286 exit(IO_ERROR);
288 } /* Continue by opening output */
290 #endif
291 case 3:
293 * Get output file, "-" means use stdout.
295 if (!streq(useargv[2], "-")) {
296 #if HOST == SYS_VMS
298 * On vms, reopen stdout with "vanilla rms" attributes.
300 if ((i = creat(useargv[2], 0, "rat=cr", "rfm=var")) == -1
301 || dup2(i, fileno(stdout)) == -1) {
302 #else
303 pCppOut = fopen( useargv[2], "w" );
304 if( pCppOut == NULL ) {
305 #endif
306 perror(useargv[2]);
307 cerror("Can't open output file \"%s\"", useargv[2]);
308 exit(IO_ERROR);
310 } /* Continue by opening input */
311 case 2: /* One file -> stdin */
313 * Open input file, "-" means use stdin.
315 if (!streq(useargv[1], "-")) {
316 pCppIn = fopen( useargv[1], "r" );
317 if( pCppIn == NULL) {
318 perror(useargv[1]);
319 cerror("Can't open input file \"%s\"", useargv[1]);
320 exit(IO_ERROR);
322 strcpy(work, useargv[1]); /* Remember input filename */
323 break;
324 } /* Else, just get stdin */
325 case 0: /* No args? */
326 case 1: /* No files, stdin -> stdout */
327 #if (HOST == SYS_UNIX) || (HOST == SYS_UNKNOWN)
328 work[0] = EOS; /* Unix can't find stdin name */
329 #else
330 fgetname(stdin, work); /* Vax-11C, Decus C know name */
331 #endif
332 break;
334 default:
335 exit(IO_ERROR); /* Can't happen */
338 setincdirs(); /* Setup -I include directories */
339 addfile( pCppIn, work); /* "open" main input file */
340 #if OSL_DEBUG_LEVEL > 1
341 if (debug > 0 || bDumpDefs)
342 dumpdef("preset #define symbols");
343 #endif
344 if( pCppIn != stdin )
345 rewind( pCppIn );
347 cppmain(); /* Process main file */
349 if ((i = (ifptr - &ifstack[0])) != 0) {
350 #if OLD_PREPROCESSOR
351 ciwarn("Inside #ifdef block at end of input, depth = %d", i);
352 #else
353 cierror("Inside #ifdef block at end of input, depth = %d", i);
354 #endif
356 #if OSL_DEBUG_LEVEL > 1
357 if( pDefOut != stdout && pDefOut != stderr )
358 fclose( pDefOut );
359 #endif
360 if( pCppOut != stdout && pCppOut != stderr )
361 fclose( pCppOut );
363 if (errors > 0) {
364 fprintf(stderr, (errors == 1)
365 ? "%d error in preprocessor\n"
366 : "%d errors in preprocessor\n", errors);
367 if (!eflag)
368 exit(IO_ERROR);
370 #ifdef NOMAIN /* BP */ /* kein exit im der LIB-Version */
371 return( IO_NORMAL );
372 #else
373 exit(IO_NORMAL); /* No errors or -E option set */
374 #endif
378 FILE_LOCAL
379 void cppmain()
381 * Main process for cpp -- copies tokens from the current input
382 * stream (main file, include file, or a macro) to the output
383 * file.
386 register int c; /* Current character */
387 register int counter; /* newlines and spaces */
390 * Explicitly output a #line at the start of cpp output so
391 * that lint (etc.) knows the name of the original source
392 * file. If we don't do this explicitly, we may get
393 * the name of the first #include file instead.
394 * We also seem to need a blank line following that first #line.
396 #ifdef EVALDEFS
397 if ( !bIsInEval )
398 #endif
400 sharp();
401 PUTCHAR('\n');
404 * This loop is started "from the top" at the beginning of each line
405 * wrongline is set TRUE in many places if it is necessary to write
406 * a #line record. (But we don't write them when expanding macros.)
408 * The counter variable has two different uses: at
409 * the start of a line, it counts the number of blank lines that
410 * have been skipped over. These are then either output via
411 * #line records or by outputting explicit blank lines.
412 * When expanding tokens within a line, the counter remembers
413 * whether a blank/tab has been output. These are dropped
414 * at the end of the line, and replaced by a single blank
415 * within lines.
417 for (;;) {
418 counter = 0; /* Count empty lines */
419 for (;;) { /* For each line, ... */
420 while (type[(c = get())] == SPA) /* Skip leading blanks */
421 ; /* in this line. */
422 if (c == '\n') /* If line's all blank, */
423 ++counter; /* Do nothing now */
424 else if (c == '#') { /* Is 1st non-space '#' */
425 keepcomments = FALSE; /* Don't pass comments */
426 counter = control(counter); /* Yes, do a #command */
427 keepcomments = (cflag && compiling);
429 else if (c == EOF_CHAR) /* At end of file? */
431 break;
433 else if (!compiling) { /* #ifdef false? */
434 skipnl(); /* Skip to newline */
435 counter++; /* Count it, too. */
437 else {
438 break; /* Actual token */
441 if (c == EOF_CHAR) /* Exit process at */
442 break; /* End of file */
444 * If the loop didn't terminate because of end of file, we
445 * know there is a token to compile. First, clean up after
446 * absorbing newlines. counter has the number we skipped.
448 if ((wrongline && infile->fp != NULL) || counter > 4)
449 sharp(); /* Output # line number */
450 else { /* If just a few, stuff */
451 while (--counter >= 0) /* them out ourselves */
452 PUTCHAR('\n');
455 * Process each token on this line.
457 unget(); /* Reread the char. */
458 for (;;) { /* For the whole line, */
459 do { /* Token concat. loop */
460 for (counter = 0; type[(c = get())] == SPA;) {
461 #if COMMENT_INVISIBLE
462 if (c != COM_SEP)
463 counter++;
464 #else
465 counter++; /* Skip over blanks */
466 #endif
468 if (c == EOF_CHAR || c == '\n')
469 goto end_line; /* Exit line loop */
470 else if (counter > 0) /* If we got any spaces */
471 PUTCHAR(' '); /* Output one space */
472 c = macroid(c); /* Grab the token */
473 } while (type[c] == LET && catenate());
474 if (c == EOF_CHAR || c == '\n') /* From macro exp error */
475 goto end_line; /* Exit line loop */
476 switch (type[c]) {
477 case LET:
478 fputs(token, pCppOut); /* Quite ordinary token */
479 #ifdef EVALDEFS
481 int len;
482 if ( bIsInEval
483 && nEvalOff + (len=strlen(token)) < NEVALBUF )
485 strcpy( &EvalBuf[nEvalOff], token );
486 nEvalOff += len;
489 #endif
490 break;
493 case DIG: /* Output a number */
494 case DOT: /* Dot may begin floats */
495 #ifdef EVALDEFS
496 if ( bIsInEval )
497 scannumber(c, outputEval);
498 else
499 scannumber(c, output);
500 #else
501 scannumber(c, output);
502 #endif
503 break;
505 case QUO: /* char or string const */
506 scanstring(c, output); /* Copy it to output */
507 break;
509 default: /* Some other character */
510 cput(c); /* Just output it */
511 #ifdef EVALDEFS
512 if ( bIsInEval && nEvalOff < NEVALBUF )
513 EvalBuf[nEvalOff++] = c;
514 #endif
515 break;
516 } /* Switch ends */
517 } /* Line for loop */
518 end_line: if (c == '\n') { /* Compiling at EOL? */
519 PUTCHAR('\n'); /* Output newline, if */
520 if (infile->fp == NULL) /* Expanding a macro, */
521 wrongline = TRUE; /* Output # line later */
523 } /* Continue until EOF */
524 #ifdef EVALDEFS
525 if ( bIsInEval )
526 EvalBuf[nEvalOff++] = '\0';
527 #endif
530 void output(int c)
532 * Output one character to stdout -- output() is passed as an
533 * argument to scanstring()
536 #if COMMENT_INVISIBLE
537 if (c != TOK_SEP && c != COM_SEP)
538 #else
539 if (c != TOK_SEP)
540 #endif
541 PUTCHAR(c);
544 #ifdef EVALDEFS
545 outputEval(c)
546 int c;
548 * Output one character to stdout -- output() is passed as an
549 * argument to scanstring()
552 #if COMMENT_INVISIBLE
553 if (c != TOK_SEP && c != COM_SEP)
554 #else
555 if (c != TOK_SEP)
556 #endif
558 PUTCHAR(c);
559 if ( bIsInEval && nEvalOff < NEVALBUF )
560 EvalBuf[nEvalOff++] = c;
563 #endif
566 FILE_LOCAL
567 void sharp()
569 * Output a line number line.
572 register char *name;
574 if (keepcomments) /* Make sure # comes on */
575 PUTCHAR('\n'); /* a fresh, new line. */
576 fprintf( pCppOut, "#%s %d", LINE_PREFIX, line);
577 if (infile->fp != NULL) {
578 name = (infile->progname != NULL)
579 ? infile->progname : infile->filename;
580 if (sharpfilename == NULL
581 || (sharpfilename != NULL && !streq(name, sharpfilename)) ) {
582 if (sharpfilename != NULL)
583 free(sharpfilename);
584 sharpfilename = savestring(name);
585 fprintf( pCppOut, " \"%s\"", name);
588 PUTCHAR('\n');
589 wrongline = FALSE;
592 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */