[!REBOL3 Extensions] REBOL 3 Extensions discussions
No, but the same callback code works from an other place where it's the same thread as R3.
well, then that's looks pretty much like the problem
the immediate solution is to have a piece of code, running in the same thread as the R3 host, which is used to initiate all callbacks
everwhere else, instead of initiating callbacks directly, you hand over control to this thread running this piece of code initiating the callback for you. that'll require basic inter-thread communication, is kaj already mentioned above
the real solution is to have R3 do this kind of thread synchronisation internally
Well, to get this code started I need to call it from R3, but than I can't return to R3 otherwise I get a new thread dealing with it. So this is not possible.
The other option is to poll from R3 in regular intervalls. But as we miss timers at the moment, this won't work too.
But I could trigger a poll via callback sending an integer! :-) It's two rounds than but that would work.
Because the interger callback works.
i assume you currently have roughly the following flow: - R3 calls into extension (via RX_Call) - extension calls into library, passing an extension-internal "activity" handler along - the library calls the extension's activity handler - the extension activity handler initiates a callback into R3
- R3 call init-lib - init-lib installs a listener, setups a C-level callback handler (CBH) and returns - the listener is sometimes triggered, calls the CBH (new thread) - CBH prepares Rebol callback, calls Rebol callback (and here it crashes with string!, not with integer!), continues and ends
Ok, the callback / pull combo works :-) Not nice, but workaround.
good to know :)
To complete the sequence from above: - Rebol exectues the rebol side callback function, which make a synchronous call to the lib, getting all buffered messages and continues to process them
I have a very strange effect: The init_block gets a c filename attached. The .r file that is used to generate the .h header file of course doesn't inlcude it. And the generated init_block numbers don't include it too.
So, this happens at compile / run-time.
When entering RX_Init the init_block string allready has the c filename appended.
How can this be? I mean it's a const-char array.
Ok, so I found out that the last number wasn't 0. When generating the header file I get this as last line: 116, 105, 97, 108, 105, 122, 101, 100, 34, 10, }; This is the line makeing problems. When I change it to: 116, 105, 97, 108, 105, 122, 101, 100, 34, 10, 0 }; it works.
Seems the R3 script I use has a bug, there is a strange line: to-cstr: either system/version/4 = 3 [ ; Windows format: func [str /local out] [ out: make string! 4 * (length? str) out: insert out tab forall str [ out: insert out reduce [to-integer first str ", "] if zero? ((index? str) // 10) [out: insert out "^/^-"] ] ;remove/part out either (pick out -1) = #" " [-2][-4] head out ] ][
The one commented. Than it works.
Is there an offical place to get the latest verison of this header converter script?
The host kit is the only place I know of
Can someone explain me, why is Carl using such an 'encryption' and why not just to use it as const char like I do here: https://github.com/Oldes/R3-extension-FMOD/blob/master/main.c#L417 Is it because he wants to be compatible with some old compilers?
Oldes, yes, it's about compiler compatibility.
And compilers are affected?
btw it's really strange.. I would thought that that's a basic thing. To be able easily define a string.
Some compilers might be.
Usually, MSVC is the problem, in such cases.
C90 requires compilers to support _single_ string literals (i.e. one quote "...") of at least 509 characters.
(C90 ~= C89 ~= "ANSI C")
C99 raides that minimum to 4095 characters.
And MSVC doesn't support C99.
Then there's also a limit how big concatenated strings can get (i.e. "..." "..." "..."). Which is 65k in MSVC, IIRC.
So, if you don't do extremely long lines and a 65k+ init string, you should be fine with string literals even in MSVC.
Which is why I don't care either :) String literals ftw!
Btw, here's my variation of a header generator script: https://github.com/earl/r3-zmq/blob/master/make-ext-header.r3 It has the nice advantage that it automatically generates a dispatch table for your commands, enabling a clean and concise RX_Call like: https://github.com/earl/r3-zmq/blob/master/zmqext.c#L31-35
For example, take the zmqext extension specification: https://github.com/earl/r3-zmq/blob/master/zmqext.r3 This is the header file generated by above generator script: https://gist.github.com/e22a35049ae56324004a
rebol.org the script library is so well done that everyone use github :P.
I vaguely recall that someone was working on ODBC support for R3. Did that ever become usable? Is there a link to this work?
Thanks! I've been using R2/Command to do the database access and R3 to process the data. All in the same script, using a trick I'll post to the Windows group.
There's a couple bugs in the REBOL portion of the ODBC extension mentioned above. I'll try to make a patching wrapper module.
This module loader for the odbc.dll extension handles the bug in its open handler that prevented it from using block specs with a target: REBOL [ title: "ODBC Extension Patch" type: module options: [private] needs: [%odbc.dll] ] odbc: import 'odbc system/schemes/odbc/actor/open: func [port [port!] /local result] bind [ port/state: context [access: 'write commit: 'auto] result: open-connection port/locals: make database-prototype  case [ string? select port/spec 'host [ajoin ["dsn=" port/spec/host]] string? select port/spec 'target [port/spec/target] 'else [cause-error 'access 'invalid-spec port/spec] ] all [block? result lit-word? first result apply :cause-error result] port ] odbc
Unfortunately, there's an error in its fallback behavior that makes it a bit difficult to use. In its docs, section 3.7: If there is no applicable REBOL datatype to contain a SQL value, the value will be returned as a string. The binary data is returned in a value of the string! type, rather than of the binary! type, which results in a corrupted string that you can't do anything with. If the value was returned as a binary then we could perform the conversions ourselves. I ran into this problem when returning SQL values of the tinyint and text types.
I love the method for triggering errors from the native core though :)
core -> code
It just occured to me that the import statement above could have potentially unwanted side effects on the user context. Replace this: odbc: import 'odbc with this: odbc: import/no-user/no-lib 'odbc
I love the method for triggering errors from the native code though :) - Brian, can you elaborate on this? I'm interested in what you there?
The method is pretty simple. Normally the functions return data in a particular format. Upon an error though they just return a block with 3 elements, the first two of which are lit-words, the last could be anything; this is passed directly to apply :cause-error. The error block can be recognized and handled easily with this code in the REBOL functions that wrap the natives: all [block? result lit-word? first result apply :cause-error result] It's similar to the way error handling is done in the low-level sys load functions, particularly sys/load-header. Upon an error, instead of a block the function returns a word! value, which can be passed to cause-error by the calling function, using code like this: set [hdr: code:] load-header/required data if word? hdr [cause-error 'syntax hdr source] Word values are easier to handle safely than error values. Note that the argument provided to cause-error in this case is different from that provided to load-header: This lets you trigger errors with information that load-header isn't provided, giving your errors more context that is useful to the programmer. Not exactly the same thing as the ODBC driver, but close.