1 /* tolua: functions to check types.
2 ** Support code for Lua bindings.
3 ** Written by Waldemar Celes
4 ** TeCGraf/PUC-Rio
5 ** Apr 2003
6 ** $Id: $
7 */
8 
9 /* This code is free software; you can redistribute it and/or modify it.
10 ** The software provided hereunder is on an "as is" basis, and
11 ** the author has no obligation to provide maintenance, support, updates,
12 ** enhancements, or modifications.
13 */
14 
15 #include "tolua++.h"
16 #include "lauxlib.h"
17 
18 #include <stdlib.h>
19 #include <string.h>
20 
21 /* a fast check if a is b, without parameter validation
22  i.e. if b is equal to a or a superclass of a. */
tolua_fast_isa(lua_State * L,int mt_indexa,int mt_indexb,int super_index)23 TOLUA_API int tolua_fast_isa(lua_State *L, int mt_indexa, int mt_indexb, int super_index)
24 {
25  int result;
26 	if (lua_rawequal(L,mt_indexa,mt_indexb))
27 		result = 1;
28 	else
29 	{
30 		if (super_index) {
31 			lua_pushvalue(L, super_index);
32 		} else {
33 			lua_pushliteral(L,"tolua_super");
34 			lua_rawget(L,LUA_REGISTRYINDEX);  /* stack: super */
35 		};
36 		lua_pushvalue(L,mt_indexa);       /* stack: super mta */
37 		lua_rawget(L,-2);                 /* stack: super super[mta] */
38 		lua_pushvalue(L,mt_indexb);       /* stack: super super[mta] mtb */
39 		lua_rawget(L,LUA_REGISTRYINDEX);  /* stack: super super[mta] typenameB */
40 		lua_rawget(L,-2);                 /* stack: super super[mta] bool */
41 		result = lua_toboolean(L,-1);
42 		lua_pop(L,3);
43 	}
44 	return result;
45 }
46 
47 /* Push and returns the corresponding object typename */
tolua_typename(lua_State * L,int lo)48 TOLUA_API const char* tolua_typename (lua_State* L, int lo)
49 {
50 	int tag = lua_type(L,lo);
51  if (tag == LUA_TNONE)
52   lua_pushstring(L,"[no object]");
53  else if (tag != LUA_TUSERDATA && tag != LUA_TTABLE)
54   lua_pushstring(L,lua_typename(L,tag));
55  else if (tag == LUA_TUSERDATA)
56  {
57   if (!lua_getmetatable(L,lo))
58    lua_pushstring(L,lua_typename(L,tag));
59 		else
60 		{
61 		 lua_rawget(L,LUA_REGISTRYINDEX);
62 		 if (!lua_isstring(L,-1))
63 			{
64 		  lua_pop(L,1);
65 				lua_pushstring(L,"[undefined]");
66 			}
67 		}
68 	}
69 	else  /* is table */
70 	{
71 		lua_pushvalue(L,lo);
72 		lua_rawget(L,LUA_REGISTRYINDEX);
73 		if (!lua_isstring(L,-1))
74 		{
75 			lua_pop(L,1);
76 			lua_pushstring(L,"table");
77 		}
78 		else
79 		{
80    lua_pushstring(L,"class ");
81 			lua_insert(L,-2);
82 			lua_concat(L,2);
83 		}
84 	}
85 	return lua_tostring(L,-1);
86 }
87 
tolua_error(lua_State * L,const char * msg,tolua_Error * err)88 TOLUA_API void tolua_error (lua_State* L, const char* msg, tolua_Error* err)
89 {
90 	if (msg[0] == '#')
91 	{
92   const char* expected = err->type;
93 		const char* provided = tolua_typename(L,err->index);
94   if (msg[1]=='f')
95   {
96    int narg = err->index;
97 			if (err->array)
98     luaL_error(L,"%s\n     argument #%d is array of '%s'; array of '%s' expected.\n",
99                msg+2,narg,provided,expected);
100 			else
101     luaL_error(L,"%s\n     argument #%d is '%s'; '%s' expected.\n",
102                msg+2,narg,provided,expected);
103   }
104   else if (msg[1]=='v')
105 		{
106 			if (err->array)
107     luaL_error(L,"%s\n     value is array of '%s'; array of '%s' expected.\n",
108                msg+2,provided,expected);
109 			else
110     luaL_error(L,"%s\n     value is '%s'; '%s' expected.\n",
111                msg+2,provided,expected);
112 		}
113  }
114  else
115   luaL_error(L,msg);
116 }
117 
118 /* the equivalent of lua_is* for usertable */
lua_isusertable(lua_State * L,int lo,const const char * type)119 static  int lua_isusertable (lua_State* L, int lo, const const char* type)
120 {
121 	int r = 0;
122 	if (lo < 0) lo = lua_gettop(L)+lo+1;
123 	lua_pushvalue(L,lo);
124 	lua_rawget(L,LUA_REGISTRYINDEX);  /* get registry[t] */
125 	if (lua_isstring(L,-1))
126 	{
127 		r = strcmp(lua_tostring(L,-1),type)==0;
128 		if (!r)
129 		{
130 			/* try const */
131 			lua_pushstring(L,"const ");
132 			lua_insert(L,-2);
133 			lua_concat(L,2);
134 			r = lua_isstring(L,-1) && strcmp(lua_tostring(L,-1),type)==0;
135 		}
136 	}
137 	lua_pop(L, 1);
138 	return r;
139 }
140 
push_table_instance(lua_State * L,int lo)141 int push_table_instance(lua_State* L, int lo) {
142 
143 	if (lua_istable(L, lo)) {
144 
145 		lua_pushstring(L, ".c_instance");
146 		lua_gettable(L, lo);
147 		if (lua_isuserdata(L, -1)) {
148 
149 			lua_replace(L, lo);
150 			return 1;
151 		} else {
152 
153 			lua_pop(L, 1);
154 			return 0;
155 		};
156 	} else {
157 		return 0;
158 	};
159 
160 	return 0;
161 };
162 
163 /* the equivalent of lua_is* for usertype */
lua_isusertype(lua_State * L,int lo,const char * type)164 static int lua_isusertype (lua_State* L, int lo, const char* type)
165 {
166 	if (!lua_isuserdata(L,lo)) {
167 		if (!push_table_instance(L, lo)) {
168 			return 0;
169 		};
170 	};
171 	{
172 		/* check if it is of the same type */
173 		int r;
174 		const char *tn;
175 		if (lua_getmetatable(L,lo))        /* if metatable? */
176 		{
177 		 lua_rawget(L,LUA_REGISTRYINDEX);  /* get registry[mt] */
178 		 tn = lua_tostring(L,-1);
179 		 r = tn && (strcmp(tn,type) == 0);
180 		 lua_pop(L, 1);
181 			if (r)
182 			 return 1;
183 			else
184 			{
185 				/* check if it is a specialized class */
186 				lua_pushstring(L,"tolua_super");
187 				lua_rawget(L,LUA_REGISTRYINDEX); /* get super */
188 				lua_getmetatable(L,lo);
189 				lua_rawget(L,-2);                /* get super[mt] */
190 				if (lua_istable(L,-1))
191 				{
192 					int b;
193 					lua_pushstring(L,type);
194 					lua_rawget(L,-2);                /* get super[mt][type] */
195 					b = lua_toboolean(L,-1);
196 					lua_pop(L,3);
197 					if (b)
198 					 return 1;
199 				}
200 			}
201 		}
202  }
203 	return 0;
204 }
205 
tolua_isnoobj(lua_State * L,int lo,tolua_Error * err)206 TOLUA_API int tolua_isnoobj (lua_State* L, int lo, tolua_Error* err)
207 {
208  if (lua_gettop(L)<abs(lo))
209 		return 1;
210 	err->index = lo;
211 	err->array = 0;
212 	err->type = "[no object]";
213  return 0;
214 }
215 
tolua_isboolean(lua_State * L,int lo,int def,tolua_Error * err)216 TOLUA_API int tolua_isboolean (lua_State* L, int lo, int def, tolua_Error* err)
217 {
218 	if (def && lua_gettop(L)<abs(lo))
219 		return 1;
220 	if (lua_isnil(L,lo) || lua_isboolean(L,lo))
221 		return 1;
222 	err->index = lo;
223 	err->array = 0;
224 	err->type = "boolean";
225 	return 0;
226 }
227 
tolua_isnumber(lua_State * L,int lo,int def,tolua_Error * err)228 TOLUA_API int tolua_isnumber (lua_State* L, int lo, int def, tolua_Error* err)
229 {
230 	if (def && lua_gettop(L)<abs(lo))
231 		return 1;
232 	if (lua_isnumber(L,lo))
233 		return 1;
234 	err->index = lo;
235 	err->array = 0;
236 	err->type = "number";
237 	return 0;
238 }
239 
tolua_isstring(lua_State * L,int lo,int def,tolua_Error * err)240 TOLUA_API int tolua_isstring (lua_State* L, int lo, int def, tolua_Error* err)
241 {
242 	if (def && lua_gettop(L)<abs(lo))
243 		return 1;
244  if (lua_isnil(L,lo) || lua_isstring(L,lo))
245 		return 1;
246 	err->index = lo;
247 	err->array = 0;
248 	err->type = "string";
249 	return 0;
250 }
251 
tolua_istable(lua_State * L,int lo,int def,tolua_Error * err)252 TOLUA_API int tolua_istable (lua_State* L, int lo, int def, tolua_Error* err)
253 {
254 	if (def && lua_gettop(L)<abs(lo))
255 		return 1;
256 	if (lua_istable(L,lo))
257 		return 1;
258 	err->index = lo;
259 	err->array = 0;
260 	err->type = "table";
261 	return 0;
262 }
263 
tolua_isusertable(lua_State * L,int lo,const char * type,int def,tolua_Error * err)264 TOLUA_API int tolua_isusertable (lua_State* L, int lo, const char* type, int def, tolua_Error* err)
265 {
266 	if (def && lua_gettop(L)<abs(lo))
267 		return 1;
268 	if (lua_isusertable(L,lo,type))
269 		return 1;
270 	err->index = lo;
271 	err->array = 0;
272 	err->type = type;
273 	return 0;
274 }
275 
276 
tolua_isuserdata(lua_State * L,int lo,int def,tolua_Error * err)277 TOLUA_API int tolua_isuserdata (lua_State* L, int lo, int def, tolua_Error* err)
278 {
279 	if (def && lua_gettop(L)<abs(lo))
280 		return 1;
281 	if (lua_isnil(L,lo) || lua_isuserdata(L,lo))
282 		return 1;
283 	err->index = lo;
284 	err->array = 0;
285 	err->type = "userdata";
286 	return 0;
287 }
288 
tolua_isvaluenil(lua_State * L,int lo,tolua_Error * err)289 TOLUA_API int tolua_isvaluenil (lua_State* L, int lo, tolua_Error* err) {
290 
291 	if (lua_gettop(L)<abs(lo))
292 		return 0; /* somebody else should chack this */
293 	if (!lua_isnil(L, lo))
294 		return 0;
295 
296 	err->index = lo;
297 	err->array = 0;
298 	err->type = "value";
299 	return 1;
300 };
301 
tolua_isvalue(lua_State * L,int lo,int def,tolua_Error * err)302 TOLUA_API int tolua_isvalue (lua_State* L, int lo, int def, tolua_Error* err)
303 {
304 	if (def || abs(lo)<=lua_gettop(L))  /* any valid index */
305 		return 1;
306 	err->index = lo;
307 	err->array = 0;
308 	err->type = "value";
309 	return 0;
310 }
311 
tolua_isusertype(lua_State * L,int lo,const char * type,int def,tolua_Error * err)312 TOLUA_API int tolua_isusertype (lua_State* L, int lo, const char* type, int def, tolua_Error* err)
313 {
314 	if (def && lua_gettop(L)<abs(lo))
315 		return 1;
316 	if (lua_isnil(L,lo) || lua_isusertype(L,lo,type))
317 		return 1;
318 	err->index = lo;
319 	err->array = 0;
320 	err->type = type;
321 	return 0;
322 }
323 
tolua_isvaluearray(lua_State * L,int lo,int dim,int def,tolua_Error * err)324 TOLUA_API int tolua_isvaluearray
325  (lua_State* L, int lo, int dim, int def, tolua_Error* err)
326 {
327 	if (!tolua_istable(L,lo,def,err))
328 		return 0;
329 	else
330 		return 1;
331 }
332 
tolua_isbooleanarray(lua_State * L,int lo,int dim,int def,tolua_Error * err)333 TOLUA_API int tolua_isbooleanarray
334  (lua_State* L, int lo, int dim, int def, tolua_Error* err)
335 {
336 	if (!tolua_istable(L,lo,def,err))
337 		return 0;
338 	else
339 	{
340 		int i;
341 		for (i=1; i<=dim; ++i)
342 		{
343 			lua_pushnumber(L,i);
344 			lua_gettable(L,lo);
345 	  if (!(lua_isnil(L,-1) || lua_isboolean(L,-1)) &&
346 					  !(def && lua_isnil(L,-1))
347 						)
348 			{
349 				err->index = lo;
350 				err->array = 1;
351 				err->type = "boolean";
352 				return 0;
353 			}
354 			lua_pop(L,1);
355 		}
356  }
357  return 1;
358 }
359 
tolua_isnumberarray(lua_State * L,int lo,int dim,int def,tolua_Error * err)360 TOLUA_API int tolua_isnumberarray
361  (lua_State* L, int lo, int dim, int def, tolua_Error* err)
362 {
363 	if (!tolua_istable(L,lo,def,err))
364 		return 0;
365 	else
366 	{
367 		int i;
368 		for (i=1; i<=dim; ++i)
369 		{
370 			lua_pushnumber(L,i);
371 			lua_gettable(L,lo);
372 			if (!lua_isnumber(L,-1) &&
373 					  !(def && lua_isnil(L,-1))
374 						)
375 			{
376 				err->index = lo;
377 				err->array = 1;
378 				err->type = "number";
379 				return 0;
380 			}
381 			lua_pop(L,1);
382 		}
383  }
384  return 1;
385 }
386 
tolua_isstringarray(lua_State * L,int lo,int dim,int def,tolua_Error * err)387 TOLUA_API int tolua_isstringarray
388  (lua_State* L, int lo, int dim, int def, tolua_Error* err)
389 {
390 	if (!tolua_istable(L,lo,def,err))
391 		return 0;
392 	else
393 	{
394 		int i;
395 		for (i=1; i<=dim; ++i)
396 		{
397 			lua_pushnumber(L,i);
398 			lua_gettable(L,lo);
399    if (!(lua_isnil(L,-1) || lua_isstring(L,-1)) &&
400 			    !(def && lua_isnil(L,-1))
401 						)
402 			{
403 				err->index = lo;
404 				err->array = 1;
405 				err->type = "string";
406 				return 0;
407 			}
408 			lua_pop(L,1);
409 		}
410  }
411  return 1;
412 }
413 
tolua_istablearray(lua_State * L,int lo,int dim,int def,tolua_Error * err)414 TOLUA_API int tolua_istablearray
415  (lua_State* L, int lo, int dim, int def, tolua_Error* err)
416 {
417 	if (!tolua_istable(L,lo,def,err))
418 		return 0;
419 	else
420 	{
421 		int i;
422 		for (i=1; i<=dim; ++i)
423 		{
424 			lua_pushnumber(L,i);
425 			lua_gettable(L,lo);
426 	  if (! lua_istable(L,-1) &&
427 			    !(def && lua_isnil(L,-1))
428 						)
429 			{
430 				err->index = lo;
431 				err->array = 1;
432 				err->type = "table";
433 				return 0;
434 			}
435 			lua_pop(L,1);
436 		}
437  }
438  return 1;
439 }
440 
tolua_isuserdataarray(lua_State * L,int lo,int dim,int def,tolua_Error * err)441 TOLUA_API int tolua_isuserdataarray
442  (lua_State* L, int lo, int dim, int def, tolua_Error* err)
443 {
444 	if (!tolua_istable(L,lo,def,err))
445 		return 0;
446 	else
447 	{
448 		int i;
449 		for (i=1; i<=dim; ++i)
450 		{
451 			lua_pushnumber(L,i);
452 			lua_gettable(L,lo);
453 	  if (!(lua_isnil(L,-1) || lua_isuserdata(L,-1)) &&
454 			    !(def && lua_isnil(L,-1))
455 						)
456 			{
457 				err->index = lo;
458 				err->array = 1;
459 				err->type = "userdata";
460 				return 0;
461 			}
462 			lua_pop(L,1);
463 		}
464  }
465  return 1;
466 }
467 
tolua_isusertypearray(lua_State * L,int lo,const char * type,int dim,int def,tolua_Error * err)468 TOLUA_API int tolua_isusertypearray
469  (lua_State* L, int lo, const char* type, int dim, int def, tolua_Error* err)
470 {
471 	if (!tolua_istable(L,lo,def,err))
472 		return 0;
473 	else
474 	{
475 		int i;
476 		for (i=1; i<=dim; ++i)
477 		{
478 			lua_pushnumber(L,i);
479 			lua_gettable(L,lo);
480 	  if (!(lua_isnil(L,-1) || lua_isuserdata(L,-1)) &&
481 			    !(def && lua_isnil(L,-1))
482 						)
483 			{
484 				err->index = lo;
485 				err->type = type;
486 				err->array = 1;
487 				return 0;
488 			}
489 			lua_pop(L,1);
490 		}
491  }
492  return 1;
493 }
494 
495 #if 0
496 int tolua_isbooleanfield
497  (lua_State* L, int lo, int i, int def, tolua_Error* err)
498 {
499 	lua_pushnumber(L,i);
500 	lua_gettable(L,lo);
501 	if (!(lua_isnil(L,-1) || lua_isboolean(L,-1)) &&
502 			  !(def && lua_isnil(L,-1))
503 				)
504 	{
505 		err->index = lo;
506 		err->array = 1;
507 		err->type = "boolean";
508 		return 0;
509 	}
510 	lua_pop(L,1);
511  return 1;
512 }
513 
514 int tolua_isnumberfield
515  (lua_State* L, int lo, int i, int def, tolua_Error* err)
516 {
517 	lua_pushnumber(L,i);
518 	lua_gettable(L,lo);
519 	if (!lua_isnumber(L,-1) &&
520 			  !(def && lua_isnil(L,-1))
521 				)
522 	{
523 		err->index = lo;
524 		err->array = 1;
525 		err->type = "number";
526 		return 0;
527 	}
528 	lua_pop(L,1);
529  return 1;
530 }
531 
532 int tolua_isstringfield
533  (lua_State* L, int lo, int i, int def, tolua_Error* err)
534 {
535 	lua_pushnumber(L,i);
536 	lua_gettable(L,lo);
537  if (!(lua_isnil(L,-1) || lua_isstring(L,-1)) &&
538 	    !(def && lua_isnil(L,-1))
539 				)
540 	{
541 		err->index = lo;
542 		err->array = 1;
543 		err->type = "string";
544 		return 0;
545 	}
546 	lua_pop(L,1);
547  return 1;
548 }
549 
550 int tolua_istablefield
551  (lua_State* L, int lo, int i, int def, tolua_Error* err)
552 {
553 	lua_pushnumber(L,i+1);
554 	lua_gettable(L,lo);
555 	if (! lua_istable(L,-1) &&
556 	    !(def && lua_isnil(L,-1))
557 				)
558 	{
559 		err->index = lo;
560 		err->array = 1;
561 		err->type = "table";
562 		return 0;
563 	}
564 	lua_pop(L,1);
565 }
566 
567 int tolua_isusertablefield
568  (lua_State* L, int lo, const char* type, int i, int def, tolua_Error* err)
569 {
570 	lua_pushnumber(L,i);
571 	lua_gettable(L,lo);
572 	if (! lua_isusertable(L,-1,type) &&
573 	    !(def && lua_isnil(L,-1))
574 				)
575 	{
576 		err->index = lo;
577 		err->array = 1;
578 		err->type = type;
579 		return 0;
580 	}
581 	lua_pop(L,1);
582  return 1;
583 }
584 
585 int tolua_isuserdatafield
586  (lua_State* L, int lo, int i, int def, tolua_Error* err)
587 {
588 	lua_pushnumber(L,i);
589 	lua_gettable(L,lo);
590 	if (!(lua_isnil(L,-1) || lua_isuserdata(L,-1)) &&
591 	    !(def && lua_isnil(L,-1))
592 				)
593 	{
594 		err->index = lo;
595 		err->array = 1;
596 		err->type = "userdata";
597 		return 0;
598 	}
599 	lua_pop(L,1);
600  return 1;
601 }
602 
603 int tolua_isusertypefield
604  (lua_State* L, int lo, const char* type, int i, int def, tolua_Error* err)
605 {
606 	lua_pushnumber(L,i);
607 	lua_gettable(L,lo);
608 	if (!(lua_isnil(L,-1) || lua_isusertype(L,-1,type)) &&
609 	    !(def && lua_isnil(L,-1))
610 				)
611 	{
612 		err->index = lo;
613 		err->type = type;
614 		err->array = 1;
615 		return 0;
616 	}
617 	lua_pop(L,1);
618  return 1;
619 }
620 
621 #endif
622