Modify how to make symbolic link in 'find-debuginfo.sh' script
[platform/upstream/rpm.git] / luaext / lrexlib.c
1 /* lrexlib.c - POSIX & PCRE regular expression library */
2 /* POSIX regexs can use Spencer extensions for matching NULs if available
3    (REG_BASIC) */
4 /* Reuben Thomas   nov00-06oct03 */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9
10 #include "lua.h"
11 #include "lauxlib.h"
12 #include "lrexlib.h"
13
14
15 /* Sanity check */
16 #if !defined(WITH_POSIX) && !defined(WITH_PCRE)
17 #error Define WITH_POSIX or WITH_PCRE, otherwise this library is useless!
18 #endif
19
20
21 /* POSIX regex methods */
22
23 #ifdef WITH_POSIX
24
25 #include <regex.h>
26
27 static int rex_comp(lua_State *L)
28 {
29   size_t l;
30   const char *pattern;
31   int res;
32   regex_t *pr = (regex_t *)lua_newuserdata(L, sizeof(regex_t));
33   pattern = luaL_checklstring(L, 1, &l);
34 #ifdef REG_BASIC
35   pr->re_endp = pattern + lua_strlen(L, 1);
36   res = regcomp(pr, pattern, REG_EXTENDED | REG_PEND);
37 #else
38   res = regcomp(pr, pattern, REG_EXTENDED);
39 #endif
40   if (res) {
41     size_t sz = regerror(res, pr, NULL, 0);
42     char errbuf[sz];
43     regerror(res, pr, errbuf, sz);
44     lua_pushstring(L, errbuf);
45     lua_error(L);
46   }
47   luaL_getmetatable(L, "regex_t");
48   lua_setmetatable(L, -2);
49   return 1;
50 }
51
52 static void rex_getargs(lua_State *L, size_t *len, size_t *ncapt,
53                         const char **text, regex_t **pr, regmatch_t **match)
54 {
55   luaL_checkany(L, 1);
56   *pr = (regex_t *)lua_touserdata(L, 1);
57 #ifdef REG_BASIC
58   *text = luaL_checklstring(L, 2, len);
59 #else
60   *text = luaL_checklstring(L, 2, NULL);
61 #endif
62   *ncapt = (*pr)->re_nsub;
63   luaL_checkstack(L, *ncapt + 2, "too many captures");
64   *match = malloc((*ncapt + 1) * sizeof(regmatch_t));
65 }
66
67 static void rex_push_matches(lua_State *L, const char *text, regmatch_t *match,
68                              size_t ncapt)
69 {
70   size_t i;
71   lua_newtable(L);
72   for (i = 1; i <= ncapt; i++) {
73     if (match[i].rm_so >= 0) {
74       lua_pushlstring(L, text + match[i].rm_so,
75                       match[i].rm_eo - match[i].rm_so);
76       lua_rawseti(L, -2, i);
77     }
78   }
79 }
80
81 static int rex_match(lua_State *L)
82 {
83   int res;
84 #ifdef REG_BASIC
85   size_t len;
86 #endif
87   size_t ncapt;
88   const char *text;
89   regex_t *pr;
90   regmatch_t *match;
91   rex_getargs(L,
92 #ifdef REG_BASIC
93           &len,
94 #else
95           NULL,
96 #endif
97           &ncapt, &text, &pr, &match);
98 #ifdef REG_BASIC
99   match[0].rm_so = 0;
100   match[0].rm_eo = len;
101   res = regexec(pr, text, ncapt + 1, match, REG_STARTEND);
102 #else
103   res = regexec(pr, text, ncapt + 1, match, 0);
104 #endif
105   if (res == 0) {
106     lua_pushnumber(L, match[0].rm_so + 1);
107     lua_pushnumber(L, match[0].rm_eo);
108     rex_push_matches(L, text, match, ncapt);
109     lua_pushstring(L, "n");
110     lua_pushnumber(L, ncapt);
111     lua_rawset(L, -3);
112     return 3;
113   } else
114     return 0;
115 }
116
117 static int rex_gmatch(lua_State *L)
118 {
119   int res;
120 #ifdef REG_BASIC
121   size_t len;
122 #endif
123   size_t ncapt, nmatch = 0, maxmatch = 0, limit = 0;
124   const char *text;
125   regex_t *pr;
126   regmatch_t *match;
127   rex_getargs(L,
128 #ifdef REG_BASIC
129           &len,
130 #else
131           NULL,
132 #endif
133           &ncapt, &text, &pr, &match);
134   luaL_checktype(L, 3, LUA_TFUNCTION);
135   if (lua_gettop(L) > 3) {
136     maxmatch = (size_t)luaL_checknumber(L, 4);
137     limit = 1;
138   }
139   while (!limit || nmatch < maxmatch) {
140 #ifdef REG_BASIC
141     match[0].rm_so = 0;
142     match[0].rm_eo = len;
143     res = regexec(pr, text, ncapt + 1, match, REG_STARTEND);
144 #else
145     res = regexec(pr, text, ncapt + 1, match, 0);
146 #endif
147     if (res == 0) {
148       lua_pushvalue(L, 3);
149       lua_pushlstring(L, text + match[0].rm_so, match[0].rm_eo - match[0].rm_so);
150       rex_push_matches(L, text, match, ncapt);
151       lua_call(L, 2, 0);
152       text += match[0].rm_eo;
153 #ifdef REG_BASIC
154       len -= match[0].rm_eo;
155 #endif
156       nmatch++;
157     } else
158       break;
159   }
160   lua_pushnumber(L, nmatch);
161   return 1;
162 }
163
164 static int rex_gc (lua_State *L)
165 {
166   regex_t *r = (regex_t *)luaL_checkudata(L, 1, "regex_t");
167   if (r)
168     regfree(r);
169   return 0;
170 }
171
172 static const luaL_Reg rexmeta[] = {
173   {"match",   rex_match},
174   {"gmatch",  rex_gmatch},
175   {"__gc",    rex_gc},
176   {NULL, NULL}
177 };
178
179 #endif /* WITH_POSIX */
180
181
182 /* PCRE methods */
183
184 #ifdef WITH_PCRE
185
186 #include <pcre/pcre.h>
187
188 static int pcre_comp(lua_State *L)
189 {
190   size_t l;
191   const char *pattern;
192   const char *error;
193   int erroffset;
194   pcre **ppr = (pcre **)lua_newuserdata(L, sizeof(pcre **));
195   pcre *pr;
196   pattern = luaL_checklstring(L, 1, &l);
197   pr = pcre_compile(pattern, 0, &error, &erroffset, NULL);
198   if (!pr) {
199     lua_pushstring(L, error);
200     lua_error(L);
201   }
202   *ppr = pr;
203   luaL_getmetatable(L, "pcre");
204   lua_setmetatable(L, -2);
205   return 1;
206 }
207
208 static void pcre_getargs(lua_State *L, int *len, int *ncapt, const char **text,
209                         pcre ***ppr, int **match)
210 {
211   luaL_checkany(L, 1);
212   *ppr = (pcre **)lua_touserdata(L, 1);
213   *text = luaL_checklstring(L, 2, len);
214   pcre_fullinfo(**ppr, NULL, PCRE_INFO_CAPTURECOUNT, ncapt);
215   luaL_checkstack(L, *ncapt + 2, "too many captures");
216   /* need (2 ints per capture, plus one for substring match) * 3/2 */
217   *match = malloc((*ncapt + 1) * 3 * sizeof(int));
218 }
219
220 static void pcre_push_matches(lua_State *L, const char *text, int *match,
221                              int ncapt)
222 {
223   int i;
224   lua_newtable(L);
225   for (i = 1; i <= ncapt; i++) {
226     if (match[i * 2] >= 0) {
227       lua_pushlstring(L, text + match[i * 2],
228                       match[i * 2 + 1] - match[i * 2]);
229       lua_rawseti(L, -2, i);
230     }
231   }
232 }
233
234 static int pcre_match(lua_State *L)
235 {
236   int res;
237   const char *text;
238   pcre **ppr;
239   int *match;
240   int ncapt;
241   int len;
242   pcre_getargs(L, &len, &ncapt, &text, &ppr, &match);
243   res = pcre_exec(*ppr, NULL, text, len, 0, 0, match, (ncapt + 1) * 3);
244   if (res >= 0) {
245     lua_pushnumber(L, match[0] + 1);
246     lua_pushnumber(L, match[1]);
247     pcre_push_matches(L, text, match, ncapt);
248     lua_pushstring(L, "n");
249     lua_pushnumber(L, ncapt);
250     lua_rawset(L, -3);
251     return 3;
252   } else
253     return 0;
254 }
255
256 static int pcre_gmatch(lua_State *L)
257 {
258   int res;
259   const char *text;
260   int limit = 0;
261   int ncapt, nmatch = 0, maxmatch;
262   pcre **ppr;
263   int *match;
264   int len;
265   pcre_getargs(L, &len, &ncapt, &text, &ppr, &match);
266   luaL_checktype(L, 3, LUA_TFUNCTION);
267   if (lua_gettop(L) > 3) {
268     maxmatch = (int)luaL_checknumber(L, 4);
269     limit = 1;
270   }
271   while (!limit || nmatch < maxmatch) {
272     res = pcre_exec(*ppr, NULL, text, len, 0, 0, match, (ncapt + 1) * 3);
273     if (res == 0) {
274       lua_pushvalue(L, 3);
275       lua_pushlstring(L, text + match[0], match[1] - match[0]);
276       pcre_push_matches(L, text, match, ncapt);
277       lua_call(L, 2, 0);
278       text += match[1];
279       len -= match[1];
280       nmatch++;
281     } else
282       break;
283   }
284   lua_pushnumber(L, nmatch);
285   return 1;
286 }
287
288 static int pcre_gc (lua_State *L)
289 {
290   pcre **ppr = (pcre **)luaL_checkudata(L, 1, "pcre");
291   if (ppr)
292     pcre_free(*ppr);
293   return 0;
294 }
295
296 static const luaL_reg pcremeta[] = {
297   {"match",  pcre_match},
298   {"gmatch", pcre_gmatch},
299   {"__gc",   pcre_gc},
300   {NULL, NULL}
301 };
302
303 #endif /* defined(WITH_PCRE) */
304
305
306 /* Open the library */
307
308 static const luaL_Reg rexlib[] = {
309 #ifdef WITH_POSIX
310   {"newPOSIX", rex_comp},
311 #endif
312 #ifdef WITH_PCRE
313   {"newPCRE", pcre_comp},
314 #endif
315   {NULL, NULL}
316 };
317
318 static void createmeta(lua_State *L, const char *name)
319 {
320   luaL_newmetatable(L, name);   /* create new metatable */
321   lua_pushliteral(L, "__index");
322   lua_pushvalue(L, -2);         /* push metatable */
323   lua_rawset(L, -3);            /* metatable.__index = metatable */
324 }
325
326 LUALIB_API int luaopen_rex(lua_State *L)
327 {
328 #ifdef WITH_POSIX
329   createmeta(L, "regex_t");
330   luaL_openlib(L, NULL, rexmeta, 0);
331   lua_pop(L, 1);
332 #endif
333 #ifdef WITH_PCRE
334   createmeta(L, "pcre");
335   luaL_openlib(L, NULL, pcremeta, 0);
336   lua_pop(L, 1);
337 #endif
338   luaL_openlib(L, "rex", rexlib, 0);
339   return 1;
340 }