Updates to coreutils
This commit is contained in:
@@ -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 = []
|
||||
|
||||
@@ -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'))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user