4 * Copyright (C) 1993-1999 by Jochen Wiedmann and Marcin Orlowski
5 * Copyright (C) 2002-2010 by the FlexCat Open Source Team
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or (at
10 * your option) any later version.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include <proto/locale.h> /* This is to get locale.library/IsAlpha() */
28 // #include <stdlib.h>
34 #include "showfuncs.h"
35 #include "readprefs.h"
38 #include "createcat.h"
40 char *CatVersionString
= NULL
; /* Version string of catalog
41 translation (## version) */
42 char *CatLanguage
= NULL
; /* Language of catalog translation */
43 char *CatRcsId
= NULL
; /* RCS ID of catalog translation
45 char *CatName
= NULL
; /* Name of catalog translation */
46 uint32 CodeSet
= 0; /* Codeset of catalog translation */
47 int CT_Scanned
= FALSE
; /* If TRUE and we are going to
48 write a new #?.ct file, then the
49 user is surely updating his own
50 #?.ct file, so we should write
51 ***NEW*** wherever necessary. */
53 #define IS_NUMBER_OR_LETTER(c) (((c) >= '0' && (c) <= '9') || \
54 ((c) >= 'a' && (c) <= 'z') || \
55 ((c) >= 'A' && (c) <= 'Z'))
59 /* This scans a catalog translation file.
60 Inputs: ctfile - name of the translation file to scan.
61 Result: TRUE if successful, FALSE otherwise. */
63 int ScanCTFile(char *ctfile
)
66 char *newline
, *line
, *idstr
, *newidstr
, *newstr
;
67 struct CatString
*cs
= NULL
;
69 int CodeSet_checked
= 0;
74 if((fp
= fopen(ctfile
, "r")) == NULL
)
76 ShowErrorQuick(MSG_ERR_NOCATALOGTRANSLATION
, ctfile
);
80 setvbuf(fp
, NULL
, _IOFBF
, buffer_size
);
83 while(!feof(fp
) && (line
= newline
= ReadLine(fp
, TRUE
)) != NULL
)
90 if(cs
&& Strnicmp(line
, Old_Msg_New
, (int)strlen(Old_Msg_New
)) == 0)
99 /* '#' in the first column of a line is the command introducer --
100 any number of # symbols, blank spaces and tabs afterwards are
101 skipped for compatibility with CatComp */
103 while(*line
== '#' || *line
== ' ' || *line
== '\t')
108 if(Strnicmp(line
, "version", 7) == 0)
110 if(CatVersionString
|| CatRcsId
|| CatName
)
112 ShowError(MSG_ERR_DOUBLECTVERSION
);
116 // perform a slightly obfuscated check for the version cookie to
117 // avoid having multiple cookies in the final binary
118 if(line
[0] == '$' && Strnicmp(&line
[1], "VER:", 4) == 0)
120 CatVersionString
= AllocString(line
);
124 ShowError(MSG_ERR_BADCTVERSION
);
127 else if(Strnicmp(line
, "codeset", 7) == 0)
133 ShowError(MSG_ERR_DOUBLECTCODESET
);
139 /* Missing argument for "## codeset" */
141 ShowError(MSG_ERR_BADCTCODESET
);
144 for(ptr
= line
; *ptr
; ptr
++)
145 if(!isdigit((int)*ptr
))
146 /* Non-digit char detected */
148 ShowError(MSG_ERR_BADCTCODESET
);
153 CodeSet
= strtoul(line
, &line
, 0);
155 /* printf("ulong_max es %lu\n",ULONG_MAX);
156 printf("CodeSet obtenido de strtoul es %lu\n",CodeSet);*/
158 if(errno
== ERANGE
&& CodeSet
== ULONG_MAX
)
160 ShowError(MSG_ERR_BADCTCODESET
);
166 else if(Strnicmp(line
, "language", 8) == 0)
172 ShowError(MSG_ERR_DOUBLECTLANGUAGE
);
176 CatLanguage
= AddCatalogChunk(strdup("LANG"), line
);
179 for(ptr
= CatLanguage
; *ptr
; ptr
++)
180 *ptr
= tolower((int)*ptr
);
182 else if(Strnicmp(line
, "chunk", 5) == 0)
189 line
+= sizeof(ULONG
);
192 AddCatalogChunk(ID
, AllocString(line
));
194 else if(Strnicmp(line
, "rcsid", 5) == 0)
196 if(CatVersionString
|| CatRcsId
)
198 ShowError(MSG_ERR_DOUBLECTVERSION
);
202 CatRcsId
= AllocString(line
);
204 else if(Strnicmp(line
, "name", 5) == 0)
206 if(CatVersionString
|| CatName
)
208 ShowError(MSG_ERR_DOUBLECTVERSION
);
212 CatName
= AllocString(line
);
216 ShowWarn(MSG_ERR_UNKNOWNCTCOMMAND
);
219 /* Stop looking for commands */
224 if(*line
== ' ' || *line
== '\t')
226 ShowError(MSG_ERR_UNEXPECTEDBLANKS
);
231 while(IS_NUMBER_OR_LETTER(*line
) || *line
== '_')
237 ShowError(MSG_ERR_NOIDENTIFIER
);
241 if((newidstr
= malloc(line
- idstr
+ 1)) == NULL
)
246 strncpy(newidstr
, idstr
, line
- idstr
);
247 newidstr
[line
- idstr
] = '\0';
252 ShowError(MSG_ERR_EXTRA_CHARACTERS_ID
, newidstr
);
255 if((newstr
= ReadLine(fp
, FALSE
)) != NULL
)
257 for(cs
= FirstCatString
; cs
!= NULL
; cs
= cs
->Next
)
259 if(strcmp(cs
->ID_Str
, newidstr
) == 0)
266 ShowWarn(MSG_ERR_UNKNOWNIDENTIFIER
, newidstr
);
275 ShowError(MSG_ERR_DOUBLE_IDENTIFIER
, cs
->ID_Str
);
279 cs
->CT_Str
= AllocString(newstr
);
282 /* Get string length */
284 reallen
= strlen(cs
->CT_Str
);
285 cd_len
= strlen(cs
->CD_Str
);
287 if(cs
->MinLen
> 0 && reallen
< (size_t)cs
->MinLen
)
289 ShowWarn(MSG_ERR_STRING_TOO_SHORT
, cs
->ID_Str
);
291 if(cs
->MaxLen
> 0 && reallen
> (size_t)cs
->MaxLen
)
293 ShowWarn(MSG_ERR_STRING_TOO_LONG
, cs
->ID_Str
);
296 // check for empty translations
297 if(cd_len
> 0 && reallen
== 0)
299 ShowWarn(MSG_ERR_EMPTYTRANSLATION
, cs
->ID_Str
);
302 /* Check for trailing ellipsis. */
303 if(reallen
>= 3 && cd_len
>= 3)
305 if(strcmp(&cs
->CD_Str
[cd_len
- 3], "...") == 0 &&
306 strcmp(&cs
->CT_Str
[reallen
- 3], "...") != 0)
308 ShowWarn(MSG_ERR_TRAILING_ELLIPSIS
, cs
->ID_Str
);
310 if(strcmp(&cs
->CD_Str
[cd_len
- 3], "...") != 0 &&
311 strcmp(&cs
->CT_Str
[reallen
- 3], "...") == 0)
313 ShowWarn(MSG_ERR_NO_TRAILING_ELLIPSIS
, cs
->ID_Str
);
318 /* Check for trailing spaces. */
319 if(reallen
>= 1 && cd_len
>= 1)
321 if(strcmp(&cs
->CD_Str
[cd_len
- 1], " ") == 0 &&
322 strcmp(&cs
->CT_Str
[reallen
- 1], " ") != 0)
325 ShowWarn(MSG_ERR_TRAILING_BLANKS
, cs
->ID_Str
);
327 if(strcmp(&cs
->CD_Str
[cd_len
- 1], " ") != 0 &&
328 strcmp(&cs
->CT_Str
[reallen
- 1], " ") == 0)
331 ShowWarn(MSG_ERR_NO_TRAILING_BLANKS
, cs
->ID_Str
);
335 /* Check for matching placeholders */
336 if(reallen
>= 1 && cd_len
>= 1)
338 char *cdP
= cs
->CD_Str
;
339 char *ctP
= cs
->CT_Str
;
343 cdP
= strchr(cdP
, '%');
344 ctP
= strchr(ctP
, '%');
346 if(cdP
== NULL
&& ctP
== NULL
)
348 // no more placeholders, bail out
351 else if(cdP
!= NULL
&& ctP
!= NULL
)
357 // check the placeholder only if the '%' is followed by an
358 // alpha-numerical character or another percent sign
359 if(IS_NUMBER_OR_LETTER(*cdP
) || *cdP
== '%')
363 ShowWarn(MSG_ERR_MISMATCHING_PLACEHOLDERS
, cs
->ID_Str
);
366 // skip the second '%' sign
372 else if(IS_NUMBER_OR_LETTER(*ctP
) || *ctP
== '%')
374 // the translation uses a placeholder while the description
376 ShowWarn(MSG_ERR_EXCESSIVE_PLACEHOLDERS
, cs
->ID_Str
);
380 else if(cdP
!= NULL
&& ctP
== NULL
)
385 // check if really a placeholder follows or just another percent sign
386 // the original string is allowed to contain more single percent signs than the translated string
387 if(IS_NUMBER_OR_LETTER(*cdP
) || *cdP
== '%')
389 // the description uses at least one more placeholder than the translation
390 ShowWarn(MSG_ERR_MISSING_PLACEHOLDERS
, cs
->ID_Str
);
394 else if(cdP
== NULL
&& ctP
!= NULL
)
399 // check if really a placeholder follows or just another percent sign
400 // the translated string is allowed to contain more single percent signs than the original string
401 if(IS_NUMBER_OR_LETTER(*ctP
) || *ctP
== '%')
403 // the translation uses at least one more placeholder than the description
404 ShowWarn(MSG_ERR_EXCESSIVE_PLACEHOLDERS
, cs
->ID_Str
);
417 ShowWarn(MSG_ERR_MISSINGSTRING
);
419 cs
->CT_Str
= (char *)"";
424 // forget the pointers as we just freed them and 'line' must not be freed again after the loop
431 ShowErrorQuick(MSG_ERR_NOCTCODESET
);
434 if(!(CatVersionString
|| (CatRcsId
&& CatName
)))
436 ShowErrorQuick(MSG_ERR_NOCTVERSION
);
439 // check if a translation exists for all identifiers
440 for(cs
= FirstCatString
; cs
!= NULL
; cs
= cs
->Next
)
442 if(cs
->CT_Str
== NULL
)
444 ShowWarnQuick(MSG_ERR_MISSINGTRANSLATION
, cs
->ID_Str
);
455 for(cs
= FirstCatString
; cs
!= NULL
; cs
= cs
->Next
)
457 if(cs
->CT_Str
== NULL
)
459 ShowWarn(MSG_ERR_CTGAP
, cs
->ID_Str
);