Initial commit
[cgperf.git] / getline.c
blobcae84c9e018be62e402986d84220972bc44faeda
1 #ifndef CGPERF_GETLINE_C
2 #define CGPERF_GETLINE_C
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <assert.h>
7 #include "c_fixing.h"
8 #include "getline.h"
9 /*------------------------------------------------------------------------------------------------*/
10 #include "namespace/getline.h"
11 /*------------------------------------------------------------------------------------------------*/
12 /*{{{ get_delim */
13 static s32 get_delim(u8 **lineptr, u32 *n, s32 delimiter, FILE *stream)
15 return getstr(lineptr, n, stream, delimiter, 0);
16 }/*}}}*/
17 /*{{{ getstr */
18 /* always add at least this many bytes when extending the buffer */
19 #define MIN_CHUNK 64
20 /* Reads up to (and including) a TERMINATOR from STREAM into *LINEPTR + OFFSET
21 (and null-terminate it). *LINEPTR is a pointer returned from new [] (or
22 NULL), pointing to *N characters of space. It is realloc'd as
23 necessary. Returns the number of characters read (not including the
24 null terminator), or -1 on error or immediate EOF.
25 NOTE: There is another getstr() function declared in <curses.h>. */
26 static s32 getstr(u8 **lineptr, u32 *n, FILE *stream, u8 terminator,
27 u32 offset)
29 u32 nchars_avail; /* allocated but unused chars in *LINEPTR */
30 u8 *read_pos; /* Where we're reading into *LINEPTR. */
32 if (!lineptr || !n || !stream)
33 return -1;
34 if (!*lineptr) {
35 *n = MIN_CHUNK;
36 *lineptr = calloc(*n, sizeof(u8));
38 nchars_avail = *n - offset;
39 read_pos = *lineptr + offset;
40 loop {
41 s32 c;
43 c = getc(stream);
45 * we always want at least one char left in the buffer, since we always (unless we
46 * get an error while reading the first char) NUL-terminate the line buffer
48 assert(*n - nchars_avail == (u32)(read_pos - *lineptr));
49 if (nchars_avail < 2) {
50 u8 *new_line;
52 if (*n > MIN_CHUNK)
53 *n *= 2;
54 else
55 *n += MIN_CHUNK;
57 nchars_avail = *n + *lineptr - read_pos;
58 new_line = calloc(*n, sizeof(u8));
59 if (*lineptr != 0) {
60 memcpy(new_line, *lineptr, read_pos - *lineptr);
61 free(*lineptr);
63 *lineptr = new_line;
64 read_pos = *n - nchars_avail + *lineptr;
65 assert(*n - nchars_avail == (u32)(read_pos - *lineptr));
67 if (c == EOF || ferror(stream)) {
68 /* return partial line, if any */
69 if (read_pos == *lineptr)
70 return -1;
71 else
72 break;
74 *read_pos++ = c;
75 nchars_avail--;
77 if (c == terminator)
78 /* return the line */
79 break;
81 /* done - NUL terminate and return the number of chars read */
82 *read_pos = '\0';
83 return read_pos - (*lineptr + offset);
85 #undef MIN_CHUNK
86 /*}}}*/
87 /*------------------------------------------------------------------------------------------------*/
88 #define EPILOG
89 #include "namespace/getline.h"
90 #undef EPILOG
91 /*------------------------------------------------------------------------------------------------*/
92 #endif