@poe-platform/safe-bash 0.1.745 → 0.1.747
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 -1
- package/dist/image-ast/browser/sharp.d.ts +1 -1
- package/dist/image-ast/index.js +133 -35
- package/dist/image-ast/sharp.d.ts +1 -1
- package/dist/safe-bash/chunks/{chunk-2F7Q532M.js → chunk-4GK4FAT6.js} +3 -3
- package/dist/safe-bash/chunks/{chunk-EAUCLWEZ.js → chunk-55AGFLG5.js} +540 -284
- package/dist/safe-bash/chunks/{chunk-WCNFCN2G.js → chunk-BS6QFRNX.js} +2 -2
- package/dist/safe-bash/chunks/{chunk-IZZ7KX4E.js → chunk-JCXAGOEK.js} +40 -3
- package/dist/safe-bash/chunks/{chunk-I3DOFJSJ.js → chunk-MUWJPSGN.js} +2 -2
- package/dist/safe-bash/chunks/{chunk-7RP6WOWK.js → chunk-OF2PDE3W.js} +2 -2
- package/dist/safe-bash/chunks/{src-FTMTU65U.js → src-T672TQJC.js} +2 -2
- package/dist/safe-bash/command-chunks/{chunk-DRCPJVZF.js → chunk-44N2IRVP.js} +17 -5
- package/dist/safe-bash/command-chunks/{chunk-LYKC7WJB.js → chunk-6742OVAC.js} +37 -3
- package/dist/safe-bash/command-chunks/{chunk-BMBXSLVX.js → chunk-6QU5OLPJ.js} +2 -2
- package/dist/safe-bash/command-chunks/{chunk-YHANNN7I.js → chunk-S3BO2NJT.js} +7 -0
- package/dist/safe-bash/commands/basic.d.ts +2 -0
- package/dist/safe-bash/commands/basic.js +236 -9
- package/dist/safe-bash/commands/pr/index.browser.js +1 -1
- package/dist/safe-bash/commands/streams.js +9 -56
- package/dist/safe-bash/commands/table-text/index.js +5 -1
- package/dist/safe-bash/commands/text.js +13 -2
- package/dist/safe-bash/commands/time-env/shared.js +2 -2
- package/dist/safe-bash/commands/time-env/sleep.js +6 -4
- package/dist/safe-bash/commands/timeout/index.d.ts +7 -0
- package/dist/safe-bash/commands/timeout/index.js +52 -32
- package/dist/safe-bash/commands/timeout/scheduler.js +7 -6
- package/dist/safe-bash/core.browser.js +2698 -543
- package/dist/safe-bash/opt-in/commands/shuf/random.js +2 -3
- package/dist/safe-bash/opt-in/shell/extensions/read/index.js +1 -1
- package/dist/safe-bash/opt-in/shell/extensions/trap/index.d.ts +1 -2
- package/dist/safe-bash/opt-in/shell/extensions/trap/index.js +1 -8
- package/dist/safe-bash/playwright/adapter.d.ts +2 -0
- package/dist/safe-bash/playwright/private-target-transport.d.ts +1 -0
- package/dist/safe-bash/playwright/private-target-transport.js +21 -21
- package/dist/safe-bash/shell/runtime.d.ts +20 -1
- package/dist/safe-bash/shell/runtime.js +3021 -532
- package/dist/safe-bash/shell/sync-jq-expression.d.ts +6 -0
- package/dist/safe-bash/shell/sync-jq-expression.js +46 -0
- package/dist/safe-bash-command-cal/index.js +32 -12
- package/dist/safe-bash-command-hostname/index.js +22 -7
- package/dist/safe-bash-command-id/index.js +28 -9
- package/dist/safe-bash-command-pandoc/command.js +1 -1
- package/dist/safe-bash-command-pandoc/index.js +1 -1
- package/dist/safe-bash-command-ssconvert/command.d.ts +2 -2
- package/dist/safe-bash-command-ssconvert/contracts.d.ts +4 -0
- package/dist/safe-bash-command-ssconvert/engine.d.ts +2 -2
- package/dist/safe-bash-command-ssconvert/index.js +524 -276
- package/dist/safe-bash-command-whoami/index.js +26 -12
- package/dist/safe-bash-query-engine/index.js +3 -3
- package/dist/safe-bash-query-engine/interpreter.js +1 -1
- package/dist/safe-bash-query-engine/parser.js +1 -1
- package/dist/safe-bash-query-engine/query-core.js +3 -3
- package/dist/safe-playwright-cloudflare/browser-private-transport.js +8 -13
- package/dist/safe-playwright-cloudflare/browser-storage-control.js +13 -4
- package/dist/safe-playwright-cloudflare/browser-trace-archive.js +1 -1
- package/package.json +18 -14
- package/dist/image-ast/streams/node.d.ts +0 -10
- package/dist/image-ast/streams/node.js +0 -5
- package/dist/image-ast/streams/web.js +0 -94
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { splitSyncJqExpression } from "./sync-jq-expression.js";
|
|
2
|
+
import { wcDisplayWidth } from "../commands/wc-width.js";
|
|
3
|
+
import { text as awkValueText, compare as awkCompare, inputValue as awkInputValue, numeric as awkNumeric, string as awkString } from "../commands/text-programs/awk-values.js";
|
|
1
4
|
import { bytesToHex, latin1Text } from "../byte-encoding.js";
|
|
2
5
|
const sharedCaptureDecoder = new TextDecoder();
|
|
3
6
|
const cachedCaptureAsciiBytes = new Uint8Array(4096);
|
|
@@ -10,6 +13,8 @@ import { writeDiagnostic } from "../escaping.js";
|
|
|
10
13
|
import { cancelTurn, hasYieldCheckpoint, inheritYieldCheckpoint, monotonicNow, registerInternalYieldCheckpoint, runYieldCheckpoint, scheduleTurn, yieldTurn } from "../contracts/yield.js";
|
|
11
14
|
import { ACCESS_MODES, FsError, basename, composeMiddleware, createBytePipe, dirname, normalizePath, pipeBytes, resolvePath, validateExitCode, writeBytes, writeText, } from "../contracts/index.js";
|
|
12
15
|
import { createBcCommands } from "../commands/bc/index.js";
|
|
16
|
+
import { createStreamInspectionCommands } from "../commands/stream-inspection/index.js";
|
|
17
|
+
import { createStreamFormatCommands } from "../commands/stream-format/index.js";
|
|
13
18
|
import { createSpongeCommands } from "../commands/sponge/index.js";
|
|
14
19
|
import { createFdCommands } from "../commands/fd/index.js";
|
|
15
20
|
import { createLessCommands } from "../commands/less/index.js";
|
|
@@ -57,7 +62,7 @@ import { invocationScope, throwCleanupFailures, InvocationScope } from "./cleanu
|
|
|
57
62
|
import { bindFileOutputBudget, openFileOutput } from "../contracts/filesystem-output.js";
|
|
58
63
|
import { outputFailure } from "../contracts/io.js";
|
|
59
64
|
import { executionCommands } from "../commands/execution.js";
|
|
60
|
-
import { defaultEchoExecutors, formatPrintf, printfCommand, tryFastPrintf } from "../commands/basic.js";
|
|
65
|
+
import { defaultEchoExecutors, extractFastPrintfSpecifiers, formatPrintf, printfCommand, tryFastPrintf } from "../commands/basic.js";
|
|
61
66
|
import { defaultMkdirExecutors, defaultRmExecutors } from "../commands/filesystem.js";
|
|
62
67
|
export const customRegisteredCommands = new WeakSet();
|
|
63
68
|
export const customRegisteredRegistries = new WeakSet();
|
|
@@ -2617,6 +2622,12 @@ const closedSource = { [Symbol.asyncIterator]() {
|
|
|
2617
2622
|
return iterator;
|
|
2618
2623
|
} };
|
|
2619
2624
|
/** Internal to the shell/runtime pair; it is not exported by the package root. */
|
|
2625
|
+
const syncAwkArithAtom = `(?:\\$(?:[0-9]+|NF)|NR|NF|-?[0-9]+(?:\\.[0-9]+)?|[a-zA-Z_][a-zA-Z0-9_]*)`;
|
|
2626
|
+
const syncAwkArithPat = `(?:${syncAwkArithAtom}(?:\\s*[+*\\/%-]\\s*${syncAwkArithAtom})+)`;
|
|
2627
|
+
const syncAwkTernaryPat = `(?:(?:\\$(?:[0-9]+|NF)|NR|NF)\\s*(?:==|!=|>=|<=|>|<)\\s*(?:-?[0-9]+(?:\\.[0-9]+)?|"[^"$\\\\]*")\\s*\\?\\s*(?:\\$(?:[0-9]+|NF)|"[^"$\\\\]*"|-?[0-9]+(?:\\.[0-9]+)?)\\s*:\\s*(?:\\$(?:[0-9]+|NF)|"[^"$\\\\]*"|-?[0-9]+(?:\\.[0-9]+)?))`;
|
|
2628
|
+
const syncAwkItemPat = `(?:${syncAwkTernaryPat}|int\\(\\$(?:[0-9]+|NF)\\)|(?:toupper|tolower)\\(\\$(?:[0-9]+|NF)\\)|substr\\(\\$(?:[0-9]+|NF)\\s*,\\s*[0-9]+(?:\\s*,\\s*[0-9]+)?\\)|index\\(\\$(?:[0-9]+|NF)\\s*,\\s*"[^"$\\\\]*"\\)|${syncAwkArithPat}|\\$(?:[0-9]+|NF)|\\$\\(NF\\s*-\\s*[0-9]+\\)|length(?:\\(\\$(?:[0-9]+|NF)\\))?|NR|NF|[a-zA-Z_][a-zA-Z0-9_]*|"[^"$\\\\]*")`;
|
|
2629
|
+
const syncAwkPrintRe = new RegExp(`^\\{\\s*(?:(g?sub)\\(\\s*\\/(\\^?[a-zA-Z0-9_ :;,=-]+\\$?)\\/\\s*,\\s*"([^"\\\\]*)"(?:\\s*,\\s*\\$([0-9]+|NF))?\\s*\\)\\s*;\\s*)?(?:print(?:\\s+(${syncAwkItemPat}(?:\\s*,?\\s*${syncAwkItemPat})*))?|printf\\s+"([^"$\\\\]*(?:\\\\[nt\\\\"][^"$\\\\]*)*)"\\s*,\\s*(${syncAwkItemPat}(?:\\s*,\\s*${syncAwkItemPat})*))\\s*;?\\s*\\}\\s*$`);
|
|
2630
|
+
const syncAwkTokenRe = new RegExp(`(${syncAwkTernaryPat})|int\\(\\$([0-9]+|NF)\\)|(toupper|tolower)\\(\\$([0-9]+|NF)\\)|substr\\(\\$([0-9]+|NF)\\s*,\\s*([0-9]+)(?:\\s*,\\s*([0-9]+))?\\)|index\\(\\$([0-9]+|NF)\\s*,\\s*"([^"$\\\\]*)"\\)|(${syncAwkArithPat})|\\$\\(NF\\s*-\\s*([0-9]+)\\)|\\$([0-9]+|NF)|length\\b(?:\\(\\$([0-9]+|NF)\\))?|(NR|NF)\\b|"([^"$\\\\]*)"|([a-zA-Z_][a-zA-Z0-9_]*)|(,)`, "g");
|
|
2620
2631
|
export class RuntimeCancellationState {
|
|
2621
2632
|
_records;
|
|
2622
2633
|
_diagnostics;
|
|
@@ -2916,7 +2927,7 @@ function hasGlobOrEscape(text, extglob = false) {
|
|
|
2916
2927
|
let nextProcessSubstitutionId = 0;
|
|
2917
2928
|
let defaultRuntimeMuscleMemoryMap;
|
|
2918
2929
|
function getRuntimeMuscleMemoryCommand(name) {
|
|
2919
|
-
defaultRuntimeMuscleMemoryMap ??= new Map([...createBcCommands(), ...createSpongeCommands(), ...createFdCommands(), ...createLessCommands(), ...createIdCommands(), ...createWhoamiCommands(), ...createUnameCommands(), ...createHostnameCommands(), ...createNprocCommands(), ...createShufCommands(), ...createDdCommands(), ...createNumfmtCommands(), ...createEnvsubstCommands(), ...createCalCommands(), ...createPathchkCommands(), ...createGetconfCommands(), ...createLocaleCommands(), ...createDfCommands(), ...createSqlite3Commands()].map(cmd => [cmd.name, cmd]));
|
|
2930
|
+
defaultRuntimeMuscleMemoryMap ??= new Map([...createStreamFormatCommands(), ...createStreamInspectionCommands(), ...createBcCommands(), ...createSpongeCommands(), ...createFdCommands(), ...createLessCommands(), ...createIdCommands(), ...createWhoamiCommands(), ...createUnameCommands(), ...createHostnameCommands(), ...createNprocCommands(), ...createShufCommands(), ...createDdCommands(), ...createNumfmtCommands(), ...createEnvsubstCommands(), ...createCalCommands(), ...createPathchkCommands(), ...createGetconfCommands(), ...createLocaleCommands(), ...createDfCommands(), ...createSqlite3Commands()].map(cmd => [cmd.name, cmd]));
|
|
2920
2931
|
return defaultRuntimeMuscleMemoryMap.get(name);
|
|
2921
2932
|
}
|
|
2922
2933
|
const fastSubScratchArgs = [];
|
|
@@ -5902,6 +5913,8 @@ export class Runtime {
|
|
|
5902
5913
|
const entry = assignment.entries[i];
|
|
5903
5914
|
if (entry.append)
|
|
5904
5915
|
return false;
|
|
5916
|
+
if (entry.value.parts.some(p => p.kind === "variable" && p.prefixNames === "@") && !this.canSyncArrayMembersWord(entry.value, rawState))
|
|
5917
|
+
return false;
|
|
5905
5918
|
if (entry.index === undefined && rawState.braceexpand !== false && this.budget.limits.maxExpansionFields === Infinity && this.budget.limits.maxExpansionBytes === Infinity && entry.value.parts.length === 1 && !entry.value.parts[0].quoted && entry.value.parts[0].kind === "text" && entry.value.parts[0].value.includes("{")) {
|
|
5906
5919
|
const braceItems = tryFastExpandBraceRange(entry.value, this.budget, undefined);
|
|
5907
5920
|
if (braceItems && braceItems.length <= 1500) {
|
|
@@ -13572,6 +13585,10 @@ export class Runtime {
|
|
|
13572
13585
|
if (this._syncLoopFnCheckDepth > 0 && (part.substring || getArraySelector(part)?.kind === "element"))
|
|
13573
13586
|
return false;
|
|
13574
13587
|
if (part.prefixNames !== undefined) {
|
|
13588
|
+
// Prefix @ may produce zero or multiple fields as loop state changes.
|
|
13589
|
+
// Scalar loop steps cannot preserve that argument cardinality.
|
|
13590
|
+
if (part.prefixNames === "@")
|
|
13591
|
+
return false;
|
|
13575
13592
|
if (part.indirect ||
|
|
13576
13593
|
part.specialParameter ||
|
|
13577
13594
|
part.length ||
|
|
@@ -13812,6 +13829,10 @@ export class Runtime {
|
|
|
13812
13829
|
}
|
|
13813
13830
|
}
|
|
13814
13831
|
}
|
|
13832
|
+
// These evaluators can decline based on runtime input. Loop execution
|
|
13833
|
+
// has no continuation for a declined substitution after earlier effects.
|
|
13834
|
+
if (w0Plain === "tac" || w0Plain === "nl" || (w0Plain === "base64" && cmd.words.length > 1))
|
|
13835
|
+
return false;
|
|
13815
13836
|
if (w0Plain === "pwd") {
|
|
13816
13837
|
if (p.commands.length === 1 && (cmd.words.length === 1 || (cmd.words.length === 2 && (cmd.words[1]?.plain === "-L" || cmd.words[1]?.plain === "--logical"))) && !rawState.functions.has("pwd") && !rawState.extensions?.builtins.has("pwd"))
|
|
13817
13838
|
continue;
|
|
@@ -13841,13 +13862,13 @@ export class Runtime {
|
|
|
13841
13862
|
w0Plain === "sort" ||
|
|
13842
13863
|
w0Plain === "uniq" ||
|
|
13843
13864
|
w0Plain === "tr" ||
|
|
13844
|
-
(hasSingleHereStringRedir && (w0Plain === "base64" || w0Plain === "rev" || w0Plain === "tac" || w0Plain === "nl"));
|
|
13845
|
-
const def = w0Plain ? (this.commands.get(w0Plain) ?? ((w0Plain === "rev" || w0Plain === "tac") ? this.getExternalCommand(w0Plain) : undefined)) : undefined;
|
|
13865
|
+
(hasSingleHereStringRedir && (w0Plain === "base64" || w0Plain === "rev" || w0Plain === "tac" || w0Plain === "nl" || w0Plain === "paste" || w0Plain === "numfmt"));
|
|
13866
|
+
const def = w0Plain ? (this.commands.get(w0Plain) ?? ((w0Plain === "rev" || w0Plain === "tac" || w0Plain === "nl" || w0Plain === "paste" || w0Plain === "jq") ? this.getExternalCommand(w0Plain) : undefined)) : undefined;
|
|
13846
13867
|
if (!w0Plain || (w0Plain !== "printf" && w0Plain !== "echo" && w0Plain !== "dirname" && w0Plain !== "basename" && w0Plain !== "seq" && !isFileCommand) || !def || rawState.functions.has(w0Plain) || rawState.extensions?.builtins.has(w0Plain))
|
|
13847
13868
|
return false;
|
|
13848
13869
|
if ((hasSingleStdinRedir || hasSingleHereStringRedir) && !isFileCommand)
|
|
13849
13870
|
return false;
|
|
13850
|
-
if (w0Plain === "printf" ? def.execute !== printfCommand.execute : w0Plain === "echo" ? !defaultEchoExecutors.has(def.execute) : (w0Plain === "seq" || w0Plain === "rev" || w0Plain === "tac") ? (!builtInDirectContextExecutors.has(def.execute) &&
|
|
13871
|
+
if (w0Plain === "printf" ? def.execute !== printfCommand.execute : w0Plain === "echo" ? !defaultEchoExecutors.has(def.execute) : (w0Plain === "seq" || w0Plain === "rev" || w0Plain === "tac" || w0Plain === "nl" || w0Plain === "paste" || w0Plain === "jq") ? (!builtInDirectContextExecutors.has(def.execute) && customRegisteredCommands.has(def.execute)) : !builtInDirectContextExecutors.has(def.execute))
|
|
13851
13872
|
return false;
|
|
13852
13873
|
if (!cmd.words.slice(1).every(w => this.isPureSyncValueWord(w, rawState)))
|
|
13853
13874
|
return false;
|
|
@@ -13868,7 +13889,7 @@ export class Runtime {
|
|
|
13868
13889
|
const opCount = opWords.length;
|
|
13869
13890
|
const op0 = opWords[0]?.plain;
|
|
13870
13891
|
const op1 = opWords[1]?.plain;
|
|
13871
|
-
if (w0Plain === "cat" || w0Plain === "rev" || w0Plain === "tac"
|
|
13892
|
+
if (w0Plain === "cat" || w0Plain === "rev" || w0Plain === "tac") {
|
|
13872
13893
|
if (opCount !== 0)
|
|
13873
13894
|
return false;
|
|
13874
13895
|
}
|
|
@@ -13877,8 +13898,8 @@ export class Runtime {
|
|
|
13877
13898
|
return false;
|
|
13878
13899
|
if (w0Plain === "head" || w0Plain === "tail") {
|
|
13879
13900
|
const validHT = opCount === 0 ||
|
|
13880
|
-
(opCount === 1 && op0 !== undefined && /^-(?:n|c)?[0-9]{1,5}$/.test(op0)) ||
|
|
13881
|
-
(opCount === 2 && (op0 === "-n" || op0 === "-c"
|
|
13901
|
+
(opCount === 1 && op0 !== undefined && (/^-(?:n|c|--lines=|--bytes=)?[0-9]{1,5}$/.test(op0) || /^--(?:lines|bytes)=[0-9]{1,5}$/.test(op0) || (w0Plain === "tail" && /^(?:-n|--lines=)\+[0-9]{1,5}$/.test(op0)) || (w0Plain === "head" && /^(?:-n|--lines=)-[0-9]{1,5}$/.test(op0)))) ||
|
|
13902
|
+
(opCount === 2 && ((op0 === "-n" && op1 !== undefined && (/^[0-9]{1,5}$/.test(op1) || (w0Plain === "tail" && /^\+[0-9]{1,5}$/.test(op1)) || (w0Plain === "head" && /^-[0-9]{1,5}$/.test(op1)))) || (op0 === "-c" && op1 !== undefined && /^[0-9]{1,5}$/.test(op1))));
|
|
13882
13903
|
if (!validHT)
|
|
13883
13904
|
return false;
|
|
13884
13905
|
}
|
|
@@ -13891,7 +13912,8 @@ export class Runtime {
|
|
|
13891
13912
|
plainOps.push(pw);
|
|
13892
13913
|
}
|
|
13893
13914
|
if (w0Plain === "cut") {
|
|
13894
|
-
|
|
13915
|
+
// Probe non-ASCII input: loop data can change after admission.
|
|
13916
|
+
if (plainOps.length !== opCount || this.evalSyncCut(["é"], plainOps, byteLocale(rawState.variables)) === undefined)
|
|
13895
13917
|
return false;
|
|
13896
13918
|
}
|
|
13897
13919
|
else if (w0Plain === "sed") {
|
|
@@ -13907,19 +13929,22 @@ export class Runtime {
|
|
|
13907
13929
|
return false;
|
|
13908
13930
|
}
|
|
13909
13931
|
else if (w0Plain === "jq") {
|
|
13910
|
-
if (plainOps.length !== opCount
|
|
13932
|
+
if (plainOps.length !== opCount)
|
|
13933
|
+
return false;
|
|
13934
|
+
const jqIn = this.extractLoopInvariantJqInput(cmd, hasSingleStdinRedir, hasSingleHereStringRedir, rawState);
|
|
13935
|
+
if (jqIn === undefined || this.evalSyncJq(jqIn, plainOps) === undefined)
|
|
13911
13936
|
return false;
|
|
13912
13937
|
}
|
|
13913
13938
|
else if (w0Plain === "wc") {
|
|
13914
|
-
if (opCount !== 1 || (op0
|
|
13939
|
+
if (opCount !== 1 || this.normalizeSyncWcFlag(op0) === undefined)
|
|
13915
13940
|
return false;
|
|
13916
13941
|
}
|
|
13917
13942
|
else if (w0Plain === "sort") {
|
|
13918
|
-
if (
|
|
13943
|
+
if (plainOps.length !== opCount || this.evalSyncSort([], plainOps, byteLocale(rawState.variables)) === undefined)
|
|
13919
13944
|
return false;
|
|
13920
13945
|
}
|
|
13921
13946
|
else if (w0Plain === "uniq") {
|
|
13922
|
-
if (
|
|
13947
|
+
if (plainOps.length !== opCount || this.evalSyncUniq([], plainOps) === undefined)
|
|
13923
13948
|
return false;
|
|
13924
13949
|
}
|
|
13925
13950
|
else if (w0Plain === "base64") {
|
|
@@ -13930,24 +13955,57 @@ export class Runtime {
|
|
|
13930
13955
|
if (plainOps.length !== opCount || this.evalSyncTr("", plainOps) === undefined)
|
|
13931
13956
|
return false;
|
|
13932
13957
|
}
|
|
13958
|
+
else if (w0Plain === "nl") {
|
|
13959
|
+
if (plainOps.length !== opCount || this.evalSyncNl([], plainOps) === undefined)
|
|
13960
|
+
return false;
|
|
13961
|
+
}
|
|
13962
|
+
else if (w0Plain === "paste") {
|
|
13963
|
+
if (plainOps.length !== opCount || this.evalSyncPaste([], plainOps) === undefined)
|
|
13964
|
+
return false;
|
|
13965
|
+
}
|
|
13966
|
+
else if (w0Plain === "numfmt") {
|
|
13967
|
+
const nmCheck = this.extractLoopInvariantJqInput(cmd, hasSingleStdinRedir, hasSingleHereStringRedir, rawState);
|
|
13968
|
+
if (nmCheck === undefined || plainOps.length !== opCount || this.evalSyncNumfmt(nmCheck.split("\n"), plainOps) === undefined)
|
|
13969
|
+
return false;
|
|
13970
|
+
}
|
|
13933
13971
|
}
|
|
13934
13972
|
}
|
|
13935
13973
|
if (w0Plain === "printf") {
|
|
13936
|
-
|
|
13937
|
-
const fmtP = fmtW?.plain ?? (fmtW?.parts.length === 1 && fmtW.parts[0].kind === "text" ? fmtW.parts[0].value : undefined);
|
|
13938
|
-
if (fmtP === undefined || fmtP.startsWith("-") || !/^(?:[^%]|%%|%[-0]*\d*(?:\.\d+)?[sdxXouc]|\\n)*$/.test(fmtP))
|
|
13974
|
+
if (!this.isSyncPrintfCallOk(cmd, 1, rawState, this._activePrintfInductionName))
|
|
13939
13975
|
return false;
|
|
13940
13976
|
}
|
|
13941
13977
|
else if (w0Plain === "echo") {
|
|
13942
|
-
|
|
13943
|
-
|
|
13944
|
-
|
|
13945
|
-
|
|
13946
|
-
|
|
13947
|
-
|
|
13978
|
+
const firstArg = cmd.words[1];
|
|
13979
|
+
if (firstArg) {
|
|
13980
|
+
const prefix = firstArg.parts.find(part => part.kind !== "text" || part.value.length > 0);
|
|
13981
|
+
// Substitution execution rejects options, including those that appear
|
|
13982
|
+
// only on later iterations. Require a stable non-option prefix.
|
|
13983
|
+
if (prefix?.kind !== "text" || prefix.value.startsWith("-"))
|
|
13984
|
+
return false;
|
|
13985
|
+
}
|
|
13948
13986
|
}
|
|
13949
|
-
else if (w0Plain === "basename") {
|
|
13950
|
-
|
|
13987
|
+
else if (w0Plain === "dirname" || w0Plain === "basename") {
|
|
13988
|
+
const simArgs = [];
|
|
13989
|
+
let seenDoubleDash = false;
|
|
13990
|
+
for (let wi = 1; wi < cmd.words.length; wi++) {
|
|
13991
|
+
const w = cmd.words[wi];
|
|
13992
|
+
// Tilde prefixes depend on mutable HOME/PWD/OLDPWD; use normal expansion.
|
|
13993
|
+
if (w.parts[0]?.kind === "text" && !w.parts[0].quoted && w.parts[0].value.startsWith("~"))
|
|
13994
|
+
return false;
|
|
13995
|
+
const st = w.plain ?? (w.parts.length > 0 && w.parts.every(pt => pt.kind === "text") ? w.parts.map(pt => pt.value).join("") : undefined);
|
|
13996
|
+
if (st !== undefined) {
|
|
13997
|
+
if (st === "--")
|
|
13998
|
+
seenDoubleDash = true;
|
|
13999
|
+
simArgs.push(st);
|
|
14000
|
+
}
|
|
14001
|
+
else {
|
|
14002
|
+
// A loop operand can become an option after admission.
|
|
14003
|
+
if (!seenDoubleDash)
|
|
14004
|
+
return false;
|
|
14005
|
+
simArgs.push("x");
|
|
14006
|
+
}
|
|
14007
|
+
}
|
|
14008
|
+
if ((w0Plain === "dirname" ? this.evalSyncDirname(simArgs) : this.evalSyncBasename(simArgs)) === undefined)
|
|
13951
14009
|
return false;
|
|
13952
14010
|
}
|
|
13953
14011
|
else if (w0Plain === "seq") {
|
|
@@ -13971,18 +14029,20 @@ export class Runtime {
|
|
|
13971
14029
|
if (p.commands.length >= 2) {
|
|
13972
14030
|
if ((w0Plain !== "printf" && w0Plain !== "echo" && w0Plain !== "seq" && w0Plain !== "cat" && !hasSingleHereStringRedir) || syncPurePipelineSlotInUse || !this.budget.canSyncPurePipe || rawState.errexit || rawState.nounset)
|
|
13973
14031
|
return false;
|
|
13974
|
-
if (w0Plain === "printf"
|
|
13975
|
-
|
|
14032
|
+
if (w0Plain === "printf") {
|
|
14033
|
+
if (!this.isSyncPrintfCallOk(cmd, 1, rawState, this._activePrintfInductionName))
|
|
14034
|
+
return false;
|
|
14035
|
+
}
|
|
13976
14036
|
for (let sIdx = 1; sIdx < p.commands.length; sIdx++) {
|
|
13977
14037
|
const sCmd = p.commands[sIdx];
|
|
13978
14038
|
if (sCmd.kind !== "simple" || sCmd.redirects.length !== 0 || sCmd.words.length === 0)
|
|
13979
14039
|
return false;
|
|
13980
14040
|
const sName = sCmd.words[0].plain;
|
|
13981
14041
|
// Range-aware tr and Buffer-free 76-col base64 are handled in pipeline stages.
|
|
13982
|
-
if (!sName || (sName !== "cut" && sName !== "tr" && sName !== "sort" && sName !== "head" && sName !== "tail" && sName !== "wc" && sName !== "sed" && sName !== "uniq" && sName !== "rev" && sName !== "awk" && sName !== "grep" && sName !== "jq" && sName !== "base64" && sName !== "tac" && sName !== "nl"))
|
|
14042
|
+
if (!sName || (sName !== "cut" && sName !== "tr" && sName !== "sort" && sName !== "head" && sName !== "tail" && sName !== "wc" && sName !== "sed" && sName !== "uniq" && sName !== "rev" && sName !== "awk" && sName !== "grep" && sName !== "jq" && sName !== "base64" && sName !== "tac" && sName !== "nl" && sName !== "paste" && sName !== "numfmt"))
|
|
13983
14043
|
return false;
|
|
13984
|
-
const sDef = this.commands.get(sName);
|
|
13985
|
-
if (!sDef || customRegisteredCommands.has(sDef.execute) || (sName !== "rev" && sName !== "tac" && !builtInDirectContextExecutors.has(sDef.execute)))
|
|
14044
|
+
const sDef = this.commands.get(sName) ?? ((sName === "rev" || sName === "tac" || sName === "nl" || sName === "paste" || sName === "jq") ? this.getExternalCommand(sName) : undefined);
|
|
14045
|
+
if (!sDef || customRegisteredCommands.has(sDef.execute) || (sName !== "rev" && sName !== "tac" && sName !== "nl" && sName !== "paste" && sName !== "jq" && !builtInDirectContextExecutors.has(sDef.execute)))
|
|
13986
14046
|
return false;
|
|
13987
14047
|
if (rawState.functions.has(sName) || rawState.extensions?.builtins.has(sName))
|
|
13988
14048
|
return false;
|
|
@@ -13991,7 +14051,7 @@ export class Runtime {
|
|
|
13991
14051
|
let allPlainStageArgs = true;
|
|
13992
14052
|
for (let k = 0; k < sArgWords.length; k++) {
|
|
13993
14053
|
const sw = sArgWords[k];
|
|
13994
|
-
const sp = sw.plain ?? (sw.parts.length
|
|
14054
|
+
const sp = sw.plain ?? (sw.parts.length > 0 && sw.parts.every(pt => pt.kind === "text") ? sw.parts.map(pt => pt.value).join("") : undefined);
|
|
13995
14055
|
if (sp === undefined) {
|
|
13996
14056
|
allPlainStageArgs = false;
|
|
13997
14057
|
break;
|
|
@@ -14000,55 +14060,78 @@ export class Runtime {
|
|
|
14000
14060
|
}
|
|
14001
14061
|
if (!allPlainStageArgs)
|
|
14002
14062
|
return false;
|
|
14003
|
-
if (sName === "sort"
|
|
14004
|
-
|
|
14005
|
-
|
|
14006
|
-
|
|
14007
|
-
if (sName === "
|
|
14008
|
-
|
|
14063
|
+
if (sName === "sort") {
|
|
14064
|
+
if (this.evalSyncSort([], sPlainArgs, byteLocale(rawState.variables)) === undefined)
|
|
14065
|
+
return false;
|
|
14066
|
+
}
|
|
14067
|
+
else if (sName === "uniq") {
|
|
14068
|
+
if (this.evalSyncUniq([], sPlainArgs) === undefined)
|
|
14069
|
+
return false;
|
|
14070
|
+
}
|
|
14071
|
+
else if (sName === "wc") {
|
|
14072
|
+
if (sPlainArgs.length !== 1 || this.normalizeSyncWcFlag(sPlainArgs[0]) === undefined)
|
|
14073
|
+
return false;
|
|
14074
|
+
}
|
|
14075
|
+
else if (sName === "head" || sName === "tail") {
|
|
14076
|
+
const okHT = sPlainArgs.length === 0 || (sPlainArgs.length === 1 && (/^-(?:n|c)?[0-9]{1,5}$/.test(sPlainArgs[0]) || /^--(?:lines|bytes)=[0-9]{1,5}$/.test(sPlainArgs[0]) || (sName === "tail" && /^(?:-n|--lines=)\+[0-9]{1,5}$/.test(sPlainArgs[0])) || (sName === "head" && /^(?:-n|--lines=)-[0-9]{1,5}$/.test(sPlainArgs[0])))) || (sPlainArgs.length === 2 && ((sPlainArgs[0] === "-n" && (/^[0-9]{1,5}$/.test(sPlainArgs[1]) || (sName === "tail" && /^\+[0-9]{1,5}$/.test(sPlainArgs[1])) || (sName === "head" && /^-[0-9]{1,5}$/.test(sPlainArgs[1])))) || (sPlainArgs[0] === "-c" && /^[0-9]{1,5}$/.test(sPlainArgs[1]))));
|
|
14009
14077
|
if (!okHT)
|
|
14010
14078
|
return false;
|
|
14011
14079
|
}
|
|
14012
|
-
if (sName === "cut") {
|
|
14013
|
-
|
|
14014
|
-
|
|
14015
|
-
const ca = sPlainArgs[ci];
|
|
14016
|
-
if ((ca === "-d" || ca === "-f") && ci + 1 < sPlainArgs.length) {
|
|
14017
|
-
normCut.push(ca + sPlainArgs[++ci]);
|
|
14018
|
-
}
|
|
14019
|
-
else {
|
|
14020
|
-
normCut.push(ca);
|
|
14021
|
-
}
|
|
14022
|
-
}
|
|
14023
|
-
const vc2 = normCut.length === 2 && ((normCut[0].length === 3 && normCut[0].startsWith("-d") && normCut[1].length >= 3 && normCut[1].startsWith("-f")) || (normCut[0] === "-c" && /^[1-9][0-9]*-[1-9][0-9]*$/.test(normCut[1])));
|
|
14024
|
-
const vc1 = normCut.length === 1 && normCut[0].length >= 3 && normCut[0].startsWith("-f");
|
|
14025
|
-
if (!vc1 && !vc2)
|
|
14080
|
+
else if (sName === "cut") {
|
|
14081
|
+
// Byte cuts may reject non-ASCII data on a later iteration.
|
|
14082
|
+
if (this.evalSyncCut(["é"], sPlainArgs, byteLocale(rawState.variables)) === undefined)
|
|
14026
14083
|
return false;
|
|
14027
14084
|
}
|
|
14028
|
-
if (sName === "
|
|
14029
|
-
|
|
14030
|
-
const awkSepOk = normAwk.length === 1 || (normAwk.length === 2 && normAwk[0].length === 3 && normAwk[0].startsWith("-F") && normAwk[0][2] !== "\\");
|
|
14031
|
-
const awkProg = normAwk[normAwk.length - 1] ?? "";
|
|
14032
|
-
if (!awkSepOk || !/^\s*\{\s*print(?:\s+(\$(?:[0-9]+|NF)(?:\s*,\s*\$(?:[0-9]+|NF))*))?\s*;?\s*\}\s*$/.test(awkProg))
|
|
14085
|
+
else if (sName === "sed") {
|
|
14086
|
+
if (this.evalSyncSed([], sPlainArgs) === undefined)
|
|
14033
14087
|
return false;
|
|
14034
14088
|
}
|
|
14035
|
-
if (sName === "
|
|
14036
|
-
|
|
14037
|
-
(sPlainArgs.length === 2 && (sPlainArgs[0] === "-v" || sPlainArgs[0] === "-i" || sPlainArgs[0] === "-c" || sPlainArgs[0] === "-F") && /^[a-zA-Z0-9_ :;,/-]+$/.test(sPlainArgs[1]));
|
|
14038
|
-
if (!grepOk)
|
|
14089
|
+
else if (sName === "awk") {
|
|
14090
|
+
if (this.evalSyncAwk([], sPlainArgs) === undefined)
|
|
14039
14091
|
return false;
|
|
14040
14092
|
}
|
|
14041
|
-
if (sName === "
|
|
14042
|
-
|
|
14043
|
-
|
|
14044
|
-
return false;
|
|
14093
|
+
else if (sName === "grep") {
|
|
14094
|
+
if (this.evalSyncGrep([], sPlainArgs, Boolean(rawState.errexit)) === undefined)
|
|
14095
|
+
return false;
|
|
14045
14096
|
}
|
|
14046
|
-
if (sName === "
|
|
14047
|
-
if (
|
|
14097
|
+
else if (sName === "tr") {
|
|
14098
|
+
if (this.evalSyncTr("", sPlainArgs) === undefined)
|
|
14099
|
+
return false;
|
|
14100
|
+
}
|
|
14101
|
+
else if (sName === "jq") {
|
|
14102
|
+
if (sIdx !== 1)
|
|
14103
|
+
return false;
|
|
14104
|
+
const jqIn = this.extractLoopInvariantJqInput(cmd, hasSingleStdinRedir, hasSingleHereStringRedir, rawState);
|
|
14105
|
+
if (jqIn === undefined || this.evalSyncJq(jqIn, sPlainArgs) === undefined)
|
|
14106
|
+
return false;
|
|
14107
|
+
}
|
|
14108
|
+
else if (sName === "base64") {
|
|
14109
|
+
if (sPlainArgs.length !== 0)
|
|
14110
|
+
return false;
|
|
14111
|
+
}
|
|
14112
|
+
else if (sName === "tac") {
|
|
14113
|
+
if (sPlainArgs.length !== 0 || (w0Plain !== "echo" && !hasSingleHereStringRedir))
|
|
14114
|
+
return false;
|
|
14115
|
+
}
|
|
14116
|
+
else if (sName === "nl") {
|
|
14117
|
+
if ((w0Plain !== "echo" && !hasSingleHereStringRedir) || this.evalSyncNl([], sPlainArgs) === undefined)
|
|
14118
|
+
return false;
|
|
14119
|
+
}
|
|
14120
|
+
else if (sName === "paste") {
|
|
14121
|
+
if (this.evalSyncPaste([], sPlainArgs) === undefined)
|
|
14122
|
+
return false;
|
|
14123
|
+
}
|
|
14124
|
+
else if (sName === "numfmt") {
|
|
14125
|
+
if (sIdx !== 1)
|
|
14126
|
+
return false;
|
|
14127
|
+
const nmCheck = this.extractLoopInvariantJqInput(cmd, hasSingleStdinRedir, hasSingleHereStringRedir, rawState);
|
|
14128
|
+
if (nmCheck === undefined || this.evalSyncNumfmt(nmCheck.split("\n"), sPlainArgs) === undefined)
|
|
14129
|
+
return false;
|
|
14130
|
+
}
|
|
14131
|
+
else if (sName === "rev") {
|
|
14132
|
+
if (sPlainArgs.length !== 0)
|
|
14048
14133
|
return false;
|
|
14049
14134
|
}
|
|
14050
|
-
if ((sName === "tac" || sName === "nl") && sPlainArgs.length !== 0)
|
|
14051
|
-
return false;
|
|
14052
14135
|
}
|
|
14053
14136
|
}
|
|
14054
14137
|
continue;
|
|
@@ -14482,7 +14565,7 @@ export class Runtime {
|
|
|
14482
14565
|
else if (p === "-n" || p === "-rn" || p === "-nr" || p === "-N" || p === "-rN" || p === "-Nr") {
|
|
14483
14566
|
if (p.includes("r"))
|
|
14484
14567
|
rawMode = true;
|
|
14485
|
-
exactChars
|
|
14568
|
+
exactChars ||= p.includes("N");
|
|
14486
14569
|
const nPlain = cmd.words[argIdx + 1]?.plain;
|
|
14487
14570
|
if (!nPlain || !/^[1-9][0-9]{0,5}$/.test(nPlain) || byteLocale(rawState.variables))
|
|
14488
14571
|
return undefined;
|
|
@@ -14494,7 +14577,7 @@ export class Runtime {
|
|
|
14494
14577
|
return undefined;
|
|
14495
14578
|
if (p.startsWith("-r"))
|
|
14496
14579
|
rawMode = true;
|
|
14497
|
-
exactChars
|
|
14580
|
+
exactChars ||= p.includes("N");
|
|
14498
14581
|
maxChars = Number(p.slice(p.startsWith("-r") ? 3 : 2));
|
|
14499
14582
|
argIdx++;
|
|
14500
14583
|
}
|
|
@@ -14707,12 +14790,12 @@ export class Runtime {
|
|
|
14707
14790
|
ifOk = false;
|
|
14708
14791
|
break;
|
|
14709
14792
|
}
|
|
14710
|
-
if (!this.canSyncLoopBody(br.body, rawState, io, true)) {
|
|
14793
|
+
if (!this.canSyncLoopBody(br.body, rawState, io, true, printfInductionName)) {
|
|
14711
14794
|
ifOk = false;
|
|
14712
14795
|
break;
|
|
14713
14796
|
}
|
|
14714
14797
|
}
|
|
14715
|
-
if (ifOk && cmd.otherwise && !this.canSyncLoopBody(cmd.otherwise, rawState, io, true))
|
|
14798
|
+
if (ifOk && cmd.otherwise && !this.canSyncLoopBody(cmd.otherwise, rawState, io, true, printfInductionName))
|
|
14716
14799
|
ifOk = false;
|
|
14717
14800
|
if (ifOk)
|
|
14718
14801
|
continue;
|
|
@@ -14733,7 +14816,7 @@ export class Runtime {
|
|
|
14733
14816
|
caseOk = false;
|
|
14734
14817
|
break;
|
|
14735
14818
|
}
|
|
14736
|
-
if (!this.canSyncLoopBody(cl.body, rawState, io, true)) {
|
|
14819
|
+
if (!this.canSyncLoopBody(cl.body, rawState, io, true, printfInductionName)) {
|
|
14737
14820
|
caseOk = false;
|
|
14738
14821
|
break;
|
|
14739
14822
|
}
|
|
@@ -15455,17 +15538,45 @@ export class Runtime {
|
|
|
15455
15538
|
const condition = command.kind === "arithmetic-for" ? command.expressions[1]?.tree : undefined;
|
|
15456
15539
|
const increment = command.kind === "arithmetic-for" ? command.expressions[2]?.tree : undefined;
|
|
15457
15540
|
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
|
|
15541
|
+
const whileTree = whileCondCmd?.kind === "arithmetic" && !whileCondCmd.expression.error ? whileCondCmd.expression.tree : undefined;
|
|
15542
|
+
const whileName = whileTree?.kind === "binary" && (whileTree.operator === "<" || whileTree.operator === "<=") &&
|
|
15543
|
+
whileTree.left.kind === "name" && whileTree.right.kind === "literal" &&
|
|
15544
|
+
whileTree.right.value >= 0n && whileTree.right.value <= 2000n ? whileTree.left.name : undefined;
|
|
15545
|
+
const whileValue = whileName === undefined ? undefined : rawState.variables[whileName];
|
|
15546
|
+
const whileStart = typeof whileValue === "string" ? Number(whileValue) : NaN;
|
|
15547
|
+
const whilePrintfInd = Number.isInteger(whileStart) && whileStart >= 0 && whileStart <= 2000 &&
|
|
15548
|
+
String(whileStart) === whileValue ? whileName : undefined;
|
|
15549
|
+
const forPrintfInd = command.kind === "for" && command.words?.length === 1 && /^\{[0-9]{1,4}\.\.[0-9]{1,4}(?:\.\.[1-9][0-9]{0,2})?\}$/.test(command.words[0].plain ?? "") ? command.name : undefined;
|
|
15459
15550
|
const printfInductionName = initializer?.kind === "binary" && initializer.operator === "=" && initializer.left.kind === "name" &&
|
|
15460
15551
|
initializer.right.kind === "literal" && initializer.right.value >= 0n && initializer.right.value <= 2000n &&
|
|
15461
15552
|
condition?.kind === "binary" && (condition.operator === "<" || condition.operator === "<=") &&
|
|
15462
15553
|
condition.left.kind === "name" && condition.left.name === initializer.left.name &&
|
|
15463
15554
|
condition.right.kind === "literal" && condition.right.value >= 0n && condition.right.value <= 2000n &&
|
|
15464
15555
|
increment?.kind === "unary" && increment.operator === "++" && increment.operand.kind === "name" && increment.operand.name === initializer.left.name &&
|
|
15465
|
-
this.canSyncPrintfInductionBody(command.body, rawState)
|
|
15556
|
+
this.canSyncPrintfInductionBody(command.body, rawState, initializer.left.name)
|
|
15466
15557
|
? initializer.left.name
|
|
15467
|
-
: (whilePrintfInd && this.canSyncPrintfInductionBody(command.body, rawState
|
|
15468
|
-
|
|
15558
|
+
: (whilePrintfInd && this.canSyncPrintfInductionBody(command.body, rawState, whilePrintfInd)
|
|
15559
|
+
? whilePrintfInd
|
|
15560
|
+
: (forPrintfInd && this.canSyncPrintfInductionBody(command.body, rawState, forPrintfInd) ? forPrintfInd : undefined));
|
|
15561
|
+
const prevActivePrintfInd = this._activePrintfInductionName;
|
|
15562
|
+
const prevActiveLoopScript = this._activeLoopBodyScript;
|
|
15563
|
+
const prevActiveLoopCond = this._activeLoopCondScript;
|
|
15564
|
+
const prevActiveLoopVar = this._activeLoopVarName;
|
|
15565
|
+
this._activePrintfInductionName = printfInductionName;
|
|
15566
|
+
this._activeLoopBodyScript = command.body;
|
|
15567
|
+
this._activeLoopCondScript = command.kind === "while" ? command.condition : undefined;
|
|
15568
|
+
this._activeLoopVarName = command.kind === "for" ? command.name : (printfInductionName ?? (whilePrintfInd || undefined));
|
|
15569
|
+
let bodySyncOk = false;
|
|
15570
|
+
try {
|
|
15571
|
+
bodySyncOk = !(guestArrays(rawState) && (guestArrays(rawState).watches.size > 0 || this.budget.limits.maxExpansionBytes < 65536)) && this.canSyncLoopBody(command.body, rawState, io, false, printfInductionName);
|
|
15572
|
+
}
|
|
15573
|
+
finally {
|
|
15574
|
+
this._activePrintfInductionName = prevActivePrintfInd;
|
|
15575
|
+
this._activeLoopBodyScript = prevActiveLoopScript;
|
|
15576
|
+
this._activeLoopCondScript = prevActiveLoopCond;
|
|
15577
|
+
this._activeLoopVarName = prevActiveLoopVar;
|
|
15578
|
+
}
|
|
15579
|
+
if (!bodySyncOk) {
|
|
15469
15580
|
command._skipTrySyncLoop = true;
|
|
15470
15581
|
return undefined;
|
|
15471
15582
|
}
|
|
@@ -15648,7 +15759,8 @@ export class Runtime {
|
|
|
15648
15759
|
}
|
|
15649
15760
|
const wordsToScan = step.arrayAssign?.kind === "compound"
|
|
15650
15761
|
? step.arrayAssign.entries.map(e => e.value)
|
|
15651
|
-
: step.
|
|
15762
|
+
: step.printfVArgs ? step.printfVArgs
|
|
15763
|
+
: step.value ? [step.value] : [];
|
|
15652
15764
|
for (let wIdx = 0; wIdx < wordsToScan.length; wIdx++) {
|
|
15653
15765
|
const wVal = wordsToScan[wIdx];
|
|
15654
15766
|
for (let i = 0; i < wVal.parts.length; i++) {
|
|
@@ -16896,29 +17008,230 @@ export class Runtime {
|
|
|
16896
17008
|
}
|
|
16897
17009
|
return pos <= 128 ? fastRedirectScratchViews[pos] : fastRedirectScratchBytes.subarray(0, pos);
|
|
16898
17010
|
}
|
|
16899
|
-
|
|
16900
|
-
|
|
16901
|
-
|
|
16902
|
-
|
|
17011
|
+
_activePrintfInductionName = undefined;
|
|
17012
|
+
_activeLoopBodyScript = undefined;
|
|
17013
|
+
_activeLoopCondScript = undefined;
|
|
17014
|
+
_activeLoopVarName = undefined;
|
|
17015
|
+
isVarUnmutatedInScript(varName, script) {
|
|
17016
|
+
for (const list of script.lists) {
|
|
17017
|
+
for (const pipeline of list.pipelines) {
|
|
17018
|
+
for (const cmd of pipeline.commands) {
|
|
17019
|
+
if (cmd.kind === "arithmetic") {
|
|
17020
|
+
if (cmd.expression.hasMutation && cmd.expression.source.includes(varName))
|
|
17021
|
+
return false;
|
|
17022
|
+
continue;
|
|
17023
|
+
}
|
|
17024
|
+
if (cmd.kind === "if") {
|
|
17025
|
+
for (const br of cmd.branches) {
|
|
17026
|
+
if (!this.isVarUnmutatedInScript(varName, br.condition) || !this.isVarUnmutatedInScript(varName, br.body))
|
|
17027
|
+
return false;
|
|
17028
|
+
}
|
|
17029
|
+
if (cmd.otherwise && !this.isVarUnmutatedInScript(varName, cmd.otherwise))
|
|
17030
|
+
return false;
|
|
17031
|
+
continue;
|
|
17032
|
+
}
|
|
17033
|
+
if (cmd.kind === "case") {
|
|
17034
|
+
for (const cl of cmd.clauses) {
|
|
17035
|
+
if (!this.isVarUnmutatedInScript(varName, cl.body))
|
|
17036
|
+
return false;
|
|
17037
|
+
}
|
|
17038
|
+
continue;
|
|
17039
|
+
}
|
|
17040
|
+
if (cmd.kind === "for") {
|
|
17041
|
+
if (cmd.name === varName || !this.isVarUnmutatedInScript(varName, cmd.body))
|
|
17042
|
+
return false;
|
|
17043
|
+
continue;
|
|
17044
|
+
}
|
|
17045
|
+
if (cmd.kind === "arithmetic-for") {
|
|
17046
|
+
if (cmd.expressions.some(e => e && e.hasMutation && e.source.includes(varName)) || !this.isVarUnmutatedInScript(varName, cmd.body))
|
|
17047
|
+
return false;
|
|
17048
|
+
continue;
|
|
17049
|
+
}
|
|
17050
|
+
if (cmd.kind === "while") {
|
|
17051
|
+
if (!this.isVarUnmutatedInScript(varName, cmd.condition) || !this.isVarUnmutatedInScript(varName, cmd.body))
|
|
17052
|
+
return false;
|
|
17053
|
+
continue;
|
|
17054
|
+
}
|
|
17055
|
+
if (cmd.kind === "group" || cmd.kind === "subshell") {
|
|
17056
|
+
if (!this.isVarUnmutatedInScript(varName, cmd.body))
|
|
17057
|
+
return false;
|
|
17058
|
+
continue;
|
|
17059
|
+
}
|
|
17060
|
+
if (cmd.kind !== "simple")
|
|
17061
|
+
return false;
|
|
17062
|
+
for (const w of cmd.words) {
|
|
17063
|
+
const arrAss = getArrayAssignment(w);
|
|
17064
|
+
if (arrAss && arrAss.name === varName)
|
|
17065
|
+
return false;
|
|
17066
|
+
const p0 = w.parts[0];
|
|
17067
|
+
if (p0?.kind === "text" && !p0.quoted && (p0.value.startsWith(varName + "=") || p0.value.startsWith(varName + "+=") || p0.value.startsWith(varName + "[")))
|
|
17068
|
+
return false;
|
|
17069
|
+
}
|
|
17070
|
+
const w0 = cmd.words[0]?.plain;
|
|
17071
|
+
if (w0 === "read" || w0 === "unset" || w0 === "declare" || w0 === "typeset" || w0 === "local" || w0 === "export" || w0 === "mapfile" || w0 === "readarray") {
|
|
17072
|
+
if (w0 === "read" && varName === "REPLY")
|
|
17073
|
+
return false;
|
|
17074
|
+
if (cmd.words.slice(1).some(w => (w.plain ?? "").includes(varName)))
|
|
17075
|
+
return false;
|
|
17076
|
+
}
|
|
17077
|
+
if (w0 === "printf" && cmd.words[1]?.plain === "-v" && (cmd.words[2]?.plain ?? "").startsWith(varName))
|
|
17078
|
+
return false;
|
|
17079
|
+
for (const w of [...cmd.words, ...cmd.redirects.map(r => r.target)]) {
|
|
17080
|
+
for (const pt of w.parts) {
|
|
17081
|
+
if (pt.kind === "arithmetic" && pt.expression.hasMutation && pt.expression.source.includes(varName))
|
|
17082
|
+
return false;
|
|
17083
|
+
if (pt.kind === "substitution" && !this.isVarUnmutatedInScript(varName, pt.script))
|
|
17084
|
+
return false;
|
|
17085
|
+
}
|
|
17086
|
+
}
|
|
17087
|
+
}
|
|
17088
|
+
}
|
|
17089
|
+
}
|
|
17090
|
+
return true;
|
|
17091
|
+
}
|
|
17092
|
+
isVarUnmutatedInActiveLoop(varName) {
|
|
17093
|
+
if (varName === this._activeLoopVarName || varName === this._activePrintfInductionName)
|
|
17094
|
+
return false;
|
|
17095
|
+
if (this._activeLoopCondScript && !this.isVarUnmutatedInScript(varName, this._activeLoopCondScript))
|
|
17096
|
+
return false;
|
|
17097
|
+
if (this._activeLoopBodyScript && !this.isVarUnmutatedInScript(varName, this._activeLoopBodyScript))
|
|
17098
|
+
return false;
|
|
17099
|
+
return true;
|
|
17100
|
+
}
|
|
17101
|
+
isFileReadOnlyScript(script, rawState) {
|
|
17102
|
+
const visit = (value) => {
|
|
17103
|
+
if (value === null || typeof value !== "object")
|
|
17104
|
+
return true;
|
|
17105
|
+
if (Array.isArray(value))
|
|
17106
|
+
return value.every(visit);
|
|
17107
|
+
const node = value;
|
|
17108
|
+
if (typeof node.operator === "string" && "target" in node && !["<", "<<<", "<<", "<<-"].includes(node.operator))
|
|
17109
|
+
return false;
|
|
17110
|
+
if (node.kind === "simple") {
|
|
17111
|
+
const cmd = value;
|
|
17112
|
+
// Unknown commands (including shell functions) cannot promise read-only I/O.
|
|
17113
|
+
const name = cmd.words[0]?.plain;
|
|
17114
|
+
if (name === undefined && !cmd.words.every(word => this.assignment(word) || getArrayAssignment(word)))
|
|
17115
|
+
return false;
|
|
17116
|
+
if (name !== undefined && (hasShellFunction(rawState, name) || !["jq", "cat", "echo", "printf", "test", "[", ":", "true", "false"].includes(name)))
|
|
17117
|
+
return false;
|
|
17118
|
+
}
|
|
17119
|
+
return Object.values(node).every(visit);
|
|
17120
|
+
};
|
|
17121
|
+
return visit(script);
|
|
17122
|
+
}
|
|
17123
|
+
extractLoopInvariantJqInput(cmd, hasSingleStdinRedir, hasSingleHereStringRedir, rawState) {
|
|
17124
|
+
const w0 = cmd.words[0]?.plain;
|
|
17125
|
+
const resolveInvariantWord = (w) => {
|
|
17126
|
+
if (w.plain !== undefined)
|
|
17127
|
+
return w.plain;
|
|
17128
|
+
if (w.parts.length > 0 && w.parts.every(pt => pt.kind === "text"))
|
|
17129
|
+
return w.parts.map(pt => pt.value).join("");
|
|
17130
|
+
if (w.parts.length === 1 && w.parts[0].kind === "variable") {
|
|
17131
|
+
const vp = w.parts[0];
|
|
17132
|
+
if (!vp.indirect && !vp.operator && !vp.substring && !vp.transform && !vp.length && !vp.prefixNames && getArraySelector(vp) === undefined && this.isVarUnmutatedInActiveLoop(vp.name)) {
|
|
17133
|
+
const val = rawState.variables[vp.name];
|
|
17134
|
+
if (typeof val === "string")
|
|
17135
|
+
return val;
|
|
17136
|
+
}
|
|
17137
|
+
}
|
|
17138
|
+
return undefined;
|
|
17139
|
+
};
|
|
17140
|
+
if (w0 === "jq" || w0 === "numfmt") {
|
|
17141
|
+
if (hasSingleHereStringRedir) {
|
|
17142
|
+
const resolved = resolveInvariantWord(cmd.redirects[0].target);
|
|
17143
|
+
return resolved !== undefined ? resolved.trim() : undefined;
|
|
17144
|
+
}
|
|
17145
|
+
if (this._fileWrites?.size || this._outputFiles?.size)
|
|
17146
|
+
return undefined;
|
|
17147
|
+
if ([this._activeLoopBodyScript, this._activeLoopCondScript].some(script => script && !this.isFileReadOnlyScript(script, rawState)))
|
|
17148
|
+
return undefined;
|
|
17149
|
+
const fPlain = hasSingleStdinRedir ? cmd.redirects[0].target.plain : cmd.words[cmd.words.length - 1]?.plain;
|
|
17150
|
+
if (!fPlain || fPlain.startsWith("-") || fPlain === "/dev/stdin")
|
|
17151
|
+
return undefined;
|
|
17152
|
+
const vCheck = this.tryReadMemoryFileViewSync(resolvePath(rawState.cwd, fPlain), false);
|
|
17153
|
+
if (!vCheck || vCheck.byteLength > 16384 || vCheck.includes(0))
|
|
17154
|
+
return undefined;
|
|
17155
|
+
return sharedSyncPipeDecoder.decode(vCheck).trim();
|
|
17156
|
+
}
|
|
17157
|
+
if (w0 === "cat") {
|
|
17158
|
+
if (hasSingleHereStringRedir) {
|
|
17159
|
+
const resolved = resolveInvariantWord(cmd.redirects[0].target);
|
|
17160
|
+
return resolved !== undefined ? resolved.trim() : undefined;
|
|
17161
|
+
}
|
|
17162
|
+
if (this._fileWrites?.size || this._outputFiles?.size)
|
|
17163
|
+
return undefined;
|
|
17164
|
+
if ([this._activeLoopBodyScript, this._activeLoopCondScript].some(script => script && !this.isFileReadOnlyScript(script, rawState)))
|
|
17165
|
+
return undefined;
|
|
17166
|
+
const fPlain = hasSingleStdinRedir ? cmd.redirects[0].target.plain : cmd.words[1]?.plain;
|
|
17167
|
+
if (!fPlain || fPlain.startsWith("-") || fPlain === "/dev/stdin")
|
|
17168
|
+
return undefined;
|
|
17169
|
+
const vCheck = this.tryReadMemoryFileViewSync(resolvePath(rawState.cwd, fPlain), false);
|
|
17170
|
+
if (!vCheck || vCheck.byteLength > 16384 || vCheck.includes(0))
|
|
17171
|
+
return undefined;
|
|
17172
|
+
return sharedSyncPipeDecoder.decode(vCheck).trim();
|
|
17173
|
+
}
|
|
17174
|
+
if (w0 === "echo" && cmd.words.length === 2) {
|
|
17175
|
+
const resolved = resolveInvariantWord(cmd.words[1]);
|
|
17176
|
+
if (resolved !== undefined && !resolved.startsWith("-"))
|
|
17177
|
+
return resolved.trim();
|
|
17178
|
+
return undefined;
|
|
17179
|
+
}
|
|
17180
|
+
if (w0 === "printf" && cmd.words.length >= 2) {
|
|
17181
|
+
const args = [];
|
|
17182
|
+
for (let i = 1; i < cmd.words.length; i++) {
|
|
17183
|
+
const r = resolveInvariantWord(cmd.words[i]);
|
|
17184
|
+
if (r === undefined)
|
|
17185
|
+
return undefined;
|
|
17186
|
+
args.push(r);
|
|
17187
|
+
}
|
|
17188
|
+
const formatted = tryFastPrintf(args);
|
|
17189
|
+
return formatted !== undefined ? formatted.trim() : undefined;
|
|
17190
|
+
}
|
|
17191
|
+
return undefined;
|
|
17192
|
+
}
|
|
17193
|
+
canSyncPrintfInductionBody(script, rawState, inductionName) {
|
|
16903
17194
|
for (const list of script.lists)
|
|
16904
17195
|
for (const pipeline of list.pipelines)
|
|
16905
17196
|
for (const command of pipeline.commands) {
|
|
16906
17197
|
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")
|
|
17198
|
+
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" && command.expression.tree.operand.name !== inductionName)) && command.expression.tree.operand.kind === "name")
|
|
16908
17199
|
continue;
|
|
16909
17200
|
return false;
|
|
16910
17201
|
}
|
|
16911
17202
|
if (command.kind !== "simple" || hasShellFunction(rawState, command.words[0]?.plain ?? "") || command.words.some(word => getArrayAssignment(word) !== undefined))
|
|
16912
17203
|
return false;
|
|
17204
|
+
const w0 = command.words[0]?.plain;
|
|
17205
|
+
if (w0 === "let" || w0 === "declare" || w0 === "typeset" || w0 === "local" || w0 === "export" || w0 === "unset" || w0 === "mapfile" || w0 === "readarray")
|
|
17206
|
+
return false;
|
|
17207
|
+
if (inductionName !== undefined) {
|
|
17208
|
+
if (command.words.some(w => {
|
|
17209
|
+
const p0 = w.parts[0];
|
|
17210
|
+
return p0?.kind === "text" && !p0.quoted && (p0.value.startsWith(inductionName + "=") || p0.value.startsWith(inductionName + "+="));
|
|
17211
|
+
}))
|
|
17212
|
+
return false;
|
|
17213
|
+
if (w0 === "read" && (inductionName === "REPLY" || command.words.slice(1).some(w => w.plain === inductionName || w.plain === "-a" || w.plain === "-ra" || w.plain === "-ar")))
|
|
17214
|
+
return false;
|
|
17215
|
+
if (w0 === "printf" && command.words[1]?.plain === "-v" && command.words[2]?.plain === inductionName)
|
|
17216
|
+
return false;
|
|
17217
|
+
}
|
|
16913
17218
|
for (const word of [...command.words, ...command.redirects.map(redirect => redirect.target)])
|
|
16914
17219
|
for (const part of word.parts) {
|
|
16915
17220
|
if (part.kind === "text")
|
|
16916
17221
|
continue;
|
|
16917
|
-
if (part.kind === "variable" &&
|
|
17222
|
+
if (part.kind === "variable" &&
|
|
17223
|
+
!part.indirect &&
|
|
17224
|
+
!part.substring &&
|
|
17225
|
+
!part.prefixNames &&
|
|
17226
|
+
getArraySelector(part) === undefined &&
|
|
17227
|
+
(part.operator === undefined ||
|
|
17228
|
+
((part.operator === "#" || part.operator === "##" || part.operator === "%" || part.operator === "%%") &&
|
|
17229
|
+
part.alternate !== undefined &&
|
|
17230
|
+
part.alternate.parts.every(p => p.kind === "text"))))
|
|
16918
17231
|
continue;
|
|
16919
17232
|
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
17233
|
continue;
|
|
16921
|
-
if (part.kind === "substitution" && this.canSyncPrintfInductionBody(part.script, rawState))
|
|
17234
|
+
if (part.kind === "substitution" && this.canSyncPrintfInductionBody(part.script, rawState, inductionName))
|
|
16922
17235
|
continue;
|
|
16923
17236
|
return false;
|
|
16924
17237
|
}
|
|
@@ -16929,41 +17242,86 @@ export class Runtime {
|
|
|
16929
17242
|
const printfDef = this.commands.get("printf");
|
|
16930
17243
|
if (hasShellFunction(rawState, "printf") || rawState.extensions?.builtins.has("printf") || printfDef?.execute !== printfCommand.execute)
|
|
16931
17244
|
return false;
|
|
16932
|
-
|
|
16933
|
-
//
|
|
16934
|
-
|
|
17245
|
+
const effInductionName = inductionName ?? this._activePrintfInductionName;
|
|
17246
|
+
// Prove unsigned arithmetic stays non-negative and within the Smi evaluator's
|
|
17247
|
+
// range. Names are matched as AST nodes, never as substrings of other names.
|
|
17248
|
+
const unsignedUpperBound = (tree) => {
|
|
17249
|
+
if (!tree)
|
|
17250
|
+
return undefined;
|
|
17251
|
+
let bound;
|
|
17252
|
+
if (tree.kind === "literal")
|
|
17253
|
+
bound = tree.value;
|
|
17254
|
+
else if (tree.kind === "name" && tree.name === effInductionName && tree.subscript === undefined)
|
|
17255
|
+
bound = 2147483647n;
|
|
17256
|
+
else if (tree.kind === "binary" && (tree.operator === "+" || tree.operator === "*")) {
|
|
17257
|
+
const left = unsignedUpperBound(tree.left);
|
|
17258
|
+
const right = unsignedUpperBound(tree.right);
|
|
17259
|
+
if (left !== undefined && right !== undefined)
|
|
17260
|
+
bound = tree.operator === "+" ? left + right : left * right;
|
|
17261
|
+
}
|
|
17262
|
+
return bound !== undefined && bound >= 0n && bound <= 2147483647n ? bound : undefined;
|
|
17263
|
+
};
|
|
16935
17264
|
const fmtWordIdx = cmd.words[argStartIdx]?.plain === "--" ? argStartIdx + 1 : argStartIdx;
|
|
16936
17265
|
if (fmtWordIdx >= cmd.words.length)
|
|
16937
17266
|
return false;
|
|
16938
|
-
|
|
17267
|
+
const fmtWord = cmd.words[fmtWordIdx];
|
|
17268
|
+
if (!this.isPureSyncValueWord(fmtWord, rawState))
|
|
17269
|
+
return false;
|
|
17270
|
+
let fmtStr = "";
|
|
17271
|
+
for (const part of fmtWord.parts) {
|
|
17272
|
+
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))))
|
|
17273
|
+
return false;
|
|
17274
|
+
fmtStr += part.value;
|
|
17275
|
+
}
|
|
17276
|
+
if (fmtWordIdx === argStartIdx && fmtStr.startsWith("-"))
|
|
17277
|
+
return false;
|
|
17278
|
+
const specs = extractFastPrintfSpecifiers(fmtStr);
|
|
17279
|
+
if (!specs)
|
|
17280
|
+
return false;
|
|
17281
|
+
const args = [];
|
|
17282
|
+
if (fmtWordIdx > argStartIdx)
|
|
17283
|
+
args.push("--");
|
|
17284
|
+
args.push(fmtStr);
|
|
17285
|
+
for (let i = fmtWordIdx + 1; i < cmd.words.length; i++) {
|
|
16939
17286
|
const w = cmd.words[i];
|
|
16940
17287
|
if (!this.isPureSyncValueWord(w, rawState))
|
|
16941
17288
|
return false;
|
|
16942
|
-
const
|
|
16943
|
-
const
|
|
16944
|
-
|
|
16945
|
-
|
|
17289
|
+
const argIdx = i - fmtWordIdx - 1;
|
|
17290
|
+
const spec = specs.length > 0 ? specs[argIdx % specs.length] : "s";
|
|
17291
|
+
const nonSplitting = w.parts.length > 0 && w.parts.every(part => part.quoted ||
|
|
17292
|
+
(part.kind === "text" && part.value.length > 0 && !part.value.includes(" ") && !part.value.includes("\t") && !part.value.includes("\n") && !part.value.includes("{") && !hasGlobOrEscape(part.value, true)));
|
|
17293
|
+
if (spec === "s" && nonSplitting) {
|
|
17294
|
+
args.push("");
|
|
16946
17295
|
continue;
|
|
16947
17296
|
}
|
|
16948
|
-
|
|
16949
|
-
|
|
16950
|
-
|
|
16951
|
-
part
|
|
16952
|
-
|
|
16953
|
-
|
|
16954
|
-
|
|
16955
|
-
!part.
|
|
16956
|
-
|
|
16957
|
-
|
|
16958
|
-
|
|
16959
|
-
|
|
16960
|
-
|
|
17297
|
+
const valueParts = w.parts.filter(part => part.kind !== "text" || part.value.length > 0);
|
|
17298
|
+
const part = valueParts[0];
|
|
17299
|
+
if ((spec === "d" || spec === "u") && valueParts.length === 1 && part?.quoted) {
|
|
17300
|
+
if (part.kind === "variable" && part.name === effInductionName && !part.indirect && !part.length && !part.substring && !part.transform && part.operator === undefined && getArraySelector(part) === undefined) {
|
|
17301
|
+
args.push("0");
|
|
17302
|
+
continue;
|
|
17303
|
+
}
|
|
17304
|
+
if (part.kind === "variable" && part.length && !part.indirect && !part.prefixNames && getArraySelector(part) === undefined) {
|
|
17305
|
+
args.push("0");
|
|
17306
|
+
continue;
|
|
17307
|
+
}
|
|
17308
|
+
if (part.kind === "arithmetic" &&
|
|
17309
|
+
!part.expression.error &&
|
|
17310
|
+
!part.expression.hasMutation &&
|
|
17311
|
+
!part.expression.hasSubscript &&
|
|
17312
|
+
isSafeSmiProgram(part.expression) &&
|
|
17313
|
+
/^[a-zA-Z0-9_ +*-]+$/.test(part.expression.source) &&
|
|
17314
|
+
this.canSyncArithmeticWithoutFault(part.expression.tree, rawState, cmd.line ?? 1) &&
|
|
17315
|
+
(spec === "d" || unsignedUpperBound(part.expression.tree) !== undefined)) {
|
|
17316
|
+
args.push("0");
|
|
17317
|
+
continue;
|
|
17318
|
+
}
|
|
16961
17319
|
}
|
|
16962
17320
|
let arg = "";
|
|
16963
|
-
for (const
|
|
16964
|
-
if (
|
|
17321
|
+
for (const p of w.parts) {
|
|
17322
|
+
if (p.kind !== "text" || (!p.quoted && (p.value.length === 0 || p.value.includes(" ") || p.value.includes("\t") || p.value.includes("\n") || p.value.includes("{") || hasGlobOrEscape(p.value, true))))
|
|
16965
17323
|
return false;
|
|
16966
|
-
arg +=
|
|
17324
|
+
arg += p.value;
|
|
16967
17325
|
}
|
|
16968
17326
|
args.push(arg);
|
|
16969
17327
|
}
|
|
@@ -16975,6 +17333,15 @@ export class Runtime {
|
|
|
16975
17333
|
return false;
|
|
16976
17334
|
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));
|
|
16977
17335
|
}
|
|
17336
|
+
syncStringLength(value, byteCount) {
|
|
17337
|
+
let length = 0;
|
|
17338
|
+
for (let offset = 0; offset < value.length;) {
|
|
17339
|
+
const point = value.codePointAt(offset);
|
|
17340
|
+
length += byteCount ? (point <= 0x7f ? 1 : point <= 0x7ff ? 2 : point <= 0xffff ? 3 : 4) : 1;
|
|
17341
|
+
offset += point > 0xffff ? 2 : 1;
|
|
17342
|
+
}
|
|
17343
|
+
return length;
|
|
17344
|
+
}
|
|
16978
17345
|
execSyncReadHereStringStep(rs, step, rawState, io, monitor, touched) {
|
|
16979
17346
|
const rawInput = this.fastValueWord(rs.inputWord, rawState, io, false, false, false, false, 0, step.line);
|
|
16980
17347
|
const delim = rs.delimChar ?? "\n";
|
|
@@ -16982,16 +17349,16 @@ export class Runtime {
|
|
|
16982
17349
|
let status = 0;
|
|
16983
17350
|
if (rs.maxChars !== undefined) {
|
|
16984
17351
|
const fullInput = rawInput + "\n";
|
|
16985
|
-
|
|
16986
|
-
|
|
16987
|
-
|
|
16988
|
-
|
|
16989
|
-
|
|
16990
|
-
|
|
16991
|
-
|
|
16992
|
-
lineStr = untilDelim.length > rs.maxChars ? untilDelim.slice(0, rs.maxChars) : untilDelim;
|
|
16993
|
-
status = (nlIdx !== -1 || fullInput.length >= rs.maxChars) ? 0 : 1;
|
|
17352
|
+
const nlIdx = rs.exactChars ? -1 : fullInput.indexOf(delim);
|
|
17353
|
+
const end = nlIdx === -1 ? fullInput.length : nlIdx;
|
|
17354
|
+
let position = 0;
|
|
17355
|
+
let count = 0;
|
|
17356
|
+
while (position < end && count < rs.maxChars) {
|
|
17357
|
+
position = nextCodePointOffset(fullInput, position);
|
|
17358
|
+
count++;
|
|
16994
17359
|
}
|
|
17360
|
+
lineStr = fullInput.slice(0, position);
|
|
17361
|
+
status = (count >= rs.maxChars || nlIdx !== -1) ? 0 : 1;
|
|
16995
17362
|
}
|
|
16996
17363
|
else {
|
|
16997
17364
|
const fullInput = delim === "\n" ? rawInput : rawInput + "\n";
|
|
@@ -24600,8 +24967,8 @@ export class Runtime {
|
|
|
24600
24967
|
invalid = true;
|
|
24601
24968
|
break;
|
|
24602
24969
|
}
|
|
24603
|
-
if (flag === "
|
|
24604
|
-
exact =
|
|
24970
|
+
if (flag === "N")
|
|
24971
|
+
exact = true;
|
|
24605
24972
|
const value = option.slice(index + 1) || names.shift();
|
|
24606
24973
|
if (value === undefined)
|
|
24607
24974
|
invalid = true;
|
|
@@ -25071,7 +25438,7 @@ export class Runtime {
|
|
|
25071
25438
|
}
|
|
25072
25439
|
if (part.kind === "variable" && part.prefixNames) {
|
|
25073
25440
|
const ifs = state.variables.IFS ?? " ";
|
|
25074
|
-
const separator = io.nameExpansionContext === "document" || io.nameExpansionContext === "conditional"
|
|
25441
|
+
const separator = io.nameExpansionContext === "document" || part.prefixNames === "@" && (io.nameExpansionContext === "conditional" || ifs.length === 0)
|
|
25075
25442
|
? " " : ifs.length ? String.fromCodePoint(ifs.codePointAt(0)) : "";
|
|
25076
25443
|
const fragments = [];
|
|
25077
25444
|
let bytes = 0;
|
|
@@ -26091,7 +26458,7 @@ export class Runtime {
|
|
|
26091
26458
|
if (pNames === undefined)
|
|
26092
26459
|
return undefined;
|
|
26093
26460
|
const ifs = rawState.variables.IFS ?? " ";
|
|
26094
|
-
const sep = io.nameExpansionContext === "document" || (io.nameExpansionContext === "conditional"
|
|
26461
|
+
const sep = io.nameExpansionContext === "document" || (part.prefixNames === "@" && (io.nameExpansionContext === "conditional" || ifs.length === 0))
|
|
26095
26462
|
? " "
|
|
26096
26463
|
: ifs.length ? String.fromCodePoint(ifs.codePointAt(0)) : "";
|
|
26097
26464
|
const joined = pNames.join(sep);
|
|
@@ -26406,11 +26773,7 @@ export class Runtime {
|
|
|
26406
26773
|
if (part.operator !== undefined)
|
|
26407
26774
|
return undefined;
|
|
26408
26775
|
const s = elemVal ?? "";
|
|
26409
|
-
|
|
26410
|
-
if (s.charCodeAt(k) >= 128)
|
|
26411
|
-
return undefined;
|
|
26412
|
-
}
|
|
26413
|
-
out += String(s.length);
|
|
26776
|
+
out += String(this.syncStringLength(s, byteLocale(rawVars)));
|
|
26414
26777
|
continue;
|
|
26415
26778
|
}
|
|
26416
26779
|
let resolvedElem;
|
|
@@ -26560,11 +26923,7 @@ export class Runtime {
|
|
|
26560
26923
|
const val = raw === undefined ? "" : (this._syncArithRawWriteOnly && this._syncArithTouched?.has(part.name) ? raw : (monitor?.values.get(part.name, raw) ?? raw));
|
|
26561
26924
|
if (typeof val !== "string")
|
|
26562
26925
|
return undefined;
|
|
26563
|
-
|
|
26564
|
-
if (val.charCodeAt(k) >= 128)
|
|
26565
|
-
return undefined;
|
|
26566
|
-
}
|
|
26567
|
-
out += String(val.length);
|
|
26926
|
+
out += String(this.syncStringLength(val, byteLocale(rawVars)));
|
|
26568
26927
|
continue;
|
|
26569
26928
|
}
|
|
26570
26929
|
if (part.operator !== undefined) {
|
|
@@ -26881,6 +27240,9 @@ export class Runtime {
|
|
|
26881
27240
|
expandSyncTrCharArray(spec) {
|
|
26882
27241
|
if (spec.length === 0)
|
|
26883
27242
|
return undefined;
|
|
27243
|
+
// Escaped endpoints need the tr parser before range expansion.
|
|
27244
|
+
if (spec.includes("\\") && spec.includes("-"))
|
|
27245
|
+
return undefined;
|
|
26884
27246
|
const posixClasses = {
|
|
26885
27247
|
"[:lower:]": "abcdefghijklmnopqrstuvwxyz",
|
|
26886
27248
|
"[:upper:]": "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
|
@@ -26921,6 +27283,16 @@ export class Runtime {
|
|
|
26921
27283
|
out.push("\r");
|
|
26922
27284
|
else if (next === "\\")
|
|
26923
27285
|
out.push("\\");
|
|
27286
|
+
else if (next >= "0" && next <= "7") {
|
|
27287
|
+
let oct = next;
|
|
27288
|
+
while (oct.length < 3 && i + 1 < spec.length && spec[i + 1] >= "0" && spec[i + 1] <= "7") {
|
|
27289
|
+
oct += spec[++i];
|
|
27290
|
+
}
|
|
27291
|
+
const code = parseInt(oct, 8);
|
|
27292
|
+
if (code <= 0 || code >= 128)
|
|
27293
|
+
return undefined;
|
|
27294
|
+
out.push(String.fromCharCode(code));
|
|
27295
|
+
}
|
|
26924
27296
|
else
|
|
26925
27297
|
return undefined;
|
|
26926
27298
|
continue;
|
|
@@ -26941,11 +27313,125 @@ export class Runtime {
|
|
|
26941
27313
|
return out;
|
|
26942
27314
|
}
|
|
26943
27315
|
evalSyncTr(input, opArgs) {
|
|
26944
|
-
|
|
26945
|
-
|
|
27316
|
+
let idx = 0;
|
|
27317
|
+
let flagC = false;
|
|
27318
|
+
let flagD = false;
|
|
27319
|
+
let flagS = false;
|
|
27320
|
+
let flagT = false;
|
|
27321
|
+
while (idx < opArgs.length) {
|
|
27322
|
+
const a = opArgs[idx];
|
|
27323
|
+
if (a === "--") {
|
|
27324
|
+
idx++;
|
|
27325
|
+
break;
|
|
27326
|
+
}
|
|
27327
|
+
if (!a.startsWith("-") || a === "-")
|
|
27328
|
+
break;
|
|
27329
|
+
if (!/^-[cCdst]+$/.test(a))
|
|
27330
|
+
return undefined;
|
|
27331
|
+
for (let k = 1; k < a.length; k++) {
|
|
27332
|
+
const ch = a[k];
|
|
27333
|
+
if (ch === "c" || ch === "C")
|
|
27334
|
+
flagC = true;
|
|
27335
|
+
else if (ch === "d")
|
|
27336
|
+
flagD = true;
|
|
27337
|
+
else if (ch === "s")
|
|
27338
|
+
flagS = true;
|
|
27339
|
+
else if (ch === "t")
|
|
27340
|
+
flagT = true;
|
|
27341
|
+
}
|
|
27342
|
+
idx++;
|
|
27343
|
+
}
|
|
27344
|
+
if (flagT && flagC)
|
|
27345
|
+
return undefined;
|
|
27346
|
+
const sets = opArgs.slice(idx);
|
|
27347
|
+
if (flagC) {
|
|
27348
|
+
if (sets.some(s => { for (let i = 0; i < s.length; i++)
|
|
27349
|
+
if (s.charCodeAt(i) >= 128)
|
|
27350
|
+
return true; return false; }))
|
|
27351
|
+
return undefined;
|
|
27352
|
+
if (flagD && !flagS && sets.length === 1) {
|
|
27353
|
+
const arr = this.expandSyncTrCharArray(sets[0]);
|
|
27354
|
+
if (!arr)
|
|
27355
|
+
return undefined;
|
|
27356
|
+
const keepSet = new Set(arr);
|
|
27357
|
+
let out = "";
|
|
27358
|
+
for (let i = 0; i < input.length; i++) {
|
|
27359
|
+
const ch = input[i];
|
|
27360
|
+
if (keepSet.has(ch))
|
|
27361
|
+
out += ch;
|
|
27362
|
+
}
|
|
27363
|
+
return out;
|
|
27364
|
+
}
|
|
27365
|
+
if (!flagD && sets.length === 2) {
|
|
27366
|
+
// Delegate multi-character complements and class validation to tr.
|
|
27367
|
+
if (sets[1].includes("[:"))
|
|
27368
|
+
return undefined;
|
|
27369
|
+
const arr1 = this.expandSyncTrCharArray(sets[0]);
|
|
27370
|
+
const arr2 = this.expandSyncTrCharArray(sets[1]);
|
|
27371
|
+
if (!arr1 || !arr2 || arr2.length !== 1)
|
|
27372
|
+
return undefined;
|
|
27373
|
+
const keepSet = new Set(arr1);
|
|
27374
|
+
const repl = arr2[arr2.length - 1];
|
|
27375
|
+
const sqSet = flagS ? new Set(arr2) : undefined;
|
|
27376
|
+
let hasNonAscii = false;
|
|
27377
|
+
for (let i = 0; i < input.length; i++) {
|
|
27378
|
+
if (input.charCodeAt(i) >= 128) {
|
|
27379
|
+
hasNonAscii = true;
|
|
27380
|
+
break;
|
|
27381
|
+
}
|
|
27382
|
+
}
|
|
27383
|
+
let out = "";
|
|
27384
|
+
let prev = "";
|
|
27385
|
+
if (hasNonAscii) {
|
|
27386
|
+
const bytes = fastSharedTextEncoder.encode(input);
|
|
27387
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
27388
|
+
const rawCh = String.fromCharCode(bytes[i]);
|
|
27389
|
+
const ch = keepSet.has(rawCh) ? rawCh : repl;
|
|
27390
|
+
if (sqSet && sqSet.has(ch) && ch === prev)
|
|
27391
|
+
continue;
|
|
27392
|
+
out += ch;
|
|
27393
|
+
prev = ch;
|
|
27394
|
+
}
|
|
27395
|
+
}
|
|
27396
|
+
else {
|
|
27397
|
+
for (let i = 0; i < input.length; i++) {
|
|
27398
|
+
const rawCh = input[i];
|
|
27399
|
+
const ch = keepSet.has(rawCh) ? rawCh : repl;
|
|
27400
|
+
if (sqSet && sqSet.has(ch) && ch === prev)
|
|
27401
|
+
continue;
|
|
27402
|
+
out += ch;
|
|
27403
|
+
prev = ch;
|
|
27404
|
+
}
|
|
27405
|
+
}
|
|
27406
|
+
return out;
|
|
27407
|
+
}
|
|
27408
|
+
if (flagD && flagS && sets.length === 2) {
|
|
27409
|
+
const arr1 = this.expandSyncTrCharArray(sets[0]);
|
|
27410
|
+
const arr2 = this.expandSyncTrCharArray(sets[1]);
|
|
27411
|
+
if (!arr1 || !arr2)
|
|
27412
|
+
return undefined;
|
|
27413
|
+
const keepSet = new Set(arr1);
|
|
27414
|
+
const sqSet = new Set(arr2);
|
|
27415
|
+
let out = "";
|
|
27416
|
+
let prev = "";
|
|
27417
|
+
for (let i = 0; i < input.length; i++) {
|
|
27418
|
+
const ch = input[i];
|
|
27419
|
+
if (!keepSet.has(ch))
|
|
27420
|
+
continue;
|
|
27421
|
+
if (sqSet.has(ch) && ch === prev)
|
|
27422
|
+
continue;
|
|
27423
|
+
out += ch;
|
|
27424
|
+
prev = ch;
|
|
27425
|
+
}
|
|
27426
|
+
return out;
|
|
27427
|
+
}
|
|
27428
|
+
return undefined;
|
|
26946
27429
|
}
|
|
26947
|
-
if (
|
|
26948
|
-
|
|
27430
|
+
if (!flagD && !flagS && sets.length === 2) {
|
|
27431
|
+
return this.translateSyncTr(input, sets[0], sets[1], flagT);
|
|
27432
|
+
}
|
|
27433
|
+
if (flagD && !flagS && sets.length === 1) {
|
|
27434
|
+
const arr = this.expandSyncTrCharArray(sets[0]);
|
|
26949
27435
|
if (!arr)
|
|
26950
27436
|
return undefined;
|
|
26951
27437
|
const delSet = new Set(arr);
|
|
@@ -26957,8 +27443,8 @@ export class Runtime {
|
|
|
26957
27443
|
}
|
|
26958
27444
|
return out;
|
|
26959
27445
|
}
|
|
26960
|
-
if (
|
|
26961
|
-
const arr = this.expandSyncTrCharArray(
|
|
27446
|
+
if (!flagD && flagS && sets.length === 1) {
|
|
27447
|
+
const arr = this.expandSyncTrCharArray(sets[0]);
|
|
26962
27448
|
if (!arr)
|
|
26963
27449
|
return undefined;
|
|
26964
27450
|
const sqSet = new Set(arr);
|
|
@@ -26973,140 +27459,654 @@ export class Runtime {
|
|
|
26973
27459
|
}
|
|
26974
27460
|
return out;
|
|
26975
27461
|
}
|
|
26976
|
-
if (
|
|
26977
|
-
const stage1 =
|
|
26978
|
-
? this.translateSyncTr(input,
|
|
26979
|
-
: this.evalSyncTr(input, ["-d",
|
|
27462
|
+
if (sets.length === 2 && (flagS || flagD)) {
|
|
27463
|
+
const stage1 = !flagD
|
|
27464
|
+
? this.translateSyncTr(input, sets[0], sets[1], flagT)
|
|
27465
|
+
: this.evalSyncTr(input, ["-d", sets[0]]);
|
|
26980
27466
|
if (stage1 === undefined)
|
|
26981
27467
|
return undefined;
|
|
26982
|
-
return this.evalSyncTr(stage1, ["-s",
|
|
27468
|
+
return this.evalSyncTr(stage1, ["-s", sets[1]]);
|
|
26983
27469
|
}
|
|
26984
27470
|
return undefined;
|
|
26985
27471
|
}
|
|
26986
|
-
|
|
26987
|
-
let
|
|
26988
|
-
let
|
|
26989
|
-
if (
|
|
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)
|
|
27472
|
+
evalSyncJqPathOps(item, expr) {
|
|
27473
|
+
let st = expr.trim();
|
|
27474
|
+
let alternatives = splitSyncJqExpression(st, "//");
|
|
27475
|
+
if (!alternatives)
|
|
26997
27476
|
return undefined;
|
|
26998
|
-
|
|
26999
|
-
|
|
27000
|
-
|
|
27001
|
-
if (
|
|
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("."))
|
|
27477
|
+
while (alternatives.wrapped) {
|
|
27478
|
+
st = st.slice(1, -1).trim();
|
|
27479
|
+
alternatives = splitSyncJqExpression(st, "//");
|
|
27480
|
+
if (!alternatives)
|
|
27018
27481
|
return undefined;
|
|
27019
|
-
|
|
27020
|
-
|
|
27021
|
-
|
|
27022
|
-
|
|
27023
|
-
|
|
27024
|
-
|
|
27025
|
-
|
|
27026
|
-
|
|
27027
|
-
|
|
27028
|
-
|
|
27482
|
+
}
|
|
27483
|
+
if (alternatives.parts.length > 1) {
|
|
27484
|
+
const lhs = alternatives.parts[0];
|
|
27485
|
+
const rhs = alternatives.parts.slice(1).join("//");
|
|
27486
|
+
const lVals = this.evalSyncJqPathOps(item, lhs);
|
|
27487
|
+
if (lVals === undefined)
|
|
27488
|
+
return undefined;
|
|
27489
|
+
// Validate both sides before admitting the fast path, even if lhs wins.
|
|
27490
|
+
let rVals = this.evalSyncJqPathOps(item, rhs);
|
|
27491
|
+
if (rVals === undefined) {
|
|
27492
|
+
try {
|
|
27493
|
+
rVals = [JSON.parse(rhs)];
|
|
27029
27494
|
}
|
|
27030
|
-
|
|
27031
|
-
|
|
27032
|
-
rest = rest.slice(2);
|
|
27033
|
-
continue;
|
|
27495
|
+
catch {
|
|
27496
|
+
return undefined;
|
|
27034
27497
|
}
|
|
27035
|
-
|
|
27036
|
-
|
|
27037
|
-
|
|
27038
|
-
|
|
27039
|
-
|
|
27498
|
+
}
|
|
27499
|
+
const truthy = lVals.filter(v => v !== null && v !== undefined && v !== false);
|
|
27500
|
+
return truthy.length > 0 ? truthy : rVals;
|
|
27501
|
+
}
|
|
27502
|
+
const pipeSplit = splitSyncJqExpression(st, "|");
|
|
27503
|
+
if (pipeSplit && pipeSplit.parts.length > 1) {
|
|
27504
|
+
let cur = [item];
|
|
27505
|
+
for (const pStage of pipeSplit.parts) {
|
|
27506
|
+
const next = [];
|
|
27507
|
+
for (const it of cur) {
|
|
27508
|
+
const r = this.evalSyncJqPathOps(it, pStage);
|
|
27509
|
+
if (r === undefined)
|
|
27510
|
+
return undefined;
|
|
27511
|
+
for (const rv of r)
|
|
27512
|
+
next.push(rv);
|
|
27040
27513
|
}
|
|
27041
|
-
|
|
27514
|
+
cur = next;
|
|
27042
27515
|
}
|
|
27043
|
-
|
|
27516
|
+
return cur;
|
|
27044
27517
|
}
|
|
27045
|
-
|
|
27046
|
-
|
|
27047
|
-
|
|
27518
|
+
if (st === ".")
|
|
27519
|
+
return [item];
|
|
27520
|
+
const dotArithM = /^\.\s*([+*\/%-])\s*(-?[0-9]+(?:\.[0-9]+)?)$/.exec(st);
|
|
27521
|
+
if (dotArithM && typeof item === "number") {
|
|
27522
|
+
const op = dotArithM[1];
|
|
27523
|
+
const rhs = Number(dotArithM[2]);
|
|
27524
|
+
if ((op === "/" || op === "%") && rhs === 0)
|
|
27525
|
+
return undefined;
|
|
27526
|
+
return [op === "+" ? item + rhs : op === "-" ? item - rhs : op === "*" ? item * rhs : op === "/" ? item / rhs : item % rhs];
|
|
27527
|
+
}
|
|
27528
|
+
if (st === "floor")
|
|
27529
|
+
return typeof item === "number" ? [Math.floor(item)] : undefined;
|
|
27530
|
+
if (st === "ceil")
|
|
27531
|
+
return typeof item === "number" ? [Math.ceil(item)] : undefined;
|
|
27532
|
+
if (st === "round")
|
|
27533
|
+
return typeof item === "number" ? [Math.round(item)] : undefined;
|
|
27534
|
+
if (st === "abs")
|
|
27535
|
+
return typeof item === "number" ? [Math.abs(item)] : undefined;
|
|
27536
|
+
if (st === "utf8bytelength")
|
|
27537
|
+
return typeof item === "string" ? [Buffer.byteLength(item, "utf8")] : undefined;
|
|
27538
|
+
if (st === "explode")
|
|
27539
|
+
return typeof item === "string" ? [Array.from(item, c => c.codePointAt(0))] : undefined;
|
|
27540
|
+
if (st === "implode") {
|
|
27541
|
+
if (!Array.isArray(item) || !item.every(x => typeof x === "number" && Number.isInteger(x) && x >= 0 && x <= 0x10ffff))
|
|
27542
|
+
return undefined;
|
|
27543
|
+
return [String.fromCodePoint(...item)];
|
|
27048
27544
|
}
|
|
27049
|
-
|
|
27545
|
+
if (st === "transpose") {
|
|
27546
|
+
if (!Array.isArray(item) || !item.every(row => Array.isArray(row)))
|
|
27547
|
+
return undefined;
|
|
27548
|
+
const rows = item;
|
|
27549
|
+
const maxCols = rows.reduce((m, r) => Math.max(m, r.length), 0);
|
|
27550
|
+
const trans = [];
|
|
27551
|
+
for (let c = 0; c < maxCols; c++) {
|
|
27552
|
+
trans.push(rows.map(r => c < r.length ? r[c] : null));
|
|
27553
|
+
}
|
|
27554
|
+
return [trans];
|
|
27555
|
+
}
|
|
27556
|
+
const idxFnM = /^(index|rindex|indices)\(\s*"([^"\\]*)"\s*\)$/.exec(st);
|
|
27557
|
+
if (idxFnM && typeof item === "string") {
|
|
27558
|
+
const fn = idxFnM[1];
|
|
27559
|
+
const sub = idxFnM[2];
|
|
27560
|
+
const found = [];
|
|
27561
|
+
if (sub.length > 0) {
|
|
27562
|
+
let pos = 0;
|
|
27563
|
+
while ((pos = item.indexOf(sub, pos)) !== -1) {
|
|
27564
|
+
found.push(Array.from(item.slice(0, pos)).length);
|
|
27565
|
+
pos += 1;
|
|
27566
|
+
}
|
|
27567
|
+
}
|
|
27568
|
+
if (fn === "indices")
|
|
27569
|
+
return [found];
|
|
27570
|
+
if (fn === "index")
|
|
27571
|
+
return [found.length > 0 ? found[0] : null];
|
|
27572
|
+
return [found.length > 0 ? found[found.length - 1] : null];
|
|
27573
|
+
}
|
|
27574
|
+
if (st === "length") {
|
|
27575
|
+
if (item === null || item === undefined)
|
|
27576
|
+
return [0];
|
|
27577
|
+
if (typeof item === "string")
|
|
27578
|
+
return [Array.from(item).length];
|
|
27579
|
+
if (typeof item === "number")
|
|
27580
|
+
return [Math.abs(item)];
|
|
27581
|
+
if (Array.isArray(item))
|
|
27582
|
+
return [item.length];
|
|
27583
|
+
if (typeof item === "object")
|
|
27584
|
+
return [Object.keys(item).length];
|
|
27050
27585
|
return undefined;
|
|
27051
27586
|
}
|
|
27052
|
-
|
|
27053
|
-
|
|
27054
|
-
|
|
27055
|
-
|
|
27056
|
-
|
|
27057
|
-
|
|
27058
|
-
|
|
27059
|
-
|
|
27060
|
-
|
|
27061
|
-
|
|
27062
|
-
|
|
27063
|
-
|
|
27064
|
-
|
|
27065
|
-
|
|
27066
|
-
|
|
27067
|
-
|
|
27068
|
-
|
|
27069
|
-
|
|
27070
|
-
|
|
27071
|
-
|
|
27072
|
-
|
|
27073
|
-
|
|
27587
|
+
if (st === "keys") {
|
|
27588
|
+
if (Array.isArray(item))
|
|
27589
|
+
return [item.map((_, idx) => idx)];
|
|
27590
|
+
if (item && typeof item === "object")
|
|
27591
|
+
return [Object.keys(item).sort()];
|
|
27592
|
+
return undefined;
|
|
27593
|
+
}
|
|
27594
|
+
if (st === "keys[]") {
|
|
27595
|
+
if (Array.isArray(item))
|
|
27596
|
+
return item.map((_, idx) => idx);
|
|
27597
|
+
if (item && typeof item === "object")
|
|
27598
|
+
return Object.keys(item).sort();
|
|
27599
|
+
return undefined;
|
|
27600
|
+
}
|
|
27601
|
+
if (st === "values") {
|
|
27602
|
+
return item === null || item === undefined ? [] : [item];
|
|
27603
|
+
}
|
|
27604
|
+
if (st === "empty")
|
|
27605
|
+
return [];
|
|
27606
|
+
if (st === "not")
|
|
27607
|
+
return [!(item !== false && item !== null && item !== undefined)];
|
|
27608
|
+
if (st === "any")
|
|
27609
|
+
return Array.isArray(item) ? [item.some(x => x !== false && x !== null && x !== undefined)] : undefined;
|
|
27610
|
+
if (st === "all")
|
|
27611
|
+
return Array.isArray(item) ? [item.every(x => x !== false && x !== null && x !== undefined)] : undefined;
|
|
27612
|
+
if (st === "keys_unsorted") {
|
|
27613
|
+
if (Array.isArray(item))
|
|
27614
|
+
return [item.map((_, idx) => idx)];
|
|
27615
|
+
if (item && typeof item === "object")
|
|
27616
|
+
return [Object.keys(item)];
|
|
27617
|
+
return undefined;
|
|
27618
|
+
}
|
|
27619
|
+
if (st === "flatten")
|
|
27620
|
+
return Array.isArray(item) ? [item.flat(Infinity)] : undefined;
|
|
27621
|
+
const flatM = /^flatten\(\s*([0-9]{1,2})\s*\)$/.exec(st);
|
|
27622
|
+
if (flatM)
|
|
27623
|
+
return Array.isArray(item) ? [item.flat(Number(flatM[1]))] : undefined;
|
|
27624
|
+
if (st === "sort") {
|
|
27625
|
+
if (!Array.isArray(item))
|
|
27626
|
+
return undefined;
|
|
27627
|
+
if (item.every(x => typeof x === "number"))
|
|
27628
|
+
return [[...item].sort((a, b) => a - b)];
|
|
27629
|
+
if (item.every(x => typeof x === "string"))
|
|
27630
|
+
return [[...item].sort()];
|
|
27631
|
+
return undefined;
|
|
27632
|
+
}
|
|
27633
|
+
if (st === "tojson")
|
|
27634
|
+
return [JSON.stringify(item)];
|
|
27635
|
+
if (st === "fromjson") {
|
|
27636
|
+
if (typeof item !== "string")
|
|
27637
|
+
return undefined;
|
|
27638
|
+
try {
|
|
27639
|
+
return [JSON.parse(item)];
|
|
27640
|
+
}
|
|
27641
|
+
catch {
|
|
27642
|
+
return undefined;
|
|
27643
|
+
}
|
|
27644
|
+
}
|
|
27645
|
+
const mvM = /^map_values\(\s*(.+)\s*\)$/.exec(st);
|
|
27646
|
+
if (mvM && item && typeof item === "object") {
|
|
27647
|
+
const subExpr = mvM[1];
|
|
27648
|
+
if (Array.isArray(item)) {
|
|
27649
|
+
const outArr = [];
|
|
27650
|
+
for (const el of item) {
|
|
27651
|
+
const r = this.evalSyncJqPathOps(el, subExpr);
|
|
27652
|
+
if (!r || r.length !== 1)
|
|
27653
|
+
return undefined;
|
|
27654
|
+
outArr.push(r[0]);
|
|
27655
|
+
}
|
|
27656
|
+
return [outArr];
|
|
27657
|
+
}
|
|
27658
|
+
const outObj = {};
|
|
27659
|
+
for (const [k, v] of Object.entries(item)) {
|
|
27660
|
+
const r = this.evalSyncJqPathOps(v, subExpr);
|
|
27661
|
+
if (!r || r.length !== 1)
|
|
27662
|
+
return undefined;
|
|
27663
|
+
outObj[k] = r[0];
|
|
27664
|
+
}
|
|
27665
|
+
return [outObj];
|
|
27666
|
+
}
|
|
27667
|
+
const byM = /^(sort_by|unique_by|group_by|min_by|max_by)\(\s*(\.[a-zA-Z_][a-zA-Z0-9_.]*)\s*\)$/.exec(st);
|
|
27668
|
+
if (byM && Array.isArray(item)) {
|
|
27669
|
+
const fn = byM[1];
|
|
27670
|
+
const kPath = byM[2];
|
|
27671
|
+
const keyed = [];
|
|
27672
|
+
for (const el of item) {
|
|
27673
|
+
const kv = this.evalSyncJqPathOps(el, kPath);
|
|
27674
|
+
if (!kv || kv.length !== 1)
|
|
27675
|
+
return undefined;
|
|
27676
|
+
const k0 = kv[0];
|
|
27677
|
+
if (typeof k0 !== "string" && typeof k0 !== "number" && typeof k0 !== "boolean" && k0 !== null)
|
|
27678
|
+
return undefined;
|
|
27679
|
+
keyed.push({ el, k: k0 });
|
|
27680
|
+
}
|
|
27681
|
+
const cmpK = (a, b) => {
|
|
27682
|
+
const rank = (value) => value === null ? 0 : value === false ? 1 : value === true ? 2 : typeof value === "number" ? 3 : 4;
|
|
27683
|
+
const typeOrder = rank(a) - rank(b);
|
|
27684
|
+
if (typeOrder !== 0)
|
|
27685
|
+
return typeOrder;
|
|
27686
|
+
if (typeof a === "number" && typeof b === "number")
|
|
27687
|
+
return a - b;
|
|
27688
|
+
const sa = String(a);
|
|
27689
|
+
const sb = String(b);
|
|
27690
|
+
return sa < sb ? -1 : sa > sb ? 1 : 0;
|
|
27691
|
+
};
|
|
27692
|
+
keyed.sort((a, b) => cmpK(a.k, b.k));
|
|
27693
|
+
if (fn === "min_by")
|
|
27694
|
+
return [keyed.length > 0 ? keyed[0].el : null];
|
|
27695
|
+
if (fn === "max_by")
|
|
27696
|
+
return [keyed.length > 0 ? keyed[keyed.length - 1].el : null];
|
|
27697
|
+
if (fn === "sort_by")
|
|
27698
|
+
return [keyed.map(p => p.el)];
|
|
27699
|
+
if (fn === "unique_by") {
|
|
27700
|
+
const u = [];
|
|
27701
|
+
for (let i = 0; i < keyed.length; i++) {
|
|
27702
|
+
if (i === 0 || cmpK(keyed[i].k, keyed[i - 1].k) !== 0)
|
|
27703
|
+
u.push(keyed[i].el);
|
|
27704
|
+
}
|
|
27705
|
+
return [u];
|
|
27706
|
+
}
|
|
27707
|
+
const groups = [];
|
|
27708
|
+
for (let i = 0; i < keyed.length; i++) {
|
|
27709
|
+
if (i === 0 || cmpK(keyed[i].k, keyed[i - 1].k) !== 0)
|
|
27710
|
+
groups.push([keyed[i].el]);
|
|
27711
|
+
else
|
|
27712
|
+
groups[groups.length - 1].push(keyed[i].el);
|
|
27713
|
+
}
|
|
27714
|
+
return [groups];
|
|
27715
|
+
}
|
|
27716
|
+
if (st === "first") {
|
|
27717
|
+
return Array.isArray(item) ? [item.length > 0 ? item[0] : null] : undefined;
|
|
27718
|
+
}
|
|
27719
|
+
if (st === "last") {
|
|
27720
|
+
return Array.isArray(item) ? [item.length > 0 ? item[item.length - 1] : null] : undefined;
|
|
27721
|
+
}
|
|
27722
|
+
if (st === "reverse") {
|
|
27723
|
+
return Array.isArray(item) ? [[...item].reverse()] : undefined;
|
|
27724
|
+
}
|
|
27725
|
+
// Use the jq engine for its complete type ordering and equality semantics.
|
|
27726
|
+
if (st === "unique")
|
|
27727
|
+
return undefined;
|
|
27728
|
+
if (st === "add") {
|
|
27729
|
+
if (!Array.isArray(item))
|
|
27730
|
+
return undefined;
|
|
27731
|
+
if (item.length === 0)
|
|
27732
|
+
return [null];
|
|
27733
|
+
if (item.every(x => typeof x === "number"))
|
|
27734
|
+
return [item.reduce((a, b) => a + b, 0)];
|
|
27735
|
+
if (item.every(x => typeof x === "string"))
|
|
27736
|
+
return [item.join("")];
|
|
27737
|
+
if (item.every(x => Array.isArray(x)))
|
|
27738
|
+
return [item.flat()];
|
|
27739
|
+
return undefined;
|
|
27740
|
+
}
|
|
27741
|
+
if (st === "min" || st === "max") {
|
|
27742
|
+
if (!Array.isArray(item))
|
|
27743
|
+
return undefined;
|
|
27744
|
+
if (item.length === 0)
|
|
27745
|
+
return [null];
|
|
27746
|
+
if (item.every(x => typeof x === "number")) {
|
|
27747
|
+
return [st === "min" ? Math.min(...item) : Math.max(...item)];
|
|
27748
|
+
}
|
|
27749
|
+
if (item.every(x => typeof x === "string")) {
|
|
27750
|
+
const sorted = [...item].sort();
|
|
27751
|
+
return [st === "min" ? sorted[0] : sorted[sorted.length - 1]];
|
|
27752
|
+
}
|
|
27753
|
+
return undefined;
|
|
27754
|
+
}
|
|
27755
|
+
if (st === "to_entries") {
|
|
27756
|
+
if (item && typeof item === "object" && !Array.isArray(item)) {
|
|
27757
|
+
return [Object.entries(item).map(([key, value]) => ({ key, value }))];
|
|
27758
|
+
}
|
|
27759
|
+
return undefined;
|
|
27760
|
+
}
|
|
27761
|
+
if (st === "from_entries") {
|
|
27762
|
+
if (!Array.isArray(item))
|
|
27763
|
+
return undefined;
|
|
27764
|
+
const obj = {};
|
|
27765
|
+
for (const el of item) {
|
|
27766
|
+
if (!el || typeof el !== "object" || Array.isArray(el))
|
|
27767
|
+
return undefined;
|
|
27768
|
+
const rec = el;
|
|
27769
|
+
const k = rec.key ?? rec.name ?? rec.k;
|
|
27770
|
+
if (typeof k !== "string")
|
|
27771
|
+
return undefined;
|
|
27772
|
+
obj[k] = Object.hasOwn(rec, "value") ? rec.value : (Object.hasOwn(rec, "v") ? rec.v : null);
|
|
27773
|
+
}
|
|
27774
|
+
return [obj];
|
|
27775
|
+
}
|
|
27776
|
+
if (st === "tonumber") {
|
|
27777
|
+
if (typeof item === "number")
|
|
27778
|
+
return [item];
|
|
27779
|
+
if (typeof item === "string" && /^[ \t]*[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?[ \t]*$/.test(item))
|
|
27780
|
+
return [Number(item)];
|
|
27781
|
+
return undefined;
|
|
27782
|
+
}
|
|
27783
|
+
if (st === "tostring") {
|
|
27784
|
+
return [typeof item === "string" ? item : JSON.stringify(item)];
|
|
27785
|
+
}
|
|
27786
|
+
if (st === "type") {
|
|
27787
|
+
return [item === null ? "null" : Array.isArray(item) ? "array" : typeof item];
|
|
27788
|
+
}
|
|
27789
|
+
if (st === "ascii_upcase") {
|
|
27790
|
+
return typeof item === "string" ? [item.replace(/[a-z]/g, ch => String.fromCharCode(ch.charCodeAt(0) - 32))] : undefined;
|
|
27791
|
+
}
|
|
27792
|
+
if (st === "ascii_downcase") {
|
|
27793
|
+
return typeof item === "string" ? [item.replace(/[A-Z]/g, ch => String.fromCharCode(ch.charCodeAt(0) + 32))] : undefined;
|
|
27794
|
+
}
|
|
27795
|
+
const strFnM = /^(join|split|ltrimstr|rtrimstr|startswith|endswith|contains)\(\s*"([^"\\]*)"\s*\)$/.exec(st);
|
|
27796
|
+
if (strFnM) {
|
|
27797
|
+
const fn = strFnM[1];
|
|
27798
|
+
const arg = strFnM[2];
|
|
27799
|
+
if (fn === "join") {
|
|
27800
|
+
if (!Array.isArray(item) || !item.every(x => typeof x === "string" || typeof x === "number" || typeof x === "boolean" || x === null))
|
|
27801
|
+
return undefined;
|
|
27802
|
+
return [item.map(x => x === null ? "" : String(x)).join(arg)];
|
|
27803
|
+
}
|
|
27804
|
+
if (fn === "split")
|
|
27805
|
+
return typeof item === "string" ? [item.split(arg)] : undefined;
|
|
27806
|
+
if (fn === "ltrimstr")
|
|
27807
|
+
return typeof item === "string" ? [item.startsWith(arg) ? item.slice(arg.length) : item] : undefined;
|
|
27808
|
+
if (fn === "rtrimstr")
|
|
27809
|
+
return typeof item === "string" ? [arg.length > 0 && item.endsWith(arg) ? item.slice(0, -arg.length) : item] : undefined;
|
|
27810
|
+
if (fn === "startswith")
|
|
27811
|
+
return typeof item === "string" ? [item.startsWith(arg)] : undefined;
|
|
27812
|
+
if (fn === "endswith")
|
|
27813
|
+
return typeof item === "string" ? [item.endsWith(arg)] : undefined;
|
|
27814
|
+
if (fn === "contains") {
|
|
27815
|
+
if (typeof item === "string")
|
|
27816
|
+
return [item.includes(arg)];
|
|
27817
|
+
return undefined;
|
|
27818
|
+
}
|
|
27819
|
+
}
|
|
27820
|
+
const hasM = /^has\(\s*"([^"\\]+)"\s*\)$/.exec(st);
|
|
27821
|
+
if (hasM) {
|
|
27822
|
+
if (item && typeof item === "object" && !Array.isArray(item))
|
|
27823
|
+
return [Object.hasOwn(item, hasM[1])];
|
|
27824
|
+
return undefined;
|
|
27825
|
+
}
|
|
27826
|
+
const mapM = /^map\(\s*(.+)\s*\)$/.exec(st);
|
|
27827
|
+
if (mapM) {
|
|
27828
|
+
if (!Array.isArray(item))
|
|
27829
|
+
return undefined;
|
|
27830
|
+
const mapped = [];
|
|
27831
|
+
for (const el of item) {
|
|
27832
|
+
const subRes = this.evalSyncJqPathOps(el, mapM[1]);
|
|
27833
|
+
if (subRes === undefined)
|
|
27834
|
+
return undefined;
|
|
27835
|
+
for (const v of subRes)
|
|
27836
|
+
mapped.push(v);
|
|
27837
|
+
}
|
|
27838
|
+
return [mapped];
|
|
27839
|
+
}
|
|
27840
|
+
const selM = /^select\(\s*(\.[a-zA-Z_][a-zA-Z0-9_.]*)\s*(?:(==|!=|>=|<=|>|<)\s*(.+))?\s*\)$/.exec(st);
|
|
27841
|
+
if (selM) {
|
|
27842
|
+
const fVals = this.evalSyncJqPathOps(item, selM[1]);
|
|
27843
|
+
if (!fVals || fVals.length !== 1)
|
|
27844
|
+
return undefined;
|
|
27845
|
+
const lv = fVals[0];
|
|
27846
|
+
if (!selM[2]) {
|
|
27847
|
+
return lv !== null && lv !== undefined && lv !== false ? [item] : [];
|
|
27848
|
+
}
|
|
27849
|
+
let rv;
|
|
27850
|
+
try {
|
|
27851
|
+
rv = JSON.parse(selM[3].trim());
|
|
27852
|
+
}
|
|
27853
|
+
catch {
|
|
27854
|
+
return undefined;
|
|
27855
|
+
}
|
|
27856
|
+
// The full jq evaluator owns structural equality and jq ordering.
|
|
27857
|
+
if ((typeof lv === "object" && lv !== null) || (typeof rv === "object" && rv !== null))
|
|
27858
|
+
return undefined;
|
|
27859
|
+
const op = selM[2];
|
|
27860
|
+
let ok = false;
|
|
27861
|
+
if (op === "==")
|
|
27862
|
+
ok = lv === rv;
|
|
27863
|
+
else if (op === "!=")
|
|
27864
|
+
ok = lv !== rv;
|
|
27865
|
+
else if (typeof lv === "number" && typeof rv === "number") {
|
|
27866
|
+
if (op === ">")
|
|
27867
|
+
ok = lv > rv;
|
|
27868
|
+
else if (op === ">=")
|
|
27869
|
+
ok = lv >= rv;
|
|
27870
|
+
else if (op === "<")
|
|
27871
|
+
ok = lv < rv;
|
|
27872
|
+
else if (op === "<=")
|
|
27873
|
+
ok = lv <= rv;
|
|
27874
|
+
}
|
|
27875
|
+
else
|
|
27876
|
+
return undefined;
|
|
27877
|
+
return ok ? [item] : [];
|
|
27878
|
+
}
|
|
27879
|
+
if (!st.startsWith("."))
|
|
27880
|
+
return undefined;
|
|
27881
|
+
let rest = st.slice(1);
|
|
27882
|
+
const ops = [];
|
|
27883
|
+
while (rest.length > 0) {
|
|
27884
|
+
if (rest.startsWith("."))
|
|
27885
|
+
rest = rest.slice(1);
|
|
27886
|
+
const propM = /^([a-zA-Z_][a-zA-Z0-9_]*)/.exec(rest);
|
|
27887
|
+
if (propM) {
|
|
27888
|
+
ops.push({ kind: "prop", key: propM[1] });
|
|
27889
|
+
rest = rest.slice(propM[1].length);
|
|
27890
|
+
continue;
|
|
27891
|
+
}
|
|
27892
|
+
if (rest.startsWith("[]")) {
|
|
27893
|
+
ops.push({ kind: "iter" });
|
|
27894
|
+
rest = rest.slice(2);
|
|
27895
|
+
continue;
|
|
27896
|
+
}
|
|
27897
|
+
const idxM = /^\[(-?[0-9]+)\]/.exec(rest);
|
|
27898
|
+
if (idxM) {
|
|
27899
|
+
ops.push({ kind: "index", idx: Number(idxM[1]) });
|
|
27900
|
+
rest = rest.slice(idxM[0].length);
|
|
27901
|
+
continue;
|
|
27902
|
+
}
|
|
27903
|
+
return undefined;
|
|
27904
|
+
}
|
|
27905
|
+
let cur = [item];
|
|
27906
|
+
for (const op of ops) {
|
|
27907
|
+
const next = [];
|
|
27908
|
+
for (const it of cur) {
|
|
27909
|
+
if (op.kind === "prop") {
|
|
27910
|
+
if (it === null || it === undefined)
|
|
27911
|
+
next.push(null);
|
|
27912
|
+
else if (typeof it === "object" && !Array.isArray(it))
|
|
27913
|
+
next.push(Object.hasOwn(it, op.key) ? it[op.key] ?? null : null);
|
|
27914
|
+
else
|
|
27915
|
+
return undefined;
|
|
27916
|
+
}
|
|
27917
|
+
else if (op.kind === "index") {
|
|
27918
|
+
if (it === null || it === undefined)
|
|
27919
|
+
next.push(null);
|
|
27920
|
+
else if (Array.isArray(it)) {
|
|
27921
|
+
const i = op.idx < 0 ? it.length + op.idx : op.idx;
|
|
27922
|
+
next.push(i >= 0 && i < it.length ? it[i] : null);
|
|
27074
27923
|
}
|
|
27075
|
-
else
|
|
27076
|
-
|
|
27077
|
-
|
|
27078
|
-
|
|
27079
|
-
|
|
27080
|
-
|
|
27081
|
-
|
|
27082
|
-
next.push(item[k]);
|
|
27083
|
-
}
|
|
27084
|
-
else
|
|
27085
|
-
return undefined;
|
|
27924
|
+
else
|
|
27925
|
+
return undefined;
|
|
27926
|
+
}
|
|
27927
|
+
else if (op.kind === "iter") {
|
|
27928
|
+
if (Array.isArray(it)) {
|
|
27929
|
+
for (const el of it)
|
|
27930
|
+
next.push(el);
|
|
27086
27931
|
}
|
|
27087
|
-
else if (
|
|
27088
|
-
|
|
27089
|
-
next.push(
|
|
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;
|
|
27932
|
+
else if (it && typeof it === "object") {
|
|
27933
|
+
for (const k of Object.keys(it))
|
|
27934
|
+
next.push(it[k]);
|
|
27096
27935
|
}
|
|
27097
|
-
else
|
|
27098
|
-
|
|
27099
|
-
|
|
27100
|
-
|
|
27101
|
-
|
|
27102
|
-
|
|
27103
|
-
|
|
27936
|
+
else
|
|
27937
|
+
return undefined;
|
|
27938
|
+
}
|
|
27939
|
+
}
|
|
27940
|
+
cur = next;
|
|
27941
|
+
}
|
|
27942
|
+
return cur;
|
|
27943
|
+
}
|
|
27944
|
+
evalSyncJq(input, opArgs) {
|
|
27945
|
+
let rawOut = false;
|
|
27946
|
+
let compactOut = false;
|
|
27947
|
+
let filter;
|
|
27948
|
+
if (opArgs.length === 1 && !opArgs[0].startsWith("-")) {
|
|
27949
|
+
filter = opArgs[0];
|
|
27950
|
+
}
|
|
27951
|
+
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")) {
|
|
27952
|
+
rawOut = ["-r", "-rc", "-cr", "--raw-output"].includes(opArgs[0]);
|
|
27953
|
+
compactOut = ["-c", "-rc", "-cr", "--compact-output"].includes(opArgs[0]);
|
|
27954
|
+
filter = opArgs[1];
|
|
27955
|
+
}
|
|
27956
|
+
if (!filter)
|
|
27957
|
+
return undefined;
|
|
27958
|
+
let current = [];
|
|
27959
|
+
try {
|
|
27960
|
+
current = [JSON.parse(input)];
|
|
27961
|
+
}
|
|
27962
|
+
catch {
|
|
27963
|
+
if (!input.includes("\n"))
|
|
27964
|
+
return undefined;
|
|
27965
|
+
try {
|
|
27966
|
+
for (const line of input.split("\n")) {
|
|
27967
|
+
const t = line.trim();
|
|
27968
|
+
if (t.length > 0)
|
|
27969
|
+
current.push(JSON.parse(t));
|
|
27970
|
+
}
|
|
27971
|
+
if (current.length === 0)
|
|
27972
|
+
return undefined;
|
|
27973
|
+
}
|
|
27974
|
+
catch {
|
|
27975
|
+
return undefined;
|
|
27976
|
+
}
|
|
27977
|
+
}
|
|
27978
|
+
const trimmedFilter = filter.trim();
|
|
27979
|
+
if (trimmedFilter.startsWith("[") && trimmedFilter.endsWith("]")) {
|
|
27980
|
+
const innerFilter = trimmedFilter.slice(1, -1).trim();
|
|
27981
|
+
const innerArgs = rawOut || compactOut ? [compactOut ? "-c" : "-r", innerFilter] : [innerFilter];
|
|
27982
|
+
const outArrays = [];
|
|
27983
|
+
for (const item of current) {
|
|
27984
|
+
const innerStages = splitSyncJqExpression(innerFilter, "|");
|
|
27985
|
+
if (!innerStages)
|
|
27986
|
+
return undefined;
|
|
27987
|
+
let subCur = [item];
|
|
27988
|
+
for (const st of innerStages.parts) {
|
|
27989
|
+
const commas = splitSyncJqExpression(st, ",");
|
|
27990
|
+
if (!commas)
|
|
27991
|
+
return undefined;
|
|
27992
|
+
const commaParts = commas.parts;
|
|
27993
|
+
const next = [];
|
|
27994
|
+
for (const it of subCur) {
|
|
27995
|
+
for (const part of commaParts) {
|
|
27996
|
+
const res = this.evalSyncJqPathOps(it, part);
|
|
27997
|
+
if (res === undefined)
|
|
27998
|
+
return undefined;
|
|
27999
|
+
for (const v of res)
|
|
28000
|
+
next.push(v);
|
|
28001
|
+
}
|
|
27104
28002
|
}
|
|
28003
|
+
subCur = next;
|
|
27105
28004
|
}
|
|
27106
|
-
|
|
28005
|
+
outArrays.push(subCur);
|
|
28006
|
+
}
|
|
28007
|
+
void innerArgs;
|
|
28008
|
+
return outArrays.map(val => JSON.stringify(val ?? null, null, compactOut ? undefined : 2));
|
|
28009
|
+
}
|
|
28010
|
+
const stages = splitSyncJqExpression(filter, "|");
|
|
28011
|
+
if (!stages)
|
|
28012
|
+
return undefined;
|
|
28013
|
+
for (const st of stages.parts) {
|
|
28014
|
+
const commas = splitSyncJqExpression(st, ",");
|
|
28015
|
+
if (!commas)
|
|
28016
|
+
return undefined;
|
|
28017
|
+
const commaParts = commas.parts;
|
|
28018
|
+
const next = [];
|
|
28019
|
+
for (const item of current) {
|
|
28020
|
+
for (const part of commaParts) {
|
|
28021
|
+
const res = this.evalSyncJqPathOps(item, part);
|
|
28022
|
+
if (res === undefined)
|
|
28023
|
+
return undefined;
|
|
28024
|
+
for (const v of res)
|
|
28025
|
+
next.push(v);
|
|
28026
|
+
}
|
|
28027
|
+
}
|
|
28028
|
+
current = next;
|
|
28029
|
+
}
|
|
28030
|
+
return current.map(val => (rawOut && typeof val === "string" ? val : JSON.stringify(val ?? null, null, compactOut ? undefined : 2)));
|
|
28031
|
+
}
|
|
28032
|
+
evalSyncDirname(args) {
|
|
28033
|
+
let idx = 0;
|
|
28034
|
+
if (args[0] === "--")
|
|
28035
|
+
idx = 1;
|
|
28036
|
+
else if (args[0] !== undefined && args[0].startsWith("-") && args[0] !== "-")
|
|
28037
|
+
return undefined;
|
|
28038
|
+
if (idx >= args.length)
|
|
28039
|
+
return undefined;
|
|
28040
|
+
const out = [];
|
|
28041
|
+
for (let i = idx; i < args.length; i++) {
|
|
28042
|
+
const p = args[i];
|
|
28043
|
+
if (p.includes("\0"))
|
|
28044
|
+
return undefined;
|
|
28045
|
+
if (idx === 0 && p.startsWith("-") && p !== "-")
|
|
28046
|
+
return undefined;
|
|
28047
|
+
const parent = dirname(p);
|
|
28048
|
+
let pEnd = parent.length;
|
|
28049
|
+
while (pEnd > 1 && parent[pEnd - 1] === "/")
|
|
28050
|
+
pEnd--;
|
|
28051
|
+
out.push(parent.slice(0, pEnd));
|
|
28052
|
+
}
|
|
28053
|
+
return out.join("\n");
|
|
28054
|
+
}
|
|
28055
|
+
evalSyncBasename(args) {
|
|
28056
|
+
let multiple = false;
|
|
28057
|
+
let suffix;
|
|
28058
|
+
let idx = 0;
|
|
28059
|
+
const operands = [];
|
|
28060
|
+
while (idx < args.length) {
|
|
28061
|
+
const a = args[idx];
|
|
28062
|
+
if (a === "--") {
|
|
28063
|
+
operands.push(...args.slice(idx + 1));
|
|
28064
|
+
break;
|
|
28065
|
+
}
|
|
28066
|
+
if (!a.startsWith("-") || a === "-") {
|
|
28067
|
+
operands.push(a);
|
|
28068
|
+
idx++;
|
|
28069
|
+
continue;
|
|
28070
|
+
}
|
|
28071
|
+
if (a === "-a" || a === "--multiple") {
|
|
28072
|
+
multiple = true;
|
|
28073
|
+
idx++;
|
|
28074
|
+
}
|
|
28075
|
+
else if (a === "-s" || a === "-as" || a === "-sa") {
|
|
28076
|
+
multiple = true;
|
|
28077
|
+
if (idx + 1 >= args.length)
|
|
28078
|
+
return undefined;
|
|
28079
|
+
suffix = args[idx + 1];
|
|
28080
|
+
idx += 2;
|
|
28081
|
+
}
|
|
28082
|
+
else if (a.startsWith("-s") && a.length > 2) {
|
|
28083
|
+
multiple = true;
|
|
28084
|
+
suffix = a.slice(2);
|
|
28085
|
+
idx++;
|
|
28086
|
+
}
|
|
28087
|
+
else {
|
|
28088
|
+
return undefined;
|
|
27107
28089
|
}
|
|
27108
28090
|
}
|
|
27109
|
-
|
|
28091
|
+
if (operands.length === 0)
|
|
28092
|
+
return undefined;
|
|
28093
|
+
if (!multiple && operands.length > 2)
|
|
28094
|
+
return undefined;
|
|
28095
|
+
const effSuffix = multiple ? suffix : operands[1];
|
|
28096
|
+
if (effSuffix !== undefined && effSuffix.includes("\0"))
|
|
28097
|
+
return undefined;
|
|
28098
|
+
const paths = multiple ? operands : [operands[0]];
|
|
28099
|
+
const out = [];
|
|
28100
|
+
for (const p of paths) {
|
|
28101
|
+
if (p.includes("\0"))
|
|
28102
|
+
return undefined;
|
|
28103
|
+
let res = /^\/+$/u.test(p) ? "/" : basename(p);
|
|
28104
|
+
if (effSuffix && res !== effSuffix && res.endsWith(effSuffix)) {
|
|
28105
|
+
res = res.slice(0, -effSuffix.length);
|
|
28106
|
+
}
|
|
28107
|
+
out.push(res);
|
|
28108
|
+
}
|
|
28109
|
+
return out.join("\n");
|
|
27110
28110
|
}
|
|
27111
28111
|
parseSyncCutSpec(spec) {
|
|
27112
28112
|
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)) {
|
|
@@ -27152,11 +28152,28 @@ export class Runtime {
|
|
|
27152
28152
|
evalSyncCut(rawLines, opArgs, byteLocaleMode) {
|
|
27153
28153
|
const norm = [];
|
|
27154
28154
|
let suppressNoDelim = false;
|
|
28155
|
+
let isComplement = false;
|
|
28156
|
+
let outDelim;
|
|
27155
28157
|
for (let ci = 0; ci < opArgs.length; ci++) {
|
|
27156
28158
|
const ca = opArgs[ci];
|
|
27157
28159
|
if (ca === "-s" || ca === "--only-delimited") {
|
|
27158
28160
|
suppressNoDelim = true;
|
|
27159
28161
|
}
|
|
28162
|
+
else if (ca === "--complement") {
|
|
28163
|
+
isComplement = true;
|
|
28164
|
+
}
|
|
28165
|
+
else if (ca.startsWith("--output-delimiter=")) {
|
|
28166
|
+
outDelim = ca.slice("--output-delimiter=".length);
|
|
28167
|
+
if (outDelim.length === 0 || outDelim.includes("\0"))
|
|
28168
|
+
return undefined;
|
|
28169
|
+
}
|
|
28170
|
+
else if (ca === "--output-delimiter") {
|
|
28171
|
+
if (ci + 1 >= opArgs.length)
|
|
28172
|
+
return undefined;
|
|
28173
|
+
outDelim = opArgs[++ci];
|
|
28174
|
+
if (outDelim.length === 0 || outDelim.includes("\0"))
|
|
28175
|
+
return undefined;
|
|
28176
|
+
}
|
|
27160
28177
|
else if (ca.startsWith("-sd") || ca.startsWith("-ds")) {
|
|
27161
28178
|
suppressNoDelim = true;
|
|
27162
28179
|
const rest = ca.slice(3);
|
|
@@ -27167,21 +28184,29 @@ export class Runtime {
|
|
|
27167
28184
|
else
|
|
27168
28185
|
return undefined;
|
|
27169
28186
|
}
|
|
27170
|
-
else if ((ca === "-d" || ca === "-f" || ca === "-c") && ci + 1 < opArgs.length) {
|
|
28187
|
+
else if ((ca === "-d" || ca === "-f" || ca === "-c" || ca === "-b") && ci + 1 < opArgs.length) {
|
|
27171
28188
|
norm.push(ca + opArgs[++ci]);
|
|
27172
28189
|
}
|
|
27173
28190
|
else {
|
|
27174
28191
|
norm.push(ca);
|
|
27175
28192
|
}
|
|
27176
28193
|
}
|
|
27177
|
-
if (!suppressNoDelim && norm.length === 1 && norm[0].startsWith("-c")) {
|
|
27178
|
-
|
|
28194
|
+
if (!suppressNoDelim && outDelim === undefined && norm.length === 1 && (norm[0].startsWith("-c") || norm[0].startsWith("-b"))) {
|
|
28195
|
+
const isByteMode = norm[0].startsWith("-b");
|
|
28196
|
+
if (!isByteMode && byteLocaleMode)
|
|
28197
|
+
return undefined;
|
|
28198
|
+
if (isByteMode && rawLines.some(l => { for (let i = 0; i < l.length; i++)
|
|
28199
|
+
if (l.charCodeAt(i) >= 128)
|
|
28200
|
+
return true; return false; }))
|
|
27179
28201
|
return undefined;
|
|
27180
|
-
const
|
|
27181
|
-
if (!
|
|
28202
|
+
const basePicker = this.parseSyncCutSpec(norm[0].slice(2));
|
|
28203
|
+
if (!basePicker)
|
|
27182
28204
|
return undefined;
|
|
28205
|
+
const picker = isComplement ? (len) => { const s = new Set(basePicker(len)); const r = []; for (let i = 0; i < len; i++)
|
|
28206
|
+
if (!s.has(i))
|
|
28207
|
+
r.push(i); return r; } : basePicker;
|
|
27183
28208
|
return rawLines.map(l => {
|
|
27184
|
-
const chars = Array.from(l);
|
|
28209
|
+
const chars = isByteMode ? l.split("") : Array.from(l);
|
|
27185
28210
|
const idxs = picker(chars.length);
|
|
27186
28211
|
return idxs.map(i => chars[i]).join("");
|
|
27187
28212
|
});
|
|
@@ -27201,9 +28226,13 @@ export class Runtime {
|
|
|
27201
28226
|
}
|
|
27202
28227
|
if (!fArg || !fArg.startsWith("-f"))
|
|
27203
28228
|
return undefined;
|
|
27204
|
-
const
|
|
27205
|
-
if (!
|
|
28229
|
+
const basePicker = this.parseSyncCutSpec(fArg.slice(2));
|
|
28230
|
+
if (!basePicker)
|
|
27206
28231
|
return undefined;
|
|
28232
|
+
const picker = isComplement ? (len) => { const s = new Set(basePicker(len)); const r = []; for (let i = 0; i < len; i++)
|
|
28233
|
+
if (!s.has(i))
|
|
28234
|
+
r.push(i); return r; } : basePicker;
|
|
28235
|
+
const joinDelim = outDelim ?? delim;
|
|
27207
28236
|
const out = [];
|
|
27208
28237
|
for (let li = 0; li < rawLines.length; li++) {
|
|
27209
28238
|
const l = rawLines[li];
|
|
@@ -27214,146 +28243,519 @@ export class Runtime {
|
|
|
27214
28243
|
}
|
|
27215
28244
|
const parts = l.split(delim);
|
|
27216
28245
|
const idxs = picker(parts.length);
|
|
27217
|
-
out.push(idxs.map(i => parts[i]).join(
|
|
28246
|
+
out.push(idxs.map(i => parts[i]).join(joinDelim));
|
|
27218
28247
|
}
|
|
27219
28248
|
return out;
|
|
27220
28249
|
}
|
|
27221
28250
|
evalSyncSed(rawLines, opArgs) {
|
|
27222
28251
|
let quiet = false;
|
|
27223
|
-
let
|
|
27224
|
-
|
|
27225
|
-
|
|
27226
|
-
|
|
27227
|
-
|
|
27228
|
-
|
|
27229
|
-
|
|
27230
|
-
|
|
27231
|
-
|
|
27232
|
-
|
|
27233
|
-
|
|
27234
|
-
|
|
27235
|
-
|
|
27236
|
-
|
|
27237
|
-
|
|
27238
|
-
|
|
27239
|
-
|
|
27240
|
-
|
|
27241
|
-
|
|
27242
|
-
|
|
27243
|
-
|
|
28252
|
+
let isExtended = false;
|
|
28253
|
+
const rawExprs = [];
|
|
28254
|
+
for (let i = 0; i < opArgs.length; i++) {
|
|
28255
|
+
const a = opArgs[i];
|
|
28256
|
+
if (a === "-n" || a === "--quiet" || a === "--silent")
|
|
28257
|
+
quiet = true;
|
|
28258
|
+
else if (a === "-E" || a === "-r" || a === "--regexp-extended")
|
|
28259
|
+
isExtended = true;
|
|
28260
|
+
else if (a === "-En" || a === "-nE" || a === "-rn" || a === "-nr") {
|
|
28261
|
+
quiet = true;
|
|
28262
|
+
isExtended = true;
|
|
28263
|
+
}
|
|
28264
|
+
else if (a === "-e") {
|
|
28265
|
+
if (i + 1 >= opArgs.length)
|
|
28266
|
+
return undefined;
|
|
28267
|
+
rawExprs.push(opArgs[++i]);
|
|
28268
|
+
}
|
|
28269
|
+
else if (!a.startsWith("-") && rawExprs.length === 0 && i === opArgs.length - 1) {
|
|
28270
|
+
rawExprs.push(a);
|
|
28271
|
+
}
|
|
28272
|
+
else {
|
|
27244
28273
|
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
28274
|
}
|
|
27276
|
-
return out;
|
|
27277
28275
|
}
|
|
27278
|
-
if (
|
|
27279
|
-
return undefined;
|
|
27280
|
-
if (!expr.startsWith("s") || expr.length < 4)
|
|
28276
|
+
if (rawExprs.length === 0)
|
|
27281
28277
|
return undefined;
|
|
27282
|
-
const
|
|
27283
|
-
|
|
27284
|
-
|
|
27285
|
-
|
|
27286
|
-
|
|
27287
|
-
|
|
27288
|
-
|
|
27289
|
-
|
|
28278
|
+
const subExprs = [];
|
|
28279
|
+
for (const re of rawExprs) {
|
|
28280
|
+
if (re.includes(";") && !re.startsWith("s;") && !re.startsWith("y;")) {
|
|
28281
|
+
for (const p of re.split(";")) {
|
|
28282
|
+
const t = p.trim();
|
|
28283
|
+
if (t.length > 0)
|
|
28284
|
+
subExprs.push(t);
|
|
28285
|
+
}
|
|
28286
|
+
}
|
|
28287
|
+
else {
|
|
28288
|
+
subExprs.push(re.trim());
|
|
28289
|
+
}
|
|
28290
|
+
}
|
|
28291
|
+
if (subExprs.length === 0)
|
|
27290
28292
|
return undefined;
|
|
27291
|
-
const
|
|
27292
|
-
const
|
|
27293
|
-
|
|
27294
|
-
|
|
27295
|
-
|
|
28293
|
+
const steps = [];
|
|
28294
|
+
for (const rawE of subExprs) {
|
|
28295
|
+
let rest = rawE;
|
|
28296
|
+
let addr;
|
|
28297
|
+
let negated = false;
|
|
28298
|
+
const addrM = /^(?:([1-9][0-9]{0,4}|\$)(?:,([1-9][0-9]{0,4}|\$))?|\/(\^?[a-zA-Z0-9_ :;,=-]+\$?)\/)\s*/.exec(rest);
|
|
28299
|
+
if (addrM) {
|
|
28300
|
+
const startSpec = addrM[1];
|
|
28301
|
+
const endSpec = addrM[2];
|
|
28302
|
+
const patSpec = addrM[3];
|
|
28303
|
+
rest = rest.slice(addrM[0].length);
|
|
28304
|
+
addr = (l, idx1, total) => {
|
|
28305
|
+
if (patSpec !== undefined) {
|
|
28306
|
+
const aStart = patSpec.startsWith("^");
|
|
28307
|
+
const c1 = aStart ? patSpec.slice(1) : patSpec;
|
|
28308
|
+
const aEnd = c1.endsWith("$");
|
|
28309
|
+
const core = aEnd ? c1.slice(0, -1) : c1;
|
|
28310
|
+
if (aStart && aEnd)
|
|
28311
|
+
return l === core;
|
|
28312
|
+
if (aStart)
|
|
28313
|
+
return l.startsWith(core);
|
|
28314
|
+
if (aEnd)
|
|
28315
|
+
return l.endsWith(core);
|
|
28316
|
+
return l.includes(core);
|
|
28317
|
+
}
|
|
28318
|
+
const sNum = startSpec === "$" ? total : Number(startSpec);
|
|
28319
|
+
if (endSpec === undefined)
|
|
28320
|
+
return idx1 === sNum;
|
|
28321
|
+
const eNum = endSpec === "$" ? total : Number(endSpec);
|
|
28322
|
+
return idx1 >= sNum && idx1 <= Math.max(sNum, eNum);
|
|
28323
|
+
};
|
|
28324
|
+
}
|
|
28325
|
+
if (rest.startsWith("!")) {
|
|
28326
|
+
negated = true;
|
|
28327
|
+
rest = rest.slice(1).trim();
|
|
28328
|
+
}
|
|
28329
|
+
if (rest === "d") {
|
|
28330
|
+
steps.push({ addr, negated, kind: "d" });
|
|
28331
|
+
continue;
|
|
28332
|
+
}
|
|
28333
|
+
if (rest === "p") {
|
|
28334
|
+
steps.push({ addr, negated, kind: "p" });
|
|
28335
|
+
continue;
|
|
28336
|
+
}
|
|
28337
|
+
if (rest === "q") {
|
|
28338
|
+
steps.push({ addr, negated, kind: "q" });
|
|
28339
|
+
continue;
|
|
28340
|
+
}
|
|
28341
|
+
if (rest === "=") {
|
|
28342
|
+
steps.push({ addr, negated, kind: "=" });
|
|
28343
|
+
continue;
|
|
28344
|
+
}
|
|
28345
|
+
// Text commands need range state and independent output terminators.
|
|
28346
|
+
// Let the canonical sed executor preserve those byte-level semantics.
|
|
28347
|
+
if (rest.startsWith("i") || rest.startsWith("a") || rest.startsWith("c"))
|
|
28348
|
+
return undefined;
|
|
28349
|
+
if (rest.startsWith("y") && rest.length >= 4) {
|
|
28350
|
+
const delim = rest[1];
|
|
28351
|
+
if (!"/#|:@,;%!".includes(delim))
|
|
28352
|
+
return undefined;
|
|
28353
|
+
const parts = rest.slice(2).split(delim);
|
|
28354
|
+
if (parts.length !== 3 || parts[2] !== "")
|
|
28355
|
+
return undefined;
|
|
28356
|
+
const srcStr = parts[0];
|
|
28357
|
+
const dstStr = parts[1];
|
|
28358
|
+
if (srcStr.includes("\\") || dstStr.includes("\\"))
|
|
28359
|
+
return undefined;
|
|
28360
|
+
const srcChars = Array.from(srcStr);
|
|
28361
|
+
const dstChars = Array.from(dstStr);
|
|
28362
|
+
if (srcChars.length !== dstChars.length)
|
|
28363
|
+
return undefined;
|
|
28364
|
+
const map = new Map();
|
|
28365
|
+
for (let i = 0; i < srcChars.length; i++) {
|
|
28366
|
+
if (!map.has(srcChars[i]))
|
|
28367
|
+
map.set(srcChars[i], dstChars[i]);
|
|
28368
|
+
}
|
|
28369
|
+
steps.push({ addr, negated, kind: "y", map });
|
|
28370
|
+
continue;
|
|
28371
|
+
}
|
|
28372
|
+
if (rest.startsWith("s") && rest.length >= 4) {
|
|
28373
|
+
const delim = rest[1];
|
|
28374
|
+
if (!"/#|:@,;%!".includes(delim))
|
|
28375
|
+
return undefined;
|
|
28376
|
+
const parts = rest.slice(2).split(delim);
|
|
28377
|
+
if (parts.length !== 3)
|
|
28378
|
+
return undefined;
|
|
28379
|
+
const [pat, rep, flags] = parts;
|
|
28380
|
+
if (!/^[giIp1-9]*$/.test(flags) || /\n|\\(?![1-9])/.test(rep))
|
|
28381
|
+
return undefined;
|
|
28382
|
+
const nthDigits = flags.match(/[1-9]/g);
|
|
28383
|
+
if (nthDigits && (nthDigits.length > 1 || flags.includes("g")))
|
|
28384
|
+
return undefined;
|
|
28385
|
+
const nth = nthDigits ? Number(nthDigits[0]) : 0;
|
|
28386
|
+
const global = flags.includes("g") || nth > 0;
|
|
28387
|
+
const ignoreCase = flags.includes("i") || flags.includes("I");
|
|
28388
|
+
const printOnMatch = flags.includes("p");
|
|
28389
|
+
const anchorStart = pat.startsWith("^");
|
|
28390
|
+
const core1 = anchorStart ? pat.slice(1) : pat;
|
|
28391
|
+
const anchorEnd = core1.endsWith("$");
|
|
28392
|
+
const core = anchorEnd ? core1.slice(0, -1) : core1;
|
|
28393
|
+
if (core.length === 0 && !anchorStart && !anchorEnd)
|
|
28394
|
+
return undefined;
|
|
28395
|
+
let reSrc;
|
|
28396
|
+
if (/^[a-zA-Z0-9_ :;,=-]*$/.test(core)) {
|
|
28397
|
+
if (/\\[1-9]/.test(rep))
|
|
28398
|
+
return undefined;
|
|
28399
|
+
reSrc = core.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
28400
|
+
}
|
|
28401
|
+
else if (core === "[ \t]*" || core === "[ \t]+" || core === "[ \\t]*" || core === "[ \\t]+" ||
|
|
28402
|
+
core === "[[:space:]]*" || core === "[[:space:]]+" ||
|
|
28403
|
+
core === "[0-9]+" || core === "[0-9]*" ||
|
|
28404
|
+
core === "[a-zA-Z]+" || core === "[a-zA-Z0-9_]+") {
|
|
28405
|
+
if (/\\[1-9]/.test(rep))
|
|
28406
|
+
return undefined;
|
|
28407
|
+
reSrc = core.replace("[[:space:]]", "[ \\t\\r\\n\\v\\f]");
|
|
28408
|
+
}
|
|
28409
|
+
else if (isExtended && /^[a-zA-Z0-9_ :;,=.+*?|()^\-[\]]+$/.test(core) && !/\([^)]*[+*][^)]*\)[+*?]/.test(core)) {
|
|
28410
|
+
try {
|
|
28411
|
+
const expanded = core.replace(/\[:space:\]/g, " \\t\\r\\n\\v\\f");
|
|
28412
|
+
void new RegExp(expanded);
|
|
28413
|
+
reSrc = expanded;
|
|
28414
|
+
}
|
|
28415
|
+
catch {
|
|
28416
|
+
reSrc = undefined;
|
|
28417
|
+
}
|
|
28418
|
+
}
|
|
28419
|
+
if (reSrc === undefined)
|
|
28420
|
+
return undefined;
|
|
28421
|
+
const fullRe = new RegExp((anchorStart ? "^" : "") + reSrc + (anchorEnd ? "$" : ""), (global ? "g" : "") + (ignoreCase ? "i" : ""));
|
|
28422
|
+
steps.push({ addr, negated, kind: "s", re: fullRe, rep, printOnMatch, nth });
|
|
28423
|
+
continue;
|
|
28424
|
+
}
|
|
27296
28425
|
return undefined;
|
|
27297
|
-
|
|
27298
|
-
|
|
27299
|
-
|
|
27300
|
-
|
|
27301
|
-
|
|
27302
|
-
|
|
27303
|
-
|
|
27304
|
-
|
|
27305
|
-
|
|
27306
|
-
|
|
28426
|
+
}
|
|
28427
|
+
const out = [];
|
|
28428
|
+
const total = rawLines.length;
|
|
28429
|
+
let lastInputIndex = -1;
|
|
28430
|
+
for (let i = 0; i < total; i++) {
|
|
28431
|
+
let l = rawLines[i];
|
|
28432
|
+
const idx1 = i + 1;
|
|
28433
|
+
let deleted = false;
|
|
28434
|
+
let quitNow = false;
|
|
28435
|
+
for (let si = 0; si < steps.length; si++) {
|
|
28436
|
+
const st = steps[si];
|
|
28437
|
+
const addrMatched = st.addr ? st.addr(l, idx1, total) : true;
|
|
28438
|
+
if (st.negated ? addrMatched : !addrMatched)
|
|
28439
|
+
continue;
|
|
28440
|
+
if (st.kind === "d") {
|
|
28441
|
+
deleted = true;
|
|
28442
|
+
break;
|
|
28443
|
+
}
|
|
28444
|
+
if (st.kind === "p") {
|
|
28445
|
+
out.push(l);
|
|
28446
|
+
lastInputIndex = i;
|
|
28447
|
+
continue;
|
|
28448
|
+
}
|
|
28449
|
+
if (st.kind === "=") {
|
|
28450
|
+
out.push(String(idx1));
|
|
28451
|
+
lastInputIndex = i;
|
|
28452
|
+
continue;
|
|
28453
|
+
}
|
|
28454
|
+
if (st.kind === "q") {
|
|
28455
|
+
if (!quiet) {
|
|
28456
|
+
out.push(l);
|
|
28457
|
+
lastInputIndex = i;
|
|
28458
|
+
}
|
|
28459
|
+
quitNow = true;
|
|
28460
|
+
break;
|
|
28461
|
+
}
|
|
28462
|
+
if (st.kind === "y") {
|
|
28463
|
+
l = Array.from(l).map(c => st.map.get(c) ?? c).join("");
|
|
28464
|
+
continue;
|
|
28465
|
+
}
|
|
28466
|
+
let matchedOnce = false;
|
|
28467
|
+
let matchIdx = 0;
|
|
28468
|
+
let previousEnd = -1;
|
|
28469
|
+
l = l.replace(st.re, (matched, ...groups) => {
|
|
28470
|
+
const offset = groups[groups.length - 2];
|
|
28471
|
+
if (matched.length === 0 && offset === previousEnd)
|
|
28472
|
+
return "";
|
|
28473
|
+
previousEnd = offset + matched.length;
|
|
28474
|
+
matchIdx++;
|
|
28475
|
+
if (st.nth > 0 && matchIdx !== st.nth)
|
|
28476
|
+
return matched;
|
|
28477
|
+
matchedOnce = true;
|
|
28478
|
+
// Expand only replacement tokens; inserted match bytes are literal.
|
|
28479
|
+
let replacement = "";
|
|
28480
|
+
for (let ri = 0; ri < st.rep.length; ri++) {
|
|
28481
|
+
const c = st.rep[ri];
|
|
28482
|
+
if (c === "&")
|
|
28483
|
+
replacement += matched;
|
|
28484
|
+
else if (c === "\\" && ri + 1 < st.rep.length) {
|
|
28485
|
+
const next = st.rep[++ri];
|
|
28486
|
+
const group = next >= "1" && next <= "9" ? groups[Number(next) - 1] : next;
|
|
28487
|
+
replacement += typeof group === "string" ? group : "";
|
|
28488
|
+
}
|
|
28489
|
+
else
|
|
28490
|
+
replacement += c;
|
|
28491
|
+
}
|
|
28492
|
+
return replacement;
|
|
28493
|
+
});
|
|
28494
|
+
if (matchedOnce && st.printOnMatch)
|
|
28495
|
+
out.push(l);
|
|
28496
|
+
}
|
|
28497
|
+
if (quitNow) {
|
|
28498
|
+
break;
|
|
28499
|
+
}
|
|
28500
|
+
if (!deleted && !quiet) {
|
|
28501
|
+
out.push(l);
|
|
28502
|
+
lastInputIndex = i;
|
|
28503
|
+
}
|
|
28504
|
+
}
|
|
28505
|
+
return { lines: out, lastInputIndex };
|
|
27307
28506
|
}
|
|
27308
28507
|
evalSyncGrep(rawLines, opArgs, errexit) {
|
|
27309
|
-
if (errexit ||
|
|
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") {
|
|
28508
|
+
if (errexit || opArgs.length < 1 || opArgs.length > 8)
|
|
27316
28509
|
return undefined;
|
|
28510
|
+
let mode = "";
|
|
28511
|
+
let maxCount = Infinity;
|
|
28512
|
+
let beforeCtx = 0;
|
|
28513
|
+
let afterCtx = 0;
|
|
28514
|
+
const rawPatterns = [];
|
|
28515
|
+
for (let i = 0; i < opArgs.length; i++) {
|
|
28516
|
+
const a = opArgs[i];
|
|
28517
|
+
if ((a === "-A" || a === "-B" || a === "-C") && i + 1 < opArgs.length && /^[0-9]{1,4}$/.test(opArgs[i + 1])) {
|
|
28518
|
+
const n = Number(opArgs[++i]);
|
|
28519
|
+
if (a === "-A" || a === "-C")
|
|
28520
|
+
afterCtx = n;
|
|
28521
|
+
if (a === "-B" || a === "-C")
|
|
28522
|
+
beforeCtx = n;
|
|
28523
|
+
}
|
|
28524
|
+
else if (/^-[ABC][0-9]{1,4}$/.test(a)) {
|
|
28525
|
+
const n = Number(a.slice(2));
|
|
28526
|
+
if (a[1] === "A" || a[1] === "C")
|
|
28527
|
+
afterCtx = n;
|
|
28528
|
+
if (a[1] === "B" || a[1] === "C")
|
|
28529
|
+
beforeCtx = n;
|
|
28530
|
+
}
|
|
28531
|
+
else if (/^--(?:after-context|before-context|context)=[0-9]{1,4}$/.test(a)) {
|
|
28532
|
+
const eq = a.indexOf("=");
|
|
28533
|
+
const n = Number(a.slice(eq + 1));
|
|
28534
|
+
if (a.startsWith("--after") || a.startsWith("--context"))
|
|
28535
|
+
afterCtx = n;
|
|
28536
|
+
if (a.startsWith("--before") || a.startsWith("--context"))
|
|
28537
|
+
beforeCtx = n;
|
|
28538
|
+
}
|
|
28539
|
+
else if (a === "-e") {
|
|
28540
|
+
if (i + 1 >= opArgs.length)
|
|
28541
|
+
return undefined;
|
|
28542
|
+
rawPatterns.push(opArgs[++i]);
|
|
28543
|
+
}
|
|
28544
|
+
else if (a.startsWith("-e") && a.length > 2) {
|
|
28545
|
+
rawPatterns.push(a.slice(2));
|
|
28546
|
+
}
|
|
28547
|
+
else if (a === "-m") {
|
|
28548
|
+
if (i + 1 >= opArgs.length || !/^[1-9][0-9]{0,5}$/.test(opArgs[i + 1]))
|
|
28549
|
+
return undefined;
|
|
28550
|
+
maxCount = Number(opArgs[++i]);
|
|
28551
|
+
}
|
|
28552
|
+
else if (a.startsWith("-m") && /^[1-9][0-9]{0,5}$/.test(a.slice(2))) {
|
|
28553
|
+
maxCount = Number(a.slice(2));
|
|
28554
|
+
}
|
|
28555
|
+
else if (a.startsWith("--max-count=") && /^[1-9][0-9]{0,5}$/.test(a.slice(12))) {
|
|
28556
|
+
maxCount = Number(a.slice(12));
|
|
28557
|
+
}
|
|
28558
|
+
else if (a.startsWith("--") && a !== "--" && rawPatterns.length === 0 && i < opArgs.length - 1) {
|
|
28559
|
+
if (a === "--extended-regexp")
|
|
28560
|
+
mode += "E";
|
|
28561
|
+
else if (a === "--fixed-strings")
|
|
28562
|
+
mode += "F";
|
|
28563
|
+
else if (a === "--ignore-case")
|
|
28564
|
+
mode += "i";
|
|
28565
|
+
else if (a === "--invert-match")
|
|
28566
|
+
mode += "v";
|
|
28567
|
+
else if (a === "--only-matching")
|
|
28568
|
+
mode += "o";
|
|
28569
|
+
else if (a === "--line-number")
|
|
28570
|
+
mode += "n";
|
|
28571
|
+
else if (a === "--count")
|
|
28572
|
+
mode += "c";
|
|
28573
|
+
else if (a === "--word-regexp")
|
|
28574
|
+
mode += "w";
|
|
28575
|
+
else if (a === "--line-regexp")
|
|
28576
|
+
mode += "x";
|
|
28577
|
+
else
|
|
28578
|
+
return undefined;
|
|
28579
|
+
}
|
|
28580
|
+
else if (a.startsWith("-") && a !== "-" && a !== "--" && rawPatterns.length === 0 && i < opArgs.length - 1) {
|
|
28581
|
+
mode += a.slice(1);
|
|
28582
|
+
}
|
|
28583
|
+
else if (!a.startsWith("-") && rawPatterns.length === 0 && i === opArgs.length - 1) {
|
|
28584
|
+
rawPatterns.push(a);
|
|
28585
|
+
}
|
|
28586
|
+
else {
|
|
28587
|
+
return undefined;
|
|
28588
|
+
}
|
|
27317
28589
|
}
|
|
28590
|
+
if (rawPatterns.length === 0 || !/^[vicFEonxw]*$/.test(mode))
|
|
28591
|
+
return undefined;
|
|
28592
|
+
const isLineNumber = mode.includes("n");
|
|
28593
|
+
const isLineRegexp = mode.includes("x");
|
|
28594
|
+
const isWordRegexp = mode.includes("w");
|
|
27318
28595
|
const isCaseInsensitive = mode.includes("i");
|
|
28596
|
+
const foldCase = (value) => value.replace(/[A-Z]/g, ch => ch.toLowerCase());
|
|
27319
28597
|
const isInvert = mode.includes("v");
|
|
27320
|
-
const isCount = mode
|
|
28598
|
+
const isCount = mode.includes("c");
|
|
27321
28599
|
const isExtended = mode.includes("E");
|
|
27322
28600
|
const isFixed = mode.includes("F");
|
|
27323
|
-
const
|
|
28601
|
+
const isOnlyMatching = mode.includes("o");
|
|
28602
|
+
// POSIX bracket classes, collating symbols and equivalence classes have
|
|
28603
|
+
// different meanings in JS RegExp. Let the command matcher parse them.
|
|
28604
|
+
if (isExtended && !isFixed && rawPatterns.some(pattern => pattern.includes("[:") || pattern.includes("[.") || pattern.includes("[=")))
|
|
28605
|
+
return undefined;
|
|
28606
|
+
if (isCount && (isLineNumber || isOnlyMatching || beforeCtx > 0 || afterCtx > 0))
|
|
28607
|
+
return undefined;
|
|
28608
|
+
if (isOnlyMatching && (beforeCtx > 0 || afterCtx > 0))
|
|
28609
|
+
return undefined;
|
|
28610
|
+
if (isOnlyMatching) {
|
|
28611
|
+
if (rawPatterns.length !== 1 || isInvert || isLineRegexp || isWordRegexp || isFixed)
|
|
28612
|
+
return undefined;
|
|
28613
|
+
const pat = rawPatterns[0];
|
|
28614
|
+
const reFlags = isCaseInsensitive ? "gi" : "g";
|
|
28615
|
+
let re;
|
|
28616
|
+
// JS alternatives are ordered; only literal alternatives below can be
|
|
28617
|
+
// sorted to implement grep's leftmost-longest choice. Other alternatives
|
|
28618
|
+
// use the command's POSIX matcher through the normal fallback.
|
|
28619
|
+
if (isExtended && !pat.includes("|") && /^[a-zA-Z0-9_ :;,=.+*?()^\-[\]]+$/.test(pat) && !/\([^)]*[+*][^)]*\)[+*?]/.test(pat)) {
|
|
28620
|
+
try {
|
|
28621
|
+
re = new RegExp(pat, reFlags);
|
|
28622
|
+
}
|
|
28623
|
+
catch {
|
|
28624
|
+
re = undefined;
|
|
28625
|
+
}
|
|
28626
|
+
}
|
|
28627
|
+
else {
|
|
28628
|
+
const branches = isExtended ? pat.split("|") : [pat];
|
|
28629
|
+
if (branches.every(b => b.length > 0 && /^[a-zA-Z0-9_ :;,/-]+$/.test(b))) {
|
|
28630
|
+
branches.sort((a, b) => b.length - a.length);
|
|
28631
|
+
re = new RegExp(branches.join("|"), reFlags);
|
|
28632
|
+
}
|
|
28633
|
+
}
|
|
28634
|
+
if (!re)
|
|
28635
|
+
return undefined;
|
|
28636
|
+
const out = [];
|
|
28637
|
+
for (let li = 0; li < rawLines.length; li++) {
|
|
28638
|
+
const matches = rawLines[li].match(re);
|
|
28639
|
+
if (matches) {
|
|
28640
|
+
for (let mi = 0; mi < matches.length; mi++) {
|
|
28641
|
+
out.push(isLineNumber ? `${li + 1}:${matches[mi]}` : matches[mi]);
|
|
28642
|
+
}
|
|
28643
|
+
}
|
|
28644
|
+
}
|
|
28645
|
+
return { lines: out, status: out.length > 0 ? 0 : 1 };
|
|
28646
|
+
}
|
|
28647
|
+
if (isExtended && isFixed)
|
|
28648
|
+
return undefined;
|
|
28649
|
+
const branches = [];
|
|
28650
|
+
for (const rp of rawPatterns) {
|
|
28651
|
+
for (const b of (isFixed ? rp.split("\n") : (isExtended ? rp.split("|") : [rp]))) {
|
|
28652
|
+
branches.push(b);
|
|
28653
|
+
}
|
|
28654
|
+
}
|
|
27324
28655
|
const compiledBranches = [];
|
|
27325
28656
|
for (const br of branches) {
|
|
27326
28657
|
if (br.length === 0)
|
|
27327
28658
|
return undefined;
|
|
27328
|
-
|
|
27329
|
-
|
|
27330
|
-
|
|
27331
|
-
|
|
27332
|
-
|
|
27333
|
-
|
|
27334
|
-
|
|
28659
|
+
if (isFixed) {
|
|
28660
|
+
if (br.includes("\0"))
|
|
28661
|
+
return undefined;
|
|
28662
|
+
compiledBranches.push({ anchorStart: isLineRegexp, anchorEnd: isLineRegexp, needle: isCaseInsensitive ? foldCase(br) : br, re: undefined });
|
|
28663
|
+
}
|
|
28664
|
+
else {
|
|
28665
|
+
const anchorStart = isLineRegexp || br.startsWith("^");
|
|
28666
|
+
const c1 = br.startsWith("^") ? br.slice(1) : br;
|
|
28667
|
+
const anchorEnd = isLineRegexp || c1.endsWith("$");
|
|
28668
|
+
const core = c1.endsWith("$") ? c1.slice(0, -1) : c1;
|
|
28669
|
+
if (core.length > 0 && /^[a-zA-Z0-9_ :;,/-]+$/.test(core)) {
|
|
28670
|
+
compiledBranches.push({ anchorStart, anchorEnd, needle: isCaseInsensitive ? foldCase(core) : core, re: undefined });
|
|
28671
|
+
}
|
|
28672
|
+
else if (isExtended && !isWordRegexp && core.length > 0 && /^[a-zA-Z0-9_ :;,=.+*?^\-[\]]+$/.test(core) && !/\([^)]*[+*][^)]*\)[+*?]/.test(core)) {
|
|
28673
|
+
try {
|
|
28674
|
+
const fullSrc = (anchorStart ? "^" : "") + core + (anchorEnd ? "$" : "");
|
|
28675
|
+
compiledBranches.push({ anchorStart, anchorEnd, needle: "", re: new RegExp(fullSrc, isCaseInsensitive ? "i" : "") });
|
|
28676
|
+
}
|
|
28677
|
+
catch {
|
|
28678
|
+
return undefined;
|
|
28679
|
+
}
|
|
28680
|
+
}
|
|
28681
|
+
else {
|
|
28682
|
+
return undefined;
|
|
28683
|
+
}
|
|
28684
|
+
}
|
|
27335
28685
|
}
|
|
28686
|
+
const isWordChar = (ch) => ch !== undefined && /^[a-zA-Z0-9_]$/.test(ch);
|
|
28687
|
+
const hasWordMatch = (hay, needle, aStart, aEnd) => {
|
|
28688
|
+
if (aStart && aEnd)
|
|
28689
|
+
return hay === needle;
|
|
28690
|
+
if (aStart)
|
|
28691
|
+
return hay.startsWith(needle) && !isWordChar(hay[needle.length]);
|
|
28692
|
+
if (aEnd)
|
|
28693
|
+
return hay.endsWith(needle) && !isWordChar(hay[hay.length - needle.length - 1]);
|
|
28694
|
+
let from = 0;
|
|
28695
|
+
while (from <= hay.length - needle.length) {
|
|
28696
|
+
const idx = hay.indexOf(needle, from);
|
|
28697
|
+
if (idx === -1)
|
|
28698
|
+
return false;
|
|
28699
|
+
if (!isWordChar(hay[idx - 1]) && !isWordChar(hay[idx + needle.length]))
|
|
28700
|
+
return true;
|
|
28701
|
+
from = idx + 1;
|
|
28702
|
+
}
|
|
28703
|
+
return false;
|
|
28704
|
+
};
|
|
27336
28705
|
const matched = [];
|
|
28706
|
+
const matchedIndices = [];
|
|
27337
28707
|
for (let li = 0; li < rawLines.length; li++) {
|
|
27338
28708
|
const l = rawLines[li];
|
|
27339
|
-
const hay = isCaseInsensitive ? l
|
|
28709
|
+
const hay = isCaseInsensitive ? foldCase(l) : l;
|
|
27340
28710
|
let hit = false;
|
|
27341
28711
|
for (let bi = 0; bi < compiledBranches.length; bi++) {
|
|
27342
28712
|
const b = compiledBranches[bi];
|
|
27343
|
-
const ok = b.
|
|
27344
|
-
?
|
|
27345
|
-
:
|
|
27346
|
-
? hay.
|
|
27347
|
-
: b.anchorEnd
|
|
27348
|
-
? hay
|
|
27349
|
-
:
|
|
28713
|
+
const ok = b.re !== undefined
|
|
28714
|
+
? b.re.test(l)
|
|
28715
|
+
: isWordRegexp
|
|
28716
|
+
? hasWordMatch(hay, b.needle, b.anchorStart, b.anchorEnd)
|
|
28717
|
+
: b.anchorStart && b.anchorEnd
|
|
28718
|
+
? hay === b.needle
|
|
28719
|
+
: b.anchorStart
|
|
28720
|
+
? hay.startsWith(b.needle)
|
|
28721
|
+
: b.anchorEnd
|
|
28722
|
+
? hay.endsWith(b.needle)
|
|
28723
|
+
: hay.includes(b.needle);
|
|
27350
28724
|
if (ok) {
|
|
27351
28725
|
hit = true;
|
|
27352
28726
|
break;
|
|
27353
28727
|
}
|
|
27354
28728
|
}
|
|
27355
|
-
if (isInvert ? !hit : hit)
|
|
27356
|
-
|
|
28729
|
+
if (isInvert ? !hit : hit) {
|
|
28730
|
+
matchedIndices.push(li);
|
|
28731
|
+
matched.push(isLineNumber ? `${li + 1}:${l}` : l);
|
|
28732
|
+
if (matched.length >= maxCount)
|
|
28733
|
+
break;
|
|
28734
|
+
}
|
|
28735
|
+
}
|
|
28736
|
+
if ((beforeCtx > 0 || afterCtx > 0) && matchedIndices.length > 0) {
|
|
28737
|
+
const matchedSet = new Set(matchedIndices);
|
|
28738
|
+
const outCtx = [];
|
|
28739
|
+
let prevEnd = -1;
|
|
28740
|
+
for (const mIdx of matchedIndices) {
|
|
28741
|
+
const start = Math.max(0, mIdx - beforeCtx);
|
|
28742
|
+
const end = Math.min(rawLines.length - 1, mIdx + afterCtx);
|
|
28743
|
+
if (prevEnd !== -1 && start > prevEnd + 1) {
|
|
28744
|
+
outCtx.push("--");
|
|
28745
|
+
}
|
|
28746
|
+
const from = prevEnd !== -1 ? Math.max(start, prevEnd + 1) : start;
|
|
28747
|
+
for (let k = from; k <= end; k++) {
|
|
28748
|
+
const lineText = rawLines[k];
|
|
28749
|
+
if (isLineNumber) {
|
|
28750
|
+
outCtx.push(`${k + 1}${matchedSet.has(k) ? ":" : "-"}${lineText}`);
|
|
28751
|
+
}
|
|
28752
|
+
else {
|
|
28753
|
+
outCtx.push(lineText);
|
|
28754
|
+
}
|
|
28755
|
+
}
|
|
28756
|
+
prevEnd = Math.max(prevEnd, end);
|
|
28757
|
+
}
|
|
28758
|
+
return { lines: outCtx, status: 0 };
|
|
27357
28759
|
}
|
|
27358
28760
|
return {
|
|
27359
28761
|
lines: isCount ? [String(matched.length)] : matched,
|
|
@@ -27361,50 +28763,413 @@ export class Runtime {
|
|
|
27361
28763
|
};
|
|
27362
28764
|
}
|
|
27363
28765
|
evalSyncAwk(rawLines, opArgs) {
|
|
27364
|
-
if (opArgs.length < 1 || opArgs.length >
|
|
28766
|
+
if (opArgs.length < 1 || opArgs.length > 8)
|
|
27365
28767
|
return undefined;
|
|
27366
|
-
const norm = opArgs.length === 3 && opArgs[0] === "-F" ? ["-F" + opArgs[1], opArgs[2]] : opArgs;
|
|
27367
28768
|
let awkSep;
|
|
27368
28769
|
let awkProg;
|
|
27369
|
-
|
|
27370
|
-
|
|
27371
|
-
|
|
27372
|
-
|
|
27373
|
-
|
|
28770
|
+
let ofs = " ";
|
|
28771
|
+
const userVars = new Map();
|
|
28772
|
+
for (let i = 0; i < opArgs.length; i++) {
|
|
28773
|
+
const a = opArgs[i];
|
|
28774
|
+
if (a === "-F") {
|
|
28775
|
+
if (i + 1 >= opArgs.length || opArgs[i + 1].length !== 1 || opArgs[i + 1] === "\\")
|
|
28776
|
+
return undefined;
|
|
28777
|
+
awkSep = opArgs[++i];
|
|
28778
|
+
}
|
|
28779
|
+
else if (a.startsWith("-F") && a.length === 3 && a[2] !== "\\") {
|
|
28780
|
+
awkSep = a.slice(2);
|
|
28781
|
+
}
|
|
28782
|
+
else if (a === "-v") {
|
|
28783
|
+
if (i + 1 >= opArgs.length)
|
|
28784
|
+
return undefined;
|
|
28785
|
+
const kv = opArgs[++i];
|
|
28786
|
+
const eq = kv.indexOf("=");
|
|
28787
|
+
if (eq <= 0 || !/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(kv.slice(0, eq)))
|
|
28788
|
+
return undefined;
|
|
28789
|
+
const k = kv.slice(0, eq);
|
|
28790
|
+
const v = kv.slice(eq + 1);
|
|
28791
|
+
if (v.includes("\\"))
|
|
28792
|
+
return undefined;
|
|
28793
|
+
if (k === "OFS")
|
|
28794
|
+
ofs = v;
|
|
28795
|
+
else if (k === "FS") {
|
|
28796
|
+
if (v.length !== 1)
|
|
28797
|
+
return undefined;
|
|
28798
|
+
awkSep = v;
|
|
28799
|
+
}
|
|
28800
|
+
else
|
|
28801
|
+
userVars.set(k, v);
|
|
28802
|
+
}
|
|
28803
|
+
else if (a.startsWith("-v") && a.length > 2) {
|
|
28804
|
+
const kv = a.slice(2);
|
|
28805
|
+
const eq = kv.indexOf("=");
|
|
28806
|
+
if (eq <= 0 || !/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(kv.slice(0, eq)))
|
|
28807
|
+
return undefined;
|
|
28808
|
+
const k = kv.slice(0, eq);
|
|
28809
|
+
const v = kv.slice(eq + 1);
|
|
28810
|
+
if (v.includes("\\"))
|
|
28811
|
+
return undefined;
|
|
28812
|
+
if (k === "OFS")
|
|
28813
|
+
ofs = v;
|
|
28814
|
+
else if (k === "FS") {
|
|
28815
|
+
if (v.length !== 1)
|
|
28816
|
+
return undefined;
|
|
28817
|
+
awkSep = v;
|
|
28818
|
+
}
|
|
28819
|
+
else
|
|
28820
|
+
userVars.set(k, v);
|
|
28821
|
+
}
|
|
28822
|
+
else if (!a.startsWith("-") && i === opArgs.length - 1) {
|
|
28823
|
+
awkProg = a;
|
|
28824
|
+
}
|
|
28825
|
+
else {
|
|
28826
|
+
return undefined;
|
|
28827
|
+
}
|
|
27374
28828
|
}
|
|
27375
28829
|
if (!awkProg)
|
|
27376
28830
|
return undefined;
|
|
27377
|
-
|
|
28831
|
+
let progRest = awkProg.trim();
|
|
28832
|
+
const beginFsM = /^BEGIN\s*\{([^}]*)\}\s*/.exec(progRest);
|
|
28833
|
+
let initVarName;
|
|
28834
|
+
let initVarVal = 0;
|
|
28835
|
+
if (beginFsM) {
|
|
28836
|
+
const bStmts = beginFsM[1].split(";").map(s => s.trim()).filter(Boolean);
|
|
28837
|
+
for (const bs of bStmts) {
|
|
28838
|
+
const ofsM = /^OFS\s*=\s*"([^"\\]*)"$/.exec(bs);
|
|
28839
|
+
if (ofsM) {
|
|
28840
|
+
ofs = ofsM[1];
|
|
28841
|
+
continue;
|
|
28842
|
+
}
|
|
28843
|
+
const fsM = /^FS\s*=\s*"([^"\\])"$/.exec(bs);
|
|
28844
|
+
if (fsM) {
|
|
28845
|
+
awkSep = fsM[1];
|
|
28846
|
+
continue;
|
|
28847
|
+
}
|
|
28848
|
+
const numInitM = /^([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(-?[0-9]+(?:\.[0-9]+)?)$/.exec(bs);
|
|
28849
|
+
if (numInitM) {
|
|
28850
|
+
initVarName = numInitM[1];
|
|
28851
|
+
initVarVal = Number(numInitM[2]);
|
|
28852
|
+
continue;
|
|
28853
|
+
}
|
|
28854
|
+
return undefined;
|
|
28855
|
+
}
|
|
28856
|
+
progRest = progRest.slice(beginFsM[0].length).trim();
|
|
28857
|
+
}
|
|
28858
|
+
const sumEndM = /^\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*(\+=|-=)\s*(?:\$([0-9]+|NF)|(-?[0-9]+(?:\.[0-9]+)?))\s*;?\s*\}\s*END\s*\{\s*print\s+\1\s*;?\s*\}$/.exec(progRest);
|
|
28859
|
+
if (sumEndM) {
|
|
28860
|
+
const varName = sumEndM[1];
|
|
28861
|
+
if (["NR", "NF", "FNR", "OFS", "FS", "ORS", "RS", "OFMT", "CONVFMT", "ARGC", "ARGIND", "FILENAME", "RSTART", "RLENGTH", "SUBSEP", "IGNORECASE", "FIELDWIDTHS", "FPAT", "BINMODE", "TEXTDOMAIN"].includes(varName))
|
|
28862
|
+
return undefined;
|
|
28863
|
+
if (initVarName !== undefined && initVarName !== varName)
|
|
28864
|
+
return undefined;
|
|
28865
|
+
const op = sumEndM[2];
|
|
28866
|
+
const fTok = sumEndM[3];
|
|
28867
|
+
const constVal = sumEndM[4] !== undefined ? Number(sumEndM[4]) : undefined;
|
|
28868
|
+
const initial = userVars.get(varName);
|
|
28869
|
+
if (initial !== undefined && !Number.isFinite(Number(initial)))
|
|
28870
|
+
return undefined;
|
|
28871
|
+
let acc = initVarName === varName ? initVarVal : Number(initial ?? 0);
|
|
28872
|
+
let touched = initVarName === varName || initial !== undefined;
|
|
28873
|
+
for (let li = 0; li < rawLines.length; li++) {
|
|
28874
|
+
const l = rawLines[li];
|
|
28875
|
+
const fields = awkSep === undefined || awkSep === " "
|
|
28876
|
+
? l.split(/[ \t]+/).filter(Boolean)
|
|
28877
|
+
: (l.length === 0 ? [] : l.split(awkSep));
|
|
28878
|
+
let delta = 0;
|
|
28879
|
+
if (constVal !== undefined) {
|
|
28880
|
+
delta = constVal;
|
|
28881
|
+
}
|
|
28882
|
+
else {
|
|
28883
|
+
const idx = fTok === "NF" ? fields.length : Number(fTok);
|
|
28884
|
+
const rawField = idx === 0 ? l : (idx >= 1 && idx <= fields.length ? fields[idx - 1] : "");
|
|
28885
|
+
const n = /^[ \t]*([+-]?(?:\d+(?:\.\d*)?|\.\d+))/.exec(rawField);
|
|
28886
|
+
delta = n ? Number(n[1]) : 0;
|
|
28887
|
+
}
|
|
28888
|
+
acc = op === "+=" ? acc + delta : acc - delta;
|
|
28889
|
+
touched = true;
|
|
28890
|
+
}
|
|
28891
|
+
return [touched ? awkValueText({ kind: "number", number: acc }) : ""];
|
|
28892
|
+
}
|
|
28893
|
+
if (initVarName !== undefined)
|
|
28894
|
+
return undefined;
|
|
28895
|
+
let rowPred;
|
|
28896
|
+
const patCondM = /^\/(\^?[a-zA-Z0-9_ :;,=-]+\$?)\/\s*/.exec(progRest);
|
|
28897
|
+
if (patCondM) {
|
|
28898
|
+
const pSpec = patCondM[1];
|
|
28899
|
+
const aS = pSpec.startsWith("^");
|
|
28900
|
+
const c1 = aS ? pSpec.slice(1) : pSpec;
|
|
28901
|
+
const aE = c1.endsWith("$");
|
|
28902
|
+
const core = aE ? c1.slice(0, -1) : c1;
|
|
28903
|
+
rowPred = (l) => aS && aE ? l === core : aS ? l.startsWith(core) : aE ? l.endsWith(core) : l.includes(core);
|
|
28904
|
+
progRest = progRest.slice(patCondM[0].length).trim();
|
|
28905
|
+
}
|
|
28906
|
+
else {
|
|
28907
|
+
const cmpCondM = /^(?:(NR|NF)|\$([0-9]+|NF))\s*(==|!=|>=|<=|>|<)\s*(?:"([^"\\]*)"|(-?[0-9]+(?:\.[0-9]+)?)|([a-zA-Z_][a-zA-Z0-9_]*))\s*/.exec(progRest);
|
|
28908
|
+
if (cmpCondM) {
|
|
28909
|
+
const nrNf = cmpCondM[1];
|
|
28910
|
+
const fTok = cmpCondM[2];
|
|
28911
|
+
const op = cmpCondM[3];
|
|
28912
|
+
const varRhs = cmpCondM[6] !== undefined ? userVars.get(cmpCondM[6]) : undefined;
|
|
28913
|
+
if (cmpCondM[6] !== undefined && varRhs === undefined)
|
|
28914
|
+
return undefined;
|
|
28915
|
+
const varAsNum = varRhs !== undefined && /^-?(?:\d+(?:\.\d*)?|\.\d+)$/.test(varRhs) ? Number(varRhs) : undefined;
|
|
28916
|
+
const strRhs = cmpCondM[4] ?? (varAsNum === undefined ? varRhs : undefined);
|
|
28917
|
+
const numRhs = cmpCondM[5] !== undefined ? Number(cmpCondM[5]) : varAsNum;
|
|
28918
|
+
if (strRhs !== undefined && op !== "==" && op !== "!=")
|
|
28919
|
+
return undefined;
|
|
28920
|
+
rowPred = (l, fields, nr) => {
|
|
28921
|
+
let rawVal;
|
|
28922
|
+
if (nrNf !== undefined)
|
|
28923
|
+
rawVal = nrNf === "NR" ? nr : fields.length;
|
|
28924
|
+
else {
|
|
28925
|
+
const idx = fTok === "NF" ? fields.length : Number(fTok);
|
|
28926
|
+
rawVal = idx === 0 ? l : (idx >= 1 && idx <= fields.length ? fields[idx - 1] : "");
|
|
28927
|
+
}
|
|
28928
|
+
const left = typeof rawVal === "number" ? awkNumeric(rawVal) : awkInputValue(rawVal);
|
|
28929
|
+
const right = strRhs !== undefined ? awkString(strRhs) : awkNumeric(numRhs);
|
|
28930
|
+
const comparison = awkCompare(left, right, "%.6g");
|
|
28931
|
+
return op === "==" ? comparison === 0 : op === "!=" ? comparison !== 0 : op === ">=" ? comparison >= 0 : op === "<=" ? comparison <= 0 : op === ">" ? comparison > 0 : comparison < 0;
|
|
28932
|
+
};
|
|
28933
|
+
progRest = progRest.slice(cmpCondM[0].length).trim();
|
|
28934
|
+
}
|
|
28935
|
+
}
|
|
28936
|
+
const awkM = syncAwkPrintRe.exec(progRest);
|
|
27378
28937
|
if (!awkM)
|
|
27379
28938
|
return undefined;
|
|
27380
|
-
const
|
|
28939
|
+
const subFn = awkM[1];
|
|
28940
|
+
const subPat = awkM[2];
|
|
28941
|
+
const subRep = awkM[3] ?? "";
|
|
28942
|
+
const subTarget = awkM[4] ?? "0";
|
|
28943
|
+
// printf must consume typed values before OFMT string conversion and use
|
|
28944
|
+
// the complete formatter, including integer precision and exponent parsing.
|
|
28945
|
+
if (awkM[6] !== undefined)
|
|
28946
|
+
return undefined;
|
|
28947
|
+
const exprBody = awkM[5]?.trim();
|
|
28948
|
+
let subRe;
|
|
28949
|
+
if (subFn && subPat !== undefined) {
|
|
28950
|
+
const aS = subPat.startsWith("^");
|
|
28951
|
+
const c1 = aS ? subPat.slice(1) : subPat;
|
|
28952
|
+
const aE = c1.endsWith("$");
|
|
28953
|
+
const core = aE ? c1.slice(0, -1) : c1;
|
|
28954
|
+
const esc = core.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
28955
|
+
subRe = new RegExp((aS ? "^" : "") + esc + (aE ? "$" : ""), subFn === "gsub" ? "g" : "");
|
|
28956
|
+
}
|
|
27381
28957
|
const parts = [];
|
|
27382
28958
|
if (!exprBody) {
|
|
27383
28959
|
parts.push({ kind: "field", token: "0" });
|
|
27384
28960
|
}
|
|
27385
28961
|
else {
|
|
27386
|
-
|
|
28962
|
+
syncAwkTokenRe.lastIndex = 0;
|
|
28963
|
+
const tokenRe = syncAwkTokenRe;
|
|
27387
28964
|
let m;
|
|
27388
28965
|
while ((m = tokenRe.exec(exprBody)) !== null) {
|
|
27389
|
-
if (m[1] !== undefined)
|
|
27390
|
-
|
|
28966
|
+
if (m[1] !== undefined) {
|
|
28967
|
+
const tm = /^(\$(?:[0-9]+|NF)|NR|NF)\s*(==|!=|>=|<=|>|<)\s*(-?[0-9]+(?:\.[0-9]+)?|"[^"$\\]*")\s*\?\s*(\$(?:[0-9]+|NF)|"[^"$\\]*"|-?[0-9]+(?:\.[0-9]+)?)\s*:\s*(\$(?:[0-9]+|NF)|"[^"$\\]*"|-?[0-9]+(?:\.[0-9]+)?)$/.exec(m[1].trim());
|
|
28968
|
+
if (!tm)
|
|
28969
|
+
return undefined;
|
|
28970
|
+
parts.push({ kind: "ternary", lhs: tm[1], op: tm[2], rhs: tm[3], yes: tm[4], no: tm[5] });
|
|
28971
|
+
}
|
|
27391
28972
|
else if (m[2] !== undefined)
|
|
27392
|
-
parts.push({ kind: "
|
|
28973
|
+
parts.push({ kind: "int", token: m[2] });
|
|
27393
28974
|
else if (m[3] !== undefined)
|
|
27394
|
-
parts.push({ kind: "
|
|
28975
|
+
parts.push({ kind: "case", fn: m[3] === "toupper" ? "upper" : "lower", token: m[4] });
|
|
28976
|
+
else if (m[5] !== undefined)
|
|
28977
|
+
parts.push({ kind: "substr", token: m[5], start: Number(m[6]), len: m[7] !== undefined ? Number(m[7]) : undefined });
|
|
28978
|
+
else if (m[8] !== undefined)
|
|
28979
|
+
parts.push({ kind: "index", token: m[8], sub: m[9] });
|
|
28980
|
+
else if (m[10] !== undefined) {
|
|
28981
|
+
const aToks = m[10].trim().split(/\s*([+*\/%-])\s*/);
|
|
28982
|
+
for (let ti = 0; ti < aToks.length; ti += 2) {
|
|
28983
|
+
const at = aToks[ti];
|
|
28984
|
+
if (!at.startsWith("$") && at !== "NR" && at !== "NF" && !/^-?[0-9]+(?:\.[0-9]+)?$/.test(at) && !userVars.has(at))
|
|
28985
|
+
return undefined;
|
|
28986
|
+
}
|
|
28987
|
+
for (let ti = 1; ti < aToks.length; ti += 2) {
|
|
28988
|
+
if (aToks[ti] === "/" || aToks[ti] === "%") {
|
|
28989
|
+
const divisor = Number(aToks[ti + 1]);
|
|
28990
|
+
if (!Number.isFinite(divisor) || divisor === 0)
|
|
28991
|
+
return undefined;
|
|
28992
|
+
}
|
|
28993
|
+
}
|
|
28994
|
+
parts.push({ kind: "arith", tokens: aToks });
|
|
28995
|
+
}
|
|
28996
|
+
else if (m[11] !== undefined) {
|
|
28997
|
+
const offset = Number(m[11]);
|
|
28998
|
+
// Refuse potentially fatal fields before loop iterations mutate state.
|
|
28999
|
+
if (offset > 0)
|
|
29000
|
+
return undefined;
|
|
29001
|
+
parts.push({ kind: "nf_minus", offset });
|
|
29002
|
+
}
|
|
29003
|
+
else if (m[12] !== undefined)
|
|
29004
|
+
parts.push({ kind: "field", token: m[12] });
|
|
29005
|
+
else if (m[0] === "length" || m[0].startsWith("length("))
|
|
29006
|
+
parts.push({ kind: "length", token: m[13] ?? "0" });
|
|
29007
|
+
else if (m[14] !== undefined)
|
|
29008
|
+
parts.push({ kind: "var", name: m[14] });
|
|
29009
|
+
else if (m[15] !== undefined)
|
|
29010
|
+
parts.push({ kind: "lit", text: m[15] });
|
|
29011
|
+
else if (m[16] !== undefined) {
|
|
29012
|
+
const uv = userVars.get(m[16]);
|
|
29013
|
+
if (uv === undefined)
|
|
29014
|
+
return undefined;
|
|
29015
|
+
parts.push({ kind: "lit", text: uv });
|
|
29016
|
+
}
|
|
29017
|
+
else if (m[17] !== undefined)
|
|
29018
|
+
parts.push({ kind: "lit", text: ofs });
|
|
27395
29019
|
}
|
|
27396
29020
|
}
|
|
27397
|
-
|
|
27398
|
-
|
|
27399
|
-
|
|
27400
|
-
|
|
27401
|
-
?
|
|
27402
|
-
: l.
|
|
29021
|
+
const outLines = [];
|
|
29022
|
+
for (let li = 0; li < rawLines.length; li++) {
|
|
29023
|
+
let l = rawLines[li];
|
|
29024
|
+
let fields = awkSep === undefined || awkSep === " "
|
|
29025
|
+
? l.split(/[ \t]+/).filter(Boolean)
|
|
29026
|
+
: (l.length === 0 ? [] : l.split(awkSep));
|
|
29027
|
+
if (rowPred && !rowPred(l, fields, li + 1))
|
|
29028
|
+
continue;
|
|
29029
|
+
if (subRe) {
|
|
29030
|
+
if (subTarget === "0") {
|
|
29031
|
+
l = l.replace(subRe, matched => subRep.split("&").join(matched));
|
|
29032
|
+
fields = awkSep === undefined || awkSep === " "
|
|
29033
|
+
? l.split(/[ \t]+/).filter(Boolean)
|
|
29034
|
+
: (l.length === 0 ? [] : l.split(awkSep));
|
|
29035
|
+
}
|
|
29036
|
+
else {
|
|
29037
|
+
const tIdx = subTarget === "NF" ? fields.length : Number(subTarget);
|
|
29038
|
+
if (tIdx >= 1 && tIdx <= fields.length) {
|
|
29039
|
+
fields = [...fields];
|
|
29040
|
+
fields[tIdx - 1] = fields[tIdx - 1].replace(subRe, matched => subRep.split("&").join(matched));
|
|
29041
|
+
l = fields.join(ofs);
|
|
29042
|
+
}
|
|
29043
|
+
}
|
|
29044
|
+
}
|
|
29045
|
+
if (parts.length === 1 && parts[0].kind === "field" && parts[0].token === "0") {
|
|
29046
|
+
outLines.push(l);
|
|
29047
|
+
continue;
|
|
29048
|
+
}
|
|
27403
29049
|
let out = "";
|
|
27404
29050
|
for (let pi = 0; pi < parts.length; pi++) {
|
|
27405
29051
|
const p = parts[pi];
|
|
27406
29052
|
if (p.kind === "lit")
|
|
27407
29053
|
out += p.text;
|
|
29054
|
+
else if (p.kind === "var")
|
|
29055
|
+
out += String(p.name === "NR" ? li + 1 : fields.length);
|
|
29056
|
+
else if (p.kind === "nf_minus") {
|
|
29057
|
+
const idx = fields.length - p.offset;
|
|
29058
|
+
if (idx < 0)
|
|
29059
|
+
return undefined;
|
|
29060
|
+
out += idx === 0 ? l : (idx >= 1 && idx <= fields.length ? fields[idx - 1] : "");
|
|
29061
|
+
}
|
|
29062
|
+
else if (p.kind === "case") {
|
|
29063
|
+
const idx = p.token === "NF" ? fields.length : Number(p.token);
|
|
29064
|
+
const s = idx === 0 ? l : (idx >= 1 && idx <= fields.length ? fields[idx - 1] : "");
|
|
29065
|
+
out += p.fn === "upper" ? s.toUpperCase() : s.toLowerCase();
|
|
29066
|
+
}
|
|
29067
|
+
else if (p.kind === "substr") {
|
|
29068
|
+
const idx = p.token === "NF" ? fields.length : Number(p.token);
|
|
29069
|
+
const s = idx === 0 ? l : (idx >= 1 && idx <= fields.length ? fields[idx - 1] : "");
|
|
29070
|
+
const chars = Array.from(s);
|
|
29071
|
+
const s0 = Math.max(0, p.start - 1);
|
|
29072
|
+
out += (p.len !== undefined ? chars.slice(s0, s0 + Math.max(0, p.len)) : chars.slice(s0)).join("");
|
|
29073
|
+
}
|
|
29074
|
+
else if (p.kind === "index") {
|
|
29075
|
+
const idx = p.token === "NF" ? fields.length : Number(p.token);
|
|
29076
|
+
const s = idx === 0 ? l : (idx >= 1 && idx <= fields.length ? fields[idx - 1] : "");
|
|
29077
|
+
const pos = p.sub.length === 0 ? -1 : s.indexOf(p.sub);
|
|
29078
|
+
out += String(pos === -1 ? 0 : pos + 1);
|
|
29079
|
+
}
|
|
29080
|
+
else if (p.kind === "int") {
|
|
29081
|
+
const idx = p.token === "NF" ? fields.length : Number(p.token);
|
|
29082
|
+
const s = idx === 0 ? l : (idx >= 1 && idx <= fields.length ? fields[idx - 1] : "");
|
|
29083
|
+
const n = Number(/^[ \t]*([+-]?(?:\d+(?:\.\d*)?|\.\d+))/.exec(s)?.[1] ?? 0);
|
|
29084
|
+
out += String(Math.trunc(n));
|
|
29085
|
+
}
|
|
29086
|
+
else if (p.kind === "ternary") {
|
|
29087
|
+
const resolveAtom = (tok) => {
|
|
29088
|
+
if (tok.startsWith("\"") && tok.endsWith("\""))
|
|
29089
|
+
return tok.slice(1, -1);
|
|
29090
|
+
if (tok === "NR")
|
|
29091
|
+
return String(li + 1);
|
|
29092
|
+
if (tok === "NF")
|
|
29093
|
+
return String(fields.length);
|
|
29094
|
+
if (tok.startsWith("$")) {
|
|
29095
|
+
const fIdx = tok === "$NF" ? fields.length : Number(tok.slice(1));
|
|
29096
|
+
return fIdx === 0 ? l : (fIdx >= 1 && fIdx <= fields.length ? fields[fIdx - 1] : "");
|
|
29097
|
+
}
|
|
29098
|
+
return tok;
|
|
29099
|
+
};
|
|
29100
|
+
const lv = resolveAtom(p.lhs);
|
|
29101
|
+
const rv = resolveAtom(p.rhs);
|
|
29102
|
+
const isStrCmp = p.rhs.startsWith("\"");
|
|
29103
|
+
let cond = false;
|
|
29104
|
+
if (isStrCmp) {
|
|
29105
|
+
cond = p.op === "==" ? lv === rv : p.op === "!=" ? lv !== rv : p.op === ">" ? lv > rv : p.op === "<" ? lv < rv : p.op === ">=" ? lv >= rv : lv <= rv;
|
|
29106
|
+
}
|
|
29107
|
+
else {
|
|
29108
|
+
const ln = Number(lv) || 0;
|
|
29109
|
+
const rn = Number(rv) || 0;
|
|
29110
|
+
cond = p.op === "==" ? ln === rn : p.op === "!=" ? ln !== rn : p.op === ">" ? ln > rn : p.op === "<" ? ln < rn : p.op === ">=" ? ln >= rn : ln <= rn;
|
|
29111
|
+
}
|
|
29112
|
+
out += resolveAtom(cond ? p.yes : p.no);
|
|
29113
|
+
}
|
|
29114
|
+
else if (p.kind === "arith") {
|
|
29115
|
+
const vals = [];
|
|
29116
|
+
const ops = [];
|
|
29117
|
+
for (let ti = 0; ti < p.tokens.length; ti++) {
|
|
29118
|
+
const tk = p.tokens[ti];
|
|
29119
|
+
if (ti % 2 === 1) {
|
|
29120
|
+
ops.push(tk);
|
|
29121
|
+
}
|
|
29122
|
+
else {
|
|
29123
|
+
let v = 0;
|
|
29124
|
+
if (tk === "NR")
|
|
29125
|
+
v = li + 1;
|
|
29126
|
+
else if (tk === "NF")
|
|
29127
|
+
v = fields.length;
|
|
29128
|
+
else if (tk.startsWith("$")) {
|
|
29129
|
+
const fSub = tk.slice(1);
|
|
29130
|
+
const idx = fSub === "NF" ? fields.length : Number(fSub);
|
|
29131
|
+
const rawF = idx === 0 ? l : (idx >= 1 && idx <= fields.length ? fields[idx - 1] : "");
|
|
29132
|
+
const nm = /^[ \t]*([+-]?(?:\d+(?:\.\d*)?|\.\d+))/.exec(rawF);
|
|
29133
|
+
v = nm ? Number(nm[1]) : 0;
|
|
29134
|
+
}
|
|
29135
|
+
else if (/^-?[0-9]+(?:\.[0-9]+)?$/.test(tk)) {
|
|
29136
|
+
v = Number(tk);
|
|
29137
|
+
}
|
|
29138
|
+
else {
|
|
29139
|
+
const uv = userVars.get(tk) ?? "";
|
|
29140
|
+
const nm = /^[ \t]*([+-]?(?:\d+(?:\.\d*)?|\.\d+))/.exec(uv);
|
|
29141
|
+
v = nm ? Number(nm[1]) : 0;
|
|
29142
|
+
}
|
|
29143
|
+
vals.push(v);
|
|
29144
|
+
}
|
|
29145
|
+
}
|
|
29146
|
+
const addVals = [vals[0]];
|
|
29147
|
+
const addOps = [];
|
|
29148
|
+
for (let oi = 0; oi < ops.length; oi++) {
|
|
29149
|
+
const op = ops[oi];
|
|
29150
|
+
const rhs = vals[oi + 1];
|
|
29151
|
+
if (op === "*" || op === "/" || op === "%") {
|
|
29152
|
+
if ((op === "/" || op === "%") && rhs === 0)
|
|
29153
|
+
return undefined;
|
|
29154
|
+
const lhs = addVals.pop();
|
|
29155
|
+
addVals.push(op === "*" ? lhs * rhs : op === "/" ? lhs / rhs : lhs % rhs);
|
|
29156
|
+
}
|
|
29157
|
+
else {
|
|
29158
|
+
addOps.push(op);
|
|
29159
|
+
addVals.push(rhs);
|
|
29160
|
+
}
|
|
29161
|
+
}
|
|
29162
|
+
let acc = addVals[0];
|
|
29163
|
+
for (let oi = 0; oi < addOps.length; oi++) {
|
|
29164
|
+
acc = addOps[oi] === "+" ? acc + addVals[oi + 1] : acc - addVals[oi + 1];
|
|
29165
|
+
}
|
|
29166
|
+
out += awkValueText(awkNumeric(acc));
|
|
29167
|
+
}
|
|
29168
|
+
else if (p.kind === "length") {
|
|
29169
|
+
const idx = p.token === "NF" ? fields.length : Number(p.token);
|
|
29170
|
+
const s = idx === 0 ? l : (idx >= 1 && idx <= fields.length ? fields[idx - 1] : "");
|
|
29171
|
+
out += String(Array.from(s).length);
|
|
29172
|
+
}
|
|
27408
29173
|
else if (p.token === "0")
|
|
27409
29174
|
out += l;
|
|
27410
29175
|
else {
|
|
@@ -27412,8 +29177,9 @@ export class Runtime {
|
|
|
27412
29177
|
out += idx === 0 ? l : (idx >= 1 && idx <= fields.length ? fields[idx - 1] : "");
|
|
27413
29178
|
}
|
|
27414
29179
|
}
|
|
27415
|
-
|
|
27416
|
-
}
|
|
29180
|
+
outLines.push(out);
|
|
29181
|
+
}
|
|
29182
|
+
return outLines;
|
|
27417
29183
|
}
|
|
27418
29184
|
formatSyncTransformQ(val) {
|
|
27419
29185
|
let ansi = false;
|
|
@@ -27456,41 +29222,716 @@ export class Runtime {
|
|
|
27456
29222
|
}
|
|
27457
29223
|
return out + "'";
|
|
27458
29224
|
}
|
|
27459
|
-
|
|
27460
|
-
|
|
27461
|
-
|
|
27462
|
-
const
|
|
29225
|
+
wcMaxLineWidth(text, singleByte) {
|
|
29226
|
+
let columns = 0;
|
|
29227
|
+
let maximum = 0;
|
|
29228
|
+
for (const char of text) {
|
|
29229
|
+
const point = char.codePointAt(0);
|
|
29230
|
+
if (point === 10 || point === 13 || point === 12) {
|
|
29231
|
+
maximum = Math.max(maximum, columns);
|
|
29232
|
+
columns = 0;
|
|
29233
|
+
}
|
|
29234
|
+
else if (point === 9)
|
|
29235
|
+
columns += 8 - columns % 8;
|
|
29236
|
+
else
|
|
29237
|
+
columns += singleByte ? Number(point >= 32 && point < 127) : wcDisplayWidth(point);
|
|
29238
|
+
}
|
|
29239
|
+
return Math.max(maximum, columns);
|
|
29240
|
+
}
|
|
29241
|
+
compareSyncVersion(a, b) {
|
|
29242
|
+
let ia = 0;
|
|
29243
|
+
let ib = 0;
|
|
29244
|
+
while (ia < a.length || ib < b.length) {
|
|
29245
|
+
while ((ia < a.length && !(a[ia] >= "0" && a[ia] <= "9")) || (ib < b.length && !(b[ib] >= "0" && b[ib] <= "9"))) {
|
|
29246
|
+
const ca = ia < a.length ? a[ia] : undefined;
|
|
29247
|
+
const cb = ib < b.length ? b[ib] : undefined;
|
|
29248
|
+
const da = ca !== undefined && ca >= "0" && ca <= "9";
|
|
29249
|
+
const db = cb !== undefined && cb >= "0" && cb <= "9";
|
|
29250
|
+
if (da && db)
|
|
29251
|
+
break;
|
|
29252
|
+
if (ca !== cb) {
|
|
29253
|
+
if (ca === undefined)
|
|
29254
|
+
return -1;
|
|
29255
|
+
if (cb === undefined)
|
|
29256
|
+
return 1;
|
|
29257
|
+
if (da)
|
|
29258
|
+
return 1;
|
|
29259
|
+
if (db)
|
|
29260
|
+
return -1;
|
|
29261
|
+
return ca < cb ? -1 : 1;
|
|
29262
|
+
}
|
|
29263
|
+
ia++;
|
|
29264
|
+
ib++;
|
|
29265
|
+
}
|
|
29266
|
+
const sa = ia;
|
|
29267
|
+
while (ia < a.length && a[ia] >= "0" && a[ia] <= "9")
|
|
29268
|
+
ia++;
|
|
29269
|
+
const sb = ib;
|
|
29270
|
+
while (ib < b.length && b[ib] >= "0" && b[ib] <= "9")
|
|
29271
|
+
ib++;
|
|
29272
|
+
if (sa < ia || sb < ib) {
|
|
29273
|
+
const na = BigInt(sa < ia ? a.slice(sa, ia) : "0");
|
|
29274
|
+
const nb = BigInt(sb < ib ? b.slice(sb, ib) : "0");
|
|
29275
|
+
if (na !== nb)
|
|
29276
|
+
return na < nb ? -1 : 1;
|
|
29277
|
+
}
|
|
29278
|
+
}
|
|
29279
|
+
return 0;
|
|
29280
|
+
}
|
|
29281
|
+
evalSyncNl(rawLines, opArgs) {
|
|
29282
|
+
let bodyStyle = "t";
|
|
29283
|
+
let format = "rn";
|
|
29284
|
+
let width = 6;
|
|
29285
|
+
let sep = "\t";
|
|
29286
|
+
let start = 1;
|
|
29287
|
+
let inc = 1;
|
|
29288
|
+
for (let i = 0; i < opArgs.length; i++) {
|
|
29289
|
+
const a = opArgs[i];
|
|
29290
|
+
if ((a === "-b" || a === "--body-numbering") && i + 1 < opArgs.length) {
|
|
29291
|
+
const v = opArgs[++i];
|
|
29292
|
+
if (v !== "a" && v !== "t" && v !== "n")
|
|
29293
|
+
return undefined;
|
|
29294
|
+
bodyStyle = v;
|
|
29295
|
+
}
|
|
29296
|
+
else if (a === "-ba" || a === "-bt" || a === "-bn") {
|
|
29297
|
+
bodyStyle = a[2];
|
|
29298
|
+
}
|
|
29299
|
+
else if ((a === "-n" || a === "--number-format") && i + 1 < opArgs.length) {
|
|
29300
|
+
const v = opArgs[++i];
|
|
29301
|
+
if (v !== "ln" && v !== "rn" && v !== "rz")
|
|
29302
|
+
return undefined;
|
|
29303
|
+
format = v;
|
|
29304
|
+
}
|
|
29305
|
+
else if (a === "-nln" || a === "-nrn" || a === "-nrz") {
|
|
29306
|
+
format = a.slice(2);
|
|
29307
|
+
}
|
|
29308
|
+
else if ((a === "-w" || a === "--number-width") && i + 1 < opArgs.length && /^[1-9][0-9]{0,2}$/.test(opArgs[i + 1])) {
|
|
29309
|
+
width = Number(opArgs[++i]);
|
|
29310
|
+
}
|
|
29311
|
+
else if (/^-w[1-9][0-9]{0,2}$/.test(a)) {
|
|
29312
|
+
width = Number(a.slice(2));
|
|
29313
|
+
}
|
|
29314
|
+
else if ((a === "-s" || a === "--number-separator") && i + 1 < opArgs.length) {
|
|
29315
|
+
sep = opArgs[++i];
|
|
29316
|
+
}
|
|
29317
|
+
else if (a.startsWith("-s") && a.length > 2) {
|
|
29318
|
+
sep = a.slice(2);
|
|
29319
|
+
}
|
|
29320
|
+
else if ((a === "-v" || a === "--starting-line-number") && i + 1 < opArgs.length && /^-?[0-9]{1,9}$/.test(opArgs[i + 1])) {
|
|
29321
|
+
start = Number(opArgs[++i]);
|
|
29322
|
+
}
|
|
29323
|
+
else if (/^-v-?[0-9]{1,9}$/.test(a)) {
|
|
29324
|
+
start = Number(a.slice(2));
|
|
29325
|
+
}
|
|
29326
|
+
else if ((a === "-i" || a === "--line-increment") && i + 1 < opArgs.length && /^-?[0-9]{1,9}$/.test(opArgs[i + 1])) {
|
|
29327
|
+
inc = Number(opArgs[++i]);
|
|
29328
|
+
}
|
|
29329
|
+
else if (/^-i-?[0-9]{1,9}$/.test(a)) {
|
|
29330
|
+
inc = Number(a.slice(2));
|
|
29331
|
+
}
|
|
29332
|
+
else {
|
|
29333
|
+
return undefined;
|
|
29334
|
+
}
|
|
29335
|
+
}
|
|
29336
|
+
const out = [];
|
|
29337
|
+
let curStyle = bodyStyle;
|
|
29338
|
+
let num = start;
|
|
29339
|
+
const unnumberedPrefix = " ".repeat(width + sep.length);
|
|
29340
|
+
for (let i = 0; i < rawLines.length; i++) {
|
|
29341
|
+
const l = rawLines[i];
|
|
29342
|
+
if (l === "\\:" || l === "\\:\\:" || l === "\\:\\:\\:") {
|
|
29343
|
+
curStyle = l === "\\:\\:" ? bodyStyle : "n";
|
|
29344
|
+
num = start;
|
|
29345
|
+
out.push("");
|
|
29346
|
+
continue;
|
|
29347
|
+
}
|
|
29348
|
+
const numbered = curStyle === "a" || (curStyle === "t" && l.length > 0);
|
|
29349
|
+
if (!numbered) {
|
|
29350
|
+
out.push(l.length === 0 && sep === "\t" ? " ".repeat(width + 1) : unnumberedPrefix + l);
|
|
29351
|
+
continue;
|
|
29352
|
+
}
|
|
29353
|
+
const label = String(num);
|
|
29354
|
+
const pad = Math.max(0, width - label.length);
|
|
29355
|
+
let prefix;
|
|
29356
|
+
if (format === "ln")
|
|
29357
|
+
prefix = label + " ".repeat(pad);
|
|
29358
|
+
else if (format === "rz")
|
|
29359
|
+
prefix = num < 0 ? "-" + "0".repeat(pad) + label.slice(1) : "0".repeat(pad) + label;
|
|
29360
|
+
else
|
|
29361
|
+
prefix = " ".repeat(pad) + label;
|
|
29362
|
+
out.push(prefix + sep + l);
|
|
29363
|
+
num += inc;
|
|
29364
|
+
}
|
|
29365
|
+
return out;
|
|
29366
|
+
}
|
|
29367
|
+
evalSyncPaste(rawLines, opArgs) {
|
|
29368
|
+
let serial = false;
|
|
29369
|
+
let delims = ["\t"];
|
|
29370
|
+
let literal = false;
|
|
29371
|
+
const files = [];
|
|
29372
|
+
const parseDelims = (s) => {
|
|
29373
|
+
if (s.length === 0)
|
|
29374
|
+
return [""];
|
|
29375
|
+
const res = [];
|
|
29376
|
+
const escapes = { b: "\b", f: "\f", n: "\n", r: "\r", t: "\t", v: "\v", "0": "" };
|
|
29377
|
+
for (let i = 0; i < s.length; i++) {
|
|
29378
|
+
const ch = s[i];
|
|
29379
|
+
if (ch === "\\") {
|
|
29380
|
+
if (i + 1 >= s.length)
|
|
29381
|
+
return undefined;
|
|
29382
|
+
const esc = s[++i];
|
|
29383
|
+
res.push(escapes[esc] ?? esc);
|
|
29384
|
+
}
|
|
29385
|
+
else {
|
|
29386
|
+
res.push(ch);
|
|
29387
|
+
}
|
|
29388
|
+
}
|
|
29389
|
+
return res.length > 0 ? res : [""];
|
|
29390
|
+
};
|
|
29391
|
+
for (let i = 0; i < opArgs.length; i++) {
|
|
29392
|
+
const a = opArgs[i];
|
|
29393
|
+
if (literal || a === "-" || !a.startsWith("-")) {
|
|
29394
|
+
files.push(a);
|
|
29395
|
+
continue;
|
|
29396
|
+
}
|
|
29397
|
+
if (a === "--") {
|
|
29398
|
+
literal = true;
|
|
29399
|
+
continue;
|
|
29400
|
+
}
|
|
29401
|
+
if (a === "--serial") {
|
|
29402
|
+
serial = true;
|
|
29403
|
+
continue;
|
|
29404
|
+
}
|
|
29405
|
+
if (a === "--delimiters" && i + 1 < opArgs.length) {
|
|
29406
|
+
const d = parseDelims(opArgs[++i]);
|
|
29407
|
+
if (!d)
|
|
29408
|
+
return undefined;
|
|
29409
|
+
delims = d;
|
|
29410
|
+
continue;
|
|
29411
|
+
}
|
|
29412
|
+
if (a.startsWith("--delimiters=")) {
|
|
29413
|
+
const d = parseDelims(a.slice(13));
|
|
29414
|
+
if (!d)
|
|
29415
|
+
return undefined;
|
|
29416
|
+
delims = d;
|
|
29417
|
+
continue;
|
|
29418
|
+
}
|
|
29419
|
+
if (a.startsWith("--"))
|
|
29420
|
+
return undefined;
|
|
29421
|
+
for (let k = 1; k < a.length; k++) {
|
|
29422
|
+
const f = a[k];
|
|
29423
|
+
if (f === "s")
|
|
29424
|
+
serial = true;
|
|
29425
|
+
else if (f === "d") {
|
|
29426
|
+
const rest = a.slice(k + 1);
|
|
29427
|
+
const rawD = rest.length > 0 ? rest : (i + 1 < opArgs.length ? opArgs[++i] : undefined);
|
|
29428
|
+
if (rawD === undefined)
|
|
29429
|
+
return undefined;
|
|
29430
|
+
const d = parseDelims(rawD);
|
|
29431
|
+
if (!d)
|
|
29432
|
+
return undefined;
|
|
29433
|
+
delims = d;
|
|
29434
|
+
break;
|
|
29435
|
+
}
|
|
29436
|
+
else
|
|
29437
|
+
return undefined;
|
|
29438
|
+
}
|
|
29439
|
+
}
|
|
29440
|
+
if (files.length === 0)
|
|
29441
|
+
files.push("-");
|
|
29442
|
+
if (!files.every(f => f === "-"))
|
|
29443
|
+
return undefined;
|
|
29444
|
+
if (serial) {
|
|
29445
|
+
if (files.length !== 1)
|
|
29446
|
+
return undefined;
|
|
29447
|
+
if (rawLines.length === 0)
|
|
29448
|
+
return [];
|
|
29449
|
+
let joined = rawLines[0];
|
|
29450
|
+
for (let i = 1; i < rawLines.length; i++) {
|
|
29451
|
+
joined += delims[(i - 1) % delims.length] + rawLines[i];
|
|
29452
|
+
}
|
|
29453
|
+
return joined.split("\n");
|
|
29454
|
+
}
|
|
29455
|
+
const cols = files.length;
|
|
29456
|
+
const out = [];
|
|
29457
|
+
for (let i = 0; i < rawLines.length; i += cols) {
|
|
29458
|
+
let row = rawLines[i] ?? "";
|
|
29459
|
+
for (let c = 1; c < cols; c++) {
|
|
29460
|
+
row += delims[(c - 1) % delims.length] + (rawLines[i + c] ?? "");
|
|
29461
|
+
}
|
|
29462
|
+
out.push(row);
|
|
29463
|
+
}
|
|
29464
|
+
return out;
|
|
29465
|
+
}
|
|
29466
|
+
evalSyncNumfmt(rawLines, opArgs) {
|
|
29467
|
+
let fromScale = "none";
|
|
29468
|
+
let toScale = "none";
|
|
29469
|
+
let padding = 0;
|
|
29470
|
+
let suffix = "";
|
|
29471
|
+
for (let i = 0; i < opArgs.length; i++) {
|
|
29472
|
+
const a = opArgs[i];
|
|
29473
|
+
if (a.startsWith("--from=")) {
|
|
29474
|
+
const v = a.slice(7);
|
|
29475
|
+
if (v === "none" || v === "iec" || v === "iec-i" || v === "si" || v === "auto")
|
|
29476
|
+
fromScale = v;
|
|
29477
|
+
else
|
|
29478
|
+
return undefined;
|
|
29479
|
+
}
|
|
29480
|
+
else if (a.startsWith("--to=")) {
|
|
29481
|
+
const v = a.slice(5);
|
|
29482
|
+
if (v === "none" || v === "iec" || v === "iec-i" || v === "si")
|
|
29483
|
+
toScale = v;
|
|
29484
|
+
else
|
|
29485
|
+
return undefined;
|
|
29486
|
+
}
|
|
29487
|
+
else if (a.startsWith("--padding=")) {
|
|
29488
|
+
const v = a.slice(10);
|
|
29489
|
+
if (!/^-?[1-9][0-9]{0,2}$/.test(v))
|
|
29490
|
+
return undefined;
|
|
29491
|
+
padding = Number(v);
|
|
29492
|
+
}
|
|
29493
|
+
else if (a.startsWith("--suffix=")) {
|
|
29494
|
+
suffix = a.slice(9);
|
|
29495
|
+
}
|
|
29496
|
+
else {
|
|
29497
|
+
return undefined;
|
|
29498
|
+
}
|
|
29499
|
+
}
|
|
29500
|
+
const units = "KMGTPEZY";
|
|
29501
|
+
const out = [];
|
|
29502
|
+
for (let i = 0; i < rawLines.length; i++) {
|
|
29503
|
+
const raw = rawLines[i].trim();
|
|
29504
|
+
if (raw.length === 0) {
|
|
29505
|
+
out.push("");
|
|
29506
|
+
continue;
|
|
29507
|
+
}
|
|
29508
|
+
const m = /^([+-]?(?:\d+(?:\.\d*)?|\.\d+))([KMGTPEZYkmgtpezy]i?)?$/.exec(raw);
|
|
29509
|
+
if (!m)
|
|
29510
|
+
return undefined;
|
|
29511
|
+
let val = Number(m[1]);
|
|
29512
|
+
const suf = m[2] ?? "";
|
|
29513
|
+
if (suf.length > 0) {
|
|
29514
|
+
if (fromScale === "none")
|
|
29515
|
+
return undefined;
|
|
29516
|
+
const uChar = suf[0].toUpperCase();
|
|
29517
|
+
const pIdx = units.indexOf(uChar) + 1;
|
|
29518
|
+
if (pIdx <= 0)
|
|
29519
|
+
return undefined;
|
|
29520
|
+
const hasI = suf.length === 2 && suf[1].toLowerCase() === "i";
|
|
29521
|
+
if (fromScale === "iec-i" && !hasI)
|
|
29522
|
+
return undefined;
|
|
29523
|
+
if ((fromScale === "iec" || fromScale === "si") && hasI)
|
|
29524
|
+
return undefined;
|
|
29525
|
+
const fBase = (fromScale === "iec" || fromScale === "iec-i" || (fromScale === "auto" && hasI)) ? 1024 : 1000;
|
|
29526
|
+
val = val * Math.pow(fBase, pIdx);
|
|
29527
|
+
}
|
|
29528
|
+
else if (fromScale === "iec-i") {
|
|
29529
|
+
// plain number ok
|
|
29530
|
+
}
|
|
29531
|
+
val = val >= 0 ? Math.ceil(val - 1e-12) : -Math.ceil(Math.abs(val) - 1e-12);
|
|
29532
|
+
let rendered;
|
|
29533
|
+
if (toScale === "none") {
|
|
29534
|
+
rendered = String(Math.trunc(val));
|
|
29535
|
+
}
|
|
29536
|
+
else {
|
|
29537
|
+
const tBase = (toScale === "iec" || toScale === "iec-i") ? 1024 : 1000;
|
|
29538
|
+
let pIdx = 0;
|
|
29539
|
+
let scaled = val;
|
|
29540
|
+
while (Math.abs(scaled) >= tBase && pIdx < units.length) {
|
|
29541
|
+
scaled /= tBase;
|
|
29542
|
+
pIdx++;
|
|
29543
|
+
}
|
|
29544
|
+
if (pIdx === 0) {
|
|
29545
|
+
rendered = String(Math.trunc(scaled));
|
|
29546
|
+
}
|
|
29547
|
+
else {
|
|
29548
|
+
if (Math.abs(scaled) < 10) {
|
|
29549
|
+
scaled = (scaled >= 0 ? Math.ceil(scaled * 10 - 1e-12) : -Math.ceil(Math.abs(scaled) * 10 - 1e-12)) / 10;
|
|
29550
|
+
if (Math.abs(scaled) >= tBase && pIdx < units.length) {
|
|
29551
|
+
scaled /= tBase;
|
|
29552
|
+
pIdx++;
|
|
29553
|
+
}
|
|
29554
|
+
}
|
|
29555
|
+
else {
|
|
29556
|
+
scaled = scaled >= 0 ? Math.ceil(scaled - 1e-12) : -Math.ceil(Math.abs(scaled) - 1e-12);
|
|
29557
|
+
if (Math.abs(scaled) >= tBase && pIdx < units.length) {
|
|
29558
|
+
scaled /= tBase;
|
|
29559
|
+
pIdx++;
|
|
29560
|
+
}
|
|
29561
|
+
}
|
|
29562
|
+
const numText = Math.abs(scaled) < 10 ? scaled.toFixed(1) : scaled.toFixed(0);
|
|
29563
|
+
const uText = (toScale === "si" && pIdx === 1 ? "k" : units[pIdx - 1]) + (toScale === "iec-i" ? "i" : "");
|
|
29564
|
+
rendered = numText + uText;
|
|
29565
|
+
}
|
|
29566
|
+
}
|
|
29567
|
+
rendered += suffix;
|
|
29568
|
+
if (padding !== 0) {
|
|
29569
|
+
const w = Math.abs(padding);
|
|
29570
|
+
if (rendered.length < w) {
|
|
29571
|
+
const pad = " ".repeat(w - rendered.length);
|
|
29572
|
+
rendered = padding < 0 ? rendered + pad : pad + rendered;
|
|
29573
|
+
}
|
|
29574
|
+
}
|
|
29575
|
+
out.push(rendered);
|
|
29576
|
+
}
|
|
29577
|
+
return out;
|
|
29578
|
+
}
|
|
29579
|
+
evalSyncSort(rawLines, opArgs, isByteLocale) {
|
|
29580
|
+
if (isByteLocale)
|
|
29581
|
+
return undefined;
|
|
29582
|
+
let rev = false;
|
|
29583
|
+
let num = false;
|
|
29584
|
+
let human = false;
|
|
29585
|
+
let month = false;
|
|
29586
|
+
let dict = false;
|
|
29587
|
+
let uniq = false;
|
|
29588
|
+
let fold = false;
|
|
29589
|
+
let blanks = false;
|
|
29590
|
+
let stable = false;
|
|
29591
|
+
let ver = false;
|
|
29592
|
+
let sep;
|
|
29593
|
+
let keySpec;
|
|
29594
|
+
for (let i = 0; i < opArgs.length; i++) {
|
|
29595
|
+
const a = opArgs[i];
|
|
29596
|
+
if (/^-[runfbsVhMd]+$/.test(a)) {
|
|
29597
|
+
if (a.includes("r"))
|
|
29598
|
+
rev = true;
|
|
29599
|
+
if (a.includes("n"))
|
|
29600
|
+
num = true;
|
|
29601
|
+
if (a.includes("h"))
|
|
29602
|
+
human = true;
|
|
29603
|
+
if (a.includes("M"))
|
|
29604
|
+
month = true;
|
|
29605
|
+
if (a.includes("d"))
|
|
29606
|
+
dict = true;
|
|
29607
|
+
if (a.includes("u"))
|
|
29608
|
+
uniq = true;
|
|
29609
|
+
if (a.includes("f"))
|
|
29610
|
+
fold = true;
|
|
29611
|
+
if (a.includes("b"))
|
|
29612
|
+
blanks = true;
|
|
29613
|
+
if (a.includes("s"))
|
|
29614
|
+
stable = true;
|
|
29615
|
+
if (a.includes("V"))
|
|
29616
|
+
ver = true;
|
|
29617
|
+
}
|
|
29618
|
+
else if (a === "--reverse")
|
|
29619
|
+
rev = true;
|
|
29620
|
+
else if (a === "--numeric-sort")
|
|
29621
|
+
num = true;
|
|
29622
|
+
else if (a === "--human-numeric-sort")
|
|
29623
|
+
human = true;
|
|
29624
|
+
else if (a === "--month-sort")
|
|
29625
|
+
month = true;
|
|
29626
|
+
else if (a === "--dictionary-order")
|
|
29627
|
+
dict = true;
|
|
29628
|
+
else if (a === "--unique")
|
|
29629
|
+
uniq = true;
|
|
29630
|
+
else if (a === "--ignore-case")
|
|
29631
|
+
fold = true;
|
|
29632
|
+
else if (a === "--ignore-leading-blanks")
|
|
29633
|
+
blanks = true;
|
|
29634
|
+
else if (a === "--stable")
|
|
29635
|
+
stable = true;
|
|
29636
|
+
else if (a === "--version-sort")
|
|
29637
|
+
ver = true;
|
|
29638
|
+
else if (a === "-t" && i + 1 < opArgs.length && opArgs[i + 1].length === 1) {
|
|
29639
|
+
sep = opArgs[++i];
|
|
29640
|
+
}
|
|
29641
|
+
else if (a.startsWith("-t") && a.length === 3) {
|
|
29642
|
+
sep = a[2];
|
|
29643
|
+
}
|
|
29644
|
+
else if (a.startsWith("--field-separator=") && a.length === 19) {
|
|
29645
|
+
sep = a[18];
|
|
29646
|
+
}
|
|
29647
|
+
else if (a === "-k" && i + 1 < opArgs.length) {
|
|
29648
|
+
if (keySpec !== undefined)
|
|
29649
|
+
return undefined;
|
|
29650
|
+
keySpec = opArgs[++i];
|
|
29651
|
+
}
|
|
29652
|
+
else if (a.startsWith("-k") && a.length > 2) {
|
|
29653
|
+
if (keySpec !== undefined)
|
|
29654
|
+
return undefined;
|
|
29655
|
+
keySpec = a.slice(2);
|
|
29656
|
+
}
|
|
29657
|
+
else {
|
|
29658
|
+
return undefined;
|
|
29659
|
+
}
|
|
29660
|
+
}
|
|
29661
|
+
if (ver || keySpec?.includes("V"))
|
|
29662
|
+
return undefined;
|
|
29663
|
+
let startField = 1;
|
|
29664
|
+
let endField;
|
|
29665
|
+
let keyNum = num;
|
|
29666
|
+
let keyHuman = human;
|
|
29667
|
+
let keyMonth = month;
|
|
29668
|
+
let keyDict = dict;
|
|
29669
|
+
let keyRev = rev;
|
|
29670
|
+
let keyFold = fold;
|
|
29671
|
+
let keyBlanks = blanks;
|
|
29672
|
+
let keyVer = ver;
|
|
29673
|
+
if (keySpec !== undefined) {
|
|
29674
|
+
const km = /^([1-9][0-9]{0,2})(?:,([1-9][0-9]{0,2}))?([nrbfVhMd]*)$/.exec(keySpec);
|
|
29675
|
+
if (!km)
|
|
29676
|
+
return undefined;
|
|
29677
|
+
startField = Number(km[1]);
|
|
29678
|
+
endField = km[2] !== undefined ? Number(km[2]) : undefined;
|
|
29679
|
+
if (endField !== undefined && endField < startField)
|
|
29680
|
+
return undefined;
|
|
29681
|
+
const kf = km[3] ?? "";
|
|
29682
|
+
if (kf.includes("n"))
|
|
29683
|
+
keyNum = true;
|
|
29684
|
+
if (kf.includes("h"))
|
|
29685
|
+
keyHuman = true;
|
|
29686
|
+
if (kf.includes("M"))
|
|
29687
|
+
keyMonth = true;
|
|
29688
|
+
if (kf.includes("d"))
|
|
29689
|
+
keyDict = true;
|
|
29690
|
+
if (kf.includes("r"))
|
|
29691
|
+
keyRev = true;
|
|
29692
|
+
if (kf.includes("f"))
|
|
29693
|
+
keyFold = true;
|
|
29694
|
+
if (kf.includes("b"))
|
|
29695
|
+
keyBlanks = true;
|
|
29696
|
+
if (kf.includes("V"))
|
|
29697
|
+
keyVer = true;
|
|
29698
|
+
}
|
|
29699
|
+
const extractKey = (l) => {
|
|
29700
|
+
let raw = keySpec === undefined
|
|
29701
|
+
? l
|
|
29702
|
+
: (() => {
|
|
29703
|
+
if (sep !== undefined) {
|
|
29704
|
+
const fields = l.split(sep);
|
|
29705
|
+
return fields.slice(startField - 1, endField).join(sep);
|
|
29706
|
+
}
|
|
29707
|
+
// Default fields include their leading blanks; retain exact bytes.
|
|
29708
|
+
let offset = 0;
|
|
29709
|
+
let start = l.length;
|
|
29710
|
+
let end = l.length;
|
|
29711
|
+
for (let field = 1; offset < l.length; field++) {
|
|
29712
|
+
if (field === startField)
|
|
29713
|
+
start = offset;
|
|
29714
|
+
while (l[offset] === " " || l[offset] === "\t")
|
|
29715
|
+
offset++;
|
|
29716
|
+
while (offset < l.length && l[offset] !== " " && l[offset] !== "\t")
|
|
29717
|
+
offset++;
|
|
29718
|
+
if (field === endField) {
|
|
29719
|
+
end = offset;
|
|
29720
|
+
break;
|
|
29721
|
+
}
|
|
29722
|
+
}
|
|
29723
|
+
return l.slice(start, end);
|
|
29724
|
+
})();
|
|
29725
|
+
if (keyBlanks)
|
|
29726
|
+
raw = raw.replace(/^[ \t]+/, "");
|
|
29727
|
+
if (keyDict)
|
|
29728
|
+
raw = raw.replace(/[^a-zA-Z0-9 \t]+/g, "");
|
|
29729
|
+
return keyFold ? raw.toUpperCase() : raw;
|
|
29730
|
+
};
|
|
27463
29731
|
const parseNum = (s) => {
|
|
27464
|
-
const m = /^[ \t]*(
|
|
29732
|
+
const m = /^[ \t]*(-?(?:\d+(?:\.\d*)?|\.\d+))/.exec(s);
|
|
27465
29733
|
return m ? Number(m[1]) : 0;
|
|
27466
29734
|
};
|
|
29735
|
+
const compareHuman = (sa, sb) => {
|
|
29736
|
+
const parseH = (s) => {
|
|
29737
|
+
const m = /^[ \t]*(-?(?:\d+(?:\.\d*)?|\.\d+))([KMGTPEZYkmgtpezy])?/.exec(s);
|
|
29738
|
+
if (!m)
|
|
29739
|
+
return { sign: 0, unit: 0, val: 0 };
|
|
29740
|
+
const val = Number(m[1]);
|
|
29741
|
+
if (val === 0)
|
|
29742
|
+
return { sign: 0, unit: 0, val: 0 };
|
|
29743
|
+
const uChar = m[2] ? m[2].toUpperCase() : "";
|
|
29744
|
+
const unit = uChar === "" ? 0 : "KMGTPEZY".indexOf(uChar) + 1;
|
|
29745
|
+
return { sign: val < 0 ? -1 : 1, unit, val };
|
|
29746
|
+
};
|
|
29747
|
+
const ha = parseH(sa);
|
|
29748
|
+
const hb = parseH(sb);
|
|
29749
|
+
if (ha.sign !== hb.sign)
|
|
29750
|
+
return ha.sign - hb.sign;
|
|
29751
|
+
if (ha.unit !== hb.unit)
|
|
29752
|
+
return ha.sign < 0 ? hb.unit - ha.unit : ha.unit - hb.unit;
|
|
29753
|
+
return ha.val - hb.val;
|
|
29754
|
+
};
|
|
29755
|
+
const parseMonth = (s) => {
|
|
29756
|
+
const m = /^[ \t]*([a-zA-Z]{3})/.exec(s);
|
|
29757
|
+
if (!m)
|
|
29758
|
+
return 0;
|
|
29759
|
+
const idx = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"].indexOf(m[1].toUpperCase());
|
|
29760
|
+
return idx === -1 ? 0 : idx + 1;
|
|
29761
|
+
};
|
|
27467
29762
|
const sorted = [...rawLines].sort((a, b) => {
|
|
27468
|
-
|
|
27469
|
-
|
|
27470
|
-
|
|
29763
|
+
const ka = extractKey(a);
|
|
29764
|
+
const kb = extractKey(b);
|
|
29765
|
+
if (keyHuman) {
|
|
29766
|
+
const hc = compareHuman(ka, kb);
|
|
29767
|
+
if (hc !== 0)
|
|
29768
|
+
return keyRev ? -hc : hc;
|
|
29769
|
+
}
|
|
29770
|
+
else if (keyMonth) {
|
|
29771
|
+
const ma = parseMonth(ka);
|
|
29772
|
+
const mb = parseMonth(kb);
|
|
29773
|
+
if (ma !== mb)
|
|
29774
|
+
return keyRev ? mb - ma : ma - mb;
|
|
29775
|
+
}
|
|
29776
|
+
else if (keyNum) {
|
|
29777
|
+
const na = parseNum(ka);
|
|
29778
|
+
const nb = parseNum(kb);
|
|
27471
29779
|
if (na !== nb)
|
|
27472
|
-
return
|
|
29780
|
+
return keyRev ? nb - na : na - nb;
|
|
29781
|
+
}
|
|
29782
|
+
else if (keyVer) {
|
|
29783
|
+
const vc = this.compareSyncVersion(ka, kb);
|
|
29784
|
+
if (vc !== 0)
|
|
29785
|
+
return keyRev ? -vc : vc;
|
|
27473
29786
|
}
|
|
29787
|
+
else if (ka !== kb) {
|
|
29788
|
+
return ka < kb ? (keyRev ? 1 : -1) : (keyRev ? -1 : 1);
|
|
29789
|
+
}
|
|
29790
|
+
if (uniq || stable)
|
|
29791
|
+
return 0;
|
|
29792
|
+
const fa = fold ? a.toUpperCase() : a;
|
|
29793
|
+
const fb = fold ? b.toUpperCase() : b;
|
|
29794
|
+
if (fa !== fb)
|
|
29795
|
+
return fa < fb ? (rev ? 1 : -1) : (rev ? -1 : 1);
|
|
27474
29796
|
return a < b ? (rev ? 1 : -1) : a > b ? (rev ? -1 : 1) : 0;
|
|
27475
29797
|
});
|
|
27476
29798
|
if (!uniq)
|
|
27477
29799
|
return sorted;
|
|
27478
29800
|
const dedup = [];
|
|
27479
29801
|
for (let i = 0; i < sorted.length; i++) {
|
|
27480
|
-
if (i === 0
|
|
29802
|
+
if (i === 0) {
|
|
27481
29803
|
dedup.push(sorted[i]);
|
|
29804
|
+
}
|
|
29805
|
+
else {
|
|
29806
|
+
const ka = extractKey(sorted[i]);
|
|
29807
|
+
const kb = extractKey(sorted[i - 1]);
|
|
29808
|
+
const same = keyHuman ? compareHuman(ka, kb) === 0 : keyMonth ? parseMonth(ka) === parseMonth(kb) : keyNum ? parseNum(ka) === parseNum(kb) : keyVer ? this.compareSyncVersion(ka, kb) === 0 : ka === kb;
|
|
29809
|
+
if (!same)
|
|
29810
|
+
dedup.push(sorted[i]);
|
|
29811
|
+
}
|
|
27482
29812
|
}
|
|
27483
29813
|
return dedup;
|
|
27484
29814
|
}
|
|
27485
|
-
|
|
27486
|
-
if (
|
|
27487
|
-
return
|
|
27488
|
-
if (
|
|
27489
|
-
return
|
|
27490
|
-
|
|
29815
|
+
normalizeSyncWcFlag(arg) {
|
|
29816
|
+
if (arg === "-l" || arg === "--lines")
|
|
29817
|
+
return "-l";
|
|
29818
|
+
if (arg === "-c" || arg === "--bytes")
|
|
29819
|
+
return "-c";
|
|
29820
|
+
if (arg === "-w" || arg === "--words")
|
|
29821
|
+
return "-w";
|
|
29822
|
+
if (arg === "-m" || arg === "--chars")
|
|
29823
|
+
return "-m";
|
|
29824
|
+
if (arg === "-L" || arg === "--max-line-length")
|
|
29825
|
+
return "-L";
|
|
29826
|
+
return undefined;
|
|
29827
|
+
}
|
|
29828
|
+
evalSyncUniq(rawLines, opArgs) {
|
|
29829
|
+
let ignoreCase = false;
|
|
29830
|
+
let hasCount = false;
|
|
29831
|
+
let onlyRepeated = false;
|
|
29832
|
+
let onlyUnique = false;
|
|
29833
|
+
let skipFields = 0;
|
|
29834
|
+
let skipChars = 0;
|
|
29835
|
+
let checkChars = Infinity;
|
|
29836
|
+
for (let i = 0; i < opArgs.length; i++) {
|
|
29837
|
+
const a = opArgs[i];
|
|
29838
|
+
if (a === "--ignore-case")
|
|
29839
|
+
ignoreCase = true;
|
|
29840
|
+
else if (a === "--count")
|
|
29841
|
+
hasCount = true;
|
|
29842
|
+
else if (a === "--repeated")
|
|
29843
|
+
onlyRepeated = true;
|
|
29844
|
+
else if (a === "--unique")
|
|
29845
|
+
onlyUnique = true;
|
|
29846
|
+
else if (/^--skip-fields=[0-9]{1,4}$/.test(a))
|
|
29847
|
+
skipFields = Number(a.slice(14));
|
|
29848
|
+
else if (/^--skip-chars=[0-9]{1,4}$/.test(a))
|
|
29849
|
+
skipChars = Number(a.slice(13));
|
|
29850
|
+
else if (/^--check-chars=[0-9]{1,4}$/.test(a))
|
|
29851
|
+
checkChars = Number(a.slice(14));
|
|
29852
|
+
else if ((a === "-f" || a === "-s" || a === "-w") && i + 1 < opArgs.length && /^[0-9]{1,4}$/.test(opArgs[i + 1])) {
|
|
29853
|
+
const n = Number(opArgs[++i]);
|
|
29854
|
+
if (a === "-f")
|
|
29855
|
+
skipFields = n;
|
|
29856
|
+
else if (a === "-s")
|
|
29857
|
+
skipChars = n;
|
|
29858
|
+
else
|
|
29859
|
+
checkChars = n;
|
|
29860
|
+
}
|
|
29861
|
+
else if (/^-[fsw][0-9]{1,4}$/.test(a)) {
|
|
29862
|
+
const n = Number(a.slice(2));
|
|
29863
|
+
if (a[1] === "f")
|
|
29864
|
+
skipFields = n;
|
|
29865
|
+
else if (a[1] === "s")
|
|
29866
|
+
skipChars = n;
|
|
29867
|
+
else
|
|
29868
|
+
checkChars = n;
|
|
29869
|
+
}
|
|
29870
|
+
else if (/^-[cdui]+$/.test(a)) {
|
|
29871
|
+
for (let k = 1; k < a.length; k++) {
|
|
29872
|
+
const ch = a[k];
|
|
29873
|
+
if (ch === "i")
|
|
29874
|
+
ignoreCase = true;
|
|
29875
|
+
else if (ch === "c")
|
|
29876
|
+
hasCount = true;
|
|
29877
|
+
else if (ch === "d")
|
|
29878
|
+
onlyRepeated = true;
|
|
29879
|
+
else if (ch === "u")
|
|
29880
|
+
onlyUnique = true;
|
|
29881
|
+
}
|
|
29882
|
+
}
|
|
29883
|
+
else {
|
|
29884
|
+
return undefined;
|
|
29885
|
+
}
|
|
29886
|
+
}
|
|
29887
|
+
const keyOf = (l) => {
|
|
29888
|
+
let offset = 0;
|
|
29889
|
+
for (let f = 0; f < skipFields; f++) {
|
|
29890
|
+
while (offset < l.length && (l[offset] === " " || l[offset] === "\t"))
|
|
29891
|
+
offset++;
|
|
29892
|
+
while (offset < l.length && l[offset] !== " " && l[offset] !== "\t")
|
|
29893
|
+
offset++;
|
|
29894
|
+
}
|
|
29895
|
+
if (skipChars === 0 && checkChars === Infinity) {
|
|
29896
|
+
const sub = l.slice(offset);
|
|
29897
|
+
return ignoreCase ? sub.toLowerCase() : sub;
|
|
29898
|
+
}
|
|
29899
|
+
const chars = Array.from(l.slice(offset));
|
|
29900
|
+
const sub = (checkChars === Infinity ? chars.slice(skipChars) : chars.slice(skipChars, skipChars + checkChars)).join("");
|
|
29901
|
+
return ignoreCase ? sub.toLowerCase() : sub;
|
|
29902
|
+
};
|
|
29903
|
+
const outLines = [];
|
|
29904
|
+
let uIdx = 0;
|
|
29905
|
+
while (uIdx < rawLines.length) {
|
|
29906
|
+
const k0 = keyOf(rawLines[uIdx]);
|
|
29907
|
+
let uEnd = uIdx + 1;
|
|
29908
|
+
while (uEnd < rawLines.length && keyOf(rawLines[uEnd]) === k0)
|
|
29909
|
+
uEnd++;
|
|
29910
|
+
const count = uEnd - uIdx;
|
|
29911
|
+
if ((!onlyRepeated || count > 1) && (!onlyUnique || count === 1)) {
|
|
29912
|
+
outLines.push(hasCount ? `${String(count).padStart(7, " ")} ${rawLines[uIdx]}` : rawLines[uIdx]);
|
|
29913
|
+
}
|
|
29914
|
+
uIdx = uEnd;
|
|
29915
|
+
}
|
|
29916
|
+
return outLines;
|
|
29917
|
+
}
|
|
29918
|
+
sortSyncLines(rawLines, flag) {
|
|
29919
|
+
return this.evalSyncSort(rawLines, flag !== undefined ? [flag] : [], false) ?? [...rawLines];
|
|
29920
|
+
}
|
|
29921
|
+
translateSyncTr(input, set1Spec, set2Spec, truncateSet1 = false) {
|
|
29922
|
+
if ((set1Spec === "a-z" || set1Spec === "[:lower:]") && (set2Spec === "A-Z" || set2Spec === "[:upper:]")) {
|
|
29923
|
+
return input.replace(/[a-z]/g, ch => String.fromCharCode(ch.charCodeAt(0) - 32));
|
|
29924
|
+
}
|
|
29925
|
+
if ((set1Spec === "A-Z" || set1Spec === "[:upper:]") && (set2Spec === "a-z" || set2Spec === "[:lower:]")) {
|
|
29926
|
+
return input.replace(/[A-Z]/g, ch => String.fromCharCode(ch.charCodeAt(0) + 32));
|
|
29927
|
+
}
|
|
29928
|
+
const rawS1 = this.expandSyncTrCharArray(set1Spec);
|
|
27491
29929
|
const s2 = this.expandSyncTrCharArray(set2Spec);
|
|
27492
|
-
if (!
|
|
29930
|
+
if (!rawS1 || !s2 || rawS1.length === 0 || s2.length === 0)
|
|
27493
29931
|
return undefined;
|
|
29932
|
+
const s1 = truncateSet1 ? rawS1.slice(0, s2.length) : rawS1;
|
|
29933
|
+
if (s1.length === 0)
|
|
29934
|
+
return input;
|
|
27494
29935
|
if (s1.length === 1 && s2.length === 1)
|
|
27495
29936
|
return input.split(s1[0]).join(s2[0]);
|
|
27496
29937
|
const map = new Map();
|
|
@@ -27684,7 +30125,7 @@ export class Runtime {
|
|
|
27684
30125
|
if (!sName || hasShellFunction(rawState, sName) || rawState.extensions?.builtins.has(sName))
|
|
27685
30126
|
return undefined;
|
|
27686
30127
|
const extDef = this.getExternalCommand(sName);
|
|
27687
|
-
if (!extDef || (sName !== "rev" && sName !== "tac" &&
|
|
30128
|
+
if (!extDef || (sName !== "rev" && sName !== "tac" && sName !== "nl" && sName !== "paste" && sName !== "jq" && !builtInDirectContextExecutors.has(extDef.execute)) || customRegisteredCommands.has(extDef.execute))
|
|
27688
30129
|
return undefined;
|
|
27689
30130
|
if (!this.arePureArgWords(sCmd.words, rawState))
|
|
27690
30131
|
return undefined;
|
|
@@ -27704,29 +30145,32 @@ export class Runtime {
|
|
|
27704
30145
|
return undefined;
|
|
27705
30146
|
}
|
|
27706
30147
|
else if (sName === "uniq") {
|
|
27707
|
-
if (
|
|
30148
|
+
if (this.evalSyncUniq([], sArgs) === undefined)
|
|
27708
30149
|
return undefined;
|
|
27709
30150
|
}
|
|
27710
30151
|
else if (sName === "sort") {
|
|
27711
|
-
if (
|
|
30152
|
+
if (this.evalSyncSort([], sArgs, byteLocale(rawState.variables)) === undefined)
|
|
27712
30153
|
return undefined;
|
|
27713
30154
|
}
|
|
27714
30155
|
else if (sName === "head" || sName === "tail") {
|
|
27715
30156
|
if (sArgs.length === 0) {
|
|
27716
30157
|
sArgs.push("-n", "10");
|
|
27717
30158
|
}
|
|
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);
|
|
30159
|
+
else if (sArgs.length === 1 && (/^-(?:n|c)?[0-9]+$/.test(sArgs[0]) || /^--(?:lines|bytes)=[0-9]+$/.test(sArgs[0]) || (sName === "tail" && /^(?:-n|--lines=)\+[0-9]+$/.test(sArgs[0])) || (sName === "head" && /^(?:-n|--lines=)-[0-9]+$/.test(sArgs[0])))) {
|
|
30160
|
+
const flag = (sArgs[0].startsWith("-c") || sArgs[0].startsWith("--bytes=")) ? "-c" : "-n";
|
|
30161
|
+
const numStr = sArgs[0].startsWith("--") ? sArgs[0].slice(sArgs[0].indexOf("=") + 1) : ((sArgs[0].startsWith("-n") || sArgs[0].startsWith("-c")) ? sArgs[0].slice(2) : sArgs[0].slice(1));
|
|
27721
30162
|
sArgs.length = 0;
|
|
27722
30163
|
sArgs.push(flag, numStr);
|
|
27723
30164
|
}
|
|
27724
|
-
|
|
30165
|
+
const validNum = sArgs.length === 2 && ((sArgs[0] === "-n" && (/^[0-9]+$/.test(sArgs[1]) || (sName === "tail" && /^\+[0-9]+$/.test(sArgs[1])) || (sName === "head" && /^-[0-9]+$/.test(sArgs[1])))) || (sArgs[0] === "-c" && /^[0-9]+$/.test(sArgs[1])));
|
|
30166
|
+
if (!validNum)
|
|
27725
30167
|
return undefined;
|
|
27726
30168
|
}
|
|
27727
30169
|
else if (sName === "wc") {
|
|
27728
|
-
|
|
30170
|
+
const normWc = sArgs.length === 1 ? this.normalizeSyncWcFlag(sArgs[0]) : undefined;
|
|
30171
|
+
if (!normWc)
|
|
27729
30172
|
return undefined;
|
|
30173
|
+
sArgs[0] = normWc;
|
|
27730
30174
|
}
|
|
27731
30175
|
else if (sName === "sed") {
|
|
27732
30176
|
if (this.evalSyncSed([], sArgs) === undefined)
|
|
@@ -27745,17 +30189,33 @@ export class Runtime {
|
|
|
27745
30189
|
return undefined;
|
|
27746
30190
|
}
|
|
27747
30191
|
else if (sName === "jq") {
|
|
27748
|
-
if (
|
|
30192
|
+
if (sArgs.length === 0 || sArgs.length > 2)
|
|
30193
|
+
return undefined;
|
|
30194
|
+
if (sArgs.length === 1 && sArgs[0].startsWith("-"))
|
|
30195
|
+
return undefined;
|
|
30196
|
+
if (sArgs.length === 2 && !["-r", "--raw-output", "-c", "--compact-output", "-rc", "-cr"].includes(sArgs[0]))
|
|
27749
30197
|
return undefined;
|
|
27750
30198
|
}
|
|
27751
30199
|
else if (sName === "base64") {
|
|
27752
30200
|
if (sArgs.length > 1 || (sArgs.length === 1 && sArgs[0] !== "-d" && sArgs[0] !== "--decode"))
|
|
27753
30201
|
return undefined;
|
|
27754
30202
|
}
|
|
27755
|
-
else if (sName === "tac"
|
|
30203
|
+
else if (sName === "tac") {
|
|
27756
30204
|
if (sArgs.length !== 0)
|
|
27757
30205
|
return undefined;
|
|
27758
30206
|
}
|
|
30207
|
+
else if (sName === "nl") {
|
|
30208
|
+
if (this.evalSyncNl([], sArgs) === undefined)
|
|
30209
|
+
return undefined;
|
|
30210
|
+
}
|
|
30211
|
+
else if (sName === "paste") {
|
|
30212
|
+
if (this.evalSyncPaste([], sArgs) === undefined)
|
|
30213
|
+
return undefined;
|
|
30214
|
+
}
|
|
30215
|
+
else if (sName === "numfmt") {
|
|
30216
|
+
if (this.evalSyncNumfmt([], sArgs) === undefined)
|
|
30217
|
+
return undefined;
|
|
30218
|
+
}
|
|
27759
30219
|
else {
|
|
27760
30220
|
return undefined;
|
|
27761
30221
|
}
|
|
@@ -27843,8 +30303,10 @@ export class Runtime {
|
|
|
27843
30303
|
const isInlineBase64 = firstName === "base64";
|
|
27844
30304
|
const isInlineTac = firstName === "tac";
|
|
27845
30305
|
const isInlineNl = firstName === "nl";
|
|
27846
|
-
const
|
|
27847
|
-
const
|
|
30306
|
+
const isInlinePaste = firstName === "paste";
|
|
30307
|
+
const isInlineNumfmt = firstName === "numfmt";
|
|
30308
|
+
const isInlineSort = firstName === "sort" && !byteLocale(rawState.variables);
|
|
30309
|
+
const isInlineUniq = firstName === "uniq";
|
|
27848
30310
|
const inlineSedMatch = firstName === "sed";
|
|
27849
30311
|
if (firstName === "rev" ||
|
|
27850
30312
|
firstName === "head" ||
|
|
@@ -27861,10 +30323,13 @@ export class Runtime {
|
|
|
27861
30323
|
isInlineJq ||
|
|
27862
30324
|
isInlineBase64 ||
|
|
27863
30325
|
isInlineTac ||
|
|
27864
|
-
isInlineNl
|
|
30326
|
+
isInlineNl ||
|
|
30327
|
+
isInlinePaste ||
|
|
30328
|
+
isInlineNumfmt) {
|
|
27865
30329
|
const inStr = prevLen === 0 ? "" : sharedSyncPipeDecoder.decode(prevBuf.subarray(0, prevLen));
|
|
27866
30330
|
const rawLines = inStr.length === 0 ? [] : (inStr.endsWith("\n") ? inStr.slice(0, -1).split("\n") : inStr.split("\n"));
|
|
27867
30331
|
let outLines = [];
|
|
30332
|
+
let sedTerminated = false;
|
|
27868
30333
|
if (firstName === "rev") {
|
|
27869
30334
|
outLines = rawLines.map(l => Array.from(l).reverse().join(""));
|
|
27870
30335
|
}
|
|
@@ -27883,7 +30348,16 @@ export class Runtime {
|
|
|
27883
30348
|
prevLen = sub.byteLength;
|
|
27884
30349
|
continue;
|
|
27885
30350
|
}
|
|
27886
|
-
|
|
30351
|
+
if (firstName === "tail" && stageArgs[1].startsWith("+")) {
|
|
30352
|
+
outLines = rawLines.slice(Math.max(0, count - 1));
|
|
30353
|
+
}
|
|
30354
|
+
else if (firstName === "head" && stageArgs[1].startsWith("-")) {
|
|
30355
|
+
const drop = Math.abs(count);
|
|
30356
|
+
outLines = drop === 0 ? [...rawLines] : rawLines.slice(0, Math.max(0, rawLines.length - drop));
|
|
30357
|
+
}
|
|
30358
|
+
else {
|
|
30359
|
+
outLines = firstName === "head" ? rawLines.slice(0, count) : (count === 0 ? [] : rawLines.slice(-count));
|
|
30360
|
+
}
|
|
27887
30361
|
}
|
|
27888
30362
|
else if (firstName === "wc") {
|
|
27889
30363
|
if (stageArgs[0] === "-l") {
|
|
@@ -27897,6 +30371,12 @@ export class Runtime {
|
|
|
27897
30371
|
const trimmed = inStr.trim();
|
|
27898
30372
|
outLines = [String(trimmed.length === 0 ? 0 : trimmed.split(/[ \t\n\r\f\v]+/).length)];
|
|
27899
30373
|
}
|
|
30374
|
+
else if (stageArgs[0] === "-m") {
|
|
30375
|
+
outLines = [String(byteLocale(rawState.variables) ? prevLen : Array.from(inStr).length)];
|
|
30376
|
+
}
|
|
30377
|
+
else if (stageArgs[0] === "-L") {
|
|
30378
|
+
outLines = [String(this.wcMaxLineWidth(inStr, byteLocale(rawState.variables)))];
|
|
30379
|
+
}
|
|
27900
30380
|
else {
|
|
27901
30381
|
outLines = [String(prevLen)];
|
|
27902
30382
|
}
|
|
@@ -27924,28 +30404,20 @@ export class Runtime {
|
|
|
27924
30404
|
continue;
|
|
27925
30405
|
}
|
|
27926
30406
|
else if (isInlineSort) {
|
|
27927
|
-
outLines = this.
|
|
30407
|
+
outLines = this.evalSyncSort(rawLines, stageArgs, false) ?? [];
|
|
27928
30408
|
}
|
|
27929
30409
|
else if (isInlineUniq) {
|
|
27930
|
-
const
|
|
27931
|
-
|
|
27932
|
-
|
|
27933
|
-
|
|
27934
|
-
let uEnd = uIdx + 1;
|
|
27935
|
-
while (uEnd < rawLines.length && rawLines[uEnd] === rawLines[uIdx])
|
|
27936
|
-
uEnd++;
|
|
27937
|
-
const count = uEnd - uIdx;
|
|
27938
|
-
if (mode === "-d" ? count > 1 : mode === "-u" ? count === 1 : true) {
|
|
27939
|
-
outLines.push(mode === "-c" ? `${String(count).padStart(7, " ")} ${rawLines[uIdx]}` : rawLines[uIdx]);
|
|
27940
|
-
}
|
|
27941
|
-
uIdx = uEnd;
|
|
27942
|
-
}
|
|
30410
|
+
const uniqRes = this.evalSyncUniq(rawLines, stageArgs);
|
|
30411
|
+
if (uniqRes === undefined)
|
|
30412
|
+
return undefined;
|
|
30413
|
+
outLines = uniqRes;
|
|
27943
30414
|
}
|
|
27944
30415
|
else if (inlineSedMatch) {
|
|
27945
30416
|
const sedRes = this.evalSyncSed(rawLines, stageArgs);
|
|
27946
30417
|
if (sedRes === undefined)
|
|
27947
30418
|
return undefined;
|
|
27948
|
-
outLines = sedRes;
|
|
30419
|
+
outLines = sedRes.lines;
|
|
30420
|
+
sedTerminated = sedRes.lastInputIndex < rawLines.length - 1;
|
|
27949
30421
|
}
|
|
27950
30422
|
else if (isInlineAwk) {
|
|
27951
30423
|
const awkRes = this.evalSyncAwk(rawLines, stageArgs);
|
|
@@ -27968,17 +30440,22 @@ export class Runtime {
|
|
|
27968
30440
|
outLines = [...rawLines].reverse();
|
|
27969
30441
|
}
|
|
27970
30442
|
else if (isInlineNl) {
|
|
27971
|
-
|
|
27972
|
-
|
|
27973
|
-
|
|
27974
|
-
|
|
27975
|
-
|
|
27976
|
-
|
|
27977
|
-
|
|
27978
|
-
|
|
27979
|
-
|
|
27980
|
-
|
|
27981
|
-
|
|
30443
|
+
const nlRes = this.evalSyncNl(rawLines, stageArgs);
|
|
30444
|
+
if (nlRes === undefined)
|
|
30445
|
+
return undefined;
|
|
30446
|
+
outLines = nlRes;
|
|
30447
|
+
}
|
|
30448
|
+
else if (isInlinePaste) {
|
|
30449
|
+
const pasteRes = this.evalSyncPaste(rawLines, stageArgs);
|
|
30450
|
+
if (pasteRes === undefined)
|
|
30451
|
+
return undefined;
|
|
30452
|
+
outLines = pasteRes;
|
|
30453
|
+
}
|
|
30454
|
+
else if (isInlineNumfmt) {
|
|
30455
|
+
const nmRes = this.evalSyncNumfmt(rawLines, stageArgs);
|
|
30456
|
+
if (nmRes === undefined)
|
|
30457
|
+
return undefined;
|
|
30458
|
+
outLines = nmRes;
|
|
27982
30459
|
}
|
|
27983
30460
|
else if (isInlineBase64) {
|
|
27984
30461
|
if (stageArgs.length === 0) {
|
|
@@ -27990,7 +30467,7 @@ export class Runtime {
|
|
|
27990
30467
|
if (cleaned.length % 4 !== 0 || (cleaned.length > 0 && !/^[A-Za-z0-9+/]+={0,2}$/.test(cleaned)))
|
|
27991
30468
|
return undefined;
|
|
27992
30469
|
const decoded = this.syncBase64DecodeBytes(cleaned);
|
|
27993
|
-
if (decoded.
|
|
30470
|
+
if (decoded.some(byte => byte === 0 || byte >= 128) || decoded.byteLength > nextBuf.byteLength)
|
|
27994
30471
|
return undefined;
|
|
27995
30472
|
const nextTotalBytes = this.budget.bytes + decoded.byteLength;
|
|
27996
30473
|
if (nextTotalBytes > this.budget.maxOutputBytesSmi && decoded.byteLength > this.budget.limits.maxOutputBytes - this.budget.bytes)
|
|
@@ -28010,7 +30487,7 @@ export class Runtime {
|
|
|
28010
30487
|
}
|
|
28011
30488
|
// These filters preserve the terminator of the final selected input line.
|
|
28012
30489
|
const preservesTerminator = firstName === "head" || firstName === "tail" || firstName === "rev" || firstName === "sed";
|
|
28013
|
-
const terminated = !preservesTerminator || inStr.endsWith("\n") || firstName === "head" && outLines.length < rawLines.length;
|
|
30490
|
+
const terminated = sedTerminated || !preservesTerminator || inStr.endsWith("\n") || firstName === "head" && outLines.length < rawLines.length;
|
|
28014
30491
|
const outStr = outLines.length > 0 ? outLines.join("\n") + (terminated ? "\n" : "") : "";
|
|
28015
30492
|
const outByteLen = shellValueByteLength(outStr);
|
|
28016
30493
|
if (outByteLen > nextBuf.byteLength)
|
|
@@ -28175,8 +30652,8 @@ export class Runtime {
|
|
|
28175
30652
|
w0Plain === "sort" ||
|
|
28176
30653
|
w0Plain === "uniq" ||
|
|
28177
30654
|
w0Plain === "tr" ||
|
|
28178
|
-
(hasSingleHereStringRedir && (w0Plain === "base64" || w0Plain === "rev" || w0Plain === "tac" || w0Plain === "nl"));
|
|
28179
|
-
if (isSingleFileTool && !hasShellFunction(rawState, w0Plain) && (this.commands.has(w0Plain) || ((w0Plain === "rev" || w0Plain === "tac") && Boolean(this.getExternalCommand(w0Plain))))) {
|
|
30655
|
+
(hasSingleHereStringRedir && (w0Plain === "base64" || w0Plain === "rev" || w0Plain === "tac" || w0Plain === "nl" || w0Plain === "paste" || w0Plain === "numfmt"));
|
|
30656
|
+
if (isSingleFileTool && !hasShellFunction(rawState, w0Plain) && (this.commands.has(w0Plain) || ((w0Plain === "rev" || w0Plain === "tac" || w0Plain === "nl" || w0Plain === "paste") && Boolean(this.getExternalCommand(w0Plain))))) {
|
|
28180
30657
|
const allArgs = [];
|
|
28181
30658
|
let fOk = true;
|
|
28182
30659
|
for (let i = 1; i < cmd.words.length; i++) {
|
|
@@ -28216,6 +30693,12 @@ export class Runtime {
|
|
|
28216
30693
|
// Non-ASCII file inputs use normal execution, which owns their raw ShellValue.
|
|
28217
30694
|
if (view && view.byteLength <= 16384 && !view.includes(0) && (hasSingleHereStringRedir || view.every(byte => byte < 128))) {
|
|
28218
30695
|
const fileStr = hasSingleHereStringRedir ? hereStrVal : sharedSyncPipeDecoder.decode(view);
|
|
30696
|
+
// Record-based shortcuts below serialize complete newline-terminated records.
|
|
30697
|
+
// Let normal commands preserve partial final records when reading files.
|
|
30698
|
+
if (fileStr.length > 0 && !fileStr.endsWith("\n") &&
|
|
30699
|
+
(w0Plain === "head" || w0Plain === "tail" || w0Plain === "sed" || w0Plain === "cut" || w0Plain === "uniq"))
|
|
30700
|
+
return undefined;
|
|
30701
|
+
const renderLines = (lines) => lines.length === 0 ? "" : lines.join("\n") + "\n";
|
|
28219
30702
|
const rawLines = fileStr.endsWith("\n") ? fileStr.slice(0, -1).split("\n") : (fileStr.length === 0 ? [] : fileStr.split("\n"));
|
|
28220
30703
|
let fileRes;
|
|
28221
30704
|
let exitStatus = 0;
|
|
@@ -28225,19 +30708,36 @@ export class Runtime {
|
|
|
28225
30708
|
else if ((w0Plain === "head" || w0Plain === "tail") && opArgs.length <= 2) {
|
|
28226
30709
|
let count = opArgs.length === 0 ? 10 : undefined;
|
|
28227
30710
|
let byteCount;
|
|
28228
|
-
|
|
28229
|
-
|
|
28230
|
-
|
|
28231
|
-
|
|
30711
|
+
let countRaw = opArgs.length === 0 ? "10" : undefined;
|
|
30712
|
+
if (opArgs.length === 1 && (opArgs[0].startsWith("-n") || opArgs[0].startsWith("--lines="))) {
|
|
30713
|
+
const sub = opArgs[0].startsWith("--lines=") ? opArgs[0].slice(8) : opArgs[0].slice(2);
|
|
30714
|
+
if (/^[0-9]{1,5}$/.test(sub) || (w0Plain === "tail" && /^\+[0-9]{1,5}$/.test(sub)) || (w0Plain === "head" && /^-[0-9]{1,5}$/.test(sub)))
|
|
30715
|
+
countRaw = sub;
|
|
30716
|
+
}
|
|
30717
|
+
else if (opArgs.length === 1 && (opArgs[0].startsWith("-c") || opArgs[0].startsWith("--bytes="))) {
|
|
30718
|
+
const sub = opArgs[0].startsWith("--bytes=") ? opArgs[0].slice(8) : opArgs[0].slice(2);
|
|
30719
|
+
if (/^[0-9]{1,5}$/.test(sub))
|
|
30720
|
+
byteCount = Number(sub);
|
|
30721
|
+
}
|
|
28232
30722
|
else if (opArgs.length === 1 && /^-[0-9]{1,5}$/.test(opArgs[0]))
|
|
28233
|
-
|
|
28234
|
-
else if (opArgs.length === 2 && opArgs[0] === "-n" && /^[0-9]{1,5}$/.test(opArgs[1]))
|
|
28235
|
-
|
|
30723
|
+
countRaw = opArgs[0].slice(1);
|
|
30724
|
+
else if (opArgs.length === 2 && opArgs[0] === "-n" && (/^[0-9]{1,5}$/.test(opArgs[1]) || (w0Plain === "tail" && /^\+[0-9]{1,5}$/.test(opArgs[1])) || (w0Plain === "head" && /^-[0-9]{1,5}$/.test(opArgs[1]))))
|
|
30725
|
+
countRaw = opArgs[1];
|
|
28236
30726
|
else if (opArgs.length === 2 && opArgs[0] === "-c" && /^[0-9]{1,5}$/.test(opArgs[1]))
|
|
28237
30727
|
byteCount = Number(opArgs[1]);
|
|
28238
|
-
if (
|
|
28239
|
-
|
|
28240
|
-
|
|
30728
|
+
if (countRaw !== undefined) {
|
|
30729
|
+
count = Number(countRaw);
|
|
30730
|
+
let sliced;
|
|
30731
|
+
if (w0Plain === "tail" && countRaw.startsWith("+"))
|
|
30732
|
+
sliced = rawLines.slice(Math.max(0, count - 1));
|
|
30733
|
+
else if (w0Plain === "head" && countRaw.startsWith("-")) {
|
|
30734
|
+
const drop = Math.abs(count);
|
|
30735
|
+
sliced = drop === 0 ? [...rawLines] : rawLines.slice(0, Math.max(0, rawLines.length - drop));
|
|
30736
|
+
}
|
|
30737
|
+
else {
|
|
30738
|
+
sliced = w0Plain === "head" ? rawLines.slice(0, count) : (count === 0 ? [] : rawLines.slice(-count));
|
|
30739
|
+
}
|
|
30740
|
+
fileRes = renderLines(sliced);
|
|
28241
30741
|
}
|
|
28242
30742
|
else if (byteCount !== undefined) {
|
|
28243
30743
|
const slicedBytes = w0Plain === "head"
|
|
@@ -28249,91 +30749,109 @@ export class Runtime {
|
|
|
28249
30749
|
else if (w0Plain === "jq") {
|
|
28250
30750
|
const jqRes = this.evalSyncJq(fileStr.trim(), opArgs);
|
|
28251
30751
|
if (jqRes !== undefined)
|
|
28252
|
-
fileRes = jqRes
|
|
30752
|
+
fileRes = renderLines(jqRes);
|
|
28253
30753
|
}
|
|
28254
30754
|
else if (w0Plain === "awk") {
|
|
28255
30755
|
const awkRes = this.evalSyncAwk(rawLines, opArgs);
|
|
28256
30756
|
if (awkRes !== undefined)
|
|
28257
|
-
fileRes = awkRes
|
|
30757
|
+
fileRes = renderLines(awkRes);
|
|
28258
30758
|
}
|
|
28259
30759
|
else if (w0Plain === "grep") {
|
|
28260
30760
|
const grepRes = this.evalSyncGrep(rawLines, opArgs, Boolean(rawState.errexit));
|
|
28261
30761
|
if (grepRes !== undefined) {
|
|
28262
30762
|
exitStatus = grepRes.status;
|
|
28263
|
-
fileRes = grepRes.lines
|
|
30763
|
+
fileRes = renderLines(grepRes.lines);
|
|
28264
30764
|
}
|
|
28265
30765
|
}
|
|
28266
30766
|
else if (w0Plain === "sed") {
|
|
28267
30767
|
const sedRes = this.evalSyncSed(rawLines, opArgs);
|
|
28268
30768
|
if (sedRes !== undefined)
|
|
28269
|
-
fileRes = sedRes.
|
|
30769
|
+
fileRes = renderLines(sedRes.lines);
|
|
28270
30770
|
}
|
|
28271
30771
|
else if (w0Plain === "cut") {
|
|
28272
30772
|
const cutRes = this.evalSyncCut(rawLines, opArgs, byteLocale(rawState.variables));
|
|
28273
30773
|
if (cutRes !== undefined)
|
|
28274
|
-
fileRes = cutRes
|
|
30774
|
+
fileRes = renderLines(cutRes);
|
|
28275
30775
|
}
|
|
28276
|
-
else if (w0Plain === "wc" && opArgs.length === 1 && (opArgs[0]
|
|
30776
|
+
else if (w0Plain === "wc" && opArgs.length === 1 && this.normalizeSyncWcFlag(opArgs[0]) !== undefined) {
|
|
30777
|
+
const wcMode = this.normalizeSyncWcFlag(opArgs[0]);
|
|
28277
30778
|
let count = 0;
|
|
28278
|
-
if (
|
|
30779
|
+
if (wcMode === "-l") {
|
|
28279
30780
|
for (let k = 0; k < view.byteLength; k++)
|
|
28280
30781
|
if (view[k] === 10)
|
|
28281
30782
|
count++;
|
|
28282
30783
|
}
|
|
28283
|
-
else if (
|
|
30784
|
+
else if (wcMode === "-c") {
|
|
28284
30785
|
count = view.byteLength;
|
|
28285
30786
|
}
|
|
30787
|
+
else if (wcMode === "-m") {
|
|
30788
|
+
count = byteLocale(rawState.variables) ? view.byteLength : Array.from(fileStr).length;
|
|
30789
|
+
}
|
|
30790
|
+
else if (wcMode === "-L") {
|
|
30791
|
+
count = this.wcMaxLineWidth(fileStr, byteLocale(rawState.variables));
|
|
30792
|
+
}
|
|
28286
30793
|
else {
|
|
28287
|
-
|
|
28288
|
-
|
|
28289
|
-
|
|
28290
|
-
|
|
28291
|
-
|
|
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]);
|
|
28306
|
-
}
|
|
28307
|
-
uIdx = uEnd;
|
|
30794
|
+
// Unicode word separators depend on locale and POSIXLY_CORRECT.
|
|
30795
|
+
// Use the maintained command for those inputs rather than JS whitespace.
|
|
30796
|
+
if (!byteLocale(rawState.variables) && view.some(byte => byte > 127))
|
|
30797
|
+
return undefined;
|
|
30798
|
+
count = fileStr.split(/[ \t\n\r\f\v]+/).filter(Boolean).length;
|
|
28308
30799
|
}
|
|
28309
|
-
fileRes =
|
|
30800
|
+
fileRes = ((hasSingleStdinRedir || hasSingleHereStringRedir) ? String(count) : `${count} ${fileArg}`) + "\n";
|
|
30801
|
+
}
|
|
30802
|
+
else if (w0Plain === "sort" && !byteLocale(rawState.variables)) {
|
|
30803
|
+
const sortRes = this.evalSyncSort(rawLines, opArgs, false);
|
|
30804
|
+
if (sortRes !== undefined)
|
|
30805
|
+
fileRes = renderLines(sortRes);
|
|
30806
|
+
}
|
|
30807
|
+
else if (w0Plain === "uniq") {
|
|
30808
|
+
const uniqRes = this.evalSyncUniq(rawLines, opArgs);
|
|
30809
|
+
if (uniqRes !== undefined)
|
|
30810
|
+
fileRes = renderLines(uniqRes);
|
|
28310
30811
|
}
|
|
28311
30812
|
else if (w0Plain === "tr" && (hasSingleStdinRedir || hasSingleHereStringRedir)) {
|
|
28312
30813
|
fileRes = this.evalSyncTr(fileStr, opArgs);
|
|
28313
30814
|
}
|
|
28314
30815
|
else if (hasSingleHereStringRedir && w0Plain === "base64" && (opArgs.length === 0 || (opArgs.length === 1 && (opArgs[0] === "-d" || opArgs[0] === "--decode")))) {
|
|
28315
30816
|
if (opArgs.length === 0)
|
|
28316
|
-
fileRes = this.syncBase64Encode(view);
|
|
28317
|
-
else
|
|
28318
|
-
|
|
30817
|
+
fileRes = this.syncBase64Encode(view) + "\n";
|
|
30818
|
+
else {
|
|
30819
|
+
const decoded = this.syncBase64DecodeBytes(fileStr);
|
|
30820
|
+
// Text-only substitutions cannot retain binary byte provenance.
|
|
30821
|
+
if (decoded.some(byte => byte === 0 || byte >= 128))
|
|
30822
|
+
return undefined;
|
|
30823
|
+
fileRes = sharedSyncPipeDecoder.decode(decoded);
|
|
30824
|
+
}
|
|
28319
30825
|
}
|
|
28320
30826
|
else if (hasSingleHereStringRedir && w0Plain === "rev" && opArgs.length === 0) {
|
|
28321
|
-
fileRes = rawLines.map(l => Array.from(l).reverse().join(""))
|
|
30827
|
+
fileRes = renderLines(rawLines.map(l => Array.from(l).reverse().join("")));
|
|
28322
30828
|
}
|
|
28323
30829
|
else if (hasSingleHereStringRedir && w0Plain === "tac" && opArgs.length === 0) {
|
|
28324
|
-
fileRes = [...rawLines].reverse()
|
|
30830
|
+
fileRes = renderLines([...rawLines].reverse());
|
|
28325
30831
|
}
|
|
28326
|
-
else if (hasSingleHereStringRedir && w0Plain === "nl"
|
|
28327
|
-
|
|
28328
|
-
|
|
30832
|
+
else if (hasSingleHereStringRedir && w0Plain === "nl") {
|
|
30833
|
+
const nlRes = this.evalSyncNl(rawLines, opArgs);
|
|
30834
|
+
if (nlRes !== undefined)
|
|
30835
|
+
fileRes = renderLines(nlRes);
|
|
30836
|
+
}
|
|
30837
|
+
else if (hasSingleHereStringRedir && w0Plain === "paste") {
|
|
30838
|
+
const pasteRes = this.evalSyncPaste(rawLines, opArgs);
|
|
30839
|
+
if (pasteRes !== undefined)
|
|
30840
|
+
fileRes = renderLines(pasteRes);
|
|
30841
|
+
}
|
|
30842
|
+
else if (hasSingleHereStringRedir && w0Plain === "numfmt") {
|
|
30843
|
+
const nmRes = this.evalSyncNumfmt(rawLines, opArgs);
|
|
30844
|
+
if (nmRes !== undefined)
|
|
30845
|
+
fileRes = renderLines(nmRes);
|
|
28329
30846
|
}
|
|
28330
30847
|
if (fileRes !== undefined) {
|
|
30848
|
+
// Charge emitted bytes before substitution removes trailing newlines.
|
|
30849
|
+
const outBytes = shellValueByteLength(fileRes);
|
|
28331
30850
|
let end = fileRes.length;
|
|
28332
30851
|
while (end > 0 && fileRes.charCodeAt(end - 1) === 10)
|
|
28333
30852
|
end--;
|
|
28334
30853
|
if (end < fileRes.length)
|
|
28335
30854
|
fileRes = fileRes.slice(0, end);
|
|
28336
|
-
const outBytes = (fileRes.length * 3 > 127 ? shellValueByteLength(fileRes) : fileRes.length) + 1;
|
|
28337
30855
|
const nextTotalBytes = this.budget.bytes + outBytes;
|
|
28338
30856
|
if (nextTotalBytes > this.budget.maxOutputBytesSmi && outBytes > this.budget.limits.maxOutputBytes - this.budget.bytes)
|
|
28339
30857
|
this.budget.fail("maxOutputBytes");
|
|
@@ -28435,46 +30953,17 @@ export class Runtime {
|
|
|
28435
30953
|
if (!this.isPureArgWord(cmd.words[i], rawState))
|
|
28436
30954
|
return undefined;
|
|
28437
30955
|
}
|
|
28438
|
-
if (w0Plain === "dirname"
|
|
28439
|
-
const
|
|
28440
|
-
|
|
28441
|
-
|
|
28442
|
-
|
|
28443
|
-
let pEnd = parent.length;
|
|
28444
|
-
while (pEnd > 1 && parent[pEnd - 1] === "/")
|
|
28445
|
-
pEnd--;
|
|
28446
|
-
let res = parent.slice(0, pEnd);
|
|
28447
|
-
const byteLength = shellValueByteLength(res) + 1;
|
|
28448
|
-
while (res.endsWith("\n"))
|
|
28449
|
-
res = res.slice(0, -1);
|
|
28450
|
-
const nextBytes = this.budget.bytes + byteLength;
|
|
28451
|
-
if (nextBytes > this.budget.maxOutputBytesSmi && byteLength > this.budget.limits.maxOutputBytes - this.budget.bytes)
|
|
28452
|
-
this.budget.fail("maxOutputBytes");
|
|
28453
|
-
this.budget.bytes = nextBytes;
|
|
28454
|
-
this.budget.tick();
|
|
28455
|
-
if (fnPositional !== undefined)
|
|
28456
|
-
this.budget.tick();
|
|
28457
|
-
rawState.substitutionStatus = 0;
|
|
28458
|
-
rawState.status = 0;
|
|
28459
|
-
return res;
|
|
28460
|
-
}
|
|
28461
|
-
if (w0Plain === "basename" && (cmd.words.length === 2 || cmd.words.length === 3 || (cmd.words.length === 4 && cmd.words[1]?.plain === "-s"))) {
|
|
28462
|
-
const isFlagS = cmd.words.length === 4 && cmd.words[1]?.plain === "-s";
|
|
28463
|
-
const pathWord = isFlagS ? cmd.words[3] : cmd.words[1];
|
|
28464
|
-
const suffixWord = isFlagS ? cmd.words[2] : (cmd.words.length === 3 ? cmd.words[2] : undefined);
|
|
28465
|
-
const wVal1 = this.fastValueWord(pathWord, state, io, true, false, false, true, undefined, part.line);
|
|
28466
|
-
if (typeof wVal1 !== "string" || wVal1.startsWith("-") || wVal1.includes("\0"))
|
|
28467
|
-
return undefined;
|
|
28468
|
-
let wVal2;
|
|
28469
|
-
if (suffixWord !== undefined) {
|
|
28470
|
-
const v2 = this.fastValueWord(suffixWord, state, io, true, false, false, true, undefined, part.line);
|
|
28471
|
-
if (typeof v2 !== "string" || v2.includes("\0"))
|
|
30956
|
+
if (w0Plain === "dirname" || w0Plain === "basename") {
|
|
30957
|
+
const dbArgs = [];
|
|
30958
|
+
for (let i = 1; i < cmd.words.length; i++) {
|
|
30959
|
+
const v = this.fastValueWord(cmd.words[i], state, io, true, false, false, true, undefined, part.line);
|
|
30960
|
+
if (typeof v !== "string")
|
|
28472
30961
|
return undefined;
|
|
28473
|
-
|
|
30962
|
+
dbArgs.push(v);
|
|
28474
30963
|
}
|
|
28475
|
-
let res =
|
|
28476
|
-
if (
|
|
28477
|
-
|
|
30964
|
+
let res = w0Plain === "dirname" ? this.evalSyncDirname(dbArgs) : this.evalSyncBasename(dbArgs);
|
|
30965
|
+
if (res === undefined)
|
|
30966
|
+
return undefined;
|
|
28478
30967
|
const byteLength = shellValueByteLength(res) + 1;
|
|
28479
30968
|
while (res.endsWith("\n"))
|
|
28480
30969
|
res = res.slice(0, -1);
|