Mercurial > vim
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(®s, ®s); /* set default drive */ | |
459 regs.h.ah = 0x19; | |
460 intdos(®s, ®s); /* 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 } |