1 /* Copyright (C) 2001-2019 Artifex Software, Inc.
2 All Rights Reserved.
3
4 This software is provided AS-IS with no warranty, either express or
5 implied.
6
7 This software is distributed under license and may not be copied,
8 modified or distributed except as expressly authorized under the terms
9 of the license contained in the file LICENSE in this distribution.
10
11 Refer to licensing information at http://www.artifex.com or contact
12 Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
13 CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15
16 //
17 //
18 // This is the setup program for Win32 GPL Ghostscript
19 //
20 // The starting point is a self extracting zip archive
21 // with the following contents:
22 // setupgs.exe
23 // uninstgs.exe
24 // filelist.txt (contains list of program files)
25 // gs#.##\* (files listed in filelist.txt)
26 // This is the same as the zip file created by Aladdin Enterprises,
27 // with the addition of setupgs.exe, uninstgs.exe, and filelist.txt
28 //
29 // The first line of the file filelist.txt
30 // contains the uninstall name to be used.
31 // The second line contains name of the main directory where
32 // uninstall log files are to be placed.
33 // Subsequent lines contain files to be copied (but not directories).
34 // For example, filelist.txt might contain:
35 // GPL Ghostscript 8.55
36 // gs8.55
37 // gs8.55\bin\gsdll32.dll
38 // gs8.55\lib\gs_init.ps
39 //
40 // The default install directory is c:\gs.
41 // The default Start Menu Folder is Ghostscript.
42 // These are set in the resources.
43 // The setup program will create the following uninstall log files
44 // c:\gs\gs#.##\uninstal.txt
45 // The uninstall program (accessed through control panel) will not
46 // remove directories nor will it remove itself.
47 //
48 // If the install directory is the same as the current file
49 // location, no files will be copied, but the existence of each file
50 // will be checked. This allows the archive to be unzipped, then
51 // configured in its current location. Running the uninstall will not
52 // remove uninstgs.exe, setupgs.exe, or filelist.txt.
53
54
55 #define STRICT
56 #include <windows.h>
57 #include <shellapi.h>
58 #include <objbase.h>
59 #include <shlobj.h>
60 #include <stdio.h>
61 #include <direct.h>
62 #include <ctype.h>
63
64 #pragma comment(lib,"user32.lib")
65
66 #ifdef MAX_PATH
67 #define MAXSTR MAX_PATH
68 #else
69 #define MAXSTR 256
70 #endif
71
72 CHAR g_szAppName[MAXSTR];
73
74 // Prototypes
75 BOOL init();
76 BOOL make_filelist(int argc, char *argv[]);
77
78
79 //////////////////////////////////////////////////////////////////////
80 // Entry point
81 //////////////////////////////////////////////////////////////////////
82
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)83 int APIENTRY WinMain(HINSTANCE hInstance,
84 HINSTANCE hPrevInstance,
85 LPSTR lpCmdLine,
86 int nCmdShow)
87 {
88 strcpy(g_szAppName, "make_filelist");
89 if (!init()) {
90 MessageBox(HWND_DESKTOP, "Initialisation failed",
91 g_szAppName, MB_OK);
92 return 1;
93 }
94
95 return 0;
96 }
97
98
99
100
101 //////////////////////////////////////////////////////////////////////
102 // Initialisation and Main dialog box
103 //////////////////////////////////////////////////////////////////////
104
105 void
message_box(const char * str)106 message_box(const char *str)
107 {
108 MessageBox(HWND_DESKTOP, str, g_szAppName, MB_OK);
109 }
110
111
112 BOOL
init()113 init()
114 {
115 DWORD dwVersion = GetVersion();
116 // get source directory
117
118
119 if (LOBYTE(LOWORD(dwVersion)) < 4) {
120 MessageBox(HWND_DESKTOP,
121 "This install program needs Windows 4.0 or later",
122 g_szAppName, MB_OK);
123 return FALSE;
124 }
125
126
127 #define MAXCMDTOKENS 128
128
129 int argc;
130 LPSTR argv[MAXCMDTOKENS];
131 LPSTR p;
132 char *args;
133 char *d, *e;
134
135 p = GetCommandLine();
136
137 argc = 0;
138 args = (char *)malloc(lstrlen(p)+1);
139 if (args == (char *)NULL)
140 return 1;
141
142 // Parse command line handling quotes.
143 d = args;
144 while (*p) {
145 // for each argument
146
147 if (argc >= MAXCMDTOKENS - 1)
148 break;
149
150 e = d;
151 while ((*p) && (*p != ' ')) {
152 if (*p == '\042') {
153 // Remove quotes, skipping over embedded spaces.
154 // Doesn't handle embedded quotes.
155 p++;
156 while ((*p) && (*p != '\042'))
157 *d++ =*p++;
158 }
159 else
160 *d++ = *p;
161 if (*p)
162 p++;
163 }
164 *d++ = '\0';
165 argv[argc++] = e;
166
167 while ((*p) && (*p == ' '))
168 p++; // Skip over trailing spaces
169 }
170 argv[argc] = NULL;
171
172 if (argc > 2) {
173 // Probably creating filelist.txt
174 return make_filelist(argc, argv);
175 }
176 return 0;
177 }
178
179
180 //////////////////////////////////////////////////////////////////////
181 // Create file list
182 //////////////////////////////////////////////////////////////////////
183
184 FILE *fList;
185
186 typedef int (*PFN_dodir)(const char *name);
187
188 /* Called once for each directory */
189 int
dodir(const char * filename)190 dodir(const char *filename)
191 {
192 return 0;
193 }
194
195 /* Called once for each file */
196 int
dofile(const char * filename)197 dofile(const char *filename)
198 {
199 if (fList != (FILE *)NULL) {
200 fputs(filename, fList);
201 fputs("\n", fList);
202 }
203
204 return 0;
205 }
206
207
208 /* Walk through directory 'path', calling dodir() for given directory
209 * and dofile() for each file.
210 * If recurse=1, recurse into subdirectories, calling dodir() for
211 * each directory.
212 */
213 int
dirwalk(char * path,int recurse,PFN_dodir dodir,PFN_dodir dofile)214 dirwalk(char *path, int recurse, PFN_dodir dodir, PFN_dodir dofile)
215 {
216 WIN32_FIND_DATA find_data;
217 HANDLE find_handle;
218 char pattern[MAXSTR]; /* orig pattern + modified pattern */
219 char base[MAXSTR];
220 char name[MAXSTR];
221 BOOL bMore = TRUE;
222 char *p;
223
224
225 if (path) {
226 strcpy(pattern, path);
227 if (strlen(pattern) != 0) {
228 p = pattern + strlen(pattern) -1;
229 if (*p == '\\')
230 *p = '\0'; // truncate trailing backslash
231 }
232
233 strcpy(base, pattern);
234 if (strchr(base, '*') != NULL) {
235 // wildcard already included
236 // truncate it from the base path
237 if ( (p = strrchr(base, '\\')) != NULL )
238 *(++p) = '\0';
239 }
240 else if (isalpha(pattern[0]) &&
241 pattern[1]==':' && pattern[2]=='\0') {
242 strcat(pattern, "\\*"); // search entire disk
243 strcat(base, "\\");
244 }
245 else {
246 // wildcard NOT included
247 // check to see if path is a directory
248 find_handle = FindFirstFile(pattern, &find_data);
249 if (find_handle != INVALID_HANDLE_VALUE) {
250 FindClose(find_handle);
251 if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
252 strcat(pattern, "\\*"); // yes, search files
253 strcat(base, "\\");
254 }
255 else {
256 dofile(path); // no, return just this file
257 return 0;
258 }
259 }
260 else
261 return 1; // path invalid
262 }
263 }
264 else {
265 base[0] = '\0';
266 strcpy(pattern, "*");
267 }
268
269 find_handle = FindFirstFile(pattern, &find_data);
270 if (find_handle == INVALID_HANDLE_VALUE)
271 return 1;
272
273 while (bMore) {
274 strcpy(name, base);
275 strcat(name, find_data.cFileName);
276 if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
277 if ( strcmp(find_data.cFileName, ".") &&
278 strcmp(find_data.cFileName, "..") ) {
279 dodir(name);
280 if (recurse)
281 dirwalk(name, recurse, dodir, dofile);
282 }
283 }
284 else {
285 dofile(name);
286 }
287 bMore = FindNextFile(find_handle, &find_data);
288 }
289 FindClose(find_handle);
290
291 return 0;
292 }
293
294
295
296 // This is used when creating a file list.
297
make_filelist(int argc,char * argv[])298 BOOL make_filelist(int argc, char *argv[])
299 {
300 char *title = NULL;
301 char *dir = NULL;
302 char *list = NULL;
303 int i;
304
305 for (i=1; i<argc; i++) {
306 if (strcmp(argv[i], "-title") == 0) {
307 i++;
308 title = argv[i];
309 }
310 else if (strcmp(argv[i], "-dir") == 0) {
311 i++;
312 dir = argv[i];
313 }
314 else if (strcmp(argv[i], "-list") == 0) {
315 i++;
316 list = argv[i];
317 }
318 else {
319 if ((title == NULL) || (strlen(title) == 0) ||
320 (dir == NULL) || (strlen(dir) == 0) ||
321 (list == NULL) || (strlen(list) == 0)) {
322 message_box("Usage: make_filelist -title \042GPL Ghostscript #.##\042 -dir \042gs#.##\042 -list \042filelist.txt\042 spec1 spec2 specn\n");
323 return FALSE;
324 }
325 if (fList == (FILE *)NULL) {
326 if ( (fList = fopen(list, "w")) == (FILE *)NULL ) {
327 message_box("Can't write list file\n");
328 return FALSE;
329 }
330 fputs(title, fList);
331 fputs("\n", fList);
332 fputs(dir, fList);
333 fputs("\n", fList);
334 }
335 if (argv[i][0] == '@') {
336 // Use @filename with list of files/directories
337 // to avoid DOS command line limit
338 FILE *f;
339 char buf[MAXSTR];
340 int j;
341 if ( (f = fopen(&(argv[i][1]), "r")) != (FILE *)NULL) {
342 while (fgets(buf, sizeof(buf), f)) {
343 // remove trailing newline and spaces
344 while ( ((j = strlen(buf)-1) >= 0) &&
345 ((buf[j] == '\n') || (buf[j] == ' ')) )
346 buf[j] = '\0';
347 dirwalk(buf, TRUE, &dodir, &dofile);
348 }
349 fclose(f);
350 }
351 else {
352 wsprintf(buf, "Can't open @ file \042%s\042",
353 &argv[i][1]);
354 message_box(buf);
355 }
356 }
357 else
358 dirwalk(argv[i], TRUE, &dodir, &dofile);
359 }
360 }
361
362 if (fList != (FILE *)NULL) {
363 fclose(fList);
364 fList = NULL;
365 }
366 return TRUE;
367 }
368
369