1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: macro.c,v $
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 ************************************************************************/
50 * do a macro definition. tp points to the name being defined in the line
53 dodefine(Tokenrow
* trp
)
60 static uchar location
[(_MAX_PATH
+ 8) * NINC
], *cp
;
62 static uchar location
[(PATH_MAX
+ 8) * NINC
], *cp
;
65 if (tp
>= trp
->lp
|| tp
->type
!= NAME
)
67 error(ERROR
, "#defined token is not a name");
71 if (np
->flag
& ISUNCHANGE
)
73 error(ERROR
, "#defined token %t can't be redefined", tp
);
76 /* collect arguments */
79 if (tp
< trp
->lp
&& tp
->type
== LP
&& tp
->wslen
== 0)
86 maketokenrow(2, args
);
100 if (narg
>= args
->max
)
102 for (atp
= args
->bp
; atp
< args
->lp
; atp
++)
103 if (atp
->len
== tp
->len
104 && strncmp((char *) atp
->t
, (char *) tp
->t
, tp
->len
) == 0)
105 error(ERROR
, "Duplicate macro argument");
111 if (tp
->type
!= COMMA
)
120 error(ERROR
, "Syntax error in macro parameters");
127 if (((trp
->lp
) - 1)->type
== NL
)
129 def
= normtokenrow(trp
);
130 if (np
->flag
& ISDEFINED
)
132 if (comparetokens(def
, np
->vp
)
133 || (np
->ap
== NULL
) != (args
== NULL
)
134 || (np
->ap
&& comparetokens(args
, np
->ap
)))
135 error(ERROR
, "Macro redefinition of %t (already defined at %s)", trp
->bp
+ 2, np
->loc
);
141 tap
= normtokenrow(args
);
147 np
->flag
|= ISDEFINED
;
149 /* build location string of macro definition */
150 for (cp
= location
, s
= cursource
; s
; s
= s
->next
)
155 sprintf((char *)cp
, "%s:%d", s
->filename
, s
->line
);
156 cp
+= strlen((char *)cp
);
159 np
->loc
= newstring(location
, strlen((char *)location
), 0);
164 error(INFO
, "Macro definition of %s(%r) [%r]", np
->name
, np
->ap
, np
->vp
);
166 error(INFO
, "Macro definition of %s [%r]", np
->name
, np
->vp
);
171 * Definition received via -D or -U
174 doadefine(Tokenrow
* trp
, int type
)
177 static uchar onestr
[2] = "1";
178 static Token onetoken
[1] = {{NUMBER
, 0, 0, 1, onestr
}};
179 static Tokenrow onetr
= {onetoken
, onetoken
, onetoken
+ 1, 1};
184 if (trp
->lp
- trp
->tp
!= 2 || trp
->tp
->type
!= NAME
)
186 if ((np
= lookup(trp
->tp
, 0)) == NULL
)
188 np
->flag
&= ~ISDEFINED
;
194 if (trp
->tp
>= trp
->lp
|| trp
->tp
->type
!= NAME
)
196 trp
->tp
->type
= ARCHITECTURE
;
197 np
= lookup(trp
->tp
, 1);
198 np
->flag
|= ISARCHITECTURE
;
200 if (trp
->tp
>= trp
->lp
|| trp
->tp
->type
== END
)
206 error(FATAL
, "Illegal -A argument %r", trp
);
209 if (trp
->tp
>= trp
->lp
|| trp
->tp
->type
!= NAME
)
211 np
= lookup(trp
->tp
, 1);
212 np
->flag
|= ISDEFINED
;
214 if (trp
->tp
>= trp
->lp
|| trp
->tp
->type
== END
)
219 if (trp
->tp
->type
!= ASGN
)
222 if ((trp
->lp
- 1)->type
== END
)
224 np
->vp
= normtokenrow(trp
);
227 error(FATAL
, "Illegal -D or -U argument %r", trp
);
231 * Do macro expansion in a row of tokens.
232 * Flag is NULL if more input can be gathered.
235 expandrow(Tokenrow
* trp
, char *flag
)
241 setsource(flag
, -1, -1, "", 0);
242 for (tp
= trp
->tp
; tp
< trp
->lp
;)
245 || quicklook(tp
->t
[0], tp
->len
> 1 ? tp
->t
[1] : 0) == 0
246 || (np
= lookup(tp
, 0)) == NULL
247 || (np
->flag
& (ISDEFINED
| ISMAC
)) == 0
248 || (np
->flag
& ISACTIVE
) != 0)
254 if (np
->val
== KDEFINED
)
257 if ((tp
+ 1) < trp
->lp
&& (tp
+ 1)->type
== NAME
)
258 (tp
+ 1)->type
= NAME1
;
260 if ((tp
+ 3) < trp
->lp
&& (tp
+ 1)->type
== LP
261 && (tp
+ 2)->type
== NAME
&& (tp
+ 3)->type
== RP
)
262 (tp
+ 2)->type
= NAME1
;
264 error(ERROR
, "Incorrect syntax for `defined'");
269 if (np
->val
== KMACHINE
)
271 if (((tp
- 1) >= trp
->bp
) && ((tp
- 1)->type
== SHARP
))
273 tp
->type
= ARCHITECTURE
;
274 if ((tp
+ 1) < trp
->lp
&& (tp
+ 1)->type
== NAME
)
275 (tp
+ 1)->type
= NAME2
;
277 if ((tp
+ 3) < trp
->lp
&& (tp
+ 1)->type
== LP
278 && (tp
+ 2)->type
== NAME
&& (tp
+ 3)->type
== RP
)
279 (tp
+ 2)->type
= NAME2
;
281 error(ERROR
, "Incorrect syntax for `#machine'");
287 if (np
->flag
& ISMAC
)
288 builtin(trp
, np
->val
);
298 * Expand the macro whose name is np, at token trp->tp, in the tokenrow.
299 * Return trp->tp at the first token next to be expanded
300 * (ordinarily the beginning of the expansion)
303 expand(Tokenrow
* trp
, Nlist
* np
)
307 Tokenrow
*atr
[NARG
+ 1];
312 error(INFO
, "Macro expansion of %t with %s(%r)", trp
->tp
, np
->name
, np
->ap
);
314 error(INFO
, "Macro expansion of %t with %s", trp
->tp
, np
->name
);
317 copytokenrow(&ntr
, np
->vp
); /* copy macro value */
318 if (np
->ap
== NULL
) /* parameterless */
322 ntokc
= gatherargs(trp
, atr
, &narg
);
324 { /* not actually a call (no '(') */
328 if (narg
!= rowlen(np
->ap
))
330 error(ERROR
, "Disagreement in number of macro arguments");
334 substargs(np
, &ntr
, atr
); /* put args into replacement */
335 for (i
= 0; i
< narg
; i
++)
342 np
->flag
|= ISACTIVE
;
344 doconcat(&ntr
); /* execute ## operators */
346 makespace(&ntr
, trp
->tp
);
347 expandrow(&ntr
, "<expand>");
348 insertrow(trp
, ntokc
, &ntr
);
351 np
->flag
&= ~ISACTIVE
;
357 * Gather an arglist, starting in trp with tp pointing at the macro name.
358 * Return total number of tokens passed, stash number of args found.
359 * trp->tp is not changed relative to the tokenrow.
362 gatherargs(Tokenrow
* trp
, Tokenrow
** atr
, int *narg
)
371 *narg
= -1; /* means that there is no macro
378 if (trp
->tp
>= trp
->lp
)
381 if ((trp
->lp
- 1)->type
== END
)
388 if (trp
->tp
->type
== LP
)
390 if (trp
->tp
->type
!= NL
)
397 /* search for the terminating ), possibly extending the row */
401 if (trp
->tp
>= trp
->lp
)
406 /* makespace(trp); [rh] */
408 if (trp
->tp
->type
== END
)
412 error(ERROR
, "EOF in macro arglist");
415 if (trp
->tp
->type
== NL
)
420 /* makespace(trp); [rh] */
424 if (trp
->tp
->type
== LP
)
427 if (trp
->tp
->type
== RP
)
433 /* Now trp->tp won't move underneath us */
434 lp
= bp
= trp
->tp
+ ntokp
;
435 for (; parens
>= 0; lp
++)
444 if (lp
->type
== DSHARP
)
445 lp
->type
= DSHARP1
; /* ## not special in arg */
446 if ((lp
->type
== COMMA
&& parens
== 0)
447 || (parens
< 0 && (lp
- 1)->type
!= LP
))
449 if (*narg
>= NARG
- 1)
450 error(FATAL
, "Sorry, too many macro arguments");
451 ttr
.bp
= ttr
.tp
= bp
;
453 atr
[(*narg
)++] = normtokenrow(&ttr
);
461 * substitute the argument list into the replacement string
462 * This would be simple except for ## and #
465 substargs(Nlist
* np
, Tokenrow
* rtr
, Tokenrow
** atr
)
471 for (rtr
->tp
= rtr
->bp
; rtr
->tp
< rtr
->lp
;)
473 if (rtr
->tp
->type
== SHARP
)
474 { /* string operator */
477 if ((argno
= lookuparg(np
, rtr
->tp
)) < 0)
479 error(ERROR
, "# not followed by macro parameter");
482 ntok
= 1 + (rtr
->tp
- tp
);
484 insertrow(rtr
, ntok
, stringify(atr
[argno
]));
487 if (rtr
->tp
->type
== NAME
488 && (argno
= lookuparg(np
, rtr
->tp
)) >= 0)
490 if (((rtr
->tp
+ 1) < rtr
->lp
&& (rtr
->tp
+ 1)->type
== DSHARP
)
491 || (rtr
->tp
!= rtr
->bp
&& (rtr
->tp
- 1)->type
== DSHARP
))
493 copytokenrow(&tatr
, atr
[argno
]);
494 makespace(&tatr
, rtr
->tp
);
495 insertrow(rtr
, 1, &tatr
);
500 copytokenrow(&tatr
, atr
[argno
]);
501 makespace(&tatr
, rtr
->tp
);
502 expandrow(&tatr
, "<macro>");
503 insertrow(rtr
, 1, &tatr
);
513 * Evaluate the ## operators in a tokenrow
516 doconcat(Tokenrow
* trp
)
522 for (trp
->tp
= trp
->bp
; trp
->tp
< trp
->lp
; trp
->tp
++)
524 if (trp
->tp
->type
== DSHARP1
)
525 trp
->tp
->type
= DSHARP
;
527 if (trp
->tp
->type
== DSHARP
)
535 if (ltp
< trp
->bp
|| ntp
>= trp
->lp
)
537 error(ERROR
, "## occurs at border of replacement");
547 if (len
+ ntp
->len
+ ntp
->wslen
> sizeof(tt
))
549 error(ERROR
, "## string concatination buffer overrun");
553 strncpy((char *) tt
+ len
, (char *) ntp
->t
- ntp
->wslen
,
554 ntp
->len
+ ntp
->wslen
);
555 len
+= ntp
->len
+ ntp
->wslen
;
560 while (ntp
< trp
->lp
);
563 setsource("<##>", -1, -1, tt
, 0);
564 maketokenrow(3, &ntr
);
567 if (ntr
.bp
->type
== UNCLASS
)
568 error(WARNING
, "Bad token %r produced by ##", &ntr
);
571 makespace(&ntr
, ltp
);
572 insertrow(trp
, ntp
- ltp
, &ntr
);
580 * tp is a potential parameter name of macro mac;
581 * look it up in mac's arglist, and if found, return the
582 * corresponding index in the argname array. Return -1 if not found.
585 lookuparg(Nlist
* mac
, Token
* tp
)
589 if (tp
->type
!= NAME
|| mac
->ap
== NULL
)
591 for (ap
= mac
->ap
->bp
; ap
< mac
->ap
->lp
; ap
++)
593 if (ap
->len
== tp
->len
&& strncmp((char *) ap
->t
, (char *) tp
->t
, ap
->len
) == 0)
594 return ap
- mac
->ap
->bp
;
600 * Return a quoted version of the tokenrow (from # arg)
604 stringify(Tokenrow
* vp
)
606 static Token t
= {STRING
, 0, 0, 0, NULL
};
607 static Tokenrow tr
= {&t
, &t
, &t
+ 1, 1};
614 for (tp
= vp
->bp
; tp
< vp
->lp
; tp
++)
616 instring
= tp
->type
== STRING
|| tp
->type
== CCON
;
617 if (sp
+ 2 * tp
->len
>= &s
[STRLEN
- 10])
619 error(ERROR
, "Stringified macro arg is too long");
622 for (i
= 0, cp
= tp
->t
; (unsigned int)i
< tp
->len
; i
++)
624 if (instring
&& (*cp
== '"' || *cp
== '\\'))
632 t
.len
= strlen((char *) sp
);
633 t
.t
= newstring(sp
, t
.len
, 0);
638 * expand a builtin name
641 builtin(Tokenrow
* trp
, int biname
)
649 /* need to find the real source */
651 while (s
&& s
->fd
== -1)
655 /* most are strings */
669 op
= outnum(op
- 1, s
->line
);
674 char *src
= s
->filename
;
676 while ((*op
++ = *src
++) != 0)
684 strncpy(op
, curtime
+ 4, 7);
685 strncpy(op
+ 7, curtime
+ 20, 4);
690 strncpy(op
, curtime
+ 11, 8);
695 error(ERROR
, "cpp botch: unknown internal macro");
698 if (tp
->type
== STRING
)
700 tp
->t
= (uchar
*) outptr
;
701 tp
->len
= op
- outptr
;