lua/lauxlib.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 23 Jun 2017 17:28:03 -0400
changeset 58 1390348facc7
parent 0 d7ee4e2ed49d
permissions -rw-r--r--
Command line tool that decrypts an OPVault keychain and dumps it to stdout.

To compile: gcc -o opvault opvault.c cJSON.c -lcrypto

Usage: ./opvault </path/to/mykeychain.opvault> <password>

This is just a proof of concept; I'll be recycling this into proper OPVault
support in 1pass later and deleting this tool.

This uses OpenSSL's libcrypto for the math instead of all the homegrown
crypto this project is otherwise using. I'll probably migrate the rest in
this direction, too, since this wasn't as bad as I expected to use and
gets you all the package-manager mojo of automatic bug fixes and security
patches and shared code, etc.

cJSON parses JSON in C. That is from https://github.com/DaveGamble/cJSON

An example OPVault keychain from AgileBits is available here:

https://cache.agilebits.com/security-kb/
icculus@0
     1
/*
icculus@0
     2
** $Id: lauxlib.c,v 1.248.1.1 2013/04/12 18:48:47 roberto Exp $
icculus@0
     3
** Auxiliary functions for building Lua libraries
icculus@0
     4
** See Copyright Notice in lua.h
icculus@0
     5
*/
icculus@0
     6
icculus@0
     7
icculus@0
     8
#include <errno.h>
icculus@0
     9
#include <stdarg.h>
icculus@0
    10
#include <stdio.h>
icculus@0
    11
#include <stdlib.h>
icculus@0
    12
#include <string.h>
icculus@0
    13
icculus@0
    14
icculus@0
    15
/* This file uses only the official API of Lua.
icculus@0
    16
** Any function declared here could be written as an application function.
icculus@0
    17
*/
icculus@0
    18
icculus@0
    19
#define lauxlib_c
icculus@0
    20
#define LUA_LIB
icculus@0
    21
icculus@0
    22
#include "lua.h"
icculus@0
    23
icculus@0
    24
#include "lauxlib.h"
icculus@0
    25
icculus@0
    26
icculus@0
    27
/*
icculus@0
    28
** {======================================================
icculus@0
    29
** Traceback
icculus@0
    30
** =======================================================
icculus@0
    31
*/
icculus@0
    32
icculus@0
    33
icculus@0
    34
#define LEVELS1	12	/* size of the first part of the stack */
icculus@0
    35
#define LEVELS2	10	/* size of the second part of the stack */
icculus@0
    36
icculus@0
    37
icculus@0
    38
icculus@0
    39
/*
icculus@0
    40
** search for 'objidx' in table at index -1.
icculus@0
    41
** return 1 + string at top if find a good name.
icculus@0
    42
*/
icculus@0
    43
static int findfield (lua_State *L, int objidx, int level) {
icculus@0
    44
  if (level == 0 || !lua_istable(L, -1))
icculus@0
    45
    return 0;  /* not found */
icculus@0
    46
  lua_pushnil(L);  /* start 'next' loop */
icculus@0
    47
  while (lua_next(L, -2)) {  /* for each pair in table */
icculus@0
    48
    if (lua_type(L, -2) == LUA_TSTRING) {  /* ignore non-string keys */
icculus@0
    49
      if (lua_rawequal(L, objidx, -1)) {  /* found object? */
icculus@0
    50
        lua_pop(L, 1);  /* remove value (but keep name) */
icculus@0
    51
        return 1;
icculus@0
    52
      }
icculus@0
    53
      else if (findfield(L, objidx, level - 1)) {  /* try recursively */
icculus@0
    54
        lua_remove(L, -2);  /* remove table (but keep name) */
icculus@0
    55
        lua_pushliteral(L, ".");
icculus@0
    56
        lua_insert(L, -2);  /* place '.' between the two names */
icculus@0
    57
        lua_concat(L, 3);
icculus@0
    58
        return 1;
icculus@0
    59
      }
icculus@0
    60
    }
icculus@0
    61
    lua_pop(L, 1);  /* remove value */
icculus@0
    62
  }
icculus@0
    63
  return 0;  /* not found */
icculus@0
    64
}
icculus@0
    65
icculus@0
    66
icculus@0
    67
static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
icculus@0
    68
  int top = lua_gettop(L);
icculus@0
    69
  lua_getinfo(L, "f", ar);  /* push function */
icculus@0
    70
  lua_pushglobaltable(L);
icculus@0
    71
  if (findfield(L, top + 1, 2)) {
icculus@0
    72
    lua_copy(L, -1, top + 1);  /* move name to proper place */
icculus@0
    73
    lua_pop(L, 2);  /* remove pushed values */
icculus@0
    74
    return 1;
icculus@0
    75
  }
icculus@0
    76
  else {
icculus@0
    77
    lua_settop(L, top);  /* remove function and global table */
icculus@0
    78
    return 0;
icculus@0
    79
  }
icculus@0
    80
}
icculus@0
    81
icculus@0
    82
icculus@0
    83
static void pushfuncname (lua_State *L, lua_Debug *ar) {
icculus@0
    84
  if (*ar->namewhat != '\0')  /* is there a name? */
icculus@0
    85
    lua_pushfstring(L, "function " LUA_QS, ar->name);
icculus@0
    86
  else if (*ar->what == 'm')  /* main? */
icculus@0
    87
      lua_pushliteral(L, "main chunk");
icculus@0
    88
  else if (*ar->what == 'C') {
icculus@0
    89
    if (pushglobalfuncname(L, ar)) {
icculus@0
    90
      lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1));
icculus@0
    91
      lua_remove(L, -2);  /* remove name */
icculus@0
    92
    }
icculus@0
    93
    else
icculus@0
    94
      lua_pushliteral(L, "?");
icculus@0
    95
  }
icculus@0
    96
  else
icculus@0
    97
    lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined);
icculus@0
    98
}
icculus@0
    99
icculus@0
   100
icculus@0
   101
static int countlevels (lua_State *L) {
icculus@0
   102
  lua_Debug ar;
icculus@0
   103
  int li = 1, le = 1;
icculus@0
   104
  /* find an upper bound */
icculus@0
   105
  while (lua_getstack(L, le, &ar)) { li = le; le *= 2; }
icculus@0
   106
  /* do a binary search */
icculus@0
   107
  while (li < le) {
icculus@0
   108
    int m = (li + le)/2;
icculus@0
   109
    if (lua_getstack(L, m, &ar)) li = m + 1;
icculus@0
   110
    else le = m;
icculus@0
   111
  }
icculus@0
   112
  return le - 1;
icculus@0
   113
}
icculus@0
   114
icculus@0
   115
icculus@0
   116
LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1,
icculus@0
   117
                                const char *msg, int level) {
icculus@0
   118
  lua_Debug ar;
icculus@0
   119
  int top = lua_gettop(L);
icculus@0
   120
  int numlevels = countlevels(L1);
icculus@0
   121
  int mark = (numlevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0;
icculus@0
   122
  if (msg) lua_pushfstring(L, "%s\n", msg);
icculus@0
   123
  lua_pushliteral(L, "stack traceback:");
icculus@0
   124
  while (lua_getstack(L1, level++, &ar)) {
icculus@0
   125
    if (level == mark) {  /* too many levels? */
icculus@0
   126
      lua_pushliteral(L, "\n\t...");  /* add a '...' */
icculus@0
   127
      level = numlevels - LEVELS2;  /* and skip to last ones */
icculus@0
   128
    }
icculus@0
   129
    else {
icculus@0
   130
      lua_getinfo(L1, "Slnt", &ar);
icculus@0
   131
      lua_pushfstring(L, "\n\t%s:", ar.short_src);
icculus@0
   132
      if (ar.currentline > 0)
icculus@0
   133
        lua_pushfstring(L, "%d:", ar.currentline);
icculus@0
   134
      lua_pushliteral(L, " in ");
icculus@0
   135
      pushfuncname(L, &ar);
icculus@0
   136
      if (ar.istailcall)
icculus@0
   137
        lua_pushliteral(L, "\n\t(...tail calls...)");
icculus@0
   138
      lua_concat(L, lua_gettop(L) - top);
icculus@0
   139
    }
icculus@0
   140
  }
icculus@0
   141
  lua_concat(L, lua_gettop(L) - top);
icculus@0
   142
}
icculus@0
   143
icculus@0
   144
/* }====================================================== */
icculus@0
   145
icculus@0
   146
icculus@0
   147
/*
icculus@0
   148
** {======================================================
icculus@0
   149
** Error-report functions
icculus@0
   150
** =======================================================
icculus@0
   151
*/
icculus@0
   152
icculus@0
   153
LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) {
icculus@0
   154
  lua_Debug ar;
icculus@0
   155
  if (!lua_getstack(L, 0, &ar))  /* no stack frame? */
icculus@0
   156
    return luaL_error(L, "bad argument #%d (%s)", narg, extramsg);
icculus@0
   157
  lua_getinfo(L, "n", &ar);
icculus@0
   158
  if (strcmp(ar.namewhat, "method") == 0) {
icculus@0
   159
    narg--;  /* do not count `self' */
icculus@0
   160
    if (narg == 0)  /* error is in the self argument itself? */
icculus@0
   161
      return luaL_error(L, "calling " LUA_QS " on bad self (%s)",
icculus@0
   162
                           ar.name, extramsg);
icculus@0
   163
  }
icculus@0
   164
  if (ar.name == NULL)
icculus@0
   165
    ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?";
icculus@0
   166
  return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)",
icculus@0
   167
                        narg, ar.name, extramsg);
icculus@0
   168
}
icculus@0
   169
icculus@0
   170
icculus@0
   171
static int typeerror (lua_State *L, int narg, const char *tname) {
icculus@0
   172
  const char *msg = lua_pushfstring(L, "%s expected, got %s",
icculus@0
   173
                                    tname, luaL_typename(L, narg));
icculus@0
   174
  return luaL_argerror(L, narg, msg);
icculus@0
   175
}
icculus@0
   176
icculus@0
   177
icculus@0
   178
static void tag_error (lua_State *L, int narg, int tag) {
icculus@0
   179
  typeerror(L, narg, lua_typename(L, tag));
icculus@0
   180
}
icculus@0
   181
icculus@0
   182
icculus@0
   183
LUALIB_API void luaL_where (lua_State *L, int level) {
icculus@0
   184
  lua_Debug ar;
icculus@0
   185
  if (lua_getstack(L, level, &ar)) {  /* check function at level */
icculus@0
   186
    lua_getinfo(L, "Sl", &ar);  /* get info about it */
icculus@0
   187
    if (ar.currentline > 0) {  /* is there info? */
icculus@0
   188
      lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline);
icculus@0
   189
      return;
icculus@0
   190
    }
icculus@0
   191
  }
icculus@0
   192
  lua_pushliteral(L, "");  /* else, no information available... */
icculus@0
   193
}
icculus@0
   194
icculus@0
   195
icculus@0
   196
LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
icculus@0
   197
  va_list argp;
icculus@0
   198
  va_start(argp, fmt);
icculus@0
   199
  luaL_where(L, 1);
icculus@0
   200
  lua_pushvfstring(L, fmt, argp);
icculus@0
   201
  va_end(argp);
icculus@0
   202
  lua_concat(L, 2);
icculus@0
   203
  return lua_error(L);
icculus@0
   204
}
icculus@0
   205
icculus@0
   206
icculus@0
   207
LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {
icculus@0
   208
  int en = errno;  /* calls to Lua API may change this value */
icculus@0
   209
  if (stat) {
icculus@0
   210
    lua_pushboolean(L, 1);
icculus@0
   211
    return 1;
icculus@0
   212
  }
icculus@0
   213
  else {
icculus@0
   214
    lua_pushnil(L);
icculus@0
   215
    if (fname)
icculus@0
   216
      lua_pushfstring(L, "%s: %s", fname, strerror(en));
icculus@0
   217
    else
icculus@0
   218
      lua_pushstring(L, strerror(en));
icculus@0
   219
    lua_pushinteger(L, en);
icculus@0
   220
    return 3;
icculus@0
   221
  }
icculus@0
   222
}
icculus@0
   223
icculus@0
   224
icculus@0
   225
#if !defined(inspectstat)	/* { */
icculus@0
   226
icculus@0
   227
#if defined(LUA_USE_POSIX)
icculus@0
   228
icculus@0
   229
#include <sys/wait.h>
icculus@0
   230
icculus@0
   231
/*
icculus@0
   232
** use appropriate macros to interpret 'pclose' return status
icculus@0
   233
*/
icculus@0
   234
#define inspectstat(stat,what)  \
icculus@0
   235
   if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \
icculus@0
   236
   else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; }
icculus@0
   237
icculus@0
   238
#else
icculus@0
   239
icculus@0
   240
#define inspectstat(stat,what)  /* no op */
icculus@0
   241
icculus@0
   242
#endif
icculus@0
   243
icculus@0
   244
#endif				/* } */
icculus@0
   245
icculus@0
   246
icculus@0
   247
LUALIB_API int luaL_execresult (lua_State *L, int stat) {
icculus@0
   248
  const char *what = "exit";  /* type of termination */
icculus@0
   249
  if (stat == -1)  /* error? */
icculus@0
   250
    return luaL_fileresult(L, 0, NULL);
icculus@0
   251
  else {
icculus@0
   252
    inspectstat(stat, what);  /* interpret result */
icculus@0
   253
    if (*what == 'e' && stat == 0)  /* successful termination? */
icculus@0
   254
      lua_pushboolean(L, 1);
icculus@0
   255
    else
icculus@0
   256
      lua_pushnil(L);
icculus@0
   257
    lua_pushstring(L, what);
icculus@0
   258
    lua_pushinteger(L, stat);
icculus@0
   259
    return 3;  /* return true/nil,what,code */
icculus@0
   260
  }
icculus@0
   261
}
icculus@0
   262
icculus@0
   263
/* }====================================================== */
icculus@0
   264
icculus@0
   265
icculus@0
   266
/*
icculus@0
   267
** {======================================================
icculus@0
   268
** Userdata's metatable manipulation
icculus@0
   269
** =======================================================
icculus@0
   270
*/
icculus@0
   271
icculus@0
   272
LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) {
icculus@0
   273
  luaL_getmetatable(L, tname);  /* try to get metatable */
icculus@0
   274
  if (!lua_isnil(L, -1))  /* name already in use? */
icculus@0
   275
    return 0;  /* leave previous value on top, but return 0 */
icculus@0
   276
  lua_pop(L, 1);
icculus@0
   277
  lua_newtable(L);  /* create metatable */
icculus@0
   278
  lua_pushvalue(L, -1);
icculus@0
   279
  lua_setfield(L, LUA_REGISTRYINDEX, tname);  /* registry.name = metatable */
icculus@0
   280
  return 1;
icculus@0
   281
}
icculus@0
   282
icculus@0
   283
icculus@0
   284
LUALIB_API void luaL_setmetatable (lua_State *L, const char *tname) {
icculus@0
   285
  luaL_getmetatable(L, tname);
icculus@0
   286
  lua_setmetatable(L, -2);
icculus@0
   287
}
icculus@0
   288
icculus@0
   289
icculus@0
   290
LUALIB_API void *luaL_testudata (lua_State *L, int ud, const char *tname) {
icculus@0
   291
  void *p = lua_touserdata(L, ud);
icculus@0
   292
  if (p != NULL) {  /* value is a userdata? */
icculus@0
   293
    if (lua_getmetatable(L, ud)) {  /* does it have a metatable? */
icculus@0
   294
      luaL_getmetatable(L, tname);  /* get correct metatable */
icculus@0
   295
      if (!lua_rawequal(L, -1, -2))  /* not the same? */
icculus@0
   296
        p = NULL;  /* value is a userdata with wrong metatable */
icculus@0
   297
      lua_pop(L, 2);  /* remove both metatables */
icculus@0
   298
      return p;
icculus@0
   299
    }
icculus@0
   300
  }
icculus@0
   301
  return NULL;  /* value is not a userdata with a metatable */
icculus@0
   302
}
icculus@0
   303
icculus@0
   304
icculus@0
   305
LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) {
icculus@0
   306
  void *p = luaL_testudata(L, ud, tname);
icculus@0
   307
  if (p == NULL) typeerror(L, ud, tname);
icculus@0
   308
  return p;
icculus@0
   309
}
icculus@0
   310
icculus@0
   311
/* }====================================================== */
icculus@0
   312
icculus@0
   313
icculus@0
   314
/*
icculus@0
   315
** {======================================================
icculus@0
   316
** Argument check functions
icculus@0
   317
** =======================================================
icculus@0
   318
*/
icculus@0
   319
icculus@0
   320
LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def,
icculus@0
   321
                                 const char *const lst[]) {
icculus@0
   322
  const char *name = (def) ? luaL_optstring(L, narg, def) :
icculus@0
   323
                             luaL_checkstring(L, narg);
icculus@0
   324
  int i;
icculus@0
   325
  for (i=0; lst[i]; i++)
icculus@0
   326
    if (strcmp(lst[i], name) == 0)
icculus@0
   327
      return i;
icculus@0
   328
  return luaL_argerror(L, narg,
icculus@0
   329
                       lua_pushfstring(L, "invalid option " LUA_QS, name));
icculus@0
   330
}
icculus@0
   331
icculus@0
   332
icculus@0
   333
LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
icculus@0
   334
  /* keep some extra space to run error routines, if needed */
icculus@0
   335
  const int extra = LUA_MINSTACK;
icculus@0
   336
  if (!lua_checkstack(L, space + extra)) {
icculus@0
   337
    if (msg)
icculus@0
   338
      luaL_error(L, "stack overflow (%s)", msg);
icculus@0
   339
    else
icculus@0
   340
      luaL_error(L, "stack overflow");
icculus@0
   341
  }
icculus@0
   342
}
icculus@0
   343
icculus@0
   344
icculus@0
   345
LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) {
icculus@0
   346
  if (lua_type(L, narg) != t)
icculus@0
   347
    tag_error(L, narg, t);
icculus@0
   348
}
icculus@0
   349
icculus@0
   350
icculus@0
   351
LUALIB_API void luaL_checkany (lua_State *L, int narg) {
icculus@0
   352
  if (lua_type(L, narg) == LUA_TNONE)
icculus@0
   353
    luaL_argerror(L, narg, "value expected");
icculus@0
   354
}
icculus@0
   355
icculus@0
   356
icculus@0
   357
LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) {
icculus@0
   358
  const char *s = lua_tolstring(L, narg, len);
icculus@0
   359
  if (!s) tag_error(L, narg, LUA_TSTRING);
icculus@0
   360
  return s;
icculus@0
   361
}
icculus@0
   362
icculus@0
   363
icculus@0
   364
LUALIB_API const char *luaL_optlstring (lua_State *L, int narg,
icculus@0
   365
                                        const char *def, size_t *len) {
icculus@0
   366
  if (lua_isnoneornil(L, narg)) {
icculus@0
   367
    if (len)
icculus@0
   368
      *len = (def ? strlen(def) : 0);
icculus@0
   369
    return def;
icculus@0
   370
  }
icculus@0
   371
  else return luaL_checklstring(L, narg, len);
icculus@0
   372
}
icculus@0
   373
icculus@0
   374
icculus@0
   375
LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) {
icculus@0
   376
  int isnum;
icculus@0
   377
  lua_Number d = lua_tonumberx(L, narg, &isnum);
icculus@0
   378
  if (!isnum)
icculus@0
   379
    tag_error(L, narg, LUA_TNUMBER);
icculus@0
   380
  return d;
icculus@0
   381
}
icculus@0
   382
icculus@0
   383
icculus@0
   384
LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) {
icculus@0
   385
  return luaL_opt(L, luaL_checknumber, narg, def);
icculus@0
   386
}
icculus@0
   387
icculus@0
   388
icculus@0
   389
LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) {
icculus@0
   390
  int isnum;
icculus@0
   391
  lua_Integer d = lua_tointegerx(L, narg, &isnum);
icculus@0
   392
  if (!isnum)
icculus@0
   393
    tag_error(L, narg, LUA_TNUMBER);
icculus@0
   394
  return d;
icculus@0
   395
}
icculus@0
   396
icculus@0
   397
icculus@0
   398
LUALIB_API lua_Unsigned luaL_checkunsigned (lua_State *L, int narg) {
icculus@0
   399
  int isnum;
icculus@0
   400
  lua_Unsigned d = lua_tounsignedx(L, narg, &isnum);
icculus@0
   401
  if (!isnum)
icculus@0
   402
    tag_error(L, narg, LUA_TNUMBER);
icculus@0
   403
  return d;
icculus@0
   404
}
icculus@0
   405
icculus@0
   406
icculus@0
   407
LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg,
icculus@0
   408
                                                      lua_Integer def) {
icculus@0
   409
  return luaL_opt(L, luaL_checkinteger, narg, def);
icculus@0
   410
}
icculus@0
   411
icculus@0
   412
icculus@0
   413
LUALIB_API lua_Unsigned luaL_optunsigned (lua_State *L, int narg,
icculus@0
   414
                                                        lua_Unsigned def) {
icculus@0
   415
  return luaL_opt(L, luaL_checkunsigned, narg, def);
icculus@0
   416
}
icculus@0
   417
icculus@0
   418
/* }====================================================== */
icculus@0
   419
icculus@0
   420
icculus@0
   421
/*
icculus@0
   422
** {======================================================
icculus@0
   423
** Generic Buffer manipulation
icculus@0
   424
** =======================================================
icculus@0
   425
*/
icculus@0
   426
icculus@0
   427
/*
icculus@0
   428
** check whether buffer is using a userdata on the stack as a temporary
icculus@0
   429
** buffer
icculus@0
   430
*/
icculus@0
   431
#define buffonstack(B)	((B)->b != (B)->initb)
icculus@0
   432
icculus@0
   433
icculus@0
   434
/*
icculus@0
   435
** returns a pointer to a free area with at least 'sz' bytes
icculus@0
   436
*/
icculus@0
   437
LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
icculus@0
   438
  lua_State *L = B->L;
icculus@0
   439
  if (B->size - B->n < sz) {  /* not enough space? */
icculus@0
   440
    char *newbuff;
icculus@0
   441
    size_t newsize = B->size * 2;  /* double buffer size */
icculus@0
   442
    if (newsize - B->n < sz)  /* not big enough? */
icculus@0
   443
      newsize = B->n + sz;
icculus@0
   444
    if (newsize < B->n || newsize - B->n < sz)
icculus@0
   445
      luaL_error(L, "buffer too large");
icculus@0
   446
    /* create larger buffer */
icculus@0
   447
    newbuff = (char *)lua_newuserdata(L, newsize * sizeof(char));
icculus@0
   448
    /* move content to new buffer */
icculus@0
   449
    memcpy(newbuff, B->b, B->n * sizeof(char));
icculus@0
   450
    if (buffonstack(B))
icculus@0
   451
      lua_remove(L, -2);  /* remove old buffer */
icculus@0
   452
    B->b = newbuff;
icculus@0
   453
    B->size = newsize;
icculus@0
   454
  }
icculus@0
   455
  return &B->b[B->n];
icculus@0
   456
}
icculus@0
   457
icculus@0
   458
icculus@0
   459
LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) {
icculus@0
   460
  char *b = luaL_prepbuffsize(B, l);
icculus@0
   461
  memcpy(b, s, l * sizeof(char));
icculus@0
   462
  luaL_addsize(B, l);
icculus@0
   463
}
icculus@0
   464
icculus@0
   465
icculus@0
   466
LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
icculus@0
   467
  luaL_addlstring(B, s, strlen(s));
icculus@0
   468
}
icculus@0
   469
icculus@0
   470
icculus@0
   471
LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
icculus@0
   472
  lua_State *L = B->L;
icculus@0
   473
  lua_pushlstring(L, B->b, B->n);
icculus@0
   474
  if (buffonstack(B))
icculus@0
   475
    lua_remove(L, -2);  /* remove old buffer */
icculus@0
   476
}
icculus@0
   477
icculus@0
   478
icculus@0
   479
LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) {
icculus@0
   480
  luaL_addsize(B, sz);
icculus@0
   481
  luaL_pushresult(B);
icculus@0
   482
}
icculus@0
   483
icculus@0
   484
icculus@0
   485
LUALIB_API void luaL_addvalue (luaL_Buffer *B) {
icculus@0
   486
  lua_State *L = B->L;
icculus@0
   487
  size_t l;
icculus@0
   488
  const char *s = lua_tolstring(L, -1, &l);
icculus@0
   489
  if (buffonstack(B))
icculus@0
   490
    lua_insert(L, -2);  /* put value below buffer */
icculus@0
   491
  luaL_addlstring(B, s, l);
icculus@0
   492
  lua_remove(L, (buffonstack(B)) ? -2 : -1);  /* remove value */
icculus@0
   493
}
icculus@0
   494
icculus@0
   495
icculus@0
   496
LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) {
icculus@0
   497
  B->L = L;
icculus@0
   498
  B->b = B->initb;
icculus@0
   499
  B->n = 0;
icculus@0
   500
  B->size = LUAL_BUFFERSIZE;
icculus@0
   501
}
icculus@0
   502
icculus@0
   503
icculus@0
   504
LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) {
icculus@0
   505
  luaL_buffinit(L, B);
icculus@0
   506
  return luaL_prepbuffsize(B, sz);
icculus@0
   507
}
icculus@0
   508
icculus@0
   509
/* }====================================================== */
icculus@0
   510
icculus@0
   511
icculus@0
   512
/*
icculus@0
   513
** {======================================================
icculus@0
   514
** Reference system
icculus@0
   515
** =======================================================
icculus@0
   516
*/
icculus@0
   517
icculus@0
   518
/* index of free-list header */
icculus@0
   519
#define freelist	0
icculus@0
   520
icculus@0
   521
icculus@0
   522
LUALIB_API int luaL_ref (lua_State *L, int t) {
icculus@0
   523
  int ref;
icculus@0
   524
  if (lua_isnil(L, -1)) {
icculus@0
   525
    lua_pop(L, 1);  /* remove from stack */
icculus@0
   526
    return LUA_REFNIL;  /* `nil' has a unique fixed reference */
icculus@0
   527
  }
icculus@0
   528
  t = lua_absindex(L, t);
icculus@0
   529
  lua_rawgeti(L, t, freelist);  /* get first free element */
icculus@0
   530
  ref = (int)lua_tointeger(L, -1);  /* ref = t[freelist] */
icculus@0
   531
  lua_pop(L, 1);  /* remove it from stack */
icculus@0
   532
  if (ref != 0) {  /* any free element? */
icculus@0
   533
    lua_rawgeti(L, t, ref);  /* remove it from list */
icculus@0
   534
    lua_rawseti(L, t, freelist);  /* (t[freelist] = t[ref]) */
icculus@0
   535
  }
icculus@0
   536
  else  /* no free elements */
icculus@0
   537
    ref = (int)lua_rawlen(L, t) + 1;  /* get a new reference */
icculus@0
   538
  lua_rawseti(L, t, ref);
icculus@0
   539
  return ref;
icculus@0
   540
}
icculus@0
   541
icculus@0
   542
icculus@0
   543
LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
icculus@0
   544
  if (ref >= 0) {
icculus@0
   545
    t = lua_absindex(L, t);
icculus@0
   546
    lua_rawgeti(L, t, freelist);
icculus@0
   547
    lua_rawseti(L, t, ref);  /* t[ref] = t[freelist] */
icculus@0
   548
    lua_pushinteger(L, ref);
icculus@0
   549
    lua_rawseti(L, t, freelist);  /* t[freelist] = ref */
icculus@0
   550
  }
icculus@0
   551
}
icculus@0
   552
icculus@0
   553
/* }====================================================== */
icculus@0
   554
icculus@0
   555
icculus@0
   556
/*
icculus@0
   557
** {======================================================
icculus@0
   558
** Load functions
icculus@0
   559
** =======================================================
icculus@0
   560
*/
icculus@0
   561
icculus@0
   562
typedef struct LoadF {
icculus@0
   563
  int n;  /* number of pre-read characters */
icculus@0
   564
  FILE *f;  /* file being read */
icculus@0
   565
  char buff[LUAL_BUFFERSIZE];  /* area for reading file */
icculus@0
   566
} LoadF;
icculus@0
   567
icculus@0
   568
icculus@0
   569
static const char *getF (lua_State *L, void *ud, size_t *size) {
icculus@0
   570
  LoadF *lf = (LoadF *)ud;
icculus@0
   571
  (void)L;  /* not used */
icculus@0
   572
  if (lf->n > 0) {  /* are there pre-read characters to be read? */
icculus@0
   573
    *size = lf->n;  /* return them (chars already in buffer) */
icculus@0
   574
    lf->n = 0;  /* no more pre-read characters */
icculus@0
   575
  }
icculus@0
   576
  else {  /* read a block from file */
icculus@0
   577
    /* 'fread' can return > 0 *and* set the EOF flag. If next call to
icculus@0
   578
       'getF' called 'fread', it might still wait for user input.
icculus@0
   579
       The next check avoids this problem. */
icculus@0
   580
    if (feof(lf->f)) return NULL;
icculus@0
   581
    *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f);  /* read block */
icculus@0
   582
  }
icculus@0
   583
  return lf->buff;
icculus@0
   584
}
icculus@0
   585
icculus@0
   586
icculus@0
   587
static int errfile (lua_State *L, const char *what, int fnameindex) {
icculus@0
   588
  const char *serr = strerror(errno);
icculus@0
   589
  const char *filename = lua_tostring(L, fnameindex) + 1;
icculus@0
   590
  lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr);
icculus@0
   591
  lua_remove(L, fnameindex);
icculus@0
   592
  return LUA_ERRFILE;
icculus@0
   593
}
icculus@0
   594
icculus@0
   595
icculus@0
   596
static int skipBOM (LoadF *lf) {
icculus@0
   597
  const char *p = "\xEF\xBB\xBF";  /* Utf8 BOM mark */
icculus@0
   598
  int c;
icculus@0
   599
  lf->n = 0;
icculus@0
   600
  do {
icculus@0
   601
    c = getc(lf->f);
icculus@0
   602
    if (c == EOF || c != *(const unsigned char *)p++) return c;
icculus@0
   603
    lf->buff[lf->n++] = c;  /* to be read by the parser */
icculus@0
   604
  } while (*p != '\0');
icculus@0
   605
  lf->n = 0;  /* prefix matched; discard it */
icculus@0
   606
  return getc(lf->f);  /* return next character */
icculus@0
   607
}
icculus@0
   608
icculus@0
   609
icculus@0
   610
/*
icculus@0
   611
** reads the first character of file 'f' and skips an optional BOM mark
icculus@0
   612
** in its beginning plus its first line if it starts with '#'. Returns
icculus@0
   613
** true if it skipped the first line.  In any case, '*cp' has the
icculus@0
   614
** first "valid" character of the file (after the optional BOM and
icculus@0
   615
** a first-line comment).
icculus@0
   616
*/
icculus@0
   617
static int skipcomment (LoadF *lf, int *cp) {
icculus@0
   618
  int c = *cp = skipBOM(lf);
icculus@0
   619
  if (c == '#') {  /* first line is a comment (Unix exec. file)? */
icculus@0
   620
    do {  /* skip first line */
icculus@0
   621
      c = getc(lf->f);
icculus@0
   622
    } while (c != EOF && c != '\n') ;
icculus@0
   623
    *cp = getc(lf->f);  /* skip end-of-line, if present */
icculus@0
   624
    return 1;  /* there was a comment */
icculus@0
   625
  }
icculus@0
   626
  else return 0;  /* no comment */
icculus@0
   627
}
icculus@0
   628
icculus@0
   629
icculus@0
   630
LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
icculus@0
   631
                                             const char *mode) {
icculus@0
   632
  LoadF lf;
icculus@0
   633
  int status, readstatus;
icculus@0
   634
  int c;
icculus@0
   635
  int fnameindex = lua_gettop(L) + 1;  /* index of filename on the stack */
icculus@0
   636
  if (filename == NULL) {
icculus@0
   637
    lua_pushliteral(L, "=stdin");
icculus@0
   638
    lf.f = stdin;
icculus@0
   639
  }
icculus@0
   640
  else {
icculus@0
   641
    lua_pushfstring(L, "@%s", filename);
icculus@0
   642
    lf.f = fopen(filename, "r");
icculus@0
   643
    if (lf.f == NULL) return errfile(L, "open", fnameindex);
icculus@0
   644
  }
icculus@0
   645
  if (skipcomment(&lf, &c))  /* read initial portion */
icculus@0
   646
    lf.buff[lf.n++] = '\n';  /* add line to correct line numbers */
icculus@0
   647
  if (c == LUA_SIGNATURE[0] && filename) {  /* binary file? */
icculus@0
   648
    lf.f = freopen(filename, "rb", lf.f);  /* reopen in binary mode */
icculus@0
   649
    if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
icculus@0
   650
    skipcomment(&lf, &c);  /* re-read initial portion */
icculus@0
   651
  }
icculus@0
   652
  if (c != EOF)
icculus@0
   653
    lf.buff[lf.n++] = c;  /* 'c' is the first character of the stream */
icculus@0
   654
  status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode);
icculus@0
   655
  readstatus = ferror(lf.f);
icculus@0
   656
  if (filename) fclose(lf.f);  /* close file (even in case of errors) */
icculus@0
   657
  if (readstatus) {
icculus@0
   658
    lua_settop(L, fnameindex);  /* ignore results from `lua_load' */
icculus@0
   659
    return errfile(L, "read", fnameindex);
icculus@0
   660
  }
icculus@0
   661
  lua_remove(L, fnameindex);
icculus@0
   662
  return status;
icculus@0
   663
}
icculus@0
   664
icculus@0
   665
icculus@0
   666
typedef struct LoadS {
icculus@0
   667
  const char *s;
icculus@0
   668
  size_t size;
icculus@0
   669
} LoadS;
icculus@0
   670
icculus@0
   671
icculus@0
   672
static const char *getS (lua_State *L, void *ud, size_t *size) {
icculus@0
   673
  LoadS *ls = (LoadS *)ud;
icculus@0
   674
  (void)L;  /* not used */
icculus@0
   675
  if (ls->size == 0) return NULL;
icculus@0
   676
  *size = ls->size;
icculus@0
   677
  ls->size = 0;
icculus@0
   678
  return ls->s;
icculus@0
   679
}
icculus@0
   680
icculus@0
   681
icculus@0
   682
LUALIB_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t size,
icculus@0
   683
                                 const char *name, const char *mode) {
icculus@0
   684
  LoadS ls;
icculus@0
   685
  ls.s = buff;
icculus@0
   686
  ls.size = size;
icculus@0
   687
  return lua_load(L, getS, &ls, name, mode);
icculus@0
   688
}
icculus@0
   689
icculus@0
   690
icculus@0
   691
LUALIB_API int luaL_loadstring (lua_State *L, const char *s) {
icculus@0
   692
  return luaL_loadbuffer(L, s, strlen(s), s);
icculus@0
   693
}
icculus@0
   694
icculus@0
   695
/* }====================================================== */
icculus@0
   696
icculus@0
   697
icculus@0
   698
icculus@0
   699
LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) {
icculus@0
   700
  if (!lua_getmetatable(L, obj))  /* no metatable? */
icculus@0
   701
    return 0;
icculus@0
   702
  lua_pushstring(L, event);
icculus@0
   703
  lua_rawget(L, -2);
icculus@0
   704
  if (lua_isnil(L, -1)) {
icculus@0
   705
    lua_pop(L, 2);  /* remove metatable and metafield */
icculus@0
   706
    return 0;
icculus@0
   707
  }
icculus@0
   708
  else {
icculus@0
   709
    lua_remove(L, -2);  /* remove only metatable */
icculus@0
   710
    return 1;
icculus@0
   711
  }
icculus@0
   712
}
icculus@0
   713
icculus@0
   714
icculus@0
   715
LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) {
icculus@0
   716
  obj = lua_absindex(L, obj);
icculus@0
   717
  if (!luaL_getmetafield(L, obj, event))  /* no metafield? */
icculus@0
   718
    return 0;
icculus@0
   719
  lua_pushvalue(L, obj);
icculus@0
   720
  lua_call(L, 1, 1);
icculus@0
   721
  return 1;
icculus@0
   722
}
icculus@0
   723
icculus@0
   724
icculus@0
   725
LUALIB_API int luaL_len (lua_State *L, int idx) {
icculus@0
   726
  int l;
icculus@0
   727
  int isnum;
icculus@0
   728
  lua_len(L, idx);
icculus@0
   729
  l = (int)lua_tointegerx(L, -1, &isnum);
icculus@0
   730
  if (!isnum)
icculus@0
   731
    luaL_error(L, "object length is not a number");
icculus@0
   732
  lua_pop(L, 1);  /* remove object */
icculus@0
   733
  return l;
icculus@0
   734
}
icculus@0
   735
icculus@0
   736
icculus@0
   737
LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
icculus@0
   738
  if (!luaL_callmeta(L, idx, "__tostring")) {  /* no metafield? */
icculus@0
   739
    switch (lua_type(L, idx)) {
icculus@0
   740
      case LUA_TNUMBER:
icculus@0
   741
      case LUA_TSTRING:
icculus@0
   742
        lua_pushvalue(L, idx);
icculus@0
   743
        break;
icculus@0
   744
      case LUA_TBOOLEAN:
icculus@0
   745
        lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false"));
icculus@0
   746
        break;
icculus@0
   747
      case LUA_TNIL:
icculus@0
   748
        lua_pushliteral(L, "nil");
icculus@0
   749
        break;
icculus@0
   750
      default:
icculus@0
   751
        lua_pushfstring(L, "%s: %p", luaL_typename(L, idx),
icculus@0
   752
                                            lua_topointer(L, idx));
icculus@0
   753
        break;
icculus@0
   754
    }
icculus@0
   755
  }
icculus@0
   756
  return lua_tolstring(L, -1, len);
icculus@0
   757
}
icculus@0
   758
icculus@0
   759
icculus@0
   760
/*
icculus@0
   761
** {======================================================
icculus@0
   762
** Compatibility with 5.1 module functions
icculus@0
   763
** =======================================================
icculus@0
   764
*/
icculus@0
   765
#if defined(LUA_COMPAT_MODULE)
icculus@0
   766
icculus@0
   767
static const char *luaL_findtable (lua_State *L, int idx,
icculus@0
   768
                                   const char *fname, int szhint) {
icculus@0
   769
  const char *e;
icculus@0
   770
  if (idx) lua_pushvalue(L, idx);
icculus@0
   771
  do {
icculus@0
   772
    e = strchr(fname, '.');
icculus@0
   773
    if (e == NULL) e = fname + strlen(fname);
icculus@0
   774
    lua_pushlstring(L, fname, e - fname);
icculus@0
   775
    lua_rawget(L, -2);
icculus@0
   776
    if (lua_isnil(L, -1)) {  /* no such field? */
icculus@0
   777
      lua_pop(L, 1);  /* remove this nil */
icculus@0
   778
      lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */
icculus@0
   779
      lua_pushlstring(L, fname, e - fname);
icculus@0
   780
      lua_pushvalue(L, -2);
icculus@0
   781
      lua_settable(L, -4);  /* set new table into field */
icculus@0
   782
    }
icculus@0
   783
    else if (!lua_istable(L, -1)) {  /* field has a non-table value? */
icculus@0
   784
      lua_pop(L, 2);  /* remove table and value */
icculus@0
   785
      return fname;  /* return problematic part of the name */
icculus@0
   786
    }
icculus@0
   787
    lua_remove(L, -2);  /* remove previous table */
icculus@0
   788
    fname = e + 1;
icculus@0
   789
  } while (*e == '.');
icculus@0
   790
  return NULL;
icculus@0
   791
}
icculus@0
   792
icculus@0
   793
icculus@0
   794
/*
icculus@0
   795
** Count number of elements in a luaL_Reg list.
icculus@0
   796
*/
icculus@0
   797
static int libsize (const luaL_Reg *l) {
icculus@0
   798
  int size = 0;
icculus@0
   799
  for (; l && l->name; l++) size++;
icculus@0
   800
  return size;
icculus@0
   801
}
icculus@0
   802
icculus@0
   803
icculus@0
   804
/*
icculus@0
   805
** Find or create a module table with a given name. The function
icculus@0
   806
** first looks at the _LOADED table and, if that fails, try a
icculus@0
   807
** global variable with that name. In any case, leaves on the stack
icculus@0
   808
** the module table.
icculus@0
   809
*/
icculus@0
   810
LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname,
icculus@0
   811
                                 int sizehint) {
icculus@0
   812
  luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1);  /* get _LOADED table */
icculus@0
   813
  lua_getfield(L, -1, modname);  /* get _LOADED[modname] */
icculus@0
   814
  if (!lua_istable(L, -1)) {  /* not found? */
icculus@0
   815
    lua_pop(L, 1);  /* remove previous result */
icculus@0
   816
    /* try global variable (and create one if it does not exist) */
icculus@0
   817
    lua_pushglobaltable(L);
icculus@0
   818
    if (luaL_findtable(L, 0, modname, sizehint) != NULL)
icculus@0
   819
      luaL_error(L, "name conflict for module " LUA_QS, modname);
icculus@0
   820
    lua_pushvalue(L, -1);
icculus@0
   821
    lua_setfield(L, -3, modname);  /* _LOADED[modname] = new table */
icculus@0
   822
  }
icculus@0
   823
  lua_remove(L, -2);  /* remove _LOADED table */
icculus@0
   824
}
icculus@0
   825
icculus@0
   826
icculus@0
   827
LUALIB_API void luaL_openlib (lua_State *L, const char *libname,
icculus@0
   828
                               const luaL_Reg *l, int nup) {
icculus@0
   829
  luaL_checkversion(L);
icculus@0
   830
  if (libname) {
icculus@0
   831
    luaL_pushmodule(L, libname, libsize(l));  /* get/create library table */
icculus@0
   832
    lua_insert(L, -(nup + 1));  /* move library table to below upvalues */
icculus@0
   833
  }
icculus@0
   834
  if (l)
icculus@0
   835
    luaL_setfuncs(L, l, nup);
icculus@0
   836
  else
icculus@0
   837
    lua_pop(L, nup);  /* remove upvalues */
icculus@0
   838
}
icculus@0
   839
icculus@0
   840
#endif
icculus@0
   841
/* }====================================================== */
icculus@0
   842
icculus@0
   843
/*
icculus@0
   844
** set functions from list 'l' into table at top - 'nup'; each
icculus@0
   845
** function gets the 'nup' elements at the top as upvalues.
icculus@0
   846
** Returns with only the table at the stack.
icculus@0
   847
*/
icculus@0
   848
LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
icculus@0
   849
  luaL_checkversion(L);
icculus@0
   850
  luaL_checkstack(L, nup, "too many upvalues");
icculus@0
   851
  for (; l->name != NULL; l++) {  /* fill the table with given functions */
icculus@0
   852
    int i;
icculus@0
   853
    for (i = 0; i < nup; i++)  /* copy upvalues to the top */
icculus@0
   854
      lua_pushvalue(L, -nup);
icculus@0
   855
    lua_pushcclosure(L, l->func, nup);  /* closure with those upvalues */
icculus@0
   856
    lua_setfield(L, -(nup + 2), l->name);
icculus@0
   857
  }
icculus@0
   858
  lua_pop(L, nup);  /* remove upvalues */
icculus@0
   859
}
icculus@0
   860
icculus@0
   861
icculus@0
   862
/*
icculus@0
   863
** ensure that stack[idx][fname] has a table and push that table
icculus@0
   864
** into the stack
icculus@0
   865
*/
icculus@0
   866
LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) {
icculus@0
   867
  lua_getfield(L, idx, fname);
icculus@0
   868
  if (lua_istable(L, -1)) return 1;  /* table already there */
icculus@0
   869
  else {
icculus@0
   870
    lua_pop(L, 1);  /* remove previous result */
icculus@0
   871
    idx = lua_absindex(L, idx);
icculus@0
   872
    lua_newtable(L);
icculus@0
   873
    lua_pushvalue(L, -1);  /* copy to be left at top */
icculus@0
   874
    lua_setfield(L, idx, fname);  /* assign new table to field */
icculus@0
   875
    return 0;  /* false, because did not find table there */
icculus@0
   876
  }
icculus@0
   877
}
icculus@0
   878
icculus@0
   879
icculus@0
   880
/*
icculus@0
   881
** stripped-down 'require'. Calls 'openf' to open a module,
icculus@0
   882
** registers the result in 'package.loaded' table and, if 'glb'
icculus@0
   883
** is true, also registers the result in the global table.
icculus@0
   884
** Leaves resulting module on the top.
icculus@0
   885
*/
icculus@0
   886
LUALIB_API void luaL_requiref (lua_State *L, const char *modname,
icculus@0
   887
                               lua_CFunction openf, int glb) {
icculus@0
   888
  lua_pushcfunction(L, openf);
icculus@0
   889
  lua_pushstring(L, modname);  /* argument to open function */
icculus@0
   890
  lua_call(L, 1, 1);  /* open module */
icculus@0
   891
  luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED");
icculus@0
   892
  lua_pushvalue(L, -2);  /* make copy of module (call result) */
icculus@0
   893
  lua_setfield(L, -2, modname);  /* _LOADED[modname] = module */
icculus@0
   894
  lua_pop(L, 1);  /* remove _LOADED table */
icculus@0
   895
  if (glb) {
icculus@0
   896
    lua_pushvalue(L, -1);  /* copy of 'mod' */
icculus@0
   897
    lua_setglobal(L, modname);  /* _G[modname] = module */
icculus@0
   898
  }
icculus@0
   899
}
icculus@0
   900
icculus@0
   901
icculus@0
   902
LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p,
icculus@0
   903
                                                               const char *r) {
icculus@0
   904
  const char *wild;
icculus@0
   905
  size_t l = strlen(p);
icculus@0
   906
  luaL_Buffer b;
icculus@0
   907
  luaL_buffinit(L, &b);
icculus@0
   908
  while ((wild = strstr(s, p)) != NULL) {
icculus@0
   909
    luaL_addlstring(&b, s, wild - s);  /* push prefix */
icculus@0
   910
    luaL_addstring(&b, r);  /* push replacement in place of pattern */
icculus@0
   911
    s = wild + l;  /* continue after `p' */
icculus@0
   912
  }
icculus@0
   913
  luaL_addstring(&b, s);  /* push last suffix */
icculus@0
   914
  luaL_pushresult(&b);
icculus@0
   915
  return lua_tostring(L, -1);
icculus@0
   916
}
icculus@0
   917
icculus@0
   918
icculus@0
   919
static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
icculus@0
   920
  (void)ud; (void)osize;  /* not used */
icculus@0
   921
  if (nsize == 0) {
icculus@0
   922
    free(ptr);
icculus@0
   923
    return NULL;
icculus@0
   924
  }
icculus@0
   925
  else
icculus@0
   926
    return realloc(ptr, nsize);
icculus@0
   927
}
icculus@0
   928
icculus@0
   929
icculus@0
   930
static int panic (lua_State *L) {
icculus@0
   931
  luai_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n",
icculus@0
   932
                   lua_tostring(L, -1));
icculus@0
   933
  return 0;  /* return to Lua to abort */
icculus@0
   934
}
icculus@0
   935
icculus@0
   936
icculus@0
   937
LUALIB_API lua_State *luaL_newstate (void) {
icculus@0
   938
  lua_State *L = lua_newstate(l_alloc, NULL);
icculus@0
   939
  if (L) lua_atpanic(L, &panic);
icculus@0
   940
  return L;
icculus@0
   941
}
icculus@0
   942
icculus@0
   943
icculus@0
   944
LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver) {
icculus@0
   945
  const lua_Number *v = lua_version(L);
icculus@0
   946
  if (v != lua_version(NULL))
icculus@0
   947
    luaL_error(L, "multiple Lua VMs detected");
icculus@0
   948
  else if (*v != ver)
icculus@0
   949
    luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f",
icculus@0
   950
                  ver, *v);
icculus@0
   951
  /* check conversions number -> integer types */
icculus@0
   952
  lua_pushnumber(L, -(lua_Number)0x1234);
icculus@0
   953
  if (lua_tointeger(L, -1) != -0x1234 ||
icculus@0
   954
      lua_tounsigned(L, -1) != (lua_Unsigned)-0x1234)
icculus@0
   955
    luaL_error(L, "bad conversion number->int;"
icculus@0
   956
                  " must recompile Lua with proper settings");
icculus@0
   957
  lua_pop(L, 1);
icculus@0
   958
}
icculus@0
   959