diff --git a/phase_1/bonus/main.c b/phase1/bonus/main.c similarity index 100% rename from phase_1/bonus/main.c rename to phase1/bonus/main.c diff --git a/phase_1/obligatory/strlen.c b/phase1/obligatory/strlen.c similarity index 100% rename from phase_1/obligatory/strlen.c rename to phase1/obligatory/strlen.c diff --git a/phase2/test.txt b/phase2/test.txt new file mode 100644 index 0000000..b0d962c --- /dev/null +++ b/phase2/test.txt @@ -0,0 +1,3 @@ +Hi ! +How are you ! +I am fine thanks! diff --git a/phase2/test2.txt b/phase2/test2.txt new file mode 100644 index 0000000..1128f3d --- /dev/null +++ b/phase2/test2.txt @@ -0,0 +1,197 @@ +Lorem ipsum dolor sit amet, consectetuer adipiscing elit. + +Aenean commodo ligula eget dolor. Aenean massa. + +Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. + +Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. + +Nulla consequat massa quis enim. + +Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. + +In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. + +Nullam dictum felis eu pede mollis pretium. + +Integer tincidunt. Cras dapibus. + +Vivamus elementum semper nisi. + +Aenean vulputate eleifend tellus. + +Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. + +Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. + +Phasellus viverra nulla ut metus varius laoreet. + +Quisque rutrum. Aenean imperdiet. + +Etiam ultricies nisi vel augue. + +Curabitur ullamcorper ultricies nisi. Nam eget dui. + +Etiam rhoncus. + +Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque sed ipsum. + +Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem. + +Maecenas nec odio et ante tincidunt tempus. + +Donec vitae sapien ut libero venenatis faucibus. + +Nullam quis ante. + +Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. + +Sed fringilla mauris sit amet nibh. Donec sodales sagittis magna. + +Sed consequat, leo eget bibendum sodales, augue velit cursus nunc, quis gravida magna mi a libero. + +Fusce vulputate eleifend sapien. + +Vestibulum purus quam, scelerisque ut, mollis sed, nonummy id, metus. + +Nullam accumsan lorem in dui. + +Cras ultricies mi eu turpis hendrerit fringilla. + +Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; In ac dui quis mi consectetuer lacinia. + +Nam pretium turpis et arcu. + +Duis arcu tortor, suscipit eget, imperdiet nec, imperdiet iaculis, ipsum. + +Sed aliquam ultrices mauris. + +Integer ante arcu, accumsan a, consectetuer eget, posuere ut, mauris. + +Praesent adipiscing. Phasellus ullamcorper ipsum rutrum nunc. + +Nunc nonummy metus. Vestibulum volutpat pretium libero. + +Cras id dui. Aenean ut eros et nisl sagittis vestibulum. + +Nullam nulla eros, ultricies sit amet, nonummy id, imperdiet feugiat, pede. + +Sed lectus. Donec mollis hendrerit risus. + +Phasellus nec sem in justo pellentesque facilisis. + +Etiam imperdiet imperdiet orci. Nunc nec neque. + +Phasellus leo dolor, tempus non, auctor et, hendrerit quis, nisi. + +Curabitur ligula sapien, tincidunt non, euismod vitae, posuere imperdiet, leo. + +Maecenas malesuada. Praesent congue erat at massa. + +Sed cursus turpis vitae tortor. Donec posuere vulputate arcu. + +Phasellus accumsan cursus velit. + +Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed aliquam, nisi quis porttitor congue, elit erat euismod orci, ac placerat dolor lectus quis orci. + +Phasellus consectetuer vestibulum elit. + +Aenean tellus metus, bibendum sed, posuere ac, mattis non, nunc. + +Vestibulum fringilla pede sit amet augue. In turpis. + +Pellentesque posuere. Praesent turpis. + +Aenean posuere, tortor sed cursus feugiat, nunc augue blandit nunc, eu sollicitudin urna dolor sagittis lacus. + +Donec elit libero, sodales nec, volutpat a, suscipit non, turpis. + +Nullam sagittis. + +Suspendisse pulvinar, augue ac venenatis condimentum, sem libero volutpat nibh, nec pellentesque velit pede quis nunc. + +Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce id purus. + +Ut varius tincidunt libero. Phasellus dolor. + +Maecenas vestibulum mollis diam. Pellentesque ut neque. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. + +In dui magna, posuere eget, vestibulum et, tempor auctor, justo. + +In ac felis quis tortor malesuada pretium. + +Pellentesque auctor neque nec urna. + +Proin sapien ipsum, porta a, auctor quis, euismod ut, mi. + +Aenean viverra rhoncus pede. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. + +Ut non enim eleifend felis pretium feugiat. Vivamus quis mi. + +Phasellus a est. Phasellus magna. In hac habitasse platea dictumst. + +Curabitur at lacus ac velit ornare lobortis. + +Curabitur a felis in nunc fringilla tristique. + +Morbi mattis ullamcorper velit. Phasellus gravida semper nisi. + +Nullam vel sem. + +Pellentesque libero tortor, tincidunt et, tincidunt eget, semper nec, quam. + +Sed hendrerit. Morbi ac felis. + +Nunc egestas, augue at pellentesque laoreet, felis eros vehicula leo, at malesuada velit leo quis pede. + +Donec interdum, metus et hendrerit aliquet, dolor diam sagittis ligula, eget egestas libero turpis vel mi. + +Nunc nulla. Fusce risus nisl, viverra et, tempor et, pretium in, sapien. + +Donec venenatis vulputate lorem. Morbi nec metus. + +Phasellus blandit leo ut odio. + +Maecenas ullamcorper, dui et placerat feugiat, eros pede varius nisi, condimentum viverra felis nunc et lorem. + +Sed magna purus, fermentum eu, tincidunt eu, varius ut, felis. + +In auctor lobortis lacus. + +Quisque libero metus, condimentum nec, tempor a, commodo mollis, magna. + +Vestibulum ullamcorper mauris at ligula. Fusce fermentum. + +Nullam cursus lacinia erat. Praesent blandit laoreet nibh. + +Fusce convallis metus id felis luctus adipiscing. + +Pellentesque egestas, neque sit amet convallis pulvinar, justo nulla eleifend augue, ac auctor orci leo non est. + +Quisque id mi. Ut tincidunt tincidunt erat. Etiam feugiat lorem non metus. + +Vestibulum dapibus nunc ac augue. Curabitur vestibulum aliquam leo. + +Praesent egestas neque eu enim. In hac habitasse platea dictumst. Fusce a quam. + +Etiam ut purus mattis mauris sodales aliquam. Curabitur nisi. + +Quisque malesuada placerat nisl. + +Nam ipsum risus, rutrum vitae, vestibulum eu, molestie vel, lacus. + +Sed augue ipsum, egestas nec, vestibulum et, malesuada adipiscing, dui. + +Vestibulum facilisis, purus nec pulvinar iaculis, ligula mi congue nunc, vitae euismod ligula urna in dolor. + +Mauris sollicitudin fermentum libero. Praesent nonummy mi in odio. Nunc interdum lacus sit amet orci. + +Vestibulum rutrum, mi nec elementum vehicula, eros quam gravida nisl, id fringilla neque ante vel mi. + +Morbi mollis tellus ac sapien. Phasellus volutpat, metus eget egestas mollis, lacus lacus blandit dui, id egestas quam mauris ut lacus. + +Fusce vel dui. Sed diff --git a/phase2/tome_reader.c b/phase2/tome_reader.c new file mode 100644 index 0000000..9805bf0 --- /dev/null +++ b/phase2/tome_reader.c @@ -0,0 +1,33 @@ +#include "tome_utils.h" + +int main(int argc, char *argv[]) { + char *data; + int fd = ERR; + // INFO: I'm sorry, I don't have much time left to implement a pipe input. + if (argc < 2) { + printer("Usage: ./tome_reader \n"); + exit(1); + } else { + fd = get_fd(argv[1], O_RDONLY); + if (fd == ERR) { + printer("Error: Unable to open file\n"); + exit(1); + } + } + + printer("--------------"); + // Loop until we get nothing + while ((data = tome_reader(fd)) != NULL) { + + printer("\n"); + printer("New line: "); + printer(data); + printer("--------------"); + free(data); + } + printer("\n"); + if (fd != 0) + close(fd); // Close the file descriptor + + return 0; +} diff --git a/phase2/tome_utils.c b/phase2/tome_utils.c new file mode 100644 index 0000000..55b7b34 --- /dev/null +++ b/phase2/tome_utils.c @@ -0,0 +1,279 @@ +#include "tome_utils.h" + +#define strlen invalid // make sure that the built-in strlen is not used + +#ifndef BUFFER_SIZE // If the GCC compiler does not define any value +#define BUFFER_SIZE 40 // Give it a default one (lines) +#endif // This should make clangd shut up about it + +#ifndef DEBUG +#define DEBUG FALSE +#endif + +// INFO: THINGS TO KEEP IN MIND: +// printf is not used in this challenge, by default it's not being used unless +// it's for debugging for simplicity sake. + +/* + * @info This is a simple implementation of the strlen function + * + * @brief Returns the length of a string + * @param str The string to measure + * @return The length of the string + * @error Returns 0 if str is NULL + */ +int strlen(const char *str) { + if (str == NULL) { + return 0; + } + int i = 0; + while (str[i] != '\0') { + i++; + } + return i; +} + +/* + * @info crude and basic implementation of "print" + * + * @brief Writes a string to STDOUT + * @param str The string to write + * @error does nothing if str is NULL + */ +void printer(char *str) { + if (str == NULL) { + return; + } + write(1, str, strlen(str)); +} + +/* + * @info Convenience function to get the file descriptor + * + * @brief Returns the file descriptor of a file + * @param filename The name of the file + * @param mode The mode to open the file in + * @return The file descriptor of the file + * @error Returns -1 if the file cannot be opened + */ +int get_fd(char *filename, int mode) { + if (filename == NULL) + return ERR; + int fd = open(filename, mode); + if (fd == ERR) + return ERR; + return fd; +} + +/* + * @info This function checks if a string contains a newline character + * + * @brief Returns TRUE (1) if the string contains a newline character, FALSE (0) + * otherwise + * @param str The string to check + * @error Returns ERR (-1) if str is NULL + */ +int newlineexists(const char *str) { + if (str == NULL) + return ERR; + for (int i = 0; str[i] != '\0'; i++) { + if (str[i] == '\n') { + return TRUE; + } + } + return FALSE; +} + +/* + * @info This function concatenates two strings + * + * @brief Returns a new string that is the concatenation of str1 and str2 + * @param str1 The first string + * @param str2 The second string + * @return The concatenated string + * @error Returns NULL if str1 or str2 is NULL, or if memory allocation fails + */ +char *concat(char const *str1, char const *str2) { + char *result; + int i, j; + // Sanity check + if (!str1 || !str2) + return NULL; + result = malloc(strlen(str1) + strlen(str2) + 1); // +1 for eof + + if (result == NULL) + return NULL; + for (i = 0; str1[i] != '\0'; i++) { + result[i] = str1[i]; + } + if (DEBUG) + printf("[DEBUG]: Concatenating: [%s] + [%s]\n", str1, str2); + for (j = 0; str2[j] != '\0'; j++, i++) { + result[i] = str2[j]; + } + result[i] = '\0'; + return result; +} + +/* + * @info This function reads from a file descriptor and stores the content in a + * string + * + * @brief Reads from a file descriptor and stores the content in a string + * @param fd The file descriptor to read from + * @param buf The buffer to store the content + * @param str The string to store the content + * @return The string containing the content read from the file descriptor + * @error Returns NULL if there is an error reading from the file descriptor or + * if memory allocation fails + */ +char *read_content(int fd, char *buf, char *temp, char *str) { + int bytes; + while (TRUE) { + bytes = read(fd, buf, BUFFER_SIZE); + if (bytes == ERR) { + return NULL; + } + if (DEBUG) + printf("[DEBUG]: Bytes gives : [%d]\n", bytes); + buf[bytes] = '\0'; + if (DEBUG) + printf("[DEBUG]: Buffer is: [%s]\n", buf); + + if (DEBUG) + printf("[DEBUG]: read %d bytes: \"%s\"\n", bytes, buf); + temp = str; // move the temporary data to str + if (temp == NULL) { + temp = malloc(sizeof(char)); + if (temp == NULL) { + return NULL; + } + temp[0] = '\0'; + } + if (DEBUG) + printf("[DEBUG]:We got a [%s] and [%s]\n", temp, buf); + str = concat(temp, buf); // concatenate the temporary data with the buffer + if (DEBUG) + printf("[DEBUG]:Variable temp: (%s), buf: (%s)\n", temp, buf); + if (DEBUG) + printf("[DEBUG]: Concatenated str is: [%s]\n", str); + free(temp); + + if (newlineexists(str) == TRUE || bytes == 0) { + break; + } + } + free(buf); + return str; +} + +/* + * @info This function returns a string up to the first newline character + * + * @brief Returns a string up to the first newline character + * @param str The string to search + * @return A string up to the first newline character + * @error Returns NULL if str is NULL or if there is no newline character in the + * string + * @details + * This function allocates memory for the new string, so it is the + * responsibility of the caller to free it when it is no longer needed. + */ +char *before_nl(const char *str) { + int i; + char *ptr = NULL; + // Sanity check + if (str == NULL || str[0] == '\0') + return NULL; // We got nothing or it's already EOF, we don't need this. + for (i = 0; str[i] != '\n' && str[i] != '\0'; + i++) { // Count up until we reach a newline or EOF + continue; + } + ptr = malloc( + (i + 1 + 1) * // The str count plus the newline plus the null terminator + sizeof(char)); // Dynamically allocate *just enough* space for the str + if (ptr == NULL) { + return NULL; + } + for (i = 0; str[i] != '\n' && str[i] != '\0'; i++) { // Same thing here. + ptr[i] = str[i]; + } + if (str[i] == '\n') { + ptr[i] = '\n'; + i++; + } + ptr[i] = '\0'; + return ptr; +} + +/* + * @info This function returns what's after the first newline character + * + * @brief I'm not repeating this ^ + * @param str The string to search + * @return What's after the first newline character + * @error Returns NULL if str is NULL, or malloc is going funky + */ +char *after_nl(char *str) { + int i, j; + char *ptr; + if (str == NULL) + return NULL; + for (i = 0; str[i] != '\n' && str[i] != '\0'; i++) + continue; + if (str[i] == '\n') { // Consume the \n by skipping it + i++; + } + if (str[i] == '\0') { // It's empty, might aswell drop it. + free(str); + return NULL; + } + if (DEBUG) + printf("[DEBUG]: strlen(str) = %d\n", strlen(str)); + ptr = malloc((strlen(str) - i + 1) * sizeof(char)); + if (ptr == NULL) + return NULL; + j = 0; + while (str[i] != '\0') + ptr[j++] = str[i++]; + ptr[j] = '\0'; + free(str); + return ptr; +} + +/* + * @info This is similar to the get_next_line function homework I found on + * GitHub ( src: https://github.com/pvaladares/42cursus-01-get_next_line ) + * Youtube ( url: https://www.youtube.com/watch?v=-Mt2FdJjVno ) + * (Heavily inspired, but not copied, I can explain what I wrote ;) ) + * @function tome_reader + * @brief Reads a line from a file descriptor + * @param fd The file descriptor to read from + * @return The line read from the file descriptor + * + * @details + * Here we start by defining a static variable str, which is used to store the + * content read from the file descriptor. + * We then proceed to actually get and return the line that is before the \n + * Then we just take the same string and we chop everything before the first \n + * and keep everything after. + */ +char *tome_reader(int fd) { + // INFO: technically static is a global variable, but I hope it's allowed for + // this one, removing static does the exact same thing. It's just for + // cleanness sake. + static char *str = NULL; + char *buf, *line; + char *temp = NULL; + if (fd == ERR || read(fd, 0, 0) == ERR) // Check if nothing wrong happened. + return NULL; + buf = malloc((BUFFER_SIZE + 1) * sizeof(char)); + if (buf == NULL) + return NULL; + str = read_content(fd, buf, temp, str); + if (str == NULL) + return NULL; + line = before_nl(str); + str = after_nl(str); + return line; +} diff --git a/phase2/tome_utils.h b/phase2/tome_utils.h new file mode 100644 index 0000000..eddb1f7 --- /dev/null +++ b/phase2/tome_utils.h @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +// BOOLEAN VALUES +enum { + TRUE = 1, + FALSE = 0, + ERR = -1, +}; + +void printer(char *str); +int get_fd(char *filename, int mode); +int newlineexists(const char *str); +char *tome_reader(int fd); +char *before_nl(const char *str); +char *after_nl(char *str); +char *read_content(int fd, char *buf, char *temp, char *str); +char *concat(char const *string1, char const *string2);