octowaddle
octowaddle

Reputation: 93

Read from pipe into C string

I want to swapn a program and capture it's output. I use popen to spawn it, but I just can't get the "contents" to be stored in a dynamically allocated c string (char *).

This is what I got:

char *spawn(char *command, int *status) {
    FILE *pipe = popen(command, "r");
    
    char line[LINE_MAX];
    char *buffer = NULL;
    size_t buffer_size = 0;
    
    while (fgets(line, sizeof (line), pipe)) {
        size_t line_length = strlen(line);
        
        buffer = realloc(buffer, (buffer_size + line_length) * sizeof *buffer);
        memcpy(buffer + buffer_size, line, line_length);
        buffer_size += line_length;
    }
                
    if (status) {
        *status = WEXITSTATUS(pclose(pipe));
    } else {
        pclose(pipe);
    }

    return buffer;
}

For some weird reason the string is always slightly too long and I get random characters at the end (e.g. ���7V). I already tried my own implementation of strlen which counts until a newline character appears (including it), but it didn't help. I also tried strcpy but this lead to a crash. I just can't find my mistake. Any help is greatly appreciated!

Upvotes: 0

Views: 520

Answers (1)

chux
chux

Reputation: 153602

some weird reason the string is always slightly too long

Code is not forming a string in buffer as it has no null character nor space for it. Better to allocate space for the '\0' and copy it in.

// size_t buffer_size = 0;
size_t buffer_len = 0;

while (fgets(line, sizeof (line), pipe)) {
    size_t line_length = strlen(line);
    
    // buffer = realloc(buffer, (buffer_size + line_length) * sizeof *buffer);
    buffer = realloc(buffer, (buffer_len + line_length + 1) * sizeof *buffer);

    // memcpy(buffer + buffer_size, line, line_length);
    memcpy(buffer + buffer_len, line, line_length + 1);

    // buffer_size += line_length;
    buffer_len += line_length;
}

Robust code would also check for allocation success.

Upvotes: 1

Related Questions