Updates to coreutils
This commit is contained in:
+188
-28
@@ -110,12 +110,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} */
|
||||
@@ -129,6 +192,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++
|
||||
@@ -219,6 +328,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
|
||||
@@ -261,37 +373,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 = []
|
||||
@@ -303,5 +451,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