#ifdef DOC_BUILD_INTERNAL
#endif
#include <ctype.h>
#include "strings.h"
#include "list.h"
BOOL string_Equal(const char* S1, const char* S2)
{
  return strcmp(S1, S2) == 0;
}
BOOL string_IsPrefix(const char *Pre, const char *Str)
{
  if ('\0' == *Pre) return TRUE;
  if (*Pre != *Str) return FALSE;
  return string_IsPrefix(Pre+1, Str+1);
}
int string_Length(const char* Str)
{
  return strlen(Str);
}
BOOL string_StringIsNumber(const char* String)
{
  int i;
  if (String == NULL || String[0] == '\0')
    return FALSE;
  i = 0;
  while (String[i] != '\0')
    if (String[i] >= '0' && String[i] <= '9')
      i++;
    else
      return FALSE;
  return TRUE;
}
BOOL string_StringIsInteger(const char* String)
{
  int i;
  if (String == NULL || String[0] == '\0')
    return FALSE;
  i = 0;
  if(String[i] == '-' && String[i+1] != '\0'){
    i++;
  }
  while (String[i] != '\0')
    if (String[i] >= '0' && String[i] <= '9')
      i++;
    else
      return FALSE;
  return TRUE;
}
BOOL string_StringIsNatural(const char* String)
{
  int i;
  if (String == NULL || String[0] == '\0')
    return FALSE;
  i = 0;
  while (String[i] != '\0')
    if (String[i] >= '0' && String[i] <= '9')
      i++;
    else
      return FALSE;
  return TRUE;
}
char* string_StringCopy(MEMORY mem, const char* String)
{
  char *copy;
  copy = (char *) memory_Malloc(mem, sizeof(char) * (strlen(String)+1));
  strcpy(copy, String);
  return copy;
}
char* string_Append(MEMORY mem, char* str1, const char* str2)
{
  char* newstr;
  newstr = (char*)memory_Malloc(mem, sizeof(char) * (strlen(str1) + strlen(str2) + 1));
  strcpy(newstr,str1);
  strcat(newstr,str2);
  string_StringFree(mem, str1);
  return newstr;
}
void string_AppendChar(char *str, const char c)
{
  size_t len;
  len = strlen(str);
  str[len] = c;
  str[len + 1] = '\0';
}
char* string_SubString(MEMORY mem, const char* str, size_t begin, size_t end)
{
  char* substring;
  if (end > strlen(str)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Out of bound.", __func__);
    misc_FinishErrorReport();
  }
  if(end <= begin) return string_EmptyString(mem);
  substring = (char*) memory_Malloc(mem, (end - begin + 1) * sizeof(char));
  strncpy(substring, str+begin, end-begin);
  substring[end-begin] = '\0';
  return substring;
}
int string_SubStringChar(const char* str, char left, char right, char* result)
{
  int i, j, k, l, length;
  i = -1;
  j = 0;
  length = string_Length(str);
  while (j < length) {
    if (str[j] == left)
      i = j;
    j++;
  }
  if (i==-1)
    return 0;
  j = i+1;
  k = -1;
  while (j < length && (k == -1)) {
    if (str[j] == right)
      k = j;
    j++;
  }
  if (k==-1)
    return 0;
  for(j=i+1,l=0;j<k;j++,l++)
    result[l] = str[j];
  return (k-i-1);
}
void string_StringFree(MEMORY mem, char* String)
{
  memory_Free(mem, String, sizeof(char)*(strlen(String)+1));
}
char* string_IntToString(MEMORY mem, int Number)
{
  char* result;
  NAT size = 1;
  if (Number > 9) {
    size = (NAT)log10((double) Number) + 1;
  } else if (Number < 0) {
    size = (NAT)log10((double) abs(Number)) + 2;
  }
  size++;
  result = (char *) memory_Malloc(mem, sizeof(char) * size);
  sprintf(result, "%d", Number);
  return result;
}
BOOL string_StringToInt(const char* String, BOOL PrintError, int* Result)
{
  long number;
  char *end;
  end = (char*)0x1;
  number = strtol(String, &end, 10);
  if (number >= INT_MIN && number <= INT_MAX && *end == '\0') {
    *Result = (int)number;
    return TRUE;
  } else {
    *Result = 0;
    if (PrintError) {
      misc_StartUserErrorReport();
      misc_UserErrorReport("\nString isn't a number or number too large: %s\n",
                           String);
      misc_FinishUserErrorReport();
    }
    return FALSE;
  }
}
BOOL string_StringToLong(const char* String, BOOL PrintError, uint64_t* Result)
{
  uint64_t number;
  char *end;
  end = (char*)0x1;
  number = strtoull(String, &end, 10);
  if (number <= UINT64_MAX && *end == '\0') {
    *Result = (uint64_t)number;
    return TRUE;
  } else {
    *Result = 0;
    if (PrintError) {
      misc_StartUserErrorReport();
      misc_UserErrorReport("\nString isn't a uint64_t number or number too large: %s\n",
                           String);
      misc_FinishUserErrorReport();
    }
    return FALSE;
  }
}
char* string_Conc(MEMORY mem, const char* s1, const char* s2)
{
  char* dst;
  dst = memory_Malloc(mem, sizeof(char) * (strlen(s1) + strlen(s2) + 1));
  strcpy(dst, s1);
  return strcat(dst,s2);
}
char* string_Nconc(MEMORY mem, char* s1, char* s2)
{
  char* dst;
  dst = memory_Malloc(mem, sizeof(char) * (strlen(s1) + strlen(s2) + 1));
  strcpy(dst, s1);
  dst = strcat(dst, s2);
  string_StringFree(mem, s1);
  string_StringFree(mem, s2);
  return dst;
}
char* string_EmptyString(MEMORY mem)
{
  char* s ;
  s = (char*)memory_Malloc(mem, sizeof(char) * 1);
  s[0] = '\0';
  return s;
}
char* string_Prefix(MEMORY mem, const char* s, int i)
{
  char* dst;
  dst = memory_Malloc(mem, sizeof(char) * (i + 1));
  strncpy(dst, s, i);
  dst[i] = '\0';
  return dst;
}
char* string_Suffix(MEMORY mem, const char* s, size_t i)
{
  size_t l;
  char *dst;
  l = strlen(s);
  if (i >= l)
    return string_EmptyString(mem);
  dst = memory_Malloc(mem, sizeof(char) * (l - i + 1));
  strcpy(dst, s+i);
  return dst;
}
static BOOL string_IsDelim(char Char, const char* Delims)
{
#ifdef CHECK
  if (Char == '\0') {
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Char is null.", __func__);
    misc_FinishErrorReport();
  }
#endif
  if (Delims) {
    while (*Delims) {
      if (Char == *Delims)
        return TRUE;
      Delims++;
    }
    return FALSE;
  } else
    return isspace(Char);
}
int string_Find(const char* str, const char* delims)
{
  int len,i;
  len = strlen(str);
  for(i=0; i<len; i++)
    {
      if(string_IsDelim(str[i],delims))
        return i;
    }
  return -1;
}
LIST string_Split(MEMORY mem, char* Source, const char* Delims)
{
  LIST Substrings;
  char *LastNonSpace, *Scan, Help;
#ifdef CHECK
  if (Source == NULL) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Source is NULL pointer.", __func__);
    misc_FinishErrorReport();
  }
#endif
  Substrings = list_Nil();
  Scan = Source + strlen(Source) - 1;
  while (Scan >= Source) {
    while (Scan >= Source && string_IsDelim( *Scan,Delims))
      Scan--;
    if (Scan >= Source) {
      LastNonSpace = Scan;
      do {
        Scan--;
      } while (Scan >= Source && !string_IsDelim((int)*Scan,Delims));
      Help = *(LastNonSpace + 1);
      *(LastNonSpace + 1) = '\0';
      Substrings = list_Cons(mem, string_StringCopy(mem, Scan+1), Substrings);
      *(LastNonSpace + 1) = Help;
    }
  }
  return Substrings;
}
char** string_Tokens(MEMORY mem, char* String, uintptr_t* ArraySize)
{
  char **Array;
  LIST Substrings;
  NAT i;
  Substrings = string_Split(mem, String,NULL);
  *ArraySize = list_Length(Substrings) + 2;
  Array = memory_Malloc(mem, sizeof(char*) * *ArraySize);
  Array[0] = string_StringCopy(mem, "SPASS");
  for (i = 1; !list_Empty(Substrings); Substrings = list_Pop(mem, Substrings), i++)
    Array[i] = list_Car(Substrings);
  Array[i] = NULL;
  (*ArraySize)--;
  return Array;
}
const char* string_GetPostfix(const char* str, const char delim)
{
  unsigned i, last;
  for (last=i=0; str[i]; ++i) {
    if (str[i] == delim) last = i+1;
  }
  return str+last;
}
MEMORY string_GetMemory(STRBUF Buf)
{
  return Buf->mem;
}
size_t string_GetLen(STRBUF Buf)
{
  return Buf->len;
}
void string_SetLen(STRBUF Buf, size_t Len)
{
#ifdef SPASS_CHECK
  if (Len >= string_GetCap(Buf)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n %s: strbuf invariant: len < cap", __func__);
    misc_FinishErrorReport();
  }
#endif
  Buf->len = Len;
}
size_t string_GetCap(STRBUF Buf)
{
  return Buf->cap;
}
void string_SetCap(STRBUF Buf, size_t Cap)
{
  Buf->cap = Cap;
}
void string_SetChar(STRBUF Buf, size_t Idx, char Chr)
{
#ifdef SPASS_CHECK
  if (Idx >= string_GetCap(Buf)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n %s: %ull outside buffer capacity. ",
                     __func__, Idx);
    misc_FinishErrorReport();
  }
#endif
  string_GetData(Buf)[Idx] = Chr;
}
const char* string_GetStr(STRBUF Buf)
{
  string_SetChar(Buf, string_GetLen(Buf), '\0');
  return Buf->data;
}
char* string_CopyStr(STRBUF Buf)
{
  return string_StringCopy(string_GetMemory(Buf), string_GetStr(Buf));
}
char* string_GetData(STRBUF Buf)
{
  return Buf->data;
}
void string_SetData(STRBUF Buf, char* Data)
{
  Buf->data = Data;
}
STRBUF string_InitWithCapacity(MEMORY Mem, size_t Cap)
{
  STRBUF buf = (STRBUF)memory_Malloc(Mem, sizeof(STRBUF_NODE));
  buf->mem = Mem;
  string_SetCap(buf, Cap);
  string_SetData(buf, (char*)memory_Malloc(Mem, sizeof(char)*Cap));
  string_Clear(buf);
  return buf;
}
STRBUF string_Init(MEMORY Mem)
{
  return string_InitWithCapacity(Mem, 32);
}
void string_Clear(STRBUF Buf)
{
  string_SetLen(Buf, 0);
}
void string_Free(STRBUF Buf)
{
  memory_Free(string_GetMemory(Buf), string_GetData(Buf), sizeof(char)*string_GetCap(Buf));
  memory_Free(string_GetMemory(Buf), Buf, sizeof(STRBUF_NODE));
}
void string_Reserve(STRBUF Buf, size_t Cap)
{
  size_t pow;
  if (string_GetCap(Buf) >= Cap) return;
  for (pow=1; pow < Cap;) pow *=2;
  string_SetData(Buf, memory_Realloc(string_GetMemory(Buf), string_GetData(Buf),
                                     sizeof(char)*string_GetCap(Buf),
                                     sizeof(char)*pow));
  string_SetCap(Buf, pow);
}
void string_ReserveExtra(STRBUF Buf, size_t Extra)
{
  string_Reserve(Buf, string_GetLen(Buf)+Extra+1);
}
void string_AddStrN(STRBUF Buf, const char* Str, size_t Len)
{
  string_ReserveExtra(Buf, Len);
  memcpy(string_GetData(Buf)+string_GetLen(Buf), Str, sizeof(char)*Len);
  string_SetLen(Buf, string_GetLen(Buf)+Len);
}
void string_AddStr(STRBUF Buf, const char* Str)
{
  string_AddStrN(Buf, Str, strlen(Str));
}
void string_AddCharUnsafe(STRBUF Buf, char Chr)
{
  string_SetChar(Buf, string_GetLen(Buf), Chr);
  string_SetLen(Buf, string_GetLen(Buf)+1);
}
void string_AddChar(STRBUF Buf, char Chr)
{
  string_ReserveExtra(Buf, 1);
  string_AddCharUnsafe(Buf, Chr);
}
void string_PrintDebug(const char *Msg, STRBUF Buf)
{
  printf("%s(Len %lu, Cap %lu): %s\n",
         Msg,
         string_GetLen(Buf),
         string_GetCap(Buf),
         string_GetStr(Buf));
}
void string_AddNat(STRBUF Buf, unsigned long long Nat)
{
  string_ReserveExtra(Buf, 23);
  string_Printf(Buf, "%llu", Nat);
}
void string_AddInt(STRBUF Buf, long long Int)
{
  string_ReserveExtra(Buf, 23);
  string_Printf(Buf, "%ll", Int);
}
const char* string_VPrintf(STRBUF Buf, const char *Format, va_list Args)
{
  va_list argsCopy;
  char *end;
  size_t free;
  int resultingLength;
  va_copy(argsCopy, Args);
  end = string_GetData(Buf) + string_GetLen(Buf);
  free = string_GetCap(Buf) - string_GetLen(Buf);
  resultingLength = vsnprintf(end, free, Format, Args);
  if (resultingLength >= 0 && (size_t)resultingLength >= free) {
    string_ReserveExtra(Buf, resultingLength);
    end = string_GetData(Buf) + string_GetLen(Buf);
    free = string_GetCap(Buf) - string_GetLen(Buf);
    resultingLength = vsnprintf(end, free, Format, argsCopy);
  }
#ifdef SPASS_CHECK
  if (resultingLength < 0 || (size_t)resultingLength >= free) {
    misc_StartErrorReport();
    misc_ErrorReport("\n %s: vsnprintf failed", __func__);
    misc_FinishErrorReport();
  }
#endif
  string_SetLen(Buf, string_GetLen(Buf)+resultingLength);
  string_GetStr(Buf);
  va_end(argsCopy);
  return end;
}
const char* string_Printf(STRBUF Buf, const char *Format, ...)
{
  va_list args;
  va_start(args, Format);
  const char *retval = string_VPrintf(Buf, Format, args);
  va_end(args);
  return retval;
}
char* string_VPrintfTempBuffer(MEMORY Mem, const char* Format, va_list Args)
{
  STRBUF buf = string_Init(Mem);
  string_VPrintf(buf, Format, Args);
  char *str = string_CopyStr(buf);
  string_Free(buf);
  return str;
}
char* string_PrintfTempBuffer(MEMORY Mem, const char* Format, ...)
{
  va_list args;
  va_start(args, Format);
  char *str = string_VPrintfTempBuffer(Mem, Format, args);
  va_end(args);
  return str;
}
BOOL string_TestCheck(size_t MaxLen, char *Base, STRBUF Buf)
{
  printf("TEST %s ", Base);
  if (string_GetLen(Buf) >= MaxLen
      || 0 != strcmp(string_GetStr(Buf), Base)) {
    string_PrintDebug("BAD ", Buf);
    return FALSE;
  }
  else {
    string_PrintDebug("OK ", Buf);
    return TRUE;
  }
}
void string_AddStrTest(size_t MaxLen, char *Base, STRBUF Buf, const char* Str)
{
  string_AddStr(Buf, Str);
  sprintf(Base+strlen(Base), "%s", Str);
  string_TestCheck(MaxLen, Base, Buf);
}
void string_AddCharTest(size_t MaxLen, char *Base, STRBUF Buf, char Chr)
{
  string_AddChar(Buf, Chr);
  sprintf(Base+strlen(Base), "%c", Chr);
  string_TestCheck(MaxLen, Base, Buf);
}
void string_PrintfTest(size_t MaxLen, char *Base, STRBUF Buf, const char *Format, ...)
{
  va_list Args;
  va_start(Args, Format);
  const char *s = string_VPrintf(Buf, Format, Args);
  printf("STRBUF: %s\n", s);
  va_end(Args);
  va_start(Args, Format);
  vsprintf(Base+strlen(Base), Format, Args);
  va_end(Args);
  va_start(Args, Format);
  printf("PRINTF: ");
  vprintf(Format, Args);
  puts("");
  va_end(Args);
  string_TestCheck(MaxLen, Base, Buf);
}
void string_Test1(MEMORY Mem)
{
  size_t n = 1e6;
  char *s = (char*)memory_Malloc(Mem, sizeof(char)*n);
  memset(s, 0, sizeof(char)*n);
  STRBUF b = string_InitWithCapacity(Mem, 1);
  string_TestCheck(n,s,b);
  string_AddCharTest(n,s,b,'a');
  string_AddCharTest(n,s,b,'b');
  string_AddCharTest(n,s,b,'c');
  string_AddCharTest(n,s,b,'d');
  string_AddStrTest(n,s,b,"");
  string_AddStrTest(n,s,b,"123");
  string_AddStrTest(n,s,b,"");
  string_AddStrTest(n,s,b,"456");
  string_PrintfTest(n,s,b,"_");
  string_PrintfTest(n,s,b,"%s","XwX");
  string_PrintfTest(n,s,b,"=%i%u",-123,456);
  memset(s, 0, sizeof(char)*n);
  string_Clear(b);
  string_TestCheck(n,s,b);
  string_AddCharTest(n,s,b,'a');
  string_AddCharTest(n,s,b,'b');
  string_AddCharTest(n,s,b,'c');
  string_AddCharTest(n,s,b,'d');
  string_AddStrTest(n,s,b,"");
  string_AddStrTest(n,s,b,"123");
  string_AddStrTest(n,s,b,"");
  string_AddStrTest(n,s,b,"456");
  string_PrintfTest(n,s,b,"_");
  string_PrintfTest(n,s,b,"%s","XwX");
  string_PrintfTest(n,s,b,"=%i%u",-123,456);
  memory_Free(Mem, s, sizeof(char)*n);
  string_Free(b);
}
void string_Test2(MEMORY Mem)
{
  size_t n = 1e6;
  char *s = (char*)memory_Malloc(Mem, sizeof(char)*n);
  memset(s, 0, sizeof(char)*n);
  STRBUF b = string_InitWithCapacity(Mem, 1);
  string_TestCheck(n,s,b);
  for (int i=0; i<34; ++i) {
    string_PrintfTest(n,s,b,"%c", '0'+(i%10));
  }
  memory_Free(Mem, s, sizeof(char)*n);
  string_Free(b);
}
void TEST(MEMORY Mem, const char* Format, ...)
{
  va_list args;
  va_start(args, Format);
  char *str = string_VPrintfTempBuffer(Mem, Format, args);
  va_end(args);
  printf("%s", str);
  string_StringFree(Mem, str);
}
void string_Test3(MEMORY M)
{
  printf("asdf\n");
  TEST(M,"asdf\n");
  printf("\n");
  TEST(M,"\n");
  printf("%u%s%f\n", 123, "456789", 0.1234);
  TEST(M,"%u%s%f\n", 123, "456789", 0.1234);
  printf("A#W_#)!%%(#)@)%u_123512%s    %fhaha\n", 123, "456789", 0.1234);
  TEST(M,"A#W_#)!%%(#)@)%u_123512%s    %fhaha\n", 123, "456789", 0.1234);
}
void string_Test(MEMORY Mem)
{
  string_Test1(Mem);
  string_Test2(Mem);
  string_Test3(Mem);
}
