added writing capacilities to files and made the appropriate changes to the filedemo.c file

This commit is contained in:
Odweta
2023-12-23 18:28:58 +01:00
parent b9c93116bc
commit 0c68944a1d
9 changed files with 172 additions and 96 deletions
+6 -6
View File
@@ -2,7 +2,7 @@
I got bored with having to use complicated checking and stuff when working with files and arrays in C, so I implemented a new `file_t` struct which can load the contents of a file into a dynamically allocated array (yes, there is an implementation of those here as well... (`vector_t` struct)). The struct also stores the number of lines the file has. I got bored with having to use complicated checking and stuff when working with files and arrays in C, so I implemented a new `file_t` struct which can load the contents of a file into a dynamically allocated array (yes, there is an implementation of those here as well... (`vector_t` struct)). The struct also stores the number of lines the file has.
Also, I managed to come up with an implementation of a Python-like list (a vector of vectors of any type interpreted as just one vector). Quite handy, I'd say. The `list_t` struct is what you want to use when working with lists. Also, I managed to come up with an implementation of a kind-of-Python-like list (a vector of vectors of any type interpreted as just one vector). Quite handy, I'd say. The `list_t` struct is what you want to use when working with lists.
The difference between a `vector_t` and a `list_t` is that a vector can only be of one type, whereas a list can have values of any type inside it (in this context, any means types defined in this library and default types in C). The difference between a `vector_t` and a `list_t` is that a vector can only be of one type, whereas a list can have values of any type inside it (in this context, any means types defined in this library and default types in C).
@@ -22,8 +22,7 @@ Examples of this work of art are in the `/examples/` directory of this repo.
3. Copy a file to another file 3. Copy a file to another file
4. Move a file to another file 4. Move a file to another file
5. Rename a file 5. Rename a file
6. Delete a file 6. Delete a file?
7. Empty a file
8. Add line numbers at the beggining of each line in a file 8. Add line numbers at the beggining of each line in a file
+ You tell me + You tell me
@@ -44,6 +43,7 @@ Examples of this work of art are in the `/examples/` directory of this repo.
1. Removing an element at a given index 1. Removing an element at a given index
2. Vectors of lists 2. Vectors of lists
3. Remove a value at a given index
+ You tell me + You tell me
@@ -67,10 +67,10 @@ Examples of this work of art are in the `/examples/` directory of this repo.
## Installation ## Installation
`git clone https://gitlab.com/Odweta/odwetalibc.git` `git clone https://gitlab.com/Odweta/odwetalibc.git && cd odwetalibc && make install`
`cd odwetalibc`
`make install`
#### Run demo #### Run demo
(the library has to be installed with `make install`)
`make && ./demo` `make && ./demo`
+15 -12
View File
@@ -1,21 +1,24 @@
#include <odweta/vector.h> #include <odweta/file.h>
#include <stdio.h> #include <stdio.h>
int main() { int main() {
printf("creating a vector using 'vectorInit(<type>)' (returns a vector_t*)\npossible type are: INT, FLOAT, CHAR, VECTOR (LIST in the future)\n"); printf("creating a file using 'fileInit(<filename>)' (returns a file_t*)\n");
vector_t* v = vectorInit(INT); file_t* f = fileInit("test.txt");
printf("pushing an integer value into the vector\nnote the kind of unusual way of passing the number argument: if you want to pass an expression (e.g. the value '1' or '4*4'), something not stored in a variable, you follow this syntax - &(type){value} (e.g. &(int){1 + 1})\n->'vectorPush(vector_t*, &(int){123})'\n"); printf("printing the file contents\n\n");
vectorPush(v, &(int){123}); filePrint(f);
vectorPrint(v);
printf("popping the last value of the vector; in this case, it is an integer, so you type: 'int poppedValue = *((int *)vectorPop(vector_t*))'\n"); printf("\nconvering the file contents into a string (char*)\n");
int poppedValue = *((int *)vectorPop(v)); char* string = fileToString(f);
printf("popped: %d\n", poppedValue); printf("\"%s\"\n", string);
vectorPrint(v);
printf("if you are finished working with the vector BEFORE the immediate end of the program, run 'vectorCleanup(vector_t*)', otherwise it is not strictly necessary\n"); printf("writing is quite simple, just call the 'fileWrite(file_t*, char*)' or 'fileWriteln(file_t*, char*)' function, where the second argument is the string you want to write into a file\nthe 'fileWriteln()' function writes the specified string AND a '\\n' after it, whereas the 'fileWrite()' function does not append the '\\n'\n");
vectorCleanup(v); fileWrite(f, "'this will not end with a \"\\n\"' ");
fileWriteln(f, "this line was appended");
filePrint(f);
printf("if you are finished working with the file BEFORE the immediate end of the program, run 'fileCleanup(file_t*)', otherwise it is not strictly necessary\nit will, though, append a '\\n' at the end of the file if you have not done so, making writing into files more consistent, so for this reason, I recommend you use it with every file_t*\n");
fileCleanup(f);
return 0; return 0;
} }
+5 -2
View File
@@ -12,9 +12,12 @@ int main() {
char* string = fileToString(f); char* string = fileToString(f);
printf("\"%s\"\n", string); printf("\"%s\"\n", string);
// TODO -> writing, clearing printf("writing is quite simple, just call the 'fileWrite(file_t*, char*)' or 'fileWriteln(file_t*, char*)' function, where the second argument is the string you want to write into a file\nthe 'fileWriteln()' function writes the specified string AND a '\\n' after it, whereas the 'fileWrite()' function does not append the '\\n'\n");
fileWrite(f, "'this will not end with a \"\\n\"' ");
fileWriteln(f, "this line was appended");
filePrint(f);
printf("if you are finished working with the file BEFORE the immediate end of the program, run 'fileCleanup(file_t*)', otherwise it is not strictly necessary\n"); printf("if you are finished working with the file BEFORE the immediate end of the program, run 'fileCleanup(file_t*)', otherwise it is not strictly necessary\nit will, though, append a '\\n' at the end of the file if you have not done so, making writing into files more consistent, so for this reason, I recommend you use it with every file_t*\n");
fileCleanup(f); fileCleanup(f);
return 0; return 0;
+4 -5
View File
@@ -4,9 +4,10 @@
#include <odweta/vector.h> #include <odweta/vector.h>
typedef struct { typedef struct {
char* path; // the file descriptor char* path; // the file descriptor
int length; // line count int length; // line count
vector_t* lines; // 2d array of chars vector_t* lines; // 2d array of chars
int not_newline_terminated; // bool: 1 = true, 0 = false
} file_t; } file_t;
file_t* fileInit(char* path); // initialization function file_t* fileInit(char* path); // initialization function
@@ -21,6 +22,4 @@ void fileWriteln(file_t* f, char* payload); // appends a given string to the fil
void fileWrite(file_t* f, char* payload); // appends a given string to the file (not on a newline!) void fileWrite(file_t* f, char* payload); // appends a given string to the file (not on a newline!)
void fileClear(file_t* f); // wipes the file contents
#endif #endif
+4 -4
View File
@@ -4,10 +4,10 @@
typedef long unsigned int size_t; typedef long unsigned int size_t;
typedef enum { typedef enum {
INT, INT = 0,
FLOAT, FLOAT = 1,
CHAR, CHAR = 2,
VECTOR // allows for multi-dimensional arrays VECTOR = 3 // allows for multi-dimensional arrays
} dataType_e; } dataType_e;
typedef struct { typedef struct {
+94 -28
View File
@@ -9,6 +9,10 @@ fileCountLines(file_t* f) {
char ch; char ch;
int lines = 0; int lines = 0;
FILE* fd = fopen(f->path, "r"); FILE* fd = fopen(f->path, "r");
if (!fd) {
fprintf(stderr, "unable to open file");
exit(EXIT_FAILURE);
}
while ((ch = fgetc(fd)) != EOF) { while ((ch = fgetc(fd)) != EOF) {
if (ch == '\n') { if (ch == '\n') {
@@ -22,25 +26,43 @@ fileCountLines(file_t* f) {
} }
void void
_fileLoadLines(file_t* f, FILE* fd) { _fileLoadLines(file_t* f) {
int lineLength;
char ch; char ch;
vector_t* line = vectorInit(CHAR);
FILE* fd = fopen(f->path, "r");
if (!fd) {
fprintf(stderr, "unable to open file %s with mode \"r\"\n", f->path);
fclose(fd);
fileCleanup(f);
exit(EXIT_FAILURE);
}
char prev;
for (int i = 0; i < f->length; i++) { for (int i = 0; i < f->length; i++) {
vector_t* line = vectorInit(CHAR); // Create a new vector for each line
while ((ch = fgetc(fd)) != '\n' && ch != EOF) { while ((ch = fgetc(fd)) != '\n' && ch != EOF) {
vectorPush(line, &ch); vectorPush(line, &ch);
} }
// Skip the newline character if it exists // Skip the newline character if it exists
if (ch == '\n') { if (ch == '\n') {
char* empty = ""; char* empty = "";
vectorPush(line, empty); vectorPush(line, empty);
} }
vectorPush(f->lines, line); vectorPush(f->lines, line);
line = vectorInit(CHAR);
prev = ch;
// Don't free the line vector here, as it's now owned by the f->lines vector
} }
if (prev != '\n') {
f->not_newline_terminated = 1; // \n is NOT at the end of a file
} else {
f->not_newline_terminated = 0; // \n IS at the end of a file
}
fclose(fd);
} }
char* char*
@@ -51,47 +73,91 @@ fileToString(file_t* f) {
file_t* file_t*
fileInit(char* path) { fileInit(char* path) {
file_t* f = malloc(sizeof(file_t)); file_t* f = malloc(sizeof(file_t));
if (f == NULL) { if (!f) {
perror("failed to allocate memory for the file\n"); fprintf(stderr, "failed to allocate memory for the file\n");
exit(EXIT_FAILURE);
}
f->lines = malloc(sizeof(vector_t));
if (f->lines == NULL) {
perror("failed to allocate memory for the file contents vector\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
f->path = path; f->path = path;
FILE* fd = fopen(f->path, "r");
if (fd == NULL) {
fprintf(stderr, "unable to open file %s with mode \"r\"\n", path);
fclose(fd);
fileCleanup(f);
exit(EXIT_FAILURE);
}
f->length = fileCountLines(f); f->length = fileCountLines(f);
f->lines = vectorInit(VECTOR); // vector of vectors of chars = vector of strings
_fileLoadLines(f, fd);
fclose(fd); f->lines = vectorInit(VECTOR); // vector of vectors of chars = vector of strings
_fileLoadLines(f);
return f; return f;
} }
void void
fileCleanup(file_t* f) { fileCleanup(file_t* f) {
if (f->not_newline_terminated == 1) {
FILE* fd = fopen(f->path, "a");
fprintf(fd, "\n");
fclose(fd);
f->not_newline_terminated = 0; // just for piece of mind
}
vectorCleanup(f->lines); vectorCleanup(f->lines);
free(f); free(f);
} }
void void
filePrint(file_t* f) { filePrint(file_t* f) {
vector_t* line = vectorInit(CHAR);
for (int i = 0; i < f->length; i++) { for (int i = 0; i < f->length; i++) {
line = (vector_t *)vectorGetAt(f->lines, i); vectorPrintAsString((vector_t *)vectorGetAt(f->lines, i));
vectorPrintAsString(line);
} }
} }
void
fileWriteln(file_t* f, char* payload) {
FILE* fd = fopen(f->path, "a");
if (!fd) {
fprintf(stderr, "unable to open file %s with mode \"a\"\n", f->path);
fclose(fd);
fileCleanup(f);
exit(EXIT_FAILURE);
}
fprintf(fd, "%s\n", payload);
fclose(fd);
// Update the file structure without re-initializing
if (f->not_newline_terminated == 0) {
vector_t* line = vectorInit(CHAR);
for (int i = 0; i < strlen(payload); i++) {
vectorPush(line, &payload[i]);
}
vectorPush(f->lines, line);
f->length++;
f->not_newline_terminated = 0;
} else if (f->not_newline_terminated == 1) {
for (int i = 0; i < strlen(payload); i++) {
vectorPush((vector_t *)vectorGetAt(f->lines, f->length-1), &payload[i]);
}
f->not_newline_terminated = 0;
}
}
void
fileWrite(file_t* f, char* payload) {
FILE* fd = fopen(f->path, "a");
if (!fd) {
fprintf(stderr, "unable to open file %s with mode \"a\"\n", f->path);
fclose(fd);
fileCleanup(f);
exit(EXIT_FAILURE);
}
fprintf(fd, "%s", payload);
fclose(fd);
// Update the file structure without re-initializing
vector_t* line = vectorInit(CHAR);
for (int i = 0; i < strlen(payload); i++) {
vectorPush(line, &payload[i]);
}
vectorPush(f->lines, line);
f->length++;
f->not_newline_terminated = 1;
}
+1 -1
View File
@@ -49,7 +49,7 @@ listPush(list_t* l, dataType_e type, void* element) {
vectorPush((vector_t *)l->data, newVec); vectorPush((vector_t *)l->data, newVec);
break; break;
default: default:
perror("specify a valid vector type\n"); fprintf(stderr, "specify a valid vector type\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
+25 -20
View File
@@ -38,7 +38,7 @@ _printVectorRecursive(vector_t* v, int depth) {
_printVectorRecursive((vector_t *)(v->data + i * v->elementSize), depth + 1); _printVectorRecursive((vector_t *)(v->data + i * v->elementSize), depth + 1);
break; break;
default: default:
perror("tried to print unsupported data type\n"); fprintf(stderr, "tried to print unsupported data type\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@@ -74,7 +74,7 @@ vectorPrint(vector_t* v) {
_printVectorRecursive((vector_t *)(v->data + i * v->elementSize), 0); _printVectorRecursive((vector_t *)(v->data + i * v->elementSize), 0);
break; break;
default: default:
perror("tried to print unsupported data type\n"); fprintf(stderr, "tried to print unsupported data type\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@@ -103,7 +103,7 @@ _printVectorAsStringRecursive(vector_t* v, int depth) {
_printVectorAsStringRecursive((vector_t *)(v->data + i * v->elementSize), depth + 1); _printVectorAsStringRecursive((vector_t *)(v->data + i * v->elementSize), depth + 1);
break; break;
default: default:
perror("tried to print a non-char type vector as string\n"); fprintf(stderr, "tried to print a non-char type vector as string\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
@@ -123,7 +123,7 @@ vectorPrintAsString(vector_t* v) {
_printVectorAsStringRecursive(v, 0); _printVectorAsStringRecursive(v, 0);
break; break;
default: default:
perror("tried to print a non-char type vector as string\n"); fprintf(stderr, "tried to print a non-char type vector as string | type: %d\n", v->type);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
@@ -131,8 +131,8 @@ vectorPrintAsString(vector_t* v) {
vector_t* vector_t*
vectorInit(dataType_e type) { vectorInit(dataType_e type) {
vector_t *v = malloc(sizeof(vector_t)); vector_t *v = malloc(sizeof(vector_t));
if (v == NULL) { if (!v) {
perror("failed to allocate memory for the vector\n"); fprintf(stderr, "failed to allocate memory for the vector\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@@ -153,13 +153,13 @@ vectorInit(dataType_e type) {
v->elementSize = sizeof(vector_t); v->elementSize = sizeof(vector_t);
break; break;
default: default:
perror("specify a valid vector type\n"); fprintf(stderr, "specify a valid vector type\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
v->data = malloc(v->elementSize * v->capacity); v->data = malloc(v->elementSize * v->capacity);
if (v->data == NULL) { if (v->data == NULL) {
perror("failed to allocate memory for vector data\n"); fprintf(stderr, "failed to allocate memory for vector data\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@@ -176,28 +176,33 @@ vectorPush(vector_t* v, void* element) {
*((float *)(v->data) + v->size) = *((float *)element); *((float *)(v->data) + v->size) = *((float *)element);
break; break;
case CHAR: case CHAR:
// Allocate memory for the character
v->data = realloc(v->data, (v->size + 1) * v->elementSize);
if (!v->data) {
fprintf(stderr, "failed to allocate memory for vector data\n");
exit(EXIT_FAILURE);
}
*((char *)(v->data) + v->size) = *((char *)element); *((char *)(v->data) + v->size) = *((char *)element);
break; break;
case VECTOR: case VECTOR:
// Instead of reallocating memory for vector_t pointers, allocate memory for the vector data // Instead of reallocating memory for vector_t pointers, allocate memory for the vector data
if (v->size == 0) { if (v->size == 0) {
// Allocate memory for the vector data for the first time // Allocate memory for the vector data for the first time
v->data = malloc(v->elementSize * v->capacity); v->data = realloc(v->data, v->elementSize);
} else { } else {
// Reallocate memory for the vector data // Reallocate memory for the vector data
v->data = realloc(v->data, v->elementSize * v->capacity); v->data = realloc(v->data, v->elementSize * (v->size + 1));
} }
if (v->data == NULL) { if (!v->data) {
perror("failed to allocate memory for vector data\n"); fprintf(stderr, "failed to allocate memory for vector data\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Copy the vector data from the element to the vector // Copy the vector data from the element to the vector
memcpy((vector_t *)(v->data) + v->size, (vector_t *)element, sizeof(vector_t)); memcpy((vector_t *)(v->data) + v->size, (vector_t *)element, sizeof(vector_t));
break; break;
default: default:
perror("specify a valid vector type\n"); fprintf(stderr, "specify a valid vector type\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@@ -239,7 +244,7 @@ vectorPop(vector_t* v) {
return vretval; return vretval;
default: default:
perror("specify a valid vector type\n"); fprintf(stderr, "specify a valid vector type\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@@ -312,7 +317,7 @@ vectorGetAt(vector_t* v, int index) {
case VECTOR: case VECTOR:
return (vector_t *)(v->data) + index; return (vector_t *)(v->data) + index;
default: default:
perror("specify a valid vector type\n"); fprintf(stderr, "specify a valid vector type\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
@@ -320,7 +325,7 @@ vectorGetAt(vector_t* v, int index) {
void void
vectorSetAt(vector_t* v, int index, void* element) { vectorSetAt(vector_t* v, int index, void* element) {
if (index >= v->size) { if (index >= v->size) {
perror("index out of range\n"); fprintf(stderr, "index out of range\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@@ -338,7 +343,7 @@ vectorSetAt(vector_t* v, int index, void* element) {
*((vector_t *)(v->data) + index) = *((vector_t *)element); *((vector_t *)(v->data) + index) = *((vector_t *)element);
break; break;
default: default:
perror("specify a valid vector type\n"); fprintf(stderr, "specify a valid vector type\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
@@ -346,7 +351,7 @@ vectorSetAt(vector_t* v, int index, void* element) {
void void
vectorInsertAt(vector_t* v, int index, void* element) { vectorInsertAt(vector_t* v, int index, void* element) {
if (index >= v->size) { if (index >= v->size) {
perror("index out of range\n"); fprintf(stderr, "index out of range\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@@ -384,7 +389,7 @@ vectorInsertAt(vector_t* v, int index, void* element) {
*((vector_t *)(v->data) + index) = *((vector_t *)element); *((vector_t *)(v->data) + index) = *((vector_t *)element);
break; break;
default: default:
perror("specify a valid vector type\n"); fprintf(stderr, "specify a valid vector type\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
+5 -5
View File
@@ -1,6 +1,6 @@
this !1@#% this is a test
is a big mega such large test
mega such large
test
and and
this was an empty line
!#%!@# <- symbols!