Skip to content

hrasamoe/parse_line_C

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 

Repository files navigation

This project was developed as part of the 42 School curriculum by hrasamoe.


Description

get_next_line is a project from the 42 Common Core.

Its objective is to implement a function that reads from a file (or any input stream via a file descriptor) line by line, without knowing the line length in advance and without using the standard getline() function.

The function must:

  • Return a complete line including the \n character (except for the last line if the file does not end with \n).
  • Work correctly with any BUFFER_SIZE value (1, 42, 9999, 1000000, etc.).
  • Return NULL cleanly on end-of-file (EOF) or error.
  • Avoid memory leaks.
  • Handle multiple file descriptors independently.

This project strengthens understanding of:

  • File I/O (open, read, close)
  • Static variables
  • Buffer management
  • Dynamic memory allocation
  • Edge case handling

Instruction

1. Clone the Repository

git clone <repo_url> get_next_line
cd get_next_line

2. Create a Main File for Testing

Example

#include "get_next_line.h"
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void test_file(const char *filename, int fd_to_use)
{
	int     fd;
	char    *line;
	int     line_nb;

	printf("\n=== Test file: %s ===\n", filename);

	if (fd_to_use >= 0)
		fd = fd_to_use;
	else
	{
		fd = open(filename, O_RDONLY);
		if (fd < 0)
		{
			perror("open");
			return;
		}
	}

	line_nb = 0;
	while (1)
	{
		line = get_next_line(fd);
		if (!line)
			break;

		line_nb++;
		printf("Line %3d |%s| (len: %zu)\n", line_nb, line, ft_strlen(line));
		free(line);
	}

	printf("→ End after %d lines\n", line_nb);

	if (fd_to_use < 0)
		close(fd);
}

int main(void)
{
	printf("BUFFER_SIZE = %d\n\n", BUFFER_SIZE);

	test_file("files/test.txt", -1);

	printf("\n=== Test STDIN (Ctrl+D to finish) ===\n");
	test_file("STDIN", 0);

	return 0;
}

3. Compile

# Default BUFFER_SIZE
cc -Wall -Wextra -Werror get_next_line.c get_next_line_utils.c -o gnl_test

# Custom BUFFER_SIZE
cc -Wall -Wextra -Werror -D BUFFER_SIZE=1 get_next_line.c get_next_line_utils.c -o gnl_test

cc -Wall -Wextra -Werror -D BUFFER_SIZE=42 get_next_line.c get_next_line_utils.c -o gnl_test

cc -Wall -Wextra -Werror -D BUFFER_SIZE=9999 get_next_line.c get_next_line_utils.c -o gnl_test

4. Run

./gnl_test

Resources

YouTube

Articles

42 Guide

AI Assistance

  • Gemini

Used to:

  • Better understand how BUFFER_SIZE impacts reading behavior
  • Clarify temporary memory storage strategy
  • Improve newline (\n) and EOF handling
  • Structure and refine the README documentation

Algorithm Explanation and Justification

Why This Algorithm Is Used

read() does not read a line. It reads a fixed number of bytes.

Problems:

  • A line may be larger than BUFFER_SIZE.
  • A line may be split across multiple read() calls.
  • read() does not preserve state between calls.
  • Multiple file descriptors may be used simultaneously.

To solve this, the algorithm:

  1. Accumulates partial data.
  2. Stores unused data between function calls.
  3. Returns exactly one complete line per call.

How the Algorithm Works

1. Persistent Storage Per File Descriptor

static char *remain[FD_MAX];

Each file descriptor has its own persistent buffer.

Purpose:

  • Prevent interference between multiple FDs.
  • Preserve leftover data for the next call.

2. Read Until a Newline Is Found

Function: read_to_static()

Steps:

  1. Allocate a temporary buffer of size BUFFER_SIZE.
  2. Call read(fd, buffer, BUFFER_SIZE).
  3. Append the buffer to remain[fd].
  4. Repeat until:
    • A \n is found, or
    • read() returns 0 (EOF).

Core loop:

while (!ft_strchr(*remain, '\n') && bytes_read > 0)

Purpose:

  • Stop reading once a complete line exists.
  • Minimize unnecessary system calls.

3. Extract the Line

Function: extract_line()

Steps:

  1. Scan remain until \n or \0.
  2. Copy that portion using ft_substr.
  3. Return the newly allocated string.

Result:

  • The returned line is independent.
  • The caller is responsible for freeing it.

4. Update the Remaining Buffer

Function: update_remain()

Example:

Before extraction:

"Hello\nWorld\n"

After extracting "Hello\n":

Remaining buffer:

"World\n"

If nothing remains:

  • Free the memory.
  • Set pointer to NULL.

Purpose:

  • Avoid re-reading the same data.
  • Maintain correct state across calls.

Execution Flow

Each call to get_next_line(fd):

  1. Validates the file descriptor.
  2. Reads and accumulates data until a newline is found.
  3. Extracts one line.
  4. Updates the remaining buffer.
  5. Returns the line.

Guarantees

This implementation ensures:

  • Correct line boundaries.
  • No data loss.
  • Support for multiple file descriptors.
  • Safe and controlled memory management.

About

Get next line for 42 school

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages