1 /* Copyright (C) 1999, 2000, Ghostgum Software Pty Ltd. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify it
4 under the terms of the GNU General Public License as published by the
5 Free Software Foundation; either version 2 of the License, or (at your
6 option) any later version.
7
8 This program is distributed in the hope that it will be useful, but
9 WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16
17 */
18
19 // $Id: dwsetup.cpp,v 1.5.6.2.2.1 2003/01/17 00:49:00 giles Exp $
20 //
21 //
22 // This is the setup program for Win32 GNU Ghostscript
23 //
24 // The starting point is a self extracting zip archive
25 // with the following contents:
26 // setupgs.exe
27 // uninstgs.exe
28 // filelist.txt (contains list of program files)
29 // fontlist.txt (contains list of font files)
30 // gs#.##\* (files listed in filelist.txt)
31 // fonts\* (fonts listed in fontlist.txt)
32 // This is the same as the zip file created by Aladdin Enterprises,
33 // with the addition of setupgs.exe, uninstgs.exe, filelist.txt and
34 // fontlist.txt.
35 //
36 // The first line of the files filelist.txt and fontlist.txt
37 // contains the uninstall name to be used.
38 // The second line contains name of the main directory where
39 // uninstall log files are to be placed.
40 // Subsequent lines contain files to be copied (but not directories).
41 // For example, filelist.txt might contain:
42 // GNU Ghostscript 6.50
43 // gs6.50
44 // gs6.50\bin\gsdll32.dll
45 // gs6.50\lib\gs_init.ps
46 // The file fontlist.txt might contain:
47 // GNU Ghostscript Fonts
48 // fonts
49 // fonts\n019003l.pfb
50 // fonts\n019023l.pfb
51 //
52 // The default install directory is c:\gs.
53 // The default Start Menu Folder is Ghostscript.
54 // These are set in the resources.
55 // The setup program will create the following uninstall log files
56 // c:\gs\gs#.##\uninstal.txt
57 // c:\gs\fonts\uninstal.txt
58 // The uninstall program (accessed through control panel) will not
59 // remove directories nor will it remove itself.
60 //
61 // If the install directory is the same as the current file
62 // location, no files will be copied, but the existence of each file
63 // will be checked. This allows the archive to be unzipped, then
64 // configured in its current location. Running the uninstall will not
65 // remove uninstgs.exe, setupgs.exe, filelist.txt or fontlist.txt.
66
67
68 #define STRICT
69 #include <windows.h>
70 #include <shellapi.h>
71 #include <objbase.h>
72 #include <shlobj.h>
73 #include <stdio.h>
74 #include <direct.h>
75
76 #ifdef MAX_PATH
77 #define MAXSTR MAX_PATH
78 #else
79 #define MAXSTR 256
80 #endif
81
82 #include "dwsetup.h"
83 #include "dwinst.h"
84
85 //#define DEBUG
86
87 #define UNINSTALLPROG "uninstgs.exe"
88
89
90 /////////////////////////////////
91 // Globals
92
93 CInstall cinst;
94
95 // TRUE = Place Start Menu items in All Users.
96 // FALSE = Current User
97 BOOL g_bUseCommon;
98
99 // TRUE = Destination is the same as Source, so don't copy files.
100 BOOL g_bNoCopy;
101
102 // Source directory, usually a temporary directory created by
103 // unzip self extractor.
104 CHAR g_szSourceDir[MAXSTR];
105
106 // Target directory for program and fonts.
107 // Default loaded from resources
108 CHAR g_szTargetDir[MAXSTR];
109
110 // Target Group for shortcut.
111 // Default loaded from resources
112 CHAR g_szTargetGroup[MAXSTR];
113
114 // Setup application name, loaded from resources
115 CHAR g_szAppName[MAXSTR];
116
117 BOOL g_bInstallFonts = TRUE;
118 BOOL g_bAllUsers = FALSE;
119
120
121 HWND g_hMain; // Main install dialog
122 HWND g_hWndText; // Install log dialog
123 HINSTANCE g_hInstance;
124
125 // If a directory is listed on the command line, g_bBatch will
126 // be TRUE and a silent install will occur.
127 BOOL g_bBatch = FALSE;
128
129 BOOL g_bQuit = FALSE; // TRUE = Get out of message loop.
130 BOOL g_bError = FALSE; // TRUE = Install was not successful
131 BOOL is_winnt = FALSE; // Disable "All Users" if not NT.
132
133
134 // Prototypes
135 BOOL CALLBACK MainDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
136 void gs_addmess_count(const char *str, int count);
137 void gs_addmess(const char *str);
138 void gs_addmess_update(void);
139 BOOL init();
140 BOOL install_all();
141 BOOL install_prog();
142 BOOL install_fonts();
143 BOOL make_filelist(int argc, char *argv[]);
144
145
146 //////////////////////////////////////////////////////////////////////
147 // Entry point
148 //////////////////////////////////////////////////////////////////////
149
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)150 int APIENTRY WinMain(HINSTANCE hInstance,
151 HINSTANCE hPrevInstance,
152 LPSTR lpCmdLine,
153 int nCmdShow)
154 {
155 MSG msg;
156 g_hInstance = hInstance;
157
158 if (!init()) {
159 MessageBox(HWND_DESKTOP, "Initialisation failed",
160 g_szAppName, MB_OK);
161 return 1;
162 }
163
164 if (!g_bBatch) {
165 while (GetMessage(&msg, (HWND)NULL, 0, 0)) {
166 if (!IsDialogMessage(g_hWndText, &msg) &&
167 !IsDialogMessage(g_hMain, &msg)) {
168 TranslateMessage(&msg);
169 DispatchMessage(&msg);
170 }
171 }
172 DestroyWindow(g_hMain);
173 }
174
175 return (g_bError ? 1 : 0);
176 }
177
178
179
180
181 //////////////////////////////////////////////////////////////////////
182 // Text log window
183 //////////////////////////////////////////////////////////////////////
184
185
186 #define TWLENGTH 32768
187 #define TWSCROLL 1024
188 char twbuf[TWLENGTH];
189 int twend;
190
191 // Modeless Dialog Box
192 BOOL CALLBACK
TextWinDlgProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)193 TextWinDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
194 {
195 switch(message) {
196 case WM_INITDIALOG:
197 EnableWindow(g_hMain, FALSE);
198 return TRUE;
199 case WM_COMMAND:
200 switch(LOWORD(wParam)) {
201 case IDC_TEXTWIN_COPY:
202 {HGLOBAL hglobal;
203 LPSTR p;
204 DWORD result;
205 int start, end;
206 result = SendDlgItemMessage(hwnd, IDC_TEXTWIN_MLE, EM_GETSEL, (WPARAM)0, (LPARAM)0);
207 start = LOWORD(result);
208 end = HIWORD(result);
209 if (start == end) {
210 start = 0;
211 end = twend;
212 }
213 hglobal = GlobalAlloc(GHND | GMEM_SHARE, end-start+1);
214 if (hglobal == (HGLOBAL)NULL) {
215 MessageBeep(-1);
216 return(FALSE);
217 }
218 p = (char *)GlobalLock(hglobal);
219 if (p == (LPSTR)NULL) {
220 MessageBeep(-1);
221 return(FALSE);
222 }
223 lstrcpyn(p, twbuf+start, end-start);
224 GlobalUnlock(hglobal);
225 OpenClipboard(hwnd);
226 EmptyClipboard();
227 SetClipboardData(CF_TEXT, hglobal);
228 CloseClipboard();
229 }
230 break;
231 case IDCANCEL:
232 g_bQuit = TRUE;
233 DestroyWindow(hwnd);
234 return TRUE;
235 }
236 break;
237 case WM_CLOSE:
238 DestroyWindow(hwnd);
239 return TRUE;
240 case WM_DESTROY:
241 g_bQuit = TRUE;
242 g_hWndText = (HWND)NULL;
243 EnableWindow(g_hMain, TRUE);
244 PostQuitMessage(0);
245 break;
246 }
247 return FALSE;
248 }
249
250
251
252 // Add string to log window
253 void
gs_addmess_count(const char * str,int count)254 gs_addmess_count(const char *str, int count)
255 {
256 const char *s;
257 char *p;
258 int i, lfcount;
259 MSG msg;
260
261 // we need to add \r after each \n, so count the \n's
262 lfcount = 0;
263 s = str;
264 for (i=0; i<count; i++) {
265 if (*s == '\n')
266 lfcount++;
267 s++;
268 }
269
270 if (count + lfcount >= TWSCROLL)
271 return; // too large
272 if (count + lfcount + twend >= TWLENGTH-1) {
273 // scroll buffer
274 twend -= TWSCROLL;
275 memmove(twbuf, twbuf+TWSCROLL, twend);
276 }
277 p = twbuf+twend;
278 for (i=0; i<count; i++) {
279 if (*str == '\n') {
280 *p++ = '\r';
281 }
282 *p++ = *str++;
283 }
284 twend += (count + lfcount);
285 *(twbuf+twend) = '\0';
286
287
288 // Update the dialog box
289 if (g_bBatch)
290 return;
291
292 gs_addmess_update();
293 while (PeekMessage(&msg, (HWND)NULL, 0, 0, PM_REMOVE)) {
294 if (!IsDialogMessage(g_hWndText, &msg) &&
295 !IsDialogMessage(g_hMain, &msg)) {
296 TranslateMessage(&msg);
297 DispatchMessage(&msg);
298 }
299 }
300 }
301
302 void
gs_addmess(const char * str)303 gs_addmess(const char *str)
304 {
305 gs_addmess_count(str, lstrlen(str));
306
307 }
308
309
310 void
gs_addmess_update(void)311 gs_addmess_update(void)
312 {
313 HWND hwndmess = g_hWndText;
314
315 if (g_bBatch)
316 return;
317
318 if (IsWindow(hwndmess)) {
319 HWND hwndtext = GetDlgItem(hwndmess, IDC_TEXTWIN_MLE);
320 DWORD linecount;
321 SendMessage(hwndtext, WM_SETREDRAW, FALSE, 0);
322 SetDlgItemText(hwndmess, IDC_TEXTWIN_MLE, twbuf);
323 linecount = SendDlgItemMessage(hwndmess, IDC_TEXTWIN_MLE, EM_GETLINECOUNT, (WPARAM)0, (LPARAM)0);
324 SendDlgItemMessage(hwndmess, IDC_TEXTWIN_MLE, EM_LINESCROLL, (WPARAM)0, (LPARAM)linecount-14);
325 SendMessage(hwndtext, WM_SETREDRAW, TRUE, 0);
326 InvalidateRect(hwndtext, (LPRECT)NULL, TRUE);
327 UpdateWindow(hwndtext);
328 }
329 }
330
331
332 //////////////////////////////////////////////////////////////////////
333 // Browse dialog box
334 //////////////////////////////////////////////////////////////////////
335
336 // nasty GLOBALS
337 char szFolderName[MAXSTR];
338 char szDirName[MAXSTR];
339
340 BOOL CALLBACK
DirDlgProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)341 DirDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
342 {
343 WORD notify_message;
344
345 switch(message) {
346 case WM_INITDIALOG:
347 DlgDirList(hwnd, szDirName, IDC_FILES, IDC_FOLDER,
348 DDL_DRIVES | DDL_DIRECTORY);
349 SetDlgItemText(hwnd, IDC_TARGET, szFolderName);
350 return FALSE;
351 case WM_COMMAND:
352 notify_message = HIWORD(wParam);
353 switch (LOWORD(wParam)) {
354 case IDC_FILES:
355 if (notify_message == LBN_DBLCLK) {
356 CHAR szPath[MAXSTR];
357 DlgDirSelectEx(hwnd, szPath, sizeof(szPath), IDC_FILES);
358 DlgDirList(hwnd, szPath, IDC_FILES, IDC_FOLDER,
359 DDL_DRIVES | DDL_DIRECTORY);
360 }
361 return FALSE;
362 case IDOK:
363 GetDlgItemText(hwnd, IDC_FOLDER, szDirName, sizeof(szDirName));
364 GetDlgItemText(hwnd, IDC_TARGET, szFolderName, sizeof(szFolderName));
365 EndDialog(hwnd, TRUE);
366 return TRUE;
367 case IDCANCEL:
368 EndDialog(hwnd, FALSE);
369 return TRUE;
370 }
371 return FALSE;
372 }
373 return FALSE;
374 }
375
376
377 //////////////////////////////////////////////////////////////////////
378 // Initialisation and Main dialog box
379 //////////////////////////////////////////////////////////////////////
380
381 void
message_box(const char * str)382 message_box(const char *str)
383 {
384 MessageBox(HWND_DESKTOP, str, g_szAppName, MB_OK);
385 }
386
387
388 BOOL
init()389 init()
390 {
391 DWORD dwVersion = GetVersion();
392 // get source directory
393 GetCurrentDirectory(sizeof(g_szSourceDir), g_szSourceDir);
394
395 // load strings
396 LoadString(g_hInstance, IDS_APPNAME, g_szAppName, sizeof(g_szAppName));
397 LoadString(g_hInstance, IDS_TARGET_GROUP,
398 g_szTargetGroup, sizeof(g_szTargetGroup));
399
400 if (LOBYTE(LOWORD(dwVersion)) < 4) {
401 MessageBox(HWND_DESKTOP,
402 "This install program needs Windows 4.0 or later",
403 g_szAppName, MB_OK);
404 return FALSE;
405 }
406 if ( (HIWORD(dwVersion) & 0x8000) == 0)
407 is_winnt = TRUE;
408
409
410 cinst.SetMessageFunction(message_box);
411
412 #define MAXCMDTOKENS 128
413
414 int argc;
415 LPSTR argv[MAXCMDTOKENS];
416 LPSTR p;
417 char command[256];
418 char *args;
419 char *d, *e;
420
421 p = GetCommandLine();
422
423 argc = 0;
424 args = (char *)malloc(lstrlen(p)+1);
425 if (args == (char *)NULL)
426 return 1;
427
428 // Parse command line handling quotes.
429 d = args;
430 while (*p) {
431 // for each argument
432
433 if (argc >= MAXCMDTOKENS - 1)
434 break;
435
436 e = d;
437 while ((*p) && (*p != ' ')) {
438 if (*p == '\042') {
439 // Remove quotes, skipping over embedded spaces.
440 // Doesn't handle embedded quotes.
441 p++;
442 while ((*p) && (*p != '\042'))
443 *d++ =*p++;
444 }
445 else
446 *d++ = *p;
447 if (*p)
448 p++;
449 }
450 *d++ = '\0';
451 argv[argc++] = e;
452
453 while ((*p) && (*p == ' '))
454 p++; // Skip over trailing spaces
455 }
456 argv[argc] = NULL;
457
458 if (strlen(argv[0]) == 0) {
459 GetModuleFileName(g_hInstance, command, sizeof(command)-1);
460 argv[0] = command;
461 }
462
463 if (argc > 2) {
464 // Probably creating filelist.txt
465 return make_filelist(argc, argv);
466 }
467
468
469 // check if batch mode requested
470 // get location of target directory from command line as argv[1]
471 if (argc == 2) {
472 strncpy(g_szTargetDir, argv[1], sizeof(g_szTargetDir));
473 g_bBatch = TRUE;
474 if (is_winnt)
475 g_bAllUsers = TRUE;
476 }
477 if (g_bBatch) {
478 if (!install_all()) {
479 // display log showing error
480 g_bBatch = FALSE;
481 g_hWndText = CreateDialogParam(g_hInstance,
482 MAKEINTRESOURCE(IDD_TEXTWIN),
483 (HWND)HWND_DESKTOP, TextWinDlgProc,
484 (LPARAM)NULL);
485 gs_addmess_update();
486 }
487 return TRUE;
488 }
489
490 // Interactive setup
491 LoadString(g_hInstance, IDS_TARGET_DIR,
492 g_szTargetDir, sizeof(g_szTargetDir));
493
494 // main dialog box
495 g_hMain = CreateDialogParam(g_hInstance, MAKEINTRESOURCE(IDD_MAIN), (HWND)NULL, MainDlgProc, (LPARAM)NULL);
496 // centre dialog on screen
497 int width = GetSystemMetrics(SM_CXFULLSCREEN);
498 int height = GetSystemMetrics(SM_CYFULLSCREEN);
499 RECT rect;
500 GetWindowRect(g_hMain, &rect);
501 MoveWindow(g_hMain, (width - (rect.right - rect.left))/2,
502 (height - (rect.bottom - rect.top))/2,
503 (rect.right - rect.left),
504 (rect.bottom - rect.top), FALSE);
505
506 // initialize targets
507 cinst.SetMessageFunction(message_box);
508 if (!cinst.Init(g_szSourceDir, "filelist.txt"))
509 return FALSE;
510
511 SetDlgItemText(g_hMain, IDC_TARGET_DIR, g_szTargetDir);
512 SetDlgItemText(g_hMain, IDC_TARGET_GROUP, g_szTargetGroup);
513 SetDlgItemText(g_hMain, IDC_PRODUCT_NAME, cinst.GetUninstallName());
514 SendDlgItemMessage(g_hMain, IDC_INSTALL_FONTS, BM_SETCHECK, BST_CHECKED, 0);
515 ShowWindow(g_hMain, SW_SHOWNORMAL);
516
517 return (g_hMain != (HWND)NULL); /* success */
518 }
519
520
521 // Main Modeless Dialog Box
522 BOOL CALLBACK
MainDlgProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)523 MainDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
524 {
525 switch(message) {
526 case WM_INITDIALOG:
527 EnableWindow(GetDlgItem(hwnd, IDC_ALLUSERS), is_winnt);
528 return TRUE;
529 case WM_COMMAND:
530 switch(LOWORD(wParam)) {
531 case IDC_README:
532 {
533 char buf[MAXSTR];
534 sprintf(buf, "%s\\%s\\doc\\Readme.htm", g_szSourceDir,
535 cinst.GetMainDir());
536 ShellExecute(hwnd, NULL, buf, NULL, g_szSourceDir,
537 SW_SHOWNORMAL);
538 }
539 return TRUE;
540 case IDC_BROWSE_DIR:
541 { char dir[MAXSTR];
542 char *p;
543 GetDlgItemText(hwnd, IDC_TARGET_DIR, dir, sizeof(dir));
544 strcpy(szDirName, dir);
545 if ( (p = strrchr(szDirName, '\\')) != (char *)NULL ) {
546 strcpy(szFolderName, p+1);
547 if (p == szDirName+2)
548 p++; // step over c:\ //
549 *p = '\0';
550 }
551 else {
552 strcpy(szDirName, "c:\\");
553 strcpy(szFolderName, dir);
554 }
555 if (DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_DIRDLG),
556 hwnd, DirDlgProc)) {
557 strcpy(dir, szDirName);
558 if (strlen(dir) && (dir[strlen(dir)-1] != '\\'))
559 strcat(dir, "\\");
560 strcat(dir, szFolderName);
561 SetDlgItemText(hwnd, IDC_TARGET_DIR, dir);
562 }
563 }
564 return TRUE;
565 case IDC_BROWSE_GROUP:
566 { char dir[MAXSTR];
567 char programs[MAXSTR];
568 char *p;
569 GetDlgItemText(hwnd, IDC_TARGET_GROUP, dir, sizeof(dir));
570 cinst.GetPrograms(
571 SendDlgItemMessage(hwnd, IDC_ALLUSERS,
572 BM_GETCHECK, 0, 0) == BST_CHECKED,
573 programs, sizeof(programs));
574 strcpy(szDirName, programs);
575 strcpy(szFolderName, dir);
576 if (DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_DIRDLG),
577 hwnd, DirDlgProc)) {
578 strcpy(dir, szFolderName);
579 p = szDirName;
580 if (strnicmp(szDirName, programs,
581 strlen(programs)) == 0) {
582 p += strlen(programs);
583 if (*p == '\\')
584 p++;
585 strcpy(dir, p);
586 if (strlen(dir) &&
587 (dir[strlen(dir)-1] != '\\'))
588 strcat(dir, "\\");
589 strcat(dir, szFolderName);
590 }
591 SetDlgItemText(hwnd, IDC_TARGET_GROUP, dir);
592 }
593 }
594 return TRUE;
595 case IDCANCEL:
596 PostQuitMessage(0);
597 return TRUE;
598 case IDC_INSTALL:
599 GetDlgItemText(hwnd, IDC_TARGET_DIR,
600 g_szTargetDir, sizeof(g_szTargetDir));
601 GetDlgItemText(hwnd, IDC_TARGET_GROUP,
602 g_szTargetGroup, sizeof(g_szTargetGroup));
603 g_bInstallFonts = (SendDlgItemMessage(g_hMain,
604 IDC_INSTALL_FONTS, BM_GETCHECK, 0, 0)
605 == BST_CHECKED);
606 g_bAllUsers = (SendDlgItemMessage(hwnd,
607 IDC_ALLUSERS, BM_GETCHECK, 0, 0
608 ) == BST_CHECKED);
609
610 // install log dialog box
611 g_hWndText = CreateDialogParam(g_hInstance,
612 MAKEINTRESOURCE(IDD_TEXTWIN),
613 (HWND)hwnd, TextWinDlgProc, (LPARAM)NULL);
614 EnableWindow(GetDlgItem(hwnd, IDC_INSTALL), FALSE);
615 if (install_all())
616 PostQuitMessage(0);
617 return TRUE;
618 default:
619 return(FALSE);
620 }
621 case WM_CLOSE:
622 PostQuitMessage(0);
623 return TRUE;
624 }
625 return FALSE;
626 }
627
628 // install program and files
629 BOOL
install_all()630 install_all()
631 {
632 gs_addmess("Source Directory=");
633 gs_addmess(g_szSourceDir);
634 gs_addmess("\n");
635 gs_addmess("Target Directory=");
636 gs_addmess(g_szTargetDir);
637 gs_addmess("\n");
638 gs_addmess("Target Shell Folder=");
639 gs_addmess(g_szTargetGroup);
640 gs_addmess("\n");
641 gs_addmess(g_bAllUsers ? " All users\n" : " Current user\n");
642
643 if (stricmp(g_szSourceDir, g_szTargetDir) == 0) {
644 // Don't copy files
645 if (!g_bBatch)
646 if (::MessageBox(g_hWndText, "Install location is the same as the current file location. No files will be copied.", g_szAppName, MB_OKCANCEL)
647 != IDOK) {
648 return FALSE;
649 }
650 g_bNoCopy = TRUE;
651 }
652
653
654 if (g_bQuit)
655 return FALSE;
656
657 if (!install_prog()) {
658 cinst.CleanUp();
659 g_bError = TRUE;
660 return FALSE;
661 }
662 if (g_bInstallFonts && !install_fonts()) {
663 cinst.CleanUp();
664 g_bError = TRUE;
665 return FALSE;
666 }
667
668 gs_addmess("Install successful\n");
669
670 // show start menu folder
671 if (!g_bBatch) {
672 char szFolder[MAXSTR];
673 szFolder[0] = '\0';
674 cinst.GetPrograms(g_bAllUsers, szFolder, sizeof(szFolder));
675 strcat(szFolder, "\\");
676 strcat(szFolder, g_szTargetGroup);
677 ShellExecute(HWND_DESKTOP, "open", szFolder,
678 NULL, NULL, SW_SHOWNORMAL);
679 }
680
681 #ifdef DEBUG
682 return FALSE;
683 #endif
684
685 return TRUE;
686 }
687
688 BOOL
install_prog()689 install_prog()
690 {
691 char *regkey1 = "GNU Ghostscript";
692 char regkey2[16];
693 char szDLL[MAXSTR];
694 char szLIB[MAXSTR];
695 char szProgram[MAXSTR];
696 char szArguments[MAXSTR];
697 char szDescription[MAXSTR];
698 char szDotVersion[MAXSTR];
699
700 if (g_bQuit)
701 return FALSE;
702
703 cinst.SetMessageFunction(gs_addmess);
704 cinst.SetTargetDir(g_szTargetDir);
705 cinst.SetTargetGroup(g_szTargetGroup);
706 cinst.SetAllUsers(g_bAllUsers);
707 if (!cinst.Init(g_szSourceDir, "filelist.txt"))
708 return FALSE;
709
710 // Get GS version number
711 gs_addmess("Installing Program...\n");
712 int nGSversion = 0;
713 const char *p = cinst.GetMainDir();
714 while (*p && !isdigit(*p)) // skip over "gs" prefix
715 p++;
716 if (strlen(p) == 4)
717 nGSversion = (p[0]-'0')*100 + (p[2]-'0')*10 + (p[3]-'0');
718 else if (strlen(p) == 3)
719 nGSversion = (p[0]-'0')*100 + (p[2]-'0')*10;
720 strncpy(szDotVersion, p, sizeof(szDotVersion));
721 strncpy(regkey2, szDotVersion, sizeof(regkey2));
722
723 // copy files
724 if (!cinst.InstallFiles(g_bNoCopy, &g_bQuit)) {
725 gs_addmess("Program install failed\n");
726 return FALSE;
727 }
728
729 if (g_bQuit)
730 return FALSE;
731
732 // write registry entries
733 gs_addmess("Updating Registry\n");
734 if (!cinst.UpdateRegistryBegin()) {
735 gs_addmess("Failed to begin registry update\n");
736 return FALSE;
737 }
738 if (!cinst.UpdateRegistryKey(regkey1, regkey2)) {
739 gs_addmess("Failed to open/create registry application key\n");
740 return FALSE;
741 }
742 strcpy(szDLL, g_szTargetDir);
743 strcat(szDLL, "\\");
744 strcat(szDLL, cinst.GetMainDir());
745 strcat(szDLL, "\\bin\\gsdll32.dll");
746 if (!cinst.UpdateRegistryValue(regkey1, regkey2, "GS_DLL", szDLL)) {
747 gs_addmess("Failed to add registry value\n");
748 return FALSE;
749 }
750 strcpy(szLIB, g_szTargetDir);
751 strcat(szLIB, "\\");
752 strcat(szLIB, cinst.GetMainDir());
753 strcat(szLIB, "\\lib;");
754 strcat(szLIB, g_szTargetDir);
755 strcat(szLIB, "\\fonts");
756 if (!cinst.UpdateRegistryValue(regkey1, regkey2, "GS_LIB", szLIB)) {
757 gs_addmess("Failed to add registry value\n");
758 return FALSE;
759 }
760 if (!cinst.UpdateRegistryEnd()) {
761 gs_addmess("Failed to end registry update\n");
762 return FALSE;
763 }
764 if (g_bQuit)
765 return FALSE;
766
767 // Add Start Menu items
768 gs_addmess("Adding Start Menu items\n");
769 if (!cinst.StartMenuBegin()) {
770 gs_addmess("Failed to begin Start Menu update\n");
771 return FALSE;
772 }
773 strcpy(szProgram, g_szTargetDir);
774 strcat(szProgram, "\\");
775 strcat(szProgram, cinst.GetMainDir());
776 strcat(szProgram, "\\bin\\gswin32.exe");
777 strcpy(szArguments, "\042-I");
778 strcat(szArguments, szLIB);
779 strcat(szArguments, "\042");
780 sprintf(szDescription, "Ghostscript %s", szDotVersion);
781 if (!cinst.StartMenuAdd(szDescription, szProgram, szArguments)) {
782 gs_addmess("Failed to add Start Menu item\n");
783 return FALSE;
784 }
785 strcpy(szProgram, g_szTargetDir);
786 strcat(szProgram, "\\");
787 strcat(szProgram, cinst.GetMainDir());
788 strcat(szProgram, "\\doc\\Readme.htm");
789 sprintf(szDescription, "Ghostscript Readme %s", szDotVersion);
790 if (!cinst.StartMenuAdd(szDescription, szProgram, NULL)) {
791 gs_addmess("Failed to add Start Menu item\n");
792 return FALSE;
793 }
794 if (!cinst.StartMenuEnd()) {
795 gs_addmess("Failed to end Start Menu update\n");
796 return FALSE;
797 }
798
799 // consolidate logs into one uninstall file
800 if (cinst.MakeLog()) {
801 // add uninstall entry for "Add/Remove Programs"
802 gs_addmess("Adding uninstall program\n");
803 if (!cinst.WriteUninstall(UNINSTALLPROG, g_bNoCopy)) {
804 gs_addmess("Failed to write uninstall entry\n");
805 return FALSE;
806 }
807 }
808 else {
809 gs_addmess("Failed to write uninstall log\n");
810 // If batch install, files might be on a server
811 // in a write protected directory.
812 // Don't return an error for batch install.
813 if (g_bBatch)
814 return TRUE;
815 return FALSE;
816 }
817
818 gs_addmess("Program install successful\n");
819 return TRUE;
820 }
821
822
823 BOOL
install_fonts()824 install_fonts()
825 {
826 cinst.SetMessageFunction(gs_addmess);
827 cinst.SetTargetDir(g_szTargetDir);
828 cinst.SetTargetGroup(g_szTargetGroup);
829 cinst.SetAllUsers(g_bAllUsers);
830 if (!cinst.Init(g_szSourceDir, "fontlist.txt"))
831 return FALSE;
832
833 // copy files
834 if (!cinst.InstallFiles(g_bNoCopy, &g_bQuit)) {
835 gs_addmess("Font install failed\n");
836 return FALSE;
837 }
838
839 if (g_bQuit)
840 return FALSE;
841
842 if (g_bNoCopy) {
843 // Don't write uninstall log or entry
844 // since we didn't copy any files.
845 cinst.CleanUp();
846 }
847 else {
848 // consolidate logs into one uninstall file
849 if (cinst.MakeLog()) {
850 // add uninstall entry for "Add/Remove Programs"
851 gs_addmess("Adding uninstall program\n");
852 if (!cinst.WriteUninstall(UNINSTALLPROG, g_bNoCopy)) {
853 gs_addmess("Failed to write uninstall entry\n");
854 return FALSE;
855 }
856 }
857 else {
858 gs_addmess("Failed to write uninstall log\n");
859 // If batch install, files might be on a server
860 // in a write protected directory.
861 // Don't return an error for batch install.
862 if (g_bBatch)
863 return TRUE;
864 return FALSE;
865 }
866 }
867
868 gs_addmess("Font install successful\n");
869 return TRUE;
870 }
871
872
873
874 //////////////////////////////////////////////////////////////////////
875 // Create file list
876 //////////////////////////////////////////////////////////////////////
877
878 FILE *fList;
879
880 typedef int (*PFN_dodir)(const char *name);
881
882 /* Called once for each directory */
883 int
dodir(const char * filename)884 dodir(const char *filename)
885 {
886 return 0;
887 }
888
889 /* Called once for each file */
890 int
dofile(const char * filename)891 dofile(const char *filename)
892 {
893 if (fList != (FILE *)NULL) {
894 fputs(filename, fList);
895 fputs("\n", fList);
896 }
897
898 return 0;
899 }
900
901
902 /* Walk through directory 'path', calling dodir() for given directory
903 * and dofile() for each file.
904 * If recurse=1, recurse into subdirectories, calling dodir() for
905 * each directory.
906 */
907 int
dirwalk(char * path,int recurse,PFN_dodir dodir,PFN_dodir dofile)908 dirwalk(char *path, int recurse, PFN_dodir dodir, PFN_dodir dofile)
909 {
910 WIN32_FIND_DATA find_data;
911 HANDLE find_handle;
912 char pattern[MAXSTR]; /* orig pattern + modified pattern */
913 char base[MAXSTR];
914 char name[MAXSTR];
915 BOOL bMore = TRUE;
916 char *p;
917
918
919 if (path) {
920 strcpy(pattern, path);
921 if (strlen(pattern) != 0) {
922 p = pattern + strlen(pattern) -1;
923 if (*p == '\\')
924 *p = '\0'; // truncate trailing backslash
925 }
926
927 strcpy(base, pattern);
928 if (strchr(base, '*') != NULL) {
929 // wildcard already included
930 // truncate it from the base path
931 if ( (p = strrchr(base, '\\')) != NULL )
932 *(++p) = '\0';
933 }
934 else if (isalpha(pattern[0]) &&
935 pattern[1]==':' && pattern[2]=='\0') {
936 strcat(pattern, "\\*"); // search entire disk
937 strcat(base, "\\");
938 }
939 else {
940 // wildcard NOT included
941 // check to see if path is a directory
942 find_handle = FindFirstFile(pattern, &find_data);
943 if (find_handle != INVALID_HANDLE_VALUE) {
944 FindClose(find_handle);
945 if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
946 strcat(pattern, "\\*"); // yes, search files
947 strcat(base, "\\");
948 }
949 else {
950 dofile(path); // no, return just this file
951 return 0;
952 }
953 }
954 else
955 return 1; // path invalid
956 }
957 }
958 else {
959 base[0] = '\0';
960 strcpy(pattern, "*");
961 }
962
963 find_handle = FindFirstFile(pattern, &find_data);
964 if (find_handle == INVALID_HANDLE_VALUE)
965 return 1;
966
967 while (bMore) {
968 strcpy(name, base);
969 strcat(name, find_data.cFileName);
970 if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
971 if ( strcmp(find_data.cFileName, ".") &&
972 strcmp(find_data.cFileName, "..") ) {
973 dodir(name);
974 if (recurse)
975 dirwalk(name, recurse, dodir, dofile);
976 }
977 }
978 else {
979 dofile(name);
980 }
981 bMore = FindNextFile(find_handle, &find_data);
982 }
983 FindClose(find_handle);
984
985 return 0;
986 }
987
988
989
990 // This is used when creating a file list.
991
make_filelist(int argc,char * argv[])992 BOOL make_filelist(int argc, char *argv[])
993 {
994 char *title = NULL;
995 char *dir = NULL;
996 char *list = NULL;
997 int i;
998 g_bBatch = TRUE; // Don't run message loop
999
1000 for (i=1; i<argc; i++) {
1001 if (strcmp(argv[i], "-title") == 0) {
1002 i++;
1003 title = argv[i];
1004 }
1005 else if (strcmp(argv[i], "-dir") == 0) {
1006 i++;
1007 dir = argv[i];
1008 }
1009 else if (strcmp(argv[i], "-list") == 0) {
1010 i++;
1011 list = argv[i];
1012 }
1013 else {
1014 if ((title == NULL) || (strlen(title) == 0) ||
1015 (dir == NULL) || (strlen(dir) == 0) ||
1016 (list == NULL) || (strlen(list) == 0)) {
1017 message_box("Usage: setupgs -title \042GNU Ghostscript #.##\042 -dir \042gs#.##\042 -list \042filelist.txt\042 spec1 spec2 specn\n");
1018 return FALSE;
1019 }
1020 if (fList == (FILE *)NULL) {
1021 if ( (fList = fopen(list, "w")) == (FILE *)NULL ) {
1022 message_box("Can't write list file\n");
1023 return FALSE;
1024 }
1025 fputs(title, fList);
1026 fputs("\n", fList);
1027 fputs(dir, fList);
1028 fputs("\n", fList);
1029 }
1030 if (argv[i][0] == '@') {
1031 // Use @filename with list of files/directories
1032 // to avoid DOS command line limit
1033 FILE *f;
1034 char buf[MAXSTR];
1035 int j;
1036 if ( (f = fopen(&(argv[i][1]), "r")) != (FILE *)NULL) {
1037 while (fgets(buf, sizeof(buf), f)) {
1038 // remove trailing newline and spaces
1039 while ( ((j = strlen(buf)-1) >= 0) &&
1040 ((buf[j] == '\n') || (buf[j] == ' ')) )
1041 buf[j] = '\0';
1042 dirwalk(buf, TRUE, &dodir, &dofile);
1043 }
1044 fclose(f);
1045 }
1046 else {
1047 wsprintf(buf, "Can't open @ file \042%s\042",
1048 &argv[i][1]);
1049 message_box(buf);
1050 }
1051 }
1052 else
1053 dirwalk(argv[i], TRUE, &dodir, &dofile);
1054 }
1055 }
1056
1057 if (fList != (FILE *)NULL) {
1058 fclose(fList);
1059 fList = NULL;
1060 }
1061 return TRUE;
1062 }
1063
1064 //////////////////////////////////////////////////////////////////////
1065