From C
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/*** Object types */
enum e_grow_status {
grow_status_success,
grow_status_invalid_param,
grow_status_too_big,
grow_status_out_of_memory,
grow_status_count
};
typedef enum e_grow_status e_grow_status;
/*** Function declarations */
e_grow_status realloc_str_buf(
char ** buf_ptr,
unsigned int new_size
);
e_grow_status append_buf(
char ** buf_ptr,
char ** tail_ptr,
unsigned int tail_size
);
int grow_status_msg(e_grow_status code);
/*** Function definitions */
int main(void) {
/*
* We will attempt to grow our storage by this
* amount, each time we need to grow it
*/
const unsigned int growth = 10;
/*
* This will point to where we put our data.
* Initially, it points to no storage
*/
char * buf = NULL;
/* Where we append data when the buffer is grown */
char * tail;
/* Buffer-growing status */
e_grow_status status;
/*
* Keep getting lines of input until there's no
* more input to be had. We append the new data
* to the end of the current data
*/
do {
/* Make sure we have some buffer available */
status = append_buf(&buf, &tail, growth);
if (status != grow_status_success) {
/* There was a problem with the buffer */
free(buf);
return grow_status_msg(status);
}
/* Read a line of input */
if (!fgets(tail, growth, stdin)) {
/* What is the nature of the problem? */
if (ferror(stdin)) {
/* An unexpected error */
fprintf(stderr, "Unexpected input error!\n");
free(buf);
return EXIT_FAILURE;
}
}
/* Do it all again */
continue;
} while (!feof(stdin));
/* All done */
printf(
"----- All input: -----\n\n%s\n\n"
"----- Final size: %u -----\n",
buf,
(unsigned int) (tail - buf)
);
free(buf);
return EXIT_SUCCESS;
}
e_grow_status realloc_str_buf(
char ** buf_ptr,
unsigned int new_size
) {
/*
* When we use 'realloc', we don't want to lose
* track of where '*buf_ptr' currently points, so
* we use another pointer to capture the result
*/
char * new_buf;
/* Check for invalid parameters */
if (!buf_ptr || !new_size) {
return grow_status_invalid_param;
}
/* Allocate more storage */
new_buf = realloc(*buf_ptr, new_size);
if (!new_buf) {
/* Problem */
return grow_status_out_of_memory;
}
/* Update the caller's pointer */
*buf_ptr = new_buf;
return grow_status_success;
}
e_grow_status append_buf(
char ** buf_ptr,
char ** tail_ptr,
unsigned int tail_size
) {
/* The current length of stored data */
unsigned int data_len;
/* The next size for a grown buffer */
unsigned int new_size;
/* Buffer-growing status */
e_grow_status status;
/* Check for invalid parameter */
if (!buf_ptr || !tail_ptr || !tail_size) {
return grow_status_invalid_param;
}
/* How much storage is used? */
if (*buf_ptr) {
data_len = strlen(*buf_ptr);
} else {
data_len = 0;
}
/* How much total storage do we need? */
new_size = data_len + tail_size;
if (new_size < data_len) {
/* Uh oh, we've wrapped around the maximum size */
return grow_status_too_big;
}
/* Allocate 'tail_size' more storage */
status = realloc_str_buf(buf_ptr, new_size);
if (status != grow_status_success) {
/* Problem */
return status;
}
/* Tell the caller where the unused storage begins */
*tail_ptr = *buf_ptr + data_len;
/*
* Ensure the tail begins with a null terminator,
* for the sake of 'strlen' safety
*/
**tail_ptr = 0;
return grow_status_success;
}
int grow_status_msg(e_grow_status code) {
char * msg;
switch (code) {
case grow_status_success:
/* No error */
return EXIT_SUCCESS;
case grow_status_invalid_param:
msg = "An invalid parameter was passed!";
break;
case grow_status_too_big:
msg = "Buffer too big!";
break;
case grow_status_out_of_memory:
msg = "Out of memory!";
break;
default:
msg = "Invalid status!";
break;
}
fprintf(stderr, "grow_status_msg: %s\n", msg);
return EXIT_FAILURE;
}