xref: /vim-8.2.3635/src/misc2.c (revision 7c25a7c0)
1edf3f97aSBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
2071d4279SBram Moolenaar  *
3071d4279SBram Moolenaar  * VIM - Vi IMproved	by Bram Moolenaar
4071d4279SBram Moolenaar  *
5071d4279SBram Moolenaar  * Do ":help uganda"  in Vim to read copying and usage conditions.
6071d4279SBram Moolenaar  * Do ":help credits" in Vim to see a list of people who contributed.
7071d4279SBram Moolenaar  * See README.txt for an overview of the Vim source code.
8071d4279SBram Moolenaar  */
9071d4279SBram Moolenaar 
10071d4279SBram Moolenaar /*
11071d4279SBram Moolenaar  * misc2.c: Various functions.
12071d4279SBram Moolenaar  */
13071d4279SBram Moolenaar #include "vim.h"
14071d4279SBram Moolenaar 
1585a2002aSBram Moolenaar static char_u	*username = NULL; // cached result of mch_get_user_name()
16f461c8e7SBram Moolenaar 
1792b8b2d3SBram Moolenaar static int coladvance2(pos_T *pos, int addspaces, int finetune, colnr_T wcol);
18071d4279SBram Moolenaar 
19071d4279SBram Moolenaar /*
20071d4279SBram Moolenaar  * Return TRUE if in the current mode we need to use virtual.
21071d4279SBram Moolenaar  */
22071d4279SBram Moolenaar     int
virtual_active(void)239b57814dSBram Moolenaar virtual_active(void)
24071d4279SBram Moolenaar {
2553ba05b0SGary Johnson     unsigned int cur_ve_flags = get_ve_flags();
2653ba05b0SGary Johnson 
2785a2002aSBram Moolenaar     // While an operator is being executed we return "virtual_op", because
2885a2002aSBram Moolenaar     // VIsual_active has already been reset, thus we can't check for "block"
2985a2002aSBram Moolenaar     // being used.
30071d4279SBram Moolenaar     if (virtual_op != MAYBE)
31071d4279SBram Moolenaar 	return virtual_op;
3253ba05b0SGary Johnson     return (cur_ve_flags == VE_ALL
3353ba05b0SGary Johnson 	    || ((cur_ve_flags & VE_BLOCK) && VIsual_active && VIsual_mode == Ctrl_V)
3453ba05b0SGary Johnson 	    || ((cur_ve_flags & VE_INSERT) && (State & INSERT)));
35071d4279SBram Moolenaar }
36071d4279SBram Moolenaar 
37071d4279SBram Moolenaar /*
38071d4279SBram Moolenaar  * Get the screen position of the cursor.
39071d4279SBram Moolenaar  */
40071d4279SBram Moolenaar     int
getviscol(void)419b57814dSBram Moolenaar getviscol(void)
42071d4279SBram Moolenaar {
43071d4279SBram Moolenaar     colnr_T	x;
44071d4279SBram Moolenaar 
45071d4279SBram Moolenaar     getvvcol(curwin, &curwin->w_cursor, &x, NULL, NULL);
46071d4279SBram Moolenaar     return (int)x;
47071d4279SBram Moolenaar }
48071d4279SBram Moolenaar 
49071d4279SBram Moolenaar /*
507aa9f6a0SBram Moolenaar  * Go to column "wcol", and add/insert white space as necessary to get the
51071d4279SBram Moolenaar  * cursor in that column.
52071d4279SBram Moolenaar  * The caller must have saved the cursor line for undo!
53071d4279SBram Moolenaar  */
54071d4279SBram Moolenaar     int
coladvance_force(colnr_T wcol)559b57814dSBram Moolenaar coladvance_force(colnr_T wcol)
56071d4279SBram Moolenaar {
57071d4279SBram Moolenaar     int rc = coladvance2(&curwin->w_cursor, TRUE, FALSE, wcol);
58071d4279SBram Moolenaar 
59071d4279SBram Moolenaar     if (wcol == MAXCOL)
60071d4279SBram Moolenaar 	curwin->w_valid &= ~VALID_VIRTCOL;
61071d4279SBram Moolenaar     else
62071d4279SBram Moolenaar     {
6385a2002aSBram Moolenaar 	// Virtcol is valid
64071d4279SBram Moolenaar 	curwin->w_valid |= VALID_VIRTCOL;
65071d4279SBram Moolenaar 	curwin->w_virtcol = wcol;
66071d4279SBram Moolenaar     }
67071d4279SBram Moolenaar     return rc;
68071d4279SBram Moolenaar }
69071d4279SBram Moolenaar 
70071d4279SBram Moolenaar /*
71977239efSBram Moolenaar  * Get the screen position of character col with a coladd in the cursor line.
72977239efSBram Moolenaar  */
73977239efSBram Moolenaar     int
getviscol2(colnr_T col,colnr_T coladd UNUSED)74fc3abf47SBram Moolenaar getviscol2(colnr_T col, colnr_T coladd UNUSED)
75977239efSBram Moolenaar {
76977239efSBram Moolenaar     colnr_T	x;
77977239efSBram Moolenaar     pos_T	pos;
78977239efSBram Moolenaar 
79977239efSBram Moolenaar     pos.lnum = curwin->w_cursor.lnum;
80977239efSBram Moolenaar     pos.col = col;
81977239efSBram Moolenaar     pos.coladd = coladd;
82977239efSBram Moolenaar     getvvcol(curwin, &pos, &x, NULL, NULL);
83977239efSBram Moolenaar     return (int)x;
84977239efSBram Moolenaar }
85977239efSBram Moolenaar 
86977239efSBram Moolenaar /*
87071d4279SBram Moolenaar  * Try to advance the Cursor to the specified screen column.
88071d4279SBram Moolenaar  * If virtual editing: fine tune the cursor position.
89071d4279SBram Moolenaar  * Note that all virtual positions off the end of a line should share
90071d4279SBram Moolenaar  * a curwin->w_cursor.col value (n.b. this is equal to STRLEN(line)),
91071d4279SBram Moolenaar  * beginning at coladd 0.
92071d4279SBram Moolenaar  *
93071d4279SBram Moolenaar  * return OK if desired column is reached, FAIL if not
94071d4279SBram Moolenaar  */
95071d4279SBram Moolenaar     int
coladvance(colnr_T wcol)969b57814dSBram Moolenaar coladvance(colnr_T wcol)
97071d4279SBram Moolenaar {
98071d4279SBram Moolenaar     int rc = getvpos(&curwin->w_cursor, wcol);
99071d4279SBram Moolenaar 
100071d4279SBram Moolenaar     if (wcol == MAXCOL || rc == FAIL)
101071d4279SBram Moolenaar 	curwin->w_valid &= ~VALID_VIRTCOL;
102dfccaf0fSBram Moolenaar     else if (*ml_get_cursor() != TAB)
103071d4279SBram Moolenaar     {
10485a2002aSBram Moolenaar 	// Virtcol is valid when not on a TAB
105071d4279SBram Moolenaar 	curwin->w_valid |= VALID_VIRTCOL;
106071d4279SBram Moolenaar 	curwin->w_virtcol = wcol;
107071d4279SBram Moolenaar     }
108071d4279SBram Moolenaar     return rc;
109071d4279SBram Moolenaar }
110071d4279SBram Moolenaar 
111071d4279SBram Moolenaar /*
112071d4279SBram Moolenaar  * Return in "pos" the position of the cursor advanced to screen column "wcol".
113071d4279SBram Moolenaar  * return OK if desired column is reached, FAIL if not
114071d4279SBram Moolenaar  */
115071d4279SBram Moolenaar     int
getvpos(pos_T * pos,colnr_T wcol)1169b57814dSBram Moolenaar getvpos(pos_T *pos, colnr_T wcol)
117071d4279SBram Moolenaar {
118071d4279SBram Moolenaar     return coladvance2(pos, FALSE, virtual_active(), wcol);
119071d4279SBram Moolenaar }
120071d4279SBram Moolenaar 
121071d4279SBram Moolenaar     static int
coladvance2(pos_T * pos,int addspaces,int finetune,colnr_T wcol_arg)1229b57814dSBram Moolenaar coladvance2(
1239b57814dSBram Moolenaar     pos_T	*pos,
124ceba3dd5SBram Moolenaar     int		addspaces,	// change the text to achieve our goal?
125ceba3dd5SBram Moolenaar     int		finetune,	// change char offset for the exact column
126ceba3dd5SBram Moolenaar     colnr_T	wcol_arg)	// column to move to (can be negative)
127071d4279SBram Moolenaar {
128ceba3dd5SBram Moolenaar     colnr_T	wcol = wcol_arg;
129071d4279SBram Moolenaar     int		idx;
130071d4279SBram Moolenaar     char_u	*ptr;
131071d4279SBram Moolenaar     char_u	*line;
132071d4279SBram Moolenaar     colnr_T	col = 0;
133071d4279SBram Moolenaar     int		csize = 0;
134071d4279SBram Moolenaar     int		one_more;
135071d4279SBram Moolenaar #ifdef FEAT_LINEBREAK
136071d4279SBram Moolenaar     int		head = 0;
137071d4279SBram Moolenaar #endif
138071d4279SBram Moolenaar 
139efd2bf15SBram Moolenaar     one_more = (State & INSERT)
140efd2bf15SBram Moolenaar 		    || restart_edit != NUL
141071d4279SBram Moolenaar 		    || (VIsual_active && *p_sel != 'o')
14253ba05b0SGary Johnson 		    || ((get_ve_flags() & VE_ONEMORE) && wcol < MAXCOL);
143a1381de5SBram Moolenaar     line = ml_get_buf(curbuf, pos->lnum, FALSE);
144071d4279SBram Moolenaar 
145071d4279SBram Moolenaar     if (wcol >= MAXCOL)
146071d4279SBram Moolenaar     {
147071d4279SBram Moolenaar 	    idx = (int)STRLEN(line) - 1 + one_more;
148071d4279SBram Moolenaar 	    col = wcol;
149071d4279SBram Moolenaar 
150071d4279SBram Moolenaar 	    if ((addspaces || finetune) && !VIsual_active)
151071d4279SBram Moolenaar 	    {
152071d4279SBram Moolenaar 		curwin->w_curswant = linetabsize(line) + one_more;
153071d4279SBram Moolenaar 		if (curwin->w_curswant > 0)
154071d4279SBram Moolenaar 		    --curwin->w_curswant;
155071d4279SBram Moolenaar 	    }
156071d4279SBram Moolenaar     }
157071d4279SBram Moolenaar     else
158071d4279SBram Moolenaar     {
1590263146bSBram Moolenaar 	int width = curwin->w_width - win_col_off(curwin);
160071d4279SBram Moolenaar 
161ebefac63SBram Moolenaar 	if (finetune
162071d4279SBram Moolenaar 		&& curwin->w_p_wrap
163071d4279SBram Moolenaar 		&& curwin->w_width != 0
16402f8694aSBram Moolenaar 		&& wcol >= (colnr_T)width
16502f8694aSBram Moolenaar 		&& width > 0)
166071d4279SBram Moolenaar 	{
167071d4279SBram Moolenaar 	    csize = linetabsize(line);
168071d4279SBram Moolenaar 	    if (csize > 0)
169071d4279SBram Moolenaar 		csize--;
170071d4279SBram Moolenaar 
171ebefac63SBram Moolenaar 	    if (wcol / width > (colnr_T)csize / width
172ebefac63SBram Moolenaar 		    && ((State & INSERT) == 0 || (int)wcol > csize + 1))
173071d4279SBram Moolenaar 	    {
17485a2002aSBram Moolenaar 		// In case of line wrapping don't move the cursor beyond the
17585a2002aSBram Moolenaar 		// right screen edge.  In Insert mode allow going just beyond
17685a2002aSBram Moolenaar 		// the last character (like what happens when typing and
17785a2002aSBram Moolenaar 		// reaching the right window edge).
178071d4279SBram Moolenaar 		wcol = (csize / width + 1) * width - 1;
179071d4279SBram Moolenaar 	    }
180071d4279SBram Moolenaar 	}
181071d4279SBram Moolenaar 
182071d4279SBram Moolenaar 	ptr = line;
183071d4279SBram Moolenaar 	while (col <= wcol && *ptr != NUL)
184071d4279SBram Moolenaar 	{
18585a2002aSBram Moolenaar 	    // Count a tab for what it's worth (if list mode not on)
186071d4279SBram Moolenaar #ifdef FEAT_LINEBREAK
187597a4224SBram Moolenaar 	    csize = win_lbr_chartabsize(curwin, line, ptr, col, &head);
18891acfffcSBram Moolenaar 	    MB_PTR_ADV(ptr);
189071d4279SBram Moolenaar #else
190597a4224SBram Moolenaar 	    csize = lbr_chartabsize_adv(line, &ptr, col);
191071d4279SBram Moolenaar #endif
192071d4279SBram Moolenaar 	    col += csize;
193071d4279SBram Moolenaar 	}
194071d4279SBram Moolenaar 	idx = (int)(ptr - line);
195071d4279SBram Moolenaar 	/*
196071d4279SBram Moolenaar 	 * Handle all the special cases.  The virtual_active() check
197071d4279SBram Moolenaar 	 * is needed to ensure that a virtual position off the end of
198071d4279SBram Moolenaar 	 * a line has the correct indexing.  The one_more comparison
199071d4279SBram Moolenaar 	 * replaces an explicit add of one_more later on.
200071d4279SBram Moolenaar 	 */
201071d4279SBram Moolenaar 	if (col > wcol || (!virtual_active() && one_more == 0))
202071d4279SBram Moolenaar 	{
203071d4279SBram Moolenaar 	    idx -= 1;
204071d4279SBram Moolenaar # ifdef FEAT_LINEBREAK
20585a2002aSBram Moolenaar 	    // Don't count the chars from 'showbreak'.
206071d4279SBram Moolenaar 	    csize -= head;
207071d4279SBram Moolenaar # endif
208071d4279SBram Moolenaar 	    col -= csize;
209071d4279SBram Moolenaar 	}
210071d4279SBram Moolenaar 
211071d4279SBram Moolenaar 	if (virtual_active()
212071d4279SBram Moolenaar 		&& addspaces
213ceba3dd5SBram Moolenaar 		&& wcol >= 0
214071d4279SBram Moolenaar 		&& ((col != wcol && col != wcol + 1) || csize > 1))
215071d4279SBram Moolenaar 	{
21685a2002aSBram Moolenaar 	    // 'virtualedit' is set: The difference between wcol and col is
21785a2002aSBram Moolenaar 	    // filled with spaces.
218071d4279SBram Moolenaar 
219071d4279SBram Moolenaar 	    if (line[idx] == NUL)
220071d4279SBram Moolenaar 	    {
22185a2002aSBram Moolenaar 		// Append spaces
222071d4279SBram Moolenaar 		int	correct = wcol - col;
223071d4279SBram Moolenaar 		char_u	*newline = alloc(idx + correct + 1);
224071d4279SBram Moolenaar 		int	t;
225071d4279SBram Moolenaar 
226071d4279SBram Moolenaar 		if (newline == NULL)
227071d4279SBram Moolenaar 		    return FAIL;
228071d4279SBram Moolenaar 
229071d4279SBram Moolenaar 		for (t = 0; t < idx; ++t)
230071d4279SBram Moolenaar 		    newline[t] = line[t];
231071d4279SBram Moolenaar 
232071d4279SBram Moolenaar 		for (t = 0; t < correct; ++t)
233071d4279SBram Moolenaar 		    newline[t + idx] = ' ';
234071d4279SBram Moolenaar 
235071d4279SBram Moolenaar 		newline[idx + correct] = NUL;
236071d4279SBram Moolenaar 
237071d4279SBram Moolenaar 		ml_replace(pos->lnum, newline, FALSE);
238071d4279SBram Moolenaar 		changed_bytes(pos->lnum, (colnr_T)idx);
239071d4279SBram Moolenaar 		idx += correct;
240071d4279SBram Moolenaar 		col = wcol;
241071d4279SBram Moolenaar 	    }
242071d4279SBram Moolenaar 	    else
243071d4279SBram Moolenaar 	    {
24485a2002aSBram Moolenaar 		// Break a tab
245071d4279SBram Moolenaar 		int	linelen = (int)STRLEN(line);
24685a2002aSBram Moolenaar 		int	correct = wcol - col - csize + 1; // negative!!
247eb3593b3SBram Moolenaar 		char_u	*newline;
248071d4279SBram Moolenaar 		int	t, s = 0;
249071d4279SBram Moolenaar 		int	v;
250071d4279SBram Moolenaar 
251eb3593b3SBram Moolenaar 		if (-correct > csize)
252eb3593b3SBram Moolenaar 		    return FAIL;
253eb3593b3SBram Moolenaar 
254eb3593b3SBram Moolenaar 		newline = alloc(linelen + csize);
255eb3593b3SBram Moolenaar 		if (newline == NULL)
256071d4279SBram Moolenaar 		    return FAIL;
257071d4279SBram Moolenaar 
258071d4279SBram Moolenaar 		for (t = 0; t < linelen; t++)
259071d4279SBram Moolenaar 		{
260071d4279SBram Moolenaar 		    if (t != idx)
261071d4279SBram Moolenaar 			newline[s++] = line[t];
262071d4279SBram Moolenaar 		    else
263071d4279SBram Moolenaar 			for (v = 0; v < csize; v++)
264071d4279SBram Moolenaar 			    newline[s++] = ' ';
265071d4279SBram Moolenaar 		}
266071d4279SBram Moolenaar 
267071d4279SBram Moolenaar 		newline[linelen + csize - 1] = NUL;
268071d4279SBram Moolenaar 
269071d4279SBram Moolenaar 		ml_replace(pos->lnum, newline, FALSE);
270071d4279SBram Moolenaar 		changed_bytes(pos->lnum, idx);
271071d4279SBram Moolenaar 		idx += (csize - 1 + correct);
272071d4279SBram Moolenaar 		col += correct;
273071d4279SBram Moolenaar 	    }
274071d4279SBram Moolenaar 	}
275071d4279SBram Moolenaar     }
276071d4279SBram Moolenaar 
277071d4279SBram Moolenaar     if (idx < 0)
278071d4279SBram Moolenaar 	pos->col = 0;
279071d4279SBram Moolenaar     else
280071d4279SBram Moolenaar 	pos->col = idx;
281071d4279SBram Moolenaar 
282071d4279SBram Moolenaar     pos->coladd = 0;
283071d4279SBram Moolenaar 
284071d4279SBram Moolenaar     if (finetune)
285071d4279SBram Moolenaar     {
286071d4279SBram Moolenaar 	if (wcol == MAXCOL)
287071d4279SBram Moolenaar 	{
28885a2002aSBram Moolenaar 	    // The width of the last character is used to set coladd.
289071d4279SBram Moolenaar 	    if (!one_more)
290071d4279SBram Moolenaar 	    {
291071d4279SBram Moolenaar 		colnr_T	    scol, ecol;
292071d4279SBram Moolenaar 
293071d4279SBram Moolenaar 		getvcol(curwin, pos, &scol, NULL, &ecol);
294071d4279SBram Moolenaar 		pos->coladd = ecol - scol;
295071d4279SBram Moolenaar 	    }
296071d4279SBram Moolenaar 	}
297071d4279SBram Moolenaar 	else
298071d4279SBram Moolenaar 	{
299071d4279SBram Moolenaar 	    int b = (int)wcol - (int)col;
300071d4279SBram Moolenaar 
30185a2002aSBram Moolenaar 	    // The difference between wcol and col is used to set coladd.
3020263146bSBram Moolenaar 	    if (b > 0 && b < (MAXCOL - 2 * curwin->w_width))
303071d4279SBram Moolenaar 		pos->coladd = b;
304071d4279SBram Moolenaar 
305071d4279SBram Moolenaar 	    col += b;
306071d4279SBram Moolenaar 	}
307071d4279SBram Moolenaar     }
308071d4279SBram Moolenaar 
30985a2002aSBram Moolenaar     // prevent from moving onto a trail byte
310071d4279SBram Moolenaar     if (has_mbyte)
31103a807aaSBram Moolenaar 	mb_adjustpos(curbuf, pos);
312071d4279SBram Moolenaar 
313ceba3dd5SBram Moolenaar     if (wcol < 0 || col < wcol)
314071d4279SBram Moolenaar 	return FAIL;
315071d4279SBram Moolenaar     return OK;
316071d4279SBram Moolenaar }
317071d4279SBram Moolenaar 
318071d4279SBram Moolenaar /*
319446cb837SBram Moolenaar  * Increment the cursor position.  See inc() for return values.
320071d4279SBram Moolenaar  */
321071d4279SBram Moolenaar     int
inc_cursor(void)3229b57814dSBram Moolenaar inc_cursor(void)
323071d4279SBram Moolenaar {
324071d4279SBram Moolenaar     return inc(&curwin->w_cursor);
325071d4279SBram Moolenaar }
326071d4279SBram Moolenaar 
327446cb837SBram Moolenaar /*
328446cb837SBram Moolenaar  * Increment the line pointer "lp" crossing line boundaries as necessary.
329446cb837SBram Moolenaar  * Return 1 when going to the next line.
330446cb837SBram Moolenaar  * Return 2 when moving forward onto a NUL at the end of the line).
331446cb837SBram Moolenaar  * Return -1 when at the end of file.
332446cb837SBram Moolenaar  * Return 0 otherwise.
333446cb837SBram Moolenaar  */
334071d4279SBram Moolenaar     int
inc(pos_T * lp)3359b57814dSBram Moolenaar inc(pos_T *lp)
336071d4279SBram Moolenaar {
3378ada6aa9SBram Moolenaar     char_u  *p;
338071d4279SBram Moolenaar 
33985a2002aSBram Moolenaar     // when searching position may be set to end of a line
3408ada6aa9SBram Moolenaar     if (lp->col != MAXCOL)
3418ada6aa9SBram Moolenaar     {
3428ada6aa9SBram Moolenaar 	p = ml_get_pos(lp);
34385a2002aSBram Moolenaar 	if (*p != NUL)	// still within line, move to next char (may be NUL)
344071d4279SBram Moolenaar 	{
345071d4279SBram Moolenaar 	    if (has_mbyte)
346071d4279SBram Moolenaar 	    {
3470fa313a7SBram Moolenaar 		int l = (*mb_ptr2len)(p);
348071d4279SBram Moolenaar 
349071d4279SBram Moolenaar 		lp->col += l;
350071d4279SBram Moolenaar 		return ((p[l] != NUL) ? 0 : 2);
351071d4279SBram Moolenaar 	    }
352071d4279SBram Moolenaar 	    lp->col++;
353071d4279SBram Moolenaar 	    lp->coladd = 0;
354071d4279SBram Moolenaar 	    return ((p[1] != NUL) ? 0 : 2);
355071d4279SBram Moolenaar 	}
3568ada6aa9SBram Moolenaar     }
35785a2002aSBram Moolenaar     if (lp->lnum != curbuf->b_ml.ml_line_count)     // there is a next line
358071d4279SBram Moolenaar     {
359071d4279SBram Moolenaar 	lp->col = 0;
360071d4279SBram Moolenaar 	lp->lnum++;
361071d4279SBram Moolenaar 	lp->coladd = 0;
362071d4279SBram Moolenaar 	return 1;
363071d4279SBram Moolenaar     }
364071d4279SBram Moolenaar     return -1;
365071d4279SBram Moolenaar }
366071d4279SBram Moolenaar 
367071d4279SBram Moolenaar /*
368071d4279SBram Moolenaar  * incl(lp): same as inc(), but skip the NUL at the end of non-empty lines
369071d4279SBram Moolenaar  */
370071d4279SBram Moolenaar     int
incl(pos_T * lp)3719b57814dSBram Moolenaar incl(pos_T *lp)
372071d4279SBram Moolenaar {
373071d4279SBram Moolenaar     int	    r;
374071d4279SBram Moolenaar 
375071d4279SBram Moolenaar     if ((r = inc(lp)) >= 1 && lp->col)
376071d4279SBram Moolenaar 	r = inc(lp);
377071d4279SBram Moolenaar     return r;
378071d4279SBram Moolenaar }
379071d4279SBram Moolenaar 
380071d4279SBram Moolenaar /*
381071d4279SBram Moolenaar  * dec(p)
382071d4279SBram Moolenaar  *
383071d4279SBram Moolenaar  * Decrement the line pointer 'p' crossing line boundaries as necessary.
384071d4279SBram Moolenaar  * Return 1 when crossing a line, -1 when at start of file, 0 otherwise.
385071d4279SBram Moolenaar  */
386071d4279SBram Moolenaar     int
dec_cursor(void)3879b57814dSBram Moolenaar dec_cursor(void)
388071d4279SBram Moolenaar {
389071d4279SBram Moolenaar     return dec(&curwin->w_cursor);
390071d4279SBram Moolenaar }
391071d4279SBram Moolenaar 
392071d4279SBram Moolenaar     int
dec(pos_T * lp)3939b57814dSBram Moolenaar dec(pos_T *lp)
394071d4279SBram Moolenaar {
395071d4279SBram Moolenaar     char_u	*p;
396071d4279SBram Moolenaar 
397071d4279SBram Moolenaar     lp->coladd = 0;
3981bd999f9SBram Moolenaar     if (lp->col == MAXCOL)
399071d4279SBram Moolenaar     {
40085a2002aSBram Moolenaar 	// past end of line
4011bd999f9SBram Moolenaar 	p = ml_get(lp->lnum);
4021bd999f9SBram Moolenaar 	lp->col = (colnr_T)STRLEN(p);
4031bd999f9SBram Moolenaar 	if (has_mbyte)
4041bd999f9SBram Moolenaar 	    lp->col -= (*mb_head_off)(p, p + lp->col);
4051bd999f9SBram Moolenaar 	return 0;
4061bd999f9SBram Moolenaar     }
4071bd999f9SBram Moolenaar 
4081bd999f9SBram Moolenaar     if (lp->col > 0)
4091bd999f9SBram Moolenaar     {
41085a2002aSBram Moolenaar 	// still within line
411071d4279SBram Moolenaar 	lp->col--;
412071d4279SBram Moolenaar 	if (has_mbyte)
413071d4279SBram Moolenaar 	{
414071d4279SBram Moolenaar 	    p = ml_get(lp->lnum);
415071d4279SBram Moolenaar 	    lp->col -= (*mb_head_off)(p, p + lp->col);
416071d4279SBram Moolenaar 	}
417071d4279SBram Moolenaar 	return 0;
418071d4279SBram Moolenaar     }
4191bd999f9SBram Moolenaar 
4201bd999f9SBram Moolenaar     if (lp->lnum > 1)
421071d4279SBram Moolenaar     {
42285a2002aSBram Moolenaar 	// there is a prior line
423071d4279SBram Moolenaar 	lp->lnum--;
424071d4279SBram Moolenaar 	p = ml_get(lp->lnum);
425071d4279SBram Moolenaar 	lp->col = (colnr_T)STRLEN(p);
426071d4279SBram Moolenaar 	if (has_mbyte)
427071d4279SBram Moolenaar 	    lp->col -= (*mb_head_off)(p, p + lp->col);
428071d4279SBram Moolenaar 	return 1;
429071d4279SBram Moolenaar     }
4301bd999f9SBram Moolenaar 
43185a2002aSBram Moolenaar     // at start of file
4321bd999f9SBram Moolenaar     return -1;
433071d4279SBram Moolenaar }
434071d4279SBram Moolenaar 
435071d4279SBram Moolenaar /*
436071d4279SBram Moolenaar  * decl(lp): same as dec(), but skip the NUL at the end of non-empty lines
437071d4279SBram Moolenaar  */
438071d4279SBram Moolenaar     int
decl(pos_T * lp)4399b57814dSBram Moolenaar decl(pos_T *lp)
440071d4279SBram Moolenaar {
441071d4279SBram Moolenaar     int	    r;
442071d4279SBram Moolenaar 
443071d4279SBram Moolenaar     if ((r = dec(lp)) == 1 && lp->col)
444071d4279SBram Moolenaar 	r = dec(lp);
445071d4279SBram Moolenaar     return r;
446071d4279SBram Moolenaar }
447071d4279SBram Moolenaar 
448071d4279SBram Moolenaar /*
44964486671SBram Moolenaar  * Get the line number relative to the current cursor position, i.e. the
45064486671SBram Moolenaar  * difference between line number and cursor position. Only look for lines that
45164486671SBram Moolenaar  * can be visible, folded lines don't count.
45264486671SBram Moolenaar  */
45364486671SBram Moolenaar     linenr_T
get_cursor_rel_lnum(win_T * wp,linenr_T lnum)4549b57814dSBram Moolenaar get_cursor_rel_lnum(
4559b57814dSBram Moolenaar     win_T	*wp,
45685a2002aSBram Moolenaar     linenr_T	lnum)		    // line number to get the result for
45764486671SBram Moolenaar {
45864486671SBram Moolenaar     linenr_T	cursor = wp->w_cursor.lnum;
45964486671SBram Moolenaar     linenr_T	retval = 0;
46064486671SBram Moolenaar 
46164486671SBram Moolenaar #ifdef FEAT_FOLDING
46264486671SBram Moolenaar     if (hasAnyFolding(wp))
46364486671SBram Moolenaar     {
46464486671SBram Moolenaar 	if (lnum > cursor)
46564486671SBram Moolenaar 	{
46664486671SBram Moolenaar 	    while (lnum > cursor)
46764486671SBram Moolenaar 	    {
4680bd7b3f4SBram Moolenaar 		(void)hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL);
46985a2002aSBram Moolenaar 		// if lnum and cursor are in the same fold,
47085a2002aSBram Moolenaar 		// now lnum <= cursor
47164486671SBram Moolenaar 		if (lnum > cursor)
47264486671SBram Moolenaar 		    retval++;
47364486671SBram Moolenaar 		lnum--;
47464486671SBram Moolenaar 	    }
47564486671SBram Moolenaar 	}
47664486671SBram Moolenaar 	else if (lnum < cursor)
47764486671SBram Moolenaar 	{
47864486671SBram Moolenaar 	    while (lnum < cursor)
47964486671SBram Moolenaar 	    {
4800bd7b3f4SBram Moolenaar 		(void)hasFoldingWin(wp, lnum, NULL, &lnum, TRUE, NULL);
48185a2002aSBram Moolenaar 		// if lnum and cursor are in the same fold,
48285a2002aSBram Moolenaar 		// now lnum >= cursor
48364486671SBram Moolenaar 		if (lnum < cursor)
48464486671SBram Moolenaar 		    retval--;
48564486671SBram Moolenaar 		lnum++;
48664486671SBram Moolenaar 	    }
48764486671SBram Moolenaar 	}
48885a2002aSBram Moolenaar 	// else if (lnum == cursor)
48985a2002aSBram Moolenaar 	//     retval = 0;
49064486671SBram Moolenaar     }
49164486671SBram Moolenaar     else
49264486671SBram Moolenaar #endif
49364486671SBram Moolenaar 	retval = lnum - cursor;
49464486671SBram Moolenaar 
49564486671SBram Moolenaar     return retval;
49664486671SBram Moolenaar }
49764486671SBram Moolenaar 
49864486671SBram Moolenaar /*
499d5824ce1SBram Moolenaar  * Make sure "pos.lnum" and "pos.col" are valid in "buf".
500d5824ce1SBram Moolenaar  * This allows for the col to be on the NUL byte.
501d5824ce1SBram Moolenaar  */
502d5824ce1SBram Moolenaar     void
check_pos(buf_T * buf,pos_T * pos)503d5824ce1SBram Moolenaar check_pos(buf_T *buf, pos_T *pos)
504d5824ce1SBram Moolenaar {
505d5824ce1SBram Moolenaar     char_u *line;
506d5824ce1SBram Moolenaar     colnr_T len;
507d5824ce1SBram Moolenaar 
508d5824ce1SBram Moolenaar     if (pos->lnum > buf->b_ml.ml_line_count)
509d5824ce1SBram Moolenaar 	pos->lnum = buf->b_ml.ml_line_count;
510d5824ce1SBram Moolenaar 
511d5824ce1SBram Moolenaar     if (pos->col > 0)
512d5824ce1SBram Moolenaar     {
513d5824ce1SBram Moolenaar 	line = ml_get_buf(buf, pos->lnum, FALSE);
514d5824ce1SBram Moolenaar 	len = (colnr_T)STRLEN(line);
515d5824ce1SBram Moolenaar 	if (pos->col > len)
516d5824ce1SBram Moolenaar 	    pos->col = len;
517d5824ce1SBram Moolenaar     }
518d5824ce1SBram Moolenaar }
519d5824ce1SBram Moolenaar 
520d5824ce1SBram Moolenaar /*
521071d4279SBram Moolenaar  * Make sure curwin->w_cursor.lnum is valid.
522071d4279SBram Moolenaar  */
523071d4279SBram Moolenaar     void
check_cursor_lnum(void)5249b57814dSBram Moolenaar check_cursor_lnum(void)
525071d4279SBram Moolenaar {
526071d4279SBram Moolenaar     if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
527071d4279SBram Moolenaar     {
528071d4279SBram Moolenaar #ifdef FEAT_FOLDING
52985a2002aSBram Moolenaar 	// If there is a closed fold at the end of the file, put the cursor in
53085a2002aSBram Moolenaar 	// its first line.  Otherwise in the last line.
531071d4279SBram Moolenaar 	if (!hasFolding(curbuf->b_ml.ml_line_count,
532071d4279SBram Moolenaar 						&curwin->w_cursor.lnum, NULL))
533071d4279SBram Moolenaar #endif
534071d4279SBram Moolenaar 	    curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
535071d4279SBram Moolenaar     }
536071d4279SBram Moolenaar     if (curwin->w_cursor.lnum <= 0)
537071d4279SBram Moolenaar 	curwin->w_cursor.lnum = 1;
538071d4279SBram Moolenaar }
539071d4279SBram Moolenaar 
540071d4279SBram Moolenaar /*
541071d4279SBram Moolenaar  * Make sure curwin->w_cursor.col is valid.
542071d4279SBram Moolenaar  */
543071d4279SBram Moolenaar     void
check_cursor_col(void)5449b57814dSBram Moolenaar check_cursor_col(void)
545071d4279SBram Moolenaar {
54603a807aaSBram Moolenaar     check_cursor_col_win(curwin);
54703a807aaSBram Moolenaar }
54803a807aaSBram Moolenaar 
54903a807aaSBram Moolenaar /*
55003a807aaSBram Moolenaar  * Make sure win->w_cursor.col is valid.
55103a807aaSBram Moolenaar  */
55203a807aaSBram Moolenaar     void
check_cursor_col_win(win_T * win)5539b57814dSBram Moolenaar check_cursor_col_win(win_T *win)
55403a807aaSBram Moolenaar {
555071d4279SBram Moolenaar     colnr_T      len;
55603a807aaSBram Moolenaar     colnr_T      oldcol = win->w_cursor.col;
55703a807aaSBram Moolenaar     colnr_T      oldcoladd = win->w_cursor.col + win->w_cursor.coladd;
55853ba05b0SGary Johnson     unsigned int cur_ve_flags = get_ve_flags();
559071d4279SBram Moolenaar 
56003a807aaSBram Moolenaar     len = (colnr_T)STRLEN(ml_get_buf(win->w_buffer, win->w_cursor.lnum, FALSE));
561071d4279SBram Moolenaar     if (len == 0)
56203a807aaSBram Moolenaar 	win->w_cursor.col = 0;
56303a807aaSBram Moolenaar     else if (win->w_cursor.col >= len)
564071d4279SBram Moolenaar     {
56585a2002aSBram Moolenaar 	// Allow cursor past end-of-line when:
56685a2002aSBram Moolenaar 	// - in Insert mode or restarting Insert mode
56785a2002aSBram Moolenaar 	// - in Visual mode and 'selection' isn't "old"
56885a2002aSBram Moolenaar 	// - 'virtualedit' is set
569ebefac63SBram Moolenaar 	if ((State & INSERT) || restart_edit
570071d4279SBram Moolenaar 		|| (VIsual_active && *p_sel != 'o')
57153ba05b0SGary Johnson 		|| (cur_ve_flags & VE_ONEMORE)
572071d4279SBram Moolenaar 		|| virtual_active())
57303a807aaSBram Moolenaar 	    win->w_cursor.col = len;
574071d4279SBram Moolenaar 	else
57587c19964SBram Moolenaar 	{
57603a807aaSBram Moolenaar 	    win->w_cursor.col = len - 1;
57785a2002aSBram Moolenaar 	    // Move the cursor to the head byte.
57887c19964SBram Moolenaar 	    if (has_mbyte)
57903a807aaSBram Moolenaar 		mb_adjustpos(win->w_buffer, &win->w_cursor);
58087c19964SBram Moolenaar 	}
581071d4279SBram Moolenaar     }
58203a807aaSBram Moolenaar     else if (win->w_cursor.col < 0)
58303a807aaSBram Moolenaar 	win->w_cursor.col = 0;
584071d4279SBram Moolenaar 
58585a2002aSBram Moolenaar     // If virtual editing is on, we can leave the cursor on the old position,
58685a2002aSBram Moolenaar     // only we must set it to virtual.  But don't do it when at the end of the
58785a2002aSBram Moolenaar     // line.
588071d4279SBram Moolenaar     if (oldcol == MAXCOL)
58903a807aaSBram Moolenaar 	win->w_cursor.coladd = 0;
59053ba05b0SGary Johnson     else if (cur_ve_flags == VE_ALL)
591552c8a56SBram Moolenaar     {
59203a807aaSBram Moolenaar 	if (oldcoladd > win->w_cursor.col)
5939aa15691SBram Moolenaar 	{
59403a807aaSBram Moolenaar 	    win->w_cursor.coladd = oldcoladd - win->w_cursor.col;
595d41babefSBram Moolenaar 
59685a2002aSBram Moolenaar 	    // Make sure that coladd is not more than the char width.
59785a2002aSBram Moolenaar 	    // Not for the last character, coladd is then used when the cursor
59885a2002aSBram Moolenaar 	    // is actually after the last character.
599d41babefSBram Moolenaar 	    if (win->w_cursor.col + 1 < len && win->w_cursor.coladd > 0)
6009aa15691SBram Moolenaar 	    {
6019aa15691SBram Moolenaar 		int cs, ce;
6029aa15691SBram Moolenaar 
6039aa15691SBram Moolenaar 		getvcol(win, &win->w_cursor, &cs, NULL, &ce);
6049aa15691SBram Moolenaar 		if (win->w_cursor.coladd > ce - cs)
6059aa15691SBram Moolenaar 		    win->w_cursor.coladd = ce - cs;
6069aa15691SBram Moolenaar 	    }
6079aa15691SBram Moolenaar 	}
608552c8a56SBram Moolenaar 	else
60985a2002aSBram Moolenaar 	    // avoid weird number when there is a miscalculation or overflow
61003a807aaSBram Moolenaar 	    win->w_cursor.coladd = 0;
611552c8a56SBram Moolenaar     }
612071d4279SBram Moolenaar }
613071d4279SBram Moolenaar 
614071d4279SBram Moolenaar /*
615071d4279SBram Moolenaar  * make sure curwin->w_cursor in on a valid character
616071d4279SBram Moolenaar  */
617071d4279SBram Moolenaar     void
check_cursor(void)6189b57814dSBram Moolenaar check_cursor(void)
619071d4279SBram Moolenaar {
620071d4279SBram Moolenaar     check_cursor_lnum();
621071d4279SBram Moolenaar     check_cursor_col();
622071d4279SBram Moolenaar }
623071d4279SBram Moolenaar 
624071d4279SBram Moolenaar #if defined(FEAT_TEXTOBJ) || defined(PROTO)
625071d4279SBram Moolenaar /*
626071d4279SBram Moolenaar  * Make sure curwin->w_cursor is not on the NUL at the end of the line.
627071d4279SBram Moolenaar  * Allow it when in Visual mode and 'selection' is not "old".
628071d4279SBram Moolenaar  */
629071d4279SBram Moolenaar     void
adjust_cursor_col(void)6309b57814dSBram Moolenaar adjust_cursor_col(void)
631071d4279SBram Moolenaar {
632071d4279SBram Moolenaar     if (curwin->w_cursor.col > 0
633071d4279SBram Moolenaar 	    && (!VIsual_active || *p_sel == 'o')
634071d4279SBram Moolenaar 	    && gchar_cursor() == NUL)
635071d4279SBram Moolenaar 	--curwin->w_cursor.col;
636071d4279SBram Moolenaar }
637071d4279SBram Moolenaar #endif
638071d4279SBram Moolenaar 
639071d4279SBram Moolenaar /*
640071d4279SBram Moolenaar  * When curwin->w_leftcol has changed, adjust the cursor position.
641071d4279SBram Moolenaar  * Return TRUE if the cursor was moved.
642071d4279SBram Moolenaar  */
643071d4279SBram Moolenaar     int
leftcol_changed(void)6449b57814dSBram Moolenaar leftcol_changed(void)
645071d4279SBram Moolenaar {
646071d4279SBram Moolenaar     long	lastcol;
647071d4279SBram Moolenaar     colnr_T	s, e;
648071d4279SBram Moolenaar     int		retval = FALSE;
649375e3390SBram Moolenaar     long        siso = get_sidescrolloff_value();
650071d4279SBram Moolenaar 
651071d4279SBram Moolenaar     changed_cline_bef_curs();
6520263146bSBram Moolenaar     lastcol = curwin->w_leftcol + curwin->w_width - curwin_col_off() - 1;
653071d4279SBram Moolenaar     validate_virtcol();
654071d4279SBram Moolenaar 
655071d4279SBram Moolenaar     /*
656071d4279SBram Moolenaar      * If the cursor is right or left of the screen, move it to last or first
657071d4279SBram Moolenaar      * character.
658071d4279SBram Moolenaar      */
659375e3390SBram Moolenaar     if (curwin->w_virtcol > (colnr_T)(lastcol - siso))
660071d4279SBram Moolenaar     {
661071d4279SBram Moolenaar 	retval = TRUE;
662375e3390SBram Moolenaar 	coladvance((colnr_T)(lastcol - siso));
663071d4279SBram Moolenaar     }
664375e3390SBram Moolenaar     else if (curwin->w_virtcol < curwin->w_leftcol + siso)
665071d4279SBram Moolenaar     {
666071d4279SBram Moolenaar 	retval = TRUE;
667375e3390SBram Moolenaar 	(void)coladvance((colnr_T)(curwin->w_leftcol + siso));
668071d4279SBram Moolenaar     }
669071d4279SBram Moolenaar 
670071d4279SBram Moolenaar     /*
671071d4279SBram Moolenaar      * If the start of the character under the cursor is not on the screen,
672071d4279SBram Moolenaar      * advance the cursor one more char.  If this fails (last char of the
673071d4279SBram Moolenaar      * line) adjust the scrolling.
674071d4279SBram Moolenaar      */
675071d4279SBram Moolenaar     getvvcol(curwin, &curwin->w_cursor, &s, NULL, &e);
676071d4279SBram Moolenaar     if (e > (colnr_T)lastcol)
677071d4279SBram Moolenaar     {
678071d4279SBram Moolenaar 	retval = TRUE;
679071d4279SBram Moolenaar 	coladvance(s - 1);
680071d4279SBram Moolenaar     }
681071d4279SBram Moolenaar     else if (s < curwin->w_leftcol)
682071d4279SBram Moolenaar     {
683071d4279SBram Moolenaar 	retval = TRUE;
68485a2002aSBram Moolenaar 	if (coladvance(e + 1) == FAIL)	// there isn't another character
685071d4279SBram Moolenaar 	{
68685a2002aSBram Moolenaar 	    curwin->w_leftcol = s;	// adjust w_leftcol instead
687071d4279SBram Moolenaar 	    changed_cline_bef_curs();
688071d4279SBram Moolenaar 	}
689071d4279SBram Moolenaar     }
690071d4279SBram Moolenaar 
691071d4279SBram Moolenaar     if (retval)
692071d4279SBram Moolenaar 	curwin->w_set_curswant = TRUE;
693071d4279SBram Moolenaar     redraw_later(NOT_VALID);
694071d4279SBram Moolenaar     return retval;
695071d4279SBram Moolenaar }
696071d4279SBram Moolenaar 
697c1a9bc1aSBram Moolenaar /*
698071d4279SBram Moolenaar  * Isolate one part of a string option where parts are separated with
699071d4279SBram Moolenaar  * "sep_chars".
70083bab71bSBram Moolenaar  * The part is copied into "buf[maxlen]".
701071d4279SBram Moolenaar  * "*option" is advanced to the next part.
702071d4279SBram Moolenaar  * The length is returned.
703071d4279SBram Moolenaar  */
704071d4279SBram Moolenaar     int
copy_option_part(char_u ** option,char_u * buf,int maxlen,char * sep_chars)7059b57814dSBram Moolenaar copy_option_part(
7069b57814dSBram Moolenaar     char_u	**option,
7079b57814dSBram Moolenaar     char_u	*buf,
7089b57814dSBram Moolenaar     int		maxlen,
7099b57814dSBram Moolenaar     char	*sep_chars)
710071d4279SBram Moolenaar {
711071d4279SBram Moolenaar     int	    len = 0;
712071d4279SBram Moolenaar     char_u  *p = *option;
713071d4279SBram Moolenaar 
71485a2002aSBram Moolenaar     // skip '.' at start of option part, for 'suffixes'
715071d4279SBram Moolenaar     if (*p == '.')
716071d4279SBram Moolenaar 	buf[len++] = *p++;
717071d4279SBram Moolenaar     while (*p != NUL && vim_strchr((char_u *)sep_chars, *p) == NULL)
718071d4279SBram Moolenaar     {
719071d4279SBram Moolenaar 	/*
720071d4279SBram Moolenaar 	 * Skip backslash before a separator character and space.
721071d4279SBram Moolenaar 	 */
722071d4279SBram Moolenaar 	if (p[0] == '\\' && vim_strchr((char_u *)sep_chars, p[1]) != NULL)
723071d4279SBram Moolenaar 	    ++p;
724071d4279SBram Moolenaar 	if (len < maxlen - 1)
725071d4279SBram Moolenaar 	    buf[len++] = *p;
726071d4279SBram Moolenaar 	++p;
727071d4279SBram Moolenaar     }
728071d4279SBram Moolenaar     buf[len] = NUL;
729071d4279SBram Moolenaar 
73085a2002aSBram Moolenaar     if (*p != NUL && *p != ',')	// skip non-standard separator
731071d4279SBram Moolenaar 	++p;
73285a2002aSBram Moolenaar     p = skip_to_option_part(p);	// p points to next file name
733071d4279SBram Moolenaar 
734071d4279SBram Moolenaar     *option = p;
735071d4279SBram Moolenaar     return len;
736071d4279SBram Moolenaar }
737071d4279SBram Moolenaar 
738071d4279SBram Moolenaar #ifndef HAVE_MEMSET
739071d4279SBram Moolenaar     void *
vim_memset(void * ptr,int c,size_t size)7409b57814dSBram Moolenaar vim_memset(void *ptr, int c, size_t size)
741071d4279SBram Moolenaar {
742071d4279SBram Moolenaar     char *p = ptr;
743071d4279SBram Moolenaar 
744071d4279SBram Moolenaar     while (size-- > 0)
745071d4279SBram Moolenaar 	*p++ = c;
746071d4279SBram Moolenaar     return ptr;
747071d4279SBram Moolenaar }
748071d4279SBram Moolenaar #endif
749071d4279SBram Moolenaar 
750071d4279SBram Moolenaar /*
751071d4279SBram Moolenaar  * Vim has its own isspace() function, because on some machines isspace()
752071d4279SBram Moolenaar  * can't handle characters above 128.
753071d4279SBram Moolenaar  */
754071d4279SBram Moolenaar     int
vim_isspace(int x)7559b57814dSBram Moolenaar vim_isspace(int x)
756071d4279SBram Moolenaar {
757071d4279SBram Moolenaar     return ((x >= 9 && x <= 13) || x == ' ');
758071d4279SBram Moolenaar }
759071d4279SBram Moolenaar 
760071d4279SBram Moolenaar /************************************************************************
761071d4279SBram Moolenaar  * functions that use lookup tables for various things, generally to do with
762071d4279SBram Moolenaar  * special key codes.
763071d4279SBram Moolenaar  */
764071d4279SBram Moolenaar 
765071d4279SBram Moolenaar /*
766071d4279SBram Moolenaar  * Some useful tables.
767071d4279SBram Moolenaar  */
768071d4279SBram Moolenaar 
769071d4279SBram Moolenaar static struct modmasktable
770071d4279SBram Moolenaar {
77185a2002aSBram Moolenaar     short	mod_mask;	// Bit-mask for particular key modifier
77285a2002aSBram Moolenaar     short	mod_flag;	// Bit(s) for particular key modifier
77385a2002aSBram Moolenaar     char_u	name;		// Single letter name of modifier
774071d4279SBram Moolenaar } mod_mask_table[] =
775071d4279SBram Moolenaar {
776071d4279SBram Moolenaar     {MOD_MASK_ALT,		MOD_MASK_ALT,		(char_u)'M'},
77719a09a18SBram Moolenaar     {MOD_MASK_META,		MOD_MASK_META,		(char_u)'T'},
778071d4279SBram Moolenaar     {MOD_MASK_CTRL,		MOD_MASK_CTRL,		(char_u)'C'},
779071d4279SBram Moolenaar     {MOD_MASK_SHIFT,		MOD_MASK_SHIFT,		(char_u)'S'},
780071d4279SBram Moolenaar     {MOD_MASK_MULTI_CLICK,	MOD_MASK_2CLICK,	(char_u)'2'},
781071d4279SBram Moolenaar     {MOD_MASK_MULTI_CLICK,	MOD_MASK_3CLICK,	(char_u)'3'},
782071d4279SBram Moolenaar     {MOD_MASK_MULTI_CLICK,	MOD_MASK_4CLICK,	(char_u)'4'},
783d057301bSBram Moolenaar #ifdef MACOS_X
784071d4279SBram Moolenaar     {MOD_MASK_CMD,		MOD_MASK_CMD,		(char_u)'D'},
785071d4279SBram Moolenaar #endif
78685a2002aSBram Moolenaar     // 'A' must be the last one
787071d4279SBram Moolenaar     {MOD_MASK_ALT,		MOD_MASK_ALT,		(char_u)'A'},
788071d4279SBram Moolenaar     {0, 0, NUL}
78985a2002aSBram Moolenaar     // NOTE: when adding an entry, update MAX_KEY_NAME_LEN!
790071d4279SBram Moolenaar };
791071d4279SBram Moolenaar 
792071d4279SBram Moolenaar /*
793071d4279SBram Moolenaar  * Shifted key terminal codes and their unshifted equivalent.
7947aa9f6a0SBram Moolenaar  * Don't add mouse codes here, they are handled separately!
795071d4279SBram Moolenaar  */
796071d4279SBram Moolenaar #define MOD_KEYS_ENTRY_SIZE 5
797071d4279SBram Moolenaar 
798071d4279SBram Moolenaar static char_u modifier_keys_table[] =
799071d4279SBram Moolenaar {
80085a2002aSBram Moolenaar //  mod mask	    with modifier		without modifier
80185a2002aSBram Moolenaar     MOD_MASK_SHIFT, '&', '9',			'@', '1',	// begin
80285a2002aSBram Moolenaar     MOD_MASK_SHIFT, '&', '0',			'@', '2',	// cancel
80385a2002aSBram Moolenaar     MOD_MASK_SHIFT, '*', '1',			'@', '4',	// command
80485a2002aSBram Moolenaar     MOD_MASK_SHIFT, '*', '2',			'@', '5',	// copy
80585a2002aSBram Moolenaar     MOD_MASK_SHIFT, '*', '3',			'@', '6',	// create
80685a2002aSBram Moolenaar     MOD_MASK_SHIFT, '*', '4',			'k', 'D',	// delete char
80785a2002aSBram Moolenaar     MOD_MASK_SHIFT, '*', '5',			'k', 'L',	// delete line
80885a2002aSBram Moolenaar     MOD_MASK_SHIFT, '*', '7',			'@', '7',	// end
80985a2002aSBram Moolenaar     MOD_MASK_CTRL,  KS_EXTRA, (int)KE_C_END,	'@', '7',	// end
81085a2002aSBram Moolenaar     MOD_MASK_SHIFT, '*', '9',			'@', '9',	// exit
81185a2002aSBram Moolenaar     MOD_MASK_SHIFT, '*', '0',			'@', '0',	// find
81285a2002aSBram Moolenaar     MOD_MASK_SHIFT, '#', '1',			'%', '1',	// help
81385a2002aSBram Moolenaar     MOD_MASK_SHIFT, '#', '2',			'k', 'h',	// home
81485a2002aSBram Moolenaar     MOD_MASK_CTRL,  KS_EXTRA, (int)KE_C_HOME,	'k', 'h',	// home
81585a2002aSBram Moolenaar     MOD_MASK_SHIFT, '#', '3',			'k', 'I',	// insert
81685a2002aSBram Moolenaar     MOD_MASK_SHIFT, '#', '4',			'k', 'l',	// left arrow
81785a2002aSBram Moolenaar     MOD_MASK_CTRL,  KS_EXTRA, (int)KE_C_LEFT,	'k', 'l',	// left arrow
81885a2002aSBram Moolenaar     MOD_MASK_SHIFT, '%', 'a',			'%', '3',	// message
81985a2002aSBram Moolenaar     MOD_MASK_SHIFT, '%', 'b',			'%', '4',	// move
82085a2002aSBram Moolenaar     MOD_MASK_SHIFT, '%', 'c',			'%', '5',	// next
82185a2002aSBram Moolenaar     MOD_MASK_SHIFT, '%', 'd',			'%', '7',	// options
82285a2002aSBram Moolenaar     MOD_MASK_SHIFT, '%', 'e',			'%', '8',	// previous
82385a2002aSBram Moolenaar     MOD_MASK_SHIFT, '%', 'f',			'%', '9',	// print
82485a2002aSBram Moolenaar     MOD_MASK_SHIFT, '%', 'g',			'%', '0',	// redo
82585a2002aSBram Moolenaar     MOD_MASK_SHIFT, '%', 'h',			'&', '3',	// replace
82685a2002aSBram Moolenaar     MOD_MASK_SHIFT, '%', 'i',			'k', 'r',	// right arr.
82785a2002aSBram Moolenaar     MOD_MASK_CTRL,  KS_EXTRA, (int)KE_C_RIGHT,	'k', 'r',	// right arr.
82885a2002aSBram Moolenaar     MOD_MASK_SHIFT, '%', 'j',			'&', '5',	// resume
82985a2002aSBram Moolenaar     MOD_MASK_SHIFT, '!', '1',			'&', '6',	// save
83085a2002aSBram Moolenaar     MOD_MASK_SHIFT, '!', '2',			'&', '7',	// suspend
83185a2002aSBram Moolenaar     MOD_MASK_SHIFT, '!', '3',			'&', '8',	// undo
83285a2002aSBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_UP,	'k', 'u',	// up arrow
83385a2002aSBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_DOWN,	'k', 'd',	// down arrow
834071d4279SBram Moolenaar 
83585a2002aSBram Moolenaar 								// vt100 F1
836071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF1,	KS_EXTRA, (int)KE_XF1,
837071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF2,	KS_EXTRA, (int)KE_XF2,
838071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF3,	KS_EXTRA, (int)KE_XF3,
839071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF4,	KS_EXTRA, (int)KE_XF4,
840071d4279SBram Moolenaar 
84185a2002aSBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F1,	'k', '1',	// F1
842071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F2,	'k', '2',
843071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F3,	'k', '3',
844071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F4,	'k', '4',
845071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F5,	'k', '5',
846071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F6,	'k', '6',
847071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F7,	'k', '7',
848071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F8,	'k', '8',
849071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F9,	'k', '9',
85085a2002aSBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F10,	'k', ';',	// F10
851071d4279SBram Moolenaar 
852071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F11,	'F', '1',
853071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F12,	'F', '2',
854071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F13,	'F', '3',
855071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F14,	'F', '4',
856071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F15,	'F', '5',
857071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F16,	'F', '6',
858071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F17,	'F', '7',
859071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F18,	'F', '8',
860071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F19,	'F', '9',
861071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F20,	'F', 'A',
862071d4279SBram Moolenaar 
863071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F21,	'F', 'B',
864071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F22,	'F', 'C',
865071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F23,	'F', 'D',
866071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F24,	'F', 'E',
867071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F25,	'F', 'F',
868071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F26,	'F', 'G',
869071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F27,	'F', 'H',
870071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F28,	'F', 'I',
871071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F29,	'F', 'J',
872071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F30,	'F', 'K',
873071d4279SBram Moolenaar 
874071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F31,	'F', 'L',
875071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F32,	'F', 'M',
876071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F33,	'F', 'N',
877071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F34,	'F', 'O',
878071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F35,	'F', 'P',
879071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F36,	'F', 'Q',
880071d4279SBram Moolenaar     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F37,	'F', 'R',
881071d4279SBram Moolenaar 
88285a2002aSBram Moolenaar 							    // TAB pseudo code
883071d4279SBram Moolenaar     MOD_MASK_SHIFT, 'k', 'B',			KS_EXTRA, (int)KE_TAB,
884071d4279SBram Moolenaar 
885071d4279SBram Moolenaar     NUL
886071d4279SBram Moolenaar };
887071d4279SBram Moolenaar 
888071d4279SBram Moolenaar static struct key_name_entry
889071d4279SBram Moolenaar {
89085a2002aSBram Moolenaar     int	    key;	// Special key code or ascii value
89185a2002aSBram Moolenaar     char_u  *name;	// Name of key
892071d4279SBram Moolenaar } key_names_table[] =
893071d4279SBram Moolenaar {
894071d4279SBram Moolenaar     {' ',		(char_u *)"Space"},
895071d4279SBram Moolenaar     {TAB,		(char_u *)"Tab"},
896071d4279SBram Moolenaar     {K_TAB,		(char_u *)"Tab"},
897071d4279SBram Moolenaar     {NL,		(char_u *)"NL"},
89885a2002aSBram Moolenaar     {NL,		(char_u *)"NewLine"},	// Alternative name
89985a2002aSBram Moolenaar     {NL,		(char_u *)"LineFeed"},	// Alternative name
90085a2002aSBram Moolenaar     {NL,		(char_u *)"LF"},	// Alternative name
901071d4279SBram Moolenaar     {CAR,		(char_u *)"CR"},
90285a2002aSBram Moolenaar     {CAR,		(char_u *)"Return"},	// Alternative name
90385a2002aSBram Moolenaar     {CAR,		(char_u *)"Enter"},	// Alternative name
904071d4279SBram Moolenaar     {K_BS,		(char_u *)"BS"},
90585a2002aSBram Moolenaar     {K_BS,		(char_u *)"BackSpace"},	// Alternative name
906071d4279SBram Moolenaar     {ESC,		(char_u *)"Esc"},
907071d4279SBram Moolenaar     {CSI,		(char_u *)"CSI"},
908071d4279SBram Moolenaar     {K_CSI,		(char_u *)"xCSI"},
909071d4279SBram Moolenaar     {'|',		(char_u *)"Bar"},
910071d4279SBram Moolenaar     {'\\',		(char_u *)"Bslash"},
911071d4279SBram Moolenaar     {K_DEL,		(char_u *)"Del"},
91285a2002aSBram Moolenaar     {K_DEL,		(char_u *)"Delete"},	// Alternative name
913071d4279SBram Moolenaar     {K_KDEL,		(char_u *)"kDel"},
914071d4279SBram Moolenaar     {K_UP,		(char_u *)"Up"},
915071d4279SBram Moolenaar     {K_DOWN,		(char_u *)"Down"},
916071d4279SBram Moolenaar     {K_LEFT,		(char_u *)"Left"},
917071d4279SBram Moolenaar     {K_RIGHT,		(char_u *)"Right"},
918bc7aa85dSBram Moolenaar     {K_XUP,		(char_u *)"xUp"},
919bc7aa85dSBram Moolenaar     {K_XDOWN,		(char_u *)"xDown"},
920bc7aa85dSBram Moolenaar     {K_XLEFT,		(char_u *)"xLeft"},
921bc7aa85dSBram Moolenaar     {K_XRIGHT,		(char_u *)"xRight"},
922ec2da36cSBram Moolenaar     {K_PS,		(char_u *)"PasteStart"},
923ec2da36cSBram Moolenaar     {K_PE,		(char_u *)"PasteEnd"},
924071d4279SBram Moolenaar 
925071d4279SBram Moolenaar     {K_F1,		(char_u *)"F1"},
926071d4279SBram Moolenaar     {K_F2,		(char_u *)"F2"},
927071d4279SBram Moolenaar     {K_F3,		(char_u *)"F3"},
928071d4279SBram Moolenaar     {K_F4,		(char_u *)"F4"},
929071d4279SBram Moolenaar     {K_F5,		(char_u *)"F5"},
930071d4279SBram Moolenaar     {K_F6,		(char_u *)"F6"},
931071d4279SBram Moolenaar     {K_F7,		(char_u *)"F7"},
932071d4279SBram Moolenaar     {K_F8,		(char_u *)"F8"},
933071d4279SBram Moolenaar     {K_F9,		(char_u *)"F9"},
934071d4279SBram Moolenaar     {K_F10,		(char_u *)"F10"},
935071d4279SBram Moolenaar 
936071d4279SBram Moolenaar     {K_F11,		(char_u *)"F11"},
937071d4279SBram Moolenaar     {K_F12,		(char_u *)"F12"},
938071d4279SBram Moolenaar     {K_F13,		(char_u *)"F13"},
939071d4279SBram Moolenaar     {K_F14,		(char_u *)"F14"},
940071d4279SBram Moolenaar     {K_F15,		(char_u *)"F15"},
941071d4279SBram Moolenaar     {K_F16,		(char_u *)"F16"},
942071d4279SBram Moolenaar     {K_F17,		(char_u *)"F17"},
943071d4279SBram Moolenaar     {K_F18,		(char_u *)"F18"},
944071d4279SBram Moolenaar     {K_F19,		(char_u *)"F19"},
945071d4279SBram Moolenaar     {K_F20,		(char_u *)"F20"},
946071d4279SBram Moolenaar 
947071d4279SBram Moolenaar     {K_F21,		(char_u *)"F21"},
948071d4279SBram Moolenaar     {K_F22,		(char_u *)"F22"},
949071d4279SBram Moolenaar     {K_F23,		(char_u *)"F23"},
950071d4279SBram Moolenaar     {K_F24,		(char_u *)"F24"},
951071d4279SBram Moolenaar     {K_F25,		(char_u *)"F25"},
952071d4279SBram Moolenaar     {K_F26,		(char_u *)"F26"},
953071d4279SBram Moolenaar     {K_F27,		(char_u *)"F27"},
954071d4279SBram Moolenaar     {K_F28,		(char_u *)"F28"},
955071d4279SBram Moolenaar     {K_F29,		(char_u *)"F29"},
956071d4279SBram Moolenaar     {K_F30,		(char_u *)"F30"},
957071d4279SBram Moolenaar 
958071d4279SBram Moolenaar     {K_F31,		(char_u *)"F31"},
959071d4279SBram Moolenaar     {K_F32,		(char_u *)"F32"},
960071d4279SBram Moolenaar     {K_F33,		(char_u *)"F33"},
961071d4279SBram Moolenaar     {K_F34,		(char_u *)"F34"},
962071d4279SBram Moolenaar     {K_F35,		(char_u *)"F35"},
963071d4279SBram Moolenaar     {K_F36,		(char_u *)"F36"},
964071d4279SBram Moolenaar     {K_F37,		(char_u *)"F37"},
965071d4279SBram Moolenaar 
966071d4279SBram Moolenaar     {K_XF1,		(char_u *)"xF1"},
967071d4279SBram Moolenaar     {K_XF2,		(char_u *)"xF2"},
968071d4279SBram Moolenaar     {K_XF3,		(char_u *)"xF3"},
969071d4279SBram Moolenaar     {K_XF4,		(char_u *)"xF4"},
970071d4279SBram Moolenaar 
971071d4279SBram Moolenaar     {K_HELP,		(char_u *)"Help"},
972071d4279SBram Moolenaar     {K_UNDO,		(char_u *)"Undo"},
973071d4279SBram Moolenaar     {K_INS,		(char_u *)"Insert"},
97485a2002aSBram Moolenaar     {K_INS,		(char_u *)"Ins"},	// Alternative name
975071d4279SBram Moolenaar     {K_KINS,		(char_u *)"kInsert"},
976071d4279SBram Moolenaar     {K_HOME,		(char_u *)"Home"},
977071d4279SBram Moolenaar     {K_KHOME,		(char_u *)"kHome"},
978071d4279SBram Moolenaar     {K_XHOME,		(char_u *)"xHome"},
97968b76a69SBram Moolenaar     {K_ZHOME,		(char_u *)"zHome"},
980071d4279SBram Moolenaar     {K_END,		(char_u *)"End"},
981071d4279SBram Moolenaar     {K_KEND,		(char_u *)"kEnd"},
982071d4279SBram Moolenaar     {K_XEND,		(char_u *)"xEnd"},
98368b76a69SBram Moolenaar     {K_ZEND,		(char_u *)"zEnd"},
984071d4279SBram Moolenaar     {K_PAGEUP,		(char_u *)"PageUp"},
985071d4279SBram Moolenaar     {K_PAGEDOWN,	(char_u *)"PageDown"},
986071d4279SBram Moolenaar     {K_KPAGEUP,		(char_u *)"kPageUp"},
987071d4279SBram Moolenaar     {K_KPAGEDOWN,	(char_u *)"kPageDown"},
988071d4279SBram Moolenaar 
989071d4279SBram Moolenaar     {K_KPLUS,		(char_u *)"kPlus"},
990071d4279SBram Moolenaar     {K_KMINUS,		(char_u *)"kMinus"},
991071d4279SBram Moolenaar     {K_KDIVIDE,		(char_u *)"kDivide"},
992071d4279SBram Moolenaar     {K_KMULTIPLY,	(char_u *)"kMultiply"},
993071d4279SBram Moolenaar     {K_KENTER,		(char_u *)"kEnter"},
994071d4279SBram Moolenaar     {K_KPOINT,		(char_u *)"kPoint"},
995071d4279SBram Moolenaar 
996071d4279SBram Moolenaar     {K_K0,		(char_u *)"k0"},
997071d4279SBram Moolenaar     {K_K1,		(char_u *)"k1"},
998071d4279SBram Moolenaar     {K_K2,		(char_u *)"k2"},
999071d4279SBram Moolenaar     {K_K3,		(char_u *)"k3"},
1000071d4279SBram Moolenaar     {K_K4,		(char_u *)"k4"},
1001071d4279SBram Moolenaar     {K_K5,		(char_u *)"k5"},
1002071d4279SBram Moolenaar     {K_K6,		(char_u *)"k6"},
1003071d4279SBram Moolenaar     {K_K7,		(char_u *)"k7"},
1004071d4279SBram Moolenaar     {K_K8,		(char_u *)"k8"},
1005071d4279SBram Moolenaar     {K_K9,		(char_u *)"k9"},
1006071d4279SBram Moolenaar 
1007071d4279SBram Moolenaar     {'<',		(char_u *)"lt"},
1008071d4279SBram Moolenaar 
1009071d4279SBram Moolenaar     {K_MOUSE,		(char_u *)"Mouse"},
10105af7d712SBram Moolenaar #ifdef FEAT_MOUSE_NET
1011071d4279SBram Moolenaar     {K_NETTERM_MOUSE,	(char_u *)"NetMouse"},
10125af7d712SBram Moolenaar #endif
10135af7d712SBram Moolenaar #ifdef FEAT_MOUSE_DEC
1014071d4279SBram Moolenaar     {K_DEC_MOUSE,	(char_u *)"DecMouse"},
10155af7d712SBram Moolenaar #endif
10165af7d712SBram Moolenaar #ifdef FEAT_MOUSE_JSB
1017071d4279SBram Moolenaar     {K_JSBTERM_MOUSE,	(char_u *)"JsbMouse"},
10185af7d712SBram Moolenaar #endif
10195af7d712SBram Moolenaar #ifdef FEAT_MOUSE_PTERM
1020071d4279SBram Moolenaar     {K_PTERM_MOUSE,	(char_u *)"PtermMouse"},
10215af7d712SBram Moolenaar #endif
10225af7d712SBram Moolenaar #ifdef FEAT_MOUSE_URXVT
10235af7d712SBram Moolenaar     {K_URXVT_MOUSE,	(char_u *)"UrxvtMouse"},
10245af7d712SBram Moolenaar #endif
10252b9578f0SBram Moolenaar     {K_SGR_MOUSE,	(char_u *)"SgrMouse"},
102621a83bd5SBram Moolenaar     {K_SGR_MOUSERELEASE, (char_u *)"SgrMouseRelease"},
1027071d4279SBram Moolenaar     {K_LEFTMOUSE,	(char_u *)"LeftMouse"},
1028071d4279SBram Moolenaar     {K_LEFTMOUSE_NM,	(char_u *)"LeftMouseNM"},
1029071d4279SBram Moolenaar     {K_LEFTDRAG,	(char_u *)"LeftDrag"},
1030071d4279SBram Moolenaar     {K_LEFTRELEASE,	(char_u *)"LeftRelease"},
1031071d4279SBram Moolenaar     {K_LEFTRELEASE_NM,	(char_u *)"LeftReleaseNM"},
103251b0f370SBram Moolenaar     {K_MOUSEMOVE,	(char_u *)"MouseMove"},
1033071d4279SBram Moolenaar     {K_MIDDLEMOUSE,	(char_u *)"MiddleMouse"},
1034071d4279SBram Moolenaar     {K_MIDDLEDRAG,	(char_u *)"MiddleDrag"},
1035071d4279SBram Moolenaar     {K_MIDDLERELEASE,	(char_u *)"MiddleRelease"},
1036071d4279SBram Moolenaar     {K_RIGHTMOUSE,	(char_u *)"RightMouse"},
1037071d4279SBram Moolenaar     {K_RIGHTDRAG,	(char_u *)"RightDrag"},
1038071d4279SBram Moolenaar     {K_RIGHTRELEASE,	(char_u *)"RightRelease"},
10398d9b40e7SBram Moolenaar     {K_MOUSEDOWN,	(char_u *)"ScrollWheelUp"},
10408d9b40e7SBram Moolenaar     {K_MOUSEUP,		(char_u *)"ScrollWheelDown"},
10418d9b40e7SBram Moolenaar     {K_MOUSELEFT,	(char_u *)"ScrollWheelRight"},
10428d9b40e7SBram Moolenaar     {K_MOUSERIGHT,	(char_u *)"ScrollWheelLeft"},
104385a2002aSBram Moolenaar     {K_MOUSEDOWN,	(char_u *)"MouseDown"}, // OBSOLETE: Use
104485a2002aSBram Moolenaar     {K_MOUSEUP,		(char_u *)"MouseUp"},	// ScrollWheelXXX instead
1045071d4279SBram Moolenaar     {K_X1MOUSE,		(char_u *)"X1Mouse"},
1046071d4279SBram Moolenaar     {K_X1DRAG,		(char_u *)"X1Drag"},
1047071d4279SBram Moolenaar     {K_X1RELEASE,		(char_u *)"X1Release"},
1048071d4279SBram Moolenaar     {K_X2MOUSE,		(char_u *)"X2Mouse"},
1049071d4279SBram Moolenaar     {K_X2DRAG,		(char_u *)"X2Drag"},
1050071d4279SBram Moolenaar     {K_X2RELEASE,		(char_u *)"X2Release"},
1051071d4279SBram Moolenaar     {K_DROP,		(char_u *)"Drop"},
1052071d4279SBram Moolenaar     {K_ZERO,		(char_u *)"Nul"},
1053071d4279SBram Moolenaar #ifdef FEAT_EVAL
1054071d4279SBram Moolenaar     {K_SNR,		(char_u *)"SNR"},
1055071d4279SBram Moolenaar #endif
1056071d4279SBram Moolenaar     {K_PLUG,		(char_u *)"Plug"},
10571db60c47SBram Moolenaar     {K_CURSORHOLD,	(char_u *)"CursorHold"},
10582f10658bSBram Moolenaar     {K_IGNORE,		(char_u *)"Ignore"},
1059957cf67dSBram Moolenaar     {K_COMMAND,		(char_u *)"Cmd"},
1060ccb47a28SBram Moolenaar     {K_FOCUSGAINED,	(char_u *)"FocusGained"},
1061ccb47a28SBram Moolenaar     {K_FOCUSLOST,	(char_u *)"FocusLost"},
1062071d4279SBram Moolenaar     {0,			NULL}
106385a2002aSBram Moolenaar     // NOTE: When adding a long name update MAX_KEY_NAME_LEN.
1064071d4279SBram Moolenaar };
1065071d4279SBram Moolenaar 
1066eeec2548SK.Takata #define KEY_NAMES_TABLE_LEN ARRAY_LENGTH(key_names_table)
1067071d4279SBram Moolenaar 
1068071d4279SBram Moolenaar /*
1069071d4279SBram Moolenaar  * Return the modifier mask bit (MOD_MASK_*) which corresponds to the given
1070071d4279SBram Moolenaar  * modifier name ('S' for Shift, 'C' for Ctrl etc).
1071071d4279SBram Moolenaar  */
10725843f5f3SBram Moolenaar     static int
name_to_mod_mask(int c)10739b57814dSBram Moolenaar name_to_mod_mask(int c)
1074071d4279SBram Moolenaar {
1075071d4279SBram Moolenaar     int	    i;
1076071d4279SBram Moolenaar 
1077071d4279SBram Moolenaar     c = TOUPPER_ASC(c);
1078071d4279SBram Moolenaar     for (i = 0; mod_mask_table[i].mod_mask != 0; i++)
1079071d4279SBram Moolenaar 	if (c == mod_mask_table[i].name)
1080071d4279SBram Moolenaar 	    return mod_mask_table[i].mod_flag;
1081071d4279SBram Moolenaar     return 0;
1082071d4279SBram Moolenaar }
1083071d4279SBram Moolenaar 
1084071d4279SBram Moolenaar /*
1085071d4279SBram Moolenaar  * Check if if there is a special key code for "key" that includes the
1086071d4279SBram Moolenaar  * modifiers specified.
1087071d4279SBram Moolenaar  */
1088071d4279SBram Moolenaar     int
simplify_key(int key,int * modifiers)10899b57814dSBram Moolenaar simplify_key(int key, int *modifiers)
1090071d4279SBram Moolenaar {
1091071d4279SBram Moolenaar     int	    i;
1092071d4279SBram Moolenaar     int	    key0;
1093071d4279SBram Moolenaar     int	    key1;
1094071d4279SBram Moolenaar 
1095071d4279SBram Moolenaar     if (*modifiers & (MOD_MASK_SHIFT | MOD_MASK_CTRL | MOD_MASK_ALT))
1096071d4279SBram Moolenaar     {
109785a2002aSBram Moolenaar 	// TAB is a special case
1098071d4279SBram Moolenaar 	if (key == TAB && (*modifiers & MOD_MASK_SHIFT))
1099071d4279SBram Moolenaar 	{
1100071d4279SBram Moolenaar 	    *modifiers &= ~MOD_MASK_SHIFT;
1101071d4279SBram Moolenaar 	    return K_S_TAB;
1102071d4279SBram Moolenaar 	}
1103071d4279SBram Moolenaar 	key0 = KEY2TERMCAP0(key);
1104071d4279SBram Moolenaar 	key1 = KEY2TERMCAP1(key);
1105071d4279SBram Moolenaar 	for (i = 0; modifier_keys_table[i] != NUL; i += MOD_KEYS_ENTRY_SIZE)
1106071d4279SBram Moolenaar 	    if (key0 == modifier_keys_table[i + 3]
1107071d4279SBram Moolenaar 		    && key1 == modifier_keys_table[i + 4]
1108071d4279SBram Moolenaar 		    && (*modifiers & modifier_keys_table[i]))
1109071d4279SBram Moolenaar 	    {
1110071d4279SBram Moolenaar 		*modifiers &= ~modifier_keys_table[i];
1111071d4279SBram Moolenaar 		return TERMCAP2KEY(modifier_keys_table[i + 1],
1112071d4279SBram Moolenaar 						   modifier_keys_table[i + 2]);
1113071d4279SBram Moolenaar 	    }
1114071d4279SBram Moolenaar     }
1115071d4279SBram Moolenaar     return key;
1116071d4279SBram Moolenaar }
1117071d4279SBram Moolenaar 
1118071d4279SBram Moolenaar /*
1119bc7aa85dSBram Moolenaar  * Change <xHome> to <Home>, <xUp> to <Up>, etc.
1120bc7aa85dSBram Moolenaar  */
1121bc7aa85dSBram Moolenaar     int
handle_x_keys(int key)11229b57814dSBram Moolenaar handle_x_keys(int key)
1123bc7aa85dSBram Moolenaar {
1124bc7aa85dSBram Moolenaar     switch (key)
1125bc7aa85dSBram Moolenaar     {
1126bc7aa85dSBram Moolenaar 	case K_XUP:	return K_UP;
1127bc7aa85dSBram Moolenaar 	case K_XDOWN:	return K_DOWN;
1128bc7aa85dSBram Moolenaar 	case K_XLEFT:	return K_LEFT;
1129bc7aa85dSBram Moolenaar 	case K_XRIGHT:	return K_RIGHT;
1130bc7aa85dSBram Moolenaar 	case K_XHOME:	return K_HOME;
113168b76a69SBram Moolenaar 	case K_ZHOME:	return K_HOME;
1132bc7aa85dSBram Moolenaar 	case K_XEND:	return K_END;
113368b76a69SBram Moolenaar 	case K_ZEND:	return K_END;
1134bc7aa85dSBram Moolenaar 	case K_XF1:	return K_F1;
1135bc7aa85dSBram Moolenaar 	case K_XF2:	return K_F2;
1136bc7aa85dSBram Moolenaar 	case K_XF3:	return K_F3;
1137bc7aa85dSBram Moolenaar 	case K_XF4:	return K_F4;
1138bc7aa85dSBram Moolenaar 	case K_S_XF1:	return K_S_F1;
1139bc7aa85dSBram Moolenaar 	case K_S_XF2:	return K_S_F2;
1140bc7aa85dSBram Moolenaar 	case K_S_XF3:	return K_S_F3;
1141bc7aa85dSBram Moolenaar 	case K_S_XF4:	return K_S_F4;
1142bc7aa85dSBram Moolenaar     }
1143bc7aa85dSBram Moolenaar     return key;
1144bc7aa85dSBram Moolenaar }
1145bc7aa85dSBram Moolenaar 
1146bc7aa85dSBram Moolenaar /*
1147071d4279SBram Moolenaar  * Return a string which contains the name of the given key when the given
1148071d4279SBram Moolenaar  * modifiers are down.
1149071d4279SBram Moolenaar  */
1150071d4279SBram Moolenaar     char_u *
get_special_key_name(int c,int modifiers)11519b57814dSBram Moolenaar get_special_key_name(int c, int modifiers)
1152071d4279SBram Moolenaar {
1153071d4279SBram Moolenaar     static char_u string[MAX_KEY_NAME_LEN + 1];
1154071d4279SBram Moolenaar 
1155071d4279SBram Moolenaar     int	    i, idx;
1156071d4279SBram Moolenaar     int	    table_idx;
1157071d4279SBram Moolenaar     char_u  *s;
1158071d4279SBram Moolenaar 
1159071d4279SBram Moolenaar     string[0] = '<';
1160071d4279SBram Moolenaar     idx = 1;
1161071d4279SBram Moolenaar 
116285a2002aSBram Moolenaar     // Key that stands for a normal character.
1163071d4279SBram Moolenaar     if (IS_SPECIAL(c) && KEY2TERMCAP0(c) == KS_KEY)
1164071d4279SBram Moolenaar 	c = KEY2TERMCAP1(c);
1165071d4279SBram Moolenaar 
1166071d4279SBram Moolenaar     /*
1167071d4279SBram Moolenaar      * Translate shifted special keys into unshifted keys and set modifier.
1168071d4279SBram Moolenaar      * Same for CTRL and ALT modifiers.
1169071d4279SBram Moolenaar      */
1170071d4279SBram Moolenaar     if (IS_SPECIAL(c))
1171071d4279SBram Moolenaar     {
1172071d4279SBram Moolenaar 	for (i = 0; modifier_keys_table[i] != 0; i += MOD_KEYS_ENTRY_SIZE)
1173071d4279SBram Moolenaar 	    if (       KEY2TERMCAP0(c) == (int)modifier_keys_table[i + 1]
1174071d4279SBram Moolenaar 		    && (int)KEY2TERMCAP1(c) == (int)modifier_keys_table[i + 2])
1175071d4279SBram Moolenaar 	    {
1176071d4279SBram Moolenaar 		modifiers |= modifier_keys_table[i];
1177071d4279SBram Moolenaar 		c = TERMCAP2KEY(modifier_keys_table[i + 3],
1178071d4279SBram Moolenaar 						   modifier_keys_table[i + 4]);
1179071d4279SBram Moolenaar 		break;
1180071d4279SBram Moolenaar 	    }
1181071d4279SBram Moolenaar     }
1182071d4279SBram Moolenaar 
118385a2002aSBram Moolenaar     // try to find the key in the special key table
1184071d4279SBram Moolenaar     table_idx = find_special_key_in_table(c);
1185071d4279SBram Moolenaar 
1186071d4279SBram Moolenaar     /*
1187071d4279SBram Moolenaar      * When not a known special key, and not a printable character, try to
1188071d4279SBram Moolenaar      * extract modifiers.
1189071d4279SBram Moolenaar      */
1190fc3abf47SBram Moolenaar     if (c > 0 && (*mb_char2len)(c) == 1)
1191071d4279SBram Moolenaar     {
1192071d4279SBram Moolenaar 	if (table_idx < 0
1193071d4279SBram Moolenaar 		&& (!vim_isprintc(c) || (c & 0x7f) == ' ')
1194071d4279SBram Moolenaar 		&& (c & 0x80))
1195071d4279SBram Moolenaar 	{
1196071d4279SBram Moolenaar 	    c &= 0x7f;
1197071d4279SBram Moolenaar 	    modifiers |= MOD_MASK_ALT;
119885a2002aSBram Moolenaar 	    // try again, to find the un-alted key in the special key table
1199071d4279SBram Moolenaar 	    table_idx = find_special_key_in_table(c);
1200071d4279SBram Moolenaar 	}
1201071d4279SBram Moolenaar 	if (table_idx < 0 && !vim_isprintc(c) && c < ' ')
1202071d4279SBram Moolenaar 	{
1203071d4279SBram Moolenaar #ifdef EBCDIC
1204071d4279SBram Moolenaar 	    c = CtrlChar(c);
1205071d4279SBram Moolenaar #else
1206071d4279SBram Moolenaar 	    c += '@';
1207071d4279SBram Moolenaar #endif
1208071d4279SBram Moolenaar 	    modifiers |= MOD_MASK_CTRL;
1209071d4279SBram Moolenaar 	}
1210071d4279SBram Moolenaar     }
1211071d4279SBram Moolenaar 
121285a2002aSBram Moolenaar     // translate the modifier into a string
1213071d4279SBram Moolenaar     for (i = 0; mod_mask_table[i].name != 'A'; i++)
1214071d4279SBram Moolenaar 	if ((modifiers & mod_mask_table[i].mod_mask)
1215071d4279SBram Moolenaar 						== mod_mask_table[i].mod_flag)
1216071d4279SBram Moolenaar 	{
1217071d4279SBram Moolenaar 	    string[idx++] = mod_mask_table[i].name;
1218071d4279SBram Moolenaar 	    string[idx++] = (char_u)'-';
1219071d4279SBram Moolenaar 	}
1220071d4279SBram Moolenaar 
122185a2002aSBram Moolenaar     if (table_idx < 0)		// unknown special key, may output t_xx
1222071d4279SBram Moolenaar     {
1223071d4279SBram Moolenaar 	if (IS_SPECIAL(c))
1224071d4279SBram Moolenaar 	{
1225071d4279SBram Moolenaar 	    string[idx++] = 't';
1226071d4279SBram Moolenaar 	    string[idx++] = '_';
1227071d4279SBram Moolenaar 	    string[idx++] = KEY2TERMCAP0(c);
1228071d4279SBram Moolenaar 	    string[idx++] = KEY2TERMCAP1(c);
1229071d4279SBram Moolenaar 	}
123085a2002aSBram Moolenaar 	// Not a special key, only modifiers, output directly
1231071d4279SBram Moolenaar 	else
1232071d4279SBram Moolenaar 	{
1233071d4279SBram Moolenaar 	    if (has_mbyte && (*mb_char2len)(c) > 1)
1234071d4279SBram Moolenaar 		idx += (*mb_char2bytes)(c, string + idx);
1235fc3abf47SBram Moolenaar 	    else if (vim_isprintc(c))
1236071d4279SBram Moolenaar 		string[idx++] = c;
1237071d4279SBram Moolenaar 	    else
1238071d4279SBram Moolenaar 	    {
1239071d4279SBram Moolenaar 		s = transchar(c);
1240071d4279SBram Moolenaar 		while (*s)
1241071d4279SBram Moolenaar 		    string[idx++] = *s++;
1242071d4279SBram Moolenaar 	    }
1243071d4279SBram Moolenaar 	}
1244071d4279SBram Moolenaar     }
124585a2002aSBram Moolenaar     else		// use name of special key
1246071d4279SBram Moolenaar     {
1247423977d3SBram Moolenaar 	size_t len = STRLEN(key_names_table[table_idx].name);
1248423977d3SBram Moolenaar 
1249423977d3SBram Moolenaar 	if (len + idx + 2 <= MAX_KEY_NAME_LEN)
1250423977d3SBram Moolenaar 	{
1251071d4279SBram Moolenaar 	    STRCPY(string + idx, key_names_table[table_idx].name);
1252423977d3SBram Moolenaar 	    idx += (int)len;
1253423977d3SBram Moolenaar 	}
1254071d4279SBram Moolenaar     }
1255071d4279SBram Moolenaar     string[idx++] = '>';
1256071d4279SBram Moolenaar     string[idx] = NUL;
1257071d4279SBram Moolenaar     return string;
1258071d4279SBram Moolenaar }
1259071d4279SBram Moolenaar 
1260071d4279SBram Moolenaar /*
1261071d4279SBram Moolenaar  * Try translating a <> name at (*srcp)[] to dst[].
1262071d4279SBram Moolenaar  * Return the number of characters added to dst[], zero for no match.
1263071d4279SBram Moolenaar  * If there is a match, srcp is advanced to after the <> name.
1264071d4279SBram Moolenaar  * dst[] must be big enough to hold the result (up to six characters)!
1265071d4279SBram Moolenaar  */
1266071d4279SBram Moolenaar     int
trans_special(char_u ** srcp,char_u * dst,int flags,int * did_simplify)12679b57814dSBram Moolenaar trans_special(
12689b57814dSBram Moolenaar     char_u	**srcp,
12699b57814dSBram Moolenaar     char_u	*dst,
1270ebe9d34aSBram Moolenaar     int		flags,		// FSK_ values
1271ebe9d34aSBram Moolenaar     int		*did_simplify)  // FSK_SIMPLIFY and found <C-H> or <A-x>
1272071d4279SBram Moolenaar {
1273071d4279SBram Moolenaar     int		modifiers = 0;
1274071d4279SBram Moolenaar     int		key;
1275071d4279SBram Moolenaar 
1276ebe9d34aSBram Moolenaar     key = find_special_key(srcp, &modifiers, flags, did_simplify);
1277071d4279SBram Moolenaar     if (key == 0)
1278071d4279SBram Moolenaar 	return 0;
1279071d4279SBram Moolenaar 
1280ebe9d34aSBram Moolenaar     return special_to_buf(key, modifiers, flags & FSK_KEYCODE, dst);
1281bf0eff0bSBram Moolenaar }
1282bf0eff0bSBram Moolenaar 
1283bf0eff0bSBram Moolenaar /*
1284bf0eff0bSBram Moolenaar  * Put the character sequence for "key" with "modifiers" into "dst" and return
1285bf0eff0bSBram Moolenaar  * the resulting length.
1286bf0eff0bSBram Moolenaar  * When "keycode" is TRUE prefer key code, e.g. K_DEL instead of DEL.
1287bf0eff0bSBram Moolenaar  * The sequence is not NUL terminated.
1288bf0eff0bSBram Moolenaar  * This is how characters in a string are encoded.
1289bf0eff0bSBram Moolenaar  */
1290bf0eff0bSBram Moolenaar     int
special_to_buf(int key,int modifiers,int keycode,char_u * dst)1291bf0eff0bSBram Moolenaar special_to_buf(int key, int modifiers, int keycode, char_u *dst)
1292bf0eff0bSBram Moolenaar {
1293bf0eff0bSBram Moolenaar     int		dlen = 0;
1294bf0eff0bSBram Moolenaar 
129585a2002aSBram Moolenaar     // Put the appropriate modifier in a string
1296071d4279SBram Moolenaar     if (modifiers != 0)
1297071d4279SBram Moolenaar     {
1298071d4279SBram Moolenaar 	dst[dlen++] = K_SPECIAL;
1299071d4279SBram Moolenaar 	dst[dlen++] = KS_MODIFIER;
1300071d4279SBram Moolenaar 	dst[dlen++] = modifiers;
1301071d4279SBram Moolenaar     }
1302071d4279SBram Moolenaar 
1303071d4279SBram Moolenaar     if (IS_SPECIAL(key))
1304071d4279SBram Moolenaar     {
1305071d4279SBram Moolenaar 	dst[dlen++] = K_SPECIAL;
1306071d4279SBram Moolenaar 	dst[dlen++] = KEY2TERMCAP0(key);
1307071d4279SBram Moolenaar 	dst[dlen++] = KEY2TERMCAP1(key);
1308071d4279SBram Moolenaar     }
1309071d4279SBram Moolenaar     else if (has_mbyte && !keycode)
1310071d4279SBram Moolenaar 	dlen += (*mb_char2bytes)(key, dst + dlen);
1311071d4279SBram Moolenaar     else if (keycode)
1312071d4279SBram Moolenaar 	dlen = (int)(add_char2buf(key, dst + dlen) - dst);
1313071d4279SBram Moolenaar     else
1314071d4279SBram Moolenaar 	dst[dlen++] = key;
1315071d4279SBram Moolenaar 
1316071d4279SBram Moolenaar     return dlen;
1317071d4279SBram Moolenaar }
1318071d4279SBram Moolenaar 
1319071d4279SBram Moolenaar /*
1320071d4279SBram Moolenaar  * Try translating a <> name at (*srcp)[], return the key and modifiers.
1321071d4279SBram Moolenaar  * srcp is advanced to after the <> name.
1322071d4279SBram Moolenaar  * returns 0 if there is no match.
1323071d4279SBram Moolenaar  */
1324071d4279SBram Moolenaar     int
find_special_key(char_u ** srcp,int * modp,int flags,int * did_simplify)13259b57814dSBram Moolenaar find_special_key(
13269b57814dSBram Moolenaar     char_u	**srcp,
13279b57814dSBram Moolenaar     int		*modp,
1328ebe9d34aSBram Moolenaar     int		flags,		// FSK_ values
1329459fd785SBram Moolenaar     int		*did_simplify)  // found <C-H> or <A-x>
1330071d4279SBram Moolenaar {
1331071d4279SBram Moolenaar     char_u	*last_dash;
1332071d4279SBram Moolenaar     char_u	*end_of_name;
1333071d4279SBram Moolenaar     char_u	*src;
1334071d4279SBram Moolenaar     char_u	*bp;
1335ebe9d34aSBram Moolenaar     int		in_string = flags & FSK_IN_STRING;
1336071d4279SBram Moolenaar     int		modifiers;
1337071d4279SBram Moolenaar     int		bit;
1338071d4279SBram Moolenaar     int		key;
133922fcfad2SBram Moolenaar     uvarnumber_T	n;
1340b8bf541fSBram Moolenaar     int		l;
1341071d4279SBram Moolenaar 
1342071d4279SBram Moolenaar     src = *srcp;
1343fccd93f0SBram Moolenaar     if (src[0] != '<')
1344071d4279SBram Moolenaar 	return 0;
1345fccd93f0SBram Moolenaar     if (src[1] == '*')	    // <*xxx>: do not simplify
1346fccd93f0SBram Moolenaar 	++src;
1347071d4279SBram Moolenaar 
134885a2002aSBram Moolenaar     // Find end of modifier list
1349071d4279SBram Moolenaar     last_dash = src;
1350e3d1f4c9SBram Moolenaar     for (bp = src + 1; *bp == '-' || vim_isNormalIDc(*bp); bp++)
1351071d4279SBram Moolenaar     {
1352071d4279SBram Moolenaar 	if (*bp == '-')
1353071d4279SBram Moolenaar 	{
1354071d4279SBram Moolenaar 	    last_dash = bp;
1355b8bf541fSBram Moolenaar 	    if (bp[1] != NUL)
1356b8bf541fSBram Moolenaar 	    {
1357b8bf541fSBram Moolenaar 		if (has_mbyte)
1358b8bf541fSBram Moolenaar 		    l = mb_ptr2len(bp + 1);
1359b8bf541fSBram Moolenaar 		else
1360b8bf541fSBram Moolenaar 		    l = 1;
1361c8fd33d1SBram Moolenaar 		// Anything accepted, like <C-?>.
1362c8fd33d1SBram Moolenaar 		// <C-"> or <M-"> are not special in strings as " is
1363c8fd33d1SBram Moolenaar 		// the string delimiter. With a backslash it works: <M-\">
1364fccd93f0SBram Moolenaar 		if (!(in_string && bp[1] == '"') && bp[l + 1] == '>')
13651d90a5a5SBram Moolenaar 		    bp += l;
136635a4cfa2SBram Moolenaar 		else if (in_string && bp[1] == '\\' && bp[2] == '"'
1367fccd93f0SBram Moolenaar 							   && bp[3] == '>')
136835a4cfa2SBram Moolenaar 		    bp += 2;
1369b8bf541fSBram Moolenaar 	    }
1370071d4279SBram Moolenaar 	}
1371071d4279SBram Moolenaar 	if (bp[0] == 't' && bp[1] == '_' && bp[2] && bp[3])
1372fccd93f0SBram Moolenaar 	    bp += 3;	// skip t_xx, xx may be '-' or '>'
1373792826c0SBram Moolenaar 	else if (STRNICMP(bp, "char-", 5) == 0)
1374792826c0SBram Moolenaar 	{
137516e9b851SBram Moolenaar 	    vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0, TRUE);
137616e9b851SBram Moolenaar 	    if (l == 0)
137716e9b851SBram Moolenaar 	    {
137816e9b851SBram Moolenaar 		emsg(_(e_invarg));
137916e9b851SBram Moolenaar 		return 0;
138016e9b851SBram Moolenaar 	    }
1381792826c0SBram Moolenaar 	    bp += l + 5;
1382792826c0SBram Moolenaar 	    break;
1383792826c0SBram Moolenaar 	}
1384071d4279SBram Moolenaar     }
1385071d4279SBram Moolenaar 
1386fccd93f0SBram Moolenaar     if (*bp == '>')	// found matching '>'
1387071d4279SBram Moolenaar     {
1388071d4279SBram Moolenaar 	end_of_name = bp + 1;
1389071d4279SBram Moolenaar 
139085a2002aSBram Moolenaar 	// Which modifiers are given?
1391071d4279SBram Moolenaar 	modifiers = 0x0;
1392071d4279SBram Moolenaar 	for (bp = src + 1; bp < last_dash; bp++)
1393071d4279SBram Moolenaar 	{
1394071d4279SBram Moolenaar 	    if (*bp != '-')
1395071d4279SBram Moolenaar 	    {
1396071d4279SBram Moolenaar 		bit = name_to_mod_mask(*bp);
1397071d4279SBram Moolenaar 		if (bit == 0x0)
139885a2002aSBram Moolenaar 		    break;	// Illegal modifier name
1399071d4279SBram Moolenaar 		modifiers |= bit;
1400071d4279SBram Moolenaar 	    }
1401071d4279SBram Moolenaar 	}
1402071d4279SBram Moolenaar 
1403071d4279SBram Moolenaar 	/*
1404071d4279SBram Moolenaar 	 * Legal modifier name.
1405071d4279SBram Moolenaar 	 */
1406071d4279SBram Moolenaar 	if (bp >= last_dash)
1407071d4279SBram Moolenaar 	{
1408b8bf541fSBram Moolenaar 	    if (STRNICMP(last_dash + 1, "char-", 5) == 0
1409b8bf541fSBram Moolenaar 						 && VIM_ISDIGIT(last_dash[6]))
1410b8bf541fSBram Moolenaar 	    {
141185a2002aSBram Moolenaar 		// <Char-123> or <Char-033> or <Char-0x33>
1412459fd785SBram Moolenaar 		vim_str2nr(last_dash + 6, NULL, &l, STR2NR_ALL, NULL,
1413459fd785SBram Moolenaar 								  &n, 0, TRUE);
141416e9b851SBram Moolenaar 		if (l == 0)
141516e9b851SBram Moolenaar 		{
141616e9b851SBram Moolenaar 		    emsg(_(e_invarg));
141716e9b851SBram Moolenaar 		    return 0;
141816e9b851SBram Moolenaar 		}
1419792826c0SBram Moolenaar 		key = (int)n;
1420b8bf541fSBram Moolenaar 	    }
1421792826c0SBram Moolenaar 	    else
1422792826c0SBram Moolenaar 	    {
142335a4cfa2SBram Moolenaar 		int off = 1;
142435a4cfa2SBram Moolenaar 
142585a2002aSBram Moolenaar 		// Modifier with single letter, or special key name.
142635a4cfa2SBram Moolenaar 		if (in_string && last_dash[1] == '\\' && last_dash[2] == '"')
142735a4cfa2SBram Moolenaar 		    off = 2;
1428b8bf541fSBram Moolenaar 		if (has_mbyte)
142935a4cfa2SBram Moolenaar 		    l = mb_ptr2len(last_dash + off);
1430b8bf541fSBram Moolenaar 		else
1431b8bf541fSBram Moolenaar 		    l = 1;
1432fccd93f0SBram Moolenaar 		if (modifiers != 0 && last_dash[l + off] == '>')
143335a4cfa2SBram Moolenaar 		    key = PTR2CHAR(last_dash + off);
1434071d4279SBram Moolenaar 		else
1435bc7aa85dSBram Moolenaar 		{
143635a4cfa2SBram Moolenaar 		    key = get_special_key_code(last_dash + off);
1437ebe9d34aSBram Moolenaar 		    if (!(flags & FSK_KEEP_X_KEY))
1438bc7aa85dSBram Moolenaar 			key = handle_x_keys(key);
1439bc7aa85dSBram Moolenaar 		}
1440792826c0SBram Moolenaar 	    }
1441071d4279SBram Moolenaar 
1442071d4279SBram Moolenaar 	    /*
1443071d4279SBram Moolenaar 	     * get_special_key_code() may return NUL for invalid
1444071d4279SBram Moolenaar 	     * special key name.
1445071d4279SBram Moolenaar 	     */
1446071d4279SBram Moolenaar 	    if (key != NUL)
1447071d4279SBram Moolenaar 	    {
1448071d4279SBram Moolenaar 		/*
1449071d4279SBram Moolenaar 		 * Only use a modifier when there is no special key code that
1450071d4279SBram Moolenaar 		 * includes the modifier.
1451071d4279SBram Moolenaar 		 */
1452071d4279SBram Moolenaar 		key = simplify_key(key, &modifiers);
1453071d4279SBram Moolenaar 
1454ebe9d34aSBram Moolenaar 		if (!(flags & FSK_KEYCODE))
1455071d4279SBram Moolenaar 		{
145685a2002aSBram Moolenaar 		    // don't want keycode, use single byte code
1457071d4279SBram Moolenaar 		    if (key == K_BS)
1458071d4279SBram Moolenaar 			key = BS;
1459071d4279SBram Moolenaar 		    else if (key == K_DEL || key == K_KDEL)
1460071d4279SBram Moolenaar 			key = DEL;
1461071d4279SBram Moolenaar 		}
1462071d4279SBram Moolenaar 
1463459fd785SBram Moolenaar 		// Normal Key with modifier: Try to make a single byte code.
1464071d4279SBram Moolenaar 		if (!IS_SPECIAL(key))
1465459fd785SBram Moolenaar 		    key = extract_modifiers(key, &modifiers,
1466ebe9d34aSBram Moolenaar 					   flags & FSK_SIMPLIFY, did_simplify);
1467071d4279SBram Moolenaar 
1468071d4279SBram Moolenaar 		*modp = modifiers;
1469071d4279SBram Moolenaar 		*srcp = end_of_name;
1470071d4279SBram Moolenaar 		return key;
1471071d4279SBram Moolenaar 	    }
1472071d4279SBram Moolenaar 	}
1473071d4279SBram Moolenaar     }
1474071d4279SBram Moolenaar     return 0;
1475071d4279SBram Moolenaar }
1476071d4279SBram Moolenaar 
1477ef6746f6SBram Moolenaar 
1478ef6746f6SBram Moolenaar /*
14794e2114e9SBram Moolenaar  * Some keys are used with Ctrl without Shift and are still expected to be
14804e2114e9SBram Moolenaar  * mapped as if Shift was pressed:
14814e2114e9SBram Moolenaar  * CTRL-2 is CTRL-@
14824e2114e9SBram Moolenaar  * CTRL-6 is CTRL-^
14834e2114e9SBram Moolenaar  * CTRL-- is CTRL-_
14844e2114e9SBram Moolenaar  * Also, <C-H> and <C-h> mean the same thing, always use "H".
14854e2114e9SBram Moolenaar  * Returns the possibly adjusted key.
14864e2114e9SBram Moolenaar  */
14874e2114e9SBram Moolenaar     int
may_adjust_key_for_ctrl(int modifiers,int key)14884e2114e9SBram Moolenaar may_adjust_key_for_ctrl(int modifiers, int key)
14894e2114e9SBram Moolenaar {
14904e2114e9SBram Moolenaar     if (modifiers & MOD_MASK_CTRL)
14914e2114e9SBram Moolenaar     {
14924e2114e9SBram Moolenaar 	if (ASCII_ISALPHA(key))
14934e2114e9SBram Moolenaar 	    return TOUPPER_ASC(key);
14944e2114e9SBram Moolenaar 	if (key == '2')
14954e2114e9SBram Moolenaar 	    return '@';
14964e2114e9SBram Moolenaar 	if (key == '6')
14974e2114e9SBram Moolenaar 	    return '^';
14984e2114e9SBram Moolenaar 	if (key == '-')
14994e2114e9SBram Moolenaar 	    return '_';
15004e2114e9SBram Moolenaar     }
15014e2114e9SBram Moolenaar     return key;
15024e2114e9SBram Moolenaar }
15034e2114e9SBram Moolenaar 
15044e2114e9SBram Moolenaar /*
1505ef6746f6SBram Moolenaar  * Some keys already have Shift included, pass them as normal keys.
15069a033d7bSBram Moolenaar  * When Ctrl is also used <C-H> and <C-S-H> are different, but <C-S-{> should
15079a033d7bSBram Moolenaar  * be <C-{>.  Same for <C-S-}> and <C-S-|>.
1508ef6746f6SBram Moolenaar  * Also for <A-S-a> and <M-S-a>.
1509daff0fb7SBram Moolenaar  * This includes all printable ASCII characters except numbers and a-z.
1510ef6746f6SBram Moolenaar  */
1511ef6746f6SBram Moolenaar     int
may_remove_shift_modifier(int modifiers,int key)1512ef6746f6SBram Moolenaar may_remove_shift_modifier(int modifiers, int key)
1513ef6746f6SBram Moolenaar {
1514ef6746f6SBram Moolenaar     if ((modifiers == MOD_MASK_SHIFT
1515ef6746f6SBram Moolenaar 		|| modifiers == (MOD_MASK_SHIFT | MOD_MASK_ALT)
1516ef6746f6SBram Moolenaar 		|| modifiers == (MOD_MASK_SHIFT | MOD_MASK_META))
1517daff0fb7SBram Moolenaar 	    && ((key >= '!' && key <= '/')
1518daff0fb7SBram Moolenaar 		|| (key >= ':' && key <= 'Z')
1519daff0fb7SBram Moolenaar 		|| (key >= '[' && key <= '`')
1520ef6746f6SBram Moolenaar 		|| (key >= '{' && key <= '~')))
1521ef6746f6SBram Moolenaar 	return modifiers & ~MOD_MASK_SHIFT;
15229a033d7bSBram Moolenaar 
15239a033d7bSBram Moolenaar     if (modifiers == (MOD_MASK_SHIFT | MOD_MASK_CTRL)
15249a033d7bSBram Moolenaar 		&& (key == '{' || key == '}' || key == '|'))
15259a033d7bSBram Moolenaar 	return modifiers & ~MOD_MASK_SHIFT;
15269a033d7bSBram Moolenaar 
1527ef6746f6SBram Moolenaar     return modifiers;
1528ef6746f6SBram Moolenaar }
1529ef6746f6SBram Moolenaar 
1530071d4279SBram Moolenaar /*
1531071d4279SBram Moolenaar  * Try to include modifiers in the key.
1532071d4279SBram Moolenaar  * Changes "Shift-a" to 'A', "Alt-A" to 0xc0, etc.
1533459fd785SBram Moolenaar  * When "simplify" is FALSE don't do Ctrl and Alt.
1534459fd785SBram Moolenaar  * When "simplify" is TRUE and Ctrl or Alt is removed from modifiers set
1535459fd785SBram Moolenaar  * "did_simplify" when it's not NULL.
1536071d4279SBram Moolenaar  */
1537071d4279SBram Moolenaar     int
extract_modifiers(int key,int * modp,int simplify,int * did_simplify)1538459fd785SBram Moolenaar extract_modifiers(int key, int *modp, int simplify, int *did_simplify)
1539071d4279SBram Moolenaar {
1540071d4279SBram Moolenaar     int	modifiers = *modp;
1541071d4279SBram Moolenaar 
1542d057301bSBram Moolenaar #ifdef MACOS_X
1543459fd785SBram Moolenaar     // Command-key really special, no fancynest
1544071d4279SBram Moolenaar     if (!(modifiers & MOD_MASK_CMD))
1545071d4279SBram Moolenaar #endif
1546071d4279SBram Moolenaar     if ((modifiers & MOD_MASK_SHIFT) && ASCII_ISALPHA(key))
1547071d4279SBram Moolenaar     {
1548071d4279SBram Moolenaar 	key = TOUPPER_ASC(key);
154920298ce6SBram Moolenaar 	// With <C-S-a> we keep the shift modifier.
155020298ce6SBram Moolenaar 	// With <S-a>, <A-S-a> and <S-A> we don't keep the shift modifier.
155120298ce6SBram Moolenaar 	if (simplify || modifiers == MOD_MASK_SHIFT
155220298ce6SBram Moolenaar 		|| modifiers == (MOD_MASK_SHIFT | MOD_MASK_ALT)
155320298ce6SBram Moolenaar 		|| modifiers == (MOD_MASK_SHIFT | MOD_MASK_META))
1554071d4279SBram Moolenaar 	    modifiers &= ~MOD_MASK_SHIFT;
1555071d4279SBram Moolenaar     }
1556459fd785SBram Moolenaar 
1557459fd785SBram Moolenaar     // <C-H> and <C-h> mean the same thing, always use "H"
1558459fd785SBram Moolenaar     if ((modifiers & MOD_MASK_CTRL) && ASCII_ISALPHA(key))
1559459fd785SBram Moolenaar 	key = TOUPPER_ASC(key);
1560459fd785SBram Moolenaar 
1561459fd785SBram Moolenaar     if (simplify && (modifiers & MOD_MASK_CTRL)
1562071d4279SBram Moolenaar #ifdef EBCDIC
1563459fd785SBram Moolenaar 	    // TODO: EBCDIC Better use:
1564459fd785SBram Moolenaar 	    // && (Ctrl_chr(key) || key == '?')
1565459fd785SBram Moolenaar 	    // ???
1566071d4279SBram Moolenaar 	    && strchr("?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_", key)
1567071d4279SBram Moolenaar 						       != NULL
1568071d4279SBram Moolenaar #else
1569071d4279SBram Moolenaar 	    && ((key >= '?' && key <= '_') || ASCII_ISALPHA(key))
1570071d4279SBram Moolenaar #endif
1571071d4279SBram Moolenaar 	    )
1572071d4279SBram Moolenaar     {
1573071d4279SBram Moolenaar 	key = Ctrl_chr(key);
1574071d4279SBram Moolenaar 	modifiers &= ~MOD_MASK_CTRL;
157585a2002aSBram Moolenaar 	// <C-@> is <Nul>
1576071d4279SBram Moolenaar 	if (key == 0)
1577071d4279SBram Moolenaar 	    key = K_ZERO;
1578459fd785SBram Moolenaar 	if (did_simplify != NULL)
1579459fd785SBram Moolenaar 	    *did_simplify = TRUE;
1580071d4279SBram Moolenaar     }
1581459fd785SBram Moolenaar 
1582d057301bSBram Moolenaar #ifdef MACOS_X
158385a2002aSBram Moolenaar     // Command-key really special, no fancynest
1584071d4279SBram Moolenaar     if (!(modifiers & MOD_MASK_CMD))
1585071d4279SBram Moolenaar #endif
1586459fd785SBram Moolenaar     if (simplify && (modifiers & MOD_MASK_ALT) && key < 0x80
1587fc3abf47SBram Moolenaar 	    && !enc_dbcs)		// avoid creating a lead byte
1588071d4279SBram Moolenaar     {
1589071d4279SBram Moolenaar 	key |= 0x80;
159085a2002aSBram Moolenaar 	modifiers &= ~MOD_MASK_ALT;	// remove the META modifier
1591459fd785SBram Moolenaar 	if (did_simplify != NULL)
1592459fd785SBram Moolenaar 	    *did_simplify = TRUE;
1593071d4279SBram Moolenaar     }
1594071d4279SBram Moolenaar 
1595071d4279SBram Moolenaar     *modp = modifiers;
1596071d4279SBram Moolenaar     return key;
1597071d4279SBram Moolenaar }
1598071d4279SBram Moolenaar 
1599071d4279SBram Moolenaar /*
1600071d4279SBram Moolenaar  * Try to find key "c" in the special key table.
1601071d4279SBram Moolenaar  * Return the index when found, -1 when not found.
1602071d4279SBram Moolenaar  */
1603071d4279SBram Moolenaar     int
find_special_key_in_table(int c)16049b57814dSBram Moolenaar find_special_key_in_table(int c)
1605071d4279SBram Moolenaar {
1606071d4279SBram Moolenaar     int	    i;
1607071d4279SBram Moolenaar 
1608071d4279SBram Moolenaar     for (i = 0; key_names_table[i].name != NULL; i++)
1609071d4279SBram Moolenaar 	if (c == key_names_table[i].key)
1610071d4279SBram Moolenaar 	    break;
1611071d4279SBram Moolenaar     if (key_names_table[i].name == NULL)
1612071d4279SBram Moolenaar 	i = -1;
1613071d4279SBram Moolenaar     return i;
1614071d4279SBram Moolenaar }
1615071d4279SBram Moolenaar 
1616071d4279SBram Moolenaar /*
1617071d4279SBram Moolenaar  * Find the special key with the given name (the given string does not have to
1618071d4279SBram Moolenaar  * end with NUL, the name is assumed to end before the first non-idchar).
1619071d4279SBram Moolenaar  * If the name starts with "t_" the next two characters are interpreted as a
1620071d4279SBram Moolenaar  * termcap name.
1621071d4279SBram Moolenaar  * Return the key code, or 0 if not found.
1622071d4279SBram Moolenaar  */
1623071d4279SBram Moolenaar     int
get_special_key_code(char_u * name)16249b57814dSBram Moolenaar get_special_key_code(char_u *name)
1625071d4279SBram Moolenaar {
1626071d4279SBram Moolenaar     char_u  *table_name;
1627071d4279SBram Moolenaar     char_u  string[3];
1628071d4279SBram Moolenaar     int	    i, j;
1629071d4279SBram Moolenaar 
1630071d4279SBram Moolenaar     /*
1631071d4279SBram Moolenaar      * If it's <t_xx> we get the code for xx from the termcap
1632071d4279SBram Moolenaar      */
1633071d4279SBram Moolenaar     if (name[0] == 't' && name[1] == '_' && name[2] != NUL && name[3] != NUL)
1634071d4279SBram Moolenaar     {
1635071d4279SBram Moolenaar 	string[0] = name[2];
1636071d4279SBram Moolenaar 	string[1] = name[3];
1637071d4279SBram Moolenaar 	string[2] = NUL;
1638071d4279SBram Moolenaar 	if (add_termcap_entry(string, FALSE) == OK)
1639071d4279SBram Moolenaar 	    return TERMCAP2KEY(name[2], name[3]);
1640071d4279SBram Moolenaar     }
1641071d4279SBram Moolenaar     else
1642071d4279SBram Moolenaar 	for (i = 0; key_names_table[i].name != NULL; i++)
1643071d4279SBram Moolenaar 	{
1644071d4279SBram Moolenaar 	    table_name = key_names_table[i].name;
1645e3d1f4c9SBram Moolenaar 	    for (j = 0; vim_isNormalIDc(name[j]) && table_name[j] != NUL; j++)
1646071d4279SBram Moolenaar 		if (TOLOWER_ASC(table_name[j]) != TOLOWER_ASC(name[j]))
1647071d4279SBram Moolenaar 		    break;
1648e3d1f4c9SBram Moolenaar 	    if (!vim_isNormalIDc(name[j]) && table_name[j] == NUL)
1649071d4279SBram Moolenaar 		return key_names_table[i].key;
1650071d4279SBram Moolenaar 	}
1651071d4279SBram Moolenaar     return 0;
1652071d4279SBram Moolenaar }
1653071d4279SBram Moolenaar 
1654071d4279SBram Moolenaar     char_u *
get_key_name(int i)16559b57814dSBram Moolenaar get_key_name(int i)
1656071d4279SBram Moolenaar {
1657e1fbddcdSBram Moolenaar     if (i >= (int)KEY_NAMES_TABLE_LEN)
1658071d4279SBram Moolenaar 	return NULL;
1659071d4279SBram Moolenaar     return  key_names_table[i].name;
1660071d4279SBram Moolenaar }
1661071d4279SBram Moolenaar 
1662071d4279SBram Moolenaar /*
1663071d4279SBram Moolenaar  * Return the current end-of-line type: EOL_DOS, EOL_UNIX or EOL_MAC.
1664071d4279SBram Moolenaar  */
1665071d4279SBram Moolenaar     int
get_fileformat(buf_T * buf)16669b57814dSBram Moolenaar get_fileformat(buf_T *buf)
1667071d4279SBram Moolenaar {
1668071d4279SBram Moolenaar     int		c = *buf->b_p_ff;
1669071d4279SBram Moolenaar 
1670071d4279SBram Moolenaar     if (buf->b_p_bin || c == 'u')
1671071d4279SBram Moolenaar 	return EOL_UNIX;
1672071d4279SBram Moolenaar     if (c == 'm')
1673071d4279SBram Moolenaar 	return EOL_MAC;
1674071d4279SBram Moolenaar     return EOL_DOS;
1675071d4279SBram Moolenaar }
1676071d4279SBram Moolenaar 
1677071d4279SBram Moolenaar /*
1678071d4279SBram Moolenaar  * Like get_fileformat(), but override 'fileformat' with "p" for "++opt=val"
1679071d4279SBram Moolenaar  * argument.
1680071d4279SBram Moolenaar  */
1681071d4279SBram Moolenaar     int
get_fileformat_force(buf_T * buf,exarg_T * eap)16829b57814dSBram Moolenaar get_fileformat_force(
16839b57814dSBram Moolenaar     buf_T	*buf,
168485a2002aSBram Moolenaar     exarg_T	*eap)	    // can be NULL!
1685071d4279SBram Moolenaar {
1686071d4279SBram Moolenaar     int		c;
1687071d4279SBram Moolenaar 
1688071d4279SBram Moolenaar     if (eap != NULL && eap->force_ff != 0)
1689333b80acSBram Moolenaar 	c = eap->force_ff;
1690071d4279SBram Moolenaar     else
1691071d4279SBram Moolenaar     {
1692071d4279SBram Moolenaar 	if ((eap != NULL && eap->force_bin != 0)
1693071d4279SBram Moolenaar 			       ? (eap->force_bin == FORCE_BIN) : buf->b_p_bin)
1694071d4279SBram Moolenaar 	    return EOL_UNIX;
1695071d4279SBram Moolenaar 	c = *buf->b_p_ff;
1696071d4279SBram Moolenaar     }
1697071d4279SBram Moolenaar     if (c == 'u')
1698071d4279SBram Moolenaar 	return EOL_UNIX;
1699071d4279SBram Moolenaar     if (c == 'm')
1700071d4279SBram Moolenaar 	return EOL_MAC;
1701071d4279SBram Moolenaar     return EOL_DOS;
1702071d4279SBram Moolenaar }
1703071d4279SBram Moolenaar 
1704071d4279SBram Moolenaar /*
1705071d4279SBram Moolenaar  * Set the current end-of-line type to EOL_DOS, EOL_UNIX or EOL_MAC.
1706071d4279SBram Moolenaar  * Sets both 'textmode' and 'fileformat'.
1707071d4279SBram Moolenaar  * Note: Does _not_ set global value of 'textmode'!
1708071d4279SBram Moolenaar  */
1709071d4279SBram Moolenaar     void
set_fileformat(int t,int opt_flags)17109b57814dSBram Moolenaar set_fileformat(
17119b57814dSBram Moolenaar     int		t,
171285a2002aSBram Moolenaar     int		opt_flags)	// OPT_LOCAL and/or OPT_GLOBAL
1713071d4279SBram Moolenaar {
1714071d4279SBram Moolenaar     char	*p = NULL;
1715071d4279SBram Moolenaar 
1716071d4279SBram Moolenaar     switch (t)
1717071d4279SBram Moolenaar     {
1718071d4279SBram Moolenaar     case EOL_DOS:
1719071d4279SBram Moolenaar 	p = FF_DOS;
1720071d4279SBram Moolenaar 	curbuf->b_p_tx = TRUE;
1721071d4279SBram Moolenaar 	break;
1722071d4279SBram Moolenaar     case EOL_UNIX:
1723071d4279SBram Moolenaar 	p = FF_UNIX;
1724071d4279SBram Moolenaar 	curbuf->b_p_tx = FALSE;
1725071d4279SBram Moolenaar 	break;
1726071d4279SBram Moolenaar     case EOL_MAC:
1727071d4279SBram Moolenaar 	p = FF_MAC;
1728071d4279SBram Moolenaar 	curbuf->b_p_tx = FALSE;
1729071d4279SBram Moolenaar 	break;
1730071d4279SBram Moolenaar     }
1731071d4279SBram Moolenaar     if (p != NULL)
1732071d4279SBram Moolenaar 	set_string_option_direct((char_u *)"ff", -1, (char_u *)p,
17335e3cb7e8SBram Moolenaar 						     OPT_FREE | opt_flags, 0);
17345e3cb7e8SBram Moolenaar 
173585a2002aSBram Moolenaar     // This may cause the buffer to become (un)modified.
1736071d4279SBram Moolenaar     check_status(curbuf);
1737997fb4baSBram Moolenaar     redraw_tabline = TRUE;
1738071d4279SBram Moolenaar #ifdef FEAT_TITLE
173985a2002aSBram Moolenaar     need_maketitle = TRUE;	    // set window title later
1740071d4279SBram Moolenaar #endif
1741071d4279SBram Moolenaar }
1742071d4279SBram Moolenaar 
1743071d4279SBram Moolenaar /*
1744071d4279SBram Moolenaar  * Return the default fileformat from 'fileformats'.
1745071d4279SBram Moolenaar  */
1746071d4279SBram Moolenaar     int
default_fileformat(void)17479b57814dSBram Moolenaar default_fileformat(void)
1748071d4279SBram Moolenaar {
1749071d4279SBram Moolenaar     switch (*p_ffs)
1750071d4279SBram Moolenaar     {
1751071d4279SBram Moolenaar 	case 'm':   return EOL_MAC;
1752071d4279SBram Moolenaar 	case 'd':   return EOL_DOS;
1753071d4279SBram Moolenaar     }
1754071d4279SBram Moolenaar     return EOL_UNIX;
1755071d4279SBram Moolenaar }
1756071d4279SBram Moolenaar 
1757071d4279SBram Moolenaar /*
1758071d4279SBram Moolenaar  * Call shell.	Calls mch_call_shell, with 'shellxquote' added.
1759071d4279SBram Moolenaar  */
1760071d4279SBram Moolenaar     int
call_shell(char_u * cmd,int opt)17619b57814dSBram Moolenaar call_shell(char_u *cmd, int opt)
1762071d4279SBram Moolenaar {
1763071d4279SBram Moolenaar     char_u	*ncmd;
1764071d4279SBram Moolenaar     int		retval;
176505159a0cSBram Moolenaar #ifdef FEAT_PROFILE
176605159a0cSBram Moolenaar     proftime_T	wait_time;
176705159a0cSBram Moolenaar #endif
1768071d4279SBram Moolenaar 
1769071d4279SBram Moolenaar     if (p_verbose > 3)
1770071d4279SBram Moolenaar     {
17715c06f8b0SBram Moolenaar 	verbose_enter();
177206f0853cSBram Moolenaar 	smsg(_("Calling shell to execute: \"%s\""), cmd == NULL ? p_sh : cmd);
1773071d4279SBram Moolenaar 	out_char('\n');
1774071d4279SBram Moolenaar 	cursor_on();
17755c06f8b0SBram Moolenaar 	verbose_leave();
1776071d4279SBram Moolenaar     }
1777071d4279SBram Moolenaar 
177805159a0cSBram Moolenaar #ifdef FEAT_PROFILE
17790126585dSBram Moolenaar     if (do_profiling == PROF_YES)
178005159a0cSBram Moolenaar 	prof_child_enter(&wait_time);
178105159a0cSBram Moolenaar #endif
178205159a0cSBram Moolenaar 
1783071d4279SBram Moolenaar     if (*p_sh == NUL)
1784071d4279SBram Moolenaar     {
1785f9e3e09fSBram Moolenaar 	emsg(_(e_shellempty));
1786071d4279SBram Moolenaar 	retval = -1;
1787071d4279SBram Moolenaar     }
1788071d4279SBram Moolenaar     else
1789071d4279SBram Moolenaar     {
1790071d4279SBram Moolenaar #ifdef FEAT_GUI_MSWIN
179185a2002aSBram Moolenaar 	// Don't hide the pointer while executing a shell command.
1792071d4279SBram Moolenaar 	gui_mch_mousehide(FALSE);
1793071d4279SBram Moolenaar #endif
1794071d4279SBram Moolenaar #ifdef FEAT_GUI
1795071d4279SBram Moolenaar 	++hold_gui_events;
1796071d4279SBram Moolenaar #endif
179785a2002aSBram Moolenaar 	// The external command may update a tags file, clear cached tags.
1798071d4279SBram Moolenaar 	tag_freematch();
1799071d4279SBram Moolenaar 
180001257a7aSBram Moolenaar 	if (cmd == NULL || *p_sxq == NUL)
1801071d4279SBram Moolenaar 	    retval = mch_call_shell(cmd, opt);
1802071d4279SBram Moolenaar 	else
1803071d4279SBram Moolenaar 	{
1804f66b3fcfSBram Moolenaar 	    char_u *ecmd = cmd;
1805f66b3fcfSBram Moolenaar 
18061a613398SBram Moolenaar 	    if (*p_sxe != NUL && *p_sxq == '(')
1807f66b3fcfSBram Moolenaar 	    {
1808f66b3fcfSBram Moolenaar 		ecmd = vim_strsave_escaped_ext(cmd, p_sxe, '^', FALSE);
1809f66b3fcfSBram Moolenaar 		if (ecmd == NULL)
1810f66b3fcfSBram Moolenaar 		    ecmd = cmd;
1811f66b3fcfSBram Moolenaar 	    }
1812964b3746SBram Moolenaar 	    ncmd = alloc(STRLEN(ecmd) + STRLEN(p_sxq) * 2 + 1);
1813071d4279SBram Moolenaar 	    if (ncmd != NULL)
1814071d4279SBram Moolenaar 	    {
1815071d4279SBram Moolenaar 		STRCPY(ncmd, p_sxq);
1816f66b3fcfSBram Moolenaar 		STRCAT(ncmd, ecmd);
18171a613398SBram Moolenaar 		// When 'shellxquote' is ( append ).
18181a613398SBram Moolenaar 		// When 'shellxquote' is "( append )".
18191a613398SBram Moolenaar 		STRCAT(ncmd, *p_sxq == '(' ? (char_u *)")"
18201a613398SBram Moolenaar 		    : *p_sxq == '"' && *(p_sxq+1) == '(' ? (char_u *)")\""
1821034b1155SBram Moolenaar 		    : p_sxq);
1822071d4279SBram Moolenaar 		retval = mch_call_shell(ncmd, opt);
1823071d4279SBram Moolenaar 		vim_free(ncmd);
1824071d4279SBram Moolenaar 	    }
1825071d4279SBram Moolenaar 	    else
1826071d4279SBram Moolenaar 		retval = -1;
1827f66b3fcfSBram Moolenaar 	    if (ecmd != cmd)
1828f66b3fcfSBram Moolenaar 		vim_free(ecmd);
1829071d4279SBram Moolenaar 	}
1830071d4279SBram Moolenaar #ifdef FEAT_GUI
1831071d4279SBram Moolenaar 	--hold_gui_events;
1832071d4279SBram Moolenaar #endif
1833071d4279SBram Moolenaar 	/*
1834071d4279SBram Moolenaar 	 * Check the window size, in case it changed while executing the
1835071d4279SBram Moolenaar 	 * external command.
1836071d4279SBram Moolenaar 	 */
1837071d4279SBram Moolenaar 	shell_resized_check();
1838071d4279SBram Moolenaar     }
1839071d4279SBram Moolenaar 
1840071d4279SBram Moolenaar #ifdef FEAT_EVAL
1841071d4279SBram Moolenaar     set_vim_var_nr(VV_SHELL_ERROR, (long)retval);
184205159a0cSBram Moolenaar # ifdef FEAT_PROFILE
18430126585dSBram Moolenaar     if (do_profiling == PROF_YES)
184405159a0cSBram Moolenaar 	prof_child_exit(&wait_time);
184505159a0cSBram Moolenaar # endif
1846071d4279SBram Moolenaar #endif
1847071d4279SBram Moolenaar 
1848071d4279SBram Moolenaar     return retval;
1849071d4279SBram Moolenaar }
1850071d4279SBram Moolenaar 
1851071d4279SBram Moolenaar /*
18520126585dSBram Moolenaar  * VISUAL, SELECTMODE and OP_PENDING State are never set, they are equal to
18530126585dSBram Moolenaar  * NORMAL State with a condition.  This function returns the real State.
1854071d4279SBram Moolenaar  */
1855071d4279SBram Moolenaar     int
get_real_state(void)18569b57814dSBram Moolenaar get_real_state(void)
1857071d4279SBram Moolenaar {
1858071d4279SBram Moolenaar     if (State & NORMAL)
1859071d4279SBram Moolenaar     {
1860071d4279SBram Moolenaar 	if (VIsual_active)
18610126585dSBram Moolenaar 	{
18620126585dSBram Moolenaar 	    if (VIsual_select)
18630126585dSBram Moolenaar 		return SELECTMODE;
1864071d4279SBram Moolenaar 	    return VISUAL;
18650126585dSBram Moolenaar 	}
1866f7ff6e85SBram Moolenaar 	else if (finish_op)
1867071d4279SBram Moolenaar 	    return OP_PENDING;
1868071d4279SBram Moolenaar     }
1869071d4279SBram Moolenaar     return State;
1870071d4279SBram Moolenaar }
1871071d4279SBram Moolenaar 
18721cd871b5SBram Moolenaar /*
18731cd871b5SBram Moolenaar  * Return TRUE if "p" points to just after a path separator.
1874b5ce04ddSBram Moolenaar  * Takes care of multi-byte characters.
18751cd871b5SBram Moolenaar  * "b" must point to the start of the file name
18761cd871b5SBram Moolenaar  */
18771cd871b5SBram Moolenaar     int
after_pathsep(char_u * b,char_u * p)18789b57814dSBram Moolenaar after_pathsep(char_u *b, char_u *p)
18791cd871b5SBram Moolenaar {
1880b5ce04ddSBram Moolenaar     return p > b && vim_ispathsep(p[-1])
18811cd871b5SBram Moolenaar 			     && (!has_mbyte || (*mb_head_off)(b, p - 1) == 0);
18821cd871b5SBram Moolenaar }
18831cd871b5SBram Moolenaar 
18841cd871b5SBram Moolenaar /*
18851cd871b5SBram Moolenaar  * Return TRUE if file names "f1" and "f2" are in the same directory.
18861cd871b5SBram Moolenaar  * "f1" may be a short name, "f2" must be a full path.
18871cd871b5SBram Moolenaar  */
18881cd871b5SBram Moolenaar     int
same_directory(char_u * f1,char_u * f2)18899b57814dSBram Moolenaar same_directory(char_u *f1, char_u *f2)
18901cd871b5SBram Moolenaar {
18911cd871b5SBram Moolenaar     char_u	ffname[MAXPATHL];
18921cd871b5SBram Moolenaar     char_u	*t1;
18931cd871b5SBram Moolenaar     char_u	*t2;
18941cd871b5SBram Moolenaar 
189585a2002aSBram Moolenaar     // safety check
18961cd871b5SBram Moolenaar     if (f1 == NULL || f2 == NULL)
18971cd871b5SBram Moolenaar 	return FALSE;
18981cd871b5SBram Moolenaar 
18991cd871b5SBram Moolenaar     (void)vim_FullName(f1, ffname, MAXPATHL, FALSE);
19001cd871b5SBram Moolenaar     t1 = gettail_sep(ffname);
19011cd871b5SBram Moolenaar     t2 = gettail_sep(f2);
19021cd871b5SBram Moolenaar     return (t1 - ffname == t2 - f2
19031cd871b5SBram Moolenaar 	     && pathcmp((char *)ffname, (char *)f2, (int)(t1 - ffname)) == 0);
19041cd871b5SBram Moolenaar }
19051cd871b5SBram Moolenaar 
19067c365fb1SBram Moolenaar #if defined(FEAT_SESSION) || defined(FEAT_AUTOCHDIR) \
1907097148e8SBram Moolenaar 	|| defined(MSWIN) || defined(FEAT_GUI_GTK) \
1908bb1969b6SBram Moolenaar 	|| defined(FEAT_NETBEANS_INTG) \
1909071d4279SBram Moolenaar 	|| defined(PROTO)
1910071d4279SBram Moolenaar /*
1911071d4279SBram Moolenaar  * Change to a file's directory.
1912071d4279SBram Moolenaar  * Caller must call shorten_fnames()!
1913071d4279SBram Moolenaar  * Return OK or FAIL.
1914071d4279SBram Moolenaar  */
1915071d4279SBram Moolenaar     int
vim_chdirfile(char_u * fname,char * trigger_autocmd)19162caad3fbSBram Moolenaar vim_chdirfile(char_u *fname, char *trigger_autocmd)
1917071d4279SBram Moolenaar {
19182caad3fbSBram Moolenaar     char_u	old_dir[MAXPATHL];
19192caad3fbSBram Moolenaar     char_u	new_dir[MAXPATHL];
1920b5cb65baSBram Moolenaar     int		res;
1921071d4279SBram Moolenaar 
19222caad3fbSBram Moolenaar     if (mch_dirname(old_dir, MAXPATHL) != OK)
19232caad3fbSBram Moolenaar 	*old_dir = NUL;
19242caad3fbSBram Moolenaar 
19252caad3fbSBram Moolenaar     vim_strncpy(new_dir, fname, MAXPATHL - 1);
19262caad3fbSBram Moolenaar     *gettail_sep(new_dir) = NUL;
19272caad3fbSBram Moolenaar 
19289eb76af4SBram Moolenaar     if (pathcmp((char *)old_dir, (char *)new_dir, -1) == 0)
19292caad3fbSBram Moolenaar 	// nothing to do
19302caad3fbSBram Moolenaar 	res = OK;
19312caad3fbSBram Moolenaar     else
19322caad3fbSBram Moolenaar     {
19332caad3fbSBram Moolenaar 	res = mch_chdir((char *)new_dir) == 0 ? OK : FAIL;
19342caad3fbSBram Moolenaar 
1935b5cb65baSBram Moolenaar 	if (res == OK && trigger_autocmd != NULL)
1936b5cb65baSBram Moolenaar 	    apply_autocmds(EVENT_DIRCHANGED, (char_u *)trigger_autocmd,
19372caad3fbSBram Moolenaar 						       new_dir, FALSE, curbuf);
19382caad3fbSBram Moolenaar     }
1939b5cb65baSBram Moolenaar     return res;
1940071d4279SBram Moolenaar }
1941071d4279SBram Moolenaar #endif
1942071d4279SBram Moolenaar 
1943071d4279SBram Moolenaar #if defined(STAT_IGNORES_SLASH) || defined(PROTO)
1944071d4279SBram Moolenaar /*
1945071d4279SBram Moolenaar  * Check if "name" ends in a slash and is not a directory.
1946071d4279SBram Moolenaar  * Used for systems where stat() ignores a trailing slash on a file name.
1947071d4279SBram Moolenaar  * The Vim code assumes a trailing slash is only ignored for a directory.
1948071d4279SBram Moolenaar  */
194991acfffcSBram Moolenaar     static int
illegal_slash(const char * name)1950d8492792SBram Moolenaar illegal_slash(const char *name)
1951071d4279SBram Moolenaar {
1952071d4279SBram Moolenaar     if (name[0] == NUL)
195385a2002aSBram Moolenaar 	return FALSE;	    // no file name is not illegal
1954071d4279SBram Moolenaar     if (name[strlen(name) - 1] != '/')
195585a2002aSBram Moolenaar 	return FALSE;	    // no trailing slash
1956071d4279SBram Moolenaar     if (mch_isdir((char_u *)name))
195785a2002aSBram Moolenaar 	return FALSE;	    // trailing slash for a directory
1958071d4279SBram Moolenaar     return TRUE;
1959071d4279SBram Moolenaar }
196091acfffcSBram Moolenaar 
196191acfffcSBram Moolenaar /*
196291acfffcSBram Moolenaar  * Special implementation of mch_stat() for Solaris.
196391acfffcSBram Moolenaar  */
196491acfffcSBram Moolenaar     int
vim_stat(const char * name,stat_T * stp)196591acfffcSBram Moolenaar vim_stat(const char *name, stat_T *stp)
196691acfffcSBram Moolenaar {
196785a2002aSBram Moolenaar     // On Solaris stat() accepts "file/" as if it was "file".  Return -1 if
196885a2002aSBram Moolenaar     // the name ends in "/" and it's not a directory.
1969d8492792SBram Moolenaar     return illegal_slash(name) ? -1 : stat(name, stp);
197091acfffcSBram Moolenaar }
1971071d4279SBram Moolenaar #endif
1972071d4279SBram Moolenaar 
1973071d4279SBram Moolenaar #if defined(CURSOR_SHAPE) || defined(PROTO)
1974071d4279SBram Moolenaar 
1975071d4279SBram Moolenaar /*
1976071d4279SBram Moolenaar  * Handling of cursor and mouse pointer shapes in various modes.
1977071d4279SBram Moolenaar  */
1978071d4279SBram Moolenaar 
1979071d4279SBram Moolenaar cursorentry_T shape_table[SHAPE_IDX_COUNT] =
1980071d4279SBram Moolenaar {
198185a2002aSBram Moolenaar     // The values will be filled in from the 'guicursor' and 'mouseshape'
198285a2002aSBram Moolenaar     // defaults when Vim starts.
198385a2002aSBram Moolenaar     // Adjust the SHAPE_IDX_ defines when making changes!
1984071d4279SBram Moolenaar     {0,	0, 0, 700L, 400L, 250L, 0, 0, "n", SHAPE_CURSOR+SHAPE_MOUSE},
1985071d4279SBram Moolenaar     {0,	0, 0, 700L, 400L, 250L, 0, 0, "v", SHAPE_CURSOR+SHAPE_MOUSE},
1986071d4279SBram Moolenaar     {0,	0, 0, 700L, 400L, 250L, 0, 0, "i", SHAPE_CURSOR+SHAPE_MOUSE},
1987071d4279SBram Moolenaar     {0,	0, 0, 700L, 400L, 250L, 0, 0, "r", SHAPE_CURSOR+SHAPE_MOUSE},
1988071d4279SBram Moolenaar     {0,	0, 0, 700L, 400L, 250L, 0, 0, "c", SHAPE_CURSOR+SHAPE_MOUSE},
1989071d4279SBram Moolenaar     {0,	0, 0, 700L, 400L, 250L, 0, 0, "ci", SHAPE_CURSOR+SHAPE_MOUSE},
1990071d4279SBram Moolenaar     {0,	0, 0, 700L, 400L, 250L, 0, 0, "cr", SHAPE_CURSOR+SHAPE_MOUSE},
1991071d4279SBram Moolenaar     {0,	0, 0, 700L, 400L, 250L, 0, 0, "o", SHAPE_CURSOR+SHAPE_MOUSE},
1992071d4279SBram Moolenaar     {0,	0, 0, 700L, 400L, 250L, 0, 0, "ve", SHAPE_CURSOR+SHAPE_MOUSE},
1993071d4279SBram Moolenaar     {0,	0, 0,   0L,   0L,   0L, 0, 0, "e", SHAPE_MOUSE},
1994071d4279SBram Moolenaar     {0,	0, 0,   0L,   0L,   0L, 0, 0, "s", SHAPE_MOUSE},
1995071d4279SBram Moolenaar     {0,	0, 0,   0L,   0L,   0L, 0, 0, "sd", SHAPE_MOUSE},
1996071d4279SBram Moolenaar     {0,	0, 0,   0L,   0L,   0L, 0, 0, "vs", SHAPE_MOUSE},
1997071d4279SBram Moolenaar     {0,	0, 0,   0L,   0L,   0L, 0, 0, "vd", SHAPE_MOUSE},
1998071d4279SBram Moolenaar     {0,	0, 0,   0L,   0L,   0L, 0, 0, "m", SHAPE_MOUSE},
1999071d4279SBram Moolenaar     {0,	0, 0,   0L,   0L,   0L, 0, 0, "ml", SHAPE_MOUSE},
2000071d4279SBram Moolenaar     {0,	0, 0, 100L, 100L, 100L, 0, 0, "sm", SHAPE_CURSOR},
2001071d4279SBram Moolenaar };
2002071d4279SBram Moolenaar 
2003071d4279SBram Moolenaar #ifdef FEAT_MOUSESHAPE
2004071d4279SBram Moolenaar /*
2005071d4279SBram Moolenaar  * Table with names for mouse shapes.  Keep in sync with all the tables for
2006071d4279SBram Moolenaar  * mch_set_mouse_shape()!.
2007071d4279SBram Moolenaar  */
2008071d4279SBram Moolenaar static char * mshape_names[] =
2009071d4279SBram Moolenaar {
201085a2002aSBram Moolenaar     "arrow",	// default, must be the first one
201185a2002aSBram Moolenaar     "blank",	// hidden
2012071d4279SBram Moolenaar     "beam",
2013071d4279SBram Moolenaar     "updown",
2014071d4279SBram Moolenaar     "udsizing",
2015071d4279SBram Moolenaar     "leftright",
2016071d4279SBram Moolenaar     "lrsizing",
2017071d4279SBram Moolenaar     "busy",
2018071d4279SBram Moolenaar     "no",
2019071d4279SBram Moolenaar     "crosshair",
2020071d4279SBram Moolenaar     "hand1",
2021071d4279SBram Moolenaar     "hand2",
2022071d4279SBram Moolenaar     "pencil",
2023071d4279SBram Moolenaar     "question",
2024071d4279SBram Moolenaar     "rightup-arrow",
2025071d4279SBram Moolenaar     "up-arrow",
2026071d4279SBram Moolenaar     NULL
2027071d4279SBram Moolenaar };
2028071d4279SBram Moolenaar #endif
2029071d4279SBram Moolenaar 
2030071d4279SBram Moolenaar /*
2031071d4279SBram Moolenaar  * Parse the 'guicursor' option ("what" is SHAPE_CURSOR) or 'mouseshape'
2032071d4279SBram Moolenaar  * ("what" is SHAPE_MOUSE).
2033071d4279SBram Moolenaar  * Returns error message for an illegal option, NULL otherwise.
2034071d4279SBram Moolenaar  */
2035f9e3e09fSBram Moolenaar     char *
parse_shape_opt(int what)20369b57814dSBram Moolenaar parse_shape_opt(int what)
2037071d4279SBram Moolenaar {
2038071d4279SBram Moolenaar     char_u	*modep;
2039071d4279SBram Moolenaar     char_u	*colonp;
2040071d4279SBram Moolenaar     char_u	*commap;
2041071d4279SBram Moolenaar     char_u	*slashp;
2042071d4279SBram Moolenaar     char_u	*p, *endp;
204385a2002aSBram Moolenaar     int		idx = 0;		// init for GCC
2044071d4279SBram Moolenaar     int		all_idx;
2045071d4279SBram Moolenaar     int		len;
2046071d4279SBram Moolenaar     int		i;
2047071d4279SBram Moolenaar     long	n;
204885a2002aSBram Moolenaar     int		found_ve = FALSE;	// found "ve" flag
2049071d4279SBram Moolenaar     int		round;
2050071d4279SBram Moolenaar 
2051071d4279SBram Moolenaar     /*
2052071d4279SBram Moolenaar      * First round: check for errors; second round: do it for real.
2053071d4279SBram Moolenaar      */
2054071d4279SBram Moolenaar     for (round = 1; round <= 2; ++round)
2055071d4279SBram Moolenaar     {
2056071d4279SBram Moolenaar 	/*
2057071d4279SBram Moolenaar 	 * Repeat for all comma separated parts.
2058071d4279SBram Moolenaar 	 */
2059071d4279SBram Moolenaar #ifdef FEAT_MOUSESHAPE
2060071d4279SBram Moolenaar 	if (what == SHAPE_MOUSE)
2061071d4279SBram Moolenaar 	    modep = p_mouseshape;
2062071d4279SBram Moolenaar 	else
2063071d4279SBram Moolenaar #endif
2064071d4279SBram Moolenaar 	    modep = p_guicursor;
2065071d4279SBram Moolenaar 	while (*modep != NUL)
2066071d4279SBram Moolenaar 	{
2067071d4279SBram Moolenaar 	    colonp = vim_strchr(modep, ':');
206824922ec2SBram Moolenaar 	    commap = vim_strchr(modep, ',');
206924922ec2SBram Moolenaar 
207024922ec2SBram Moolenaar 	    if (colonp == NULL || (commap != NULL && commap < colonp))
2071f9e3e09fSBram Moolenaar 		return N_("E545: Missing colon");
2072071d4279SBram Moolenaar 	    if (colonp == modep)
2073f9e3e09fSBram Moolenaar 		return N_("E546: Illegal mode");
2074071d4279SBram Moolenaar 
2075071d4279SBram Moolenaar 	    /*
2076071d4279SBram Moolenaar 	     * Repeat for all mode's before the colon.
2077071d4279SBram Moolenaar 	     * For the 'a' mode, we loop to handle all the modes.
2078071d4279SBram Moolenaar 	     */
2079071d4279SBram Moolenaar 	    all_idx = -1;
2080071d4279SBram Moolenaar 	    while (modep < colonp || all_idx >= 0)
2081071d4279SBram Moolenaar 	    {
2082071d4279SBram Moolenaar 		if (all_idx < 0)
2083071d4279SBram Moolenaar 		{
208485a2002aSBram Moolenaar 		    // Find the mode.
2085071d4279SBram Moolenaar 		    if (modep[1] == '-' || modep[1] == ':')
2086071d4279SBram Moolenaar 			len = 1;
2087071d4279SBram Moolenaar 		    else
2088071d4279SBram Moolenaar 			len = 2;
2089071d4279SBram Moolenaar 		    if (len == 1 && TOLOWER_ASC(modep[0]) == 'a')
2090071d4279SBram Moolenaar 			all_idx = SHAPE_IDX_COUNT - 1;
2091071d4279SBram Moolenaar 		    else
2092071d4279SBram Moolenaar 		    {
2093071d4279SBram Moolenaar 			for (idx = 0; idx < SHAPE_IDX_COUNT; ++idx)
2094071d4279SBram Moolenaar 			    if (STRNICMP(modep, shape_table[idx].name, len)
2095071d4279SBram Moolenaar 									 == 0)
2096071d4279SBram Moolenaar 				break;
2097071d4279SBram Moolenaar 			if (idx == SHAPE_IDX_COUNT
2098071d4279SBram Moolenaar 				   || (shape_table[idx].used_for & what) == 0)
2099f9e3e09fSBram Moolenaar 			    return N_("E546: Illegal mode");
2100071d4279SBram Moolenaar 			if (len == 2 && modep[0] == 'v' && modep[1] == 'e')
2101071d4279SBram Moolenaar 			    found_ve = TRUE;
2102071d4279SBram Moolenaar 		    }
2103071d4279SBram Moolenaar 		    modep += len + 1;
2104071d4279SBram Moolenaar 		}
2105071d4279SBram Moolenaar 
2106071d4279SBram Moolenaar 		if (all_idx >= 0)
2107071d4279SBram Moolenaar 		    idx = all_idx--;
2108071d4279SBram Moolenaar 		else if (round == 2)
2109071d4279SBram Moolenaar 		{
2110071d4279SBram Moolenaar #ifdef FEAT_MOUSESHAPE
2111071d4279SBram Moolenaar 		    if (what == SHAPE_MOUSE)
2112071d4279SBram Moolenaar 		    {
211385a2002aSBram Moolenaar 			// Set the default, for the missing parts
2114071d4279SBram Moolenaar 			shape_table[idx].mshape = 0;
2115071d4279SBram Moolenaar 		    }
2116071d4279SBram Moolenaar 		    else
2117071d4279SBram Moolenaar #endif
2118071d4279SBram Moolenaar 		    {
211985a2002aSBram Moolenaar 			// Set the defaults, for the missing parts
2120071d4279SBram Moolenaar 			shape_table[idx].shape = SHAPE_BLOCK;
2121071d4279SBram Moolenaar 			shape_table[idx].blinkwait = 700L;
2122071d4279SBram Moolenaar 			shape_table[idx].blinkon = 400L;
2123071d4279SBram Moolenaar 			shape_table[idx].blinkoff = 250L;
2124071d4279SBram Moolenaar 		    }
2125071d4279SBram Moolenaar 		}
2126071d4279SBram Moolenaar 
212785a2002aSBram Moolenaar 		// Parse the part after the colon
2128071d4279SBram Moolenaar 		for (p = colonp + 1; *p && *p != ','; )
2129071d4279SBram Moolenaar 		{
2130071d4279SBram Moolenaar #ifdef FEAT_MOUSESHAPE
2131071d4279SBram Moolenaar 		    if (what == SHAPE_MOUSE)
2132071d4279SBram Moolenaar 		    {
2133071d4279SBram Moolenaar 			for (i = 0; ; ++i)
2134071d4279SBram Moolenaar 			{
2135071d4279SBram Moolenaar 			    if (mshape_names[i] == NULL)
2136071d4279SBram Moolenaar 			    {
2137071d4279SBram Moolenaar 				if (!VIM_ISDIGIT(*p))
2138f9e3e09fSBram Moolenaar 				    return N_("E547: Illegal mouseshape");
2139071d4279SBram Moolenaar 				if (round == 2)
2140071d4279SBram Moolenaar 				    shape_table[idx].mshape =
2141071d4279SBram Moolenaar 					      getdigits(&p) + MSHAPE_NUMBERED;
2142071d4279SBram Moolenaar 				else
2143071d4279SBram Moolenaar 				    (void)getdigits(&p);
2144071d4279SBram Moolenaar 				break;
2145071d4279SBram Moolenaar 			    }
2146071d4279SBram Moolenaar 			    len = (int)STRLEN(mshape_names[i]);
2147071d4279SBram Moolenaar 			    if (STRNICMP(p, mshape_names[i], len) == 0)
2148071d4279SBram Moolenaar 			    {
2149071d4279SBram Moolenaar 				if (round == 2)
2150071d4279SBram Moolenaar 				    shape_table[idx].mshape = i;
2151071d4279SBram Moolenaar 				p += len;
2152071d4279SBram Moolenaar 				break;
2153071d4279SBram Moolenaar 			    }
2154071d4279SBram Moolenaar 			}
2155071d4279SBram Moolenaar 		    }
215685a2002aSBram Moolenaar 		    else // if (what == SHAPE_MOUSE)
2157071d4279SBram Moolenaar #endif
2158071d4279SBram Moolenaar 		    {
2159071d4279SBram Moolenaar 			/*
2160071d4279SBram Moolenaar 			 * First handle the ones with a number argument.
2161071d4279SBram Moolenaar 			 */
2162071d4279SBram Moolenaar 			i = *p;
2163071d4279SBram Moolenaar 			len = 0;
2164071d4279SBram Moolenaar 			if (STRNICMP(p, "ver", 3) == 0)
2165071d4279SBram Moolenaar 			    len = 3;
2166071d4279SBram Moolenaar 			else if (STRNICMP(p, "hor", 3) == 0)
2167071d4279SBram Moolenaar 			    len = 3;
2168071d4279SBram Moolenaar 			else if (STRNICMP(p, "blinkwait", 9) == 0)
2169071d4279SBram Moolenaar 			    len = 9;
2170071d4279SBram Moolenaar 			else if (STRNICMP(p, "blinkon", 7) == 0)
2171071d4279SBram Moolenaar 			    len = 7;
2172071d4279SBram Moolenaar 			else if (STRNICMP(p, "blinkoff", 8) == 0)
2173071d4279SBram Moolenaar 			    len = 8;
2174071d4279SBram Moolenaar 			if (len != 0)
2175071d4279SBram Moolenaar 			{
2176071d4279SBram Moolenaar 			    p += len;
2177071d4279SBram Moolenaar 			    if (!VIM_ISDIGIT(*p))
2178f9e3e09fSBram Moolenaar 				return N_("E548: digit expected");
2179071d4279SBram Moolenaar 			    n = getdigits(&p);
218085a2002aSBram Moolenaar 			    if (len == 3)   // "ver" or "hor"
2181071d4279SBram Moolenaar 			    {
2182071d4279SBram Moolenaar 				if (n == 0)
2183f9e3e09fSBram Moolenaar 				    return N_("E549: Illegal percentage");
2184071d4279SBram Moolenaar 				if (round == 2)
2185071d4279SBram Moolenaar 				{
2186071d4279SBram Moolenaar 				    if (TOLOWER_ASC(i) == 'v')
2187071d4279SBram Moolenaar 					shape_table[idx].shape = SHAPE_VER;
2188071d4279SBram Moolenaar 				    else
2189071d4279SBram Moolenaar 					shape_table[idx].shape = SHAPE_HOR;
2190071d4279SBram Moolenaar 				    shape_table[idx].percentage = n;
2191071d4279SBram Moolenaar 				}
2192071d4279SBram Moolenaar 			    }
2193071d4279SBram Moolenaar 			    else if (round == 2)
2194071d4279SBram Moolenaar 			    {
2195071d4279SBram Moolenaar 				if (len == 9)
2196071d4279SBram Moolenaar 				    shape_table[idx].blinkwait = n;
2197071d4279SBram Moolenaar 				else if (len == 7)
2198071d4279SBram Moolenaar 				    shape_table[idx].blinkon = n;
2199071d4279SBram Moolenaar 				else
2200071d4279SBram Moolenaar 				    shape_table[idx].blinkoff = n;
2201071d4279SBram Moolenaar 			    }
2202071d4279SBram Moolenaar 			}
2203071d4279SBram Moolenaar 			else if (STRNICMP(p, "block", 5) == 0)
2204071d4279SBram Moolenaar 			{
2205071d4279SBram Moolenaar 			    if (round == 2)
2206071d4279SBram Moolenaar 				shape_table[idx].shape = SHAPE_BLOCK;
2207071d4279SBram Moolenaar 			    p += 5;
2208071d4279SBram Moolenaar 			}
220985a2002aSBram Moolenaar 			else	// must be a highlight group name then
2210071d4279SBram Moolenaar 			{
2211071d4279SBram Moolenaar 			    endp = vim_strchr(p, '-');
221285a2002aSBram Moolenaar 			    if (commap == NULL)		    // last part
2213071d4279SBram Moolenaar 			    {
2214071d4279SBram Moolenaar 				if (endp == NULL)
221585a2002aSBram Moolenaar 				    endp = p + STRLEN(p);   // find end of part
2216071d4279SBram Moolenaar 			    }
2217071d4279SBram Moolenaar 			    else if (endp > commap || endp == NULL)
2218071d4279SBram Moolenaar 				endp = commap;
2219071d4279SBram Moolenaar 			    slashp = vim_strchr(p, '/');
2220071d4279SBram Moolenaar 			    if (slashp != NULL && slashp < endp)
2221071d4279SBram Moolenaar 			    {
222285a2002aSBram Moolenaar 				// "group/langmap_group"
2223071d4279SBram Moolenaar 				i = syn_check_group(p, (int)(slashp - p));
2224071d4279SBram Moolenaar 				p = slashp + 1;
2225071d4279SBram Moolenaar 			    }
2226071d4279SBram Moolenaar 			    if (round == 2)
2227071d4279SBram Moolenaar 			    {
2228071d4279SBram Moolenaar 				shape_table[idx].id = syn_check_group(p,
2229071d4279SBram Moolenaar 							     (int)(endp - p));
2230071d4279SBram Moolenaar 				shape_table[idx].id_lm = shape_table[idx].id;
2231071d4279SBram Moolenaar 				if (slashp != NULL && slashp < endp)
2232071d4279SBram Moolenaar 				    shape_table[idx].id = i;
2233071d4279SBram Moolenaar 			    }
2234071d4279SBram Moolenaar 			    p = endp;
2235071d4279SBram Moolenaar 			}
223685a2002aSBram Moolenaar 		    } // if (what != SHAPE_MOUSE)
2237071d4279SBram Moolenaar 
2238071d4279SBram Moolenaar 		    if (*p == '-')
2239071d4279SBram Moolenaar 			++p;
2240071d4279SBram Moolenaar 		}
2241071d4279SBram Moolenaar 	    }
2242071d4279SBram Moolenaar 	    modep = p;
2243071d4279SBram Moolenaar 	    if (*modep == ',')
2244071d4279SBram Moolenaar 		++modep;
2245071d4279SBram Moolenaar 	}
2246071d4279SBram Moolenaar     }
2247071d4279SBram Moolenaar 
224885a2002aSBram Moolenaar     // If the 's' flag is not given, use the 'v' cursor for 's'
2249071d4279SBram Moolenaar     if (!found_ve)
2250071d4279SBram Moolenaar     {
2251071d4279SBram Moolenaar #ifdef FEAT_MOUSESHAPE
2252071d4279SBram Moolenaar 	if (what == SHAPE_MOUSE)
2253071d4279SBram Moolenaar 	{
2254071d4279SBram Moolenaar 	    shape_table[SHAPE_IDX_VE].mshape = shape_table[SHAPE_IDX_V].mshape;
2255071d4279SBram Moolenaar 	}
2256071d4279SBram Moolenaar 	else
2257071d4279SBram Moolenaar #endif
2258071d4279SBram Moolenaar 	{
2259071d4279SBram Moolenaar 	    shape_table[SHAPE_IDX_VE].shape = shape_table[SHAPE_IDX_V].shape;
2260071d4279SBram Moolenaar 	    shape_table[SHAPE_IDX_VE].percentage =
2261071d4279SBram Moolenaar 					 shape_table[SHAPE_IDX_V].percentage;
2262071d4279SBram Moolenaar 	    shape_table[SHAPE_IDX_VE].blinkwait =
2263071d4279SBram Moolenaar 					  shape_table[SHAPE_IDX_V].blinkwait;
2264071d4279SBram Moolenaar 	    shape_table[SHAPE_IDX_VE].blinkon =
2265071d4279SBram Moolenaar 					    shape_table[SHAPE_IDX_V].blinkon;
2266071d4279SBram Moolenaar 	    shape_table[SHAPE_IDX_VE].blinkoff =
2267071d4279SBram Moolenaar 					   shape_table[SHAPE_IDX_V].blinkoff;
2268071d4279SBram Moolenaar 	    shape_table[SHAPE_IDX_VE].id = shape_table[SHAPE_IDX_V].id;
2269071d4279SBram Moolenaar 	    shape_table[SHAPE_IDX_VE].id_lm = shape_table[SHAPE_IDX_V].id_lm;
2270071d4279SBram Moolenaar 	}
2271071d4279SBram Moolenaar     }
2272071d4279SBram Moolenaar 
2273071d4279SBram Moolenaar     return NULL;
2274071d4279SBram Moolenaar }
2275071d4279SBram Moolenaar 
2276ac6e65f8SBram Moolenaar # if defined(MCH_CURSOR_SHAPE) || defined(FEAT_GUI) \
2277ac6e65f8SBram Moolenaar 	|| defined(FEAT_MOUSESHAPE) || defined(PROTO)
2278071d4279SBram Moolenaar /*
2279071d4279SBram Moolenaar  * Return the index into shape_table[] for the current mode.
2280071d4279SBram Moolenaar  * When "mouse" is TRUE, consider indexes valid for the mouse pointer.
2281071d4279SBram Moolenaar  */
2282071d4279SBram Moolenaar     int
get_shape_idx(int mouse)22839b57814dSBram Moolenaar get_shape_idx(int mouse)
2284071d4279SBram Moolenaar {
2285071d4279SBram Moolenaar #ifdef FEAT_MOUSESHAPE
2286071d4279SBram Moolenaar     if (mouse && (State == HITRETURN || State == ASKMORE))
2287071d4279SBram Moolenaar     {
2288071d4279SBram Moolenaar # ifdef FEAT_GUI
22899588a0f7SBram Moolenaar 	int x, y;
22909588a0f7SBram Moolenaar 	gui_mch_getmouse(&x, &y);
22919588a0f7SBram Moolenaar 	if (Y_2_ROW(y) == Rows - 1)
2292071d4279SBram Moolenaar 	    return SHAPE_IDX_MOREL;
2293071d4279SBram Moolenaar # endif
2294071d4279SBram Moolenaar 	return SHAPE_IDX_MORE;
2295071d4279SBram Moolenaar     }
2296071d4279SBram Moolenaar     if (mouse && drag_status_line)
2297071d4279SBram Moolenaar 	return SHAPE_IDX_SDRAG;
2298071d4279SBram Moolenaar     if (mouse && drag_sep_line)
2299071d4279SBram Moolenaar 	return SHAPE_IDX_VDRAG;
2300071d4279SBram Moolenaar #endif
2301071d4279SBram Moolenaar     if (!mouse && State == SHOWMATCH)
2302071d4279SBram Moolenaar 	return SHAPE_IDX_SM;
2303071d4279SBram Moolenaar     if (State & VREPLACE_FLAG)
2304071d4279SBram Moolenaar 	return SHAPE_IDX_R;
2305071d4279SBram Moolenaar     if (State & REPLACE_FLAG)
2306071d4279SBram Moolenaar 	return SHAPE_IDX_R;
2307071d4279SBram Moolenaar     if (State & INSERT)
2308071d4279SBram Moolenaar 	return SHAPE_IDX_I;
2309071d4279SBram Moolenaar     if (State & CMDLINE)
2310071d4279SBram Moolenaar     {
2311071d4279SBram Moolenaar 	if (cmdline_at_end())
2312071d4279SBram Moolenaar 	    return SHAPE_IDX_C;
2313071d4279SBram Moolenaar 	if (cmdline_overstrike())
2314071d4279SBram Moolenaar 	    return SHAPE_IDX_CR;
2315071d4279SBram Moolenaar 	return SHAPE_IDX_CI;
2316071d4279SBram Moolenaar     }
2317071d4279SBram Moolenaar     if (finish_op)
2318071d4279SBram Moolenaar 	return SHAPE_IDX_O;
2319071d4279SBram Moolenaar     if (VIsual_active)
2320071d4279SBram Moolenaar     {
2321071d4279SBram Moolenaar 	if (*p_sel == 'e')
2322071d4279SBram Moolenaar 	    return SHAPE_IDX_VE;
2323071d4279SBram Moolenaar 	else
2324071d4279SBram Moolenaar 	    return SHAPE_IDX_V;
2325071d4279SBram Moolenaar     }
2326071d4279SBram Moolenaar     return SHAPE_IDX_N;
2327071d4279SBram Moolenaar }
2328ac6e65f8SBram Moolenaar #endif
2329071d4279SBram Moolenaar 
2330071d4279SBram Moolenaar # if defined(FEAT_MOUSESHAPE) || defined(PROTO)
2331071d4279SBram Moolenaar static int old_mouse_shape = 0;
2332071d4279SBram Moolenaar 
2333071d4279SBram Moolenaar /*
2334071d4279SBram Moolenaar  * Set the mouse shape:
2335071d4279SBram Moolenaar  * If "shape" is -1, use shape depending on the current mode,
2336071d4279SBram Moolenaar  * depending on the current state.
2337071d4279SBram Moolenaar  * If "shape" is -2, only update the shape when it's CLINE or STATUS (used
2338071d4279SBram Moolenaar  * when the mouse moves off the status or command line).
2339071d4279SBram Moolenaar  */
2340071d4279SBram Moolenaar     void
update_mouseshape(int shape_idx)23419b57814dSBram Moolenaar update_mouseshape(int shape_idx)
2342071d4279SBram Moolenaar {
2343071d4279SBram Moolenaar     int new_mouse_shape;
2344071d4279SBram Moolenaar 
234585a2002aSBram Moolenaar     // Only works in GUI mode.
23466bb68366SBram Moolenaar     if (!gui.in_use || gui.starting)
2347071d4279SBram Moolenaar 	return;
2348071d4279SBram Moolenaar 
234985a2002aSBram Moolenaar     // Postpone the updating when more is to come.  Speeds up executing of
235085a2002aSBram Moolenaar     // mappings.
2351071d4279SBram Moolenaar     if (shape_idx == -1 && char_avail())
2352071d4279SBram Moolenaar     {
2353071d4279SBram Moolenaar 	postponed_mouseshape = TRUE;
2354071d4279SBram Moolenaar 	return;
2355071d4279SBram Moolenaar     }
2356071d4279SBram Moolenaar 
235785a2002aSBram Moolenaar     // When ignoring the mouse don't change shape on the statusline.
235814716817SBram Moolenaar     if (*p_mouse == NUL
235914716817SBram Moolenaar 	    && (shape_idx == SHAPE_IDX_CLINE
236014716817SBram Moolenaar 		|| shape_idx == SHAPE_IDX_STATUS
236114716817SBram Moolenaar 		|| shape_idx == SHAPE_IDX_VSEP))
236214716817SBram Moolenaar 	shape_idx = -2;
236314716817SBram Moolenaar 
2364071d4279SBram Moolenaar     if (shape_idx == -2
2365071d4279SBram Moolenaar 	    && old_mouse_shape != shape_table[SHAPE_IDX_CLINE].mshape
2366071d4279SBram Moolenaar 	    && old_mouse_shape != shape_table[SHAPE_IDX_STATUS].mshape
2367071d4279SBram Moolenaar 	    && old_mouse_shape != shape_table[SHAPE_IDX_VSEP].mshape)
2368071d4279SBram Moolenaar 	return;
2369071d4279SBram Moolenaar     if (shape_idx < 0)
2370071d4279SBram Moolenaar 	new_mouse_shape = shape_table[get_shape_idx(TRUE)].mshape;
2371071d4279SBram Moolenaar     else
2372071d4279SBram Moolenaar 	new_mouse_shape = shape_table[shape_idx].mshape;
2373071d4279SBram Moolenaar     if (new_mouse_shape != old_mouse_shape)
2374071d4279SBram Moolenaar     {
2375071d4279SBram Moolenaar 	mch_set_mouse_shape(new_mouse_shape);
2376071d4279SBram Moolenaar 	old_mouse_shape = new_mouse_shape;
2377071d4279SBram Moolenaar     }
2378071d4279SBram Moolenaar     postponed_mouseshape = FALSE;
2379071d4279SBram Moolenaar }
2380071d4279SBram Moolenaar # endif
2381071d4279SBram Moolenaar 
238285a2002aSBram Moolenaar #endif // CURSOR_SHAPE
2383071d4279SBram Moolenaar 
2384071d4279SBram Moolenaar 
2385071d4279SBram Moolenaar /*
2386071d4279SBram Moolenaar  * Change directory to "new_dir".  If FEAT_SEARCHPATH is defined, search
2387071d4279SBram Moolenaar  * 'cdpath' for relative directory names, otherwise just mch_chdir().
2388071d4279SBram Moolenaar  */
2389071d4279SBram Moolenaar     int
vim_chdir(char_u * new_dir)23909b57814dSBram Moolenaar vim_chdir(char_u *new_dir)
2391071d4279SBram Moolenaar {
2392071d4279SBram Moolenaar #ifndef FEAT_SEARCHPATH
2393071d4279SBram Moolenaar     return mch_chdir((char *)new_dir);
2394071d4279SBram Moolenaar #else
2395071d4279SBram Moolenaar     char_u	*dir_name;
2396071d4279SBram Moolenaar     int		r;
2397071d4279SBram Moolenaar 
2398071d4279SBram Moolenaar     dir_name = find_directory_in_path(new_dir, (int)STRLEN(new_dir),
2399071d4279SBram Moolenaar 						FNAME_MESS, curbuf->b_ffname);
2400071d4279SBram Moolenaar     if (dir_name == NULL)
2401071d4279SBram Moolenaar 	return -1;
2402071d4279SBram Moolenaar     r = mch_chdir((char *)dir_name);
2403071d4279SBram Moolenaar     vim_free(dir_name);
2404071d4279SBram Moolenaar     return r;
2405071d4279SBram Moolenaar #endif
2406071d4279SBram Moolenaar }
2407071d4279SBram Moolenaar 
2408071d4279SBram Moolenaar /*
2409bbebc857SBram Moolenaar  * Get user name from machine-specific function.
2410071d4279SBram Moolenaar  * Returns the user name in "buf[len]".
2411bbebc857SBram Moolenaar  * Some systems are quite slow in obtaining the user name (Windows NT), thus
2412bbebc857SBram Moolenaar  * cache the result.
2413071d4279SBram Moolenaar  * Returns OK or FAIL.
2414071d4279SBram Moolenaar  */
2415071d4279SBram Moolenaar     int
get_user_name(char_u * buf,int len)24169b57814dSBram Moolenaar get_user_name(char_u *buf, int len)
2417071d4279SBram Moolenaar {
2418f461c8e7SBram Moolenaar     if (username == NULL)
2419071d4279SBram Moolenaar     {
2420071d4279SBram Moolenaar 	if (mch_get_user_name(buf, len) == FAIL)
2421071d4279SBram Moolenaar 	    return FAIL;
2422f461c8e7SBram Moolenaar 	username = vim_strsave(buf);
2423071d4279SBram Moolenaar     }
2424071d4279SBram Moolenaar     else
2425bbebc857SBram Moolenaar 	vim_strncpy(buf, username, len - 1);
2426071d4279SBram Moolenaar     return OK;
2427071d4279SBram Moolenaar }
2428071d4279SBram Moolenaar 
2429cbae5802SYegappan Lakshmanan /*
2430cbae5802SYegappan Lakshmanan  * Free the memory allocated by get_user_name()
2431cbae5802SYegappan Lakshmanan  */
2432cbae5802SYegappan Lakshmanan     void
free_username(void)2433cbae5802SYegappan Lakshmanan free_username(void)
2434cbae5802SYegappan Lakshmanan {
2435cbae5802SYegappan Lakshmanan     vim_free(username);
2436cbae5802SYegappan Lakshmanan }
2437cbae5802SYegappan Lakshmanan 
2438071d4279SBram Moolenaar #ifndef HAVE_QSORT
2439071d4279SBram Moolenaar /*
2440071d4279SBram Moolenaar  * Our own qsort(), for systems that don't have it.
2441071d4279SBram Moolenaar  * It's simple and slow.  From the K&R C book.
2442071d4279SBram Moolenaar  */
2443071d4279SBram Moolenaar     void
qsort(void * base,size_t elm_count,size_t elm_size,int (* cmp)(const void *,const void *))24449b57814dSBram Moolenaar qsort(
24459b57814dSBram Moolenaar     void	*base,
24469b57814dSBram Moolenaar     size_t	elm_count,
24479b57814dSBram Moolenaar     size_t	elm_size,
24489b57814dSBram Moolenaar     int (*cmp)(const void *, const void *))
2449071d4279SBram Moolenaar {
2450071d4279SBram Moolenaar     char_u	*buf;
2451071d4279SBram Moolenaar     char_u	*p1;
2452071d4279SBram Moolenaar     char_u	*p2;
2453071d4279SBram Moolenaar     int		i, j;
2454071d4279SBram Moolenaar     int		gap;
2455071d4279SBram Moolenaar 
2456964b3746SBram Moolenaar     buf = alloc(elm_size);
2457071d4279SBram Moolenaar     if (buf == NULL)
2458071d4279SBram Moolenaar 	return;
2459071d4279SBram Moolenaar 
2460071d4279SBram Moolenaar     for (gap = elm_count / 2; gap > 0; gap /= 2)
2461071d4279SBram Moolenaar 	for (i = gap; i < elm_count; ++i)
2462071d4279SBram Moolenaar 	    for (j = i - gap; j >= 0; j -= gap)
2463071d4279SBram Moolenaar 	    {
246485a2002aSBram Moolenaar 		// Compare the elements.
2465071d4279SBram Moolenaar 		p1 = (char_u *)base + j * elm_size;
2466071d4279SBram Moolenaar 		p2 = (char_u *)base + (j + gap) * elm_size;
2467071d4279SBram Moolenaar 		if ((*cmp)((void *)p1, (void *)p2) <= 0)
2468071d4279SBram Moolenaar 		    break;
246985a2002aSBram Moolenaar 		// Exchange the elements.
2470071d4279SBram Moolenaar 		mch_memmove(buf, p1, elm_size);
2471071d4279SBram Moolenaar 		mch_memmove(p1, p2, elm_size);
2472071d4279SBram Moolenaar 		mch_memmove(p2, buf, elm_size);
2473071d4279SBram Moolenaar 	    }
2474071d4279SBram Moolenaar 
2475071d4279SBram Moolenaar     vim_free(buf);
2476071d4279SBram Moolenaar }
2477071d4279SBram Moolenaar #endif
2478071d4279SBram Moolenaar 
2479071d4279SBram Moolenaar /*
2480071d4279SBram Moolenaar  * The putenv() implementation below comes from the "screen" program.
2481071d4279SBram Moolenaar  * Included with permission from Juergen Weigert.
2482071d4279SBram Moolenaar  * See pty.c for the copyright notice.
2483071d4279SBram Moolenaar  */
2484071d4279SBram Moolenaar 
2485071d4279SBram Moolenaar /*
2486071d4279SBram Moolenaar  *  putenv  --	put value into environment
2487071d4279SBram Moolenaar  *
2488071d4279SBram Moolenaar  *  Usage:  i = putenv (string)
2489071d4279SBram Moolenaar  *    int i;
2490071d4279SBram Moolenaar  *    char  *string;
2491071d4279SBram Moolenaar  *
2492071d4279SBram Moolenaar  *  where string is of the form <name>=<value>.
2493071d4279SBram Moolenaar  *  Putenv returns 0 normally, -1 on error (not enough core for malloc).
2494071d4279SBram Moolenaar  *
2495071d4279SBram Moolenaar  *  Putenv may need to add a new name into the environment, or to
2496071d4279SBram Moolenaar  *  associate a value longer than the current value with a particular
2497071d4279SBram Moolenaar  *  name.  So, to make life simpler, putenv() copies your entire
2498071d4279SBram Moolenaar  *  environment into the heap (i.e. malloc()) from the stack
2499071d4279SBram Moolenaar  *  (i.e. where it resides when your process is initiated) the first
2500071d4279SBram Moolenaar  *  time you call it.
2501071d4279SBram Moolenaar  *
2502071d4279SBram Moolenaar  *  (history removed, not very interesting.  See the "screen" sources.)
2503071d4279SBram Moolenaar  */
2504071d4279SBram Moolenaar 
2505071d4279SBram Moolenaar #if !defined(HAVE_SETENV) && !defined(HAVE_PUTENV)
2506071d4279SBram Moolenaar 
250785a2002aSBram Moolenaar #define EXTRASIZE 5		// increment to add to env. size
2508071d4279SBram Moolenaar 
250985a2002aSBram Moolenaar static int  envsize = -1;	// current size of environment
251085a2002aSBram Moolenaar extern char **environ;		// the global which is your env.
2511071d4279SBram Moolenaar 
251285a2002aSBram Moolenaar static int  findenv(char *name); // look for a name in the env.
251385a2002aSBram Moolenaar static int  newenv(void);	// copy env. from stack to heap
251485a2002aSBram Moolenaar static int  moreenv(void);	// incr. size of env.
2515071d4279SBram Moolenaar 
2516071d4279SBram Moolenaar     int
putenv(const char * string)25179b57814dSBram Moolenaar putenv(const char *string)
2518071d4279SBram Moolenaar {
2519071d4279SBram Moolenaar     int	    i;
2520071d4279SBram Moolenaar     char    *p;
2521071d4279SBram Moolenaar 
2522071d4279SBram Moolenaar     if (envsize < 0)
252385a2002aSBram Moolenaar     {				// first time putenv called
252485a2002aSBram Moolenaar 	if (newenv() < 0)	// copy env. to heap
2525071d4279SBram Moolenaar 	    return -1;
2526071d4279SBram Moolenaar     }
2527071d4279SBram Moolenaar 
252885a2002aSBram Moolenaar     i = findenv((char *)string); // look for name in environment
2529071d4279SBram Moolenaar 
2530071d4279SBram Moolenaar     if (i < 0)
253185a2002aSBram Moolenaar     {				// name must be added
2532071d4279SBram Moolenaar 	for (i = 0; environ[i]; i++);
2533071d4279SBram Moolenaar 	if (i >= (envsize - 1))
253485a2002aSBram Moolenaar 	{			// need new slot
2535071d4279SBram Moolenaar 	    if (moreenv() < 0)
2536071d4279SBram Moolenaar 		return -1;
2537071d4279SBram Moolenaar 	}
2538c799fe20SBram Moolenaar 	p = alloc(strlen(string) + 1);
253985a2002aSBram Moolenaar 	if (p == NULL)		// not enough core
2540071d4279SBram Moolenaar 	    return -1;
254185a2002aSBram Moolenaar 	environ[i + 1] = 0;	// new end of env.
2542071d4279SBram Moolenaar     }
2543071d4279SBram Moolenaar     else
254485a2002aSBram Moolenaar     {				// name already in env.
2545071d4279SBram Moolenaar 	p = vim_realloc(environ[i], strlen(string) + 1);
2546071d4279SBram Moolenaar 	if (p == NULL)
2547071d4279SBram Moolenaar 	    return -1;
2548071d4279SBram Moolenaar     }
254985a2002aSBram Moolenaar     sprintf(p, "%s", string);	// copy into env.
2550071d4279SBram Moolenaar     environ[i] = p;
2551071d4279SBram Moolenaar 
2552071d4279SBram Moolenaar     return 0;
2553071d4279SBram Moolenaar }
2554071d4279SBram Moolenaar 
2555071d4279SBram Moolenaar     static int
findenv(char * name)25569b57814dSBram Moolenaar findenv(char *name)
2557071d4279SBram Moolenaar {
2558071d4279SBram Moolenaar     char    *namechar, *envchar;
2559071d4279SBram Moolenaar     int	    i, found;
2560071d4279SBram Moolenaar 
2561071d4279SBram Moolenaar     found = 0;
2562071d4279SBram Moolenaar     for (i = 0; environ[i] && !found; i++)
2563071d4279SBram Moolenaar     {
2564071d4279SBram Moolenaar 	envchar = environ[i];
2565071d4279SBram Moolenaar 	namechar = name;
2566071d4279SBram Moolenaar 	while (*namechar && *namechar != '=' && (*namechar == *envchar))
2567071d4279SBram Moolenaar 	{
2568071d4279SBram Moolenaar 	    namechar++;
2569071d4279SBram Moolenaar 	    envchar++;
2570071d4279SBram Moolenaar 	}
2571071d4279SBram Moolenaar 	found = ((*namechar == '\0' || *namechar == '=') && *envchar == '=');
2572071d4279SBram Moolenaar     }
2573071d4279SBram Moolenaar     return found ? i - 1 : -1;
2574071d4279SBram Moolenaar }
2575071d4279SBram Moolenaar 
2576071d4279SBram Moolenaar     static int
newenv(void)25779b57814dSBram Moolenaar newenv(void)
2578071d4279SBram Moolenaar {
2579071d4279SBram Moolenaar     char    **env, *elem;
2580071d4279SBram Moolenaar     int	    i, esize;
2581071d4279SBram Moolenaar 
2582071d4279SBram Moolenaar     for (i = 0; environ[i]; i++)
2583071d4279SBram Moolenaar 	;
2584d057301bSBram Moolenaar 
2585071d4279SBram Moolenaar     esize = i + EXTRASIZE + 1;
2586c799fe20SBram Moolenaar     env = ALLOC_MULT(char *, esize);
2587071d4279SBram Moolenaar     if (env == NULL)
2588071d4279SBram Moolenaar 	return -1;
2589071d4279SBram Moolenaar 
2590071d4279SBram Moolenaar     for (i = 0; environ[i]; i++)
2591071d4279SBram Moolenaar     {
2592c799fe20SBram Moolenaar 	elem = alloc(strlen(environ[i]) + 1);
2593071d4279SBram Moolenaar 	if (elem == NULL)
2594071d4279SBram Moolenaar 	    return -1;
2595071d4279SBram Moolenaar 	env[i] = elem;
2596071d4279SBram Moolenaar 	strcpy(elem, environ[i]);
2597071d4279SBram Moolenaar     }
2598071d4279SBram Moolenaar 
2599071d4279SBram Moolenaar     env[i] = 0;
2600071d4279SBram Moolenaar     environ = env;
2601071d4279SBram Moolenaar     envsize = esize;
2602071d4279SBram Moolenaar     return 0;
2603071d4279SBram Moolenaar }
2604071d4279SBram Moolenaar 
2605071d4279SBram Moolenaar     static int
moreenv(void)26069b57814dSBram Moolenaar moreenv(void)
2607071d4279SBram Moolenaar {
2608071d4279SBram Moolenaar     int	    esize;
2609071d4279SBram Moolenaar     char    **env;
2610071d4279SBram Moolenaar 
2611071d4279SBram Moolenaar     esize = envsize + EXTRASIZE;
2612c799fe20SBram Moolenaar     env = vim_realloc((char *)environ, esize * sizeof (*env));
2613071d4279SBram Moolenaar     if (env == 0)
2614071d4279SBram Moolenaar 	return -1;
2615071d4279SBram Moolenaar     environ = env;
2616071d4279SBram Moolenaar     envsize = esize;
2617071d4279SBram Moolenaar     return 0;
2618071d4279SBram Moolenaar }
2619071d4279SBram Moolenaar 
2620071d4279SBram Moolenaar # ifdef USE_VIMPTY_GETENV
2621613fe7adSBram Moolenaar /*
2622613fe7adSBram Moolenaar  * Used for mch_getenv() for Mac.
2623613fe7adSBram Moolenaar  */
2624071d4279SBram Moolenaar     char_u *
vimpty_getenv(const char_u * string)26259b57814dSBram Moolenaar vimpty_getenv(const char_u *string)
2626071d4279SBram Moolenaar {
2627071d4279SBram Moolenaar     int i;
2628071d4279SBram Moolenaar     char_u *p;
2629071d4279SBram Moolenaar 
2630071d4279SBram Moolenaar     if (envsize < 0)
2631071d4279SBram Moolenaar 	return NULL;
2632071d4279SBram Moolenaar 
2633071d4279SBram Moolenaar     i = findenv((char *)string);
2634071d4279SBram Moolenaar 
2635071d4279SBram Moolenaar     if (i < 0)
2636071d4279SBram Moolenaar 	return NULL;
2637071d4279SBram Moolenaar 
2638071d4279SBram Moolenaar     p = vim_strchr((char_u *)environ[i], '=');
2639071d4279SBram Moolenaar     return (p + 1);
2640071d4279SBram Moolenaar }
2641071d4279SBram Moolenaar # endif
2642071d4279SBram Moolenaar 
264385a2002aSBram Moolenaar #endif // !defined(HAVE_SETENV) && !defined(HAVE_PUTENV)
2644c4a06d34SBram Moolenaar 
2645c4956c8dSBram Moolenaar #if defined(FEAT_EVAL) || defined(FEAT_SPELL) || defined(PROTO)
2646c4a06d34SBram Moolenaar /*
2647c4a06d34SBram Moolenaar  * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
2648c4a06d34SBram Moolenaar  * rights to write into.
2649c4a06d34SBram Moolenaar  */
2650c4a06d34SBram Moolenaar     int
filewritable(char_u * fname)26519b57814dSBram Moolenaar filewritable(char_u *fname)
2652c4a06d34SBram Moolenaar {
2653c4a06d34SBram Moolenaar     int		retval = 0;
2654c4a06d34SBram Moolenaar #if defined(UNIX) || defined(VMS)
2655c4a06d34SBram Moolenaar     int		perm = 0;
2656c4a06d34SBram Moolenaar #endif
2657c4a06d34SBram Moolenaar 
2658c4a06d34SBram Moolenaar #if defined(UNIX) || defined(VMS)
2659c4a06d34SBram Moolenaar     perm = mch_getperm(fname);
2660c4a06d34SBram Moolenaar #endif
2661c4a06d34SBram Moolenaar     if (
26624f97475dSBram Moolenaar # ifdef MSWIN
2663c4a06d34SBram Moolenaar 	    mch_writable(fname) &&
2664c4a06d34SBram Moolenaar # else
2665c4a06d34SBram Moolenaar # if defined(UNIX) || defined(VMS)
2666c4a06d34SBram Moolenaar 	    (perm & 0222) &&
2667c4a06d34SBram Moolenaar #  endif
2668c4a06d34SBram Moolenaar # endif
2669c4a06d34SBram Moolenaar 	    mch_access((char *)fname, W_OK) == 0
2670c4a06d34SBram Moolenaar        )
2671c4a06d34SBram Moolenaar     {
2672c4a06d34SBram Moolenaar 	++retval;
2673c4a06d34SBram Moolenaar 	if (mch_isdir(fname))
2674c4a06d34SBram Moolenaar 	    ++retval;
2675c4a06d34SBram Moolenaar     }
2676c4a06d34SBram Moolenaar     return retval;
2677c4a06d34SBram Moolenaar }
2678c4a06d34SBram Moolenaar #endif
26796bab4d1fSBram Moolenaar 
2680cdf04208SBram Moolenaar #if defined(FEAT_SPELL) || defined(FEAT_PERSISTENT_UNDO) || defined(PROTO)
2681cdf04208SBram Moolenaar /*
2682cdf04208SBram Moolenaar  * Read 2 bytes from "fd" and turn them into an int, MSB first.
2683e26e0d2bSBram Moolenaar  * Returns -1 when encountering EOF.
2684cdf04208SBram Moolenaar  */
2685cdf04208SBram Moolenaar     int
get2c(FILE * fd)26869b57814dSBram Moolenaar get2c(FILE *fd)
2687cdf04208SBram Moolenaar {
2688e26e0d2bSBram Moolenaar     int		c, n;
2689cdf04208SBram Moolenaar 
2690cdf04208SBram Moolenaar     n = getc(fd);
2691e26e0d2bSBram Moolenaar     if (n == EOF) return -1;
2692e26e0d2bSBram Moolenaar     c = getc(fd);
2693e26e0d2bSBram Moolenaar     if (c == EOF) return -1;
2694e26e0d2bSBram Moolenaar     return (n << 8) + c;
2695cdf04208SBram Moolenaar }
2696cdf04208SBram Moolenaar 
2697cdf04208SBram Moolenaar /*
2698cdf04208SBram Moolenaar  * Read 3 bytes from "fd" and turn them into an int, MSB first.
2699e26e0d2bSBram Moolenaar  * Returns -1 when encountering EOF.
2700cdf04208SBram Moolenaar  */
2701cdf04208SBram Moolenaar     int
get3c(FILE * fd)27029b57814dSBram Moolenaar get3c(FILE *fd)
2703cdf04208SBram Moolenaar {
2704e26e0d2bSBram Moolenaar     int		c, n;
2705cdf04208SBram Moolenaar 
2706cdf04208SBram Moolenaar     n = getc(fd);
2707e26e0d2bSBram Moolenaar     if (n == EOF) return -1;
2708e26e0d2bSBram Moolenaar     c = getc(fd);
2709e26e0d2bSBram Moolenaar     if (c == EOF) return -1;
2710e26e0d2bSBram Moolenaar     n = (n << 8) + c;
2711e26e0d2bSBram Moolenaar     c = getc(fd);
2712e26e0d2bSBram Moolenaar     if (c == EOF) return -1;
2713e26e0d2bSBram Moolenaar     return (n << 8) + c;
2714cdf04208SBram Moolenaar }
2715cdf04208SBram Moolenaar 
2716cdf04208SBram Moolenaar /*
2717cdf04208SBram Moolenaar  * Read 4 bytes from "fd" and turn them into an int, MSB first.
2718e26e0d2bSBram Moolenaar  * Returns -1 when encountering EOF.
2719cdf04208SBram Moolenaar  */
2720cdf04208SBram Moolenaar     int
get4c(FILE * fd)27219b57814dSBram Moolenaar get4c(FILE *fd)
2722cdf04208SBram Moolenaar {
2723e26e0d2bSBram Moolenaar     int		c;
272485a2002aSBram Moolenaar     // Use unsigned rather than int otherwise result is undefined
272585a2002aSBram Moolenaar     // when left-shift sets the MSB.
272695235e64SBram Moolenaar     unsigned	n;
2727cdf04208SBram Moolenaar 
2728e26e0d2bSBram Moolenaar     c = getc(fd);
2729e26e0d2bSBram Moolenaar     if (c == EOF) return -1;
2730e26e0d2bSBram Moolenaar     n = (unsigned)c;
2731e26e0d2bSBram Moolenaar     c = getc(fd);
2732e26e0d2bSBram Moolenaar     if (c == EOF) return -1;
2733e26e0d2bSBram Moolenaar     n = (n << 8) + (unsigned)c;
2734e26e0d2bSBram Moolenaar     c = getc(fd);
2735e26e0d2bSBram Moolenaar     if (c == EOF) return -1;
2736e26e0d2bSBram Moolenaar     n = (n << 8) + (unsigned)c;
2737e26e0d2bSBram Moolenaar     c = getc(fd);
2738e26e0d2bSBram Moolenaar     if (c == EOF) return -1;
2739e26e0d2bSBram Moolenaar     n = (n << 8) + (unsigned)c;
274095235e64SBram Moolenaar     return (int)n;
2741cdf04208SBram Moolenaar }
2742cdf04208SBram Moolenaar 
2743cdf04208SBram Moolenaar /*
2744cdf04208SBram Moolenaar  * Read a string of length "cnt" from "fd" into allocated memory.
2745cdf04208SBram Moolenaar  * Returns NULL when out of memory or unable to read that many bytes.
2746cdf04208SBram Moolenaar  */
2747cdf04208SBram Moolenaar     char_u *
read_string(FILE * fd,int cnt)27489b57814dSBram Moolenaar read_string(FILE *fd, int cnt)
2749cdf04208SBram Moolenaar {
2750cdf04208SBram Moolenaar     char_u	*str;
2751cdf04208SBram Moolenaar     int		i;
2752cdf04208SBram Moolenaar     int		c;
2753cdf04208SBram Moolenaar 
275485a2002aSBram Moolenaar     // allocate memory
2755964b3746SBram Moolenaar     str = alloc(cnt + 1);
2756cdf04208SBram Moolenaar     if (str != NULL)
2757cdf04208SBram Moolenaar     {
275885a2002aSBram Moolenaar 	// Read the string.  Quit when running into the EOF.
2759cdf04208SBram Moolenaar 	for (i = 0; i < cnt; ++i)
2760cdf04208SBram Moolenaar 	{
2761cdf04208SBram Moolenaar 	    c = getc(fd);
2762cdf04208SBram Moolenaar 	    if (c == EOF)
2763cdf04208SBram Moolenaar 	    {
2764cdf04208SBram Moolenaar 		vim_free(str);
2765cdf04208SBram Moolenaar 		return NULL;
2766cdf04208SBram Moolenaar 	    }
2767cdf04208SBram Moolenaar 	    str[i] = c;
2768cdf04208SBram Moolenaar 	}
2769cdf04208SBram Moolenaar 	str[i] = NUL;
2770cdf04208SBram Moolenaar     }
2771cdf04208SBram Moolenaar     return str;
2772cdf04208SBram Moolenaar }
2773cdf04208SBram Moolenaar 
2774cdf04208SBram Moolenaar /*
2775cdf04208SBram Moolenaar  * Write a number to file "fd", MSB first, in "len" bytes.
2776cdf04208SBram Moolenaar  */
2777cdf04208SBram Moolenaar     int
put_bytes(FILE * fd,long_u nr,int len)27789b57814dSBram Moolenaar put_bytes(FILE *fd, long_u nr, int len)
2779cdf04208SBram Moolenaar {
2780cdf04208SBram Moolenaar     int	    i;
2781cdf04208SBram Moolenaar 
2782cdf04208SBram Moolenaar     for (i = len - 1; i >= 0; --i)
2783cdf04208SBram Moolenaar 	if (putc((int)(nr >> (i * 8)), fd) == EOF)
2784cdf04208SBram Moolenaar 	    return FAIL;
2785cdf04208SBram Moolenaar     return OK;
2786cdf04208SBram Moolenaar }
2787cdf04208SBram Moolenaar 
2788cdf04208SBram Moolenaar #endif
278910b7b39bSBram Moolenaar 
279085a2002aSBram Moolenaar #ifndef PROTO  // proto is defined in vim.h
279151628229SBram Moolenaar # ifdef ELAPSED_TIMEVAL
2792833eb1d7SBram Moolenaar /*
2793833eb1d7SBram Moolenaar  * Return time in msec since "start_tv".
2794833eb1d7SBram Moolenaar  */
2795833eb1d7SBram Moolenaar     long
elapsed(struct timeval * start_tv)2796833eb1d7SBram Moolenaar elapsed(struct timeval *start_tv)
2797833eb1d7SBram Moolenaar {
2798833eb1d7SBram Moolenaar     struct timeval  now_tv;
2799833eb1d7SBram Moolenaar 
2800833eb1d7SBram Moolenaar     gettimeofday(&now_tv, NULL);
2801833eb1d7SBram Moolenaar     return (now_tv.tv_sec - start_tv->tv_sec) * 1000L
2802833eb1d7SBram Moolenaar 	 + (now_tv.tv_usec - start_tv->tv_usec) / 1000L;
2803833eb1d7SBram Moolenaar }
2804833eb1d7SBram Moolenaar # endif
2805833eb1d7SBram Moolenaar 
2806833eb1d7SBram Moolenaar # ifdef ELAPSED_TICKCOUNT
2807833eb1d7SBram Moolenaar /*
2808833eb1d7SBram Moolenaar  * Return time in msec since "start_tick".
2809833eb1d7SBram Moolenaar  */
2810833eb1d7SBram Moolenaar     long
elapsed(DWORD start_tick)2811833eb1d7SBram Moolenaar elapsed(DWORD start_tick)
2812833eb1d7SBram Moolenaar {
2813833eb1d7SBram Moolenaar     DWORD	now = GetTickCount();
2814833eb1d7SBram Moolenaar 
2815833eb1d7SBram Moolenaar     return (long)now - (long)start_tick;
2816833eb1d7SBram Moolenaar }
2817833eb1d7SBram Moolenaar # endif
281851628229SBram Moolenaar #endif
281920608920SBram Moolenaar 
282020608920SBram Moolenaar #if defined(FEAT_JOB_CHANNEL) \
282120608920SBram Moolenaar 	|| (defined(UNIX) && (!defined(USE_SYSTEM) \
282220608920SBram Moolenaar 	|| (defined(FEAT_GUI) && defined(FEAT_TERMINAL)))) \
282320608920SBram Moolenaar 	|| defined(PROTO)
282420608920SBram Moolenaar /*
282520608920SBram Moolenaar  * Parse "cmd" and put the white-separated parts in "argv".
282620608920SBram Moolenaar  * "argv" is an allocated array with "argc" entries and room for 4 more.
282720608920SBram Moolenaar  * Returns FAIL when out of memory.
282820608920SBram Moolenaar  */
282920608920SBram Moolenaar     int
mch_parse_cmd(char_u * cmd,int use_shcf,char *** argv,int * argc)283020608920SBram Moolenaar mch_parse_cmd(char_u *cmd, int use_shcf, char ***argv, int *argc)
283120608920SBram Moolenaar {
283220608920SBram Moolenaar     int		i;
283320608920SBram Moolenaar     char_u	*p, *d;
283420608920SBram Moolenaar     int		inquote;
283520608920SBram Moolenaar 
283620608920SBram Moolenaar     /*
283720608920SBram Moolenaar      * Do this loop twice:
283820608920SBram Moolenaar      * 1: find number of arguments
283920608920SBram Moolenaar      * 2: separate them and build argv[]
284020608920SBram Moolenaar      */
28417851b1caSBram Moolenaar     for (i = 1; i <= 2; ++i)
284220608920SBram Moolenaar     {
284320608920SBram Moolenaar 	p = skipwhite(cmd);
284420608920SBram Moolenaar 	inquote = FALSE;
284520608920SBram Moolenaar 	*argc = 0;
28467851b1caSBram Moolenaar 	while (*p != NUL)
284720608920SBram Moolenaar 	{
28487851b1caSBram Moolenaar 	    if (i == 2)
284920608920SBram Moolenaar 		(*argv)[*argc] = (char *)p;
285020608920SBram Moolenaar 	    ++*argc;
285120608920SBram Moolenaar 	    d = p;
285220608920SBram Moolenaar 	    while (*p != NUL && (inquote || (*p != ' ' && *p != TAB)))
285320608920SBram Moolenaar 	    {
285420608920SBram Moolenaar 		if (p[0] == '"')
28551df2fa47SBram Moolenaar 		    // quotes surrounding an argument and are dropped
285620608920SBram Moolenaar 		    inquote = !inquote;
285720608920SBram Moolenaar 		else
285820608920SBram Moolenaar 		{
28591df2fa47SBram Moolenaar 		    if (rem_backslash(p))
286020608920SBram Moolenaar 		    {
28611df2fa47SBram Moolenaar 			// First pass: skip over "\ " and "\"".
28621df2fa47SBram Moolenaar 			// Second pass: Remove the backslash.
286320608920SBram Moolenaar 			++p;
286420608920SBram Moolenaar 		    }
28657851b1caSBram Moolenaar 		    if (i == 2)
286620608920SBram Moolenaar 			*d++ = *p;
286720608920SBram Moolenaar 		}
286820608920SBram Moolenaar 		++p;
286920608920SBram Moolenaar 	    }
287020608920SBram Moolenaar 	    if (*p == NUL)
287120608920SBram Moolenaar 	    {
28727851b1caSBram Moolenaar 		if (i == 2)
287320608920SBram Moolenaar 		    *d++ = NUL;
287420608920SBram Moolenaar 		break;
287520608920SBram Moolenaar 	    }
28767851b1caSBram Moolenaar 	    if (i == 2)
287720608920SBram Moolenaar 		*d++ = NUL;
287820608920SBram Moolenaar 	    p = skipwhite(p + 1);
287920608920SBram Moolenaar 	}
288020608920SBram Moolenaar 	if (*argv == NULL)
288120608920SBram Moolenaar 	{
288220608920SBram Moolenaar 	    if (use_shcf)
288320608920SBram Moolenaar 	    {
288485a2002aSBram Moolenaar 		// Account for possible multiple args in p_shcf.
288520608920SBram Moolenaar 		p = p_shcf;
288620608920SBram Moolenaar 		for (;;)
288720608920SBram Moolenaar 		{
288820608920SBram Moolenaar 		    p = skiptowhite(p);
288920608920SBram Moolenaar 		    if (*p == NUL)
289020608920SBram Moolenaar 			break;
289120608920SBram Moolenaar 		    ++*argc;
289220608920SBram Moolenaar 		    p = skipwhite(p);
289320608920SBram Moolenaar 		}
289420608920SBram Moolenaar 	    }
289520608920SBram Moolenaar 
2896c799fe20SBram Moolenaar 	    *argv = ALLOC_MULT(char *, *argc + 4);
289785a2002aSBram Moolenaar 	    if (*argv == NULL)	    // out of memory
289820608920SBram Moolenaar 		return FAIL;
289920608920SBram Moolenaar 	}
290020608920SBram Moolenaar     }
290120608920SBram Moolenaar     return OK;
290220608920SBram Moolenaar }
2903ebe74b73SBram Moolenaar 
2904ebe74b73SBram Moolenaar # if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
2905ebe74b73SBram Moolenaar /*
2906ebe74b73SBram Moolenaar  * Build "argv[argc]" from the string "cmd".
2907ebe74b73SBram Moolenaar  * "argv[argc]" is set to NULL;
2908ebe74b73SBram Moolenaar  * Return FAIL when out of memory.
2909ebe74b73SBram Moolenaar  */
2910ebe74b73SBram Moolenaar     int
build_argv_from_string(char_u * cmd,char *** argv,int * argc)2911ebe74b73SBram Moolenaar build_argv_from_string(char_u *cmd, char ***argv, int *argc)
2912ebe74b73SBram Moolenaar {
2913ebe74b73SBram Moolenaar     char_u	*cmd_copy;
2914ebe74b73SBram Moolenaar     int		i;
2915ebe74b73SBram Moolenaar 
291685a2002aSBram Moolenaar     // Make a copy, parsing will modify "cmd".
2917ebe74b73SBram Moolenaar     cmd_copy = vim_strsave(cmd);
2918ebe74b73SBram Moolenaar     if (cmd_copy == NULL
2919ebe74b73SBram Moolenaar 	    || mch_parse_cmd(cmd_copy, FALSE, argv, argc) == FAIL)
2920ebe74b73SBram Moolenaar     {
2921ebe74b73SBram Moolenaar 	vim_free(cmd_copy);
2922ebe74b73SBram Moolenaar 	return FAIL;
2923ebe74b73SBram Moolenaar     }
2924ebe74b73SBram Moolenaar     for (i = 0; i < *argc; i++)
2925ebe74b73SBram Moolenaar 	(*argv)[i] = (char *)vim_strsave((char_u *)(*argv)[i]);
2926ebe74b73SBram Moolenaar     (*argv)[*argc] = NULL;
2927ebe74b73SBram Moolenaar     vim_free(cmd_copy);
2928ebe74b73SBram Moolenaar     return OK;
2929ebe74b73SBram Moolenaar }
2930ebe74b73SBram Moolenaar 
2931ebe74b73SBram Moolenaar /*
2932ebe74b73SBram Moolenaar  * Build "argv[argc]" from the list "l".
2933ebe74b73SBram Moolenaar  * "argv[argc]" is set to NULL;
2934ebe74b73SBram Moolenaar  * Return FAIL when out of memory.
2935ebe74b73SBram Moolenaar  */
2936ebe74b73SBram Moolenaar     int
build_argv_from_list(list_T * l,char *** argv,int * argc)2937ebe74b73SBram Moolenaar build_argv_from_list(list_T *l, char ***argv, int *argc)
2938ebe74b73SBram Moolenaar {
2939ebe74b73SBram Moolenaar     listitem_T  *li;
2940ebe74b73SBram Moolenaar     char_u	*s;
2941ebe74b73SBram Moolenaar 
294285a2002aSBram Moolenaar     // Pass argv[] to mch_call_shell().
2943c799fe20SBram Moolenaar     *argv = ALLOC_MULT(char *, l->lv_len + 1);
2944ebe74b73SBram Moolenaar     if (*argv == NULL)
2945ebe74b73SBram Moolenaar 	return FAIL;
2946ebe74b73SBram Moolenaar     *argc = 0;
2947aeea7215SBram Moolenaar     FOR_ALL_LIST_ITEMS(l, li)
2948ebe74b73SBram Moolenaar     {
2949d155d7a8SBram Moolenaar 	s = tv_get_string_chk(&li->li_tv);
2950ebe74b73SBram Moolenaar 	if (s == NULL)
2951ebe74b73SBram Moolenaar 	{
2952ebe74b73SBram Moolenaar 	    int i;
2953ebe74b73SBram Moolenaar 
2954ebe74b73SBram Moolenaar 	    for (i = 0; i < *argc; ++i)
2955df195607SBram Moolenaar 		VIM_CLEAR((*argv)[i]);
2956*7c25a7c0SBram Moolenaar 	    (*argv)[0] = NULL;
2957ebe74b73SBram Moolenaar 	    return FAIL;
2958ebe74b73SBram Moolenaar 	}
2959ebe74b73SBram Moolenaar 	(*argv)[*argc] = (char *)vim_strsave(s);
2960ebe74b73SBram Moolenaar 	*argc += 1;
2961ebe74b73SBram Moolenaar     }
2962ebe74b73SBram Moolenaar     (*argv)[*argc] = NULL;
2963ebe74b73SBram Moolenaar     return OK;
2964ebe74b73SBram Moolenaar }
2965ebe74b73SBram Moolenaar # endif
296620608920SBram Moolenaar #endif
296757da6981SBram Moolenaar 
296857da6981SBram Moolenaar /*
296957da6981SBram Moolenaar  * Change the behavior of vterm.
297057da6981SBram Moolenaar  * 0: As usual.
297157da6981SBram Moolenaar  * 1: Windows 10 version 1809
297257da6981SBram Moolenaar  *      The bug causes unstable handling of ambiguous width character.
297336e7a823SBram Moolenaar  * 2: Windows 10 version 1903 & 1909
297457da6981SBram Moolenaar  *      Use the wrong result because each result is different.
297557da6981SBram Moolenaar  * 3: Windows 10 insider preview (current latest logic)
297657da6981SBram Moolenaar  */
297757da6981SBram Moolenaar     int
get_special_pty_type(void)297857da6981SBram Moolenaar get_special_pty_type(void)
297957da6981SBram Moolenaar {
298057da6981SBram Moolenaar #ifdef MSWIN
298157da6981SBram Moolenaar     return get_conpty_type();
298257da6981SBram Moolenaar #else
298357da6981SBram Moolenaar     return 0;
298457da6981SBram Moolenaar #endif
298557da6981SBram Moolenaar }
2986