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 * os_win16.c
11 *
12 * Win16 (Windows 3.1x) system-dependent routines.
13 * Carved brutally from os_win32.c by Vince Negri <vn@aslnet.co.uk>
14 */
15#ifdef __BORLANDC__
16# pragma warn -par
17# pragma warn -ucp
18# pragma warn -use
19# pragma warn -aus
20# pragma warn -obs
21#endif
22
23#include "vimio.h"
24#include "vim.h"
25
26#include <dos.h>
27#include <string.h>
28#include <sys/types.h>
29#include <errno.h>
30#include <signal.h>
31#include <limits.h>
32#include <process.h>
33
34#undef chdir
35#include <direct.h>
36#include <shellapi.h>	/* required for FindExecutable() */
37
38
39/* Record all output and all keyboard & mouse input */
40/* #define MCH_WRITE_DUMP */
41
42#ifdef MCH_WRITE_DUMP
43FILE* fdDump = NULL;
44#endif
45
46
47/*
48 * When generating prototypes for Win32 on Unix, these lines make the syntax
49 * errors disappear.  They do not need to be correct.
50 */
51#ifdef PROTO
52typedef int HANDLE;
53typedef int SMALL_RECT;
54typedef int COORD;
55typedef int SHORT;
56typedef int WORD;
57typedef int DWORD;
58typedef int BOOL;
59typedef int LPSTR;
60typedef int LPTSTR;
61typedef int KEY_EVENT_RECORD;
62typedef int MOUSE_EVENT_RECORD;
63# define WINAPI
64typedef int CONSOLE_CURSOR_INFO;
65typedef char * LPCSTR;
66# define WINBASEAPI
67typedef int INPUT_RECORD;
68# define _cdecl
69#endif
70
71#ifdef __BORLANDC__
72/* being a more ANSI compliant compiler, BorlandC doesn't define _stricoll:
73 * but it does in BC 5.02! */
74# if __BORLANDC__ < 0x502
75int _stricoll(char *a, char *b);
76# endif
77#endif
78
79/* cproto doesn't create a prototype for main() */
80int _cdecl
81VimMain
82__ARGS((int argc, char **argv));
83static int (_cdecl *pmain)(int, char **);
84
85#ifndef PROTO
86void _cdecl SaveInst(HINSTANCE hInst);
87static void (_cdecl *pSaveInst)(HINSTANCE);
88
89int WINAPI
90WinMain(
91    HINSTANCE	hInstance,
92    HINSTANCE	hPrevInst,
93    LPSTR	lpszCmdLine,
94    int		nCmdShow)
95{
96    int		argc;
97    char	**argv;
98    char	*tofree;
99    char	prog[256];
100
101    /*
102     * Ron: added full path name so that the $VIM variable will get set to our
103     * startup path (so the .vimrc file can be found w/o a VIM env. var.)
104     * Remove the ".exe" extension, and find the 1st non-space.
105     */
106    GetModuleFileName(hInstance, prog, 255);
107    if (*prog != NUL)
108	exe_name = FullName_save((char_u *)prog, FALSE);
109
110    /* Separate the command line into arguments. */
111    argc = get_cmd_args(prog, (char *)lpszCmdLine, &argv, &tofree);
112    if (argc == 0)
113    {
114	/* Error message? */
115	return 0;
116    }
117
118    pSaveInst = SaveInst;
119    pmain = VimMain;
120    pSaveInst(hInstance);
121    pmain(argc, argv);
122
123    free(argv);
124    if (tofree != NULL)
125	free(tofree);
126
127    return 0;
128}
129#endif
130
131
132
133
134
135
136#ifdef FEAT_MOUSE
137
138/*
139 * For the GUI the mouse handling is in gui_w32.c.
140 */
141    void
142mch_setmouse(
143    int on)
144{
145}
146#endif /* FEAT_MOUSE */
147
148
149
150/*
151 * GUI version of mch_init().
152 */
153    void
154mch_init()
155{
156    extern int _fmode;
157
158
159    /* Let critical errors result in a failure, not in a dialog box.  Required
160     * for the timestamp test to work on removed floppies. */
161    SetErrorMode(SEM_FAILCRITICALERRORS);
162
163    _fmode = O_BINARY;		/* we do our own CR-LF translation */
164
165    /* Specify window size.  Is there a place to get the default from? */
166    Rows = 25;
167    Columns = 80;
168
169
170    set_option_value((char_u *)"grepprg", 0, (char_u *)"grep -n", 0);
171
172#ifdef FEAT_CLIPBOARD
173    clip_init(TRUE);
174
175    /*
176     * Vim's own clipboard format recognises whether the text is char, line,
177     * or rectangular block.  Only useful for copying between two Vims.
178     * "VimClipboard" was used for previous versions, using the first
179     * character to specify MCHAR, MLINE or MBLOCK.
180     */
181    clip_star.format = RegisterClipboardFormat("VimClipboard2");
182    clip_star.format_raw = RegisterClipboardFormat("VimRawBytes");
183#endif
184}
185
186
187
188/*
189 * Do we have an interactive window?
190 */
191    int
192mch_check_win(
193    int argc,
194    char **argv)
195{
196    return OK;	    /* GUI always has a tty */
197}
198
199
200/*
201 * return process ID
202 */
203    long
204mch_get_pid()
205{
206    return (long)GetCurrentTask();
207}
208
209
210/*
211 * Specialised version of system().
212 * This version proceeds as follows:
213 *    1. Start the program with WinExec
214 *    2. Wait for the module use count of the program to go to 0
215 *	 (This is the best way of detecting the program has finished)
216 */
217
218    static int
219mch_system(char *cmd, int options)
220{
221    DWORD		ret = 0;
222    UINT		wShowWindow;
223    UINT		h_module;
224    MSG			msg;
225    BOOL		again = TRUE;
226
227    /*
228     * It's nicer to run a filter command in a minimized window, but in
229     */
230    if (options & SHELL_DOOUT)
231	wShowWindow = SW_SHOWMINIMIZED;
232    else
233	wShowWindow = SW_SHOWNORMAL;
234
235    /* Now, run the command */
236    h_module = WinExec((LPCSTR)cmd, wShowWindow);
237
238    if (h_module < 32)
239    {
240	/*error*/
241	ret = -h_module;
242    }
243    else
244    {
245	/* Wait for the command to terminate before continuing */
246	while (GetModuleUsage((HINSTANCE)h_module) > 0 && again )
247	{
248	    while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) && again )
249	    {
250		if(msg.message == WM_QUIT)
251
252		{
253		    PostQuitMessage(msg.wParam);
254		    again = FALSE;
255		}
256		TranslateMessage(&msg);
257		DispatchMessage(&msg);
258	    }
259	}
260    }
261
262    return ret;
263}
264
265/*
266 * Either execute a command by calling the shell or start a new shell
267 */
268    int
269mch_call_shell(
270    char_u *cmd,
271    int options)	    /* SHELL_, see vim.h */
272{
273    int		x;
274    int		tmode = cur_tmode;
275
276    out_flush();
277
278
279#ifdef MCH_WRITE_DUMP
280    if (fdDump)
281    {
282	fprintf(fdDump, "mch_call_shell(\"%s\", %d)\n", cmd, options);
283	fflush(fdDump);
284    }
285#endif
286
287    /*
288     * Catch all deadly signals while running the external command, because a
289     * CTRL-C, Ctrl-Break or illegal instruction  might otherwise kill us.
290     */
291    signal(SIGINT, SIG_IGN);
292    signal(SIGILL, SIG_IGN);
293    signal(SIGFPE, SIG_IGN);
294    signal(SIGSEGV, SIG_IGN);
295    signal(SIGTERM, SIG_IGN);
296    signal(SIGABRT, SIG_IGN);
297
298    if (options & SHELL_COOKED)
299	settmode(TMODE_COOK);	/* set to normal mode */
300
301    if (cmd == NULL)
302    {
303	x = mch_system(p_sh, options);
304    }
305    else
306    {
307	/* we use "command" or "cmd" to start the shell; slow but easy */
308	char_u *newcmd;
309
310	newcmd = lalloc(
311		STRLEN(p_sh) + STRLEN(p_shcf) + STRLEN(cmd) + 10, TRUE);
312	if (newcmd != NULL)
313	{
314	    if (STRNICMP(cmd, "start ", 6) == 0)
315	    {
316		sprintf((char *)newcmd, "%s\0", cmd+6);
317		if (WinExec((LPCSTR)newcmd, SW_SHOWNORMAL) > 31)
318		    x = 0;
319		else
320		    x = -1;
321	    }
322	    else
323	    {
324		sprintf((char *)newcmd, "%s%s %s %s",
325			"",
326			p_sh,
327			p_shcf,
328			cmd);
329		x = mch_system((char *)newcmd, options);
330	    }
331	    vim_free(newcmd);
332	}
333    }
334
335    if (tmode == TMODE_RAW)
336	settmode(TMODE_RAW);	/* set to raw mode */
337
338    if (x && !(options & SHELL_SILENT) && !emsg_silent)
339    {
340	smsg(_("shell returned %d"), x);
341	msg_putchar('\n');
342    }
343#ifdef FEAT_TITLE
344    resettitle();
345#endif
346
347    signal(SIGINT, SIG_DFL);
348    signal(SIGILL, SIG_DFL);
349    signal(SIGFPE, SIG_DFL);
350    signal(SIGSEGV, SIG_DFL);
351    signal(SIGTERM, SIG_DFL);
352    signal(SIGABRT, SIG_DFL);
353
354
355    return x;
356}
357
358
359/*
360 * Delay for half a second.
361 */
362    void
363mch_delay(
364    long    msec,
365    int	    ignoreinput)
366{
367#ifdef MUST_FIX
368    Sleep((int)msec);	    /* never wait for input */
369#endif
370}
371
372
373/*
374 * check for an "interrupt signal": CTRL-break or CTRL-C
375 */
376    void
377mch_breakcheck()
378{
379    /* never used */
380}
381
382
383/*
384 * How much memory is available?
385 */
386    long_u
387mch_avail_mem(
388    int special)
389{
390    return GetFreeSpace(0);
391}
392
393
394/*
395 * Like rename(), returns 0 upon success, non-zero upon failure.
396 * Should probably set errno appropriately when errors occur.
397 */
398    int
399mch_rename(
400    const char	*pszOldFile,
401    const char	*pszNewFile)
402{
403
404    /*
405     * No need to play tricks, this isn't rubbish like Windows 95 <g>
406     */
407    return rename(pszOldFile, pszNewFile);
408
409}
410
411/*
412 * Get the default shell for the current hardware platform
413 */
414    char*
415default_shell()
416{
417    char* psz = NULL;
418
419    psz = "command.com";
420
421    return psz;
422}
423