]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/liblua/lutils.c
zfs: merge openzfs/zfs@9198de8f1
[FreeBSD/FreeBSD.git] / stand / liblua / lutils.c
1 /*-
2  * Copyright (c) 2014 Pedro Souza <pedrosouza@freebsd.org>
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/cdefs.h>
29 #include <sys/param.h>
30
31 #include "lua.h"
32 #include "lauxlib.h"
33 #include "lstd.h"
34 #include "lutils.h"
35 #include "bootstrap.h"
36 #include <gfx_fb.h>
37 #include <pnglite.h>
38
39 /*
40  * Like loader.perform, except args are passed already parsed
41  * on the stack.
42  */
43 static int
44 lua_command(lua_State *L)
45 {
46         int     i;
47         int     res = 1;
48         int     argc = lua_gettop(L);
49         char    **argv;
50
51         argv = malloc(sizeof(char *) * (argc + 1));
52         if (argv == NULL)
53                 return 0;
54         for (i = 0; i < argc; i++)
55                 argv[i] = (char *)(intptr_t)luaL_checkstring(L, i + 1);
56         argv[argc] = NULL;
57         res = interp_builtin_cmd(argc, argv);
58         free(argv);
59         lua_pushinteger(L, res);
60
61         return 1;
62 }
63
64 static int
65 lua_has_command(lua_State *L)
66 {
67         const char      *cmd;
68
69         if (lua_gettop(L) != 1) {
70                 lua_pushnil(L);
71                 return 1;
72         }
73         cmd = luaL_checkstring(L, 1);
74         lua_pushinteger(L, interp_has_builtin_cmd(cmd));
75
76         return 1;
77 }
78
79 static int
80 lua_perform(lua_State *L)
81 {
82         int     argc;
83         char    **argv;
84         int     res = 1;
85
86         if (parse(&argc, &argv, luaL_checkstring(L, 1)) == 0) {
87                 res = interp_builtin_cmd(argc, argv);
88                 free(argv);
89         }
90         lua_pushinteger(L, res);
91
92         return 1;
93 }
94
95 static int
96 lua_command_error(lua_State *L)
97 {
98
99         lua_pushstring(L, command_errbuf);
100         return 1;
101 }
102
103 /*
104  * Accepts a space-delimited loader command and runs it through the standard
105  * loader parsing, as if it were executed at the loader prompt by the user.
106  */
107 static int
108 lua_interpret(lua_State *L)
109 {
110         const char      *interp_string;
111
112         if (lua_gettop(L) != 1) {
113                 lua_pushnil(L);
114                 return 1;
115         }
116
117         interp_string = luaL_checkstring(L, 1);
118         lua_pushinteger(L, interp_run(interp_string));
119         return 1;
120 }
121
122 static int
123 lua_parse(lua_State *L)
124 {
125         int     argc, nargc;
126         char    **argv;
127
128         if (parse(&argc, &argv, luaL_checkstring(L, 1)) == 0) {
129                 for (nargc = 0; nargc < argc; ++nargc) {
130                         lua_pushstring(L, argv[nargc]);
131                 }
132                 free(argv);
133                 return nargc;
134         }
135
136         lua_pushnil(L);
137         return 1;
138 }
139
140 static int
141 lua_getchar(lua_State *L)
142 {
143
144         lua_pushinteger(L, getchar());
145         return 1;
146 }
147
148 static int
149 lua_ischar(lua_State *L)
150 {
151
152         lua_pushboolean(L, ischar());
153         return 1;
154 }
155
156 static int
157 lua_gets(lua_State *L)
158 {
159         char    buf[129];
160
161         ngets(buf, 128);
162         lua_pushstring(L, buf);
163         return 1;
164 }
165
166 static int
167 lua_time(lua_State *L)
168 {
169
170         lua_pushinteger(L, time(NULL));
171         return 1;
172 }
173
174 static int
175 lua_delay(lua_State *L)
176 {
177
178         delay((int)luaL_checknumber(L, 1));
179         return 0;
180 }
181
182 static int
183 lua_getenv(lua_State *L)
184 {
185         lua_pushstring(L, getenv(luaL_checkstring(L, 1)));
186
187         return 1;
188 }
189
190 static int
191 lua_setenv(lua_State *L)
192 {
193         const char *key, *val;
194
195         key = luaL_checkstring(L, 1);
196         val = luaL_checkstring(L, 2);
197         lua_pushinteger(L, setenv(key, val, 1));
198
199         return 1;
200 }
201
202 static int
203 lua_unsetenv(lua_State *L)
204 {
205         const char      *ev;
206
207         ev = luaL_checkstring(L, 1);
208         lua_pushinteger(L, unsetenv(ev));
209
210         return 1;
211 }
212
213 static int
214 lua_printc(lua_State *L)
215 {
216         ssize_t cur, l;
217         const char *s = luaL_checklstring(L, 1, &l);
218
219         for (cur = 0; cur < l; ++cur)
220                 putchar((unsigned char)*(s++));
221
222         return 1;
223 }
224
225 static int
226 lua_openfile(lua_State *L)
227 {
228         const char      *mode, *str;
229         int     nargs;
230
231         nargs = lua_gettop(L);
232         if (nargs < 1 || nargs > 2) {
233                 lua_pushnil(L);
234                 return 1;
235         }
236         str = lua_tostring(L, 1);
237         mode = "r";
238         if (nargs > 1) {
239                 mode = lua_tostring(L, 2);
240                 if (mode == NULL) {
241                         lua_pushnil(L);
242                         return 1;
243                 }
244         }
245         FILE * f = fopen(str, mode);
246         if (f != NULL) {
247                 FILE ** ptr = (FILE**)lua_newuserdata(L, sizeof(FILE**));
248                 *ptr = f;
249         } else
250                 lua_pushnil(L);
251         return 1;
252 }
253
254 static int
255 lua_closefile(lua_State *L)
256 {
257         FILE ** f;
258         if (lua_gettop(L) != 1) {
259                 lua_pushboolean(L, 0);
260                 return 1;
261         }
262
263         f = (FILE**)lua_touserdata(L, 1);
264         if (f != NULL && *f != NULL) {
265                 lua_pushboolean(L, fclose(*f) == 0 ? 1 : 0);
266                 *f = NULL;
267         } else
268                 lua_pushboolean(L, 0);
269
270         return 1;
271 }
272
273 static int
274 lua_readfile(lua_State *L)
275 {
276         FILE    **f;
277         size_t  size, r;
278         char * buf;
279
280         if (lua_gettop(L) < 1 || lua_gettop(L) > 2) {
281                 lua_pushnil(L);
282                 lua_pushinteger(L, 0);
283                 return 2;
284         }
285
286         f = (FILE**)lua_touserdata(L, 1);
287
288         if (f == NULL || *f == NULL) {
289                 lua_pushnil(L);
290                 lua_pushinteger(L, 0);
291                 return 2;
292         }
293
294         if (lua_gettop(L) == 2)
295                 size = (size_t)lua_tonumber(L, 2);
296         else
297                 size = (*f)->size;
298
299
300         buf = (char*)malloc(size);
301         r = fread(buf, 1, size, *f);
302         lua_pushlstring(L, buf, r);
303         free(buf);
304         lua_pushinteger(L, r);
305
306         return 2;
307 }
308
309 /*
310  * Implements io.write(file, ...)
311  * Any number of string and number arguments may be passed to it,
312  * and it will return the number of bytes written, or nil, an error string, and
313  * the errno.
314  */
315 static int
316 lua_writefile(lua_State *L)
317 {
318         FILE    **f;
319         const char      *buf;
320         int     i, nargs;
321         size_t  bufsz, w, wrsz;
322
323         buf = NULL;
324         bufsz = 0;
325         w = 0;
326         wrsz = 0;
327         nargs = lua_gettop(L);
328         if (nargs < 2) {
329                 errno = EINVAL;
330                 return luaL_fileresult(L, 0, NULL);
331         }
332
333         f = (FILE**)lua_touserdata(L, 1);
334
335         if (f == NULL || *f == NULL) {
336                 errno = EINVAL;
337                 return luaL_fileresult(L, 0, NULL);
338         }
339
340         /* Do a validation pass first */
341         for (i = 0; i < nargs - 1; i++) {
342                 /*
343                  * With Lua's API, lua_isstring really checks if the argument
344                  * is a string or a number.  The latter will be implicitly
345                  * converted to a string by our later call to lua_tolstring.
346                  */
347                 if (!lua_isstring(L, i + 2)) {
348                         errno = EINVAL;
349                         return luaL_fileresult(L, 0, NULL);
350                 }
351         }
352         for (i = 0; i < nargs - 1; i++) {
353                 /* We've already validated; there's no chance of failure */
354                 buf = lua_tolstring(L, i + 2, &bufsz);
355                 wrsz = fwrite(buf, 1, bufsz, *f);
356                 if (wrsz < bufsz)
357                         return luaL_fileresult(L, 0, NULL);
358                 w += wrsz;
359         }
360         lua_pushinteger(L, w);
361         return 1;
362 }
363
364 /*
365  * put image using terminal coordinates.
366  */
367 static int
368 lua_term_putimage(lua_State *L)
369 {
370         const char *name;
371         png_t png;
372         uint32_t x1, y1, x2, y2, f;
373         int nargs, ret = 0, error;
374
375         nargs = lua_gettop(L);
376         if (nargs != 6) {
377                 lua_pushboolean(L, 0);
378                 return 1;
379         }
380
381         name = luaL_checkstring(L, 1);
382         x1 = luaL_checknumber(L, 2);
383         y1 = luaL_checknumber(L, 3);
384         x2 = luaL_checknumber(L, 4);
385         y2 = luaL_checknumber(L, 5);
386         f = luaL_checknumber(L, 6);
387
388         x1 = gfx_state.tg_origin.tp_col + x1 * gfx_state.tg_font.vf_width;
389         y1 = gfx_state.tg_origin.tp_row + y1 * gfx_state.tg_font.vf_height;
390         if (x2 != 0) {
391                 x2 = gfx_state.tg_origin.tp_col +
392                     x2 * gfx_state.tg_font.vf_width;
393         }
394         if (y2 != 0) {
395                 y2 = gfx_state.tg_origin.tp_row +
396                     y2 * gfx_state.tg_font.vf_height;
397         }
398
399         if ((error = png_open(&png, name)) != PNG_NO_ERROR) {
400                 if (f & FL_PUTIMAGE_DEBUG)
401                         printf("%s\n", png_error_string(error));
402         } else {
403                 if (gfx_fb_putimage(&png, x1, y1, x2, y2, f) == 0)
404                         ret = 1;
405                 (void) png_close(&png);
406         }
407         lua_pushboolean(L, ret);
408         return 1;
409 }
410
411 static int
412 lua_fb_putimage(lua_State *L)
413 {
414         const char *name;
415         png_t png;
416         uint32_t x1, y1, x2, y2, f;
417         int nargs, ret = 0, error;
418
419         nargs = lua_gettop(L);
420         if (nargs != 6) {
421                 lua_pushboolean(L, 0);
422                 return 1;
423         }
424
425         name = luaL_checkstring(L, 1);
426         x1 = luaL_checknumber(L, 2);
427         y1 = luaL_checknumber(L, 3);
428         x2 = luaL_checknumber(L, 4);
429         y2 = luaL_checknumber(L, 5);
430         f = luaL_checknumber(L, 6);
431
432         if ((error = png_open(&png, name)) != PNG_NO_ERROR) {
433                 if (f & FL_PUTIMAGE_DEBUG)
434                         printf("%s\n", png_error_string(error));
435         } else {
436                 if (gfx_fb_putimage(&png, x1, y1, x2, y2, f) == 0)
437                         ret = 1;
438                 (void) png_close(&png);
439         }
440         lua_pushboolean(L, ret);
441         return 1;
442 }
443
444 static int
445 lua_fb_setpixel(lua_State *L)
446 {
447         uint32_t x, y;
448         int nargs;
449
450         nargs = lua_gettop(L);
451         if (nargs != 2) {
452                 lua_pushnil(L);
453                 return 1;
454         }
455
456         x = luaL_checknumber(L, 1);
457         y = luaL_checknumber(L, 2);
458         gfx_fb_setpixel(x, y);
459         return 0;
460 }
461
462 static int
463 lua_fb_line(lua_State *L)
464 {
465         uint32_t x0, y0, x1, y1, wd;
466         int nargs;
467
468         nargs = lua_gettop(L);
469         if (nargs != 5) {
470                 lua_pushnil(L);
471                 return 1;
472         }
473
474         x0 = luaL_checknumber(L, 1);
475         y0 = luaL_checknumber(L, 2);
476         x1 = luaL_checknumber(L, 3);
477         y1 = luaL_checknumber(L, 4);
478         wd = luaL_checknumber(L, 5);
479         gfx_fb_line(x0, y0, x1, y1, wd);
480         return 0;
481 }
482
483 static int
484 lua_fb_bezier(lua_State *L)
485 {
486         uint32_t x0, y0, x1, y1, x2, y2, width;
487         int nargs;
488
489         nargs = lua_gettop(L);
490         if (nargs != 7) {
491                 lua_pushnil(L);
492                 return 1;
493         }
494
495         x0 = luaL_checknumber(L, 1);
496         y0 = luaL_checknumber(L, 2);
497         x1 = luaL_checknumber(L, 3);
498         y1 = luaL_checknumber(L, 4);
499         x2 = luaL_checknumber(L, 5);
500         y2 = luaL_checknumber(L, 6);
501         width = luaL_checknumber(L, 7);
502         gfx_fb_bezier(x0, y0, x1, y1, x2, y2, width);
503         return 0;
504 }
505
506 static int
507 lua_fb_drawrect(lua_State *L)
508 {
509         uint32_t x0, y0, x1, y1, fill;
510         int nargs;
511
512         nargs = lua_gettop(L);
513         if (nargs != 5) {
514                 lua_pushnil(L);
515                 return 1;
516         }
517
518         x0 = luaL_checknumber(L, 1);
519         y0 = luaL_checknumber(L, 2);
520         x1 = luaL_checknumber(L, 3);
521         y1 = luaL_checknumber(L, 4);
522         fill = luaL_checknumber(L, 5);
523         gfx_fb_drawrect(x0, y0, x1, y1, fill);
524         return 0;
525 }
526
527 static int
528 lua_term_drawrect(lua_State *L)
529 {
530         uint32_t x0, y0, x1, y1;
531         int nargs;
532
533         nargs = lua_gettop(L);
534         if (nargs != 4) {
535                 lua_pushnil(L);
536                 return 1;
537         }
538
539         x0 = luaL_checknumber(L, 1);
540         y0 = luaL_checknumber(L, 2);
541         x1 = luaL_checknumber(L, 3);
542         y1 = luaL_checknumber(L, 4);
543         gfx_term_drawrect(x0, y0, x1, y1);
544         return 0;
545 }
546
547 #define REG_SIMPLE(n)   { #n, lua_ ## n }
548 static const struct luaL_Reg loaderlib[] = {
549         REG_SIMPLE(delay),
550         REG_SIMPLE(command_error),
551         REG_SIMPLE(command),
552         REG_SIMPLE(interpret),
553         REG_SIMPLE(parse),
554         REG_SIMPLE(getenv),
555         REG_SIMPLE(has_command),
556         REG_SIMPLE(perform),
557         REG_SIMPLE(printc),     /* Also registered as the global 'printc' */
558         REG_SIMPLE(setenv),
559         REG_SIMPLE(time),
560         REG_SIMPLE(unsetenv),
561         REG_SIMPLE(fb_bezier),
562         REG_SIMPLE(fb_drawrect),
563         REG_SIMPLE(fb_line),
564         REG_SIMPLE(fb_putimage),
565         REG_SIMPLE(fb_setpixel),
566         REG_SIMPLE(term_drawrect),
567         REG_SIMPLE(term_putimage),
568         { NULL, NULL },
569 };
570
571 static const struct luaL_Reg iolib[] = {
572         { "close", lua_closefile },
573         REG_SIMPLE(getchar),
574         REG_SIMPLE(gets),
575         REG_SIMPLE(ischar),
576         { "open", lua_openfile },
577         { "read", lua_readfile },
578         { "write", lua_writefile },
579         { NULL, NULL },
580 };
581 #undef REG_SIMPLE
582
583 int
584 luaopen_loader(lua_State *L)
585 {
586         luaL_newlib(L, loaderlib);
587         /* Add loader.machine and loader.machine_arch properties */
588         lua_pushstring(L, MACHINE);
589         lua_setfield(L, -2, "machine");
590         lua_pushstring(L, MACHINE_ARCH);
591         lua_setfield(L, -2, "machine_arch");
592         lua_pushstring(L, LUA_PATH);
593         lua_setfield(L, -2, "lua_path");
594         lua_pushinteger(L, bootprog_rev);
595         lua_setfield(L, -2, "version");
596         /* Set global printc to loader.printc */
597         lua_register(L, "printc", lua_printc);
598         return 1;
599 }
600
601 int
602 luaopen_io(lua_State *L)
603 {
604         luaL_newlib(L, iolib);
605         return 1;
606 }