diff anagram/support/agstring.cpp @ 0:13d2b8934445

Import AnaGram (near-)release tree into Mercurial.
author David A. Holland
date Sat, 22 Dec 2007 17:52:45 -0500
parents
children 57b2cc9b87f7
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/anagram/support/agstring.cpp	Sat Dec 22 17:52:45 2007 -0500
@@ -0,0 +1,578 @@
+/**********************************************************
+
+The AnaGram Class Library
+
+The AgString Class
+Copyright 1997-2002 Parsifal Software. All Rights Reserved.
+See the file COPYING for license and usage terms.
+
+***********************************************************/
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "port.h"
+
+#include "agstring.h"
+#include "assert.h"
+#include "csexp.h"  // sigh... XXX  (for agToUpper)
+
+//#define INCLUDE_LOGGING
+#include "log.h"
+
+
+void AgString::allocate(unsigned n) {
+  // XXX shouldn't this be just n+sizeof(short)? There's no need to round
+  // up, and this isn't a correct roundup anyway...
+  // (and what if malloc returns NULL?)
+  store = (char *) malloc(((n+sizeof(short))/sizeof(short) + 1)*sizeof(short))
+    + sizeof(short);
+}
+
+void AgString::lock() {
+  if (store) {
+    (((short *) (void *)store)[-1])++;
+  }
+}
+
+void AgString::unlock() {
+  if (store && --(((short *) (void *) store)[-1]) <= 0) {
+    //delete [] (store - sizeof(short));
+    free(store - sizeof(short));
+  }
+  store = 0;
+}
+
+AgString::AgString(const char *s)
+  : AgIndexedContainer<char>()
+{
+  LOGSECTION("AgString::AgString(const char *)");
+  LOGV(s);
+  if (s) {
+    allocate(strlen(s));
+    assert(store != 0);
+    ((short *) (void *)store)[-1] = 1;
+    strcpy(store, s);
+    LOGV(store);
+  }
+  else store = 0;
+}
+
+AgString::AgString(const unsigned n)
+{
+  if (n) {
+    allocate(n);
+    assert(store != 0);
+    ((short *) (void *)store)[-1] = 1;
+    memset(store, 0, n+1);
+  }
+  else {
+    store = 0;
+  }
+}
+
+AgString::AgString(const char *s, const unsigned n)
+{
+  if (n) {
+    allocate(n);
+    unsigned k = strlen(s);
+    if (n < k) {
+      k = n;
+    }
+    assert(store != 0);
+    ((short *)(void *) store)[-1] = 1;
+    if (s) {
+      strncpy(store, s, k);
+    }
+    store[k] = 0;
+  }
+  else {
+    store = 0;
+  }
+}
+
+AgString::AgString(const AgString &s, const unsigned n)
+{
+  if (n) {
+    allocate(n);
+    assert(store != 0);
+    ((short *)(void *) store)[-1] = 1;
+    if (s.store) {
+      strncpy(store, s.store, n);
+    }
+    store[n] = 0;
+  }
+  else {
+    store = 0;
+  }
+}
+
+char &AgString::operator [] (const unsigned x) {
+  assert(x < size());
+  return store[x];
+}
+
+const char &AgString::operator [] (const unsigned x) const {
+  assert(x < size());
+  return store[x];
+}
+
+AgString &AgString::operator = (const AgString &s) {
+  unlock();
+  store = s.store;
+  lock();
+  return *this;
+}
+
+AgString &AgString::toUpper() {
+  if (store) {
+    char *s = store;
+    while (*s) {
+      *s = (char) agToUpper(*s);
+      s++;
+    }
+  }
+  return *this;
+}
+
+/*
+AgString &AgString::toLower() {
+  if (store) {
+    char *s = store;
+    while (*s) {
+      *s = (char) tolower(*s);
+      s++;
+    }
+  }
+  return *this;
+}
+*/
+
+int AgString::operator < (const AgString &s) const {
+  //LOGSECTION("AgString::operator <");
+  if (store == s.store) {
+    return 0;
+  }
+  else if (store && s.store) {
+    //LOGV(store) LCV(s.store);
+    return strcmp(store, s.store) < 0;
+  }
+  else {
+    return store == 0;
+  }
+}
+
+int AgString::operator < (const char *s) const {
+  if (store == s) {
+    return 0;
+  }
+  else if (store && s) {
+    return strcmp(store, s) < 0;
+  }
+  else {
+    return store == 0;
+  }
+}
+
+int AgString::operator <= (const AgString &s) const {
+  if (store == s.store) {
+    return 1;
+  }
+  else if (store && s.store) {
+    return strcmp(store, s.store) <= 0;
+  }
+  else {
+    return store == 0;
+  }
+}
+
+int AgString::operator <= (const char *s) const {
+  if (store == s) {
+    return 1;
+  }
+  else if (store && s) {
+    return strcmp(store, s) <= 0;
+  }
+  else {
+    return store == 0;
+  }
+}
+
+int AgString::operator > (const AgString &s) const {
+  if (store == s.store) {
+    return 0;
+  }
+  else if (store && s.store) {
+    return strcmp(store, s.store) > 0;
+  }
+  else {
+    return s.store == 0;
+  }
+}
+
+int AgString::operator > (const char *s) const {
+  if (store == s) {
+    return 0;
+  }
+  else if (store && s) {
+    return strcmp(store, s) > 0;
+  }
+  else {
+    return s == 0;
+  }
+}
+
+int AgString::operator >= (const AgString &s) const {
+  if (store == s.store) {
+    return 1;
+  }
+  else if (store && s.store) {
+    return strcmp(store, s.store) >= 0;
+  }
+  else {
+    return s.store == 0;
+  }
+}
+
+int AgString::operator >= (const char *s) const {
+  if (store == s) {
+    return 1;
+  }
+  else if (store && s) {
+    return strcmp(store, s) >= 0;
+  }
+  else {
+    return s == 0;
+  }
+}
+
+int AgString::iEq(const AgString &s) const {
+  if (store == s.store) {
+    return 1;
+  }
+  if (store && s.store) {
+    return stricmp(store, s.store) == 0;
+  }
+  else {
+    return 0;
+  }
+}
+
+int AgString::iEq(const char *s) const {
+  if (store == s) {
+    return 1;
+  }
+  if (store && s) {
+    return stricmp(store, s) == 0;
+  }
+  else {
+    return 0;
+  }
+}
+
+int AgString::operator == (const AgString &s) const {
+  if (store == s.store) {
+    return 1;
+  }
+  if (store && s.store) {
+    return strcmp(store, s.store) == 0;
+  }
+  else {
+    return 0;
+  }
+}
+
+int AgString::operator == (const char *s) const {
+  if (store == s) {
+    return 1;
+  }
+  if (store && s) {
+    return strcmp(store, s) == 0;
+  }
+  else {
+    return 0;
+  }
+}
+
+int AgString::operator != (const AgString &s) const {
+  if (store == s.store) {
+    return 0;
+  }
+  if (store && s.store) {
+    return strcmp(store, s.store) != 0;
+  }
+  else {
+    return 1;
+  }
+}
+
+int AgString::operator != (const char *s) const {
+  if (store == s) {
+    return 0;
+  }
+  if (store && s) {
+    return strcmp(store, s) != 0;
+  }
+  else {
+    return 1;
+  }
+}
+
+AgString AgString::format(const char *fs, ...) {
+  va_list ap;
+  int n;
+
+  if (fs == NULL) {
+    return AgString();
+  }
+  //int bufLength = 3*strlen(fs);
+  //if (bufLength < 2000) bufLength = 2000;
+  //char *buf = new char[bufLength];
+  char buf[2000];
+
+  //assert(buf != NULL);
+
+  va_start(ap, fs);
+  n = vsprintf(buf, fs, ap);
+  assert(n < 2000);
+  va_end(ap);
+
+  AgString result(buf, n);
+  //delete [] buf;
+  return result;
+}
+
+
+// concatenation operators
+
+AgString AgString::concat(const char *s) const {
+  LOGSECTION("AgString::concat");
+  LOGV(store) LCV(s);
+  if (s == NULL) {
+    return *this;
+  }
+  if (store == NULL) {
+    return AgString(s);
+  }
+  AgString result(store, size() + strlen(s));
+  LOGV(result);
+  strcat(result.pointer(), s);
+  LOGV(result);
+  return result;
+}
+
+AgString AgString::concat(const AgString s) const {
+  if (s.store == NULL) {
+    return *this;
+  }
+  if (store == NULL) {
+    return s;
+  }
+  AgString result(store, size() + s.size());
+  strcat(result.pointer(), s.pointer());
+  return result;
+}
+
+AgString::Cut AgString::firstCut(const char c) const {
+  LOGSECTION("AgString::firstCut(char)");
+  if (store) {
+    char *p = strchr(store, c);
+    LOGV(p) LCV(c);
+/*
+    int n = p ? (int)( p - store) : -1;
+    return AgString::Cut(*this, n);
+*/
+    if (p) {
+      return AgString::Cut(*this, p - store);
+    }
+  }
+  return AgString::Cut();
+}
+
+AgString::Cut AgString::lastCut(const char c) const {
+  //LOGSECTION("lastCut");
+  if (store) {
+    char *p = strrchr(store, c);
+    //LOGV(store);
+    //LOGV(c);
+    //LOGV(p);
+    int n = p ? (int) (p - store) : strlen(store);
+    return AgString::Cut(*this, n);
+  }
+  return AgString::Cut();
+}
+
+AgString::Cut AgString::firstCut(const char *s) const {
+  LOGSECTION("firstCut(const char *)");
+  if (store) {
+    unsigned k = strcspn(store, s);
+    LOGV(store);
+    LOGV(s);
+    LOGV(k);
+    if (k < size()) {
+      return AgString::Cut(*this, k);
+    }
+  }
+  return AgString::Cut();
+}
+
+AgString::Cut AgString::lastCut(const char *s) const {
+  //LOGSECTION("lastCut");
+  if (store) {
+    int k = size();
+    while (k--) {
+      if (strchr(s, store[k])) {
+	//LOGV(store);
+	//LOGV(&store[k]);
+	//LOGV(k);
+	return AgString::Cut(*this, k);
+      }
+    }
+    return AgString::Cut(*this, size());
+  }
+  return AgString::Cut();
+}
+
+AgString::Cut::Cut(const AgString &s, const int x)
+  : store(s.pointer())
+  , index(x)
+{
+  if (store) {
+    assert((unsigned) x <= strlen(store));
+  }
+  lock();
+}
+
+void AgString::Cut::lock() {
+  if (store) {
+    (((short *) (void *)store)[-1])++;
+  }
+}
+
+void AgString::Cut::unlock() {
+  if (store && --(((short *) (void *) store)[-1]) <= 0) {
+    //delete [] (store - sizeof(short));
+    free(store - sizeof(short));
+    store = 0;
+  }
+}
+
+char &AgString::Cut::character() const {
+  assert(store != 0);
+  return store[index];
+}
+
+AgString AgString::Cut::leftI() const {
+  //LOGSECTION("Cut::leftI");
+  //LOGV(store);
+  //LOGV(index);
+  if (store == 0 || index < 0) {
+    return AgString();
+  }
+  /* Include the separator... but not if it's the null terminator. */
+  int pos = index;
+  if (store[pos]) {
+    pos++;
+  }
+  return AgString(store, pos);
+}
+
+AgString AgString::Cut::leftX() const {
+  LOGSECTION("Cut::leftX");
+  LOGV(store);
+  LOGV(index);
+  if (store == 0 || index <= 0) {
+    return AgString();
+  }
+  /* Does this end up with the wrong length if store[index]==0? XXX */
+  return AgString(store, index);
+}
+
+AgString AgString::Cut::rightI() const {
+  //LOGSECTION("Cut::rightI");
+  //LOGV(store);
+  //LOGV(index);
+  if (store == 0) {
+    return AgString();
+  }
+  if (index < 0) {
+    return AgString(store);
+  }
+  return AgString(store + index);
+}
+
+AgString AgString::Cut::rightX() const {
+  //LOGSECTION("Cut::rightX");
+  //LOGV(store);
+  //LOGV(index);
+  if (store == 0) {
+    return AgString();
+  }
+  /* Exclude the separator... but not if it's the null terminator. */
+  int pos = index;
+  if (store[pos]) {
+    pos++;
+  }
+  return AgString(store + pos);
+}
+
+/*
+AgString AgString::Cut::insertLeft(const AgString &s) const {
+  AgString newString(store, strlen(store) + s.size());
+  char *p = newString.pointer();
+  p[index] = 0;
+  strcat(p, s.pointer());
+  strcat(p, store+index);
+  return newString;
+}
+
+AgString AgString::Cut::insertLeft(const char *s) const {
+  AgString newString(store, strlen(store) + strlen(s));
+  char *p = newString.pointer();
+  p[index] = 0;
+  strcat(p, s);
+  strcat(p, store+index);
+  return newString;
+}
+
+AgString AgString::Cut::insertRight(const AgString &s) const {
+  AgString newString(store, strlen(store) + s.size());
+  char *p = newString.pointer();
+  p[index+1] = 0;
+  strcat(p, s.pointer());
+  strcat(p, store+index+1);
+  return newString;
+}
+
+AgString AgString::Cut::insertRight(const char *s) const {
+  AgString newString(store, strlen(store) + strlen(s));
+  char *p = newString.pointer();
+  p[index+1] = 0;
+  strcat(p, s);
+  strcat(p, store+index+1);
+  return newString;
+}
+
+AgString AgString::Cut::replace(const AgString &s) const {
+  if (store == 0) return AgString();
+  if (index < 0 || index > strlen(store)) return AgString(store);
+  AgString newString(store, strlen(store) + s.size() - 1);
+  char *p = newString.pointer();
+  p[index] = 0;
+  if (s.size()) strcat(p, s.pointer());
+  strcat(p, store+index+1);
+  return newString;
+}
+
+AgString AgString::Cut::replace(const char *s) const {
+  if (store == 0) return AgString();
+  if (index < 0 || index > strlen(store)) return AgString(store);
+  int n = s!= 0 ? strlen(s) : 0;
+  AgString newString(store, strlen(store) + n - 1);
+  char *p = newString.pointer();
+  p[index] = 0;
+  if (n) strcat(p, s);
+  strcat(p, store+index+1);
+  return newString;
+}
+*/