mirror of https://gitlab.com/rnger/amath
472 lines
17 KiB
C
472 lines
17 KiB
C
/*
|
|
* $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 <proto/locale.h> /* This is to get locale.library/IsAlpha() */
|
|
#endif
|
|
|
|
// #include <stdio.h>
|
|
// #include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
|
|
|
|
#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);
|
|
}
|
|
|
|
///
|
|
|