Ben said:
I was thinking that a reasonable step in the realloc() would be
multiples of 16.
stream = popen("/bin/uname -snm", "r");
fgets(sys,len,stream); /* len is the allocated length */
n=strlen(sys)-1;
if(n>=0 && sys[n]=='\n') sys[n]=0;
else (do something here)
printf("n is %d, and sys is %s\n", n, sys);
pclose(stream);
I don't attribute with this source, as I don't see how it would catch
the over-run character by character.
Do you agree?
I'm sorry, but I don't know what you mean.
The main problem when using fgets to read long lines is determining when
a partial line has been read. This can be done marking the last space
in the buffer with something other than a null byte and observing if it
is overwritten. If it is, and the previous character is not \n, we know
that a partial line has been seen.
The normal strategy for realloc is to double the buffer size every time
(though lots of other patterns are quite acceptable). Putting these two
together gives something like this loop:
char *rest_of_line, *line = 0;
size_t space_left, buffer_size = 0;
do {
size_t new_size = buffer_size ? buffer_size * 2 : 16;
char *new_line = realloc(line, new_size);
if (new_line == 0)
break;
line = new_line;
rest_of_line = line + (buffer_size ? buffer_size - 1 : 0);
space_left = new_size - (rest_of_line - line);
buffer_size = new_size;
rest_of_line[space_left - 1] = !0;
} while (fgets(rest_of_line, space_left, fp) &&
rest_of_line[space_left - 1] == 0 &&
rest_of_line[space_left - 2] != '\n');
This is complex enough that I'm sure I've got something wrong though I
won't say "not tested" because I always try to test posted code. I hope
this helps.
Well of course it helps, Ben, but the above is a little more than I'm
interesting in right now. It's heavy with C, and the do-while control
always confuses the bejesus out of me.
I'm trying to adapt Heathfield's published advice on this topic:
$ gcc -Wall -Wextra b1.c -o out
b1.c: In function ‘main’:
b1.c:19: warning: implicit declaration of function ‘strlen’
b1.c:19: warning: incompatible implicit declaration of built-in function
‘strlen’
b1.c:19: error: ‘s’ undeclared (first use in this function)
b1.c:19: error: (Each undeclared identifier is reported only once
b1.c:19: error: for each function it appears in.)
b1.c:23: error: ‘p’ undeclared (first use in this function)
$ cat b1.c
// snippet from chp 8 c unleashed
// all rights reserved, the eton company
// 731 Sedge Way
// the UK
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
/* Listing 8.4 */
static char *buffer = NULL;
static size_t bufsize = 0;
size_t len = strlen(s) + 1;
while(len > bufsize)
{
p = realloc(buffer, bufsize * 2);
if(p != NULL)
{
bufsize *= 2;
buffer = p;
}
else
{
p = realloc(buffer, len);
if(p != NULL)
{
bufsize = len;
buffer = p;
}
else
{
/* What to do next depends very heavily
* on the nature of the application.
*/
printf("What we need here is a design decision!\n");
}
}
}
return 0;
}
// gcc -Wall -Wextra b1.c -o out
$
I see a lot of shortcomings with this source. As a journeyman
carpenter, I've learned to recognize the corners I can knock down with
the detail sander, and those I can't.
Ben, do you agree with me that 's' is what is getting passed to and fro?
The fortran caller will declare the pointer. Caller cannot know how
large the output is.
So instead of thinking of the passed command from a fortran string as
'uname', instead consider it to be ls /etc or ls etc. I have
post-windows-can't see-one-slash from the other syndrome. Please work
with me.
I'm asking for advise on design printf("What we need here is a design
decision!\n");decisions.