获取对源文件中特定函数的所有调用并生成其他文件(使用 C、C++预处理器或脚本)



我有一个如下程序:

// test.c
#include <stdio.h>
#define LOG     printf
int main(int argc, char *argv[]) 
{
LOG("Hello, my name %s, my age %dn", "John", 30);
LOG("I have wife and %d kidsn", 2);
return 0;
}

我想创建一个包含所有文本的日志文件,例如:

// message.txt
LINE: "Hello, my name %s, my age %dn"
LINE: "I have wife and %d kidsn"

是否可以使用 C 的预处理器make甚至脚本来做到这一点?


编辑:

假设我有一个程序已经用英语打印这些消息,我肯定有源代码,现在我想支持法语然后:
我需要获取开发人员放入其程序中的所有消息并创建一个包含所有文本的message.txt,将原始程序中的每个消息替换为一个标识号,该标识号将每条消息映射到message.txt。我想以编程方式而不是手动完成。

您正在寻找的是本地化,请在此处阅读有关它的内容。如果您使用的是 posix 系统,则可以使用gettext(),请参阅手册页。如果您使用的是Windows,则可以查看GetText for Windows。


尽管如此,我还是编写了一个C++程序来生成您想要的文件,请参见下面的代码。 您可以通过myProg filename logFunction调用它,其中filename是您要输入的源文件,logFunction是例如LOG

您将获得一个名为filename_map的映射文件和一个新的源文件filename_new。新的源文件将包含一个新的宏LOG和一个函数readLocaleStrings(),它将在程序开始时从filename_map文件读取所有字符串。然后,新的宏LOG将自动使用正确的字符串。


在您的示例中,您将按myProg test.c LOG调用它,并将得到:

test_map.txt

7: "Hello, my name %s, my age %dn"
8: "I have wife and %d kidsn"

test_new.c

// test.c
#include <stdio.h>
#define LOG(filename,line,...)   printf(localeStrings.strings[localeStrings.lastIdx++], __VA_ARGS__)
/* Beginning: Generated code for localization */
#include <stdlib.h>
#include <string.h>
typedef struct {
size_t  count;
size_t  lastIdx;
char ** strings;
} stringArray_t;
stringArray_t localeStrings = { 0, 0, NULL };
int readLocaleStrings (const char * const filename)
{
FILE * file = NULL;
char * line = NULL;
char * str = NULL;
size_t len = 0;
ssize_t read;
file = fopen(filename, "r");
if (file == NULL)
{
return -1;
}
localeStrings.strings = malloc (sizeof (char *));
localeStrings.count = 0;
while (-1 != (read = getline(&line, &len, file)))
{
size_t curIdx = localeStrings.count++;
localeStrings.strings = realloc(localeStrings.strings, localeStrings.count * sizeof (char *));
str = strstr(line, """);
localeStrings.strings[curIdx] = malloc(sizeof (char) * (size_t)(1 + read));
strcpy (localeStrings.strings[curIdx], str);
}
fclose(file);
if (line)
{
free(line);
}
return 0;
}
void freeLocaleStrings()
{
size_t idx;
for (idx = 0; idx < localeStrings.count; ++idx)
{
free(localeStrings.strings[idx]);
}
free(localeStrings.strings);
}
/* End: Generated code for localization */
int main(int argc, char *argv[]) 
{
readLocaleStrings("test_map.txt");
LOG("test_map.txt", "7", "John", 30);
LOG("test_map.txt", "8", 2);
freeLocaleStrings();
return 0;
}

C++程序:

C++程序有限制,如果您还想在任何地方找到带有空格LOG,它只会找到LOG("LOG ("您必须更改该代码。此外,还有多行消息、已注释掉的消息等情况。然后,您必须根据您的要求扩展代码。也没有很好的参数解析处理或错误检查。此外,为了编写辅助代码,需要找到 main 函数。但是对于您给定的输入文件,它可以完美运行,并且应该为您指明正确的方向。使用正则表达式库更轻松地扩展它并使其更灵活将是明智的。

法典:

#include <iostream>
#include <fstream>
/* Function definition is under main function */
const char * getNextHelperFunctionLine();
std::string getExtension (const std::string filename)
{
/* get dot of e.g. foo.c */
size_t posDot = filename.rfind('.');
/* extract extension */
std::string extension;
if (std::string::npos != posDot)
{
/* extension found */
extension = filename.substr(posDot);
}
return extension;
}
std::string getFilename (const std::string filename)
{
/* get dot of e.g. foo.c */
size_t posDot = filename.rfind('.');
/* extract filename */
std::string name = filename;
if (std::string::npos != posDot)
{
name  = name.substr(0, posDot);
}
return name;
}
int main (int argc, char* argv[])
{
if (argc < 3)
{
std::cerr << "Usage: "
<< "   " << argv[0] << " filename logFunction"
<< std::endl;
return 0;
}
std::string infileName (argv[1]);
/* extract filename and extension */
std::string filename  = getFilename(infileName);
std::string extension = getExtension(infileName);;
/* names for generated files */
std::string mapfileName = filename + "_map.txt";
std::string mappedfileName = filename + "_new" + extension;
/* open streams for input and output */
std::ifstream infile(infileName.c_str());
std::ofstream fileMap(mapfileName.c_str());
std::ofstream fileMapped(mappedfileName.c_str());
/* string for log function e.g. "LOG(" */
std::string logFun = std::string(argv[2]);
std::string logFunOpen = logFun + "("";
std::string lineRead;
size_t lineNr = 1;
size_t mainParanthesis = 0;
bool   mainReturnFound = false;
/* Loop through whole input file */
while (std::getline(infile, lineRead))
{
/* position of log function opening e.g. "LOG(" */
size_t posLogOpen = lineRead.find(logFunOpen);
/* opening found? */
bool foundOpen  = std::string::npos != posLogOpen;
if (foundOpen)
{
bool foundClose = false;
/* position of the string beginning */
size_t posLogStringBeg = posLogOpen + logFunOpen.length();
size_t posLogClose = posLogStringBeg;
/* find closing of the log function e.g. "LOG(...)" */
while (!foundClose)
{
/* search for '"' and skip these if they are in the string */
posLogClose = lineRead.find(""", posLogClose + 1);
if (std::string::npos != posLogClose)
{
foundClose = (0 != lineRead.compare(posLogClose - 1, 1, "\"));
}
}
/* closing found write map file and new source file */
if (foundClose)
{
size_t len = posLogClose - posLogStringBeg;
fileMap << lineNr << ": ""
<< lineRead.substr(posLogStringBeg, len) << """
<< std::endl;
fileMapped << lineRead.substr(0, posLogStringBeg - 1)
<< '"' << mapfileName << "", "
<< '"' << lineNr
<< lineRead.substr(posLogClose)
<< std::endl;
}
}
/* not a log function write normal code */
else
{
if (   std::string::npos != lineRead.find("#define")
&& std::string::npos != lineRead.find(logFun))
{
/* log functions needs to be changed */
fileMapped << "#define "
<< logFun << "(filename,line,...)   "
<< "printf(localeStrings.strings[localeStrings.lastIdx++], __VA_ARGS__)" << std::endl;
}
else if (   0 == mainParanthesis
&& std::string::npos != lineRead.find(" main")
&& std::string::npos != lineRead.find("(")
&& std::string::npos != lineRead.find(")"))
{
/* found main function write all helper functions in front of it */
const char * helperLine;
while ((helperLine = getNextHelperFunctionLine()))
{
fileMapped << helperLine << std::endl;
}
/* write main function part */
fileMapped << lineRead << std::endl;
/* is there an opening parenthesis? */
if (std::string::npos != lineRead.find("{"))
{
++mainParanthesis;
fileMapped << "   readLocaleStrings("" << mapfileName << "");" << std::endl;
}
}
else
{
/* in main function write first part */
if (std::string::npos != lineRead.find("{"))
{
/* write opening */
fileMapped << lineRead << std::endl;
if (0 == mainParanthesis)
{
fileMapped << "   readLocaleStrings("" << mapfileName << "");" << std::endl;
}
++mainParanthesis;
}
/* return statement? */
else if (   1 == mainParanthesis
&& std::string::npos != lineRead.find("return"))
{
mainReturnFound = true;
fileMapped << "   freeLocaleStrings();" << std::endl;
/* write return */
fileMapped << lineRead << std::endl;
}
else if (   1 == mainParanthesis
&& std::string::npos != lineRead.find("}"))
{
--mainParanthesis;
if (!mainReturnFound)
{
fileMapped << "   freeLocaleStrings();" << std::endl;
}
/* write closing */
fileMapped << lineRead << std::endl;
}
else
{
/* write other code */
fileMapped << lineRead << std::endl;
}
}
}
++lineNr;
}
return 0;
}
const char * getNextHelperFunctionLine()
{
static size_t idx = 0;
static const char * helperFunLines[] =
{
"",
"/* Beginning: Generated code for localization */",
"#include <stdlib.h>",
"#include <string.h>",
"",
"typedef struct {",
"   size_t  count;",
"   size_t  lastIdx;",
"   char ** strings;",
"} stringArray_t;",
"",
"stringArray_t localeStrings = { 0, 0, NULL };",
"",
"int readLocaleStrings (const char * const filename)",
"{",
"   FILE * file = NULL;",
"   char * line = NULL;",
"   char * str = NULL;",
"   size_t len = 0;",
"   ssize_t read;",
"",
"   file = fopen(filename, "r");",
"   if (file == NULL)",
"   {",
"      return -1;",
"   }",
"",
"   localeStrings.strings = malloc (sizeof (char *));",
"   localeStrings.count = 0;",
"",
"   while (-1 != (read = getline(&line, &len, file)))",
"   {",
"      size_t curIdx = localeStrings.count++;",
"      localeStrings.strings = realloc(localeStrings.strings, localeStrings.count * sizeof (char *));",
"",
"      str = strstr(line, "\"");",
"      localeStrings.strings[curIdx] = malloc(sizeof (char) * (size_t)(1 + read));",
"      strcpy (localeStrings.strings[curIdx], str);",
"   }",
"",
"   fclose(file);",
"   if (line)",
"   {",
"      free(line);",
"   }",
"",
"   return 0;",
"}",
"",
"void freeLocaleStrings()",
"{",
"   size_t idx;",
"   for (idx = 0; idx < localeStrings.count; ++idx)",
"   {",
"      free(localeStrings.strings[idx]);",
"   }",
"   free(localeStrings.strings);",
"}",
"/* End: Generated code for localization */",
""
};
if (idx < (sizeof (helperFunLines) / sizeof (helperFunLines[0])))
{
return helperFunLines[idx++];
}
else
{
return nullptr; /* use NULL if compiler doesn't support nullptr */
}
}

最新更新