1 /* port.h                                          -*- mode:c; coding:utf-8; -*-
2  *
3  *   Copyright (c) 2010-2021  Takashi Kato <ktakashi@ymail.com>
4  *
5  *   Redistribution and use in source and binary forms, with or without
6  *   modification, are permitted provided that the following conditions
7  *   are met:
8  *
9  *   1. Redistributions of source code must retain the above copyright
10  *      notice, this list of conditions and the following disclaimer.
11  *
12  *   2. Redistributions in binary form must reproduce the above copyright
13  *      notice, this list of conditions and the following disclaimer in the
14  *      documentation and/or other materials provided with the distribution.
15  *
16  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
22  *   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23  *   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24  *   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  *   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  *  $Id: $
29  */
30 #ifndef SAGITTARIUS_PRIVATE_PORT_H_
31 #define SAGITTARIUS_PRIVATE_PORT_H_
32 
33 #include "sagittariusdefs.h"
34 #include "thread.h"
35 #include "clos.h"
36 #include "file.h"
37 #include "vm.h"
38 #include "system.h"
39 
40 typedef enum SgFileLockType SgPortLockType;
41 
42 typedef enum {
43   SG_INPUT_PORT = 1UL,
44   SG_OUTPUT_PORT = 1UL<<1,
45   SG_IN_OUT_PORT = SG_INPUT_PORT | SG_OUTPUT_PORT,
46   /* input/output port + alpha */
47   SG_BIDIRECTIONAL_PORT = 1UL<<2 | SG_IN_OUT_PORT
48 } SgPortDirection;
49 
50 typedef enum {
51   SG_PORT_OPEN = 0,
52   SG_PORT_PSEUDO = 1,
53   SG_PORT_CLOSED = 2
54 } SgPortClosedType;
55 
56 #define SG_STREAM_BUFFER_SIZE 32
57 
58 #define SG_MAKE_STREAM_BUFFER(type, data)		\
59   typedef struct type##_rec				\
60   {							\
61     int position;					\
62     data buf[SG_STREAM_BUFFER_SIZE];			\
63     struct type##_rec *next;				\
64   } type;
65 
66 SG_MAKE_STREAM_BUFFER(byte_buffer, uint8_t);
67 SG_MAKE_STREAM_BUFFER(char_buffer, SgChar);
68 
69 #define SG_STREAM_BUFFER_PUT_REC(type, r, _buf, c)	\
70   do {							\
71     type *__tmp = (_buf);				\
72     if (__tmp->position >= SG_STREAM_BUFFER_SIZE) {	\
73       if (__tmp->next == NULL) {			\
74 	__tmp->next = SG_NEW(type);			\
75       }							\
76       __tmp->next->position = 0;			\
77       (r) = __tmp = __tmp->next;			\
78     }							\
79     __tmp->buf[__tmp->position++] = (c);		\
80   } while(0)
81 
82 #define SG_STREAM_BUFFER_PUTB(r, buf, b)		\
83   SG_STREAM_BUFFER_PUT_REC(byte_buffer, r, buf, b)
84 #define SG_STREAM_BUFFER_PUTC(r, buf, c)		\
85   SG_STREAM_BUFFER_PUT_REC(char_buffer, r, buf, c)
86 
87 
88 #define SG_STREAM_BUFFER_COUNT_REC(type, r, start)			\
89   do {									\
90     type *__t = (start);						\
91     for ((r)=0;__t && __t &&__t->next; __t=__t->next,(r)++);		\
92     (r) *= SG_STREAM_BUFFER_SIZE;					\
93     if (__t) (r) += __t->position;					\
94   } while (0)
95 #define SG_STREAM_BUFFER_COUNTC(r, start)	\
96   SG_STREAM_BUFFER_COUNT_REC(char_buffer, r, start)
97 #define SG_STREAM_BUFFER_COUNTB(r, start)	\
98   SG_STREAM_BUFFER_COUNT_REC(byte_buffer, r, start)
99 
100 #define SG_STREAM_BUFFER_POSITION_REC(type, r, start, current)		\
101   do {									\
102     type *__t = (start);						\
103     for ((r)=0LL;__t && __t == (current); __t=__t->next,(r)++);		\
104     (r) *= SG_STREAM_BUFFER_SIZE;					\
105     if (__t) (r) += __t->position;					\
106   } while (0)
107 #define SG_STREAM_BUFFER_POSITIONC(r, start, current)			\
108   SG_STREAM_BUFFER_POSITION_REC(char_buffer, r, start, current)
109 #define SG_STREAM_BUFFER_POSITIONB(r, start)				\
110   SG_STREAM_BUFFER_POSITION_REC(byte_buffer, r, start, current)
111 
112 
113 
114 #define SG_STREAM_BUFFER_GET_BUFFER_REC(buftype, type, r, start)	\
115   do {									\
116     int __off;								\
117     type *__t = (start);						\
118     for (__off=0; __t && __t->position >= SG_STREAM_BUFFER_SIZE;	\
119 	 __t=__t->next,__off+=SG_STREAM_BUFFER_SIZE) {			\
120       memcpy((r)+__off, __t->buf, sizeof(buftype)*SG_STREAM_BUFFER_SIZE); \
121     }									\
122     if (__t) memcpy((r)+__off, __t->buf,sizeof(buftype)*__t->position);	\
123   } while (0)
124 
125 #define SG_STREAM_BUFFER_GET_BUFFERB(r, start)		\
126   SG_STREAM_BUFFER_GET_BUFFER_REC(uint8_t, byte_buffer, r, start)
127 
128 #define SG_STREAM_BUFFER_GET_BUFFERC(r, start)		\
129   SG_STREAM_BUFFER_GET_BUFFER_REC(SgChar, char_buffer, r, start)
130 
131 #define SG_STREAM_BUFFER_SET_POSITION_REC(type, start, cur, pos)	\
132   do {								\
133     type *__t = (start);					\
134     int __c = (int)(pos)/SG_STREAM_BUFFER_SIZE;			\
135     int __o = (int)(pos)%SG_STREAM_BUFFER_SIZE;			\
136     int __i;							\
137     for (__i = 0; __i < __c; __i++, __t =__t->next) {		\
138       __t->position = SG_STREAM_BUFFER_SIZE;			\
139       if (!__t->next) __t->next = SG_NEW(type);			\
140     }								\
141     __t->position = __o;					\
142     (cur) = __t;						\
143   } while(0)							\
144 
145 #define SG_STREAM_BUFFER_SET_POSITIONB(start, cur, pos)		\
146   SG_STREAM_BUFFER_SET_POSITION_REC(byte_buffer, start, cur, pos)
147 #define SG_STREAM_BUFFER_SET_POSITIONC(start, cur, pos)		\
148   SG_STREAM_BUFFER_SET_POSITION_REC(char_buffer, start, cur, pos)
149 
150 /*
151    Port
152 
153    On Sagittarius, port has the following class hierarchy.
154 
155    + port
156       + bytevector port
157       + string port
158       + file port
159       + custom port
160       + buffered port
161 
162    Buffer mode from R6RS is handled in 'buffered port'.
163  */
164 /* base port class */
165 SG_CLASS_DECL(Sg_PortClass);
166 #define SG_CLASS_PORT (&Sg_PortClass)
167 
168 typedef struct SgPortTableRec
169 {
170   void (*flush)(SgObject);
171   int  (*close)(SgObject);
172   int  (*ready)(SgObject);
173   int  (*lockPort)(SgObject, SgPortLockType);
174   int  (*unlockPort)(SgObject);
175   /*
176      portPosition used to have whence however it's rather useless.
177      say whence is current then it always return 0.
178      if the whence is end, where should it be especially the
179      port is input port and contains infinite data.
180    */
181   int64_t  (*portPosition)(SgObject);
182   void     (*setPortPosition)(SgObject, int64_t, SgWhence);
183   /* port operations */
184   int     (*open)(SgObject);
185 
186   /* Binary port operations */
187   /* reads byte arrey from port */
188   int64_t (*readb)(SgObject, uint8_t *, int64_t);
189   /* reads all bytes from port */
190   int64_t (*readbAll)(SgObject, uint8_t **);
191   /* writes bytes to port */
192   int64_t (*writeb)(SgObject, uint8_t *, int64_t);
193 
194   /* Textual port operations */
195   /* reads string from port */
196   int64_t (*reads)(SgObject, SgChar *, int64_t);
197   int64_t (*writes)(SgObject, SgChar *, int64_t);
198 } SgPortTable;
199 
200 struct SgPortRec
201 {
202   SG_INSTANCE_HEADER;		/* can be extended */
203   SgPortTable *vtbl;
204   SgPortDirection direction;
205   /* we may want to use bit field but for now no need for it */
206   /* port closed type but for future extension (may not happen)
207      it's int. (for bit field)
208    */
209   int closed;
210   SgChar peek;			/* this can be char or byte */
211   /* Assosiated transcoder:
212      #f : no transcoder (binary port)
213      #t : string port
214      transcoder: transcoded textual port
215    */
216   SgObject transcoder;
217   unsigned int readLockCount;
218   unsigned int writeLockCount;
219   SgVM        *readLockOwner;
220   SgVM        *writeLockOwner;
221 
222   readtable_t *readtable;
223   SgObject     reader;
224   SgObject     data;		/* alist of port data */
225 
226   /*
227      The actual locks are emulated by above VM instances.
228      This mutex is the actual lock to obtain them. Unlike
229      the emulated locks, the actual lock can only be one
230      since the port lock macro always releases the mutex
231      in very short time (only just setting VM instances).
232      Thus holding 2 mutex would more cost than waiting
233      the period.
234    */
235   SgInternalMutex lock;
236   int64_t      position;	/* current position */
237   int64_t      lineNo;		/* line no */
238 };
239 
240 #define SG_PORT(obj)           ((SgPort*)obj)
241 #define SG_PORTP(obj)          SG_ISA(obj, SG_CLASS_PORT)
242 #define SG_PORT_VTABLE(obj)    SG_PORT(obj)->vtbl
243 #define SG_PORT_READER(obj)    SG_PORT(obj)->reader
244 #define SG_PORT_READTABLE(obj) SG_PORT(obj)->readtable
245 #define SG_PORT_DATA(obj)      SG_PORT(obj)->data
246 
247 #define SG_PORT_HAS_U8_AHEAD(obj)    (SG_PORT(obj)->peek != EOF)
248 #define SG_PORT_U8_AHEAD(obj)        (SG_PORT(obj)->peek)
249 #define SG_PORT_HAS_CHAR_AHEAD(obj)  (SG_PORT(obj)->peek != EOF)
250 #define SG_PORT_CHAR_AHEAD(obj)      (SG_PORT(obj)->peek)
251 
252 /* port type */
253 #define SG_BINARY_PORTP(obj)					\
254   ((SG_PORTP(obj)) && SG_FALSEP(SG_PORT(obj)->transcoder))
255 #define SG_TEXTUAL_PORTP(obj)					\
256   ((SG_PORTP(obj)) && !SG_FALSEP(SG_PORT(obj)->transcoder))
257 
258 /* port direction */
259 #define SG_INPUT_PORTP(obj)					\
260   (SG_PORTP(obj) && SG_PORT(obj)->direction & SG_INPUT_PORT)
261 #define SG_OUTPUT_PORTP(obj)					\
262   (SG_PORTP(obj) && SG_PORT(obj)->direction & SG_OUTPUT_PORT)
263 #define SG_IN_OUT_PORTP(obj)					\
264   (SG_PORTP(obj) &&						\
265    (SG_PORT(obj)->direction & SG_IN_OUT_PORT) == SG_IN_OUT_PORT)
266 #define SG_BIDIRECTIONAL_PORTP(obj)					\
267   (SG_PORTP(obj) &&							\
268    (SG_PORT(obj)->direction & SG_BIDIRECTIONAL_PORT) == SG_BIDIRECTIONAL_PORT)
269 
270 
271 typedef struct SgFilePortRec
272 {
273   SgPort parent;
274   SgFile *file;
275 } SgFilePort;
276 
277 #define SG_FILE_PORT(obj) ((SgFilePort *)obj)
278 
279 typedef struct SgBytePortRec
280 {
281   SgPort parent;
282   union {
283     struct {
284       byte_buffer *start;
285       byte_buffer *current;
286     } /* out */ ;
287     struct {
288       uint8_t *buf;
289       uint8_t *end;
290       size_t   index;
291     } /* in */ ;
292   } buffer;
293 } SgBytePort;
294 
295 #define SG_BYTE_PORT(obj) ((SgBytePort *)obj)
296 
297 typedef struct SgStringPortRec
298 {
299   SgPort parent;
300   union {
301     struct {
302       char_buffer *start;
303       char_buffer *current;
304     } /* out */ ;
305     struct {
306       SgChar *buf;
307       SgChar *end;
308       size_t  index;
309     } /* in */ ;
310   } buffer;
311 } SgStringPort;
312 
313 #define SG_STRING_PORT(obj) ((SgStringPort *)obj)
314 
315 
316 /* to create fresh port by transcoded-port
317    it's rather silly but no choice.
318  */
319 typedef struct SgTranscodedPortRec
320 {
321   SgPort parent;
322   SgPort *port;
323 } SgTranscodedPort;
324 #define SG_TRANSCODED_PORT(o) ((SgTranscodedPort *)o)
325 #define SG_TRANSCODED_PORT_UNGET(o) SG_PORT(o)->peek
326 #define SG_TRANSCODED_PORT_PORT(o)  SG_TRANSCODED_PORT(o)->port
327 #define SG_TRANSCODED_PORT_LINE_NO(o)  SG_PORT(o)->lineNo
328 #define SG_TRANSCODED_PORT_TRANSCODER(o) SG_PORT(o)->transcoder
329 
330 #define SG_PORT_DEFAULT_BUFFER_SIZE 8196
331 
332 typedef enum {
333   SG_BUFFER_MODE_NONE = 0x01,
334   SG_BUFFER_MODE_LINE = 0x02,
335   SG_BUFFER_MODE_BLOCK = 0x03
336 } SgBufferMode;
337 
338 typedef struct SgBufferedPortRec
339 {
340   SgPort parent;
341   SgPort *src;			/* src port */
342   SgBufferMode mode;		/* mode */
343   uint8_t *buffer;		/* buffer */
344   size_t   size;		/* allocated buffer size */
345   int64_t  bufferSize;		/* read buffer size */
346   int64_t  index;		/* buffer index */
347   int      dirty;		/* TRUE if port position is changed */
348 } SgBufferedPort;
349 #define SG_BUFFERED_PORT(obj) ((SgBufferedPort *)obj)
350 #define SG_BUFFERED_PORT_SRC(obj) SG_BUFFERED_PORT(obj)->src
351 
352 #define SG_CUSTOM_PORT_TYPE_BINARY  0
353 #define SG_CUSTOM_PORT_TYPE_TEXTUAL 1
354 typedef struct SgCustomPortSpecRec
355 {
356   int       type;		/* type. binary or texual */
357   int       direction;
358   SgString *id;			/* id must be string */
359   /* common procs */
360   SgObject  getPosition;	/* get-position */
361   SgObject  setPosition;	/* set-position! */
362   SgObject  close;		/* close */
363   /* for input port */
364   SgObject  read;		/* read */
365   /* for output port */
366   SgObject  write;		/* write */
367   SgObject  ready;		/* u8 or char ready */
368   SgObject  flush;		/* flush */
369   /* vtable, if this is NULL, then get from type */
370   SgPortTable *table;
371   int wrap;			/* wrap set position */
372 } SgCustomPortSpec;
373 
374 typedef struct SgCustomPortRec
375 {
376   SgPort    parent;
377   SgString *id;			/* id must be string */
378   /* common procs */
379   SgObject  getPosition;	/* get-position */
380   SgObject  setPosition;	/* set-position! */
381   SgObject  close;		/* close */
382   /* for input port */
383   SgObject  read;		/* read */
384   /* for output port */
385   SgObject  write;		/* write */
386   SgObject  ready;		/* u8 or char ready */
387   SgObject  flush;		/* flush */
388 
389   /* custom port buffer */
390   union {
391     SgString     *textualBuffer; /* buffer for custom textual port */
392     SgByteVector *binaryBuffer;	/* buffer for custom binary port */
393   };
394 } SgCustomPort;
395 #define SG_CUSTOM_PORT(obj) ((SgCustomPort *)obj)
396 
397 SG_CLASS_DECL(Sg_FilePortClass);
398 SG_CLASS_DECL(Sg_BytePortClass);
399 SG_CLASS_DECL(Sg_StringPortClass);
400 SG_CLASS_DECL(Sg_CustomPortClass);
401 SG_CLASS_DECL(Sg_BufferedPortClass);
402 SG_CLASS_DECL(Sg_TranscodedPortClass);
403 /* This is not a real port but only marking to make get-bytevector-n
404    or get-string-n related procedure read only once even though the
405    port isn't reached to EOF. This is useful when the port has an
406    indefinite stream source such socket.
407  */
408 SG_CLASS_DECL(Sg_ReadOncePortClass);
409 
410 #define SG_CLASS_FILE_PORT (&Sg_FilePortClass)
411 #define SG_CLASS_BYTE_PORT (&Sg_BytePortClass)
412 #define SG_CLASS_STRING_PORT (&Sg_StringPortClass)
413 #define SG_CLASS_CUSTOM_PORT (&Sg_CustomPortClass)
414 #define SG_CLASS_BUFFERED_PORT (&Sg_BufferedPortClass)
415 #define SG_CLASS_TRANSCODED_PORT (&Sg_TranscodedPortClass)
416 #define SG_CLASS_READ_ONCE_PORT (&Sg_ReadOncePortClass)
417 
418 #define SG_FILE_PORTP(o)       SG_ISA(o, SG_CLASS_FILE_PORT)
419 #define SG_BYTE_PORTP(o)       SG_ISA(o, SG_CLASS_BYTE_PORT)
420 #define SG_STRING_PORTP(o)     SG_ISA(o, SG_CLASS_STRING_PORT)
421 #define SG_CUSTOM_PORTP(o)     SG_ISA(o, SG_CLASS_CUSTOM_PORT)
422 #define SG_BUFFERED_PORTP(o)   SG_ISA(o, SG_CLASS_BUFFERED_PORT)
423 #define SG_TRANSCODED_PORTP(o) SG_ISA(o, SG_CLASS_TRANSCODED_PORT)
424 
425 /* from Gauche but we need to manage both read and write lock */
426 #define SG_PORT_LOCK_REC(port, owner__, counter__)		\
427   do {								\
428     SgVM *vm = Sg_VM();						\
429     if ((port)-> owner__ != vm) {				\
430       for (;;) {						\
431 	SgVM *owner_;						\
432 	Sg_LockMutex(&(port)->lock);				\
433 	owner_ = (port)-> owner__;				\
434 	if (owner_ == NULL					\
435 	    || (owner_->threadState == SG_VM_TERMINATED)) {	\
436 	  (port)-> owner__ = vm;				\
437 	  (port)-> counter__ = 1;				\
438 	}							\
439 	Sg_UnlockMutex(&(port)->lock);				\
440 	if ((port)-> owner__ == vm) break;			\
441 	Sg_YieldCPU();						\
442       }								\
443     } else {							\
444       (port)-> counter__ ++;					\
445     }								\
446   } while (0)
447 
448 #define SG_PORT_UNLOCK_REC(port, owner__, counter__)		\
449   do {								\
450     if (--(port)-> counter__ <= 0) (port)-> owner__ = NULL;	\
451   } while (0)
452 
453 #define SG_PORT_LOCK_READ(port)				\
454   SG_PORT_LOCK_REC(port, readLockOwner, readLockCount)
455 #define SG_PORT_UNLOCK_READ(port)				\
456   SG_PORT_UNLOCK_REC(port, readLockOwner, readLockCount)
457 
458 #define SG_PORT_LOCK_WRITE(port)				\
459   do {								\
460     if (SG_BIDIRECTIONAL_PORTP(port)) {				\
461 	SG_PORT_LOCK_REC(port, writeLockOwner, writeLockCount);	\
462       } else {							\
463 	SG_PORT_LOCK_READ(port);				\
464       }								\
465   } while (0)
466 
467 #define SG_PORT_UNLOCK_WRITE(port)				\
468   do {								\
469     if (SG_BIDIRECTIONAL_PORTP(port)) {				\
470       SG_PORT_UNLOCK_REC(port, writeLockOwner, writeLockCount);	\
471     } else {							\
472       SG_PORT_UNLOCK_READ(port);				\
473     }								\
474   } while (0)
475 
476 #define SG_INIT_PORT(port, clazz, d, tbl, tr)		\
477   do {							\
478     SG_SET_CLASS((port), (clazz));			\
479     SG_PORT(port)->direction = (d);			\
480     SG_PORT(port)->position = 0;			\
481     SG_PORT(port)->vtbl = (tbl);			\
482     SG_PORT(port)->transcoder = (tr);			\
483     SG_PORT(port)->reader = SG_FALSE;			\
484     SG_PORT(port)->closed = SG_PORT_OPEN;		\
485     SG_PORT(port)->data = SG_NIL;			\
486     SG_PORT(port)->readtable = NULL;			\
487     SG_PORT(port)->readLockCount = 0;			\
488     SG_PORT(port)->readLockOwner = NULL;		\
489     SG_PORT(port)->writeLockCount = 0;			\
490     SG_PORT(port)->writeLockOwner = NULL;		\
491     SG_PORT(port)->lineNo = -1;				\
492     SG_PORT(port)->peek = EOF;				\
493     Sg_InitMutex(&SG_PORT(port)->lock, TRUE);		\
494   } while (0)
495 
496 #define SG_INIT_BINARY_PORT(bp, t)		\
497   do {						\
498     (bp)->type = (t);				\
499     (bp)->buffer = NULL;			\
500     (bp)->bufferSize = 0;			\
501     (bp)->bufferIndex = 0;			\
502     (bp)->position = 0;				\
503     (bp)->dirty = FALSE;			\
504     (bp)->closed = SG_BPORT_OPEN;		\
505   } while (0)
506 
507 
508 #define SG_CLEAN_PORT_LOCK(port)			\
509   do {							\
510     Sg_DestroyMutex(&(port)->lock);			\
511   } while (0)
512 
513 /* for GC friendliness */
514 /* The src is union so it is enough to make first 2 words NULL */
515 #define SG_CLEAN_BYTE_PORT(bp)			\
516   do {						\
517     SG_BYTE_PORT(bp)->buffer.start = NULL;	\
518     SG_BYTE_PORT(bp)->buffer.current = NULL;	\
519   } while (0)
520 #define SG_CLEAN_TRANSCODED_PORT(tp)		\
521     do {					\
522     SG_TRANSCODED_PORT(tp)->port = NULL;	\
523     SG_PORT(tp)->transcoder = SG_TRUE;		\
524   } while (0)
525 #define SG_CLEAN_STRING_PORT(tp)		\
526     do {					\
527       (tp)->buffer.start = NULL;		\
528       (tp)->buffer.current = NULL;		\
529   } while (0)
530 
531 SG_CDECL_BEGIN
532 
533 SG_EXTERN SgObject Sg_MakeFileBinaryInputPort(SgFile *file, int bufferMode);
534 SG_EXTERN SgObject Sg_MakeFileBinaryOutputPort(SgFile *file, int bufferMode);
535 SG_EXTERN SgObject Sg_MakeFileBinaryInputOutputPort(SgFile *file,
536 						    int bufferMode);
537 SG_EXTERN SgObject Sg_InitFileBinaryPort(SgFilePort *port,
538 					 SgFile *file,
539 					 SgPortDirection d,
540 					 SgBufferedPort *bufferedPort,
541 					 SgBufferMode mode,
542 					 uint8_t *buffer,
543 					 size_t bufferSize);
544 /* Sg_MakeByteVectorInputPort is just for bytevector->string to avoid an
545    allocation. so we don't provide output and input/output port for it.
546  */
547 SG_EXTERN SgObject Sg_MakeByteVectorInputPort(SgByteVector *bv,
548 					      int64_t start, int64_t end);
549 SG_EXTERN SgObject Sg_MakeByteArrayInputPort(uint8_t *src, int64_t size);
550 /* We can't make common byte array initialisation function... */
551 SG_EXTERN SgObject Sg_InitByteArrayInputPort(SgBytePort *port,
552 					     uint8_t *src,
553 					     size_t start, size_t end);
554 SG_EXTERN SgObject Sg_MakeByteArrayOutputPort(size_t bufferSize);
555 SG_EXTERN SgObject Sg_InitByteArrayOutputPort(SgBytePort *port,
556 					      size_t bufferSize);
557 
558 SG_EXTERN SgObject Sg_MakeTranscodedPort(SgPort *port,
559 					 SgTranscoder *transcoder);
560 SG_EXTERN SgObject Sg_InitTranscodedPort(SgTranscodedPort *port,
561 					 SgPort *src,
562 					 SgTranscoder *transcoder,
563 					 SgPortDirection direction);
564 
565 /* buffer size is not used yet */
566 SG_EXTERN SgObject Sg_MakeStringOutputPort(size_t bufferSize);
567 SG_EXTERN SgObject Sg_InitStringOutputPort(SgStringPort *port,
568 					   size_t bufferSize);
569 SG_EXTERN SgObject Sg_MakeStringInputPort(SgString *in,
570 					  int64_t start, int64_t end);
571 SG_EXTERN SgObject Sg_InitStringInputPort(SgStringPort *port, SgString *in,
572 					  int64_t start, int64_t end);
573 /* For convenience and future improvement */
574 SG_EXTERN SgObject Sg_ConvertToStringOutputPort(SgChar *buf, int bufferSize);
575 
576 /* custom ports */
577 SG_EXTERN SgObject Sg_MakeCustomBinaryPort(SgString *id,
578 					   int direction,
579 					   SgObject read,
580 					   SgObject write,
581 					   SgObject getPosition,
582 					   SgObject setPosition,
583 					   SgObject close,
584 					   SgObject ready);
585 SG_EXTERN SgObject Sg_MakeCustomTextualPort(SgString *id,
586 					    int direction,
587 					    SgObject read,
588 					    SgObject write,
589 					    SgObject getPosition,
590 					    SgObject setPosition,
591 					    SgObject close,
592 					    SgObject ready);
593 /* easier */
594 SG_EXTERN SgObject Sg_MakeCustomPort(SgCustomPortSpec *spec);
595 
596 /* buffered port */
597 SG_EXTERN SgObject Sg_MakeBufferedPort(SgPort *src, SgBufferMode mode,
598 				       uint8_t *buffer, size_t size);
599 SG_EXTERN SgObject Sg_InitBufferedPort(SgBufferedPort *port,
600 				       SgBufferMode mode, SgPort *src,
601 				       uint8_t *buffer, size_t size);
602 
603 SG_EXTERN uint8_t* Sg_GetByteArrayFromBinaryPort(SgBytePort *port);
604 SG_EXTERN SgObject Sg_GetByteVectorFromBinaryPort(SgBytePort *port);
605 SG_EXTERN SgObject Sg_GetStringFromStringPort(SgStringPort *port);
606 
607 SG_EXTERN void     Sg_ClosePort(SgPort *port);
608 SG_EXTERN void     Sg_PseudoClosePort(SgPort *port);
609 SG_EXTERN int      Sg_PortClosedP(SgPort *port);
610 SG_EXTERN int      Sg_PseudoPortClosedP(SgPort *port);
611 
612 SG_EXTERN SgObject Sg_StandardOutputPort();
613 SG_EXTERN SgObject Sg_StandardInputPort();
614 SG_EXTERN SgObject Sg_StandardErrorPort();
615 
616 /* accessor */
617 SG_EXTERN SgObject Sg_PortTranscoder(SgObject port);
618 
619 SG_EXTERN int      Sg_ReadOncePortP(SgPort *port);
620 
621 /* utility methods */
622 SG_EXTERN int      Sg_LockPortResource(SgPort *port, SgPortLockType lockType);
623 SG_EXTERN int      Sg_UnlockPortResouce(SgPort *port);
624 SG_EXTERN int      Sg_PortReady(SgPort *port);
625 SG_EXTERN int      Sg_UTF16ConsolePortP(SgPort *port);
626 SG_EXTERN void     Sg_FlushPort(SgPort *port);
627 SG_EXTERN void     Sg_FlushAllPort(int exitting);
628 SG_EXTERN int      Sg_Getb(SgPort *port);
629 SG_EXTERN int      Sg_Peekb(SgPort *port);
630 SG_EXTERN int64_t  Sg_Readb(SgPort *port, uint8_t *buf, int64_t size);
631 SG_EXTERN int64_t  Sg_ReadbAll(SgPort *port, uint8_t **buf);
632 SG_EXTERN void     Sg_Writeb(SgPort *port, uint8_t *b,
633 			     int64_t start, int64_t count);
634 SG_EXTERN void     Sg_Putb(SgPort *port, uint8_t b);
635 SG_EXTERN void     Sg_Putbv(SgPort *port, SgByteVector *bv);
636 SG_EXTERN SgChar   Sg_Getc(SgPort *port);
637 SG_EXTERN SgChar   Sg_Peekc(SgPort *port);
638 SG_EXTERN void     Sg_Putc(SgPort *port, SgChar ch);
639 SG_EXTERN void     Sg_Putz(SgPort *port, const char *str);
640 SG_EXTERN void     Sg_Putuz(SgPort *port, const SgChar *str);
641 SG_EXTERN void     Sg_Puts(SgPort *port, SgString *str);
642 
643 SG_EXTERN void     Sg_PutbUnsafe(SgPort *port, uint8_t b);
644 SG_EXTERN void     Sg_PutbvUnsafe(SgPort *port, SgByteVector *bv);
645 SG_EXTERN void     Sg_WritebUnsafe(SgPort *port, uint8_t *b, int64_t start,
646 				   int64_t count);
647 /* for textual port */
648 SG_EXTERN void     Sg_Writes(SgPort *port, SgChar *s, int64_t count);
649 SG_EXTERN void     Sg_WritesUnsafe(SgPort *port, SgChar *s, int64_t count);
650 SG_EXTERN int64_t  Sg_Reads(SgPort *port, SgChar *s, int64_t count);
651 SG_EXTERN int64_t  Sg_ReadsUnsafe(SgPort *port, SgChar *s, int64_t count);
652 
653 SG_EXTERN void     Sg_PutcUnsafe(SgPort *port, SgChar ch);
654 SG_EXTERN void     Sg_PutzUnsafe(SgPort *port, const char *str);
655 /* is this too similar? */
656 SG_EXTERN void     Sg_PutuzUnsafe(SgPort *port, const SgChar *str);
657 SG_EXTERN void     Sg_PutsUnsafe(SgPort *port, SgString *str);
658 SG_EXTERN SgChar   Sg_GetcUnsafe(SgPort *port);
659 SG_EXTERN int      Sg_GetbUnsafe(SgPort *port);
660 SG_EXTERN int64_t  Sg_ReadbUnsafe(SgPort *port, uint8_t *buf, int64_t size);
661 SG_EXTERN int64_t  Sg_ReadbAllUnsafe(SgPort *port, uint8_t **buf);
662 SG_EXTERN void     Sg_UngetcUnsafe(SgPort *port, SgChar ch);
663 SG_EXTERN int      Sg_PeekbUnsafe(SgPort *port);
664 SG_EXTERN SgChar   Sg_PeekcUnsafe(SgPort *port);
665 
666 /* seek/tell */
667 SG_EXTERN int      Sg_HasPortPosition(SgPort *port);
668 SG_EXTERN int      Sg_HasSetPortPosition(SgPort *port);
669 SG_EXTERN int64_t  Sg_PortPosition(SgPort *port);
670 SG_EXTERN void     Sg_SetPortPosition(SgPort *port, int64_t offset,
671 				      SgWhence whence);
672 
673 SG_EXTERN int64_t Sg_LineNo(SgPort *port);
674 SG_EXTERN SgObject Sg_FileName(SgPort *port);
675 SG_EXTERN SgObject Sg_PortFile(SgPort *port);
676 
677 /* for user defined port */
678 SG_EXTERN int      Sg_AddPortCleanup(SgPort *port);
679 
680 /* misc */
681 SG_EXTERN int      Sg_PortCaseInsensitiveP(SgPort *port);
682 SG_EXTERN SgObject Sg_ReadLine(SgPort *port, SgEolStyle eolStyle);
683 SG_EXTERN SgObject Sg_ReadbUntil(SgPort *port, SgByteVector *eol);
684 SG_EXTERN void     Sg_DefaultPortPrinter(SgObject obj, SgPort *port,
685 					 SgWriteContext *ctx);
686 
687 
688 SG_CDECL_END
689 
690 #endif /* SAGITTARIUS_PORT_H_ */
691 
692 /*
693   end of file
694   Local Variables:
695   coding: utf-8-unix
696   End:
697 */
698