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