1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 #include <stdarg.h> 41 #include <stdlib.h> 42 #include <limits.h> 43 extern short putoctal; 44 /* 45 * This version of printf is compatible with the Version 7 C 46 * printf. The differences are only minor except that 47 * viprintf assumes it is to print through putchar. Version 7 48 * printf is more general (and is much larger) and includes 49 * provisions for floating point. 50 */ 51 52 53 #define MAXOCT 11 /* Maximum octal digits in a long */ 54 #define MAXINT 32767 /* largest normal length positive integer */ 55 #define BIG 1000000000 /* largest power of 10 less than an unsigned long */ 56 #define MAXDIGS 10 /* number of digits in BIG */ 57 58 static int width, sign, fill; 59 60 unsigned char *_p_dconv(); 61 void _p_emit(unsigned char *, unsigned char *); 62 63 /*VARARGS*/ 64 void 65 viprintf(unsigned char *fmt, ...) 66 { 67 va_list ap; 68 unsigned char fcode; 69 wchar_t wfcode; 70 int prec; 71 int length,mask1,nbits,n; 72 int length2; 73 long int mask2, num; 74 unsigned char *bptr; 75 unsigned char *ptr; 76 unsigned char buf[134]; 77 78 va_start(ap, fmt); 79 for (;;) { 80 /* process format string first */ 81 for (;;) { 82 length2 = mbtowc(&wfcode, (char *)fmt, MB_LEN_MAX); 83 if(length2 <= 0) { 84 if (*fmt == '\0') { 85 fmt++; 86 return; 87 } 88 putchar(*fmt++); 89 } else { 90 if (wfcode == '%') { 91 fmt++; 92 break; 93 } 94 /* ordinary (non-%) character */ 95 putchar(wfcode); 96 fmt += length2; 97 } 98 } 99 /* length modifier: -1 for h, 1 for l, 0 for none */ 100 length = 0; 101 /* check for a leading - sign */ 102 sign = 0; 103 if (*fmt == '-') { 104 sign++; 105 fmt++; 106 } 107 /* a '0' may follow the - sign */ 108 /* this is the requested fill character */ 109 fill = 1; 110 if (*fmt == '0') { 111 fill--; 112 fmt++; 113 } 114 115 /* Now comes a digit string which may be a '*' */ 116 if (*fmt == '*') { 117 width = va_arg(ap, int); 118 if (width < 0) { 119 width = -width; 120 sign = !sign; 121 } 122 fmt++; 123 } 124 else { 125 width = 0; 126 while (*fmt>='0' && *fmt<='9') 127 width = width * 10 + (*fmt++ - '0'); 128 } 129 130 /* maybe a decimal point followed by more digits (or '*') */ 131 if (*fmt=='.') { 132 if (*++fmt == '*') { 133 prec = va_arg(ap, int); 134 fmt++; 135 } 136 else { 137 prec = 0; 138 while (*fmt>='0' && *fmt<='9') 139 prec = prec * 10 + (*fmt++ - '0'); 140 } 141 } 142 else 143 prec = -1; 144 145 /* 146 * At this point, "sign" is nonzero if there was 147 * a sign, "fill" is 0 if there was a leading 148 * zero and 1 otherwise, "width" and "prec" 149 * contain numbers corresponding to the digit 150 * strings before and after the decimal point, 151 * respectively, and "fmt" addresses the next 152 * character after the whole mess. If there was 153 * no decimal point, "prec" will be -1. 154 */ 155 switch (*fmt) { 156 case 'L': 157 case 'l': 158 length = 2; 159 /* FALLTHROUGH */ 160 case 'h': 161 case 'H': 162 length--; 163 fmt++; 164 break; 165 } 166 167 /* 168 * At exit from the following switch, we will 169 * emit the characters starting at "bptr" and 170 * ending at "ptr"-1, unless fcode is '\0'. 171 */ 172 switch (fcode = *fmt++) { 173 /* process characters and strings first */ 174 case 'c': 175 buf[0] = va_arg(ap, int); 176 ptr = bptr = &buf[0]; 177 if (buf[0] != '\0') 178 ptr++; 179 break; 180 case 's': 181 bptr = va_arg(ap,unsigned char *); 182 if (bptr==0) 183 bptr = (unsigned char *)"(null pointer)"; 184 if (prec < 0) 185 prec = MAXINT; 186 for (n=0; *bptr++ && n < prec; n++) ; 187 ptr = --bptr; 188 bptr -= n; 189 break; 190 case 'O': 191 length = 1; 192 fcode = 'o'; 193 /* FALLTHROUGH */ 194 case 'o': 195 case 'X': 196 case 'x': 197 if (length > 0) 198 num = va_arg(ap,long); 199 else 200 num = (unsigned)va_arg(ap,int); 201 if (fcode=='o') { 202 mask1 = 0x7; 203 mask2 = 0x1fffffffL; 204 nbits = 3; 205 } 206 else { 207 mask1 = 0xf; 208 mask2 = 0x0fffffffL; 209 nbits = 4; 210 } 211 n = (num!=0); 212 bptr = buf + MAXOCT + 3; 213 /* shift and mask for speed */ 214 do 215 if (((int) num & mask1) < 10) 216 *--bptr = ((int) num & mask1) + 060; 217 else 218 *--bptr = ((int) num & mask1) + 0127; 219 while (num = (num >> nbits) & mask2); 220 221 if (fcode=='o') { 222 if (n) 223 *--bptr = '0'; 224 } 225 else 226 if (!sign && fill <= 0) { 227 putchar('0'); 228 putchar(fcode); 229 width -= 2; 230 } 231 else { 232 *--bptr = fcode; 233 *--bptr = '0'; 234 } 235 ptr = buf + MAXOCT + 3; 236 break; 237 case 'D': 238 case 'U': 239 case 'I': 240 length = 1; 241 fcode = fcode + 'a' - 'A'; 242 /* FALLTHROUGH */ 243 case 'd': 244 case 'i': 245 case 'u': 246 if (length > 0) 247 num = va_arg(ap,long); 248 else { 249 n = va_arg(ap,int); 250 if (fcode=='u') 251 num = (unsigned) n; 252 else 253 num = (long) n; 254 } 255 if (n = (fcode != 'u' && num < 0)) 256 num = -num; 257 /* now convert to digits */ 258 bptr = _p_dconv(num, buf); 259 if (n) 260 *--bptr = '-'; 261 if (fill == 0) 262 fill = -1; 263 ptr = buf + MAXDIGS + 1; 264 break; 265 default: 266 /* not a control character, 267 * print it. 268 */ 269 ptr = bptr = &fcode; 270 ptr++; 271 break; 272 } 273 if (fcode != '\0') 274 _p_emit(bptr,ptr); 275 } 276 va_end(ap); 277 } 278 279 /* _p_dconv converts the unsigned long integer "value" to 280 * printable decimal and places it in "buffer", right-justified. 281 * The value returned is the address of the first non-zero character, 282 * or the address of the last character if all are zero. 283 * The result is NOT null terminated, and is MAXDIGS characters long, 284 * starting at buffer[1] (to allow for insertion of a sign). 285 * 286 * This program assumes it is running on 2's complement machine 287 * with reasonable overflow treatment. 288 */ 289 unsigned char * 290 _p_dconv(value, buffer) 291 long value; 292 unsigned char *buffer; 293 { 294 unsigned char *bp; 295 int svalue; 296 int n; 297 long lval; 298 299 bp = buffer; 300 301 /* zero is a special case */ 302 if (value == 0) { 303 bp += MAXDIGS; 304 *bp = '0'; 305 return(bp); 306 } 307 308 /* develop the leading digit of the value in "n" */ 309 n = 0; 310 while (value < 0) { 311 value -= BIG; /* will eventually underflow */ 312 n++; 313 } 314 while ((lval = value - BIG) >= 0) { 315 value = lval; 316 n++; 317 } 318 319 /* stash it in buffer[1] to allow for a sign */ 320 bp[1] = n + '0'; 321 /* 322 * Now develop the rest of the digits. Since speed counts here, 323 * we do it in two loops. The first gets "value" down until it 324 * is no larger than MAXINT. The second one uses integer divides 325 * rather than long divides to speed it up. 326 */ 327 bp += MAXDIGS + 1; 328 while (value > MAXINT) { 329 *--bp = (int)(value % 10) + '0'; 330 value /= 10; 331 } 332 333 /* cannot lose precision */ 334 svalue = value; 335 while (svalue > 0) { 336 *--bp = (svalue % 10) + '0'; 337 svalue /= 10; 338 } 339 340 /* fill in intermediate zeroes if needed */ 341 if (buffer[1] != '0') { 342 while (bp > buffer + 2) 343 *--bp = '0'; 344 --bp; 345 } 346 return(bp); 347 } 348 349 /* 350 * This program sends string "s" to putchar. The character after 351 * the end of "s" is given by "send". This allows the size of the 352 * field to be computed; it is stored in "alen". "width" contains the 353 * user specified length. If width<alen, the width will be taken to 354 * be alen. "sign" is zero if the string is to be right-justified 355 * in the field, nonzero if it is to be left-justified. "fill" is 356 * 0 if the string is to be padded with '0', positive if it is to be 357 * padded with ' ', and negative if an initial '-' should appear before 358 * any padding in right-justification (to avoid printing "-3" as 359 * "000-3" where "-0003" was intended). 360 */ 361 void 362 _p_emit(unsigned char *s, unsigned char *send) 363 { 364 unsigned char cfill; 365 int alen; 366 int npad, length; 367 wchar_t wchar; 368 369 alen = send - s; 370 if (alen > width) 371 width = alen; 372 cfill = fill>0? ' ': '0'; 373 374 /* we may want to print a leading '-' before anything */ 375 if (*s == '-' && fill < 0) { 376 putchar(*s++); 377 alen--; 378 width--; 379 } 380 npad = width - alen; 381 382 /* emit any leading pad characters */ 383 if (!sign) 384 while (--npad >= 0) 385 putchar(cfill); 386 387 /* emit the string itself */ 388 while (--alen >= 0) { 389 length = mbtowc(&wchar, (char *)s, MB_LEN_MAX); 390 if(length <= 0) { 391 putoctal = 1; 392 putchar((unsigned char)*s++); 393 putoctal = 0; 394 } else { 395 putchar(wchar); 396 s += length; 397 alen = alen - length + 1; 398 } 399 } 400 /* emit trailing pad characters */ 401 if (sign) 402 while (--npad >= 0) 403 putchar(cfill); 404 } 405