dvander@276: #include dvander@300: #include dvander@276: #include "CTranslator.h" dvander@276: #include "CLogger.h" dvander@276: #include "CTextParsers.h" dvander@276: #include "LibrarySys.h" dvander@276: #include "sm_stringutil.h" dvander@300: #include "sourcemod.h" dvander@276: dvander@276: CTranslator g_Translator; dvander@276: dvander@276: struct trans_t dvander@276: { dvander@276: int stridx; dvander@276: int fmt_order; dvander@276: }; dvander@276: dvander@276: struct phrase_t dvander@276: { dvander@276: int fmt_list; dvander@276: unsigned int fmt_count; dvander@276: unsigned int fmt_bytes; dvander@276: int trans_tbl; dvander@276: unsigned int translations; dvander@276: }; dvander@276: dvander@276: CPhraseFile::CPhraseFile(CTranslator *pTranslator, const char *file) dvander@276: { dvander@276: m_pStringTab = pTranslator->GetStringTable(); dvander@276: m_pMemory = m_pStringTab->GetMemTable(); dvander@276: m_LangCount = pTranslator->GetLanguageCount(); dvander@276: m_File.assign(file); dvander@276: m_pTranslator = pTranslator; dvander@276: m_pPhraseLookup = NULL; dvander@276: } dvander@276: dvander@276: CPhraseFile::~CPhraseFile() dvander@276: { dvander@276: if (m_pPhraseLookup) dvander@276: { dvander@276: sm_trie_destroy(m_pPhraseLookup); dvander@276: } dvander@276: } dvander@276: dvander@276: void CPhraseFile::ParseError(const char *message, ...) dvander@276: { dvander@276: char buffer[1024]; dvander@276: va_list ap; dvander@276: va_start(ap, message); dvander@276: vsnprintf(buffer, sizeof(buffer), message, ap); dvander@276: va_end(ap); dvander@276: dvander@276: m_ParseError.assign(buffer); dvander@276: } dvander@276: dvander@276: void CPhraseFile::ParseWarning(const char *message, ...) dvander@276: { dvander@276: char buffer[1024]; dvander@276: va_list ap; dvander@276: va_start(ap, message); dvander@276: vsnprintf(buffer, sizeof(buffer), message, ap); dvander@276: va_end(ap); dvander@276: dvander@276: if (!m_FileLogged) dvander@276: { dvander@306: g_Logger.LogError("[SM] Warning(s) encountered in translation file \"%s\"", m_File.c_str()); faluco@334: m_FileLogged = true; dvander@276: } dvander@276: dvander@306: g_Logger.LogError("[SM] %s", message); dvander@276: } dvander@276: dvander@276: void CPhraseFile::ReparseFile() dvander@276: { dvander@276: if (m_pPhraseLookup) dvander@276: { dvander@276: sm_trie_destroy(m_pPhraseLookup); dvander@276: } dvander@276: m_pPhraseLookup = sm_trie_create(); dvander@276: dvander@276: m_LangCount = m_pTranslator->GetLanguageCount(); dvander@276: dvander@276: if (!m_LangCount) dvander@276: { dvander@276: return; dvander@276: } dvander@276: dvander@276: SMCParseError err; dvander@276: char path[PLATFORM_MAX_PATH+1]; dvander@317: g_SourceMod.BuildPath(Path_SM, path, PLATFORM_MAX_PATH, "translations/%s", m_File.c_str()); dvander@276: unsigned int line=0, col=0; dvander@276: dvander@276: if ((err=g_TextParser.ParseFile_SMC(path, this, &line, &col)) != SMCParse_Okay) dvander@276: { dvander@276: const char *msg = g_TextParser.GetSMCErrorString(err); dvander@276: if (!msg) dvander@276: { dvander@276: msg = m_ParseError.c_str(); dvander@276: } dvander@276: dvander@306: g_Logger.LogError("[SM] Fatal error encountered parsing translation file \"%s\"", m_File.c_str()); dvander@306: g_Logger.LogError("[SM] Error (line %d, column %d): %s", line, col, msg); dvander@276: } dvander@276: } dvander@276: dvander@276: void CPhraseFile::ReadSMC_ParseStart() dvander@276: { dvander@276: m_CurPhrase = -1; dvander@276: m_ParseState = PPS_None; dvander@276: m_CurLine = 0; dvander@276: m_FileLogged = false; dvander@276: m_LastPhraseString.clear(); dvander@276: } dvander@276: dvander@276: SMCParseResult CPhraseFile::ReadSMC_RawLine(const char *line, unsigned int curline) dvander@276: { dvander@276: m_CurLine = curline; dvander@276: dvander@276: return SMCParse_Continue; dvander@276: } dvander@276: dvander@276: SMCParseResult CPhraseFile::ReadSMC_NewSection(const char *name, bool opt_quotes) dvander@276: { dvander@276: bool recognized = false; dvander@276: if (m_ParseState == PPS_None) dvander@276: { dvander@276: if (strcmp(name, "Phrases") == 0) dvander@276: { dvander@276: m_ParseState = PPS_Phrases; dvander@276: recognized = true; dvander@276: } dvander@276: } else if (m_ParseState == PPS_Phrases) { dvander@276: m_ParseState = PPS_InPhrase; dvander@276: recognized = true; dvander@276: dvander@276: phrase_t *pPhrase; dvander@276: m_CurPhrase = m_pMemory->CreateMem(sizeof(phrase_t), (void **)&pPhrase); dvander@276: dvander@276: /* Create the reverse lookup */ dvander@276: if (!sm_trie_insert(m_pPhraseLookup, name, reinterpret_cast(m_CurPhrase))) dvander@276: { dvander@276: ParseWarning("Skipping duplicate phrase \"%s\" on line %d.", name, m_CurLine); dvander@276: /* :IDEA: prevent memory waste by seeking backwards in memtable? */ dvander@276: m_CurPhrase = -1; dvander@276: } else { dvander@276: /* Initialize new phrase */ dvander@276: trans_t *pTrans; dvander@276: dvander@276: pPhrase->fmt_count = 0; dvander@276: pPhrase->fmt_list = -1; dvander@276: pPhrase->trans_tbl = m_pMemory->CreateMem(sizeof(trans_t) * m_LangCount, (void **)&pTrans); dvander@276: pPhrase->translations = 0; dvander@276: pPhrase->fmt_bytes = 0; dvander@276: dvander@276: for (unsigned int i=0; iGetAddress(m_CurPhrase); dvander@276: dvander@276: if (key[0] == '#' && strcmp(key, "#format") == 0) dvander@276: { dvander@276: if (pPhrase->fmt_list != -1) dvander@276: { dvander@276: ParseWarning("Ignoring duplicated #format property on line %d", m_CurLine); dvander@276: return SMCParse_Continue; dvander@276: } dvander@276: dvander@276: if (pPhrase->translations > 0) dvander@276: { dvander@276: ParseWarning("#format property should come before translations on line %d, ignoring", m_CurLine); dvander@276: return SMCParse_Continue; dvander@276: } dvander@276: dvander@276: /* Do an initial browsing for error checking and what not */ dvander@276: enum ParseStates dvander@276: { dvander@276: Parse_None, dvander@276: Parse_Index, dvander@276: Parse_Format, dvander@276: }; dvander@276: dvander@276: ParseStates state = Parse_None; dvander@276: dvander@276: const char *old_value = value; dvander@276: while (*value != '\0') dvander@276: { dvander@276: if (state == Parse_None) dvander@276: { dvander@276: if (*value == '{') dvander@276: { dvander@276: pPhrase->fmt_count++; dvander@276: state = Parse_Index; dvander@276: } else if (*value == ',') { dvander@276: /* Do nothing */ dvander@276: } else { dvander@276: unsigned int bytes = g_TextParser.GetUTF8CharBytes(value); dvander@276: if (bytes != 1 || !isalpha(*value)) dvander@276: { dvander@276: ParseWarning("Invalid token '%c' in #format property on line %d.", *value, m_CurLine); dvander@276: } dvander@276: } dvander@276: } else if (state == Parse_Index) { dvander@276: if (*value == ':') dvander@276: { dvander@276: state = Parse_Format; dvander@276: if (value - old_value >= 15) dvander@276: { dvander@276: ParseWarning("Too many digits in format index on line %d, phrase will be ignored.", m_CurLine); dvander@276: m_CurPhrase = -1; dvander@276: return SMCParse_Continue; dvander@276: } dvander@276: } else { dvander@276: unsigned int bytes = g_TextParser.GetUTF8CharBytes(value); dvander@276: if (bytes != 1 || !isdigit(*value)) dvander@276: { dvander@276: ParseWarning("Token '%c' in #format property on line %d is not a digit, phrase will be ignored.", dvander@276: *value, dvander@276: m_CurLine); dvander@276: m_CurPhrase = -1; dvander@276: return SMCParse_Continue; dvander@276: } dvander@276: } dvander@276: } else if (state == Parse_Format) { dvander@276: if (*value == '}') dvander@276: { dvander@276: state = Parse_None; dvander@276: } dvander@276: } dvander@276: value++; dvander@276: } dvander@276: dvander@276: if (state != Parse_None) dvander@276: { dvander@276: /* Moose clam cow. */ dvander@276: ParseWarning("Unterminated format string on line %d, phrase will be ignored.", m_CurLine); dvander@276: m_CurPhrase = -1; dvander@276: return SMCParse_Continue; dvander@276: } dvander@276: value = old_value; dvander@276: dvander@276: /* Allocate the format table */ dvander@276: char fmt_buf[16]; dvander@276: int *fmt_list; dvander@276: pPhrase->fmt_list = m_pMemory->CreateMem(sizeof(int) * pPhrase->fmt_count, (void **)&fmt_list); dvander@276: dvander@276: /* Initialize */ dvander@276: for (size_t i=0; ifmt_count; i++) dvander@276: { dvander@276: fmt_list[i] = -1; dvander@276: } dvander@276: dvander@276: /* Now we need to read again... this time into the format buffer */ dvander@276: const char *in_ptr = value; dvander@276: const char *idx_ptr = NULL; dvander@276: char *out_ptr = NULL; dvander@276: unsigned int cur_idx = 0; dvander@276: state = Parse_None; dvander@276: while (*in_ptr != '\0') dvander@276: { dvander@276: if (state == Parse_None) dvander@276: { dvander@276: if (*in_ptr == '{') dvander@276: { dvander@276: state = Parse_Index; dvander@276: idx_ptr = NULL; dvander@276: } dvander@276: } else if (state == Parse_Index) { dvander@276: if (*in_ptr == ':') dvander@276: { dvander@276: /* Check the number! */ dvander@276: if (!idx_ptr) dvander@276: { dvander@276: ParseWarning("Format property contains unindexed format string on line %d, phrase will be ignored.", m_CurLine); dvander@276: m_CurPhrase = -1; dvander@276: return SMCParse_Continue; dvander@276: } dvander@276: long idx = strtol(idx_ptr, NULL, 10); dvander@276: if (idx < 1 || idx > (long)pPhrase->fmt_count) dvander@276: { dvander@276: ParseWarning("Format property contains invalid index '%d' on line %d, phrase will be ignored.", idx, m_CurLine); dvander@276: m_CurPhrase = -1; dvander@276: return SMCParse_Continue; dvander@276: } else if (fmt_list[idx - 1] != -1) { dvander@276: ParseWarning("Format property contains duplicated index '%d' on line %d, phrase will be ignored.", idx, m_CurLine); dvander@276: m_CurPhrase = -1; dvander@276: return SMCParse_Continue; dvander@276: } dvander@276: cur_idx = (unsigned int)idx; dvander@276: state = Parse_Format; dvander@276: out_ptr = NULL; dvander@276: } else if (!idx_ptr) { dvander@276: idx_ptr = in_ptr; dvander@276: } dvander@276: } else if (state == Parse_Format) { dvander@276: if (*in_ptr == '}') dvander@276: { dvander@276: if (!out_ptr) dvander@276: { dvander@276: ParseWarning("Format property contains empty format string on line %d, phrase will be ignored.", m_CurLine); dvander@276: m_CurPhrase = -1; dvander@276: return SMCParse_Continue; dvander@276: } dvander@276: *out_ptr = '\0'; dvander@276: state = Parse_None; dvander@276: /* Now, add this to our table */ dvander@276: fmt_list[cur_idx - 1] = m_pStringTab->AddString(fmt_buf); dvander@276: pPhrase->fmt_bytes += strlen(fmt_buf); dvander@276: } else { dvander@276: if (!out_ptr) dvander@276: { dvander@276: out_ptr = fmt_buf; dvander@276: *out_ptr++ = '%'; dvander@276: } dvander@276: /* Check length ... */ dvander@276: if (out_ptr - fmt_buf >= sizeof(fmt_buf) - 1) dvander@276: { dvander@276: ParseWarning("Format property contains format string that exceeds maximum length on line %d, phrase will be ignored.", dvander@276: m_CurLine); dvander@276: m_CurPhrase = -1; dvander@276: return SMCParse_Continue; dvander@276: } dvander@276: *out_ptr++ = *in_ptr; dvander@276: } dvander@276: } dvander@276: in_ptr++; dvander@276: } dvander@276: dvander@276: /* If we've gotten here, we only accepted unique indexes in a range. dvander@276: * Therefore, the list has to be completely filled. Double check anyway. dvander@276: */ dvander@276: for (size_t i=0; ifmt_count; i++) dvander@276: { dvander@276: if (fmt_list[i] == -1) dvander@276: { dvander@276: ParseWarning("Format property contains no string for index %d on line %d, phrase will be ignored.", dvander@276: i + 1, dvander@276: m_CurLine); dvander@276: m_CurPhrase = -1; dvander@276: return SMCParse_Continue; dvander@276: } dvander@276: } dvander@276: } else { dvander@276: size_t len = strlen(key); dvander@276: if (len != 2) dvander@276: { dvander@276: ParseWarning("Ignoring translation to invalid language \"%s\" on line %d.", key, m_CurLine); dvander@276: return SMCParse_Continue; dvander@276: } dvander@276: dvander@276: unsigned int lang; dvander@276: if (!m_pTranslator->GetLanguageByCode(key, &lang)) dvander@276: { dvander@276: /* Ignore if we don't have a language. dvander@276: * :IDEA: issue a one-time alert? dvander@276: */ dvander@276: return SMCParse_Continue; dvander@276: } dvander@276: dvander@276: /* See how many bytes we need for this string, then allocate. dvander@276: * NOTE: THIS SHOULD GUARANTEE THAT WE DO NOT NEED TO NEED TO SIZE CHECK dvander@276: */ dvander@276: len = strlen(value) + pPhrase->fmt_bytes + 1; dvander@276: char *out_buf; dvander@276: int out_idx; dvander@276: dvander@276: out_idx = m_pMemory->CreateMem(len, (void **)&out_buf); dvander@276: dvander@276: int *fmt_order; dvander@276: int *fmt_list = (int *)m_pMemory->GetAddress(pPhrase->fmt_list); dvander@276: trans_t *pTrans = (trans_t *)m_pMemory->GetAddress(pPhrase->trans_tbl); dvander@276: dvander@276: pTrans = &pTrans[lang]; dvander@276: pTrans->stridx = out_idx; dvander@276: dvander@276: bool params[MAX_TRANSLATE_PARAMS]; dvander@276: dvander@276: /* Build the format order list, if necessary */ dvander@276: if (fmt_list) dvander@276: { dvander@276: pTrans->fmt_order = m_pMemory->CreateMem(pPhrase->fmt_count * sizeof(int), (void **)&fmt_order); dvander@276: dvander@276: for (unsigned int i=0; ifmt_count; i++) dvander@276: { dvander@276: fmt_order[i] = -1; dvander@276: } dvander@276: memset(¶ms[0], 0, sizeof(params)); dvander@276: } dvander@276: dvander@276: const char *in_ptr = value; dvander@276: char *out_ptr = out_buf; dvander@276: unsigned int order_idx = 0; dvander@276: while (*in_ptr != '\0') dvander@276: { dvander@276: if (*in_ptr == '\\') dvander@276: { dvander@276: switch (*(in_ptr + 1)) dvander@276: { dvander@276: case '\n': dvander@276: *out_ptr++ = '\n'; dvander@276: break; dvander@276: case '\t': dvander@276: *out_ptr++ = '\t'; dvander@276: break; dvander@276: case '\r': dvander@276: *out_ptr++ = '\r'; dvander@276: break; dvander@276: case '{': dvander@276: *out_ptr++ = '{'; dvander@276: break; dvander@276: default: dvander@276: /* Copy both bytes since we don't know what's going on */ dvander@276: *out_ptr++ = *in_ptr++; dvander@276: *out_ptr++ = *in_ptr; dvander@276: break; dvander@276: } dvander@276: /* Skip past the last byte read */ dvander@276: in_ptr++; dvander@276: } else if (*in_ptr == '{' && fmt_list != NULL) { dvander@276: /* Search for parameters if this is a formatted string */ dvander@276: const char *scrap_in_point = in_ptr; dvander@276: const char *digit_start = ++in_ptr; dvander@276: unsigned int bytes; dvander@276: while (*in_ptr != '\0') dvander@276: { dvander@276: bytes = g_TextParser.GetUTF8CharBytes(in_ptr); dvander@276: if (bytes != 1) dvander@276: { dvander@276: goto scrap_point; dvander@276: } dvander@276: if (*in_ptr == '}') dvander@276: { dvander@276: /* Did we get an index? */ dvander@276: if (in_ptr == digit_start) dvander@276: { dvander@276: goto scrap_point; dvander@276: } dvander@276: /* Is it valid? */ dvander@276: long idx = strtol(digit_start, NULL, 10); dvander@276: if (idx < 1 || idx > (int)pPhrase->fmt_count) dvander@276: { dvander@276: goto scrap_point; dvander@276: } dvander@276: if (params[idx-1]) dvander@276: { dvander@276: goto scrap_point; dvander@276: } dvander@276: dvander@276: /* We're safe to insert the string. First mark order. */ dvander@276: fmt_order[order_idx++] = (int)idx - 1; dvander@276: /* Now concatenate */ dvander@276: out_ptr += sprintf(out_ptr, "%s", m_pStringTab->GetString(fmt_list[idx-1])); dvander@276: /* Mark as used */ dvander@276: params[idx-1] = true; dvander@276: dvander@276: goto cont_loop; dvander@276: } dvander@276: in_ptr++; dvander@276: } dvander@276: scrap_point: dvander@276: /* Pretend none of this ever happened. Move along now! */ dvander@276: in_ptr = scrap_in_point; dvander@276: *out_ptr++ = *in_ptr; dvander@276: } else { dvander@276: *out_ptr++ = *in_ptr; dvander@276: } dvander@276: cont_loop: dvander@276: in_ptr++; dvander@276: } dvander@276: *out_ptr = '\0'; dvander@276: pPhrase->translations++; dvander@276: } dvander@276: dvander@276: return SMCParse_Continue; dvander@276: } dvander@276: dvander@276: SMCParseResult CPhraseFile::ReadSMC_LeavingSection() dvander@276: { dvander@276: if (m_ParseState == PPS_InPhrase) dvander@276: { dvander@276: if (m_CurPhrase == -1 && m_LastPhraseString.size()) dvander@276: { dvander@276: sm_trie_delete(m_pPhraseLookup, m_LastPhraseString.c_str()); dvander@276: } dvander@276: m_CurPhrase = -1; dvander@276: m_ParseState = PPS_Phrases; dvander@276: m_LastPhraseString.assign(""); dvander@276: } else if (m_ParseState == PPS_Phrases) { dvander@276: m_ParseState = PPS_None; dvander@276: } dvander@276: dvander@276: return SMCParse_Continue; dvander@276: } dvander@276: dvander@276: void CPhraseFile::ReadSMC_ParseEnd(bool halted, bool failed) dvander@276: { dvander@276: /* Check to see if we have any dangling phrases that weren't completed, and scrap them */ dvander@276: if ((halted || failed) && m_LastPhraseString.size()) dvander@276: { dvander@276: sm_trie_delete(m_pPhraseLookup, m_LastPhraseString.c_str()); dvander@276: } dvander@276: } dvander@276: dvander@276: const char *CPhraseFile::GetTranslation(const Translation *pTrans, int **fmt_order, unsigned int *fmt_count) dvander@276: { dvander@276: if (pTrans->lang_id >= m_LangCount) dvander@276: { dvander@276: return NULL; dvander@276: } dvander@276: dvander@276: void *object; dvander@276: if (!sm_trie_retrieve(m_pPhraseLookup, pTrans->szPhrase, &object)) dvander@276: { dvander@276: return NULL; dvander@276: } dvander@276: dvander@276: phrase_t *pPhrase = (phrase_t *)m_pMemory->GetAddress(reinterpret_cast(object)); dvander@276: trans_t *trans = (trans_t *)m_pMemory->GetAddress(pPhrase->trans_tbl); dvander@276: dvander@276: trans = &trans[pTrans->lang_id]; dvander@276: dvander@276: if (trans->stridx == -1) dvander@276: { dvander@276: return NULL; dvander@276: } dvander@276: dvander@276: *fmt_order = (int *)m_pMemory->GetAddress(trans->fmt_order); dvander@276: *fmt_count = pPhrase->fmt_count; dvander@276: dvander@276: return m_pStringTab->GetString(trans->stridx); dvander@276: } dvander@276: dvander@276: const char *CPhraseFile::GetFilename() dvander@276: { dvander@276: return m_File.c_str(); dvander@276: } dvander@276: dvander@276: CTranslator::CTranslator() dvander@276: { dvander@276: m_pStringTab = new BaseStringTable(2048); dvander@276: m_pLCodeLookup = sm_trie_create(); dvander@276: } dvander@276: dvander@276: CTranslator::~CTranslator() dvander@276: { dvander@276: for (size_t i=0; i(_index); dvander@276: } dvander@276: dvander@276: return true; dvander@276: } dvander@276: dvander@276: unsigned int CTranslator::GetLanguageCount() dvander@276: { dvander@276: return (unsigned int)m_Languages.size(); dvander@276: } dvander@276: dvander@276: BaseStringTable *CTranslator::GetStringTable() dvander@276: { dvander@276: return m_pStringTab; dvander@276: } dvander@276: dvander@276: unsigned int CTranslator::FindOrAddPhraseFile(const char *phrase_file) dvander@276: { dvander@276: for (size_t i=0; iGetFilename(), phrase_file) == 0) dvander@276: { dvander@276: return (unsigned int)i; dvander@276: } dvander@276: } dvander@276: dvander@276: CPhraseFile *pFile = new CPhraseFile(this, phrase_file); dvander@276: unsigned int idx = (unsigned int)m_Files.size(); dvander@276: dvander@276: m_Files.push_back(pFile); dvander@276: dvander@276: pFile->ReparseFile(); dvander@276: dvander@276: return idx; dvander@276: } dvander@276: dvander@276: void CTranslator::RebuildLanguageDatabase(const char *lang_header_file) dvander@276: { dvander@276: /* Erase everything we have */ dvander@276: sm_trie_destroy(m_pLCodeLookup); dvander@276: m_pLCodeLookup = sm_trie_create(); dvander@276: m_pStringTab->Reset(); dvander@276: dvander@276: for (size_t i=0; iReparseFile(); dvander@276: } dvander@276: } dvander@276: dvander@276: void CTranslator::ReadSMC_ParseStart() dvander@276: { dvander@276: m_InLanguageSection = false; dvander@276: m_CustomError.clear(); dvander@276: } dvander@276: dvander@276: SMCParseResult CTranslator::ReadSMC_NewSection(const char *name, bool opt_quotes) dvander@276: { dvander@276: if (!m_InLanguageSection) dvander@276: { dvander@276: if (strcmp(name, "Languages") == 0) dvander@276: { dvander@276: m_InLanguageSection = true; dvander@276: } dvander@276: } dvander@276: dvander@276: if (!m_InLanguageSection) dvander@276: { faluco@334: g_Logger.LogError("[SM] Warning: Unrecognized section \"%s\" in languages.cfg", name); dvander@276: } dvander@276: dvander@276: return SMCParse_Continue; dvander@276: } dvander@276: dvander@276: SMCParseResult CTranslator::ReadSMC_LeavingSection() dvander@276: { dvander@276: m_InLanguageSection = false; dvander@276: dvander@276: return SMCParse_Continue; dvander@276: } dvander@276: dvander@276: SMCParseResult CTranslator::ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes) dvander@276: { dvander@276: size_t len = strlen(key); dvander@276: dvander@276: if (len != 2) dvander@276: { dvander@306: g_Logger.LogError("[SM] Warning encountered parsing languages.cfg file."); faluco@334: g_Logger.LogError("[SM] Invalid language code \"%s\" is being ignored.", key); dvander@276: } dvander@276: dvander@276: Language *pLanguage = new Language; dvander@276: unsigned int idx = m_Languages.size(); dvander@276: dvander@276: strcpy(pLanguage->m_code2, key); dvander@276: pLanguage->m_FullName = m_pStringTab->AddString(value); dvander@276: dvander@276: sm_trie_insert(m_pLCodeLookup, key, reinterpret_cast(idx)); dvander@276: dvander@276: m_Languages.push_back(pLanguage); dvander@276: dvander@276: return SMCParse_Continue; dvander@276: } dvander@276: dvander@276: size_t CTranslator::Translate(char *buffer, size_t maxlength, const Translation *pTrans) dvander@276: { dvander@276: if (pTrans->file_id >= m_Files.size()) dvander@276: { dvander@276: return 0; dvander@276: } dvander@276: dvander@276: CPhraseFile *pFile = m_Files[pTrans->file_id]; dvander@276: unsigned int count; dvander@276: int *order_table; dvander@276: const char *str; dvander@276: dvander@276: if ((str=pFile->GetTranslation(pTrans, &order_table, &count)) == NULL) dvander@276: { dvander@276: return 0; dvander@276: } dvander@276: dvander@276: void *params[MAX_TRANSLATE_PARAMS]; dvander@276: dvander@276: /* Rewrite the parameter order */ dvander@276: for (unsigned int i=0; iparams[order_table[i]]; dvander@276: } dvander@276: dvander@276: return gnprintf(buffer, maxlength, str, params); dvander@276: }