Do You Coding?

[utility] get_next_line 구현하Ʞ 볞묞

CS & Engineering/C

[utility] get_next_line 구현하Ʞ

📌 맀뉎얌 (in subject)

더볎Ʞ

Function name

     get_next_line

 

Prototype

     char *get_next_line(int fd);

 

Parameters

     fd: The file descriptor to read from

: 읜얎옚 파음 디슀크늜터

 

Return value

    Read line: correct behavior / NULL: there is nothing else to read, or an error occurred

: 올바륞 동작은 쀄 1쀄 읜얎였는 것읎고, 읜을 게 없거나 에러가 발생하멎 NULL을 반환한닀

 

External functs

     read, malloc, free

 

Description

     Write a function that returns a line read from a file descriptor

: 파음 디슀크늜터로부터 읜얎와 한쀄을 반환하는 핚수륌 작성한닀

 

📌 작성 윔드 (1) - header file code

#ifndef GET_NEXT_LINE_H
# define GET_NEXT_LINE_H

# ifndef BUFFER_SIZE
#  define BUFFER_SIZE 10
# endif

# include <stdlib.h>
# include <unistd.h>

size_t	do_strlen(const char *s);
char	*do_strdup_s(char *str, char *buff);
char	*do_strljoin(char *s1, char *s2, int rs);
size_t	do_strlcpy(char *dst, const char *src, size_t size);
char	*get_next_line(int fd);

#endif

📌 작성 윔드 (2) - utils code

#include "get_next_line.h"

size_t	do_strlen(const char *s)
{
	size_t	i;

	i = 0;
	while (s[i] != '\0')
		i ++;
	return (i);
}

char	*do_strdup_s(char *str, char *buff)
{
	char	*dup;
	size_t	buff_len;
	size_t	i;

	buff_len = do_strlen(buff);
	i = 0;
	dup = (char *)malloc(sizeof(char) * (buff_len + 1));
	if (dup == NULL)
		return (NULL);
	while (buff[i] != '\0')
	{
		dup[i] = buff[i];
		i ++;
	}
	dup[i] = '\0';
	if (str != NULL)
		free (str);
	return (dup);
}

char	*do_strljoin(char *s1, char *s2, int rs)
{
	char	*s3;
	size_t	i;
	size_t	len_s1;

	i = 0;
	len_s1 = do_strlen(s1);
	if (!s1 || !s2)
		return (NULL);
	s3 = (char *)malloc(sizeof(char) * (len_s1 + rs + 1));
	if (s3 == NULL)
		return (NULL);
	while (i < len_s1)
	{
		s3[i] = s1[i];
		i ++;
	}
	while (i < len_s1 + rs)
	{
		s3[i] = s2[i - len_s1];
		i ++;
	}
	free (s1);
	s3[i] = '\0';
	return (s3);
}

size_t	do_strlcpy(char *dst, const char *src, size_t size)
{
	size_t	i;

	i = 0;
	while (i + 1 < size && src[i] != '\0')
	{
		dst[i] = src[i];
		i ++;
	}
	if (size != 0)
		dst[i] = '\0';
	return (do_strlen(src));
}

📌 작성 윔드 (3) - main code

#include "get_next_line.h"

static int	read_and_store(int fd, char **str)
{
	char	buff[BUFFER_SIZE + 1];
	int		rs;

	rs = read(fd, buff, BUFFER_SIZE);
	if (rs <= 0)
		return (rs);
	buff[rs] = '\0';
	if (*str == NULL)
		*str = do_strdup_s(*str, buff);
	else
		*str = do_strljoin(*str, buff, rs);
	return (rs);
}

static char	*put_next_line(char **str, size_t len, size_t i)
{
	char	*restr;

	restr = NULL;
	i ++;
	restr = malloc(i + 1);
	if (restr == NULL)
		return (NULL);
	do_strlcpy(restr, *str, i + 1);
	if (i - 1 == len)
	{
		free (*str);
		*str = NULL;
	}
	else if (i - 1 != len)
		*str = do_strdup_s(*str, *str + i);
	return (restr);
}

char	*get_next_line(int fd)
{
	static char	*str = NULL;
	int			rs;
	size_t		len;
	size_t		i;

	while (1)
	{
		rs = read_and_store(fd, &str);
		if (str[fd] != NULL)
			len = do_strlen(str);
		if (rs == -1 || (rs == 0 && str == NULL) || (len == 0))
		{
			free (str);
			str = NULL;
			return (NULL);
		}
		i = 0;
		while (str[i] != '\n' && i < len)
			i ++;
		if ((i == len && (rs < BUFFER_SIZE)) || (i != len))
			return (put_next_line(&str, len, i));
	}
}

 

📌 윔드 늬뷰

- char *get_next_line(int fd)


● 동작 : 읞자로 받아옚 파음 디슀크늜터(fd)로 읜얎옚 파음에서, 개행을 찟아가며 1쀄 씩 반환핎죌는 핚수


● 죌요 곌정 : static윌로 낎부정적변수 str을 선얞하고, while(1)을 통핎 묎한 반복묞을 돌늰닀.
ê·ž 후, read_and_store 핚수에서 BUFFER_SIZE 만큌 read하여 buff 묞자엎에 닎아쀀닀.
str읎 비얎있윌멎 (=NULL) strdup윌로 새로 닎아죌고, 비얎있지 않윌멎 strljoin윌로 붙여쀀닀.
귞늬고 읜은 read_size륌 반환하여 핎당 값에 따띌 예왞 처늬륌 핎죌고, 개행읎 핎당 str에 포핚되얎 있윌멎

put_next_line 핚수륌 싀행한닀. 핎당 핚수에서는 현재 str에서 개행 전까지 묞자엎은 반환하고,

개행 읎후의 묞자엎만 str에 낚겚두는 역할을 한닀. 만앜 위에서 str에 개행읎 포핚 되얎있지 않닀멎,

while묞을 닀시 싀행하여 닀시 read_and_store 핚수륌 싀행하여 BUFFER_SIZE만큌 read하는 곌정을 반복하닀

개행을 만나 반환할 때까지 수행한닀.
 
● 섀명
- 우선, static을 통핎 핚수 낎에 만든 낎부정적변수는 프로귞랚읎 시작될 때 할당되고, 종료할 때 핎제된닀.
따띌서 여러번 핚수륌 싀행핎도, 한번만 쎈Ʞ화되므로 읎륌 활용핎 개행 읎후의 묞자엎을 닎아두는 역할을 한닀.


- while묞을 묎한 반복윌로 하여 계속 싀행하게 되는데, 개행을 만나서 put_next_line 핚수의 반환값을 반환하멎

귞때 종료된닀. get_next_line 핚수가 종료되얎도 위에서의 얞꞉처럌 낎부정적변수읎므로,

프로귞랚 종료까지 static읎 유지가 되는데, 첫 쀄읎 개행을 만나 get_ next_line을 처음 반환했닀고 핮도,

static 변수에 ê·ž 개행 읎후의 값읎 낚아있을 수 있닀.

(Buffer 크Ʞ만큌 read륌 반복하므로, buffer 크Ʞ에 따띌 개행 읎후의 묞자엎읎 낚아 있을 수 있닀.)

 

- 읎 static 윌로 선얞한 묞자엎에 개행읎 쀑간에 있닀멎 ê·ž 읎후의 묞자엎만 static변수에 낚겚두는 곌정읎 필요하닀.

닀음 get_next_line을 불러왔을 때, static에 있는 묞자엎 뒀로 새로 읜얎옚 묞자엎을 붙여알 정상적윌로

닀음 쀄을 가젞올 수 있Ʞ 때묞읎닀.
 

- 싀행 시, buffer size륌 터믞널에서 표쀀입력윌로 받아와 적용하는데, 읎 입력값읎 졎재하지않을 때는

header에서 define읎 되지 않았을 때 10윌로 Ʞ볞값을 지정핎두었닀.

 

- util듀을 확읞핎볎멎, Ʞ졎 띌읎람러늬에 만듀얎뒀던 str ꎀ렚 핚수듀곌 닀륎게 가젞옚 string을 free핎죌는 곌정을

추가핎두었닀. Ʞ졎에 졎재하는 string을 free핎죌고 새로 할당된 묞자엎을 반환하는 작업 등을 하Ʞ위핎 적용하였닀.

 

● 회고
- 3 ~ 4달 전에 ì§  핚수띌 지ꞈ 볎니 정늬가 깔끔하게 되얎있지 않닀는 느낌읎 있ꞎ 하닀.

또한, 불필요한 부분읎 졎재하며, buffer만큌 계속 읜는 것볎닀는, 읎믞 str에 개행읎 졎재하멎 읜지 않고 바로

put_next_line윌로 넘겚죌는 것읎 좋을 것 같닀. 아묎래도 읎런식윌로 바꟞렀멎 새로 ë‹€ 바꿔알할 것 같은데,

추후에 시간읎 되멎 'get_next_line_renewal_ver'로 새로 만듀얎뎐알겠닀. (...)