doprnt.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /*
  2. * doprnt.c - print formatted output
  3. */
  4. /* $Id$ */
  5. #include <ctype.h>
  6. #include <stdio.h>
  7. #include <stdarg.h>
  8. #include <string.h>
  9. #include "loc_incl.h"
  10. /* gnum() is used to get the width and precision fields of a format. */
  11. static const char *
  12. gnum(register const char *f, int *ip, va_list *app)
  13. {
  14. register int i, c;
  15. if (*f == '*') {
  16. *ip = va_arg((*app), int);
  17. f++;
  18. } else {
  19. i = 0;
  20. while ((c = *f - '0') >= 0 && c <= 9) {
  21. i = i*10 + c;
  22. f++;
  23. }
  24. *ip = i;
  25. }
  26. return f;
  27. }
  28. #if _EM_WSIZE == _EM_PSIZE
  29. #define set_pointer(flags) /* nothing */
  30. #elif _EM_LSIZE == _EM_PSIZE
  31. #define set_pointer(flags) (flags |= FL_LONG)
  32. #else
  33. #error garbage pointer size
  34. #define set_pointer(flags) /* compilation might continue */
  35. #endif
  36. /* print an ordinal number */
  37. static char *
  38. o_print(va_list *ap, int flags, char *s, char c, int precision, int is_signed)
  39. {
  40. long signed_val;
  41. unsigned long unsigned_val;
  42. char *old_s = s;
  43. int base;
  44. switch (flags & (FL_SHORT | FL_LONG)) {
  45. case FL_SHORT:
  46. if (is_signed) {
  47. signed_val = (short) va_arg(*ap, int);
  48. } else {
  49. unsigned_val = (unsigned short) va_arg(*ap, unsigned);
  50. }
  51. break;
  52. case FL_LONG:
  53. if (is_signed) {
  54. signed_val = va_arg(*ap, long);
  55. } else {
  56. unsigned_val = va_arg(*ap, unsigned long);
  57. }
  58. break;
  59. default:
  60. if (is_signed) {
  61. signed_val = va_arg(*ap, int);
  62. } else {
  63. unsigned_val = va_arg(*ap, unsigned int);
  64. }
  65. break;
  66. }
  67. if (is_signed) {
  68. if (signed_val < 0) {
  69. *s++ = '-';
  70. signed_val = -signed_val;
  71. } else if (flags & FL_SIGN) *s++ = '+';
  72. else if (flags & FL_SPACE) *s++ = ' ';
  73. unsigned_val = signed_val;
  74. }
  75. if ((flags & FL_ALT) && (c == 'o')) *s++ = '0';
  76. if (!unsigned_val) {
  77. if (!precision)
  78. return s;
  79. } else if (((flags & FL_ALT) && (c == 'x' || c == 'X'))
  80. || c == 'p') {
  81. *s++ = '0';
  82. *s++ = (c == 'X' ? 'X' : 'x');
  83. }
  84. switch (c) {
  85. case 'b': base = 2; break;
  86. case 'o': base = 8; break;
  87. case 'd':
  88. case 'i':
  89. case 'u': base = 10; break;
  90. case 'x':
  91. case 'X':
  92. case 'p': base = 16; break;
  93. }
  94. s = _i_compute(unsigned_val, base, s, precision);
  95. if (c == 'X')
  96. while (old_s != s) {
  97. *old_s = toupper(*old_s);
  98. old_s++;
  99. }
  100. return s;
  101. }
  102. int
  103. _doprnt(register const char *fmt, va_list ap, FILE *stream)
  104. {
  105. register char *s;
  106. register int j;
  107. int i, c, width, precision, zfill, flags, between_fill;
  108. int nrchars=0;
  109. const char *oldfmt;
  110. char *s1, buf[1025];
  111. while (c = *fmt++) {
  112. if (c != '%') {
  113. #ifdef CPM
  114. if (c == '\n') {
  115. if (putc('\r', stream) == EOF)
  116. return nrchars ? -nrchars : -1;
  117. nrchars++;
  118. }
  119. #endif
  120. if (putc(c, stream) == EOF)
  121. return nrchars ? -nrchars : -1;
  122. nrchars++;
  123. continue;
  124. }
  125. flags = 0;
  126. do {
  127. switch(*fmt) {
  128. case '-': flags |= FL_LJUST; break;
  129. case '+': flags |= FL_SIGN; break;
  130. case ' ': flags |= FL_SPACE; break;
  131. case '#': flags |= FL_ALT; break;
  132. case '0': flags |= FL_ZEROFILL; break;
  133. default: flags |= FL_NOMORE; continue;
  134. }
  135. fmt++;
  136. } while(!(flags & FL_NOMORE));
  137. oldfmt = fmt;
  138. fmt = gnum(fmt, &width, &ap);
  139. if (fmt != oldfmt) flags |= FL_WIDTHSPEC;
  140. if (*fmt == '.') {
  141. fmt++; oldfmt = fmt;
  142. fmt = gnum(fmt, &precision, &ap);
  143. if (precision >= 0) flags |= FL_PRECSPEC;
  144. }
  145. if ((flags & FL_WIDTHSPEC) && width < 0) {
  146. width = -width;
  147. flags |= FL_LJUST;
  148. }
  149. if (!(flags & FL_WIDTHSPEC)) width = 0;
  150. if (flags & FL_SIGN) flags &= ~FL_SPACE;
  151. if (flags & FL_LJUST) flags &= ~FL_ZEROFILL;
  152. s = s1 = buf;
  153. switch (*fmt) {
  154. case 'h': flags |= FL_SHORT; fmt++; break;
  155. case 'l': flags |= FL_LONG; fmt++; break;
  156. case 'L': flags |= FL_LONGDOUBLE; fmt++; break;
  157. }
  158. switch (c = *fmt++) {
  159. default:
  160. #ifdef CPM
  161. if (c == '\n') {
  162. if (putc('\r', stream) == EOF)
  163. return nrchars ? -nrchars : -1;
  164. nrchars++;
  165. }
  166. #endif
  167. if (putc(c, stream) == EOF)
  168. return nrchars ? -nrchars : -1;
  169. nrchars++;
  170. continue;
  171. case 'n':
  172. if (flags & FL_SHORT)
  173. *va_arg(ap, short *) = (short) nrchars;
  174. else if (flags & FL_LONG)
  175. *va_arg(ap, long *) = (long) nrchars;
  176. else
  177. *va_arg(ap, int *) = (int) nrchars;
  178. continue;
  179. case 's':
  180. s1 = va_arg(ap, char *);
  181. if (s1 == NULL)
  182. s1 = "(null)";
  183. s = s1;
  184. while (precision || !(flags & FL_PRECSPEC)) {
  185. if (*s == '\0')
  186. break;
  187. s++;
  188. precision--;
  189. }
  190. break;
  191. case 'p':
  192. set_pointer(flags);
  193. /* fallthrough */
  194. case 'b':
  195. case 'o':
  196. case 'u':
  197. case 'x':
  198. case 'X':
  199. if (!(flags & FL_PRECSPEC)) precision = 1;
  200. else if (c != 'p') flags &= ~FL_ZEROFILL;
  201. s = o_print(&ap, flags, s, c, precision, 0);
  202. break;
  203. case 'd':
  204. case 'i':
  205. flags |= FL_SIGNEDCONV;
  206. if (!(flags & FL_PRECSPEC)) precision = 1;
  207. else flags &= ~FL_ZEROFILL;
  208. s = o_print(&ap, flags, s, c, precision, 1);
  209. break;
  210. case 'c':
  211. *s++ = va_arg(ap, int);
  212. break;
  213. #ifndef NOFLOAT
  214. case 'G':
  215. case 'g':
  216. if ((flags & FL_PRECSPEC) && (precision == 0))
  217. precision = 1;
  218. case 'f':
  219. case 'E':
  220. case 'e':
  221. if (!(flags & FL_PRECSPEC))
  222. precision = 6;
  223. if (precision >= sizeof(buf))
  224. precision = sizeof(buf) - 1;
  225. flags |= FL_SIGNEDCONV;
  226. s = _f_print(&ap, flags, s, c, precision);
  227. break;
  228. #endif /* NOFLOAT */
  229. case 'r':
  230. ap = va_arg(ap, va_list);
  231. fmt = va_arg(ap, char *);
  232. continue;
  233. }
  234. zfill = ' ';
  235. if (flags & FL_ZEROFILL) zfill = '0';
  236. j = s - s1;
  237. /* between_fill is true under the following conditions:
  238. * 1- the fill character is '0'
  239. * and
  240. * 2a- the number is of the form 0x... or 0X...
  241. * or
  242. * 2b- the number contains a sign or space
  243. */
  244. between_fill = 0;
  245. if ((flags & FL_ZEROFILL)
  246. && (((c == 'x' || c == 'X') && (flags & FL_ALT))
  247. || (c == 'p')
  248. || ((flags & FL_SIGNEDCONV)
  249. && ( *s1 == '+' || *s1 == '-' || *s1 == ' '))))
  250. between_fill++;
  251. if ((i = width - j) > 0)
  252. if (!(flags & FL_LJUST)) { /* right justify */
  253. nrchars += i;
  254. if (between_fill) {
  255. if (flags & FL_SIGNEDCONV) {
  256. j--; nrchars++;
  257. if (putc(*s1++, stream) == EOF)
  258. return nrchars ? -nrchars : -1;
  259. } else {
  260. j -= 2; nrchars += 2;
  261. if ((putc(*s1++, stream) == EOF)
  262. || (putc(*s1++, stream) == EOF))
  263. return nrchars ? -nrchars : -1;
  264. }
  265. }
  266. do {
  267. if (putc(zfill, stream) == EOF)
  268. return nrchars ? -nrchars : -1;
  269. } while (--i);
  270. }
  271. nrchars += j;
  272. while (--j >= 0) {
  273. if (putc(*s1++, stream) == EOF)
  274. return nrchars ? -nrchars : -1;
  275. }
  276. if (i > 0) nrchars += i;
  277. while (--i >= 0)
  278. if (putc(zfill, stream) == EOF)
  279. return nrchars ? -nrchars : -1;
  280. }
  281. return nrchars;
  282. }