How to Replace only Part of the Variable using #define - c++

#define C_TX_ TX_
#define C_RX_ RX_
enum Test
{
C_TX_MAC = 0x0100, // Pre-Processor should replace C_TX_ to TX_
C_RX_MAC = 0x0101 // But Not Working.
};
int main(int argc, char *argv[])
{
cout << TX_MAC; // HOW TO PRINT ?
cout << RX_MAC; // HOW TO PRINT ?
return true;
}

The pre-processor only operates on strings that are entire tokens. There would be chaos otherwise.
Try:
#define C_TX_MAC TX_MAC
#define C_RX_MAC RX_MAC

You cannot split a token with the pre-processor. You need to
#define C_RX_MAC RX_MAC
#define C_TX_MAC TX_MAC
(Of course there's ugly solutions such as adding a pre-pre-processing step:
sed s/C_ADDR_// x.cpp | g++ -x c++ -
But sed doesn't know about the context. It will replace strings e.g. cout << "And C_ADDR_RX = " with cout << "And RX = ".)

As stated in the other answers the pre-processor uses the whitespace to work out where the token is defined, and cannot replace it 'part way through". Perhaps you could try a "Find/Replace In Files" to rename the variables in your source code directly. Visual Studio's Find and Replace function can be used to replace any occurences in any folders/subfolders, or if you don't run with the Microsoft there's some other programs like NotePad++ that offer the same functionality. Both also support Regular Expressions for better targeted find/replace queries

The preprocessor replaces tokens, and C_TX_MAC is a full token.
However, you can achieve this fairly easily with some macro concatenation:
#include <iostream>
#define foo(x) C_ ## x
enum Test
{
C_TX_MAC = 0x0100, // Pre-Processor should replace C_TX_ to TX_
C_RX_MAC = 0x0101 // But Not Working.
};
int main()
{
std::cout << foo(TX_MAC) << ' ' << foo(RX_MAC) << '\n';
}
(live demo)
Easy. No need for sed, and no need for find-and-replace in your text editor.

Related

How to call macro that uses token pasting?

I am trying to print ffmpeg version in a C++ program. I see that in the /libavutil/version.h there is AV_VERSION which should tell the version number in the format x.x.x.
As a test I used some random numbers as function parameters like this: std::string version = AV_VERSION(3,4,2);. The same error I get if I use LIBAVUTIL_VERSION_MAJOR, LIBAVUTIL_VERSION_MINOR and LIBAVUTIL_VERSION_MICRO from the file. That was actually my first try to print the version number.
The error I get is invalid suffix '.2' on floating constant or invalid suffix '.101' on floating constant if I try to print std::cout << AV_VERSION(LIBAVUTIL_VERSION_MAJOR,LIBAVUTIL_VERSION_MINOR,LIBAVUTIL_VERSION_MICRO) << std::endl;
I do understand that the preprocessor is thinking that the token is a float, hence the error. How do you actually use this type of macro funtion?
That macro is in the file I mentioned above, so it must be a way to call that macro function without giving an error, thinking that is a mature library, and I guess other libraries use something similar for printing version number.
Here is how AV_VERSION is defined in the header file and how I call it:
#define AV_VERSION_INT(a, b, c) ((a)<<16 | (b)<<8 | (c))
#define AV_VERSION_DOT(a, b, c) a ##.## b ##.## c
#define AV_VERSION(a, b, c) AV_VERSION_DOT(a, b, c)
#define AV_VERSION_MAJOR(a) ((a) >> 16)
#define AV_VERSION_MINOR(a) (((a) & 0x00FF00) >> 8)
#define AV_VERSION_MICRO(a) ((a) & 0xFF)
#define LIBAVUTIL_VERSION_MAJOR 57
#define LIBAVUTIL_VERSION_MINOR 9
#define LIBAVUTIL_VERSION_MICRO 101
#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
LIBAVUTIL_VERSION_MINOR, \
LIBAVUTIL_VERSION_MICRO)
#define LIBAVUTIL_VERSION AV_VERSION(LIBAVUTIL_VERSION_MAJOR, \
LIBAVUTIL_VERSION_MINOR, \
LIBAVUTIL_VERSION_MICRO)
int main()
{
std::string version = AV_VERSION(3,4,2);
std::cout << AV_VERSION(LIBAVUTIL_VERSION_MAJOR,LIBAVUTIL_VERSION_MINOR,LIBAVUTIL_VERSION_MICRO) << std::endl;
return 0;
}
I coud've skip this error but as I'm trying to learn C++ I am pretty sure that I will find more of this type of macros so no point to avoid learning them now as I'm facing them.
Thanks in advance!
You need to use a stringize expansion. Because of how the preprocessor works, this involves two macros:
#define STR(x) #x
#define XSTR(x) STR(x)
The macro STR will take whatever parameter you give it and make that a string literal.
The macro XSTR will first expand its parameter x and the result will be the parameter to STR.
To illustrate:
STR(LIBAVUTIL_VERSION) will give "LIBAVUTIL_VERSION"
XSTR(LIBAVUTIL_VERSION) will give "57.9.101"
Demo according to your code:
int main()
{
std::string version1 = XSTR(LIBAVUTIL_VERSION);
std::string version2 = XSTR(AV_VERSION(3,4,2));
std::cout << version1 << "\n";
std::cout << version2 << "\n";
return 0;
}
Output:
57.9.101
3.4.2

Garbled character output when using cout API

I am trying to run this simple code in VS 2015
#include "stdafx.h"
# include <iostream>
int main()
{
char * szOldPath = "\"C:\icm\scripts\StartupSync\runall.bat\" nonprod";
std::cout << szOldPath << std::endl;
return 0;
}
However, the output of szOldPath is not proper and the console is printing--
unall.bat" nonprodupSync
I suspect this might be because of Unicode and I should be using wcout. So I disabled Unicode by going to Configuration Properties -> General --> Character Set and tried setting it to Not Set or Multi Byte. But still running into this issue.
I understand it is not good to disable UNICODE but I am trying to understand some legacy code written in our company and this experiment is a part of this exercise,is there any way I can get the cout command to print szOldPath successfully?
Your issue has nothing to do with Unicode.
\r is the escape sequence for a carriage return. So, you are printing out "C:\icm\scripts\StartupSync, and then \r tells the terminal to move the cursor back to the beginning of the current line, and then unall.bat" nonprod is printed, overwriting what was already there.
You need to escape all of the \ characters in your string literal, just like you had to escape the " characters.
Also, your variable needs to be declared as a pointer to const char when assigning a string literal to the pointer. This is enforced in C++11 and later:
#include "stdafx.h"
#include <iostream>
int main()
{
const char * szOldPath = "\"C:\\icm\\scripts\\StartupSync\\runall.bat\" nonprod";
std::cout << szOldPath << std::endl;
return 0;
}
Alternatively, in C++11 and later, you can use a raw string literal instead to avoid having to escape any characters with a leading \:
const char * szOldPath = R"("C:\icm\scripts\StartupSync\runall.bat" nonprod)";

Regex error at runtime Visual Studio 2019 [duplicate]

I would like to use regular expression from here:
https://www.rfc-editor.org/rfc/rfc3986#appendix-B
I am trying to compile it like this:
#include <regex.h>
...
regex_t regexp;
if((regcomp(&regexp, "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?", REG_EXTENDED)) != 0){
return SOME_ERROR:
}
But I am stuck with return value of regcomp:
REG_BADRPT
According to man it means:
Invalid use of repetition operators such as using * as the first character.
Similar meaning at this man:
?, * or + is not preceded by valid regular expression
I wrote parser using my own regular expression, but I would like to test this one too, since its officially in rfc. I do no intend to use it for validation though.
As Oli Charlesworth suggested, you need to escape backslash \\ for the question marks \?. See C++ escape sequences for more information.
test program
#include <regex.h>
#include <iostream>
void test_regcomp(char *rx){
regex_t regexp;
if((regcomp(&regexp, rx, REG_EXTENDED)) != 0){
std::cout << "ERROR :" << rx <<"\n";
}
else{
std::cout << " OK :"<< rx <<"\n";
}
}
int main()
{
char *rx1 = "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?" ;
char *rx2 = "^(([^:/\?#]+):)\?(//([^/\?#]*))\?([^\?#]*)(\\\?([^#]*))\?(#(.*))\?" ;
test_regcomp(rx1);
test_regcomp(rx2);
return 0;
}
output
ERROR :^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(?([^#]*))?(#(.*))?
OK :^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
The \?in your regex is the source of the REG_BADRPT error. It gets converted to ?. If you replace it by \\?, regcomp will be able to compile your regex.
"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"
OK :^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?

Get file string in compile time [duplicate]

Is there a way to include an entire text file as a string in a C program at compile-time?
something like:
file.txt:
This is
a little
text file
main.c:
#include <stdio.h>
int main(void) {
#blackmagicinclude("file.txt", content)
/*
equiv: char[] content = "This is\na little\ntext file";
*/
printf("%s", content);
}
obtaining a little program that prints on stdout "This is
a little
text file"
At the moment I used an hackish python script, but it's butt-ugly and limited to only one variable name, can you tell me another way to do it?
I'd suggest using (unix util)xxd for this.
you can use it like so
$ echo hello world > a
$ xxd -i a
outputs:
unsigned char a[] = {
0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x0a
};
unsigned int a_len = 12;
The question was about C but in case someone tries to do it with C++11 then it can be done with only little changes to the included text file thanks to the new raw string literals:
In C++ do this:
const char *s =
#include "test.txt"
;
In the text file do this:
R"(Line 1
Line 2
Line 3
Line 4
Line 5
Line 6)"
So there must only be a prefix at the top of the file and a suffix at the end of it. Between it you can do what you want, no special escaping is necessary as long as you don't need the character sequence )". But even this can work if you specify your own custom delimiter:
R"=====(Line 1
Line 2
Line 3
Now you can use "( and )" in the text file, too.
Line 5
Line 6)====="
I like kayahr's answer. If you don't want to touch the input files however, and if you are using CMake, you can add the delimeter character sequences on the file. The following CMake code, for instance, copies the input files and wraps their content accordingly:
function(make_includable input_file output_file)
file(READ ${input_file} content)
set(delim "for_c++_include")
set(content "R\"${delim}(\n${content})${delim}\"")
file(WRITE ${output_file} "${content}")
endfunction(make_includable)
# Use like
make_includable(external/shaders/cool.frag generated/cool.frag)
Then include in c++ like this:
constexpr char *test =
#include "generated/cool.frag"
;
You have two possibilities:
Make use of compiler/linker extensions to convert a file into a binary file, with proper symbols pointing to the begin and end of the binary data. See this answer: Include binary file with GNU ld linker script.
Convert your file into a sequence of character constants that can initialize an array. Note you can't just do "" and span multiple lines. You would need a line continuation character (\), escape " characters and others to make that work. Easier to just write a little program to convert the bytes into a sequence like '\xFF', '\xAB', ...., '\0' (or use the unix tool xxd described by another answer, if you have it available!):
Code:
#include <stdio.h>
int main() {
int c;
while((c = fgetc(stdin)) != EOF) {
printf("'\\x%X',", (unsigned)c);
}
printf("'\\0'"); // put terminating zero
}
(not tested). Then do:
char my_file[] = {
#include "data.h"
};
Where data.h is generated by
cat file.bin | ./bin2c > data.h
You can do this using objcopy:
objcopy --input binary --output elf64-x86-64 myfile.txt myfile.o
Now you have an object file you can link into your executable which contains symbols for the beginning, end, and size of the content from myfile.txt.
ok, inspired by Daemin's post i tested the following simple example :
a.data:
"this is test\n file\n"
test.c:
int main(void)
{
char *test =
#include "a.data"
;
return 0;
}
gcc -E test.c output:
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "test.c"
int main(void)
{
char *test =
# 1 "a.data" 1
"this is test\n file\n"
# 6 "test.c" 2
;
return 0;
}
So it's working but require data surrounded with quotation marks.
If you're willing to resort to some dirty tricks you can get creative with raw string literals and #include for certain types of files.
For example, say I want to include some SQL scripts for SQLite in my project and I want to get syntax highlighting but don't want any special build infrastructure. I can have this file test.sql which is valid SQL for SQLite where -- starts a comment:
--x, R"(--
SELECT * from TestTable
WHERE field = 5
--)"
And then in my C++ code I can have:
int main()
{
auto x = 0;
const char* mysql = (
#include "test.sql"
);
cout << mysql << endl;
}
The output is:
--
SELECT * from TestTable
WHERE field = 5
--
Or to include some Python code from a file test.py which is a valid Python script (because # starts a comment in Python and pass is a no-op):
#define pass R"(
pass
def myfunc():
print("Some Python code")
myfunc()
#undef pass
#define pass )"
pass
And then in the C++ code:
int main()
{
const char* mypython = (
#include "test.py"
);
cout << mypython << endl;
}
Which will output:
pass
def myfunc():
print("Some Python code")
myfunc()
#undef pass
#define pass
It should be possible to play similar tricks for various other types of code you might want to include as a string. Whether or not it is a good idea I'm not sure. It's kind of a neat hack but probably not something you'd want in real production code. Might be ok for a weekend hack project though.
You need my xtr utility but you can do it with a bash script. This is a script I call bin2inc. The first parameter is the name of the resulting char[] variable. The second parameter is the name of the file. The output is C include file with the file content encoded (in lowercase hex) as the variable name given. The char array is zero terminated, and the length of the data is stored in $variableName_length
#!/bin/bash
fileSize ()
{
[ -e "$1" ] && {
set -- `ls -l "$1"`;
echo $5;
}
}
echo unsigned char $1'[] = {'
./xtr -fhex -p 0x -s ', ' < "$2";
echo '0x00'
echo '};';
echo '';
echo unsigned long int ${1}_length = $(fileSize "$2")';'
YOU CAN GET XTR HERE xtr (character eXTRapolator) is GPLV3
Why not link the text into the program and use it as a global variable! Here is an example. I'm considering using this to include Open GL shader files within an executable since GL shaders need to be compiled for the GPU at runtime.
I reimplemented xxd in python3, fixing all of xxd's annoyances:
Const correctness
string length datatype: int → size_t
Null termination (in case you might want that)
C string compatible: Drop unsigned on the array.
Smaller, readable output, as you would have written it: Printable ascii is output as-is; other bytes are hex-encoded.
Here is the script, filtered by itself, so you can see what it does:
pyxxd.c
#include <stddef.h>
extern const char pyxxd[];
extern const size_t pyxxd_len;
const char pyxxd[] =
"#!/usr/bin/env python3\n"
"\n"
"import sys\n"
"import re\n"
"\n"
"def is_printable_ascii(byte):\n"
" return byte >= ord(' ') and byte <= ord('~')\n"
"\n"
"def needs_escaping(byte):\n"
" return byte == ord('\\\"') or byte == ord('\\\\')\n"
"\n"
"def stringify_nibble(nibble):\n"
" if nibble < 10:\n"
" return chr(nibble + ord('0'))\n"
" return chr(nibble - 10 + ord('a'))\n"
"\n"
"def write_byte(of, byte):\n"
" if is_printable_ascii(byte):\n"
" if needs_escaping(byte):\n"
" of.write('\\\\')\n"
" of.write(chr(byte))\n"
" elif byte == ord('\\n'):\n"
" of.write('\\\\n\"\\n\"')\n"
" else:\n"
" of.write('\\\\x')\n"
" of.write(stringify_nibble(byte >> 4))\n"
" of.write(stringify_nibble(byte & 0xf))\n"
"\n"
"def mk_valid_identifier(s):\n"
" s = re.sub('^[^_a-z]', '_', s)\n"
" s = re.sub('[^_a-z0-9]', '_', s)\n"
" return s\n"
"\n"
"def main():\n"
" # `xxd -i` compatibility\n"
" if len(sys.argv) != 4 or sys.argv[1] != \"-i\":\n"
" print(\"Usage: xxd -i infile outfile\")\n"
" exit(2)\n"
"\n"
" with open(sys.argv[2], \"rb\") as infile:\n"
" with open(sys.argv[3], \"w\") as outfile:\n"
"\n"
" identifier = mk_valid_identifier(sys.argv[2]);\n"
" outfile.write('#include <stddef.h>\\n\\n');\n"
" outfile.write('extern const char {}[];\\n'.format(identifier));\n"
" outfile.write('extern const size_t {}_len;\\n\\n'.format(identifier));\n"
" outfile.write('const char {}[] =\\n\"'.format(identifier));\n"
"\n"
" while True:\n"
" byte = infile.read(1)\n"
" if byte == b\"\":\n"
" break\n"
" write_byte(outfile, ord(byte))\n"
"\n"
" outfile.write('\";\\n\\n');\n"
" outfile.write('const size_t {}_len = sizeof({}) - 1;\\n'.format(identifier, identifier));\n"
"\n"
"if __name__ == '__main__':\n"
" main()\n"
"";
const size_t pyxxd_len = sizeof(pyxxd) - 1;
Usage (this extracts the script):
#include <stdio.h>
extern const char pyxxd[];
extern const size_t pyxxd_len;
int main()
{
fwrite(pyxxd, 1, pyxxd_len, stdout);
}
Here's a hack I use for Visual C++. I add the following Pre-Build Event (where file.txt is the input and file_txt.h is the output):
#(
echo const char text[] = R"***(
type file.txt
echo ^^^)***";
) > file_txt.h
I then include file_txt.h where I need it.
This isn't perfect, as it adds \n at the start and \n^ at the end, but that's not a problem to handle and I like the simplicity of this solution. If anyone can refine is to get rid of the extra chars, that would be nice.
You can use assembly for this:
asm("fileData: .incbin \"filename.ext\"");
asm("fileDataEnd: db 0x00");
extern char fileData[];
extern char fileDataEnd[];
const int fileDataSize = fileDataEnd - fileData + 1;
Even if it can be done at compile time (I don't think it can in general), the text would likely be the preprocessed header rather than the files contents verbatim. I expect you'll have to load the text from the file at runtime or do a nasty cut-n-paste job.
Hasturkun's answer using the xxd -i option is excellent. If you want to incorporate the conversion process (text -> hex include file) directly into your build the hexdump.c tool/library recently added a capability similar to xxd's -i option (it doesn't give you the full header - you need to provide the char array definition - but that has the advantage of letting you pick the name of the char array):
http://25thandclement.com/~william/projects/hexdump.c.html
It's license is a lot more "standard" than xxd and is very liberal - an example of using it to embed an init file in a program can be seen in the CMakeLists.txt and scheme.c files here:
https://github.com/starseeker/tinyscheme-cmake
There are pros and cons both to including generated files in source trees and bundling utilities - how to handle it will depend on the specific goals and needs of your project. hexdump.c opens up the bundling option for this application.
I think it is not possible with the compiler and preprocessor alone. gcc allows this:
#define _STRGF(x) # x
#define STRGF(x) _STRGF(x)
printk ( MODULE_NAME " built " __DATE__ " at " __TIME__ " on host "
STRGF(
# define hostname my_dear_hostname
hostname
)
"\n" );
But unfortunately not this:
#define _STRGF(x) # x
#define STRGF(x) _STRGF(x)
printk ( MODULE_NAME " built " __DATE__ " at " __TIME__ " on host "
STRGF(
# include "/etc/hostname"
)
"\n" );
The error is:
/etc/hostname: In function ‘init_module’:
/etc/hostname:1:0: error: unterminated argument list invoking macro "STRGF"
I had similar issues, and for small files the aforementioned solution of Johannes Schaub worked like a charm for me.
However, for files that are a bit larger, it ran into issues with the character array limit of the compiler. Therefore, I wrote a small encoder application that converts file content into a 2D character array of equally sized chunks (and possibly padding zeros). It produces output textfiles with 2D array data like this:
const char main_js_file_data[8][4]= {
{'\x69','\x73','\x20','\0'},
{'\x69','\x73','\x20','\0'},
{'\x61','\x20','\x74','\0'},
{'\x65','\x73','\x74','\0'},
{'\x20','\x66','\x6f','\0'},
{'\x72','\x20','\x79','\0'},
{'\x6f','\x75','\xd','\0'},
{'\xa','\0','\0','\0'}};
where 4 is actually a variable MAX_CHARS_PER_ARRAY in the encoder. The file with the resulting C code, called, for example "main_js_file_data.h" can then easily be inlined into the C++ application, for example like this:
#include "main_js_file_data.h"
Here is the source code of the encoder:
#include <fstream>
#include <iterator>
#include <vector>
#include <algorithm>
#define MAX_CHARS_PER_ARRAY 2048
int main(int argc, char * argv[])
{
// three parameters: input filename, output filename, variable name
if (argc < 4)
{
return 1;
}
// buffer data, packaged into chunks
std::vector<char> bufferedData;
// open input file, in binary mode
{
std::ifstream fStr(argv[1], std::ios::binary);
if (!fStr.is_open())
{
return 1;
}
bufferedData.assign(std::istreambuf_iterator<char>(fStr),
std::istreambuf_iterator<char>() );
}
// write output text file, containing a variable declaration,
// which will be a fixed-size two-dimensional plain array
{
std::ofstream fStr(argv[2]);
if (!fStr.is_open())
{
return 1;
}
const std::size_t numChunks = std::size_t(std::ceil(double(bufferedData.size()) / (MAX_CHARS_PER_ARRAY - 1)));
fStr << "const char " << argv[3] << "[" << numChunks << "]" <<
"[" << MAX_CHARS_PER_ARRAY << "]= {" << std::endl;
std::size_t count = 0;
fStr << std::hex;
while (count < bufferedData.size())
{
std::size_t n = 0;
fStr << "{";
for (; n < MAX_CHARS_PER_ARRAY - 1 && count < bufferedData.size(); ++n)
{
fStr << "'\\x" << int(unsigned char(bufferedData[count++])) << "',";
}
// fill missing part to reach fixed chunk size with zero entries
for (std::size_t j = 0; j < (MAX_CHARS_PER_ARRAY - 1) - n; ++j)
{
fStr << "'\\0',";
}
fStr << "'\\0'}";
if (count < bufferedData.size())
{
fStr << ",\n";
}
}
fStr << "};\n";
}
return 0;
}
This problem was irritating me and xxd doesn't work for my use case because it made the variable called something like __home_myname_build_prog_cmakelists_src_autogen when I tried to script it in, so I made a utility to solve this exact problem:
https://github.com/Exaeta/brcc
It generates a source and header file and allows you to explicitly set the name of each variable so then you can use them via std::begin(arrayname) and std::end(arrayname).
I incorporated it into my cmake project like so:
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/binary_resources.hpp ${CMAKE_CURRENT_BINARY_DIR}/binary_resources.cpp
COMMAND brcc ${CMAKE_CURRENT_BINARY_DIR}/binary_resources RGAME_BINARY_RESOURCES_HH txt_vertex_shader ${CMAKE_CURRENT_BINARY_DIR}/src/vertex_shader1.glsl
DEPENDS src/vertex_shader1.glsl)
With small tweaks I suppose it could be made to work for C as well.
If you are using CMake, you probably may be interested in writing CMake preprocessing script like the following:
cmake/ConvertLayout.cmake
function(convert_layout file include_dir)
get_filename_component(name ${file} NAME_WE)
get_filename_component(directory ${file} DIRECTORY)
get_filename_component(directory ${directory} NAME)
string(TOUPPER ${name} NAME)
string(TOUPPER ${directory} DIRECTORY)
set(new_file ${include_dir}/${directory}/${name}.h)
if (${file} IS_NEWER_THAN ${new_file})
file(READ ${file} content)
string(REGEX REPLACE "\"" "\\\\\"" content "${content}")
string(REGEX REPLACE "[\r\n]" "\\\\n\"\\\\\n\"" content "${content}")
set(content "\"${content}\"")
set(content "#ifndef ${DIRECTORY}_${NAME}\n#define ${DIRECTORY}_${NAME} ${content} \n#endif")
message(STATUS "${content}")
file(WRITE ${new_file} "${content}")
message(STATUS "Generated layout include file ${new_file} from ${file}")
endif()
endfunction()
function(convert_layout_directory layout_dir include_dir)
file(GLOB layouts ${layout_dir}/*)
foreach(layout ${layouts})
convert_layout(${layout} ${include_dir})
endforeach()
endfunction()
your CMakeLists.txt
include(cmake/ConvertLayout.cmake)
convert_layout_directory(layout ${CMAKE_BINARY_DIR}/include)
include_directories(${CMAKE_BINARY_DIR}/include)
somewhere in c++
#include "layout/menu.h"
Glib::ustring ui_info = LAYOUT_MENU;
I like #Martin R.'s answer because, as it says, it doesn't touch the input file and automates the process. To improve on this, I added the capability to automatically split up large files that exceed compiler limits. The output file is written as an array of smaller strings which can then be reassembled in code. The resulting script, based on #Martin R.'s version, and an example is included here:
https://github.com/skillcheck/cmaketools.git
The relevant CMake setup is:
make_includable( LargeFile.h
${CMAKE_CURRENT_BINARY_DIR}/generated/LargeFile.h
"c++-include" "L" LINE_COUNT FILE_SIZE
)
The source code is then:
static std::vector<std::wstring> const chunks = {
#include "generated/LargeFile.h"
};
std::string contents =
std::accumulate( chunks.begin(), chunks.end(), std::wstring() );
in x.h
"this is a "
"buncha text"
in main.c
#include <stdio.h>
int main(void)
{
char *textFileContents =
#include "x.h"
;
printf("%s\n", textFileContents);
return 0
}
ought to do the job.
What might work is if you do something like:
int main()
{
const char* text = "
#include "file.txt"
";
printf("%s", text);
return 0;
}
Of course you'll have to be careful with what is actually in the file, making sure there are no double quotes, that all appropriate characters are escaped, etc.
Therefore it might be easier if you just load the text from a file at runtime, or embed the text directly into the code.
If you still wanted the text in another file you could have it in there, but it would have to be represented there as a string. You would use the code as above but without the double quotes in it. For example:
file.txt
"Something evil\n"\
"this way comes!"
main.cpp
int main()
{
const char* text =
#include "file.txt"
;
printf("%s", text);
return 0;
}
So basically having a C or C++ style string in a text file that you include. It would make the code neater because there isn't this huge lot of text at the start of the file.

Looping with macros

I need to do a loop where I turn this simple example of reflection:
std::string mystring[3] = {{"mystring[0]"},{"mystring[1]"},{"mystring[2]"}};
into a more managable form for longer arrays. The solution sounds like I should either use macros with a loop, or recursion. However, macros don't support loops or recursion!
How do I create a macro to handle this for me arbitrarily?
#define NAME_OBJ(type, name, size)
Try using Boost. If it fails, try using more Boost.
#include <boost/preprocessor/repeat.hpp>
#include <boost/preprocessor/comma_if.hpp>
#include <boost/preprocessor/stringize.hpp>
#define DETAIL_NAME_OBJ_ELEM(z, n, name) \
BOOST_PP_COMMA_IF(n) { BOOST_PP_STRINGIZE(name) "[" BOOST_PP_STRINGIZE(n) "]" }
#define NAME_OBJ(type, name, size) \
type name[size] = { BOOST_PP_REPEAT(size, DETAIL_NAME_OBJ_ELEM, name) }
Then this:
NAME_OBJ(std::string, mystring, 3);
... expands to this:
std::string mystring[3] = {
{ "mystring" "[" "0" "]" },
{ "mystring" "[" "1" "]" },
{ "mystring" "[" "2" "]" }
};
... in which the adjacent string literals are then automatically merged before compilation.
See it live on Coliru
As you stated, macros in C++ do not support loops or recursion, such that you would have to duplicate lines of code.
A common way of solving such topics is to write a program - let's say myGenerator, which contains a "normal" C++-loop and which's output is a C++ source file (.cpp or .h). Integrate then a call to myGenerartor in a build step before building the rest of your program.
Based on a great answer to handling macros here
https://stackoverflow.com/a/12540675/1723954
I modified/simplified the solution for this specific case:
#define NAME_OBJ(type, name, size) \
type name[size] = { INIT_ELEMENT_ ## size(name) }
#define INIT_ELEMENT_1(name) { #name "[0]" }
#define INIT_ELEMENT_2(name) INIT_ELEMENT_1(name), { #name "[1]" }
#define INIT_ELEMENT_3(name) INIT_ELEMENT_2(name), { #name "[2]" }
...
The solution does not allow for very-very-very large arrays, only as large as you are willing to code. I did 128 and that's fine for all of the cases in my project.