update dev300-m57
[ooovba.git] / rsc / source / rscpp / cpp2.c
blob7bb1deb8ec1d0950b5f918a611442b1d9094a5e7
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: cpp2.c,v $
10 * $Revision: 1.6 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include <stdio.h>
32 #include <ctype.h>
33 #include "cppdef.h"
34 #include "cpp.h"
35 #if HOST == SYS_VMS
37 * Include the rms stuff. (We can't just include rms.h as it uses the
38 * VaxC-specific library include syntax that Decus CPP doesn't support.
39 * By including things by hand, we can CPP ourself.)
41 #include <nam.h>
42 #include <fab.h>
43 #include <rab.h>
44 #include <rmsdef.h>
45 #endif
48 * Generate (by hand-inspection) a set of unique values for each control
49 * operator. Note that this is not guaranteed to work for non-Ascii
50 * machines. CPP won't compile if there are hash conflicts.
53 #define L_assert ('a' + ('s' << 1))
54 #define L_define ('d' + ('f' << 1))
55 #define L_elif ('e' + ('i' << 1))
56 #define L_else ('e' + ('s' << 1))
57 #define L_endif ('e' + ('d' << 1))
58 #define L_if ('i' + (EOS << 1))
59 #define L_ifdef ('i' + ('d' << 1))
60 #define L_ifndef ('i' + ('n' << 1))
61 #define L_include ('i' + ('c' << 1))
62 #define L_line ('l' + ('n' << 1))
63 #define L_nogood (EOS + (EOS << 1)) /* To catch #i */
64 #define L_pragma ('p' + ('a' << 1))
65 #define L_undef ('u' + ('d' << 1))
66 #define L_error ('e' + ('r' << 1)) /* BP 5.3.92, #error */
67 #define MAXLINE 80 /* BP 5.3.92, #error */
68 #if OSL_DEBUG_LEVEL > 1
69 #define L_debug ('d' + ('b' << 1)) /* #debug */
70 #define L_nodebug ('n' + ('d' << 1)) /* #nodebug */
71 #endif
74 void InitCpp2()
80 int
81 control(int counter)
83 * Process #control lines. Simple commands are processed inline,
84 * while complex commands have their own subroutines.
86 * The counter is used to force out a newline before #line, and
87 * #pragma commands. This prevents these commands from ending up at
88 * the end of the previous line if cpp is invoked with the -C option.
91 register int c;
92 register char *tp;
93 register int hash;
94 char *ep;
96 c = skipws();
97 if (c == '\n' || c == EOF_CHAR)
98 return (counter + 1);
99 if (!isdigit(c))
100 scanid(c); /* Get #word to token[] */
101 else {
102 unget(); /* Hack -- allow #123 as a */
103 strcpy(token, "line"); /* synonym for #line 123 */
105 hash = (token[1] == EOS) ? L_nogood : (token[0] + (token[2] << 1));
106 switch (hash) {
107 case L_assert: tp = "assert"; break;
108 case L_define: tp = "define"; break;
109 case L_elif: tp = "elif"; break;
110 case L_else: tp = "else"; break;
111 case L_endif: tp = "endif"; break;
112 case L_if: tp = "if"; break;
113 case L_ifdef: tp = "ifdef"; break;
114 case L_ifndef: tp = "ifndef"; break;
115 case L_include: tp = "include"; break;
116 case L_line: tp = "line"; break;
117 case L_pragma: tp = "pragma"; break;
118 case L_undef: tp = "undef"; break;
119 case L_error: tp = "error"; break;
120 #if OSL_DEBUG_LEVEL > 1
121 case L_debug: tp = "debug"; break;
122 case L_nodebug: tp = "nodebug"; break;
123 #endif
124 default: hash = L_nogood;
125 case L_nogood: tp = ""; break;
127 if (!streq(tp, token))
128 hash = L_nogood;
130 * hash is set to a unique value corresponding to the
131 * control keyword (or L_nogood if we think it's nonsense).
133 if (infile->fp == NULL)
134 cwarn("Control line \"%s\" within macro expansion", token);
135 if (!compiling) { /* Not compiling now */
136 switch (hash) {
137 case L_if: /* These can't turn */
138 case L_ifdef: /* compilation on, but */
139 case L_ifndef: /* we must nest #if's */
140 if (++ifptr >= &ifstack[BLK_NEST])
141 goto if_nest_err;
142 *ifptr = 0; /* !WAS_COMPILING */
143 case L_line: /* Many */
145 * Are pragma's always processed?
147 case L_pragma: /* options */
148 case L_include: /* are uninteresting */
149 case L_define: /* if we */
150 case L_undef: /* aren't */
151 case L_assert: /* compiling. */
152 case L_error: /* BP 5.3.92, #error */
153 dump_line: skipnl(); /* Ignore rest of line */
154 return (counter + 1);
158 * Make sure that #line and #pragma are output on a fresh line.
160 if (counter > 0 && (hash == L_line || hash == L_pragma)) {
161 PUTCHAR('\n');
162 counter--;
164 switch (hash) {
165 case L_line:
167 * Parse the line to update the line number and "progname"
168 * field and line number for the next input line.
169 * Set wrongline to force it out later.
171 c = skipws();
172 workp = work; /* Save name in work */
173 while (c != '\n' && c != EOF_CHAR) {
174 save(c);
175 c = get();
177 unget();
178 save(EOS);
180 * Split #line argument into <line-number> and <name>
181 * We subtract 1 as we want the number of the next line.
183 line = atoi(work) - 1; /* Reset line number */
184 for (tp = work; isdigit(*tp) || type[(int)*tp] == SPA; tp++)
185 ; /* Skip over digits */
186 if (*tp != EOS) { /* Got a filename, so: */
187 if (*tp == '"' && (ep = strrchr(tp + 1, '"')) != NULL) {
188 tp++; /* Skip over left quote */
189 *ep = EOS; /* And ignore right one */
191 if (infile->progname != NULL) /* Give up the old name */
192 free(infile->progname); /* if it's allocated. */
193 infile->progname = savestring(tp);
195 wrongline = TRUE; /* Force output later */
196 break;
198 case L_include:
199 doinclude();
200 break;
202 case L_define:
203 dodefine();
204 break;
206 case L_undef:
207 doundef();
208 break;
210 case L_else:
211 if (ifptr == &ifstack[0])
212 goto nest_err;
213 else if ((*ifptr & ELSE_SEEN) != 0)
214 goto else_seen_err;
215 *ifptr |= ELSE_SEEN;
216 if ((*ifptr & WAS_COMPILING) != 0) {
217 if (compiling || (*ifptr & TRUE_SEEN) != 0)
218 compiling = FALSE;
219 else {
220 compiling = TRUE;
223 break;
225 case L_elif:
226 if (ifptr == &ifstack[0])
227 goto nest_err;
228 else if ((*ifptr & ELSE_SEEN) != 0) {
229 else_seen_err: cerror("#%s may not follow #else", token);
230 goto dump_line;
232 if ((*ifptr & (WAS_COMPILING | TRUE_SEEN)) != WAS_COMPILING) {
233 compiling = FALSE; /* Done compiling stuff */
234 goto dump_line; /* Skip this clause */
236 doif(L_if);
237 break;
239 case L_if:
240 case L_ifdef:
241 case L_ifndef:
242 if (++ifptr >= &ifstack[BLK_NEST])
243 if_nest_err: cfatal("Too many nested #%s statements", token);
244 *ifptr = WAS_COMPILING;
245 doif(hash);
246 break;
248 case L_endif:
249 if (ifptr == &ifstack[0]) {
250 nest_err: cerror("#%s must be in an #if", token);
251 goto dump_line;
253 if (!compiling && (*ifptr & WAS_COMPILING) != 0)
254 wrongline = TRUE;
255 compiling = ((*ifptr & WAS_COMPILING) != 0);
256 --ifptr;
257 break;
259 case L_assert:
260 if (eval() == 0)
261 cerror("Preprocessor assertion failure", NULLST);
262 break;
264 case L_pragma:
266 * #pragma is provided to pass "options" to later
267 * passes of the compiler. cpp doesn't have any yet.
269 fprintf( pCppOut, "#pragma ");
270 while ((c = get()) != '\n' && c != EOF_CHAR)
271 cput(c);
272 unget();
273 break;
275 #if OSL_DEBUG_LEVEL > 1
276 case L_debug:
277 if (debug == 0)
278 dumpdef("debug set on");
279 debug++;
280 break;
282 case L_nodebug:
283 debug--;
284 break;
285 #endif
286 case L_error: /* BP 5.3.92, #error */
288 fprintf( pCppOut, "cpp: line %u, Error directive: ", line );
289 while ((c = get()) != '\n' && c != EOF_CHAR)
290 cput(c);
291 fprintf( pCppOut, "\n" );
292 exit( 1 );
293 break;
295 default:
297 * Undefined #control keyword.
298 * Note: the correct behavior may be to warn and
299 * pass the line to a subsequent compiler pass.
300 * This would allow #asm or similar extensions.
302 cerror("Illegal # command \"%s\"", token);
303 break;
305 if (hash != L_include) {
306 #if OLD_PREPROCESSOR
308 * Ignore the rest of the #control line so you can write
309 * #if foo
310 * #endif foo
312 goto dump_line; /* Take common exit */
313 #else
314 if (skipws() != '\n') {
315 cwarn("Unexpected text in #control line ignored", NULLST);
316 skipnl();
318 #endif
320 return (counter + 1);
323 FILE_LOCAL
324 void doif(int hash)
326 * Process an #if, #ifdef, or #ifndef. The latter two are straightforward,
327 * while #if needs a subroutine of its own to evaluate the expression.
329 * doif() is called only if compiling is TRUE. If false, compilation
330 * is always supressed, so we don't need to evaluate anything. This
331 * supresses unnecessary warnings.
334 register int c;
335 register int found;
337 if ((c = skipws()) == '\n' || c == EOF_CHAR) {
338 unget();
339 goto badif;
341 if (hash == L_if) {
342 unget();
343 found = (eval() != 0); /* Evaluate expr, != 0 is TRUE */
344 hash = L_ifdef; /* #if is now like #ifdef */
346 else {
347 if (type[c] != LET) /* Next non-blank isn't letter */
348 goto badif; /* ... is an error */
349 found = (lookid(c) != NULL); /* Look for it in symbol table */
351 if (found == (hash == L_ifdef)) {
352 compiling = TRUE;
353 *ifptr |= TRUE_SEEN;
355 else {
356 compiling = FALSE;
358 return;
360 badif: cerror("#if, #ifdef, or #ifndef without an argument", NULLST);
361 #if !OLD_PREPROCESSOR
362 skipnl(); /* Prevent an extra */
363 unget(); /* Error message */
364 #endif
365 return;
368 FILE_LOCAL
369 void doinclude()
371 * Process the #include control line.
372 * There are three variations:
373 * #include "file" search somewhere relative to the
374 * current source file, if not found,
375 * treat as #include <file>.
376 * #include <file> Search in an implementation-dependent
377 * list of places.
378 * #include token Expand the token, it must be one of
379 * "file" or <file>, process as such.
381 * Note: the November 12 draft forbids '>' in the #include <file> format.
382 * This restriction is unnecessary and not implemented.
385 register int c;
386 register int delim;
387 #if HOST == SYS_VMS
388 char def_filename[NAM$C_MAXRSS + 1];
389 #endif
391 delim = macroid(skipws());
392 if (delim != '<' && delim != '"')
393 goto incerr;
394 if (delim == '<')
395 delim = '>';
396 workp = work;
397 instring = TRUE; /* Accept all characters */
398 #ifdef CONTROL_COMMENTS_NOT_ALLOWED
399 while ((c = get()) != '\n' && c != EOF_CHAR)
400 save(c); /* Put it away. */
401 unget(); /* Force nl after includee */
403 * The draft is unclear if the following should be done.
405 while (--workp >= work && *workp == ' ')
406 ; /* Trim blanks from filename */
407 if (*workp != delim)
408 goto incerr;
409 #else
410 while ((c = get()) != delim && c != EOF_CHAR)
411 save(c);
412 #endif
413 *workp = EOS; /* Terminate filename */
414 instring = FALSE;
415 #if HOST == SYS_VMS
417 * Assume the default .h filetype.
419 if (!vmsparse(work, ".H", def_filename)) {
420 perror(work); /* Oops. */
421 goto incerr;
423 else if (openinclude(def_filename, (delim == '"')))
424 return;
425 #else
426 if (openinclude(work, (delim == '"')))
427 return;
428 #endif
430 * No sense continuing if #include file isn't there.
432 cfatal("Cannot open include file \"%s\"", work);
434 incerr: cerror("#include syntax error", NULLST);
435 return;
438 FILE_LOCAL int
439 openinclude(char* filename, int searchlocal)
441 * Actually open an include file. This routine is only called from
442 * doinclude() above, but was written as a separate subroutine for
443 * programmer convenience. It searches the list of directories
444 * and actually opens the file, linking it into the list of
445 * active files. Returns TRUE if the file was opened, FALSE
446 * if openinclude() fails. No error message is printed.
449 register char **incptr;
450 #if HOST == SYS_VMS
451 #if NFWORK < (NAM$C_MAXRSS + 1)
452 << error, NFWORK is not greater than NAM$C_MAXRSS >>
453 #endif
454 #endif
455 char tmpname[NFWORK]; /* Filename work area */
457 if (searchlocal) {
459 * Look in local directory first
461 #if HOST == SYS_UNIX
463 * Try to open filename relative to the directory of the current
464 * source file (as opposed to the current directory). (ARF, SCK).
466 if (filename[0] != '/'
467 && hasdirectory(infile->filename, tmpname))
468 strcat(tmpname, filename);
469 else {
470 strcpy(tmpname, filename);
472 #else
473 if (!hasdirectory(filename, tmpname)
474 && hasdirectory(infile->filename, tmpname))
475 strcat(tmpname, filename);
476 else {
477 strcpy(tmpname, filename);
479 #endif
480 if (openfile(tmpname))
481 return (TRUE);
484 * Look in any directories specified by -I command line
485 * arguments, then in the builtin search list.
487 for (incptr = incdir; incptr < incend; incptr++) {
488 if (strlen(*incptr) + strlen(filename) >= (NFWORK - 1))
489 cfatal("Filename work buffer overflow", NULLST);
490 else {
491 #if HOST == SYS_UNIX
492 if (filename[0] == '/')
493 strcpy(tmpname, filename);
494 else {
495 sprintf(tmpname, "%s/%s", *incptr, filename);
497 #elif HOST == SYS_UNKNOWN
498 if (filename[0] == '\\')
499 strcpy(tmpname, filename);
500 else {
501 sprintf(tmpname, "%s\\%s", *incptr, filename);
503 #else
504 if (!hasdirectory(filename, tmpname))
505 sprintf(tmpname, "%s%s", *incptr, filename);
506 #endif
507 if (openfile(tmpname))
508 return (TRUE);
511 return (FALSE);
514 FILE_LOCAL int
515 hasdirectory(char* source, char* result)
517 * If a device or directory is found in the source filename string, the
518 * node/device/directory part of the string is copied to result and
519 * hasdirectory returns TRUE. Else, nothing is copied and it returns FALSE.
522 #if HOST == SYS_UNIX
523 register char *tp;
525 if ((tp = strrchr(source, '/')) == NULL)
526 return (FALSE);
527 else {
528 strncpy(result, source, tp - source + 1);
529 result[tp - source + 1] = EOS;
530 return (TRUE);
532 #else
533 #if HOST == SYS_VMS
534 if (vmsparse(source, NULLST, result)
535 && result[0] != EOS)
536 return (TRUE);
537 else {
538 return (FALSE);
540 #else
542 * Random DEC operating system (RSX, RT11, RSTS/E)
544 register char *tp;
546 if ((tp = strrchr(source, ']')) == NULL
547 && (tp = strrchr(source, ':')) == NULL)
548 return (FALSE);
549 else {
550 strncpy(result, source, tp - source + 1);
551 result[tp - source + 1] = EOS;
552 return (TRUE);
554 #endif
555 #endif
558 #if HOST == SYS_VMS
561 * EXP_DEV is set if a device was specified, EXP_DIR if a directory
562 * is specified. (Both set indicate a file-logical, but EXP_DEV
563 * would be set by itself if you are reading, say, SYS$INPUT:)
565 #define DEVDIR (NAM$M_EXP_DEV | NAM$M_EXP_DIR)
567 FILE_LOCAL int
568 vmsparse(source, defstring, result)
569 char *source;
570 char *defstring; /* non-NULL -> default string. */
571 char *result; /* Size is at least NAM$C_MAXRSS + 1 */
573 * Parse the source string, applying the default (properly, using
574 * the system parse routine), storing it in result.
575 * TRUE if it parsed, FALSE on error.
577 * If defstring is NULL, there are no defaults and result gets
578 * (just) the node::[directory] part of the string (possibly "")
581 struct FAB fab = cc$rms_fab; /* File access block */
582 struct NAM nam = cc$rms_nam; /* File name block */
583 char fullname[NAM$C_MAXRSS + 1];
584 register char *rp; /* Result pointer */
586 fab.fab$l_nam = &nam; /* fab -> nam */
587 fab.fab$l_fna = source; /* Source filename */
588 fab.fab$b_fns = strlen(source); /* Size of source */
589 fab.fab$l_dna = defstring; /* Default string */
590 if (defstring != NULLST)
591 fab.fab$b_dns = strlen(defstring); /* Size of default */
592 nam.nam$l_esa = fullname; /* Expanded filename */
593 nam.nam$b_ess = NAM$C_MAXRSS; /* Expanded name size */
594 if (sys$parse(&fab) == RMS$_NORMAL) { /* Parse away */
595 fullname[nam.nam$b_esl] = EOS; /* Terminate string */
596 result[0] = EOS; /* Just in case */
597 rp = &result[0];
599 * Remove stuff added implicitly, accepting node names and
600 * dev:[directory] strings (but not process-permanent files).
602 if ((nam.nam$l_fnb & NAM$M_PPF) == 0) {
603 if ((nam.nam$l_fnb & NAM$M_NODE) != 0) {
604 strncpy(result, nam.nam$l_node, nam.nam$b_node);
605 rp += nam.nam$b_node;
606 *rp = EOS;
608 if ((nam.nam$l_fnb & DEVDIR) == DEVDIR) {
609 strncpy(rp, nam.nam$l_dev, nam.nam$b_dev + nam.nam$b_dir);
610 rp += nam.nam$b_dev + nam.nam$b_dir;
611 *rp = EOS;
614 if (defstring != NULLST) {
615 strncpy(rp, nam.nam$l_name, nam.nam$b_name + nam.nam$b_type);
616 rp += nam.nam$b_name + nam.nam$b_type;
617 *rp = EOS;
618 if ((nam.nam$l_fnb & NAM$M_EXP_VER) != 0) {
619 strncpy(rp, nam.nam$l_ver, nam.nam$b_ver);
620 rp[nam.nam$b_ver] = EOS;
623 return (TRUE);
625 return (FALSE);
627 #endif