doprnt.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. /*
  2. * doprnt.c - print formatted output
  3. */
  4. /* $Header$ */
  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 i, 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 - 1);
  95. if (c == 'X')
  96. while (old_s != s) {
  97. *old_s = toupper(*old_s);
  98. old_s++;
  99. }
  100. return s;
  101. }
  102. #ifndef NOFLOAT
  103. static char *
  104. f_print(va_list *ap, int flags, char *s, char c, int precision)
  105. {
  106. register char *old_s = s;
  107. long double ld_val;
  108. if (flags & FL_LONGDOUBLE) ld_val = va_arg(*ap, long double);
  109. else ld_val = (long double) va_arg(*ap, double);
  110. switch(c) {
  111. case 'f':
  112. s = _pfloat(ld_val, s, precision, flags);
  113. break;
  114. case 'e':
  115. case 'E':
  116. s = _pscien(ld_val, s, precision , flags);
  117. break;
  118. case 'g':
  119. case 'G':
  120. s = _gcvt(ld_val, precision, s, flags) + strlen(s);
  121. break;
  122. }
  123. if ( c == 'E' || c == 'G') {
  124. while (*old_s && *old_s != 'e') old_s++;
  125. if (*old_s == 'e') *old_s = 'E';
  126. }
  127. return s;
  128. }
  129. #endif /* NOFLOAT */
  130. int
  131. _doprnt(register const char *fmt, va_list ap, FILE *stream)
  132. {
  133. register char *s;
  134. unsigned int uint;
  135. register int j;
  136. int i, c, width, precision, zfill, flags, between_fill;
  137. int nrchars=0;
  138. const char *oldfmt;
  139. char *s1, buf[1025];
  140. while (c = *fmt++) {
  141. if (c != '%') {
  142. #ifdef CPM
  143. if (c == '\n') {
  144. if (putc('\r', stream) == EOF)
  145. return nrchars ? -nrchars : -1;
  146. nrchars++;
  147. }
  148. #endif
  149. if (putc(c, stream) == EOF)
  150. return nrchars ? -nrchars : -1;
  151. nrchars++;
  152. continue;
  153. }
  154. flags = 0;
  155. do {
  156. switch(*fmt) {
  157. case '-': flags |= FL_LJUST; break;
  158. case '+': flags |= FL_SIGN; break;
  159. case ' ': flags |= FL_SPACE; break;
  160. case '#': flags |= FL_ALT; break;
  161. case '0': flags |= FL_ZEROFILL; break;
  162. default: flags |= FL_NOMORE; continue;
  163. }
  164. fmt++;
  165. } while(!(flags & FL_NOMORE));
  166. oldfmt = fmt;
  167. fmt = gnum(fmt, &width, &ap);
  168. if (fmt != oldfmt) flags |= FL_WIDTHSPEC;
  169. if (*fmt == '.') {
  170. fmt++; oldfmt = fmt;
  171. fmt = gnum(fmt, &precision, &ap);
  172. if (precision >= 0) flags |= FL_PRECSPEC;
  173. }
  174. if ((flags & FL_WIDTHSPEC) && width < 0) {
  175. width = -width;
  176. flags |= FL_LJUST;
  177. }
  178. if (!(flags & FL_WIDTHSPEC)) width = 0;
  179. if (flags & FL_SIGN) flags &= ~FL_SPACE;
  180. if (flags & FL_LJUST) flags &= ~FL_ZEROFILL;
  181. s = s1 = buf;
  182. switch (*fmt) {
  183. case 'h': flags |= FL_SHORT; fmt++; break;
  184. case 'l': flags |= FL_LONG; fmt++; break;
  185. case 'L': flags |= FL_LONGDOUBLE; fmt++; break;
  186. }
  187. switch (c = *fmt++) {
  188. default:
  189. #ifdef CPM
  190. if (c == '\n') {
  191. if (putc('\r', stream) == EOF)
  192. return nrchars ? -nrchars : -1;
  193. nrchars++;
  194. }
  195. #endif
  196. if (putc(c, stream) == EOF)
  197. return nrchars ? -nrchars : -1;
  198. nrchars++;
  199. continue;
  200. case 'n':
  201. if (flags & FL_SHORT)
  202. *va_arg(ap, short *) = (short) nrchars;
  203. else if (flags & FL_LONG)
  204. *va_arg(ap, long *) = (long) nrchars;
  205. else
  206. *va_arg(ap, int *) = (int) nrchars;
  207. continue;
  208. case 's':
  209. s1 = va_arg(ap, char *);
  210. if (s1 == NULL)
  211. s1 = "(null)";
  212. s = s1;
  213. while (precision || !(flags & FL_PRECSPEC)) {
  214. if (*s == '\0')
  215. break;
  216. s++;
  217. precision--;
  218. }
  219. break;
  220. case 'p':
  221. set_pointer(flags);
  222. /* fallthrough */
  223. case 'b':
  224. case 'o':
  225. case 'u':
  226. case 'x':
  227. case 'X':
  228. if (!(flags & FL_PRECSPEC)) precision = 1;
  229. else if (c != 'p') flags &= ~FL_ZEROFILL;
  230. s = o_print(&ap, flags, s, c, precision, 0);
  231. break;
  232. case 'd':
  233. case 'i':
  234. flags |= FL_SIGNEDCONV;
  235. if (!(flags & FL_PRECSPEC)) precision = 1;
  236. else flags &= ~FL_ZEROFILL;
  237. s = o_print(&ap, flags, s, c, precision, 1);
  238. break;
  239. case 'c':
  240. uint = va_arg(ap, unsigned int);
  241. for ( i= sizeof(uint) -1 ; i>=0 ; i-- ) {
  242. if ( *s = uint%256 ) s++;
  243. uint/= 256 ;
  244. }
  245. break;
  246. #ifndef NOFLOAT
  247. case 'G':
  248. case 'g':
  249. if ((flags & FL_PRECSPEC) && (precision == 0))
  250. precision = 1;
  251. case 'f':
  252. case 'E':
  253. case 'e':
  254. if (!(flags & FL_PRECSPEC))
  255. precision = 6;
  256. if (precision >= sizeof(buf))
  257. precision = sizeof(buf) - 1;
  258. flags |= FL_SIGNEDCONV;
  259. s = f_print(&ap, flags, s, c, precision);
  260. break;
  261. #endif /* NOFLOAT */
  262. case 'r':
  263. ap = va_arg(ap, va_list);
  264. fmt = va_arg(ap, char *);
  265. continue;
  266. }
  267. zfill = ' ';
  268. if (flags & FL_ZEROFILL) zfill = '0';
  269. j = s - s1;
  270. /* between_fill is true under the following conditions:
  271. * 1- the fill character is '0'
  272. * and
  273. * 2a- the number is of the form 0x... or 0X...
  274. * or
  275. * 2b- the number contains a sign or space
  276. */
  277. between_fill = 0;
  278. if ((flags & FL_ZEROFILL)
  279. && (((c == 'x' || c == 'X') && (flags & FL_ALT))
  280. || (c == 'p')
  281. || ((flags & FL_SIGNEDCONV)
  282. && ( *s1 == '+' || *s1 == '-' || *s1 == ' '))))
  283. between_fill++;
  284. if ((i = width - j) > 0)
  285. if (!(flags & FL_LJUST)) { /* right justify */
  286. nrchars += i;
  287. if (between_fill) {
  288. if (flags & FL_SIGNEDCONV) {
  289. j--; nrchars++;
  290. if (putc(*s1++, stream) == EOF)
  291. return nrchars ? -nrchars : -1;
  292. } else {
  293. j -= 2; nrchars += 2;
  294. if ((putc(*s1++, stream) == EOF)
  295. || (putc(*s1++, stream) == EOF))
  296. return nrchars ? -nrchars : -1;
  297. }
  298. }
  299. do {
  300. if (putc(zfill, stream) == EOF)
  301. return nrchars ? -nrchars : -1;
  302. } while (--i);
  303. }
  304. nrchars += j;
  305. while (--j >= 0) {
  306. if (putc(*s1++, stream) == EOF)
  307. return nrchars ? -nrchars : -1;
  308. }
  309. if (i > 0) nrchars += i;
  310. while (--i >= 0)
  311. if (putc(zfill, stream) == EOF)
  312. return nrchars ? -nrchars : -1;
  313. }
  314. return nrchars;
  315. }