Edinburgh Speech Tools  2.4-release
 All Classes Functions Variables Typedefs Enumerations Enumerator Friends Pages
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 
70 typedef int ReadProc(FILE16 *file, unsigned char *buf, int max_count);
71 typedef int WriteProc(FILE16 *file, const unsigned char *buf, int count);
72 typedef int SeekProc(FILE16 *file, long offset, int ptrname);
73 typedef int FlushProc(FILE16 *file);
74 typedef int CloseProc(FILE16 *file);
75 
76 struct _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 
93 static int FileRead(FILE16 *file, unsigned char *buf, int max_count);
94 static int FileWrite(FILE16 *file, const unsigned char *buf, int count);
95 static int FileSeek(FILE16 *file, long offset, int ptrname);
96 static int FileClose(FILE16 *file);
97 static int FileFlush(FILE16 *file);
98 
99 static int StringRead(FILE16 *file, unsigned char *buf, int max_count);
100 static int StringWrite(FILE16 *file, const unsigned char *buf, int count);
101 static int StringSeek(FILE16 *file, long offset, int ptrname);
102 static int StringClose(FILE16 *file);
103 static int StringFlush(FILE16 *file);
104 
105 #ifdef WIN32
106 #ifdef SOCKETS_IMPLEMENTED
107 static int WinsockRead(FILE16 *file, unsigned char *buf, int max_count);
108 static int WinsockWrite(FILE16 *file, const unsigned char *buf, int count);
109 static int WinsockSeek(FILE16 *file, long offset, int ptrname);
110 static int WinsockClose(FILE16 *file);
111 static int WinsockFlush(FILE16 *file);
112 #endif
113 #endif
114 
115 #ifdef HAVE_LIBZ
116 static int GzipRead(FILE16 *file, unsigned char *buf, int max_count);
117 static int GzipWrite(FILE16 *file, const unsigned char *buf, int count);
118 static int GzipSeek(FILE16 *file, long offset, int ptrname);
119 static int GzipClose(FILE16 *file);
120 static int GzipFlush(FILE16 *file);
121 #endif
122 
123 FILE16 *Stdin, *Stdout, *Stderr;
124 
125 void 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 
134 static int ConvertASCII(const char8 *buf, int count, FILE16 *file);
135 static 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 
145 static 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 
208 static 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 
309 int Readu(FILE16 *file, unsigned char *buf, int max_count)
310 {
311  return file->read(file, buf, max_count);
312 }
313 
314 int Writeu(FILE16 *file, unsigned char *buf, int count)
315 {
316  return file->write(file, buf, count);
317 }
318 
319 int Fclose(FILE16 *file)
320 {
321  int ret = 0;
322 
323  ret = file->close(file);
324  Free(file);
325 
326  return ret;
327 }
328 
329 int Fseek(FILE16 *file, long offset, int ptrname)
330 {
331  return file->seek(file, offset, ptrname);
332 }
333 
334 int Fflush(FILE16 *file)
335 {
336  return file->flush(file);
337 }
338 
339 FILE *GetFILE(FILE16 *file)
340 {
341  if(file->read == FileRead)
342  return (FILE *)file->handle;
343  else
344  return 0;
345 }
346 
347 void 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 
355 void SetFileEncoding(FILE16 *file, CharacterEncoding encoding)
356 {
357  file->enc = encoding;
358 }
359 
360 CharacterEncoding GetFileEncoding(FILE16 *file)
361 {
362  return file->enc;
363 }
364 
365 int Fprintf(FILE16 *file, const char *format, ...)
366 {
367  va_list args;
368  va_start(args, format);
369  return Vfprintf(file, format, args);
370 }
371 
372 int Printf(const char *format, ...)
373 {
374  va_list args;
375  va_start(args, format);
376  return Vfprintf(Stdout, format, args);
377 }
378 
379 int 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 
386 int Vprintf(const char *format, va_list args)
387 {
388  return Vfprintf(Stdout, format, args);
389 }
390 
391 int 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 
408 int 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 
643 static 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 
661 FILE16 *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 
678 static 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 
688 static 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 
697 static int FileSeek(FILE16 *file, long offset, int ptrname)
698 {
699  FILE *f = file->handle;
700 
701  return fseek(f, offset, ptrname);
702 }
703 
704 static int FileClose(FILE16 *file)
705 {
706  FILE *f = file->handle;
707 
708  return (file->flags & FILE16_close_underlying) ? fclose(f) : 0;
709 }
710 
711 static int FileFlush(FILE16 *file)
712 {
713  FILE *f = file->handle;
714 
715  return fflush(f);
716 }
717 
718 FILE16 *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 
738 static 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 
754 static 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 
767 static 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 
789 static 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 
802 static int StringFlush(FILE16 *file)
803 {
804  return 0;
805 }
806 
807 
808 #ifdef WIN32
809 #ifdef SOCKETS_IMPLEMENTED
810 
811 FILE16 *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 
828 static 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 
839 static int WinsockWrite(FILE16 *file, const unsigned char *buf, int count)
840 {
841  /* Not yet implemented */
842 
843  return -1;
844 }
845 
846 static int WinsockSeek(FILE16 *file, long offset, int ptrname)
847 {
848  return -1;
849 }
850 
851 static int WinsockClose(FILE16 *file)
852 {
853  /* What should happen here? XXX */
854 
855  return 0;
856 }
857 
858 static int WinsockFlush(FILE16 *file)
859 {
860  return 0;
861 }
862 
863 #endif
864 #endif
865 
866 #ifdef HAVE_LIBZ
867 
868 FILE16 *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 
885 static 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 
901 static 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 
916 static int GzipSeek(FILE16 *file, long offset, int ptrname)
917 {
918  return -1;
919 }
920 
921 static int GzipClose(FILE16 *file)
922 {
923  gzFile f = (gzFile)file->handle;
924 
925  return (file->flags & FILE16_close_underlying) ? gzclose(f) : 0;
926 }
927 
928 static int GzipFlush(FILE16 *file)
929 {
930  return 0;
931 }
932 
933 #endif
934 
935 #ifdef test
936 
937 int 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