2017-06-16 24 views
1

我有一個像下面的程序:獲取源文件中的特定函數的所有調用,並生成其他文件(用C,C++預處理程序或腳本)

// 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; 
} 

我想創建一個包含所有文本日誌文件像:

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

是否有可能用C的預處理使,甚至腳本辦呢?


編輯:

比方說,我有一個在英語打印這些消息已經是一個程序,我可以肯定的源代碼,現在我要支持法國則:
我需要得到的所有消息開發人員投入他們的程序並創建一個包含所有文本的message.txt,用原始程序中的每個消息替換爲標識號,該標識號映射message.txt中的每個消息。我想以編程方式而不是手動執行。

+1

我有點不確定你實際上問...你只是想搜索的地方LOG'使用'所有源文件?或者你是否真的想要實現一個日誌系統? –

+0

所以你說你想記錄原始格式字符串?爲什麼? – dbush

+0

不知道預處理器和Make,但肯定可以用腳本來完成。或者你可以寫一個'c'程序:-) – 4386427

回答

2

你在找什麼是本地化,讀些關於它的東西here。如果您使用的是posix系統,那麼可以使用gettext(),請參閱manpage。如果你使用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 %d\n" 
8: "I have wife and %d kids\n" 

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 (",你必須改變這種代碼。此外,還有一些情況,比如多行消息,已被註釋掉的消息等。然後,您必須爲您的需求擴展代碼。也沒有很好的參數解析處理或錯誤檢查。此外,爲了編寫幫助代碼,需要找到主要功能。但是對於你給定的輸入文件,它可以很好地工作,並且應該指向正確的方向。使用正則表達式庫來擴展它更加簡單並且使其更加靈活將是明智的。

代碼:

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

多語句宏體實際上是我推薦的東西。最後一個與'do ... while(0)'在一起更好。還有其他解決方案,包括使用宏將參數傳遞給執行日誌記錄的單個函數(我寧願推薦)。但目前還不清楚這是否是OP真正要問的問題。 –

+0

@Someprogrammerdude:是的你說得對,我也改變了其他人。 –

+0

你好@AndreKampling,謝謝,我會檢查。重要的是如何處理錯誤情況,如多行消息,消息已被註釋掉,消息有特殊的轉義字符(例如:\「)等等。 – sdao

相關問題