/*
* Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "internal/numbers.h"
#include "internal/cryptlib.h"
#include <openssl/bio.h>
/*
* Copyright Patrick Powell 1995
* This code is based on code written by Patrick Powell <papowell@astart.com>
* It may be used for any purpose as long as this notice remains intact
* on all source code distributions.
*/
#ifdef HAVE_LONG_DOUBLE
# define LDOUBLE long double
#else
# define LDOUBLE double
#endif
static int fmtstr(char **, char **, size_t *, size_t *,
const char *, int, int, int);
static int fmtint(char **, char **, size_t *, size_t *,
int64_t, int, int, int, int);
static int fmtfp(char **, char **, size_t *, size_t *,
LDOUBLE, int, int, int, int);
static int doapr_outch(char **, char **, size_t *, size_t *, int);
static int _dopr(char **sbuffer, char **buffer,
size_t *maxlen, size_t *retlen, int *truncated,
const char *format, va_list args);
/* format read states */
#define DP_S_DEFAULT 0
#define DP_S_FLAGS 1
#define DP_S_MIN 2
#define DP_S_DOT 3
#define DP_S_MAX 4
#define DP_S_MOD 5
#define DP_S_CONV 6
#define DP_S_DONE 7
/* format flags - Bits */
/* left-aligned padding */
#define DP_F_MINUS (1 << 0)
/* print an explicit '+' for a value with positive sign */
#define DP_F_PLUS (1 << 1)
/* print an explicit ' ' for a value with positive sign */
#define DP_F_SPACE (1 << 2)
/* print 0/0x prefix for octal/hex and decimal point for floating point */
#define DP_F_NUM (1 << 3)
/* print leading zeroes */
#define DP_F_ZERO (1 << 4)
/* print HEX in UPPPERcase */
#define DP_F_UP (1 << 5)
/* treat value as unsigned */
#define DP_F_UNSIGNED (1 << 6)
/* conversion flags */
#define DP_C_SHORT 1
#define DP_C_LONG 2
#define DP_C_LDOUBLE 3
#define DP_C_LLONG 4
#define DP_C_SIZE 5
/* Floating point formats */
#define F_FORMAT 0
#define E_FORMAT 1
#define G_FORMAT 2
/* some handy macros */
#define char_to_int(p) (p - '0')
#define OSSL_MAX(p,q) ((p >= q) ? p : q)
static int
_dopr(char **sbuffer,
char **buffer,
size_t *maxlen,
size_t *retlen, int *truncated, const char *format, va_list args)
{
char ch;
int64_t value;
LDOUBLE fvalue;
char *strvalue;
int min;
int max;
int state;
int flags;
int cflags;
size_t currlen;
state = DP_S_DEFAULT;
flags = currlen = cflags = min = 0;
max = -1;
ch = *format++;
while (state != DP_S_DONE) {
if (ch == '\0' || (buffer == NULL && currlen >= *maxlen))
state = DP_S_DONE;
switch (state) {
case DP_S_DEFAULT:
if (ch == '%')
state = DP_S_FLAGS;
else
if(!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch))
return 0;
ch = *format++;
break;
case DP_S_FLAGS:
switch (ch) {
case '-':
flags |= DP_F_MINUS;
ch = *format++;
break;
case '+':
flags |= DP_F_PLUS;
ch = *format++;
break;
case ' ':
flags |= DP_F_SPACE;
ch = *format++;
break;
case '#':
flags |= DP_F_NUM;
ch = *format++;
break;
case '0':
flags |= DP_F_ZERO;
ch = *format++;
break;
default:
state = DP_S_MIN;
break;
}
break;
case DP_S_MIN:
if (isdigit((unsigned char)ch)) {
min = 10 * min + char_to_int(ch);
ch = *format++;
} else if (ch == '*') {
min = va_arg(args, int);
ch = *format++;
state = DP_S_DOT;
} else
state = DP_S_DOT;
break;
case DP_S_DOT:
if (ch == '.') {
state = DP_S_MAX;
ch =