ouhma ouhma - 1 month ago 17
C Question

How could I allocate a variable length command output?

I have a bash script which prints a single huge line of variable output.
All the examples I've seen uses a fixed buffer of 1024 bytes or so, in order to read line by line.

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

int main( int argc, char *argv[] ) {

FILE *fp;
char path[1024];

/* Open the command for reading. */
fp = popen("bash /home/ouhma/myscript.sh", "r");
if (fp == NULL) {
printf("Failed to run command\n" );
exit(1);
}

/* Read the output a line at a time - output it. */
while (fgets(path, sizeof(path)-1, fp) != NULL) {
printf("%s", path);
}

/* close */
pclose(fp);

return 0;
}


Link reference: C: Run a System Command and Get Output?

But what if I don't know if the output line has a length even bigger of 1024 bytes?
How could I handle it through reading with
popen()
command?

alk alk
Answer

But what if I don't know if the output line has a length even bigger of 1024 bytes

You then need to handle the storage for incoming data dynamically.

To do so you would additionally to what you show add a dynamically allocated "string" which grows if fully used by reallocating it to provide more room.

Code doing so might look like this:

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


#define BUFFER_SIZE (1024)
#define START_SIZE (1) /* Has to be > 0 */


int main(void) 
{
  size_t s = START_SIZE;
  char * path = malloc(s);
  if (NULL == path)
  {
    perror("malloc() failed");
    return EXIT_FAILURE);
  }

  path[0] = '\0';

  {
    /* Open the command for reading. */
    FILE * fp = popen("bash /home/ouhma/myscript.sh", "r");
    if (NULL == fp) 
    {
      perror("popen() failed");
      return EXIT_FAILURE); /* By returning here the code leaks the memory
                               already allocated to path as well as fp. */
    }

    {
      char buffer[BUFFER_SIZE];

      /* Read the output a line at a time - output it. */
      while (NULL != fgets(buffer, sizeof buffer, fp)) 
      {
        fprintf(stderr, "partly read: '%s'\n", buffer);

        while ((s - 1) < strlen(buffer))
        {
          void * p = realloc(path, s *= 2); /* Grow s exponentially. */
          if (NULL == p)
          {
            perror("realloc() failed");
            return EXIT_FAILURE; /* By returning here the code leaks the memory
                                    already allocated to path as well as fp. */
          }

          path = p;
        }

        /* Concatenate what just had been read to final "string". */
        strcat(path, buffer);
      }
    }

    if (!feof(fp))
    {
      perror("fgets() failed");
    }

    /* Close file. */
    if (-1 == pclose(fp))
    {
      perror("pclose() failed");
    }
  }

  /* Print result. */
  printf("read: '%s'\n", path);

  /* Clean up. */
  free(path);

  return EXIT_SUCCESS;
}

Clean up of open file descriptors and dynamically allocated memory in case of any failure is left as an exercise to the reader ... ;-)