/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- Scm_Putb
- Scm_Putc
- Scm_Puts
- Scm_Putz
- Scm_Flush
- Scm_Ungetc
- Scm_Peekc
- Scm_Ungetb
- Scm_Peekb
- shift_scratch
- getb_scratch
- getb_ungotten
- Scm_Getb
- getc_scratch
- Scm_Getc
- getz_scratch
- getz_istr
- Scm_Getz
- readline_body
- Scm_ReadLine
- Scm_ByteReady
- Scm_CharReady
- seek_istr
- Scm_PortSeek
1 /*
2 * portapi.c - port common API
3 *
4 * Copyright (c) 2000-2004 Shiro Kawai, All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the authors nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * $Id: portapi.c,v 1.29 2005/10/13 08:14:13 shirok Exp $
34 */
35
36 /* This file is included _twice_ by port.c to define safe- and unsafe-
37 * variant of port common APIs. It is to minimize the overhead of
38 * locking operations.
39 *
40 * The macro SHORTCUT allows 'safe' version to bypass lock/unlock
41 * stuff by calling 'unsafe' version when the port is already locked by
42 * the calling thread.
43 */
44
45 /* [scratch and ungottern buffer]
46 * It is always possible to mix binary and character i/o for Gauche's
47 * ports. To support peek operations in Scheme and 'unget' operations
48 * in C, we need to buffer at most one character or its equivalent
49 * byte sequence. The 'ungotten' and 'scratch' fields are used for
50 * character and binary buffering, respectively.
51 * (This level of buffering is common to all input port types, and
52 * distinct from the buffering of 'buffered' (file) port type.)
53 *
54 * 'Ungotten' field keeps SCM_CHAR_INVALID if there's no buffered
55 * character. Otherwise, its value is the buffered character.
56 * The number of bytes in the 'scratch' array is kept in 'scrcnt'
57 * field. If 'scrcnt' field is not zero, there's data in the
58 * 'scratch' array.
59 *
60 * In no cases there should be data in both ungotten and scratch
61 * field. The consistency is taken care of the routines defined here;
62 * no other routine should touch these buffering field.
63 */
64
65 #ifdef SAFE_PORT_OP
66 #define VMDECL ScmVM *vm = Scm_VM()
67 #define LOCK(p) PORT_LOCK(p, vm)
68 #define UNLOCK(p) PORT_UNLOCK(p)
69 #define SAFE_CALL(p, exp) PORT_SAFE_CALL(p, exp)
70 #define SHORTCUT(p, unsafe) \
71 do { if (PORT_LOCKED(p, vm)) { unsafe; }} while (0)
72 #else
73 #define VMDECL /*none*/
74 #define LOCK(p) /*none*/
75 #define UNLOCK(p) /*none*/
76 #define SAFE_CALL(p, exp) (exp)
77 #define SHORTCUT(p, unsafe) /* none */
78 #endif
79
80
81 /* Convenience macro */
82 #ifndef CLOSE_CHECK
83 #define CLOSE_CHECK(port) \
84 do { \
85 if (SCM_PORT_CLOSED_P(port)) { \
86 UNLOCK(p); \
87 Scm_PortError((port), SCM_PORT_ERROR_CLOSED, \
88 "I/O attempted on closed port: %S", (port)); \
89 } \
90 } while (0)
91 #endif /* CLOSE_CHECK */
92
93 /*=================================================================
94 * Putb
95 */
96
97 #ifdef SAFE_PORT_OP
98 void Scm_Putb(ScmByte b, ScmPort *p)
99 #else
100 void Scm_PutbUnsafe(ScmByte b, ScmPort *p)
101 #endif
102 {
103 VMDECL;
104 SHORTCUT(p, Scm_PutbUnsafe(b, p); return);
105 LOCK(p);
106 CLOSE_CHECK(p);
107
108 switch (SCM_PORT_TYPE(p)) {
109 case SCM_PORT_FILE:
110 if (p->src.buf.current >= p->src.buf.end) {
111 SAFE_CALL(p, bufport_flush(p, p->src.buf.current - p->src.buf.buffer, FALSE));
112 }
113 SCM_ASSERT(p->src.buf.current < p->src.buf.end);
114 *p->src.buf.current++ = b;
115 if (p->src.buf.mode == SCM_PORT_BUFFER_NONE) {
116 SAFE_CALL(p, bufport_flush(p, 1, FALSE));
117 }
118 UNLOCK(p);
119 break;
120 case SCM_PORT_OSTR:
121 SCM_DSTRING_PUTB(&p->src.ostr, b);
122 UNLOCK(p);
123 break;
124 case SCM_PORT_PROC:
125 SAFE_CALL(p, p->src.vt.Putb(b, p));
126 UNLOCK(p);
127 break;
128 default:
129 UNLOCK(p);
130 Scm_PortError(p, SCM_PORT_ERROR_OUTPUT,
131 "bad port type for output: %S", p);
132 }
133 }
134
135 /*=================================================================
136 * Putc
137 */
138
139 #ifdef SAFE_PORT_OP
140 void Scm_Putc(ScmChar c, ScmPort *p)
141 #else
142 void Scm_PutcUnsafe(ScmChar c, ScmPort *p)
143 #endif
144 {
145 int nb;
146 VMDECL;
147 SHORTCUT(p, Scm_PutcUnsafe(c, p); return);
148 LOCK(p);
149 CLOSE_CHECK(p);
150
151 switch (SCM_PORT_TYPE(p)) {
152 case SCM_PORT_FILE:
153 nb = SCM_CHAR_NBYTES(c);
154 if (p->src.buf.current+nb > p->src.buf.end) {
155 SAFE_CALL(p, bufport_flush(p, p->src.buf.current - p->src.buf.buffer, FALSE));
156 }
157 SCM_ASSERT(p->src.buf.current+nb <= p->src.buf.end);
158 SCM_CHAR_PUT(p->src.buf.current, c);
159 p->src.buf.current += nb;
160 if (p->src.buf.mode == SCM_PORT_BUFFER_LINE) {
161 if (c == '\n') {
162 SAFE_CALL(p, bufport_flush(p, nb, FALSE));
163 }
164 } else if (p->src.buf.mode == SCM_PORT_BUFFER_NONE) {
165 SAFE_CALL(p, bufport_flush(p, nb, FALSE));
166 }
167 UNLOCK(p);
168 break;
169 case SCM_PORT_OSTR:
170 SCM_DSTRING_PUTC(&p->src.ostr, c);
171 UNLOCK(p);
172 break;
173 case SCM_PORT_PROC:
174 PORT_SAFE_CALL(p, p->src.vt.Putc(c, p));
175 UNLOCK(p);
176 break;
177 default:
178 UNLOCK(p);
179 Scm_PortError(p, SCM_PORT_ERROR_OUTPUT,
180 "bad port type for output: %S", p);
181 }
182 }
183
184 /*=================================================================
185 * Puts
186 */
187
188 #ifdef SAFE_PORT_OP
189 void Scm_Puts(ScmString *s, ScmPort *p)
190 #else
191 void Scm_PutsUnsafe(ScmString *s, ScmPort *p)
192 #endif
193 {
194 VMDECL;
195 SHORTCUT(p, Scm_PutsUnsafe(s, p); return);
196 LOCK(p);
197 CLOSE_CHECK(p);
198
199 switch (SCM_PORT_TYPE(p)) {
200 case SCM_PORT_FILE: {
201 u_int size;
202 const char *ss = Scm_GetStringContent(s, &size, NULL, NULL);
203 SAFE_CALL(p, bufport_write(p, ss, size));
204
205 if (p->src.buf.mode == SCM_PORT_BUFFER_LINE) {
206 const char *cp = p->src.buf.current;
207 while (cp-- > p->src.buf.buffer) {
208 if (*cp == '\n') {
209 SAFE_CALL(p, bufport_flush(p, (int)(cp - p->src.buf.current), FALSE));
210 break;
211 }
212 }
213 } else if (p->src.buf.mode == SCM_PORT_BUFFER_NONE) {
214 SAFE_CALL(p, bufport_flush(p, 0, TRUE));
215 }
216 UNLOCK(p);
217 break;
218 }
219 case SCM_PORT_OSTR:
220 Scm_DStringAdd(&p->src.ostr, s);
221 UNLOCK(p);
222 break;
223 case SCM_PORT_PROC:
224 SAFE_CALL(p, p->src.vt.Puts(s, p));
225 UNLOCK(p);
226 break;
227 default:
228 UNLOCK(p);
229 Scm_PortError(p, SCM_PORT_ERROR_OUTPUT,
230 "bad port type for output: %S", p);
231 }
232 }
233
234 /*=================================================================
235 * Putz
236 */
237
238 #ifdef SAFE_PORT_OP
239 void Scm_Putz(const char *s, int siz, ScmPort *p)
240 #else
241 void Scm_PutzUnsafe(const char *s, int siz, ScmPort *p)
242 #endif
243 {
244 VMDECL;
245 SHORTCUT(p, Scm_PutzUnsafe(s, siz, p); return);
246 LOCK(p);
247 CLOSE_CHECK(p);
248 if (siz < 0) siz = strlen(s);
249 switch (SCM_PORT_TYPE(p)) {
250 case SCM_PORT_FILE:
251 SAFE_CALL(p, bufport_write(p, s, siz));
252 if (p->src.buf.mode == SCM_PORT_BUFFER_LINE) {
253 const char *cp = p->src.buf.current;
254 while (cp-- > p->src.buf.buffer) {
255 if (*cp == '\n') {
256 SAFE_CALL(p, bufport_flush(p, (int)(cp - p->src.buf.current), FALSE));
257 break;
258 }
259 }
260 } else if (p->src.buf.mode == SCM_PORT_BUFFER_NONE) {
261 SAFE_CALL(p, bufport_flush(p, 0, TRUE));
262 }
263 UNLOCK(p);
264 break;
265 case SCM_PORT_OSTR:
266 Scm_DStringPutz(&p->src.ostr, s, siz);
267 UNLOCK(p);
268 break;
269 case SCM_PORT_PROC:
270 SAFE_CALL(p, p->src.vt.Putz(s, siz, p));
271 UNLOCK(p);
272 break;
273 default:
274 UNLOCK(p);
275 Scm_PortError(p, SCM_PORT_ERROR_OUTPUT,
276 "bad port type for output: %S", p);
277 }
278 }
279
280 /*=================================================================
281 * Flush
282 */
283
284 #ifdef SAFE_PORT_OP
285 void Scm_Flush(ScmPort *p)
286 #else
287 void Scm_FlushUnsafe(ScmPort *p)
288 #endif
289 {
290 VMDECL;
291 SHORTCUT(p, Scm_FlushUnsafe(p); return);
292 LOCK(p);
293 CLOSE_CHECK(p);
294 switch (SCM_PORT_TYPE(p)) {
295 case SCM_PORT_FILE:
296 SAFE_CALL(p, bufport_flush(p, 0, TRUE));
297 UNLOCK(p);
298 break;
299 case SCM_PORT_OSTR:
300 UNLOCK(p);
301 break;
302 case SCM_PORT_PROC:
303 SAFE_CALL(p, p->src.vt.Flush(p));
304 UNLOCK(p);
305 break;
306 default:
307 UNLOCK(p);
308 Scm_PortError(p, SCM_PORT_ERROR_OUTPUT,
309 "bad port type for output: %S", p);
310 }
311 }
312
313 /*=================================================================
314 * Ungetc & PeekChar
315 */
316
317 #ifdef SAFE_PORT_OP
318 void Scm_Ungetc(ScmChar c, ScmPort *p)
319 #else
320 void Scm_UngetcUnsafe(ScmChar c, ScmPort *p)
321 #endif
322 {
323 VMDECL;
324 SHORTCUT(p, Scm_UngetcUnsafe(c, p); return);
325 LOCK(p);
326 if (p->ungotten != SCM_CHAR_INVALID
327 || p->scrcnt != 0) {
328 Scm_PortError(p, SCM_PORT_ERROR_INPUT,
329 "pushback buffer overflow on port %S", p);
330 }
331 p->ungotten = c;
332 UNLOCK(p);
333 }
334
335 #ifdef SAFE_PORT_OP
336 ScmChar Scm_Peekc(ScmPort *p)
337 #else
338 ScmChar Scm_PeekcUnsafe(ScmPort *p)
339 #endif
340 {
341 ScmChar ch;
342 VMDECL;
343 SHORTCUT(p, return Scm_PeekcUnsafe(p));
344 LOCK(p);
345 if ((ch = p->ungotten) == SCM_CHAR_INVALID) {
346 ch = Scm_GetcUnsafe(p);
347 p->ungotten = ch;
348 }
349 UNLOCK(p);
350 return ch;
351 }
352
353 /*=================================================================
354 * Ungetb & PeekByte
355 */
356
357 #ifdef SAFE_PORT_OP
358 void Scm_Ungetb(int b, ScmPort *p)
359 #else
360 void Scm_UngetbUnsafe(int b, ScmPort *p)
361 #endif
362 {
363 VMDECL;
364 SHORTCUT(p, Scm_UngetbUnsafe(b, p); return);
365 LOCK(p);
366 if (p->ungotten != SCM_CHAR_INVALID
367 || p->scrcnt >= SCM_CHAR_MAX_BYTES) {
368 Scm_PortError(p, SCM_PORT_ERROR_INPUT,
369 "pushback buffer overflow on port %S", p);
370 }
371 p->scratch[p->scrcnt++] = b;
372 UNLOCK(p);
373 }
374
375 #ifdef SAFE_PORT_OP
376 int Scm_Peekb(ScmPort *p)
377 #else
378 int Scm_PeekbUnsafe(ScmPort *p)
379 #endif
380 {
381 int b;
382 VMDECL;
383 SHORTCUT(p, return Scm_PeekbUnsafe(p));
384 LOCK(p);
385 if (p->scrcnt > 0) {
386 b = (unsigned char)p->scratch[0];
387 } else {
388 SCM_GETB(b, p);
389 if (b >= 0) {
390 if (p->scrcnt > 0) {
391 /* unshift scratch buffer */
392 int i;
393 SCM_ASSERT(p->scrcnt < SCM_CHAR_MAX_BYTES);
394 for (i=p->scrcnt; i>0; i--) {
395 p->scratch[i] = p->scratch[i-1];
396 }
397 p->scratch[0] = b;
398 p->scrcnt++;
399 } else {
400 p->scratch[0] = b;
401 p->scrcnt = 1;
402 }
403 }
404 }
405 UNLOCK(p);
406 return b;
407 }
408
409 /*=================================================================
410 * Getb
411 */
412
413 #ifndef SHIFT_SCRATCH /* we need to define this only once */
414 #define SHIFT_SCRATCH
415
416 /* shift scratch buffer content */
417 static inline void shift_scratch(ScmPort *p, int off)
418 {
419 int i;
420 for (i=0; i<p->scrcnt; i++) {
421 p->scratch[i] = p->scratch[i+off];
422 }
423 }
424
425 /* handle the case that there's remaining data in the scratch buffer */
426 static int getb_scratch(ScmPort *p)
427 {
428 int b = (unsigned char)p->scratch[0];
429 p->scrcnt--;
430 shift_scratch(p, 1);
431 return b;
432 }
433
434 /* handle the case that there's an ungotten char */
435 static int getb_ungotten(ScmPort *p)
436 {
437 SCM_CHAR_PUT(p->scratch, p->ungotten);
438 p->scrcnt = SCM_CHAR_NBYTES(p->ungotten);
439 p->ungotten = SCM_CHAR_INVALID;
440 return getb_scratch(p);
441 }
442 #endif /*SHIFT_SCRATCH*/
443
444 /* Getb body */
445 #ifdef SAFE_PORT_OP
446 int Scm_Getb(ScmPort *p)
447 #else
448 int Scm_GetbUnsafe(ScmPort *p)
449 #endif
450 {
451 int b = 0, r = 0;
452 VMDECL;
453 SHORTCUT(p, return Scm_GetbUnsafe(p));
454 LOCK(p);
455 CLOSE_CHECK(p);
456
457 /* check if there's "pushed back" stuff */
458 if (p->scrcnt) {
459 b = getb_scratch(p);
460 } else if (p->ungotten != SCM_CHAR_INVALID) {
461 b = getb_ungotten(p);
462 } else {
463 switch (SCM_PORT_TYPE(p)) {
464 case SCM_PORT_FILE:
465 if (p->src.buf.current >= p->src.buf.end) {
466 SAFE_CALL(p, r = bufport_fill(p, 1, FALSE));
467 if (r == 0) {
468 UNLOCK(p);
469 return EOF;
470 }
471 }
472 b = (unsigned char)*p->src.buf.current++;
473 break;
474 case SCM_PORT_ISTR:
475 if (p->src.istr.current >= p->src.istr.end) b = EOF;
476 else b = (unsigned char)*p->src.istr.current++;
477 break;
478 case SCM_PORT_PROC:
479 SAFE_CALL(p, b = p->src.vt.Getb(p));
480 break;
481 default:
482 UNLOCK(p);
483 Scm_PortError(p, SCM_PORT_ERROR_INPUT,
484 "bad port type for input: %S", p);
485 }
486 }
487 UNLOCK(p);
488 return b;
489 }
490
491 /*=================================================================
492 * Getc
493 */
494
495 /* handle the case that there's data in scratch area */
496 #ifdef SAFE_PORT_OP
497 #define GETC_SCRATCH getc_scratch
498 static int getc_scratch(ScmPort *p)
499 #else
500 #define GETC_SCRATCH getc_scratch_unsafe
501 static int getc_scratch_unsafe(ScmPort *p)
502 #endif
503 {
504 char tbuf[SCM_CHAR_MAX_BYTES];
505 int nb = SCM_CHAR_NFOLLOWS(p->scratch[0]), ch, i, curr = p->scrcnt;
506 int r = 0;
507
508 memcpy(tbuf, p->scratch, curr);
509 p->scrcnt = 0;
510 for (i=curr; i<=nb; i++) {
511 SAFE_CALL(p, r = Scm_Getb(p));
512 if (r == EOF) {
513 UNLOCK(p);
514 Scm_PortError(p, SCM_PORT_ERROR_INPUT,
515 "encountered EOF in middle of a multibyte character from port %S", p);
516 }
517 tbuf[i] = (char)r;
518 }
519 SCM_CHAR_GET(tbuf, ch);
520 return ch;
521 }
522
523 /* Getc body */
524 #ifdef SAFE_PORT_OP
525 int Scm_Getc(ScmPort *p)
526 #else
527 int Scm_GetcUnsafe(ScmPort *p)
528 #endif
529 {
530 int first, nb, c = 0, r = 0;
531 VMDECL;
532 SHORTCUT(p, return Scm_GetcUnsafe(p));
533 LOCK(p);
534 CLOSE_CHECK(p);
535 if (p->scrcnt > 0) {
536 r = GETC_SCRATCH(p);
537 UNLOCK(p);
538 return r;
539 }
540 if (p->ungotten != SCM_CHAR_INVALID) {
541 c = p->ungotten;
542 p->ungotten = SCM_CHAR_INVALID;
543 UNLOCK(p);
544 return c;
545 }
546
547 switch (SCM_PORT_TYPE(p)) {
548 case SCM_PORT_FILE:
549 if (p->src.buf.current >= p->src.buf.end) {
550 SAFE_CALL(p, r = bufport_fill(p, 1, FALSE));
551 if (r == 0) {
552 UNLOCK(p);
553 return EOF;
554 }
555 }
556 first = (unsigned char)*p->src.buf.current++;
557 nb = SCM_CHAR_NFOLLOWS(first);
558 if (nb > 0) {
559 if (p->src.buf.current + nb > p->src.buf.end) {
560 /* The buffer doesn't have enough bytes to consist a char.
561 move the incomplete char to the scratch buffer and try
562 to fetch the rest of the char. */
563 int rest, filled = 0;
564 p->scrcnt = (unsigned char)(p->src.buf.end - p->src.buf.current + 1);
565 memcpy(p->scratch, p->src.buf.current-1, p->scrcnt);
566 p->src.buf.current = p->src.buf.end;
567 rest = nb + 1 - p->scrcnt;
568 for (;;) {
569 SAFE_CALL(p, filled = bufport_fill(p, rest, FALSE));
570 if (filled <= 0) {
571 /* TODO: make this behavior customizable */
572 UNLOCK(p);
573 Scm_PortError(p, SCM_PORT_ERROR_INPUT,
574 "encountered EOF in middle of a multibyte character from port %S", p);
575 }
576 if (filled >= rest) {
577 memcpy(p->scratch+p->scrcnt, p->src.buf.current, rest);
578 p->scrcnt += rest;
579 p->src.buf.current += rest;
580 break;
581 } else {
582 memcpy(p->scratch+p->scrcnt, p->src.buf.current, filled);
583 p->scrcnt += filled;
584 p->src.buf.current = p->src.buf.end;
585 rest -= filled;
586 }
587 }
588 SCM_CHAR_GET(p->scratch, c);
589 p->scrcnt = 0;
590 } else {
591 SCM_CHAR_GET(p->src.buf.current-1, c);
592 p->src.buf.current += nb;
593 }
594 } else {
595 c = first;
596 if (c == '\n') p->line++;
597 }
598 UNLOCK(p);
599 return c;
600 case SCM_PORT_ISTR:
601 if (p->src.istr.current >= p->src.istr.end) {
602 UNLOCK(p);
603 return EOF;
604 }
605 first = (unsigned char)*p->src.istr.current++;
606 nb = SCM_CHAR_NFOLLOWS(first);
607 if (nb > 0) {
608 if (p->src.istr.current + nb > p->src.istr.end) {
609 /* TODO: make this behavior customizable */
610 UNLOCK(p);
611 Scm_PortError(p, SCM_PORT_ERROR_INPUT,
612 "encountered EOF in middle of a multibyte character from port %S", p);
613 }
614 SCM_CHAR_GET(p->src.istr.current-1, c);
615 p->src.istr.current += nb;
616 } else {
617 c = first;
618 if (c == '\n') p->line++;
619 }
620 UNLOCK(p);
621 return c;
622 case SCM_PORT_PROC:
623 SAFE_CALL(p, c = p->src.vt.Getc(p));
624 if (c == '\n') p->line++;
625 UNLOCK(p);
626 return c;
627 default:
628 UNLOCK(p);
629 Scm_PortError(p, SCM_PORT_ERROR_INPUT,
630 "bad port type for input: %S", p);
631 }
632 return 0;/*dummy*/
633 }
634
635 #undef GETC_SCRATCH
636
637 /*=================================================================
638 * Getz - block read.
639 * If the buffering mode is BUFFER_FULL, this reads BUFLEN bytes
640 * unless it reaches EOF. Otherwise, this reads less than BUFLEN
641 * if the data is not immediately available.
642 */
643
644 #ifdef SAFE_PORT_OP
645 #define GETZ_SCRATCH getz_scratch
646 static int getz_scratch(char *buf, int buflen, ScmPort *p)
647 #else
648 #define GETZ_SCRATCH getz_scratch_unsafe
649 static int getz_scratch_unsafe(char *buf, int buflen, ScmPort *p)
650 #endif
651 {
652 int i, n = 0;
653 if (p->scrcnt >= buflen) {
654 memcpy(buf, p->scratch, buflen);
655 p->scrcnt -= buflen;
656 shift_scratch(p, buflen);
657 return buflen;
658 } else {
659 memcpy(buf, p->scratch, p->scrcnt);
660 i = p->scrcnt;
661 p->scrcnt = 0;
662 SAFE_CALL(p, n = Scm_Getz(buf+i, buflen-i, p));
663 return i + n;
664 }
665 }
666
667 #ifndef GETZ_ISTR /* common part */
668 #define GETZ_ISTR getz_istr
669 static int getz_istr(ScmPort *p, char *buf, int buflen)
670 {
671 int siz;
672 if (p->src.istr.current + buflen >= p->src.istr.end) {
673 if (p->src.istr.current >= p->src.istr.end) return EOF;
674 siz = (int)(p->src.istr.end - p->src.istr.current);
675 memcpy(buf, p->src.istr.current, siz);
676 p->src.istr.current = p->src.istr.end;
677 return siz;
678 } else {
679 memcpy(buf, p->src.istr.current, buflen);
680 p->src.istr.current += buflen;
681 return buflen;
682 }
683 }
684 #endif /*!GETZ_ISTR*/
685
686 #ifdef SAFE_PORT_OP
687 int Scm_Getz(char *buf, int buflen, ScmPort *p)
688 #else
689 int Scm_GetzUnsafe(char *buf, int buflen, ScmPort *p)
690 #endif
691 {
692 int siz = 0, r = 0;
693 VMDECL;
694 SHORTCUT(p, return Scm_GetzUnsafe(buf, buflen, p));
695 LOCK(p);
696 CLOSE_CHECK(p);
697
698 if (p->scrcnt) {
699 r = GETZ_SCRATCH(buf, buflen, p);
700 UNLOCK(p);
701 return r;
702 }
703 if (p->ungotten != SCM_CHAR_INVALID) {
704 p->scrcnt = SCM_CHAR_NBYTES(p->ungotten);
705 SCM_CHAR_PUT(p->scratch, p->ungotten);
706 p->ungotten = SCM_CHAR_INVALID;
707 r = GETZ_SCRATCH(buf, buflen, p);
708 UNLOCK(p);
709 return r;
710 }
711
712 switch (SCM_PORT_TYPE(p)) {
713 case SCM_PORT_FILE:
714 SAFE_CALL(p, siz = bufport_read(p, buf, buflen));
715 UNLOCK(p);
716 if (siz == 0) return EOF;
717 else return siz;
718 case SCM_PORT_ISTR:
719 r = GETZ_ISTR(p, buf, buflen);
720 UNLOCK(p);
721 return r;
722 case SCM_PORT_PROC:
723 SAFE_CALL(p, r = p->src.vt.Getz(buf, buflen, p));
724 UNLOCK(p);
725 return r;
726 default:
727 UNLOCK(p);
728 Scm_PortError(p, SCM_PORT_ERROR_INPUT,
729 "bad port type for input: %S", p);
730 }
731 return -1; /* dummy */
732 }
733
734 #undef GETZ_SCRATCH
735
736 /*=================================================================
737 * ReadLine
738 * Reads up to EOL or EOF.
739 */
740
741 /* Auxiliary procedures */
742
743 /* NB: it may be further optimized by scanning the contents of buffer
744 when the port is a buffered port or an input string, which allows
745 us to avoid mb->wc->mb conversion. See port.c, v 1.69 for some
746 attempt to do so. The problem there is that if I have to take
747 into account the cases of the ungotten char and the scratch buffer,
748 code becomes ugly. There might be some better approach. */
749
750 #ifndef READLINE_AUX
751 #define READLINE_AUX
752 /* Assumes the port is locked, and the caller takes care of unlocking
753 even if an error is signalled within this body */
754 /* NB: this routine reads bytes, not chars. It allows to readline
755 from a port in unknown character encoding (e.g. reading the first
756 line of xml doc to find out charset parameter). */
757 ScmObj readline_body(ScmPort *p)
758 {
759 int b1 = 0, b2 = 0;
760 ScmDString ds;
761
762 Scm_DStringInit(&ds);
763 b1 = Scm_GetbUnsafe(p);
764 if (b1 == EOF) return SCM_EOF;
765 for (;;) {
766 if (b1 == EOF) return Scm_DStringGet(&ds, 0);
767 if (b1 == '\n') break;
768 if (b1 == '\r') {
769 b2 = Scm_GetbUnsafe(p);
770 if (b2 == EOF || b2 == '\n') break;
771 Scm_UngetbUnsafe(b2, p);
772 break;
773 }
774 SCM_DSTRING_PUTB(&ds, b1);
775 b1 = Scm_GetbUnsafe(p);
776 }
777 p->line++;
778 return Scm_DStringGet(&ds, 0);
779 }
780 #endif /* READLINE_AUX */
781
782 #ifdef SAFE_PORT_OP
783 ScmObj Scm_ReadLine(ScmPort *p)
784 #else
785 ScmObj Scm_ReadLineUnsafe(ScmPort *p)
786 #endif
787 {
788 ScmObj r = SCM_UNDEFINED;
789 VMDECL;
790 SHORTCUT(p, return Scm_ReadLineUnsafe(p));
791
792 LOCK(p);
793 SAFE_CALL(p, r = readline_body(p));
794 UNLOCK(p);
795 return r;
796 }
797
798 /*=================================================================
799 * ByteReady
800 */
801
802 #ifdef SAFE_PORT_OP
803 int Scm_ByteReady(ScmPort *p)
804 #else
805 int Scm_ByteReadyUnsafe(ScmPort *p)
806 #endif
807 {
808 int r = 0;
809 VMDECL;
810 SHORTCUT(p, return Scm_ByteReadyUnsafe(p));
811 if (!SCM_IPORTP(p)) Scm_Error("input port required, but got %S", p);
812 LOCK(p);
813 if (p->ungotten != SCM_CHAR_INVALID
814 || p->scrcnt > 0) {
815 r = TRUE;
816 } else {
817 switch (SCM_PORT_TYPE(p)) {
818 case SCM_PORT_FILE:
819 if (p->src.buf.current < p->src.buf.end) r = TRUE;
820 else if (p->src.buf.ready == NULL) r = TRUE;
821 else {
822 SAFE_CALL(p, r = (p->src.buf.ready(p) != SCM_FD_WOULDBLOCK));
823 }
824 break;
825 case SCM_PORT_PROC:
826 SAFE_CALL(p, r = p->src.vt.Ready(p, FALSE));
827 break;
828 default:
829 r = TRUE;
830 }
831 }
832 UNLOCK(p);
833 return r;
834 }
835
836 /*=================================================================
837 * CharReady
838 */
839
840 #ifdef SAFE_PORT_OP
841 int Scm_CharReady(ScmPort *p)
842 #else
843 int Scm_CharReadyUnsafe(ScmPort *p)
844 #endif
845 {
846 int r = 0;
847 VMDECL;
848 SHORTCUT(p, return Scm_CharReadyUnsafe(p));
849 if (!SCM_IPORTP(p)) Scm_Error("input port required, but got %S", p);
850 LOCK(p);
851 if (p->ungotten != SCM_CHAR_INVALID) r = TRUE;
852 else {
853 switch (SCM_PORT_TYPE(p)) {
854 case SCM_PORT_FILE:
855 if (p->src.buf.current < p->src.buf.end) r = TRUE;
856 else if (p->src.buf.ready == NULL) r = TRUE;
857 else {
858 SAFE_CALL(p, r = (p->src.buf.ready(p) != SCM_FD_WOULDBLOCK));
859 }
860 break;
861 case SCM_PORT_PROC:
862 SAFE_CALL(p, r = p->src.vt.Ready(p, TRUE));
863 break;
864 default:
865 r = TRUE;
866 }
867 }
868 UNLOCK(p);
869 return r;
870 }
871
872 /*=================================================================
873 * PortSeek
874 */
875
876 #ifndef SEEK_ISTR /* common part */
877 #define SEEK_ISTR seek_istr
878 static off_t seek_istr(ScmPort *p, off_t o, int whence, int nomove)
879 {
880 off_t r;
881 if (nomove) {
882 r = (off_t)(p->src.istr.current - p->src.istr.start);
883 } else {
884 long z = (long)o;
885 if (whence == SEEK_CUR) {
886 z += (long)(p->src.istr.current - p->src.istr.start);
887 } else if (whence == SEEK_END) {
888 z += (long)(p->src.istr.end - p->src.istr.start);
889 }
890 if (z < 0 || z > (long)(p->src.istr.end - p->src.istr.start)) {
891 r = (off_t)-1;
892 } else {
893 p->src.istr.current = p->src.istr.start + z;
894 r = (off_t)(p->src.istr.current - p->src.istr.start);
895 }
896 p->ungotten = SCM_CHAR_INVALID;
897 }
898 return r;
899 }
900 #endif /*SEEK_ISTR*/
901
902 #ifdef SAFE_PORT_OP
903 ScmObj Scm_PortSeek(ScmPort *p, ScmObj off, int whence)
904 #else
905 ScmObj Scm_PortSeekUnsafe(ScmPort *p, ScmObj off, int whence)
906 #endif
907 {
908 off_t r = (off_t)-1, o = Scm_IntegerToOffset(off);
909 int nomove = (whence == SEEK_CUR && o == 0);
910 VMDECL;
911 SHORTCUT(p, return Scm_PortSeekUnsafe(p, off, whence));
912 if (SCM_PORT_CLOSED_P(p)) {
913 Scm_PortError(p, SCM_PORT_ERROR_CLOSED,
914 "attempt to seek on closed port: %S", p);
915 }
916 LOCK(p);
917 switch (SCM_PORT_TYPE(p)) {
918 case SCM_PORT_FILE:
919 /* NB: we might be able to skip calling seeker if we keep the
920 # of bytes read or write so far, but such count may be off
921 when the port has been experienced an error condition. */
922 /* NB: the following doesn't work if we have bidirectional port.
923 In such case we need to keep whether the last call of buffer
924 handling routine was input or output. */
925 if (!p->src.buf.seeker) break;
926 if (nomove) {
927 SAFE_CALL(p, r = p->src.buf.seeker(p, 0, SEEK_CUR));
928 if (SCM_PORT_DIR(p)&SCM_PORT_INPUT) {
929 r -= (off_t)(p->src.buf.end - p->src.buf.current);
930 } else {
931 r += (off_t)(p->src.buf.current - p->src.buf.buffer);
932 }
933 } else {
934 /* NB: possible optimization: the specified position is within
935 the current buffer, we can avoid calling seeker. */
936 if (SCM_PORT_DIR(p)&SCM_PORT_INPUT) {
937 if (whence == SEEK_CUR) {
938 o -= (off_t)(p->src.buf.end - p->src.buf.current);
939 }
940 p->src.buf.current = p->src.buf.end; /* invalidate buffer */
941 SAFE_CALL(p, r = p->src.buf.seeker(p, o, whence));
942 } else {
943 SAFE_CALL(p, bufport_flush(p, 0, TRUE));
944 SAFE_CALL(p, r = p->src.buf.seeker(p, o, whence));
945 }
946 /* Invalidate ungotten char */
947 p->ungotten = SCM_CHAR_INVALID;
948 }
949 break;
950 case SCM_PORT_ISTR:
951 r = SEEK_ISTR(p, o, whence, nomove);
952 break;
953 case SCM_PORT_OSTR:
954 if (nomove) {
955 r = (off_t)Scm_DStringSize(&(p->src.ostr));
956 } else {
957 /* Not supported yet */
958 r = (off_t)-1;
959 }
960 break;
961 case SCM_PORT_PROC:
962 if (p->src.vt.Seek) {
963 SAFE_CALL(p, r = p->src.vt.Seek(p, o, whence));
964 }
965 break;
966 }
967 UNLOCK(p);
968 if (r == (off_t)-1) return SCM_FALSE;
969 else return Scm_OffsetToInteger(r);
970 }
971
972 #undef VMDECL
973 #undef LOCK
974 #undef UNLOCK
975 #undef SAFE_CALL
976 #undef SHORTCUT
977 #undef CLOSE_CHECK
978