r3wp [groups: 83 posts: 189283]
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

World: r3wp

[!REBOL3 Extensions] REBOL 3 Extensions discussions

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;
ChristianE
30-Nov-2010
[1802]
I never got RL_FIND_WORD to work, but I stopped trying around A102 
I guess and forgotten about it since then.
Oldes
30-Nov-2010
[1803]
(never mind, time to sleep for a while:)
ChristianE
30-Nov-2010
[1804]
Yeah, time for bed here too, good night.
Oldes
1-Dec-2010
[1805]
hm.. I think I understand how it's supposed to work now, but it looks 
it's just a temp solution. Here is the init part for graphics:
words: [
	;gui-metric
    screen-size
    border-size
    border-fixed
    title-size
    work-origin
    work-size
]
;temp hack - will be removed later
init-words: command [
	words [block!]
]
init-words words