From 020a9262f723a5fab1d5695f3a654bb69519e4b2 Mon Sep 17 00:00:00 2001 From: Brian Koropoff Date: Tue, 25 Feb 2003 08:04:48 +0000 Subject: [PATCH] Made the parser anal about concatenation usage and fixed several bugs by running /dev/urandom through carne to catch problems. --- doc/config/gib/infobot.gib | 137 +++++++++++++++++++++++++++++++------ libs/gib/gib_execute.c | 18 ++--- libs/gib/gib_parse.c | 30 ++++++-- 3 files changed, 148 insertions(+), 37 deletions(-) diff --git a/doc/config/gib/infobot.gib b/doc/config/gib/infobot.gib index e9e425ec3..37131c4a7 100644 --- a/doc/config/gib/infobot.gib +++ b/doc/config/gib/infobot.gib @@ -27,20 +27,10 @@ domain infobot global rcsid = "$Id$" -global facts addr_cmds cmds -global botname = "Console" - -// Set up some cvars if they aren't already -ifnot $infobot_restrict { - set infobot_restrict 0 -} - -ifnot $(length $infobot_password) { - set infobot_password "" -} +global facts addr_cmds cmds current_file function infobot::makeKey { - return $(regex::replace $args[1] \. -- \_)_ + return $(regex::replace $args[1] "\." -- "\_")_ } function infobot::hasAccess { @@ -48,14 +38,46 @@ function infobot::hasAccess { } function infobot::defineFactoid { - if (!$infobot_restrict || $(infobot::hasAccess $args[1])) { + if (!$infobot_restrict_factoids || $(infobot::hasAccess $args[1])) { key = $(infobot::makeKey $args[2]) - facts.$key = @args[3:] + // Filter out newlines/carriage returns + if ${facts.${key}[2]} { + return -2 + } + facts.${key}[0] = $(regex::replace $args[3] "[\n\r]" g "") + facts.${key}[1] = @args[4:] return 0 } return -1 } +function infobot::factToString { + local out + for i in @args[1:] { + out = $out, $i, "\255" + } + return $out +} + +function infobot::saveFactoids { + local output = "" + // Build up output to write to a file + for fact in %facts { + output = $output, $fact, "\255", $(infobot::factToString @facts.$fact), "\n" + } + file::write $args[1],".fct" $output +} + +function infobot::loadFactoids { + delete facts + global facts + for line in $(split $(file::read $args[1],".fct") "\n") { + fact = $(split $line "\255") + facts.${fact[0]} = @fact[1:] + } + current_file = $args[1] +} + function infobot::chatEvent { // Ignore teamtalk/spectalk if $args[3] { @@ -67,7 +89,7 @@ function infobot::chatEvent { local res // see if we are being addressed by name - res = $(regex::extract $mesg $botname, "[:,][[:space:]]+(.+)" i) + res = $(regex::extract $mesg $infobot_name, "[:,][[:space:]]+(.+)" i) if #res { mesg = $res[2] local addr = 1 @@ -91,10 +113,15 @@ function infobot::chatEvent { } res = $(regex::extract $mesg "^([^[:space:]]+)[[:space:]]+(is|are)[[:space:]]+(.+)" i) if #res { - if ($(infobot::defineFactoid $args[1] $res[2] $res[4] $res[3]) && $addr) { - say $from, ": You do not have the privileges to alter factoids." - } else if $addr { - say $from, ": Understood." + res = $(infobot::defineFactoid $args[1] $res[2] $res[4] $res[3]) + if $addr { + if ($res == -1) { + say $from, ": You do not have the privileges to alter factoids." + } else if ($res == -2) { + say $from, ": That factoid is locked." + } else { + say $from, ": Understood." + } } return } @@ -119,8 +146,8 @@ function infobot::cmdRegister { cmds.$args[1] = $args[2] } -function infobot::forget { - ifnot (!$infobot_restrict || $(infobot::hasAccess $args[1])) { +function infobot::forgetFactoid { + if ($infobot_restrict_factoids && !$(infobot::hasAccess $args[1])) { say $args[2], ": You do not have the privileges to alter factoids." return } @@ -133,10 +160,76 @@ function infobot::forget { } } +function infobot::lockFactoid { + ifnot $(infobot::hasAccess $args[1]) { + say $args[2], ": You do not have the privileges to lock factoids." + return + } + fact = $(infobot::makeKey $args[3]) + ifnot #{facts.$fact} { + say $args[2], ": No such factoid exists." + return + } + facts.${fact}[2] = 1 + say $args[2], ": \"", $args[3], "\" is now locked." +} + +function infobot::unlockFactoid { + ifnot $(infobot::hasAccess $args[1]) { + say $args[2], ": You do not have the privileges to unlock factoids." + return + } + fact = $(infobot::makeKey $args[3]) + ifnot #{facts.$fact} { + say $args[2], ": No such factoid exists." + return + } + facts.${fact}[2] = 0 + say $args[2], ": \"", $args[3], "\" is now unlocked." +} + function infobot::stats { say $args[2], ": I currently reference ", $(count %facts), " factoid(s) and ", ($(count %cmds) + $(count %addr_cmds)), " command(s)." } +function infobot::syncFactoids { + ifnot $(infobot::hasAccess $args[1]) { + say $args[2], ": You do not have syncing privileges." + return + } + if #args[3] { + file = $args[3] + } else { + file = $current_file + } + infobot::saveFactoids $file + say $args[2], ": Factoids successfully synced to file ", $file, ".fct." +} + +// These are useful to the admin +function::export infobot::saveFactoids infobot::loadFactoids + event::register chat infobot::chatEvent -infobot::cmdAddrRegister "forget" infobot::forget +infobot::cmdAddrRegister "forget" infobot::forgetFactoid +infobot::cmdAddrRegister "lock" infobot::lockFactoid +infobot::cmdAddrRegister "unlock" infobot::unlockFactoid infobot::cmdAddrRegister "infostats" infobot::stats +infobot::cmdAddrRegister "sync" infobot::syncFactoids + +// Set default values +ifnot $(length $infobot_restrict_factoids) { + set infobot_restrict_factoids 0 +} + +ifnot $(length $infobot_password) { + set infobot_password "hackme" +} + +ifnot $(length $infobot_name) { + set infobot_name "Console" +} + +// Try to load a default factoids file +if $(contains "default.fct" $(file::find *.fct)) { + infobot::loadFactoids "default" +} diff --git a/libs/gib/gib_execute.c b/libs/gib/gib_execute.c index 694c72eb2..8707ef77a 100644 --- a/libs/gib/gib_execute.c +++ b/libs/gib/gib_execute.c @@ -84,7 +84,9 @@ GIB_Execute_Split_Var (cbuf_t * cbuf) char *c, *str = cbuf->args->argv[cbuf->args->argc - 1]->str + 1; void *m = cbuf->args->argm[cbuf->args->argc - 1]; - i = strlen (str) - 1; + i = strlen (str); + if (i) + i--; if (str[-1] == '@') { if (str[i] == ']') for (; i; i--) @@ -229,15 +231,15 @@ GIB_Execute (cbuf_t * cbuf) g->ip = g->ip->next; continue; case TREE_T_CMD: + if (g->ip->flags & TREE_L_EMBED) { + // Get ready for return values + g->waitret = true; + GIB_Buffer_Push_Sstack (cbuf); + } else + g->waitret = false; if (GIB_Execute_Prepare_Line (cbuf, g->ip)) return; else if (cbuf->args->argc) { - if (g->ip->flags & TREE_L_EMBED) { - // Get ready for return values - g->waitret = true; - GIB_Buffer_Push_Sstack (cbuf); - } else - g->waitret = false; if ((b = GIB_Builtin_Find (cbuf->args->argv[0]->str))) b->func (); else if ((f = GIB_Function_Find (cbuf->args->argv[0]->str))) { @@ -254,8 +256,8 @@ GIB_Execute (cbuf_t * cbuf) } if (cbuf->state) return; - g->ip = g->ip->next; } + g->ip = g->ip->next; continue; default: GIB_Error ("QUAKEFORGE-BUG-PLEASE-REPORT", "Unknown instruction type; tastes like chicken."); diff --git a/libs/gib/gib_parse.c b/libs/gib/gib_parse.c index 078257962..a083aabed 100644 --- a/libs/gib/gib_parse.c +++ b/libs/gib/gib_parse.c @@ -224,7 +224,8 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs, gib_t unsigned int tstart, start; gib_tree_t *nodes = 0, *cur, *new, *embs = 0, *tmp; gib_tree_t **node = &nodes; - qboolean cat = false; + enum {CAT_NORMAL = 0, CAT_DISALLOW, CAT_CONCAT} cat = CAT_DISALLOW; + const char *catestr = "Comma found before first argument, nothing to concatenate to."; gib_parse_error = false; @@ -234,10 +235,15 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs, gib_t (*i)++; // Check for concatenation, skip comma and any more whitespace if (program[*i] == ',') { - cat = true; + if (cat == CAT_DISALLOW) { + GIB_Parse_Error(catestr, *i + pofs); + goto ERROR; + } + cat = CAT_CONCAT; (*i)++; continue; - } + } else + cat = CAT_NORMAL; // New line/command? if (!program[*i] || program[*i] == '\n' || program[*i] == ';') break; @@ -290,6 +296,12 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs, gib_t str = calloc (*i - tstart + 1, sizeof (char)); memcpy (str, program + tstart, *i - tstart); if (cur->delim == '{') { + if (cat == CAT_CONCAT) { + GIB_Parse_Error ("Program blocks may not be concatenated with other arguments.", start + pofs); + goto ERROR; + } + catestr = "Program blocks may not be concatenated with other arguments."; + cat = CAT_DISALLOW; // Try to parse sub-program if (!(new = GIB_Parse_Lines (str, tstart + pofs))) goto ERROR; @@ -315,7 +327,13 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs, gib_t } // Check for array splitting // Concatenating this onto something else is non-sensical - if (cur->delim == ' ' && (str[0] == '@' || str[0] == '%') && !cat) { + if (cur->delim == ' ' && (str[0] == '@' || str[0] == '%')) { + if (cat == CAT_CONCAT) { + GIB_Parse_Error ("Variable expansions may not be concatenated with other arguments.", start + pofs); + goto ERROR; + } + catestr = "Variable expansions may not be concatenated with other arguments."; + cat = CAT_DISALLOW; cur->flags |= TREE_A_EXPAND; } // We can handle escape characters now @@ -323,10 +341,8 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs, gib_t GIB_Process_Escapes (str); cur->str = str; - if (cat) { + if (cat == CAT_CONCAT) cur->flags |= TREE_A_CONCAT; - cat = false; - } // Nothing left to parse? if (!program[*i]) break;