+
+ if (size > sz_off) {
+ va_start(ap, fmt);
+ ret = vsnprintf(p + sz_off, size - sz_off, fmt, ap);
+ va_end(ap);
+ if (ret > -1 && ret < size - sz_off) { /* success */
+ b->offset += ret + sz_off;
+ if (sz_off)
+ write_size_header(p, ret);
+ return ret + sz_off;
+ }
+ }
+ /* check if we may grow the buffer */
+ if (!b->max_size || 2 * b->size < b->max_size) { /* yes */
+ /* try again with more space */
+ b->size *= 2;
+ b->buf = para_realloc(b->buf, b->size);
+ continue;
+ }
+ /* can't grow buffer */
+ if (!b->offset || !b->max_size_handler) /* message too large */
+ return -ERRNO_TO_PARA_ERROR(ENOSPC);
+ ret = b->max_size_handler(b->buf, b->offset, b->private_data);
+ if (ret < 0)
+ return ret;
+ b->offset = 0;
+ }
+}
+
+/** \cond LLONG_MAX and LLONG_LIN might not be defined. */
+#ifndef LLONG_MAX
+#define LLONG_MAX (1 << (sizeof(long) - 1))
+#endif
+#ifndef LLONG_MIN
+#define LLONG_MIN (-LLONG_MAX - 1LL)
+#endif
+/** \endcond */
+
+/**
+ * Convert a string to a 64-bit signed integer value.
+ *
+ * \param str The string to be converted.
+ * \param value Result pointer.
+ *
+ * \return Standard.
+ *
+ * \sa para_atoi32(), strtol(3), atoi(3).
+ */
+int para_atoi64(const char *str, int64_t *value)
+{
+ char *endptr;
+ long long tmp;
+
+ errno = 0; /* To distinguish success/failure after call */
+ tmp = strtoll(str, &endptr, 10);
+ if (errno == ERANGE && (tmp == LLONG_MAX || tmp == LLONG_MIN))
+ return -E_ATOI_OVERFLOW;
+ if (errno != 0 && tmp == 0) /* other error */
+ return -E_STRTOLL;
+ if (endptr == str)
+ return -E_ATOI_NO_DIGITS;
+ if (*endptr != '\0') /* Further characters after number */
+ return -E_ATOI_JUNK_AT_END;
+ *value = tmp;
+ return 1;
+}
+
+/**
+ * Convert a string to a 32-bit signed integer value.
+ *
+ * \param str The string to be converted.
+ * \param value Result pointer.
+ *
+ * \return Standard.
+ *
+ * \sa para_atoi64().
+*/
+int para_atoi32(const char *str, int32_t *value)
+{
+ int64_t tmp;
+ int ret;
+ const int32_t max = 2147483647;
+
+ ret = para_atoi64(str, &tmp);
+ if (ret < 0)
+ return ret;
+ if (tmp > max || tmp < -max - 1)
+ return -E_ATOI_OVERFLOW;
+ *value = tmp;
+ return 1;
+}
+
+static inline int loglevel_equal(const char *arg, const char * const ll)
+{
+ return !strncasecmp(arg, ll, strlen(ll));
+}
+
+/**
+ * Compute the loglevel number from its name.
+ *
+ * \param txt The name of the loglevel (debug, info, ...).
+ *
+ * \return The numeric representation of the loglevel name.
+ */
+int get_loglevel_by_name(const char *txt)
+{
+ if (loglevel_equal(txt, "debug"))
+ return LL_DEBUG;
+ if (loglevel_equal(txt, "info"))
+ return LL_INFO;
+ if (loglevel_equal(txt, "notice"))
+ return LL_NOTICE;
+ if (loglevel_equal(txt, "warning"))
+ return LL_WARNING;
+ if (loglevel_equal(txt, "error"))
+ return LL_ERROR;
+ if (loglevel_equal(txt, "crit"))
+ return LL_CRIT;
+ if (loglevel_equal(txt, "emerg"))
+ return LL_EMERG;
+ return -1;
+}
+
+static int get_next_word(const char *buf, const char *delim, char **word)
+{
+ enum line_state_flags {LSF_HAVE_WORD = 1, LSF_BACKSLASH = 2,
+ LSF_SINGLE_QUOTE = 4, LSF_DOUBLE_QUOTE = 8};
+ const char *in;
+ char *out;
+ int ret, state = 0;
+
+ out = para_malloc(strlen(buf) + 1);
+ *out = '\0';
+ *word = out;
+ for (in = buf; *in; in++) {
+ const char *p;
+
+ switch (*in) {
+ case '\\':
+ if (state & LSF_BACKSLASH) /* \\ */
+ goto copy_char;
+ state |= LSF_BACKSLASH;
+ state |= LSF_HAVE_WORD;
+ continue;
+ case 'n':
+ case 't':
+ if (state & LSF_BACKSLASH) { /* \n or \t */
+ *out++ = (*in == 'n')? '\n' : '\t';
+ state &= ~LSF_BACKSLASH;
+ continue;
+ }
+ goto copy_char;
+ case '"':
+ if (state & LSF_BACKSLASH) /* \" */
+ goto copy_char;
+ if (state & LSF_SINGLE_QUOTE) /* '" */
+ goto copy_char;
+ if (state & LSF_DOUBLE_QUOTE) {
+ state &= ~LSF_DOUBLE_QUOTE;
+ continue;
+ }
+ state |= LSF_HAVE_WORD;
+ state |= LSF_DOUBLE_QUOTE;
+ continue;
+ case '\'':
+ if (state & LSF_BACKSLASH) /* \' */
+ goto copy_char;
+ if (state & LSF_DOUBLE_QUOTE) /* "' */
+ goto copy_char;
+ if (state & LSF_SINGLE_QUOTE) {
+ state &= ~LSF_SINGLE_QUOTE;
+ continue;
+ }
+ state |= LSF_HAVE_WORD;
+ state |= LSF_SINGLE_QUOTE;
+ continue;
+ }
+ for (p = delim; *p; p++) {
+ if (*in != *p)
+ continue;
+ if (state & LSF_BACKSLASH)
+ goto copy_char;
+ if (state & LSF_SINGLE_QUOTE)
+ goto copy_char;
+ if (state & LSF_DOUBLE_QUOTE)
+ goto copy_char;
+ if (state & LSF_HAVE_WORD)
+ goto success;