Are you bored of re-writing partial, defective memory growing string manipulation code in C, over and over? Don't suffer anymore. Cut and paste this into one of your C headers and never worry again.
Here it is:
/* dynamic string manipulation nano-library */
#ifndef ds_init
struct ds { char * d; int p; int s; };
#define ds_init(x) do { x.d = (char *)0; x.p = x.s = 0; } while(0)
#define ds_rewind(x) x.p = 0;
#define ds_free(x) do { if (x.d) free(x.d); ds_init(x); } while(0)
#define ds_redim(x) do { if (x.p >= x.s) x.d = realloc(x.d, x.s += 32); } while(0)
#define ds_poke(x,c) do { ds_redim(x); x.d[x.p++] = c; } while(0)
#define ds_pokes(x,t) do { char * p = t; while (*p) ds_poke(x, *p++); } while(0)
#endif /* ds_init */
It's just ten lines (including its name in a comment and two lines of
redefining protection). They are implemented as macros; this means that you
should not abuse them, as your code will be bloated. On the other hand, you
don't have to worry about linking nor adding it to your building system. They
use realloc() and free(), so be sure to include stdlib.h.
This example loads a file into a dynamic string:
FILE * f;
struct ds s;
if ((f = fopen("file.txt", "r")) != NULL) {
int c;
ds_init(s);
while ((c = fget(f)) != EOF)
ds_poke(s, c);
ds_poke(s, '\0');
fclose(f);
}
/* the loaded file is in s.d */
By using ds_poke(), you add a char into the string, that is automatically
expanded as needed to make room for it. The struct ds has three elements:
the dynamic string itself (d), the length of the string (p) and the real
length of the allocated block (s). Blocks are expanded in multiples of 32
bytes.
Other available macros are ds_init(), to init a dynamic string, ds_free(), to
free it, ds_rewind(), to restart the insertion of characters to the
beginning of the string, and ds_pokes(), a convenience function to store a
null-terminated string by calling ds_poke() repeatedly. ds_redim() ensures
there is room for a new char; it's internal and you must not use it. As you
can see, it has new datatypes, public, internal and convenience code; not too
bad for ten lines.
The Dynamic String Manipulation Nano-Library has a sister, with the same name and purpose, but implemented as code instead of macros:
/* dynamic string manipulation: prototypes */
struct ds { char * d; int p; int s; };
void ds_init(struct ds * x);
void ds_rewind(struct ds * x);
void ds_free(struct ds * x);
void ds_poke(struct ds * x, int c);
void ds_pokes(struct ds * x, char * t);
/* dynamic string manipulation: implementation */
void ds_init(struct ds * x) { x->d = (char *)0; x->p = x->s = 0; }
void ds_rewind(struct ds * x) { x->p = 0; }
void ds_free(struct ds * x) { if (x->d != NULL) free(x->d); ds_init(x); }
void ds_redim(struct ds * x) { if (x->p >= x->s) x->d = realloc(x->d, x->s += 32); }
void ds_poke(struct ds * x, int c) { ds_redim(x); x->d[x->p++] = c; }
void ds_pokes(struct ds * x, char * t) { while (*t) ds_poke(x, *t++); }
The first stanza contains the prototypes, and the second the code. Obviously, this version lacks the glamour of the previous one.
All this code is licensed under the GPL.