1 /* $Id$
2
3 Part of SWI-Prolog
4
5 Author: Jan Wielemaker
6 E-mail: J.Wielemaker@uva.nl
7 WWW: http://www.swi-prolog.org
8 Copyright (C): 1985-2009, University of Amsterdam
9
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2.1 of the License, or (at your option) any later version.
14
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
19
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24
25 #ifdef __MINGW32__
26 #define __WINDOWS__ 1
27 #endif
28
29 #ifdef __WINDOWS__
30 #include <uxnt/uxnt.h>
31 #ifdef __MINGW32__
32 #include "config.h"
33 #include <windows.h>
34 #else
35 #ifdef WIN64
36 #define MD "config/win64.h"
37 #else
38 #define MD "config/win32.h"
39 #endif
40 #endif
41 #include <winsock2.h>
42 #include "pl-mswchar.h"
43 #define CRLF_MAPPING 1
44 #endif
45
46 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
47 This modules defines the SWI-Prolog I/O streams. These streams are
48 provided to gain common access to any type of character data: files,
49 stdio streams, but also resources, strings, XPCE objects, etc.
50
51 MT:
52
53 Multithreading is supported through Slock() and Sunlock(). These are
54 recursive locks. If a stream handle might be known to another thread
55 locking is required.
56 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
57
58 #ifdef MD
59 #include MD
60 #else
61 #include <config.h>
62 #endif
63
64 #if _FILE_OFFSET_BITS == 64 || defined(_LARGE_FILES)
65 #define O_LARGEFILES 1 /* use for conditional code in Prolog */
66 #else
67 #undef O_LARGEFILES
68 #endif
69
70 #define PL_KERNEL 1
71 #include <wchar.h>
72 typedef wchar_t pl_wchar_t;
73 #include "SWI-Stream.h"
74 #include "pl-utf8.h"
75 #include <sys/types.h>
76 #ifdef HAVE_SYS_TIME_H
77 #include <sys/time.h>
78 #else
79 #include <time.h>
80 #endif
81 #include <errno.h>
82 #ifdef HAVE_MALLOC_H
83 #include <malloc.h>
84 #else
85 #ifdef HAVE_SYS_MALLOC_H
86 #include <sys/malloc.h>
87 #endif
88 #endif
89 #include <memory.h>
90 #include <string.h>
91 #include <fcntl.h>
92 #include <stdlib.h>
93 #include <limits.h>
94 #include <stdarg.h>
95 #include <ctype.h>
96 #include <sys/stat.h>
97 #ifdef HAVE_SYS_SELECT_H
98 #include <sys/select.h>
99 #endif
100 #ifdef HAVE_UNISTD_H
101 #include <unistd.h>
102 #endif
103 #include <stdio.h> /* sprintf() for numeric values */
104 #include <assert.h>
105 #ifdef SYSLIB_H
106 #include SYSLIB_H
107 #endif
108
109 #ifndef MB_LEN_MAX
110 #define MB_LEN_MAX 6
111 #endif
112
113 #define ROUND(p, n) ((((p) + (n) - 1) & ~((n) - 1)))
114 #define UNDO_SIZE ROUND(MB_LEN_MAX, sizeof(wchar_t))
115
116 #ifndef FALSE
117 #define FALSE 0
118 #endif
119 #ifndef TRUE
120 #define TRUE 1
121 #endif
122
123 #define char_to_int(c) (0xff & (int)(c))
124
125 #define TMPBUFSIZE 256 /* Serror bufsize for Svfprintf() */
126
127 int Slinesize = SIO_LINESIZE; /* Sgets() buffer size */
128
129 static ssize_t S__flushbuf(IOSTREAM *s);
130 static void run_close_hooks(IOSTREAM *s);
131 static int S__removebuf(IOSTREAM *s);
132 static int S__seterror(IOSTREAM *s);
133
134 #ifdef O_PLMT
135 #define SLOCK(s) if ( s->mutex ) recursiveMutexLock(s->mutex)
136 #define SUNLOCK(s) if ( s->mutex ) recursiveMutexUnlock(s->mutex)
137 inline int
STRYLOCK(IOSTREAM * s)138 STRYLOCK(IOSTREAM *s)
139 { if ( s->mutex &&
140 recursiveMutexTryLock(s->mutex) == EBUSY )
141 return FALSE;
142
143 return TRUE;
144 }
145 #else
146 #define SLOCK(s)
147 #define SUNLOCK(s)
148 #define STRYLOCK(s) (TRUE)
149 #endif
150
151 #include "pl-error.h"
152 typedef void *record_t;
153 typedef intptr_t term_t;
154
155 extern int fatalError(const char *fm, ...);
156 extern int PL_error(const char *pred, int arity,
157 const char *msg, int id, ...);
158 extern int PL_handle_signals(void);
159 extern IOENC initEncoding(void);
160 extern int reportStreamError(IOSTREAM *s);
161 extern record_t PL_record(term_t t);
162 extern int PL_thread_self(void);
163
164
165 /*******************************
166 * BUFFER *
167 *******************************/
168
169 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
170 Note that the buffer is allocated from s->unbuffer, which starts
171 UNDO_SIZE before s->buffer, so we can always push-back a wide
172 character into a multibyte stream. We do not do this for SIO_USERBUF
173 case, but this is only used by the output stream Svfprintf() where it is
174 not needed.
175 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
176
177 static size_t
S__setbuf(IOSTREAM * s,char * buffer,size_t size)178 S__setbuf(IOSTREAM *s, char *buffer, size_t size)
179 { char *newbuf, *newunbuf;
180 int newflags = s->flags;
181
182 if ( size == 0 )
183 size = SIO_BUFSIZE;
184
185 if ( (s->flags & SIO_OUTPUT) )
186 { if ( S__removebuf(s) < 0 )
187 return -1;
188 }
189
190 if ( buffer )
191 { newunbuf = newbuf = buffer;
192 newflags |= SIO_USERBUF;
193 } else
194 { if ( !(newunbuf = malloc(size+UNDO_SIZE)) )
195 { errno = ENOMEM;
196 return -1;
197 }
198 newflags &= ~SIO_USERBUF;
199 newbuf = newunbuf + UNDO_SIZE;
200 }
201
202 if ( (s->flags & SIO_INPUT) )
203 { size_t buffered = s->limitp - s->bufp;
204 size_t copy = (buffered < size ? buffered : size);
205
206 if ( size < buffered )
207 { size_t offset = size - buffered;
208 int64_t newpos;
209
210 if ( s->functions->seek64 )
211 { newpos = (*s->functions->seek64)(s->handle, offset, SIO_SEEK_CUR);
212 } else if ( s->functions->seek )
213 { newpos = (*s->functions->seek)(s->handle, (long)offset, SIO_SEEK_CUR);
214 } else
215 { newpos = -1;
216 errno = ESPIPE;
217 }
218
219 if ( newpos == -1 )
220 { if ( !(newflags & SIO_USERBUF) )
221 { int oldeno = errno;
222
223 free(newunbuf);
224 errno = oldeno;
225 S__seterror(s);
226 return -1;
227 }
228 }
229 }
230
231 memcpy(newbuf, s->bufp, copy);
232 S__removebuf(s);
233 s->unbuffer = newunbuf;
234 s->bufp = s->buffer = newbuf;
235 s->limitp = s->buffer+copy;
236 } else
237 { s->unbuffer = newunbuf;
238 s->bufp = s->buffer = newbuf;
239 s->limitp = &s->buffer[size];
240 }
241 s->bufsize = (int)size;
242 s->flags = newflags;
243
244 return size;
245 }
246
247
248 void
Ssetbuffer(IOSTREAM * s,char * buffer,size_t size)249 Ssetbuffer(IOSTREAM *s, char *buffer, size_t size)
250 { if ( S__setbuf(s, buffer, size) != (size_t)-1 )
251 s->flags &= ~SIO_USERBUF;
252 }
253
254
255 static int
S__removebuf(IOSTREAM * s)256 S__removebuf(IOSTREAM *s)
257 { if ( s->buffer && s->unbuffer )
258 { int rval = 0;
259
260 if ( (s->flags & SIO_OUTPUT) && S__flushbuf(s) < 0 )
261 rval = -1;
262
263 if ( !(s->flags & SIO_USERBUF) )
264 free(s->unbuffer);
265 s->bufp = s->limitp = s->buffer = s->unbuffer = NULL;
266 s->bufsize = 0;
267
268 return rval;
269 }
270
271 return 0;
272 }
273
274
275 #ifdef DEBUG_IO_LOCKS
276 static char *
Sname(IOSTREAM * s)277 Sname(IOSTREAM *s)
278 { if ( s == Serror ) return "error";
279 if ( s == Sinput ) return "input";
280 if ( s == Soutput ) return "output";
281 return "?";
282 }
283
284
285 #include <execinfo.h>
286 #include <string.h>
287
288 static void
print_trace(void)289 print_trace(void)
290 { void *array[7];
291 size_t size;
292 char **strings;
293 size_t i;
294
295 size = backtrace(array, sizeof(array)/sizeof(void *));
296 strings = backtrace_symbols(array, size);
297
298 printf(" Stack:");
299 for(i = 1; i < size; i++)
300 { printf("\n\t[%ld] %s", (long)i, strings[i]);
301 }
302 printf("\n");
303
304 free(strings);
305 }
306 #endif /*DEBUG_IO_LOCKS*/
307
308
309 int
Slock(IOSTREAM * s)310 Slock(IOSTREAM *s)
311 { SLOCK(s);
312
313 #ifdef DEBUG_IO_LOCKS
314 if ( s->locks > 2 )
315 { printf(" Lock [%d]: %s: %d locks", PL_thread_self(), Sname(s), s->locks+1);
316 print_trace();
317 }
318 #endif
319
320 if ( !s->locks++ )
321 { if ( (s->flags & (SIO_NBUF|SIO_OUTPUT)) == (SIO_NBUF|SIO_OUTPUT) )
322 return S__setbuf(s, NULL, TMPBUFSIZE) == (size_t)-1 ? -1 : 0;
323 }
324
325 return 0;
326 }
327
328
329 int
StryLock(IOSTREAM * s)330 StryLock(IOSTREAM *s)
331 { if ( !STRYLOCK(s) )
332 return -1;
333
334 if ( !s->locks++ )
335 { if ( (s->flags & (SIO_NBUF|SIO_OUTPUT)) == (SIO_NBUF|SIO_OUTPUT) )
336 return S__setbuf(s, NULL, TMPBUFSIZE) == (size_t)-1 ? -1 : 0;
337 }
338
339 return 0;
340 }
341
342
343 int
Sunlock(IOSTREAM * s)344 Sunlock(IOSTREAM *s)
345 { int rval = 0;
346
347 #ifdef DEBUG_IO_LOCKS
348 if ( s->locks > 3 )
349 { printf("Unlock [%d]: %s: %d locks", PL_thread_self(), Sname(s), s->locks-1);
350 print_trace();
351 }
352 #endif
353
354 if ( s->locks )
355 { if ( --s->locks == 0 )
356 { if ( (s->flags & (SIO_NBUF|SIO_OUTPUT)) == (SIO_NBUF|SIO_OUTPUT) )
357 rval = S__removebuf(s);
358 }
359 } else
360 { assert(0);
361 }
362
363 SUNLOCK(s);
364 return rval;
365 }
366
367
368 /*******************************
369 * FLUSH/FILL *
370 *******************************/
371
372 /* return values: -1: error, else #bytes written */
373
374 static ssize_t
S__flushbuf(IOSTREAM * s)375 S__flushbuf(IOSTREAM *s)
376 { char *from, *to;
377 ssize_t rc;
378
379 SLOCK(s);
380 from = s->buffer;
381 to = s->bufp;
382
383 while ( from < to )
384 { size_t size = (size_t)(to - from);
385 ssize_t n = (*s->functions->write)(s->handle, from, size);
386
387 if ( n > 0 ) /* wrote some */
388 { from += n;
389 } else if ( n < 0 ) /* error */
390 { S__seterror(s);
391 rc = -1;
392 goto out;
393 } else /* wrote nothing? */
394 { break;
395 }
396 }
397
398 if ( to == from ) /* full flush */
399 { rc = s->bufp - s->buffer;
400 s->bufp = s->buffer;
401 } else /* partial flush */
402 { size_t left = to - from;
403
404 rc = from - s->buffer;
405 memmove(s->buffer, from, left);
406 s->bufp = s->buffer + left;
407 }
408
409 out:
410 SUNLOCK(s);
411 return rc;
412 }
413
414
415 static int
S__flushbufc(int c,IOSTREAM * s)416 S__flushbufc(int c, IOSTREAM *s)
417 { if ( s->buffer )
418 { if ( S__flushbuf(s) <= 0 ) /* == 0: no progress!? */
419 c = -1;
420 else
421 *s->bufp++ = (c & 0xff);
422 } else
423 { if ( s->flags & SIO_NBUF )
424 { char chr = (char)c;
425
426 if ( (*s->functions->write)(s->handle, &chr, 1) != 1 )
427 { S__seterror(s);
428 c = -1;
429 }
430 } else
431 { if ( S__setbuf(s, NULL, 0) == (size_t)-1 )
432 c = -1;
433 else
434 *s->bufp++ = (char)c;
435 }
436 }
437
438 return c;
439 }
440
441
442 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
443 S__fillbuf() fills the read-buffer, returning the first character of it.
444 It also realises the SWI-Prolog timeout facility.
445 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
446
447 int
S__fillbuf(IOSTREAM * s)448 S__fillbuf(IOSTREAM *s)
449 { int c;
450
451 if ( s->flags & (SIO_FEOF|SIO_FERR) )
452 { s->flags |= SIO_FEOF2; /* reading past eof */
453 return -1;
454 }
455
456 #ifdef HAVE_SELECT
457 s->flags &= ~SIO_TIMEOUT;
458
459 if ( s->timeout >= 0 )
460 { int fd = Sfileno(s);
461
462 if ( fd >= 0 )
463 { fd_set wait;
464 struct timeval time;
465 int rc;
466
467 time.tv_sec = s->timeout / 1000;
468 time.tv_usec = (s->timeout % 1000) * 1000;
469 FD_ZERO(&wait);
470 #ifdef __WINDOWS__
471 FD_SET((SOCKET)fd, &wait);
472 #else
473 FD_SET(fd, &wait);
474 #endif
475
476 for(;;)
477 { rc = select(fd+1, &wait, NULL, NULL, &time);
478
479 if ( rc < 0 && errno == EINTR )
480 { if ( PL_handle_signals() < 0 )
481 { errno = EPLEXCEPTION;
482 return -1;
483 }
484
485 continue;
486 }
487
488 break;
489 }
490
491 if ( rc == 0 )
492 { s->flags |= (SIO_TIMEOUT|SIO_FERR);
493 return -1;
494 }
495 } else
496 { errno = EPERM; /* no permission to select */
497 s->flags |= SIO_FERR;
498 return -1;
499 }
500 }
501 #endif
502
503
504 if ( s->flags & SIO_NBUF )
505 { char chr;
506 ssize_t n;
507
508 if ( (n=(*s->functions->read)(s->handle, &chr, 1)) == 1 )
509 { c = char_to_int(chr);
510 return c;
511 } else if ( n == 0 )
512 { if ( !(s->flags & SIO_NOFEOF) )
513 s->flags |= SIO_FEOF;
514 return -1;
515 } else
516 { S__seterror(s);
517 return -1;
518 }
519 } else
520 { ssize_t n;
521 size_t len;
522
523 if ( !s->buffer )
524 { if ( S__setbuf(s, NULL, 0) == (size_t)-1 )
525 return -1;
526 s->bufp = s->limitp = s->buffer;
527 len = s->bufsize;
528 } else if ( s->bufp < s->limitp )
529 { len = s->limitp - s->bufp;
530 memmove(s->buffer, s->bufp, s->limitp - s->bufp);
531 s->bufp = s->buffer;
532 s->limitp = &s->bufp[len];
533 len = s->bufsize - len;
534 } else
535 { s->bufp = s->limitp = s->buffer;
536 len = s->bufsize;
537 }
538
539 if ( (n=(*s->functions->read)(s->handle, s->limitp, len)) > 0 )
540 { s->limitp += n;
541 c = char_to_int(*s->bufp++);
542 return c;
543 } else
544 { if ( n == 0 )
545 { if ( !(s->flags & SIO_NOFEOF) )
546 s->flags |= SIO_FEOF;
547 return -1;
548 #ifdef EWOULDBLOCK
549 } else if ( errno == EWOULDBLOCK )
550 { s->bufp = s->buffer;
551 s->limitp = s->buffer;
552 S__seterror(s);
553 return -1;
554 #endif
555 } else
556 { S__seterror(s);
557 return -1;
558 }
559 }
560 }
561 }
562
563 /*******************************
564 * CHARACTER I/O *
565 *******************************/
566
567
568 static inline void
update_linepos(IOSTREAM * s,int c)569 update_linepos(IOSTREAM *s, int c)
570 { IOPOS *p = s->position;
571
572 if ( c > '\r' ) /* speedup the 99% case a bit */
573 { p->linepos++;
574 return;
575 }
576
577 switch(c)
578 { case '\n':
579 p->lineno++;
580 p->linepos = 0;
581 s->flags &= ~SIO_NOLINEPOS;
582 break;
583 case '\r':
584 p->linepos = 0;
585 s->flags &= ~SIO_NOLINEPOS;
586 break;
587 case '\b':
588 if ( p->linepos > 0 )
589 p->linepos--;
590 break;
591 case EOF:
592 break;
593 case '\t':
594 p->linepos |= 7;
595 default:
596 p->linepos++;
597 }
598 }
599
600
601
602 int
S__fcheckpasteeof(IOSTREAM * s,int c)603 S__fcheckpasteeof(IOSTREAM *s, int c)
604 { S__checkpasteeof(s, c);
605
606 return c;
607 }
608
609
610 int
S__fupdatefilepos_getc(IOSTREAM * s,int c)611 S__fupdatefilepos_getc(IOSTREAM *s, int c)
612 { IOPOS *p = s->position;
613
614 update_linepos(s, c);
615 p->byteno++;
616 p->charno++;
617
618 return c;
619 }
620
621
622 static inline int
S__updatefilepos(IOSTREAM * s,int c)623 S__updatefilepos(IOSTREAM *s, int c)
624 { IOPOS *p = s->position;
625
626 if ( p )
627 { update_linepos(s, c);
628 p->charno++;
629 }
630 S__checkpasteeof(s,c);
631
632 return c;
633 }
634
635
636 static inline int
get_byte(IOSTREAM * s)637 get_byte(IOSTREAM *s)
638 { int c = Snpgetc(s);
639
640 if ( s->position )
641 s->position->byteno++;
642
643 return c;
644 }
645
646
647 static int
put_byte(int c,IOSTREAM * s)648 put_byte(int c, IOSTREAM *s)
649 { c &= 0xff;
650
651 if ( s->bufp < s->limitp )
652 { *s->bufp++ = c;
653 } else
654 { if ( S__flushbufc(c, s) < 0 )
655 { s->lastc = EOF;
656 return -1;
657 }
658 }
659
660 if ( s->position )
661 s->position->byteno++;
662
663 return c;
664 }
665
666
667 int
Sputc(int c,IOSTREAM * s)668 Sputc(int c, IOSTREAM *s)
669 { c &= 0xff;
670
671 if ( put_byte(c, s) < 0 )
672 return -1;
673
674 s->lastc = c;
675
676 if ( c == '\n' && (s->flags & SIO_LBUF) )
677 { if ( S__flushbuf(s) < 0 )
678 return -1;
679 }
680
681 return S__updatefilepos(s, c);
682 }
683
684
685 int
Sfgetc(IOSTREAM * s)686 Sfgetc(IOSTREAM *s)
687 { return Sgetc(s);
688 }
689
690
691 static inline void
unget_byte(int c,IOSTREAM * s)692 unget_byte(int c, IOSTREAM *s)
693 { IOPOS *p = s->position;
694
695 *--s->bufp = c;
696 if ( p )
697 { p->charno--; /* FIXME: not correct */
698 p->byteno--;
699 if ( c == '\n' )
700 p->lineno--;
701 s->flags |= SIO_NOLINEPOS;
702 }
703 }
704
705
706 int
Sungetc(int c,IOSTREAM * s)707 Sungetc(int c, IOSTREAM *s)
708 { if ( s->bufp > s->unbuffer )
709 { unget_byte(c, s);
710
711 return c;
712 }
713
714 return -1;
715 }
716
717
718 static int
reperror(int c,IOSTREAM * s)719 reperror(int c, IOSTREAM *s)
720 { if ( c >= 0 && (s->flags & (SIO_REPXML|SIO_REPPL)) )
721 { char buf[16];
722 const char *q;
723
724 if ( (s->flags & SIO_REPPL) )
725 { if ( c <= 0xffff )
726 sprintf(buf, "\\u%04X", c);
727 else
728 sprintf(buf, "\\U%08X", c);
729 } else
730 sprintf(buf, "&#%d;", c);
731
732 for(q = buf; *q; q++)
733 { if ( put_byte(*q, s) < 0 )
734 return -1;
735 }
736
737 return c;
738 }
739
740 Sseterr(s, SIO_FERR|SIO_CLEARERR, "Encoding cannot represent character");
741 return -1;
742 }
743
744
745
746 static int
put_code(int c,IOSTREAM * s)747 put_code(int c, IOSTREAM *s)
748 { switch(s->encoding)
749 { case ENC_OCTET:
750 case ENC_ISO_LATIN_1:
751 if ( c >= 256 )
752 { if ( reperror(c, s) < 0 )
753 return -1;
754 break;
755 }
756 simple:
757 if ( put_byte(c, s) < 0 )
758 return -1;
759 break;
760 case ENC_ASCII:
761 if ( c >= 128 )
762 { if ( reperror(c, s) < 0 )
763 return -1;
764 break;
765 }
766 goto simple;
767 case ENC_ANSI:
768 { char b[MB_LEN_MAX];
769 size_t n;
770
771 if ( !s->mbstate )
772 { if ( !(s->mbstate = malloc(sizeof(*s->mbstate))) )
773 return EOF; /* out of memory */
774 memset(s->mbstate, 0, sizeof(*s->mbstate));
775 }
776
777 if ( (n = wcrtomb(b, (wchar_t)c, s->mbstate)) == (size_t)-1 )
778 { if ( reperror(c, s) < 0 )
779 return -1;
780 } else
781 { size_t i;
782
783 for(i=0; i<n; i++)
784 { if ( put_byte(b[i]&0xff, s) < 0 )
785 return -1;
786 }
787 }
788
789 break;
790 }
791 case ENC_UTF8:
792 { char buf[6];
793 char *p, *end;
794
795 if ( c < 128 )
796 goto simple;
797
798 end = utf8_put_char(buf, c);
799 for(p=buf; p<end; p++)
800 { if ( put_byte(*p&0xff, s) < 0 )
801 return -1;
802 }
803
804 break;
805 }
806 case ENC_UNICODE_BE:
807 if ( put_byte(c>>8, s) < 0 )
808 return -1;
809 if ( put_byte(c&0xff, s) < 0 )
810 return -1;
811 break;
812 case ENC_UNICODE_LE:
813 if ( put_byte(c&0xff, s) < 0 )
814 return -1;
815 if ( put_byte(c>>8, s) < 0 )
816 return -1;
817 break;
818 case ENC_WCHAR:
819 { pl_wchar_t chr = c;
820 unsigned char *q = (unsigned char *)&chr;
821 unsigned char *e = &q[sizeof(pl_wchar_t)];
822
823 while(q<e)
824 { if ( put_byte(*q++, s) < 0 )
825 return -1;
826 }
827
828 break;
829 }
830 case ENC_UNKNOWN:
831 return -1;
832 }
833
834
835 s->lastc = c;
836
837 if ( c == '\n' && (s->flags & SIO_LBUF) )
838 { if ( S__flushbuf(s) < 0 )
839 return -1;
840 }
841
842 return S__updatefilepos(s, c);
843 }
844
845
846 int
Sputcode(int c,IOSTREAM * s)847 Sputcode(int c, IOSTREAM *s)
848 { if ( c < 0 )
849 return reperror(c, s);
850
851 if ( s->tee && s->tee->magic == SIO_MAGIC )
852 Sputcode(c, s->tee);
853
854 if ( c == '\n' && (s->flags&SIO_TEXT) && s->newline == SIO_NL_DOS )
855 { if ( put_code('\r', s) < 0 )
856 return -1;
857 }
858
859 return put_code(c, s);
860 }
861
862
863 int
Scanrepresent(int c,IOSTREAM * s)864 Scanrepresent(int c, IOSTREAM *s)
865 { switch(s->encoding)
866 { case ENC_OCTET:
867 case ENC_ISO_LATIN_1:
868 if ( c <= 0xff )
869 return 0;
870 return -1;
871 case ENC_ASCII:
872 if ( c < 0x7f )
873 return 0;
874 return -1;
875 case ENC_ANSI:
876 { mbstate_t state;
877 char b[MB_LEN_MAX];
878
879 memset(&state, 0, sizeof(state));
880 if ( wcrtomb(b, (wchar_t)c, &state) != (size_t)-1 )
881 return 0;
882 return -1;
883 }
884 case ENC_WCHAR:
885 if ( sizeof(wchar_t) > 2 )
886 return 0;
887 /*FALLTHROUGH*/
888 case ENC_UNICODE_BE:
889 case ENC_UNICODE_LE:
890 if ( c <= 0xffff )
891 return 0;
892 return -1;
893 case ENC_UTF8:
894 return 0;
895 default:
896 assert(0);
897 return -1;
898 }
899 }
900
901
902 int
Sgetcode(IOSTREAM * s)903 Sgetcode(IOSTREAM *s)
904 { int c;
905
906 retry:
907 switch(s->encoding)
908 { case ENC_OCTET:
909 case ENC_ISO_LATIN_1:
910 c = get_byte(s);
911 break;
912 case ENC_ASCII:
913 { c = get_byte(s);
914 if ( c > 128 )
915 Sseterr(s, SIO_WARN, "non-ASCII character");
916 break;
917 }
918 case ENC_ANSI:
919 { char b[1];
920 size_t rc, n = 0;
921 wchar_t wc;
922
923 if ( !s->mbstate )
924 { if ( !(s->mbstate = malloc(sizeof(*s->mbstate))) )
925 return EOF; /* out of memory */
926 memset(s->mbstate, 0, sizeof(*s->mbstate));
927 }
928
929 for(;;)
930 { if ( (c = get_byte(s)) == EOF )
931 { if ( n == 0 )
932 { goto out;
933 } else
934 { Sseterr(s, SIO_WARN, "EOF in multibyte Sequence");
935 goto mberr;
936 }
937 }
938 b[0] = c;
939
940 if ( (rc=mbrtowc(&wc, b, 1, s->mbstate)) == 1 )
941 { c = wc;
942 goto out;
943 } else if ( rc == (size_t)-1 )
944 { Sseterr(s, SIO_WARN, "Illegal multibyte Sequence");
945 goto mberr;
946 } /* else -2: incomplete */
947 }
948
949 mberr:
950 c = UTF8_MALFORMED_REPLACEMENT;
951 goto out;
952 }
953 case ENC_UTF8:
954 { c = get_byte(s);
955 if ( c == EOF )
956 break;
957
958 if ( c & 0x80 )
959 { int extra = UTF8_FBN(c);
960 int code;
961
962 if ( extra < 0 )
963 { Sseterr(s, SIO_WARN, "Illegal UTF-8 start");
964 c = UTF8_MALFORMED_REPLACEMENT;
965 goto out;
966 }
967
968 code = UTF8_FBV(c,extra);
969 for( ; extra > 0; extra-- )
970 { int c2 = get_byte(s);
971
972 if ( !ISUTF8_CB(c2) )
973 { Sseterr(s, SIO_WARN, "Illegal UTF-8 continuation");
974 c = UTF8_MALFORMED_REPLACEMENT;
975 Sungetc(c2, s);
976 goto out;
977 }
978 code = (code<<6)+(c2&0x3f);
979 }
980 c = code;
981 }
982 break;
983 }
984 case ENC_UNICODE_BE:
985 case ENC_UNICODE_LE:
986 { int c1, c2;
987
988 c1 = get_byte(s);
989 if ( c1 == EOF )
990 { c = -1;
991 goto out;
992 }
993 c2 = get_byte(s);
994
995 if ( c2 == EOF )
996 { Sseterr(s, SIO_WARN, "EOF in unicode character");
997 c = UTF8_MALFORMED_REPLACEMENT;
998 } else
999 { if ( s->encoding == ENC_UNICODE_BE )
1000 c = (c1<<8)+c2;
1001 else
1002 c = (c2<<8)+c1;
1003 }
1004
1005 break;
1006 }
1007 case ENC_WCHAR:
1008 { pl_wchar_t chr;
1009 char *p = (char*)&chr;
1010 size_t n;
1011
1012 for(n=0; n<sizeof(pl_wchar_t); n++)
1013 { int c1 = get_byte(s);
1014
1015 if ( c1 == EOF )
1016 { if ( n == 0 )
1017 { c = -1;
1018 goto out;
1019 } else
1020 { Sseterr(s, SIO_WARN, "EOF in UCS character");
1021 c = UTF8_MALFORMED_REPLACEMENT;
1022 goto out;
1023 }
1024 }
1025
1026 *p++ = c1;
1027 }
1028
1029 c = chr;
1030 break;
1031 }
1032 default:
1033 assert(0);
1034 c = -1;
1035 }
1036
1037 out:
1038 if ( c == '\r' && (s->flags&SIO_TEXT) )
1039 { switch(s->newline)
1040 { case SIO_NL_DETECT:
1041 s->newline = SIO_NL_DOS;
1042 /*FALLTHROUGH*/
1043 case SIO_NL_DOS:
1044 goto retry;
1045 }
1046 }
1047
1048 if ( s->tee && s->tee->magic == SIO_MAGIC && c != -1 )
1049 Sputcode(c, s->tee);
1050
1051 return S__updatefilepos(s, c);
1052 }
1053
1054
1055 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1056 (*) For ENC_ANSI there is a problem as this deals with multi-modal
1057 streams, streams that may hold escape sequences to move from one
1058 character set to another: ascii ... <esc1> japanese <esc2> ascii ...
1059 Suppose now we have two characters [ascii, japanese]. When reading the
1060 japanese character the first time, the system will translate the
1061 <esc><japanese> and the mode will be japanese. When pushing back, only
1062 the japanese character will be put back, not the escape sequence. What
1063 to do?
1064 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1065
1066 int
Sungetcode(int c,IOSTREAM * s)1067 Sungetcode(int c, IOSTREAM *s)
1068 { switch(s->encoding)
1069 { case ENC_OCTET:
1070 case ENC_ISO_LATIN_1:
1071 if ( c >= 256 )
1072 return -1; /* illegal */
1073 simple:
1074 if ( s->bufp > s->unbuffer )
1075 { unget_byte(c, s);
1076 return c;
1077 }
1078 return -1; /* no room */
1079 case ENC_ASCII:
1080 if ( c >= 128 )
1081 return -1; /* illegal */
1082 goto simple;
1083 case ENC_ANSI: /* (*) See above */
1084 { char b[MB_LEN_MAX];
1085 size_t n;
1086
1087 if ( !s->mbstate ) /* do we need a seperate state? */
1088 { if ( !(s->mbstate = malloc(sizeof(*s->mbstate))) )
1089 return EOF; /* out of memory */
1090 memset(s->mbstate, 0, sizeof(*s->mbstate));
1091 }
1092
1093 if ( (n = wcrtomb(b, (wchar_t)c, s->mbstate)) != (size_t)-1 &&
1094 s->bufp >= n + s->unbuffer )
1095 { size_t i;
1096
1097 for(i=n; i-- > 0; )
1098 { unget_byte(b[i], s);
1099 }
1100
1101 return c;
1102 }
1103
1104 return -1;
1105 }
1106 case ENC_UTF8:
1107 { if ( (unsigned)c >= 0x8000000 )
1108 return -1;
1109
1110 if ( c < 0x80 )
1111 { goto simple;
1112 } else
1113 { char buf[6];
1114 char *p, *end;
1115
1116 end = utf8_put_char(buf, c);
1117 if ( s->bufp - s->unbuffer >= end-buf )
1118 { for(p=end-1; p>=buf; p--)
1119 { unget_byte(*p, s);
1120 }
1121
1122 return c;
1123 }
1124
1125 return -1;
1126 }
1127 }
1128 case ENC_UNICODE_BE:
1129 { if ( c >= 0x10000 )
1130 return -1;
1131
1132 if ( s->bufp-1 > s->unbuffer )
1133 { unget_byte(c&0xff, s);
1134 unget_byte((c>>8)&0xff, s);
1135
1136 return c;
1137 }
1138 return -1;
1139 }
1140 case ENC_UNICODE_LE:
1141 { if ( c >= 0x10000 )
1142 return -1;
1143
1144 if ( s->bufp-1 > s->unbuffer )
1145 { unget_byte((c>>8)&0xff, s);
1146 unget_byte(c&0xff, s);
1147
1148 return c;
1149 }
1150 return -1;
1151 }
1152 case ENC_WCHAR:
1153 { pl_wchar_t chr = c;
1154
1155 if ( s->bufp-sizeof(chr) >= s->unbuffer )
1156 { char *p = (char*)&chr;
1157 int n;
1158
1159 for(n=sizeof(chr); --n>=0; )
1160 unget_byte(p[n], s);
1161
1162 return c;
1163 }
1164 return -1;
1165 }
1166 case ENC_UNKNOWN:
1167 return -1;
1168 }
1169
1170 assert(0);
1171 return -1;
1172 }
1173
1174 /*******************************
1175 * PUTW/GETW *
1176 *******************************/
1177
1178 int
Sputw(int w,IOSTREAM * s)1179 Sputw(int w, IOSTREAM *s)
1180 { unsigned char *q = (unsigned char *)&w;
1181 unsigned int n;
1182
1183 for(n=0; n<sizeof(w); n++)
1184 { if ( Sputc(*q++, s) < 0 )
1185 return -1;
1186 }
1187
1188 return w;
1189 }
1190
1191
1192 int
Sgetw(IOSTREAM * s)1193 Sgetw(IOSTREAM *s)
1194 { int w;
1195 unsigned char *q = (unsigned char *)&w;
1196 unsigned int n;
1197
1198 for(n=0; n<sizeof(w); n++)
1199 { int c;
1200
1201 if ( (c = Sgetc(s)) < 0 )
1202 return -1;
1203 *q++ = c & 0xff;
1204 }
1205
1206 return w;
1207 }
1208
1209 /*******************************
1210 * FREAD/FWRITE *
1211 *******************************/
1212
1213 size_t
Sfread(void * data,size_t size,size_t elms,IOSTREAM * s)1214 Sfread(void *data, size_t size, size_t elms, IOSTREAM *s)
1215 { size_t chars = size * elms;
1216 char *buf = data;
1217
1218 if ( s->position )
1219 { for( ; chars > 0; chars-- )
1220 { int c;
1221
1222 if ( (c = Sgetc(s)) == EOF )
1223 break;
1224
1225 *buf++ = c & 0xff;
1226 }
1227 } else
1228 { while(chars > 0)
1229 { int c;
1230
1231 if ( s->bufp < s->limitp )
1232 { size_t avail = s->limitp - s->bufp;
1233
1234 if ( chars <= avail )
1235 { memcpy(buf, s->bufp, chars);
1236 s->bufp += chars;
1237 return elms;
1238 } else
1239 { memcpy(buf, s->bufp, avail);
1240 chars -= avail;
1241 buf += avail;
1242 s->bufp += avail;
1243 }
1244 }
1245
1246 if ( (c = S__fillbuf(s)) == EOF )
1247 break;
1248
1249 *buf++ = c & 0xff;
1250 chars--;
1251 }
1252 }
1253
1254 return (size*elms - chars)/size;
1255 }
1256
1257
1258 size_t
Sfwrite(const void * data,size_t size,size_t elms,IOSTREAM * s)1259 Sfwrite(const void *data, size_t size, size_t elms, IOSTREAM *s)
1260 { size_t chars = size * elms;
1261 const char *buf = data;
1262
1263 for( ; chars > 0; chars-- )
1264 { if ( Sputc(*buf++, s) < 0 )
1265 break;
1266 }
1267
1268 return (size*elms - chars)/size;
1269 }
1270
1271
1272 /*******************************
1273 * PENDING *
1274 *******************************/
1275
1276 ssize_t
Sread_pending(IOSTREAM * s,char * buf,size_t limit,int flags)1277 Sread_pending(IOSTREAM *s, char *buf, size_t limit, int flags)
1278 { int done = 0;
1279 size_t n;
1280
1281 if ( s->bufp >= s->limitp && (flags & SIO_RP_BLOCK) )
1282 { int c = S__fillbuf(s);
1283
1284 if ( c < 0 )
1285 { if ( (s->flags & SIO_FEOF) )
1286 return 0;
1287 return c;
1288 }
1289
1290 buf[0] = c;
1291 limit--;
1292 done = 1;
1293 }
1294
1295 n = s->limitp - s->bufp;
1296 if ( n > limit )
1297 n = limit;
1298 memcpy(&buf[done], s->bufp, n);
1299 s->bufp += n;
1300
1301 return done+n;
1302 }
1303
1304
1305 /*******************************
1306 * BOM *
1307 *******************************/
1308
1309 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1310 Check the stream for a BOM (Byte Order Marker). If present (and known),
1311 update the stream encoding. Return value is one of
1312
1313 -1: error (check errno)
1314 0: ok. If BOM, SIO_BOM is added to flags
1315 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1316
1317 typedef struct
1318 { IOENC encoding;
1319 unsigned int bomlen;
1320 const char *bom;
1321 } bomdef;
1322
1323 static const bomdef bomdefs[] =
1324 { { ENC_UTF8, 3, "\357\273\277" }, /* 0xef, 0xbb, 0xbb */
1325 { ENC_UNICODE_BE, 2, "\376\377" }, /* 0xfe, oxff */
1326 { ENC_UNICODE_LE, 2, "\377\376" }, /* 0xff, oxfe */
1327 { ENC_UNKNOWN, 0, NULL }
1328 };
1329
1330 int
ScheckBOM(IOSTREAM * s)1331 ScheckBOM(IOSTREAM *s)
1332 { if ( (s->flags & SIO_NBUF) )
1333 { errno = EINVAL;
1334 return -1;
1335 }
1336
1337 for(;;)
1338 { size_t avail = s->limitp - s->bufp;
1339 const bomdef *bd;
1340
1341 for(bd=bomdefs; bd->bomlen; bd++)
1342 { if ( avail >= bd->bomlen && memcmp(s->bufp, bd->bom, bd->bomlen) == 0 )
1343 { s->encoding = bd->encoding;
1344 s->bufp += bd->bomlen;
1345 s->flags |= SIO_BOM;
1346 return 0;
1347 }
1348 }
1349
1350 if ( avail >= 4 ) /* longest BOM */
1351 return 0;
1352
1353 if ( S__fillbuf(s) == -1 )
1354 return 0; /* empty stream */
1355 s->bufp--;
1356 }
1357 }
1358
1359
1360 int
SwriteBOM(IOSTREAM * s)1361 SwriteBOM(IOSTREAM *s)
1362 { switch(s->encoding)
1363 { case ENC_UTF8:
1364 case ENC_UNICODE_LE:
1365 case ENC_UNICODE_BE:
1366 { if ( Sputcode(0xfeff, s) != -1 )
1367 { s->flags |= SIO_BOM;
1368
1369 return 0;
1370 }
1371 return -1;
1372 }
1373 default:
1374 return 0;
1375 }
1376 }
1377
1378
1379 /*******************************
1380 * FLAGS *
1381 *******************************/
1382
1383 int
Sfeof(IOSTREAM * s)1384 Sfeof(IOSTREAM *s)
1385 { if ( s->flags & SIO_FEOF )
1386 return TRUE;
1387
1388 if ( s->bufp < s->limitp )
1389 return FALSE;
1390
1391 if ( s->flags & SIO_NBUF )
1392 { errno = EINVAL;
1393 return -1;
1394 }
1395
1396 if ( S__fillbuf(s) == -1 )
1397 return TRUE;
1398
1399 s->bufp--;
1400 return FALSE;
1401 }
1402
1403
1404 static int
S__seterror(IOSTREAM * s)1405 S__seterror(IOSTREAM *s)
1406 { s->io_errno = errno;
1407
1408 if ( !(s->flags&SIO_CLOSING) && /* s->handle is already invalid */
1409 s->functions->control )
1410 { char *msg;
1411
1412 if ( (*s->functions->control)(s->handle,
1413 SIO_LASTERROR,
1414 (void *)&msg) == 0 )
1415 { Sseterr(s, SIO_FERR, msg);
1416 return 0;
1417 }
1418 }
1419
1420 s->flags |= SIO_FERR;
1421 return 0;
1422 }
1423
1424
1425 int
Sferror(IOSTREAM * s)1426 Sferror(IOSTREAM *s)
1427 { return (s->flags & SIO_FERR) != 0;
1428 }
1429
1430
1431 int
Sfpasteof(IOSTREAM * s)1432 Sfpasteof(IOSTREAM *s)
1433 { return (s->flags & (SIO_FEOF2ERR|SIO_FEOF2)) == (SIO_FEOF2ERR|SIO_FEOF2);
1434 }
1435
1436
1437 void
Sclearerr(IOSTREAM * s)1438 Sclearerr(IOSTREAM *s)
1439 { s->flags &= ~(SIO_FEOF|SIO_WARN|SIO_FERR|SIO_FEOF2|SIO_TIMEOUT|SIO_CLEARERR);
1440 s->io_errno = 0;
1441 Sseterr(s, 0, NULL);
1442 }
1443
1444
1445 void
Sseterr(IOSTREAM * s,int flag,const char * message)1446 Sseterr(IOSTREAM *s, int flag, const char *message)
1447 { if ( s->message )
1448 { free(s->message);
1449 s->message = NULL;
1450 s->flags &= ~SIO_CLEARERR;
1451 }
1452 if ( message )
1453 { s->flags |= flag;
1454 s->message = strdup(message);
1455 } else
1456 { s->flags &= ~flag;
1457 }
1458 }
1459
1460
1461 void
Sset_exception(IOSTREAM * s,term_t ex)1462 Sset_exception(IOSTREAM *s, term_t ex)
1463 { s->exception = PL_record(ex);
1464 s->flags |= SIO_FERR;
1465 }
1466
1467
1468 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1469 Set the encoding of a stream. The enc argument is the new encoding. If
1470 old is not NULL, the old encoding is written to the given location.
1471
1472 Please note that not all code changing the encoding call Ssetenc at the
1473 moment.
1474 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1475
1476 int
Ssetenc(IOSTREAM * s,IOENC enc,IOENC * old)1477 Ssetenc(IOSTREAM *s, IOENC enc, IOENC *old)
1478 { if ( old )
1479 *old = s->encoding;
1480 if ( enc == s->encoding )
1481 return 0;
1482
1483 if ( s->functions->control )
1484 { if ( (*s->functions->control)(s->handle,
1485 SIO_SETENCODING,
1486 (void *)&enc) != 0 )
1487 return -1;
1488 }
1489
1490 s->encoding = enc;
1491 return 0;
1492 }
1493
1494 /*******************************
1495 * FLUSH *
1496 *******************************/
1497
1498 int
Sflush(IOSTREAM * s)1499 Sflush(IOSTREAM *s)
1500 { if ( s->buffer && (s->flags & SIO_OUTPUT) )
1501 { if ( S__flushbuf(s) < 0 )
1502 return -1;
1503 if ( s->functions->control &&
1504 (*s->functions->control)(s->handle, SIO_FLUSHOUTPUT, NULL) < 0 )
1505 return -1;
1506 }
1507
1508 return 0;
1509 }
1510
1511 /*******************************
1512 * SEEK *
1513 *******************************/
1514
1515 int
Sunit_size(IOSTREAM * s)1516 Sunit_size(IOSTREAM *s)
1517 { switch(s->encoding)
1518 { case ENC_UNKNOWN:
1519 case ENC_OCTET:
1520 case ENC_ASCII:
1521 case ENC_ISO_LATIN_1:
1522 case ENC_ANSI:
1523 case ENC_UTF8:
1524 return 1;
1525 case ENC_UNICODE_BE:
1526 case ENC_UNICODE_LE:
1527 return 2;
1528 case ENC_WCHAR:
1529 return sizeof(wchar_t);
1530 default:
1531 assert(0);
1532 return 1; /* not reached */
1533 }
1534 }
1535
1536
1537 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1538 Return the size of the underlying data object. Should be optimized;
1539 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1540
1541 long
Ssize(IOSTREAM * s)1542 Ssize(IOSTREAM *s)
1543 { if ( s->functions->control )
1544 { long size;
1545
1546 if ( (*s->functions->control)(s->handle, SIO_GETSIZE, (void *)&size) == 0 )
1547 return size;
1548 }
1549 if ( s->functions->seek )
1550 { long here = Stell(s);
1551 long end;
1552
1553 if ( Sseek(s, 0, SIO_SEEK_END) == 0 )
1554 end = Stell(s);
1555 else
1556 end = -1;
1557 Sseek(s, here, SIO_SEEK_SET);
1558
1559 return end;
1560 }
1561
1562 errno = ESPIPE;
1563 S__seterror(s);
1564 return -1;
1565 }
1566
1567
1568 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1569 Sseek64(IOSTREAM *s, int64_t pos, int whence)
1570
1571 Re-position the stream to byte-no 'pos'.
1572
1573 Maybe we should optimise this to become block-aligned? Or can we leave
1574 this to read/write?
1575
1576 The first part checks whether repositioning the read pointer in the
1577 buffer suffices to achieve the seek.
1578 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1579
1580 int
Sseek64(IOSTREAM * s,int64_t pos,int whence)1581 Sseek64(IOSTREAM *s, int64_t pos, int whence)
1582 { if ( (s->flags & SIO_INPUT) && s->limitp > s->buffer ) /* something there */
1583 { int64_t now = Stell64(s);
1584
1585 if ( now != -1 )
1586 { int64_t newpos;
1587 char *nbufp = (char *)-1;
1588
1589 if ( whence == SIO_SEEK_CUR )
1590 { nbufp = s->bufp + pos;
1591 newpos = now + pos;
1592 } else if ( whence == SIO_SEEK_SET )
1593 { nbufp = s->bufp + (pos - now);
1594 newpos = pos;
1595 } else
1596 newpos = -1; /* should not happen */
1597
1598 if ( nbufp >= s->buffer && nbufp < s->limitp )
1599 { s->bufp = nbufp;
1600
1601 pos = newpos;
1602 goto update;
1603 }
1604 }
1605 }
1606
1607 if ( !s->functions->seek && !s->functions->seek64 )
1608 { errno = ESPIPE;
1609 S__seterror(s);
1610 return -1;
1611 }
1612
1613 Sflush(s);
1614
1615 s->bufp = s->buffer;
1616 if ( (s->flags & SIO_INPUT) )
1617 s->limitp = s->buffer;
1618
1619 if ( whence == SIO_SEEK_CUR )
1620 { pos += Stell64(s);
1621 whence = SIO_SEEK_SET;
1622 }
1623
1624 if ( s->functions->seek64 )
1625 pos = (*s->functions->seek64)(s->handle, pos, whence);
1626 else if ( pos <= LONG_MAX )
1627 pos = (*s->functions->seek)(s->handle, (long)pos, whence);
1628 else
1629 { errno = EINVAL;
1630 S__seterror(s);
1631 return -1;
1632 }
1633
1634 if ( pos < 0 )
1635 { S__seterror(s);
1636 return -1;
1637 }
1638
1639 update:
1640 s->flags &= ~(SIO_FEOF|SIO_FEOF2); /* not on eof of file anymore */
1641
1642 if ( s->position )
1643 { s->flags |= (SIO_NOLINENO|SIO_NOLINEPOS); /* no update this */
1644 s->position->byteno = pos;
1645 s->position->charno = pos/Sunit_size(s); /* compatibility */
1646 }
1647
1648 return 0;
1649 }
1650
1651
1652 int
Sseek(IOSTREAM * s,long pos,int whence)1653 Sseek(IOSTREAM *s, long pos, int whence)
1654 { return Sseek64(s, (int64_t)pos, whence);
1655 }
1656
1657
1658
1659 /* Stell64(IOSTREAM *s) returns the current position in the file in
1660 bytes
1661 */
1662
1663 int64_t
Stell64(IOSTREAM * s)1664 Stell64(IOSTREAM *s)
1665 { if ( s->position )
1666 { return s->position->byteno;
1667 } else if ( s->functions->seek || s->functions->seek64 )
1668 { int64_t pos;
1669
1670 if ( s->functions->seek64 )
1671 pos = (*s->functions->seek64)(s->handle, 0L, SIO_SEEK_CUR);
1672 else
1673 pos = (*s->functions->seek)(s->handle, 0L, SIO_SEEK_CUR);
1674
1675 if ( s->buffer ) /* open */
1676 { int64_t off = s->bufp - s->buffer;
1677
1678 if ( s->flags & SIO_INPUT )
1679 off -= s->limitp - s->buffer;
1680
1681 pos += off;
1682 }
1683
1684 return pos;
1685 } else
1686 { errno = EINVAL;
1687 S__seterror(s);
1688 return -1;
1689 }
1690 }
1691
1692
1693 long
Stell(IOSTREAM * s)1694 Stell(IOSTREAM *s)
1695 { int64_t pos = Stell64(s);
1696
1697 if ( pos == -1 )
1698 return -1;
1699 if ( pos <= LONG_MAX )
1700 return (long) pos;
1701
1702 errno = EINVAL;
1703 S__seterror(s);
1704 return -1;
1705 }
1706
1707
1708 /*******************************
1709 * CLOSE *
1710 *******************************/
1711
1712 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1713 (*) Sclose() can be called recursively. For example if an XPCE object is
1714 only referenced from an open stream, the close-function will delete the
1715 object, which in turn calls the ->unlink which may wish to close the
1716 associated stream.
1717 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1718
1719 int
Sclose(IOSTREAM * s)1720 Sclose(IOSTREAM *s)
1721 { int rval = 0;
1722
1723 if ( s->magic != SIO_MAGIC ) /* already closed!? */
1724 { s->io_errno = errno = EINVAL;
1725 return -1;
1726 }
1727
1728 if ( (s->flags&SIO_CLOSING) ) /* recursive (*) */
1729 return rval;
1730
1731 if ( s->upstream )
1732 { Sseterr(s, SIO_FERR, "Locked by upstream filter");
1733 reportStreamError(s);
1734 return -1;
1735 }
1736
1737 SLOCK(s);
1738 s->flags |= SIO_CLOSING;
1739 rval = S__removebuf(s);
1740 if ( s->mbstate )
1741 free(s->mbstate);
1742
1743 #ifdef __WINDOWS__
1744 if ( (s->flags & SIO_ADVLOCK) )
1745 { OVERLAPPED ov;
1746 HANDLE h = (HANDLE)_get_osfhandle((int)s->handle);
1747
1748 memset(&ov, 0, sizeof(ov));
1749 UnlockFileEx(h, 0, 0, 0xffffffff, &ov);
1750 s->flags &= ~SIO_ADVLOCK;
1751 }
1752 #endif
1753 if ( s->functions->close && (*s->functions->close)(s->handle) < 0 )
1754 { S__seterror(s);
1755 rval = -1;
1756 }
1757
1758 while(s->locks > 0) /* remove buffer-locks */
1759 { int rc = Sunlock(s);
1760
1761 if ( rval == 0 )
1762 rval = rc;
1763 }
1764 if ( rval < 0 )
1765 reportStreamError(s);
1766 run_close_hooks(s); /* deletes Prolog registration */
1767 SUNLOCK(s);
1768
1769 #ifdef O_PLMT
1770 if ( s->mutex )
1771 { recursiveMutexDelete(s->mutex);
1772 free(s->mutex);
1773 s->mutex = NULL;
1774 }
1775 #endif
1776
1777 s->magic = SIO_CMAGIC;
1778 if ( s->message )
1779 free(s->message);
1780 if ( !(s->flags & SIO_STATIC) )
1781 free(s);
1782
1783 return rval;
1784 }
1785
1786
1787 /*******************************
1788 * STRING I/O *
1789 *******************************/
1790
1791 char *
Sfgets(char * buf,int n,IOSTREAM * s)1792 Sfgets(char *buf, int n, IOSTREAM *s)
1793 { char *q = buf;
1794
1795 while( n-- > 0 )
1796 { int c = Sgetc(s);
1797
1798 if ( c == EOF )
1799 { *q = '\0';
1800 if ( q == buf )
1801 buf = NULL;
1802 goto out;
1803 } else
1804 { *q++ = c;
1805 if ( c == '\n' )
1806 { if ( n > 0 )
1807 *q = '\0';
1808 goto out;
1809 }
1810 }
1811 }
1812
1813 out:
1814 return buf;
1815 }
1816
1817
1818 char *
Sgets(char * buf)1819 Sgets(char *buf)
1820 { char *s = Sfgets(buf, Slinesize, Sinput);
1821 char *q;
1822
1823 if ( s ) /* delete trailing \n */
1824 { q = &s[strlen(s)];
1825 if ( q > s && q[-1] == '\n' )
1826 *--q = '\0';
1827 }
1828
1829 return s;
1830 }
1831
1832
1833 int
Sfputs(const char * q,IOSTREAM * s)1834 Sfputs(const char *q, IOSTREAM *s)
1835 { for( ; *q; q++)
1836 { if ( Sputcode(*q&0xff, s) < 0 )
1837 return EOF;
1838 }
1839
1840 return 0;
1841 }
1842
1843
1844 int
Sputs(const char * q)1845 Sputs(const char *q)
1846 { return Sfputs(q, Soutput);
1847 }
1848
1849
1850 /*******************************
1851 * PRINTF *
1852 *******************************/
1853
1854 int
Sfprintf(IOSTREAM * s,const char * fm,...)1855 Sfprintf(IOSTREAM *s, const char *fm, ...)
1856 { va_list args;
1857 int rval;
1858
1859 va_start(args, fm);
1860 rval = Svfprintf(s, fm, args);
1861 va_end(args);
1862
1863 return rval;
1864 }
1865
1866
1867 int
Sprintf(const char * fm,...)1868 Sprintf(const char *fm, ...)
1869 { va_list args;
1870 int rval;
1871
1872 va_start(args, fm);
1873 rval = Svfprintf(Soutput, fm, args);
1874 va_end(args);
1875
1876 return rval;
1877 }
1878
1879
1880 int
Svprintf(const char * fm,va_list args)1881 Svprintf(const char *fm, va_list args)
1882 { return Svfprintf(Soutput, fm, args);
1883 }
1884
1885
1886 #define NEXTCHR(s, c) if ( utf8 ) \
1887 { (s) = utf8_get_char((s), &(c)); \
1888 } else \
1889 { c = *(s)++; c &= 0xff; \
1890 }
1891
1892 #define OUTCHR(s, c) do { printed++; \
1893 if ( Sputcode((c), (s)) < 0 ) goto error; \
1894 } while(0)
1895 #define valdigit(c) ((c) - '0')
1896 #define A_LEFT 0 /* left-aligned field */
1897 #define A_RIGHT 1 /* right-aligned field */
1898
1899 int
Svfprintf(IOSTREAM * s,const char * fm,va_list args)1900 Svfprintf(IOSTREAM *s, const char *fm, va_list args)
1901 { intptr_t printed = 0;
1902 char buf[TMPBUFSIZE];
1903 int tmpbuf;
1904
1905 SLOCK(s);
1906
1907 if ( !s->buffer && (s->flags & SIO_NBUF) )
1908 { S__setbuf(s, buf, sizeof(buf));
1909 tmpbuf = TRUE;
1910 } else
1911 tmpbuf = FALSE;
1912
1913 while(*fm)
1914 { if ( *fm == '%' )
1915 { fm++;
1916
1917 if ( *fm == '%' )
1918 { OUTCHR(s, *fm);
1919 fm++;
1920 continue;
1921 } else
1922 { int align = A_RIGHT;
1923 int modified = FALSE;
1924 int has_arg1 = FALSE, has_arg2 = FALSE;
1925 int arg1=0, arg2=0;
1926 char fbuf[100], *fs = fbuf, *fe = fbuf;
1927 int islong = 0;
1928 int pad = ' ';
1929 int utf8 = FALSE;
1930
1931 for(;;)
1932 { switch(*fm)
1933 { case '+': align = A_RIGHT; fm++; continue;
1934 case '-': align = A_LEFT; fm++; continue;
1935 case '0': pad = '0'; fm++; continue;
1936 case ' ': pad = ' '; fm++; continue;
1937 case '#': modified = TRUE; fm++; continue;
1938 }
1939 break;
1940 }
1941
1942 if ( *fm == '*' )
1943 { has_arg1++;
1944 fm++;
1945 arg1 = va_arg(args, int);
1946 } else if ( isdigit(char_to_int(*fm)) )
1947 { if ( *fm == '0' )
1948 pad = '0';
1949 arg1 = valdigit(*fm);
1950 has_arg1++;
1951 for( fm++; isdigit(char_to_int(*fm)); fm++)
1952 arg1 = arg1*10 + valdigit(*fm);
1953 }
1954 if ( *fm == '.' )
1955 { has_arg2++;
1956 fm++;
1957 if ( *fm == '*' )
1958 { arg2 = va_arg(args, int);
1959 } else
1960 { arg2 = 0;
1961 for( ; isdigit(char_to_int(*fm)); fm++)
1962 arg2 = arg2*10 + valdigit(*fm);
1963 }
1964 }
1965
1966 if ( *fm == 'l' )
1967 { islong++; /* 1: %ld */
1968 fm++;
1969 }
1970 if ( *fm == 'l' )
1971 { islong++; /* 2: %lld */
1972 fm++;
1973 }
1974 if ( *fm == 'U' ) /* %Us: UTF-8 string */
1975 { utf8 = TRUE;
1976 fm++;
1977 }
1978
1979 switch(*fm)
1980 { case 'c':
1981 *fe++ = va_arg(args, int);
1982 break;
1983 case 'p':
1984 { void *ptr = va_arg(args, void*);
1985 char fmbuf[8], *fp=fmbuf;
1986 *fp++ = '%';
1987 if ( modified )
1988 *fp++ = '#';
1989 *fp++ = 'p';
1990 *fp = '\0';
1991 sprintf(fs, fmbuf, ptr);
1992 fe = &fs[strlen(fs)];
1993
1994 break;
1995 }
1996 case 'd':
1997 case 'i':
1998 case 'o':
1999 case 'u':
2000 case 'x':
2001 case 'X':
2002 { intptr_t v = 0; /* make compiler silent */
2003 int64_t vl = 0;
2004 char fmbuf[8], *fp=fmbuf;
2005
2006 switch( islong )
2007 { case 0:
2008 v = va_arg(args, int);
2009 break;
2010 case 1:
2011 v = va_arg(args, long);
2012 break;
2013 case 2:
2014 vl = va_arg(args, int64_t);
2015 break;
2016 }
2017
2018 *fp++ = '%';
2019 if ( modified )
2020 *fp++ = '#';
2021 *fp++ = 'l';
2022 if ( islong < 2 )
2023 { *fp++ = *fm;
2024 *fp = '\0';
2025 sprintf(fs, fmbuf, v);
2026 } else
2027 {
2028 #ifdef __WINDOWS__
2029 strcat(fp-1, "I64"); /* Synchronise with INT64_FORMAT! */
2030 fp += strlen(fp);
2031 #else
2032 *fp++ = 'l';
2033 #endif
2034 *fp++ = *fm;
2035 *fp = '\0';
2036 sprintf(fs, fmbuf, vl);
2037 }
2038 fe = &fs[strlen(fs)];
2039
2040 break;
2041 }
2042 case 'f':
2043 case 'e':
2044 case 'E':
2045 case 'g':
2046 case 'G':
2047 { double v = va_arg(args, double);
2048 char fmbuf[8], *fp=fmbuf;
2049
2050 *fp++ = '%';
2051 if ( modified )
2052 *fp++ = '#';
2053 if ( has_arg2 ) /* specified percission */
2054 { *fp++ = '.';
2055 *fp++ = '*';
2056 *fp++ = *fm;
2057 *fp = '\0';
2058 sprintf(fs, fmbuf, arg2, v);
2059 } else
2060 { *fp++ = *fm;
2061 *fp = '\0';
2062 sprintf(fs, fmbuf, v);
2063 }
2064 fe = &fs[strlen(fs)];
2065
2066 break;
2067 }
2068 case 's':
2069 fs = va_arg(args, char *);
2070 if ( !fs )
2071 fs = "(null)";
2072 break;
2073 }
2074
2075 if ( has_arg1 ) /* aligned field */
2076 { if ( fs == fbuf )
2077 *fe = '\0';
2078
2079 if ( align == A_LEFT )
2080 { int w = 0;
2081 while(*fs)
2082 { int c;
2083 NEXTCHR(fs, c);
2084 OUTCHR(s, c);
2085 w++;
2086 }
2087 while(w < arg1)
2088 { OUTCHR(s, pad);
2089 w++;
2090 }
2091 } else /*if ( align == A_RIGHT ) */
2092 { size_t w;
2093
2094 if ( fs == fbuf )
2095 w = fe - fs;
2096 else
2097 w = strlen(fs);
2098
2099 if ( utf8 )
2100 w = utf8_strlen(fs, w);
2101
2102 if ( (ssize_t)w < arg1 )
2103 { w = arg1 - w;
2104 while(w > 0 )
2105 { OUTCHR(s, pad);
2106 w--;
2107 }
2108 }
2109 while(*fs)
2110 { int c;
2111 NEXTCHR(fs, c);
2112 OUTCHR(s, c);
2113 }
2114 }
2115 } else
2116 { if ( fs == fbuf ) /* unaligned field, just output */
2117 { while(fs < fe)
2118 OUTCHR(s, *fs++);
2119 } else
2120 { while(*fs)
2121 { int c;
2122 NEXTCHR(fs, c);
2123 OUTCHR(s, c);
2124 }
2125 }
2126 }
2127 fm++;
2128 }
2129 } else if ( *fm == '\\' && fm[1] )
2130 { OUTCHR(s, fm[1]);
2131 fm += 2;
2132 } else
2133 { OUTCHR(s, *fm);
2134 fm++;
2135 }
2136 }
2137
2138 if ( tmpbuf )
2139 { if ( S__removebuf(s) < 0 )
2140 goto error;
2141 }
2142
2143 SUNLOCK(s);
2144 return (int)printed;
2145
2146 error:
2147 SUNLOCK(s);
2148 return -1;
2149 }
2150
2151
2152 int
Ssprintf(char * buf,const char * fm,...)2153 Ssprintf(char *buf, const char *fm, ...)
2154 { va_list args;
2155 int rval;
2156
2157 va_start(args, fm);
2158 rval = Svsprintf(buf, fm, args);
2159 va_end(args);
2160
2161 return rval;
2162 }
2163
2164
2165 int
Svsprintf(char * buf,const char * fm,va_list args)2166 Svsprintf(char *buf, const char *fm, va_list args)
2167 { IOSTREAM s;
2168 int rval;
2169
2170 memset(&s, 0, sizeof(s));
2171 s.bufp = buf;
2172 s.limitp = (char *)(~0L);
2173 s.buffer = buf;
2174 s.flags = SIO_FBUF|SIO_OUTPUT;
2175 s.encoding = ENC_ISO_LATIN_1;
2176
2177 if ( (rval = Svfprintf(&s, fm, args)) >= 0 )
2178 *s.bufp = '\0';
2179
2180 return rval;
2181 }
2182
2183
2184 int
Svdprintf(const char * fm,va_list args)2185 Svdprintf(const char *fm, va_list args)
2186 { int rval;
2187 IOSTREAM *s = Soutput;
2188
2189 Slock(s);
2190 rval = Svfprintf(s, fm, args);
2191 #if defined(_DEBUG) && defined(__WINDOWS__)
2192 Sputc('\0', s);
2193 s->bufp--; /* `Unput' */
2194 OutputDebugString(s->buffer);
2195 #endif
2196 if ( Sflush(s) != 0 )
2197 rval = -1;
2198 Sunlock(s);
2199
2200 return rval;
2201 }
2202
2203
2204 int
Sdprintf(const char * fm,...)2205 Sdprintf(const char *fm, ...)
2206 { va_list args;
2207 int rval;
2208
2209 va_start(args, fm);
2210 rval = Svdprintf(fm, args);
2211 va_end(args);
2212
2213 return rval;
2214 }
2215
2216 #if 0
2217 /*******************************
2218 * SCANF *
2219 *******************************/
2220
2221 int
2222 Svfscanf(IOSTREAM *s, const char *fm, va_list args)
2223 { int done = 0; /* # items converted */
2224 int chread = 0; /* # characters read */
2225 int c = GET(s); /* current character */
2226 int supress; /* if TRUE, don't assign (*) */
2227 int field_width; /* max width of field */
2228 int tsize; /* SZ_SHORT, SZ_NORMAL, SZ_LONG */
2229
2230 while(*fm)
2231 { if ( *fm == ' ' )
2232 { while ( isblank(c) )
2233 c = GET(s);
2234 fm++;
2235 continue;
2236 } else if ( *fm == '%' && fm[1] != '%' )
2237 { supress = FALSE;
2238 field_width = -1;
2239 int size = SZ_STANDARD;
2240
2241 for(;;) /* parse modifiers */
2242 { fm++;
2243 if ( isdigit(*fm) )
2244 { field_width = valdigit(*fm);
2245 for(++fm; isdigit(*fm); fm++)
2246 field_width = 10*field_width + valdigit(*fm);
2247 fm--;
2248 continue;
2249 }
2250 if ( *fm == '*' )
2251 { supress++;
2252 continue;
2253 }
2254 if ( *fm == 'l' )
2255 { size = SZ_LONG;
2256 continue;
2257 }
2258 if ( *fm == 'h' )
2259 { size = SZ_SHORT;
2260 continue;
2261 }
2262 }
2263
2264 if ( *fm != '[' && *fm != c )
2265 while(isblank(c))
2266 c = GET(s);
2267
2268 switch(*fm)
2269 { { intptr_t v; /* collect value here */
2270 int negative; /* true if < 0 */
2271 int base; /* base for conversion */
2272 int ok; /* successful */
2273 case 'd':
2274 base = 10;
2275
2276 do_int:
2277 negative = FALSE;
2278 if ( c == '+' )
2279 c = GET(s);
2280 else if ( c == '-' )
2281 { negative++;
2282 c = GET(s);
2283 }
2284 do_unsigned:
2285 ok = FALSE;
2286 if ( base == 16 ) /* hexadecimal */
2287 { if ( isxdigit(c) )
2288 { v = valxdigit(c);
2289 for(c = GET(s); isxdigit(c); c = GET(s))
2290 v = base*v + valxdigit(c);
2291 ok++;
2292 }
2293 } else
2294 { int cv;
2295
2296 if ( isdigit(c) && (cv=valdigit(c)) < base )
2297 { v = cv;
2298 for(c = GET(s); isdigit(c) && (cv=valdigit(c)) < base; c = GET(s))
2299 v = base*v + cv;
2300 ok++;
2301 }
2302 }
2303
2304 if ( ok )
2305 { if ( !supress )
2306 { if ( negative )
2307 v = -v;
2308 if ( tsize == SZ_SHORT )
2309 { short *vp = va_arg(args, short *);
2310 *vp = v;
2311 } else if ( tsize == SZ_LONG )
2312 { intptr_t *vp = va_arg(args, intptr_t *);
2313 *vp = v;
2314 } else
2315 { int *vp = va_arg(args, int *);
2316 *vp = v;
2317 }
2318 done++;
2319 }
2320 continue; /* with next */
2321 } else
2322 return done;
2323 case 'u':
2324 base = 10;
2325 negative = FALSE;
2326 goto do_unsigned;
2327 case 'o':
2328 base = 8;
2329 goto do_int;
2330 case 'x':
2331 base = 16;
2332 goto do_int;
2333 case 'i':
2334 if ( c == '0' )
2335 { int c2 = GET(s);
2336
2337 if ( c2 == 'x' )
2338 { base = 16;
2339 c = GET(s);
2340 } else
2341 { UNGET(c2, s);
2342 base = 8;
2343 }
2344 negative = FALSE;
2345 goto do_unsigned;
2346 }
2347 base = 10;
2348 goto do_int;
2349 }
2350 case 'n':
2351 if ( !supress )
2352 { if ( tsize == SZ_SHORT )
2353 { short *vp = va_arg(args, short *);
2354 *vp = chread;
2355 } else if ( tsize == SZ_LONG )
2356 { intptr_t *vp = va_arg(args, intptr_t *);
2357 *vp = chread;
2358 } else
2359 { int *vp = va_arg(args, int *);
2360 *vp = chread;
2361 }
2362 done++;
2363 }
2364 fm++;
2365 continue;
2366 case 'E':
2367 case 'e':
2368 case 'f':
2369 case 'G':
2370 case 'g':
2371 { char work[200];
2372 char *w = work;
2373 int ds = 0;
2374 double v;
2375
2376 if ( c == '-' || c == '+' ) /* [+|-] */
2377 { *w++ = c;
2378 c = GET(s);
2379 }
2380 while(isdigit(c)) /* {digit} */
2381 { *w++ = c;
2382 c = GET(s);
2383 ds++;
2384 }
2385 if ( c == '.' ) /* [.] */
2386 *w++ = c;
2387 while(isdigit(c)) /* {digit} */
2388 { *w++ = c;
2389 c = GET(s);
2390 ds++;
2391 }
2392 if ( !ds )
2393 SCAN_ERROR(s)
2394 if ( c == 'e' || c == 'E' ) /* [e<digit>{<digit>}] */
2395 { *w++ = c;
2396 c = GET(s);
2397 if ( !isdigit(c) )
2398 SCAN_ERROR(s)
2399 while(isdigit(c))
2400 { *w++ = c;
2401 c = GET(s);
2402 }
2403 }
2404
2405 if ( !supress )
2406 { *w = '\0';
2407 v = strtod(work, &w)
2408 if ( w == work )
2409 SCAN_ERROR(s);
2410
2411 switch(tsize)
2412 { case SZ_NORMAL:
2413 { float *fp = va_arg(args, float *);
2414 *fp = v;
2415 break;
2416 }
2417 case SZ_LONG:
2418 { double *fp = va_arg(args, double *);
2419 *fp = v;
2420 break;
2421 }
2422 }
2423 done++;
2424 }
2425
2426 fm++;
2427 continue;
2428 }
2429 case 's':
2430 if ( !supress )
2431 { char *sp = va_arg(args, char *);
2432
2433 while(!isblank(c) && field_width-- != 0)
2434 { *sp++ = c;
2435 c = GET(s);
2436 }
2437 } else
2438 while(!isblank(c) && field_width-- != 0)
2439 c = GET(s);
2440 fm++;
2441 continue;
2442 case 'c':
2443 if ( !supress )
2444 { char *cp = va_arg(args, char *);
2445 *cp = c;
2446 }
2447 c = GET(s);
2448 fm++;
2449 continue;
2450 case '[':
2451 { char set[256];
2452
2453 memset(set, 0, sizeof(set));
2454 fm++;
2455 if ( *fm == ']' )
2456 set[*fm++]++;
2457 else if ( *fm == '^' )
2458 { fm++;
2459 negate++;
2460 }
2461 while(*fm != ']')
2462 { if ( *fm == '-' )
2463
2464 }
2465 }
2466 }
2467 } else /* normal character */
2468 { if ( c == *fm )
2469 { c = GET(s);
2470 fm++;
2471 continue;
2472 }
2473
2474 break;
2475 }
2476 }
2477
2478 out:
2479 UNGET(c, s);
2480
2481 return done;
2482 }
2483
2484 #endif /*0*/
2485
2486
2487 /*******************************
2488 * FILTER STREAMS *
2489 *******************************/
2490
2491 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2492 Link two streams in a pipeline, where filter filters data for stream
2493 `parent'. If parent is an output steam we have
2494
2495 application --> filter --> parent -->
2496
2497 If parent is an input stream we have
2498
2499 --> parent --> filter --> application
2500 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2501
2502 int
Sset_filter(IOSTREAM * parent,IOSTREAM * filter)2503 Sset_filter(IOSTREAM *parent, IOSTREAM *filter)
2504 { if ( !parent || parent->magic != SIO_MAGIC )
2505 { errno = EINVAL;
2506 return -1;
2507 }
2508
2509 if ( filter )
2510 { if ( filter->magic != SIO_MAGIC )
2511 { errno = EINVAL;
2512 return -1;
2513 }
2514 }
2515
2516 parent->upstream = filter;
2517 if ( filter )
2518 filter->downstream = parent;
2519
2520 return 0;
2521 }
2522
2523
2524 /*******************************
2525 * FILE STREAMS *
2526 *******************************/
2527
2528 static ssize_t
Sread_file(void * handle,char * buf,size_t size)2529 Sread_file(void *handle, char *buf, size_t size)
2530 { intptr_t h = (intptr_t) handle;
2531 ssize_t bytes;
2532
2533 for(;;)
2534 {
2535 #ifdef __WINDOWS__
2536 bytes = read((int)h, buf, (int)size);
2537 #else
2538 bytes = read((int)h, buf, size);
2539 #endif
2540
2541 if ( bytes == -1 && errno == EINTR )
2542 { if ( PL_handle_signals() < 0 )
2543 { errno = EPLEXCEPTION;
2544 return -1;
2545 }
2546
2547 continue;
2548 }
2549
2550 return bytes;
2551 }
2552 }
2553
2554
2555 static ssize_t
Swrite_file(void * handle,char * buf,size_t size)2556 Swrite_file(void *handle, char *buf, size_t size)
2557 { intptr_t h = (intptr_t) handle;
2558 ssize_t bytes;
2559
2560 for(;;)
2561 {
2562 #ifdef __WINDOWS__
2563 bytes = write((int)h, buf, (int)size);
2564 #else
2565 bytes = write((int)h, buf, size);
2566 #endif
2567
2568 if ( bytes == -1 && errno == EINTR )
2569 { if ( PL_handle_signals() < 0 )
2570 { errno = EPLEXCEPTION;
2571 return -1;
2572 }
2573
2574 continue;
2575 }
2576
2577 return bytes;
2578 }
2579 }
2580
2581
2582 static long
Sseek_file(void * handle,long pos,int whence)2583 Sseek_file(void *handle, long pos, int whence)
2584 { intptr_t h = (intptr_t) handle;
2585
2586 /* cannot do EINTR according to man */
2587 return lseek((int)h, pos, whence);
2588 }
2589
2590
2591 #ifdef O_LARGEFILES
2592 static int64_t
Sseek_file64(void * handle,int64_t pos,int whence)2593 Sseek_file64(void *handle, int64_t pos, int whence)
2594 { intptr_t h = (intptr_t) handle;
2595
2596 /* cannot do EINTR according to man */
2597 return lseek((int)h, pos, whence);
2598 }
2599 #endif
2600
2601
2602 static int
Sclose_file(void * handle)2603 Sclose_file(void *handle)
2604 { intptr_t h = (intptr_t) handle;
2605 int rc;
2606
2607 do
2608 { rc = close((int) h);
2609 } while ( rc == -1 && errno == EINTR );
2610
2611 return rc;
2612 }
2613
2614
2615 static int
Scontrol_file(void * handle,int action,void * arg)2616 Scontrol_file(void *handle, int action, void *arg)
2617 { intptr_t h = (intptr_t) handle;
2618 int fd = (int)h;
2619
2620 switch(action)
2621 { case SIO_GETSIZE:
2622 { intptr_t *rval = arg;
2623 struct stat buf;
2624
2625 if ( fstat(fd, &buf) == 0 )
2626 { *rval = buf.st_size;
2627 return 0;
2628 }
2629 return -1;
2630 }
2631 case SIO_SETENCODING:
2632 case SIO_FLUSHOUTPUT:
2633 return 0;
2634 default:
2635 return -1;
2636 }
2637 }
2638
2639
2640 IOFUNCTIONS Sfilefunctions =
2641 { Sread_file,
2642 Swrite_file,
2643 Sseek_file,
2644 Sclose_file,
2645 Scontrol_file,
2646 #ifdef O_LARGEFILES
2647 Sseek_file64
2648 #else
2649 NULL
2650 #endif
2651 };
2652
2653
2654 IOFUNCTIONS Sttyfunctions =
2655 { Sread_file,
2656 Swrite_file,
2657 NULL,
2658 Sclose_file,
2659 Scontrol_file,
2660 #ifdef O_LARGEFILES
2661 Sseek_file64
2662 #else
2663 NULL
2664 #endif
2665 };
2666
2667
2668 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2669 (*) Windows isatty() is totally broken since VC9; crashing the
2670 application instead of returning EINVAL on wrong values of fd. As we
2671 provide the socket-id through Sfileno, this code crashes on
2672 tcp_open_socket(). As ttys and its detection is of no value on Windows
2673 anyway, we skip this. Second, Windows doesn't have fork(), so FD_CLOEXEC
2674 is of no value.
2675 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2676
2677 IOSTREAM *
Snew(void * handle,int flags,IOFUNCTIONS * functions)2678 Snew(void *handle, int flags, IOFUNCTIONS *functions)
2679 { IOSTREAM *s;
2680 int fd;
2681
2682 if ( !(s = malloc(sizeof(IOSTREAM))) )
2683 { errno = ENOMEM;
2684 return NULL;
2685 }
2686 memset((char *)s, 0, sizeof(IOSTREAM));
2687 s->magic = SIO_MAGIC;
2688 s->lastc = EOF;
2689 s->flags = flags;
2690 s->handle = handle;
2691 s->functions = functions;
2692 s->timeout = -1; /* infinite */
2693 s->posbuf.lineno = 1;
2694 s->encoding = ENC_ISO_LATIN_1;
2695 #if CRLF_MAPPING
2696 s->newline = SIO_NL_DOS;
2697 #endif
2698 if ( flags & SIO_RECORDPOS )
2699 s->position = &s->posbuf;
2700 #ifdef O_PLMT
2701 if ( !(flags & SIO_NOMUTEX) )
2702 { if ( !(s->mutex = malloc(sizeof(recursiveMutex))) )
2703 { free(s);
2704 return NULL;
2705 }
2706 recursiveMutexInit(s->mutex);
2707 }
2708 #endif
2709
2710 #ifndef __WINDOWS__ /* (*) */
2711 if ( (fd = Sfileno(s)) >= 0 )
2712 { if ( isatty(fd) )
2713 s->flags |= SIO_ISATTY;
2714 #if defined(F_SETFD) && defined(FD_CLOEXEC)
2715 fcntl(fd, F_SETFD, FD_CLOEXEC);
2716 #endif
2717 }
2718 #endif
2719
2720 return s;
2721 }
2722
2723
2724 #ifndef O_BINARY
2725 #define O_BINARY 0
2726 #endif
2727
2728 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2729 Open a file. In addition to the normal arguments, "lr" means get a read
2730 (shared-) lock on the file and "lw" means get an write (exclusive-)
2731 lock. How much do we need to test here?
2732
2733 Note that the low-level open is always binary as O_TEXT open files
2734 result in lost and corrupted data in some encodings (UTF-16 is one of
2735 them). Sgetcode() and Sputcode() do the LF <-> CRLF mapping of
2736 CRLF_MAPPING is defined.
2737 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2738
2739 IOSTREAM *
Sopen_file(const char * path,const char * how)2740 Sopen_file(const char *path, const char *how)
2741 { int fd;
2742 int oflags = O_BINARY;
2743 int flags = SIO_FILE|SIO_TEXT|SIO_RECORDPOS|SIO_FBUF;
2744 int op = *how++;
2745 intptr_t lfd;
2746 enum {lnone=0,lread,lwrite} lock = lnone;
2747 IOSTREAM *s;
2748 IOENC enc = ENC_UNKNOWN;
2749
2750 for( ; *how; how++)
2751 { switch(*how)
2752 { case 'b': /* binary */
2753 flags &= ~SIO_TEXT;
2754 enc = ENC_OCTET;
2755 break;
2756 case 'r': /* no record */
2757 flags &= ~SIO_RECORDPOS;
2758 break;
2759 case 'l': /* lock r: read, w: write */
2760 if ( *++how == 'r' )
2761 lock = lread;
2762 else if ( *how == 'w' )
2763 lock = lwrite;
2764 else
2765 { errno = EINVAL;
2766 return NULL;
2767 }
2768 break;
2769 default:
2770 errno = EINVAL;
2771 return NULL;
2772 }
2773 }
2774
2775 #if O_LARGEFILES && defined(O_LARGEFILE)
2776 oflags |= O_LARGEFILE;
2777 #endif
2778
2779 switch(op)
2780 { case 'w':
2781 fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|oflags, 0666);
2782 flags |= SIO_OUTPUT;
2783 break;
2784 case 'a':
2785 fd = open(path, O_WRONLY|O_CREAT|O_APPEND|oflags, 0666);
2786 flags |= SIO_OUTPUT|SIO_APPEND;
2787 break;
2788 case 'u':
2789 fd = open(path, O_WRONLY|O_CREAT|oflags, 0666);
2790 flags |= SIO_OUTPUT|SIO_UPDATE;
2791 break;
2792 case 'r':
2793 fd = open(path, O_RDONLY|oflags);
2794 flags |= SIO_INPUT;
2795 break;
2796 default:
2797 errno = EINVAL;
2798 return NULL;
2799 }
2800
2801
2802
2803 if ( fd < 0 )
2804 return NULL;
2805
2806 if ( lock )
2807 {
2808 #ifdef FCNTL_LOCKS
2809 struct flock buf;
2810
2811 memset(&buf, 0, sizeof(buf));
2812 buf.l_type = (lock == lread ? F_RDLCK : F_WRLCK);
2813
2814 if ( fcntl(fd, F_SETLKW, &buf) < 0 )
2815 { int save = errno;
2816 close(fd);
2817 errno = save;
2818 return NULL;
2819 }
2820 #else /* we don't have locking */
2821 #if __WINDOWS__
2822 HANDLE h = (HANDLE)_get_osfhandle(fd);
2823 OVERLAPPED ov;
2824
2825 memset(&ov, 0, sizeof(ov));
2826 if ( !LockFileEx(h, (lock == lread ? 0 : LOCKFILE_EXCLUSIVE_LOCK),
2827 0,
2828 0, 0xfffffff,
2829 &ov) )
2830 { close(fd);
2831 errno = EACCES; /* TBD: proper error */
2832 return NULL;
2833 }
2834 #else
2835 close(fd);
2836 errno = EINVAL;
2837 return NULL;
2838 #endif
2839 #endif
2840 }
2841
2842 lfd = (intptr_t)fd;
2843 s = Snew((void *)lfd, flags, &Sfilefunctions);
2844 if ( enc != ENC_UNKNOWN )
2845 s->encoding = enc;
2846 if ( lock )
2847 s->flags |= SIO_ADVLOCK;
2848
2849 return s;
2850 }
2851
2852
2853 IOSTREAM *
Sfdopen(int fd,const char * type)2854 Sfdopen(int fd, const char *type)
2855 { intptr_t lfd;
2856 int flags = SIO_FILE|SIO_RECORDPOS|SIO_FBUF;
2857
2858 if ( fd < 0 )
2859 { errno = EINVAL;
2860 return NULL;
2861 }
2862 #if defined(HAVE_FCNTL) && defined(F_GETFL)
2863 if ( fcntl(fd, F_GETFL) == -1 )
2864 return NULL;
2865 #endif
2866
2867 if ( *type == 'r' )
2868 { flags |= SIO_INPUT;
2869 } else if ( *type == 'w' )
2870 { flags |= SIO_OUTPUT;
2871 } else
2872 { errno = EINVAL;
2873 return NULL;
2874 }
2875 if ( type[1] != 'b' )
2876 flags |= SIO_TEXT;
2877
2878 lfd = (intptr_t)fd;
2879
2880 return Snew((void *)lfd, flags, &Sfilefunctions);
2881 }
2882
2883 /* MT: as long as s is valid, this should be ok
2884 */
2885
2886 int
Sfileno(IOSTREAM * s)2887 Sfileno(IOSTREAM *s)
2888 { int n;
2889
2890 if ( s->flags & SIO_FILE )
2891 { intptr_t h = (intptr_t)s->handle;
2892 n = (int)h;
2893 } else if ( s->flags & SIO_PIPE )
2894 { n = fileno((FILE *)s->handle);
2895 } else if ( s->functions->control &&
2896 (*s->functions->control)(s->handle,
2897 SIO_GETFILENO,
2898 (void *)&n) == 0 )
2899 { ;
2900 } else
2901 { errno = EINVAL;
2902 n = -1; /* no file stream */
2903 }
2904
2905 return n;
2906 }
2907
2908
2909 /*******************************
2910 * PIPES *
2911 *******************************/
2912
2913 #ifdef HAVE_POPEN
2914 #ifdef __WINDOWS__
2915 #include "popen.c"
2916
2917 #define popen(cmd, how) pt_popen(cmd, how)
2918 #define pclose(fd) pt_pclose(fd)
2919 #endif
2920
2921 static ssize_t
Sread_pipe(void * handle,char * buf,size_t size)2922 Sread_pipe(void *handle, char *buf, size_t size)
2923 { FILE *fp = handle;
2924
2925 #ifdef __WINDOWS__
2926 return read(fileno(fp), buf, (unsigned int)size);
2927 #else
2928 return read(fileno(fp), buf, size);
2929 #endif
2930 }
2931
2932
2933 static ssize_t
Swrite_pipe(void * handle,char * buf,size_t size)2934 Swrite_pipe(void *handle, char *buf, size_t size)
2935 { FILE *fp = handle;
2936
2937 #ifdef __WINDOWS__
2938 return write(fileno(fp), buf, (unsigned int)size);
2939 #else
2940 return write(fileno(fp), buf, size);
2941 #endif
2942 }
2943
2944
2945 static int
Sclose_pipe(void * handle)2946 Sclose_pipe(void *handle)
2947 { FILE *fp = handle;
2948
2949 pclose(fp);
2950 return 0;
2951 }
2952
2953
2954 IOFUNCTIONS Spipefunctions =
2955 { Sread_pipe,
2956 Swrite_pipe,
2957 (Sseek_function)0,
2958 Sclose_pipe
2959 };
2960
2961
2962 IOSTREAM *
Sopen_pipe(const char * command,const char * type)2963 Sopen_pipe(const char *command, const char *type)
2964 { char mode[2];
2965 FILE *fd;
2966
2967 #if 0
2968 Sdprintf("Opening \"%s\", mode \"%s\" --> %p (%d)\n",
2969 command, type, fd, errno);
2970 #endif
2971
2972 mode[0] = type[0];
2973 mode[1] = '\0';
2974
2975 if ( (fd = popen(command, mode)) )
2976 { int flags;
2977
2978 if ( *type == 'r' )
2979 flags = SIO_PIPE|SIO_INPUT|SIO_FBUF;
2980 else
2981 flags = SIO_PIPE|SIO_OUTPUT|SIO_FBUF;
2982
2983 return Snew((void *)fd, flags, &Spipefunctions);
2984 }
2985
2986 return NULL;
2987 }
2988
2989 #endif /*HAVE_POPEN*/
2990
2991 /*******************************
2992 * MEMORY STREAMS *
2993 *******************************/
2994
2995 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2996 Memory streams form a replacement for sprintf(), sscanf() and friends.
2997 They allow regarding a piece of (for output) malloc() maintained memory
2998 to serve as a temporary buffer.
2999
3000 MT: we assume these handles are not passed between threads
3001 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
3002
3003 typedef struct
3004 { size_t here; /* `here' location */
3005 size_t size; /* size of buffer */
3006 size_t *sizep; /* pointer to size */
3007 size_t allocated; /* allocated size */
3008 char **buffer; /* allocated buffer */
3009 int malloced; /* malloc() maintained */
3010 } memfile;
3011
3012
3013 void
Sfree(void * ptr)3014 Sfree(void *ptr) /* Windows: must free from same */
3015 { free(ptr); /* DLL */
3016 }
3017
3018
3019 static size_t
S__memfile_nextsize(size_t needed)3020 S__memfile_nextsize(size_t needed)
3021 { size_t size = 512;
3022
3023 while ( size < needed )
3024 size *= 2;
3025
3026 return size;
3027 }
3028
3029
3030 static ssize_t
Swrite_memfile(void * handle,char * buf,size_t size)3031 Swrite_memfile(void *handle, char *buf, size_t size)
3032 { memfile *mf = handle;
3033
3034 if ( mf->here + size + 1 >= mf->allocated )
3035 { size_t ns = S__memfile_nextsize(mf->here + size + 1);
3036 char *nb;
3037
3038 if ( mf->allocated == 0 || !mf->malloced )
3039 { if ( !(nb = malloc(ns)) )
3040 { errno = ENOMEM;
3041 return -1;
3042 }
3043 if ( !mf->malloced )
3044 { if ( *mf->buffer )
3045 memcpy(nb, *mf->buffer, mf->allocated);
3046 mf->malloced = TRUE;
3047 }
3048 } else
3049 { if ( !(nb = realloc(*mf->buffer, ns)) )
3050 { errno = ENOMEM;
3051 return -1;
3052 }
3053 }
3054
3055 mf->allocated = ns;
3056 *mf->buffer = nb;
3057 }
3058
3059 memcpy(&(*mf->buffer)[mf->here], buf, size);
3060 mf->here += size;
3061
3062 if ( mf->here > mf->size )
3063 { mf->size = mf->here;
3064 if ( mf->sizep ) /* make externally known */
3065 *mf->sizep = mf->size;
3066 (*mf->buffer)[mf->size] = '\0';
3067 }
3068
3069 return size;
3070 }
3071
3072
3073 static ssize_t
Sread_memfile(void * handle,char * buf,size_t size)3074 Sread_memfile(void *handle, char *buf, size_t size)
3075 { memfile *mf = handle;
3076
3077 if ( size + mf->here > mf->size )
3078 { if ( mf->here > mf->size )
3079 size = 0;
3080 else
3081 size = mf->size - mf->here;
3082 }
3083
3084 memcpy(buf, &(*mf->buffer)[mf->here], size);
3085 mf->here += size;
3086
3087 return size;
3088 }
3089
3090
3091 static long
Sseek_memfile(void * handle,long offset,int whence)3092 Sseek_memfile(void *handle, long offset, int whence)
3093 { memfile *mf = handle;
3094
3095 switch(whence)
3096 { case SIO_SEEK_SET:
3097 break;
3098 case SIO_SEEK_CUR:
3099 offset += (long)mf->here; /* Win64: truncates */
3100 break;
3101 case SIO_SEEK_END:
3102 offset = (long)mf->size - offset; /* Win64 */
3103 break;
3104 default:
3105 errno = EINVAL;
3106 return -1;
3107 }
3108 if ( offset < 0 || offset > (long)mf->size )
3109 { errno = EINVAL;
3110 return -1;
3111 }
3112 mf->here = offset;
3113
3114 return offset;
3115 }
3116
3117
3118 static int
Sclose_memfile(void * handle)3119 Sclose_memfile(void *handle)
3120 { memfile *mf = handle;
3121
3122 if ( mf )
3123 { free(mf);
3124 return 0;
3125 }
3126
3127 errno = EINVAL; /* not opened */
3128 return -1;
3129 }
3130
3131
3132 IOFUNCTIONS Smemfunctions =
3133 { Sread_memfile,
3134 Swrite_memfile,
3135 Sseek_memfile,
3136 Sclose_memfile
3137 };
3138
3139
3140 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3141 Sopenmem(char **buffer, size_t *sizep, const char* mode)
3142 Open a memory area as a stream. Output streams will automatically
3143 resized using realloc() if *size = 0 or the stream is opened with mode
3144 "wa".
3145
3146 If the buffer is allocated or enlarged, this is achieved using malloc()
3147 or realloc(). In this case the returned buffer should be freed by the
3148 caller when done. Example:
3149
3150 { char buf[1024]; (don't allocate for small stuff)
3151 char *s = buf;
3152 IOSTREAM *fd;
3153 size_t size = sizeof(buf);
3154
3155 fd = Sopenmem(&s, &size, "w");
3156 ...
3157 Sclose(fd);
3158 ...
3159 if ( s != buf ) (appearently moved)
3160 Sfree(s);
3161 }
3162
3163 Note: Its is NOT allows to access streams created with this call from
3164 multiple threads. This is ok for all usage inside Prolog itself (often
3165 through tellString()/toldString(). This call is intented to use write
3166 and other output predicates to create strings.
3167 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
3168
3169 IOSTREAM *
Sopenmem(char ** buffer,size_t * sizep,const char * mode)3170 Sopenmem(char **buffer, size_t *sizep, const char *mode)
3171 { memfile *mf = malloc(sizeof(memfile));
3172 int flags = SIO_FBUF|SIO_RECORDPOS|SIO_NOMUTEX;
3173 size_t size;
3174
3175 if ( !mf )
3176 { errno = ENOMEM;
3177 return NULL;
3178 }
3179
3180 mf->malloced = FALSE;
3181
3182 switch(*mode)
3183 { case 'r':
3184 flags |= SIO_INPUT;
3185 if ( sizep == NULL || *sizep == (size_t)-1 )
3186 size = (*buffer ? strlen(*buffer) : 0);
3187 else
3188 size = *sizep;
3189 mf->size = size;
3190 mf->allocated = size+1;
3191 break;
3192 case 'w':
3193 flags |= SIO_OUTPUT;
3194 mf->size = 0;
3195 mf->allocated = (sizep ? *sizep : 0);
3196 if ( *buffer == NULL || mode[1] == 'a' )
3197 mf->malloced = TRUE;
3198 if ( *buffer )
3199 *buffer[0] = '\0';
3200 if ( sizep )
3201 *sizep = mf->size;
3202 break;
3203 default:
3204 free(mf);
3205 errno = EINVAL;
3206 return NULL;
3207 }
3208
3209 mf->sizep = sizep;
3210 mf->here = 0;
3211 mf->buffer = buffer;
3212
3213 return Snew(mf, flags, &Smemfunctions);
3214 }
3215
3216 /*******************************
3217 * STRINGS *
3218 *******************************/
3219
3220 /* MT: we assume these handles are not passed between threads
3221 */
3222
3223 static ssize_t
Sread_string(void * handle,char * buf,size_t size)3224 Sread_string(void *handle, char *buf, size_t size)
3225 { return 0; /* signal EOF */
3226 }
3227
3228 static ssize_t
Swrite_string(void * handle,char * buf,size_t size)3229 Swrite_string(void *handle, char *buf, size_t size)
3230 { errno = ENOSPC; /* signal error */
3231 return -1;
3232 }
3233
3234 static int
Sclose_string(void * handle)3235 Sclose_string(void *handle)
3236 { IOSTREAM *s = handle;
3237
3238 if ( s->flags & SIO_OUTPUT )
3239 { if ( s->bufp < s->limitp )
3240 { *s->bufp++ = '\0';
3241 return 0;
3242 } else
3243 { errno = ENOSPC; /* signal error */
3244 return -1;
3245 }
3246 } else
3247 return 0; /* input string */
3248 }
3249
3250 IOFUNCTIONS Sstringfunctions =
3251 { Sread_string,
3252 Swrite_string,
3253 (Sseek_function)0,
3254 Sclose_string
3255 };
3256
3257
3258 IOSTREAM *
Sopen_string(IOSTREAM * s,char * buf,size_t size,const char * mode)3259 Sopen_string(IOSTREAM *s, char *buf, size_t size, const char *mode)
3260 { int flags = SIO_FBUF|SIO_USERBUF;
3261
3262 if ( !s )
3263 { if ( !(s = malloc(sizeof(IOSTREAM))) )
3264 { errno = ENOMEM;
3265 return NULL;
3266 }
3267 } else
3268 flags |= SIO_STATIC;
3269
3270 memset((char *)s, 0, sizeof(IOSTREAM));
3271 s->timeout = -1;
3272 s->buffer = buf;
3273 s->bufp = buf;
3274 s->unbuffer = buf;
3275 s->handle = s; /* for Sclose_string() */
3276 s->functions = &Sstringfunctions;
3277 s->encoding = ENC_ISO_LATIN_1;
3278
3279 switch(*mode)
3280 { case 'r':
3281 if ( size == (size_t)-1 )
3282 size = strlen(buf);
3283 flags |= SIO_INPUT;
3284 break;
3285 case 'w':
3286 flags |= SIO_OUTPUT;
3287 break;
3288 default:
3289 errno = EINVAL;
3290 return NULL;
3291 }
3292
3293 s->flags = flags;
3294 s->limitp = &buf[size];
3295 s->magic = SIO_MAGIC;
3296
3297 return s;
3298 }
3299
3300 /*******************************
3301 * STANDARD HANDLES *
3302 *******************************/
3303
3304 #define STDIO(n, f) { NULL, NULL, NULL, NULL, \
3305 EOF, SIO_MAGIC, 0, f, {0, 0, 0}, NULL, \
3306 ((void *)(n)), &Sttyfunctions, \
3307 0, NULL, \
3308 (void (*)(void *))0, NULL, \
3309 -1, \
3310 0, \
3311 ENC_ISO_LATIN_1 \
3312 }
3313
3314 #define SIO_STDIO (SIO_FILE|SIO_STATIC|SIO_NOCLOSE|SIO_ISATTY|SIO_TEXT)
3315 #define STDIO_STREAMS \
3316 STDIO(0, SIO_STDIO|SIO_LBUF|SIO_INPUT|SIO_NOFEOF), /* Sinput */ \
3317 STDIO(1, SIO_STDIO|SIO_LBUF|SIO_OUTPUT|SIO_REPPL), /* Soutput */ \
3318 STDIO(2, SIO_STDIO|SIO_NBUF|SIO_OUTPUT|SIO_REPPL) /* Serror */
3319
3320
3321 IOSTREAM S__iob[] =
3322 { STDIO_STREAMS
3323 };
3324
3325
3326 static const IOSTREAM S__iob0[] =
3327 { STDIO_STREAMS
3328 };
3329
3330
3331 void
SinitStreams()3332 SinitStreams()
3333 { static int done;
3334
3335 if ( !done++ )
3336 { int i;
3337 IOENC enc = initEncoding();
3338
3339 for(i=0; i<=2; i++)
3340 { if ( !isatty(i) )
3341 { S__iob[i].flags &= ~SIO_ISATTY;
3342 S__iob[i].functions = &Sfilefunctions; /* Check for pipe? */
3343 }
3344 if ( S__iob[i].encoding == ENC_ISO_LATIN_1 )
3345 S__iob[i].encoding = enc;
3346 #ifdef O_PLMT
3347 S__iob[i].mutex = malloc(sizeof(recursiveMutex));
3348 recursiveMutexInit(S__iob[i].mutex);
3349 #endif
3350 #if CRLF_MAPPING
3351 _setmode(i, O_BINARY);
3352 S__iob[i].newline = SIO_NL_DOS;
3353 #endif
3354 }
3355
3356 #ifdef __WINDOWS__
3357 pt_init(); /* init popen() issues */
3358 #endif
3359 }
3360 }
3361
3362
3363 IOSTREAM *
S__getiob()3364 S__getiob()
3365 { return S__iob;
3366 }
3367
3368
3369 /*******************************
3370 * HOOKS *
3371 *******************************/
3372
3373 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3374 This allows external packages (Prolog itself) to monitor the destruction
3375 of streams.
3376 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
3377
3378 typedef struct _close_hook
3379 { struct _close_hook *next;
3380 void (*hook)(IOSTREAM *s);
3381 } close_hook;
3382
3383 static close_hook *close_hooks;
3384
3385 static void
run_close_hooks(IOSTREAM * s)3386 run_close_hooks(IOSTREAM *s)
3387 { close_hook *p;
3388
3389 for(p=close_hooks; p; p = p->next)
3390 (*p->hook)(s);
3391
3392 if ( s->close_hook )
3393 (*s->close_hook)(s->closure);
3394 }
3395
3396 int
Sclosehook(void (* hook)(IOSTREAM * s))3397 Sclosehook(void (*hook)(IOSTREAM *s))
3398 { close_hook *h = malloc(sizeof(*h));
3399
3400 if ( !h )
3401 return -1;
3402 h->next = close_hooks;
3403 h->hook = hook;
3404 close_hooks = h;
3405
3406 return 0;
3407 }
3408
3409
3410 /*******************************
3411 * CLEANUP *
3412 *******************************/
3413
3414 void
Sreset(void)3415 Sreset(void)
3416 { IOSTREAM *s;
3417
3418 if ( (s=Sinput) && s->magic == SIO_MAGIC )
3419 { s->bufp = s->limitp = s->buffer;
3420 }
3421 if ( (s=Soutput) && s->magic == SIO_MAGIC )
3422 { s->bufp = s->buffer;
3423 }
3424 if ( (s=Serror) && s->magic == SIO_MAGIC )
3425 { s->bufp = s->buffer;
3426 }
3427 }
3428
3429
3430 void
Scleanup(void)3431 Scleanup(void)
3432 { close_hook *p, *next;
3433 int i;
3434
3435 for(p=close_hooks; p; p=next)
3436 { next = p->next;
3437 free(p);
3438 }
3439
3440 close_hooks = NULL;
3441
3442 for(i=0; i<=2; i++)
3443 { IOSTREAM *s = &S__iob[i];
3444
3445 s->bufp = s->buffer; /* avoid actual flush */
3446 S__removebuf(s);
3447
3448 #ifdef O_PLMT
3449 if ( S__iob[i].mutex )
3450 { recursiveMutex *m = S__iob[i].mutex;
3451
3452 S__iob[i].mutex = NULL;
3453 recursiveMutexDelete(m);
3454 free(m);
3455 }
3456 #endif
3457
3458 *s = S__iob0[i]; /* re-initialise */
3459 }
3460 }
3461
3462