#include <stdio.h> #include <string.h> #include <ctype.h> #include "externs.h" #include "function.h" SCFUNC *sc_function_list = NULL; extern int quiet_reboot; static SCFUNC *find_sc_func(OBJ *player, char *fname) { SCFUNC *f; for(f = sc_function_list;f;f = f->next) { if(f->flags & SCFUNC_GLOBAL || !player || f->owner == player->owner) { if(!strcmp(f->name, fname)) break; } } return(f); } static SCFUNC *new_sc_func() { SCFUNC *f; f = (SCFUNC *)stack_alloc(sizeof(SCFUNC), 1, 0); f->next = sc_function_list; sc_function_list = f; return(f); } static unsigned long parse_sc_func_flags(char *flaglist) { char *p, *q; unsigned long flags = 0; char buf[1024]; strcpy(buf, flaglist); p = buf; while((q = strchr(p, ','))) { *q++ = '\0'; if(!string_compare(p, "global")) flags |= SCFUNC_GLOBAL; else return(-1); p = q; } if(!string_compare(p, "global")) flags |= SCFUNC_GLOBAL; else return(-1); return(flags); } static int ok_func_name(char *name) { char *p; for(p = name;*p;p++) if(isspace(*p) || !isalnum(*p)) return(0); if(!*name) return(0); return(1); } static void list_funcs(OBJ *player, int all) { SCFUNC *f; int ctr = 0; char flags[128]; for(f = sc_function_list;f;f = f->next) if(all || f->flags & SCFUNC_GLOBAL || f->owner == player->owner) { if(f->owner == player->owner) strcpy(flags, " "); else strcpy(flags, my_ljust(tprintf("#%d", f->owner->dbref), 7)); if(f->flags & SCFUNC_GLOBAL) strcpy(flags, "GLOBAL "); if(!ctr) notify(player, " FLAGS NAME ARGS"); notify(player, tprintf("%s %s %d", flags, my_ljust(f->name, 20), f->nargs)); ctr++; } if(ctr) notify(player, ""); notify(player, tprintf("|+B|Total functions available|+W|: |+C|%d", ctr)); } void do_function(OBJ *player, char *arg1, char *arg2) { SCFUNC *func, *pfunc; char buf[4096]; char *p; int nargs; unsigned long flags; int is_global; if(!*arg1) { list_funcs(player, 0); return; } if(!*arg2) { if(!strcmp(arg1, "ALL") && power(player, POW_FUNCTIONS)) { list_funcs(player, 1); return; } if(power(player, POW_FUNCTIONS)) func = find_sc_func(NULL, arg1); else func = find_sc_func(player, arg1); if(!func) { notify(player, tprintf("Unknown function '%s'.", arg1)); return; } is_global = func->flags & SCFUNC_GLOBAL; notify(player, tprintf("|+B|Function |+G|%s()|+W|%s|+R|%s", func->name, (is_global)?" (GLOBAL)":"", (func->owner != player->owner && !is_global)?" (UNAVAILABLE)":"")); notify(player, tprintf("|+B|Owner|+W|: %s", unparse_object(player, func->owner))); notify(player, tprintf("|+B|Number of Arguments|+W|: |+C|%d", func->nargs)); notify(player, tprintf("|+B|Value|+W|: |+C|%s", func->value)); return; } if(!string_compare(arg1, "new")) { strcpy(buf, arg2); if(!(p = strchr(buf, ','))) { notify(player, "Type 'help +function' for help."); return; } *p++ = '\0'; if((func = find_sc_func(NULL, buf))) { notify(player, tprintf("Function %s already exists.", buf)); return; } nargs = atoi(p); if(nargs < 0 || nargs > 9 || !*p) { notify(player, "You must specify a valid number of arguments."); return; } if(!(p = strchr(p, ','))) flags = 0; else { if((flags = parse_sc_func_flags(p+1)) == -1) { notify(player, "Unknown flag in list."); return; } } if(!ok_func_name(buf)) { notify(player, "Illegal function name."); return; } func = new_sc_func(); func->name = stack_string_alloc(buf, 1); func->owner = player->owner; func->flags = flags; func->nargs = nargs; func->value = stack_string_alloc("", 1); notify(player, tprintf("Function '%s' defined.", buf)); return; } if(!string_compare(arg1, "set")) { strcpy(buf, arg2); if(!(p = strchr(buf, ','))) { notify(player, "Type 'help +function' for help."); return; } *p++ = '\0'; if(power(player, POW_FUNCTIONS)) func = find_sc_func(NULL, buf); else func = find_sc_func(player, buf); if(!func) { notify(player, tprintf("Unknown function '%s'.", buf)); return; } if(func->owner != player->owner && !power(player, POW_FUNCTIONS)) { notify(player, perm_denied()); return; } func->value = stack_string_realloc(func->value, p); notify(player, tprintf("Function '%s' set.", buf)); return; } if(!string_compare(arg1, "del")) { if(!(func = find_sc_func(player, arg2))) { notify(player, tprintf("Unknown function '%s'.", arg2)); return; } if(func->owner != player->owner && !power(player, POW_FUNCTIONS)) { notify(player, perm_denied()); return; } if(func == sc_function_list) sc_function_list = func->next; else { for(pfunc = sc_function_list;pfunc;pfunc = pfunc->next) { if(pfunc->next) if(pfunc->next == func) break; } pfunc->next = func->next; } stack_free(func->name); stack_free(func->value); stack_free(func); notify(player, tprintf("Function '%s' deleted.", buf)); return; } if(!strcmp(arg1, "args")) { strcpy(buf, arg2); if(!(p = strchr(buf, ','))) { notify(player, "You must specify a valid number of arguments."); return; } *p++ = '\0'; if(power(player, POW_FUNCTIONS)) func = find_sc_func(NULL, buf); else func = find_sc_func(player, buf); if(!func) { notify(player, tprintf("Unknown function '%s'.", buf)); return; } nargs = atoi(p); if(nargs < 0 || nargs > 9 || !*p) { notify(player, "You must specify a valid number of arguments."); return; } if(func->owner != player->owner && !power(player, POW_FUNCTIONS)) { notify(player, perm_denied()); return; } func->nargs = nargs; notify(player, tprintf("Number of args for function '%s' is now %d.", func->name, nargs)); return; } if(!strcmp(arg1, "flags")) { strcpy(buf, arg2); if(!(p = strchr(buf, ','))) flags = 0; else { *p++ = '\0'; if((flags = parse_sc_func_flags(p)) == -1) { notify(player, "Unknown flag in list."); return; } } if(power(player, POW_FUNCTIONS)) func = find_sc_func(NULL, buf); else func = find_sc_func(player, buf); if(!func) { notify(player, tprintf("Unknown function '%s'.", buf)); return; } if(func->owner != player->owner && !power(player, POW_FUNCTIONS)) { notify(player, perm_denied()); return; } func->flags = flags; notify(player, "Flags set."); return; } notify(player, "Type 'help +function' for help."); return; } void save_sc_funcs() { const char *filename = "db/scfuncs.db"; SCFUNC *f; FILE *fp; int num_funcs = 0; if(!(fp = fopen(filename, "w"))) { log_error(tprintf("Couldn't open \"%s\" for writing!", filename)); return; } for(f = sc_function_list;f;f = f->next) num_funcs++; fprintf(fp, "%d\n", num_funcs); for(f = sc_function_list;f;f = f->next) { fprintf(fp, "%s\n", f->name); fprintf(fp, "%d\n", f->owner->dbref); fprintf(fp, "%ld\n", f->flags); fprintf(fp, "%d\n", f->nargs); fprintf(fp, "%s\n", f->value); } fclose(fp); } void load_sc_funcs() { FILE *fp; const char *filename = "db/scfuncs.db"; int num_funcs; SCFUNC *f; char buf[4096]; if(!(fp = fopen(filename, "r"))) { log_error(tprintf("Couldn't open \"%s\" for reading!", filename)); return; } fgets(buf, sizeof(buf), fp); num_funcs = atoi(buf); if(!quiet_reboot && num_funcs) { notify_all2(tprintf("Loading %d softcode function%s...", num_funcs, check_plural(num_funcs == 1, "", "s")), NULL); flush_all_output(); } while(num_funcs--) { f = new_sc_func(); fgets(buf, sizeof(buf), fp); *(buf+strlen(buf)-1) = '\0'; f->name = stack_string_alloc(buf, 1); fgets(buf, sizeof(buf), fp); f->owner = find_object(atoi(buf)); fgets(buf, sizeof(buf), fp); f->flags = atol(buf); fgets(buf, sizeof(buf), fp); f->nargs = atoi(buf); fgets(buf, sizeof(buf), fp); *(buf+strlen(buf)-1) = '\0'; f->value = stack_string_alloc(buf, 1); } fclose(fp); } void free_sc_funcs() { SCFUNC *f, *fnext; for(f = sc_function_list;f;f = fnext) { fnext = f->next; stack_free(f->name); stack_free(f->value); stack_free(f); } sc_function_list = NULL; } static void expand_user_func_args(char *str, char *retbuf) { char *p, *s, *q; int ch; /* 0 if variable is an integer, 1 if char or string */ char *cval = 0; int ival = 0; char varname[4096]; char *v; char buf[4096]; strcpy(retbuf, str); for(p = retbuf;*p;p++) { ch = 0; if(*p == '"') { p++; while(*p && *p != '"') p++; if(!*p) break; continue; } if(*p != '~') continue; s = p++; for(v = varname;isalnum(*p);v++,p++) *v = *p; *v = '\0'; if(*p == '$') { ch = 1; p++; } for(q = s;*q && q < p;p--) extract_char(q); if(ch) cval = cvar_val(varname); else ival = ivar_val(varname); strncpy(buf, retbuf, s-retbuf); *(buf+(s-retbuf)) = '\0'; if(ch) strcat(buf, cval); else sprintf(buf+strlen(buf), "%d", ival); strcat(buf, p); strcpy(retbuf, buf); p = retbuf; if(*p == '"') p--; } } int chk_user_func(OBJ *player, char *buffer, char *start) { char buf[4096], buf2[4096]; char *p, *f, *a; char funcname[4096]; SCFUNC *func; int deep; int num_args; SCVAR *var; strncpy(buf, buffer, start-buffer); *(buf+(start-buffer)) = '\0'; for(p = start, f = funcname;*p && *p != '(';p++, f++) *f = *p; *f = '\0'; if(!*p || !*funcname) return(0); if(!(func = find_sc_func(player, funcname))) return(0); num_args = 1; deep = 0; a = buf2; /* Start at the first '(' and find the last one */ while(*p) { switch(*p) { case ',': if(num_args < 9 && deep == 1) { if(!(var = find_var(tprintf("arg%d", num_args), VAR_STR))) { notify(code_ptr->executor, tprintf("|+bR|Fatal internal error in |+bY|%d|+bR|.", code_ptr->pline->line)); return(0); /* Parent function should end the program */ } *a = '\0'; var->cvalue = stack_string_realloc(var->cvalue, buf2); num_args++; a = buf2; } break; case '(': deep++; break; case '{': while(*p && *p != '}') p++; if(!*p) return(0); break; case '}': return(0); case ')': deep--; break; default: *a++ = *p; } if(!deep) { *a = '\0'; if(num_args == 1 && !*buf2) { num_args = 0; break; } if(!(var = find_var(tprintf("arg%d", num_args), VAR_STR))) { notify(code_ptr->executor, tprintf("|+bR|Fatal internal error in |+bY|%d|+bR|.", code_ptr->pline->line)); return(0); /* Parent function should end the program */ } var->cvalue = stack_string_realloc(var->cvalue, buf2); break; } p++; } if(!*p) return(0); p++; if(func->nargs != num_args) { notify(code_ptr->executor, tprintf("|+R|Expect %d args for function |+G|%s |+R|in |+Y|%d|+R|.", func->nargs, func->name, code_ptr->pline->line)); return(0); } expand_user_func_args(func->value, buf2); sprintf(buf+strlen(buf), "%s%s", buf2, p); strcpy(buffer, buf); return(1); }