User Tools

Site Tools


Using the inbuilt embedded perl functions

Let me start out by saying that it is possible, and still advisable in most cases to use the EXEC command to do many of the things you want from an external scripting language. The external script will run as a separate process which will save you performance problems and memory.

The reason you might want to use the $perl*() functions are in those situations where you need data to be returned from the perl script or if you need it to do something within the epic environment from that script. These mechanisms are faster and much more stable in these functions than trying to do the same thing with an /exec.

The perl environment can be used at many levels, from being a helper to your irc script to almost entirely driving your script from within perl. Most perl modules are available for use from within the perl environment, but those that don't return control to your script are unlikely to be useful. It is also makes it possible to alter epics process environment, such as redefining signals, forking and making other random system calls, which is not always a good idea.

The embedded perl script starts with a call to $perl(expression). When $perl() is called, the perl environment is initialized and the expression is evaluated.

Typically what you want is an expression that loads a script or defines subroutines for use from your epic environment with the $perlcall() functions.

At this point, the $perlcall() and $perlxcall() functions can be used to call whatever subroutines have been defined. $perlcall(sub any text) calls the perl subroutine “sub” in scalar context with “any text” as its first argument. More complex calls involving Karll arrays(7) are possible with $perlxcall().

Three new subroutines are available from within the perl environment: EPIC::cmd evaluates its arguments as irc commands, returning nothing. EPIC::eval evaluates its arguments as if they were applied to /eval, also returning nothing. EPIC::expr evaluates its arguments as epic expressions(7), returning the results of those expressions.

The exact difference between cmd and eval is that anything passed to eval is subject to Epics parsing rules while anything passed to cmd is not. This is not unlike the difference between single and double quoting in perl.

You can use these to “drive” your script from perl, although, if you are going to do this with a long running script, it is highly recommended that you make calls to EPIC::eval(“pause 1”) liberally.

You should not call the EPIC functions from within %SIG signal handlers other than $SIG{WARN} and $SIG{DIE}. Epics internals are likely to be unable to handle such behavior.

From the perl environment, hooks, aliases and other miscellaneous settings can be changed via the EPIC functions:

EPIC::eval('on hook * @perlcall(sub $*)') Sets up a callback from a hook.
EPIC::eval('alias foo @perlcall(sub $*)') Defines an alias with a callback.
EPIC::eval('echo $foo') Echoes the epic variable $foo.
EPIC::cmd ('echo $foo') Echoes the text “$foo”.
EPIC::cmd (“echo $foo”) Echoes the perl variable $foo.
EPIC::expr('var') Returns value of variable var.
EPIC::expr('aliasctl(assign get var)') Also returns variable var.
EPIC::expr('myalias(x)') Calls epic alias myalias().
EPIC::expr('jot(0 99)') Calls epic function jot(0 99).
EPIC::expr('1+2*3') How to use epic for math.
EPIC::expr('perl(EPIC::expr “1+2*3”)') One last facetious example. :-)

To fully understand what is possible with EPIC::expr, you should read Expressions(7). Briefly, you can retrieve anything from within the epic environment with it, and do many things as well. Exceptions to this are covered by EPIC::cmd and EPIC::eval, which execute commands, for which you should read Programming(7).

Miscellaneous things to be aware of:

By default, perl warnings and errors will be yelled and are trapable with the on(5) yell hook or from perl with the $SIG{DIE} and $SIG{WARN} hooks. This is accomplished with EPIC::yell. This you can use for your own purposes, but it's better to use EPIC::cmd “echo …”.

$perlcall() and $perlxcall() will return a zero length string if they are called while the perl environment is uninitialized or if the sub is undefined. You can use this from within an epic script to trigger an autoload of a perl subroutine for eg.

In terms of performance, perl*call() are pretty damn fast, but the overhead of switching to perlspace takes an order of magnitude longer than making the same call from perlspace. To gain performance, you should avoid switching universes as much as possible. The EPIC::* functions all take and return lists. You will probably find that combining many calls into one makes them a lot faster.

While it is possible to write a script almost entirely in perl, with calls to the EPIC functions, the script will need to be loaded with a call to $perl() from an epic script or with a command.

The EPIC::* functions will execute within the context that called $perl*() so it is possible to manipulate epic variables local to that context.

While perl is quite capable of assigning any string of characters to a variable, epic is not. Any perl string containing a null character will be silently truncated when it is assigned to an epic variable.

Using perl for non-trivial networking is likely to be trickier than under pure perl. Not only does your code have to maintain its sockets, but it has to give epic enough cpu time to maintain its own. This can be done by including all of epics file descriptors in a perl select() call and calling EPIC::eval “pause 1” each time select returns one of them. There currently is no definitive way to obtain these descriptors, but they are included in some hooks such as send_to_server and dcc_raw.

Alternatives to the above are:

  • Use epic for networking with the raw dcc interface.
  • Use an external script to handle the request, via the exec interface.
  • Keep your perl networking code short and sweet.

“alias perl unless (functioncall()) {@perl($*)}” sets up a /PERL command. The arguments will be executed within the embedded perl environment. You may also want to use this alias for calling an external interpreter, which is why there is no inbuilt /PERL command. The choice is yours.

using_perl.txt · Last modified: 2006/08/29 20:18 (external edit)