300 lines
6.3 KiB
C
300 lines
6.3 KiB
C
/******************************************************************************
|
|
* Copyright (c) 2004, 2008 IBM Corporation
|
|
* All rights reserved.
|
|
* This program and the accompanying materials
|
|
* are made available under the terms of the BSD License
|
|
* which accompanies this distribution, and is available at
|
|
* http://www.opensource.org/licenses/bsd-license.php
|
|
*
|
|
* Contributors:
|
|
* IBM Corporation - initial implementation
|
|
*****************************************************************************/
|
|
|
|
#include <stdbool.h>
|
|
#include <compiler.h>
|
|
#include "stdio.h"
|
|
#include "stdlib.h"
|
|
#include "string.h"
|
|
#include "ctype.h"
|
|
|
|
static const unsigned long long convert[] = {
|
|
0x0, 0xFF, 0xFFFF, 0xFFFFFF, 0xFFFFFFFF,
|
|
0xFFFFFFFFFFULL, 0xFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL
|
|
};
|
|
|
|
static int
|
|
print_str_fill(char **buffer, size_t bufsize, char *sizec,
|
|
const char *str, char c)
|
|
{
|
|
size_t i, sizei, len;
|
|
char *bstart = *buffer;
|
|
|
|
sizei = strtoul(sizec, NULL, 10);
|
|
len = strlen(str);
|
|
if (sizei > len) {
|
|
for (i = 0;
|
|
(i < (sizei - len)) && ((*buffer - bstart) < bufsize);
|
|
i++) {
|
|
**buffer = c;
|
|
*buffer += 1;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
print_str(char **buffer, size_t bufsize, const char *str)
|
|
{
|
|
char *bstart = *buffer;
|
|
size_t i;
|
|
|
|
for (i = 0; (i < strlen(str)) && ((*buffer - bstart) < bufsize); i++) {
|
|
**buffer = str[i];
|
|
*buffer += 1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static unsigned int __attrconst
|
|
print_intlen(unsigned long value, unsigned short int base)
|
|
{
|
|
int i = 0;
|
|
|
|
while (value > 0) {
|
|
value /= base;
|
|
i++;
|
|
}
|
|
if (i == 0)
|
|
i = 1;
|
|
return i;
|
|
}
|
|
|
|
static int
|
|
print_itoa(char **buffer, size_t bufsize, unsigned long value,
|
|
unsigned short base, bool upper)
|
|
{
|
|
const char zeichen[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
|
|
char c;
|
|
int i, len;
|
|
|
|
if(base <= 2 || base > 16)
|
|
return 0;
|
|
|
|
len = i = print_intlen(value, base);
|
|
|
|
/* Don't print to buffer if bufsize is not enough. */
|
|
if (len > bufsize)
|
|
return 0;
|
|
|
|
do {
|
|
c = zeichen[value % base];
|
|
if (upper)
|
|
c = toupper(c);
|
|
|
|
(*buffer)[--i] = c;
|
|
value /= base;
|
|
} while(value);
|
|
|
|
*buffer += len;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
print_fill(char **buffer, size_t bufsize, char *sizec, unsigned long size,
|
|
unsigned short int base, char c, int optlen)
|
|
{
|
|
int i, sizei, len;
|
|
char *bstart = *buffer;
|
|
|
|
sizei = strtoul(sizec, NULL, 10);
|
|
len = print_intlen(size, base) + optlen;
|
|
if (sizei > len) {
|
|
for (i = 0;
|
|
(i < (sizei - len)) && ((*buffer - bstart) < bufsize);
|
|
i++) {
|
|
**buffer = c;
|
|
*buffer += 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int
|
|
print_format(char **buffer, size_t bufsize, const char *format, void *var)
|
|
{
|
|
char *start;
|
|
unsigned int i = 0, length_mod = sizeof(int);
|
|
unsigned long value = 0;
|
|
unsigned long signBit;
|
|
char *form, sizec[32];
|
|
char sign = ' ';
|
|
bool upper = false;
|
|
|
|
form = (char *) format;
|
|
start = *buffer;
|
|
|
|
form++;
|
|
if(*form == '0' || *form == '.') {
|
|
sign = '0';
|
|
form++;
|
|
}
|
|
|
|
while ((*form != '\0') && ((*buffer - start) < bufsize)) {
|
|
switch(*form) {
|
|
case 'u':
|
|
case 'd':
|
|
case 'i':
|
|
sizec[i] = '\0';
|
|
value = (unsigned long) var;
|
|
signBit = 0x1ULL << (length_mod * 8 - 1);
|
|
if ((*form != 'u') && (signBit & value)) {
|
|
**buffer = '-';
|
|
*buffer += 1;
|
|
value = (-(unsigned long)value) & convert[length_mod];
|
|
}
|
|
print_fill(buffer, bufsize - (*buffer - start),
|
|
sizec, value, 10, sign, 0);
|
|
print_itoa(buffer, bufsize - (*buffer - start),
|
|
value, 10, upper);
|
|
break;
|
|
case 'X':
|
|
upper = true;
|
|
/* fallthrough */
|
|
case 'x':
|
|
sizec[i] = '\0';
|
|
value = (unsigned long) var & convert[length_mod];
|
|
print_fill(buffer, bufsize - (*buffer - start),
|
|
sizec, value, 16, sign, 0);
|
|
print_itoa(buffer, bufsize - (*buffer - start),
|
|
value, 16, upper);
|
|
break;
|
|
case 'O':
|
|
case 'o':
|
|
sizec[i] = '\0';
|
|
value = (long int) var & convert[length_mod];
|
|
print_fill(buffer, bufsize - (*buffer - start),
|
|
sizec, value, 8, sign, 0);
|
|
print_itoa(buffer, bufsize - (*buffer - start),
|
|
value, 8, upper);
|
|
break;
|
|
case 'p':
|
|
sizec[i] = '\0';
|
|
print_fill(buffer, bufsize - (*buffer - start),
|
|
sizec, (unsigned long) var, 16, ' ', 2);
|
|
print_str(buffer, bufsize - (*buffer - start),
|
|
"0x");
|
|
print_itoa(buffer, bufsize - (*buffer - start),
|
|
(unsigned long) var, 16, upper);
|
|
break;
|
|
case 'c':
|
|
sizec[i] = '\0';
|
|
print_fill(buffer, bufsize - (*buffer - start),
|
|
sizec, 1, 10, ' ', 0);
|
|
**buffer = (unsigned long) var;
|
|
*buffer += 1;
|
|
break;
|
|
case 's':
|
|
sizec[i] = '\0';
|
|
print_str_fill(buffer,
|
|
bufsize - (*buffer - start), sizec,
|
|
(char *) var, ' ');
|
|
|
|
print_str(buffer, bufsize - (*buffer - start),
|
|
(char *) var);
|
|
break;
|
|
case 'l':
|
|
form++;
|
|
if(*form == 'l') {
|
|
length_mod = sizeof(long long int);
|
|
} else {
|
|
form--;
|
|
length_mod = sizeof(long int);
|
|
}
|
|
break;
|
|
case 'h':
|
|
form++;
|
|
if(*form == 'h') {
|
|
length_mod = sizeof(signed char);
|
|
} else {
|
|
form--;
|
|
length_mod = sizeof(short int);
|
|
}
|
|
break;
|
|
case 'z':
|
|
length_mod = sizeof(size_t);
|
|
break;
|
|
default:
|
|
if(*form >= '0' && *form <= '9')
|
|
sizec[i++] = *form;
|
|
}
|
|
form++;
|
|
}
|
|
|
|
|
|
return (long int) (*buffer - start);
|
|
}
|
|
|
|
|
|
/*
|
|
* The vsnprintf function prints a formatted strings into a buffer.
|
|
* BUG: buffer size checking does not fully work yet
|
|
*/
|
|
int
|
|
vsnprintf(char *buffer, size_t bufsize, const char *format, va_list arg)
|
|
{
|
|
char *ptr, *bstart;
|
|
|
|
bstart = buffer;
|
|
ptr = (char *) format;
|
|
|
|
/*
|
|
* Return from here if size passed is zero, otherwise we would
|
|
* overrun buffer while setting NULL character at the end.
|
|
*/
|
|
if (!buffer || !bufsize)
|
|
return 0;
|
|
|
|
/* Leave one space for NULL character */
|
|
bufsize--;
|
|
|
|
while(*ptr != '\0' && (buffer - bstart) < bufsize)
|
|
{
|
|
if(*ptr == '%') {
|
|
char formstr[20];
|
|
int i=0;
|
|
|
|
do {
|
|
formstr[i] = *ptr;
|
|
ptr++;
|
|
i++;
|
|
} while(!(*ptr == 'd' || *ptr == 'i' || *ptr == 'u' || *ptr == 'x' || *ptr == 'X'
|
|
|| *ptr == 'p' || *ptr == 'c' || *ptr == 's' || *ptr == '%'
|
|
|| *ptr == 'O' || *ptr == 'o' ));
|
|
formstr[i++] = *ptr;
|
|
formstr[i] = '\0';
|
|
if(*ptr == '%') {
|
|
*buffer++ = '%';
|
|
} else {
|
|
print_format(&buffer,
|
|
bufsize - (buffer - bstart),
|
|
formstr, va_arg(arg, void *));
|
|
}
|
|
ptr++;
|
|
} else {
|
|
|
|
*buffer = *ptr;
|
|
|
|
buffer++;
|
|
ptr++;
|
|
}
|
|
}
|
|
|
|
*buffer = '\0';
|
|
|
|
return (buffer - bstart);
|
|
}
|