# $EPIC: Perl,v 1.12 2003/04/19 00:36:02 crazyed Exp $
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*(6) 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(6) 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(6)
functions.

At this point, the $perlcall(6) and $perlxcall(6) 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(6).

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(6) and $perlxcall(6) 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(6) 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(6) 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.

See Also:
perl(6); perlcall(6); perlxcall(6); Expressions(7); Programming(7); Arrays(7)
