strgen/strgen.c
changeset 4370 5beb8896ae3d
parent 4344 7e123fec5b0b
child 4371 28ce2bc97a5f
equal deleted inserted replaced
4369:3812b4335df9 4370:5beb8896ae3d
     1 /* $Id$ */
     1 /* $Id$ */
     2 
     2 
     3 #define STRGEN
     3 #if defined(WIN32) || defined(WIN64) || defined(__CYGWIN__)
       
     4 #define WIN32
       
     5 #else
       
     6 #define UNIX
       
     7 #endif
     4 
     8 
     5 #include "../stdafx.h"
     9 #include "../stdafx.h"
     6 #include "../macros.h"
    10 #include "../macros.h"
       
    11 #include "../string.h"
     7 #include <stdio.h>
    12 #include <stdio.h>
     8 #include <string.h>
    13 #include <string.h>
     9 #include <stdlib.h>
    14 #include <stdlib.h>
    10 #include <stdarg.h>
    15 #include <stdarg.h>
    11 
    16 
    12 #if (!defined(WIN32) && !defined(WIN64)) || defined(__CYGWIN__)
    17 #if (!defined(WIN32) && !defined(WIN64)) || defined(__CYGWIN__)
    13 #include <unistd.h>
    18 #include <unistd.h>
    14 #endif
    19 #endif
       
    20 
       
    21 #if defined WIN32 || defined __WATCOMC__
       
    22 #include <direct.h>
       
    23 #endif /* WIN32 || __WATCOMC__ */
    15 
    24 
    16 #ifdef __MORPHOS__
    25 #ifdef __MORPHOS__
    17 #ifdef stderr
    26 #ifdef stderr
    18 #undef stderr
    27 #undef stderr
    19 #endif
    28 #endif
    20 #define stderr stdout
    29 #define stderr stdout
    21 #endif // __MORPHOS__
    30 #endif /* __MORPHOS__ */
    22 
    31 
    23 #ifdef __WATCOMC__
    32 #ifdef __WATCOMC__
    24 	uint _map_log_x;     // an unpleasant hack required because Watcom is insisting on
    33 	uint _map_log_x;     // an unpleasant hack required because Watcom is insisting on
    25 	uint _map_size_x;    // these variables being valid references in map.h
    34 	uint _map_size_x;    // these variables being valid references in map.h
    26 	uint _map_size_y;
    35 	uint _map_size_y;
    27 	uint _map_tile_mask;
    36 	uint _map_tile_mask;
    28 	uint _map_size;
    37 	uint _map_size;
    29 #endif
    38 #endif /* __WATCOMC__ */
    30 
    39 
    31 /* Compiles a list of strings into a compiled string list */
    40 /* Compiles a list of strings into a compiled string list */
    32 
    41 
    33 typedef void (*ParseCmdProc)(char *buf, int value);
    42 typedef void (*ParseCmdProc)(char *buf, int value);
    34 
    43 
   158 static void CDECL Warning(const char *s, ...)
   167 static void CDECL Warning(const char *s, ...)
   159 {
   168 {
   160 	char buf[1024];
   169 	char buf[1024];
   161 	va_list va;
   170 	va_list va;
   162 	va_start(va, s);
   171 	va_start(va, s);
   163 	vsprintf(buf, s, va);
   172 	vsnprintf(buf, lengthof(buf), s, va);
   164 	va_end(va);
   173 	va_end(va);
   165 	fprintf(stderr, "%s" LINE_NUM_FMT ": Warning: %s\n", _file, _cur_line, buf);
   174 	fprintf(stderr, "%s" LINE_NUM_FMT ": Warning: %s\n", _file, _cur_line, buf);
   166 	_warnings++;
   175 	_warnings++;
   167 }
   176 }
   168 
   177 
   170 static void CDECL Error(const char *s, ...)
   179 static void CDECL Error(const char *s, ...)
   171 {
   180 {
   172 	char buf[1024];
   181 	char buf[1024];
   173 	va_list va;
   182 	va_list va;
   174 	va_start(va, s);
   183 	va_start(va, s);
   175 	vsprintf(buf, s, va);
   184 	vsnprintf(buf, lengthof(buf), s, va);
   176 	va_end(va);
   185 	va_end(va);
   177 	fprintf(stderr, "%s" LINE_NUM_FMT ": Error: %s\n", _file, _cur_line, buf);
   186 	fprintf(stderr, "%s" LINE_NUM_FMT ": Error: %s\n", _file, _cur_line, buf);
   178 	_errors++;
   187 	_errors++;
   179 }
   188 }
   180 
   189 
   182 static void NORETURN CDECL Fatal(const char *s, ...)
   191 static void NORETURN CDECL Fatal(const char *s, ...)
   183 {
   192 {
   184 	char buf[1024];
   193 	char buf[1024];
   185 	va_list va;
   194 	va_list va;
   186 	va_start(va, s);
   195 	va_start(va, s);
   187 	vsprintf(buf, s, va);
   196 	vsnprintf(buf, lengthof(buf), s, va);
   188 	va_end(va);
   197 	va_end(va);
   189 	fprintf(stderr, "%s" LINE_NUM_FMT ": FATAL: %s\n", _file, _cur_line, buf);
   198 	fprintf(stderr, "%s" LINE_NUM_FMT ": FATAL: %s\n", _file, _cur_line, buf);
   190 	exit(1);
   199 	exit(1);
   191 }
   200 }
   192 
       
   193 
       
   194 static void ttd_strlcpy(char *dst, const char *src, size_t len)
       
   195 {
       
   196 	assert(len > 0);
       
   197 	while (--len > 0 && *src != '\0') *dst++ = *src++;
       
   198 	*dst = '\0';
       
   199 }
       
   200 
       
   201 
   201 
   202 static void PutByte(byte c)
   202 static void PutByte(byte c)
   203 {
   203 {
   204 	if (_put_pos == lengthof(_put_buf)) Fatal("Put buffer too small");
   204 	if (_put_pos == lengthof(_put_buf)) Fatal("Put buffer too small");
   205 	_put_buf[_put_pos++] = c;
   205 	_put_buf[_put_pos++] = c;
  1203 
  1203 
  1204 	fputc(0, f);
  1204 	fputc(0, f);
  1205 	fclose(f);
  1205 	fclose(f);
  1206 }
  1206 }
  1207 
  1207 
       
  1208 /** Multi-OS mkdirectory function */
       
  1209 static inline void ottd_mkdir(const char *directory)
       
  1210 {
       
  1211 #if defined(WIN32) || defined(__WATCOMC__)
       
  1212 		mkdir(directory);
       
  1213 #else
       
  1214 		mkdir(directory, 0755);
       
  1215 #endif
       
  1216 }
       
  1217 
       
  1218 /** Create a path consisting of an already existing path, a possible
       
  1219  * path seperator and the filename. The seperator is only appended if the path
       
  1220  * does not already end with a seperator */
       
  1221 static inline char *mkpath(char *buf, size_t buflen, const char *path, const char *file)
       
  1222 {
       
  1223 	char *p;
       
  1224 	ttd_strlcpy(buf, path, buflen); // copy directory into buffer
       
  1225 
       
  1226 	p = strchr(buf, '\0'); // add path seperator if necessary
       
  1227 	if (p[-1] != PATHSEPCHAR && (size_t)(p - buf) + 1 < buflen) *p++ = PATHSEPCHAR;
       
  1228 	ttd_strlcpy(p, file, buflen - (size_t)(p - buf)); // catenate filename at end of buffer
       
  1229 	return buf;
       
  1230 }
       
  1231 
  1208 
  1232 
  1209 int CDECL main(int argc, char* argv[])
  1233 int CDECL main(int argc, char* argv[])
  1210 {
  1234 {
       
  1235 	char pathbuf[256];
       
  1236 	const char *src_dir, *dest_dir;
       
  1237 
  1211 	int show_todo = 0;
  1238 	int show_todo = 0;
  1212 
  1239 
  1213 	if (argc > 1 && (strcmp(argv[1], "-v") == 0 || strcmp(argv[1], "--version") == 0)) {
  1240 	if (argc > 1 && (strcmp(argv[1], "-v") == 0 || strcmp(argv[1], "--version") == 0)) {
  1214 		puts("$Revision$");
  1241 		puts("$Revision$");
  1215 		return 0;
  1242 		return 0;
  1216 	}
  1243 	}
  1217 
  1244 
  1218 	if (argc > 1 &&
  1245 	if (argc > 1 && (strcmp(argv[1], "-t") == 0 || strcmp(argv[1], "--todo") == 0)) {
  1219 			(strcmp(argv[1], "-t") == 0 || strcmp(argv[1], "--todo") == 0)) {
       
  1220 		show_todo = 1;
  1246 		show_todo = 1;
  1221 		argc--, argv++;
  1247 		argc--, argv++;
  1222 	}
  1248 	}
  1223 
  1249 
  1224 	if (argc > 1 &&
  1250 	if (argc > 1 && (strcmp(argv[1], "-w") == 0 || strcmp(argv[1], "--warning") == 0)) {
  1225 			(strcmp(argv[1], "-w") == 0 || strcmp(argv[1], "--warning") == 0)) {
       
  1226 		show_todo = 2;
  1251 		show_todo = 2;
  1227 		argc--, argv++;
  1252 		argc--, argv++;
  1228 	}
  1253 	}
  1229 
  1254 
  1230 	if (argc > 1 && (
  1255 	if (argc > 1 && (
  1233 				strcmp(argv[1], "-?") == 0
  1258 				strcmp(argv[1], "-?") == 0
  1234 			)) {
  1259 			)) {
  1235 		puts(
  1260 		puts(
  1236 			"strgen - $Revision$\n"
  1261 			"strgen - $Revision$\n"
  1237 			" -v | --version    print version information and exit\n"
  1262 			" -v | --version    print version information and exit\n"
  1238 			" -h | -? | --help  print this help message and exit\n"
       
  1239 			" -t | --todo       replace any untranslated strings with '<TODO>'\n"
  1263 			" -t | --todo       replace any untranslated strings with '<TODO>'\n"
  1240 			" -w | --warning    print a warning for any untranslated strings\n"
  1264 			" -w | --warning    print a warning for any untranslated strings\n"
  1241 			" Run without parameters strgen will search for lang/english.txt and\n"
  1265 			" -h | -? | --help  print this help message and exit\n"
  1242 			" parse it. Passing an argument, strgen will translate that language\n"
  1266 			" -s | --source_dir search for english.txt in the specified directory\n"
  1243 			" file with lang/english.txt as a reference."
  1267 			" -d | --dest_dir   put output file in the specified directory, create if needed\n"
       
  1268 			" Run without parameters and strgen will search for english.txt and parse it,\n"
       
  1269 			" creating strings.h. Passing an argument, strgen will translate that language\n"
       
  1270 			" file using english.txt as a reference and output <language>.lng."
  1244 		);
  1271 		);
  1245 		return 0;
  1272 		return 0;
  1246 	}
  1273 	}
  1247 
  1274 
       
  1275 	src_dir = dest_dir = ".";
       
  1276 	if (argc > 2 && (strcmp(argv[1], "-s") == 0 || strcmp(argv[1], "--source_dir") == 0)) {
       
  1277 		src_dir = dest_dir = argv[2]; // if dest_dir is not specified, it equals src_dir
       
  1278 		argc -= 2, argv += 2;
       
  1279 	}
       
  1280 
       
  1281 	if (argc > 2 && (strcmp(argv[1], "-d") == 0 || strcmp(argv[1], "--dest_dir") == 0)) {
       
  1282 		dest_dir = argv[2];
       
  1283 		argc -= 2, argv += 2;
       
  1284 	}
       
  1285 
       
  1286 	/* strgen has two modes of operation. If no (free) arguments are passed
       
  1287 	 * strgen generates strings.h to the destination directory. If it is supplied
       
  1288 	 * with a (free) parameter the program will translate that language to destination
       
  1289 	 * directory. As input english.txt is parsed from the source directory */
  1248 	if (argc == 1) {
  1290 	if (argc == 1) {
       
  1291 		mkpath(pathbuf, lengthof(pathbuf), src_dir, "english.txt");
       
  1292 
       
  1293 		/* parse master file */
  1249 		_masterlang = true;
  1294 		_masterlang = true;
  1250 		// parse master file
  1295 		ParseFile(pathbuf, true);
  1251 		ParseFile("lang/english.txt", true);
       
  1252 		MakeHashOfStrings();
  1296 		MakeHashOfStrings();
  1253 		if (_errors) return 1;
  1297 		if (_errors) return 1;
  1254 
  1298 
  1255 		// write english.lng and strings.h
  1299 		/* write strings.h */
  1256 
  1300 		ottd_mkdir(dest_dir);
  1257 		WriteLangfile("lang/english.lng", 0);
  1301 		mkpath(pathbuf, lengthof(pathbuf), dest_dir, "strings.h");
  1258 		WriteStringsH("table/strings.h");
  1302 		WriteStringsH(pathbuf);
  1259 	} else if (argc == 2) {
  1303 	} else if (argc == 2) {
  1260 		char buf[256];
  1304 		char *r;
  1261 		char* r;
  1305 
  1262 
  1306 		mkpath(pathbuf, lengthof(pathbuf), src_dir, "english.txt");
       
  1307 
       
  1308 		/* parse master file and check if target file is correct */
  1263 		_masterlang = false;
  1309 		_masterlang = false;
  1264 		ParseFile("lang/english.txt", true);
  1310 		ParseFile(pathbuf, true);
  1265 		MakeHashOfStrings();
  1311 		MakeHashOfStrings();
  1266 		ParseFile(argv[1], false);
  1312 		ParseFile(argv[1], false); // target file
  1267 
       
  1268 		if (_errors) return 1;
  1313 		if (_errors) return 1;
  1269 
  1314 
  1270 		strcpy(buf, argv[1]);
  1315 		/* get the targetfile, strip any directories and append to destination path */
  1271 		r = strrchr(buf, '.');
  1316 		r = strrchr(argv[1], PATHSEPCHAR);
  1272 		if (r == NULL || strcmp(r, ".txt") != 0) r = strchr(buf, 0);
  1317 		mkpath(pathbuf, lengthof(pathbuf), dest_dir, (r != NULL) ? &r[1] : argv[1]);
  1273 		strcpy(r, ".lng");
  1318 
  1274 		WriteLangfile(buf, show_todo);
  1319 		/* rename the .txt (input-extension) to .lng */
       
  1320 		r = strrchr(pathbuf, '.');
       
  1321 		if (r == NULL || strcmp(r, ".txt") != 0) r = strchr(pathbuf, '\0');
       
  1322 		ttd_strlcpy(r, ".lng", (size_t)(r - pathbuf));
       
  1323 		WriteLangfile(pathbuf, show_todo);
  1275 	} else {
  1324 	} else {
  1276 		fprintf(stderr, "invalid arguments\n");
  1325 		fprintf(stderr, "Invalid arguments\n");
  1277 	}
  1326 	}
  1278 
  1327 
  1279 	return 0;
  1328 	return 0;
  1280 }
  1329 }