X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcommon%2Fstrbuf.c;h=320e912932ac86ca1c9a15979a522a22e38cc98e;hb=0d8e8a95338560a1e0d96258d6def311cf2ad368;hp=12f7239b7699a479e9e6929ed27dca2376bce15e;hpb=e43766ea93c025c6544df77bdbed2423fc28a6de;p=cc65 diff --git a/src/common/strbuf.c b/src/common/strbuf.c index 12f7239b7..320e91293 100644 --- a/src/common/strbuf.c +++ b/src/common/strbuf.c @@ -6,8 +6,8 @@ /* */ /* */ /* */ -/* (C) 2001-2004 Ullrich von Bassewitz */ -/* Römerstrasse 52 */ +/* (C) 2001-2008 Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ /* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ /* */ @@ -34,9 +34,12 @@ #include +#include /* common */ +#include "chartype.h" #include "strbuf.h" +#include "va_copy.h" #include "xmalloc.h" #include "xsprintf.h" @@ -59,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); + } } @@ -86,7 +104,7 @@ StrBuf* NewStrBuf (void) StrBuf* B = xmalloc (sizeof (StrBuf)); /* Initialize the struct... */ - InitStrBuf (B); + SB_Init (B); /* ...and return it */ return B; @@ -97,7 +115,7 @@ StrBuf* NewStrBuf (void) void FreeStrBuf (StrBuf* B) /* Free a string buffer */ { - DoneStrBuf (B); + SB_Done (B); xfree (B); } @@ -119,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; } @@ -165,11 +225,13 @@ void SB_Terminate (StrBuf* B) 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); +{ + if (Size) { + if (Target->Allocated < Size) { + SB_CheapRealloc (Target, Size); + } + memcpy (Target->Buf, Buf, Size); } - memcpy (Target->Buf, Buf, Size); Target->Len = Size; } @@ -268,8 +330,9 @@ void SB_Slice (StrBuf* Target, const StrBuf* Source, unsigned Start, unsigned Le /* Target will be empty */ SB_Clear (Target); return; - } else if (Start + Len > Source->Len) { - Len = (Start + Len) - Source->Len; + } + if (Start + Len > Source->Len) { + Len = Source->Len - Start; } /* Make sure we have enough room in the target string buffer */ @@ -290,7 +353,7 @@ void SB_Move (StrBuf* Target, StrBuf* Source) */ { /* Free the target string */ - if (Target->Buf) { + if (Target->Allocated) { xfree (Target->Buf); } @@ -298,7 +361,35 @@ void SB_Move (StrBuf* Target, StrBuf* Source) *Target = *Source; /* Clear Source */ - InitStrBuf (Source); + SB_Init (Source); +} + + + +void SB_ToLower (StrBuf* S) +/* Convert all characters in S to lower case */ +{ + unsigned I; + char* B = S->Buf; + for (I = 0; I < S->Len; ++I, ++B) { + if (IsUpper (*B)) { + *B = tolower (*B); + } + } +} + + + +void SB_ToUpper (StrBuf* S) +/* Convert all characters in S to upper case */ +{ + unsigned I; + char* B = S->Buf; + for (I = 0; I < S->Len; ++I, ++B) { + if (IsLower (*B)) { + *B = toupper (*B); + } + } } @@ -327,6 +418,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 @@ -342,7 +458,7 @@ void SB_VPrintf (StrBuf* S, const char* Format, va_list ap) * an allocation. If not, we have to reallocate and try again. */ va_copy (tmp, ap); - SizeNeeded = xvsnprintf (S->Buf, S->Allocated, Format, ap); + SizeNeeded = xvsnprintf (S->Buf, S->Allocated, Format, tmp); va_end (tmp); /* Check the result, the xvsnprintf function should not fail */ @@ -350,10 +466,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); }