The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/bhnd/nvram/bhnd_nvram_value_prf.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: d59b18dc63a4b959b87a5b53ebf89118


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.