#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 */ return grow_status_msg(status); } /* Read a line of input */ /* What is the nature of the problem? */ /* An unexpected error */ return EXIT_FAILURE; } } /* Do it all again */ continue; /* All done */ "----- All input: -----\n\n%s\n\n" "----- Final size: %u -----\n", buf, (unsigned int) (tail - 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 */ 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) { } 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; } return EXIT_FAILURE; }
#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;
}----- All input: -----
#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;
}
----- Final size: 4644 -----