├── README-ptbr.md ├── README.md ├── get_next_line.c ├── get_next_line.h └── get_next_line_utils.c /README-ptbr.md: -------------------------------------------------------------------------------- 1 |

get_next_line - @42sp

2 | 3 |

:information_source: Uma função em C que lê qualquer arquivo válido linha por linha até o final

4 | 5 |

6 |

7 |

104/100

8 |

9 | 10 | ## Índice 11 | 12 | * [O que é get-next-line?](#o-que-e-get-next-line) 13 | * [Requisitos](#requisitos) 14 | * [Como funciona?](#como-funciona) 15 | * [Como eu uso a Função?](#como-eu-uso-a-funcao) 16 | * [Como eu testo?](#como-eu-testo) 17 | * [42 Cursus](#42-cursus) 18 | * [Autor](#autor) 19 | 20 |

O que é get-next-line?

21 | 22 | O segunda projeto na 42. É uma função em C que retorna uma linha lida de um file descriptor. Em resumo, pode ler qualquer arquivo válido e faz isso linha por linha para otimizar memória, uma vez que o tamanho do arquivo é desconhecido. É uma função extremamente útil e pode ser usada em projetos futuros dentro da 42. 23 | 24 |

Requisitos

25 | 26 |

:warning: O projeto deve estar de acordo com a Norma

27 | A Norma é um padrão de programação que define um conjunto de regras a seguir ao escrever um código na 42. A norma aplica-se a todos os projetos C dentro do currículo interno por padrão, e para qualquer projeto onde é especificado. Aqui algumas das regras: 28 | 29 | Cada função dever ter no máximo 25 linhas, não contando suas próprias chaves '{}'. 30 | 31 | Cada linha deve ter no máximo 80 colunas de largura, comentários incluídos. 32 | 33 | Uma função pode ter no máximo 4 parâmetros definidos. 34 | 35 | Não podem ser declaradas mais que 5 variáveis por função. 36 | 37 | Não é permitido o uso de: for , do...while , switch , case , goto , 38 | operadores ternários como `?' e VLAs - Matrizes de comprimento variável. 39 | A norminette (como chamamos a norma na 42) é feita em python e é open source. 40 | 41 | O repositório está disponível em https://github.com/42School/norminette 42 | 43 | Além da norma padrão, o projeto tem alguns requisitos próprios 44 | 45 | É proibido declarar variáveis globais. 46 | 47 | Sua leitura deve usar o BUFFER_SIZE definido durante a compilação para ler de um 48 | arquivo ou do stdin. Esse valor será modificado durante a avaliação para fins de 49 | teste. 50 | 51 | O programa será compilado dessa forma: 52 | gcc -Wall -Wextra -Werror -D BUFFER_SIZE=42 .c. 53 | 54 | A libft não é autorizada para este projeto. você deve adicionar um arquivo 55 | get_next_line_utils.c que vai conter as funções que você precisa para a sua 56 | get_next_line funcionar. 57 | 58 |

Como funciona?

59 | 60 |

:sparkles: Para este projeto fomos apresentados ao conceito de variáveis estáticas :sparkles:

61 | 62 |

:information_source: Uma variável estática é alocada "estaticamente", o que significa que seu tempo de vida é toda a execução do programa.

63 | 64 | A linha é por definição uma string encerrada em "\n" (quebra de linha) ou "EOF" (para o fim do arquivo) e que, segundo o subject, deve ser lida em um buffer de tamanho definido 65 | na compilação. A get_next_line roda a função read e guarda o que foi lido durante a chamada só então procura por um "\n" - quando encontra sabemos que chegamos ao fim da linha, 66 | caso não encontre o "\n" mas o read retorne 0 sabemos que não tem nada à frente para ser lido (EOF), nos outros casos, simplesmente não chegamos ao final da linha, o que foi 67 | lido é armazenado na linha que vai ser retornada e seguimos na leitura do arquivo. Na maioria das vezes o buffer não condiz com o tamanho exato da linha, 68 | e também não é possível reler o mesmo trecho da linha, o que gera um dos maiores problemas no desenvolvimento da get_next_line: 69 | O que aconteceria nesses casos em que, por exemplo, o BUFFER_SIZE é de 10 caracteres e a linha acaba no 6º caracter? 70 | Os 4 caracteres restantes após a quebra de linha seriam perdidos e a leitura continuaria no próximo buffer de 10 caracteres. 71 | Para resolver isso, usamos a variável estática como um backup, para guardar esses caracteres que sobram. 72 | E quando a função é chamada novamente, uma das primeiras coisas feitas é checar se há algo no backup e se houver, começar a nova linha a partir dali. 73 | No geral é assim que ela funciona, outros detalhes de funcionamento são mais técnicos e achei melhor deixá-los de fora dessa explicação, mas você pode conferir checando 74 | a função. 75 | 76 |

Como eu uso a Função?

77 | O objetivo é criar uma bilioteca chamada libgetnextline.a feita com os arquivos fonte. 78 | 79 | Para criar a biblioteca, clone o projeto: 80 | 81 | git clone https://github.com/augustobecker/get_next_line get_next_line 82 | Entre no repositório: 83 | 84 | cd get_next_line 85 | Rode esse comandos para transformar os arquivos em objetos: 86 | 87 | clang -Wall -Werror -Wextra -c get_next_line.c -o get_next_line.o 88 | clang -Wall -Werror -Wextra -c get_next_line_utils.c -o get_next_line_utils.o 89 | 90 | E esse outro para criar a biblioteca 91 | 92 | ar -rcs libgetnextline.a get_next_line.o get_next_line_utils.o 93 | 94 | Você deve ver um arquivo libgetnextline.a e alguns arquivos objeto (.o). 95 | 96 | Você pode remover os arquivos .o 97 | 98 | rm -f get_next_line.o get_next_line_utils.o 99 | Agora, só precisa adicionar esse cabeçalho nos seus arquivos .c e usar as funções da libgetnextline: 100 | 101 | #include "get_next_line.h" 102 | Se tentar compilar seus arquivos com clang usando "clang exemplo.c" vai receber um erro de undefined symbol para as funções da biblioteca. 103 | 104 | Você deve mostrar qual é a biblioteca: 105 | 106 | clang exemplo.c libgetnextline.a 107 | 108 | É isso, agora basta executar com ./a.out 109 | 110 | Agora, se estiver buscando uma forma de utilizar essa função, aqui vai uma demonstração prática: 111 | 112 | char *full_file; 113 | char *line_temp; 114 | int file_fd 115 | 116 | file_fd = open(argv, O_RDONLY); 117 | if (file_fd == -1) 118 | ft_error_msg("The Map couldn't be opened. Invalid fd"); 119 | full_file = ft_strdup(""); 120 | while (true) 121 | { 122 | full_file = get_next_line(file_fd); 123 | if (line_temp == 0) 124 | break ; 125 | full_file(full_file, line_temp); 126 | free(line_temp); 127 | } 128 | close(file_fd); 129 | return (full_file); 130 | 131 | 132 |

Como eu testo?

133 | 134 | Para testar o código vamos usar um Tester para a get_next_line feito pelo @jgambard. Há vários outros bons testers mas hoje vou cobrir apenas esse. 135 | 136 | Para testar o código desse repositório: 137 | Clone o repositório e entre nele: 138 | 139 | git clone https://github.com/augustobecker/get_next_line get_next_line 140 | 141 | cd get_next_line/ 142 | 143 | Agora, clone o gnlTester do @jgambard 144 | 145 | git clone https://github.com/Tripouille/gnlTester Tester_get_next_line 146 | Entre na pasta do Tester e rode o teste mandatório: 147 | 148 | cd Tester_get_next_line 149 | make m 150 | 151 | Se você fez tudo corretamente, deve ver algo como isso: 152 | 153 | ![68747470733a2f2f692e696d6775722e636f6d2f75344c6936414d2e706e67](https://user-images.githubusercontent.com/81205527/158914684-a53f2bf1-7a7a-4155-944f-7863ddb09855.png) 154 | 155 |

42 Cursus

156 | 157 | A 42 é uma iniciativa educacional global que propõe uma nova forma de aprender tecnologia: sem professores, sem salas de aula, 158 | estudantes aprendendo com seus colegas estudantes (Aprendizado peer to peer), 159 | com uma metodologia que desenvolve habilidades de computação e da vida. 160 | Sem mencionar que é completamente gratuita e aberta para todos, sem pré-requisitos. 161 | 162 | As admissões na 42 são diferentes de outras escolas. Usamos um processo de admissão baseado em mérito. 163 | O passo final no processo é a Piscina - parte parte do processo seletivo que requer 4 semanas de código intenso e imersivo. 164 | Não é necessário experiência anterior em programação. 165 | 166 | Você pode conferir mais sobre o processo de admissão no site da 42sp: https://www.42sp.org.br 167 | 168 | ou no meu repositório do github: 42 Piscine 169 | 170 | Para ver outros projetos da 42 desenvolvidos por mim, clique aqui: 42 Cursus 171 | 172 |

Autor

173 |
174 |
175 | 176 |
177 |
178 | Augusto Becker | acesar-l | 🇧🇷👨‍🚀 179 | 180 | :wave: Fale comigo: 181 |
182 |
183 | LinkedIn 184 | Instagram 185 | Gmail - augustobecker.dev@gmail.com 186 | Discord - beckerzz#3614 187 |
188 |
189 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

get_next_line - @42sp

2 | 3 |

:information_source: A C function that reads any valid file line by line until the end

4 | 5 |

6 |

7 |

104/100

8 |

9 | 10 | ## Index 11 | 12 | * [What is get-next-line?](#what-is-get-next-line) 13 | * [Requirements](#requirements) 14 | * [How does it work?](#how-does-it-work) 15 | * [How do I use the function?](#how-do-i-use-the-function) 16 | * [How do I test it?](#how-do-i-test-it) 17 | * [42 Cursus](#42-cursus) 18 | * [Author](#author) 19 | 20 |

What is get-next-line?

21 | 22 | It's the second project at 42. A function, in C, that returns a line, read from a file descriptor. In short, it can read any valid file and does that line by line to optimize memory, since the file size is not known. It's an extremely useful function that can be used in the next school's projects. 23 | 24 |

Requirements

25 | 26 |

:warning: The project must be written in accordance with the Norm

27 | The Norm is a programming standard that defines a set of rules to follow when writing code at 42. It applies to all C projects within the Common Core by default, and 28 | to any project where it's specified. These are some of them: 29 | 30 | Each function must be maximum 25 lines, not counting the function's own curly brackets. 31 | 32 | Each line must be at most 80 columns wide, comments included. 33 | 34 | A function can take 4 named parameters maximum. 35 | 36 | You can't declare more than 5 variables per function. 37 | 38 | You're not allowed to use: for , do...while , switch , case , goto , 39 | ternary operators such as `?' and VLAs - Variable Length Arrays. 40 | The norminette (as we call the norm at 42) is in python and open source. 41 | 42 | Its repository is available at https://github.com/42School/norminette. 43 | 44 | In addition to the Norm, the subject have other requirements, which are: 45 | 46 | It is forbidden to declare global variables. 47 | 48 | Your read must use the BUFFER_SIZE defined during compilation to read from 49 | a file or from stdin. This value will be modified during the evaluation for testing 50 | purposes. 51 | 52 | The program will be compiled in this way: 53 | gcc -Wall -Wextra -Werror -D BUFFER_SIZE=42 .c. 54 | 55 | libft is not allowed for this project. You must add a get_next_line_utils.c file 56 | which will contain the functions that are needed for your get_next_line to work 57 | 58 |

How does it work?

59 | 60 |

✨ For this project we were introduced to the concept of static variables ✨

61 | 62 |

ℹ️ A static variable is allocated "statically", which means its lifetime is the entire execution of the program.

63 | 64 | The line is, by definition, a string ending in "\n" (line break) or "EOF" (to the end of the file) and which, according to the subject, must be read in a buffer of a size defined in the compilation. get_next_line runs the read function and stores what was read during the call, only then it looks for a "\n" - when it finds it we know we've reached the end of the line, if it doesn't find the "\n" but read returns 0 we know that there is nothing ahead to be read (EOF), in other cases, we simply do not reach the end of the line, what was read is stored in the line that will be returned and we continue reading the file. Most of the time, the buffer does not match the exact size of the line, and it is also not possible to read the same stretch of the line two times, which creates one of the biggest problems in the development of get_next_line: 65 | What happens in those cases where, for example, the BUFFER_SIZE is 10 and the line ends at the 6th character? 66 | The 4 characters remaining after the line break would be lost and reading would continue into the next 10 character buffer. To solve this, we use the static variable as a backup, to store those leftover characters. And when the function is called again, one of the first things done is to check if there is anything in the backup and if there is, start the new line from there. In general this is how it works, other details of how it works are more technical and I thought it best to leave them out of this explanation, but you can check it out by checking the function. 67 |

How do I use the function?

68 | 69 | It aims to create a library called libgetnextline.a from the source files. 70 | To create this library, clone the project: 71 | 72 | git clone https://github.com/augustobecker/get_next_line get_next_line 73 | Enter the repository: 74 | 75 | cd get_next_line 76 | 77 | Run these commands to compile the source code to object files: 78 | 79 | clang -Wall -Werror -Wextra -c get_next_line.c -o get_next_line.o 80 | clang -Wall -Werror -Wextra -c get_next_line_utils.c -o get_next_line_utils.o 81 | 82 | And then creating the library libgetnextline.a: 83 | 84 | ar -rcs libgetnextline.a get_next_line.o get_next_line_utils.o 85 | 86 | You should see a libgetnextline.a file and some object files (.o). 87 | 88 | Now to clean up (removing the .o files), run this command: 89 | 90 | rm -f get_next_line.o get_next_line_utils.o 91 | Now you just have to add this header at your .c files and use the get_next_line function or any other from the library: 92 | 93 | #include "get_next_line.h" 94 | 95 | If you try to compile your .c files with clang using "clang example.c" you will get an undefined symbol error for libgetnextline functions. 96 | 97 | You have to tell the file which library it's using: 98 | 99 | clang example.c libgetnextline.a 100 | 101 | That's it. Now run it using ./a.out 102 | 103 | Now, if you're looking for a way to use this function, here's a practical demonstration: 104 | 105 | char *full_file; 106 | char *line_temp; 107 | int file_fd 108 | 109 | file_fd = open(argv, O_RDONLY); 110 | if (file_fd == -1) 111 | ft_error_msg("The Map couldn't be opened. Invalid fd"); 112 | full_file = ft_strdup(""); 113 | while (true) 114 | { 115 | full_file = get_next_line(file_fd); 116 | if (line_temp == 0) 117 | break ; 118 | full_file(full_file, line_temp); 119 | free(line_temp); 120 | } 121 | close(file_fd); 122 | return (full_file); 123 | 124 | 125 |

How do I test it?

126 | 127 | To test the code we're going to be using @jgambard's gnlTester. There are some good others but I'll only be covering this one. 128 | 129 | To test the code in this repo 130 | Clone this repo and cd into it: 131 | 132 | git clone https://github.com/augustobecker/get_next_line get_next_line 133 | 134 | cd get_next_line/ 135 | 136 | Now, clone @jgambard's gnlTester 137 | 138 | https://github.com/Tripouille/gnlTester Tester_get_next_line 139 | Go into the test folder and run the mandatory test: 140 | 141 | cd Tester_get_next_line 142 | make m 143 | 144 | If you did everything correctly you should see something like this: 145 | ![68747470733a2f2f692e696d6775722e636f6d2f75344c6936414d2e706e67](https://user-images.githubusercontent.com/81205527/158914684-a53f2bf1-7a7a-4155-944f-7863ddb09855.png) 146 | 147 |

42 Cursus

148 | 149 | 42 is a global education initiative that proposes a new way of learning technology: no teachers, no classrooms, 150 | students learning from their fellow students (peer to peer learning), 151 | with a methodology that develops both computing and life skills. 152 | Not to mention that it's completely free of charge and open to all with no prerequisites. 153 | 154 | Admissions at 42 are unlike other colleges. We use a merit-based admission process. 155 | The final step of the admission is the Piscine - This is part of the admissions process and 156 | requires 4 weeks of intensive and immersive coding. No prior coding experience is necessary at all. 157 | 158 | You can check more about the admission process on the 42sp website: https://www.42sp.org.br or on my github repository: 42 Piscine 159 | 160 | To see other projects developed by me at 42, click here: 42 Cursus 161 | 162 |

Author

163 |
164 |
165 | 166 |
167 |
168 | Augusto Becker | acesar-l | 🇧🇷👨‍🚀 169 | 170 | :wave: How to reach me: 171 |
172 |
173 | LinkedIn 174 | Instagram 175 | Gmail - augustobecker.dev@gmail.com 176 | Discord - beckerzz#3614 177 |
178 |
179 | -------------------------------------------------------------------------------- /get_next_line.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* get_next_line.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: acesar-l +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/10/29 11:41:08 by acesar-l #+# #+# */ 9 | /* Updated: 2021/10/29 12:09:57 by acesar-l ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "get_next_line.h" 14 | 15 | static void free_ptr(char **ptr) 16 | { 17 | free(*ptr); 18 | *ptr = NULL; 19 | } 20 | 21 | static char *get_line(char **backup, char **line) 22 | { 23 | char *next_backup; 24 | int i; 25 | 26 | i = 0; 27 | next_backup = NULL; 28 | while (*(*backup + i) != '\n' && *(*backup + i) != '\0') 29 | i++; 30 | if (*(*backup + i) == '\n') 31 | { 32 | i++; 33 | *line = gnl_substr(*backup, 0, i); 34 | next_backup = gnl_strdup(*backup + i); 35 | } 36 | else 37 | *line = gnl_strdup(*backup); 38 | free_ptr(backup); 39 | return (next_backup); 40 | } 41 | 42 | static int read_line(int fd, char **buffer, char **backup, char **line) 43 | { 44 | int bytes_read; 45 | char *temporary; 46 | 47 | bytes_read = 1; 48 | while (!gnl_strchr(*backup, '\n') && bytes_read) 49 | { 50 | bytes_read = read(fd, *buffer, BUFFER_SIZE); 51 | (*buffer)[bytes_read] = '\0'; 52 | temporary = *backup; 53 | *backup = gnl_strjoin(temporary, *buffer); 54 | free(temporary); 55 | } 56 | free_ptr(buffer); 57 | *backup = get_line(backup, line); 58 | if (!(**line)) 59 | free_ptr(line); 60 | return (bytes_read); 61 | } 62 | 63 | char *get_next_line(int fd) 64 | { 65 | static char *buffer_backup = NULL; 66 | char *buffer; 67 | char *line; 68 | 69 | if (fd < 0 || fd >= 1024 || BUFFER_SIZE <= 0 ) 70 | return (NULL); 71 | buffer = (char *)malloc(sizeof(char) * (BUFFER_SIZE + 1)); 72 | if (!buffer) 73 | return (NULL); 74 | if (read(fd, buffer, 0) < 0) 75 | { 76 | free(buffer); 77 | return (NULL); 78 | } 79 | if (!buffer_backup) 80 | buffer_backup = gnl_strdup(""); 81 | if (!read_line(fd, &buffer, &buffer_backup, &line) && !line) 82 | return (NULL); 83 | return (line); 84 | } 85 | -------------------------------------------------------------------------------- /get_next_line.h: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* get_next_line.h :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: acesar-l +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/10/29 11:43:29 by acesar-l #+# #+# */ 9 | /* Updated: 2021/10/29 12:13:00 by acesar-l ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #ifndef GET_NEXT_LINE_H 14 | # define GET_NEXT_LINE_H 15 | # include 16 | # include 17 | 18 | # ifndef BUFFER_SIZE 19 | # define BUFFER_SIZE 10 20 | # endif 21 | 22 | char *get_next_line(int fd); 23 | char *gnl_strchr(const char *str, int argument); 24 | size_t gnl_strlcpy(char *dest, const char *src, size_t destsize); 25 | char *gnl_substr(char const *s, unsigned int start, size_t len); 26 | char *gnl_strjoin(const char *s1, const char *s2); 27 | char *gnl_strdup(char *src); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /get_next_line_utils.c: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* get_next_line_utils.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: acesar-l +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2021/10/29 11:44:15 by acesar-l #+# #+# */ 9 | /* Updated: 2021/10/29 12:07:11 by acesar-l ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "get_next_line.h" 14 | 15 | char *gnl_strchr(const char *str, int argument) 16 | { 17 | int i; 18 | 19 | i = 0; 20 | while (str[i]) 21 | { 22 | if ((unsigned char) str[i] == (unsigned char)argument) 23 | return ((char *) &str[i]); 24 | i++; 25 | } 26 | if (argument == '\0') 27 | return ((char *) &str[i]); 28 | return ((void *) 0); 29 | } 30 | 31 | size_t gnl_strlcpy(char *dest, const char *src, size_t destsize) 32 | { 33 | size_t i; 34 | size_t src_length; 35 | 36 | i = 0; 37 | src_length = 0; 38 | while (src[src_length]) 39 | src_length++; 40 | if (destsize <= 0) 41 | return (src_length); 42 | while (src[i] && i < destsize - 1) 43 | { 44 | dest[i] = src[i]; 45 | i++; 46 | } 47 | dest[i] = '\0'; 48 | return (src_length); 49 | } 50 | 51 | char *gnl_strdup(char *src) 52 | { 53 | size_t i; 54 | size_t len; 55 | char *dup; 56 | 57 | i = 0; 58 | len = 0; 59 | if (!src) 60 | return (NULL); 61 | while (src[len]) 62 | len++; 63 | dup = (char *)malloc(sizeof(char) * (len + 1)); 64 | if (!dup) 65 | return (NULL); 66 | while (src[i]) 67 | { 68 | dup[i] = src[i]; 69 | ++i; 70 | } 71 | dup[i] = '\0'; 72 | return (dup); 73 | } 74 | 75 | char *gnl_substr(char const *s, unsigned int start, size_t len) 76 | { 77 | size_t substr_length; 78 | size_t s_length; 79 | char *substr; 80 | 81 | if (!s) 82 | return (NULL); 83 | s_length = 0; 84 | while (s[s_length]) 85 | s_length++; 86 | substr_length = s_length - start; 87 | if (s_length > start) 88 | { 89 | if (substr_length > len) 90 | substr = (char *) malloc(sizeof(char) * (len + 1)); 91 | else 92 | substr = (char *) malloc(sizeof(char) * (substr_length + 1)); 93 | if (!substr) 94 | return (NULL); 95 | gnl_strlcpy(substr, &s[start], len + 1); 96 | } 97 | else 98 | substr = gnl_strdup(""); 99 | return (substr); 100 | } 101 | 102 | char *gnl_strjoin(const char *s1, const char *s2) 103 | { 104 | char *str; 105 | size_t s1_len; 106 | size_t s2_len; 107 | 108 | s1_len = 0; 109 | s2_len = 0; 110 | while (s1[s1_len]) 111 | s1_len++; 112 | while (s2[s2_len]) 113 | s2_len++; 114 | str = (char *)malloc(sizeof(char) * (s1_len + s2_len + 1)); 115 | if (!str) 116 | return (NULL); 117 | gnl_strlcpy(str, s1, s1_len + 1); 118 | gnl_strlcpy(&str[s1_len], s2, s1_len + s2_len + 1); 119 | return (str); 120 | } 121 | --------------------------------------------------------------------------------