fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / rsc / source / rscpp / cpp2.c
blob8da4100c8be7691625dead38743b1750c3331490
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <stdio.h>
21 #include <ctype.h>
22 #include "cppdef.h"
23 #include "cpp.h"
24 #if HOST == SYS_VMS
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.)
30 #include <nam.h>
31 #include <fab.h>
32 #include <rab.h>
33 #include <rmsdef.h>
34 #endif
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.
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
62 void InitCpp2()
68 int
69 control(int counter)
71 * Process #control lines. Simple commands are processed inline,
72 * while complex commands have their own subroutines.
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.
79 register int c;
80 register char *tp;
81 register int hash;
82 char *ep;
84 c = skipws();
85 if (c == '\n' || c == EOF_CHAR)
86 return (counter + 1);
87 if (!isdigit(c))
88 scanid(c); /* Get #word to token[] */
89 else {
90 unget(); /* Hack -- allow #123 as a */
91 strcpy(token, "line"); /* synonym for #line 123 */
93 hash = (token[1] == EOS) ? L_nogood : (token[0] + (token[2] << 1));
94 switch (hash) {
95 case L_assert: tp = "assert"; break;
96 case L_define: tp = "define"; break;
97 case L_elif: tp = "elif"; break;
98 case L_else: tp = "else"; break;
99 case L_endif: tp = "endif"; break;
100 case L_if: tp = "if"; break;
101 case L_ifdef: tp = "ifdef"; break;
102 case L_ifndef: tp = "ifndef"; break;
103 case L_include: tp = "include"; break;
104 case L_line: tp = "line"; break;
105 case L_pragma: tp = "pragma"; break;
106 case L_undef: tp = "undef"; break;
107 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 default: hash = L_nogood;
113 case L_nogood: tp = ""; break;
115 if (!streq(tp, token))
116 hash = L_nogood;
118 * hash is set to a unique value corresponding to the
119 * control keyword (or L_nogood if we think it's nonsense).
121 if (infile->fp == NULL)
122 cwarn("Control line \"%s\" within macro expansion", token);
123 if (!compiling) { /* Not compiling now */
124 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 if (++ifptr >= &ifstack[BLK_NEST])
129 goto if_nest_err;
130 *ifptr = 0; /* !WAS_COMPILING */
131 case L_line: /* Many */
133 * Are pragma's always processed?
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 dump_line: skipnl(); /* Ignore rest of line */
142 return (counter + 1);
146 * Make sure that #line and #pragma are output on a fresh line.
148 if (counter > 0 && (hash == L_line || hash == L_pragma)) {
149 PUTCHAR('\n');
150 counter--;
152 switch (hash) {
153 case L_line:
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.
159 c = skipws();
160 workp = work; /* Save name in work */
161 while (c != '\n' && c != EOF_CHAR) {
162 save(c);
163 c = get();
165 unget();
166 save(EOS);
168 * Split #line argument into <line-number> and <name>
169 * We subtract 1 as we want the number of the next line.
171 line = atoi(work) - 1; /* Reset line number */
172 for (tp = work; isdigit(*tp) || type[(int)*tp] == SPA; tp++)
173 ; /* Skip over digits */
174 if (*tp != EOS) { /* Got a filename, so: */
175 if (*tp == '"' && (ep = strrchr(tp + 1, '"')) != NULL) {
176 tp++; /* Skip over left quote */
177 *ep = EOS; /* And ignore right one */
179 if (infile->progname != NULL) /* Give up the old name */
180 free(infile->progname); /* if it's allocated. */
181 infile->progname = savestring(tp);
183 wrongline = TRUE; /* Force output later */
184 break;
186 case L_include:
187 doinclude();
188 break;
190 case L_define:
191 dodefine();
192 break;
194 case L_undef:
195 doundef();
196 break;
198 case L_else:
199 if (ifptr == &ifstack[0])
200 goto nest_err;
201 else if ((*ifptr & ELSE_SEEN) != 0)
202 goto else_seen_err;
203 *ifptr |= ELSE_SEEN;
204 if ((*ifptr & WAS_COMPILING) != 0) {
205 if (compiling || (*ifptr & TRUE_SEEN) != 0)
206 compiling = FALSE;
207 else {
208 compiling = TRUE;
211 break;
213 case L_elif:
214 if (ifptr == &ifstack[0])
215 goto nest_err;
216 else if ((*ifptr & ELSE_SEEN) != 0) {
217 else_seen_err: cerror("#%s may not follow #else", token);
218 goto dump_line;
220 if ((*ifptr & (WAS_COMPILING | TRUE_SEEN)) != WAS_COMPILING) {
221 compiling = FALSE; /* Done compiling stuff */
222 goto dump_line; /* Skip this clause */
224 doif(L_if);
225 break;
227 case L_if:
228 case L_ifdef:
229 case L_ifndef:
230 if (++ifptr >= &ifstack[BLK_NEST])
231 if_nest_err: cfatal("Too many nested #%s statements", token);
232 *ifptr = WAS_COMPILING;
233 doif(hash);
234 break;
236 case L_endif:
237 if (ifptr == &ifstack[0]) {
238 nest_err: cerror("#%s must be in an #if", token);
239 goto dump_line;
241 if (!compiling && (*ifptr & WAS_COMPILING) != 0)
242 wrongline = TRUE;
243 compiling = ((*ifptr & WAS_COMPILING) != 0);
244 --ifptr;
245 break;
247 case L_assert:
248 if (eval() == 0)
249 cerror("Preprocessor assertion failure", NULLST);
250 break;
252 case L_pragma:
254 * #pragma is provided to pass "options" to later
255 * passes of the compiler. cpp doesn't have any yet.
257 fprintf( pCppOut, "#pragma ");
258 while ((c = get()) != '\n' && c != EOF_CHAR)
259 cput(c);
260 unget();
261 break;
263 #if OSL_DEBUG_LEVEL > 1
264 case L_debug:
265 if (debug == 0)
266 dumpdef("debug set on");
267 debug++;
268 break;
270 case L_nodebug:
271 debug--;
272 break;
273 #endif
274 case L_error: /* BP 5.3.92, #error */
276 fprintf( pCppOut, "cpp: line %u, Error directive: ", line );
277 while ((c = get()) != '\n' && c != EOF_CHAR)
278 cput(c);
279 fprintf( pCppOut, "\n" );
280 exit( 1 );
281 break;
283 default:
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.
290 cerror("Illegal # command \"%s\"", token);
291 break;
293 if (hash != L_include) {
294 #if OLD_PREPROCESSOR
296 * Ignore the rest of the #control line so you can write
297 * #if foo
298 * #endif foo
300 goto dump_line; /* Take common exit */
301 #else
302 if (skipws() != '\n') {
303 cwarn("Unexpected text in #control line ignored", NULLST);
304 skipnl();
306 #endif
308 return (counter + 1);
311 FILE_LOCAL
312 void doif(int hash)
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.
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.
322 register int c;
323 register int found;
325 if ((c = skipws()) == '\n' || c == EOF_CHAR) {
326 unget();
327 goto badif;
329 if (hash == L_if) {
330 unget();
331 found = (eval() != 0); /* Evaluate expr, != 0 is TRUE */
332 hash = L_ifdef; /* #if is now like #ifdef */
334 else {
335 if (type[c] != LET) /* Next non-blank isn't letter */
336 goto badif; /* ... is an error */
337 found = (lookid(c) != NULL); /* Look for it in symbol table */
339 if (found == (hash == L_ifdef)) {
340 compiling = TRUE;
341 *ifptr |= TRUE_SEEN;
343 else {
344 compiling = FALSE;
346 return;
348 badif: cerror("#if, #ifdef, or #ifndef without an argument", NULLST);
349 #if !OLD_PREPROCESSOR
350 skipnl(); /* Prevent an extra */
351 unget(); /* Error message */
352 #endif
353 return;
356 FILE_LOCAL
357 void doinclude()
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.
369 * Note: the November 12 draft forbids '>' in the #include <file> format.
370 * This restriction is unnecessary and not implemented.
373 register int c;
374 register int delim;
375 #if HOST == SYS_VMS
376 char def_filename[NAM$C_MAXRSS + 1];
377 #endif
379 delim = macroid(skipws());
380 if (delim != '<' && delim != '"')
381 goto incerr;
382 if (delim == '<')
383 delim = '>';
384 workp = work;
385 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 */
391 * The draft is unclear if the following should be done.
393 while (--workp >= work && *workp == ' ')
394 ; /* Trim blanks from filename */
395 if (*workp != delim)
396 goto incerr;
397 #else
398 while ((c = get()) != delim && c != EOF_CHAR)
399 save(c);
400 #endif
401 *workp = EOS; /* Terminate filename */
402 instring = FALSE;
403 #if HOST == SYS_VMS
405 * Assume the default .h filetype.
407 if (!vmsparse(work, ".H", def_filename)) {
408 perror(work); /* Oops. */
409 goto incerr;
411 else if (openinclude(def_filename, (delim == '"')))
412 return;
413 #else
414 if (openinclude(work, (delim == '"')))
415 return;
416 #endif
418 * No sense continuing if #include file isn't there.
420 cfatal("Cannot open include file \"%s\"", work);
422 incerr: cerror("#include syntax error", NULLST);
423 return;
426 FILE_LOCAL int
427 openinclude(char* filename, int searchlocal)
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.
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 */
445 if (searchlocal) {
447 * Look in local directory first
449 #if HOST == SYS_UNIX
451 * Try to open filename relative to the directory of the current
452 * source file (as opposed to the current directory). (ARF, SCK).
454 if (filename[0] != '/'
455 && hasdirectory(infile->filename, tmpname))
456 strcat(tmpname, filename);
457 else {
458 strcpy(tmpname, filename);
460 #else
461 if (!hasdirectory(filename, tmpname)
462 && hasdirectory(infile->filename, tmpname))
463 strcat(tmpname, filename);
464 else {
465 strcpy(tmpname, filename);
467 #endif
468 if (openfile(tmpname))
469 return (TRUE);
472 * Look in any directories specified by -I command line
473 * arguments, then in the builtin search list.
475 for (incptr = incdir; incptr < incend; incptr++) {
476 if (strlen(*incptr) + strlen(filename) >= (NFWORK - 1))
477 cfatal("Filename work buffer overflow", NULLST);
478 else {
479 #if HOST == SYS_UNIX
480 if (filename[0] == '/')
481 strcpy(tmpname, filename);
482 else {
483 sprintf(tmpname, "%s/%s", *incptr, filename);
485 #elif HOST == SYS_UNKNOWN
486 if (filename[0] == '\\')
487 strcpy(tmpname, filename);
488 else {
489 sprintf(tmpname, "%s\\%s", *incptr, filename);
491 #else
492 if (!hasdirectory(filename, tmpname))
493 sprintf(tmpname, "%s%s", *incptr, filename);
494 #endif
495 if (openfile(tmpname))
496 return (TRUE);
499 return (FALSE);
502 FILE_LOCAL int
503 hasdirectory(char* source, char* result)
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.
510 #if HOST == SYS_UNIX
511 register char *tp;
513 if ((tp = strrchr(source, '/')) == NULL)
514 return (FALSE);
515 else {
516 strncpy(result, source, tp - source + 1);
517 result[tp - source + 1] = EOS;
518 return (TRUE);
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);
528 #else
530 * Random DEC operating system (RSX, RT11, RSTS/E)
532 register char *tp;
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);
542 #endif
543 #endif
546 #if HOST == SYS_VMS
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:)
553 #define DEVDIR (NAM$M_EXP_DEV | NAM$M_EXP_DIR)
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 */
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.
565 * If defstring is NULL, there are no defaults and result gets
566 * (just) the node::[directory] part of the string (possibly "")
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 */
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];
587 * Remove stuff added implicitly, accepting node names and
588 * dev:[directory] strings (but not process-permanent files).
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;
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;
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;
611 return (TRUE);
613 return (FALSE);
615 #endif
617 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */