Make much more usage of dynamic strings (StrBufs) instead of char* and

friends. Since names and other strings are now StrBufs in many places, code
for output had to be changed.
Added support for string literals to StrBuf.


git-svn-id: svn://svn.cc65.org/cc65/trunk@3825 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz
2008-03-31 20:54:45 +00:00
parent 6a7e844500
commit 9174f65e54
78 changed files with 1228 additions and 864 deletions

View File

@@ -6,10 +6,10 @@
/* */
/* */
/* */
/* (C) 1998 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* (C) 1998-2008 Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
@@ -33,6 +33,11 @@
/* common */
#include "hashstr.h"
/*****************************************************************************/
/* Code */
/*****************************************************************************/
@@ -54,3 +59,18 @@ unsigned HashStr (const char* S)
unsigned HashBuf (const StrBuf* S)
/* Return a hash value for the given string buffer */
{
unsigned I, L, H;
/* Do the hash */
H = L = 0;
for (I = 0; I < SB_GetLen (S); ++I) {
H = ((H << 3) ^ ((unsigned char) SB_AtUnchecked (S, I))) + L++;
}
return H;
}

View File

@@ -1,15 +1,15 @@
/*****************************************************************************/
/* */
/* hashstr.h */
/* hashstr.h */
/* */
/* Hash function for strings */
/* Hash function for strings */
/* */
/* */
/* */
/* (C) 1998 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* (C) 1998-2008 Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
@@ -38,7 +38,9 @@
/* common */
#include "attrib.h"
#include "strbuf.h"
@@ -51,6 +53,9 @@
unsigned HashStr (const char* S) attribute ((const));
/* Return a hash value for the given string */
unsigned HashBuf (const StrBuf* S) attribute ((const));
/* Return a hash value for the given string buffer */
/* End of hashstr.h */

View File

@@ -6,8 +6,8 @@
/* */
/* */
/* */
/* (C) 2003 Ullrich von Bassewitz */
/* R<EFBFBD>merstrasse 52 */
/* (C) 2003-2008 Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
@@ -112,7 +112,7 @@ INLINE void InitHashNode (HashNode* N, void* Entry)
#define InitHashNode(N, E) \
(N)->Next = 0, \
(N)->Owner = 0, \
(N)->Entry = (E)
(N)->Entry = (E)
#endif
#if defined(HAVE_INLINE)

View File

@@ -6,8 +6,8 @@
/* */
/* */
/* */
/* (C) 2000-2003 Ullrich von Bassewitz */
/* R<EFBFBD>merstrasse 52 */
/* (C) 2000-2008 Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
@@ -138,7 +138,7 @@ static char* Find (const char* Path, const char* File)
if (access (SB_GetBuf (&PathName), 0) == 0) {
/* The file exists, return its name */
char* Name = xstrdup (SB_GetBuf (&PathName));
DoneStrBuf (&PathName);
SB_Done (&PathName);
return Name;
}
@@ -149,7 +149,7 @@ static char* Find (const char* Path, const char* File)
}
/* Not found */
DoneStrBuf (&PathName);
SB_Done (&PathName);
return 0;
}

View File

@@ -62,22 +62,37 @@ const StrBuf EmptyStrBuf = STATIC_STRBUF_INITIALIZER;
StrBuf* InitStrBuf (StrBuf* B)
#if !defined(HAVE_INLINE)
StrBuf* SB_Init (StrBuf* B)
/* Initialize a string buffer */
{
*B = EmptyStrBuf;
return B;
}
#endif
StrBuf* SB_InitFromString (StrBuf* B, const char* S)
/* Initialize a string buffer from a literal string. Beware: The buffer won't
* store a copy but a pointer to the actual string.
*/
{
B->Allocated = 0;
B->Len = 0;
B->Len = strlen (S);
B->Index = 0;
B->Buf = 0;
B->Buf = (char*) S;
return B;
}
void DoneStrBuf (StrBuf* B)
void SB_Done (StrBuf* B)
/* Free the data of a string buffer (but not the struct itself) */
{
xfree (B->Buf);
if (B->Allocated) {
xfree (B->Buf);
}
}
@@ -89,7 +104,7 @@ StrBuf* NewStrBuf (void)
StrBuf* B = xmalloc (sizeof (StrBuf));
/* Initialize the struct... */
InitStrBuf (B);
SB_Init (B);
/* ...and return it */
return B;
@@ -100,7 +115,7 @@ StrBuf* NewStrBuf (void)
void FreeStrBuf (StrBuf* B)
/* Free a string buffer */
{
DoneStrBuf (B);
SB_Done (B);
xfree (B);
}
@@ -122,8 +137,50 @@ void SB_Realloc (StrBuf* B, unsigned NewSize)
NewAllocated *= 2;
}
/* Reallocate the buffer */
B->Buf = xrealloc (B->Buf, NewAllocated);
/* Reallocate the buffer. Beware: The allocated size may be zero while the
* length is not. This means that we have a buffer that wasn't allocated
* on the heap.
*/
if (B->Allocated) {
/* Just reallocate the block */
B->Buf = xrealloc (B->Buf, NewAllocated);
} else {
/* Allocate a new block and copy */
B->Buf = memcpy (xmalloc (NewAllocated), B->Buf, B->Len);
}
/* Remember the new block size */
B->Allocated = NewAllocated;
}
static void SB_CheapRealloc (StrBuf* B, unsigned NewSize)
/* Reallocate the string buffer space, make sure at least NewSize bytes are
* available. This function won't copy the old buffer contents over to the new
* buffer and may be used if the old contents are overwritten later.
*/
{
/* Get the current size, use a minimum of 8 bytes */
unsigned NewAllocated = B->Allocated;
if (NewAllocated == 0) {
NewAllocated = 8;
}
/* Round up to the next power of two */
while (NewAllocated < NewSize) {
NewAllocated *= 2;
}
/* Free the old buffer if there is one */
if (B->Allocated) {
xfree (B->Buf);
}
/* Allocate a fresh block */
B->Buf = xmalloc (NewAllocated);
/* Remember the new block size */
B->Allocated = NewAllocated;
}
@@ -170,7 +227,7 @@ void SB_CopyBuf (StrBuf* Target, const char* Buf, unsigned Size)
/* Copy Buf to Target, discarding the old contents of Target */
{
if (Target->Allocated < Size) {
SB_Realloc (Target, Size);
SB_CheapRealloc (Target, Size);
}
memcpy (Target->Buf, Buf, Size);
Target->Len = Size;
@@ -294,7 +351,7 @@ void SB_Move (StrBuf* Target, StrBuf* Source)
*/
{
/* Free the target string */
if (Target->Buf) {
if (Target->Allocated) {
xfree (Target->Buf);
}
@@ -302,7 +359,7 @@ void SB_Move (StrBuf* Target, StrBuf* Source)
*Target = *Source;
/* Clear Source */
InitStrBuf (Source);
SB_Init (Source);
}
@@ -359,6 +416,31 @@ int SB_Compare (const StrBuf* S1, const StrBuf* S2)
int SB_CompareStr (const StrBuf* S1, const char* S2)
/* Do a lexical compare of S1 and S2. See strcmp for result codes. */
{
int Result;
unsigned S2Len = strlen (S2);
if (S1->Len < S2Len) {
Result = memcmp (S1->Buf, S2, S1->Len);
if (Result == 0) {
/* S1 considered lesser because it's shorter */
Result = -1;
}
} else if (S1->Len > S2Len) {
Result = memcmp (S1->Buf, S2, S2Len);
if (Result == 0) {
/* S2 considered lesser because it's shorter */
Result = 1;
}
} else {
Result = memcmp (S1->Buf, S2, S1->Len);
}
return Result;
}
void SB_VPrintf (StrBuf* S, const char* Format, va_list ap)
/* printf function with S as target. The function is safe, which means that
* the current contents of S are discarded, and are allocated again with
@@ -382,10 +464,8 @@ void SB_VPrintf (StrBuf* S, const char* Format, va_list ap)
/* Check if we must reallocate */
if ((unsigned) SizeNeeded >= S->Allocated) {
/* Must retry. Don't use Realloc to avoid copying */
xfree (S->Buf);
S->Allocated = SizeNeeded + 1; /* Account for '\0' */
S->Buf = xmalloc (S->Allocated);
/* Must retry. Use CheapRealloc to avoid copying */
SB_CheapRealloc (S, SizeNeeded + 1); /* Account for '\0' */
(void) xvsnprintf (S->Buf, S->Allocated, Format, ap);
}

View File

@@ -49,18 +49,18 @@
/*****************************************************************************/
/* Data */
/* Data */
/*****************************************************************************/
typedef struct StrBuf StrBuf;
struct StrBuf {
unsigned Allocated; /* Size of allocated memory */
char* Buf; /* Pointer to buffer */
unsigned Len; /* Length of the string */
unsigned Index; /* Used for reading (Get and friends) */
char* Buf; /* Pointer to buffer */
};
unsigned Allocated; /* Size of allocated memory */
};
/* An empty string buf */
extern const StrBuf EmptyStrBuf;
@@ -71,18 +71,36 @@ extern const StrBuf EmptyStrBuf;
/* Initializer for auto string bufs */
#define AUTO_STRBUF_INITIALIZER EmptyStrBuf
/* Initialize with a string literal (beware: evaluates str twice!) */
#define LIT_STRBUF_INITIALIZER(str) { (char*)str, sizeof(str)-1, 0, 0 }
/*****************************************************************************/
/* Code */
/* Code */
/*****************************************************************************/
StrBuf* InitStrBuf (StrBuf* B);
#if defined(HAVE_INLINE)
INLINE StrBuf* SB_Init (StrBuf* B)
/* Initialize a string buffer */
{
*B = EmptyStrBuf;
return B;
}
#else
StrBuf* SB_Init (StrBuf* B);
#endif
void DoneStrBuf (StrBuf* B);
StrBuf* SB_InitFromString (StrBuf* B, const char* S);
/* Initialize a string buffer from a literal string. Beware: The buffer won't
* store a copy but a pointer to the actual string. A buffer initialized with
* this routine may be "forgotten" without calling SB_Done, since no memory
* has been allocated.
*/
void SB_Done (StrBuf* B);
/* Free the data of a string buffer (but not the struct itself) */
StrBuf* NewStrBuf (void);
@@ -358,14 +376,17 @@ void SB_ToUpper (StrBuf* S);
int SB_Compare (const StrBuf* S1, const StrBuf* S2);
/* Do a lexical compare of S1 and S2. See strcmp for result codes. */
void SB_VPrintf (StrBuf* S, const char* Format, va_list ap);
int SB_CompareStr (const StrBuf* S1, const char* S2);
/* Do a lexical compare of S1 and S2. See strcmp for result codes. */
void SB_VPrintf (StrBuf* S, const char* Format, va_list ap) attribute ((format (printf, 2, 0)));
/* printf function with S as target. The function is safe, which means that
* the current contents of S are discarded, and are allocated again with
* a matching size for the output. The function will call FAIL when problems
* are detected (anything that let xsnprintf return -1).
*/
void SB_Printf (StrBuf* S, const char* Format, ...);
void SB_Printf (StrBuf* S, const char* Format, ...) attribute ((format (printf, 2, 3)));
/* vprintf function with S as target. The function is safe, which means that
* the current contents of S are discarded, and are allocated again with
* a matching size for the output. The function will call FAIL when problems

View File

@@ -6,8 +6,8 @@
/* */
/* */
/* */
/* (C) 2003 Ullrich von Bassewitz */
/* R<EFBFBD>merstrasse 52 */
/* (C) 2003-2008 Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
@@ -35,7 +35,7 @@
/* A string pool is used to store identifiers and other strings. Each string
* stored in the pool has a unique id, which may be used to access the string
* in the pool. Identical strings are only stored once in the pool and have
* in the pool. Identical strings are stored only once in the pool and have
* identical ids. This means that instead of comparing strings, just the
* string pool ids must be compared.
*/
@@ -64,8 +64,7 @@ struct StringPoolEntry {
StringPoolEntry* Next; /* Pointer to next entry in hash chain */
unsigned Hash; /* Full hash value */
unsigned Id; /* The numeric string id */
unsigned Len; /* Length of the string (excluding terminator) */
char S[1]; /* The string itself */
StrBuf Buf; /* The string itself */
};
@@ -76,21 +75,21 @@ struct StringPoolEntry {
static StringPoolEntry* NewStringPoolEntry (const char* S, unsigned Hash, unsigned Id)
static StringPoolEntry* NewStringPoolEntry (const StrBuf* S, unsigned Hash, unsigned Id)
/* Create a new string pool entry and return it. */
{
/* Get the length of the string */
unsigned Len = strlen (S);
/* Allocate memory */
StringPoolEntry* E = xmalloc (sizeof (StringPoolEntry) + Len);
StringPoolEntry* E = xmalloc (sizeof (StringPoolEntry));
/* Initialize the fields */
E->Next = 0;
E->Hash = Hash;
E->Id = Id;
E->Len = Len;
memcpy (E->S, S, Len+1);
E->Buf = AUTO_STRBUF_INITIALIZER;
SB_Copy (&E->Buf, S);
/* Always zero terminate the string */
SB_Terminate (&E->Buf);
/* Return the new entry */
return E;
@@ -129,7 +128,15 @@ void DoneStringPool (StringPool* P)
/* Free all entries and clear the entry collection */
for (I = 0; I < CollCount (&P->Entries); ++I) {
xfree (CollAtUnchecked (&P->Entries, I));
/* Get a pointer to the entry */
StringPoolEntry* E = CollAtUnchecked (&P->Entries, I);
/* Free string buffer memory */
SB_Done (&E->Buf);
/* Free the memory for the entry itself */
xfree (E);
}
CollDeleteAll (&P->Entries);
@@ -165,25 +172,26 @@ void FreeStringPool (StringPool* P)
const char* SP_Get (const StringPool* P, unsigned Index)
const StrBuf* SP_Get (const StringPool* P, unsigned Index)
/* Return a string from the pool. Index must exist, otherwise FAIL is called. */
{
/* Get the collection entry */
const StringPoolEntry* E = CollConstAt (&P->Entries, Index);
/* Return the string from the entry */
return E->S;
return &E->Buf;
}
unsigned SP_Add (StringPool* P, const char* S)
/* Add a string to the buffer and return the index. If the string does already
* exist in the pool, SP_Add will just return the index of the existing string.
unsigned SP_Add (StringPool* P, const StrBuf* S)
/* Add a string buffer to the buffer and return the index. If the string does
* already exist in the pool, SP_AddBuf will just return the index of the
* existing string.
*/
{
/* Calculate the string hash */
unsigned Hash = HashStr (S);
unsigned Hash = HashBuf (S);
/* Calculate the reduced string hash */
unsigned RHash = Hash % (sizeof (P->Tab)/sizeof (P->Tab[0]));
@@ -191,7 +199,7 @@ unsigned SP_Add (StringPool* P, const char* S)
/* Search for an existing entry */
StringPoolEntry* E = P->Tab[RHash];
while (E) {
if (E->Hash == Hash && strcmp (E->S, S) == 0) {
if (E->Hash == Hash && SB_Compare (&E->Buf, S) == 0) {
/* Found, return the id of the existing string */
return E->Id;
}
@@ -208,8 +216,8 @@ unsigned SP_Add (StringPool* P, const char* S)
E->Next = P->Tab[RHash];
P->Tab[RHash] = E;
/* Add up the string size (plus terminator) */
P->TotalSize += E->Len + 1;
/* Add up the string size */
P->TotalSize += SB_GetLen (&E->Buf);
/* Return the id of the entry */
return E->Id;
@@ -217,3 +225,22 @@ unsigned SP_Add (StringPool* P, const char* S)
unsigned SP_AddStr (StringPool* P, const char* S)
/* Add a string to the buffer and return the index. If the string does already
* exist in the pool, SP_Add will just return the index of the existing string.
*/
{
unsigned Id;
/* First make a string buffer, then add it. This is some overhead, but the
* routine will probably go.
*/
StrBuf Buf;
Id = SP_Add (P, SB_InitFromString (&Buf, S));
/* Return the id of the new entry */
return Id;
}

View File

@@ -6,8 +6,8 @@
/* */
/* */
/* */
/* (C) 2003 Ullrich von Bassewitz */
/* R<EFBFBD>merstrasse 52 */
/* (C) 2003-2008 Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
@@ -48,6 +48,7 @@
/* common */
#include "attrib.h"
#include "coll.h"
#include "inline.h"
#include "strbuf.h"
@@ -100,10 +101,16 @@ StringPool* NewStringPool (void);
void FreeStringPool (StringPool* P);
/* Free a string pool */
const char* SP_Get (const StringPool* P, unsigned Index);
const StrBuf* SP_Get (const StringPool* P, unsigned Index);
/* Return a string from the pool. Index must exist, otherwise FAIL is called. */
unsigned SP_Add (StringPool* P, const char* S);
unsigned SP_Add (StringPool* P, const StrBuf* S);
/* Add a string buffer to the buffer and return the index. If the string does
* already exist in the pool, SP_AddBuf will just return the index of the
* existing string.
*/
unsigned SP_AddStr (StringPool* P, const char* S);
/* Add a string to the buffer and return the index. If the string does already
* exist in the pool, SP_Add will just return the index of the existing string.
*/

View File

@@ -6,8 +6,8 @@
/* */
/* */
/* */
/* (C) 2000-2004 Ullrich von Bassewitz */
/* R<EFBFBD>merstrasse 52 */
/* (C) 2000-2008 Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
@@ -35,6 +35,7 @@
#include <string.h>
/* common */
#include "abend.h"
#include "check.h"
#include "target.h"
@@ -212,6 +213,16 @@ void TgtTranslateBuf (void* Buf, unsigned Len)
void TgtTranslateStrBuf (StrBuf* Buf)
/* Translate a string buffer from the source character set into the target
* system character set.
*/
{
TgtTranslateBuf (SB_GetBuf (Buf), SB_GetLen (Buf));
}
void TgtTranslateSet (unsigned Index, unsigned char C)
/* Set the translation code for the given character */
{

View File

@@ -6,8 +6,8 @@
/* */
/* */
/* */
/* (C) 2000-2003 Ullrich von Bassewitz */
/* R<EFBFBD>merstrasse 52 */
/* (C) 2000-2008 Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
@@ -34,7 +34,12 @@
#ifndef TGTTRANS_H
#define TGTTRANS_H
#define TGTTRANS_H
/* common */
#include "strbuf.h"
@@ -62,6 +67,11 @@ void TgtTranslateBuf (void* Buf, unsigned Len);
* the target system character set.
*/
void TgtTranslateStrBuf (StrBuf* Buf);
/* Translate a string buffer from the source character set into the target
* system character set.
*/
void TgtTranslateSet (unsigned Index, unsigned char C);
/* Set the translation code for the given character */