On Wed, Apr 09, at 04:15 Charles E Campbell Jr wrote: > > Bram Moolenaar wrote: > > > > OK, so we do need to worry about this. > > > > This patch to message.c, replacing the previous one, should do it. > > > Hello! > > I applied the first patch, and it worked. However, the second one... > > vim71/ djinni? patch -p0 < ../diff_float2.ptch > patching file src/message.c > Hunk #2 FAILED at 3823. > Hunk #3 succeeded at 3819 with fuzz 2 (offset -53 lines). > Hunk #4 succeeded at 4000 with fuzz 2 (offset 84 lines). > Hunk #5 succeeded at 3965 (offset -53 lines). > Hunk #6 FAILED at 4113. > Hunk #7 succeeded at 4618 with fuzz 2 (offset 116 lines). > Hunk #8 FAILED at 4772. > 3 out of 8 hunks FAILED -- saving rejects to file src/message.c.rej >
Please try the attached patch on top of patch level 292. Apply with -p1. echo len(printf('%.350f', &100 / 3)) 341 By the way, Thanks Bram! --~--~---------~--~----~------------~-------~--~----~ You received this message from the "vim_dev" maillist. For more information, visit http://www.vim.org/maillist.php -~----------~----~----~----~------~----~------~--~---
diff -Naur vim71.orig/runtime/doc/eval.txt vim71/runtime/doc/eval.txt --- vim71.orig/runtime/doc/eval.txt 2008-04-10 21:44:22.122448331 +0300 +++ vim71/runtime/doc/eval.txt 2008-04-10 21:40:51.361980814 +0300 @@ -39,11 +39,15 @@ *E712* There are five types of variables: -Number A 32 bit signed number. +Number A 32 bit signed number. |expr-number| Examples: -123 0x10 0177 +Float A floating point number. |floating-point-format| + {only when compiled with the |+float| feature} + Examples: 123.456 1.15e-6 -1.1e3 + String A NUL terminated string of 8-bit unsigned characters (bytes). - Examples: "ab\txx\"--" 'x-z''a,c' + |expr-string| Examples: "ab\txx\"--" 'x-z''a,c' Funcref A reference to a function |Funcref|. Example: function("strlen") @@ -92,6 +96,10 @@ < *E745* *E728* *E703* *E729* *E730* *E731* List, Dictionary and Funcref types are not automatically converted. + *E805* *E806* +When mixing Number and Float the Number is converted to Float. Otherwise +there is no automatic conversion of Float. + *E706* You will get an error if you try to change the type of a variable. You need to |:unlet| it first to avoid this error. String and Number are considered @@ -258,13 +266,13 @@ < 0 Thus comparing Lists is more strict than comparing numbers and strings. You -can compare simple values this way too by putting them in a string: > +can compare simple values this way too by putting them in a list: > :let a = 5 :let b = "5" - echo a == b + :echo a == b < 1 > - echo [a] == [b] + :echo [a] == [b] < 0 @@ -797,6 +805,8 @@ None of these work for |Funcref|s. +. and % do not work for Float. *E804* + expr7 *expr7* ----- @@ -909,6 +919,27 @@ Decimal, Hexadecimal (starting with 0x or 0X), or Octal (starting with 0). + *floating-point-format* +Floating point numbers can be written in two forms: +- &N.M, where N and M are numbers. The .M can be omitted. The N cannot be + omitted. There can be a minus sign in the N. Examples: + &123.456 + &0.0001 + &55 + &-0.123 + Only a decimal point is accepted, not a comma. No matter what the current + locale is. +- Same, with a following exponent in the form "eX", where X is a decimal + number with an optional minus sign. The 'e' can also be upper case. + Examples: + &1.234e3 + &1E-6 + &-3.1416e88 +The precision and range of floating points numbers depends on the library Vim +was compiled with. There is no way to change this at runtime. +{only when compiled with the |+float| feature} + + string *expr-string* *E114* ------ @@ -2024,7 +2055,7 @@ < The current 'encoding' is used. Example for "utf-8": > char2nr("�") returns 225 char2nr("�"[0]) returns 195 -< nr2char() does the opposite. +< |nr2char()| does the opposite. cindent({lnum}) *cindent()* Get the amount of indent for line {lnum} according the C @@ -3893,6 +3924,9 @@ %04x hex number padded with zeros to at least 4 characters %X hex number using upper case letters %o octal number + %f floating point number in the form 123.456 + %e floating point number in the form 1.234e3 + %E floating pointer number in the form 1.234E3 %% the % character itself Conversion specifications start with '%' and end with the @@ -3951,6 +3985,8 @@ This gives the minimum number of digits to appear for d, o, x, and X conversions, or the maximum number of bytes to be printed from a string for s conversions. + For floating point it is the number of digits after + the decimal point. type A character that specifies the type of conversion to @@ -3968,6 +4004,7 @@ The conversion specifiers and their meanings are: + *printf-d* *printf-o* *printf-x* *printf-X* doxX The Number argument is converted to signed decimal (d), unsigned octal (o), or unsigned hexadecimal (x and X) notation. The letters "abcdef" are used for @@ -3982,13 +4019,30 @@ a conversion is wider than the field width, the field is expanded to contain the conversion result. + *printf-c* c The Number argument is converted to a byte, and the resulting character is written. + *printf-s* s The text of the String argument is used. If a precision is specified, no more bytes than the number specified are used. + *printf-f* *E807* + f The Float argument is converted into a string of the + form 123.456. Currently doesn't do any padding. The + precision specifies the number of digits after the + decimal point. When the precision is zero the decimal + point is omitted. When the precision is not specified + 6 is used. + + *printf-e* *printf-E* + e E The Float argument is converted into a string of the + form 1.234e3 or 1.234E3 (when using 'E'). The + precision specifies the number of digits after the + decimal point, like with 'f'. + + *printf-%* % A '%' is written. No argument is converted. The complete conversion specification is "%%". @@ -4781,6 +4835,19 @@ Text after the number is silently ignored. +str2float( {expr}) *str2float()* + Convert string {expr} to a Float. This works the same as when + using a floating point number directly, see + |floating-point-format|, but without the leading '&'. + A comma is also accepted for a decimal point. + Text after the number is silently ignored. + A second comma or decimal point also ends the number: + "12,345.67" is converted to 12.345. You can strip out + thousands separators with |substitute()|: > + let f = str2float(substitute(text, ',', '', 'g')) +< {only when compiled with the |+float| feature} + + strftime({format} [, {time}]) *strftime()* The result is a String, which is a formatted date and time, as specified by the {format} string. The given {time} is used, @@ -5142,6 +5209,7 @@ Funcref: 2 List: 3 Dictionary: 4 + Float: 5 To avoid the magic numbers it should be used this way: > :if type(myvar) == type(0) :if type(myvar) == type("") @@ -5200,6 +5268,8 @@ < This enters the same Visual mode as before. It is also useful in scripts if you wish to act differently depending on the Visual mode that was used. + If Visual mode is active, use |mode()| to get the Visual mode + (e.g., in a |:vmap|). If an expression is supplied that results in a non-zero number or a non-empty string, then the Visual mode will be cleared diff -Naur vim71.orig/src/auto/configure vim71/src/auto/configure --- vim71.orig/src/auto/configure 2008-04-10 21:44:22.135444043 +0300 +++ vim71/src/auto/configure 2008-04-10 21:40:51.366978946 +0300 @@ -10311,9 +10311,10 @@ + for ac_header in stdarg.h stdlib.h string.h sys/select.h sys/utsname.h \ termcap.h fcntl.h sgtty.h sys/ioctl.h sys/time.h sys/types.h termio.h \ - iconv.h langinfo.h unistd.h stropts.h errno.h \ + iconv.h langinfo.h math.h unistd.h stropts.h errno.h \ sys/resource.h sys/systeminfo.h locale.h \ sys/stream.h sys/ptem.h termios.h libc.h sys/statfs.h \ poll.h sys/poll.h pwd.h utime.h sys/param.h libintl.h \ @@ -13083,6 +13084,138 @@ rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext + +echo "$as_me:$LINENO: checking for pow in -lm" >&5 +echo $ECHO_N "checking for pow in -lm... $ECHO_C" >&6 +if test "${ac_cv_lib_m_pow+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lm $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char pow (); +int +main () +{ +pow (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_m_pow=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_m_pow=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_m_pow" >&5 +echo "${ECHO_T}$ac_cv_lib_m_pow" >&6 +if test $ac_cv_lib_m_pow = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBM 1 +_ACEOF + + LIBS="-lm $LIBS" + +fi + +echo "$as_me:$LINENO: checking for pow()" >&5 +echo $ECHO_N "checking for pow()... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#ifdef HAVE_MATH_H +# include <math.h> +#endif + +int +main () +{ +double f = pow(1.1, 3.0); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; cat >>confdefs.h <<\_ACEOF +#define HAVE_POW 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + echo "$as_me:$LINENO: checking --disable-acl argument" >&5 echo $ECHO_N "checking --disable-acl argument... $ECHO_C" >&6 # Check whether --enable-acl or --disable-acl was given. diff -Naur vim71.orig/src/config.h.in vim71/src/config.h.in --- vim71.orig/src/config.h.in 2007-04-26 17:40:34.000000000 +0300 +++ vim71/src/config.h.in 2008-04-10 21:40:51.367978692 +0300 @@ -150,6 +150,7 @@ #undef HAVE_MEMSET #undef HAVE_NANOSLEEP #undef HAVE_OPENDIR +#undef HAVE_POW #undef HAVE_PUTENV #undef HAVE_QSORT #undef HAVE_READLINK @@ -199,6 +200,7 @@ #undef HAVE_LIBGEN_H #undef HAVE_LIBINTL_H #undef HAVE_LOCALE_H +#undef HAVE_MATH_H #undef HAVE_NDIR_H #undef HAVE_POLL_H #undef HAVE_PTHREAD_NP_H diff -Naur vim71.orig/src/configure.in vim71/src/configure.in --- vim71.orig/src/configure.in 2008-04-10 21:44:22.151439060 +0300 +++ vim71/src/configure.in 2008-04-10 21:40:51.368978290 +0300 @@ -2034,7 +2034,7 @@ AC_CHECK_HEADERS(stdarg.h stdlib.h string.h sys/select.h sys/utsname.h \ termcap.h fcntl.h sgtty.h sys/ioctl.h sys/time.h sys/types.h termio.h \ - iconv.h langinfo.h unistd.h stropts.h errno.h \ + iconv.h langinfo.h math.h unistd.h stropts.h errno.h \ sys/resource.h sys/systeminfo.h locale.h \ sys/stream.h sys/ptem.h termios.h libc.h sys/statfs.h \ poll.h sys/poll.h pwd.h utime.h sys/param.h libintl.h \ @@ -2490,6 +2490,17 @@ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_NL_LANGINFO_CODESET), AC_MSG_RESULT(no)) +dnl Need pow() for floating point support. +AC_CHECK_LIB(m, pow) +AC_MSG_CHECKING(for pow()) +AC_TRY_LINK([ +#ifdef HAVE_MATH_H +# include <math.h> +#endif +], [double f = pow(1.1, 3.0);], + AC_MSG_RESULT(yes); AC_DEFINE(HAVE_POW), + AC_MSG_RESULT(no)) + dnl Link with -lposix1e for ACL stuff; if not found, try -lacl for SGI dnl when -lacl works, also try to use -lattr (required for Debian). AC_MSG_CHECKING(--disable-acl argument) diff -Naur vim71.orig/src/eval.c vim71/src/eval.c --- vim71.orig/src/eval.c 2008-04-10 21:44:22.174431146 +0300 +++ vim71/src/eval.c 2008-04-10 21:40:51.381974296 +0300 @@ -30,6 +30,10 @@ #if defined(FEAT_EVAL) || defined(PROTO) +#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) +# include <math.h> +#endif + #define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */ /* @@ -349,10 +353,11 @@ }; /* shorthand */ -#define vv_type vv_di.di_tv.v_type -#define vv_nr vv_di.di_tv.vval.v_number -#define vv_str vv_di.di_tv.vval.v_string -#define vv_tv vv_di.di_tv +#define vv_type vv_di.di_tv.v_type +#define vv_nr vv_di.di_tv.vval.v_number +#define vv_float vv_di.di_tv.vval.v_float +#define vv_str vv_di.di_tv.vval.v_string +#define vv_tv vv_di.di_tv /* * The v: variables are stored in dictionary "vimvardict". @@ -450,6 +455,10 @@ static char_u *echo_string __ARGS((typval_T *tv, char_u **tofree, char_u *numbuf, int copyID)); static char_u *tv2string __ARGS((typval_T *tv, char_u **tofree, char_u *numbuf, int copyID)); static char_u *string_quote __ARGS((char_u *str, int function)); +#ifdef FEAT_FLOAT +static void get_float_tv __ARGS((char_u **arg, typval_T *rettv, int evaluate)); +static int string2float __ARGS((char_u *text, float_T *value, int comma)); +#endif static int get_env_tv __ARGS((char_u **arg, typval_T *rettv, int evaluate)); static int find_internal_func __ARGS((char_u *name)); static char_u *deref_func_name __ARGS((char_u *name, int *lenp)); @@ -637,6 +646,9 @@ static void f_spellbadword __ARGS((typval_T *argvars, typval_T *rettv)); static void f_spellsuggest __ARGS((typval_T *argvars, typval_T *rettv)); static void f_split __ARGS((typval_T *argvars, typval_T *rettv)); +#ifdef FEAT_FLOAT +static void f_str2float __ARGS((typval_T *argvars, typval_T *rettv)); +#endif static void f_str2nr __ARGS((typval_T *argvars, typval_T *rettv)); #ifdef HAVE_STRFTIME static void f_strftime __ARGS((typval_T *argvars, typval_T *rettv)); @@ -1421,7 +1433,8 @@ || defined(FEAT_COMPL_FUNC) || defined(PROTO) /* * Call some vimL function and return the result in "*rettv". - * Uses argv[argc] for the function arguments. + * Uses argv[argc] for the function arguments. Only Number and String + * arguments are currently supported. * Returns OK or FAIL. */ static int @@ -2848,16 +2861,36 @@ { /* nr += nr or nr -= nr*/ n = get_tv_number(tv1); - if (*op == '+') - n += get_tv_number(tv2); +#ifdef FEAT_FLOAT + if (tv2->v_type == VAR_FLOAT) + { + float_T f = n; + + if (*op == '+') + f += tv2->vval.v_float; + else + f -= tv2->vval.v_float; + clear_tv(tv1); + tv1->v_type = VAR_FLOAT; + tv1->vval.v_float = f; + } else - n -= get_tv_number(tv2); - clear_tv(tv1); - tv1->v_type = VAR_NUMBER; - tv1->vval.v_number = n; +#endif + { + if (*op == '+') + n += get_tv_number(tv2); + else + n -= get_tv_number(tv2); + clear_tv(tv1); + tv1->v_type = VAR_NUMBER; + tv1->vval.v_number = n; + } } else { + if (tv2->v_type == VAR_FLOAT) + break; + /* str .= str */ s = get_tv_string(tv1); s = concat_str(s, get_tv_string_buf(tv2, numbuf)); @@ -2866,6 +2899,27 @@ tv1->vval.v_string = s; } return OK; + +#ifdef FEAT_FLOAT + case VAR_FLOAT: + { + float_T f; + + if (*op == '.' || (tv2->v_type != VAR_FLOAT + && tv2->v_type != VAR_NUMBER + && tv2->v_type != VAR_STRING)) + break; + if (tv2->v_type == VAR_FLOAT) + f = tv2->vval.v_float; + else + f = get_tv_number(tv2); + if (*op == '+') + tv1->vval.v_float += f; + else + tv1->vval.v_float -= f; + } + return OK; +#endif } } @@ -4237,6 +4291,40 @@ } } +#ifdef FEAT_FLOAT + /* + * If one of the two variables is a float, compare as a float. + * When using "=~" or "!~", always compare as string. + */ + else if ((rettv->v_type == VAR_FLOAT || var2.v_type == VAR_FLOAT) + && type != TYPE_MATCH && type != TYPE_NOMATCH) + { + float_T f1, f2; + + if (rettv->v_type == VAR_FLOAT) + f1 = rettv->vval.v_float; + else + f1 = get_tv_number(rettv); + if (var2.v_type == VAR_FLOAT) + f2 = var2.vval.v_float; + else + f2 = get_tv_number(&var2); + n1 = FALSE; + switch (type) + { + case TYPE_EQUAL: n1 = (f1 == f2); break; + case TYPE_NEQUAL: n1 = (f1 != f2); break; + case TYPE_GREATER: n1 = (f1 > f2); break; + case TYPE_GEQUAL: n1 = (f1 >= f2); break; + case TYPE_SMALLER: n1 = (f1 < f2); break; + case TYPE_SEQUAL: n1 = (f1 <= f2); break; + case TYPE_UNKNOWN: + case TYPE_MATCH: + case TYPE_NOMATCH: break; /* avoid gcc warning */ + } + } +#endif + /* * If one of the two variables is a number, compare as a number. * When using "=~" or "!~", always compare as string. @@ -4329,6 +4417,9 @@ typval_T var3; int op; long n1, n2; +#ifdef FEAT_FLOAT + float_T f1 = 0, f2 = 0; +#endif char_u *s1, *s2; char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN]; char_u *p; @@ -4348,7 +4439,11 @@ if (op != '+' && op != '-' && op != '.') break; - if (op != '+' || rettv->v_type != VAR_LIST) + if ((op != '+' || rettv->v_type != VAR_LIST) +#ifdef FEAT_FLOAT + && (op == '.' || rettv->v_type != VAR_FLOAT) +#endif + ) { /* For "list + ...", an illegal use of the first operand as * a number cannot be determined before evaluating the 2nd @@ -4412,29 +4507,73 @@ { int error = FALSE; - n1 = get_tv_number_chk(rettv, &error); - if (error) +#ifdef FEAT_FLOAT + if (rettv->v_type == VAR_FLOAT) { - /* This can only happen for "list + non-list". - * For "non-list + ..." or "something - ...", we returned - * before evaluating the 2nd operand. */ - clear_tv(rettv); - return FAIL; + f1 = rettv->vval.v_float; + n1 = 0; } - n2 = get_tv_number_chk(&var2, &error); - if (error) + else +#endif { - clear_tv(rettv); - clear_tv(&var2); - return FAIL; + n1 = get_tv_number_chk(rettv, &error); + if (error) + { + /* This can only happen for "list + non-list". For + * "non-list + ..." or "something - ...", we returned + * before evaluating the 2nd operand. */ + clear_tv(rettv); + return FAIL; + } +#ifdef FEAT_FLOAT + if (var2.v_type == VAR_FLOAT) + f1 = n1; +#endif + } +#ifdef FEAT_FLOAT + if (var2.v_type == VAR_FLOAT) + { + f2 = var2.vval.v_float; + n2 = 0; + } + else +#endif + { + n2 = get_tv_number_chk(&var2, &error); + if (error) + { + clear_tv(rettv); + clear_tv(&var2); + return FAIL; + } +#ifdef FEAT_FLOAT + if (rettv->v_type == VAR_FLOAT) + f2 = n2; +#endif } clear_tv(rettv); - if (op == '+') - n1 = n1 + n2; + +#ifdef FEAT_FLOAT + /* If there is a float on either side the result is a float. */ + if (rettv->v_type == VAR_FLOAT || var2.v_type == VAR_FLOAT) + { + if (op == '+') + f1 = f1 + f2; + else + f1 = f1 - f2; + rettv->v_type = VAR_FLOAT; + rettv->vval.v_float = f1; + } else - n1 = n1 - n2; - rettv->v_type = VAR_NUMBER; - rettv->vval.v_number = n1; +#endif + { + if (op == '+') + n1 = n1 + n2; + else + n1 = n1 - n2; + rettv->v_type = VAR_NUMBER; + rettv->vval.v_number = n1; + } } clear_tv(&var2); } @@ -4462,6 +4601,10 @@ typval_T var2; int op; long n1, n2; +#ifdef FEAT_FLOAT + int use_float = FALSE; + float_T f1 = 0, f2; +#endif int error = FALSE; /* @@ -4481,7 +4624,16 @@ if (evaluate) { - n1 = get_tv_number_chk(rettv, &error); +#ifdef FEAT_FLOAT + if (rettv->v_type == VAR_FLOAT) + { + f1 = rettv->vval.v_float; + use_float = TRUE; + n1 = 0; + } + else +#endif + n1 = get_tv_number_chk(rettv, &error); clear_tv(rettv); if (error) return FAIL; @@ -4498,32 +4650,80 @@ if (evaluate) { - n2 = get_tv_number_chk(&var2, &error); - clear_tv(&var2); - if (error) - return FAIL; +#ifdef FEAT_FLOAT + if (var2.v_type == VAR_FLOAT) + { + if (!use_float) + { + f1 = n1; + use_float = TRUE; + } + f2 = var2.vval.v_float; + n2 = 0; + } + else +#endif + { + n2 = get_tv_number_chk(&var2, &error); + clear_tv(&var2); + if (error) + return FAIL; +#ifdef FEAT_FLOAT + if (use_float) + f2 = n2; +#endif + } /* * Compute the result. + * When either side is a float the result is a float. */ - if (op == '*') - n1 = n1 * n2; - else if (op == '/') +#ifdef FEAT_FLOAT + if (use_float) { - if (n2 == 0) /* give an error message? */ - n1 = 0x7fffffffL; + if (op == '*') + f1 = f1 * f2; + else if (op == '/') + { + if (f2 == 0.0) /* give an error message? */ +# ifdef INFINITY + f1 = INFINITY; +# else + f1 = 0x7fffffffL; +# endif + else + f1 = f1 / f2; + } else - n1 = n1 / n2; + { + EMSG(_("E804: Cannot use % with float")); + return FAIL; + } + rettv->v_type = VAR_FLOAT; + rettv->vval.v_float = f1; } else +#endif { - if (n2 == 0) /* give an error message? */ - n1 = 0; + if (op == '*') + n1 = n1 * n2; + else if (op == '/') + { + if (n2 == 0) /* give an error message? */ + n1 = 0x7fffffffL; + else + n1 = n1 / n2; + } else - n1 = n1 % n2; + { + if (n2 == 0) /* give an error message? */ + n1 = 0; + else + n1 = n1 % n2; + } + rettv->v_type = VAR_NUMBER; + rettv->vval.v_number = n1; } - rettv->v_type = VAR_NUMBER; - rettv->vval.v_number = n1; } } @@ -4565,7 +4765,6 @@ long n; int len; char_u *s; - int val; char_u *start_leader, *end_leader; int ret = OK; char_u *alias; @@ -4635,7 +4834,13 @@ /* * Option value: &name */ - case '&': ret = get_option_tv(arg, rettv, evaluate); + case '&': +#ifdef FEAT_FLOAT + if (vim_isdigit(*(*arg + 1))) + get_float_tv(arg, rettv, evaluate); + else +#endif + ret = get_option_tv(arg, rettv, evaluate); break; /* @@ -4734,8 +4939,15 @@ if (ret == OK && evaluate && end_leader > start_leader) { int error = FALSE; + int val = 0; +#ifdef FEAT_FLOAT + float_T f = 0; - val = get_tv_number_chk(rettv, &error); + if (rettv->v_type == VAR_FLOAT) + f = rettv->vval.v_float; + else +#endif + val = get_tv_number_chk(rettv, &error); if (error) { clear_tv(rettv); @@ -4747,13 +4959,37 @@ { --end_leader; if (*end_leader == '!') - val = !val; + { +#ifdef FEAT_FLOAT + if (rettv->v_type == VAR_FLOAT) + f = !f; + else +#endif + val = !val; + } else if (*end_leader == '-') - val = -val; + { +#ifdef FEAT_FLOAT + if (rettv->v_type == VAR_FLOAT) + f = -f; + else +#endif + val = -val; + } + } +#ifdef FEAT_FLOAT + if (rettv->v_type == VAR_FLOAT) + { + clear_tv(rettv); + rettv->vval.v_float = f; + } + else +#endif + { + clear_tv(rettv); + rettv->v_type = VAR_NUMBER; + rettv->vval.v_number = val; } - clear_tv(rettv); - rettv->v_type = VAR_NUMBER; - rettv->vval.v_number = val; } } @@ -4780,7 +5016,11 @@ char_u *s; char_u *key = NULL; - if (rettv->v_type == VAR_FUNC) + if (rettv->v_type == VAR_FUNC +#ifdef FEAT_FLOAT + || rettv->v_type == VAR_FLOAT +#endif + ) { if (verbose) EMSG(_("E695: Cannot index a Funcref")); @@ -5566,7 +5806,7 @@ /* * Return TRUE if "tv1" and "tv2" have the same value. * Compares the items just like "==" would compare them, but strings and - * numbers are different. + * numbers are different. Floats and numbers are also different. */ static int tv_equal(tv1, tv2, ic) @@ -5608,6 +5848,11 @@ case VAR_NUMBER: return tv1->vval.v_number == tv2->vval.v_number; +#ifdef FEAT_FLOAT + case VAR_FLOAT: + return tv1->vval.v_float == tv2->vval.v_float; +#endif + case VAR_STRING: s1 = get_tv_string_buf(tv1, buf1); s2 = get_tv_string_buf(tv2, buf2); @@ -6897,6 +7142,14 @@ r = get_tv_string_buf(tv, numbuf); break; +#ifdef FEAT_FLOAT + case VAR_FLOAT: + *tofree = NULL; + vim_snprintf(numbuf, NUMBUFLEN, "%f", tv->vval.v_float); + r = numbuf; + break; +#endif + default: EMSG2(_(e_intern2), "echo_string()"); *tofree = NULL; @@ -6929,6 +7182,9 @@ *tofree = string_quote(tv->vval.v_string, FALSE); return *tofree; case VAR_NUMBER: +#ifdef FEAT_FLOAT + case VAR_FLOAT: +#endif case VAR_LIST: case VAR_DICT: break; @@ -6984,6 +7240,71 @@ return s; } +#ifdef FEAT_FLOAT +/* + * Get the value of a floating point number: &123.456 + * "arg" is pointing to the '&'. It is advanced to after the number. + */ + static void +get_float_tv(arg, rettv, evaluate) + char_u **arg; + typval_T *rettv; + int evaluate; +{ + float_T f; + + ++*arg; + *arg += string2float(*arg, &f, FALSE); + if (evaluate) + { + rettv->v_type = VAR_FLOAT; + rettv->vval.v_float = f; + } +} + +/* + * Convert the sting "text" to a floating point number. + * Returns the length of the text that was consumed. + */ + static int +string2float(text, value, comma) + char_u *text; + float_T *value; /* result stored here */ + int comma; /* accept a comma as decimal separator */ +{ + char_u *s = text; + int len; + long n; + float_T f; + + vim_str2nr(s, NULL, &len, FALSE, FALSE, &n, NULL); + s += len; + f = n; + + if ((*s == '.' || (comma && *s == ',')) && s[1] != '-') + { + ++s; + vim_str2nr(s, NULL, &len, FALSE, FALSE, &n, NULL); + s += len; + f += (float_T)n / pow(10.0, (double)len); + } + + /* 1.234e-20 */ + if (*s == 'e' || *s == 'E') + { + ++s; + if (*s == '+') /* accept 1.234e+3 */ + ++s; + vim_str2nr(s, NULL, &len, FALSE, FALSE, &n, NULL); + s += len; + f *= pow(10.0, (double)n); + } + + *value = f; + return (int)(s - text); +} +#endif + /* * Get the value of an environment variable. * "arg" is pointing to the '$'. It is advanced to after the name. @@ -7240,6 +7561,9 @@ {"spellbadword", 0, 1, f_spellbadword}, {"spellsuggest", 1, 3, f_spellsuggest}, {"split", 1, 3, f_split}, +#ifdef FEAT_FLOAT + {"str2float", 1, 1, f_str2float}, +#endif {"str2nr", 1, 2, f_str2nr}, #ifdef HAVE_STRFTIME {"strftime", 1, 2, f_strftime}, @@ -8800,6 +9124,11 @@ case VAR_NUMBER: n = argvars[0].vval.v_number == 0; break; +#ifdef FEAT_FLOAT + case VAR_FLOAT: + n = argvars[0].vval.v_float == 0.0; + break; +#endif case VAR_LIST: n = argvars[0].vval.v_list == NULL || argvars[0].vval.v_list->lv_first == NULL; @@ -10877,6 +11206,9 @@ #ifdef FEAT_FIND_ID "find_in_path", #endif +#ifdef FEAT_FLOAT + "float", +#endif #ifdef FEAT_FOLDING "folding", #endif @@ -15432,6 +15764,21 @@ p_cpo = save_cpo; } +#ifdef FEAT_FLOAT +/* + * "str2float()" function + */ + static void +f_str2float(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ + (void)string2float(skipwhite(get_tv_string(&argvars[0])), + &rettv->vval.v_float, TRUE); + rettv->v_type = VAR_FLOAT; +} +#endif + /* * "str2nr()" function */ @@ -16476,6 +16823,9 @@ case VAR_FUNC: n = 2; break; case VAR_LIST: n = 3; break; case VAR_DICT: n = 4; break; +#ifdef FEAT_FLOAT + case VAR_FLOAT: n = 5; break; +#endif default: EMSG2(_(e_intern2), "f_type()"); n = 0; break; } rettv->vval.v_number = n; @@ -17662,6 +18012,9 @@ dict_unref(varp->vval.v_dict); break; case VAR_NUMBER: +#ifdef FEAT_FLOAT + case VAR_FLOAT: +#endif case VAR_UNKNOWN: break; default: @@ -17701,6 +18054,11 @@ case VAR_NUMBER: varp->vval.v_number = 0; break; +#ifdef FEAT_FLOAT + case VAR_FLOAT: + varp->vval.v_float = 0; + break; +#endif case VAR_UNKNOWN: break; default: @@ -17749,6 +18107,11 @@ { case VAR_NUMBER: return (long)(varp->vval.v_number); +#ifdef FEAT_FLOAT + case VAR_FLOAT: + EMSG(_("E805: Using a Float as a number")); + break; +#endif case VAR_FUNC: EMSG(_("E703: Using a Funcref as a number")); break; @@ -17872,6 +18235,11 @@ case VAR_DICT: EMSG(_("E731: using Dictionary as a String")); break; +#ifdef FEAT_FLOAT + case VAR_FLOAT: + EMSG(_("E806: using Float as a String")); + break; +#endif case VAR_STRING: if (varp->vval.v_string != NULL) return varp->vval.v_string; @@ -18410,6 +18778,11 @@ case VAR_NUMBER: to->vval.v_number = from->vval.v_number; break; +#ifdef FEAT_FLOAT + case VAR_FLOAT: + to->vval.v_float = from->vval.v_float; + break; +#endif case VAR_STRING: case VAR_FUNC: if (from->vval.v_string == NULL) @@ -18472,6 +18845,9 @@ switch (from->v_type) { case VAR_NUMBER: +#ifdef FEAT_FLOAT + case VAR_FLOAT: +#endif case VAR_STRING: case VAR_FUNC: copy_tv(from, to); @@ -20846,9 +21222,9 @@ #if defined(FEAT_VIMINFO) || defined(FEAT_SESSION) typedef enum { - VAR_FLAVOUR_DEFAULT, - VAR_FLAVOUR_SESSION, - VAR_FLAVOUR_VIMINFO + VAR_FLAVOUR_DEFAULT, /* doesn't start with uppercase */ + VAR_FLAVOUR_SESSION, /* starts with uppercase, some lower */ + VAR_FLAVOUR_VIMINFO /* all uppercase */ } var_flavour_T; static var_flavour_T var_flavour __ARGS((char_u *varname)); @@ -20881,7 +21257,7 @@ int writing; { char_u *tab; - int is_string = FALSE; + int type = VAR_NUMBER; typval_T tv; if (!writing && (find_viminfo_parameter('!') != NULL)) @@ -20891,24 +21267,27 @@ { *tab++ = '\0'; /* isolate the variable name */ if (*tab == 'S') /* string var */ - is_string = TRUE; + type = VAR_STRING; +#ifdef FEAT_FLOAT + else if (*tab == 'F') + type = VAR_FLOAT; +#endif tab = vim_strchr(tab, '\t'); if (tab != NULL) { - if (is_string) - { - tv.v_type = VAR_STRING; + tv.v_type = type; + if (type == VAR_STRING) tv.vval.v_string = viminfo_readstring(virp, (int)(tab - virp->vir_line + 1), TRUE); - } +#ifdef FEAT_FLOAT + else if (type == VAR_FLOAT) + (void)string2float(tab + 1, &tv.vval.v_float, TRUE); +#endif else - { - tv.v_type = VAR_NUMBER; tv.vval.v_number = atol((char *)tab + 1); - } set_var(virp->vir_line + 1, &tv, FALSE); - if (is_string) + if (type == VAR_STRING) vim_free(tv.vval.v_string); } } @@ -20950,6 +21329,9 @@ { case VAR_STRING: s = "STR"; break; case VAR_NUMBER: s = "NUM"; break; +#ifdef FEAT_FLOAT + case VAR_FLOAT: s = "FLO"; break; +#endif default: continue; } fprintf(fp, "!%s\t%s\t", this_var->di_key, s); @@ -21009,6 +21391,24 @@ } vim_free(p); } +#ifdef FEAT_FLOAT + else if (this_var->di_tv.v_type == VAR_FLOAT + && var_flavour(this_var->di_key) == VAR_FLAVOUR_SESSION) + { + float_T f = this_var->di_tv.vval.v_float; + int sign = ' '; + + if (f < 0) + { + f = -f; + sign = '-'; + } + if ((fprintf(fd, "let %s = %c&%f", + this_var->di_key, sign, f) < 0) + || put_eol(fd) == FAIL) + return FAIL; + } +#endif } } return OK; @@ -21080,7 +21480,7 @@ vim_free(*bufp); *fnamep = *bufp = newbuf; - l = GetShortPathName(*fnamep,*fnamep,l+1); + l = GetShortPathName(*fnamep, *fnamep, l+1); /* Really should always succeed, as the buffer is big enough */ } diff -Naur vim71.orig/src/feature.h vim71/src/feature.h --- vim71.orig/src/feature.h 2008-04-10 21:44:22.195424329 +0300 +++ vim71/src/feature.h 2008-04-10 21:40:51.381974296 +0300 @@ -35,7 +35,7 @@ * +small few features enabled, as basic as possible * +normal A default selection of features enabled * +big many features enabled, as rich as possible. - * +huge all possible featues enabled. + * +huge all possible features enabled. * * When +small is used, +tiny is also included. +normal implies +small, etc. */ @@ -376,9 +376,13 @@ /* * +eval Built-in script language and expression evaluation, * ":let", ":if", etc. + * +float Floating point variables. */ #ifdef FEAT_NORMAL # define FEAT_EVAL +# if defined(HAVE_POW) +# define FEAT_FLOAT +# endif #endif /* diff -Naur vim71.orig/src/if_python.c vim71/src/if_python.c --- vim71.orig/src/if_python.c 2007-03-07 00:00:53.000000000 +0200 +++ vim71/src/if_python.c 2008-04-10 21:40:51.382974351 +0300 @@ -1130,6 +1130,17 @@ result = Py_BuildValue("s", buf); PyDict_SetItemString(lookupDict, ptrBuf, result); } +#ifdef FEAT_FLOAT + else if (our_tv->v_type == VAR_FLOAT) + { + char buf[NUMBUFLEN]; + + /* For backwards compatibility numbers are stored as strings. */ + sprintf(buf, "%f", (long)our_tv->vval.v_float); + result = Py_BuildValue("s", buf); + PyDict_SetItemString(lookupDict, ptrBuf, result); + } +#endif else if (our_tv->v_type == VAR_LIST) { list_T *list = our_tv->vval.v_list; diff -Naur vim71.orig/src/message.c vim71/src/message.c --- vim71.orig/src/message.c 2008-04-10 21:44:22.230412683 +0300 +++ vim71/src/message.c 2008-04-10 21:40:45.664888239 +0300 @@ -15,6 +15,10 @@ #include "vim.h" +#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) +# include <math.h> +#endif + static int other_sourcing_name __ARGS((void)); static char_u *get_emsg_source __ARGS((void)); static char_u *get_emsg_lnum __ARGS((void)); @@ -3819,6 +3823,9 @@ static long tv_nr __ARGS((typval_T *tvs, int *idxp)); static char *tv_str __ARGS((typval_T *tvs, int *idxp)); +# ifdef FEAT_FLOAT +static double tv_float __ARGS((typval_T *tvs, int *idxp)); +# endif /* * Get number argument from "idxp" entry in "tvs". First entry is 1. @@ -3865,6 +3872,32 @@ } return s; } + +# ifdef FEAT_FLOAT +/* + * Get float argument from "idxp" entry in "tvs". First entry is 1. + */ + static double +tv_float(tvs, idxp) + typval_T *tvs; + int *idxp; +{ + int idx = *idxp - 1; + double f = 0; + + if (tvs[idx].v_type == VAR_UNKNOWN) + EMSG(_(e_printf)); + else + { + ++*idxp; + if (tvs[idx].v_type == VAR_FLOAT) + f = tvs[idx].vval.v_float; + else + EMSG(_("E807: Expected Float argument for printf()")); + } + return f; +} +# endif #endif /* @@ -3883,6 +3916,8 @@ * with flags: '-', '+', ' ', '0' and '#'. * An asterisk is supported for field width as well as precision. * + * Limited support for 'f', 'e' and 'E' (floating point) was added. + * * Length modifiers 'h' (short int) and 'l' (long int) are supported. * 'll' (long long int) is not supported. * @@ -3983,7 +4018,14 @@ char length_modifier = '\0'; /* temporary buffer for simple numeric->string conversion */ - char tmp[32]; +#ifdef FEAT_FLOAT +# define TMP_LEN 350 /* On my system 1e308 is the biggest number possible. + * That sounds reasonable to use as the maximum + * printable. */ +#else +# define TMP_LEN 32 +#endif + char tmp[TMP_LEN]; /* string address in case of string argument */ char *str_arg; @@ -4124,6 +4166,7 @@ case 'D': fmt_spec = 'd'; length_modifier = 'l'; break; case 'U': fmt_spec = 'u'; length_modifier = 'l'; break; case 'O': fmt_spec = 'o'; length_modifier = 'l'; break; + case 'F': fmt_spec = 'f'; break; default: break; } @@ -4459,6 +4502,53 @@ break; } +#ifdef FEAT_FLOAT + case 'f': + case 'e': + case 'E': + { + /* Floating point. Very limited at the moment. */ + double f; + char format[40]; + int l; + + f = +# ifndef HAVE_STDARG_H + get_a_arg(arg_idx); +# else +# if defined(FEAT_EVAL) + tvs != NULL ? tv_float(tvs, &arg_idx) : +# endif + va_arg(ap, double); +# endif + if (fmt_spec == 'f' && f > 1.0e307) + { + /* Avoid a buffer overflow */ + strcpy(tmp, "inf"); + str_arg_l = 3; + } + else + { + format[0] = '%'; + l = 1; + if (precision_specified) + { + if (fmt_spec == 'f' + && log10(f) + precision > TMP_LEN - 10) + precision = TMP_LEN - 10 - log10(f); + else if (precision > TMP_LEN - 10) + precision = TMP_LEN - 10; + l += sprintf(format + 1, ".%d", precision); + } + format[l] = fmt_spec; + format[l + 1] = NUL; + str_arg_l = sprintf(tmp, format, f); + } + str_arg = tmp; + break; + } +#endif + default: /* unrecognized conversion specifier, keep format string * as-is */ @@ -4566,7 +4656,8 @@ if (justify_left) { /* right blank padding to the field width */ - int pn = (int)(min_field_width - (str_arg_l + number_of_zeros_to_pad)); + int pn = (int)(min_field_width + - (str_arg_l + number_of_zeros_to_pad)); if (pn > 0) { diff -Naur vim71.orig/src/structs.h vim71/src/structs.h --- vim71.orig/src/structs.h 2008-04-10 21:44:22.288393601 +0300 +++ vim71/src/structs.h 2008-04-10 21:40:51.384973103 +0300 @@ -1005,6 +1005,7 @@ #else typedef int varnumber_T; #endif +typedef double float_T; typedef struct listvar_S list_T; typedef struct dictvar_S dict_T; @@ -1019,6 +1020,9 @@ union { varnumber_T v_number; /* number value */ +#ifdef FEAT_FLOAT + float_T v_float; /* floating number value */ +#endif char_u *v_string; /* string value (can be NULL!) */ list_T *v_list; /* list value (can be NULL!) */ dict_T *v_dict; /* dict value (can be NULL!) */ @@ -1032,6 +1036,7 @@ #define VAR_FUNC 3 /* "v_string" is function name */ #define VAR_LIST 4 /* "v_list" is used */ #define VAR_DICT 5 /* "v_dict" is used */ +#define VAR_FLOAT 6 /* "v_float" is used */ /* Values for "v_lock". */ #define VAR_LOCKED 1 /* locked with lock(), can use unlock() */ diff -Naur vim71.orig/src/version.c vim71/src/version.c --- vim71.orig/src/version.c 2008-04-10 21:44:22.301389216 +0300 +++ vim71/src/version.c 2008-04-10 21:40:51.385973840 +0300 @@ -217,6 +217,11 @@ #else "-find_in_path", #endif +#ifdef FEAT_FLOAT + "+float", +#else + "-float", +#endif #ifdef FEAT_FOLDING "+folding", #else