1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
23 #if defined(__IBMC__) || defined(__EMX__) || defined(_MSC_VER)
25 # define PATH_MAX _MAX_PATH
30 #include <sal/types.h>
37 * do a macro definition. tp points to the name being defined in the line
40 dodefine(Tokenrow
* trp
)
46 static uchar location
[(PATH_MAX
+ 8) * NINC
], *cp
;
49 if (tp
>= trp
->lp
|| tp
->type
!= NAME
)
51 error(ERROR
, "#defined token is not a name");
55 if (np
->flag
& ISUNCHANGE
)
57 error(ERROR
, "#defined token %t can't be redefined", tp
);
60 /* collect arguments */
63 if (tp
< trp
->lp
&& tp
->type
== LP
&& tp
->wslen
== 0)
67 maketokenrow(2, args
);
83 if (narg
>= args
->max
)
85 for (atp
= args
->bp
; atp
< args
->lp
; atp
++)
86 if (atp
->len
== tp
->len
87 && strncmp((char *) atp
->t
, (char *) tp
->t
, tp
->len
) == 0)
88 error(ERROR
, "Duplicate macro argument");
94 if (tp
->type
!= COMMA
)
103 error(ERROR
, "Syntax error in macro parameters");
110 if (((trp
->lp
) - 1)->type
== NL
)
112 def
= normtokenrow(trp
);
113 if (np
->flag
& ISDEFINED
)
115 if (comparetokens(def
, np
->vp
)
116 || (np
->ap
== NULL
) != (args
== NULL
)
117 || (np
->ap
&& comparetokens(args
, np
->ap
)))
121 "Macro redefinition of %t (already defined at %s)",
122 trp
->bp
+ 2, np
->loc
);
125 "Macro redefinition of %t (already defined at %s)",
126 trp
->bp
+ 2, "commandline" );
133 tap
= normtokenrow(args
);
140 np
->flag
|= ISDEFINED
;
142 /* build location string of macro definition */
143 for (cp
= location
, s
= cursource
; s
; s
= s
->next
)
148 SAL_WNODEPRECATED_DECLARATIONS_PUSH
/* sprintf (macOS 13 SDK) */
149 sprintf((char *)cp
, "%s:%d", s
->filename
, s
->line
);
150 SAL_WNODEPRECATED_DECLARATIONS_POP
151 cp
+= strlen((char *)cp
);
154 np
->loc
= newstring(location
, strlen((char *)location
), 0);
159 error(INFO
, "Macro definition of %s(%r) [%r]", np
->name
, np
->ap
, np
->vp
);
161 error(INFO
, "Macro definition of %s [%r]", np
->name
, np
->vp
);
166 * Definition received via -D or -U
169 doadefine(Tokenrow
* trp
, int type
)
172 static uchar onestr
[2] = "1";
173 static Token onetoken
[1] = {{NUMBER
, 0, 1, onestr
, 0}};
174 static Tokenrow onetr
= {onetoken
, onetoken
, onetoken
+ 1, 1};
179 if (trp
->lp
- trp
->tp
!= 2 || trp
->tp
->type
!= NAME
)
181 if ((np
= lookup(trp
->tp
, 0)) == NULL
)
183 np
->flag
&= ~ISDEFINED
;
189 if (trp
->tp
>= trp
->lp
|| trp
->tp
->type
!= NAME
)
191 trp
->tp
->type
= ARCHITECTURE
;
192 np
= lookup(trp
->tp
, 1);
193 np
->flag
|= ISARCHITECTURE
;
195 if (trp
->tp
>= trp
->lp
|| trp
->tp
->type
== END
)
201 error(FATAL
, "Illegal -A argument %r", trp
);
204 if (trp
->tp
>= trp
->lp
|| trp
->tp
->type
!= NAME
)
206 np
= lookup(trp
->tp
, 1);
207 np
->flag
|= ISDEFINED
;
209 if (trp
->tp
>= trp
->lp
|| trp
->tp
->type
== END
)
214 if (trp
->tp
->type
!= ASGN
)
217 if ((trp
->lp
- 1)->type
== END
)
219 np
->vp
= normtokenrow(trp
);
222 error(FATAL
, "Illegal -D or -U argument %r", trp
);
228 * Do macro expansion in a row of tokens.
229 * Flag is NULL if more input can be gathered.
232 expandrow(Tokenrow
* trp
, char *flag
)
237 MacroValidatorList validators
;
238 mvl_init(&validators
);
239 /* Sets all token-identifiers to 0 because tokens may not be initialised (never use C!) */
240 tokenrow_zeroTokenIdentifiers(trp
);
243 setsource(flag
, -1, -1, "", 0);
244 for (tp
= trp
->tp
; tp
< trp
->lp
;)
246 mvl_check(&validators
, tp
);
249 || quicklook(tp
->t
[0], tp
->len
> 1 ? tp
->t
[1] : 0) == 0
250 || (np
= lookup(tp
, 0)) == NULL
251 || (np
->flag
& (ISDEFINED
| ISMAC
)) == 0
252 || (np
->flag
& ISACTIVE
) != 0)
258 if (np
->val
== KDEFINED
)
261 if ((tp
+ 1) < trp
->lp
&& (tp
+ 1)->type
== NAME
)
262 (tp
+ 1)->type
= NAME1
;
264 if ((tp
+ 3) < trp
->lp
&& (tp
+ 1)->type
== LP
265 && (tp
+ 2)->type
== NAME
&& (tp
+ 3)->type
== RP
)
266 (tp
+ 2)->type
= NAME1
;
268 error(ERROR
, "Incorrect syntax for `defined'");
273 if (np
->val
== KMACHINE
)
275 if (((tp
- 1) >= trp
->bp
) && ((tp
- 1)->type
== SHARP
))
277 tp
->type
= ARCHITECTURE
;
278 if ((tp
+ 1) < trp
->lp
&& (tp
+ 1)->type
== NAME
)
279 (tp
+ 1)->type
= NAME2
;
281 if ((tp
+ 3) < trp
->lp
&& (tp
+ 1)->type
== LP
282 && (tp
+ 2)->type
== NAME
&& (tp
+ 3)->type
== RP
)
283 (tp
+ 2)->type
= NAME2
;
285 error(ERROR
, "Incorrect syntax for `#machine'");
291 if (np
->flag
& ISMAC
)
292 builtin(trp
, np
->val
);
295 // coverity[overrun-buffer-arg: FALSE] - a multiple of trp->max is allocated, not trp->max itself
296 expand(trp
, np
, &validators
);
303 mvl_destruct(&validators
);
307 * Expand the macro whose name is np, at token trp->tp, in the tokenrow.
308 * Return trp->tp at the first token next to be expanded
309 * (ordinarily the beginning of the expansion)
310 * I.e.: the same position as before!
311 * Only one expansion is performed, then we return to the expandrow()
312 * loop and start at same position.
315 expand(Tokenrow
* trp
, Nlist
* np
, MacroValidatorList
* pValidators
)
319 Tokenrow
*atr
[NARG
+ 1];
324 error(INFO
, "Macro expansion of %t with %s(%r)", trp
->tp
, np
->name
, np
->ap
);
326 error(INFO
, "Macro expansion of %t with %s", trp
->tp
, np
->name
);
329 copytokenrow(&ntr
, np
->vp
); /* copy macro value */
330 if (np
->ap
== NULL
) /* parameterless */
336 ntokc
= gatherargs(trp
, atr
, &narg
);
338 { /* not actually a call (no '(') */
342 if (narg
!= rowlen(np
->ap
))
344 error(ERROR
, "Disagreement in number of macro arguments");
349 /** If gatherargs passed a macro validating token, this token
350 must become valid here.
351 trp->tp+0 was checked in expandrow(), so we don't need to do it
354 for (i
= 1; i
< ntokc
; i
++)
356 mvl_check(pValidators
,trp
->tp
+i
);
359 substargs(np
, &ntr
, atr
); /* put args into replacement */
360 for (i
= 0; i
< narg
; i
++)
367 doconcat(&ntr
); /* execute ## operators */
369 makespace(&ntr
, trp
->tp
);
371 tokenrow_zeroTokenIdentifiers(&ntr
);
372 insertrow(trp
, ntokc
, &ntr
);
374 /* add validator for just invalidated macro:
376 np
->flag
|= ISACTIVE
;
377 if (trp
->tp
!= trp
->lp
)
378 { /* tp is a valid pointer: */
379 mvl_add(pValidators
,np
,trp
->tp
);
382 { /* tp is == lp, therefore does not point to valid memory: */
383 mvl_add(pValidators
,np
,NULL
);
385 /* reset trp->tp to original position:
387 trp
->tp
-= ntr
.lp
- ntr
.bp
; /* so the result will be tested for macros from the same position again */
395 * Gather an arglist, starting in trp with tp pointing at the macro name.
396 * Return total number of tokens passed, stash number of args found.
397 * trp->tp is not changed relative to the tokenrow.
400 gatherargs(Tokenrow
* trp
, Tokenrow
** atr
, int *narg
)
409 *narg
= -1; /* means that there is no macro
416 if (trp
->tp
>= trp
->lp
)
418 // coverity[overrun-buffer-arg: FALSE] - a multiple of trp->max is allocated, not trp->max itself
420 if ((trp
->lp
- 1)->type
== END
)
427 if (trp
->tp
->type
== LP
)
429 if (trp
->tp
->type
!= NL
)
436 /* search for the terminating ), possibly extending the row */
440 if (trp
->tp
>= trp
->lp
)
442 // coverity[overrun-buffer-arg: FALSE] - a multiple of trp->max is allocated, not trp->max itself
448 /* makespace(trp); [rh] */
450 if (trp
->tp
->type
== END
)
454 error(ERROR
, "EOF in macro arglist");
457 if (trp
->tp
->type
== NL
)
462 /* makespace(trp); [rh] */
466 if (trp
->tp
->type
== LP
)
469 if (trp
->tp
->type
== RP
)
475 /* Now trp->tp won't move underneath us */
476 lp
= bp
= trp
->tp
+ ntokp
;
477 for (; parens
>= 0; lp
++)
486 if (lp
->type
== DSHARP
)
487 lp
->type
= DSHARP1
; /* ## not special in arg */
488 if ((lp
->type
== COMMA
&& parens
== 0) ||
489 ( parens
< 0 && ((lp
- 1)->type
!= LP
)))
491 if (*narg
>= NARG
- 1)
492 error(FATAL
, "Sorry, too many macro arguments");
493 ttr
.bp
= ttr
.tp
= bp
;
495 atr
[(*narg
)++] = normtokenrow(&ttr
);
503 * substitute the argument list into the replacement string
504 * This would be simple except for ## and #
507 substargs(Nlist
* np
, Tokenrow
* rtr
, Tokenrow
** atr
)
513 for (rtr
->tp
= rtr
->bp
; rtr
->tp
< rtr
->lp
;)
515 if (rtr
->tp
->type
== SHARP
)
516 { /* string operator */
519 if ((argno
= lookuparg(np
, rtr
->tp
)) < 0)
521 error(ERROR
, "# not followed by macro parameter");
524 ntok
= 1 + (int)(rtr
->tp
- tp
);
526 insertrow(rtr
, ntok
, stringify(atr
[argno
]));
529 if (rtr
->tp
->type
== NAME
530 && (argno
= lookuparg(np
, rtr
->tp
)) >= 0)
532 if (((rtr
->tp
+ 1) < rtr
->lp
&& (rtr
->tp
+ 1)->type
== DSHARP
)
533 || (rtr
->tp
!= rtr
->bp
&& (rtr
->tp
- 1)->type
== DSHARP
))
535 copytokenrow(&tatr
, atr
[argno
]);
536 makespace(&tatr
, rtr
->tp
);
537 insertrow(rtr
, 1, &tatr
);
542 copytokenrow(&tatr
, atr
[argno
]);
543 makespace(&tatr
, rtr
->tp
);
544 expandrow(&tatr
, "<macro>");
545 insertrow(rtr
, 1, &tatr
);
555 * Evaluate the ## operators in a tokenrow
558 doconcat(Tokenrow
* trp
)
564 for (trp
->tp
= trp
->bp
; trp
->tp
< trp
->lp
; trp
->tp
++)
566 if (trp
->tp
->type
== DSHARP1
)
567 trp
->tp
->type
= DSHARP
;
569 if (trp
->tp
->type
== DSHARP
)
577 if (ltp
< trp
->bp
|| ntp
>= trp
->lp
)
579 error(ERROR
, "## occurs at border of replacement");
589 if (len
+ ntp
->len
+ ntp
->wslen
> sizeof(tt
))
591 error(ERROR
, "## string concatenation buffer overrun");
595 if (ntp
!= trp
->tp
+ 1)
597 strncpy((char *) tt
+ len
, (char *) ntp
->t
- ntp
->wslen
,
598 ntp
->len
+ ntp
->wslen
);
599 len
+= ntp
->len
+ ntp
->wslen
;
603 // remove spaces around ##
604 strncpy((char *) tt
+ len
, (char *) ntp
->t
, ntp
->len
);
611 while (ntp
< trp
->lp
);
614 setsource("<##>", -1, -1, tt
, 0);
615 maketokenrow(3, &ntr
);
616 // coverity[overrun-buffer-arg: FALSE] - a multiple of trp->max is allocated, not trp->max itself
619 if (ntr
.bp
->type
== UNCLASS
)
620 error(WARNING
, "Bad token %r produced by ##", &ntr
);
621 while ((ntr
.lp
-1)->len
== 0 && ntr
.lp
!= ntr
.bp
)
626 makespace(&ntr
, ltp
);
627 insertrow(trp
, (int)(ntp
- ltp
), &ntr
);
635 * tp is a potential parameter name of macro mac;
636 * look it up in mac's arglist, and if found, return the
637 * corresponding index in the argname array. Return -1 if not found.
640 lookuparg(Nlist
* mac
, Token
const * tp
)
644 if (tp
->type
!= NAME
|| mac
->ap
== NULL
)
646 for (ap
= mac
->ap
->bp
; ap
< mac
->ap
->lp
; ap
++)
648 if (ap
->len
== tp
->len
&& strncmp((char *) ap
->t
, (char *) tp
->t
, ap
->len
) == 0)
649 return (int)(ap
- mac
->ap
->bp
);
655 * Return a quoted version of the tokenrow (from # arg)
659 stringify(Tokenrow
* vp
)
661 static Token t
= {STRING
, 0, 0, NULL
, 0};
662 static Tokenrow tr
= {&t
, &t
, &t
+ 1, 1};
669 for (tp
= vp
->bp
; tp
< vp
->lp
; tp
++)
671 instring
= tp
->type
== STRING
|| tp
->type
== CCON
;
672 if (sp
+ 2 * tp
->len
+ tp
->wslen
>= &s
[STRLEN
- 10])
674 error(ERROR
, "Stringified macro arg is too long");
678 // Change by np 31.10.2001, #93725 - begin
683 for (i
= 0, cp
= tp
->t
; (unsigned int)i
< tp
->len
; i
++)
685 if (instring
&& (*cp
== '"' || *cp
== '\\'))
693 t
.len
= strlen((char *) sp
);
694 t
.t
= newstring(sp
, t
.len
, 0);
699 * expand a builtin name
702 builtin(Tokenrow
* trp
, int biname
)
710 /* need to find the real source */
712 while (s
&& s
->fd
== -1)
716 /* most are strings */
730 op
= outnum(op
- 1, s
->line
);
735 char *src
= s
->filename
;
737 while ((*op
++ = *src
++) != 0)
745 strncpy(op
, curtime
+ 4, 7);
746 strncpy(op
+ 7, curtime
+ 20, 4);
751 strncpy(op
, curtime
+ 11, 8);
756 error(ERROR
, "cpp botch: unknown internal macro");
759 if (tp
->type
== STRING
)
761 tp
->t
= (uchar
*) outptr
;
762 tp
->len
= op
- outptr
;
766 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */