sort: support -h
function old new delta static.scale_suffix - 62 +62 .rodata 104304 104336 +32 compare_keys 820 848 +28 packed_usage 34159 34184 +25 static.suffix - 9 +9 sort_opt_str 37 38 +1 ------------------------------------------------------------------------------ (add/remove: 2/0 grow/shrink: 4/0 up/down: 157/0) Total: 157 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
cc7d2e2178
commit
34e0bb3931
@ -18,7 +18,7 @@
|
|||||||
//config: sort is used to sort lines of text in specified files.
|
//config: sort is used to sort lines of text in specified files.
|
||||||
//config:
|
//config:
|
||||||
//config:config FEATURE_SORT_BIG
|
//config:config FEATURE_SORT_BIG
|
||||||
//config: bool "Full SuSv3 compliant sort (support -ktcbdfiogM)"
|
//config: bool "Full SuSv3 compliant sort (support -ktcbdfioghM)"
|
||||||
//config: default y
|
//config: default y
|
||||||
//config: depends on SORT
|
//config: depends on SORT
|
||||||
//config: help
|
//config: help
|
||||||
@ -43,7 +43,7 @@
|
|||||||
|
|
||||||
//usage:#define sort_trivial_usage
|
//usage:#define sort_trivial_usage
|
||||||
//usage: "[-nru"
|
//usage: "[-nru"
|
||||||
//usage: IF_FEATURE_SORT_BIG("gMcszbdfiokt] [-o FILE] [-k START[.OFS][OPTS][,END[.OFS][OPTS]] [-t CHAR")
|
//usage: IF_FEATURE_SORT_BIG("ghMcszbdfiokt] [-o FILE] [-k START[.OFS][OPTS][,END[.OFS][OPTS]] [-t CHAR")
|
||||||
//usage: "] [FILE]..."
|
//usage: "] [FILE]..."
|
||||||
//usage:#define sort_full_usage "\n\n"
|
//usage:#define sort_full_usage "\n\n"
|
||||||
//usage: "Sort lines of text\n"
|
//usage: "Sort lines of text\n"
|
||||||
@ -59,6 +59,7 @@
|
|||||||
//usage: "\n -n Sort numbers"
|
//usage: "\n -n Sort numbers"
|
||||||
//usage: IF_FEATURE_SORT_BIG(
|
//usage: IF_FEATURE_SORT_BIG(
|
||||||
//usage: "\n -g General numerical sort"
|
//usage: "\n -g General numerical sort"
|
||||||
|
//usage: "\n -h Sort human readable numbers (2K 1G)"
|
||||||
//usage: "\n -M Sort month"
|
//usage: "\n -M Sort month"
|
||||||
//usage: "\n -V Sort version"
|
//usage: "\n -V Sort version"
|
||||||
//usage: "\n -t CHAR Field separator"
|
//usage: "\n -t CHAR Field separator"
|
||||||
@ -94,31 +95,32 @@
|
|||||||
enum {
|
enum {
|
||||||
FLAG_n = 1 << 0, /* Numeric sort */
|
FLAG_n = 1 << 0, /* Numeric sort */
|
||||||
FLAG_g = 1 << 1, /* Sort using strtod() */
|
FLAG_g = 1 << 1, /* Sort using strtod() */
|
||||||
FLAG_M = 1 << 2, /* Sort date */
|
FLAG_h = 1 << 2, /* Sort using strtod(), plus KMGT suffixes */
|
||||||
FLAG_V = 1 << 3, /* Sort version */
|
FLAG_M = 1 << 3, /* Sort date */
|
||||||
|
FLAG_V = 1 << 4, /* Sort version */
|
||||||
/* ucsz apply to root level only, not keys. b at root level implies bb */
|
/* ucsz apply to root level only, not keys. b at root level implies bb */
|
||||||
FLAG_u = 1 << 4, /* Unique */
|
FLAG_u = 1 << 5, /* Unique */
|
||||||
FLAG_c = 1 << 5, /* Check: no output, exit(!ordered) */
|
FLAG_c = 1 << 6, /* Check: no output, exit(!ordered) */
|
||||||
FLAG_s = 1 << 6, /* Stable sort, no ascii fallback at end */
|
FLAG_s = 1 << 7, /* Stable sort, no ascii fallback at end */
|
||||||
FLAG_z = 1 << 7, /* Input and output is NUL terminated, not \n */
|
FLAG_z = 1 << 8, /* Input and output is NUL terminated, not \n */
|
||||||
/* These can be applied to search keys, the previous four can't */
|
/* These can be applied to search keys, the previous four can't */
|
||||||
FLAG_b = 1 << 8, /* Ignore leading blanks */
|
FLAG_b = 1 << 9, /* Ignore leading blanks */
|
||||||
FLAG_r = 1 << 9, /* Reverse */
|
FLAG_r = 1 << 10, /* Reverse */
|
||||||
FLAG_d = 1 << 10, /* Ignore !(isalnum()|isspace()) */
|
FLAG_d = 1 << 11, /* Ignore !(isalnum()|isspace()) */
|
||||||
FLAG_f = 1 << 11, /* Force uppercase */
|
FLAG_f = 1 << 12, /* Force uppercase */
|
||||||
FLAG_i = 1 << 12, /* Ignore !isprint() */
|
FLAG_i = 1 << 13, /* Ignore !isprint() */
|
||||||
FLAG_m = 1 << 13, /* ignored: merge already sorted files; do not sort */
|
FLAG_m = 1 << 14, /* ignored: merge already sorted files; do not sort */
|
||||||
FLAG_S = 1 << 14, /* ignored: -S, --buffer-size=SIZE */
|
FLAG_S = 1 << 15, /* ignored: -S, --buffer-size=SIZE */
|
||||||
FLAG_T = 1 << 15, /* ignored: -T, --temporary-directory=DIR */
|
FLAG_T = 1 << 16, /* ignored: -T, --temporary-directory=DIR */
|
||||||
FLAG_o = 1 << 16,
|
FLAG_o = 1 << 17,
|
||||||
FLAG_k = 1 << 17,
|
FLAG_k = 1 << 18,
|
||||||
FLAG_t = 1 << 18,
|
FLAG_t = 1 << 19,
|
||||||
FLAG_bb = 0x80000000, /* Ignore trailing blanks */
|
FLAG_bb = 0x80000000, /* Ignore trailing blanks */
|
||||||
FLAG_no_tie_break = 0x40000000,
|
FLAG_no_tie_break = 0x40000000,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char sort_opt_str[] ALIGN1 = "^"
|
static const char sort_opt_str[] ALIGN1 = "^"
|
||||||
"ngMVucszbrdfimS:T:o:k:*t:"
|
"nghMVucszbrdfimS:T:o:k:*t:"
|
||||||
"\0" "o--o:t--t"/*-t, -o: at most one of each*/;
|
"\0" "o--o:t--t"/*-t, -o: at most one of each*/;
|
||||||
/*
|
/*
|
||||||
* OPT_STR must not be string literal, needs to have stable address:
|
* OPT_STR must not be string literal, needs to have stable address:
|
||||||
@ -253,6 +255,25 @@ static struct sort_key *add_key(void)
|
|||||||
#define GET_LINE(fp) xmalloc_fgetline(fp)
|
#define GET_LINE(fp) xmalloc_fgetline(fp)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if ENABLE_FEATURE_SORT_BIG
|
||||||
|
static int scale_suffix(const char *tail)
|
||||||
|
{
|
||||||
|
static const char suffix[] ALIGN1 = "kmgtpezy";
|
||||||
|
const char *s;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (!tail[0])
|
||||||
|
return -1;
|
||||||
|
s = strchr(suffix, tail[0] | 0x20);
|
||||||
|
if (!s)
|
||||||
|
return -1;
|
||||||
|
n = s - suffix;
|
||||||
|
if (n != 0 && tail[0] >= 'a')
|
||||||
|
return -1; /* mg... not accepted, only MG... */
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Iterate through keys list and perform comparisons */
|
/* Iterate through keys list and perform comparisons */
|
||||||
static int compare_keys(const void *xarg, const void *yarg)
|
static int compare_keys(const void *xarg, const void *yarg)
|
||||||
{
|
{
|
||||||
@ -275,7 +296,7 @@ static int compare_keys(const void *xarg, const void *yarg)
|
|||||||
y = *(char **)yarg;
|
y = *(char **)yarg;
|
||||||
#endif
|
#endif
|
||||||
/* Perform actual comparison */
|
/* Perform actual comparison */
|
||||||
switch (flags & (FLAG_n | FLAG_g | FLAG_M | FLAG_V)) {
|
switch (flags & (FLAG_n | FLAG_g | FLAG_h | FLAG_M | FLAG_V)) {
|
||||||
default:
|
default:
|
||||||
bb_simple_error_msg_and_die("unknown sort type");
|
bb_simple_error_msg_and_die("unknown sort type");
|
||||||
break;
|
break;
|
||||||
@ -293,7 +314,8 @@ static int compare_keys(const void *xarg, const void *yarg)
|
|||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
#if ENABLE_FEATURE_SORT_BIG
|
#if ENABLE_FEATURE_SORT_BIG
|
||||||
case FLAG_g: {
|
case FLAG_g:
|
||||||
|
case FLAG_h: {
|
||||||
char *xx, *yy;
|
char *xx, *yy;
|
||||||
//TODO: needs setlocale(LC_NUMERIC, "C")?
|
//TODO: needs setlocale(LC_NUMERIC, "C")?
|
||||||
double dx = strtod(x, &xx);
|
double dx = strtod(x, &xx);
|
||||||
@ -308,16 +330,26 @@ static int compare_keys(const void *xarg, const void *yarg)
|
|||||||
retval = (dy != dy) ? 0 : -1;
|
retval = (dy != dy) ? 0 : -1;
|
||||||
else if (dy != dy)
|
else if (dy != dy)
|
||||||
retval = 1;
|
retval = 1;
|
||||||
/* Check for infinity. Could underflow, but it avoids libm. */
|
else {
|
||||||
else if (1.0 / dx == 0.0) {
|
if (flags & FLAG_h) {
|
||||||
if (dx < 0)
|
int xs = scale_suffix(xx);
|
||||||
retval = (1.0 / dy == 0.0 && dy < 0) ? 0 : -1;
|
int ys = scale_suffix(yy);
|
||||||
|
if (xs != ys) {
|
||||||
|
retval = xs - ys;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Check for infinity. Could underflow, but it avoids libm. */
|
||||||
|
if (1.0 / dx == 0.0) {
|
||||||
|
if (dx < 0)
|
||||||
|
retval = (1.0 / dy == 0.0 && dy < 0) ? 0 : -1;
|
||||||
|
else
|
||||||
|
retval = (1.0 / dy == 0.0 && dy > 0) ? 0 : 1;
|
||||||
|
} else if (1.0 / dy == 0.0)
|
||||||
|
retval = (dy < 0) ? 1 : -1;
|
||||||
else
|
else
|
||||||
retval = (1.0 / dy == 0.0 && dy > 0) ? 0 : 1;
|
retval = (dx > dy) ? 1 : ((dx < dy) ? -1 : 0);
|
||||||
} else if (1.0 / dy == 0.0)
|
}
|
||||||
retval = (dy < 0) ? 1 : -1;
|
|
||||||
else
|
|
||||||
retval = (dx > dy) ? 1 : ((dx < dy) ? -1 : 0);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FLAG_M: {
|
case FLAG_M: {
|
||||||
@ -476,6 +508,7 @@ int sort_main(int argc UNUSED_PARAM, char **argv)
|
|||||||
FLAG_allowed_for_k =
|
FLAG_allowed_for_k =
|
||||||
FLAG_n | /* Numeric sort */
|
FLAG_n | /* Numeric sort */
|
||||||
FLAG_g | /* Sort using strtod() */
|
FLAG_g | /* Sort using strtod() */
|
||||||
|
FLAG_h | /* Sort using strtod(), plus KMGT suffixes */
|
||||||
FLAG_M | /* Sort date */
|
FLAG_M | /* Sort date */
|
||||||
FLAG_b | /* Ignore leading blanks */
|
FLAG_b | /* Ignore leading blanks */
|
||||||
FLAG_r | /* Reverse */
|
FLAG_r | /* Reverse */
|
||||||
|
@ -188,6 +188,35 @@ c 1
|
|||||||
d 2
|
d 2
|
||||||
" ""
|
" ""
|
||||||
|
|
||||||
|
testing "sort -h" \
|
||||||
|
"sort -h input" "\
|
||||||
|
3e
|
||||||
|
4m
|
||||||
|
5y
|
||||||
|
1023
|
||||||
|
1024
|
||||||
|
1025
|
||||||
|
3000
|
||||||
|
2K
|
||||||
|
3k
|
||||||
|
1M
|
||||||
|
2E
|
||||||
|
1Y
|
||||||
|
" "\
|
||||||
|
1Y
|
||||||
|
5y
|
||||||
|
1M
|
||||||
|
2E
|
||||||
|
3k
|
||||||
|
3e
|
||||||
|
2K
|
||||||
|
4m
|
||||||
|
1023
|
||||||
|
1025
|
||||||
|
3000
|
||||||
|
1024
|
||||||
|
" ""
|
||||||
|
|
||||||
# testing "description" "command(s)" "result" "infile" "stdin"
|
# testing "description" "command(s)" "result" "infile" "stdin"
|
||||||
|
|
||||||
exit $FAILCOUNT
|
exit $FAILCOUNT
|
||||||
|
Loading…
Reference in New Issue
Block a user