static int printf_string (STREAM *stream, struct printf_info *const pinfo, union printf_arg const *args) { int len = 0, count_or_errorcode = SNV_OK; const char *p = NULL; return_val_if_fail (pinfo != NULL, SNV_ERROR); /* Read these now to advance the argument pointer appropriately */ if (pinfo->prec == -1) pinfo->prec = 0; /* Check for valid pre-state. */ if (pinfo->prec <= -1 || pinfo->is_char || pinfo->is_short || pinfo->is_long || pinfo->is_long_double) { PRINTF_ERROR (pinfo, "invalid flags"); return -1; } /* Extract the correct argument from the arg vector. */ p = args->pa_string; /* Left pad to the width if the supplied argument is less than the width specifier. */ if (p != NULL) { len = strlen (p); if (pinfo->prec && pinfo->prec < len) len = pinfo->prec; } if ((len < pinfo->width) && !pinfo->left) { int padwidth = pinfo->width - len; while ((count_or_errorcode >= 0) && (count_or_errorcode < padwidth)) SNV_EMIT (pinfo->pad, stream, count_or_errorcode); } /* Fill the buffer with as many characters from the format argument as possible without overflowing or exceeding the precision. */ if ((count_or_errorcode >= 0) && (p != NULL)) { int mark = count_or_errorcode; while ((count_or_errorcode >= 0) && *p != '\0' && ((pinfo->prec == 0) || (count_or_errorcode - mark < len))) SNV_EMIT (*p++, stream, count_or_errorcode); } /* Right pad to the width if we still didn't reach the specified width and the left justify flag was set. */ if ((count_or_errorcode < pinfo->width) && pinfo->left) while ((count_or_errorcode >= 0) && (count_or_errorcode < pinfo->width)) SNV_EMIT (pinfo->pad, stream, count_or_errorcode); /* Return the number of characters emitted. */ return count_or_errorcode; }
static int printf_char (STREAM *stream, struct printf_info *const pinfo, union printf_arg const *args) { int count_or_errorcode = SNV_OK; char ch = '\0'; return_val_if_fail (pinfo != NULL, SNV_ERROR); /* Check for valid pre-state. */ if (pinfo->prec != -1 || pinfo->is_char || pinfo->is_short || pinfo->is_long || pinfo->is_long_double || pinfo->pad == '0' || pinfo->alt || pinfo->space || pinfo->showsign) { PRINTF_ERROR (pinfo, "invalid flags"); return -1; } /* Extract the correct argument from the arg vector. */ ch = args->pa_char; /* Left pad to the width if the supplied argument is less than the width specifier. */ if ((pinfo->width > 1) && !pinfo->left) { int padwidth = pinfo->width - 1; while ((count_or_errorcode >= 0) && (count_or_errorcode < padwidth)) SNV_EMIT (pinfo->pad, stream, count_or_errorcode); } /* Emit the character argument. */ SNV_EMIT (ch, stream, count_or_errorcode); /* Right pad to the width if we still didn't reach the specified width and the left justify flag was set. */ if ((count_or_errorcode < pinfo->width) && pinfo->left) while ((count_or_errorcode >= 0) && (count_or_errorcode < pinfo->width)) SNV_EMIT (pinfo->pad, stream, count_or_errorcode); /* Return the number of characters emitted. */ return count_or_errorcode; }
static int printf_pointer (STREAM *stream, struct printf_info *const pinfo, union printf_arg const *args) { int count_or_errorcode = SNV_OK; return_val_if_fail (pinfo != NULL, SNV_ERROR); /* Read these now to advance the argument pointer appropriately */ if (pinfo->prec == -1) pinfo->prec = 0; /* Check for valid pre-state. */ if (pinfo->prec <= -1 || pinfo->is_char || pinfo->is_short || pinfo->is_long || pinfo->is_long_double) { PRINTF_ERROR (pinfo, "invalid flags"); return -1; } /* Always print 0x. */ pinfo->alt = 1; pinfo->is_long = sizeof(long) == sizeof (char *); pinfo->is_long_double = sizeof(intmax_t) == sizeof (char *); /* Use the standard routine for numbers for the printing call, if the pointer is not NULL. */ if (args->pa_pointer != NULL) return printf_integer (stream, pinfo, args); /* Print a NULL pointer as (nil), appropriately padded. */ if ((pinfo->width > 5) && !pinfo->left) { int padwidth = pinfo->width - 5; while ((count_or_errorcode >= 0) && (count_or_errorcode < padwidth)) SNV_EMIT (pinfo->pad, stream, count_or_errorcode); } SNV_EMIT ('(', stream, count_or_errorcode); SNV_EMIT ('n', stream, count_or_errorcode); SNV_EMIT ('i', stream, count_or_errorcode); SNV_EMIT ('l', stream, count_or_errorcode); SNV_EMIT (')', stream, count_or_errorcode); if ((pinfo->width > 5) && pinfo->left) while ((count_or_errorcode >= 0) && (count_or_errorcode < pinfo->width)) SNV_EMIT (pinfo->pad, stream, count_or_errorcode); return count_or_errorcode; }
/** * printf_generic: * @stream: the stream (possibly a struct printfv_stream appropriately * cast) on which to write output. * @pinfo: the current state information for the format string parser. * @args: the pointer to the first argument to be read by the handler * * An example implementation of a %printf_function, used to provide easy * access to justification, width and precision options. * * Return value: * The number of characters output. **/ int printf_generic (STREAM *stream, struct printf_info *const pinfo, union printf_arg const *args) { int len = 0, count_or_errorcode = SNV_OK; char *p = NULL; /* Used to interface to the custom function. */ STREAM *out; Filament *fil; printf_function *user_func = (printf_function *) pinfo->extra; return_val_if_fail (pinfo != NULL, SNV_ERROR); /* Read these now to advance the argument pointer appropriately */ if (pinfo->prec == -1) pinfo->prec = 0; /* Check for valid pre-state. */ if (pinfo->prec <= -1) { PRINTF_ERROR (pinfo, "invalid flags"); return -1; } /* Print to a stream using a user-supplied function. */ fil = filnew (NULL, (size_t)0); out = stream_new (fil, SNV_UNLIMITED, NULL, snv_filputc); user_func (out, pinfo, args); stream_delete (out); len = (int)fillen (fil); p = fildelete (fil); /* Left pad to the width if the supplied argument is less than the width specifier. */ if (p != NULL && pinfo->prec && pinfo->prec < len) len = pinfo->prec; if ((len < pinfo->width) && !pinfo->left) { int padwidth = pinfo->width - len; while ((count_or_errorcode >= 0) && (count_or_errorcode < padwidth)) SNV_EMIT (pinfo->pad, stream, count_or_errorcode); } /* Fill the buffer with as many characters from the format argument * as possible without overflowing or exceeding the precision. */ if ((count_or_errorcode >= 0) && (p != NULL)) { int mark = count_or_errorcode; while ((count_or_errorcode >= 0) && *p != '\0' && ((pinfo->prec == 0) || (count_or_errorcode - mark < len))) SNV_EMIT (*p++, stream, count_or_errorcode); } /* Right pad to the width if we still didn't reach the specified * width and the left justify flag was set. */ if ((count_or_errorcode < pinfo->width) && pinfo->left) while ((count_or_errorcode >= 0) && (count_or_errorcode < pinfo->width)) SNV_EMIT (pinfo->pad, stream, count_or_errorcode); /* Return the number of characters emitted. */ return count_or_errorcode; }
static int printf_integer (STREAM *stream, struct printf_info *const pinfo, union printf_arg const *args) { static const char digits_lower[] = "0123456789abcdefghijklmnopqrstuvwxyz"; static const char digits_upper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; const char *digits; unsigned base = SNV_POINTER_TO_UINT (pinfo->extra); uintmax_t value = 0L; int type, count_or_errorcode = SNV_OK; char buffer[256], *p, *end; boolean is_negative = FALSE; return_val_if_fail (pinfo != NULL, SNV_ERROR); /* Check for valid pre-state. */ if (!(pinfo->state & (SNV_STATE_BEGIN | SNV_STATE_SPECIFIER))) { PRINTF_ERROR (pinfo, "out of range"); return -1; } /* Upper or lower-case hex conversion? */ digits = ((pinfo->spec >= 'a') && (pinfo->spec <= 'z')) ? digits_lower : digits_upper; if (pinfo->prec == -1) pinfo->prec = 0; /* Check for valid pre-state. */ if (pinfo->prec < 0) { PRINTF_ERROR (pinfo, "invalid precision"); return -1; } type = pinfo->type; /* Extract the correct argument from the arg vector. */ if (type & PA_FLAG_UNSIGNED) { value = fetch_uintmax (pinfo, args); is_negative = FALSE; pinfo->showsign = pinfo->space = FALSE; } else { intmax_t svalue = 0L; svalue = fetch_intmax (pinfo, args); is_negative = (svalue < 0); value = (uintmax_t) ABS (svalue); } /* Convert the number into a string. */ p = end = &buffer[sizeof (buffer) - 1]; if (value == 0) *p-- = '0'; else while (value > 0) { *p-- = digits[value % base]; value /= base; } pinfo->width -= end - p; pinfo->prec -= end - p; /* Octal numbers have a leading zero in alterate form. */ if (pinfo->alt && base == 8) { *p-- = '0'; --pinfo->width; } /* Left pad with zeros to make up the precision. */ if (pinfo->prec > 0) { pinfo->width -= pinfo->prec; while (pinfo->prec-- > 0) *p-- = '0'; } /* Reserve room for leading `0x' for hexadecimal. */ if (pinfo->alt && base == 16) pinfo->width -= 2; /* Reserve room for a sign character. */ if (is_negative || pinfo->showsign || pinfo->space) --pinfo->width; /* Left pad to the remaining width if the supplied argument is less * than the width specifier, and the padding character is ' '. */ if (pinfo->pad == ' ' && !pinfo->left) while ((count_or_errorcode >= 0) && (pinfo->width-- > 0)) SNV_EMIT (pinfo->pad, stream, count_or_errorcode); /* Display any sign character. */ if (count_or_errorcode >= 0) { if (is_negative) SNV_EMIT ('-', stream, count_or_errorcode); else if (pinfo->showsign) SNV_EMIT ('+', stream, count_or_errorcode); else if (pinfo->space) SNV_EMIT (' ', stream, count_or_errorcode); } /* Display `0x' for alternate hexadecimal specifier. */ if ((count_or_errorcode >= 0) && (base == 16) && pinfo->alt) { SNV_EMIT ('0', stream, count_or_errorcode); SNV_EMIT (digits['X' - 'A' + 10], stream, count_or_errorcode); } /* Left pad to the remaining width if the supplied argument is less * than the width specifier, and the padding character is not ' '. */ if (pinfo->pad != ' ' && !pinfo->left) while ((count_or_errorcode >= 0) && (pinfo->width-- > 0)) SNV_EMIT (pinfo->pad, stream, count_or_errorcode); /* Fill the stream buffer with as many characters from the number * buffer as possible without overflowing. */ while ((count_or_errorcode >= 0) && (++p < &buffer[sizeof (buffer)])) SNV_EMIT (*p, stream, count_or_errorcode); /* Right pad to the width if we still didn't reach the specified * width and the left justify flag was set. */ if (pinfo->left) while ((count_or_errorcode >= 0) && (pinfo->width-- > 0)) SNV_EMIT (pinfo->pad, stream, count_or_errorcode); /* Return the number of characters emitted. */ return count_or_errorcode; }
static int printf_float (STREAM *stream, struct printf_info *const pinfo, union printf_arg const *args) { snv_long_double value = 0.0; int sign, len, count_or_errorcode = SNV_OK; #ifdef HAVE_LONG_DOUBLE char buffer[LDBL_MAX_10_EXP * 2 + 20], *p = buffer; #else char buffer[DBL_MAX_10_EXP * 2 + 20], *p = buffer; #endif return_val_if_fail (pinfo != NULL, SNV_ERROR); /* Check for valid pre-state */ if (pinfo->prec == -1) pinfo->prec = SNV_POINTER_TO_INT (pinfo->extra); /* Check for valid pre-state. */ if (pinfo->prec <= -1 || pinfo->is_char || pinfo->is_short || pinfo->is_long) { PRINTF_ERROR (pinfo, "invalid flags"); return -1; } /* Extract the correct argument from the arg vector. */ value = fetch_double (pinfo, args); /* Convert the number into a string. */ len = print_float (pinfo, buffer, buffer + sizeof (buffer), &sign, value); if (*buffer == '0') p++, len--; /* Compute the size of the padding. */ pinfo->width -= len; if (sign) pinfo->width--; /* Left pad to the remaining width if the supplied argument is less than the width specifier, and the padding character is ' '. */ if (pinfo->pad == ' ' && !pinfo->left) while ((count_or_errorcode >= 0) && (pinfo->width-- > 0)) SNV_EMIT (pinfo->pad, stream, count_or_errorcode); /* Display any sign character. */ if (count_or_errorcode >= 0 && sign) SNV_EMIT (sign, stream, count_or_errorcode); /* Left pad to the remaining width if the supplied argument is less than the width specifier, and the padding character is not ' '. */ if (pinfo->pad != ' ' && !pinfo->left) while ((count_or_errorcode >= 0) && (pinfo->width-- > 0)) SNV_EMIT (pinfo->pad, stream, count_or_errorcode); /* Fill the stream buffer with as many characters from the number buffer as possible without overflowing. */ while ((count_or_errorcode >= 0) && (len-- > 0)) SNV_EMIT (*p++, stream, count_or_errorcode); /* Right pad to the width if we still didn't reach the specified width and the left justify flag was set. */ if (pinfo->left) while ((count_or_errorcode >= 0) && (pinfo->width-- > 0)) SNV_EMIT (pinfo->pad, stream, count_or_errorcode); /* Return the number of characters emitted. */ return count_or_errorcode; }