1

Well, i am trying to create a program that reads from a file descriptor piece by piece (defined as BUFFER_SIZE), until it finds a '\n' or the EOF. The problem its i am getting stuck in a infinite loop, which i try to address the cause without success, (you can notice the printf's all around the code). note: for this assignment i am only allowed to use a limited number of standard functions so to use realloc i have to implement my own, same with strlen and others. (assume that they are correct). ALLOWED FUNCTIONS: WRITE, READ, MALLOC AND FREE. There is the code:

void    *ft_realloc(void *ptr, size_t oldsize, size_t size)
{
void    *new;
size_t  minsize;

if (size == 0)
{
    free(ptr);
    return (NULL);
}
if (ptr == NULL)
    return (malloc(size));
new = malloc(size);
if (!new)
   return (NULL);
minsize = size;
if (oldsize < size)
   minsize = oldsize;
memcpy(new, ptr, minsize);
while (size - oldsize != 0)
   ((char *)new)[oldsize++] = '\0';
free(ptr);
return (new);
}

int find_newline_eof(char *buffer)
{
int i;

i = 0;
if (!buffer)
    return (-1);
while (buffer[i])
{
    if (buffer[i] == '\n')
        return (i);
    i++;
}
return (-1);
}

char    *extract_line(char **buffer, int newline_pos)
{
char    *line;
int     remaining_len;
//in terms of params, to newline be -1, means that we reach EOF 
 without '\n'
if (!*buffer)
    return (NULL);
if (newline_pos == -1)
    newline_pos = ft_strlen(*buffer);
line = malloc(newline_pos + 1);
if (!line)
    return (NULL);
memcpy(line, *buffer, newline_pos);
line[newline_pos] = '\0';
if ((*buffer)[newline_pos] == '\n')
    newline_pos++;
printf("reached EXTRACT_LINE, line: (%s)\n", line);
return (NULL); // The function reaches HERE, the error is beyond.
remaining_len = ft_strlen(*buffer + newline_pos);
// memmove safer against overlapping than memcpy
memmove(*buffer, *buffer + newline_pos, remaining_len + 1);
*buffer = ft_realloc(*buffer, ft_strlen(*buffer), remaining_len + 1);
if (!*buffer)
{
    free(line);
    return (NULL);
}
return (line);
}

int read_newpiece(int fd, char **buffer)
{
int         bytes_readed;
char        current_buffer[BUFFER_SIZE + 1];
char        *new_buffer;

bytes_readed = read(fd, current_buffer, BUFFER_SIZE);
if (bytes_readed <=0) //SAFE CHECKS
    return (bytes_readed);
current_buffer[bytes_readed] = '\0';
//printf("entered here!\n");
//return (bytes_readed);
if (!*buffer)
{
    *buffer = malloc(1);
    if (!*buffer)
        return (-1);
    (*buffer)[0] = '\0'; // Initialize as an empty string
}
new_buffer = ft_realloc(*buffer, ft_strlen(*buffer), 
ft_strlen(*buffer) + bytes_readed + 1);
if (!new_buffer)
    return (-1);
*buffer = new_buffer;
strncat(*buffer, current_buffer, bytes_readed);
return (bytes_readed);
}

char    *get_next_line(int fd)
{
static char *buffer = NULL;
char        *line; //returned value
int         newline_index; //position where we find the EOF or '\n';

if (fd < 0 || BUFFER_SIZE <= 0)
    return (NULL);
if (!buffer)
{
    buffer = malloc(1);
    if (!buffer)
        return (NULL);
    buffer[0] = '\0';
}
newline_index = -1; //-1 (NOT FOUND)
while (newline_index == -1 && read_newpiece(fd, &buffer) > 0)
{
    printf("buffer after read: /%s/\n", buffer);
    newline_index = find_newline_eof(buffer);
    printf("newline index: %d\n", newline_index);
    //return (NULL);
}
if (newline_index == -1 && !buffer)
   return (NULL);
line = extract_line(&buffer, newline_index);
printf("extracted line: ///%s///\n", line);
return (NULL);
}

int main(int ac, char **av)
{
int     fd;
char    *line;

if (ac < 2)
    return (write(1, "Usage: ./a.out <filename>\n", 27));
fd = open(av[1], O_RDONLY);
if (fd <= -1) //SAFE CHECKS
    return (write(1, "error opening file\n", 20));

while ((line = get_next_line(fd)) != NULL)
{
    printf("%s\n", line);
    free (line);
}
close (fd);
return (0);
}

the realloc take three params, the original buffer, the length of this buffer and the new desired size. It copies the entire buffer to a new one if the size > length, and copies (size) characters if the size if size < length. I appreciate any suggestion on any aspect of the code, but mainly to resolve the problem

i try to identify the issue step by step with aid of printf to check the value in some contexts

26
  • 2
    Also, for code such as write(1, "error opening file\n", 20), instead of relying on counting bytes, use something like static const char msg1[] = "error opening file\n"; write( 1, msg1, sizeof( msg1 ) - 1 ); Use multiple variable names like msg1, msg2, etc so you can easily use have more than one message. Commented Sep 11, 2024 at 21:29
  • 1
    What does find_newline_eof() do? How does it detect EOF? What happens if the input file doesn't end with newline? Commented Sep 11, 2024 at 21:29
  • 1
    None of the code after return (bytes_readed); in read_newpiece() ever executes. So it never copied into buffer. Commented Sep 11, 2024 at 21:31
  • 1
    static char *buffer = NULL is going to be trouble when you malloc it. Commented Sep 11, 2024 at 21:49
  • 2
    "I am not allowed to use functions" – that's in the submitted work. Start off with as many standard functions as you need, get the code working, and only then replace them with home-made functions. Commented Sep 11, 2024 at 21:58

1 Answer 1

2

get_next_line() returns on "" on every call so the infinite loop is in main():

    while ((line = get_next_line(fd)) != NULL) {
        printf("%s\n", line);
        free (line);
    }

This is because read_newpiece() never assigns anything to *buffer with the unconditional return bytes_readed in the middle of the function.

Here is a minimal implementation where OP can replace and/or reimplement restricted functions. It's possible to read a block at time but ideally caller would ideally retain the lookahead via argument (possible struct) instead of a static variable. Don't forget to handle short reads (read was able to read less than a block). Block size should probably be an argument. These all complicate the implementation.

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

// If you use a macro instead of a function then you can
// retain the regular realloc() interface.
void realloc_or_die(void **ptr, size_t n) {
    void *tmp = realloc(*ptr, n);
    if(!tmp) {
        perror("realloc failed");
        free(ptr);
        exit(1);
    }
    *ptr = tmp;
}

// Return number of bytes read not counting '\0'
size_t get_next_line(char **line, int fd) {
    size_t i = 0;
    for(;;) {
        realloc_or_die((void **) line, i+1);
        if(!read(fd, *line+i, 1)) {
            break;
        }
        i++;
        if((*line)[i] == '\n')
            break;
    }
    realloc_or_die((void **) line, i+1);
    (*line)[i] = '\0';
    return i;
}

int main(int ac, char **av) {
    if (ac < 2) {
        printf("Usage: ./a.out <filename>\n");
        return EXIT_FAILURE;
    }
    int fd = open(av[1], O_RDONLY);
    if (fd < 0) {
        printf("error opening file\n");
        return EXIT_FAILURE;
    }
    char *line = NULL;
    for(;;) {
        if(!get_next_line(&line, fd))
            break;
        printf("%s", line);
    }
    free (line);
    close (fd);
    printf("\n");
}

and example runs:

$ ./a.out <(printf 'hello\nworld\n')
hello
world

$ ./a.out <(printf 'hello')
hello
$
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.