/* * $Id$ * * Copyright (C) 1993-1999 by Jochen Wiedmann and Marcin Orlowski * Copyright (C) 2002-2015 FlexCat Open Source Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #ifdef AMIGA #include /* This is to get locale.library/IsAlpha() */ #endif // #include // #include #include #include #include "flexcat.h" #include "showfuncs.h" #include "readprefs.h" #include "globals.h" #include "utils.h" #include "createcat.h" char *CatVersionString = NULL; /* Version string of catalog translation (## version) */ char *CatLanguage = NULL; /* Language of catalog translation */ char *CatRcsId = NULL; /* RCS ID of catalog translation (## rcsid) */ char *CatName = NULL; /* Name of catalog translation */ uint32 CodeSet = 0; /* Codeset of catalog translation */ int CT_Scanned = FALSE; /* If TRUE and we are going to write a new #?.ct file, then the user is surely updating his own #?.ct file, so we should write ***NEW*** wherever necessary. */ #define IS_NUMBER_OR_LETTER(c) (((c) >= '0' && (c) <= '9') || \ ((c) >= 'a' && (c) <= 'z') || \ ((c) >= 'A' && (c) <= 'Z')) /// ScanCTFile /* This scans a catalog translation file. Inputs: ctfile - name of the translation file to scan. Result: TRUE if successful, FALSE otherwise. */ int ScanCTFile(char *ctfile) { FILE *fp; char *newline, *line, *idstr, *newidstr, *newstr; struct CatString *cs = NULL; int Result = TRUE; int CodeSet_checked = 0; ScanFile = ctfile; ScanLine = 0; if((fp = fopen(ctfile, "r")) == NULL) { ShowErrorQuick(MSG_ERR_NOCATALOGTRANSLATION, ctfile); } if(!NoBufferedIO) setvbuf(fp, NULL, _IOFBF, buffer_size); while(!feof(fp) && (line = newline = ReadLine(fp, TRUE)) != NULL) { switch(*line) { case ';': if(CopyNEWs == TRUE) { if(cs && Strnicmp(line, Old_Msg_New, (int)strlen(Old_Msg_New)) == 0) { cs->NotInCT = TRUE; } } break; case '#': /* '#' in the first column of a line is the command introducer -- any number of # symbols, blank spaces and tabs afterwards are skipped for compatibility with CatComp */ while(*line == '#' || *line == ' ' || *line == '\t') { ++line; } if(Strnicmp(line, "version", 7) == 0) { if(CatVersionString || CatRcsId || CatName) { ShowError(MSG_ERR_DOUBLECTVERSION); } line += 7; OverSpace(&line); // perform a slightly obfuscated check for the version cookie to // avoid having multiple cookies in the final binary if(line[0] == '$' && Strnicmp(&line[1], "VER:", 4) == 0) { CatVersionString = AllocString(line); } else { ShowError(MSG_ERR_BADCTVERSION); } } else if(Strnicmp(line, "codeset", 7) == 0) { char *ptr; if(CodeSet_checked) { ShowError(MSG_ERR_DOUBLECTCODESET); } line += 7; OverSpace(&line); if(!*line) /* Missing argument for "## codeset" */ { ShowError(MSG_ERR_BADCTCODESET); } for(ptr = line; *ptr; ptr++) if(!isdigit((int)*ptr)) /* Non-digit char detected */ { ShowError(MSG_ERR_BADCTCODESET); } errno = 0; CodeSet = strtoul(line, &line, 0); /* printf("ulong_max es %lu\n",ULONG_MAX); printf("CodeSet obtenido de strtoul es %lu\n",CodeSet);*/ if(errno == ERANGE && CodeSet == ULONG_MAX) { ShowError(MSG_ERR_BADCTCODESET); } CodeSet_checked = 1; // errno = 0; } else if(Strnicmp(line, "language", 8) == 0) { char *ptr; if(CatLanguage) { ShowError(MSG_ERR_DOUBLECTLANGUAGE); } line += 8; OverSpace(&line); CatLanguage = AddCatalogChunk(strdup("LANG"), line); if(LANGToLower) for(ptr = CatLanguage; *ptr; ptr++) *ptr = tolower((int)*ptr); } else if(Strnicmp(line, "chunk", 5) == 0) { char *ID; line += 5; OverSpace(&line); ID = line; line += sizeof(ULONG); OverSpace(&line); AddCatalogChunk(ID, AllocString(line)); } else if(Strnicmp(line, "rcsid", 5) == 0) { if(CatVersionString || CatRcsId) { ShowError(MSG_ERR_DOUBLECTVERSION); } line += 5; OverSpace(&line); CatRcsId = AllocString(line); } else if(Strnicmp(line, "name", 5) == 0) { if(CatVersionString || CatName) { ShowError(MSG_ERR_DOUBLECTVERSION); } line += 4; OverSpace(&line); CatName = AllocString(line); } else { ShowWarn(MSG_ERR_UNKNOWNCTCOMMAND); } /* Stop looking for commands */ break; default: if(*line == ' ' || *line == '\t') { ShowError(MSG_ERR_UNEXPECTEDBLANKS); OverSpace(&line); } idstr = line; while(IS_NUMBER_OR_LETTER(*line) || *line == '_') { ++line; } if(idstr == line) { ShowError(MSG_ERR_NOIDENTIFIER); break; } if((newidstr = malloc(line - idstr + 1)) == NULL) { MemError(); } strncpy(newidstr, idstr, line - idstr); newidstr[line - idstr] = '\0'; OverSpace(&line); if(*line) { ShowError(MSG_ERR_EXTRA_CHARACTERS_ID, newidstr); } if((newstr = ReadLine(fp, FALSE)) != NULL) { for(cs = FirstCatString; cs != NULL; cs = cs->Next) { if(strcmp(cs->ID_Str, newidstr) == 0) { break; } } if(cs == NULL) { ShowWarn(MSG_ERR_UNKNOWNIDENTIFIER, newidstr); } else { size_t reallen; size_t cd_len; if(cs->CT_Str) { ShowError(MSG_ERR_DOUBLE_IDENTIFIER, cs->ID_Str); Result = FALSE; free(cs->CT_Str); } cs->CT_Str = AllocString(newstr); cs->NotInCT = FALSE; /* Get string length */ reallen = strlen(cs->CT_Str); cd_len = strlen(cs->CD_Str); if(cs->MinLen > 0 && reallen < (size_t)cs->MinLen) { ShowWarn(MSG_ERR_STRING_TOO_SHORT, cs->ID_Str); } if(cs->MaxLen > 0 && reallen > (size_t)cs->MaxLen) { ShowWarn(MSG_ERR_STRING_TOO_LONG, cs->ID_Str); } // check for empty translations if(cd_len > 0 && reallen == 0) { ShowWarn(MSG_ERR_EMPTYTRANSLATION, cs->ID_Str); } /* Check for trailing ellipsis. */ if(reallen >= 3 && cd_len >= 3) { if(strcmp(&cs->CD_Str[cd_len - 3], "...") == 0 && strcmp(&cs->CT_Str[reallen - 3], "...") != 0) { ShowWarn(MSG_ERR_TRAILING_ELLIPSIS, cs->ID_Str); } if(strcmp(&cs->CD_Str[cd_len - 3], "...") != 0 && strcmp(&cs->CT_Str[reallen - 3], "...") == 0) { ShowWarn(MSG_ERR_NO_TRAILING_ELLIPSIS, cs->ID_Str); } } /* Check for trailing spaces. */ if(reallen >= 1 && cd_len >= 1) { if(strcmp(&cs->CD_Str[cd_len - 1], " ") == 0 && strcmp(&cs->CT_Str[reallen - 1], " ") != 0) { ShowWarn(MSG_ERR_TRAILING_BLANKS, cs->ID_Str); } if(strcmp(&cs->CD_Str[cd_len - 1], " ") != 0 && strcmp(&cs->CT_Str[reallen - 1], " ") == 0) { ShowWarn(MSG_ERR_NO_TRAILING_BLANKS, cs->ID_Str); } } /* Check for matching placeholders */ if(reallen >= 1 && cd_len >= 1) { char *cdP = cs->CD_Str; char *ctP = cs->CT_Str; do { cdP = strchr(cdP, '%'); ctP = strchr(ctP, '%'); if(cdP == NULL && ctP == NULL) { // no more placeholders, bail out break; } else if(cdP != NULL && ctP != NULL) { // skip the '%' sign cdP++; ctP++; // check the placeholder only if the '%' is followed by an // alpha-numerical character or another percent sign if(IS_NUMBER_OR_LETTER(*cdP) || *cdP == '%') { if(*cdP != *ctP) { ShowWarn(MSG_ERR_MISMATCHING_PLACEHOLDERS, cs->ID_Str); break; } // skip the second '%' sign if(*cdP == '%') cdP++; if(*ctP == '%') ctP++; } else if(IS_NUMBER_OR_LETTER(*ctP) || *ctP == '%') { // the translation uses a placeholder while the description // uses none. ShowWarn(MSG_ERR_EXCESSIVE_PLACEHOLDERS, cs->ID_Str); break; } } else if(cdP != NULL && ctP == NULL) { // skip the '%' sign cdP++; // check if really a placeholder follows or just another percent sign // the original string is allowed to contain more single percent signs than the translated string if(IS_NUMBER_OR_LETTER(*cdP) || *cdP == '%') { // the description uses at least one more placeholder than the translation ShowWarn(MSG_ERR_MISSING_PLACEHOLDERS, cs->ID_Str); } break; } else if(cdP == NULL && ctP != NULL) { // skip the '%' sign ctP++; // check if really a placeholder follows or just another percent sign // the translated string is allowed to contain more single percent signs than the original string if(IS_NUMBER_OR_LETTER(*ctP) || *ctP == '%') { // the translation uses at least one more placeholder than the description ShowWarn(MSG_ERR_EXCESSIVE_PLACEHOLDERS, cs->ID_Str); } break; } } while(TRUE); } } free(newstr); } else { ShowWarn(MSG_ERR_MISSINGSTRING); if(cs) cs->CT_Str = (char *)""; } free(newidstr); } free(newline); // forget the pointers as we just freed them and 'line' must not be freed again after the loop newline = NULL; line = NULL; } if(!CodeSet_checked) { ShowErrorQuick(MSG_ERR_NOCTCODESET); } if(!(CatVersionString || (CatRcsId && CatName))) { ShowErrorQuick(MSG_ERR_NOCTVERSION); } // check if a translation exists for all identifiers for(cs = FirstCatString; cs != NULL; cs = cs->Next) { if(cs->CT_Str == NULL) { ShowWarnQuick(MSG_ERR_MISSINGTRANSLATION, cs->ID_Str); } } if(line != NULL) free(line); fclose(fp); if(WarnCTGaps) { for(cs = FirstCatString; cs != NULL; cs = cs->Next) { if(cs->CT_Str == NULL) { ShowWarn(MSG_ERR_CTGAP, cs->ID_Str); } } } if(Result) CT_Scanned = TRUE; return(Result); } ///