aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2005-12-15 16:53:34 -0200
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2005-12-15 16:53:34 -0200
commit9fbefdf69c1491fd9105b0d717a9c574a266b610 (patch)
treed96eb5bb8ec708301e658a8f20d847d03b484c06
parent43c61fc11381a20376c15a6c0fd4f53912c43ccc (diff)
downloadlua-9fbefdf69c1491fd9105b0d717a9c574a266b610.tar.gz
lua-9fbefdf69c1491fd9105b0d717a9c574a266b610.tar.bz2
lua-9fbefdf69c1491fd9105b0d717a9c574a266b610.zip
integer formats in 'string.format' may need to operate with larger-than-int
types
-rw-r--r--lstrlib.c57
-rw-r--r--luaconf.h22
2 files changed, 58 insertions, 21 deletions
diff --git a/lstrlib.c b/lstrlib.c
index a105c306..fdf26af4 100644
--- a/lstrlib.c
+++ b/lstrlib.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lstrlib.c,v 1.126 2005/10/23 17:46:30 roberto Exp roberto $ 2** $Id: lstrlib.c,v 1.127 2005/10/26 13:28:19 roberto Exp roberto $
3** Standard library for string operations and pattern-matching 3** Standard library for string operations and pattern-matching
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -683,8 +683,13 @@ static int str_gsub (lua_State *L) {
683 683
684/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ 684/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
685#define MAX_ITEM 512 685#define MAX_ITEM 512
686/* maximum size of each format specification (such as '%-099.99d') */ 686/* valid flags in a format specification */
687#define MAX_FORMAT 20 687#define FLAGS "-+ #0"
688/*
689** maximum size of each format specification (such as '%-099.99d')
690** (+10 accounts for %99.99x plus margin of error)
691*/
692#define MAX_FORMAT (sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10)
688 693
689 694
690static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { 695static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
@@ -712,30 +717,37 @@ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
712 luaL_addchar(b, '"'); 717 luaL_addchar(b, '"');
713} 718}
714 719
715 720static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
716static const char *scanformat (lua_State *L, const char *strfrmt,
717 char *form, int *hasprecision) {
718 const char *p = strfrmt; 721 const char *p = strfrmt;
719 while (strchr("-+ #0", *p)) p++; /* skip flags */ 722 while (strchr(FLAGS, *p)) p++; /* skip flags */
723 if ((size_t)(p - strfrmt) >= sizeof(FLAGS))
724 luaL_error(L, "invalid format (repeated flags)");
720 if (isdigit(uchar(*p))) p++; /* skip width */ 725 if (isdigit(uchar(*p))) p++; /* skip width */
721 if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ 726 if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
722 if (*p == '.') { 727 if (*p == '.') {
723 p++; 728 p++;
724 *hasprecision = 1;
725 if (isdigit(uchar(*p))) p++; /* skip precision */ 729 if (isdigit(uchar(*p))) p++; /* skip precision */
726 if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ 730 if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
727 } 731 }
728 if (isdigit(uchar(*p))) 732 if (isdigit(uchar(*p)))
729 luaL_error(L, "invalid format (width or precision too long)"); 733 luaL_error(L, "invalid format (width or precision too long)");
730 if (p-strfrmt+2 > MAX_FORMAT) /* +2 to include `%' and the specifier */ 734 *(form++) = '%';
731 luaL_error(L, "invalid format (too long)"); 735 strncpy(form, strfrmt, p - strfrmt + 1);
732 form[0] = L_ESC; 736 form += p - strfrmt + 1;
733 strncpy(form+1, strfrmt, p-strfrmt+1); 737 *form = '\0';
734 form[p-strfrmt+2] = 0;
735 return p; 738 return p;
736} 739}
737 740
738 741
742static void addintlen (char *form) {
743 int l = strlen(form);
744 char spec = form[l - 1];
745 strcpy(form + l - 1, LUA_INTFRMLEN);
746 form[l + sizeof(LUA_INTFRMLEN) - 2] = spec;
747 form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0';
748}
749
750
739static int str_format (lua_State *L) { 751static int str_format (lua_State *L) {
740 int arg = 1; 752 int arg = 1;
741 size_t sfl; 753 size_t sfl;
@@ -751,21 +763,26 @@ static int str_format (lua_State *L) {
751 else { /* format item */ 763 else { /* format item */
752 char form[MAX_FORMAT]; /* to store the format (`%...') */ 764 char form[MAX_FORMAT]; /* to store the format (`%...') */
753 char buff[MAX_ITEM]; /* to store the formatted item */ 765 char buff[MAX_ITEM]; /* to store the formatted item */
754 int hasprecision = 0;
755 arg++; 766 arg++;
756 strfrmt = scanformat(L, strfrmt, form, &hasprecision); 767 strfrmt = scanformat(L, strfrmt, form);
757 switch (*strfrmt++) { 768 switch (*strfrmt++) {
758 case 'c': case 'd': case 'i': { 769 case 'c': {
759 sprintf(buff, form, luaL_checkint(L, arg)); 770 sprintf(buff, form, (int)luaL_checknumber(L, arg));
771 break;
772 }
773 case 'd': case 'i': {
774 addintlen(form);
775 sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg));
760 break; 776 break;
761 } 777 }
762 case 'o': case 'u': case 'x': case 'X': { 778 case 'o': case 'u': case 'x': case 'X': {
763 sprintf(buff, form, (unsigned int)(luaL_checknumber(L, arg))); 779 addintlen(form);
780 sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg));
764 break; 781 break;
765 } 782 }
766 case 'e': case 'E': case 'f': 783 case 'e': case 'E': case 'f':
767 case 'g': case 'G': { 784 case 'g': case 'G': {
768 sprintf(buff, form, luaL_checknumber(L, arg)); 785 sprintf(buff, form, (double)luaL_checknumber(L, arg));
769 break; 786 break;
770 } 787 }
771 case 'q': { 788 case 'q': {
@@ -775,7 +792,7 @@ static int str_format (lua_State *L) {
775 case 's': { 792 case 's': {
776 size_t l; 793 size_t l;
777 const char *s = luaL_checklstring(L, arg, &l); 794 const char *s = luaL_checklstring(L, arg, &l);
778 if (!hasprecision && l >= 100) { 795 if (!strchr(form, '.') && l >= 100) {
779 /* no precision and string is too long to be formatted; 796 /* no precision and string is too long to be formatted;
780 keep original string */ 797 keep original string */
781 lua_pushvalue(L, arg); 798 lua_pushvalue(L, arg);
diff --git a/luaconf.h b/luaconf.h
index 3370b9df..a0504e0f 100644
--- a/luaconf.h
+++ b/luaconf.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: luaconf.h,v 1.74 2005/11/16 16:24:28 roberto Exp roberto $ 2** $Id: luaconf.h,v 1.75 2005/11/25 13:29:11 roberto Exp roberto $
3** Configuration file for Lua 3** Configuration file for Lua
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -708,6 +708,26 @@ union luai_Cast { double l_d; long l_l; };
708#define luai_userstateyield(L,n) ((void)L) 708#define luai_userstateyield(L,n) ((void)L)
709 709
710 710
711/*
712@@ LUA_INTFRMLEN is the length modifier for integer conversions
713@* in 'string.fomat'.
714@@ LUA_INTFRM_T is the integer type correspoding to the previous length
715@* modifier.
716** CHANGE them if your system supports long long or does not support long.
717*/
718
719#if defined(LUA_USELONGLONG)
720
721#define LUA_INTFRMLEN "ll"
722#define LUA_INTFRM_T long long
723
724#else
725
726#define LUA_INTFRMLEN "l"
727#define LUA_INTFRM_T long
728
729#endif
730
711 731
712 732
713/* =================================================================== */ 733/* =================================================================== */