/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <stdio.h> #include <printf.h> #include <cpu/inc/cpuMath.h> static uint32_t StrPrvPrintfEx_number(printf_write_c putc_, void* userData, uint64_t number, bool base10, bool zeroExtend, bool isSigned, uint32_t padToLength, bool caps, bool* bail) { char buf[64]; uint32_t idx = sizeof(buf) - 1; uint32_t chr, i; bool neg = false; uint32_t numPrinted = 0; *bail = false; if (padToLength > sizeof(buf) - 1) padToLength = sizeof(buf) - 1; buf[idx--] = 0; //terminate if (isSigned) { if (((int64_t)number) < 0) { neg = true; number = -number; } } do{ if (base10) { uint64_t t = U64_DIV_BY_CONST_U16(number, 10); chr = (number - t * 10) + '0'; number = t; } else { chr = number & 0x0F; number >>= 4; chr = (chr >= 10) ? (chr + (caps ? 'A' : 'a') - 10) : (chr + '0'); } buf[idx--] = chr; numPrinted++; } while (number); if (neg) { buf[idx--] = '-'; numPrinted++; } if (padToLength > numPrinted) { padToLength -= numPrinted; } else { padToLength = 0; } while (padToLength--) { buf[idx--] = zeroExtend ? '0' : ' '; numPrinted++; } idx++; for(i = 0; i < numPrinted; i++) { if (!putc_(userData,(buf + idx)[i])) { *bail = true; break; } } return i; } static uint32_t StrVPrintf_StrLen_withMax(const char* s, uint32_t max) { uint32_t len = 0; while ((*s++) && (len < max)) len++; return len; } static uint32_t StrVPrintf_StrLen(const char* s) { uint32_t len = 0; while (*s++) len++; return len; } static inline char prvGetChar(const char** fmtP) { return *(*fmtP)++; } uint32_t cvprintf(printf_write_c putc_f, void* userData, const char* fmtStr, va_list vl) { char c, t; uint32_t numPrinted = 0; uint64_t val64; #define putc_(_ud,_c) \ do { \ if (!putc_f(_ud,_c)) \ goto out; \ } while(0) while ((c = prvGetChar(&fmtStr)) != 0) { if (c == '\n') { putc_(userData,c); numPrinted++; } else if (c == '%') { bool zeroExtend = false, useLong = false, useLongLong = false, useSizeT = false, bail = false, caps = false; uint32_t padToLength = 0, len, i; const char* str; more_fmt: c = prvGetChar(&fmtStr); switch(c) { case '%': putc_(userData,c); numPrinted++; break; case 'c': t = va_arg(vl,unsigned int); putc_(userData,t); numPrinted++; break; case 's': str = va_arg(vl,char*); if (!str) str = "(null)"; if (padToLength) len = StrVPrintf_StrLen_withMax(str,padToLength); else padToLength = len = StrVPrintf_StrLen(str); if (len > padToLength) len = padToLength; else { for(i = len; i < padToLength; i++) putc_(userData, ' '); } numPrinted += padToLength; for(i = 0; i < len; i++) putc_(userData,*str++); numPrinted += len; break; case '0': case '.': if (!zeroExtend && !padToLength) { zeroExtend = true; goto more_fmt; } case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': padToLength = (padToLength * 10) + c - '0'; goto more_fmt; #define GET_UVAL64() \ useSizeT ? va_arg(vl, size_t) : \ useLongLong ? va_arg(vl, unsigned long long) : \ useLong ? va_arg(vl, unsigned long) : \ va_arg(vl, unsigned int) #define GET_SVAL64() \ useSizeT ? va_arg(vl, size_t) : \ useLongLong ? va_arg(vl, signed long long) : \ useLong ? va_arg(vl, signed long) : \ va_arg(vl, signed int) case 'u': val64 = GET_UVAL64(); numPrinted += StrPrvPrintfEx_number(putc_f, userData, val64, true, zeroExtend,0,padToLength,0,&bail); if (bail) goto out; break; case 'd': case 'i': val64 = GET_SVAL64(); numPrinted += StrPrvPrintfEx_number(putc_f, userData, val64, true, zeroExtend, true, padToLength, false, &bail); if (bail) goto out; break; case 'X': caps = true; case 'x': val64 = GET_UVAL64(); numPrinted += StrPrvPrintfEx_number(putc_f, userData, val64, false, zeroExtend, false, padToLength, caps, &bail); if (bail) goto out; break; case 'p': putc_(userData,'0'); putc_(userData,'x'); numPrinted += 2; val64 = (uintptr_t)va_arg(vl, const void*); numPrinted += StrPrvPrintfEx_number(putc_f, userData, val64, false, zeroExtend, false, padToLength, caps, &bail); if (bail) goto out; break; #undef GET_UVAL64 #undef GET_SVAL64 case 'h': // Technically, we're supposed to cast down to short/char, so that // { int x = 256; printf("%hhd", x); } would yield "0" (assuming 32-bit int // and 8-bit char). But the more common usage would be to expect the caller // to do printf("%hhd", (char) x) to get this output, which we're assuming // here to make our implementation simpler. goto more_fmt; case 'L': case 'l': if (useLong) useLongLong = true; useLong = true; goto more_fmt; case 'z': useSizeT = true; goto more_fmt; default: putc_(userData,c); numPrinted++; break; } } else { putc_(userData,c); numPrinted++; } } out: return numPrinted; }