153 # define LINE_NUM_FMT "(%d)" |
153 # define LINE_NUM_FMT "(%d)" |
154 #else |
154 #else |
155 # define LINE_NUM_FMT ":%d" |
155 # define LINE_NUM_FMT ":%d" |
156 #endif |
156 #endif |
157 |
157 |
158 static void CDECL warning(const char *s, ...) |
158 static void CDECL strgen_warning(const char *s, ...) |
159 { |
159 { |
160 char buf[1024]; |
160 char buf[1024]; |
161 va_list va; |
161 va_list va; |
162 va_start(va, s); |
162 va_start(va, s); |
163 vsnprintf(buf, lengthof(buf), s, va); |
163 vsnprintf(buf, lengthof(buf), s, va); |
164 va_end(va); |
164 va_end(va); |
165 fprintf(stderr, "%s" LINE_NUM_FMT ": warning: %s\n", _file, _cur_line, buf); |
165 fprintf(stderr, "%s" LINE_NUM_FMT ": warning: %s\n", _file, _cur_line, buf); |
166 _warnings++; |
166 _warnings++; |
167 } |
167 } |
168 |
168 |
169 void CDECL error(const char *s, ...) |
169 static void CDECL strgen_error(const char *s, ...) |
170 { |
170 { |
171 char buf[1024]; |
171 char buf[1024]; |
172 va_list va; |
172 va_list va; |
173 va_start(va, s); |
173 va_start(va, s); |
174 vsnprintf(buf, lengthof(buf), s, va); |
174 vsnprintf(buf, lengthof(buf), s, va); |
175 va_end(va); |
175 va_end(va); |
176 fprintf(stderr, "%s" LINE_NUM_FMT ": error: %s\n", _file, _cur_line, buf); |
176 fprintf(stderr, "%s" LINE_NUM_FMT ": error: %s\n", _file, _cur_line, buf); |
177 _errors++; |
177 _errors++; |
178 } |
178 } |
179 |
179 |
180 |
180 void NORETURN CDECL error(const char *s, ...) |
181 static void NORETURN CDECL fatal(const char *s, ...) |
|
182 { |
181 { |
183 char buf[1024]; |
182 char buf[1024]; |
184 va_list va; |
183 va_list va; |
185 va_start(va, s); |
184 va_start(va, s); |
186 vsnprintf(buf, lengthof(buf), s, va); |
185 vsnprintf(buf, lengthof(buf), s, va); |
211 PutByte(0xF0 + GB(value, 18, 3)); |
210 PutByte(0xF0 + GB(value, 18, 3)); |
212 PutByte(0x80 + GB(value, 12, 6)); |
211 PutByte(0x80 + GB(value, 12, 6)); |
213 PutByte(0x80 + GB(value, 6, 6)); |
212 PutByte(0x80 + GB(value, 6, 6)); |
214 PutByte(0x80 + GB(value, 0, 6)); |
213 PutByte(0x80 + GB(value, 0, 6)); |
215 } else { |
214 } else { |
216 warning("Invalid unicode value U+0x%X", value); |
215 strgen_warning("Invalid unicode value U+0x%X", value); |
217 } |
216 } |
218 } |
217 } |
219 |
218 |
220 |
219 |
221 size_t Utf8Validate(const char *s) |
220 size_t Utf8Validate(const char *s) |
243 } |
242 } |
244 |
243 |
245 |
244 |
246 static void EmitSingleChar(char *buf, int value) |
245 static void EmitSingleChar(char *buf, int value) |
247 { |
246 { |
248 if (*buf != '\0') warning("Ignoring trailing letters in command"); |
247 if (*buf != '\0') strgen_warning("Ignoring trailing letters in command"); |
249 PutUtf8(value); |
248 PutUtf8(value); |
250 } |
249 } |
251 |
250 |
252 |
251 |
253 static void EmitSetX(char *buf, int value) |
252 static void EmitSetX(char *buf, int value) |
254 { |
253 { |
255 char *err; |
254 char *err; |
256 int x = strtol(buf, &err, 0); |
255 int x = strtol(buf, &err, 0); |
257 if (*err != 0) fatal("SetX param invalid"); |
256 if (*err != 0) error("SetX param invalid"); |
258 PutUtf8(SCC_SETX); |
257 PutUtf8(SCC_SETX); |
259 PutByte((byte)x); |
258 PutByte((byte)x); |
260 } |
259 } |
261 |
260 |
262 |
261 |
369 words[nw] = ParseWord(&buf); |
368 words[nw] = ParseWord(&buf); |
370 if (words[nw] == NULL) break; |
369 if (words[nw] == NULL) break; |
371 } |
370 } |
372 |
371 |
373 if (nw == 0) |
372 if (nw == 0) |
374 fatal("%s: No plural words", _cur_ident); |
373 error("%s: No plural words", _cur_ident); |
375 |
374 |
376 if (_plural_form_counts[_lang_pluralform] != nw) { |
375 if (_plural_form_counts[_lang_pluralform] != nw) { |
377 if (_translated) { |
376 if (_translated) { |
378 fatal("%s: Invalid number of plural forms. Expecting %d, found %d.", _cur_ident, |
377 error("%s: Invalid number of plural forms. Expecting %d, found %d.", _cur_ident, |
379 _plural_form_counts[_lang_pluralform], nw); |
378 _plural_form_counts[_lang_pluralform], nw); |
380 } else { |
379 } else { |
381 if ((_show_todo & 2) != 0) warning("'%s' is untranslated. Tweaking english string to allow compilation for plural forms", _cur_ident); |
380 if ((_show_todo & 2) != 0) strgen_warning("'%s' is untranslated. Tweaking english string to allow compilation for plural forms", _cur_ident); |
382 if (nw > _plural_form_counts[_lang_pluralform]) { |
381 if (nw > _plural_form_counts[_lang_pluralform]) { |
383 nw = _plural_form_counts[_lang_pluralform]; |
382 nw = _plural_form_counts[_lang_pluralform]; |
384 } else { |
383 } else { |
385 for (; nw < _plural_form_counts[_lang_pluralform]; nw++) { |
384 for (; nw < _plural_form_counts[_lang_pluralform]; nw++) { |
386 words[nw] = words[nw - 1]; |
385 words[nw] = words[nw - 1]; |
403 if (buf[0] == '=') { |
402 if (buf[0] == '=') { |
404 buf++; |
403 buf++; |
405 |
404 |
406 // This is a {G=DER} command |
405 // This is a {G=DER} command |
407 for (nw = 0; ; nw++) { |
406 for (nw = 0; ; nw++) { |
408 if (nw >= 8) fatal("G argument '%s' invalid", buf); |
407 if (nw >= 8) error("G argument '%s' invalid", buf); |
409 if (strcmp(buf, _genders[nw]) == 0) break; |
408 if (strcmp(buf, _genders[nw]) == 0) break; |
410 } |
409 } |
411 // now nw contains the gender index |
410 // now nw contains the gender index |
412 PutUtf8(SCC_GENDER_INDEX); |
411 PutUtf8(SCC_GENDER_INDEX); |
413 PutByte(nw); |
412 PutByte(nw); |
420 |
419 |
421 for (nw = 0; nw < 8; nw++) { |
420 for (nw = 0; nw < 8; nw++) { |
422 words[nw] = ParseWord(&buf); |
421 words[nw] = ParseWord(&buf); |
423 if (words[nw] == NULL) break; |
422 if (words[nw] == NULL) break; |
424 } |
423 } |
425 if (nw != _numgenders) fatal("Bad # of arguments for gender command"); |
424 if (nw != _numgenders) error("Bad # of arguments for gender command"); |
426 PutUtf8(SCC_GENDER_LIST); |
425 PutUtf8(SCC_GENDER_LIST); |
427 PutByte(TranslateArgumentIdx(argidx)); |
426 PutByte(TranslateArgumentIdx(argidx)); |
428 EmitWordList(words, nw); |
427 EmitWordList(words, nw); |
429 } |
428 } |
430 } |
429 } |
551 uint i; |
550 uint i; |
552 |
551 |
553 for (i = 0; i < MAX_NUM_CASES; i++) { |
552 for (i = 0; i < MAX_NUM_CASES; i++) { |
554 if (memcmp(_cases[i], str, len) == 0 && _cases[i][len] == 0) return i + 1; |
553 if (memcmp(_cases[i], str, len) == 0 && _cases[i][len] == 0) return i + 1; |
555 } |
554 } |
556 fatal("Invalid case-name '%s'", str); |
555 error("Invalid case-name '%s'", str); |
557 } |
556 } |
558 |
557 |
559 |
558 |
560 // returns NULL on eof |
559 // returns NULL on eof |
561 // else returns command struct |
560 // else returns command struct |
588 c = *s++; |
587 c = *s++; |
589 } while (c != '}' && c != ' ' && c != '=' && c != '.' && c != 0); |
588 } while (c != '}' && c != ' ' && c != '=' && c != '.' && c != 0); |
590 |
589 |
591 cmd = FindCmd(start, s - start - 1); |
590 cmd = FindCmd(start, s - start - 1); |
592 if (cmd == NULL) { |
591 if (cmd == NULL) { |
593 error("Undefined command '%.*s'", s - start - 1, start); |
592 strgen_error("Undefined command '%.*s'", s - start - 1, start); |
594 return NULL; |
593 return NULL; |
595 } |
594 } |
596 |
595 |
597 if (c == '.') { |
596 if (c == '.') { |
598 const char *casep = s; |
597 const char *casep = s; |
599 |
598 |
600 if (!(cmd->flags & C_CASE)) |
599 if (!(cmd->flags & C_CASE)) |
601 fatal("Command '%s' can't have a case", cmd->cmd); |
600 error("Command '%s' can't have a case", cmd->cmd); |
602 |
601 |
603 do c = *s++; while (c != '}' && c != ' ' && c != '\0'); |
602 do c = *s++; while (c != '}' && c != ' ' && c != '\0'); |
604 *casei = ResolveCaseName(casep, s - casep - 1); |
603 *casei = ResolveCaseName(casep, s - casep - 1); |
605 } |
604 } |
606 |
605 |
607 if (c == '\0') { |
606 if (c == '\0') { |
608 error("Missing } from command '%s'", start); |
607 strgen_error("Missing } from command '%s'", start); |
609 return NULL; |
608 return NULL; |
610 } |
609 } |
611 |
610 |
612 |
611 |
613 if (c != '}') { |
612 if (c != '}') { |
644 } else if (!memcmp(str, "isocode ", 8)) { |
643 } else if (!memcmp(str, "isocode ", 8)) { |
645 ttd_strlcpy(_lang_isocode, str + 8, sizeof(_lang_isocode)); |
644 ttd_strlcpy(_lang_isocode, str + 8, sizeof(_lang_isocode)); |
646 } else if (!memcmp(str, "plural ", 7)) { |
645 } else if (!memcmp(str, "plural ", 7)) { |
647 _lang_pluralform = atoi(str + 7); |
646 _lang_pluralform = atoi(str + 7); |
648 if (_lang_pluralform >= lengthof(_plural_form_counts)) |
647 if (_lang_pluralform >= lengthof(_plural_form_counts)) |
649 fatal("Invalid pluralform %d", _lang_pluralform); |
648 error("Invalid pluralform %d", _lang_pluralform); |
650 } else if (!memcmp(str, "gender ", 7)) { |
649 } else if (!memcmp(str, "gender ", 7)) { |
651 char* buf = str + 7; |
650 char* buf = str + 7; |
652 |
651 |
653 for (;;) { |
652 for (;;) { |
654 const char* s = ParseWord(&buf); |
653 const char* s = ParseWord(&buf); |
655 |
654 |
656 if (s == NULL) break; |
655 if (s == NULL) break; |
657 if (_numgenders >= MAX_NUM_GENDER) fatal("Too many genders, max %d", MAX_NUM_GENDER); |
656 if (_numgenders >= MAX_NUM_GENDER) error("Too many genders, max %d", MAX_NUM_GENDER); |
658 ttd_strlcpy(_genders[_numgenders], s, sizeof(_genders[_numgenders])); |
657 ttd_strlcpy(_genders[_numgenders], s, sizeof(_genders[_numgenders])); |
659 _numgenders++; |
658 _numgenders++; |
660 } |
659 } |
661 } else if (!memcmp(str, "case ", 5)) { |
660 } else if (!memcmp(str, "case ", 5)) { |
662 char* buf = str + 5; |
661 char* buf = str + 5; |
663 |
662 |
664 for (;;) { |
663 for (;;) { |
665 const char* s = ParseWord(&buf); |
664 const char* s = ParseWord(&buf); |
666 |
665 |
667 if (s == NULL) break; |
666 if (s == NULL) break; |
668 if (_numcases >= MAX_NUM_CASES) fatal("Too many cases, max %d", MAX_NUM_CASES); |
667 if (_numcases >= MAX_NUM_CASES) error("Too many cases, max %d", MAX_NUM_CASES); |
669 ttd_strlcpy(_cases[_numcases], s, sizeof(_cases[_numcases])); |
668 ttd_strlcpy(_cases[_numcases], s, sizeof(_cases[_numcases])); |
670 _numcases++; |
669 _numcases++; |
671 } |
670 } |
672 } else { |
671 } else { |
673 fatal("unknown pragma '%s'", str); |
672 error("unknown pragma '%s'", str); |
674 } |
673 } |
675 } |
674 } |
676 |
675 |
677 static void ExtractCommandString(ParsedCommandStruct* p, const char* s, bool warnings) |
676 static void ExtractCommandString(ParsedCommandStruct* p, const char* s, bool warnings) |
678 { |
677 { |
688 const CmdStruct* ar = ParseCommandString(&s, param, &argno, &casei); |
687 const CmdStruct* ar = ParseCommandString(&s, param, &argno, &casei); |
689 |
688 |
690 if (ar == NULL) break; |
689 if (ar == NULL) break; |
691 |
690 |
692 // Sanity checking |
691 // Sanity checking |
693 if (argno != -1 && ar->consumes == 0) fatal("Non consumer param can't have a paramindex"); |
692 if (argno != -1 && ar->consumes == 0) error("Non consumer param can't have a paramindex"); |
694 |
693 |
695 if (ar->consumes) { |
694 if (ar->consumes) { |
696 if (argno != -1) argidx = argno; |
695 if (argno != -1) argidx = argno; |
697 if (argidx < 0 || argidx >= lengthof(p->cmd)) fatal("invalid param idx %d", argidx); |
696 if (argidx < 0 || argidx >= lengthof(p->cmd)) error("invalid param idx %d", argidx); |
698 if (p->cmd[argidx] != NULL && p->cmd[argidx] != ar) fatal("duplicate param idx %d", argidx); |
697 if (p->cmd[argidx] != NULL && p->cmd[argidx] != ar) error("duplicate param idx %d", argidx); |
699 |
698 |
700 p->cmd[argidx++] = ar; |
699 p->cmd[argidx++] = ar; |
701 } else if (!(ar->flags & C_DONTCOUNT)) { // Ignore some of them |
700 } else if (!(ar->flags & C_DONTCOUNT)) { // Ignore some of them |
702 if (p->np >= lengthof(p->pairs)) fatal("too many commands in string, max %d", lengthof(p->pairs)); |
701 if (p->np >= lengthof(p->pairs)) error("too many commands in string, max %d", lengthof(p->pairs)); |
703 p->pairs[p->np].a = ar; |
702 p->pairs[p->np].a = ar; |
704 p->pairs[p->np].v = param[0] != '\0' ? strdup(param) : ""; |
703 p->pairs[p->np].v = param[0] != '\0' ? strdup(param) : ""; |
705 p->np++; |
704 p->np++; |
706 } |
705 } |
707 } |
706 } |
736 ExtractCommandString(&templ, b, true); |
735 ExtractCommandString(&templ, b, true); |
737 ExtractCommandString(&lang, a, true); |
736 ExtractCommandString(&lang, a, true); |
738 |
737 |
739 // For each string in templ, see if we find it in lang |
738 // For each string in templ, see if we find it in lang |
740 if (templ.np != lang.np) { |
739 if (templ.np != lang.np) { |
741 warning("%s: template string and language string have a different # of commands", name); |
740 strgen_warning("%s: template string and language string have a different # of commands", name); |
742 result = false; |
741 result = false; |
743 } |
742 } |
744 |
743 |
745 for (i = 0; i < templ.np; i++) { |
744 for (i = 0; i < templ.np; i++) { |
746 // see if we find it in lang, and zero it out |
745 // see if we find it in lang, and zero it out |
754 break; |
753 break; |
755 } |
754 } |
756 } |
755 } |
757 |
756 |
758 if (!found) { |
757 if (!found) { |
759 warning("%s: command '%s' exists in template file but not in language file", name, templ.pairs[i].a->cmd); |
758 strgen_warning("%s: command '%s' exists in template file but not in language file", name, templ.pairs[i].a->cmd); |
760 result = false; |
759 result = false; |
761 } |
760 } |
762 } |
761 } |
763 |
762 |
764 // if we reach here, all non consumer commands match up. |
763 // if we reach here, all non consumer commands match up. |
765 // Check if the non consumer commands match up also. |
764 // Check if the non consumer commands match up also. |
766 for (i = 0; i < lengthof(templ.cmd); i++) { |
765 for (i = 0; i < lengthof(templ.cmd); i++) { |
767 if (TranslateCmdForCompare(templ.cmd[i]) != TranslateCmdForCompare(lang.cmd[i])) { |
766 if (TranslateCmdForCompare(templ.cmd[i]) != TranslateCmdForCompare(lang.cmd[i])) { |
768 warning("%s: Param idx #%d '%s' doesn't match with template command '%s'", name, i, |
767 strgen_warning("%s: Param idx #%d '%s' doesn't match with template command '%s'", name, i, |
769 lang.cmd[i] == NULL ? "<empty>" : lang.cmd[i]->cmd, |
768 lang.cmd[i] == NULL ? "<empty>" : lang.cmd[i]->cmd, |
770 templ.cmd[i] == NULL ? "<empty>" : templ.cmd[i]->cmd); |
769 templ.cmd[i] == NULL ? "<empty>" : templ.cmd[i]->cmd); |
771 result = false; |
770 result = false; |
772 } |
771 } |
773 } |
772 } |
789 // Ignore comments & blank lines |
788 // Ignore comments & blank lines |
790 if (*str == ';' || *str == ' ' || *str == '\0') return; |
789 if (*str == ';' || *str == ' ' || *str == '\0') return; |
791 |
790 |
792 s = strchr(str, ':'); |
791 s = strchr(str, ':'); |
793 if (s == NULL) { |
792 if (s == NULL) { |
794 error("Line has no ':' delimiter"); |
793 strgen_error("Line has no ':' delimiter"); |
795 return; |
794 return; |
796 } |
795 } |
797 |
796 |
798 // Trim spaces. |
797 // Trim spaces. |
799 // After this str points to the command name, and s points to the command contents |
798 // After this str points to the command name, and s points to the command contents |
819 // Check if this string already exists.. |
818 // Check if this string already exists.. |
820 ent = HashFind(str); |
819 ent = HashFind(str); |
821 |
820 |
822 if (master) { |
821 if (master) { |
823 if (ent != NULL && casep == NULL) { |
822 if (ent != NULL && casep == NULL) { |
824 error("String name '%s' is used multiple times", str); |
823 strgen_error("String name '%s' is used multiple times", str); |
825 return; |
824 return; |
826 } |
825 } |
827 |
826 |
828 if (ent == NULL && casep != NULL) { |
827 if (ent == NULL && casep != NULL) { |
829 error("Base string name '%s' doesn't exist yet. Define it before defining a case.", str); |
828 strgen_error("Base string name '%s' doesn't exist yet. Define it before defining a case.", str); |
830 return; |
829 return; |
831 } |
830 } |
832 |
831 |
833 if (ent == NULL) { |
832 if (ent == NULL) { |
834 if (_strings[_next_string_id]) { |
833 if (_strings[_next_string_id]) { |
835 error("String ID 0x%X for '%s' already in use by '%s'", ent, str, _strings[_next_string_id]->name); |
834 strgen_error("String ID 0x%X for '%s' already in use by '%s'", ent, str, _strings[_next_string_id]->name); |
836 return; |
835 return; |
837 } |
836 } |
838 |
837 |
839 // Allocate a new LangString |
838 // Allocate a new LangString |
840 ent = CallocT<LangString>(1); |
839 ent = CallocT<LangString>(1); |
857 ent->english = strdup(s); |
856 ent->english = strdup(s); |
858 } |
857 } |
859 |
858 |
860 } else { |
859 } else { |
861 if (ent == NULL) { |
860 if (ent == NULL) { |
862 warning("String name '%s' does not exist in master file", str); |
861 strgen_warning("String name '%s' does not exist in master file", str); |
863 return; |
862 return; |
864 } |
863 } |
865 |
864 |
866 if (ent->translated && casep == NULL) { |
865 if (ent->translated && casep == NULL) { |
867 error("String name '%s' is used multiple times", str); |
866 strgen_error("String name '%s' is used multiple times", str); |
868 return; |
867 return; |
869 } |
868 } |
870 |
869 |
871 if (s[0] == ':' && s[1] == '\0' && casep == NULL) { |
870 if (s[0] == ':' && s[1] == '\0' && casep == NULL) { |
872 // Special syntax :: means we should just inherit the master string |
871 // Special syntax :: means we should just inherit the master string |
910 _lang_name[0] = _lang_ownname[0] = _lang_isocode[0] = '\0'; |
909 _lang_name[0] = _lang_ownname[0] = _lang_isocode[0] = '\0'; |
911 // TODO:!! We can't reset the cases. In case the translated strings |
910 // TODO:!! We can't reset the cases. In case the translated strings |
912 // derive some strings from english.... |
911 // derive some strings from english.... |
913 |
912 |
914 in = fopen(file, "r"); |
913 in = fopen(file, "r"); |
915 if (in == NULL) fatal("Cannot open file"); |
914 if (in == NULL) error("Cannot open file"); |
916 _cur_line = 1; |
915 _cur_line = 1; |
917 while (fgets(buf, sizeof(buf), in) != NULL) { |
916 while (fgets(buf, sizeof(buf), in) != NULL) { |
918 rstrip(buf); |
917 rstrip(buf); |
919 HandleString(buf, english); |
918 HandleString(buf, english); |
920 _cur_line++; |
919 _cur_line++; |
921 } |
920 } |
922 fclose(in); |
921 fclose(in); |
923 |
922 |
924 if (StrEmpty(_lang_name) || StrEmpty(_lang_ownname) || StrEmpty(_lang_isocode)) { |
923 if (StrEmpty(_lang_name) || StrEmpty(_lang_ownname) || StrEmpty(_lang_isocode)) { |
925 fatal("Language must include ##name, ##ownname and ##isocode"); |
924 error("Language must include ##name, ##ownname and ##isocode"); |
926 } |
925 } |
927 } |
926 } |
928 |
927 |
929 |
928 |
930 static uint32 MyHashStr(uint32 hash, const char *s) |
929 static uint32 MyHashStr(uint32 hash, const char *s) |
989 |
988 |
990 f2 = fopen(n2, "rb"); |
989 f2 = fopen(n2, "rb"); |
991 if (f2 == NULL) return false; |
990 if (f2 == NULL) return false; |
992 |
991 |
993 f1 = fopen(n1, "rb"); |
992 f1 = fopen(n1, "rb"); |
994 if (f1 == NULL) fatal("can't open %s", n1); |
993 if (f1 == NULL) error("can't open %s", n1); |
995 |
994 |
996 do { |
995 do { |
997 l1 = fread(b1, 1, sizeof(b1), f1); |
996 l1 = fread(b1, 1, sizeof(b1), f1); |
998 l2 = fread(b2, 1, sizeof(b2), f2); |
997 l2 = fread(b2, 1, sizeof(b2), f2); |
999 |
998 |
1015 FILE *out; |
1014 FILE *out; |
1016 int i; |
1015 int i; |
1017 int next = -1; |
1016 int next = -1; |
1018 |
1017 |
1019 out = fopen("tmp.xxx", "w"); |
1018 out = fopen("tmp.xxx", "w"); |
1020 if (out == NULL) fatal("can't open tmp.xxx"); |
1019 if (out == NULL) error("can't open tmp.xxx"); |
1021 |
1020 |
1022 fprintf(out, "/* This file is automatically generated. Do not modify */\n\n"); |
1021 fprintf(out, "/* This file is automatically generated. Do not modify */\n\n"); |
1023 fprintf(out, "#ifndef TABLE_STRINGS_H\n"); |
1022 fprintf(out, "#ifndef TABLE_STRINGS_H\n"); |
1024 fprintf(out, "#define TABLE_STRINGS_H\n"); |
1023 fprintf(out, "#define TABLE_STRINGS_H\n"); |
1025 |
1024 |
1050 } else { |
1049 } else { |
1051 // else rename tmp.xxx into filename |
1050 // else rename tmp.xxx into filename |
1052 #if defined(WIN32) || defined(WIN64) |
1051 #if defined(WIN32) || defined(WIN64) |
1053 unlink(filename); |
1052 unlink(filename); |
1054 #endif |
1053 #endif |
1055 if (rename("tmp.xxx", filename) == -1) fatal("rename() failed"); |
1054 if (rename("tmp.xxx", filename) == -1) error("rename() failed"); |
1056 } |
1055 } |
1057 } |
1056 } |
1058 |
1057 |
1059 static int TranslateArgumentIdx(int argidx) |
1058 static int TranslateArgumentIdx(int argidx) |
1060 { |
1059 { |
1061 int i, sum; |
1060 int i, sum; |
1062 |
1061 |
1063 if (argidx < 0 || argidx >= lengthof(_cur_pcs.cmd)) |
1062 if (argidx < 0 || argidx >= lengthof(_cur_pcs.cmd)) |
1064 fatal("invalid argidx %d", argidx); |
1063 error("invalid argidx %d", argidx); |
1065 |
1064 |
1066 for (i = sum = 0; i < argidx; i++) { |
1065 for (i = sum = 0; i < argidx; i++) { |
1067 const CmdStruct *cs = _cur_pcs.cmd[i]; |
1066 const CmdStruct *cs = _cur_pcs.cmd[i]; |
1068 sum += (cs != NULL) ? cs->consumes : 1; |
1067 sum += (cs != NULL) ? cs->consumes : 1; |
1069 } |
1068 } |
1140 LanguagePackHeader hdr; |
1139 LanguagePackHeader hdr; |
1141 uint i; |
1140 uint i; |
1142 uint j; |
1141 uint j; |
1143 |
1142 |
1144 f = fopen(filename, "wb"); |
1143 f = fopen(filename, "wb"); |
1145 if (f == NULL) fatal("can't open %s", filename); |
1144 if (f == NULL) error("can't open %s", filename); |
1146 |
1145 |
1147 memset(&hdr, 0, sizeof(hdr)); |
1146 memset(&hdr, 0, sizeof(hdr)); |
1148 for (i = 0; i != 32; i++) { |
1147 for (i = 0; i != 32; i++) { |
1149 uint n = CountInUse(i); |
1148 uint n = CountInUse(i); |
1150 |
1149 |
1178 _cur_line = ls->line; |
1177 _cur_line = ls->line; |
1179 |
1178 |
1180 // Produce a message if a string doesn't have a translation. |
1179 // Produce a message if a string doesn't have a translation. |
1181 if (_show_todo > 0 && ls->translated == NULL) { |
1180 if (_show_todo > 0 && ls->translated == NULL) { |
1182 if ((_show_todo & 2) != 0) { |
1181 if ((_show_todo & 2) != 0) { |
1183 warning("'%s' is untranslated", ls->name); |
1182 strgen_warning("'%s' is untranslated", ls->name); |
1184 } |
1183 } |
1185 if ((_show_todo & 1) != 0) { |
1184 if ((_show_todo & 1) != 0) { |
1186 const char *s = "<TODO> "; |
1185 const char *s = "<TODO> "; |
1187 while (*s != '\0') PutByte(*s++); |
1186 while (*s != '\0') PutByte(*s++); |
1188 } |
1187 } |