Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * The program below will read any text file passed as the first argument
- * (or it will read from stdin if no argument is given). It will dynamically
- * allocate pointers as needed in MAXL blocks (rather than one-at-a-time
- * which is highly inefficient). It will allocate (and reallocate) lines
- * as required to accommodate lines of any length. It uses a fixed buffer
- * of MAXC chars to read continually until a complete line is read saving
- * the offset to the position in the current line to append subsequent
- * reads as required until a line is fully read. It keeps track of the
- * ending '\n' for each line and will accomodate files without a POSIX
- * '\n' at the end of file.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- enum { MAXL = 32, MAXC = 1024 };
- char **read_file_into_buf (char ***buf, FILE *fp, int *nlines);
- int main (int argc, char **argv) {
- char **buf = NULL; /* buffer to hold lines of file */
- int n; /* number of lines read */
- FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
- if (!fp) { /* validate file open for reading */
- fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
- return 1;
- }
- if (read_file_into_buf (&buf, fp, &n)) { /* read file into buf */
- for (int i = 0; i < n; i++) { /* loop over all lines */
- #ifdef WLNUMBERS
- printf ("line[%3d]: %s\n", i, buf[i]); /* output w/ln numbers */
- #else
- printf ("%s\n", buf[i]); /* output line */
- #endif
- free (buf[i]); /* free line */
- }
- free (buf); /* free buffer */
- }
- if (fp != stdin) fclose (fp); /* close file if not stdin */
- return 0;
- }
- /** read text file from 'fp' into 'buf' update 'nlines'.
- * Being a 3-STAR Programmer, is NOT a compliment. However,
- * to pass a pointer to pointer to char as a parameter and
- * allocate within the function, it is required. You must
- * pass the address of buf from main otherwise the function
- * recieves a copy whose allocation is lost on return. A better
- * approach is to simply assign the return in 'main' and not
- * pass buf at all.
- */
- char **read_file_into_buf (char ***buf, FILE *fp, int *nlines)
- {
- /* current allocation, current index, and offset if less
- * than a whole line is read into line on fgets call, len
- * holds the line len, and eol indicates '\n' present.
- */
- size_t n = MAXL, idx = 0, offset = 0, len = 0, eol = 0;
- char line[MAXC] = ""; /* temp buffer for MAXC chars */
- void *tmp = NULL; /* pointer for realloc */
- /* validate address, file ptr & nlines address */
- if (!buf || !fp || !nlines) {
- fprintf (stderr, "error; invalid parameter.\n");
- return NULL;
- }
- /* allocate initial MAXL pointers, calloc used to avoid valgrind
- * warning about basing a conditional jump on uninitialized value.
- * calloc allocates and initializes.
- */
- if (!(*buf = calloc (sizeof *buf, MAXL))) {
- fprintf (stderr, "error: virtual memory exhausted.\n");
- return NULL;
- }
- while (fgets (line, MAXC, fp)) /* read every line in file */
- {
- /* save offset from prior read (if any), get len */
- size_t end = offset;
- len = strlen (line);
- if (len && line[len - 1] == '\n') { /* test for new line */
- line[--len] = 0; /* overwrite with nul */
- offset = 0; /* zero offset, all read */
- eol = 1; /* POSIX eol present */
- }
- else {
- line[len] = 0; /* nul-terminate */
- offset += len; /* short read, save offset to last char */
- eol = 0; /* no POSIX eol */
- }
- /* allocate/reallocate for current line + nul-byte */
- tmp = realloc ((*buf)[idx], sizeof ***buf * (end + len + 1));
- if (!tmp) {
- fprintf (stderr, "error: realloc, memory exhausted.\n");
- return *buf; /* return current buf */
- }
- (*buf)[idx] = tmp; /* assign block to current index */
- strcpy ((*buf)[idx] + end, line); /* copy line to block */
- if (!eol) continue; /* chars remain in line, go read them */
- if (++idx == n) { /* check pointer allocation, realloc as needed */
- tmp = realloc (*buf, sizeof **buf * (n + MAXL));
- if (!tmp) {
- fprintf (stderr, "error: realloc buf, memory exhausted.\n");
- return *buf;
- }
- *buf = tmp; /* assign new block to *buf */
- memset (*buf + n, 0, sizeof **buf * MAXL); /* zero new memory */
- n += MAXL; /* update the current number of ptrs allocated */
- }
- *nlines = idx; /* update the number of lines read */
- }
- if (!eol) { /* protect against file with no POSIX ending '\n' */
- idx++; /* account for final line */
- *nlines = idx; /* update nlines */
- }
- /* final realloc to size buf to exactly fit number of lines */
- tmp = realloc (*buf, sizeof **buf * (idx));
- if (!tmp) /* if it fails, return current buf */
- return *buf;
- *buf = tmp; /* assign reallocated block to buf */
- return *buf;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement