@poe-platform/safe-bash 0.1.744 → 0.1.745
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/README.md +5 -0
- package/dist/safe-bash/chunks/{chunk-2CO4WCMK.js → chunk-EAUCLWEZ.js} +16 -5
- package/dist/safe-bash/chunks/{chunk-WN7FYUWU.js → chunk-MC2KZY3D.js} +26 -13
- package/dist/safe-bash/chunks/{pdf-renderer-3TVUXNBT.js → pdf-renderer-4APIM7F7.js} +2 -2
- package/dist/safe-bash/chunks/{src-5VZS2ZKB.js → src-FTMTU65U.js} +2 -2
- package/dist/safe-bash/core.browser.js +1057 -619
- package/dist/safe-bash/opt-in/shell/extensions/read/index.js +1 -2
- package/dist/safe-bash/playwright/capability-events.d.ts +7 -0
- package/dist/safe-bash/playwright/capability-events.js +11 -3
- package/dist/safe-bash/playwright/controller.d.ts +14 -0
- package/dist/safe-bash/playwright/controller.js +36 -8
- package/dist/safe-bash/playwright/index.d.ts +1 -0
- package/dist/safe-bash/playwright/index.js +1 -0
- package/dist/safe-bash/shell/runtime.d.ts +14 -1
- package/dist/safe-bash/shell/runtime.js +1395 -717
- package/dist/safe-bash-command-ssconvert/index.js +15 -4
- package/dist/safe-bash-command-wkhtmltopdf/index.js +24 -11
- package/dist/safe-bash-command-wkhtmltopdf/limits.d.ts +1 -1
- package/dist/safe-bash-command-wkhtmltopdf/resources.d.ts +1 -1
- package/package.json +2 -2
|
@@ -3771,7 +3771,7 @@ export class Runtime {
|
|
|
3771
3771
|
throw new NounsetDiagnosticFailure(reason);
|
|
3772
3772
|
}
|
|
3773
3773
|
}
|
|
3774
|
-
extractSimpleErePattern(pattern) {
|
|
3774
|
+
extractSimpleErePattern(pattern, state) {
|
|
3775
3775
|
const cached = pattern._cachedSimpleEre;
|
|
3776
3776
|
if (cached !== undefined)
|
|
3777
3777
|
return cached ?? undefined;
|
|
@@ -3781,8 +3781,35 @@ export class Runtime {
|
|
|
3781
3781
|
}
|
|
3782
3782
|
if (pattern.parts.length === 1) {
|
|
3783
3783
|
const p0 = pattern.parts[0];
|
|
3784
|
+
if (state !== undefined &&
|
|
3785
|
+
p0.kind === "variable" &&
|
|
3786
|
+
!p0.quoted &&
|
|
3787
|
+
!p0.operator &&
|
|
3788
|
+
!p0.substring &&
|
|
3789
|
+
!p0.length &&
|
|
3790
|
+
!p0.indirect &&
|
|
3791
|
+
!p0.prefixNames &&
|
|
3792
|
+
!p0.specialParameter &&
|
|
3793
|
+
!p0.transform &&
|
|
3794
|
+
getArraySelector(p0) === undefined &&
|
|
3795
|
+
isShellIdentifier(p0.name) &&
|
|
3796
|
+
!stateMonitor(state)?.store?.get(p0.name)) {
|
|
3797
|
+
const raw = state.variables[p0.name];
|
|
3798
|
+
const val = this._syncArithRawWriteOnly && this._syncArithTouched?.has(p0.name)
|
|
3799
|
+
? raw
|
|
3800
|
+
: (raw === undefined ? undefined : (stateMonitor(state)?.values.get(p0.name, raw) ?? raw));
|
|
3801
|
+
if (typeof val !== "string" || val.length === 0 || val.includes("\\") || val.includes("~"))
|
|
3802
|
+
return undefined;
|
|
3803
|
+
const varCache = pattern._cachedVarEre;
|
|
3804
|
+
if (varCache && varCache.text === val)
|
|
3805
|
+
return varCache;
|
|
3806
|
+
const nextVarCache = { text: val, literal: false, isVar: p0.name };
|
|
3807
|
+
pattern._cachedVarEre = nextVarCache;
|
|
3808
|
+
return nextVarCache;
|
|
3809
|
+
}
|
|
3784
3810
|
if (p0.kind !== "text" || p0.byteValue || p0.value.includes("\\") || p0.value.includes("~")) {
|
|
3785
|
-
|
|
3811
|
+
if (p0.kind !== "variable")
|
|
3812
|
+
pattern._cachedSimpleEre = null;
|
|
3786
3813
|
return undefined;
|
|
3787
3814
|
}
|
|
3788
3815
|
const res = { text: p0.value, literal: !!p0.quoted };
|
|
@@ -3803,7 +3830,7 @@ export class Runtime {
|
|
|
3803
3830
|
return res;
|
|
3804
3831
|
}
|
|
3805
3832
|
getFastAnchoredEreRegex(pattern, state) {
|
|
3806
|
-
const pat = this.extractSimpleErePattern(pattern);
|
|
3833
|
+
const pat = this.extractSimpleErePattern(pattern, state);
|
|
3807
3834
|
if (!pat || pat.literal || state.nocasematch || this.budget.limits.maxExpansionBytes !== Infinity || this.budget.limits.maxExpansionFields !== Infinity) {
|
|
3808
3835
|
return undefined;
|
|
3809
3836
|
}
|
|
@@ -3831,6 +3858,8 @@ export class Runtime {
|
|
|
3831
3858
|
}
|
|
3832
3859
|
}
|
|
3833
3860
|
if (caretOk &&
|
|
3861
|
+
!pat.text.includes("|") &&
|
|
3862
|
+
!/[*+?][*+?]/.test(pat.text) &&
|
|
3834
3863
|
/^[\^a-zA-Z0-9_.\-/:@()\[\]+?*,;=| $]+$/.test(pat.text) &&
|
|
3835
3864
|
!pat.text.includes("[:") &&
|
|
3836
3865
|
!pat.text.includes("[.") &&
|
|
@@ -3853,7 +3882,7 @@ export class Runtime {
|
|
|
3853
3882
|
return patWithCache._fastAnchoredRe ?? undefined;
|
|
3854
3883
|
}
|
|
3855
3884
|
trySyncEre(subject, pattern, state, ignoreYield = false) {
|
|
3856
|
-
const pat = this.extractSimpleErePattern(pattern);
|
|
3885
|
+
const pat = this.extractSimpleErePattern(pattern, state);
|
|
3857
3886
|
if (!pat)
|
|
3858
3887
|
return undefined;
|
|
3859
3888
|
const monitor = stateMonitor(state);
|
|
@@ -5820,7 +5849,7 @@ export class Runtime {
|
|
|
5820
5849
|
if (!entry.index || entry.append)
|
|
5821
5850
|
return false;
|
|
5822
5851
|
const kSrc = entry.index.source ?? entry.index.decimal;
|
|
5823
|
-
if (kSrc.length === 0 || kSrc.length > 4096 || /[$\x60\\"']/.test(kSrc))
|
|
5852
|
+
if (kSrc.length === 0 || kSrc.length > 4096 || kSrc.startsWith("~") || /[$\x60\\"']/.test(kSrc))
|
|
5824
5853
|
return false;
|
|
5825
5854
|
let val = "";
|
|
5826
5855
|
if (entry.value.parts.length > 0) {
|
|
@@ -5904,6 +5933,34 @@ export class Runtime {
|
|
|
5904
5933
|
}
|
|
5905
5934
|
continue;
|
|
5906
5935
|
}
|
|
5936
|
+
if (entry.value.parts.length === 1 &&
|
|
5937
|
+
!entry.value.parts[0].quoted &&
|
|
5938
|
+
(entry.value.parts[0].kind === "variable" || entry.value.parts[0].kind === "substitution") &&
|
|
5939
|
+
(rawState.variables.IFS === undefined || rawState.variables.IFS === " \t\n") &&
|
|
5940
|
+
!rawState.noglob &&
|
|
5941
|
+
this.budget.limits.maxExpansionFields === Infinity &&
|
|
5942
|
+
this.budget.limits.maxExpansionBytes === Infinity) {
|
|
5943
|
+
let unsplit;
|
|
5944
|
+
try {
|
|
5945
|
+
unsplit = this.fastValueWord(entry.value, rawState, io, false, false, false, false, undefined, diagnosticLine);
|
|
5946
|
+
}
|
|
5947
|
+
catch {
|
|
5948
|
+
return false;
|
|
5949
|
+
}
|
|
5950
|
+
if (typeof unsplit !== "string" || hasGlobOrEscape(unsplit, !!rawState.extglob))
|
|
5951
|
+
return false;
|
|
5952
|
+
const cw = entry.value;
|
|
5953
|
+
const splitWords = (cw._cachedSplitSrc === unsplit && cw._cachedSplitWords !== undefined)
|
|
5954
|
+
? cw._cachedSplitWords
|
|
5955
|
+
: (cw._cachedSplitSrc = unsplit, cw._cachedSplitWords = unsplit.split(/[ \t\n]+/).filter(w => w.length > 0));
|
|
5956
|
+
if (splitWords.length > 1500)
|
|
5957
|
+
return false;
|
|
5958
|
+
for (let swIdx = 0; swIdx < splitWords.length; swIdx++) {
|
|
5959
|
+
const sw = splitWords[swIdx];
|
|
5960
|
+
items.push({ explicitIdx: undefined, val: sw, bLen: shellValueByteLength(sw) });
|
|
5961
|
+
}
|
|
5962
|
+
continue;
|
|
5963
|
+
}
|
|
5907
5964
|
if (entry.value.parts.length === 0 || !entry.value.parts.every(p => p.quoted || (p.kind === "text" && p.value.length > 0 && !p.value.includes(" ") && !p.value.includes("\t") && !p.value.includes("\n") && !p.value.includes("{") && !hasGlobOrEscape(p.value, true)))) {
|
|
5908
5965
|
return false;
|
|
5909
5966
|
}
|
|
@@ -5941,18 +5998,16 @@ export class Runtime {
|
|
|
5941
5998
|
}
|
|
5942
5999
|
try {
|
|
5943
6000
|
if (!assignment.append && target.values.size > 0) {
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
target.remove(k);
|
|
5948
|
-
}
|
|
5949
|
-
let newMax = -1;
|
|
5950
|
-
for (const k of target.values.keys()) {
|
|
5951
|
-
if (k > newMax)
|
|
5952
|
-
newMax = k;
|
|
5953
|
-
}
|
|
5954
|
-
target.maximum = newMax;
|
|
6001
|
+
for (const k of target.values.keys()) {
|
|
6002
|
+
if (!keepIndices.has(k))
|
|
6003
|
+
target.remove(k);
|
|
5955
6004
|
}
|
|
6005
|
+
let newMax = -1;
|
|
6006
|
+
for (const k of target.values.keys()) {
|
|
6007
|
+
if (k > newMax)
|
|
6008
|
+
newMax = k;
|
|
6009
|
+
}
|
|
6010
|
+
target.maximum = newMax;
|
|
5956
6011
|
}
|
|
5957
6012
|
for (let i = 0; i < resolved.length; i++) {
|
|
5958
6013
|
const { idx, val, bLen } = resolved[i];
|
|
@@ -8804,7 +8859,7 @@ export class Runtime {
|
|
|
8804
8859
|
return false;
|
|
8805
8860
|
if (isAssoc) {
|
|
8806
8861
|
const kSrc = e.index ? (e.index.source ?? e.index.decimal) : "";
|
|
8807
|
-
return kSrc.length > 0 && !/[$\x60\\"']/.test(kSrc) && isNoBraceSyncAssignWord(e.value);
|
|
8862
|
+
return kSrc.length > 0 && !kSrc.startsWith("~") && !/[$\x60\\"']/.test(kSrc) && isNoBraceSyncAssignWord(e.value);
|
|
8808
8863
|
}
|
|
8809
8864
|
if (e.index !== undefined) {
|
|
8810
8865
|
const kSrc = (e.index.source ?? e.index.decimal).trim();
|
|
@@ -9019,7 +9074,7 @@ export class Runtime {
|
|
|
9019
9074
|
return false;
|
|
9020
9075
|
if (wantAssoc) {
|
|
9021
9076
|
const kSrc = e.index ? (e.index.source ?? e.index.decimal) : "";
|
|
9022
|
-
return kSrc.length > 0 && !/[$\x60\\"']/.test(kSrc) && isNoBraceSyncAssignWord(e.value);
|
|
9077
|
+
return kSrc.length > 0 && !kSrc.startsWith("~") && !/[$\x60\\"']/.test(kSrc) && isNoBraceSyncAssignWord(e.value);
|
|
9023
9078
|
}
|
|
9024
9079
|
if (e.index !== undefined) {
|
|
9025
9080
|
const kSrc = (e.index.source ?? e.index.decimal).trim();
|
|
@@ -9346,7 +9401,7 @@ export class Runtime {
|
|
|
9346
9401
|
return (e.operator === "-n" || e.operator === "-z" || e.operator === "-v" || (syncConditionalFileUnaryOps.has(e.operator) && this._isMemoryBackingFs && this.canFastMemoryRedirect && this.budget.limits.maxFileSystemOperations >= 1000 && (this._fileWrites === undefined || this._fileWrites.size === 0) && (this._outputFiles === undefined || this._outputFiles.size === 0))) && this.isPureSyncValueWord(e.operand, rawState);
|
|
9347
9402
|
if (e.kind === "binary") {
|
|
9348
9403
|
if (e.operator === "=~") {
|
|
9349
|
-
if (!this.isPureSyncValueWord(e.left, rawState) || !this.extractSimpleErePattern(e.right) || rawState.readonlyVariables?.has("BASH_REMATCH") || rawState.exported.has("BASH_REMATCH") || hasUnpreparedLocal(rawState, "BASH_REMATCH"))
|
|
9404
|
+
if (!this.isPureSyncValueWord(e.left, rawState) || !this.extractSimpleErePattern(e.right, rawState) || rawState.readonlyVariables?.has("BASH_REMATCH") || rawState.exported.has("BASH_REMATCH") || hasUnpreparedLocal(rawState, "BASH_REMATCH"))
|
|
9350
9405
|
return false;
|
|
9351
9406
|
const mon = stateMonitor(rawState);
|
|
9352
9407
|
if (!mon || (this.budget.limits.maxExpansionBytes !== Infinity || this.budget.limits.maxExpansionFields !== Infinity) || mon.hasOverlay("BASH_REMATCH"))
|
|
@@ -9721,7 +9776,7 @@ export class Runtime {
|
|
|
9721
9776
|
// Matching publishes BASH_REMATCH. A sibling may still require fallback,
|
|
9722
9777
|
// so only a standalone match can be attempted without replaying writes.
|
|
9723
9778
|
if (expr.operator === "=~")
|
|
9724
|
-
return depth === 0 && this.extractSimpleErePattern(expr.right) !== undefined;
|
|
9779
|
+
return depth === 0 && this.extractSimpleErePattern(expr.right, rawState) !== undefined;
|
|
9725
9780
|
if (expr.operator === "==" || expr.operator === "=" || expr.operator === "!=") {
|
|
9726
9781
|
if (expr.right.parts.length > 0 && expr.right.parts.every(p => p.quoted))
|
|
9727
9782
|
return true;
|
|
@@ -9845,7 +9900,7 @@ export class Runtime {
|
|
|
9845
9900
|
if (expr.operator === "=~") {
|
|
9846
9901
|
if (depth !== 0)
|
|
9847
9902
|
return undefined;
|
|
9848
|
-
if (!this.extractSimpleErePattern(expr.right))
|
|
9903
|
+
if (!this.extractSimpleErePattern(expr.right, rawState))
|
|
9849
9904
|
return undefined;
|
|
9850
9905
|
let subject;
|
|
9851
9906
|
try {
|
|
@@ -11202,7 +11257,7 @@ export class Runtime {
|
|
|
11202
11257
|
catch {
|
|
11203
11258
|
scanArgs = undefined;
|
|
11204
11259
|
}
|
|
11205
|
-
if (typeof optstring === "string" && scanArgs !== undefined) {
|
|
11260
|
+
if (typeof optstring === "string" && (!optstring.startsWith("-") || optstring === "-") && scanArgs !== undefined) {
|
|
11206
11261
|
rawState.getopts ??= cloneGetoptsBinding(rawState);
|
|
11207
11262
|
const res = scanGetoptsSync(rawState.getopts.cursor, optstring, scanArgs);
|
|
11208
11263
|
if (res !== undefined) {
|
|
@@ -12279,10 +12334,11 @@ export class Runtime {
|
|
|
12279
12334
|
const ops = [];
|
|
12280
12335
|
for (let ui = uStart; ui < command.words.length; ui++) {
|
|
12281
12336
|
const wu = command.words[ui];
|
|
12337
|
+
const canSkipGlobUnset = Boolean(wu.parts[0]?.quoted || rawState.noglob || (!rawState.nullglob && this._isMemoryBackingFs && tryGetMemoryDirectoryEntryNamesSync(this.backingFs, rawState.cwd)?.size === 0));
|
|
12282
12338
|
let tExpanded;
|
|
12283
12339
|
try {
|
|
12284
|
-
const fv = this.fastValueWord(wu, rawState, io,
|
|
12285
|
-
if (typeof fv === "string")
|
|
12340
|
+
const fv = this.fastValueWord(wu, rawState, io, !canSkipGlobUnset, false, false, true, undefined, diagnosticLine);
|
|
12341
|
+
if (typeof fv === "string" && (!canSkipGlobUnset || (!fv.includes(" ") && !fv.includes("\t") && !fv.includes("\n"))))
|
|
12286
12342
|
tExpanded = fv;
|
|
12287
12343
|
}
|
|
12288
12344
|
catch { }
|
|
@@ -13515,8 +13571,42 @@ export class Runtime {
|
|
|
13515
13571
|
// as loop state changes. Decide before the loop produces any effects.
|
|
13516
13572
|
if (this._syncLoopFnCheckDepth > 0 && (part.substring || getArraySelector(part)?.kind === "element"))
|
|
13517
13573
|
return false;
|
|
13518
|
-
if (part.prefixNames !== undefined
|
|
13519
|
-
|
|
13574
|
+
if (part.prefixNames !== undefined) {
|
|
13575
|
+
if (part.indirect ||
|
|
13576
|
+
part.specialParameter ||
|
|
13577
|
+
part.length ||
|
|
13578
|
+
part.substring ||
|
|
13579
|
+
part.transform !== undefined ||
|
|
13580
|
+
part.operator !== undefined ||
|
|
13581
|
+
getArraySelector(part) !== undefined ||
|
|
13582
|
+
this.budget.limits.maxExpansionFields !== Infinity ||
|
|
13583
|
+
this.budget.limits.maxExpansionBytes !== Infinity ||
|
|
13584
|
+
!isShellIdentifier(part.name)) {
|
|
13585
|
+
return false;
|
|
13586
|
+
}
|
|
13587
|
+
continue;
|
|
13588
|
+
}
|
|
13589
|
+
if (part.transform !== undefined) {
|
|
13590
|
+
if ((part.transform !== "U" && part.transform !== "L" && part.transform !== "u" && (part.transform !== "Q" || byteLocale(rawState.variables))) ||
|
|
13591
|
+
part.indirect ||
|
|
13592
|
+
part.specialParameter ||
|
|
13593
|
+
part.length ||
|
|
13594
|
+
part.substring ||
|
|
13595
|
+
part.operator !== undefined ||
|
|
13596
|
+
getArraySelector(part) !== undefined ||
|
|
13597
|
+
this.budget.limits.maxExpansionBytes !== Infinity ||
|
|
13598
|
+
!isShellIdentifier(part.name) ||
|
|
13599
|
+
stateMonitor(rawState)?.store?.get(part.name) ||
|
|
13600
|
+
part.name === "PIPESTATUS" ||
|
|
13601
|
+
part.name === "LINENO" ||
|
|
13602
|
+
part.name === "_" ||
|
|
13603
|
+
part.name === "FUNCNAME" ||
|
|
13604
|
+
part.name === "DIRSTACK" ||
|
|
13605
|
+
(rawState.nounset && rawState.variables[part.name] === undefined)) {
|
|
13606
|
+
return false;
|
|
13607
|
+
}
|
|
13608
|
+
continue;
|
|
13609
|
+
}
|
|
13520
13610
|
if (!part.indirect && !part.prefixNames && !part.length && !part.substring && !part.transform && part.operator === undefined && getArraySelector(part) === undefined && (part.name === "?" || part.name === "#" || (part.name.length === 1 && part.name >= "1" && part.name <= "9"))) {
|
|
13521
13611
|
if (rawState.nounset && part.name >= "1" && part.name <= "9" && rawState.positional[part.name.charCodeAt(0) - 49] === undefined)
|
|
13522
13612
|
return false;
|
|
@@ -13691,11 +13781,12 @@ export class Runtime {
|
|
|
13691
13781
|
!cmd.redirects[0].move &&
|
|
13692
13782
|
!cmd.redirects[0].document &&
|
|
13693
13783
|
this.isPureSyncValueWord(cmd.redirects[0].target, rawState);
|
|
13694
|
-
|
|
13695
|
-
|
|
13696
|
-
|
|
13697
|
-
}
|
|
13784
|
+
// Loop substitutions require a real subshell: header admission can
|
|
13785
|
+
// decline at runtime, and induction writes also change export attributes.
|
|
13786
|
+
if (cmd.kind === "for" || cmd.kind === "arithmetic-for" || cmd.kind === "while")
|
|
13698
13787
|
return false;
|
|
13788
|
+
if (p.commands.length === 1 && (cmd.kind === "if" || cmd.kind === "case") && this.isPureSyncSubIfOrCase(cmd, rawState)) {
|
|
13789
|
+
continue;
|
|
13699
13790
|
}
|
|
13700
13791
|
if (cmd.kind !== "simple" || (cmd.redirects.length > 0 && !hasSingleStdinRedir && !hasSingleHereStringRedir) || cmd.words.length === 0)
|
|
13701
13792
|
return false;
|
|
@@ -13748,14 +13839,15 @@ export class Runtime {
|
|
|
13748
13839
|
w0Plain === "cut" ||
|
|
13749
13840
|
w0Plain === "wc" ||
|
|
13750
13841
|
w0Plain === "sort" ||
|
|
13842
|
+
w0Plain === "uniq" ||
|
|
13751
13843
|
w0Plain === "tr" ||
|
|
13752
13844
|
(hasSingleHereStringRedir && (w0Plain === "base64" || w0Plain === "rev" || w0Plain === "tac" || w0Plain === "nl"));
|
|
13753
|
-
|
|
13845
|
+
const def = w0Plain ? (this.commands.get(w0Plain) ?? ((w0Plain === "rev" || w0Plain === "tac") ? this.getExternalCommand(w0Plain) : undefined)) : undefined;
|
|
13846
|
+
if (!w0Plain || (w0Plain !== "printf" && w0Plain !== "echo" && w0Plain !== "dirname" && w0Plain !== "basename" && w0Plain !== "seq" && !isFileCommand) || !def || rawState.functions.has(w0Plain) || rawState.extensions?.builtins.has(w0Plain))
|
|
13754
13847
|
return false;
|
|
13755
13848
|
if ((hasSingleStdinRedir || hasSingleHereStringRedir) && !isFileCommand)
|
|
13756
13849
|
return false;
|
|
13757
|
-
|
|
13758
|
-
if (!def || (w0Plain === "printf" ? def.execute !== printfCommand.execute : w0Plain === "echo" ? !defaultEchoExecutors.has(def.execute) : w0Plain === "seq" ? (!builtInDirectContextExecutors.has(def.execute) && (customRegisteredCommands.has(def.execute) || customRegisteredRegistries.has(this.commands))) : !builtInDirectContextExecutors.has(def.execute)))
|
|
13850
|
+
if (w0Plain === "printf" ? def.execute !== printfCommand.execute : w0Plain === "echo" ? !defaultEchoExecutors.has(def.execute) : (w0Plain === "seq" || w0Plain === "rev" || w0Plain === "tac") ? (!builtInDirectContextExecutors.has(def.execute) && (customRegisteredCommands.has(def.execute) || customRegisteredRegistries.has(this.commands))) : !builtInDirectContextExecutors.has(def.execute))
|
|
13759
13851
|
return false;
|
|
13760
13852
|
if (!cmd.words.slice(1).every(w => this.isPureSyncValueWord(w, rawState)))
|
|
13761
13853
|
return false;
|
|
@@ -13772,7 +13864,10 @@ export class Runtime {
|
|
|
13772
13864
|
if (!vCheck || vCheck.byteLength > 16384 || vCheck.includes(0))
|
|
13773
13865
|
return false;
|
|
13774
13866
|
}
|
|
13775
|
-
const
|
|
13867
|
+
const opWords = (hasSingleStdinRedir || hasSingleHereStringRedir) ? cmd.words.slice(1) : cmd.words.slice(1, -1);
|
|
13868
|
+
const opCount = opWords.length;
|
|
13869
|
+
const op0 = opWords[0]?.plain;
|
|
13870
|
+
const op1 = opWords[1]?.plain;
|
|
13776
13871
|
if (w0Plain === "cat" || w0Plain === "rev" || w0Plain === "tac" || w0Plain === "nl") {
|
|
13777
13872
|
if (opCount !== 0)
|
|
13778
13873
|
return false;
|
|
@@ -13780,18 +13875,61 @@ export class Runtime {
|
|
|
13780
13875
|
else {
|
|
13781
13876
|
if (p.commands.length !== 1 && !hasSingleHereStringRedir)
|
|
13782
13877
|
return false;
|
|
13783
|
-
if (
|
|
13784
|
-
|
|
13785
|
-
|
|
13786
|
-
|
|
13787
|
-
|
|
13788
|
-
|
|
13789
|
-
|
|
13790
|
-
|
|
13791
|
-
|
|
13792
|
-
|
|
13793
|
-
|
|
13794
|
-
|
|
13878
|
+
if (w0Plain === "head" || w0Plain === "tail") {
|
|
13879
|
+
const validHT = opCount === 0 ||
|
|
13880
|
+
(opCount === 1 && op0 !== undefined && /^-(?:n|c)?[0-9]{1,5}$/.test(op0)) ||
|
|
13881
|
+
(opCount === 2 && (op0 === "-n" || op0 === "-c") && op1 !== undefined && /^[0-9]{1,5}$/.test(op1));
|
|
13882
|
+
if (!validHT)
|
|
13883
|
+
return false;
|
|
13884
|
+
}
|
|
13885
|
+
const plainOps = [];
|
|
13886
|
+
for (let oi = 0; oi < opCount; oi++) {
|
|
13887
|
+
const ow = opWords[oi];
|
|
13888
|
+
const pw = ow.plain ?? (ow.parts.length > 0 && ow.parts.every(pt => pt.kind === "text") ? ow.parts.map(pt => pt.value).join("") : undefined);
|
|
13889
|
+
if (pw === undefined)
|
|
13890
|
+
break;
|
|
13891
|
+
plainOps.push(pw);
|
|
13892
|
+
}
|
|
13893
|
+
if (w0Plain === "cut") {
|
|
13894
|
+
if (plainOps.length !== opCount || this.evalSyncCut([], plainOps, byteLocale(rawState.variables)) === undefined)
|
|
13895
|
+
return false;
|
|
13896
|
+
}
|
|
13897
|
+
else if (w0Plain === "sed") {
|
|
13898
|
+
if (plainOps.length !== opCount || this.evalSyncSed([], plainOps) === undefined)
|
|
13899
|
+
return false;
|
|
13900
|
+
}
|
|
13901
|
+
else if (w0Plain === "grep") {
|
|
13902
|
+
if (plainOps.length !== opCount || this.evalSyncGrep([], plainOps, Boolean(rawState.errexit)) === undefined)
|
|
13903
|
+
return false;
|
|
13904
|
+
}
|
|
13905
|
+
else if (w0Plain === "awk") {
|
|
13906
|
+
if (plainOps.length !== opCount || this.evalSyncAwk([], plainOps) === undefined)
|
|
13907
|
+
return false;
|
|
13908
|
+
}
|
|
13909
|
+
else if (w0Plain === "jq") {
|
|
13910
|
+
if (plainOps.length !== opCount || this.evalSyncJq("null", plainOps) === undefined)
|
|
13911
|
+
return false;
|
|
13912
|
+
}
|
|
13913
|
+
else if (w0Plain === "wc") {
|
|
13914
|
+
if (opCount !== 1 || (op0 !== "-l" && op0 !== "-c" && op0 !== "-w"))
|
|
13915
|
+
return false;
|
|
13916
|
+
}
|
|
13917
|
+
else if (w0Plain === "sort") {
|
|
13918
|
+
if (byteLocale(rawState.variables) || opCount > 1 || (opCount === 1 && op0 !== "-r" && op0 !== "-u" && op0 !== "-n" && op0 !== "-rn" && op0 !== "-nr" && op0 !== "-ru" && op0 !== "-ur"))
|
|
13919
|
+
return false;
|
|
13920
|
+
}
|
|
13921
|
+
else if (w0Plain === "uniq") {
|
|
13922
|
+
if (opCount > 1 || (opCount === 1 && op0 !== "-d" && op0 !== "-u" && op0 !== "-c"))
|
|
13923
|
+
return false;
|
|
13924
|
+
}
|
|
13925
|
+
else if (w0Plain === "base64") {
|
|
13926
|
+
if (opCount > 1 || (opCount === 1 && op0 !== "-d" && op0 !== "--decode"))
|
|
13927
|
+
return false;
|
|
13928
|
+
}
|
|
13929
|
+
else if (w0Plain === "tr") {
|
|
13930
|
+
if (plainOps.length !== opCount || this.evalSyncTr("", plainOps) === undefined)
|
|
13931
|
+
return false;
|
|
13932
|
+
}
|
|
13795
13933
|
}
|
|
13796
13934
|
}
|
|
13797
13935
|
if (w0Plain === "printf") {
|
|
@@ -13833,6 +13971,8 @@ export class Runtime {
|
|
|
13833
13971
|
if (p.commands.length >= 2) {
|
|
13834
13972
|
if ((w0Plain !== "printf" && w0Plain !== "echo" && w0Plain !== "seq" && w0Plain !== "cat" && !hasSingleHereStringRedir) || syncPurePipelineSlotInUse || !this.budget.canSyncPurePipe || rawState.errexit || rawState.nounset)
|
|
13835
13973
|
return false;
|
|
13974
|
+
if (w0Plain === "printf" && !this.isSyncPrintfCallOk(cmd, 1, rawState))
|
|
13975
|
+
return false;
|
|
13836
13976
|
for (let sIdx = 1; sIdx < p.commands.length; sIdx++) {
|
|
13837
13977
|
const sCmd = p.commands[sIdx];
|
|
13838
13978
|
if (sCmd.kind !== "simple" || sCmd.redirects.length !== 0 || sCmd.words.length === 0)
|
|
@@ -13899,9 +14039,9 @@ export class Runtime {
|
|
|
13899
14039
|
return false;
|
|
13900
14040
|
}
|
|
13901
14041
|
if (sName === "jq") {
|
|
13902
|
-
|
|
13903
|
-
|
|
13904
|
-
|
|
14042
|
+
// JSON types are runtime inputs: the speculative evaluator may
|
|
14043
|
+
// refuse array indexing and must leave diagnostics to jq.
|
|
14044
|
+
return false;
|
|
13905
14045
|
}
|
|
13906
14046
|
if (sName === "base64") {
|
|
13907
14047
|
if (sPlainArgs.length > 1 || (sPlainArgs.length === 1 && sPlainArgs[0] !== "-d" && sPlainArgs[0] !== "--decode"))
|
|
@@ -13978,6 +14118,53 @@ export class Runtime {
|
|
|
13978
14118
|
}
|
|
13979
14119
|
return undefined;
|
|
13980
14120
|
}
|
|
14121
|
+
execSyncUnsetStep(step, rawState, io, monitor, touched) {
|
|
14122
|
+
const uVars = step.unsetVars;
|
|
14123
|
+
const store = monitor.store;
|
|
14124
|
+
let lastExpanded = "";
|
|
14125
|
+
for (let ui = 0; ui < uVars.length; ui++) {
|
|
14126
|
+
const uvn = uVars[ui];
|
|
14127
|
+
if (uvn.charCodeAt(0) === 64) {
|
|
14128
|
+
const wIdx = Number(uvn.slice(1));
|
|
14129
|
+
const wu = step.cmd.words[wIdx];
|
|
14130
|
+
const tExpanded = this.fastValueWord(wu, rawState, io, false, false, false, false, 0, step.line);
|
|
14131
|
+
lastExpanded = tExpanded;
|
|
14132
|
+
const bracket = tExpanded.indexOf("[");
|
|
14133
|
+
if (bracket > 0 && tExpanded.endsWith("]") && store) {
|
|
14134
|
+
const arrName = tExpanded.slice(0, bracket);
|
|
14135
|
+
const subStr = tExpanded.slice(bracket + 1, -1);
|
|
14136
|
+
const binding = store.get(arrName);
|
|
14137
|
+
if (binding) {
|
|
14138
|
+
if (binding.associative) {
|
|
14139
|
+
const id = fastStringHexIdentity(subStr);
|
|
14140
|
+
const existingKey = binding.keys.get(id);
|
|
14141
|
+
if (existingKey !== undefined) {
|
|
14142
|
+
binding.remove(existingKey.index);
|
|
14143
|
+
store.changed(monitor.chargeInternal(syncRestorationCharge, syncRestorationTickets), arrName);
|
|
14144
|
+
}
|
|
14145
|
+
}
|
|
14146
|
+
else {
|
|
14147
|
+
const idxNum = /^(?:0|[1-9][0-9]{0,8})$/.test(subStr)
|
|
14148
|
+
? Number(subStr)
|
|
14149
|
+
: resolveSimpleArithOperand(subStr, rawState, monitor, store, this._syncArithRawWriteOnly ? this._syncArithTouched : undefined);
|
|
14150
|
+
const resolvedIdx = idxNum !== undefined ? (idxNum >= 0 ? idxNum : binding.maximum + 1 + idxNum) : undefined;
|
|
14151
|
+
if (resolvedIdx !== undefined && resolvedIdx >= 0 && binding.values.has(resolvedIdx)) {
|
|
14152
|
+
binding.remove(resolvedIdx);
|
|
14153
|
+
store.changed(monitor.chargeInternal(syncRestorationCharge, syncRestorationTickets), arrName);
|
|
14154
|
+
}
|
|
14155
|
+
}
|
|
14156
|
+
}
|
|
14157
|
+
}
|
|
14158
|
+
}
|
|
14159
|
+
else {
|
|
14160
|
+
delete rawState.variables[uvn];
|
|
14161
|
+
monitor.proxy.exported.delete(uvn);
|
|
14162
|
+
touched.add(uvn);
|
|
14163
|
+
lastExpanded = uvn;
|
|
14164
|
+
}
|
|
14165
|
+
}
|
|
14166
|
+
return lastExpanded;
|
|
14167
|
+
}
|
|
13981
14168
|
extractSyncUnsetVars(cmd, rawState) {
|
|
13982
14169
|
if (this._syncLoopFnCheckDepth > 0 || cmd.redirects.length !== 0 || cmd.words.length < 2 || cmd.words.length > 16 || cmd.words[0].plain !== "unset")
|
|
13983
14170
|
return undefined;
|
|
@@ -13998,6 +14185,26 @@ export class Runtime {
|
|
|
13998
14185
|
if (vn && startIdx === 1 && hasShellFunction(rawState, vn))
|
|
13999
14186
|
return undefined;
|
|
14000
14187
|
if (!vn || vn.startsWith("-") || !isShellIdentifier(vn) || controlNames.has(vn) || vn === "OPTIND" || rawState.readonlyVariables?.has(vn) || rawState.variableAttributes?.get(vn) || store?.get(vn) || stateMonitor(rawState)?.hasOverlay(vn) || rawState.locals.some(f => f.has(vn))) {
|
|
14188
|
+
const wu = cmd.words[i];
|
|
14189
|
+
const p0 = wu.parts[0];
|
|
14190
|
+
const pLast = wu.parts[wu.parts.length - 1];
|
|
14191
|
+
const m = p0?.kind === "text" ? /^([a-zA-Z_][a-zA-Z0-9_]*)\[/.exec(p0.value) : undefined;
|
|
14192
|
+
const arrName = m?.[1];
|
|
14193
|
+
const b = arrName ? store?.get(arrName) : undefined;
|
|
14194
|
+
if (arrName &&
|
|
14195
|
+
b &&
|
|
14196
|
+
b.references === 1 &&
|
|
14197
|
+
!store.watches.has(arrName) &&
|
|
14198
|
+
!rawState.readonlyVariables?.has(arrName) &&
|
|
14199
|
+
!hasUnpreparedLocal(rawState, arrName) &&
|
|
14200
|
+
!stateMonitor(rawState)?.hasOverlay(arrName) &&
|
|
14201
|
+
pLast?.kind === "text" &&
|
|
14202
|
+
pLast.value.endsWith("]") &&
|
|
14203
|
+
this.isPureSyncValueWord(wu, rawState) &&
|
|
14204
|
+
(p0.quoted || rawState.noglob || (!rawState.nullglob && this._isMemoryBackingFs && tryGetMemoryDirectoryEntryNamesSync(this.backingFs, rawState.cwd)?.size === 0))) {
|
|
14205
|
+
vars.push(`@${i}`);
|
|
14206
|
+
continue;
|
|
14207
|
+
}
|
|
14001
14208
|
return undefined;
|
|
14002
14209
|
}
|
|
14003
14210
|
vars.push(vn);
|
|
@@ -14026,14 +14233,11 @@ export class Runtime {
|
|
|
14026
14233
|
return undefined;
|
|
14027
14234
|
if (w0Plain === "local" && rawState.locals.length === 0)
|
|
14028
14235
|
return undefined;
|
|
14029
|
-
|
|
14030
|
-
let attr;
|
|
14236
|
+
const startIdx = 1;
|
|
14031
14237
|
const w1Plain = cmd.words[1]?.plain;
|
|
14032
14238
|
if (w0Plain !== "export" && (w1Plain === "-u" || w1Plain === "-l" || w1Plain === "-i")) {
|
|
14033
|
-
|
|
14034
|
-
|
|
14035
|
-
attr = w1Plain.slice(1);
|
|
14036
|
-
startIdx = 2;
|
|
14239
|
+
// Attribute changes invalidate the assumptions used to plan later loop steps.
|
|
14240
|
+
return undefined;
|
|
14037
14241
|
}
|
|
14038
14242
|
const store = stateMonitor(rawState)?.store;
|
|
14039
14243
|
const items = [];
|
|
@@ -14069,7 +14273,7 @@ export class Runtime {
|
|
|
14069
14273
|
return undefined;
|
|
14070
14274
|
}
|
|
14071
14275
|
}
|
|
14072
|
-
return { kind: w0Plain === "export" ? "export" : w0Plain === "local" ? "local" : "declare",
|
|
14276
|
+
return { kind: w0Plain === "export" ? "export" : w0Plain === "local" ? "local" : "declare", items };
|
|
14073
14277
|
}
|
|
14074
14278
|
isQuotedAtWord(w) {
|
|
14075
14279
|
const p0 = w.parts.length === 1 ? w.parts[0] : (w.parts.length === 2 && w.parts[0].kind === "text" && w.parts[0].value === "" ? w.parts[1] : undefined);
|
|
@@ -14082,22 +14286,14 @@ export class Runtime {
|
|
|
14082
14286
|
return false;
|
|
14083
14287
|
if (words.length === 1 && this.isQuotedAtWord(words[0]))
|
|
14084
14288
|
return true;
|
|
14085
|
-
|
|
14289
|
+
// Unquoted expansions need splitting and globbing against the state at
|
|
14290
|
+
// execution time. The loop body can change IFS or the expansion value.
|
|
14086
14291
|
if (words.length === 1) {
|
|
14087
14292
|
const w0 = words[0];
|
|
14088
14293
|
if (rawState.braceexpand !== false && tryFastExpandBraceRange(w0, this.budget, undefined) !== undefined)
|
|
14089
14294
|
return true;
|
|
14090
14295
|
if (io !== undefined && this.tryExpandSyncArrayMembersWord(w0, rawState, io, line) !== undefined)
|
|
14091
14296
|
return true;
|
|
14092
|
-
const p0 = w0.parts.length === 1 ? w0.parts[0] : (w0.parts.length === 2 && w0.parts[0].kind === "text" && w0.parts[0].value === "" ? w0.parts[1] : undefined);
|
|
14093
|
-
if (p0 && (rawState.variables.IFS === undefined || rawState.variables.IFS === " \t\n") && !rawState.noglob) {
|
|
14094
|
-
if (p0.kind === "variable" && !p0.quoted && !p0.indirect && !p0.prefixNames && !p0.length && !p0.substring && !p0.transform && p0.operator === undefined && getArraySelector(p0) === undefined && isShellIdentifier(p0.name) && !store?.get(p0.name) && !stateMonitor(rawState)?.hasOverlay(p0.name)) {
|
|
14095
|
-
return true;
|
|
14096
|
-
}
|
|
14097
|
-
if (p0.kind === "substitution" && !p0.quoted && this.isPureSyncValueWord(w0, rawState)) {
|
|
14098
|
-
return true;
|
|
14099
|
-
}
|
|
14100
|
-
}
|
|
14101
14297
|
}
|
|
14102
14298
|
const stdIfs = (rawState.variables.IFS ?? " \t\n") === " \t\n";
|
|
14103
14299
|
for (let i = 0; i < words.length; i++) {
|
|
@@ -14134,9 +14330,10 @@ export class Runtime {
|
|
|
14134
14330
|
return arrMembers;
|
|
14135
14331
|
const p0 = w0.parts.length === 1 ? w0.parts[0] : (w0.parts.length === 2 && w0.parts[0].kind === "text" && w0.parts[0].value === "" ? w0.parts[1] : undefined);
|
|
14136
14332
|
if (p0 && !p0.quoted && (rawState.variables.IFS === undefined || rawState.variables.IFS === " \t\n") && !rawState.noglob) {
|
|
14137
|
-
if (p0.kind === "variable" && !p0.indirect && !p0.prefixNames && !p0.length && !p0.
|
|
14138
|
-
const
|
|
14139
|
-
|
|
14333
|
+
if (p0.kind === "variable" && !p0.indirect && !p0.prefixNames && !p0.length && !p0.transform && getArraySelector(p0) === undefined) {
|
|
14334
|
+
const rawVal = (p0.operator === undefined && !p0.substring)
|
|
14335
|
+
? (rawState.variables[p0.name] === undefined ? "" : (touched.has(p0.name) ? rawState.variables[p0.name] : (monitor.values.get(p0.name, rawState.variables[p0.name]) ?? rawState.variables[p0.name])))
|
|
14336
|
+
: this.fastValueWord(w0, rawState, io, false, false, false, false, 0, line);
|
|
14140
14337
|
if (typeof rawVal === "string") {
|
|
14141
14338
|
const cw = w0;
|
|
14142
14339
|
if (cw._cachedSplitSrc === rawVal && cw._cachedSplitWords !== undefined)
|
|
@@ -14250,6 +14447,8 @@ export class Runtime {
|
|
|
14250
14447
|
let rawMode = false;
|
|
14251
14448
|
let arrayTarget;
|
|
14252
14449
|
let delimChar;
|
|
14450
|
+
let maxChars;
|
|
14451
|
+
let exactChars;
|
|
14253
14452
|
if (isMapfile) {
|
|
14254
14453
|
rawMode = true;
|
|
14255
14454
|
arrayTarget = cmd.words[2]?.plain ?? "MAPFILE";
|
|
@@ -14280,6 +14479,25 @@ export class Runtime {
|
|
|
14280
14479
|
delimChar = dPlain;
|
|
14281
14480
|
argIdx += 2;
|
|
14282
14481
|
}
|
|
14482
|
+
else if (p === "-n" || p === "-rn" || p === "-nr" || p === "-N" || p === "-rN" || p === "-Nr") {
|
|
14483
|
+
if (p.includes("r"))
|
|
14484
|
+
rawMode = true;
|
|
14485
|
+
exactChars = p.includes("N");
|
|
14486
|
+
const nPlain = cmd.words[argIdx + 1]?.plain;
|
|
14487
|
+
if (!nPlain || !/^[1-9][0-9]{0,5}$/.test(nPlain) || byteLocale(rawState.variables))
|
|
14488
|
+
return undefined;
|
|
14489
|
+
maxChars = Number(nPlain);
|
|
14490
|
+
argIdx += 2;
|
|
14491
|
+
}
|
|
14492
|
+
else if ((p.startsWith("-n") || p.startsWith("-rn") || p.startsWith("-N") || p.startsWith("-rN")) && /^[1-9][0-9]{0,5}$/.test(p.slice(p.startsWith("-r") ? 3 : 2))) {
|
|
14493
|
+
if (byteLocale(rawState.variables))
|
|
14494
|
+
return undefined;
|
|
14495
|
+
if (p.startsWith("-r"))
|
|
14496
|
+
rawMode = true;
|
|
14497
|
+
exactChars = p.includes("N");
|
|
14498
|
+
maxChars = Number(p.slice(p.startsWith("-r") ? 3 : 2));
|
|
14499
|
+
argIdx++;
|
|
14500
|
+
}
|
|
14283
14501
|
else if (p === "-ra" || p === "-ar" || p === "-a") {
|
|
14284
14502
|
if (p.includes("r"))
|
|
14285
14503
|
rawMode = true;
|
|
@@ -14297,7 +14515,7 @@ export class Runtime {
|
|
|
14297
14515
|
return undefined;
|
|
14298
14516
|
}
|
|
14299
14517
|
}
|
|
14300
|
-
if (!rawMode || (delimChar !== undefined && arrayTarget !== undefined))
|
|
14518
|
+
if (!rawMode || ((delimChar !== undefined || maxChars !== undefined) && arrayTarget !== undefined))
|
|
14301
14519
|
return undefined;
|
|
14302
14520
|
}
|
|
14303
14521
|
const monitor = stateMonitor(rawState);
|
|
@@ -14317,36 +14535,9 @@ export class Runtime {
|
|
|
14317
14535
|
return undefined;
|
|
14318
14536
|
}
|
|
14319
14537
|
const arrStore = store ?? requireArrays(rawState);
|
|
14320
|
-
|
|
14321
|
-
|
|
14322
|
-
|
|
14323
|
-
if (!existingArr && !arrStore.watches.has(arrayTarget)) {
|
|
14324
|
-
const recTickets = arrStore.owner.charge({ generation: true, version: true, epoch: true, work: 8 });
|
|
14325
|
-
const recBinding = arrStore.takeRecycled(arrayTarget, false, recTickets);
|
|
14326
|
-
if (recBinding) {
|
|
14327
|
-
if (monitor)
|
|
14328
|
-
monitor.epoch = recTickets.epoch;
|
|
14329
|
-
existingArr = recBinding;
|
|
14330
|
-
}
|
|
14331
|
-
else {
|
|
14332
|
-
try {
|
|
14333
|
-
const created = IndexedBinding.create(arrStore.owner, false);
|
|
14334
|
-
const prepared = arrStore.prepareExistingName(arrayTarget, shellValueByteLength(arrayTarget), arrStore.owner, this.signal);
|
|
14335
|
-
if (prepared) {
|
|
14336
|
-
const initTickets = arrStore.owner.charge({ generation: true, version: true, epoch: true, work: 8 });
|
|
14337
|
-
arrStore.publish(arrayTarget, created, initTickets, prepared, false, arrStore.owner);
|
|
14338
|
-
if (monitor)
|
|
14339
|
-
monitor.epoch = initTickets.epoch;
|
|
14340
|
-
existingArr = created;
|
|
14341
|
-
}
|
|
14342
|
-
else {
|
|
14343
|
-
void created.release();
|
|
14344
|
-
}
|
|
14345
|
-
}
|
|
14346
|
-
catch { }
|
|
14347
|
-
}
|
|
14348
|
-
}
|
|
14349
|
-
if (!existingArr)
|
|
14538
|
+
// Planning must not publish bindings: the read may never execute.
|
|
14539
|
+
const existingArr = arrStore.get(arrayTarget);
|
|
14540
|
+
if (!existingArr || existingArr.associative || existingArr.references !== 1 || arrStore.watches.has(arrayTarget))
|
|
14350
14541
|
return undefined;
|
|
14351
14542
|
return { ifsWord, varNames: [], arrayTarget, ...(isMapfile ? { isMapfile: true } : {}), isBareReply: false, inputWord: r0.target };
|
|
14352
14543
|
}
|
|
@@ -14364,7 +14555,67 @@ export class Runtime {
|
|
|
14364
14555
|
return undefined;
|
|
14365
14556
|
varNames.push("REPLY");
|
|
14366
14557
|
}
|
|
14367
|
-
return { ifsWord, varNames, isBareReply, inputWord: r0.target, ...(delimChar !== undefined ? { delimChar } : {}) };
|
|
14558
|
+
return { ifsWord, varNames, isBareReply, inputWord: r0.target, ...(delimChar !== undefined ? { delimChar } : {}), ...(maxChars !== undefined ? { maxChars } : {}), ...(exactChars !== undefined ? { exactChars } : {}) };
|
|
14559
|
+
}
|
|
14560
|
+
isPureSyncSubIfOrCase(cmd, rawState) {
|
|
14561
|
+
if (cmd.redirects.length !== 0)
|
|
14562
|
+
return false;
|
|
14563
|
+
const isSimpleEchoOrPrintf = (s) => {
|
|
14564
|
+
if (s.lists.length !== 1 || s.lists[0].terminator || s.lists[0].pipelines.length !== 1)
|
|
14565
|
+
return false;
|
|
14566
|
+
const pl = s.lists[0].pipelines[0];
|
|
14567
|
+
if (pl.negate || pl.commands.length !== 1)
|
|
14568
|
+
return false;
|
|
14569
|
+
const sc = pl.commands[0];
|
|
14570
|
+
if (sc.kind !== "simple" || sc.redirects.length !== 0 || sc.words.length === 0)
|
|
14571
|
+
return false;
|
|
14572
|
+
const w0 = sc.words[0]?.plain;
|
|
14573
|
+
if (w0 === "echo")
|
|
14574
|
+
return this.isSyncEchoCallOk(sc, rawState);
|
|
14575
|
+
if (w0 === "printf" && sc.words[1]?.plain !== "-v")
|
|
14576
|
+
return this.isSyncPrintfCallOk(sc, 1, rawState);
|
|
14577
|
+
return false;
|
|
14578
|
+
};
|
|
14579
|
+
if (cmd.kind === "if") {
|
|
14580
|
+
for (const br of cmd.branches) {
|
|
14581
|
+
if (br.condition.lists.length !== 1 || br.condition.lists[0].terminator || br.condition.lists[0].pipelines.length !== 1)
|
|
14582
|
+
return false;
|
|
14583
|
+
const bp = br.condition.lists[0].pipelines[0];
|
|
14584
|
+
if (bp.negate || bp.commands.length !== 1)
|
|
14585
|
+
return false;
|
|
14586
|
+
const bc = bp.commands[0];
|
|
14587
|
+
if (bc.kind === "arithmetic") {
|
|
14588
|
+
if (bc.redirects.length !== 0 || bc.expression.error || bc.expression.hasMutation || bc.expression.hasSubscript || !isSafeSmiProgram(bc.expression) || !this.canSyncArithmeticWithoutFault(bc.expression.tree, rawState, bc.line ?? 1))
|
|
14589
|
+
return false;
|
|
14590
|
+
}
|
|
14591
|
+
else if (bc.kind === "conditional") {
|
|
14592
|
+
if (bc.redirects.length !== 0 || rawState.nocasematch || byteLocale(rawState.variables) || !this.canSyncConditional(bc.expression, 0, rawState))
|
|
14593
|
+
return false;
|
|
14594
|
+
if (bc.expression.kind === "binary" && bc.expression.operator === "=~")
|
|
14595
|
+
return false;
|
|
14596
|
+
}
|
|
14597
|
+
else if (!this.extractPosixBracketCondExpr(bc, rawState, true, br.body)) {
|
|
14598
|
+
return false;
|
|
14599
|
+
}
|
|
14600
|
+
if (!isSimpleEchoOrPrintf(br.body))
|
|
14601
|
+
return false;
|
|
14602
|
+
}
|
|
14603
|
+
if (cmd.otherwise && !isSimpleEchoOrPrintf(cmd.otherwise))
|
|
14604
|
+
return false;
|
|
14605
|
+
return true;
|
|
14606
|
+
}
|
|
14607
|
+
if (rawState.nocasematch || rawState.extglob || !this.isPureSyncValueWord(cmd.subject, rawState))
|
|
14608
|
+
return false;
|
|
14609
|
+
const work = { remaining: 4096, signal: this.signal, exhausted: () => this.budget.fail("maxExpansionBytes") };
|
|
14610
|
+
for (const cl of cmd.clauses) {
|
|
14611
|
+
if (cl.terminator !== ";;" && cl.terminator !== "esac")
|
|
14612
|
+
return false;
|
|
14613
|
+
if (!cl.patterns.every(pw => pw.plain !== undefined && tryMatchesPatternSync(pw.plain, "", work, false, false) !== undefined))
|
|
14614
|
+
return false;
|
|
14615
|
+
if (!isSimpleEchoOrPrintf(cl.body))
|
|
14616
|
+
return false;
|
|
14617
|
+
}
|
|
14618
|
+
return true;
|
|
14368
14619
|
}
|
|
14369
14620
|
canSyncLoopBody(script, rawState, io, nested = false, printfInductionName) {
|
|
14370
14621
|
if (script.lists.length === 0)
|
|
@@ -14388,8 +14639,13 @@ export class Runtime {
|
|
|
14388
14639
|
if (e.kind === "unary")
|
|
14389
14640
|
return (e.operator === "-n" || e.operator === "-z" || e.operator === "-v" || (syncConditionalFileUnaryOps.has(e.operator) && this._isMemoryBackingFs && this.canFastMemoryRedirect && this.budget.limits.maxFileSystemOperations >= 1000 && (this._fileWrites === undefined || this._fileWrites.size === 0) && (this._outputFiles === undefined || this._outputFiles.size === 0))) && this.isPureSyncValueWord(e.operand, rawState);
|
|
14390
14641
|
if (e.kind === "binary") {
|
|
14391
|
-
if (e.operator === "=~")
|
|
14642
|
+
if (e.operator === "=~") {
|
|
14643
|
+
const patInfo = this.extractSimpleErePattern(e.right, rawState);
|
|
14644
|
+
// A variable pattern can change through expansions or called functions.
|
|
14645
|
+
if (patInfo?.isVar)
|
|
14646
|
+
return false;
|
|
14392
14647
|
return this.isPureSyncValueWord(e.left, rawState) && this.getFastAnchoredEreRegex(e.right, rawState) !== undefined && !rawState.readonlyVariables?.has("BASH_REMATCH") && !rawState.exported.has("BASH_REMATCH") && !stateMonitor(rawState)?.hasOverlay("BASH_REMATCH") && !(store ?? requireArrays(rawState))?.watches.has("BASH_REMATCH");
|
|
14648
|
+
}
|
|
14393
14649
|
return this.isPureSyncValueWord(e.left, rawState) && (e.operator === "==" || e.operator === "=" || e.operator === "!=" ? this.canSyncPatternWordParts(e.right, rawState) : this.isPureSyncValueWord(e.right, rawState));
|
|
14394
14650
|
}
|
|
14395
14651
|
if (e.kind === "not")
|
|
@@ -14642,7 +14898,8 @@ export class Runtime {
|
|
|
14642
14898
|
}
|
|
14643
14899
|
return false;
|
|
14644
14900
|
}
|
|
14645
|
-
|
|
14901
|
+
const declaration = this.extractSyncLocalDeclStep(cmd, rawState);
|
|
14902
|
+
if (this.extractSyncUnsetVars(cmd, rawState) !== undefined || declaration !== undefined || this.extractSyncShiftCount(cmd, rawState) !== undefined) {
|
|
14646
14903
|
continue;
|
|
14647
14904
|
}
|
|
14648
14905
|
if (cmd.redirects.length === 0 && cmd.words.length >= 1 && cmd.words.length <= 16 && this.extractSyncLoopFnSpec(cmd, rawState, io) !== undefined) {
|
|
@@ -14668,56 +14925,39 @@ export class Runtime {
|
|
|
14668
14925
|
return false;
|
|
14669
14926
|
if (hasUnpreparedLocals(rawState))
|
|
14670
14927
|
return false;
|
|
14671
|
-
|
|
14672
|
-
|
|
14673
|
-
|
|
14674
|
-
|
|
14675
|
-
|
|
14676
|
-
isShellIdentifier(arrAssign.name) &&
|
|
14677
|
-
rawState.variables[arrAssign.name] === undefined &&
|
|
14678
|
-
!rawState.readonlyVariables?.has(arrAssign.name) &&
|
|
14679
|
-
!rawState.exported.has(arrAssign.name) &&
|
|
14680
|
-
!rawState.variableAttributes?.get(arrAssign.name) &&
|
|
14681
|
-
!controlNames.has(arrAssign.name) &&
|
|
14682
|
-
!stateMonitor(rawState)?.hasOverlay(arrAssign.name)) {
|
|
14683
|
-
const monitor = stateMonitor(rawState);
|
|
14684
|
-
const arrStore = monitor?.store ?? (monitor ? requireArrays(rawState) : undefined);
|
|
14685
|
-
if (arrStore && !arrStore.watches.has(arrAssign.name)) {
|
|
14686
|
-
const recTickets = arrStore.owner.charge({ generation: true, version: true, epoch: true, work: 8 });
|
|
14687
|
-
const recBinding = arrStore.takeRecycled(arrAssign.name, false, recTickets);
|
|
14688
|
-
if (recBinding) {
|
|
14689
|
-
if (monitor)
|
|
14690
|
-
monitor.epoch = recTickets.epoch;
|
|
14691
|
-
curArr = recBinding;
|
|
14692
|
-
}
|
|
14693
|
-
else {
|
|
14694
|
-
try {
|
|
14695
|
-
const created = IndexedBinding.create(arrStore.owner, false);
|
|
14696
|
-
const prepared = arrStore.prepareExistingName(arrAssign.name, shellValueByteLength(arrAssign.name), arrStore.owner, this.signal);
|
|
14697
|
-
if (prepared) {
|
|
14698
|
-
const initTickets = arrStore.owner.charge({ generation: true, version: true, epoch: true, work: 8 });
|
|
14699
|
-
arrStore.publish(arrAssign.name, created, initTickets, prepared, false, arrStore.owner);
|
|
14700
|
-
if (monitor)
|
|
14701
|
-
monitor.epoch = initTickets.epoch;
|
|
14702
|
-
curArr = created;
|
|
14703
|
-
}
|
|
14704
|
-
else {
|
|
14705
|
-
void created.release();
|
|
14706
|
-
}
|
|
14707
|
-
}
|
|
14708
|
-
catch { }
|
|
14709
|
-
}
|
|
14710
|
-
}
|
|
14711
|
-
}
|
|
14928
|
+
// Eligibility checks must not create bindings: the loop may never run.
|
|
14929
|
+
// Element subscripts need the normal arithmetic and relative-index evaluator.
|
|
14930
|
+
if (arrAssign.kind === "element")
|
|
14931
|
+
return false;
|
|
14932
|
+
const curArr = store?.get(arrAssign.name);
|
|
14712
14933
|
const activeArrStore = store ?? stateMonitor(rawState)?.store;
|
|
14713
14934
|
if (!curArr || curArr.references !== 1 || activeArrStore?.watches.has(arrAssign.name) || rawState.readonlyVariables?.has(arrAssign.name) || rawState.exported.has(arrAssign.name) || controlNames.has(arrAssign.name)) {
|
|
14714
14935
|
return false;
|
|
14715
14936
|
}
|
|
14716
|
-
if (arrAssign.kind === "compound" &&
|
|
14937
|
+
if (arrAssign.kind === "compound" && arrAssign.entries.length <= 16 && arrAssign.entries.every(e => !e.append)) {
|
|
14717
14938
|
let allEntriesOk = true;
|
|
14718
14939
|
for (let ei = 0; ei < arrAssign.entries.length; ei++) {
|
|
14719
|
-
const
|
|
14720
|
-
|
|
14940
|
+
const entry = arrAssign.entries[ei];
|
|
14941
|
+
const ev = entry.value;
|
|
14942
|
+
if (curArr.associative) {
|
|
14943
|
+
const kSrc = entry.index ? (entry.index.source ?? entry.index.decimal) : "";
|
|
14944
|
+
if (kSrc.length === 0 || kSrc.length > 4096 || kSrc.startsWith("~") || /[$\x60\\"']/.test(kSrc) || !this.isPureSyncValueWord(ev, rawState)) {
|
|
14945
|
+
allEntriesOk = false;
|
|
14946
|
+
break;
|
|
14947
|
+
}
|
|
14948
|
+
continue;
|
|
14949
|
+
}
|
|
14950
|
+
if (entry.index !== undefined) {
|
|
14951
|
+
const kSrc = (entry.index.source ?? entry.index.decimal).trim();
|
|
14952
|
+
const original = compoundEntryWords.get(entry);
|
|
14953
|
+
const hasBraceInOriginal = rawState.braceexpand !== false && Boolean(original?.parts.some(p => p.kind === "text" && !p.quoted && p.value.includes("{")));
|
|
14954
|
+
if (!/^(?:0|[1-9][0-9]{0,8})$/.test(kSrc) || hasBraceInOriginal || (rawState.braceexpand !== false && ev.parts.some(p => !p.quoted && p.kind === "text" && p.value.includes("{"))) || !this.isPureSyncValueWord(ev, rawState)) {
|
|
14955
|
+
allEntriesOk = false;
|
|
14956
|
+
break;
|
|
14957
|
+
}
|
|
14958
|
+
continue;
|
|
14959
|
+
}
|
|
14960
|
+
if (!this.isPureSyncValueWord(ev, rawState) || (!ev.parts.every(p => p.quoted || (p.kind === "text" && p.value.length > 0 && !p.value.includes(" ") && !p.value.includes("\t") && !p.value.includes("\n") && !p.value.includes("{") && !hasGlobOrEscape(p.value, true))))) {
|
|
14721
14961
|
allEntriesOk = false;
|
|
14722
14962
|
break;
|
|
14723
14963
|
}
|
|
@@ -14726,19 +14966,6 @@ export class Runtime {
|
|
|
14726
14966
|
continue;
|
|
14727
14967
|
return false;
|
|
14728
14968
|
}
|
|
14729
|
-
if (arrAssign.kind === "element" && (!arrAssign.append || this.budget.limits.maxExpansionBytes === Infinity) && curArr.associative) {
|
|
14730
|
-
const kSrc = arrAssign.index.source ?? arrAssign.index.decimal;
|
|
14731
|
-
if (kSrc.trim().length > 0 && !kSrc.includes("`") && !kSrc.includes("$(") && this.isPureSyncValueWord(arrAssign.value, rawState))
|
|
14732
|
-
continue;
|
|
14733
|
-
return false;
|
|
14734
|
-
}
|
|
14735
|
-
if (arrAssign.kind === "element" && !curArr.associative) {
|
|
14736
|
-
const subSrc = (arrAssign.index.source ?? arrAssign.index.decimal).trim();
|
|
14737
|
-
if (subSrc.length > 0 && subSrc.length <= 64 && /^[$a-zA-Z0-9_ +*-]+$/.test(subSrc) && !subSrc.includes("/") && !subSrc.includes("%") && !subSrc.includes("=") && !subSrc.includes("++") && !subSrc.includes("--") && this.isPureSyncValueWord(arrAssign.value, rawState)) {
|
|
14738
|
-
continue;
|
|
14739
|
-
}
|
|
14740
|
-
return false;
|
|
14741
|
-
}
|
|
14742
14969
|
return false;
|
|
14743
14970
|
}
|
|
14744
14971
|
const assignment = this.assignment(w0);
|
|
@@ -15194,6 +15421,8 @@ export class Runtime {
|
|
|
15194
15421
|
return 0;
|
|
15195
15422
|
}
|
|
15196
15423
|
trySyncLoop(command, pipeline, rawState, monitor, store, existing, elem0, canMutatePipeStatus, io, diagnosticLine, syncReadInputText) {
|
|
15424
|
+
if (!syncSinks.get(io.stderr))
|
|
15425
|
+
return undefined;
|
|
15197
15426
|
// Substitution callers also need to refuse before effects when status
|
|
15198
15427
|
// publication requires array admission. Cleanup cannot start async fallback.
|
|
15199
15428
|
if (store && !existing) {
|
|
@@ -15225,13 +15454,17 @@ export class Runtime {
|
|
|
15225
15454
|
const initializer = command.kind === "arithmetic-for" ? command.expressions[0]?.tree : undefined;
|
|
15226
15455
|
const condition = command.kind === "arithmetic-for" ? command.expressions[1]?.tree : undefined;
|
|
15227
15456
|
const increment = command.kind === "arithmetic-for" ? command.expressions[2]?.tree : undefined;
|
|
15457
|
+
const whileCondCmd = command.kind === "while" && command.condition.lists.length === 1 && command.condition.lists[0].pipelines.length === 1 ? command.condition.lists[0].pipelines[0].commands[0] : undefined;
|
|
15458
|
+
const whilePrintfInd = whileCondCmd?.kind === "arithmetic" && !whileCondCmd.expression.error && whileCondCmd.expression.tree?.kind === "binary" && (whileCondCmd.expression.tree.left.kind === "name" ? whileCondCmd.expression.tree.left.name : (whileCondCmd.expression.tree.left.kind === "unary" && whileCondCmd.expression.tree.left.operand.kind === "name" ? whileCondCmd.expression.tree.left.operand.name : undefined));
|
|
15228
15459
|
const printfInductionName = initializer?.kind === "binary" && initializer.operator === "=" && initializer.left.kind === "name" &&
|
|
15229
15460
|
initializer.right.kind === "literal" && initializer.right.value >= 0n && initializer.right.value <= 2000n &&
|
|
15230
15461
|
condition?.kind === "binary" && (condition.operator === "<" || condition.operator === "<=") &&
|
|
15231
15462
|
condition.left.kind === "name" && condition.left.name === initializer.left.name &&
|
|
15232
15463
|
condition.right.kind === "literal" && condition.right.value >= 0n && condition.right.value <= 2000n &&
|
|
15233
15464
|
increment?.kind === "unary" && increment.operator === "++" && increment.operand.kind === "name" && increment.operand.name === initializer.left.name &&
|
|
15234
|
-
this.canSyncPrintfInductionBody(command.body, rawState)
|
|
15465
|
+
this.canSyncPrintfInductionBody(command.body, rawState)
|
|
15466
|
+
? initializer.left.name
|
|
15467
|
+
: (whilePrintfInd && this.canSyncPrintfInductionBody(command.body, rawState) ? whilePrintfInd : undefined);
|
|
15235
15468
|
if ((guestArrays(rawState) && (guestArrays(rawState).watches.size > 0 || this.budget.limits.maxExpansionBytes < 65536)) || !this.canSyncLoopBody(command.body, rawState, io, false, printfInductionName)) {
|
|
15236
15469
|
command._skipTrySyncLoop = true;
|
|
15237
15470
|
return undefined;
|
|
@@ -15246,7 +15479,7 @@ export class Runtime {
|
|
|
15246
15479
|
if (!existing || !elem0)
|
|
15247
15480
|
return undefined;
|
|
15248
15481
|
}
|
|
15249
|
-
for (const v of Object.values(rawState.variables)) {
|
|
15482
|
+
for (const v of [...Object.values(rawState.variables), ...rawState.positional]) {
|
|
15250
15483
|
if (typeof v === "string") {
|
|
15251
15484
|
for (let k = 0; k < v.length; k++) {
|
|
15252
15485
|
if (v.charCodeAt(k) >= 128)
|
|
@@ -15254,10 +15487,22 @@ export class Runtime {
|
|
|
15254
15487
|
}
|
|
15255
15488
|
}
|
|
15256
15489
|
}
|
|
15490
|
+
// The loop evaluator assumes ASCII, including values reached through array elements.
|
|
15491
|
+
if (store) {
|
|
15492
|
+
for (const { binding } of store.bindings.values()) {
|
|
15493
|
+
for (const slot of binding.values.values()) {
|
|
15494
|
+
const value = slot.text.value;
|
|
15495
|
+
for (let k = 0; k < value.length; k++) {
|
|
15496
|
+
if (value.charCodeAt(k) >= 128)
|
|
15497
|
+
return undefined;
|
|
15498
|
+
}
|
|
15499
|
+
}
|
|
15500
|
+
}
|
|
15501
|
+
}
|
|
15257
15502
|
const { steps: bodyAssignments, redirectCount } = this.buildSyncLoopBody(command, rawState, io);
|
|
15258
15503
|
if (bodyAssignments.length > 30)
|
|
15259
15504
|
return undefined;
|
|
15260
|
-
const touched = sharedSyncLoopTouched;
|
|
15505
|
+
const touched = this._syncArithRawWriteOnly ? new Set() : sharedSyncLoopTouched;
|
|
15261
15506
|
touched.clear();
|
|
15262
15507
|
let lastCmd;
|
|
15263
15508
|
let lastArg = "";
|
|
@@ -15350,7 +15595,7 @@ export class Runtime {
|
|
|
15350
15595
|
const stepMutatesInduction = (st) => {
|
|
15351
15596
|
// Integer declarations evaluate arithmetic strings, which can mutate
|
|
15352
15597
|
// any variable. Array reads can also replace the scalar counter.
|
|
15353
|
-
if (st.name === inductionName || st.readHereString?.varNames.includes(inductionName) || st.readHereString?.arrayTarget === inductionName || st.unsetVars?.includes(inductionName) || st.localDecl?.
|
|
15598
|
+
if (st.name === inductionName || st.readHereString?.varNames.includes(inductionName) || st.readHereString?.arrayTarget === inductionName || st.unsetVars?.includes(inductionName) || st.localDecl?.items.some(it => it.name === inductionName))
|
|
15354
15599
|
return true;
|
|
15355
15600
|
if (st.arithStmt?.hasMutation && arithTreeMutatesVar(st.arithStmt.tree, inductionName))
|
|
15356
15601
|
return true;
|
|
@@ -15401,9 +15646,13 @@ export class Runtime {
|
|
|
15401
15646
|
intSteps[b] = intStep;
|
|
15402
15647
|
continue;
|
|
15403
15648
|
}
|
|
15404
|
-
|
|
15405
|
-
|
|
15406
|
-
|
|
15649
|
+
const wordsToScan = step.arrayAssign?.kind === "compound"
|
|
15650
|
+
? step.arrayAssign.entries.map(e => e.value)
|
|
15651
|
+
: step.value ? [step.value] : [];
|
|
15652
|
+
for (let wIdx = 0; wIdx < wordsToScan.length; wIdx++) {
|
|
15653
|
+
const wVal = wordsToScan[wIdx];
|
|
15654
|
+
for (let i = 0; i < wVal.parts.length; i++) {
|
|
15655
|
+
const part = wVal.parts[i];
|
|
15407
15656
|
if (part.kind === "text" || part.kind === "variable")
|
|
15408
15657
|
continue;
|
|
15409
15658
|
if (part.kind === "arithmetic") {
|
|
@@ -15525,7 +15774,7 @@ export class Runtime {
|
|
|
15525
15774
|
let lastInductionVal;
|
|
15526
15775
|
const intBudgetSnapshot = this.budget.parsing.snapshot();
|
|
15527
15776
|
// Empty loops must evaluate the header without publishing unexecuted body registers or command state.
|
|
15528
|
-
let canUseIntRegisters = iterations > 0 && allIntStepsReady && (!hasSubIntStep || (this.middleware.length === 0 && rawState.depth < this.budget.maxSubstitutionDepthSmi)) && !this.budget.hasCpuLimit && this.budget.maxExpansionFieldsSmi >= 1 && this.budget.maxExpansionBytesSmi >= 32 && !store?.get(inductionName) && inductionName !== "LINENO" && inductionName !== "_" && inductionName !== "FUNCNAME";
|
|
15777
|
+
let canUseIntRegisters = !prevRawWrite && iterations > 0 && allIntStepsReady && (!hasSubIntStep || (this.middleware.length === 0 && rawState.depth < this.budget.maxSubstitutionDepthSmi)) && !this.budget.hasCpuLimit && this.budget.maxExpansionFieldsSmi >= 1 && this.budget.maxExpansionBytesSmi >= 32 && !store?.get(inductionName) && inductionName !== "LINENO" && inductionName !== "_" && inductionName !== "FUNCNAME";
|
|
15529
15778
|
if (canUseIntRegisters && arithNamesList.length > 0) {
|
|
15530
15779
|
for (let a = 0; a < arithNamesList.length; a++) {
|
|
15531
15780
|
const refName = arithNamesList[a];
|
|
@@ -15807,6 +16056,10 @@ export class Runtime {
|
|
|
15807
16056
|
return (e.operator === "-n" || e.operator === "-z" || e.operator === "-v") && this.isPureSyncValueWord(e.operand, rawState);
|
|
15808
16057
|
if (e.kind === "binary") {
|
|
15809
16058
|
if (e.operator === "=~") {
|
|
16059
|
+
const patInfo = this.extractSimpleErePattern(e.right, rawState);
|
|
16060
|
+
// Nested branches cannot prove a variable pattern is invariant.
|
|
16061
|
+
if (patInfo?.isVar)
|
|
16062
|
+
return false;
|
|
15810
16063
|
return (depth === 0 &&
|
|
15811
16064
|
this.isPureSyncValueWord(e.left, rawState) &&
|
|
15812
16065
|
this.getFastAnchoredEreRegex(e.right, rawState) !== undefined &&
|
|
@@ -16257,9 +16510,11 @@ export class Runtime {
|
|
|
16257
16510
|
if (asciiOk)
|
|
16258
16511
|
fastLoopWords = arrMembers;
|
|
16259
16512
|
}
|
|
16260
|
-
else if (p0.kind === "variable" && !p0.quoted && !p0.indirect && !p0.prefixNames && !p0.length && !p0.
|
|
16261
|
-
const rawVal =
|
|
16262
|
-
|
|
16513
|
+
else if (p0.kind === "variable" && !p0.quoted && !p0.indirect && !p0.prefixNames && !p0.length && !p0.transform && getArraySelector(p0) === undefined && (rawState.variables.IFS === undefined || rawState.variables.IFS === " \t\n") && !rawState.noglob && !store?.get(p0.name) && !monitor.hasOverlay(p0.name) && ((p0.operator === undefined && !p0.substring) || this.isPureSyncValueWord(command.words[0], rawState))) {
|
|
16514
|
+
const rawVal = (p0.operator === undefined && !p0.substring)
|
|
16515
|
+
? (rawState.variables[p0.name] ?? "")
|
|
16516
|
+
: this.fastValueWord(command.words[0], rawState, io, false, false, false, false, 0, diagnosticLine);
|
|
16517
|
+
if (typeof rawVal === "string" && rawVal.length <= 32768 && !/[*?[\]\\]/.test(rawVal)) {
|
|
16263
16518
|
let asciiOk = true;
|
|
16264
16519
|
for (let j = 0; j < rawVal.length; j++) {
|
|
16265
16520
|
if (rawVal.charCodeAt(j) >= 128) {
|
|
@@ -16648,6 +16903,11 @@ export class Runtime {
|
|
|
16648
16903
|
for (const list of script.lists)
|
|
16649
16904
|
for (const pipeline of list.pipelines)
|
|
16650
16905
|
for (const command of pipeline.commands) {
|
|
16906
|
+
if (command.kind === "arithmetic") {
|
|
16907
|
+
if (command.redirects.length === 0 && !command.expression.error && !command.expression.hasSubscript && isSafeSmiProgram(command.expression) && command.expression.tree?.kind === "unary" && (command.expression.tree.operator === "++" || command.expression.tree.operator === "--") && command.expression.tree.operand.kind === "name")
|
|
16908
|
+
continue;
|
|
16909
|
+
return false;
|
|
16910
|
+
}
|
|
16651
16911
|
if (command.kind !== "simple" || hasShellFunction(rawState, command.words[0]?.plain ?? "") || command.words.some(word => getArrayAssignment(word) !== undefined))
|
|
16652
16912
|
return false;
|
|
16653
16913
|
for (const word of [...command.words, ...command.redirects.map(redirect => redirect.target)])
|
|
@@ -16656,6 +16916,8 @@ export class Runtime {
|
|
|
16656
16916
|
continue;
|
|
16657
16917
|
if (part.kind === "variable" && !part.indirect && !part.length && !part.substring && !part.transform && !part.prefixNames && part.operator === undefined && getArraySelector(part) === undefined)
|
|
16658
16918
|
continue;
|
|
16919
|
+
if (part.kind === "arithmetic" && !part.expression.error && !part.expression.hasMutation && !part.expression.hasSubscript && isSafeSmiProgram(part.expression) && /^[a-zA-Z0-9_ +*-]+$/.test(part.expression.source))
|
|
16920
|
+
continue;
|
|
16659
16921
|
if (part.kind === "substitution" && this.canSyncPrintfInductionBody(part.script, rawState))
|
|
16660
16922
|
continue;
|
|
16661
16923
|
return false;
|
|
@@ -16683,6 +16945,20 @@ export class Runtime {
|
|
|
16683
16945
|
args.push("0");
|
|
16684
16946
|
continue;
|
|
16685
16947
|
}
|
|
16948
|
+
if (i > fmtWordIdx &&
|
|
16949
|
+
inductionName !== undefined &&
|
|
16950
|
+
valueParts.length === 1 &&
|
|
16951
|
+
part?.kind === "arithmetic" &&
|
|
16952
|
+
part.quoted &&
|
|
16953
|
+
!part.expression.error &&
|
|
16954
|
+
!part.expression.hasMutation &&
|
|
16955
|
+
!part.expression.hasSubscript &&
|
|
16956
|
+
isSafeSmiProgram(part.expression) &&
|
|
16957
|
+
/^[a-zA-Z0-9_ +*-]+$/.test(part.expression.source) &&
|
|
16958
|
+
this.canSyncArithmeticWithoutFault(part.expression.tree, rawState, cmd.line ?? 1)) {
|
|
16959
|
+
args.push("0");
|
|
16960
|
+
continue;
|
|
16961
|
+
}
|
|
16686
16962
|
let arg = "";
|
|
16687
16963
|
for (const part of w.parts) {
|
|
16688
16964
|
if (part.kind !== "text" || (!part.quoted && (part.value.length === 0 || part.value.includes(" ") || part.value.includes("\t") || part.value.includes("\n") || part.value.includes("{") || hasGlobOrEscape(part.value, true))))
|
|
@@ -16699,6 +16975,39 @@ export class Runtime {
|
|
|
16699
16975
|
return false;
|
|
16700
16976
|
return w.parts.every(p => p.kind === "text" || (p.kind === "variable" && !p.indirect && !p.prefixNames && !p.length && !p.substring && p.operator === undefined && getArraySelector(p) === undefined));
|
|
16701
16977
|
}
|
|
16978
|
+
execSyncReadHereStringStep(rs, step, rawState, io, monitor, touched) {
|
|
16979
|
+
const rawInput = this.fastValueWord(rs.inputWord, rawState, io, false, false, false, false, 0, step.line);
|
|
16980
|
+
const delim = rs.delimChar ?? "\n";
|
|
16981
|
+
let lineStr;
|
|
16982
|
+
let status = 0;
|
|
16983
|
+
if (rs.maxChars !== undefined) {
|
|
16984
|
+
const fullInput = rawInput + "\n";
|
|
16985
|
+
if (rs.exactChars) {
|
|
16986
|
+
lineStr = fullInput.length > rs.maxChars ? fullInput.slice(0, rs.maxChars) : fullInput;
|
|
16987
|
+
status = fullInput.length >= rs.maxChars ? 0 : 1;
|
|
16988
|
+
}
|
|
16989
|
+
else {
|
|
16990
|
+
const nlIdx = fullInput.indexOf(delim);
|
|
16991
|
+
const untilDelim = nlIdx === -1 ? fullInput : fullInput.slice(0, nlIdx);
|
|
16992
|
+
lineStr = untilDelim.length > rs.maxChars ? untilDelim.slice(0, rs.maxChars) : untilDelim;
|
|
16993
|
+
status = (nlIdx !== -1 || fullInput.length >= rs.maxChars) ? 0 : 1;
|
|
16994
|
+
}
|
|
16995
|
+
}
|
|
16996
|
+
else {
|
|
16997
|
+
const fullInput = delim === "\n" ? rawInput : rawInput + "\n";
|
|
16998
|
+
const nlIdx = rs.isMapfile ? -1 : fullInput.indexOf(delim);
|
|
16999
|
+
lineStr = nlIdx === -1 ? fullInput : fullInput.slice(0, nlIdx);
|
|
17000
|
+
status = (!rs.isMapfile && delim !== "\n" && nlIdx === -1) ? 1 : 0;
|
|
17001
|
+
}
|
|
17002
|
+
const ifsStr = rs.exactChars
|
|
17003
|
+
? ""
|
|
17004
|
+
: rs.ifsWord !== undefined
|
|
17005
|
+
? this.fastValueWord(rs.ifsWord, rawState, io, false, false, false, false, 0, step.line)
|
|
17006
|
+
: (rawState.variables.IFS ?? " \t\n");
|
|
17007
|
+
this.splitSyncReadLine(lineStr, ifsStr, rs.varNames, rs.isBareReply, rawState, touched, rs.arrayTarget, monitor, rs.isMapfile);
|
|
17008
|
+
rawState.status = status;
|
|
17009
|
+
return step.cmd.words[step.cmd.words.length - 1].plain;
|
|
17010
|
+
}
|
|
16702
17011
|
splitSyncReadLine(lineStr, ifsStr, varNames, isBareReply, rawState, touched, arrayTarget, monitor, isMapfile = false) {
|
|
16703
17012
|
if (arrayTarget !== undefined && monitor !== undefined) {
|
|
16704
17013
|
const arrStore = monitor.store ?? requireArrays(rawState);
|
|
@@ -16833,17 +17142,8 @@ export class Runtime {
|
|
|
16833
17142
|
touched.add(item.name);
|
|
16834
17143
|
}
|
|
16835
17144
|
if (item.value !== undefined) {
|
|
16836
|
-
|
|
16837
|
-
if (
|
|
16838
|
-
val = val.toUpperCase();
|
|
16839
|
-
else if (decl.attr === "l")
|
|
16840
|
-
val = val.toLowerCase();
|
|
16841
|
-
else if (decl.attr === "i") {
|
|
16842
|
-
const curRaw = item.append ? rawState.variables[item.name] : undefined;
|
|
16843
|
-
const curStr = curRaw === undefined ? "" : (touched.has(item.name) ? curRaw : (monitor.values.get(item.name, curRaw) ?? curRaw));
|
|
16844
|
-
val = applySyncScalarAttributes("i", val, typeof curStr === "string" ? curStr : "", item.append, rawState, monitor, arrayStore(rawState), touched) ?? "0";
|
|
16845
|
-
}
|
|
16846
|
-
if (item.append && decl.attr !== "i") {
|
|
17145
|
+
const val = this.fastValueWord(item.value, rawState, io, false, false, false, rawState.braceexpand !== false, 0, line);
|
|
17146
|
+
if (item.append) {
|
|
16847
17147
|
const curRaw = rawState.variables[item.name];
|
|
16848
17148
|
const curStr = curRaw === undefined ? "" : (touched.has(item.name) ? curRaw : (monitor.values.get(item.name, curRaw) ?? curRaw));
|
|
16849
17149
|
rawState.variables[item.name] = (typeof curStr === "string" ? curStr : "") + val;
|
|
@@ -16857,9 +17157,6 @@ export class Runtime {
|
|
|
16857
17157
|
else {
|
|
16858
17158
|
lastArg = item.name;
|
|
16859
17159
|
}
|
|
16860
|
-
if (decl.attr !== undefined) {
|
|
16861
|
-
(this._syncPendingVarAttrs ??= new Map()).set(item.name, decl.attr);
|
|
16862
|
-
}
|
|
16863
17160
|
if (decl.kind === "export") {
|
|
16864
17161
|
rawState.exported.add(item.name);
|
|
16865
17162
|
}
|
|
@@ -16867,20 +17164,12 @@ export class Runtime {
|
|
|
16867
17164
|
return lastArg;
|
|
16868
17165
|
}
|
|
16869
17166
|
_syncTouchedPositionals = false;
|
|
16870
|
-
_syncPendingVarAttrs = undefined;
|
|
16871
17167
|
flushSyncPositionals(rawState) {
|
|
16872
17168
|
if (this._syncTouchedPositionals) {
|
|
16873
17169
|
this._syncTouchedPositionals = false;
|
|
16874
17170
|
this._fastSubPositional = undefined;
|
|
16875
17171
|
this.replacePositionals(rawState, rawState.positional);
|
|
16876
17172
|
}
|
|
16877
|
-
if (this._syncPendingVarAttrs && this._syncPendingVarAttrs.size > 0) {
|
|
16878
|
-
rawState.variableAttributes ??= new Map();
|
|
16879
|
-
for (const [k, v] of this._syncPendingVarAttrs) {
|
|
16880
|
-
rawState.variableAttributes.set(k, v);
|
|
16881
|
-
}
|
|
16882
|
-
this._syncPendingVarAttrs.clear();
|
|
16883
|
-
}
|
|
16884
17173
|
}
|
|
16885
17174
|
execSyncShiftStep(shiftCount, cmd, rawState) {
|
|
16886
17175
|
const activePos = this._fastSubPositional ?? rawState.positional;
|
|
@@ -17006,13 +17295,7 @@ export class Runtime {
|
|
|
17006
17295
|
break;
|
|
17007
17296
|
}
|
|
17008
17297
|
if (step.unsetVars !== undefined) {
|
|
17009
|
-
|
|
17010
|
-
const uvn = step.unsetVars[ui];
|
|
17011
|
-
delete rawState.variables[uvn];
|
|
17012
|
-
monitor.proxy.exported.delete(uvn);
|
|
17013
|
-
touched.add(uvn);
|
|
17014
|
-
}
|
|
17015
|
-
lastArg = step.cmd.words[step.cmd.words.length - 1].plain;
|
|
17298
|
+
lastArg = this.execSyncUnsetStep(step, rawState, io, monitor, touched);
|
|
17016
17299
|
rawState.status = 0;
|
|
17017
17300
|
continue;
|
|
17018
17301
|
}
|
|
@@ -17028,16 +17311,7 @@ export class Runtime {
|
|
|
17028
17311
|
continue;
|
|
17029
17312
|
}
|
|
17030
17313
|
if (step.readHereString !== undefined) {
|
|
17031
|
-
|
|
17032
|
-
const rawInput = this.fastValueWord(rs.inputWord, rawState, io, false, false, false, false, 0, step.line);
|
|
17033
|
-
const delim = rs.delimChar ?? "\n";
|
|
17034
|
-
const fullInput = delim === "\n" ? rawInput : rawInput + "\n";
|
|
17035
|
-
const nlIdx = rs.isMapfile ? -1 : fullInput.indexOf(delim);
|
|
17036
|
-
const lineStr = nlIdx === -1 ? fullInput : fullInput.slice(0, nlIdx);
|
|
17037
|
-
const ifsStr = rs.ifsWord !== undefined ? this.fastValueWord(rs.ifsWord, rawState, io, false, false, false, false, 0, step.line) : (rawState.variables.IFS ?? " \t\n");
|
|
17038
|
-
this.splitSyncReadLine(lineStr, ifsStr, rs.varNames, rs.isBareReply, rawState, touched, rs.arrayTarget, monitor, rs.isMapfile);
|
|
17039
|
-
lastArg = step.cmd.words[step.cmd.words.length - 1].plain;
|
|
17040
|
-
rawState.status = (!rs.isMapfile && delim !== "\n" && nlIdx === -1) ? 1 : 0;
|
|
17314
|
+
lastArg = this.execSyncReadHereStringStep(step.readHereString, step, rawState, io, monitor, touched);
|
|
17041
17315
|
continue;
|
|
17042
17316
|
}
|
|
17043
17317
|
if (deferredMask & (1 << b)) {
|
|
@@ -17092,7 +17366,9 @@ export class Runtime {
|
|
|
17092
17366
|
lastArg = pLastArg;
|
|
17093
17367
|
}
|
|
17094
17368
|
else if (step.arrayAssign !== undefined) {
|
|
17095
|
-
this.tryFastArrayAssignmentSync(step.arrayAssign, rawState, io, step.line, undefined, undefined, true)
|
|
17369
|
+
if (!this.tryFastArrayAssignmentSync(step.arrayAssign, rawState, io, step.line, undefined, undefined, true)) {
|
|
17370
|
+
throw new Error("Synchronous loop array assignment was not executable");
|
|
17371
|
+
}
|
|
17096
17372
|
lastArg = "";
|
|
17097
17373
|
}
|
|
17098
17374
|
else if (step.caseClauses !== undefined) {
|
|
@@ -17270,44 +17546,56 @@ export class Runtime {
|
|
|
17270
17546
|
}
|
|
17271
17547
|
}
|
|
17272
17548
|
evalSyncLoopArithStmt(expr, rawState, io, touched, line) {
|
|
17273
|
-
|
|
17274
|
-
|
|
17275
|
-
|
|
17276
|
-
|
|
17277
|
-
|
|
17278
|
-
|
|
17279
|
-
|
|
17280
|
-
|
|
17281
|
-
|
|
17282
|
-
|
|
17283
|
-
|
|
17284
|
-
|
|
17285
|
-
|
|
17286
|
-
|
|
17287
|
-
|
|
17288
|
-
|
|
17289
|
-
|
|
17290
|
-
|
|
17291
|
-
|
|
17549
|
+
try {
|
|
17550
|
+
if (!expr.error)
|
|
17551
|
+
return this.syncShellArithmeticNonZero(expr, rawState, line);
|
|
17552
|
+
const cachedExpr = expr;
|
|
17553
|
+
const expWord = cachedExpr._cachedArithWord ?? parseArithmeticExpansion(expr.source, this.budget.parsing, false, 0, undefined, rawState.extensions?.syntax);
|
|
17554
|
+
cachedExpr._cachedArithWord = expWord;
|
|
17555
|
+
const fastSrc = this.fastValueWord(expWord, rawState, io, false, false, true, false, 0, line);
|
|
17556
|
+
const scalarMutMatch = fastSrc.length <= 64 ? SIMPLE_SCALAR_MUT_RE.exec(fastSrc) : null;
|
|
17557
|
+
if (scalarMutMatch) {
|
|
17558
|
+
const varName = resolveSyncNameref(rawState, scalarMutMatch[1]);
|
|
17559
|
+
const binOp = scalarMutMatch[2];
|
|
17560
|
+
const rhs1 = Number(scalarMutMatch[3]);
|
|
17561
|
+
const rhsOp = scalarMutMatch[4];
|
|
17562
|
+
const rhs2 = scalarMutMatch[5] !== undefined ? Number(scalarMutMatch[5]) : 0;
|
|
17563
|
+
const rhsNum = rhsOp === "+" ? rhs1 + rhs2 : rhsOp === "-" ? rhs1 - rhs2 : rhsOp === "*" ? rhs1 * rhs2 : rhs1;
|
|
17564
|
+
const curVal = rawState.variables[varName] ?? "0";
|
|
17565
|
+
if (curVal === "" || /^-?(?:0|[1-9][0-9]{0,12})$/.test(curVal)) {
|
|
17566
|
+
const curNum = curVal === "" ? 0 : Number(curVal);
|
|
17567
|
+
const nextNum = binOp === "=" ? rhsNum : binOp === "+=" ? curNum + rhsNum : curNum - rhsNum;
|
|
17568
|
+
if (Number.isSafeInteger(nextNum)) {
|
|
17569
|
+
this.budget.parsing.admit(4);
|
|
17570
|
+
rawState.variables[varName] = intToStr(nextNum);
|
|
17571
|
+
touched.add(varName);
|
|
17572
|
+
return nextNum !== 0;
|
|
17573
|
+
}
|
|
17574
|
+
}
|
|
17575
|
+
}
|
|
17576
|
+
const binCmpMatch = fastSrc.length <= 64 ? /^\s*(-?(?:0|[1-9][0-9]{0,12}))\s*(==|!=|<|<=|>|>=)\s*(-?(?:0|[1-9][0-9]{0,12}))\s*$/.exec(fastSrc) : null;
|
|
17577
|
+
if (binCmpMatch) {
|
|
17578
|
+
const lhs = Number(binCmpMatch[1]);
|
|
17579
|
+
const op = binCmpMatch[2];
|
|
17580
|
+
const rhs = Number(binCmpMatch[3]);
|
|
17581
|
+
if (Number.isSafeInteger(lhs) && Number.isSafeInteger(rhs)) {
|
|
17292
17582
|
this.budget.parsing.admit(4);
|
|
17293
|
-
|
|
17294
|
-
touched.add(varName);
|
|
17295
|
-
return nextNum !== 0;
|
|
17583
|
+
return op === ">" ? lhs > rhs : op === ">=" ? lhs >= rhs : op === "<" ? lhs < rhs : op === "<=" ? lhs <= rhs : op === "==" ? lhs === rhs : lhs !== rhs;
|
|
17296
17584
|
}
|
|
17297
17585
|
}
|
|
17586
|
+
const dynProg = prepareArithmetic(fastSrc, this.budget.parsing);
|
|
17587
|
+
return this.syncShellArithmeticNonZero(dynProg, rawState, line);
|
|
17298
17588
|
}
|
|
17299
|
-
|
|
17300
|
-
|
|
17301
|
-
|
|
17302
|
-
const
|
|
17303
|
-
|
|
17304
|
-
|
|
17305
|
-
|
|
17306
|
-
|
|
17307
|
-
|
|
17589
|
+
catch (error) {
|
|
17590
|
+
if (!(error instanceof PublicDiagnostic))
|
|
17591
|
+
throw error;
|
|
17592
|
+
const write = syncSinks.get(io.stderr);
|
|
17593
|
+
if (!write)
|
|
17594
|
+
throw error;
|
|
17595
|
+
write(fastSharedTextEncoder.encode(`${io.scriptName ?? "shell"}: line ${line}: ((: ${error.message}\n`));
|
|
17596
|
+
rawState.status = 1;
|
|
17597
|
+
return undefined;
|
|
17308
17598
|
}
|
|
17309
|
-
const dynProg = prepareArithmetic(fastSrc, this.budget.parsing);
|
|
17310
|
-
return this.syncShellArithmeticNonZero(dynProg, rawState, line);
|
|
17311
17599
|
}
|
|
17312
17600
|
extractSyncLoopFnSpec(cmd, rawState, io) {
|
|
17313
17601
|
if (this._syncLoopFnCheckDepth > 0 || (rawState.locals && rawState.locals.length > 0))
|
|
@@ -17585,13 +17873,7 @@ export class Runtime {
|
|
|
17585
17873
|
break;
|
|
17586
17874
|
}
|
|
17587
17875
|
if (step.unsetVars !== undefined) {
|
|
17588
|
-
|
|
17589
|
-
const uvn = step.unsetVars[ui];
|
|
17590
|
-
delete rawState.variables[uvn];
|
|
17591
|
-
monitor.proxy.exported.delete(uvn);
|
|
17592
|
-
touched.add(uvn);
|
|
17593
|
-
}
|
|
17594
|
-
lastArg = step.cmd.words[step.cmd.words.length - 1].plain;
|
|
17876
|
+
lastArg = this.execSyncUnsetStep(step, rawState, io, monitor, touched);
|
|
17595
17877
|
rawState.status = 0;
|
|
17596
17878
|
onUpdate({ lastCmd, lastArg });
|
|
17597
17879
|
continue;
|
|
@@ -17610,16 +17892,7 @@ export class Runtime {
|
|
|
17610
17892
|
continue;
|
|
17611
17893
|
}
|
|
17612
17894
|
if (step.readHereString !== undefined) {
|
|
17613
|
-
|
|
17614
|
-
const rawInput = this.fastValueWord(rs.inputWord, rawState, io, false, false, false, false, 0, step.line);
|
|
17615
|
-
const delim = rs.delimChar ?? "\n";
|
|
17616
|
-
const fullInput = delim === "\n" ? rawInput : rawInput + "\n";
|
|
17617
|
-
const nlIdx = rs.isMapfile ? -1 : fullInput.indexOf(delim);
|
|
17618
|
-
const lineStr = nlIdx === -1 ? fullInput : fullInput.slice(0, nlIdx);
|
|
17619
|
-
const ifsStr = rs.ifsWord !== undefined ? this.fastValueWord(rs.ifsWord, rawState, io, false, false, false, false, 0, step.line) : (rawState.variables.IFS ?? " \t\n");
|
|
17620
|
-
this.splitSyncReadLine(lineStr, ifsStr, rs.varNames, rs.isBareReply, rawState, touched, rs.arrayTarget, monitor, rs.isMapfile);
|
|
17621
|
-
lastArg = step.cmd.words[step.cmd.words.length - 1].plain;
|
|
17622
|
-
rawState.status = (!rs.isMapfile && delim !== "\n" && nlIdx === -1) ? 1 : 0;
|
|
17895
|
+
lastArg = this.execSyncReadHereStringStep(step.readHereString, step, rawState, io, monitor, touched);
|
|
17623
17896
|
onUpdate({ lastCmd, lastArg });
|
|
17624
17897
|
continue;
|
|
17625
17898
|
}
|
|
@@ -17694,7 +17967,9 @@ export class Runtime {
|
|
|
17694
17967
|
lastArg = pLastArg;
|
|
17695
17968
|
}
|
|
17696
17969
|
else if (step.arrayAssign !== undefined) {
|
|
17697
|
-
this.tryFastArrayAssignmentSync(step.arrayAssign, rawState, io, step.line, undefined, undefined, true)
|
|
17970
|
+
if (!this.tryFastArrayAssignmentSync(step.arrayAssign, rawState, io, step.line, undefined, undefined, true)) {
|
|
17971
|
+
throw new Error("Synchronous loop array assignment was not executable");
|
|
17972
|
+
}
|
|
17698
17973
|
lastArg = "";
|
|
17699
17974
|
}
|
|
17700
17975
|
else if (step.printfVArgs !== undefined && step.name !== undefined) {
|
|
@@ -17783,13 +18058,7 @@ export class Runtime {
|
|
|
17783
18058
|
break;
|
|
17784
18059
|
}
|
|
17785
18060
|
if (step.unsetVars !== undefined) {
|
|
17786
|
-
|
|
17787
|
-
const uvn = step.unsetVars[ui];
|
|
17788
|
-
delete rawState.variables[uvn];
|
|
17789
|
-
monitor.proxy.exported.delete(uvn);
|
|
17790
|
-
touched.add(uvn);
|
|
17791
|
-
}
|
|
17792
|
-
lastArg = step.cmd.words[step.cmd.words.length - 1].plain;
|
|
18061
|
+
lastArg = this.execSyncUnsetStep(step, rawState, io, monitor, touched);
|
|
17793
18062
|
rawState.status = 0;
|
|
17794
18063
|
continue;
|
|
17795
18064
|
}
|
|
@@ -17805,16 +18074,7 @@ export class Runtime {
|
|
|
17805
18074
|
continue;
|
|
17806
18075
|
}
|
|
17807
18076
|
if (step.readHereString !== undefined) {
|
|
17808
|
-
|
|
17809
|
-
const rawInput = this.fastValueWord(rs.inputWord, rawState, io, false, false, false, false, 0, step.line);
|
|
17810
|
-
const delim = rs.delimChar ?? "\n";
|
|
17811
|
-
const fullInput = delim === "\n" ? rawInput : rawInput + "\n";
|
|
17812
|
-
const nlIdx = rs.isMapfile ? -1 : fullInput.indexOf(delim);
|
|
17813
|
-
const lineStr = nlIdx === -1 ? fullInput : fullInput.slice(0, nlIdx);
|
|
17814
|
-
const ifsStr = rs.ifsWord !== undefined ? this.fastValueWord(rs.ifsWord, rawState, io, false, false, false, false, 0, step.line) : (rawState.variables.IFS ?? " \t\n");
|
|
17815
|
-
this.splitSyncReadLine(lineStr, ifsStr, rs.varNames, rs.isBareReply, rawState, touched, rs.arrayTarget, monitor, rs.isMapfile);
|
|
17816
|
-
lastArg = step.cmd.words[step.cmd.words.length - 1].plain;
|
|
17817
|
-
rawState.status = (!rs.isMapfile && delim !== "\n" && nlIdx === -1) ? 1 : 0;
|
|
18077
|
+
lastArg = this.execSyncReadHereStringStep(step.readHereString, step, rawState, io, monitor, touched);
|
|
17818
18078
|
continue;
|
|
17819
18079
|
}
|
|
17820
18080
|
if (step.coalesceNext) {
|
|
@@ -17882,7 +18142,9 @@ export class Runtime {
|
|
|
17882
18142
|
continue;
|
|
17883
18143
|
}
|
|
17884
18144
|
else if (step.arrayAssign !== undefined) {
|
|
17885
|
-
this.tryFastArrayAssignmentSync(step.arrayAssign, rawState, io, step.line, undefined, undefined, true)
|
|
18145
|
+
if (!this.tryFastArrayAssignmentSync(step.arrayAssign, rawState, io, step.line, undefined, undefined, true)) {
|
|
18146
|
+
throw new Error("Synchronous loop array assignment was not executable");
|
|
18147
|
+
}
|
|
17886
18148
|
lastArg = "";
|
|
17887
18149
|
}
|
|
17888
18150
|
else if (step.arithStmt !== undefined) {
|
|
@@ -19153,7 +19415,7 @@ export class Runtime {
|
|
|
19153
19415
|
try {
|
|
19154
19416
|
status = await evaluateConditional(command.expression, {
|
|
19155
19417
|
fs: this.fs, cwd: state.cwd, signal: this.signal, predicateIdentity: io.capabilities?.predicateIdentity, reference: name => state.variableAttributes?.get(name)?.includes("n") ?? false, locale: state.variables.LC_ALL || state.variables.LC_COLLATE || state.variables.LANG || "C", characterLocale: state.variables.LC_ALL || state.variables.LC_CTYPE || state.variables.LANG || "C", ignoreCase: !!state.nocasematch, extglob: true, work: { remaining: this.budget.limits.maxExpansionBytes, signal: this.signal, exhausted: () => this.budget.fail("maxExpansionBytes"), allocation }, expand: async (word, pattern = false) => {
|
|
19156
|
-
const fast = !pattern ? this.fastValueWord(word, state, io, false, false, false, false) : undefined;
|
|
19418
|
+
const fast = !pattern ? this.fastValueWord(word, state, { ...io, nameExpansionContext: "conditional" }, false, false, false, false) : undefined;
|
|
19157
19419
|
if (typeof fast === "string")
|
|
19158
19420
|
return fast;
|
|
19159
19421
|
return (await this.word(word, state, { ...io, nameExpansionContext: "conditional" }, false, pattern, false, pattern)).join("");
|
|
@@ -24338,8 +24600,8 @@ export class Runtime {
|
|
|
24338
24600
|
invalid = true;
|
|
24339
24601
|
break;
|
|
24340
24602
|
}
|
|
24341
|
-
if (flag === "N")
|
|
24342
|
-
exact =
|
|
24603
|
+
if (flag === "n" || flag === "N")
|
|
24604
|
+
exact = flag === "N";
|
|
24343
24605
|
const value = option.slice(index + 1) || names.shift();
|
|
24344
24606
|
if (value === undefined)
|
|
24345
24607
|
invalid = true;
|
|
@@ -25782,25 +26044,27 @@ export class Runtime {
|
|
|
25782
26044
|
return undefined;
|
|
25783
26045
|
let transformed;
|
|
25784
26046
|
if (part.transform === "Q") {
|
|
25785
|
-
|
|
25786
|
-
|
|
25787
|
-
|
|
25788
|
-
return undefined;
|
|
25789
|
-
}
|
|
25790
|
-
transformed = "'" + (val.includes("'") ? val.split("'").join("'\\''") : val) + "'";
|
|
26047
|
+
if (byteLocale(rawState.variables))
|
|
26048
|
+
return undefined;
|
|
26049
|
+
transformed = this.formatSyncTransformQ(val);
|
|
25791
26050
|
}
|
|
25792
26051
|
else {
|
|
25793
|
-
|
|
25794
|
-
|
|
25795
|
-
|
|
26052
|
+
if (part.transform === "U") {
|
|
26053
|
+
transformed = val.toUpperCase();
|
|
26054
|
+
}
|
|
26055
|
+
else if (part.transform === "L") {
|
|
26056
|
+
transformed = val.toLowerCase();
|
|
26057
|
+
}
|
|
26058
|
+
else if (val.length === 0) {
|
|
26059
|
+
transformed = "";
|
|
26060
|
+
}
|
|
26061
|
+
else if (val.charCodeAt(0) < 128) {
|
|
26062
|
+
transformed = val[0].toUpperCase() + val.slice(1);
|
|
26063
|
+
}
|
|
26064
|
+
else {
|
|
26065
|
+
const first = [...val][0];
|
|
26066
|
+
transformed = first.toUpperCase() + val.slice(first.length);
|
|
25796
26067
|
}
|
|
25797
|
-
transformed = part.transform === "U"
|
|
25798
|
-
? val.toUpperCase()
|
|
25799
|
-
: part.transform === "L"
|
|
25800
|
-
? val.toLowerCase()
|
|
25801
|
-
: val.length === 0
|
|
25802
|
-
? ""
|
|
25803
|
-
: val[0].toUpperCase() + val.slice(1);
|
|
25804
26068
|
}
|
|
25805
26069
|
if (split && !part.quoted) {
|
|
25806
26070
|
if (transformed.length === 0 || transformed.includes(" ") || transformed.includes("\t") || transformed.includes("\n") || (!rawState.noglob && hasGlobOrEscape(transformed, !!rawState.extglob)))
|
|
@@ -25809,8 +26073,35 @@ export class Runtime {
|
|
|
25809
26073
|
out += transformed;
|
|
25810
26074
|
continue;
|
|
25811
26075
|
}
|
|
25812
|
-
if (part.prefixNames !== undefined)
|
|
25813
|
-
|
|
26076
|
+
if (part.prefixNames !== undefined) {
|
|
26077
|
+
if ((split && !(part.quoted && part.prefixNames === "*")) ||
|
|
26078
|
+
part.indirect ||
|
|
26079
|
+
part.specialParameter ||
|
|
26080
|
+
part.length ||
|
|
26081
|
+
part.substring ||
|
|
26082
|
+
part.transform !== undefined ||
|
|
26083
|
+
part.operator !== undefined ||
|
|
26084
|
+
getArraySelector(part) !== undefined ||
|
|
26085
|
+
this.budget.limits.maxExpansionFields !== Infinity ||
|
|
26086
|
+
this.budget.limits.maxExpansionBytes !== Infinity ||
|
|
26087
|
+
!isShellIdentifier(part.name)) {
|
|
26088
|
+
return undefined;
|
|
26089
|
+
}
|
|
26090
|
+
const pNames = this.collectSyncPrefixNames(part.name, rawState);
|
|
26091
|
+
if (pNames === undefined)
|
|
26092
|
+
return undefined;
|
|
26093
|
+
const ifs = rawState.variables.IFS ?? " ";
|
|
26094
|
+
const sep = io.nameExpansionContext === "document" || (io.nameExpansionContext === "conditional" && part.prefixNames === "@")
|
|
26095
|
+
? " "
|
|
26096
|
+
: ifs.length ? String.fromCodePoint(ifs.codePointAt(0)) : "";
|
|
26097
|
+
const joined = pNames.join(sep);
|
|
26098
|
+
if (split && !part.quoted) {
|
|
26099
|
+
if (joined.length === 0 || joined.includes(" ") || joined.includes("\t") || joined.includes("\n"))
|
|
26100
|
+
return undefined;
|
|
26101
|
+
}
|
|
26102
|
+
out += joined;
|
|
26103
|
+
continue;
|
|
26104
|
+
}
|
|
25814
26105
|
if (part.indirect || part.specialParameter)
|
|
25815
26106
|
return undefined;
|
|
25816
26107
|
if (part.name === "@" || part.name === "*" || part.name === "PIPESTATUS" || part.name === "LINENO" || part.name === "_" || part.name === "FUNCNAME" || part.name === "DIRSTACK")
|
|
@@ -26587,12 +26878,638 @@ export class Runtime {
|
|
|
26587
26878
|
this.budget.fail("maxExpansionBytes");
|
|
26588
26879
|
return out;
|
|
26589
26880
|
}
|
|
26590
|
-
|
|
26591
|
-
|
|
26881
|
+
expandSyncTrCharArray(spec) {
|
|
26882
|
+
if (spec.length === 0)
|
|
26883
|
+
return undefined;
|
|
26884
|
+
const posixClasses = {
|
|
26885
|
+
"[:lower:]": "abcdefghijklmnopqrstuvwxyz",
|
|
26886
|
+
"[:upper:]": "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
|
26887
|
+
"[:digit:]": "0123456789",
|
|
26888
|
+
"[:alpha:]": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
|
|
26889
|
+
"[:alnum:]": "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
|
|
26890
|
+
"[:space:]": "\t\n\v\f\r ",
|
|
26891
|
+
"[:blank:]": "\t ",
|
|
26892
|
+
"[:xdigit:]": "0123456789ABCDEFabcdef",
|
|
26893
|
+
"[:punct:]": "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
|
|
26894
|
+
};
|
|
26895
|
+
const out = [];
|
|
26592
26896
|
for (let i = 0; i < spec.length; i++) {
|
|
26593
|
-
if (i
|
|
26594
|
-
const
|
|
26595
|
-
|
|
26897
|
+
if (spec[i] === "[" && spec[i + 1] === ":") {
|
|
26898
|
+
const close = spec.indexOf(":]", i + 2);
|
|
26899
|
+
if (close === -1)
|
|
26900
|
+
return undefined;
|
|
26901
|
+
const cls = spec.slice(i, close + 2);
|
|
26902
|
+
const exp = posixClasses[cls];
|
|
26903
|
+
if (!exp)
|
|
26904
|
+
return undefined;
|
|
26905
|
+
for (let k = 0; k < exp.length; k++)
|
|
26906
|
+
out.push(exp[k]);
|
|
26907
|
+
i = close + 1;
|
|
26908
|
+
continue;
|
|
26909
|
+
}
|
|
26910
|
+
if (spec[i] === "[")
|
|
26911
|
+
return undefined;
|
|
26912
|
+
if (spec[i] === "\\") {
|
|
26913
|
+
if (i + 1 >= spec.length)
|
|
26914
|
+
return undefined;
|
|
26915
|
+
const next = spec[++i];
|
|
26916
|
+
if (next === "n")
|
|
26917
|
+
out.push("\n");
|
|
26918
|
+
else if (next === "t")
|
|
26919
|
+
out.push("\t");
|
|
26920
|
+
else if (next === "r")
|
|
26921
|
+
out.push("\r");
|
|
26922
|
+
else if (next === "\\")
|
|
26923
|
+
out.push("\\");
|
|
26924
|
+
else
|
|
26925
|
+
return undefined;
|
|
26926
|
+
continue;
|
|
26927
|
+
}
|
|
26928
|
+
if (i + 2 < spec.length && spec[i + 1] === "-" && spec[i + 2] !== "\\") {
|
|
26929
|
+
const start = spec.charCodeAt(i);
|
|
26930
|
+
const end = spec.charCodeAt(i + 2);
|
|
26931
|
+
if (start <= end && end - start <= 256) {
|
|
26932
|
+
for (let c = start; c <= end; c++)
|
|
26933
|
+
out.push(String.fromCharCode(c));
|
|
26934
|
+
i += 2;
|
|
26935
|
+
continue;
|
|
26936
|
+
}
|
|
26937
|
+
return undefined;
|
|
26938
|
+
}
|
|
26939
|
+
out.push(spec[i]);
|
|
26940
|
+
}
|
|
26941
|
+
return out;
|
|
26942
|
+
}
|
|
26943
|
+
evalSyncTr(input, opArgs) {
|
|
26944
|
+
if (opArgs.length === 2 && !opArgs[0].startsWith("-") && !opArgs[1].startsWith("-")) {
|
|
26945
|
+
return this.translateSyncTr(input, opArgs[0], opArgs[1]);
|
|
26946
|
+
}
|
|
26947
|
+
if (opArgs.length === 2 && opArgs[0] === "-d" && !opArgs[1].startsWith("-")) {
|
|
26948
|
+
const arr = this.expandSyncTrCharArray(opArgs[1]);
|
|
26949
|
+
if (!arr)
|
|
26950
|
+
return undefined;
|
|
26951
|
+
const delSet = new Set(arr);
|
|
26952
|
+
let out = "";
|
|
26953
|
+
for (let i = 0; i < input.length; i++) {
|
|
26954
|
+
const ch = input[i];
|
|
26955
|
+
if (!delSet.has(ch))
|
|
26956
|
+
out += ch;
|
|
26957
|
+
}
|
|
26958
|
+
return out;
|
|
26959
|
+
}
|
|
26960
|
+
if (opArgs.length === 2 && opArgs[0] === "-s" && !opArgs[1].startsWith("-")) {
|
|
26961
|
+
const arr = this.expandSyncTrCharArray(opArgs[1]);
|
|
26962
|
+
if (!arr)
|
|
26963
|
+
return undefined;
|
|
26964
|
+
const sqSet = new Set(arr);
|
|
26965
|
+
let out = "";
|
|
26966
|
+
let prev = "";
|
|
26967
|
+
for (let i = 0; i < input.length; i++) {
|
|
26968
|
+
const ch = input[i];
|
|
26969
|
+
if (sqSet.has(ch) && ch === prev)
|
|
26970
|
+
continue;
|
|
26971
|
+
out += ch;
|
|
26972
|
+
prev = ch;
|
|
26973
|
+
}
|
|
26974
|
+
return out;
|
|
26975
|
+
}
|
|
26976
|
+
if (opArgs.length === 3 && (opArgs[0] === "-s" || opArgs[0] === "-ds" || opArgs[0] === "-sd") && !opArgs[1].startsWith("-") && !opArgs[2].startsWith("-")) {
|
|
26977
|
+
const stage1 = opArgs[0] === "-s"
|
|
26978
|
+
? this.translateSyncTr(input, opArgs[1], opArgs[2])
|
|
26979
|
+
: this.evalSyncTr(input, ["-d", opArgs[1]]);
|
|
26980
|
+
if (stage1 === undefined)
|
|
26981
|
+
return undefined;
|
|
26982
|
+
return this.evalSyncTr(stage1, ["-s", opArgs[2]]);
|
|
26983
|
+
}
|
|
26984
|
+
return undefined;
|
|
26985
|
+
}
|
|
26986
|
+
evalSyncJq(input, opArgs) {
|
|
26987
|
+
let rawOut = false;
|
|
26988
|
+
let filter;
|
|
26989
|
+
if (opArgs.length === 1 && !opArgs[0].startsWith("-")) {
|
|
26990
|
+
filter = opArgs[0];
|
|
26991
|
+
}
|
|
26992
|
+
else if (opArgs.length === 2 && (opArgs[0] === "-r" || opArgs[0] === "--raw-output" || opArgs[0] === "-c" || opArgs[0] === "--compact-output" || opArgs[0] === "-rc" || opArgs[0] === "-cr")) {
|
|
26993
|
+
rawOut = opArgs[0].includes("r");
|
|
26994
|
+
filter = opArgs[1];
|
|
26995
|
+
}
|
|
26996
|
+
if (!filter)
|
|
26997
|
+
return undefined;
|
|
26998
|
+
const stages = filter.split("|").map(s => s.trim());
|
|
26999
|
+
const compiledStages = [];
|
|
27000
|
+
for (const st of stages) {
|
|
27001
|
+
if (st === ".") {
|
|
27002
|
+
compiledStages.push([]);
|
|
27003
|
+
continue;
|
|
27004
|
+
}
|
|
27005
|
+
if (st === "length") {
|
|
27006
|
+
compiledStages.push([{ kind: "length" }]);
|
|
27007
|
+
continue;
|
|
27008
|
+
}
|
|
27009
|
+
if (st === "keys") {
|
|
27010
|
+
compiledStages.push([{ kind: "keys" }]);
|
|
27011
|
+
continue;
|
|
27012
|
+
}
|
|
27013
|
+
if (st === "keys[]") {
|
|
27014
|
+
compiledStages.push([{ kind: "keys" }, { kind: "iter" }]);
|
|
27015
|
+
continue;
|
|
27016
|
+
}
|
|
27017
|
+
if (!st.startsWith("."))
|
|
27018
|
+
return undefined;
|
|
27019
|
+
let rest = st.slice(1);
|
|
27020
|
+
const ops = [];
|
|
27021
|
+
while (rest.length > 0) {
|
|
27022
|
+
if (rest.startsWith("."))
|
|
27023
|
+
rest = rest.slice(1);
|
|
27024
|
+
const propM = /^([a-zA-Z_][a-zA-Z0-9_]*)/.exec(rest);
|
|
27025
|
+
if (propM) {
|
|
27026
|
+
ops.push({ kind: "prop", key: propM[1] });
|
|
27027
|
+
rest = rest.slice(propM[1].length);
|
|
27028
|
+
continue;
|
|
27029
|
+
}
|
|
27030
|
+
if (rest.startsWith("[]")) {
|
|
27031
|
+
ops.push({ kind: "iter" });
|
|
27032
|
+
rest = rest.slice(2);
|
|
27033
|
+
continue;
|
|
27034
|
+
}
|
|
27035
|
+
const idxM = /^\[(-?[0-9]+)\]/.exec(rest);
|
|
27036
|
+
if (idxM) {
|
|
27037
|
+
ops.push({ kind: "index", idx: Number(idxM[1]) });
|
|
27038
|
+
rest = rest.slice(idxM[0].length);
|
|
27039
|
+
continue;
|
|
27040
|
+
}
|
|
27041
|
+
return undefined;
|
|
27042
|
+
}
|
|
27043
|
+
compiledStages.push(ops);
|
|
27044
|
+
}
|
|
27045
|
+
let parsed;
|
|
27046
|
+
try {
|
|
27047
|
+
parsed = JSON.parse(input);
|
|
27048
|
+
}
|
|
27049
|
+
catch {
|
|
27050
|
+
return undefined;
|
|
27051
|
+
}
|
|
27052
|
+
let current = [parsed];
|
|
27053
|
+
for (const ops of compiledStages) {
|
|
27054
|
+
for (const op of ops) {
|
|
27055
|
+
const next = [];
|
|
27056
|
+
for (const item of current) {
|
|
27057
|
+
if (op.kind === "prop") {
|
|
27058
|
+
if (item === null || item === undefined)
|
|
27059
|
+
next.push(null);
|
|
27060
|
+
else if (typeof item === "object" && !Array.isArray(item))
|
|
27061
|
+
next.push(item[op.key] ?? null);
|
|
27062
|
+
else
|
|
27063
|
+
return undefined;
|
|
27064
|
+
}
|
|
27065
|
+
else if (op.kind === "index") {
|
|
27066
|
+
if (item === null || item === undefined)
|
|
27067
|
+
next.push(null);
|
|
27068
|
+
else if (Array.isArray(item)) {
|
|
27069
|
+
const i = op.idx < 0 ? item.length + op.idx : op.idx;
|
|
27070
|
+
next.push(i >= 0 && i < item.length ? item[i] : null);
|
|
27071
|
+
}
|
|
27072
|
+
else
|
|
27073
|
+
return undefined;
|
|
27074
|
+
}
|
|
27075
|
+
else if (op.kind === "iter") {
|
|
27076
|
+
if (Array.isArray(item)) {
|
|
27077
|
+
for (const el of item)
|
|
27078
|
+
next.push(el);
|
|
27079
|
+
}
|
|
27080
|
+
else if (item && typeof item === "object") {
|
|
27081
|
+
for (const k of Object.keys(item))
|
|
27082
|
+
next.push(item[k]);
|
|
27083
|
+
}
|
|
27084
|
+
else
|
|
27085
|
+
return undefined;
|
|
27086
|
+
}
|
|
27087
|
+
else if (op.kind === "length") {
|
|
27088
|
+
if (item === null || item === undefined)
|
|
27089
|
+
next.push(0);
|
|
27090
|
+
else if (typeof item === "string" || Array.isArray(item))
|
|
27091
|
+
next.push(item.length);
|
|
27092
|
+
else if (typeof item === "object")
|
|
27093
|
+
next.push(Object.keys(item).length);
|
|
27094
|
+
else
|
|
27095
|
+
return undefined;
|
|
27096
|
+
}
|
|
27097
|
+
else if (op.kind === "keys") {
|
|
27098
|
+
if (Array.isArray(item))
|
|
27099
|
+
next.push(item.map((_, idx) => idx));
|
|
27100
|
+
else if (item && typeof item === "object")
|
|
27101
|
+
next.push(Object.keys(item).sort());
|
|
27102
|
+
else
|
|
27103
|
+
return undefined;
|
|
27104
|
+
}
|
|
27105
|
+
}
|
|
27106
|
+
current = next;
|
|
27107
|
+
}
|
|
27108
|
+
}
|
|
27109
|
+
return current.map(val => (rawOut && typeof val === "string" ? val : JSON.stringify(val ?? null)));
|
|
27110
|
+
}
|
|
27111
|
+
parseSyncCutSpec(spec) {
|
|
27112
|
+
if (!/^(?:[1-9][0-9]{0,4}|[1-9][0-9]{0,4}-[1-9][0-9]{0,4}|[1-9][0-9]{0,4}-|-[1-9][0-9]{0,4})(?:,(?:[1-9][0-9]{0,4}|[1-9][0-9]{0,4}-[1-9][0-9]{0,4}|[1-9][0-9]{0,4}-|-[1-9][0-9]{0,4}))*$/.test(spec)) {
|
|
27113
|
+
return undefined;
|
|
27114
|
+
}
|
|
27115
|
+
const ranges = [];
|
|
27116
|
+
for (const part of spec.split(",")) {
|
|
27117
|
+
const dash = part.indexOf("-");
|
|
27118
|
+
if (dash === -1) {
|
|
27119
|
+
const n = Number(part);
|
|
27120
|
+
ranges.push([n, n]);
|
|
27121
|
+
}
|
|
27122
|
+
else if (dash === 0) {
|
|
27123
|
+
const end = Number(part.slice(1));
|
|
27124
|
+
ranges.push([1, end]);
|
|
27125
|
+
}
|
|
27126
|
+
else if (dash === part.length - 1) {
|
|
27127
|
+
const start = Number(part.slice(0, -1));
|
|
27128
|
+
ranges.push([start, Infinity]);
|
|
27129
|
+
}
|
|
27130
|
+
else {
|
|
27131
|
+
const start = Number(part.slice(0, dash));
|
|
27132
|
+
const end = Number(part.slice(dash + 1));
|
|
27133
|
+
if (start > end)
|
|
27134
|
+
return undefined;
|
|
27135
|
+
ranges.push([start, end]);
|
|
27136
|
+
}
|
|
27137
|
+
}
|
|
27138
|
+
return (len) => {
|
|
27139
|
+
const out = [];
|
|
27140
|
+
for (let i = 1; i <= len; i++) {
|
|
27141
|
+
for (let r = 0; r < ranges.length; r++) {
|
|
27142
|
+
const [s, e] = ranges[r];
|
|
27143
|
+
if (i >= s && i <= e) {
|
|
27144
|
+
out.push(i - 1);
|
|
27145
|
+
break;
|
|
27146
|
+
}
|
|
27147
|
+
}
|
|
27148
|
+
}
|
|
27149
|
+
return out;
|
|
27150
|
+
};
|
|
27151
|
+
}
|
|
27152
|
+
evalSyncCut(rawLines, opArgs, byteLocaleMode) {
|
|
27153
|
+
const norm = [];
|
|
27154
|
+
let suppressNoDelim = false;
|
|
27155
|
+
for (let ci = 0; ci < opArgs.length; ci++) {
|
|
27156
|
+
const ca = opArgs[ci];
|
|
27157
|
+
if (ca === "-s" || ca === "--only-delimited") {
|
|
27158
|
+
suppressNoDelim = true;
|
|
27159
|
+
}
|
|
27160
|
+
else if (ca.startsWith("-sd") || ca.startsWith("-ds")) {
|
|
27161
|
+
suppressNoDelim = true;
|
|
27162
|
+
const rest = ca.slice(3);
|
|
27163
|
+
if (rest.length > 0)
|
|
27164
|
+
norm.push("-d" + rest);
|
|
27165
|
+
else if (ci + 1 < opArgs.length)
|
|
27166
|
+
norm.push("-d" + opArgs[++ci]);
|
|
27167
|
+
else
|
|
27168
|
+
return undefined;
|
|
27169
|
+
}
|
|
27170
|
+
else if ((ca === "-d" || ca === "-f" || ca === "-c") && ci + 1 < opArgs.length) {
|
|
27171
|
+
norm.push(ca + opArgs[++ci]);
|
|
27172
|
+
}
|
|
27173
|
+
else {
|
|
27174
|
+
norm.push(ca);
|
|
27175
|
+
}
|
|
27176
|
+
}
|
|
27177
|
+
if (!suppressNoDelim && norm.length === 1 && norm[0].startsWith("-c")) {
|
|
27178
|
+
if (byteLocaleMode)
|
|
27179
|
+
return undefined;
|
|
27180
|
+
const picker = this.parseSyncCutSpec(norm[0].slice(2));
|
|
27181
|
+
if (!picker)
|
|
27182
|
+
return undefined;
|
|
27183
|
+
return rawLines.map(l => {
|
|
27184
|
+
const chars = Array.from(l);
|
|
27185
|
+
const idxs = picker(chars.length);
|
|
27186
|
+
return idxs.map(i => chars[i]).join("");
|
|
27187
|
+
});
|
|
27188
|
+
}
|
|
27189
|
+
let delim = "\t";
|
|
27190
|
+
let fArg;
|
|
27191
|
+
if (norm.length === 1 && norm[0].startsWith("-f")) {
|
|
27192
|
+
fArg = norm[0];
|
|
27193
|
+
}
|
|
27194
|
+
else if (norm.length === 2) {
|
|
27195
|
+
const dCandidate = norm[0].startsWith("-d") ? norm[0] : (norm[1].startsWith("-d") ? norm[1] : undefined);
|
|
27196
|
+
const fCandidate = norm[0].startsWith("-f") ? norm[0] : (norm[1].startsWith("-f") ? norm[1] : undefined);
|
|
27197
|
+
if (dCandidate && dCandidate.length === 3 && fCandidate) {
|
|
27198
|
+
delim = dCandidate[2];
|
|
27199
|
+
fArg = fCandidate;
|
|
27200
|
+
}
|
|
27201
|
+
}
|
|
27202
|
+
if (!fArg || !fArg.startsWith("-f"))
|
|
27203
|
+
return undefined;
|
|
27204
|
+
const picker = this.parseSyncCutSpec(fArg.slice(2));
|
|
27205
|
+
if (!picker)
|
|
27206
|
+
return undefined;
|
|
27207
|
+
const out = [];
|
|
27208
|
+
for (let li = 0; li < rawLines.length; li++) {
|
|
27209
|
+
const l = rawLines[li];
|
|
27210
|
+
if (!l.includes(delim)) {
|
|
27211
|
+
if (!suppressNoDelim)
|
|
27212
|
+
out.push(l);
|
|
27213
|
+
continue;
|
|
27214
|
+
}
|
|
27215
|
+
const parts = l.split(delim);
|
|
27216
|
+
const idxs = picker(parts.length);
|
|
27217
|
+
out.push(idxs.map(i => parts[i]).join(delim));
|
|
27218
|
+
}
|
|
27219
|
+
return out;
|
|
27220
|
+
}
|
|
27221
|
+
evalSyncSed(rawLines, opArgs) {
|
|
27222
|
+
let quiet = false;
|
|
27223
|
+
let expr;
|
|
27224
|
+
if (opArgs.length === 1 && !opArgs[0].startsWith("-")) {
|
|
27225
|
+
expr = opArgs[0];
|
|
27226
|
+
}
|
|
27227
|
+
else if (opArgs.length === 2 && opArgs[0] === "-e") {
|
|
27228
|
+
expr = opArgs[1];
|
|
27229
|
+
}
|
|
27230
|
+
else if (opArgs.length === 2 && opArgs[0] === "-n") {
|
|
27231
|
+
quiet = true;
|
|
27232
|
+
expr = opArgs[1];
|
|
27233
|
+
}
|
|
27234
|
+
else if (opArgs.length === 3 && ((opArgs[0] === "-n" && opArgs[1] === "-e") || (opArgs[0] === "-e" && opArgs[1] === "-n"))) {
|
|
27235
|
+
quiet = true;
|
|
27236
|
+
expr = opArgs[2];
|
|
27237
|
+
}
|
|
27238
|
+
if (!expr)
|
|
27239
|
+
return undefined;
|
|
27240
|
+
const addrCmdM = /^(?:([1-9][0-9]{0,4}|\$)(?:,([1-9][0-9]{0,4}|\$))?|\/(\^?[a-zA-Z0-9_ :;,.-]+\$?)\/)([dp])$/.exec(expr);
|
|
27241
|
+
if (addrCmdM) {
|
|
27242
|
+
const cmdChar = addrCmdM[4];
|
|
27243
|
+
if ((quiet && cmdChar !== "p") || (!quiet && cmdChar !== "d"))
|
|
27244
|
+
return undefined;
|
|
27245
|
+
const startSpec = addrCmdM[1];
|
|
27246
|
+
const endSpec = addrCmdM[2];
|
|
27247
|
+
const patSpec = addrCmdM[3];
|
|
27248
|
+
const matchLine = (l, idx1, total) => {
|
|
27249
|
+
if (patSpec !== undefined) {
|
|
27250
|
+
const aStart = patSpec.startsWith("^");
|
|
27251
|
+
const c1 = aStart ? patSpec.slice(1) : patSpec;
|
|
27252
|
+
const aEnd = c1.endsWith("$");
|
|
27253
|
+
const core = aEnd ? c1.slice(0, -1) : c1;
|
|
27254
|
+
if (aStart && aEnd)
|
|
27255
|
+
return l === core;
|
|
27256
|
+
if (aStart)
|
|
27257
|
+
return l.startsWith(core);
|
|
27258
|
+
if (aEnd)
|
|
27259
|
+
return l.endsWith(core);
|
|
27260
|
+
return l.includes(core);
|
|
27261
|
+
}
|
|
27262
|
+
const sNum = startSpec === "$" ? total : Number(startSpec);
|
|
27263
|
+
if (endSpec === undefined)
|
|
27264
|
+
return idx1 === sNum;
|
|
27265
|
+
const eNum = endSpec === "$" ? total : Number(endSpec);
|
|
27266
|
+
return idx1 >= sNum && idx1 <= eNum;
|
|
27267
|
+
};
|
|
27268
|
+
const out = [];
|
|
27269
|
+
for (let i = 0; i < rawLines.length; i++) {
|
|
27270
|
+
const hit = matchLine(rawLines[i], i + 1, rawLines.length);
|
|
27271
|
+
if (cmdChar === "p" && hit)
|
|
27272
|
+
out.push(rawLines[i]);
|
|
27273
|
+
else if (cmdChar === "d" && !hit)
|
|
27274
|
+
out.push(rawLines[i]);
|
|
27275
|
+
}
|
|
27276
|
+
return out;
|
|
27277
|
+
}
|
|
27278
|
+
if (quiet)
|
|
27279
|
+
return undefined;
|
|
27280
|
+
if (!expr.startsWith("s") || expr.length < 4)
|
|
27281
|
+
return undefined;
|
|
27282
|
+
const delim = expr[1];
|
|
27283
|
+
if (!"/#|:@,;%!".includes(delim))
|
|
27284
|
+
return undefined;
|
|
27285
|
+
const parts = expr.slice(2).split(delim);
|
|
27286
|
+
if (parts.length !== 3)
|
|
27287
|
+
return undefined;
|
|
27288
|
+
const [pat, rep, flags] = parts;
|
|
27289
|
+
if ((flags !== "" && flags !== "g") || /[&\\\n]/.test(rep))
|
|
27290
|
+
return undefined;
|
|
27291
|
+
const anchorStart = pat.startsWith("^");
|
|
27292
|
+
const core1 = anchorStart ? pat.slice(1) : pat;
|
|
27293
|
+
const anchorEnd = core1.endsWith("$");
|
|
27294
|
+
const core = anchorEnd ? core1.slice(0, -1) : core1;
|
|
27295
|
+
if (core.length === 0 || !/^[a-zA-Z0-9_ :;,/-]+$/.test(core))
|
|
27296
|
+
return undefined;
|
|
27297
|
+
const isGlobal = flags === "g";
|
|
27298
|
+
return rawLines.map(l => {
|
|
27299
|
+
if (anchorStart && anchorEnd)
|
|
27300
|
+
return l === core ? rep : l;
|
|
27301
|
+
if (anchorStart)
|
|
27302
|
+
return l.startsWith(core) ? rep + l.slice(core.length) : l;
|
|
27303
|
+
if (anchorEnd)
|
|
27304
|
+
return l.endsWith(core) ? l.slice(0, l.length - core.length) + rep : l;
|
|
27305
|
+
return isGlobal ? l.split(core).join(rep) : l.replace(core, () => rep);
|
|
27306
|
+
});
|
|
27307
|
+
}
|
|
27308
|
+
evalSyncGrep(rawLines, opArgs, errexit) {
|
|
27309
|
+
if (errexit || (opArgs.length !== 1 && opArgs.length !== 2))
|
|
27310
|
+
return undefined;
|
|
27311
|
+
const mode = opArgs.length === 2 ? opArgs[0] : "";
|
|
27312
|
+
const pat = opArgs[opArgs.length - 1];
|
|
27313
|
+
if (pat.startsWith("-"))
|
|
27314
|
+
return undefined;
|
|
27315
|
+
if (opArgs.length === 2 && mode !== "-v" && mode !== "-i" && mode !== "-c" && mode !== "-F" && mode !== "-E" && mode !== "-Ei" && mode !== "-iE" && mode !== "-Ev" && mode !== "-vE") {
|
|
27316
|
+
return undefined;
|
|
27317
|
+
}
|
|
27318
|
+
const isCaseInsensitive = mode.includes("i");
|
|
27319
|
+
const isInvert = mode.includes("v");
|
|
27320
|
+
const isCount = mode === "-c";
|
|
27321
|
+
const isExtended = mode.includes("E");
|
|
27322
|
+
const isFixed = mode.includes("F");
|
|
27323
|
+
const branches = isExtended ? pat.split("|") : [pat];
|
|
27324
|
+
const compiledBranches = [];
|
|
27325
|
+
for (const br of branches) {
|
|
27326
|
+
if (br.length === 0)
|
|
27327
|
+
return undefined;
|
|
27328
|
+
const anchorStart = !isFixed && br.startsWith("^");
|
|
27329
|
+
const c1 = anchorStart ? br.slice(1) : br;
|
|
27330
|
+
const anchorEnd = !isFixed && c1.endsWith("$");
|
|
27331
|
+
const core = anchorEnd ? c1.slice(0, -1) : c1;
|
|
27332
|
+
if (core.length === 0 || !/^[a-zA-Z0-9_ :;,/-]+$/.test(core))
|
|
27333
|
+
return undefined;
|
|
27334
|
+
compiledBranches.push({ anchorStart, anchorEnd, needle: isCaseInsensitive ? core.toLowerCase() : core });
|
|
27335
|
+
}
|
|
27336
|
+
const matched = [];
|
|
27337
|
+
for (let li = 0; li < rawLines.length; li++) {
|
|
27338
|
+
const l = rawLines[li];
|
|
27339
|
+
const hay = isCaseInsensitive ? l.toLowerCase() : l;
|
|
27340
|
+
let hit = false;
|
|
27341
|
+
for (let bi = 0; bi < compiledBranches.length; bi++) {
|
|
27342
|
+
const b = compiledBranches[bi];
|
|
27343
|
+
const ok = b.anchorStart && b.anchorEnd
|
|
27344
|
+
? hay === b.needle
|
|
27345
|
+
: b.anchorStart
|
|
27346
|
+
? hay.startsWith(b.needle)
|
|
27347
|
+
: b.anchorEnd
|
|
27348
|
+
? hay.endsWith(b.needle)
|
|
27349
|
+
: hay.includes(b.needle);
|
|
27350
|
+
if (ok) {
|
|
27351
|
+
hit = true;
|
|
27352
|
+
break;
|
|
27353
|
+
}
|
|
27354
|
+
}
|
|
27355
|
+
if (isInvert ? !hit : hit)
|
|
27356
|
+
matched.push(l);
|
|
27357
|
+
}
|
|
27358
|
+
return {
|
|
27359
|
+
lines: isCount ? [String(matched.length)] : matched,
|
|
27360
|
+
status: matched.length > 0 ? 0 : 1,
|
|
27361
|
+
};
|
|
27362
|
+
}
|
|
27363
|
+
evalSyncAwk(rawLines, opArgs) {
|
|
27364
|
+
if (opArgs.length < 1 || opArgs.length > 3)
|
|
27365
|
+
return undefined;
|
|
27366
|
+
const norm = opArgs.length === 3 && opArgs[0] === "-F" ? ["-F" + opArgs[1], opArgs[2]] : opArgs;
|
|
27367
|
+
let awkSep;
|
|
27368
|
+
let awkProg;
|
|
27369
|
+
if (norm.length === 1)
|
|
27370
|
+
awkProg = norm[0];
|
|
27371
|
+
else if (norm.length === 2 && norm[0].length === 3 && norm[0].startsWith("-F") && norm[0][2] !== "\\") {
|
|
27372
|
+
awkSep = norm[0].slice(2);
|
|
27373
|
+
awkProg = norm[1];
|
|
27374
|
+
}
|
|
27375
|
+
if (!awkProg)
|
|
27376
|
+
return undefined;
|
|
27377
|
+
const awkM = /^\s*\{\s*print(?:\s+((?:\$(?:[0-9]+|NF)|"[^"$\\]*")(?:\s*,?\s*(?:\$(?:[0-9]+|NF)|"[^"$\\]*"))*))?\s*;?\s*\}\s*$/.exec(awkProg);
|
|
27378
|
+
if (!awkM)
|
|
27379
|
+
return undefined;
|
|
27380
|
+
const exprBody = awkM[1]?.trim();
|
|
27381
|
+
const parts = [];
|
|
27382
|
+
if (!exprBody) {
|
|
27383
|
+
parts.push({ kind: "field", token: "0" });
|
|
27384
|
+
}
|
|
27385
|
+
else {
|
|
27386
|
+
const tokenRe = /\$([0-9]+|NF)|"([^"$\\]*)"|(,)/g;
|
|
27387
|
+
let m;
|
|
27388
|
+
while ((m = tokenRe.exec(exprBody)) !== null) {
|
|
27389
|
+
if (m[1] !== undefined)
|
|
27390
|
+
parts.push({ kind: "field", token: m[1] });
|
|
27391
|
+
else if (m[2] !== undefined)
|
|
27392
|
+
parts.push({ kind: "lit", text: m[2] });
|
|
27393
|
+
else if (m[3] !== undefined)
|
|
27394
|
+
parts.push({ kind: "lit", text: " " });
|
|
27395
|
+
}
|
|
27396
|
+
}
|
|
27397
|
+
return rawLines.map(l => {
|
|
27398
|
+
if (parts.length === 1 && parts[0].kind === "field" && parts[0].token === "0")
|
|
27399
|
+
return l;
|
|
27400
|
+
const fields = awkSep !== undefined
|
|
27401
|
+
? (awkSep === " " ? l.trim().split(/\s+/).filter(Boolean) : (l.length === 0 ? [] : l.split(awkSep)))
|
|
27402
|
+
: l.trim().split(/\s+/).filter(Boolean);
|
|
27403
|
+
let out = "";
|
|
27404
|
+
for (let pi = 0; pi < parts.length; pi++) {
|
|
27405
|
+
const p = parts[pi];
|
|
27406
|
+
if (p.kind === "lit")
|
|
27407
|
+
out += p.text;
|
|
27408
|
+
else if (p.token === "0")
|
|
27409
|
+
out += l;
|
|
27410
|
+
else {
|
|
27411
|
+
const idx = p.token === "NF" ? fields.length : Number(p.token);
|
|
27412
|
+
out += idx === 0 ? l : (idx >= 1 && idx <= fields.length ? fields[idx - 1] : "");
|
|
27413
|
+
}
|
|
27414
|
+
}
|
|
27415
|
+
return out;
|
|
27416
|
+
});
|
|
27417
|
+
}
|
|
27418
|
+
formatSyncTransformQ(val) {
|
|
27419
|
+
let ansi = false;
|
|
27420
|
+
for (let i = 0; i < val.length; i++) {
|
|
27421
|
+
const c = val.charCodeAt(i);
|
|
27422
|
+
if (c < 32 || c === 127) {
|
|
27423
|
+
ansi = true;
|
|
27424
|
+
break;
|
|
27425
|
+
}
|
|
27426
|
+
if (c >= 128) {
|
|
27427
|
+
const cp = val.codePointAt(i);
|
|
27428
|
+
if (/[\p{Cc}\p{Cf}\p{Cn}]/u.test(String.fromCodePoint(cp))) {
|
|
27429
|
+
ansi = true;
|
|
27430
|
+
break;
|
|
27431
|
+
}
|
|
27432
|
+
if (cp > 0xffff)
|
|
27433
|
+
i++;
|
|
27434
|
+
}
|
|
27435
|
+
}
|
|
27436
|
+
if (!ansi) {
|
|
27437
|
+
return "'" + (val.includes("'") ? val.split("'").join("'\\''") : val) + "'";
|
|
27438
|
+
}
|
|
27439
|
+
const escMap = { 7: "\\a", 8: "\\b", 9: "\\t", 10: "\\n", 11: "\\v", 12: "\\f", 13: "\\r", 27: "\\E" };
|
|
27440
|
+
let out = "$'";
|
|
27441
|
+
for (const ch of val) {
|
|
27442
|
+
const cp = ch.codePointAt(0);
|
|
27443
|
+
if (escMap[cp] !== undefined)
|
|
27444
|
+
out += escMap[cp];
|
|
27445
|
+
else if (cp === 39)
|
|
27446
|
+
out += "\\'";
|
|
27447
|
+
else if (cp === 92)
|
|
27448
|
+
out += "\\\\";
|
|
27449
|
+
else if ((cp >= 32 && cp < 127) || (cp >= 128 && !/[\p{Cc}\p{Cf}\p{Cn}]/u.test(ch)))
|
|
27450
|
+
out += ch;
|
|
27451
|
+
else {
|
|
27452
|
+
const bytes = fastSharedTextEncoder.encode(ch);
|
|
27453
|
+
for (let bi = 0; bi < bytes.length; bi++)
|
|
27454
|
+
out += "\\" + bytes[bi].toString(8).padStart(3, "0");
|
|
27455
|
+
}
|
|
27456
|
+
}
|
|
27457
|
+
return out + "'";
|
|
27458
|
+
}
|
|
27459
|
+
sortSyncLines(rawLines, flag) {
|
|
27460
|
+
const rev = flag !== undefined && flag.includes("r");
|
|
27461
|
+
const num = flag !== undefined && flag.includes("n");
|
|
27462
|
+
const uniq = flag !== undefined && flag.includes("u");
|
|
27463
|
+
const parseNum = (s) => {
|
|
27464
|
+
const m = /^[ \t]*([+-]?(?:\d+(?:\.\d*)?|\.\d+))/.exec(s);
|
|
27465
|
+
return m ? Number(m[1]) : 0;
|
|
27466
|
+
};
|
|
27467
|
+
const sorted = [...rawLines].sort((a, b) => {
|
|
27468
|
+
if (num) {
|
|
27469
|
+
const na = parseNum(a);
|
|
27470
|
+
const nb = parseNum(b);
|
|
27471
|
+
if (na !== nb)
|
|
27472
|
+
return rev ? nb - na : na - nb;
|
|
27473
|
+
}
|
|
27474
|
+
return a < b ? (rev ? 1 : -1) : a > b ? (rev ? -1 : 1) : 0;
|
|
27475
|
+
});
|
|
27476
|
+
if (!uniq)
|
|
27477
|
+
return sorted;
|
|
27478
|
+
const dedup = [];
|
|
27479
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
27480
|
+
if (i === 0 || sorted[i] !== sorted[i - 1])
|
|
27481
|
+
dedup.push(sorted[i]);
|
|
27482
|
+
}
|
|
27483
|
+
return dedup;
|
|
27484
|
+
}
|
|
27485
|
+
translateSyncTr(input, set1Spec, set2Spec) {
|
|
27486
|
+
if (set1Spec === "a-z" && set2Spec === "A-Z")
|
|
27487
|
+
return input.toUpperCase();
|
|
27488
|
+
if (set1Spec === "A-Z" && set2Spec === "a-z")
|
|
27489
|
+
return input.toLowerCase();
|
|
27490
|
+
const s1 = this.expandSyncTrCharArray(set1Spec);
|
|
27491
|
+
const s2 = this.expandSyncTrCharArray(set2Spec);
|
|
27492
|
+
if (!s1 || !s2 || s1.length === 0 || s2.length === 0)
|
|
27493
|
+
return undefined;
|
|
27494
|
+
if (s1.length === 1 && s2.length === 1)
|
|
27495
|
+
return input.split(s1[0]).join(s2[0]);
|
|
27496
|
+
const map = new Map();
|
|
27497
|
+
for (let i = 0; i < s1.length; i++) {
|
|
27498
|
+
map.set(s1[i], s2[Math.min(i, s2.length - 1)]);
|
|
27499
|
+
}
|
|
27500
|
+
let out = "";
|
|
27501
|
+
for (let i = 0; i < input.length; i++) {
|
|
27502
|
+
const ch = input[i];
|
|
27503
|
+
out += map.get(ch) ?? ch;
|
|
27504
|
+
}
|
|
27505
|
+
return out;
|
|
27506
|
+
}
|
|
27507
|
+
expandSyncTrCharSet(spec) {
|
|
27508
|
+
const out = new Set();
|
|
27509
|
+
for (let i = 0; i < spec.length; i++) {
|
|
27510
|
+
if (i + 2 < spec.length && spec[i + 1] === "-") {
|
|
27511
|
+
const start = spec.charCodeAt(i);
|
|
27512
|
+
const end = spec.charCodeAt(i + 2);
|
|
26596
27513
|
if (start <= end && end - start <= 256) {
|
|
26597
27514
|
for (let c = start; c <= end; c++)
|
|
26598
27515
|
out.add(String.fromCharCode(c));
|
|
@@ -26779,35 +27696,11 @@ export class Runtime {
|
|
|
26779
27696
|
sArgs.push(v);
|
|
26780
27697
|
}
|
|
26781
27698
|
if (sName === "cut") {
|
|
26782
|
-
|
|
26783
|
-
for (let ci = 0; ci < sArgs.length; ci++) {
|
|
26784
|
-
const ca = sArgs[ci];
|
|
26785
|
-
if ((ca === "-d" || ca === "-f") && ci + 1 < sArgs.length) {
|
|
26786
|
-
normCut.push(ca + sArgs[++ci]);
|
|
26787
|
-
}
|
|
26788
|
-
else {
|
|
26789
|
-
normCut.push(ca);
|
|
26790
|
-
}
|
|
26791
|
-
}
|
|
26792
|
-
sArgs.length = 0;
|
|
26793
|
-
for (let ci = 0; ci < normCut.length; ci++)
|
|
26794
|
-
sArgs.push(normCut[ci]);
|
|
26795
|
-
const validCut2 = sArgs.length === 2 && ((sArgs[0].length === 3 && sArgs[0].startsWith("-d") && sArgs[1].length >= 3 && sArgs[1].startsWith("-f")) || (sArgs[0] === "-c" && /^[1-9][0-9]*-[1-9][0-9]*$/.test(sArgs[1])));
|
|
26796
|
-
const validCut1 = sArgs.length === 1 && sArgs[0].length >= 3 && sArgs[0].startsWith("-f");
|
|
26797
|
-
if (!validCut2 && !validCut1)
|
|
27699
|
+
if (this.evalSyncCut([], sArgs, byteLocale(rawState.variables)) === undefined)
|
|
26798
27700
|
return undefined;
|
|
26799
|
-
if (sArgs[0] === "-c") {
|
|
26800
|
-
if (byteLocale(rawState.variables))
|
|
26801
|
-
return undefined;
|
|
26802
|
-
const [start, end] = sArgs[1].split("-").map(Number);
|
|
26803
|
-
if (!Number.isSafeInteger(start) || !Number.isSafeInteger(end) || start > end)
|
|
26804
|
-
return undefined;
|
|
26805
|
-
}
|
|
26806
27701
|
}
|
|
26807
27702
|
else if (sName === "tr") {
|
|
26808
|
-
|
|
26809
|
-
const validTr3 = sArgs.length === 3 && (sArgs[0] === "-ds" || sArgs[0] === "-sd" || sArgs[0] === "-s") && !sArgs[1].startsWith("-") && !sArgs[2].startsWith("-");
|
|
26810
|
-
if (!validTr2 && !validTr3)
|
|
27703
|
+
if (this.evalSyncTr("", sArgs) === undefined)
|
|
26811
27704
|
return undefined;
|
|
26812
27705
|
}
|
|
26813
27706
|
else if (sName === "uniq") {
|
|
@@ -26815,16 +27708,20 @@ export class Runtime {
|
|
|
26815
27708
|
return undefined;
|
|
26816
27709
|
}
|
|
26817
27710
|
else if (sName === "sort") {
|
|
26818
|
-
if (sArgs.length > 1 || (sArgs.length === 1 && sArgs[0] !== "-r"))
|
|
27711
|
+
if (sArgs.length > 1 || (sArgs.length === 1 && sArgs[0] !== "-r" && sArgs[0] !== "-u" && sArgs[0] !== "-n" && sArgs[0] !== "-rn" && sArgs[0] !== "-nr" && sArgs[0] !== "-ru" && sArgs[0] !== "-ur"))
|
|
26819
27712
|
return undefined;
|
|
26820
27713
|
}
|
|
26821
27714
|
else if (sName === "head" || sName === "tail") {
|
|
26822
|
-
if (sArgs.length ===
|
|
26823
|
-
|
|
27715
|
+
if (sArgs.length === 0) {
|
|
27716
|
+
sArgs.push("-n", "10");
|
|
27717
|
+
}
|
|
27718
|
+
else if (sArgs.length === 1 && /^-(?:n|c)?[0-9]+$/.test(sArgs[0])) {
|
|
27719
|
+
const flag = sArgs[0].startsWith("-c") ? "-c" : "-n";
|
|
27720
|
+
const numStr = (sArgs[0].startsWith("-n") || sArgs[0].startsWith("-c")) ? sArgs[0].slice(2) : sArgs[0].slice(1);
|
|
26824
27721
|
sArgs.length = 0;
|
|
26825
|
-
sArgs.push(
|
|
27722
|
+
sArgs.push(flag, numStr);
|
|
26826
27723
|
}
|
|
26827
|
-
if (sArgs.length !== 2 || sArgs[0] !== "-n" || !/^[0-9]+$/.test(sArgs[1]))
|
|
27724
|
+
if (sArgs.length !== 2 || (sArgs[0] !== "-n" && sArgs[0] !== "-c") || !/^[0-9]+$/.test(sArgs[1]))
|
|
26828
27725
|
return undefined;
|
|
26829
27726
|
}
|
|
26830
27727
|
else if (sName === "wc") {
|
|
@@ -26832,9 +27729,7 @@ export class Runtime {
|
|
|
26832
27729
|
return undefined;
|
|
26833
27730
|
}
|
|
26834
27731
|
else if (sName === "sed") {
|
|
26835
|
-
|
|
26836
|
-
const validSed2 = sArgs.length === 2 && sArgs[0] === "-e" && sArgs[1].startsWith("s");
|
|
26837
|
-
if (!validSed1 && !validSed2)
|
|
27732
|
+
if (this.evalSyncSed([], sArgs) === undefined)
|
|
26838
27733
|
return undefined;
|
|
26839
27734
|
}
|
|
26840
27735
|
else if (sName === "rev") {
|
|
@@ -26842,23 +27737,15 @@ export class Runtime {
|
|
|
26842
27737
|
return undefined;
|
|
26843
27738
|
}
|
|
26844
27739
|
else if (sName === "awk") {
|
|
26845
|
-
if (
|
|
26846
|
-
sArgs.splice(0, 2, "-F" + sArgs[1]);
|
|
26847
|
-
}
|
|
26848
|
-
const awkSepOk = sArgs.length === 1 || (sArgs.length === 2 && sArgs[0].length === 3 && sArgs[0].startsWith("-F") && sArgs[0][2] !== "\\");
|
|
26849
|
-
const awkProg = sArgs[sArgs.length - 1] ?? "";
|
|
26850
|
-
if (!awkSepOk || !/^\s*\{\s*print(?:\s+(\$(?:[0-9]+|NF)(?:\s*,\s*\$(?:[0-9]+|NF))*))?\s*;?\s*\}\s*$/.test(awkProg))
|
|
27740
|
+
if (this.evalSyncAwk([], sArgs) === undefined)
|
|
26851
27741
|
return undefined;
|
|
26852
27742
|
}
|
|
26853
27743
|
else if (sName === "grep") {
|
|
26854
|
-
|
|
26855
|
-
(sArgs.length === 2 && (sArgs[0] === "-v" || sArgs[0] === "-i" || sArgs[0] === "-c" || sArgs[0] === "-F") && /^[a-zA-Z0-9_ :;,/-]+$/.test(sArgs[1]));
|
|
26856
|
-
if (!grepOk)
|
|
27744
|
+
if (this.evalSyncGrep([], sArgs, Boolean(rawState.errexit)) === undefined)
|
|
26857
27745
|
return undefined;
|
|
26858
27746
|
}
|
|
26859
27747
|
else if (sName === "jq") {
|
|
26860
|
-
|
|
26861
|
-
if (!jqFilter || !/^\.[a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*$/.test(jqFilter))
|
|
27748
|
+
if (this.evalSyncJq("null", sArgs) === undefined)
|
|
26862
27749
|
return undefined;
|
|
26863
27750
|
}
|
|
26864
27751
|
else if (sName === "base64") {
|
|
@@ -26948,23 +27835,17 @@ export class Runtime {
|
|
|
26948
27835
|
const extDef = stageDefs[sIdx];
|
|
26949
27836
|
const stageArgs = stageArgsList[sIdx];
|
|
26950
27837
|
const nextBuf = (index & 1) === 0 ? sharedSyncPipeBuf0 : sharedSyncPipeBuf1;
|
|
26951
|
-
const isInlineCutField = firstName === "cut"
|
|
26952
|
-
|
|
26953
|
-
const isInlineTr = firstName === "tr" && stageArgs.length === 2 && ((stageArgs[0] === "a-z" && stageArgs[1] === "A-Z") ||
|
|
26954
|
-
(stageArgs[0] === "A-Z" && stageArgs[1] === "a-z") ||
|
|
26955
|
-
(stageArgs[0] === "-d" && /^[a-zA-Z0-9_ :;,./-]+$/.test(stageArgs[1])) ||
|
|
26956
|
-
(stageArgs[0] === "-s" && stageArgs[1].length === 1));
|
|
27838
|
+
const isInlineCutField = firstName === "cut";
|
|
27839
|
+
const isInlineTr = firstName === "tr";
|
|
26957
27840
|
const isInlineAwk = firstName === "awk";
|
|
26958
27841
|
const isInlineGrep = firstName === "grep";
|
|
26959
27842
|
const isInlineJq = firstName === "jq";
|
|
26960
27843
|
const isInlineBase64 = firstName === "base64";
|
|
26961
27844
|
const isInlineTac = firstName === "tac";
|
|
26962
27845
|
const isInlineNl = firstName === "nl";
|
|
26963
|
-
const isInlineSort = firstName === "sort" && !byteLocale(rawState.variables) && (stageArgs.length === 0 || (stageArgs.length === 1 && stageArgs[0] === "-r"));
|
|
26964
|
-
const isInlineUniq = firstName === "uniq" && (stageArgs.length === 0 || (stageArgs.length === 1 && (stageArgs[0] === "-d" || stageArgs[0] === "-u")));
|
|
26965
|
-
const inlineSedMatch = firstName === "sed"
|
|
26966
|
-
? /^s\/([a-zA-Z0-9_ :;,-]+)\/([a-zA-Z0-9_ :;,./-]*)\/(g?)$/.exec(stageArgs.length === 1 ? stageArgs[0] : (stageArgs.length === 2 && stageArgs[0] === "-e" ? stageArgs[1] : ""))
|
|
26967
|
-
: null;
|
|
27846
|
+
const isInlineSort = firstName === "sort" && !byteLocale(rawState.variables) && (stageArgs.length === 0 || (stageArgs.length === 1 && (stageArgs[0] === "-r" || stageArgs[0] === "-u" || stageArgs[0] === "-n" || stageArgs[0] === "-rn" || stageArgs[0] === "-nr" || stageArgs[0] === "-ru" || stageArgs[0] === "-ur")));
|
|
27847
|
+
const isInlineUniq = firstName === "uniq" && (stageArgs.length === 0 || (stageArgs.length === 1 && (stageArgs[0] === "-d" || stageArgs[0] === "-u" || stageArgs[0] === "-c")));
|
|
27848
|
+
const inlineSedMatch = firstName === "sed";
|
|
26968
27849
|
if (firstName === "rev" ||
|
|
26969
27850
|
firstName === "head" ||
|
|
26970
27851
|
firstName === "tail" ||
|
|
@@ -26974,7 +27855,7 @@ export class Runtime {
|
|
|
26974
27855
|
isInlineTr ||
|
|
26975
27856
|
isInlineSort ||
|
|
26976
27857
|
isInlineUniq ||
|
|
26977
|
-
inlineSedMatch
|
|
27858
|
+
inlineSedMatch ||
|
|
26978
27859
|
isInlineAwk ||
|
|
26979
27860
|
isInlineGrep ||
|
|
26980
27861
|
isInlineJq ||
|
|
@@ -26987,16 +27868,22 @@ export class Runtime {
|
|
|
26987
27868
|
if (firstName === "rev") {
|
|
26988
27869
|
outLines = rawLines.map(l => Array.from(l).reverse().join(""));
|
|
26989
27870
|
}
|
|
26990
|
-
else if (firstName === "head") {
|
|
26991
|
-
|
|
26992
|
-
|
|
26993
|
-
|
|
26994
|
-
|
|
26995
|
-
|
|
26996
|
-
|
|
26997
|
-
|
|
26998
|
-
|
|
26999
|
-
|
|
27871
|
+
else if (firstName === "head" || firstName === "tail") {
|
|
27872
|
+
const count = Number(stageArgs[1]);
|
|
27873
|
+
if (stageArgs[0] === "-c") {
|
|
27874
|
+
const sub = firstName === "head"
|
|
27875
|
+
? prevBuf.subarray(0, Math.min(prevLen, count))
|
|
27876
|
+
: (count === 0 ? prevBuf.subarray(0, 0) : prevBuf.subarray(Math.max(0, prevLen - count), prevLen));
|
|
27877
|
+
const nextTotalBytes = this.budget.bytes + sub.byteLength;
|
|
27878
|
+
if (nextTotalBytes > this.budget.maxOutputBytesSmi && sub.byteLength > this.budget.limits.maxOutputBytes - this.budget.bytes)
|
|
27879
|
+
this.budget.fail("maxOutputBytes");
|
|
27880
|
+
this.budget.bytes = nextTotalBytes;
|
|
27881
|
+
nextBuf.set(sub, 0);
|
|
27882
|
+
prevBuf = nextBuf;
|
|
27883
|
+
prevLen = sub.byteLength;
|
|
27884
|
+
continue;
|
|
27885
|
+
}
|
|
27886
|
+
outLines = firstName === "head" ? rawLines.slice(0, count) : (count === 0 ? [] : rawLines.slice(-count));
|
|
27000
27887
|
}
|
|
27001
27888
|
else if (firstName === "wc") {
|
|
27002
27889
|
if (stageArgs[0] === "-l") {
|
|
@@ -27015,60 +27902,16 @@ export class Runtime {
|
|
|
27015
27902
|
}
|
|
27016
27903
|
}
|
|
27017
27904
|
else if (isInlineCutField) {
|
|
27018
|
-
const
|
|
27019
|
-
|
|
27020
|
-
|
|
27021
|
-
outLines =
|
|
27022
|
-
if (!l.includes(delim))
|
|
27023
|
-
return l;
|
|
27024
|
-
const parts = l.split(delim);
|
|
27025
|
-
const picked = [];
|
|
27026
|
-
for (let fi = 0; fi < fIndices.length; fi++) {
|
|
27027
|
-
const idx = fIndices[fi] - 1;
|
|
27028
|
-
if (idx >= 0 && idx < parts.length)
|
|
27029
|
-
picked.push(parts[idx]);
|
|
27030
|
-
}
|
|
27031
|
-
return picked.join(delim);
|
|
27032
|
-
});
|
|
27905
|
+
const cutRes = this.evalSyncCut(rawLines, stageArgs, byteLocale(rawState.variables));
|
|
27906
|
+
if (cutRes === undefined)
|
|
27907
|
+
return undefined;
|
|
27908
|
+
outLines = cutRes;
|
|
27033
27909
|
}
|
|
27034
27910
|
else if (isInlineTr) {
|
|
27035
|
-
|
|
27036
|
-
if (
|
|
27037
|
-
|
|
27038
|
-
|
|
27039
|
-
else if (stageArgs[0] === "A-Z" && stageArgs[1] === "a-z") {
|
|
27040
|
-
transformed = inStr.replace(/[A-Z]/g, ch => String.fromCharCode(ch.charCodeAt(0) + 32));
|
|
27041
|
-
}
|
|
27042
|
-
else if (stageArgs[0] === "-s") {
|
|
27043
|
-
const sq = stageArgs[1];
|
|
27044
|
-
let out = "";
|
|
27045
|
-
let prevSq = false;
|
|
27046
|
-
for (let ci = 0; ci < inStr.length; ci++) {
|
|
27047
|
-
const ch = inStr[ci];
|
|
27048
|
-
if (ch === sq) {
|
|
27049
|
-
if (!prevSq) {
|
|
27050
|
-
out += ch;
|
|
27051
|
-
prevSq = true;
|
|
27052
|
-
}
|
|
27053
|
-
}
|
|
27054
|
-
else {
|
|
27055
|
-
out += ch;
|
|
27056
|
-
prevSq = false;
|
|
27057
|
-
}
|
|
27058
|
-
}
|
|
27059
|
-
transformed = out;
|
|
27060
|
-
}
|
|
27061
|
-
else if (stageArgs[0] === "-d") {
|
|
27062
|
-
const delSet = this.expandSyncTrCharSet(stageArgs[1]);
|
|
27063
|
-
let out = "";
|
|
27064
|
-
for (let ci = 0; ci < inStr.length; ci++) {
|
|
27065
|
-
const ch = inStr[ci];
|
|
27066
|
-
if (!delSet.has(ch))
|
|
27067
|
-
out += ch;
|
|
27068
|
-
}
|
|
27069
|
-
transformed = out;
|
|
27070
|
-
}
|
|
27071
|
-
const outByteLen = transformed.length * 3 > 127 ? shellValueByteLength(transformed) : transformed.length;
|
|
27911
|
+
const transformed = this.evalSyncTr(inStr, stageArgs);
|
|
27912
|
+
if (transformed === undefined)
|
|
27913
|
+
return undefined;
|
|
27914
|
+
const outByteLen = shellValueByteLength(transformed);
|
|
27072
27915
|
if (outByteLen > nextBuf.byteLength)
|
|
27073
27916
|
return undefined;
|
|
27074
27917
|
const nextTotalBytes = this.budget.bytes + outByteLen;
|
|
@@ -27081,8 +27924,7 @@ export class Runtime {
|
|
|
27081
27924
|
continue;
|
|
27082
27925
|
}
|
|
27083
27926
|
else if (isInlineSort) {
|
|
27084
|
-
|
|
27085
|
-
outLines = [...rawLines].sort((a, b) => (a < b ? (revSort ? 1 : -1) : a > b ? (revSort ? -1 : 1) : 0));
|
|
27927
|
+
outLines = this.sortSyncLines(rawLines, stageArgs[0]);
|
|
27086
27928
|
}
|
|
27087
27929
|
else if (isInlineUniq) {
|
|
27088
27930
|
const mode = stageArgs[0];
|
|
@@ -27094,69 +27936,31 @@ export class Runtime {
|
|
|
27094
27936
|
uEnd++;
|
|
27095
27937
|
const count = uEnd - uIdx;
|
|
27096
27938
|
if (mode === "-d" ? count > 1 : mode === "-u" ? count === 1 : true) {
|
|
27097
|
-
outLines.push(rawLines[uIdx]);
|
|
27939
|
+
outLines.push(mode === "-c" ? `${String(count).padStart(7, " ")} ${rawLines[uIdx]}` : rawLines[uIdx]);
|
|
27098
27940
|
}
|
|
27099
27941
|
uIdx = uEnd;
|
|
27100
27942
|
}
|
|
27101
27943
|
}
|
|
27102
|
-
else if (inlineSedMatch
|
|
27103
|
-
const
|
|
27104
|
-
|
|
27105
|
-
|
|
27106
|
-
outLines =
|
|
27944
|
+
else if (inlineSedMatch) {
|
|
27945
|
+
const sedRes = this.evalSyncSed(rawLines, stageArgs);
|
|
27946
|
+
if (sedRes === undefined)
|
|
27947
|
+
return undefined;
|
|
27948
|
+
outLines = sedRes;
|
|
27107
27949
|
}
|
|
27108
27950
|
else if (isInlineAwk) {
|
|
27109
|
-
const
|
|
27110
|
-
|
|
27111
|
-
const awkM = /^\s*\{\s*print(?:\s+(\$(?:[0-9]+|NF)(?:\s*,\s*\$(?:[0-9]+|NF))*))?\s*;?\s*\}\s*$/.exec(awkProg);
|
|
27112
|
-
if (!awkM)
|
|
27951
|
+
const awkRes = this.evalSyncAwk(rawLines, stageArgs);
|
|
27952
|
+
if (awkRes === undefined)
|
|
27113
27953
|
return undefined;
|
|
27114
|
-
|
|
27115
|
-
outLines = [];
|
|
27116
|
-
for (let li = 0; li < rawLines.length; li++) {
|
|
27117
|
-
const l = rawLines[li];
|
|
27118
|
-
if (toks.length === 1 && toks[0] === "0") {
|
|
27119
|
-
outLines.push(l);
|
|
27120
|
-
continue;
|
|
27121
|
-
}
|
|
27122
|
-
let fields;
|
|
27123
|
-
if (awkSep === undefined || awkSep === " ") {
|
|
27124
|
-
const tr = l.replace(/^[ \t]+|[ \t]+$/g, "");
|
|
27125
|
-
fields = tr.length === 0 ? [] : tr.split(/[ \t]+/);
|
|
27126
|
-
}
|
|
27127
|
-
else {
|
|
27128
|
-
fields = l.length === 0 ? [] : l.split(awkSep);
|
|
27129
|
-
}
|
|
27130
|
-
const vals = [];
|
|
27131
|
-
for (let ti = 0; ti < toks.length; ti++) {
|
|
27132
|
-
const tk = toks[ti];
|
|
27133
|
-
if (tk === "0")
|
|
27134
|
-
vals.push(l);
|
|
27135
|
-
else if (tk === "NF")
|
|
27136
|
-
vals.push(fields.length > 0 ? fields[fields.length - 1] : l);
|
|
27137
|
-
else {
|
|
27138
|
-
const idx = Number(tk);
|
|
27139
|
-
vals.push(idx >= 1 && idx <= fields.length ? fields[idx - 1] : "");
|
|
27140
|
-
}
|
|
27141
|
-
}
|
|
27142
|
-
outLines.push(vals.join(" "));
|
|
27143
|
-
}
|
|
27954
|
+
outLines = awkRes;
|
|
27144
27955
|
}
|
|
27145
27956
|
else if (isInlineGrep) {
|
|
27146
|
-
const
|
|
27147
|
-
|
|
27148
|
-
|
|
27149
|
-
|
|
27150
|
-
for (let li = 0; li < rawLines.length; li++) {
|
|
27151
|
-
const l = rawLines[li];
|
|
27152
|
-
const hit = gMode === "-i" ? l.toLowerCase().includes(gPatLower) : l.includes(gPat);
|
|
27153
|
-
if (gMode === "-v" ? !hit : hit)
|
|
27154
|
-
matched.push(l);
|
|
27155
|
-
}
|
|
27156
|
-
stageStatus = matched.length === 0 ? 1 : 0;
|
|
27957
|
+
const grepRes = this.evalSyncGrep(rawLines, stageArgs, Boolean(rawState.errexit));
|
|
27958
|
+
if (grepRes === undefined)
|
|
27959
|
+
return undefined;
|
|
27960
|
+
stageStatus = grepRes.status;
|
|
27157
27961
|
if (stageStatus !== 0)
|
|
27158
27962
|
failureStatus = stageStatus;
|
|
27159
|
-
outLines =
|
|
27963
|
+
outLines = grepRes.lines;
|
|
27160
27964
|
}
|
|
27161
27965
|
else if (isInlineTac) {
|
|
27162
27966
|
if (inStr.length > 0 && !inStr.endsWith("\n"))
|
|
@@ -27199,49 +28003,10 @@ export class Runtime {
|
|
|
27199
28003
|
}
|
|
27200
28004
|
}
|
|
27201
28005
|
else if (isInlineJq) {
|
|
27202
|
-
const
|
|
27203
|
-
|
|
27204
|
-
const trimmedJson = inStr.trim();
|
|
27205
|
-
if (!trimmedJson.startsWith("{") || trimmedJson.includes("\n"))
|
|
27206
|
-
return undefined;
|
|
27207
|
-
let parsedObj;
|
|
27208
|
-
try {
|
|
27209
|
-
parsedObj = JSON.parse(trimmedJson);
|
|
27210
|
-
}
|
|
27211
|
-
catch {
|
|
27212
|
-
return undefined;
|
|
27213
|
-
}
|
|
27214
|
-
if (!parsedObj || typeof parsedObj !== "object" || Array.isArray(parsedObj))
|
|
27215
|
-
return undefined;
|
|
27216
|
-
const keys = filter.slice(1).split(".");
|
|
27217
|
-
let cur = parsedObj;
|
|
27218
|
-
for (let ki = 0; ki < keys.length; ki++) {
|
|
27219
|
-
if (cur === null || cur === undefined || typeof cur !== "object") {
|
|
27220
|
-
cur = undefined;
|
|
27221
|
-
break;
|
|
27222
|
-
}
|
|
27223
|
-
if (Array.isArray(cur))
|
|
27224
|
-
return undefined;
|
|
27225
|
-
cur = Object.hasOwn(cur, keys[ki]) ? cur[keys[ki]] : undefined;
|
|
27226
|
-
}
|
|
27227
|
-
if (cur !== null && cur !== undefined && typeof cur === "object")
|
|
28006
|
+
const jqRes = this.evalSyncJq(inStr.trim(), stageArgs);
|
|
28007
|
+
if (jqRes === undefined)
|
|
27228
28008
|
return undefined;
|
|
27229
|
-
|
|
27230
|
-
if (typeof cur === "string") {
|
|
27231
|
-
if (cur.includes("\n"))
|
|
27232
|
-
return undefined;
|
|
27233
|
-
outLines = [cur];
|
|
27234
|
-
}
|
|
27235
|
-
else if (typeof cur === "number" || typeof cur === "boolean") {
|
|
27236
|
-
outLines = [String(cur)];
|
|
27237
|
-
}
|
|
27238
|
-
else {
|
|
27239
|
-
outLines = ["null"];
|
|
27240
|
-
}
|
|
27241
|
-
}
|
|
27242
|
-
else {
|
|
27243
|
-
outLines = [JSON.stringify(cur ?? null)];
|
|
27244
|
-
}
|
|
28009
|
+
outLines = jqRes;
|
|
27245
28010
|
}
|
|
27246
28011
|
// These filters preserve the terminator of the final selected input line.
|
|
27247
28012
|
const preservesTerminator = firstName === "head" || firstName === "tail" || firstName === "rev" || firstName === "sed";
|
|
@@ -27318,62 +28083,66 @@ export class Runtime {
|
|
|
27318
28083
|
if (pipeline.commands.length !== 1)
|
|
27319
28084
|
return undefined;
|
|
27320
28085
|
let cmd = pipeline.commands[0];
|
|
27321
|
-
if ((cmd.kind === "
|
|
28086
|
+
if ((cmd.kind === "if" || cmd.kind === "case") && this.isPureSyncSubIfOrCase(cmd, rawState)) {
|
|
27322
28087
|
const monitor = stateMonitor(state);
|
|
27323
|
-
if (monitor)
|
|
27324
|
-
|
|
27325
|
-
|
|
27326
|
-
|
|
27327
|
-
|
|
27328
|
-
|
|
27329
|
-
|
|
27330
|
-
|
|
27331
|
-
|
|
27332
|
-
|
|
27333
|
-
|
|
27334
|
-
|
|
27335
|
-
|
|
27336
|
-
|
|
27337
|
-
|
|
27338
|
-
|
|
27339
|
-
|
|
27340
|
-
|
|
27341
|
-
|
|
27342
|
-
|
|
27343
|
-
|
|
27344
|
-
|
|
27345
|
-
|
|
27346
|
-
|
|
27347
|
-
|
|
27348
|
-
|
|
27349
|
-
|
|
27350
|
-
|
|
27351
|
-
|
|
27352
|
-
|
|
27353
|
-
|
|
27354
|
-
|
|
27355
|
-
|
|
27356
|
-
|
|
27357
|
-
|
|
27358
|
-
|
|
27359
|
-
|
|
27360
|
-
|
|
27361
|
-
|
|
27362
|
-
|
|
27363
|
-
|
|
27364
|
-
|
|
27365
|
-
|
|
27366
|
-
|
|
27367
|
-
end--;
|
|
27368
|
-
if (end < str.length)
|
|
27369
|
-
str = str.slice(0, end);
|
|
27370
|
-
return str;
|
|
27371
|
-
}
|
|
27372
|
-
}
|
|
28088
|
+
if (!monitor)
|
|
28089
|
+
return undefined;
|
|
28090
|
+
let selectedBody;
|
|
28091
|
+
if (cmd.kind === "if") {
|
|
28092
|
+
for (const br of cmd.branches) {
|
|
28093
|
+
const bc = br.condition.lists[0].pipelines[0].commands[0];
|
|
28094
|
+
let condOk = false;
|
|
28095
|
+
if (bc.kind === "arithmetic") {
|
|
28096
|
+
condOk = this.evalSyncLoopArithStmt(bc.expression, rawState, io, this._syncArithTouched ?? new Set(), bc.line ?? part.line) === true;
|
|
28097
|
+
}
|
|
28098
|
+
else if (bc.kind === "conditional") {
|
|
28099
|
+
const st = this.tryEvalConditionalSync(bc.expression, rawState, monitor, arrayStore(rawState), io, bc.line ?? part.line);
|
|
28100
|
+
if (st === undefined)
|
|
28101
|
+
return undefined;
|
|
28102
|
+
condOk = st === 0;
|
|
28103
|
+
}
|
|
28104
|
+
else {
|
|
28105
|
+
const bExpr = this.extractPosixBracketCondExpr(bc, rawState, true, br.body);
|
|
28106
|
+
if (!bExpr)
|
|
28107
|
+
return undefined;
|
|
28108
|
+
const st = this.tryEvalConditionalSync(bExpr, rawState, monitor, arrayStore(rawState), io, bc.line ?? part.line);
|
|
28109
|
+
if (st === undefined)
|
|
28110
|
+
return undefined;
|
|
28111
|
+
condOk = st === 0;
|
|
28112
|
+
}
|
|
28113
|
+
if (condOk) {
|
|
28114
|
+
selectedBody = br.body;
|
|
28115
|
+
break;
|
|
28116
|
+
}
|
|
28117
|
+
}
|
|
28118
|
+
if (!selectedBody)
|
|
28119
|
+
selectedBody = cmd.otherwise;
|
|
28120
|
+
}
|
|
28121
|
+
else {
|
|
28122
|
+
const subj = this.fastValueWord(cmd.subject, rawState, io, false, false, false, false, undefined, part.line);
|
|
28123
|
+
if (typeof subj !== "string")
|
|
28124
|
+
return undefined;
|
|
28125
|
+
const work = { remaining: this.budget.limits.maxExpansionBytes, signal: this.signal, exhausted: () => this.budget.fail("maxExpansionBytes") };
|
|
28126
|
+
for (const cl of cmd.clauses) {
|
|
28127
|
+
let matched = false;
|
|
28128
|
+
for (const pw of cl.patterns) {
|
|
28129
|
+
if (pw.plain !== undefined && tryMatchesPatternSync(pw.plain, subj, work, false, false) === true) {
|
|
28130
|
+
matched = true;
|
|
28131
|
+
break;
|
|
27373
28132
|
}
|
|
27374
28133
|
}
|
|
28134
|
+
if (matched) {
|
|
28135
|
+
selectedBody = cl.body;
|
|
28136
|
+
break;
|
|
28137
|
+
}
|
|
27375
28138
|
}
|
|
27376
28139
|
}
|
|
28140
|
+
if (!selectedBody) {
|
|
28141
|
+
rawState.substitutionStatus = 0;
|
|
28142
|
+
rawState.status = 0;
|
|
28143
|
+
return "";
|
|
28144
|
+
}
|
|
28145
|
+
cmd = selectedBody.lists[0].pipelines[0].commands[0];
|
|
27377
28146
|
}
|
|
27378
28147
|
const hasSingleStdinRedir = cmd.kind === "simple" &&
|
|
27379
28148
|
cmd.redirects.length === 1 &&
|
|
@@ -27404,9 +28173,10 @@ export class Runtime {
|
|
|
27404
28173
|
w0Plain === "cut" ||
|
|
27405
28174
|
w0Plain === "wc" ||
|
|
27406
28175
|
w0Plain === "sort" ||
|
|
28176
|
+
w0Plain === "uniq" ||
|
|
27407
28177
|
w0Plain === "tr" ||
|
|
27408
28178
|
(hasSingleHereStringRedir && (w0Plain === "base64" || w0Plain === "rev" || w0Plain === "tac" || w0Plain === "nl"));
|
|
27409
|
-
if (isSingleFileTool && !hasShellFunction(rawState, w0Plain) && this.commands.has(w0Plain)) {
|
|
28179
|
+
if (isSingleFileTool && !hasShellFunction(rawState, w0Plain) && (this.commands.has(w0Plain) || ((w0Plain === "rev" || w0Plain === "tac") && Boolean(this.getExternalCommand(w0Plain))))) {
|
|
27410
28180
|
const allArgs = [];
|
|
27411
28181
|
let fOk = true;
|
|
27412
28182
|
for (let i = 1; i < cmd.words.length; i++) {
|
|
@@ -27454,130 +28224,55 @@ export class Runtime {
|
|
|
27454
28224
|
}
|
|
27455
28225
|
else if ((w0Plain === "head" || w0Plain === "tail") && opArgs.length <= 2) {
|
|
27456
28226
|
let count = opArgs.length === 0 ? 10 : undefined;
|
|
28227
|
+
let byteCount;
|
|
27457
28228
|
if (opArgs.length === 1 && opArgs[0].startsWith("-n") && /^[0-9]{1,5}$/.test(opArgs[0].slice(2)))
|
|
27458
28229
|
count = Number(opArgs[0].slice(2));
|
|
28230
|
+
else if (opArgs.length === 1 && opArgs[0].startsWith("-c") && /^[0-9]{1,5}$/.test(opArgs[0].slice(2)))
|
|
28231
|
+
byteCount = Number(opArgs[0].slice(2));
|
|
27459
28232
|
else if (opArgs.length === 1 && /^-[0-9]{1,5}$/.test(opArgs[0]))
|
|
27460
28233
|
count = Number(opArgs[0].slice(1));
|
|
27461
28234
|
else if (opArgs.length === 2 && opArgs[0] === "-n" && /^[0-9]{1,5}$/.test(opArgs[1]))
|
|
27462
28235
|
count = Number(opArgs[1]);
|
|
28236
|
+
else if (opArgs.length === 2 && opArgs[0] === "-c" && /^[0-9]{1,5}$/.test(opArgs[1]))
|
|
28237
|
+
byteCount = Number(opArgs[1]);
|
|
27463
28238
|
if (count !== undefined) {
|
|
27464
28239
|
const sliced = w0Plain === "head" ? rawLines.slice(0, count) : (count === 0 ? [] : rawLines.slice(-count));
|
|
27465
28240
|
fileRes = sliced.join("\n");
|
|
27466
28241
|
}
|
|
27467
|
-
|
|
27468
|
-
|
|
27469
|
-
|
|
27470
|
-
|
|
27471
|
-
|
|
27472
|
-
try {
|
|
27473
|
-
let cur = JSON.parse(fileStr.trim());
|
|
27474
|
-
const keys = jqFilter.slice(1).split(".");
|
|
27475
|
-
let validJq = true;
|
|
27476
|
-
for (const k of keys) {
|
|
27477
|
-
if (cur !== null && typeof cur === "object" && !Array.isArray(cur)) {
|
|
27478
|
-
cur = cur[k];
|
|
27479
|
-
}
|
|
27480
|
-
else {
|
|
27481
|
-
validJq = false;
|
|
27482
|
-
break;
|
|
27483
|
-
}
|
|
27484
|
-
}
|
|
27485
|
-
if (validJq && cur !== undefined && (cur === null || typeof cur === "string" || typeof cur === "number" || typeof cur === "boolean")) {
|
|
27486
|
-
fileRes = cur === null ? "null" : typeof cur === "string" ? (rawMode ? cur : JSON.stringify(cur)) : String(cur);
|
|
27487
|
-
}
|
|
27488
|
-
}
|
|
27489
|
-
catch { }
|
|
28242
|
+
else if (byteCount !== undefined) {
|
|
28243
|
+
const slicedBytes = w0Plain === "head"
|
|
28244
|
+
? view.subarray(0, Math.min(view.byteLength, byteCount))
|
|
28245
|
+
: (byteCount === 0 ? view.subarray(0, 0) : view.subarray(Math.max(0, view.byteLength - byteCount), view.byteLength));
|
|
28246
|
+
fileRes = sharedSyncPipeDecoder.decode(slicedBytes);
|
|
27490
28247
|
}
|
|
27491
28248
|
}
|
|
27492
|
-
else if (w0Plain === "
|
|
27493
|
-
const
|
|
27494
|
-
|
|
27495
|
-
|
|
27496
|
-
if (normAwk.length === 1)
|
|
27497
|
-
awkProg = normAwk[0];
|
|
27498
|
-
else if (normAwk.length === 2 && normAwk[0].length === 3 && normAwk[0].startsWith("-F") && normAwk[0][2] !== "\\") {
|
|
27499
|
-
awkSep = normAwk[0].slice(2);
|
|
27500
|
-
awkProg = normAwk[1];
|
|
27501
|
-
}
|
|
27502
|
-
const awkM = awkProg ? /^\s*\{\s*print(?:\s+(\$(?:[0-9]+|NF)(?:\s*,\s*\$(?:[0-9]+|NF))*))?\s*;?\s*\}\s*$/.exec(awkProg) : null;
|
|
27503
|
-
if (awkM) {
|
|
27504
|
-
const toks = awkM[1] ? awkM[1].split(",").map(t => t.trim().slice(1)) : ["0"];
|
|
27505
|
-
const outLines = [];
|
|
27506
|
-
for (let li = 0; li < rawLines.length; li++) {
|
|
27507
|
-
const l = rawLines[li];
|
|
27508
|
-
if (toks.length === 1 && toks[0] === "0") {
|
|
27509
|
-
outLines.push(l);
|
|
27510
|
-
}
|
|
27511
|
-
else {
|
|
27512
|
-
const fields = awkSep !== undefined ? (awkSep === " " ? l.trim().split(/\s+/).filter(Boolean) : l.split(awkSep)) : l.trim().split(/\s+/).filter(Boolean);
|
|
27513
|
-
const vals = toks.map(tk => {
|
|
27514
|
-
if (tk === "0")
|
|
27515
|
-
return l;
|
|
27516
|
-
const idx = tk === "NF" ? fields.length : Number(tk);
|
|
27517
|
-
if (idx === 0)
|
|
27518
|
-
return l;
|
|
27519
|
-
return idx >= 1 && idx <= fields.length ? fields[idx - 1] : "";
|
|
27520
|
-
});
|
|
27521
|
-
outLines.push(vals.join(" "));
|
|
27522
|
-
}
|
|
27523
|
-
}
|
|
27524
|
-
fileRes = outLines.join("\n");
|
|
27525
|
-
}
|
|
27526
|
-
}
|
|
27527
|
-
else if (w0Plain === "grep" && !rawState.errexit && (opArgs.length === 1 || opArgs.length === 2)) {
|
|
27528
|
-
const mode = opArgs.length === 2 ? opArgs[0] : "";
|
|
27529
|
-
const pat = opArgs[opArgs.length - 1];
|
|
27530
|
-
if ((opArgs.length === 1 || mode === "-v" || mode === "-i" || mode === "-c" || mode === "-F") && /^[a-zA-Z0-9_ :;,/-]+$/.test(pat)) {
|
|
27531
|
-
const needle = mode === "-i" ? pat.toLowerCase() : pat;
|
|
27532
|
-
const matched = [];
|
|
27533
|
-
for (let li = 0; li < rawLines.length; li++) {
|
|
27534
|
-
const l = rawLines[li];
|
|
27535
|
-
const hay = mode === "-i" ? l.toLowerCase() : l;
|
|
27536
|
-
const ok = hay.includes(needle);
|
|
27537
|
-
if (mode === "-v" ? !ok : ok)
|
|
27538
|
-
matched.push(l);
|
|
27539
|
-
}
|
|
27540
|
-
exitStatus = matched.length > 0 ? 0 : 1;
|
|
27541
|
-
fileRes = mode === "-c" ? String(matched.length) : matched.join("\n");
|
|
27542
|
-
}
|
|
28249
|
+
else if (w0Plain === "jq") {
|
|
28250
|
+
const jqRes = this.evalSyncJq(fileStr.trim(), opArgs);
|
|
28251
|
+
if (jqRes !== undefined)
|
|
28252
|
+
fileRes = jqRes.join("\n");
|
|
27543
28253
|
}
|
|
27544
|
-
else if (w0Plain === "
|
|
27545
|
-
const
|
|
27546
|
-
|
|
27547
|
-
|
|
27548
|
-
const pat = sedM[1];
|
|
27549
|
-
const rep = sedM[2];
|
|
27550
|
-
const isGlobal = sedM[3] === "g";
|
|
27551
|
-
fileRes = rawLines.map(l => (isGlobal ? l.split(pat).join(rep) : l.replace(pat, () => rep))).join("\n");
|
|
27552
|
-
}
|
|
28254
|
+
else if (w0Plain === "awk") {
|
|
28255
|
+
const awkRes = this.evalSyncAwk(rawLines, opArgs);
|
|
28256
|
+
if (awkRes !== undefined)
|
|
28257
|
+
fileRes = awkRes.join("\n");
|
|
27553
28258
|
}
|
|
27554
|
-
else if (w0Plain === "
|
|
27555
|
-
const
|
|
27556
|
-
|
|
27557
|
-
|
|
27558
|
-
|
|
27559
|
-
normCut.push(ca + opArgs[++ci]);
|
|
27560
|
-
else
|
|
27561
|
-
normCut.push(ca);
|
|
27562
|
-
}
|
|
27563
|
-
if (normCut.length === 2 && normCut[0] === "-c" && /^[1-9][0-9]*-[1-9][0-9]*$/.test(normCut[1])) {
|
|
27564
|
-
const [cStart, cEnd] = normCut[1].split("-").map(Number);
|
|
27565
|
-
fileRes = rawLines.map(l => Array.from(l).slice(cStart - 1, cEnd).join("")).join("\n");
|
|
27566
|
-
}
|
|
27567
|
-
else {
|
|
27568
|
-
const delim = normCut.length === 2 && normCut[0].length === 3 && normCut[0].startsWith("-d") ? normCut[0][2] : (normCut.length === 1 ? "\t" : undefined);
|
|
27569
|
-
const fSpec = normCut.length === 2 ? normCut[1] : normCut[0];
|
|
27570
|
-
if (delim !== undefined && fSpec && fSpec.startsWith("-f") && /^[1-9][0-9]*(?:,[1-9][0-9]*)*$/.test(fSpec.slice(2))) {
|
|
27571
|
-
const fIdxs = fSpec.slice(2).split(",").map(s => Number(s) - 1);
|
|
27572
|
-
fileRes = rawLines.map(l => {
|
|
27573
|
-
if (!l.includes(delim))
|
|
27574
|
-
return l;
|
|
27575
|
-
const parts = l.split(delim);
|
|
27576
|
-
return fIdxs.map(idx => (idx < parts.length ? parts[idx] : "")).join(delim);
|
|
27577
|
-
}).join("\n");
|
|
27578
|
-
}
|
|
28259
|
+
else if (w0Plain === "grep") {
|
|
28260
|
+
const grepRes = this.evalSyncGrep(rawLines, opArgs, Boolean(rawState.errexit));
|
|
28261
|
+
if (grepRes !== undefined) {
|
|
28262
|
+
exitStatus = grepRes.status;
|
|
28263
|
+
fileRes = grepRes.lines.join("\n");
|
|
27579
28264
|
}
|
|
27580
28265
|
}
|
|
28266
|
+
else if (w0Plain === "sed") {
|
|
28267
|
+
const sedRes = this.evalSyncSed(rawLines, opArgs);
|
|
28268
|
+
if (sedRes !== undefined)
|
|
28269
|
+
fileRes = sedRes.join("\n");
|
|
28270
|
+
}
|
|
28271
|
+
else if (w0Plain === "cut") {
|
|
28272
|
+
const cutRes = this.evalSyncCut(rawLines, opArgs, byteLocale(rawState.variables));
|
|
28273
|
+
if (cutRes !== undefined)
|
|
28274
|
+
fileRes = cutRes.join("\n");
|
|
28275
|
+
}
|
|
27581
28276
|
else if (w0Plain === "wc" && opArgs.length === 1 && (opArgs[0] === "-l" || opArgs[0] === "-c" || opArgs[0] === "-w")) {
|
|
27582
28277
|
let count = 0;
|
|
27583
28278
|
if (opArgs[0] === "-l") {
|
|
@@ -27594,44 +28289,27 @@ export class Runtime {
|
|
|
27594
28289
|
}
|
|
27595
28290
|
fileRes = (hasSingleStdinRedir || hasSingleHereStringRedir) ? String(count) : `${count} ${fileArg}`;
|
|
27596
28291
|
}
|
|
27597
|
-
else if (w0Plain === "sort" && !byteLocale(rawState.variables) && (opArgs.length === 0 || (opArgs.length === 1 && opArgs[0] === "-r"))) {
|
|
27598
|
-
|
|
27599
|
-
|
|
27600
|
-
|
|
27601
|
-
|
|
27602
|
-
|
|
27603
|
-
|
|
27604
|
-
|
|
27605
|
-
|
|
27606
|
-
|
|
27607
|
-
|
|
27608
|
-
|
|
27609
|
-
|
|
27610
|
-
|
|
27611
|
-
if (!delSet.has(ch))
|
|
27612
|
-
out += ch;
|
|
27613
|
-
}
|
|
27614
|
-
fileRes = out;
|
|
27615
|
-
}
|
|
27616
|
-
else if (opArgs[0] === "-s" && opArgs[1].length === 1) {
|
|
27617
|
-
const sq = opArgs[1];
|
|
27618
|
-
let out = "";
|
|
27619
|
-
let prevSq = false;
|
|
27620
|
-
for (let ci = 0; ci < fileStr.length; ci++) {
|
|
27621
|
-
const ch = fileStr[ci];
|
|
27622
|
-
if (ch === sq) {
|
|
27623
|
-
if (!prevSq) {
|
|
27624
|
-
out += ch;
|
|
27625
|
-
prevSq = true;
|
|
27626
|
-
}
|
|
27627
|
-
}
|
|
27628
|
-
else {
|
|
27629
|
-
out += ch;
|
|
27630
|
-
prevSq = false;
|
|
27631
|
-
}
|
|
28292
|
+
else if (w0Plain === "sort" && !byteLocale(rawState.variables) && (opArgs.length === 0 || (opArgs.length === 1 && (opArgs[0] === "-r" || opArgs[0] === "-u" || opArgs[0] === "-n" || opArgs[0] === "-rn" || opArgs[0] === "-nr" || opArgs[0] === "-ru" || opArgs[0] === "-ur")))) {
|
|
28293
|
+
fileRes = this.sortSyncLines(rawLines, opArgs[0]).join("\n");
|
|
28294
|
+
}
|
|
28295
|
+
else if (w0Plain === "uniq" && (opArgs.length === 0 || (opArgs.length === 1 && (opArgs[0] === "-d" || opArgs[0] === "-u" || opArgs[0] === "-c")))) {
|
|
28296
|
+
const mode = opArgs[0];
|
|
28297
|
+
const outLines = [];
|
|
28298
|
+
let uIdx = 0;
|
|
28299
|
+
while (uIdx < rawLines.length) {
|
|
28300
|
+
let uEnd = uIdx + 1;
|
|
28301
|
+
while (uEnd < rawLines.length && rawLines[uEnd] === rawLines[uIdx])
|
|
28302
|
+
uEnd++;
|
|
28303
|
+
const count = uEnd - uIdx;
|
|
28304
|
+
if (mode === "-d" ? count > 1 : mode === "-u" ? count === 1 : true) {
|
|
28305
|
+
outLines.push(mode === "-c" ? `${String(count).padStart(7, " ")} ${rawLines[uIdx]}` : rawLines[uIdx]);
|
|
27632
28306
|
}
|
|
27633
|
-
|
|
28307
|
+
uIdx = uEnd;
|
|
27634
28308
|
}
|
|
28309
|
+
fileRes = outLines.join("\n");
|
|
28310
|
+
}
|
|
28311
|
+
else if (w0Plain === "tr" && (hasSingleStdinRedir || hasSingleHereStringRedir)) {
|
|
28312
|
+
fileRes = this.evalSyncTr(fileStr, opArgs);
|
|
27635
28313
|
}
|
|
27636
28314
|
else if (hasSingleHereStringRedir && w0Plain === "base64" && (opArgs.length === 0 || (opArgs.length === 1 && (opArgs[0] === "-d" || opArgs[0] === "--decode")))) {
|
|
27637
28315
|
if (opArgs.length === 0)
|