Updates to coreutils

This commit is contained in:
Raven Scott
2026-04-03 22:37:04 -04:00
parent 35ac6633ea
commit eeef3da6e1
17 changed files with 883 additions and 120 deletions
+30 -2
View File
@@ -2,6 +2,8 @@ async function run(ctx, argv) {
const vfs = ctx.vfs
let showAll = false
let longFmt = false
/** One name per line (GNU **`-1`** / **`--format=single-column`**, or piped/captured stdout). */
let singleColumn = false
/** @type {'never' | 'auto' | 'always'} */
let colorMode = 'auto'
const paths = []
@@ -23,6 +25,10 @@ async function run(ctx, argv) {
else colorMode = 'auto'
continue
}
if (a === '--format=single-column' || a === '--format=vertical') {
singleColumn = true
continue
}
ctx.console.error('ls: unrecognized option ' + a)
ctx.exitCode = 2
return
@@ -32,7 +38,7 @@ async function run(ctx, argv) {
const c = a[j]
if (c === 'a') showAll = true
else if (c === 'l') longFmt = true
else if (c === '1') longFmt = false
else if (c === '1') singleColumn = true
}
continue
}
@@ -40,6 +46,8 @@ async function run(ctx, argv) {
}
const targets = paths.length ? paths : ['.']
const useColor = bareLsUseColor(ctx, colorMode)
const onePerLine =
singleColumn || ctx.bareOsStdoutCaptured === true
for (const t of targets) {
if (targets.length > 1) ctx.console.log(t + ':')
@@ -61,7 +69,27 @@ async function run(ctx, argv) {
}
if (!showAll) names = names.filter((n) => !n.startsWith('.'))
if (!longFmt) {
if (!useColor) {
if (onePerLine) {
for (const n of names) {
if (!useColor) {
ctx.console.log(n)
} else {
const sub =
singleEntryPath != null
? singleEntryPath
: t === '.' || t === './'
? n
: t.replace(/\/$/, '') + '/' + n
let st = null
try {
st = await vfs.lstat(sub)
} catch {
st = null
}
ctx.console.log(bareLsColorWrap(n, st, true, ctx))
}
}
} else if (!useColor) {
ctx.console.log(names.join(' '))
} else {
const parts = []
+188 -28
View File
@@ -21,12 +21,75 @@ function sortKeySlice(line, delim, start1, end1) {
return slice.join(' ')
}
/**
* @param {object} o
* @param {string} o.line
* @param {boolean} o.numeric
* @param {boolean} o.fold
* @param {number | null} o.keyStart
* @param {number | null} o.keyEnd
* @param {string | null} o.dForKey
*/
function sortKeyObj(o) {
const keyText =
o.keyStart != null
? sortKeySlice(o.line, o.dForKey, o.keyStart, o.keyEnd)
: o.line
if (o.numeric) {
const m = String(keyText).match(
/^\s*(-?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?)/
)
if (m) return { n: Number(m[1]), raw: keyText }
return { n: Number.POSITIVE_INFINITY, raw: keyText }
}
if (o.fold) return { n: 0, raw: keyText.toLowerCase() }
return { n: 0, raw: keyText }
}
/**
* @param {string} x
* @param {string} y
* @param {object} opts
* @param {boolean} opts.numeric
* @param {boolean} opts.reverse
* @param {boolean} opts.fold
* @param {number | null} opts.keyStart
* @param {number | null} opts.keyEnd
* @param {string | null} opts.dForKey
* @returns {number}
*/
function sortCompareLines(x, y, opts) {
const base = {
numeric: opts.numeric,
fold: opts.fold,
keyStart: opts.keyStart,
keyEnd: opts.keyEnd,
dForKey: opts.dForKey
}
const kx = sortKeyObj({ ...base, line: x })
const ky = sortKeyObj({ ...base, line: y })
if (opts.numeric) {
if (kx.n !== ky.n) {
const ord = kx.n < ky.n ? -1 : 1
return opts.reverse ? -ord : ord
}
}
const cmp =
kx.raw < ky.raw ? -1 : kx.raw > ky.raw ? 1 : x < y ? -1 : x > y ? 1 : 0
return opts.reverse ? -cmp : cmp
}
async function run(ctx, argv) {
const vfs = ctx.vfs
let numeric = false
let reverse = false
let uniq = false
let fold = false
/** @type {'off' | 'verbose' | 'quiet'} */
let checkMode = 'off'
let stable = false
/** @type {string | null} */
let outFile = null
/** @type {string | undefined} */
let delim
/** @type {number | null} */
@@ -40,6 +103,52 @@ async function run(ctx, argv) {
i++
break
}
if (a === '--check' || a === '--check=diagnose-first') {
checkMode = 'verbose'
i++
continue
}
if (a === '--check=silent' || a === '--check=quiet') {
checkMode = 'quiet'
i++
continue
}
if (a === '-C') {
checkMode = 'quiet'
i++
continue
}
if (a === '-c') {
checkMode = 'verbose'
i++
continue
}
if (a === '-s' || a === '--stable') {
stable = true
i++
continue
}
if (a === '-o' || a === '--output') {
const f = argv[++i]
if (f === undefined) {
ctx.console.error('sort: option requires an argument -- output')
ctx.exitCode = 1
return
}
outFile = f
i++
continue
}
if (a.startsWith('--output=')) {
outFile = a.slice('--output='.length) || null
if (!outFile) {
ctx.console.error('sort: option requires an argument -- output')
ctx.exitCode = 1
return
}
i++
continue
}
if (a === '-n' || a === '--numeric-sort' || a === '-g') {
numeric = true
i++
@@ -130,6 +239,9 @@ async function run(ctx, argv) {
else if (c === 'r') reverse = true
else if (c === 'u') uniq = true
else if (c === 'f') fold = true
else if (c === 'c') checkMode = 'verbose'
else if (c === 'C') checkMode = 'quiet'
else if (c === 's') stable = true
else {
ok = false
break
@@ -172,37 +284,73 @@ async function run(ctx, argv) {
}
const dForKey = delim === undefined ? null : delim
/** @param {string} s */
function sortKey(s) {
const keyText =
keyStart != null
? sortKeySlice(s, dForKey, keyStart, keyEnd)
: s
if (numeric) {
const m = String(keyText).match(
/^\s*(-?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?)/
)
if (m) return { n: Number(m[1]), raw: keyText }
return { n: Number.POSITIVE_INFINITY, raw: keyText }
}
if (fold) return { n: 0, raw: keyText.toLowerCase() }
return { n: 0, raw: keyText }
const cmpOpts = {
numeric,
reverse,
fold,
keyStart,
keyEnd,
dForKey
}
lines.sort((x, y) => {
const kx = sortKey(x)
const ky = sortKey(y)
if (numeric) {
if (kx.n !== ky.n) {
const ord = kx.n < ky.n ? -1 : 1
return reverse ? -ord : ord
if (checkMode !== 'off') {
const checkLabel = files.length === 1 ? files[0] : '-'
for (let li = 0; li < lines.length - 1; li++) {
const aLine = lines[li]
const bLine = lines[li + 1]
const c = sortCompareLines(aLine, bLine, cmpOpts)
if (uniq && c === 0) {
ctx.exitCode = 1
if (checkMode === 'verbose') {
ctx.console.error(
'sort: ' +
checkLabel +
':' +
(li + 2) +
': disorder: ' +
bLine
)
}
return
}
if (c > 0) {
ctx.exitCode = 1
if (checkMode === 'verbose') {
ctx.console.error(
'sort: ' +
checkLabel +
':' +
(li + 2) +
': disorder: ' +
bLine
)
}
return
}
}
const cmp =
kx.raw < ky.raw ? -1 : kx.raw > ky.raw ? 1 : x < y ? -1 : x > y ? 1 : 0
return reverse ? -cmp : cmp
})
ctx.exitCode = 0
return
}
/** @param {string} x
* @param {string} y */
function cmpPair(x, y) {
const primary = sortCompareLines(x, y, cmpOpts)
if (primary !== 0 || !stable) return primary
return 0
}
if (stable) {
const decorated = lines.map((line, idx) => ({ line, idx }))
decorated.sort((a, b) => {
const p = sortCompareLines(a.line, b.line, cmpOpts)
if (p !== 0) return p
return a.idx - b.idx
})
lines = decorated.map((d) => d.line)
} else {
lines.sort(cmpPair)
}
if (uniq) {
const out = []
@@ -214,5 +362,17 @@ async function run(ctx, argv) {
lines = out
}
if (lines.length) ctx.console.log(lines.join('\n'))
const body = lines.length ? lines.join('\n') + '\n' : ''
if (outFile != null) {
try {
await vfs.writeFile(outFile, ctx.b4a.from(body))
} catch (e) {
ctx.console.error('sort: ' + outFile + ': ' + (e.message || e))
ctx.exitCode = 1
return
}
} else if (lines.length) {
ctx.console.log(lines.join('\n'))
}
}