altos: Create ao_data_fill shared function
[fw/altos] / icon / windows-stub.c
1 /*
2  * Copyright © 2015 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 /* A windows stub program to launch a java program with suitable parameters
20  *
21  * Given that the name of this exe is altusmetrum-foo.exe living in directory bar, and
22  * that it was run with 'args' extra command line parameters, run:
23  *
24  *      javaw.exe -Djava.library.path="bar" -jar "bar/foo-fat.jar" args
25  */
26
27 #define _UNICODE
28 #define UNICODE
29 #include <stdlib.h>
30 #include <windows.h>
31 #include <setupapi.h>
32 #include <stdio.h>
33 #include <stdarg.h>
34 #include <shlwapi.h>
35
36 /* Concatenate a list of strings together
37  */
38 static LPTSTR
39 wcsbuild(LPTSTR first, ...)
40 {
41         va_list args;
42         int     len;
43         LPTSTR  buf;
44         LPTSTR  arg;
45
46         buf = wcsdup(first);
47         va_start(args, first);
48         while ((arg = va_arg(args, LPTSTR)) != NULL) {
49                 len = wcslen(buf) + wcslen(arg) + 1;
50                 buf = realloc(buf, len * sizeof (wchar_t));
51                 wcscat(buf, arg);
52         }
53         va_end(args);
54         return buf;
55 }
56
57 /* Quote a single string, taking care to escape embedded quote and
58  * backslashes within
59  */
60 static LPTSTR
61 quote_arg(LPTSTR arg)
62 {
63         LPTSTR  result;
64         LPTSTR  in, out;
65         int     out_len = 3;    /* quotes and terminating null */
66
67         /* Find quote and backslashes */
68         for (in = arg; *in; in++) {
69                 switch (*in) {
70                 case '"':
71                 case '\\':
72                         out_len += 2;
73                         break;
74                 default:
75                         out_len++;
76                         break;
77                 }
78         }
79
80         result = malloc ((out_len + 1) * sizeof (wchar_t));
81         out = result;
82         *out++ = '"';
83         for (in = arg; *in; in++) {
84                 switch (*in) {
85                 case '"':
86                 case '\\':
87                         *out++ = '\\';
88                         break;
89                 }
90                 *out++ = *in;
91         }
92         *out++ = '"';
93         *out++ = '\0';
94         return result;
95 }
96
97 /* Construct a single string from a list of arguments
98  */
99 static LPTSTR
100 quote_args(LPTSTR *argv, int argc)
101 {
102         LPTSTR  result = NULL, arg;
103         int     i;
104
105         result = malloc(1 * sizeof (wchar_t));
106         result[0] = '\0';
107         for (i = 0; i < argc; i++) {
108                 arg = quote_arg(argv[i]);
109                 result = realloc(result, (wcslen(result) + 1 + wcslen(arg) + 1) * sizeof (wchar_t));
110                 wcscat(result, L" ");
111                 wcscat(result, arg);
112                 free(arg);
113         }
114         return result;
115 }
116
117 /* Return the directory portion of the provided file
118  */
119 static LPTSTR
120 get_dir(LPTSTR file)
121 {
122         DWORD   len = GetFullPathName(file, 0, NULL, NULL);
123         LPTSTR  full = malloc (len * sizeof (wchar_t));
124         GetFullPathName(file, len, full, NULL);
125         PathRemoveFileSpec(full);
126         return full;
127 }
128
129 /* Convert a .exe name into a -fat.jar name, starting
130  * by computing the complete path name of the source filename
131  */
132 static LPTSTR
133 make_jar(LPTSTR file)
134 {
135         DWORD   len = GetFullPathName(file, 0, NULL, NULL);
136         LPTSTR  full = malloc (len * sizeof (wchar_t));
137         LPTSTR  base_part;
138         LPTSTR  jar;
139         LPTSTR  dot;
140         GetFullPathName(file, len, full, &base_part);
141         static const wchar_t head[] = L"altusmetrum-";
142
143         if (wcsncmp(base_part, head, wcslen(head)) == 0)
144                 base_part += wcslen(head);
145         dot = wcsrchr(base_part, '.');
146         if (dot)
147                 *dot = '\0';
148         jar = wcsdup(base_part);
149         PathRemoveFileSpec(full);
150         return wcsbuild(full, L"\\", jar, L"-fat.jar", NULL);
151 }
152
153 /* Build the complete command line from the pieces
154  */
155 static LPTSTR
156 make_cmd(LPTSTR dir, LPTSTR jar, LPTSTR quote_args)
157 {
158         LPTSTR  quote_dir = quote_arg(dir);
159         LPTSTR  quote_jar = quote_arg(jar);
160         LPTSTR  cmd;
161
162         cmd = wcsbuild(L"javaw.exe -Djava.library.path=", quote_dir, L" -jar ", quote_jar, quote_args, NULL);
163         free(quote_jar);
164         free(jar);
165         free(quote_dir);
166         return cmd;
167 }
168
169 int WINAPI
170 WinMain(HINSTANCE instance, HINSTANCE prev_instance, LPSTR cmd_line_a, int cmd_show)
171 {
172         STARTUPINFO             startup_info;
173         PROCESS_INFORMATION     process_information;
174         BOOL                    result;
175         wchar_t                 *command_line;
176         int                     argc;
177         LPTSTR                  *argv = CommandLineToArgvW(GetCommandLine(), &argc);
178         LPTSTR                  my_dir;
179         LPTSTR                  my_jar;
180         LPTSTR                  args = quote_args(argv + 1, argc - 1);
181
182         my_dir = get_dir(argv[0]);
183         my_jar = make_jar(argv[0]);
184         command_line = make_cmd(my_dir, my_jar, args);
185         memset(&startup_info, '\0', sizeof startup_info);
186         startup_info.cb = sizeof startup_info;
187         result = CreateProcess(NULL,
188                                command_line,
189                                NULL,
190                                NULL,
191                                FALSE,
192                                CREATE_NO_WINDOW,
193                                NULL,
194                                NULL,
195                                &startup_info,
196                                &process_information);
197         if (result) {
198                 CloseHandle(process_information.hProcess);
199                 CloseHandle(process_information.hThread);
200         }
201         exit(0);
202 }