177cb4d3eSLandon J. Fuller /*-
277cb4d3eSLandon J. Fuller * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
377cb4d3eSLandon J. Fuller * All rights reserved.
477cb4d3eSLandon J. Fuller *
577cb4d3eSLandon J. Fuller * Redistribution and use in source and binary forms, with or without
677cb4d3eSLandon J. Fuller * modification, are permitted provided that the following conditions
777cb4d3eSLandon J. Fuller * are met:
877cb4d3eSLandon J. Fuller * 1. Redistributions of source code must retain the above copyright
977cb4d3eSLandon J. Fuller * notice, this list of conditions and the following disclaimer,
1077cb4d3eSLandon J. Fuller * without modification.
1177cb4d3eSLandon J. Fuller * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1277cb4d3eSLandon J. Fuller * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
1377cb4d3eSLandon J. Fuller * redistribution must be conditioned upon including a substantially
1477cb4d3eSLandon J. Fuller * similar Disclaimer requirement for further binary redistribution.
1577cb4d3eSLandon J. Fuller *
1677cb4d3eSLandon J. Fuller * NO WARRANTY
1777cb4d3eSLandon J. Fuller * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1877cb4d3eSLandon J. Fuller * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1977cb4d3eSLandon J. Fuller * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
2077cb4d3eSLandon J. Fuller * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
2177cb4d3eSLandon J. Fuller * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
2277cb4d3eSLandon J. Fuller * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2377cb4d3eSLandon J. Fuller * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2477cb4d3eSLandon J. Fuller * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
2577cb4d3eSLandon J. Fuller * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2677cb4d3eSLandon J. Fuller * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
2777cb4d3eSLandon J. Fuller * THE POSSIBILITY OF SUCH DAMAGES.
2877cb4d3eSLandon J. Fuller */
2977cb4d3eSLandon J. Fuller
3077cb4d3eSLandon J. Fuller #include <sys/param.h>
31*91898857SMark Johnston #include <sys/limits.h>
3277cb4d3eSLandon J. Fuller #include <sys/sbuf.h>
3377cb4d3eSLandon J. Fuller
3477cb4d3eSLandon J. Fuller #ifdef _KERNEL
3577cb4d3eSLandon J. Fuller
3677cb4d3eSLandon J. Fuller #include <sys/ctype.h>
3777cb4d3eSLandon J. Fuller #include <sys/kernel.h>
3877cb4d3eSLandon J. Fuller #include <sys/malloc.h>
3977cb4d3eSLandon J. Fuller #include <sys/systm.h>
4077cb4d3eSLandon J. Fuller
4177cb4d3eSLandon J. Fuller #include <machine/_inttypes.h>
4277cb4d3eSLandon J. Fuller
4377cb4d3eSLandon J. Fuller #else /* !_KERNEL */
4477cb4d3eSLandon J. Fuller
4577cb4d3eSLandon J. Fuller #include <ctype.h>
4677cb4d3eSLandon J. Fuller #include <inttypes.h>
4777cb4d3eSLandon J. Fuller #include <errno.h>
4877cb4d3eSLandon J. Fuller #include <stdlib.h>
4977cb4d3eSLandon J. Fuller #include <string.h>
5077cb4d3eSLandon J. Fuller
5177cb4d3eSLandon J. Fuller #endif /* _KERNEL */
5277cb4d3eSLandon J. Fuller
5377cb4d3eSLandon J. Fuller #include "bhnd_nvram_private.h"
5477cb4d3eSLandon J. Fuller #include "bhnd_nvram_valuevar.h"
5577cb4d3eSLandon J. Fuller
5677cb4d3eSLandon J. Fuller #ifdef _KERNEL
5777cb4d3eSLandon J. Fuller #define bhnd_nv_hex2ascii(hex) hex2ascii(hex)
5877cb4d3eSLandon J. Fuller #else /* !_KERNEL */
5977cb4d3eSLandon J. Fuller static char const bhnd_nv_hex2ascii[] = "0123456789abcdefghijklmnopqrstuvwxyz";
6077cb4d3eSLandon J. Fuller #define bhnd_nv_hex2ascii(hex) (bhnd_nv_hex2ascii[hex])
6177cb4d3eSLandon J. Fuller #endif /* _KERNEL */
6277cb4d3eSLandon J. Fuller
6377cb4d3eSLandon J. Fuller /**
6477cb4d3eSLandon J. Fuller * Maximum size, in bytes, of a string-encoded NVRAM integer value, not
6577cb4d3eSLandon J. Fuller * including any prefix (0x, 0, etc).
6677cb4d3eSLandon J. Fuller *
6777cb4d3eSLandon J. Fuller * We assume the largest possible encoding is the base-2 representation
6877cb4d3eSLandon J. Fuller * of a 64-bit integer.
6977cb4d3eSLandon J. Fuller */
7077cb4d3eSLandon J. Fuller #define NV_NUMSTR_MAX ((sizeof(uint64_t) * CHAR_BIT) + 1)
7177cb4d3eSLandon J. Fuller
7277cb4d3eSLandon J. Fuller /**
7377cb4d3eSLandon J. Fuller * Format a string representation of @p value using @p fmt, with, writing the
7477cb4d3eSLandon J. Fuller * result to @p outp.
7577cb4d3eSLandon J. Fuller *
7677cb4d3eSLandon J. Fuller * @param value The value to be formatted.
7777cb4d3eSLandon J. Fuller * @param fmt The format string.
7877cb4d3eSLandon J. Fuller * @param[out] outp On success, the string will be written to this
7977cb4d3eSLandon J. Fuller * buffer. This argment may be NULL if the value is
8077cb4d3eSLandon J. Fuller * not desired.
8177cb4d3eSLandon J. Fuller * @param[in,out] olen The capacity of @p outp. On success, will be set
8277cb4d3eSLandon J. Fuller * to the actual number of bytes required for the
8377cb4d3eSLandon J. Fuller * requested string encoding (including a trailing
8477cb4d3eSLandon J. Fuller * NUL).
8577cb4d3eSLandon J. Fuller *
8677cb4d3eSLandon J. Fuller * Refer to bhnd_nvram_val_vprintf() for full format string documentation.
8777cb4d3eSLandon J. Fuller *
8877cb4d3eSLandon J. Fuller * @retval 0 success
8977cb4d3eSLandon J. Fuller * @retval EINVAL If @p fmt contains unrecognized format string
9077cb4d3eSLandon J. Fuller * specifiers.
9177cb4d3eSLandon J. Fuller * @retval ENOMEM If the @p outp is non-NULL, and the provided @p olen
9277cb4d3eSLandon J. Fuller * is too small to hold the encoded value.
9377cb4d3eSLandon J. Fuller * @retval EFTYPE If value coercion from @p value to a single string
9477cb4d3eSLandon J. Fuller * value via @p fmt is unsupported.
9577cb4d3eSLandon J. Fuller * @retval ERANGE If value coercion of @p value would overflow (or
9677cb4d3eSLandon J. Fuller * underflow) the representation defined by @p fmt.
9777cb4d3eSLandon J. Fuller */
9877cb4d3eSLandon J. Fuller int
bhnd_nvram_val_printf(bhnd_nvram_val * value,const char * fmt,char * outp,size_t * olen,...)9958efe686SLandon J. Fuller bhnd_nvram_val_printf(bhnd_nvram_val *value, const char *fmt, char *outp,
10077cb4d3eSLandon J. Fuller size_t *olen, ...)
10177cb4d3eSLandon J. Fuller {
10277cb4d3eSLandon J. Fuller va_list ap;
10377cb4d3eSLandon J. Fuller int error;
10477cb4d3eSLandon J. Fuller
10577cb4d3eSLandon J. Fuller va_start(ap, olen);
10677cb4d3eSLandon J. Fuller error = bhnd_nvram_val_vprintf(value, fmt, outp, olen, ap);
10777cb4d3eSLandon J. Fuller va_end(ap);
10877cb4d3eSLandon J. Fuller
10977cb4d3eSLandon J. Fuller return (error);
11077cb4d3eSLandon J. Fuller }
11177cb4d3eSLandon J. Fuller
11277cb4d3eSLandon J. Fuller /**
11377cb4d3eSLandon J. Fuller * Format a string representation of the elements of @p value using @p fmt,
11477cb4d3eSLandon J. Fuller * writing the result to @p outp.
11577cb4d3eSLandon J. Fuller *
11677cb4d3eSLandon J. Fuller * @param value The value to be formatted.
11777cb4d3eSLandon J. Fuller * @param fmt The format string.
11877cb4d3eSLandon J. Fuller * @param[out] outp On success, the string will be written to this
11977cb4d3eSLandon J. Fuller * buffer. This argment may be NULL if the value is
12077cb4d3eSLandon J. Fuller * not desired.
12177cb4d3eSLandon J. Fuller * @param[in,out] olen The capacity of @p outp. On success, will be set
12277cb4d3eSLandon J. Fuller * to the actual number of bytes required for the
12377cb4d3eSLandon J. Fuller * requested string encoding (including a trailing
12477cb4d3eSLandon J. Fuller * NUL).
12577cb4d3eSLandon J. Fuller * @param ap Argument list.
12677cb4d3eSLandon J. Fuller *
12777cb4d3eSLandon J. Fuller * @par Format Strings
12877cb4d3eSLandon J. Fuller *
12977cb4d3eSLandon J. Fuller * Value format strings are similar, but not identical to, those used
13077cb4d3eSLandon J. Fuller * by printf(3).
13177cb4d3eSLandon J. Fuller *
13277cb4d3eSLandon J. Fuller * Format specifier format:
13377cb4d3eSLandon J. Fuller * %[repeat][flags][width][.precision][length modifier][specifier]
13477cb4d3eSLandon J. Fuller *
13577cb4d3eSLandon J. Fuller * The format specifier is interpreted as an encoding directive for an
13677cb4d3eSLandon J. Fuller * individual value element; each format specifier will fetch the next element
13777cb4d3eSLandon J. Fuller * from the value, encode the element as the appropriate type based on the
13877cb4d3eSLandon J. Fuller * length modifiers and specifier, and then format the result as a string.
13977cb4d3eSLandon J. Fuller *
14077cb4d3eSLandon J. Fuller * For example, given a string value of '0x000F', and a format specifier of
14177cb4d3eSLandon J. Fuller * '%#hhx', the value will be asked to encode its first element as
14277cb4d3eSLandon J. Fuller * BHND_NVRAM_TYPE_UINT8. String formatting will then be applied to the 8-bit
14377cb4d3eSLandon J. Fuller * unsigned integer representation, producing a string value of "0xF".
14477cb4d3eSLandon J. Fuller *
14577cb4d3eSLandon J. Fuller * Repeat:
14677cb4d3eSLandon J. Fuller * - [digits] Repeatedly apply the format specifier to the input
14777cb4d3eSLandon J. Fuller * value's elements up to `digits` times. The delimiter
14877cb4d3eSLandon J. Fuller * must be passed as a string in the next variadic
14977cb4d3eSLandon J. Fuller * argument.
15077cb4d3eSLandon J. Fuller * - [] Repeatedly apply the format specifier to the input
15177cb4d3eSLandon J. Fuller * value's elements until all elements have been. The
15277cb4d3eSLandon J. Fuller * processed. The delimiter must be passed as a string in
15377cb4d3eSLandon J. Fuller * the next variadic argument.
15477cb4d3eSLandon J. Fuller * - [*] Repeatedly apply the format specifier to the input
15577cb4d3eSLandon J. Fuller * value's elements. The repeat count is read from the
15677cb4d3eSLandon J. Fuller * next variadic argument as a size_t value
15777cb4d3eSLandon J. Fuller *
15877cb4d3eSLandon J. Fuller * Flags:
15977cb4d3eSLandon J. Fuller * - '#' use alternative form (e.g. 0x/0X prefixing of hex
16077cb4d3eSLandon J. Fuller * strings).
16177cb4d3eSLandon J. Fuller * - '0' zero padding
16277cb4d3eSLandon J. Fuller * - '-' left adjust padding
16377cb4d3eSLandon J. Fuller * - '+' include a sign character
16477cb4d3eSLandon J. Fuller * - ' ' include a space in place of a sign character for
16577cb4d3eSLandon J. Fuller * positive numbers.
16677cb4d3eSLandon J. Fuller *
16777cb4d3eSLandon J. Fuller * Width/Precision:
16877cb4d3eSLandon J. Fuller * - digits minimum field width.
16977cb4d3eSLandon J. Fuller * - * read the minimum field width from the next variadic
17077cb4d3eSLandon J. Fuller * argument as a ssize_t value. A negative value enables
17177cb4d3eSLandon J. Fuller * left adjustment.
17277cb4d3eSLandon J. Fuller * - .digits field precision.
17377cb4d3eSLandon J. Fuller * - .* read the field precision from the next variadic argument
17477cb4d3eSLandon J. Fuller * as a ssize_t value. A negative value enables left
17577cb4d3eSLandon J. Fuller * adjustment.
17677cb4d3eSLandon J. Fuller *
17777cb4d3eSLandon J. Fuller * Length Modifiers:
17877cb4d3eSLandon J. Fuller * - 'hh', 'I8' Convert the value to an 8-bit signed or unsigned
17977cb4d3eSLandon J. Fuller * integer.
18077cb4d3eSLandon J. Fuller * - 'h', 'I16' Convert the value to an 16-bit signed or unsigned
18177cb4d3eSLandon J. Fuller * integer.
18277cb4d3eSLandon J. Fuller * - 'l', 'I32' Convert the value to an 32-bit signed or unsigned
18377cb4d3eSLandon J. Fuller * integer.
18477cb4d3eSLandon J. Fuller * - 'll', 'j', 'I64' Convert the value to an 64-bit signed or unsigned
18577cb4d3eSLandon J. Fuller * integer.
18677cb4d3eSLandon J. Fuller *
18777cb4d3eSLandon J. Fuller * Data Specifiers:
18877cb4d3eSLandon J. Fuller * - 'd', 'i' Convert and format as a signed decimal integer.
18977cb4d3eSLandon J. Fuller * - 'u' Convert and format as an unsigned decimal integer.
19077cb4d3eSLandon J. Fuller * - 'o' Convert and format as an unsigned octal integer.
19177cb4d3eSLandon J. Fuller * - 'x' Convert and format as an unsigned hexadecimal integer,
19277cb4d3eSLandon J. Fuller * using lowercase hex digits.
19377cb4d3eSLandon J. Fuller * - 'X' Convert and format as an unsigned hexadecimal integer,
19477cb4d3eSLandon J. Fuller * using uppercase hex digits.
19577cb4d3eSLandon J. Fuller * - 's' Convert and format as a string.
19677cb4d3eSLandon J. Fuller * - '%' Print a literal '%' character.
19777cb4d3eSLandon J. Fuller *
19877cb4d3eSLandon J. Fuller * @retval 0 success
19977cb4d3eSLandon J. Fuller * @retval EINVAL If @p fmt contains unrecognized format string
20077cb4d3eSLandon J. Fuller * specifiers.
20177cb4d3eSLandon J. Fuller * @retval ENOMEM If the @p outp is non-NULL, and the provided @p olen
20277cb4d3eSLandon J. Fuller * is too small to hold the encoded value.
20377cb4d3eSLandon J. Fuller * @retval EFTYPE If value coercion from @p value to a single string
20477cb4d3eSLandon J. Fuller * value via @p fmt is unsupported.
20577cb4d3eSLandon J. Fuller * @retval ERANGE If value coercion of @p value would overflow (or
20677cb4d3eSLandon J. Fuller * underflow) the representation defined by @p fmt.
20777cb4d3eSLandon J. Fuller */
20877cb4d3eSLandon J. Fuller int
bhnd_nvram_val_vprintf(bhnd_nvram_val * value,const char * fmt,char * outp,size_t * olen,va_list ap)20958efe686SLandon J. Fuller bhnd_nvram_val_vprintf(bhnd_nvram_val *value, const char *fmt, char *outp,
21077cb4d3eSLandon J. Fuller size_t *olen, va_list ap)
21177cb4d3eSLandon J. Fuller {
21277cb4d3eSLandon J. Fuller const void *elem;
21377cb4d3eSLandon J. Fuller size_t elen;
21477cb4d3eSLandon J. Fuller size_t limit, nbytes;
21577cb4d3eSLandon J. Fuller int error;
21677cb4d3eSLandon J. Fuller
21777cb4d3eSLandon J. Fuller elem = NULL;
21877cb4d3eSLandon J. Fuller
21977cb4d3eSLandon J. Fuller /* Determine output byte limit */
22077cb4d3eSLandon J. Fuller nbytes = 0;
22177cb4d3eSLandon J. Fuller if (outp != NULL)
22277cb4d3eSLandon J. Fuller limit = *olen;
22377cb4d3eSLandon J. Fuller else
22477cb4d3eSLandon J. Fuller limit = 0;
22577cb4d3eSLandon J. Fuller
22677cb4d3eSLandon J. Fuller #define WRITE_CHAR(_c) do { \
22777cb4d3eSLandon J. Fuller if (limit > nbytes) \
22877cb4d3eSLandon J. Fuller *(outp + nbytes) = _c; \
22977cb4d3eSLandon J. Fuller \
23077cb4d3eSLandon J. Fuller if (nbytes == SIZE_MAX) \
23177cb4d3eSLandon J. Fuller return (EFTYPE); \
23277cb4d3eSLandon J. Fuller nbytes++; \
23377cb4d3eSLandon J. Fuller } while (0)
23477cb4d3eSLandon J. Fuller
23577cb4d3eSLandon J. Fuller /* Encode string value as per the format string */
23677cb4d3eSLandon J. Fuller for (const char *p = fmt; *p != '\0'; p++) {
23777cb4d3eSLandon J. Fuller const char *delim;
23877cb4d3eSLandon J. Fuller size_t precision, width, delim_len;
23977cb4d3eSLandon J. Fuller u_long repeat, bits;
24077cb4d3eSLandon J. Fuller bool alt_form, ladjust, have_precision;
24177cb4d3eSLandon J. Fuller char padc, signc, lenc;
24277cb4d3eSLandon J. Fuller
24377cb4d3eSLandon J. Fuller padc = ' ';
24477cb4d3eSLandon J. Fuller signc = '\0';
24577cb4d3eSLandon J. Fuller lenc = '\0';
24677cb4d3eSLandon J. Fuller delim = "";
24777cb4d3eSLandon J. Fuller delim_len = 0;
24877cb4d3eSLandon J. Fuller
24977cb4d3eSLandon J. Fuller ladjust = false;
25077cb4d3eSLandon J. Fuller alt_form = false;
25177cb4d3eSLandon J. Fuller
25277cb4d3eSLandon J. Fuller have_precision = false;
25377cb4d3eSLandon J. Fuller precision = 1;
25477cb4d3eSLandon J. Fuller bits = 32;
25577cb4d3eSLandon J. Fuller width = 0;
25677cb4d3eSLandon J. Fuller repeat = 1;
25777cb4d3eSLandon J. Fuller
25877cb4d3eSLandon J. Fuller /* Copy all input to output until we hit a format specifier */
25977cb4d3eSLandon J. Fuller if (*p != '%') {
26077cb4d3eSLandon J. Fuller WRITE_CHAR(*p);
26177cb4d3eSLandon J. Fuller continue;
26277cb4d3eSLandon J. Fuller }
26377cb4d3eSLandon J. Fuller
26477cb4d3eSLandon J. Fuller /* Hit '%' -- is this followed by an escaped '%' literal? */
26577cb4d3eSLandon J. Fuller p++;
26677cb4d3eSLandon J. Fuller if (*p == '%') {
26777cb4d3eSLandon J. Fuller WRITE_CHAR('%');
26877cb4d3eSLandon J. Fuller p++;
26977cb4d3eSLandon J. Fuller continue;
27077cb4d3eSLandon J. Fuller }
27177cb4d3eSLandon J. Fuller
27277cb4d3eSLandon J. Fuller /* Parse repeat specifier */
27377cb4d3eSLandon J. Fuller if (*p == '[') {
27477cb4d3eSLandon J. Fuller p++;
27577cb4d3eSLandon J. Fuller
27677cb4d3eSLandon J. Fuller /* Determine repeat count */
27777cb4d3eSLandon J. Fuller if (*p == ']') {
27877cb4d3eSLandon J. Fuller /* Repeat consumes all input */
27977cb4d3eSLandon J. Fuller repeat = bhnd_nvram_val_nelem(value);
28077cb4d3eSLandon J. Fuller } else if (*p == '*') {
28177cb4d3eSLandon J. Fuller /* Repeat is supplied as an argument */
28277cb4d3eSLandon J. Fuller repeat = va_arg(ap, size_t);
28377cb4d3eSLandon J. Fuller p++;
28477cb4d3eSLandon J. Fuller } else {
28577cb4d3eSLandon J. Fuller char *endp;
28677cb4d3eSLandon J. Fuller
28777cb4d3eSLandon J. Fuller /* Repeat specified as argument */
28877cb4d3eSLandon J. Fuller repeat = strtoul(p, &endp, 10);
28977cb4d3eSLandon J. Fuller if (p == endp) {
29077cb4d3eSLandon J. Fuller BHND_NV_LOG("error parsing repeat "
29177cb4d3eSLandon J. Fuller "count at '%s'", p);
29277cb4d3eSLandon J. Fuller return (EINVAL);
29377cb4d3eSLandon J. Fuller }
29477cb4d3eSLandon J. Fuller
29577cb4d3eSLandon J. Fuller /* Advance past repeat count */
29677cb4d3eSLandon J. Fuller p = endp;
29777cb4d3eSLandon J. Fuller }
29877cb4d3eSLandon J. Fuller
29977cb4d3eSLandon J. Fuller /* Advance past terminating ']' */
30077cb4d3eSLandon J. Fuller if (*p != ']') {
30177cb4d3eSLandon J. Fuller BHND_NV_LOG("error parsing repeat count at "
30277cb4d3eSLandon J. Fuller "'%s'", p);
30377cb4d3eSLandon J. Fuller return (EINVAL);
30477cb4d3eSLandon J. Fuller }
30577cb4d3eSLandon J. Fuller p++;
30677cb4d3eSLandon J. Fuller
30777cb4d3eSLandon J. Fuller delim = va_arg(ap, const char *);
30877cb4d3eSLandon J. Fuller delim_len = strlen(delim);
30977cb4d3eSLandon J. Fuller }
31077cb4d3eSLandon J. Fuller
31177cb4d3eSLandon J. Fuller /* Parse flags */
31277cb4d3eSLandon J. Fuller while (*p != '\0') {
31377cb4d3eSLandon J. Fuller const char *np;
31477cb4d3eSLandon J. Fuller bool stop;
31577cb4d3eSLandon J. Fuller
31677cb4d3eSLandon J. Fuller stop = false;
31777cb4d3eSLandon J. Fuller np = p+1;
31877cb4d3eSLandon J. Fuller
31977cb4d3eSLandon J. Fuller switch (*p) {
32077cb4d3eSLandon J. Fuller case '#':
32177cb4d3eSLandon J. Fuller alt_form = true;
32277cb4d3eSLandon J. Fuller break;
32377cb4d3eSLandon J. Fuller case '0':
32477cb4d3eSLandon J. Fuller padc = '0';
32577cb4d3eSLandon J. Fuller break;
32677cb4d3eSLandon J. Fuller case '-':
32777cb4d3eSLandon J. Fuller ladjust = true;
32877cb4d3eSLandon J. Fuller break;
32977cb4d3eSLandon J. Fuller case ' ':
33077cb4d3eSLandon J. Fuller /* Must not override '+' */
33177cb4d3eSLandon J. Fuller if (signc != '+')
33277cb4d3eSLandon J. Fuller signc = ' ';
33377cb4d3eSLandon J. Fuller break;
33477cb4d3eSLandon J. Fuller case '+':
33577cb4d3eSLandon J. Fuller signc = '+';
33677cb4d3eSLandon J. Fuller break;
33777cb4d3eSLandon J. Fuller default:
33877cb4d3eSLandon J. Fuller /* Non-flag character */
33977cb4d3eSLandon J. Fuller stop = true;
34077cb4d3eSLandon J. Fuller break;
34177cb4d3eSLandon J. Fuller }
34277cb4d3eSLandon J. Fuller
34377cb4d3eSLandon J. Fuller if (stop)
34477cb4d3eSLandon J. Fuller break;
34577cb4d3eSLandon J. Fuller else
34677cb4d3eSLandon J. Fuller p = np;
34777cb4d3eSLandon J. Fuller }
34877cb4d3eSLandon J. Fuller
34977cb4d3eSLandon J. Fuller /* Parse minimum width */
35077cb4d3eSLandon J. Fuller if (*p == '*') {
35177cb4d3eSLandon J. Fuller ssize_t arg;
35277cb4d3eSLandon J. Fuller
35377cb4d3eSLandon J. Fuller /* Width is supplied as an argument */
35477cb4d3eSLandon J. Fuller arg = va_arg(ap, int);
35577cb4d3eSLandon J. Fuller
35677cb4d3eSLandon J. Fuller /* Negative width argument is interpreted as
35777cb4d3eSLandon J. Fuller * '-' flag followed by positive width */
35877cb4d3eSLandon J. Fuller if (arg < 0) {
35977cb4d3eSLandon J. Fuller ladjust = true;
36077cb4d3eSLandon J. Fuller arg = -arg;
36177cb4d3eSLandon J. Fuller }
36277cb4d3eSLandon J. Fuller
36377cb4d3eSLandon J. Fuller width = arg;
36477cb4d3eSLandon J. Fuller p++;
36577cb4d3eSLandon J. Fuller } else if (bhnd_nv_isdigit(*p)) {
36677cb4d3eSLandon J. Fuller uint32_t v;
36777cb4d3eSLandon J. Fuller size_t len, parsed;
36877cb4d3eSLandon J. Fuller
36977cb4d3eSLandon J. Fuller /* Parse width value */
37077cb4d3eSLandon J. Fuller len = sizeof(v);
37177cb4d3eSLandon J. Fuller error = bhnd_nvram_parse_int(p, strlen(p), 10, &parsed,
37277cb4d3eSLandon J. Fuller &v, &len, BHND_NVRAM_TYPE_UINT32);
37377cb4d3eSLandon J. Fuller if (error) {
37477cb4d3eSLandon J. Fuller BHND_NV_LOG("error parsing width %s: %d\n", p,
37577cb4d3eSLandon J. Fuller error);
37677cb4d3eSLandon J. Fuller return (EINVAL);
37777cb4d3eSLandon J. Fuller }
37877cb4d3eSLandon J. Fuller
37977cb4d3eSLandon J. Fuller /* Save width and advance input */
38077cb4d3eSLandon J. Fuller width = v;
38177cb4d3eSLandon J. Fuller p += parsed;
38277cb4d3eSLandon J. Fuller }
38377cb4d3eSLandon J. Fuller
38477cb4d3eSLandon J. Fuller /* Parse precision */
38577cb4d3eSLandon J. Fuller if (*p == '.') {
38677cb4d3eSLandon J. Fuller uint32_t v;
38777cb4d3eSLandon J. Fuller size_t len, parsed;
38877cb4d3eSLandon J. Fuller
38977cb4d3eSLandon J. Fuller p++;
39077cb4d3eSLandon J. Fuller have_precision = true;
39177cb4d3eSLandon J. Fuller
39277cb4d3eSLandon J. Fuller if (*p == '*') {
39377cb4d3eSLandon J. Fuller ssize_t arg;
39477cb4d3eSLandon J. Fuller
39577cb4d3eSLandon J. Fuller /* Precision is specified as an argument */
39677cb4d3eSLandon J. Fuller arg = va_arg(ap, int);
39777cb4d3eSLandon J. Fuller
39877cb4d3eSLandon J. Fuller /* Negative precision argument is interpreted
39977cb4d3eSLandon J. Fuller * as '-' flag followed by positive
40077cb4d3eSLandon J. Fuller * precision */
40177cb4d3eSLandon J. Fuller if (arg < 0) {
40277cb4d3eSLandon J. Fuller ladjust = true;
40377cb4d3eSLandon J. Fuller arg = -arg;
40477cb4d3eSLandon J. Fuller }
40577cb4d3eSLandon J. Fuller
40677cb4d3eSLandon J. Fuller precision = arg;
40777cb4d3eSLandon J. Fuller } else if (!bhnd_nv_isdigit(*p)) {
40877cb4d3eSLandon J. Fuller /* Implicit precision of 0 */
40977cb4d3eSLandon J. Fuller precision = 0;
41077cb4d3eSLandon J. Fuller } else {
41177cb4d3eSLandon J. Fuller /* Parse precision value */
41277cb4d3eSLandon J. Fuller len = sizeof(v);
41377cb4d3eSLandon J. Fuller error = bhnd_nvram_parse_int(p, strlen(p), 10,
41477cb4d3eSLandon J. Fuller &parsed, &v, &len,
41577cb4d3eSLandon J. Fuller BHND_NVRAM_TYPE_UINT32);
41677cb4d3eSLandon J. Fuller if (error) {
41777cb4d3eSLandon J. Fuller BHND_NV_LOG("error parsing width %s: "
41877cb4d3eSLandon J. Fuller "%d\n", p, error);
41977cb4d3eSLandon J. Fuller return (EINVAL);
42077cb4d3eSLandon J. Fuller }
42177cb4d3eSLandon J. Fuller
42277cb4d3eSLandon J. Fuller /* Save precision and advance input */
42377cb4d3eSLandon J. Fuller precision = v;
42477cb4d3eSLandon J. Fuller p += parsed;
42577cb4d3eSLandon J. Fuller }
42677cb4d3eSLandon J. Fuller }
42777cb4d3eSLandon J. Fuller
42877cb4d3eSLandon J. Fuller /* Parse length modifiers */
42977cb4d3eSLandon J. Fuller while (*p != '\0') {
43077cb4d3eSLandon J. Fuller const char *np;
43177cb4d3eSLandon J. Fuller bool stop;
43277cb4d3eSLandon J. Fuller
43377cb4d3eSLandon J. Fuller stop = false;
43477cb4d3eSLandon J. Fuller np = p+1;
43577cb4d3eSLandon J. Fuller
43677cb4d3eSLandon J. Fuller switch (*p) {
43777cb4d3eSLandon J. Fuller case 'h':
43877cb4d3eSLandon J. Fuller if (lenc == '\0') {
43977cb4d3eSLandon J. Fuller /* Set initial length value */
44077cb4d3eSLandon J. Fuller lenc = *p;
44177cb4d3eSLandon J. Fuller bits = 16;
44277cb4d3eSLandon J. Fuller } else if (lenc == *p && bits == 16) {
44377cb4d3eSLandon J. Fuller /* Modify previous length value */
44477cb4d3eSLandon J. Fuller bits = 8;
44577cb4d3eSLandon J. Fuller } else {
44677cb4d3eSLandon J. Fuller BHND_NV_LOG("invalid length modifier "
44777cb4d3eSLandon J. Fuller "%c\n", *p);
44877cb4d3eSLandon J. Fuller return (EINVAL);
44977cb4d3eSLandon J. Fuller }
45077cb4d3eSLandon J. Fuller break;
45177cb4d3eSLandon J. Fuller
45277cb4d3eSLandon J. Fuller case 'l':
45377cb4d3eSLandon J. Fuller if (lenc == '\0') {
45477cb4d3eSLandon J. Fuller /* Set initial length value */
45577cb4d3eSLandon J. Fuller lenc = *p;
45677cb4d3eSLandon J. Fuller bits = 32;
45777cb4d3eSLandon J. Fuller } else if (lenc == *p && bits == 32) {
45877cb4d3eSLandon J. Fuller /* Modify previous length value */
45977cb4d3eSLandon J. Fuller bits = 64;
46077cb4d3eSLandon J. Fuller } else {
46177cb4d3eSLandon J. Fuller BHND_NV_LOG("invalid length modifier "
46277cb4d3eSLandon J. Fuller "%c\n", *p);
46377cb4d3eSLandon J. Fuller return (EINVAL);
46477cb4d3eSLandon J. Fuller }
46577cb4d3eSLandon J. Fuller break;
46677cb4d3eSLandon J. Fuller
46777cb4d3eSLandon J. Fuller case 'j':
46877cb4d3eSLandon J. Fuller /* Conflicts with all other length
46977cb4d3eSLandon J. Fuller * specifications, and may only occur once */
47077cb4d3eSLandon J. Fuller if (lenc != '\0') {
47177cb4d3eSLandon J. Fuller BHND_NV_LOG("invalid length modifier "
47277cb4d3eSLandon J. Fuller "%c\n", *p);
47377cb4d3eSLandon J. Fuller return (EINVAL);
47477cb4d3eSLandon J. Fuller }
47577cb4d3eSLandon J. Fuller
47677cb4d3eSLandon J. Fuller lenc = *p;
47777cb4d3eSLandon J. Fuller bits = 64;
47877cb4d3eSLandon J. Fuller break;
47977cb4d3eSLandon J. Fuller
48077cb4d3eSLandon J. Fuller case 'I': {
48177cb4d3eSLandon J. Fuller char *endp;
48277cb4d3eSLandon J. Fuller
48377cb4d3eSLandon J. Fuller /* Conflicts with all other length
48477cb4d3eSLandon J. Fuller * specifications, and may only occur once */
48577cb4d3eSLandon J. Fuller if (lenc != '\0') {
48677cb4d3eSLandon J. Fuller BHND_NV_LOG("invalid length modifier "
48777cb4d3eSLandon J. Fuller "%c\n", *p);
48877cb4d3eSLandon J. Fuller return (EINVAL);
48977cb4d3eSLandon J. Fuller }
49077cb4d3eSLandon J. Fuller
49177cb4d3eSLandon J. Fuller lenc = *p;
49277cb4d3eSLandon J. Fuller
49377cb4d3eSLandon J. Fuller /* Parse the length specifier value */
49477cb4d3eSLandon J. Fuller p++;
49577cb4d3eSLandon J. Fuller bits = strtoul(p, &endp, 10);
49677cb4d3eSLandon J. Fuller if (p == endp) {
49777cb4d3eSLandon J. Fuller BHND_NV_LOG("invalid size specifier: "
49877cb4d3eSLandon J. Fuller "%s\n", p);
49977cb4d3eSLandon J. Fuller return (EINVAL);
50077cb4d3eSLandon J. Fuller }
50177cb4d3eSLandon J. Fuller
50277cb4d3eSLandon J. Fuller /* Advance input past the parsed integer */
50377cb4d3eSLandon J. Fuller np = endp;
50477cb4d3eSLandon J. Fuller break;
50577cb4d3eSLandon J. Fuller }
50677cb4d3eSLandon J. Fuller default:
50777cb4d3eSLandon J. Fuller /* Non-length modifier character */
50877cb4d3eSLandon J. Fuller stop = true;
50977cb4d3eSLandon J. Fuller break;
51077cb4d3eSLandon J. Fuller }
51177cb4d3eSLandon J. Fuller
51277cb4d3eSLandon J. Fuller if (stop)
51377cb4d3eSLandon J. Fuller break;
51477cb4d3eSLandon J. Fuller else
51577cb4d3eSLandon J. Fuller p = np;
51677cb4d3eSLandon J. Fuller }
51777cb4d3eSLandon J. Fuller
51877cb4d3eSLandon J. Fuller /* Parse conversion specifier and format the value(s) */
51977cb4d3eSLandon J. Fuller for (u_long n = 0; n < repeat; n++) {
52077cb4d3eSLandon J. Fuller bhnd_nvram_type arg_type;
52177cb4d3eSLandon J. Fuller size_t arg_size;
52277cb4d3eSLandon J. Fuller size_t i;
52377cb4d3eSLandon J. Fuller u_long base;
52477cb4d3eSLandon J. Fuller bool is_signed, is_upper;
52577cb4d3eSLandon J. Fuller
52677cb4d3eSLandon J. Fuller is_signed = false;
52777cb4d3eSLandon J. Fuller is_upper = false;
52877cb4d3eSLandon J. Fuller base = 0;
52977cb4d3eSLandon J. Fuller
53077cb4d3eSLandon J. Fuller /* Fetch next element */
53177cb4d3eSLandon J. Fuller elem = bhnd_nvram_val_next(value, elem, &elen);
53277cb4d3eSLandon J. Fuller if (elem == NULL) {
53377cb4d3eSLandon J. Fuller BHND_NV_LOG("format string references more "
53477cb4d3eSLandon J. Fuller "than %zu available value elements\n",
53577cb4d3eSLandon J. Fuller bhnd_nvram_val_nelem(value));
53677cb4d3eSLandon J. Fuller return (EINVAL);
53777cb4d3eSLandon J. Fuller }
53877cb4d3eSLandon J. Fuller
53977cb4d3eSLandon J. Fuller /*
54077cb4d3eSLandon J. Fuller * If this is not the first value, append the delimiter.
54177cb4d3eSLandon J. Fuller */
54277cb4d3eSLandon J. Fuller if (n > 0) {
54377cb4d3eSLandon J. Fuller size_t nremain = 0;
54477cb4d3eSLandon J. Fuller if (limit > nbytes)
54577cb4d3eSLandon J. Fuller nremain = limit - nbytes;
54677cb4d3eSLandon J. Fuller
54777cb4d3eSLandon J. Fuller if (nremain >= delim_len)
54877cb4d3eSLandon J. Fuller memcpy(outp + nbytes, delim, delim_len);
54977cb4d3eSLandon J. Fuller
55077cb4d3eSLandon J. Fuller /* Add delimiter length to the total byte count */
55177cb4d3eSLandon J. Fuller if (SIZE_MAX - nbytes < delim_len)
55277cb4d3eSLandon J. Fuller return (EFTYPE); /* overflows size_t */
55377cb4d3eSLandon J. Fuller
55477cb4d3eSLandon J. Fuller nbytes += delim_len;
55577cb4d3eSLandon J. Fuller }
55677cb4d3eSLandon J. Fuller
55777cb4d3eSLandon J. Fuller /* Parse integer conversion specifiers */
55877cb4d3eSLandon J. Fuller switch (*p) {
55977cb4d3eSLandon J. Fuller case 'd':
56077cb4d3eSLandon J. Fuller case 'i':
56177cb4d3eSLandon J. Fuller base = 10;
56277cb4d3eSLandon J. Fuller is_signed = true;
56377cb4d3eSLandon J. Fuller break;
56477cb4d3eSLandon J. Fuller
56577cb4d3eSLandon J. Fuller case 'u':
56677cb4d3eSLandon J. Fuller base = 10;
56777cb4d3eSLandon J. Fuller break;
56877cb4d3eSLandon J. Fuller
56977cb4d3eSLandon J. Fuller case 'o':
57077cb4d3eSLandon J. Fuller base = 8;
57177cb4d3eSLandon J. Fuller break;
57277cb4d3eSLandon J. Fuller
57377cb4d3eSLandon J. Fuller case 'x':
57477cb4d3eSLandon J. Fuller base = 16;
57577cb4d3eSLandon J. Fuller break;
57677cb4d3eSLandon J. Fuller
57777cb4d3eSLandon J. Fuller case 'X':
57877cb4d3eSLandon J. Fuller base = 16;
57977cb4d3eSLandon J. Fuller is_upper = true;
58077cb4d3eSLandon J. Fuller break;
58177cb4d3eSLandon J. Fuller }
58277cb4d3eSLandon J. Fuller
58377cb4d3eSLandon J. Fuller /* Format argument */
58477cb4d3eSLandon J. Fuller switch (*p) {
58577cb4d3eSLandon J. Fuller #define NV_ENCODE_INT(_width) do { \
58677cb4d3eSLandon J. Fuller arg_type = (is_signed) ? BHND_NVRAM_TYPE_INT ## _width : \
58777cb4d3eSLandon J. Fuller BHND_NVRAM_TYPE_UINT ## _width; \
58877cb4d3eSLandon J. Fuller arg_size = sizeof(v.u ## _width); \
58977cb4d3eSLandon J. Fuller error = bhnd_nvram_val_encode_elem(value, elem, elen, \
59077cb4d3eSLandon J. Fuller &v.u ## _width, &arg_size, arg_type); \
59177cb4d3eSLandon J. Fuller if (error) { \
59277cb4d3eSLandon J. Fuller BHND_NV_LOG("error encoding argument as %s: %d\n", \
59377cb4d3eSLandon J. Fuller bhnd_nvram_type_name(arg_type), error); \
59477cb4d3eSLandon J. Fuller return (error); \
59577cb4d3eSLandon J. Fuller } \
59677cb4d3eSLandon J. Fuller \
59777cb4d3eSLandon J. Fuller if (is_signed) { \
59877cb4d3eSLandon J. Fuller if (v.i ## _width < 0) { \
59977cb4d3eSLandon J. Fuller add_neg = true; \
60077cb4d3eSLandon J. Fuller numval = (int64_t)-(v.i ## _width); \
60177cb4d3eSLandon J. Fuller } else { \
60277cb4d3eSLandon J. Fuller numval = (int64_t) (v.i ## _width); \
60377cb4d3eSLandon J. Fuller } \
60477cb4d3eSLandon J. Fuller } else { \
60577cb4d3eSLandon J. Fuller numval = v.u ## _width; \
60677cb4d3eSLandon J. Fuller } \
60777cb4d3eSLandon J. Fuller } while(0)
60877cb4d3eSLandon J. Fuller case 'd':
60977cb4d3eSLandon J. Fuller case 'i':
61077cb4d3eSLandon J. Fuller case 'u':
61177cb4d3eSLandon J. Fuller case 'o':
61277cb4d3eSLandon J. Fuller case 'x':
61377cb4d3eSLandon J. Fuller case 'X': {
61477cb4d3eSLandon J. Fuller char numbuf[NV_NUMSTR_MAX];
61577cb4d3eSLandon J. Fuller char *sptr;
61677cb4d3eSLandon J. Fuller uint64_t numval;
61777cb4d3eSLandon J. Fuller size_t slen;
61877cb4d3eSLandon J. Fuller bool add_neg;
61977cb4d3eSLandon J. Fuller union {
62077cb4d3eSLandon J. Fuller uint8_t u8;
62177cb4d3eSLandon J. Fuller uint16_t u16;
62277cb4d3eSLandon J. Fuller uint32_t u32;
62377cb4d3eSLandon J. Fuller uint64_t u64;
62477cb4d3eSLandon J. Fuller int8_t i8;
62577cb4d3eSLandon J. Fuller int16_t i16;
62677cb4d3eSLandon J. Fuller int32_t i32;
62777cb4d3eSLandon J. Fuller int64_t i64;
62877cb4d3eSLandon J. Fuller } v;
62977cb4d3eSLandon J. Fuller
63077cb4d3eSLandon J. Fuller add_neg = false;
63177cb4d3eSLandon J. Fuller
63277cb4d3eSLandon J. Fuller /* If precision is specified, it overrides
63377cb4d3eSLandon J. Fuller * (and behaves identically) to a zero-prefixed
63477cb4d3eSLandon J. Fuller * minimum width */
63577cb4d3eSLandon J. Fuller if (have_precision) {
63677cb4d3eSLandon J. Fuller padc = '0';
63777cb4d3eSLandon J. Fuller width = precision;
63877cb4d3eSLandon J. Fuller ladjust = false;
63977cb4d3eSLandon J. Fuller }
64077cb4d3eSLandon J. Fuller
64177cb4d3eSLandon J. Fuller /* If zero-padding is used, value must be right
64277cb4d3eSLandon J. Fuller * adjusted */
64377cb4d3eSLandon J. Fuller if (padc == '0')
64477cb4d3eSLandon J. Fuller ladjust = false;
64577cb4d3eSLandon J. Fuller
64677cb4d3eSLandon J. Fuller /* Request encode to the appropriate integer
64777cb4d3eSLandon J. Fuller * type, and then promote to common 64-bit
64877cb4d3eSLandon J. Fuller * representation */
64977cb4d3eSLandon J. Fuller switch (bits) {
65077cb4d3eSLandon J. Fuller case 8:
65177cb4d3eSLandon J. Fuller NV_ENCODE_INT(8);
65277cb4d3eSLandon J. Fuller break;
65377cb4d3eSLandon J. Fuller case 16:
65477cb4d3eSLandon J. Fuller NV_ENCODE_INT(16);
65577cb4d3eSLandon J. Fuller break;
65677cb4d3eSLandon J. Fuller case 32:
65777cb4d3eSLandon J. Fuller NV_ENCODE_INT(32);
65877cb4d3eSLandon J. Fuller break;
65977cb4d3eSLandon J. Fuller case 64:
66077cb4d3eSLandon J. Fuller NV_ENCODE_INT(64);
66177cb4d3eSLandon J. Fuller break;
66277cb4d3eSLandon J. Fuller default:
66377cb4d3eSLandon J. Fuller BHND_NV_LOG("invalid length specifier: "
66477cb4d3eSLandon J. Fuller "%lu\n", bits);
66577cb4d3eSLandon J. Fuller return (EINVAL);
66677cb4d3eSLandon J. Fuller }
66777cb4d3eSLandon J. Fuller #undef NV_ENCODE_INT
66877cb4d3eSLandon J. Fuller
66977cb4d3eSLandon J. Fuller /* If a precision of 0 is specified and the
67077cb4d3eSLandon J. Fuller * value is also zero, no characters should
67177cb4d3eSLandon J. Fuller * be produced */
67277cb4d3eSLandon J. Fuller if (have_precision && precision == 0 &&
67377cb4d3eSLandon J. Fuller numval == 0)
67477cb4d3eSLandon J. Fuller {
67577cb4d3eSLandon J. Fuller break;
67677cb4d3eSLandon J. Fuller }
67777cb4d3eSLandon J. Fuller
67877cb4d3eSLandon J. Fuller /* Emit string representation to local buffer */
67977cb4d3eSLandon J. Fuller BHND_NV_ASSERT(base <= 16, ("invalid base"));
68077cb4d3eSLandon J. Fuller sptr = numbuf + nitems(numbuf) - 1;
68177cb4d3eSLandon J. Fuller for (slen = 0; slen < sizeof(numbuf); slen++) {
68277cb4d3eSLandon J. Fuller char c;
68377cb4d3eSLandon J. Fuller uint64_t n;
68477cb4d3eSLandon J. Fuller
68577cb4d3eSLandon J. Fuller n = numval % base;
68677cb4d3eSLandon J. Fuller c = bhnd_nv_hex2ascii(n);
68777cb4d3eSLandon J. Fuller if (is_upper)
68877cb4d3eSLandon J. Fuller c = bhnd_nv_toupper(c);
68977cb4d3eSLandon J. Fuller
69077cb4d3eSLandon J. Fuller sptr--;
69177cb4d3eSLandon J. Fuller *sptr = c;
69277cb4d3eSLandon J. Fuller
69377cb4d3eSLandon J. Fuller numval /= (uint64_t)base;
69477cb4d3eSLandon J. Fuller if (numval == 0) {
69577cb4d3eSLandon J. Fuller slen++;
69677cb4d3eSLandon J. Fuller break;
69777cb4d3eSLandon J. Fuller }
69877cb4d3eSLandon J. Fuller }
69977cb4d3eSLandon J. Fuller
70077cb4d3eSLandon J. Fuller arg_size = slen;
70177cb4d3eSLandon J. Fuller
70277cb4d3eSLandon J. Fuller /* Reserve space for 0/0x prefix? */
70377cb4d3eSLandon J. Fuller if (alt_form) {
70477cb4d3eSLandon J. Fuller if (numval == 0) {
70577cb4d3eSLandon J. Fuller /* If 0, no prefix */
70677cb4d3eSLandon J. Fuller alt_form = false;
70777cb4d3eSLandon J. Fuller } else if (base == 8) {
70877cb4d3eSLandon J. Fuller arg_size += 1; /* 0 */
70977cb4d3eSLandon J. Fuller } else if (base == 16) {
71077cb4d3eSLandon J. Fuller arg_size += 2; /* 0x/0X */
71177cb4d3eSLandon J. Fuller }
71277cb4d3eSLandon J. Fuller }
71377cb4d3eSLandon J. Fuller
71477cb4d3eSLandon J. Fuller /* Reserve space for ' ', '+', or '-' prefix? */
71577cb4d3eSLandon J. Fuller if (add_neg || signc != '\0') {
71677cb4d3eSLandon J. Fuller if (add_neg)
71777cb4d3eSLandon J. Fuller signc = '-';
71877cb4d3eSLandon J. Fuller
71977cb4d3eSLandon J. Fuller arg_size++;
72077cb4d3eSLandon J. Fuller }
72177cb4d3eSLandon J. Fuller
72277cb4d3eSLandon J. Fuller /* Right adjust (if using spaces) */
72377cb4d3eSLandon J. Fuller if (!ladjust && padc != '0') {
72477cb4d3eSLandon J. Fuller for (i = arg_size; i < width; i++)
72577cb4d3eSLandon J. Fuller WRITE_CHAR(padc);
72677cb4d3eSLandon J. Fuller }
72777cb4d3eSLandon J. Fuller
72877cb4d3eSLandon J. Fuller if (signc != '\0')
72977cb4d3eSLandon J. Fuller WRITE_CHAR(signc);
73077cb4d3eSLandon J. Fuller
73177cb4d3eSLandon J. Fuller if (alt_form) {
73277cb4d3eSLandon J. Fuller if (base == 8) {
73377cb4d3eSLandon J. Fuller WRITE_CHAR('0');
73477cb4d3eSLandon J. Fuller } else if (base == 16) {
73577cb4d3eSLandon J. Fuller WRITE_CHAR('0');
73677cb4d3eSLandon J. Fuller if (is_upper)
73777cb4d3eSLandon J. Fuller WRITE_CHAR('X');
73877cb4d3eSLandon J. Fuller else
73977cb4d3eSLandon J. Fuller WRITE_CHAR('x');
74077cb4d3eSLandon J. Fuller }
74177cb4d3eSLandon J. Fuller }
74277cb4d3eSLandon J. Fuller
74377cb4d3eSLandon J. Fuller /* Right adjust (if using zeros) */
74477cb4d3eSLandon J. Fuller if (!ladjust && padc == '0') {
74577cb4d3eSLandon J. Fuller for (i = slen; i < width; i++)
74677cb4d3eSLandon J. Fuller WRITE_CHAR(padc);
74777cb4d3eSLandon J. Fuller }
74877cb4d3eSLandon J. Fuller
74977cb4d3eSLandon J. Fuller /* Write the string to our output buffer */
75077cb4d3eSLandon J. Fuller if (limit > nbytes && limit - nbytes >= slen)
75177cb4d3eSLandon J. Fuller memcpy(outp + nbytes, sptr, slen);
75277cb4d3eSLandon J. Fuller
75377cb4d3eSLandon J. Fuller /* Update the total byte count */
75477cb4d3eSLandon J. Fuller if (SIZE_MAX - nbytes < arg_size)
75577cb4d3eSLandon J. Fuller return (EFTYPE); /* overflows size_t */
75677cb4d3eSLandon J. Fuller
75777cb4d3eSLandon J. Fuller nbytes += arg_size;
75877cb4d3eSLandon J. Fuller
75977cb4d3eSLandon J. Fuller /* Left adjust */
76077cb4d3eSLandon J. Fuller for (i = arg_size; ladjust && i < width; i++)
76177cb4d3eSLandon J. Fuller WRITE_CHAR(padc);
76277cb4d3eSLandon J. Fuller
76377cb4d3eSLandon J. Fuller break;
76477cb4d3eSLandon J. Fuller }
76577cb4d3eSLandon J. Fuller
76677cb4d3eSLandon J. Fuller case 's': {
76777cb4d3eSLandon J. Fuller char *s;
76877cb4d3eSLandon J. Fuller size_t slen;
76977cb4d3eSLandon J. Fuller
77077cb4d3eSLandon J. Fuller /* Query the total length of the element when
77177cb4d3eSLandon J. Fuller * converted to a string */
77277cb4d3eSLandon J. Fuller arg_type = BHND_NVRAM_TYPE_STRING;
77377cb4d3eSLandon J. Fuller error = bhnd_nvram_val_encode_elem(value, elem,
77477cb4d3eSLandon J. Fuller elen, NULL, &arg_size, arg_type);
77577cb4d3eSLandon J. Fuller if (error) {
77677cb4d3eSLandon J. Fuller BHND_NV_LOG("error encoding argument "
77777cb4d3eSLandon J. Fuller "as %s: %d\n",
77877cb4d3eSLandon J. Fuller bhnd_nvram_type_name(arg_type),
77977cb4d3eSLandon J. Fuller error);
78077cb4d3eSLandon J. Fuller return (error);
78177cb4d3eSLandon J. Fuller }
78277cb4d3eSLandon J. Fuller
78377cb4d3eSLandon J. Fuller /* Do not include trailing NUL in the string
78477cb4d3eSLandon J. Fuller * length */
78577cb4d3eSLandon J. Fuller if (arg_size > 0)
78677cb4d3eSLandon J. Fuller arg_size--;
78777cb4d3eSLandon J. Fuller
78877cb4d3eSLandon J. Fuller /* Right adjust */
78977cb4d3eSLandon J. Fuller for (i = arg_size; !ladjust && i < width; i++)
79077cb4d3eSLandon J. Fuller WRITE_CHAR(padc);
79177cb4d3eSLandon J. Fuller
79277cb4d3eSLandon J. Fuller /* Determine output positition and remaining
79377cb4d3eSLandon J. Fuller * buffer space */
79477cb4d3eSLandon J. Fuller if (limit > nbytes) {
79577cb4d3eSLandon J. Fuller s = outp + nbytes;
79677cb4d3eSLandon J. Fuller slen = limit - nbytes;
79777cb4d3eSLandon J. Fuller } else {
79877cb4d3eSLandon J. Fuller s = NULL;
79977cb4d3eSLandon J. Fuller slen = 0;
80077cb4d3eSLandon J. Fuller }
80177cb4d3eSLandon J. Fuller
80277cb4d3eSLandon J. Fuller /* Encode the string to our output buffer */
80377cb4d3eSLandon J. Fuller error = bhnd_nvram_val_encode_elem(value, elem,
80477cb4d3eSLandon J. Fuller elen, s, &slen, arg_type);
80577cb4d3eSLandon J. Fuller if (error && error != ENOMEM) {
80677cb4d3eSLandon J. Fuller BHND_NV_LOG("error encoding argument "
80777cb4d3eSLandon J. Fuller "as %s: %d\n",
80877cb4d3eSLandon J. Fuller bhnd_nvram_type_name(arg_type),
80977cb4d3eSLandon J. Fuller error);
81077cb4d3eSLandon J. Fuller return (error);
81177cb4d3eSLandon J. Fuller }
81277cb4d3eSLandon J. Fuller
81377cb4d3eSLandon J. Fuller /* Update the total byte count */
81477cb4d3eSLandon J. Fuller if (SIZE_MAX - nbytes < arg_size)
81577cb4d3eSLandon J. Fuller return (EFTYPE); /* overflows size_t */
81677cb4d3eSLandon J. Fuller
81777cb4d3eSLandon J. Fuller nbytes += arg_size;
81877cb4d3eSLandon J. Fuller
81977cb4d3eSLandon J. Fuller /* Left adjust */
82077cb4d3eSLandon J. Fuller for (i = arg_size; ladjust && i < width; i++)
82177cb4d3eSLandon J. Fuller WRITE_CHAR(padc);
82277cb4d3eSLandon J. Fuller
82377cb4d3eSLandon J. Fuller break;
82477cb4d3eSLandon J. Fuller }
82577cb4d3eSLandon J. Fuller
82677cb4d3eSLandon J. Fuller case 'c': {
82777cb4d3eSLandon J. Fuller char c;
82877cb4d3eSLandon J. Fuller
82977cb4d3eSLandon J. Fuller arg_type = BHND_NVRAM_TYPE_CHAR;
8309be0790dSLandon J. Fuller arg_size = bhnd_nvram_type_width(arg_type);
83177cb4d3eSLandon J. Fuller
83277cb4d3eSLandon J. Fuller /* Encode as single character */
83377cb4d3eSLandon J. Fuller error = bhnd_nvram_val_encode_elem(value, elem,
83477cb4d3eSLandon J. Fuller elen, &c, &arg_size, arg_type);
83577cb4d3eSLandon J. Fuller if (error) {
83677cb4d3eSLandon J. Fuller BHND_NV_LOG("error encoding argument "
83777cb4d3eSLandon J. Fuller "as %s: %d\n",
83877cb4d3eSLandon J. Fuller bhnd_nvram_type_name(arg_type),
83977cb4d3eSLandon J. Fuller error);
84077cb4d3eSLandon J. Fuller return (error);
84177cb4d3eSLandon J. Fuller }
84277cb4d3eSLandon J. Fuller
84377cb4d3eSLandon J. Fuller BHND_NV_ASSERT(arg_size == sizeof(c),
84477cb4d3eSLandon J. Fuller ("invalid encoded size"));
84577cb4d3eSLandon J. Fuller
84677cb4d3eSLandon J. Fuller /* Right adjust */
84777cb4d3eSLandon J. Fuller for (i = arg_size; !ladjust && i < width; i++)
84877cb4d3eSLandon J. Fuller WRITE_CHAR(padc);
84977cb4d3eSLandon J. Fuller
85077cb4d3eSLandon J. Fuller WRITE_CHAR(padc);
85177cb4d3eSLandon J. Fuller
85277cb4d3eSLandon J. Fuller /* Left adjust */
85377cb4d3eSLandon J. Fuller for (i = arg_size; ladjust && i < width; i++)
85477cb4d3eSLandon J. Fuller WRITE_CHAR(padc);
85577cb4d3eSLandon J. Fuller
85677cb4d3eSLandon J. Fuller break;
85777cb4d3eSLandon J. Fuller }
85877cb4d3eSLandon J. Fuller }
85977cb4d3eSLandon J. Fuller }
86077cb4d3eSLandon J. Fuller }
86177cb4d3eSLandon J. Fuller
86277cb4d3eSLandon J. Fuller /* Append terminating NUL */
86377cb4d3eSLandon J. Fuller if (limit > nbytes)
86477cb4d3eSLandon J. Fuller *(outp + nbytes) = '\0';
86577cb4d3eSLandon J. Fuller
86677cb4d3eSLandon J. Fuller if (nbytes < SIZE_MAX)
86777cb4d3eSLandon J. Fuller nbytes++;
86877cb4d3eSLandon J. Fuller else
86977cb4d3eSLandon J. Fuller return (EFTYPE);
87077cb4d3eSLandon J. Fuller
87177cb4d3eSLandon J. Fuller /* Report required space */
87277cb4d3eSLandon J. Fuller *olen = nbytes;
87377cb4d3eSLandon J. Fuller if (limit < nbytes) {
87477cb4d3eSLandon J. Fuller if (outp != NULL)
87577cb4d3eSLandon J. Fuller return (ENOMEM);
87677cb4d3eSLandon J. Fuller }
87777cb4d3eSLandon J. Fuller
87877cb4d3eSLandon J. Fuller return (0);
87977cb4d3eSLandon J. Fuller }
880