Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/bhnd/nvram/bhnd_nvram_value_prf.c
39536 views
1
/*-
2
* Copyright (c) 2015-2016 Landon Fuller <[email protected]>
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer,
10
* without modification.
11
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
12
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13
* redistribution must be conditioned upon including a substantially
14
* similar Disclaimer requirement for further binary redistribution.
15
*
16
* NO WARRANTY
17
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27
* THE POSSIBILITY OF SUCH DAMAGES.
28
*/
29
30
#include <sys/param.h>
31
#include <sys/limits.h>
32
#include <sys/sbuf.h>
33
34
#ifdef _KERNEL
35
36
#include <sys/ctype.h>
37
#include <sys/kernel.h>
38
#include <sys/malloc.h>
39
#include <sys/systm.h>
40
41
#include <machine/_inttypes.h>
42
43
#else /* !_KERNEL */
44
45
#include <ctype.h>
46
#include <inttypes.h>
47
#include <errno.h>
48
#include <stdlib.h>
49
#include <string.h>
50
51
#endif /* _KERNEL */
52
53
#include "bhnd_nvram_private.h"
54
#include "bhnd_nvram_valuevar.h"
55
56
#ifdef _KERNEL
57
#define bhnd_nv_hex2ascii(hex) hex2ascii(hex)
58
#else /* !_KERNEL */
59
static char const bhnd_nv_hex2ascii[] = "0123456789abcdefghijklmnopqrstuvwxyz";
60
#define bhnd_nv_hex2ascii(hex) (bhnd_nv_hex2ascii[hex])
61
#endif /* _KERNEL */
62
63
/**
64
* Maximum size, in bytes, of a string-encoded NVRAM integer value, not
65
* including any prefix (0x, 0, etc).
66
*
67
* We assume the largest possible encoding is the base-2 representation
68
* of a 64-bit integer.
69
*/
70
#define NV_NUMSTR_MAX ((sizeof(uint64_t) * CHAR_BIT) + 1)
71
72
/**
73
* Format a string representation of @p value using @p fmt, with, writing the
74
* result to @p outp.
75
*
76
* @param value The value to be formatted.
77
* @param fmt The format string.
78
* @param[out] outp On success, the string will be written to this
79
* buffer. This argment may be NULL if the value is
80
* not desired.
81
* @param[in,out] olen The capacity of @p outp. On success, will be set
82
* to the actual number of bytes required for the
83
* requested string encoding (including a trailing
84
* NUL).
85
*
86
* Refer to bhnd_nvram_val_vprintf() for full format string documentation.
87
*
88
* @retval 0 success
89
* @retval EINVAL If @p fmt contains unrecognized format string
90
* specifiers.
91
* @retval ENOMEM If the @p outp is non-NULL, and the provided @p olen
92
* is too small to hold the encoded value.
93
* @retval EFTYPE If value coercion from @p value to a single string
94
* value via @p fmt is unsupported.
95
* @retval ERANGE If value coercion of @p value would overflow (or
96
* underflow) the representation defined by @p fmt.
97
*/
98
int
99
bhnd_nvram_val_printf(bhnd_nvram_val *value, const char *fmt, char *outp,
100
size_t *olen, ...)
101
{
102
va_list ap;
103
int error;
104
105
va_start(ap, olen);
106
error = bhnd_nvram_val_vprintf(value, fmt, outp, olen, ap);
107
va_end(ap);
108
109
return (error);
110
}
111
112
/**
113
* Format a string representation of the elements of @p value using @p fmt,
114
* writing the result to @p outp.
115
*
116
* @param value The value to be formatted.
117
* @param fmt The format string.
118
* @param[out] outp On success, the string will be written to this
119
* buffer. This argment may be NULL if the value is
120
* not desired.
121
* @param[in,out] olen The capacity of @p outp. On success, will be set
122
* to the actual number of bytes required for the
123
* requested string encoding (including a trailing
124
* NUL).
125
* @param ap Argument list.
126
*
127
* @par Format Strings
128
*
129
* Value format strings are similar, but not identical to, those used
130
* by printf(3).
131
*
132
* Format specifier format:
133
* %[repeat][flags][width][.precision][length modifier][specifier]
134
*
135
* The format specifier is interpreted as an encoding directive for an
136
* individual value element; each format specifier will fetch the next element
137
* from the value, encode the element as the appropriate type based on the
138
* length modifiers and specifier, and then format the result as a string.
139
*
140
* For example, given a string value of '0x000F', and a format specifier of
141
* '%#hhx', the value will be asked to encode its first element as
142
* BHND_NVRAM_TYPE_UINT8. String formatting will then be applied to the 8-bit
143
* unsigned integer representation, producing a string value of "0xF".
144
*
145
* Repeat:
146
* - [digits] Repeatedly apply the format specifier to the input
147
* value's elements up to `digits` times. The delimiter
148
* must be passed as a string in the next variadic
149
* argument.
150
* - [] Repeatedly apply the format specifier to the input
151
* value's elements until all elements have been. The
152
* processed. The delimiter must be passed as a string in
153
* the next variadic argument.
154
* - [*] Repeatedly apply the format specifier to the input
155
* value's elements. The repeat count is read from the
156
* next variadic argument as a size_t value
157
*
158
* Flags:
159
* - '#' use alternative form (e.g. 0x/0X prefixing of hex
160
* strings).
161
* - '0' zero padding
162
* - '-' left adjust padding
163
* - '+' include a sign character
164
* - ' ' include a space in place of a sign character for
165
* positive numbers.
166
*
167
* Width/Precision:
168
* - digits minimum field width.
169
* - * read the minimum field width from the next variadic
170
* argument as a ssize_t value. A negative value enables
171
* left adjustment.
172
* - .digits field precision.
173
* - .* read the field precision from the next variadic argument
174
* as a ssize_t value. A negative value enables left
175
* adjustment.
176
*
177
* Length Modifiers:
178
* - 'hh', 'I8' Convert the value to an 8-bit signed or unsigned
179
* integer.
180
* - 'h', 'I16' Convert the value to an 16-bit signed or unsigned
181
* integer.
182
* - 'l', 'I32' Convert the value to an 32-bit signed or unsigned
183
* integer.
184
* - 'll', 'j', 'I64' Convert the value to an 64-bit signed or unsigned
185
* integer.
186
*
187
* Data Specifiers:
188
* - 'd', 'i' Convert and format as a signed decimal integer.
189
* - 'u' Convert and format as an unsigned decimal integer.
190
* - 'o' Convert and format as an unsigned octal integer.
191
* - 'x' Convert and format as an unsigned hexadecimal integer,
192
* using lowercase hex digits.
193
* - 'X' Convert and format as an unsigned hexadecimal integer,
194
* using uppercase hex digits.
195
* - 's' Convert and format as a string.
196
* - '%' Print a literal '%' character.
197
*
198
* @retval 0 success
199
* @retval EINVAL If @p fmt contains unrecognized format string
200
* specifiers.
201
* @retval ENOMEM If the @p outp is non-NULL, and the provided @p olen
202
* is too small to hold the encoded value.
203
* @retval EFTYPE If value coercion from @p value to a single string
204
* value via @p fmt is unsupported.
205
* @retval ERANGE If value coercion of @p value would overflow (or
206
* underflow) the representation defined by @p fmt.
207
*/
208
int
209
bhnd_nvram_val_vprintf(bhnd_nvram_val *value, const char *fmt, char *outp,
210
size_t *olen, va_list ap)
211
{
212
const void *elem;
213
size_t elen;
214
size_t limit, nbytes;
215
int error;
216
217
elem = NULL;
218
219
/* Determine output byte limit */
220
nbytes = 0;
221
if (outp != NULL)
222
limit = *olen;
223
else
224
limit = 0;
225
226
#define WRITE_CHAR(_c) do { \
227
if (limit > nbytes) \
228
*(outp + nbytes) = _c; \
229
\
230
if (nbytes == SIZE_MAX) \
231
return (EFTYPE); \
232
nbytes++; \
233
} while (0)
234
235
/* Encode string value as per the format string */
236
for (const char *p = fmt; *p != '\0'; p++) {
237
const char *delim;
238
size_t precision, width, delim_len;
239
u_long repeat, bits;
240
bool alt_form, ladjust, have_precision;
241
char padc, signc, lenc;
242
243
padc = ' ';
244
signc = '\0';
245
lenc = '\0';
246
delim = "";
247
delim_len = 0;
248
249
ladjust = false;
250
alt_form = false;
251
252
have_precision = false;
253
precision = 1;
254
bits = 32;
255
width = 0;
256
repeat = 1;
257
258
/* Copy all input to output until we hit a format specifier */
259
if (*p != '%') {
260
WRITE_CHAR(*p);
261
continue;
262
}
263
264
/* Hit '%' -- is this followed by an escaped '%' literal? */
265
p++;
266
if (*p == '%') {
267
WRITE_CHAR('%');
268
p++;
269
continue;
270
}
271
272
/* Parse repeat specifier */
273
if (*p == '[') {
274
p++;
275
276
/* Determine repeat count */
277
if (*p == ']') {
278
/* Repeat consumes all input */
279
repeat = bhnd_nvram_val_nelem(value);
280
} else if (*p == '*') {
281
/* Repeat is supplied as an argument */
282
repeat = va_arg(ap, size_t);
283
p++;
284
} else {
285
char *endp;
286
287
/* Repeat specified as argument */
288
repeat = strtoul(p, &endp, 10);
289
if (p == endp) {
290
BHND_NV_LOG("error parsing repeat "
291
"count at '%s'", p);
292
return (EINVAL);
293
}
294
295
/* Advance past repeat count */
296
p = endp;
297
}
298
299
/* Advance past terminating ']' */
300
if (*p != ']') {
301
BHND_NV_LOG("error parsing repeat count at "
302
"'%s'", p);
303
return (EINVAL);
304
}
305
p++;
306
307
delim = va_arg(ap, const char *);
308
delim_len = strlen(delim);
309
}
310
311
/* Parse flags */
312
while (*p != '\0') {
313
const char *np;
314
bool stop;
315
316
stop = false;
317
np = p+1;
318
319
switch (*p) {
320
case '#':
321
alt_form = true;
322
break;
323
case '0':
324
padc = '0';
325
break;
326
case '-':
327
ladjust = true;
328
break;
329
case ' ':
330
/* Must not override '+' */
331
if (signc != '+')
332
signc = ' ';
333
break;
334
case '+':
335
signc = '+';
336
break;
337
default:
338
/* Non-flag character */
339
stop = true;
340
break;
341
}
342
343
if (stop)
344
break;
345
else
346
p = np;
347
}
348
349
/* Parse minimum width */
350
if (*p == '*') {
351
ssize_t arg;
352
353
/* Width is supplied as an argument */
354
arg = va_arg(ap, int);
355
356
/* Negative width argument is interpreted as
357
* '-' flag followed by positive width */
358
if (arg < 0) {
359
ladjust = true;
360
arg = -arg;
361
}
362
363
width = arg;
364
p++;
365
} else if (bhnd_nv_isdigit(*p)) {
366
uint32_t v;
367
size_t len, parsed;
368
369
/* Parse width value */
370
len = sizeof(v);
371
error = bhnd_nvram_parse_int(p, strlen(p), 10, &parsed,
372
&v, &len, BHND_NVRAM_TYPE_UINT32);
373
if (error) {
374
BHND_NV_LOG("error parsing width %s: %d\n", p,
375
error);
376
return (EINVAL);
377
}
378
379
/* Save width and advance input */
380
width = v;
381
p += parsed;
382
}
383
384
/* Parse precision */
385
if (*p == '.') {
386
uint32_t v;
387
size_t len, parsed;
388
389
p++;
390
have_precision = true;
391
392
if (*p == '*') {
393
ssize_t arg;
394
395
/* Precision is specified as an argument */
396
arg = va_arg(ap, int);
397
398
/* Negative precision argument is interpreted
399
* as '-' flag followed by positive
400
* precision */
401
if (arg < 0) {
402
ladjust = true;
403
arg = -arg;
404
}
405
406
precision = arg;
407
} else if (!bhnd_nv_isdigit(*p)) {
408
/* Implicit precision of 0 */
409
precision = 0;
410
} else {
411
/* Parse precision value */
412
len = sizeof(v);
413
error = bhnd_nvram_parse_int(p, strlen(p), 10,
414
&parsed, &v, &len,
415
BHND_NVRAM_TYPE_UINT32);
416
if (error) {
417
BHND_NV_LOG("error parsing width %s: "
418
"%d\n", p, error);
419
return (EINVAL);
420
}
421
422
/* Save precision and advance input */
423
precision = v;
424
p += parsed;
425
}
426
}
427
428
/* Parse length modifiers */
429
while (*p != '\0') {
430
const char *np;
431
bool stop;
432
433
stop = false;
434
np = p+1;
435
436
switch (*p) {
437
case 'h':
438
if (lenc == '\0') {
439
/* Set initial length value */
440
lenc = *p;
441
bits = 16;
442
} else if (lenc == *p && bits == 16) {
443
/* Modify previous length value */
444
bits = 8;
445
} else {
446
BHND_NV_LOG("invalid length modifier "
447
"%c\n", *p);
448
return (EINVAL);
449
}
450
break;
451
452
case 'l':
453
if (lenc == '\0') {
454
/* Set initial length value */
455
lenc = *p;
456
bits = 32;
457
} else if (lenc == *p && bits == 32) {
458
/* Modify previous length value */
459
bits = 64;
460
} else {
461
BHND_NV_LOG("invalid length modifier "
462
"%c\n", *p);
463
return (EINVAL);
464
}
465
break;
466
467
case 'j':
468
/* Conflicts with all other length
469
* specifications, and may only occur once */
470
if (lenc != '\0') {
471
BHND_NV_LOG("invalid length modifier "
472
"%c\n", *p);
473
return (EINVAL);
474
}
475
476
lenc = *p;
477
bits = 64;
478
break;
479
480
case 'I': {
481
char *endp;
482
483
/* Conflicts with all other length
484
* specifications, and may only occur once */
485
if (lenc != '\0') {
486
BHND_NV_LOG("invalid length modifier "
487
"%c\n", *p);
488
return (EINVAL);
489
}
490
491
lenc = *p;
492
493
/* Parse the length specifier value */
494
p++;
495
bits = strtoul(p, &endp, 10);
496
if (p == endp) {
497
BHND_NV_LOG("invalid size specifier: "
498
"%s\n", p);
499
return (EINVAL);
500
}
501
502
/* Advance input past the parsed integer */
503
np = endp;
504
break;
505
}
506
default:
507
/* Non-length modifier character */
508
stop = true;
509
break;
510
}
511
512
if (stop)
513
break;
514
else
515
p = np;
516
}
517
518
/* Parse conversion specifier and format the value(s) */
519
for (u_long n = 0; n < repeat; n++) {
520
bhnd_nvram_type arg_type;
521
size_t arg_size;
522
size_t i;
523
u_long base;
524
bool is_signed, is_upper;
525
526
is_signed = false;
527
is_upper = false;
528
base = 0;
529
530
/* Fetch next element */
531
elem = bhnd_nvram_val_next(value, elem, &elen);
532
if (elem == NULL) {
533
BHND_NV_LOG("format string references more "
534
"than %zu available value elements\n",
535
bhnd_nvram_val_nelem(value));
536
return (EINVAL);
537
}
538
539
/*
540
* If this is not the first value, append the delimiter.
541
*/
542
if (n > 0) {
543
size_t nremain = 0;
544
if (limit > nbytes)
545
nremain = limit - nbytes;
546
547
if (nremain >= delim_len)
548
memcpy(outp + nbytes, delim, delim_len);
549
550
/* Add delimiter length to the total byte count */
551
if (SIZE_MAX - nbytes < delim_len)
552
return (EFTYPE); /* overflows size_t */
553
554
nbytes += delim_len;
555
}
556
557
/* Parse integer conversion specifiers */
558
switch (*p) {
559
case 'd':
560
case 'i':
561
base = 10;
562
is_signed = true;
563
break;
564
565
case 'u':
566
base = 10;
567
break;
568
569
case 'o':
570
base = 8;
571
break;
572
573
case 'x':
574
base = 16;
575
break;
576
577
case 'X':
578
base = 16;
579
is_upper = true;
580
break;
581
}
582
583
/* Format argument */
584
switch (*p) {
585
#define NV_ENCODE_INT(_width) do { \
586
arg_type = (is_signed) ? BHND_NVRAM_TYPE_INT ## _width : \
587
BHND_NVRAM_TYPE_UINT ## _width; \
588
arg_size = sizeof(v.u ## _width); \
589
error = bhnd_nvram_val_encode_elem(value, elem, elen, \
590
&v.u ## _width, &arg_size, arg_type); \
591
if (error) { \
592
BHND_NV_LOG("error encoding argument as %s: %d\n", \
593
bhnd_nvram_type_name(arg_type), error); \
594
return (error); \
595
} \
596
\
597
if (is_signed) { \
598
if (v.i ## _width < 0) { \
599
add_neg = true; \
600
numval = (int64_t)-(v.i ## _width); \
601
} else { \
602
numval = (int64_t) (v.i ## _width); \
603
} \
604
} else { \
605
numval = v.u ## _width; \
606
} \
607
} while(0)
608
case 'd':
609
case 'i':
610
case 'u':
611
case 'o':
612
case 'x':
613
case 'X': {
614
char numbuf[NV_NUMSTR_MAX];
615
char *sptr;
616
uint64_t numval;
617
size_t slen;
618
bool add_neg;
619
union {
620
uint8_t u8;
621
uint16_t u16;
622
uint32_t u32;
623
uint64_t u64;
624
int8_t i8;
625
int16_t i16;
626
int32_t i32;
627
int64_t i64;
628
} v;
629
630
add_neg = false;
631
632
/* If precision is specified, it overrides
633
* (and behaves identically) to a zero-prefixed
634
* minimum width */
635
if (have_precision) {
636
padc = '0';
637
width = precision;
638
ladjust = false;
639
}
640
641
/* If zero-padding is used, value must be right
642
* adjusted */
643
if (padc == '0')
644
ladjust = false;
645
646
/* Request encode to the appropriate integer
647
* type, and then promote to common 64-bit
648
* representation */
649
switch (bits) {
650
case 8:
651
NV_ENCODE_INT(8);
652
break;
653
case 16:
654
NV_ENCODE_INT(16);
655
break;
656
case 32:
657
NV_ENCODE_INT(32);
658
break;
659
case 64:
660
NV_ENCODE_INT(64);
661
break;
662
default:
663
BHND_NV_LOG("invalid length specifier: "
664
"%lu\n", bits);
665
return (EINVAL);
666
}
667
#undef NV_ENCODE_INT
668
669
/* If a precision of 0 is specified and the
670
* value is also zero, no characters should
671
* be produced */
672
if (have_precision && precision == 0 &&
673
numval == 0)
674
{
675
break;
676
}
677
678
/* Emit string representation to local buffer */
679
BHND_NV_ASSERT(base <= 16, ("invalid base"));
680
sptr = numbuf + nitems(numbuf) - 1;
681
for (slen = 0; slen < sizeof(numbuf); slen++) {
682
char c;
683
uint64_t n;
684
685
n = numval % base;
686
c = bhnd_nv_hex2ascii(n);
687
if (is_upper)
688
c = bhnd_nv_toupper(c);
689
690
sptr--;
691
*sptr = c;
692
693
numval /= (uint64_t)base;
694
if (numval == 0) {
695
slen++;
696
break;
697
}
698
}
699
700
arg_size = slen;
701
702
/* Reserve space for 0/0x prefix? */
703
if (alt_form) {
704
if (numval == 0) {
705
/* If 0, no prefix */
706
alt_form = false;
707
} else if (base == 8) {
708
arg_size += 1; /* 0 */
709
} else if (base == 16) {
710
arg_size += 2; /* 0x/0X */
711
}
712
}
713
714
/* Reserve space for ' ', '+', or '-' prefix? */
715
if (add_neg || signc != '\0') {
716
if (add_neg)
717
signc = '-';
718
719
arg_size++;
720
}
721
722
/* Right adjust (if using spaces) */
723
if (!ladjust && padc != '0') {
724
for (i = arg_size; i < width; i++)
725
WRITE_CHAR(padc);
726
}
727
728
if (signc != '\0')
729
WRITE_CHAR(signc);
730
731
if (alt_form) {
732
if (base == 8) {
733
WRITE_CHAR('0');
734
} else if (base == 16) {
735
WRITE_CHAR('0');
736
if (is_upper)
737
WRITE_CHAR('X');
738
else
739
WRITE_CHAR('x');
740
}
741
}
742
743
/* Right adjust (if using zeros) */
744
if (!ladjust && padc == '0') {
745
for (i = slen; i < width; i++)
746
WRITE_CHAR(padc);
747
}
748
749
/* Write the string to our output buffer */
750
if (limit > nbytes && limit - nbytes >= slen)
751
memcpy(outp + nbytes, sptr, slen);
752
753
/* Update the total byte count */
754
if (SIZE_MAX - nbytes < arg_size)
755
return (EFTYPE); /* overflows size_t */
756
757
nbytes += arg_size;
758
759
/* Left adjust */
760
for (i = arg_size; ladjust && i < width; i++)
761
WRITE_CHAR(padc);
762
763
break;
764
}
765
766
case 's': {
767
char *s;
768
size_t slen;
769
770
/* Query the total length of the element when
771
* converted to a string */
772
arg_type = BHND_NVRAM_TYPE_STRING;
773
error = bhnd_nvram_val_encode_elem(value, elem,
774
elen, NULL, &arg_size, arg_type);
775
if (error) {
776
BHND_NV_LOG("error encoding argument "
777
"as %s: %d\n",
778
bhnd_nvram_type_name(arg_type),
779
error);
780
return (error);
781
}
782
783
/* Do not include trailing NUL in the string
784
* length */
785
if (arg_size > 0)
786
arg_size--;
787
788
/* Right adjust */
789
for (i = arg_size; !ladjust && i < width; i++)
790
WRITE_CHAR(padc);
791
792
/* Determine output positition and remaining
793
* buffer space */
794
if (limit > nbytes) {
795
s = outp + nbytes;
796
slen = limit - nbytes;
797
} else {
798
s = NULL;
799
slen = 0;
800
}
801
802
/* Encode the string to our output buffer */
803
error = bhnd_nvram_val_encode_elem(value, elem,
804
elen, s, &slen, arg_type);
805
if (error && error != ENOMEM) {
806
BHND_NV_LOG("error encoding argument "
807
"as %s: %d\n",
808
bhnd_nvram_type_name(arg_type),
809
error);
810
return (error);
811
}
812
813
/* Update the total byte count */
814
if (SIZE_MAX - nbytes < arg_size)
815
return (EFTYPE); /* overflows size_t */
816
817
nbytes += arg_size;
818
819
/* Left adjust */
820
for (i = arg_size; ladjust && i < width; i++)
821
WRITE_CHAR(padc);
822
823
break;
824
}
825
826
case 'c': {
827
char c;
828
829
arg_type = BHND_NVRAM_TYPE_CHAR;
830
arg_size = bhnd_nvram_type_width(arg_type);
831
832
/* Encode as single character */
833
error = bhnd_nvram_val_encode_elem(value, elem,
834
elen, &c, &arg_size, arg_type);
835
if (error) {
836
BHND_NV_LOG("error encoding argument "
837
"as %s: %d\n",
838
bhnd_nvram_type_name(arg_type),
839
error);
840
return (error);
841
}
842
843
BHND_NV_ASSERT(arg_size == sizeof(c),
844
("invalid encoded size"));
845
846
/* Right adjust */
847
for (i = arg_size; !ladjust && i < width; i++)
848
WRITE_CHAR(padc);
849
850
WRITE_CHAR(padc);
851
852
/* Left adjust */
853
for (i = arg_size; ladjust && i < width; i++)
854
WRITE_CHAR(padc);
855
856
break;
857
}
858
}
859
}
860
}
861
862
/* Append terminating NUL */
863
if (limit > nbytes)
864
*(outp + nbytes) = '\0';
865
866
if (nbytes < SIZE_MAX)
867
nbytes++;
868
else
869
return (EFTYPE);
870
871
/* Report required space */
872
*olen = nbytes;
873
if (limit < nbytes) {
874
if (outp != NULL)
875
return (ENOMEM);
876
}
877
878
return (0);
879
}
880
881