On Sat, Nov 26, 2011 at 12:21 PM, Alexander Nezhinsky <alexandern@xxxxxxxxxxxx> wrote: > Text queries issued through tgtadm use a fixed-size buffer that is filled, > step by step, typically by a few calls to snprintf() or an equivalent. > This requires tracking the current position within the buffer and guarding > against overflows. Currently these goals are achived by few separate macros: > shprintf(), buffer_check() and _buffer_check(). > This approach relies upon local/global counter variables that describe > the buffer state and in some cases a label to escape through on errors. > Two kinds of problems arise in such settings: > First, using hardcoded variable names and especially 'goto' statements in > macros is unsafe, and second, it becomes difficult to use nested function > calls if the called functions also append some strings to the buffer. > > The alternative offered by this patch uses a buffer descriptor context, > 'struct concat_buf', which stores the buffer pointer and relevant counters > and error code. This internal state information avoids writes when buffer is > full and in all cases of previosuly encountered errors. > > Thus we can continue with the function flow as if the buffer is unlimited > and in the end return an appropriate error code using concat_buf_ret(). > Code is simplified and the tedious checks afer each snprintf are avoided. > > As the context may be passed to other functions easily and its state is > preserved upon return, nested calls are naturally enabled. > > Signed-off-by: Alexander Nezhinsky <alexandern@xxxxxxxxxxxx> > --- > usr/util.c | 26 ++++++++++++++++++++++++++ > usr/util.h | 40 +++++++++++++++++++++++++++++----------- > 2 files changed, 55 insertions(+), 11 deletions(-) > > diff --git a/usr/util.c b/usr/util.c > index c78a999..43d2690 100644 > --- a/usr/util.c > +++ b/usr/util.c > @@ -194,3 +194,29 @@ int get_blk_shift(unsigned int size) > return shift; > } > > +int concat_printf(struct concat_buf *b, const char *format, ...) > +{ > + va_list args; > + int rest = b->size - b->used; > + int nprinted; > + > + if (b->err) > + return b->err; > + if (!rest) > + return (b->err = -ENOSPC); > + > + va_start(args, format); > + nprinted = vsnprintf(b->buf + b->used, rest, format, args); > + va_end(args); > + > + if (nprinted < 0) > + return (b->err = nprinted); > + > + if (nprinted >= rest) { > + nprinted = rest; > + b->err = -ENOSPC; > + } > + b->used += nprinted; > + return b->err; > +} > + > diff --git a/usr/util.h b/usr/util.h > index 8abdb94..18d81b8 100644 > --- a/usr/util.h > +++ b/usr/util.h > @@ -8,6 +8,7 @@ > #include <signal.h> > #include <syscall.h> > #include <unistd.h> > +#include <stdarg.h> > #include <limits.h> > #include <linux/types.h> > > @@ -88,17 +89,6 @@ static inline int between(uint32_t seq1, uint32_t seq2, uint32_t seq3) > return seq3 - seq2 >= seq1 - seq2; > } > > -#define shprintf(total, buf, rest, fmt, args...) \ > -do { \ > - int len; \ > - len = snprintf(buf, rest, fmt, ##args); \ > - if (len > rest) \ > - goto overflow; \ > - buf += len; \ > - total += len; \ > - rest -= len; \ > -} while (0) > - > extern unsigned long pagesize, pageshift; > > #if defined(__NR_signalfd) && defined(USE_SIGNALFD) > @@ -151,4 +141,32 @@ struct signalfd_siginfo { > ret; \ > }) > > +struct concat_buf { > + char *buf; > + int size; > + int used; > + int err; > +}; > + > +static inline void concat_buf_init(struct concat_buf *b, > + char *buf, int size) > +{ > + b->buf = buf; > + b->size = size; > + b->used = 0; > + b->err = 0; > +} > + > +static inline int concat_buf_ret(struct concat_buf *b) > +{ > + return !b->err ? b->used : b->err; > +} > + > +static inline const char *concat_delim(struct concat_buf *b, const char *delim) > +{ > + return !b->used ? "" : delim; > +} > + > +extern int concat_printf(struct concat_buf *b, const char *format, ...); > + > #endif Looks like a duplicate of asprintf() ? See also http://www.gnu.org/s/libc/manual/html_node/Dynamic-Output.html. Fubo. -- To unsubscribe from this list: send the line "unsubscribe stgt" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html