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/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_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 REG_SIMPLE(fb_bezier), 582 REG_SIMPLE(fb_drawrect), 583 REG_SIMPLE(fb_line), 584 REG_SIMPLE(fb_putimage), 585 REG_SIMPLE(fb_setpixel), 586 REG_SIMPLE(term_drawrect), 587 REG_SIMPLE(term_putimage), 588 { NULL, NULL }, 589 }; 590 591 static const struct luaL_Reg iolib[] = { 592 { "close", lua_closefile }, 593 REG_SIMPLE(getchar), 594 REG_SIMPLE(gets), 595 REG_SIMPLE(ischar), 596 { "open", lua_openfile }, 597 { "read", lua_readfile }, 598 { "write", lua_writefile }, 599 { NULL, NULL }, 600 }; 601 #undef REG_SIMPLE 602 603 static void 604 lua_add_feature(void *cookie, const char *name, const char *desc, bool enabled) 605 { 606 lua_State *L = cookie; 607 608 /* 609 * The feature table consists solely of features that are enabled, and 610 * their associated descriptions for debugging purposes. 611 */ 612 lua_pushstring(L, desc); 613 lua_setfield(L, -2, name); 614 } 615 616 static void 617 lua_add_features(lua_State *L) 618 { 619 620 lua_newtable(L); 621 feature_iter(&lua_add_feature, L); 622 623 /* 624 * We should still have just the table on the stack after we're done 625 * iterating. 626 */ 627 lua_setfield(L, -2, "features"); 628 } 629 630 int 631 luaopen_loader(lua_State *L) 632 { 633 luaL_newlib(L, loaderlib); 634 /* Add loader.machine and loader.machine_arch properties */ 635 lua_pushstring(L, MACHINE); 636 lua_setfield(L, -2, "machine"); 637 lua_pushstring(L, MACHINE_ARCH); 638 lua_setfield(L, -2, "machine_arch"); 639 lua_pushstring(L, LUA_PATH); 640 lua_setfield(L, -2, "lua_path"); 641 lua_pushinteger(L, bootprog_rev); 642 lua_setfield(L, -2, "version"); 643 lua_add_features(L); 644 /* Set global printc to loader.printc */ 645 lua_register(L, "printc", lua_printc); 646 return 1; 647 } 648 649 int 650 luaopen_io(lua_State *L) 651 { 652 luaL_newlib(L, iolib); 653 return 1; 654 } 655