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

World: r3wp

[!REBOL3 Extensions] REBOL 3 Extensions discussions

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
[1805x5]
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
But I think that the easiest way is to define the enum constants 
during the extension init like:
    export PIXELS-PER-INCH-RESOLUTION: 1
    export PIXELS-PER-CENTIMETER-RESOLUTION: 2
    protect/words [
    	PIXELS-PER-INCH-RESOLUTION
    	PIXELS-PER-CENTIMETER-RESOLUTION
    ]
and then just use:
    SomeFunc PIXELS-PER-CENTIMETER-RESOLUTION
or
    SomeFunc 1

with the correct int bound check in the command so only valid numbers 
are processed.  I really like what is possible with R3.. I should 
start real coding in it soon.
Hm.. maybe it's too soon.. the protect seems to be not working if 
used in the extension's init. I can change the values:/
CC: http://curecode.org/rebol3/ticket.rsp?id=1786
hm.. the protect above is not required anyway as long as there is 
the validity check in the command.
ChristianE
1-Dec-2010
[1810]
Here's how I explained to myself how things went:


With A102, the time I started playing around with extensions, there 
was this RL_FIND_WORD which is supposed to map words against an "extension 
local" word block. But sadly, I never got that working.

It was the "temp hack" comment from which I concluded that the preferred 
method then became RL_MAP_WORD, which maps a word to a global word 
id, hence the 1381 number you've got yesterday. With that, you don't 
need to ENUM in your code but can just compare words supplied with 
words known.


But, I may be totally off track with that reasoning ... wouldn't 
take me any wonder :-)
Cyphre
1-Dec-2010
[1811]
Guys, I put the comment about 'temp hack' couple of months ago when 
I discussed this issue with Carl. Not sure but the init-words trick 
will probably stay as is because it works fine that way. Ofcourse 
I may be wrong if there is some better method and Carl decides differently.
ChristianE
2-Dec-2010
[1812]
Ah, good, to know. So I'm off track indeed, I was expecting that.
Oldes
5-Dec-2010
[1813]
When I have:
#if defined(_WIN64) 
#  define ssize_t  __int64
#else
#  define ssize_t  long
#endif


and function which arg is ssize_t type, how I should get the right 
value from REBOL in command?
Is this correct?:
(ssize_t)RXA_INT64(frm, 1))
Andreas
5-Dec-2010
[1814]
Yes, Oldes.