简体   繁体   English

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

[英]Get all calls to specific function in source file and generate other files (using C, C++ preprocessor or scripts)

I have a program like below: 我有一个程序如下:

// test.c
#include <stdio.h>

#define LOG     printf
int main(int argc, char *argv[]) 
{
    LOG("Hello, my name %s, my age %d\n", "John", 30);
    LOG("I have wife and %d kids\n", 2);
    return 0;
}

I want to create a log file which contains all texts like: 我想创建一个包含所有文本的日志文件,例如:

// message.txt
LINE: "Hello, my name %s, my age %d\n"
LINE: "I have wife and %d kids\n"

Is it possible to do it using C's preprocessor , make , or even a script ? 是否可以使用C的预处理器make甚至脚本来完成


Edited: 编辑:

Let's say I have a program that prints those messages in English already, I have source code for sure, now I want to support French then: 假设我有一个程序已经可以用英语打印这些消息了,我肯定有源代码,现在我要支持法语:
I need to get all messages that developers put into their program and create a message.txt which contains all texts, replace each message in original program with an identify number which maps each message in message.txt . 我需要获取开发人员放入其程序中的所有消息,并创建一个包含所有文本的message.txt ,将原始程序中的每条消息替换为一个标识号,该标识号将message.txt每条消息映射。 I want to do it programmatically not manually. 我想以编程方式而不是手动进行。

What you are looking for is localization, read something about it here . 您正在寻找的是本地化,请在此处阅读有关它的内容。 If you're on a posix system you can use gettext() for that, see manpage . 如果您使用的是posix系统,则可以为此使用gettext() ,请参阅manpage If you're using Windows you can take a look at GetText for Windows . 如果您使用的是Windows,则可以查看Windows的GetText


Nevertheless I wrote a little C++ program that generate the files you want, see code below. 尽管如此,我还是写了一个小的C ++程序来生成所需的文件,请参见下面的代码。 You call it via myProg filename logFunction where filename is the source file you want to input and logFunction is for example LOG . 您可以通过myProg filename logFunction调用它,其中filename是要输入的源文件,而logFunction例如是LOG

You will get a map file called filename_map and a new source file filename_new . 您将获得一个名为filename_map的映射文件和一个新的源文件filename_new The new source file will contain a new macro LOG and a function readLocaleStrings() which will read all the strings at program start from the filename_map file. 新的源文件将包含一个新的宏LOG和一个函数readLocaleStrings() ,该函数将在程序开始时从filename_map文件读取所有字符串。 The new macro LOG will use the right strings automatically then. 然后,新的宏LOG将自动使用正确的字符串。


In your example you would call it by myProg test.c LOG and would get: 在您的示例中,将通过myProg test.c LOG对其进行调用,并将获得:

test_map.txt : test_map.txt

7: "Hello, my name %s, my age %d\n"
8: "I have wife and %d kids\n"

and a test_new.c : 和一个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++ program: C ++程序:

The C++ program has limitation, it will just find LOG(" if you want also to find LOG with spaces anywhere like: LOG (" you have to change that code. Moreover there are cases such as multiple lines messages, messages that had been commented out etc. You have to extend the code for your requirements then. Also there is no great argument parse handling or error checking. Further for the writing of the helper code it is needed to find the main function. But for your given input file it works perfectly and should just point you in the right direction. To extend it more easy and make it more flexible using a regex library would be wise. 在C ++程序有局限性,它只会找到LOG("如果你想也找到LOG与空间的任何地方,如: LOG ("你必须更改代码而且有这样的情况,例如多行的消息,已被评论的邮件然后必须根据需要扩展代码,也没有很好的参数解析处理或错误检查方法,此外,编写辅助代码时需要找到主函数,但对于给定的输入文件,可以完美地工作,并且应该为您指明正确的方向。使用正则表达式库使其更容易扩展并使其更灵活将是明智的。

Code: 码:

#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 */
   }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何为其他目录中的所有C ++文件生成标记文件? - How to generate a tags file for all C++ files in the other directory? 如何使用 libclang 从 C++ 源文件中检索所有函数调用? - How do I retrieve all function calls from C++ source files with libclang? 使用没有标准库的预处理器连接 C++ 源文件包括 - Concatenating C++ source files using the preprocessor without standard library includes 为特定目录中的所有C ++文件生成一个标记文件(子目录除外) - Generate a tags file for all C++ files in specific directory except on its subdirectories 我可以使用C ++模板生成函数的Unicode / ANSI变体,而不使用预处理器吗? - Can I use C++ templates to generate Unicode/ANSI variants of a function, rather than using the preprocessor? 如何在其他源文件中定义函数:C ++ CodeBlocks - How to define function in other source file:C++ CodeBlocks 多个文件函数调用C ++ - Multiple files function calls C++ C++,是否有可能/您将如何定义在.h &amp;.cpp 源文件中调用 function 的 class 构造函数 - C++, Is it possible / how would you define a class constructor that calls a function in the .h & .cpp source files 使用c-preprocessor自动生成函数转发器 - Auto generate function forwarders with c-preprocessor 使用纯c ++(跨平台)获取特定路径中的所有目录/文件和子目录 - Get all directories/files and sub-directories in a specific path using pure c++ (cross-platform)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM