view anagram/support/agstring.cpp @ 4:bebb2ba69e1d

maybe help with getting tex to fail properly on error
author David A. Holland
date Sat, 18 Apr 2020 17:12:17 -0400
parents 13d2b8934445
children 57b2cc9b87f7
line wrap: on
line source

/**********************************************************

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;
}
*/