#include #include #include #include #include #include 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; }