/* * handle_cmd.c -- handling commands to PMF (local and remote) * * PMF -- Padrone's MudFrontend, a frontend for (maybe mostly LP-)mud * Thomas Padron-McCarthy (Email: padrone@lysator.liu.se), 1990, 1991 * Share and enjoy, but be nice: don't steal my program! Hugo is watching! * This file latest updated: Sept 22, 1991 * */ #include #include #include #include #include #include #include "safe_malloc.h" #include "config.h" #include "pmf.h" #include "globals.h" extern char *get_input_line(), *expand_alias(), *find_alias_string(), *expand_history(), *get_statstring(), *getmud(), *apply_definition(); extern int handle_command(); extern void do_remote_command(); /*---------------------------------------------------------------------------*/ /* This function takes care of a command given by the player. * It is supposed to be in a malloc'ed string, * with the trailing '\n' removed. * It will not be free'd in this function or in functions called by it. */ void player_command(command_line) char *command_line; { char *cp, *cmd_subst = NULL; int retval; USER_DEBUG(("player_command(\"%s\")", command_line)); cmd_subst = NULL; /* First, skip leading white space. */ cp = command_line; while (isspace(*cp)) ++cp; /* We don't check for comment lines here, since it's only when * reading commands from files that lines starting with # * should be skipped. */ /* Blank lines are simply sent to the Mud process. * All the white space is sent. */ if (*cp == 0) { do_remote_command(command_line, 0); return; } /* If this is a "quote" command, simply send the rest of the line to Mud. */ if ( (slash_commands && !strncmp("/quote", cp, 6)) || (!slash_commands && !strncmp("quote", cp, 5))) { do_remote_command(cp + (slash_commands ? 7 : 6), 0); add_mud_history(cp); return; } if (substitute_history) { /* Not a quote command. Substitue any history references (!! and !number). */ cmd_subst = expand_history(cp); if (cmd_subst) { /* The "cmd_subst" string is a new, malloc'ed, string. * Don't forget to free it later! */ USER_DEBUG(("History substitution yielded: %s", cmd_subst)); cp = cmd_subst; } if (cmd_subst && verbose) ldisplay("History substitution yielded: %s\n", cp); } add_mud_history(cp); /* History substitution might have yielded a new "quote" command, * but that will be handled in handle_command. */ if (cmd_subst) retval = handle_command(cp, 0); else retval = handle_command(command_line, 0); if (cmd_subst) safe_free(cmd_subst); if (retval && pmf_prompt && !sourcing) ldisplay(pmf_prompt, query_latest_event_nr() + 1); } /* player_command */ /* Handle a command line from the user (possibly form a source'd file). * It is called AFTER any history substitution, and AFTER storing the * command on the history list. Also, comments and "quote" commands have * already been taken care of. * If the line is expanded to several lines, by use of the $n notation, * this function is called recursively for each of those new lines. * If expressflag is true, the remote command(s) will be added at * the HEAD of the queue of commands to send to the game * (but not directly -- they are put on a special express list first). * The number of executed local commands is returned. */ int handle_command(command_line, expressflag) char *command_line; int expressflag; { char *cp, *the_definition, *this_expanded, *latest_expanded; int nr_words, nr_alias_expansions, i, result; char *command_line_words[MAX_WORDS_PER_LINE], command_line_words_buffer[2 * MAX_LINE_LENGTH]; int use_command_line, recursive_retval; int was_slash_command; USER_DEBUG(("handle_command(\"%s\", %d)", command_line, expressflag)); use_command_line = 1; /* First, skip leading white space. It will still be there! */ cp = command_line; while (isspace(*cp)) ++cp; /* Comment lines, i. e. lines that start with # (even after white space) are ignored. * If this was a player command, those lines are skipped, but not if it was source'd. */ if (*cp == '#') { return 0; } /* Blank lines are simply sent to the Mud process. All the white space is sent. */ if (*cp == 0) { do_remote_command(command_line, expressflag); return 0; } was_slash_command = slash_commands && *cp == '/'; /* If this is a "quote" command, simply send the rest of the line to Mud. */ if ( (slash_commands && !strncmp("/quote", cp, 6)) || (!slash_commands && !strncmp("quote", cp, 5))) { do_remote_command(cp + (slash_commands ? 7 : 6), 0); return 0; } /* Now, do alias substitution! The function "expand_one_alias" will return NULL * if no substitutions were done, or a malloc'ed string that we must free later! * "cp" still points to the first non-blank char, so we can do "alias /foo fum". */ nr_alias_expansions = 0; latest_expanded = NULL; nr_words = word_split(cp, command_line_words, command_line_words_buffer); /* If word_split failed (it returned 0), * we simply send the line to the Mud process. */ if (nr_words == 0) { do_remote_command(command_line, expressflag); if (verbose) ldisplay("The line is not interpreted by PMF, but is sent directly to MUD.\n"); return 0; } /* If the command line contained at least one un-quoted $n, it was * split into lines instead of words. Each line is a new command! */ if (nr_words < 0) { use_command_line = 0; nr_words = -nr_words; if (verbose) { ldisplay("The command line was split into %d new command lines.\n", nr_words); for (i=0; i 0) { int i; ldisplay("DEBUG: First splitting (1) of the command line: %d words:\n", nr_words); for (i=0; i MAX_ALIAS_EXPANSIONS) error("Alias loop. Too many levels (%d) substituted.", nr_alias_expansions); this_expanded = apply_definition(the_definition, nr_words, command_line_words, 1); USER_DEBUG(("This alias substitution yielded: %s", this_expanded)); if (latest_expanded) safe_free(latest_expanded); latest_expanded = this_expanded; cp = this_expanded; nr_words = word_split(cp, command_line_words, command_line_words_buffer); /* If word_split failed (it returned 0), * we simply send the line to the Mud process. */ if (nr_words == 0) { do_remote_command(cp, expressflag); /* This alias! */ if (verbose) ldisplay("The line is not interpreted by PMF, but is sent directly to MUD.\n"); return 0; } /* If the command line contained at least one un-quoted $n, it was * split into lines instead of words. Each line is a new command! */ if (nr_words < 0) { nr_words = -nr_words; if (verbose) { ldisplay("The command line was split into %d new command lines:\n", nr_words); for (i=0; i 0) { int i; ldisplay("DEBUG: This splitting (2) of the command line: %d words:\n", nr_words); for (i=0; i 3) message("Too many arguments to the \"connect\" command."); else cmd_connect(words[1], words[2]); } else if (!strcmp(words[0], LOCAL_COMMAND("disconnect", "/disconnect"))) { if (nr_words > 1) message("You cannot give any arguments to the \"disconnect\" command."); else cmd_disconnect(); } else if (!strcmp(words[0], LOCAL_COMMAND("help", "/help"))) { if (nr_words > 2) message("Usage: /help [ SUBJECT ]."); else cmd_help(words[1]); } else if (!strcmp(words[0], "help")) { if (nr_words == 2 && (!strcmp(lower_string(words[1]), "pmf") || !strcmp(words[1], "front"))) cmd_help(0); else { if (verbose) { ldisplay("(Note: PMF is passing on this \"help\" command to MUD.\n"); ldisplay(" Use the command \"/help\" for help about the PMF program.)\n"); } do_remote_command(the_local_command, expressflag); return 1; } } else if (!strcmp(words[0], LOCAL_COMMAND("status", "/status"))) { if (nr_words > 1) message("You cannot give any arguments to the \"/status\" command."); else cmd_status(); } else if (!strcmp(words[0], LOCAL_COMMAND("history", "/history"))) { if (nr_words > 2) message("Too many arguments to the \"history\" command."); else cmd_history(words[1]); } else if (!strcmp(words[0], LOCAL_COMMAND("log", "/log"))) { if (nr_words > 2) message("Usage: /log [ FILENAME ]\n"); else cmd_log(words[1], 0); } else if (!strcmp(words[0], LOCAL_COMMAND("debuglog", "/debuglog"))) { if (nr_words > 2) message("Usage: /debuglog [ FILENAME ]\n"); else cmd_log(words[1], 1); } else if (!strcmp(words[0], LOCAL_COMMAND("perform", "/perform"))) { if (nr_words < 2) message("You must give a MUD command as argument to the \"perform\" command."); else if (nr_words > 3) message("Too many arguments to the \"perform\" command."); else cmd_perform(words[1], words[2]); } else if (!strcmp(words[0], LOCAL_COMMAND("send", "/send"))) { if (nr_words < 2) message("You must give a file name as argument to the \"send\" command."); else if (nr_words > 3) message("Too many arguments to the \"send\" command."); else cmd_send(words[1], words[2], 0); } else if (!strcmp(words[0], LOCAL_COMMAND("receive", "/receive"))) { if (nr_words < 2) message("You must give a file name as argument to the \"receive\" command."); else if (nr_words < 3) message("You must give a stop string as second argument to the \"receive\" command."); else if (nr_words > 3) message("Too many arguments to the \"receive\" command."); else cmd_receive(words[1], words[2], 0); } else if (!strcmp(words[0], LOCAL_COMMAND("putfile", "/putfile"))) { if (nr_words < 2) message("You must give at least one file name as argument to \"putfile\"."); else if (nr_words > 3) message("Too many arguments to \"putfile\"."); else cmd_putfile(words[1], words[2]); } else if (!strcmp(words[0], LOCAL_COMMAND("getfile", "/getfile"))) { if (nr_words < 2) message("You must give at least one file name as argument to \"getfile\"."); else if (nr_words > 4) message("Too many arguments to \"getfile\"."); else cmd_getfile(words[1], words[2]); } else if (!strcmp(words[0], LOCAL_COMMAND("last", "/last"))) { if (nr_words > 2) message("Too many arguments to the \"last\" command."); else cmd_last(words[1]); } else if (!strcmp(words[0], LOCAL_COMMAND("source", "/source"))) { if (nr_words < 2) message("You must give a file name as argument to the \"source\" command."); else if (nr_words > 2) message("Too many arguments to \"source\" command."); else cmd_source(words[1]); } else if (!strcmp(words[0], LOCAL_COMMAND("dump", "/dump"))) { if (nr_words < 2) message("You must give a file name as argument to the \"dump\" command."); else if (nr_words > 2) message("Too many arguments to the \"dump\" command."); else cmd_dump(words[1]); } else if (!strcmp(words[0], LOCAL_COMMAND("alias", "/alias"))) { if (nr_words == 3) restargs = words[2]; else if (nr_words > 3 && quotes_in_line(the_local_command)) { message("No quoting allowed if you have more than two arguments to \"alias\"."); return 0; } else if (nr_words > 3) { restargs = the_local_command; while (isspace(*restargs)) ++restargs; /* Now we are at the beginning of the first word. */ while (!isspace(*restargs)) ++restargs; while (isspace(*restargs)) ++restargs; /* Now we are at the beginning of the second word. */ while (!isspace(*restargs)) ++restargs; while (isspace(*restargs)) ++restargs; /* Now we are at the beginning of the third word. */ } else restargs = NULL; cmd_alias(words[1], restargs); } else if (!strcmp(words[0], LOCAL_COMMAND("unalias", "/unalias"))) { if (nr_words < 2) message("You must give an argument to the \"unalias\" command."); else if (nr_words > 2) message("Too many arguments to the \"unalias\" command."); else cmd_unalias(words[1]); } else if (!strcmp(words[0], LOCAL_COMMAND("action", "/action"))) { if (nr_words == 3) restargs = words[2]; else if (nr_words > 3 && quotes_in_line(the_local_command)) { message("No quoting allowed if you have more than two arguments to \"action\"."); return 0; } else if (nr_words > 3) { restargs = the_local_command; while (isspace(*restargs)) ++restargs; /* Now we are at the beginning of the first word. */ while (!isspace(*restargs)) ++restargs; while (isspace(*restargs)) ++restargs; /* Now we are at the beginning of the second word. */ while (!isspace(*restargs)) ++restargs; while (isspace(*restargs)) ++restargs; /* Now we are at the beginning of the third word. */ } else restargs = NULL; cmd_action(words[1], restargs); } else if (!strcmp(words[0], LOCAL_COMMAND("unaction", "/unaction"))) { if (nr_words < 2) message("You must give an argument to the \"unaction\" command."); else if (nr_words > 2) message("Too many arguments to the \"unaction\" command."); else cmd_unaction(words[1]); } else if (!strcmp(words[0], LOCAL_COMMAND("unactionall", "/unactionall"))) { if (nr_words != 1) message("You can't give any arguments to \"unactionall\"."); else cmd_unactionall(); } else if (!strcmp(words[0], LOCAL_COMMAND("sound", "/sound"))) { if (nr_words == 3) restargs = words[2]; else if (nr_words > 3 && quotes_in_line(the_local_command)) { message("No quoting allowed if you have more than two arguments to \"sound\"."); return 0; } else if (nr_words > 3) { restargs = the_local_command; while (isspace(*restargs)) ++restargs; /* Now we are at the beginning of the first word. */ while (!isspace(*restargs)) ++restargs; while (isspace(*restargs)) ++restargs; /* Now we are at the beginning of the second word. */ while (!isspace(*restargs)) ++restargs; while (isspace(*restargs)) ++restargs; /* Now we are at the beginning of the third word. */ } else restargs = NULL; #ifdef SOUND cmd_sound(words[1], restargs); #endif } else if (!strcmp(words[0], LOCAL_COMMAND("unsound", "/unsound"))) { if (nr_words < 2) message("You must give an argument to the \"unsound\" command."); else if (nr_words > 2) message("Too many arguments to the \"unsound\" command."); #ifdef SOUND else cmd_unsound(words[1]); #endif } else if (!strcmp(words[0], LOCAL_COMMAND("beep", "/beep"))) { if (nr_words != 1) message("You can not give any arguments to the \"beep\" command."); else cmd_beep(); } else if (!strcmp(words[0], LOCAL_COMMAND("echo", "/echo"))) { if (nr_words == 1) restargs = NULL; else if (nr_words == 2) restargs = words[1]; else { ASSERT(nr_words > 2); restargs = the_local_command; while (isspace(*restargs)) ++restargs; /* Now we are at the beginning of the first word. */ while (!isspace(*restargs)) ++restargs; while (isspace(*restargs)) ++restargs; /* Now we are at the beginning of the second word. */ } cmd_echo(restargs); } else if (!strcmp(words[0], LOCAL_COMMAND("cd", "/cd"))) { if (nr_words > 2) message("Usage: /cd [ DIRECTORY-NAME ]"); else cmd_cd(words[1]); } else if (!strcmp(words[0], LOCAL_COMMAND("cryptsay", "/cryptsay"))) { if (nr_words == 1) { message("You must give an argument to the \"cryptsay\" command."); return 0; } else if (nr_words == 2) restargs = words[1]; else { ASSERT(nr_words > 2); restargs = the_local_command; while (isspace(*restargs)) ++restargs; /* Now we are at the beginning of the first word. */ while (!isspace(*restargs)) ++restargs; while (isspace(*restargs)) ++restargs; /* Now we are at the beginning of the second word. */ } cmd_cryptsay(restargs); } else if (!strcmp(words[0], LOCAL_COMMAND("crypttell", "/crypttell"))) { if (nr_words < 3) { message("You must give at least two arguments to the \"crypttell\" command."); return 0; } else if (nr_words == 3) restargs = words[2]; else { ASSERT(nr_words > 3); restargs = the_local_command; while (isspace(*restargs)) ++restargs; /* Now we are at the beginning of the first word. */ while (!isspace(*restargs)) ++restargs; while (isspace(*restargs)) ++restargs; /* Now we are at the beginning of the second word. */ while (!isspace(*restargs)) ++restargs; /* Now we are just after the second word. */ ++restargs; /* Now we are after the second word, plus one space or tab. */ } cmd_crypttell(words[1], restargs); } else if (!strcmp(words[0], LOCAL_COMMAND("system", "/system"))) { if (nr_words < 2) restargs = NULL; else if (nr_words == 2) restargs = words[1]; else if (nr_words > 2 && quotes_in_line(the_local_command)) { message("No quoting allowed if you have more than two arguments to \"system\"."); return 0; } else { ASSERT(nr_words > 2); restargs = the_local_command; while (isspace(*restargs)) ++restargs; /* Now we are at the beginning of the first word. */ while (!isspace(*restargs)) ++restargs; while (isspace(*restargs)) ++restargs; /* Now we are at the beginning of the second word. */ } cmd_system(restargs); } else if (!strcmp(words[0], LOCAL_COMMAND("gag", "/gag"))) { if (nr_words > 2) message("You cannot give more than one person or pattern as argument to the \"gag\" command."); else cmd_gag(words[1]); } else if (!strcmp(words[0], LOCAL_COMMAND("ungag", "/ungag"))) { if (nr_words < 2) message("Yes, but who dou you want to ungag?"); else if (nr_words > 2) message("You cannot give more than one person as argument to the \"ungag\" command."); else cmd_ungag(words[1]); } else if (!strcmp(words[0], LOCAL_COMMAND("set", "/set"))) { if (nr_words > 3) message("Usage: /set VARIABLE-NAME [ VALUE ]"); else cmd_set(words[1], words[2]); } else if (!strcmp(words[0], LOCAL_COMMAND("unset", "/unset"))) { if (nr_words != 2) message("Usage: /unset VARIABLE-NAME"); else { cmd_unset(words[1]); } } else if (!strcmp(words[0], LOCAL_COMMAND("quit", "/quit"))) { if (nr_words > 1) message("You cannot give any arguments to the command \"/quit\"."); else cmd_quit(); } else return -1; return 0; } /* do_local_command */ void do_remote_command(the_remote_command, expressflag) char *the_remote_command; int expressflag; { if (!connected) message("You cannot give commands to MUD until you are connected to MUD."); else if (sending) message("You cannot give commands to MUD while sending a file."); else if (expressflag) express_queue_mudline(the_remote_command, ""); else queue_mudline(the_remote_command, ""); } /* do_remote_command */