package CCRBot; # Package for basic CCR robots by nelson@santafe.edu # contains basic parse functions and such. # Variables # Must be set # $robotLibDir you should set this in main before this file is used. # $name English name used to address me # $ccrName object name in CCR land # Readable / possibly setable. # $debugFilename file for debugging info # $debugFlag whether to do debugging # Functions # parseccrl Parse ccrl, return it. # parsewhatsunder Parse whatsunder output # parsewhen Parse ccrl timespecs # initRobot initialize robot - do file I/O, etc. # toggleDebug turn debugging off or on # readLine read a line from stdin, also do debug dump # ccrl send a line out, append \n, do debug dump use Exporter; @ISA = qw(Exporter); @EXPORT = qw($name $ccrName $debugFilename $debugFlag parseccrl parsewhatsunder parsewhen initRobot toggleDebug readLine ccrl); use FileHandle; # load nice filehandle code. $name = 'foo'; # you should set this to English name $ccrName = ''; # and this to the CCR objid $debugFilename = ''; # set this if you don't want default $debugFlag = 0; # toggleDebug sets this # {{{ initRobot # initialization - deal with I/O, create debugging support. sub initRobot { STDOUT->autoflush(1); # flush stdout after a print if ($#debugFilename < 1) { $debugFilename = '>>' . $::robotLibDir . 'debug'; } open(DEBUG, $debugFilename); # open up a debugging output DEBUG->autoflush(1); # flush debugging output print "CCRL\n"; # start up the communication } # }}} # {{{ parseccrl ### Given an input line like ### [/Bump Subject :nelson Object :puppet Text "ha ha"] ### parse it out so that $verb is the verb, and %args are the args. Ie: ### $verb eq '/Bump' ### %args == ( 'Subject' => ':nelson' ### 'Object' => ':puppet' ### 'Text' => "ha ha" ### ); ### it then becomes a straightforward matter to act on that ccrl output. ### You can reference $verb to get the string "/Bump", ### Or $args{'Object'} to get the string ":puppet". ### (%args is an associative array). ### Note - the / stays in the verb name, to indicate past tense. ### The parser is fairly icky, but does its best to chop up ### [verb keyword argument keyword argument keyword argument]. ### We recognize four kinds of arguments: ### a string in double quotes (handles \" embedded properly) ### a timespec, Ie: t(Thu Sep...+0600) ### an enclosed vspec, Ie: [UDPMessage data "foo"]. ### the handling of ] and \" inside the vspec itself is not 100% correct." ### or else, any symbol (nonwhitespace text) ### the regex line down there parses out arguments of these types into @foo. # The component things we match. Note that doublequoted string isn't here: # getting all those \s through perl's quoted string reader sucks. $ccrlTime='t\(.*?\)'; $ccrlSymbol='\S+'; $ccrlCmd='\[[^\]]*\]'; # this attempts to handle a ] in the string, but fails. # $ccrlCmd='\[(?:[^"\]]|"[^"]*")*\]'; sub parseccrl { my @input; my $verb; $_[0] =~ s/^\[(.*)\]$/$1/; # strip out enclosing []s. @input = ($_[0] =~ m/("(?:[^\"\\]|\\\\|\\\")*"|$ccrlTime|$ccrlCmd|$ccrlSymbol)\s*/g); # if the string looks like it's surrounded by quotes, strip out the # quotes. Bad hack, but we can't make the perl regexp matcher do # nested parenthesis the way we want. foreach $s (@input) { $s =~ s/^"(.*)"$/$1/; } $verb = shift(@input); # get the verb as the first arg of @input return($verb, @input); } # }}} # {{{ parsewhatsunder ### parse a whatsunder output. ### usage: parsewhatsunder(whatsundertext) ### returns: associative array of objects and their positions ### for example: ### %locations = parsewhatsunder('"(V3(:Nelson-1 b1x1@0,-1 b1x1@0,0"') ### print $locations{':Nelson-1'}; $numberRE = '-?[0-9]+'; # match one number. sub parsewhatsunder { $_[0] =~ m/V3\((\S+) b[0-9]+x[0-9]+@($numberRE,$numberRE) \S+\)/g; } # }}} # {{{ parsewhen ### parse out a CCR time into an array ### input: a CCR time spec ($args{'When'}) ### output a list of (weekday month day year time) ### for example: ### @parsedTime = parsewhen($args{'When'}); ### print "The time is $parsedTime[4]" sub parsewhen { $_[0] =~ /t\((\w+)\s+(\w+)\s+(\d+)\s+(\d+)\s+(\d+:\d+:\d+)\.\d+\/\d+.*\)/; } # }}} # {{{ toggleDebug sub toggleDebug { if ($debugFlag == 0) { $debugFlag = 1; print DEBUG ("Debugging for $name turned on\n"); } else { $debugFlag = 0; print DEBUG ("Debugging for $name turned off\n"); } return $debugFlag; } # }}} # {{{ readLine # Read a line of input from the stream and return it. Also writes the # input to the debug handle if debugging is on. sub readLine { $_ = <>; if ($debugFlag == 1) { print DEBUG $_; } return $_; } # }}} # {{{ ccrl # Send out a line of text to the stream. Also does debugging write. sub ccrl { if ($debugFlag == 1) { print DEBUG "-- $_[0]\n"; } print "$_[0]\n"; 1; } # }}} 1;