comparison src/dosinst.h @ 7:3fc0f57ecb91 v7.0001

updated for version 7.0001
author vimboss
date Sun, 13 Jun 2004 20:20:40 +0000
parents
children 0f9f4761ad9c
comparison
equal deleted inserted replaced
6:c2daee826b8f 7:3fc0f57ecb91
1 /* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9 /*
10 * dosinst.h: Common code for dosinst.c and uninstal.c
11 */
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17
18 #ifndef UNIX_LINT
19 # include <io.h>
20 # include <ctype.h>
21
22 # ifndef __CYGWIN__
23 # include <direct.h>
24 # endif
25
26 # if defined(_WIN64) || defined(WIN32)
27 # define WIN3264
28 # include <windows.h>
29 # include <shlobj.h>
30 # else
31 # include <dir.h>
32 # include <bios.h>
33 # include <dos.h>
34 # endif
35 #endif
36
37 #ifdef UNIX_LINT
38 /* Running lint on Unix: Some things are missing. */
39 char *searchpath(char *name);
40 #endif
41
42 #if defined(DJGPP) || defined(UNIX_LINT)
43 # include <unistd.h>
44 # include <errno.h>
45 #endif
46
47 #include "version.h"
48
49 #if defined(DJGPP) || defined(UNIX_LINT)
50 # define vim_mkdir(x, y) mkdir((char *)(x), y)
51 #else
52 # if defined(WIN3264) && !defined(__BORLANDC__)
53 # define vim_mkdir(x, y) _mkdir((char *)(x))
54 # else
55 # define vim_mkdir(x, y) mkdir((char *)(x))
56 # endif
57 #endif
58 /* ---------------------------------------- */
59
60
61 #define BUFSIZE 512 /* long enough to hold a file name path */
62 #define NUL 0
63
64 #define FAIL 0
65 #define OK 1
66
67 #ifndef FALSE
68 # define FALSE 0
69 #endif
70 #ifndef TRUE
71 # define TRUE 1
72 #endif
73
74 #define VIM_STARTMENU "Programs\\Vim " VIM_VERSION_SHORT
75
76 int interactive; /* non-zero when running interactively */
77
78 /*
79 * Call malloc() and exit when out of memory.
80 */
81 static void *
82 alloc(int len)
83 {
84 char *s;
85
86 s = malloc(len);
87 if (s == NULL)
88 {
89 printf("ERROR: out of memory\n");
90 exit(1);
91 }
92 return (void *)s;
93 }
94
95 /*
96 * The toupper() in Bcc 5.5 doesn't work, use our own implementation.
97 */
98 static int
99 mytoupper(int c)
100 {
101 if (c >= 'a' && c <= 'z')
102 return c - 'a' + 'A';
103 return c;
104 }
105
106 static void
107 myexit(int n)
108 {
109 if (!interactive)
110 {
111 /* Present a prompt, otherwise error messages can't be read. */
112 printf("Press Enter to continue\n");
113 rewind(stdin);
114 (void)getchar();
115 }
116 exit(n);
117 }
118
119 #ifdef WIN3264
120 /* This symbol is not defined in older versions of the SDK or Visual C++ */
121
122 #ifndef VER_PLATFORM_WIN32_WINDOWS
123 # define VER_PLATFORM_WIN32_WINDOWS 1
124 #endif
125
126 static DWORD g_PlatformId;
127
128 /*
129 * Set g_PlatformId to VER_PLATFORM_WIN32_NT (NT) or
130 * VER_PLATFORM_WIN32_WINDOWS (Win95).
131 */
132 static void
133 PlatformId(void)
134 {
135 static int done = FALSE;
136
137 if (!done)
138 {
139 OSVERSIONINFO ovi;
140
141 ovi.dwOSVersionInfoSize = sizeof(ovi);
142 GetVersionEx(&ovi);
143
144 g_PlatformId = ovi.dwPlatformId;
145 done = TRUE;
146 }
147 }
148
149 # ifdef __BORLANDC__
150 /* Borland defines its own searchpath() in dir.h */
151 # include <dir.h>
152 # else
153 static char *
154 searchpath(char *name)
155 {
156 static char widename[2 * BUFSIZE];
157 static char location[2 * BUFSIZE + 2];
158
159 /* There appears to be a bug in FindExecutableA() on Windows NT.
160 * Use FindExecutableW() instead... */
161 PlatformId();
162 if (g_PlatformId == VER_PLATFORM_WIN32_NT)
163 {
164 MultiByteToWideChar(CP_ACP, 0, (LPCTSTR)name, -1,
165 (LPWSTR)widename, BUFSIZE);
166 if (FindExecutableW((LPCWSTR)widename, (LPCWSTR)"",
167 (LPWSTR)location) > (HINSTANCE)32)
168 {
169 WideCharToMultiByte(CP_ACP, 0, (LPWSTR)location, -1,
170 (LPSTR)widename, 2 * BUFSIZE, NULL, NULL);
171 return widename;
172 }
173 }
174 else
175 {
176 if (FindExecutableA((LPCTSTR)name, (LPCTSTR)"",
177 (LPTSTR)location) > (HINSTANCE)32)
178 return location;
179 }
180 return NULL;
181 }
182 # endif
183 #endif
184
185 /*
186 * Call searchpath() and save the result in allocated memory, or return NULL.
187 */
188 static char *
189 searchpath_save(char *name)
190 {
191 char *p;
192 char *s;
193
194 p = searchpath(name);
195 if (p == NULL)
196 return NULL;
197 s = alloc(strlen(p) + 1);
198 strcpy(s, p);
199 return s;
200 }
201
202 #ifdef WIN3264
203 /*
204 * Get the path to a requested Windows shell folder.
205 *
206 * Return FAIL on error, OK on success
207 */
208 int
209 get_shell_folder_path(
210 char *shell_folder_path,
211 const char *shell_folder_name)
212 {
213 /*
214 * The following code was successfully built with make_mvc.mak.
215 * The resulting executable worked on Windows 95, Millennium Edition, and
216 * 2000 Professional. But it was changed after testing...
217 */
218 LPITEMIDLIST pidl = 0; /* Pointer to an Item ID list allocated below */
219 LPMALLOC pMalloc; /* Pointer to an IMalloc interface */
220 int csidl;
221 int alt_csidl = -1;
222 static int desktop_csidl = -1;
223 static int programs_csidl = -1;
224 int *pcsidl;
225 int r;
226
227 if (strcmp(shell_folder_name, "desktop") == 0)
228 {
229 pcsidl = &desktop_csidl;
230 #ifdef CSIDL_COMMON_DESKTOPDIRECTORY
231 csidl = CSIDL_COMMON_DESKTOPDIRECTORY;
232 alt_csidl = CSIDL_DESKTOP;
233 #else
234 csidl = CSIDL_DESKTOP;
235 #endif
236 }
237 else if (strncmp(shell_folder_name, "Programs", 8) == 0)
238 {
239 pcsidl = &programs_csidl;
240 #ifdef CSIDL_COMMON_PROGRAMS
241 csidl = CSIDL_COMMON_PROGRAMS;
242 alt_csidl = CSIDL_PROGRAMS;
243 #else
244 csidl = CSIDL_PROGRAMS;
245 #endif
246 }
247 else
248 {
249 printf("\nERROR (internal) unrecognised shell_folder_name: \"%s\"\n\n",
250 shell_folder_name);
251 return FAIL;
252 }
253
254 /* Did this stuff before, use the same ID again. */
255 if (*pcsidl >= 0)
256 {
257 csidl = *pcsidl;
258 alt_csidl = -1;
259 }
260
261 retry:
262 /* Initialize pointer to IMalloc interface */
263 if (NOERROR != SHGetMalloc(&pMalloc))
264 {
265 printf("\nERROR getting interface for shell_folder_name: \"%s\"\n\n",
266 shell_folder_name);
267 return FAIL;
268 }
269
270 /* Get an ITEMIDLIST corresponding to the folder code */
271 if (NOERROR != SHGetSpecialFolderLocation(0, csidl, &pidl))
272 {
273 if (alt_csidl < 0 || NOERROR != SHGetSpecialFolderLocation(0,
274 alt_csidl, &pidl))
275 {
276 printf("\nERROR getting ITEMIDLIST for shell_folder_name: \"%s\"\n\n",
277 shell_folder_name);
278 return FAIL;
279 }
280 csidl = alt_csidl;
281 alt_csidl = -1;
282 }
283
284 /* Translate that ITEMIDLIST to a string */
285 r = SHGetPathFromIDList(pidl, shell_folder_path);
286
287 /* Free the data associated with pidl */
288 pMalloc->lpVtbl->Free(pMalloc, pidl);
289 /* Release the IMalloc interface */
290 pMalloc->lpVtbl->Release(pMalloc);
291
292 if (!r)
293 {
294 if (alt_csidl >= 0)
295 {
296 /* We probably get here for Windows 95: the "all users"
297 * desktop/start menu entry doesn't exist. */
298 csidl = alt_csidl;
299 alt_csidl = -1;
300 goto retry;
301 }
302 printf("\nERROR translating ITEMIDLIST for shell_folder_name: \"%s\"\n\n",
303 shell_folder_name);
304 return FAIL;
305 }
306
307 /* If there is an alternative: verify we can write in this directory.
308 * This should cause a retry when the "all users" directory exists but we
309 * are a normal user and can't write there. */
310 if (alt_csidl >= 0)
311 {
312 char tbuf[BUFSIZE];
313 FILE *fd;
314
315 strcpy(tbuf, shell_folder_path);
316 strcat(tbuf, "\\vim write test");
317 fd = fopen(tbuf, "w");
318 if (fd == NULL)
319 {
320 csidl = alt_csidl;
321 alt_csidl = -1;
322 goto retry;
323 }
324 fclose(fd);
325 unlink(tbuf);
326 }
327
328 /*
329 * Keep the found csidl for next time, so that we don't have to do the
330 * write test every time.
331 */
332 if (*pcsidl < 0)
333 *pcsidl = csidl;
334
335 if (strncmp(shell_folder_name, "Programs\\", 9) == 0)
336 strcat(shell_folder_path, shell_folder_name + 8);
337
338 return OK;
339 }
340 #endif
341
342 /*
343 * List of targets. The first one (index zero) is used for the default path
344 * for the batch files.
345 */
346 #define TARGET_COUNT 8
347
348 struct
349 {
350 char *name; /* Vim exe name (without .exe) */
351 char *batname; /* batch file name */
352 char *lnkname; /* shortcut file name */
353 char *exename; /* exe file name */
354 char *exenamearg; /* exe file name when using exearg */
355 char *exearg; /* argument for vim.exe or gvim.exe */
356 char *oldbat; /* path to existing xxx.bat or NULL */
357 char *oldexe; /* path to existing xxx.exe or NULL */
358 char batpath[BUFSIZE]; /* path of batch file to create; not
359 created when it's empty */
360 } targets[TARGET_COUNT] =
361 {
362 {"all", "batch files"},
363 {"vim", "vim.bat", "Vim.lnk",
364 "vim.exe", "vim.exe", ""},
365 {"gvim", "gvim.bat", "gVim.lnk",
366 "gvim.exe", "gvim.exe", ""},
367 {"evim", "evim.bat", "gVim Easy.lnk",
368 "evim.exe", "gvim.exe", "-y"},
369 {"view", "view.bat", "Vim Read-only.lnk",
370 "view.exe", "vim.exe", "-R"},
371 {"gview", "gview.bat", "gVim Read-only.lnk",
372 "gview.exe", "gvim.exe", "-R"},
373 {"vimdiff", "vimdiff.bat", "Vim Diff.lnk",
374 "vimdiff.exe","vim.exe", "-d"},
375 {"gvimdiff","gvimdiff.bat", "gVim Diff.lnk",
376 "gvimdiff.exe","gvim.exe", "-d"},
377 };
378
379 #define ICON_COUNT 3
380 char *(icon_names[ICON_COUNT]) =
381 {"gVim " VIM_VERSION_SHORT,
382 "gVim Easy " VIM_VERSION_SHORT,
383 "gVim Read only " VIM_VERSION_SHORT};
384 char *(icon_link_names[ICON_COUNT]) =
385 {"gVim " VIM_VERSION_SHORT ".lnk",
386 "gVim Easy " VIM_VERSION_SHORT ".lnk",
387 "gVim Read only " VIM_VERSION_SHORT ".lnk"};
388
389 /* This is only used for dosinst.c and for uninstal.c when not being able to
390 * directly access registry entries. */
391 #if !defined(WIN3264) || defined(DOSINST)
392 /*
393 * Run an external command and wait for it to finish.
394 */
395 static void
396 run_command(char *cmd)
397 {
398 char *cmd_path;
399 char cmd_buf[BUFSIZE];
400 char *p;
401
402 /* On WinNT, 'start' is a shell built-in for cmd.exe rather than an
403 * executable (start.exe) like in Win9x. DJGPP, being a DOS program,
404 * is given the COMSPEC command.com by WinNT, so we have to find
405 * cmd.exe manually and use it. */
406 cmd_path = searchpath_save("cmd.exe");
407 if (cmd_path != NULL)
408 {
409 /* There is a cmd.exe, so this might be Windows NT. If it is,
410 * we need to call cmd.exe explicitly. If it is a later OS,
411 * calling cmd.exe won't hurt if it is present.
412 * Also, "wait" on NT expects a window title argument.
413 */
414 /* Replace the slashes with backslashes. */
415 while ((p = strchr(cmd_path, '/')) != NULL)
416 *p = '\\';
417 sprintf(cmd_buf, "%s /c start \"vimcmd\" /w %s", cmd_path, cmd);
418 free(cmd_path);
419 }
420 else
421 {
422 /* No cmd.exe, just make the call and let the system handle it. */
423 sprintf(cmd_buf, "start /w %s", cmd);
424 }
425 system(cmd_buf);
426 }
427 #endif
428
429 /*
430 * Append a backslash to "name" if there isn't one yet.
431 */
432 static void
433 add_pathsep(char *name)
434 {
435 int len = strlen(name);
436
437 if (len > 0 && name[len - 1] != '\\' && name[len - 1] != '/')
438 strcat(name, "\\");
439 }
440
441 /*
442 * The normal chdir() does not change the default drive. This one does.
443 */
444 /*ARGSUSED*/
445 int
446 change_drive(int drive)
447 {
448 #ifdef WIN3264
449 char temp[3] = "-:";
450 temp[0] = (char)(drive + 'A' - 1);
451 return !SetCurrentDirectory(temp);
452 #else
453 # ifndef UNIX_LINT
454 union REGS regs;
455
456 regs.h.ah = 0x0e;
457 regs.h.dl = drive - 1;
458 intdos(&regs, &regs); /* set default drive */
459 regs.h.ah = 0x19;
460 intdos(&regs, &regs); /* get default drive */
461 if (regs.h.al == drive - 1)
462 return 0;
463 # endif
464 return -1;
465 #endif
466 }
467
468 /*
469 * Change directory to "path".
470 * Return 0 for success, -1 for failure.
471 */
472 int
473 mch_chdir(char *path)
474 {
475 if (path[0] == NUL) /* just checking... */
476 return 0;
477 if (path[1] == ':') /* has a drive name */
478 {
479 if (change_drive(mytoupper(path[0]) - 'A' + 1))
480 return -1; /* invalid drive name */
481 path += 2;
482 }
483 if (*path == NUL) /* drive name only */
484 return 0;
485 return chdir(path); /* let the normal chdir() do the rest */
486 }
487
488 /*
489 * Expand the executable name into a full path name.
490 */
491 #if defined(__BORLANDC__) && !defined(WIN3264)
492
493 /* Only Borland C++ has this. */
494 # define my_fullpath(b, n, l) _fullpath(b, n, l)
495
496 #else
497 static char *
498 my_fullpath(char *buf, char *fname, int len)
499 {
500 # ifdef WIN3264
501 /* Only GetModuleFileName() will get the long file name path.
502 * GetFullPathName() may still use the short (FAT) name. */
503 DWORD len_read = GetModuleFileName(NULL, buf, (size_t)len);
504
505 return (len_read > 0 && len_read < (DWORD)len) ? buf : NULL;
506 # else
507 char olddir[BUFSIZE];
508 char *p, *q;
509 int c;
510 char *retval = buf;
511
512 if (strchr(fname, ':') != NULL) /* allready expanded */
513 {
514 strncpy(buf, fname, len);
515 }
516 else
517 {
518 *buf = NUL;
519 /*
520 * change to the directory for a moment,
521 * and then do the getwd() (and get back to where we were).
522 * This will get the correct path name with "../" things.
523 */
524 p = strrchr(fname, '/');
525 q = strrchr(fname, '\\');
526 if (q != NULL && (p == NULL || q > p))
527 p = q;
528 q = strrchr(fname, ':');
529 if (q != NULL && (p == NULL || q > p))
530 p = q;
531 if (p != NULL)
532 {
533 if (getcwd(olddir, BUFSIZE) == NULL)
534 {
535 p = NULL; /* can't get current dir: don't chdir */
536 retval = NULL;
537 }
538 else
539 {
540 if (p == fname) /* /fname */
541 q = p + 1; /* -> / */
542 else if (q + 1 == p) /* ... c:\foo */
543 q = p + 1; /* -> c:\ */
544 else /* but c:\foo\bar */
545 q = p; /* -> c:\foo */
546
547 c = *q; /* truncate at start of fname */
548 *q = NUL;
549 if (mch_chdir(fname)) /* change to the directory */
550 retval = NULL;
551 else
552 {
553 fname = q;
554 if (c == '\\') /* if we cut the name at a */
555 fname++; /* '\', don't add it again */
556 }
557 *q = c;
558 }
559 }
560 if (getcwd(buf, len) == NULL)
561 {
562 retval = NULL;
563 *buf = NUL;
564 }
565 /*
566 * Concatenate the file name to the path.
567 */
568 if (strlen(buf) + strlen(fname) >= len - 1)
569 {
570 printf("ERROR: File name too long!\n");
571 myexit(1);
572 }
573 add_pathsep(buf);
574 strcat(buf, fname);
575 if (p)
576 mch_chdir(olddir);
577 }
578
579 /* Replace forward slashes with backslashes, required for the path to a
580 * command. */
581 while ((p = strchr(buf, '/')) != NULL)
582 *p = '\\';
583
584 return retval;
585 # endif
586 }
587 #endif
588
589 /*
590 * Remove the tail from a file or directory name.
591 * Puts a NUL on the last '/' or '\'.
592 */
593 static void
594 remove_tail(char *path)
595 {
596 int i;
597
598 for (i = strlen(path) - 1; i > 0; --i)
599 if (path[i] == '/' || path[i] == '\\')
600 {
601 path[i] = NUL;
602 break;
603 }
604 }
605
606
607 char installdir[BUFSIZE]; /* top of the installation dir, where the
608 install.exe is located, E.g.:
609 "c:\vim\vim60" */
610 int runtimeidx; /* index in installdir[] where "vim60" starts */
611 char *sysdrive; /* system drive or "c:\" */
612
613 /*
614 * Setup for using this program.
615 * Sets "installdir[]".
616 */
617 static void
618 do_inits(char **argv)
619 {
620 #ifdef DJGPP
621 /*
622 * Use Long File Names by default, if $LFN not set.
623 */
624 if (getenv("LFN") == NULL)
625 putenv("LFN=y");
626 #endif
627
628 /* Find out the full path of our executable. */
629 if (my_fullpath(installdir, argv[0], BUFSIZE) == NULL)
630 {
631 printf("ERROR: Cannot get name of executable\n");
632 myexit(1);
633 }
634 /* remove the tail, the executable name "install.exe" */
635 remove_tail(installdir);
636
637 /* change to the installdir */
638 mch_chdir(installdir);
639
640 /* Find the system drive. Only used for searching the Vim executable, not
641 * very important. */
642 sysdrive = getenv("SYSTEMDRIVE");
643 if (sysdrive == NULL || *sysdrive == NUL)
644 sysdrive = "C:\\";
645 }