/*
* Auto-growing string with optional translation of ' -> '\'' to
* escape shell * quoting.
*
* Copyright (C) 2002 Pete Wyckoff <pw@osc.edu>
*
* $Id: growstr.c 326 2006-01-24 21:35:26Z pw $
*/
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "util.h"
#include "growstr.h"
static const int growstr_grow_chunk = 200;
/*
* Grow the line.
*/
static void
growstr_grow(growstr_t *g)
{
char *x;
g->max += growstr_grow_chunk;
x = Malloc(g->max * sizeof(*x));
if (g->len) {
memcpy(x, g->s, g->len);
free(g->s);
}
g->s = x;
g->s[g->len] = '\0';
}
growstr_t *
growstr_init_empty(void)
{
growstr_t *g = Malloc(sizeof(*g));
g->len = 0;
g->max = 0;
g->translate_single_quote = 0;
g->s = NULL;
return g;
}
/*
* Init and allocate one chunk, assumes it will be used now.
*/
growstr_t *
growstr_init(void)
{
growstr_t *g = growstr_init_empty();
growstr_grow(g);
return g;
}
void
growstr_zero(growstr_t *g)
{
g->len = 0;
if (g->s)
g->s[0] = '\0';
}
void
growstr_free(growstr_t *g)
{
if (g->s)
free(g->s);
free(g);
}
void
growstr_append(growstr_t *g, const char *s)
{
const char *cp;
for (cp=s; *cp; cp++) {
if (g->len + 5 >= g->max)
growstr_grow(g);
if (*cp == '\'' && g->translate_single_quote) {
/* close ongoing single quote string */
g->s[g->len++] = '\'';
/* literal backslash */
g->s[g->len++] = '\\';
g->s[g->len++] = '\\';
/* literal single-quote */
g->s[g->len++] = '\\';
g->s[g->len++] = '\'';
/* restart ongoing single quote string */
g->s[g->len++] = '\'';
} else
g->s[g->len++] = *cp;
}
g->s[g->len] = 0;
}
/*
* Appending printf, does not reinitialize the string.
*/
void
growstr_printf(growstr_t *g, const char *format, ...)
{
growstr_t *h = growstr_init();
for (;;) {
int n;
va_list ap;
/* must reinit ap every loop as vsnprintf will change it */
va_start(ap, format);
n = vsnprintf(h->s, h->max, format, ap);
va_end(ap);
if (n < h->max) {
h->len = n;
break;
}
while (n >= h->max)
growstr_grow(h);
}
growstr_append(g, h->s);
growstr_free(h);
}
syntax highlighted by Code2HTML, v. 0.9.1