@sjawhar/pi-legion-envoy 5.16.9 → 5.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/legion.js +1058 -145
- package/package.json +1 -1
package/dist/legion.js
CHANGED
|
@@ -33473,7 +33473,7 @@ import { logger } from "@oh-my-pi/pi-utils";
|
|
|
33473
33473
|
// package.json
|
|
33474
33474
|
var package_default = {
|
|
33475
33475
|
name: "@sjawhar/pi-legion-envoy",
|
|
33476
|
-
version: "5.
|
|
33476
|
+
version: "5.17.0",
|
|
33477
33477
|
type: "module",
|
|
33478
33478
|
omp: {
|
|
33479
33479
|
extensions: [
|
|
@@ -40317,6 +40317,148 @@ class Parser {
|
|
|
40317
40317
|
}
|
|
40318
40318
|
}
|
|
40319
40319
|
|
|
40320
|
+
// src/legion/pane-guard-bash.ts
|
|
40321
|
+
function isAscii(text) {
|
|
40322
|
+
for (let i = 0;i < text.length; i += 1)
|
|
40323
|
+
if (text.charCodeAt(i) > 127)
|
|
40324
|
+
return false;
|
|
40325
|
+
return true;
|
|
40326
|
+
}
|
|
40327
|
+
var ANY_RUN = -1;
|
|
40328
|
+
var ANY_ONE = -2;
|
|
40329
|
+
function globWork(glob, n, operator) {
|
|
40330
|
+
const characters = operator === "/" || operator === "//" ? n * (n + 3) / 2 + 1 : n + 1;
|
|
40331
|
+
return characters * (glob.length + 8);
|
|
40332
|
+
}
|
|
40333
|
+
function prefixMatches(glob, value, from) {
|
|
40334
|
+
const m = glob.length;
|
|
40335
|
+
const matches = new Uint8Array(value.length - from + 1);
|
|
40336
|
+
let reached = new Uint8Array(m + 1);
|
|
40337
|
+
let next = new Uint8Array(m + 1);
|
|
40338
|
+
reached[0] = 1;
|
|
40339
|
+
closeRuns(glob, reached);
|
|
40340
|
+
for (let k = 0;; k += 1) {
|
|
40341
|
+
matches[k] = reached[m];
|
|
40342
|
+
if (from + k === value.length)
|
|
40343
|
+
break;
|
|
40344
|
+
const c = value.charCodeAt(from + k);
|
|
40345
|
+
next.fill(0);
|
|
40346
|
+
let any2 = false;
|
|
40347
|
+
for (let i = 0;i < m; i += 1) {
|
|
40348
|
+
if (reached[i] !== 1)
|
|
40349
|
+
continue;
|
|
40350
|
+
const element = glob[i];
|
|
40351
|
+
if (element === ANY_RUN)
|
|
40352
|
+
next[i] = 1;
|
|
40353
|
+
else if (element === ANY_ONE || element === c)
|
|
40354
|
+
next[i + 1] = 1;
|
|
40355
|
+
else
|
|
40356
|
+
continue;
|
|
40357
|
+
any2 = true;
|
|
40358
|
+
}
|
|
40359
|
+
if (!any2)
|
|
40360
|
+
break;
|
|
40361
|
+
closeRuns(glob, next);
|
|
40362
|
+
[reached, next] = [next, reached];
|
|
40363
|
+
}
|
|
40364
|
+
return matches;
|
|
40365
|
+
}
|
|
40366
|
+
function closeRuns(glob, reached) {
|
|
40367
|
+
for (let i = 0;i < glob.length; i += 1) {
|
|
40368
|
+
if (reached[i] === 1 && glob[i] === ANY_RUN)
|
|
40369
|
+
reached[i + 1] = 1;
|
|
40370
|
+
}
|
|
40371
|
+
}
|
|
40372
|
+
function globMatches(glob, value) {
|
|
40373
|
+
return prefixMatches(glob, value, 0)[value.length] === 1;
|
|
40374
|
+
}
|
|
40375
|
+
function matchEdge(value, glob, from, longest) {
|
|
40376
|
+
const matches = from === "start" ? prefixMatches(glob, value, 0) : prefixMatches([...glob].reverse(), [...value].reverse().join(""), 0);
|
|
40377
|
+
const length = longest ? matches.lastIndexOf(1) : matches.indexOf(1);
|
|
40378
|
+
return length === -1 ? undefined : length;
|
|
40379
|
+
}
|
|
40380
|
+
function removePattern(value, operator, glob) {
|
|
40381
|
+
const from = operator.startsWith("#") ? "start" : "end";
|
|
40382
|
+
const length = matchEdge(value, glob, from, operator.length === 2);
|
|
40383
|
+
if (length === undefined)
|
|
40384
|
+
return value;
|
|
40385
|
+
return from === "start" ? value.slice(length) : value.slice(0, value.length - length);
|
|
40386
|
+
}
|
|
40387
|
+
function replacePattern(value, operator, glob, replacement) {
|
|
40388
|
+
const n = value.length;
|
|
40389
|
+
if (operator === "/#" || operator === "/%") {
|
|
40390
|
+
const from = operator === "/#" ? "start" : "end";
|
|
40391
|
+
const length = matchEdge(value, glob, from, true);
|
|
40392
|
+
if (length === undefined)
|
|
40393
|
+
return value;
|
|
40394
|
+
return from === "start" ? replacement + value.slice(length) : value.slice(0, n - length) + replacement;
|
|
40395
|
+
}
|
|
40396
|
+
if (n === 0)
|
|
40397
|
+
return globMatches(glob, "") ? replacement : value;
|
|
40398
|
+
let out = "";
|
|
40399
|
+
let at = 0;
|
|
40400
|
+
while (at < n) {
|
|
40401
|
+
const length = prefixMatches(glob, value, at).lastIndexOf(1);
|
|
40402
|
+
if (length <= 0) {
|
|
40403
|
+
out += value[at];
|
|
40404
|
+
at += 1;
|
|
40405
|
+
continue;
|
|
40406
|
+
}
|
|
40407
|
+
out += replacement;
|
|
40408
|
+
at += length;
|
|
40409
|
+
if (operator === "/")
|
|
40410
|
+
return out + value.slice(at);
|
|
40411
|
+
}
|
|
40412
|
+
return out;
|
|
40413
|
+
}
|
|
40414
|
+
function evaluateTest(operands) {
|
|
40415
|
+
const [left = "", operator = "", right = ""] = operands;
|
|
40416
|
+
if (operands.length === 1)
|
|
40417
|
+
return left !== "";
|
|
40418
|
+
if (operands.length === 2) {
|
|
40419
|
+
if (left === "!")
|
|
40420
|
+
return operator === "";
|
|
40421
|
+
if (left === "-n")
|
|
40422
|
+
return operator !== "";
|
|
40423
|
+
if (left === "-z")
|
|
40424
|
+
return operator === "";
|
|
40425
|
+
return;
|
|
40426
|
+
}
|
|
40427
|
+
if (operands.length !== 3)
|
|
40428
|
+
return;
|
|
40429
|
+
if (operator === "=" || operator === "==")
|
|
40430
|
+
return left === right;
|
|
40431
|
+
if (operator === "!=")
|
|
40432
|
+
return left !== right;
|
|
40433
|
+
if (!/^-?[0-9]+$/.test(left) || !/^-?[0-9]+$/.test(right))
|
|
40434
|
+
return;
|
|
40435
|
+
const a = Number(left);
|
|
40436
|
+
const b = Number(right);
|
|
40437
|
+
switch (operator) {
|
|
40438
|
+
case "-eq":
|
|
40439
|
+
return a === b;
|
|
40440
|
+
case "-ne":
|
|
40441
|
+
return a !== b;
|
|
40442
|
+
case "-gt":
|
|
40443
|
+
return a > b;
|
|
40444
|
+
case "-ge":
|
|
40445
|
+
return a >= b;
|
|
40446
|
+
case "-lt":
|
|
40447
|
+
return a < b;
|
|
40448
|
+
case "-le":
|
|
40449
|
+
return a <= b;
|
|
40450
|
+
default:
|
|
40451
|
+
return;
|
|
40452
|
+
}
|
|
40453
|
+
}
|
|
40454
|
+
function shellQuoted(text) {
|
|
40455
|
+
if (text === "")
|
|
40456
|
+
return "''";
|
|
40457
|
+
if (/^[A-Za-z0-9_/.:@%+=,-]+$/.test(text))
|
|
40458
|
+
return text;
|
|
40459
|
+
return `'${text.replaceAll("'", "'\\''")}'`;
|
|
40460
|
+
}
|
|
40461
|
+
|
|
40320
40462
|
// src/legion/pane-guard-code.ts
|
|
40321
40463
|
var UNKNOWN_MARKER = "__LEGION_GUARD_UNKNOWN__";
|
|
40322
40464
|
var PY_STRING_PREFIX = new Set(["r", "u", "b", "f", "br", "rb", "fr", "rf"]);
|
|
@@ -41287,6 +41429,19 @@ function scanIpythonShell(source, sinks) {
|
|
|
41287
41429
|
}
|
|
41288
41430
|
|
|
41289
41431
|
// src/legion/pane-guard.ts
|
|
41432
|
+
var UNSET = [{ kind: "literal", text: "", unset: true }];
|
|
41433
|
+
function isUnset(value) {
|
|
41434
|
+
return value?.length === 1 && value[0]?.unset === true;
|
|
41435
|
+
}
|
|
41436
|
+
var NO_ELEMENTS = { kind: "literal", text: "", noElements: true };
|
|
41437
|
+
function stored(value) {
|
|
41438
|
+
if (!value.some((piece) => piece.noElements === true))
|
|
41439
|
+
return value;
|
|
41440
|
+
return value.map((piece) => piece.noElements === true ? literal2("") : piece);
|
|
41441
|
+
}
|
|
41442
|
+
var ANY_NAME = "\x00";
|
|
41443
|
+
var IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
41444
|
+
var ARRAY_ELEMENT = /^([A-Za-z_][A-Za-z0-9_]*)\[.*\]$/s;
|
|
41290
41445
|
var definitions = new WeakMap;
|
|
41291
41446
|
function trapSignal(operand) {
|
|
41292
41447
|
const name = operand.toUpperCase();
|
|
@@ -41322,7 +41477,10 @@ function wrapRefusal(error48, site, label) {
|
|
|
41322
41477
|
}
|
|
41323
41478
|
var MAX_DEPTH = 8;
|
|
41324
41479
|
var MAX_WALK_STEPS = 1e5;
|
|
41480
|
+
var WALK_LIMIT = `the guard reached its walk limit of ${MAX_WALK_STEPS} nodes; run a smaller script`;
|
|
41325
41481
|
var MAX_ALTERNATIVES = 64;
|
|
41482
|
+
var MAX_PATTERN_VALUE = 512;
|
|
41483
|
+
var PATTERN_WORK_PER_STEP = 1024;
|
|
41326
41484
|
var MAX_SCRIPT_BYTES = 1024 * 1024;
|
|
41327
41485
|
var FRESH_TEMP_NAME = "tmp.XXXXXXXXXX";
|
|
41328
41486
|
var PROTECTED_SCRATCH = [
|
|
@@ -41410,7 +41568,7 @@ function realish(abs, followFinal) {
|
|
|
41410
41568
|
return path4.join(realExisting(path4.dirname(resolved)), path4.basename(resolved));
|
|
41411
41569
|
}
|
|
41412
41570
|
function isProtectedScratchComponent(component, roots, partial2 = false) {
|
|
41413
|
-
return roots.protectedScratch.some((name) => component.startsWith(name) || partial2 && name.startsWith(component));
|
|
41571
|
+
return roots.protectedScratch.some((name) => component.startsWith(name) || partial2 && name.startsWith(component)) || roots.protectedDirectories.some((name) => component === name || partial2 && name.startsWith(component));
|
|
41414
41572
|
}
|
|
41415
41573
|
function inWorkspace(real, roots) {
|
|
41416
41574
|
const workspace = roots.workspace;
|
|
@@ -41516,12 +41674,81 @@ function unquotedLiteral(source, tildeAt, st, ctx) {
|
|
|
41516
41674
|
function lookup(name, st, ctx) {
|
|
41517
41675
|
const own = st.vars.get(name);
|
|
41518
41676
|
if (own !== undefined)
|
|
41519
|
-
return own;
|
|
41677
|
+
return isUnset(own) ? undefined : own;
|
|
41678
|
+
const any2 = st.vars.get(ANY_NAME)?.[0];
|
|
41679
|
+
if (any2 !== undefined)
|
|
41680
|
+
return [{ ...any2, why: `\`$${name}\`, which ${any2.why}` }];
|
|
41520
41681
|
if (name === "PWD" && st.cwd !== undefined)
|
|
41521
41682
|
return [literal2(st.cwd)];
|
|
41522
41683
|
const value = ctx.env[name];
|
|
41523
41684
|
return value === undefined ? undefined : [literal2(value)];
|
|
41524
41685
|
}
|
|
41686
|
+
function assignScalar(st, name, value) {
|
|
41687
|
+
if (attributed(st, name)) {
|
|
41688
|
+
keepAttributed(st, name);
|
|
41689
|
+
return;
|
|
41690
|
+
}
|
|
41691
|
+
const kept = stored(value);
|
|
41692
|
+
st.vars.set(name, kept);
|
|
41693
|
+
const elements = st.arrays.get(name);
|
|
41694
|
+
if (elements !== undefined)
|
|
41695
|
+
st.arrays.set(name, new Map(elements).set("0", kept));
|
|
41696
|
+
}
|
|
41697
|
+
function attributed(st, name) {
|
|
41698
|
+
return st.vars.get(name)?.some((piece) => piece.rewrites === true) === true;
|
|
41699
|
+
}
|
|
41700
|
+
function keepAttributed(st, name, unsets = false) {
|
|
41701
|
+
const before = st.vars.get(name);
|
|
41702
|
+
const maybeUnset = unsets || before === undefined || isUnset(before) || before.some((piece) => piece.maybeUnset === true);
|
|
41703
|
+
const kept = [
|
|
41704
|
+
{
|
|
41705
|
+
...unknown2(`\`$${name}\`, whose \`readonly\`, \`-i\`, \`-l\` or \`-u\` refuses or rewrites a write`),
|
|
41706
|
+
rewrites: true,
|
|
41707
|
+
...maybeUnset ? { maybeUnset: true } : {}
|
|
41708
|
+
}
|
|
41709
|
+
];
|
|
41710
|
+
st.vars.set(name, kept);
|
|
41711
|
+
if (st.arrays.has(name))
|
|
41712
|
+
st.arrays.set(name, new Map([[UNKNOWN_ARRAY_INDEX, kept]]));
|
|
41713
|
+
}
|
|
41714
|
+
function assignByName(st, name, value, writer) {
|
|
41715
|
+
if (name === undefined) {
|
|
41716
|
+
forgetVariables(st, `${writer} under a name the guard cannot read may have changed`);
|
|
41717
|
+
return;
|
|
41718
|
+
}
|
|
41719
|
+
if (IDENTIFIER.test(name)) {
|
|
41720
|
+
assignScalar(st, name, value);
|
|
41721
|
+
return;
|
|
41722
|
+
}
|
|
41723
|
+
const base = ARRAY_ELEMENT.exec(name)?.[1];
|
|
41724
|
+
if (base === undefined)
|
|
41725
|
+
return;
|
|
41726
|
+
if (attributed(st, base)) {
|
|
41727
|
+
keepAttributed(st, base, true);
|
|
41728
|
+
return;
|
|
41729
|
+
}
|
|
41730
|
+
const element = [
|
|
41731
|
+
{ ...unknown2(`\`$${base}\`, whose element ${writer} assigns`), maybeUnset: true }
|
|
41732
|
+
];
|
|
41733
|
+
st.vars.set(base, element);
|
|
41734
|
+
st.arrays.set(base, new Map([[UNKNOWN_ARRAY_INDEX, element]]));
|
|
41735
|
+
}
|
|
41736
|
+
function forgetVariables(st, why) {
|
|
41737
|
+
const forgotten = (name) => [
|
|
41738
|
+
{
|
|
41739
|
+
...unknown2(`\`$${name}\`, which ${why}`),
|
|
41740
|
+
maybeUnset: true,
|
|
41741
|
+
...attributed(st, name) ? { rewrites: true } : {}
|
|
41742
|
+
}
|
|
41743
|
+
];
|
|
41744
|
+
for (const name of st.vars.keys())
|
|
41745
|
+
if (name !== ANY_NAME)
|
|
41746
|
+
st.vars.set(name, forgotten(name));
|
|
41747
|
+
st.vars.set(ANY_NAME, [{ ...unknown2(why), maybeUnset: true }]);
|
|
41748
|
+
for (const name of st.arrays.keys()) {
|
|
41749
|
+
st.arrays.set(name, new Map([[UNKNOWN_ARRAY_INDEX, forgotten(name)]]));
|
|
41750
|
+
}
|
|
41751
|
+
}
|
|
41525
41752
|
function resolveArrayIndex(index, st, ctx) {
|
|
41526
41753
|
if (index === undefined)
|
|
41527
41754
|
return;
|
|
@@ -41534,7 +41761,7 @@ function parameter(name, quoted, st, ctx) {
|
|
|
41534
41761
|
if (name === "@" || name === "*") {
|
|
41535
41762
|
if (st.positional === undefined)
|
|
41536
41763
|
return [[unknown2(`\`$${name}\` (the positional parameters)`)]];
|
|
41537
|
-
return st.positional
|
|
41764
|
+
return elements(st.positional, name === "*" && quoted);
|
|
41538
41765
|
}
|
|
41539
41766
|
if (/^[0-9]+$/.test(name)) {
|
|
41540
41767
|
if (name === "0")
|
|
@@ -41542,6 +41769,8 @@ function parameter(name, quoted, st, ctx) {
|
|
|
41542
41769
|
const value2 = st.positional?.[Number(name) - 1];
|
|
41543
41770
|
if (value2 !== undefined)
|
|
41544
41771
|
return [[...value2]];
|
|
41772
|
+
if (st.positional !== undefined)
|
|
41773
|
+
return [[literal2("")]];
|
|
41545
41774
|
return [[unknown2(`\`$${name}\` (a positional parameter)`)]];
|
|
41546
41775
|
}
|
|
41547
41776
|
if (name === "$") {
|
|
@@ -41550,8 +41779,12 @@ function parameter(name, quoted, st, ctx) {
|
|
|
41550
41779
|
if (name === "!") {
|
|
41551
41780
|
return [[unknown2("`$!` (the last background job)", st.backgroundStarted ? true : undefined)]];
|
|
41552
41781
|
}
|
|
41782
|
+
if (name === "#" && st.positional !== undefined)
|
|
41783
|
+
return [[literal2(String(st.positional.length))]];
|
|
41553
41784
|
if (["?", "#", "-"].includes(name))
|
|
41554
41785
|
return [[unknown2(`\`$${name}\``)]];
|
|
41786
|
+
if (isUnset(st.vars.get(name)))
|
|
41787
|
+
return [[literal2("")]];
|
|
41555
41788
|
const value = lookup(name, st, ctx);
|
|
41556
41789
|
if (value === undefined) {
|
|
41557
41790
|
return [[unknown2(`\`$${name}\`, which is not set in this command or the pane's environment`)]];
|
|
@@ -41569,6 +41802,30 @@ function parameter(name, quoted, st, ctx) {
|
|
|
41569
41802
|
}
|
|
41570
41803
|
return [pieces];
|
|
41571
41804
|
}
|
|
41805
|
+
function elements(values, joined) {
|
|
41806
|
+
if (joined)
|
|
41807
|
+
return [values.flatMap((value, index) => index === 0 ? value : [literal2(" "), ...value])];
|
|
41808
|
+
return values.length === 0 ? [[NO_ELEMENTS]] : values.map((value) => [...value]);
|
|
41809
|
+
}
|
|
41810
|
+
function operatorValue(name, st, ctx) {
|
|
41811
|
+
const unknownValue = [unknown2(`\`$${name}\``)];
|
|
41812
|
+
if (!/^([0-9]+|[@*#?$!-])$/.test(name)) {
|
|
41813
|
+
const value = lookup(name, st, ctx);
|
|
41814
|
+
if (value === undefined)
|
|
41815
|
+
return { set: false, value: [] };
|
|
41816
|
+
return { set: value.some((piece) => piece.maybeUnset === true) ? undefined : true, value };
|
|
41817
|
+
}
|
|
41818
|
+
if (/^[1-9][0-9]*$/.test(name) || name === "@" || name === "*") {
|
|
41819
|
+
if (st.positional === undefined)
|
|
41820
|
+
return { set: undefined, value: unknownValue };
|
|
41821
|
+
const value = name === "@" || name === "*" ? st.positional.length === 0 ? undefined : elements(st.positional, true)[0] : st.positional[Number(name) - 1];
|
|
41822
|
+
return value === undefined ? { set: false, value: [] } : { set: true, value };
|
|
41823
|
+
}
|
|
41824
|
+
if (name === "!" && !st.backgroundStarted)
|
|
41825
|
+
return { set: undefined, value: unknownValue };
|
|
41826
|
+
const alternatives = parameter(name, true, st, ctx);
|
|
41827
|
+
return { set: true, value: alternatives.length === 1 ? alternatives[0] ?? [] : unknownValue };
|
|
41828
|
+
}
|
|
41572
41829
|
function parameterExpansion(part, quoted, st, ctx) {
|
|
41573
41830
|
const name = part.parameter;
|
|
41574
41831
|
if (name === "BASH_SOURCE" && part.index === "0" && st.script !== undefined) {
|
|
@@ -41580,8 +41837,7 @@ function parameterExpansion(part, quoted, st, ctx) {
|
|
|
41580
41837
|
const unknownElement = array2.get(UNKNOWN_ARRAY_INDEX);
|
|
41581
41838
|
if (unknownElement !== undefined)
|
|
41582
41839
|
return [[...unknownElement]];
|
|
41583
|
-
|
|
41584
|
-
return values.length === 0 ? [[literal2("")]] : values.map((value2) => [...value2]);
|
|
41840
|
+
return elements([...array2.values()], part.index === "*" && quoted);
|
|
41585
41841
|
}
|
|
41586
41842
|
return parameter(name, quoted, st, ctx);
|
|
41587
41843
|
}
|
|
@@ -41592,33 +41848,50 @@ function parameterExpansion(part, quoted, st, ctx) {
|
|
|
41592
41848
|
}
|
|
41593
41849
|
return [[unknown2(`\`${part.text}\``)]];
|
|
41594
41850
|
}
|
|
41595
|
-
if (part.length || part.indirect || part.slice
|
|
41851
|
+
if (part.length || part.indirect || part.slice) {
|
|
41596
41852
|
return [[unknown2(`\`${part.text}\``)]];
|
|
41597
41853
|
}
|
|
41854
|
+
if (part.replace !== undefined || ["#", "##", "%", "%%"].includes(part.operator ?? "")) {
|
|
41855
|
+
return patternExpansion(part, quoted, st, ctx);
|
|
41856
|
+
}
|
|
41598
41857
|
const operator = part.operator;
|
|
41599
41858
|
if (operator === undefined)
|
|
41600
41859
|
return parameter(name, quoted, st, ctx);
|
|
41601
|
-
const value =
|
|
41602
|
-
const
|
|
41603
|
-
const
|
|
41604
|
-
const
|
|
41860
|
+
const { set: set2, value } = operatorValue(name, st, ctx);
|
|
41861
|
+
const nonEmpty2 = set2 === true && value.map((p) => p.text).join("") !== "";
|
|
41862
|
+
const known = set2 === false || set2 === true && value.every((p) => p.kind === "literal");
|
|
41863
|
+
const surelyNonEmpty = set2 === true && value.some((p) => p.descendantPid === true || p.kind === "literal" && p.text !== "");
|
|
41864
|
+
const undecided = [[unknown2(`\`${part.text}\``)]];
|
|
41605
41865
|
const operand = () => part.operand === undefined ? [[literal2("")]] : expandWord(part.operand, st, ctx);
|
|
41866
|
+
const assigning = (result, maybe) => {
|
|
41867
|
+
if ((operator === ":=" || operator === "=") && IDENTIFIER.test(name)) {
|
|
41868
|
+
const only = result.length === 1 && !maybe ? result[0] : undefined;
|
|
41869
|
+
assignScalar(st, name, only ?? [unknown2(`\`$${name}\`, which \`${part.text}\` may assign`)]);
|
|
41870
|
+
}
|
|
41871
|
+
return result;
|
|
41872
|
+
};
|
|
41606
41873
|
switch (operator) {
|
|
41607
41874
|
case ":-":
|
|
41608
41875
|
case ":=":
|
|
41876
|
+
if (surelyNonEmpty)
|
|
41877
|
+
return parameter(name, quoted, st, ctx);
|
|
41609
41878
|
if (!known)
|
|
41610
|
-
return
|
|
41611
|
-
return nonEmpty2 ? parameter(name, quoted, st, ctx) : operand();
|
|
41879
|
+
return assigning(undecided, true);
|
|
41880
|
+
return nonEmpty2 ? parameter(name, quoted, st, ctx) : assigning(operand(), false);
|
|
41612
41881
|
case "-":
|
|
41613
41882
|
case "=":
|
|
41614
|
-
if (
|
|
41615
|
-
return
|
|
41616
|
-
return set2 ? parameter(name, quoted, st, ctx) : operand();
|
|
41883
|
+
if (set2 === undefined)
|
|
41884
|
+
return assigning(undecided, true);
|
|
41885
|
+
return set2 ? parameter(name, quoted, st, ctx) : assigning(operand(), false);
|
|
41617
41886
|
case ":+":
|
|
41887
|
+
if (surelyNonEmpty)
|
|
41888
|
+
return operand();
|
|
41618
41889
|
if (!known)
|
|
41619
|
-
return
|
|
41890
|
+
return undecided;
|
|
41620
41891
|
return nonEmpty2 ? operand() : [[literal2("")]];
|
|
41621
41892
|
case "+":
|
|
41893
|
+
if (set2 === undefined)
|
|
41894
|
+
return undecided;
|
|
41622
41895
|
return set2 ? operand() : [[literal2("")]];
|
|
41623
41896
|
case ":?":
|
|
41624
41897
|
case "?":
|
|
@@ -41627,6 +41900,57 @@ function parameterExpansion(part, quoted, st, ctx) {
|
|
|
41627
41900
|
return [[unknown2(`\`${part.text}\``)]];
|
|
41628
41901
|
}
|
|
41629
41902
|
}
|
|
41903
|
+
function patternExpansion(part, quoted, st, ctx) {
|
|
41904
|
+
const unknownResult = [[unknown2(`\`${part.text}\``)]];
|
|
41905
|
+
const because = (pieces) => {
|
|
41906
|
+
const cause = pieces.find((piece) => piece.kind === "unknown")?.why;
|
|
41907
|
+
return cause === undefined ? unknownResult : [[unknown2(`\`${part.text}\` (${cause})`)]];
|
|
41908
|
+
};
|
|
41909
|
+
const operator = part.operator ?? "";
|
|
41910
|
+
const head = `\${${part.parameter}${operator}`;
|
|
41911
|
+
const accounted = part.replace === undefined ? part.text === `${head}${part.operand?.text ?? ""}}` : part.text === `${head}${part.replace.pattern.text}/${part.replace.replacement.text}}` || part.replace.replacement.text === "" && part.text === `${head}${part.replace.pattern.text}}`;
|
|
41912
|
+
const slashPattern = operator === "/" || operator === "//";
|
|
41913
|
+
if (!accounted || slashPattern && part.replace?.pattern.text === "")
|
|
41914
|
+
return unknownResult;
|
|
41915
|
+
const { set: set2, value: held } = operatorValue(part.parameter, st, ctx);
|
|
41916
|
+
const knownUnset = set2 === false && (/^([1-9][0-9]*|[@*])$/.test(part.parameter) || isUnset(st.vars.get(part.parameter)));
|
|
41917
|
+
const value = set2 === true ? literalText(held) : knownUnset ? "" : undefined;
|
|
41918
|
+
if (value === undefined)
|
|
41919
|
+
return because(held);
|
|
41920
|
+
if (value.length > MAX_PATTERN_VALUE || !isAscii(value))
|
|
41921
|
+
return unknownResult;
|
|
41922
|
+
const patternWord = part.replace?.pattern ?? part.operand;
|
|
41923
|
+
const patterns = patternWord === undefined ? [[literal2("")]] : expandWord(patternWord, st, ctx);
|
|
41924
|
+
const glob = patterns.length === 1 ? patternGlob(patterns[0]) : undefined;
|
|
41925
|
+
if (glob === undefined || slashPattern && glob.length === 0)
|
|
41926
|
+
return unknownResult;
|
|
41927
|
+
if (!spendPatternWork(globWork(glob, value.length, operator), ctx))
|
|
41928
|
+
return unknownResult;
|
|
41929
|
+
let result;
|
|
41930
|
+
if (part.replace === undefined) {
|
|
41931
|
+
result = removePattern(value, operator, glob);
|
|
41932
|
+
} else {
|
|
41933
|
+
const replacements = expandWord(part.replace.replacement, st, ctx);
|
|
41934
|
+
const pieces = replacements.length === 1 ? replacements[0] : undefined;
|
|
41935
|
+
if (pieces === undefined)
|
|
41936
|
+
return unknownResult;
|
|
41937
|
+
if (pieces.some((piece) => piece.kind === "unknown"))
|
|
41938
|
+
return because(pieces);
|
|
41939
|
+
const replacement = pieces.map((piece) => piece.text).join("");
|
|
41940
|
+
if (/[&\\]/.test(replacement))
|
|
41941
|
+
return unknownResult;
|
|
41942
|
+
const most = value.length + (operator === "//" ? Math.max(value.length, 1) : 1) * replacement.length;
|
|
41943
|
+
if (most > MAX_VALUE_LENGTH)
|
|
41944
|
+
return [[overLong(`\`${part.text}\``)]];
|
|
41945
|
+
result = replacePattern(value, operator, glob, replacement);
|
|
41946
|
+
}
|
|
41947
|
+
if (quoted)
|
|
41948
|
+
return [[literal2(result)]];
|
|
41949
|
+
if (/\s/.test(result)) {
|
|
41950
|
+
return [[unknown2(`unquoted \`${part.text}\`, which splits into several words`)]];
|
|
41951
|
+
}
|
|
41952
|
+
return [unquotedLiteral(result.replaceAll("\\", "\\\\"), undefined, st, ctx)];
|
|
41953
|
+
}
|
|
41630
41954
|
function substitution(script, text, st, ctx) {
|
|
41631
41955
|
const pidRead = /^\$\(<(.+)\)$/.exec(text);
|
|
41632
41956
|
const variableRead = /^\$\(<"?\$([A-Za-z_][A-Za-z0-9_]*)"?\)$/.exec(text);
|
|
@@ -41693,6 +42017,8 @@ function substitutionPath(base, list, st) {
|
|
|
41693
42017
|
const target = literalText(operands(list, "").operands.at(-1)?.exp);
|
|
41694
42018
|
if (target === undefined || st.cwd === undefined)
|
|
41695
42019
|
return;
|
|
42020
|
+
if (target === "")
|
|
42021
|
+
return base === "dirname" ? "." : "";
|
|
41696
42022
|
const abs = path4.resolve(st.cwd, target);
|
|
41697
42023
|
if (base === "dirname")
|
|
41698
42024
|
return path4.dirname(abs);
|
|
@@ -41771,11 +42097,23 @@ function product(left, right) {
|
|
|
41771
42097
|
if (out.length >= MAX_ALTERNATIVES) {
|
|
41772
42098
|
return [[unknown2(`a brace expansion with more than ${MAX_ALTERNATIVES} alternatives`)]];
|
|
41773
42099
|
}
|
|
41774
|
-
|
|
42100
|
+
const long = a.length + b.length > MAX_VALUE_PIECES || textLength(a) + textLength(b) > MAX_VALUE_LENGTH;
|
|
42101
|
+
out.push(long ? [overLong("a word")] : [...a, ...b]);
|
|
41775
42102
|
}
|
|
41776
42103
|
}
|
|
41777
42104
|
return out;
|
|
41778
42105
|
}
|
|
42106
|
+
var MAX_VALUE_LENGTH = 65536;
|
|
42107
|
+
var MAX_VALUE_PIECES = 4096;
|
|
42108
|
+
function overLong(what) {
|
|
42109
|
+
return unknown2(`${what}, longer than the guard builds (${MAX_VALUE_LENGTH} characters or ${MAX_VALUE_PIECES} pieces)`);
|
|
42110
|
+
}
|
|
42111
|
+
function textLength(pieces) {
|
|
42112
|
+
let length = 0;
|
|
42113
|
+
for (const piece of pieces)
|
|
42114
|
+
length += piece.text.length;
|
|
42115
|
+
return length;
|
|
42116
|
+
}
|
|
41779
42117
|
function expandWord(word, st, ctx) {
|
|
41780
42118
|
let alternatives = [[]];
|
|
41781
42119
|
if (word.parts === undefined)
|
|
@@ -41790,8 +42128,38 @@ function expandWord(word, st, ctx) {
|
|
|
41790
42128
|
function runtimeText(exp) {
|
|
41791
42129
|
return exp.map((piece) => piece.kind === "unknown" ? UNKNOWN_MARKER : piece.text).join("");
|
|
41792
42130
|
}
|
|
42131
|
+
var SPLIT_PARTS = new Set([
|
|
42132
|
+
"SimpleExpansion",
|
|
42133
|
+
"ParameterExpansion",
|
|
42134
|
+
"CommandExpansion",
|
|
42135
|
+
"ArithmeticExpansion"
|
|
42136
|
+
]);
|
|
41793
42137
|
function args(words, st, ctx) {
|
|
41794
|
-
return words.flatMap((word) =>
|
|
42138
|
+
return words.flatMap((word) => {
|
|
42139
|
+
const parts = word.parts ?? [];
|
|
42140
|
+
const unquoted = parts.some((part) => SPLIT_PARTS.has(part.type));
|
|
42141
|
+
const onlyExpansions = parts.length > 0 && parts.every((part) => SPLIT_PARTS.has(part.type));
|
|
42142
|
+
return expandWord(word, st, ctx).map((exp) => {
|
|
42143
|
+
if (exp.some((piece) => piece.kind === "glob")) {
|
|
42144
|
+
return { text: word.text, exp, fields: "unknown" };
|
|
42145
|
+
}
|
|
42146
|
+
if (unquoted && exp.some((piece) => piece.kind === "unknown" || /[ \t\n]/.test(piece.text))) {
|
|
42147
|
+
return { text: word.text, exp, fields: "unknown" };
|
|
42148
|
+
}
|
|
42149
|
+
if (onlyExpansions && exp.every((piece) => piece.text === "")) {
|
|
42150
|
+
return { text: word.text, exp, fields: "none" };
|
|
42151
|
+
}
|
|
42152
|
+
if (exp.length > 0 && exp.every((piece) => piece.noElements === true)) {
|
|
42153
|
+
return { text: word.text, exp, fields: "none" };
|
|
42154
|
+
}
|
|
42155
|
+
return { text: word.text, exp };
|
|
42156
|
+
});
|
|
42157
|
+
});
|
|
42158
|
+
}
|
|
42159
|
+
function positionalOf(list) {
|
|
42160
|
+
if (list.some((arg) => arg.fields === "unknown"))
|
|
42161
|
+
return;
|
|
42162
|
+
return list.filter((arg) => arg.fields !== "none").map((arg) => arg.exp);
|
|
41795
42163
|
}
|
|
41796
42164
|
function literalText(exp) {
|
|
41797
42165
|
if (exp === undefined || exp.some((piece) => piece.kind !== "literal"))
|
|
@@ -41838,6 +42206,19 @@ function visitWord(word, st, ctx) {
|
|
|
41838
42206
|
if (word !== undefined)
|
|
41839
42207
|
visitParts(word.parts, st, ctx);
|
|
41840
42208
|
}
|
|
42209
|
+
var ARITHMETIC_ASSIGNMENTS = new Set([
|
|
42210
|
+
"=",
|
|
42211
|
+
"+=",
|
|
42212
|
+
"-=",
|
|
42213
|
+
"*=",
|
|
42214
|
+
"/=",
|
|
42215
|
+
"%=",
|
|
42216
|
+
"<<=",
|
|
42217
|
+
">>=",
|
|
42218
|
+
"&=",
|
|
42219
|
+
"^=",
|
|
42220
|
+
"|="
|
|
42221
|
+
]);
|
|
41841
42222
|
function visitArithmetic(expression, st, ctx) {
|
|
41842
42223
|
if (expression === undefined)
|
|
41843
42224
|
return;
|
|
@@ -41845,9 +42226,14 @@ function visitArithmetic(expression, st, ctx) {
|
|
|
41845
42226
|
case "ArithmeticBinary":
|
|
41846
42227
|
visitArithmetic(expression.left, st, ctx);
|
|
41847
42228
|
visitArithmetic(expression.right, st, ctx);
|
|
42229
|
+
if (ARITHMETIC_ASSIGNMENTS.has(expression.operator))
|
|
42230
|
+
assignArithmetic(expression.left, st);
|
|
41848
42231
|
break;
|
|
41849
42232
|
case "ArithmeticUnary":
|
|
41850
42233
|
visitArithmetic(expression.operand, st, ctx);
|
|
42234
|
+
if (expression.operator === "++" || expression.operator === "--") {
|
|
42235
|
+
assignArithmetic(expression.operand, st);
|
|
42236
|
+
}
|
|
41851
42237
|
break;
|
|
41852
42238
|
case "ArithmeticTernary":
|
|
41853
42239
|
visitArithmetic(expression.test, st, ctx);
|
|
@@ -41865,6 +42251,13 @@ function visitArithmetic(expression, st, ctx) {
|
|
|
41865
42251
|
break;
|
|
41866
42252
|
}
|
|
41867
42253
|
}
|
|
42254
|
+
function assignArithmetic(target, st) {
|
|
42255
|
+
if (target.type !== "ArithmeticWord")
|
|
42256
|
+
return;
|
|
42257
|
+
const name = /[$`]/.test(target.value) ? undefined : target.value;
|
|
42258
|
+
const number4 = [unknown2(`\`$${target.value}\`, an arithmetic result`)];
|
|
42259
|
+
assignByName(st, name, number4, "an arithmetic expression");
|
|
42260
|
+
}
|
|
41868
42261
|
function visitTest(expression, st, ctx) {
|
|
41869
42262
|
switch (expression.type) {
|
|
41870
42263
|
case "TestUnary":
|
|
@@ -41899,11 +42292,12 @@ function clone2(st) {
|
|
|
41899
42292
|
...st,
|
|
41900
42293
|
vars: new Map(st.vars),
|
|
41901
42294
|
exported: new Set(st.exported),
|
|
41902
|
-
arrays: new Map([...st.arrays].map(([name,
|
|
42295
|
+
arrays: new Map([...st.arrays].map(([name, elements2]) => [name, new Map(elements2)])),
|
|
41903
42296
|
functions: new Map(st.functions),
|
|
41904
42297
|
traps: [...st.traps],
|
|
41905
42298
|
runningFunctions: new Set(st.runningFunctions),
|
|
41906
|
-
pidFiles: st.pidFiles
|
|
42299
|
+
pidFiles: st.pidFiles,
|
|
42300
|
+
locals: st.locals === undefined ? undefined : new Map(st.locals)
|
|
41907
42301
|
};
|
|
41908
42302
|
}
|
|
41909
42303
|
function merge2(target, branches) {
|
|
@@ -41917,9 +42311,35 @@ function merge2(target, branches) {
|
|
|
41917
42311
|
if (first !== undefined && values.every((value) => value === values[0])) {
|
|
41918
42312
|
target.vars.set(name, first);
|
|
41919
42313
|
} else {
|
|
41920
|
-
|
|
42314
|
+
const signalSafe = branches.every((branch) => {
|
|
42315
|
+
const value = branch.vars.get(name);
|
|
42316
|
+
return value !== undefined && (literalText(value) === "" || value.length > 0 && value.every((piece) => piece.descendantPid === true));
|
|
42317
|
+
});
|
|
42318
|
+
const maybeUnset = branches.some((branch) => {
|
|
42319
|
+
const value = branch.vars.get(name);
|
|
42320
|
+
return value === undefined || isUnset(value) || value.some((piece) => piece.maybeUnset);
|
|
42321
|
+
});
|
|
42322
|
+
const rewrites = branches.some((branch) => attributed(branch, name));
|
|
42323
|
+
const cause = branches.flatMap((branch) => branch.vars.get(name) ?? []).find((piece) => piece.kind === "unknown")?.why;
|
|
42324
|
+
const merged2 = unknown2(name === ANY_NAME ? `${cause ?? "a write the guard cannot read may have changed"}, in a branch or loop body` : `\`$${name}\`, which a branch sets differently${cause === undefined ? "" : ` (${cause})`}`, signalSafe ? true : undefined);
|
|
42325
|
+
target.vars.set(name, [
|
|
42326
|
+
{
|
|
42327
|
+
...merged2,
|
|
42328
|
+
...maybeUnset ? { maybeUnset: true } : {},
|
|
42329
|
+
...rewrites ? { rewrites: true } : {}
|
|
42330
|
+
}
|
|
42331
|
+
]);
|
|
41921
42332
|
}
|
|
41922
42333
|
}
|
|
42334
|
+
if (target.locals !== undefined) {
|
|
42335
|
+
const locals = new Map;
|
|
42336
|
+
for (const branch of branches) {
|
|
42337
|
+
for (const name of branch.locals?.keys() ?? []) {
|
|
42338
|
+
locals.set(name, branches.every((other) => other.locals?.get(name) === true));
|
|
42339
|
+
}
|
|
42340
|
+
}
|
|
42341
|
+
target.locals = locals;
|
|
42342
|
+
}
|
|
41923
42343
|
const arrayNames = new Set;
|
|
41924
42344
|
for (const branch of branches)
|
|
41925
42345
|
for (const name of branch.arrays.keys())
|
|
@@ -42035,13 +42455,108 @@ function walkList(statements, st, ctx) {
|
|
|
42035
42455
|
for (const statement of statements)
|
|
42036
42456
|
walkNode(statement, st, ctx, false);
|
|
42037
42457
|
}
|
|
42458
|
+
var MAX_DECIDED_PASSES = 64;
|
|
42459
|
+
function walkLoopAnyPasses(node, st, ctx) {
|
|
42460
|
+
const before = st.output;
|
|
42461
|
+
const body = clone2(st);
|
|
42462
|
+
walkList(node.clause.commands, body, ctx);
|
|
42463
|
+
walkList(node.body.commands, body, ctx);
|
|
42464
|
+
merge2(st, [clone2(st), body]);
|
|
42465
|
+
if (outputChanged(before, body.output))
|
|
42466
|
+
st.output = undefined;
|
|
42467
|
+
}
|
|
42468
|
+
function walkLoop(node, st, ctx) {
|
|
42469
|
+
if (!/\b(break|continue)\b/.test(st.source.slice(node.body.pos, node.body.end))) {
|
|
42470
|
+
for (let pass = 0;pass < MAX_DECIDED_PASSES; pass += 1) {
|
|
42471
|
+
const holds = decideCondition(node.clause, st, ctx);
|
|
42472
|
+
if (holds === undefined)
|
|
42473
|
+
break;
|
|
42474
|
+
walkList(node.clause.commands, st, ctx);
|
|
42475
|
+
if (holds === (node.kind === "until"))
|
|
42476
|
+
return;
|
|
42477
|
+
walkList(node.body.commands, st, ctx);
|
|
42478
|
+
}
|
|
42479
|
+
}
|
|
42480
|
+
walkLoopAnyPasses(node, st, ctx);
|
|
42481
|
+
}
|
|
42482
|
+
function decideCondition(clause, st, ctx) {
|
|
42483
|
+
const [statement, ...others] = clause.commands;
|
|
42484
|
+
if (statement === undefined || others.length > 0 || statement.background)
|
|
42485
|
+
return;
|
|
42486
|
+
const command = statement.command;
|
|
42487
|
+
if (statement.redirects.length > 0 || command.type !== "Command" || command.name === undefined || command.prefix.length > 0 || command.redirects.length > 0) {
|
|
42488
|
+
return;
|
|
42489
|
+
}
|
|
42490
|
+
const name = command.name.text;
|
|
42491
|
+
if (name !== "[" && name !== "test")
|
|
42492
|
+
return;
|
|
42493
|
+
const argv = args(command.suffix, st, ctx);
|
|
42494
|
+
if (argv.length !== command.suffix.length)
|
|
42495
|
+
return;
|
|
42496
|
+
const words = argv.map((arg) => literalText(arg.exp));
|
|
42497
|
+
if (words.some((word) => word === undefined || word === ""))
|
|
42498
|
+
return;
|
|
42499
|
+
const operands = words;
|
|
42500
|
+
if (name === "[")
|
|
42501
|
+
return operands.at(-1) === "]" ? evaluateTest(operands.slice(0, -1)) : undefined;
|
|
42502
|
+
return evaluateTest(operands);
|
|
42503
|
+
}
|
|
42504
|
+
function decideCase(node, st, ctx) {
|
|
42505
|
+
const words = expandWord(node.word, st, ctx);
|
|
42506
|
+
const value = words.length === 1 ? literalText(words[0]) : undefined;
|
|
42507
|
+
if (value === undefined)
|
|
42508
|
+
return;
|
|
42509
|
+
for (const item of node.items) {
|
|
42510
|
+
for (const word of item.pattern) {
|
|
42511
|
+
const patterns = expandWord(word, st, ctx);
|
|
42512
|
+
const matched = patterns.length === 1 ? matchesPattern(patterns[0], value, ctx) : undefined;
|
|
42513
|
+
if (matched === undefined)
|
|
42514
|
+
return;
|
|
42515
|
+
if (matched)
|
|
42516
|
+
return item.terminator === undefined || item.terminator === ";;" ? item : undefined;
|
|
42517
|
+
}
|
|
42518
|
+
}
|
|
42519
|
+
return;
|
|
42520
|
+
}
|
|
42521
|
+
function matchesPattern(pattern, value, ctx) {
|
|
42522
|
+
const glob = patternGlob(pattern);
|
|
42523
|
+
if (glob === undefined || !isAscii(value))
|
|
42524
|
+
return;
|
|
42525
|
+
if (!spendPatternWork(globWork(glob, value.length, ""), ctx))
|
|
42526
|
+
return;
|
|
42527
|
+
return globMatches(glob, value);
|
|
42528
|
+
}
|
|
42529
|
+
function patternGlob(pattern) {
|
|
42530
|
+
const glob = [];
|
|
42531
|
+
for (const piece of pattern) {
|
|
42532
|
+
if (piece.kind === "unknown" || !isAscii(piece.text))
|
|
42533
|
+
return;
|
|
42534
|
+
if (piece.kind === "glob") {
|
|
42535
|
+
if (piece.text === "*")
|
|
42536
|
+
glob.push(ANY_RUN);
|
|
42537
|
+
else if (piece.text === "?")
|
|
42538
|
+
glob.push(ANY_ONE);
|
|
42539
|
+
else
|
|
42540
|
+
return;
|
|
42541
|
+
} else if (/[()|]/.test(piece.text))
|
|
42542
|
+
return;
|
|
42543
|
+
else
|
|
42544
|
+
for (let i = 0;i < piece.text.length; i += 1)
|
|
42545
|
+
glob.push(piece.text.charCodeAt(i));
|
|
42546
|
+
}
|
|
42547
|
+
return glob;
|
|
42548
|
+
}
|
|
42549
|
+
function spendPatternWork(work, ctx) {
|
|
42550
|
+
ctx.steps.count += Math.ceil(work / PATTERN_WORK_PER_STEP);
|
|
42551
|
+
return ctx.steps.count <= MAX_WALK_STEPS;
|
|
42552
|
+
}
|
|
42038
42553
|
function outputChanged(before, after) {
|
|
42039
42554
|
return before !== undefined && (after === undefined || JSON.stringify(before) !== JSON.stringify(after));
|
|
42040
42555
|
}
|
|
42041
42556
|
function walkNode(node, st, ctx, pipeIn) {
|
|
42042
42557
|
if (++ctx.steps.count > MAX_WALK_STEPS) {
|
|
42043
42558
|
const site = siteOf(node, st);
|
|
42044
|
-
throw new Refusal(site.snippet, site.line,
|
|
42559
|
+
throw new Refusal(site.snippet, site.line, WALK_LIMIT);
|
|
42045
42560
|
}
|
|
42046
42561
|
switch (node.type) {
|
|
42047
42562
|
case "Statement": {
|
|
@@ -42056,6 +42571,13 @@ function walkNode(node, st, ctx, pipeIn) {
|
|
|
42056
42571
|
st.backgroundStarted = true;
|
|
42057
42572
|
return;
|
|
42058
42573
|
}
|
|
42574
|
+
if (node.command.type === "BraceGroup") {
|
|
42575
|
+
const written = groupOutputFile(node, st, ctx);
|
|
42576
|
+
if (written !== undefined) {
|
|
42577
|
+
st.files.set(written, walkRenderingGroup(node.command, st, ctx));
|
|
42578
|
+
return;
|
|
42579
|
+
}
|
|
42580
|
+
}
|
|
42059
42581
|
walkNode(node.command, st, ctx, pipeIn);
|
|
42060
42582
|
return;
|
|
42061
42583
|
}
|
|
@@ -42126,7 +42648,7 @@ function walkNode(node, st, ctx, pipeIn) {
|
|
|
42126
42648
|
if (node.type === "For" && known.every((w) => w !== undefined) && known.length <= 16) {
|
|
42127
42649
|
for (const value of known) {
|
|
42128
42650
|
const body = clone2(st);
|
|
42129
|
-
body
|
|
42651
|
+
assignScalar(body, name, [literal2(value)]);
|
|
42130
42652
|
walkList(node.body.commands, body, ctx);
|
|
42131
42653
|
branches.push(body);
|
|
42132
42654
|
}
|
|
@@ -42136,7 +42658,9 @@ function walkNode(node, st, ctx, pipeIn) {
|
|
|
42136
42658
|
const text = literalText(word.exp);
|
|
42137
42659
|
return text === "" || word.exp.length > 0 && word.exp.every((piece) => piece.descendantPid);
|
|
42138
42660
|
});
|
|
42139
|
-
body
|
|
42661
|
+
assignScalar(body, name, signalSafe ? [unknown2(`\`$${name}\`, a loop variable`, true)] : [unknown2(`\`$${name}\`, a loop variable`)]);
|
|
42662
|
+
if (node.type === "Select")
|
|
42663
|
+
assignScalar(body, "REPLY", [unknown2("`$REPLY`, read from input")]);
|
|
42140
42664
|
walkList(node.body.commands, body, ctx);
|
|
42141
42665
|
branches.push(body);
|
|
42142
42666
|
}
|
|
@@ -42158,16 +42682,19 @@ function walkNode(node, st, ctx, pipeIn) {
|
|
|
42158
42682
|
return;
|
|
42159
42683
|
}
|
|
42160
42684
|
case "While": {
|
|
42161
|
-
|
|
42162
|
-
const body = clone2(st);
|
|
42163
|
-
walkList(node.clause.commands, body, ctx);
|
|
42164
|
-
walkList(node.body.commands, body, ctx);
|
|
42165
|
-
merge2(st, [clone2(st), body]);
|
|
42166
|
-
if (outputChanged(before, body.output))
|
|
42167
|
-
st.output = undefined;
|
|
42685
|
+
walkLoop(node, st, ctx);
|
|
42168
42686
|
return;
|
|
42169
42687
|
}
|
|
42170
42688
|
case "Case": {
|
|
42689
|
+
const chosen = decideCase(node, st, ctx);
|
|
42690
|
+
if (chosen !== undefined) {
|
|
42691
|
+
visitWord(node.word, st, ctx);
|
|
42692
|
+
for (const item of node.items)
|
|
42693
|
+
for (const word of item.pattern)
|
|
42694
|
+
visitWord(word, st, ctx);
|
|
42695
|
+
walkList(chosen.body.commands, st, ctx);
|
|
42696
|
+
return;
|
|
42697
|
+
}
|
|
42171
42698
|
const before = st.output;
|
|
42172
42699
|
visitWord(node.word, st, ctx);
|
|
42173
42700
|
const branches = [clone2(st)];
|
|
@@ -42237,15 +42764,18 @@ function checkRedirects(redirects, command, site, st, ctx) {
|
|
|
42237
42764
|
const file2 = path4.resolve(st.cwd ?? "/", target);
|
|
42238
42765
|
let content = null;
|
|
42239
42766
|
if (command?.name === "cat" && command.args.length === 0) {
|
|
42240
|
-
|
|
42241
|
-
|
|
42242
|
-
|
|
42243
|
-
|
|
42244
|
-
|
|
42767
|
+
if (heredoc !== undefined)
|
|
42768
|
+
content = heredocText(heredoc);
|
|
42769
|
+
else if (herestring !== undefined)
|
|
42770
|
+
content = herestringText(herestring, st, ctx);
|
|
42771
|
+
} else if (command?.name === "echo") {
|
|
42772
|
+
content = echoText(command.args);
|
|
42773
|
+
} else if (command?.name === "printf") {
|
|
42774
|
+
content = printfText(command.args, MAX_SCRIPT_BYTES, true) ?? null;
|
|
42245
42775
|
}
|
|
42246
42776
|
st.pidFiles.delete(file2);
|
|
42247
42777
|
const before = appends ? st.files.get(file2) : "";
|
|
42248
|
-
st.files.set(file2, content === null || before === null ? null : `${before ?? ""}${content}`);
|
|
42778
|
+
st.files.set(file2, content === null || before === null ? null : readable(`${before ?? ""}${content}`));
|
|
42249
42779
|
if (writes && !appends && command?.name === "echo" && command.args.length === 1 && command.args[0]?.exp.length > 0 && command.args[0]?.exp.every((piece) => piece.descendantPid)) {
|
|
42250
42780
|
st.pidFiles.set(file2, command.args[0].exp);
|
|
42251
42781
|
}
|
|
@@ -42257,6 +42787,137 @@ function herestringText(redirect, st, ctx) {
|
|
|
42257
42787
|
return null;
|
|
42258
42788
|
return literalText(expandWord(redirect.target, st, ctx)[0]) ?? null;
|
|
42259
42789
|
}
|
|
42790
|
+
function groupOutputFile(statement, st, ctx) {
|
|
42791
|
+
const [redirect, ...others] = statement.redirects;
|
|
42792
|
+
if (redirect === undefined || others.length > 0 || redirect.fileDescriptor !== undefined) {
|
|
42793
|
+
return;
|
|
42794
|
+
}
|
|
42795
|
+
if (redirect.operator !== ">" && redirect.operator !== ">|" || redirect.target === undefined) {
|
|
42796
|
+
return;
|
|
42797
|
+
}
|
|
42798
|
+
const targets = expandWord(redirect.target, st, ctx);
|
|
42799
|
+
const target = targets.length === 1 ? literalText(targets[0]) : undefined;
|
|
42800
|
+
if (target === undefined || st.cwd === undefined && !target.startsWith("/"))
|
|
42801
|
+
return;
|
|
42802
|
+
return path4.resolve(st.cwd ?? "/", target);
|
|
42803
|
+
}
|
|
42804
|
+
function walkRenderingGroup(group, st, ctx) {
|
|
42805
|
+
let content = "";
|
|
42806
|
+
for (const statement of group.body.commands) {
|
|
42807
|
+
if (content !== null) {
|
|
42808
|
+
const text = statementOutput(statement, st, ctx);
|
|
42809
|
+
content = text === undefined ? null : readable(content + text);
|
|
42810
|
+
}
|
|
42811
|
+
walkNode(statement, st, ctx, false);
|
|
42812
|
+
}
|
|
42813
|
+
return content;
|
|
42814
|
+
}
|
|
42815
|
+
function echoText(list) {
|
|
42816
|
+
if (literalText(list[0]?.exp)?.startsWith("-"))
|
|
42817
|
+
return null;
|
|
42818
|
+
const words = [];
|
|
42819
|
+
let length = 0;
|
|
42820
|
+
for (const arg of list) {
|
|
42821
|
+
const word = literalText(arg.exp);
|
|
42822
|
+
if (word === undefined)
|
|
42823
|
+
return null;
|
|
42824
|
+
words.push(word);
|
|
42825
|
+
length += word.length + 1;
|
|
42826
|
+
}
|
|
42827
|
+
return length > MAX_SCRIPT_BYTES ? null : `${words.join(" ")}
|
|
42828
|
+
`;
|
|
42829
|
+
}
|
|
42830
|
+
function readable(content) {
|
|
42831
|
+
return content.length > MAX_SCRIPT_BYTES ? null : content;
|
|
42832
|
+
}
|
|
42833
|
+
function heredocText(heredoc) {
|
|
42834
|
+
const text = heredoc.content;
|
|
42835
|
+
if (text === undefined)
|
|
42836
|
+
return null;
|
|
42837
|
+
return !heredoc.heredocQuoted && /[$`]|\\[$`\\\n]/.test(text) ? null : text;
|
|
42838
|
+
}
|
|
42839
|
+
function statementOutput(statement, st, ctx) {
|
|
42840
|
+
const command = statement.command;
|
|
42841
|
+
if (statement.background || statement.redirects.length > 0 || command.type !== "Command") {
|
|
42842
|
+
return;
|
|
42843
|
+
}
|
|
42844
|
+
if (command.name === undefined)
|
|
42845
|
+
return command.redirects.length === 0 ? "" : undefined;
|
|
42846
|
+
const name = literalText(expandWord(command.name, st, ctx)[0]);
|
|
42847
|
+
const rest = args(command.suffix, st, ctx);
|
|
42848
|
+
if (name === "cat" && rest.length === 0) {
|
|
42849
|
+
const [heredoc, ...others] = command.redirects;
|
|
42850
|
+
if (heredoc === undefined || others.length > 0)
|
|
42851
|
+
return;
|
|
42852
|
+
if (heredoc.operator !== "<<" && heredoc.operator !== "<<-")
|
|
42853
|
+
return;
|
|
42854
|
+
return heredocText(heredoc) ?? undefined;
|
|
42855
|
+
}
|
|
42856
|
+
if (command.redirects.length > 0)
|
|
42857
|
+
return;
|
|
42858
|
+
if (name === "printf")
|
|
42859
|
+
return printfText(rest, MAX_SCRIPT_BYTES, true);
|
|
42860
|
+
if (name === "echo")
|
|
42861
|
+
return echoText(rest) ?? undefined;
|
|
42862
|
+
return;
|
|
42863
|
+
}
|
|
42864
|
+
function printfText(list, limit, script = false) {
|
|
42865
|
+
const [formatArg, ...values] = list;
|
|
42866
|
+
const format = literalText(formatArg?.exp);
|
|
42867
|
+
if (format === undefined || format.startsWith("-"))
|
|
42868
|
+
return;
|
|
42869
|
+
if (script && values.some((value) => value.fields === "unknown"))
|
|
42870
|
+
return;
|
|
42871
|
+
const parts = [];
|
|
42872
|
+
for (let i = 0;i < format.length; i += 1) {
|
|
42873
|
+
const char = format.charAt(i);
|
|
42874
|
+
const next = format.charAt(i + 1);
|
|
42875
|
+
if (char === "%") {
|
|
42876
|
+
if (next === "%")
|
|
42877
|
+
parts.push({ text: "%" });
|
|
42878
|
+
else if (next === "s" || next === "q" || next === "d")
|
|
42879
|
+
parts.push({ conversion: next });
|
|
42880
|
+
else
|
|
42881
|
+
return;
|
|
42882
|
+
i += 1;
|
|
42883
|
+
} else if (char === "\\") {
|
|
42884
|
+
const text = next === "n" ? `
|
|
42885
|
+
` : next === "t" ? "\t" : next === "\\" ? "\\" : undefined;
|
|
42886
|
+
if (text === undefined)
|
|
42887
|
+
return;
|
|
42888
|
+
parts.push({ text });
|
|
42889
|
+
i += 1;
|
|
42890
|
+
} else
|
|
42891
|
+
parts.push({ text: char });
|
|
42892
|
+
}
|
|
42893
|
+
const conversions = parts.filter((part) => ("conversion" in part)).length;
|
|
42894
|
+
let out = "";
|
|
42895
|
+
let index = 0;
|
|
42896
|
+
do {
|
|
42897
|
+
for (const part of parts) {
|
|
42898
|
+
if ("text" in part) {
|
|
42899
|
+
out += part.text;
|
|
42900
|
+
continue;
|
|
42901
|
+
}
|
|
42902
|
+
const value = values[index];
|
|
42903
|
+
index += 1;
|
|
42904
|
+
if (script && part.conversion !== "d" && value !== undefined) {
|
|
42905
|
+
if (literalText(value.exp) === undefined)
|
|
42906
|
+
return;
|
|
42907
|
+
}
|
|
42908
|
+
const text = value === undefined ? "" : runtimeText(value.exp);
|
|
42909
|
+
if (part.conversion === "s")
|
|
42910
|
+
out += text;
|
|
42911
|
+
else if (part.conversion === "d")
|
|
42912
|
+
out += /^-?[0-9]+$/.test(text) ? text : value === undefined ? "0" : UNKNOWN_MARKER;
|
|
42913
|
+
else
|
|
42914
|
+
out += shellQuoted(text);
|
|
42915
|
+
if (out.length > limit)
|
|
42916
|
+
return out;
|
|
42917
|
+
}
|
|
42918
|
+
} while (conversions > 0 && index < values.length);
|
|
42919
|
+
return out;
|
|
42920
|
+
}
|
|
42260
42921
|
function refusal(site, detail, ctx) {
|
|
42261
42922
|
return new Refusal(site.snippet, site.line, `${detail}, outside ${describeRoots(ctx.roots)}. ${HINT}`);
|
|
42262
42923
|
}
|
|
@@ -42270,39 +42931,51 @@ function handleCommand(command, st, ctx, pipeIn) {
|
|
|
42270
42931
|
visitWord(word, st, ctx);
|
|
42271
42932
|
if (assignment.name === undefined)
|
|
42272
42933
|
continue;
|
|
42273
|
-
const expanded = assignment.value === undefined ? [literal2("")] : expandWord(assignment.value, st, ctx)[0] ?? [];
|
|
42934
|
+
const expanded = stored(assignment.value === undefined ? [literal2("")] : expandWord(assignment.value, st, ctx)[0] ?? []);
|
|
42274
42935
|
const arrayAssignment = assignment.array !== undefined || assignment.append || assignment.index !== undefined;
|
|
42275
42936
|
const descendantPid = expanded.length > 0 && expanded.every((piece) => piece.descendantPid);
|
|
42276
42937
|
const value = arrayAssignment ? [unknown2(`\`$${assignment.name}\`, an array or appended value`, descendantPid || undefined)] : expanded;
|
|
42277
|
-
overlay.set(assignment.name, value);
|
|
42938
|
+
overlay.set(assignment.name, attributed(st, assignment.name) ? [{ ...unknown2(`\`$${assignment.name}\`, an attributed variable`), rewrites: true }] : value);
|
|
42278
42939
|
if (command.name === undefined) {
|
|
42279
|
-
if (arrayAssignment) {
|
|
42280
|
-
|
|
42940
|
+
if (!arrayAssignment) {
|
|
42941
|
+
assignScalar(st, assignment.name, value);
|
|
42942
|
+
} else if (attributed(st, assignment.name)) {
|
|
42943
|
+
keepAttributed(st, assignment.name);
|
|
42944
|
+
} else {
|
|
42945
|
+
const elements2 = assignment.array !== undefined && !assignment.append ? new Map : new Map(st.arrays.get(assignment.name) ?? []);
|
|
42281
42946
|
if (assignment.array !== undefined) {
|
|
42282
|
-
let index = assignment.append ? Math.max(0, ...[...
|
|
42283
|
-
|
|
42284
|
-
|
|
42285
|
-
|
|
42947
|
+
let index = assignment.append ? Math.max(0, ...[...elements2.keys()].filter((key) => /^[0-9]+$/.test(key)).map((key) => Number(key) + 1)) : 0;
|
|
42948
|
+
const words2 = args(assignment.array, st, ctx);
|
|
42949
|
+
if (words2.some((word) => word.fields === "unknown")) {
|
|
42950
|
+
elements2.clear();
|
|
42951
|
+
elements2.set(UNKNOWN_ARRAY_INDEX, [
|
|
42952
|
+
unknown2(`\`$${assignment.name}\`, an array a word of which may be several elements`)
|
|
42953
|
+
]);
|
|
42954
|
+
} else {
|
|
42955
|
+
for (const word of words2) {
|
|
42956
|
+
if (word.fields === "none")
|
|
42957
|
+
continue;
|
|
42958
|
+
elements2.set(String(index), stored(word.exp));
|
|
42959
|
+
index += 1;
|
|
42960
|
+
}
|
|
42286
42961
|
}
|
|
42287
42962
|
} else if (assignment.append) {
|
|
42288
|
-
const index = Math.max(0, ...[...
|
|
42289
|
-
|
|
42963
|
+
const index = Math.max(0, ...[...elements2.keys()].filter((key) => /^[0-9]+$/.test(key)).map((key) => Number(key) + 1));
|
|
42964
|
+
elements2.set(String(index), expanded);
|
|
42290
42965
|
} else {
|
|
42291
42966
|
const index = resolveArrayIndex(assignment.index, st, ctx);
|
|
42292
42967
|
if (index === undefined) {
|
|
42293
|
-
|
|
42294
|
-
|
|
42968
|
+
elements2.clear();
|
|
42969
|
+
elements2.set(UNKNOWN_ARRAY_INDEX, [
|
|
42295
42970
|
unknown2(`\`$${assignment.name}\`, an array element with an unresolved index`)
|
|
42296
42971
|
]);
|
|
42297
42972
|
} else {
|
|
42298
|
-
|
|
42973
|
+
elements2.set(index, expanded);
|
|
42299
42974
|
}
|
|
42300
42975
|
}
|
|
42301
|
-
st.arrays.set(assignment.name,
|
|
42302
|
-
|
|
42303
|
-
st.arrays.delete(assignment.name);
|
|
42976
|
+
st.arrays.set(assignment.name, elements2);
|
|
42977
|
+
st.vars.set(assignment.name, value);
|
|
42304
42978
|
}
|
|
42305
|
-
st.vars.set(assignment.name, value);
|
|
42306
42979
|
}
|
|
42307
42980
|
}
|
|
42308
42981
|
const words = command.name === undefined ? command.suffix : [command.name, ...command.suffix];
|
|
@@ -42441,7 +43114,7 @@ function unwrap2(argv, st, ctx, site) {
|
|
|
42441
43114
|
list = rest.slice(i);
|
|
42442
43115
|
state = { ...clone2(state), cwd, cwdWhy: "`env -C`" };
|
|
42443
43116
|
for (const name2 of unset) {
|
|
42444
|
-
state.vars.set(name2,
|
|
43117
|
+
state.vars.set(name2, UNSET);
|
|
42445
43118
|
state.exported.delete(name2);
|
|
42446
43119
|
}
|
|
42447
43120
|
for (const [name2, value] of overlay) {
|
|
@@ -42458,9 +43131,10 @@ function runFunction(name, definition, args2, outer, ctx) {
|
|
|
42458
43131
|
return;
|
|
42459
43132
|
const child = {
|
|
42460
43133
|
...clone2(outer),
|
|
42461
|
-
positional: args2
|
|
43134
|
+
positional: positionalOf(args2),
|
|
42462
43135
|
source: definition.source,
|
|
42463
|
-
script: definition.file ?? outer.script
|
|
43136
|
+
script: definition.file ?? outer.script,
|
|
43137
|
+
locals: new Map
|
|
42464
43138
|
};
|
|
42465
43139
|
child.runningFunctions.add(name);
|
|
42466
43140
|
try {
|
|
@@ -42468,11 +43142,12 @@ function runFunction(name, definition, args2, outer, ctx) {
|
|
|
42468
43142
|
} catch (error48) {
|
|
42469
43143
|
locateRefusal(error48, definition.file);
|
|
42470
43144
|
}
|
|
43145
|
+
returnLocals(name, child, outer);
|
|
42471
43146
|
outer.vars = child.vars;
|
|
42472
43147
|
outer.exported = child.exported;
|
|
42473
43148
|
outer.arrays.clear();
|
|
42474
|
-
for (const [name2,
|
|
42475
|
-
outer.arrays.set(name2, new Map(
|
|
43149
|
+
for (const [name2, elements2] of child.arrays)
|
|
43150
|
+
outer.arrays.set(name2, new Map(elements2));
|
|
42476
43151
|
outer.cwd = child.cwd;
|
|
42477
43152
|
outer.cwdWhy = child.cwdWhy;
|
|
42478
43153
|
outer.functions = child.functions;
|
|
@@ -42480,15 +43155,47 @@ function runFunction(name, definition, args2, outer, ctx) {
|
|
|
42480
43155
|
outer.output = child.output;
|
|
42481
43156
|
outer.backgroundStarted ||= child.backgroundStarted;
|
|
42482
43157
|
}
|
|
43158
|
+
function returnLocals(name, child, caller) {
|
|
43159
|
+
for (const [local, everyPath] of child.locals ?? []) {
|
|
43160
|
+
const value = caller.vars.get(local);
|
|
43161
|
+
const elements2 = caller.arrays.get(local);
|
|
43162
|
+
if (everyPath) {
|
|
43163
|
+
if (value === undefined)
|
|
43164
|
+
child.vars.delete(local);
|
|
43165
|
+
else
|
|
43166
|
+
child.vars.set(local, value);
|
|
43167
|
+
if (elements2 === undefined)
|
|
43168
|
+
child.arrays.delete(local);
|
|
43169
|
+
else
|
|
43170
|
+
child.arrays.set(local, new Map(elements2));
|
|
43171
|
+
if (caller.exported.has(local))
|
|
43172
|
+
child.exported.add(local);
|
|
43173
|
+
else
|
|
43174
|
+
child.exported.delete(local);
|
|
43175
|
+
continue;
|
|
43176
|
+
}
|
|
43177
|
+
const same = JSON.stringify(child.vars.get(local) ?? null) === JSON.stringify(value ?? null) && JSON.stringify([...child.arrays.get(local) ?? []]) === JSON.stringify([...elements2 ?? []]);
|
|
43178
|
+
if (same)
|
|
43179
|
+
continue;
|
|
43180
|
+
const either = [
|
|
43181
|
+
{ ...unknown2(`\`$${local}\`, local to \`${name}\` on some paths`), maybeUnset: true }
|
|
43182
|
+
];
|
|
43183
|
+
child.vars.set(local, either);
|
|
43184
|
+
if (elements2 !== undefined || child.arrays.has(local)) {
|
|
43185
|
+
child.arrays.set(local, new Map([[UNKNOWN_ARRAY_INDEX, either]]));
|
|
43186
|
+
}
|
|
43187
|
+
}
|
|
43188
|
+
}
|
|
42483
43189
|
function functionOutput(name, definition, args2, outer, ctx) {
|
|
42484
43190
|
if (outer.runningFunctions.has(name))
|
|
42485
43191
|
return;
|
|
42486
43192
|
const child = {
|
|
42487
43193
|
...clone2(outer),
|
|
42488
|
-
positional: args2
|
|
43194
|
+
positional: positionalOf(args2),
|
|
42489
43195
|
source: definition.source,
|
|
42490
43196
|
script: definition.file ?? outer.script,
|
|
42491
|
-
output: []
|
|
43197
|
+
output: [],
|
|
43198
|
+
locals: new Map
|
|
42492
43199
|
};
|
|
42493
43200
|
child.runningFunctions.add(name);
|
|
42494
43201
|
try {
|
|
@@ -42529,7 +43236,9 @@ function dispatch(invocation, outer, ctx) {
|
|
|
42529
43236
|
return;
|
|
42530
43237
|
}
|
|
42531
43238
|
const stdoutRedirected = invocation.redirects.some((redirect) => (redirect.fileDescriptor === undefined || redirect.fileDescriptor === 1) && [">", ">>", ">|", "&>", "&>>", ">&"].includes(redirect.operator));
|
|
42532
|
-
|
|
43239
|
+
const umaskWords = base === "umask" ? rest.map((arg) => literalText(arg.exp)) : [];
|
|
43240
|
+
const silentUmask = umaskWords.every((word) => word !== undefined) && umaskWords.some((word) => !word?.startsWith("-"));
|
|
43241
|
+
if (outer.output !== undefined && !stdoutRedirected && base !== "echo" && base !== "printf" && !silentUmask && FUNCTION_OUTPUT_SILENT[base] !== true) {
|
|
42533
43242
|
outer.output = undefined;
|
|
42534
43243
|
}
|
|
42535
43244
|
switch (base) {
|
|
@@ -42553,35 +43262,68 @@ function dispatch(invocation, outer, ctx) {
|
|
|
42553
43262
|
case "typeset":
|
|
42554
43263
|
case "local":
|
|
42555
43264
|
case "readonly":
|
|
42556
|
-
declaration(base, rest, outer, ctx);
|
|
43265
|
+
declaration(base, rest, outer, ctx, site);
|
|
42557
43266
|
return;
|
|
42558
|
-
case "unset":
|
|
42559
|
-
|
|
42560
|
-
|
|
42561
|
-
|
|
42562
|
-
|
|
42563
|
-
|
|
43267
|
+
case "unset": {
|
|
43268
|
+
const found = operands(rest, "");
|
|
43269
|
+
const functionsOnly = found.options.some((option) => /^-[a-zA-Z]*f/.test(option));
|
|
43270
|
+
const variablesOnly = found.options.some((option) => /^-[a-zA-Z]*v/.test(option));
|
|
43271
|
+
for (const arg of found.operands) {
|
|
43272
|
+
const name2 = literalText(arg.exp);
|
|
43273
|
+
if (!variablesOnly) {
|
|
43274
|
+
if (name2 === undefined) {
|
|
43275
|
+
for (const [fn, callee2] of outer.functions)
|
|
43276
|
+
outer.functions.set(fn, orCommand(callee2));
|
|
43277
|
+
} else {
|
|
43278
|
+
const callee2 = outer.functions.get(name2);
|
|
43279
|
+
const held = functionsOnly ? undefined : lookup(name2, outer, ctx);
|
|
43280
|
+
if (callee2 !== undefined && held === undefined)
|
|
43281
|
+
outer.functions.delete(name2);
|
|
43282
|
+
else if (callee2 !== undefined && held?.some((piece) => piece.maybeUnset)) {
|
|
43283
|
+
outer.functions.set(name2, orCommand(callee2));
|
|
43284
|
+
}
|
|
43285
|
+
}
|
|
42564
43286
|
}
|
|
43287
|
+
if (functionsOnly)
|
|
43288
|
+
continue;
|
|
43289
|
+
if (name2 === undefined || !IDENTIFIER.test(name2)) {
|
|
43290
|
+
assignByName(outer, name2, [], "`unset`");
|
|
43291
|
+
continue;
|
|
43292
|
+
}
|
|
43293
|
+
if (attributed(outer, name2)) {
|
|
43294
|
+
keepAttributed(outer, name2, true);
|
|
43295
|
+
continue;
|
|
43296
|
+
}
|
|
43297
|
+
outer.vars.set(name2, UNSET);
|
|
43298
|
+
outer.exported.delete(name2);
|
|
43299
|
+
outer.arrays.delete(name2);
|
|
42565
43300
|
}
|
|
42566
43301
|
return;
|
|
43302
|
+
}
|
|
42567
43303
|
case "read":
|
|
42568
43304
|
case "mapfile":
|
|
42569
43305
|
case "readarray":
|
|
42570
43306
|
case "getopts": {
|
|
42571
|
-
|
|
42572
|
-
|
|
42573
|
-
|
|
42574
|
-
|
|
42575
|
-
const
|
|
42576
|
-
|
|
42577
|
-
|
|
42578
|
-
|
|
42579
|
-
|
|
42580
|
-
|
|
42581
|
-
|
|
42582
|
-
|
|
42583
|
-
|
|
42584
|
-
|
|
43307
|
+
readInput(base, rest, outer);
|
|
43308
|
+
return;
|
|
43309
|
+
}
|
|
43310
|
+
case "wait": {
|
|
43311
|
+
for (const [index, arg] of rest.entries()) {
|
|
43312
|
+
if (!/^-[a-zA-Z]*p$/.test(literalText(arg.exp) ?? ""))
|
|
43313
|
+
continue;
|
|
43314
|
+
const pid = [{ ...unknown2("the pid `wait -p` assigns", true), maybeUnset: true }];
|
|
43315
|
+
assignByName(outer, literalText(rest[index + 1]?.exp), pid, "`wait -p`");
|
|
43316
|
+
}
|
|
43317
|
+
return;
|
|
43318
|
+
}
|
|
43319
|
+
case "let": {
|
|
43320
|
+
for (const arg of rest) {
|
|
43321
|
+
const text = literalText(arg.exp);
|
|
43322
|
+
const command = text === undefined ? undefined : parse5(`(( ${text} ))`).commands[0]?.command;
|
|
43323
|
+
if (command?.type === "ArithmeticCommand")
|
|
43324
|
+
visitArithmetic(command.expression, outer, ctx);
|
|
43325
|
+
else
|
|
43326
|
+
forgetVariables(outer, "`let` in text the guard cannot read may have changed");
|
|
42585
43327
|
}
|
|
42586
43328
|
return;
|
|
42587
43329
|
}
|
|
@@ -42589,22 +43331,46 @@ function dispatch(invocation, outer, ctx) {
|
|
|
42589
43331
|
const list = rest.map((arg) => literalText(arg.exp));
|
|
42590
43332
|
const dashDash = list.indexOf("--");
|
|
42591
43333
|
if (dashDash !== -1)
|
|
42592
|
-
outer.positional = rest.slice(dashDash + 1)
|
|
43334
|
+
outer.positional = positionalOf(rest.slice(dashDash + 1));
|
|
42593
43335
|
else if (list.length > 0 && !list[0]?.startsWith("-") && !list[0]?.startsWith("+")) {
|
|
42594
|
-
outer.positional = rest
|
|
43336
|
+
outer.positional = positionalOf(rest);
|
|
42595
43337
|
}
|
|
42596
43338
|
return;
|
|
42597
43339
|
}
|
|
42598
43340
|
case "shift": {
|
|
42599
|
-
const
|
|
42600
|
-
|
|
43341
|
+
const text = rest.length === 0 ? "1" : literalText(rest[0]?.exp);
|
|
43342
|
+
if (text === undefined)
|
|
43343
|
+
outer.positional = undefined;
|
|
43344
|
+
else if (/^[0-9]+$/.test(text) && outer.positional !== undefined) {
|
|
43345
|
+
const count = Number(text);
|
|
43346
|
+
if (count <= outer.positional.length)
|
|
43347
|
+
outer.positional = outer.positional.slice(count);
|
|
43348
|
+
}
|
|
42601
43349
|
return;
|
|
42602
43350
|
}
|
|
42603
43351
|
case "printf": {
|
|
42604
|
-
const
|
|
42605
|
-
const
|
|
42606
|
-
|
|
42607
|
-
|
|
43352
|
+
const head = rest[0]?.exp ?? [];
|
|
43353
|
+
const leading = head[0];
|
|
43354
|
+
const spaced = literalText(head) === "-v";
|
|
43355
|
+
const joined = !spaced && leading?.kind === "literal" && leading.text.startsWith("-v") && (leading.text.length > 2 || head.length > 1);
|
|
43356
|
+
if (spaced || joined) {
|
|
43357
|
+
const variable = spaced ? literalText(rest[1]?.exp) : literalText([
|
|
43358
|
+
{ ...leading, text: leading?.text.slice(2) ?? "" },
|
|
43359
|
+
...head.slice(1)
|
|
43360
|
+
]);
|
|
43361
|
+
const printed = rest.slice(spaced ? 2 : 1);
|
|
43362
|
+
const [format, value, ...others] = printed;
|
|
43363
|
+
let assigned;
|
|
43364
|
+
if (literalText(format?.exp) === "%s" && value !== undefined && others.length === 0) {
|
|
43365
|
+
assigned = value.exp;
|
|
43366
|
+
} else {
|
|
43367
|
+
const text = printfText(printed, MAX_VALUE_LENGTH);
|
|
43368
|
+
const cause = printed.flatMap((arg) => arg.exp).find((p) => p.kind === "unknown")?.why;
|
|
43369
|
+
assigned = text === undefined || text.includes(UNKNOWN_MARKER) ? [
|
|
43370
|
+
unknown2(`\`$${variable ?? "?"}\` (printf -v${cause === undefined ? "" : `: ${cause}`})`)
|
|
43371
|
+
] : text.length > MAX_VALUE_LENGTH ? [overLong(`\`$${variable ?? "?"}\` (printf -v)`)] : [literal2(text)];
|
|
43372
|
+
}
|
|
43373
|
+
assignByName(outer, variable, assigned, "`printf -v`");
|
|
42608
43374
|
return;
|
|
42609
43375
|
}
|
|
42610
43376
|
if (outer.output !== undefined && !stdoutRedirected) {
|
|
@@ -42613,7 +43379,11 @@ function dispatch(invocation, outer, ctx) {
|
|
|
42613
43379
|
return;
|
|
42614
43380
|
}
|
|
42615
43381
|
case "eval": {
|
|
42616
|
-
|
|
43382
|
+
const text = rest.map((arg) => runtimeText(arg.exp)).join(" ");
|
|
43383
|
+
runText(text, "the `eval` text", outer, ctx, site);
|
|
43384
|
+
if (text.includes(UNKNOWN_MARKER)) {
|
|
43385
|
+
forgetVariables(outer, "`eval` of text the guard cannot read may have changed");
|
|
43386
|
+
}
|
|
42617
43387
|
return;
|
|
42618
43388
|
}
|
|
42619
43389
|
case "trap": {
|
|
@@ -42621,12 +43391,12 @@ function dispatch(invocation, outer, ctx) {
|
|
|
42621
43391
|
if (handler === undefined)
|
|
42622
43392
|
return;
|
|
42623
43393
|
const text = literalText(handler.exp);
|
|
42624
|
-
const
|
|
42625
|
-
const signals =
|
|
43394
|
+
const readable2 = conditions.map((arg) => literalText(arg.exp));
|
|
43395
|
+
const signals = readable2.map((condition) => condition === undefined ? UNREADABLE_CONDITION : trapSignal(condition));
|
|
42626
43396
|
const handled = signals.length === 0 ? ["EXIT"] : signals;
|
|
42627
43397
|
const file2 = outer.script ?? outer.source;
|
|
42628
43398
|
if (text === "-") {
|
|
42629
|
-
const named =
|
|
43399
|
+
const named = readable2.flatMap((condition) => condition === undefined ? [] : [trapSignal(condition)]);
|
|
42630
43400
|
outer.traps = outer.traps.flatMap((trap) => {
|
|
42631
43401
|
const signals2 = trap.signals.filter((signal) => !named.includes(signal));
|
|
42632
43402
|
return signals2.length === 0 ? [] : [{ ...trap, signals: signals2 }];
|
|
@@ -42759,7 +43529,8 @@ function dispatch(invocation, outer, ctx) {
|
|
|
42759
43529
|
if (target !== undefined && st.cwd !== undefined) {
|
|
42760
43530
|
const file2 = path4.resolve(st.cwd, target);
|
|
42761
43531
|
st.pidFiles.delete(file2);
|
|
42762
|
-
|
|
43532
|
+
const text = heredoc === undefined ? null : heredocText(heredoc);
|
|
43533
|
+
st.files.set(file2, append || text === null ? null : readable(text));
|
|
42763
43534
|
}
|
|
42764
43535
|
}
|
|
42765
43536
|
return;
|
|
@@ -42862,37 +43633,156 @@ function changeDirectory(target, st, ctx) {
|
|
|
42862
43633
|
}
|
|
42863
43634
|
st.cwd = path4.resolve(st.cwd, text);
|
|
42864
43635
|
}
|
|
42865
|
-
function declaration(builtin, list, st, ctx) {
|
|
42866
|
-
const
|
|
43636
|
+
function declaration(builtin, list, st, ctx, site) {
|
|
43637
|
+
const options = list.map((arg) => literalText(arg.exp) ?? "").filter((text) => /^[-+][a-zA-Z]+$/.test(text));
|
|
43638
|
+
const option = (letter) => options.some((text) => text.startsWith("-") && text.includes(letter));
|
|
43639
|
+
if (builtin !== "export" && option("n")) {
|
|
43640
|
+
throw new Refusal(site.snippet, site.line, "the guard does not follow a nameref (`declare -n`), whose writes land in the variable it names");
|
|
43641
|
+
}
|
|
43642
|
+
if (option("f") || option("F"))
|
|
43643
|
+
return;
|
|
43644
|
+
if (builtin === "local" && st.locals === undefined)
|
|
43645
|
+
return;
|
|
43646
|
+
const array2 = option("a") || option("A");
|
|
43647
|
+
const exports = builtin === "export" || option("x");
|
|
43648
|
+
const keeps = builtin === "readonly" || option("r");
|
|
43649
|
+
const rewrites = option("i") || option("l") || option("u");
|
|
43650
|
+
const locals = builtin === "local" || (builtin === "declare" || builtin === "typeset") && !option("g") ? st.locals : undefined;
|
|
43651
|
+
const writer = `\`${builtin}\``;
|
|
42867
43652
|
for (const arg of list) {
|
|
42868
|
-
const
|
|
42869
|
-
|
|
42870
|
-
|
|
42871
|
-
|
|
43653
|
+
const text = literalText(arg.exp);
|
|
43654
|
+
if (text !== undefined && /^[-+][a-zA-Z]+$/.test(text))
|
|
43655
|
+
continue;
|
|
43656
|
+
const { name, value: assigned } = nameAndValue(arg);
|
|
43657
|
+
if (name === undefined) {
|
|
43658
|
+
forgetVariables(st, `${writer} under a name the guard cannot read may have changed`);
|
|
43659
|
+
continue;
|
|
43660
|
+
}
|
|
43661
|
+
const base = ARRAY_ELEMENT.exec(name)?.[1] ?? name;
|
|
43662
|
+
if (!IDENTIFIER.test(base))
|
|
43663
|
+
continue;
|
|
43664
|
+
if (exports)
|
|
43665
|
+
st.exported.add(base);
|
|
43666
|
+
if (rewrites || attributed(st, base) && (assigned !== undefined || locals !== undefined)) {
|
|
43667
|
+
keepAttributed(st, base);
|
|
42872
43668
|
continue;
|
|
42873
|
-
|
|
43669
|
+
}
|
|
43670
|
+
if (attributed(st, base))
|
|
42874
43671
|
continue;
|
|
42875
|
-
if (
|
|
42876
|
-
|
|
42877
|
-
|
|
43672
|
+
if (locals !== undefined) {
|
|
43673
|
+
locals.set(base, true);
|
|
43674
|
+
if (assigned === undefined) {
|
|
43675
|
+
st.vars.set(base, UNSET);
|
|
43676
|
+
st.arrays.delete(base);
|
|
43677
|
+
}
|
|
43678
|
+
}
|
|
43679
|
+
if (assigned === undefined) {
|
|
43680
|
+
if (keeps)
|
|
43681
|
+
markKept(st, base, ctx);
|
|
42878
43682
|
continue;
|
|
42879
|
-
|
|
42880
|
-
|
|
42881
|
-
|
|
42882
|
-
|
|
42883
|
-
|
|
42884
|
-
|
|
42885
|
-
|
|
42886
|
-
|
|
42887
|
-
if (array2) {
|
|
42888
|
-
if (arg.text.slice(equals + 1) === "()") {
|
|
42889
|
-
st.arrays.set(variable, new Map);
|
|
43683
|
+
}
|
|
43684
|
+
const value = arg.text.startsWith(`${name}=~`) ? [...unquotedLiteral(arg.text.slice(name.length + 1), 0, st, ctx), ...arg.exp.slice(1)] : assigned;
|
|
43685
|
+
if (!array2 || name !== base) {
|
|
43686
|
+
assignByName(st, name, value, writer);
|
|
43687
|
+
} else {
|
|
43688
|
+
st.vars.set(name, [unknown2(`\`$${name}\`, an array`)]);
|
|
43689
|
+
if (arg.text === `${name}=()`) {
|
|
43690
|
+
st.arrays.set(name, new Map);
|
|
42890
43691
|
} else {
|
|
42891
|
-
const unknownArray = [unknown2(`\`$${
|
|
42892
|
-
st.arrays.set(
|
|
43692
|
+
const unknownArray = [unknown2(`\`$${name}\`, an array assignment`)];
|
|
43693
|
+
st.arrays.set(name, new Map([[UNKNOWN_ARRAY_INDEX, unknownArray]]));
|
|
42893
43694
|
}
|
|
42894
43695
|
}
|
|
43696
|
+
if (keeps)
|
|
43697
|
+
markKept(st, base, ctx);
|
|
43698
|
+
}
|
|
43699
|
+
}
|
|
43700
|
+
function markKept(st, name, ctx) {
|
|
43701
|
+
const held = st.vars.get(name) ?? lookup(name, st, ctx) ?? UNSET;
|
|
43702
|
+
const value = held.length === 0 ? [literal2("")] : held;
|
|
43703
|
+
st.vars.set(name, value.map((piece) => ({ ...piece, rewrites: true })));
|
|
43704
|
+
}
|
|
43705
|
+
function readInput(builtin, rest, st) {
|
|
43706
|
+
const valued = builtin === "read" ? "adinNptu" : builtin === "getopts" ? "" : "dnOsuCc";
|
|
43707
|
+
const writer = `\`${builtin}\``;
|
|
43708
|
+
const input = (name) => [
|
|
43709
|
+
unknown2(`\`$${name ?? "?"}\`, read from input`)
|
|
43710
|
+
];
|
|
43711
|
+
let array2;
|
|
43712
|
+
let arrayOption = false;
|
|
43713
|
+
const names = [];
|
|
43714
|
+
let options = builtin !== "getopts";
|
|
43715
|
+
for (let i = 0;i < rest.length; i += 1) {
|
|
43716
|
+
const arg = rest[i];
|
|
43717
|
+
const text = literalText(arg.exp);
|
|
43718
|
+
if (options && text === "--") {
|
|
43719
|
+
options = false;
|
|
43720
|
+
continue;
|
|
43721
|
+
}
|
|
43722
|
+
if (options && text !== undefined && /^-./.test(text)) {
|
|
43723
|
+
for (let j = 1;j < text.length; j += 1) {
|
|
43724
|
+
const flag = text.charAt(j);
|
|
43725
|
+
if (!valued.includes(flag))
|
|
43726
|
+
continue;
|
|
43727
|
+
const attached = text.slice(j + 1);
|
|
43728
|
+
i += attached === "" ? 1 : 0;
|
|
43729
|
+
const value = attached === "" ? rest[i] : { text: attached, exp: [literal2(attached)] };
|
|
43730
|
+
if (flag === "a" && builtin === "read") {
|
|
43731
|
+
arrayOption = true;
|
|
43732
|
+
array2 = value;
|
|
43733
|
+
}
|
|
43734
|
+
break;
|
|
43735
|
+
}
|
|
43736
|
+
continue;
|
|
43737
|
+
}
|
|
43738
|
+
options = false;
|
|
43739
|
+
names.push(arg);
|
|
43740
|
+
}
|
|
43741
|
+
const fill = (arg, fallback) => {
|
|
43742
|
+
const name = arg === undefined ? fallback : literalText(arg.exp);
|
|
43743
|
+
if (name === undefined || !IDENTIFIER.test(name) || attributed(st, name)) {
|
|
43744
|
+
assignByName(st, name, input(name), writer);
|
|
43745
|
+
return;
|
|
43746
|
+
}
|
|
43747
|
+
st.vars.set(name, input(name));
|
|
43748
|
+
st.arrays.set(name, new Map([[UNKNOWN_ARRAY_INDEX, input(name)]]));
|
|
43749
|
+
};
|
|
43750
|
+
if (builtin === "getopts") {
|
|
43751
|
+
const name = names[1];
|
|
43752
|
+
if (name !== undefined)
|
|
43753
|
+
assignByName(st, literalText(name.exp), input(name.text), writer);
|
|
43754
|
+
for (const variable of ["OPTARG", "OPTIND"])
|
|
43755
|
+
assignScalar(st, variable, input(variable));
|
|
43756
|
+
} else if (builtin !== "read") {
|
|
43757
|
+
fill(names[0], "MAPFILE");
|
|
43758
|
+
} else if (arrayOption) {
|
|
43759
|
+
if (array2 !== undefined)
|
|
43760
|
+
fill(array2, "");
|
|
43761
|
+
} else if (names.length === 0) {
|
|
43762
|
+
assignScalar(st, "REPLY", input("REPLY"));
|
|
43763
|
+
} else {
|
|
43764
|
+
for (const name of names)
|
|
43765
|
+
assignByName(st, literalText(name.exp), input(name.text), writer);
|
|
43766
|
+
}
|
|
43767
|
+
}
|
|
43768
|
+
function orCommand(callee) {
|
|
43769
|
+
return callee.includes(undefined) ? callee : [...callee, undefined];
|
|
43770
|
+
}
|
|
43771
|
+
function nameAndValue(arg) {
|
|
43772
|
+
let name = "";
|
|
43773
|
+
for (const [index, piece] of arg.exp.entries()) {
|
|
43774
|
+
if (piece.kind !== "literal")
|
|
43775
|
+
return { name: undefined, value: undefined };
|
|
43776
|
+
const equals = piece.text.indexOf("=");
|
|
43777
|
+
if (equals === -1) {
|
|
43778
|
+
name += piece.text;
|
|
43779
|
+
continue;
|
|
43780
|
+
}
|
|
43781
|
+
const rest = piece.text.slice(equals + 1);
|
|
43782
|
+
const value = [...rest === "" ? [] : [{ ...piece, text: rest }], ...arg.exp.slice(index + 1)];
|
|
43783
|
+
return { name: name + piece.text.slice(0, equals), value };
|
|
42895
43784
|
}
|
|
43785
|
+
return { name, value: undefined };
|
|
42896
43786
|
}
|
|
42897
43787
|
function checkTargets(program, verb, targets, follow, st, ctx, site) {
|
|
42898
43788
|
for (const target of targets) {
|
|
@@ -43118,11 +44008,18 @@ function childState(st, overlay) {
|
|
|
43118
44008
|
if (value !== undefined)
|
|
43119
44009
|
vars.set(name, value);
|
|
43120
44010
|
}
|
|
44011
|
+
for (const [name, value] of st.vars)
|
|
44012
|
+
if (isUnset(value))
|
|
44013
|
+
vars.set(name, value);
|
|
43121
44014
|
for (const [name, value] of overlay)
|
|
43122
44015
|
vars.set(name, value);
|
|
44016
|
+
const exported = new Set(vars.keys());
|
|
44017
|
+
const any2 = st.vars.get(ANY_NAME);
|
|
44018
|
+
if (any2 !== undefined)
|
|
44019
|
+
vars.set(ANY_NAME, any2);
|
|
43123
44020
|
return {
|
|
43124
44021
|
vars,
|
|
43125
|
-
exported
|
|
44022
|
+
exported,
|
|
43126
44023
|
cwd: st.cwd,
|
|
43127
44024
|
cwdWhy: st.cwdWhy,
|
|
43128
44025
|
positional: [],
|
|
@@ -43138,7 +44035,8 @@ function childState(st, overlay) {
|
|
|
43138
44035
|
arrays: new Map,
|
|
43139
44036
|
functions: new Map,
|
|
43140
44037
|
traps: [],
|
|
43141
|
-
runningFunctions: new Set
|
|
44038
|
+
runningFunctions: new Set,
|
|
44039
|
+
locals: undefined
|
|
43142
44040
|
};
|
|
43143
44041
|
}
|
|
43144
44042
|
function runText(text, label, st, ctx, site) {
|
|
@@ -43185,19 +44083,23 @@ function runShell(list, invocation, st, ctx) {
|
|
|
43185
44083
|
child.argv0 = operand[1]?.exp;
|
|
43186
44084
|
if (command) {
|
|
43187
44085
|
const text = operand[0] === undefined ? "" : runtimeText(operand[0].exp);
|
|
43188
|
-
child.positional = operand.slice(2)
|
|
44086
|
+
child.positional = positionalOf(operand.slice(2));
|
|
43189
44087
|
runText(text, "its `-c` text", child, ctx, site);
|
|
43190
44088
|
return;
|
|
43191
44089
|
}
|
|
43192
44090
|
const file2 = operand[0];
|
|
43193
44091
|
if (file2 !== undefined) {
|
|
43194
|
-
child.positional = operand.slice(1)
|
|
44092
|
+
child.positional = positionalOf(operand.slice(1));
|
|
43195
44093
|
runFile(file2, operand.slice(1), child, ctx, site, "shell");
|
|
43196
44094
|
return;
|
|
43197
44095
|
}
|
|
43198
44096
|
const heredoc = invocation.redirects.find((r) => r.operator === "<<" || r.operator === "<<-");
|
|
43199
|
-
if (heredoc
|
|
43200
|
-
|
|
44097
|
+
if (heredoc !== undefined) {
|
|
44098
|
+
const text = heredocText(heredoc);
|
|
44099
|
+
if (text === null) {
|
|
44100
|
+
throw new Refusal(site.snippet, site.line, "the guard cannot read the script this shell reads from its here-document, which bash expands first; quote its delimiter (`<<'EOF'`) or write the script with the write tool");
|
|
44101
|
+
}
|
|
44102
|
+
runText(text, "the script it reads from the heredoc", child, ctx, site);
|
|
43201
44103
|
return;
|
|
43202
44104
|
}
|
|
43203
44105
|
const herestring = invocation.redirects.find((r) => r.operator === "<<<");
|
|
@@ -43253,8 +44155,12 @@ function runInterpreter(base, language, list, invocation, st, ctx) {
|
|
|
43253
44155
|
return;
|
|
43254
44156
|
if (word === "-") {
|
|
43255
44157
|
const heredoc = invocation.redirects.find((r) => r.operator === "<<" || r.operator === "<<-");
|
|
43256
|
-
if (heredoc
|
|
43257
|
-
|
|
44158
|
+
if (heredoc !== undefined) {
|
|
44159
|
+
const text = heredocText(heredoc);
|
|
44160
|
+
if (text === null) {
|
|
44161
|
+
throw new Refusal(site.snippet, site.line, "the guard cannot read the program this interpreter reads from its here-document, which bash expands first; quote its delimiter (`<<'PY'`) or write the program with the write tool");
|
|
44162
|
+
}
|
|
44163
|
+
runCode(language, { text: "<heredoc>", exp: [literal2(text)] }, invocation, st, ctx, site);
|
|
43258
44164
|
}
|
|
43259
44165
|
return;
|
|
43260
44166
|
}
|
|
@@ -43290,7 +44196,7 @@ function runFile(file2, positional, st, ctx, site, kind, source = false) {
|
|
|
43290
44196
|
if (st.files.has(abs)) {
|
|
43291
44197
|
const written = st.files.get(abs);
|
|
43292
44198
|
if (written === null || written === undefined) {
|
|
43293
|
-
throw new Refusal(site.snippet, site.line, `this command writes ${abs} in a way the guard cannot read before running it; write the script with the write tool first`);
|
|
44199
|
+
throw new Refusal(site.snippet, site.line, `this command writes ${abs} in a way the guard cannot read before running it (output it cannot render, or more than the ${MAX_SCRIPT_BYTES} bytes it reads of a script); write the script with the write tool first`);
|
|
43294
44200
|
}
|
|
43295
44201
|
content = written;
|
|
43296
44202
|
} else {
|
|
@@ -43326,22 +44232,24 @@ function runFile(file2, positional, st, ctx, site, kind, source = false) {
|
|
|
43326
44232
|
throw new Refusal(site.snippet, site.line, "the guard stops following scripts this deep; run the inner script directly");
|
|
43327
44233
|
}
|
|
43328
44234
|
const child = { ...clone2(st), source: content, script: abs, depth: st.depth + 1 };
|
|
43329
|
-
const operands2 = positional
|
|
43330
|
-
|
|
44235
|
+
const operands2 = positionalOf(positional);
|
|
44236
|
+
const noOperands = operands2 !== undefined && operands2.length === 0;
|
|
44237
|
+
child.positional = source && noOperands ? st.positional : operands2;
|
|
43331
44238
|
walkScript(parse5(content), child, ctx, !source);
|
|
43332
44239
|
if (source) {
|
|
43333
|
-
st.positional =
|
|
44240
|
+
st.positional = noOperands ? child.positional : child.positional === operands2 ? st.positional : undefined;
|
|
43334
44241
|
st.vars = child.vars;
|
|
43335
44242
|
st.exported = child.exported;
|
|
43336
44243
|
st.arrays.clear();
|
|
43337
|
-
for (const [name,
|
|
43338
|
-
st.arrays.set(name, new Map(
|
|
44244
|
+
for (const [name, elements2] of child.arrays)
|
|
44245
|
+
st.arrays.set(name, new Map(elements2));
|
|
43339
44246
|
st.cwd = child.cwd;
|
|
43340
44247
|
st.cwdWhy = child.cwdWhy;
|
|
43341
44248
|
st.functions = child.functions;
|
|
43342
44249
|
st.traps = child.traps;
|
|
43343
44250
|
st.output = child.output;
|
|
43344
44251
|
st.backgroundStarted ||= child.backgroundStarted;
|
|
44252
|
+
st.locals = child.locals;
|
|
43345
44253
|
}
|
|
43346
44254
|
} else
|
|
43347
44255
|
checkCode(language, content, st, ctx);
|
|
@@ -43383,7 +44291,9 @@ function checkCode(language, code, st, ctx, ipython = false) {
|
|
|
43383
44291
|
const env = { ...ctx.env };
|
|
43384
44292
|
for (const [name, value] of st.vars) {
|
|
43385
44293
|
const text = literalText(value);
|
|
43386
|
-
if (
|
|
44294
|
+
if (isUnset(value))
|
|
44295
|
+
delete env[name];
|
|
44296
|
+
else if (text !== undefined)
|
|
43387
44297
|
env[name] = text;
|
|
43388
44298
|
}
|
|
43389
44299
|
scanCode(language, code, { env, cwd: cwd ?? "/", tmpdir: env.TMPDIR ?? "/tmp", ipython }, {
|
|
@@ -43465,12 +44375,14 @@ function createPaneGuard(options) {
|
|
|
43465
44375
|
if (workspace === "/" || home !== undefined && (home === workspace || home.startsWith(`${workspace}/`))) {
|
|
43466
44376
|
workspace = undefined;
|
|
43467
44377
|
}
|
|
43468
|
-
const protectedScratch = [...PROTECTED_SCRATCH];
|
|
43469
44378
|
const tmuxDir = env.TMUX_TMPDIR === undefined ? undefined : realish(env.TMUX_TMPDIR, true);
|
|
43470
|
-
|
|
43471
|
-
|
|
44379
|
+
const protectedDirectories = [];
|
|
44380
|
+
for (const owned of [tmuxDir, home]) {
|
|
44381
|
+
const component = owned?.startsWith(`${scratch}/`) ? owned.slice(scratch.length + 1).split("/")[0] : undefined;
|
|
44382
|
+
if (component !== undefined && component !== "")
|
|
44383
|
+
protectedDirectories.push(component);
|
|
43472
44384
|
}
|
|
43473
|
-
return { workspace, scratch, protectedScratch };
|
|
44385
|
+
return { workspace, scratch, protectedScratch: PROTECTED_SCRATCH, protectedDirectories };
|
|
43474
44386
|
};
|
|
43475
44387
|
const context = (env) => ({
|
|
43476
44388
|
roots: roots(env),
|
|
@@ -43497,12 +44409,13 @@ function createPaneGuard(options) {
|
|
|
43497
44409
|
pidFiles: new Map,
|
|
43498
44410
|
arrays: new Map,
|
|
43499
44411
|
functions: new Map,
|
|
43500
|
-
traps: []
|
|
44412
|
+
traps: [],
|
|
44413
|
+
locals: undefined
|
|
43501
44414
|
});
|
|
43502
|
-
const run = (attempt, fallback) => {
|
|
44415
|
+
const run = (ctx, attempt, fallback) => {
|
|
43503
44416
|
try {
|
|
43504
44417
|
attempt();
|
|
43505
|
-
return;
|
|
44418
|
+
return ctx.steps.count > MAX_WALK_STEPS ? `refused \`${fallback}\`: ${WALK_LIMIT}` : undefined;
|
|
43506
44419
|
} catch (error48) {
|
|
43507
44420
|
if (!(error48 instanceof Refusal))
|
|
43508
44421
|
throw error48;
|
|
@@ -43512,13 +44425,13 @@ function createPaneGuard(options) {
|
|
|
43512
44425
|
return {
|
|
43513
44426
|
bash: (command, cwd, env) => {
|
|
43514
44427
|
const ctx = context(env);
|
|
43515
|
-
return run(() => walkScript(parse5(command), initial(cwd, command), ctx), command.trim());
|
|
44428
|
+
return run(ctx, () => walkScript(parse5(command), initial(cwd, command), ctx), command.trim());
|
|
43516
44429
|
},
|
|
43517
44430
|
argv: (argv, cwd, env) => {
|
|
43518
44431
|
const ctx = context(env);
|
|
43519
44432
|
const list = argv.map((item) => ({ text: item, exp: [literal2(item)] }));
|
|
43520
44433
|
const snippet = argv.join(" ");
|
|
43521
|
-
return run(() => dispatch({
|
|
44434
|
+
return run(ctx, () => dispatch({
|
|
43522
44435
|
args: list,
|
|
43523
44436
|
site: { snippet, line: 1 },
|
|
43524
44437
|
overlay: new Map,
|
|
@@ -43528,7 +44441,7 @@ function createPaneGuard(options) {
|
|
|
43528
44441
|
},
|
|
43529
44442
|
code: (language, code, cwd, env) => {
|
|
43530
44443
|
const ctx = context(env);
|
|
43531
|
-
return run(() => checkCode(language, code, initial(cwd, code), ctx, true), `${language} code`);
|
|
44444
|
+
return run(ctx, () => checkCode(language, code, initial(cwd, code), ctx, true), `${language} code`);
|
|
43532
44445
|
}
|
|
43533
44446
|
};
|
|
43534
44447
|
}
|