diff options
| author | 2026-04-17 20:30:14 +0200 | |
|---|---|---|
| committer | 2026-04-17 20:57:03 +0200 | |
| commit | 8a78aee7e3d55399d9de3086632bb367c4bea676 (patch) | |
| tree | 689000e2c38322871e95012aad35655f25de27e8 | |
| parent | 919cbebac4a66dfde36aa2accd84abdba2909080 (diff) | |
cpp: #include_next
| -rw-r--r-- | src/c_lex.c | 74 | ||||
| -rw-r--r-- | src/c_lex.h | 1 |
2 files changed, 46 insertions, 29 deletions
diff --git a/src/c_lex.c b/src/c_lex.c index 6370a1c..970fac9 100644 --- a/src/c_lex.c +++ b/src/c_lex.c @@ -1782,7 +1782,7 @@ ppelse(Lexer *lx, const Span *span) enum { MAXINCLUDE = 200 }; static bool -tryincludepath(Lexer *lx, const Span *span, char *path) +tryincludepath(Lexer *lx, const Span *span, char *path, int src_incdiridx) { Lexer new; const char *err; @@ -1801,6 +1801,7 @@ tryincludepath(Lexer *lx, const Span *span, char *path) if (++includedepth == MAXINCLUDE) lxfatal(lx, span, "Maximum nested include depth of %d reached", includedepth); + lx->src_incdiridx = src_incdiridx; break; case LXFILESKIP: xbfree(path); @@ -1810,17 +1811,20 @@ tryincludepath(Lexer *lx, const Span *span, char *path) } static bool -doinclude(Lexer *lx, const Span *span, bool quote, const char *str, size_t slen) +doinclude(Lexer *lx, const Span *span, bool quote, const char *str, size_t slen, bool incnext) { char *path = NULL; const char *base, *end; - if (quote) { - if (str[0] == '/') { + int incdiridx = 0, + req_incdiridx = incnext ? lx->src_incdiridx+1 : 0; + if (quote && req_incdiridx <= 2) { + if (req_incdiridx <= 1 && str[0] == '/') { /* try absolute path */ xbgrow(&path, slen + 1); memcpy(path, str, slen); path[slen] = 0; - if (tryincludepath(lx, span, path)) return 1; + incdiridx = 1; + if (tryincludepath(lx, span, path, incdiridx)) return 1; goto NotFound; } @@ -1833,7 +1837,8 @@ doinclude(Lexer *lx, const Span *span, bool quote, const char *str, size_t slen) memcpy(path, base, end - base); memcpy(path + (end - base), str, slen); path[end - base + slen] = 0; - if (tryincludepath(lx, span, path)) return 1; + incdiridx = 2; + if (tryincludepath(lx, span, path, incdiridx)) return 1; } /* try system paths. order: * 1. -iquote @@ -1844,22 +1849,29 @@ doinclude(Lexer *lx, const Span *span, bool quote, const char *str, size_t slen) * 6. -idirafter */ for (int i = quote ? CINCL_iquote : CINCL_I; i < countof(cinclpaths); ++i) { + incdiridx = 2 + 1000*i; for (CInclPath *p = cinclpaths[i]; p; p = p->next) { if (i == CINCLsys) { /* try embedded files pseudo-path */ - xbgrow(&path, slen + 3); - path[0] = '@', path[1] = ':'; - memcpy(path+2, str, slen); - path[slen+2] = 0; - if (tryincludepath(lx, span, path)) return 1; + if (incdiridx >= req_incdiridx) { + xbgrow(&path, slen + 3); + path[0] = '@', path[1] = ':'; + memcpy(path+2, str, slen); + path[slen+2] = 0; + if (tryincludepath(lx, span, path, incdiridx)) return 1; + } + ++incdiridx; + } + if (incdiridx >= req_incdiridx) { + int ndir = strlen(p->path); + xbgrow(&path, ndir + slen + 2); + memcpy(path, p->path, ndir); + path[ndir++] = '/'; + memcpy(path + ndir, str, slen); + path[ndir + slen] = 0; + if (tryincludepath(lx, span, path, incdiridx)) return 1; } - int ndir = strlen(p->path); - xbgrow(&path, ndir + slen + 2); - memcpy(path, p->path, ndir); - path[ndir++] = '/'; - memcpy(path + ndir, str, slen); - path[ndir + slen] = 0; - if (tryincludepath(lx, span, path)) return 1; + ++incdiridx; } } NotFound: @@ -1869,7 +1881,7 @@ NotFound: } static bool -ppinclude(Lexer *lx, const Span *span0) +ppinclude(Lexer *lx, const Span *span0, bool incnext) { Token tk; Span span = *span0; @@ -1877,7 +1889,7 @@ ppinclude(Lexer *lx, const Span *span0) if (in_range(lex0(lx, &tk, 1), TKPPHDRH, TKPPHDRQ)) { expecteol(lx, "include"); joinspan(&span.ex, tk.span.ex); - return doinclude(lx, &span, tk.t == TKPPHDRQ, tk.s, tk.len); + return doinclude(lx, &span, tk.t == TKPPHDRQ, tk.s, tk.len, incnext); } else if (tk.t == '\n' || tk.t == TKEOF) { goto BadSyntax; } else { @@ -1897,9 +1909,9 @@ ppinclude(Lexer *lx, const Span *span0) } if (tks.n >= 1 && tks.p[0].t == TKSTRLIT) { /* "header.h" */ if (tks.n > 1) - (ccopt.pedant ? error : warn)(&tks.p[1].span, "extra tokens after #include"); + (ccopt.pedant ? error : warn)(&tks.p[1].span, "extra tokens after #include directive"); joinspan(&span.ex, tks.p[0].span.ex); - return doinclude(lx, &span, 1, tks.p[0].s, tks.p[0].len); + return doinclude(lx, &span, 1, tks.p[0].s, tks.p[0].len, incnext); } else if (tks.n > 2 && tks.p[0].t == '<' && tks.p[tks.n-1].t == '>') { /* <header.h> */ /* this is multiple tokens, concatenate them together */ char buf[4096]; @@ -1911,7 +1923,7 @@ ppinclude(Lexer *lx, const Span *span0) joinspan(&span.ex, tks.p[tks.n-1].span.ex); if (wbuf.err) error(&span, "path too long"); else { - return doinclude(lx, &span, 0, buf, wbuf.len); + return doinclude(lx, &span, 0, buf, wbuf.len, incnext); } } else { BadSyntax: @@ -2026,6 +2038,7 @@ enum directive { PPIFDEF, PPIFNDEF, PPINCLUDE, + PPINCLUDENEXT, PPLINE, PPPRAGMA, PPUNDEF, @@ -2048,6 +2061,7 @@ findppcmd(const Token *tk) "ifdef", "ifndef", "include", + "include_next", "line", "pragma", "undef", @@ -2139,11 +2153,13 @@ ppdirective(Lexer *lx, bool *skip, bool *inclerror) case PPPRAGMA: pppragma(lx, &tk->span); break; case PPWARNING: ppdiag(lx, &tk->span, 0); break; case PPERROR: ppdiag(lx, &tk->span, 1); break; - case PPINCLUDE: if (!inclerror) - error(&tk->span, "#include directive within macro argument"); - else - *inclerror |= !ppinclude(lx, &tk->span); - break; + case PPINCLUDE: + case PPINCLUDENEXT: + if (!inclerror) + error(&tk->span, "#include directive within macro argument"); + else + *inclerror |= !ppinclude(lx, &tk->span, lastcmd == PPINCLUDENEXT); + break; default: assert(0&&"nyi"); } } else { @@ -2164,7 +2180,7 @@ ppdirective(Lexer *lx, bool *skip, bool *inclerror) default: ppskipline(lx); break; } } - if (lastcmd != PPINCLUDE) + if (lastcmd != PPINCLUDE && lastcmd != PPINCLUDENEXT) lx->firstdirective = 0; *skip = nppcnd ? ppcndstk[nppcnd-1].cnd != PPCNDTRUE : 0; } else { diff --git a/src/c_lex.h b/src/c_lex.h index d436967..151889c 100644 --- a/src/c_lex.h +++ b/src/c_lex.h @@ -106,6 +106,7 @@ typedef struct Lexer { bool firstdirective; short nppcnd0; short inclnerror, inclnwarn; + short src_incdiridx; internstr inclguard; uchar chrbuf[1<<10]; uint chridxbuf[1<<10]; |