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

World: r3wp

[!REBOL3 Extensions] REBOL 3 Extensions discussions

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.