mirror of
https://github.com/johnkerl/miller.git
synced 2026-07-27 09:48:46 +00:00
236 lines
5.8 KiB
C
236 lines
5.8 KiB
C
#include <stdio.h>
|
|
#include "lib/mlr_arch.h"
|
|
#include "lib/mlrutil.h"
|
|
#include "input/line_readers.h"
|
|
|
|
// ----------------------------------------------------------------
|
|
char* mlr_alloc_read_line_single_delimiter(
|
|
FILE* fp,
|
|
int delimiter,
|
|
size_t* pold_then_new_strlen,
|
|
int do_auto_line_term,
|
|
context_t* pctx)
|
|
{
|
|
size_t linecap = power_of_two_above(*pold_then_new_strlen + 1); // +1 for null-terminator
|
|
char* restrict line = mlr_malloc_or_die(linecap);
|
|
char* restrict p = line;
|
|
int reached_eof = FALSE;
|
|
int c;
|
|
int nread = 0;
|
|
|
|
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 == EOF) {
|
|
*p = 0;
|
|
reached_eof = TRUE;
|
|
break;
|
|
} else if (c == delimiter) {
|
|
nread++;
|
|
*p = 0;
|
|
break;
|
|
} else {
|
|
nread++;
|
|
*(p++) = c;
|
|
}
|
|
}
|
|
|
|
if (do_auto_line_term) {
|
|
char* q = p - 1;
|
|
if (q >= line && *q == '\r') {
|
|
*q = 0;
|
|
context_set_autodetected_crlf(pctx);
|
|
p = q;
|
|
} else {
|
|
context_set_autodetected_lf(pctx);
|
|
}
|
|
}
|
|
|
|
// linelen excludes line-ending characters.
|
|
// nread includes line-ending characters.
|
|
int linelen = p - line;
|
|
if (nread == 0 && reached_eof) {
|
|
free(line);
|
|
line = NULL;
|
|
linelen = 0;
|
|
}
|
|
*pold_then_new_strlen = linelen;
|
|
|
|
return line;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
char* mlr_alloc_read_line_multiple_delimiter(
|
|
FILE* fp,
|
|
char* delimiter,
|
|
int delimiter_length,
|
|
size_t* pold_then_new_strlen)
|
|
{
|
|
size_t linecap = power_of_two_above(*pold_then_new_strlen + 1); // +1 for null-terminator
|
|
char* line = mlr_malloc_or_die(linecap);
|
|
char* p = line; // points to null-terminator in (chomped) output string
|
|
char* q = line; // points to end of line in (non-chomped) data read from file
|
|
int reached_eof = FALSE;
|
|
int c;
|
|
int nread = 0;
|
|
int dlm1 = delimiter_length - 1;
|
|
char delimend = delimiter[dlm1];
|
|
|
|
while (TRUE) {
|
|
size_t offset = q - line;
|
|
if (offset >= linecap-1) {
|
|
linecap = linecap << 1;
|
|
line = mlr_realloc_or_die(line, linecap);
|
|
q = line + offset;
|
|
}
|
|
c = mlr_arch_getc(fp);
|
|
if (c == EOF) {
|
|
*q = 0;
|
|
reached_eof = TRUE;
|
|
p = q;
|
|
break;
|
|
} else if (c == delimend) {
|
|
// For efficiency, do a single-character test to see if we've seen
|
|
// the last character in the line-ending sequence. If we have, then
|
|
// strcmp back to see if we've seen the entire line-ending sequence.
|
|
//
|
|
// This function exists separately from in order to avoid the performance
|
|
// penalty of this strcmp.
|
|
nread++;
|
|
*(q++) = c;
|
|
p = q - delimiter_length;
|
|
if (q - line >= delimiter_length && memcmp(p, delimiter, delimiter_length) == 0) {
|
|
*p = 0;
|
|
break;
|
|
}
|
|
} else {
|
|
nread++;
|
|
*(q++) = c;
|
|
}
|
|
}
|
|
|
|
// linelen excludes line-ending characters.
|
|
// nread includes line-ending characters.
|
|
int linelen = p - line;
|
|
if (nread == 0 && reached_eof) {
|
|
free(line);
|
|
line = NULL;
|
|
linelen = 0;
|
|
}
|
|
*pold_then_new_strlen = linelen;
|
|
|
|
return line;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
char* mlr_alloc_read_line_single_delimiter_stripping_comments(
|
|
FILE* fp,
|
|
int delimiter,
|
|
size_t* pold_then_new_strlen,
|
|
int do_auto_line_term,
|
|
comment_handling_t comment_handling,
|
|
char* comment_string,
|
|
context_t* pctx)
|
|
{
|
|
return mlr_alloc_read_line_single_delimiter_stripping_comments_aux(
|
|
fp,
|
|
delimiter,
|
|
pold_then_new_strlen,
|
|
do_auto_line_term,
|
|
comment_handling,
|
|
comment_string,
|
|
NULL,
|
|
pctx);
|
|
}
|
|
|
|
char* mlr_alloc_read_line_single_delimiter_stripping_comments_aux(
|
|
FILE* fp,
|
|
int delimiter,
|
|
size_t* pold_then_new_strlen,
|
|
int do_auto_line_term,
|
|
comment_handling_t comment_handling,
|
|
char* comment_string,
|
|
int* pnum_lines_comment_skipped,
|
|
context_t* pctx)
|
|
{
|
|
if (pnum_lines_comment_skipped != NULL)
|
|
*pnum_lines_comment_skipped = 0;
|
|
while (TRUE) {
|
|
char* line = mlr_alloc_read_line_single_delimiter(
|
|
fp, delimiter, pold_then_new_strlen, do_auto_line_term, pctx);
|
|
if (line == NULL) {
|
|
return line;
|
|
} else if (string_starts_with(line, comment_string)) {
|
|
if (pnum_lines_comment_skipped != NULL)
|
|
(*pnum_lines_comment_skipped)++;
|
|
if (comment_handling == PASS_COMMENTS) {
|
|
fputs(line, stdout);
|
|
if (do_auto_line_term) {
|
|
fputs(pctx->auto_line_term, stdout);
|
|
} else {
|
|
fputc(delimiter, stdout);
|
|
}
|
|
fflush(stdout);
|
|
}
|
|
free(line);
|
|
} else {
|
|
return line;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
char* mlr_alloc_read_line_multiple_delimiter_stripping_comments(
|
|
FILE* fp,
|
|
char* delimiter,
|
|
int delimiter_length,
|
|
size_t* pold_then_new_strlen,
|
|
comment_handling_t comment_handling,
|
|
char* comment_string)
|
|
{
|
|
return mlr_alloc_read_line_multiple_delimiter_stripping_comments_aux(
|
|
fp,
|
|
delimiter,
|
|
delimiter_length,
|
|
pold_then_new_strlen,
|
|
comment_handling,
|
|
comment_string,
|
|
NULL);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
char* mlr_alloc_read_line_multiple_delimiter_stripping_comments_aux(
|
|
FILE* fp,
|
|
char* delimiter,
|
|
int delimiter_length,
|
|
size_t* pold_then_new_strlen,
|
|
comment_handling_t comment_handling,
|
|
char* comment_string,
|
|
int* pnum_lines_comment_skipped)
|
|
{
|
|
if (pnum_lines_comment_skipped != NULL)
|
|
*pnum_lines_comment_skipped = 0;
|
|
while (TRUE) {
|
|
char* line = mlr_alloc_read_line_multiple_delimiter(
|
|
fp, delimiter, delimiter_length, pold_then_new_strlen);
|
|
if (line == NULL) {
|
|
return line;
|
|
} else if (string_starts_with(line, comment_string)) {
|
|
if (pnum_lines_comment_skipped != NULL)
|
|
(*pnum_lines_comment_skipped)++;
|
|
if (comment_handling == PASS_COMMENTS) {
|
|
fputs(line, stdout);
|
|
fputs(delimiter, stdout);
|
|
fflush(stdout);
|
|
}
|
|
free(line);
|
|
} else {
|
|
return line;
|
|
}
|
|
}
|
|
}
|