C read all input once optimization - c

first I'm looking for optimization, fast time execution
I would like to read data from input in C so here is my code (Linux)
int main(void) {
char command_str[MAX_COMMAND_SIZE];
while (!feof(stdin)) {
fgets(command_str, MAX_COMMAND_SIZE, stdin);
// Parse data
}
return EXIT_SUCCESS;
}
According to this post Read a line of input faster than fgets? read() function seems to be the solution.
The data input is like:
100 C
1884231 B
8978456 Z
...
From a file, so I execute my program like ./myapp < mytext.txt
It is not possible to know how many entries there is, it's could be 10, 10000 or even more.
From this post
Drop all the casts on malloc and realloc; they aren't necessary and clutter up the code
So if I use a dynamic array my app will be slower I think.
The idea is:
Read the whole input in one go into a buffer.
Process the lines from that buffer.
That's the fastest possible solution.
If someone would help me. Thanks in advance.

while (!feof(f)) is always wrong. Use this instead:
#include <stdio.h>
int main(void) {
char command_str[MAX_COMMAND_SIZE];
while (fgets(command_str, MAX_COMMAND_SIZE, stdin)) {
// Parse data
}
return EXIT_SUCCESS;
}
Reading file contents faster than fgets() is feasible, but seems beyond your skill level. Learn the simple stuff first. There is an awful lot that can be achieved with standard line by line readers... Very few use cases warrant the use of more advanced approaches.
If you want to read the whole input and parse it as a single string, here is a generic solution that should work for all (finite) input types:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
size_t pos = 0, size = 1025, nread;
char *buf0 = malloc(size);
char *buf = buf0;
for (;;) {
if (buf == NULL) {
fprintf(stderr, "not enough memory for %zu bytes\n", size);
free(buf0);
exit(1);
}
nread = fread(buf + pos, 1, size - pos - 1, stdin);
if (nread == 0)
break;
pos += nread;
/* Grow the buffer size exponentially (Fibonacci ratio) */
if (size - pos < size / 2)
size += size / 2 + size / 8;
buf = realloc(buf0 = buf, size);
}
buf[pos] = '\0';
// parse pos bytes of data in buf as a string
printf("read %zu bytes\n", strlen(buf));
free(buf);
return EXIT_SUCCESS;
}

Maybe you could use fseek (stdin, 0, SEEK_END) to go to the end of the standard input stream, then use ftell (stdin) to get its size in bytes, then allocate memory to save all that in a buffer and then process it's contents.

Related

Trying to read an unknown string length from a file using fgetc()

So yeah, saw many similar questions to this one, but thought to try solving it my way. Getting huge amount of text blocks after running it (it compiles fine).
Im trying to get an unknown size of string from a file. Thought about allocating pts at size of 2 (1 char and null terminator) and then use malloc to increase the size of the char array for every char that exceeds the size of the array.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char *pts = NULL;
int temp = 0;
pts = malloc(2 * sizeof(char));
FILE *fp = fopen("txtfile", "r");
while (fgetc(fp) != EOF) {
if (strlen(pts) == temp) {
pts = realloc(pts, sizeof(char));
}
pts[temp] = fgetc(fp);
temp++;
}
printf("the full string is a s follows : %s\n", pts);
free(pts);
fclose(fp);
return 0;
}
You probably want something like this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define CHUNK_SIZE 1000 // initial buffer size
int main()
{
int ch; // you need int, not char for EOF
int size = CHUNK_SIZE;
char *pts = malloc(CHUNK_SIZE);
FILE* fp = fopen("txtfile", "r");
int i = 0;
while ((ch = fgetc(fp)) != EOF) // read one char until EOF
{
pts[i++] = ch; // add char into buffer
if (i == size + CHUNK_SIZE) // if buffer full ...
{
size += CHUNK_SIZE; // increase buffer size
pts = realloc(pts, size); // reallocate new size
}
}
pts[i] = 0; // add NUL terminator
printf("the full string is a s follows : %s\n", pts);
free(pts);
fclose(fp);
return 0;
}
Disclaimers:
this is untested code, it may not work, but it shows the idea
there is absolutely no error checking for brevity, you should add this.
there is room for other improvements, it can probably be done even more elegantly
Leaving aside for now the question of if you should do this at all:
You're pretty close on this solution but there are a few mistakes
while (fgetc(fp) != EOF) {
This line is going to read one char from the file and then discard it after comparing it against EOF. You'll need to save that byte to add to your buffer. A type of syntax like while ((tmp=fgetc(fp)) != EOF) should work.
pts = realloc(pts, sizeof(char));
Check the documentation for realloc, you'll need to pass in the new size in the second parameter.
pts = malloc(2 * sizeof(char));
You'll need to zero this memory after acquiring it. You probably also want to zero any memory given to you by realloc, or you may lose the null off the end of your string and strlen will be incorrect.
But as I alluded to earlier, using realloc in a loop like this when you've got a fair idea of the size of the buffer already is generally going to be non-idiomatic C design. Get the size of the file ahead of time and allocate enough space for all the data in your buffer. You can still realloc if you go over the size of the buffer, but do so using chunks of memory instead of one byte at a time.
Probably the most efficient way is (as mentioned in the comment by Fiddling Bits) is to read the whole file in one go (after first getting the file's size):
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
int main()
{
size_t nchars = 0; // Declare here and set to zero...
// ... so we can optionally try using the "stat" function, if the O/S supports it...
struct stat st;
if (stat("txtfile", &st) == 0) nchars = st.st_size;
FILE* fp = fopen("txtfile", "rb"); // Make sure we open in BINARY mode!
if (nchars == 0) // This code will be used if the "stat" function is unavailable or failed ...
{
fseek(fp, 0, SEEK_END); // Go to end of file (NOTE: SEEK_END may not be implemented - but PROBABLY is!)
// while (fgetc(fp) != EOF) {} // If your system doesn't implement SEEK_END, you can do this instead:
nchars = (size_t)(ftell(fp)); // Add one for NUL terminator
}
char* pts = calloc(nchars + 1, sizeof(char));
if (pts != NULL)
{
fseek(fp, 0, SEEK_SET); // Return to start of file...
fread(pts, sizeof(char), nchars, fp); // ... and read one great big chunk!
printf("the full string is a s follows : %s\n", pts);
free(pts);
}
else
{
printf("the file is too big for me to handle (%zu bytes)!", nchars);
}
fclose(fp);
return 0;
}
On the issue of the use of SEEK_END, see this cppreference page, where it states:
Library implementations are allowed to not meaningfully support SEEK_END (therefore, code using it has no real standard portability).
On whether or not you will be able to use the stat function, see this Wikipedia page. (But it is now available in MSVC on Windows!)

popen and output of system command

I have to figure out the available space in /mnt/ in my application. I wrote the following code. However, execute_cmd some times returns junk apart from the actual output. For ex: 4.5K(followed by junk). Where am I going wrong? Could some one review and let me know why execute_cmd returns a junk byte at the end? How do I improve the code?
char *execute_cmd(char *cmd)
{
FILE *fp;
char path[100];
int ii = 0;
//char ii = 0;
char *buffer = malloc(1024);
char len = 0;
/* Open the command for reading. */
fp = popen(cmd, "r");
if (fp == NULL) {
printf("Failed to run command\n" );
exit(1);
}
printf("Running command is: %s\n", cmd);
memset(buffer, 0, sizeof(buffer));
do {
len = fread(path, 100, 1, fp); /* Is it okay to use fread? I do not know how many bytes to read as this function is a generic function which can be used for executing any command */
strcat(buffer,path);
printf("Number of bytes is: %d\n", len);
} while (len != 0);
len = strlen(buffer);
printf("Buffer contents are: %s %d\n", buffer,len);
/* close */
pclose(fp);
}
void main()
{
char *buffer = "df -h | grep \"/mnt\" | awk '{ print $4}'"; /* FIXME */
char len;
char units;
float number;
char dummy = 0;
char *avail_space;
avail_space = execute_cmd(buffer);
len = strlen(avail_space);
units = avail_space[len - 1];
printf("Available space is: %s %d %c end here\n", avail_space, len, units);
number = strtof(avail_space, NULL);
printf("Number is: %f\n", number);
}
sizeof(buffer) is sizeof(char*), which is probably 8 (or maybe 4). So your memset only clears a little bit of buffer. But with your use of fread, it's not just buffer that needs to be cleared; it's the temporary path.
Uninitialized local variables like path are not zero-initialised. You could use memset(path, 0, sizeof(path)); to clear it -- here the sizeof works because path really is an array -- but simpler is to initialise it in the declaration: char path[100] = "";.
Since fread does not NUL-terminate what it reads, there might be arbitrary garbage following it, making the strcat Undefined Behaviour. In fact, the strcat is totally unnecessary and a waste of cycles. You know how much data you read (it's in len) so you know exactly where to read the next chunk and you can do so directly without a temporary buffer and without a copy.
For future reference, if you are planning on calling malloc and then using memset to clear the allocated region, you should instead use calloc. That's what it's there for.

How to parse files that cannot fit entirely in memory RAM

I have created a framework to parse text files of reasonable size that can fit in memory RAM, and for now, things are going well. I have no complaints, however what if I encountered a situation where I have to deal with large files, say, greater than 8GB(which is the size of mine)?
What would be an efficient approach to deal with such large files?
My framework:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int Parse(const char *filename,
const char *outputfile);
int main(void)
{
clock_t t1 = clock();
/* ............................................................................................................................. */
Parse("file.txt", NULL);
/* ............................................................................................................................. */
clock_t t2 = clock();
fprintf(stderr, "time elapsed: %.4f\n", (double)(t2 - t1) / CLOCKS_PER_SEC);
fprintf(stderr, "Press any key to continue . . . ");
getchar();
return 0;
}
long GetFileSize(FILE * fp)
{
long f_size;
fseek(fp, 0L, SEEK_END);
f_size = ftell(fp);
fseek(fp, 0L, SEEK_SET);
return f_size;
}
char *dump_file_to_array(FILE *fp,
size_t f_size)
{
char *buf = (char *)calloc(f_size + 1, 1);
if (buf) {
size_t n = 0;
while (fgets(buf + n, INT_MAX, fp)) {
n += strlen(buf + n);
}
}
return buf;
}
int Parse(const char *filename,
const char *outputfile)
{
/* open file for reading in text mode */
FILE *fp = fopen(filename, "r");
if (!fp) {
perror(filename);
return 1;
}
/* store file in dynamic memory and close file */
size_t f_size = GetFileSize(fp);
char *buf = dump_file_to_array(fp, f_size);
fclose(fp);
if (!buf) {
fputs("error: memory allocation failed.\n", stderr);
return 2;
}
/* state machine variables */
// ........
/* array index variables */
size_t x = 0;
size_t y = 0;
/* main loop */
while (buf[x]) {
switch (buf[x]) {
/* ... */
}
x++;
}
/* NUL-terminate array at y */
buf[y] = '\0';
/* write buffer to file and clean up */
outputfile ? fp = fopen(outputfile, "w") :
fp = fopen(filename, "w");
if (!fp) {
outputfile ? perror(outputfile) :
perror(filename);
}
else {
fputs(buf, fp);
fclose(fp);
}
free(buf);
return 0;
}
Pattern deletion function based on the framework:
int delete_pattern_in_file(const char *filename,
const char *pattern, const char *outputfile)
{
/* open file for reading in text mode */
FILE *fp = fopen(filename, "r");
if (!fp) {
perror(filename);
return 1;
}
/* copy file contents to buffer and close file */
size_t f_size = GetFileSize(fp);
char *buf = dump_file_to_array(fp, f_size);
fclose(fp);
if (!buf) {
fputs("error - memory allocation failed", stderr);
return 2;
}
/* delete first match */
size_t n = 0, pattern_len = strlen(pattern);
char *tmp, *ptr = strstr(buf, pattern);
if (!ptr) {
fputs("No match found.\n", stderr);
free(buf);
return -1;
}
else {
n = ptr - buf;
ptr += pattern_len;
tmp = ptr;
}
/* delete the rest */
while (ptr = strstr(ptr, pattern)) {
while (tmp < ptr) {
buf[n++] = *tmp++;
}
ptr += pattern_len;
tmp = ptr;
}
/* copy the rest of the buffer */
strcpy(buf + n, tmp);
/* open file for writing and print the processed buffer to it */
outputfile ? fp = fopen(outputfile, "w") :
fp = fopen(filename, "w");
if (!fp) {
outputfile ? perror(outputfile) :
perror(filename);
}
else {
fputs(buf, fp);
fclose(fp);
}
free(buf);
return 0;
}
If you wish to stick with your current design, an option might be to mmap() the file instead of reading it into a memory buffer.
You could change the function dump_file_to_array to the following (linux-specific):
char *dump_file_to_array(FILE *fp, size_t f_size) {
buf = mmap(NULL, f_size, PROT_READ, MAP_SHARED, fileno(fp), 0);
if (buf == MAP_FAILED)
return NULL;
return buf;
}
Now you can read over the file, the memory manager will take automatically care to only hold the relevant potions of the file in memory.
For Windows, similar mechanisms exist.
Chances you are parsing the file line-by line. So read in a large block (4k or 16k) and parse all the lines in that. Copy the small remainder to the beginning of the 4k or 16k buffer and read in the rest of the buffer. Rinse and repeat.
For JSON or XML you will need an event based parser that can accept multiple blocks or input.
There are multiple issues with your approach.
The concept of maximum and available memory are not so evident: technically, you are not limited by the RAM size, but by the quantity of memory your environment will let you allocate and use for your program. This depends on various factors:
What ABI you compile for: the maximum memory size accessible to your program is limited to less than 4 GB if you compile for 32-bit code, even if your system has more RAM than that.
What quota the system is configured to let your program use. This may be less than available memory.
What strategy the system uses when more memory is requested than is physically available: most modern systems use virtual memory and share physical memory between processes and system tasks (such as the disk cache) using very advanced algorithms that cannot be describe in a few lines. It is possible on some systems for your program to allocate and use more memory than is physically installed on the motherboard, swapping memory pages to disk as more memory is accessed, at a huge cost in lag time.
There are further issues in your code:
The type long might be too small to hold the size of the file: on Windows systems, long is 32-bit even on 64-bit versions where memory can be allocated in chunks larger than 2GB. You must use different API to request the file size from the system.
You read the file with an series of calls to fgets(). This is inefficient, a single call to fread() would suffice. Furthermore, if the file contains embedded null bytes ('\0' characters), chunks from the file will be missing in memory. However you could not deal with embedded null bytes if you use string functions such as strstr() and strcpy() to handle your string deletion task.
the condition in while (ptr = strstr(ptr, pattern)) is an assignment. While not strictly incorrect, it is poor style as it confuses readers of your code and prevents life saving warnings by the compiler where such assignment-conditions are coding errors. You might think that could never happen, but anyone can make a typo and a missing = in a test is difficult to spot and has dire consequences.
you short-hand use of the ternary operator in place of if statements is quite confusing too: outputfile ? fp = fopen(outputfile, "w") : fp = fopen(filename, "w");
rewriting the input file in place is risky too: if anything goes wrong, the input file will be lost.
Note that you can implement the filtering on the fly, without a buffer, albeit inefficiently:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "usage: delpat PATTERN < inputfile > outputfile\n");
return 1;
}
unsigned char *pattern = (unsigned char*)argv[1];
size_t i, j, n = strlen(argv[1]);
size_t skip[n + 1];
int c;
skip[0] = 0;
for (i = j = 1; i < n; i++) {
while (memcmp(pattern, pattern + j, i - j)) {
j++;
}
skip[i] = j;
}
i = 0;
while ((c = getchar()) != EOF) {
for (;;) {
if (i < n && c == pattern[i]) {
if (++i == n) {
i = 0; /* match found, consumed */
}
break;
}
if (i == 0) {
putchar(c);
break;
}
for (j = 0; j < skip[i]; j++) {
putchar(pattern[j]);
}
i -= skip[i];
}
}
for (j = 0; j < i; j++) {
putchar(pattern[j]);
}
return 0;
}
First of all I wouldn't suggest holding such big files in RAM but instead using streams. This because buffering is usually done by the library as well as by the kernel.
If you are accessing the file sequentially, which seems to be the case, then you probably know that all modern systems implement read-ahead algorithms so just reading the whole file ahead of time IN RAM may in most cases just waste time.
You didn't specify the use-cases you have to cover so I'm going to have to assume that using streams like
std::ifstream
and doing the parsing on the fly will suit your needs. As a side note, also make sure your operations on files that are expected to be large are done in separate threads.
An alternative solution: If you're on linux systems, and you have a decent amount of swap space, just open the whole bad boy up. It will consume your ram and also consume harddrive space (swap). Thus you can have the entire thing open at once, just not all of it will be on the ram.
Pros
If an unexpected shut down occurred, the memory on the swap space is recoverable.
RAM is expensive, HDDs are cheap, so the application would put less strain on your expensive equipment
Virus could not harm your computer because there would be no room in RAM for them to run
You'll be taking full advantage of the Linux operating system by using the swap space. Normally the swap space module is not used and all it does is clog up precious ram.
The additional energy that is needed to utilize the entirety of the ram can warm the immediate area. Useful during winter time
You can add "Complex and Special Memory Allocation Engineering" to your resume.
Cons
None
Consider treating the file as an external array of lines.
Code can use an array of line indexes. This index array can be kept in memory at a fraction of the size of the large file. Access to any line is accomplished quickly via this lookup, a seek with fsetpos() and an fread()/fgets(). As the lines are edited, the new lines can be saved, in any order, in temporary text file. Saving of the file reads both the original file and temp one in sequence to form and write the new file.
typedef struct {
int attributes; // not_yet_read, line_offset/length_determined,
// line_changed/in_other_file, deleted, etc.
fpos_t line_offset; // use with fgetpos() fsetpos()
unsigned line_length; // optional field as code could re-compute as needed.
} line_index;
size_t line_count;
// read some lines
line_index *index = malloc(sizeof *index * line_count);
// read more lines
index = realloc(index, sizeof *index * line_count);
// edit lines, save changes to appended temporary file.
// ...
// Save file -weave the contents of the source file and temp file to the new output file.
Additionally, with enormous files, the array line_index[] itself can be realized in disk memory too. Access to is easily computed. In an extreme sense, only 1 line of the file needs to in memory at any time.
You mentioned state-machine. Every finite-state-automata can be optimized to have minimal (or no) lookahead.
Is it possible to do this in Lex? It will generate output c file which you can compile.
If you don't want to use Lex, you can always do following:
Read n chars into (ring?) buffer where n is size of pattern.
Try to match buffer with pattern
If match goto 1
Print buffer[0], read char, goto 2
Also for very long patterns and degenerate inputs strstr can be slow. In that case you might want to look into more advanced sting matching aglorithms.
mmap() is a pretty good way of working on files with large sizes.
It provides you with lot of flexibility but you need to be cautious with page size. Here is a good article which talks about more specifics.

program wouldn't stop reading file

I was experimenting with writing a program that would reverse the contents of a file.
So, giving the inputfile with the content "abc" it should make a file with a content "cba".
Unfortunately, it doesn't work and I don't understand why.
Could you guys please help me?
Thanks
EDIT: i forgot to mention that it was a school assignment - and we have to use functions like lseek and open - Please dont posr me that I should've used fgetc anfd other functions :)
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
void reverse_file(char * in, char * out)
{
int infile, outfile;
infile = open(in, O_RDONLY);
outfile = open(out, O_WRONLY);
char buffer;
char end = EOF;
write(outfile, &end, sizeof(char));
do
{
// seek to the beginning of a file
read(infile, &buffer, sizeof(char));
// printf("the code of a character %d\n", buffer); // returns 10 instead of EOF
lseek(outfile, 0, SEEK_SET);
write(outfile, &buffer, sizeof(char));
} while (buffer != EOF);
close(outfile);
close(infile);
}
int main()
{
reverse_file("tt", "testoutput");
return 0;
}
read returns the number of bytes it reads. To make your loop stop when you reach the end of the file, change your condition to the return value of read.
int read_ret;
do
{
// seek to the beginning of a file
read_ret = read(infile, &buffer, sizeof(char));
// printf("the code of a character %d\n", buffer); // returns 10 instead of EOF
lseek(outfile, 0, SEEK_SET);
write(outfile, &buffer, sizeof(char));
} while (read_ret > 0);
When read reach the end of the file and returns zero, it does not set *buffer. That is why your loop never stop.
Your current code (outside the fact that the test for the end of file is wrong), will make a file of one char, because write overwrite the data present in the file at the current position (unless it's at the end, where it would append).
Actually, to reverse the file, you should read it starting from the end.
struct stat instat;
int pos;
fstat(infile, &instat);
pos = instat.st_size - 1;
do
{
// seek backward in the input file, starting from the end
lseek(infile, SEEK_SET, pos);
read(infile, &buffer, sizeof(char));
write(outfile, &buffer, sizeof(char));
} while (pos-- > 0);
(Reading char by char is very ineficient with the unix read and write system calls, so as a second step, you should consider using the C primitives (fopen, fread, fwrite), or do some buffered reads and writes with the unix system calls.)
See:
open
read
write
lseek
fstat
You need to read to read the whole input file and then write it out. Don't try to do it char by char and don't use lseek.

C getline function not reading lines as specified

I need getline() to read the request header sent by my browser to the webserver I'm programming. This is the getMessage function which is supposed to do that task:
char *getMessage(int fd) {
FILE *sstream = fdopen(fd, "r");
// initialise block to 1 char and set it to null
char *block = malloc(sizeof(char));
*block = '\0';
int size = 1;
// Read from the file descriptor fd (using a FILE stream) until a blank line is
// received.
// Read 100 lines (buffersize) from sstream and put into the buffer. If lines have
// been successfully read concatenate them with block.
int buffersize = 100;
char *buffer = malloc (buffersize + 1);
while(getline(&buffer,&buffersize,sstream) != -1){
int length = strlen(buffer);
printf("Buffer length: %d\n",length);
block = realloc(block,strlen(block)+strlen(buffer)+1);
strcat(block,buffer);
if(strcmp(buffer,"\r\n") == 0) break;
}
int len = strlen(block);
printf("Block length: %d\n", len);
printf("%s \n", block);
return block;
}
Basically the input of the getMessage function (fd), is the input from my listening socket declared in my main method. I have verified that the output is correct. Now I need to convert the output from the file descriptor to a string and return that string. But every time I run my server it gets stuck in the while loop. Not executing the statements in the loop.
EDIT: Added a loop-terminating condition: Now it jumps to "Block length" immediatley.
Help is much appreciated!
If you are using the POSIX 2008 getline() function, then you're throwing away useful information (it returns the length of the line it reads, so if you capture that information, you would not need the strlen() in the loop.
If the code blocks on a getline() call, it probably means that the upstream socket is not closed, but there is no data being sent any more. Your sending code needs to close the socket so that this code can detect EOF.
Or, since you discuss 'a blank line', then maybe your code should be checking for a line containing just \r\n (or maybe just \n) and break the loop; your code is not doing that at the moment.
Your loop also exhibits quadratic behaviour because you are repeatedly using strcat(). You would do better to keep tabs on the end of the string and simply strcpy() the new data after the old, then adjust the pointer to the end of the string.
On further review, I note that you use fdopen() to open a file stream based on the file descriptor, but you neither close it nor return the file stream to the caller for closing. This leads to a leakage problem.
Rule of Thumb: if you allocate a resource, you should release it, or pass it back to be released.
I recommend changing the interface to use an already-open FILE *, and doing the fdopen() in the calling code. Alternatively, if you won't need the file descriptor again, you can keep the current interface and use fclose() before returning, but this will close the underlying file descriptor too.
This code works for me (MacOS X 10.7.2; XCode 4.2.1):
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern char *getMessage(FILE *);
char *getMessage(FILE *fp)
{
char *block = 0;
size_t size = 0;
size_t buffersize = 0;
char *buffer = 0;
ssize_t newlen;
while ((newlen = getline(&buffer, &buffersize, fp)) > 0)
{
printf("Buffer length: %ld\n", (long)newlen);
block = realloc(block, size + newlen + 1);
strcat(&block[size], buffer);
size += newlen;
if (strcmp(buffer, "\r\n") == 0)
break;
}
printf("Block length: %zd\n", size);
if (size > 0)
printf("<<%s>>\n", block);
return block;
}
int main(void)
{
char *msg;
while ((msg = getMessage(stdin)) != 0)
{
printf("Double check: <<%s>>\n", msg);
free(msg);
}
return 0;
}
I tested it with a file with DOS-style line endings as standard input, with both a blank line as the last line and with a non-blank line. Two blank lines in a row also seemed to be OK.
char buffer = (char *) malloc (buffersize + 1);
should be:
char *buffer = malloc (buffersize + 1);

Resources