pos - start_offset);
static char sbuf[7];
snprintf(sbuf, sizeof(sbuf),
- "\\u00%c%c",
- json_hex_chars[c >> 4],
- json_hex_chars[c & 0xf]);
- printbuf_memappend (pb, sbuf, sizeof(sbuf) - 1);
-
+ "\\u00%c%c",
+ json_hex_chars[c >> 4],
+ json_hex_chars[c & 0xf]);
+ printbuf_memappend_fast(pb, sbuf, (int) sizeof(sbuf) - 1);
start_offset = ++pos;
} else
pos++;
int had_children = 0;
struct json_object_iter iter;
- sprintbuf(pb, "{" /*}*/);
+ printbuf_strappend(pb, "{" /*}*/);
if (flags & JSON_C_TO_STRING_PRETTY)
- sprintbuf(pb, "\n");
+ printbuf_strappend(pb, "\n");
json_object_object_foreachC(jso, iter)
{
if (had_children)
{
- sprintbuf(pb, ",");
+ printbuf_strappend(pb, ",");
if (flags & JSON_C_TO_STRING_PRETTY)
- sprintbuf(pb, "\n");
+ printbuf_strappend(pb, "\n");
}
had_children = 1;
if (flags & JSON_C_TO_STRING_SPACED)
- sprintbuf(pb, " ");
+ printbuf_strappend(pb, " ");
indent(pb, level+1, flags);
- sprintbuf(pb, "\"");
+ printbuf_strappend(pb, "\"");
json_escape_str(pb, iter.key, strlen(iter.key), flags);
if (flags & JSON_C_TO_STRING_SPACED)
- sprintbuf(pb, "\": ");
+ printbuf_strappend(pb, "\": ");
else
- sprintbuf(pb, "\":");
+ printbuf_strappend(pb, "\":");
if(iter.val == NULL)
- sprintbuf(pb, "null");
+ printbuf_strappend(pb, "null");
else
if (iter.val->_to_json_string(iter.val, pb, level+1,flags) < 0)
return -1;
if (flags & JSON_C_TO_STRING_PRETTY)
{
if (had_children)
- sprintbuf(pb, "\n");
+ printbuf_strappend(pb, "\n");
indent(pb,level,flags);
}
if (flags & JSON_C_TO_STRING_SPACED)
- return sprintbuf(pb, /*{*/ " }");
+ return printbuf_strappend(pb, /*{*/ " }");
else
- return sprintbuf(pb, /*{*/ "}");
+ return printbuf_strappend(pb, /*{*/ "}");
}
int flags)
{
if (jso->o.c_boolean)
- return sprintbuf(pb, "true");
- return sprintbuf(pb, "false");
+ return printbuf_strappend(pb, "true");
+ return printbuf_strappend(pb, "false");
}
struct json_object* json_object_new_boolean(json_bool b)
/* room for 19 digits, the sign char, and a null term */
static char sbuf[21];
snprintf(sbuf, sizeof(sbuf), "%"PRId64, jso->o.c_int64);
- return sprintbuf(pb, sbuf);
+ return printbuf_memappend (pb, sbuf, strlen(sbuf));
}
struct json_object* json_object_new_int(int32_t i)
int level,
int flags)
{
- sprintbuf(pb, "\"");
+ printbuf_strappend(pb, "\"");
json_escape_str(pb, get_string_component(jso), jso->o.c_string.len, flags);
- sprintbuf(pb, "\"");
+ printbuf_strappend(pb, "\"");
return 0;
}
int had_children = 0;
size_t ii;
- sprintbuf(pb, "[");
+ printbuf_strappend(pb, "[");
if (flags & JSON_C_TO_STRING_PRETTY)
- sprintbuf(pb, "\n");
+ printbuf_strappend(pb, "\n");
for(ii=0; ii < json_object_array_length(jso); ii++)
{
struct json_object *val;
if (had_children)
{
- sprintbuf(pb, ",");
+ printbuf_strappend(pb, ",");
if (flags & JSON_C_TO_STRING_PRETTY)
- sprintbuf(pb, "\n");
+ printbuf_strappend(pb, "\n");
}
had_children = 1;
if (flags & JSON_C_TO_STRING_SPACED)
- sprintbuf(pb, " ");
+ printbuf_strappend(pb, " ");
indent(pb, level + 1, flags);
val = json_object_array_get_idx(jso, ii);
if(val == NULL)
- sprintbuf(pb, "null");
+ printbuf_strappend(pb, "null");
else
if (val->_to_json_string(val, pb, level+1, flags) < 0)
return -1;
if (flags & JSON_C_TO_STRING_PRETTY)
{
if (had_children)
- sprintbuf(pb, "\n");
+ printbuf_strappend(pb, "\n");
indent(pb,level,flags);
}
if (flags & JSON_C_TO_STRING_SPACED)
- return sprintbuf(pb, " ]");
- return sprintbuf(pb, "]");
+ return printbuf_strappend(pb, " ]");
+ return printbuf_strappend(pb, "]");
}
static void json_object_array_entry_free(void *data)
if (printbuf_extend(p, p->bpos + size + 1) < 0)
return -1;
}
-
memcpy(p->buf + p->bpos, buf, size);
p->bpos += size;
p->buf[p->bpos]= '\0';
return 0;
}
+int sprintbuf(struct printbuf *p, const char *msg, ...)
+{
+ va_list ap;
+ char *t;
+ int size;
+ char buf[128];
+
+ /* user stack buffer first */
+ va_start(ap, msg);
+ size = vsnprintf(buf, 128, msg, ap);
+ va_end(ap);
+ /* if string is greater than stack buffer, then use dynamic string
+ with vasprintf. Note: some implementation of vsnprintf return -1
+ if output is truncated whereas some return the number of bytes that
+ would have been written - this code handles both cases. */
+ if(size == -1 || size > 127) {
+ va_start(ap, msg);
+ if((size = vasprintf(&t, msg, ap)) < 0) { va_end(ap); return -1; }
+ va_end(ap);
+ printbuf_memappend(p, t, size);
+ free(t);
+ return size;
+ } else {
+ printbuf_memappend(p, buf, size);
+ return size;
+ }
+}
+
void printbuf_reset(struct printbuf *p)
{
p->buf[0] = '\0';
free(p);
}
}
-
-inline int sprintbuf(struct printbuf *p, const char *buf)
-{
- return printbuf_memappend(p, buf, strlen(buf));
-}
extern struct printbuf*
printbuf_new(void);
-/* As an optimization, printbuf_memappend_fast is defined as a macro
+/* As an optimization, printbuf_memappend_fast() is defined as a macro
* that handles copying data if the buffer is large enough; otherwise
- * it invokes printbuf_memappend_real() which performs the heavy
+ * it invokes printbuf_memappend() which performs the heavy
* lifting of realloc()ing the buffer and copying data.
- * Your code should not use printbuf_memappend directly--use
- * printbuf_memappend_fast instead.
+ *
+ * Your code should not use printbuf_memappend() directly unless it
+ * checks the return code. Use printbuf_memappend_fast() instead.
*/
extern int
printbuf_memappend(struct printbuf *p, const char *buf, int size);
#define printbuf_length(p) ((p)->bpos)
+/**
+ * Results in a compile error if the argument is not a string literal.
+ */
+#define _printbuf_check_literal(mystr) ("" mystr)
+
+/**
+ * This is an optimization wrapper around printbuf_memappend() that is useful
+ * for appending string literals. Since the size of string constants is known
+ * at compile time, using this macro can avoid a costly strlen() call. This is
+ * especially helpful when a constant string must be appended many times. If
+ * you got here because of a compilation error caused by passing something
+ * other than a string literal, use printbuf_memappend_fast() in conjunction
+ * with strlen().
+ *
+ * See also:
+ * printbuf_memappend_fast()
+ * printbuf_memappend()
+ * sprintbuf()
+ */
+#define printbuf_strappend(pb, str) \
+ printbuf_memappend ((pb), _printbuf_check_literal(str), sizeof(str) - 1)
+
/**
* Set len bytes of the buffer to charvalue, starting at offset offset.
* Similar to calling memset(x, charvalue, len);
extern int
printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len);
+/**
+ * Formatted print to printbuf.
+ *
+ * This function is the most expensive of the available functions for appending
+ * string data to a printbuf and should be used only where convenience is more
+ * important than speed. Avoid using this function in high performance code or
+ * tight loops; in these scenarios, consider using snprintf() with a static
+ * buffer in conjunction with one of the printbuf_*append() functions.
+ *
+ * See also:
+ * printbuf_memappend_fast()
+ * printbuf_memappend()
+ * printbuf_strappend()
+ */
extern int
-sprintbuf(struct printbuf *p, const char *msg);
+sprintbuf(struct printbuf *p, const char *msg, ...);
extern void
printbuf_reset(struct printbuf *p);
printf("%s: starting test\n", __func__);
pb = printbuf_new();
- sprintbuf(pb, "blue:1");
+ sprintbuf(pb, "blue:%d", 1);
printbuf_memset(pb, -1, 'x', 52);
printf("Buffer contents:%.*s\n", printbuf_length(pb), pb->buf);
printbuf_free(pb);
printf("Append to just after resize: %d, [%s]\n", printbuf_length(pb), pb->buf);
free(data);
+ printbuf_free(pb);
+
+#define SA_TEST_STR "XXXXXXXXXXXXXXXX"
+ pb = printbuf_new();
+ printbuf_strappend(pb, SA_TEST_STR);
+ printf("Buffer size after printbuf_strappend(): %d, [%s]\n", printbuf_length(pb), pb->buf);
+ printbuf_free(pb);
+#undef SA_TEST_STR
+
+ printf("%s: end test\n", __func__);
+}
+
+static void test_sprintbuf(int before_resize);
+static void test_sprintbuf(int before_resize)
+{
+ struct printbuf *pb;
+
+ printf("%s: starting test\n", __func__);
+ pb = printbuf_new();
+ printf("Buffer length: %d\n", printbuf_length(pb));
+
+ char *data = malloc(before_resize + 1 + 1);
+ memset(data, 'X', before_resize + 1 + 1);
+ data[before_resize + 1] = '\0';
+ sprintbuf(pb, "%s", data);
+ free(data);
+ printf("sprintbuf to just after resize(%d+1): %d, [%s], strlen(buf)=%d\n", before_resize, printbuf_length(pb), pb->buf, (int)strlen(pb->buf));
+
+ printbuf_reset(pb);
+ sprintbuf(pb, "plain");
+ printf("%d, [%s]\n", printbuf_length(pb), pb->buf);
+
+ sprintbuf(pb, "%d", 1);
+ printf("%d, [%s]\n", printbuf_length(pb), pb->buf);
+
+ sprintbuf(pb, "%d", INT_MAX);
+ printf("%d, [%s]\n", printbuf_length(pb), pb->buf);
+
+ sprintbuf(pb, "%d", INT_MIN);
+ printf("%d, [%s]\n", printbuf_length(pb), pb->buf);
+
+ sprintbuf(pb, "%s", "%s");
+ printf("%d, [%s]\n", printbuf_length(pb), pb->buf);
printbuf_free(pb);
printf("%s: end test\n", __func__);
printf("========================================\n");
test_printbuf_memappend(&before_resize);
printf("========================================\n");
+ test_sprintbuf(before_resize);
+ printf("========================================\n");
return 0;
}
With embedded \0 character: 4, [ab]
Append to just before resize: 31, [XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX]
Append to just after resize: 32, [XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX]
+Buffer size after printbuf_strappend(): 16, [XXXXXXXXXXXXXXXX]
test_printbuf_memappend: end test
========================================
+test_sprintbuf: starting test
+Buffer length: 0
+sprintbuf to just after resize(31+1): 32, [XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX], strlen(buf)=32
+5, [plain]
+6, [plain1]
+16, [plain12147483647]
+27, [plain12147483647-2147483648]
+29, [plain12147483647-2147483648%s]
+test_sprintbuf: end test
+========================================