views:

628

answers:

11

Hi, Say i have a file, t.txt, that contains the following two lines:

one

two

Now, I would like to write a program which will #include that file somehow and print its contents, nothing more. That is, i want the contents of that file to appear in my code as a static text, at compile time.

Any ideas?


The reason im asking is this:

I would like to create a quine by including my own file (with ifndefs to prevent recursive inclusion after the first two): http://en.wikipedia.org/wiki/Quine_(computing) . So I'd still love to get an answer.

A: 

Would something like this work for you?

example.c

static const char *var = 
#include "staticstring.txt"
;

int main() {
    printf( "%s\n" var );
    return 0;
}

staticstring.txt

"Some string that gets included at compile time"

I'm sure there's a way that you can do it without having the quotes inside the text file, but nothing is coming to mind right now.

Graeme Perrow
That's a solution i've tried before. It has (at least) two downsides: 1. it will not work without the quotes. 2. it will not work with multiple lines. Thanks alot, and I'd really appreciate it if anybody has a better solution :)
rmn
+2  A: 

Alternative solution (since the original one won't work without limitations, as mentioned in the comments): As part of your build process, use a script (perl or python would do it easily) to generate staticstring.h from staticstring.txt, adding quotes and \n's as necessary, then use the other solution. This way your original file does not change.

You want to change

Text file with text
on multiple
lines

to

"Text file with text\n"
"on multiple\n"
"lines"

I think that doing it purely with the preprocessor is not possible.

Graeme Perrow
I really would not want to change the file, if possible. I suspect, like you, that it can't be done (I've wasted quite some time on this myself), but i'd love to be surprised.. Thanks for the suggestion.
rmn
@rmn But why can't you treat generated file as a temporary file required just for build? Original txt-file stays intact. (Sorry if I am not following. :)
Virne
Virne is right, that's the idea. We do this during our build in a number of places.
Graeme Perrow
This is not a suitable solution to what I'm trying to do..
rmn
OK, if you can explain why it's not suitable, we might be able to come up with something.
Graeme Perrow
I would like to create a quine by including my own file (with ifndefs to prevent recursive inclusion after the first two): http://en.wikipedia.org/wiki/Quine_(computing) .I'd still love to get an answer, though :)
rmn
+1  A: 

This is the Microsoft Tutorial to do that: http://support.microsoft.com/kb/816181/en-us

It is not explaining how to embedd the file programatically or via preprocessor, but via the Visual Studio 2005+ menus. And explains how to read it back from the resources sector.

Borland Delphi does that via preprocessor, I don't know about C++. But I know it is possible to edit the resources by hand and include it, just like the VS do.

Havenard
Delphi doesn't have a preprocessor. It's a single pass compiler. You're thinking of compiler directives, which have nothing to do with a preprocessor.
Ken White
+1  A: 

xxd -i

See here: previous answer

Charles Bailey
+1, the question is, though, if it's safe to rely on `xxd` being available. I used `sed` for similar purpose (it's a plaintext file after all).
Michael Krelin - hacker
A: 

You could do this in the makefile:

all:  target

TEXT_FILES  = $(wildcard *.txt)
TEXT_OBJS   = $(patsubst %.txt,%.text.o,$(TEXT_FILES))


target: main.o $(TEXT_OBJS)
    $(CXX) -o app $^

%.text.cpp: %.txt
    @echo "Building Text Source $*"
    @echo "char const* $* =" > $@
    @awk '{print "\"" $$0 "\\n\"";}' $^ >> $@
    @echo ";" >> $@

What this does.
If you have a text file called plop.txt. Then it creates a file plop.text.cpp with the variable 'char const* plop ='. Once compiled the temporary file is removed but if you change the plop.txt file it will be auto-magically be rebuilt into plop.text.o

This is then all combined together:

The following Example is what I tested:

> cat main.cpp

#include <iostream>
extern char* text;

int main()
{
std::cout << text;
}

> cat text.txt 

Hi there this is a file
with multiple lines
we want to print out.
> make
g++    -c -o main.o main.cpp
Building Text Source text
g++    -c -o text.text.o text.text.cpp
g++ -o app main.o text.text.o
rm text.text.cpp
> ./app

Hi there this is a file
with multiple lines
we want to print out.
>
Martin York
A: 

What I did was this:

COPYING.cc: ${top_srcdir}/COPYING
    echo "const char * COPYING = " >$@ || (rm $@;exit 1)
    sed -e 's/"/\\"/g' -e 's/^/\"/' -e 's/$$/\\n\"/' $< >>$@ || (rm $@;exit 1)
    echo ';' >>$@ || (rm $@;exit 1)

in my Makefile. I then referred to it as extern const char *COPYING, but one can #include it as well.

Michael Krelin - hacker
A: 

You can use objcopy to create an object file out of the source file and link it with the actual object file. It creates the symbols _binary_objfile_start, _binary_objfile_end and _binary_objfile_size, which you can access as an array of char.

Ozan
A: 

As far as I'm aware, the shortest possible quine in C is this:

main(){char*a="main(){char*a=%c%s%c;printf(a,34,a,34);}";printf(a,34,a,34);}

Note that this is not valid C++, since it uses an implicit definition of printf(). To make it valid C++, you need to do this:

#include <stdio.h>
main(){char*a="#include <stdio.h>%cmain(){char*a=%c%s%c;printf(a,10,34,a,34);}";printf(a,10,34,a,34);}

No tricky include tricks -- just carefully constructing a string and printing it out twice, and using ASCII codes (10 and 34 instead of '\n' and '"') to avoid annoyingness with having to escape stuff.

Adam Rosenfield
A: 

I don't believe it's going to be possible, as you can't #include an arbitrary text file in C. The reason is that there are no multi-line constants in C (although you can concatenate a number of single-line string constants).

The only options I can see are to require that each line of the text file be quoted, or generate a temporary file at build-time (as others have suggested).

Martin
A: 

t.t:

printf ("int main () {\n");
printf ("#include <t.t>\n");
printf ("}");
return 0;

t.c

int main () {
#include <t.t>
}


$ gcc -I. t.c
$ ./a.out
int main () {
#include <t.t>
}

Update: If you are not after a pure quine, but just something that will spit out the contents of the included file, you can do the following:

t.c:

#include <stdio.h>
#include "t.t"

t.t:

#define FOO(f) do { \
        FILE * ff = fopen(f, "rb"); \
        char foo[255] = {0}; \
        while (fgets (foo, 255, ff)) { \
                printf ("%s", foo); \
        }\
        fclose(ff); \
} while (0)

int main () {
        FOO("t.t");
        return 0;
}

running this yields

$ gcc t.c
$ ./a.out
#define FOO(f) do { \
        FILE * ff = fopen(f, "rb"); \
        char foo[255] = {0}; \
        while (fgets (foo, 255, ff)) { \
                printf ("%s", foo); \
        }\
        fclose(ff); \
} while (0)

int main () {
        FOO("t.t");
        return 0;
}
ezpz
A: 

It's very easy:

#include <stdio.h>

// include the file somehow
#define one 
#define two 
#include "t.txt"

int main(int argc, char* argv[])
{
    // and print the contents of the file
    const char* static_text = "one\ntwo\n";
    printf(static_text);

    // nothing more ;-)
    return 0;
}

Seriously, it's not possible to "#include" an arbitrary file. (Go with one of the preprocessing suggestions given in other answers if you need this.)

If the contents of the file is not arbitrary, but contains something meaningful to the compiler, you might be able to hack something together. To make the contents meaningful, you can use C code and/or define's as I did above.

Ralph