1. wrapping C code - my exercise in incompetence.
- Posted by ssallen Mar 12, 2013
- 3219 views
Hello benevolent Eu masters. As mentioned previously, I am working on wrapping the ASSIMP library. Things are going moderately, kinda, OK but I am having some issues with either total incompetence or some deeper and more sinister, intellectual defect. What I present here, is my humble efforts at peeking and poking my way through the mother of all C structures. So much peeking and poking in fact that I somewhat suspect it could be considered sexual harrassment in some states.
Anyways, I have the following C Structures which I am trying to get all the data out of and place in Eu sequences. Some of it works perfectly and some doesn't work at all as noted.
C:
struct aiScene { /** Any combination of the AI_SCENE_FLAGS_XXX flags. By default * this value is 0, no flags are set. Most applications will * want to reject all scenes with the AI_SCENE_FLAGS_INCOMPLETE * bit set. */ unsigned int mFlags; /** The root node of the hierarchy. * * There will always be at least the root node if the import * was successful (and no special flags have been set). * Presence of further nodes depends on the format and content * of the imported file. */ C_STRUCT aiNode* mRootNode; /** The number of meshes in the scene. */ unsigned int mNumMeshes; /** The array of meshes. * * Use the indices given in the aiNode structure to access * this array. The array is mNumMeshes in size. If the * AI_SCENE_FLAGS_INCOMPLETE flag is not set there will always * be at least ONE material. */ C_STRUCT aiMesh** mMeshes; /** The number of materials in the scene. */ unsigned int mNumMaterials; /** The array of materials. * * Use the index given in each aiMesh structure to access this * array. The array is mNumMaterials in size. If the * AI_SCENE_FLAGS_INCOMPLETE flag is not set there will always * be at least ONE material. */ C_STRUCT aiMaterial** mMaterials; /** The number of animations in the scene. */ unsigned int mNumAnimations; /** The array of animations. * * All animations imported from the given file are listed here. * The array is mNumAnimations in size. */ C_STRUCT aiAnimation** mAnimations; /** The number of textures embedded into the file */ unsigned int mNumTextures; /** The array of embedded textures. * * Not many file formats embed their textures into the file. * An example is Quake's MDL format (which is also used by * some GameStudio versions) */ C_STRUCT aiTexture** mTextures; /** The number of light sources in the scene. Light sources * are fully optional, in most cases this attribute will be 0 */ unsigned int mNumLights; /** The array of light sources. * * All light sources imported from the given file are * listed here. The array is mNumLights in size. */ C_STRUCT aiLight** mLights; /** The number of cameras in the scene. Cameras * are fully optional, in most cases this attribute will be 0 */ unsigned int mNumCameras; /** The array of cameras. * * All cameras imported from the given file are listed here. * The array is mNumCameras in size. The first camera in the * array (if existing) is the default camera view into * the scene. */ C_STRUCT aiCamera** mCameras; } aiMaterial /** List of all material properties loaded. */ C_STRUCT aiMaterialProperty** mProperties; /** Number of properties in the data base */ unsigned int mNumProperties; /** Storage allocated */ unsigned int mNumAllocated; aiMaterialProperty struct aiMaterialProperty { /** Specifies the name of the property (key) * Keys are generally case insensitive. */ C_STRUCT aiString mKey; /** Textures: Specifies their exact usage semantic. * For non-texture properties, this member is always 0 * (or, better-said, #aiTextureType_NONE). */ unsigned int mSemantic; /** Textures: Specifies the index of the texture. * For non-texture properties, this member is always 0. */ unsigned int mIndex; /** Size of the buffer mData is pointing to, in bytes. * This value may not be 0. */ unsigned int mDataLength; /** Type information for the property. * * Defines the data layout inside the data buffer. This is used * by the library internally to perform debug checks and to * utilize proper type conversions. * (It's probably a hacky solution, but it works.) */ C_ENUM aiPropertyTypeInfo mType; /** Binary buffer to hold the property's value. * The size of the buffer is always mDataLength. */ char* mData;
2. Re: wrapping C code - my exercise in incompetence.
- Posted by ssallen Mar 12, 2013
- 3325 views
Eucode:
function get_mat_properties(atom ptr, integer numProps) sequence props, tprop, blob atom tptr, loc props = {} loc = peek4u(ptr) --blob = peek({loc, 2000}) testing --writedebugai("blob.txt", blob) for impm = 0 to numProps-1 do tprop = AI_MATERIAL_PROPERTY tprop[1] = get_aiString_sequence(loc) -- *** works perfectly loc += length(tprop[1][2]) + 5 tprop[2] = peek4u(loc) -- incorrect value --UINT loc += 4 tprop[3] = peek4u(loc) -- incorrect value --UINT loc += 4 tprop[4] = peek4u(loc) -- incorrect value --UINT loc += 4 tprop[5] = peek4u(loc) -- incorrect value --UINT loc += 4 tprop[6] = {peek4u(loc)} -- char * mData -- incorrect value loc += 4 -- I know this is wrong its just returning the pointer to test. props &= {tprop} end for return props end function function get_materials(atom ptr, integer numMats) -- ***this function works perfectly. sequence mats, tmat atom propsloc, tptr mats = {} for impx = 0 to numMats-1 do tmat = AI_MATERIAL -- a sequence structure tptr = peek4u(ptr + (impx*4)) -- ptr propsloc = peek4u(tptr) tmat[2] = peek4u(tptr+4) tmat[3] = peek4u(tptr+8) tmat[1] = get_mat_properties(propsloc, tmat[2]) mats &= {tmat} end for return mats end function public function euConvertScene(atom aiScene) -- aiScene is a ptr to the scene object sequence euScene, mesh, norms, uvs atom node_ptr, mesh_ptr, mats_ptr, anims_ptr, txtr_ptr, lights_ptr, cam_ptr euScene = AI_SCENE mesh = {} norms = {} uvs = {} node_ptr = peek4u(aiScene + 4) mesh_ptr = peek4u(aiScene + 12) mats_ptr = peek4u(aiScene + 20) anims_ptr = peek4u(aiScene + 28) txtr_ptr = peek4u(aiScene + 36) lights_ptr = peek4u(aiScene + 44) cam_ptr = peek4u(aiScene + 52) euScene[1] = peek4u(aiScene) -- get flags euScene[2] = get_node_sequence(node_ptr) euScene[3] = peek4u(aiScene+8) -- numMeshes euScene[4] = get_meshes(mesh_ptr, euScene[3]) -- get all meshes euScene[5] = peek4u(aiScene+16) -- numMaterials euScene[6] = get_materials(mats_ptr, euScene[5]) euScene[7] = peek4u(aiScene+24) -- anims euScene[8] = {anims_ptr} euScene[9] = peek4u(aiScene+32) -- textures euScene[10] = {txtr_ptr} euScene[11] = peek4u(aiScene+40) --lights euScene[12] = {lights_ptr} euScene[13] = peek4u(aiScene+48) -- cams euScene[14] = {cam_ptr} writedebugai("assimp_check.txt", euScene) return euScene end function
3. Re: wrapping C code - my exercise in incompetence.
- Posted by ssallen Mar 12, 2013
- 3160 views
So my question is... where am I going wrong in my get_mat_properties() routine? Am I pointing in the wrong place? If so, why does my get_aiString_sequence() consistently give me the correct value? Ugh, this is the better part of the memory blob, the mesh chunk is even worse. :)
Thanks,
Steve A.
4. Re: wrapping C code - my exercise in incompetence.
- Posted by ghaberek (admin) Mar 12, 2013
- 3112 views
So my question is... where am I going wrong in my get_mat_properties() routine? Am I pointing in the wrong place? If so, why does my get_aiString_sequence() consistently give me the correct value? Ugh, this is the better part of the memory blob, the mesh chunk is even worse.
Can we see your code for get_aiString_sequence()?
-Greg
5. Re: wrapping C code - my exercise in incompetence.
- Posted by ssallen Mar 12, 2013
- 3096 views
Yep, I will post it tomorrow. Its on my work computer unfortunately.
6. Re: wrapping C code - my exercise in incompetence.
- Posted by gbonvehi Mar 12, 2013
- 3222 views
Looking at aiString declaration here: http://realxtend-naali-deps.googlecode.com/svn-history/r64/bin/build_deps/assimp/include/aiTypes.h
I think the problem is that aiString's sizeof is not 5. It may be something like 1024 (MAXLEN) + size_t (which I assume is 4). Just guessing by taking a quick look at that declaration, I may be wrong and probably your get_aistring_sequence will shed some light to this.
Edit: I knew Eu4 had size_t defined, the size may vary: http://openeuphoria.org/docs/std_dll.html#_5402_c_size_t
7. Re: wrapping C code - my exercise in incompetence.
- Posted by ghaberek (admin) Mar 12, 2013
- 3158 views
Looking at aiString declaration here: http://realxtend-naali-deps.googlecode.com/svn-history/r64/bin/build_deps/assimp/include/aiTypes.h
I think the problem is that aiString's sizeof is not 5. It may be something like 1024 (MAXLEN) + size_t (which I assume is 4). Just guessing by taking a quick look at that declaration, I may be wrong and probably your get_aistring_sequence will shed some light to this.
That's exactly what I was thinking. We can (for the time being) assume size_t is an unsigned int (4 bytes). So the aiString structure should be 1028 bytes.
Edit: I knew Eu4 had size_t defined, the size may vary: http://openeuphoria.org/docs/std_dll.html#_5402_c_size_t
Those are constants for define_c_func/proc and are not meant to be sizes in and of themselves. You can, however, shift them down to their respected sizes quite easily:
public function sizeof( atom x ) -- returns 1, 2, 4, or 8 return and_bits( x, #FF ) end function public constant SIGNED = 1, UNSIGNED = 2, FLOAT = 3 public function sign( atom x ) -- returns SIGNED, UNSIGNED, or FLOAT return and_bits( x / #1000000, #FF ) end function
Although it's not perfect, since C_DWORDLONG (which is an 8 byte unsigned int) has the same value as C_DOUBLE (which is an 8-byte float).
Edit: this will not be necessary on Euphoria 4.1, since it includes its own sizeof() function and native structure support.
-Greg
8. Re: wrapping C code - my exercise in incompetence.
- Posted by gbonvehi Mar 12, 2013
- 3100 views
Those are constants for define_c_func/proc and are not meant to be sizes in and of themselves. You can, however, shift them down to their respected sizes quite easily:
Ouch, that's what I get for peeking to quick at the docs, yeap, all C_ are constants used to define things, thanks for the heads up.
Edit: this will not be necessary on Euphoria 4.1, since it includes its own sizeof() function and native structure support.
Having sizeof function will help a lot, thanks guys for making interfacing with C easier!
9. Re: wrapping C code - my exercise in incompetence.
- Posted by ssallen Mar 13, 2013
- 3003 views
Hello again, here is my get_aiString_Sequence method.
function get_aiString_sequence(atom loc) sequence aiStr aiStr = AI_STRING aiStr[1] = peek4u(loc) -- t_size if aiStr[1] < 1 then aiStr[2] = "bad length" else aiStr[2] = peek_string(loc+4) -- string end if if length(aiStr[2]) != aiStr[1] then -- Handle: length doesn't match! end if return aiStr end function
10. Re: wrapping C code - my exercise in incompetence.
- Posted by gbonvehi Mar 13, 2013
- 3006 views
The get_aiString_sequence function seems fine.
According to the structure declaration that I linked above, the size of aiString structure is fixed, so you should change the line
loc += length(tprop[1][2]) + 5
to
loc += 1024 + 4 -- MAXLEN + size_t
MAXLEN is defined as 1024 in the .h file and size_t may vary and you can get it dynamically as explained by Greg above but it's probably 4 in your system.
11. Re: wrapping C code - my exercise in incompetence.
- Posted by ssallen Mar 13, 2013
- 2976 views
The get_aiString_sequence function seems fine.
According to the structure declaration that I linked above, the size of aiString structure is fixed, so you should change the line
loc += length(tprop[1][2]) + 5
to
loc += 1024 + 4 -- MAXLEN + size_t
MAXLEN is defined as 1024 in the .h file and size_t may vary and you can get it dynamically as explained by Greg above but it's probably 4 in your system.
Oh, that makes sense. I just assumed since the first item in the structure was size that it would be the length of the buffer. I'll give this a run and report back. Thanks everyone!
Steve A.
12. Re: wrapping C code - my exercise in incompetence.
- Posted by ssallen Mar 13, 2013
- 2965 views
Ok, that fixed a lot of my problems. Thanks everyone!
My new issue is how to deal with this:
ASSIMP_API C_STRUCT aiLogStream aiGetPredefinedLogStream( C_ENUM aiDefaultLogStream pStreams, const char* file);
That function appears to return an actual structure and not a pointer to one. How do I deal with that? Do I have to duplicate the structure in memory by allocating and peeking/poking? The aiLogStream structure looks like this:
struct aiLogStream { /** callback to be called */ aiLogStreamCallback callback; /** user data to be passed to the callback */ char* user; };
and then, of course, the aiLogStreamCallback:
typedef void (*aiLogStreamCallback)(const char* /* message */, char* /* user */);
13. Re: wrapping C code - my exercise in incompetence.
- Posted by ghaberek (admin) Mar 13, 2013
- 2977 views
My new issue is how to deal with this:
ASSIMP_API C_STRUCT aiLogStream aiGetPredefinedLogStream( C_ENUM aiDefaultLogStream pStreams, const char* file);
That function appears to return an actual structure and not a pointer to one. How do I deal with that? Do I have to duplicate the structure in memory by allocating and peeking/poking?
It's passing the structure by value instead of by reference, which is another big no-no in many books. Unfortunately, Euphoria is completely incapable of dealing with this correctly. I have dealt with this first-hand, see: define_c_func/proc and 64-bit return types.
I had to resort to writing a "shim" library (dll/so) in C to push the structure from the stack (pass-by-value) to the heap (pass-by-reference, a.k.a. pointers) and back again. I'm afraid you may have to do the same. I'd be glad to help, if you need. You may also be able to use Assembly code to do this, but I've had no such luck. I'm still quite rusty when it comes to Assembly.
and then, of course, the aiLogStreamCallback:
typedef void (*aiLogStreamCallback)(const char* /* message */, char* /* user */);
That is not a real function. It is a typedef, which defines how your function should look when passing its reference to other functions. You just need to setup a call_back() and pass that value to whatever function(s) call for it.
public function aiLogStreamCallback( atom pMessage /* char* */, atom pUser /* char* */ ) sequence message = peek_string( pMessage ) sequence user = peek_string( pUser ) -- do what you need here return 0 end function constant alLogStreamCallback_cb = call_back( routine_id("aiLogStreamCallback") )
-Greg
14. Re: wrapping C code - my exercise in incompetence.
- Posted by ssallen Mar 14, 2013
- 2906 views
Thanks Greg. I will probably take you up on that once I get the rest of the model extracted. I made good progress getting the texture and mesh data out. Now I am just working on the animations.
Incidentally, if the c code has a double, should I use float64_to_atom? Or do I need to use some witchcraft?
/** Duration of the animation in ticks. */ double mDuration; /** Ticks per second. 0 if not specified in the imported file */ double mTicksPerSecond;
Disregard, I found the answer.
Thanks!
Steve A.
15. Re: wrapping C code - my exercise in incompetence.
- Posted by jmduro Jan 08, 2016
- 2437 views
Although it's not perfect, since C_DWORDLONG (which is an 8 byte unsigned int) has the same value as C_DOUBLE (which is an 8-byte float).
In Euphoria 4.1, both have different values. Can't this be changed in 4.05 ?
Jean-Marc
16. Re: wrapping C code - my exercise in incompetence.
- Posted by ghaberek (admin) Jan 08, 2016
- 2395 views
Although it's not perfect, since C_DWORDLONG (which is an 8 byte unsigned int) has the same value as C_DOUBLE (which is an 8-byte float).
In Euphoria 4.1, both have different values. Can't this be changed in 4.05 ?
You left out the part of my comment, which I believe is the answer you're seeking.
Edit: this will not be necessary on Euphoria 4.1, since it includes its own sizeof() function and native structure support.
You can wrap my custom sizeof() stuff in an ifdef EU4_0 block if you want to support both versions.
-Greg
17. Re: wrapping C code - my exercise in incompetence.
- Posted by jmduro Jan 08, 2016
- 2399 views
You left out the part of my comment, which I believe is the answer you're seeking.
I'm afraid it does not. I try to adapt functions I used in my Low-level Windows wrapper to automatically fill or parse structures according to the computers processor and the compiler release. When I use Eu4.05, I get the same value for both C_DOUBLE and C_DWORDLONG, even with your functions. In one case, I have to deal with a float, in another with a 64-bit integer.
I'm wondering if Eu4.05 knows #03000002 or not (C_DWORDLONG). Maybe I should not care as I use the decimal values.
Jean-Marc
18. Re: wrapping C code - my exercise in incompetence.
- Posted by jimcbrown (admin) Jan 08, 2016
- 2394 views
You left out the part of my comment, which I believe is the answer you're seeking.
I'm afraid it does not. I try to adapt functions I used in my Low-level Windows wrapper to automatically fill or parse structures according to the computers processor and the compiler release. When I use Eu4.05, I get the same value for both C_DOUBLE and C_DWORDLONG, even with your functions. In one case, I have to deal with a float, in another with a 64-bit integer.
I'm wondering if Eu4.05 knows #03000002 or not (C_DWORDLONG). Maybe I should not care as I use the decimal values.
Jean-Marc
4.0.5 (and 4.0.6, when it's released) do not recongize #03000002. The ability for the interpreter to use this value was added in 4.1.0 only.
Here's the section in 4.1.0 that uses this value: http://scm.openeuphoria.org/hg/euphoria/file/16462e686646/source/be_callc.c#l1364
There's the same section in 4.0.6 (or the closest area anyways, the section itself doesn't exist in this version of the file): http://scm.openeuphoria.org/hg/euphoria/file/cbee492464f0/source/be_callc.c#l178
19. Re: wrapping C code - my exercise in incompetence.
- Posted by jmduro Jan 08, 2016
- 2409 views
4.0.5 (and 4.0.6, when it's released) do not recongize #03000002. The ability for the interpreter to use this value was added in 4.1.0 only.
Thank you Jim,
I will try to exploit following tables for what I intend to do:
Euphoria 3.1 | Euphoria 4.05 | Euphoria 4.1 | |
---|---|---|---|
#01000001 | C_CHAR | C_BYTE, C_CHAR | C_BYTE, C_CHAR |
#01000002 | C_SHORT | C_SHORT, C_WORD | C_SHORT, C_WORD |
#01000004 | C_INT, C_LONG | C_INT, C_BOOL, C_LONG, C_HRESULT, C_LPARAM, C_WPARAM | C_INT, C_BOOL |
#01000008 | C_LONG, C_HRESULT | ||
#02000001 | C_UCHAR | C_UBYTE, C_UCHAR | C_UBYTE, C_UCHAR |
#02000002 | C_USHORT | C_USHORT | C_USHORT |
#02000004 | C_UINT, C_ULONG, C_POINTER | C_UINT, C_DWORD, C_HANDLE, C_HWND, C_POINTER, C_SIZE_T, C_ULONG | C_UINT, C_DWORD |
#02000008 | C_ULONG, C_SIZE_T | ||
#03000001 | C_POINTER, C_HANDLE, C_HWND, C_LPARAM, C_WPARAM | ||
#03000002 | C_DWORDLONG, C_LONGLONG | ||
#03000004 | C_FLOAT | C_FLOAT | C_FLOAT |
#03000008 | C_DOUBLE | C_DOUBLE, C_DWORDLONG | C_DOUBLE |
Euphoria 3.1 | Euphoria 4.05 | Euphoria 4.1 | |
---|---|---|---|
C_BYTE | #01000001 | #01000001 | |
C_CHAR | #01000001 | #01000001 | #01000001 |
C_SHORT | #01000002 | #01000002 | #01000002 |
C_WORD | #01000002 | #01000002 | |
C_INT | #01000004 | #01000004 | #01000004 |
C_BOOL | #01000004 | #01000004 | |
C_LONG | #01000004 | #01000004 | #01000008 |
C_HRESULT | #01000004 | #01000008 | |
C_UBYTE | #02000001 | #02000001 | |
C_UCHAR | #02000001 | #02000001 | #02000001 |
C_USHORT | #02000002 | #02000002 | #02000002 |
C_UINT | #02000004 | #02000004 | #02000004 |
C_DWORD | #02000004 | #02000004 | |
C_ULONG | #02000004 | #02000004 | #02000008 |
C_SIZE_T | #02000004 | #02000008 | |
C_POINTER | #02000004 | #02000004 | #03000001 |
C_HANDLE | #02000004 | #03000001 | |
C_HWND | #02000004 | #03000001 | |
C_LPARAM | #01000004 | #03000001 | |
C_WPARAM | #01000004 | #03000001 | |
C_DWORDLONG | #03000008 | #03000002 | |
C_LONGLONG | #03000002 | ||
C_FLOAT | #03000004 | #03000004 | |
C_DOUBLE | #03000008 | #03000008 |
Jean-Marc
20. Re: wrapping C code - my exercise in incompetence.
- Posted by jmduro Jan 09, 2016
- 2336 views
I uploaded a library to allocate, write, read and free structures in memory. Pointers and variables are automatically sized according to OEU version and OS Architecture.
Here is an example of use, no matter if your system is 32-bit or 64-bit, no matter if you use OEU 4.05 or OEU 4.1.
atom p = NULL atom s1 = allocate_string("A string") p = allocateStructure(p, {C_POINTER, C_INT, C_FLOAT} ) writeStructure(p, {C_POINTER, C_INT, C_INT}, {s1, 12, 25.2} ) sequence s2 = readStructure(p, {C_POINTER, C_INT, C_INT} ) printf(1, "s2[1] = %s, s2[2] = %d, s2[3] = %4.1f\n", {peek_string(s2[1]), s2[2], s2[3]}) freeStructure(p, {C_POINTER, C_INT, C_INT} )
Jean-Marc
21. Re: wrapping C code - my exercise in incompetence.
- Posted by K_D_R Jan 09, 2016
- 2340 views
I uploaded a library to allocate, write, read and free structures in memory. Pointers and variables are automatically sized according to OEU version and OS Architecture.
Here is an example of use, no matter if your system is 32-bit or 64-bit, no matter if you use OEU 4.05 or OEU 4.1.
atom p = NULL atom s1 = allocate_string("A string") p = allocateStructure(p, {C_POINTER, C_INT, C_FLOAT} ) writeStructure(p, {C_POINTER, C_INT, C_INT}, {s1, 12, 25.2} ) sequence s2 = readStructure(p, {C_POINTER, C_INT, C_INT} ) printf(1, "s2[1] = %s, s2[2] = %d, s2[3] = %4.1f\n", {peek_string(s2[1]), s2[2], s2[3]}) freeStructure(p, {C_POINTER, C_INT, C_INT} )
Jean-Marc
test_structures.ex crashed on my system:
Ubuntu 15.10, 64-bit Euphoria Interpreter v4.1.0 development 64-bit Linux, Using System Memory Revision Date: 2015-02-02 14:18:53, Id: 5861:57179171dbed kenneth@kenneth-desktop:~/euprogs/Structures$ ls eu_types.ods ex.err functions.e structures.e test_structures.ex kenneth@kenneth-desktop:~/euprogs/Structures$ eui test_structures.ex /home/kenneth/euprogs/Structures/structures.e:22 in function allocateStructure() A machine-level exception occurred during execution of this statement (signal 11) ... called from /home/kenneth/euprogs/Structures/test_structures.ex:10 --> See ex.err ex.err: /home/kenneth/euprogs/Structures/structures.e:22 in function allocateStructure() A machine-level exception occurred during execution of this statement (signal 11) p = 0 def = {50331649,16777220,50331652} lg = 0 i = 1 ... called from /home/kenneth/euprogs/Structures/test_structures.ex:10 Public & Export & Global & Local Variables /home/kenneth/euphoria-4.1.0-Linux-x64/include/std/memconst.e: DEP_really_works = 0 use_DEP = 1 FREE_RID = 2 kernel_dll = <no value> memDLL_id = <no value> VirtualAlloc_rid = <no value> VirtualLock_rid = <no value> VirtualUnlock_rid = <no value> VirtualProtect_rid = <no value> GetLastError_rid = <no value> GetSystemInfo_rid = <no value> /home/kenneth/euphoria-4.1.0-Linux-x64/include/std/memory.e: edges_only = <no value> check_calls = 1 VirtualFree_rid = <no value> /home/kenneth/euphoria-4.1.0-Linux-x64/include/std/types.e: Defined_Sets = { {98'b',99'c',100'd',102'f',103'g',104'h',106'j',107'k', 108'l',109'm',110'n',112'p',113'q',114'r',115's',116't',118'v',119'w',120'x', 121'y',122'z',66'B',67'C',68'D',70'F',71'G',72'H',74'J',75'K',76'L',77'M', 78'N',80'P',81'Q',82'R',83'S',84'T',86'V',87'W',88'X',89'Y',90'Z'}, {97'a',101'e',105'i',111'o',117'u',65'A',69'E',73'I', 79'O',85'U'}, { {48'0',57'9'}, {65'A',70'F'}, {97'a',102'f'} }, {32' ',9,10,13,11,160}, { {32' ',47'/'}, {58':',63'?'}, {91'[',96'`'}, {123'{',126'~'} }, { {32' ',126'~'} }, { {32' ',126'~'}, {32' ',32' '}, {9,9}, {10,10}, {13,13}, {8,8}, {7,7} }, { {97'a',122'z'} }, { {65'A',90'Z'} }, { {48'0',57'9'}, {97'a',122'z'}, {65'A',90'Z'} }, { {48'0',57'9'}, {97'a',122'z'}, {65'A',90'Z'}, {95'_',95'_'} }, { {97'a',122'z'}, {65'A',90'Z'} }, { {0,127} }, { {0,31}, {127,127} }, { {48'0',57'9'} }, { {33'!',126'~'} }, { {0,255} }, {95'_'}, {1,0} } /home/kenneth/euphoria-4.1.0-Linux-x64/include/std/machine.e: FREE_ARRAY_RID = 1 page_size = 4096 /home/kenneth/euphoria-4.1.0-Linux-x64/include/std/convert.e: mem = 18919424 decimal_mark = 46'.' /home/kenneth/euphoria-4.1.0-Linux-x64/include/std/datetime.e: yydiff = 80'P' month_names = { {74'J',97'a',110'n',117'u',97'a',114'r',121'y'}, {70'F',101'e',98'b',114'r',117'u',97'a',114'r',121'y'}, {77'M',97'a',114'r',99'c',104'h'}, {65'A',112'p',114'r',105'i',108'l'}, {77'M',97'a',121'y'}, {74'J',117'u',110'n',101'e'}, {74'J',117'u',108'l',121'y'}, {65'A',117'u',103'g',117'u',115's',116't'}, {83'S',101'e',112'p',116't',101'e',109'm',98'b',101'e', 114'r'}, {79'O',99'c',116't',111'o',98'b',101'e',114'r'}, {78'N',111'o',118'v',101'e',109'm',98'b',101'e',114'r'}, {68'D',101'e',99'c',101'e',109'm',98'b',101'e',114'r'} } month_abbrs = { {74'J',97'a',110'n'}, {70'F',101'e',98'b'}, {77'M',97'a',114'r'}, {65'A',112'p',114'r'}, {77'M',97'a',121'y'}, {74'J',117'u',110'n'}, {74'J',117'u',108'l'}, {65'A',117'u',103'g'}, {83'S',101'e',112'p'}, {79'O',99'c',116't'}, {78'N',111'o',118'v'}, {68'D',101'e',99'c'} } day_names = { {83'S',117'u',110'n',100'd',97'a',121'y'}, {77'M',111'o',110'n',100'd',97'a',121'y'}, {84'T',117'u',101'e',115's',100'd',97'a',121'y'}, {87'W',101'e',100'd',110'n',101'e',115's',100'd',97'a', 121'y'}, {84'T',104'h',117'u',114'r',115's',100'd',97'a',121'y'}, {70'F',114'r',105'i',100'd',97'a',121'y'}, {83'S',97'a',116't',117'u',114'r',100'd',97'a',121'y'} } day_abbrs = { {83'S',117'u',110'n'}, {77'M',111'o',110'n'}, {84'T',117'u',101'e'}, {87'W',101'e',100'd'}, {84'T',104'h',117'u'}, {70'F',114'r',105'i'}, {83'S',97'a',116't'} } ampm = { {65'A',77'M'}, {80'P',77'M'} } /home/kenneth/euphoria-4.1.0-Linux-x64/include/std/filesys.e: STAT_VER = 0 my_dir = -2 InitCurDir = {47'/',104'h',111'o',109'm',101'e',47'/',107'k',101'e',110'n', 110'n',101'e',116't',104'h',47'/',101'e',117'u',112'p',114'r',111'o',103'g', 115's',47'/',83'S',116't',114'r',117'u',99'c',116't',117'u',114'r',101'e', 115's',47'/'} file_counters = {} /home/kenneth/euphoria-4.1.0-Linux-x64/include/std/pretty.e: pretty_end_col = <no value> pretty_chars = <no value> pretty_start_col = <no value> pretty_level = <no value> pretty_file = <no value> pretty_ascii = <no value> pretty_indent = <no value> pretty_ascii_min = <no value> pretty_ascii_max = <no value> pretty_line_count = <no value> pretty_line_max = <no value> pretty_dots = <no value> pretty_line_breaks = <no value> pretty_printing = <no value> pretty_fp_format = <no value> pretty_int_format = <no value> pretty_line = <no value> /home/kenneth/euphoria-4.1.0-Linux-x64/include/std/serialize.e: mem0 = 15736832 mem1 = 15736833 mem2 = 15736834 mem3 = 15736835 mem4 = 15736836 mem5 = 15736837 mem6 = 15736838 mem7 = 15736839 /home/kenneth/euphoria-4.1.0-Linux-x64/include/std/text.e: lower_case_SET = {} upper_case_SET = {} encoding_NAME = {65'A',83'S',67'C',73'I',73'I'} /home/kenneth/euphoria-4.1.0-Linux-x64/include/std/io.e: mem0 = 17715200 mem1 = 17715201 mem2 = 17715202 mem3 = 17715203 /home/kenneth/euphoria-4.1.0-Linux-x64/include/std/scinot.e: NATIVE_FORMAT = 3 /home/kenneth/euphoria-4.1.0-Linux-x64/include/std/get.e: input_file = <no value> input_string = <no value> string_next = <no value> ch = <no value> leading_whitespace = <no value> /home/kenneth/euphoria-4.1.0-Linux-x64/include/std/eumem.e: ram_space = {} ram_free_list = 0 free_rid = 6 /home/kenneth/euphoria-4.1.0-Linux-x64/include/std/primes.e: list_of_primes = {2,3} /home/kenneth/euphoria-4.1.0-Linux-x64/include/std/graphcst.e: true_fgcolor = {0,4,2,6,1,5,3,7,8,12,10,14,9,13,11,15,16,20,18,22,17, 21,19,23,24,28,26,28,25,29,17,31} true_bgcolor = {0,4,2,6,1,5,3,7,8,12,10,14,9,13,11,15,16,20,18,22,17, 21,19,23,24,28,26,28,25,29,17,31} /home/kenneth/euprogs/Structures/test_structures.ex: p = 0 s1 = 15777792 s2 = <no value>
22. Re: wrapping C code - my exercise in incompetence.
- Posted by jmduro Jan 11, 2016
- 2301 views
Thank you Kenneth,
It took some time but I finally found where it hurts. OE 4.1 does not manage correctly ifdef statements on Linux (Revision Date: 2013-04-15 or Revision Date: 2015-02-02).
If you remove ifdefs and keep only the case statements which apply to your OE version and OS architecture, it will work. Of course there is less value for the library this way.
Jean-Marc
23. Re: wrapping C code - my exercise in incompetence.
- Posted by jimcbrown (admin) Jan 11, 2016
- 2260 views
It took some time but I finally found where it hurts. OE 4.1 does not manage correctly ifdef statements on Linux (Revision Date: 2013-04-15 or Revision Date: 2015-02-02).
Hmm. Can you give the output of running 'make test' so we can see which (if any) of the ifdef tests are failing?
A short and simple example that demonstrates the bug would help too.
24. Re: wrapping C code - my exercise in incompetence.
- Posted by jmduro Jan 11, 2016
- 2291 views
Here it is
t_ifdef.e ============================================================================ all tests successful Passed: ifdef normal (0) Passed: ifdef not (0) Passed: ifdef and (0) Passed: ifdef or 1 (0) Passed: ifdef or 2 (0) Passed: ifdef or 3 (0) Passed: ifdef and not 1 (0) Passed: ifdef and not 2 (0) Passed: ifdef or not 1 (0) Passed: ifdef or not 2 (0) Passed: ifdef and and not (0) Passed: ifdef nested 1 (0) Passed: ifdef nested 2 (0) Passed: found elseifdef ABC or FOO (0) Passed: found 2nd elsifdef, second ifdef DEF (0) Passed: sizeof C_POINTER X86_64 (0) Passed: sizeof C_POINTER BITS64 (0) Passed: sizeof C_LONG LONG64 (0) ---------------------------------------------------------------------------- (Tests: 0018) (Status: ok) (Failed: 0000) (Passed: 0018) (Time: 0.000000) t_ifdef-bound ============================================================================ all tests successful Passed: ifdef normal (0) Passed: ifdef not (0) Passed: ifdef and (0) Passed: ifdef or 1 (0) Passed: ifdef or 2 (0) Passed: ifdef or 3 (0) Passed: ifdef and not 1 (0) Passed: ifdef and not 2 (0) Passed: ifdef or not 1 (0) Passed: ifdef or not 2 (0) Passed: ifdef and and not (0) Passed: ifdef nested 1 (0) Passed: ifdef nested 2 (0) Passed: found elseifdef ABC or FOO (0) Passed: found 2nd elsifdef, second ifdef DEF (0) Passed: sizeof C_POINTER X86_64 (0) Passed: sizeof C_POINTER BITS64 (0) Passed: sizeof C_LONG LONG64 (0) ---------------------------------------------------------------------------- (Tests: 0018) (Status: ok) (Failed: 0000) (Passed: 0018) (Time: 0.000000) t_ifdef-translated ============================================================================ all tests successful Passed: ifdef normal (0) Passed: ifdef not (0) Passed: ifdef and (0) Passed: ifdef or 1 (0) Passed: ifdef or 2 (0) Passed: ifdef or 3 (0) Passed: ifdef and not 1 (0) Passed: ifdef and not 2 (0) Passed: ifdef or not 1 (0) Passed: ifdef or not 2 (0) Passed: ifdef and and not (0) Passed: ifdef nested 1 (0) Passed: ifdef nested 2 (0) Passed: found elseifdef ABC or FOO (0) Passed: found 2nd elsifdef, second ifdef DEF (0) Passed: sizeof C_POINTER X86_64 (0) Passed: sizeof C_POINTER BITS64 (0) Passed: sizeof C_LONG LONG64 (0) ---------------------------------------------------------------------------- (Tests: 0018) (Status: ok) (Failed: 0000) (Passed: 0018) (Time: 0.000000) t_ifdef_const.e ============================================================================ all tests successful Passed: ifdef constant a (0) Passed: ifdef constant b (0) ---------------------------------------------------------------------------- (Tests: 0002) (Status: ok) (Failed: 0000) (Passed: 0002) (Time: 0.000000) t_ifdef_const-bound ============================================================================ all tests successful Passed: ifdef constant a (0) Passed: ifdef constant b (0) ---------------------------------------------------------------------------- (Tests: 0002) (Status: ok) (Failed: 0000) (Passed: 0002) (Time: 0.000000) t_ifdef_const-translated ============================================================================ all tests successful Passed: ifdef constant a (0) Passed: ifdef constant b (0) ---------------------------------------------------------------------------- (Tests: 0002) (Status: ok) (Failed: 0000) (Passed: 0002) (Time: 0.000000) t_ifdef_proc.e ============================================================================ all tests successful Passed: Format of ifdef code (0) Passed: ifdef at beginning of function breaks recursion (0) ---------------------------------------------------------------------------- (Tests: 0002) (Status: ok) (Failed: 0000) (Passed: 0002) (Time: 0.000000) t_ifdef_proc-bound ============================================================================ all tests successful Passed: Format of ifdef code (0) Passed: ifdef at beginning of function breaks recursion (0) ---------------------------------------------------------------------------- (Tests: 0002) (Status: ok) (Failed: 0000) (Passed: 0002) (Time: 0.000000) t_ifdef_proc-translated ============================================================================ all tests successful Passed: Format of ifdef code (0) Passed: ifdef at beginning of function breaks recursion (0) ---------------------------------------------------------------------------- (Tests: 0002) (Status: ok) (Failed: 0000) (Passed: 0002) (Time: 0.000000) t_ifdef_switch.e ============================================================================ all tests successful Passed: ifdef recognizes 'case else' (0) ---------------------------------------------------------------------------- (Tests: 0001) (Status: ok) (Failed: 0000) (Passed: 0001) (Time: 0.000000) t_ifdef_switch-bound ============================================================================ all tests successful Passed: ifdef recognizes 'case else' (0) ---------------------------------------------------------------------------- (Tests: 0001) (Status: ok) (Failed: 0000) (Passed: 0001) (Time: 0.000000) t_ifdef_switch-translated ============================================================================ all tests successful Passed: ifdef recognizes 'case else' (0) ---------------------------------------------------------------------------- (Tests: 0001) (Status: ok) (Failed: 0000) (Passed: 0001) (Time: 0.000000)
Test code is here: http://rapideuphoria.com/structures_v0.2.zip
Jean-Marc
25. Re: wrapping C code - my exercise in incompetence.
- Posted by jimcbrown (admin) Jan 11, 2016
- 2244 views
Looks like all the tests passed.
Test code is here: http://rapideuphoria.com/structures_v0.2.zip
Jean-Marc
Can you come up with a simpler test case?
Also, can you file a ticket for this bug?
26. Re: wrapping C code - my exercise in incompetence.
- Posted by PeteE Jan 11, 2016
- 2219 views
Can you come up with a simpler test case?
Also, can you file a ticket for this bug?
Hi Jim, I simplified the test case and filed a ticket.
27. Re: wrapping C code - my exercise in incompetence.
- Posted by jimcbrown (admin) Jan 11, 2016
- 2237 views
Can you come up with a simpler test case?
Also, can you file a ticket for this bug?
Hi Jim, I simplified the test case and filed a ticket.
Thanks for doing this.
It took some time but I finally found where it hurts. OE 4.1 does not manage correctly ifdef statements on Linux (Revision Date: 2013-04-15 or Revision Date: 2015-02-02).
So if I understand the ticket correctly, jmduro is wrong - there is no bug with the ifdefs.
28. Re: wrapping C code - my exercise in incompetence.
- Posted by PeteE Jan 11, 2016
- 2193 views
Can you come up with a simpler test case?
Also, can you file a ticket for this bug?
Hi Jim, I simplified the test case and filed a ticket.
Thanks for doing this.
It took some time but I finally found where it hurts. OE 4.1 does not manage correctly ifdef statements on Linux (Revision Date: 2013-04-15 or Revision Date: 2015-02-02).
So if I understand the ticket correctly, jmduro is wrong - there is no bug with the ifdefs.
Correct. The ifdef BITS32 in his code prevents the bug on 32-bit platforms, so I can see how it can seem to be ifdef-related.
29. Re: wrapping C code - my exercise in incompetence.
- Posted by jmduro Jan 12, 2016
- 2234 views
Correct. The ifdef BITS32 in his code prevents the bug on 32-bit platforms, so I can see how it can seem to be ifdef-related.
Could you explain please? When I extract the portion between ifdefs, I still don't understand where I have to correct the code because I didn't catch the logic behind ifdef management.
ifdef EU4_0 then case C_INT, C_BOOL, C_LONG, C_HRESULT, C_LPARAM, C_WPARAM then -- 32-bit signed (#01000004) lg += 4 case C_UINT, C_DWORD, C_HANDLE, C_HWND, C_POINTER, C_SIZE_T, C_ULONG then -- 32-bit unsigned (#02000004) lg += 4 elsifdef EU4_1 then case C_BOOL, C_INT then -- 32-bit signed (#01000004) lg += 4 case C_DWORD, C_UINT then -- 32-bit unsigned (#02000004) lg += 4 case C_DWORDLONG, C_LONGLONG then -- 64-bit integer (#03000002) lg += 8 ifdef BITS32 then -- 32-bit case C_LONG, C_HRESULT then -- 32-bit signed (#01000008) lg += 4 case C_ULONG, C_SIZE_T then -- 32-bit unsigned (#02000008) lg += 4 case C_POINTER, C_HANDLE, C_HWND, C_LPARAM, C_WPARAM then -- 32-bit pointer (#03000001) lg += 4 elsifdef BITS64 then -- 64-bit case C_LONG, C_HRESULT then -- 64-bit signed (#01000008) lg += 8 case C_ULONG, C_SIZE_T then -- 64-bit unsigned (#02000008) lg += 8 case C_POINTER, C_HANDLE, C_HWND, C_LPARAM, C_WPARAM then -- 64-bit pointer (#03000001) lg += 8 end ifdef end ifdef
In my case, Eu 4.1 on x86-64, the interpreter should see
case C_BOOL, C_INT then -- 32-bit signed (#01000004) lg += 4 case C_DWORD, C_UINT then -- 32-bit unsigned (#02000004) lg += 4 case C_DWORDLONG, C_LONGLONG then -- 64-bit integer (#03000002) lg += 8 case C_LONG, C_HRESULT then -- 64-bit signed (#01000008) lg += 8 case C_ULONG, C_SIZE_T then -- 64-bit unsigned (#02000008) lg += 8 case C_POINTER, C_HANDLE, C_HWND, C_LPARAM, C_WPARAM then -- 64-bit pointer (#03000001) lg += 8
Do I have to understand that on a 64-bit system, both BITS32 and BITS64 are defined ?
Jean-Marc
30. Re: wrapping C code - my exercise in incompetence.
- Posted by ne1uno Jan 12, 2016
- 2204 views
ifdef EU4_0 then case C_INT, C_BOOL, C_LONG, C_HRESULT, C_LPARAM, C_WPARAM then -- 32-bit signed (#01000004) lg += 4 case C_UINT, C_DWORD, C_HANDLE, C_HWND, C_POINTER, C_SIZE_T, C_ULONG then -- 32-bit unsigned (#02000004) lg += 4 elsifdef EU4_1 then case C_BOOL, C_INT then -- 32-bit signed (#01000004) lg += 4 case C_DWORD, C_UINT then -- 32-bit unsigned (#02000004) lg += 4 case C_DWORDLONG, C_LONGLONG then -- 64-bit integer (#03000002) lg += 8 ifdef BITS32 then -- 32-bit case C_LONG, C_HRESULT then -- 32-bit signed (#01000008) lg += 4 case C_ULONG, C_SIZE_T then -- 32-bit unsigned (#02000008) lg += 4 case C_POINTER, C_HANDLE, C_HWND, C_LPARAM, C_WPARAM then -- 32-bit pointer (#03000001) lg += 4 elsifdef BITS64 then -- 64-bit case C_LONG, C_HRESULT then -- 64-bit signed (#01000008) lg += 8 case C_ULONG, C_SIZE_T then -- 64-bit unsigned (#02000008) lg += 8 case C_POINTER, C_HANDLE, C_HWND, C_LPARAM, C_WPARAM then -- 64-bit pointer (#03000001) lg += 8 end ifdef end ifdef
unrelated to the above, to future proof code a little: instead of checking for EU4_1,
I wonder if that should instead be EU4
euphoria 4.0 will be handled already by the ifdef EU4_0 and at some future time when EU4_2 is defined, the code presumably could still work as expected.
31. Re: wrapping C code - my exercise in incompetence.
- Posted by jimcbrown (admin) Jan 12, 2016
- 2232 views
Correct. The ifdef BITS32 in his code prevents the bug on 32-bit platforms, so I can see how it can seem to be ifdef-related.
Could you explain please? When I extract the portion between ifdefs, I still don't understand where I have to correct the code because I didn't catch the logic behind ifdef management.
In my case, Eu 4.1 on x86-64, the interpreter should see
case C_BOOL, C_INT then -- 32-bit signed (#01000004) lg += 4 case C_DWORD, C_UINT then -- 32-bit unsigned (#02000004) lg += 4 case C_DWORDLONG, C_LONGLONG then -- 64-bit integer (#03000002) lg += 8 case C_LONG, C_HRESULT then -- 64-bit signed (#01000008) lg += 8 case C_ULONG, C_SIZE_T then -- 64-bit unsigned (#02000008) lg += 8 case C_POINTER, C_HANDLE, C_HWND, C_LPARAM, C_WPARAM then -- 64-bit pointer (#03000001) lg += 8
On 64bit, C_HANDLE is defined as a C_LONGLONG (#03000002), not as a C_POINTER (#03000001)
See http://scm.openeuphoria.org/hg/euphoria/file/16462e686646/include/std/dll.e#l68 and http://scm.openeuphoria.org/hg/euphoria/file/16462e686646/include/std/dll.e#l64
unrelated to the above, to future proof code a little: instead of checking for EU4_1,
I wonder if that should instead be EU4
euphoria 4.0 will be handled already by the ifdef EU4_0 and at some future time when EU4_2 is defined, the code presumably could still work as expected.
Sounds reasonable.
Do I have to understand that on a 64-bit system, both BITS32 and BITS64 are defined ?
Nope.
32. Re: wrapping C code - my exercise in incompetence.
- Posted by SDPringle Jan 12, 2016
- 2221 views
In order to avoid what Jeremy Cowgar called a Chicken and Egg problem1, the 4.1 can be translated with 4.0 binaries. That is why there is a sizeof() function defined in the 4.1 source for 4.0. You can copy this function and put it in the source of your program and then replace that switch/case and ifdef combination with:
lg += sizeof(c_type)
(1) without a working a binary that understands the new syntax you cannot convert the the source code that uses that new syntax into C, and without the translated source in C you cannot compile and get an up to date version of the binary. When the syntax was changing in 4.0.0 development this was a problem.
33. Re: wrapping C code - my exercise in incompetence.
- Posted by jmduro Jan 12, 2016
- 2205 views
On 64bit, C_HANDLE is defined as a C_LONGLONG (#03000002), not as a C_POINTER (#03000001)
See http://scm.openeuphoria.org/hg/euphoria/file/16462e686646/include/std/dll.e#l68 and http://scm.openeuphoria.org/hg/euphoria/file/16462e686646/include/std/dll.e#l64
Now I understand better what's going on. In std/dll.e of my OE 4.1 release (2015-02-13), C_HANDLE is defined as a C_POINTER, not as a C_LONGLONG, both in the 32-bit and 64-bit versions.
--** handle sizeof pointer C_HANDLE = C_POINTER,
Jean-Marc
34. Re: wrapping C code - my exercise in incompetence.
- Posted by jimcbrown (admin) Jan 12, 2016
- 2184 views
Now I understand better what's going on. In std/dll.e of my OE 4.1 release (2015-02-13), C_HANDLE is defined as a C_POINTER, not as a C_LONGLONG, both in the 32-bit and 64-bit versions.
Something is wrong here. Looking at the hg logs, http://scm.openeuphoria.org/hg/euphoria/log/16462e686646/include/std/dll.e , there was only one change between that date and now, and that was Greg adding a C_ULONGLONG type (which didn't affect C_HANDLE http://scm.openeuphoria.org/hg/euphoria/rev/802120a0fe4e ).
The C_HANDLE change was made in March 2013: http://scm.openeuphoria.org/hg/euphoria/rev/4799252e3ba5
35. Re: wrapping C code - my exercise in incompetence.
- Posted by jmduro Jan 12, 2016
- 2167 views
[unrelated to the above, to future proof code a little: instead of checking for EU4_1,
I wonder if that should instead be EU4
euphoria 4.0 will be handled already by the ifdef EU4_0 and at some future time when EU4_2 is defined, the code presumably could still work as expected.
If you look a the tables above (#19), you'll see that some variables have different numeric values in 4.05 and 4.1: C_LONG, C_ULONG, etc.
Jean-Marc
36. Re: wrapping C code - my exercise in incompetence.
- Posted by jmduro Jan 12, 2016
- 2242 views
Now I understand better what's going on. In std/dll.e of my OE 4.1 release (2015-02-13), C_HANDLE is defined as a C_POINTER, not as a C_LONGLONG, both in the 32-bit and 64-bit versions.
Something is wrong here. Looking at the hg logs, http://scm.openeuphoria.org/hg/euphoria/log/16462e686646/include/std/dll.e , there was only one change between that date and now, and that was Greg adding a C_ULONGLONG type (which didn't affect C_HANDLE http://scm.openeuphoria.org/hg/euphoria/rev/802120a0fe4e ).
The C_HANDLE change was made in March 2013: http://scm.openeuphoria.org/hg/euphoria/rev/4799252e3ba5
I see. My executables ared dated 2015-05-20 but the include files are dated 2012-08-26.
Jean-Marc
37. Re: wrapping C code - my exercise in incompetence.
- Posted by jmduro Jan 15, 2016
- 2107 views
Can you come up with a simpler test case?
Also, can you file a ticket for this bug?
Hi Jim, I simplified the test case and filed a ticket.
Thanks for doing this.
It took some time but I finally found where it hurts. OE 4.1 does not manage correctly ifdef statements on Linux (Revision Date: 2013-04-15 or Revision Date: 2015-02-02).
So if I understand the ticket correctly, jmduro is wrong - there is no bug with the ifdefs.
I will correct my code. However, ifdefs (or switch statement) still have a bug. This is not allowed:
switch def[i] do ifdef EU4_0 then -- error if ifdef follows immediatly switch statement case C_LPARAM, C_WPARAM then free(values[i]) elsifdef EU4_1 then case C_LONG_PTR, C_HANDLE, C_HWND then -- 32-bit signed (#01000008) free(values[i]) end ifdef end switch