-1

I need a code to read using the function read from stdin until there's a newline, and then use that line. The thing is that I can't just read chars and putting them in a array until I read "\n" cause the exercise requires to read a max of 16bytes at a time.

I tried using the function strtok to divide the lines using the divider "\n" but it doesn't work as I want, so is there any way to only read until it detects the "\n"? Also I need it to be constantly reading it.

Here is what I have right now:

void readline(char *buf, unsigned buf_size){
    ssize_t num_read;
    while((num_read = read(STDIN_FILENO,buf,buf_size)) > 0){
    }
}

Then in the main function:

while(i == 0){ 
    readline(buf,BUF_SIZE);
    token1 = strtok(buf,"\n");
    while(token1 != NULL){
        orden->num=0;
        token2 = strtok(token1, " ");
        orden->args[orden->num] = token2;
        while(token2 != NULL){
            if(token2!=NULL) {
                orden->num+=1;
                orden->args[orden->num] = token2;
            }
        }
        orden->num+=1;
        orden->args[orden->num] = NULL;
        insertar_final(lista,orden);
        token1 = strtok(NULL,"\n");
    };
...

The others strtoks declarations using " " are for other things my code needs, but that works so don't mind them.

wovano
  • 4,543
  • 5
  • 22
  • 49
  • 2
    I am confused. Do you want to read until '\n' or read 16 bytes? Or read up to 16 bytes, stopping when you hit '\n'? What does `strtok` have to do with it? Could we see the specification of the problem? – Neil Oct 08 '22 at 16:47
  • Sorry I didn't made it clear. I need to read up to 16 bytes and stopping when I hit 16 bytes. I used strtok to try a form to divide the full buffer on the divider "\n" – Joaquín Ayala Filardi Oct 08 '22 at 16:49
  • 1
    Why can't you use `fgets` to read max 16 bytes? It will stop reading at 16 bytes or (and including) the newline, and anything else remains in the input buffer. – Weather Vane Oct 08 '22 at 17:09
  • So `readline` reads 16 bytes? You later parse it into lines in `main`? How do you get memory if your line is greater then 16 bytes? – Neil Oct 08 '22 at 17:11
  • Does it also reads from stdin? – Joaquín Ayala Filardi Oct 08 '22 at 17:11
  • `read` is non-standard and possibly less-buffered; `fgets` would be a much better solution, if possible. – Neil Oct 08 '22 at 17:22
  • I tried to use fgets and it reads the 16 bytes I need, but it ignores the \n. For example if I write from stdin "Hello\nHello\nHello\n" and write what the program reads in the stdout it writes "Hello\nHello\nH" and in another line "ello\n". It does read 16 bytes but it ignores the \n. Also is it posible to stick together the lines if they're higher than 16 bytes? The lines must have a maximum of 128 bytes and I need to read them in groups of 16, so I need to detect the whole line. – Joaquín Ayala Filardi Oct 08 '22 at 17:24
  • 1
    The `fgets()` does *not* ignore a newline. It stops reading there, and so you don't need `strtok()`. It's unclear what you are trying to achieve. – Weather Vane Oct 08 '22 at 17:27
  • I need to read lines of a maximum of 128 bytes in pieces of 16 bytes and stick all the parts together. So, I need to read the line 16 bytes at a time until it detects the \n – Joaquín Ayala Filardi Oct 08 '22 at 17:28
  • 1
    So, use `fgets` to read into `buffer + n * 16` in 16-byte chunks until the newline is detected. – Weather Vane Oct 08 '22 at 17:31
  • That's what I tried now, but it doesn't read until newline. It reads the whole 16 bytes even when the line is shorter – Joaquín Ayala Filardi Oct 08 '22 at 17:46
  • Sorry this site is not an interactive tutorial. Have a go at reworking you code and ask a new question if needed. – Weather Vane Oct 08 '22 at 17:52
  • NB: OP continued this question [here](https://stackoverflow.com/questions/73999895/read-with-fgets-until-n) – wovano Oct 09 '22 at 07:39

1 Answers1

0

From your code, forget the 16 bytes thing.

You are just trying to store an array of words separated by whitespace (e.g. space and/or newline). The words may be [up to] 16 bytes but that doesn't really matter.

Use fgets. It does not strip a newline.

Your issue is that the buffer is reused on each separate line. So (e.g.), on the second line read, it overwrites the words from the first line.

You need to use strdup to save a unique copy of each token.

Change:

orden->args[orden->num] = token2;

Into:

orden->args[orden->num] = strdup(token2);

Here is some refactored code:

char buf[128 + 1];

while (fgets(buf,sizeof(buf),stdin) != NULL) {
    // save off all whitespace separated tokens
    char *tok = strtok(buf," \n");
    while (tok != NULL) {
        orden->args[orden->num++] = strdup(tok);
        tok = strtok(NULL," \n");
    }

    // add NULL terminator
    orden->args[orden->num] = NULL;

    // add line to list of lines
    insertar_final(lista,orden);
}
Craig Estey
  • 30,627
  • 4
  • 24
  • 48
  • No, that's a different thing my code needs to do, and that works perfectly. I need the 16 bytes things cause is a requirement in the project the teacher told us to do. – Joaquín Ayala Filardi Oct 08 '22 at 18:41
  • @JoaquínAyalaFilardi So, your teacher wants you to recreate the functionality that `fgets` provides using `read` with a length of 16??? – Craig Estey Oct 08 '22 at 18:50
  • No, he hasn't told us to use read function, I was trying with that. I have also tried using fgets but it doesn't at the '\n' char, it reads the while 16 bytes – Joaquín Ayala Filardi Oct 08 '22 at 19:17
  • No, `fgets` will _stop_ at the newline. But, the newline spanning a boundary is an issue. You could try `mmap`. See my answer: [read line by line in the most efficient way *platform specific*](https://stackoverflow.com/a/33620968/5382650) – Craig Estey Oct 08 '22 at 19:27
  • The thing is that I have to use the Linux terminal using the stdout of a command as the stdin. For example if a use echo "Hello\nHello\nHello" | ./mycode it needs to recognize the '\n' as the end of the line, and it doesn't – Joaquín Ayala Filardi Oct 08 '22 at 19:32
  • @JoaquínAyalaFilardi Please edit your _question_ and post more exact constraints. Again, do you have to implement your own version of `fgets`? What are the exact constraints on your line read function? – Craig Estey Oct 08 '22 at 19:53
  • The program I need to develope reads from stdin Linux commands and create a son process to execute that command. It needs to be constantly be reading lines up to 128bytes in chunks of 16bytes. That's the problem I have. I don't know how to teach the program to recognize different lines and to combine the 16 bytes pieces together – Joaquín Ayala Filardi Oct 08 '22 at 19:58
  • @JoaquínAyalaFilardi Remember I said _edit your **question**_? Take _all_ of the comments you've been posting here and in the top section and put them into a complete full problem description in the question. You just added an additional part of the problem (e.g. "son process") that should have been in the description from the beginning. I've asked a few specific questions [repeatedly] that you've not answered. – Craig Estey Oct 08 '22 at 20:06
  • What I did is creating a whole new question with new code. Also I did not mention the son process because I don't have a problem with that, I have a problem reading from stdin as I was requested. And what questions? – Joaquín Ayala Filardi Oct 08 '22 at 20:19