1 /*
2 * An implementation of printf that
3 * - allows printing of 16-bit unicode characters and strings
4 * - translates output to a specified character set
5 *
6 * "char8" is 8 bits and contains ISO-Latin-1 (or ASCII) values
7 * "char16" is 16 bits and contains UTF-16 values
8 * "Char" is char8 or char16 depending on whether CHAR_SIZE is 8 or 16
9 *
10 * Author: Richard Tobin
11 */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <stdarg.h>
17 #include <err.h>
18
19 #ifdef FOR_LT
20
21 #include "lt-memory.h"
22 #include "nsl-err.h"
23
24 #define ERR(m) LT_ERROR(NECHAR,m)
25 #define ERR1(m,x) LT_ERROR1(NECHAR,m,x)
26 #define ERR2(m,x,y) LT_ERROR2(NECHAR,m,x,y)
27
28 #define Malloc salloc
29 #define Realloc srealloc
30 #define Free sfree
31
32 #else
33
34 #include "system.h"
35
36 #define ERR(m) fprintf(stderr,m)
37 #define ERR1(m,x) fprintf(stderr,m,x)
38 #define ERR2(m,x,y) fprintf(stderr,m,x,y)
39 #endif
40
41 #if defined(WIN32) && !defined(__CYGWIN__)
42 #undef boolean
43 #include <winsock.h>
44 #include <fcntl.h>
45 #include <io.h>
46 #else
47 #include <unistd.h>
48 #endif
49
50 #include "charset.h"
51 #include "string16.h"
52 #include "stdio16.h"
53
54 /* When we return -1 for non-io errors, we set errno to 0 to avoid confusion */
55 #include <errno.h>
56
57 #define BufferSize 4096
58
59 typedef int ReadProc(FILE16 *file, unsigned char *buf, int max_count);
60 typedef int WriteProc(FILE16 *file, const unsigned char *buf, int count);
61 typedef int SeekProc(FILE16 *file, long offset, int ptrname);
62 typedef int FlushProc(FILE16 *file);
63 typedef int CloseProc(FILE16 *file);
64
65 struct _FILE16 {
66 union {
67 void *handle;
68 const void *chandle;
69 };
70 int handle2, handle3;
71 ReadProc *read;
72 WriteProc *write;
73 SeekProc *seek;
74 FlushProc *flush;
75 CloseProc *close;
76 int flags;
77 CharacterEncoding enc;
78 char16 save;
79 /* There are incount unread bytes starting at inbuf[inoffset] */
80 unsigned char inbuf[4096];
81 int incount, inoffset;
82 };
83
84 #define FILE16_read 0x01
85 #define FILE16_write 0x02
86 #define FILE16_close_underlying 0x04
87 #define FILE16_crlf 0x08
88 #define FILE16_needs_binary 0x8000
89 #define FILE16_error 0x4000
90 #define FILE16_eof 0x2000
91
92 static void filbuf(FILE16 *file);
93
94 static int FileRead(FILE16 *file, unsigned char *buf, int max_count);
95 static int FileWrite(FILE16 *file, const unsigned char *buf, int count);
96 static int FileSeek(FILE16 *file, long offset, int ptrname);
97 static int FileClose(FILE16 *file);
98 static int FileFlush(FILE16 *file);
99
100 static int FDRead(FILE16 *file, unsigned char *buf, int max_count);
101 static int FDWrite(FILE16 *file, const unsigned char *buf, int count);
102 static int FDSeek(FILE16 *file, long offset, int ptrname);
103 static int FDClose(FILE16 *file);
104 static int FDFlush(FILE16 *file);
105
106 static int StringRead(FILE16 *file, unsigned char *buf, int max_count);
107 static int StringWrite(FILE16 *file, const unsigned char *buf, int count);
108 static int StringWriteTrunc(FILE16 *file, const unsigned char *buf, int count);
109 static int StringSeek(FILE16 *file, long offset, int ptrname);
110 static int StringClose(FILE16 *file);
111 static int StringFlush(FILE16 *file);
112
113 #if defined(WIN32) && ! defined(__CYGWIN__)
114 #ifdef SOCKETS_IMPLEMENTED
115 static int WinsockRead(FILE16 *file, unsigned char *buf, int max_count);
116 static int WinsockWrite(FILE16 *file, const unsigned char *buf, int count);
117 static int WinsockSeek(FILE16 *file, long offset, int ptrname);
118 static int WinsockClose(FILE16 *file);
119 static int WinsockFlush(FILE16 *file);
120 #endif
121 #endif
122
123 #ifdef HAVE_LIBZ
124 static int GzipRead(FILE16 *file, unsigned char *buf, int max_count);
125 static int GzipWrite(FILE16 *file, const unsigned char *buf, int count);
126 static int GzipSeek(FILE16 *file, long offset, int ptrname);
127 static int GzipClose(FILE16 *file);
128 static int GzipFlush(FILE16 *file);
129 #endif
130
131 FILE16 *Stdin, *Stdout, *Stderr;
132 static int Stdin_open = 0, Stdout_open = 0, Stderr_open = 0;
133
init_stdio16(void)134 int init_stdio16(void) {
135 if(!Stdin_open)
136 {
137 if(!(Stdin = MakeFILE16FromFILE(stdin, "r")))
138 return -1;
139 SetFileEncoding(Stdin, CE_ISO_8859_1);
140 Stdin_open = 1;
141 }
142 if(!Stdout_open)
143 {
144 if(!(Stdout = MakeFILE16FromFILE(stdout, "w")))
145 return -1;
146 SetFileEncoding(Stdout, CE_ISO_8859_1);
147 Stdout_open = 1;
148 }
149 if(!Stderr_open)
150 {
151 if(!(Stderr = MakeFILE16FromFILE(stderr, "w")))
152 return -1;
153 SetFileEncoding(Stderr, CE_ISO_8859_1);
154 Stderr_open = 1;
155 }
156
157 return 0;
158 }
159
deinit_stdio16(void)160 void deinit_stdio16(void) {
161 if(Stdin_open) Fclose(Stdin);
162 if(Stdout_open) Fclose(Stdout);
163 if(Stderr_open) Fclose(Stderr);
164 }
165
166 /* Return the size (in bytes) of nul in the given encoding */
167
NullSize(CharacterEncoding enc)168 static int NullSize(CharacterEncoding enc)
169 {
170 switch(enc)
171 {
172 default:
173 return 1;
174
175 case CE_UTF_16B:
176 case CE_ISO_10646_UCS_2B:
177 case CE_UTF_16L:
178 case CE_ISO_10646_UCS_2L:
179 return 2;
180 }
181 }
182
183 /* Output an ASCII buffer in the specified encoding */
184
185 /* In fact, we don't translate the buffer at all if we are outputting
186 an 8-bit encoding, and we treat it as Latin-1 is we are outputting
187 a 16-bit encoding. This means that all the various ASCII supersets
188 will be passed through unaltered in the usual case, since we don't
189 translate them on input either. */
190
ConvertASCII(const char8 * buf,int count,FILE16 * file)191 static int ConvertASCII(const char8 *buf, int count, FILE16 *file)
192 {
193 /* It *could* be that every character is linefeed... */
194 unsigned char outbuf[BufferSize*4];
195 unsigned char c;
196 int i, j;
197
198 switch(file->enc)
199 {
200 case CE_ISO_646:
201 case CE_ISO_8859_1:
202 case CE_ISO_8859_2:
203 case CE_ISO_8859_3:
204 case CE_ISO_8859_4:
205 case CE_ISO_8859_5:
206 case CE_ISO_8859_6:
207 case CE_ISO_8859_7:
208 case CE_ISO_8859_8:
209 case CE_ISO_8859_9:
210 case CE_ISO_8859_10:
211 case CE_ISO_8859_11:
212 case CE_ISO_8859_13:
213 case CE_ISO_8859_14:
214 case CE_ISO_8859_15:
215 case CE_unspecified_ascii_superset:
216 if(file->flags & FILE16_crlf)
217 {
218 for(i=j=0; i<count; i++)
219 {
220 c = buf[i];
221 if(c == '\n')
222 outbuf[j++] = '\r';
223 outbuf[j++] = c;
224 }
225 return Writeu(file, outbuf, j);
226 }
227 else
228 return Writeu(file, (const unsigned char *)buf, count);
229
230 case CE_UTF_8:
231 for(i=j=0; i<count; i++)
232 {
233 c = buf[i];
234 if(c == '\n' && (file->flags & FILE16_crlf))
235 outbuf[j++] = '\r';
236 if(c < 128)
237 outbuf[j++] = c;
238 else
239 {
240 outbuf[j++] = 0xc0 + (c >> 6);
241 outbuf[j++] = 0x80 + (c & 0x3f);
242 }
243 }
244 return Writeu(file, outbuf, j);
245
246 case CE_UTF_16B:
247 case CE_ISO_10646_UCS_2B:
248 for(i=j=0; i<count; i++)
249 {
250 c = buf[i];
251 if(c == '\n' && (file->flags & FILE16_crlf))
252 {
253 outbuf[j++] = 0;
254 outbuf[j++] = '\r';
255 }
256 outbuf[j++] = 0;
257 outbuf[j++] = c;
258 }
259 return Writeu(file, outbuf, j);
260
261 case CE_UTF_16L:
262 case CE_ISO_10646_UCS_2L:
263 for(i=j=0; i<count; i++)
264 {
265 c = buf[i];
266 if(c == '\n' && (file->flags & FILE16_crlf))
267 {
268 outbuf[j++] = '\r';
269 outbuf[j++] = 0;
270 }
271 outbuf[j++] = c;
272 outbuf[j++] = 0;
273 }
274 return Writeu(file, outbuf, j);
275
276 default:
277 ERR2("Bad output character encoding %d (%s)\n",
278 file->enc,
279 file->enc < CE_enum_count ? CharacterEncodingName[file->enc] :
280 "unknown");
281 errno = 0;
282 return -1;
283 }
284 }
285
286 /* Output a UTF-16 buffer in the specified encoding */
287
ConvertUTF16(const char16 * buf,int count,FILE16 * file)288 static int ConvertUTF16(const char16 *buf, int count, FILE16 *file)
289 {
290 /* It *could* be that every character is linefeed... */
291 unsigned char outbuf[BufferSize*4];
292 char16 c;
293 int i, j, tablenum, max;
294 char8 *from_unicode;
295 char32 big;
296
297 switch(file->enc)
298 {
299 case CE_ISO_646: /* should really check for >127 */
300 case CE_ISO_8859_1:
301 case CE_unspecified_ascii_superset:
302 for(i=j=0; i<count; i++)
303 {
304 c = buf[i];
305 if(c == '\n' && (file->flags & FILE16_crlf))
306 outbuf[j++] = '\r';
307 if(c < 256)
308 outbuf[j++] = (unsigned char)c;
309 else
310 outbuf[j++] = '?';
311 }
312 return Writeu(file, outbuf, j);
313
314 case CE_ISO_8859_2:
315 case CE_ISO_8859_3:
316 case CE_ISO_8859_4:
317 case CE_ISO_8859_5:
318 case CE_ISO_8859_6:
319 case CE_ISO_8859_7:
320 case CE_ISO_8859_8:
321 case CE_ISO_8859_9:
322 case CE_ISO_8859_10:
323 case CE_ISO_8859_11:
324 case CE_ISO_8859_13:
325 case CE_ISO_8859_14:
326 case CE_ISO_8859_15:
327 tablenum = (file->enc - CE_ISO_8859_2);
328 max = iso_max_val[tablenum];
329 from_unicode = unicode_to_iso[tablenum];
330 for(i=j=0; i<count; i++)
331 {
332 c = buf[i];
333 if(c == '\n' && (file->flags & FILE16_crlf))
334 outbuf[j++] = '\r';
335 if(c <= max)
336 outbuf[j++] = (unsigned char)from_unicode[c];
337 else
338 outbuf[j++] = '?';
339 }
340 return Writeu(file, outbuf, j);
341
342 case CE_UTF_8:
343 for(i=j=0; i<count; i++)
344 {
345 c = buf[i];
346 if(c == '\n' && (file->flags & FILE16_crlf))
347 outbuf[j++] = '\r';
348 if(c < 0x80)
349 outbuf[j++] = (unsigned char)c;
350 else if(c < 0x800)
351 {
352 outbuf[j++] = 0xc0 + (c >> 6);
353 outbuf[j++] = 0x80 + (c & 0x3f);
354 }
355 else if(c >= 0xd800 && c <= 0xdbff)
356 file->save = c;
357 else if(c >= 0xdc00 && c <= 0xdfff)
358 {
359 big = 0x10000 +
360 ((file->save - 0xd800) << 10) + (c - 0xdc00);
361 outbuf[j++] = 0xf0 + (big >> 18);
362 outbuf[j++] = 0x80 + ((big >> 12) & 0x3f);
363 outbuf[j++] = 0x80 + ((big >> 6) & 0x3f);
364 outbuf[j++] = 0x80 + (big & 0x3f);
365 }
366 else
367 {
368 outbuf[j++] = 0xe0 + (c >> 12);
369 outbuf[j++] = 0x80 + ((c >> 6) & 0x3f);
370 outbuf[j++] = 0x80 + (c & 0x3f);
371 }
372 }
373 return Writeu(file, outbuf, j);
374
375 case CE_UTF_16B:
376 case CE_ISO_10646_UCS_2B:
377 for(i=j=0; i<count; i++)
378 {
379 c = buf[i];
380 if(c == '\n' && (file->flags & FILE16_crlf))
381 {
382 outbuf[j++] = 0;
383 outbuf[j++] = '\r';
384 }
385 outbuf[j++] = (c >> 8);
386 outbuf[j++] = (c & 0xff);
387
388 }
389 return Writeu(file, outbuf, j);
390
391 case CE_UTF_16L:
392 case CE_ISO_10646_UCS_2L:
393 for(i=j=0; i<count; i++)
394 {
395 c = buf[i];
396 if(c == '\n' && (file->flags & FILE16_crlf))
397 {
398 outbuf[j++] = '\r';
399 outbuf[j++] = 0;
400 }
401 outbuf[j++] = (c & 0xff);
402 outbuf[j++] = (c >> 8);
403
404 }
405 return Writeu(file, outbuf, j);
406
407 default:
408 ERR2("Bad output character encoding %d (%s)\n",
409 file->enc,
410 file->enc < CE_enum_count ? CharacterEncodingName[file->enc] :
411 "unknown");
412 errno = 0;
413 return -1;
414 }
415 }
416
417 #if 0
418 int Readu(FILE16 *file, unsigned char *buf, int max_count)
419 {
420 return file->read(file, buf, max_count);
421 }
422 #endif
423
Writeu(FILE16 * file,const unsigned char * buf,int count)424 int Writeu(FILE16 *file, const unsigned char *buf, int count)
425 {
426 int ret;
427
428 ret = file->write(file, buf, count);
429 if(ret < 0)
430 file->flags |= FILE16_error;
431
432 return ret;
433 }
434
Fclose(FILE16 * file)435 int Fclose(FILE16 *file)
436 {
437 int ret = 0;
438
439 ret = file->close(file);
440 Free(file);
441
442 if(file == Stdin)
443 Stdin_open = 0;
444 else if(file == Stdout)
445 Stdout_open = 0;
446 else if(file == Stderr)
447 Stderr_open = 0;
448
449 return ret;
450 }
451
Fseek(FILE16 * file,long offset,int ptrname)452 int Fseek(FILE16 *file, long offset, int ptrname)
453 {
454 file->incount = file->inoffset = 0;
455 file->flags &= ~(FILE16_error | FILE16_eof);
456 return file->seek(file, offset, ptrname);
457 }
458
Fflush(FILE16 * file)459 int Fflush(FILE16 *file)
460 {
461 return file->flush(file);
462 }
463
Ferror(FILE16 * file)464 int Ferror(FILE16 *file)
465 {
466 return file->flags & FILE16_error;
467 }
468
Feof(FILE16 * file)469 int Feof(FILE16 *file)
470 {
471 return file->flags & FILE16_eof;
472 }
473
Getu(FILE16 * file)474 int Getu(FILE16 *file)
475 {
476 filbuf(file);
477 if(file->flags & (FILE16_error | FILE16_eof))
478 return EOF;
479 file->incount--;
480 return file->inbuf[file->inoffset++];
481 }
482
Readu(FILE16 * file,unsigned char * buf,int max_count)483 int Readu(FILE16 *file, unsigned char *buf, int max_count)
484 {
485 int count=0, lump;
486
487 while(count < max_count)
488 {
489 filbuf(file);
490 if(file->flags & FILE16_error)
491 return 0;
492 if(file->flags & FILE16_eof)
493 break;
494 lump = max_count - count;
495 if(lump > file->incount)
496 lump = file->incount;
497 memcpy(buf+count, file->inbuf+file->inoffset, lump);
498 count += lump;
499 file->inoffset += lump;
500 file->incount -= lump;
501 }
502
503 return count;
504 }
505
506 /* After calling filbuf, either file->incount > 0 or file->flags has
507 FILE16_eof or FILE16_error set. */
508
filbuf(FILE16 * file)509 static void filbuf(FILE16 *file)
510 {
511 int ret;
512
513 if(file->incount > 0)
514 return;
515
516 ret = file->read(file, file->inbuf, sizeof(file->inbuf));
517 if(ret < 0)
518 file->flags |= FILE16_error;
519 else if(ret == 0)
520 file->flags |= FILE16_eof;
521 else
522 {
523 file->inoffset = 0;
524 file->incount = ret;
525 }
526 }
527
GetFILE(FILE16 * file)528 FILE *GetFILE(FILE16 *file)
529 {
530 if(file->read == FileRead)
531 return (FILE *)file->handle;
532 else
533 return 0;
534 }
535
SetCloseUnderlying(FILE16 * file,int cu)536 void SetCloseUnderlying(FILE16 *file, int cu)
537 {
538 if(cu)
539 file->flags |= FILE16_close_underlying;
540 else
541 file->flags &= ~FILE16_close_underlying;
542 }
543
SetFileEncoding(FILE16 * file,CharacterEncoding encoding)544 void SetFileEncoding(FILE16 *file, CharacterEncoding encoding)
545 {
546 file->enc = encoding;
547 }
548
GetFileEncoding(FILE16 * file)549 CharacterEncoding GetFileEncoding(FILE16 *file)
550 {
551 return file->enc;
552 }
553
554 #if defined(WIN32)
SetNormalizeLineEnd(FILE16 * file,int nle)555 void SetNormalizeLineEnd(FILE16 *file, int nle)
556 {
557 if(nle)
558 file->flags |= FILE16_crlf;
559 else
560 file->flags &= ~FILE16_crlf;
561 }
562 #endif
563
Fprintf(FILE16 * file,const char * format,...)564 int Fprintf(FILE16 *file, const char *format, ...)
565 {
566 va_list args;
567 va_start(args, format);
568 return Vfprintf(file, format, args);
569 }
570
Printf(const char * format,...)571 int Printf(const char *format, ...)
572 {
573 va_list args;
574 va_start(args, format);
575 return Vfprintf(Stdout, format, args);
576 }
577
Sprintf(void * buf,CharacterEncoding enc,const char * format,...)578 int Sprintf(void *buf, CharacterEncoding enc, const char *format, ...)
579 {
580 va_list args;
581 va_start(args, format);
582 return Vsprintf(buf, enc, format, args);
583 }
584
Snprintf(void * buf,size_t size,CharacterEncoding enc,const char * format,...)585 int Snprintf(void *buf, size_t size, CharacterEncoding enc,
586 const char *format, ...)
587 {
588 va_list args;
589 va_start(args, format);
590 return Vsnprintf(buf, size, enc, format, args);
591 }
592
Vprintf(const char * format,va_list args)593 int Vprintf(const char *format, va_list args)
594 {
595 return Vfprintf(Stdout, format, args);
596 }
597
Vsprintf(void * buf,CharacterEncoding enc,const char * format,va_list args)598 int Vsprintf(void *buf, CharacterEncoding enc, const char *format,
599 va_list args)
600 {
601 int nchars;
602 FILE16 file = {.handle3 = -1, .write = StringWrite, .flush = StringFlush,
603 .close = StringClose, .flags = FILE16_write};
604
605 file.handle = buf;
606 file.enc = enc;
607
608 nchars = Vfprintf(&file, format, args);
609 file.close(&file); /* Fclose would try to free file */
610
611 return nchars;
612 }
613
Vsnprintf(void * buf,size_t size,CharacterEncoding enc,const char * format,va_list args)614 int Vsnprintf(void *buf, size_t size, CharacterEncoding enc,
615 const char *format, va_list args)
616 {
617 int nchars;
618 FILE16 file = {.handle3 = -1, .write = StringWriteTrunc,
619 .flush = StringFlush, .close = StringClose, .flags = FILE16_write};
620
621 file.handle = buf;
622 file.enc = enc;
623 file.handle3 = size - NullSize(enc); /* make sure we can null-terminate */
624
625 nchars = Vfprintf(&file, format, args);
626 file.handle3 = size; /* ready for null-termination */
627 file.close(&file); /* Fclose would try to free file */
628
629 return nchars;
630 }
631
632 #define put(x) {nchars++; if(count == sizeof(buf)) {if(ConvertASCII(buf, count, file) == -1) return -1; count = 0;} buf[count++] = x;}
633
Vfprintf(FILE16 * file,const char * format,va_list args)634 int Vfprintf(FILE16 *file, const char *format, va_list args)
635 {
636 char8 buf[BufferSize];
637 int count = 0;
638 int c, i, n, width, prec;
639 char fmt[200];
640 char8 val[200];
641 const char8 *start;
642 const char8 *p;
643 const char16 *q;
644 #if CHAR_SIZE == 16
645 char16 cbuf[1];
646 #endif
647 int mflag;
648 int l, h, L, ll;
649 int nchars = 0;
650
651 while((c = *format++))
652 {
653 if(c != '%')
654 {
655 put(c);
656 continue;
657 }
658
659 start = format-1;
660 width = 0;
661 prec = -1;
662 mflag=0;
663 l=0, h=0, L=0, ll=0;
664
665 while(1)
666 {
667 switch(c = *format++)
668 {
669 case '-':
670 mflag = 1;
671 break;
672 default:
673 goto flags_done;
674 }
675 }
676 flags_done:
677
678 if(c == '*')
679 {
680 width = va_arg(args, int);
681 c = *format++;
682 }
683 else if(c >= '0' && c <= '9')
684 {
685 width = c - '0';
686 while((c = *format++) >= '0' && c <= '9')
687 width = width * 10 + c - '0';
688 }
689
690 if(c == '.')
691 {
692 c = *format++;
693 if(c == '*')
694 {
695 prec = va_arg(args, int);
696 c = *format++;
697 }
698 else if(c >= '0' && c <= '9')
699 {
700 prec = c - '0';
701 while((c = *format++) >= '0' && c <= '9')
702 prec = prec * 10 + c - '0';
703 }
704 else
705 prec = 0;
706 }
707
708 switch(c)
709 {
710 case 'l':
711 l = 1;
712 c = *format++;
713 #ifdef HAVE_LONG_LONG
714 if(c == 'l')
715 {
716 l = 0;
717 ll = 1;
718 c = *format++;
719 }
720 #endif
721 break;
722 case 'h':
723 h = 1;
724 c = *format++;
725 break;
726 #ifdef HAVE_LONG_DOUBLE
727 case 'L':
728 L = 1;
729 c = *format++;
730 break;
731 #endif
732 }
733
734 if (format - start + 1 > (int)sizeof(fmt))
735 {
736 ERR("Printf: format specifier too long");
737 errno = 0;
738 return -1;
739 }
740
741 strncpy(fmt, start, format - start);
742 fmt[format - start] = '\0';
743
744 /* XXX should check it fits in val */
745
746 switch(c)
747 {
748 case 'n':
749 *va_arg(args, int *) = nchars;
750 break;
751 case 'd':
752 case 'i':
753 case 'o':
754 case 'u':
755 case 'x':
756 case 'X':
757 if(h)
758 sprintf(val, fmt, va_arg(args, int)); /* promoted to int */
759 else if(l)
760 sprintf(val, fmt, va_arg(args, long));
761 #ifdef HAVE_LONG_LONG
762 else if(ll)
763 sprintf(val, fmt, va_arg(args, long long));
764 #endif
765 else
766 sprintf(val, fmt, va_arg(args, int));
767 for(p=val; *p; p++)
768 put(*p);
769 break;
770 case 'f':
771 case 'e':
772 case 'E':
773 case 'g':
774 case 'G':
775 #ifdef HAVE_LONG_DOUBLE
776 if(L)
777 sprintf(val, fmt, va_arg(args, long double));
778 else
779 #endif
780 sprintf(val, fmt, va_arg(args, double));
781 for(p=val; *p; p++)
782 put(*p);
783 break;
784 case 'c':
785 #if CHAR_SIZE == 16
786 if(ConvertASCII(buf, count, file) == -1)
787 return -1;
788 count = 0;
789 cbuf[0] = va_arg(args, int);
790 if(ConvertUTF16(cbuf, 1, file) == -1)
791 return -1;
792 #else
793 put(va_arg(args, int));
794 #endif
795 break;
796 case 'p':
797 sprintf(val, fmt, va_arg(args, void *));
798 for(p=val; *p; p++)
799 put(*p);
800 break;
801 case '%':
802 put('%');
803 break;
804 case 's':
805 if(l)
806 {
807 static char16 sNULL[] = {'(','N','U','L','L',')',0};
808 #if CHAR_SIZE == 16
809 string:
810 #endif
811 q = va_arg(args, char16 *);
812 if(!q)
813 q = sNULL;
814 for(n=0; n != prec && q[n]; n++)
815 ;
816 if(n < width && !mflag)
817 for(i=width-n; i>0; i--)
818 put(' ');
819 if(ConvertASCII(buf, count, file) == -1)
820 return -1;
821 count = 0;
822 nchars += n;
823 for(i = n; i > 0; i -= BufferSize)
824 {
825 /* ConvertUTF16 can only handle <= BufferSize chars */
826 if(ConvertUTF16(q, i > BufferSize ? BufferSize : i, file) == -1)
827 return -1;
828 q += BufferSize;
829 }
830 }
831 else
832 {
833 #if CHAR_SIZE == 8
834 string:
835 #endif
836 p = va_arg(args, char8 *);
837 if(!p)
838 p = "(null)";
839 for(n=0; n != prec && p[n]; n++)
840 ;
841 if(n < width && !mflag)
842 for(i=width-n; i>0; i--)
843 put(' ');
844 for(i=0; i<n; i++)
845 put(p[i]);
846 }
847 if(n < width && mflag)
848 for(i=width-n; i>0; i--)
849 put(' ');
850 break;
851 case 'S':
852 goto string;
853 default:
854 ERR1("unknown format character %c\n", c);
855 errno = 0;
856 return -1;
857 }
858 }
859
860 if(count > 0)
861 if(ConvertASCII(buf, count, file) == -1)
862 return -1;
863
864 return nchars;
865 }
866
MakeFILE16(const char * type)867 static FILE16 *MakeFILE16(const char *type)
868 {
869 FILE16 *file;
870
871 if(!(file = Malloc(sizeof(*file))))
872 return 0;
873
874 file->flags = 0;
875 if(*type == 'r')
876 {
877 file->flags |= FILE16_read;
878 type++;
879 }
880 if(*type == 'w')
881 file->flags |= FILE16_write;
882
883 file->enc = InternalCharacterEncoding;
884
885 file->incount = file->inoffset = 0;
886
887 return file;
888 }
889
MakeFILE16FromFD(int fd,const char * type)890 FILE16 *MakeFILE16FromFD(int fd, const char *type)
891 {
892 FILE16 *file;
893
894 if(!(file = MakeFILE16(type)))
895 return 0;
896
897 #if defined(WIN32)
898 file->flags |= FILE16_crlf;
899 #endif
900
901 file->read = FDRead;
902 file->write = FDWrite;
903 file->seek = FDSeek;
904 file->close = FDClose;
905 file->flush = FDFlush;
906 file->handle2 = fd;
907
908 return file;
909 }
910
FDRead(FILE16 * file,unsigned char * buf,int max_count)911 static int FDRead(FILE16 *file, unsigned char *buf, int max_count)
912 {
913 int fd = file->handle2;
914 int count = 0;
915
916 count = read(fd, buf, max_count);
917
918 return count;
919 }
920
FDWrite(FILE16 * file,const unsigned char * buf,int count)921 static int FDWrite(FILE16 *file, const unsigned char *buf, int count)
922 {
923 int fd = file->handle2;
924 int ret;
925
926 while(count > 0)
927 {
928 ret = write(fd, buf, count);
929 if(ret < 0)
930 return ret;
931 count -= ret;
932 buf += ret;
933 }
934
935 return 0;
936 }
937
FDSeek(FILE16 * file,long offset,int ptrname)938 static int FDSeek(FILE16 *file, long offset, int ptrname)
939 {
940 int fd = file->handle2;
941
942 return lseek(fd, offset, ptrname);
943 }
944
FDClose(FILE16 * file)945 static int FDClose(FILE16 *file)
946 {
947 int fd = file->handle2;
948
949 return (file->flags & FILE16_close_underlying) ? close(fd) : 0;
950 }
951
FDFlush(FILE16 * file __unused)952 static int FDFlush(FILE16 *file __unused)
953 {
954 return 0;
955 }
956
MakeFILE16FromFILE(FILE * f,const char * type)957 FILE16 *MakeFILE16FromFILE(FILE *f, const char *type)
958 {
959 FILE16 *file;
960
961 if(!(file = MakeFILE16(type)))
962 return 0;
963
964 #if defined(WIN32)
965 /* We need to do Windows-style lf <-> crlf conversion ourselves,
966 because the standard i/o library doesn't know about 16-bit
967 characters. We don't want it to insert cr before output bytes
968 that just happen to look like linefeed, or change input byte
969 sequences that happen to look like crlf. */
970
971 file->flags |= FILE16_crlf;
972
973 /* So we have to switch the underlying file into binary mode, but
974 we probably don't want to automatically do that for Stdin/out/err
975 which are opened though the user may not want them (and may
976 want to keep stdin/out/err in text mode). So we just flag
977 it as needing to be switched when the first i/o is done. */
978
979 file->flags |= FILE16_needs_binary;
980 #endif
981
982 file->read = FileRead;
983 file->write = FileWrite;
984 file->seek = FileSeek;
985 file->close = FileClose;
986 file->flush = FileFlush;
987 file->handle = f;
988
989 return file;
990 }
991
FileRead(FILE16 * file,unsigned char * buf,int max_count)992 static int FileRead(FILE16 *file, unsigned char *buf, int max_count)
993 {
994 FILE *f = file->handle;
995 int count = 0;
996
997 #if defined(WIN32)
998 if(file->flags & FILE16_needs_binary)
999 {
1000 #ifdef __CYGWIN__
1001 setmode(fileno(f), _O_BINARY);
1002 #else
1003 _setmode(fileno(f), _O_BINARY);
1004 #endif
1005 file->flags &= ~FILE16_needs_binary;
1006 }
1007 #endif
1008
1009 /* Terminal EOF is sticky for fread() on Linux, even though feof() is true.
1010 How can they have got this wrong and never noticed it?
1011 So check feof() here.
1012 */
1013 if(feof(f))
1014 return 0;
1015
1016 count = fread(buf, 1, max_count, f);
1017
1018 return ferror(f) ? -1 : count;
1019 }
1020
FileWrite(FILE16 * file,const unsigned char * buf,int count)1021 static int FileWrite(FILE16 *file, const unsigned char *buf, int count)
1022 {
1023 FILE *f = file->handle;
1024
1025 #if defined(WIN32)
1026 if(file->flags & FILE16_needs_binary)
1027 {
1028 #ifdef __CYGWIN__
1029 setmode(fileno(f), _O_BINARY);
1030 #else
1031 _setmode(fileno(f), _O_BINARY);
1032 #endif
1033 file->flags &= ~FILE16_needs_binary;
1034 }
1035 #endif
1036
1037 if(count == 0)
1038 return 0;
1039 return fwrite(buf, 1, count, f) == 0 ? -1 : 0;
1040 }
1041
FileSeek(FILE16 * file,long offset,int ptrname)1042 static int FileSeek(FILE16 *file, long offset, int ptrname)
1043 {
1044 FILE *f = file->handle;
1045
1046 return fseek(f, offset, ptrname);
1047 }
1048
FileClose(FILE16 * file)1049 static int FileClose(FILE16 *file)
1050 {
1051 FILE *f = file->handle;
1052
1053 return (file->flags & FILE16_close_underlying) ? fclose(f) : 0;
1054 }
1055
FileFlush(FILE16 * file)1056 static int FileFlush(FILE16 *file)
1057 {
1058 FILE *f = file->handle;
1059
1060 return fflush(f);
1061 }
1062
MakeFILE16FromString(const void * buf,long size,const char * type)1063 FILE16 *MakeFILE16FromString(const void *buf, long size, const char *type)
1064 {
1065 FILE16 *file;
1066
1067 if(!(file = MakeFILE16(type)))
1068 return 0;
1069
1070 file->read = StringRead;
1071 file->write = StringWrite;
1072 file->seek = StringSeek;
1073 file->close = StringClose;
1074 file->flush = StringFlush;
1075
1076 file->chandle = buf;
1077 file->handle2 = 0;
1078 file->handle3 = size;
1079
1080 return file;
1081 }
1082
StringRead(FILE16 * file,unsigned char * buf,int max_count)1083 static int StringRead(FILE16 *file, unsigned char *buf, int max_count)
1084 {
1085 char *p = (char *)file->handle + file->handle2;
1086
1087 if(file->handle3 >= 0 && file->handle2 + max_count > file->handle3)
1088 max_count = file->handle3 - file->handle2;
1089
1090 if(max_count <= 0)
1091 return 0;
1092
1093 memcpy(buf, p, max_count);
1094 file->handle2 += max_count;
1095
1096 return max_count;
1097 }
1098
StringWrite(FILE16 * file,const unsigned char * buf,int count)1099 static int StringWrite(FILE16 *file, const unsigned char *buf, int count)
1100 {
1101 char *p = (char *)file->handle + file->handle2;
1102
1103 if(file->handle3 >= 0 && file->handle2 + count > file->handle3)
1104 return -1;
1105
1106 memcpy(p, buf, count);
1107 file->handle2 += count;
1108
1109 return 0;
1110 }
1111
1112 /* Like StringWrite, but ignores overflow rather than returning an error.
1113 Used for Vsnprintf. */
1114
StringWriteTrunc(FILE16 * file,const unsigned char * buf,int count)1115 static int StringWriteTrunc(FILE16 *file, const unsigned char *buf, int count)
1116 {
1117 char *p = (char *)file->handle + file->handle2;
1118
1119 if(file->handle3 >= 0 && file->handle2 + count > file->handle3)
1120 /* XXX This doesn't really work; a character might be truncated.
1121 Safe for fixed-size encodings if buffer size is a multiple
1122 of the character size. */
1123 count = file->handle3 - file->handle2;
1124
1125 memcpy(p, buf, count);
1126 file->handle2 += count;
1127
1128 return 0;
1129 }
1130
StringSeek(FILE16 * file,long offset,int ptrname)1131 static int StringSeek(FILE16 *file, long offset, int ptrname)
1132 {
1133 switch(ptrname)
1134 {
1135 case SEEK_CUR:
1136 offset = file->handle2 + offset;
1137 break;
1138 case SEEK_END:
1139 if(file->handle3 < 0)
1140 return -1;
1141 offset = file->handle3 + offset;
1142 break;
1143 }
1144
1145 if(file->handle3 >= 0 && offset > file->handle3)
1146 return -1;
1147
1148 file->handle2 = offset;
1149
1150 return 0;
1151 }
1152
StringClose(FILE16 * file)1153 static int StringClose(FILE16 *file)
1154 {
1155 static char8 null = 0;
1156
1157 if(file->flags & FILE16_write)
1158 ConvertASCII(&null, 1, file); /* null terminate */
1159
1160 if(file->flags & FILE16_close_underlying)
1161 Free((char *)file->handle);
1162
1163 return 0;
1164 }
1165
StringFlush(FILE16 * file __unused)1166 static int StringFlush(FILE16 *file __unused)
1167 {
1168 return 0;
1169 }
1170
1171
1172 #if defined(WIN32) && ! defined(__CYGWIN__)
1173 #ifdef SOCKETS_IMPLEMENTED
1174
MakeFILE16FromWinsock(int sock,const char * type)1175 FILE16 *MakeFILE16FromWinsock(int sock, const char *type)
1176 {
1177 FILE16 *file;
1178
1179 if(!(file = MakeFILE16(type)))
1180 return 0;
1181
1182 file->flags |= FILE16_crlf;
1183
1184 file->read = WinsockRead;
1185 file->write = WinsockWrite;
1186 file->seek = WinsockSeek;
1187 file->close = WinsockClose;
1188 file->flush = WinsockFlush;
1189 file->handle2 = sock;
1190
1191 return file;
1192 }
1193
WinsockRead(FILE16 * file,unsigned char * buf,int max_count)1194 static int WinsockRead(FILE16 *file, unsigned char *buf, int max_count)
1195 {
1196 int f = file->handle2;
1197 int count;
1198
1199 /* "Relax" said the nightman, we are programmed to recv() */
1200 count = recv(f, buf, max_count, 0);
1201
1202 return count;
1203 }
1204
WinsockWrite(FILE16 * file,const unsigned char * buf,int count)1205 static int WinsockWrite(FILE16 *file, const unsigned char *buf, int count)
1206 {
1207 int f = file->handle2;
1208
1209 return send(f, buf, count ,0);
1210 }
1211
WinsockSeek(FILE16 * file,long offset,int ptrname)1212 static int WinsockSeek(FILE16 *file, long offset, int ptrname)
1213 {
1214 return -1;
1215 }
1216
WinsockClose(FILE16 * file)1217 static int WinsockClose(FILE16 *file)
1218 {
1219 int f = file->handle2;
1220
1221 if(file->flags & FILE16_close_underlying)
1222 closesocket(f);
1223
1224 return 0;
1225 }
1226
WinsockFlush(FILE16 * file)1227 static int WinsockFlush(FILE16 *file)
1228 {
1229 return 0;
1230 }
1231
1232 #endif
1233 #endif
1234
1235 #ifdef HAVE_LIBZ
1236
MakeFILE16FromGzip(gzFile f,const char * type)1237 FILE16 *MakeFILE16FromGzip(gzFile f, const char *type)
1238 {
1239 FILE16 *file;
1240
1241 if(!(file = MakeFILE16(type)))
1242 return 0;
1243
1244 file->read = GzipRead;
1245 file->write = GzipWrite;
1246 file->seek = GzipSeek;
1247 file->close = GzipClose;
1248 file->flush = GzipFlush;
1249 file->handle = (void *)f;
1250
1251 return file;
1252 }
1253
GzipRead(FILE16 * file,unsigned char * buf,int max_count)1254 static int GzipRead(FILE16 *file, unsigned char *buf, int max_count)
1255 {
1256 gzFile f = (gzFile)file->handle;
1257 int count = 0;
1258 int gzerr;
1259 const char *errorString;
1260
1261 count = gzread(f, buf, max_count);
1262
1263 errorString = gzerror(f, &gzerr);
1264 if (gzerr != 0 && gzerr != Z_STREAM_END) {
1265 warnx("%s: %s", __func__, errorString);
1266 return -1;
1267 }
1268
1269 return count;
1270 }
1271
GzipWrite(FILE16 * file,const unsigned char * buf,int count)1272 static int GzipWrite(FILE16 *file, const unsigned char *buf, int count)
1273 {
1274 gzFile f = (gzFile)file->handle;
1275 int gzerr;
1276 const char *errorString;
1277
1278 count = gzwrite(f, buf, count);
1279
1280 errorString = gzerror(f, &gzerr);
1281 if (gzerr != 0 && gzerr != Z_STREAM_END) {
1282 warnx("%s: %s", __func__, errorString);
1283 return -1;
1284 }
1285
1286 return count;
1287 }
1288
GzipSeek(FILE16 * file __unused,long offset __unused,int ptrname __unused)1289 static int GzipSeek(FILE16 *file __unused, long offset __unused, int ptrname __unused)
1290 {
1291 return -1;
1292 }
1293
GzipClose(FILE16 * file)1294 static int GzipClose(FILE16 *file)
1295 {
1296 gzFile f = (gzFile)file->handle;
1297
1298 return (file->flags & FILE16_close_underlying) ? gzclose(f) : 0;
1299 }
1300
GzipFlush(FILE16 * file __unused)1301 static int GzipFlush(FILE16 *file __unused)
1302 {
1303 return 0;
1304 }
1305
1306 #endif
1307
1308 #ifdef test
1309
main(int argc,char ** argv)1310 int main(int argc, char **argv)
1311 {
1312 short s=3;
1313 int n, c;
1314 char16 S[] = {'w', 'o', 'r', 'l', 'd', ' ', '�' & 0xff, 0xd841, 0xdc42, 0};
1315
1316 n=Printf(argv[1], s, 98765432, &c, 5.3, 3.2L, "�hello", S);
1317 printf("\nreturned %d, c=%d\n", n, c);
1318 n=Printf(argv[1], s, 98765432, &c, 5.3, 3.2L, "�hello", S);
1319 printf("\nreturned %d, c=%d\n", n, c);
1320 n=Printf(argv[1], s, 98765432, &c, 5.3, 3.2L, "�hello", S);
1321 printf("\nreturned %d, c=%d\n", n, c);
1322 n=Printf(argv[1], s, 98765432, &c, 5.3, 3.2L, "�hello", S);
1323 printf("\nreturned %d, c=%d\n", n, c);
1324
1325 return 0;
1326 }
1327
1328 #endif
1329
1330