| /****************************************************************************** |
| * 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); |
| } |