~ubuntu-branches/debian/sid/rpm/sid

« back to all changes in this revision

Viewing changes to .pc/Finish-lua-5.2-support-trac-865.patch/rpmio/rpmlua.c

  • Committer: Package Import Robot
  • Author(s): Michal Čihař
  • Date: 2013-06-06 11:39:34 UTC
  • mfrom: (1.1.16)
  • Revision ID: package-import@ubuntu.com-20130606113934-ela3du14fyba0t6u
Tags: 4.11.0.1-1
* New upstream release.
* Bump standards to 3.9.4.
* Refresh patches, update patch from Fedora.
* Build with Lua 5.2.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "system.h"
 
2
 
 
3
#ifdef  WITH_LUA
 
4
#include <lua.h>
 
5
#include <lualib.h>
 
6
#include <lauxlib.h>
 
7
#include <lposix.h>
 
8
#include <lrexlib.h>
 
9
 
 
10
#ifndef lua_open
 
11
#define lua_open()      luaL_newstate()
 
12
#endif
 
13
 
 
14
#ifndef lua_strlen
 
15
#define lua_strlen(L,i) lua_rawlen(L, (i))
 
16
#endif
 
17
 
 
18
#ifndef lua_pushglobaltable
 
19
#define lua_pushglobaltable(L)  lua_pushvalue(L, LUA_GLOBALSINDEX)
 
20
#endif
 
21
 
 
22
#include <unistd.h>
 
23
#include <assert.h>
 
24
 
 
25
#include <rpm/rpmio.h>
 
26
#include <rpm/rpmmacro.h>
 
27
#include <rpm/rpmlog.h>
 
28
#include <rpm/rpmurl.h>
 
29
#include <rpm/rpmfileutil.h>
 
30
#include <rpm/rpmbase64.h>
 
31
#include "rpmio/rpmhook.h"
 
32
 
 
33
#define _RPMLUA_INTERNAL
 
34
#include "rpmio/rpmlua.h"
 
35
 
 
36
#include "debug.h"
 
37
 
 
38
#define INITSTATE(_lua, lua) \
 
39
    rpmlua lua = _lua ? _lua : \
 
40
            (globalLuaState ? globalLuaState : \
 
41
                        \
 
42
                        (globalLuaState = rpmluaNew()) \
 
43
                        \
 
44
            )
 
45
 
 
46
struct rpmluapb_s {
 
47
    size_t alloced;
 
48
    size_t used;
 
49
    char *buf;
 
50
    rpmluapb next;
 
51
};
 
52
 
 
53
static rpmlua globalLuaState = NULL;
 
54
 
 
55
static int luaopen_rpm(lua_State *L);
 
56
static int rpm_print(lua_State *L);
 
57
 
 
58
rpmlua rpmluaGetGlobalState(void)
 
59
{
 
60
    INITSTATE(NULL, lua);
 
61
    return lua;
 
62
}
 
63
 
 
64
rpmlua rpmluaNew()
 
65
{
 
66
    rpmlua lua = (rpmlua) xcalloc(1, sizeof(*lua));
 
67
    struct stat st;
 
68
    const luaL_Reg *lib;
 
69
    char *initlua = rpmGenPath(rpmConfigDir(), "init.lua", NULL);
 
70
   
 
71
    static const luaL_Reg extlibs[] = {
 
72
        {"posix", luaopen_posix},
 
73
        {"rex", luaopen_rex},
 
74
        {"rpm", luaopen_rpm},
 
75
        {"os",  luaopen_rpm_os},
 
76
        {NULL, NULL},
 
77
    };
 
78
    
 
79
    lua_State *L = lua_open();
 
80
    luaL_openlibs(L);
 
81
    lua->L = L;
 
82
 
 
83
    for (lib = extlibs; lib->name; lib++) {
 
84
        lua_pushcfunction(L, lib->func);
 
85
        lua_pushstring(L, lib->name);
 
86
        lua_call(L, 1, 0);
 
87
        lua_settop(L, 0);
 
88
    }
 
89
#ifndef LUA_GLOBALSINDEX
 
90
    lua_pushglobaltable(L);
 
91
#endif
 
92
    lua_pushliteral(L, "LUA_PATH");
 
93
    lua_pushfstring(L, "%s/%s", rpmConfigDir(), "/lua/?.lua");
 
94
#ifdef LUA_GLOBALSINDEX
 
95
    lua_rawset(L, LUA_GLOBALSINDEX);
 
96
#else
 
97
    lua_settable(L, -3);
 
98
#endif
 
99
    lua_pushliteral(L, "print");
 
100
    lua_pushcfunction(L, rpm_print);
 
101
#ifdef LUA_GLOBALSINDEX
 
102
    lua_rawset(L, LUA_GLOBALSINDEX);
 
103
#else
 
104
    lua_settable(L, -3);
 
105
#endif
 
106
#ifndef LUA_GLOBALSINDEX
 
107
    lua_pop(L, 1);
 
108
#endif
 
109
    rpmluaSetData(lua, "lua", lua);
 
110
    if (stat(initlua, &st) != -1)
 
111
        (void)rpmluaRunScriptFile(lua, initlua);
 
112
    free(initlua);
 
113
    return lua;
 
114
}
 
115
 
 
116
rpmlua rpmluaFree(rpmlua lua)
 
117
{
 
118
    if (lua) {
 
119
        if (lua->L) lua_close(lua->L);
 
120
        free(lua->printbuf);
 
121
        free(lua);
 
122
        if (lua == globalLuaState) globalLuaState = NULL;
 
123
    }
 
124
    return NULL;
 
125
}
 
126
 
 
127
void rpmluaSetData(rpmlua _lua, const char *key, const void *data)
 
128
{
 
129
    INITSTATE(_lua, lua);
 
130
    lua_State *L = lua->L;
 
131
    lua_pushliteral(L, "rpm_");
 
132
    lua_pushstring(L, key);
 
133
    lua_concat(L, 2);
 
134
    if (data == NULL)
 
135
        lua_pushnil(L);
 
136
    else
 
137
        lua_pushlightuserdata(L, (void *)data);
 
138
    lua_rawset(L, LUA_REGISTRYINDEX);
 
139
}
 
140
 
 
141
static void *getdata(lua_State *L, const char *key)
 
142
{
 
143
    void *ret = NULL;
 
144
    lua_pushliteral(L, "rpm_");
 
145
    lua_pushstring(L, key);
 
146
    lua_concat(L, 2);
 
147
    lua_rawget(L, LUA_REGISTRYINDEX);
 
148
    if (lua_islightuserdata(L, -1))
 
149
        ret = lua_touserdata(L, -1);
 
150
    lua_pop(L, 1);
 
151
    return ret;
 
152
}
 
153
 
 
154
void *rpmluaGetData(rpmlua _lua, const char *key)
 
155
{
 
156
    INITSTATE(_lua, lua);
 
157
    return getdata(lua->L, key);
 
158
}
 
159
 
 
160
void rpmluaPushPrintBuffer(rpmlua _lua)
 
161
{
 
162
    INITSTATE(_lua, lua);
 
163
    rpmluapb prbuf = xcalloc(1, sizeof(*prbuf));
 
164
    prbuf->buf = NULL;
 
165
    prbuf->alloced = 0;
 
166
    prbuf->used = 0;
 
167
    prbuf->next = lua->printbuf;
 
168
 
 
169
    lua->printbuf = prbuf;
 
170
}
 
171
 
 
172
char *rpmluaPopPrintBuffer(rpmlua _lua)
 
173
{
 
174
    INITSTATE(_lua, lua);
 
175
    rpmluapb prbuf = lua->printbuf;
 
176
    char *ret = NULL;
 
177
 
 
178
    if (prbuf) {
 
179
        ret = prbuf->buf;
 
180
        lua->printbuf = prbuf->next;
 
181
        free(prbuf);
 
182
    }
 
183
    
 
184
    return ret;
 
185
}
 
186
 
 
187
static int pushvar(lua_State *L, rpmluavType type, void *value)
 
188
{
 
189
    int ret = 0;
 
190
    switch (type) {
 
191
        case RPMLUAV_NIL:
 
192
            lua_pushnil(L);
 
193
            break;
 
194
        case RPMLUAV_STRING:
 
195
            lua_pushstring(L, *((char **)value));
 
196
            break;
 
197
        case RPMLUAV_NUMBER:
 
198
            lua_pushnumber(L, *((double *)value));
 
199
            break;
 
200
        default:
 
201
            ret = -1;
 
202
            break;
 
203
    }
 
204
    return ret;
 
205
}
 
206
 
 
207
void rpmluaSetVar(rpmlua _lua, rpmluav var)
 
208
{
 
209
    INITSTATE(_lua, lua);
 
210
    lua_State *L = lua->L;
 
211
    if (var->listmode && lua->pushsize > 0) {
 
212
        if (var->keyType != RPMLUAV_NUMBER || var->key.num == (double)0) {
 
213
            var->keyType = RPMLUAV_NUMBER;
 
214
            var->key.num = (double) luaL_getn(L, -1);
 
215
        }
 
216
        var->key.num++;
 
217
    }
 
218
    if (!var->listmode || lua->pushsize > 0) {
 
219
        if (lua->pushsize == 0)
 
220
            lua_pushglobaltable(L);
 
221
        if (pushvar(L, var->keyType, &var->key) != -1) {
 
222
            if (pushvar(L, var->valueType, &var->value) != -1)
 
223
                lua_rawset(L, -3);
 
224
            else
 
225
                lua_pop(L, 1);
 
226
        }
 
227
        if (lua->pushsize == 0)
 
228
            lua_pop(L, 1);
 
229
    }
 
230
}
 
231
 
 
232
static void popvar(lua_State *L, rpmluavType *type, void *value)
 
233
{
 
234
    switch (lua_type(L, -1)) {
 
235
    case LUA_TSTRING:
 
236
        *type = RPMLUAV_STRING;
 
237
        *((const char **)value) = lua_tostring(L, -1);
 
238
        break;
 
239
    case LUA_TNUMBER:
 
240
        *type = RPMLUAV_NUMBER;
 
241
        *((double *)value) = lua_tonumber(L, -1);
 
242
        break;
 
243
    default:
 
244
        *type = RPMLUAV_NIL;
 
245
        *((void **)value) = NULL;
 
246
        break;
 
247
    }
 
248
    lua_pop(L, 1);
 
249
}
 
250
 
 
251
void rpmluaGetVar(rpmlua _lua, rpmluav var)
 
252
{
 
253
    INITSTATE(_lua, lua);
 
254
    lua_State *L = lua->L;
 
255
    if (!var->listmode) {
 
256
        if (lua->pushsize == 0)
 
257
            lua_pushglobaltable(L);
 
258
        if (pushvar(L, var->keyType, &var->key) != -1) {
 
259
            lua_rawget(L, -2);
 
260
            popvar(L, &var->valueType, &var->value);
 
261
        }
 
262
        if (lua->pushsize == 0)
 
263
            lua_pop(L, 1);
 
264
    } else if (lua->pushsize > 0) {
 
265
        (void) pushvar(L, var->keyType, &var->key);
 
266
        if (lua_next(L, -2) != 0)
 
267
            popvar(L, &var->valueType, &var->value);
 
268
    }
 
269
}
 
270
 
 
271
#define FINDKEY_RETURN 0
 
272
#define FINDKEY_CREATE 1
 
273
#define FINDKEY_REMOVE 2
 
274
static int findkey(lua_State *L, int oper, const char *key, va_list va)
 
275
{
 
276
    char *buf;
 
277
    const char *s, *e;
 
278
    int ret = 0;
 
279
    int blen;
 
280
 
 
281
    blen = vsnprintf(NULL, 0, key, va);
 
282
    if (blen <= 0) {
 
283
        return -1;
 
284
    }
 
285
 
 
286
    buf = xmalloc(blen + 1);
 
287
    vsnprintf(buf, blen + 1, key, va);
 
288
 
 
289
    s = e = buf;
 
290
    lua_pushglobaltable(L);
 
291
    for (;;) {
 
292
        if (*e == '\0' || *e == '.') {
 
293
            if (e != s) {
 
294
                lua_pushlstring(L, s, e-s);
 
295
                switch (oper) {
 
296
                case FINDKEY_REMOVE:
 
297
                    if (*e == '\0') {
 
298
                        lua_pushnil(L);
 
299
                        lua_rawset(L, -3);
 
300
                        lua_pop(L, 1);
 
301
                        break;
 
302
                    }
 
303
                case FINDKEY_RETURN:
 
304
                    lua_rawget(L, -2);
 
305
                    lua_remove(L, -2);
 
306
                    break;
 
307
                case FINDKEY_CREATE:
 
308
                    lua_rawget(L, -2);
 
309
                    if (!lua_istable(L, -1)) {
 
310
                        lua_pop(L, 1);
 
311
                        lua_newtable(L);
 
312
                        lua_pushlstring(L, s, e-s);
 
313
                        lua_pushvalue(L, -2);
 
314
                        lua_rawset(L, -4);
 
315
                    }
 
316
                    lua_remove(L, -2);
 
317
                    break;
 
318
                }
 
319
            }
 
320
            if (*e == '\0')
 
321
                break;
 
322
            if (!lua_istable(L, -1)) {
 
323
                lua_pop(L, 1);
 
324
                ret = -1;
 
325
                break;
 
326
            }
 
327
            s = e+1;
 
328
        }
 
329
        e++;
 
330
    }
 
331
    free(buf);
 
332
 
 
333
    return ret;
 
334
}
 
335
 
 
336
void rpmluaDelVar(rpmlua _lua, const char *key, ...)
 
337
{
 
338
    INITSTATE(_lua, lua);
 
339
    va_list va;
 
340
    va_start(va, key);
 
341
    (void) findkey(lua->L, FINDKEY_REMOVE, key, va);
 
342
    va_end(va);
 
343
}
 
344
 
 
345
int rpmluaVarExists(rpmlua _lua, const char *key, ...)
 
346
{
 
347
    INITSTATE(_lua, lua);
 
348
    lua_State *L = lua->L;
 
349
    int ret = 0;
 
350
    va_list va;
 
351
    va_start(va, key);
 
352
    if (findkey(L, FINDKEY_RETURN, key, va) == 0) {
 
353
        if (!lua_isnil(L, -1))
 
354
            ret = 1;
 
355
        lua_pop(L, 1);
 
356
    }
 
357
    va_end(va);
 
358
    return ret;
 
359
}
 
360
 
 
361
void rpmluaPushTable(rpmlua _lua, const char *key, ...)
 
362
{
 
363
    INITSTATE(_lua, lua);
 
364
    va_list va;
 
365
    va_start(va, key);
 
366
    (void) findkey(lua->L, FINDKEY_CREATE, key, va);
 
367
    lua->pushsize++;
 
368
    va_end(va);
 
369
}
 
370
 
 
371
void rpmluaPop(rpmlua _lua)
 
372
{
 
373
    INITSTATE(_lua, lua);
 
374
    assert(lua->pushsize > 0);
 
375
    lua->pushsize--;
 
376
    lua_pop(lua->L, 1);
 
377
}
 
378
 
 
379
rpmluav rpmluavNew(void)
 
380
{
 
381
    rpmluav var = (rpmluav) xcalloc(1, sizeof(*var));
 
382
    return var;
 
383
}
 
384
 
 
385
rpmluav rpmluavFree(rpmluav var)
 
386
{
 
387
    free(var);
 
388
    return NULL;
 
389
}
 
390
 
 
391
void rpmluavSetListMode(rpmluav var, int flag)
 
392
{
 
393
    var->listmode = flag;
 
394
    var->keyType = RPMLUAV_NIL;
 
395
}
 
396
 
 
397
void rpmluavSetKey(rpmluav var, rpmluavType type, const void *value)
 
398
{
 
399
    var->keyType = type;
 
400
    switch (type) {
 
401
        case RPMLUAV_NUMBER:
 
402
            var->key.num = *((double *)value);
 
403
            break;
 
404
        case RPMLUAV_STRING:
 
405
            var->key.str = (char *)value;
 
406
            break;
 
407
        default:
 
408
            break;
 
409
    }
 
410
}
 
411
 
 
412
void rpmluavSetValue(rpmluav var, rpmluavType type, const void *value)
 
413
{
 
414
    var->valueType = type;
 
415
    switch (type) {
 
416
        case RPMLUAV_NUMBER:
 
417
            var->value.num = *((const double *)value);
 
418
            break;
 
419
        case RPMLUAV_STRING:
 
420
            var->value.str = (const char *)value;
 
421
            break;
 
422
        default:
 
423
            break;
 
424
    }
 
425
}
 
426
 
 
427
void rpmluavGetKey(rpmluav var, rpmluavType *type, void **value)
 
428
{
 
429
    *type = var->keyType;
 
430
    switch (var->keyType) {
 
431
        case RPMLUAV_NUMBER:
 
432
            *((double **)value) = &var->key.num;
 
433
            break;
 
434
        case RPMLUAV_STRING:
 
435
            *((const char **)value) = var->key.str;
 
436
            break;
 
437
        default:
 
438
            break;
 
439
    }
 
440
}
 
441
 
 
442
void rpmluavGetValue(rpmluav var, rpmluavType *type, void **value)
 
443
{
 
444
    *type = var->valueType;
 
445
    switch (var->valueType) {
 
446
        case RPMLUAV_NUMBER:
 
447
            *((double **)value) = &var->value.num;
 
448
            break;
 
449
        case RPMLUAV_STRING:
 
450
            *((const char **)value) = var->value.str;
 
451
            break;
 
452
        default:
 
453
            break;
 
454
    }
 
455
}
 
456
 
 
457
void rpmluavSetKeyNum(rpmluav var, double value)
 
458
{
 
459
    rpmluavSetKey(var, RPMLUAV_NUMBER, &value);
 
460
}
 
461
 
 
462
void rpmluavSetValueNum(rpmluav var, double value)
 
463
{
 
464
    rpmluavSetValue(var, RPMLUAV_NUMBER, &value);
 
465
}
 
466
 
 
467
double rpmluavGetKeyNum(rpmluav var)
 
468
{
 
469
    rpmluavType type;
 
470
    void *value;
 
471
    rpmluavGetKey(var, &type, &value);
 
472
    if (type == RPMLUAV_NUMBER)
 
473
        return *((double *)value);
 
474
    return (double) 0;
 
475
}
 
476
 
 
477
double rpmluavGetValueNum(rpmluav var)
 
478
{
 
479
    rpmluavType type;
 
480
    void *value;
 
481
    rpmluavGetValue(var, &type, &value);
 
482
    if (type == RPMLUAV_NUMBER)
 
483
        return *((double *)value);
 
484
    return (double) 0;
 
485
}
 
486
 
 
487
int rpmluavKeyIsNum(rpmluav var)
 
488
{
 
489
    return (var->keyType == RPMLUAV_NUMBER) ? 1 : 0;
 
490
}
 
491
 
 
492
int rpmluavValueIsNum(rpmluav var)
 
493
{
 
494
    return (var->valueType == RPMLUAV_NUMBER) ? 1 : 0;
 
495
}
 
496
 
 
497
int rpmluaCheckScript(rpmlua _lua, const char *script, const char *name)
 
498
{
 
499
    INITSTATE(_lua, lua);
 
500
    lua_State *L = lua->L;
 
501
    int ret = 0;
 
502
    if (name == NULL)
 
503
        name = "<lua>";
 
504
    if (luaL_loadbuffer(L, script, strlen(script), name) != 0) {
 
505
        rpmlog(RPMLOG_ERR,
 
506
                _("invalid syntax in lua scriptlet: %s\n"),
 
507
                  lua_tostring(L, -1));
 
508
        ret = -1;
 
509
    }
 
510
    lua_pop(L, 1); /* Error or chunk. */
 
511
    return ret;
 
512
}
 
513
 
 
514
int rpmluaRunScript(rpmlua _lua, const char *script, const char *name)
 
515
{
 
516
    INITSTATE(_lua, lua);
 
517
    lua_State *L = lua->L;
 
518
    int ret = 0;
 
519
    if (name == NULL)
 
520
        name = "<lua>";
 
521
    if (luaL_loadbuffer(L, script, strlen(script), name) != 0) {
 
522
        rpmlog(RPMLOG_ERR, _("invalid syntax in lua script: %s\n"),
 
523
                 lua_tostring(L, -1));
 
524
        lua_pop(L, 1);
 
525
        ret = -1;
 
526
    } else if (lua_pcall(L, 0, 0, 0) != 0) {
 
527
        rpmlog(RPMLOG_ERR, _("lua script failed: %s\n"),
 
528
                 lua_tostring(L, -1));
 
529
        lua_pop(L, 1);
 
530
        ret = -1;
 
531
    }
 
532
    return ret;
 
533
}
 
534
 
 
535
int rpmluaRunScriptFile(rpmlua _lua, const char *filename)
 
536
{
 
537
    INITSTATE(_lua, lua);
 
538
    lua_State *L = lua->L;
 
539
    int ret = 0;
 
540
    if (luaL_loadfile(L, filename) != 0) {
 
541
        rpmlog(RPMLOG_ERR, _("invalid syntax in lua file: %s\n"),
 
542
                 lua_tostring(L, -1));
 
543
        lua_pop(L, 1);
 
544
        ret = -1;
 
545
    } else if (lua_pcall(L, 0, 0, 0) != 0) {
 
546
        rpmlog(RPMLOG_ERR, _("lua script failed: %s\n"),
 
547
                 lua_tostring(L, -1));
 
548
        lua_pop(L, 1);
 
549
        ret = -1;
 
550
    }
 
551
    return ret;
 
552
}
 
553
 
 
554
/* From lua.c */
 
555
static int rpmluaReadline(lua_State *L, const char *prompt)
 
556
{
 
557
   static char buffer[1024];
 
558
   if (prompt) {
 
559
      (void) fputs(prompt, stdout);
 
560
      (void) fflush(stdout);
 
561
   }
 
562
   if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
 
563
      return 0;  /* read fails */
 
564
   } else {
 
565
      lua_pushstring(L, buffer);
 
566
      return 1;
 
567
   }
 
568
}
 
569
 
 
570
/* Based on lua.c */
 
571
static void _rpmluaInteractive(lua_State *L)
 
572
{
 
573
   (void) fputs("\n", stdout);
 
574
   printf("RPM Interactive %s Interpreter\n", LUA_VERSION);
 
575
   for (;;) {
 
576
      int rc = 0;
 
577
 
 
578
      if (rpmluaReadline(L, "> ") == 0)
 
579
         break;
 
580
      if (lua_tostring(L, -1)[0] == '=') {
 
581
         (void) lua_pushfstring(L, "print(%s)", lua_tostring(L, -1)+1);
 
582
         lua_remove(L, -2);
 
583
      }
 
584
      for (;;) {
 
585
         rc = luaL_loadbuffer(L, lua_tostring(L, -1),
 
586
                              lua_strlen(L, -1), "<lua>");
 
587
         if (rc == LUA_ERRSYNTAX &&
 
588
             strstr(lua_tostring(L, -1), "near `<eof>'") != NULL) {
 
589
            if (rpmluaReadline(L, ">> ") == 0)
 
590
               break;
 
591
            lua_remove(L, -2); /* Remove error */
 
592
            lua_concat(L, 2);
 
593
            continue;
 
594
         }
 
595
         break;
 
596
      }
 
597
      if (rc == 0)
 
598
         rc = lua_pcall(L, 0, 0, 0);
 
599
      if (rc != 0) {
 
600
         fprintf(stderr, "%s\n", lua_tostring(L, -1));
 
601
         lua_pop(L, 1);
 
602
      }
 
603
      lua_pop(L, 1); /* Remove line */
 
604
   }
 
605
   (void) fputs("\n", stdout);
 
606
}
 
607
 
 
608
void rpmluaInteractive(rpmlua _lua)
 
609
{
 
610
    INITSTATE(_lua, lua);
 
611
    _rpmluaInteractive(lua->L);
 
612
}
 
613
 
 
614
/* ------------------------------------------------------------------ */
 
615
/* Lua API */
 
616
 
 
617
static int rpm_b64encode(lua_State *L)
 
618
{
 
619
    const char *str = luaL_checkstring(L, 1);
 
620
    size_t len = lua_strlen(L, 1);
 
621
    int linelen = -1;
 
622
    if (lua_gettop(L) == 2)
 
623
        linelen = luaL_checkinteger(L, 2);
 
624
    if (str && len) {
 
625
        char *data = rpmBase64Encode(str, len, linelen);
 
626
        lua_pushstring(L, data);
 
627
        free(data);
 
628
    }
 
629
    return 1;
 
630
}
 
631
 
 
632
static int rpm_b64decode(lua_State *L)
 
633
{
 
634
    const char *str = luaL_checkstring(L, 1);
 
635
    if (str) {
 
636
        void *data = NULL;
 
637
        size_t len = 0;
 
638
        if (rpmBase64Decode(str, &data, &len) == 0) {
 
639
            lua_pushlstring(L, data, len);
 
640
        } else {
 
641
            lua_pushnil(L);
 
642
        }
 
643
        free(data);
 
644
    }
 
645
    return 1;
 
646
}
 
647
 
 
648
static int rpm_expand(lua_State *L)
 
649
{
 
650
    const char *str = luaL_checkstring(L, 1);
 
651
    char *val = rpmExpand(str, NULL);
 
652
    lua_pushstring(L, val);
 
653
    free(val);
 
654
    return 1;
 
655
}
 
656
 
 
657
static int rpm_define(lua_State *L)
 
658
{
 
659
    const char *str = luaL_checkstring(L, 1);
 
660
    (void) rpmDefineMacro(NULL, str, 0);
 
661
    return 0;
 
662
}
 
663
 
 
664
static int rpm_interactive(lua_State *L)
 
665
{
 
666
    _rpmluaInteractive(L);
 
667
    return 0;
 
668
}
 
669
 
 
670
typedef struct rpmluaHookData_s {
 
671
    lua_State *L;
 
672
    int funcRef;
 
673
    int dataRef;
 
674
} * rpmluaHookData;
 
675
 
 
676
static int rpmluaHookWrapper(rpmhookArgs args, void *data)
 
677
{
 
678
    rpmluaHookData hookdata = (rpmluaHookData)data;
 
679
    lua_State *L = hookdata->L;
 
680
    int ret = 0;
 
681
    int i;
 
682
    lua_rawgeti(L, LUA_REGISTRYINDEX, hookdata->funcRef);
 
683
    lua_newtable(L);
 
684
    for (i = 0; i != args->argc; i++) {
 
685
        switch (args->argt[i]) {
 
686
            case 's':
 
687
                lua_pushstring(L, args->argv[i].s);
 
688
                lua_rawseti(L, -2, i+1);
 
689
                break;
 
690
            case 'i':
 
691
                lua_pushnumber(L, (lua_Number)args->argv[i].i);
 
692
                lua_rawseti(L, -2, i+1);
 
693
                break;
 
694
            case 'f':
 
695
                lua_pushnumber(L, (lua_Number)args->argv[i].f);
 
696
                lua_rawseti(L, -2, i+1);
 
697
                break;
 
698
            case 'p':
 
699
                lua_pushlightuserdata(L, args->argv[i].p);
 
700
                lua_rawseti(L, -2, i+1);
 
701
                break;
 
702
            default:
 
703
                (void) luaL_error(L, "unsupported type '%c' as "
 
704
                              "a hook argument\n", args->argt[i]);
 
705
                break;
 
706
        }
 
707
    }
 
708
    if (lua_pcall(L, 1, 1, 0) != 0) {
 
709
        rpmlog(RPMLOG_ERR, _("lua hook failed: %s\n"),
 
710
                 lua_tostring(L, -1));
 
711
        lua_pop(L, 1);
 
712
    } else {
 
713
        if (lua_isnumber(L, -1))
 
714
            ret = (int)lua_tonumber(L, -1);
 
715
        lua_pop(L, 1);
 
716
    }
 
717
    return ret;
 
718
}
 
719
 
 
720
static int rpm_register(lua_State *L)
 
721
{
 
722
    if (!lua_isstring(L, 1)) {
 
723
        (void) luaL_argerror(L, 1, "hook name expected");
 
724
    } else if (!lua_isfunction(L, 2)) {
 
725
        (void) luaL_argerror(L, 2, "function expected");
 
726
    } else {
 
727
        rpmluaHookData hookdata =
 
728
            lua_newuserdata(L, sizeof(struct rpmluaHookData_s));
 
729
        lua_pushvalue(L, -1);
 
730
        hookdata->dataRef = luaL_ref(L, LUA_REGISTRYINDEX);
 
731
        lua_pushvalue(L, 2);
 
732
        hookdata->funcRef = luaL_ref(L, LUA_REGISTRYINDEX);
 
733
        hookdata->L = L;
 
734
        rpmhookRegister(lua_tostring(L, 1), rpmluaHookWrapper, hookdata);
 
735
        return 1;
 
736
    }
 
737
    return 0;
 
738
}
 
739
 
 
740
static int rpm_unregister(lua_State *L)
 
741
{
 
742
    if (!lua_isstring(L, 1)) {
 
743
        (void) luaL_argerror(L, 1, "hook name expected");
 
744
    } else if (!lua_isuserdata(L, 2)) {
 
745
        (void) luaL_argerror(L, 2, "hook information expected");
 
746
    } else {
 
747
        rpmluaHookData hookdata = (rpmluaHookData)lua_touserdata(L, 2);
 
748
        luaL_unref(L, LUA_REGISTRYINDEX, hookdata->funcRef);
 
749
        luaL_unref(L, LUA_REGISTRYINDEX, hookdata->dataRef);
 
750
        rpmhookUnregister(lua_tostring(L, 1), rpmluaHookWrapper, hookdata);
 
751
    }
 
752
    return 0;
 
753
}
 
754
 
 
755
static int rpm_call(lua_State *L)
 
756
{
 
757
    if (!lua_isstring(L, 1)) {
 
758
        (void) luaL_argerror(L, 1, "hook name expected");
 
759
    } else {
 
760
        rpmhookArgs args = rpmhookArgsNew(lua_gettop(L)-1);
 
761
        const char *name = lua_tostring(L, 1);
 
762
        char *argt = (char *)xmalloc(args->argc+1);
 
763
        int i;
 
764
        for (i = 0; i != args->argc; i++) {
 
765
            switch (lua_type(L, i+1)) {
 
766
                case LUA_TNIL:
 
767
                    argt[i] = 'p';
 
768
                    args->argv[i].p = NULL;
 
769
                    break;
 
770
                case LUA_TNUMBER: {
 
771
                    float f = (float)lua_tonumber(L, i+1);
 
772
                    if (f == (int)f) {
 
773
                        argt[i] = 'i';
 
774
                        args->argv[i].i = (int)f;
 
775
                    } else {
 
776
                        argt[i] = 'f';
 
777
                        args->argv[i].f = f;
 
778
                    }
 
779
                }   break;
 
780
                case LUA_TSTRING:
 
781
                    argt[i] = 's';
 
782
                    args->argv[i].s = lua_tostring(L, i+1);
 
783
                    break;
 
784
                case LUA_TUSERDATA:
 
785
                case LUA_TLIGHTUSERDATA:
 
786
                    argt[i] = 'p';
 
787
                    args->argv[i].p = lua_touserdata(L, i+1);
 
788
                    break;
 
789
                default:
 
790
                    (void) luaL_error(L, "unsupported Lua type passed to hook");
 
791
                    argt[i] = 'p';
 
792
                    args->argv[i].p = NULL;
 
793
                    break;
 
794
            }
 
795
        }
 
796
        args->argt = argt;
 
797
        rpmhookCallArgs(name, args);
 
798
        free(argt);
 
799
        (void) rpmhookArgsFree(args);
 
800
    }
 
801
    return 0;
 
802
}
 
803
 
 
804
/* Based on luaB_print. */
 
805
static int rpm_print (lua_State *L)
 
806
{
 
807
    rpmlua lua = (rpmlua)getdata(L, "lua");
 
808
    int n = lua_gettop(L);  /* number of arguments */
 
809
    int i;
 
810
    if (!lua) return 0;
 
811
    lua_getglobal(L, "tostring");
 
812
    for (i = 1; i <= n; i++) {
 
813
        const char *s;
 
814
        lua_pushvalue(L, -1);  /* function to be called */
 
815
        lua_pushvalue(L, i);   /* value to print */
 
816
        lua_call(L, 1, 1);
 
817
        s = lua_tostring(L, -1);  /* get result */
 
818
        if (s == NULL)
 
819
            return luaL_error(L, "`tostring' must return a string to `print'");
 
820
        if (lua->printbuf) {
 
821
            rpmluapb prbuf = lua->printbuf;
 
822
            int sl = lua_strlen(L, -1);
 
823
            if (prbuf->used+sl+1 > prbuf->alloced) {
 
824
                prbuf->alloced += sl+512;
 
825
                prbuf->buf = xrealloc(prbuf->buf, prbuf->alloced);
 
826
            }
 
827
            if (i > 1)
 
828
                prbuf->buf[prbuf->used++] = '\t';
 
829
            memcpy(prbuf->buf+prbuf->used, s, sl+1);
 
830
            prbuf->used += sl;
 
831
        } else {
 
832
            if (i > 1)
 
833
                (void) fputs("\t", stdout);
 
834
            (void) fputs(s, stdout);
 
835
        }
 
836
        lua_pop(L, 1);  /* pop result */
 
837
    }
 
838
    if (!lua->printbuf) {
 
839
        (void) fputs("\n", stdout);
 
840
    } else {
 
841
        rpmluapb prbuf = lua->printbuf;
 
842
        if (prbuf->used+1 > prbuf->alloced) {
 
843
            prbuf->alloced += 512;
 
844
            prbuf->buf = xrealloc(prbuf->buf, prbuf->alloced);
 
845
        }
 
846
        prbuf->buf[prbuf->used] = '\0';
 
847
    }
 
848
    return 0;
 
849
}
 
850
 
 
851
static const luaL_Reg rpmlib[] = {
 
852
    {"b64encode", rpm_b64encode},
 
853
    {"b64decode", rpm_b64decode},
 
854
    {"expand", rpm_expand},
 
855
    {"define", rpm_define},
 
856
    {"register", rpm_register},
 
857
    {"unregister", rpm_unregister},
 
858
    {"call", rpm_call},
 
859
    {"interactive", rpm_interactive},
 
860
    {NULL, NULL}
 
861
};
 
862
 
 
863
static int luaopen_rpm(lua_State *L)
 
864
{
 
865
    lua_pushglobaltable(L);
 
866
    luaL_openlib(L, "rpm", rpmlib, 0);
 
867
    return 0;
 
868
}
 
869
#endif  /* WITH_LUA */
 
870