How to create a TCL function with optional arguments using SWIG? - c

I have a simple c/c++ app that has an optional TCL interpreter with the function wrappers generated using SWIG. For several of the functions all the arguments are optional. How is this typically handled? I'd like to support a TCL command like this, where any of the arguments are optional but the C function takes fixed arguments:
//TCL command
get_list [options] filename
-opt1
-opt2
-opt3 arg1
-opt4 arg2
filename
//C function
static signed get_list(bool opt1,
bool opt2,
char * arg1,
objectType * arg2,
char * fileName)
Currently I have something like this:
static pList * get_list(char * arg1=NULL,
char * arg2=NULL,
char * arg3=NULL,
tObject * arg4=NULL)
This has many problems such as enforcing the object pointer is always the last argument. The SWIG documentation talks at length about C functions with variable arguments using "..." but I don't think this is what I need. I'd like the C function arguments to be fixed.

The easiest method is to wrap a Tcl procedure around the outside, like this:
rename get_list original.get_list
proc get_list args {
if {[llength $args] == 0 || [llength $args] % 2 == 0} {
error "wrong # args: ..."; # Do a proper error message here!
}
# Handle the required argument
set filename [lindex $args end]
# Initialize the defaults
array set opts {
-opt1 false
-opt2 false
-opt3 ""
-opt4 ""
}
# Merge in the supplied options
foreach {opt val} [lrange $args 0 end-1] {
if {![info exist opts($opt)]} {
error "unrecognized option \"$opt\""
}
set opts($opt) $value
}
# Hand off to C level...
original.get_list $opts(-opt1) $opts(-opt2) $opts(-opt3) $opts(-opt4) $filename
}
If you've got Tcl 8.6, that last handoff is best done with tailcall so the rewriting code is cut out of the Tcl stack. It's not vital though, as SWIGged code rarely resolves names of Tcl commands and variables.

Related

Can we use CMake foreach in template source file?

For unit testing my functions, i have auto-generated the name, like it:
test_implode
test_range
into a CMake variable.
I want to call all automatically in C.
I also used config file (.in.c) in CMake
set(CONFIG configuration)
configure_file(${CONFIG}.in.c ${CONFIG}.c)
set(CONFIG_SRC ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG}.c)
But the name of the function are just in a List in CMake, the C syntax is not valid. I could generate a variable in CMake with appropriate syntax, but generating output in config file would let the CMake source file clean and could be possibly very powerful.
Concretly, what I would like to do is that (imaginary syntax):
#include "tests.h"
void all_tests() {
void(*tests)()[] = {
#FOREACH(FUNC FUNCTIONS)#
test_#FUNC#,
#ENDFOREACH()#
NULL
};
void(*test_function)() = tests[0];
while(test_function) {
test_function();
test_function++;
}
}
Similarly to blade or php.
Can I use CMake as a scripting language (or a foreach) or is it mandatory to put this in the CMake source file and store it into a variable ?
What I currently do, which is acceptable, works. But I'm learning and I would like to know if it's still possible or not
foreach(PHP_FUNCTION ${PHP_FUNCTIONS})
list(APPEND GENERATED_C_CODE_RUN_TEST "\n\ttest_${PHP_FUNCTION}()")
endforeach()
set(GENERATED_C_CODE_RUN_TEST "${GENERATED_C_CODE_RUN_TEST};")
set(CONFIG configuration)
configure_file(${CONFIG}.in.c ${CONFIG}.c)
set(CONFIG_SRC ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG}.c)
add_executable(...);
#include "tests.h"
void all_tests() {
#GENERATED_C_CODE_RUN_TEST#
}
One solution is to append the test_ prefix to each test name in a list, then use list(JOIN ...) to construct a string representing a comma-separated list (which is valid C syntax).
list(APPEND PHP_FUNCTIONS
func1
func2
func3
)
# Append the 'test_' prefix to each test function name.
foreach(PHP_FUNCTION ${PHP_FUNCTIONS})
list(APPEND FUNCTION_NAMES_LIST "test_${PHP_FUNCTION}")
endforeach()
message(STATUS "FUNCTION_NAMES_LIST: ${FUNCTION_NAMES_LIST}")
# Construct a comma-separated string from the list.
list(JOIN FUNCTION_NAMES_LIST "," FUNCTION_NAMES_STRING)
message(STATUS "FUNCTION_NAMES_STRING: ${FUNCTION_NAMES_STRING}")
This prints the following:
FUNCTION_NAMES_LIST: test_func1;test_func2;test_func3
FUNCTION_NAMES_STRING: test_func1,test_func2,test_func3
Then, you can modify your configuration.in.c file so only one variable needs to be substituted:
void all_tests() {
void(*tests)()[] = {
#FUNCTION_NAMES_STRING#,
NULL
};
void(*test_function)() = tests[0];
while(test_function) {
test_function();
test_function++;
}
}
You can play around with the "glue" or separator string used to join the CMake list together. In my example, I used "," but you can use ", " or ",\n\t" to make the resultant C code more visually pleasing. CMake list() (and string()) have lots of manipulation options to play around with, so I encourage you to check them out.

tcl library: how to use tcl_eval() to set return result for c-code tcl command extension?

Let's suppose I implemented a new tcl command written in c-code that I registered using Tcl_CreateObjCommand, and inside of this c-code I call Tcl_Eval to eval a string containing code to create an Associative array and store it in a variable tmp. How can I set this tmp variable created with Tcl_eval() as the return result object from the c-function?
Example:
int MyCommand(
ClientData clientData,
Tcl_Interp* interp,
int argc,
char* argv[])
{
int rc = Tcl_Eval(interp,
"array set tmp [list {key1} {value1} {key2} {value2}]");
if (rc != TCL_OK) {
return rc;
}
//???
Tcl_SetObjResult(interp, ?? tmp variable from eval??);
return TCL_OK;
}
When I run the Tcl interpreter with the above C-extension, I would expect to see this result:
TCL> set x [MyCommand]
TCL> puts "$x(key1)"
value1 # Currently an Error and not set
TCL> puts "$x(key2)"
value2 # Currently and Error and not set
In a way the above works. Just not the way I want it to. For Example, if I type:
TCL> set x [MyCommand]
TCL> puts "$tmp(key1)"
value1 # Its Works! Except, I didn't want to set a global variable tmp
TCL> puts "$tmp(key2)"
value2 # Its Works! Except, I didn't want to set a global variable tmp
(Maybe its a "feature" to set tmp instead??) Anyways, I still want it to work the correct way by returning the value using the proc "return" mechanism.
It should be legal to call Tcl_Eval() from inside of Tcl_Eval of c-command-extension because the documentation for the "Tcl Library" States that for tcl_eval, it is legal to make nested calls to evaluate other commands. I just don't know how to copy the object result from Tcl_Eval to "return" object for c-extension procedure.
I see two problems here. You can't set the return value of a command to be the value of an array because arrays are not values. Arrays are collections of variables indexed by a string. It's a common misunderstanding. You could return the value of an element of an array. If you want a key / value map that is a proper Tcl value, consider a dictionary. Dictionaries are values and can be returned as the value of a command.
The second problem why are you using Tcl_Eval() to create an array. It is much simpler to use Tcl_SetVar() or one of its several variations to build an array.
The recommended way to set an array (given you're working with char* values in the first place) is using calls to Tcl_SetVar2 (so named because it takes variable names as two parts).
Tcl_SetVar2(interp, "tmp", "key1", "value1", 0);
Tcl_SetVar2(interp, "tmp", "key2", "value2", 0);
Idiomatically, you'd use a name passed in as an argument to your C command implementation as an argument, so that the caller can tell you what variable to write into, and you'd want to check the results too:
int MyCommand(
ClientData clientData,
Tcl_Interp* interp,
int argc,
char* argv[])
{
// Missing: check # of arguments
if (Tcl_SetVar2(interp, argv[1], "key1", "value1", 0) == NULL)
return TCL_ERROR;
if (Tcl_SetVar2(interp, argv[1], "key2", "value2", 0) == NULL)
return TCL_ERROR;
return TCL_OK;
}
You'd then call that like this:
MyCommand x
# It has no meaningful result.
puts $x(key1)
puts $x(key2)

How to pass array as argument inside ARGV

I have a ruby script that takes two inputs for ARGV. The second input is an array of files. I'm having trouble iterating through the file array passed to ARGV. Here is what I have so far:
arg1, FILES = ARGV
FILES.each do |fname|
#do something with fname
end
I'm running my script from the command line like this:
ruby myScript.rb arg1 ['path/to/file1.jpg', '/path/to/file2.jpg']
And I'm getting the following error:
zsh: bad pattern: [path/to/file1.jpg,
Enclosing the array argument in single quotes like this:
ruby myScript.rb arg1 '['path/to/file1.jpg', '/path/to/file2.jpg']'
Produces a different error, as it interprets it as a String rather than array.
How can I accomplish this correctly?
Use
arg1, *FILES = ARGV
and don't place any brackets or commas during invocation:
ruby myScript.rb arg1 file1 file2 file3
EDIT: If you want to add another argument, you can do:
arg1, arg2, *FILES = ARGV
or
arg1, *FILES, arg2 = ARGV
You can't pass an array as a command-line argument. All arguments are passed as strings.
But given your code, you could just pass the arguments like this:
$ ruby myScript.rb arg1 path/to/file1.jpg /path/to/file2.jpg
And then, change your first line of code to this:
arg1, *FILES = ARGV
And after, arg1 = 'arg1' and FILES = ['path/to/file1.jpg', 'path/to/file2.jpg'].
You can either split manually, e.g. arg, arr = ARGV[0], ARGV[1..-1] or use the splat operator arg, *arr = ARGV
arg1, _files = ARGV
files = eval(_files)
files.each { |f| ... }
But there are reasons to not use eval (see Is 'eval' supposed to be nasty?).
You might pass the files list as a json string and then do JSON.parse on it to be safer, e.g.:
require 'json'
arg1, _files = ARGV
files = JSON.parse(_files)
files.each { |f| ... }
#> ruby myScript.rb arg1 '["path/to/file1.jpg", "/path/to/file2.jpg"]'

Regex to detect begining of the c function body

I working on a perl script that prints the required function body from the c source file. i have written a regex to get to the start of the function body as
(/(void|int)\s*($function_name)\s*\(.*?\)\s*{/s
but this works only for functions returning void or int(basic types)
how can i change this regex to handle user defined datatypes (struct or pointers)
Try this one (untested!), although it does expect the function to start at the beginning of a line :
/
^ # Start of line
\s*(?:struct\s+)[a-z0-9_]+ # return type
\s*\** # return type can be a pointer
\s*([a-z0-9_]+) # Function name
\s*\( # Opening parenthesis
(
(?:struct\s+) # Maybe we accept a struct?
\s*[a-z0-9_]+\** # Argument type
\s*(?:[a-z0-9_]+) # Argument name
\s*,? # Comma to separate the arguments
)*
\s*\) # Closing parenthesis
\s*{? # Maybe a {
\s*$ # End of the line
/mi # Close our regex and mark as case insensitive
You can squeeze all of these into a single line by removing the whitespace and comments.
Parsing code with a regex is generally hard though, and this regex is not perfect at all.

Embedding Ruby, calling a function from C

I'm writing an app that calls ruby code from c. I am having a little difficulty and wondered if anyone could point me in the rite direction.
I currently have in my C.
#include ruby.h
main()
{
ruby_init();
rb_require("myRubyFile");
rb_funcall(rb_module_new(), rb_intern("RubyFunction"), 0, NULL);
}
My ruby file is in the same directory as my c file and is called myRubyFile.rb and contains a definition of the function RubyFunction().
This is a cut down of what I actually want to do, just making it more readable for others. I just require some feedback as to whether this is the correct method to call ruby code from my c file.
Regards
Short answer:
extern VALUE rb_vm_top_self(void); /* Assumes 1.9. Under 1.8, use the global
* VALUE ruby_top_self
*/
...
rb_funcall(rb_vm_top_self(), /* irb> RubyFunction() */
rb_intern("RubyFunction"), /* irb> self.RubyFunction() # same thing */
0,
NULL);
Longer answer:
The first argument to rb_funcall is the receiver of the method call.
Assuming you defined RubyFunction() outside of any explicit class or module context, then it is added to the eigenclass of the implicit, main object at the "top level" of every ruby vm.
In ruby, this object is accessible as the top-level self:
$ cat myRubyFile.rb
# file: myRubyFile.rb
def foo
puts "foo"
end
$ irb
irb> require "myRubyFile"
=> true
irb> foo
foo
=> nil
irb> self.foo() # same thing, more explicit
foo
=> nil
irb> self
=> main
In C under 1.9 it is accessible as indicated above.
I try to use the following approach:
Basic struct to share data
typedef struct ruby_shared_data {
VALUE obj;
ID method_id;
int nargs;
VALUE args[4];
} ruby_shared_data;
Create a function for call ruby objects on some part of your code
static VALUE ruby_callback(VALUE ptr) {
ruby_shared_data *data = (ruby_shared_data*)ptr;
return rb_funcall2(data->obj,data->method_id,data->nargs,data->args);
}
On some part of your code...
ruby_shared_data rbdata;
rbdata.obj = obj;
rbdata.method_id = rb_intern("mycallback");
rbdata.nargs = 1;
rbdata.args[0] = rb_str_new2("im a parameter");
int error = 0;
VALUE result = rb_protect(ruby_callback,(VALUE)&rbdata,&error);
if (error)
throw "Ruby exception on callback";
Is always a good idea to wrap rb_funcall with rb_protect.
Another interesting thing is to know the parameters of the callback, one approach is the following
ruby_shared_data rbdata;
rbdata.obj = callback;
rbdata.method_id = rb_intern("arity");
rbdata.nargs = 0;
int error = 0;
VALUE result = rb_protect(ruby_callback,(VALUE)&rbdata,&error);
if (error)
throw "Ruby exception on callback";
narguments = NUM2INT(result);
I don't like to call ruby from inside C unless you have complex C project which you don't want to re-build in ruby.
There are two ways to interact between C and ruby. You can extend ruby with code written in C. See SWIG.
Or you can embed ruby, see here, here and here.
BTW, what do you mention is "embed" ruby, not "extend" ruby.

Resources