_________ __                 __
        /   _____//  |_____________ _/  |______     ____  __ __  ______
        \_____  \\   __\_  __ \__  \\   __\__  \   / ___\|  |  \/  ___/
        /        \|  |  |  | \// __ \|  |  / __ \_/ /_/  >  |  /\___ \
       /_______  /|__|  |__|  (____  /__| (____  /\___  /|____//____  >
               \/                  \/          \//_____/            \/
    ______________________                           ______________________
                          T H E   W A R   B E G I N S
                   Stratagus - A free fantasy real time strategy game engine

stratagus-game-launcher.h
Go to the documentation of this file.
1 /*
2  _________ __ __
3  / _____// |_____________ _/ |______ ____ __ __ ______
4  \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
5  / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
6  /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
7  \/ \/ \//_____/ \/
8  ______________________ ______________________
9  T H E W A R B E G I N S
10  Stratagus - A free fantasy real time strategy game engine
11 
12 stratagus-game-launcher.h - Stratagus Game Launcher
13  Copyright (C) 2010-2011 Pali Rohár <[email protected]>
14 
15  This program is free software: you can redistribute it and/or modify
16  it under the terms of the GNU General Public License as published by
17  the Free Software Foundation, either version 2 of the License, or
18  (at your option) any later version.
19 
20  This program is distributed in the hope that it will be useful,
21  but WITHOUT ANY WARRANTY; without even the implied warranty of
22  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23  GNU General Public License for more details.
24 
25  You should have received a copy of the GNU General Public License
26  along with this program. If not, see <http://www.gnu.org/licenses/>.
27 */
28 
131 #ifndef STRATAGUS_GAME_LAUNCHER_H
132 #define STRATAGUS_GAME_LAUNCHER_H
133 
134 /* Fake definitions for Doxygen */
135 #include <sys/types.h>
136 #ifdef DOXYGEN
137 #define GAME_NAME
138 #define GAME_CD
139 #define GAME
140 #define DATA_PATH
141 #define SCRIPTS_PATH
142 #define STRATAGUS_BIN
143 #endif
144 
145 #if ! defined (GAME_NAME) || ! defined (GAME_CD) || ! defined (GAME) || ! defined(EXTRACTOR_TOOL)
146 #error You need to define all Game macros, see stratagus-game-launcher.h
147 #endif
148 
149 #ifndef GAME_SHOULD_EXTRACT_AGAIN
150 #define GAME_SHOULD_EXTRACT_AGAIN false
151 #endif
152 
157 #ifndef TITLE_PNG
158 #ifdef WIN32
159 #define TITLE_PNG "%s\\graphics\\ui\\title.png"
160 #else
161 #define TITLE_PNG "%s/graphics/ui/title.png"
162 #endif
163 #endif
164 
165 #ifndef WIN32
166 #if ! defined (DATA_PATH) || ! defined (SCRIPTS_PATH) || ! defined (STRATAGUS_BIN)
167 #error You need to define paths, see stratagus-game-launcher.h
168 #endif
169 #pragma GCC diagnostic ignored "-Wwrite-strings"
170 #endif
171 
172 #ifdef _MSC_VER
173 #pragma comment(linker, "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")
174 #endif
175 
176 #ifdef _WIN64
177 #define REGKEY "Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Stratagus (64 bit)"
178 #elif defined (WIN32)
179 #define REGKEY "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Stratagus"
180 #endif
181 
182 #define TITLE GAME_NAME
183 #define EXTRACTOR_NOT_FOUND GAME_NAME " could not find its extraction tool.\n" EXTRACTOR_TOOL "!\n"
184 #define STRATAGUS_NOT_FOUND "Stratagus is not installed.\nYou need Stratagus to run " GAME_NAME "!\n"
185 #define DATA_NOT_EXTRACTED GAME_NAME " data was not extracted, is corrupted, or outdated.\nYou need to extract it from original " GAME_CD "."
186 
187 #include "stratagus-gameutils.h"
188 
189 static void SetUserDataPath(char* data_path) {
190 #if defined(WIN32)
191  char marker[MAX_PATH] = {'\0'};
192  if (PathCombine(marker, data_path, "portable-install")) {
193  if (PathFileExists(marker)) {
194  return;
195  }
196  }
197  SHGetFolderPathA(NULL, CSIDL_PERSONAL|CSIDL_FLAG_CREATE, NULL, 0, data_path);
198  // strcpy(data_path, getenv("APPDATA"));
199 #else
200  strcpy(data_path, getenv("HOME"));
201 #endif
202  int datalen = strlen(data_path);
203 #if defined(WIN32)
204  strcat(data_path, "\\Stratagus\\");
205 #elif defined(USE_MAC)
206  strcat(data_path, "/Library/Stratagus/");
207 #else
208  strcat(data_path, "/.stratagus/");
209 #endif
210  strcat(data_path, "data." GAME_NAME);
211 }
212 
213 int check_version(char* tool_path, char* data_path) {
214  char buf[4096] = {'\0'};
215  sprintf(buf, "%s/extracted" , data_path);
216  FILE *f = fopen(buf, "r");
217  char dataversion[20] = {'\0'};
218  char toolversion[20] = {'\0'};
219  if (f) {
220  fgets(dataversion, 20, f);
221  fclose(f);
222  } else {
223 #ifdef CHECK_EXTRACTED_VERSION
224  return 0; // No file means we have a problem
225 #else
226  return 1; // No file means we don't care
227 #endif
228  }
229 #ifndef WIN32
230  sprintf(buf, "%s -V", tool_path);
231  FILE *pipe = popen(buf, "r");
232  if (f) {
233  fgets(toolversion, 20, pipe);
234  pclose(pipe);
235  }
236 #else
237  sprintf(buf, "%s -V", tool_path); // tool_path is already quoted
238  HANDLE g_hChildStd_OUT_Rd = NULL;
239  HANDLE g_hChildStd_OUT_Wr = NULL;
240  DWORD nbByteRead;
241  SECURITY_ATTRIBUTES saAttr;
242  saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
243  saAttr.bInheritHandle = TRUE;
244  saAttr.lpSecurityDescriptor = NULL;
245  if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0))
246  return 1;
247  if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
248  return 1;
249  PROCESS_INFORMATION piProcInfo;
250  STARTUPINFO siStartInfo;
251  ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
252  ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
253  siStartInfo.cb = sizeof(STARTUPINFO);
254  siStartInfo.hStdError = g_hChildStd_OUT_Wr;
255  siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
256  siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
257  if (!CreateProcess(NULL, buf, NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &piProcInfo))
258  return 1;
259  CloseHandle(piProcInfo.hProcess);
260  CloseHandle(piProcInfo.hThread);
261  ReadFile(g_hChildStd_OUT_Rd, toolversion, 20, &nbByteRead, NULL);
262 #endif
263  // strip whitespace
264  for (size_t i=0, j=0; toolversion[j]=toolversion[i]; j+=!isspace(toolversion[i++]));
265  for (size_t i=0, j=0; dataversion[j]=dataversion[i]; j+=!isspace(dataversion[i++]));
266  if (strcmp(dataversion, toolversion) == 0) {
267  return 1;
268  }
269  return 0;
270 }
271 
272 static void ExtractData(char* extractor_tool, char *const extractor_args[], char* destination, char* scripts_path, int force=0, char* datafileCstr=NULL) {
273  int canJustReextract;
274 #ifdef EXTRACTION_FILES
275  if (force == 0) {
276  canJustReextract = 1;
277  char* extraction_files[] = { EXTRACTION_FILES, NULL };
278  char* efile = extraction_files[0];
279  for (int i = 0; efile != NULL; i++) {
280  fs::path efile_path = fs::path(destination) / efile;
281  if (!fs::exists(efile_path)) {
282  // file to extract not found
283  canJustReextract = 0;
284  }
285  efile = extraction_files[i + 1];
286  }
287  } else {
288  canJustReextract = 0;
289  }
290 #else
291  canJustReextract = 0;
292 #endif
293  if (canJustReextract) {
294  tinyfd_messageBox("", GAME " game data format changed, we can migrate in-place. Please be patient.", "ok", "info", 1);
295  } else if (force == 0) {
296  tinyfd_messageBox("Missing data",
297  DATA_NOT_EXTRACTED " Please select the " GAME_CD, "ok", "question", 1);
298  } else if (force == 1) {
299  tinyfd_messageBox("", "Please select the " GAME_CD, "ok", "question", 1);
300  } else if (force == 2) {
301  // pass
302  }
303 #ifdef USE_MAC
304  int patterncount = 0;
305  char* filepatterns[] = { NULL };
306  // file types as names not working at least on macOS sierra
307 #else
308  char* filepatterns[] = { GAME_CD_FILE_PATTERNS, NULL };
309  int patterncount = 0;
310  while (filepatterns[patterncount++] != NULL);
311 #endif
312  fs::path srcfolder;
313  if (!canJustReextract || datafileCstr != NULL) {
314  if (datafileCstr == NULL) {
315  datafileCstr = tinyfd_openFileDialog(GAME_CD " location", "",
316  patterncount - 1, filepatterns, NULL, 0);
317  }
318  if (datafileCstr == NULL) {
319  exit(-1);
320  }
321  std::string datafile = datafileCstr;
322  if (datafile.compare(datafile.length() - 4, 4, ".exe") == 0) {
323  // test if this is an innoextract installer and if so, extract it to a tempdir and pass that
324 #ifdef WIN32
325  char moduleFileName[BUFF_SIZE];
326  memset(moduleFileName, 0, sizeof(moduleFileName));
327  GetModuleFileName(NULL, moduleFileName, sizeof(moduleFileName)-1);
328  fs::path innoextractPath = fs::path(moduleFileName).parent_path() / "innoextract.exe";
329  std::wstring file = innoextractPath.wstring();
330  std::vector<std::wstring> argv = {L"-i", fs::path(datafile).wstring()};
331 #else
332  const char *file = "innoextract";
333  char *argv[] = {"-i", (char*)datafile.c_str(), NULL};
334 #endif
335  if (runCommand(file, argv) == 0) {
336  // innoextract exists and this exe file is an innosetup file
337  bool success = false;
338  fs::path tmpp = fs::temp_directory_path() / GAME;
339  fs::create_directories(tmpp);
340 #ifdef WIN32
341  wchar_t *curdir = _wgetcwd(NULL, 0);
342 #else
343  char *curdir = getcwd(NULL, 0);
344 #endif
345  if (curdir != NULL) {
346 #ifdef WIN32
347  if (_wchdir(tmpp.wstring().c_str()) == 0) {
348 #else
349  if (chdir(tmpp.string().c_str()) == 0) {
350 #endif
351 #ifdef WIN32
352  argv[0] = L"-m";
353 #else
354  argv[0] = "-m";
355 #endif
356  success = runCommand(file, argv) == 0;
357 #ifdef WIN32
358  _wchdir(curdir);
359 #else
360  chdir(curdir);
361 #endif
362  }
363  free(curdir);
364  }
365  if (!success) {
366  error("Problem with installer",
367  "You selected an innosetup installer, and we could not extract it. "
368  "Please extract it manually and point the extraction tool there.");
369  } else {
370  srcfolder = tmpp;
371  }
372  } else {
373  // we cannot test if this is an innoextract installer, assume not but maybe warn
374  if (datafile.compare("INSTALL.EXE") == 0 ||
375  datafile.compare("install.exe") == 0 ||
376  datafile.compare("INSTALL.exe") == 0 ||
377  datafile.compare("SETUP.EXE") == 0 ||
378  datafile.compare("setup.exe") == 0 ||
379  datafile.compare("SETUP.exe") == 0) {
380  // probably not a packaged installer
381  } else {
382  // warn
383  tinyfd_messageBox("", "You selected an exe file, but I cannot run innoextract "
384  "to check if its a single-file installer. If it is, please extract/install "
385  "manually first and then run " GAME " again.", "ok", "question", 1);
386  }
387  srcfolder = fs::path(datafile).parent_path();
388  }
389  } else {
390  srcfolder = fs::path(datafile).parent_path();
391  }
392  } else {
393  srcfolder = fs::path(destination);
394  }
395 
396 #ifdef WIN32
397  char* sourcepath = _strdup(scripts_path);
398  if (sourcepath[0] == '"') {
399  // if scripts_path is quoted, remove the quotes, i.e.,
400  // copy all but the first until all but the last char.
401  // sourcepath is already large enough because it used to contain the
402  // entire scripts_path
403  strncpy(sourcepath, scripts_path + 1, strlen(scripts_path) - 2);
404  sourcepath[strlen(scripts_path) - 2] = '\0';
405  }
406 #else
407  char* sourcepath = strdup(scripts_path);
408 #endif
409 
410  fs::create_directories(fs::path(destination));
411 
412  if (!fs::exists(sourcepath)) {
413  // deployment time path not found, try compile time path
414  strcpy(sourcepath, fs::path(SRC_PATH()).parent_path().string().c_str());
415  }
416 
417 #ifndef WIN32
418  if (!fs::exists(sourcepath)) {
419  // deployment time path might be same as extractor
420  strcpy(sourcepath, fs::path(extractor_tool).parent_path().string().c_str());
421  }
422 #endif
423 
424  if (!fs::exists(sourcepath)) {
425  // scripts not found, abort!
426  std::string msg("There was an error copying the data, could not discover scripts path: ");
427  msg += sourcepath;
428  tinyfd_messageBox("Error", msg.c_str(), "ok", "error", 1);
429  return;
430  }
431 
432  if (force != 2) {
433  fs::path contrib_src_path;
434  fs::path contrib_dest_path(destination);
435  int i = 0;
436  int optional = 0;
437  char* contrib_directories[] = CONTRIB_DIRECTORIES;
438  while (contrib_directories[i] != NULL && contrib_directories[i + 1] != NULL) {
439  if (!strcmp(contrib_directories[i], ":optional:")) {
440  i += 1;
441  optional = 1;
442  } else {
443  if (contrib_directories[i][0] != '/') {
444  // absolute Unix paths are not appended to the source path
445  contrib_src_path = fs::path(sourcepath);
446  contrib_src_path /= contrib_directories[i];
447  } else {
448  contrib_src_path = fs::path(contrib_directories[i]);
449  }
450 
451  if (!fs::exists(contrib_src_path)) {
452  // contrib dir not found, abort!
453  if (!optional) {
454  std::string msg("There was an error copying the data, could not discover contributed directory path: ");
455  msg += contrib_src_path.string();
456  error("Error", msg.c_str());
457  return;
458  }
459  } else {
460  copy_dir(contrib_src_path, contrib_dest_path / contrib_directories[i + 1]);
461  }
462  i += 2;
463  }
464  }
465  }
466 
467  int exitcode = 0;
468 
469  char cmdbuf[4096] = {'\0'};
470 #ifdef WIN32
471  std::wstring file;
472  std::vector<std::wstring> args;
473 
474  file = fs::path(extractor_tool).wstring();
475  for (int i = 0; ; i++) {
476  const char *earg = extractor_args[i];
477  if (earg == NULL) {
478  break;
479  } else {
480  const size_t WCHARBUF = 100;
481  wchar_t wszDest[WCHARBUF];
482  MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, earg, -1, wszDest, WCHARBUF);
483  args.push_back(wszDest);
484  }
485  }
486  args.push_back(srcfolder.wstring());
487  args.push_back(fs::path(destination).wstring());
488  std::wstring combinedCommandline;
489  exitcode = runCommand(file, args, true, &combinedCommandline);
490 #else
491 
492 #ifdef USE_MAC
493  strcat(cmdbuf, "osascript -e \"tell application \\\"Terminal\\\"\n"
494  " set w to do script \\\"");
495 #else
496  if (!isatty(1)) {
497  strcat(cmdbuf, "xterm -e bash -c ");
498  strcat(cmdbuf, " \"");
499  }
500 #endif
501 
502  strcat(cmdbuf, extractor_tool);
503  for (int i = 0; ; i++) {
504  const char *earg = extractor_args[i];
505  if (earg == NULL) {
506  break;
507  } else {
508  strcat(cmdbuf, " ");
509  strcat(cmdbuf, earg);
510  }
511  }
512  strcat(cmdbuf, " " QUOTE);
513  strcat(cmdbuf, srcfolder.string().c_str());
514  strcat(cmdbuf, QUOTE " " QUOTE);
515  strcat(cmdbuf, destination);
516  strcat(cmdbuf, QUOTE);
517 
518 #ifdef USE_MAC
519  strcat(cmdbuf, "; exit\\\"\n"
520  " repeat\n"
521  " delay 1\n"
522  " if not busy of w then exit repeat\n"
523  " end repeat\n"
524  "end tell\"");
525 #else
526  if (!isatty(1)) {
527  strcat(cmdbuf, "; echo 'Press RETURN to continue...'; read\"");
528  }
529 #endif
530 
531  printf("Running extractor as %s\n", cmdbuf);
532  exitcode = system(cmdbuf);
533 #endif
534 
535  if (exitcode != 0) {
536 #ifdef WIN32
537  WideCharToMultiByte(CP_ACP, 0, combinedCommandline.c_str(), combinedCommandline.size(), cmdbuf, sizeof(cmdbuf) - 1, NULL, NULL);
538 #endif
539  char* extractortext = (char*)calloc(sizeof(char), strlen(cmdbuf) + 1024);
540  sprintf(extractortext, "The following command was used to extract the data (you can run it manually in a console to find out more):\n%s", cmdbuf);
541  tinyfd_messageBox("Extraction failed!", extractortext, "ok", "error", 1);
542  } else if (!canJustReextract && GAME_SHOULD_EXTRACT_AGAIN) {
543  ExtractData(extractor_tool, extractor_args, destination, scripts_path, 2);
544  }
545 }
546 
547 int main(int argc, char * argv[]) {
548  struct stat st;
549  int argccpy = argc;
550  char data_path[BUFF_SIZE];
551  char scripts_path[BUFF_SIZE];
552  char stratagus_bin[BUFF_SIZE];
553  char title_path[BUFF_SIZE];
554  char extractor_path[BUFF_SIZE] = {'\0'};
555 
556  // Try the extractor from the same dir as we are
557  if (strchr(argv[0], SLASH[0])) {
558  strcpy(extractor_path, argv[0]);
559  parentdir(extractor_path);
560  strcat(extractor_path, SLASH EXTRACTOR_TOOL);
561 #ifdef WIN32
562  if (!strstr(extractor_path, ".exe")) {
563  strcat(extractor_path, ".exe");
564  }
565 #endif
566  if (stat(extractor_path, &st) == 0) {
567 #ifndef WIN32
568  // Once we have the path, we quote it by moving the memory one byte to the
569  // right, and surrounding it with the quote character and finishing null
570  // bytes. Then we add the arguments.
571  extractor_path[strlen(extractor_path) + 1] = '\0';
572  memmove(extractor_path + 1, extractor_path, strlen(extractor_path));
573  extractor_path[0] = QUOTE[0];
574  extractor_path[strlen(extractor_path) + 1] = '\0';
575  extractor_path[strlen(extractor_path)] = QUOTE[0];
576 #endif
577  } else {
578  extractor_path[0] = '\0';
579  }
580  }
581  if (extractor_path[0] == '\0') {
582  // Use extractor from PATH
583  strcpy(extractor_path, EXTRACTOR_TOOL);
584  if (!detectPresence(extractor_path)) {
585  char msg[BUFF_SIZE * 2] = {'\0'};;
586  strcpy(msg, EXTRACTOR_NOT_FOUND);
587  strcat(msg, " (expected at ");
588  strcat(msg, extractor_path);
589  strcat(msg, ")");
590  error(TITLE, msg);
591  }
592  }
593 
594 #ifdef WIN32
595  char executable_path[BUFF_SIZE];
596  memset(executable_path, 0, sizeof(executable_path));
597  GetModuleFileName(NULL, executable_path, sizeof(executable_path)-1);
598 
599  char executable_drive[_MAX_DRIVE];
600  char executable_dir[_MAX_DIR];
601  memset(executable_drive, 0, sizeof(executable_drive));
602  memset(executable_dir, 0, sizeof(executable_dir));
603  _splitpath(executable_path, executable_drive, executable_dir, NULL, NULL);
604 
605  size_t data_path_size = sizeof(data_path);
606  memset(data_path, 0, data_path_size);
607 
608  if (executable_path[0] && executable_drive[0] && executable_dir[0]) {
609  PathCombine(data_path, executable_drive, executable_dir);
610  } else {
611  _getcwd(data_path, data_path_size);
612  }
613  PathRemoveBackslash(data_path);
614  sprintf(scripts_path, "\"%s\"", data_path);
615 
616  char stratagus_path[BUFF_SIZE];
617 
618  // Try to use stratagus.exe from data (install) directory first
619  sprintf(stratagus_bin, "%s\\stratagus.exe", data_path);
620  if (stat(stratagus_bin, &st) != 0) {
621  // If no local stratagus.exe is present, search PATH
622  if (!SearchPath(NULL, "stratagus", ".exe", MAX_PATH, stratagus_bin, NULL) &&
623  !SearchPath(NULL, "stratagus-dbg", ".exe", MAX_PATH, stratagus_bin, NULL)) {
624  // If no local or PATH stratagus.exe is present, look for a globally installed version
625  DWORD stratagus_path_size = sizeof(stratagus_path);
626  memset(stratagus_path, 0, stratagus_path_size);
627  HKEY key;
628 
629  if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY, 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) {
630  if (RegQueryValueEx(key, "InstallLocation", NULL, NULL, (LPBYTE)stratagus_path, &stratagus_path_size) == ERROR_SUCCESS) {
631  if (stratagus_path_size == 0 || strlen(stratagus_path) == 0) {
632  char msg[BUFF_SIZE * 2] = {'\0'};
633  strcat(msg, STRATAGUS_NOT_FOUND);
634  strcat(msg, " (expected globally installed or in ");
635  strcat(msg, stratagus_bin);
636  strcat(msg, ")");
637  error(TITLE, msg);
638  }
639  }
640  RegCloseKey(key);
641  }
642 
643  if (_chdir(stratagus_path) != 0) {
644  char msg[BUFF_SIZE * 2] = {'\0'};
645  strcat(msg, STRATAGUS_NOT_FOUND);
646  strcat(msg, " (registry key found, but directory ");
647  strcat(msg, stratagus_path);
648  strcat(msg, " cannot be opened)");
649  error(TITLE, msg);
650  }
651  sprintf(stratagus_bin, "%s\\stratagus.exe", stratagus_path);
652  }
653  }
654 
655 #ifdef DATA_PATH
656  // usually this isn't defined for windows builds. if it is, use it
657  strcpy(data_path, DATA_PATH);
658 #endif
659 #else
660  strcpy(data_path, DATA_PATH);
661  strcpy(scripts_path, SCRIPTS_PATH);
662  strcpy(stratagus_bin, STRATAGUS_BIN);
663 #endif
664 
665  char *const extractor_args[] = EXTRACTOR_ARGS;
666 
667  if (argc == 2) {
668  if (stat(argv[1], &st) == 0) {
669  // extraction file given as argument and it is accessible => force extraction and exit
671  SetUserDataPath(data_path);
672  ExtractData(extractor_path, extractor_args, data_path, scripts_path, 2, argv[1]);
673  return 0;
674  } else if (!strcmp(argv[1], "--extract")) {
675  // Force extraction and exit
676  SetUserDataPath(data_path);
677  ExtractData(extractor_path, extractor_args, data_path, scripts_path, 1);
678  return 0;
679  } else if (!strcmp(argv[1], "--extract-no-gui")) {
680  // Force extraction without ui and exit
682  SetUserDataPath(data_path);
683  ExtractData(extractor_path, extractor_args, data_path, scripts_path, 1);
684  return 0;
685  } else if (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) {
686  printf("Usage: %s [path to extraction file|--extract|--extract-no-gui]\n"
687  "\tpath to extraction file - will be used as file to start the extraction process on\n"
688  "\t--extract - force extraction even if data is already extracted\n"
689  "\t--extract-no-gui - force extraction even if data is already extracted, using the console only for prompts\n\n",
690  argv[0]);
691  }
692  }
693 
694  if ( stat(stratagus_bin, &st) != 0 ) {
695 #ifdef WIN32
696  _fullpath(stratagus_bin, argv[0], BUFF_SIZE);
697  PathRemoveFileSpec(stratagus_bin);
698  strcat(extractor_path, "\\stratagus.exe");
699  if (stat(stratagus_bin, &st) != 0) {
700  char msg[BUFF_SIZE * 2] = {'\0'};
701  strcat(msg, STRATAGUS_NOT_FOUND);
702  strcat(msg, " (expected in ");
703  strcat(msg, stratagus_bin);
704  strcat(msg, ")");
705  error(TITLE, msg);
706  }
707 #else
708  if (!detectPresence(stratagus_bin)) {
709  realpath(argv[0], stratagus_bin);
710  parentdir(stratagus_bin);
711  if (strlen(stratagus_bin) > 0) {
712  strcat(stratagus_bin, "/stratagus");
713  } else {
714  strcat(stratagus_bin, "./stratagus");
715  }
716  if ( stat(stratagus_bin, &st) != 0 ) {
717  char msg[BUFF_SIZE * 2] = {'\0'};
718  strcat(msg, STRATAGUS_NOT_FOUND);
719  strcat(msg, " (expected in ");
720  strcat(msg, stratagus_bin);
721  strcat(msg, ")");
722  error(TITLE, msg);
723  }
724  }
725 #endif
726  }
727 
728  sprintf(title_path, TITLE_PNG, data_path);
729  if ( stat(title_path, &st) != 0 ) {
730  SetUserDataPath(data_path);
731  sprintf(title_path, TITLE_PNG, data_path);
732  if ( stat(title_path, &st) != 0 ) {
733  ExtractData(extractor_path, extractor_args, data_path, scripts_path);
734  }
735  if ( stat(title_path, &st) != 0 ) {
736  std::string msg(DATA_NOT_EXTRACTED);
737  msg += " (extraction was attempted, but it seems an error occurred)";
738  error(TITLE, msg.c_str());
739  }
740  }
741 
742  if (!check_version(extractor_path, data_path)) {
743  ExtractData(extractor_path, extractor_args, data_path, scripts_path);
744  }
745 
746 #ifdef WIN32
747  int data_path_len = strlen(data_path);
748  _chdir(data_path);
749 
750  for (int i = data_path_len - 1; i >= 0; --i) {
751  data_path[i + 1] = data_path[i];
752  }
753  data_path[0] = '"';
754  data_path[data_path_len + 1] = '"';
755  data_path[data_path_len + 2] = 0;
756 #endif
757 
758 #ifdef _MSC_VER
759  char** stratagus_argv;
760  stratagus_argv = (char**) malloc((argc + 3) * sizeof (*stratagus_argv));
761 #else
762  char * stratagus_argv[argc + 3];
763 #endif
764 
765 #ifdef WIN32
766  char stratagus_argv0_esc[BUFF_SIZE];
767  memset(stratagus_argv0_esc, 0, sizeof(stratagus_argv0_esc));
768  strcpy(stratagus_argv0_esc + 1, argv[0]);
769  stratagus_argv0_esc[0] = '"';
770  stratagus_argv0_esc[strlen(argv[0]) + 1] = '"';
771  stratagus_argv0_esc[strlen(argv[0]) + 2] = 0;
772  stratagus_argv[0] = stratagus_argv0_esc;
773 #else
774  stratagus_argv[0] = argv[0];
775 #endif
776 
777  stratagus_argv[1] = "-d";
778  stratagus_argv[2] = data_path;
779 
780  for (int i = 3; i < argc + 2; ++i ) {
781  stratagus_argv[i] = argv[i - 2];
782  }
783  stratagus_argv[argc + 2] = NULL;
784 
785  // Needed to reduce CPU load while idle threads are wating for havn't finished yet ones
786  extern char** environ;
787  int i = 0;
788  while(environ[i]) { i++; }
789  environ[i] = (char*)"OMP_WAIT_POLICY=passive";
790  environ[i + 1] = NULL;
791 #ifdef WIN32
792  int ret = _spawnvpe(_P_WAIT, stratagus_bin, stratagus_argv, environ);
793 #else
794  int ret = 0;
795  int childpid = fork();
796  if (childpid == 0) {
797  execvp(stratagus_bin, stratagus_argv);
798  if (strcmp(stratagus_bin, "stratagus") == 0) {
799  realpath(argv[0], stratagus_bin);
800  parentdir(stratagus_bin);
801  strcat(stratagus_bin, "/stratagus");
802  }
803  execvp(stratagus_bin, stratagus_argv);
804  exit(ENOENT);
805  } else if (childpid > 0) {
806  waitpid(childpid, &ret, 0);
807  } else {
808  ret = ENOENT;
809  }
810 #endif
811  if (ret == ENOENT) {
812  char msg[BUFF_SIZE * 8];
813  strcpy(msg, "Execution failed for: ");
814  strcat(msg, stratagus_bin);
815  strcat(msg, " ");
816  for (int i = 1; stratagus_argv[i] != NULL; i++) {
817  if (strlen(msg) + strlen(stratagus_argv[i]) > BUFF_SIZE * 8) {
818  break;
819  }
820  strcat(msg, stratagus_argv[i]);
821  strcat(msg, " ");
822  }
823  error(TITLE, msg);
824  } else if (ret != 0) {
825  char message[8096 * 2] = {'\0'};
826  snprintf(message, 8096 * 2,
827  "Stratagus failed to load game data. "
828  "If you just launched the game without any arguments, this may indicate a bug with the extraction process. "
829  "Please report this on https://github.com/Wargus/stratagus/issues/new, "
830  "and please give details, including: operating system, installation path, username, kind of source CD. "
831  "If you got an error message about the extraction command failing, please try to run it in a console "
832  "and post the output to the issue. A common problem is symbols in the path for the installation, the game data path, "
833  "or the username (like an ampersand or exclamation mark). Try changing these. "
834 #ifndef WIN32
835 #ifdef WIN32
836  "Also check if the file '%s' exists and check for errors or post it to the issue. "
837 #endif
838  "Try also to remove the folder %s and try the extraction again.",
839 #ifdef WIN32
840  GetExtractionLogPath(GAME_NAME, data_path),
841 #endif
842  data_path);
843 #else
844  "If not already done, please try using the portable version and check for stdout.txt, stderr.txt, and an extraction.log in the folder."
845  );
846 #endif
847  error(TITLE, message);
848 #ifdef WIN32
849  _unlink(title_path);
850  _unlink(data_path);
851 #else
852  unlink(title_path);
853  unlink(data_path);
854 #endif
855  }
856  exit(ret);
857 }
858 
859 #endif
EXTRACTOR_NOT_FOUND
#define EXTRACTOR_NOT_FOUND
Definition: stratagus-game-launcher.h:183
error
void error(const char *title, const char *text)
Definition: stratagus-gameutils.h:121
DATA_PATH
#define DATA_PATH
Definition: stratagus-game-launcher.h:140
STRATAGUS_BIN
#define STRATAGUS_BIN
Definition: stratagus-game-launcher.h:142
stratagus-gameutils.h
GAME
#define GAME
Definition: stratagus-game-launcher.h:139
SetUserDataPath
static void SetUserDataPath(char *data_path)
Definition: stratagus-game-launcher.h:189
tinyfd_messageBox
int tinyfd_messageBox(char const *aTitle, char const *aMessage, char const *aDialogType, char const *aIconType, int aDefaultButton)
Definition: stratagus-tinyfiledialogs.h:4015
detectPresence
static int detectPresence(char const *aExecutable)
Definition: stratagus-tinyfiledialogs.h:3230
copy_dir
void copy_dir(const char *source_folder, const char *target_folder)
TITLE_PNG
#define TITLE_PNG
Definition: stratagus-game-launcher.h:159
runCommand
int runCommand(std::wstring &file, std::vector< std::wstring > argv, bool echo=false, std::wstring *outputCommandline=NULL)
Definition: stratagus-gameutils.h:275
parentdir
#define parentdir(x)
Definition: stratagus-gameutils.h:69
SCRIPTS_PATH
#define SCRIPTS_PATH
Definition: stratagus-game-launcher.h:141
SLASH
#define SLASH
Definition: stratagus-tinyfiledialogs.h:401
GAME_CD
#define GAME_CD
Definition: stratagus-game-launcher.h:138
GAME_NAME
#define GAME_NAME
Definition: stratagus-game-launcher.h:137
BUFF_SIZE
#define BUFF_SIZE
Definition: stratagus-gameutils.h:116
GetExtractionLogPath
char * GetExtractionLogPath(const char *game_name, char *data_path)
Definition: stratagus-gameutils.h:153
GAME_SHOULD_EXTRACT_AGAIN
#define GAME_SHOULD_EXTRACT_AGAIN
Definition: stratagus-game-launcher.h:150
QUOTE
#define QUOTE
Definition: stratagus-gameutils.h:82
REGKEY
#define REGKEY
Definition: stratagus-game-launcher.h:179
STRATAGUS_NOT_FOUND
#define STRATAGUS_NOT_FOUND
Definition: stratagus-game-launcher.h:184
TITLE
#define TITLE
Definition: stratagus-game-launcher.h:182
tinyfd_openFileDialog
char * tinyfd_openFileDialog(char const *aTitle, char const *aDefaultPathAndFile, int aNumOfFilterPatterns, char const *const *aFilterPatterns, char const *aSingleFilterDescription, int aAllowMultipleSelects)
Definition: stratagus-tinyfiledialogs.h:5744
ExtractData
static void ExtractData(char *extractor_tool, char *const extractor_args[], char *destination, char *scripts_path, int force=0, char *datafileCstr=NULL)
Definition: stratagus-game-launcher.h:272
DATA_NOT_EXTRACTED
#define DATA_NOT_EXTRACTED
Definition: stratagus-game-launcher.h:185
main
int main(int argc, char *argv[])
Definition: stratagus-game-launcher.h:547
tinyfd_forceConsole
int tinyfd_forceConsole
Definition: stratagus-tinyfiledialogs.h:431
check_version
int check_version(char *tool_path, char *data_path)
Definition: stratagus-game-launcher.h:213
(C) Copyright 1998-2012 by The Stratagus Project under the GNU General Public License.
All trademarks and copyrights on this page are owned by their respective owners.