build: separate package identity from storage paths
This commit is contained in:
12
Makefile
12
Makefile
@@ -55,6 +55,10 @@ WWTEST_BIN = $(BIN)/wwtest
|
|||||||
WWTEST_SRC = cmd/wwtest/wwtest.ww \
|
WWTEST_SRC = cmd/wwtest/wwtest.ww \
|
||||||
internal/wwpackage/package.ww lib/os/exec/exec.ww \
|
internal/wwpackage/package.ww lib/os/exec/exec.ww \
|
||||||
lib/ascii/ascii.ww lib/bytes/bytes.ww \
|
lib/ascii/ascii.ww lib/bytes/bytes.ww \
|
||||||
|
lib/crypto/math/math.ww lib/crypto/sha256/sha256.ww \
|
||||||
|
lib/endian/big.ww lib/endian/little.ww lib/endian/network.ww \
|
||||||
|
lib/errors/errors.ww lib/hash/hash.ww \
|
||||||
|
lib/io/empty.ww lib/io/io.ww lib/io/stream.ww lib/io/types.ww \
|
||||||
lib/encoding/utf8/utf8.ww lib/math/floats.ww lib/math/math.ww \
|
lib/encoding/utf8/utf8.ww lib/math/floats.ww lib/math/math.ww \
|
||||||
lib/os/os.ww lib/rt/malloc.ww \
|
lib/os/os.ww lib/rt/malloc.ww \
|
||||||
lib/strconv/decimal.ww lib/strconv/ftos.ww lib/strconv/ftos_data.ww \
|
lib/strconv/decimal.ww lib/strconv/ftos.ww lib/strconv/ftos_data.ww \
|
||||||
@@ -99,6 +103,10 @@ PACKAGE_TEST_BIN = $(BIN)/test_package
|
|||||||
PACKAGE_TEST_SRC = test/package/package_test.ww lib/os/exec/exec.ww \
|
PACKAGE_TEST_SRC = test/package/package_test.ww lib/os/exec/exec.ww \
|
||||||
lib/test/run.ww lib/fnmatch/fnmatch.ww \
|
lib/test/run.ww lib/fnmatch/fnmatch.ww \
|
||||||
lib/ascii/ascii.ww lib/bytes/bytes.ww \
|
lib/ascii/ascii.ww lib/bytes/bytes.ww \
|
||||||
|
lib/crypto/math/math.ww lib/crypto/sha256/sha256.ww \
|
||||||
|
lib/endian/big.ww lib/endian/little.ww lib/endian/network.ww \
|
||||||
|
lib/errors/errors.ww lib/hash/hash.ww \
|
||||||
|
lib/io/empty.ww lib/io/io.ww lib/io/stream.ww lib/io/types.ww \
|
||||||
lib/encoding/utf8/utf8.ww lib/os/os.ww lib/rt/malloc.ww \
|
lib/encoding/utf8/utf8.ww lib/os/os.ww lib/rt/malloc.ww \
|
||||||
lib/strings/strings.ww lib/temp/temp.ww lib/time/time.ww \
|
lib/strings/strings.ww lib/temp/temp.ww lib/time/time.ww \
|
||||||
lib/types/types.ww
|
lib/types/types.ww
|
||||||
@@ -256,6 +264,10 @@ $(BIN)/w6l_ww: selfhost/cmd/w6l/main.ww selfhost/cmd/w6l/sym.ww \
|
|||||||
$(BIN)/ww_ww: selfhost/cmd/ww/main.ww lib/os/exec/exec.ww \
|
$(BIN)/ww_ww: selfhost/cmd/ww/main.ww lib/os/exec/exec.ww \
|
||||||
lib/os/os.ww lib/rt/malloc.ww \
|
lib/os/os.ww lib/rt/malloc.ww \
|
||||||
lib/time/time.ww lib/types/types.ww \
|
lib/time/time.ww lib/types/types.ww \
|
||||||
|
lib/crypto/math/math.ww lib/crypto/sha256/sha256.ww \
|
||||||
|
lib/endian/big.ww lib/endian/little.ww lib/endian/network.ww \
|
||||||
|
lib/errors/errors.ww lib/hash/hash.ww \
|
||||||
|
lib/io/empty.ww lib/io/io.ww lib/io/stream.ww lib/io/types.ww \
|
||||||
lib/strings/strings.ww lib/bytes/bytes.ww lib/encoding/utf8/utf8.ww \
|
lib/strings/strings.ww lib/bytes/bytes.ww lib/encoding/utf8/utf8.ww \
|
||||||
lib/ww/syntax/lex.ww lib/ww/syntax/tok.ww lib/ww/syntax/ast.ww \
|
lib/ww/syntax/lex.ww lib/ww/syntax/tok.ww lib/ww/syntax/ast.ww \
|
||||||
lib/ww/syntax/parse.ww lib/ww/syntax/expr.ww \
|
lib/ww/syntax/parse.ww lib/ww/syntax/expr.ww \
|
||||||
|
|||||||
124
cmd/w6a/parse.c
124
cmd/w6a/parse.c
@@ -50,16 +50,20 @@ a_intern(Asm *a, const char *name)
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* line iterator: returns the next line as a NUL-terminated buffer in
|
|
||||||
* line/llen pointers, advances pos. Returns 0 on EOF.
|
|
||||||
*/
|
|
||||||
static int
|
static int
|
||||||
nextline(Asm *a, char **line, size_t *llen, char *buf, size_t bufsz)
|
nextline(Asm *a, char **line, size_t *llen)
|
||||||
{
|
{
|
||||||
if (a->pos >= a->srclen) return 0;
|
if (a->pos >= a->srclen) return 0;
|
||||||
size_t n = 0;
|
u64 start = a->pos;
|
||||||
while (a->pos < a->srclen && a->src[a->pos] != '\n' && n + 1 < bufsz)
|
while (a->pos < a->srclen && a->src[a->pos] != '\n') a->pos++;
|
||||||
buf[n++] = a->src[a->pos++];
|
size_t n = (size_t)(a->pos - start);
|
||||||
|
char *buf = malloc(n + 1);
|
||||||
|
if (buf == NULL) {
|
||||||
|
err(a, "out of memory");
|
||||||
|
a->pos = a->srclen;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memcpy(buf, a->src + start, n);
|
||||||
buf[n] = '\0';
|
buf[n] = '\0';
|
||||||
if (a->pos < a->srclen && a->src[a->pos] == '\n') a->pos++;
|
if (a->pos < a->srclen && a->src[a->pos] == '\n') a->pos++;
|
||||||
*line = buf;
|
*line = buf;
|
||||||
@@ -206,10 +210,13 @@ parse_operand(Asm *a, const char *s, Aoperand *out)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (a_isidstart((unsigned char)*s)) {
|
if (a_isidstart((unsigned char)*s)) {
|
||||||
char buf[256] = {0};
|
const char *start = s;
|
||||||
int n = 0;
|
while (a_isidcont((unsigned char)*s)) s++;
|
||||||
while (a_isidcont((unsigned char)*s) && n < 255) buf[n++] = *s++;
|
size_t n = (size_t)(s - start);
|
||||||
buf[n] = 0;
|
char *name = malloc(n + 1);
|
||||||
|
if (name == NULL) { err(a, "out of memory"); return -1; }
|
||||||
|
memcpy(name, start, n);
|
||||||
|
name[n] = 0;
|
||||||
|
|
||||||
/* Optional `+disp` between the ident and `(SB)`. Used by
|
/* Optional `+disp` between the ident and `(SB)`. Used by
|
||||||
* DATAR to address bytes inside an existing .data slot
|
* DATAR to address bytes inside an existing .data slot
|
||||||
@@ -227,12 +234,16 @@ parse_operand(Asm *a, const char *s, Aoperand *out)
|
|||||||
int rn = 0;
|
int rn = 0;
|
||||||
s++;
|
s++;
|
||||||
while (*s && *s != ')' && rn < 7) rbuf[rn++] = *s++;
|
while (*s && *s != ')' && rn < 7) rbuf[rn++] = *s++;
|
||||||
if (*s != ')') { err(a, "missing ')'"); return -1; }
|
if (*s != ')') {
|
||||||
|
err(a, "missing ')'");
|
||||||
|
free(name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
s++;
|
s++;
|
||||||
int r = reg_lookup(rbuf);
|
int r = reg_lookup(rbuf);
|
||||||
if (r == D_PSB) {
|
if (r == D_PSB) {
|
||||||
out->type = D_EXTERN;
|
out->type = D_EXTERN;
|
||||||
out->sym = strdup(buf);
|
out->sym = name;
|
||||||
out->offset = sym_disp;
|
out->offset = sym_disp;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -241,16 +252,18 @@ parse_operand(Asm *a, const char *s, Aoperand *out)
|
|||||||
* reg_lookup and silently discarded the ident and
|
* reg_lookup and silently discarded the ident and
|
||||||
* +disp (rule 7). */
|
* +disp (rule 7). */
|
||||||
err(a, "unsupported name(reg) operand");
|
err(a, "unsupported name(reg) operand");
|
||||||
|
free(name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int r = reg_lookup(buf);
|
int r = reg_lookup(name);
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
out->type = r;
|
out->type = r;
|
||||||
|
free(name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
out->type = D_BRANCH;
|
out->type = D_BRANCH;
|
||||||
out->sym = strdup(buf);
|
out->sym = name;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,17 +274,14 @@ parse_operand(Asm *a, const char *s, Aoperand *out)
|
|||||||
int
|
int
|
||||||
a_parse(Asm *a)
|
a_parse(Asm *a)
|
||||||
{
|
{
|
||||||
/* Big enough for a DATAW emitting a [256]u32 table (1024 bytes
|
|
||||||
* → ~4100 chars of `\xNN` escapes plus directive boilerplate).
|
|
||||||
* Selfhost w6a allocates per-line; this is the cstage equivalent. */
|
|
||||||
static char buf[32768];
|
|
||||||
char *line;
|
char *line;
|
||||||
size_t len;
|
size_t len;
|
||||||
const char *pending_label = NULL;
|
const char *pending_label = NULL;
|
||||||
|
|
||||||
while (nextline(a, &line, &len, buf, sizeof buf)) {
|
while (nextline(a, &line, &len)) {
|
||||||
const char *p = skipws(line);
|
const char *p = skipws(line);
|
||||||
if (*p == '\0' || (*p == '/' && p[1] == '/')) {
|
if (*p == '\0' || (*p == '/' && p[1] == '/')) {
|
||||||
|
free(line);
|
||||||
a->line++;
|
a->line++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -282,6 +292,11 @@ a_parse(Asm *a)
|
|||||||
if (*q == ':') {
|
if (*q == ':') {
|
||||||
size_t nl = q - p;
|
size_t nl = q - p;
|
||||||
char *name = malloc(nl + 1);
|
char *name = malloc(nl + 1);
|
||||||
|
if (name == NULL) {
|
||||||
|
err(a, "out of memory");
|
||||||
|
free(line);
|
||||||
|
return a->errs;
|
||||||
|
}
|
||||||
memcpy(name, p, nl);
|
memcpy(name, p, nl);
|
||||||
name[nl] = '\0';
|
name[nl] = '\0';
|
||||||
/* If a label is already pending we'd lose it
|
/* If a label is already pending we'd lose it
|
||||||
@@ -297,6 +312,7 @@ a_parse(Asm *a)
|
|||||||
a->tail = prg;
|
a->tail = prg;
|
||||||
}
|
}
|
||||||
pending_label = name;
|
pending_label = name;
|
||||||
|
free(line);
|
||||||
a->line++;
|
a->line++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -311,6 +327,7 @@ a_parse(Asm *a)
|
|||||||
int op = opcode_lookup(mnem);
|
int op = opcode_lookup(mnem);
|
||||||
if (op == 0) {
|
if (op == 0) {
|
||||||
err(a, "unknown opcode");
|
err(a, "unknown opcode");
|
||||||
|
free(line);
|
||||||
a->line++;
|
a->line++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -322,14 +339,20 @@ a_parse(Asm *a)
|
|||||||
pending_label = NULL;
|
pending_label = NULL;
|
||||||
|
|
||||||
while (*m == ' ' || *m == '\t') m++;
|
while (*m == ' ' || *m == '\t') m++;
|
||||||
const char *rest = m;
|
char *rest = (char *)m;
|
||||||
|
|
||||||
if (op == A_TEXT) {
|
if (op == A_TEXT) {
|
||||||
char nbuf[256] = {0};
|
const char *start = m;
|
||||||
int nn = 0;
|
while (*m && *m != ',') m++;
|
||||||
while (*m && *m != ',' && nn < 255) nbuf[nn++] = *m++;
|
size_t nn = (size_t)(m - start);
|
||||||
|
char *name = malloc(nn + 1);
|
||||||
|
if (name == NULL) {
|
||||||
|
err(a, "out of memory"); free(line); return a->errs;
|
||||||
|
}
|
||||||
|
memcpy(name, start, nn);
|
||||||
|
name[nn] = 0;
|
||||||
prg->to.type = D_EXTERN;
|
prg->to.type = D_EXTERN;
|
||||||
prg->to.sym = strdup(nbuf);
|
prg->to.sym = name;
|
||||||
if (*m == ',') {
|
if (*m == ',') {
|
||||||
m++;
|
m++;
|
||||||
while (*m == ' ' || *m == '$') m++;
|
while (*m == ' ' || *m == '$') m++;
|
||||||
@@ -339,11 +362,17 @@ a_parse(Asm *a)
|
|||||||
} else if (op == A_DATA || op == A_DATAW) {
|
} else if (op == A_DATA || op == A_DATAW) {
|
||||||
/* DATA name(SB),"escaped bytes" — read-only in .text
|
/* DATA name(SB),"escaped bytes" — read-only in .text
|
||||||
* DATAW name(SB),"escaped bytes" — writable in .data */
|
* DATAW name(SB),"escaped bytes" — writable in .data */
|
||||||
char nbuf[256] = {0};
|
const char *start = m;
|
||||||
int nn = 0;
|
while (*m && *m != '(') m++;
|
||||||
while (*m && *m != '(' && nn < 255) nbuf[nn++] = *m++;
|
size_t nn = (size_t)(m - start);
|
||||||
|
char *name = malloc(nn + 1);
|
||||||
|
if (name == NULL) {
|
||||||
|
err(a, "out of memory"); free(line); return a->errs;
|
||||||
|
}
|
||||||
|
memcpy(name, start, nn);
|
||||||
|
name[nn] = 0;
|
||||||
prg->to.type = D_EXTERN;
|
prg->to.type = D_EXTERN;
|
||||||
prg->to.sym = strdup(nbuf);
|
prg->to.sym = name;
|
||||||
if (*m == '(') {
|
if (*m == '(') {
|
||||||
while (*m && *m != ')') m++;
|
while (*m && *m != ')') m++;
|
||||||
if (*m == ')') m++;
|
if (*m == ')') m++;
|
||||||
@@ -357,6 +386,9 @@ a_parse(Asm *a)
|
|||||||
m++;
|
m++;
|
||||||
size_t cap = 32, len = 0;
|
size_t cap = 32, len = 0;
|
||||||
u8 *buf = malloc(cap);
|
u8 *buf = malloc(cap);
|
||||||
|
if (buf == NULL) {
|
||||||
|
err(a, "out of memory"); free(line); return a->errs;
|
||||||
|
}
|
||||||
while (*m && *m != '"') {
|
while (*m && *m != '"') {
|
||||||
int c = (unsigned char)*m++;
|
int c = (unsigned char)*m++;
|
||||||
if (c == '\\' && *m) {
|
if (c == '\\' && *m) {
|
||||||
@@ -381,7 +413,12 @@ a_parse(Asm *a)
|
|||||||
}
|
}
|
||||||
if (len + 1 > cap) {
|
if (len + 1 > cap) {
|
||||||
cap *= 2;
|
cap *= 2;
|
||||||
buf = realloc(buf, cap);
|
u8 *next = realloc(buf, cap);
|
||||||
|
if (next == NULL) {
|
||||||
|
free(buf); err(a, "out of memory");
|
||||||
|
free(line); return a->errs;
|
||||||
|
}
|
||||||
|
buf = next;
|
||||||
}
|
}
|
||||||
buf[len++] = (u8)c;
|
buf[len++] = (u8)c;
|
||||||
}
|
}
|
||||||
@@ -389,27 +426,30 @@ a_parse(Asm *a)
|
|||||||
prg->nbytes = len;
|
prg->nbytes = len;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const char *comma = NULL;
|
int operand_bad = 0;
|
||||||
for (const char *q = rest; *q; q++)
|
char *comma = NULL;
|
||||||
|
for (char *q = rest; *q; q++)
|
||||||
if (*q == ',' && comma == NULL) comma = q;
|
if (*q == ',' && comma == NULL) comma = q;
|
||||||
if (comma) {
|
if (comma) {
|
||||||
char op1[256], op2[256];
|
*comma = '\0';
|
||||||
size_t l1 = comma - rest;
|
if (parse_operand(a, rest, &prg->from) < 0
|
||||||
if (l1 >= sizeof op1) l1 = sizeof op1 - 1;
|
|| parse_operand(a, comma + 1, &prg->to) < 0)
|
||||||
memcpy(op1, rest, l1); op1[l1] = '\0';
|
operand_bad = 1;
|
||||||
size_t l2 = strlen(comma + 1);
|
|
||||||
if (l2 >= sizeof op2) l2 = sizeof op2 - 1;
|
|
||||||
memcpy(op2, comma + 1, l2); op2[l2] = '\0';
|
|
||||||
parse_operand(a, op1, &prg->from);
|
|
||||||
parse_operand(a, op2, &prg->to);
|
|
||||||
} else if (*rest) {
|
} else if (*rest) {
|
||||||
parse_operand(a, rest, &prg->to);
|
if (parse_operand(a, rest, &prg->to) < 0)
|
||||||
|
operand_bad = 1;
|
||||||
|
}
|
||||||
|
if (operand_bad) {
|
||||||
|
free(line);
|
||||||
|
a->line++;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a->head == NULL) a->head = prg;
|
if (a->head == NULL) a->head = prg;
|
||||||
else a->tail->link = prg;
|
else a->tail->link = prg;
|
||||||
a->tail = prg;
|
a->tail = prg;
|
||||||
|
free(line);
|
||||||
a->line++;
|
a->line++;
|
||||||
}
|
}
|
||||||
return a->errs;
|
return a->errs;
|
||||||
|
|||||||
@@ -22,6 +22,18 @@ slurp(const char *path, char **outbuf, u64 *outlen)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
export_owner_matches(const char *buf, u64 len, const char *path)
|
||||||
|
{
|
||||||
|
static const char prefix[] = "//ww:module ";
|
||||||
|
size_t pn = strlen(path);
|
||||||
|
size_t need = sizeof prefix - 1 + pn + 1;
|
||||||
|
return len >= need
|
||||||
|
&& memcmp(buf, prefix, sizeof prefix - 1) == 0
|
||||||
|
&& memcmp(buf + sizeof prefix - 1, path, pn) == 0
|
||||||
|
&& buf[need - 1] == '\n';
|
||||||
|
}
|
||||||
|
|
||||||
struct importin {
|
struct importin {
|
||||||
const char *path;
|
const char *path;
|
||||||
const char *file;
|
const char *file;
|
||||||
@@ -164,6 +176,13 @@ main(int argc, char **argv)
|
|||||||
imports[i].path, imports[i].file);
|
imports[i].path, imports[i].file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if (!export_owner_matches(imports[i].buf, imports[i].len,
|
||||||
|
imports[i].path)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"w6c: import %s: export owner mismatch in %s\n",
|
||||||
|
imports[i].path, imports[i].file);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
int bad = 0;
|
int bad = 0;
|
||||||
Node *f = parseinput(a, imports[i].file, imports[i].buf,
|
Node *f = parseinput(a, imports[i].file, imports[i].buf,
|
||||||
imports[i].len, imports[i].path, testsupport, 0, &bad);
|
imports[i].len, imports[i].path, testsupport, 0, &bad);
|
||||||
|
|||||||
@@ -864,6 +864,8 @@ wwi_emit(Checker *c, FILE *of, Node *file)
|
|||||||
const char *dot = strrchr(file->module, '.');
|
const char *dot = strrchr(file->module, '.');
|
||||||
pkg = dot ? dot + 1 : file->module;
|
pkg = dot ? dot + 1 : file->module;
|
||||||
}
|
}
|
||||||
|
if (file->module != NULL && file->module[0] != '\0')
|
||||||
|
fprintf(of, "//ww:module %s\n", file->module);
|
||||||
fprintf(of, "package %s;\n", pkg);
|
fprintf(of, "package %s;\n", pkg);
|
||||||
|
|
||||||
/* imports — primary N_USE, byte-sorted by import path. */
|
/* imports — primary N_USE, byte-sorted by import path. */
|
||||||
|
|||||||
@@ -82,9 +82,8 @@ resolve_typename(Checker *c, Node *n)
|
|||||||
* same name as the module itself (e.g. `random.random`). */
|
* same name as the module itself (e.g. `random.random`). */
|
||||||
const char *dot = strrchr(nm, '.');
|
const char *dot = strrchr(nm, '.');
|
||||||
if (dot) {
|
if (dot) {
|
||||||
char head[128] = {0};
|
|
||||||
size_t hl = (size_t)(dot - nm);
|
size_t hl = (size_t)(dot - nm);
|
||||||
if (hl < sizeof head) memcpy(head, nm, hl);
|
char *head = astrndup(c->a, nm, hl);
|
||||||
Sym *m = scope_lookup(c->cur, head);
|
Sym *m = scope_lookup(c->cur, head);
|
||||||
if (m && (m->kind == SK_USE || m->use_alias)) {
|
if (m && (m->kind == SK_USE || m->use_alias)) {
|
||||||
/* M1 #22: map the qualifier alias to its dotted
|
/* M1 #22: map the qualifier alias to its dotted
|
||||||
|
|||||||
1073
cmd/ww/main.c
1073
cmd/ww/main.c
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,7 @@
|
|||||||
package wwpackage;
|
package wwpackage;
|
||||||
|
|
||||||
|
import crypto.sha256;
|
||||||
|
import hash;
|
||||||
import os;
|
import os;
|
||||||
import os.exec;
|
import os.exec;
|
||||||
import strconv;
|
import strconv;
|
||||||
@@ -269,9 +271,9 @@ fn pkgkeepfile(name: str) bool = {
|
|||||||
|
|
||||||
// One explicit package directory; with recurse (the DIR/... form) every
|
// One explicit package directory; with recurse (the DIR/... form) every
|
||||||
// subdirectory whose name does not begin with '.' or '_' is descended as
|
// subdirectory whose name does not begin with '.' or '_' is descended as
|
||||||
// well, Go's ./... convention. lstat is used for the root and each
|
// well, Go's ./... convention. An explicitly selected root may be a symlink;
|
||||||
// candidate so a symlink cannot be used to cross the boundary (including
|
// canonical planning coalesces it with the target directory. Recursive child
|
||||||
// DT_UNKNOWN files); a symlinked subdirectory is skipped, not followed.
|
// symlinks remain skipped and symlink source files remain rejected.
|
||||||
fn pkgdiscoverdir(path: str, st: *pkgdiscover, recurse: bool) void = {
|
fn pkgdiscoverdir(path: str, st: *pkgdiscover, recurse: bool) void = {
|
||||||
let rootstat: os.filestat;
|
let rootstat: os.filestat;
|
||||||
match (os.lstat(&rootstat, path)) {
|
match (os.lstat(&rootstat, path)) {
|
||||||
@@ -283,9 +285,14 @@ fn pkgdiscoverdir(path: str, st: *pkgdiscover, recurse: bool) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (pkgmodeis(rootstat.mode, os.mode.LINK)) {
|
if (pkgmodeis(rootstat.mode, os.mode.LINK)) {
|
||||||
pkgfailpath(path, "symlink traversal is not allowed");
|
match (os.stat(&rootstat, path)) {
|
||||||
st.errors += 1;
|
case void => void;
|
||||||
return;
|
case let e: os.oserror => {
|
||||||
|
pkgfailpath(path, "cannot stat package directory");
|
||||||
|
st.errors += 1;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
if (!pkgmodeis(rootstat.mode, os.mode.DIR)) {
|
if (!pkgmodeis(rootstat.mode, os.mode.DIR)) {
|
||||||
pkgfailpath(path, "expected one package directory");
|
pkgfailpath(path, "expected one package directory");
|
||||||
@@ -540,7 +547,25 @@ fn pkgworkescape(s: str) str = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fn pkgworkkey(dir: str) str = {
|
fn pkgworkkey(dir: str) str = {
|
||||||
return strings.concat("d_", pkgworkescape(dir));
|
let escaped: str = strings.concat("d_", pkgworkescape(dir));
|
||||||
|
if (escaped.len <= 255) { return escaped; };
|
||||||
|
let state: sha256.state = sha256.sha256();
|
||||||
|
let h: *hash.hash = (&state): *hash.hash;
|
||||||
|
hash.write(h, strings.toutf8("ww-request-workdir-v1:"));
|
||||||
|
hash.write(h, strings.toutf8(dir));
|
||||||
|
let digest: [32]u8;
|
||||||
|
hash.sum(h, digest[0:32]);
|
||||||
|
let out: []u8 = alloc([], 65u64)!;
|
||||||
|
let digits: str = "0123456789abcdef";
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < 32) {
|
||||||
|
let high: i32 = (digest[i] / 16u8): i32;
|
||||||
|
let low: i32 = (digest[i] % 16u8): i32;
|
||||||
|
append(out, digits[high]);
|
||||||
|
append(out, digits[low]);
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
return strings.concat("d_", strings.frombytes(out));
|
||||||
};
|
};
|
||||||
|
|
||||||
fn pkgsetplanpaths(p: *pkgplan, groups: []pkggroup, root: str, index: i32,
|
fn pkgsetplanpaths(p: *pkgplan, groups: []pkggroup, root: str, index: i32,
|
||||||
|
|||||||
@@ -629,7 +629,9 @@ export fn parsefile(p: *parser) *node = {
|
|||||||
|| strings.compare(name, "main_test") == 0);
|
|| strings.compare(name, "main_test") == 0);
|
||||||
if (strings.compare(name, last) != 0 && !testsupport
|
if (strings.compare(name, last) != 0 && !testsupport
|
||||||
&& !commandpackage) {
|
&& !commandpackage) {
|
||||||
errmsg(p, "package does not match import path");
|
errmsg(p, strings.concat(strings.concat(strings.concat(
|
||||||
|
"package ", name),
|
||||||
|
" does not match import path "), active));
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
p.curmod = name;
|
p.curmod = name;
|
||||||
|
|||||||
@@ -60,6 +60,25 @@ fn slurp(path: *u8) (*u8, u64) = {
|
|||||||
return buf.ptr, nz;
|
return buf.ptr, nz;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn exportownermatches(buf: *u8, n: u64, path: *u8) bool = {
|
||||||
|
let prefix: str = "//ww:module ";
|
||||||
|
let pn: u64 = cstrlen(path);
|
||||||
|
let poff: u64 = prefix.len: u64;
|
||||||
|
let need: u64 = poff + pn + 1u64;
|
||||||
|
if (n < need) { return false; };
|
||||||
|
let i: u64 = 0u64;
|
||||||
|
for (i < poff) {
|
||||||
|
if (buf[i] != prefix.ptr[i]) { return false; };
|
||||||
|
i += 1u64;
|
||||||
|
};
|
||||||
|
i = 0u64;
|
||||||
|
for (i < pn) {
|
||||||
|
if (buf[poff + i] != path[i]) { return false; };
|
||||||
|
i += 1u64;
|
||||||
|
};
|
||||||
|
return buf[need - 1u64] == 10u8;
|
||||||
|
};
|
||||||
|
|
||||||
export fn main(argc: i32, argv: **u8) i32 = {
|
export fn main(argc: i32, argv: **u8) i32 = {
|
||||||
let src: *u8 = nil;
|
let src: *u8 = nil;
|
||||||
let out: *u8 = nil;
|
let out: *u8 = nil;
|
||||||
@@ -204,6 +223,17 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
os.write(2, nl.ptr, nl.len: u64);
|
os.write(2, nl.ptr, nl.len: u64);
|
||||||
return 1;
|
return 1;
|
||||||
};
|
};
|
||||||
|
if (!exportownermatches(ibuf, ilen, importpaths[importi])) {
|
||||||
|
let pre: str = "w6c: import ";
|
||||||
|
let mid: str = ": export owner mismatch in ";
|
||||||
|
let nl: str = "\n";
|
||||||
|
os.write(2, pre.ptr, pre.len: u64);
|
||||||
|
os.write(2, importpaths[importi], cstrlen(importpaths[importi]));
|
||||||
|
os.write(2, mid.ptr, mid.len: u64);
|
||||||
|
os.write(2, importfiles[importi], cstrlen(importfiles[importi]));
|
||||||
|
os.write(2, nl.ptr, nl.len: u64);
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
let il: lex;
|
let il: lex;
|
||||||
lexinit(&il, strings.dup(pathstr(importfiles[importi])), ibuf, ilen);
|
lexinit(&il, strings.dup(pathstr(importfiles[importi])), ibuf, ilen);
|
||||||
let ips: parser;
|
let ips: parser;
|
||||||
|
|||||||
@@ -1017,6 +1017,9 @@ fn wwiemit(c: *checker, file: *syntax.node, path: str) i32 = {
|
|||||||
pkg = file.nmod;
|
pkg = file.nmod;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
if (file.nmod.len > 0) {
|
||||||
|
wputs(fd, "//ww:module "); wputs(fd, file.nmod); wputs(fd, "\n");
|
||||||
|
};
|
||||||
wputs(fd, "package ");
|
wputs(fd, "package ");
|
||||||
wputs(fd, pkg);
|
wputs(fd, pkg);
|
||||||
wputs(fd, ";\n");
|
wputs(fd, ";\n");
|
||||||
|
|||||||
@@ -13,6 +13,8 @@
|
|||||||
|
|
||||||
package main;
|
package main;
|
||||||
|
|
||||||
|
import crypto.sha256;
|
||||||
|
import hash;
|
||||||
import os;
|
import os;
|
||||||
import os.exec;
|
import os.exec;
|
||||||
import rt;
|
import rt;
|
||||||
@@ -137,8 +139,9 @@ fn selfdirinto(dst: *u8, dstsz: u64, argv0: *u8) void = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fn joinpath(dir: *u8, name: *u8) *u8 = {
|
fn joinpath(dir: *u8, name: *u8) *u8 = {
|
||||||
let buf: []u8 = alloc([], (os.PATH_MAX: u64))!;
|
let need: u64 = cstrlen(dir) + 1u64 + cstrlen(name) + 1u64;
|
||||||
buf.len = os.PATH_MAX;
|
let buf: []u8 = alloc([], need)!;
|
||||||
|
buf.len = need: i32;
|
||||||
let off: u64 = cstrinto(buf.ptr, 0u64, dir);
|
let off: u64 = cstrinto(buf.ptr, 0u64, dir);
|
||||||
off = byteinto(buf.ptr, off, 47u8);
|
off = byteinto(buf.ptr, off, 47u8);
|
||||||
off = cstrinto(buf.ptr, off, name);
|
off = cstrinto(buf.ptr, off, name);
|
||||||
@@ -147,8 +150,9 @@ fn joinpath(dir: *u8, name: *u8) *u8 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fn joinpathlit(dir: *u8, name: str) *u8 = {
|
fn joinpathlit(dir: *u8, name: str) *u8 = {
|
||||||
let buf: []u8 = alloc([], (os.PATH_MAX: u64))!;
|
let need: u64 = cstrlen(dir) + 1u64 + name.len: u64 + 1u64;
|
||||||
buf.len = os.PATH_MAX;
|
let buf: []u8 = alloc([], need)!;
|
||||||
|
buf.len = need: i32;
|
||||||
let off: u64 = cstrinto(buf.ptr, 0u64, dir);
|
let off: u64 = cstrinto(buf.ptr, 0u64, dir);
|
||||||
off = byteinto(buf.ptr, off, 47u8);
|
off = byteinto(buf.ptr, off, 47u8);
|
||||||
off = strinto(buf.ptr, off, name);
|
off = strinto(buf.ptr, off, name);
|
||||||
@@ -495,7 +499,6 @@ def SEP_ROLE_GENERATED_MAIN: i32 = 2;
|
|||||||
def SEP_TEST_SUPPORT_MODULE: str = "__wwtest";
|
def SEP_TEST_SUPPORT_MODULE: str = "__wwtest";
|
||||||
def SEP_MAXPRODUCT: i32 = 256;
|
def SEP_MAXPRODUCT: i32 = 256;
|
||||||
def SEP_MAXCONTEXT: i32 = 257;
|
def SEP_MAXCONTEXT: i32 = 257;
|
||||||
def SEP_ARTIFACT_MAX: i32 = 1024;
|
|
||||||
|
|
||||||
// Classify a selected directory entry: 1 production, 2 test, 0 skipped,
|
// Classify a selected directory entry: 1 production, 2 test, 0 skipped,
|
||||||
// -1 @test outside *_test.ww, -2 non-regular source.
|
// -1 @test outside *_test.ww, -2 non-regular source.
|
||||||
@@ -558,11 +561,6 @@ fn dirpackagename(path: *u8) *u8 = {
|
|||||||
cerr(": error: invalid or missing package clause\n");
|
cerr(": error: invalid or missing package clause\n");
|
||||||
return nil;
|
return nil;
|
||||||
};
|
};
|
||||||
if (imports.nmod.len >= 256) {
|
|
||||||
cerrpos(imports.file, imports.line, imports.col);
|
|
||||||
cerr(": error: package name is too long\n");
|
|
||||||
return nil;
|
|
||||||
};
|
|
||||||
return arenadupcstr(imports.nmod.ptr, imports.nmod.len: u64);
|
return arenadupcstr(imports.nmod.ptr, imports.nmod.len: u64);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -759,8 +757,9 @@ fn makestem(stem: *u8, src: *u8) void = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fn appendlit(stem: *u8, suffix: str) *u8 = {
|
fn appendlit(stem: *u8, suffix: str) *u8 = {
|
||||||
let buf: []u8 = alloc([], (os.PATH_MAX: u64))!;
|
let need: u64 = cstrlen(stem) + suffix.len: u64 + 1u64;
|
||||||
buf.len = os.PATH_MAX;
|
let buf: []u8 = alloc([], need)!;
|
||||||
|
buf.len = need: i32;
|
||||||
let off: u64 = cstrinto(buf.ptr, 0u64, stem);
|
let off: u64 = cstrinto(buf.ptr, 0u64, stem);
|
||||||
off = strinto(buf.ptr, off, suffix);
|
off = strinto(buf.ptr, off, suffix);
|
||||||
cstrseal(buf.ptr, off);
|
cstrseal(buf.ptr, off);
|
||||||
@@ -804,6 +803,8 @@ type seppkg = struct {
|
|||||||
entry: *u8, // resolved package dir (or file, file root), NUL-term
|
entry: *u8, // resolved package dir (or file, file root), NUL-term
|
||||||
canon: *u8, // canonical location; never package identity
|
canon: *u8, // canonical location; never package identity
|
||||||
artifact: *u8, // stable non-importable variant artifact key
|
artifact: *u8, // stable non-importable variant artifact key
|
||||||
|
storage: *u8, // internal storage basename; never package identity
|
||||||
|
storagehashed: bool,
|
||||||
name: *u8, // validated declared name; directory packages only
|
name: *u8, // validated declared name; directory packages only
|
||||||
testpackage: *u8,
|
testpackage: *u8,
|
||||||
sources: **u8, // owned, byte-sorted selected paths; dirs only
|
sources: **u8, // owned, byte-sorted selected paths; dirs only
|
||||||
@@ -930,10 +931,7 @@ fn sepcommandcompilermarker(g: *sepgraph, pi: i32) bool = {
|
|||||||
// identity. The compiler path is derived from that base and the semantic
|
// identity. The compiler path is derived from that base and the semantic
|
||||||
// variant; root/product/artifact state never participates.
|
// variant; root/product/artifact state never participates.
|
||||||
fn sepbindimportbase(g: *sepgraph, pi: i32, base: *u8) i32 = {
|
fn sepbindimportbase(g: *sepgraph, pi: i32, base: *u8) i32 = {
|
||||||
if (base == nil || base[0u64] == 0u8 || cstrlen(base) >= 256u64) {
|
if (base == nil || base[0u64] == 0u8) { return -1; };
|
||||||
cerr("ww: package path is too long (limit 255 bytes)\n");
|
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
if (!reservedimportpath(base) && !sepimportbasevalid(base)) {
|
if (!reservedimportpath(base) && !sepimportbasevalid(base)) {
|
||||||
cerr("ww: invalid package path "); cerr(pathstr(base)); cerr("\n");
|
cerr("ww: invalid package path "); cerr(pathstr(base)); cerr("\n");
|
||||||
return -1;
|
return -1;
|
||||||
@@ -992,10 +990,6 @@ fn sepbindimportbase(g: *sepgraph, pi: i32, base: *u8) i32 = {
|
|||||||
fn sepfindoraddvariant(g: *sepgraph, path: *u8, entry: *u8,
|
fn sepfindoraddvariant(g: *sepgraph, path: *u8, entry: *u8,
|
||||||
isdir: i32, variant: i32, testpackage: *u8, role: i32,
|
isdir: i32, variant: i32, testpackage: *u8, role: i32,
|
||||||
artifact: *u8, root: bool) i32 = {
|
artifact: *u8, root: bool) i32 = {
|
||||||
if (cstrlen(path) >= 256u64) {
|
|
||||||
cerr("ww: package path is too long (limit 255 bytes)\n");
|
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
let canon: *u8 = nil;
|
let canon: *u8 = nil;
|
||||||
if (isdir != 0) {
|
if (isdir != 0) {
|
||||||
canon = canonicaldir(pathstr(entry));
|
canon = canonicaldir(pathstr(entry));
|
||||||
@@ -1004,10 +998,6 @@ fn sepfindoraddvariant(g: *sepgraph, path: *u8, entry: *u8,
|
|||||||
cerr(pathstr(entry)); cerr("\n");
|
cerr(pathstr(entry)); cerr("\n");
|
||||||
return -1;
|
return -1;
|
||||||
};
|
};
|
||||||
if (cstrlen(canon) >= 1024u64) {
|
|
||||||
cerr("ww: canonical package path is too long\n");
|
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
let incoming: *u8 = nil;
|
let incoming: *u8 = nil;
|
||||||
if (isdir != 0 && path[0u64] != 0u8) {
|
if (isdir != 0 && path[0u64] != 0u8) {
|
||||||
@@ -1094,6 +1084,8 @@ fn sepfindoraddvariant(g: *sepgraph, path: *u8, entry: *u8,
|
|||||||
g.pkg[g.n].entry = arenadupcstr(entry, elen);
|
g.pkg[g.n].entry = arenadupcstr(entry, elen);
|
||||||
g.pkg[g.n].canon = canon;
|
g.pkg[g.n].canon = canon;
|
||||||
g.pkg[g.n].artifact = nil;
|
g.pkg[g.n].artifact = nil;
|
||||||
|
g.pkg[g.n].storage = nil;
|
||||||
|
g.pkg[g.n].storagehashed = false;
|
||||||
g.pkg[g.n].name = nil;
|
g.pkg[g.n].name = nil;
|
||||||
g.pkg[g.n].testpackage = nil;
|
g.pkg[g.n].testpackage = nil;
|
||||||
if (testpackage != nil) {
|
if (testpackage != nil) {
|
||||||
@@ -1186,17 +1178,12 @@ fn sepgraphfree(g: *sepgraph) void = {
|
|||||||
|
|
||||||
fn sepcontextfor(g: *sepgraph, root: *u8, incs: *u8,
|
fn sepcontextfor(g: *sepgraph, root: *u8, incs: *u8,
|
||||||
toolsrcdir: *u8) i32 = {
|
toolsrcdir: *u8) i32 = {
|
||||||
let cap: u64 = (os.PATH_MAX: u64) * 2u64;
|
|
||||||
let need: u64 = cstrlen(root) + 1u64 + cstrlen(toolsrcdir) + 1u64;
|
let need: u64 = cstrlen(root) + 1u64 + cstrlen(toolsrcdir) + 1u64;
|
||||||
if (incs != nil && incs[0u64] != 0u8) {
|
if (incs != nil && incs[0u64] != 0u8) {
|
||||||
need += cstrlen(incs) + 1u64;
|
need += cstrlen(incs) + 1u64;
|
||||||
};
|
};
|
||||||
if (need > cap) {
|
let search: []u8 = alloc([], need)!;
|
||||||
cerr("ww: package import search path is too long\n");
|
search.len = need: i32;
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
let search: []u8 = alloc([], cap)!;
|
|
||||||
search.len = cap: i32;
|
|
||||||
let off: u64 = cstrinto(search.ptr, 0u64, root);
|
let off: u64 = cstrinto(search.ptr, 0u64, root);
|
||||||
off = byteinto(search.ptr, off, 58u8);
|
off = byteinto(search.ptr, off, 58u8);
|
||||||
if (incs != nil && incs[0u64] != 0u8) {
|
if (incs != nil && incs[0u64] != 0u8) {
|
||||||
@@ -1221,59 +1208,142 @@ fn sepcontextfor(g: *sepgraph, root: *u8, incs: *u8,
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Build one artifact path. Test roots use distinct names even though both
|
def SEP_NAME_MAX: u64 = 255u64;
|
||||||
// compiler units reset to the bare executable namespace.
|
|
||||||
|
fn sepstoragedigest(p: *seppkg) *u8 = {
|
||||||
|
let state: sha256.state = sha256.sha256();
|
||||||
|
let h: *hash.hash = (&state): *hash.hash;
|
||||||
|
hash.write(h, strings.toutf8("ww-package-storage-v2:"));
|
||||||
|
let tag: [4]u8;
|
||||||
|
tag[0] = ('0': i32 + p.variant): u8;
|
||||||
|
tag[1] = ':': u8;
|
||||||
|
tag[2] = ('0': i32 + p.role): u8;
|
||||||
|
tag[3] = ':': u8;
|
||||||
|
hash.write(h, tag[0:4]);
|
||||||
|
hash.write(h, strings.toutf8(pathstr(p.path)));
|
||||||
|
let zero: [1]u8;
|
||||||
|
zero[0] = 0u8;
|
||||||
|
hash.write(h, zero[0:1]);
|
||||||
|
hash.write(h, strings.toutf8(pathstr(p.canon)));
|
||||||
|
let digest: [32]u8;
|
||||||
|
hash.sum(h, digest[0:32]);
|
||||||
|
let need: u64 = "__wwpkg.v".len: u64 + 1u64 + ".r".len: u64
|
||||||
|
+ 1u64 + ".h".len: u64 + 64u64 + 1u64;
|
||||||
|
let out: []u8 = alloc([], need)!;
|
||||||
|
out.len = need: i32;
|
||||||
|
let off: u64 = strinto(out.ptr, 0u64, "__wwpkg.v");
|
||||||
|
off = byteinto(out.ptr, off, tag[0]);
|
||||||
|
off = strinto(out.ptr, off, ".r");
|
||||||
|
off = byteinto(out.ptr, off, tag[2]);
|
||||||
|
off = strinto(out.ptr, off, ".h");
|
||||||
|
let hex: str = "0123456789abcdef";
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < 32) {
|
||||||
|
let high: i32 = (digest[i] / 16u8): i32;
|
||||||
|
let low: i32 = (digest[i] % 16u8): i32;
|
||||||
|
off = byteinto(out.ptr, off, hex[high]);
|
||||||
|
off = byteinto(out.ptr, off, hex[low]);
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
cstrseal(out.ptr, off);
|
||||||
|
return out.ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
fn seplegacyartifact(p: *seppkg) *u8 = {
|
||||||
|
if (p.artifact != nil && p.artifact[0u64] != 0u8) { return p.artifact; };
|
||||||
|
if (p.path != nil && p.path[0u64] != 0u8) { return p.path; };
|
||||||
|
return "__root\0".ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
fn sepvalidatestoragepath(p: *seppkg, scratch: *u8) i32 = {
|
||||||
|
let need: u64 = cstrlen(scratch) + 1u64 + cstrlen(p.storage)
|
||||||
|
+ ".unit.new".len: u64 + 1u64;
|
||||||
|
if (cstrlen(p.storage) + ".unit.new".len: u64 > SEP_NAME_MAX
|
||||||
|
|| need > os.PATH_MAX: u64) {
|
||||||
|
cerr("ww: package artifact path is too long\n");
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
fn sepassignstorage(p: *seppkg, scratch: *u8) i32 = {
|
||||||
|
let base: *u8 = seplegacyartifact(p);
|
||||||
|
let need: u64 = cstrlen(scratch) + 1u64 + cstrlen(base)
|
||||||
|
+ ".unit.new".len: u64 + 1u64;
|
||||||
|
if (cstrlen(base) + ".unit.new".len: u64 <= SEP_NAME_MAX
|
||||||
|
&& need <= os.PATH_MAX: u64) {
|
||||||
|
p.storage = arenadupcstr(base, cstrlen(base));
|
||||||
|
p.storagehashed = false;
|
||||||
|
} else {
|
||||||
|
p.storage = sepstoragedigest(p);
|
||||||
|
p.storagehashed = true;
|
||||||
|
};
|
||||||
|
return sepvalidatestoragepath(p, scratch);
|
||||||
|
};
|
||||||
|
|
||||||
fn sepfname(g: *sepgraph, pi: i32, scratch: *u8, suffix: str) *u8 = {
|
fn sepfname(g: *sepgraph, pi: i32, scratch: *u8, suffix: str) *u8 = {
|
||||||
let buf: []u8 = alloc([], SEP_ARTIFACT_MAX: u64)!;
|
let need: u64 = cstrlen(scratch) + 1u64
|
||||||
buf.len = SEP_ARTIFACT_MAX;
|
+ cstrlen(g.pkg[pi].storage) + suffix.len: u64 + 1u64;
|
||||||
|
let buf: []u8 = alloc([], need)!;
|
||||||
|
buf.len = need: i32;
|
||||||
let off: u64 = cstrinto(buf.ptr, 0u64, scratch);
|
let off: u64 = cstrinto(buf.ptr, 0u64, scratch);
|
||||||
off = byteinto(buf.ptr, off, 47u8); // '/'
|
off = byteinto(buf.ptr, off, 47u8); // '/'
|
||||||
if (g.pkg[pi].artifact != nil) {
|
off = cstrinto(buf.ptr, off, g.pkg[pi].storage);
|
||||||
off = cstrinto(buf.ptr, off, g.pkg[pi].artifact);
|
|
||||||
} else { if (g.pkg[pi].path[0u64] != 0u8) {
|
|
||||||
off = cstrinto(buf.ptr, off, g.pkg[pi].path);
|
|
||||||
} else {
|
|
||||||
off = strinto(buf.ptr, off, "__root");
|
|
||||||
}; };
|
|
||||||
off = strinto(buf.ptr, off, suffix);
|
off = strinto(buf.ptr, off, suffix);
|
||||||
cstrseal(buf.ptr, off);
|
cstrseal(buf.ptr, off);
|
||||||
return buf.ptr;
|
return buf.ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
// sepfname uses SEP_ARTIFACT_MAX storage. Validate the longest suffix once
|
|
||||||
// before opening files so two action identities can never alias by truncation.
|
|
||||||
fn sepvalidateartifactpaths(g: *sepgraph, scratch: *u8) i32 = {
|
fn sepvalidateartifactpaths(g: *sepgraph, scratch: *u8) i32 = {
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < g.n) {
|
for (i < g.n) {
|
||||||
if (g.pkg[i].failed || !g.pkg[i].loaded) { i += 1; continue; };
|
if (g.pkg[i].failed || !g.pkg[i].loaded) { i += 1; continue; };
|
||||||
let base: *u8 = g.pkg[i].artifact;
|
if (g.pkg[i].storage == nil
|
||||||
if (base == nil) {
|
&& sepassignstorage(&g.pkg[i], scratch) < 0) { return -1; };
|
||||||
base = g.pkg[i].path;
|
|
||||||
if (base[0u64] == 0u8) { base = "__root\0".ptr; };
|
|
||||||
};
|
|
||||||
let need: u64 = cstrlen(scratch) + 1u64 + cstrlen(base)
|
|
||||||
+ ".unit.new".len: u64 + 1u64;
|
|
||||||
if (need > SEP_ARTIFACT_MAX: u64) {
|
|
||||||
cerr("ww: package artifact path is too long\n");
|
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
let j: i32 = i + 1;
|
|
||||||
for (j < g.n) {
|
|
||||||
if (g.pkg[j].failed || !g.pkg[j].loaded) { j += 1; continue; };
|
|
||||||
let other: *u8 = g.pkg[j].artifact;
|
|
||||||
if (other == nil) {
|
|
||||||
other = g.pkg[j].path;
|
|
||||||
if (other[0u64] == 0u8) { other = "__root\0".ptr; };
|
|
||||||
};
|
|
||||||
if (cstreq(base, other)) {
|
|
||||||
cerr("ww: package actions share artifact identity ");
|
|
||||||
cerr(pathstr(base)); cerr("\n");
|
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
j += 1;
|
|
||||||
};
|
|
||||||
i += 1;
|
i += 1;
|
||||||
};
|
};
|
||||||
|
let changed: bool = true;
|
||||||
|
for (changed) {
|
||||||
|
changed = false;
|
||||||
|
i = 0;
|
||||||
|
for (i < g.n && !changed) {
|
||||||
|
if (g.pkg[i].failed || !g.pkg[i].loaded) { i += 1; continue; };
|
||||||
|
let j: i32 = i + 1;
|
||||||
|
for (j < g.n) {
|
||||||
|
if (g.pkg[j].failed || !g.pkg[j].loaded
|
||||||
|
|| !cstreq(g.pkg[i].storage, g.pkg[j].storage)) {
|
||||||
|
j += 1; continue;
|
||||||
|
};
|
||||||
|
if (!g.pkg[i].storagehashed || !g.pkg[j].storagehashed) {
|
||||||
|
if (!g.pkg[i].storagehashed) {
|
||||||
|
g.pkg[i].storage = sepstoragedigest(&g.pkg[i]);
|
||||||
|
g.pkg[i].storagehashed = true;
|
||||||
|
if (sepvalidatestoragepath(&g.pkg[i], scratch) < 0) {
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (!g.pkg[j].storagehashed) {
|
||||||
|
g.pkg[j].storage = sepstoragedigest(&g.pkg[j]);
|
||||||
|
g.pkg[j].storagehashed = true;
|
||||||
|
if (sepvalidatestoragepath(&g.pkg[j], scratch) < 0) {
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
changed = true;
|
||||||
|
j = g.n;
|
||||||
|
} else {
|
||||||
|
cerr("ww: package storage collision for ");
|
||||||
|
cerr(pathstr(g.pkg[i].path)); cerr(" in ");
|
||||||
|
cerr(pathstr(g.pkg[i].canon)); cerr(" and ");
|
||||||
|
cerr(pathstr(g.pkg[j].path)); cerr(" in ");
|
||||||
|
cerr(pathstr(g.pkg[j].canon)); cerr(" at ");
|
||||||
|
cerr(pathstr(g.pkg[i].storage)); cerr("\n");
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1384,11 +1454,6 @@ fn sepscanfile(g: *sepgraph, pi: i32, file: *u8, searchpath: *u8,
|
|||||||
&& (ownedsource != 0 || g.pkg[pi].name == nil)) {
|
&& (ownedsource != 0 || g.pkg[pi].name == nil)) {
|
||||||
let declared: *u8 = imports.nmod.ptr;
|
let declared: *u8 = imports.nmod.ptr;
|
||||||
let declaredn: u64 = imports.nmod.len: u64;
|
let declaredn: u64 = imports.nmod.len: u64;
|
||||||
if (declaredn >= 256u64) {
|
|
||||||
cerrpos(imports.file, imports.line, imports.col);
|
|
||||||
cerr(": error: package name is too long\n");
|
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
if (g.pkg[pi].name == nil) {
|
if (g.pkg[pi].name == nil) {
|
||||||
g.pkg[pi].name = arenadupcstr(declared, declaredn);
|
g.pkg[pi].name = arenadupcstr(declared, declaredn);
|
||||||
} else { if (bytecmp(g.pkg[pi].name, cstrlen(g.pkg[pi].name),
|
} else { if (bytecmp(g.pkg[pi].name, cstrlen(g.pkg[pi].name),
|
||||||
@@ -1465,11 +1530,6 @@ fn sepscanfile(g: *sepgraph, pi: i32, file: *u8, searchpath: *u8,
|
|||||||
cerr(u.usepath); cerr(" is reserved\n");
|
cerr(u.usepath); cerr(" is reserved\n");
|
||||||
return -1;
|
return -1;
|
||||||
};
|
};
|
||||||
if (idn >= 256u64) {
|
|
||||||
cerrpos(u.file, u.line, u.col);
|
|
||||||
cerr(": error: import path is too long (limit 255 bytes)\n");
|
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
let externalproduction: bool = false;
|
let externalproduction: bool = false;
|
||||||
let ipath: *u8 = nil;
|
let ipath: *u8 = nil;
|
||||||
if (g.pkg[pi].variant == SEP_VARIANT_EXTERNAL
|
if (g.pkg[pi].variant == SEP_VARIANT_EXTERNAL
|
||||||
@@ -1638,6 +1698,8 @@ fn sepaddgeneratedmain(g: *sepgraph, product: *sepproduct, ordinal: i32,
|
|||||||
let variantartifact: *u8 = g.pkg[variant].artifact;
|
let variantartifact: *u8 = g.pkg[variant].artifact;
|
||||||
if (variantartifact == nil) { variantartifact = g.pkg[variant].path; };
|
if (variantartifact == nil) { variantartifact = g.pkg[variant].path; };
|
||||||
p.artifact = appendlit(variantartifact, "-main");
|
p.artifact = appendlit(variantartifact, "-main");
|
||||||
|
p.storage = nil;
|
||||||
|
p.storagehashed = false;
|
||||||
p.name = arenadupcstr("main\0".ptr, 4u64);
|
p.name = arenadupcstr("main\0".ptr, 4u64);
|
||||||
p.testpackage = nil;
|
p.testpackage = nil;
|
||||||
p.sources = nil;
|
p.sources = nil;
|
||||||
@@ -1888,10 +1950,7 @@ fn sepreverseimportbase(g: *sepgraph, p: *seppkg, context: i32,
|
|||||||
if (rel != nil) {
|
if (rel != nil) {
|
||||||
let converted: i32 = sepimportpathfromrelative(rel,
|
let converted: i32 = sepimportpathfromrelative(rel,
|
||||||
out, outsz);
|
out, outsz);
|
||||||
if (converted < 0) {
|
if (converted < 0) { return -1; };
|
||||||
cerr("ww: package path is too long (limit 255 bytes)\n");
|
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
if (converted > 0 && reservedimportpath(out)) {
|
if (converted > 0 && reservedimportpath(out)) {
|
||||||
converted = 0;
|
converted = 0;
|
||||||
};
|
};
|
||||||
@@ -1981,12 +2040,14 @@ fn sepfinalizedirectoryidentities(g: *sepgraph) i32 = {
|
|||||||
let ci: i32 = 0;
|
let ci: i32 = 0;
|
||||||
for (ci < g.ncontext) {
|
for (ci < g.ncontext) {
|
||||||
if (p.contextstate[ci] == 2u8) {
|
if (p.contextstate[ci] == 2u8) {
|
||||||
let candidate: [256]u8;
|
let candidatesz: u64 = cstrlen(p.canon) + 1u64;
|
||||||
|
let candidate: []u8 = alloc([], candidatesz)!;
|
||||||
|
candidate.len = candidatesz: i32;
|
||||||
let found: i32 = sepreverseimportbase(g, p, ci,
|
let found: i32 = sepreverseimportbase(g, p, ci,
|
||||||
&candidate[0], 256u64);
|
candidate.ptr, candidatesz);
|
||||||
if (found < 0) { return -1; };
|
if (found < 0) { return -1; };
|
||||||
if (found > 0 && sepbindimportbase(g, pi,
|
if (found > 0 && sepbindimportbase(g, pi,
|
||||||
&candidate[0]) < 0) { return -1; };
|
candidate.ptr) < 0) { return -1; };
|
||||||
};
|
};
|
||||||
ci += 1;
|
ci += 1;
|
||||||
};
|
};
|
||||||
@@ -2014,10 +2075,7 @@ fn sepfinalizedirectoryidentities(g: *sepgraph) i32 = {
|
|||||||
};
|
};
|
||||||
if (base == nil) {
|
if (base == nil) {
|
||||||
base = seplocalimportbase(p);
|
base = seplocalimportbase(p);
|
||||||
if (base == nil || cstrlen(base) >= 256u64) {
|
if (base == nil) { return -1; };
|
||||||
cerr("ww: local package identity is too long (limit 255 bytes)\n");
|
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
if (sepbindimportbase(g, pi, base) < 0) { return -1; };
|
if (sepbindimportbase(g, pi, base) < 0) { return -1; };
|
||||||
};
|
};
|
||||||
@@ -2353,6 +2411,70 @@ fn filesizenonzero(path: *u8) bool = {
|
|||||||
return ok;
|
return ok;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn sepvalidateunitowner(g: *sepgraph, pi: i32, scratch: *u8) i32 = {
|
||||||
|
let unit: *u8 = sepfname(g, pi, scratch, ".unit.ww");
|
||||||
|
let fi: os.filestat;
|
||||||
|
match (os.lstat(&fi, pathstr(unit))) {
|
||||||
|
case let e: os.oserror => {
|
||||||
|
if ((e: i64) == -2i64) { return 0; };
|
||||||
|
cerr("ww: package storage owner mismatch at ");
|
||||||
|
cerr(pathstr(g.pkg[pi].storage)); cerr(" for ");
|
||||||
|
if (g.pkg[pi].path[0u64] == 0u8) { cerr("(root)"); }
|
||||||
|
else { cerr(pathstr(g.pkg[pi].path)); };
|
||||||
|
cerr("\n");
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
case void => void;
|
||||||
|
};
|
||||||
|
let typ: u32 = (fi.mode: u32) & 61440u32;
|
||||||
|
if (typ != os.mode.REG: u32) {
|
||||||
|
cerr("ww: package storage owner mismatch at ");
|
||||||
|
cerr(pathstr(g.pkg[pi].storage)); cerr(" for ");
|
||||||
|
if (g.pkg[pi].path[0u64] == 0u8) { cerr("(root)"); }
|
||||||
|
else { cerr(pathstr(g.pkg[pi].path)); };
|
||||||
|
cerr("\n");
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
let buf: *u8;
|
||||||
|
let n: u64;
|
||||||
|
buf, n = slurp(unit);
|
||||||
|
let prefix: str = "//ww:module-reset";
|
||||||
|
let pathn: u64 = cstrlen(g.pkg[pi].path);
|
||||||
|
let want: u64 = prefix.len: u64 + 1u64;
|
||||||
|
if (pathn > 0u64) { want += 1u64 + pathn; };
|
||||||
|
let matches: bool = buf != nil && n >= want
|
||||||
|
&& bytecmp(buf, prefix.len: u64, prefix.ptr,
|
||||||
|
prefix.len: u64) == 0;
|
||||||
|
if (matches) {
|
||||||
|
let off: u64 = prefix.len: u64;
|
||||||
|
if (pathn == 0u64) {
|
||||||
|
matches = buf[off] == ('\n': u8);
|
||||||
|
} else {
|
||||||
|
matches = buf[off] == (' ': u8)
|
||||||
|
&& bytecmp(buf + off + 1u64, pathn,
|
||||||
|
g.pkg[pi].path, pathn) == 0
|
||||||
|
&& buf[off + 1u64 + pathn] == ('\n': u8);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (matches) { return 1; };
|
||||||
|
cerr("ww: package storage owner mismatch at ");
|
||||||
|
cerr(pathstr(g.pkg[pi].storage)); cerr(" for ");
|
||||||
|
if (pathn == 0u64) { cerr("(root)"); }
|
||||||
|
else { cerr(pathstr(g.pkg[pi].path)); };
|
||||||
|
cerr("\n");
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
fn sepvalidateworkdirowners(g: *sepgraph, scratch: *u8) i32 = {
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < g.n) {
|
||||||
|
if (!g.pkg[i].failed && g.pkg[i].loaded
|
||||||
|
&& sepvalidateunitowner(g, i, scratch) < 0) { return -1; };
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
// Byte equality of two files; absence or IO error is inequality.
|
// Byte equality of two files; absence or IO error is inequality.
|
||||||
fn fileequal(a: *u8, b: *u8) bool = {
|
fn fileequal(a: *u8, b: *u8) bool = {
|
||||||
let fa: i32 = os.open(pathstr(a), os.flag.RDONLY, 0i32);
|
let fa: i32 = os.open(pathstr(a), os.flag.RDONLY, 0i32);
|
||||||
@@ -2423,14 +2545,14 @@ fn copyfileatomic(src: *u8, dst: *u8) i32 = {
|
|||||||
fn workdirstamptext(istest: i32, emitasm: i32) str = {
|
fn workdirstamptext(istest: i32, emitasm: i32) str = {
|
||||||
if (istest != 0) {
|
if (istest != 0) {
|
||||||
if (emitasm != 0) {
|
if (emitasm != 0) {
|
||||||
return "ww workdir fmt 9 mode test asm 1\n";
|
return "ww workdir fmt 11 mode test asm 1\n";
|
||||||
};
|
};
|
||||||
return "ww workdir fmt 9 mode test asm 0\n";
|
return "ww workdir fmt 11 mode test asm 0\n";
|
||||||
};
|
};
|
||||||
if (emitasm != 0) {
|
if (emitasm != 0) {
|
||||||
return "ww workdir fmt 8 mode build asm 1\n";
|
return "ww workdir fmt 10 mode build asm 1\n";
|
||||||
};
|
};
|
||||||
return "ww workdir fmt 8 mode build asm 0\n";
|
return "ww workdir fmt 10 mode build asm 0\n";
|
||||||
};
|
};
|
||||||
|
|
||||||
fn stampmatches(path: *u8, want: str) bool = {
|
fn stampmatches(path: *u8, want: str) bool = {
|
||||||
@@ -2595,20 +2717,18 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
let stem: []u8 = alloc([], (os.PATH_MAX: u64))!;
|
let stem: *u8 = nil;
|
||||||
stem.len = os.PATH_MAX;
|
|
||||||
if (entryisdir != 0) {
|
if (entryisdir != 0) {
|
||||||
let dlen: u64 = cstrlen(srcd.ptr);
|
let dlen: u64 = cstrlen(srcd.ptr);
|
||||||
let bo: u64 = basenameoff(srcd.ptr, dlen);
|
let bo: u64 = basenameoff(srcd.ptr, dlen);
|
||||||
let off: u64 = cstrinto(stem.ptr, 0u64, srcd.ptr);
|
stem = joinpath(srcd.ptr, srcd.ptr + bo);
|
||||||
stem[off] = 47u8; off += 1u64; // '/'
|
|
||||||
let i: u64 = bo;
|
|
||||||
for (i < dlen) { stem[off] = srcd[i]; off += 1u64; i += 1u64; };
|
|
||||||
cstrseal(stem.ptr, off);
|
|
||||||
} else {
|
} else {
|
||||||
makestem(stem.ptr, src);
|
let stembuf: []u8 = alloc([], cstrlen(src) + 1u64)!;
|
||||||
|
stembuf.len = (cstrlen(src) + 1u64): i32;
|
||||||
|
makestem(stembuf.ptr, src);
|
||||||
|
stem = stembuf.ptr;
|
||||||
};
|
};
|
||||||
let effstem: *u8 = stem.ptr;
|
let effstem: *u8 = stem;
|
||||||
if (objstem != nil) { effstem = objstem; };
|
if (objstem != nil) { effstem = objstem; };
|
||||||
let warm: bool = false;
|
let warm: bool = false;
|
||||||
if (workdir != nil) {
|
if (workdir != nil) {
|
||||||
@@ -2675,7 +2795,6 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
if (!fileequal(toola, a6)) { staleall = true; };
|
if (!fileequal(toola, a6)) { staleall = true; };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (staleall && invalidateworkdirunits(scratch) != 0) { return 1; };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let rtpaths: []*u8 = alloc([], 2u64)!;
|
let rtpaths: []*u8 = alloc([], 2u64)!;
|
||||||
@@ -2882,6 +3001,8 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (sepvalidateartifactpaths(g, scratch) < 0) { return 1; };
|
if (sepvalidateartifactpaths(g, scratch) < 0) { return 1; };
|
||||||
|
if (warm && sepvalidateworkdirowners(g, scratch) < 0) { return 1; };
|
||||||
|
if (warm && staleall && invalidateworkdirunits(scratch) != 0) { return 1; };
|
||||||
let rootpackage: bool = packageonly != 0;
|
let rootpackage: bool = packageonly != 0;
|
||||||
if (rootpackage && !g.pkg[products[0].root].failed
|
if (rootpackage && !g.pkg[products[0].root].failed
|
||||||
&& cstreqlit(g.pkg[products[0].root].name, "main")) {
|
&& cstreqlit(g.pkg[products[0].root].name, "main")) {
|
||||||
@@ -3534,8 +3655,14 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
|||||||
let workdir: *u8 = nil; // -w persistent package-artifact workdir
|
let workdir: *u8 = nil; // -w persistent package-artifact workdir
|
||||||
let emitasm: i32 = 0;
|
let emitasm: i32 = 0;
|
||||||
let packageonly: i32 = 0;
|
let packageonly: i32 = 0;
|
||||||
let incs: []u8 = alloc([], (os.PATH_MAX: u64) * 2u64)!;
|
let inccap: u64 = 1u64;
|
||||||
incs.len = ((os.PATH_MAX: u64) * 2u64): i32;
|
let capi: i32 = start;
|
||||||
|
for (capi < argc) {
|
||||||
|
inccap += cstrlen(argv[capi]) + 1u64;
|
||||||
|
capi += 1;
|
||||||
|
};
|
||||||
|
let incs: []u8 = alloc([], inccap)!;
|
||||||
|
incs.len = inccap: i32;
|
||||||
let incoff: u64 = 0u64;
|
let incoff: u64 = 0u64;
|
||||||
cstrseal(incs.ptr, 0u64);
|
cstrseal(incs.ptr, 0u64);
|
||||||
|
|
||||||
@@ -3739,8 +3866,14 @@ fn makedrivertmp(buf: *u8, prefix: str) void = {
|
|||||||
fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||||
let src: *u8 = nil;
|
let src: *u8 = nil;
|
||||||
let passstart: i32 = -1; // first argv idx to pass through to program
|
let passstart: i32 = -1; // first argv idx to pass through to program
|
||||||
let incs: []u8 = alloc([], (os.PATH_MAX: u64) * 2u64)!;
|
let inccap: u64 = 1u64;
|
||||||
incs.len = ((os.PATH_MAX: u64) * 2u64): i32;
|
let capi: i32 = start;
|
||||||
|
for (capi < argc) {
|
||||||
|
inccap += cstrlen(argv[capi]) + 1u64;
|
||||||
|
capi += 1;
|
||||||
|
};
|
||||||
|
let incs: []u8 = alloc([], inccap)!;
|
||||||
|
incs.len = inccap: i32;
|
||||||
let incoff: u64 = 0u64;
|
let incoff: u64 = 0u64;
|
||||||
cstrseal(incs.ptr, 0u64);
|
cstrseal(incs.ptr, 0u64);
|
||||||
|
|
||||||
@@ -4038,8 +4171,14 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
|||||||
// to the test binary as argv[1] (single-file/module only; dir-mode
|
// to the test binary as argv[1] (single-file/module only; dir-mode
|
||||||
// rejects). cstage twin: do_test `pattern`.
|
// rejects). cstage twin: do_test `pattern`.
|
||||||
let patarg: *u8 = nil;
|
let patarg: *u8 = nil;
|
||||||
let incs: []u8 = alloc([], (os.PATH_MAX: u64) * 2u64)!;
|
let inccap: u64 = 1u64;
|
||||||
incs.len = ((os.PATH_MAX: u64) * 2u64): i32;
|
let capi: i32 = start;
|
||||||
|
for (capi < argc) {
|
||||||
|
inccap += cstrlen(argv[capi]) + 1u64;
|
||||||
|
capi += 1;
|
||||||
|
};
|
||||||
|
let incs: []u8 = alloc([], inccap)!;
|
||||||
|
incs.len = inccap: i32;
|
||||||
let incoff: u64 = 0u64;
|
let incoff: u64 = 0u64;
|
||||||
cstrseal(incs.ptr, 0u64);
|
cstrseal(incs.ptr, 0u64);
|
||||||
|
|
||||||
@@ -4093,7 +4232,7 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
|||||||
if ((!cstreqlit(kind, "production")
|
if ((!cstreqlit(kind, "production")
|
||||||
&& !cstreqlit(kind, "same")
|
&& !cstreqlit(kind, "same")
|
||||||
&& !cstreqlit(kind, "external"))
|
&& !cstreqlit(kind, "external"))
|
||||||
|| pn == 0u64 || pn >= 256u64
|
|| pn == 0u64
|
||||||
|| dir[0u64] == 0u8 || output[0u64] == 0u8
|
|| dir[0u64] == 0u8 || output[0u64] == 0u8
|
||||||
|| status[0u64] == 0u8
|
|| status[0u64] == 0u8
|
||||||
|| (cstreqlit(kind, "external")
|
|| (cstreqlit(kind, "external")
|
||||||
|
|||||||
Reference in New Issue
Block a user