xref: /vim-8.2.3635/src/os_w32exe.c (revision 15d0a8c7)
1 /* vi:set ts=8 sts=4 sw=4:
2  *
3  * VIM - Vi IMproved		by Bram Moolenaar
4  *				GUI support by Robert Webb
5  *
6  * Do ":help uganda"  in Vim to read copying and usage conditions.
7  * Do ":help credits" in Vim to see a list of people who contributed.
8  * See README.txt for an overview of the Vim source code.
9  */
10 /*
11  * Windows GUI: main program (EXE) entry point:
12  *
13  * Ron Aaron <[email protected]> wrote this and  the DLL support code.
14  */
15 #include "vim.h"
16 
17 #ifdef __MINGW32__
18 # ifndef _cdecl
19 #  define _cdecl
20 # endif
21 #endif
22 
23 /* cproto doesn't create a prototype for main() */
24 int _cdecl
25 #if defined(FEAT_GUI_W32)
26 VimMain
27 #else
28     main
29 #endif
30 	__ARGS((int argc, char **argv));
31 int (_cdecl *pmain)(int, char **);
32 
33 #ifdef FEAT_MBYTE
34 /* The commandline arguments in UCS2. */
35 static DWORD	nArgsW = 0;
36 static LPWSTR	*ArglistW = NULL;
37 static int	global_argc;
38 static char	**global_argv;
39 
40 static int	used_file_argc = 0;	/* last argument in global_argv[] used
41 					   for the argument list. */
42 static int	*used_file_indexes = NULL; /* indexes in global_argv[] for
43 					      command line arguments added to
44 					      the argument list */
45 static int	used_file_count = 0;	/* nr of entries in used_file_indexes */
46 static int	used_file_literal = FALSE;  /* take file names literally */
47 static int	used_file_full_path = FALSE;  /* file name was full path */
48 static int	used_alist_count = 0;
49 #endif
50 
51 #ifndef PROTO
52 #ifdef FEAT_GUI
53 #ifndef VIMDLL
54 void _cdecl SaveInst(HINSTANCE hInst);
55 #endif
56 void (_cdecl *pSaveInst)(HINSTANCE);
57 #endif
58 
59     int WINAPI
60 WinMain(
61     HINSTANCE	hInstance,
62     HINSTANCE	hPrevInst,
63     LPSTR	lpszCmdLine,
64     int		nCmdShow)
65 {
66     int		argc = 0;
67     char	**argv;
68     char	*tofree;
69     char	prog[256];
70 #ifdef VIMDLL
71     char	*p;
72     HANDLE	hLib;
73 #endif
74 
75     /* Ron: added full path name so that the $VIM variable will get set to our
76      * startup path (so the .vimrc file can be found w/o a VIM env. var.) */
77     GetModuleFileName(NULL, prog, 255);
78 
79     /* Separate the command line into arguments.  Use the Unicode functions
80      * when possible. When 'encoding' is later changed these are used to
81      * recode the arguments. */
82 #ifdef FEAT_MBYTE
83     ArglistW = CommandLineToArgvW(GetCommandLineW(), &nArgsW);
84     if (ArglistW != NULL)
85     {
86 	argv = malloc((nArgsW + 1) * sizeof(char *));
87 	if (argv != NULL)
88 	{
89 	    int		i;
90 
91 	    argv[argc] = NULL;
92 	    argc = nArgsW;
93 	    for (i = 0; i < argc; ++i)
94 	    {
95 		int	len;
96 
97 		WideCharToMultiByte_alloc(GetACP(), 0,
98 				ArglistW[i], wcslen(ArglistW[i]) + 1,
99 				(LPSTR *)&argv[i], &len, 0, 0);
100 		if (argv[i] == NULL)
101 		{
102 		    while (i > 0)
103 			free(argv[--i]);
104 		    free(argv);
105 		    argc = 0;
106 		}
107 	    }
108 	}
109     }
110 
111     if (argc == 0)
112 #endif
113     {
114 	argc = get_cmd_args(prog, (char *)lpszCmdLine, &argv, &tofree);
115 	if (argc == 0)
116 	{
117 	    MessageBox(0, "Could not allocate memory for command line.",
118 								  "VIM Error", 0);
119 	    return 0;
120 	}
121     }
122 
123 #ifdef FEAT_MBYTE
124     global_argc = argc;
125     global_argv = argv;
126     used_file_indexes = malloc(argc * sizeof(int));
127 #endif
128 
129 #ifdef DYNAMIC_GETTEXT
130     /* Initialize gettext library */
131     dyn_libintl_init(NULL);
132 #endif
133 
134 #ifdef VIMDLL
135     // LoadLibrary - get name of dll to load in here:
136     p = strrchr(prog, '\\');
137     if (p != NULL)
138     {
139 # ifdef DEBUG
140 	strcpy(p+1, "vim32d.dll");
141 # else
142 	strcpy(p+1, "vim32.dll");
143 # endif
144     }
145     hLib = LoadLibrary(prog);
146     if (hLib == NULL)
147     {
148 	MessageBox(0, _("Could not load vim32.dll!"), _("VIM Error"), 0);
149 	goto errout;
150     }
151     // fix up the function pointers
152 # ifdef FEAT_GUI
153     pSaveInst = GetProcAddress(hLib, (LPCSTR)2);
154 # endif
155     pmain = GetProcAddress(hLib, (LPCSTR)1);
156     if (pmain == NULL)
157     {
158 	MessageBox(0, _("Could not fix up function pointers to the DLL!"),
159 							    _("VIM Error"),0);
160 	goto errout;
161     }
162 #else
163 # ifdef FEAT_GUI
164     pSaveInst = SaveInst;
165 # endif
166     pmain =
167 # if defined(FEAT_GUI_W32)
168     //&& defined(__MINGW32__)
169 	VimMain
170 # else
171 	main
172 # endif
173 	;
174 #endif
175 #ifdef FEAT_GUI
176     pSaveInst(
177 #ifdef __MINGW32__
178 	    GetModuleHandle(NULL)
179 #else
180 	    hInstance
181 #endif
182 	    );
183 #endif
184     pmain(argc, argv);
185 
186 #ifdef VIMDLL
187     FreeLibrary(hLib);
188 errout:
189 #endif
190     free(argv);
191     free(tofree);
192 #ifdef FEAT_MBYTE
193     if (ArglistW != NULL)
194 	GlobalFree(ArglistW);
195 #endif
196 
197     return 0;
198 }
199 #endif
200 
201 #ifdef FEAT_MBYTE
202 /*
203  * Remember "name" is an argument that was added to the argument list.
204  * This avoids that we have to re-parse the argument list when fix_arg_enc()
205  * is called.
206  */
207     void
208 used_file_arg(name, literal, full_path)
209     char	*name;
210     int		literal;
211     int		full_path;
212 {
213     int		i;
214 
215     if (used_file_indexes == NULL)
216 	return;
217     for (i = used_file_argc + 1; i < global_argc; ++i)
218 	if (STRCMP(global_argv[i], name) == 0)
219 	{
220 	    used_file_argc = i;
221 	    used_file_indexes[used_file_count++] = i;
222 	    break;
223 	}
224     used_file_literal = literal;
225     used_file_full_path = full_path;
226 }
227 
228 /*
229  * Remember the length of the argument list as it was.  If it changes then we
230  * leave it alone when 'encoding' is set.
231  */
232     void
233 set_alist_count(void)
234 {
235     used_alist_count = GARGCOUNT;
236 }
237 
238 /*
239  * Fix the encoding of the command line arguments.  Invoked when 'encoding'
240  * has been changed while starting up.  Use the UCS-2 command line arguments
241  * and convert them to 'encoding'.
242  */
243     void
244 fix_arg_enc()
245 {
246     int		i;
247     int		idx;
248     char_u	*str;
249 
250     /* Safety checks:
251      * - if argument count differs between the wide and non-wide argument
252      *   list, something must be wrong.
253      * - the file name arguments must have been located.
254      * - the length of the argument list wasn't changed by the user.
255      */
256     if (global_argc != (int)nArgsW
257 	    || ArglistW == NULL
258 	    || used_file_indexes == NULL
259 	    || used_file_count == 0
260 	    || used_alist_count != GARGCOUNT)
261 	return;
262 
263     /* Clear the argument list.  Make room for the new arguments. */
264     alist_clear(&global_alist);
265     if (ga_grow(&global_alist.al_ga, used_file_count) == FAIL)
266 	return;	    /* out of memory */
267 
268     for (i = 0; i < used_file_count; ++i)
269     {
270 	idx = used_file_indexes[i];
271 	str = ucs2_to_enc(ArglistW[idx], NULL);
272 	if (str != NULL)
273 	    alist_add(&global_alist, str, used_file_literal ? 2 : 0);
274     }
275 
276     if (!used_file_literal)
277     {
278 	/* Now expand wildcards in the arguments. */
279 	/* Temporarily add '(' and ')' to 'isfname'.  These are valid
280 	 * filename characters but are excluded from 'isfname' to make
281 	 * "gf" work on a file name in parenthesis (e.g.: see vim.h). */
282 	do_cmdline_cmd((char_u *)":let SaVe_ISF = &isf|set isf+=(,)");
283 	alist_expand();
284 	do_cmdline_cmd((char_u *)":let &isf = SaVe_ISF|unlet SaVe_ISF");
285     }
286 
287     /* If wildcard expansion failed, we are editing the first file of the
288      * arglist and there is no file name: Edit the first argument now. */
289     if (curwin->w_arg_idx == 0 && curbuf->b_fname == NULL)
290     {
291 	do_cmdline_cmd((char_u *)":rewind");
292 	if (GARGCOUNT == 1 && used_file_full_path)
293 	    (void)vim_chdirfile(alist_name(&GARGLIST[0]));
294     }
295 }
296 #endif
297 
298