Assuming your code is stored in file foo
, all you need is to open the file and read it. To open the file, you need fopen()
, defined in stdio.h. You can then read it line by line using fgets()
. I'm not familiar with mruby, so I'm not exactly sure if mrb_load_string expects that every mruby code is in a single line. I will assume so. Here's how you can do it:
#define MAX_CODE_SIZE 128
FILE *code;
char code_buf[128]
code = fopen("foo", "r");
if (code == NULL) {
/* File couldn't be opened, handle error case... */
}
fgets(code_buf, MAX_CODE_SIZE, code);
/* Do some work ... */
fclose(code); /* Don't forget to close the file */
This piece of code reads the first line of file foo
, up to a limit of 127 characters (including newline), and stores it in code_buf
. You can then call mrb_load_string
:
mrb_load_string(mrb, code);
I'm not sure if this is what you wanted, I never touched mruby, but from what I saw, mrb_load_string
expects a char *
with the code, and you want that to come from a file. That's how you do it.
If you want to read a file with code in multiple lines, you have no choice but to allocate a large enough buffer and read it using fread()
:
#include <stdio.h>
#define MAX_LINE_LENGTH 128
#define MAX_LINES 256
#define MAX_FILE_SIZE MAX_LINE_LENGTH*MAX_LINES
char code[MAX_FILE_SIZE];
int read_code(char *filepath) {
FILE *fp = fopen(filepath, "r");
if (fp == NULL)
return 0;
fread(code, 1, MAX_FILE_SIZE, fp);
fclose(fp);
return 1;
}
This function reads the whole file (assuming it doesn't exceed our buffer limits). code
is global because you can easily reach the stack capacity if you allocate large local variables (another alternative is to use dynamic allocation). When you call read_code()
, you should make sure to check its return value, to check for possible errors upon opening the file. Also, you can play with fread()
's return value to know if the buffer size wasn't enough to read everything.
Just make sure you don't forget to close the file when you're done.
EDIT: For the fgets()
version, please note that in case the line holds less than 128 characters, newline will be retained in code_buf
. You may want to set code_buf[strlen(code_buf)-1]
to '\0'
if that's the case.
UPDATE:
From our discussion on the comments below, I am updating my answer with a rudimentary parser to enable you to read the ruby file at compile time. Basically, the parser will read your ruby file and generate an output file with valid C code that inserts the file's content in a char array. Special characters are accordingly escaped. Here it is:
#include <stdio.h>
void inline insert(int, FILE *);
int main(int argc, char *argv[]) {
FILE *out, *in;
int c;
if (argc != 3) {
printf("Usage: %s <input_file> <output_file>\n", argv[0]);
return 1;
}
in = fopen(argv[1], "r");
out = fopen(argv[2], "w");
if (out == NULL) {
printf("Unable to create or write to %s\n", argv[1]);
return 1;
}
if (in == NULL) {
printf("Unable to read %s\n", argv[1]);
return 1;
}
fputs("#ifndef MRUBY_CODE_FILE_GUARD\n", out);
fputs("#define MRUBY_CODE_FILE_GUARD\n", out);
fputs("char mruby_code[] = \"", out);
while ((c = getc(in)) != EOF)
insert(c, out);
fputs("\";\n", out);
fputs("#endif\n", out);
fclose(in);
fclose(out);
return 0;
}
void inline insert(int c, FILE *fp) {
switch (c) {
case '\a':
fputs("\\a", fp);
break;
case '\b':
fputs("\\b", fp);
break;
case '\f':
fputs("\\f", fp);
break;
case '\n':
fputs("\\n", fp);
break;
case '\r':
fputs("\\r", fp);
break;
case '\t':
fputs("\\t", fp);
break;
case '\v':
fputs("\\v", fp);
break;
case '\\':
fputs("\\\\", fp);
break;
case '\'':
fputs("\\'", fp);
break;
case '"':
fputs("\\\"", fp);
break;
default:
fputc(c, fp);
}
}
Now, go back to your original program and add the following include directive in the beginning:
#include mruby_code.h
You have to do the following steps to compile a runnable program, assuming that this parser was compiled into a file named fileparser.c
:
- Run
./fileparser /path/to/mruby_code_file /path/to/program/mruby_code.h
.
- Compile your original program (it will include
mruby_code.h
)
The mruby code is provided in a variable called mruby_code
. This is a char array, so you can pass it to mrb_load_string
. And voila, you got the mruby file read once at compile time.