World: r3wp
[!REBOL3 Extensions] REBOL 3 Extensions discussions
older newer | first last |
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 [1777x2] | That's too complex as on my C side I would like to have just the one function. Some enums can be pretty large. |
on the other side I could just do range test and use the integer/variable from REBOL side. | |
ChristianE 30-Nov-2010 [1779] | Would that work? Is it even proper C? typedef enum { PixelsPerInchResolution = RL_MAP_WORD("ppi"), PixelsPerCentimeterResolution = RL_MAP_WORD("ppcm"), ... } |
Oldes 30-Nov-2010 [1780] | I don't think so. |
ChristianE 30-Nov-2010 [1781x2] | Why do you think the first idea is too complex? I for now don't get the "I would like to have just one function" argument. |
How would one function be more simple using only enums? | |
Oldes 30-Nov-2010 [1783x2] | if (unit == RL_MAP_WORD("PixelsPerInchResolution")) { SomeFunc(PixelsPerInchResolution); } elseif (unit == RL_MAP_WORD("PixelsPerCentimeterResolution")) { SomeFunc(PixelsPerCentimeterResolution); } else { SomeFunc(UndefinedResolution); } it just looks strange. |
Also this is simplified case, what if I would have more enum args? | |
ChristianE 30-Nov-2010 [1785] | No, I didn't mean to dispatch to different functions, it's meant as an if/else statement in SomeFunc. |
Oldes 30-Nov-2010 [1786] | Ah.. yes.. that would be fine, but I would like to write wrapper to existing functions, not to write the functions. |
ChristianE 30-Nov-2010 [1787x4] | I was about to suggest RXIEXT int SomeFunc(RXIFRM *frm) { int unit = RL_GET_VALUE(frm, 0, RXT_WORD); if (unit == RL_MAP_WORD("PixelsPerInchResolution")) { } elseif (unit == RL_MAP_WORD("PixelsPerCentimeterResolution")) { } else { } } |
Than you mentioned the wrapper you're going to write. Let me think about that a bit. | |
*Than = Then | |
So, no creative solutions from me, then, I guess. | |
Oldes 30-Nov-2010 [1791x2] | I have this one so far: int unit = RXA_INT64(frm, 1); if(unit >= 0 && unit < 3) { SomeFunc(unit); return RXR_TRUE; } return RXR_FALSE; and in REBOL just: SomeFunc 2 or PixelsPerCentimeterResolution: 2 SomeFunc PixelsPerCentimeterResolution or using dialect |
I guess there is no easy solution as the enum is converted to the integer during compilation. If we are only in C. | |
ChristianE 30-Nov-2010 [1793x3] | How is the above superior to ---- REBOL ---- some-func 'pixels-per-centimeter-resolution ---- C ---- if (unit == RL_MAP_WORD("pixels-per-centimeter-resolution") { SomeFunc(unit); return RXR_TRUE; } But a dialected approach like >> some-func: func [unit [word!]] [select [pixels-per-inch-resolution 1 pixels-per-centimeter-resolution 2] unit] does look ok to me, though. At least, that way, assigning other numerical values to the "keywords" wouldn't harm. |
Probably easier to maintain in REBOL than in C. | |
(Typo in the above, should've read "SomeFunc(2)" instead of "SomeFunc(unit)", but that has already been replaced by the REBOL dialect anymways) | |
Oldes 30-Nov-2010 [1796x2] | the problem with the above is, that in A110: words: [pixels-per-centimeter-resolution] export testword: command ['wrd [lit-word!]] ... case testword: { int unit = RL_MAP_WORD("pixels-per-centimeter-resolution"); RL->print("int: %d\n", unit); } prints int: 1399 = something what I don't expect :) |
for: int unit = RXA_WORD(frm, 1); I get 1381 | |
ChristianE 30-Nov-2010 [1798x2] | That is expected ;-) The numbers you'll get are fairly random. You would have to get the word-number of a supplied word and compare it to the word-number of the allowed words. If they match, act accordingly. |
Or, as stated, compare words in REBOL, e.g. as in my SELECT example. But just don't rely on PIXELSPERCENTIMETERRESOLUTION: 2 | |
Oldes 30-Nov-2010 [1800x2] | now I see that in host-graphics.c is used something like: u32 w = RL_FIND_WORD(graphics_ext_words,RXA_WORD(frm, 1)); switch(w) { case W_GRAPHICS_SCREEN_SIZE: x = GetSystemMetrics(SM_CXSCREEN); y = GetSystemMetrics(SM_CYSCREEN); break; case W_GRAPHICS_TITLE_SIZE: x = 0; y = GetSystemMetrics(SM_CYCAPTION); break; ... |
with: case CMD_GRAPHICS_INIT_WORDS: //temp hack - will be removed later graphics_ext_words = RL_MAP_WORDS(RXA_SERIES(frm,1)); break; | |
older newer | first last |