commit fe575b5ca645d6751fba56efa907952eda200b09 Author: Willy Tarreau Date: Wed Aug 21 13:17:37 2019 +0200 MINOR: tools: add append_prefixed_str() This is somewhat related to indent_msg() except that this one places a known prefix at the beginning of each line, allows to replace the EOL character, and not to insert a prefix on the first line if not desired. It works with a normal output buffer/chunk so it doesn't need to allocate anything nor to modify the input string. It is suitable for use in multi- line backtraces. (cherry picked from commit a2c9911ace8537e0a350daf8d981170a001b6c7a) [wt: backported to improve troubleshooting when the watchdog fires] Signed-off-by: Willy Tarreau diff --git a/include/common/standard.h b/include/common/standard.h index 0f4b1870..cdefc9f5 100644 --- a/include/common/standard.h +++ b/include/common/standard.h @@ -1238,6 +1238,7 @@ char *memprintf(char **out, const char *format, ...) * free(err); */ char *indent_msg(char **out, int level); +int append_prefixed_str(struct buffer *out, const char *in, const char *pfx, char eol, int first); /* removes environment variable from the environment as found in * environ. This is only provided as an alternative for systems without diff --git a/src/standard.c b/src/standard.c index 2f205f74..717c14a9 100644 --- a/src/standard.c +++ b/src/standard.c @@ -3709,6 +3709,41 @@ char *indent_msg(char **out, int level) return ret; } +/* makes a copy of message into , with each line prefixed with + * and end of lines replaced with if not 0. The first line to indent has + * to be indicated in (starts at zero), so that it is possible to skip + * indenting the first line if it has to be appended after an existing message. + * Empty strings are never indented, and NULL strings are considered empty both + * for and . It returns non-zero if an EOL was appended as the last + * character, non-zero otherwise. + */ +int append_prefixed_str(struct buffer *out, const char *in, const char *pfx, char eol, int first) +{ + int bol, lf; + int pfxlen = pfx ? strlen(pfx) : 0; + + if (!in) + return 0; + + bol = 1; + lf = 0; + while (*in) { + if (bol && pfxlen) { + if (first > 0) + first--; + else + b_putblk(out, pfx, pfxlen); + bol = 0; + } + + lf = (*in == '\n'); + bol |= lf; + b_putchr(out, (lf && eol) ? eol : *in); + in++; + } + return lf; +} + /* removes environment variable from the environment as found in * environ. This is only provided as an alternative for systems without * unsetenv() (old Solaris and AIX versions). THIS IS NOT THREAD SAFE.