aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/io.c
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2026-03-17 13:43:05 +0100
committerlemon <lsof@mailbox.org>2026-03-17 16:10:00 +0100
commit3eeb6f219e4d32160fa10895b57a8ddfefff5ff7 (patch)
treefebb6021a9e4a8593bd67402b25082b2f7109f72 /src/io.c
parenta8d6f8bf30c07edb775e56889f568ca20240bedf (diff)
REFACTOR: finish renaming
Diffstat (limited to 'src/io.c')
-rw-r--r--src/io.c1255
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: */