This commit is contained in:
Raven Scott
2026-04-04 18:41:34 -04:00
parent 7cf1a8d1c5
commit d75f4e7383
29 changed files with 1219 additions and 469 deletions
+46 -16
View File
@@ -87,30 +87,54 @@ function bareOsEmitRaw(ctx, chunk) {
return false
}
/**
* @param {string} raw
* @param {number} curLen
* @returns {number | null}
*/
function resolveTruncateSize(raw, curLen) {
const s = String(raw).trim()
if (!s) return null
if (/%$/.test(s)) {
const inner = s.startsWith('+') || s.startsWith('-') ? s.slice(1) : s
const pct = Number.parseFloat(inner.replace(/%$/, ''))
if (!Number.isFinite(pct)) return null
const delta = Math.floor((curLen * pct) / 100)
if (s.startsWith('+')) return Math.max(0, curLen + delta)
if (s.startsWith('-')) return Math.max(0, curLen - delta)
return Math.max(0, Math.floor((curLen * pct) / 100))
}
if (s.startsWith('+')) {
const n = Number.parseInt(s.slice(1), 10)
if (!Number.isFinite(n)) return null
return Math.max(0, curLen + n)
}
if (s.startsWith('-')) {
const n = Number.parseInt(s.slice(1), 10)
if (!Number.isFinite(n)) return null
return Math.max(0, curLen - n)
}
const abs = Number.parseInt(s, 10)
if (!Number.isFinite(abs) || abs < 0) return null
return abs
}
async function run(ctx, argv) {
let size = null
/** @type {string | null} */
let sizeSpec = null
const paths = []
for (let i = 1; i < argv.length; i++) {
const a = argv[i]
if (a === '-h' || a === '--help') {
ctx.console.log(
'usage: truncate -s SIZE FILE\nSet file length to SIZE bytes (padded with zeros if growing).'
'usage: truncate -s SIZE FILE\n' +
'SIZE: bytes, +N, -N, +N%, -N%, or N% (of current length).\n' +
'Sets file length (padded with zeros if growing).'
)
return
}
if ((a === '-s' || a === '--size') && argv[i + 1]) {
const raw = argv[++i]
if (raw.startsWith('+') || raw.startsWith('-')) {
ctx.console.error('truncate: relative sizes not supported')
ctx.exitCode = 1
return
}
size = parseInt(raw, 10)
if (!Number.isFinite(size) || size < 0) {
ctx.console.error('truncate: invalid size')
ctx.exitCode = 1
return
}
sizeSpec = argv[++i]
continue
}
if (a.startsWith('-')) {
@@ -120,7 +144,7 @@ async function run(ctx, argv) {
}
paths.push(a)
}
if (size == null || paths.length !== 1) {
if (!sizeSpec || paths.length !== 1) {
ctx.console.error('usage: truncate -s SIZE FILE')
ctx.exitCode = 1
return
@@ -131,7 +155,13 @@ async function run(ctx, argv) {
const b = await ctx.vfs.readFile(file)
if (b) cur = b instanceof Uint8Array ? b : new Uint8Array(b)
} catch {
/* new file */
/* new file — relative sizes use curLen 0 */
}
const size = resolveTruncateSize(sizeSpec, cur.length)
if (size == null) {
ctx.console.error('truncate: invalid size: ' + sizeSpec)
ctx.exitCode = 1
return
}
const out = new Uint8Array(size)
out.set(cur.subarray(0, Math.min(cur.length, size)))