📄 sort.c
字号:
if (key->sword != (size_t) -1) line->keybeg = begfield (line, key); else { if (key->skipsblanks) while (blanks[UCHAR (*line_start)]) line_start++; line->keybeg = line_start; } if (key->skipeblanks) trim_trailing_blanks (line->keybeg, &line->keylim); } line_start = ptr; } ptr = ptrlim; if (buf->eof) break; } buf->used = ptr - buf->buf; buf->nlines = buffer_linelim (buf) - line; if (buf->nlines != 0) { buf->left = ptr - line_start; merge_buffer_size = mergesize + MIN_MERGE_BUFFER_SIZE; return 1; } /* The current input line is too long to fit in the buffer. Double the buffer size and try again. */ if (2 * buf->alloc < buf->alloc) xalloc_die (); buf->alloc *= 2; buf->buf = xrealloc (buf->buf, buf->alloc); }}/* Compare strings A and B containing decimal fractions < 1. Each string should begin with a decimal point followed immediately by the digits of the fraction. Strings not of this form are considered to be zero. *//* The goal here, is to take two numbers a and b... compare these in parallel. Instead of converting each, and then comparing the outcome. Most likely stopping the comparison before the conversion is complete. The algorithm used, in the old sort: Algorithm: fraccompare Action : compare two decimal fractions accepts : char *a, char *b returns : -1 if a<b, 0 if a=b, 1 if a>b. implement: if *a == decimal_point AND *b == decimal_point find first character different in a and b. if both are digits, return the difference *a - *b. if *a is a digit skip past zeros if digit return 1, else 0 if *b is a digit skip past zeros if digit return -1, else 0 if *a is a decimal_point skip past decimal_point and zeros if digit return 1, else 0 if *b is a decimal_point skip past decimal_point and zeros if digit return -1, else 0 return 0 */static intfraccompare (register const char *a, register const char *b){ if (*a == decimal_point && *b == decimal_point) { while (*++a == *++b) if (! ISDIGIT (*a)) return 0; if (ISDIGIT (*a) && ISDIGIT (*b)) return *a - *b; if (ISDIGIT (*a)) goto a_trailing_nonzero; if (ISDIGIT (*b)) goto b_trailing_nonzero; return 0; } else if (*a++ == decimal_point) { a_trailing_nonzero: while (*a == NUMERIC_ZERO) a++; return ISDIGIT (*a); } else if (*b++ == decimal_point) { b_trailing_nonzero: while (*b == NUMERIC_ZERO) b++; return - ISDIGIT (*b); } return 0;}/* Compare strings A and B as numbers without explicitly converting them to machine numbers. Comparatively slow for short strings, but asymptotically hideously fast. */static intnumcompare (register const char *a, register const char *b){ register int tmpa, tmpb, tmp; register size_t loga, logb; tmpa = *a; tmpb = *b; while (blanks[UCHAR (tmpa)]) tmpa = *++a; while (blanks[UCHAR (tmpb)]) tmpb = *++b; if (tmpa == NEGATION_SIGN) { do tmpa = *++a; while (tmpa == NUMERIC_ZERO || IS_THOUSANDS_SEP (tmpa)); if (tmpb != NEGATION_SIGN) { if (tmpa == decimal_point) do tmpa = *++a; while (tmpa == NUMERIC_ZERO); if (ISDIGIT (tmpa)) return -1; while (tmpb == NUMERIC_ZERO || IS_THOUSANDS_SEP (tmpb)) tmpb = *++b; if (tmpb == decimal_point) do tmpb = *++b; while (tmpb == NUMERIC_ZERO); if (ISDIGIT (tmpb)) return -1; return 0; } do tmpb = *++b; while (tmpb == NUMERIC_ZERO || IS_THOUSANDS_SEP (tmpb)); while (tmpa == tmpb && ISDIGIT (tmpa)) { do tmpa = *++a; while (IS_THOUSANDS_SEP (tmpa)); do tmpb = *++b; while (IS_THOUSANDS_SEP (tmpb)); } if ((tmpa == decimal_point && !ISDIGIT (tmpb)) || (tmpb == decimal_point && !ISDIGIT (tmpa))) return -fraccompare (a, b); tmp = tmpb - tmpa; for (loga = 0; ISDIGIT (tmpa); ++loga) do tmpa = *++a; while (IS_THOUSANDS_SEP (tmpa)); for (logb = 0; ISDIGIT (tmpb); ++logb) do tmpb = *++b; while (IS_THOUSANDS_SEP (tmpb)); if (loga != logb) return loga < logb ? 1 : -1; if (!loga) return 0; return tmp; } else if (tmpb == NEGATION_SIGN) { do tmpb = *++b; while (tmpb == NUMERIC_ZERO || IS_THOUSANDS_SEP (tmpb)); if (tmpb == decimal_point) do tmpb = *++b; while (tmpb == NUMERIC_ZERO); if (ISDIGIT (tmpb)) return 1; while (tmpa == NUMERIC_ZERO || IS_THOUSANDS_SEP (tmpa)) tmpa = *++a; if (tmpa == decimal_point) do tmpa = *++a; while (tmpa == NUMERIC_ZERO); if (ISDIGIT (tmpa)) return 1; return 0; } else { while (tmpa == NUMERIC_ZERO || IS_THOUSANDS_SEP (tmpa)) tmpa = *++a; while (tmpb == NUMERIC_ZERO || IS_THOUSANDS_SEP (tmpb)) tmpb = *++b; while (tmpa == tmpb && ISDIGIT (tmpa)) { do tmpa = *++a; while (IS_THOUSANDS_SEP (tmpa)); do tmpb = *++b; while (IS_THOUSANDS_SEP (tmpb)); } if ((tmpa == decimal_point && !ISDIGIT (tmpb)) || (tmpb == decimal_point && !ISDIGIT (tmpa))) return fraccompare (a, b); tmp = tmpa - tmpb; for (loga = 0; ISDIGIT (tmpa); ++loga) do tmpa = *++a; while (IS_THOUSANDS_SEP (tmpa)); for (logb = 0; ISDIGIT (tmpb); ++logb) do tmpb = *++b; while (IS_THOUSANDS_SEP (tmpb)); if (loga != logb) return loga < logb ? -1 : 1; if (!loga) return 0; return tmp; }}static intgeneral_numcompare (const char *sa, const char *sb){ /* FIXME: add option to warn about failed conversions. */ /* FIXME: maybe add option to try expensive FP conversion only if A and B can't be compared more cheaply/accurately. */ char *ea; char *eb; double a = strtod (sa, &ea); double b = strtod (sb, &eb); /* Put conversion errors at the start of the collating sequence. */ if (sa == ea) return sb == eb ? 0 : -1; if (sb == eb) return 1; /* Sort numbers in the usual way, where -0 == +0. Put NaNs after conversion errors but before numbers; sort them by internal bit-pattern, for lack of a more portable alternative. */ return (a < b ? -1 : a > b ? 1 : a == b ? 0 : b == b ? -1 : a == a ? 1 : memcmp ((char *) &a, (char *) &b, sizeof a));}/* Return an integer in 1..12 of the month name S with length LEN. Return 0 if the name in S is not recognized. */static intgetmonth (const char *s, size_t len){ char *month; register size_t i; register int lo = 0, hi = MONTHS_PER_YEAR, result; while (len > 0 && blanks[UCHAR (*s)]) { ++s; --len; } if (len == 0) return 0; month = (char *) alloca (len + 1); for (i = 0; i < len; ++i) month[i] = fold_toupper[UCHAR (s[i])]; while (blanks[UCHAR (month[i - 1])]) --i; month[i] = '\0'; do { int ix = (lo + hi) / 2; if (strncmp (month, monthtab[ix].name, strlen (monthtab[ix].name)) < 0) hi = ix; else lo = ix; } while (hi - lo > 1); result = (!strncmp (month, monthtab[lo].name, strlen (monthtab[lo].name)) ? monthtab[lo].val : 0); return result;}/* Compare two lines A and B trying every key in sequence until there are no more keys or a difference is found. */static intkeycompare (const struct line *a, const struct line *b){ struct keyfield *key = keylist; /* For the first iteration only, the key positions have been precomputed for us. */ register char *texta = a->keybeg; register char *textb = b->keybeg; register char *lima = a->keylim; register char *limb = b->keylim; int diff; for (;;) { register unsigned char *translate = (unsigned char *) key->translate; register int *ignore = key->ignore; /* Find the lengths. */ size_t lena = lima <= texta ? 0 : lima - texta; size_t lenb = limb <= textb ? 0 : limb - textb; if (key->skipeblanks) { char *a_end = texta + lena; char *b_end = textb + lenb; trim_trailing_blanks (texta, &a_end); trim_trailing_blanks (textb, &b_end); lena = a_end - texta; lenb = b_end - textb; } /* Actually compare the fields. */ if (key->numeric | key->general_numeric) { char savea = *lima, saveb = *limb; *lima = *limb = '\0'; diff = ((key->numeric ? numcompare : general_numcompare) (texta, textb)); *lima = savea, *limb = saveb; } else if (key->month) diff = getmonth (texta, lena) - getmonth (textb, lenb); /* Sorting like this may become slow, so in a simple locale the user can select a faster sort that is similar to ascii sort */ else if (HAVE_SETLOCALE && hard_LC_COLLATE) { if (ignore || translate) { char *copy_a = (char *) alloca (lena + 1 + lenb + 1); char *copy_b = copy_a + lena + 1; size_t new_len_a, new_len_b, i; /* Ignore and/or translate chars before comparing. */ for (new_len_a = new_len_b = i = 0; i < max (lena, lenb); i++) { if (i < lena) { copy_a[new_len_a] = (translate ? translate[UCHAR (texta[i])] : texta[i]); if (!ignore || !ignore[UCHAR (texta[i])]) ++new_len_a; } if (i < lenb) { copy_b[new_len_b] = (translate ? translate[UCHAR (textb[i])] : textb [i]); if (!ignore || !ignore[UCHAR (textb[i])]) ++new_len_b; } } diff = xmemcoll (copy_a, new_len_a, copy_b, new_len_b); } else if (lena == 0) diff = - NONZERO (lenb); else if (lenb == 0) goto greater; else diff = xmemcoll (texta, lena, textb, lenb); } else if (ignore) {#define CMP_WITH_IGNORE(A, B) \ do \ { \ for (;;) \ { \ while (texta < lima && ignore[UCHAR (*texta)]) \ ++texta; \ while (textb < limb && ignore[UCHAR (*textb)]) \ ++textb; \ if (! (texta < lima && textb < limb)) \ break; \ diff = UCHAR (A) - UCHAR (B); \ if (diff) \ goto not_equal; \ ++texta; \ ++textb; \ } \ \ diff = (texta < lima) - (textb < limb); \ } \ while (0) if (translate) CMP_WITH_IGNORE (translate[UCHAR (*texta)], translate[UCHAR (*textb)]); else CMP_WITH_IGNORE (UCHAR (*texta), UCHAR (*textb)); } else if (lena == 0) diff = - NONZERO (lenb); else if (lenb == 0) goto greater; else { if (translate) { while (texta < lima && textb < limb) { diff = (UCHAR (translate[UCHAR (*texta++)]) - UCHAR (translate[UCHAR (*textb++)])); if (diff) goto not_equal; } } else { diff = memcmp (texta, textb, min (lena, lenb)); if (diff) goto not_equal; } diff = lena < lenb ? -1 : lena != lenb; } if (diff) goto not_equal; key = key->next; if (! key) break; /* Find the beginning and limit of the next field. */ if (key->eword != (size_t) -1) lima = limfield (a, key), limb = limfield (b, key); else lima = a->text + a->length - 1, limb = b->text + b->length - 1; if (key->sword != (size_t) -1) texta = begfield (a, key), textb = begfield (b, key); else { texta = a->text, textb = b->text; if (key->skipsblanks) { while (texta < lima && blanks[UCHAR (*texta)]) ++texta; while (textb < limb && blanks[UCHAR (*textb)]) ++textb; } } } return 0; greater: diff = 1; not_equal: return key->reverse ? -diff : diff;}/* Compare two lines A and B, returning negative, zero, or positive depending on whether A compares less than, equal to, or greater than B. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -