#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 -----