⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sort.c

📁 Linux.Programming.by example 的源代码绝对经典
💻 C
📖 第 1 页 / 共 5 页
字号:
		  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 + -