Logo Search packages:      
Sourcecode: papaya version File versions  Download package

History.cpp

#include <stdlib.h>
#include <string.h>
#include "History.h"
#include "mudclient.h"

// MAX_HISTORY items...
// Treated as a circular array.

History::History(int msize, bool h_circular) {
  // Setup a marker entry so that prev/next works out nicely.
  commands = (struct history_entry *) malloc(sizeof(struct history_entry));
  commands->cmd = strdup("");
  commands->prev = commands;
  commands->next = commands;

  max_size = msize;
  size = 0;
  read_pos = commands;
  write_pos = commands;
  search_pos = commands;

  setCircular(h_circular);
}

History::~History() {
  struct history_entry * kill = commands;
  struct history_entry * kill_next;

  write_pos->next = NULL; // break the circle

  while (kill) {
    kill_next = kill->next;
    free(kill->cmd);
    free(kill);
    kill = kill_next;
  }
}

char * History::getNext() {
  if (read_pos && read_pos->next != NULL)
    read_pos = read_pos->next;

  return (read_pos != NULL) ? read_pos->cmd : (char *)"";
}

char * History::getPrev() {
  if (read_pos && read_pos->prev != NULL)
    read_pos = read_pos->prev;

  return (read_pos != NULL) ? read_pos->cmd : (char *)"";
}

void History::add(char * t, gboolean ignore_same) {
  struct history_entry * new_cmd;
  char * newline;

  // This must always happen to maintain consistent scrolling
  read_pos = write_pos;
  search_pos = write_pos->prev;

  if (ignore_same && write_pos->prev && !strcmp(t, write_pos->prev->cmd)) {
    return;
  }

  /*
   * No blank history entries please.
   */
  if ( t[0] == '\0' || t[0] == '\n' )
      return;

  /*
   * If we're over the limit we'll recycle memory from the head of the list.
   * This works because this operation always resets the read_pos and write_pos
   * pointers.
   */
  if (max_size > 0 && size >= max_size) {
    new_cmd = commands;
    commands = new_cmd->next;

    free(new_cmd->cmd);
  } else {
    new_cmd = (struct history_entry *) malloc(sizeof(struct history_entry));
    ++size;
  }

  if (commands == NULL || commands == write_pos)
    commands = new_cmd;

  new_cmd->cmd  = strdup(t);
  new_cmd->next = write_pos;
  new_cmd->prev = write_pos->prev;

  if (write_pos->prev != NULL)
    write_pos->prev->next = new_cmd;
  write_pos->prev = new_cmd;
  if (circular) {
    write_pos->next = commands;
    commands->prev = write_pos;
  } else {
    write_pos->next = NULL;
    commands->prev = NULL;
  }

  /*
   * We've just added an item, so re-set the tab search pos.  We don't
   * need to reset the read_pos in the same way since it is bound to
   * write_pos, which never changes.
   */
  search_pos = write_pos->prev;
  
  newline = strchr(new_cmd->cmd, '\n');
  if (newline)
    *newline = '\0'; // Get rid of the \n...
}

char * History::findMatch(char * string, gboolean honour_null) {
  int len = strlen(string);
  static char * last_string = NULL;
  char * r_val;

  if ( last_string == NULL || strcasecmp( string, last_string ) )
  {
      if ( last_string != NULL )
        free( last_string );

      last_string = strdup( string );
      search_pos = write_pos->prev;
  }

  /*
   * We can't allow write_pos to match because it is a null string which
   * throws off circular looping.
   */
  if (search_pos == write_pos)
  {
      search_pos = write_pos->prev;
      return NULL;
  }

  if (!len && !honour_null)
    return NULL;

  for ( ; search_pos != NULL && search_pos != write_pos; search_pos = search_pos->prev) {
    if (!strncasecmp(search_pos->cmd, string, len)) {
      r_val = search_pos->cmd;
      search_pos = search_pos->prev;
      return r_val;
    }
  }

  return NULL;
}

void History::setMaxSize(int new_size) {
  max_size = new_size;

  /*
   * A max_size of 0 is taken as being infinitely large
   */
  if (size > max_size && max_size != 0 ) {
    int count;
    int free_count = size - max_size;
    struct history_entry * nuke;
    struct history_entry * next_nuke = commands;

    for (count = 0; count < free_count; ++count) {
      nuke = next_nuke;
      next_nuke = nuke->next;

      if (nuke == write_pos)
      break;

      free(nuke->cmd);
      free(nuke);

      commands = next_nuke;
    }

    size -= count;

    if (circular) {
      write_pos->next = commands;
      commands->prev = write_pos;
    } else {
      commands->prev = NULL;
      write_pos->next = NULL;
    }

    read_pos = write_pos;
    search_pos = write_pos->prev;
  }
}

void History::setCircular(bool b) {
  circular = b;

  if (b) {
    commands->prev = write_pos;
    write_pos->next = commands;
  } else {
    commands->prev = NULL;
    write_pos->next = NULL;
  }
}

Generated by  Doxygen 1.6.0   Back to index