Home | History | Annotate | Download | only in src
      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