1*31615c96Sdholland /*-
2*31615c96Sdholland * Copyright (c) 2010, 2013 The NetBSD Foundation, Inc.
3*31615c96Sdholland * All rights reserved.
4*31615c96Sdholland *
5*31615c96Sdholland * This code is derived from software contributed to The NetBSD Foundation
6*31615c96Sdholland * by David A. Holland.
7*31615c96Sdholland *
8*31615c96Sdholland * Redistribution and use in source and binary forms, with or without
9*31615c96Sdholland * modification, are permitted provided that the following conditions
10*31615c96Sdholland * are met:
11*31615c96Sdholland * 1. Redistributions of source code must retain the above copyright
12*31615c96Sdholland * notice, this list of conditions and the following disclaimer.
13*31615c96Sdholland * 2. Redistributions in binary form must reproduce the above copyright
14*31615c96Sdholland * notice, this list of conditions and the following disclaimer in the
15*31615c96Sdholland * documentation and/or other materials provided with the distribution.
16*31615c96Sdholland *
17*31615c96Sdholland * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18*31615c96Sdholland * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19*31615c96Sdholland * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20*31615c96Sdholland * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21*31615c96Sdholland * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22*31615c96Sdholland * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23*31615c96Sdholland * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*31615c96Sdholland * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25*31615c96Sdholland * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26*31615c96Sdholland * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27*31615c96Sdholland * POSSIBILITY OF SUCH DAMAGE.
28*31615c96Sdholland */
29*31615c96Sdholland
30*31615c96Sdholland #include <assert.h>
31*31615c96Sdholland #include <stdlib.h>
32*31615c96Sdholland #include <string.h>
33*31615c96Sdholland #include <limits.h>
34*31615c96Sdholland #include <errno.h>
35*31615c96Sdholland
36*31615c96Sdholland #include "bool.h"
37*31615c96Sdholland #include "utils.h"
38*31615c96Sdholland #include "mode.h"
39*31615c96Sdholland #include "place.h"
40*31615c96Sdholland #include "files.h"
41*31615c96Sdholland #include "directive.h"
42*31615c96Sdholland #include "macro.h"
43*31615c96Sdholland #include "eval.h"
44*31615c96Sdholland #include "output.h"
45*31615c96Sdholland
46*31615c96Sdholland struct ifstate {
47*31615c96Sdholland struct ifstate *prev;
48*31615c96Sdholland struct place startplace;
49*31615c96Sdholland bool curtrue;
50*31615c96Sdholland bool evertrue;
51*31615c96Sdholland bool seenelse;
52*31615c96Sdholland };
53*31615c96Sdholland
54*31615c96Sdholland static struct ifstate *ifstate;
55*31615c96Sdholland
56*31615c96Sdholland ////////////////////////////////////////////////////////////
57*31615c96Sdholland // common parsing bits
58*31615c96Sdholland
59*31615c96Sdholland static
60*31615c96Sdholland void
uncomment(char * buf)61*31615c96Sdholland uncomment(char *buf)
62*31615c96Sdholland {
63*31615c96Sdholland char *s, *t, *u = NULL;
64*31615c96Sdholland bool incomment = false;
65*31615c96Sdholland bool inesc = false;
66*31615c96Sdholland bool inquote = false;
67*31615c96Sdholland char quote = '\0';
68*31615c96Sdholland
69*31615c96Sdholland for (s = t = buf; *s; s++) {
70*31615c96Sdholland if (incomment) {
71*31615c96Sdholland if (s[0] == '*' && s[1] == '/') {
72*31615c96Sdholland s++;
73*31615c96Sdholland incomment = false;
74*31615c96Sdholland }
75*31615c96Sdholland } else {
76*31615c96Sdholland if (!inquote && s[0] == '/' && s[1] == '*') {
77*31615c96Sdholland incomment = true;
78*31615c96Sdholland } else {
79*31615c96Sdholland if (inesc) {
80*31615c96Sdholland inesc = false;
81*31615c96Sdholland } else if (s[0] == '\\') {
82*31615c96Sdholland inesc = true;
83*31615c96Sdholland } else if (!inquote &&
84*31615c96Sdholland (s[0] == '"' || s[0] == '\'')) {
85*31615c96Sdholland inquote = true;
86*31615c96Sdholland quote = s[0];
87*31615c96Sdholland } else if (inquote && s[0] == quote) {
88*31615c96Sdholland inquote = false;
89*31615c96Sdholland }
90*31615c96Sdholland
91*31615c96Sdholland if (t != s) {
92*31615c96Sdholland *t = *s;
93*31615c96Sdholland }
94*31615c96Sdholland if (!strchr(ws, *t)) {
95*31615c96Sdholland u = t;
96*31615c96Sdholland }
97*31615c96Sdholland t++;
98*31615c96Sdholland }
99*31615c96Sdholland }
100*31615c96Sdholland }
101*31615c96Sdholland if (u) {
102*31615c96Sdholland /* end string after last non-whitespace char */
103*31615c96Sdholland u[1] = '\0';
104*31615c96Sdholland } else {
105*31615c96Sdholland *t = '\0';
106*31615c96Sdholland }
107*31615c96Sdholland }
108*31615c96Sdholland
109*31615c96Sdholland static
110*31615c96Sdholland void
oneword(const char * what,struct place * p2,char * line)111*31615c96Sdholland oneword(const char *what, struct place *p2, char *line)
112*31615c96Sdholland {
113*31615c96Sdholland size_t pos;
114*31615c96Sdholland
115*31615c96Sdholland pos = strcspn(line, ws);
116*31615c96Sdholland if (line[pos] != '\0') {
117*31615c96Sdholland place_addcolumns(p2, pos);
118*31615c96Sdholland complain(p2, "Garbage after %s argument", what);
119*31615c96Sdholland complain_fail();
120*31615c96Sdholland line[pos] = '\0';
121*31615c96Sdholland }
122*31615c96Sdholland }
123*31615c96Sdholland
124*31615c96Sdholland ////////////////////////////////////////////////////////////
125*31615c96Sdholland // if handling
126*31615c96Sdholland
127*31615c96Sdholland static
128*31615c96Sdholland struct ifstate *
ifstate_create(struct ifstate * prev,struct place * p,bool startstate)129*31615c96Sdholland ifstate_create(struct ifstate *prev, struct place *p, bool startstate)
130*31615c96Sdholland {
131*31615c96Sdholland struct ifstate *is;
132*31615c96Sdholland
133*31615c96Sdholland is = domalloc(sizeof(*is));
134*31615c96Sdholland is->prev = prev;
135*31615c96Sdholland if (p != NULL) {
136*31615c96Sdholland is->startplace = *p;
137*31615c96Sdholland } else {
138*31615c96Sdholland place_setbuiltin(&is->startplace, 1);
139*31615c96Sdholland }
140*31615c96Sdholland is->curtrue = startstate;
141*31615c96Sdholland is->evertrue = is->curtrue;
142*31615c96Sdholland is->seenelse = false;
143*31615c96Sdholland return is;
144*31615c96Sdholland }
145*31615c96Sdholland
146*31615c96Sdholland static
147*31615c96Sdholland void
ifstate_destroy(struct ifstate * is)148*31615c96Sdholland ifstate_destroy(struct ifstate *is)
149*31615c96Sdholland {
150*31615c96Sdholland dofree(is, sizeof(*is));
151*31615c96Sdholland }
152*31615c96Sdholland
153*31615c96Sdholland static
154*31615c96Sdholland void
ifstate_push(struct place * p,bool startstate)155*31615c96Sdholland ifstate_push(struct place *p, bool startstate)
156*31615c96Sdholland {
157*31615c96Sdholland struct ifstate *newstate;
158*31615c96Sdholland
159*31615c96Sdholland newstate = ifstate_create(ifstate, p, startstate);
160*31615c96Sdholland if (!ifstate->curtrue) {
161*31615c96Sdholland newstate->curtrue = false;
162*31615c96Sdholland newstate->evertrue = true;
163*31615c96Sdholland }
164*31615c96Sdholland ifstate = newstate;
165*31615c96Sdholland }
166*31615c96Sdholland
167*31615c96Sdholland static
168*31615c96Sdholland void
ifstate_pop(void)169*31615c96Sdholland ifstate_pop(void)
170*31615c96Sdholland {
171*31615c96Sdholland struct ifstate *is;
172*31615c96Sdholland
173*31615c96Sdholland is = ifstate;
174*31615c96Sdholland ifstate = ifstate->prev;
175*31615c96Sdholland ifstate_destroy(is);
176*31615c96Sdholland }
177*31615c96Sdholland
178*31615c96Sdholland static
179*31615c96Sdholland void
d_if(struct lineplace * lp,struct place * p2,char * line)180*31615c96Sdholland d_if(struct lineplace *lp, struct place *p2, char *line)
181*31615c96Sdholland {
182*31615c96Sdholland bool doprint;
183*31615c96Sdholland char *expr;
184*31615c96Sdholland bool val;
185*31615c96Sdholland struct place p3 = *p2;
186*31615c96Sdholland size_t oldlen;
187*31615c96Sdholland
188*31615c96Sdholland doprint = ifstate->curtrue;
189*31615c96Sdholland
190*31615c96Sdholland expr = macroexpand(p2, line, strlen(line), true);
191*31615c96Sdholland
192*31615c96Sdholland oldlen = strlen(expr);
193*31615c96Sdholland uncomment(expr);
194*31615c96Sdholland /* trim to fit, so the malloc debugging won't complain */
195*31615c96Sdholland expr = dorealloc(expr, oldlen + 1, strlen(expr) + 1);
196*31615c96Sdholland
197*31615c96Sdholland if (ifstate->curtrue) {
198*31615c96Sdholland val = eval(&p3, expr);
199*31615c96Sdholland } else {
200*31615c96Sdholland val = 0;
201*31615c96Sdholland }
202*31615c96Sdholland ifstate_push(&lp->current, val);
203*31615c96Sdholland dostrfree(expr);
204*31615c96Sdholland
205*31615c96Sdholland if (doprint) {
206*31615c96Sdholland debuglog(&lp->current, "#if: %s",
207*31615c96Sdholland ifstate->curtrue ? "taken" : "not taken");
208*31615c96Sdholland }
209*31615c96Sdholland }
210*31615c96Sdholland
211*31615c96Sdholland static
212*31615c96Sdholland void
d_ifdef(struct lineplace * lp,struct place * p2,char * line)213*31615c96Sdholland d_ifdef(struct lineplace *lp, struct place *p2, char *line)
214*31615c96Sdholland {
215*31615c96Sdholland bool doprint;
216*31615c96Sdholland
217*31615c96Sdholland doprint = ifstate->curtrue;
218*31615c96Sdholland
219*31615c96Sdholland uncomment(line);
220*31615c96Sdholland oneword("#ifdef", p2, line);
221*31615c96Sdholland ifstate_push(&lp->current, macro_isdefined(line));
222*31615c96Sdholland
223*31615c96Sdholland if (doprint) {
224*31615c96Sdholland debuglog(&lp->current, "#ifdef %s: %s",
225*31615c96Sdholland line, ifstate->curtrue ? "taken" : "not taken");
226*31615c96Sdholland }
227*31615c96Sdholland }
228*31615c96Sdholland
229*31615c96Sdholland static
230*31615c96Sdholland void
d_ifndef(struct lineplace * lp,struct place * p2,char * line)231*31615c96Sdholland d_ifndef(struct lineplace *lp, struct place *p2, char *line)
232*31615c96Sdholland {
233*31615c96Sdholland bool doprint;
234*31615c96Sdholland
235*31615c96Sdholland doprint = ifstate->curtrue;
236*31615c96Sdholland
237*31615c96Sdholland uncomment(line);
238*31615c96Sdholland oneword("#ifndef", p2, line);
239*31615c96Sdholland ifstate_push(&lp->current, !macro_isdefined(line));
240*31615c96Sdholland
241*31615c96Sdholland if (doprint) {
242*31615c96Sdholland debuglog(&lp->current, "#ifndef %s: %s",
243*31615c96Sdholland line, ifstate->curtrue ? "taken" : "not taken");
244*31615c96Sdholland }
245*31615c96Sdholland }
246*31615c96Sdholland
247*31615c96Sdholland static
248*31615c96Sdholland void
d_elif(struct lineplace * lp,struct place * p2,char * line)249*31615c96Sdholland d_elif(struct lineplace *lp, struct place *p2, char *line)
250*31615c96Sdholland {
251*31615c96Sdholland bool doprint;
252*31615c96Sdholland char *expr;
253*31615c96Sdholland struct place p3 = *p2;
254*31615c96Sdholland size_t oldlen;
255*31615c96Sdholland
256*31615c96Sdholland if (ifstate->seenelse) {
257*31615c96Sdholland complain(&lp->current, "#elif after #else");
258*31615c96Sdholland complain_fail();
259*31615c96Sdholland }
260*31615c96Sdholland
261*31615c96Sdholland doprint = ifstate->curtrue;
262*31615c96Sdholland
263*31615c96Sdholland if (ifstate->evertrue) {
264*31615c96Sdholland ifstate->curtrue = false;
265*31615c96Sdholland } else {
266*31615c96Sdholland expr = macroexpand(p2, line, strlen(line), true);
267*31615c96Sdholland
268*31615c96Sdholland oldlen = strlen(expr);
269*31615c96Sdholland uncomment(expr);
270*31615c96Sdholland /* trim to fit, so the malloc debugging won't complain */
271*31615c96Sdholland expr = dorealloc(expr, oldlen + 1, strlen(expr) + 1);
272*31615c96Sdholland
273*31615c96Sdholland ifstate->curtrue = eval(&p3, expr);
274*31615c96Sdholland ifstate->evertrue = ifstate->curtrue;
275*31615c96Sdholland dostrfree(expr);
276*31615c96Sdholland }
277*31615c96Sdholland
278*31615c96Sdholland if (doprint) {
279*31615c96Sdholland debuglog2(&lp->current, &ifstate->startplace, "#elif: %s",
280*31615c96Sdholland ifstate->curtrue ? "taken" : "not taken");
281*31615c96Sdholland }
282*31615c96Sdholland }
283*31615c96Sdholland
284*31615c96Sdholland static
285*31615c96Sdholland void
d_else(struct lineplace * lp,struct place * p2,char * line)286*31615c96Sdholland d_else(struct lineplace *lp, struct place *p2, char *line)
287*31615c96Sdholland {
288*31615c96Sdholland bool doprint;
289*31615c96Sdholland
290*31615c96Sdholland (void)p2;
291*31615c96Sdholland (void)line;
292*31615c96Sdholland
293*31615c96Sdholland if (ifstate->seenelse) {
294*31615c96Sdholland complain(&lp->current,
295*31615c96Sdholland "Multiple #else directives in one conditional");
296*31615c96Sdholland complain_fail();
297*31615c96Sdholland }
298*31615c96Sdholland
299*31615c96Sdholland doprint = ifstate->curtrue;
300*31615c96Sdholland
301*31615c96Sdholland ifstate->curtrue = !ifstate->evertrue;
302*31615c96Sdholland ifstate->evertrue = true;
303*31615c96Sdholland ifstate->seenelse = true;
304*31615c96Sdholland
305*31615c96Sdholland if (doprint) {
306*31615c96Sdholland debuglog2(&lp->current, &ifstate->startplace, "#else: %s",
307*31615c96Sdholland ifstate->curtrue ? "taken" : "not taken");
308*31615c96Sdholland }
309*31615c96Sdholland }
310*31615c96Sdholland
311*31615c96Sdholland static
312*31615c96Sdholland void
d_endif(struct lineplace * lp,struct place * p2,char * line)313*31615c96Sdholland d_endif(struct lineplace *lp, struct place *p2, char *line)
314*31615c96Sdholland {
315*31615c96Sdholland (void)p2;
316*31615c96Sdholland (void)line;
317*31615c96Sdholland
318*31615c96Sdholland if (ifstate->prev == NULL) {
319*31615c96Sdholland complain(&lp->current, "Unmatched #endif");
320*31615c96Sdholland complain_fail();
321*31615c96Sdholland } else {
322*31615c96Sdholland debuglog2(&lp->current, &ifstate->startplace, "#endif");
323*31615c96Sdholland ifstate_pop();
324*31615c96Sdholland }
325*31615c96Sdholland }
326*31615c96Sdholland
327*31615c96Sdholland ////////////////////////////////////////////////////////////
328*31615c96Sdholland // macros
329*31615c96Sdholland
330*31615c96Sdholland static
331*31615c96Sdholland void
d_define(struct lineplace * lp,struct place * p2,char * line)332*31615c96Sdholland d_define(struct lineplace *lp, struct place *p2, char *line)
333*31615c96Sdholland {
334*31615c96Sdholland size_t pos, argpos;
335*31615c96Sdholland struct place p3, p4;
336*31615c96Sdholland
337*31615c96Sdholland (void)lp;
338*31615c96Sdholland
339*31615c96Sdholland /*
340*31615c96Sdholland * line may be:
341*31615c96Sdholland * macro expansion
342*31615c96Sdholland * macro(arg, arg, ...) expansion
343*31615c96Sdholland */
344*31615c96Sdholland
345*31615c96Sdholland pos = strcspn(line, " \t\f\v(");
346*31615c96Sdholland if (line[pos] == '(') {
347*31615c96Sdholland line[pos++] = '\0';
348*31615c96Sdholland argpos = pos;
349*31615c96Sdholland pos = pos + strcspn(line+pos, "()");
350*31615c96Sdholland if (line[pos] == '(') {
351*31615c96Sdholland place_addcolumns(p2, pos);
352*31615c96Sdholland complain(p2, "Left parenthesis in macro parameters");
353*31615c96Sdholland complain_fail();
354*31615c96Sdholland return;
355*31615c96Sdholland }
356*31615c96Sdholland if (line[pos] != ')') {
357*31615c96Sdholland place_addcolumns(p2, pos);
358*31615c96Sdholland complain(p2, "Unclosed macro parameter list");
359*31615c96Sdholland complain_fail();
360*31615c96Sdholland return;
361*31615c96Sdholland }
362*31615c96Sdholland line[pos++] = '\0';
363*31615c96Sdholland #if 0
364*31615c96Sdholland if (!strchr(ws, line[pos])) {
365*31615c96Sdholland p2->column += pos;
366*31615c96Sdholland complain(p2, "Trash after macro parameter list");
367*31615c96Sdholland complain_fail();
368*31615c96Sdholland return;
369*31615c96Sdholland }
370*31615c96Sdholland #endif
371*31615c96Sdholland } else if (line[pos] == '\0') {
372*31615c96Sdholland argpos = 0;
373*31615c96Sdholland } else {
374*31615c96Sdholland line[pos++] = '\0';
375*31615c96Sdholland argpos = 0;
376*31615c96Sdholland }
377*31615c96Sdholland
378*31615c96Sdholland pos += strspn(line+pos, ws);
379*31615c96Sdholland
380*31615c96Sdholland p3 = *p2;
381*31615c96Sdholland place_addcolumns(&p3, argpos);
382*31615c96Sdholland
383*31615c96Sdholland p4 = *p2;
384*31615c96Sdholland place_addcolumns(&p4, pos);
385*31615c96Sdholland
386*31615c96Sdholland if (argpos) {
387*31615c96Sdholland debuglog(&lp->current, "Defining %s()", line);
388*31615c96Sdholland macro_define_params(p2, line, &p3,
389*31615c96Sdholland line + argpos, &p4,
390*31615c96Sdholland line + pos);
391*31615c96Sdholland } else {
392*31615c96Sdholland debuglog(&lp->current, "Defining %s", line);
393*31615c96Sdholland macro_define_plain(p2, line, &p4, line + pos);
394*31615c96Sdholland }
395*31615c96Sdholland }
396*31615c96Sdholland
397*31615c96Sdholland static
398*31615c96Sdholland void
d_undef(struct lineplace * lp,struct place * p2,char * line)399*31615c96Sdholland d_undef(struct lineplace *lp, struct place *p2, char *line)
400*31615c96Sdholland {
401*31615c96Sdholland (void)lp;
402*31615c96Sdholland
403*31615c96Sdholland uncomment(line);
404*31615c96Sdholland oneword("#undef", p2, line);
405*31615c96Sdholland debuglog(&lp->current, "Undef %s", line);
406*31615c96Sdholland macro_undef(line);
407*31615c96Sdholland }
408*31615c96Sdholland
409*31615c96Sdholland ////////////////////////////////////////////////////////////
410*31615c96Sdholland // includes
411*31615c96Sdholland
412*31615c96Sdholland static
413*31615c96Sdholland bool
tryinclude(struct place * p,char * line)414*31615c96Sdholland tryinclude(struct place *p, char *line)
415*31615c96Sdholland {
416*31615c96Sdholland size_t len;
417*31615c96Sdholland
418*31615c96Sdholland len = strlen(line);
419*31615c96Sdholland if (len > 2 && line[0] == '"' && line[len-1] == '"') {
420*31615c96Sdholland line[len-1] = '\0';
421*31615c96Sdholland debuglog(p, "Entering include file \"%s\"", line+1);
422*31615c96Sdholland file_readquote(p, line+1);
423*31615c96Sdholland debuglog(p, "Leaving include file \"%s\"", line+1);
424*31615c96Sdholland line[len-1] = '"';
425*31615c96Sdholland return true;
426*31615c96Sdholland }
427*31615c96Sdholland if (len > 2 && line[0] == '<' && line[len-1] == '>') {
428*31615c96Sdholland line[len-1] = '\0';
429*31615c96Sdholland debuglog(p, "Entering include file <%s>", line+1);
430*31615c96Sdholland file_readbracket(p, line+1);
431*31615c96Sdholland debuglog(p, "Leaving include file <%s>", line+1);
432*31615c96Sdholland line[len-1] = '>';
433*31615c96Sdholland return true;
434*31615c96Sdholland }
435*31615c96Sdholland return false;
436*31615c96Sdholland }
437*31615c96Sdholland
438*31615c96Sdholland static
439*31615c96Sdholland void
d_include(struct lineplace * lp,struct place * p2,char * line)440*31615c96Sdholland d_include(struct lineplace *lp, struct place *p2, char *line)
441*31615c96Sdholland {
442*31615c96Sdholland char *text;
443*31615c96Sdholland size_t oldlen;
444*31615c96Sdholland
445*31615c96Sdholland uncomment(line);
446*31615c96Sdholland if (tryinclude(&lp->current, line)) {
447*31615c96Sdholland return;
448*31615c96Sdholland }
449*31615c96Sdholland text = macroexpand(p2, line, strlen(line), false);
450*31615c96Sdholland
451*31615c96Sdholland oldlen = strlen(text);
452*31615c96Sdholland uncomment(text);
453*31615c96Sdholland /* trim to fit, so the malloc debugging won't complain */
454*31615c96Sdholland text = dorealloc(text, oldlen + 1, strlen(text) + 1);
455*31615c96Sdholland
456*31615c96Sdholland if (tryinclude(&lp->current, text)) {
457*31615c96Sdholland dostrfree(text);
458*31615c96Sdholland return;
459*31615c96Sdholland }
460*31615c96Sdholland complain(&lp->current, "Illegal #include directive");
461*31615c96Sdholland complain(&lp->current, "Before macro expansion: #include %s", line);
462*31615c96Sdholland complain(&lp->current, "After macro expansion: #include %s", text);
463*31615c96Sdholland dostrfree(text);
464*31615c96Sdholland complain_fail();
465*31615c96Sdholland }
466*31615c96Sdholland
467*31615c96Sdholland static
468*31615c96Sdholland void
d_line(struct lineplace * lp,struct place * p2,char * line)469*31615c96Sdholland d_line(struct lineplace *lp, struct place *p2, char *line)
470*31615c96Sdholland {
471*31615c96Sdholland char *text;
472*31615c96Sdholland size_t oldlen;
473*31615c96Sdholland unsigned long val;
474*31615c96Sdholland char *moretext;
475*31615c96Sdholland size_t moretextlen;
476*31615c96Sdholland char *filename;
477*31615c96Sdholland
478*31615c96Sdholland text = macroexpand(p2, line, strlen(line), true);
479*31615c96Sdholland
480*31615c96Sdholland oldlen = strlen(text);
481*31615c96Sdholland uncomment(text);
482*31615c96Sdholland /* trim to fit, so the malloc debugging won't complain */
483*31615c96Sdholland text = dorealloc(text, oldlen + 1, strlen(text) + 1);
484*31615c96Sdholland
485*31615c96Sdholland /*
486*31615c96Sdholland * What we should have here: either 1234 "file.c",
487*31615c96Sdholland * or just 1234.
488*31615c96Sdholland */
489*31615c96Sdholland
490*31615c96Sdholland errno = 0;
491*31615c96Sdholland val = strtoul(text, &moretext, 10);
492*31615c96Sdholland if (errno) {
493*31615c96Sdholland complain(&lp->current,
494*31615c96Sdholland "Invalid line number in #line directive");
495*31615c96Sdholland goto fail;
496*31615c96Sdholland }
497*31615c96Sdholland #if UINT_MAX < ULONG_MAX
498*31615c96Sdholland if (val > UINT_MAX) {
499*31615c96Sdholland complain(&lp->current,
500*31615c96Sdholland "Line number in #line directive too large");
501*31615c96Sdholland goto fail;
502*31615c96Sdholland }
503*31615c96Sdholland #endif
504*31615c96Sdholland moretext += strspn(moretext, ws);
505*31615c96Sdholland moretextlen = strlen(moretext);
506*31615c96Sdholland place_addcolumns(&lp->current, moretext - text);
507*31615c96Sdholland
508*31615c96Sdholland if (moretextlen > 2 &&
509*31615c96Sdholland moretext[0] == '"' && moretext[moretextlen-1] == '"') {
510*31615c96Sdholland filename = dostrndup(moretext+1, moretextlen-2);
511*31615c96Sdholland place_changefile(&lp->nextline, filename);
512*31615c96Sdholland dostrfree(filename);
513*31615c96Sdholland }
514*31615c96Sdholland else if (moretextlen > 0) {
515*31615c96Sdholland complain(&lp->current,
516*31615c96Sdholland "Invalid file name in #line directive");
517*31615c96Sdholland goto fail;
518*31615c96Sdholland }
519*31615c96Sdholland
520*31615c96Sdholland lp->nextline.line = val;
521*31615c96Sdholland dostrfree(text);
522*31615c96Sdholland return;
523*31615c96Sdholland
524*31615c96Sdholland fail:
525*31615c96Sdholland complain(&lp->current, "Before macro expansion: #line %s", line);
526*31615c96Sdholland complain(&lp->current, "After macro expansion: #line %s", text);
527*31615c96Sdholland complain_fail();
528*31615c96Sdholland dostrfree(text);
529*31615c96Sdholland }
530*31615c96Sdholland
531*31615c96Sdholland ////////////////////////////////////////////////////////////
532*31615c96Sdholland // messages
533*31615c96Sdholland
534*31615c96Sdholland static
535*31615c96Sdholland void
d_warning(struct lineplace * lp,struct place * p2,char * line)536*31615c96Sdholland d_warning(struct lineplace *lp, struct place *p2, char *line)
537*31615c96Sdholland {
538*31615c96Sdholland char *msg;
539*31615c96Sdholland
540*31615c96Sdholland msg = macroexpand(p2, line, strlen(line), false);
541*31615c96Sdholland complain(&lp->current, "#warning: %s", msg);
542*31615c96Sdholland if (mode.werror) {
543*31615c96Sdholland complain_fail();
544*31615c96Sdholland }
545*31615c96Sdholland dostrfree(msg);
546*31615c96Sdholland }
547*31615c96Sdholland
548*31615c96Sdholland static
549*31615c96Sdholland void
d_error(struct lineplace * lp,struct place * p2,char * line)550*31615c96Sdholland d_error(struct lineplace *lp, struct place *p2, char *line)
551*31615c96Sdholland {
552*31615c96Sdholland char *msg;
553*31615c96Sdholland
554*31615c96Sdholland msg = macroexpand(p2, line, strlen(line), false);
555*31615c96Sdholland complain(&lp->current, "#error: %s", msg);
556*31615c96Sdholland complain_fail();
557*31615c96Sdholland dostrfree(msg);
558*31615c96Sdholland }
559*31615c96Sdholland
560*31615c96Sdholland ////////////////////////////////////////////////////////////
561*31615c96Sdholland // other
562*31615c96Sdholland
563*31615c96Sdholland static
564*31615c96Sdholland void
d_pragma(struct lineplace * lp,struct place * p2,char * line)565*31615c96Sdholland d_pragma(struct lineplace *lp, struct place *p2, char *line)
566*31615c96Sdholland {
567*31615c96Sdholland (void)p2;
568*31615c96Sdholland
569*31615c96Sdholland complain(&lp->current, "#pragma %s", line);
570*31615c96Sdholland complain_fail();
571*31615c96Sdholland }
572*31615c96Sdholland
573*31615c96Sdholland ////////////////////////////////////////////////////////////
574*31615c96Sdholland // directive table
575*31615c96Sdholland
576*31615c96Sdholland static const struct {
577*31615c96Sdholland const char *name;
578*31615c96Sdholland bool ifskip;
579*31615c96Sdholland void (*func)(struct lineplace *, struct place *, char *line);
580*31615c96Sdholland } directives[] = {
581*31615c96Sdholland { "define", true, d_define },
582*31615c96Sdholland { "elif", false, d_elif },
583*31615c96Sdholland { "else", false, d_else },
584*31615c96Sdholland { "endif", false, d_endif },
585*31615c96Sdholland { "error", true, d_error },
586*31615c96Sdholland { "if", false, d_if },
587*31615c96Sdholland { "ifdef", false, d_ifdef },
588*31615c96Sdholland { "ifndef", false, d_ifndef },
589*31615c96Sdholland { "include", true, d_include },
590*31615c96Sdholland { "line", true, d_line },
591*31615c96Sdholland { "pragma", true, d_pragma },
592*31615c96Sdholland { "undef", true, d_undef },
593*31615c96Sdholland { "warning", true, d_warning },
594*31615c96Sdholland };
595*31615c96Sdholland static const unsigned numdirectives = HOWMANY(directives);
596*31615c96Sdholland
597*31615c96Sdholland static
598*31615c96Sdholland void
directive_gotdirective(struct lineplace * lp,char * line)599*31615c96Sdholland directive_gotdirective(struct lineplace *lp, char *line)
600*31615c96Sdholland {
601*31615c96Sdholland struct place p2;
602*31615c96Sdholland size_t len, skip;
603*31615c96Sdholland unsigned i;
604*31615c96Sdholland
605*31615c96Sdholland p2 = lp->current;
606*31615c96Sdholland for (i=0; i<numdirectives; i++) {
607*31615c96Sdholland len = strlen(directives[i].name);
608*31615c96Sdholland if (!strncmp(line, directives[i].name, len) &&
609*31615c96Sdholland strchr(ws, line[len])) {
610*31615c96Sdholland if (directives[i].ifskip && !ifstate->curtrue) {
611*31615c96Sdholland return;
612*31615c96Sdholland }
613*31615c96Sdholland skip = len + strspn(line+len, ws);
614*31615c96Sdholland place_addcolumns(&p2, skip);
615*31615c96Sdholland line += skip;
616*31615c96Sdholland
617*31615c96Sdholland len = strlen(line);
618*31615c96Sdholland len = notrailingws(line, len);
619*31615c96Sdholland if (len < strlen(line)) {
620*31615c96Sdholland line[len] = '\0';
621*31615c96Sdholland }
622*31615c96Sdholland directives[i].func(lp, &p2, line);
623*31615c96Sdholland return;
624*31615c96Sdholland }
625*31615c96Sdholland }
626*31615c96Sdholland /* ugh. allow # by itself, including with a comment after it */
627*31615c96Sdholland uncomment(line);
628*31615c96Sdholland if (line[0] == '\0') {
629*31615c96Sdholland return;
630*31615c96Sdholland }
631*31615c96Sdholland
632*31615c96Sdholland skip = strcspn(line, ws);
633*31615c96Sdholland complain(&lp->current, "Unknown directive #%.*s", (int)skip, line);
634*31615c96Sdholland complain_fail();
635*31615c96Sdholland }
636*31615c96Sdholland
637*31615c96Sdholland /*
638*31615c96Sdholland * Check for nested comment delimiters in LINE.
639*31615c96Sdholland */
640*31615c96Sdholland static
641*31615c96Sdholland size_t
directive_scancomments(const struct lineplace * lp,char * line,size_t len)642*31615c96Sdholland directive_scancomments(const struct lineplace *lp, char *line, size_t len)
643*31615c96Sdholland {
644*31615c96Sdholland size_t pos;
645*31615c96Sdholland bool incomment;
646*31615c96Sdholland struct place p2;
647*31615c96Sdholland
648*31615c96Sdholland p2 = lp->current;
649*31615c96Sdholland incomment = 0;
650*31615c96Sdholland for (pos = 0; pos+1 < len; pos++) {
651*31615c96Sdholland if (line[pos] == '/' && line[pos+1] == '*') {
652*31615c96Sdholland if (incomment) {
653*31615c96Sdholland complain(&p2, "Warning: %c%c within comment",
654*31615c96Sdholland '/', '*');
655*31615c96Sdholland if (mode.werror) {
656*31615c96Sdholland complain_failed();
657*31615c96Sdholland }
658*31615c96Sdholland } else {
659*31615c96Sdholland incomment = true;
660*31615c96Sdholland }
661*31615c96Sdholland pos++;
662*31615c96Sdholland } else if (line[pos] == '*' && line[pos+1] == '/') {
663*31615c96Sdholland if (incomment) {
664*31615c96Sdholland incomment = false;
665*31615c96Sdholland } else {
666*31615c96Sdholland /* stray end-comment; should we care? */
667*31615c96Sdholland }
668*31615c96Sdholland pos++;
669*31615c96Sdholland }
670*31615c96Sdholland if (line[pos] == '\n') {
671*31615c96Sdholland place_addlines(&p2, 1);
672*31615c96Sdholland p2.column = 0;
673*31615c96Sdholland } else {
674*31615c96Sdholland place_addcolumns(&p2, 1);
675*31615c96Sdholland }
676*31615c96Sdholland }
677*31615c96Sdholland
678*31615c96Sdholland /* multiline comments are supposed to arrive in a single buffer */
679*31615c96Sdholland assert(!incomment);
680*31615c96Sdholland return len;
681*31615c96Sdholland }
682*31615c96Sdholland
683*31615c96Sdholland void
directive_gotline(struct lineplace * lp,char * line,size_t len)684*31615c96Sdholland directive_gotline(struct lineplace *lp, char *line, size_t len)
685*31615c96Sdholland {
686*31615c96Sdholland size_t skip;
687*31615c96Sdholland
688*31615c96Sdholland if (warns.nestcomment) {
689*31615c96Sdholland directive_scancomments(lp, line, len);
690*31615c96Sdholland }
691*31615c96Sdholland
692*31615c96Sdholland /* check if we have a directive line (# exactly in column 0) */
693*31615c96Sdholland if (len > 0 && line[0] == '#') {
694*31615c96Sdholland skip = 1 + strspn(line + 1, ws);
695*31615c96Sdholland assert(skip <= len);
696*31615c96Sdholland place_addcolumns(&lp->current, skip);
697*31615c96Sdholland assert(line[len] == '\0');
698*31615c96Sdholland directive_gotdirective(lp, line+skip /*, length = len-skip */);
699*31615c96Sdholland place_addcolumns(&lp->current, len-skip);
700*31615c96Sdholland } else if (ifstate->curtrue) {
701*31615c96Sdholland macro_sendline(&lp->current, line, len);
702*31615c96Sdholland place_addcolumns(&lp->current, len);
703*31615c96Sdholland }
704*31615c96Sdholland }
705*31615c96Sdholland
706*31615c96Sdholland void
directive_goteof(struct place * p)707*31615c96Sdholland directive_goteof(struct place *p)
708*31615c96Sdholland {
709*31615c96Sdholland while (ifstate->prev != NULL) {
710*31615c96Sdholland complain(p, "Missing #endif");
711*31615c96Sdholland complain(&ifstate->startplace, "...opened at this point");
712*31615c96Sdholland complain_failed();
713*31615c96Sdholland ifstate_pop();
714*31615c96Sdholland }
715*31615c96Sdholland macro_sendeof(p);
716*31615c96Sdholland }
717*31615c96Sdholland
718*31615c96Sdholland ////////////////////////////////////////////////////////////
719*31615c96Sdholland // module initialization
720*31615c96Sdholland
721*31615c96Sdholland void
directive_init(void)722*31615c96Sdholland directive_init(void)
723*31615c96Sdholland {
724*31615c96Sdholland ifstate = ifstate_create(NULL, NULL, true);
725*31615c96Sdholland }
726*31615c96Sdholland
727*31615c96Sdholland void
directive_cleanup(void)728*31615c96Sdholland directive_cleanup(void)
729*31615c96Sdholland {
730*31615c96Sdholland assert(ifstate->prev == NULL);
731*31615c96Sdholland ifstate_destroy(ifstate);
732*31615c96Sdholland ifstate = NULL;
733*31615c96Sdholland }
734