From: Ben Bacarisse on
cri(a)tiac.net (Richard Harter) writes:

> On Wed, 7 Nov 2007 11:08:30 +0100, "Charlie Gordon"
> <news(a)chqrlie.org> wrote:
>
>>"Richard Harter" <cri(a)tiac.net> a écrit dans le message de news:
>>4729fd77.329292093(a)news.sbtc.net...
>>>
>><snipped long interesting discussion>
>>>
>>> Finally, what should the interface look like? I now believe that
>>> the prototype should look like this:
>>>
>>> int getfline(FILE * fptr,
>>> char ** line_ptr,
>>> long * status,
>>> size_t * length_ptr,
>>> size_t maxlen);
>>>
<snip>
>>- the return value could be more informative: we could make it an ssize_t to
>>return the length of the line read or EOF upon end of file. It would also
>>be more intuitive as a replacement for fgets() if it returned a pointer to
>>the char buffer.
<snip>
> Thanks muchly for the comments. I think I will follow most of
> your suggestions. AFAICT bit fields would be the right way
> to go. Using a struct to hold most of the stuff might be
> cleaner, though I'm still waffling on that one. Returning a
> pointer to the line is probably right. Ugh, I hate rewriting.

I would not advocate returning a pointer to a buffer that also
"returned" via a char **. The reason is that you get an alias that
may subsequently become invalid (or change). Of course, it is not
"wrong", but I would be wary of adding that pitfall to your otherwise
very clear and flexible API.

--
Ben.
From: Richard Harter on
On Fri, 09 Nov 2007 17:00:57 +0000, Ben Bacarisse
<ben.usenet(a)bsb.me.uk> wrote:

>cri(a)tiac.net (Richard Harter) writes:
>
>> On Wed, 7 Nov 2007 11:08:30 +0100, "Charlie Gordon"
>> <news(a)chqrlie.org> wrote:
[snip]

>> Thanks muchly for the comments. I think I will follow most of
>> your suggestions. AFAICT bit fields would be the right way
>> to go. Using a struct to hold most of the stuff might be
>> cleaner, though I'm still waffling on that one. Returning a
>> pointer to the line is probably right. Ugh, I hate rewriting.
>
>I would not advocate returning a pointer to a buffer that also
>"returned" via a char **. The reason is that you get an alias that
>may subsequently become invalid (or change). Of course, it is not
>"wrong", but I would be wary of adding that pitfall to your otherwise
>very clear and flexible API.

Point well taken. Upon reflection, I'm not sure that bit fields
work well in this context. Is there a portable way to set
several bits in a bit field struct?


Richard Harter, cri(a)tiac.net
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
From: Richard Harter on
On Fri, 09 Nov 2007 11:36:18 -0500, Eric Sosman
<Eric.Sosman(a)sun.com> wrote:

>Richard Harter wrote On 11/09/07 10:34,:
>> Below is a "man page" for a file read utility. An HTML version
>> can be found at http://home.tiac.net/~cri/2007/gflspec.html. It
>> is not guaranteed to be typo or brain fart clean.
>>
>> ----
>>
>> SYNOPSIS:
>>
>> #include "getfline.h"
>>
>> int getfline(FILE * fptr,
>> char ** line_ptr,
>> size_t * length_ptr,
>> size_t * bufsize_ptr,
>> size_t maxlen,
>> long * flags);
>> [...]
>
> Isn't there some way you can find an excuse to add
>a couple more arguments? Six is too many for most people
>to keep straight, but you may as well try to confuse the
>geniuses, too. ;-)

I take it you didn't check out the list of flags. I'm
after the geniuses too. :-)

>
> Kidding aside, an argument list of that length suggests
>to me that the function may be trying to be too many things
>to too many people at the same time. It might be wise to
>give up some functionality to improve ease of use; the net
>change in usefulness could in fact be positive.

Point well taken, though there really is nothing that I would
want to give up. I wouldn't want to give up error information,
nor a bound on maximum line size, nor a reusable buffer (for
which both address and size are needed), and not even the line
length. One thing that could be done is package some of the
arguments in a struct. Frex:

struct getfline_args {
size_t bufsize,
size_t length,
size_t maxlen,
long flags);

Then we can have a prototype that looks like this:

int * getfline(FILE *fptr,
char **line_ptr,
struct getfline_args *args);

If we adopt the convention a maxlen of zero means no upper bound
check or alternately, another input flag needed to activate
bounds checking, then instead of a single long calling sequence
we can do:

struct getfline_args gfl_args = {0,0,0,0};
char *line = 0;
FILE *fptr = 0;
...
while (getfline(fptr,&line,&gfl_args) {
/* Do stuff */
}

This doesn't really change anything but it makes it easier to use
the defaults and it moves some of the definitions into the
include file. What do you think of this?


Richard Harter, cri(a)tiac.net
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
From: Eric Sosman on
Richard Harter wrote On 11/09/07 17:00,:
> On Fri, 09 Nov 2007 11:36:18 -0500, Eric Sosman
> <Eric.Sosman(a)sun.com> wrote:
>
>
>>Richard Harter wrote On 11/09/07 10:34,:
>>
>>>Below is a "man page" for a file read utility. An HTML version
>>>can be found at http://home.tiac.net/~cri/2007/gflspec.html. It
>>>is not guaranteed to be typo or brain fart clean.
>>>
>>>----
>>>
>>>SYNOPSIS:
>>>
>>>#include "getfline.h"
>>>
>>>int getfline(FILE * fptr,
>>> char ** line_ptr,
>>> size_t * length_ptr,
>>> size_t * bufsize_ptr,
>>> size_t maxlen,
>>> long * flags);
>>>[...]
>>
>> Isn't there some way you can find an excuse to add
>>a couple more arguments? Six is too many for most people
>>to keep straight, but you may as well try to confuse the
>>geniuses, too. ;-)
>
>
> I take it you didn't check out the list of flags. I'm
> after the geniuses too. :-)

Well, I noticed you needed a `long' to hold them,
not a mere `int' ... Close to two dozen flags, aren't
there?

>> Kidding aside, an argument list of that length suggests
>>to me that the function may be trying to be too many things
>>to too many people at the same time. It might be wise to
>>give up some functionality to improve ease of use; the net
>>change in usefulness could in fact be positive.
>
> Point well taken, though there really is nothing that I would
> want to give up. I wouldn't want to give up error information,
> nor a bound on maximum line size, nor a reusable buffer (for
> which both address and size are needed), and not even the line
> length. One thing that could be done is package some of the
> arguments in a struct. Frex:
>
> struct getfline_args {
> size_t bufsize,
> size_t length,
> size_t maxlen,
> long flags);
>
> Then we can have a prototype that looks like this:
>
> int * getfline(FILE *fptr,
> char **line_ptr,
> struct getfline_args *args);

I'm not sure why the return value changed from an int
to a pointer. Typo?

> If we adopt the convention a maxlen of zero means no upper bound
> check or alternately, another input flag needed to activate
> bounds checking, then instead of a single long calling sequence
> we can do:
>
> struct getfline_args gfl_args = {0,0,0,0};
> char *line = 0;
> FILE *fptr = 0;
> ...
> while (getfline(fptr,&line,&gfl_args) {
> /* Do stuff */
> }
>
> This doesn't really change anything but it makes it easier to use
> the defaults and it moves some of the definitions into the
> include file. What do you think of this?

It reawakens memories of the days when interfaces
used "control blocks," often populated by assembly macros.
The C library's struct tm is such a beast, FILE can be
thought of in that light, and POSIX has no shortage of
structured arguments. If you take this route, you'll at
least be on a well-marked trail.

If you like the control block approach, though, why
not go whole hog and put the line_ptr in the struct, too?
You *could* even park the fptr there, but it could ease
things a little if a struct initialized to all zeroes
meant something sensible. With a purpose-built struct
type handy by, that overwhelming mass of flags might
become a bunch of bit-fields. Bit-fields are, IMHO, a
mixed blessing, but in a case like this they'd avoid the
need to pollute the name space with all those GFL_xxx
macros.

Still, I can't shake the feeling that you're trying
to get one function to do too many tasks. Instead of
using a bazillion flags to govern different modes of
operation, might you consider a suite of related functions
to handle the important variations? In effect, you'd be
moving a few flags out of the struct and into the function
name. Observe the exec*() family of POSIX interfaces, for
example: they all do "the same thing" and they probably
all devolve on the same internal implementation, but using
different names for different (although related) operations
is a useful simplification. Try to imagine what it would
be like if all of printf(), fprintf(), sprintf(), vprintf(),
vfprintf(), vsprintf(), and vsnprintf() were packaged
into one function name with a control block to choose
different operation modes ... Ugh!

As you may gather, I am a big fan of small, simple
interfaces. Some people feel my adoration of simplicity
is unhealthily intense; my own line-getter has been
criticized for violating the "... but not simpler" part
of Einstein's dictum. (The critic was someone I think
highly of, so I gave his criticism careful thought before
deciding to ignore it.) I mention all this to make my
biases clear: the KISS principle is very important to me,
but may not hold quite so much sway over others.

--
Eric.Sosman(a)sun.com
From: CBFalconer on
Eric Sosman wrote:
>
.... snip ...
>
> As you may gather, I am a big fan of small, simple interfaces.
> Some people feel my adoration of simplicity is unhealthily
> intense; my own line-getter has been criticized for violating
> the "... but not simpler" part of Einstein's dictum. (The
> critic was someone I think highly of, so I gave his criticism
> careful thought before deciding to ignore it.) I mention all
> this to make my biases clear: the KISS principle is very
> important to me, but may not hold quite so much sway over others.

Here is the heart of my ggets function, which more or less adheres
to your principles. The entire package, with testing code, demos,
docs, etc. is available at:

<http://cbfalconer.home.att.net/download/>

#include <stdio.h>
#include <stdlib.h>
#include "ggets.h"

#define INITSIZE 112 /* power of 2 minus 16, helps malloc */
#define DELTASIZE (INITSIZE + 16)

enum {OK = 0, NOMEM};

int fggets(char* *ln, FILE *f)
{
int cursize, ch, ix;
char *buffer, *temp;

*ln = NULL; /* default */
if (NULL == (buffer = malloc(INITSIZE))) return NOMEM;
cursize = INITSIZE;

ix = 0;
while ((EOF != (ch = getc(f))) && ('\n' != ch)) {
if (ix >= (cursize - 1)) { /* extend buffer */
cursize += DELTASIZE;
if (NULL == (temp = realloc(buffer, (size_t)cursize))) {
/* ran out of memory, return partial line */
buffer[ix] = '\0';
*ln = buffer;
return NOMEM;
}
buffer = temp;
}
buffer[ix++] = ch;
}
if ((EOF == ch) && (0 == ix)) {
free(buffer);
return EOF;
}

buffer[ix] = '\0';
if (NULL == (temp = realloc(buffer, (size_t)ix + 1))) {
*ln = buffer; /* without reducing it */
}
else *ln = temp;
return OK;
} /* fggets */

--
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home.att.net>
Try the download section.



--
Posted via a free Usenet account from http://www.teranews.com

First  |  Prev  |  Next  |  Last
Pages: 1 2 3 4 5 6 7 8 9 10
Prev: problem analysis chart
Next: Please help!