World: r3wp
[!REBOL3 Extensions] REBOL 3 Extensions discussions
older newer | first last |
Maxim 10-Nov-2010 [1719x2] | and replace: #define RL_PRINT(a,b) RL->print(a,b) with: #define RL_PRINT(a,b) RL->print(a,__VA_ARGS__) can't test it right now, but that should work. |
the function itself is defined with variable arguments, its just the #define which isn't ... the above redefines it so it matches the function declaration. | |
Oldes 10-Nov-2010 [1721] | __VA_ARGS__ can only appear in the expansion of a C99 variadic macro Never mind... I really have to do real work now :) |
Maxim 10-Nov-2010 [1722] | what? I'm using it my own gcc compiled version of the host-kit... I don't understand... Andreas will have to step in... I don't know why you're having that error. |
Oldes 10-Nov-2010 [1723] | Actually it's: ../src/include/reb-lib.h:270:49: warning: __VA_ARGS__ can only appear in the expansion of a C99 variadic macro wand.c:74:43: macro "RL_PRINT" passed 3 arguments, but takes just 2 wand.c: In function `RX_Call': wand.c:74: error: `RL_PRINT' undeclared (first use in this function) |
Maxim 10-Nov-2010 [1724] | ok, well, I guess you'll have to use just two args for now ;-) |
Oldes 10-Nov-2010 [1725] | But I have a solution, this works: RL->print("%d %s\n", n,item); |
Maxim 10-Nov-2010 [1726x2] | true. btw, keep reb-lib.h open when you code extension stuff, its the best source to get the proper argument information for all the available RLxxxxx functions. |
if you look at the web version it mangles the argument types, by stripping away any pointer use... so it gets really screwed up. | |
Oldes 10-Nov-2010 [1728] | Extensions are quite additive as I'm getting closer to a real work :) I'm sure I will have other questions, but must force myself to stop now. |
Maxim 10-Nov-2010 [1729] | yes, once you understand that just about everything obeys the same basic pattern, it gets quite easy and addictive, since you get results pretty quickly :-) |
Oldes 10-Nov-2010 [1730x2] | true, once I will understand the patterns, I will make a script, which will create the C code for me. |
oh s**t, I cannot stop.. I'm already able to convert images.. | |
Maxim 10-Nov-2010 [1732] | hahaha |
Pekr 10-Nov-2010 [1733] | Oldes - LOL :-) |
Gregg 11-Nov-2010 [1734] | :-) |
Oldes 11-Nov-2010 [1735x3] | When I have integer (from REBOL side) and want to use it as a pointer, what I must do? |
And, what would you do: (1.) Save wand pointers on REBOL side, or (2.) only on C side and provide just IDs (index) to this pointers (which is probably safer but would require dynamic array on the C side)? | |
I think I've found answer on my question, but please correct me, if there is better way: i32 magick_wand_ptr; MagickWand *magick_wand; magick_wand_ptr = RXA_INT32(frm, 1); magick_wand = magick_wand_ptr; | |
Cyphre 11-Nov-2010 [1738] | I think you could just do this: magick_wand = (MagickWand*)RXA_INT32(frm, 1); |
Oldes 11-Nov-2010 [1739x4] | Right, that works as well:) |
I§m having problems to get string from REBOL input if it's unicode:/ | |
So with Cyphre's help I have this function: char* rebser_to_utf8(REBSER* series) { char *uf8str; REBCHR* str; REBINT result = RL_GET_STRING(series, 0 , (void**)&str); if (result > 0){ //unicode string int iLen = wcslen(str); int oLen = iLen * sizeof(REBCHR); uf8str = malloc(oLen); int result = WideCharToMultiByte(CP_UTF8, 0, str, iLen, uf8str, oLen, 0, 0); if (result == 0) { int err = GetLastError(); RL->print("err: %d\n", err); } } else if (result < 0) { //bytes string (ascii or latin-1) uf8str = malloc(strlen((char *)str)); strcpy(uf8str, (char *)str); } return uf8str; } and I can than use: .. char *filename = rebser_to_utf8(RXA_SERIES(frm, 1)); status=MagickReadImage(current_wand, filename); free(filename); if (status == MagickFalse) { ThrowWandException(current_wand); } return RXR_TRUE; | |
Is it correct? It's working but maybe there is something I don't see as a C newbie. | |
BrianH 11-Nov-2010 [1743] | Why are you using an integer on the REBOL side to store a pointer? That is what handle! is for. |
Oldes 11-Nov-2010 [1744] | because I don't know handle. I'm learning and there are no examples yet |
BrianH 11-Nov-2010 [1745] | REBOL doesn't have pointers, it has references, and it doesn't have addresses. So the only way you could legitimately get a pointer is to return it from a command. But you don't want to have any way to construct an illegitimate pointer in REBOL and pass it to a command because that would be a much worse security and stability problem than just having commands at all, and treating pointers as integers lets you do that. So there is the handle! type to store pointers. A handle! is an immediate value that is the size of a pointer, but that you can't convert directly to or from any other value, or even mold it to see its contents. When you return a pointer from a command you set the value to the handle! type. Then that handle! will be usable when passed back to other commands in the same extension, and maybe even when passed to other extensions, depending on address space issues. Handles are also used to store function pointers in R3, and other opaque system values like library addresses. |
Oldes 11-Nov-2010 [1746] | changed to use handle, but the string conversion function is probably bad. |
BrianH 11-Nov-2010 [1747] | What you absolutely don't want to have available in REBOL code is address arithmetic. That should be reserved for native code. |
Oldes 11-Nov-2010 [1748] | Right, now it's clear that I cannot mess with the wand pointers, so it's safe to store the wands on the REBOL side. Thanks for that info. |
BrianH 11-Nov-2010 [1749] | And on that subject, what is the current state of string conversion in extensions? When last I checked it was really poor, all sorts of missing macros. |
PeterWood 11-Nov-2010 [1750] | Oldes: HAve you tested the function with a string including a unicode code point which translates to a three-byte utf-8 character? The size of utf8str appears to beonly twice the number of codepoints in the REBOL stirng. A good example of a three-byte utf-8 character is the Euro sign - Unicode 20AC UTF-8 E2 82 AC |
Oldes 11-Nov-2010 [1751] | Right, so what is the best way to allocate the buffer. Also the function as it is is working strange if I use it multiple times. So I guess the allocation is bad. |
PeterWood 11-Nov-2010 [1752x2] | The maximum length of a utf-8 translation of a UCS-2 string would be 1.5 times the length of the string. So if wcslen returns the number of codepoints in a string, the length of the utf-8 should be the length of the str multiplied by 3 integer divided by 2 plus 1. |
If wcslen returns the length in bytes then multiply it by 3. | |
Oldes 11-Nov-2010 [1754x2] | the problem with my function is, that the utf8 string is not null-terminated, how to do it properly? |
int oLen = WideCharToMultiByte( CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL); should be used to get the correct length. | |
PeterWood 11-Nov-2010 [1756] | I'd be surprised if WideChatToMultiByte didn't null-terminate the translated field. Have you checked that it isn't now that you are allocating the correct length?. . |
Oldes 11-Nov-2010 [1757x2] | This seems to be working: char* REBSER_to_UTF8(REBSER* series) { char *uf8str; REBCHR* str; REBINT result = RL_GET_STRING(series, 0 , (void**)&str); if (result > 0){ //unicode string int iLen = wcslen(str); //int oLen = iLen * sizeof(REBCHR); int oLen = WideCharToMultiByte( CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL); uf8str = malloc(oLen); int result = WideCharToMultiByte(CP_UTF8, 0, str, iLen, uf8str, oLen, 0, 0); if (result == 0) { int err = GetLastError(); RL->print("err: %d\n", err); } uf8str[oLen] = 0; } else if (result < 0) { //bytes string (ascii or latin-1) uf8str = strdup((char *)str); } return uf8str; } |
OK.. next step... how to create REBOL errors? :) | |
PeterWood 11-Nov-2010 [1759x2] | If it doesn't you would need to add one using pointer arithmetic. I think the code would be something like this:: char *last; last = utf8str + result + 1; *last = 0; |
One question about your function. When do you free the memory you allocated to utf8str? | |
Oldes 11-Nov-2010 [1761x2] | when I don't need it.. so for example: char *filename = rebser_to_utf8(RXA_SERIES(frm, 1)); status=MagickReadImage(current_wand, filename); free(filename); |
Correct me, if it's bad behaviour or if there is better way. I'm really C newbie. | |
ChristianE 11-Nov-2010 [1763] | Is generating erros from C code possible with A110 (it wasn't before)? I have yet to check that. It would be cool, I could simplify my ODBC extension using that. |
Oldes 11-Nov-2010 [1764] | there is RXR_ERROR but hard to say how to use it. I was hoping you will know it:) |
Maxim 11-Nov-2010 [1765x3] | Oldes, thanks for that UTF-8 function converter :-) |
we can return RXR_ERROR, but I don't think it really generates errors... though I haven't even tested it at length. | |
what you can do, is wrap your command within a function in the extension's module and expose that function. this allows you to control the return type of the command better and handle it within the comfort of rebol. | |
Oldes 12-Nov-2010 [1768] | Again with Cyphre's help, here is a function which converts MultiByte (utf-8) string from C side to REBSER used to return the string to REBOL side: REBSER* MultiByteToRebser(char* mbStr) { int len = MultiByteToWideChar( CP_UTF8, 0, mbStr, -1, NULL, 0); //the len is length of the string + null terminator wchar_t *wcStr = malloc(len * sizeof(wchar_t)); int result = MultiByteToWideChar(CP_UTF8, 0, mbStr, strlen(mbStr), wcStr, len); if (result == 0) { int err = GetLastError(); RL->print("ERROR: MultiByteToWideChar -> %d\n", err); exit(-1); //how to throw ERROR on REBOL side? } REBSER *ser = RL_MAKE_STRING(len-1,TRUE); REBUNI *dst; //hack! - will set the tail to len REBINT *s = (REBINT*)ser; s[1] = len-1; RL_GET_STRING(ser,0,(void**)&dst); wcscpy(dst, wcStr); free(wcStr); wcStr = NULL; return ser; } I'm not sure how safe it is, but it seems to be working. To return the string value I use: RXA_TYPE(frm, 1) = RXT_STRING; RXA_SERIES(frm, 1) = (REBSER *)MultiByteToRebser(utf8str); return RXR_VALUE; |
older newer | first last |