1 /** \file   archdep_win32.c
2  * \brief   Miscellaneous Windows-specific stuff
3  *
4  * \author  Marco van den Heuvel <blackystardust68@yahoo.com>
5  */
6 
7 /*
8  * This file is part of VICE, the Versatile Commodore Emulator.
9  * See README for copyright notice.
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation; either version 2 of the License, or
14  *  (at your option) any later version.
15  *
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program; if not, write to the Free Software
23  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24  *  02111-1307  USA.
25  *
26  */
27 
28 #include "vice.h"
29 
30 #include <stdio.h>
31 #include <glib.h>
32 #include <windows.h>
33 #ifdef HAVE_FCNTL_H
34 #include <fcntl.h>
35 #endif
36 
37 #if defined(HAVE_IO_H) && !defined(WINMIPS)
38 #include <io.h>
39 #endif
40 
41 #ifdef HAVE_PROCESS_H
42 #include <process.h>
43 #endif
44 
45 #ifdef HAVE_SYS_STAT_H
46 #include <sys/stat.h>
47 #endif
48 
49 #ifdef HAVE_SYS_TYPES_H
50 #include <sys/types.h>
51 #endif
52 
53 #ifdef HAVE_UNISTD_H
54 #include <unistd.h>
55 #endif
56 
57 #include "lib.h"
58 #include "util.h"
59 
60 #include "debug_gtk3.h"
61 
62 #include "archdep.h"
63 
64 /* fix VICE userdir */
65 #ifdef VICEUSERDIR
66 # undef VICEUSERDIR
67 #endif
68 #define VICEUSERDIR "vice"
69 
70 #if 0
71 /** \brief  Path separator used in GLib code
72  */
73 static const gchar *path_separator = "\\";
74 #endif
75 
76 
77 /** \brief  Write message to Windows debugger/logger
78  *
79  * param[in]    level_string    log level string
80  * param[in]    txt             log message
81  *
82  * \note    Shamelessly copied from win32/archdep.c
83  *
84  * \return  0 on success, < 0 on failure
85  */
archdep_default_logger(const char * level_string,const char * txt)86 int archdep_default_logger(const char *level_string, const char *txt)
87 {
88     char *out = lib_msprintf("*** %s %s\n", level_string, txt);
89     OutputDebugString(out);
90     lib_free(out);
91     return 0;
92 }
93 
94 
archdep_shutdown(void)95 void archdep_shutdown(void)
96 {
97     /* free memory used by the exec path */
98     archdep_program_path_free();
99     /* free memory used by the exec name */
100     archdep_program_name_free();
101     /* free memory used by the boot path */
102     archdep_boot_path_free();
103     /* free memory used by the home path */
104     archdep_home_path_free();
105     /* free memory used by the config files path */
106     archdep_user_config_path_free();
107     /* free memory used by the sysfile pathlist */
108     archdep_default_sysfile_pathlist_free();
109 
110     /* do we need this anymore? argv is guaranteed to exist during the program
111      * lifetime and we already set a reference to argv[0] with
112      * archdep_program_path_set_argv0() */
113     if (argv0 != NULL) {
114         lib_free(argv0);
115         argv0 = NULL;
116     }
117 
118     /* archdep_network_shutdown(); */
119 }
120 
121 
archdep_mkstemp_fd(char ** filename,const char * mode)122 FILE *archdep_mkstemp_fd(char **filename, const char *mode)
123 {
124     char *tmp;
125     FILE *fd;
126 
127     if (getenv("temp")) {
128         tmp = util_concat(getenv("temp"), tmpnam(NULL), NULL);
129     } else if (getenv("tmp")) {
130         tmp = util_concat(getenv("tmp"), tmpnam(NULL), NULL);
131     } else {
132         tmp = lib_stralloc(tmpnam(NULL));
133     }
134 
135     fd = fopen(tmp, mode);
136 
137     if (fd == NULL) {
138         return NULL;
139     }
140 
141     *filename = tmp;
142 
143     return fd;
144 }
145 
146 
147 /** \brief  Spawn new process
148  *
149  * Shamelessly stolen from arch/sdl/archdep_win32.c
150  */
archdep_spawn(const char * name,char ** argv,char ** pstdout_redir,const char * stderr_redir)151 int archdep_spawn(const char *name, char **argv, char **pstdout_redir, const char *stderr_redir)
152 {
153     int new_stdout, new_stderr;
154     int old_stdout_mode, old_stderr_mode;
155     int old_stdout, old_stderr;
156     int retval;
157     char *stdout_redir = NULL;
158 
159     if (pstdout_redir != NULL) {
160         if (*pstdout_redir == NULL) {
161             *pstdout_redir = archdep_tmpnam();
162         }
163         stdout_redir = *pstdout_redir;
164     }
165 
166     new_stdout = new_stderr = old_stdout = old_stderr = -1;
167 
168     /* Make sure we are in binary mode.  */
169     old_stdout_mode = _setmode(STDOUT_FILENO, _O_BINARY);
170     old_stderr_mode = _setmode(STDERR_FILENO, _O_BINARY);
171 
172     /* Redirect stdout and stderr as requested, saving the old
173        descriptors.  */
174     if (stdout_redir != NULL) {
175         old_stdout = _dup(STDOUT_FILENO);
176         new_stdout = _open(stdout_redir, _O_WRONLY | _O_TRUNC | _O_CREAT, _S_IWRITE | _S_IREAD);
177         if (new_stdout == -1) {
178             log_error(LOG_DEFAULT, "open(\"%s\") failed: %s.", stdout_redir, strerror(errno));
179             retval = -1;
180             goto cleanup;
181         }
182         _dup2(new_stdout, STDOUT_FILENO);
183     }
184     if (stderr_redir != NULL) {
185         old_stderr = _dup(STDERR_FILENO);
186         new_stderr = _open(stderr_redir, _O_WRONLY | _O_TRUNC | _O_CREAT, _S_IWRITE | _S_IREAD);
187         if (new_stderr == -1) {
188             log_error(LOG_DEFAULT, "open(\"%s\") failed: %s.", stderr_redir, strerror(errno));
189             retval = -1;
190             goto cleanup;
191         }
192         _dup2(new_stderr, STDERR_FILENO);
193     }
194 
195     /* Spawn the child process.  */
196     retval = (int)_spawnvp(_P_WAIT, name, (const char **)argv);
197 
198 cleanup:
199     if (old_stdout >= 0) {
200         _dup2(old_stdout, STDOUT_FILENO);
201         _close(old_stdout);
202     }
203     if (old_stderr >= 0) {
204         _dup2(old_stderr, STDERR_FILENO);
205         _close(old_stderr);
206     }
207     if (old_stdout_mode >= 0) {
208         _setmode(STDOUT_FILENO, old_stdout_mode);
209     }
210     if (old_stderr_mode >= 0) {
211         _setmode(STDERR_FILENO, old_stderr_mode);
212     }
213     if (new_stdout >= 0) {
214         _close(new_stdout);
215     }
216     if (new_stderr >= 0) {
217         _close(new_stderr);
218     }
219 
220     return retval;
221 }
222 
223 #if 0
224 /** \brief  Create a unique temporary filename
225  *
226  * \return  unique filename in the %TEMP% directory
227  */
228 char *archdep_tmpnam(void)
229 {
230     if (getenv("temp")) {
231         return util_concat(getenv("temp"), tmpnam(NULL), NULL);
232     } else if (getenv("tmp")) {
233         return util_concat(getenv("tmp"), tmpnam(NULL), NULL);
234     } else {
235         return lib_stralloc(tmpnam(NULL));
236     }
237 }
238 #endif
239 
240 /* Provide a usleep replacement */
vice_usleep(uint64_t waitTime)241 void vice_usleep(uint64_t waitTime)
242 {
243     uint64_t time1 = 0, time2 = 0, freq = 0;
244 
245     QueryPerformanceCounter((LARGE_INTEGER *) &time1);
246     QueryPerformanceFrequency((LARGE_INTEGER *)&freq);
247 
248     do {
249         QueryPerformanceCounter((LARGE_INTEGER *) &time2);
250     } while((time2-time1) < waitTime);
251 }
252 
is_windows_nt(void)253 int is_windows_nt(void)
254 {
255     OSVERSIONINFO os_version_info;
256 
257     ZeroMemory(&os_version_info, sizeof(os_version_info));
258     os_version_info.dwOSVersionInfoSize = sizeof(os_version_info);
259 
260     GetVersionEx(&os_version_info);
261 
262     if (os_version_info.dwPlatformId == VER_PLATFORM_WIN32_NT) {
263         return 1;
264     }
265     return 0;
266 }
267 
268 
archdep_signals_init(int do_core_dumps)269 void archdep_signals_init(int do_core_dumps)
270 {
271     /* NOP */
272 }
273