🤪

次の行を読み込む関数を作成する

3 min read

これはエンジニア養成機関42 Tokyoの課題です。
自分用のメモ以上のなにものでもないので、悪しからず。

課題の内容

42の規則上課題のPDFを掲載できないのですが、ざっくりいうと渡したファイルを1行ずつ読み込んでくれる関数です。
forswitchなどがコード規約で禁止されているため、一部モダンじゃない書き方をしています。
それ以外で「ここもっとスッキリかけそう」と言う箇所があればお知らせください。
また、使用できる標準関数はreadmallocおよびfreeのみです。
ft_で始まる関数は標準関数を自作したもので、挙動は同じになっているはずです、

ソースコード

get_next_line.h
#ifndef GET_NEXT_LINE_H
# define GET_NEXT_LINE_H
# define SUCCESS 1
# define END_OF_FILE 0
# define READ_ERROR -1

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

int	get_next_line(int fd, char **line);
size_t	ft_strlen(const char *s);
char	*ft_strchr(char *s, int c);
void	*ft_memmove(void *dst, const void *src, size_t len);
char	*ft_substr(char const *s, unsigned int start, size_t len);

#endif
get_next_line.c
#include "get_next_line.h"

static char	*free_return(char *save)
{
	free(save);
	save = NULL;
	return (NULL);
}

static int	count_till_endl(char *s)
{
	int	i;

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

static char	*gnl_strjoin(char const *s1, char const *s2)
{
	size_t	len1;
	size_t	len2;
	size_t	total_len;
	char	*ret;

	if (!s1 && !s2)
		return (NULL);
	len1 = ft_strlen((char *)s1);
	len2 = ft_strlen((char *)s2);
	total_len = len1 + len2;
	if (!(ret = (char *)malloc((total_len + 1) * sizeof(char))))
		return (NULL);
	ft_memmove(ret, s1, len1);
	ft_memmove(ret + len1, s2, len2);
	ret[total_len] = '\0';
	free((char *)s1);
	return (ret);
}

static char	*get_save(char *save)
{
	char	*ret;
	int	i;
	int	j;

	i = 0;
	j = 0;
	if (!save)
		return (NULL);
	while (save[i] != '\n')
	{
		if (!save[i])
			return (free_return(save));
		i++;
	}
	if (!(ret = malloc(sizeof(char) * ((ft_strlen(save) - i) + 1))))
		return (NULL);
	i++;
	while (save[i])
		ret[j++] = save[i++];
	ret[j] = '\0';
	free(save);
	return (ret);
}

int		get_next_line(int fd, char **line)
{
	int		read_res;
	char		*buf;
	static char	*save;

	read_res = SUCCESS;
	if (fd < 0 || !line || BUFFER_SIZE < 1 ||
	!(buf = (char *)malloc((size_t)BUFFER_SIZE + 1)))
		return (READ_ERROR);
	while (!(ft_strchr(save, '\n')) && read_res != 0)
	{
		if ((read_res = read(fd, buf, BUFFER_SIZE)) == READ_ERROR)
		{
			free(buf);
			return (READ_ERROR);
		}
		buf[read_res] = '\0';
		save = gnl_strjoin(save, buf);
	}
	free(buf);
	*line = ft_substr(save, 0, count_till_endl(save));
	save = get_save(save);
	return ((read_res == END_OF_FILE) ? END_OF_FILE : SUCCESS);
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

#include "get_next_line.h"

/*main.cは提出しないため、printfとか使ってもOKです*/
int	main(int argc, char **argv)
{
	int	fd;
	char	*line;

	if (argc == 1 || argc == 2)
	{
		fd = (argc == 1) ? 0 : open(argv[1], P_RDONLY);
		while (get_next_line(fd, &line) == 1)
		{
			printf("%s\n", line);
			free(line);
		}
		close(fd);
	}
	else
		return (2);
	system("leaks a.out");
	return (0);
}