csomh / source-git / rpm

Forked from source-git/rpm 4 years ago
Clone
2ff057
/* lrexlib.c - POSIX & PCRE regular expression library */
2ff057
/* POSIX regexs can use Spencer extensions for matching NULs if available
2ff057
   (REG_BASIC) */
2ff057
/* Reuben Thomas   nov00-06oct03 */
2ff057
2ff057
#include <stdio.h>
2ff057
#include <stdlib.h>
2ff057
#include <string.h>
2ff057
2ff057
#include "lua.h"
2ff057
#include "lauxlib.h"
2ff057
#include "lrexlib.h"
2ff057
2ff057
2ff057
/* Sanity check */
2ff057
#if !defined(WITH_POSIX) && !defined(WITH_PCRE)
2ff057
#error Define WITH_POSIX or WITH_PCRE, otherwise this library is useless!
2ff057
#endif
2ff057
2ff057
2ff057
/* POSIX regex methods */
2ff057
2ff057
#ifdef WITH_POSIX
2ff057
2ff057
#include <regex.h>
2ff057
2ff057
static int rex_comp(lua_State *L)
2ff057
{
2ff057
  size_t l;
2ff057
  const char *pattern;
2ff057
  int res;
2ff057
  regex_t *pr = (regex_t *)lua_newuserdata(L, sizeof(regex_t));
2ff057
  pattern = luaL_checklstring(L, 1, &l);
2ff057
#ifdef REG_BASIC
2ff057
  pr->re_endp = pattern + lua_strlen(L, 1);
2ff057
  res = regcomp(pr, pattern, REG_EXTENDED | REG_PEND);
2ff057
#else
2ff057
  res = regcomp(pr, pattern, REG_EXTENDED);
2ff057
#endif
2ff057
  if (res) {
2ff057
    size_t sz = regerror(res, pr, NULL, 0);
2ff057
    char errbuf[sz];
2ff057
    regerror(res, pr, errbuf, sz);
2ff057
    lua_pushstring(L, errbuf);
2ff057
    lua_error(L);
2ff057
  }
2ff057
  luaL_getmetatable(L, "regex_t");
2ff057
  lua_setmetatable(L, -2);
2ff057
  return 1;
2ff057
}
2ff057
2ff057
static void rex_getargs(lua_State *L, size_t *len, size_t *ncapt,
2ff057
                        const char **text, regex_t **pr, regmatch_t **match)
2ff057
{
2ff057
  luaL_checkany(L, 1);
2ff057
  *pr = (regex_t *)lua_touserdata(L, 1);
2ff057
#ifdef REG_BASIC
2ff057
  *text = luaL_checklstring(L, 2, len);
2ff057
#else
2ff057
  *text = luaL_checklstring(L, 2, NULL);
2ff057
#endif
2ff057
  *ncapt = (*pr)->re_nsub;
2ff057
  luaL_checkstack(L, *ncapt + 2, "too many captures");
2ff057
  *match = malloc((*ncapt + 1) * sizeof(regmatch_t));
2ff057
}
2ff057
2ff057
static void rex_push_matches(lua_State *L, const char *text, regmatch_t *match,
2ff057
                             size_t ncapt)
2ff057
{
2ff057
  size_t i;
2ff057
  lua_newtable(L);
2ff057
  for (i = 1; i <= ncapt; i++) {
2ff057
    if (match[i].rm_so >= 0) {
2ff057
      lua_pushlstring(L, text + match[i].rm_so,
2ff057
                      match[i].rm_eo - match[i].rm_so);
2ff057
      lua_rawseti(L, -2, i);
2ff057
    }
2ff057
  }
2ff057
}
2ff057
2ff057
static int rex_match(lua_State *L)
2ff057
{
2ff057
  int res;
2ff057
#ifdef REG_BASIC
2ff057
  size_t len;
2ff057
#endif
2ff057
  size_t ncapt;
2ff057
  const char *text;
2ff057
  regex_t *pr;
2ff057
  regmatch_t *match;
2ff057
  rex_getargs(L,
2ff057
#ifdef REG_BASIC
2ff057
          &len,
2ff057
#else
2ff057
          NULL,
2ff057
#endif
2ff057
          &ncapt, &text, &pr, &match);
2ff057
#ifdef REG_BASIC
2ff057
  match[0].rm_so = 0;
2ff057
  match[0].rm_eo = len;
2ff057
  res = regexec(pr, text, ncapt + 1, match, REG_STARTEND);
2ff057
#else
2ff057
  res = regexec(pr, text, ncapt + 1, match, 0);
2ff057
#endif
2ff057
  if (res == 0) {
2ff057
    lua_pushnumber(L, match[0].rm_so + 1);
2ff057
    lua_pushnumber(L, match[0].rm_eo);
2ff057
    rex_push_matches(L, text, match, ncapt);
2ff057
    lua_pushstring(L, "n");
2ff057
    lua_pushnumber(L, ncapt);
2ff057
    lua_rawset(L, -3);
2ff057
    return 3;
2ff057
  } else
2ff057
    return 0;
2ff057
}
2ff057
2ff057
static int rex_gmatch(lua_State *L)
2ff057
{
2ff057
  int res;
2ff057
#ifdef REG_BASIC
2ff057
  size_t len;
2ff057
#endif
2ff057
  size_t ncapt, nmatch = 0, maxmatch = 0, limit = 0;
2ff057
  const char *text;
2ff057
  regex_t *pr;
2ff057
  regmatch_t *match;
2ff057
  rex_getargs(L,
2ff057
#ifdef REG_BASIC
2ff057
          &len,
2ff057
#else
2ff057
          NULL,
2ff057
#endif
2ff057
          &ncapt, &text, &pr, &match);
2ff057
  luaL_checktype(L, 3, LUA_TFUNCTION);
2ff057
  if (lua_gettop(L) > 3) {
2ff057
    maxmatch = (size_t)luaL_checknumber(L, 4);
2ff057
    limit = 1;
2ff057
  }
2ff057
  while (!limit || nmatch < maxmatch) {
2ff057
#ifdef REG_BASIC
2ff057
    match[0].rm_so = 0;
2ff057
    match[0].rm_eo = len;
2ff057
    res = regexec(pr, text, ncapt + 1, match, REG_STARTEND);
2ff057
#else
2ff057
    res = regexec(pr, text, ncapt + 1, match, 0);
2ff057
#endif
2ff057
    if (res == 0) {
2ff057
      lua_pushvalue(L, 3);
2ff057
      lua_pushlstring(L, text + match[0].rm_so, match[0].rm_eo - match[0].rm_so);
2ff057
      rex_push_matches(L, text, match, ncapt);
2ff057
      lua_call(L, 2, 0);
2ff057
      text += match[0].rm_eo;
2ff057
#ifdef REG_BASIC
2ff057
      len -= match[0].rm_eo;
2ff057
#endif
2ff057
      nmatch++;
2ff057
    } else
2ff057
      break;
2ff057
  }
2ff057
  lua_pushnumber(L, nmatch);
2ff057
  return 1;
2ff057
}
2ff057
2ff057
static int rex_gc (lua_State *L)
2ff057
{
2ff057
  regex_t *r = (regex_t *)luaL_checkudata(L, 1, "regex_t");
2ff057
  if (r)
2ff057
    regfree(r);
2ff057
  return 0;
2ff057
}
2ff057
2ff057
static const luaL_Reg rexmeta[] = {
2ff057
  {"match",   rex_match},
2ff057
  {"gmatch",  rex_gmatch},
2ff057
  {"__gc",    rex_gc},
2ff057
  {NULL, NULL}
2ff057
};
2ff057
2ff057
#endif /* WITH_POSIX */
2ff057
2ff057
2ff057
/* PCRE methods */
2ff057
2ff057
#ifdef WITH_PCRE
2ff057
2ff057
#include <pcre/pcre.h>
2ff057
2ff057
static int pcre_comp(lua_State *L)
2ff057
{
2ff057
  size_t l;
2ff057
  const char *pattern;
2ff057
  const char *error;
2ff057
  int erroffset;
2ff057
  pcre **ppr = (pcre **)lua_newuserdata(L, sizeof(pcre **));
2ff057
  pcre *pr;
2ff057
  pattern = luaL_checklstring(L, 1, &l);
2ff057
  pr = pcre_compile(pattern, 0, &error, &erroffset, NULL);
2ff057
  if (!pr) {
2ff057
    lua_pushstring(L, error);
2ff057
    lua_error(L);
2ff057
  }
2ff057
  *ppr = pr;
2ff057
  luaL_getmetatable(L, "pcre");
2ff057
  lua_setmetatable(L, -2);
2ff057
  return 1;
2ff057
}
2ff057
2ff057
static void pcre_getargs(lua_State *L, int *len, int *ncapt, const char **text,
2ff057
                        pcre ***ppr, int **match)
2ff057
{
2ff057
  luaL_checkany(L, 1);
2ff057
  *ppr = (pcre **)lua_touserdata(L, 1);
2ff057
  *text = luaL_checklstring(L, 2, len);
2ff057
  pcre_fullinfo(**ppr, NULL, PCRE_INFO_CAPTURECOUNT, ncapt);
2ff057
  luaL_checkstack(L, *ncapt + 2, "too many captures");
2ff057
  /* need (2 ints per capture, plus one for substring match) * 3/2 */
2ff057
  *match = malloc((*ncapt + 1) * 3 * sizeof(int));
2ff057
}
2ff057
2ff057
static void pcre_push_matches(lua_State *L, const char *text, int *match,
2ff057
                             int ncapt)
2ff057
{
2ff057
  int i;
2ff057
  lua_newtable(L);
2ff057
  for (i = 1; i <= ncapt; i++) {
2ff057
    if (match[i * 2] >= 0) {
2ff057
      lua_pushlstring(L, text + match[i * 2],
2ff057
                      match[i * 2 + 1] - match[i * 2]);
2ff057
      lua_rawseti(L, -2, i);
2ff057
    }
2ff057
  }
2ff057
}
2ff057
2ff057
static int pcre_match(lua_State *L)
2ff057
{
2ff057
  int res;
2ff057
  const char *text;
2ff057
  pcre **ppr;
2ff057
  int *match;
2ff057
  int ncapt;
2ff057
  int len;
2ff057
  pcre_getargs(L, &len, &ncapt, &text, &ppr, &match);
2ff057
  res = pcre_exec(*ppr, NULL, text, len, 0, 0, match, (ncapt + 1) * 3);
2ff057
  if (res >= 0) {
2ff057
    lua_pushnumber(L, match[0] + 1);
2ff057
    lua_pushnumber(L, match[1]);
2ff057
    pcre_push_matches(L, text, match, ncapt);
2ff057
    lua_pushstring(L, "n");
2ff057
    lua_pushnumber(L, ncapt);
2ff057
    lua_rawset(L, -3);
2ff057
    return 3;
2ff057
  } else
2ff057
    return 0;
2ff057
}
2ff057
2ff057
static int pcre_gmatch(lua_State *L)
2ff057
{
2ff057
  int res;
2ff057
  const char *text;
2ff057
  int limit = 0;
2ff057
  int ncapt, nmatch = 0, maxmatch;
2ff057
  pcre **ppr;
2ff057
  int *match;
2ff057
  int len;
2ff057
  pcre_getargs(L, &len, &ncapt, &text, &ppr, &match);
2ff057
  luaL_checktype(L, 3, LUA_TFUNCTION);
2ff057
  if (lua_gettop(L) > 3) {
2ff057
    maxmatch = (int)luaL_checknumber(L, 4);
2ff057
    limit = 1;
2ff057
  }
2ff057
  while (!limit || nmatch < maxmatch) {
2ff057
    res = pcre_exec(*ppr, NULL, text, len, 0, 0, match, (ncapt + 1) * 3);
2ff057
    if (res == 0) {
2ff057
      lua_pushvalue(L, 3);
2ff057
      lua_pushlstring(L, text + match[0], match[1] - match[0]);
2ff057
      pcre_push_matches(L, text, match, ncapt);
2ff057
      lua_call(L, 2, 0);
2ff057
      text += match[1];
2ff057
      len -= match[1];
2ff057
      nmatch++;
2ff057
    } else
2ff057
      break;
2ff057
  }
2ff057
  lua_pushnumber(L, nmatch);
2ff057
  return 1;
2ff057
}
2ff057
2ff057
static int pcre_gc (lua_State *L)
2ff057
{
2ff057
  pcre **ppr = (pcre **)luaL_checkudata(L, 1, "pcre");
2ff057
  if (ppr)
2ff057
    pcre_free(*ppr);
2ff057
  return 0;
2ff057
}
2ff057
2ff057
static const luaL_reg pcremeta[] = {
2ff057
  {"match",  pcre_match},
2ff057
  {"gmatch", pcre_gmatch},
2ff057
  {"__gc",   pcre_gc},
2ff057
  {NULL, NULL}
2ff057
};
2ff057
2ff057
#endif /* defined(WITH_PCRE) */
2ff057
2ff057
2ff057
/* Open the library */
2ff057
2ff057
static const luaL_Reg rexlib[] = {
2ff057
#ifdef WITH_POSIX
2ff057
  {"newPOSIX", rex_comp},
2ff057
#endif
2ff057
#ifdef WITH_PCRE
2ff057
  {"newPCRE", pcre_comp},
2ff057
#endif
2ff057
  {NULL, NULL}
2ff057
};
2ff057
2ff057
static void createmeta(lua_State *L, const char *name)
2ff057
{
2ff057
  luaL_newmetatable(L, name);   /* create new metatable */
2ff057
  lua_pushliteral(L, "__index");
2ff057
  lua_pushvalue(L, -2);         /* push metatable */
2ff057
  lua_rawset(L, -3);            /* metatable.__index = metatable */
2ff057
}
2ff057
2ff057
LUALIB_API int luaopen_rex(lua_State *L)
2ff057
{
2ff057
#ifdef WITH_POSIX
2ff057
  createmeta(L, "regex_t");
2ff057
  luaL_openlib(L, NULL, rexmeta, 0);
2ff057
  lua_pop(L, 1);
2ff057
#endif
2ff057
#ifdef WITH_PCRE
2ff057
  createmeta(L, "pcre");
2ff057
  luaL_openlib(L, NULL, pcremeta, 0);
2ff057
  lua_pop(L, 1);
2ff057
#endif
2ff057
  luaL_openlib(L, "rex", rexlib, 0);
2ff057
  return 1;
2ff057
}