1/* 2 * Copyright (C) 2001 MontaVista Software Inc. 3 * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License as published by the 7 * Free Software Foundation; either version 2 of the License, or (at your 8 * option) any later version. 9 * 10 */ 11 12#include "printf.h" 13 14extern void board_putc(int ch); 15 16/* this is the maximum width for a variable */ 17#define LP_MAX_BUF 256 18 19/* macros */ 20#define IsDigit(x) ( ((x) >= '0') && ((x) <= '9') ) 21#define Ctod(x) ( (x) - '0') 22 23/* forward declaration */ 24static int PrintChar(char *, char, int, int); 25static int PrintString(char *, char *, int, int); 26static int PrintNum(char *, unsigned long, int, int, int, int, char, int); 27 28/* private variable */ 29static const char theFatalMsg[] = "fatal error in lp_Print!"; 30 31/* -*- 32 * A low level printf() function. 33 */ 34static void 35lp_Print(void (*output)(void *, char *, int), 36 void * arg, 37 char *fmt, 38 va_list ap) 39{ 40 41#define OUTPUT(arg, s, l) \ 42 { if (((l) < 0) || ((l) > LP_MAX_BUF)) { \ 43 (*output)(arg, (char*)theFatalMsg, sizeof(theFatalMsg)-1); for(;;); \ 44 } else { \ 45 (*output)(arg, s, l); \ 46 } \ 47 } 48 49 char buf[LP_MAX_BUF]; 50 51 char c; 52 char *s; 53 long int num; 54 55 int longFlag; 56 int negFlag; 57 int width; 58 int prec; 59 int ladjust; 60 char padc; 61 62 int length; 63 64 for(;;) { 65 { 66 /* scan for the next '%' */ 67 char *fmtStart = fmt; 68 while ( (*fmt != '\0') && (*fmt != '%')) { 69 fmt ++; 70 } 71 72 /* flush the string found so far */ 73 OUTPUT(arg, fmtStart, fmt-fmtStart); 74 75 /* are we hitting the end? */ 76 if (*fmt == '\0') break; 77 } 78 79 /* we found a '%' */ 80 fmt ++; 81 82 /* check for long */ 83 if (*fmt == 'l') { 84 longFlag = 1; 85 fmt ++; 86 } else { 87 longFlag = 0; 88 } 89 90 /* check for other prefixes */ 91 width = 0; 92 prec = -1; 93 ladjust = 0; 94 padc = ' '; 95 96 if (*fmt == '-') { 97 ladjust = 1; 98 fmt ++; 99 } 100 101 if (*fmt == '0') { 102 padc = '0'; 103 fmt++; 104 } 105 106 if (IsDigit(*fmt)) { 107 while (IsDigit(*fmt)) { 108 width = 10 * width + Ctod(*fmt++); 109 } 110 } 111 112 if (*fmt == '.') { 113 fmt ++; 114 if (IsDigit(*fmt)) { 115 prec = 0; 116 while (IsDigit(*fmt)) { 117 prec = prec*10 + Ctod(*fmt++); 118 } 119 } 120 } 121 122 123 /* check format flag */ 124 negFlag = 0; 125 switch (*fmt) { 126 case 'b': 127 if (longFlag) { 128 num = va_arg(ap, long int); 129 } else { 130 num = va_arg(ap, int); 131 } 132 length = PrintNum(buf, num, 2, 0, width, ladjust, padc, 0); 133 OUTPUT(arg, buf, length); 134 break; 135 136 case 'd': 137 case 'D': 138 if (longFlag) { 139 num = va_arg(ap, long int); 140 } else { 141 num = va_arg(ap, int); 142 } 143 if (num < 0) { 144 num = - num; 145 negFlag = 1; 146 } 147 length = PrintNum(buf, num, 10, negFlag, width, ladjust, padc, 0); 148 OUTPUT(arg, buf, length); 149 break; 150 151 case 'o': 152 case 'O': 153 if (longFlag) { 154 num = va_arg(ap, long int); 155 } else { 156 num = va_arg(ap, int); 157 } 158 length = PrintNum(buf, num, 8, 0, width, ladjust, padc, 0); 159 OUTPUT(arg, buf, length); 160 break; 161 162 case 'u': 163 case 'U': 164 if (longFlag) { 165 num = va_arg(ap, long int); 166 } else { 167 num = va_arg(ap, int); 168 } 169 length = PrintNum(buf, num, 10, 0, width, ladjust, padc, 0); 170 OUTPUT(arg, buf, length); 171 break; 172 173 case 'x': 174 if (longFlag) { 175 num = va_arg(ap, long int); 176 } else { 177 num = va_arg(ap, int); 178 } 179 length = PrintNum(buf, num, 16, 0, width, ladjust, padc, 0); 180 OUTPUT(arg, buf, length); 181 break; 182 183 case 'X': 184 if (longFlag) { 185 num = va_arg(ap, long int); 186 } else { 187 num = va_arg(ap, int); 188 } 189 length = PrintNum(buf, num, 16, 0, width, ladjust, padc, 1); 190 OUTPUT(arg, buf, length); 191 break; 192 193 case 'c': 194 c = (char)va_arg(ap, int); 195 length = PrintChar(buf, c, width, ladjust); 196 OUTPUT(arg, buf, length); 197 break; 198 199 case 's': 200 s = (char*)va_arg(ap, char *); 201 length = PrintString(buf, s, width, ladjust); 202 OUTPUT(arg, buf, length); 203 break; 204 205 case '\0': 206 fmt --; 207 break; 208 209 default: 210 /* output this char as it is */ 211 OUTPUT(arg, fmt, 1); 212 } /* switch (*fmt) */ 213 214 fmt ++; 215 } /* for(;;) */ 216 217 /* special termination call */ 218 OUTPUT(arg, "\0", 1); 219} 220 221 222/* --------------- local help functions --------------------- */ 223static int 224PrintChar(char * buf, char c, int length, int ladjust) 225{ 226 int i; 227 228 if (length < 1) length = 1; 229 if (ladjust) { 230 *buf = c; 231 for (i=1; i< length; i++) buf[i] = ' '; 232 } else { 233 for (i=0; i< length-1; i++) buf[i] = ' '; 234 buf[length - 1] = c; 235 } 236 return length; 237} 238 239static int 240PrintString(char * buf, char* s, int length, int ladjust) 241{ 242 int i; 243 int len=0; 244 char* s1 = s; 245 while (*s1++) len++; 246 if (length < len) length = len; 247 248 if (ladjust) { 249 for (i=0; i< len; i++) buf[i] = s[i]; 250 for (i=len; i< length; i++) buf[i] = ' '; 251 } else { 252 for (i=0; i< length-len; i++) buf[i] = ' '; 253 for (i=length-len; i < length; i++) buf[i] = s[i-length+len]; 254 } 255 return length; 256} 257 258static int 259PrintNum(char * buf, unsigned long u, int base, int negFlag, 260 int length, int ladjust, char padc, int upcase) 261{ 262 /* algorithm : 263 * 1. prints the number from left to right in reverse form. 264 * 2. fill the remaining spaces with padc if length is longer than 265 * the actual length 266 * TRICKY : if left adjusted, no "0" padding. 267 * if negtive, insert "0" padding between "0" and number. 268 * 3. if (!ladjust) we reverse the whole string including paddings 269 * 4. otherwise we only reverse the actual string representing the num. 270 */ 271 272 int actualLength =0; 273 char *p = buf; 274 int i; 275 276 do { 277 int tmp = u %base; 278 if (tmp <= 9) { 279 *p++ = '0' + tmp; 280 } else if (upcase) { 281 *p++ = 'A' + tmp - 10; 282 } else { 283 *p++ = 'a' + tmp - 10; 284 } 285 u /= base; 286 } while (u != 0); 287 288 if (negFlag) { 289 *p++ = '-'; 290 } 291 292 /* figure out actual length and adjust the maximum length */ 293 actualLength = p - buf; 294 if (length < actualLength) length = actualLength; 295 296 /* add padding */ 297 if (ladjust) { 298 padc = ' '; 299 } 300 if (negFlag && !ladjust && (padc == '0')) { 301 for (i = actualLength-1; i< length-1; i++) buf[i] = padc; 302 buf[length -1] = '-'; 303 } else { 304 for (i = actualLength; i< length; i++) buf[i] = padc; 305 } 306 307 308 /* prepare to reverse the string */ 309 { 310 int begin = 0; 311 int end; 312 if (ladjust) { 313 end = actualLength - 1; 314 } else { 315 end = length -1; 316 } 317 318 while (end > begin) { 319 char tmp = buf[begin]; 320 buf[begin] = buf[end]; 321 buf[end] = tmp; 322 begin ++; 323 end --; 324 } 325 } 326 327 /* adjust the string pointer */ 328 return length; 329} 330 331static void printf_output(void *arg, char *s, int l) 332{ 333 int i; 334 335 // special termination call 336 if ((l==1) && (s[0] == '\0')) return; 337 338 for (i=0; i< l; i++) { 339 board_putc(s[i]); 340 if (s[i] == '\n') board_putc('\r'); 341 } 342} 343 344void printf(char *fmt, ...) 345{ 346 va_list ap; 347 va_start(ap, fmt); 348 lp_Print(printf_output, 0, fmt, ap); 349 va_end(ap); 350} 351