print.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  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. #include "print.h"
  12. /* macros */
  13. #define IsDigit(x) ( ((x) >= '0') && ((x) <= '9') )
  14. #define Ctod(x) ( (x) - '0')
  15. /* forward declaration */
  16. extern int PrintChar(char *, char, int, int);
  17. extern int PrintString(char *, char *, int, int);
  18. extern int PrintNum(char *, unsigned long, int, int, int, int, char, int);
  19. /* private variable */
  20. static const char theFatalMsg[] = "fatal error in lp_Print!";
  21. /* -*-
  22. * A low level printf() function.
  23. */
  24. void
  25. lp_Print(void (*output)(void *, char *, int),
  26. void * arg,
  27. char *fmt,
  28. va_list ap)
  29. {
  30. #define OUTPUT(arg, s, l) \
  31. { if (((l) < 0) || ((l) > LP_MAX_BUF)) { \
  32. (*output)(arg, (char*)theFatalMsg, sizeof(theFatalMsg)-1); for(;;); \
  33. } else { \
  34. (*output)(arg, s, l); \
  35. } \
  36. }
  37. char buf[LP_MAX_BUF];
  38. char c;
  39. char *s;
  40. long int num;
  41. int longFlag;
  42. int negFlag;
  43. int width;
  44. int prec;
  45. int ladjust;
  46. char padc;
  47. int length;
  48. for(;;) {
  49. {
  50. /* scan for the next '%' */
  51. char *fmtStart = fmt;
  52. while ( (*fmt != '\0') && (*fmt != '%')) {
  53. fmt ++;
  54. }
  55. /* flush the string found so far */
  56. OUTPUT(arg, fmtStart, fmt-fmtStart);
  57. /* are we hitting the end? */
  58. if (*fmt == '\0') break;
  59. }
  60. /* we found a '%' */
  61. fmt ++;
  62. /* check for long */
  63. if (*fmt == 'l') {
  64. longFlag = 1;
  65. fmt ++;
  66. } else {
  67. longFlag = 0;
  68. }
  69. /* check for other prefixes */
  70. width = 0;
  71. prec = -1;
  72. ladjust = 0;
  73. padc = ' ';
  74. if (*fmt == '-') {
  75. ladjust = 1;
  76. fmt ++;
  77. }
  78. if (*fmt == '0') {
  79. padc = '0';
  80. fmt++;
  81. }
  82. if (IsDigit(*fmt)) {
  83. while (IsDigit(*fmt)) {
  84. width = 10 * width + Ctod(*fmt++);
  85. }
  86. }
  87. if (*fmt == '.') {
  88. fmt ++;
  89. if (IsDigit(*fmt)) {
  90. prec = 0;
  91. while (IsDigit(*fmt)) {
  92. prec = prec*10 + Ctod(*fmt++);
  93. }
  94. }
  95. }
  96. /* check format flag */
  97. negFlag = 0;
  98. switch (*fmt) {
  99. case 'b':
  100. if (longFlag) {
  101. num = va_arg(ap, long int);
  102. } else {
  103. num = va_arg(ap, int);
  104. }
  105. length = PrintNum(buf, num, 2, 0, width, ladjust, padc, 0);
  106. OUTPUT(arg, buf, length);
  107. break;
  108. case 'd':
  109. case 'D':
  110. if (longFlag) {
  111. num = va_arg(ap, long int);
  112. } else {
  113. num = va_arg(ap, int);
  114. }
  115. if (num < 0) {
  116. num = - num;
  117. negFlag = 1;
  118. }
  119. length = PrintNum(buf, num, 10, negFlag, width, ladjust, padc, 0);
  120. OUTPUT(arg, buf, length);
  121. break;
  122. case 'o':
  123. case 'O':
  124. if (longFlag) {
  125. num = va_arg(ap, long int);
  126. } else {
  127. num = va_arg(ap, int);
  128. }
  129. length = PrintNum(buf, num, 8, 0, width, ladjust, padc, 0);
  130. OUTPUT(arg, buf, length);
  131. break;
  132. case 'u':
  133. case 'U':
  134. if (longFlag) {
  135. num = va_arg(ap, long int);
  136. } else {
  137. num = va_arg(ap, int);
  138. }
  139. length = PrintNum(buf, num, 10, 0, width, ladjust, padc, 0);
  140. OUTPUT(arg, buf, length);
  141. break;
  142. case 'x':
  143. if (longFlag) {
  144. num = va_arg(ap, long int);
  145. } else {
  146. num = va_arg(ap, int);
  147. }
  148. length = PrintNum(buf, num, 16, 0, width, ladjust, padc, 0);
  149. OUTPUT(arg, buf, length);
  150. break;
  151. case 'X':
  152. if (longFlag) {
  153. num = va_arg(ap, long int);
  154. } else {
  155. num = va_arg(ap, int);
  156. }
  157. length = PrintNum(buf, num, 16, 0, width, ladjust, padc, 1);
  158. OUTPUT(arg, buf, length);
  159. break;
  160. case 'c':
  161. c = (char)va_arg(ap, int);
  162. length = PrintChar(buf, c, width, ladjust);
  163. OUTPUT(arg, buf, length);
  164. break;
  165. case 's':
  166. s = (char*)va_arg(ap, char *);
  167. length = PrintString(buf, s, width, ladjust);
  168. OUTPUT(arg, buf, length);
  169. break;
  170. case '\0':
  171. fmt --;
  172. break;
  173. default:
  174. /* output this char as it is */
  175. OUTPUT(arg, fmt, 1);
  176. } /* switch (*fmt) */
  177. fmt ++;
  178. } /* for(;;) */
  179. /* special termination call */
  180. OUTPUT(arg, "\0", 1);
  181. }
  182. /* --------------- local help functions --------------------- */
  183. int
  184. PrintChar(char * buf, char c, int length, int ladjust)
  185. {
  186. int i;
  187. if (length < 1) length = 1;
  188. if (ladjust) {
  189. *buf = c;
  190. for (i=1; i< length; i++) buf[i] = ' ';
  191. } else {
  192. for (i=0; i< length-1; i++) buf[i] = ' ';
  193. buf[length - 1] = c;
  194. }
  195. return length;
  196. }
  197. int
  198. PrintString(char * buf, char* s, int length, int ladjust)
  199. {
  200. int i;
  201. int len=0;
  202. char* s1 = s;
  203. while (*s1++) len++;
  204. if (length < len) length = len;
  205. if (ladjust) {
  206. for (i=0; i< len; i++) buf[i] = s[i];
  207. for (i=len; i< length; i++) buf[i] = ' ';
  208. } else {
  209. for (i=0; i< length-len; i++) buf[i] = ' ';
  210. for (i=length-len; i < length; i++) buf[i] = s[i-length+len];
  211. }
  212. return length;
  213. }
  214. int
  215. PrintNum(char * buf, unsigned long u, int base, int negFlag,
  216. int length, int ladjust, char padc, int upcase)
  217. {
  218. /* algorithm :
  219. * 1. prints the number from left to right in reverse form.
  220. * 2. fill the remaining spaces with padc if length is longer than
  221. * the actual length
  222. * TRICKY : if left adjusted, no "0" padding.
  223. * if negtive, insert "0" padding between "0" and number.
  224. * 3. if (!ladjust) we reverse the whole string including paddings
  225. * 4. otherwise we only reverse the actual string representing the num.
  226. */
  227. int actualLength =0;
  228. char *p = buf;
  229. int i;
  230. do {
  231. int tmp = u %base;
  232. if (tmp <= 9) {
  233. *p++ = '0' + tmp;
  234. } else if (upcase) {
  235. *p++ = 'A' + tmp - 10;
  236. } else {
  237. *p++ = 'a' + tmp - 10;
  238. }
  239. u /= base;
  240. } while (u != 0);
  241. if (negFlag) {
  242. *p++ = '-';
  243. }
  244. /* figure out actual length and adjust the maximum length */
  245. actualLength = p - buf;
  246. if (length < actualLength) length = actualLength;
  247. /* add padding */
  248. if (ladjust) {
  249. padc = ' ';
  250. }
  251. if (negFlag && !ladjust && (padc == '0')) {
  252. for (i = actualLength-1; i< length-1; i++) buf[i] = padc;
  253. buf[length -1] = '-';
  254. } else {
  255. for (i = actualLength; i< length; i++) buf[i] = padc;
  256. }
  257. /* prepare to reverse the string */
  258. {
  259. int begin = 0;
  260. int end;
  261. if (ladjust) {
  262. end = actualLength - 1;
  263. } else {
  264. end = length -1;
  265. }
  266. while (end > begin) {
  267. char tmp = buf[begin];
  268. buf[begin] = buf[end];
  269. buf[end] = tmp;
  270. begin ++;
  271. end --;
  272. }
  273. }
  274. /* adjust the string pointer */
  275. return length;
  276. }