• Re: make c/c++ data structures accesible to tcl

    From Georgios Petasis@21:1/5 to All on Thu Mar 24 22:00:32 2022
    Hi,

    In my view, SWIG was build to address this exact same problem. I have
    been using it for years (15+).

    http://www.swig.org/

    There is highly probable that it will read you c++ header files,
    unmodified or with little modification, and write all the "glue" code
    required. It supports even STL structures...

    George

    Στις 24/3/2022 21:44, ο/η pd έγραψε:
    Hi,

    I was wondering for the best way to make c and c++ data structures accesible to tcl running as a script engine for a c/c++ program.

    The idea is to give scripting capabilities to a C/C++ program using tcl as a extension scripting language in a way users can control the main program using tcl. So I need to access data structures (structs, classes...) from tcl.

    To make it clear let me use and example, let's say I have a C program implementing a phone list, so I have contacts as "objects" (among others), I want to let my users to script the program using tcl for example having a port listening to tcl commads
    or a config file the program reads at startup. I want users to issue commands like:

    foreach contact in $phonelist {
    puts $contact
    puts [name $contact]
    }

    where phonelist is a liked list of C struct Contact and contact is a Contact struct like:

    struct Contact {
    char *name;
    char *surname;
    char *phone_number;
    }

    The problem is how to access the data structure in tcl in a way like:

    puts "$contact.name $contact.surname"

    being more tclish like:

    puts "[name $contact] [surname $contact]"

    After a bit thinking on it , my idea is the tcl way of doing this is not giving access to the data structure but to design a set of commands to access the data and extend the interpreter with those commands, for example:

    puts "[contact name $contact] [contact surname $contact] [contact phone $contact]"

    or something like this.

    Is this the better way to proceed to give tcl access to "objects" of the C program? this also would apply to accessing classes and objects both methods and properties.

    regards

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From pd@21:1/5 to All on Thu Mar 24 12:44:49 2022
    Hi,

    I was wondering for the best way to make c and c++ data structures accesible to tcl running as a script engine for a c/c++ program.

    The idea is to give scripting capabilities to a C/C++ program using tcl as a extension scripting language in a way users can control the main program using tcl. So I need to access data structures (structs, classes...) from tcl.

    To make it clear let me use and example, let's say I have a C program implementing a phone list, so I have contacts as "objects" (among others), I want to let my users to script the program using tcl for example having a port listening to tcl commads or
    a config file the program reads at startup. I want users to issue commands like:

    foreach contact in $phonelist {
    puts $contact
    puts [name $contact]
    }

    where phonelist is a liked list of C struct Contact and contact is a Contact struct like:

    struct Contact {
    char *name;
    char *surname;
    char *phone_number;
    }

    The problem is how to access the data structure in tcl in a way like:

    puts "$contact.name $contact.surname"

    being more tclish like:

    puts "[name $contact] [surname $contact]"

    After a bit thinking on it , my idea is the tcl way of doing this is not giving access to the data structure but to design a set of commands to access the data and extend the interpreter with those commands, for example:

    puts "[contact name $contact] [contact surname $contact] [contact phone $contact]"

    or something like this.

    Is this the better way to proceed to give tcl access to "objects" of the C program? this also would apply to accessing classes and objects both methods and properties.

    regards

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From briang@21:1/5 to All on Thu Mar 24 13:46:10 2022
    On Thursday, March 24, 2022 at 12:44:51 PM UTC-7, pd wrote:
    Hi,

    I was wondering for the best way to make c and c++ data structures accesible to tcl running as a script engine for a c/c++ program.

    The idea is to give scripting capabilities to a C/C++ program using tcl as a extension scripting language in a way users can control the main program using tcl. So I need to access data structures (structs, classes...) from tcl.

    To make it clear let me use and example, let's say I have a C program implementing a phone list, so I have contacts as "objects" (among others), I want to let my users to script the program using tcl for example having a port listening to tcl commads
    or a config file the program reads at startup. I want users to issue commands like:

    foreach contact in $phonelist {
    puts $contact
    puts [name $contact]
    }

    where phonelist is a liked list of C struct Contact and contact is a Contact struct like:

    struct Contact {
    char *name;
    char *surname;
    char *phone_number;
    }

    The problem is how to access the data structure in tcl in a way like:

    puts "$contact.name $contact.surname"

    being more tclish like:

    puts "[name $contact] [surname $contact]"

    After a bit thinking on it , my idea is the tcl way of doing this is not giving access to the data structure but to design a set of commands to access the data and extend the interpreter with those commands, for example:

    puts "[contact name $contact] [contact surname $contact] [contact phone $contact]"

    or something like this.

    Is this the better way to proceed to give tcl access to "objects" of the C program? this also would apply to accessing classes and objects both methods and properties.

    regards

    The Tk paradigm is one way to do this. Define a command to obtain a phone list, lets call it [new_phonelist]:

    set phonelist [new_phonelist -from somewhere]

    The "new..." command, when invoked, will then register a new command, say pl341592. That command has the form: pl341592 <subcommand> ?<arguments?
    Let's say that one subcommand is "contacts" which returns a list of contact handles. These are also tcl commands:

    foreach contact in $phonelist {
    puts $contact
    puts [$contact name]
    puts [$contact address]
    puts [$contact cellphone]
    }

    On the C/C++ side, the command implementation can be a simple piece of dispatch code for a "phonelist" command that uses the clientData field to hold the actual C++ object handle. This way it can access the relevant fields or call relevant methods.

    You can get more insight on this by exploring the Tk implementation for widgets, at least the command interface portion.

    I hope this helps.
    -Brian

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Robert Heller@21:1/5 to petasisg@yahoo.gr on Thu Mar 24 15:40:15 2022
    YES, SWIG is actually quite wonderful. About the only things you will need to deal with are:

    "hiding" private members from Tcl:

    class SomeClass {
    #ifndef SWIG
    private:
    int x;
    #endif
    public:
    int y;
    };

    In some cases you might want to deal specially with certain types of arrays
    and pointers. And certain types of C/C++ "idioms" that Tcl does differently (stuff like "char *buffer, int bufferlen" for example). And maybe handle enums in a "Tcl" way (create typewraps that "convert" between numerical and symbolic ENums). And maybe Tcl-ish foreach like control structures as wrappers to implement C++ interator loops. In some cases this is just to make things more convient and in other cases there might be things that work fine when coding C++ but might be awkward in Tcl, that could be tweaked with ifdefs and the use of typewraps and other SWIG "tricks". All of this is optional, of course --
    run SWIG over the unmodified header files initially. Then go from there.

    At Thu, 24 Mar 2022 22:00:32 +0200 Georgios Petasis <petasisg@yahoo.gr> wrote:


    Hi,

    In my view, SWIG was build to address this exact same problem. I have
    been using it for years (15+).

    http://www.swig.org/

    There is highly probable that it will read you c++ header files,
    unmodified or with little modification, and write all the "glue" code required. It supports even STL structures...

    George

    Στις 24/3/2022 21:44, ο/η pd έγραψε:
    Hi,

    I was wondering for the best way to make c and c++ data structures accesible to tcl running as a script engine for a c/c++ program.

    The idea is to give scripting capabilities to a C/C++ program using tcl as a extension scripting language in a way users can control the main program using tcl. So I need to access data structures (structs, classes...) from tcl.

    To make it clear let me use and example, let's say I have a C program implementing a phone list, so I have contacts as "objects" (among others), I want to let my users to script the program using tcl for example having a port listening to tcl
    commads or a config file the program reads at startup. I want users to issue commands like:

    foreach contact in $phonelist {
    puts $contact
    puts [name $contact]
    }

    where phonelist is a liked list of C struct Contact and contact is a Contact struct like:

    struct Contact {
    char *name;
    char *surname;
    char *phone_number;
    }

    The problem is how to access the data structure in tcl in a way like:

    puts "$contact.name $contact.surname"

    being more tclish like:

    puts "[name $contact] [surname $contact]"

    After a bit thinking on it , my idea is the tcl way of doing this is not giving access to the data structure but to design a set of commands to access the data and extend the interpreter with those commands, for example:

    puts "[contact name $contact] [contact surname $contact] [contact phone $contact]"

    or something like this.

    Is this the better way to proceed to give tcl access to "objects" of the C program? this also would apply to accessing classes and objects both methods and properties.

    regards




    --
    Robert Heller -- Cell: 413-658-7953 GV: 978-633-5364
    Deepwoods Software -- Custom Software Services
    http://www.deepsoft.com/ -- Linux Administration Services
    heller@deepsoft.com -- Webhosting Services

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From pd@21:1/5 to All on Fri Mar 25 02:25:17 2022
    SWIG is pretty interesting, I was reading it and it solves the problem with elegance.

    But I was asking for the best way to design a tcl interface to a program in C/C++, one way may be the swig way, to give direct access to underneath data structures and even procudures (methods, functions...) but I feel a best way or at least more tcl
    style way is to define a set of commands to present a interface from tcl to the data and procedures in the C side, you can define commands and subcommands something like string does or like tk, as pointed by briang

    My point is even when swig way is more direct and with a full mapping with original objects, the tcl way of defining a set of commands is better in the sense it is more independet of original objects and C implementation, the goal is don't have to know
    the structure of datatypes, objects and their relations to use them from tcl (I know you can also do the tcl way using swig)

    For example, using the phone list example, maybe the C implemetation is a linked list of structs like:

    struct Contact {
    char *name;
    char *phone_number;
    struct Contact *next
    }

    the direct swig way would give a tcl:

    Contact c
    while {expr {[c next] ne "NULL"}} {
    puts "[c name] [c phone_number]"
    }

    But I don't want to know of "next" procedure, an implementation detail, I only want to know about phonelist and contacts, so maybe a better way would be:

    phonelist pl
    foreach c in pl {
    puts "[contact name $c] [contact phone_number $c]"
    }

    or even:

    phonelist -create pl
    foreach c in [phonelist contacts] {
    puts "[phonelist contact name $c] [phonelist contact phone_number $c]"
    }

    maybe this last one is more in the line of what briang said about using the tk way.

    My question is what you think is a better approach, something akin the swig direct way or something akin the tcl commands way



    El jueves, 24 de marzo de 2022 a las 21:46:13 UTC+1, briang escribió:

    The Tk paradigm is one way to do this. Define a command to obtain a phone list, lets call it [new_phonelist]:
    The "new..." command, when invoked, will then register a new command, say pl341592. That command has the form: pl341592 <subcommand> ?<arguments?
    On the C/C++ side, the command implementation can be a simple piece of dispatch code for a "phonelist" command that uses the clientData field to hold the actual C++ object handle. This way it can access the relevant fields or call relevant methods.

    You can get more insight on this by exploring the Tk implementation for widgets, at least the command interface portion.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Georgios Petasis@21:1/5 to All on Fri Mar 25 16:11:48 2022
    Even in your case, what I would do is write this "Abstraction" layer in
    C++, and expose this through SWIG... :-)

    George

    Στις 25/3/2022 11:25, ο/η pd έγραψε:
    SWIG is pretty interesting, I was reading it and it solves the problem with elegance.

    But I was asking for the best way to design a tcl interface to a program in C/C++, one way may be the swig way, to give direct access to underneath data structures and even procudures (methods, functions...) but I feel a best way or at least more tcl
    style way is to define a set of commands to present a interface from tcl to the data and procedures in the C side, you can define commands and subcommands something like string does or like tk, as pointed by briang

    My point is even when swig way is more direct and with a full mapping with original objects, the tcl way of defining a set of commands is better in the sense it is more independet of original objects and C implementation, the goal is don't have to
    know the structure of datatypes, objects and their relations to use them from tcl (I know you can also do the tcl way using swig)

    For example, using the phone list example, maybe the C implemetation is a linked list of structs like:

    struct Contact {
    char *name;
    char *phone_number;
    struct Contact *next
    }

    the direct swig way would give a tcl:

    Contact c
    while {expr {[c next] ne "NULL"}} {
    puts "[c name] [c phone_number]"
    }

    But I don't want to know of "next" procedure, an implementation detail, I only want to know about phonelist and contacts, so maybe a better way would be:

    phonelist pl
    foreach c in pl {
    puts "[contact name $c] [contact phone_number $c]"
    }

    or even:

    phonelist -create pl
    foreach c in [phonelist contacts] {
    puts "[phonelist contact name $c] [phonelist contact phone_number $c]"
    }

    maybe this last one is more in the line of what briang said about using the tk way.

    My question is what you think is a better approach, something akin the swig direct way or something akin the tcl commands way



    El jueves, 24 de marzo de 2022 a las 21:46:13 UTC+1, briang escribió:

    The Tk paradigm is one way to do this. Define a command to obtain a phone list, lets call it [new_phonelist]:
    The "new..." command, when invoked, will then register a new command, say pl341592. That command has the form: pl341592 <subcommand> ?<arguments?
    On the C/C++ side, the command implementation can be a simple piece of dispatch code for a "phonelist" command that uses the clientData field to hold the actual C++ object handle. This way it can access the relevant fields or call relevant methods.

    You can get more insight on this by exploring the Tk implementation for widgets, at least the command interface portion.



    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From briang@21:1/5 to This makes the Tcl code easier to on Fri Mar 25 08:48:59 2022
    On Friday, March 25, 2022 at 2:25:20 AM UTC-7, pd wrote:
    SWIG is pretty interesting, I was reading it and it solves the problem with elegance.

    But I was asking for the best way to design a tcl interface to a program in C/C++, one way may be the swig way, to give direct access to underneath data structures and even procudures (methods, functions...) but I feel a best way or at least more tcl
    style way is to define a set of commands to present a interface from tcl to the data and procedures in the C side, you can define commands and subcommands something like string does or like tk, as pointed by briang

    My point is even when swig way is more direct and with a full mapping with original objects, the tcl way of defining a set of commands is better in the sense it is more independet of original objects and C implementation, the goal is don't have to know
    the structure of datatypes, objects and their relations to use them from tcl (I know you can also do the tcl way using swig)

    For example, using the phone list example, maybe the C implemetation is a linked list of structs like:

    struct Contact {
    char *name;
    char *phone_number;
    struct Contact *next
    }

    Mapping the C data and its structure to Tcl first requires understanding the available data storage options in Tcl.

    There's 4 basic values in Tcl:

    A (scalar) string which maps to a C scalar (int, double, char*).
    A list which maps to a C array (i.e. int x[100]).
    A dict which maps (loosely) to a C struct.
    An array which maps to a C hash table. (ok, not really a "value")

    The list and dict are composites of scalar or can be composites of lists or dicts.
    Arrays are named and cannot be treated as pure values, at least not easily.

    There is also TclOO, which is a class mechanism, but I don't think you are looking to map the C++ classes and objects into Tcl directly, but that would be one possibility.


    the direct swig way would give a tcl:

    Contact c
    while {expr {[c next] ne "NULL"}} {
    puts "[c name] [c phone_number]"
    }


    Side note: the [expr] here is redundant.

    But I don't want to know of "next" procedure, an implementation detail, I only want to know about phonelist and contacts, so maybe a better way would be:

    phonelist pl
    foreach c in pl {
    puts "[contact name $c] [contact phone_number $c]"
    }

    or even:

    phonelist -create pl
    foreach c in [phonelist contacts] {
    puts "[phonelist contact name $c] [phonelist contact phone_number $c]"
    }

    This style may not be what you would like to see, but you do have to consider that the call to [phonelist contacts] must first fully replicate, from start to finish, the entire list of contact info into a Tcl list before the [foreach] command can iterate
    upon it. This may be impractical if the contact list has 500 million entries, from both a space and time aspect. Something to consider carefully when designing the interface.


    maybe this last one is more in the line of what briang said about using the tk way.

    The "Tk" way inverts the commands: [$c name] instead of [phonelist contact name $c]. This makes the Tcl code easier to write since the class name, "contact", doesn't have to be replicated in each expression, the class name is implicit in $c.


    My question is what you think is a better approach, something akin the swig direct way or something akin the tcl commands way

    It really comes down to how the Tcl script writers will be using/consuming the data. Also, the efficiency of the mapping is always an important consideration.

    El jueves, 24 de marzo de 2022 a las 21:46:13 UTC+1, briang escribió:

    The Tk paradigm is one way to do this. Define a command to obtain a phone list, lets call it [new_phonelist]:
    The "new..." command, when invoked, will then register a new command, say pl341592. That command has the form: pl341592 <subcommand> ?<arguments?
    On the C/C++ side, the command implementation can be a simple piece of dispatch code for a "phonelist" command that uses the clientData field to hold the actual C++ object handle. This way it can access the relevant fields or call relevant methods.

    You can get more insight on this by exploring the Tk implementation for widgets, at least the command interface portion.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From pd@21:1/5 to All on Sat Mar 26 12:25:27 2022
    El viernes, 25 de marzo de 2022 a las 16:49:02 UTC+1, briang escribió:

    phonelist -create pl
    foreach c in [phonelist contacts] {
    puts "[phonelist contact name $c] [phonelist contact phone_number $c]"
    }
    This style may not be what you would like to see, but you do have to consider that the call to [phonelist contacts] must first fully replicate, from start to finish, the entire list of contact info into a Tcl list before the [foreach] command can
    iterate upon it. This may be impractical if the contact list has 500 million entries, from both a space and time aspect. Something to consider carefully when designing the interface.

    this is a good point, obviously you have to consider performance and limitations, but having all that into account I still believe it would better to design a command based interface not coupled with C design or implementation, it's only you have to
    design it with care ;-).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From EL@21:1/5 to eukelade@gmail.com on Sun Mar 27 06:23:37 2022
    pd <eukelade@gmail.com> wrote:

    To make it clear let me use and example, let's say I have a C program implementing a phone list, so I have contacts as "objects" (among
    others), I want to let my users to script the program using tcl for
    example having a port listening to tcl commads or a config file the
    program reads at startup. I want users to issue commands like:

    SWIG was already mentioned. You can also do manually what SWIG does automatically, that is write a wrapper around your C/C++ data and
    functions. Often that might be more desirable.

    I would like to add: consider the security of your program. Scripting
    enables your users to manipulate the data of the running program and maybe
    read out information that might be confidential. Plus the possibillity to
    build in new buffer overruns in your extension code and things they can do
    with the Tcl interp, which might have unwanted side effects. If that is an issue, consider safe interpreters and put sensible measures of control to
    what exactly is exposed to the scripting side of your application.

    Just a hint ;)

    --
    EL

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)