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