circlemud_squared_0.5.153/cnf/
circlemud_squared_0.5.153/etc/
circlemud_squared_0.5.153/etc/etc/
circlemud_squared_0.5.153/etc/house/
circlemud_squared_0.5.153/etc/misc/
circlemud_squared_0.5.153/etc/plralias/A-E/
circlemud_squared_0.5.153/etc/plralias/F-J/
circlemud_squared_0.5.153/etc/plralias/K-O/
circlemud_squared_0.5.153/etc/plralias/P-T/
circlemud_squared_0.5.153/etc/plralias/U-Z/
circlemud_squared_0.5.153/etc/plralias/ZZZ/
circlemud_squared_0.5.153/etc/plrobjs/
circlemud_squared_0.5.153/etc/plrobjs/A-E/
circlemud_squared_0.5.153/etc/plrobjs/F-J/
circlemud_squared_0.5.153/etc/plrobjs/K-O/
circlemud_squared_0.5.153/etc/plrobjs/P-T/
circlemud_squared_0.5.153/etc/plrobjs/U-Z/
circlemud_squared_0.5.153/etc/plrobjs/ZZZ/
circlemud_squared_0.5.153/etc/text/
circlemud_squared_0.5.153/etc/text/help/
circlemud_squared_0.5.153/src/util/
circlemud_squared_0.5.153/src/util/worldconv/
/**
 * @file act_alias.c
 *
 * Alias routine implementations.
 *
 * @author Geoff Davis <geoff@circlemudsquared.org>
 * @ingroup alias
 * @license All rights reserved.  See license.doc for complete information.
 * @package cs
 * @since v1.0
 *
 * Copyright (C) 2006 Geoff Davis <geoff@circlemudsquared.org>
 *                    Greg Buxton <greg@circlemudsquared.org>
 *
 * Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University
 * CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.
 */

#define __ACT_ALIAS_C__

#include "conf.h"
#include "sysdep.h"
#include "structs.h"
#include "utils.h"
#include "alias.h"
#include "comm.h"
#include "command.h"
#include "db.h"
#include "interpreter.h"
#include "log.h"

/**
 * Writes a player's aliases to disk.
 * @param ch the player whose aliases are to be written to disk
 * @return none
 */
void write_aliases(charData_t *ch)
{
  FILE *file;
  char fn[MAX_STRING_LENGTH];
  aliasData_t *temp;

  get_filename(fn, sizeof(fn), ALIAS_FILE, GET_NAME(ch));
  remove(fn);

  if (GET_ALIASES(ch) == NULL)
    return;

  if ((file = fopen(fn, "w")) == NULL) {
    log("SYSERR: Couldn't save aliases for %s in '%s'.", GET_NAME(ch), fn);
    perror("SYSERR: write_aliases");
    return;
  }

  for (temp = GET_ALIASES(ch); temp; temp = temp->next) {
    int aliaslen = strlen(temp->alias);
    int repllen = strlen(temp->replacement) - 1;

    fprintf(file, "%d\n%s\n"	/* Alias */
		  "%d\n%s\n"	/* Replacement */
		  "%d\n",	/* type */
		aliaslen, temp->alias,
		repllen, temp->replacement + 1,
		temp->type);
  }
  
  fclose(file);
}

/**
 * Reads a player's aliases from disk.
 * @param ch the player whose aliases are to be read from disk
 * @return none
 */
void read_aliases(charData_t *ch)
{   
  FILE *file;
  char xbuf[MAX_STRING_LENGTH];
  aliasData_t *t2, *prev = NULL;
  int length;

  get_filename(xbuf, sizeof(xbuf), ALIAS_FILE, GET_NAME(ch));

  if ((file = fopen(xbuf, "r")) == NULL) {
    if (errno != ENOENT) {
      log("SYSERR: Couldn't open alias file '%s' for %s.", xbuf, GET_NAME(ch));
      perror("SYSERR: read_aliases");
    }
    return;
  }
 
  CREATE(GET_ALIASES(ch), aliasData_t, 1);
  t2 = GET_ALIASES(ch); 

  for (;;) {
    /* Read the aliased command. */
    if (fscanf(file, "%d\n", &length) != 1)
      goto read_alias_error;

    fgets(xbuf, length + 1, file);
    t2->alias = strdup(xbuf);

    /* Build the replacement. */
    if (fscanf(file, "%d\n", &length) != 1)
       goto read_alias_error;

    *xbuf = ' ';		/* Doesn't need terminated, fgets() will. */
    fgets(xbuf + 1, length + 1, file);
    t2->replacement = strdup(xbuf); 

    /* Figure out the alias type. */
    if (fscanf(file, "%d\n", &length) != 1)
      goto read_alias_error;

    t2->type = length;

    if (feof(file))
      break;

    CREATE(t2->next, aliasData_t, 1);
    prev = t2;
    t2 = t2->next;
  }; 
  
  fclose(file);
  return;

read_alias_error:
  if (t2->alias)
    free(t2->alias);
  free(t2);
  if (prev)
    prev->next = NULL;
  fclose(file);
} 

/**
 * Deletes the aliases file for the named player.
 * @param charname the name of the player whose alias file is to be deleted
 * @return none
 */
void delete_aliases(const char *charname)
{
  char filename[PATH_MAX];

  if (!get_filename(filename, sizeof(filename), ALIAS_FILE, charname))
    return;

  if (remove(filename) < 0 && errno != ENOENT)
    log("SYSERR: deleting alias file %s: %s", filename, strerror(errno));
}

/**
 * Searches for an alias by name.
 * @param aliases the list of aliases to be searched
 * @param str the name of the alias for which to search
 * @return the named alias, or NULL if the alias cannot be found
 */
aliasData_t *find_alias(aliasData_t *aliases, const char *str)
{
  /* Iterate over the list of aliases. */
  while (aliases != NULL) {
    /* Check whether this is the alias we're searching for. */
    if (strcasecmp(str, aliases->alias) == 0) {
      return (aliases);
    }
    /* Advance to the next alias in the list. */
    aliases = aliases->next;
  }
  return (NULL);
}

/**
 * Frees an alias.
 * @param alias the alias to be freed
 * @return none
 */
void free_alias(aliasData_t *alias)
{
  if (alias->alias)
    free(alias->alias);
  if (alias->replacement)
    free(alias->replacement);
  free(alias);
}

/**
 * The ALIAS command.
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @returns none
 */
ACMD(do_alias)
{
  char arg[MAX_INPUT_LENGTH];
  char *repl;
  aliasData_t *a, *temp;

  if (IS_NPC(ch))
    return;

  repl = any_one_arg(argument, arg);

  if (!*arg) {                  /* no argument specified -- list currently defined aliases */
    send_to_char(ch, "Currently defined aliases:\r\n");
    if ((a = GET_ALIASES(ch)) == NULL)
      send_to_char(ch, " None.\r\n");
    else {
      while (a != NULL) {
        send_to_char(ch, "%-15s %s\r\n", a->alias, a->replacement);
        a = a->next;
      }
    }
  } else {                      /* otherwise, add or remove aliases */
    /* is this an alias we've already defined? */
    if ((a = find_alias(GET_ALIASES(ch), arg)) != NULL) {
      REMOVE_FROM_LIST(a, GET_ALIASES(ch), next);
      free_alias(a);
    }
    /* if no replacement string is specified, assume we want to delete */
    if (!*repl) {
      if (a == NULL)
        send_to_char(ch, "No such alias.\r\n");
      else
        send_to_char(ch, "Alias deleted.\r\n");
    } else {                    /* otherwise, either add or redefine an alias */
      if (!str_cmp(arg, "alias")) {
        send_to_char(ch, "You can't alias 'alias'.\r\n");
        return;
      }
      CREATE(a, aliasData_t, 1);
      a->alias = strdup(arg);
      delete_doubledollar(repl);
      a->replacement = strdup(repl);
      if (strchr(repl, ALIAS_SEP_CHAR) || strchr(repl, ALIAS_VAR_CHAR)) {
        a->type = ALIAS_COMPLEX;
      } else {
        a->type = ALIAS_SIMPLE;
      }
      a->next = GET_ALIASES(ch);
      GET_ALIASES(ch) = a;
      send_to_char(ch, "Alias added.\r\n");
    }
  }
}

/*
 * Valid numeric replacements are only $1 .. $9 (makes parsing a little
 * easier, and it's not that much of a limitation anyway.)  Also valid
 * is "$*", which stands for the entire original line after the alias.
 * ";" is used to delimit commands.
 */
#define NUM_TOKENS       9

/**
 * Performs a complex alias replacement.
 * @param input_q the character's input queue
 * @param orig the original string to be processed
 * @param alias the corresponding alias
 * @return none
 */
void perform_complex_alias(textQueue_t *input_q, char *orig, aliasData_t *alias)
{
  textQueue_t temp_queue;
  char *tokens[NUM_TOKENS], *temp, *write_point;
  char buf2[MAX_RAW_INPUT_LENGTH], buf[MAX_RAW_INPUT_LENGTH];   /* raw? */
  int num_of_tokens = 0, num;

  /* First, parse the original string */
  strcpy(buf2, orig);   /* strcpy: OK (orig:MAX_INPUT_LENGTH < buf2:MAX_RAW_INPUT_LENGTH) */
  temp = strtok(buf2, " ");
  while (temp != NULL && num_of_tokens < NUM_TOKENS) {
    tokens[num_of_tokens++] = temp;
    temp = strtok(NULL, " ");
  }

  /* initialize */
  write_point = buf;
  temp_queue.head = temp_queue.tail = NULL;

  /* now parse the alias */
  for (temp = alias->replacement; *temp; temp++) {
    if (*temp == ALIAS_SEP_CHAR) {
      *write_point = '\0';
      buf[MAX_INPUT_LENGTH - 1] = '\0';
      write_to_q(buf, &temp_queue, 1);
      write_point = buf;
    } else if (*temp == ALIAS_VAR_CHAR) {
      temp++;
      if ((num = *temp - '1') < num_of_tokens && num >= 0) {
        strcpy(write_point, tokens[num]);       /* strcpy: OK */
        write_point += strlen(tokens[num]);
      } else if (*temp == ALIAS_GLOB_CHAR) {
        strcpy(write_point, orig);              /* strcpy: OK */
        write_point += strlen(orig);
      } else if ((*(write_point++) = *temp) == '$')     /* redouble $ for act safety */
        *(write_point++) = '$';
    } else
      *(write_point++) = *temp;
  }

  *write_point = '\0';
  buf[MAX_INPUT_LENGTH - 1] = '\0';
  write_to_q(buf, &temp_queue, 1);

  /* push our temp_queue on to the _front_ of the input queue */
  if (input_q->head == NULL)
    *input_q = temp_queue;
  else {
    temp_queue.tail->next = input_q->head;
    input_q->head = temp_queue.head;
  }
}

/**
 * Performs an alias replacement on a given string.
 * @param d the descriptor at which the alias replacement occurs
 * @param orig the original string to be processed
 * @param maxlen the maximum length of the resulting string
 * @return 0 if the string was modified in place;
 *         1 if the string was _not_ modified in place and expanded aliases
 *           have been placed at the front of the character's input queue
 */
int perform_alias(descriptorData_t *d, char *orig, size_t maxlen)
{
  char first_arg[MAX_INPUT_LENGTH], *ptr;
  aliasData_t *a, *tmp;

  /* Mobs don't have alaises. */
  if (IS_NPC(d->character))
    return (0);

  /* bail out immediately if the guy doesn't have any aliases */
  if ((tmp = GET_ALIASES(d->character)) == NULL)
    return (0);

  /* find the alias we're supposed to match */
  ptr = any_one_arg(orig, first_arg);

  /* bail out if it's null */
  if (!*first_arg)
    return (0);

  /* if the first arg is not an alias, return without doing anything */
  if ((a = find_alias(tmp, first_arg)) == NULL)
    return (0);

  if (a->type == ALIAS_SIMPLE) {
    strlcpy(orig, a->replacement, maxlen);
    return (0);
  } else {
    perform_complex_alias(&d->input, ptr, a);
    return (1);
  }
}