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 
StrPrvPrintfEx_number(printf_write_c putc_,void * userData,uint64_t number,bool base10,bool zeroExtend,bool isSigned,uint32_t padToLength,bool caps,bool * bail)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 
StrVPrintf_StrLen_withMax(const char * s,uint32_t max)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 
StrVPrintf_StrLen(const char * s)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 
prvGetChar(const char ** fmtP)119 static inline char prvGetChar(const char** fmtP)
120 {
121 
122     return *(*fmtP)++;
123 }
124 
cvprintf(printf_write_c putc_f,void * userData,const char * fmtStr,va_list vl)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