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