- #include <cstdio>
- #include <cctype>
- #include <cstring>
- #include <fstream>
- #include <map>
- #include <string>
- #include <iostream>
- using namespace std;
- struct SLangInfo
- {
- const char *pszPo;
- const char *pszLang;
- const char *pszOutput;
- } g_Languages[] = {
- {"pl", "LANG_POLISH", "pl-PL"},
- {"en", "LANG_ENGLISH", "en-US"},
- };
- class CPoParser
- {
- public:
- CPoParser(ifstream &Stream)
- {
- Load(Stream);
- }
- void Load(ifstream &Stream)
- {
- m_Line = 0;
- m_szBuf[0] = 0;
- m_Ptr = m_szBuf;
- while(Stream.good())
- {
- string strName, strMsgId, strCtxt, strMsg;
- if(!GetEntry(Stream, strName, strMsgId))
- break;
- if(strName == "msgctxt")
- {
- strCtxt = strMsgId;
- if(!GetEntry(Stream, strName, strMsgId))
- break;
- }
- if(strName != "msgid")
- {
- cerr << "Expected msgid at line " << m_Line << ", got " << strName << "\n";
- continue;
- }
- if(!GetEntry(Stream, strName, strMsg) || strName != "msgstr")
- {
- cerr << "Expected msgstr at line " << m_Line << ", got " << strName << "\n";
- continue;
- }
- if(!strCtxt.empty())
- strMsgId = string("#msgctxt#") + strCtxt + "#" + strMsgId;
- m_Messages[strMsgId] = strMsg;
- }
- }
- const char *GetMsg(const char *pszMsgId)
- {
- map<string, string>::iterator it = m_Messages.find(pszMsgId);
- if(it == m_Messages.end())
- return NULL;
- return it->second.c_str();
- }
- private:
- map<string, string> m_Messages;
- unsigned m_Line;
- char m_szBuf[256];
- const char *m_Ptr;
- bool GetEntry(ifstream &Stream, string &strName, string &strValue)
- {
- if(!GetToken(Stream, strName, false))
- return false;
- if(!GetToken(Stream, strValue, true))
- {
- cerr << "Expected string at line " << m_Line << ", got " << m_Ptr << "\n";
- return false;
- }
- string strTemp;
- while(GetToken(Stream, strTemp, true))
- strValue += strTemp;
- return true;
- }
- bool LoadNextLine(ifstream &Stream)
- {
- while(Stream.good())
- {
- Stream.getline(m_szBuf, sizeof(m_szBuf));
- ++m_Line;
- m_Ptr = m_szBuf;
- IgnoreWhiteChars();
- if(m_Ptr[0] != '#')
- return true;
- }
- return false;
- }
- void IgnoreWhiteChars()
- {
- while(isspace(*m_Ptr))
- ++m_Ptr;
- }
- bool GetToken(ifstream &Stream, string &strResult, bool bStr)
- {
- IgnoreWhiteChars();
- if(!m_Ptr[0] && !LoadNextLine(Stream))
- return false;
- bool bIsStr = (*m_Ptr == '"');
- if(bStr != bIsStr)
- return false;
- strResult = "";
- if(bIsStr)
- {
- ++m_Ptr;
- while(*m_Ptr)
- {
- if(*m_Ptr == '"')
- {
- ++m_Ptr;
- break;
- }
- if(m_Ptr[0] == '\\' && m_Ptr[1] == '"')
- {
- strResult += '"';
- m_Ptr += 2;
- } else
- strResult += *(m_Ptr++);
- }
- }
- else
- {
- while(*m_Ptr && !isspace(*m_Ptr))
- strResult += *(m_Ptr++);
- }
- return true;
- }
- };
- class CRcTranslator
- {
- public:
- void Define(const char *pszName, const char *pszValue)
- {
- m_Defines[pszName] = pszValue;
- }
- void Process(istream &Input, ostream &Output, CPoParser &PoParser)
- {
- LoadNextLine(Input);
- string strTemp;
- while(Input.good())
- {
- if(!m_Ptr[0])
- {
- Output << "\n";
- if(!LoadNextLine(Input))
- break;
- continue;
- }
- if(IgnoreShortComment(Input, Output))
- continue;
- if(IgnoreLongComment(Input, Output))
- continue;
- if(GetString(Input, strTemp))
- {
- OutputTranslatedString(Output, PoParser, strTemp.c_str());
- continue;
- }
- if(GetIdentifier(Input, strTemp))
- {
- map<string, string>::iterator it = m_Defines.find(strTemp);
- if(it == m_Defines.end())
- Output << strTemp;
- else
- Output << it->second;
- continue;
- }
- Output << *(m_Ptr++);
- }
- }
- private:
- char m_szBuf[256], *m_Ptr;
- map<string, string> m_Defines;
- bool IgnoreShortComment(istream &Input, ostream &Output)
- {
- if(m_Ptr[0] != '/' || m_Ptr[1] != '/')
- return false;
- Output << m_Ptr << "\n";
- LoadNextLine(Input);
- return true;
- }
- bool IgnoreLongComment(istream &Input, ostream &Output)
- {
- if(m_Ptr[0] != '/' || m_Ptr[1] != '*')
- return false;
- m_Ptr += 2;
- Output << "/*";
- while(true)
- {
- if(!m_Ptr[0])
- {
- Output << "\n";
- if(!LoadNextLine(Input))
- break;
- }
- else if(m_Ptr[0] == '*' && m_Ptr[1] == '/')
- {
- m_Ptr += 2;
- break;
- } else
- Output << *(m_Ptr++);
- }
- Output << "*/";
- return true;
- }
- bool GetString(istream &Input, string &strResult)
- {
- if(m_Ptr[0] != '"')
- return false;
- ++m_Ptr;
- strResult = "";
- while(true)
- {
- if(m_Ptr[0] == '\\' && !m_Ptr[1])
- {
- if(!LoadNextLine(Input))
- break;
- }
- else if(!m_Ptr[0])
- return false;
- else if(m_Ptr[0] == '"')
- {
- m_Ptr++;
- break;
- } else
- strResult += *(m_Ptr++);
- }
- return true;
- }
- bool GetIdentifier(istream &Input, string &strResult)
- {
- strResult = "";
- while(isalnum(*m_Ptr) || *m_Ptr == '_')
- strResult += *(m_Ptr++);
- return !strResult.empty();
- }
- bool LoadNextLine(istream &Stream)
- {
- if(!Stream.good())
- return false;
- Stream.getline(m_szBuf, sizeof(m_szBuf));
- m_Ptr = m_szBuf;
- return true;
- }
- void OutputTranslatedString(ostream &Output, CPoParser &PoParser, const char *pszStr)
- {
- const char *pszMsg = pszStr[0] ? PoParser.GetMsg(pszStr) : NULL;
- if(!pszMsg)
- pszMsg = pszStr;
- static char szSpecialCtxt[] = "#msgctxt#do not translate#";
- if(strncmp(pszMsg, szSpecialCtxt, sizeof(szSpecialCtxt) - 1) == 0)
- pszMsg += sizeof(szSpecialCtxt) - 1;
- Output << '"';
- while(*pszMsg)
- {
- if(pszMsg[0] == '\\' && pszMsg[1] == 'n')
- {
- Output << "\\n\\\n";
- pszMsg += 2;
- } else
- Output << *(pszMsg++);
- }
- Output << '"';
- }
- };
- int main(int argc, const char *argv[])
- {
- const char *pszPoPath = NULL, *pszRcPath = NULL, *pszOutputPath = "output.rc";
- bool bUsage = false;
- CRcTranslator Translator;
- for(int i = 1; i < argc; ++i)
- {
- const char *pszArg = argv[i];
- if(pszArg[0] == '/' || pszArg[0] == '-')
- ++pszArg;
- char chOpt = tolower(pszArg[0]);
- if(chOpt && pszArg[1])
- chOpt = 0;
- if(chOpt == 'p' && i + 1 < argc)
- pszPoPath = argv[++i];
- else if(chOpt == 'r' && i + 1 < argc)
- pszRcPath = argv[++i];
- else if(chOpt == 'o' && i + 1 < argc)
- pszOutputPath = argv[++i];
- else if(chOpt == 'h')
- bUsage = true;
- else if(tolower(pszArg[0]) == 'd')
- {
- const char *pszDef = pszArg + 1;
- if(!pszDef[0] && i + 1 < argc)
- pszDef = argv[++i];
- const char *pszVal = strchr(pszDef, '=');
- string strName;
- if(pszVal)
- {
- string strName(pszDef, pszVal - pszDef);
- Translator.Define(strName.c_str(), pszVal + 1);
- }
- else
- Translator.Define(pszDef, "1");
- } else
- cerr << "Warning! Unknown option: " << argv[i] << ".\n";
- }
- if(!pszPoPath || !pszRcPath || !pszOutputPath || bUsage)
- {
- cout << "Usage:\n";
- cout << argv[0] << " -r rc_path -p po_path [-o output_path] [-Dname=value]\n";
- cout << "\t-r rc_path\tSets path of rc file to process\n";
- cout << "\t-p po_path\tSets path to a po file for translation\n";
- cout << "\t-o output_path\tSets path to output rc file\n";
- cout << "\t-d name=value\tReplaces specified identifier in rc file\n";
- return 0;
- }
- ifstream RcFile(pszRcPath);
- if(!RcFile.good())
- {
- cerr << "Error! Cannot open " << pszRcPath << ".\n";
- return -1;
- }
- ifstream PoFile(pszPoPath);
- if(!PoFile.good())
- {
- cerr << "Error! Cannot open " << pszPoPath << ".\n";
- return -1;
- }
- ofstream OutputFile(pszOutputPath);
- if(!RcFile.good())
- {
- cerr << "Error! Cannot open " << pszOutputPath << ".\n";
- return -1;
- }
- CPoParser PoParser(PoFile);
- Translator.Process(RcFile, OutputFile, PoParser);
- cout << "Done!\n";
- return 0;
- }