vfwprintf.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. #include "stdio_impl.h"
  2. #include <errno.h>
  3. #include <ctype.h>
  4. #include <limits.h>
  5. #include <string.h>
  6. #include <stdarg.h>
  7. #include <wchar.h>
  8. #include <inttypes.h>
  9. /* Convenient bit representation for modifier flags, which all fall
  10. * within 31 codepoints of the space character. */
  11. #define ALT_FORM (1U<<'#'-' ')
  12. #define ZERO_PAD (1U<<'0'-' ')
  13. #define LEFT_ADJ (1U<<'-'-' ')
  14. #define PAD_POS (1U<<' '-' ')
  15. #define MARK_POS (1U<<'+'-' ')
  16. #define GROUPED (1U<<'\''-' ')
  17. #define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS|GROUPED)
  18. #if UINT_MAX == ULONG_MAX
  19. #define LONG_IS_INT
  20. #endif
  21. #if SIZE_MAX != ULONG_MAX || UINTMAX_MAX != ULLONG_MAX
  22. #define ODD_TYPES
  23. #endif
  24. /* State machine to accept length modifiers + conversion specifiers.
  25. * Result is 0 on failure, or an argument type to pop on success. */
  26. enum {
  27. BARE, LPRE, LLPRE, HPRE, HHPRE, BIGLPRE,
  28. ZTPRE, JPRE,
  29. STOP,
  30. PTR, INT, UINT, ULLONG,
  31. #ifndef LONG_IS_INT
  32. LONG, ULONG,
  33. #else
  34. #define LONG INT
  35. #define ULONG UINT
  36. #endif
  37. SHORT, USHORT, CHAR, UCHAR,
  38. #ifdef ODD_TYPES
  39. LLONG, SIZET, IMAX, UMAX, PDIFF, UIPTR,
  40. #else
  41. #define LLONG ULLONG
  42. #define SIZET ULONG
  43. #define IMAX LLONG
  44. #define UMAX ULLONG
  45. #define PDIFF LONG
  46. #define UIPTR ULONG
  47. #endif
  48. DBL, LDBL,
  49. NOARG,
  50. MAXSTATE
  51. };
  52. #define S(x) [(x)-'A']
  53. static const unsigned char states[]['z'-'A'+1] = {
  54. { /* 0: bare types */
  55. S('d') = INT, S('i') = INT,
  56. S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT,
  57. S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
  58. S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
  59. S('c') = CHAR, S('C') = INT,
  60. S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR,
  61. S('m') = NOARG,
  62. S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE,
  63. S('z') = ZTPRE, S('j') = JPRE, S('t') = ZTPRE,
  64. }, { /* 1: l-prefixed */
  65. S('d') = LONG, S('i') = LONG,
  66. S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG,
  67. S('c') = INT, S('s') = PTR, S('n') = PTR,
  68. S('l') = LLPRE,
  69. }, { /* 2: ll-prefixed */
  70. S('d') = LLONG, S('i') = LLONG,
  71. S('o') = ULLONG, S('u') = ULLONG,
  72. S('x') = ULLONG, S('X') = ULLONG,
  73. S('n') = PTR,
  74. }, { /* 3: h-prefixed */
  75. S('d') = SHORT, S('i') = SHORT,
  76. S('o') = USHORT, S('u') = USHORT,
  77. S('x') = USHORT, S('X') = USHORT,
  78. S('n') = PTR,
  79. S('h') = HHPRE,
  80. }, { /* 4: hh-prefixed */
  81. S('d') = CHAR, S('i') = CHAR,
  82. S('o') = UCHAR, S('u') = UCHAR,
  83. S('x') = UCHAR, S('X') = UCHAR,
  84. S('n') = PTR,
  85. }, { /* 5: L-prefixed */
  86. S('e') = LDBL, S('f') = LDBL, S('g') = LDBL, S('a') = LDBL,
  87. S('E') = LDBL, S('F') = LDBL, S('G') = LDBL, S('A') = LDBL,
  88. S('n') = PTR,
  89. }, { /* 6: z- or t-prefixed (assumed to be same size) */
  90. S('d') = PDIFF, S('i') = PDIFF,
  91. S('o') = SIZET, S('u') = SIZET,
  92. S('x') = SIZET, S('X') = SIZET,
  93. S('n') = PTR,
  94. }, { /* 7: j-prefixed */
  95. S('d') = IMAX, S('i') = IMAX,
  96. S('o') = UMAX, S('u') = UMAX,
  97. S('x') = UMAX, S('X') = UMAX,
  98. S('n') = PTR,
  99. }
  100. };
  101. #define OOB(x) ((unsigned)(x)-'A' > 'z'-'A')
  102. union arg
  103. {
  104. uintmax_t i;
  105. long double f;
  106. void *p;
  107. };
  108. static void pop_arg(union arg *arg, int type, va_list *ap)
  109. {
  110. /* Give the compiler a hint for optimizing the switch. */
  111. if ((unsigned)type > MAXSTATE) return;
  112. switch (type) {
  113. case PTR: arg->p = va_arg(*ap, void *);
  114. break; case INT: arg->i = va_arg(*ap, int);
  115. break; case UINT: arg->i = va_arg(*ap, unsigned int);
  116. #ifndef LONG_IS_INT
  117. break; case LONG: arg->i = va_arg(*ap, long);
  118. break; case ULONG: arg->i = va_arg(*ap, unsigned long);
  119. #endif
  120. break; case ULLONG: arg->i = va_arg(*ap, unsigned long long);
  121. break; case SHORT: arg->i = (short)va_arg(*ap, int);
  122. break; case USHORT: arg->i = (unsigned short)va_arg(*ap, int);
  123. break; case CHAR: arg->i = (signed char)va_arg(*ap, int);
  124. break; case UCHAR: arg->i = (unsigned char)va_arg(*ap, int);
  125. #ifdef ODD_TYPES
  126. break; case LLONG: arg->i = va_arg(*ap, long long);
  127. break; case SIZET: arg->i = va_arg(*ap, size_t);
  128. break; case IMAX: arg->i = va_arg(*ap, intmax_t);
  129. break; case UMAX: arg->i = va_arg(*ap, uintmax_t);
  130. break; case PDIFF: arg->i = va_arg(*ap, ptrdiff_t);
  131. break; case UIPTR: arg->i = (uintptr_t)va_arg(*ap, void *);
  132. #endif
  133. break; case DBL: arg->f = va_arg(*ap, double);
  134. break; case LDBL: arg->f = va_arg(*ap, long double);
  135. }
  136. }
  137. static void out(FILE *f, const wchar_t *s, size_t l)
  138. {
  139. while (l-- && !(f->flags & F_ERR)) fputwc(*s++, f);
  140. }
  141. static int getint(wchar_t **s) {
  142. int i;
  143. for (i=0; iswdigit(**s); (*s)++)
  144. i = 10*i + (**s-'0');
  145. return i;
  146. }
  147. static const char sizeprefix['y'-'a'] = {
  148. ['a'-'a']='L', ['e'-'a']='L', ['f'-'a']='L', ['g'-'a']='L',
  149. ['d'-'a']='j', ['i'-'a']='j', ['o'-'a']='j', ['u'-'a']='j', ['x'-'a']='j',
  150. ['p'-'a']='j'
  151. };
  152. static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_arg, int *nl_type)
  153. {
  154. wchar_t *a, *z, *s=(wchar_t *)fmt;
  155. unsigned l10n=0, litpct, fl;
  156. int w, p;
  157. union arg arg;
  158. int argpos;
  159. unsigned st, ps;
  160. int cnt=0, l=0;
  161. int i;
  162. int t;
  163. char *bs;
  164. char charfmt[16];
  165. wchar_t wc;
  166. for (;;) {
  167. /* Update output count, end loop when fmt is exhausted */
  168. if (cnt >= 0) {
  169. if (l > INT_MAX - cnt) {
  170. if (!ferror(f)) errno = EOVERFLOW;
  171. cnt = -1;
  172. } else cnt += l;
  173. }
  174. if (!*s) break;
  175. /* Handle literal text and %% format specifiers */
  176. for (a=s; *s && *s!='%'; s++);
  177. litpct = wcsspn(s, L"%")/2; /* Optimize %%%% runs */
  178. z = s+litpct;
  179. s += 2*litpct;
  180. l = z-a;
  181. if (f) out(f, a, l);
  182. if (l) continue;
  183. if (iswdigit(s[1]) && s[2]=='$') {
  184. l10n=1;
  185. argpos = s[1]-'0';
  186. s+=3;
  187. } else {
  188. argpos = -1;
  189. s++;
  190. }
  191. /* Read modifier flags */
  192. for (fl=0; (unsigned)*s-' '<32 && (FLAGMASK&(1U<<*s-' ')); s++)
  193. fl |= 1U<<*s-' ';
  194. /* Read field width */
  195. if (*s=='*') {
  196. if (iswdigit(s[1]) && s[2]=='$') {
  197. l10n=1;
  198. nl_type[s[1]-'0'] = INT;
  199. w = nl_arg[s[1]-'0'].i;
  200. s+=3;
  201. } else if (!l10n) {
  202. w = f ? va_arg(*ap, int) : 0;
  203. s++;
  204. } else return -1;
  205. if (w<0) fl|=LEFT_ADJ, w=-w;
  206. } else if ((w=getint(&s))<0) return -1;
  207. /* Read precision */
  208. if (*s=='.' && s[1]=='*') {
  209. if (isdigit(s[2]) && s[3]=='$') {
  210. nl_type[s[2]-'0'] = INT;
  211. p = nl_arg[s[2]-'0'].i;
  212. s+=4;
  213. } else if (!l10n) {
  214. p = f ? va_arg(*ap, int) : 0;
  215. s+=2;
  216. } else return -1;
  217. } else if (*s=='.') {
  218. s++;
  219. p = getint(&s);
  220. } else p = -1;
  221. /* Format specifier state machine */
  222. st=0;
  223. do {
  224. if (OOB(*s)) return -1;
  225. ps=st;
  226. st=states[st]S(*s++);
  227. } while (st-1<STOP);
  228. if (!st) return -1;
  229. /* Check validity of argument type (nl/normal) */
  230. if (st==NOARG) {
  231. if (argpos>=0) return -1;
  232. } else {
  233. if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos];
  234. else if (f) pop_arg(&arg, st, ap);
  235. else return 0;
  236. }
  237. if (!f) continue;
  238. t = s[-1];
  239. if (ps && (t&15)==3) t&=~32;
  240. switch (t) {
  241. case 'n':
  242. switch(ps) {
  243. case BARE: *(int *)arg.p = cnt; break;
  244. case LPRE: *(long *)arg.p = cnt; break;
  245. case LLPRE: *(long long *)arg.p = cnt; break;
  246. case HPRE: *(unsigned short *)arg.p = cnt; break;
  247. case HHPRE: *(unsigned char *)arg.p = cnt; break;
  248. case ZTPRE: *(size_t *)arg.p = cnt; break;
  249. case JPRE: *(uintmax_t *)arg.p = cnt; break;
  250. }
  251. continue;
  252. case 'c':
  253. fputwc(btowc(arg.i), f);
  254. l = 1;
  255. continue;
  256. case 'C':
  257. fputwc(arg.i, f);
  258. l = 1;
  259. continue;
  260. case 'S':
  261. a = arg.p;
  262. z = wmemchr(a, 0, p);
  263. if (z) p=z-a;
  264. if (w<p) w=p;
  265. if (!(fl&LEFT_ADJ)) fprintf(f, "%.*s", w-p, "");
  266. out(f, a, p);
  267. if ((fl&LEFT_ADJ)) fprintf(f, "%.*s", w-p, "");
  268. l=w;
  269. continue;
  270. case 'm':
  271. arg.p = strerror(errno);
  272. case 's':
  273. if (!arg.p) arg.p = "(null)";
  274. bs = arg.p;
  275. if (p<0) p = INT_MAX;
  276. for (i=l=0; l<p && (i=mbtowc(&wc, bs, MB_LEN_MAX))>0; bs+=i, l++);
  277. if (i<0) return -1;
  278. p=l;
  279. if (w<p) w=p;
  280. if (!(fl&LEFT_ADJ)) fprintf(f, "%.*s", w-p, "");
  281. bs = arg.p;
  282. while (l--) {
  283. i=mbtowc(&wc, bs, MB_LEN_MAX);
  284. bs+=i;
  285. fputwc(wc, f);
  286. }
  287. if ((fl&LEFT_ADJ)) fprintf(f, "%.*s", w-p, "");
  288. l=w;
  289. continue;
  290. }
  291. snprintf(charfmt, sizeof charfmt, "%%%s%s%s%s%s*.*%c%c",
  292. "#"+!(fl & ALT_FORM),
  293. "+"+!(fl & MARK_POS),
  294. "-"+!(fl & LEFT_ADJ),
  295. " "+!(fl & PAD_POS),
  296. "0"+!(fl & ZERO_PAD),
  297. sizeprefix[(t|32)-'a'], t);
  298. switch (t|32) {
  299. case 'a': case 'e': case 'f': case 'g':
  300. l = fprintf(f, charfmt, w, p, arg.f);
  301. break;
  302. case 'd': case 'i': case 'o': case 'u': case 'x': case 'p':
  303. l = fprintf(f, charfmt, w, p, arg.i);
  304. break;
  305. }
  306. }
  307. if (f) return cnt;
  308. if (!l10n) return 0;
  309. for (i=1; i<=NL_ARGMAX && nl_type[i]; i++)
  310. pop_arg(nl_arg+i, nl_type[i], ap);
  311. for (; i<=NL_ARGMAX && !nl_type[i]; i++);
  312. if (i<=NL_ARGMAX) return -1;
  313. return 1;
  314. }
  315. int vfwprintf(FILE *restrict f, const wchar_t *restrict fmt, va_list ap)
  316. {
  317. va_list ap2;
  318. int nl_type[NL_ARGMAX] = {0};
  319. union arg nl_arg[NL_ARGMAX];
  320. int olderr;
  321. int ret;
  322. /* the copy allows passing va_list* even if va_list is an array */
  323. va_copy(ap2, ap);
  324. if (wprintf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) {
  325. va_end(ap2);
  326. return -1;
  327. }
  328. FLOCK(f);
  329. fwide(f, 1);
  330. olderr = f->flags & F_ERR;
  331. f->flags &= ~F_ERR;
  332. ret = wprintf_core(f, fmt, &ap2, nl_arg, nl_type);
  333. if (f->flags & F_ERR) ret = -1;
  334. f->flags |= olderr;
  335. FUNLOCK(f);
  336. va_end(ap2);
  337. return ret;
  338. }