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