Added smprintf() and outbuf to the testingpriv.h functions, introducing a simpler outbuf API along the way. Changing the test suite to actually use this comes next.
This commit is contained in:
parent
40508a457c
commit
9bec2005a1
|
@ -31,7 +31,7 @@ struct uiprivArray {
|
|||
arr.what = whatstr;
|
||||
#define uiprivArrayFree(arr) \
|
||||
uiprivFree(arr.buf); \
|
||||
memset(&arr, 0, sizeof (uiprivArray);
|
||||
memset(&arr, 0, sizeof (uiprivArray));
|
||||
#define uiprivArrayAt(arr, T, n) (((T *) (arr.buf)) + (n))
|
||||
extern void *uiprivArrayAppend(uiprivArray *arr, size_t n);
|
||||
extern void *uiprivArrayInsertAt(uiprivArray *arr, size_t pos, size_t n);
|
||||
|
|
|
@ -62,7 +62,6 @@ static void outbufVprintf(struct outbuf *o, int indent, const char *format, va_l
|
|||
|
||||
va_copy(ap2, ap);
|
||||
n = testingprivVsnprintf(NULL, 0, format, ap2);
|
||||
// TODO handle n < 0 case
|
||||
va_end(ap2);
|
||||
buf = testingprivNewArray(char, n + 1);
|
||||
testingprivVsnprintf(buf, n + 1, format, ap);
|
||||
|
|
|
@ -139,3 +139,147 @@ char *testingprivStrdup(const char *s)
|
|||
strcpy(t, s);
|
||||
return t;
|
||||
}
|
||||
|
||||
char *testingprivVsmprintf(const char *fmt, va_list ap)
|
||||
{
|
||||
char *s;
|
||||
va_list ap2;
|
||||
int n;
|
||||
|
||||
va_copy(ap2, ap);
|
||||
n = testingprivVsnprintf(NULL, 0, fmt, ap2);
|
||||
va_end(ap2);
|
||||
s = (char *) testingprivAlloc((n + 1) * sizeof (char), "char[]");
|
||||
testingprivVsnprintf(s, n + 1, fmt, ap);
|
||||
return s;
|
||||
}
|
||||
|
||||
char *testingprivSmprintf(const char *fmt, ...)
|
||||
{
|
||||
char *s;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
s = testingprivVsmprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
return s;
|
||||
}
|
||||
|
||||
struct testingprivOutbuf {
|
||||
testingprivArray buf;
|
||||
};
|
||||
|
||||
testingprivOutbuf *testingprivNewOutbuf(void)
|
||||
{
|
||||
testingprivOutbuf *o;
|
||||
|
||||
o = testingprivNew(testingprivOutbuf);
|
||||
testingprivArrayInit(o->buf, char, 32, "testing output buffer");
|
||||
return o;
|
||||
}
|
||||
|
||||
void testingprivOutbufFree(testingprivOutbuf *o)
|
||||
{
|
||||
testingprivArrayFree(o->buf);
|
||||
testingprivFree(o);
|
||||
}
|
||||
|
||||
void testingprivOutbufVprintf(testingprivOutbuf *o, const char *fmt, va_list ap)
|
||||
{
|
||||
char *dest;
|
||||
va_list ap2;
|
||||
int n;
|
||||
|
||||
if (o == NULL) {
|
||||
vprintf(fmt, ap);
|
||||
return;
|
||||
}
|
||||
va_copy(ap2, ap);
|
||||
n = testingprivVsnprintf(NULL, 0, fmt, ap);
|
||||
va_end(ap2);
|
||||
// To conserve memory, we only allocate the terminating NUL once.
|
||||
if (o->buf.len == 0)
|
||||
dest = (char *) testingprivArrayAppend(&(o->buf), n + 1);
|
||||
else {
|
||||
dest = (char *) testingprivArrayAppend(&(o->buf), n);
|
||||
dest--;
|
||||
}
|
||||
testingprivVsnprintf(dest, n + 1, fmt, ap);
|
||||
}
|
||||
|
||||
void testingprivOutbufPrintf(testingprivOutbuf *o, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
testingprivOutbufVprintf(o, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
// TODO right now this assumes the last character in o before calling this is a newline
|
||||
void testingprivOutbufAppendOutbuf(testingprivOutbuf *o, testingprivOutbuf *src, int indent)
|
||||
{
|
||||
char *buf;
|
||||
size_t n;
|
||||
int hasTrailingBlankLine;
|
||||
size_t trailingBlankLinePos;
|
||||
char *lineStart, *lineEnd;
|
||||
int firstLine;
|
||||
char *indentstr;
|
||||
int indentoff;
|
||||
|
||||
buf = src->buf.buf;
|
||||
n = src->buf.len;
|
||||
if (n == 0)
|
||||
// nothing to write
|
||||
return;
|
||||
|
||||
// strip trailing blank lines, if any
|
||||
hasTrailingBlankLine = 0;
|
||||
if (buf[n - 1] == '\n') {
|
||||
hasTrailingBlankLine = 1;
|
||||
while (n > 0 && buf[n - 1] == '\n')
|
||||
n--;
|
||||
if (n == 0) {
|
||||
// the buffer only has blank lines, so just add a single newline and be done with it
|
||||
// TODO verify that this is the correct behavior
|
||||
testingprivOutbufPrintf(o, "\n");
|
||||
return;
|
||||
}
|
||||
trailingBlankLinePos = n;
|
||||
buf[trailingBlankLinePos] = '\0';
|
||||
}
|
||||
|
||||
// precompute the indent string so we don't have to repeatedly print four spaces each time
|
||||
// the + 4 is because lines after the first have one extra level of indent; indentoff is used to control that
|
||||
indentstr = (char *) testingprivAlloc((indent * 4 + 4 + 1) * sizeof (char), "indent string");
|
||||
// the NUL was added by testingprivAlloc()
|
||||
memset(indentstr, ' ', (indent * 4 + 4) * sizeof (char));
|
||||
firstLine = 1;
|
||||
indentoff = 4;
|
||||
|
||||
lineStart = buf;
|
||||
for (;;) {
|
||||
lineEnd = strchr(lineStart, '\n');
|
||||
if (lineEnd == NULL) // last line
|
||||
break;
|
||||
*lineEnd = '\0';
|
||||
testingprivOutbufPrintf(o, "%s%s\n", indentstr + indentoff, lineStart);
|
||||
// be sure to restore src to its original state
|
||||
*lineEnd = '\n';
|
||||
lineStart = lineEnd + 1;
|
||||
if (firstLine) {
|
||||
// subsequent lines are indented twice
|
||||
firstLine = 0;
|
||||
indentoff = 0;
|
||||
}
|
||||
}
|
||||
// print the last line
|
||||
testingprivOutbufPrintf(o, "%s%s\n", indentstr + indentoff, lineStart);
|
||||
|
||||
testingprivFree(indentstr);
|
||||
|
||||
// restore src to its original state
|
||||
if (hasTrailingBlankLine)
|
||||
buf[trailingBlankLinePos] = '\n';
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ struct testingprivArray {
|
|||
arr.what = whatstr;
|
||||
#define testingprivArrayFree(arr) \
|
||||
testingprivFree(arr.buf); \
|
||||
memset(&arr, 0, sizeof (testingprivArray);
|
||||
memset(&arr, 0, sizeof (testingprivArray));
|
||||
#define testingprivArrayAt(arr, T, n) (((T *) (arr.buf)) + (n))
|
||||
extern void *testingprivArrayAppend(testingprivArray *arr, size_t n);
|
||||
extern void *testingprivArrayInsertAt(testingprivArray *arr, size_t pos, size_t n);
|
||||
|
@ -38,3 +38,13 @@ extern void testingprivArrayQsort(testingprivArray *arr, int (*compare)(const vo
|
|||
extern int testingprivVsnprintf(char *s, size_t n, const char *format, va_list ap);
|
||||
extern int testingprivSnprintf(char *s, size_t n, const char *format, ...);
|
||||
extern char *testingprivStrdup(const char *s);
|
||||
extern char *testingprivVsmprintf(const char *fmt, va_list ap);
|
||||
extern char *testingprivSmprintf(const char *fmt, ...);
|
||||
|
||||
// a testingprivOutbuf of NULL writes directly to stdout
|
||||
typedef struct testingprivOutbuf testingprivOutbuf;
|
||||
extern testingprivOutbuf *testingprivNewOutbuf(void);
|
||||
extern void testingprivOutbufFree(testingprivOutbuf *o);
|
||||
extern void testingprivOutbufVprintf(testingprivOutbuf *o, const char *fmt, va_list ap);
|
||||
extern void testingprivOutbufPrintf(testingprivOutbuf *o, const char *fmt, ...);
|
||||
extern void testingprivOutbufAppendOutbuf(testingprivOutbuf *o, testingprivOutbuf *src, int indent);
|
||||
|
|
Loading…
Reference in New Issue