shell-dsl 0.0.36 → 0.0.38
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 +4 -3
- package/dist/cjs/index.cjs +2 -1
- package/dist/cjs/index.cjs.map +3 -3
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/src/commands/echo/echo.cjs +29 -23
- package/dist/cjs/src/commands/echo/echo.cjs.map +3 -3
- package/dist/cjs/src/commands/find/find.cjs +27 -11
- package/dist/cjs/src/commands/find/find.cjs.map +3 -3
- package/dist/cjs/src/commands/index.cjs +6 -2
- package/dist/cjs/src/commands/index.cjs.map +3 -3
- package/dist/cjs/src/commands/od/od.cjs +274 -0
- package/dist/cjs/src/commands/od/od.cjs.map +10 -0
- package/dist/cjs/src/commands/tree/tree.cjs +15 -8
- package/dist/cjs/src/commands/tree/tree.cjs.map +3 -3
- package/dist/mjs/index.mjs +4 -2
- package/dist/mjs/index.mjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/src/commands/echo/echo.mjs +29 -23
- package/dist/mjs/src/commands/echo/echo.mjs.map +3 -3
- package/dist/mjs/src/commands/find/find.mjs +27 -11
- package/dist/mjs/src/commands/find/find.mjs.map +3 -3
- package/dist/mjs/src/commands/index.mjs +6 -2
- package/dist/mjs/src/commands/index.mjs.map +3 -3
- package/dist/mjs/src/commands/od/od.mjs +234 -0
- package/dist/mjs/src/commands/od/od.mjs.map +10 -0
- package/dist/mjs/src/commands/tree/tree.mjs +15 -8
- package/dist/mjs/src/commands/tree/tree.mjs.map +3 -3
- package/dist/types/index.d.ts +1 -1
- package/dist/types/src/commands/index.d.ts +1 -0
- package/dist/types/src/commands/od/od.d.ts +2 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/commands/find/find.ts
|
|
2
2
|
import { matchGlob } from "../../utils/match-glob.mjs";
|
|
3
|
-
async function evalExpr(expr, basename, isFile, isDir, entryPath, ctx) {
|
|
3
|
+
async function evalExpr(expr, basename, isFile, isDir, entryPath, ctx, runActions) {
|
|
4
4
|
switch (expr.type) {
|
|
5
5
|
case "true":
|
|
6
6
|
return true;
|
|
@@ -9,23 +9,32 @@ async function evalExpr(expr, basename, isFile, isDir, entryPath, ctx) {
|
|
|
9
9
|
case "ftype":
|
|
10
10
|
return expr.value === "f" ? isFile : isDir;
|
|
11
11
|
case "and": {
|
|
12
|
-
const leftResult = await evalExpr(expr.left, basename, isFile, isDir, entryPath, ctx);
|
|
12
|
+
const leftResult = await evalExpr(expr.left, basename, isFile, isDir, entryPath, ctx, runActions);
|
|
13
13
|
if (!leftResult)
|
|
14
14
|
return false;
|
|
15
|
-
return evalExpr(expr.right, basename, isFile, isDir, entryPath, ctx);
|
|
15
|
+
return evalExpr(expr.right, basename, isFile, isDir, entryPath, ctx, runActions);
|
|
16
16
|
}
|
|
17
17
|
case "or": {
|
|
18
|
-
const leftResult = await evalExpr(expr.left, basename, isFile, isDir, entryPath, ctx);
|
|
18
|
+
const leftResult = await evalExpr(expr.left, basename, isFile, isDir, entryPath, ctx, runActions);
|
|
19
19
|
if (leftResult)
|
|
20
20
|
return true;
|
|
21
|
-
return evalExpr(expr.right, basename, isFile, isDir, entryPath, ctx);
|
|
21
|
+
return evalExpr(expr.right, basename, isFile, isDir, entryPath, ctx, runActions);
|
|
22
22
|
}
|
|
23
23
|
case "not":
|
|
24
|
-
return !await evalExpr(expr.expr, basename, isFile, isDir, entryPath, ctx);
|
|
24
|
+
return !await evalExpr(expr.expr, basename, isFile, isDir, entryPath, ctx, runActions);
|
|
25
|
+
case "print":
|
|
26
|
+
if (runActions) {
|
|
27
|
+
await ctx.stdout.writeText(entryPath + `
|
|
28
|
+
`);
|
|
29
|
+
}
|
|
30
|
+
return true;
|
|
25
31
|
case "exec": {
|
|
26
32
|
if (expr.batchMode) {
|
|
27
33
|
return true;
|
|
28
34
|
}
|
|
35
|
+
if (!runActions) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
29
38
|
if (!ctx.exec) {
|
|
30
39
|
await ctx.stderr.writeText(`find: -exec not supported (no exec capability)
|
|
31
40
|
`);
|
|
@@ -45,6 +54,7 @@ async function evalExpr(expr, basename, isFile, isDir, entryPath, ctx) {
|
|
|
45
54
|
}
|
|
46
55
|
function hasActionExpr(expr) {
|
|
47
56
|
switch (expr.type) {
|
|
57
|
+
case "print":
|
|
48
58
|
case "exec":
|
|
49
59
|
return true;
|
|
50
60
|
case "and":
|
|
@@ -183,6 +193,10 @@ function parseExprArgs(args) {
|
|
|
183
193
|
}
|
|
184
194
|
return { type: "exec", cmdName, cmdArgs, batchMode };
|
|
185
195
|
}
|
|
196
|
+
if (tok === "-print") {
|
|
197
|
+
advance();
|
|
198
|
+
return { type: "print" };
|
|
199
|
+
}
|
|
186
200
|
throw new ParseError(`find: unknown predicate '${tok}'`);
|
|
187
201
|
}
|
|
188
202
|
const expr = parseOr();
|
|
@@ -281,8 +295,9 @@ var find = async (ctx) => {
|
|
|
281
295
|
const isDir = entryStat.isDirectory();
|
|
282
296
|
const isFile = entryStat.isFile();
|
|
283
297
|
const basename = ctx.fs.basename(path);
|
|
284
|
-
const
|
|
285
|
-
|
|
298
|
+
const meetsMinDepth = minDepth === undefined || depth >= minDepth;
|
|
299
|
+
const matches = await evalExpr(expr, basename, isFile, isDir, displayPath, ctx, meetsMinDepth);
|
|
300
|
+
if (matches && meetsMinDepth) {
|
|
286
301
|
if (batchExecNodes.length > 0) {
|
|
287
302
|
batchPaths.push(displayPath);
|
|
288
303
|
} else if (!hasAction) {
|
|
@@ -304,8 +319,9 @@ var find = async (ctx) => {
|
|
|
304
319
|
}
|
|
305
320
|
if (stat.isFile()) {
|
|
306
321
|
const basename = ctx.fs.basename(resolvedStart);
|
|
307
|
-
const
|
|
308
|
-
|
|
322
|
+
const meetsMinDepth = minDepth === undefined || minDepth <= 0;
|
|
323
|
+
const matches = await evalExpr(expr, basename, true, false, normalizedPath, ctx, meetsMinDepth);
|
|
324
|
+
if (maxDepth !== undefined && maxDepth < 0) {} else if (matches && meetsMinDepth) {
|
|
309
325
|
if (batchExecNodes.length > 0) {
|
|
310
326
|
batchPaths.push(normalizedPath);
|
|
311
327
|
} else if (!hasAction) {
|
|
@@ -342,4 +358,4 @@ export {
|
|
|
342
358
|
find
|
|
343
359
|
};
|
|
344
360
|
|
|
345
|
-
//# debugId=
|
|
361
|
+
//# debugId=10955D1C374A7D0364756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/commands/find/find.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import type { Command, CommandContext, ExecResult } from \"../../types.mjs\";\nimport { matchGlob } from \"../../utils/match-glob.mjs\";\n\n// Expression tree types\ntype FindExpr =\n | { type: \"name\"; pattern: string; ignoreCase: boolean }\n | { type: \"ftype\"; value: \"f\" | \"d\" }\n | { type: \"and\"; left: FindExpr; right: FindExpr }\n | { type: \"or\"; left: FindExpr; right: FindExpr }\n | { type: \"not\"; expr: FindExpr }\n | { type: \"true\" }\n | { type: \"exec\"; cmdName: string; cmdArgs: string[]; batchMode: boolean };\n\nasync function evalExpr(\n expr: FindExpr,\n basename: string,\n isFile: boolean,\n isDir: boolean,\n entryPath: string,\n ctx: CommandContext,\n): Promise<boolean> {\n switch (expr.type) {\n case \"true\":\n return true;\n case \"name\":\n return matchGlob(expr.pattern, basename, expr.ignoreCase);\n case \"ftype\":\n return expr.value === \"f\" ? isFile : isDir;\n case \"and\": {\n const leftResult = await evalExpr(expr.left, basename, isFile, isDir, entryPath, ctx);\n if (!leftResult) return false;\n return evalExpr(expr.right, basename, isFile, isDir, entryPath, ctx);\n }\n case \"or\": {\n const leftResult = await evalExpr(expr.left, basename, isFile, isDir, entryPath, ctx);\n if (leftResult) return true;\n return evalExpr(expr.right, basename, isFile, isDir, entryPath, ctx);\n }\n case \"not\":\n return !(await evalExpr(expr.expr, basename, isFile, isDir, entryPath, ctx));\n case \"exec\": {\n if (expr.batchMode) {\n // In batch mode, always return true during traversal; paths are collected externally\n return true;\n }\n // Per-file mode: execute command with {} replaced by entryPath\n if (!ctx.exec) {\n await ctx.stderr.writeText(\"find: -exec not supported (no exec capability)\\n\");\n return false;\n }\n const resolvedArgs = expr.cmdArgs.map(a => a === \"{}\" ? entryPath : a);\n const result: ExecResult = await ctx.exec(expr.cmdName, resolvedArgs);\n // Pass stdout/stderr through to find's streams\n if (result.stdout.length > 0) {\n await ctx.stdout.write(result.stdout);\n }\n if (result.stderr.length > 0) {\n await ctx.stderr.write(result.stderr);\n }\n return result.exitCode === 0;\n }\n }\n}\n\n/** Check if expression tree contains any -exec node */\nfunction hasActionExpr(expr: FindExpr): boolean {\n switch (expr.type) {\n case \"exec\":\n return true;\n case \"and\":\n case \"or\":\n return hasActionExpr(expr.left) || hasActionExpr(expr.right);\n case \"not\":\n return hasActionExpr(expr.expr);\n default:\n return false;\n }\n}\n\n/** Collect all batch-mode -exec nodes from the expression tree */\nfunction collectBatchExecNodes(expr: FindExpr): Array<{ type: \"exec\"; cmdName: string; cmdArgs: string[]; batchMode: boolean }> {\n switch (expr.type) {\n case \"exec\":\n return expr.batchMode ? [expr] : [];\n case \"and\":\n case \"or\":\n return [...collectBatchExecNodes(expr.left), ...collectBatchExecNodes(expr.right)];\n case \"not\":\n return collectBatchExecNodes(expr.expr);\n default:\n return [];\n }\n}\n\nclass ParseError extends Error {\n constructor(msg: string) {\n super(msg);\n }\n}\n\nfunction parseExprArgs(args: string[]): FindExpr {\n if (args.length === 0) return { type: \"true\" };\n\n let pos = 0;\n\n function peek(): string | undefined {\n return args[pos];\n }\n\n function advance(): string {\n return args[pos++]!;\n }\n\n function parseOr(): FindExpr {\n let left = parseAnd();\n while (peek() === \"-o\") {\n advance();\n const right = parseAnd();\n left = { type: \"or\", left, right };\n }\n return left;\n }\n\n function parseAnd(): FindExpr {\n let left = parseUnary();\n while (pos < args.length) {\n const next = peek();\n if (next === \"-o\" || next === \")\" || next === undefined) break;\n if (next === \"-a\") {\n advance();\n }\n const right = parseUnary();\n left = { type: \"and\", left, right };\n }\n return left;\n }\n\n function parseUnary(): FindExpr {\n const next = peek();\n if (next === \"!\" || next === \"-not\") {\n advance();\n const expr = parseUnary();\n return { type: \"not\", expr };\n }\n return parsePrimary();\n }\n\n function parsePrimary(): FindExpr {\n const tok = peek();\n if (tok === undefined) {\n throw new ParseError(\"find: expected expression\");\n }\n\n if (tok === \"(\") {\n advance();\n const expr = parseOr();\n if (peek() !== \")\") {\n throw new ParseError(\"find: missing closing ')'\");\n }\n advance();\n return expr;\n }\n\n if (tok === \"-name\" || tok === \"-iname\") {\n advance();\n const pattern = peek();\n if (pattern === undefined) {\n throw new ParseError(`find: missing argument to '${tok}'`);\n }\n advance();\n return { type: \"name\", pattern, ignoreCase: tok === \"-iname\" };\n }\n\n if (tok === \"-type\") {\n advance();\n const val = peek();\n if (val === undefined) {\n throw new ParseError(\"find: missing argument to '-type'\");\n }\n if (val !== \"f\" && val !== \"d\") {\n throw new ParseError(`find: Unknown argument to -type: ${val}`);\n }\n advance();\n return { type: \"ftype\", value: val };\n }\n\n if (tok === \"-exec\") {\n advance();\n const cmdName = peek();\n if (cmdName === undefined || cmdName === \";\" || cmdName === \"+\") {\n throw new ParseError(\"find: -exec: missing command\");\n }\n advance();\n\n const cmdArgs: string[] = [];\n let batchMode = false;\n let foundTerminator = false;\n\n while (pos < args.length) {\n const a = args[pos]!;\n if (a === \";\") {\n advance();\n foundTerminator = true;\n break;\n }\n if (a === \"+\") {\n advance();\n batchMode = true;\n foundTerminator = true;\n break;\n }\n cmdArgs.push(a);\n advance();\n }\n\n if (!foundTerminator) {\n throw new ParseError(\"find: -exec: missing terminator (';' or '+')\");\n }\n\n return { type: \"exec\", cmdName, cmdArgs, batchMode };\n }\n\n throw new ParseError(`find: unknown predicate '${tok}'`);\n }\n\n const expr = parseOr();\n if (pos < args.length) {\n throw new ParseError(`find: unexpected '${args[pos]}'`);\n }\n return expr;\n}\n\nexport const find: Command = async (ctx) => {\n const args = [...ctx.args];\n const paths: string[] = [];\n\n // Parse arguments: paths come before first flag/operator\n let i = 0;\n\n // Collect paths (args before first -, !, or ()\n while (i < args.length && !args[i]!.startsWith(\"-\") && args[i] !== \"!\" && args[i] !== \"(\" && args[i] !== \")\") {\n paths.push(args[i]!);\n i++;\n }\n\n // Default to current directory if no paths\n if (paths.length === 0) {\n paths.push(\".\");\n }\n\n // Extract global options (-maxdepth, -mindepth) from remaining args\n let maxDepth: number | undefined;\n let minDepth: number | undefined;\n const exprArgs: string[] = [];\n\n let j = i;\n while (j < args.length) {\n const arg = args[j]!;\n if (arg === \"-maxdepth\") {\n j++;\n if (j >= args.length) {\n await ctx.stderr.writeText(\"find: missing argument to '-maxdepth'\\n\");\n return 1;\n }\n const depth = parseInt(args[j]!, 10);\n if (isNaN(depth) || depth < 0) {\n await ctx.stderr.writeText(`find: Invalid argument '${args[j]}' to -maxdepth\\n`);\n return 1;\n }\n maxDepth = depth;\n } else if (arg === \"-mindepth\") {\n j++;\n if (j >= args.length) {\n await ctx.stderr.writeText(\"find: missing argument to '-mindepth'\\n\");\n return 1;\n }\n const depth = parseInt(args[j]!, 10);\n if (isNaN(depth) || depth < 0) {\n await ctx.stderr.writeText(`find: Invalid argument '${args[j]}' to -mindepth\\n`);\n return 1;\n }\n minDepth = depth;\n } else {\n exprArgs.push(arg);\n }\n j++;\n }\n\n // Parse expression tree\n let expr: FindExpr;\n try {\n expr = parseExprArgs(exprArgs);\n } catch (e) {\n if (e instanceof ParseError) {\n await ctx.stderr.writeText(e.message + \"\\n\");\n return 1;\n }\n throw e;\n }\n\n const hasAction = hasActionExpr(expr);\n const batchExecNodes = collectBatchExecNodes(expr);\n const batchPaths: string[] = [];\n\n let hasError = false;\n\n // Process each starting path\n for (const startPath of paths) {\n const normalizedPath = startPath === \"/\" ? \"/\" : startPath.replace(/\\/+$/, '');\n const resolvedStart = ctx.fs.resolve(ctx.cwd, startPath);\n\n // Check if path exists\n let stat;\n try {\n stat = await ctx.fs.stat(resolvedStart);\n } catch {\n await ctx.stderr.writeText(`find: '${startPath}': No such file or directory\\n`);\n hasError = true;\n continue;\n }\n\n // Recursive traversal function\n async function traverse(path: string, displayPath: string, depth: number): Promise<void> {\n // Check maxdepth\n if (maxDepth !== undefined && depth > maxDepth) {\n return;\n }\n\n let entryStat;\n try {\n entryStat = await ctx.fs.stat(path);\n } catch {\n return;\n }\n\n const isDir = entryStat.isDirectory();\n const isFile = entryStat.isFile();\n const basename = ctx.fs.basename(path);\n\n // Check if this entry matches the expression\n const matches = await evalExpr(expr, basename, isFile, isDir, displayPath, ctx);\n\n if (matches && (minDepth === undefined || depth >= minDepth)) {\n if (batchExecNodes.length > 0) {\n batchPaths.push(displayPath);\n } else if (!hasAction) {\n // No action expressions: default print behavior\n await ctx.stdout.writeText(displayPath + \"\\n\");\n }\n // If has per-file -exec actions, output was already handled in evalExpr\n }\n\n // Recurse into directories\n if (isDir) {\n try {\n const entries = await ctx.fs.readdir(path);\n entries.sort();\n for (const entry of entries) {\n const childPath = ctx.fs.resolve(path, entry);\n const childDisplayPath = displayPath === \".\" ? entry : `${displayPath}/${entry}`;\n await traverse(childPath, childDisplayPath, depth + 1);\n }\n } catch {\n // Ignore errors reading directory contents\n }\n }\n }\n\n // Start traversal\n if (stat.isFile()) {\n const basename = ctx.fs.basename(resolvedStart);\n const matches = await evalExpr(expr, basename, true, false, normalizedPath, ctx);\n\n if (maxDepth !== undefined && maxDepth < 0) {\n // skip\n } else if (matches && (minDepth === undefined || minDepth <= 0)) {\n if (batchExecNodes.length > 0) {\n batchPaths.push(normalizedPath);\n } else if (!hasAction) {\n await ctx.stdout.writeText(normalizedPath + \"\\n\");\n }\n }\n } else {\n await traverse(resolvedStart, normalizedPath, 0);\n }\n }\n\n // Execute batch -exec nodes with all collected paths\n if (batchExecNodes.length > 0 && batchPaths.length > 0 && ctx.exec) {\n for (const node of batchExecNodes) {\n // Replace {} in cmdArgs with all paths\n const resolvedArgs: string[] = [];\n for (const a of node.cmdArgs) {\n if (a === \"{}\") {\n resolvedArgs.push(...batchPaths);\n } else {\n resolvedArgs.push(a);\n }\n }\n const result = await ctx.exec(node.cmdName, resolvedArgs);\n if (result.stdout.length > 0) {\n await ctx.stdout.write(result.stdout);\n }\n if (result.stderr.length > 0) {\n await ctx.stderr.write(result.stderr);\n }\n }\n }\n\n return hasError ? 1 : 0;\n};\n"
|
|
5
|
+
"import type { Command, CommandContext, ExecResult } from \"../../types.mjs\";\nimport { matchGlob } from \"../../utils/match-glob.mjs\";\n\n// Expression tree types\ntype FindExpr =\n | { type: \"name\"; pattern: string; ignoreCase: boolean }\n | { type: \"ftype\"; value: \"f\" | \"d\" }\n | { type: \"and\"; left: FindExpr; right: FindExpr }\n | { type: \"or\"; left: FindExpr; right: FindExpr }\n | { type: \"not\"; expr: FindExpr }\n | { type: \"true\" }\n | { type: \"print\" }\n | { type: \"exec\"; cmdName: string; cmdArgs: string[]; batchMode: boolean };\n\nasync function evalExpr(\n expr: FindExpr,\n basename: string,\n isFile: boolean,\n isDir: boolean,\n entryPath: string,\n ctx: CommandContext,\n runActions: boolean,\n): Promise<boolean> {\n switch (expr.type) {\n case \"true\":\n return true;\n case \"name\":\n return matchGlob(expr.pattern, basename, expr.ignoreCase);\n case \"ftype\":\n return expr.value === \"f\" ? isFile : isDir;\n case \"and\": {\n const leftResult = await evalExpr(expr.left, basename, isFile, isDir, entryPath, ctx, runActions);\n if (!leftResult) return false;\n return evalExpr(expr.right, basename, isFile, isDir, entryPath, ctx, runActions);\n }\n case \"or\": {\n const leftResult = await evalExpr(expr.left, basename, isFile, isDir, entryPath, ctx, runActions);\n if (leftResult) return true;\n return evalExpr(expr.right, basename, isFile, isDir, entryPath, ctx, runActions);\n }\n case \"not\":\n return !(await evalExpr(expr.expr, basename, isFile, isDir, entryPath, ctx, runActions));\n case \"print\":\n if (runActions) {\n await ctx.stdout.writeText(entryPath + \"\\n\");\n }\n return true;\n case \"exec\": {\n if (expr.batchMode) {\n // In batch mode, always return true during traversal; paths are collected externally\n return true;\n }\n if (!runActions) {\n return true;\n }\n // Per-file mode: execute command with {} replaced by entryPath\n if (!ctx.exec) {\n await ctx.stderr.writeText(\"find: -exec not supported (no exec capability)\\n\");\n return false;\n }\n const resolvedArgs = expr.cmdArgs.map(a => a === \"{}\" ? entryPath : a);\n const result: ExecResult = await ctx.exec(expr.cmdName, resolvedArgs);\n // Pass stdout/stderr through to find's streams\n if (result.stdout.length > 0) {\n await ctx.stdout.write(result.stdout);\n }\n if (result.stderr.length > 0) {\n await ctx.stderr.write(result.stderr);\n }\n return result.exitCode === 0;\n }\n }\n}\n\n/** Check if expression tree contains any -exec node */\nfunction hasActionExpr(expr: FindExpr): boolean {\n switch (expr.type) {\n case \"print\":\n case \"exec\":\n return true;\n case \"and\":\n case \"or\":\n return hasActionExpr(expr.left) || hasActionExpr(expr.right);\n case \"not\":\n return hasActionExpr(expr.expr);\n default:\n return false;\n }\n}\n\n/** Collect all batch-mode -exec nodes from the expression tree */\nfunction collectBatchExecNodes(expr: FindExpr): Array<{ type: \"exec\"; cmdName: string; cmdArgs: string[]; batchMode: boolean }> {\n switch (expr.type) {\n case \"exec\":\n return expr.batchMode ? [expr] : [];\n case \"and\":\n case \"or\":\n return [...collectBatchExecNodes(expr.left), ...collectBatchExecNodes(expr.right)];\n case \"not\":\n return collectBatchExecNodes(expr.expr);\n default:\n return [];\n }\n}\n\nclass ParseError extends Error {\n constructor(msg: string) {\n super(msg);\n }\n}\n\nfunction parseExprArgs(args: string[]): FindExpr {\n if (args.length === 0) return { type: \"true\" };\n\n let pos = 0;\n\n function peek(): string | undefined {\n return args[pos];\n }\n\n function advance(): string {\n return args[pos++]!;\n }\n\n function parseOr(): FindExpr {\n let left = parseAnd();\n while (peek() === \"-o\") {\n advance();\n const right = parseAnd();\n left = { type: \"or\", left, right };\n }\n return left;\n }\n\n function parseAnd(): FindExpr {\n let left = parseUnary();\n while (pos < args.length) {\n const next = peek();\n if (next === \"-o\" || next === \")\" || next === undefined) break;\n if (next === \"-a\") {\n advance();\n }\n const right = parseUnary();\n left = { type: \"and\", left, right };\n }\n return left;\n }\n\n function parseUnary(): FindExpr {\n const next = peek();\n if (next === \"!\" || next === \"-not\") {\n advance();\n const expr = parseUnary();\n return { type: \"not\", expr };\n }\n return parsePrimary();\n }\n\n function parsePrimary(): FindExpr {\n const tok = peek();\n if (tok === undefined) {\n throw new ParseError(\"find: expected expression\");\n }\n\n if (tok === \"(\") {\n advance();\n const expr = parseOr();\n if (peek() !== \")\") {\n throw new ParseError(\"find: missing closing ')'\");\n }\n advance();\n return expr;\n }\n\n if (tok === \"-name\" || tok === \"-iname\") {\n advance();\n const pattern = peek();\n if (pattern === undefined) {\n throw new ParseError(`find: missing argument to '${tok}'`);\n }\n advance();\n return { type: \"name\", pattern, ignoreCase: tok === \"-iname\" };\n }\n\n if (tok === \"-type\") {\n advance();\n const val = peek();\n if (val === undefined) {\n throw new ParseError(\"find: missing argument to '-type'\");\n }\n if (val !== \"f\" && val !== \"d\") {\n throw new ParseError(`find: Unknown argument to -type: ${val}`);\n }\n advance();\n return { type: \"ftype\", value: val };\n }\n\n if (tok === \"-exec\") {\n advance();\n const cmdName = peek();\n if (cmdName === undefined || cmdName === \";\" || cmdName === \"+\") {\n throw new ParseError(\"find: -exec: missing command\");\n }\n advance();\n\n const cmdArgs: string[] = [];\n let batchMode = false;\n let foundTerminator = false;\n\n while (pos < args.length) {\n const a = args[pos]!;\n if (a === \";\") {\n advance();\n foundTerminator = true;\n break;\n }\n if (a === \"+\") {\n advance();\n batchMode = true;\n foundTerminator = true;\n break;\n }\n cmdArgs.push(a);\n advance();\n }\n\n if (!foundTerminator) {\n throw new ParseError(\"find: -exec: missing terminator (';' or '+')\");\n }\n\n return { type: \"exec\", cmdName, cmdArgs, batchMode };\n }\n\n if (tok === \"-print\") {\n advance();\n return { type: \"print\" };\n }\n\n throw new ParseError(`find: unknown predicate '${tok}'`);\n }\n\n const expr = parseOr();\n if (pos < args.length) {\n throw new ParseError(`find: unexpected '${args[pos]}'`);\n }\n return expr;\n}\n\nexport const find: Command = async (ctx) => {\n const args = [...ctx.args];\n const paths: string[] = [];\n\n // Parse arguments: paths come before first flag/operator\n let i = 0;\n\n // Collect paths (args before first -, !, or ()\n while (i < args.length && !args[i]!.startsWith(\"-\") && args[i] !== \"!\" && args[i] !== \"(\" && args[i] !== \")\") {\n paths.push(args[i]!);\n i++;\n }\n\n // Default to current directory if no paths\n if (paths.length === 0) {\n paths.push(\".\");\n }\n\n // Extract global options (-maxdepth, -mindepth) from remaining args\n let maxDepth: number | undefined;\n let minDepth: number | undefined;\n const exprArgs: string[] = [];\n\n let j = i;\n while (j < args.length) {\n const arg = args[j]!;\n if (arg === \"-maxdepth\") {\n j++;\n if (j >= args.length) {\n await ctx.stderr.writeText(\"find: missing argument to '-maxdepth'\\n\");\n return 1;\n }\n const depth = parseInt(args[j]!, 10);\n if (isNaN(depth) || depth < 0) {\n await ctx.stderr.writeText(`find: Invalid argument '${args[j]}' to -maxdepth\\n`);\n return 1;\n }\n maxDepth = depth;\n } else if (arg === \"-mindepth\") {\n j++;\n if (j >= args.length) {\n await ctx.stderr.writeText(\"find: missing argument to '-mindepth'\\n\");\n return 1;\n }\n const depth = parseInt(args[j]!, 10);\n if (isNaN(depth) || depth < 0) {\n await ctx.stderr.writeText(`find: Invalid argument '${args[j]}' to -mindepth\\n`);\n return 1;\n }\n minDepth = depth;\n } else {\n exprArgs.push(arg);\n }\n j++;\n }\n\n // Parse expression tree\n let expr: FindExpr;\n try {\n expr = parseExprArgs(exprArgs);\n } catch (e) {\n if (e instanceof ParseError) {\n await ctx.stderr.writeText(e.message + \"\\n\");\n return 1;\n }\n throw e;\n }\n\n const hasAction = hasActionExpr(expr);\n const batchExecNodes = collectBatchExecNodes(expr);\n const batchPaths: string[] = [];\n\n let hasError = false;\n\n // Process each starting path\n for (const startPath of paths) {\n const normalizedPath = startPath === \"/\" ? \"/\" : startPath.replace(/\\/+$/, '');\n const resolvedStart = ctx.fs.resolve(ctx.cwd, startPath);\n\n // Check if path exists\n let stat;\n try {\n stat = await ctx.fs.stat(resolvedStart);\n } catch {\n await ctx.stderr.writeText(`find: '${startPath}': No such file or directory\\n`);\n hasError = true;\n continue;\n }\n\n // Recursive traversal function\n async function traverse(path: string, displayPath: string, depth: number): Promise<void> {\n // Check maxdepth\n if (maxDepth !== undefined && depth > maxDepth) {\n return;\n }\n\n let entryStat;\n try {\n entryStat = await ctx.fs.stat(path);\n } catch {\n return;\n }\n\n const isDir = entryStat.isDirectory();\n const isFile = entryStat.isFile();\n const basename = ctx.fs.basename(path);\n const meetsMinDepth = minDepth === undefined || depth >= minDepth;\n\n // Check if this entry matches the expression\n const matches = await evalExpr(expr, basename, isFile, isDir, displayPath, ctx, meetsMinDepth);\n\n if (matches && meetsMinDepth) {\n if (batchExecNodes.length > 0) {\n batchPaths.push(displayPath);\n } else if (!hasAction) {\n // No action expressions: default print behavior\n await ctx.stdout.writeText(displayPath + \"\\n\");\n }\n // If has per-file -exec actions, output was already handled in evalExpr\n }\n\n // Recurse into directories\n if (isDir) {\n try {\n const entries = await ctx.fs.readdir(path);\n entries.sort();\n for (const entry of entries) {\n const childPath = ctx.fs.resolve(path, entry);\n const childDisplayPath = displayPath === \".\" ? entry : `${displayPath}/${entry}`;\n await traverse(childPath, childDisplayPath, depth + 1);\n }\n } catch {\n // Ignore errors reading directory contents\n }\n }\n }\n\n // Start traversal\n if (stat.isFile()) {\n const basename = ctx.fs.basename(resolvedStart);\n const meetsMinDepth = minDepth === undefined || minDepth <= 0;\n const matches = await evalExpr(expr, basename, true, false, normalizedPath, ctx, meetsMinDepth);\n\n if (maxDepth !== undefined && maxDepth < 0) {\n // skip\n } else if (matches && meetsMinDepth) {\n if (batchExecNodes.length > 0) {\n batchPaths.push(normalizedPath);\n } else if (!hasAction) {\n await ctx.stdout.writeText(normalizedPath + \"\\n\");\n }\n }\n } else {\n await traverse(resolvedStart, normalizedPath, 0);\n }\n }\n\n // Execute batch -exec nodes with all collected paths\n if (batchExecNodes.length > 0 && batchPaths.length > 0 && ctx.exec) {\n for (const node of batchExecNodes) {\n // Replace {} in cmdArgs with all paths\n const resolvedArgs: string[] = [];\n for (const a of node.cmdArgs) {\n if (a === \"{}\") {\n resolvedArgs.push(...batchPaths);\n } else {\n resolvedArgs.push(a);\n }\n }\n const result = await ctx.exec(node.cmdName, resolvedArgs);\n if (result.stdout.length > 0) {\n await ctx.stdout.write(result.stdout);\n }\n if (result.stderr.length > 0) {\n await ctx.stderr.write(result.stderr);\n }\n }\n }\n\n return hasError ? 1 : 0;\n};\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";AACA;
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "10955D1C374A7D0364756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -26,6 +26,7 @@ import { colon } from "./colon/colon.mjs";
|
|
|
26
26
|
import { cd } from "./cd/cd.mjs";
|
|
27
27
|
import { tr } from "./tr/tr.mjs";
|
|
28
28
|
import { cut } from "./cut/cut.mjs";
|
|
29
|
+
import { od } from "./od/od.mjs";
|
|
29
30
|
import { echo as echo2 } from "./echo/echo.mjs";
|
|
30
31
|
import { cat as cat2 } from "./cat/cat.mjs";
|
|
31
32
|
import { grep as grep2 } from "./grep/grep.mjs";
|
|
@@ -53,6 +54,7 @@ import { colon as colon2 } from "./colon/colon.mjs";
|
|
|
53
54
|
import { cd as cd2 } from "./cd/cd.mjs";
|
|
54
55
|
import { tr as tr2 } from "./tr/tr.mjs";
|
|
55
56
|
import { cut as cut2 } from "./cut/cut.mjs";
|
|
57
|
+
import { od as od2 } from "./od/od.mjs";
|
|
56
58
|
var builtinCommands = {
|
|
57
59
|
echo: echo2,
|
|
58
60
|
cat: cat2,
|
|
@@ -83,7 +85,8 @@ var builtinCommands = {
|
|
|
83
85
|
":": colon2,
|
|
84
86
|
cd: cd2,
|
|
85
87
|
tr: tr2,
|
|
86
|
-
cut: cut2
|
|
88
|
+
cut: cut2,
|
|
89
|
+
od: od2
|
|
87
90
|
};
|
|
88
91
|
export {
|
|
89
92
|
wc,
|
|
@@ -99,6 +102,7 @@ export {
|
|
|
99
102
|
sed,
|
|
100
103
|
rm,
|
|
101
104
|
pwd,
|
|
105
|
+
od,
|
|
102
106
|
mv,
|
|
103
107
|
mkdir,
|
|
104
108
|
ls,
|
|
@@ -119,4 +123,4 @@ export {
|
|
|
119
123
|
awk
|
|
120
124
|
};
|
|
121
125
|
|
|
122
|
-
//# debugId=
|
|
126
|
+
//# debugId=B7E3709FE74A7FB764756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/commands/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import type { Command } from \"../types.mjs\";\n\nexport { echo } from \"./echo/echo.mjs\";\nexport { cat } from \"./cat/cat.mjs\";\nexport { grep } from \"./grep/grep.mjs\";\nexport { wc } from \"./wc/wc.mjs\";\nexport { head } from \"./head/head.mjs\";\nexport { tail } from \"./tail/tail.mjs\";\nexport { sort } from \"./sort/sort.mjs\";\nexport { uniq } from \"./uniq/uniq.mjs\";\nexport { pwd } from \"./pwd/pwd.mjs\";\nexport { ls } from \"./ls/ls.mjs\";\nexport { mkdir } from \"./mkdir/mkdir.mjs\";\nexport { rm } from \"./rm/rm.mjs\";\nexport { test, bracket } from \"./test/test.mjs\";\nexport { trueCmd, falseCmd } from \"./true-false/true-false.mjs\";\nexport { touch } from \"./touch/touch.mjs\";\nexport { cp } from \"./cp/cp.mjs\";\nexport { mv } from \"./mv/mv.mjs\";\nexport { tee } from \"./tee/tee.mjs\";\nexport { tree } from \"./tree/tree.mjs\";\nexport { find } from \"./find/find.mjs\";\nexport { sed } from \"./sed/sed.mjs\";\nexport { awk } from \"./awk/awk.mjs\";\nexport { breakCmd, continueCmd } from \"./break-continue/break-continue.mjs\";\nexport { colon } from \"./colon/colon.mjs\";\nexport { cd } from \"./cd/cd.mjs\";\nexport { tr } from \"./tr/tr.mjs\";\nexport { cut } from \"./cut/cut.mjs\";\n\n// Re-export all commands as a bundle\nimport { echo } from \"./echo/echo.mjs\";\nimport { cat } from \"./cat/cat.mjs\";\nimport { grep } from \"./grep/grep.mjs\";\nimport { wc } from \"./wc/wc.mjs\";\nimport { head } from \"./head/head.mjs\";\nimport { tail } from \"./tail/tail.mjs\";\nimport { sort } from \"./sort/sort.mjs\";\nimport { uniq } from \"./uniq/uniq.mjs\";\nimport { pwd } from \"./pwd/pwd.mjs\";\nimport { ls } from \"./ls/ls.mjs\";\nimport { mkdir } from \"./mkdir/mkdir.mjs\";\nimport { rm } from \"./rm/rm.mjs\";\nimport { test, bracket } from \"./test/test.mjs\";\nimport { trueCmd, falseCmd } from \"./true-false/true-false.mjs\";\nimport { touch } from \"./touch/touch.mjs\";\nimport { cp } from \"./cp/cp.mjs\";\nimport { mv } from \"./mv/mv.mjs\";\nimport { tee } from \"./tee/tee.mjs\";\nimport { tree } from \"./tree/tree.mjs\";\nimport { find } from \"./find/find.mjs\";\nimport { sed } from \"./sed/sed.mjs\";\nimport { awk } from \"./awk/awk.mjs\";\nimport { breakCmd, continueCmd } from \"./break-continue/break-continue.mjs\";\nimport { colon } from \"./colon/colon.mjs\";\nimport { cd } from \"./cd/cd.mjs\";\nimport { tr } from \"./tr/tr.mjs\";\nimport { cut } from \"./cut/cut.mjs\";\n\nexport const builtinCommands: Record<string, Command> = {\n echo,\n cat,\n grep,\n wc,\n head,\n tail,\n sort,\n uniq,\n pwd,\n ls,\n mkdir,\n rm,\n test,\n \"[\": bracket,\n true: trueCmd,\n false: falseCmd,\n touch,\n cp,\n mv,\n tee,\n tree,\n find,\n sed,\n awk,\n break: breakCmd,\n continue: continueCmd,\n \":\": colon,\n cd,\n tr,\n cut,\n};\n"
|
|
5
|
+
"import type { Command } from \"../types.mjs\";\n\nexport { echo } from \"./echo/echo.mjs\";\nexport { cat } from \"./cat/cat.mjs\";\nexport { grep } from \"./grep/grep.mjs\";\nexport { wc } from \"./wc/wc.mjs\";\nexport { head } from \"./head/head.mjs\";\nexport { tail } from \"./tail/tail.mjs\";\nexport { sort } from \"./sort/sort.mjs\";\nexport { uniq } from \"./uniq/uniq.mjs\";\nexport { pwd } from \"./pwd/pwd.mjs\";\nexport { ls } from \"./ls/ls.mjs\";\nexport { mkdir } from \"./mkdir/mkdir.mjs\";\nexport { rm } from \"./rm/rm.mjs\";\nexport { test, bracket } from \"./test/test.mjs\";\nexport { trueCmd, falseCmd } from \"./true-false/true-false.mjs\";\nexport { touch } from \"./touch/touch.mjs\";\nexport { cp } from \"./cp/cp.mjs\";\nexport { mv } from \"./mv/mv.mjs\";\nexport { tee } from \"./tee/tee.mjs\";\nexport { tree } from \"./tree/tree.mjs\";\nexport { find } from \"./find/find.mjs\";\nexport { sed } from \"./sed/sed.mjs\";\nexport { awk } from \"./awk/awk.mjs\";\nexport { breakCmd, continueCmd } from \"./break-continue/break-continue.mjs\";\nexport { colon } from \"./colon/colon.mjs\";\nexport { cd } from \"./cd/cd.mjs\";\nexport { tr } from \"./tr/tr.mjs\";\nexport { cut } from \"./cut/cut.mjs\";\nexport { od } from \"./od/od.mjs\";\n\n// Re-export all commands as a bundle\nimport { echo } from \"./echo/echo.mjs\";\nimport { cat } from \"./cat/cat.mjs\";\nimport { grep } from \"./grep/grep.mjs\";\nimport { wc } from \"./wc/wc.mjs\";\nimport { head } from \"./head/head.mjs\";\nimport { tail } from \"./tail/tail.mjs\";\nimport { sort } from \"./sort/sort.mjs\";\nimport { uniq } from \"./uniq/uniq.mjs\";\nimport { pwd } from \"./pwd/pwd.mjs\";\nimport { ls } from \"./ls/ls.mjs\";\nimport { mkdir } from \"./mkdir/mkdir.mjs\";\nimport { rm } from \"./rm/rm.mjs\";\nimport { test, bracket } from \"./test/test.mjs\";\nimport { trueCmd, falseCmd } from \"./true-false/true-false.mjs\";\nimport { touch } from \"./touch/touch.mjs\";\nimport { cp } from \"./cp/cp.mjs\";\nimport { mv } from \"./mv/mv.mjs\";\nimport { tee } from \"./tee/tee.mjs\";\nimport { tree } from \"./tree/tree.mjs\";\nimport { find } from \"./find/find.mjs\";\nimport { sed } from \"./sed/sed.mjs\";\nimport { awk } from \"./awk/awk.mjs\";\nimport { breakCmd, continueCmd } from \"./break-continue/break-continue.mjs\";\nimport { colon } from \"./colon/colon.mjs\";\nimport { cd } from \"./cd/cd.mjs\";\nimport { tr } from \"./tr/tr.mjs\";\nimport { cut } from \"./cut/cut.mjs\";\nimport { od } from \"./od/od.mjs\";\n\nexport const builtinCommands: Record<string, Command> = {\n echo,\n cat,\n grep,\n wc,\n head,\n tail,\n sort,\n uniq,\n pwd,\n ls,\n mkdir,\n rm,\n test,\n \"[\": bracket,\n true: trueCmd,\n false: falseCmd,\n touch,\n cp,\n mv,\n tee,\n tree,\n find,\n sed,\n awk,\n break: breakCmd,\n continue: continueCmd,\n \":\": colon,\n cd,\n tr,\n cut,\n od,\n};\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA,iBAAS;AACT,gBAAS;AACT,iBAAS;AACT,eAAS;AACT,iBAAS;AACT,iBAAS;AACT,iBAAS;AACT,iBAAS;AACT,gBAAS;AACT,eAAS;AACT,kBAAS;AACT,eAAS;AACT,iBAAS,kBAAM;AACf,oBAAS,sBAAS;AAClB,kBAAS;AACT,eAAS;AACT,eAAS;AACT,gBAAS;AACT,iBAAS;AACT,iBAAS;AACT,gBAAS;AACT,gBAAS;AACT,qBAAS,0BAAU;AACnB,kBAAS;AACT,eAAS;AACT,eAAS;AACT,gBAAS;AAEF,IAAM,kBAA2C;AAAA,EACtD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,KAAK;AAAA,EACL,MAAM;AAAA,EACN,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,UAAU;AAAA,EACV,KAAK;AAAA,EACL;AAAA,EACA;AAAA,EACA;AACF;",
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": ";AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA,iBAAS;AACT,gBAAS;AACT,iBAAS;AACT,eAAS;AACT,iBAAS;AACT,iBAAS;AACT,iBAAS;AACT,iBAAS;AACT,gBAAS;AACT,eAAS;AACT,kBAAS;AACT,eAAS;AACT,iBAAS,kBAAM;AACf,oBAAS,sBAAS;AAClB,kBAAS;AACT,eAAS;AACT,eAAS;AACT,gBAAS;AACT,iBAAS;AACT,iBAAS;AACT,gBAAS;AACT,gBAAS;AACT,qBAAS,0BAAU;AACnB,kBAAS;AACT,eAAS;AACT,eAAS;AACT,gBAAS;AACT,eAAS;AAEF,IAAM,kBAA2C;AAAA,EACtD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,KAAK;AAAA,EACL,MAAM;AAAA,EACN,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,UAAU;AAAA,EACV,KAAK;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;",
|
|
8
|
+
"debugId": "B7E3709FE74A7FB764756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
// src/commands/od/od.ts
|
|
2
|
+
import { createFlagParser } from "../../utils/flag-parser.mjs";
|
|
3
|
+
var ADDRESS_WIDTH = 7;
|
|
4
|
+
var ADDRESS_SEPARATOR = " ";
|
|
5
|
+
var NO_ADDRESS_PREFIX = " ".repeat(ADDRESS_WIDTH + ADDRESS_SEPARATOR.length);
|
|
6
|
+
var LINE_BYTES = 16;
|
|
7
|
+
var spec = {
|
|
8
|
+
name: "od",
|
|
9
|
+
flags: [
|
|
10
|
+
{ short: "A", takesValue: true },
|
|
11
|
+
{ short: "b" },
|
|
12
|
+
{ short: "c" },
|
|
13
|
+
{ short: "j", takesValue: true },
|
|
14
|
+
{ short: "N", takesValue: true },
|
|
15
|
+
{ short: "o" },
|
|
16
|
+
{ short: "t", takesValue: true },
|
|
17
|
+
{ short: "v" },
|
|
18
|
+
{ short: "x" }
|
|
19
|
+
],
|
|
20
|
+
usage: "od [-bcovx] [-A radix] [-j skip] [-N count] [-t type] [file ...]"
|
|
21
|
+
};
|
|
22
|
+
var defaults = {
|
|
23
|
+
addressRadix: "o",
|
|
24
|
+
format: null,
|
|
25
|
+
formatConflict: null,
|
|
26
|
+
invalidType: null,
|
|
27
|
+
verbose: false,
|
|
28
|
+
skip: null,
|
|
29
|
+
count: null
|
|
30
|
+
};
|
|
31
|
+
function selectFormat(flags, format, source) {
|
|
32
|
+
if (flags.format === null) {
|
|
33
|
+
flags.format = format;
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
flags.formatConflict = source;
|
|
37
|
+
}
|
|
38
|
+
function isOutputFormat(value) {
|
|
39
|
+
return value === "x1" || value === "x2" || value === "o1" || value === "o2" || value === "c";
|
|
40
|
+
}
|
|
41
|
+
var parser = createFlagParser(spec, defaults, (flags, flag, value) => {
|
|
42
|
+
switch (flag.short) {
|
|
43
|
+
case "A":
|
|
44
|
+
flags.addressRadix = value ?? "o";
|
|
45
|
+
break;
|
|
46
|
+
case "b":
|
|
47
|
+
selectFormat(flags, "o1", "-b");
|
|
48
|
+
break;
|
|
49
|
+
case "c":
|
|
50
|
+
selectFormat(flags, "c", "-c");
|
|
51
|
+
break;
|
|
52
|
+
case "j":
|
|
53
|
+
flags.skip = value ?? null;
|
|
54
|
+
break;
|
|
55
|
+
case "N":
|
|
56
|
+
flags.count = value ?? null;
|
|
57
|
+
break;
|
|
58
|
+
case "o":
|
|
59
|
+
selectFormat(flags, "o2", "-o");
|
|
60
|
+
break;
|
|
61
|
+
case "t":
|
|
62
|
+
if (value && isOutputFormat(value)) {
|
|
63
|
+
selectFormat(flags, value, "-t");
|
|
64
|
+
} else if (value) {
|
|
65
|
+
flags.invalidType = value;
|
|
66
|
+
}
|
|
67
|
+
break;
|
|
68
|
+
case "v":
|
|
69
|
+
flags.verbose = true;
|
|
70
|
+
break;
|
|
71
|
+
case "x":
|
|
72
|
+
selectFormat(flags, "x2", "-x");
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
function isAddressRadix(value) {
|
|
77
|
+
return value === "o" || value === "d" || value === "x" || value === "n";
|
|
78
|
+
}
|
|
79
|
+
function parseNonNegativeInteger(value, label) {
|
|
80
|
+
if (!/^\d+$/.test(value)) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
const parsed = Number(value);
|
|
84
|
+
if (!Number.isSafeInteger(parsed)) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
return parsed;
|
|
88
|
+
}
|
|
89
|
+
function formatAddress(offset, radix) {
|
|
90
|
+
const base = radix === "o" ? 8 : radix === "d" ? 10 : 16;
|
|
91
|
+
return offset.toString(base).padStart(ADDRESS_WIDTH, "0");
|
|
92
|
+
}
|
|
93
|
+
function formatCharacter(byte) {
|
|
94
|
+
let token;
|
|
95
|
+
if (byte === 0) {
|
|
96
|
+
token = "\\0";
|
|
97
|
+
} else if (byte === 9) {
|
|
98
|
+
token = "\\t";
|
|
99
|
+
} else if (byte === 10) {
|
|
100
|
+
token = "\\n";
|
|
101
|
+
} else if (byte >= 32 && byte <= 126) {
|
|
102
|
+
token = String.fromCharCode(byte);
|
|
103
|
+
} else {
|
|
104
|
+
token = `\\${byte.toString(8).padStart(3, "0")}`;
|
|
105
|
+
}
|
|
106
|
+
return token.length < 3 ? token.padStart(3, " ") : token;
|
|
107
|
+
}
|
|
108
|
+
function formatWord(bytes, index, radix) {
|
|
109
|
+
const low = bytes[index] ?? 0;
|
|
110
|
+
const high = bytes[index + 1] ?? 0;
|
|
111
|
+
const value = low | high << 8;
|
|
112
|
+
const base = radix === "hex" ? 16 : 8;
|
|
113
|
+
const width = radix === "hex" ? 4 : 6;
|
|
114
|
+
return value.toString(base).padStart(width, "0");
|
|
115
|
+
}
|
|
116
|
+
function formatRow(bytes, format) {
|
|
117
|
+
const values = [];
|
|
118
|
+
if (format === "x1") {
|
|
119
|
+
for (const byte of bytes) {
|
|
120
|
+
values.push(byte.toString(16).padStart(2, "0"));
|
|
121
|
+
}
|
|
122
|
+
} else if (format === "o1") {
|
|
123
|
+
for (const byte of bytes) {
|
|
124
|
+
values.push(byte.toString(8).padStart(3, "0"));
|
|
125
|
+
}
|
|
126
|
+
} else if (format === "c") {
|
|
127
|
+
for (const byte of bytes) {
|
|
128
|
+
values.push(formatCharacter(byte));
|
|
129
|
+
}
|
|
130
|
+
} else if (format === "x2") {
|
|
131
|
+
for (let i = 0;i < bytes.length; i += 2) {
|
|
132
|
+
values.push(formatWord(bytes, i, "hex"));
|
|
133
|
+
}
|
|
134
|
+
} else {
|
|
135
|
+
for (let i = 0;i < bytes.length; i += 2) {
|
|
136
|
+
values.push(formatWord(bytes, i, "octal"));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return values.join(" ");
|
|
140
|
+
}
|
|
141
|
+
async function readInput(ctx, files) {
|
|
142
|
+
if (files.length === 0) {
|
|
143
|
+
return await ctx.stdin.buffer();
|
|
144
|
+
}
|
|
145
|
+
const chunks = [];
|
|
146
|
+
for (const file of files) {
|
|
147
|
+
try {
|
|
148
|
+
const path = ctx.fs.resolve(ctx.cwd, file);
|
|
149
|
+
chunks.push(await ctx.fs.readFile(path));
|
|
150
|
+
} catch {
|
|
151
|
+
await ctx.stderr.writeText(`od: ${file}: No such file or directory
|
|
152
|
+
`);
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return Buffer.concat(chunks);
|
|
157
|
+
}
|
|
158
|
+
var od = async (ctx) => {
|
|
159
|
+
const result = parser.parse(ctx.args);
|
|
160
|
+
if (result.error) {
|
|
161
|
+
await parser.writeError(result.error, ctx.stderr);
|
|
162
|
+
return 1;
|
|
163
|
+
}
|
|
164
|
+
const { addressRadix, formatConflict, invalidType, skip, count, verbose } = result.flags;
|
|
165
|
+
if (!isAddressRadix(addressRadix)) {
|
|
166
|
+
await ctx.stderr.writeText(`od: invalid address radix '${addressRadix}'
|
|
167
|
+
`);
|
|
168
|
+
return 1;
|
|
169
|
+
}
|
|
170
|
+
if (invalidType !== null) {
|
|
171
|
+
await ctx.stderr.writeText(`od: invalid type string '${invalidType}'
|
|
172
|
+
`);
|
|
173
|
+
return 1;
|
|
174
|
+
}
|
|
175
|
+
if (formatConflict !== null) {
|
|
176
|
+
await ctx.stderr.writeText(`od: multiple output formats are not supported
|
|
177
|
+
`);
|
|
178
|
+
return 1;
|
|
179
|
+
}
|
|
180
|
+
const skipBytes = skip === null ? 0 : parseNonNegativeInteger(skip, "skip");
|
|
181
|
+
if (skipBytes === null) {
|
|
182
|
+
await ctx.stderr.writeText(`od: invalid skip '${skip}'
|
|
183
|
+
`);
|
|
184
|
+
return 1;
|
|
185
|
+
}
|
|
186
|
+
const countBytes = count === null ? null : parseNonNegativeInteger(count, "count");
|
|
187
|
+
if (count !== null && countBytes === null) {
|
|
188
|
+
await ctx.stderr.writeText(`od: invalid byte count '${count}'
|
|
189
|
+
`);
|
|
190
|
+
return 1;
|
|
191
|
+
}
|
|
192
|
+
const input = await readInput(ctx, result.args);
|
|
193
|
+
if (input === null) {
|
|
194
|
+
return 1;
|
|
195
|
+
}
|
|
196
|
+
const start = Math.min(skipBytes, input.length);
|
|
197
|
+
const sliced = countBytes === null ? input.subarray(start) : input.subarray(start, Math.min(start + countBytes, input.length));
|
|
198
|
+
if (sliced.length === 0) {
|
|
199
|
+
return 0;
|
|
200
|
+
}
|
|
201
|
+
const format = result.flags.format ?? "o2";
|
|
202
|
+
let previousRow = null;
|
|
203
|
+
let emittedSqueezeMarker = false;
|
|
204
|
+
let offset = start;
|
|
205
|
+
for (let i = 0;i < sliced.length; i += LINE_BYTES) {
|
|
206
|
+
const rowBytes = sliced.subarray(i, Math.min(i + LINE_BYTES, sliced.length));
|
|
207
|
+
const row = formatRow(rowBytes, format);
|
|
208
|
+
if (!verbose && row === previousRow) {
|
|
209
|
+
if (!emittedSqueezeMarker) {
|
|
210
|
+
await ctx.stdout.writeText(`*
|
|
211
|
+
`);
|
|
212
|
+
emittedSqueezeMarker = true;
|
|
213
|
+
}
|
|
214
|
+
offset += rowBytes.length;
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
previousRow = row;
|
|
218
|
+
emittedSqueezeMarker = false;
|
|
219
|
+
const prefix = addressRadix === "n" ? NO_ADDRESS_PREFIX : `${formatAddress(offset, addressRadix)}${ADDRESS_SEPARATOR}`;
|
|
220
|
+
await ctx.stdout.writeText(`${prefix}${row}
|
|
221
|
+
`);
|
|
222
|
+
offset += rowBytes.length;
|
|
223
|
+
}
|
|
224
|
+
if (addressRadix !== "n") {
|
|
225
|
+
await ctx.stdout.writeText(`${formatAddress(offset, addressRadix)}
|
|
226
|
+
`);
|
|
227
|
+
}
|
|
228
|
+
return 0;
|
|
229
|
+
};
|
|
230
|
+
export {
|
|
231
|
+
od
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
//# debugId=2B4F57CE0D46E09864756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/commands/od/od.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import type { Command } from \"../../types.mjs\";\nimport { createFlagParser, type FlagDefinition } from \"../../utils/flag-parser.mjs\";\n\ntype AddressRadix = \"o\" | \"d\" | \"x\" | \"n\";\ntype OutputFormat = \"x1\" | \"x2\" | \"o1\" | \"o2\" | \"c\";\n\ninterface OdFlags {\n addressRadix: string;\n format: OutputFormat | null;\n formatConflict: string | null;\n invalidType: string | null;\n verbose: boolean;\n skip: string | null;\n count: string | null;\n}\n\nconst ADDRESS_WIDTH = 7;\nconst ADDRESS_SEPARATOR = \" \";\nconst NO_ADDRESS_PREFIX = \" \".repeat(ADDRESS_WIDTH + ADDRESS_SEPARATOR.length);\nconst LINE_BYTES = 16;\n\nconst spec = {\n name: \"od\",\n flags: [\n { short: \"A\", takesValue: true },\n { short: \"b\" },\n { short: \"c\" },\n { short: \"j\", takesValue: true },\n { short: \"N\", takesValue: true },\n { short: \"o\" },\n { short: \"t\", takesValue: true },\n { short: \"v\" },\n { short: \"x\" },\n ] as FlagDefinition[],\n usage: \"od [-bcovx] [-A radix] [-j skip] [-N count] [-t type] [file ...]\",\n};\n\nconst defaults: OdFlags = {\n addressRadix: \"o\",\n format: null,\n formatConflict: null,\n invalidType: null,\n verbose: false,\n skip: null,\n count: null,\n};\n\nfunction selectFormat(flags: OdFlags, format: OutputFormat, source: string): void {\n if (flags.format === null) {\n flags.format = format;\n return;\n }\n\n flags.formatConflict = source;\n}\n\nfunction isOutputFormat(value: string): value is OutputFormat {\n return value === \"x1\" || value === \"x2\" || value === \"o1\" || value === \"o2\" || value === \"c\";\n}\n\nconst parser = createFlagParser(spec, defaults, (flags, flag, value) => {\n switch (flag.short) {\n case \"A\":\n flags.addressRadix = value ?? \"o\";\n break;\n case \"b\":\n selectFormat(flags, \"o1\", \"-b\");\n break;\n case \"c\":\n selectFormat(flags, \"c\", \"-c\");\n break;\n case \"j\":\n flags.skip = value ?? null;\n break;\n case \"N\":\n flags.count = value ?? null;\n break;\n case \"o\":\n selectFormat(flags, \"o2\", \"-o\");\n break;\n case \"t\":\n if (value && isOutputFormat(value)) {\n selectFormat(flags, value, \"-t\");\n } else if (value) {\n flags.invalidType = value;\n }\n break;\n case \"v\":\n flags.verbose = true;\n break;\n case \"x\":\n selectFormat(flags, \"x2\", \"-x\");\n break;\n }\n});\n\nfunction isAddressRadix(value: string): value is AddressRadix {\n return value === \"o\" || value === \"d\" || value === \"x\" || value === \"n\";\n}\n\nfunction parseNonNegativeInteger(value: string, label: \"skip\" | \"count\"): number | null {\n if (!/^\\d+$/.test(value)) {\n return null;\n }\n\n const parsed = Number(value);\n if (!Number.isSafeInteger(parsed)) {\n return null;\n }\n\n return parsed;\n}\n\nfunction formatAddress(offset: number, radix: Exclude<AddressRadix, \"n\">): string {\n const base = radix === \"o\" ? 8 : radix === \"d\" ? 10 : 16;\n return offset.toString(base).padStart(ADDRESS_WIDTH, \"0\");\n}\n\nfunction formatCharacter(byte: number): string {\n let token: string;\n\n if (byte === 0) {\n token = \"\\\\0\";\n } else if (byte === 9) {\n token = \"\\\\t\";\n } else if (byte === 10) {\n token = \"\\\\n\";\n } else if (byte >= 32 && byte <= 126) {\n token = String.fromCharCode(byte);\n } else {\n token = `\\\\${byte.toString(8).padStart(3, \"0\")}`;\n }\n\n return token.length < 3 ? token.padStart(3, \" \") : token;\n}\n\nfunction formatWord(bytes: Uint8Array, index: number, radix: \"hex\" | \"octal\"): string {\n const low = bytes[index] ?? 0;\n const high = bytes[index + 1] ?? 0;\n const value = low | (high << 8);\n const base = radix === \"hex\" ? 16 : 8;\n const width = radix === \"hex\" ? 4 : 6;\n return value.toString(base).padStart(width, \"0\");\n}\n\nfunction formatRow(bytes: Uint8Array, format: OutputFormat): string {\n const values: string[] = [];\n\n if (format === \"x1\") {\n for (const byte of bytes) {\n values.push(byte.toString(16).padStart(2, \"0\"));\n }\n } else if (format === \"o1\") {\n for (const byte of bytes) {\n values.push(byte.toString(8).padStart(3, \"0\"));\n }\n } else if (format === \"c\") {\n for (const byte of bytes) {\n values.push(formatCharacter(byte));\n }\n } else if (format === \"x2\") {\n for (let i = 0; i < bytes.length; i += 2) {\n values.push(formatWord(bytes, i, \"hex\"));\n }\n } else {\n for (let i = 0; i < bytes.length; i += 2) {\n values.push(formatWord(bytes, i, \"octal\"));\n }\n }\n\n return values.join(\" \");\n}\n\nasync function readInput(ctx: Parameters<Command>[0], files: string[]): Promise<Buffer | null> {\n if (files.length === 0) {\n return await ctx.stdin.buffer();\n }\n\n const chunks: Buffer[] = [];\n\n for (const file of files) {\n try {\n const path = ctx.fs.resolve(ctx.cwd, file);\n chunks.push(await ctx.fs.readFile(path));\n } catch {\n await ctx.stderr.writeText(`od: ${file}: No such file or directory\\n`);\n return null;\n }\n }\n\n return Buffer.concat(chunks);\n}\n\nexport const od: Command = async (ctx) => {\n const result = parser.parse(ctx.args);\n\n if (result.error) {\n await parser.writeError(result.error, ctx.stderr);\n return 1;\n }\n\n const { addressRadix, formatConflict, invalidType, skip, count, verbose } = result.flags;\n\n if (!isAddressRadix(addressRadix)) {\n await ctx.stderr.writeText(`od: invalid address radix '${addressRadix}'\\n`);\n return 1;\n }\n\n if (invalidType !== null) {\n await ctx.stderr.writeText(`od: invalid type string '${invalidType}'\\n`);\n return 1;\n }\n\n if (formatConflict !== null) {\n await ctx.stderr.writeText(\"od: multiple output formats are not supported\\n\");\n return 1;\n }\n\n const skipBytes = skip === null ? 0 : parseNonNegativeInteger(skip, \"skip\");\n if (skipBytes === null) {\n await ctx.stderr.writeText(`od: invalid skip '${skip}'\\n`);\n return 1;\n }\n\n const countBytes = count === null ? null : parseNonNegativeInteger(count, \"count\");\n if (count !== null && countBytes === null) {\n await ctx.stderr.writeText(`od: invalid byte count '${count}'\\n`);\n return 1;\n }\n\n const input = await readInput(ctx, result.args);\n if (input === null) {\n return 1;\n }\n\n const start = Math.min(skipBytes, input.length);\n const sliced = countBytes === null\n ? input.subarray(start)\n : input.subarray(start, Math.min(start + countBytes, input.length));\n\n if (sliced.length === 0) {\n return 0;\n }\n\n const format = result.flags.format ?? \"o2\";\n\n let previousRow: string | null = null;\n let emittedSqueezeMarker = false;\n let offset = start;\n\n for (let i = 0; i < sliced.length; i += LINE_BYTES) {\n const rowBytes = sliced.subarray(i, Math.min(i + LINE_BYTES, sliced.length));\n const row = formatRow(rowBytes, format);\n\n if (!verbose && row === previousRow) {\n if (!emittedSqueezeMarker) {\n await ctx.stdout.writeText(\"*\\n\");\n emittedSqueezeMarker = true;\n }\n offset += rowBytes.length;\n continue;\n }\n\n previousRow = row;\n emittedSqueezeMarker = false;\n\n const prefix = addressRadix === \"n\"\n ? NO_ADDRESS_PREFIX\n : `${formatAddress(offset, addressRadix)}${ADDRESS_SEPARATOR}`;\n\n await ctx.stdout.writeText(`${prefix}${row}\\n`);\n offset += rowBytes.length;\n }\n\n if (addressRadix !== \"n\") {\n await ctx.stdout.writeText(`${formatAddress(offset, addressRadix)}\\n`);\n }\n\n return 0;\n};\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "2B4F57CE0D46E09864756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -9,9 +9,10 @@ var spec = {
|
|
|
9
9
|
{ short: "L", takesValue: true },
|
|
10
10
|
{ short: "I", takesValue: true },
|
|
11
11
|
{ long: "dirsfirst" },
|
|
12
|
-
{ long: "prune" }
|
|
12
|
+
{ long: "prune" },
|
|
13
|
+
{ long: "noreport" }
|
|
13
14
|
],
|
|
14
|
-
usage: "tree [-adI] [-L level] [-I pattern] [--dirsfirst] [--prune] [directory ...]"
|
|
15
|
+
usage: "tree [-adI] [-L level] [-I pattern] [--dirsfirst] [--prune] [--noreport] [directory ...]"
|
|
15
16
|
};
|
|
16
17
|
var defaults = {
|
|
17
18
|
all: false,
|
|
@@ -19,6 +20,7 @@ var defaults = {
|
|
|
19
20
|
maxDepth: Infinity,
|
|
20
21
|
dirsfirst: true,
|
|
21
22
|
prune: false,
|
|
23
|
+
noReport: false,
|
|
22
24
|
ignorePatterns: []
|
|
23
25
|
};
|
|
24
26
|
var handlerResult = {};
|
|
@@ -31,6 +33,8 @@ var handler = (flags, flag, value) => {
|
|
|
31
33
|
flags.dirsfirst = true;
|
|
32
34
|
if (flag.long === "prune")
|
|
33
35
|
flags.prune = true;
|
|
36
|
+
if (flag.long === "noreport")
|
|
37
|
+
flags.noReport = true;
|
|
34
38
|
if (flag.short === "I" && value) {
|
|
35
39
|
if (flags.ignorePatterns === defaults.ignorePatterns) {
|
|
36
40
|
flags.ignorePatterns = [];
|
|
@@ -60,7 +64,7 @@ var tree = async (ctx) => {
|
|
|
60
64
|
await ctx.stderr.writeText(handlerResult.error);
|
|
61
65
|
return 1;
|
|
62
66
|
}
|
|
63
|
-
const { all: showAll, directoriesOnly, maxDepth, prune, ignorePatterns } = result.flags;
|
|
67
|
+
const { all: showAll, directoriesOnly, maxDepth, prune, noReport, ignorePatterns } = result.flags;
|
|
64
68
|
const targetPath = result.args[0] ?? ".";
|
|
65
69
|
if (maxDepth < 1) {
|
|
66
70
|
await ctx.stderr.writeText(`tree: Invalid level, must be greater than 0
|
|
@@ -77,7 +81,8 @@ var tree = async (ctx) => {
|
|
|
77
81
|
return 1;
|
|
78
82
|
}
|
|
79
83
|
if (stat.isFile()) {
|
|
80
|
-
await ctx.stdout.writeText(targetPath + `
|
|
84
|
+
await ctx.stdout.writeText(noReport ? targetPath + `
|
|
85
|
+
` : targetPath + `
|
|
81
86
|
|
|
82
87
|
0 directories, 1 file
|
|
83
88
|
`);
|
|
@@ -165,15 +170,17 @@ var tree = async (ctx) => {
|
|
|
165
170
|
}
|
|
166
171
|
}
|
|
167
172
|
await printTree(resolvedPath, "", 1);
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
173
|
+
if (!noReport) {
|
|
174
|
+
const dirWord = dirCount === 1 ? "directory" : "directories";
|
|
175
|
+
const fileWord = fileCount === 1 ? "file" : "files";
|
|
176
|
+
await ctx.stdout.writeText(`
|
|
171
177
|
${dirCount} ${dirWord}, ${fileCount} ${fileWord}
|
|
172
178
|
`);
|
|
179
|
+
}
|
|
173
180
|
return 0;
|
|
174
181
|
};
|
|
175
182
|
export {
|
|
176
183
|
tree
|
|
177
184
|
};
|
|
178
185
|
|
|
179
|
-
//# debugId=
|
|
186
|
+
//# debugId=F796F052BBAF936964756E2164756E21
|