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

World: r3wp

[!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 
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 
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 
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:


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:

It has the nice advantage that it automatically generates a dispatch 
table for your commands, enabling a clean and concise RX_Call like:
For example, take the zmqext extension specification:

This is the header file generated by above generator script:
rebol.org the script library is so well done that everyone use github 
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 

	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] 
] 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.