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 } 607