소스 검색

own implementation for 'string.format("%a")' for C89 platforms

Roberto Ierusalimschy 10 년 전
부모
커밋
8efcd411fe
2개의 변경된 파일92개의 추가작업 그리고 11개의 파일을 삭제
  1. 84 3
      lstrlib.c
  2. 8 8
      luaconf.h

+ 84 - 3
lstrlib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lstrlib.c,v 1.221 2014/12/11 14:03:07 roberto Exp roberto $
+** $Id: lstrlib.c,v 1.223 2015/02/04 12:52:57 roberto Exp $
 ** Standard library for string operations and pattern-matching
 ** See Copyright Notice in lua.h
 */
@@ -797,6 +797,86 @@ static int str_gsub (lua_State *L) {
 ** =======================================================
 */
 
+#if !defined(lua_number2strx)	/* { */
+
+/*
+** Hexadecimal floating-point formatter
+*/
+
+#include <math.h>
+
+#define SIZELENMOD	(sizeof(LUA_NUMBER_FRMLEN)/sizeof(char))
+
+
+/*
+** Number of bits that goes into the first digit. It can be any value
+** between 1 and 4; the following definition tries to align the number
+** to nibble boundaries. The default is 1 bit, that aligns double
+** (1+52-bit mantissa) and quad precision (1+112-bit mantissa). For
+** float (24-bit mantissa) and 80-bit long double (64-bit mantissa), 4
+** does the alignment.
+*/
+#define L_NBFD	((sizeof(lua_Number) == 4 || sizeof(lua_Number) == 12) ? 4 : 1)
+
+
+/*
+** Add integer part of 'x' to buffer and return new 'x'
+*/
+static lua_Number adddigit (char *buff, int n, lua_Number x) {
+  double dd = l_mathop(floor)(x);  /* get integer part from 'x' */
+  int d = (int)dd;
+  buff[n] = (d < 10 ? d + '0' : d - 10 + 'a');  /* add to buffer */
+  return x - dd;  /* return what is left */
+}
+
+
+static int num2straux (char *buff, lua_Number x) {
+  if (x != x || x == HUGE_VAL || x == -HUGE_VAL)  /* inf or NaN? */
+    return sprintf(buff, LUA_NUMBER_FMT, x);  /* equal to '%g' */
+  else if (x == 0) {  /* can be -0... */
+    sprintf(buff, LUA_NUMBER_FMT, x);
+    strcpy(buff + (buff[0] == '-' ? 1 : 0), "0x0p+0");
+    return strlen(buff);
+  }
+  else {
+    int e;
+    lua_Number m = l_mathop(frexp)(x, &e);  /* 'x' fraction and exponent */
+    int n = 0;  /* character count */
+    if (m < 0) {  /* is number negative? */
+      buff[n++] = '-';  /* add signal */
+      m = -m;  /* make it positive */
+    }
+    buff[n++] = '0'; buff[n++] = 'x';  /* add "0x" */
+    m = adddigit(buff, n++, m * (1 << L_NBFD));  /* add first digit */
+    e -= L_NBFD;  /* this digit goes before the radix point */
+    if (m > 0) {  /* more digits? */
+      buff[n++] = '.';  /* add radix point */
+      do {  /* add as many digits as needed */
+        m = adddigit(buff, n++, m * 16);
+      } while (m > 0);
+    }
+    n += sprintf(buff + n, "p%+d", e);  /* add exponent */
+    return n;
+  }
+}
+
+
+static int lua_number2strx (lua_State *L, char *buff, const char *fmt,
+                            lua_Number x) {
+  int n = num2straux(buff, x);
+  if (fmt[SIZELENMOD] == 'A') {
+    int i;
+    for (i = 0; i < n; i++)
+      buff[i] = toupper(uchar(buff[i]));
+  }
+  else if (fmt[SIZELENMOD] != 'a')
+    luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented");
+  return n;
+}
+
+#endif				/* } */
+
+
 /*
 ** Maximum size of each formatted item. This maximum size is produced
 ** by format('%.99f', minfloat), and is equal to 99 + 2 ('-' and '.') +
@@ -908,9 +988,10 @@ static int str_format (lua_State *L) {
           nb = sprintf(buff, form, n);
           break;
         }
-#if defined(LUA_USE_AFORMAT)
         case 'a': case 'A':
-#endif
+          addlenmod(form, LUA_NUMBER_FRMLEN);
+          nb = lua_number2strx(L, buff, form, luaL_checknumber(L, arg));
+          break;
         case 'e': case 'E': case 'f':
         case 'g': case 'G': {
           addlenmod(form, LUA_NUMBER_FRMLEN);

+ 8 - 8
luaconf.h

@@ -1,5 +1,5 @@
 /*
-** $Id: luaconf.h,v 1.241 2015/01/16 17:15:52 roberto Exp roberto $
+** $Id: luaconf.h,v 1.242 2015/01/16 17:26:56 roberto Exp roberto $
 ** Configuration file for Lua
 ** See Copyright Notice in lua.h
 */
@@ -598,7 +598,7 @@
 
 /*
 @@ lua_strx2number converts an hexadecimal numeric string to a number.
-** In C99, 'strtod' does both conversions. Otherwise, you can
+** In C99, 'strtod' does that conversion. Otherwise, you can
 ** leave 'lua_strx2number' undefined and Lua will provide its own
 ** implementation.
 */
@@ -608,12 +608,13 @@
 
 
 /*
-@@ LUA_USE_AFORMAT allows '%a'/'%A' specifiers in 'string.format'
-** Enable it if the C function 'printf' supports these specifiers.
-** (C99 demands it and Windows also supports it.)
+@@ lua_number2strx converts a float to an hexadecimal numeric string. 
+** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that.
+** Otherwise, you can leave 'lua_number2strx' undefined and Lua will
+** provide its own implementation.
 */
-#if !defined(LUA_USE_C89) || defined(LUA_USE_WINDOWS)
-#define LUA_USE_AFORMAT
+#if !defined(LUA_USE_C89)
+#define lua_number2strx(L,b,f,n)	sprintf(b,f,n)
 #endif
 
 
@@ -699,7 +700,6 @@
 #define LUAL_BUFFERSIZE		8192
 #else
 #define LUAL_BUFFERSIZE   ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer)))
-
 #endif
 
 /* }================================================================== */