Callback to Perl interpreter in C--something simpler than XS?

Discussion in 'Perl Misc' started by Kevin Walzer, Jan 25, 2013.

  1. Kevin Walzer

    Kevin Walzer Guest

    I'm trying to implement a Perl interface to a subset of Apple's
    AppleEvent framework, allowing a Perl app to respond to AppleScript
    commands. CPAN has a module devoted to this, but it is part of a larger
    framework that is suffering from bit-rot, has large swaths of deprecated
    and obsolete API calls, and won't build under 64-bit.

    I'm moving right along with the AppleEvent / C API stuff, but I'm not
    quite clear on how to convert this vanilla C code into something that
    Perl can interface with. What I want to do is to pass a subroutine name
    as a string to the Perl interpreter that the interpreter can run.

    Here's one example C function:

    //Handler for AppleEvents
    static OSErr AEScriptsAEHandler(const AppleEvent *theAppleEvent,
    AppleEvent *reply, long refCon) {

    OSErr err = noErr;
    AEDesc returnData;
    AEEventID eventID;
    OSType typeCode;
    AEDesc directParameter;
    char *script;

    //Read the AppleEvent
    err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeUnicodeText,
    &returnData);

    //get event ID to look up in CFDictionary
    err = AEGetAttributePtr(theAppleEvent, keyEventIDAttr, typeType,
    NULL, &eventID, sizeof(eventID), NULL );

    //get direct parameter
    err = AEGetKeyDesc(theAppleEvent, keyDirectObject, typeType,
    &directParameter);

    CFStringRef scriptName;
    stringeventID = UTCreateStringForOSType(eventID);
    scriptName = CFDictionaryGetValue(aeDict, stringeventID);

    CFIndex length = CFStringGetLength(scriptName);
    CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length,
    kCFStringEncodingUTF8);
    script = (char *)malloc(maxSize);
    CFStringGetCString(scriptName, script, maxSize, kCFStringEncodingUTF8);

    //actually run the script
    err = ExecuteScript(script, NULL);
    }

    What this code does is check a CFDictionary ref for a value that
    corresponds to the ID of a specific Apple event ("script"), and my idea
    is to pass the "script" string to a function called "ExecuteScript" that
    would incorporate the Perl interpreter. Is there a simpler way to
    implement this than wading through all the XSUB goo?

    In Tcl's C API it's simple as initializing a Tcl interpreter:

    static Tcl_Interp *myInterp;

    and then calling this function:

    Tcl_Eval(myInterp, script);

    In looking at the XS bits, am I missing something simpler that might
    serve my needs? The idea here is that I'm passing a single subroutine
    call to the Perl interpreter, then I'll be returning the subroutine's
    output back to the AppleEvent C API as a string. There aren't a lot of
    hooks or complex data structures that need to be addressed: I just want
    to have this as a loadable module that can interact with the running
    interpreter.

    Thanks for any advice,
    Kevin


    --
    Kevin Walzer
    Code by Kevin
    http://www.codebykevin.com
    Kevin Walzer, Jan 25, 2013
    #1
    1. Advertising

  2. Kevin Walzer

    Kevin Walzer Guest

    On 1/26/13 5:09 AM, Ben Morrow wrote
    >
    > ...and now you've gone back to talking about extending perl again. I'm
    > confused. How does your program start? Do you want to start in Perl,
    > call into C, and then call back into Perl again? That's entirely
    > possible, but you have to use both the perlxs and perlcall facilities.


    OK, perhaps this is the way I need to go. I'm not embedding Perl; I'm
    creating an AppleEvents wrapper that will be loaded into the Perl
    interpreter as a package.

    >
    > However, that C above looks to me as though it's a callback from some
    > Apple facility. How does that get invoked? If it gets called
    > asynchronously, while there is other Perl code being executed, you will
    > probably need to use the ithreads mechanism to prevent the two bits of
    > Perl from interfering with each other.


    The AppleEvent API is a form of IPC where an app can communicate with
    another app via sending AppleEvents. The high-level interface is the
    AppleScript language. Something like this:

    tell app "Foo"
    dosomething()
    end tell

    My Perl app will be the recipient of the "tell" command in this
    instance. My C code is intended to register the Apple Events the app
    will handle with the OS, which has to be done in C. But the actual
    execution of the code has to be done at the Perl level by the running
    interpreter. Does this make sense?

    Tcl's C API allows for easy two-way communication between the running
    interpreter and code at the C level, and it can be done so without
    threads. Here's some similar code in Tcl's C API:

    char *data = ckalloc(size + 1);
    theErr = AEGetParamPtr(event, keyDirectObject, typeUTF8Text, NULL, data,
    size, NULL);
    if (theErr == noErr) {
    tclErr = Tcl_EvalEx(interp, data, size, TCL_EVAL_GLOBAL);
    }

    if (tclErr >= 0) {
    int reslen;
    const char *result =
    Tcl_GetStringFromObj(Tcl_GetObjResult(interp), &reslen);

    if (tclErr == TCL_OK) {
    AEPutParamPtr(reply, keyDirectObject, typeChar, result, reslen);
    } else {
    AEPutParamPtr(reply, keyErrorString, typeChar, result, reslen);
    AEPutParamPtr(reply, keyErrorNumber, typeSInt32, (Ptr) &tclErr,
    sizeof(int));
    }

    The TclEvalEx() call executes the Tcl script, and the output is obtained
    at the C level by the Tcl_GetStringFromObj(Tcl_GetObjResult(interp),
    &reslen) call, and then passed back along the AppleEvents mechanism
    (AEPutParamPtr).

    It seems that Perl has two separate API's for interacting with C, rather
    than one.

    I'll dig deeper into the XS API and see if I can make that dance the way
    I want to. I don't want to start a separate Perl interpreter, but rather
    use the main one I have. The callback part is what's leading me in this
    direction; otherwise I'd just use SWIG.

    Other suggestions, anything I've missed, are appreciated.

    Thanks,
    Kevin

    --
    Kevin Walzer
    Code by Kevin
    http://www.codebykevin.com
    Kevin Walzer, Jan 26, 2013
    #2
    1. Advertising

  3. Kevin Walzer

    Kevin Walzer Guest

    On 1/26/13 9:20 AM, Ben Morrow wrote:
    > I would recommend staying away from SWIG, at least for perl. I've never
    > seen a SWIG-generated perl extension that was anything other than
    > painful to use; IMHO it's trying too hard to provide a cross-interpreter
    > interface, and the various interpreters' APIs aren't really compatible
    > enough for that to work. A basic XS interface that doesn't do anything
    > clever is just a matter of going through and listing the functions
    > involved.


    I think I'm going to take a different tack here: ActiveState's Tkx
    module, which allows you to put a Tk interface on a Perl app, also
    includes fairly complete integration with the Tcl interpreter. I have a
    working Tcl AppleEvent implementation in my apps written in Tcl, and I
    can probably access that from Perl, and even use Perl callbacks, via the
    Tkx module. I had thought this would involve a lot of overhead and
    wanted to see if I could get a Perl-native implementation going, but it
    seems too convoluted for me. Thanks for your time.

    --Kevin

    --
    Kevin Walzer
    Code by Kevin
    http://www.codebykevin.com
    Kevin Walzer, Jan 28, 2013
    #3
  4. Kevin Walzer

    greymaus Guest

    On 2013-01-28, Kevin Walzer <> wrote:
    > On 1/26/13 9:20 AM, Ben Morrow wrote:
    >> I would recommend staying away from SWIG, at least for perl. I've never
    >> seen a SWIG-generated perl extension that was anything other than
    >> painful to use; IMHO it's trying too hard to provide a cross-interpreter
    >> interface, and the various interpreters' APIs aren't really compatible
    >> enough for that to work. A basic XS interface that doesn't do anything
    >> clever is just a matter of going through and listing the functions
    >> involved.

    >
    > I think I'm going to take a different tack here: ActiveState's Tkx
    > module, which allows you to put a Tk interface on a Perl app, also
    > includes fairly complete integration with the Tcl interpreter. I have a
    > working Tcl AppleEvent implementation in my apps written in Tcl, and I
    > can probably access that from Perl, and even use Perl callbacks, via the
    > Tkx module. I had thought this would involve a lot of overhead and
    > wanted to see if I could get a Perl-native implementation going, but it
    > seems too convoluted for me. Thanks for your time.
    >
    > --Kevin
    >


    Man2Doctor "When I hold my arm this way, I get an incredible pain"
    Doctor2Man "Well, dont hold your arm that way"


    --
    maus
    greymaus, Jan 28, 2013
    #4
  5. Kevin Walzer <> writes:
    > On 1/26/13 9:20 AM, Ben Morrow wrote:
    >> I would recommend staying away from SWIG, at least for perl. I've never
    >> seen a SWIG-generated perl extension that was anything other than
    >> painful to use; IMHO it's trying too hard to provide a cross-interpreter
    >> interface, and the various interpreters' APIs aren't really compatible
    >> enough for that to work. A basic XS interface that doesn't do anything
    >> clever is just a matter of going through and listing the functions
    >> involved.

    >
    > I think I'm going to take a different tack here: ActiveState's Tkx
    > module, which allows you to put a Tk interface on a Perl app, also
    > includes fairly complete integration with the Tcl interpreter. I have
    > a working Tcl AppleEvent implementation in my apps written in Tcl, and
    > I can probably access that from Perl, and even use Perl callbacks, via
    > the Tkx module. I had thought this would involve a lot of overhead and
    > wanted to see if I could get a Perl-native implementation going, but
    > it seems too convoluted for me.


    That's IMHO an impression you mostly got because you were seeking for
    the Tcl-interface you're familiar with in Perl --- but the Perl
    interface is different. In the following, I'm going to assume that the
    AppleScript event handler is registered with some Apple library and
    then called from the library as part of some kind of 'event loop'
    processing. If this is so, the way to integrate this with perl would
    involve:

    - provide an initialization function callable from perl via
    XS which performs any initialization which may be necessary
    and enables the caller to register a Perl subroutine
    supposed to handle the events

    - provide a second perl-callable function which enters the
    event loop

    The C event handler routine would then need to invoke the Perl
    callback (=> perlcall) and pass the results back to the library after
    the Perl program called the init rouine and entered the event loop.

    That's not really difficult and while XS seems somewhat dauting at a
    first glance, for simple cases, like the one you have here, declaring
    the signatures of the Perl entry points should be sufficient. As a
    contrived example and without the boilerplate, for the init routine,
    this could look like this:

    int
    event_library_init(subref)
    SV * subref

    which declares an XS routine returning an int to Perl and taking a
    single argument which will be a pointer to a 'scalar value' (SV). The
    actual code will then be generated by the xsubpp preprocessor. The
    h2xs program is also very helpful to 'jumpstart' a new extension
    module.
    Rainer Weikusat, Jan 28, 2013
    #5
  6. greymaus <> writes:
    > On 2013-01-28, Kevin Walzer <> wrote:
    >> On 1/26/13 9:20 AM, Ben Morrow wrote:
    >>> I would recommend staying away from SWIG, at least for perl. I've never
    >>> seen a SWIG-generated perl extension that was anything other than
    >>> painful to use; IMHO it's trying too hard to provide a cross-interpreter
    >>> interface, and the various interpreters' APIs aren't really compatible
    >>> enough for that to work. A basic XS interface that doesn't do anything
    >>> clever is just a matter of going through and listing the functions
    >>> involved.

    >>
    >> I think I'm going to take a different tack here: ActiveState's Tkx
    >> module, which allows you to put a Tk interface on a Perl app, also
    >> includes fairly complete integration with the Tcl interpreter. I have a
    >> working Tcl AppleEvent implementation in my apps written in Tcl, and I
    >> can probably access that from Perl, and even use Perl callbacks, via the
    >> Tkx module. I had thought this would involve a lot of overhead and
    >> wanted to see if I could get a Perl-native implementation going, but it
    >> seems too convoluted for me. Thanks for your time.
    >>
    >> --Kevin
    >>

    >
    > Man2Doctor "When I hold my arm this way, I get an incredible pain"
    > Doctor2Man "Well, dont hold your arm that way"


    Son2Father: Whenever I try to stand up and walk, I fall down!
    Father2Son: You're only seventeen, kid, and should really stay away
    from this adult stuff for somewhat longer. While it won't help you
    stay young, it might even make you feel as if you remained a happy
    toddler for some years to come!
    Rainer Weikusat, Jan 28, 2013
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    9
    Views:
    350
    Douglas Alan
    Mar 8, 2006
  2. arubin
    Replies:
    8
    Views:
    466
    jacko
    Sep 26, 2006
  3. Hendrik van Rooyen
    Replies:
    6
    Views:
    357
    Hendrik van Rooyen
    Oct 17, 2006
  4. Replies:
    3
    Views:
    754
    Ziga Seilnacht
    Jan 3, 2007
  5. Jeff
    Replies:
    6
    Views:
    196
Loading...

Share This Page