Question

I have a C function that reads a stream of characters from a FILE*.

How might I create a FILE* from a string in this situation?

Edit:

I think my original post may have been misleading. I want to create a FILE* from a literal string value, so that the resulting FILE* would behave as though there really was a file somewhere that contains the string without actually creating a file.

The following is what I would like to do:

void parse(FILE* f, Element* result);

int main(int argc, char** argv){
    FILE* f = mysteryFunc("hello world!");
    Element result;
    parse(f,&result);
}
Was it helpful?

Solution

Standard C provides no such facility, but POSIX defines the fmemopen() function that does exactly what you want.

OTHER TIPS

Unfortunately, C's standard library doesn't provide this functionality; but there are a few ways to get around it:

  • Create a temporary file, write your string to it, then open it for reading. If you've got POSIX, gettempnam will choose a unique name for you

  • The other option (again for POSIX only) is to fork a new process, whose job will be to write the string to a pipe, while you fdopen the other end to obtain a FILE* for your function.

  • As @KeithThompson pointed out, fmemopen does exactily what you want, so if you have POSIX, use that. On any other platform, (unless you can find the platform-equivalent), you'll need a temporary file.

Last time I had this kind of problem I actually created a pipe, launched a thread, and used the thread to write the data into the pipe... you would have to look into operating system calls, though.

There are probably other ways, like creating a memory mapped file, but I was looking for something that just worked without a lot of work and research.

EDIT: you can, of course, change the problem to "how do I find a nice temporary filename". Then you could write the data to a file, and read it back in :-)

pid_t pid;
int pipeIDs[2];

if (pipe (pipeIDs)) {
   fprintf (stderr, "ERROR, cannot create pipe.\n");
   return EXIT_FAILURE;
} 

pid = fork ();
if (pid == (pid_t) 0) {
   /* Write to PIPE in this THREAD  */

   FILE * file = fdopen( pipe[1], 'w');

   fprintf( file, "Hello world");
   return EXIT_SUCCESS;

} else if (pid < (pid_t) 0) {
  fprintf (stderr, "ERROR, cannot create thread.\n");
  return EXIT_FAILURE;
}


FILE* myFile = fdopen(pipe[0], 'r');

// DONE! You can read the string from myFile

....  .....

Maybe you can change the code a little bit to receive a custom handle.

void parse(my_handle *h, Element *result)
{
  // read from handle and process
  // call h->read instead of fread
}

and defines the handle like this:

struct my_handle
{
    // wrapper for fread or something
    int (*read)(struct my_handle *h, char *buffer, int readsize);
    // maybe some more methods you need
};

implement your FILE* wrapper

struct my_file_handle
{
    struct my_handle base;
    FILE *fp;
};

int read_from_file(struct my_handle *h, char *buffer, int readsize)
{
    return fread(buffer, 1, readsize, ((my_file_handle*)h)->fp);
}

// function to init the FILE* wrapper
void init_my_file_handle(struct my_file_handle *h, FILE *fp)
{
    h->base.read = read_from_file;
    h->fp = fp;
}

Now, implement your string reader

struct my_string_handle
{
    struct my_handle base;
    // string buffer, size, and current position
    const char *buffer;
    int size;
    int position;
};

// string reader
int read_from_string(struct my_handle *h, char *buffer, int readsize)
{
    // implement it yourself. It's easy.
}

// create string reader handle
void init_my_string_handle(struct my_string_handle *h, const char *str, int strsize)
{
    // i think you know how to init it now.
}

//////////////////////////////////////////////////

And now, you can simply send a handle to your parse function. The function doesn't care where the data comes from, it can even read data from network!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top