Cleanup by breaking up C impl to separate sources
This commit is contained in:
parent
2660e765c3
commit
cd2ecb5c8f
8 changed files with 245 additions and 183 deletions
|
@ -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
33
c_impl/src/argparse.c
Normal 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
16
c_impl/src/argparse.h
Normal 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
64
c_impl/src/csventry.c
Normal 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
19
c_impl/src/csventry.h
Normal 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
|
|
@ -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
77
c_impl/src/strdlist.c
Normal 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
23
c_impl/src/strdlist.h
Normal 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
|
Loading…
Reference in a new issue