forked from aniani/vim
		
	patch 7.4.1143
Problem:    Can't sort on floating point numbers.
Solution:   Add the "f" flag to ":sort".  (Alex Jakushev)  Also add the "f"
            flag to sort().
			
			
This commit is contained in:
		| @@ -1,4 +1,4 @@ | ||||
| *change.txt*    For Vim version 7.4.  Last change: 2016 Jan 02 | ||||
| *change.txt*    For Vim version 7.4.  Last change: 2016 Jan 19 | ||||
|  | ||||
|  | ||||
| 		  VIM REFERENCE MANUAL    by Bram Moolenaar | ||||
| @@ -1745,7 +1745,7 @@ Vim has a sorting function and a sorting command.  The sorting function can be | ||||
| found here: |sort()|, |uniq()|. | ||||
|  | ||||
| 							*:sor* *:sort* | ||||
| :[range]sor[t][!] [i][u][r][n][x][o][b] [/{pattern}/] | ||||
| :[range]sor[t][!] [b][f][i][n][o][r][u][x] [/{pattern}/] | ||||
| 			Sort lines in [range].  When no range is given all | ||||
| 			lines are sorted. | ||||
|  | ||||
| @@ -1753,10 +1753,18 @@ found here: |sort()|, |uniq()|. | ||||
|  | ||||
| 			With [i] case is ignored. | ||||
|  | ||||
| 			Options [n][f][x][o][b] are mutually exclusive. | ||||
|  | ||||
| 			With [n] sorting is done on the first decimal number | ||||
| 			in the line (after or inside a {pattern} match). | ||||
| 			One leading '-' is included in the number. | ||||
|  | ||||
| 			With [f] sorting is done on the Float in the line. | ||||
| 			The value of Float is determined similar to passing | ||||
| 			the text (after or inside a {pattern} match) to | ||||
| 			str2float() function. This option is available only | ||||
| 			if Vim was compiled with Floating point support. | ||||
|  | ||||
| 			With [x] sorting is done on the first hexadecimal | ||||
| 			number in the line (after or inside a {pattern} | ||||
| 			match).  A leading "0x" or "0X" is ignored. | ||||
| @@ -1768,10 +1776,10 @@ found here: |sort()|, |uniq()|. | ||||
| 			With [b] sorting is done on the first binary number in | ||||
| 			the line (after or inside a {pattern} match). | ||||
|  | ||||
| 			With [u] only keep the first of a sequence of | ||||
| 			identical lines (ignoring case when [i] is used). | ||||
| 			Without this flag, a sequence of identical lines | ||||
| 			will be kept in their original order. | ||||
| 			With [u] (u stands for unique) only keep the first of | ||||
| 			a sequence of identical lines (ignoring case when [i] | ||||
| 			is used).  Without this flag, a sequence of identical | ||||
| 			lines will be kept in their original order. | ||||
| 			Note that leading and trailing white space may cause | ||||
| 			lines to be different. | ||||
|  | ||||
|   | ||||
							
								
								
									
										60
									
								
								src/eval.c
									
									
									
									
									
								
							
							
						
						
									
										60
									
								
								src/eval.c
									
									
									
									
									
								
							| @@ -809,6 +809,9 @@ static typval_T *alloc_tv __ARGS((void)); | ||||
| static typval_T *alloc_string_tv __ARGS((char_u *string)); | ||||
| static void init_tv __ARGS((typval_T *varp)); | ||||
| static long get_tv_number __ARGS((typval_T *varp)); | ||||
| #ifdef FEAT_FLOAT | ||||
| static float_T get_tv_float(typval_T *varp); | ||||
| #endif | ||||
| static linenr_T get_tv_lnum __ARGS((typval_T *argvars)); | ||||
| static linenr_T get_tv_lnum_buf __ARGS((typval_T *argvars, buf_T *buf)); | ||||
| static char_u *get_tv_string __ARGS((typval_T *varp)); | ||||
| @@ -18143,6 +18146,9 @@ typedef struct | ||||
| static int	item_compare_ic; | ||||
| static int	item_compare_numeric; | ||||
| static int	item_compare_numbers; | ||||
| #ifdef FEAT_FLOAT | ||||
| static int	item_compare_float; | ||||
| #endif | ||||
| static char_u	*item_compare_func; | ||||
| static dict_T	*item_compare_selfdict; | ||||
| static int	item_compare_func_err; | ||||
| @@ -18182,6 +18188,16 @@ item_compare(s1, s2) | ||||
| 	return v1 == v2 ? 0 : v1 > v2 ? 1 : -1; | ||||
|     } | ||||
|  | ||||
| #ifdef FEAT_FLOAT | ||||
|     if (item_compare_float) | ||||
|     { | ||||
| 	float_T	v1 = get_tv_float(tv1); | ||||
| 	float_T	v2 = get_tv_float(tv2); | ||||
|  | ||||
| 	return v1 == v2 ? 0 : v1 > v2 ? 1 : -1; | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     /* tv2string() puts quotes around a string and allocates memory.  Don't do | ||||
|      * that for string variables. Use a single quote when comparing with a | ||||
|      * non-string to do what the docs promise. */ | ||||
| @@ -18316,6 +18332,9 @@ do_sort_uniq(argvars, rettv, sort) | ||||
| 	item_compare_ic = FALSE; | ||||
| 	item_compare_numeric = FALSE; | ||||
| 	item_compare_numbers = FALSE; | ||||
| #ifdef FEAT_FLOAT | ||||
| 	item_compare_float = FALSE; | ||||
| #endif | ||||
| 	item_compare_func = NULL; | ||||
| 	item_compare_selfdict = NULL; | ||||
| 	if (argvars[1].v_type != VAR_UNKNOWN) | ||||
| @@ -18346,6 +18365,13 @@ do_sort_uniq(argvars, rettv, sort) | ||||
| 			item_compare_func = NULL; | ||||
| 			item_compare_numbers = TRUE; | ||||
| 		    } | ||||
| #ifdef FEAT_FLOAT | ||||
| 		    else if (STRCMP(item_compare_func, "f") == 0) | ||||
| 		    { | ||||
| 			item_compare_func = NULL; | ||||
| 			item_compare_float = TRUE; | ||||
| 		    } | ||||
| #endif | ||||
| 		    else if (STRCMP(item_compare_func, "i") == 0) | ||||
| 		    { | ||||
| 			item_compare_func = NULL; | ||||
| @@ -21613,6 +21639,40 @@ get_tv_number_chk(varp, denote) | ||||
|     return n; | ||||
| } | ||||
|  | ||||
| #ifdef FEAT_FLOAT | ||||
|     static float_T | ||||
| get_tv_float(varp) | ||||
|     typval_T	*varp; | ||||
| { | ||||
|     switch (varp->v_type) | ||||
|     { | ||||
| 	case VAR_NUMBER: | ||||
| 	    return (float_T)(varp->vval.v_number); | ||||
| #ifdef FEAT_FLOAT | ||||
| 	case VAR_FLOAT: | ||||
| 	    return varp->vval.v_float; | ||||
| 	    break; | ||||
| #endif | ||||
| 	case VAR_FUNC: | ||||
| 	    EMSG(_("E891: Using a Funcref as a Float")); | ||||
| 	    break; | ||||
| 	case VAR_STRING: | ||||
| 	    EMSG(_("E892: Using a String as a Float")); | ||||
| 	    break; | ||||
| 	case VAR_LIST: | ||||
| 	    EMSG(_("E893: Using a List as a Float")); | ||||
| 	    break; | ||||
| 	case VAR_DICT: | ||||
| 	    EMSG(_("E894: Using a Dictionary as a Float")); | ||||
| 	    break; | ||||
| 	default: | ||||
| 	    EMSG2(_(e_intern2), "get_tv_float()"); | ||||
| 	    break; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * Get the lnum from the first argument. | ||||
|  * Also accepts ".", "$", etc., but that only works for the current buffer. | ||||
|   | ||||
| @@ -278,6 +278,9 @@ static char_u	*sortbuf2; | ||||
| static int	sort_ic;	/* ignore case */ | ||||
| static int	sort_nr;	/* sort on number */ | ||||
| static int	sort_rx;	/* sort on regex instead of skipping it */ | ||||
| #ifdef FEAT_FLOAT | ||||
| static int	sort_flt;	/* sort on floating number */ | ||||
| #endif | ||||
|  | ||||
| static int	sort_abort;	/* flag to indicate if sorting has been interrupted */ | ||||
|  | ||||
| @@ -285,8 +288,17 @@ static int	sort_abort;		/* flag to indicate if sorting has been interrupted */ | ||||
| typedef struct | ||||
| { | ||||
|     linenr_T	lnum;			/* line number */ | ||||
|     long	start_col_nr;		/* starting column number or number */ | ||||
|     union { | ||||
| 	struct | ||||
| 	{ | ||||
| 	    long	start_col_nr;		/* starting column number */ | ||||
| 	    long	end_col_nr;		/* ending column number */ | ||||
| 	} line; | ||||
| 	long	value;		/* value if sorting by integer */ | ||||
| #ifdef FEAT_FLOAT | ||||
| 	float_T value_flt;	/* value if sorting by float */ | ||||
| #endif | ||||
|     } st_u; | ||||
| } sorti_T; | ||||
|  | ||||
| static int | ||||
| @@ -319,19 +331,24 @@ sort_compare(s1, s2) | ||||
|     /* When sorting numbers "start_col_nr" is the number, not the column | ||||
|      * number. */ | ||||
|     if (sort_nr) | ||||
| 	result = l1.start_col_nr == l2.start_col_nr ? 0 | ||||
| 				 : l1.start_col_nr > l2.start_col_nr ? 1 : -1; | ||||
| 	result = l1.st_u.value == l2.st_u.value ? 0 | ||||
| 				 : l1.st_u.value > l2.st_u.value ? 1 : -1; | ||||
| #ifdef FEAT_FLOAT | ||||
|     else if (sort_flt) | ||||
| 	result = l1.st_u.value_flt == l2.st_u.value_flt ? 0 | ||||
| 			     : l1.st_u.value_flt > l2.st_u.value_flt ? 1 : -1; | ||||
| #endif | ||||
|     else | ||||
|     { | ||||
| 	/* We need to copy one line into "sortbuf1", because there is no | ||||
| 	 * guarantee that the first pointer becomes invalid when obtaining the | ||||
| 	 * second one. */ | ||||
| 	STRNCPY(sortbuf1, ml_get(l1.lnum) + l1.start_col_nr, | ||||
| 					 l1.end_col_nr - l1.start_col_nr + 1); | ||||
| 	sortbuf1[l1.end_col_nr - l1.start_col_nr] = 0; | ||||
| 	STRNCPY(sortbuf2, ml_get(l2.lnum) + l2.start_col_nr, | ||||
| 					 l2.end_col_nr - l2.start_col_nr + 1); | ||||
| 	sortbuf2[l2.end_col_nr - l2.start_col_nr] = 0; | ||||
| 	STRNCPY(sortbuf1, ml_get(l1.lnum) + l1.st_u.line.start_col_nr, | ||||
| 		     l1.st_u.line.end_col_nr - l1.st_u.line.start_col_nr + 1); | ||||
| 	sortbuf1[l1.st_u.line.end_col_nr - l1.st_u.line.start_col_nr] = 0; | ||||
| 	STRNCPY(sortbuf2, ml_get(l2.lnum) + l2.st_u.line.start_col_nr, | ||||
| 		     l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr + 1); | ||||
| 	sortbuf2[l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr] = 0; | ||||
|  | ||||
| 	result = sort_ic ? STRICMP(sortbuf1, sortbuf2) | ||||
| 						 : STRCMP(sortbuf1, sortbuf2); | ||||
| @@ -382,6 +399,9 @@ ex_sort(eap) | ||||
| 	goto sortend; | ||||
|  | ||||
|     sort_abort = sort_ic = sort_rx = sort_nr = 0; | ||||
| #ifdef FEAT_FLOAT | ||||
|     sort_flt = 0; | ||||
| #endif | ||||
|  | ||||
|     for (p = eap->arg; *p != NUL; ++p) | ||||
|     { | ||||
| @@ -393,9 +413,16 @@ ex_sort(eap) | ||||
| 	    sort_rx = TRUE; | ||||
| 	else if (*p == 'n') | ||||
| 	{ | ||||
| 	    sort_nr = 2; | ||||
| 	    sort_nr = 1; | ||||
| 	    ++format_found; | ||||
| 	} | ||||
| #ifdef FEAT_FLOAT | ||||
| 	else if (*p == 'f') | ||||
| 	{ | ||||
| 	    sort_flt = 1; | ||||
| 	    ++format_found; | ||||
| 	} | ||||
| #endif | ||||
| 	else if (*p == 'b') | ||||
| 	{ | ||||
| 	    sort_what = STR2NR_BIN + STR2NR_FORCE; | ||||
| @@ -460,7 +487,8 @@ ex_sort(eap) | ||||
| 	goto sortend; | ||||
|     } | ||||
|  | ||||
|     /* From here on "sort_nr" is used as a flag for any number sorting. */ | ||||
|     /* From here on "sort_nr" is used as a flag for any integer number | ||||
|      * sorting. */ | ||||
|     sort_nr += sort_what; | ||||
|  | ||||
|     /* | ||||
| @@ -494,7 +522,7 @@ ex_sort(eap) | ||||
| 	    if (regmatch.regprog != NULL) | ||||
| 		end_col = 0; | ||||
|  | ||||
| 	if (sort_nr) | ||||
| 	if (sort_nr || sort_flt) | ||||
| 	{ | ||||
| 	    /* Make sure vim_str2nr doesn't read any digits past the end | ||||
| 	     * of the match, by temporarily terminating the string there */ | ||||
| @@ -503,6 +531,8 @@ ex_sort(eap) | ||||
| 	    *s2 = NUL; | ||||
| 	    /* Sorting on number: Store the number itself. */ | ||||
| 	    p = s + start_col; | ||||
| 	    if (sort_nr) | ||||
| 	    { | ||||
| 		if (sort_what & STR2NR_HEX) | ||||
| 		    s = skiptohex(p); | ||||
| 		else if (sort_what & STR2NR_BIN) | ||||
| @@ -513,17 +543,33 @@ ex_sort(eap) | ||||
| 		    --s;  /* include preceding negative sign */ | ||||
| 		if (*s == NUL) | ||||
| 		    /* empty line should sort before any number */ | ||||
| 		nrs[lnum - eap->line1].start_col_nr = -MAXLNUM; | ||||
| 		    nrs[lnum - eap->line1].st_u.value = -MAXLNUM; | ||||
| 		else | ||||
| 		    vim_str2nr(s, NULL, NULL, sort_what, | ||||
| 			       &nrs[lnum - eap->line1].start_col_nr, NULL, 0); | ||||
| 			       &nrs[lnum - eap->line1].st_u.value, NULL, 0); | ||||
| 	    } | ||||
| #ifdef FEAT_FLOAT | ||||
| 	    else | ||||
| 	    { | ||||
| 		s = skipwhite(p); | ||||
| 		if (*s == '+') | ||||
| 		    s = skipwhite(s + 1); | ||||
|  | ||||
| 		if (*s == NUL) | ||||
| 		    /* empty line should sort before any number */ | ||||
| 		    nrs[lnum - eap->line1].st_u.value_flt = -DBL_MAX; | ||||
| 		else | ||||
| 		    nrs[lnum - eap->line1].st_u.value_flt = | ||||
| 						      strtod((char *)s, NULL); | ||||
| 	    } | ||||
| #endif | ||||
| 	    *s2 = c; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 	    /* Store the column to sort at. */ | ||||
| 	    nrs[lnum - eap->line1].start_col_nr = start_col; | ||||
| 	    nrs[lnum - eap->line1].end_col_nr = end_col; | ||||
| 	    nrs[lnum - eap->line1].st_u.line.start_col_nr = start_col; | ||||
| 	    nrs[lnum - eap->line1].st_u.line.end_col_nr = end_col; | ||||
| 	} | ||||
|  | ||||
| 	nrs[lnum - eap->line1].lnum = lnum; | ||||
|   | ||||
| @@ -32,6 +32,7 @@ STARTTEST | ||||
| :/^t27:/+1,/^t28/-1sort no | ||||
| :/^t28:/+1,/^t29/-1sort b | ||||
| :/^t29:/+1,/^t30/-1sort b | ||||
| :/^t30:/+1,/^t31/-1sort f | ||||
| :/^t01:/,$wq! test.out | ||||
| ENDTEST | ||||
|  | ||||
| @@ -496,9 +497,9 @@ c321d | ||||
| b322b | ||||
| b321 | ||||
| b321b | ||||
|  | ||||
|  | ||||
| t28: binary | ||||
|  | ||||
|  | ||||
| 0b111000 | ||||
| 0b101100 | ||||
| 0b101001 | ||||
| @@ -513,9 +514,9 @@ t28: binary | ||||
| 0b100010 | ||||
| 0b100100 | ||||
| 0b100010 | ||||
|  | ||||
|  | ||||
| t29: binary with leading characters | ||||
|  | ||||
|  | ||||
| 0b100010 | ||||
| 0b010000 | ||||
|  0b101001 | ||||
| @@ -530,4 +531,15 @@ ab0b100000 | ||||
| 0b101010 | ||||
| 0b000000 | ||||
| b0b111000 | ||||
| t30: done | ||||
|  | ||||
|  | ||||
| t30: float | ||||
| 1.234 | ||||
| 0.88 | ||||
| 123.456 | ||||
| 1.15e-6 | ||||
| -1.1e3 | ||||
| -1.01e3 | ||||
|  | ||||
|  | ||||
| t31: done | ||||
|   | ||||
| @@ -453,6 +453,8 @@ c321d | ||||
| b322b | ||||
| b321 | ||||
| b321b | ||||
|  | ||||
|  | ||||
| t28: binary | ||||
|  | ||||
|  | ||||
| @@ -487,4 +489,13 @@ a0b101001 | ||||
| 0b101010 | ||||
| b0b101100 | ||||
| b0b111000 | ||||
| t30: done | ||||
| t30: float | ||||
|  | ||||
|  | ||||
| -1.1e3 | ||||
| -1.01e3 | ||||
| 1.15e-6 | ||||
| 0.88 | ||||
| 1.234 | ||||
| 123.456 | ||||
| t31: done | ||||
|   | ||||
| @@ -17,3 +17,7 @@ func Test_sort_numbers() | ||||
|   call assert_equal([3, 13, 28], sort([13, 28, 3], 'N')) | ||||
|   call assert_equal(['3', '13', '28'], sort(['13', '28', '3'], 'N')) | ||||
| endfunc | ||||
|  | ||||
| func Test_sort_float() | ||||
|   call assert_equal([0.28, 3, 13.5], sort([13.5, 0.28, 3], 'f')) | ||||
| endfunc | ||||
|   | ||||
| @@ -741,6 +741,8 @@ static char *(features[]) = | ||||
|  | ||||
| static int included_patches[] = | ||||
| {   /* Add new patch number below this line */ | ||||
| /**/ | ||||
|     1143, | ||||
| /**/ | ||||
|     1142, | ||||
| /**/ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user