line-reader iterate

This commit is contained in:
John Kerl 2017-03-08 07:29:55 -05:00
parent 00a7125b04
commit dee19f1896
3 changed files with 152 additions and 1 deletions

View file

@ -148,3 +148,46 @@ ssize_t local_getdelim(char** restrict pline, size_t* restrict plinecap, int del
//
// reuse linecap on subsequent calls. power of two above last readlen.
// work autodetect deeper into the callstack
// ----------------------------------------------------------------
char* mlr_alloc_read_line_single_delimiter(
FILE* fp,
int delimiter,
int* preached_eof,
size_t* pold_then_new_strlen,
size_t* pold_then_new_linecap)
{
// xxx wip
size_t linecap = power_of_two_above(*pold_then_new_strlen);
char* restrict line = mlr_malloc_or_die(linecap);
char* restrict p = line;
int reached_eof = FALSE;
int c;
while (TRUE) {
size_t offset = p - line;
if (offset >= linecap) {
linecap = linecap << 1;
line = mlr_realloc_or_die(line, linecap);
p = line + offset;
}
c = mlr_arch_getc(fp);
if (c == delimiter) {
*(p++) = 0;
break;
} else if (c == EOF) {
*(p++) = 0;
if (p == line)
reached_eof = TRUE;
break;
} else {
*(p++) = c;
}
}
*preached_eof = reached_eof;
*pold_then_new_strlen = p - line - 1; // exclude null terminator
*pold_then_new_linecap = linecap;
return line;
}

View file

@ -24,4 +24,25 @@ char* mlr_get_sline(FILE* input_stream, char* irs, int irslen);
// inside mlr_arch.c, for unit-testing visibility.
ssize_t local_getdelim(char** restrict pline, size_t* restrict plinecap, int delimiter, FILE* restrict stream);
// xxx type up comments:
// * in delimiter (single/multiple)
// * in fp
// * -in do_auto_line_term- separate variant
// * -inout pctx- separate variant
// * out line
// * out reached eof
// * inout strlen (old/new). DEFAULT_SIZE @ first call
// * inout linecap (old/new) DEFAULT_SIZE @ first call
//
// reuse linecap on subsequent calls. power of two above last readlen.
// work autodetect deeper into the callstack
#define MLR_ALLOC_READ_LINE_INITIAL_SIZE 128
char* mlr_alloc_read_line_single_delimiter(
FILE* fp,
int delimiter,
int* preached_eof,
size_t* pold_then_new_strlen,
size_t* pold_then_new_linecap);
#endif // LINE_READERS_H

View file

@ -26,6 +26,7 @@ static FILE* fopen_or_die(char* filename) {
return fp;
}
// ----------------------------------------------------------------
static char* test_getdelim_impl(getdelim_t* pgetdelim) {
char delimiter = '\n';
char* contents = NULL;
@ -108,6 +109,92 @@ static char* test_getdelim_impl(getdelim_t* pgetdelim) {
return NULL;
}
// ----------------------------------------------------------------
static char* test_mlr_alloc_read_line_single_delimiter() {
#if 0
char delimiter = '\n';
char* path = NULL;
FILE* fp = NULL;
char* contents = NULL;
char* line = NULL;
int reached_eof = FALSE;
size_t linelen = 0;
size_t linecap = 0;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
contents = "";
path = write_temp_file_or_die(contents);
fp = fopen_or_die(path);
// Read line
linecap = 4;
line = mlr_alloc_read_line_single_delimiter(fp, delimiter, &reached_eof, &linelen, &linecap);
printf("reof=%d,linelen=%d,linecap=%d,line=\"%s\"\n", (int)reached_eof, (int)linelen, (int)linecap, line);
mu_assert_lf(line != NULL);
mu_assert_lf(streq(line, ""));
mu_assert_lf(reached_eof == TRUE);
mu_assert_lf(linelen == strlen(""));
mu_assert_lf(linecap > linelen);
// Read past EOF
line = mlr_alloc_read_line_single_delimiter(fp, delimiter, &reached_eof, &linelen, &linecap);
mu_assert_lf(line != NULL);
mu_assert_lf(streq(line, ""));
mu_assert_lf(reached_eof == TRUE);
fclose(fp);
unlink_file_or_die(path);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
contents = "\n";
path = write_temp_file_or_die(contents);
fp = fopen_or_die(path);
// Read line
line = NULL;
linecap = 0;
rc = (*pgetdelim)(&line, &linecap, delimiter, fp);
mu_assert_lf(rc == 1);
mu_assert_lf(streq(line, "\n"));
mu_assert_lf(linecap >= 1+strlen(contents));
// Read past EOF
line = NULL;
linecap = 0;
rc = (*pgetdelim)(&line, &linecap, delimiter, fp);
mu_assert_lf(rc == -1);
fclose(fp);
unlink_file_or_die(path);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
contents = "\r\n";
path = write_temp_file_or_die(contents);
fp = fopen_or_die(path);
// Read line
line = NULL;
linecap = 0;
rc = (*pgetdelim)(&line, &linecap, delimiter, fp);
mu_assert_lf(rc == 2);
mu_assert_lf(streq(line, "\r\n"));
mu_assert_lf(linecap >= 1+strlen(contents));
// Read past EOF
line = NULL;
linecap = 0;
rc = (*pgetdelim)(&line, &linecap, delimiter, fp);
mu_assert_lf(rc == -1);
fclose(fp);
unlink_file_or_die(path);
#endif
return NULL;
}
// ----------------------------------------------------------------
// On unixish platforms this is testing the system getdelim() which is correct by definition.
// (At least, we verify it's behaving as we expect.) On Windows, this tests our local_getdelim
@ -126,7 +213,7 @@ static char* test_getdelim() {
// ================================================================
static char * run_all_tests() {
mu_run_test(test_getdelim);
// xxx WIP mu_run_test(test_local_getdelim);
mu_run_test(test_mlr_alloc_read_line_single_delimiter);
return 0;
}