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

stratagus-gameutils.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) 2015-2016 The Stratagus Developers
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 
29 #ifndef STRATAGUS_GAMEUTILS_H
30 #define STRATAGUS_GAMEUTILS_H
31 
32 void error(const char *title, const char *text);
33 void mkdir_p(const char *path);
34 void copy_dir(const char *source_folder, const char *target_folder);
35 
36 #if __APPLE__
37 #define USE_MAC
38 #endif
39 
40 #if ( defined (_MSC_VER) || defined (_WIN32) || defined (_WIN64) ) && ! defined (WIN32)
41 #define WIN32 1
42 #endif
43 
44 #ifndef _CRT_SECURE_NO_DEPRECATE
45 #define _CRT_SECURE_NO_DEPRECATE
46 #endif
47 #ifndef _CRT_SECURE_NO_WARNINGS
48 #define _CRT_SECURE_NO_WARNINGS
49 #endif
50 
51 #ifdef WIN32
52 
53 // set everything to winxp sp2 compatiblity
54 #define NTDDI_VERSION 0x05010200
55 #define _WIN32_WINNT 0x0501
56 #define WINVER 0x0501
57 
58 #ifndef PATH_MAX
59 #define PATH_MAX MAX_PATH
60 #endif
61 #include <Shlwapi.h>
62 #include <Shlobj.h>
63 #pragma comment(lib, "comdlg32.lib")
64 #pragma comment(lib, "ole32.lib")
65 #pragma comment(lib, "Shlwapi.lib")
66 #include <direct.h>
67 #define mkdir(f, m) _mkdir(f)
68 // PathRemoveFileSpec on a drive (e.g. when extracting from CD) will leave the trailing \... remove that
69 #define parentdir(x) PathRemoveFileSpec(x); if (x[strlen(x) - 1] == '\\') x[strlen(x) - 1] = '\0'
70 #else
71 #if defined(USE_MAC)
72 #define parentdir(x) strcpy(x, dirname(x))
73 #else
74 #define parentdir(x) dirname(x)
75 #endif
76 #endif
77 
78 #ifdef WIN32
79 #include <windows.h>
80 #include <wincon.h>
81 #include <process.h>
82 #define QUOTE "\""
83 #else
84 #include <ftw.h>
85 #include <unistd.h>
86 #include <libgen.h>
87 #include <sys/wait.h>
88 #define QUOTE "'"
89 #endif
90 
91 #include <errno.h>
92 #include <stdio.h>
93 #include <stdlib.h>
94 #include <string.h>
95 #include <sys/stat.h>
96 #include <sys/types.h>
97 
98 #include <string>
99 #include <vector>
100 #include <iostream>
101 #include <sstream>
102 #include <istream>
103 #if __has_include(<filesystem>)
104 #include <filesystem>
105 namespace fs = std::filesystem;
106 #elif __has_include(<experimental/filesystem>)
107 #include <experimental/filesystem>
108 namespace fs = std::experimental::filesystem;
109 #else
110 error "Missing the <filesystem> header."
111 #endif
112 
114 
115 #ifdef WIN32
116 #define BUFF_SIZE MAX_PATH
117 #else
118 #define BUFF_SIZE 4096
119 #endif
120 
121 void error(const char *title, const char *text)
122 {
123  tinyfd_messageBox(title, text, "ok", "error", 1);
124  exit(-1);
125 }
126 
127 void mkdir_p(const char *path)
128 {
129  fs::create_directories(path);
130 }
131 void mkdir_p(const wchar_t *path)
132 {
133  fs::create_directories(path);
134 }
135 
136 void copy_dir(fs::path source_folder, fs::path target_folder)
137 {
138  if (fs::exists(target_folder)) {
139  if (fs::equivalent(source_folder, target_folder)) {
140  return;
141  }
142  // first delete the target_folder, if it exists, to ensure clean slate
143  fs::remove_all(target_folder);
144  } else {
145  // make the parentdir of the target folder
146  fs::create_directories(target_folder.parent_path());
147  }
148  // now copy the new folder in its place
149  fs::copy(source_folder, target_folder, fs::copy_options::recursive | fs::copy_options::overwrite_existing);
150 }
151 
152 #ifdef WIN32
153 char *GetExtractionLogPath(const char *game_name, char *data_path)
154 {
155  static char *marker = (char *)calloc(MAX_PATH, sizeof(char));
156  if (marker[0] != '\0') {
157  return marker;
158  }
159  char logname[MAX_PATH];
160  strcpy(logname, game_name);
161  strcat(logname, "-extraction.log");
162  if (PathCombineA(marker, data_path, "portable-install")) {
163  if (PathFileExistsA(marker)) {
164  PathCombineA(marker, data_path, logname);
165  return marker;
166  }
167  }
168  SHGetFolderPathA(NULL, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, 0, marker);
169  PathAppendA(marker, "Stratagus");
170  mkdir_p(marker);
171  PathAppendA(marker, logname);
172  return marker;
173 }
174 
175 wchar_t *GetExtractionLogPath(const wchar_t *game_name, const wchar_t *data_path)
176 {
177  static wchar_t *marker = (wchar_t *)calloc(MAX_PATH, sizeof(wchar_t));
178  if (marker[0] != '\0') {
179  return marker;
180  }
181  wchar_t logname[MAX_PATH];
182  wcscpy(logname, game_name);
183  wcscat(logname, L"-extraction.log");
184  if (PathCombineW(marker, data_path, L"portable-install")) {
185  if (PathFileExistsW(marker)) {
186  PathCombineW(marker, data_path, logname);
187  return marker;
188  }
189  }
190  SHGetFolderPathW(NULL, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, 0, marker);
191  PathAppendW(marker, L"Stratagus");
192  mkdir_p(marker);
193  PathAppendW(marker, logname);
194  return marker;
195 }
196 #endif
197 
198 #ifdef WIN32
199 // quoting logic taken from "Everyone quotes command line arguments the wrong way" by Daniel Colascione
200 /*++
201 
202 Routine Description:
203 
204  This routine appends the given argument to a command line such
205  that CommandLineToArgvW will return the argument string unchanged.
206  Arguments in a command line should be separated by spaces; this
207  function does not add these spaces.
208 
209 Arguments:
210 
211  Argument - Supplies the argument to encode.
212 
213  CommandLine - Supplies the command line to which we append the encoded argument string.
214 
215  Force - Supplies an indication of whether we should quote
216  the argument even if it does not contain any characters that would
217  ordinarily require quoting.
218 
219 Return Value:
220 
221  None.
222 
223 Environment:
224 
225  Arbitrary.
226 
227 --*/
228 void ArgvQuote(const std::wstring &Argument, std::wstring &CommandLine, bool Force)
229 {
230  //
231  // Unless we're told otherwise, don't quote unless we actually
232  // need to do so --- hopefully avoid problems if programs won't
233  // parse quotes properly
234  //
235  if (Force == false && Argument.empty() == false && Argument.find_first_of(L" \t\n\v\"") == Argument.npos) {
236  CommandLine.append(Argument);
237  } else {
238  CommandLine.push_back(L'"');
239 
240  for (auto It = Argument.begin(); ; ++It) {
241  unsigned NumberBackslashes = 0;
242 
243  while (It != Argument.end() && *It == L'\\') {
244  ++It;
245  ++NumberBackslashes;
246  }
247 
248  if (It == Argument.end()) {
249  //
250  // Escape all backslashes, but let the terminating
251  // double quotation mark we add below be interpreted
252  // as a metacharacter.
253  //
254  CommandLine.append(NumberBackslashes * 2, L'\\');
255  break;
256  } else if (*It == L'"') {
257  //
258  // Escape all backslashes and the following
259  // double quotation mark.
260  //
261  CommandLine.append(NumberBackslashes * 2 + 1, L'\\');
262  CommandLine.push_back(*It);
263  } else {
264  //
265  // Backslashes aren't special here.
266  //
267  CommandLine.append(NumberBackslashes, L'\\');
268  CommandLine.push_back(*It);
269  }
270  }
271  CommandLine.push_back(L'"');
272  }
273 }
274 
275 int runCommand(std::wstring &file, std::vector<std::wstring> argv, bool echo = false, std::wstring *outputCommandline = NULL)
276 {
277  std::wstring cmdline;
278  std::wstring executable;
279 
280  ArgvQuote(file, executable, false);
281 
282  for (size_t i = 0; i < argv.size(); i++) {
283  std::wstring arg = argv[i];
284  ArgvQuote(arg, cmdline, false);
285  if (i + 1 < argv.size()) {
286  cmdline.push_back(L' ');
287  }
288  }
289  std::wstring cmdcmdline;
290  for (auto c : cmdline) {
291  if (c == L'(' || c == L')' || c == L'%' || c == L'!' || c == L'^' || c == L'"' || c == L'<' || c == L'>' || c == L'&' || c == L'|') {
292  cmdcmdline.push_back(L'^');
293  }
294  cmdcmdline.push_back(c);
295  }
296 
297  if (argv.size() > 0) {
298  cmdcmdline = std::wstring(L"@") + executable + std::wstring(L" ") + cmdcmdline;
299  } else {
300  cmdcmdline = std::wstring(L"@") + executable;
301  }
302 
303  if (outputCommandline != NULL) {
304  outputCommandline->append(cmdcmdline);
305  }
306  if (echo) {
307  std::wcout << executable << L' ' << cmdline << L'\n';
308  std::wcout << cmdcmdline << L'\n';
309  }
310  _flushall();
311  int code = _wsystem(cmdcmdline.c_str());
312  if (code == -1) {
313  std::wcout << _wcserror(errno) << L'\n';
314  }
315  return code;
316 }
317 #else
318 #include <sys/types.h>
319 #include <unistd.h>
320 #include <sys/wait.h>
321 
322 int runCommand(const char *file, char *const argv[], bool echo = false, std::string *outputCommandline = NULL)
323 {
324  pid_t pid = fork();
325 
326  if (echo || outputCommandline) {
327  std::string commandline = file;
328  for (int i = 0; ; i++) {
329  if (argv[i] == NULL) {
330  break;
331  }
332  commandline += " ";
333  commandline += argv[i];
334  }
335  if (echo) {
336  std::cout << commandline << std::endl;
337  }
338  if (outputCommandline) {
339  outputCommandline->append(commandline);
340  }
341  }
342 
343  if (pid == 0) {
344  // child
345  exit(execvp(file, argv));
346  } else {
347  int status;
348  waitpid(pid, &status, 0);
349  if (WIFEXITED(status)) {
350  return WEXITSTATUS(status);
351  } else {
352  return -1;
353  }
354  }
355 }
356 #endif
357 
358 #endif
error
void error(const char *title, const char *text)
Definition: stratagus-gameutils.h:121
stratagus-tinyfiledialogs.h
tinyfd_messageBox
int tinyfd_messageBox(char const *aTitle, char const *aMessage, char const *aDialogType, char const *aIconType, int aDefaultButton)
Definition: stratagus-tinyfiledialogs.h:4015
copy_dir
void copy_dir(const char *source_folder, const char *target_folder)
runCommand
int runCommand(std::wstring &file, std::vector< std::wstring > argv, bool echo=false, std::wstring *outputCommandline=NULL)
Definition: stratagus-gameutils.h:275
GetExtractionLogPath
char * GetExtractionLogPath(const char *game_name, char *data_path)
Definition: stratagus-gameutils.h:153
mkdir_p
void mkdir_p(const char *path)
Definition: stratagus-gameutils.h:127
ArgvQuote
void ArgvQuote(const std::wstring &Argument, std::wstring &CommandLine, bool Force)
Definition: stratagus-gameutils.h:228
(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.