0

I am modifying a parser I've inherited which currently only reads from FILE* via read. It now has the requirement of being able to pull data from char* constants as well so inline text inside C strings can be parsed.

I've looked at providing a simple interface to both in the form of "readers" so you can provide a file reader and a char reader from which the parser can grab characters. For example:

// Inputs
const char *str = "stringToParse";
FILE *f = fopen(...);

// Creating a reader. Each reader stores a function ptr to a destructor
// which closes the file if required and an internal state object.
Reader *r = FileReader(f);
// -or- 
Reader *r = CharReader(str);

// Start parsing ---------------------------
// Inside the parser, repeated calls to:
int error = ReadBytes(&buf /* target buf */, &nRead /* n read out */, maxBytes /* max to read */);
// End parsing -----------------------------

CloseReader(&r); // calls destructor, free's state, self

I'd like to keep this really simple. Are there any obvious other ways to achieve this using less infrastructure that I have missed?

Note: I have simplified this considerably from what is there to highlight the programming interface concerns. It actually uses wchar_t internally and a mush of encoding stuff and is a bit of a rat's nest which I will untangle at the same time.


Thanks to everyone who answered. The cleanest answer is to use fmemopen. I've provided a full example below:

#include <stdio.h>
#include <string.h>

void dump(FILE *f) {
        char c;
        while ((c = fgetc(f)) != EOF)
                putchar(c);
}

int main(int argc, char *argv[]) {
        /* open string */
        const char str[] = "Hello string!\n";
        FILE *fstr  = fmemopen(&str, strlen(str), "r");

        /* open file */
        FILE *ffile = fopen("hello.file", "r");

        /* dump each to stdout */
        dump(ffile);
        dump(fstr);

        /* clean up */
        fclose(ffile);
        fclose(fstr);
}
pointyhat
  • 167
  • 1
  • 1
  • 10

2 Answers2

3

You don't even need a CharReader in your infrastructure. Instead, the following should work when memory buffers have the same layout as files:

const char *str = "stringToParse";
FILE *f = fmemopen(str, strlen(str), "r");

Reader *r = FileReader(f);

// use FileReader to read from string...
jop
  • 2,226
  • 15
  • 16
0

Its pretty hard to have a simpler API than "create_resource", "use_resource", "free_resource". So abstraction wise this seems pretty reasonable.

I assume &nRead is the stream reader argument to ReadBytes? If not, how does ReadBytes indicate which stream it wants to process? (If this is the only stream you are going to process, then you can leave the resource unnamed and simply refer to the unique one in ReadBytes. But in that case, Reader and CloseReader need not return the stream entity either).

Ira Baxter
  • 93,541
  • 22
  • 172
  • 341