--- var.c 2002/03/07 09:14:05 1.85
+++ var.c 2002/03/07 12:11:09 1.86
@@ -104,6 +104,134 @@
/*
**
+** ==== FORMATTING FUNCTIONS ====
+**
+*/
+
+/* minimal output-independent vprintf(3) variant which supports %{c,s,d,%} only */
+static int
+var_mvxprintf(
+ int (*output)(void *ctx, const char *buffer, size_t bufsize), void *ctx,
+ const char *format, va_list ap)
+{
+ /* sufficient integer buffer: <available-bits> x log_10(2) + safety */
+ char ibuf[((sizeof(int)*8)/3)+10];
+ char *cp;
+ char c;
+ int d;
+ int n;
+ int bytes;
+
+ if (format == NULL || ap == NULL)
+ return -1;
+ bytes = 0;
+ while (*format != '\0') {
+ if (*format == '%') {
+ c = *(format+1);
+ if (c == '%') {
+ /* expand "%%" */
+ cp = &c;
+ n = sizeof(char);
+ }
+ else if (c == 'c') {
+ /* expand "%c" */
+ c = (char)va_arg(ap, int);
+ cp = &c;
+ n = sizeof(char);
+ }
+ else if (c == 's') {
+ /* expand "%s" */
+ if ((cp = (char *)va_arg(ap, char *)) == NULL)
+ cp = "(null)";
+ n = strlen(cp);
+ }
+ else if (c == 'd') {
+ /* expand "%d" */
+ d = (int)va_arg(ap, int);
+#ifdef HAVE_SNPRINTF
+ snprintf(ibuf, sizeof(ibuf), "%d", d); /* explicitly secure */
+#else
+ sprintf(ibuf, "%d", d); /* implicitly secure */
+#endif
+ cp = ibuf;
+ n = strlen(cp);
+ }
+ else {
+ /* any other "%X" */
+ cp = (char *)format;
+ n = 2;
+ }
+ format += 2;
+ }
+ else {
+ /* plain text */
+ cp = (char *)format;
+ if ((format = strchr(cp, '%')) == NULL)
+ format = strchr(cp, '\0');
+ n = format - cp;
+ }
+ /* perform output operation */
+ if (output != NULL)
+ if ((n = output(ctx, cp, n)) == -1)
+ break;
+ bytes += n;
+ }
+ return bytes;
+}
+
+/* output callback function context for var_mvsnprintf() */
+typedef struct {
+ char *bufptr;
+ size_t buflen;
+} var_mvsnprintf_cb_t;
+
+/* output callback function for var_mvsnprintf() */
+static int
+var_mvsnprintf_cb(
+ void *_ctx,
+ const char *buffer, size_t bufsize)
+{
+ var_mvsnprintf_cb_t *ctx = (var_mvsnprintf_cb_t *)_ctx;
+
+ if (bufsize > ctx->buflen)
+ return -1;
+ memcpy(ctx->bufptr, buffer, bufsize);
+ ctx->bufptr += bufsize;
+ ctx->buflen -= bufsize;
+ return bufsize;
+}
+
+/* minimal vsnprintf(3) variant which supports %{c,s,d} only */
+static int
+var_mvsnprintf(
+ char *buffer, size_t bufsize,
+ const char *format, va_list ap)
+{
+ int n;
+ var_mvsnprintf_cb_t ctx;
+
+ if (format == NULL || ap == NULL)
+ return -1;
+ if (buffer != NULL && bufsize == 0)
+ return -1;
+ if (buffer == NULL)
+ /* just determine output length */
+ n = var_mvxprintf(NULL, NULL, format, ap);
+ else {
+ /* perform real output */
+ ctx.bufptr = buffer;
+ ctx.buflen = bufsize;
+ n = var_mvxprintf(var_mvsnprintf_cb, &ctx, format, ap);
+ if (n != -1 && ctx.buflen == 0)
+ n = -1;
+ if (n != -1)
+ *(ctx.bufptr) = '\0';
+ }
+ return n;
+}
+
+/*
+**
** ==== PARSE CONTEXT FUNCTIONS ====
**
*/
@@ -2476,6 +2604,71 @@
return VAR_RC(rc);
}
+/* format and expand a string */
+var_rc_t
+var_formatv(
+ var_t *var,
+ char **dst_ptr, int force_expand,
+ const char *fmt, va_list ap)
+{
+ var_rc_t rc;
+ va_list apbak;
+ char *cpBuf;
+ int nBuf;
+
+ /* argument sanity checks */
+ if (var == NULL || dst_ptr == NULL || fmt == NULL)
+ return VAR_RC(VAR_ERR_INVALID_ARGUMENT);
+
+ /* determine formatting buffer length */
+ apbak = ap;
+ nBuf = var_mvsnprintf(NULL, 0, fmt, ap);
+ ap = apbak;
+ if (nBuf == -1)
+ return VAR_RC(VAR_ERR_FORMATTING_FAILURE);
+
+ /* perform formatting */
+ if ((cpBuf = (char *)malloc(nBuf+1)) == NULL)
+ return VAR_RC(VAR_ERR_OUT_OF_MEMORY);
+ nBuf = var_mvsnprintf(cpBuf, nBuf+1, fmt, ap);
+ if (nBuf == -1) {
+ free(cpBuf);
+ return VAR_RC(VAR_ERR_FORMATTING_FAILURE);
+ }
+
+ /* perform expansion */
+ if ((rc = var_expand(var, cpBuf, nBuf, dst_ptr, NULL, force_expand)) != VAR_OK) {
+ free(cpBuf);
+ return VAR_RC(rc);
+ }
+
+ /* cleanup */
+ free(cpBuf);
+
+ return VAR_OK;
+}
+
+/* format and expand a string */
+var_rc_t
+var_format(
+ var_t *var,
+ char **dst_ptr, int force_expand,
+ const char *fmt, ...)
+{
+ var_rc_t rc;
+ va_list ap;
+
+ /* argument sanity checks */
+ if (var == NULL || dst_ptr == NULL || fmt == NULL)
+ return VAR_RC(VAR_ERR_INVALID_ARGUMENT);
+
+ va_start(ap, fmt);
+ rc = var_formatv(var, dst_ptr, force_expand, fmt, ap);
+ va_end(ap);
+
+ return VAR_RC(rc);
+}
+
/* var_rc_t to string mapping table */
static const char *var_errors[] = {
"everything ok", /* VAR_OK = 0 */
@@ -2522,7 +2715,8 @@
"unterminated loop construct", /* VAR_ERR_UNTERMINATED_LOOP_CONSTRUCT */
"invalid character in loop limits", /* VAR_ERR_INVALID_CHAR_IN_LOOP_LIMITS */
"malformed operation argument list", /* VAR_ERR_MALFORMED_OPERATION_ARGUMENTS */
- "undefined operation" /* VAR_ERR_UNDEFINED_OPERATION */
+ "undefined operation", /* VAR_ERR_UNDEFINED_OPERATION */
+ "formatting failure" /* VAR_ERR_FORMATTING_FAILURE */
};
/* transslate a return code into its corresponding descriptive text */
|