Edinburgh Speech Tools 2.4-release
stdio16.c
1/*************************************************************************/
2/* */
3/* Copyright (c) 1997-98 Richard Tobin, Language Technology Group, HCRC, */
4/* University of Edinburgh. */
5/* */
6/* THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, */
7/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
8/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
9/* IN NO EVENT SHALL THE AUTHOR OR THE UNIVERSITY OF EDINBURGH BE LIABLE */
10/* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF */
11/* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION */
12/* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
13/* */
14/*************************************************************************/
15/*
16 * An implementation of printf that
17 * - allows printing of 16-bit unicode characters and strings
18 * - translates output to a specified character set
19 *
20 * "char8" is 8 bits and contains ISO-Latin-1 (or ASCII) values
21 * "char16" is 16 bits and contains UTF-16 values
22 * "Char" is char8 or char16 depending on whether CHAR_SIZE is 8 or 16
23 *
24 * Author: Richard Tobin
25 */
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <stdarg.h>
31
32#ifdef FOR_LT
33
34#include "lt-memory.h"
35#include "nsl-err.h"
36
37#define ERR(m) LT_ERROR(NECHAR,m)
38#define ERR1(m,x) LT_ERROR1(NECHAR,m,x)
39#define ERR2(m,x,y) LT_ERROR2(NECHAR,m,x,y)
40
41#define Malloc salloc
42#define Realloc srealloc
43#define Free sfree
44
45#else
46
47#include "system.h"
48#define WIN_IMP
49
50#define ERR(m) fprintf(stderr,m)
51#define ERR1(m,x) fprintf(stderr,m,x)
52#define ERR2(m,x,y) fprintf(stderr,m,x,y)
53#endif
54
55#ifdef WIN32
56#undef boolean
57#include <winsock.h>
58#include <fcntl.h>
59#endif
60
61#include "charset.h"
62#include "string16.h"
63#include "stdio16.h"
64
65/* When we return -1 for non-io errors, we set errno to 0 to avoid confusion */
66#include <errno.h>
67
68#define BufferSize 4096
69
70typedef int ReadProc(FILE16 *file, unsigned char *buf, int max_count);
71typedef int WriteProc(FILE16 *file, const unsigned char *buf, int count);
72typedef int SeekProc(FILE16 *file, long offset, int ptrname);
73typedef int FlushProc(FILE16 *file);
74typedef int CloseProc(FILE16 *file);
75
76struct _FILE16 {
77 void *handle;
78 int handle2, handle3;
79 ReadProc *read;
80 WriteProc *write;
81 SeekProc *seek;
82 FlushProc *flush;
83 CloseProc *close;
84 int flags;
85 CharacterEncoding enc;
86 char16 save;
87};
88
89#define FILE16_read 0x01
90#define FILE16_write 0x02
91#define FILE16_close_underlying 0x04
92
93static int FileRead(FILE16 *file, unsigned char *buf, int max_count);
94static int FileWrite(FILE16 *file, const unsigned char *buf, int count);
95static int FileSeek(FILE16 *file, long offset, int ptrname);
96static int FileClose(FILE16 *file);
97static int FileFlush(FILE16 *file);
98
99static int StringRead(FILE16 *file, unsigned char *buf, int max_count);
100static int StringWrite(FILE16 *file, const unsigned char *buf, int count);
101static int StringSeek(FILE16 *file, long offset, int ptrname);
102static int StringClose(FILE16 *file);
103static int StringFlush(FILE16 *file);
104
105#ifdef WIN32
106#ifdef SOCKETS_IMPLEMENTED
107static int WinsockRead(FILE16 *file, unsigned char *buf, int max_count);
108static int WinsockWrite(FILE16 *file, const unsigned char *buf, int count);
109static int WinsockSeek(FILE16 *file, long offset, int ptrname);
110static int WinsockClose(FILE16 *file);
111static int WinsockFlush(FILE16 *file);
112#endif
113#endif
114
115#ifdef HAVE_LIBZ
116static int GzipRead(FILE16 *file, unsigned char *buf, int max_count);
117static int GzipWrite(FILE16 *file, const unsigned char *buf, int count);
118static int GzipSeek(FILE16 *file, long offset, int ptrname);
119static int GzipClose(FILE16 *file);
120static int GzipFlush(FILE16 *file);
121#endif
122
123FILE16 *Stdin, *Stdout, *Stderr;
124
125void init_stdio16(void) {
126 Stdin = MakeFILE16FromFILE(stdin, "r");
127 SetFileEncoding(Stdin, CE_ISO_8859_1);
128 Stdout = MakeFILE16FromFILE(stdout, "w");
129 SetFileEncoding(Stdout, CE_ISO_8859_1);
130 Stderr = MakeFILE16FromFILE(stderr, "w");
131 SetFileEncoding(Stderr, CE_ISO_8859_1);
132}
133
134static int ConvertASCII(const char8 *buf, int count, FILE16 *file);
135static int ConvertUTF16(const char16 *buf, int count, FILE16 *file);
136
137/* Output an ASCII buffer in the specified encoding */
138
139/* In fact, we don't translate the buffer at all if we are outputting
140 an 8-bit encoding, and we treat it as Latin-1 is we are outputting
141 a 16-bit encoding. This means that all the various ASCII supersets
142 will be passed through unaltered in the usual case, since we don't
143 translate them on input either. */
144
145static int ConvertASCII(const char8 *buf, int count, FILE16 *file)
146{
147 unsigned char outbuf[BufferSize*2];
148 int i, j;
149
150 switch(file->enc)
151 {
152 case CE_ISO_8859_1:
153 case CE_ISO_8859_2:
154 case CE_ISO_8859_3:
155 case CE_ISO_8859_4:
156 case CE_ISO_8859_5:
157 case CE_ISO_8859_6:
158 case CE_ISO_8859_7:
159 case CE_ISO_8859_8:
160 case CE_ISO_8859_9:
161 case CE_unspecified_ascii_superset:
162 return file->write(file, (unsigned char *)buf, count);
163
164 case CE_UTF_8:
165 for(i=j=0; i<count; i++)
166 {
167 unsigned char c = buf[i];
168 if(c < 128)
169 outbuf[j++] = c;
170 else
171 {
172 outbuf[j++] = 0xc0 + (c >> 6);
173 outbuf[j++] = 0x80 + (c & 0x3f);
174 }
175 }
176 return file->write(file, outbuf, j);
177
178 case CE_UTF_16B:
179 case CE_ISO_10646_UCS_2B:
180 for(i=j=0; i<count; i++)
181 {
182 outbuf[j++] = 0;
183 outbuf[j++] = buf[i];
184 }
185 return file->write(file, outbuf, count*2);
186
187 case CE_UTF_16L:
188 case CE_ISO_10646_UCS_2L:
189 for(i=j=0; i<count; i++)
190 {
191 outbuf[j++] = buf[i];
192 outbuf[j++] = 0;
193 }
194 return file->write(file, outbuf, count*2);
195
196 default:
197 ERR2("Bad output character encoding %d (%s)\n",
198 file->enc,
199 file->enc < CE_enum_count ? CharacterEncodingName[file->enc] :
200 "unknown");
201 errno = 0;
202 return -1;
203 }
204}
205
206/* Output a UTF-16 buffer in the specified encoding */
207
208static int ConvertUTF16(const char16 *buf, int count, FILE16 *file)
209{
210 /* size is max for UTF-8 with saved first half */
211 unsigned char outbuf[BufferSize*3 + 1];
212 int i, j, tablenum, max;
213 char8 *from_unicode;
214 char32 big;
215
216 switch(file->enc)
217 {
218 case CE_ISO_8859_1:
219 case CE_unspecified_ascii_superset:
220 for(i=0; i<count; i++)
221 {
222 if(buf[i] < 256)
223 outbuf[i] = (unsigned char)buf[i];
224 else
225 outbuf[i] = '?';
226 }
227 return file->write(file, outbuf, count);
228
229 case CE_ISO_8859_2:
230 case CE_ISO_8859_3:
231 case CE_ISO_8859_4:
232 case CE_ISO_8859_5:
233 case CE_ISO_8859_6:
234 case CE_ISO_8859_7:
235 case CE_ISO_8859_8:
236 case CE_ISO_8859_9:
237 tablenum = (file->enc - CE_ISO_8859_2);
238 max = iso_max_val[tablenum];
239 from_unicode = unicode_to_iso[tablenum];
240 for(i=0; i<count; i++)
241 {
242 if(buf[i] <= max)
243 outbuf[i] = (unsigned char)from_unicode[buf[i]];
244 else
245 outbuf[i] = '?';
246 }
247 return file->write(file, outbuf, count);
248
249 case CE_UTF_8:
250 for(i=j=0; i<count; i++)
251 {
252 if(buf[i] < 0x80)
253 outbuf[j++] = (unsigned char)buf[i];
254 else if(buf[i] < 0x800)
255 {
256 outbuf[j++] = 0xc0 + (buf[i] >> 6);
257 outbuf[j++] = 0x80 + (buf[i] & 0x3f);
258 }
259 else if(buf[i] >= 0xd800 && buf[i] <= 0xdbff)
260 file->save = buf[i];
261 else if(buf[i] >= 0xdc00 && buf[i] <= 0xdfff)
262 {
263 big = 0x10000 +
264 ((file->save - 0xd800) << 10) + (buf[i] - 0xdc00);
265 outbuf[j++] = 0xf0 + (big >> 18);
266 outbuf[j++] = 0x80 + ((big >> 12) & 0x3f);
267 outbuf[j++] = 0x80 + ((big >> 6) & 0x3f);
268 outbuf[j++] = 0x80 + (big & 0x3f);
269 }
270 else
271 {
272 outbuf[j++] = 0xe0 + (buf[i] >> 12);
273 outbuf[j++] = 0x80 + ((buf[i] >> 6) & 0x3f);
274 outbuf[j++] = 0x80 + (buf[i] & 0x3f);
275 }
276 }
277 return file->write(file, outbuf, j);
278
279 case CE_UTF_16B:
280 case CE_ISO_10646_UCS_2B:
281 for(i=j=0; i<count; i++)
282 {
283 outbuf[j++] = (buf[i] >> 8);
284 outbuf[j++] = (buf[i] & 0xff);
285
286 }
287 return file->write(file, outbuf, count*2);
288
289 case CE_UTF_16L:
290 case CE_ISO_10646_UCS_2L:
291 for(i=j=0; i<count; i++)
292 {
293 outbuf[j++] = (buf[i] & 0xff);
294 outbuf[j++] = (buf[i] >> 8);
295
296 }
297 return file->write(file, outbuf, count*2);
298
299 default:
300 ERR2("Bad output character encoding %d (%s)\n",
301 file->enc,
302 file->enc < CE_enum_count ? CharacterEncodingName[file->enc] :
303 "unknown");
304 errno = 0;
305 return -1;
306 }
307}
308
309int Readu(FILE16 *file, unsigned char *buf, int max_count)
310{
311 return file->read(file, buf, max_count);
312}
313
314int Writeu(FILE16 *file, unsigned char *buf, int count)
315{
316 return file->write(file, buf, count);
317}
318
319int Fclose(FILE16 *file)
320{
321 int ret = 0;
322
323 ret = file->close(file);
324 Free(file);
325
326 return ret;
327}
328
329int Fseek(FILE16 *file, long offset, int ptrname)
330{
331 return file->seek(file, offset, ptrname);
332}
333
334int Fflush(FILE16 *file)
335{
336 return file->flush(file);
337}
338
339FILE *GetFILE(FILE16 *file)
340{
341 if(file->read == FileRead)
342 return (FILE *)file->handle;
343 else
344 return 0;
345}
346
347void SetCloseUnderlying(FILE16 *file, int cu)
348{
349 if(cu)
350 file->flags |= FILE16_close_underlying;
351 else
352 file->flags &= ~FILE16_close_underlying;
353}
354
355void SetFileEncoding(FILE16 *file, CharacterEncoding encoding)
356{
357 file->enc = encoding;
358}
359
360CharacterEncoding GetFileEncoding(FILE16 *file)
361{
362 return file->enc;
363}
364
365int Fprintf(FILE16 *file, const char *format, ...)
366{
367 va_list args;
368 va_start(args, format);
369 return Vfprintf(file, format, args);
370}
371
372int Printf(const char *format, ...)
373{
374 va_list args;
375 va_start(args, format);
376 return Vfprintf(Stdout, format, args);
377}
378
379int Sprintf(void *buf, CharacterEncoding enc, const char *format, ...)
380{
381 va_list args;
382 va_start(args, format);
383 return Vsprintf(buf, enc, format, args);
384}
385
386int Vprintf(const char *format, va_list args)
387{
388 return Vfprintf(Stdout, format, args);
389}
390
391int Vsprintf(void *buf, CharacterEncoding enc, const char *format,
392 va_list args)
393{
394 int nchars;
395 FILE16 file = {0, 0, -1, StringRead, StringWrite, StringSeek, StringFlush, StringClose, FILE16_write};
396
397 file.handle = buf;
398 file.enc = enc;
399
400 nchars = Vfprintf(&file, format, args);
401 file.close(&file); /* Fclose would try to free it */
402
403 return nchars;
404}
405
406#define put(x) {nchars++; if(count == sizeof(buf)) {if(ConvertASCII(buf, count, file) == -1) return -1; count = 0;} buf[count++] = x;}
407
408int Vfprintf(FILE16 *file, const char *format, va_list args)
409{
410 char8 buf[BufferSize];
411 int count = 0;
412 int c, i, n, width, prec;
413 char fmt[200];
414 char8 val[200];
415 const char8 *start;
416 const char8 *p;
417 const char16 *q;
418 char16 cbuf[1];
419 int mflag, pflag, sflag, hflag, zflag;
420 int l, h, L;
421 int nchars = 0;
422
423 while((c = *format++))
424 {
425 if(c != '%')
426 {
427 put(c);
428 continue;
429 }
430
431 start = format-1;
432 width = 0;
433 prec = -1;
434 mflag=0, pflag=0, sflag=0, hflag=0, zflag=0;
435 l=0, h=0, L=0;
436
437 while(1)
438 {
439 switch(c = *format++)
440 {
441 case '-':
442 mflag = 1;
443 break;
444 case '+':
445 pflag = 1;
446 break;
447 case ' ':
448 sflag = 1;
449 break;
450 case '#':
451 hflag = 1;
452 break;
453 case '0':
454 zflag = 1;
455 break;
456 default:
457 goto flags_done;
458 }
459 }
460 flags_done:
461
462 if(c == '*')
463 {
464 width = va_arg(args, int);
465 c = *format++;
466 }
467 else if(c >= '0' && c <= '9')
468 {
469 width = c - '0';
470 while((c = *format++) >= '0' && c <= '9')
471 width = width * 10 + c - '0';
472 }
473
474 if(c == '.')
475 {
476 c = *format++;
477 if(c == '*')
478 {
479 prec = va_arg(args, int);
480 c = *format++;
481 }
482 else if(c >= '0' && c <= '9')
483 {
484 prec = c - '0';
485 while((c = *format++) >= '0' && c <= '9')
486 prec = prec * 10 + c - '0';
487 }
488 else
489 prec = 0;
490 }
491
492 switch(c)
493 {
494 case 'l':
495 l = 1;
496 c = *format++;
497 break;
498 case 'h':
499 h = 1;
500 c = *format++;
501 break;
502#ifdef HAVE_LONG_DOUBLE
503 case 'L':
504 L = 1;
505 c = *format++;
506 break;
507#endif
508 }
509
510 if(format - start + 1 > sizeof(fmt))
511 {
512 ERR("Printf: format specifier too long");
513 errno = 0;
514 return -1;
515 }
516
517 strncpy(fmt, start, format - start);
518 fmt[format - start] = '\0';
519
520 /* XXX should check it fits in val */
521
522 switch(c)
523 {
524 case 'n':
525 *va_arg(args, int *) = nchars;
526 break;
527 case 'd':
528 case 'i':
529 case 'o':
530 case 'u':
531 case 'x':
532 case 'X':
533 if(h)
534 sprintf(val, fmt, va_arg(args, int)); /* promoted to int */
535 else if(l)
536 sprintf(val, fmt, va_arg(args, long));
537 else
538 sprintf(val, fmt, va_arg(args, int));
539 for(p=val; *p; p++)
540 put(*p);
541 break;
542 case 'f':
543 case 'e':
544 case 'E':
545 case 'g':
546 case 'G':
547#ifdef HAVE_LONG_DOUBLE
548 if(L)
549 sprintf(val, fmt, va_arg(args, long double));
550 else
551#endif
552 sprintf(val, fmt, va_arg(args, double));
553 for(p=val; *p; p++)
554 put(*p);
555 break;
556 case 'c':
557#if CHAR_SIZE == 16
558 if(ConvertASCII(buf, count, file) == -1)
559 return -1;
560 count = 0;
561 cbuf[0] = va_arg(args, int);
562 if(ConvertUTF16(cbuf, 1, file) == -1)
563 return -1;
564#else
565 (void)cbuf;
566 put(va_arg(args, int));
567#endif
568 break;
569 case 'p':
570 sprintf(val, fmt, va_arg(args, void *));
571 for(p=val; *p; p++)
572 put(*p);
573 break;
574 case '%':
575 put('%');
576 break;
577 case 's':
578 if(l)
579 {
580 static char16 sNULL[] = {'(','N','U','L','L',')',0};
581#if CHAR_SIZE == 16
582 string:
583#endif
584 q = va_arg(args, char16 *);
585 if(!q)
586 q = sNULL;
587 n = strlen16(q);
588 if(prec >= 0 && n > prec)
589 n = prec;
590 if(n < width && !mflag)
591 for(i=width-n; i>0; i--)
592 put(' ');
593 if(ConvertASCII(buf, count, file) == -1)
594 return -1;
595 count = 0;
596 nchars += n;
597 while(n > 0)
598 {
599 /* ConvertUTF16 can only handle <= BufferSize chars */
600 if(ConvertUTF16(q, n > BufferSize ? BufferSize : n, file) == -1)
601 return -1;
602 n -= BufferSize;
603 q += BufferSize;
604 }
605 }
606 else
607 {
608#if CHAR_SIZE == 8
609 string:
610#endif
611 p = va_arg(args, char8 *);
612 if(!p)
613 p = "(null)";
614 n = strlen(p);
615 if(prec >= 0 && n > prec)
616 n = prec;
617 if(n < width && !mflag)
618 for(i=width-n; i>0; i--)
619 put(' ');
620 for(i=0; i<n; i++)
621 put(p[i]);
622 }
623 if(n < width && mflag)
624 for(i=width-n; i>0; i--)
625 put(' ');
626 break;
627 case 'S':
628 goto string;
629 default:
630 ERR1("unknown format character %c\n", c);
631 errno = 0;
632 return -1;
633 }
634 }
635
636 if(count > 0)
637 if(ConvertASCII(buf, count, file) == -1)
638 return -1;
639
640 return nchars;
641}
642
643static FILE16 *MakeFILE16(const char *type)
644{
645 FILE16 *file;
646
647 if(!(file = Malloc(sizeof(*file))))
648 return 0;
649
650 file->flags = 0;
651 if(*type == 'r')
652 file->flags |= FILE16_read;
653 else
654 file->flags |= FILE16_write;
655
656 file->enc = InternalCharacterEncoding;
657
658 return file;
659}
660
661FILE16 *MakeFILE16FromFILE(FILE *f, const char *type)
662{
663 FILE16 *file;
664
665 if(!(file = MakeFILE16(type)))
666 return 0;
667
668 file->read = FileRead;
669 file->write = FileWrite;
670 file->seek = FileSeek;
671 file->close = FileClose;
672 file->flush = FileFlush;
673 file->handle = f;
674
675 return file;
676}
677
678static int FileRead(FILE16 *file, unsigned char *buf, int max_count)
679{
680 FILE *f = file->handle;
681 int count = 0;
682
683 count = fread(buf, 1, max_count, f);
684
685 return ferror(f) ? -1 : count;
686}
687
688static int FileWrite(FILE16 *file, const unsigned char *buf, int count)
689{
690 FILE *f = file->handle;
691
692 if(count == 0)
693 return 0;
694 return fwrite(buf, 1, count, f) == 0 ? -1 : 0;
695}
696
697static int FileSeek(FILE16 *file, long offset, int ptrname)
698{
699 FILE *f = file->handle;
700
701 return fseek(f, offset, ptrname);
702}
703
704static int FileClose(FILE16 *file)
705{
706 FILE *f = file->handle;
707
708 return (file->flags & FILE16_close_underlying) ? fclose(f) : 0;
709}
710
711static int FileFlush(FILE16 *file)
712{
713 FILE *f = file->handle;
714
715 return fflush(f);
716}
717
718FILE16 *MakeFILE16FromString(void *buf, long size, const char *type)
719{
720 FILE16 *file;
721
722 if(!(file = MakeFILE16(type)))
723 return 0;
724
725 file->read = StringRead;
726 file->write = StringWrite;
727 file->seek = StringSeek;
728 file->close = StringClose;
729 file->flush = StringFlush;
730
731 file->handle = buf;
732 file->handle2 = 0;
733 file->handle3 = size;
734
735 return file;
736}
737
738static int StringRead(FILE16 *file, unsigned char *buf, int max_count)
739{
740 char *p = (char *)file->handle + file->handle2;
741
742 if(file->handle3 >= 0 && file->handle2 + max_count > file->handle3)
743 max_count = file->handle3 - file->handle2;
744
745 if(max_count <= 0)
746 return 0;
747
748 memcpy(buf, p, max_count);
749 file->handle2 += max_count;
750
751 return max_count;
752}
753
754static int StringWrite(FILE16 *file, const unsigned char *buf, int count)
755{
756 char *p = (char *)file->handle + file->handle2;
757
758 if(file->handle3 >= 0 && file->handle2 + count > file->handle3)
759 return -1;
760
761 memcpy(p, buf, count);
762 file->handle2 += count;
763
764 return 0;
765}
766
767static int StringSeek(FILE16 *file, long offset, int ptrname)
768{
769 switch(ptrname)
770 {
771 case SEEK_CUR:
772 offset = file->handle2 + offset;
773 break;
774 case SEEK_END:
775 if(file->handle3 < 0)
776 return -1;
777 offset = file->handle3 + offset;
778 break;
779 }
780
781 if(file->handle3 >= 0 && offset > file->handle3)
782 return -1;
783
784 file->handle2 = offset;
785
786 return 0;
787}
788
789static int StringClose(FILE16 *file)
790{
791 static char8 null = 0;
792
793 if(file->flags & FILE16_write)
794 ConvertASCII(&null, 1, file); /* null terminate */
795
796 if(file->flags & FILE16_close_underlying)
797 Free((char *)file->handle);
798
799 return 0;
800}
801
802static int StringFlush(FILE16 *file)
803{
804 return 0;
805}
806
807
808#ifdef WIN32
809#ifdef SOCKETS_IMPLEMENTED
810
811FILE16 *MakeFILE16FromWinsock(int sock, const char *type)
812{
813 FILE16 *file;
814
815 if(!(file = MakeFILE16(type)))
816 return 0;
817
818 file->read = WinsockRead;
819 file->write = WinsockWrite;
820 file->seek = WinsockSeek;
821 file->close = WinsockClose;
822 file->flush = WinsockFlush;
823 file->handle2 = sock;
824
825 return file;
826}
827
828static int WinsockRead(FILE16 *file, unsigned char *buf, int max_count)
829{
830 int f = (int)file->handle2;
831 int count;
832
833 /* "Relax" said the nightman, we are programmed to recv() */
834 count = recv(f, buf, max_count, 0);
835
836 return count;
837}
838
839static int WinsockWrite(FILE16 *file, const unsigned char *buf, int count)
840{
841 /* Not yet implemented */
842
843 return -1;
844}
845
846static int WinsockSeek(FILE16 *file, long offset, int ptrname)
847{
848 return -1;
849}
850
851static int WinsockClose(FILE16 *file)
852{
853 /* What should happen here? XXX */
854
855 return 0;
856}
857
858static int WinsockFlush(FILE16 *file)
859{
860 return 0;
861}
862
863#endif
864#endif
865
866#ifdef HAVE_LIBZ
867
868FILE16 *MakeFILE16FromGzip(gzFile f, const char *type)
869{
870 FILE16 *file;
871
872 if(!(file = MakeFILE16(type)))
873 return 0;
874
875 file->read = GzipRead;
876 file->write = GzipWrite;
877 file->seek = GzipSeek;
878 file->close = GzipClose;
879 file->flush = GzipFlush;
880 file->handle = (void *)f;
881
882 return file;
883}
884
885static int GzipRead(FILE16 *file, unsigned char *buf, int max_count)
886{
887 gzFile f = (gzFile)file->handle;
888 int count = 0;
889 int gzerr;
890 const char *errorString;
891
892 count = gzread(f, buf, max_count);
893
894 errorString = gzerror(f, &gzerr);
895 if(gzerr != 0 && gzerr != Z_STREAM_END)
896 return -1;
897
898 return count;
899}
900
901static int GzipWrite(FILE16 *file, const unsigned char *buf, int count)
902{
903 gzFile f = (gzFile)file->handle;
904 int gzerr;
905 const char *errorString;
906
907 count = gzwrite(f, (char *)buf, count);
908
909 errorString = gzerror(f, &gzerr);
910 if(gzerr != 0 && gzerr != Z_STREAM_END)
911 return -1;
912
913 return count;
914}
915
916static int GzipSeek(FILE16 *file, long offset, int ptrname)
917{
918 return -1;
919}
920
921static int GzipClose(FILE16 *file)
922{
923 gzFile f = (gzFile)file->handle;
924
925 return (file->flags & FILE16_close_underlying) ? gzclose(f) : 0;
926}
927
928static int GzipFlush(FILE16 *file)
929{
930 return 0;
931}
932
933#endif
934
935#ifdef test
936
937int main(int argc, char **argv)
938{
939 short s=3;
940 int n, c;
941 char16 S[] = {'w', 'o', 'r', 'l', 'd', ' ', '£' & 0xff, 0xd841, 0xdc42, 0};
942
943 n=Printf(argv[1], s, 98765432, &c, 5.3, 3.2L, "÷hello", S);
944 printf("\nreturned %d, c=%d\n", n, c);
945 n=Printf(argv[1], s, 98765432, &c, 5.3, 3.2L, "÷hello", S);
946 printf("\nreturned %d, c=%d\n", n, c);
947 n=Printf(argv[1], s, 98765432, &c, 5.3, 3.2L, "÷hello", S);
948 printf("\nreturned %d, c=%d\n", n, c);
949 n=Printf(argv[1], s, 98765432, &c, 5.3, 3.2L, "÷hello", S);
950 printf("\nreturned %d, c=%d\n", n, c);
951
952 return 0;
953}
954
955#endif
956