|
|
#include "../../unity/unity.h" |
|
|
#include <stdlib.h> |
|
|
#include <string.h> |
|
|
#include <stdbool.h> |
|
|
#include <stdint.h> |
|
|
#include <stdio.h> |
|
|
#include <unistd.h> |
|
|
#include <errno.h> |
|
|
|
|
|
|
|
|
extern struct field_range_pair *frp; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static struct field_range_pair* set_frp_from_pairs(const uintmax_t (*pairs)[2], size_t count) { |
|
|
struct field_range_pair *arr = (struct field_range_pair*) malloc(sizeof(*arr) * (count + 1)); |
|
|
if (!arr) return NULL; |
|
|
for (size_t i = 0; i < count; i++) { |
|
|
arr[i].lo = pairs[i][0]; |
|
|
arr[i].hi = pairs[i][1]; |
|
|
} |
|
|
|
|
|
arr[count].lo = UINTMAX_MAX; |
|
|
arr[count].hi = UINTMAX_MAX; |
|
|
frp = arr; |
|
|
return arr; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static char* run_cut_fields_capture( |
|
|
const char *input, |
|
|
const uintmax_t (*pairs)[2], size_t npairs, |
|
|
unsigned char in_delim, |
|
|
const char *out_delim_str, |
|
|
bool only_delimited) |
|
|
{ |
|
|
|
|
|
suppress_non_delimited = only_delimited; |
|
|
|
|
|
|
|
|
delim = in_delim; |
|
|
|
|
|
|
|
|
output_delimiter_default[0] = delim; |
|
|
if (out_delim_str == NULL) { |
|
|
output_delimiter_string = output_delimiter_default; |
|
|
output_delimiter_length = 1; |
|
|
} else { |
|
|
output_delimiter_string = (char*)out_delim_str; |
|
|
output_delimiter_length = strlen(out_delim_str); |
|
|
} |
|
|
|
|
|
|
|
|
line_delim = '\n'; |
|
|
|
|
|
|
|
|
struct field_range_pair *local_frp = set_frp_from_pairs(pairs, npairs); |
|
|
if (!local_frp) { |
|
|
|
|
|
char *empty = (char*)malloc(1); |
|
|
if (empty) empty[0] = '\0'; |
|
|
return empty; |
|
|
} |
|
|
|
|
|
|
|
|
FILE *in = tmpfile(); |
|
|
if (!in) { |
|
|
free(local_frp); |
|
|
char *empty = (char*)malloc(1); |
|
|
if (empty) empty[0] = '\0'; |
|
|
return empty; |
|
|
} |
|
|
if (input && *input) { |
|
|
fwrite(input, 1, strlen(input), in); |
|
|
} |
|
|
fflush(in); |
|
|
fseek(in, 0, SEEK_SET); |
|
|
|
|
|
|
|
|
fflush(stdout); |
|
|
int saved_stdout_fd = dup(fileno(stdout)); |
|
|
FILE *cap = tmpfile(); |
|
|
if (cap == NULL) { |
|
|
fclose(in); |
|
|
free(local_frp); |
|
|
char *empty = (char*)malloc(1); |
|
|
if (empty) empty[0] = '\0'; |
|
|
return empty; |
|
|
} |
|
|
dup2(fileno(cap), fileno(stdout)); |
|
|
clearerr(stdout); |
|
|
|
|
|
|
|
|
cut_fields(in); |
|
|
|
|
|
|
|
|
fflush(stdout); |
|
|
dup2(saved_stdout_fd, fileno(stdout)); |
|
|
close(saved_stdout_fd); |
|
|
|
|
|
|
|
|
fflush(cap); |
|
|
fseek(cap, 0, SEEK_END); |
|
|
long sz = ftell(cap); |
|
|
if (sz < 0) sz = 0; |
|
|
fseek(cap, 0, SEEK_SET); |
|
|
char *out = (char*)malloc((size_t)sz + 1); |
|
|
if (!out) { |
|
|
out = (char*)malloc(1); |
|
|
if (out) out[0] = '\0'; |
|
|
} else { |
|
|
size_t nread = fread(out, 1, (size_t)sz, cap); |
|
|
out[nread] = '\0'; |
|
|
} |
|
|
|
|
|
|
|
|
fclose(cap); |
|
|
fclose(in); |
|
|
free(local_frp); |
|
|
|
|
|
return out; |
|
|
} |
|
|
|
|
|
void setUp(void) { |
|
|
|
|
|
suppress_non_delimited = false; |
|
|
|
|
|
delim = '\t'; |
|
|
line_delim = '\n'; |
|
|
output_delimiter_default[0] = delim; |
|
|
output_delimiter_string = output_delimiter_default; |
|
|
output_delimiter_length = 1; |
|
|
} |
|
|
|
|
|
void tearDown(void) { |
|
|
|
|
|
if (field_1_buffer) { |
|
|
free(field_1_buffer); |
|
|
field_1_buffer = NULL; |
|
|
field_1_bufsize = 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void test_cut_fields_basic_selection_default_delim(void) { |
|
|
const char *input = "a\tb\tc\n1\t2\t3\n"; |
|
|
const uintmax_t pairs[][2] = { {2,3} }; |
|
|
char *out = run_cut_fields_capture(input, pairs, 1, '\t', NULL, false); |
|
|
TEST_ASSERT_NOT_NULL(out); |
|
|
TEST_ASSERT_EQUAL_STRING("b\tc\n2\t3\n", out); |
|
|
free(out); |
|
|
} |
|
|
|
|
|
|
|
|
void test_cut_fields_nondelimited_without_s(void) { |
|
|
const char *input = "abc\n"; |
|
|
const uintmax_t pairs[][2] = { {2,2} }; |
|
|
char *out = run_cut_fields_capture(input, pairs, 1, ',', NULL, false); |
|
|
TEST_ASSERT_NOT_NULL(out); |
|
|
TEST_ASSERT_EQUAL_STRING("abc\n", out); |
|
|
free(out); |
|
|
} |
|
|
|
|
|
|
|
|
void test_cut_fields_nondelimited_with_s(void) { |
|
|
const char *input = "abc\n"; |
|
|
const uintmax_t pairs[][2] = { {1,1} }; |
|
|
char *out = run_cut_fields_capture(input, pairs, 1, ',', NULL, true); |
|
|
TEST_ASSERT_NOT_NULL(out); |
|
|
TEST_ASSERT_EQUAL_STRING("", out); |
|
|
free(out); |
|
|
} |
|
|
|
|
|
|
|
|
void test_cut_fields_custom_output_delimiter(void) { |
|
|
const char *input = "a,b,c\nx,y,z\n"; |
|
|
const uintmax_t pairs[][2] = { {1,1}, {3,3} }; |
|
|
char *out = run_cut_fields_capture(input, pairs, 2, ',', ":", false); |
|
|
TEST_ASSERT_NOT_NULL(out); |
|
|
TEST_ASSERT_EQUAL_STRING("a:c\nx:z\n", out); |
|
|
free(out); |
|
|
} |
|
|
|
|
|
|
|
|
void test_cut_fields_missing_field_produces_empty_line(void) { |
|
|
const char *input = "a,b\nx,y\n"; |
|
|
const uintmax_t pairs[][2] = { {3,3} }; |
|
|
char *out = run_cut_fields_capture(input, pairs, 1, ',', NULL, false); |
|
|
TEST_ASSERT_NOT_NULL(out); |
|
|
TEST_ASSERT_EQUAL_STRING("\n\n", out); |
|
|
free(out); |
|
|
} |
|
|
|
|
|
|
|
|
void test_cut_fields_no_trailing_newline(void) { |
|
|
const char *input = "a,b,c"; |
|
|
const uintmax_t pairs[][2] = { {2,2} }; |
|
|
char *out = run_cut_fields_capture(input, pairs, 1, ',', NULL, false); |
|
|
TEST_ASSERT_NOT_NULL(out); |
|
|
TEST_ASSERT_EQUAL_STRING("b\n", out); |
|
|
free(out); |
|
|
} |
|
|
|
|
|
|
|
|
void test_cut_fields_empty_selected_field(void) { |
|
|
const char *input = "a,,c\n"; |
|
|
const uintmax_t pairs[][2] = { {2,2} }; |
|
|
char *out = run_cut_fields_capture(input, pairs, 1, ',', NULL, false); |
|
|
TEST_ASSERT_NOT_NULL(out); |
|
|
TEST_ASSERT_EQUAL_STRING("\n", out); |
|
|
free(out); |
|
|
} |
|
|
|
|
|
int main(void) { |
|
|
UNITY_BEGIN(); |
|
|
RUN_TEST(test_cut_fields_basic_selection_default_delim); |
|
|
RUN_TEST(test_cut_fields_nondelimited_without_s); |
|
|
RUN_TEST(test_cut_fields_nondelimited_with_s); |
|
|
RUN_TEST(test_cut_fields_custom_output_delimiter); |
|
|
RUN_TEST(test_cut_fields_missing_field_produces_empty_line); |
|
|
RUN_TEST(test_cut_fields_no_trailing_newline); |
|
|
RUN_TEST(test_cut_fields_empty_selected_field); |
|
|
return UNITY_END(); |
|
|
} |