diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2005-12-15 16:53:34 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2005-12-15 16:53:34 -0200 |
commit | 9fbefdf69c1491fd9105b0d717a9c574a266b610 (patch) | |
tree | d96eb5bb8ec708301e658a8f20d847d03b484c06 | |
parent | 43c61fc11381a20376c15a6c0fd4f53912c43ccc (diff) | |
download | lua-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.c | 57 | ||||
-rw-r--r-- | luaconf.h | 22 |
2 files changed, 58 insertions, 21 deletions
@@ -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 | ||
690 | static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { | 695 | static 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 | 720 | static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { | |
716 | static 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 | ||
742 | static 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 | |||
739 | static int str_format (lua_State *L) { | 751 | static 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); |
@@ -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 | /* =================================================================== */ |