1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <stdio.h> 18 #include <printf.h> 19 #include <cpu/inc/cpuMath.h> 20 21 22 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) 23 { 24 char buf[64]; 25 uint32_t idx = sizeof(buf) - 1; 26 uint32_t chr, i; 27 bool neg = false; 28 uint32_t numPrinted = 0; 29 30 *bail = false; 31 32 if (padToLength > sizeof(buf) - 1) 33 padToLength = sizeof(buf) - 1; 34 35 buf[idx--] = 0; //terminate 36 37 if (isSigned) { 38 39 if (((int64_t)number) < 0) { 40 41 neg = true; 42 number = -number; 43 } 44 } 45 46 do{ 47 if (base10) { 48 uint64_t t = U64_DIV_BY_CONST_U16(number, 10); 49 chr = (number - t * 10) + '0'; 50 number = t; 51 } 52 else { 53 chr = number & 0x0F; 54 number >>= 4; 55 chr = (chr >= 10) ? (chr + (caps ? 'A' : 'a') - 10) : (chr + '0'); 56 } 57 58 buf[idx--] = chr; 59 60 numPrinted++; 61 62 } while (number); 63 64 if (neg) { 65 66 buf[idx--] = '-'; 67 numPrinted++; 68 } 69 70 if (padToLength > numPrinted) { 71 72 padToLength -= numPrinted; 73 } 74 else { 75 76 padToLength = 0; 77 } 78 79 while (padToLength--) { 80 81 buf[idx--] = zeroExtend ? '0' : ' '; 82 numPrinted++; 83 } 84 85 idx++; 86 87 88 for(i = 0; i < numPrinted; i++) { 89 90 if (!putc_(userData,(buf + idx)[i])) { 91 92 *bail = true; 93 break; 94 } 95 } 96 97 98 return i; 99 } 100 101 static uint32_t StrVPrintf_StrLen_withMax(const char* s, uint32_t max) 102 { 103 uint32_t len = 0; 104 105 while ((*s++) && (len < max)) len++; 106 107 return len; 108 } 109 110 static uint32_t StrVPrintf_StrLen(const char* s) 111 { 112 uint32_t len = 0; 113 114 while (*s++) len++; 115 116 return len; 117 } 118 119 static inline char prvGetChar(const char** fmtP) 120 { 121 122 return *(*fmtP)++; 123 } 124 125 uint32_t cvprintf(printf_write_c putc_f, void* userData, const char* fmtStr, va_list vl) 126 { 127 128 char c, t; 129 uint32_t numPrinted = 0; 130 uint64_t val64; 131 132 #define putc_(_ud,_c) \ 133 do { \ 134 if (!putc_f(_ud,_c)) \ 135 goto out; \ 136 } while(0) 137 138 while ((c = prvGetChar(&fmtStr)) != 0) { 139 140 if (c == '\n') { 141 142 putc_(userData,c); 143 numPrinted++; 144 } 145 else if (c == '%') { 146 147 bool zeroExtend = false, useLong = false, useLongLong = false, useSizeT = false, bail = false, caps = false; 148 uint32_t padToLength = 0, len, i; 149 const char* str; 150 151 more_fmt: 152 153 c = prvGetChar(&fmtStr); 154 155 switch(c) { 156 157 case '%': 158 159 putc_(userData,c); 160 numPrinted++; 161 break; 162 163 case 'c': 164 165 t = va_arg(vl,unsigned int); 166 putc_(userData,t); 167 numPrinted++; 168 break; 169 170 case 's': 171 172 str = va_arg(vl,char*); 173 if (!str) str = "(null)"; 174 if (padToLength) 175 len = StrVPrintf_StrLen_withMax(str,padToLength); 176 else 177 padToLength = len = StrVPrintf_StrLen(str); 178 179 if (len > padToLength) 180 len = padToLength; 181 else { 182 for(i = len; i < padToLength; i++) 183 putc_(userData, ' '); 184 } 185 numPrinted += padToLength; 186 for(i = 0; i < len; i++) 187 putc_(userData,*str++); 188 189 numPrinted += len; 190 break; 191 192 case '0': 193 case '.': 194 195 if (!zeroExtend && !padToLength) { 196 197 zeroExtend = true; 198 goto more_fmt; 199 } 200 201 case '1': 202 case '2': 203 case '3': 204 case '4': 205 case '5': 206 case '6': 207 case '7': 208 case '8': 209 case '9': 210 211 padToLength = (padToLength * 10) + c - '0'; 212 goto more_fmt; 213 214 #define GET_UVAL64() \ 215 useSizeT ? va_arg(vl, size_t) : \ 216 useLongLong ? va_arg(vl, unsigned long long) : \ 217 useLong ? va_arg(vl, unsigned long) : \ 218 va_arg(vl, unsigned int) 219 220 #define GET_SVAL64() \ 221 useSizeT ? va_arg(vl, size_t) : \ 222 useLongLong ? va_arg(vl, signed long long) : \ 223 useLong ? va_arg(vl, signed long) : \ 224 va_arg(vl, signed int) 225 226 case 'u': 227 228 val64 = GET_UVAL64(); 229 numPrinted += StrPrvPrintfEx_number(putc_f, userData, val64, true, zeroExtend,0,padToLength,0,&bail); 230 if (bail) 231 goto out; 232 break; 233 234 case 'd': 235 case 'i': 236 237 val64 = GET_SVAL64(); 238 numPrinted += StrPrvPrintfEx_number(putc_f, userData, val64, true, zeroExtend, true, padToLength, false, &bail); 239 if (bail) 240 goto out; 241 break; 242 243 case 'X': 244 caps = true; 245 246 case 'x': 247 248 val64 = GET_UVAL64(); 249 numPrinted += StrPrvPrintfEx_number(putc_f, userData, val64, false, zeroExtend, false, padToLength, caps, &bail); 250 if (bail) 251 goto out; 252 break; 253 254 case 'p': 255 putc_(userData,'0'); 256 putc_(userData,'x'); 257 numPrinted += 2; 258 val64 = (uintptr_t)va_arg(vl, const void*); 259 numPrinted += StrPrvPrintfEx_number(putc_f, userData, val64, false, zeroExtend, false, padToLength, caps, &bail); 260 if (bail) 261 goto out; 262 break; 263 264 #undef GET_UVAL64 265 #undef GET_SVAL64 266 267 case 'L': 268 case 'l': 269 if (useLong) 270 useLongLong = true; 271 useLong = true; 272 goto more_fmt; 273 274 case 'z': 275 useSizeT = true; 276 goto more_fmt; 277 278 default: 279 280 putc_(userData,c); 281 numPrinted++; 282 break; 283 284 } 285 } 286 else { 287 288 putc_(userData,c); 289 numPrinted++; 290 } 291 } 292 293 out: 294 295 return numPrinted; 296 } 297