Lua: fix crash when a string argument is missing or an array instead. Implemented universal error messages and checks for function arguments
git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1356 416bcca6-2ee7-4201-b75f-2eb2f807beb1
This commit is contained in:
parent
14464fef39
commit
b393482c58
257
factory.c
257
factory.c
@ -48,6 +48,7 @@
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <lualib.h>
|
||||
#include <float.h> // for DBL_MAX
|
||||
|
||||
///
|
||||
/// Number of characters for name in fileselector.
|
||||
@ -73,20 +74,65 @@ static inline byte clamp_byte(double value)
|
||||
else return (byte)value;
|
||||
}
|
||||
|
||||
///
|
||||
/// This macro reads a Lua argument into a double or integral lvalue.
|
||||
/// If argument is invalid, it will break the caller and raise a verbose message.
|
||||
/// This macro uses 2 existing symbols: L for the context, and nb_args=lua_gettop(L)
|
||||
/// @param index Index of the argument to check, starting at 1.
|
||||
/// @param func_name The name of the lua callback, to display a message in case of error.
|
||||
/// @param dest Destination lvalue. Can be a double, or any integral type. Conversion will "floor".
|
||||
/// @param min_value Check for minimum value. Pass a double, or if you don't care, -DBL_MAX.
|
||||
/// @param max_value Check for maximum value. Pass a double, or if you don't care, DBL_MAX.
|
||||
#define LUA_ARG_NUMBER(index, func_name, dest, min_value, max_value) \
|
||||
do { \
|
||||
double value; \
|
||||
if (nb_args < (index)) return luaL_error(L, "%s: Argument %d is missing.", func_name, (index)); \
|
||||
if (!lua_isnumber(L, (index))) return luaL_error(L, "%s: Argument %d is not a number.", func_name, (index)); \
|
||||
value = lua_tonumber(L, (index)); \
|
||||
if ((min_value) != -DBL_MAX && value<(min_value)) return luaL_error(L, "%s: Argument %d was too small, it had value of %f and minimum should be %f.", func_name, (index), value, (double)(min_value)); \
|
||||
if ((max_value) != DBL_MAX && value>(max_value)) return luaL_error(L, "%s: Argument %d was too big, it had value of %f and maximum should be %f.", func_name, (index), value, (double)(max_value)); \
|
||||
dest = value; \
|
||||
} while(0)
|
||||
|
||||
///
|
||||
/// This macro reads a Lua argument into a string.
|
||||
/// If argument is invalid, it will break the caller and raise a verbose message.
|
||||
/// This macro uses 2 existing symbols: L for the context, and nb_args=lua_gettop(L)
|
||||
/// @param index Index of the argument to check, starting at 1.
|
||||
/// @param func_name The name of the lua callback, to display a message in case of error.
|
||||
/// @param dest Destination string pointer, ideally a const char *.
|
||||
#define LUA_ARG_STRING(index, func_name, dest) \
|
||||
do { \
|
||||
if (nb_args < (index)) return luaL_error(L, "%s: Argument %d is missing.", func_name, index); \
|
||||
if (!lua_isstring(L, (index))) return luaL_error(L, "%s: Argument %d is not a string.", func_name, index); \
|
||||
dest = lua_tostring(L, (index)); \
|
||||
} while (0)
|
||||
|
||||
/// Check if 'num' arguments were provided exactly
|
||||
#define LUA_ARG_LIMIT(num, func_name) \
|
||||
do { \
|
||||
if (nb_args != (num)) \
|
||||
return luaL_error(L, "%s: Expected %d arguments, but found %d.", func_name, (num), nb_args); \
|
||||
} while(0)
|
||||
|
||||
|
||||
|
||||
|
||||
// Wrapper functions to call C from Lua
|
||||
|
||||
int L_SetBrushSize(lua_State* L)
|
||||
{
|
||||
int w = lua_tonumber(L,1);
|
||||
int h = lua_tonumber(L,2);
|
||||
int w;
|
||||
int h;
|
||||
int nb_args=lua_gettop(L);
|
||||
|
||||
LUA_ARG_LIMIT (2, "setbrushsize");
|
||||
LUA_ARG_NUMBER(1, "setbrushsize", w, 1, 10000);
|
||||
LUA_ARG_NUMBER(2, "setbrushsize", h, 1, 10000);
|
||||
|
||||
if (w<1 || h<1)
|
||||
{
|
||||
return luaL_error(L, "SetBrushSize: Unreasonable arguments");
|
||||
}
|
||||
if (Realloc_brush(w, h))
|
||||
{
|
||||
return luaL_error(L, "SetBrushSize: Resize failed");
|
||||
return luaL_error(L, "setbrushsize: Resize failed");
|
||||
}
|
||||
Brush_was_altered=1;
|
||||
// Fill with Back_color
|
||||
@ -112,10 +158,16 @@ int L_GetBrushTransparentColor(lua_State* L)
|
||||
|
||||
int L_PutBrushPixel(lua_State* L)
|
||||
{
|
||||
int x = lua_tonumber(L,1);
|
||||
int y = lua_tonumber(L,2);
|
||||
uint8_t c = lua_tonumber(L,3);
|
||||
int x;
|
||||
int y;
|
||||
uint8_t c;
|
||||
int nb_args=lua_gettop(L);
|
||||
|
||||
LUA_ARG_LIMIT (3, "putbrushpixel");
|
||||
LUA_ARG_NUMBER(1, "putbrushpixel", x, INT_MIN, INT_MAX);
|
||||
LUA_ARG_NUMBER(2, "putbrushpixel", y, INT_MIN, INT_MAX);
|
||||
LUA_ARG_NUMBER(3, "putbrushpixel", c, INT_MIN, INT_MAX);
|
||||
|
||||
Brush_was_altered=1;
|
||||
|
||||
if (x<0 || y<0 || x>=Brush_width || y>=Brush_height)
|
||||
@ -129,9 +181,15 @@ int L_PutBrushPixel(lua_State* L)
|
||||
|
||||
int L_GetBrushPixel(lua_State* L)
|
||||
{
|
||||
int x = lua_tonumber(L,1);
|
||||
int y = lua_tonumber(L,2);
|
||||
int x;
|
||||
int y;
|
||||
uint8_t c;
|
||||
int nb_args=lua_gettop(L);
|
||||
|
||||
LUA_ARG_LIMIT (2, "getbrushpixel");
|
||||
LUA_ARG_NUMBER(1, "getbrushpixel", x, INT_MIN, INT_MAX);
|
||||
LUA_ARG_NUMBER(2, "getbrushpixel", y, INT_MIN, INT_MAX);
|
||||
|
||||
if (x<0 || y<0 || x>=Brush_width || y>=Brush_height)
|
||||
{
|
||||
c = Back_color; // Return 'transparent'
|
||||
@ -146,9 +204,15 @@ int L_GetBrushPixel(lua_State* L)
|
||||
|
||||
int L_GetBrushBackupPixel(lua_State* L)
|
||||
{
|
||||
int x = lua_tonumber(L,1);
|
||||
int y = lua_tonumber(L,2);
|
||||
int x;
|
||||
int y;
|
||||
uint8_t c;
|
||||
int nb_args=lua_gettop(L);
|
||||
|
||||
LUA_ARG_LIMIT (2, "getbrushbackuppixel");
|
||||
LUA_ARG_NUMBER(1, "getbrushbackuppixel", x, INT_MIN, INT_MAX);
|
||||
LUA_ARG_NUMBER(2, "getbrushbackuppixel", y, INT_MIN, INT_MAX);
|
||||
|
||||
if (x<0 || y<0 || x>=Brush_backup_width || y>=Brush_backup_height)
|
||||
{
|
||||
c = Back_color; // Return 'transparent'
|
||||
@ -163,11 +227,14 @@ int L_GetBrushBackupPixel(lua_State* L)
|
||||
|
||||
int L_SetPictureSize(lua_State* L)
|
||||
{
|
||||
int w = lua_tonumber(L,1);
|
||||
int h = lua_tonumber(L,2);
|
||||
|
||||
if (w<1 || h<1 || w>9999 || h>9999)
|
||||
return luaL_error(L, "SetPictureSize: Unreasonable dimensions");
|
||||
int w;
|
||||
int h;
|
||||
int nb_args=lua_gettop(L);
|
||||
|
||||
LUA_ARG_LIMIT (2, "setpicturesize");
|
||||
LUA_ARG_NUMBER(1, "setpicturesize", w, 1, 9999);
|
||||
LUA_ARG_NUMBER(2, "setpicturesize", h, 1, 9999);
|
||||
|
||||
Resize_image(w, h); // TODO: a return value to catch runtime errors
|
||||
return 0;
|
||||
@ -175,16 +242,22 @@ int L_SetPictureSize(lua_State* L)
|
||||
|
||||
int L_GetPictureSize(lua_State* L)
|
||||
{
|
||||
lua_pushinteger(L, Main_image_width);
|
||||
lua_pushinteger(L, Main_image_height);
|
||||
lua_pushinteger(L, Main_image_width);
|
||||
lua_pushinteger(L, Main_image_height);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int L_PutPicturePixel(lua_State* L)
|
||||
{
|
||||
int x = lua_tonumber(L,1);
|
||||
int y = lua_tonumber(L,2);
|
||||
int c = lua_tonumber(L,3);
|
||||
int x;
|
||||
int y;
|
||||
int c;
|
||||
int nb_args=lua_gettop(L);
|
||||
|
||||
LUA_ARG_LIMIT (3, "putpicturepixel");
|
||||
LUA_ARG_NUMBER(1, "putpicturepixel", x, INT_MIN, INT_MAX);
|
||||
LUA_ARG_NUMBER(2, "putpicturepixel", y, INT_MIN, INT_MAX);
|
||||
LUA_ARG_NUMBER(3, "putpicturepixel", c, INT_MIN, INT_MAX);
|
||||
|
||||
// Bound check
|
||||
if (x<0 || y<0 || x>=Main_image_width || y>=Main_image_height)
|
||||
@ -198,8 +271,14 @@ int L_PutPicturePixel(lua_State* L)
|
||||
|
||||
int L_GetPicturePixel(lua_State* L)
|
||||
{
|
||||
int x = lua_tonumber(L,1);
|
||||
int y = lua_tonumber(L,2);
|
||||
int x;
|
||||
int y;
|
||||
int nb_args=lua_gettop(L);
|
||||
|
||||
LUA_ARG_LIMIT (2, "getpicturepixel");
|
||||
LUA_ARG_NUMBER(1, "getpicturepixel", x, INT_MIN, INT_MAX);
|
||||
LUA_ARG_NUMBER(2, "getpicturepixel", y, INT_MIN, INT_MAX);
|
||||
|
||||
// Bound check
|
||||
if (x<0 || y<0 || x>=Main_image_width || y>=Main_image_height)
|
||||
{
|
||||
@ -213,8 +292,14 @@ int L_GetPicturePixel(lua_State* L)
|
||||
|
||||
int L_GetBackupPixel(lua_State* L)
|
||||
{
|
||||
int x = lua_tonumber(L,1);
|
||||
int y = lua_tonumber(L,2);
|
||||
int x;
|
||||
int y;
|
||||
int nb_args=lua_gettop(L);
|
||||
|
||||
LUA_ARG_LIMIT (2, "getbackuppixel");
|
||||
LUA_ARG_NUMBER(1, "getbackuppixel", x, INT_MIN, INT_MAX);
|
||||
LUA_ARG_NUMBER(2, "getbackuppixel", y, INT_MIN, INT_MAX);
|
||||
|
||||
// Bound check
|
||||
if (x<0 || y<0 || x>=Main_image_width || y>=Main_image_height)
|
||||
{
|
||||
@ -228,8 +313,14 @@ int L_GetBackupPixel(lua_State* L)
|
||||
|
||||
int L_GetLayerPixel(lua_State* L)
|
||||
{
|
||||
int x = lua_tonumber(L,1);
|
||||
int y = lua_tonumber(L,2);
|
||||
int x;
|
||||
int y;
|
||||
int nb_args=lua_gettop(L);
|
||||
|
||||
LUA_ARG_LIMIT (2, "getlayerpixel");
|
||||
LUA_ARG_NUMBER(1, "getlayerpixel", x, INT_MIN, INT_MAX);
|
||||
LUA_ARG_NUMBER(2, "getlayerpixel", y, INT_MIN, INT_MAX);
|
||||
|
||||
// Bound check
|
||||
if (x<0 || y<0 || x>=Main_image_width || y>=Main_image_height)
|
||||
{
|
||||
@ -252,8 +343,14 @@ int L_GetSparePictureSize(lua_State* L)
|
||||
|
||||
int L_GetSpareLayerPixel(lua_State* L)
|
||||
{
|
||||
int x = lua_tonumber(L,1);
|
||||
int y = lua_tonumber(L,2);
|
||||
int x;
|
||||
int y;
|
||||
int nb_args=lua_gettop(L);
|
||||
|
||||
LUA_ARG_LIMIT (2, "getsparelayerpixel");
|
||||
LUA_ARG_NUMBER(1, "getsparelayerpixel", x, INT_MIN, INT_MAX);
|
||||
LUA_ARG_NUMBER(2, "getsparelayerpixel", y, INT_MIN, INT_MAX);
|
||||
|
||||
// Bound check
|
||||
if (x<0 || y<0 || x>=Spare_image_width || y>=Spare_image_height)
|
||||
{
|
||||
@ -267,8 +364,14 @@ int L_GetSpareLayerPixel(lua_State* L)
|
||||
|
||||
int L_GetSparePicturePixel(lua_State* L)
|
||||
{
|
||||
int x = lua_tonumber(L,1);
|
||||
int y = lua_tonumber(L,2);
|
||||
int x;
|
||||
int y;
|
||||
int nb_args=lua_gettop(L);
|
||||
|
||||
LUA_ARG_LIMIT (2, "getsparepicturepixel");
|
||||
LUA_ARG_NUMBER(1, "getsparepicturepixel", x, INT_MIN, INT_MAX);
|
||||
LUA_ARG_NUMBER(2, "getsparepicturepixel", y, INT_MIN, INT_MAX);
|
||||
|
||||
// Some bound checking is done by the function itself, here's the rest.
|
||||
if (x<0 || y<0)
|
||||
{
|
||||
@ -282,7 +385,11 @@ int L_GetSparePicturePixel(lua_State* L)
|
||||
|
||||
int L_GetSpareColor(lua_State* L)
|
||||
{
|
||||
byte c=lua_tonumber(L,1);
|
||||
byte c;
|
||||
int nb_args=lua_gettop(L);
|
||||
|
||||
LUA_ARG_LIMIT (1, "getsparecolor");
|
||||
LUA_ARG_NUMBER(1, "getsparecolor", c, INT_MIN, INT_MAX);
|
||||
|
||||
lua_pushinteger(L, Spare_palette[c].R);
|
||||
lua_pushinteger(L, Spare_palette[c].G);
|
||||
@ -300,15 +407,20 @@ int L_GetSpareTransColor(lua_State* L)
|
||||
|
||||
int L_SetColor(lua_State* L)
|
||||
{
|
||||
byte c=lua_tonumber(L,1);
|
||||
|
||||
byte r=clamp_byte((double)lua_tonumber(L,2));
|
||||
byte g=clamp_byte((double)lua_tonumber(L,3));
|
||||
byte b=clamp_byte((double)lua_tonumber(L,4));
|
||||
byte c;
|
||||
double r, g, b;
|
||||
int nb_args=lua_gettop(L);
|
||||
|
||||
Main_palette[c].R=Round_palette_component(r);
|
||||
Main_palette[c].G=Round_palette_component(g);
|
||||
Main_palette[c].B=Round_palette_component(b);
|
||||
LUA_ARG_LIMIT (4, "setcolor");
|
||||
LUA_ARG_NUMBER(1, "setcolor", c, INT_MIN, INT_MAX);
|
||||
LUA_ARG_NUMBER(2, "setcolor", r, INT_MIN, INT_MAX);
|
||||
LUA_ARG_NUMBER(3, "setcolor", g, INT_MIN, INT_MAX);
|
||||
LUA_ARG_NUMBER(4, "setcolor", b, INT_MIN, INT_MAX);
|
||||
|
||||
|
||||
Main_palette[c].R=Round_palette_component(clamp_byte(r));
|
||||
Main_palette[c].G=Round_palette_component(clamp_byte(g));
|
||||
Main_palette[c].B=Round_palette_component(clamp_byte(b));
|
||||
// Set_color(c, r, g, b); Not needed. Update screen when script is finished
|
||||
Palette_has_changed=1;
|
||||
return 0;
|
||||
@ -316,7 +428,11 @@ int L_SetColor(lua_State* L)
|
||||
|
||||
int L_GetColor(lua_State* L)
|
||||
{
|
||||
byte c=lua_tonumber(L,1);
|
||||
byte c;
|
||||
int nb_args=lua_gettop(L);
|
||||
|
||||
LUA_ARG_LIMIT (1, "getcolor");
|
||||
LUA_ARG_NUMBER(1, "getcolor", c, INT_MIN, INT_MAX);
|
||||
|
||||
lua_pushinteger(L, Main_palette[c].R);
|
||||
lua_pushinteger(L, Main_palette[c].G);
|
||||
@ -326,7 +442,11 @@ int L_GetColor(lua_State* L)
|
||||
|
||||
int L_GetBackupColor(lua_State* L)
|
||||
{
|
||||
byte c=lua_tonumber(L,1);
|
||||
byte c;
|
||||
int nb_args=lua_gettop(L);
|
||||
|
||||
LUA_ARG_LIMIT (1, "getbackupcolor");
|
||||
LUA_ARG_NUMBER(1, "getbackupcolor", c, INT_MIN, INT_MAX);
|
||||
|
||||
lua_pushinteger(L, Main_backups->Pages->Next->Palette[c].R);
|
||||
lua_pushinteger(L, Main_backups->Pages->Next->Palette[c].G);
|
||||
@ -336,11 +456,16 @@ int L_GetBackupColor(lua_State* L)
|
||||
|
||||
int L_MatchColor(lua_State* L)
|
||||
{
|
||||
byte r=clamp_byte(lua_tonumber(L,1));
|
||||
byte g=clamp_byte(lua_tonumber(L,2));
|
||||
byte b=clamp_byte(lua_tonumber(L,3));
|
||||
double r, g, b;
|
||||
int c;
|
||||
int nb_args=lua_gettop(L);
|
||||
|
||||
int c = Best_color_nonexcluded(r,g,b);
|
||||
LUA_ARG_LIMIT (3, "matchcolor");
|
||||
LUA_ARG_NUMBER(1, "matchcolor", r, -DBL_MAX, DBL_MAX);
|
||||
LUA_ARG_NUMBER(2, "matchcolor", g, -DBL_MAX, DBL_MAX);
|
||||
LUA_ARG_NUMBER(3, "matchcolor", b, -DBL_MAX, DBL_MAX);
|
||||
|
||||
c = Best_color_nonexcluded(clamp_byte(r),clamp_byte(g),clamp_byte(b));
|
||||
lua_pushinteger(L, c);
|
||||
return 1;
|
||||
}
|
||||
@ -398,42 +523,43 @@ int L_InputBox(lua_State* L)
|
||||
|
||||
nb_args = lua_gettop (L);
|
||||
|
||||
|
||||
if (nb_args < 6)
|
||||
{
|
||||
return luaL_error(L, "InputBox: Less than 6 arguments");
|
||||
return luaL_error(L, "inputbox: Less than 6 arguments");
|
||||
}
|
||||
if ((nb_args - 1) % args_per_setting)
|
||||
{
|
||||
return luaL_error(L, "InputBox: Wrong number of arguments");
|
||||
return luaL_error(L, "inputbox: Wrong number of arguments");
|
||||
}
|
||||
nb_settings = (nb_args-1)/args_per_setting;
|
||||
if (nb_settings > max_settings)
|
||||
{
|
||||
return luaL_error(L, "InputBox: Too many settings, limit reached");
|
||||
return luaL_error(L, "inputbox: Too many settings, limit reached");
|
||||
}
|
||||
|
||||
max_label_length=4; // Minimum size to account for OK / Cancel buttons
|
||||
|
||||
// First argument is window caption
|
||||
window_caption = lua_tostring(L,1);
|
||||
LUA_ARG_STRING(1, "inputbox", window_caption);
|
||||
caption_length = strlen(window_caption);
|
||||
if ( caption_length > 14)
|
||||
max_label_length = caption_length - 10;
|
||||
|
||||
for (setting=0; setting<nb_settings; setting++)
|
||||
{
|
||||
label[setting] = lua_tostring(L,setting*args_per_setting+2);
|
||||
LUA_ARG_STRING(setting*args_per_setting+2, "inputbox", label[setting]);
|
||||
if (strlen(label[setting]) > max_label_length)
|
||||
max_label_length = strlen(label[setting]);
|
||||
|
||||
current_value[setting] = lua_tonumber(L,setting*args_per_setting+3);
|
||||
min_value[setting] = lua_tonumber(L,setting*args_per_setting+4);
|
||||
|
||||
LUA_ARG_NUMBER(setting*args_per_setting+3, "inputbox", current_value[setting], -DBL_MAX, DBL_MAX);
|
||||
LUA_ARG_NUMBER(setting*args_per_setting+4, "inputbox", min_value[setting], -DBL_MAX, DBL_MAX);
|
||||
/*if (min_value[setting] < -999999999999999.0)
|
||||
min_value[setting] = -999999999999999.0;*/
|
||||
max_value[setting] = lua_tonumber(L,setting*args_per_setting+5);
|
||||
LUA_ARG_NUMBER(setting*args_per_setting+5, "inputbox", max_value[setting], -DBL_MAX, DBL_MAX);
|
||||
/*if (max_value[setting] > 999999999999999.0)
|
||||
max_value[setting] = 999999999999999.0;*/
|
||||
decimal_places[setting] = lua_tonumber(L,setting*args_per_setting+6);
|
||||
LUA_ARG_NUMBER(setting*args_per_setting+6, "inputbox", decimal_places[setting], INT_MIN, INT_MAX);
|
||||
if (decimal_places[setting]>15)
|
||||
decimal_places[setting]=15;
|
||||
// Keep current value in range
|
||||
@ -588,23 +714,23 @@ int L_InputBox(lua_State* L)
|
||||
|
||||
int L_MessageBox(lua_State* L)
|
||||
{
|
||||
int nb_args = lua_gettop (L);
|
||||
const char * caption;
|
||||
const char * message;
|
||||
int nb_args = lua_gettop (L);
|
||||
|
||||
if (nb_args == 1)
|
||||
{
|
||||
caption = "Script message";
|
||||
message = lua_tostring(L,1);
|
||||
LUA_ARG_STRING(1, "messagebox", message);
|
||||
}
|
||||
else if (nb_args == 2)
|
||||
{
|
||||
caption = lua_tostring(L,1);
|
||||
message = lua_tostring(L,2);
|
||||
LUA_ARG_STRING(1, "messagebox", caption);
|
||||
LUA_ARG_STRING(2, "messagebox", message);
|
||||
}
|
||||
else
|
||||
{
|
||||
return luaL_error(L, "MessageBox: Needs one or two arguments.");
|
||||
return luaL_error(L, "messagebox: Needs one or two arguments.");
|
||||
}
|
||||
|
||||
Verbose_message(caption, message);
|
||||
@ -884,8 +1010,9 @@ void Button_Brush_Factory(void)
|
||||
|
||||
if (luaL_loadfile(L,scriptdir) != 0)
|
||||
{
|
||||
message = lua_tostring(L, 1);
|
||||
if(message)
|
||||
int stack_size;
|
||||
stack_size= lua_gettop(L);
|
||||
if (stack_size>0 && (message = lua_tostring(L, stack_size))!=NULL)
|
||||
Verbose_message("Error!", message);
|
||||
else
|
||||
Warning_message("Unknown error loading script!");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user