@poe-platform/safe-bash 0.1.745 → 0.1.746
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-EAUCLWEZ.js → chunk-3ZNXN3XO.js} +423 -245
- package/dist/safe-bash/chunks/{chunk-2F7Q532M.js → chunk-4GK4FAT6.js} +3 -3
- 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-T2WAWJXF.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 +2697 -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 +3014 -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 +410 -237
- 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);
|
|
27107
28006
|
}
|
|
28007
|
+
void innerArgs;
|
|
28008
|
+
return outArrays.map(val => JSON.stringify(val ?? null, null, compactOut ? undefined : 2));
|
|
27108
28009
|
}
|
|
27109
|
-
|
|
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;
|
|
28089
|
+
}
|
|
28090
|
+
}
|
|
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)
|
|
27179
28197
|
return undefined;
|
|
27180
|
-
|
|
27181
|
-
|
|
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; }))
|
|
27182
28201
|
return undefined;
|
|
28202
|
+
const basePicker = this.parseSyncCutSpec(norm[0].slice(2));
|
|
28203
|
+
if (!basePicker)
|
|
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,512 @@ 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)
|
|
27281
|
-
return undefined;
|
|
27282
|
-
const delim = expr[1];
|
|
27283
|
-
if (!"/#|:@,;%!".includes(delim))
|
|
27284
|
-
return undefined;
|
|
27285
|
-
const parts = expr.slice(2).split(delim);
|
|
27286
|
-
if (parts.length !== 3)
|
|
28276
|
+
if (rawExprs.length === 0)
|
|
27287
28277
|
return undefined;
|
|
27288
|
-
const
|
|
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
|
+
if (isCount && (isLineNumber || isOnlyMatching || beforeCtx > 0 || afterCtx > 0))
|
|
28603
|
+
return undefined;
|
|
28604
|
+
if (isOnlyMatching && (beforeCtx > 0 || afterCtx > 0))
|
|
28605
|
+
return undefined;
|
|
28606
|
+
if (isOnlyMatching) {
|
|
28607
|
+
if (rawPatterns.length !== 1 || isInvert || isLineRegexp || isWordRegexp || isFixed)
|
|
28608
|
+
return undefined;
|
|
28609
|
+
const pat = rawPatterns[0];
|
|
28610
|
+
const reFlags = isCaseInsensitive ? "gi" : "g";
|
|
28611
|
+
let re;
|
|
28612
|
+
if (isExtended && /^[a-zA-Z0-9_ :;,=.+*?|()^\-[\]]+$/.test(pat) && !/\([^)]*[+*][^)]*\)[+*?]/.test(pat)) {
|
|
28613
|
+
try {
|
|
28614
|
+
re = new RegExp(pat, reFlags);
|
|
28615
|
+
}
|
|
28616
|
+
catch {
|
|
28617
|
+
re = undefined;
|
|
28618
|
+
}
|
|
28619
|
+
}
|
|
28620
|
+
else {
|
|
28621
|
+
const branches = isExtended ? pat.split("|") : [pat];
|
|
28622
|
+
if (branches.every(b => b.length > 0 && /^[a-zA-Z0-9_ :;,/-]+$/.test(b))) {
|
|
28623
|
+
branches.sort((a, b) => b.length - a.length);
|
|
28624
|
+
re = new RegExp(branches.join("|"), reFlags);
|
|
28625
|
+
}
|
|
28626
|
+
}
|
|
28627
|
+
if (!re)
|
|
28628
|
+
return undefined;
|
|
28629
|
+
const out = [];
|
|
28630
|
+
for (let li = 0; li < rawLines.length; li++) {
|
|
28631
|
+
const matches = rawLines[li].match(re);
|
|
28632
|
+
if (matches) {
|
|
28633
|
+
for (let mi = 0; mi < matches.length; mi++) {
|
|
28634
|
+
out.push(isLineNumber ? `${li + 1}:${matches[mi]}` : matches[mi]);
|
|
28635
|
+
}
|
|
28636
|
+
}
|
|
28637
|
+
}
|
|
28638
|
+
return { lines: out, status: out.length > 0 ? 0 : 1 };
|
|
28639
|
+
}
|
|
28640
|
+
if (isExtended && isFixed)
|
|
28641
|
+
return undefined;
|
|
28642
|
+
const branches = [];
|
|
28643
|
+
for (const rp of rawPatterns) {
|
|
28644
|
+
for (const b of (isFixed ? rp.split("\n") : (isExtended ? rp.split("|") : [rp]))) {
|
|
28645
|
+
branches.push(b);
|
|
28646
|
+
}
|
|
28647
|
+
}
|
|
27324
28648
|
const compiledBranches = [];
|
|
27325
28649
|
for (const br of branches) {
|
|
27326
28650
|
if (br.length === 0)
|
|
27327
28651
|
return undefined;
|
|
27328
|
-
|
|
27329
|
-
|
|
27330
|
-
|
|
27331
|
-
|
|
27332
|
-
|
|
27333
|
-
|
|
27334
|
-
|
|
28652
|
+
if (isFixed) {
|
|
28653
|
+
if (br.includes("\0"))
|
|
28654
|
+
return undefined;
|
|
28655
|
+
compiledBranches.push({ anchorStart: isLineRegexp, anchorEnd: isLineRegexp, needle: isCaseInsensitive ? foldCase(br) : br, re: undefined });
|
|
28656
|
+
}
|
|
28657
|
+
else {
|
|
28658
|
+
const anchorStart = isLineRegexp || br.startsWith("^");
|
|
28659
|
+
const c1 = br.startsWith("^") ? br.slice(1) : br;
|
|
28660
|
+
const anchorEnd = isLineRegexp || c1.endsWith("$");
|
|
28661
|
+
const core = c1.endsWith("$") ? c1.slice(0, -1) : c1;
|
|
28662
|
+
if (core.length > 0 && /^[a-zA-Z0-9_ :;,/-]+$/.test(core)) {
|
|
28663
|
+
compiledBranches.push({ anchorStart, anchorEnd, needle: isCaseInsensitive ? foldCase(core) : core, re: undefined });
|
|
28664
|
+
}
|
|
28665
|
+
else if (isExtended && !isWordRegexp && core.length > 0 && /^[a-zA-Z0-9_ :;,=.+*?^\-[\]]+$/.test(core) && !/\([^)]*[+*][^)]*\)[+*?]/.test(core)) {
|
|
28666
|
+
try {
|
|
28667
|
+
const fullSrc = (anchorStart ? "^" : "") + core + (anchorEnd ? "$" : "");
|
|
28668
|
+
compiledBranches.push({ anchorStart, anchorEnd, needle: "", re: new RegExp(fullSrc, isCaseInsensitive ? "i" : "") });
|
|
28669
|
+
}
|
|
28670
|
+
catch {
|
|
28671
|
+
return undefined;
|
|
28672
|
+
}
|
|
28673
|
+
}
|
|
28674
|
+
else {
|
|
28675
|
+
return undefined;
|
|
28676
|
+
}
|
|
28677
|
+
}
|
|
27335
28678
|
}
|
|
28679
|
+
const isWordChar = (ch) => ch !== undefined && /^[a-zA-Z0-9_]$/.test(ch);
|
|
28680
|
+
const hasWordMatch = (hay, needle, aStart, aEnd) => {
|
|
28681
|
+
if (aStart && aEnd)
|
|
28682
|
+
return hay === needle;
|
|
28683
|
+
if (aStart)
|
|
28684
|
+
return hay.startsWith(needle) && !isWordChar(hay[needle.length]);
|
|
28685
|
+
if (aEnd)
|
|
28686
|
+
return hay.endsWith(needle) && !isWordChar(hay[hay.length - needle.length - 1]);
|
|
28687
|
+
let from = 0;
|
|
28688
|
+
while (from <= hay.length - needle.length) {
|
|
28689
|
+
const idx = hay.indexOf(needle, from);
|
|
28690
|
+
if (idx === -1)
|
|
28691
|
+
return false;
|
|
28692
|
+
if (!isWordChar(hay[idx - 1]) && !isWordChar(hay[idx + needle.length]))
|
|
28693
|
+
return true;
|
|
28694
|
+
from = idx + 1;
|
|
28695
|
+
}
|
|
28696
|
+
return false;
|
|
28697
|
+
};
|
|
27336
28698
|
const matched = [];
|
|
28699
|
+
const matchedIndices = [];
|
|
27337
28700
|
for (let li = 0; li < rawLines.length; li++) {
|
|
27338
28701
|
const l = rawLines[li];
|
|
27339
|
-
const hay = isCaseInsensitive ? l
|
|
28702
|
+
const hay = isCaseInsensitive ? foldCase(l) : l;
|
|
27340
28703
|
let hit = false;
|
|
27341
28704
|
for (let bi = 0; bi < compiledBranches.length; bi++) {
|
|
27342
28705
|
const b = compiledBranches[bi];
|
|
27343
|
-
const ok = b.
|
|
27344
|
-
?
|
|
27345
|
-
:
|
|
27346
|
-
? hay.
|
|
27347
|
-
: b.anchorEnd
|
|
27348
|
-
? hay
|
|
27349
|
-
:
|
|
28706
|
+
const ok = b.re !== undefined
|
|
28707
|
+
? b.re.test(l)
|
|
28708
|
+
: isWordRegexp
|
|
28709
|
+
? hasWordMatch(hay, b.needle, b.anchorStart, b.anchorEnd)
|
|
28710
|
+
: b.anchorStart && b.anchorEnd
|
|
28711
|
+
? hay === b.needle
|
|
28712
|
+
: b.anchorStart
|
|
28713
|
+
? hay.startsWith(b.needle)
|
|
28714
|
+
: b.anchorEnd
|
|
28715
|
+
? hay.endsWith(b.needle)
|
|
28716
|
+
: hay.includes(b.needle);
|
|
27350
28717
|
if (ok) {
|
|
27351
28718
|
hit = true;
|
|
27352
28719
|
break;
|
|
27353
28720
|
}
|
|
27354
28721
|
}
|
|
27355
|
-
if (isInvert ? !hit : hit)
|
|
27356
|
-
|
|
28722
|
+
if (isInvert ? !hit : hit) {
|
|
28723
|
+
matchedIndices.push(li);
|
|
28724
|
+
matched.push(isLineNumber ? `${li + 1}:${l}` : l);
|
|
28725
|
+
if (matched.length >= maxCount)
|
|
28726
|
+
break;
|
|
28727
|
+
}
|
|
28728
|
+
}
|
|
28729
|
+
if ((beforeCtx > 0 || afterCtx > 0) && matchedIndices.length > 0) {
|
|
28730
|
+
const matchedSet = new Set(matchedIndices);
|
|
28731
|
+
const outCtx = [];
|
|
28732
|
+
let prevEnd = -1;
|
|
28733
|
+
for (const mIdx of matchedIndices) {
|
|
28734
|
+
const start = Math.max(0, mIdx - beforeCtx);
|
|
28735
|
+
const end = Math.min(rawLines.length - 1, mIdx + afterCtx);
|
|
28736
|
+
if (prevEnd !== -1 && start > prevEnd + 1) {
|
|
28737
|
+
outCtx.push("--");
|
|
28738
|
+
}
|
|
28739
|
+
const from = prevEnd !== -1 ? Math.max(start, prevEnd + 1) : start;
|
|
28740
|
+
for (let k = from; k <= end; k++) {
|
|
28741
|
+
const lineText = rawLines[k];
|
|
28742
|
+
if (isLineNumber) {
|
|
28743
|
+
outCtx.push(`${k + 1}${matchedSet.has(k) ? ":" : "-"}${lineText}`);
|
|
28744
|
+
}
|
|
28745
|
+
else {
|
|
28746
|
+
outCtx.push(lineText);
|
|
28747
|
+
}
|
|
28748
|
+
}
|
|
28749
|
+
prevEnd = Math.max(prevEnd, end);
|
|
28750
|
+
}
|
|
28751
|
+
return { lines: outCtx, status: 0 };
|
|
27357
28752
|
}
|
|
27358
28753
|
return {
|
|
27359
28754
|
lines: isCount ? [String(matched.length)] : matched,
|
|
@@ -27361,50 +28756,413 @@ export class Runtime {
|
|
|
27361
28756
|
};
|
|
27362
28757
|
}
|
|
27363
28758
|
evalSyncAwk(rawLines, opArgs) {
|
|
27364
|
-
if (opArgs.length < 1 || opArgs.length >
|
|
28759
|
+
if (opArgs.length < 1 || opArgs.length > 8)
|
|
27365
28760
|
return undefined;
|
|
27366
|
-
const norm = opArgs.length === 3 && opArgs[0] === "-F" ? ["-F" + opArgs[1], opArgs[2]] : opArgs;
|
|
27367
28761
|
let awkSep;
|
|
27368
28762
|
let awkProg;
|
|
27369
|
-
|
|
27370
|
-
|
|
27371
|
-
|
|
27372
|
-
|
|
27373
|
-
|
|
28763
|
+
let ofs = " ";
|
|
28764
|
+
const userVars = new Map();
|
|
28765
|
+
for (let i = 0; i < opArgs.length; i++) {
|
|
28766
|
+
const a = opArgs[i];
|
|
28767
|
+
if (a === "-F") {
|
|
28768
|
+
if (i + 1 >= opArgs.length || opArgs[i + 1].length !== 1 || opArgs[i + 1] === "\\")
|
|
28769
|
+
return undefined;
|
|
28770
|
+
awkSep = opArgs[++i];
|
|
28771
|
+
}
|
|
28772
|
+
else if (a.startsWith("-F") && a.length === 3 && a[2] !== "\\") {
|
|
28773
|
+
awkSep = a.slice(2);
|
|
28774
|
+
}
|
|
28775
|
+
else if (a === "-v") {
|
|
28776
|
+
if (i + 1 >= opArgs.length)
|
|
28777
|
+
return undefined;
|
|
28778
|
+
const kv = opArgs[++i];
|
|
28779
|
+
const eq = kv.indexOf("=");
|
|
28780
|
+
if (eq <= 0 || !/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(kv.slice(0, eq)))
|
|
28781
|
+
return undefined;
|
|
28782
|
+
const k = kv.slice(0, eq);
|
|
28783
|
+
const v = kv.slice(eq + 1);
|
|
28784
|
+
if (v.includes("\\"))
|
|
28785
|
+
return undefined;
|
|
28786
|
+
if (k === "OFS")
|
|
28787
|
+
ofs = v;
|
|
28788
|
+
else if (k === "FS") {
|
|
28789
|
+
if (v.length !== 1)
|
|
28790
|
+
return undefined;
|
|
28791
|
+
awkSep = v;
|
|
28792
|
+
}
|
|
28793
|
+
else
|
|
28794
|
+
userVars.set(k, v);
|
|
28795
|
+
}
|
|
28796
|
+
else if (a.startsWith("-v") && a.length > 2) {
|
|
28797
|
+
const kv = a.slice(2);
|
|
28798
|
+
const eq = kv.indexOf("=");
|
|
28799
|
+
if (eq <= 0 || !/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(kv.slice(0, eq)))
|
|
28800
|
+
return undefined;
|
|
28801
|
+
const k = kv.slice(0, eq);
|
|
28802
|
+
const v = kv.slice(eq + 1);
|
|
28803
|
+
if (v.includes("\\"))
|
|
28804
|
+
return undefined;
|
|
28805
|
+
if (k === "OFS")
|
|
28806
|
+
ofs = v;
|
|
28807
|
+
else if (k === "FS") {
|
|
28808
|
+
if (v.length !== 1)
|
|
28809
|
+
return undefined;
|
|
28810
|
+
awkSep = v;
|
|
28811
|
+
}
|
|
28812
|
+
else
|
|
28813
|
+
userVars.set(k, v);
|
|
28814
|
+
}
|
|
28815
|
+
else if (!a.startsWith("-") && i === opArgs.length - 1) {
|
|
28816
|
+
awkProg = a;
|
|
28817
|
+
}
|
|
28818
|
+
else {
|
|
28819
|
+
return undefined;
|
|
28820
|
+
}
|
|
27374
28821
|
}
|
|
27375
28822
|
if (!awkProg)
|
|
27376
28823
|
return undefined;
|
|
27377
|
-
|
|
28824
|
+
let progRest = awkProg.trim();
|
|
28825
|
+
const beginFsM = /^BEGIN\s*\{([^}]*)\}\s*/.exec(progRest);
|
|
28826
|
+
let initVarName;
|
|
28827
|
+
let initVarVal = 0;
|
|
28828
|
+
if (beginFsM) {
|
|
28829
|
+
const bStmts = beginFsM[1].split(";").map(s => s.trim()).filter(Boolean);
|
|
28830
|
+
for (const bs of bStmts) {
|
|
28831
|
+
const ofsM = /^OFS\s*=\s*"([^"\\]*)"$/.exec(bs);
|
|
28832
|
+
if (ofsM) {
|
|
28833
|
+
ofs = ofsM[1];
|
|
28834
|
+
continue;
|
|
28835
|
+
}
|
|
28836
|
+
const fsM = /^FS\s*=\s*"([^"\\])"$/.exec(bs);
|
|
28837
|
+
if (fsM) {
|
|
28838
|
+
awkSep = fsM[1];
|
|
28839
|
+
continue;
|
|
28840
|
+
}
|
|
28841
|
+
const numInitM = /^([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(-?[0-9]+(?:\.[0-9]+)?)$/.exec(bs);
|
|
28842
|
+
if (numInitM) {
|
|
28843
|
+
initVarName = numInitM[1];
|
|
28844
|
+
initVarVal = Number(numInitM[2]);
|
|
28845
|
+
continue;
|
|
28846
|
+
}
|
|
28847
|
+
return undefined;
|
|
28848
|
+
}
|
|
28849
|
+
progRest = progRest.slice(beginFsM[0].length).trim();
|
|
28850
|
+
}
|
|
28851
|
+
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);
|
|
28852
|
+
if (sumEndM) {
|
|
28853
|
+
const varName = sumEndM[1];
|
|
28854
|
+
if (["NR", "NF", "FNR", "OFS", "FS", "ORS", "RS", "OFMT", "CONVFMT", "ARGC", "ARGIND", "FILENAME", "RSTART", "RLENGTH", "SUBSEP", "IGNORECASE", "FIELDWIDTHS", "FPAT", "BINMODE", "TEXTDOMAIN"].includes(varName))
|
|
28855
|
+
return undefined;
|
|
28856
|
+
if (initVarName !== undefined && initVarName !== varName)
|
|
28857
|
+
return undefined;
|
|
28858
|
+
const op = sumEndM[2];
|
|
28859
|
+
const fTok = sumEndM[3];
|
|
28860
|
+
const constVal = sumEndM[4] !== undefined ? Number(sumEndM[4]) : undefined;
|
|
28861
|
+
const initial = userVars.get(varName);
|
|
28862
|
+
if (initial !== undefined && !Number.isFinite(Number(initial)))
|
|
28863
|
+
return undefined;
|
|
28864
|
+
let acc = initVarName === varName ? initVarVal : Number(initial ?? 0);
|
|
28865
|
+
let touched = initVarName === varName || initial !== undefined;
|
|
28866
|
+
for (let li = 0; li < rawLines.length; li++) {
|
|
28867
|
+
const l = rawLines[li];
|
|
28868
|
+
const fields = awkSep === undefined || awkSep === " "
|
|
28869
|
+
? l.split(/[ \t]+/).filter(Boolean)
|
|
28870
|
+
: (l.length === 0 ? [] : l.split(awkSep));
|
|
28871
|
+
let delta = 0;
|
|
28872
|
+
if (constVal !== undefined) {
|
|
28873
|
+
delta = constVal;
|
|
28874
|
+
}
|
|
28875
|
+
else {
|
|
28876
|
+
const idx = fTok === "NF" ? fields.length : Number(fTok);
|
|
28877
|
+
const rawField = idx === 0 ? l : (idx >= 1 && idx <= fields.length ? fields[idx - 1] : "");
|
|
28878
|
+
const n = /^[ \t]*([+-]?(?:\d+(?:\.\d*)?|\.\d+))/.exec(rawField);
|
|
28879
|
+
delta = n ? Number(n[1]) : 0;
|
|
28880
|
+
}
|
|
28881
|
+
acc = op === "+=" ? acc + delta : acc - delta;
|
|
28882
|
+
touched = true;
|
|
28883
|
+
}
|
|
28884
|
+
return [touched ? awkValueText({ kind: "number", number: acc }) : ""];
|
|
28885
|
+
}
|
|
28886
|
+
if (initVarName !== undefined)
|
|
28887
|
+
return undefined;
|
|
28888
|
+
let rowPred;
|
|
28889
|
+
const patCondM = /^\/(\^?[a-zA-Z0-9_ :;,=-]+\$?)\/\s*/.exec(progRest);
|
|
28890
|
+
if (patCondM) {
|
|
28891
|
+
const pSpec = patCondM[1];
|
|
28892
|
+
const aS = pSpec.startsWith("^");
|
|
28893
|
+
const c1 = aS ? pSpec.slice(1) : pSpec;
|
|
28894
|
+
const aE = c1.endsWith("$");
|
|
28895
|
+
const core = aE ? c1.slice(0, -1) : c1;
|
|
28896
|
+
rowPred = (l) => aS && aE ? l === core : aS ? l.startsWith(core) : aE ? l.endsWith(core) : l.includes(core);
|
|
28897
|
+
progRest = progRest.slice(patCondM[0].length).trim();
|
|
28898
|
+
}
|
|
28899
|
+
else {
|
|
28900
|
+
const cmpCondM = /^(?:(NR|NF)|\$([0-9]+|NF))\s*(==|!=|>=|<=|>|<)\s*(?:"([^"\\]*)"|(-?[0-9]+(?:\.[0-9]+)?)|([a-zA-Z_][a-zA-Z0-9_]*))\s*/.exec(progRest);
|
|
28901
|
+
if (cmpCondM) {
|
|
28902
|
+
const nrNf = cmpCondM[1];
|
|
28903
|
+
const fTok = cmpCondM[2];
|
|
28904
|
+
const op = cmpCondM[3];
|
|
28905
|
+
const varRhs = cmpCondM[6] !== undefined ? userVars.get(cmpCondM[6]) : undefined;
|
|
28906
|
+
if (cmpCondM[6] !== undefined && varRhs === undefined)
|
|
28907
|
+
return undefined;
|
|
28908
|
+
const varAsNum = varRhs !== undefined && /^-?(?:\d+(?:\.\d*)?|\.\d+)$/.test(varRhs) ? Number(varRhs) : undefined;
|
|
28909
|
+
const strRhs = cmpCondM[4] ?? (varAsNum === undefined ? varRhs : undefined);
|
|
28910
|
+
const numRhs = cmpCondM[5] !== undefined ? Number(cmpCondM[5]) : varAsNum;
|
|
28911
|
+
if (strRhs !== undefined && op !== "==" && op !== "!=")
|
|
28912
|
+
return undefined;
|
|
28913
|
+
rowPred = (l, fields, nr) => {
|
|
28914
|
+
let rawVal;
|
|
28915
|
+
if (nrNf !== undefined)
|
|
28916
|
+
rawVal = nrNf === "NR" ? nr : fields.length;
|
|
28917
|
+
else {
|
|
28918
|
+
const idx = fTok === "NF" ? fields.length : Number(fTok);
|
|
28919
|
+
rawVal = idx === 0 ? l : (idx >= 1 && idx <= fields.length ? fields[idx - 1] : "");
|
|
28920
|
+
}
|
|
28921
|
+
const left = typeof rawVal === "number" ? awkNumeric(rawVal) : awkInputValue(rawVal);
|
|
28922
|
+
const right = strRhs !== undefined ? awkString(strRhs) : awkNumeric(numRhs);
|
|
28923
|
+
const comparison = awkCompare(left, right, "%.6g");
|
|
28924
|
+
return op === "==" ? comparison === 0 : op === "!=" ? comparison !== 0 : op === ">=" ? comparison >= 0 : op === "<=" ? comparison <= 0 : op === ">" ? comparison > 0 : comparison < 0;
|
|
28925
|
+
};
|
|
28926
|
+
progRest = progRest.slice(cmpCondM[0].length).trim();
|
|
28927
|
+
}
|
|
28928
|
+
}
|
|
28929
|
+
const awkM = syncAwkPrintRe.exec(progRest);
|
|
27378
28930
|
if (!awkM)
|
|
27379
28931
|
return undefined;
|
|
27380
|
-
const
|
|
28932
|
+
const subFn = awkM[1];
|
|
28933
|
+
const subPat = awkM[2];
|
|
28934
|
+
const subRep = awkM[3] ?? "";
|
|
28935
|
+
const subTarget = awkM[4] ?? "0";
|
|
28936
|
+
// printf must consume typed values before OFMT string conversion and use
|
|
28937
|
+
// the complete formatter, including integer precision and exponent parsing.
|
|
28938
|
+
if (awkM[6] !== undefined)
|
|
28939
|
+
return undefined;
|
|
28940
|
+
const exprBody = awkM[5]?.trim();
|
|
28941
|
+
let subRe;
|
|
28942
|
+
if (subFn && subPat !== undefined) {
|
|
28943
|
+
const aS = subPat.startsWith("^");
|
|
28944
|
+
const c1 = aS ? subPat.slice(1) : subPat;
|
|
28945
|
+
const aE = c1.endsWith("$");
|
|
28946
|
+
const core = aE ? c1.slice(0, -1) : c1;
|
|
28947
|
+
const esc = core.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
28948
|
+
subRe = new RegExp((aS ? "^" : "") + esc + (aE ? "$" : ""), subFn === "gsub" ? "g" : "");
|
|
28949
|
+
}
|
|
27381
28950
|
const parts = [];
|
|
27382
28951
|
if (!exprBody) {
|
|
27383
28952
|
parts.push({ kind: "field", token: "0" });
|
|
27384
28953
|
}
|
|
27385
28954
|
else {
|
|
27386
|
-
|
|
28955
|
+
syncAwkTokenRe.lastIndex = 0;
|
|
28956
|
+
const tokenRe = syncAwkTokenRe;
|
|
27387
28957
|
let m;
|
|
27388
28958
|
while ((m = tokenRe.exec(exprBody)) !== null) {
|
|
27389
|
-
if (m[1] !== undefined)
|
|
27390
|
-
|
|
28959
|
+
if (m[1] !== undefined) {
|
|
28960
|
+
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());
|
|
28961
|
+
if (!tm)
|
|
28962
|
+
return undefined;
|
|
28963
|
+
parts.push({ kind: "ternary", lhs: tm[1], op: tm[2], rhs: tm[3], yes: tm[4], no: tm[5] });
|
|
28964
|
+
}
|
|
27391
28965
|
else if (m[2] !== undefined)
|
|
27392
|
-
parts.push({ kind: "
|
|
28966
|
+
parts.push({ kind: "int", token: m[2] });
|
|
27393
28967
|
else if (m[3] !== undefined)
|
|
27394
|
-
parts.push({ kind: "
|
|
28968
|
+
parts.push({ kind: "case", fn: m[3] === "toupper" ? "upper" : "lower", token: m[4] });
|
|
28969
|
+
else if (m[5] !== undefined)
|
|
28970
|
+
parts.push({ kind: "substr", token: m[5], start: Number(m[6]), len: m[7] !== undefined ? Number(m[7]) : undefined });
|
|
28971
|
+
else if (m[8] !== undefined)
|
|
28972
|
+
parts.push({ kind: "index", token: m[8], sub: m[9] });
|
|
28973
|
+
else if (m[10] !== undefined) {
|
|
28974
|
+
const aToks = m[10].trim().split(/\s*([+*\/%-])\s*/);
|
|
28975
|
+
for (let ti = 0; ti < aToks.length; ti += 2) {
|
|
28976
|
+
const at = aToks[ti];
|
|
28977
|
+
if (!at.startsWith("$") && at !== "NR" && at !== "NF" && !/^-?[0-9]+(?:\.[0-9]+)?$/.test(at) && !userVars.has(at))
|
|
28978
|
+
return undefined;
|
|
28979
|
+
}
|
|
28980
|
+
for (let ti = 1; ti < aToks.length; ti += 2) {
|
|
28981
|
+
if (aToks[ti] === "/" || aToks[ti] === "%") {
|
|
28982
|
+
const divisor = Number(aToks[ti + 1]);
|
|
28983
|
+
if (!Number.isFinite(divisor) || divisor === 0)
|
|
28984
|
+
return undefined;
|
|
28985
|
+
}
|
|
28986
|
+
}
|
|
28987
|
+
parts.push({ kind: "arith", tokens: aToks });
|
|
28988
|
+
}
|
|
28989
|
+
else if (m[11] !== undefined) {
|
|
28990
|
+
const offset = Number(m[11]);
|
|
28991
|
+
// Refuse potentially fatal fields before loop iterations mutate state.
|
|
28992
|
+
if (offset > 0)
|
|
28993
|
+
return undefined;
|
|
28994
|
+
parts.push({ kind: "nf_minus", offset });
|
|
28995
|
+
}
|
|
28996
|
+
else if (m[12] !== undefined)
|
|
28997
|
+
parts.push({ kind: "field", token: m[12] });
|
|
28998
|
+
else if (m[0] === "length" || m[0].startsWith("length("))
|
|
28999
|
+
parts.push({ kind: "length", token: m[13] ?? "0" });
|
|
29000
|
+
else if (m[14] !== undefined)
|
|
29001
|
+
parts.push({ kind: "var", name: m[14] });
|
|
29002
|
+
else if (m[15] !== undefined)
|
|
29003
|
+
parts.push({ kind: "lit", text: m[15] });
|
|
29004
|
+
else if (m[16] !== undefined) {
|
|
29005
|
+
const uv = userVars.get(m[16]);
|
|
29006
|
+
if (uv === undefined)
|
|
29007
|
+
return undefined;
|
|
29008
|
+
parts.push({ kind: "lit", text: uv });
|
|
29009
|
+
}
|
|
29010
|
+
else if (m[17] !== undefined)
|
|
29011
|
+
parts.push({ kind: "lit", text: ofs });
|
|
27395
29012
|
}
|
|
27396
29013
|
}
|
|
27397
|
-
|
|
27398
|
-
|
|
27399
|
-
|
|
27400
|
-
|
|
27401
|
-
?
|
|
27402
|
-
: l.
|
|
29014
|
+
const outLines = [];
|
|
29015
|
+
for (let li = 0; li < rawLines.length; li++) {
|
|
29016
|
+
let l = rawLines[li];
|
|
29017
|
+
let fields = awkSep === undefined || awkSep === " "
|
|
29018
|
+
? l.split(/[ \t]+/).filter(Boolean)
|
|
29019
|
+
: (l.length === 0 ? [] : l.split(awkSep));
|
|
29020
|
+
if (rowPred && !rowPred(l, fields, li + 1))
|
|
29021
|
+
continue;
|
|
29022
|
+
if (subRe) {
|
|
29023
|
+
if (subTarget === "0") {
|
|
29024
|
+
l = l.replace(subRe, matched => subRep.split("&").join(matched));
|
|
29025
|
+
fields = awkSep === undefined || awkSep === " "
|
|
29026
|
+
? l.split(/[ \t]+/).filter(Boolean)
|
|
29027
|
+
: (l.length === 0 ? [] : l.split(awkSep));
|
|
29028
|
+
}
|
|
29029
|
+
else {
|
|
29030
|
+
const tIdx = subTarget === "NF" ? fields.length : Number(subTarget);
|
|
29031
|
+
if (tIdx >= 1 && tIdx <= fields.length) {
|
|
29032
|
+
fields = [...fields];
|
|
29033
|
+
fields[tIdx - 1] = fields[tIdx - 1].replace(subRe, matched => subRep.split("&").join(matched));
|
|
29034
|
+
l = fields.join(ofs);
|
|
29035
|
+
}
|
|
29036
|
+
}
|
|
29037
|
+
}
|
|
29038
|
+
if (parts.length === 1 && parts[0].kind === "field" && parts[0].token === "0") {
|
|
29039
|
+
outLines.push(l);
|
|
29040
|
+
continue;
|
|
29041
|
+
}
|
|
27403
29042
|
let out = "";
|
|
27404
29043
|
for (let pi = 0; pi < parts.length; pi++) {
|
|
27405
29044
|
const p = parts[pi];
|
|
27406
29045
|
if (p.kind === "lit")
|
|
27407
29046
|
out += p.text;
|
|
29047
|
+
else if (p.kind === "var")
|
|
29048
|
+
out += String(p.name === "NR" ? li + 1 : fields.length);
|
|
29049
|
+
else if (p.kind === "nf_minus") {
|
|
29050
|
+
const idx = fields.length - p.offset;
|
|
29051
|
+
if (idx < 0)
|
|
29052
|
+
return undefined;
|
|
29053
|
+
out += idx === 0 ? l : (idx >= 1 && idx <= fields.length ? fields[idx - 1] : "");
|
|
29054
|
+
}
|
|
29055
|
+
else if (p.kind === "case") {
|
|
29056
|
+
const idx = p.token === "NF" ? fields.length : Number(p.token);
|
|
29057
|
+
const s = idx === 0 ? l : (idx >= 1 && idx <= fields.length ? fields[idx - 1] : "");
|
|
29058
|
+
out += p.fn === "upper" ? s.toUpperCase() : s.toLowerCase();
|
|
29059
|
+
}
|
|
29060
|
+
else if (p.kind === "substr") {
|
|
29061
|
+
const idx = p.token === "NF" ? fields.length : Number(p.token);
|
|
29062
|
+
const s = idx === 0 ? l : (idx >= 1 && idx <= fields.length ? fields[idx - 1] : "");
|
|
29063
|
+
const chars = Array.from(s);
|
|
29064
|
+
const s0 = Math.max(0, p.start - 1);
|
|
29065
|
+
out += (p.len !== undefined ? chars.slice(s0, s0 + Math.max(0, p.len)) : chars.slice(s0)).join("");
|
|
29066
|
+
}
|
|
29067
|
+
else if (p.kind === "index") {
|
|
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 pos = p.sub.length === 0 ? -1 : s.indexOf(p.sub);
|
|
29071
|
+
out += String(pos === -1 ? 0 : pos + 1);
|
|
29072
|
+
}
|
|
29073
|
+
else if (p.kind === "int") {
|
|
29074
|
+
const idx = p.token === "NF" ? fields.length : Number(p.token);
|
|
29075
|
+
const s = idx === 0 ? l : (idx >= 1 && idx <= fields.length ? fields[idx - 1] : "");
|
|
29076
|
+
const n = Number(/^[ \t]*([+-]?(?:\d+(?:\.\d*)?|\.\d+))/.exec(s)?.[1] ?? 0);
|
|
29077
|
+
out += String(Math.trunc(n));
|
|
29078
|
+
}
|
|
29079
|
+
else if (p.kind === "ternary") {
|
|
29080
|
+
const resolveAtom = (tok) => {
|
|
29081
|
+
if (tok.startsWith("\"") && tok.endsWith("\""))
|
|
29082
|
+
return tok.slice(1, -1);
|
|
29083
|
+
if (tok === "NR")
|
|
29084
|
+
return String(li + 1);
|
|
29085
|
+
if (tok === "NF")
|
|
29086
|
+
return String(fields.length);
|
|
29087
|
+
if (tok.startsWith("$")) {
|
|
29088
|
+
const fIdx = tok === "$NF" ? fields.length : Number(tok.slice(1));
|
|
29089
|
+
return fIdx === 0 ? l : (fIdx >= 1 && fIdx <= fields.length ? fields[fIdx - 1] : "");
|
|
29090
|
+
}
|
|
29091
|
+
return tok;
|
|
29092
|
+
};
|
|
29093
|
+
const lv = resolveAtom(p.lhs);
|
|
29094
|
+
const rv = resolveAtom(p.rhs);
|
|
29095
|
+
const isStrCmp = p.rhs.startsWith("\"");
|
|
29096
|
+
let cond = false;
|
|
29097
|
+
if (isStrCmp) {
|
|
29098
|
+
cond = p.op === "==" ? lv === rv : p.op === "!=" ? lv !== rv : p.op === ">" ? lv > rv : p.op === "<" ? lv < rv : p.op === ">=" ? lv >= rv : lv <= rv;
|
|
29099
|
+
}
|
|
29100
|
+
else {
|
|
29101
|
+
const ln = Number(lv) || 0;
|
|
29102
|
+
const rn = Number(rv) || 0;
|
|
29103
|
+
cond = p.op === "==" ? ln === rn : p.op === "!=" ? ln !== rn : p.op === ">" ? ln > rn : p.op === "<" ? ln < rn : p.op === ">=" ? ln >= rn : ln <= rn;
|
|
29104
|
+
}
|
|
29105
|
+
out += resolveAtom(cond ? p.yes : p.no);
|
|
29106
|
+
}
|
|
29107
|
+
else if (p.kind === "arith") {
|
|
29108
|
+
const vals = [];
|
|
29109
|
+
const ops = [];
|
|
29110
|
+
for (let ti = 0; ti < p.tokens.length; ti++) {
|
|
29111
|
+
const tk = p.tokens[ti];
|
|
29112
|
+
if (ti % 2 === 1) {
|
|
29113
|
+
ops.push(tk);
|
|
29114
|
+
}
|
|
29115
|
+
else {
|
|
29116
|
+
let v = 0;
|
|
29117
|
+
if (tk === "NR")
|
|
29118
|
+
v = li + 1;
|
|
29119
|
+
else if (tk === "NF")
|
|
29120
|
+
v = fields.length;
|
|
29121
|
+
else if (tk.startsWith("$")) {
|
|
29122
|
+
const fSub = tk.slice(1);
|
|
29123
|
+
const idx = fSub === "NF" ? fields.length : Number(fSub);
|
|
29124
|
+
const rawF = idx === 0 ? l : (idx >= 1 && idx <= fields.length ? fields[idx - 1] : "");
|
|
29125
|
+
const nm = /^[ \t]*([+-]?(?:\d+(?:\.\d*)?|\.\d+))/.exec(rawF);
|
|
29126
|
+
v = nm ? Number(nm[1]) : 0;
|
|
29127
|
+
}
|
|
29128
|
+
else if (/^-?[0-9]+(?:\.[0-9]+)?$/.test(tk)) {
|
|
29129
|
+
v = Number(tk);
|
|
29130
|
+
}
|
|
29131
|
+
else {
|
|
29132
|
+
const uv = userVars.get(tk) ?? "";
|
|
29133
|
+
const nm = /^[ \t]*([+-]?(?:\d+(?:\.\d*)?|\.\d+))/.exec(uv);
|
|
29134
|
+
v = nm ? Number(nm[1]) : 0;
|
|
29135
|
+
}
|
|
29136
|
+
vals.push(v);
|
|
29137
|
+
}
|
|
29138
|
+
}
|
|
29139
|
+
const addVals = [vals[0]];
|
|
29140
|
+
const addOps = [];
|
|
29141
|
+
for (let oi = 0; oi < ops.length; oi++) {
|
|
29142
|
+
const op = ops[oi];
|
|
29143
|
+
const rhs = vals[oi + 1];
|
|
29144
|
+
if (op === "*" || op === "/" || op === "%") {
|
|
29145
|
+
if ((op === "/" || op === "%") && rhs === 0)
|
|
29146
|
+
return undefined;
|
|
29147
|
+
const lhs = addVals.pop();
|
|
29148
|
+
addVals.push(op === "*" ? lhs * rhs : op === "/" ? lhs / rhs : lhs % rhs);
|
|
29149
|
+
}
|
|
29150
|
+
else {
|
|
29151
|
+
addOps.push(op);
|
|
29152
|
+
addVals.push(rhs);
|
|
29153
|
+
}
|
|
29154
|
+
}
|
|
29155
|
+
let acc = addVals[0];
|
|
29156
|
+
for (let oi = 0; oi < addOps.length; oi++) {
|
|
29157
|
+
acc = addOps[oi] === "+" ? acc + addVals[oi + 1] : acc - addVals[oi + 1];
|
|
29158
|
+
}
|
|
29159
|
+
out += awkValueText(awkNumeric(acc));
|
|
29160
|
+
}
|
|
29161
|
+
else if (p.kind === "length") {
|
|
29162
|
+
const idx = p.token === "NF" ? fields.length : Number(p.token);
|
|
29163
|
+
const s = idx === 0 ? l : (idx >= 1 && idx <= fields.length ? fields[idx - 1] : "");
|
|
29164
|
+
out += String(Array.from(s).length);
|
|
29165
|
+
}
|
|
27408
29166
|
else if (p.token === "0")
|
|
27409
29167
|
out += l;
|
|
27410
29168
|
else {
|
|
@@ -27412,8 +29170,9 @@ export class Runtime {
|
|
|
27412
29170
|
out += idx === 0 ? l : (idx >= 1 && idx <= fields.length ? fields[idx - 1] : "");
|
|
27413
29171
|
}
|
|
27414
29172
|
}
|
|
27415
|
-
|
|
27416
|
-
}
|
|
29173
|
+
outLines.push(out);
|
|
29174
|
+
}
|
|
29175
|
+
return outLines;
|
|
27417
29176
|
}
|
|
27418
29177
|
formatSyncTransformQ(val) {
|
|
27419
29178
|
let ansi = false;
|
|
@@ -27456,41 +29215,716 @@ export class Runtime {
|
|
|
27456
29215
|
}
|
|
27457
29216
|
return out + "'";
|
|
27458
29217
|
}
|
|
27459
|
-
|
|
27460
|
-
|
|
27461
|
-
|
|
27462
|
-
const
|
|
29218
|
+
wcMaxLineWidth(text, singleByte) {
|
|
29219
|
+
let columns = 0;
|
|
29220
|
+
let maximum = 0;
|
|
29221
|
+
for (const char of text) {
|
|
29222
|
+
const point = char.codePointAt(0);
|
|
29223
|
+
if (point === 10 || point === 13 || point === 12) {
|
|
29224
|
+
maximum = Math.max(maximum, columns);
|
|
29225
|
+
columns = 0;
|
|
29226
|
+
}
|
|
29227
|
+
else if (point === 9)
|
|
29228
|
+
columns += 8 - columns % 8;
|
|
29229
|
+
else
|
|
29230
|
+
columns += singleByte ? Number(point >= 32 && point < 127) : wcDisplayWidth(point);
|
|
29231
|
+
}
|
|
29232
|
+
return Math.max(maximum, columns);
|
|
29233
|
+
}
|
|
29234
|
+
compareSyncVersion(a, b) {
|
|
29235
|
+
let ia = 0;
|
|
29236
|
+
let ib = 0;
|
|
29237
|
+
while (ia < a.length || ib < b.length) {
|
|
29238
|
+
while ((ia < a.length && !(a[ia] >= "0" && a[ia] <= "9")) || (ib < b.length && !(b[ib] >= "0" && b[ib] <= "9"))) {
|
|
29239
|
+
const ca = ia < a.length ? a[ia] : undefined;
|
|
29240
|
+
const cb = ib < b.length ? b[ib] : undefined;
|
|
29241
|
+
const da = ca !== undefined && ca >= "0" && ca <= "9";
|
|
29242
|
+
const db = cb !== undefined && cb >= "0" && cb <= "9";
|
|
29243
|
+
if (da && db)
|
|
29244
|
+
break;
|
|
29245
|
+
if (ca !== cb) {
|
|
29246
|
+
if (ca === undefined)
|
|
29247
|
+
return -1;
|
|
29248
|
+
if (cb === undefined)
|
|
29249
|
+
return 1;
|
|
29250
|
+
if (da)
|
|
29251
|
+
return 1;
|
|
29252
|
+
if (db)
|
|
29253
|
+
return -1;
|
|
29254
|
+
return ca < cb ? -1 : 1;
|
|
29255
|
+
}
|
|
29256
|
+
ia++;
|
|
29257
|
+
ib++;
|
|
29258
|
+
}
|
|
29259
|
+
const sa = ia;
|
|
29260
|
+
while (ia < a.length && a[ia] >= "0" && a[ia] <= "9")
|
|
29261
|
+
ia++;
|
|
29262
|
+
const sb = ib;
|
|
29263
|
+
while (ib < b.length && b[ib] >= "0" && b[ib] <= "9")
|
|
29264
|
+
ib++;
|
|
29265
|
+
if (sa < ia || sb < ib) {
|
|
29266
|
+
const na = BigInt(sa < ia ? a.slice(sa, ia) : "0");
|
|
29267
|
+
const nb = BigInt(sb < ib ? b.slice(sb, ib) : "0");
|
|
29268
|
+
if (na !== nb)
|
|
29269
|
+
return na < nb ? -1 : 1;
|
|
29270
|
+
}
|
|
29271
|
+
}
|
|
29272
|
+
return 0;
|
|
29273
|
+
}
|
|
29274
|
+
evalSyncNl(rawLines, opArgs) {
|
|
29275
|
+
let bodyStyle = "t";
|
|
29276
|
+
let format = "rn";
|
|
29277
|
+
let width = 6;
|
|
29278
|
+
let sep = "\t";
|
|
29279
|
+
let start = 1;
|
|
29280
|
+
let inc = 1;
|
|
29281
|
+
for (let i = 0; i < opArgs.length; i++) {
|
|
29282
|
+
const a = opArgs[i];
|
|
29283
|
+
if ((a === "-b" || a === "--body-numbering") && i + 1 < opArgs.length) {
|
|
29284
|
+
const v = opArgs[++i];
|
|
29285
|
+
if (v !== "a" && v !== "t" && v !== "n")
|
|
29286
|
+
return undefined;
|
|
29287
|
+
bodyStyle = v;
|
|
29288
|
+
}
|
|
29289
|
+
else if (a === "-ba" || a === "-bt" || a === "-bn") {
|
|
29290
|
+
bodyStyle = a[2];
|
|
29291
|
+
}
|
|
29292
|
+
else if ((a === "-n" || a === "--number-format") && i + 1 < opArgs.length) {
|
|
29293
|
+
const v = opArgs[++i];
|
|
29294
|
+
if (v !== "ln" && v !== "rn" && v !== "rz")
|
|
29295
|
+
return undefined;
|
|
29296
|
+
format = v;
|
|
29297
|
+
}
|
|
29298
|
+
else if (a === "-nln" || a === "-nrn" || a === "-nrz") {
|
|
29299
|
+
format = a.slice(2);
|
|
29300
|
+
}
|
|
29301
|
+
else if ((a === "-w" || a === "--number-width") && i + 1 < opArgs.length && /^[1-9][0-9]{0,2}$/.test(opArgs[i + 1])) {
|
|
29302
|
+
width = Number(opArgs[++i]);
|
|
29303
|
+
}
|
|
29304
|
+
else if (/^-w[1-9][0-9]{0,2}$/.test(a)) {
|
|
29305
|
+
width = Number(a.slice(2));
|
|
29306
|
+
}
|
|
29307
|
+
else if ((a === "-s" || a === "--number-separator") && i + 1 < opArgs.length) {
|
|
29308
|
+
sep = opArgs[++i];
|
|
29309
|
+
}
|
|
29310
|
+
else if (a.startsWith("-s") && a.length > 2) {
|
|
29311
|
+
sep = a.slice(2);
|
|
29312
|
+
}
|
|
29313
|
+
else if ((a === "-v" || a === "--starting-line-number") && i + 1 < opArgs.length && /^-?[0-9]{1,9}$/.test(opArgs[i + 1])) {
|
|
29314
|
+
start = Number(opArgs[++i]);
|
|
29315
|
+
}
|
|
29316
|
+
else if (/^-v-?[0-9]{1,9}$/.test(a)) {
|
|
29317
|
+
start = Number(a.slice(2));
|
|
29318
|
+
}
|
|
29319
|
+
else if ((a === "-i" || a === "--line-increment") && i + 1 < opArgs.length && /^-?[0-9]{1,9}$/.test(opArgs[i + 1])) {
|
|
29320
|
+
inc = Number(opArgs[++i]);
|
|
29321
|
+
}
|
|
29322
|
+
else if (/^-i-?[0-9]{1,9}$/.test(a)) {
|
|
29323
|
+
inc = Number(a.slice(2));
|
|
29324
|
+
}
|
|
29325
|
+
else {
|
|
29326
|
+
return undefined;
|
|
29327
|
+
}
|
|
29328
|
+
}
|
|
29329
|
+
const out = [];
|
|
29330
|
+
let curStyle = bodyStyle;
|
|
29331
|
+
let num = start;
|
|
29332
|
+
const unnumberedPrefix = " ".repeat(width + sep.length);
|
|
29333
|
+
for (let i = 0; i < rawLines.length; i++) {
|
|
29334
|
+
const l = rawLines[i];
|
|
29335
|
+
if (l === "\\:" || l === "\\:\\:" || l === "\\:\\:\\:") {
|
|
29336
|
+
curStyle = l === "\\:\\:" ? bodyStyle : "n";
|
|
29337
|
+
num = start;
|
|
29338
|
+
out.push("");
|
|
29339
|
+
continue;
|
|
29340
|
+
}
|
|
29341
|
+
const numbered = curStyle === "a" || (curStyle === "t" && l.length > 0);
|
|
29342
|
+
if (!numbered) {
|
|
29343
|
+
out.push(l.length === 0 && sep === "\t" ? " ".repeat(width + 1) : unnumberedPrefix + l);
|
|
29344
|
+
continue;
|
|
29345
|
+
}
|
|
29346
|
+
const label = String(num);
|
|
29347
|
+
const pad = Math.max(0, width - label.length);
|
|
29348
|
+
let prefix;
|
|
29349
|
+
if (format === "ln")
|
|
29350
|
+
prefix = label + " ".repeat(pad);
|
|
29351
|
+
else if (format === "rz")
|
|
29352
|
+
prefix = num < 0 ? "-" + "0".repeat(pad) + label.slice(1) : "0".repeat(pad) + label;
|
|
29353
|
+
else
|
|
29354
|
+
prefix = " ".repeat(pad) + label;
|
|
29355
|
+
out.push(prefix + sep + l);
|
|
29356
|
+
num += inc;
|
|
29357
|
+
}
|
|
29358
|
+
return out;
|
|
29359
|
+
}
|
|
29360
|
+
evalSyncPaste(rawLines, opArgs) {
|
|
29361
|
+
let serial = false;
|
|
29362
|
+
let delims = ["\t"];
|
|
29363
|
+
let literal = false;
|
|
29364
|
+
const files = [];
|
|
29365
|
+
const parseDelims = (s) => {
|
|
29366
|
+
if (s.length === 0)
|
|
29367
|
+
return [""];
|
|
29368
|
+
const res = [];
|
|
29369
|
+
const escapes = { b: "\b", f: "\f", n: "\n", r: "\r", t: "\t", v: "\v", "0": "" };
|
|
29370
|
+
for (let i = 0; i < s.length; i++) {
|
|
29371
|
+
const ch = s[i];
|
|
29372
|
+
if (ch === "\\") {
|
|
29373
|
+
if (i + 1 >= s.length)
|
|
29374
|
+
return undefined;
|
|
29375
|
+
const esc = s[++i];
|
|
29376
|
+
res.push(escapes[esc] ?? esc);
|
|
29377
|
+
}
|
|
29378
|
+
else {
|
|
29379
|
+
res.push(ch);
|
|
29380
|
+
}
|
|
29381
|
+
}
|
|
29382
|
+
return res.length > 0 ? res : [""];
|
|
29383
|
+
};
|
|
29384
|
+
for (let i = 0; i < opArgs.length; i++) {
|
|
29385
|
+
const a = opArgs[i];
|
|
29386
|
+
if (literal || a === "-" || !a.startsWith("-")) {
|
|
29387
|
+
files.push(a);
|
|
29388
|
+
continue;
|
|
29389
|
+
}
|
|
29390
|
+
if (a === "--") {
|
|
29391
|
+
literal = true;
|
|
29392
|
+
continue;
|
|
29393
|
+
}
|
|
29394
|
+
if (a === "--serial") {
|
|
29395
|
+
serial = true;
|
|
29396
|
+
continue;
|
|
29397
|
+
}
|
|
29398
|
+
if (a === "--delimiters" && i + 1 < opArgs.length) {
|
|
29399
|
+
const d = parseDelims(opArgs[++i]);
|
|
29400
|
+
if (!d)
|
|
29401
|
+
return undefined;
|
|
29402
|
+
delims = d;
|
|
29403
|
+
continue;
|
|
29404
|
+
}
|
|
29405
|
+
if (a.startsWith("--delimiters=")) {
|
|
29406
|
+
const d = parseDelims(a.slice(13));
|
|
29407
|
+
if (!d)
|
|
29408
|
+
return undefined;
|
|
29409
|
+
delims = d;
|
|
29410
|
+
continue;
|
|
29411
|
+
}
|
|
29412
|
+
if (a.startsWith("--"))
|
|
29413
|
+
return undefined;
|
|
29414
|
+
for (let k = 1; k < a.length; k++) {
|
|
29415
|
+
const f = a[k];
|
|
29416
|
+
if (f === "s")
|
|
29417
|
+
serial = true;
|
|
29418
|
+
else if (f === "d") {
|
|
29419
|
+
const rest = a.slice(k + 1);
|
|
29420
|
+
const rawD = rest.length > 0 ? rest : (i + 1 < opArgs.length ? opArgs[++i] : undefined);
|
|
29421
|
+
if (rawD === undefined)
|
|
29422
|
+
return undefined;
|
|
29423
|
+
const d = parseDelims(rawD);
|
|
29424
|
+
if (!d)
|
|
29425
|
+
return undefined;
|
|
29426
|
+
delims = d;
|
|
29427
|
+
break;
|
|
29428
|
+
}
|
|
29429
|
+
else
|
|
29430
|
+
return undefined;
|
|
29431
|
+
}
|
|
29432
|
+
}
|
|
29433
|
+
if (files.length === 0)
|
|
29434
|
+
files.push("-");
|
|
29435
|
+
if (!files.every(f => f === "-"))
|
|
29436
|
+
return undefined;
|
|
29437
|
+
if (serial) {
|
|
29438
|
+
if (files.length !== 1)
|
|
29439
|
+
return undefined;
|
|
29440
|
+
if (rawLines.length === 0)
|
|
29441
|
+
return [];
|
|
29442
|
+
let joined = rawLines[0];
|
|
29443
|
+
for (let i = 1; i < rawLines.length; i++) {
|
|
29444
|
+
joined += delims[(i - 1) % delims.length] + rawLines[i];
|
|
29445
|
+
}
|
|
29446
|
+
return joined.split("\n");
|
|
29447
|
+
}
|
|
29448
|
+
const cols = files.length;
|
|
29449
|
+
const out = [];
|
|
29450
|
+
for (let i = 0; i < rawLines.length; i += cols) {
|
|
29451
|
+
let row = rawLines[i] ?? "";
|
|
29452
|
+
for (let c = 1; c < cols; c++) {
|
|
29453
|
+
row += delims[(c - 1) % delims.length] + (rawLines[i + c] ?? "");
|
|
29454
|
+
}
|
|
29455
|
+
out.push(row);
|
|
29456
|
+
}
|
|
29457
|
+
return out;
|
|
29458
|
+
}
|
|
29459
|
+
evalSyncNumfmt(rawLines, opArgs) {
|
|
29460
|
+
let fromScale = "none";
|
|
29461
|
+
let toScale = "none";
|
|
29462
|
+
let padding = 0;
|
|
29463
|
+
let suffix = "";
|
|
29464
|
+
for (let i = 0; i < opArgs.length; i++) {
|
|
29465
|
+
const a = opArgs[i];
|
|
29466
|
+
if (a.startsWith("--from=")) {
|
|
29467
|
+
const v = a.slice(7);
|
|
29468
|
+
if (v === "none" || v === "iec" || v === "iec-i" || v === "si" || v === "auto")
|
|
29469
|
+
fromScale = v;
|
|
29470
|
+
else
|
|
29471
|
+
return undefined;
|
|
29472
|
+
}
|
|
29473
|
+
else if (a.startsWith("--to=")) {
|
|
29474
|
+
const v = a.slice(5);
|
|
29475
|
+
if (v === "none" || v === "iec" || v === "iec-i" || v === "si")
|
|
29476
|
+
toScale = v;
|
|
29477
|
+
else
|
|
29478
|
+
return undefined;
|
|
29479
|
+
}
|
|
29480
|
+
else if (a.startsWith("--padding=")) {
|
|
29481
|
+
const v = a.slice(10);
|
|
29482
|
+
if (!/^-?[1-9][0-9]{0,2}$/.test(v))
|
|
29483
|
+
return undefined;
|
|
29484
|
+
padding = Number(v);
|
|
29485
|
+
}
|
|
29486
|
+
else if (a.startsWith("--suffix=")) {
|
|
29487
|
+
suffix = a.slice(9);
|
|
29488
|
+
}
|
|
29489
|
+
else {
|
|
29490
|
+
return undefined;
|
|
29491
|
+
}
|
|
29492
|
+
}
|
|
29493
|
+
const units = "KMGTPEZY";
|
|
29494
|
+
const out = [];
|
|
29495
|
+
for (let i = 0; i < rawLines.length; i++) {
|
|
29496
|
+
const raw = rawLines[i].trim();
|
|
29497
|
+
if (raw.length === 0) {
|
|
29498
|
+
out.push("");
|
|
29499
|
+
continue;
|
|
29500
|
+
}
|
|
29501
|
+
const m = /^([+-]?(?:\d+(?:\.\d*)?|\.\d+))([KMGTPEZYkmgtpezy]i?)?$/.exec(raw);
|
|
29502
|
+
if (!m)
|
|
29503
|
+
return undefined;
|
|
29504
|
+
let val = Number(m[1]);
|
|
29505
|
+
const suf = m[2] ?? "";
|
|
29506
|
+
if (suf.length > 0) {
|
|
29507
|
+
if (fromScale === "none")
|
|
29508
|
+
return undefined;
|
|
29509
|
+
const uChar = suf[0].toUpperCase();
|
|
29510
|
+
const pIdx = units.indexOf(uChar) + 1;
|
|
29511
|
+
if (pIdx <= 0)
|
|
29512
|
+
return undefined;
|
|
29513
|
+
const hasI = suf.length === 2 && suf[1].toLowerCase() === "i";
|
|
29514
|
+
if (fromScale === "iec-i" && !hasI)
|
|
29515
|
+
return undefined;
|
|
29516
|
+
if ((fromScale === "iec" || fromScale === "si") && hasI)
|
|
29517
|
+
return undefined;
|
|
29518
|
+
const fBase = (fromScale === "iec" || fromScale === "iec-i" || (fromScale === "auto" && hasI)) ? 1024 : 1000;
|
|
29519
|
+
val = val * Math.pow(fBase, pIdx);
|
|
29520
|
+
}
|
|
29521
|
+
else if (fromScale === "iec-i") {
|
|
29522
|
+
// plain number ok
|
|
29523
|
+
}
|
|
29524
|
+
val = val >= 0 ? Math.ceil(val - 1e-12) : -Math.ceil(Math.abs(val) - 1e-12);
|
|
29525
|
+
let rendered;
|
|
29526
|
+
if (toScale === "none") {
|
|
29527
|
+
rendered = String(Math.trunc(val));
|
|
29528
|
+
}
|
|
29529
|
+
else {
|
|
29530
|
+
const tBase = (toScale === "iec" || toScale === "iec-i") ? 1024 : 1000;
|
|
29531
|
+
let pIdx = 0;
|
|
29532
|
+
let scaled = val;
|
|
29533
|
+
while (Math.abs(scaled) >= tBase && pIdx < units.length) {
|
|
29534
|
+
scaled /= tBase;
|
|
29535
|
+
pIdx++;
|
|
29536
|
+
}
|
|
29537
|
+
if (pIdx === 0) {
|
|
29538
|
+
rendered = String(Math.trunc(scaled));
|
|
29539
|
+
}
|
|
29540
|
+
else {
|
|
29541
|
+
if (Math.abs(scaled) < 10) {
|
|
29542
|
+
scaled = (scaled >= 0 ? Math.ceil(scaled * 10 - 1e-12) : -Math.ceil(Math.abs(scaled) * 10 - 1e-12)) / 10;
|
|
29543
|
+
if (Math.abs(scaled) >= tBase && pIdx < units.length) {
|
|
29544
|
+
scaled /= tBase;
|
|
29545
|
+
pIdx++;
|
|
29546
|
+
}
|
|
29547
|
+
}
|
|
29548
|
+
else {
|
|
29549
|
+
scaled = scaled >= 0 ? Math.ceil(scaled - 1e-12) : -Math.ceil(Math.abs(scaled) - 1e-12);
|
|
29550
|
+
if (Math.abs(scaled) >= tBase && pIdx < units.length) {
|
|
29551
|
+
scaled /= tBase;
|
|
29552
|
+
pIdx++;
|
|
29553
|
+
}
|
|
29554
|
+
}
|
|
29555
|
+
const numText = Math.abs(scaled) < 10 ? scaled.toFixed(1) : scaled.toFixed(0);
|
|
29556
|
+
const uText = (toScale === "si" && pIdx === 1 ? "k" : units[pIdx - 1]) + (toScale === "iec-i" ? "i" : "");
|
|
29557
|
+
rendered = numText + uText;
|
|
29558
|
+
}
|
|
29559
|
+
}
|
|
29560
|
+
rendered += suffix;
|
|
29561
|
+
if (padding !== 0) {
|
|
29562
|
+
const w = Math.abs(padding);
|
|
29563
|
+
if (rendered.length < w) {
|
|
29564
|
+
const pad = " ".repeat(w - rendered.length);
|
|
29565
|
+
rendered = padding < 0 ? rendered + pad : pad + rendered;
|
|
29566
|
+
}
|
|
29567
|
+
}
|
|
29568
|
+
out.push(rendered);
|
|
29569
|
+
}
|
|
29570
|
+
return out;
|
|
29571
|
+
}
|
|
29572
|
+
evalSyncSort(rawLines, opArgs, isByteLocale) {
|
|
29573
|
+
if (isByteLocale)
|
|
29574
|
+
return undefined;
|
|
29575
|
+
let rev = false;
|
|
29576
|
+
let num = false;
|
|
29577
|
+
let human = false;
|
|
29578
|
+
let month = false;
|
|
29579
|
+
let dict = false;
|
|
29580
|
+
let uniq = false;
|
|
29581
|
+
let fold = false;
|
|
29582
|
+
let blanks = false;
|
|
29583
|
+
let stable = false;
|
|
29584
|
+
let ver = false;
|
|
29585
|
+
let sep;
|
|
29586
|
+
let keySpec;
|
|
29587
|
+
for (let i = 0; i < opArgs.length; i++) {
|
|
29588
|
+
const a = opArgs[i];
|
|
29589
|
+
if (/^-[runfbsVhMd]+$/.test(a)) {
|
|
29590
|
+
if (a.includes("r"))
|
|
29591
|
+
rev = true;
|
|
29592
|
+
if (a.includes("n"))
|
|
29593
|
+
num = true;
|
|
29594
|
+
if (a.includes("h"))
|
|
29595
|
+
human = true;
|
|
29596
|
+
if (a.includes("M"))
|
|
29597
|
+
month = true;
|
|
29598
|
+
if (a.includes("d"))
|
|
29599
|
+
dict = true;
|
|
29600
|
+
if (a.includes("u"))
|
|
29601
|
+
uniq = true;
|
|
29602
|
+
if (a.includes("f"))
|
|
29603
|
+
fold = true;
|
|
29604
|
+
if (a.includes("b"))
|
|
29605
|
+
blanks = true;
|
|
29606
|
+
if (a.includes("s"))
|
|
29607
|
+
stable = true;
|
|
29608
|
+
if (a.includes("V"))
|
|
29609
|
+
ver = true;
|
|
29610
|
+
}
|
|
29611
|
+
else if (a === "--reverse")
|
|
29612
|
+
rev = true;
|
|
29613
|
+
else if (a === "--numeric-sort")
|
|
29614
|
+
num = true;
|
|
29615
|
+
else if (a === "--human-numeric-sort")
|
|
29616
|
+
human = true;
|
|
29617
|
+
else if (a === "--month-sort")
|
|
29618
|
+
month = true;
|
|
29619
|
+
else if (a === "--dictionary-order")
|
|
29620
|
+
dict = true;
|
|
29621
|
+
else if (a === "--unique")
|
|
29622
|
+
uniq = true;
|
|
29623
|
+
else if (a === "--ignore-case")
|
|
29624
|
+
fold = true;
|
|
29625
|
+
else if (a === "--ignore-leading-blanks")
|
|
29626
|
+
blanks = true;
|
|
29627
|
+
else if (a === "--stable")
|
|
29628
|
+
stable = true;
|
|
29629
|
+
else if (a === "--version-sort")
|
|
29630
|
+
ver = true;
|
|
29631
|
+
else if (a === "-t" && i + 1 < opArgs.length && opArgs[i + 1].length === 1) {
|
|
29632
|
+
sep = opArgs[++i];
|
|
29633
|
+
}
|
|
29634
|
+
else if (a.startsWith("-t") && a.length === 3) {
|
|
29635
|
+
sep = a[2];
|
|
29636
|
+
}
|
|
29637
|
+
else if (a.startsWith("--field-separator=") && a.length === 19) {
|
|
29638
|
+
sep = a[18];
|
|
29639
|
+
}
|
|
29640
|
+
else if (a === "-k" && i + 1 < opArgs.length) {
|
|
29641
|
+
if (keySpec !== undefined)
|
|
29642
|
+
return undefined;
|
|
29643
|
+
keySpec = opArgs[++i];
|
|
29644
|
+
}
|
|
29645
|
+
else if (a.startsWith("-k") && a.length > 2) {
|
|
29646
|
+
if (keySpec !== undefined)
|
|
29647
|
+
return undefined;
|
|
29648
|
+
keySpec = a.slice(2);
|
|
29649
|
+
}
|
|
29650
|
+
else {
|
|
29651
|
+
return undefined;
|
|
29652
|
+
}
|
|
29653
|
+
}
|
|
29654
|
+
if (ver || keySpec?.includes("V"))
|
|
29655
|
+
return undefined;
|
|
29656
|
+
let startField = 1;
|
|
29657
|
+
let endField;
|
|
29658
|
+
let keyNum = num;
|
|
29659
|
+
let keyHuman = human;
|
|
29660
|
+
let keyMonth = month;
|
|
29661
|
+
let keyDict = dict;
|
|
29662
|
+
let keyRev = rev;
|
|
29663
|
+
let keyFold = fold;
|
|
29664
|
+
let keyBlanks = blanks;
|
|
29665
|
+
let keyVer = ver;
|
|
29666
|
+
if (keySpec !== undefined) {
|
|
29667
|
+
const km = /^([1-9][0-9]{0,2})(?:,([1-9][0-9]{0,2}))?([nrbfVhMd]*)$/.exec(keySpec);
|
|
29668
|
+
if (!km)
|
|
29669
|
+
return undefined;
|
|
29670
|
+
startField = Number(km[1]);
|
|
29671
|
+
endField = km[2] !== undefined ? Number(km[2]) : undefined;
|
|
29672
|
+
if (endField !== undefined && endField < startField)
|
|
29673
|
+
return undefined;
|
|
29674
|
+
const kf = km[3] ?? "";
|
|
29675
|
+
if (kf.includes("n"))
|
|
29676
|
+
keyNum = true;
|
|
29677
|
+
if (kf.includes("h"))
|
|
29678
|
+
keyHuman = true;
|
|
29679
|
+
if (kf.includes("M"))
|
|
29680
|
+
keyMonth = true;
|
|
29681
|
+
if (kf.includes("d"))
|
|
29682
|
+
keyDict = true;
|
|
29683
|
+
if (kf.includes("r"))
|
|
29684
|
+
keyRev = true;
|
|
29685
|
+
if (kf.includes("f"))
|
|
29686
|
+
keyFold = true;
|
|
29687
|
+
if (kf.includes("b"))
|
|
29688
|
+
keyBlanks = true;
|
|
29689
|
+
if (kf.includes("V"))
|
|
29690
|
+
keyVer = true;
|
|
29691
|
+
}
|
|
29692
|
+
const extractKey = (l) => {
|
|
29693
|
+
let raw = keySpec === undefined
|
|
29694
|
+
? l
|
|
29695
|
+
: (() => {
|
|
29696
|
+
if (sep !== undefined) {
|
|
29697
|
+
const fields = l.split(sep);
|
|
29698
|
+
return fields.slice(startField - 1, endField).join(sep);
|
|
29699
|
+
}
|
|
29700
|
+
// Default fields include their leading blanks; retain exact bytes.
|
|
29701
|
+
let offset = 0;
|
|
29702
|
+
let start = l.length;
|
|
29703
|
+
let end = l.length;
|
|
29704
|
+
for (let field = 1; offset < l.length; field++) {
|
|
29705
|
+
if (field === startField)
|
|
29706
|
+
start = offset;
|
|
29707
|
+
while (l[offset] === " " || l[offset] === "\t")
|
|
29708
|
+
offset++;
|
|
29709
|
+
while (offset < l.length && l[offset] !== " " && l[offset] !== "\t")
|
|
29710
|
+
offset++;
|
|
29711
|
+
if (field === endField) {
|
|
29712
|
+
end = offset;
|
|
29713
|
+
break;
|
|
29714
|
+
}
|
|
29715
|
+
}
|
|
29716
|
+
return l.slice(start, end);
|
|
29717
|
+
})();
|
|
29718
|
+
if (keyBlanks)
|
|
29719
|
+
raw = raw.replace(/^[ \t]+/, "");
|
|
29720
|
+
if (keyDict)
|
|
29721
|
+
raw = raw.replace(/[^a-zA-Z0-9 \t]+/g, "");
|
|
29722
|
+
return keyFold ? raw.toUpperCase() : raw;
|
|
29723
|
+
};
|
|
27463
29724
|
const parseNum = (s) => {
|
|
27464
|
-
const m = /^[ \t]*(
|
|
29725
|
+
const m = /^[ \t]*(-?(?:\d+(?:\.\d*)?|\.\d+))/.exec(s);
|
|
27465
29726
|
return m ? Number(m[1]) : 0;
|
|
27466
29727
|
};
|
|
29728
|
+
const compareHuman = (sa, sb) => {
|
|
29729
|
+
const parseH = (s) => {
|
|
29730
|
+
const m = /^[ \t]*(-?(?:\d+(?:\.\d*)?|\.\d+))([KMGTPEZYkmgtpezy])?/.exec(s);
|
|
29731
|
+
if (!m)
|
|
29732
|
+
return { sign: 0, unit: 0, val: 0 };
|
|
29733
|
+
const val = Number(m[1]);
|
|
29734
|
+
if (val === 0)
|
|
29735
|
+
return { sign: 0, unit: 0, val: 0 };
|
|
29736
|
+
const uChar = m[2] ? m[2].toUpperCase() : "";
|
|
29737
|
+
const unit = uChar === "" ? 0 : "KMGTPEZY".indexOf(uChar) + 1;
|
|
29738
|
+
return { sign: val < 0 ? -1 : 1, unit, val };
|
|
29739
|
+
};
|
|
29740
|
+
const ha = parseH(sa);
|
|
29741
|
+
const hb = parseH(sb);
|
|
29742
|
+
if (ha.sign !== hb.sign)
|
|
29743
|
+
return ha.sign - hb.sign;
|
|
29744
|
+
if (ha.unit !== hb.unit)
|
|
29745
|
+
return ha.sign < 0 ? hb.unit - ha.unit : ha.unit - hb.unit;
|
|
29746
|
+
return ha.val - hb.val;
|
|
29747
|
+
};
|
|
29748
|
+
const parseMonth = (s) => {
|
|
29749
|
+
const m = /^[ \t]*([a-zA-Z]{3})/.exec(s);
|
|
29750
|
+
if (!m)
|
|
29751
|
+
return 0;
|
|
29752
|
+
const idx = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"].indexOf(m[1].toUpperCase());
|
|
29753
|
+
return idx === -1 ? 0 : idx + 1;
|
|
29754
|
+
};
|
|
27467
29755
|
const sorted = [...rawLines].sort((a, b) => {
|
|
27468
|
-
|
|
27469
|
-
|
|
27470
|
-
|
|
29756
|
+
const ka = extractKey(a);
|
|
29757
|
+
const kb = extractKey(b);
|
|
29758
|
+
if (keyHuman) {
|
|
29759
|
+
const hc = compareHuman(ka, kb);
|
|
29760
|
+
if (hc !== 0)
|
|
29761
|
+
return keyRev ? -hc : hc;
|
|
29762
|
+
}
|
|
29763
|
+
else if (keyMonth) {
|
|
29764
|
+
const ma = parseMonth(ka);
|
|
29765
|
+
const mb = parseMonth(kb);
|
|
29766
|
+
if (ma !== mb)
|
|
29767
|
+
return keyRev ? mb - ma : ma - mb;
|
|
29768
|
+
}
|
|
29769
|
+
else if (keyNum) {
|
|
29770
|
+
const na = parseNum(ka);
|
|
29771
|
+
const nb = parseNum(kb);
|
|
27471
29772
|
if (na !== nb)
|
|
27472
|
-
return
|
|
29773
|
+
return keyRev ? nb - na : na - nb;
|
|
29774
|
+
}
|
|
29775
|
+
else if (keyVer) {
|
|
29776
|
+
const vc = this.compareSyncVersion(ka, kb);
|
|
29777
|
+
if (vc !== 0)
|
|
29778
|
+
return keyRev ? -vc : vc;
|
|
27473
29779
|
}
|
|
29780
|
+
else if (ka !== kb) {
|
|
29781
|
+
return ka < kb ? (keyRev ? 1 : -1) : (keyRev ? -1 : 1);
|
|
29782
|
+
}
|
|
29783
|
+
if (uniq || stable)
|
|
29784
|
+
return 0;
|
|
29785
|
+
const fa = fold ? a.toUpperCase() : a;
|
|
29786
|
+
const fb = fold ? b.toUpperCase() : b;
|
|
29787
|
+
if (fa !== fb)
|
|
29788
|
+
return fa < fb ? (rev ? 1 : -1) : (rev ? -1 : 1);
|
|
27474
29789
|
return a < b ? (rev ? 1 : -1) : a > b ? (rev ? -1 : 1) : 0;
|
|
27475
29790
|
});
|
|
27476
29791
|
if (!uniq)
|
|
27477
29792
|
return sorted;
|
|
27478
29793
|
const dedup = [];
|
|
27479
29794
|
for (let i = 0; i < sorted.length; i++) {
|
|
27480
|
-
if (i === 0
|
|
29795
|
+
if (i === 0) {
|
|
27481
29796
|
dedup.push(sorted[i]);
|
|
29797
|
+
}
|
|
29798
|
+
else {
|
|
29799
|
+
const ka = extractKey(sorted[i]);
|
|
29800
|
+
const kb = extractKey(sorted[i - 1]);
|
|
29801
|
+
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;
|
|
29802
|
+
if (!same)
|
|
29803
|
+
dedup.push(sorted[i]);
|
|
29804
|
+
}
|
|
27482
29805
|
}
|
|
27483
29806
|
return dedup;
|
|
27484
29807
|
}
|
|
27485
|
-
|
|
27486
|
-
if (
|
|
27487
|
-
return
|
|
27488
|
-
if (
|
|
27489
|
-
return
|
|
27490
|
-
|
|
29808
|
+
normalizeSyncWcFlag(arg) {
|
|
29809
|
+
if (arg === "-l" || arg === "--lines")
|
|
29810
|
+
return "-l";
|
|
29811
|
+
if (arg === "-c" || arg === "--bytes")
|
|
29812
|
+
return "-c";
|
|
29813
|
+
if (arg === "-w" || arg === "--words")
|
|
29814
|
+
return "-w";
|
|
29815
|
+
if (arg === "-m" || arg === "--chars")
|
|
29816
|
+
return "-m";
|
|
29817
|
+
if (arg === "-L" || arg === "--max-line-length")
|
|
29818
|
+
return "-L";
|
|
29819
|
+
return undefined;
|
|
29820
|
+
}
|
|
29821
|
+
evalSyncUniq(rawLines, opArgs) {
|
|
29822
|
+
let ignoreCase = false;
|
|
29823
|
+
let hasCount = false;
|
|
29824
|
+
let onlyRepeated = false;
|
|
29825
|
+
let onlyUnique = false;
|
|
29826
|
+
let skipFields = 0;
|
|
29827
|
+
let skipChars = 0;
|
|
29828
|
+
let checkChars = Infinity;
|
|
29829
|
+
for (let i = 0; i < opArgs.length; i++) {
|
|
29830
|
+
const a = opArgs[i];
|
|
29831
|
+
if (a === "--ignore-case")
|
|
29832
|
+
ignoreCase = true;
|
|
29833
|
+
else if (a === "--count")
|
|
29834
|
+
hasCount = true;
|
|
29835
|
+
else if (a === "--repeated")
|
|
29836
|
+
onlyRepeated = true;
|
|
29837
|
+
else if (a === "--unique")
|
|
29838
|
+
onlyUnique = true;
|
|
29839
|
+
else if (/^--skip-fields=[0-9]{1,4}$/.test(a))
|
|
29840
|
+
skipFields = Number(a.slice(14));
|
|
29841
|
+
else if (/^--skip-chars=[0-9]{1,4}$/.test(a))
|
|
29842
|
+
skipChars = Number(a.slice(13));
|
|
29843
|
+
else if (/^--check-chars=[0-9]{1,4}$/.test(a))
|
|
29844
|
+
checkChars = Number(a.slice(14));
|
|
29845
|
+
else if ((a === "-f" || a === "-s" || a === "-w") && i + 1 < opArgs.length && /^[0-9]{1,4}$/.test(opArgs[i + 1])) {
|
|
29846
|
+
const n = Number(opArgs[++i]);
|
|
29847
|
+
if (a === "-f")
|
|
29848
|
+
skipFields = n;
|
|
29849
|
+
else if (a === "-s")
|
|
29850
|
+
skipChars = n;
|
|
29851
|
+
else
|
|
29852
|
+
checkChars = n;
|
|
29853
|
+
}
|
|
29854
|
+
else if (/^-[fsw][0-9]{1,4}$/.test(a)) {
|
|
29855
|
+
const n = Number(a.slice(2));
|
|
29856
|
+
if (a[1] === "f")
|
|
29857
|
+
skipFields = n;
|
|
29858
|
+
else if (a[1] === "s")
|
|
29859
|
+
skipChars = n;
|
|
29860
|
+
else
|
|
29861
|
+
checkChars = n;
|
|
29862
|
+
}
|
|
29863
|
+
else if (/^-[cdui]+$/.test(a)) {
|
|
29864
|
+
for (let k = 1; k < a.length; k++) {
|
|
29865
|
+
const ch = a[k];
|
|
29866
|
+
if (ch === "i")
|
|
29867
|
+
ignoreCase = true;
|
|
29868
|
+
else if (ch === "c")
|
|
29869
|
+
hasCount = true;
|
|
29870
|
+
else if (ch === "d")
|
|
29871
|
+
onlyRepeated = true;
|
|
29872
|
+
else if (ch === "u")
|
|
29873
|
+
onlyUnique = true;
|
|
29874
|
+
}
|
|
29875
|
+
}
|
|
29876
|
+
else {
|
|
29877
|
+
return undefined;
|
|
29878
|
+
}
|
|
29879
|
+
}
|
|
29880
|
+
const keyOf = (l) => {
|
|
29881
|
+
let offset = 0;
|
|
29882
|
+
for (let f = 0; f < skipFields; f++) {
|
|
29883
|
+
while (offset < l.length && (l[offset] === " " || l[offset] === "\t"))
|
|
29884
|
+
offset++;
|
|
29885
|
+
while (offset < l.length && l[offset] !== " " && l[offset] !== "\t")
|
|
29886
|
+
offset++;
|
|
29887
|
+
}
|
|
29888
|
+
if (skipChars === 0 && checkChars === Infinity) {
|
|
29889
|
+
const sub = l.slice(offset);
|
|
29890
|
+
return ignoreCase ? sub.toLowerCase() : sub;
|
|
29891
|
+
}
|
|
29892
|
+
const chars = Array.from(l.slice(offset));
|
|
29893
|
+
const sub = (checkChars === Infinity ? chars.slice(skipChars) : chars.slice(skipChars, skipChars + checkChars)).join("");
|
|
29894
|
+
return ignoreCase ? sub.toLowerCase() : sub;
|
|
29895
|
+
};
|
|
29896
|
+
const outLines = [];
|
|
29897
|
+
let uIdx = 0;
|
|
29898
|
+
while (uIdx < rawLines.length) {
|
|
29899
|
+
const k0 = keyOf(rawLines[uIdx]);
|
|
29900
|
+
let uEnd = uIdx + 1;
|
|
29901
|
+
while (uEnd < rawLines.length && keyOf(rawLines[uEnd]) === k0)
|
|
29902
|
+
uEnd++;
|
|
29903
|
+
const count = uEnd - uIdx;
|
|
29904
|
+
if ((!onlyRepeated || count > 1) && (!onlyUnique || count === 1)) {
|
|
29905
|
+
outLines.push(hasCount ? `${String(count).padStart(7, " ")} ${rawLines[uIdx]}` : rawLines[uIdx]);
|
|
29906
|
+
}
|
|
29907
|
+
uIdx = uEnd;
|
|
29908
|
+
}
|
|
29909
|
+
return outLines;
|
|
29910
|
+
}
|
|
29911
|
+
sortSyncLines(rawLines, flag) {
|
|
29912
|
+
return this.evalSyncSort(rawLines, flag !== undefined ? [flag] : [], false) ?? [...rawLines];
|
|
29913
|
+
}
|
|
29914
|
+
translateSyncTr(input, set1Spec, set2Spec, truncateSet1 = false) {
|
|
29915
|
+
if ((set1Spec === "a-z" || set1Spec === "[:lower:]") && (set2Spec === "A-Z" || set2Spec === "[:upper:]")) {
|
|
29916
|
+
return input.replace(/[a-z]/g, ch => String.fromCharCode(ch.charCodeAt(0) - 32));
|
|
29917
|
+
}
|
|
29918
|
+
if ((set1Spec === "A-Z" || set1Spec === "[:upper:]") && (set2Spec === "a-z" || set2Spec === "[:lower:]")) {
|
|
29919
|
+
return input.replace(/[A-Z]/g, ch => String.fromCharCode(ch.charCodeAt(0) + 32));
|
|
29920
|
+
}
|
|
29921
|
+
const rawS1 = this.expandSyncTrCharArray(set1Spec);
|
|
27491
29922
|
const s2 = this.expandSyncTrCharArray(set2Spec);
|
|
27492
|
-
if (!
|
|
29923
|
+
if (!rawS1 || !s2 || rawS1.length === 0 || s2.length === 0)
|
|
27493
29924
|
return undefined;
|
|
29925
|
+
const s1 = truncateSet1 ? rawS1.slice(0, s2.length) : rawS1;
|
|
29926
|
+
if (s1.length === 0)
|
|
29927
|
+
return input;
|
|
27494
29928
|
if (s1.length === 1 && s2.length === 1)
|
|
27495
29929
|
return input.split(s1[0]).join(s2[0]);
|
|
27496
29930
|
const map = new Map();
|
|
@@ -27684,7 +30118,7 @@ export class Runtime {
|
|
|
27684
30118
|
if (!sName || hasShellFunction(rawState, sName) || rawState.extensions?.builtins.has(sName))
|
|
27685
30119
|
return undefined;
|
|
27686
30120
|
const extDef = this.getExternalCommand(sName);
|
|
27687
|
-
if (!extDef || (sName !== "rev" && sName !== "tac" &&
|
|
30121
|
+
if (!extDef || (sName !== "rev" && sName !== "tac" && sName !== "nl" && sName !== "paste" && sName !== "jq" && !builtInDirectContextExecutors.has(extDef.execute)) || customRegisteredCommands.has(extDef.execute))
|
|
27688
30122
|
return undefined;
|
|
27689
30123
|
if (!this.arePureArgWords(sCmd.words, rawState))
|
|
27690
30124
|
return undefined;
|
|
@@ -27704,29 +30138,32 @@ export class Runtime {
|
|
|
27704
30138
|
return undefined;
|
|
27705
30139
|
}
|
|
27706
30140
|
else if (sName === "uniq") {
|
|
27707
|
-
if (
|
|
30141
|
+
if (this.evalSyncUniq([], sArgs) === undefined)
|
|
27708
30142
|
return undefined;
|
|
27709
30143
|
}
|
|
27710
30144
|
else if (sName === "sort") {
|
|
27711
|
-
if (
|
|
30145
|
+
if (this.evalSyncSort([], sArgs, byteLocale(rawState.variables)) === undefined)
|
|
27712
30146
|
return undefined;
|
|
27713
30147
|
}
|
|
27714
30148
|
else if (sName === "head" || sName === "tail") {
|
|
27715
30149
|
if (sArgs.length === 0) {
|
|
27716
30150
|
sArgs.push("-n", "10");
|
|
27717
30151
|
}
|
|
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);
|
|
30152
|
+
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])))) {
|
|
30153
|
+
const flag = (sArgs[0].startsWith("-c") || sArgs[0].startsWith("--bytes=")) ? "-c" : "-n";
|
|
30154
|
+
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
30155
|
sArgs.length = 0;
|
|
27722
30156
|
sArgs.push(flag, numStr);
|
|
27723
30157
|
}
|
|
27724
|
-
|
|
30158
|
+
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])));
|
|
30159
|
+
if (!validNum)
|
|
27725
30160
|
return undefined;
|
|
27726
30161
|
}
|
|
27727
30162
|
else if (sName === "wc") {
|
|
27728
|
-
|
|
30163
|
+
const normWc = sArgs.length === 1 ? this.normalizeSyncWcFlag(sArgs[0]) : undefined;
|
|
30164
|
+
if (!normWc)
|
|
27729
30165
|
return undefined;
|
|
30166
|
+
sArgs[0] = normWc;
|
|
27730
30167
|
}
|
|
27731
30168
|
else if (sName === "sed") {
|
|
27732
30169
|
if (this.evalSyncSed([], sArgs) === undefined)
|
|
@@ -27745,17 +30182,33 @@ export class Runtime {
|
|
|
27745
30182
|
return undefined;
|
|
27746
30183
|
}
|
|
27747
30184
|
else if (sName === "jq") {
|
|
27748
|
-
if (
|
|
30185
|
+
if (sArgs.length === 0 || sArgs.length > 2)
|
|
30186
|
+
return undefined;
|
|
30187
|
+
if (sArgs.length === 1 && sArgs[0].startsWith("-"))
|
|
30188
|
+
return undefined;
|
|
30189
|
+
if (sArgs.length === 2 && !["-r", "--raw-output", "-c", "--compact-output", "-rc", "-cr"].includes(sArgs[0]))
|
|
27749
30190
|
return undefined;
|
|
27750
30191
|
}
|
|
27751
30192
|
else if (sName === "base64") {
|
|
27752
30193
|
if (sArgs.length > 1 || (sArgs.length === 1 && sArgs[0] !== "-d" && sArgs[0] !== "--decode"))
|
|
27753
30194
|
return undefined;
|
|
27754
30195
|
}
|
|
27755
|
-
else if (sName === "tac"
|
|
30196
|
+
else if (sName === "tac") {
|
|
27756
30197
|
if (sArgs.length !== 0)
|
|
27757
30198
|
return undefined;
|
|
27758
30199
|
}
|
|
30200
|
+
else if (sName === "nl") {
|
|
30201
|
+
if (this.evalSyncNl([], sArgs) === undefined)
|
|
30202
|
+
return undefined;
|
|
30203
|
+
}
|
|
30204
|
+
else if (sName === "paste") {
|
|
30205
|
+
if (this.evalSyncPaste([], sArgs) === undefined)
|
|
30206
|
+
return undefined;
|
|
30207
|
+
}
|
|
30208
|
+
else if (sName === "numfmt") {
|
|
30209
|
+
if (this.evalSyncNumfmt([], sArgs) === undefined)
|
|
30210
|
+
return undefined;
|
|
30211
|
+
}
|
|
27759
30212
|
else {
|
|
27760
30213
|
return undefined;
|
|
27761
30214
|
}
|
|
@@ -27843,8 +30296,10 @@ export class Runtime {
|
|
|
27843
30296
|
const isInlineBase64 = firstName === "base64";
|
|
27844
30297
|
const isInlineTac = firstName === "tac";
|
|
27845
30298
|
const isInlineNl = firstName === "nl";
|
|
27846
|
-
const
|
|
27847
|
-
const
|
|
30299
|
+
const isInlinePaste = firstName === "paste";
|
|
30300
|
+
const isInlineNumfmt = firstName === "numfmt";
|
|
30301
|
+
const isInlineSort = firstName === "sort" && !byteLocale(rawState.variables);
|
|
30302
|
+
const isInlineUniq = firstName === "uniq";
|
|
27848
30303
|
const inlineSedMatch = firstName === "sed";
|
|
27849
30304
|
if (firstName === "rev" ||
|
|
27850
30305
|
firstName === "head" ||
|
|
@@ -27861,10 +30316,13 @@ export class Runtime {
|
|
|
27861
30316
|
isInlineJq ||
|
|
27862
30317
|
isInlineBase64 ||
|
|
27863
30318
|
isInlineTac ||
|
|
27864
|
-
isInlineNl
|
|
30319
|
+
isInlineNl ||
|
|
30320
|
+
isInlinePaste ||
|
|
30321
|
+
isInlineNumfmt) {
|
|
27865
30322
|
const inStr = prevLen === 0 ? "" : sharedSyncPipeDecoder.decode(prevBuf.subarray(0, prevLen));
|
|
27866
30323
|
const rawLines = inStr.length === 0 ? [] : (inStr.endsWith("\n") ? inStr.slice(0, -1).split("\n") : inStr.split("\n"));
|
|
27867
30324
|
let outLines = [];
|
|
30325
|
+
let sedTerminated = false;
|
|
27868
30326
|
if (firstName === "rev") {
|
|
27869
30327
|
outLines = rawLines.map(l => Array.from(l).reverse().join(""));
|
|
27870
30328
|
}
|
|
@@ -27883,7 +30341,16 @@ export class Runtime {
|
|
|
27883
30341
|
prevLen = sub.byteLength;
|
|
27884
30342
|
continue;
|
|
27885
30343
|
}
|
|
27886
|
-
|
|
30344
|
+
if (firstName === "tail" && stageArgs[1].startsWith("+")) {
|
|
30345
|
+
outLines = rawLines.slice(Math.max(0, count - 1));
|
|
30346
|
+
}
|
|
30347
|
+
else if (firstName === "head" && stageArgs[1].startsWith("-")) {
|
|
30348
|
+
const drop = Math.abs(count);
|
|
30349
|
+
outLines = drop === 0 ? [...rawLines] : rawLines.slice(0, Math.max(0, rawLines.length - drop));
|
|
30350
|
+
}
|
|
30351
|
+
else {
|
|
30352
|
+
outLines = firstName === "head" ? rawLines.slice(0, count) : (count === 0 ? [] : rawLines.slice(-count));
|
|
30353
|
+
}
|
|
27887
30354
|
}
|
|
27888
30355
|
else if (firstName === "wc") {
|
|
27889
30356
|
if (stageArgs[0] === "-l") {
|
|
@@ -27897,6 +30364,12 @@ export class Runtime {
|
|
|
27897
30364
|
const trimmed = inStr.trim();
|
|
27898
30365
|
outLines = [String(trimmed.length === 0 ? 0 : trimmed.split(/[ \t\n\r\f\v]+/).length)];
|
|
27899
30366
|
}
|
|
30367
|
+
else if (stageArgs[0] === "-m") {
|
|
30368
|
+
outLines = [String(byteLocale(rawState.variables) ? prevLen : Array.from(inStr).length)];
|
|
30369
|
+
}
|
|
30370
|
+
else if (stageArgs[0] === "-L") {
|
|
30371
|
+
outLines = [String(this.wcMaxLineWidth(inStr, byteLocale(rawState.variables)))];
|
|
30372
|
+
}
|
|
27900
30373
|
else {
|
|
27901
30374
|
outLines = [String(prevLen)];
|
|
27902
30375
|
}
|
|
@@ -27924,28 +30397,20 @@ export class Runtime {
|
|
|
27924
30397
|
continue;
|
|
27925
30398
|
}
|
|
27926
30399
|
else if (isInlineSort) {
|
|
27927
|
-
outLines = this.
|
|
30400
|
+
outLines = this.evalSyncSort(rawLines, stageArgs, false) ?? [];
|
|
27928
30401
|
}
|
|
27929
30402
|
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
|
-
}
|
|
30403
|
+
const uniqRes = this.evalSyncUniq(rawLines, stageArgs);
|
|
30404
|
+
if (uniqRes === undefined)
|
|
30405
|
+
return undefined;
|
|
30406
|
+
outLines = uniqRes;
|
|
27943
30407
|
}
|
|
27944
30408
|
else if (inlineSedMatch) {
|
|
27945
30409
|
const sedRes = this.evalSyncSed(rawLines, stageArgs);
|
|
27946
30410
|
if (sedRes === undefined)
|
|
27947
30411
|
return undefined;
|
|
27948
|
-
outLines = sedRes;
|
|
30412
|
+
outLines = sedRes.lines;
|
|
30413
|
+
sedTerminated = sedRes.lastInputIndex < rawLines.length - 1;
|
|
27949
30414
|
}
|
|
27950
30415
|
else if (isInlineAwk) {
|
|
27951
30416
|
const awkRes = this.evalSyncAwk(rawLines, stageArgs);
|
|
@@ -27968,17 +30433,22 @@ export class Runtime {
|
|
|
27968
30433
|
outLines = [...rawLines].reverse();
|
|
27969
30434
|
}
|
|
27970
30435
|
else if (isInlineNl) {
|
|
27971
|
-
|
|
27972
|
-
|
|
27973
|
-
|
|
27974
|
-
|
|
27975
|
-
|
|
27976
|
-
|
|
27977
|
-
|
|
27978
|
-
|
|
27979
|
-
|
|
27980
|
-
|
|
27981
|
-
|
|
30436
|
+
const nlRes = this.evalSyncNl(rawLines, stageArgs);
|
|
30437
|
+
if (nlRes === undefined)
|
|
30438
|
+
return undefined;
|
|
30439
|
+
outLines = nlRes;
|
|
30440
|
+
}
|
|
30441
|
+
else if (isInlinePaste) {
|
|
30442
|
+
const pasteRes = this.evalSyncPaste(rawLines, stageArgs);
|
|
30443
|
+
if (pasteRes === undefined)
|
|
30444
|
+
return undefined;
|
|
30445
|
+
outLines = pasteRes;
|
|
30446
|
+
}
|
|
30447
|
+
else if (isInlineNumfmt) {
|
|
30448
|
+
const nmRes = this.evalSyncNumfmt(rawLines, stageArgs);
|
|
30449
|
+
if (nmRes === undefined)
|
|
30450
|
+
return undefined;
|
|
30451
|
+
outLines = nmRes;
|
|
27982
30452
|
}
|
|
27983
30453
|
else if (isInlineBase64) {
|
|
27984
30454
|
if (stageArgs.length === 0) {
|
|
@@ -27990,7 +30460,7 @@ export class Runtime {
|
|
|
27990
30460
|
if (cleaned.length % 4 !== 0 || (cleaned.length > 0 && !/^[A-Za-z0-9+/]+={0,2}$/.test(cleaned)))
|
|
27991
30461
|
return undefined;
|
|
27992
30462
|
const decoded = this.syncBase64DecodeBytes(cleaned);
|
|
27993
|
-
if (decoded.
|
|
30463
|
+
if (decoded.some(byte => byte === 0 || byte >= 128) || decoded.byteLength > nextBuf.byteLength)
|
|
27994
30464
|
return undefined;
|
|
27995
30465
|
const nextTotalBytes = this.budget.bytes + decoded.byteLength;
|
|
27996
30466
|
if (nextTotalBytes > this.budget.maxOutputBytesSmi && decoded.byteLength > this.budget.limits.maxOutputBytes - this.budget.bytes)
|
|
@@ -28010,7 +30480,7 @@ export class Runtime {
|
|
|
28010
30480
|
}
|
|
28011
30481
|
// These filters preserve the terminator of the final selected input line.
|
|
28012
30482
|
const preservesTerminator = firstName === "head" || firstName === "tail" || firstName === "rev" || firstName === "sed";
|
|
28013
|
-
const terminated = !preservesTerminator || inStr.endsWith("\n") || firstName === "head" && outLines.length < rawLines.length;
|
|
30483
|
+
const terminated = sedTerminated || !preservesTerminator || inStr.endsWith("\n") || firstName === "head" && outLines.length < rawLines.length;
|
|
28014
30484
|
const outStr = outLines.length > 0 ? outLines.join("\n") + (terminated ? "\n" : "") : "";
|
|
28015
30485
|
const outByteLen = shellValueByteLength(outStr);
|
|
28016
30486
|
if (outByteLen > nextBuf.byteLength)
|
|
@@ -28175,8 +30645,8 @@ export class Runtime {
|
|
|
28175
30645
|
w0Plain === "sort" ||
|
|
28176
30646
|
w0Plain === "uniq" ||
|
|
28177
30647
|
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))))) {
|
|
30648
|
+
(hasSingleHereStringRedir && (w0Plain === "base64" || w0Plain === "rev" || w0Plain === "tac" || w0Plain === "nl" || w0Plain === "paste" || w0Plain === "numfmt"));
|
|
30649
|
+
if (isSingleFileTool && !hasShellFunction(rawState, w0Plain) && (this.commands.has(w0Plain) || ((w0Plain === "rev" || w0Plain === "tac" || w0Plain === "nl" || w0Plain === "paste") && Boolean(this.getExternalCommand(w0Plain))))) {
|
|
28180
30650
|
const allArgs = [];
|
|
28181
30651
|
let fOk = true;
|
|
28182
30652
|
for (let i = 1; i < cmd.words.length; i++) {
|
|
@@ -28216,6 +30686,12 @@ export class Runtime {
|
|
|
28216
30686
|
// Non-ASCII file inputs use normal execution, which owns their raw ShellValue.
|
|
28217
30687
|
if (view && view.byteLength <= 16384 && !view.includes(0) && (hasSingleHereStringRedir || view.every(byte => byte < 128))) {
|
|
28218
30688
|
const fileStr = hasSingleHereStringRedir ? hereStrVal : sharedSyncPipeDecoder.decode(view);
|
|
30689
|
+
// Record-based shortcuts below serialize complete newline-terminated records.
|
|
30690
|
+
// Let normal commands preserve partial final records when reading files.
|
|
30691
|
+
if (fileStr.length > 0 && !fileStr.endsWith("\n") &&
|
|
30692
|
+
(w0Plain === "head" || w0Plain === "tail" || w0Plain === "sed" || w0Plain === "cut" || w0Plain === "uniq"))
|
|
30693
|
+
return undefined;
|
|
30694
|
+
const renderLines = (lines) => lines.length === 0 ? "" : lines.join("\n") + "\n";
|
|
28219
30695
|
const rawLines = fileStr.endsWith("\n") ? fileStr.slice(0, -1).split("\n") : (fileStr.length === 0 ? [] : fileStr.split("\n"));
|
|
28220
30696
|
let fileRes;
|
|
28221
30697
|
let exitStatus = 0;
|
|
@@ -28225,19 +30701,36 @@ export class Runtime {
|
|
|
28225
30701
|
else if ((w0Plain === "head" || w0Plain === "tail") && opArgs.length <= 2) {
|
|
28226
30702
|
let count = opArgs.length === 0 ? 10 : undefined;
|
|
28227
30703
|
let byteCount;
|
|
28228
|
-
|
|
28229
|
-
|
|
28230
|
-
|
|
28231
|
-
|
|
30704
|
+
let countRaw = opArgs.length === 0 ? "10" : undefined;
|
|
30705
|
+
if (opArgs.length === 1 && (opArgs[0].startsWith("-n") || opArgs[0].startsWith("--lines="))) {
|
|
30706
|
+
const sub = opArgs[0].startsWith("--lines=") ? opArgs[0].slice(8) : opArgs[0].slice(2);
|
|
30707
|
+
if (/^[0-9]{1,5}$/.test(sub) || (w0Plain === "tail" && /^\+[0-9]{1,5}$/.test(sub)) || (w0Plain === "head" && /^-[0-9]{1,5}$/.test(sub)))
|
|
30708
|
+
countRaw = sub;
|
|
30709
|
+
}
|
|
30710
|
+
else if (opArgs.length === 1 && (opArgs[0].startsWith("-c") || opArgs[0].startsWith("--bytes="))) {
|
|
30711
|
+
const sub = opArgs[0].startsWith("--bytes=") ? opArgs[0].slice(8) : opArgs[0].slice(2);
|
|
30712
|
+
if (/^[0-9]{1,5}$/.test(sub))
|
|
30713
|
+
byteCount = Number(sub);
|
|
30714
|
+
}
|
|
28232
30715
|
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
|
-
|
|
30716
|
+
countRaw = opArgs[0].slice(1);
|
|
30717
|
+
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]))))
|
|
30718
|
+
countRaw = opArgs[1];
|
|
28236
30719
|
else if (opArgs.length === 2 && opArgs[0] === "-c" && /^[0-9]{1,5}$/.test(opArgs[1]))
|
|
28237
30720
|
byteCount = Number(opArgs[1]);
|
|
28238
|
-
if (
|
|
28239
|
-
|
|
28240
|
-
|
|
30721
|
+
if (countRaw !== undefined) {
|
|
30722
|
+
count = Number(countRaw);
|
|
30723
|
+
let sliced;
|
|
30724
|
+
if (w0Plain === "tail" && countRaw.startsWith("+"))
|
|
30725
|
+
sliced = rawLines.slice(Math.max(0, count - 1));
|
|
30726
|
+
else if (w0Plain === "head" && countRaw.startsWith("-")) {
|
|
30727
|
+
const drop = Math.abs(count);
|
|
30728
|
+
sliced = drop === 0 ? [...rawLines] : rawLines.slice(0, Math.max(0, rawLines.length - drop));
|
|
30729
|
+
}
|
|
30730
|
+
else {
|
|
30731
|
+
sliced = w0Plain === "head" ? rawLines.slice(0, count) : (count === 0 ? [] : rawLines.slice(-count));
|
|
30732
|
+
}
|
|
30733
|
+
fileRes = renderLines(sliced);
|
|
28241
30734
|
}
|
|
28242
30735
|
else if (byteCount !== undefined) {
|
|
28243
30736
|
const slicedBytes = w0Plain === "head"
|
|
@@ -28249,91 +30742,109 @@ export class Runtime {
|
|
|
28249
30742
|
else if (w0Plain === "jq") {
|
|
28250
30743
|
const jqRes = this.evalSyncJq(fileStr.trim(), opArgs);
|
|
28251
30744
|
if (jqRes !== undefined)
|
|
28252
|
-
fileRes = jqRes
|
|
30745
|
+
fileRes = renderLines(jqRes);
|
|
28253
30746
|
}
|
|
28254
30747
|
else if (w0Plain === "awk") {
|
|
28255
30748
|
const awkRes = this.evalSyncAwk(rawLines, opArgs);
|
|
28256
30749
|
if (awkRes !== undefined)
|
|
28257
|
-
fileRes = awkRes
|
|
30750
|
+
fileRes = renderLines(awkRes);
|
|
28258
30751
|
}
|
|
28259
30752
|
else if (w0Plain === "grep") {
|
|
28260
30753
|
const grepRes = this.evalSyncGrep(rawLines, opArgs, Boolean(rawState.errexit));
|
|
28261
30754
|
if (grepRes !== undefined) {
|
|
28262
30755
|
exitStatus = grepRes.status;
|
|
28263
|
-
fileRes = grepRes.lines
|
|
30756
|
+
fileRes = renderLines(grepRes.lines);
|
|
28264
30757
|
}
|
|
28265
30758
|
}
|
|
28266
30759
|
else if (w0Plain === "sed") {
|
|
28267
30760
|
const sedRes = this.evalSyncSed(rawLines, opArgs);
|
|
28268
30761
|
if (sedRes !== undefined)
|
|
28269
|
-
fileRes = sedRes.
|
|
30762
|
+
fileRes = renderLines(sedRes.lines);
|
|
28270
30763
|
}
|
|
28271
30764
|
else if (w0Plain === "cut") {
|
|
28272
30765
|
const cutRes = this.evalSyncCut(rawLines, opArgs, byteLocale(rawState.variables));
|
|
28273
30766
|
if (cutRes !== undefined)
|
|
28274
|
-
fileRes = cutRes
|
|
30767
|
+
fileRes = renderLines(cutRes);
|
|
28275
30768
|
}
|
|
28276
|
-
else if (w0Plain === "wc" && opArgs.length === 1 && (opArgs[0]
|
|
30769
|
+
else if (w0Plain === "wc" && opArgs.length === 1 && this.normalizeSyncWcFlag(opArgs[0]) !== undefined) {
|
|
30770
|
+
const wcMode = this.normalizeSyncWcFlag(opArgs[0]);
|
|
28277
30771
|
let count = 0;
|
|
28278
|
-
if (
|
|
30772
|
+
if (wcMode === "-l") {
|
|
28279
30773
|
for (let k = 0; k < view.byteLength; k++)
|
|
28280
30774
|
if (view[k] === 10)
|
|
28281
30775
|
count++;
|
|
28282
30776
|
}
|
|
28283
|
-
else if (
|
|
30777
|
+
else if (wcMode === "-c") {
|
|
28284
30778
|
count = view.byteLength;
|
|
28285
30779
|
}
|
|
30780
|
+
else if (wcMode === "-m") {
|
|
30781
|
+
count = byteLocale(rawState.variables) ? view.byteLength : Array.from(fileStr).length;
|
|
30782
|
+
}
|
|
30783
|
+
else if (wcMode === "-L") {
|
|
30784
|
+
count = this.wcMaxLineWidth(fileStr, byteLocale(rawState.variables));
|
|
30785
|
+
}
|
|
28286
30786
|
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;
|
|
30787
|
+
// Unicode word separators depend on locale and POSIXLY_CORRECT.
|
|
30788
|
+
// Use the maintained command for those inputs rather than JS whitespace.
|
|
30789
|
+
if (!byteLocale(rawState.variables) && view.some(byte => byte > 127))
|
|
30790
|
+
return undefined;
|
|
30791
|
+
count = fileStr.split(/[ \t\n\r\f\v]+/).filter(Boolean).length;
|
|
28308
30792
|
}
|
|
28309
|
-
fileRes =
|
|
30793
|
+
fileRes = ((hasSingleStdinRedir || hasSingleHereStringRedir) ? String(count) : `${count} ${fileArg}`) + "\n";
|
|
30794
|
+
}
|
|
30795
|
+
else if (w0Plain === "sort" && !byteLocale(rawState.variables)) {
|
|
30796
|
+
const sortRes = this.evalSyncSort(rawLines, opArgs, false);
|
|
30797
|
+
if (sortRes !== undefined)
|
|
30798
|
+
fileRes = renderLines(sortRes);
|
|
30799
|
+
}
|
|
30800
|
+
else if (w0Plain === "uniq") {
|
|
30801
|
+
const uniqRes = this.evalSyncUniq(rawLines, opArgs);
|
|
30802
|
+
if (uniqRes !== undefined)
|
|
30803
|
+
fileRes = renderLines(uniqRes);
|
|
28310
30804
|
}
|
|
28311
30805
|
else if (w0Plain === "tr" && (hasSingleStdinRedir || hasSingleHereStringRedir)) {
|
|
28312
30806
|
fileRes = this.evalSyncTr(fileStr, opArgs);
|
|
28313
30807
|
}
|
|
28314
30808
|
else if (hasSingleHereStringRedir && w0Plain === "base64" && (opArgs.length === 0 || (opArgs.length === 1 && (opArgs[0] === "-d" || opArgs[0] === "--decode")))) {
|
|
28315
30809
|
if (opArgs.length === 0)
|
|
28316
|
-
fileRes = this.syncBase64Encode(view);
|
|
28317
|
-
else
|
|
28318
|
-
|
|
30810
|
+
fileRes = this.syncBase64Encode(view) + "\n";
|
|
30811
|
+
else {
|
|
30812
|
+
const decoded = this.syncBase64DecodeBytes(fileStr);
|
|
30813
|
+
// Text-only substitutions cannot retain binary byte provenance.
|
|
30814
|
+
if (decoded.some(byte => byte === 0 || byte >= 128))
|
|
30815
|
+
return undefined;
|
|
30816
|
+
fileRes = sharedSyncPipeDecoder.decode(decoded);
|
|
30817
|
+
}
|
|
28319
30818
|
}
|
|
28320
30819
|
else if (hasSingleHereStringRedir && w0Plain === "rev" && opArgs.length === 0) {
|
|
28321
|
-
fileRes = rawLines.map(l => Array.from(l).reverse().join(""))
|
|
30820
|
+
fileRes = renderLines(rawLines.map(l => Array.from(l).reverse().join("")));
|
|
28322
30821
|
}
|
|
28323
30822
|
else if (hasSingleHereStringRedir && w0Plain === "tac" && opArgs.length === 0) {
|
|
28324
|
-
fileRes = [...rawLines].reverse()
|
|
30823
|
+
fileRes = renderLines([...rawLines].reverse());
|
|
28325
30824
|
}
|
|
28326
|
-
else if (hasSingleHereStringRedir && w0Plain === "nl"
|
|
28327
|
-
|
|
28328
|
-
|
|
30825
|
+
else if (hasSingleHereStringRedir && w0Plain === "nl") {
|
|
30826
|
+
const nlRes = this.evalSyncNl(rawLines, opArgs);
|
|
30827
|
+
if (nlRes !== undefined)
|
|
30828
|
+
fileRes = renderLines(nlRes);
|
|
30829
|
+
}
|
|
30830
|
+
else if (hasSingleHereStringRedir && w0Plain === "paste") {
|
|
30831
|
+
const pasteRes = this.evalSyncPaste(rawLines, opArgs);
|
|
30832
|
+
if (pasteRes !== undefined)
|
|
30833
|
+
fileRes = renderLines(pasteRes);
|
|
30834
|
+
}
|
|
30835
|
+
else if (hasSingleHereStringRedir && w0Plain === "numfmt") {
|
|
30836
|
+
const nmRes = this.evalSyncNumfmt(rawLines, opArgs);
|
|
30837
|
+
if (nmRes !== undefined)
|
|
30838
|
+
fileRes = renderLines(nmRes);
|
|
28329
30839
|
}
|
|
28330
30840
|
if (fileRes !== undefined) {
|
|
30841
|
+
// Charge emitted bytes before substitution removes trailing newlines.
|
|
30842
|
+
const outBytes = shellValueByteLength(fileRes);
|
|
28331
30843
|
let end = fileRes.length;
|
|
28332
30844
|
while (end > 0 && fileRes.charCodeAt(end - 1) === 10)
|
|
28333
30845
|
end--;
|
|
28334
30846
|
if (end < fileRes.length)
|
|
28335
30847
|
fileRes = fileRes.slice(0, end);
|
|
28336
|
-
const outBytes = (fileRes.length * 3 > 127 ? shellValueByteLength(fileRes) : fileRes.length) + 1;
|
|
28337
30848
|
const nextTotalBytes = this.budget.bytes + outBytes;
|
|
28338
30849
|
if (nextTotalBytes > this.budget.maxOutputBytesSmi && outBytes > this.budget.limits.maxOutputBytes - this.budget.bytes)
|
|
28339
30850
|
this.budget.fail("maxOutputBytes");
|
|
@@ -28435,46 +30946,17 @@ export class Runtime {
|
|
|
28435
30946
|
if (!this.isPureArgWord(cmd.words[i], rawState))
|
|
28436
30947
|
return undefined;
|
|
28437
30948
|
}
|
|
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"))
|
|
30949
|
+
if (w0Plain === "dirname" || w0Plain === "basename") {
|
|
30950
|
+
const dbArgs = [];
|
|
30951
|
+
for (let i = 1; i < cmd.words.length; i++) {
|
|
30952
|
+
const v = this.fastValueWord(cmd.words[i], state, io, true, false, false, true, undefined, part.line);
|
|
30953
|
+
if (typeof v !== "string")
|
|
28472
30954
|
return undefined;
|
|
28473
|
-
|
|
30955
|
+
dbArgs.push(v);
|
|
28474
30956
|
}
|
|
28475
|
-
let res =
|
|
28476
|
-
if (
|
|
28477
|
-
|
|
30957
|
+
let res = w0Plain === "dirname" ? this.evalSyncDirname(dbArgs) : this.evalSyncBasename(dbArgs);
|
|
30958
|
+
if (res === undefined)
|
|
30959
|
+
return undefined;
|
|
28478
30960
|
const byteLength = shellValueByteLength(res) + 1;
|
|
28479
30961
|
while (res.endsWith("\n"))
|
|
28480
30962
|
res = res.slice(0, -1);
|