?login_element?

Subversion Repositories NedoOS

Rev

Blame | Last modification | View Log | Download

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