|Allegro CL version 8.1|
Unrevised from 8.0 to 8.1.
Arguments: stream eof-error-p eof-value &optional given-string
This function implements read-line for simple-streams. In addition, it allows an optional string as a buffer into which to store characters being read. Unless an EOF is encountered immediately, in which case an error is signaled or eof-value is returned, the first return value is a string. If the given-string is supplied but is too small to hold the whole line, a new string of the exact size needed is allocated and returned. (If a new string is allocated, the contents of a provided given-string when this function returns are undefined -- they will likely have been changed in anticipation of the string being used.)
Two values are always returned (following the behavior of read-line) and a third value is sometimes returned. The first two return values are:
nil, if the line was terminated with a newline; and
tif the line was not terminated with a newline (that is, the end of file was reached).
A third value is returned when given-string is large enough to hold the line read. (No third value is returned when given-string is not supplied or when given-string is too small). The third value is:
Since you do not typically know in advance whether the given-string or a new string is returned, the number of characters read (not counting the newline) is the value of
(or end (length string)) ;; END is the third return value, STRING the first
given-string may be simple or non-simple, but must be a string. The other arguments are as for read-line (note there is no recursive-p argument and stream, eof-error-p, and eof-value are required, not optional).
The motivation for this function is twofold: to provide a direct implementation for read-line for simple-streams, and to provide a tradeoff for consing between that of read-line and that of excl:read-line-into (excl:read-line-into does no consing but requires more bookkeeping). If the supplied string is large enough, then most of the time consing will not occur, but for the occasional larger-than-expected line, the allocation of a string is automatic.
See also read-line-into. That function is more space efficient than this one, but has a more complicated interface.
;; Assume the file myfile.txt contains (no trailing spaces): 12345 12345678901234567890 123456789 1234567890 123456789012345 ;; That is 6 lines or lengths 5, 0, 20, 9, 10, 15, 0, not counting ;; the newlines. ;; ;; We read the file one line at a time: (with-open-file (f "myfile.txt" :direction :input) (let (res stopped end (given-string (make-string 10 :initial-element #\a))) (block around (loop (multiple-value-setq (res stopped end) (simple-stream-read-line f nil f give-string) (if (eq res f) (return-from around)) (format t " res is ~S, eq to given-string ~S~% ~ length ~D, given-string is ~S~%" res (eq res given-string) (or end (length res)) given-string)))))) "12345aaaaa" t 5 "12345aaaaa" "12345aaaa" t 0 "12345aaaaa" "12345678901234567890" nil 20 "1234567890" ;; actual value of given-string may be different "1234567890" t 9 "1234567890" ;; GIVEN-STRING is used "1234567890" nil ;; GIVEN-STRING not used, see below 10 "1234567890" "123456789012345" nil 15 "1234567890" nil ;; One trick is, when a new string is allocated, use that string ;; as the given-string from then on. (It already exists, so no ;; extra allocation and it is bigger so more likely not to overflow.) ;; Here is the same example with using any newly allocated string: (with-open-file (f "myfile.txt" :direction :input) (let (res stopped end (given-string (make-string 10 :initial-element #\a))) (block around (loop (multiple-value-setq (res stopped end) (simple-stream-read-line f nil f give-string) (if (eq res f) (return-from around)) (format t " res is ~S, eq to given-string ~S~% ~ length ~D, given-string is ~S~%" res (eq res given-string) (or end (length res)) given-string) (unless end (setq given-string res)) ))))) "12345aaaaa" t 5 "12345aaaaa" "12345aaaa" t 0 "12345aaaaa" "12345678901234567890" nil 20 "1234567890" ;; actual value of given-string may be different "12345678901234567890" t 9 "12345678901234567890" ;; Note: given-string is now last returned string "12345678901234567890" t 10 "12345678901234567890" "12345678901234567890" t 15 "12345678901234567890" nil
The examples above include a case where the line has 10 characters, and the given-string is length 10 but it is not used. Instead, a new string of length 10 is allocated. Why is the given-string insufficient? The problem is that the most efficient time to allocate a new string when necessary is to do it when the given-string is full and there is known to be at least one more character to read, but before it is known what that character is. If that additional character turns out to be a newline, then in fact the given-string was big enough but by this time the new string is already allocated.
Therefore, given-string must be larger than the anticipated maximum line length in order that it always be used. (For common external formats, it must be one larger. There may be external formats where more that one extra character is needed.)
This need for a longer given-string than the maximal line length (not counting the newline) is suboptimal behavior, and may be replaced in a future release if an efficient implementation can be discovered. However, as currently implemented, too much extra time would have to be spent in order to determine whether a line is or is not exactly as big as the given-string.
Copyright (c) 1998-2009, Franz Inc. Oakland, CA., USA. All rights reserved.
Documentation for Allegro CL version 8.1. This page was not revised from the 8.0 page.
|Allegro CL version 8.1|
Unrevised from 8.0 to 8.1.