src/lxplib.c

1
/*
2
** $Id: lxplib.c,v 1.16 2007/06/05 20:03:12 carregal Exp $
3
** LuaExpat: Lua bind for Expat library
4
** See Copyright Notice in license.html
5
*/
6
 
7
 
8
#include <assert.h>
9
#include <stdlib.h>
10
#include <string.h>
11
 
12
#include "expat.h"
13
 
14
#include "lua.h"
15
#include "lauxlib.h"
16
 
17
 
18
#include "lxplib.h"
19
 
20
#if (LUA_VERSION_NUM == 501)
21
#define lua_getuservalue(L, i) lua_getfenv(L, i)
22
#define lua_setuservalue(L, i) lua_setfenv(L, i)
23
#define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R)
24
#endif
25
 
26
#if !defined(lua_pushliteral)
27
#define lua_pushliteral(L, s)	\
28
	lua_pushstring(L, "" s, (sizeof(s)/sizeof(char))-1)
29
#endif
30
 
31
 
32
enum XPState {
33
  XPSpre,  /* parser just initialized */
34
  XPSok,   /* state while parsing */
35
  XPSfinished,  /* state after finished parsing */
36
  XPSerror,
37
  XPSstring  /* state while reading a string */
38
};
39
 
40
struct lxp_userdata {
41
  lua_State *L;
42
  XML_Parser parser;  /* associated expat parser */
43
  int errorref;  /* reference to error message if state is XPSerror */
44
  enum XPState state;
45
  luaL_Buffer *b;  /* to concatenate sequences of cdata pieces */
46
  int bufferCharData; /* whether to buffer cdata pieces */
47
};
48
 
49
typedef struct lxp_userdata lxp_userdata;
50
 
51
 
52
static int reporterror (lxp_userdata *xpu) {
53
  lua_State *L = xpu->L;
54
  XML_Parser p = xpu->parser;
55
  lua_pushnil(L);
56
  lua_pushstring(L, XML_ErrorString(XML_GetErrorCode(p)));
57
  lua_pushnumber(L, XML_GetCurrentLineNumber(p));
58
  lua_pushnumber(L, XML_GetCurrentColumnNumber(p) + 1);
59
  lua_pushnumber(L, XML_GetCurrentByteIndex(p) + 1);
60
  return 5;
61
}
62
 
63
 
64
static lxp_userdata *createlxp (lua_State *L) {
65
  lxp_userdata *xpu = (lxp_userdata *)lua_newuserdata(L, sizeof(lxp_userdata));
66
  xpu->errorref = LUA_REFNIL;
67
  xpu->parser = NULL;
68
  xpu->L = NULL;
69
  xpu->state = XPSpre;
70
  luaL_getmetatable(L, ParserType);
71
  lua_setmetatable(L, -2);
72
  return xpu;
73
}
74
 
75
 
76
static void lxpclose (lua_State *L, lxp_userdata *xpu) {
77
  luaL_unref(L, LUA_REGISTRYINDEX, xpu->errorref);
78
  xpu->errorref = LUA_REFNIL;
79
  if (xpu->parser)
80
    XML_ParserFree(xpu->parser);
81
  xpu->parser = NULL;
82
}
83
 
84
 
85
 
86
 
87
/*
88
** Auxiliary function to call a Lua handle
89
*/
90
static void docall (lxp_userdata *xpu, int nargs, int nres) {
91
  lua_State *L = xpu->L;
92
  assert(xpu->state == XPSok);
93
  if (lua_pcall(L, nargs + 1, nres, 0) != 0) {
94
    xpu->state = XPSerror;
95
    xpu->errorref = luaL_ref(L, LUA_REGISTRYINDEX);  /* error message */
96
  }
97
}
98
 
99
 
100
/*
101
** Check whether there is pending Cdata, and call its handle if necessary
102
*/
103
static void dischargestring (lxp_userdata *xpu) {
104
  assert(xpu->state == XPSstring);
105
  xpu->state = XPSok;
106
  luaL_pushresult(xpu->b);
107
  docall(xpu, 1, 0);
108
}
109
 
110
 
111
/*
112
** Check whether there is a Lua handle for a given event: If so,
113
** put it on the stack (to be called later), and also push `self'
114
*/
115
static int getHandle (lxp_userdata *xpu, const char *handle) {
116
  lua_State *L = xpu->L;
117
  if (xpu->state == XPSstring) dischargestring(xpu);
118
  if (xpu->state == XPSerror)
119
    return 0;  /* some error happened before; skip all handles */
120
  lua_pushstring(L, handle);
121
  lua_gettable(L, 3);
122
  if (lua_toboolean(L, -1) == 0) {
123
    lua_pop(L, 1);
124
    return 0;
125
  }
126
  if (!lua_isfunction(L, -1)) {
127
    luaL_error(L, "lxp `%s' callback is not a function", handle);
128
  }
129
  lua_pushvalue(L, 1);  /* first argument in every call (self) */
130
  return 1;
131
}
132
 
133
 
134
 
135
/*
136
** {======================================================
137
** Handles
138
** =======================================================
139
*/
140
 
141
 
142
static void f_StartCdata (void *ud) {
143
  lxp_userdata *xpu = (lxp_userdata *)ud;
144
  if (getHandle(xpu, StartCdataKey) == 0) return;  /* no handle */
145
  docall(xpu, 0, 0);
146
}
147
 
148
 
149
static void f_EndCdataKey (void *ud) {
150
  lxp_userdata *xpu = (lxp_userdata *)ud;
151
  if (getHandle(xpu, EndCdataKey) == 0) return;  /* no handle */
152
  docall(xpu, 0, 0);
153
}
154
 
155
 
156
static void f_CharData (void *ud, const char *s, int len) {
157
  lxp_userdata *xpu = (lxp_userdata *)ud;
158
  if (xpu->state == XPSok) {
159
    if (getHandle(xpu, CharDataKey) == 0) return;  /* no handle */
160
    if(xpu->bufferCharData != 0) {
161
      xpu->state = XPSstring;
162
      luaL_buffinit(xpu->L, xpu->b);
163
    } else {
164
      lua_pushlstring(xpu->L, s, len);
165
      docall(xpu, 1, 0);
166
    }
167
  }
168
  if (xpu->state == XPSstring)
169
    luaL_addlstring(xpu->b, s, len);
170
}
171
 
172
 
173
static void f_Comment (void *ud, const char *data) {
174
  lxp_userdata *xpu = (lxp_userdata *)ud;
175
  if (getHandle(xpu, CommentKey) == 0) return;  /* no handle */
176
  lua_pushstring(xpu->L, data);
177
  docall(xpu, 1, 0);
178
}
179
 
180
 
181
static void f_Default (void *ud, const char *data, int len) {
182
  lxp_userdata *xpu = (lxp_userdata *)ud;
183
  if (getHandle(xpu, DefaultKey) == 0) return;  /* no handle */
184
  lua_pushlstring(xpu->L, data, len);
185
  docall(xpu, 1, 0);
186
}
187
 
188
 
189
static void f_DefaultExpand (void *ud, const char *data, int len) {
190
  lxp_userdata *xpu = (lxp_userdata *)ud;
191
  if (getHandle(xpu, DefaultExpandKey) == 0) return;  /* no handle */
192
  lua_pushlstring(xpu->L, data, len);
193
  docall(xpu, 1, 0);
194
}
195
 
196
 
197
static void f_StartElement (void *ud, const char *name, const char **attrs) {
198
  lxp_userdata *xpu = (lxp_userdata *)ud;
199
  lua_State *L = xpu->L;
200
  int lastspec = XML_GetSpecifiedAttributeCount(xpu->parser) / 2;
201
  int i = 1;
202
  if (getHandle(xpu, StartElementKey) == 0) return;  /* no handle */
203
  lua_pushstring(L, name);
204
  lua_newtable(L);
205
  while (*attrs) {
206
    if (i <= lastspec) {
207
      lua_pushnumber(L, i++);
208
      lua_pushstring(L, *attrs);
209
      lua_settable(L, -3);
210
    }
211
    lua_pushstring(L, *attrs++);
212
    lua_pushstring(L, *attrs++);
213
    lua_settable(L, -3);
214
  }
215
  docall(xpu, 2, 0);  /* call function with self, name, and attributes */
216
}
217
 
218
 
219
static void f_EndElement (void *ud, const char *name) {
220
  lxp_userdata *xpu = (lxp_userdata *)ud;
221
  if (getHandle(xpu, EndElementKey) == 0) return;  /* no handle */
222
  lua_pushstring(xpu->L, name);
223
  docall(xpu, 1, 0);
224
}
225
 
226
 
227
static int f_ExternaEntity (XML_Parser p, const char *context,
228
                                          const char *base,
229
                                          const char *systemId,
230
                                          const char *publicId) {
231
  lxp_userdata *xpu = (lxp_userdata *)XML_GetUserData(p);
232
  lua_State *L = xpu->L;
233
  lxp_userdata *child;
234
  int status;
235
  if (getHandle(xpu, ExternalEntityKey) == 0) return 1;  /* no handle */
236
  child = createlxp(L);
237
  child->parser = XML_ExternalEntityParserCreate(p, context, NULL);
238
  if (!child->parser)
239
    luaL_error(L, "XML_ParserCreate failed");
240
  lua_getuservalue(L, 1);
241
  lua_setuservalue(L, -2); /* child uses the same table of its father */
242
  lua_pushstring(L, base);
243
  lua_pushstring(L, systemId);
244
  lua_pushstring(L, publicId);
245
  docall(xpu, 4, 1);
246
  status = lua_toboolean(L, -1);
247
  lua_pop(L, 1);
248
  lxpclose(L, child);
249
  return status;
250
}
251
 
252
 
253
static void f_StartNamespaceDecl (void *ud, const char *prefix,
254
                                            const char *uri) {
255
  lxp_userdata *xpu = (lxp_userdata *)ud;
256
  lua_State *L = xpu->L;
257
  if (getHandle(xpu, StartNamespaceDeclKey) == 0) return;  /* no handle */
258
  lua_pushstring(L, prefix);
259
  lua_pushstring(L, uri);
260
  docall(xpu, 2, 0);
261
}
262
 
263
 
264
static void f_EndNamespaceDecl (void *ud, const char *prefix) {
265
  lxp_userdata *xpu = (lxp_userdata *)ud;
266
  if (getHandle(xpu, EndNamespaceDeclKey) == 0) return;  /* no handle */
267
  lua_pushstring(xpu->L, prefix);
268
  docall(xpu, 1, 0);
269
}
270
 
271
 
272
static void f_NotationDecl (void *ud, const char *notationName,
273
                                      const char *base,
274
                                      const char *systemId,
275
                                      const char *publicId) {
276
  lxp_userdata *xpu = (lxp_userdata *)ud;
277
  lua_State *L = xpu->L;
278
  if (getHandle(xpu, NotationDeclKey) == 0) return;  /* no handle */
279
  lua_pushstring(L, notationName);
280
  lua_pushstring(L, base);
281
  lua_pushstring(L, systemId);
282
  lua_pushstring(L, publicId);
283
  docall(xpu, 4, 0);
284
}
285
 
286
 
287
static int f_NotStandalone (void *ud) {
288
  int status;
289
  lxp_userdata *xpu = (lxp_userdata *)ud;
290
  lua_State *L = xpu->L;
291
  if (getHandle(xpu, NotStandaloneKey) == 0) return 1;  /* no handle */
292
  docall(xpu, 0, 1);
293
  status = lua_toboolean(L, -1);
294
  lua_pop(L, 1);
295
  return status;
296
}
297
 
298
 
299
static void f_ProcessingInstruction (void *ud, const char *target,
300
                                               const char *data) {
301
  lxp_userdata *xpu = (lxp_userdata *)ud;
302
  lua_State *L = xpu->L;
303
  if (getHandle(xpu, ProcessingInstructionKey) == 0) return;  /* no handle */
304
  lua_pushstring(L, target);
305
  lua_pushstring(L, data);
306
  docall(xpu, 2, 0);
307
}
308
 
309
 
310
static void f_UnparsedEntityDecl (void *ud, const char *entityName,
311
                                            const char *base,
312
                                            const char *systemId,
313
                                            const char *publicId,
314
                                            const char *notationName) {
315
  lxp_userdata *xpu = (lxp_userdata *)ud;
316
  lua_State *L = xpu->L;
317
  if (getHandle(xpu, UnparsedEntityDeclKey) == 0) return;  /* no handle */
318
  lua_pushstring(L, entityName);
319
  lua_pushstring(L, base);
320
  lua_pushstring(L, systemId);
321
  lua_pushstring(L, publicId);
322
  lua_pushstring(L, notationName);
323
  docall(xpu, 5, 0);
324
}
325
 
326
static void f_StartDoctypeDecl (void *ud, const XML_Char *doctypeName,
327
                                          const XML_Char *sysid,
328
                                          const XML_Char *pubid,
329
                                          int has_internal_subset) {
330
  lxp_userdata *xpu = (lxp_userdata *)ud;
331
  if (getHandle(xpu, StartDoctypeDeclKey) == 0) return;  /* no handle */
332
  lua_pushstring(xpu->L, doctypeName);
333
  lua_pushstring(xpu->L, sysid);
334
  lua_pushstring(xpu->L, pubid);
335
  lua_pushboolean(xpu->L, has_internal_subset);
336
  docall(xpu, 4, 0);
337
}
338
 
339
static void f_XmlDecl (void *ud, const XML_Char *version,
340
                                 const XML_Char *encoding,
341
                                 int standalone) {
342
  lxp_userdata *xpu = (lxp_userdata *)ud;
343
  if (getHandle(xpu, XmlDeclKey) == 0) return;  /* no handle */
344
  lua_pushstring(xpu->L, version);
345
  lua_pushstring(xpu->L, encoding);
346
  lua_pushboolean(xpu->L, standalone);
347
  docall(xpu, 3, 0);
348
}
349
/* }====================================================== */
350
 
351
 
352
 
353
static int hasfield (lua_State *L, const char *fname) {
354
  int res;
355
  lua_pushstring(L, fname);
356
  lua_gettable(L, 1);
357
  res = !lua_isnil(L, -1);
358
  lua_pop(L, 1);
359
  return res;
360
}
361
 
362
 
363
static void checkcallbacks (lua_State *L) {
364
  static const char *const validkeys[] = {
365
    "StartCdataSection", "EndCdataSection", "CharacterData", "Comment",
366
    "Default", "DefaultExpand", "StartElement", "EndElement",
367
    "ExternalEntityRef", "StartNamespaceDecl", "EndNamespaceDecl",
368
    "NotationDecl", "NotStandalone", "ProcessingInstruction",
369
    "UnparsedEntityDecl", "StartDoctypeDecl", "XmlDecl", NULL};
370
  if (hasfield(L, "_nonstrict")) return;
371
  lua_pushnil(L);
372
  while (lua_next(L, 1)) {
373
    lua_pop(L, 1);  /* remove value */
374
#if ! defined (LUA_VERSION_NUM) || LUA_VERSION_NUM < 501
375
    if (lua_type(L, -1) != LUA_TSTRING ||
376
        luaL_findstring(lua_tostring(L, -1), validkeys) < 0)
377
      luaL_error(L, "invalid key `%s' in callback table", lua_tostring(L, -1));
378
#else
379
    luaL_checkoption(L, -1, NULL, validkeys);
380
#endif
381
  }
382
}
383
 
384
 
385
static int lxp_make_parser (lua_State *L) {
386
  XML_Parser p;
387
  int bufferCharData = (lua_type(L, 3) != LUA_TBOOLEAN) || (lua_toboolean(L, 3) != 0);
388
  char sep = *luaL_optstring(L, 2, "");
389
  lxp_userdata *xpu = createlxp(L);
390
  xpu->bufferCharData = bufferCharData;
391
  p = xpu->parser = (sep == '\0') ? XML_ParserCreate(NULL) :
392
                                    XML_ParserCreateNS(NULL, sep);
393
  if (!p)
394
    luaL_error(L, "XML_ParserCreate failed");
395
  luaL_checktype(L, 1, LUA_TTABLE);
396
  checkcallbacks(L);
397
  lua_pushvalue(L, 1);
398
  lua_setuservalue(L, -2);
399
  XML_SetUserData(p, xpu);
400
  if (hasfield(L, StartCdataKey) || hasfield(L, EndCdataKey))
401
    XML_SetCdataSectionHandler(p, f_StartCdata, f_EndCdataKey);
402
  if (hasfield(L, CharDataKey))
403
    XML_SetCharacterDataHandler(p, f_CharData);
404
  if (hasfield(L, CommentKey))
405
    XML_SetCommentHandler(p, f_Comment);
406
  if (hasfield(L, DefaultKey))
407
    XML_SetDefaultHandler(p, f_Default);
408
  if (hasfield(L, DefaultExpandKey))
409
    XML_SetDefaultHandlerExpand(p, f_DefaultExpand);
410
  if (hasfield(L, StartElementKey) || hasfield(L, EndElementKey))
411
    XML_SetElementHandler(p, f_StartElement, f_EndElement);
412
  if (hasfield(L, ExternalEntityKey))
413
    XML_SetExternalEntityRefHandler(p, f_ExternaEntity);
414
  if (hasfield(L, StartNamespaceDeclKey) || hasfield(L, EndNamespaceDeclKey))
415
    XML_SetNamespaceDeclHandler(p, f_StartNamespaceDecl, f_EndNamespaceDecl);
416
  if (hasfield(L, NotationDeclKey))
417
    XML_SetNotationDeclHandler(p, f_NotationDecl);
418
  if (hasfield(L, NotStandaloneKey))
419
    XML_SetNotStandaloneHandler(p, f_NotStandalone);
420
  if (hasfield(L, ProcessingInstructionKey))
421
    XML_SetProcessingInstructionHandler(p, f_ProcessingInstruction);
422
  if (hasfield(L, UnparsedEntityDeclKey))
423
    XML_SetUnparsedEntityDeclHandler(p, f_UnparsedEntityDecl);
424
  if (hasfield(L, StartDoctypeDeclKey))
425
    XML_SetStartDoctypeDeclHandler(p, f_StartDoctypeDecl);
426
  if (hasfield(L, XmlDeclKey))
427
    XML_SetXmlDeclHandler(p, f_XmlDecl);
428
  return 1;
429
}
430
 
431
 
432
static lxp_userdata *checkparser (lua_State *L, int idx) {
433
  lxp_userdata *xpu = (lxp_userdata *)luaL_checkudata(L, idx, ParserType);
434
  luaL_argcheck(L, xpu, idx, "expat parser expected");
435
  luaL_argcheck(L, xpu->parser, idx, "parser is closed");
436
  return xpu;
437
}
438
 
439
 
440
static int parser_gc (lua_State *L) {
441
  lxp_userdata *xpu = (lxp_userdata *)luaL_checkudata(L, 1, ParserType);
442
  luaL_argcheck(L, xpu, 1, "expat parser expected");
443
  lxpclose(L, xpu);
444
  return 0;
445
}
446
 
447
 
448
static int setbase (lua_State *L) {
449
  lxp_userdata *xpu = checkparser(L, 1);
450
  if (XML_SetBase(xpu->parser, luaL_checkstring(L, 2)) == 0)
451
    luaL_error(L, "no memory to store base");
452
  return 0;
453
}
454
 
455
 
456
static int getbase (lua_State *L) {
457
  lxp_userdata *xpu = checkparser(L, 1);
458
  lua_pushstring(L, XML_GetBase(xpu->parser));
459
  return 1;
460
}
461
 
462
 
463
static int getcallbacks (lua_State *L) {
464
  checkparser(L, 1);
465
  lua_getuservalue(L, 1);
466
  return 1;
467
}
468
 
469
 
470
static int parse_aux (lua_State *L, lxp_userdata *xpu, const char *s,
471
                      size_t len) {
472
  luaL_Buffer b;
473
  int status;
474
  xpu->L = L;
475
  xpu->state = XPSok;
476
  xpu->b = &b;
477
  lua_settop(L, 2);
478
  getcallbacks(L);
479
  status = XML_Parse(xpu->parser, s, (int)len, s == NULL);
480
  if (xpu->state == XPSstring) dischargestring(xpu);
481
  if (xpu->state == XPSerror) {  /* callback error? */
482
    lua_rawgeti(L, LUA_REGISTRYINDEX, xpu->errorref);  /* get original msg. */
483
    lua_error(L);
484
  }
485
  if (s == NULL) xpu->state = XPSfinished;
486
  if (status) {
487
    lua_pushboolean(L, 1);
488
    return 1;
489
  }
490
  else { /* error */
491
    return reporterror(xpu);
492
  }
493
}
494
 
495
 
496
static int lxp_parse (lua_State *L) {
497
  lxp_userdata *xpu = checkparser(L, 1);
498
  size_t len;
499
  const char *s = luaL_optlstring(L, 2, NULL, &len);
500
  if (xpu->state == XPSfinished && s != NULL) {
501
    lua_pushnil(L);
502
    lua_pushliteral(L, "cannot parse - document is finished");
503
    return 2;
504
  }
505
  return parse_aux(L, xpu, s, len);
506
}
507
 
508
 
509
static int lxp_close (lua_State *L) {
510
  int status = 1;
511
  lxp_userdata *xpu = (lxp_userdata *)luaL_checkudata(L, 1, ParserType);
512
  luaL_argcheck(L, xpu, 1, "expat parser expected");
513
  if (xpu->state != XPSfinished)
514
    status = parse_aux(L, xpu, NULL, 0);
515
  lxpclose(L, xpu);
516
  if (status > 1) luaL_error(L, "error closing parser: %s",
517
                                lua_tostring(L, -status+1));
518
  return 0;
519
}
520
 
521
 
522
static int lxp_pos (lua_State *L) {
523
  lxp_userdata *xpu = checkparser(L, 1);
524
  XML_Parser p = xpu->parser;
525
  lua_pushnumber(L, XML_GetCurrentLineNumber(p));
526
  lua_pushnumber(L, XML_GetCurrentColumnNumber(p) + 1);
527
  lua_pushnumber(L, XML_GetCurrentByteIndex(p) + 1);
528
  return 3;
529
}
530
 
531
 
532
static int lxp_setencoding (lua_State *L) {
533
  lxp_userdata *xpu = checkparser(L, 1);
534
  const char *encoding = luaL_checkstring(L, 2);
535
  luaL_argcheck(L, xpu->state == XPSpre, 1, "invalid parser state");
536
  XML_SetEncoding(xpu->parser, encoding);
537
  return 0;
538
}
539
 
540
static int lxp_stop (lua_State *L) {
541
  lxp_userdata *xpu = checkparser(L, 1);
542
  lua_pushboolean(L, XML_StopParser(xpu->parser, XML_FALSE) == XML_STATUS_OK);
543
  return 1;
544
}
545
 
546
#if !defined LUA_VERSION_NUM
547
/* Lua 5.0 */
548
#define luaL_Reg luaL_reg
549
#endif
550
 
551
static int lxp_getcurrentbytecount (lua_State* L) {
552
  lxp_userdata *xpu = checkparser(L, 1);
553
  lua_pushinteger(L, XML_GetCurrentByteCount(xpu->parser));
554
  return 1;
555
}
556
 
557
static const struct luaL_Reg lxp_meths[] = {
558
  {"parse", lxp_parse},
559
  {"close", lxp_close},
560
  {"__gc", parser_gc},
561
  {"pos", lxp_pos},
562
  {"getcurrentbytecount", lxp_getcurrentbytecount},
563
  {"setencoding", lxp_setencoding},
564
  {"getcallbacks", getcallbacks},
565
  {"getbase", getbase},
566
  {"setbase", setbase},
567
  {"stop", lxp_stop},
568
  {NULL, NULL}
569
};
570
 
571
static const struct luaL_Reg lxp_funcs[] = {
572
  {"new", lxp_make_parser},
573
  {NULL, NULL}
574
};
575
 
576
 
577
/*
578
** Assumes the table is on top of the stack.
579
*/
580
static void set_info (lua_State *L) {
581
	lua_pushliteral (L, "_COPYRIGHT");
582
	lua_pushliteral (L, "Copyright (C) 2003-2021 Kepler Project, Matthew Wild");
583
	lua_settable (L, -3);
584
	lua_pushliteral (L, "_DESCRIPTION");
585
	lua_pushliteral (L, "LuaExpat is a SAX XML parser based on the Expat library");
586
	lua_settable (L, -3);
587
	lua_pushliteral (L, "_VERSION");
588
	lua_pushliteral (L, "LuaExpat 1.3.0");
589
	lua_settable (L, -3);
590
	lua_pushliteral (L, "_EXPAT_VERSION");
591
	lua_pushstring (L, XML_ExpatVersion());
592
	lua_settable (L, -3);
593
}
594
 
595
int luaopen_lxp (lua_State *L) {
596
	luaL_newmetatable(L, ParserType);
597
 
598
	lua_pushliteral(L, "__index");
599
	lua_pushvalue(L, -2);
600
	lua_rawset(L, -3);
601
 
602
	luaL_setfuncs (L, lxp_meths, 0);
603
	lua_pop (L, 1); /* remove metatable */
604
 
605
	lua_newtable (L); /* push library table */
606
	luaL_setfuncs (L, lxp_funcs, 0);
607
	set_info (L);
608
	return 1;
609
}