xref: /aosp_15_r20/external/lua/src/lobject.c (revision 088332b5b69e7ab13924864b272aabfc2509d2d5)
1*088332b5SXin Li /*
2*088332b5SXin Li ** $Id: lobject.c $
3*088332b5SXin Li ** Some generic functions over Lua objects
4*088332b5SXin Li ** See Copyright Notice in lua.h
5*088332b5SXin Li */
6*088332b5SXin Li 
7*088332b5SXin Li #define lobject_c
8*088332b5SXin Li #define LUA_CORE
9*088332b5SXin Li 
10*088332b5SXin Li #include "lprefix.h"
11*088332b5SXin Li 
12*088332b5SXin Li 
13*088332b5SXin Li #include <locale.h>
14*088332b5SXin Li #include <math.h>
15*088332b5SXin Li #include <stdarg.h>
16*088332b5SXin Li #include <stdio.h>
17*088332b5SXin Li #include <stdlib.h>
18*088332b5SXin Li #include <string.h>
19*088332b5SXin Li 
20*088332b5SXin Li #include "lua.h"
21*088332b5SXin Li 
22*088332b5SXin Li #include "lctype.h"
23*088332b5SXin Li #include "ldebug.h"
24*088332b5SXin Li #include "ldo.h"
25*088332b5SXin Li #include "lmem.h"
26*088332b5SXin Li #include "lobject.h"
27*088332b5SXin Li #include "lstate.h"
28*088332b5SXin Li #include "lstring.h"
29*088332b5SXin Li #include "lvm.h"
30*088332b5SXin Li 
31*088332b5SXin Li 
32*088332b5SXin Li /*
33*088332b5SXin Li ** Computes ceil(log2(x))
34*088332b5SXin Li */
luaO_ceillog2(unsigned int x)35*088332b5SXin Li int luaO_ceillog2 (unsigned int x) {
36*088332b5SXin Li   static const lu_byte log_2[256] = {  /* log_2[i] = ceil(log2(i - 1)) */
37*088332b5SXin Li     0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
38*088332b5SXin Li     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
39*088332b5SXin Li     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
40*088332b5SXin Li     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
41*088332b5SXin Li     8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
42*088332b5SXin Li     8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
43*088332b5SXin Li     8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
44*088332b5SXin Li     8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
45*088332b5SXin Li   };
46*088332b5SXin Li   int l = 0;
47*088332b5SXin Li   x--;
48*088332b5SXin Li   while (x >= 256) { l += 8; x >>= 8; }
49*088332b5SXin Li   return l + log_2[x];
50*088332b5SXin Li }
51*088332b5SXin Li 
52*088332b5SXin Li 
intarith(lua_State * L,int op,lua_Integer v1,lua_Integer v2)53*088332b5SXin Li static lua_Integer intarith (lua_State *L, int op, lua_Integer v1,
54*088332b5SXin Li                                                    lua_Integer v2) {
55*088332b5SXin Li   switch (op) {
56*088332b5SXin Li     case LUA_OPADD: return intop(+, v1, v2);
57*088332b5SXin Li     case LUA_OPSUB:return intop(-, v1, v2);
58*088332b5SXin Li     case LUA_OPMUL:return intop(*, v1, v2);
59*088332b5SXin Li     case LUA_OPMOD: return luaV_mod(L, v1, v2);
60*088332b5SXin Li     case LUA_OPIDIV: return luaV_idiv(L, v1, v2);
61*088332b5SXin Li     case LUA_OPBAND: return intop(&, v1, v2);
62*088332b5SXin Li     case LUA_OPBOR: return intop(|, v1, v2);
63*088332b5SXin Li     case LUA_OPBXOR: return intop(^, v1, v2);
64*088332b5SXin Li     case LUA_OPSHL: return luaV_shiftl(v1, v2);
65*088332b5SXin Li     case LUA_OPSHR: return luaV_shiftl(v1, -v2);
66*088332b5SXin Li     case LUA_OPUNM: return intop(-, 0, v1);
67*088332b5SXin Li     case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1);
68*088332b5SXin Li     default: lua_assert(0); return 0;
69*088332b5SXin Li   }
70*088332b5SXin Li }
71*088332b5SXin Li 
72*088332b5SXin Li 
numarith(lua_State * L,int op,lua_Number v1,lua_Number v2)73*088332b5SXin Li static lua_Number numarith (lua_State *L, int op, lua_Number v1,
74*088332b5SXin Li                                                   lua_Number v2) {
75*088332b5SXin Li   switch (op) {
76*088332b5SXin Li     case LUA_OPADD: return luai_numadd(L, v1, v2);
77*088332b5SXin Li     case LUA_OPSUB: return luai_numsub(L, v1, v2);
78*088332b5SXin Li     case LUA_OPMUL: return luai_nummul(L, v1, v2);
79*088332b5SXin Li     case LUA_OPDIV: return luai_numdiv(L, v1, v2);
80*088332b5SXin Li     case LUA_OPPOW: return luai_numpow(L, v1, v2);
81*088332b5SXin Li     case LUA_OPIDIV: return luai_numidiv(L, v1, v2);
82*088332b5SXin Li     case LUA_OPUNM: return luai_numunm(L, v1);
83*088332b5SXin Li     case LUA_OPMOD: return luaV_modf(L, v1, v2);
84*088332b5SXin Li     default: lua_assert(0); return 0;
85*088332b5SXin Li   }
86*088332b5SXin Li }
87*088332b5SXin Li 
88*088332b5SXin Li 
luaO_rawarith(lua_State * L,int op,const TValue * p1,const TValue * p2,TValue * res)89*088332b5SXin Li int luaO_rawarith (lua_State *L, int op, const TValue *p1, const TValue *p2,
90*088332b5SXin Li                    TValue *res) {
91*088332b5SXin Li   switch (op) {
92*088332b5SXin Li     case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR:
93*088332b5SXin Li     case LUA_OPSHL: case LUA_OPSHR:
94*088332b5SXin Li     case LUA_OPBNOT: {  /* operate only on integers */
95*088332b5SXin Li       lua_Integer i1; lua_Integer i2;
96*088332b5SXin Li       if (tointegerns(p1, &i1) && tointegerns(p2, &i2)) {
97*088332b5SXin Li         setivalue(res, intarith(L, op, i1, i2));
98*088332b5SXin Li         return 1;
99*088332b5SXin Li       }
100*088332b5SXin Li       else return 0;  /* fail */
101*088332b5SXin Li     }
102*088332b5SXin Li     case LUA_OPDIV: case LUA_OPPOW: {  /* operate only on floats */
103*088332b5SXin Li       lua_Number n1; lua_Number n2;
104*088332b5SXin Li       if (tonumberns(p1, n1) && tonumberns(p2, n2)) {
105*088332b5SXin Li         setfltvalue(res, numarith(L, op, n1, n2));
106*088332b5SXin Li         return 1;
107*088332b5SXin Li       }
108*088332b5SXin Li       else return 0;  /* fail */
109*088332b5SXin Li     }
110*088332b5SXin Li     default: {  /* other operations */
111*088332b5SXin Li       lua_Number n1; lua_Number n2;
112*088332b5SXin Li       if (ttisinteger(p1) && ttisinteger(p2)) {
113*088332b5SXin Li         setivalue(res, intarith(L, op, ivalue(p1), ivalue(p2)));
114*088332b5SXin Li         return 1;
115*088332b5SXin Li       }
116*088332b5SXin Li       else if (tonumberns(p1, n1) && tonumberns(p2, n2)) {
117*088332b5SXin Li         setfltvalue(res, numarith(L, op, n1, n2));
118*088332b5SXin Li         return 1;
119*088332b5SXin Li       }
120*088332b5SXin Li       else return 0;  /* fail */
121*088332b5SXin Li     }
122*088332b5SXin Li   }
123*088332b5SXin Li }
124*088332b5SXin Li 
125*088332b5SXin Li 
luaO_arith(lua_State * L,int op,const TValue * p1,const TValue * p2,StkId res)126*088332b5SXin Li void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2,
127*088332b5SXin Li                  StkId res) {
128*088332b5SXin Li   if (!luaO_rawarith(L, op, p1, p2, s2v(res))) {
129*088332b5SXin Li     /* could not perform raw operation; try metamethod */
130*088332b5SXin Li     luaT_trybinTM(L, p1, p2, res, cast(TMS, (op - LUA_OPADD) + TM_ADD));
131*088332b5SXin Li   }
132*088332b5SXin Li }
133*088332b5SXin Li 
134*088332b5SXin Li 
luaO_hexavalue(int c)135*088332b5SXin Li int luaO_hexavalue (int c) {
136*088332b5SXin Li   if (lisdigit(c)) return c - '0';
137*088332b5SXin Li   else return (ltolower(c) - 'a') + 10;
138*088332b5SXin Li }
139*088332b5SXin Li 
140*088332b5SXin Li 
isneg(const char ** s)141*088332b5SXin Li static int isneg (const char **s) {
142*088332b5SXin Li   if (**s == '-') { (*s)++; return 1; }
143*088332b5SXin Li   else if (**s == '+') (*s)++;
144*088332b5SXin Li   return 0;
145*088332b5SXin Li }
146*088332b5SXin Li 
147*088332b5SXin Li 
148*088332b5SXin Li 
149*088332b5SXin Li /*
150*088332b5SXin Li ** {==================================================================
151*088332b5SXin Li ** Lua's implementation for 'lua_strx2number'
152*088332b5SXin Li ** ===================================================================
153*088332b5SXin Li */
154*088332b5SXin Li 
155*088332b5SXin Li #if !defined(lua_strx2number)
156*088332b5SXin Li 
157*088332b5SXin Li /* maximum number of significant digits to read (to avoid overflows
158*088332b5SXin Li    even with single floats) */
159*088332b5SXin Li #define MAXSIGDIG	30
160*088332b5SXin Li 
161*088332b5SXin Li /*
162*088332b5SXin Li ** convert a hexadecimal numeric string to a number, following
163*088332b5SXin Li ** C99 specification for 'strtod'
164*088332b5SXin Li */
lua_strx2number(const char * s,char ** endptr)165*088332b5SXin Li static lua_Number lua_strx2number (const char *s, char **endptr) {
166*088332b5SXin Li   int dot = lua_getlocaledecpoint();
167*088332b5SXin Li   lua_Number r = 0.0;  /* result (accumulator) */
168*088332b5SXin Li   int sigdig = 0;  /* number of significant digits */
169*088332b5SXin Li   int nosigdig = 0;  /* number of non-significant digits */
170*088332b5SXin Li   int e = 0;  /* exponent correction */
171*088332b5SXin Li   int neg;  /* 1 if number is negative */
172*088332b5SXin Li   int hasdot = 0;  /* true after seen a dot */
173*088332b5SXin Li   *endptr = cast_charp(s);  /* nothing is valid yet */
174*088332b5SXin Li   while (lisspace(cast_uchar(*s))) s++;  /* skip initial spaces */
175*088332b5SXin Li   neg = isneg(&s);  /* check sign */
176*088332b5SXin Li   if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')))  /* check '0x' */
177*088332b5SXin Li     return 0.0;  /* invalid format (no '0x') */
178*088332b5SXin Li   for (s += 2; ; s++) {  /* skip '0x' and read numeral */
179*088332b5SXin Li     if (*s == dot) {
180*088332b5SXin Li       if (hasdot) break;  /* second dot? stop loop */
181*088332b5SXin Li       else hasdot = 1;
182*088332b5SXin Li     }
183*088332b5SXin Li     else if (lisxdigit(cast_uchar(*s))) {
184*088332b5SXin Li       if (sigdig == 0 && *s == '0')  /* non-significant digit (zero)? */
185*088332b5SXin Li         nosigdig++;
186*088332b5SXin Li       else if (++sigdig <= MAXSIGDIG)  /* can read it without overflow? */
187*088332b5SXin Li           r = (r * cast_num(16.0)) + luaO_hexavalue(*s);
188*088332b5SXin Li       else e++; /* too many digits; ignore, but still count for exponent */
189*088332b5SXin Li       if (hasdot) e--;  /* decimal digit? correct exponent */
190*088332b5SXin Li     }
191*088332b5SXin Li     else break;  /* neither a dot nor a digit */
192*088332b5SXin Li   }
193*088332b5SXin Li   if (nosigdig + sigdig == 0)  /* no digits? */
194*088332b5SXin Li     return 0.0;  /* invalid format */
195*088332b5SXin Li   *endptr = cast_charp(s);  /* valid up to here */
196*088332b5SXin Li   e *= 4;  /* each digit multiplies/divides value by 2^4 */
197*088332b5SXin Li   if (*s == 'p' || *s == 'P') {  /* exponent part? */
198*088332b5SXin Li     int exp1 = 0;  /* exponent value */
199*088332b5SXin Li     int neg1;  /* exponent sign */
200*088332b5SXin Li     s++;  /* skip 'p' */
201*088332b5SXin Li     neg1 = isneg(&s);  /* sign */
202*088332b5SXin Li     if (!lisdigit(cast_uchar(*s)))
203*088332b5SXin Li       return 0.0;  /* invalid; must have at least one digit */
204*088332b5SXin Li     while (lisdigit(cast_uchar(*s)))  /* read exponent */
205*088332b5SXin Li       exp1 = exp1 * 10 + *(s++) - '0';
206*088332b5SXin Li     if (neg1) exp1 = -exp1;
207*088332b5SXin Li     e += exp1;
208*088332b5SXin Li     *endptr = cast_charp(s);  /* valid up to here */
209*088332b5SXin Li   }
210*088332b5SXin Li   if (neg) r = -r;
211*088332b5SXin Li   return l_mathop(ldexp)(r, e);
212*088332b5SXin Li }
213*088332b5SXin Li 
214*088332b5SXin Li #endif
215*088332b5SXin Li /* }====================================================== */
216*088332b5SXin Li 
217*088332b5SXin Li 
218*088332b5SXin Li /* maximum length of a numeral to be converted to a number */
219*088332b5SXin Li #if !defined (L_MAXLENNUM)
220*088332b5SXin Li #define L_MAXLENNUM	200
221*088332b5SXin Li #endif
222*088332b5SXin Li 
223*088332b5SXin Li /*
224*088332b5SXin Li ** Convert string 's' to a Lua number (put in 'result'). Return NULL on
225*088332b5SXin Li ** fail or the address of the ending '\0' on success. ('mode' == 'x')
226*088332b5SXin Li ** means a hexadecimal numeral.
227*088332b5SXin Li */
l_str2dloc(const char * s,lua_Number * result,int mode)228*088332b5SXin Li static const char *l_str2dloc (const char *s, lua_Number *result, int mode) {
229*088332b5SXin Li   char *endptr;
230*088332b5SXin Li   *result = (mode == 'x') ? lua_strx2number(s, &endptr)  /* try to convert */
231*088332b5SXin Li                           : lua_str2number(s, &endptr);
232*088332b5SXin Li   if (endptr == s) return NULL;  /* nothing recognized? */
233*088332b5SXin Li   while (lisspace(cast_uchar(*endptr))) endptr++;  /* skip trailing spaces */
234*088332b5SXin Li   return (*endptr == '\0') ? endptr : NULL;  /* OK iff no trailing chars */
235*088332b5SXin Li }
236*088332b5SXin Li 
237*088332b5SXin Li 
238*088332b5SXin Li /*
239*088332b5SXin Li ** Convert string 's' to a Lua number (put in 'result') handling the
240*088332b5SXin Li ** current locale.
241*088332b5SXin Li ** This function accepts both the current locale or a dot as the radix
242*088332b5SXin Li ** mark. If the conversion fails, it may mean number has a dot but
243*088332b5SXin Li ** locale accepts something else. In that case, the code copies 's'
244*088332b5SXin Li ** to a buffer (because 's' is read-only), changes the dot to the
245*088332b5SXin Li ** current locale radix mark, and tries to convert again.
246*088332b5SXin Li ** The variable 'mode' checks for special characters in the string:
247*088332b5SXin Li ** - 'n' means 'inf' or 'nan' (which should be rejected)
248*088332b5SXin Li ** - 'x' means a hexadecimal numeral
249*088332b5SXin Li ** - '.' just optimizes the search for the common case (no special chars)
250*088332b5SXin Li */
l_str2d(const char * s,lua_Number * result)251*088332b5SXin Li static const char *l_str2d (const char *s, lua_Number *result) {
252*088332b5SXin Li   const char *endptr;
253*088332b5SXin Li   const char *pmode = strpbrk(s, ".xXnN");  /* look for special chars */
254*088332b5SXin Li   int mode = pmode ? ltolower(cast_uchar(*pmode)) : 0;
255*088332b5SXin Li   if (mode == 'n')  /* reject 'inf' and 'nan' */
256*088332b5SXin Li     return NULL;
257*088332b5SXin Li   endptr = l_str2dloc(s, result, mode);  /* try to convert */
258*088332b5SXin Li   if (endptr == NULL) {  /* failed? may be a different locale */
259*088332b5SXin Li     char buff[L_MAXLENNUM + 1];
260*088332b5SXin Li     const char *pdot = strchr(s, '.');
261*088332b5SXin Li     if (strlen(s) > L_MAXLENNUM || pdot == NULL)
262*088332b5SXin Li       return NULL;  /* string too long or no dot; fail */
263*088332b5SXin Li     strcpy(buff, s);  /* copy string to buffer */
264*088332b5SXin Li     buff[pdot - s] = lua_getlocaledecpoint();  /* correct decimal point */
265*088332b5SXin Li     endptr = l_str2dloc(buff, result, mode);  /* try again */
266*088332b5SXin Li     if (endptr != NULL)
267*088332b5SXin Li       endptr = s + (endptr - buff);  /* make relative to 's' */
268*088332b5SXin Li   }
269*088332b5SXin Li   return endptr;
270*088332b5SXin Li }
271*088332b5SXin Li 
272*088332b5SXin Li 
273*088332b5SXin Li #define MAXBY10		cast(lua_Unsigned, LUA_MAXINTEGER / 10)
274*088332b5SXin Li #define MAXLASTD	cast_int(LUA_MAXINTEGER % 10)
275*088332b5SXin Li 
l_str2int(const char * s,lua_Integer * result)276*088332b5SXin Li static const char *l_str2int (const char *s, lua_Integer *result) {
277*088332b5SXin Li   lua_Unsigned a = 0;
278*088332b5SXin Li   int empty = 1;
279*088332b5SXin Li   int neg;
280*088332b5SXin Li   while (lisspace(cast_uchar(*s))) s++;  /* skip initial spaces */
281*088332b5SXin Li   neg = isneg(&s);
282*088332b5SXin Li   if (s[0] == '0' &&
283*088332b5SXin Li       (s[1] == 'x' || s[1] == 'X')) {  /* hex? */
284*088332b5SXin Li     s += 2;  /* skip '0x' */
285*088332b5SXin Li     for (; lisxdigit(cast_uchar(*s)); s++) {
286*088332b5SXin Li       a = a * 16 + luaO_hexavalue(*s);
287*088332b5SXin Li       empty = 0;
288*088332b5SXin Li     }
289*088332b5SXin Li   }
290*088332b5SXin Li   else {  /* decimal */
291*088332b5SXin Li     for (; lisdigit(cast_uchar(*s)); s++) {
292*088332b5SXin Li       int d = *s - '0';
293*088332b5SXin Li       if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg))  /* overflow? */
294*088332b5SXin Li         return NULL;  /* do not accept it (as integer) */
295*088332b5SXin Li       a = a * 10 + d;
296*088332b5SXin Li       empty = 0;
297*088332b5SXin Li     }
298*088332b5SXin Li   }
299*088332b5SXin Li   while (lisspace(cast_uchar(*s))) s++;  /* skip trailing spaces */
300*088332b5SXin Li   if (empty || *s != '\0') return NULL;  /* something wrong in the numeral */
301*088332b5SXin Li   else {
302*088332b5SXin Li     *result = l_castU2S((neg) ? 0u - a : a);
303*088332b5SXin Li     return s;
304*088332b5SXin Li   }
305*088332b5SXin Li }
306*088332b5SXin Li 
307*088332b5SXin Li 
luaO_str2num(const char * s,TValue * o)308*088332b5SXin Li size_t luaO_str2num (const char *s, TValue *o) {
309*088332b5SXin Li   lua_Integer i; lua_Number n;
310*088332b5SXin Li   const char *e;
311*088332b5SXin Li   if ((e = l_str2int(s, &i)) != NULL) {  /* try as an integer */
312*088332b5SXin Li     setivalue(o, i);
313*088332b5SXin Li   }
314*088332b5SXin Li   else if ((e = l_str2d(s, &n)) != NULL) {  /* else try as a float */
315*088332b5SXin Li     setfltvalue(o, n);
316*088332b5SXin Li   }
317*088332b5SXin Li   else
318*088332b5SXin Li     return 0;  /* conversion failed */
319*088332b5SXin Li   return (e - s) + 1;  /* success; return string size */
320*088332b5SXin Li }
321*088332b5SXin Li 
322*088332b5SXin Li 
luaO_utf8esc(char * buff,unsigned long x)323*088332b5SXin Li int luaO_utf8esc (char *buff, unsigned long x) {
324*088332b5SXin Li   int n = 1;  /* number of bytes put in buffer (backwards) */
325*088332b5SXin Li   lua_assert(x <= 0x7FFFFFFFu);
326*088332b5SXin Li   if (x < 0x80)  /* ascii? */
327*088332b5SXin Li     buff[UTF8BUFFSZ - 1] = cast_char(x);
328*088332b5SXin Li   else {  /* need continuation bytes */
329*088332b5SXin Li     unsigned int mfb = 0x3f;  /* maximum that fits in first byte */
330*088332b5SXin Li     do {  /* add continuation bytes */
331*088332b5SXin Li       buff[UTF8BUFFSZ - (n++)] = cast_char(0x80 | (x & 0x3f));
332*088332b5SXin Li       x >>= 6;  /* remove added bits */
333*088332b5SXin Li       mfb >>= 1;  /* now there is one less bit available in first byte */
334*088332b5SXin Li     } while (x > mfb);  /* still needs continuation byte? */
335*088332b5SXin Li     buff[UTF8BUFFSZ - n] = cast_char((~mfb << 1) | x);  /* add first byte */
336*088332b5SXin Li   }
337*088332b5SXin Li   return n;
338*088332b5SXin Li }
339*088332b5SXin Li 
340*088332b5SXin Li 
341*088332b5SXin Li /*
342*088332b5SXin Li ** Maximum length of the conversion of a number to a string. Must be
343*088332b5SXin Li ** enough to accommodate both LUA_INTEGER_FMT and LUA_NUMBER_FMT.
344*088332b5SXin Li ** (For a long long int, this is 19 digits plus a sign and a final '\0',
345*088332b5SXin Li ** adding to 21. For a long double, it can go to a sign, 33 digits,
346*088332b5SXin Li ** the dot, an exponent letter, an exponent sign, 5 exponent digits,
347*088332b5SXin Li ** and a final '\0', adding to 43.)
348*088332b5SXin Li */
349*088332b5SXin Li #define MAXNUMBER2STR	44
350*088332b5SXin Li 
351*088332b5SXin Li 
352*088332b5SXin Li /*
353*088332b5SXin Li ** Convert a number object to a string, adding it to a buffer
354*088332b5SXin Li */
tostringbuff(TValue * obj,char * buff)355*088332b5SXin Li static int tostringbuff (TValue *obj, char *buff) {
356*088332b5SXin Li   int len;
357*088332b5SXin Li   lua_assert(ttisnumber(obj));
358*088332b5SXin Li   if (ttisinteger(obj))
359*088332b5SXin Li     len = lua_integer2str(buff, MAXNUMBER2STR, ivalue(obj));
360*088332b5SXin Li   else {
361*088332b5SXin Li     len = lua_number2str(buff, MAXNUMBER2STR, fltvalue(obj));
362*088332b5SXin Li     if (buff[strspn(buff, "-0123456789")] == '\0') {  /* looks like an int? */
363*088332b5SXin Li       buff[len++] = lua_getlocaledecpoint();
364*088332b5SXin Li       buff[len++] = '0';  /* adds '.0' to result */
365*088332b5SXin Li     }
366*088332b5SXin Li   }
367*088332b5SXin Li   return len;
368*088332b5SXin Li }
369*088332b5SXin Li 
370*088332b5SXin Li 
371*088332b5SXin Li /*
372*088332b5SXin Li ** Convert a number object to a Lua string, replacing the value at 'obj'
373*088332b5SXin Li */
luaO_tostring(lua_State * L,TValue * obj)374*088332b5SXin Li void luaO_tostring (lua_State *L, TValue *obj) {
375*088332b5SXin Li   char buff[MAXNUMBER2STR];
376*088332b5SXin Li   int len = tostringbuff(obj, buff);
377*088332b5SXin Li   setsvalue(L, obj, luaS_newlstr(L, buff, len));
378*088332b5SXin Li }
379*088332b5SXin Li 
380*088332b5SXin Li 
381*088332b5SXin Li 
382*088332b5SXin Li 
383*088332b5SXin Li /*
384*088332b5SXin Li ** {==================================================================
385*088332b5SXin Li ** 'luaO_pushvfstring'
386*088332b5SXin Li ** ===================================================================
387*088332b5SXin Li */
388*088332b5SXin Li 
389*088332b5SXin Li /* size for buffer space used by 'luaO_pushvfstring' */
390*088332b5SXin Li #define BUFVFS		200
391*088332b5SXin Li 
392*088332b5SXin Li /* buffer used by 'luaO_pushvfstring' */
393*088332b5SXin Li typedef struct BuffFS {
394*088332b5SXin Li   lua_State *L;
395*088332b5SXin Li   int pushed;  /* number of string pieces already on the stack */
396*088332b5SXin Li   int blen;  /* length of partial string in 'space' */
397*088332b5SXin Li   char space[BUFVFS];  /* holds last part of the result */
398*088332b5SXin Li } BuffFS;
399*088332b5SXin Li 
400*088332b5SXin Li 
401*088332b5SXin Li /*
402*088332b5SXin Li ** Push given string to the stack, as part of the buffer, and
403*088332b5SXin Li ** join the partial strings in the stack into one.
404*088332b5SXin Li */
pushstr(BuffFS * buff,const char * str,size_t l)405*088332b5SXin Li static void pushstr (BuffFS *buff, const char *str, size_t l) {
406*088332b5SXin Li   lua_State *L = buff->L;
407*088332b5SXin Li   setsvalue2s(L, L->top, luaS_newlstr(L, str, l));
408*088332b5SXin Li   L->top++;  /* may use one extra slot */
409*088332b5SXin Li   buff->pushed++;
410*088332b5SXin Li   luaV_concat(L, buff->pushed);  /* join partial results into one */
411*088332b5SXin Li   buff->pushed = 1;
412*088332b5SXin Li }
413*088332b5SXin Li 
414*088332b5SXin Li 
415*088332b5SXin Li /*
416*088332b5SXin Li ** empty the buffer space into the stack
417*088332b5SXin Li */
clearbuff(BuffFS * buff)418*088332b5SXin Li static void clearbuff (BuffFS *buff) {
419*088332b5SXin Li   pushstr(buff, buff->space, buff->blen);  /* push buffer contents */
420*088332b5SXin Li   buff->blen = 0;  /* space now is empty */
421*088332b5SXin Li }
422*088332b5SXin Li 
423*088332b5SXin Li 
424*088332b5SXin Li /*
425*088332b5SXin Li ** Get a space of size 'sz' in the buffer. If buffer has not enough
426*088332b5SXin Li ** space, empty it. 'sz' must fit in an empty buffer.
427*088332b5SXin Li */
getbuff(BuffFS * buff,int sz)428*088332b5SXin Li static char *getbuff (BuffFS *buff, int sz) {
429*088332b5SXin Li   lua_assert(buff->blen <= BUFVFS); lua_assert(sz <= BUFVFS);
430*088332b5SXin Li   if (sz > BUFVFS - buff->blen)  /* not enough space? */
431*088332b5SXin Li     clearbuff(buff);
432*088332b5SXin Li   return buff->space + buff->blen;
433*088332b5SXin Li }
434*088332b5SXin Li 
435*088332b5SXin Li 
436*088332b5SXin Li #define addsize(b,sz)	((b)->blen += (sz))
437*088332b5SXin Li 
438*088332b5SXin Li 
439*088332b5SXin Li /*
440*088332b5SXin Li ** Add 'str' to the buffer. If string is larger than the buffer space,
441*088332b5SXin Li ** push the string directly to the stack.
442*088332b5SXin Li */
addstr2buff(BuffFS * buff,const char * str,size_t slen)443*088332b5SXin Li static void addstr2buff (BuffFS *buff, const char *str, size_t slen) {
444*088332b5SXin Li   if (slen <= BUFVFS) {  /* does string fit into buffer? */
445*088332b5SXin Li     char *bf = getbuff(buff, cast_int(slen));
446*088332b5SXin Li     memcpy(bf, str, slen);  /* add string to buffer */
447*088332b5SXin Li     addsize(buff, cast_int(slen));
448*088332b5SXin Li   }
449*088332b5SXin Li   else {  /* string larger than buffer */
450*088332b5SXin Li     clearbuff(buff);  /* string comes after buffer's content */
451*088332b5SXin Li     pushstr(buff, str, slen);  /* push string */
452*088332b5SXin Li   }
453*088332b5SXin Li }
454*088332b5SXin Li 
455*088332b5SXin Li 
456*088332b5SXin Li /*
457*088332b5SXin Li ** Add a number to the buffer.
458*088332b5SXin Li */
addnum2buff(BuffFS * buff,TValue * num)459*088332b5SXin Li static void addnum2buff (BuffFS *buff, TValue *num) {
460*088332b5SXin Li   char *numbuff = getbuff(buff, MAXNUMBER2STR);
461*088332b5SXin Li   int len = tostringbuff(num, numbuff);  /* format number into 'numbuff' */
462*088332b5SXin Li   addsize(buff, len);
463*088332b5SXin Li }
464*088332b5SXin Li 
465*088332b5SXin Li 
466*088332b5SXin Li /*
467*088332b5SXin Li ** this function handles only '%d', '%c', '%f', '%p', '%s', and '%%'
468*088332b5SXin Li    conventional formats, plus Lua-specific '%I' and '%U'
469*088332b5SXin Li */
luaO_pushvfstring(lua_State * L,const char * fmt,va_list argp)470*088332b5SXin Li const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
471*088332b5SXin Li   BuffFS buff;  /* holds last part of the result */
472*088332b5SXin Li   const char *e;  /* points to next '%' */
473*088332b5SXin Li   buff.pushed = buff.blen = 0;
474*088332b5SXin Li   buff.L = L;
475*088332b5SXin Li   while ((e = strchr(fmt, '%')) != NULL) {
476*088332b5SXin Li     addstr2buff(&buff, fmt, e - fmt);  /* add 'fmt' up to '%' */
477*088332b5SXin Li     switch (*(e + 1)) {  /* conversion specifier */
478*088332b5SXin Li       case 's': {  /* zero-terminated string */
479*088332b5SXin Li         const char *s = va_arg(argp, char *);
480*088332b5SXin Li         if (s == NULL) s = "(null)";
481*088332b5SXin Li         addstr2buff(&buff, s, strlen(s));
482*088332b5SXin Li         break;
483*088332b5SXin Li       }
484*088332b5SXin Li       case 'c': {  /* an 'int' as a character */
485*088332b5SXin Li         char c = cast_uchar(va_arg(argp, int));
486*088332b5SXin Li         addstr2buff(&buff, &c, sizeof(char));
487*088332b5SXin Li         break;
488*088332b5SXin Li       }
489*088332b5SXin Li       case 'd': {  /* an 'int' */
490*088332b5SXin Li         TValue num;
491*088332b5SXin Li         setivalue(&num, va_arg(argp, int));
492*088332b5SXin Li         addnum2buff(&buff, &num);
493*088332b5SXin Li         break;
494*088332b5SXin Li       }
495*088332b5SXin Li       case 'I': {  /* a 'lua_Integer' */
496*088332b5SXin Li         TValue num;
497*088332b5SXin Li         setivalue(&num, cast(lua_Integer, va_arg(argp, l_uacInt)));
498*088332b5SXin Li         addnum2buff(&buff, &num);
499*088332b5SXin Li         break;
500*088332b5SXin Li       }
501*088332b5SXin Li       case 'f': {  /* a 'lua_Number' */
502*088332b5SXin Li         TValue num;
503*088332b5SXin Li         setfltvalue(&num, cast_num(va_arg(argp, l_uacNumber)));
504*088332b5SXin Li         addnum2buff(&buff, &num);
505*088332b5SXin Li         break;
506*088332b5SXin Li       }
507*088332b5SXin Li       case 'p': {  /* a pointer */
508*088332b5SXin Li         const int sz = 3 * sizeof(void*) + 8; /* enough space for '%p' */
509*088332b5SXin Li         char *bf = getbuff(&buff, sz);
510*088332b5SXin Li         void *p = va_arg(argp, void *);
511*088332b5SXin Li         int len = lua_pointer2str(bf, sz, p);
512*088332b5SXin Li         addsize(&buff, len);
513*088332b5SXin Li         break;
514*088332b5SXin Li       }
515*088332b5SXin Li       case 'U': {  /* a 'long' as a UTF-8 sequence */
516*088332b5SXin Li         char bf[UTF8BUFFSZ];
517*088332b5SXin Li         int len = luaO_utf8esc(bf, va_arg(argp, long));
518*088332b5SXin Li         addstr2buff(&buff, bf + UTF8BUFFSZ - len, len);
519*088332b5SXin Li         break;
520*088332b5SXin Li       }
521*088332b5SXin Li       case '%': {
522*088332b5SXin Li         addstr2buff(&buff, "%", 1);
523*088332b5SXin Li         break;
524*088332b5SXin Li       }
525*088332b5SXin Li       default: {
526*088332b5SXin Li         luaG_runerror(L, "invalid option '%%%c' to 'lua_pushfstring'",
527*088332b5SXin Li                          *(e + 1));
528*088332b5SXin Li       }
529*088332b5SXin Li     }
530*088332b5SXin Li     fmt = e + 2;  /* skip '%' and the specifier */
531*088332b5SXin Li   }
532*088332b5SXin Li   addstr2buff(&buff, fmt, strlen(fmt));  /* rest of 'fmt' */
533*088332b5SXin Li   clearbuff(&buff);  /* empty buffer into the stack */
534*088332b5SXin Li   lua_assert(buff.pushed == 1);
535*088332b5SXin Li   return svalue(s2v(L->top - 1));
536*088332b5SXin Li }
537*088332b5SXin Li 
538*088332b5SXin Li 
luaO_pushfstring(lua_State * L,const char * fmt,...)539*088332b5SXin Li const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) {
540*088332b5SXin Li   const char *msg;
541*088332b5SXin Li   va_list argp;
542*088332b5SXin Li   va_start(argp, fmt);
543*088332b5SXin Li   msg = luaO_pushvfstring(L, fmt, argp);
544*088332b5SXin Li   va_end(argp);
545*088332b5SXin Li   return msg;
546*088332b5SXin Li }
547*088332b5SXin Li 
548*088332b5SXin Li /* }================================================================== */
549*088332b5SXin Li 
550*088332b5SXin Li 
551*088332b5SXin Li #define RETS	"..."
552*088332b5SXin Li #define PRE	"[string \""
553*088332b5SXin Li #define POS	"\"]"
554*088332b5SXin Li 
555*088332b5SXin Li #define addstr(a,b,l)	( memcpy(a,b,(l) * sizeof(char)), a += (l) )
556*088332b5SXin Li 
luaO_chunkid(char * out,const char * source,size_t srclen)557*088332b5SXin Li void luaO_chunkid (char *out, const char *source, size_t srclen) {
558*088332b5SXin Li   size_t bufflen = LUA_IDSIZE;  /* free space in buffer */
559*088332b5SXin Li   if (*source == '=') {  /* 'literal' source */
560*088332b5SXin Li     if (srclen <= bufflen)  /* small enough? */
561*088332b5SXin Li       memcpy(out, source + 1, srclen * sizeof(char));
562*088332b5SXin Li     else {  /* truncate it */
563*088332b5SXin Li       addstr(out, source + 1, bufflen - 1);
564*088332b5SXin Li       *out = '\0';
565*088332b5SXin Li     }
566*088332b5SXin Li   }
567*088332b5SXin Li   else if (*source == '@') {  /* file name */
568*088332b5SXin Li     if (srclen <= bufflen)  /* small enough? */
569*088332b5SXin Li       memcpy(out, source + 1, srclen * sizeof(char));
570*088332b5SXin Li     else {  /* add '...' before rest of name */
571*088332b5SXin Li       addstr(out, RETS, LL(RETS));
572*088332b5SXin Li       bufflen -= LL(RETS);
573*088332b5SXin Li       memcpy(out, source + 1 + srclen - bufflen, bufflen * sizeof(char));
574*088332b5SXin Li     }
575*088332b5SXin Li   }
576*088332b5SXin Li   else {  /* string; format as [string "source"] */
577*088332b5SXin Li     const char *nl = strchr(source, '\n');  /* find first new line (if any) */
578*088332b5SXin Li     addstr(out, PRE, LL(PRE));  /* add prefix */
579*088332b5SXin Li     bufflen -= LL(PRE RETS POS) + 1;  /* save space for prefix+suffix+'\0' */
580*088332b5SXin Li     if (srclen < bufflen && nl == NULL) {  /* small one-line source? */
581*088332b5SXin Li       addstr(out, source, srclen);  /* keep it */
582*088332b5SXin Li     }
583*088332b5SXin Li     else {
584*088332b5SXin Li       if (nl != NULL) srclen = nl - source;  /* stop at first newline */
585*088332b5SXin Li       if (srclen > bufflen) srclen = bufflen;
586*088332b5SXin Li       addstr(out, source, srclen);
587*088332b5SXin Li       addstr(out, RETS, LL(RETS));
588*088332b5SXin Li     }
589*088332b5SXin Li     memcpy(out, POS, (LL(POS) + 1) * sizeof(char));
590*088332b5SXin Li   }
591*088332b5SXin Li }
592*088332b5SXin Li 
593