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