lobject.c(5.3.4)解析

来源:互联网 发布:彩票数据分析 编辑:程序博客网 时间:2024/06/05 11:11
/*** $Id: lobject.c,v 2.113 2016/12/22 13:08:50 roberto Exp $** Some generic functions over Lua objects** See Copyright Notice in lua.h*/#define lobject_c#define LUA_CORE#include "lprefix.h"#include <locale.h>#include <math.h>#include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include "lua.h"#include "lctype.h"#include "ldebug.h"#include "ldo.h"#include "lmem.h"#include "lobject.h"#include "lstate.h"#include "lstring.h"#include "lvm.h"LUAI_DDEF const TValue luaO_nilobject_ = {NILCONSTANT};/*** converts an integer to a "floating point byte", represented as** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if** eeeee != 0 and (xxx) otherwise.*/// 使用浮点数的方法扩充整数范围(0 ~ 15 * 2^30)// e代表指数// 如果传进来的x没有超出三位尾数的范围那么就直接返回int luaO_int2fb (unsigned int x) {  int e = 0;  /* exponent */  if (x < 8) return x;  while (x >= (8 << 4)) {  /* coarse steps */    x = (x + 0xf) >> 4;  /* x = ceil(x / 16) */    e += 4;  }  while (x >= (8 << 1)) {  /* fine steps */    x = (x + 1) >> 1;  /* x = ceil(x / 2) */    e++;  }  return ((e+1) << 3) | (cast_int(x) - 8);}/* converts back */int luaO_fb2int (int x) {  return (x < 8) ? x : ((x & 7) + 8) << ((x >> 3) - 1);}/*** Computes ceil(log2(x))*/// 解释一下这个函数,作用是计算 ceil(log2(x)),也就是求出x的以2为底的对数,在对结果进行向上取整// 函数的大意就是,先把x转换成2^n的形式,然后求出n就可以了// 打个比方说传进来的是256,那么就是2^8 这里的log_2数组之所以这么写,就是为了按照这种思想求n// 如果传进来的数字在128和256之间  那么也用8来作为n的结果。目的就是实现ceil的向上取整// 如果x大于256,就让x除以256,然后把结果加上8int luaO_ceillog2 (unsigned int x) {  static const lu_byte log_2[256] = {  /* log_2[i] = ceil(log2(i - 1)) */    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,    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,    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,    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,    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,    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,    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,    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  };  int l = 0;  x--;  while (x >= 256) { l += 8; x >>= 8; }  return l + log_2[x];}// 两个整数之间的运算// op是传进来的操作码,定义在lua.h中,LUA_OPADD是0,LUA_OPBNOT是13// intop和luaV_mod等算术操作定义在lvm.h中,都是基于堆栈的算术操作,到那里再具体分析// LUA_OPADD:加法操作// LUA_OPSUB:减法操作// LUA_OPMUL:乘法操作// LUA_OPMOD:取摸操作// LUA_OPIDIV:向下取整的除法操作// LUA_OPBAND:按位与操作// LUA_OPBOR:按位或操作// LUA_OPBXOR:按位异或操作// LUA_OPSHL:左移操作// LUA_OPSHR:右移操作// LUA_OPUNM:取负操作(就是沿用的减法操作,第一个操作数为0)// LUA_OPBNOT:按位取反操作static lua_Integer intarith (lua_State *L, int op, lua_Integer v1,                                                   lua_Integer v2) {  switch (op) {    case LUA_OPADD: return intop(+, v1, v2);    case LUA_OPSUB:return intop(-, v1, v2);    case LUA_OPMUL:return intop(*, v1, v2);    case LUA_OPMOD: return luaV_mod(L, v1, v2);    case LUA_OPIDIV: return luaV_div(L, v1, v2);    case LUA_OPBAND: return intop(&, v1, v2);    case LUA_OPBOR: return intop(|, v1, v2);    case LUA_OPBXOR: return intop(^, v1, v2);    case LUA_OPSHL: return luaV_shiftl(v1, v2);    case LUA_OPSHR: return luaV_shiftl(v1, -v2);    case LUA_OPUNM: return intop(-, 0, v1);    case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1);    default: lua_assert(0); return 0;  }}// 两个number之间的运算// luai_numadd等方法定义在llimits.h中,内部操作依靠+-*等操作,取摸等复杂操作则调用C函数// LUA_OPADD:加法操作// LUA_OPSUB:减法操作// LUA_OPMUL:乘法操作// LUA_OPDIV:普通的除法操作// LUA_OPPOW:幂操作// LUA_OPIDIV:向下取整的除法操作// LUA_OPUNM:取负操作// LUA_OPMOD:取摸操作static lua_Number numarith (lua_State *L, int op, lua_Number v1,                                                  lua_Number v2) {  switch (op) {    case LUA_OPADD: return luai_numadd(L, v1, v2);    case LUA_OPSUB: return luai_numsub(L, v1, v2);    case LUA_OPMUL: return luai_nummul(L, v1, v2);    case LUA_OPDIV: return luai_numdiv(L, v1, v2);    case LUA_OPPOW: return luai_numpow(L, v1, v2);    case LUA_OPIDIV: return luai_numidiv(L, v1, v2);    case LUA_OPUNM: return luai_numunm(L, v1);    case LUA_OPMOD: {      lua_Number m;      luai_nummod(L, v1, v2, m);      return m;    }    default: lua_assert(0); return 0;  }}// 两个TValue的算术运算// 具体做法是先把TValue的具体值取出来然后再调用上面的两种类型函数进行操作void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2,                 TValue *res) {  switch (op) {    case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR:    case LUA_OPSHL: case LUA_OPSHR:    case LUA_OPBNOT: {  /* operate only on integers */      lua_Integer i1; lua_Integer i2;      if (tointeger(p1, &i1) && tointeger(p2, &i2)) {        setivalue(res, intarith(L, op, i1, i2));        return;      }      else break;  /* go to the end */    }    case LUA_OPDIV: case LUA_OPPOW: {  /* operate only on floats */      lua_Number n1; lua_Number n2;      if (tonumber(p1, &n1) && tonumber(p2, &n2)) {        setfltvalue(res, numarith(L, op, n1, n2));        return;      }      else break;  /* go to the end */    }    default: {  /* other operations */      lua_Number n1; lua_Number n2;      if (ttisinteger(p1) && ttisinteger(p2)) {        setivalue(res, intarith(L, op, ivalue(p1), ivalue(p2)));        return;      }      else if (tonumber(p1, &n1) && tonumber(p2, &n2)) {        setfltvalue(res, numarith(L, op, n1, n2));        return;      }      else break;  /* go to the end */    }  }  /* could not perform raw operation; try metamethod */  lua_assert(L != NULL);  /* should not fail when folding (compile time) */  luaT_trybinTM(L, p1, p2, res, cast(TMS, (op - LUA_OPADD) + TM_ADD));}// lisdigit检查参数是否为十进制数字字符,当c为数字0~9时,返回非零值,否则返回零// 如果c是十进制字符的话,就返回具体的数字// 如果不是的话,ltolower就把字符转成小写字符之后,再减去'a'得到数字,加上10,就等于说16进制的字符变成了数字// 总的来说,luaO_hexavalue的作用就是把能转变成数字的字符变成数字并返回int luaO_hexavalue (int c) {  if (lisdigit(c)) return c - '0';  else return (ltolower(c) - 'a') + 10;}// 获取*s指向的字符是'+'还是'-'// 1代表负,0代表正,并且s向前移一位static int isneg (const char **s) {  if (**s == '-') { (*s)++; return 1; }  else if (**s == '+') (*s)++;  return 0;}/*** {==================================================================** Lua's implementation for 'lua_strx2number'** ===================================================================*/#if !defined(lua_strx2number)/* maximum number of significant digits to read (to avoid overflows   even with single floats) */#define MAXSIGDIG30/*** convert an hexadecimal numeric string to a number, following** C99 specification for 'strtod'*/// 将十六进制数字串转换成数字,下面是关于'strtod'的C99规范// lua_getlocaledecpoint得到本地的小数点号(ascii表示'.'为46)// lisspace主要用于检查参数是否为空格字符,若参数c为空格字符,则返回TRUE,否则返回NULL(0)// 首先s跳过前面的空格,然后neg得到*s的符号,1代表负,0代表正// 然后检测开头的两位字符是不是"0x"或"0X",不然的话就不是16进制,直接返回0// 在循环里面刚开始遇见第一个点就把hasdot赋值1,如果第二次再碰见点的话就跳出循环// lisxdigit检查参数是否为16进制数字,如果是的话返回非0值,不然返回0.参数类型为int,但是可以直接将char 类型数据传入.// sigdig代表有意义数字的数量,nosigdig代表没有意义数字的数量(没有意义的就是字符串开头的0,中间的不算)// luaO_hexavalue把参数转换成十进制数字// 重要的操作是r * cast_num(16.0) 把之前的结果乘以16,就代表16进制往左移了一位,然后再加上新的数// 然后超出MAXSIGDIG限制的字符会被计入e,然后小数点后面如果有字符的话会抵消一部分e// endptr是有效字符的下一位static lua_Number lua_strx2number (const char *s, char **endptr) {  int dot = lua_getlocaledecpoint();  lua_Number r = 0.0;  /* result (accumulator) */  int sigdig = 0;  /* number of significant digits */  int nosigdig = 0;  /* number of non-significant digits */  int e = 0;  /* exponent correction */  int neg;  /* 1 if number is negative */  int hasdot = 0;  /* true after seen a dot */  *endptr = cast(char *, s);  /* nothing is valid yet */  while (lisspace(cast_uchar(*s))) s++;  /* skip initial spaces */  neg = isneg(&s);  /* check signal */  if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')))  /* check '0x' */    return 0.0;  /* invalid format (no '0x') */  for (s += 2; ; s++) {  /* skip '0x' and read numeral */    if (*s == dot) {      if (hasdot) break;  /* second dot? stop loop */      else hasdot = 1;    }    else if (lisxdigit(cast_uchar(*s))) {      if (sigdig == 0 && *s == '0')  /* non-significant digit (zero)? */        nosigdig++;      else if (++sigdig <= MAXSIGDIG)  /* can read it without overflow? */          r = (r * cast_num(16.0)) + luaO_hexavalue(*s);      else e++; /* too many digits; ignore, but still count for exponent */      if (hasdot) e--;  /* decimal digit? correct exponent */    }    else break;  /* neither a dot nor a digit */  }  if (nosigdig + sigdig == 0)  /* no digits? */    return 0.0;  /* invalid format */  *endptr = cast(char *, s);  /* valid up to here */  e *= 4;  /* each digit multiplies/divides value by 2^4 */  if (*s == 'p' || *s == 'P') {  /* exponent part? */    int exp1 = 0;  /* exponent value */    int neg1;  /* exponent signal */    s++;  /* skip 'p' */    neg1 = isneg(&s);  /* signal */    if (!lisdigit(cast_uchar(*s)))      return 0.0;  /* invalid; must have at least one digit */    while (lisdigit(cast_uchar(*s)))  /* read exponent */      exp1 = exp1 * 10 + *(s++) - '0';    if (neg1) exp1 = -exp1;    e += exp1;    *endptr = cast(char *, s);  /* valid up to here */  }  if (neg) r = -r;  return l_mathop(ldexp)(r, e);}#endif/* }====================================================== *//* maximum length of a numeral */#if !defined (L_MAXLENNUM)#define L_MAXLENNUM200#endif// lua_strx2number把一个十六进制字符转成数字// lua_str2number把一个普通字符转成数字static const char *l_str2dloc (const char *s, lua_Number *result, int mode) {  char *endptr;  *result = (mode == 'x') ? lua_strx2number(s, &endptr)  /* try to convert */                          : lua_str2number(s, &endptr);  if (endptr == s) return NULL;  /* nothing recognized? */  while (lisspace(cast_uchar(*endptr))) endptr++;  /* skip trailing spaces */  return (*endptr == '\0') ? endptr : NULL;  /* OK if no trailing characters */}/*** Convert string 's' to a Lua number (put in 'result'). Return NULL** on fail or the address of the ending '\0' on success.** 'pmode' points to (and 'mode' contains) special things in the string:** - 'x'/'X' means an hexadecimal numeral** - 'n'/'N' means 'inf' or 'nan' (which should be rejected)** - '.' just optimizes the search for the common case (nothing special)** This function accepts both the current locale or a dot as the radix** mark. If the convertion fails, it may mean number has a dot but** locale accepts something else. In that case, the code copies 's'** to a buffer (because 's' is read-only), changes the dot to the** current locale radix mark, and tries to convert again.*/// 把字符串s转换成number数据,在失败时返回NULL或在成功时返回字符串最后一位的地址(就是'\0'的地址)// strpbrk(const char *s1, const char *s2)是在源字符串(s1)中找出最先含有搜索字符串(s2)中任一字符的位置并返回,若找不到则返回空指针。// pmode指向字符串中特殊的字符('.','x','X','n','N')// 'x'/'X'意味着十六进制字符// 'n'/'N'意味着无穷大或未定义(它们被直接返回)// 该函数接受当前区域设置或点作为基数标记。如果转换失败,那可能意味着数字是一个点并且本地也接受了其他别的东西// 在这种情况下,代码拷贝了一个s来指向一段缓冲区(因为s是只读的),将点更改为当前区域设置的基数,并尝试再次转换。static const char *l_str2d (const char *s, lua_Number *result) {  const char *endptr;  const char *pmode = strpbrk(s, ".xXnN");  int mode = pmode ? ltolower(cast_uchar(*pmode)) : 0;  if (mode == 'n')  /* reject 'inf' and 'nan' */    return NULL;  endptr = l_str2dloc(s, result, mode);  /* try to convert */  if (endptr == NULL) {  /* failed? may be a different locale */    char buff[L_MAXLENNUM + 1];    const char *pdot = strchr(s, '.');    if (strlen(s) > L_MAXLENNUM || pdot == NULL)      return NULL;  /* string too long or no dot; fail */    strcpy(buff, s);  /* copy string to buffer */    buff[pdot - s] = lua_getlocaledecpoint();  /* correct decimal point */    endptr = l_str2dloc(buff, result, mode);  /* try again */    if (endptr != NULL)      endptr = s + (endptr - buff);  /* make relative to 's' */  }  return endptr;}#define MAXBY10cast(lua_Unsigned, LUA_MAXINTEGER / 10)#define MAXLASTDcast_int(LUA_MAXINTEGER % 10)// 把字符串转换为int,结果保存在result中// 通过lisspace跳过开头的空格字符// 然后isneg获取正负号,1代表负,0代表正,并且s向前移一位// 然后判断是不是十六进制,是的话跳过'0x',然后lisxdigit检查参数是否为16进制数字,如果是的话返回非0值,不然返回0.参数类型为int,但是可以直接将char 类型数据传入.// 然后将结果*16并加上新得的数字,luaO_hexavalue的作用就是把能转变成数字的字符变成数字并返回// 10进制的话,原理一样,但是多了一个溢出检测,机制就是判断a是不是大于LUA_MAXINTEGER / 10,因为下一步要进行a*10static const char *l_str2int (const char *s, lua_Integer *result) {  lua_Unsigned a = 0;  int empty = 1;  int neg;  while (lisspace(cast_uchar(*s))) s++;  /* skip initial spaces */  neg = isneg(&s);  if (s[0] == '0' &&      (s[1] == 'x' || s[1] == 'X')) {  /* hex? */    s += 2;  /* skip '0x' */    for (; lisxdigit(cast_uchar(*s)); s++) {      a = a * 16 + luaO_hexavalue(*s);      empty = 0;    }  }  else {  /* decimal */    for (; lisdigit(cast_uchar(*s)); s++) {      int d = *s - '0';      if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg))  /* overflow? */        return NULL;  /* do not accept it (as integer) */      a = a * 10 + d;      empty = 0;    }  }  while (lisspace(cast_uchar(*s))) s++;  /* skip trailing spaces */  if (empty || *s != '\0') return NULL;  /* something wrong in the numeral */  else {    *result = l_castU2S((neg) ? 0u - a : a);    return s;  }}// 把一个字符串转换成数字// 首先调用l_str2int看能不能转换成int,可以的话调用setivalue创建一个类型为LUA_TNUMINT的int// 不行的话调用setfltvalue看能不能转换成float类型的数据,可以的话调用setfltvalue创建一个类型为LUA_TNUMFLT的float// 还是不行的就返回0,代表转换失败// 成功的话返回字符串的长度size_t luaO_str2num (const char *s, TValue *o) {  lua_Integer i; lua_Number n;  const char *e;  if ((e = l_str2int(s, &i)) != NULL) {  /* try as an integer */    setivalue(o, i);  }  else if ((e = l_str2d(s, &n)) != NULL) {  /* else try as a float */    setfltvalue(o, n);  }  else    return 0;  /* conversion failed */  return (e - s) + 1;  /* success; return string size */}// 返回x的utf8字节数量// x <= 0x10FFFF,这里x不能超过unicode的最大编码// x < 0x80属于ascii编码,buff的最后一位保存x,并且返回字节数1// 0x80等于十进制的128// 如果不属于ascii范围的话,就需要延长字节// 首先定义一个mfb,因为ascii的范围为0x00 - 0x7f// 大于ascii的范围之后就需要扩充字节了// else部分不太明白int luaO_utf8esc (char *buff, unsigned long x) {  int n = 1;  /* number of bytes put in buffer (backwards) */  lua_assert(x <= 0x10FFFF);  if (x < 0x80)  /* ascii? */    buff[UTF8BUFFSZ - 1] = cast(char, x);  else {  /* need continuation bytes */    unsigned int mfb = 0x3f;  /* maximum that fits in first byte */    do {  /* add continuation bytes */      buff[UTF8BUFFSZ - (n++)] = cast(char, 0x80 | (x & 0x3f));      x >>= 6;  /* remove added bits */      mfb >>= 1;  /* now there is one less bit available in first byte */    } while (x > mfb);  /* still needs continuation byte? */    buff[UTF8BUFFSZ - n] = cast(char, (~mfb << 1) | x);  /* add first byte */  }  return n;}/* maximum length of the conversion of a number to a string */#define MAXNUMBER2STR50/*** Convert a number object to a string*/// 把一个数字对象转换成字符串// lua_integer2str的作用就是把一个整数转换成字符串,定义在luaconf.h中// lua_number2str的作用就是把一个浮点型数据转换成字符串,定义在luaconf.h中// strspn的原型为:size_t strspn (const char *s,const char * accept)// strspn()从参数s 字符串的开头计算连续的字符,而这些字符都完全是accept 所指字符串中的字符。// 简单的说,若strspn()返回的数值为n,则代表字符串s 开头连续有n 个字符都是属于字符串accept内的字符。// 所以这里通过strspn判断是不是转换成了int值// 如果定义了LUA_COMPAT_FLOATSTRING则在字符串结尾加上0(定义在luaconf.h中)// lua_getlocaledecpoint()返回当地的小数点// 然后调用setsvalue2s创建一个LUA_TSTRING类型的TValue压入栈中void luaO_tostring (lua_State *L, StkId obj) {  char buff[MAXNUMBER2STR];  size_t len;  lua_assert(ttisnumber(obj));  if (ttisinteger(obj))    len = lua_integer2str(buff, sizeof(buff), ivalue(obj));  else {    len = lua_number2str(buff, sizeof(buff), fltvalue(obj));#if !defined(LUA_COMPAT_FLOATSTRING)    if (buff[strspn(buff, "-0123456789")] == '\0') {  /* looks like an int? */      buff[len++] = lua_getlocaledecpoint();      buff[len++] = '0';  /* adds '.0' to result */    }#endif  }  setsvalue2s(L, obj, luaS_newlstr(L, buff, len));}// 创建一个字符串,让L->top指向该字符串// luaS_newlstr创建一个字符串,到lstring.c中再分析// 然后调用luaD_inctop,让栈顶指针自增1static void pushstr (lua_State *L, const char *str, size_t l) {  setsvalue2s(L, L->top, luaS_newlstr(L, str, l));  luaD_inctop(L);}/*** this function handles only '%d', '%c', '%f', '%p', and '%s'   conventional formats, plus Lua-specific '%I' and '%U'*/// luaO_pushfstring(L, "%s:%d: %s", buff, line, msg)// luaO_pushvfstring的作用是把luaO_pushfstring传进来的可变参数中的值,一个一个的加入lua栈中// 这个函数仅支持'%d', '%c', '%f', '%p', and '%s'转换格式,外加lua的'%I' and '%U'// strchr作用是找出fmt中首次出现'%'的位置,并返回其指针// 首先,e的位置就是%的位置,然后调用pushstr向栈中=顶压入一个字符串,并栈顶自增1// 下面就是不同格式的参数压入规则了// 如果是's'的话,代表以'\0'结尾的字符串,通过va_arg返回可变的参数,va_arg的第二个参数是你要返回的参数的类型// 如果是'c'的话,代表以int作为的字符,然后lisprint判断是否为可打印字符,是的话直接入栈,不然就(这个地方我还不知道)// 如果是'd'的话,就代表是一个int,直接入栈,然后把这个int转换成字符串// 如果是'I'的话,就代表lua里面的lua_Integer,也是直接入栈,然后把这个lua_Integer转换成字符串// 如果是'f'的话,就代表是一个lua_Number,执行流程和lua_Integer一样// 如果是'p'的话,就代表是一个指针,把argp中的void *类型的参数按照%p的格式转换进buff中,然后返回装入buff中的size,然后入栈// 如果是'U'的话,就代表一个UTF-8序列,计算出序列的字节数,然后入栈const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {  int n = 0;  for (;;) {    const char *e = strchr(fmt, '%');    if (e == NULL) break;    pushstr(L, fmt, e - fmt);    switch (*(e+1)) {      case 's': {  /* zero-terminated string */        const char *s = va_arg(argp, char *);        if (s == NULL) s = "(null)";        pushstr(L, s, strlen(s));        break;      }      case 'c': {  /* an 'int' as a character */        char buff = cast(char, va_arg(argp, int));        if (lisprint(cast_uchar(buff)))          pushstr(L, &buff, 1);        else  /* non-printable character; print its code */          luaO_pushfstring(L, "<\\%d>", cast_uchar(buff));        break;      }      case 'd': {  /* an 'int' */        setivalue(L->top, va_arg(argp, int));        goto top2str;      }      case 'I': {  /* a 'lua_Integer' */        setivalue(L->top, cast(lua_Integer, va_arg(argp, l_uacInt)));        goto top2str;      }      case 'f': {  /* a 'lua_Number' */        setfltvalue(L->top, cast_num(va_arg(argp, l_uacNumber)));      top2str:  /* convert the top element to a string */        luaD_inctop(L);        luaO_tostring(L, L->top - 1);        break;      }      case 'p': {  /* a pointer */        char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */        int l = l_sprintf(buff, sizeof(buff), "%p", va_arg(argp, void *));        pushstr(L, buff, l);        break;      }      case 'U': {  /* an 'int' as a UTF-8 sequence */        char buff[UTF8BUFFSZ];        int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long)));        pushstr(L, buff + UTF8BUFFSZ - l, l);        break;      }      case '%': {        pushstr(L, "%", 1);        break;      }      default: {        luaG_runerror(L, "invalid option '%%%c' to 'lua_pushfstring'",                         *(e + 1));      }    }    n += 2;    fmt = e+2;  }  luaD_checkstack(L, 1);  pushstr(L, fmt, strlen(fmt));  if (n > 0) luaV_concat(L, n + 1);  return svalue(L->top - 1);}// luaO_pushfstring的作用是把一个字符串按照固定格式压入L栈中,比如说:// luaO_pushfstring(L, "%s:%d: %s", buff, line, msg)   把一个调试信息格式的打印日志压入L栈中// va_list,va_start,va_end 这些宏定义在stdarg.h中// va_list定义了一个可变参数argp// va_start初始化了argp,第一个参数是argp,第二个参数是fmt(可变参数的前一个参数)const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) {  const char *msg;  va_list argp;  va_start(argp, fmt);  msg = luaO_pushvfstring(L, fmt, argp);  va_end(argp);  return msg;}/* number of chars of a literal string without the ending \0 */#define LL(x)(sizeof(x)/sizeof(char) - 1)#define RETS"..."#define PRE"[string \""#define POS"\"]"#define addstr(a,b,l)( memcpy(a,b,(l) * sizeof(char)), a += (l) )// 看完debug的相关调用后,再回来分析void luaO_chunkid (char *out, const char *source, size_t bufflen) {  size_t l = strlen(source);  if (*source == '=') {  /* 'literal' source */    if (l <= bufflen)  /* small enough? */      memcpy(out, source + 1, l * sizeof(char));    else {  /* truncate it */      addstr(out, source + 1, bufflen - 1);      *out = '\0';    }  }  else if (*source == '@') {  /* file name */    if (l <= bufflen)  /* small enough? */      memcpy(out, source + 1, l * sizeof(char));    else {  /* add '...' before rest of name */      addstr(out, RETS, LL(RETS));      bufflen -= LL(RETS);      memcpy(out, source + 1 + l - bufflen, bufflen * sizeof(char));    }  }  else {  /* string; format as [string "source"] */    const char *nl = strchr(source, '\n');  /* find first new line (if any) */    addstr(out, PRE, LL(PRE));  /* add prefix */    bufflen -= LL(PRE RETS POS) + 1;  /* save space for prefix+suffix+'\0' */    if (l < bufflen && nl == NULL) {  /* small one-line source? */      addstr(out, source, l);  /* keep it */    }    else {      if (nl != NULL) l = nl - source;  /* stop at first newline */      if (l > bufflen) l = bufflen;      addstr(out, source, l);      addstr(out, RETS, LL(RETS));    }    memcpy(out, POS, (LL(POS) + 1) * sizeof(char));  }}

阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 绝妙好辞 绝妙夸能赋 绝妙 绝妙的创业项目 十二不中绝妙公式 创新营销的绝妙点子 我的绝妙总裁老婆 地砖有油太滑解绝妙招 网游之绝学 网游绝学 继绝学 绝学无忧 金庸绝学 高才绝学 鬼谷子绝学 绝学 暴走大侠绝学先后顺序 暴走大侠绝学怎么学 暴走大侠绝学满级多少级 三种倒车绝学 玄元剑仙绝学 暴走大侠绝学满级 天龙之少林绝学大宗师 修真模拟器绝学 继往圣之绝学开万世之太平 金庸绝学异世横行txt下载 金庸绝学横行龙珠 玄元剑仙绝学门派 暴走大侠绝学学什么 暴走大侠门派绝学 玄元剑仙门派绝学 暴走大侠各门派绝学列表 修真模拟器门派绝学 绝密者 绝密押运 绝密飞行2 绝密跟踪 绝密配方 绝密1950 绝密战舰 绝密任务