diff options
author | Benoit Germain <bnt.germain@gmail.com> | 2011-01-04 21:31:17 +0100 |
---|---|---|
committer | Benoit Germain <bnt.germain@gmail.com> | 2011-01-04 21:31:17 +0100 |
commit | 79e46938c5d8daf164ab2d934f668fa27b32e4cf (patch) | |
tree | 407761f25bbdc3d5b2066a705dcbcf8711690242 /src/tools.c | |
parent | ed07b457b6b45ece85d367dc8b89bf3c040abd9a (diff) | |
download | lanes-79e46938c5d8daf164ab2d934f668fa27b32e4cf.tar.gz lanes-79e46938c5d8daf164ab2d934f668fa27b32e4cf.tar.bz2 lanes-79e46938c5d8daf164ab2d934f668fa27b32e4cf.zip |
Take all code from Asko Kauppi's SVN server, and push it here so that the github repository becomes the official Lanes source codebase.
Note that Asko's SVN server holds version 2.0.9, whereas this is version 2.0.10, but I don't see any real need to update SVN if it is to become deprecated.
Next steps:
- upgrade the rockspec to the latest version
- make the html help available online somewhere
Signed-off-by: Benoit Germain <bnt.germain@gmail.com>
Diffstat (limited to 'src/tools.c')
-rw-r--r-- | src/tools.c | 260 |
1 files changed, 108 insertions, 152 deletions
diff --git a/src/tools.c b/src/tools.c index a2ec517..2f3140d 100644 --- a/src/tools.c +++ b/src/tools.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * TOOLS.C Copyright (c) 2002-08, Asko Kauppi | 2 | * TOOLS.C Copyright (c) 2002-10, Asko Kauppi |
3 | * | 3 | * |
4 | * Lua tools to support Lanes. | 4 | * Lua tools to support Lanes. |
5 | */ | 5 | */ |
@@ -7,7 +7,7 @@ | |||
7 | /* | 7 | /* |
8 | =============================================================================== | 8 | =============================================================================== |
9 | 9 | ||
10 | Copyright (C) 2002-08 Asko Kauppi <akauppi@gmail.com> | 10 | Copyright (C) 2002-10 Asko Kauppi <akauppi@gmail.com> |
11 | 11 | ||
12 | Permission is hereby granted, free of charge, to any person obtaining a copy | 12 | Permission is hereby granted, free of charge, to any person obtaining a copy |
13 | of this software and associated documentation files (the "Software"), to deal | 13 | of this software and associated documentation files (the "Software"), to deal |
@@ -40,8 +40,6 @@ THE SOFTWARE. | |||
40 | #include <ctype.h> | 40 | #include <ctype.h> |
41 | #include <stdlib.h> | 41 | #include <stdlib.h> |
42 | 42 | ||
43 | static volatile lua_CFunction hijacked_tostring; // = NULL | ||
44 | |||
45 | MUTEX_T deep_lock; | 43 | MUTEX_T deep_lock; |
46 | MUTEX_T mtid_lock; | 44 | MUTEX_T mtid_lock; |
47 | 45 | ||
@@ -600,7 +598,7 @@ uint_t get_mt_id( lua_State *L, int i ) { | |||
600 | // [-2]: reg[REG_MTID] | 598 | // [-2]: reg[REG_MTID] |
601 | // [-1]: nil/uint | 599 | // [-1]: nil/uint |
602 | 600 | ||
603 | id= lua_tointeger(L,-1); // 0 for nil | 601 | id= (uint_t)lua_tointeger(L,-1); // 0 for nil |
604 | lua_pop(L,1); | 602 | lua_pop(L,1); |
605 | STACK_MID(L,1) | 603 | STACK_MID(L,1) |
606 | 604 | ||
@@ -644,73 +642,60 @@ static int buf_writer( lua_State *L, const void* b, size_t n, void* B ) { | |||
644 | * Returns TRUE if the table was cached (no need to fill it!); FALSE if | 642 | * Returns TRUE if the table was cached (no need to fill it!); FALSE if |
645 | * it's a virgin. | 643 | * it's a virgin. |
646 | */ | 644 | */ |
647 | static | 645 | static bool_t push_cached_table( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ) |
648 | bool_t push_cached_table( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ) { | 646 | { |
649 | bool_t ret; | 647 | bool_t ret; |
650 | |||
651 | ASSERT_L( hijacked_tostring ); | ||
652 | ASSERT_L( L2_cache_i != 0 ); | ||
653 | |||
654 | STACK_GROW(L,2); | ||
655 | STACK_GROW(L2,3); | ||
656 | 648 | ||
657 | // Create an identity string for table at [i]; it should stay unique at | 649 | ASSERT_L( L2_cache_i != 0 ); |
658 | // least during copying of the data (then we can clear the caches). | ||
659 | // | ||
660 | STACK_CHECK(L) | ||
661 | lua_pushcfunction( L, hijacked_tostring ); | ||
662 | lua_pushvalue( L, i ); | ||
663 | lua_call( L, 1 /*args*/, 1 /*retvals*/ ); | ||
664 | // | ||
665 | // [-1]: "table: 0x...." | ||
666 | 650 | ||
667 | STACK_END(L,1) | 651 | STACK_GROW(L2,3); |
668 | ASSERT_L( lua_type(L,-1) == LUA_TSTRING ); | ||
669 | 652 | ||
670 | // L2_cache[id_str]= [{...}] | 653 | // L2_cache[id_str]= [{...}] |
671 | // | 654 | // |
672 | STACK_CHECK(L2) | 655 | STACK_CHECK(L2) |
673 | 656 | ||
674 | // We don't need to use the from state ('L') in ID since the life span | 657 | // We don't need to use the from state ('L') in ID since the life span |
675 | // is only for the duration of a copy (both states are locked). | 658 | // is only for the duration of a copy (both states are locked). |
676 | // | 659 | // |
677 | lua_pushstring( L2, lua_tostring(L,-1) ); | 660 | lua_pushlightuserdata( L2, (void*)lua_topointer( L, i )); // push a light userdata uniquely representing the table |
678 | lua_pop(L,1); // remove the 'tostring(tbl)' value (in L!) | ||
679 | 661 | ||
680 | //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) ); | 662 | //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) ); |
681 | 663 | ||
682 | lua_pushvalue( L2, -1 ); | 664 | lua_pushvalue( L2, -1 ); |
683 | lua_rawget( L2, L2_cache_i ); | 665 | lua_rawget( L2, L2_cache_i ); |
684 | // | 666 | // |
685 | // [-2]: identity string ("table: 0x...") | 667 | // [-2]: identity table pointer lightuserdata |
686 | // [-1]: table|nil | 668 | // [-1]: table|nil |
687 | |||
688 | if (lua_isnil(L2,-1)) { | ||
689 | lua_pop(L2,1); | ||
690 | lua_newtable(L2); | ||
691 | lua_pushvalue(L2,-1); | ||
692 | lua_insert(L2,-3); | ||
693 | // | ||
694 | // [-3]: new table (2nd ref) | ||
695 | // [-2]: identity string | ||
696 | // [-1]: new table | ||
697 | 669 | ||
698 | lua_rawset(L2, L2_cache_i); | 670 | if (lua_isnil(L2,-1)) |
699 | // | 671 | { |
700 | // [-1]: new table (tied to 'L2_cache' table') | 672 | lua_pop(L2,1); |
701 | 673 | lua_newtable(L2); | |
702 | ret= FALSE; // brand new | 674 | lua_pushvalue(L2,-1); |
703 | 675 | lua_insert(L2,-3); | |
704 | } else { | 676 | // |
705 | lua_remove(L2,-2); | 677 | // [-3]: new table (2nd ref) |
706 | ret= TRUE; // from cache | 678 | // [-2]: identity table pointer lightuserdata |
707 | } | 679 | // [-1]: new table |
708 | STACK_END(L2,1) | ||
709 | // | ||
710 | // L2 [-1]: table to use as destination | ||
711 | 680 | ||
712 | ASSERT_L( lua_istable(L2,-1) ); | 681 | lua_rawset(L2, L2_cache_i); |
713 | return ret; | 682 | // |
683 | // [-1]: new table (tied to 'L2_cache' table') | ||
684 | |||
685 | ret= FALSE; // brand new | ||
686 | |||
687 | } | ||
688 | else | ||
689 | { | ||
690 | lua_remove(L2,-2); | ||
691 | ret= TRUE; // from cache | ||
692 | } | ||
693 | STACK_END(L2,1) | ||
694 | // | ||
695 | // L2 [-1]: table to use as destination | ||
696 | |||
697 | ASSERT_L( lua_istable(L2,-1) ); | ||
698 | return ret; | ||
714 | } | 699 | } |
715 | 700 | ||
716 | 701 | ||
@@ -722,82 +707,76 @@ bool_t push_cached_table( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t | |||
722 | */ | 707 | */ |
723 | static void inter_copy_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ); | 708 | static void inter_copy_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ); |
724 | 709 | ||
725 | static | 710 | static void push_cached_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ) |
726 | void push_cached_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ) { | 711 | { |
727 | // TBD: Merge this and same code for tables | 712 | // TBD: Merge this and same code for tables |
728 | 713 | ||
729 | ASSERT_L( hijacked_tostring ); | 714 | ASSERT_L( L2_cache_i != 0 ); |
730 | ASSERT_L( L2_cache_i != 0 ); | ||
731 | 715 | ||
732 | STACK_GROW(L,2); | 716 | STACK_GROW(L2,3); |
733 | STACK_GROW(L2,3); | ||
734 | 717 | ||
735 | STACK_CHECK(L) | 718 | // L2_cache[id_str]= function |
736 | lua_pushcfunction( L, hijacked_tostring ); | 719 | // |
737 | lua_pushvalue( L, i ); | 720 | STACK_CHECK(L2) |
738 | lua_call( L, 1 /*args*/, 1 /*retvals*/ ); | ||
739 | // | ||
740 | // [-1]: "function: 0x...." | ||
741 | 721 | ||
742 | STACK_END(L,1) | 722 | // We don't need to use the from state ('L') in ID since the life span |
743 | ASSERT_L( lua_type(L,-1) == LUA_TSTRING ); | 723 | // is only for the duration of a copy (both states are locked). |
744 | 724 | // | |
745 | // L2_cache[id_str]= function | 725 | lua_pushlightuserdata( L2, (void*)lua_topointer( L, i )); // push a light userdata uniquely representing the function |
746 | // | ||
747 | STACK_CHECK(L2) | ||
748 | 726 | ||
749 | // We don't need to use the from state ('L') in ID since the life span | 727 | //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) ); |
750 | // is only for the duration of a copy (both states are locked). | ||
751 | // | ||
752 | lua_pushstring( L2, lua_tostring(L,-1) ); | ||
753 | lua_pop(L,1); // remove the 'tostring(tbl)' value (in L!) | ||
754 | 728 | ||
755 | //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) ); | 729 | lua_pushvalue( L2, -1 ); |
730 | lua_rawget( L2, L2_cache_i ); | ||
731 | // | ||
732 | // [-2]: identity lightuserdata function pointer | ||
733 | // [-1]: function|nil|true (true means: we're working on it; recursive) | ||
756 | 734 | ||
757 | lua_pushvalue( L2, -1 ); | 735 | if (lua_isnil(L2,-1)) |
758 | lua_rawget( L2, L2_cache_i ); | 736 | { |
759 | // | 737 | lua_pop(L2,1); |
760 | // [-2]: identity string ("function: 0x...") | ||
761 | // [-1]: function|nil|true (true means: we're working on it; recursive) | ||
762 | 738 | ||
763 | if (lua_isnil(L2,-1)) { | 739 | // Set to 'true' for the duration of creation; need to find self-references |
764 | lua_pop(L2,1); | 740 | // via upvalues |
765 | 741 | // | |
766 | // Set to 'true' for the duration of creation; need to find self-references | 742 | lua_pushvalue( L2, -1); |
767 | // via upvalues | 743 | lua_pushboolean(L2,TRUE); |
768 | // | 744 | lua_rawset( L2, L2_cache_i); |
769 | lua_pushboolean(L2,TRUE); | ||
770 | lua_setfield( L2, L2_cache_i, lua_tostring(L2,-2) ); | ||
771 | |||
772 | inter_copy_func( L2, L2_cache_i, L, i ); // pushes a copy of the func | ||
773 | 745 | ||
774 | lua_pushvalue(L2,-1); | 746 | inter_copy_func( L2, L2_cache_i, L, i ); // pushes a copy of the func |
775 | lua_insert(L2,-3); | ||
776 | // | ||
777 | // [-3]: function (2nd ref) | ||
778 | // [-2]: identity string | ||
779 | // [-1]: function | ||
780 | 747 | ||
781 | lua_rawset(L2,L2_cache_i); | 748 | lua_pushvalue(L2,-1); |
782 | // | 749 | lua_insert(L2,-3); |
783 | // [-1]: function (tied to 'L2_cache' table') | 750 | // |
784 | 751 | // [-3]: function (2nd ref) | |
785 | } else if (lua_isboolean(L2,-1)) { | 752 | // [-2]: identity lightuserdata function pointer |
786 | // Loop in preparing upvalues; either direct or via a table | 753 | // [-1]: function |
787 | // | ||
788 | // Note: This excludes the case where a function directly addresses | ||
789 | // itself as an upvalue (recursive lane creation). | ||
790 | // | ||
791 | luaL_error( L, "Recursive use of upvalues; cannot copy the function" ); | ||
792 | |||
793 | } else { | ||
794 | lua_remove(L2,-2); | ||
795 | } | ||
796 | STACK_END(L2,1) | ||
797 | // | ||
798 | // L2 [-1]: function | ||
799 | 754 | ||
800 | ASSERT_L( lua_isfunction(L2,-1) ); | 755 | lua_rawset(L2,L2_cache_i); |
756 | // | ||
757 | // [-1]: function (tied to 'L2_cache' table') | ||
758 | |||
759 | } | ||
760 | else if (lua_isboolean(L2,-1)) | ||
761 | { | ||
762 | // Loop in preparing upvalues; either direct or via a table | ||
763 | // | ||
764 | // Note: This excludes the case where a function directly addresses | ||
765 | // itself as an upvalue (recursive lane creation). | ||
766 | // | ||
767 | STACK_GROW(L,1); | ||
768 | luaL_error( L, "Recursive use of upvalues; cannot copy the function" ); | ||
769 | |||
770 | } | ||
771 | else | ||
772 | { | ||
773 | lua_remove(L2,-2); | ||
774 | } | ||
775 | STACK_END(L2,1) | ||
776 | // | ||
777 | // L2 [-1]: function | ||
778 | |||
779 | ASSERT_L( lua_isfunction(L2,-1) ); | ||
801 | } | 780 | } |
802 | 781 | ||
803 | 782 | ||
@@ -1137,29 +1116,6 @@ void luaG_inter_copy( lua_State* L, lua_State *L2, uint_t n ) | |||
1137 | uint_t top_L2= lua_gettop(L2); | 1116 | uint_t top_L2= lua_gettop(L2); |
1138 | uint_t i; | 1117 | uint_t i; |
1139 | 1118 | ||
1140 | /* steal Lua library's 'luaB_tostring()' from the first call. Other calls | ||
1141 | * don't have to have access to it. | ||
1142 | * | ||
1143 | * Note: multiple threads won't come here at once; this function will | ||
1144 | * be called before there can be multiple threads (no locking needed). | ||
1145 | */ | ||
1146 | if (!hijacked_tostring) { | ||
1147 | STACK_GROW( L,1 ); | ||
1148 | |||
1149 | STACK_CHECK(L) | ||
1150 | lua_getglobal( L, "tostring" ); | ||
1151 | // | ||
1152 | // [-1]: function|nil | ||
1153 | |||
1154 | hijacked_tostring= lua_tocfunction( L, -1 ); | ||
1155 | lua_pop(L,1); | ||
1156 | STACK_END(L,0) | ||
1157 | |||
1158 | if (!hijacked_tostring) { | ||
1159 | luaL_error( L, "Need to see 'tostring()' once" ); | ||
1160 | } | ||
1161 | } | ||
1162 | |||
1163 | if (n > top_L) | 1119 | if (n > top_L) |
1164 | luaL_error( L, "Not enough values: %d < %d", top_L, n ); | 1120 | luaL_error( L, "Not enough values: %d < %d", top_L, n ); |
1165 | 1121 | ||