World: r3wp
[!REBOL3 Extensions] REBOL 3 Extensions discussions
older newer | first last |
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; |
Cyphre 13-Nov-2010 [1769] | This looks ok Oldes. But be aware of the 'hack' part . I put it there just to show you it is possible to copy the whole string without using loop with RL_SET_CHAR. In case Carl changes the REBSER internal struct this function will stop work. But I think you are safe to use the 'hack' at the moment until Carl enhance the HostKit api. One small note in general. Always put all variable declaration at the beginning of code block in C as some compilers will complain about it. |
jocko 13-Nov-2010 [1770] | Updated my ImageMagick extension and doc. It is now possible to exchange image data between Rebol and ImageMagick without using disk files, thanks to the "mpr:" (memory program register) format which allows in-memory save and recover. http://www.colineau.fr/rebol/R3_extensions.html(refresh the page in your web navigator) |
jocko 14-Nov-2010 [1771] | I have put also the sources (Visual Studio project) |
Oldes 30-Nov-2010 [1772x3] | I have a minute again.. so next step in my lesson... Lets have: typedef enum { UndefinedResolution, PixelsPerInchResolution, PixelsPerCentimeterResolution } ResolutionType; and function like: SomeFunc(const ResolutionType units); What's the best way how to provide the units from the REBOL side to the extension's command? |
I know I can use integers instead of the names, or constant variables with integers on the REBOL side but isn't there some other, better way? | |
Providing integers from REBOL side is pretty unstable solution, so I guess I should use words somehow. | |
ChristianE 30-Nov-2010 [1775x2] | Not sure If that's what you're after, but anyways ... ---- REBOL side ---- convert: command [value [number!] unit [word!]] ---- C side ---- if (unit == RL_MAP_WORD("ppi")) { // do something } elseif (unit == RL_MAP_WORD("ppcm")) { // do some other thing } Do you get the idea? >> convert 18 'ppi >> convert 20 'ppcm |
Happily ignoring your ENUM, but hey, who cares? ;-) | |
Oldes 30-Nov-2010 [1777] | That's too complex as on my C side I would like to have just the one function. Some enums can be pretty large. |
older newer | first last |