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