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 630 : void InitCpp3()
42 : {
43 630 : }
44 :
45 :
46 : int
47 32565 : 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 32565 : if ((fp = fopen(filename, "r")) == NULL) {
56 : #if OSL_DEBUG_LEVEL > 1
57 : if ( debug || !bDumpDefs )
58 : perror(filename);
59 : #endif
60 23786 : return (FALSE);
61 : }
62 : #if OSL_DEBUG_LEVEL > 1
63 : if (debug)
64 : fprintf(stderr, "Reading from \"%s\"\n", filename);
65 : #endif
66 8779 : addfile(fp, filename);
67 8779 : return (TRUE);
68 : }
69 :
70 9409 : 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 9409 : file = getfile(NBUFF, filename);
82 9409 : file->fp = fp; /* Better remember FILE * */
83 9409 : file->buffer[0] = EOS; /* Initialize for first read */
84 9409 : line = 1; /* Working on line 1 now */
85 9409 : wrongline = TRUE; /* Force out initial #line */
86 9409 : }
87 :
88 630 : 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 630 : *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 630 : }
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 9323 : int AddInclude( char* pIncStr )
185 : {
186 9323 : char *pIncEnv = NULL; /* Kopie des INCLUDE */
187 : char *pIncPos; /* wandert zum naechsten */
188 :
189 9323 : pIncEnv = savestring( pIncStr );
190 9323 : pIncPos = strtok( pIncEnv, ";" );
191 :
192 27969 : while( pIncPos != NULL )
193 : {
194 9323 : if (incend >= &incdir[MAXINCLUDE])
195 0 : cfatal("Too many include directories", NULLST);
196 9323 : *incend++ = pIncPos;
197 9323 : pIncPos = strtok( NULL, ";" );
198 : }
199 9323 : return( 1 );
200 : }
201 :
202 : int
203 630 : 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 20663 : for (i = j = 1; i < argc; i++) {
220 20033 : arg = ap = argv[i];
221 :
222 20033 : if (*ap++ != '-' || *ap == EOS)
223 : {
224 1260 : argv[j++] = argv[i];
225 : }
226 : else {
227 18773 : c = *ap++; /* Option byte */
228 18773 : if (islower(c)) /* Normalize case */
229 0 : c = toupper(c);
230 18773 : 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 88830 : while (*ap != EOS && *ap != '=')
241 69930 : ap++;
242 9450 : if (*ap == EOS)
243 7560 : ap = "1";
244 : else
245 1890 : *ap++ = EOS;
246 : /*
247 : * Now, save the word and its definition.
248 : */
249 9450 : dp = defendel(argv[i] + 2, FALSE);
250 9450 : dp->repl = savestring(ap);
251 9450 : dp->nargs = DEF_NOARGS;
252 9450 : break;
253 :
254 : case 'E': /* Ignore non-fatal */
255 0 : eflag = TRUE; /* errors. */
256 0 : break;
257 :
258 : case 'I': /* Include directory */
259 9323 : AddInclude( ap ); /* BP, 11.09.91 */
260 9323 : 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 630 : if (j > 3) {
339 : #endif
340 0 : cerror(
341 : "Too many file arguments. Usage: cpp [input [output]]",
342 : NULLST);
343 : }
344 630 : return (j); /* Return new argc */
345 : }
346 :
347 : int
348 630 : readoptions(char* filename, char*** pfargv)
349 : {
350 : FILE *fp;
351 : int c;
352 630 : int bInQuotes = 0;
353 : char optbuff[1024], *poptbuff;
354 630 : int fargc=0, back;
355 : char *fargv[PARALIMIT], **pfa;
356 :
357 630 : pfa=*pfargv=malloc(sizeof(fargv));
358 :
359 630 : poptbuff=&optbuff[0];
360 630 : filename++;
361 630 : 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 593294 : c=fgetc(fp);
377 593294 : if ( c != ' ' && c != CR && c != NL && c != HT && c != EOF)
378 : {
379 572631 : *poptbuff++=(char)c;
380 1145262 : if( c == '"' )
381 0 : bInQuotes = ~bInQuotes;
382 : }
383 : else
384 : {
385 20663 : if( c != EOF && bInQuotes )
386 0 : *poptbuff++=(char)c;
387 : else
388 : {
389 20663 : *poptbuff=EOS;
390 20663 : if (strlen(optbuff)>0)
391 : {
392 20033 : pfa[fargc+1]=malloc(strlen(optbuff)+1);
393 20033 : strcpy(pfa[fargc+1],optbuff);
394 20033 : fargc++;
395 20033 : pfa[fargc+1]=0;
396 20033 : poptbuff=&optbuff[0];
397 : }
398 : }
399 : }
400 : }
401 593294 : while ( c != EOF );
402 :
403 630 : fclose(fp);
404 630 : back=dooptions(fargc+1,pfa);
405 :
406 630 : 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 630 : 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 630 : if (nflag == 0) {
456 1260 : for (pp = preset; *pp != NULL; pp++) {
457 630 : if (*pp[0] != EOS) {
458 630 : dp = defendel(*pp, FALSE);
459 630 : dp->repl = savestring("1");
460 630 : 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 630 : if (nflag < 2) {
471 1890 : for (pp = magic, i = DEF_NOARGS; *pp != NULL; pp++) {
472 1260 : dp = defendel(*pp, FALSE);
473 1260 : dp->nargs = --i;
474 : }
475 : #if OK_DATE
476 : /*
477 : * Define __DATE__ as today's date.
478 : */
479 630 : dp = defendel("__DATE__", FALSE);
480 630 : dp->repl = tp = getmem(27);
481 630 : dp->nargs = DEF_NOARGS;
482 630 : time( &tvec);
483 630 : *tp++ = '"';
484 630 : strcpy(tp, ctime(&tvec));
485 630 : tp[24] = '"'; /* Overwrite newline */
486 : #endif
487 : }
488 630 : }
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: */
|