[snip original post]
Here (unless I am persuaded otherwise) is my final take on the
interface. Many thanks to all that commented.
The getfline.h include file defines four things:
(1,2) There are two variables, flags and errno, that replace the
status word (they will be inside a structure.)
They are supported by two enumerated types called gfl_flags and
gfl_errors. These replace the macro definitions. After some
thought I decided that bit fields were a bad idea. The
enumerated types still invade the user space but in a nicer way.
The gfl_flags enum declaration looks like this:
enum gfl_flags {
gfl_clean = 0x1, gfl_eofok = 0x2, gfl_cut = 0x4,
gfl_trunc = 0x8, gfl_omit = 0x20, gfl_exit = 0x40,
gfl_log = 0x80, gfl_nomax = 0x100
};
The gfl_flags type expresses the same values as the corresponding
macros and are to be used in the same way. For example
cb.flags = gfl_eofok | gfl_cut | gfl_log;
The "nomax" flag is an addition. It turns off bounds checking.
The "clean" flag is a replacement for the "TRANS" flag. What is
happening here is that the default is changed to transient
copies. The gfl_errors enum declaration looks like this:
enum gfl_errors {
gfl_ok = 0, gfl_stream, gfl_bufsize, gfl_flags,
gfl_io, gfl_storage, gfl_corrupt
};
The usage is different from before. The errno variable will have
one of these values. Most of the argument errors are no longer
needed. The gfl_corrupt return has been added because it may be
possible for to corrupt the hidden state. The get_ok value for
errno says that was no error; a positive value says that there
was an error.
(3) A structure that looks like this:
struct gfl_cb {
struct gfl_private * pvt;
size_t length;
gfl_errors errno;
size_t maxlen;
int flags;
};
The gfl_private struct is new; it is an opaque pointer to a
struct created by getfline that is used to hold the state data
from one call to the next. The gfl_cb struct does not have to be
used (see prototypes below) but if it is it should be populated
as follows:
struct gfl_cb = {0,0,0,MAXLEN,FLAGS};
where MAXLEN is the maximum line length permitted, and FLAGS is
set as the or of the selected flags. MAXLEN may be 0 if the
nomax flag is selected. Arguments two and three don't need
initializing,; setting them to zero might be good practice.
The pvt pointer must be 0 (NULL) when the first line is
extracted; if it is not bad things may happen. It will be
cleared by getfline after the last line is extracted.
(4,5) Two prototypes that look like this:
char * getfline (FILE * fptr, struct gfl_cb * cb);
int gfl_terminate ( struct gfl_cb * cb);
Getfline is the principle function. If the second argument is
NULL getfline will run in clean copy mode with no bounds check
and will ignore a missing final EOL. It is the appropriate
choice for simple usage. If the second argument is not NULL it
must be correctly initiialized.
Gfl_terminate is there for a special case. Ordinarily getfline
will clean up its private data after the last line is extracted.
However the user may break out of the read loop before the last
line is read. If so, gfl_terminate should be called to clean up
the private data. Failure to do is not fatal; however it will
leak some memory. Return of zero is okay, nonzero is an error.
Example usage:
while (line = getfline(fptr, &cb)) {
... do stuff ...
if (something_happened) {
if (gfl_terminate(cb)) die_horribly();
break;
}
... do other stuff ...
}
Richard Harter, (e-mail address removed)
http://home.tiac.net/~cri,
http://www.varinoma.com
In the fields of Hell where the grass grows high
Are the graves of dreams allowed to die