root/src/portapi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. Scm_Putb
  2. Scm_Putc
  3. Scm_Puts
  4. Scm_Putz
  5. Scm_Flush
  6. Scm_Ungetc
  7. Scm_Peekc
  8. Scm_Ungetb
  9. Scm_Peekb
  10. shift_scratch
  11. getb_scratch
  12. getb_ungotten
  13. Scm_Getb
  14. getc_scratch
  15. Scm_Getc
  16. getz_scratch
  17. getz_istr
  18. Scm_Getz
  19. readline_body
  20. Scm_ReadLine
  21. Scm_ByteReady
  22. Scm_CharReady
  23. seek_istr
  24. 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 

/* [<][>][^][v][top][bottom][index][help] */