diff options
Diffstat (limited to 'src/io.c')
| -rw-r--r-- | src/io.c | 1255 |
1 files changed, 0 insertions, 1255 deletions
diff --git a/src/io.c b/src/io.c deleted file mode 100644 index d33afb1..0000000 --- a/src/io.c +++ /dev/null @@ -1,1255 +0,0 @@ -#include "c/lex.h" -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <unistd.h> - -struct wbuf bstdout, bstderr; - -void -ioinit(void) -{ - bstdout.fp = stdout; - bstdout.isfp = 1; - bstderr.fp = stderr; - bstderr.isfp = 1; -} - -void -iowrite(struct wbuf *buf, const void *Src, int n) -{ - const uchar *src = Src; - - if (buf->isfp) { - fwrite(Src, 1, n, buf->fp); - buf->err = ferror(buf->fp) != 0; - return; - } - while (n > 0) { - int avail = buf->cap - buf->len; - int amt = avail < n ? avail : n; - - memcpy(buf->buf + buf->len, src, amt); - n -= amt; - src += amt; - buf->len += amt; - if (n > 0 && buf->len == buf->cap) { - if (buf->fd < 0) { - buf->err = 1; - return; - } - ioflush(buf); - } - } -} - -void -ioflush(struct wbuf *buf) -{ - int i, ret; - - if (buf->isfp) { - fflush(buf->fp); - buf->err = ferror(buf->fp) != 0; - return; - } - buf->err = 0; - if (buf->fd < 0) { - buf->len = 0; - return; - } - for (i = 0; buf->len > 0;) { - ret = write(buf->fd, buf->buf + i, buf->len); - if (ret > 0) { - assert(ret <= buf->len); - buf->len -= ret; - i += ret; - } else if (errno == EAGAIN || errno == EWOULDBLOCK) { - continue; - } else { - buf->err = 1; - break; - } - } -} - -void -ioputc(struct wbuf *buf, uchar c) -{ - if (buf->isfp) { - buf->err = fputc(c, buf->fp) != EOF; - return; - } - if (buf->len == buf->cap) { - if (buf->fd < 0) { - buf->err = 1; - return; - } - ioflush(buf); - } - buf->buf[buf->len++] = c; -} - -static int -putquoted(struct wbuf *buf, uchar c, uchar qchar, int next) -{ - if (c == qchar || c == '\\' || !aisprint(c)) { - int n = (ioputc(buf, '\\'), 1); - uchar cseq; - - switch (c) { - case '\\': - case '\'': - case '"': - cseq = c; - Charseq: - n += (ioputc(buf, cseq), 1); - break; - case '\a': cseq = 'a'; goto Charseq; - case '\b': cseq = 'b'; goto Charseq; - case '\f': cseq = 'f'; goto Charseq; - case '\r': cseq = 'r'; goto Charseq; - case '\t': cseq = 't'; goto Charseq; - case '\v': cseq = 'v'; goto Charseq; - case '\n': cseq = 'n'; goto Charseq; - default: - if (!next || in_range(next, '0', '7')) - n += bfmt(buf, "%.3o", c); - else - n += bfmt(buf, "%o", c); - } - return n; - } - if (c == '?' && (!next || next == '?')) { - return ioputc(buf, c), ioputc(buf, '\\'), 2; - } - return ioputc(buf, c), 1; -} - -static int -putuint(struct wbuf *buf, uvlong x, int base, bool lower) -{ - uchar tmp[64]; - uchar *end = tmp + sizeof(tmp); - uchar *s = end; - switch (base) { - case 2: - do *--s = '0' + x%2; while (x >>= 1); - break; - case 8: - do *--s = '0' + x%8; while (x >>= 3); - break; - case 10: - do *--s = '0' + x%10; while (x /= 10); - break; - case 16: - do *--s = "0123456789ABCDEF"[x&15] | (-lower & 0x20); while (x >>= 4); - break; - default: - assert(0&&"base"); - } - iowrite(buf, s, end - s); - return end - s; -} - -static void -fmterr(const char *fmt, ...) -{ - va_list ap; - - efmt("fmt Error: "); - va_start(ap, fmt); - vbfmt(&bstderr, fmt, ap); - va_end(ap); - ioputc(&bstderr, '\n'); - ioflush(&bstderr); - ioflush(&bstdout); - abort(); -} - -#define bwriteS(buf, S) (iowrite(buf, S, sizeof S - 1), sizeof S - 1) -#define bputc(B, C) (ioputc(B, C), 1) - -static int -priquals(struct wbuf *buf, int q) -{ - const char s[] = " const volatile", *p = s; - int m = sizeof s - 1; - if (!q) return 0; - else if (q == QCONST) m -= 9; - else if (q == QVOLATILE) p += 6, m -= 6; - else assert(q == (QCONST | QVOLATILE)); - iowrite(buf, p, m); - return m; -} -static int -pritypebefore(struct wbuf *buf, union type ty, int qual) -{ - const char *s, *s2; - union type chld; - int n; - switch (ty.t) { - case TYVOID: s = "void"; Prim: n = bfmt(buf, "%s", s); return n + priquals(buf, qual); - case TYBOOL: s = "bool"; goto Prim; - case TYCHAR: s = "char"; goto Prim; - case TYSCHAR: s = "signed char"; goto Prim; - case TYUCHAR: s = "unsigned char"; goto Prim; - case TYSHORT: s = "short"; goto Prim; - case TYUSHORT: s = "unsigned short"; goto Prim; - case TYINT: s = "int"; goto Prim; - case TYUINT: s = "unsigned int"; goto Prim; - case TYLONG: s = "long"; goto Prim; - case TYULONG: s = "unsigned long"; goto Prim; - case TYVLONG: s = "long long"; goto Prim; - case TYUVLONG: s = "unsigned long long"; goto Prim; - case TYFLOAT: s = "float"; goto Prim; - case TYDOUBLE: s = "double"; goto Prim; - case TYLDOUBLE:s = "long double"; goto Prim; - case TYCOMPLEXF:s = "float complex"; goto Prim; - case TYCOMPLEX: s = "double complex"; goto Prim; - case TYCOMPLEXL:s = "long double complex"; goto Prim; - case TYPTR: - chld = typechild(ty); - n = pritypebefore(buf, chld, ty.flag & TFCHLDQUAL); - if (!isptrcvtt(chld.t)) - n += bputc(buf, ' '); - if (chld.t == TYARRAY || chld.t == TYFUNC) - n += bputc(buf, '('); - n += bputc(buf, '*'); - n += priquals(buf, qual); - return n; - case TYARRAY: - return pritypebefore(buf, typechild(ty), ty.flag & TFCHLDQUAL); - case TYFUNC: - return pritypebefore(buf, typedata[ty.dat].ret, 0); - case TYSTRUCT: - s = "struct"; - Tagged: - n = bfmt(buf, "%s %s", s, (s2 = (char *)ttypenames[typedata[ty.dat].id]) ? s2 : "(anonymous)"); - return n + priquals(buf, qual); - case TYUNION: - s = "union"; - goto Tagged; - case TYENUM: - s = "enum"; - goto Tagged; - default: - return bfmt(buf, "?\?%d?",ty.t); - } -} - -static int -pritypeafter(struct wbuf *buf, union type ty, int qual) -{ - const struct typedata *td; - int n = 0; - switch (ty.t) { - case TYPTR: - if (typechild(ty).t == TYARRAY || typechild(ty).t == TYFUNC) - n += bputc(buf, ')'); - n += pritypeafter(buf, typechild(ty), ty.flag & TFCHLDQUAL); - break; - case TYARRAY: - n += bputc(buf, '['); - if (typearrlen(ty)) - n += bfmt(buf, "%u", typearrlen(ty)); - n += bputc(buf, ']'); - n += pritypeafter(buf, typechild(ty), ty.flag & TFCHLDQUAL); - break; - case TYFUNC: - td = &typedata[ty.dat]; - n += bputc(buf, '('); - for (int i = 0; i < td->nmemb; ++i) { - n += bfmt(buf, "%ty", td->param[i]); - if (i < td->nmemb - 1 || td->variadic) - n += bwriteS(buf, ", "); - } - if (td->variadic) n += bwriteS(buf, "..."); - else if (td->nmemb == 0 && !td->kandr) n += bwriteS(buf, "void"); - n += bwriteS(buf, ")"); - n += pritypeafter(buf, td->ret, 0); - break; - } - return n; -} - -static int -fmttype(struct wbuf *buf, union type ty, int qual) -{ - int n = pritypebefore(buf, ty, qual); - n += pritypeafter(buf, ty, qual); - return n; -} - -static int -putdouble(struct wbuf *buf, double x) -{ - char tmp[200]; - int n = snprintf(tmp, sizeof tmp, "%f", x); - if (n >= sizeof tmp-1) n = snprintf(tmp, sizeof tmp, "%g", x); - assert(n < sizeof tmp-1); - iowrite(buf, tmp, n); - return n; -} - -int -vbfmt(struct wbuf *out, const char *fmt, va_list ap) -{ - bool quote, umod, lmod, zmod, lower, possign; - int base; - vlong i; - int pad, prec, q; - const char *s; - void *p; - struct token *tok; - union type ty; - double f; - char tmpbuf1[70], tmpbuf2[70]; - struct wbuf tmp1 = MEMBUF(tmpbuf1, sizeof tmpbuf1); - struct wbuf tmp2 = MEMBUF(tmpbuf2, sizeof tmpbuf2); - struct wbuf *buf = out; - int n = 0, prevn; - - while (*fmt) { - buf = out; - if (*fmt++ != '%') { - n += bputc(buf, fmt[-1]); - continue; - } - if (*fmt == '%') { - n += bputc(buf, *fmt++); - continue; - } - fmt += quote = *fmt == '\''; - fmt += possign = *fmt == '+'; - pad = 0; - if (aisdigit(*fmt)) { /* left pad */ - for (; aisdigit(*fmt); ++fmt) - pad = pad*10 + *fmt-'0'; - if (pad) { - tmp1.len = 0; - buf = &tmp1; - } - } else if (*fmt == '-') { /* right pad */ - if (!aisdigit(*++fmt)) - fmterr("padding amount expected"); - for (; aisdigit(*fmt); ++fmt) - pad = pad*10 - (*fmt-'0'); - } - prec = -1; - if (*fmt == '.') { - if (!aisdigit(*++fmt)) - fmterr("precision expected"); - prec = 0; - for (; aisdigit(*fmt); ++fmt) - prec = prec*10 + *fmt-'0'; - } - fmt += umod = *fmt == 'u'; - if ((zmod = *fmt == 'z')) - ++fmt, lmod = 0; - else - fmt += lmod = *fmt == 'l'; - lower = 0; - prevn = n; - switch (*fmt++) { - case 'c': /* character */ - if (quote) { - n += bputc(buf, '\''); - n += putquoted(buf, va_arg(ap, int), '\'', -1); - n += bputc(buf, '\''); - } else { - n += bputc(buf, va_arg(ap, int)); - } - break; - case 's': /* nullterminated string */ - s = va_arg(ap, const char *); - if (quote) { - if (!s) { - n += bwriteS(buf, "(null)"); - break; - } - QuotedStr: - n += bputc(buf, '"'); - if (lmod) /* lower */ - for (; *s; ++s) n += putquoted(buf, aisalpha(*s) ? *s|32 : *s, '"', s[1]); - else - for (; *s; ++s) n += putquoted(buf, *s, '"', s[1]); - n += bputc(buf, '"'); - } else { - assert(s && "%s null!"); - if (lmod) /* lower */ - for (; *s; ++s) n += bputc(buf, aisalpha(*s) ? *s|32 : *s); - else - while (*s) n += bputc(buf, *s++); - } - break; - case 'S': /* string ptr + len */ - s = va_arg(ap, const char *); - i = va_arg(ap, uint); - PriS: - assert(s && "%S null"); - if (quote) { - n += bputc(buf, '"'); - for (; i--; ++s) n += putquoted(buf, *s, '"', i ? s[1] : -1); - n += bputc(buf, '"'); - } else { - iowrite(buf, s, i); - n += i; - } - break; - case 'y': /* symbol: print string literally if valid identifier, or quote it */ - s = va_arg(ap, const char *); - assert(s && "%y null"); - for (i = 0; s[i]; ++i) { - if (aisalpha(s[i]) || s[i] == '_' || (i > 0 && aisdigit(s[i]))) - continue; - goto QuotedStr; - } - /* valid identifier */ - while (*s) n += bputc(buf, *s++); - break; - case 'd': /* decimal */ - base = 10; - Int: - if (base != 10) umod = 1; - i = lmod ? va_arg(ap, vlong) - : umod ? va_arg(ap, uint) - : zmod && sizeof(&i-&i) > sizeof(int) ? va_arg(ap, vlong) - : (vlong)va_arg(ap, int); - tmp2.len = 0; - if (!umod && i < 0) { - n += bputc(buf, '-'); - i = -(uvlong)i; - } else if (possign) { - n += bputc(buf, '+'); - } - if (quote) { - switch (base) { - case 2: n += bwriteS(buf, "0b"); break; - case 8: n += bwriteS(buf, "0"); break; - case 16: n += bwriteS(buf, "0x"); break; - } - } - n += putuint(prec > 0 ? &tmp2 : buf, i, base, lower); - if (prec > 0) { - int fil = prec - tmp2.len; - while (fil-- > 0) n += bputc(buf, '0'); - iowrite(buf, tmp2.buf, tmp2.len); - } - break; - case 'o': /* octal */ - base = 8; - goto Int; - case 'b': /* binary */ - base = 2; - goto Int; - case 'x': case 'X': /* hexadecimal */ - base = 16; - lower = fmt[-1] == 'x'; - goto Int; - case 'p': /* pointer */ - p = va_arg(ap, void *); - if (!p && quote) { - n += bwriteS(buf, "NULL"); - } else { - n += bwriteS(buf, "0x"); - tmp2.len = 0; - n += putuint(prec > 0 ? &tmp2 : buf, (uvlong)p, 16, 1); - if (prec > 0) { - int fil = prec - tmp2.len; - while (fil-- > 0) n += bputc(buf, '0'); - iowrite(buf, tmp2.buf, tmp2.len); - } - } - break; - case 'f': /* float */ - f = va_arg(ap, double); - n += putdouble(buf, f); - break; - case 't': /* token/tokentag/type */ - switch (*fmt++) { - case 'k': /* tk token */ - tok = va_arg(ap, struct token *); - Tok: - switch (tok->t) { - case TKXXX: - n += bwriteS(buf, "\?\?\?"); - break; - case TKNUMLIT: - if (quote) { - n += bputc(buf, '`'); - iowrite(buf, tok->s, tok->len); - n += tok->len; - n += bputc(buf, '\''); - } else { - s = tok->s; - i = tok->len; - goto PriS; - } - break; - case TKCHRLIT: - if (tok->wide) n += bputc(buf, tok->wideuni ? tok->wide == 1 ? 'u' : 'U' : 'L'); - n += bputc(buf, '\''); - if (tok->wide == 0) - for (int i = 0; i < tok->len; ++i) - n += putquoted(buf, tok->s[i], '\'', i < tok->len - 1 ? tok->s[i+1] : -1); - else { - char p[4]; - uint c = tok->wide == 1 ? tok->ws16[0] : tok->ws32[0]; - int l = utf8enc(p, c); - if (l == 1) - n += putquoted(buf, *p, '\'', -1); - else - n += (iowrite(buf, p, l), l); - } - n += bputc(buf, '\''); - break; - case TKSTRLIT: - if (tok->wide == 0) { - s = tok->s; - i = tok->len; - quote = 1; - goto PriS; - } else { - n += bputc(buf, tok->wideuni ? tok->wide == 1 ? 'u' : 'U' : 'L'); - n += bputc(buf, '\"'); - for (int i = 0; i < tok->len; ++i) { - char p[4]; - uint c = tok->wide == 1 ? tok->ws16[i] : tok->ws32[i]; - int l = utf8enc(p, c); - if (l == 1) - n += putquoted(buf, *p, '\"', 0); - else - n += (iowrite(buf, p, l), l); - } - n += bputc(buf, '\"'); - } - break; - case TKPPMACSTR: - if (quote) n += bputc(buf, '`'); - n += bfmt(buf, "#%s", tok->s); - if (quote) n += bputc(buf, '\''); - break; - case TKPPMACARG: - case TKIDENT: - if (quote) n += bputc(buf, '`'); - n += bfmt(buf, "%s", tok->name); - if (quote) n += bputc(buf, '\''); - break; - case TKEOF: - n += bwriteS(buf, "<end-of-file>"); - break; - case TKEQU: s = "=="; C2: iowrite(buf, s, 2); n += 2; break; - case TKNEQ: s = "!="; goto C2; - case TKLTE: s = "<="; goto C2; - case TKGTE: s = ">="; goto C2; - case TKSHR: s = ">>"; goto C2; - case TKSHL: s = "<<"; goto C2; - case TKINC: s = "++"; goto C2; - case TKDEC: s = "--"; goto C2; - case TKDOTS: n += bwriteS(buf, "..."); break; - case TKARROW: s = "->"; goto C2; - case TKPPCAT: s = "##"; goto C2; - case TKLOGAND: s = "&&"; goto C2; - case TKLOGIOR: s = "||"; goto C2; - case TKSETADD: s = "+="; goto C2; - case TKSETSUB: s = "-="; goto C2; - case TKSETMUL: s = "*="; goto C2; - case TKSETDIV: s = "/="; goto C2; - case TKSETREM: s = "%="; goto C2; - case TKSETIOR: s = "|="; goto C2; - case TKSETXOR: s = "^="; goto C2; - case TKSETAND: s = "&="; goto C2; - case TKSETSHR: n += bwriteS(buf, ">>="); break; - case TKSETSHL: n += bwriteS(buf, "<<="); break; - default: - if (quote) n += bputc(buf, '`'); - if (in_range(tok->t, TKWBEGIN_, TKWEND_)) { - iowrite(buf, tok->name, tok->len); - n += tok->len; - } else if (aisprint(tok->t)) { - n += bputc(buf, tok->t); - } else { - n += bwriteS(buf, "??"); - } - if (quote) n += bputc(buf, '\''); - break; - } - break; - case 't': /* tt token tag */ - tok = &(struct token) { va_arg(ap, int) }; - switch (tok->t) { - case TKNUMLIT: - n += bwriteS(buf, "numeric literal"); - break; - case TKSTRLIT: - n += bwriteS(buf, "string literal"); - break; - case TKIDENT: - n += bwriteS(buf, "identifier"); - break; - case TKEOF: - n += bwriteS(buf, "<end-of-file>"); - break; - default: - if (tok->t >= TKWBEGIN_ && tok->t <= TKWEND_) { - static const char *tab[] = { - #define _(kw, c, ...) #kw, - #include "c/keywords.def" - #undef _ - }; - tok->s = tab[tok->t - TKWBEGIN_]; - tok->len = strlen(tok->s); - } - goto Tok; - } - break; - case 'y': /* ty type */ - ty = va_arg(ap, union type); - n += fmttype(buf, ty, 0); - break; - case 'q': /* tq qualified type */ - ty = va_arg(ap, union type); - q = va_arg(ap, int); - n += fmttype(buf, ty, q); - break; - default: - if (fmt[-1] == ' ' || !aisprint(fmt[-1])) - fmterr("expected format specifier"); - else - fmterr("unknown format specifier 't%c'", fmt[-1]); - } - break; - case 'g': /* graphics rendition (color) */ - if (!ccopt.nocolor) n += bwriteS(buf, "\033["); - while (*fmt++ != '.') { - if (ccopt.nocolor) continue; - n += bputc(buf, fmt[-1]); - } - if (!ccopt.nocolor) n += bputc(buf, 'm'); - break; - case 'M': /* cc mode */ - iowrite(buf, &"C89\0C99\0C11\0C23"[ccopt.cstd*4], 3); - n += 3; - n += bwriteS(buf, " mode"); - break; - default: - if (umod || lmod) { - --fmt; - base = 10; - goto Int; - } - if (fmt[-1] == ' ' || !aisprint(fmt[-1])) - fmterr("expected format specifier"); - else - fmterr("unknown format specifier '%c'", fmt[-1]); - } - if (pad > 0) { /* left pad */ - while (pad-- > buf->len) - n += bputc(out, ' '); - assert(buf != out); - iowrite(out, buf->buf, buf->len); - out->err |= buf->err; - } else if (pad < 0) { /* right pad */ - int len = n - prevn; - while (pad++ < -len) - n += bputc(out, ' '); - } - } - return n; -} - -int -bfmt(struct wbuf *buf, const char *fmt, ...) -{ - va_list ap; - int ret; - - va_start(ap, fmt); - ret = vbfmt(buf, fmt, ap); - va_end(ap); - return ret; -} - -void -gpritype(union type ty) -{ - efmt("%ty\n", ty); - ioflush(&bstderr); -} - -static uint pagesiz; - -extern struct embedfile embedfilesdir[]; - -struct memfile -mapopen(const char **err, const char *path) -{ - struct stat stat; - int fd = -1; - void *p = NULL; - struct memfile f = {0}; - uint mapsiz; - - assert("nullp" && err && path); - - if (!pagesiz) pagesiz = sysconf(_SC_PAGESIZE); - *err = NULL; - - if (*path == '@' && path[1] == ':') { - for (struct embedfile *e = embedfilesdir; e->name; ++e) { - if (!strcmp(e->name, path+2)) { - return (struct memfile) { (const uchar *)e->s, e->len, .statik = 1 }; - } - } - } - - if ((fd = open(path, O_RDONLY)) < 0) - goto Err; - if (fstat(fd, &stat) != 0) - goto Err; - - if (S_ISREG(stat.st_mode)) { - if (stat.st_size > UINT_MAX) { - Big: - errno = EFBIG; - goto Err; - } - mapsiz = alignup(stat.st_size, pagesiz); - if ((p = mmap(NULL, mapsiz + pagesiz, PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0)) == MAP_FAILED) - goto Err; - if (mapsiz > 0 && mmap(p, mapsiz, PROT_READ, MAP_FIXED|MAP_PRIVATE, fd, 0) == MAP_FAILED) - goto Err; - - close(fd); - f.p = p; - f.n = stat.st_size; - return f; - } else if (S_ISFIFO(stat.st_mode) || S_ISCHR(stat.st_mode)) { - uint cap = 0; - int ret; - - do { - enum { CHUNKSIZ = 1<<10 }; - if (f.n + CHUNKSIZ >= cap && (cap += CHUNKSIZ) < CHUNKSIZ) { - /* overflow */ - free(p); - goto Big; - } - if (!(f.p = p ? realloc(p, cap) : malloc(cap))) { - free(p); - goto Err; - } - p = (void *)f.p; - ret = read(fd, (char *)p + f.n, CHUNKSIZ); - if (ret >= 0) - f.n += ret; - else if (errno != EAGAIN && errno != EWOULDBLOCK) - goto Err; - } while (ret != 0); - - close(fd); - fd = -1; - mapsiz = alignup(f.n, pagesiz); - if ((f.p = mmap(NULL, mapsiz + pagesiz, PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0)) == MAP_FAILED) { - free(p); - goto Err; - } - memcpy((void *)f.p, p, f.n); - free(p); - mprotect((void *)f.p, mapsiz + pagesiz, PROT_READ); - return f; - } else { - *err = "Not a file"; - } - -Err: - if (fd >= 0) close(fd); - if (!*err) *err = strerror(errno); - return f; -} - -void -mapclose(struct memfile *f) -{ - assert(f->p); - if (!f->statik) - munmap((void *)f->p, alignup(f->n, pagesiz) + pagesiz); - memset(f, 0, sizeof *f); -} - -void * -mapzeros(uint N) -{ - void *p = mmap(NULL, N, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - return p == MAP_FAILED ? NULL : p; -} - -void -_assertfmt(const char *file, int line, const char *func, const char *expr) -{ - ioflush(&bstdout); - efmt("%s:%d: %s: Assertion `%s' failed.\n", file, line, func, expr); - ioflush(&bstderr); -} - -struct fileuid { - long dev; - union { - long ino; - const char *str; - }; -}; - -/* one entry per #line */ -struct linemap { - int phys; - int toline; - const char *tofile; -}; - -static struct file { - struct fileuid uid; - const char *path; - struct memfile f; - vec_of(uint) lineoffs; - vec_of(struct linemap) linemap; - bool once; - bool seen; - internstr guardmac; -} *fileht[1<<SPANFILEBITS]; -static int nfiles; - -int -getpredeffile(struct memfile **pf, const char *name) -{ - struct file *f; - struct fileuid uid; - uint h, id, n = countof(fileht); - - uid.dev = -11; - uid.ino = hashs(0, name); - for (id = h = uid.dev ^ uid.ino;; ++id) { - id &= countof(fileht) - 1; - f = fileht[id]; - if (f && f->uid.dev == uid.dev && f->uid.ino == uid.ino) { - break; - } else if (!f) { - f = allocz(&globarena, sizeof *f, 0); - f->uid = uid; - f->path = name; - f->f = (struct memfile) { .statik = 1 }; - fileht[id] = f; - vinit(&f->lineoffs, NULL, 10); - vpush(&f->lineoffs, 0); - ++nfiles; - break; - } - assert(--n > 0 && "fileht full"); - } - *pf = &f->f; - return id; -} - -int -openfile(const char **err, struct memfile **pf, const char *path) -{ - struct stat st; - struct file *f; - struct fileuid uid; - size_t h, id, n = countof(fileht); - - if (*path == '@' && path[1] == ':') { - /* fast path to rule out filenames we know for sure aren't builtin */ - /* !KEEP SYNC with embedfilesdir */ - if (path[2] != 's' /* std*.h */ - && path[2] != 'f' /* float.h */) return -1; - uid.dev = -1; - uid.str = path; - h = hashs(0, path+2); - } else { - if (stat(path, &st) != 0) { - *err = strerror(errno); - return -1; - } - uid.dev = st.st_dev, uid.ino = st.st_ino; - h = uid.dev ^ uid.ino; - } - for (id = h;; ++id) { - id &= countof(fileht) - 1; - f = fileht[id]; - if (f && f->uid.dev == uid.dev && (uid.dev >= 0 ? f->uid.ino == uid.ino : !strcmp(f->uid.str, uid.str))) { - break; - } else if (!f) { - struct memfile m; - m = mapopen(err, path); - if (*err) return -1; - f = allocz(&globarena, sizeof *f, 0); - f->uid = uid; - f->path = path; - f->f = m; - fileht[id] = f; - vinit(&f->lineoffs, NULL, 50); - vpush(&f->lineoffs, 0); - ++nfiles; - break; - } - assert(--n > 0 && "fileht full"); - } - *pf = &f->f; - return id; -} - -const char * -getfilename(int id, uint atoff) -{ - assert((uint)id < countof(fileht) && fileht[id]); - if (!fileht[id]->linemap.n || !atoff) - return fileht[id]->path; - return getfilepos(NULL, NULL, id, atoff); -} - -struct memfile * -getfile(int id) -{ - assert((uint)id < countof(fileht) && fileht[id]); - return &fileht[id]->f; -} - -void -addfileline(int id, uint off) -{ - assert((uint)id < countof(fileht) && fileht[id]); - vec_of(uint) *lineoffs = (void *)&fileht[id]->lineoffs; - if (lineoffs->n && off > lineoffs->p[lineoffs->n-1]) - vpush(lineoffs, off); -} - -void -setfileline(int id, uint off, int line, const char *file) -{ - assert((uint)id < countof(fileht) && fileht[id]); - vec_of(struct linemap) *linemap = (void *)&fileht[id]->linemap; - vec_of(uint) *lineoffs = (void *)&fileht[id]->lineoffs; - int phys = 2; - for (int i = lineoffs->n-1; i >= 0; --i) { - if (lineoffs->p[i] < off) { - phys = i+2; - break; - } - } - if (linemap->n > 0) { - assert(linemap->p[linemap->n-1].phys < phys); - if (!file) file = linemap->p[linemap->n-1].tofile; - } - vpush(linemap, ((struct linemap){ phys, line, file })); -} - -const char * -getfilepos(int *pline, int *pcol, int id, uint off) -{ - assert((uint)id < countof(fileht) && fileht[id]); - uint *offs = fileht[id]->lineoffs.p; - uint n = fileht[id]->lineoffs.n; - /* binary search over offsets array */ - int l = 0, h = n - 1, i = 0; - while (l <= h) { - i = (l + h) / 2; - if (offs[i] < off) l = i + 1; - else if (offs[i] > off) h = i - 1; - else break; - } - i -= offs[i] > off; - int line = i + 1, col = off - offs[i] + 1; - const char *file = fileht[id]->path; - vec_of(struct linemap) *linemap = (void *)&fileht[id]->linemap; - if (linemap->n) { - /* binary search over linemap array */ - l = 0, h = linemap->n - 1, i = 0; - while (l <= h) { - i = (l + h) / 2; - if (linemap->p[i].phys < line) l = i + 1; - else if (linemap->p[i].phys > line) h = i - 1; - else break; - } - i -= linemap->p[i].phys > line; - if (i >= 0) { - line = linemap->p[i].toline + (line - linemap->p[i].phys); - if (linemap->p[i].tofile) file = linemap->p[i].tofile; - } - } - if (pline) *pline = line; - if (pcol) *pcol = col; - return file; -} - -bool -isoncefile(int id, internstr *guard) -{ - assert(id < countof(fileht) && fileht[id]); - *guard = fileht[id]->guardmac; - return fileht[id]->once; -} - -void -markfileonce(int id, internstr guard) -{ - assert(id < countof(fileht) && fileht[id]); - fileht[id]->once = 1; - fileht[id]->guardmac = guard; -} - -void -markfileseen(int id) -{ - assert(id < countof(fileht) && fileht[id]); - fileht[id]->seen = 1; -} - -bool -isfileseen(int id) -{ - assert(id < countof(fileht) && fileht[id]); - return fileht[id]->seen; -} - -void -closefile(int id) -{ - assert(id < countof(fileht) && fileht[id]); - mapclose(&fileht[id]->f); -} - -void -vdiag(const struct span *span, enum diagkind kind, const char *fmt, va_list ap) -{ - /* to avoid concurrent invocations of the compiler mixing up the diagnostics - * in the unbuffered stderr output, use a separate buffer here and write() - * it all out bypassing stdio */ - static char ebuf[4096]; - static struct wbuf out = FDBUF(ebuf, sizeof ebuf, STDERR_FILENO); - static int depth = 0; /* needed for nested note() calls */ - - static const char *label[] = { "error", "warning", "note" }; - static const char *color[] = { "%g1;31.", "%g1;35.", "%g1;36." }; - int line, col; - struct memfile *f; - const struct span0 *loc; - - ++depth; - if (span) { - loc = span->ex.len ? &span->ex : &span->sl; - f = getfile(loc->file); - const char *file = getfilepos(&line, &col, loc->file, loc->off); - bfmt(&out, "%s:%d:%d: ", file, line, col); - } - bfmt(&out, color[kind]); - bfmt(&out, "%s: %g.", label[kind]); - vbfmt(&out, fmt, ap); - bfmt(&out, "\n"); - if (span) { - uint i; - int nmark; - char mark = '^'; - - /* find start of line */ - for (i = loc->off - 1; i + 1 > 0 && f->p[i] != '\n'; --i) ; - if (i || f->p[i] == '\n') ++i; - - nmark = loc->len; - while (i < loc->off + loc->len) { - int j, end; - int curoff = bfmt(&out, "%5d | ", line); - const uchar *linep = &f->p[i]; - bool begintabs = 1; - for (end = 0; f->p[i] != '\n' && i < f->n; ++i, ++end) { - uchar c = f->p[i]; - if (c == '\t') { - if (!begintabs) c = ' '; - } else { - begintabs = 0; - } - ioputc(&out, c); - } - ioputc(&out, '\n'); - ++i; - - for (j = -curoff; j < 0; ++j) - ioputc(&out, j == -2 ? '|' : ' '); - for (begintabs = 1; j < col-1; ++j) { - uchar c = *linep++; - if (c == '\t') { - if (!begintabs) c = ' '; - } else { - c = ' '; - begintabs = 0; - } - ioputc(&out, c); - } - bfmt(&out, color[kind]); - do { - ioputc(&out, mark); - mark = '~'; - } while (--nmark > 0 && ++j < end); - col = 1; - ++line; - bfmt(&out, "%g.\n"); - --nmark; - } - ioputc(&out, '\n'); - } - - if (span && loc == &span->ex && span->sl.len) - if (span->ex.file != span->sl.file || !((uint) span->sl.off - span->ex.off < span->ex.len)) - note(&(struct span){ span->sl }, "expanded from here"); - - if (--depth == 0) ioflush(&out); -} - -void _Noreturn -fatal(const struct span *span, const char *fmt, ...) -{ - if (fmt) { - va_list ap; - va_start(ap, fmt); - vdiag(span, DGERROR, fmt, ap); - va_end(ap); - } - if (!fmt || span) efmt("Aborting due to previous error.\n"); - exit(1); -} - -int nerror, nwarn; -enum { MAXERROR = 20 }; - -void -error(const struct span *span, const char *fmt, ...) -{ - va_list ap; - - ++nerror; - va_start(ap, fmt); - vdiag(span, DGERROR, fmt, ap); - va_end(ap); - if (nerror > MAXERROR) { - efmt("Too many errors emitted, stopping now.\n"); - exit(1); - } -} - -void -warn(const struct span *span, const char *fmt, ...) -{ - va_list ap; - - if (ccopt.wnone) return; - if (ccopt.werror) ++nerror; - else ++nwarn; - va_start(ap, fmt); - vdiag(span, ccopt.werror ? DGERROR : DGWARN, fmt, ap); - va_end(ap); - if (nerror > MAXERROR) { - efmt("Too many errors emitted, stopping now.\n"); - exit(1); - } -} - -void -note(const struct span *span, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vdiag(span, DGNOTE, fmt, ap); - va_end(ap); -} - -/*** UTF util ***/ - -ushort * -utf8to16(uint *ulen, struct arena **arena, const uchar *s, size_t len) -{ - assert(0 && "nyi"); -} - -uint * -utf8to32(uint *ulen, struct arena **arena, const uchar *s, size_t len) -{ - uint *ret, *w; - const uchar *p, *end; - size_t n = 0; - bool istrunc; - - if (!len) return NULL; - - for (p = end = s; p < s + len; ++n) { - end = p; - if ((*p & 0xF8) == 0xF0) /* 11110xxx */ - p += 4; - else if ((*p & 0xF0) == 0xE0) /* 1110xxxx */ - p += 3; - else if ((*p & 0xE0) == 0xC0) /* 110xxxxx */ - p += 2; - else p += 1; - } - istrunc = p > s+len; - if (!istrunc) end += 1; - - ret = allocz(arena, n * sizeof *ret, sizeof *ret); - for (w = ret, p = s; p < end; ++w) { - if ((*p & 0xF8) == 0xF0) { /* 11110xxx */ - *w = (uint)(p[0] & 0x07) << 18 - | (uint)(p[1] & 0x3F) << 12 - | (uint)(p[2] & 0x3F) << 6 - | (uint)(p[3] & 0x3F); - p += 4; - } else if ((*p & 0xF0) == 0xE0) { /* 1110xxxx */ - *w = (uint)(p[0] & 0x07) << 12 - | (uint)(p[1] & 0x3F) << 6 - | (uint)(p[2] & 0x3F); - p += 3; - } else if ((*p & 0xE0) == 0xC0) { /* 110xxxxx */ - *w = (uint)(p[0] & 0x07) << 6 - | (uint)(p[1] & 0x3F); - p += 2; - } else { - *w = *p; - p += 1; - } - } - if (istrunc) *w++ = 0xFFFD; - *ulen = n; - - return ret; -} - -int -utf8enc(char p[4], uint cp) -{ - if ((cp & 0xffffff80) == 0) { - p[0] = cp; - return 1; - } else if ((cp & 0xfffff800) == 0) { - p[0] = 0xC0 | (cp >> 6 & 0x1F); - p[1] = 0x80 | (cp & 0x3F); - return 2; - } else if ((cp & 0xffff0000) == 0) { - p[0] = 0xE0 | (cp >> 12 & 0x0F); - p[1] = 0x80 | (cp >> 6 & 0x3F); - p[2] = 0x80 | (cp & 0x3F); - return 3; - } else { - p[0] = 0xF0 | (cp >> 18 & 0x07); - p[1] = 0x80 | (cp >> 12 & 0x3F); - p[2] = 0x80 | (cp >> 6 & 0x3F); - p[3] = 0x80 | (cp & 0x3F); - return 4; - } -} - -/* vim:set ts=3 sw=3 expandtab: */ |