YAP 7.1.0
iopreds.c
Go to the documentation of this file.
1/*************************************************************************
2 * *
3 * YAP Prolog *
4 * *
5 * Yap Prolog was developed at NCCUP - Universidade do Porto *
6 * *
7 * Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
8 * *
9 **************************************************************************
10 * *
11 * File: iopreds.c *
12 * Last rev: 5/2/88 *
13 * mods: *
14 * comments: Input/Output C implemented predicates *
15 * *
16 *************************************************************************/
17#ifdef SCCS
18static char SccsId[] = "%W% %G%";
19#endif
20
29/*
30 * This file includes the definition of a miscellania of standard predicates *
31 *for yap refering to: Files and GLOBAL_1588
32 *451ams, Simple Input/Output,
33 *
34 */
35
36#include "Yap.h"
37#include "YapEval.h"
38#include "YapHeap.h"
39#include "YapText.h"
40#include "Yatom.h"
41#include "yapio.h"
42#include "sysbits.h"
43#include <stdlib.h>
44
45#if HAVE_UNISTD_H
46
47#include <unistd.h>
48
49#endif
50#if HAVE_STDARG_H
51
52#include <stdarg.h>
53
54#endif
55#if HAVE_CTYPE_H
56#endif
57#if HAVE_WCTYPE_Hab
58#endif
59#if HAVE_SYS_TIME_H
60
61#include <sys/time.h>
62
63#endif
64#if HAVE_SYS_TYPES_H
65
66#include <sys/types.h>
67
68#endif
69#ifdef HAVE_SYS_STAT_H
70
71#include <sys/stat.h>
72
73#endif
74#if HAVE_SYS_SELECT_H && !_MSC_VER && !defined(__MINGW32__)
75
76#include <sys/select.h>
77
78#endif
79#ifdef HAVE_UNISTD_H
80#endif
81#if HAVE_STRING_H
82
83#include <string.h>
84
85#endif
86#if HAVE_SIGNAL_H
87
88#include <signal.h>
89
90#endif
91#if HAVE_FCNTL_H
92/* for O_BINARY and O_TEXT in WIN32 */
93#include <fcntl.h>
94
95#endif
96#ifdef _WIN32
97#if HAVE_IO_H
98/* Windows */
99#include <io.h>
100#endif
101#endif
102#if !HAVE_STRNCAT
103#define strncat(X, Y, Z) strcat(X, Y)
104#endif
105#if !HAVE_STRNCPY
106#define strncpy(X, Y, Z) strcpy(X, Y)
107#endif
108#if _MSC_VER || defined(__MINGW32__)
109#if HAVE_SOCKET
110#include <winsock2.h>
111#endif
112#include <windows.h>
113#ifndef S_ISDIR
114#define S_ISDIR(x) (((x)&_S_IFDIR) == _S_IFDIR)
115#endif
116#endif
117
118#include "iopreds.h"
119
120#include "getw.h"
121
122static int get_wchar_from_file(int);
123
124FILE *Yap_stdin;
125FILE *Yap_stdout;
126FILE *Yap_stderr;
127
128
129 char *Yap_VF(const char *path) {
130 char *out;
131
132 out = (char *)malloc(MAX_PATH + 1);
133 if (GLOBAL_cwd == NULL || GLOBAL_cwd[0] == 0 ||
134 !Yap_IsAbsolutePath(path, false)) {
135 return (char *)path;
136 }
137 strcpy(out, GLOBAL_cwd);
138 strcat(out, "/");
139 strcat(out, path);
140 return out;
141}
142
143char *Yap_VFAlloc(const char *path) {
144 char *out;
145
146 out = (char *)malloc(MAX_PATH + 1);
147 if (GLOBAL_cwd == NULL || GLOBAL_cwd[0] == 0 ||
148 !Yap_IsAbsolutePath(path, false)) {
149 return (char *)path;
150 }
151 strcpy(out, GLOBAL_cwd);
152 strcat(out, "/");
153 strcat(out, path);
154 return out;
155}
156
157
158int ResetEOF(StreamDesc *s) {
159 if (s->status & Eof_Error_Stream_f) {
160 Atom name = s->name;
161 // Yap_CloseStream(s - GLOBAL_Stream);
162 Yap_ThrowError(PERMISSION_ERROR_INPUT_PAST_END_OF_STREAM, MkAtomTerm(name),
163 "GetC");
164 return FALSE;
165 } else if (s->status & Reset_Eof_Stream_f) {
166 s->status &= ~Push_Eof_Stream_f;
167 /* reset the eof indicator on file */
168 if (feof(s->file))
169 clearerr(s->file);
170 /* reset our function for reading input */
171 Yap_DefaultStreamOps(s);
172 /* next, reset our own error indicator */
173 s->status &= ~Eof_Stream_f;
174 /* try reading again */
175 return TRUE;
176 } else {
177 s->status |= Past_Eof_Stream_f;
178 return FALSE;
179 }
180}
181
182/* handle reading from a stream after having found an EOF */
183static int EOFWGetc(int sno) {
184 register StreamDesc *s = &GLOBAL_Stream[sno];
185
186 if (s->status & Push_Eof_Stream_f) {
187 /* ok, we have pushed an EOF, send it away */
188 s->status &= ~Push_Eof_Stream_f;
189 return EOF;
190 }
191 if (ResetEOF(s)) {
192 Yap_DefaultStreamOps(s);
193 return (s->stream_wgetc(sno));
194 }
195 return EOF;
196}
197
198static int EOFGetc(int sno) {
199 register StreamDesc *s = &GLOBAL_Stream[sno];
200
201 if (s->status & Push_Eof_Stream_f) {
202 /* ok, we have pushed an EOF, send it away */
203 s->status &= ~Push_Eof_Stream_f;
204 ResetEOF(s);
205 return EOF;
206 }
207 if (ResetEOF(s)) {
208 Yap_DefaultStreamOps(s);
209 return s->stream_getc(sno);
210 }
211 return EOF;
212}
213
214static void unix_upd_stream_info(StreamDesc *s) {
215 if (s->status & InMemory_Stream_f) {
216 s->status |= Seekable_Stream_f;
217 return;
218 }
219 Yap_socketStream(s);
220#if _MSC_VER || defined(__MINGW32__)
221 {
222 if (_isatty(_fileno(s->file))) {
223 s->status |= Tty_Stream_f | Reset_Eof_Stream_f | Promptable_Stream_f;
224 /* make all console descriptors unbuffered */
225 setvbuf(s->file, NULL, _IONBF, 0);
226 return;
227 }
228#if _MSC_VER
229 /* standard error stream should never be buffered */
230 else if (StdErrStream == s - GLOBAL_Stream) {
231 setvbuf(s->file, NULL, _IONBF, 0);
232 }
233#endif
234 s->status |= Seekable_Stream_f;
235 return;
236 }
237#else
238#if HAVE_ISATTY
239#if __simplescalar__
240 /* isatty does not seem to work with simplescar. I'll assume the first
241 three streams will probably be ttys (pipes are not thatg different) */
242 if (s - Stream < 3) {
243 s->name = AtomTty;
244 s->status |= Tty_Stream_f | Reset_Eof_Stream_f | Promptable_Stream_f;
245 }
246#else
247 {
248 int filedes; /* visualc */
249 if (!s->file) {
250 s->name = AtomNil;
251 return;
252 }
253 filedes = fileno(s->file);
254 if (isatty(filedes)) {
255 char buf1[PATH_MAX];
256#if HAVE_TTYNAME
257 int rc = ttyname_r(filedes,buf1, MAX_PATH - 1);
258 if (rc == 0)
259 s->name = Yap_LookupAtom(buf1);
260 else
261 s->name = AtomTtys;
262#else
263 s->name = AtomTty;
264#endif
265 s->status |= Tty_Stream_f | Reset_Eof_Stream_f | Promptable_Stream_f;
266 return;
267 }
268 }
269#endif
270#endif /* HAVE_ISATTY */
271#endif /* _MSC_VER */
272 s->status |= Seekable_Stream_f;
273}
274
275static void default_peek(StreamDesc *st) {
276 {
277 st->stream_peek = Yap_peekChar;
278 st->stream_wpeek = Yap_peekWide;
279 }
280 if (st->status & Eof_Stream_f) {
281 st->stream_peek = EOFPeek;
282 st->stream_wpeek = EOFPeek;
283 st->stream_getc = EOFGetc;
284 st->stream_wgetc = EOFWGetc;
285 }
286 if (GLOBAL_CharConversionTable != NULL)
287 st->stream_wgetc_for_read = ISOWGetc;
288 else
290}
291
292void Yap_DefaultStreamOps(StreamDesc *st) {
293 CACHE_REGS
294
295 unix_upd_stream_info(st);
296 st->stream_wputc = put_wchar;
297 st->stream_wgetc = get_wchar;
298 if (st->vfs && !st->file) {
299 st->stream_putc = st->vfs->put_char;
300 st->stream_wputc = st->vfs->put_wchar;
301 st->stream_getc = st->vfs->get_char;
302 st->stream_wgetc = st->vfs->get_wchar;
303 default_peek(st);
304 return;
305 } else {
306 if (st->encoding == ENC_ISO_UTF8)
307 st->stream_wgetc = get_wchar_UTF8;
308 st->stream_putc = FilePutc;
309 st->stream_getc = PlGetc;
310 if (st->status & Pipe_Stream_f) {
311 Yap_PipeOps(st);
312 } else if (st->status & InMemory_Stream_f) {
313 Yap_MemOps(st);
314#if HAVE_SETBUF
315 setbuf(stdin, NULL);
316#endif /* HAVE_SETBUF */
317 } else if (st->status & Tty_Stream_f) {
318 Yap_ConsoleOps(st);
319 } else {
320 }
321 if (st->status & (Promptable_Stream_f)) {
322 Yap_ConsoleOps(st);
323 }
324#ifndef _WIN32
325 else if (st->file != NULL && 0 && !(st->status & InMemory_Stream_f)) {
326 st->stream_wgetc = get_wchar_from_file;
327 }
328#endif
329 if (st->buf.on) {
330 st->stream_getc = Yap_popChar;
331 st->stream_wgetc = Yap_popWide;
332 }
333 }
334#if USE_READLINE
335 if (st->status & Readline_Stream_f) {
336 st->stream_peek = Yap_ReadlinePeekChar;
337 st->stream_wpeek = Yap_ReadlinePeekChar;
338 }
339
340 /* else {
341 st->stream_peek = Yap_peekWithGetc;
342 st->stream_wpeek = Yap_peekWideWithGetwc;
343 }
344 } else if (st->status & Seekable_Stream_f) {
345 st->stream_peek = Yap_peekWithSeek;
346 st->stream_wpeek = Yap_peekWideWithSeek;
347 } */
348 else
349#endif
350 default_peek(st);
351}
352
353static void InitFileIO(StreamDesc *s) {
354 CACHE_REGS
355 Yap_DefaultStreamOps(s);
356}
357
358static void InitStdStream(int sno, SMALLUNSGN flags, FILE *file, VFS_t *vfsp) {
359 StreamDesc *s = &GLOBAL_Stream[sno];
360 s->file = file;
361 s->status = flags;
362 s->linestart = 0;
363 s->linecount = 1;
364 s->charcount = 0;
365 s->vfs = vfsp;
366 s->buf.on = false;
367 s->encoding = ENC_ISO_UTF8;
368 INIT_LOCK(s->streamlock);
369 if (vfsp == NULL) {
370 unix_upd_stream_info(s);
371 }
372 /* Getting streams to prompt is a mess because we need for cooperation
373 between readers and writers to the stream :-(
374 */
375 InitFileIO(s);
376 switch (sno) {
377 case 0:
378 s->user_name = TermUserIn;
379 break;
380 case 1:
381 s->user_name = TermUserOut;
382 break;
383 default:
384 s->user_name = TermUserErr;
385 break;
386 }
387 s->user_name = MkAtomTerm(s->name);
388#if LIGHT
389 s->status |= Tty_Stream_f | Promptable_Stream_f;
390#endif
391 s->buf.on = false;
392 Yap_DefaultStreamOps(s);
393#if HAVE_SETBUF
394 if (s->status & Tty_Stream_f && sno == 0) {
395 /* make sure input is unbuffered if it comes from stdin, this
396 makes life simpler for interrupt handling */
397 setbuf(stdin, NULL);
398 // fprintf(stderr,"here I am\n");
399 }
400#endif /* HAVE_SETBUF */
401}
402
403void Yap_InitStdStream(int sno, unsigned int flags, FILE *file, VFS_t *vfsp) {
404 InitStdStream(sno, flags, file, vfsp);
405}
406
407Term Yap_StreamUserName(int sno) {
408 Term atname;
409 StreamDesc *s = &GLOBAL_Stream[sno];
410 if (s->user_name != 0L) {
411 return (s->user_name);
412 }
413 if ((atname = StreamName(sno)))
414 return atname;
415 return TermNil;
416}
417
418static void InitStdStreams(void) {
419 CACHE_REGS
420 if (LOCAL_sockets_io) {
421 InitStdStream(StdInStream, Input_Stream_f, NULL, NULL);
422 InitStdStream(StdOutStream, Output_Stream_f, NULL, NULL);
423 InitStdStream(StdErrStream, Output_Stream_f, NULL, NULL);
424 } else {
425 InitStdStream(StdInStream, Input_Stream_f, stdin, NULL);
426 InitStdStream(StdOutStream, Output_Stream_f, stdout, NULL);
427 InitStdStream(StdErrStream, Output_Stream_f, stderr, NULL);
428 }
429 GLOBAL_Stream[StdInStream].name = Yap_LookupAtom("user_input");
430 GLOBAL_Stream[StdOutStream].name = Yap_LookupAtom("user_output");
431 GLOBAL_Stream[StdErrStream].name = Yap_LookupAtom("user_error");
432#if USE_READLINE
433 if (GLOBAL_Stream[StdInStream].status & Tty_Stream_f &&
434 GLOBAL_Stream[StdOutStream].status & Tty_Stream_f &&
435 GLOBAL_Stream[StdErrStream].status & Tty_Stream_f && !Yap_Embedded) {
436 Yap_InitReadline(TermTrue);
437 }
438#endif
439 LOCAL_c_input_stream = StdInStream;
440 LOCAL_c_output_stream = StdOutStream;
441 LOCAL_c_error_stream = StdErrStream;
442}
443
444void Yap_InitStdStreams(void) { InitStdStreams(); }
445
446Int PlIOError__(const char *file, const char *function, int lineno,
447 yap_error_number type, Term culprit, ...) {
448 if (FileErrors() ||
449 type == RESOURCE_ERROR_MAX_STREAMS /* do not catch resource errors */) {
450 va_list args;
451 const char *format;
452 char who[1024];
453
454 va_start(args, culprit);
455 format = va_arg(args, char *);
456 if (format) {
457 vsnprintf(who, 1023, format, args);
458 } else {
459 who[0] = '\0';
460 }
461 va_end(args);
462 Yap_ThrowError__(file, function, lineno, type, culprit, who);
463 /* and fail */
464 return false;
465 } else {
466 pop_text_stack(0);
467 memset(LOCAL_ActiveError, 0, sizeof(*LOCAL_ActiveError));
468 Yap_SetGlobalVal(AtomZip, MkVarTerm());
469 return false;
470 }
471}
472
473bool
474 UnixIOError__(const char *file, const char *function, int lineno,
475 int error, io_kind_t io_type, Term culprit, ...) {
476 if (FileErrors() ) {
477 va_list args;
478 const char *format;
479 char *who = Malloc(1024);
480 yap_error_number e_type;
481
482 va_start(args, culprit);
483 format = va_arg(args, char *);
484 if (format) {
485 vsnprintf(who, 1023, format, args);
486 } else {
487 who[0] = '\0';
488 }
489 va_end(args);
490 switch (error) {
491 case EPERM:
492 case EROFS:
493 // operation not permitted,
494 switch (io_type) {
495 case CREATE_DIRECTORY:
496 e_type = PERMISSION_ERROR_CREATE_DIRECTORY;
497 break;
498 case CREATE_FILE:
499 e_type = PERMISSION_ERROR_CREATE_DIRECTORY;
500 break;
501 default:
502 e_type = SYSTEM_ERROR_INTERNAL;
503 break;
504 }
505 case EEXIST:
506 switch (io_type) {
507 case CREATE_DIRECTORY:
508 e_type = EXISTENCE_ERROR_DIRECTORY;
509 break;
510 case CREATE_FILE:
511 e_type = EXISTENCE_ERROR_FILE;
512 break;
513 default:
514 e_type = SYSTEM_ERROR_INTERNAL;
515 }
516 break;
517 case EACCES:
518 switch (io_type) {
519 case CREATE_DIRECTORY:
520 e_type = PERMISSION_ERROR_CREATE_DIRECTORY;
521 break;
522 case CREATE_FILE:
523 e_type = PERMISSION_ERROR_CREATE_FILE;
524 break;
525 default:
526 e_type = SYSTEM_ERROR_INTERNAL;
527 }
528 break;
529 default:
530 e_type = SYSTEM_ERROR_INTERNAL;
531 }
532
533 Yap_ThrowError__(file, function, lineno, e_type, culprit, who);
534 /* aRgrownd fail */
535 } else {
536 pop_text_stack(0);
537 memset(LOCAL_ActiveError, 0, sizeof(*LOCAL_ActiveError));
538
539 }
540 return false;
541 }
542
543static int eolflg = 1;
544
545static char my_line[200] = {0};
546static char *lp = my_line;
547
548FILE *curfile, *Yap_logfile;
549
550bool Yap_Option[256];
551
552#ifdef MACC
553
554static void InTTYLine(char *line) {
555 char *p = line;
556 char ch;
557 while ((ch = InKey()) != '\n' && ch != '\r')
558 if (ch == 8) {
559 if (line < p)
560 BackupTTY(*--p);
561 } else
562 TTYChar(*p++ = ch);
563 TTYChar('\n');
564 *p = 0;
565}
566#endif
567
568void Yap_DebugSetIFile(char *fname) {
569 if (curfile)
570 fclose(curfile);
571 curfile = fopen(fname, "r");
572 if (curfile == NULL) {
573 curfile = stdin;
574 Yap_Warning("%% YAP open %s for input\n", fname);
575 }
576}
577
578void Yap_DebugEndline() { *lp = 0; }
579
580int Yap_DebugGetc() {
581 int ch;
582 if (eolflg) {
583 if (curfile != NULL) {
584 if (fgets(my_line, 200, curfile) == 0)
585 curfile = NULL;
586 }
587 if (curfile == NULL)
588 if (fgets(my_line, 200, stdin) == NULL) {
589 return EOF;
590 }
591 eolflg = 0;
592 lp = my_line;
593 }
594 if ((ch = *lp++) == 0)
595 ch = '\n', eolflg = 1;
596 if (Yap_Option['l' - 96])
597 putc(ch, Yap_logfile);
598 return (ch);
599}
600
601int Yap_DebugPutc(FILE *s, wchar_t ch) {
602 if (Yap_Option['l' - 96])
603 (void)putc(ch, Yap_logfile);
604 return (putc(ch, stderr));
605}
606
607int Yap_DebugPuts(FILE *s, const char *sch) {
608 if (Yap_Option['l' - 96])
609 (void)fputs(sch, Yap_logfile);
610 return fputs(sch, stderr);
611}
612
613void Yap_DebugErrorPuts(const char *s) { Yap_DebugPuts(stderr, s); }
614
615void Yap_DebugPlWrite(Term t) {
616 if (t == 0)
617 fprintf(stderr, "NULL");
618 Yap_plwrite(t, GLOBAL_Stream + 2, 10, HR, 0, NULL);
619}
620
621void Yap_DebugPlWriteln(Term t) {
622 CACHE_REGS
623 if (t == 0)
624 fprintf(stderr, "NULL");
625 Yap_plwrite(t, GLOBAL_Stream+LOCAL_c_error_stream , 10, HR, Handle_cyclics_f|Quote_illegal_f, NULL);
626 Yap_DebugPutc(GLOBAL_Stream[LOCAL_c_error_stream].file, '.');
627 Yap_DebugPutc(GLOBAL_Stream[LOCAL_c_error_stream].file, 10);
628}
629
630void Yap_DebugErrorPutc(int c) {
631 CACHE_REGS
632 Yap_DebugPutc(GLOBAL_Stream[LOCAL_c_error_stream].file, c);
633}
634
635void Yap_DebugWriteIndicator(PredEntry *ap) {
636 CACHE_REGS
637 Term tmod = ap->ModuleOfPred;
638 if (!tmod)
639 tmod = TermProlog;
640#if THREADS
641 Yap_DebugPlWrite(MkIntegerTerm(worker_id));
642 Yap_DebugPutc(stderr, ' ');
643#endif
644 Yap_DebugPutc(stderr, '>');
645 Yap_DebugPutc(stderr, '\t');
646 Yap_DebugPlWrite(tmod);
647 Yap_DebugPutc(stderr, ':');
648 if (ap->ModuleOfPred == IDB_MODULE) {
649 Term t = Deref(ARG1);
650 if (IsAtomTerm(t)) {
651 Yap_DebugPlWrite(t);
652 } else if (IsIntegerTerm(t)) {
653 Yap_DebugPlWrite(t);
654 } else {
655 Functor f = FunctorOfTerm(t);
656 Atom At = NameOfFunctor(f);
657 Yap_DebugPlWrite(MkAtomTerm(At));
658 Yap_DebugPutc(stderr, '/');
659 Yap_DebugPlWrite(MkIntegerTerm(ArityOfFunctor(f)));
660 }
661 } else {
662 if (ap->ArityOfPE == 0) {
663 Atom At = (Atom)ap->FunctorOfPred;
664 Yap_DebugPlWrite(MkAtomTerm(At));
665 } else {
666 Functor f = ap->FunctorOfPred;
667 Atom At = NameOfFunctor(f);
668 Yap_DebugPlWrite(MkAtomTerm(At));
669 Yap_DebugPutc(stderr, '/');
670 Yap_DebugPlWrite(MkIntegerTerm(ArityOfFunctor(f)));
671 }
672 }
673
674 Yap_DebugPutc(stderr, '\n');
675}
676
677/* static */
678int FilePutc(int sno, int ch) {
679 StreamDesc *s = &GLOBAL_Stream[sno];
680#if MAC || _MSC_VER
681 if (ch == 10) {
682 ch = '\n';
683 }
684#endif
685 putc(ch, s->file);
686#if MAC || _MSC_VER
687 if (ch == 10) {
688 fflush(s->file);
689 }
690#endif
691 count_output_char(ch, s);
692 return ((int)ch);
693}
694
695static int NullPutc(int sno, int ch) {
696 StreamDesc *s = &GLOBAL_Stream[sno];
697#if MAC || _MSC_VER
698 if (ch == 10) {
699 ch = '\n';
700 }
701#endif
702 count_output_char(ch, s);
703 return ((int)ch);
704}
705
706/* check if we read a LOCAL_newline or an EOF */
707int console_post_process_eof(StreamDesc *s) {
708 CACHE_REGS
709 if (!ResetEOF(s)) {
710 s->status |= Eof_Stream_f;
711 s->stream_getc = EOFGetc;
712 s->stream_wgetc = EOFWGetc;
713 s->stream_wgetc_for_read = EOFWGetc;
714 LOCAL_newline = true;
715 }
716 return EOFCHAR;
717}
718
719/* check if we read a newline or an EOF */
720int post_process_read_wchar(int ch, size_t n, StreamDesc *s) {
721 if (ch == EOF) {
722 return post_process_weof(s);
723 }
724#if DEBUG
725 if (GLOBAL_Option[1]) {
726 static int v;
727 fprintf(stderr, "%d %C\n", v, ch);
728 v++;
729 }
730#endif
731 s->charcount += n;
732 if (ch == '\n') {
733 ++s->linecount;
734 s->linestart = s->charcount;
735 /* don't convert if the stream is binary */
736 if (!(s->status & Binary_Stream_f))
737 ch = 10;
738 }
739 return ch;
740}
741
742int post_process_weof(StreamDesc *s) {
743 if (!ResetEOF(s)) {
744 s->status |= Eof_Stream_f;
745 s->stream_wgetc = EOFWGetc;
746 s->stream_getc = EOFGetc;
747 s->stream_wgetc_for_read = EOFWGetc;
748 }
749 return EOFCHAR;
750}
751
752void *Yap_RepStreamFromId(int sno) { return GLOBAL_Stream + (sno); }
753
763int EOFPeek(int sno) { return EOFCHAR; }
764
765int EOFWPeek(int sno) { return EOFCHAR; }
766
767/* standard routine, it should read from anything pointed by a FILE *.
768 It could be made more efficient by doing our own buffering and avoiding
769 post_process_read_char, something to think about */
770int PlGetc(int sno) {
771 StreamDesc *s = &GLOBAL_Stream[sno];
772 return fgetc(s->file);
773}
774
775// layered version
776static inline int get_wchar_from_file(int sno) {
777 return post_process_read_wchar(fgetwc(GLOBAL_Stream[sno].file), 1,
778 GLOBAL_Stream + sno);
779}
780
781#ifndef MB_LEN_MAX
782#define MB_LEN_MAX 6
783#endif
784
785static int handle_write_encoding_error(int sno, wchar_t ch) {
786 if (GLOBAL_Stream[sno].status & RepError_Xml_f) {
787 /* use HTML/XML encoding in ASCII */
788 int i = ch, digits = 1;
789 GLOBAL_Stream[sno].stream_putc(sno, '&');
790 GLOBAL_Stream[sno].stream_putc(sno, '#');
791 while (digits < i)
792 digits *= 10;
793 if (digits > i)
794 digits /= 10;
795 while (i) {
796 GLOBAL_Stream[sno].stream_putc(sno, i / digits);
797 i %= 10;
798 digits /= 10;
799 }
800 GLOBAL_Stream[sno].stream_putc(sno, ';');
801 return ch;
802 } else if (GLOBAL_Stream[sno].status & RepError_Prolog_f) {
803 /* write quoted */
804 GLOBAL_Stream[sno].stream_putc(sno, '\\');
805 GLOBAL_Stream[sno].stream_putc(sno, 'u');
806 GLOBAL_Stream[sno].stream_putc(sno, ch >> 24);
807 GLOBAL_Stream[sno].stream_putc(sno, 256 & (ch >> 16));
808 GLOBAL_Stream[sno].stream_putc(sno, 256 & (ch >> 8));
809 GLOBAL_Stream[sno].stream_putc(sno, 256 & ch);
810 return ch;
811 } else {
812 CACHE_REGS
813 Yap_ThrowError(REPRESENTATION_ERROR_CHARACTER, MkIntegerTerm(ch),
814 "charater %ld cannot be encoded in stream %d",
815 (unsigned long int)ch, sno);
816 return -1;
817 }
818}
819
820int put_wchar(int sno, wchar_t ch) {
821 /* pass the bucck if we can */
822 switch (GLOBAL_Stream[sno].encoding) {
823 case ENC_OCTET:
824 return GLOBAL_Stream[sno].stream_putc(sno, ch);
825 case ENC_ISO_LATIN1:
826 if (ch >= 0xff) {
827 return handle_write_encoding_error(sno, ch);
828 }
829 return GLOBAL_Stream[sno].stream_putc(sno, ch);
830 case ENC_ISO_ASCII:
831 if (ch >= 0x80) {
832 return handle_write_encoding_error(sno, ch);
833 }
834 return GLOBAL_Stream[sno].stream_putc(sno, ch);
835 case ENC_ISO_ANSI: {
836 char buf[MB_LEN_MAX];
837 mbstate_t mbstate;
838 int n;
839
840 memset((void *)&mbstate, 0, sizeof(mbstate_t));
841 if ((n = wcrtomb(buf, ch, &mbstate)) < 0) {
842 /* error */
843 GLOBAL_Stream[sno].stream_putc(sno, ch);
844 return -1;
845 } else {
846 int i;
847
848 for (i = 0; i < n; i++) {
849 GLOBAL_Stream[sno].stream_putc(sno, buf[i]);
850 }
851 return ch;
852 }
853 case ENC_ISO_UTF8:
854 if (ch < 0x80) {
855 GLOBAL_Stream[sno].stream_putc(sno, ch);
856 } else if (ch < 0x800) {
857 GLOBAL_Stream[sno].stream_putc(sno, 0xC0 | ch >> 6);
858 GLOBAL_Stream[sno].stream_putc(sno, 0x80 | (ch & 0x3F));
859 } else if (ch < 0x10000) {
860 GLOBAL_Stream[sno].stream_putc(sno, 0xE0 | ch >> 12);
861 GLOBAL_Stream[sno].stream_putc(sno, 0x80 | (ch >> 6 & 0x3F));
862 GLOBAL_Stream[sno].stream_putc(sno, 0x80 | (ch & 0x3F));
863 } else if (ch < 0x200000) {
864 GLOBAL_Stream[sno].stream_putc(sno, 0xF0 | ch >> 18);
865 GLOBAL_Stream[sno].stream_putc(sno, 0x80 | (ch >> 12 & 0x3F));
866 GLOBAL_Stream[sno].stream_putc(sno, 0x80 | (ch >> 6 & 0x3F));
867 GLOBAL_Stream[sno].stream_putc(sno, 0x80 | (ch & 0x3F));
868 } else {
869 /* should never happen */
870 return -1;
871 }
872 return ch;
873 break;
874 case ENC_UTF16_LE: {
875 if (ch < 0x10000) {
876 GLOBAL_Stream[sno].stream_putc(sno, (ch & 0xff));
877 GLOBAL_Stream[sno].stream_putc(sno, (ch >> 8));
878 } else {
879 // computations
880 uint16_t ich = ch;
881 uint16_t lead = LEAD_OFFSET + (ich >> 10);
882 uint16_t trail = 0xDC00 + (ich & 0x3FF);
883
884 GLOBAL_Stream[sno].stream_putc(sno, (trail & 0xff));
885 GLOBAL_Stream[sno].stream_putc(sno, (trail >> 8));
886 GLOBAL_Stream[sno].stream_putc(sno, (lead & 0xff));
887 GLOBAL_Stream[sno].stream_putc(sno, (lead >> 8));
888 }
889 return ch;
890 }
891 case ENC_UTF16_BE: {
892 // computations
893 if (ch < 0x10000) {
894 GLOBAL_Stream[sno].stream_putc(sno, (ch >> 8));
895 GLOBAL_Stream[sno].stream_putc(sno, (ch & 0xff));
896 } else {
897 uint16_t lead = (uint16_t)LEAD_OFFSET + ((uint16_t)ch >> 10);
898 uint16_t trail = 0xDC00 + ((uint16_t)ch & 0x3FF);
899
900 GLOBAL_Stream[sno].stream_putc(sno, (lead >> 8));
901 GLOBAL_Stream[sno].stream_putc(sno, (lead & 0xff));
902 GLOBAL_Stream[sno].stream_putc(sno, (trail >> 8));
903 GLOBAL_Stream[sno].stream_putc(sno, (trail & 0xff));
904 }
905 return ch;
906 }
907 case ENC_UCS2_LE: {
908 if (ch >= 0x10000) {
909 return 0;
910 }
911 GLOBAL_Stream[sno].stream_putc(sno, (ch & 0xff));
912 GLOBAL_Stream[sno].stream_putc(sno, (ch >> 8));
913 return ch;
914 }
915 case ENC_UCS2_BE: {
916 // computations
917 if (ch < 0x10000) {
918 GLOBAL_Stream[sno].stream_putc(sno, (ch >> 8));
919 GLOBAL_Stream[sno].stream_putc(sno, (ch & 0xff));
920 return ch;
921 } else {
922 return 0;
923 }
924 }
925
926 case ENC_ISO_UTF32_BE:
927 GLOBAL_Stream[sno].stream_putc(sno, (ch >> 24) & 0xff);
928 GLOBAL_Stream[sno].stream_putc(sno, (ch >> 16) & 0xff);
929 GLOBAL_Stream[sno].stream_putc(sno, (ch >> 8) & 0xff);
930 GLOBAL_Stream[sno].stream_putc(sno, ch & 0xff);
931 return ch;
932 case ENC_ISO_UTF32_LE:
933 GLOBAL_Stream[sno].stream_putc(sno, ch & 0xff);
934 GLOBAL_Stream[sno].stream_putc(sno, (ch >> 8) & 0xff);
935 GLOBAL_Stream[sno].stream_putc(sno, (ch >> 16) & 0xff);
936 GLOBAL_Stream[sno].stream_putc(sno, (ch >> 24) & 0xff);
937 return ch;
938 }
939 }
940 return -1;
941}
942
943/* used by user-code to read characters from the current input stream */
944int Yap_PlGetchar(void) {
945 CACHE_REGS
946 return (
947 GLOBAL_Stream[LOCAL_c_input_stream].stream_getc(LOCAL_c_input_stream));
948}
949
950int Yap_PlGetWchar(void) {
951 CACHE_REGS
952 return get_wchar(LOCAL_c_input_stream);
953}
954
955/* avoid using a variable to call a function */
956int Yap_PlFGetchar(void) {
957 CACHE_REGS
958 return (PlGetc(LOCAL_c_input_stream));
959}
960
961Term Yap_MkStream(int n) {
962 Term t[1];
963 t[0] = MkIntTerm(n);
964 return (Yap_MkApplTerm(FunctorStream, 1, t));
965}
966
967/* given a stream index, get the corresponding fd */
968Int GetStreamFd(int sno) {
969#if HAVE_SOCKET
970 if (GLOBAL_Stream[sno].status & Socket_Stream_f) {
971 return (GLOBAL_Stream[sno].u.socket.fd);
972 } else
973#endif
974 if (GLOBAL_Stream[sno].status & Pipe_Stream_f) {
975 return (GLOBAL_Stream[sno].u.pipe.fd);
976 } else if (GLOBAL_Stream[sno].status & InMemory_Stream_f) {
977 return (-1);
978 }
979 return (fileno(GLOBAL_Stream[sno].file));
980}
981
982Int Yap_GetStreamFd(int sno) { return GetStreamFd(sno); }
983
984static int binary_file(const char *file_name) {
985#if HAVE_STAT
986#if _MSC_VER || defined(__MINGW32__)
987 struct _stat ss;
988 if (_stat(file_name, &ss) != 0)
989#else
990 struct stat ss;
991 if (stat(file_name, &ss) != 0)
992#endif
993 {
994 /* ignore errors while checking a file */
995 return false;
996 }
997 return (S_ISDIR(ss.st_mode));
998#else
999 return (FALSE);
1000#endif
1001}
1002
1003static int write_bom(int sno, StreamDesc *st) {
1004 /* dump encoding */
1005 switch (st->encoding) {
1006 case ENC_ISO_UTF8:
1007 if (st->stream_putc(sno, 0xEF) < 0)
1008 return false;
1009 if (st->stream_putc(sno, 0xBB) < 0)
1010 return false;
1011 if (st->stream_putc(sno, 0xBF) < 0)
1012 return false;
1013 st->status |= HAS_BOM_f;
1014 return true;
1015 case ENC_UTF16_BE:
1016 case ENC_UCS2_BE:
1017 if (st->stream_putc(sno, 0xFE) < 0)
1018 return false;
1019 if (st->stream_putc(sno, 0xFF) < 0)
1020 return false;
1021 st->status |= HAS_BOM_f;
1022 return true;
1023 case ENC_UTF16_LE:
1024 case ENC_UCS2_LE:
1025 if (st->stream_putc(sno, 0xFF) < 0)
1026 return false;
1027 if (st->stream_putc(sno, 0xFE) < 0)
1028 return false;
1029 st->status |= HAS_BOM_f;
1030 return true;
1031 case ENC_ISO_UTF32_BE:
1032 if (st->stream_putc(sno, 0x00) < 0)
1033 return false;
1034 if (st->stream_putc(sno, 0x00) < 0)
1035 return false;
1036 if (st->stream_putc(sno, 0xFE) < 0)
1037 return false;
1038 if (st->stream_putc(sno, 0xFF) < 0)
1039 return false;
1040 st->status |= HAS_BOM_f;
1041 return true;
1042 case ENC_ISO_UTF32_LE:
1043 if (st->stream_putc(sno, 0xFF) < 0)
1044 return false;
1045 if (st->stream_putc(sno, 0xFE) < 0)
1046 return false;
1047 if (st->stream_putc(sno, 0x00) < 0)
1048 return false;
1049 if (st->stream_putc(sno, 0x00) < 0)
1050 return false;
1051 st->status |= HAS_BOM_f;
1052 return true;
1053 default:
1054 return true;
1055 }
1056}
1057
1058static int check_bom(int sno, StreamDesc *st) {
1059 int ch1, ch2, ch3, ch4;
1060 if (st->file == NULL) {
1061 Yap_ThrowError(SYSTEM_ERROR_INTERNAL, Yap_MkStream(sno),
1062 "YAP does not support BOM n %x type of files", st->status);
1063 return -1;
1064 }
1065 ch1 = fgetc(st->file);
1066 switch (ch1) {
1067 case 0x00: {
1068 ch2 = fgetc(st->file);
1069 if (ch2 != 0x00) {
1070 ungetc(ch1, st->file);
1071 ungetc(ch2, st->file);
1072 return 0;
1073 } else {
1074 ch3 = fgetc(st->file);
1075 if (ch3 == EOFCHAR || ch3 != 0xFE) {
1076 ungetc(ch1, st->file);
1077 ungetc(ch2, st->file);
1078 ungetc(ch3, st->file);
1079 return 0;
1080 } else {
1081 ch4 = fgetc(st->file);
1082 if (ch4 == EOFCHAR || ch3 != 0xFF) {
1083 ungetc(ch1, st->file);
1084 ungetc(ch2, st->file);
1085 ungetc(ch3, st->file);
1086 ungetc(ch4, st->file);
1087 return 0;
1088 } else {
1089 st->status |= HAS_BOM_f;
1090 st->encoding = ENC_ISO_UTF32_BE;
1091 return 4;
1092 }
1093 }
1094 }
1095 }
1096 case 0xFE: {
1097 ch2 = fgetc(st->file);
1098 if (ch2 != 0xFF) {
1099 ungetc(ch1, st->file);
1100 ungetc(ch2, st->file);
1101 return 0;
1102 } else {
1103 st->status |= HAS_BOM_f;
1104 st->encoding = ENC_UTF16_BE;
1105 return 2;
1106 }
1107 }
1108 case 0xFF: {
1109 ch2 = fgetc(st->file);
1110 if (ch2 != 0xFE) {
1111 ungetc(ch1, st->file);
1112 ungetc(ch2, st->file);
1113 return 0;
1114 } else {
1115 ch3 = fgetc(st->file);
1116 if (ch3 != 0x00) {
1117 ungetc(ch3, st->file);
1118 } else {
1119 ch4 = fgetc(st->file);
1120 if (ch4 == 0x00) {
1121 st->charcount += 4;
1122 st->status |= HAS_BOM_f;
1123 st->encoding = ENC_ISO_UTF32_LE;
1124 return 4;
1125 } else {
1126 ungetc(ch3, st->file);
1127 ungetc(ch4, st->file);
1128 }
1129 }
1130 }
1131 st->status |= HAS_BOM_f;
1132 st->encoding = ENC_UTF16_LE;
1133 return 2;
1134 }
1135 case 0xEF:
1136 ch2 = fgetc(st->file);
1137 if (ch2 != 0xBB) {
1138 ungetc(ch1, st->file);
1139 ungetc(ch2, st->file);
1140 return 0;
1141 } else {
1142 ch3 = fgetc(st->file);
1143 if (ch3 != 0xBF) {
1144 ungetc(ch1, st->file);
1145 ungetc(ch2, st->file);
1146 ungetc(ch3, st->file);
1147 return 0;
1148 } else {
1149 st->status |= HAS_BOM_f;
1150 st->encoding = ENC_ISO_UTF8;
1151 return 3;
1152 }
1153 }
1154 default:
1155 ungetc(ch1, st->file);
1156 return 0;
1157 }
1158}
1159
1160bool Yap_initStream__(const char *file, const char *f, int line, int sno, FILE *fd, Atom name, const char *io_mode,
1161 Term file_name, encoding_t encoding, stream_flags_t flags,
1162 void *vfs) {
1163 extern void jmp_deb(int);
1164 if (sno==29)
1165 jmp_deb(1);
1166// fprintf(stderr,"+ %s --> %d @%s:%s:%d\n", RepAtom(name)->StrOfAE, sno, file, f, line);
1167 StreamDesc *st = &GLOBAL_Stream[sno];
1168 __android_log_print(
1169 ANDROID_LOG_INFO, "YAPDroid", "init %s %s:%s stream <%d>", io_mode,
1170 CurrentModule == 0 ? "prolog"
1171 : RepAtom(AtomOfTerm(CurrentModule))->StrOfAE,
1172 RepAtom(name)->StrOfAE, sno);
1173 if (io_mode == NULL)
1174 Yap_ThrowError(PERMISSION_ERROR_NEW_ALIAS_FOR_STREAM, MkIntegerTerm(sno),
1175 "File opened with NULL Permissions");
1176 if (strchr(io_mode, 'a')) {
1177 st->status = Append_Stream_f | Output_Stream_f | flags;
1178 } else if (strchr(io_mode, 'w')) {
1179 st->status = Output_Stream_f | flags;
1180 }
1181 if (strchr(io_mode, 'r')) {
1182 st->status = Input_Stream_f | flags;
1183 }
1184 if (strchr(io_mode, 'b')) {
1185 st->status = Binary_Stream_f | flags;
1186 }
1187
1188 // st->vfs = vfs;
1189 st->buf.on = false;
1190 st->charcount = 0;
1191 st->linecount = 1;
1192 st->linestart = 0;
1193 if (flags & Binary_Stream_f) {
1194 st->encoding = ENC_OCTET;
1195 } else {
1196 st->encoding = encoding;
1197 }
1198
1199 st->name = Yap_guessFileName(fd, sno, MAX_PATH);
1200 if (!st->name)
1201 Yap_ThrowError(SYSTEM_ERROR_INTERNAL, file_name,
1202 "Yap_guessFileName failed: opening a file without a name");
1203 st->user_name = file_name;
1204 st->file = fd;
1205 st->linestart = 0;
1206 Yap_DefaultStreamOps(st);
1207 return true;
1208}
1209
1210static bool scan_failed(int sno, long pos, encoding_t onc) {
1211 long i;
1212 rewind(GLOBAL_Stream[sno].file);
1213 GLOBAL_Stream[sno].encoding = onc;
1214 for (i=0;i<pos;i++)
1215 GLOBAL_Stream[sno].stream_getc(sno);
1216 return false;
1217}
1218
1219
1220/*
1221 * scan_a_char gets the next character, assuming we may have NULLs inbetween characters
1222 */
1223static int scan_a_char_preceeded_by_spaces(int sno) {
1224 int ch;
1225 while ((ch = GLOBAL_Stream[sno].stream_getc(sno)) == '\0' ||
1226 ch == '\n' ||
1227 chtype(ch) == BS);
1228 return ch;
1229}
1230
1231static int scan_a_char(int sno) {
1232 int ch;
1233 while ((ch = GLOBAL_Stream[sno].stream_getc(sno)) == '\0');
1234 return ch;
1235}
1236
1237static bool scan_check_a_text(int sno, const char *txt) {
1238 int i, sz = strlen(txt);
1239 if (scan_a_char_preceeded_by_spaces(sno) != txt[0])
1240 return false;
1241 for (i=1; i <sz; i++) {
1242 if (scan_a_char(sno) != txt[i])
1243 return false;
1244 }
1245 return true;
1246}
1247
1248
1249static bool scan_fetch_a_text(int sno, char *txt) {
1250 int ch, i=0, quote = 0;
1251 if (chtype(ch = scan_a_char_preceeded_by_spaces(sno)) == EF)
1252 return false;
1253 if (ch == '\'' || ch == '"' || ch == '`') {
1254 quote = ch;
1255 } else {
1256 txt[i++] = ch;
1257 }
1258 while (chtype(ch = scan_a_char(sno))!=EF) {
1259 if (ch == '\n') {
1260 txt[i] = '\0';
1261 return quote == 0;
1262 }
1263 if (ch == quote) {
1264 txt[i] = '\0';
1265 break;
1266 } else if (ch == ')') {
1267 txt[i] = '\0';
1268 break;
1269 } else {
1270 txt[i++] = ch;
1271 }
1272 }
1273 if (chtype(ch) == EF)
1274 return false;
1275 if (ch != ')') {
1276 ch = scan_a_char_preceeded_by_spaces(sno);
1277 if (ch != ')')
1278 return false;
1279 }
1280 if (ch != '.') {
1281 ch = scan_a_char_preceeded_by_spaces(sno);
1282 if (ch != '.')
1283 return false;
1284 }
1285 txt[i] = '\0';
1286return true;
1287}
1288
1289static bool scan_encoding(int sno, long pos) {
1290 encoding_t onc = GLOBAL_Stream[sno].encoding;
1291 char txt[256];
1292 int ch,l;
1293
1294 GLOBAL_Stream[sno].encoding = ENC_ISO_ASCII;
1295 while ((ch=(GLOBAL_Stream[sno].stream_getc(sno)=='\0'))) l++;
1296 if (ch != ':')
1297 return scan_failed(sno, pos, onc);
1298 if (l==1) {
1299 l=0;
1300 while ((ch=(GLOBAL_Stream[sno].stream_getc(sno))=='\0')) l++;
1301 }
1302 if (ch!='-') return scan_failed(sno, pos, onc);
1303 if (!scan_check_a_text(sno, "encoding(")) return scan_failed(sno, pos, onc);
1304 if (!scan_fetch_a_text(sno, txt)) return scan_failed(sno, pos, onc);
1305 GLOBAL_Stream[sno].encoding = enc_id(txt, onc);
1306 while(GLOBAL_Stream[sno].stream_getc(sno)!='\n');
1307 for(;l>0;l--)
1308 GLOBAL_Stream[sno].stream_getc(sno);
1309 return true;
1310}
1311
1312static bool open_header(int sno, Atom open_mode) {
1313 if (open_mode == AtomWrite) {
1314 const char *ptr;
1315 const char s[] = "#!";
1316 int ch;
1317
1318 ptr = s;
1319 while ((ch = *ptr++))
1320 GLOBAL_Stream[sno].stream_wputc(sno, ch);
1321 const char *b = Yap_FindExecutable();
1322 ptr = b;
1323 while ((ch = *ptr++))
1324 GLOBAL_Stream[sno].stream_wputc(sno, ch);
1325 const char *l = " -L --\n\n YAP script\n#\n# .\n";
1326 ptr = l;
1327 while ((ch = *ptr++))
1328 GLOBAL_Stream[sno].stream_wputc(sno, ch);
1329
1330 } else if (open_mode == AtomRead) {
1331 // skip header
1332 int ch;
1333 while ((ch = Yap_peek(sno)) == '#') {
1334 while ((ch = GLOBAL_Stream[sno].stream_wgetc(sno)) != 10 && ch != -1);
1335 }
1336 }
1337 return true;
1338}
1339
1340#undef PAR
1341#define OPEN_DEFS() \
1342 PAR("alias", isatom, OPEN_ALIAS) \
1343 , PAR("bom", booleanFlag, OPEN_BOM), PAR("buffer", isatom, OPEN_BUFFER), \
1344 PAR("close_on_abort", booleanFlag, OPEN_CLOSE_ON_ABORT), \
1345 PAR("create", isatom, OPEN_CREATE), \
1346 PAR("encoding", isatom, OPEN_ENCODING), \
1347 PAR("eof_action", isatom, OPEN_EOF_ACTION), \
1348 PAR("expand_filename", booleanFlag, OPEN_EXPAND_FILENAME), \
1349 PAR("file_name", isatom, OPEN_FILE_NAME), PAR("input", ok, OPEN_INPUT), \
1350 PAR("locale", isatom, OPEN_LOCALE), PAR("lock", isatom, OPEN_LOCK), \
1351 PAR("mode", isatom, OPEN_MODE), PAR("output", ok, OPEN_OUTPUT), \
1352 PAR("representation_errors", booleanFlag, OPEN_REPRESENTATION_ERRORS), \
1353 PAR("reposition", booleanFlag, OPEN_REPOSITION), \
1354 PAR("script", booleanFlag, OPEN_SCRIPT), PAR("type", isatom, OPEN_TYPE), \
1355 PAR("wait", booleanFlag, OPEN_WAIT), PAR(NULL, ok, OPEN_END)
1356
1357#define PAR(x, y, z) z
1358typedef enum open_enum_choices { OPEN_DEFS() } open_choices_t;
1359
1360#undef PAR
1361
1362#define PAR(x, y, z) \
1363 { x, y, z }
1364
1365static const param_t open_defs[] = {OPEN_DEFS()};
1366#undef PAR
1367
1368static bool fill_stream(int sno, StreamDesc *st, Term tin, const char *io_mode,
1369 Term user_name, bool *avoid_bomp, encoding_t enc) {
1370 struct vfs *vfsp = NULL;
1371 const char *fname;
1372
1373 if (IsAtomTerm(tin))
1374 fname = RepAtom(AtomOfTerm(tin))->StrOfAE;
1375 else if (IsStringTerm(tin))
1376 fname = StringOfTerm(tin);
1377 else
1378 fname = NULL;
1379
1380 st->file = NULL;
1381 if (fname) {
1382 if ((vfsp = vfs_owner(fname)) != NULL) {
1383 if (vfsp->open(vfsp, fname, io_mode, sno)) {
1384 // read, write, append
1385 user_name = st->user_name;
1386 st->vfs = vfsp;
1387 UNLOCK(st->streamlock);
1388 __android_log_print(
1389 ANDROID_LOG_INFO, "YAPDroid", "got %d ", sno);
1390 } else {
1391 UNLOCK(st->streamlock);
1392 __android_log_print(
1393 ANDROID_LOG_INFO, "YAPDroid", "failed %s ",fname);
1394return false;
1395 }
1396 } else {
1397 st->file = fopen(fname, io_mode);
1398 if (st->file == NULL) {
1399 __android_log_print(
1400 ANDROID_LOG_INFO, "YAPDroid", "failed %s ",fname);
1401 UNLOCK(st->streamlock);
1402 if (errno == ENOENT && !strchr(io_mode, 'r')) {
1403 PlIOError(EXISTENCE_ERROR_SOURCE_SINK, tin, "%s: %s", fname,
1404 strerror(errno));
1405 } else {
1406 PlIOError(PERMISSION_ERROR_OPEN_SOURCE_SINK, tin, "%s: %s", fname,
1407 strerror(errno));
1408 }
1409 return false;
1410 }
1411
1412 }
1413 } else if (IsApplTerm(tin)) {
1414 Functor f = FunctorOfTerm(tin);
1415 if (f == FunctorAtom || f == FunctorString || f == FunctorCodes1 ||
1416 f == FunctorCodes || f == FunctorChars1 || f == FunctorChars) {
1417 if (strchr(io_mode, 'w')) {
1418 return Yap_OpenBufWriteStream(PASS_REGS1);
1419 } else {
1420 int j = push_text_stack();
1421 const char *buf;
1422 // encoding_t enc = ENC_ISO_UTF8;
1423 //if (f == FunctorAtom || f == FunctorString)
1424 // enc = ENC_ISO_UTF8;
1425 *avoid_bomp = true;
1426 buf = Yap_TextTermToText(ArgOfTerm(1,tin) PASS_REGS);
1427 if (!buf) {
1428 pop_text_stack(j);
1429 return false;
1430 }
1431 st->nbuf = pop_output_text_stack(j, buf);
1432 Atom nat = Yap_LookupAtom(Yap_StrPrefix(buf, 32));
1433 sno = Yap_open_buf_read_stream(st, buf, st->nsize=(strlen(buf) + 1), &LOCAL_encoding,
1434 MEM_BUF_MALLOC, nat,
1435 MkAtomTerm(NameOfFunctor(f)));
1436 pop_text_stack(j);
1437 }
1438 } else if (!strcmp(RepAtom(NameOfFunctor(f))->StrOfAE, "popen")) {
1439 const char *buf;
1440 int i = push_text_stack();
1441 buf = Yap_TextTermToText(ArgOfTerm(1, tin) PASS_REGS);
1442 if (buf == NULL) {
1443 return false;
1444 }
1445#if _WIN32
1446 st->file = _popen(buf, io_mode);
1447#else
1448 st->file = popen(buf, io_mode);
1449#endif
1450 fname = "popen";
1451 user_name = tin;
1452 st->status |= Popen_Stream_f;
1453 pop_text_stack(i);
1454 } else {
1455 Yap_ThrowError(DOMAIN_ERROR_SOURCE_SINK, tin, "open");
1456 }
1457 }
1458 if (!strchr(io_mode, 'b') && binary_file(fname)) {
1459 st->status |= Binary_Stream_f;
1460 }
1461 Yap_initStream(sno, st->file, Yap_LookupAtom(fname), io_mode, user_name,
1462 LOCAL_encoding, st->status, vfsp);
1463 return true;
1464}
1465
1466static Int do_open(Term file_name, Term t2, Term tlist USES_REGS) {
1467 Atom open_mode;
1468 bool avoid_bom = false, needs_bom = false;
1469 Term tenc;
1470 char io_mode[8];
1471 int sno = GetFreeStreamD();
1472 if (sno < 0)
1473 return (PlIOError(RESOURCE_ERROR_MAX_STREAMS, file_name,
1474 "new stream not available for opening"));
1475 StreamDesc *st = GLOBAL_Stream + sno;
1476 memset(st, 0, sizeof(*st));
1477 // user requested encoding?
1478 // BOM mess
1479 st->encoding = LOCAL_encoding;
1480 if (st->encoding == ENC_UTF16_BE || st->encoding == ENC_UTF16_LE ||
1481 st->encoding == ENC_UCS2_BE || st->encoding == ENC_UCS2_LE ||
1482 st->encoding == ENC_ISO_UTF32_BE || st->encoding == ENC_ISO_UTF32_LE) {
1483 st->status |= HAS_BOM_f;
1484 }
1485 st->user_name = Deref(file_name);
1486 if (IsVarTerm(file_name)) {
1487 Yap_ThrowError(INSTANTIATION_ERROR, file_name,
1488 "while opening a list of options");
1489 }
1490 // open mode
1491 if (IsVarTerm(t2)) {
1492 Yap_ThrowError(INSTANTIATION_ERROR, t2, "open/3");
1493 return false;
1494 }
1495 if (!IsAtomTerm(t2)) {
1496 if (IsStringTerm(t2)) {
1497 open_mode = Yap_LookupAtom(StringOfTerm(t2));
1498 } else {
1499 Yap_ThrowError(TYPE_ERROR_ATOM, t2, "open/3");
1500 return false;
1501 }
1502 } else {
1503 open_mode = AtomOfTerm(t2);
1504 }
1505 /* get options */
1506xarg * args = Yap_ArgListToVector(tlist, open_defs, OPEN_END, NULL,DOMAIN_ERROR_OPEN_OPTION);
1507 if (args == NULL) {
1508 if (LOCAL_Error_TYPE != YAP_NO_ERROR) {
1509 Yap_ThrowError(LOCAL_Error_TYPE, tlist, "option handling in open/3");
1510 }
1511 return false;
1512 }
1513 /* done */
1514 st->status = 0;
1515 const char *s_encoding;
1516 if (args[OPEN_ENCODING].used) {
1517 tenc = args[OPEN_ENCODING].tvalue;
1518 s_encoding = RepAtom(AtomOfTerm(tenc))->StrOfAE;
1519 } else {
1520 s_encoding = "default";
1521 }
1522 // default encoding, no bom yet
1523 st->encoding = enc_id(s_encoding, ENC_OCTET);
1524 // only set encoding after getting BOM
1525 char const *fname0;
1526 bool ok = (args[OPEN_EXPAND_FILENAME].used
1527 ? args[OPEN_EXPAND_FILENAME].tvalue == TermTrue
1528 : false);
1529 if (ok) {
1530 if (((IsAtomTerm(file_name) &&
1531 (fname0 = RepAtom(AtomOfTerm(file_name))->StrOfAE))) ||
1532 (IsStringTerm(file_name) && (fname0 = StringOfTerm(file_name)))) {
1533 int lvl = push_text_stack();
1534 const char *fname = Yap_AbsoluteFile(fname0, ok);
1535 file_name = MkAtomTerm(Yap_LookupAtom(fname));
1536 if (!fname) {
1537 pop_text_stack(lvl);
1538 PlIOError(EXISTENCE_ERROR_SOURCE_SINK, ARG1, NULL);
1539 }
1540 }
1541 }
1542 // Skip scripts that start with !#/.. or similar
1543
1544 if (open_mode == AtomRead) {
1545 strncpy(io_mode, "r", 8);
1546 } else if (open_mode == AtomWrite) {
1547 strncpy(io_mode, "w", 8);
1548 } else if (open_mode == AtomAppend) {
1549 strncpy(io_mode, "a", 8);
1550 } else {
1551 return false;
1552 }
1553 // binary type
1554 if (args[OPEN_TYPE].used) {
1555 Term t = args[OPEN_TYPE].tvalue;
1556 bool bin = (t == TermBinary);
1557 if (bin) {
1558#ifdef _WIN32
1559 strncat(io_mode, "b", 8);
1560#endif
1561 st->status |= Binary_Stream_f;
1562 st->encoding = ENC_OCTET;
1563 avoid_bom = true;
1564 needs_bom = false;
1565 } else if (t == TermText) {
1566#ifdef _WIN32
1567 strncat(io_mode, "t", 8);
1568#endif
1569 /* note that this matters for UNICODE style conversions */
1570 } else {
1571 Yap_ThrowError(DOMAIN_ERROR_STREAM_OPTION, t,
1572 "type is ~a, must be one of binary or text", t);
1573 }
1574 }
1575
1576 st = &GLOBAL_Stream[sno];
1577
1578 if (!fill_stream(sno, st, file_name, io_mode, st->user_name, &avoid_bom, st->encoding)) {
1579 return false;
1580 }
1581
1582 if (args[OPEN_BOM].used) {
1583 if (args[OPEN_BOM].tvalue == TermTrue) {
1584 avoid_bom = false;
1585 needs_bom = true;
1586 } else if (args[OPEN_BOM].tvalue == TermFalse) {
1587 avoid_bom = true;
1588 needs_bom = false;
1589 }
1590 }
1591 bool script =
1592 (args[OPEN_SCRIPT].used ? args[OPEN_SCRIPT].tvalue == TermTrue : false);
1593
1594 if (args[OPEN_ALIAS].used) {
1595 Atom al = AtomOfTerm(args[OPEN_ALIAS].tvalue);
1596 if (!Yap_AddAlias(al, sno)) {
1597 free(args);
1598 return false;
1599 }
1600 }
1601 if (st - GLOBAL_Stream < 3) {
1602 st->status |= RepError_Prolog_f;
1603 }
1604#if MAC
1605 if (open_mode == AtomWrite) {
1606 Yap_SetTextFile(RepAtom(AtomOfTerm(file_name))->StrOfAE);
1607 }
1608#endif
1609 // interactive streams do not have a start, so they probably don't have
1610 // a BOM
1611 avoid_bom = avoid_bom || (st->status & Tty_Stream_f);
1612 if (needs_bom && !write_bom(sno, st)) {
1613 return false;
1614 } else if (open_mode == AtomRead) {
1615 long bsz = 0;
1616 if (!avoid_bom) {
1617 bsz = check_bom(sno, st); // can change encoding
1618 // follow declaration unless there is v
1619 if (st->status & HAS_BOM_f) {
1620 st->encoding = enc_id(s_encoding, st->encoding);
1621 }
1622 }
1623 if (
1624 st->status & Seekable_Stream_f &&
1625 st->file)
1626 scan_encoding(sno, bsz);
1627 }
1628 Yap_DefaultStreamOps(st);
1629 if (script) {
1630 open_header(sno, open_mode);
1631 }
1632
1633 free(args);
1634 UNLOCK(st->streamlock);
1635 {
1636 Term t = Yap_MkStream(sno);
1637 return (Yap_unify(ARG3, t));
1638 }
1639}
1640
1661static Int open3(USES_REGS1) {
1662 /* '$open'(+File,+Mode,?Stream,-ReturnCode) */
1663 return do_open(Deref(ARG1), Deref(ARG2), TermNil PASS_REGS);
1664}
1665
1744static Int open4(USES_REGS1) { /* '$open'(+File,+Mode,?Stream,-ReturnCode) */
1745 return do_open(Deref(ARG1), Deref(ARG2), Deref(ARG4) PASS_REGS);
1746}
1747
1748static Int p_file_expansion(USES_REGS1) { /* '$file_expansion'(+File,-Name) */
1749 Term file_name = Deref(ARG1);
1750
1751 /* we know file_name is bound */
1752 if (IsVarTerm(file_name)) {
1753 Yap_ThrowError(INSTANTIATION_ERROR, file_name, "absolute_file_name/3");
1754 return (FALSE);
1755 }
1756 int lvl = push_text_stack();
1757 const char *tmp;
1758 if ((tmp = Yap_AbsoluteFile(RepAtom(AtomOfTerm(file_name))->StrOfAE,
1759 false)) == NULL) {
1760 pop_text_stack(lvl);
1761 return (PlIOError(EXISTENCE_ERROR_SOURCE_SINK, file_name,
1762 "absolute_file_name/3"));
1763 }
1764 bool rc = (Yap_unify(ARG2, MkAtomTerm(Yap_LookupAtom(tmp))));
1765 pop_text_stack(lvl);
1766 return rc;
1767}
1768
1769static Int p_open_null_stream(USES_REGS1) {
1770 Term t;
1771 StreamDesc *st;
1772 int sno = GetFreeStreamD();
1773 if (sno < 0) {
1774 Yap_ThrowError(SYSTEM_ERROR_INTERNAL, TermNil,
1775 "new stream not available for open_null_stream/1");
1776
1777 return false;
1778}
1779 st = &GLOBAL_Stream[sno];
1780 st->status = Append_Stream_f | Output_Stream_f | Null_Stream_f;
1781#if _WIN32
1782 st->file = fopen("NUL", "w");
1783#else
1784 st->file = fopen("/dev/null", "w");
1785#endif
1786 if (st->file == NULL) {
1787 Yap_ThrowError(SYSTEM_ERROR_INTERNAL, TermNil,
1788 "Could not open NULL stream (/dev/null,NUL)");
1789 return false;
1790 }
1791 st->linestart = 0;
1792 st->charcount = 0;
1793 st->linecount = 1;
1794 st->stream_putc = NullPutc;
1795 st->stream_wputc = put_wchar;
1796 st->stream_getc = PlGetc;
1797 st->stream_wgetc = get_wchar;
1799 st->user_name = MkAtomTerm(st->name = AtomDevNull);
1800 UNLOCK(st->streamlock);
1801 t = Yap_MkStream(sno);
1802 return (Yap_unify(ARG1, t));
1803}
1804
1805int Yap_OpenStream(Term tin, const char *io_mode, Term user_name,
1806 encoding_t enc) {
1807 CACHE_REGS
1808 int sno;
1809 StreamDesc *st;
1810
1811 sno = GetFreeStreamD();
1812 if (sno < 0) {
1813 Yap_ThrowError(RESOURCE_ERROR_MAX_STREAMS, tin,
1814 "new stream not available for opening");
1815 return -1;
1816 }
1817 st = GLOBAL_Stream + sno;
1818 // fname = Yap_VF(fname);
1819 bool avoid_bom = false;
1820 if (fill_stream(sno, st, tin, io_mode, user_name, &avoid_bom, enc))
1821 return sno;
1822 return -1;
1823}
1824
1825int Yap_FileStream(FILE *fd, Atom name, Term file_name, int flags,
1826 VFS_t *vfsp) {
1827 CACHE_REGS
1828 int sno;
1829 const char *mode;
1830
1831 sno = GetFreeStreamD();
1832 if (sno < 0) {
1833 Yap_ThrowError(RESOURCE_ERROR_MAX_STREAMS, file_name,
1834 "new stream not available for opening");
1835 return false;
1836}
1837 if (flags & Output_Stream_f) {
1838 if (flags & Append_Stream_f)
1839 mode = "a";
1840 else
1841 mode = "w";
1842 } else {
1843 mode = "r";
1844 }
1845 Yap_initStream(sno, fd, name, mode, file_name, LOCAL_encoding, flags, vfsp);
1846 return sno;
1847}
1848
1849#define CheckStream(arg, kind, msg) \
1850 CheckStream__(__FILE__, __FUNCTION__, __LINE__, arg, kind, msg)
1851
1852static int CheckStream__(const char *file, const char *f, int line, Term arg,
1853 int kind, const char *msg) {
1854 int sno = -1;
1855 arg = Deref(arg);
1856 if (IsVarTerm(arg)) {
1857 Yap_ThrowError(INSTANTIATION_ERROR, arg, msg);
1858 return -1;
1859 } else if (IsAtomTerm(arg)) {
1860 Atom sname = AtomOfTerm(arg);
1861
1862 if (sname == AtomUser) {
1863 if (kind & Input_Stream_f) {
1864 if (kind & (Output_Stream_f | Append_Stream_f)) {
1865 Yap_ThrowError__(file, f, line, PERMISSION_ERROR_OUTPUT_STREAM, arg,
1866 "ambiguous use of 'user' as <a stream");
1867 return (-1);
1868 }
1869 sname = AtomUserIn;
1870 } else {
1871 sname = AtomUserOut;
1872 }
1873 }
1874 if ((sno = Yap_CheckAlias(sname)) < 0) {
1875 UNLOCK(GLOBAL_Stream[sno].streamlock);
1876 Yap_ThrowError__(file, f, line, EXISTENCE_ERROR_STREAM, arg, msg);
1877 return -1;
1878 } else {
1879 LOCK(GLOBAL_Stream[sno].streamlock);
1880 }
1881 } else if (IsApplTerm(arg) && FunctorOfTerm(arg) == FunctorStream) {
1882 arg = ArgOfTerm(1, arg);
1883 if (!IsVarTerm(arg) && IsIntegerTerm(arg)) {
1884 sno = IntegerOfTerm(arg);
1885 }
1886 } else {
1887 Yap_ThrowError(TYPE_ERROR_STREAM, arg, msg);
1888
1889 }
1890 if (sno < 0 || sno > MaxStreams) {
1891 Yap_ThrowError(DOMAIN_ERROR_STREAM_OR_ALIAS, arg, msg);
1892 return -1;
1893 }
1894 if (GLOBAL_Stream[sno].status & Free_Stream_f) {
1895 Yap_ThrowError__(file, f, line, EXISTENCE_ERROR_STREAM, arg, msg);
1896 return -1;
1897 }
1898 LOCK(GLOBAL_Stream[sno].streamlock);
1899 if ((GLOBAL_Stream[sno].status & Input_Stream_f) &&
1900 !(kind & Input_Stream_f)) {
1901 UNLOCK(GLOBAL_Stream[sno].streamlock);
1902 Yap_ThrowError__(file, f, line, PERMISSION_ERROR_OUTPUT_STREAM, arg, msg);
1903 return -1;
1904 }
1905 if ((GLOBAL_Stream[sno].status & (Append_Stream_f | Output_Stream_f)) &&
1906 !(kind & Output_Stream_f)) {
1907 UNLOCK(GLOBAL_Stream[sno].streamlock);
1908 Yap_ThrowError__(file, f, line, PERMISSION_ERROR_INPUT_STREAM, arg, msg);
1909 return -1;
1910 }
1911 return sno;
1912}
1913
1914int Yap_CheckStream__(const char *file, const char *f, int line, Term arg,
1915 int kind, const char *msg) {
1916 return CheckStream__(file, f, line, arg, kind, msg);
1917}
1918
1919int Yap_CheckTextStream__(const char *file, const char *f, int line, Term arg,
1920 int kind, const char *msg) {
1921 int sno;
1922 if ((sno = CheckStream__(file, f, line, arg, kind, msg)) < 0)
1923 return -1;
1924 if ((GLOBAL_Stream[sno].status & Binary_Stream_f)) {
1925 UNLOCK(GLOBAL_Stream[sno].streamlock);
1926 if (kind == Input_Stream_f)
1927 Yap_ThrowError__(file, f, line, PERMISSION_ERROR_INPUT_BINARY_STREAM, arg,
1928 msg);
1929 else
1930 Yap_ThrowError__(file, f, line, PERMISSION_ERROR_OUTPUT_BINARY_STREAM, arg,
1931 msg);
1932 return -1;
1933 }
1934 return sno;
1935}
1936
1937int Yap_CheckTextWriteStream__(const char *file, const char *f, int line,
1938 Term arg, const char *msg) {
1939 int sno, kind = Output_Stream_f;
1940 if ((sno = CheckStream__(file, f, line, arg, kind, msg)) < 0)
1941 return -1;
1942 if ((GLOBAL_Stream[sno].status & Binary_Stream_f)) {
1943 UNLOCK(GLOBAL_Stream[sno].streamlock);
1944 if (kind & Output_Stream_f)
1945 Yap_ThrowError__(file, f, line, PERMISSION_ERROR_INPUT_BINARY_STREAM, arg,
1946 msg);
1947 else
1948 Yap_ThrowError__(file, f, line, PERMISSION_ERROR_OUTPUT_BINARY_STREAM, arg,
1949 msg);
1950 return -1;
1951 }
1952 return sno;
1953}
1954
1955int Yap_CheckTextReadStream__(const char *file, const char *f, int line,
1956 Term arg, const char *msg) {
1957 int sno, kind = Input_Stream_f;
1958 if ((sno = CheckStream__(file, f, line, arg, kind, msg)) < 0)
1959 return -1;
1960 if ((GLOBAL_Stream[sno].status & Binary_Stream_f)) {
1961 UNLOCK(GLOBAL_Stream[sno].streamlock);
1962 if (kind & Input_Stream_f)
1963 Yap_ThrowError__(file, f, line, PERMISSION_ERROR_INPUT_BINARY_STREAM, arg,
1964 msg);
1965 else
1966 Yap_ThrowError__(file, f, line, PERMISSION_ERROR_OUTPUT_BINARY_STREAM, arg,
1967 msg);
1968 return -1;
1969 }
1970 return sno;
1971}
1972
1973int Yap_CheckBinaryStream__(const char *file, const char *f, int line, Term arg,
1974 int kind, const char *msg) {
1975 int sno;
1976 if ((sno = CheckStream__(file, f, line, arg, kind, msg)) < 0)
1977 return -1;
1978 if (!(GLOBAL_Stream[sno].status & Binary_Stream_f)) {
1979 UNLOCK(GLOBAL_Stream[sno].streamlock);
1980 if (kind == Input_Stream_f)
1981 Yap_ThrowError__(file, f, line, PERMISSION_ERROR_INPUT_TEXT_STREAM, arg, msg);
1982 else
1983 Yap_ThrowError__(file, f, line, PERMISSION_ERROR_OUTPUT_TEXT_STREAM, arg, msg);
1984 return -1;
1985 }
1986 return sno;
1987}
1988
1989/* used from C-interface */
1990int Yap_GetFreeStreamDForReading(void) {
1991 int sno = GetFreeStreamD();
1992 StreamDesc *s;
1993
1994 if (sno < 0)
1995 return sno;
1996 s = GLOBAL_Stream + sno;
1997 s->status |= User_Stream_f | Input_Stream_f;
1998 s->charcount = 0;
1999 s->linecount = 1;
2000 s->linestart = 0;
2001 Yap_DefaultStreamOps(s);
2002 UNLOCK(s->streamlock);
2003 return sno;
2004}
2005
2013static Int always_prompt_user(USES_REGS1) {
2014 StreamDesc *s = GLOBAL_Stream + StdInStream;
2015
2016 s->status |= Promptable_Stream_f;
2017 Yap_DefaultStreamOps(s);
2018 return (TRUE);
2019}
2020
2027static Int close1(USES_REGS1) { /* '$close'(+GLOBAL_Stream) */
2028 int sno = CheckStream(
2029 ARG1, (Input_Stream_f | Output_Stream_f | Socket_Stream_f), "close/2");
2030 if (sno < 0)
2031 return false;
2032 if (sno <= StdErrStream) {
2033 UNLOCK(GLOBAL_Stream[sno].streamlock);
2034 return true;
2035 }
2036 Yap_CloseStream(sno);
2037 UNLOCK(GLOBAL_Stream[sno].streamlock);
2038 return (TRUE);
2039}
2040
2041#define CLOSE_DEFS() \
2042 PAR("force", booleanFlag, CLOSE_FORCE), PAR(NULL, ok, CLOSE_END)
2043
2044#define PAR(x, y, z) z
2045
2046typedef enum close_enum_choices { CLOSE_DEFS() } close_choices_t;
2047
2048#undef PAR
2049
2050#define PAR(x, y, z) \
2051 { x, y, z }
2052
2053static const param_t close_defs[] = {CLOSE_DEFS()};
2054#undef PAR
2055
2065static Int close2(USES_REGS1) { /* '$close'(+GLOBAL_Stream) */
2066 Int sno = CheckStream(
2067 ARG1, (Input_Stream_f | Output_Stream_f | Socket_Stream_f), "close/2");
2068 Term tlist;
2069 if (sno < 0)
2070 return (FALSE);
2071 if (sno <= StdErrStream) {
2072 UNLOCK(GLOBAL_Stream[sno].streamlock);
2073 return TRUE;
2074 }
2075 xarg *args = Yap_ArgListToVector((tlist = Deref(ARG2)), close_defs, CLOSE_END, NULL,
2076 DOMAIN_ERROR_CLOSE_OPTION);
2077 if (args == NULL) {
2078 if (LOCAL_Error_TYPE != YAP_NO_ERROR) {
2079 Yap_ThrowError(LOCAL_Error_TYPE, tlist, NULL);
2080 }
2081 return false;
2082 }
2083 // if (args[CLOSE_FORCE].used) {
2084 // }
2085 Yap_CloseStream(sno);
2086 UNLOCK(GLOBAL_Stream[sno].streamlock);
2087 return (TRUE);
2088}
2089
2090Term read_line(int sno) {
2091 CACHE_REGS
2092 Term tail;
2093 Int ch;
2094
2095 if ((ch = GLOBAL_Stream[sno].stream_wgetc(sno)) == 10) {
2096 return (TermNil);
2097 }
2098 tail = read_line(sno);
2099 return (MkPairTerm(MkIntTerm(ch), tail));
2100}
2101void Yap_InitPlIO(struct yap_boot_params *argi) {
2102 Int i;
2103 if (argi->inp > 0)
2104 Yap_stdin = fdopen(argi->inp - 1, "r");
2105 else if (argi->inp < 0)
2106 Yap_stdin = NULL;
2107 else
2108 Yap_stdin = stdin;
2109 if (argi->out > 0)
2110 Yap_stdout = fdopen(argi->out - 1, "a");
2111 else if (argi->out < 0)
2112 Yap_stdout = NULL;
2113 else
2114 Yap_stdout = stdout;
2115 if (argi->err > 0)
2116 Yap_stderr = fdopen(argi->err - 1, "a");
2117 else if (argi->out)
2118 Yap_stdout = NULL;
2119 else
2120 Yap_stderr = stderr;
2121 GLOBAL_Stream =
2122 (StreamDesc *)Yap_AllocCodeSpace(sizeof(StreamDesc) * MaxStreams);
2123 for (i = 0; i < MaxStreams; ++i) {
2124 INIT_LOCK(GLOBAL_Stream[i].streamlock);
2125 GLOBAL_Stream[i].status = Free_Stream_f;
2126 }
2127 InitStdStreams();
2128}
2129
2130void Yap_InitIOPreds(void) {
2131 /* here the Input/Output predicates */
2132 Yap_InitCPred("always_prompt_user", 0, always_prompt_user,
2133 SafePredFlag | SyncPredFlag);
2134 Yap_InitCPred("close", 1, close1, SafePredFlag | SyncPredFlag);
2135 Yap_InitCPred("close", 2, close2, SafePredFlag | SyncPredFlag);
2136 Yap_InitCPred("open", 4, open4, SyncPredFlag);
2137 Yap_InitCPred("open", 3, open3, SyncPredFlag);
2138 Yap_InitCPred("$file_expansion", 2, p_file_expansion,
2139 SafePredFlag | SyncPredFlag | HiddenPredFlag);
2140 Yap_InitCPred("$open_null_stream", 1, p_open_null_stream,
2141 SafePredFlag | SyncPredFlag | HiddenPredFlag);
2142 Yap_InitIOStreams();
2143 Yap_InitAliases();
2144 Yap_InitCharsio();
2145 Yap_InitChtypes();
2146 Yap_InitConsole();
2147 Yap_InitReadUtil();
2148 Yap_InitMems();
2149 Yap_InitPipes();
2150 Yap_InitFiles();
2151 Yap_InitWriteTPreds();
2152 Yap_InitReadTPreds();
2153 Yap_InitFormat();
2154 Yap_InitRandomPreds();
2155#if USE_READLINE
2156 Yap_InitReadlinePreds();
2157#endif
2158 Yap_InitSockets();
2159 Yap_InitSignalPreds();
2160 Yap_InitSysPreds();
2161 Yap_InitTimePreds();
2162 Yap_InitAbsfPreds();
2163 }
Main definitions.
const char * Yap_AbsoluteFile(const char *spec, bool ok)
generate absolute path, if ok first expand SICStus Prolog style
Definition: absf.c:145
void * Malloc(size_t sz USES_REGS)
allocate a temporary text block
Definition: alloc.c:1759
void Yap_ThrowError__(const char *file, const char *function, int lineno, yap_error_number type, Term where, const char *msg,...)
Throw an error directly to the error handler.
Definition: errors.c:789
@ encoding
support for coding systens, YAP relies on UTF-8 internally
Definition: YapLFlagInfo.h:83
int EOFPeek(int sno)
caled after EOF found a peek, it just calls console_post_process to conclude the job
Definition: iopreds.c:763
Definition: Yatom.h:544
int(* stream_getc)(int)
function the stream uses for writing a character
Definition: YapStreams.h:256
int(* stream_wputc)(int, wchar_t)
function the stream uses for writing a single octet
Definition: YapStreams.h:254
encoding_t encoding
check if the next wide character is available
Definition: YapStreams.h:265
int(* stream_wgetc)(int)
function the stream uses for reading an octet
Definition: YapStreams.h:257
int(* stream_wpeek)(int)
check if the next character is available
Definition: YapStreams.h:264
struct vfs * vfs
function the stream uses for reading a character
Definition: YapStreams.h:259
int(* stream_wgetc_for_read)(int)
direct handle to stream in that space
Definition: YapStreams.h:261
int(* stream_peek)(int)
function the stream uses for parser
Definition: YapStreams.h:263
Definition: VFS.h:74
void *(* open)(struct vfs *, const char *fname, const char *io_mode, int sno)
operations
Definition: VFS.h:82
int(* put_char)(int sno, int ch)
unget an octet from the stream
Definition: VFS.h:91
int(* get_wchar)(int sno)
get an octet from the stream
Definition: VFS.h:88
int(* get_char)(int sno)
close the object
Definition: VFS.h:87
int(* put_wchar)(int sno, int ch)
output an octet to the stream
Definition: VFS.h:92
encoding_t enc
set working directory (may be virtual)
Definition: VFS.h:108
Definition: YapFlags.h:152