Wanderer/Info: fix compilation
[AROS.git] / tools / flexcat / src / scanct.c
blobc808af823be409de4443c52d84aa0d920f5741aa
1 /*
2 * $Id$
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.
23 #ifdef AMIGA
24 #include <proto/locale.h> /* This is to get locale.library/IsAlpha() */
25 #endif
27 // #include <stdio.h>
28 // #include <stdlib.h>
29 #include <errno.h>
30 #include <limits.h>
33 #include "flexcat.h"
34 #include "showfuncs.h"
35 #include "readprefs.h"
36 #include "globals.h"
37 #include "utils.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
44 (## rcsid) */
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'))
57 /// ScanCTFile
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)
65 FILE *fp;
66 char *newline, *line, *idstr, *newidstr, *newstr;
67 struct CatString *cs = NULL;
68 int Result = TRUE;
69 int CodeSet_checked = 0;
71 ScanFile = ctfile;
72 ScanLine = 0;
74 if((fp = fopen(ctfile, "r")) == NULL)
76 ShowErrorQuick(MSG_ERR_NOCATALOGTRANSLATION, ctfile);
79 if(!NoBufferedIO)
80 setvbuf(fp, NULL, _IOFBF, buffer_size);
83 while(!feof(fp) && (line = newline = ReadLine(fp, TRUE)) != NULL)
85 switch(*line)
87 case ';':
88 if(CopyNEWs == TRUE)
90 if(cs && Strnicmp(line, Old_Msg_New, (int)strlen(Old_Msg_New)) == 0)
92 cs->NotInCT = TRUE;
95 break;
97 case '#':
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')
105 ++line;
108 if(Strnicmp(line, "version", 7) == 0)
110 if(CatVersionString || CatRcsId || CatName)
112 ShowError(MSG_ERR_DOUBLECTVERSION);
114 line += 7;
115 OverSpace(&line);
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);
122 else
124 ShowError(MSG_ERR_BADCTVERSION);
127 else if(Strnicmp(line, "codeset", 7) == 0)
129 char *ptr;
131 if(CodeSet_checked)
133 ShowError(MSG_ERR_DOUBLECTCODESET);
135 line += 7;
136 OverSpace(&line);
138 if(!*line)
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);
151 errno = 0;
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);
163 CodeSet_checked = 1;
164 // errno = 0;
166 else if(Strnicmp(line, "language", 8) == 0)
168 char *ptr;
170 if(CatLanguage)
172 ShowError(MSG_ERR_DOUBLECTLANGUAGE);
174 line += 8;
175 OverSpace(&line);
176 CatLanguage = AddCatalogChunk(strdup("LANG"), line);
178 if(LANGToLower)
179 for(ptr = CatLanguage; *ptr; ptr++)
180 *ptr = tolower((int)*ptr);
182 else if(Strnicmp(line, "chunk", 5) == 0)
184 char *ID;
186 line += 5;
187 OverSpace(&line);
188 ID = line;
189 line += sizeof(ULONG);
190 OverSpace(&line);
192 AddCatalogChunk(ID, AllocString(line));
194 else if(Strnicmp(line, "rcsid", 5) == 0)
196 if(CatVersionString || CatRcsId)
198 ShowError(MSG_ERR_DOUBLECTVERSION);
200 line += 5;
201 OverSpace(&line);
202 CatRcsId = AllocString(line);
204 else if(Strnicmp(line, "name", 5) == 0)
206 if(CatVersionString || CatName)
208 ShowError(MSG_ERR_DOUBLECTVERSION);
210 line += 4;
211 OverSpace(&line);
212 CatName = AllocString(line);
214 else
216 ShowWarn(MSG_ERR_UNKNOWNCTCOMMAND);
219 /* Stop looking for commands */
221 break;
223 default:
224 if(*line == ' ' || *line == '\t')
226 ShowError(MSG_ERR_UNEXPECTEDBLANKS);
227 OverSpace(&line);
229 idstr = line;
231 while(IS_NUMBER_OR_LETTER(*line) || *line == '_')
233 ++line;
235 if(idstr == line)
237 ShowError(MSG_ERR_NOIDENTIFIER);
238 break;
241 if((newidstr = malloc(line - idstr + 1)) == NULL)
243 MemError();
246 strncpy(newidstr, idstr, line - idstr);
247 newidstr[line - idstr] = '\0';
248 OverSpace(&line);
250 if(*line)
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)
261 break;
264 if(cs == NULL)
266 ShowWarn(MSG_ERR_UNKNOWNIDENTIFIER, newidstr);
268 else
270 size_t reallen;
271 size_t cd_len;
273 if(cs->CT_Str)
275 ShowError(MSG_ERR_DOUBLE_IDENTIFIER, cs->ID_Str);
276 Result = FALSE;
277 free(cs->CT_Str);
279 cs->CT_Str = AllocString(newstr);
280 cs->NotInCT = FALSE;
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
349 break;
351 else if(cdP != NULL && ctP != NULL)
353 // skip the '%' sign
354 cdP++;
355 ctP++;
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 == '%')
361 if(*cdP != *ctP)
363 ShowWarn(MSG_ERR_MISMATCHING_PLACEHOLDERS, cs->ID_Str);
364 break;
366 // skip the second '%' sign
367 if(*cdP == '%')
368 cdP++;
369 if(*ctP == '%')
370 ctP++;
372 else if(IS_NUMBER_OR_LETTER(*ctP) || *ctP == '%')
374 // the translation uses a placeholder while the description
375 // uses none.
376 ShowWarn(MSG_ERR_EXCESSIVE_PLACEHOLDERS, cs->ID_Str);
377 break;
380 else if(cdP != NULL && ctP == NULL)
382 // skip the '%' sign
383 cdP++;
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);
392 break;
394 else if(cdP == NULL && ctP != NULL)
396 // skip the '%' sign
397 ctP++;
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);
406 break;
409 while(TRUE);
413 free(newstr);
415 else
417 ShowWarn(MSG_ERR_MISSINGSTRING);
418 if(cs)
419 cs->CT_Str = (char *)"";
421 free(newidstr);
423 free(newline);
424 // forget the pointers as we just freed them and 'line' must not be freed again after the loop
425 newline = NULL;
426 line = NULL;
429 if(!CodeSet_checked)
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);
448 if(line != NULL)
449 free(line);
451 fclose(fp);
453 if(WarnCTGaps)
455 for(cs = FirstCatString; cs != NULL; cs = cs->Next)
457 if(cs->CT_Str == NULL)
459 ShowWarn(MSG_ERR_CTGAP, cs->ID_Str);
464 if(Result)
465 CT_Scanned = TRUE;
467 return(Result);