root/lib/pdf/xpdf/GString.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. size
  2. resize
  3. fromInt
  4. format
  5. formatv
  6. clear
  7. append
  8. append
  9. append
  10. append
  11. appendf
  12. appendfv
  13. formatInt
  14. formatUInt
  15. formatDouble
  16. insert
  17. insert
  18. insert
  19. insert
  20. del
  21. upperCase
  22. lowerCase
  23. cmp
  24. cmpN
  25. cmp
  26. cmpN

//========================================================================
//
// GString.cc
//
// Simple variable-length string type.
//
// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================

#include <aconf.h>

#ifdef USE_GCC_PRAGMAS
#pragma implementation
#endif

#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include "gmem.h"
#include "GString.h"

//------------------------------------------------------------------------

union GStringFormatArg {
  int i;
  Guint ui;
  long l;
  Gulong ul;
  double f;
  char c;
  char *s;
  GString *gs;
};

enum GStringFormatType {
  fmtIntDecimal,
  fmtIntHex,
  fmtIntOctal,
  fmtIntBinary,
  fmtUIntDecimal,
  fmtUIntHex,
  fmtUIntOctal,
  fmtUIntBinary,
  fmtLongDecimal,
  fmtLongHex,
  fmtLongOctal,
  fmtLongBinary,
  fmtULongDecimal,
  fmtULongHex,
  fmtULongOctal,
  fmtULongBinary,
  fmtDouble,
  fmtDoubleTrim,
  fmtChar,
  fmtString,
  fmtGString,
  fmtSpace
};

static char *formatStrings[] = {
  "d", "x", "o", "b", "ud", "ux", "uo", "ub",
  "ld", "lx", "lo", "lb", "uld", "ulx", "ulo", "ulb",
  "f", "g",
  "c",
  "s",
  "t",
  "w",
  NULL
};

//------------------------------------------------------------------------

static inline int size(int len) {
  int delta;
  for (delta = 8; delta < len && delta < 0x100000; delta <<= 1) ;
  // this is ((len + 1) + (delta - 1)) & ~(delta - 1)
  return (len + delta) & ~(delta - 1);
}

inline void GString::resize(int length1) {
  char *s1;

  if (!s) {
    s = new char[size(length1)];
  } else if (size(length1) != size(length)) {
    s1 = new char[size(length1)];
    if (length1 < length) {
      memcpy(s1, s, length1);
      s1[length1] = '\0';
    } else {
      memcpy(s1, s, length + 1);
    }
    delete[] s;
    s = s1;
  }
}

GString::GString() {
  s = NULL;
  resize(length = 0);
  s[0] = '\0';
}

GString::GString(const char *sA) {
  int n = strlen(sA);

  s = NULL;
  resize(length = n);
  memcpy(s, sA, n + 1);
}

GString::GString(const char *sA, int lengthA) {
  s = NULL;
  resize(length = lengthA);
  memcpy(s, sA, length * sizeof(char));
  s[length] = '\0';
}

GString::GString(GString *str, int idx, int lengthA) {
  s = NULL;
  resize(length = lengthA);
  memcpy(s, str->getCString() + idx, length);
  s[length] = '\0';
}

GString::GString(GString *str) {
  s = NULL;
  resize(length = str->getLength());
  memcpy(s, str->getCString(), length + 1);
}

GString::GString(GString *str1, GString *str2) {
  int n1 = str1->getLength();
  int n2 = str2->getLength();

  s = NULL;
  resize(length = n1 + n2);
  memcpy(s, str1->getCString(), n1);
  memcpy(s + n1, str2->getCString(), n2 + 1);
}

GString *GString::fromInt(int x) {
  char buf[24]; // enough space for 64-bit ints plus a little extra
  char *p;
  int len;

  formatInt(x, buf, sizeof(buf), gFalse, 0, 10, &p, &len);
  return new GString(p, len);
}

GString *GString::format(char *fmt, ...) {
  va_list argList;
  GString *s;

  s = new GString();
  va_start(argList, fmt);
  s->appendfv(fmt, argList);
  va_end(argList);
  return s;
}

GString *GString::formatv(char *fmt, va_list argList) {
  GString *s;

  s = new GString();
  s->appendfv(fmt, argList);
  return s;
}

GString::~GString() {
  delete[] s;
}

GString *GString::clear() {
  s[length = 0] = '\0';
  resize(0);
  return this;
}

GString *GString::append(char c) {
  resize(length + 1);
  s[length++] = c;
  s[length] = '\0';
  return this;
}

GString *GString::append(GString *str) {
  int n = str->getLength();

  resize(length + n);
  memcpy(s + length, str->getCString(), n + 1);
  length += n;
  return this;
}

GString *GString::append(const char *str) {
  int n = strlen(str);

  resize(length + n);
  memcpy(s + length, str, n + 1);
  length += n;
  return this;
}

GString *GString::append(const char *str, int lengthA) {
  resize(length + lengthA);
  memcpy(s + length, str, lengthA);
  length += lengthA;
  s[length] = '\0';
  return this;
}

GString *GString::appendf(char *fmt, ...) {
  va_list argList;

  va_start(argList, fmt);
  appendfv(fmt, argList);
  va_end(argList);
  return this;
}

GString *GString::appendfv(char *fmt, va_list argList) {
  GStringFormatArg *args;
  int argsLen, argsSize;
  GStringFormatArg arg;
  int idx, width, prec;
  GBool reverseAlign, zeroFill;
  GStringFormatType ft;
  char buf[65];
  int len, i;
  char *p0, *p1, *str;

  argsLen = 0;
  argsSize = 8;
  args = (GStringFormatArg *)gmallocn(argsSize, sizeof(GStringFormatArg));

  p0 = fmt;
  while (*p0) {
    if (*p0 == '{') {
      ++p0;
      if (*p0 == '{') {
        ++p0;
        append('{');
      } else {

        // parse the format string
        if (!(*p0 >= '0' && *p0 <= '9')) {
          break;
        }
        idx = *p0 - '0';
        for (++p0; *p0 >= '0' && *p0 <= '9'; ++p0) {
          idx = 10 * idx + (*p0 - '0');
        }
        if (*p0 != ':') {
          break;
        }
        ++p0;
        if (*p0 == '-') {
          reverseAlign = gTrue;
          ++p0;
        } else {
          reverseAlign = gFalse;
        }
        width = 0;
        zeroFill = *p0 == '0';
        for (; *p0 >= '0' && *p0 <= '9'; ++p0) {
          width = 10 * width + (*p0 - '0');
        }
        if (*p0 == '.') {
          ++p0;
          prec = 0;
          for (; *p0 >= '0' && *p0 <= '9'; ++p0) {
            prec = 10 * prec + (*p0 - '0');
          }
        } else {
          prec = 0;
        }
        for (ft = (GStringFormatType)0;
             formatStrings[ft];
             ft = (GStringFormatType)(ft + 1)) {
          if (!strncmp(p0, formatStrings[ft], strlen(formatStrings[ft]))) {
            break;
          }
        }
        if (!formatStrings[ft]) {
          break;
        }
        p0 += strlen(formatStrings[ft]);
        if (*p0 != '}') {
          break;
        }
        ++p0;

        // fetch the argument
        if (idx > argsLen) {
          break;
        }
        if (idx == argsLen) {
          if (argsLen == argsSize) {
            argsSize *= 2;
            args = (GStringFormatArg *)greallocn(args, argsSize,
                                                 sizeof(GStringFormatArg));
          }
          switch (ft) {
          case fmtIntDecimal:
          case fmtIntHex:
          case fmtIntOctal:
          case fmtIntBinary:
          case fmtSpace:
            args[argsLen].i = va_arg(argList, int);
            break;
          case fmtUIntDecimal:
          case fmtUIntHex:
          case fmtUIntOctal:
          case fmtUIntBinary:
            args[argsLen].ui = va_arg(argList, Guint);
            break;
          case fmtLongDecimal:
          case fmtLongHex:
          case fmtLongOctal:
          case fmtLongBinary:
            args[argsLen].l = va_arg(argList, long);
            break;
          case fmtULongDecimal:
          case fmtULongHex:
          case fmtULongOctal:
          case fmtULongBinary:
            args[argsLen].ul = va_arg(argList, Gulong);
            break;
          case fmtDouble:
          case fmtDoubleTrim:
            args[argsLen].f = va_arg(argList, double);
            break;
          case fmtChar:
            args[argsLen].c = (char)va_arg(argList, int);
            break;
          case fmtString:
            args[argsLen].s = va_arg(argList, char *);
            break;
          case fmtGString:
            args[argsLen].gs = va_arg(argList, GString *);
            break;
          }
          ++argsLen;
        }

        // format the argument
        arg = args[idx];
        switch (ft) {
        case fmtIntDecimal:
          formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 10, &str, &len);
          break;
        case fmtIntHex:
          formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 16, &str, &len);
          break;
        case fmtIntOctal:
          formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
          break;
        case fmtIntBinary:
          formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
          break;
        case fmtUIntDecimal:
          formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 10,
                     &str, &len);
          break;
        case fmtUIntHex:
          formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 16,
                     &str, &len);
          break;
        case fmtUIntOctal:
          formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
          break;
        case fmtUIntBinary:
          formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
          break;
        case fmtLongDecimal:
          formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 10, &str, &len);
          break;
        case fmtLongHex:
          formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 16, &str, &len);
          break;
        case fmtLongOctal:
          formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
          break;
        case fmtLongBinary:
          formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
          break;
        case fmtULongDecimal:
          formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 10,
                     &str, &len);
          break;
        case fmtULongHex:
          formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 16,
                     &str, &len);
          break;
        case fmtULongOctal:
          formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
          break;
        case fmtULongBinary:
          formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
          break;
        case fmtDouble:
          formatDouble(arg.f, buf, sizeof(buf), prec, gFalse, &str, &len);
          break;
        case fmtDoubleTrim:
          formatDouble(arg.f, buf, sizeof(buf), prec, gTrue, &str, &len);
          break;
        case fmtChar:
          buf[0] = arg.c;
          str = buf;
          len = 1;
          reverseAlign = !reverseAlign;
          break;
        case fmtString:
          str = arg.s;
          len = strlen(str);
          reverseAlign = !reverseAlign;
          break;
        case fmtGString:
          str = arg.gs->getCString();
          len = arg.gs->getLength();
          reverseAlign = !reverseAlign;
          break;
        case fmtSpace:
          str = buf;
          len = 0;
          width = arg.i;
          break;
        }

        // append the formatted arg, handling width and alignment
        if (!reverseAlign && len < width) {
          for (i = len; i < width; ++i) {
            append(' ');
          }
        }
        append(str, len);
        if (reverseAlign && len < width) {
          for (i = len; i < width; ++i) {
            append(' ');
          }
        }
      }

    } else if (*p0 == '}') {
      ++p0;
      if (*p0 == '}') {
        ++p0;
      }
      append('}');
      
    } else {
      for (p1 = p0 + 1; *p1 && *p1 != '{' && *p1 != '}'; ++p1) ;
      append(p0, p1 - p0);
      p0 = p1;
    }
  }

  gfree(args);
  return this;
}

void GString::formatInt(long x, char *buf, int bufSize,
                        GBool zeroFill, int width, int base,
                        char **p, int *len) {
  static char vals[17] = "0123456789abcdef";
  GBool neg;
  int start, i, j;

  i = bufSize;
  if ((neg = x < 0)) {
    x = -x;
  }
  start = neg ? 1 : 0;
  if (x == 0) {
    buf[--i] = '0';
  } else {
    while (i > start && x) {
      buf[--i] = vals[x % base];
      x /= base;
    }
  }
  if (zeroFill) {
    for (j = bufSize - i; i > start && j < width - start; ++j) {
      buf[--i] = '0';
    }
  }
  if (neg) {
    buf[--i] = '-';
  }
  *p = buf + i;
  *len = bufSize - i;
}

void GString::formatUInt(Gulong x, char *buf, int bufSize,
                         GBool zeroFill, int width, int base,
                         char **p, int *len) {
  static char vals[17] = "0123456789abcdef";
  int i, j;

  i = bufSize;
  if (x == 0) {
    buf[--i] = '0';
  } else {
    while (i > 0 && x) {
      buf[--i] = vals[x % base];
      x /= base;
    }
  }
  if (zeroFill) {
    for (j = bufSize - i; i > 0 && j < width; ++j) {
      buf[--i] = '0';
    }
  }
  *p = buf + i;
  *len = bufSize - i;
}

void GString::formatDouble(double x, char *buf, int bufSize, int prec,
                           GBool trim, char **p, int *len) {
  GBool neg, started;
  double x2;
  int d, i, j;

  if ((neg = x < 0)) {
    x = -x;
  }
  x = floor(x * pow(10, prec) + 0.5);
  i = bufSize;
  started = !trim;
  for (j = 0; j < prec && i > 1; ++j) {
    x2 = floor(0.1 * (x + 0.5));
    d = (int)floor(x - 10 * x2 + 0.5);
    if (started || d != 0) {
      buf[--i] = '0' + d;
      started = gTrue;
    }
    x = x2;
  }
  if (i > 1 && started) {
    buf[--i] = '.';
  }
  if (i > 1) {
    do {
      x2 = floor(0.1 * (x + 0.5));
      d = (int)floor(x - 10 * x2 + 0.5);
      buf[--i] = '0' + d;
      x = x2;
    } while (i > 1 && x);
  }
  if (neg) {
    buf[--i] = '-';
  }
  *p = buf + i;
  *len = bufSize - i;
}

GString *GString::insert(int i, char c) {
  int j;

  resize(length + 1);
  for (j = length + 1; j > i; --j)
    s[j] = s[j-1];
  s[i] = c;
  ++length;
  return this;
}

GString *GString::insert(int i, GString *str) {
  int n = str->getLength();
  int j;

  resize(length + n);
  for (j = length; j >= i; --j)
    s[j+n] = s[j];
  memcpy(s+i, str->getCString(), n);
  length += n;
  return this;
}

GString *GString::insert(int i, const char *str) {
  int n = strlen(str);
  int j;

  resize(length + n);
  for (j = length; j >= i; --j)
    s[j+n] = s[j];
  memcpy(s+i, str, n);
  length += n;
  return this;
}

GString *GString::insert(int i, const char *str, int lengthA) {
  int j;

  resize(length + lengthA);
  for (j = length; j >= i; --j)
    s[j+lengthA] = s[j];
  memcpy(s+i, str, lengthA);
  length += lengthA;
  return this;
}

GString *GString::del(int i, int n) {
  int j;

  if (n > 0) {
    if (i + n > length) {
      n = length - i;
    }
    for (j = i; j <= length - n; ++j) {
      s[j] = s[j + n];
    }
    resize(length -= n);
  }
  return this;
}

GString *GString::upperCase() {
  int i;

  for (i = 0; i < length; ++i) {
    if (islower(s[i]))
      s[i] = toupper(s[i]);
  }
  return this;
}

GString *GString::lowerCase() {
  int i;

  for (i = 0; i < length; ++i) {
    if (isupper(s[i]))
      s[i] = tolower(s[i]);
  }
  return this;
}

int GString::cmp(GString *str) {
  int n1, n2, i, x;
  char *p1, *p2;

  n1 = length;
  n2 = str->length;
  for (i = 0, p1 = s, p2 = str->s; i < n1 && i < n2; ++i, ++p1, ++p2) {
    x = *p1 - *p2;
    if (x != 0) {
      return x;
    }
  }
  return n1 - n2;
}

int GString::cmpN(GString *str, int n) {
  int n1, n2, i, x;
  char *p1, *p2;

  n1 = length;
  n2 = str->length;
  for (i = 0, p1 = s, p2 = str->s;
       i < n1 && i < n2 && i < n;
       ++i, ++p1, ++p2) {
    x = *p1 - *p2;
    if (x != 0) {
      return x;
    }
  }
  if (i == n) {
    return 0;
  }
  return n1 - n2;
}

int GString::cmp(const char *sA) {
  int n1, i, x;
  const char *p1, *p2;

  n1 = length;
  for (i = 0, p1 = s, p2 = sA; i < n1 && *p2; ++i, ++p1, ++p2) {
    x = *p1 - *p2;
    if (x != 0) {
      return x;
    }
  }
  if (i < n1) {
    return 1;
  }
  if (*p2) {
    return -1;
  }
  return 0;
}

int GString::cmpN(const char *sA, int n) {
  int n1, i, x;
  const char *p1, *p2;

  n1 = length;
  for (i = 0, p1 = s, p2 = sA; i < n1 && *p2 && i < n; ++i, ++p1, ++p2) {
    x = *p1 - *p2;
    if (x != 0) {
      return x;
    }
  }
  if (i == n) {
    return 0;
  }
  if (i < n1) {
    return 1;
  }
  if (*p2) {
    return -1;
  }
  return 0;
}

/* [<][>][^][v][top][bottom][index][help] */