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