254 lines
5.9 KiB
C
254 lines
5.9 KiB
C
#include <odweta/file.h>
|
|
#include <odweta/vector.h>
|
|
#include <odweta/util.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
int file_count_lines(file_t *self) {
|
|
char ch;
|
|
int lines = 0;
|
|
|
|
FILE *fd = fopen(self->path, "r");
|
|
if (fd == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
while ((ch = fgetc(fd)) != EOF) {
|
|
if (ch == '\n') {
|
|
lines++;
|
|
}
|
|
}
|
|
|
|
fclose(fd);
|
|
|
|
return lines;
|
|
}
|
|
|
|
void _file_load_lines(file_t *self) {
|
|
char ch;
|
|
|
|
FILE *fd = fopen(self->path, "r");
|
|
if (fd == NULL) {
|
|
fclose(fd);
|
|
file_cleanup(self);
|
|
return;
|
|
}
|
|
|
|
char prev;
|
|
for (int i = 0; i < self->length; i++) {
|
|
vector_t *line = vector_new(CHAR); // Create a new vector for each line
|
|
|
|
while ((ch = fgetc(fd)) != '\n' && ch != EOF) {
|
|
vector_push(line, &ch);
|
|
}
|
|
|
|
// Skip the newline character if it exists
|
|
if (ch == '\n') {
|
|
char *empty = "";
|
|
vector_push(line, empty);
|
|
}
|
|
|
|
vector_push(self->lines, line);
|
|
|
|
prev = ch;
|
|
// Don't free the line vector here, as it's now owned by the self->lines vector
|
|
}
|
|
if (prev != '\n') {
|
|
self->not_newline_terminated = 1; // \n is NOT at the end of a file
|
|
} else {
|
|
self->not_newline_terminated = 0; // \n IS at the end of a file
|
|
}
|
|
|
|
fclose(fd);
|
|
}
|
|
|
|
char *file_to_string(file_t *self) {
|
|
return vector_to_string(self->lines);
|
|
}
|
|
|
|
bool_t file_exists(file_t *self) {
|
|
FILE *fd = fopen(self->path, "r");
|
|
|
|
bool_t retval = (fd == NULL) ? FALSE : TRUE;
|
|
|
|
fclose(fd);
|
|
|
|
return retval;
|
|
}
|
|
|
|
void file_create(char *path) {
|
|
fclose(fopen(path, "w"));
|
|
}
|
|
|
|
file_t *file_new(char *path) {
|
|
file_t *self = (file_t *)malloc(sizeof(file_t));
|
|
if (self == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
self->path = path;
|
|
|
|
if (file_exists(self) == FALSE) {
|
|
// if file 'self' does not exist
|
|
file_create(self->path);
|
|
return file_new(self->path);
|
|
}
|
|
|
|
self->length = file_count_lines(self);
|
|
|
|
self->lines = vector_new(VECTOR); // vector of vectors of chars = vector of strings
|
|
_file_load_lines(self);
|
|
|
|
return self;
|
|
}
|
|
|
|
void file_cleanup(file_t *self) {
|
|
if (self->not_newline_terminated == 1) {
|
|
FILE *fd = fopen(self->path, "a");
|
|
fprintf(fd, "\n");
|
|
fclose(fd);
|
|
self->not_newline_terminated = 0; // just for piece of mind
|
|
}
|
|
|
|
vector_cleanup(self->lines);
|
|
free(self);
|
|
}
|
|
|
|
void file_print(file_t *self) {
|
|
for (int i = 0; i < self->length; i++) {
|
|
vector_print_as_string((vector_t *)vector_get_at(self->lines, i));
|
|
}
|
|
}
|
|
|
|
void file_writeln(file_t *self, char *payload) {
|
|
FILE *fd = fopen(self->path, "a");
|
|
if (fd == NULL) {
|
|
fclose(fd);
|
|
file_cleanup(self);
|
|
return;
|
|
}
|
|
|
|
fprintf(fd, "%s\n", payload);
|
|
|
|
fclose(fd);
|
|
|
|
// Update the file structure without re-initializing
|
|
if (self->not_newline_terminated == 0) {
|
|
vector_t *line = vector_new(CHAR);
|
|
for (int i = 0; i < strlen(payload); i++) {
|
|
vector_push(line, &payload[i]);
|
|
}
|
|
vector_push(self->lines, line);
|
|
self->length++;
|
|
self->not_newline_terminated = 0;
|
|
} else if (self->not_newline_terminated == 1) {
|
|
for (int i = 0; i < strlen(payload); i++) {
|
|
vector_push((vector_t *)vector_get_at(self->lines, self->length-1), &payload[i]);
|
|
}
|
|
self->not_newline_terminated = 0;
|
|
}
|
|
}
|
|
|
|
void file_write(file_t *self, char *payload) {
|
|
FILE *fd = fopen(self->path, "a");
|
|
if (fd) {
|
|
fprintf(stderr, "unable to open file %s with mode \"a\"\n", self->path);
|
|
fclose(fd);
|
|
file_cleanup(self);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
fprintf(fd, "%s", payload);
|
|
|
|
fclose(fd);
|
|
|
|
// Update the file structure without re-initializing
|
|
vector_t *line = vector_new(CHAR);
|
|
for (int i = 0; i < strlen(payload); i++) {
|
|
vector_push(line, &payload[i]);
|
|
}
|
|
vector_push(self->lines, line);
|
|
self->length++;
|
|
self->not_newline_terminated = 1;
|
|
}
|
|
|
|
void file_copy(file_t *src, char *dst) {
|
|
FILE *fd = fopen(dst, "w");
|
|
if (fd == NULL) {
|
|
fclose(fd);
|
|
return;
|
|
}
|
|
|
|
char ch;
|
|
for (int i = 0; i < src->length; i++) {
|
|
for (int j = 0; j < ((vector_t *)vector_get_at(src->lines, i))->size; j++) {
|
|
ch = *((char *)vector_get_at((vector_t *)vector_get_at(src->lines, i), j));
|
|
fprintf(fd, "%c", ch);
|
|
}
|
|
fprintf(fd, "\n");
|
|
}
|
|
|
|
fclose(fd);
|
|
}
|
|
|
|
void file_delete(file_t *self) {
|
|
if (remove(self->path) == 0)
|
|
file_cleanup(self);
|
|
}
|
|
|
|
void file_move(file_t *src, char *dst) {
|
|
file_copy(src, dst);
|
|
|
|
file_delete(src);
|
|
}
|
|
|
|
void file_number_lines(file_t *self) {
|
|
FILE *fd = fopen(self->path, "w");
|
|
if (fd == NULL) {
|
|
fclose(fd);
|
|
return;
|
|
}
|
|
|
|
int mlp = max_lower_power_of_10(self->length);
|
|
|
|
for (int i = 0; i < self->length; i++) {
|
|
// print to the file descriptor
|
|
fprintf(fd, "%d %s\n", i+1, vector_to_string((vector_t *)vector_get_at(self->lines, i)));
|
|
|
|
// print to self->lines
|
|
vector_insert_at((vector_t*)vector_get_at(self->lines, i), 0, &(char){' '});
|
|
char *string = int_to_string(i+1);
|
|
for (int j = strlen(string)-1; j >= 0; j--) {
|
|
vector_insert_at((vector_t*)vector_get_at(self->lines, i), 0, &(char){string[j]});
|
|
}
|
|
|
|
// prepend the correct amount of ' '
|
|
for (int j = 0; j < strlen(int_to_string(mlp))-strlen(int_to_string(i+1)); j++) {
|
|
vector_insert_at((vector_t*)vector_get_at(self->lines, i), 0, &(char){' '});
|
|
}
|
|
}
|
|
|
|
fclose(fd);
|
|
}
|
|
|
|
int file_count_words(file_t *self) {
|
|
int num_words = 0;
|
|
char prev;
|
|
for (int i = 0; i < self->length; i++) {
|
|
for (int j = 0; j < ((vector_t*)vector_get_at(self->lines, i))->size; j++) {
|
|
char ch = *((char*)vector_get_at((vector_t*)vector_get_at(self->lines, i), j));
|
|
if (
|
|
(ch == ' ' && prev != ' ') ||
|
|
(i == self->length-1 && j == ((vector_t*)vector_get_at(self->lines, i))->size-1) ||
|
|
(j == ((vector_t*)vector_get_at(self->lines, i))->size-1 && j != 0)
|
|
) {
|
|
num_words++;
|
|
}
|
|
prev = ch;
|
|
}
|
|
}
|
|
|
|
return num_words;
|
|
}
|