Branch data 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 : : #include <stdio.h>
20 : : #ifdef UNX
21 : : #include <stdlib.h>
22 : : #endif
23 : : #include <ctype.h>
24 : : #include "cppdef.h"
25 : : #include "cpp.h"
26 : :
27 : : #include "time.h" /* BP */
28 : :
29 : : #ifndef _STRING_H
30 : : #include <string.h>
31 : : #endif
32 : :
33 : : #ifndef _NO_PROTO
34 : : int AddInclude( char *pIncStr ); /* BP, 11.09.91, Forward-Deklaration */
35 : : #endif
36 : :
37 : : #if (OSL_DEBUG_LEVEL > 1) && (HOST == SYS_VMS || HOST == SYS_UNIX)
38 : : #include <signal.h>
39 : : #endif
40 : :
41 : 1320 : void InitCpp3()
42 : : {
43 : 1320 : }
44 : :
45 : :
46 : : int
47 : 69646 : openfile(char* filename)
48 : : /*
49 : : * Open a file, add it to the linked list of open files.
50 : : * This is called only from openfile() above.
51 : : */
52 : : {
53 : : register FILE *fp;
54 : :
55 [ + + ]: 69646 : if ((fp = fopen(filename, "r")) == NULL) {
56 : : #if OSL_DEBUG_LEVEL > 1
57 : : if ( debug || !bDumpDefs )
58 : : perror(filename);
59 : : #endif
60 : 50954 : return (FALSE);
61 : : }
62 : : #if OSL_DEBUG_LEVEL > 1
63 : : if (debug)
64 : : fprintf(stderr, "Reading from \"%s\"\n", filename);
65 : : #endif
66 : 18692 : addfile(fp, filename);
67 : 69646 : return (TRUE);
68 : : }
69 : :
70 : 20012 : void addfile(FILE* fp, char* filename)
71 : : /*
72 : : * Initialize tables for this open file. This is called from openfile()
73 : : * above (for #include files), and from the entry to cpp to open the main
74 : : * input file. It calls a common routine, getfile() to build the FILEINFO
75 : : * structure which is used to read characters. (getfile() is also called
76 : : * to setup a macro replacement.)
77 : : */
78 : : {
79 : : register FILEINFO *file;
80 : : extern FILEINFO *getfile( int, char * );
81 : 20012 : file = getfile(NBUFF, filename);
82 : 20012 : file->fp = fp; /* Better remember FILE * */
83 : 20012 : file->buffer[0] = EOS; /* Initialize for first read */
84 : 20012 : line = 1; /* Working on line 1 now */
85 : 20012 : wrongline = TRUE; /* Force out initial #line */
86 : 20012 : }
87 : :
88 : 1320 : void setincdirs()
89 : : /*
90 : : * Append system-specific directories to the include directory list.
91 : : * Called only when cpp is started.
92 : : */
93 : : {
94 : :
95 : : #ifdef CPP_INCLUDE
96 : : *incend++ = CPP_INCLUDE;
97 : : #define IS_INCLUDE 1
98 : : #else
99 : : #define IS_INCLUDE 0
100 : : #endif
101 : :
102 : : #if HOST == SYS_UNIX
103 : 1320 : *incend++ = "/usr/include";
104 : : #define MAXINCLUDE (NINCLUDE - 1 - IS_INCLUDE)
105 : : #endif
106 : :
107 : : #if HOST == SYS_VMS
108 : : extern char *getenv();
109 : :
110 : : if (getenv("C$LIBRARY") != NULL)
111 : : *incend++ = "C$LIBRARY:";
112 : : *incend++ = "SYS$LIBRARY:";
113 : : #define MAXINCLUDE (NINCLUDE - 2 - IS_INCLUDE)
114 : : #endif
115 : :
116 : : #if HOST == SYS_RSX
117 : : extern int $$rsts; /* TRUE on RSTS/E */
118 : : extern int $$pos; /* TRUE on PRO-350 P/OS */
119 : : extern int $$vms; /* TRUE on VMS compat. */
120 : :
121 : : if ($$pos) { /* P/OS? */
122 : : *incend++ = "SY:[ZZDECUSC]"; /* C #includes */
123 : : *incend++ = "LB:[1,5]"; /* RSX library */
124 : : }
125 : : else if ($$rsts) { /* RSTS/E? */
126 : : *incend++ = "SY:@"; /* User-defined account */
127 : : *incend++ = "C:"; /* Decus-C library */
128 : : *incend++ = "LB:[1,1]"; /* RSX library */
129 : : }
130 : : else if ($$vms) { /* VMS compatibility? */
131 : : *incend++ = "C:";
132 : : }
133 : : else { /* Plain old RSX/IAS */
134 : : *incend++ = "LB:[1,1]";
135 : : }
136 : : #define MAXINCLUDE (NINCLUDE - 3 - IS_INCLUDE)
137 : : #endif
138 : :
139 : : #if HOST == SYS_RT11
140 : : extern int $$rsts; /* RSTS/E emulation? */
141 : :
142 : : if ($$rsts)
143 : : *incend++ = "SY:@"; /* User-defined account */
144 : : *incend++ = "C:"; /* Decus-C library disk */
145 : : *incend++ = "SY:"; /* System (boot) disk */
146 : : #define MAXINCLUDE (NINCLUDE - 3 - IS_INCLUDE)
147 : : #endif
148 : :
149 : : #if HOST == SYS_UNKNOWN
150 : : /*
151 : : * Kontext: GenMake
152 : : * Unter DOS wird nun auch die Environment-Variable INCLUDE ausgewetet.
153 : : * Es kommt erschwerend hinzu, dass alle Eintraege, die mit ';' getrennt
154 : : * sind, mit in die Liste aufenommen werden muessen.
155 : : * Dies wird mit der Funktion strtok() realisiert.
156 : : * Vorsicht bei der Benutzung von malloc !!!
157 : : * In savestring wird naemlich getmem() verwendet. Vermutlich kommen sich
158 : : * die beiden Funktion in die Quere. Als ich malloc statt savestring
159 : : * verwendete knallte es in strcpy() !
160 : : */
161 : :
162 : : #if !defined( WNT ) && ! defined UNX
163 : : extern char *getenv( char *pStr ); /* BP */
164 : : #endif
165 : : char *pIncGetEnv = NULL; /* Pointer auf INCLUDE */
166 : :
167 : : if ( ( pIncGetEnv = getenv("INCLUDE") ) != NULL )
168 : : AddInclude( pIncGetEnv );
169 : :
170 : : #define MAXINCLUDE (NINCLUDE - 3 - IS_INCLUDE)
171 : : #endif
172 : :
173 : :
174 : 1320 : }
175 : :
176 : : /* Kontext: Erweiterung des INCLUDE-Services
177 : : * Bislang konnte der cpp keine Include-Angaben in der Kommandozeile
178 : : * vertragen, bei denen die directries mit ';' getrennt wurden.
179 : : * Dies ist auch verstaendlich, da dieses cpp fuer UNIX-Systeme
180 : : * massgeschneidert wurde und in UNI die ';' als Zeichen zum Abschluss
181 : : * von Kommandos gilt.
182 : : */
183 : :
184 : 20000 : int AddInclude( char* pIncStr )
185 : : {
186 : 20000 : char *pIncEnv = NULL; /* Kopie des INCLUDE */
187 : : char *pIncPos; /* wandert zum naechsten */
188 : :
189 : 20000 : pIncEnv = savestring( pIncStr );
190 : 20000 : pIncPos = strtok( pIncEnv, ";" );
191 : :
192 [ + + ]: 40000 : while( pIncPos != NULL )
193 : : {
194 [ - + ]: 20000 : if (incend >= &incdir[MAXINCLUDE])
195 : 0 : cfatal("Too many include directories", NULLST);
196 : 20000 : *incend++ = pIncPos;
197 : 20000 : pIncPos = strtok( NULL, ";" );
198 : : }
199 : 20000 : return( 1 );
200 : : }
201 : :
202 : : int
203 : 1320 : dooptions(int argc, char** argv)
204 : : /*
205 : : * dooptions is called to process command line arguments (-Detc).
206 : : * It is called only at cpp startup.
207 : : */
208 : : {
209 : : register char *ap;
210 : : register DEFBUF *dp;
211 : : register int c;
212 : : int i, j;
213 : : char *arg;
214 : : SIZES *sizp; /* For -S */
215 : : int size; /* For -S */
216 : : int isdatum; /* FALSE for -S* */
217 : : int endtest; /* For -S */
218 : :
219 [ + + ]: 49040 : for (i = j = 1; i < argc; i++) {
220 : 47720 : arg = ap = argv[i];
221 : :
222 [ + + ][ - + ]: 47720 : if (*ap++ != '-' || *ap == EOS)
223 : : {
224 : 2640 : argv[j++] = argv[i];
225 : : }
226 : : else {
227 : 45080 : c = *ap++; /* Option byte */
228 [ - + ]: 45080 : if (islower(c)) /* Normalize case */
229 : 0 : c = toupper(c);
230 [ - + - + : 45080 : switch (c) { /* Command character */
- - - - ]
231 : : case 'C': /* Keep comments */
232 : 0 : cflag = TRUE;
233 : 0 : keepcomments = TRUE;
234 : 0 : break;
235 : :
236 : : case 'D': /* Define symbol */
237 : : /*
238 : : * If the option is just "-Dfoo", make it -Dfoo=1
239 : : */
240 [ + + ][ + + ]: 267960 : while (*ap != EOS && *ap != '=')
241 : 242880 : ap++;
242 [ + + ]: 25080 : if (*ap == EOS)
243 : 19800 : ap = "1";
244 : : else
245 : 5280 : *ap++ = EOS;
246 : : /*
247 : : * Now, save the word and its definition.
248 : : */
249 : 25080 : dp = defendel(argv[i] + 2, FALSE);
250 : 25080 : dp->repl = savestring(ap);
251 : 25080 : dp->nargs = DEF_NOARGS;
252 : 25080 : break;
253 : :
254 : : case 'E': /* Ignore non-fatal */
255 : 0 : eflag = TRUE; /* errors. */
256 : 0 : break;
257 : :
258 : : case 'I': /* Include directory */
259 : 20000 : AddInclude( ap ); /* BP, 11.09.91 */
260 : 20000 : break;
261 : :
262 : : case 'N': /* No predefineds */
263 : 0 : nflag++; /* Repeat to undefine */
264 : 0 : break; /* __LINE__, etc. */
265 : :
266 : : case 'S':
267 : 0 : sizp = size_table;
268 [ # # ]: 0 : if (0 != (isdatum = (*ap != '*'))) /* If it's just -S, */
269 : 0 : endtest = T_FPTR; /* Stop here */
270 : : else { /* But if it's -S* */
271 : 0 : ap++; /* Step over '*' */
272 : 0 : endtest = 0; /* Stop at end marker */
273 : : }
274 [ # # ][ # # ]: 0 : while (sizp->bits != endtest && *ap != EOS) {
275 [ # # ]: 0 : if (!isdigit(*ap)) { /* Skip to next digit */
276 : 0 : ap++;
277 : 0 : continue;
278 : : }
279 : 0 : size = 0; /* Compile the value */
280 [ # # ]: 0 : while (isdigit(*ap)) {
281 : 0 : size *= 10;
282 : 0 : size += (*ap++ - '0');
283 : : }
284 [ # # ]: 0 : if (isdatum)
285 : 0 : sizp->size = size; /* Datum size */
286 : : else
287 : 0 : sizp->psize = size; /* Pointer size */
288 : 0 : sizp++;
289 : : }
290 [ # # ]: 0 : if (sizp->bits != endtest)
291 : 0 : cwarn("-S, too few values specified in %s", argv[i]);
292 [ # # ]: 0 : else if (*ap != EOS)
293 : 0 : cwarn("-S, too many values, \"%s\" unused", ap);
294 : 0 : break;
295 : :
296 : : case 'U': /* Undefine symbol */
297 [ # # ]: 0 : if (defendel(ap, TRUE) == NULL)
298 : 0 : cwarn("\"%s\" wasn't defined", ap);
299 : 0 : break;
300 : :
301 : : #if OSL_DEBUG_LEVEL > 1
302 : : case 'X': /* Debug */
303 : : debug = (isdigit(*ap)) ? atoi(ap) : 1;
304 : : #if (HOST == SYS_VMS || HOST == SYS_UNIX)
305 : : signal(SIGINT, (void (*)(int)) abort); /* Trap "interrupt" */
306 : : #endif
307 : : fprintf(stderr, "Debug set to %d\n", debug);
308 : : break;
309 : : #endif
310 : :
311 : : #if OSL_DEBUG_LEVEL > 1
312 : : case 'P': /* #define's dump */
313 : : bDumpDefs = 1;
314 : : fprintf(stderr, "Dump #define's is on\n");
315 : : break;
316 : : #endif
317 : :
318 : : default: /* What is this one? */
319 : 0 : cwarn("Unknown option \"%s\"", arg);
320 : 0 : fprintf(stderr, "The following options are valid:\n\
321 : : -C\t\t\tWrite source file comments to output\n\
322 : : -Dsymbol=value\tDefine a symbol with the given (optional) value\n\
323 : : -Idirectory\t\tAdd a directory to the #include search list\n\
324 : : -N\t\t\tDon't predefine target-specific names\n\
325 : : -Stext\t\tSpecify sizes for #if sizeof\n\
326 : : -Usymbol\t\tUndefine symbol\n");
327 : : #if OSL_DEBUG_LEVEL > 1
328 : : fprintf(stderr, " -Xvalue\t\tSet internal debug flag\n");
329 : : fprintf(stderr, " -P\t\t\tdump #define's\n");
330 : : #endif
331 : 0 : break;
332 : : } /* Switch on all options */
333 : : } /* If it's a -option */
334 : : } /* For all arguments */
335 : : #if OSL_DEBUG_LEVEL > 1
336 : : if ( (bDumpDefs ? j > 4 : j > 3) ) {
337 : : #else
338 [ - + ]: 1320 : if (j > 3) {
339 : : #endif
340 : 0 : cerror(
341 : : "Too many file arguments. Usage: cpp [input [output]]",
342 : : NULLST);
343 : : }
344 : 1320 : return (j); /* Return new argc */
345 : : }
346 : :
347 : : int
348 : 1320 : readoptions(char* filename, char*** pfargv)
349 : : {
350 : : FILE *fp;
351 : : int c;
352 : 1320 : int bInQuotes = 0;
353 : : char optbuff[1024], *poptbuff;
354 : 1320 : int fargc=0, back;
355 : : char *fargv[PARALIMIT], **pfa;
356 : :
357 : 1320 : pfa=*pfargv=malloc(sizeof(fargv));
358 : :
359 : 1320 : poptbuff=&optbuff[0];
360 : 1320 : filename++;
361 [ - + ]: 1320 : if ((fp = fopen(filename, "r")) == NULL) {
362 : : #if OSL_DEBUG_LEVEL > 1
363 : : if ( debug || !bDumpDefs )
364 : : perror(filename);
365 : : #endif
366 : 0 : return (FALSE);
367 : : }
368 : : do
369 : : {
370 : : /*
371 : : * #i27914# double ticks '"' now have a duplicate function:
372 : : * 1. they define a string ( e.g. -DFOO="baz" )
373 : : * 2. a string can contain spaces, so -DFOO="baz zum" defines one
374 : : * argument no two !
375 : : */
376 : 1438950 : c=fgetc(fp);
377 [ + - ][ + - ]: 1438950 : if ( c != ' ' && c != CR && c != NL && c != HT && c != EOF)
[ + - ][ + + ]
[ + + ]
378 : : {
379 : 1389910 : *poptbuff++=(char)c;
380 [ - + ]: 1389910 : if( c == '"' )
381 : 0 : bInQuotes = ~bInQuotes;
382 : : }
383 : : else
384 : : {
385 [ + + ][ - + ]: 49040 : if( c != EOF && bInQuotes )
386 : 0 : *poptbuff++=(char)c;
387 : : else
388 : : {
389 : 49040 : *poptbuff=EOS;
390 [ + + ]: 49040 : if (strlen(optbuff)>0)
391 : : {
392 : 47720 : pfa[fargc+1]=malloc(strlen(optbuff)+1);
393 : 47720 : strcpy(pfa[fargc+1],optbuff);
394 : 47720 : fargc++;
395 : 47720 : pfa[fargc+1]=0;
396 : 47720 : poptbuff=&optbuff[0];
397 : : }
398 : : }
399 : : }
400 : : }
401 [ + + ]: 1438950 : while ( c != EOF );
402 : :
403 : 1320 : fclose(fp);
404 : 1320 : back=dooptions(fargc+1,pfa);
405 : :
406 : 1320 : return (back);
407 : : }
408 : :
409 : : #if HOST != SYS_UNIX
410 : : FILE_LOCAL void
411 : : zap_uc(char* ap)
412 : : /*
413 : : * Dec operating systems mangle upper-lower case in command lines.
414 : : * This routine forces the -D and -U arguments to uppercase.
415 : : * It is called only on cpp startup by dooptions().
416 : : */
417 : : {
418 : : while (*ap != EOS) {
419 : : /*
420 : : * Don't use islower() here so it works with Multinational
421 : : */
422 : : if (*ap >= 'a' && *ap <= 'z')
423 : : *ap = (char)toupper(*ap);
424 : : ap++;
425 : : }
426 : : }
427 : : #endif
428 : :
429 : 1320 : void initdefines()
430 : : /*
431 : : * Initialize the built-in #define's. There are two flavors:
432 : : * #define decus 1 (static definitions)
433 : : * #define __FILE__ ?? (dynamic, evaluated by magic)
434 : : * Called only on cpp startup.
435 : : *
436 : : * Note: the built-in static definitions are supressed by the -N option.
437 : : * __LINE__, __FILE__, and __DATE__ are always present.
438 : : */
439 : : {
440 : : register char **pp;
441 : : register char *tp;
442 : : register DEFBUF *dp;
443 : : int i;
444 : : time_t tvec;
445 : :
446 : : #if !defined( WNT ) && !defined(G3)
447 : : extern char *ctime();
448 : : #endif
449 : :
450 : : /*
451 : : * Predefine the built-in symbols. Allow the
452 : : * implementor to pre-define a symbol as "" to
453 : : * eliminate it.
454 : : */
455 [ + - ]: 1320 : if (nflag == 0) {
456 [ + + ]: 2640 : for (pp = preset; *pp != NULL; pp++) {
457 [ + - ]: 1320 : if (*pp[0] != EOS) {
458 : 1320 : dp = defendel(*pp, FALSE);
459 : 1320 : dp->repl = savestring("1");
460 : 1320 : dp->nargs = DEF_NOARGS;
461 : : }
462 : : }
463 : : }
464 : : /*
465 : : * The magic pre-defines (__FILE__ and __LINE__ are
466 : : * initialized with negative argument counts. expand()
467 : : * notices this and calls the appropriate routine.
468 : : * DEF_NOARGS is one greater than the first "magic" definition.
469 : : */
470 [ + - ]: 1320 : if (nflag < 2) {
471 [ + + ]: 3960 : for (pp = magic, i = DEF_NOARGS; *pp != NULL; pp++) {
472 : 2640 : dp = defendel(*pp, FALSE);
473 : 2640 : dp->nargs = --i;
474 : : }
475 : : #if OK_DATE
476 : : /*
477 : : * Define __DATE__ as today's date.
478 : : */
479 : 1320 : dp = defendel("__DATE__", FALSE);
480 : 1320 : dp->repl = tp = getmem(27);
481 : 1320 : dp->nargs = DEF_NOARGS;
482 : 1320 : time( &tvec);
483 : 1320 : *tp++ = '"';
484 : 1320 : strcpy(tp, ctime(&tvec));
485 : 1320 : tp[24] = '"'; /* Overwrite newline */
486 : : #endif
487 : : }
488 : 1320 : }
489 : :
490 : : #if HOST == SYS_VMS
491 : : /*
492 : : * getredirection() is intended to aid in porting C programs
493 : : * to VMS (Vax-11 C) which does not support '>' and '<'
494 : : * I/O redirection. With suitable modification, it may
495 : : * useful for other portability problems as well.
496 : : */
497 : :
498 : : int
499 : : getredirection(argc, argv)
500 : : int argc;
501 : : char **argv;
502 : : /*
503 : : * Process vms redirection arg's. Exit if any error is seen.
504 : : * If getredirection() processes an argument, it is erased
505 : : * from the vector. getredirection() returns a new argc value.
506 : : *
507 : : * Warning: do not try to simplify the code for vms. The code
508 : : * presupposes that getredirection() is called before any data is
509 : : * read from stdin or written to stdout.
510 : : *
511 : : * Normal usage is as follows:
512 : : *
513 : : * main(argc, argv)
514 : : * int argc;
515 : : * char *argv[];
516 : : * {
517 : : * argc = getredirection(argc, argv);
518 : : * }
519 : : */
520 : : {
521 : : register char *ap; /* Argument pointer */
522 : : int i; /* argv[] index */
523 : : int j; /* Output index */
524 : : int file; /* File_descriptor */
525 : : extern int errno; /* Last vms i/o error */
526 : :
527 : : for (j = i = 1; i < argc; i++) { /* Do all arguments */
528 : : switch (*(ap = argv[i])) {
529 : : case '<': /* <file */
530 : : if (freopen(++ap, "r", stdin) == NULL) {
531 : : perror(ap); /* Can't find file */
532 : : exit(errno); /* Is a fatal error */
533 : : }
534 : : break;
535 : :
536 : : case '>': /* >file or >>file */
537 : : if (*++ap == '>') { /* >>file */
538 : : /*
539 : : * If the file exists, and is writable by us,
540 : : * call freopen to append to the file (using the
541 : : * file's current attributes). Otherwise, create
542 : : * a new file with "vanilla" attributes as if the
543 : : * argument was given as ">filename".
544 : : * access(name, 2) returns zero if we can write on
545 : : * the specified file.
546 : : */
547 : : if (access(++ap, 2) == 0) {
548 : : if (freopen(ap, "a", stdout) != NULL)
549 : : break; /* Exit case statement */
550 : : perror(ap); /* Error, can't append */
551 : : exit(errno); /* After access test */
552 : : } /* If file accessable */
553 : : }
554 : : /*
555 : : * On vms, we want to create the file using "standard"
556 : : * record attributes. creat(...) creates the file
557 : : * using the caller's default protection mask and
558 : : * "variable length, implied carriage return"
559 : : * attributes. dup2() associates the file with stdout.
560 : : */
561 : : if ((file = creat(ap, 0, "rat=cr", "rfm=var")) == -1
562 : : || dup2(file, fileno(stdout)) == -1) {
563 : : perror(ap); /* Can't create file */
564 : : exit(errno); /* is a fatal error */
565 : : } /* If '>' creation */
566 : : break; /* Exit case test */
567 : :
568 : : default:
569 : : argv[j++] = ap; /* Not a redirector */
570 : : break; /* Exit case test */
571 : : }
572 : : } /* For all arguments */
573 : : argv[j] = NULL; /* Terminate argv[] */
574 : : return (j); /* Return new argc */
575 : : }
576 : : #endif
577 : :
578 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|