New C90-compatible code, which improvements and a few new functions:
Code:
// C String Library.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include <string.h>
#include <stdlib.h>
#include "CLib.h"
//#include <new>
#include <assert.h>
#include <stdio.h>
struct SStrInt
{
char* Str;
size_t Length;
size_t Size;
bool Free;
};
#ifndef __cplusplus
typedef struct SStrInt SStrInt;
#endif
EError g_LastError;
int g_LastCError;
EError CopyStrInt(SStrInt* pDst, char* pDstCopyStart, SStrInt* pSrc, size_t* pReqSpace);
EError NewStrPointer(SStrInt** pStr);
EError ResizeStr(SStrInt* pStr, size_t NewSize);
EError _GetLastError()
{
return g_LastError;
}
int GetLastCError()
{
return g_LastCError;
}
EError NewStrPointer(SStrInt** pStr)
{
if (pStr == NULL)
return ERR_NULL_POINTER;
*pStr = (SStrInt*)malloc(sizeof(SStrInt));
if (*pStr == NULL)
return ERR_NOT_ENOUGH_MEMORY;
return ERR_SUCCESS;
}
SStr* NewDStr(const char* Str)
{
SStrInt* pStr;
EError err = NewStrPointer(&pStr);
if (Str == NULL)
{
g_LastError = ERR_NULL_POINTER;
return NULL;
}
err = NewStrPointer(&pStr);
if (err != ERROR_SUCCESS)
{
g_LastError = err;
return NULL;
}
pStr->Length = strlen(Str);
pStr->Size = (pStr->Length + 1) * 2;
pStr->Str = (char*)malloc(pStr->Size);
if (pStr->Str == NULL)
{
// Malloc failed
g_LastError = ERR_NOT_ENOUGH_MEMORY;
return NULL;
}
pStr->Free = true;
memcpy(pStr->Str, Str, pStr->Length + 1); // +1 for the null char
g_LastError = ERR_SUCCESS;
return (SStr*)pStr;
}
SStr* NewStr(char* Str, size_t BufferSize)
{
SStrInt* pStr;
EError err = NewStrPointer(&pStr);
if (Str == NULL)
{
g_LastError = ERR_NULL_POINTER;
return NULL;
}
err = NewStrPointer(&pStr);
if (err != ERROR_SUCCESS)
{
g_LastError = err;
return NULL;
}
pStr->Str = Str;
pStr->Length = strlen(Str);
pStr->Free = false;
pStr->Size = BufferSize;
g_LastError = ERR_SUCCESS;
return (SStr*)pStr;
}
EError FreeStr(SStr* pStr_)
{
SStrInt* pStr;
if (pStr_ == NULL)
return ERR_NULL_POINTER;
pStr = (SStrInt*)pStr_;
if (pStr->Free)
free(pStr->Str);
memset(pStr, 0, sizeof(*pStr));
return ERR_SUCCESS;
}
EError CopyStrInt(SStrInt* pDst, char* pDstCopyStart, SStrInt* pSrc, size_t* pReqSpace)
{
if (pDst == NULL || pDstCopyStart == NULL || pSrc == NULL)
return ERR_NULL_POINTER;
// Set position to copy new data
if (pDst->Length + pSrc->Length + 1 > pDst->Size)
{
EError err;
// Not enough room in buffer
if (!pDst->Free)
{
if (pReqSpace)
*pReqSpace = pDst->Length + pSrc->Length + 1; // - pDst->Size;
return ERR_BUFFER_TOO_SMALL; // Not enough room.
}
err = ResizeStr(pDst, (pDst->Length + pSrc->Length + 1) * 2);
if (err != ERR_SUCCESS)
return err;
pDstCopyStart = &pDst->Str[pDst->Length];
}
// Copy new data
memcpy(pDstCopyStart, pSrc->Str, pSrc->Length + 1); // +1 for the null char
// Set new length
pDst->Length += pSrc->Length;
return ERR_SUCCESS;
}
size_t CopyStr(SStr* pDst_, const SStr* pSrc_)
{
SStrInt* pDst = (SStrInt*)pDst_;
SStrInt* pSrc = (SStrInt*)pSrc_;
size_t ReqSpace = 0;
EError Err;
if (pDst_ == NULL || pSrc_ == NULL)
{
g_LastError = ERR_NULL_POINTER;
return 0xFFFFFFFF;
}
Err = CopyStrInt(pDst, pDst->Str, pSrc, &ReqSpace);
g_LastError = Err;
return ReqSpace;
}
size_t CatStr(SStr* pDst_, const SStr* pSrc_)
{
SStrInt* pDst;
SStrInt* pSrc;
char* pDst__;
EError err;
size_t ReqSpace = 0;
if (pDst_ == NULL || pSrc_ == NULL)
{
g_LastError = ERR_NULL_POINTER;
return 0xFFFFFFFF;
}
pDst = (SStrInt*)pDst_;
pSrc = (SStrInt*)pSrc_;
pDst__ = &pDst->Str[pDst->Length];
err = CopyStrInt(pDst, pDst__, pSrc, &ReqSpace);
g_LastError = err;
return ReqSpace;
}
int CmpStr(const SStr* lhs_, const SStr* rhs_)
{
SStrInt* lhs = (SStrInt*)lhs_;
SStrInt* rhs = (SStrInt*)rhs_;
if (lhs_ == NULL || rhs_ == NULL)
{
g_LastError = ERR_NULL_POINTER;
return 0xFFFFFFFF;
}
return strcmp(lhs->Str, rhs->Str);
}
int SearchStr(const SStr* lhs_, const SStr* rhs_)
{
SStrInt* lhs = (SStrInt*)lhs_;
SStrInt* rhs = (SStrInt*)rhs_;
char* p;
if (lhs_ == NULL || rhs_ == NULL)
{
g_LastError = ERR_NULL_POINTER;
return -1;
}
p = strstr(lhs->Str, rhs->Str);
if (p == NULL)
{
g_LastError = ERR_NOT_FOUND;
return -1;
}
else
return p - lhs->Str;
}
int SearchChr(const SStr* lhs_, const char c)
{
SStrInt* lhs = (SStrInt*)lhs_;
char* p;
if (lhs_ == NULL)
{
g_LastError = ERR_NULL_POINTER;
return -1;
}
p = strchr(lhs->Str, c);
if (p == NULL)
{
g_LastError = ERR_NOT_FOUND;
return -1;
}
else
return p - lhs->Str;
}
const char* GetCStr(const SStr* Str_)
{
SStrInt* Str = (SStrInt*)Str_;
if (Str_ == NULL)
return NULL;
return Str->Str;
}
EError ReadInput(SStr* Str_)
{
SStrInt* Str = (SStrInt*)Str_;
SStrInt TmpStr;
if (Str_ == NULL)
return ERR_NULL_POINTER;
ResizeStr(&TmpStr, 1024);
Str->Length = 0;
for(;;)
{
char* p = fgets(TmpStr.Str, TmpStr.Size, stdin);
if (p == NULL)
{
assert(!feof(stdin));
assert(ferror(stdin) != 0);
g_LastCError = ferror(stdin);
return ERR_C_FUNCTION;
}
TmpStr.Length = strlen(TmpStr.Str);
CatStr((SStr*)Str, (SStr*)&TmpStr);
p = strchr(Str->Str, '\n');
if (p)
{
*p = '\0'; // Strip newline
break;
}
}
return ERR_SUCCESS;
}
/* CAREFUL!
Reading from a file will NOT null-terminate a string, because it's no longer a string!
That means that NO function C string function will work with the buffer! */
int ReadFromFile(SStr* Str_, unsigned int ElementSize, unsigned int Count, FILE* File)
{
SStrInt* Str = (SStrInt*)Str_;
unsigned int n;
if (Str_ == NULL || File == NULL)
{
g_LastError = ERR_NULL_POINTER;
return 0;
}
if (Str->Size < ElementSize * Count)
{
EError Err;
if (!Str->Free)
{
g_LastError = ERR_BUFFER_TOO_SMALL;
return 0;
}
Err = ResizeStr(Str, ElementSize * Count * 2);
if (Err != ERROR_SUCCESS)
{
g_LastError = Err;
return 0;
}
}
n = fread(Str->Str, ElementSize, Count, File);
if (n < Count)
{
if (!feof(File))
{
g_LastError = ERR_IO;
g_LastCError = ferror(File);
return n;
}
}
g_LastError = ERR_SUCCESS;
return n;
}
EError ResizeStr(SStrInt* pStr, size_t NewSize)
{
char* pOldBuffer;
char* pTemp;
size_t OldLength;
if (pStr == NULL)
return ERR_NULL_POINTER;
if (NewSize <= pStr->Length)
return ERR_SIZE_TOO_SMALL;
// Store old buffer
pOldBuffer = pStr->Str;
OldLength = pStr->Length;
// Allocate new size
pTemp = (char*)malloc(NewSize);
if (pTemp == NULL)
return ERR_NOT_ENOUGH_MEMORY;
// Assign new buffer
pStr->Str = pTemp;
pStr->Size = NewSize;
// Copy over old data
if (pOldBuffer)
memcpy(pTemp, pOldBuffer, OldLength + 1);
// Free old buffer
free(pOldBuffer);
pOldBuffer = NULL;
pTemp = NULL;
return ERR_SUCCESS;
}
And header:
Code:
#ifndef CSTRLIB_171038_H
#define CSTRLIB_171038_H
#include <stddef.h>
#include <stdio.h>
#ifndef __cplusplus
#if __STDC_VERSION__ >= 19990L
#include <stdbool.h>
#else
#ifndef bool
typedef char bool;
#endif
#endif
#ifndef false
#define false 0
#endif
#ifndef true
#define true 1
#endif
#endif
enum EError
{
ERR_SUCCESS = 0, /* Function succeeded */
ERR_NOT_FOUND = -1, /* The search string or character was not found */
ERR_NULL_POINTER = 1, /* One or more arguments which must be non-NULL was NULL */
ERR_NOT_ENOUGH_MEMORY, /* Unable to allocate enough required memory */
ERR_BUFFER_TOO_SMALL, /* String was not dynamic and was too small for the new data */
ERR_C_FUNCTION, /* A C library function failed. More information is avilable in an extra argument passed. */
ERR_NO_MORE_DATA, /* There is no more data available to be read. */
ERR_MORE_DATA_AVAILABLE, /* There is more data available to be read. */
ERR_SIZE_TOO_SMALL, /* The specified size is too small. */
ERR_IO /* An IO call went wrong. See the C function error constant for more information. */
};
#ifdef __cplusplus
struct SStr { };
#else
struct SStr
{
char unused;
};
#endif
#ifndef __cplusplus
typedef struct SStr SStr;
typedef enum EError EError;
#endif
#ifdef __cplusplus
extern "C"
{
#endif
SStr* NewDStr(const char* Str);
SStr* NewStr(char* Str, size_t BufferSize);
EError FreeStr(SStr* pStr);
const char* GetCStr(const SStr* Str);
EError ReadInput(SStr* Str);
int ReadFromFile(SStr* Str, unsigned int ElementSize, unsigned int Count, FILE* File);
EError _GetLastError();
int GetLastCError();
size_t CopyStr(SStr* pDst, const SStr* pSrc);
size_t CatStr(SStr* pDst, const SStr* pSrc);
#ifdef __cplusplus
}
#endif
#endif // CSTRLIB_171038_H
Hopefully, I've taken care of a lot of criticism.
I actually have added more than just string functions, but they do work with strings. The new improved fgets, for example, that will now read everything in the buffer, not leaving anything in there and automatically strips the newline.