summaryrefslogtreecommitdiff
path: root/include/linux/printbuf.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/linux/printbuf.h')
-rw-r--r--include/linux/printbuf.h106
1 files changed, 82 insertions, 24 deletions
diff --git a/include/linux/printbuf.h b/include/linux/printbuf.h
index fa8e73d5..24e62e56 100644
--- a/include/linux/printbuf.h
+++ b/include/linux/printbuf.h
@@ -32,6 +32,10 @@
* Since no equivalent yet exists for GFP_ATOMIC/GFP_NOWAIT, memory allocations
* will be done with GFP_NOWAIT if printbuf->atomic is nonzero.
*
+ * It's allowed to grab the output buffer and free it later with kfree() instead
+ * of using printbuf_exit(), if the user just needs a heap allocated string at
+ * the end.
+ *
* Memory allocation failures: We don't return errors directly, because on
* memory allocation failure we usually don't want to bail out and unwind - we
* want to print what we've got, on a best-effort basis. But code that does want
@@ -67,6 +71,8 @@ enum printbuf_si {
PRINTBUF_UNITS_10, /* use powers of 10^3 (standard SI) */
};
+#define PRINTBUF_INLINE_TABSTOPS 4
+
struct printbuf {
char *buf;
unsigned size;
@@ -82,19 +88,34 @@ struct printbuf {
bool heap_allocated:1;
enum printbuf_si si_units:1;
bool human_readable_units:1;
- u8 tabstop;
- u8 tabstops[4];
+ bool has_indent_or_tabstops:1;
+ bool suppress_indent_tabstop_handling:1;
+ u8 nr_tabstops;
+
+ /*
+ * Do not modify directly: use printbuf_tabstop_add(),
+ * printbuf_tabstop_get()
+ */
+ u8 cur_tabstop;
+ u8 _tabstops[PRINTBUF_INLINE_TABSTOPS];
};
int printbuf_make_room(struct printbuf *, unsigned);
const char *printbuf_str(const struct printbuf *);
void printbuf_exit(struct printbuf *);
-void prt_newline(struct printbuf *);
+void printbuf_tabstops_reset(struct printbuf *);
+void printbuf_tabstop_pop(struct printbuf *);
+int printbuf_tabstop_push(struct printbuf *, unsigned);
+
void printbuf_indent_add(struct printbuf *, unsigned);
void printbuf_indent_sub(struct printbuf *, unsigned);
+
+void prt_newline(struct printbuf *);
void prt_tab(struct printbuf *);
void prt_tab_rjust(struct printbuf *);
+
+void prt_bytes_indented(struct printbuf *, const char *, unsigned);
void prt_human_readable_u64(struct printbuf *, u64);
void prt_human_readable_s64(struct printbuf *, s64);
void prt_units_u64(struct printbuf *, u64);
@@ -129,7 +150,7 @@ static inline unsigned printbuf_remaining(struct printbuf *out)
static inline unsigned printbuf_written(struct printbuf *out)
{
- return min(out->pos, out->size);
+ return out->size ? min(out->pos, out->size - 1) : 0;
}
/*
@@ -150,21 +171,6 @@ static inline void printbuf_nul_terminate(struct printbuf *out)
out->buf[out->size - 1] = 0;
}
-static inline void __prt_chars_reserved(struct printbuf *out, char c, unsigned n)
-{
- memset(out->buf + out->pos,
- c,
- min(n, printbuf_remaining(out)));
- out->pos += n;
-}
-
-static inline void prt_chars(struct printbuf *out, char c, unsigned n)
-{
- printbuf_make_room(out, n);
- __prt_chars_reserved(out, c, n);
- printbuf_nul_terminate(out);
-}
-
/* Doesn't call printbuf_make_room(), doesn't nul terminate: */
static inline void __prt_char_reserved(struct printbuf *out, char c)
{
@@ -186,14 +192,34 @@ static inline void prt_char(struct printbuf *out, char c)
printbuf_nul_terminate(out);
}
+static inline void __prt_chars_reserved(struct printbuf *out, char c, unsigned n)
+{
+ unsigned i, can_print = min(n, printbuf_remaining(out));
+
+ for (i = 0; i < can_print; i++)
+ out->buf[out->pos++] = c;
+ out->pos += n - can_print;
+}
+
+static inline void prt_chars(struct printbuf *out, char c, unsigned n)
+{
+ printbuf_make_room(out, n);
+ __prt_chars_reserved(out, c, n);
+ printbuf_nul_terminate(out);
+}
+
static inline void prt_bytes(struct printbuf *out, const void *b, unsigned n)
{
+ unsigned i, can_print;
+
printbuf_make_room(out, n);
- memcpy(out->buf + out->pos,
- b,
- min(n, printbuf_remaining(out)));
- out->pos += n;
+ can_print = min(n, printbuf_remaining(out));
+
+ for (i = 0; i < can_print; i++)
+ out->buf[out->pos++] = ((char *) b)[i];
+ out->pos += n - can_print;
+
printbuf_nul_terminate(out);
}
@@ -202,6 +228,11 @@ static inline void prt_str(struct printbuf *out, const char *str)
prt_bytes(out, str, strlen(str));
}
+static inline void prt_str_indented(struct printbuf *out, const char *str)
+{
+ prt_bytes_indented(out, str, strlen(str));
+}
+
static inline void prt_hex_byte(struct printbuf *out, u8 byte)
{
printbuf_make_room(out, 2);
@@ -226,7 +257,8 @@ static inline void printbuf_reset(struct printbuf *buf)
buf->pos = 0;
buf->allocation_failure = 0;
buf->indent = 0;
- buf->tabstop = 0;
+ buf->nr_tabstops = 0;
+ buf->cur_tabstop = 0;
}
/**
@@ -245,4 +277,30 @@ static inline void printbuf_atomic_dec(struct printbuf *buf)
buf->atomic--;
}
+/*
+ * This is used for the %pf(%p) sprintf format extension, where we pass a pretty
+ * printer and arguments to the pretty-printer to sprintf
+ *
+ * Instead of passing a pretty-printer function to sprintf directly, we pass it
+ * a pointer to a struct call_pp, so that sprintf can check that the magic
+ * number is present, which in turn ensures that the CALL_PP() macro has been
+ * used in order to typecheck the arguments to the pretty printer function
+ *
+ * Example usage:
+ * sprintf("%pf(%p)", CALL_PP(prt_bdev, bdev));
+ */
+struct call_pp {
+ unsigned long magic;
+ void *fn;
+};
+
+#define PP_TYPECHECK(fn, ...) \
+ ({ while (0) fn((struct printbuf *) NULL, ##__VA_ARGS__); })
+
+#define CALL_PP_MAGIC (unsigned long) 0xce0b92d22f6b6be4
+
+#define CALL_PP(fn, ...) \
+ (PP_TYPECHECK(fn, ##__VA_ARGS__), \
+ &((struct call_pp) { CALL_PP_MAGIC, fn })), ##__VA_ARGS__
+
#endif /* _LINUX_PRINTBUF_H */