Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/stand/liblua/lutils.c
34680 views
1
/*-
2
* Copyright (c) 2014 Pedro Souza <[email protected]>
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
*
14
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
* SUCH DAMAGE.
25
*
26
*/
27
28
#include <sys/param.h>
29
30
#include "lua.h"
31
#include "lauxlib.h"
32
#include "lstd.h"
33
#include "lutils.h"
34
#include "bootstrap.h"
35
36
/*
37
* Like loader.perform, except args are passed already parsed
38
* on the stack.
39
*/
40
static int
41
lua_command(lua_State *L)
42
{
43
int i;
44
int res = 1;
45
int argc = lua_gettop(L);
46
char **argv;
47
48
argv = malloc(sizeof(char *) * (argc + 1));
49
if (argv == NULL)
50
return 0;
51
for (i = 0; i < argc; i++)
52
argv[i] = (char *)(intptr_t)luaL_checkstring(L, i + 1);
53
argv[argc] = NULL;
54
res = interp_builtin_cmd(argc, argv);
55
free(argv);
56
lua_pushinteger(L, res);
57
58
return 1;
59
}
60
61
static int
62
lua_has_command(lua_State *L)
63
{
64
const char *cmd;
65
66
cmd = luaL_checkstring(L, 1);
67
if (interp_has_builtin_cmd(cmd)) {
68
lua_pushboolean(L, 1);
69
return 1;
70
}
71
72
lua_pushnil(L);
73
lua_pushstring(L, "Builtin command not found");
74
return 2;
75
}
76
77
static int
78
lua_has_feature(lua_State *L)
79
{
80
const char *feature;
81
char *msg;
82
83
feature = luaL_checkstring(L, 1);
84
85
if (feature_name_is_enabled(feature)) {
86
lua_pushboolean(L, 1);
87
return 1;
88
}
89
90
lua_pushnil(L);
91
lua_pushstring(L, "Feature not enabled");
92
return 2;
93
}
94
95
96
static int
97
lua_perform(lua_State *L)
98
{
99
int argc;
100
char **argv;
101
int res = 1;
102
103
if (parse(&argc, &argv, luaL_checkstring(L, 1)) == 0) {
104
res = interp_builtin_cmd(argc, argv);
105
free(argv);
106
}
107
lua_pushinteger(L, res);
108
109
return 1;
110
}
111
112
static int
113
lua_exit(lua_State *L)
114
{
115
exit(luaL_checkinteger(L, 1));
116
return 0;
117
}
118
119
static int
120
lua_command_error(lua_State *L)
121
{
122
123
lua_pushstring(L, command_errbuf);
124
return 1;
125
}
126
127
/*
128
* Accepts a space-delimited loader command and runs it through the standard
129
* loader parsing, as if it were executed at the loader prompt by the user.
130
*/
131
static int
132
lua_interpret(lua_State *L)
133
{
134
const char *interp_string;
135
136
if (lua_gettop(L) != 1) {
137
lua_pushnil(L);
138
return 1;
139
}
140
141
interp_string = luaL_checkstring(L, 1);
142
lua_pushinteger(L, interp_run(interp_string));
143
return 1;
144
}
145
146
static int
147
lua_parse(lua_State *L)
148
{
149
int argc, nargc;
150
char **argv;
151
152
if (parse(&argc, &argv, luaL_checkstring(L, 1)) == 0) {
153
for (nargc = 0; nargc < argc; ++nargc) {
154
lua_pushstring(L, argv[nargc]);
155
}
156
free(argv);
157
return nargc;
158
}
159
160
lua_pushnil(L);
161
return 1;
162
}
163
164
static int
165
lua_getchar(lua_State *L)
166
{
167
168
lua_pushinteger(L, getchar());
169
return 1;
170
}
171
172
static int
173
lua_ischar(lua_State *L)
174
{
175
176
lua_pushboolean(L, ischar());
177
return 1;
178
}
179
180
static int
181
lua_gets(lua_State *L)
182
{
183
char buf[129];
184
185
ngets(buf, 128);
186
lua_pushstring(L, buf);
187
return 1;
188
}
189
190
static int
191
lua_time(lua_State *L)
192
{
193
194
lua_pushinteger(L, time(NULL));
195
return 1;
196
}
197
198
static int
199
lua_delay(lua_State *L)
200
{
201
202
delay((int)luaL_checknumber(L, 1));
203
return 0;
204
}
205
206
static int
207
lua_getenv(lua_State *L)
208
{
209
lua_pushstring(L, getenv(luaL_checkstring(L, 1)));
210
211
return 1;
212
}
213
214
static int
215
lua_setenv(lua_State *L)
216
{
217
const char *key, *val;
218
219
key = luaL_checkstring(L, 1);
220
val = luaL_checkstring(L, 2);
221
lua_pushinteger(L, setenv(key, val, 1));
222
223
return 1;
224
}
225
226
static int
227
lua_unsetenv(lua_State *L)
228
{
229
const char *ev;
230
231
ev = luaL_checkstring(L, 1);
232
lua_pushinteger(L, unsetenv(ev));
233
234
return 1;
235
}
236
237
static int
238
lua_printc(lua_State *L)
239
{
240
ssize_t cur, l;
241
const char *s = luaL_checklstring(L, 1, &l);
242
243
for (cur = 0; cur < l; ++cur)
244
putchar((unsigned char)*(s++));
245
246
return 1;
247
}
248
249
static int
250
lua_openfile(lua_State *L)
251
{
252
const char *mode, *str;
253
int nargs;
254
255
nargs = lua_gettop(L);
256
if (nargs < 1 || nargs > 2) {
257
lua_pushnil(L);
258
return 1;
259
}
260
str = lua_tostring(L, 1);
261
mode = "r";
262
if (nargs > 1) {
263
mode = lua_tostring(L, 2);
264
if (mode == NULL) {
265
lua_pushnil(L);
266
return 1;
267
}
268
}
269
FILE * f = fopen(str, mode);
270
if (f != NULL) {
271
FILE ** ptr = (FILE**)lua_newuserdata(L, sizeof(FILE**));
272
*ptr = f;
273
} else
274
lua_pushnil(L);
275
return 1;
276
}
277
278
static int
279
lua_closefile(lua_State *L)
280
{
281
FILE ** f;
282
if (lua_gettop(L) != 1) {
283
lua_pushboolean(L, 0);
284
return 1;
285
}
286
287
f = (FILE**)lua_touserdata(L, 1);
288
if (f != NULL && *f != NULL) {
289
lua_pushboolean(L, fclose(*f) == 0 ? 1 : 0);
290
*f = NULL;
291
} else
292
lua_pushboolean(L, 0);
293
294
return 1;
295
}
296
297
static int
298
lua_readfile(lua_State *L)
299
{
300
FILE **f;
301
size_t size, r;
302
char * buf;
303
304
if (lua_gettop(L) < 1 || lua_gettop(L) > 2) {
305
lua_pushnil(L);
306
lua_pushinteger(L, 0);
307
return 2;
308
}
309
310
f = (FILE**)lua_touserdata(L, 1);
311
312
if (f == NULL || *f == NULL) {
313
lua_pushnil(L);
314
lua_pushinteger(L, 0);
315
return 2;
316
}
317
318
if (lua_gettop(L) == 2)
319
size = (size_t)lua_tonumber(L, 2);
320
else
321
size = (*f)->size;
322
323
324
buf = (char*)malloc(size);
325
r = fread(buf, 1, size, *f);
326
lua_pushlstring(L, buf, r);
327
free(buf);
328
lua_pushinteger(L, r);
329
330
return 2;
331
}
332
333
/*
334
* Implements io.write(file, ...)
335
* Any number of string and number arguments may be passed to it,
336
* and it will return the number of bytes written, or nil, an error string, and
337
* the errno.
338
*/
339
static int
340
lua_writefile(lua_State *L)
341
{
342
FILE **f;
343
const char *buf;
344
int i, nargs;
345
size_t bufsz, w, wrsz;
346
347
buf = NULL;
348
bufsz = 0;
349
w = 0;
350
wrsz = 0;
351
nargs = lua_gettop(L);
352
if (nargs < 2) {
353
errno = EINVAL;
354
return luaL_fileresult(L, 0, NULL);
355
}
356
357
f = (FILE**)lua_touserdata(L, 1);
358
359
if (f == NULL || *f == NULL) {
360
errno = EINVAL;
361
return luaL_fileresult(L, 0, NULL);
362
}
363
364
/* Do a validation pass first */
365
for (i = 0; i < nargs - 1; i++) {
366
/*
367
* With Lua's API, lua_isstring really checks if the argument
368
* is a string or a number. The latter will be implicitly
369
* converted to a string by our later call to lua_tolstring.
370
*/
371
if (!lua_isstring(L, i + 2)) {
372
errno = EINVAL;
373
return luaL_fileresult(L, 0, NULL);
374
}
375
}
376
for (i = 0; i < nargs - 1; i++) {
377
/* We've already validated; there's no chance of failure */
378
buf = lua_tolstring(L, i + 2, &bufsz);
379
wrsz = fwrite(buf, 1, bufsz, *f);
380
if (wrsz < bufsz)
381
return luaL_fileresult(L, 0, NULL);
382
w += wrsz;
383
}
384
lua_pushinteger(L, w);
385
return 1;
386
}
387
388
#define REG_SIMPLE(n) { #n, lua_ ## n }
389
static const struct luaL_Reg loaderlib[] = {
390
REG_SIMPLE(command),
391
REG_SIMPLE(command_error),
392
REG_SIMPLE(delay),
393
REG_SIMPLE(exit),
394
REG_SIMPLE(getenv),
395
REG_SIMPLE(has_command),
396
REG_SIMPLE(has_feature),
397
REG_SIMPLE(interpret),
398
REG_SIMPLE(parse),
399
REG_SIMPLE(perform),
400
REG_SIMPLE(printc), /* Also registered as the global 'printc' */
401
REG_SIMPLE(setenv),
402
REG_SIMPLE(time),
403
REG_SIMPLE(unsetenv),
404
{ NULL, NULL },
405
};
406
407
static const struct luaL_Reg iolib[] = {
408
{ "close", lua_closefile },
409
REG_SIMPLE(getchar),
410
REG_SIMPLE(gets),
411
REG_SIMPLE(ischar),
412
{ "open", lua_openfile },
413
{ "read", lua_readfile },
414
{ "write", lua_writefile },
415
{ NULL, NULL },
416
};
417
#undef REG_SIMPLE
418
419
static void
420
lua_add_feature(void *cookie, const char *name, const char *desc, bool enabled)
421
{
422
lua_State *L = cookie;
423
424
/*
425
* The feature table consists solely of features that are enabled, and
426
* their associated descriptions for debugging purposes.
427
*/
428
lua_pushstring(L, desc);
429
lua_setfield(L, -2, name);
430
}
431
432
static void
433
lua_add_features(lua_State *L)
434
{
435
436
lua_newtable(L);
437
feature_iter(&lua_add_feature, L);
438
439
/*
440
* We should still have just the table on the stack after we're done
441
* iterating.
442
*/
443
lua_setfield(L, -2, "features");
444
}
445
446
int
447
luaopen_loader(lua_State *L)
448
{
449
luaL_newlib(L, loaderlib);
450
/* Add loader.machine and loader.machine_arch properties */
451
lua_pushstring(L, MACHINE);
452
lua_setfield(L, -2, "machine");
453
lua_pushstring(L, MACHINE_ARCH);
454
lua_setfield(L, -2, "machine_arch");
455
lua_pushstring(L, LUA_PATH);
456
lua_setfield(L, -2, "lua_path");
457
lua_pushinteger(L, bootprog_rev);
458
lua_setfield(L, -2, "version");
459
lua_pushinteger(L, CMD_OK);
460
lua_setfield(L, -2, "CMD_OK");
461
lua_pushinteger(L, CMD_WARN);
462
lua_setfield(L, -2, "CMD_WARN");
463
lua_pushinteger(L, CMD_ERROR);
464
lua_setfield(L, -2, "CMD_ERROR");
465
lua_pushinteger(L, CMD_CRIT);
466
lua_setfield(L, -2, "CMD_CRIT");
467
lua_pushinteger(L, CMD_FATAL);
468
lua_setfield(L, -2, "CMD_FATAL");
469
lua_add_features(L);
470
/* Set global printc to loader.printc */
471
lua_register(L, "printc", lua_printc);
472
return 1;
473
}
474
475
int
476
luaopen_io(lua_State *L)
477
{
478
luaL_newlib(L, iolib);
479
return 1;
480
}
481
482