123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- /*
- * Copyright (C) 2001 MontaVista Software Inc.
- * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
- #include "print.h"
- /* macros */
- #define IsDigit(x) ( ((x) >= '0') && ((x) <= '9') )
- #define Ctod(x) ( (x) - '0')
- /* forward declaration */
- extern int PrintChar(char *, char, int, int);
- extern int PrintString(char *, char *, int, int);
- extern int PrintNum(char *, unsigned long, int, int, int, int, char, int);
- /* private variable */
- static const char theFatalMsg[] = "fatal error in lp_Print!";
- /* -*-
- * A low level printf() function.
- */
- void
- lp_Print(void (*output)(void *, char *, int),
- void * arg,
- char *fmt,
- va_list ap)
- {
- #define OUTPUT(arg, s, l) \
- { if (((l) < 0) || ((l) > LP_MAX_BUF)) { \
- (*output)(arg, (char*)theFatalMsg, sizeof(theFatalMsg)-1); for(;;); \
- } else { \
- (*output)(arg, s, l); \
- } \
- }
-
- char buf[LP_MAX_BUF];
- char c;
- char *s;
- long int num;
- int longFlag;
- int negFlag;
- int width;
- int prec;
- int ladjust;
- char padc;
- int length;
- for(;;) {
- {
- /* scan for the next '%' */
- char *fmtStart = fmt;
- while ( (*fmt != '\0') && (*fmt != '%')) {
- fmt ++;
- }
- /* flush the string found so far */
- OUTPUT(arg, fmtStart, fmt-fmtStart);
- /* are we hitting the end? */
- if (*fmt == '\0') break;
- }
- /* we found a '%' */
- fmt ++;
-
- /* check for long */
- if (*fmt == 'l') {
- longFlag = 1;
- fmt ++;
- } else {
- longFlag = 0;
- }
- /* check for other prefixes */
- width = 0;
- prec = -1;
- ladjust = 0;
- padc = ' ';
- if (*fmt == '-') {
- ladjust = 1;
- fmt ++;
- }
- if (*fmt == '0') {
- padc = '0';
- fmt++;
- }
- if (IsDigit(*fmt)) {
- while (IsDigit(*fmt)) {
- width = 10 * width + Ctod(*fmt++);
- }
- }
- if (*fmt == '.') {
- fmt ++;
- if (IsDigit(*fmt)) {
- prec = 0;
- while (IsDigit(*fmt)) {
- prec = prec*10 + Ctod(*fmt++);
- }
- }
- }
- /* check format flag */
- negFlag = 0;
- switch (*fmt) {
- case 'b':
- if (longFlag) {
- num = va_arg(ap, long int);
- } else {
- num = va_arg(ap, int);
- }
- length = PrintNum(buf, num, 2, 0, width, ladjust, padc, 0);
- OUTPUT(arg, buf, length);
- break;
- case 'd':
- case 'D':
- if (longFlag) {
- num = va_arg(ap, long int);
- } else {
- num = va_arg(ap, int);
- }
- if (num < 0) {
- num = - num;
- negFlag = 1;
- }
- length = PrintNum(buf, num, 10, negFlag, width, ladjust, padc, 0);
- OUTPUT(arg, buf, length);
- break;
- case 'o':
- case 'O':
- if (longFlag) {
- num = va_arg(ap, long int);
- } else {
- num = va_arg(ap, int);
- }
- length = PrintNum(buf, num, 8, 0, width, ladjust, padc, 0);
- OUTPUT(arg, buf, length);
- break;
- case 'u':
- case 'U':
- if (longFlag) {
- num = va_arg(ap, long int);
- } else {
- num = va_arg(ap, int);
- }
- length = PrintNum(buf, num, 10, 0, width, ladjust, padc, 0);
- OUTPUT(arg, buf, length);
- break;
-
- case 'x':
- if (longFlag) {
- num = va_arg(ap, long int);
- } else {
- num = va_arg(ap, int);
- }
- length = PrintNum(buf, num, 16, 0, width, ladjust, padc, 0);
- OUTPUT(arg, buf, length);
- break;
- case 'X':
- if (longFlag) {
- num = va_arg(ap, long int);
- } else {
- num = va_arg(ap, int);
- }
- length = PrintNum(buf, num, 16, 0, width, ladjust, padc, 1);
- OUTPUT(arg, buf, length);
- break;
- case 'c':
- c = (char)va_arg(ap, int);
- length = PrintChar(buf, c, width, ladjust);
- OUTPUT(arg, buf, length);
- break;
- case 's':
- s = (char*)va_arg(ap, char *);
- length = PrintString(buf, s, width, ladjust);
- OUTPUT(arg, buf, length);
- break;
- case '\0':
- fmt --;
- break;
- default:
- /* output this char as it is */
- OUTPUT(arg, fmt, 1);
- } /* switch (*fmt) */
- fmt ++;
- } /* for(;;) */
- /* special termination call */
- OUTPUT(arg, "\0", 1);
- }
- /* --------------- local help functions --------------------- */
- int
- PrintChar(char * buf, char c, int length, int ladjust)
- {
- int i;
-
- if (length < 1) length = 1;
- if (ladjust) {
- *buf = c;
- for (i=1; i< length; i++) buf[i] = ' ';
- } else {
- for (i=0; i< length-1; i++) buf[i] = ' ';
- buf[length - 1] = c;
- }
- return length;
- }
- int
- PrintString(char * buf, char* s, int length, int ladjust)
- {
- int i;
- int len=0;
- char* s1 = s;
- while (*s1++) len++;
- if (length < len) length = len;
- if (ladjust) {
- for (i=0; i< len; i++) buf[i] = s[i];
- for (i=len; i< length; i++) buf[i] = ' ';
- } else {
- for (i=0; i< length-len; i++) buf[i] = ' ';
- for (i=length-len; i < length; i++) buf[i] = s[i-length+len];
- }
- return length;
- }
- int
- PrintNum(char * buf, unsigned long u, int base, int negFlag,
- int length, int ladjust, char padc, int upcase)
- {
- /* algorithm :
- * 1. prints the number from left to right in reverse form.
- * 2. fill the remaining spaces with padc if length is longer than
- * the actual length
- * TRICKY : if left adjusted, no "0" padding.
- * if negtive, insert "0" padding between "0" and number.
- * 3. if (!ladjust) we reverse the whole string including paddings
- * 4. otherwise we only reverse the actual string representing the num.
- */
- int actualLength =0;
- char *p = buf;
- int i;
- do {
- int tmp = u %base;
- if (tmp <= 9) {
- *p++ = '0' + tmp;
- } else if (upcase) {
- *p++ = 'A' + tmp - 10;
- } else {
- *p++ = 'a' + tmp - 10;
- }
- u /= base;
- } while (u != 0);
- if (negFlag) {
- *p++ = '-';
- }
- /* figure out actual length and adjust the maximum length */
- actualLength = p - buf;
- if (length < actualLength) length = actualLength;
- /* add padding */
- if (ladjust) {
- padc = ' ';
- }
- if (negFlag && !ladjust && (padc == '0')) {
- for (i = actualLength-1; i< length-1; i++) buf[i] = padc;
- buf[length -1] = '-';
- } else {
- for (i = actualLength; i< length; i++) buf[i] = padc;
- }
-
- /* prepare to reverse the string */
- {
- int begin = 0;
- int end;
- if (ladjust) {
- end = actualLength - 1;
- } else {
- end = length -1;
- }
- while (end > begin) {
- char tmp = buf[begin];
- buf[begin] = buf[end];
- buf[end] = tmp;
- begin ++;
- end --;
- }
- }
- /* adjust the string pointer */
- return length;
- }
|