Cleanup by breaking up C impl to separate sources

This commit is contained in:
Stephen Seo 2022-03-24 16:04:16 +09:00
parent 2660e765c3
commit cd2ecb5c8f
8 changed files with 245 additions and 183 deletions

View file

@ -6,7 +6,10 @@ else
endif endif
SOURCES = \ SOURCES = \
src/main.o src/main.o \
src/argparse.o \
src/csventry.o \
src/strdlist.o
all: fields_from_csv all: fields_from_csv

33
c_impl/src/argparse.c Normal file
View file

@ -0,0 +1,33 @@
#include "argparse.h"
ParsedArgs parse_args(int argc, char **argv) {
// init
ParsedArgs args;
args.input_filename = NULL;
args.fields = create_strdlist();
args.usage_print = 0;
args.error = 0;
--argc;
++argv;
// get filename and field from args
if (argc > 1) {
args.input_filename = argv[0];
} else {
args.error = 1;
args.usage_print = 1;
}
--argc;
++argv;
while (argc > 0) {
append_strdlist(args.fields, argv[0]);
--argc;
++argv;
}
return args;
}
// vim: et: ts=2: sts=2: sw=2

16
c_impl/src/argparse.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef SEODISPARATE_FIELDS_FROM_CSV_ARG_PARSE_H_
#define SEODISPARATE_FIELDS_FROM_CSV_ARG_PARSE_H_
#include "strdlist.h"
typedef struct ParsedArgs {
const char *input_filename;
StrDList *fields;
int usage_print;
int error;
} ParsedArgs;
ParsedArgs parse_args(int argc, char **argv);
#endif
// vim: et: ts=2: sts=2: sw=2

64
c_impl/src/csventry.c Normal file
View file

@ -0,0 +1,64 @@
#include "csventry.h"
CSVEntry get_field(FILE *fd, size_t field_idx) {
size_t current_size = 512;
CSVEntry entry;
entry.is_end_of_line = 0;
entry.is_end_of_file = 0;
entry.is_chosen_field = 0;
entry.buf = NULL;
size_t idx = 0;
int next = fgetc(fd);
while (next != EOF) {
if (next == ',') {
break;
} else if (next == '\n') {
entry.is_end_of_line = 1;
break;
} else if (next == ' ' || next == '\t') {
next = fgetc(fd);
continue;
}
if (!entry.buf) {
// malloc of buf deferred to here in case a field reaches EOF
entry.buf = malloc(current_size);
}
entry.buf[idx++] = next;
if (idx >= current_size) {
current_size *= 2;
entry.buf = realloc(entry.buf, current_size);
}
next = fgetc(fd);
}
if (next == EOF) {
entry.is_end_of_file = 1;
}
if (entry.buf) {
if (idx >= current_size) {
current_size += 1;
entry.buf = realloc(entry.buf, current_size);
entry.buf[idx] = 0;
} else {
entry.buf[idx] = 0;
}
}
entry.idx = field_idx;
return entry;
}
void cleanup_csventry(CSVEntry *csvEntry, int nullify) {
if (csvEntry->buf) {
free(csvEntry->buf);
}
if (nullify) {
csvEntry->buf = NULL;
}
}
// vim: et: ts=2: sts=2: sw=2

19
c_impl/src/csventry.h Normal file
View file

@ -0,0 +1,19 @@
#ifndef SEODISPARATE_FIELDS_FROM_CSV_CSVENTRY_H_
#define SEODISPARATE_FIELDS_FROM_CSV_CSVENTRY_H_
#include <stdio.h>
#include <stdlib.h>
typedef struct CSVEntry {
char *buf;
size_t idx;
int is_end_of_line;
int is_end_of_file;
int is_chosen_field;
} CSVEntry;
CSVEntry get_field(FILE *fd, size_t field_idx);
void cleanup_csventry(CSVEntry *csvEntry, int nullify);
#endif
// vim: et: ts=2: sts=2: sw=2

View file

@ -2,18 +2,9 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
typedef struct StrDList { #include "argparse.h"
char *string; #include "csventry.h"
struct StrDList *next; #include "strdlist.h"
struct StrDList *prev;
} StrDList;
typedef struct ParsedArgs {
const char *input_filename;
StrDList *fields;
int usage_printed;
int error;
} ParsedArgs;
void usage() { void usage() {
puts( puts(
@ -21,176 +12,14 @@ void usage() {
"./fields_from_csv <input_csv> <field> [<field>...]\n"); "./fields_from_csv <input_csv> <field> [<field>...]\n");
} }
StrDList *create_strdlist() { return calloc(1, sizeof(StrDList)); }
void append_strdlist(StrDList *head, const char *string) {
StrDList *current = head;
while (current->next) {
current = current->next;
}
current->next = calloc(1, sizeof(StrDList));
current->next->prev = current;
size_t string_size = strlen(string);
current->next->string = malloc(string_size + 1);
memcpy(current->next->string, string, string_size);
current->next->string[string_size] = 0;
}
void cleanup_strdlist(StrDList **head) {
if (!head || !*head) {
return;
}
StrDList *current = *head;
while (current->next) {
current = current->next;
}
while (current->prev) {
current = current->prev;
if (current->next->string) {
free(current->next->string);
}
free(current->next);
current->next = NULL;
}
(*head)->next = NULL;
free(*head);
*head = NULL;
}
size_t print_and_count_strdlist(StrDList *head) {
size_t count = 0;
StrDList *current = head;
puts("Printing strdlist...");
while (current->next) {
current = current->next;
printf("%s ", current->string);
++count;
}
printf("\n");
return count;
}
int strdlist_has_str(StrDList *head, const char *str) {
StrDList *current = head;
int idx = 0;
while (current->next) {
current = current->next;
if (strcmp(current->string, str) == 0) {
return idx;
} else {
++idx;
}
}
return -1;
}
ParsedArgs parse_args(int argc, char **argv) {
// init
ParsedArgs args;
args.input_filename = NULL;
args.fields = create_strdlist();
args.usage_printed = 0;
args.error = 0;
--argc;
++argv;
// get filename and field from args
if (argc > 1) {
args.input_filename = argv[0];
} else {
args.error = 1;
usage();
args.usage_printed = 1;
}
--argc;
++argv;
while (argc > 0) {
append_strdlist(args.fields, argv[0]);
--argc;
++argv;
}
return args;
}
typedef struct CSVEntry {
char *buf;
size_t idx;
int is_end_of_line;
int is_end_of_file;
int is_chosen_field;
} CSVEntry;
CSVEntry get_field(FILE *fd, size_t field_idx) {
size_t current_size = 512;
CSVEntry entry;
entry.is_end_of_line = 0;
entry.is_end_of_file = 0;
entry.is_chosen_field = 0;
entry.buf = NULL;
size_t idx = 0;
int next = fgetc(fd);
while (next != EOF) {
if (next == ',') {
break;
} else if (next == '\n') {
entry.is_end_of_line = 1;
break;
} else if (next == ' ' || next == '\t') {
next = fgetc(fd);
continue;
}
if (!entry.buf) {
// malloc of buf deferred to here in case a field reaches EOF
entry.buf = malloc(current_size);
}
entry.buf[idx++] = next;
if (idx >= current_size) {
current_size *= 2;
entry.buf = realloc(entry.buf, current_size);
}
next = fgetc(fd);
}
if (next == EOF) {
entry.is_end_of_file = 1;
}
if (entry.buf) {
if (idx >= current_size) {
current_size += 1;
entry.buf = realloc(entry.buf, current_size);
entry.buf[idx] = 0;
} else {
entry.buf[idx] = 0;
}
}
entry.idx = field_idx;
return entry;
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
ParsedArgs args = parse_args(argc, argv); ParsedArgs args = parse_args(argc, argv);
if (args.error) { if (args.error) {
cleanup_strdlist(&args.fields); cleanup_strdlist(&args.fields);
return 1; return 1;
} else if (args.usage_printed) { } else if (args.usage_print) {
usage();
cleanup_strdlist(&args.fields); cleanup_strdlist(&args.fields);
return 0; return 0;
} }
@ -242,9 +71,7 @@ int main(int argc, char **argv) {
printf("%s, ", entry.buf); printf("%s, ", entry.buf);
} }
if (entry.buf) { cleanup_csventry(&entry, 1);
free(entry.buf);
}
if (entry.is_end_of_file) { if (entry.is_end_of_file) {
break; break;
@ -258,11 +85,11 @@ int main(int argc, char **argv) {
fclose(csv_fd); fclose(csv_fd);
for (size_t i = 0; i < number_of_entries; ++i) { for (size_t i = 0; i < number_of_entries; ++i) {
if (entries[i].buf) { cleanup_csventry(entries + i, 0);
free(entries[i].buf);
}
} }
free(entries); free(entries);
cleanup_strdlist(&args.fields); cleanup_strdlist(&args.fields);
return 0; return 0;
} }
// vim: et: ts=2: sts=2: sw=2

77
c_impl/src/strdlist.c Normal file
View file

@ -0,0 +1,77 @@
#include "strdlist.h"
#include <stdio.h>
#include <string.h>
StrDList *create_strdlist() { return calloc(1, sizeof(StrDList)); }
void append_strdlist(StrDList *head, const char *string) {
StrDList *current = head;
while (current->next) {
current = current->next;
}
current->next = calloc(1, sizeof(StrDList));
current->next->prev = current;
size_t string_size = strlen(string);
current->next->string = malloc(string_size + 1);
memcpy(current->next->string, string, string_size);
current->next->string[string_size] = 0;
}
void cleanup_strdlist(StrDList **head) {
if (!head || !*head) {
return;
}
StrDList *current = *head;
while (current->next) {
current = current->next;
}
while (current->prev) {
current = current->prev;
if (current->next->string) {
free(current->next->string);
}
free(current->next);
current->next = NULL;
}
(*head)->next = NULL;
free(*head);
*head = NULL;
}
size_t print_and_count_strdlist(StrDList *head) {
size_t count = 0;
StrDList *current = head;
puts("Printing strdlist...");
while (current->next) {
current = current->next;
printf("%s ", current->string);
++count;
}
printf("\n");
return count;
}
int strdlist_has_str(StrDList *head, const char *str) {
StrDList *current = head;
int idx = 0;
while (current->next) {
current = current->next;
if (strcmp(current->string, str) == 0) {
return idx;
} else {
++idx;
}
}
return -1;
}
// vim: et: ts=2: sts=2: sw=2

23
c_impl/src/strdlist.h Normal file
View file

@ -0,0 +1,23 @@
#ifndef SEODISPARATE_FIELDS_FROM_CSV_STRDLIST_H_
#define SEODISPARATE_FIELDS_FROM_CSV_STRDLIST_H_
#include <stdlib.h>
typedef struct StrDList {
char *string;
struct StrDList *next;
struct StrDList *prev;
} StrDList;
StrDList *create_strdlist();
void append_strdlist(StrDList *head, const char *string);
void cleanup_strdlist(StrDList **head);
size_t print_and_count_strdlist(StrDList *head);
int strdlist_has_str(StrDList *head, const char *str);
#endif
// vim: et: ts=2: sts=2: sw=2