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