156 # define LINE_NUM_FMT "(%d)" |
156 # define LINE_NUM_FMT "(%d)" |
157 #else |
157 #else |
158 # define LINE_NUM_FMT ":%d" |
158 # define LINE_NUM_FMT ":%d" |
159 #endif |
159 #endif |
160 |
160 |
161 static void CDECL Warning(const char *s, ...) |
161 static void CDECL warning(const char *s, ...) |
162 { |
162 { |
163 char buf[1024]; |
163 char buf[1024]; |
164 va_list va; |
164 va_list va; |
165 va_start(va, s); |
165 va_start(va, s); |
166 vsnprintf(buf, lengthof(buf), s, va); |
166 vsnprintf(buf, lengthof(buf), s, va); |
167 va_end(va); |
167 va_end(va); |
168 fprintf(stderr, "%s" LINE_NUM_FMT ": warning: %s\n", _file, _cur_line, buf); |
168 fprintf(stderr, "%s" LINE_NUM_FMT ": warning: %s\n", _file, _cur_line, buf); |
169 _warnings++; |
169 _warnings++; |
170 } |
170 } |
171 |
171 |
172 |
172 void CDECL error(const char *s, ...) |
173 static void CDECL Error(const char *s, ...) |
|
174 { |
173 { |
175 char buf[1024]; |
174 char buf[1024]; |
176 va_list va; |
175 va_list va; |
177 va_start(va, s); |
176 va_start(va, s); |
178 vsnprintf(buf, lengthof(buf), s, va); |
177 vsnprintf(buf, lengthof(buf), s, va); |
180 fprintf(stderr, "%s" LINE_NUM_FMT ": error: %s\n", _file, _cur_line, buf); |
179 fprintf(stderr, "%s" LINE_NUM_FMT ": error: %s\n", _file, _cur_line, buf); |
181 _errors++; |
180 _errors++; |
182 } |
181 } |
183 |
182 |
184 |
183 |
185 static void NORETURN CDECL Fatal(const char *s, ...) |
184 static void NORETURN CDECL fatal(const char *s, ...) |
186 { |
185 { |
187 char buf[1024]; |
186 char buf[1024]; |
188 va_list va; |
187 va_list va; |
189 va_start(va, s); |
188 va_start(va, s); |
190 vsnprintf(buf, lengthof(buf), s, va); |
189 vsnprintf(buf, lengthof(buf), s, va); |
193 exit(1); |
192 exit(1); |
194 } |
193 } |
195 |
194 |
196 static void PutByte(byte c) |
195 static void PutByte(byte c) |
197 { |
196 { |
198 if (_put_pos == lengthof(_put_buf)) Fatal("Put buffer too small"); |
197 if (_put_pos == lengthof(_put_buf)) fatal("Put buffer too small"); |
199 _put_buf[_put_pos++] = c; |
198 _put_buf[_put_pos++] = c; |
200 } |
199 } |
201 |
200 |
202 |
201 |
203 static void EmitSingleByte(char *buf, int value) |
202 static void EmitSingleByte(char *buf, int value) |
204 { |
203 { |
205 if (*buf != '\0') Warning("Ignoring trailing letters in command"); |
204 if (*buf != '\0') warning("Ignoring trailing letters in command"); |
206 PutByte((byte)value); |
205 PutByte((byte)value); |
207 } |
206 } |
208 |
207 |
209 |
208 |
210 static void EmitEscapedByte(char *buf, int value) |
209 static void EmitEscapedByte(char *buf, int value) |
211 { |
210 { |
212 if (*buf != '\0') Warning("Ignoring trailing letters in command"); |
211 if (*buf != '\0') warning("Ignoring trailing letters in command"); |
213 PutByte(0x85); |
212 PutByte(0x85); |
214 PutByte((byte)value); |
213 PutByte((byte)value); |
215 } |
214 } |
216 |
215 |
217 static void EmitSetX(char *buf, int value) |
216 static void EmitSetX(char *buf, int value) |
218 { |
217 { |
219 char *err; |
218 char *err; |
220 int x = strtol(buf, &err, 0); |
219 int x = strtol(buf, &err, 0); |
221 if (*err != 0) Fatal("SetX param invalid"); |
220 if (*err != 0) fatal("SetX param invalid"); |
222 PutByte(1); |
221 PutByte(1); |
223 PutByte((byte)x); |
222 PutByte((byte)x); |
224 } |
223 } |
225 |
224 |
226 |
225 |
333 words[nw] = ParseWord(&buf); |
332 words[nw] = ParseWord(&buf); |
334 if (words[nw] == NULL) break; |
333 if (words[nw] == NULL) break; |
335 } |
334 } |
336 |
335 |
337 if (nw == 0) |
336 if (nw == 0) |
338 Fatal("%s: No plural words", _cur_ident); |
337 fatal("%s: No plural words", _cur_ident); |
339 |
338 |
340 if (_plural_form_counts[_lang_pluralform] != nw) { |
339 if (_plural_form_counts[_lang_pluralform] != nw) { |
341 if (_translated) { |
340 if (_translated) { |
342 Fatal("%s: Invalid number of plural forms. Expecting %d, found %d.", _cur_ident, |
341 fatal("%s: Invalid number of plural forms. Expecting %d, found %d.", _cur_ident, |
343 _plural_form_counts[_lang_pluralform], nw); |
342 _plural_form_counts[_lang_pluralform], nw); |
344 } else { |
343 } else { |
345 Warning("'%s' is untranslated. Tweaking english string to allow compilation for plural forms", _cur_ident); |
344 warning("'%s' is untranslated. Tweaking english string to allow compilation for plural forms", _cur_ident); |
346 if (nw > _plural_form_counts[_lang_pluralform]) { |
345 if (nw > _plural_form_counts[_lang_pluralform]) { |
347 nw = _plural_form_counts[_lang_pluralform]; |
346 nw = _plural_form_counts[_lang_pluralform]; |
348 } else { |
347 } else { |
349 for (; nw < _plural_form_counts[_lang_pluralform]; nw++) { |
348 for (; nw < _plural_form_counts[_lang_pluralform]; nw++) { |
350 words[nw] = words[nw - 1]; |
349 words[nw] = words[nw - 1]; |
367 if (buf[0] == '=') { |
366 if (buf[0] == '=') { |
368 buf++; |
367 buf++; |
369 |
368 |
370 // This is a {G=DER} command |
369 // This is a {G=DER} command |
371 for (nw = 0; ; nw++) { |
370 for (nw = 0; ; nw++) { |
372 if (nw >= 8) Fatal("G argument '%s' invalid", buf); |
371 if (nw >= 8) fatal("G argument '%s' invalid", buf); |
373 if (strcmp(buf, _genders[nw]) == 0) break; |
372 if (strcmp(buf, _genders[nw]) == 0) break; |
374 } |
373 } |
375 // now nw contains the gender index |
374 // now nw contains the gender index |
376 PutByte(0x87); |
375 PutByte(0x87); |
377 PutByte(nw); |
376 PutByte(nw); |
384 |
383 |
385 for (nw = 0; nw < 8; nw++) { |
384 for (nw = 0; nw < 8; nw++) { |
386 words[nw] = ParseWord(&buf); |
385 words[nw] = ParseWord(&buf); |
387 if (words[nw] == NULL) break; |
386 if (words[nw] == NULL) break; |
388 } |
387 } |
389 if (nw != _numgenders) Fatal("Bad # of arguments for gender command"); |
388 if (nw != _numgenders) fatal("Bad # of arguments for gender command"); |
390 PutByte(0x85); |
389 PutByte(0x85); |
391 PutByte(13); |
390 PutByte(13); |
392 PutByte(TranslateArgumentIdx(argidx)); |
391 PutByte(TranslateArgumentIdx(argidx)); |
393 EmitWordList(words, nw); |
392 EmitWordList(words, nw); |
394 } |
393 } |
518 uint i; |
517 uint i; |
519 |
518 |
520 for (i = 0; i < MAX_NUM_CASES; i++) { |
519 for (i = 0; i < MAX_NUM_CASES; i++) { |
521 if (memcmp(_cases[i], str, len) == 0 && _cases[i][len] == 0) return i + 1; |
520 if (memcmp(_cases[i], str, len) == 0 && _cases[i][len] == 0) return i + 1; |
522 } |
521 } |
523 Fatal("Invalid case-name '%s'", str); |
522 fatal("Invalid case-name '%s'", str); |
524 } |
523 } |
525 |
524 |
526 |
525 |
527 // returns NULL on eof |
526 // returns NULL on eof |
528 // else returns command struct |
527 // else returns command struct |
555 c = *s++; |
554 c = *s++; |
556 } while (c != '}' && c != ' ' && c != '=' && c != '.' && c != 0); |
555 } while (c != '}' && c != ' ' && c != '=' && c != '.' && c != 0); |
557 |
556 |
558 cmd = FindCmd(start, s - start - 1); |
557 cmd = FindCmd(start, s - start - 1); |
559 if (cmd == NULL) { |
558 if (cmd == NULL) { |
560 Error("Undefined command '%.*s'", s - start - 1, start); |
559 error("Undefined command '%.*s'", s - start - 1, start); |
561 return NULL; |
560 return NULL; |
562 } |
561 } |
563 |
562 |
564 if (c == '.') { |
563 if (c == '.') { |
565 const char *casep = s; |
564 const char *casep = s; |
566 |
565 |
567 if (!(cmd->flags & C_CASE)) |
566 if (!(cmd->flags & C_CASE)) |
568 Fatal("Command '%s' can't have a case", cmd->cmd); |
567 fatal("Command '%s' can't have a case", cmd->cmd); |
569 |
568 |
570 do c = *s++; while (c != '}' && c != ' ' && c != '\0'); |
569 do c = *s++; while (c != '}' && c != ' ' && c != '\0'); |
571 *casei = ResolveCaseName(casep, s - casep - 1); |
570 *casei = ResolveCaseName(casep, s - casep - 1); |
572 } |
571 } |
573 |
572 |
574 if (c == '\0') { |
573 if (c == '\0') { |
575 Error("Missing } from command '%s'", start); |
574 error("Missing } from command '%s'", start); |
576 return NULL; |
575 return NULL; |
577 } |
576 } |
578 |
577 |
579 |
578 |
580 if (c != '}') { |
579 if (c != '}') { |
611 } else if (!memcmp(str, "isocode ", 8)) { |
610 } else if (!memcmp(str, "isocode ", 8)) { |
612 ttd_strlcpy(_lang_isocode, str + 8, sizeof(_lang_isocode)); |
611 ttd_strlcpy(_lang_isocode, str + 8, sizeof(_lang_isocode)); |
613 } else if (!memcmp(str, "plural ", 7)) { |
612 } else if (!memcmp(str, "plural ", 7)) { |
614 _lang_pluralform = atoi(str + 7); |
613 _lang_pluralform = atoi(str + 7); |
615 if (_lang_pluralform >= lengthof(_plural_form_counts)) |
614 if (_lang_pluralform >= lengthof(_plural_form_counts)) |
616 Fatal("Invalid pluralform %d", _lang_pluralform); |
615 fatal("Invalid pluralform %d", _lang_pluralform); |
617 } else if (!memcmp(str, "gender ", 7)) { |
616 } else if (!memcmp(str, "gender ", 7)) { |
618 char* buf = str + 7; |
617 char* buf = str + 7; |
619 |
618 |
620 for (;;) { |
619 for (;;) { |
621 const char* s = ParseWord(&buf); |
620 const char* s = ParseWord(&buf); |
622 |
621 |
623 if (s == NULL) break; |
622 if (s == NULL) break; |
624 if (_numgenders >= MAX_NUM_GENDER) Fatal("Too many genders, max %d", MAX_NUM_GENDER); |
623 if (_numgenders >= MAX_NUM_GENDER) fatal("Too many genders, max %d", MAX_NUM_GENDER); |
625 ttd_strlcpy(_genders[_numgenders], s, sizeof(_genders[_numgenders])); |
624 ttd_strlcpy(_genders[_numgenders], s, sizeof(_genders[_numgenders])); |
626 _numgenders++; |
625 _numgenders++; |
627 } |
626 } |
628 } else if (!memcmp(str, "case ", 5)) { |
627 } else if (!memcmp(str, "case ", 5)) { |
629 char* buf = str + 5; |
628 char* buf = str + 5; |
630 |
629 |
631 for (;;) { |
630 for (;;) { |
632 const char* s = ParseWord(&buf); |
631 const char* s = ParseWord(&buf); |
633 |
632 |
634 if (s == NULL) break; |
633 if (s == NULL) break; |
635 if (_numcases >= MAX_NUM_CASES) Fatal("Too many cases, max %d", MAX_NUM_CASES); |
634 if (_numcases >= MAX_NUM_CASES) fatal("Too many cases, max %d", MAX_NUM_CASES); |
636 ttd_strlcpy(_cases[_numcases], s, sizeof(_cases[_numcases])); |
635 ttd_strlcpy(_cases[_numcases], s, sizeof(_cases[_numcases])); |
637 _numcases++; |
636 _numcases++; |
638 } |
637 } |
639 } else { |
638 } else { |
640 Fatal("unknown pragma '%s'", str); |
639 fatal("unknown pragma '%s'", str); |
641 } |
640 } |
642 } |
641 } |
643 |
642 |
644 static void ExtractCommandString(ParsedCommandStruct* p, const char* s, bool warnings) |
643 static void ExtractCommandString(ParsedCommandStruct* p, const char* s, bool warnings) |
645 { |
644 { |
655 const CmdStruct* ar = ParseCommandString(&s, param, &argno, &casei); |
654 const CmdStruct* ar = ParseCommandString(&s, param, &argno, &casei); |
656 |
655 |
657 if (ar == NULL) break; |
656 if (ar == NULL) break; |
658 |
657 |
659 // Sanity checking |
658 // Sanity checking |
660 if (argno != -1 && ar->consumes == 0) Fatal("Non consumer param can't have a paramindex"); |
659 if (argno != -1 && ar->consumes == 0) fatal("Non consumer param can't have a paramindex"); |
661 |
660 |
662 if (ar->consumes) { |
661 if (ar->consumes) { |
663 if (argno != -1) argidx = argno; |
662 if (argno != -1) argidx = argno; |
664 if (argidx < 0 || argidx >= lengthof(p->cmd)) Fatal("invalid param idx %d", argidx); |
663 if (argidx < 0 || argidx >= lengthof(p->cmd)) fatal("invalid param idx %d", argidx); |
665 if (p->cmd[argidx] != NULL && p->cmd[argidx] != ar) Fatal("duplicate param idx %d", argidx); |
664 if (p->cmd[argidx] != NULL && p->cmd[argidx] != ar) fatal("duplicate param idx %d", argidx); |
666 |
665 |
667 p->cmd[argidx++] = ar; |
666 p->cmd[argidx++] = ar; |
668 } else if (!(ar->flags & C_DONTCOUNT)) { // Ignore some of them |
667 } else if (!(ar->flags & C_DONTCOUNT)) { // Ignore some of them |
669 if (p->np >= lengthof(p->pairs)) Fatal("too many commands in string, max %d", lengthof(p->pairs)); |
668 if (p->np >= lengthof(p->pairs)) fatal("too many commands in string, max %d", lengthof(p->pairs)); |
670 p->pairs[p->np].a = ar; |
669 p->pairs[p->np].a = ar; |
671 p->pairs[p->np].v = param[0] != '\0' ? strdup(param) : ""; |
670 p->pairs[p->np].v = param[0] != '\0' ? strdup(param) : ""; |
672 p->np++; |
671 p->np++; |
673 } |
672 } |
674 } |
673 } |
703 ExtractCommandString(&templ, b, true); |
702 ExtractCommandString(&templ, b, true); |
704 ExtractCommandString(&lang, a, true); |
703 ExtractCommandString(&lang, a, true); |
705 |
704 |
706 // For each string in templ, see if we find it in lang |
705 // For each string in templ, see if we find it in lang |
707 if (templ.np != lang.np) { |
706 if (templ.np != lang.np) { |
708 Warning("%s: template string and language string have a different # of commands", name); |
707 warning("%s: template string and language string have a different # of commands", name); |
709 result = false; |
708 result = false; |
710 } |
709 } |
711 |
710 |
712 for (i = 0; i < templ.np; i++) { |
711 for (i = 0; i < templ.np; i++) { |
713 // see if we find it in lang, and zero it out |
712 // see if we find it in lang, and zero it out |
721 break; |
720 break; |
722 } |
721 } |
723 } |
722 } |
724 |
723 |
725 if (!found) { |
724 if (!found) { |
726 Warning("%s: command '%s' exists in template file but not in language file", name, templ.pairs[i].a->cmd); |
725 warning("%s: command '%s' exists in template file but not in language file", name, templ.pairs[i].a->cmd); |
727 result = false; |
726 result = false; |
728 } |
727 } |
729 } |
728 } |
730 |
729 |
731 // if we reach here, all non consumer commands match up. |
730 // if we reach here, all non consumer commands match up. |
732 // Check if the non consumer commands match up also. |
731 // Check if the non consumer commands match up also. |
733 for (i = 0; i < lengthof(templ.cmd); i++) { |
732 for (i = 0; i < lengthof(templ.cmd); i++) { |
734 if (TranslateCmdForCompare(templ.cmd[i]) != TranslateCmdForCompare(lang.cmd[i])) { |
733 if (TranslateCmdForCompare(templ.cmd[i]) != TranslateCmdForCompare(lang.cmd[i])) { |
735 Warning("%s: Param idx #%d '%s' doesn't match with template command '%s'", name, i, |
734 warning("%s: Param idx #%d '%s' doesn't match with template command '%s'", name, i, |
736 lang.cmd[i] == NULL ? "<empty>" : lang.cmd[i]->cmd, |
735 lang.cmd[i] == NULL ? "<empty>" : lang.cmd[i]->cmd, |
737 templ.cmd[i] == NULL ? "<empty>" : templ.cmd[i]->cmd); |
736 templ.cmd[i] == NULL ? "<empty>" : templ.cmd[i]->cmd); |
738 result = false; |
737 result = false; |
739 } |
738 } |
740 } |
739 } |
756 // Ignore comments & blank lines |
755 // Ignore comments & blank lines |
757 if (*str == ';' || *str == ' ' || *str == '\0') return; |
756 if (*str == ';' || *str == ' ' || *str == '\0') return; |
758 |
757 |
759 s = strchr(str, ':'); |
758 s = strchr(str, ':'); |
760 if (s == NULL) { |
759 if (s == NULL) { |
761 Error("Line has no ':' delimiter"); |
760 error("Line has no ':' delimiter"); |
762 return; |
761 return; |
763 } |
762 } |
764 |
763 |
765 // Trim spaces. |
764 // Trim spaces. |
766 // After this str points to the command name, and s points to the command contents |
765 // After this str points to the command name, and s points to the command contents |
776 // Check if this string already exists.. |
775 // Check if this string already exists.. |
777 ent = HashFind(str); |
776 ent = HashFind(str); |
778 |
777 |
779 if (master) { |
778 if (master) { |
780 if (ent != NULL && casep == NULL) { |
779 if (ent != NULL && casep == NULL) { |
781 Error("String name '%s' is used multiple times", str); |
780 error("String name '%s' is used multiple times", str); |
782 return; |
781 return; |
783 } |
782 } |
784 |
783 |
785 if (ent == NULL && casep != NULL) { |
784 if (ent == NULL && casep != NULL) { |
786 Error("Base string name '%s' doesn't exist yet. Define it before defining a case.", str); |
785 error("Base string name '%s' doesn't exist yet. Define it before defining a case.", str); |
787 return; |
786 return; |
788 } |
787 } |
789 |
788 |
790 if (ent == NULL) { |
789 if (ent == NULL) { |
791 if (_strings[_next_string_id]) { |
790 if (_strings[_next_string_id]) { |
792 Error("String ID 0x%X for '%s' already in use by '%s'", ent, str, _strings[_next_string_id]->name); |
791 error("String ID 0x%X for '%s' already in use by '%s'", ent, str, _strings[_next_string_id]->name); |
793 return; |
792 return; |
794 } |
793 } |
795 |
794 |
796 // Allocate a new LangString |
795 // Allocate a new LangString |
797 ent = calloc(1, sizeof(*ent)); |
796 ent = calloc(1, sizeof(*ent)); |
814 ent->english = strdup(s); |
813 ent->english = strdup(s); |
815 } |
814 } |
816 |
815 |
817 } else { |
816 } else { |
818 if (ent == NULL) { |
817 if (ent == NULL) { |
819 Warning("String name '%s' does not exist in master file", str); |
818 warning("String name '%s' does not exist in master file", str); |
820 return; |
819 return; |
821 } |
820 } |
822 |
821 |
823 if (ent->translated && casep == NULL) { |
822 if (ent->translated && casep == NULL) { |
824 Error("String name '%s' is used multiple times", str); |
823 error("String name '%s' is used multiple times", str); |
825 return; |
824 return; |
826 } |
825 } |
827 |
826 |
828 if (s[0] == ':' && s[1] == '\0' && casep == NULL) { |
827 if (s[0] == ':' && s[1] == '\0' && casep == NULL) { |
829 // Special syntax :: means we should just inherit the master string |
828 // Special syntax :: means we should just inherit the master string |
867 // TODO:!! We can't reset the cases. In case the translated strings |
866 // TODO:!! We can't reset the cases. In case the translated strings |
868 // derive some strings from english.... |
867 // derive some strings from english.... |
869 |
868 |
870 |
869 |
871 in = fopen(file, "r"); |
870 in = fopen(file, "r"); |
872 if (in == NULL) Fatal("Cannot open file"); |
871 if (in == NULL) fatal("Cannot open file"); |
873 _cur_line = 1; |
872 _cur_line = 1; |
874 while (fgets(buf, sizeof(buf),in) != NULL) { |
873 while (fgets(buf, sizeof(buf),in) != NULL) { |
875 rstrip(buf); |
874 rstrip(buf); |
876 HandleString(buf, english); |
875 HandleString(buf, english); |
877 _cur_line++; |
876 _cur_line++; |
942 |
941 |
943 f2 = fopen(n2, "rb"); |
942 f2 = fopen(n2, "rb"); |
944 if (f2 == NULL) return false; |
943 if (f2 == NULL) return false; |
945 |
944 |
946 f1 = fopen(n1, "rb"); |
945 f1 = fopen(n1, "rb"); |
947 if (f1 == NULL) Fatal("can't open %s", n1); |
946 if (f1 == NULL) fatal("can't open %s", n1); |
948 |
947 |
949 do { |
948 do { |
950 l1 = fread(b1, 1, sizeof(b1), f1); |
949 l1 = fread(b1, 1, sizeof(b1), f1); |
951 l2 = fread(b2, 1, sizeof(b2), f2); |
950 l2 = fread(b2, 1, sizeof(b2), f2); |
952 |
951 |
1006 } else { |
1005 } else { |
1007 // else rename tmp.xxx into filename |
1006 // else rename tmp.xxx into filename |
1008 #if defined(WIN32) || defined(WIN64) |
1007 #if defined(WIN32) || defined(WIN64) |
1009 unlink(filename); |
1008 unlink(filename); |
1010 #endif |
1009 #endif |
1011 if (rename("tmp.xxx", filename) == -1) Fatal("rename() failed"); |
1010 if (rename("tmp.xxx", filename) == -1) fatal("rename() failed"); |
1012 } |
1011 } |
1013 } |
1012 } |
1014 |
1013 |
1015 static int TranslateArgumentIdx(int argidx) |
1014 static int TranslateArgumentIdx(int argidx) |
1016 { |
1015 { |
1017 int i, sum; |
1016 int i, sum; |
1018 |
1017 |
1019 if (argidx < 0 || argidx >= lengthof(_cur_pcs.cmd)) |
1018 if (argidx < 0 || argidx >= lengthof(_cur_pcs.cmd)) |
1020 Fatal("invalid argidx %d", argidx); |
1019 fatal("invalid argidx %d", argidx); |
1021 |
1020 |
1022 for (i = sum = 0; i < argidx; i++) { |
1021 for (i = sum = 0; i < argidx; i++) { |
1023 const CmdStruct *cs = _cur_pcs.cmd[i]; |
1022 const CmdStruct *cs = _cur_pcs.cmd[i]; |
1024 sum += (cs != NULL) ? cs->consumes : 1; |
1023 sum += (cs != NULL) ? cs->consumes : 1; |
1025 } |
1024 } |
1082 fputc(length, f); |
1081 fputc(length, f); |
1083 } else if (length < 0x4000) { |
1082 } else if (length < 0x4000) { |
1084 fputc((length >> 8) | 0xC0, f); |
1083 fputc((length >> 8) | 0xC0, f); |
1085 fputc(length & 0xFF, f); |
1084 fputc(length & 0xFF, f); |
1086 } else { |
1085 } else { |
1087 Fatal("string too long"); |
1086 fatal("string too long"); |
1088 } |
1087 } |
1089 } |
1088 } |
1090 |
1089 |
1091 |
1090 |
1092 static void WriteLangfile(const char *filename, int show_todo) |
1091 static void WriteLangfile(const char *filename, int show_todo) |
1096 LanguagePackHeader hdr; |
1095 LanguagePackHeader hdr; |
1097 uint i; |
1096 uint i; |
1098 uint j; |
1097 uint j; |
1099 |
1098 |
1100 f = fopen(filename, "wb"); |
1099 f = fopen(filename, "wb"); |
1101 if (f == NULL) Fatal("can't open %s", filename); |
1100 if (f == NULL) fatal("can't open %s", filename); |
1102 |
1101 |
1103 memset(&hdr, 0, sizeof(hdr)); |
1102 memset(&hdr, 0, sizeof(hdr)); |
1104 for (i = 0; i != 32; i++) { |
1103 for (i = 0; i != 32; i++) { |
1105 uint n = CountInUse(i); |
1104 uint n = CountInUse(i); |
1106 |
1105 |
1134 _cur_line = ls->line; |
1133 _cur_line = ls->line; |
1135 |
1134 |
1136 // Produce a message if a string doesn't have a translation. |
1135 // Produce a message if a string doesn't have a translation. |
1137 if (show_todo > 0 && ls->translated == NULL) { |
1136 if (show_todo > 0 && ls->translated == NULL) { |
1138 if (show_todo == 2) { |
1137 if (show_todo == 2) { |
1139 Warning("'%s' is untranslated", ls->name); |
1138 warning("'%s' is untranslated", ls->name); |
1140 } else { |
1139 } else { |
1141 const char *s = "<TODO> "; |
1140 const char *s = "<TODO> "; |
1142 while (*s != '\0') PutByte(*s++); |
1141 while (*s != '\0') PutByte(*s++); |
1143 } |
1142 } |
1144 } |
1143 } |