/* ************************************************************************ * File: interpreter.c Part of CircleMUD * * Usage: parse user commands, search for specials, call ACMD functions * * * * All rights reserved. See license.doc for complete information. * * * * Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University * * CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. * ************************************************************************ */ /* * This file contains the functions to load the world files into memory * into the stock CircleMUD arrays. * * You should update this code to match the code in your MUD if it's been * changed from stock in any way. */ #include "sysdep.h" #include "utils.h" #include "structs.h" #include "interpreter.h" #include "main.h" const char *fill[] = { "in", "from", "with", "the", "on", "at", "to", "\n" }; /* * Function to skip over the leading spaces of a string. */ void skip_spaces(char **string) { for (; **string && isspace(**string); (*string)++); } int fill_word(char *argument) { return (search_block(argument, fill, TRUE) >= 0); } /* * one_word is like one_argument, except that words in quotes ("") are * considered one word. */ char *one_word(char *argument, char *first_arg) { char *begin = first_arg; do { skip_spaces(&argument); first_arg = begin; if (*argument == '\"') { argument++; while (*argument && *argument != '\"') { *(first_arg++) = LOWER(*argument); argument++; } argument++; } else { while (*argument && !isspace(*argument)) { *(first_arg++) = LOWER(*argument); argument++; } } *first_arg = '\0'; } while (fill_word(begin)); return (argument); } /** * Returns whether a string a valid integer. * @param str the string to be tested * @param allowSign whether an initial + or - sign is permitted * @return TRUE if the string is a valid integer; * FALSE otherwise */ bool isInteger(const char *str, bool allowSign) { if (str != NULL && *str != '\0') { /* Skip any leading whitespace. */ while (*str != '\0' && isspace(*str)) { str++; } /* Skip the sign character if its permitted. */ if (allowSign && strchr("+-", *str) != NULL) { str++; } if (isdigit(*str)) { /* Skip any digit characters. */ while (isdigit(*str)) { str++; } /* Skip any trailing whitespace. */ while (*str != '\0' && isspace(*str)) { str++; } if (*str == '\0') { return (TRUE); } } } return (FALSE); } /* * searches an array of strings for a target string. "exact" can be * 0 or non-0, depending on whether or not the match must be exact for * it to be returned. Returns -1 if not found; 0..n otherwise. Array * must be terminated with a '\n' so it knows to stop searching. */ ssize_t search_block(const char *arg, const char **list, bool exact) { int i, l; /* We used to have \r as the first character on certain array items to * prevent the explicit choice of that point. It seems a bit silly to * dump control characters into arrays to prevent that, so we'll just * check in here to see if the first character of the argument is '!', * and if so, just blindly return a '-1' for not found. - ae. */ if (*arg == '!') return (-1); /* Record the length of the argument. */ l = strlen(arg); if (exact) { for (i = 0; **(list + i) != '\n'; i++) if (!strcasecmp(arg, *(list + i))) return (i); } else { if (!l) l = 1; /* Avoid "" to match the first available * string */ for (i = 0; **(list + i) != '\n'; i++) if (!strncasecmp(arg, *(list + i), l)) return (i); } return (-1); } /** * Reads one token from a source string. * @param buf the buffer into which the token is to be written * @param buflen the length of the specified buffer * @param delims the list of characters delimiting the next token * @param src the source string from which the token is to be read * @return a pointer to the character in the source string that bounds the * token written into the specified buffer, or NULL if some error occurs */ const char *onetoken(char *buf, size_t buflen, const char *delims, const char *src) { register const char *p = NULL; if (buf == NULL) { log("onetoken(): invalid 'buf' string."); } else if (buflen == 0) { log("onetoken(): invalid 'buflen' value 0."); } else if (delims == NULL || *delims == '\0') { log("onetoken(): invalid 'delims' string."); } else if (src == NULL) { log("onetoken(): invalid 'src' string."); } else { /* Declare a variable to contain the buffer position. */ register size_t bufpos = 0; /* Iterate over the source string. */ for (p = src; *p != '\0' && strchr(delims, *p) == NULL; p++) { /* Accumulate the character. */ if (bufpos < buflen - 1 && *p != '\r') { buf[bufpos++] = *p; } } /* Terminate the buffer with a NUL character. */ buf[bufpos] = '\0'; } return (p); } /** * Gets whether a string represents a numeric value. * @param string the string to be tested * @return <code>true</code> if the specified string represents an integer or * floating point numeric value; <code>false</code> otherwise */ bool isNumber(const char *string) { if (string && *string != '\0') { /* Skip a leading + or - sign. */ if (*string == '+' || *string == '-') { string++; } if (isdigit(*string)) { /* Declare a variable to point to the end of the source string. */ char *endPointer = NULL; /* Parse a floating point value from the source string. */ double dummy = strtod(string, &endPointer); /* Skip any trailing whitespace. */ while (endPointer && *endPointer != '\0' && isspace(*endPointer)) { endPointer++; } /* Test whether we parsed a valid number. */ if (dummy != 0.0 || (endPointer != string && *endPointer == '\0')) { return (TRUE); } } } return (FALSE); }