xref: /vim-8.2.3635/src/misc2.c (revision 843ee41e)
1 /* vi:set ts=8 sts=4 sw=4:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 
10 /*
11  * misc2.c: Various functions.
12  */
13 #include "vim.h"
14 
15 #ifdef HAVE_FCNTL_H
16 # include <fcntl.h>	    /* for chdir() */
17 #endif
18 
19 #if defined(FEAT_VIRTUALEDIT) || defined(PROTO)
20 static int coladvance2 __ARGS((pos_T *pos, int addspaces, int finetune, colnr_T wcol));
21 
22 /*
23  * Return TRUE if in the current mode we need to use virtual.
24  */
25     int
26 virtual_active()
27 {
28     /* While an operator is being executed we return "virtual_op", because
29      * VIsual_active has already been reset, thus we can't check for "block"
30      * being used. */
31     if (virtual_op != MAYBE)
32 	return virtual_op;
33     return (ve_flags == VE_ALL
34 # ifdef FEAT_VISUAL
35 	    || ((ve_flags & VE_BLOCK) && VIsual_active && VIsual_mode == Ctrl_V)
36 # endif
37 	    || ((ve_flags & VE_INSERT) && (State & INSERT)));
38 }
39 
40 /*
41  * Get the screen position of the cursor.
42  */
43     int
44 getviscol()
45 {
46     colnr_T	x;
47 
48     getvvcol(curwin, &curwin->w_cursor, &x, NULL, NULL);
49     return (int)x;
50 }
51 
52 /*
53  * Get the screen position of character col with a coladd in the cursor line.
54  */
55     int
56 getviscol2(col, coladd)
57     colnr_T	col;
58     colnr_T	coladd;
59 {
60     colnr_T	x;
61     pos_T	pos;
62 
63     pos.lnum = curwin->w_cursor.lnum;
64     pos.col = col;
65     pos.coladd = coladd;
66     getvvcol(curwin, &pos, &x, NULL, NULL);
67     return (int)x;
68 }
69 
70 /*
71  * Go to column "wcol", and add/insert white space as neccessary to get the
72  * cursor in that column.
73  * The caller must have saved the cursor line for undo!
74  */
75     int
76 coladvance_force(wcol)
77     colnr_T wcol;
78 {
79     int rc = coladvance2(&curwin->w_cursor, TRUE, FALSE, wcol);
80 
81     if (wcol == MAXCOL)
82 	curwin->w_valid &= ~VALID_VIRTCOL;
83     else
84     {
85 	/* Virtcol is valid */
86 	curwin->w_valid |= VALID_VIRTCOL;
87 	curwin->w_virtcol = wcol;
88     }
89     return rc;
90 }
91 #endif
92 
93 /*
94  * Try to advance the Cursor to the specified screen column.
95  * If virtual editing: fine tune the cursor position.
96  * Note that all virtual positions off the end of a line should share
97  * a curwin->w_cursor.col value (n.b. this is equal to STRLEN(line)),
98  * beginning at coladd 0.
99  *
100  * return OK if desired column is reached, FAIL if not
101  */
102     int
103 coladvance(wcol)
104     colnr_T	wcol;
105 {
106     int rc = getvpos(&curwin->w_cursor, wcol);
107 
108     if (wcol == MAXCOL || rc == FAIL)
109 	curwin->w_valid &= ~VALID_VIRTCOL;
110     else
111     {
112 	/* Virtcol is valid */
113 	curwin->w_valid |= VALID_VIRTCOL;
114 	curwin->w_virtcol = wcol;
115     }
116     return rc;
117 }
118 
119 /*
120  * Return in "pos" the position of the cursor advanced to screen column "wcol".
121  * return OK if desired column is reached, FAIL if not
122  */
123     int
124 getvpos(pos, wcol)
125     pos_T   *pos;
126     colnr_T wcol;
127 {
128 #ifdef FEAT_VIRTUALEDIT
129     return coladvance2(pos, FALSE, virtual_active(), wcol);
130 }
131 
132     static int
133 coladvance2(pos, addspaces, finetune, wcol)
134     pos_T	*pos;
135     int		addspaces;	/* change the text to achieve our goal? */
136     int		finetune;	/* change char offset for the excact column */
137     colnr_T	wcol;		/* column to move to */
138 {
139 #endif
140     int		idx;
141     char_u	*ptr;
142     char_u	*line;
143     colnr_T	col = 0;
144     int		csize = 0;
145     int		one_more;
146 #ifdef FEAT_LINEBREAK
147     int		head = 0;
148 #endif
149 
150     one_more = (State & INSERT) || restart_edit != NUL
151 #ifdef FEAT_VISUAL
152 					  || (VIsual_active && *p_sel != 'o')
153 #endif
154 					  ;
155     line = ml_get_curline();
156 
157     if (wcol >= MAXCOL)
158     {
159 	    idx = (int)STRLEN(line) - 1 + one_more;
160 	    col = wcol;
161 
162 #ifdef FEAT_VIRTUALEDIT
163 	    if ((addspaces || finetune) && !VIsual_active)
164 	    {
165 		curwin->w_curswant = linetabsize(line) + one_more;
166 		if (curwin->w_curswant > 0)
167 		    --curwin->w_curswant;
168 	    }
169 #endif
170     }
171     else
172     {
173 #ifdef FEAT_VIRTUALEDIT
174 	int width = W_WIDTH(curwin) - win_col_off(curwin);
175 
176 	if ((addspaces || finetune)
177 		&& curwin->w_p_wrap
178 # ifdef FEAT_VERTSPLIT
179 		&& curwin->w_width != 0
180 # endif
181 		&& wcol >= (colnr_T)width)
182 	{
183 	    csize = linetabsize(line);
184 	    if (csize > 0)
185 		csize--;
186 
187 	    if (wcol / width > (colnr_T)csize / width)
188 	    {
189 		/* In case of line wrapping don't move the cursor beyond the
190 		 * right screen edge. */
191 		wcol = (csize / width + 1) * width - 1;
192 	    }
193 	}
194 #endif
195 
196 	idx = -1;
197 	ptr = line;
198 	while (col <= wcol && *ptr != NUL)
199 	{
200 	    /* Count a tab for what it's worth (if list mode not on) */
201 #ifdef FEAT_LINEBREAK
202 	    csize = win_lbr_chartabsize(curwin, ptr, col, &head);
203 # ifdef FEAT_MBYTE
204 	    if (has_mbyte)
205 		ptr += (*mb_ptr2len_check)(ptr);
206 	    else
207 # endif
208 		++ptr;
209 #else
210 	    csize = lbr_chartabsize_adv(&ptr, col);
211 #endif
212 	    col += csize;
213 	}
214 	idx = (int)(ptr - line);
215 	/*
216 	 * Handle all the special cases.  The virtual_active() check
217 	 * is needed to ensure that a virtual position off the end of
218 	 * a line has the correct indexing.  The one_more comparison
219 	 * replaces an explicit add of one_more later on.
220 	 */
221 	if (col > wcol || (!virtual_active() && one_more == 0))
222 	{
223 	    idx -= 1;
224 # ifdef FEAT_LINEBREAK
225 	    /* Don't count the chars from 'showbreak'. */
226 	    csize -= head;
227 # endif
228 	    col -= csize;
229 	}
230 
231 #ifdef FEAT_VIRTUALEDIT
232 	if (virtual_active()
233 		&& addspaces
234 		&& ((col != wcol && col != wcol + 1) || csize > 1))
235 	{
236 	    /* 'virtualedit' is set: The difference between wcol and col is
237 	     * filled with spaces. */
238 
239 	    if (line[idx] == NUL)
240 	    {
241 		/* Append spaces */
242 		int	correct = wcol - col;
243 		char_u	*newline = alloc(idx + correct + 1);
244 		int	t;
245 
246 		if (newline == NULL)
247 		    return FAIL;
248 
249 		for (t = 0; t < idx; ++t)
250 		    newline[t] = line[t];
251 
252 		for (t = 0; t < correct; ++t)
253 		    newline[t + idx] = ' ';
254 
255 		newline[idx + correct] = NUL;
256 
257 		ml_replace(pos->lnum, newline, FALSE);
258 		changed_bytes(pos->lnum, (colnr_T)idx);
259 		idx += correct;
260 		col = wcol;
261 	    }
262 	    else
263 	    {
264 		/* Break a tab */
265 		int	linelen = (int)STRLEN(line);
266 		int	correct = wcol - col - csize + 1; /* negative!! */
267 		char_u	*newline = alloc(linelen + csize);
268 		int	t, s = 0;
269 		int	v;
270 
271 		/*
272 		 * break a tab
273 		 */
274 		if (newline == NULL || -correct > csize)
275 		    return FAIL;
276 
277 		for (t = 0; t < linelen; t++)
278 		{
279 		    if (t != idx)
280 			newline[s++] = line[t];
281 		    else
282 			for (v = 0; v < csize; v++)
283 			    newline[s++] = ' ';
284 		}
285 
286 		newline[linelen + csize - 1] = NUL;
287 
288 		ml_replace(pos->lnum, newline, FALSE);
289 		changed_bytes(pos->lnum, idx);
290 		idx += (csize - 1 + correct);
291 		col += correct;
292 	    }
293 	}
294 #endif
295     }
296 
297     if (idx < 0)
298 	pos->col = 0;
299     else
300 	pos->col = idx;
301 
302 #ifdef FEAT_VIRTUALEDIT
303     pos->coladd = 0;
304 
305     if (finetune)
306     {
307 	if (wcol == MAXCOL)
308 	{
309 	    /* The width of the last character is used to set coladd. */
310 	    if (!one_more)
311 	    {
312 		colnr_T	    scol, ecol;
313 
314 		getvcol(curwin, pos, &scol, NULL, &ecol);
315 		pos->coladd = ecol - scol;
316 	    }
317 	}
318 	else
319 	{
320 	    int b = (int)wcol - (int)col;
321 
322 	    /* The difference between wcol and col is used to set coladd. */
323 	    if (b > 0 && b < (MAXCOL - 2 * W_WIDTH(curwin)))
324 		pos->coladd = b;
325 
326 	    col += b;
327 	}
328     }
329 #endif
330 
331 #ifdef FEAT_MBYTE
332     /* prevent cursor from moving on the trail byte */
333     if (has_mbyte)
334 	mb_adjust_cursor();
335 #endif
336 
337     if (col < wcol)
338 	return FAIL;
339     return OK;
340 }
341 
342 /*
343  * inc(p)
344  *
345  * Increment the line pointer 'p' crossing line boundaries as necessary.
346  * Return 1 when going to the next line.
347  * Return 2 when moving forward onto a NUL at the end of the line).
348  * Return -1 when at the end of file.
349  * Return 0 otherwise.
350  */
351     int
352 inc_cursor()
353 {
354     return inc(&curwin->w_cursor);
355 }
356 
357     int
358 inc(lp)
359     pos_T  *lp;
360 {
361     char_u  *p = ml_get_pos(lp);
362 
363     if (*p != NUL)	/* still within line, move to next char (may be NUL) */
364     {
365 #ifdef FEAT_MBYTE
366 	if (has_mbyte)
367 	{
368 	    int l = (*mb_ptr2len_check)(p);
369 
370 	    lp->col += l;
371 	    return ((p[l] != NUL) ? 0 : 2);
372 	}
373 #endif
374 	lp->col++;
375 #ifdef FEAT_VIRTUALEDIT
376 	lp->coladd = 0;
377 #endif
378 	return ((p[1] != NUL) ? 0 : 2);
379     }
380     if (lp->lnum != curbuf->b_ml.ml_line_count)     /* there is a next line */
381     {
382 	lp->col = 0;
383 	lp->lnum++;
384 #ifdef FEAT_VIRTUALEDIT
385 	lp->coladd = 0;
386 #endif
387 	return 1;
388     }
389     return -1;
390 }
391 
392 /*
393  * incl(lp): same as inc(), but skip the NUL at the end of non-empty lines
394  */
395     int
396 incl(lp)
397     pos_T    *lp;
398 {
399     int	    r;
400 
401     if ((r = inc(lp)) >= 1 && lp->col)
402 	r = inc(lp);
403     return r;
404 }
405 
406 /*
407  * dec(p)
408  *
409  * Decrement the line pointer 'p' crossing line boundaries as necessary.
410  * Return 1 when crossing a line, -1 when at start of file, 0 otherwise.
411  */
412     int
413 dec_cursor()
414 {
415     return dec(&curwin->w_cursor);
416 }
417 
418     int
419 dec(lp)
420     pos_T  *lp;
421 {
422     char_u	*p;
423 
424 #ifdef FEAT_VIRTUALEDIT
425     lp->coladd = 0;
426 #endif
427     if (lp->col > 0)		/* still within line */
428     {
429 	lp->col--;
430 #ifdef FEAT_MBYTE
431 	if (has_mbyte)
432 	{
433 	    p = ml_get(lp->lnum);
434 	    lp->col -= (*mb_head_off)(p, p + lp->col);
435 	}
436 #endif
437 	return 0;
438     }
439     if (lp->lnum > 1)		/* there is a prior line */
440     {
441 	lp->lnum--;
442 	p = ml_get(lp->lnum);
443 	lp->col = (colnr_T)STRLEN(p);
444 #ifdef FEAT_MBYTE
445 	if (has_mbyte)
446 	    lp->col -= (*mb_head_off)(p, p + lp->col);
447 #endif
448 	return 1;
449     }
450     return -1;			/* at start of file */
451 }
452 
453 /*
454  * decl(lp): same as dec(), but skip the NUL at the end of non-empty lines
455  */
456     int
457 decl(lp)
458     pos_T    *lp;
459 {
460     int	    r;
461 
462     if ((r = dec(lp)) == 1 && lp->col)
463 	r = dec(lp);
464     return r;
465 }
466 
467 /*
468  * Make sure curwin->w_cursor.lnum is valid.
469  */
470     void
471 check_cursor_lnum()
472 {
473     if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
474     {
475 #ifdef FEAT_FOLDING
476 	/* If there is a closed fold at the end of the file, put the cursor in
477 	 * its first line.  Otherwise in the last line. */
478 	if (!hasFolding(curbuf->b_ml.ml_line_count,
479 						&curwin->w_cursor.lnum, NULL))
480 #endif
481 	    curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
482     }
483     if (curwin->w_cursor.lnum <= 0)
484 	curwin->w_cursor.lnum = 1;
485 }
486 
487 /*
488  * Make sure curwin->w_cursor.col is valid.
489  */
490     void
491 check_cursor_col()
492 {
493     colnr_T len;
494 #ifdef FEAT_VIRTUALEDIT
495     colnr_T oldcol = curwin->w_cursor.col + curwin->w_cursor.coladd;
496 #endif
497 
498     len = (colnr_T)STRLEN(ml_get_curline());
499     if (len == 0)
500 	curwin->w_cursor.col = 0;
501     else if (curwin->w_cursor.col >= len)
502     {
503 	/* Allow cursor past end-of-line in Insert mode, restarting Insert
504 	 * mode or when in Visual mode and 'selection' isn't "old" */
505 	if (State & INSERT || restart_edit
506 #ifdef FEAT_VISUAL
507 		|| (VIsual_active && *p_sel != 'o')
508 #endif
509 		|| virtual_active())
510 	    curwin->w_cursor.col = len;
511 	else
512 	    curwin->w_cursor.col = len - 1;
513     }
514 
515 #ifdef FEAT_VIRTUALEDIT
516     /* If virtual editing is on, we can leave the cursor on the old position,
517      * only we must set it to virtual.  But don't do it when at the end of the
518      * line. */
519     if (oldcol == MAXCOL)
520 	curwin->w_cursor.coladd = 0;
521     else if (ve_flags == VE_ALL)
522 	curwin->w_cursor.coladd = oldcol - curwin->w_cursor.col;
523 #endif
524 }
525 
526 /*
527  * make sure curwin->w_cursor in on a valid character
528  */
529     void
530 check_cursor()
531 {
532     check_cursor_lnum();
533     check_cursor_col();
534 }
535 
536 #if defined(FEAT_TEXTOBJ) || defined(PROTO)
537 /*
538  * Make sure curwin->w_cursor is not on the NUL at the end of the line.
539  * Allow it when in Visual mode and 'selection' is not "old".
540  */
541     void
542 adjust_cursor_col()
543 {
544     if (curwin->w_cursor.col > 0
545 # ifdef FEAT_VISUAL
546 	    && (!VIsual_active || *p_sel == 'o')
547 # endif
548 	    && gchar_cursor() == NUL)
549 	--curwin->w_cursor.col;
550 }
551 #endif
552 
553 /*
554  * When curwin->w_leftcol has changed, adjust the cursor position.
555  * Return TRUE if the cursor was moved.
556  */
557     int
558 leftcol_changed()
559 {
560     long	lastcol;
561     colnr_T	s, e;
562     int		retval = FALSE;
563 
564     changed_cline_bef_curs();
565     lastcol = curwin->w_leftcol + W_WIDTH(curwin) - curwin_col_off() - 1;
566     validate_virtcol();
567 
568     /*
569      * If the cursor is right or left of the screen, move it to last or first
570      * character.
571      */
572     if (curwin->w_virtcol > (colnr_T)(lastcol - p_siso))
573     {
574 	retval = TRUE;
575 	coladvance((colnr_T)(lastcol - p_siso));
576     }
577     else if (curwin->w_virtcol < curwin->w_leftcol + p_siso)
578     {
579 	retval = TRUE;
580 	(void)coladvance((colnr_T)(curwin->w_leftcol + p_siso));
581     }
582 
583     /*
584      * If the start of the character under the cursor is not on the screen,
585      * advance the cursor one more char.  If this fails (last char of the
586      * line) adjust the scrolling.
587      */
588     getvvcol(curwin, &curwin->w_cursor, &s, NULL, &e);
589     if (e > (colnr_T)lastcol)
590     {
591 	retval = TRUE;
592 	coladvance(s - 1);
593     }
594     else if (s < curwin->w_leftcol)
595     {
596 	retval = TRUE;
597 	if (coladvance(e + 1) == FAIL)	/* there isn't another character */
598 	{
599 	    curwin->w_leftcol = s;	/* adjust w_leftcol instead */
600 	    changed_cline_bef_curs();
601 	}
602     }
603 
604     if (retval)
605 	curwin->w_set_curswant = TRUE;
606     redraw_later(NOT_VALID);
607     return retval;
608 }
609 
610 /**********************************************************************
611  * Various routines dealing with allocation and deallocation of memory.
612  */
613 
614 #if defined(MEM_PROFILE) || defined(PROTO)
615 
616 # define MEM_SIZES  8200
617 static long_u mem_allocs[MEM_SIZES];
618 static long_u mem_frees[MEM_SIZES];
619 static long_u mem_allocated;
620 static long_u mem_freed;
621 static long_u mem_peak;
622 static long_u num_alloc;
623 static long_u num_freed;
624 
625 static void mem_pre_alloc_s __ARGS((size_t *sizep));
626 static void mem_pre_alloc_l __ARGS((long_u *sizep));
627 static void mem_post_alloc __ARGS((void **pp, size_t size));
628 static void mem_pre_free __ARGS((void **pp));
629 
630     static void
631 mem_pre_alloc_s(sizep)
632     size_t *sizep;
633 {
634     *sizep += sizeof(size_t);
635 }
636 
637     static void
638 mem_pre_alloc_l(sizep)
639     long_u *sizep;
640 {
641     *sizep += sizeof(size_t);
642 }
643 
644     static void
645 mem_post_alloc(pp, size)
646     void **pp;
647     size_t size;
648 {
649     if (*pp == NULL)
650 	return;
651     size -= sizeof(size_t);
652     *(long_u *)*pp = size;
653     if (size <= MEM_SIZES-1)
654 	mem_allocs[size-1]++;
655     else
656 	mem_allocs[MEM_SIZES-1]++;
657     mem_allocated += size;
658     if (mem_allocated - mem_freed > mem_peak)
659 	mem_peak = mem_allocated - mem_freed;
660     num_alloc++;
661     *pp = (void *)((char *)*pp + sizeof(size_t));
662 }
663 
664     static void
665 mem_pre_free(pp)
666     void **pp;
667 {
668     long_u size;
669 
670     *pp = (void *)((char *)*pp - sizeof(size_t));
671     size = *(size_t *)*pp;
672     if (size <= MEM_SIZES-1)
673 	mem_frees[size-1]++;
674     else
675 	mem_frees[MEM_SIZES-1]++;
676     mem_freed += size;
677     num_freed++;
678 }
679 
680 /*
681  * called on exit via atexit()
682  */
683     void
684 vim_mem_profile_dump()
685 {
686     int i, j;
687 
688     printf("\r\n");
689     j = 0;
690     for (i = 0; i < MEM_SIZES - 1; i++)
691     {
692 	if (mem_allocs[i] || mem_frees[i])
693 	{
694 	    if (mem_frees[i] > mem_allocs[i])
695 		printf("\r\n%s", _("ERROR: "));
696 	    printf("[%4d / %4lu-%-4lu] ", i + 1, mem_allocs[i], mem_frees[i]);
697 	    j++;
698 	    if (j > 3)
699 	    {
700 		j = 0;
701 		printf("\r\n");
702 	    }
703 	}
704     }
705 
706     i = MEM_SIZES - 1;
707     if (mem_allocs[i])
708     {
709 	printf("\r\n");
710 	if (mem_frees[i] > mem_allocs[i])
711 	    printf(_("ERROR: "));
712 	printf("[>%d / %4lu-%-4lu]", i, mem_allocs[i], mem_frees[i]);
713     }
714 
715     printf(_("\n[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"),
716 	    mem_allocated, mem_freed, mem_allocated - mem_freed, mem_peak);
717     printf(_("[calls] total re/malloc()'s %lu, total free()'s %lu\n\n"),
718 	    num_alloc, num_freed);
719 }
720 
721 #endif /* MEM_PROFILE */
722 
723 /*
724  * Some memory is reserved for error messages and for being able to
725  * call mf_release_all(), which needs some memory for mf_trans_add().
726  */
727 #if defined(MSDOS) && !defined(DJGPP)
728 # define SMALL_MEM
729 # define KEEP_ROOM 8192L
730 #else
731 # define KEEP_ROOM (2 * 8192L)
732 #endif
733 
734 /*
735  * Note: if unsinged is 16 bits we can only allocate up to 64K with alloc().
736  * Use lalloc for larger blocks.
737  */
738     char_u *
739 alloc(size)
740     unsigned	    size;
741 {
742     return (lalloc((long_u)size, TRUE));
743 }
744 
745 /*
746  * Allocate memory and set all bytes to zero.
747  */
748     char_u *
749 alloc_clear(size)
750     unsigned	    size;
751 {
752     char_u *p;
753 
754     p = (lalloc((long_u)size, TRUE));
755     if (p != NULL)
756 	(void)vim_memset(p, 0, (size_t)size);
757     return p;
758 }
759 
760 /*
761  * alloc() with check for maximum line length
762  */
763     char_u *
764 alloc_check(size)
765     unsigned	    size;
766 {
767 #if !defined(UNIX) && !defined(__EMX__)
768     if (sizeof(int) == 2 && size > 0x7fff)
769     {
770 	/* Don't hide this message */
771 	emsg_silent = 0;
772 	EMSG(_("E340: Line is becoming too long"));
773 	return NULL;
774     }
775 #endif
776     return (lalloc((long_u)size, TRUE));
777 }
778 
779 /*
780  * Allocate memory like lalloc() and set all bytes to zero.
781  */
782     char_u *
783 lalloc_clear(size, message)
784     long_u	size;
785     int		message;
786 {
787     char_u *p;
788 
789     p = (lalloc(size, message));
790     if (p != NULL)
791 	(void)vim_memset(p, 0, (size_t)size);
792     return p;
793 }
794 
795 /*
796  * Low level memory allocation function.
797  * This is used often, KEEP IT FAST!
798  */
799     char_u *
800 lalloc(size, message)
801     long_u	size;
802     int		message;
803 {
804     char_u	*p;		    /* pointer to new storage space */
805     static int	releasing = FALSE;  /* don't do mf_release_all() recursive */
806     int		try_again;
807 #if defined(HAVE_AVAIL_MEM) && !defined(SMALL_MEM)
808     static long_u allocated = 0;    /* allocated since last avail check */
809 #endif
810 
811     /* Safety check for allocating zero bytes */
812     if (size == 0)
813     {
814 	/* Don't hide this message */
815 	emsg_silent = 0;
816 	EMSGN(_("E341: Internal error: lalloc(%ld, )"), size);
817 	return NULL;
818     }
819 
820 #ifdef MEM_PROFILE
821     mem_pre_alloc_l(&size);
822 #endif
823 
824 #if defined(MSDOS) && !defined(DJGPP)
825     if (size >= 0xfff0)		/* in MSDOS we can't deal with >64K blocks */
826 	p = NULL;
827     else
828 #endif
829 
830     /*
831      * Loop when out of memory: Try to release some memfile blocks and
832      * if some blocks are released call malloc again.
833      */
834     for (;;)
835     {
836 	/*
837 	 * Handle three kind of systems:
838 	 * 1. No check for available memory: Just return.
839 	 * 2. Slow check for available memory: call mch_avail_mem() after
840 	 *    allocating KEEP_ROOM amount of memory.
841 	 * 3. Strict check for available memory: call mch_avail_mem()
842 	 */
843 	if ((p = (char_u *)malloc((size_t)size)) != NULL)
844 	{
845 #ifndef HAVE_AVAIL_MEM
846 	    /* 1. No check for available memory: Just return. */
847 	    goto theend;
848 #else
849 # ifndef SMALL_MEM
850 	    /* 2. Slow check for available memory: call mch_avail_mem() after
851 	     *    allocating (KEEP_ROOM / 2) amount of memory. */
852 	    allocated += size;
853 	    if (allocated < KEEP_ROOM / 2)
854 		goto theend;
855 	    allocated = 0;
856 # endif
857 	    /* 3. check for available memory: call mch_avail_mem() */
858 	    if (mch_avail_mem(TRUE) < KEEP_ROOM && !releasing)
859 	    {
860 		vim_free((char *)p);	/* System is low... no go! */
861 		p = NULL;
862 	    }
863 	    else
864 		goto theend;
865 #endif
866 	}
867 	/*
868 	 * Remember that mf_release_all() is being called to avoid an endless
869 	 * loop, because mf_release_all() may call alloc() recursively.
870 	 */
871 	if (releasing)
872 	    break;
873 	releasing = TRUE;
874 	try_again = mf_release_all();
875 	releasing = FALSE;
876 	if (!try_again)
877 	    break;
878     }
879 
880     if (message && p == NULL)
881 	do_outofmem_msg(size);
882 
883 theend:
884 #ifdef MEM_PROFILE
885     mem_post_alloc((void **)&p, (size_t)size);
886 #endif
887     return p;
888 }
889 
890 #if defined(MEM_PROFILE) || defined(PROTO)
891 /*
892  * realloc() with memory profiling.
893  */
894     void *
895 mem_realloc(ptr, size)
896     void *ptr;
897     size_t size;
898 {
899     void *p;
900 
901     mem_pre_free(&ptr);
902     mem_pre_alloc_s(&size);
903 
904     p = realloc(ptr, size);
905 
906     mem_post_alloc(&p, size);
907 
908     return p;
909 }
910 #endif
911 
912 /*
913 * Avoid repeating the error message many times (they take 1 second each).
914 * Did_outofmem_msg is reset when a character is read.
915 */
916     void
917 do_outofmem_msg(size)
918     long_u	size;
919 {
920     if (!did_outofmem_msg)
921     {
922 	/* Don't hide this message */
923 	emsg_silent = 0;
924 	EMSGN(_("E342: Out of memory!  (allocating %lu bytes)"), size);
925 	did_outofmem_msg = TRUE;
926     }
927 }
928 
929 /*
930  * copy a string into newly allocated memory
931  */
932     char_u *
933 vim_strsave(string)
934     char_u	*string;
935 {
936     char_u	*p;
937     unsigned	len;
938 
939     len = (unsigned)STRLEN(string) + 1;
940     p = alloc(len);
941     if (p != NULL)
942 	mch_memmove(p, string, (size_t)len);
943     return p;
944 }
945 
946     char_u *
947 vim_strnsave(string, len)
948     char_u	*string;
949     int		len;
950 {
951     char_u	*p;
952 
953     p = alloc((unsigned)(len + 1));
954     if (p != NULL)
955     {
956 	STRNCPY(p, string, len);
957 	p[len] = NUL;
958     }
959     return p;
960 }
961 
962 #if 0	/* not used */
963 /*
964  * like vim_strnsave(), but remove backslashes from the string.
965  */
966     char_u *
967 vim_strnsave_esc(string, len)
968     char_u	*string;
969     int		len;
970 {
971     char_u *p1, *p2;
972 
973     p1 = alloc((unsigned) (len + 1));
974     if (p1 != NULL)
975     {
976 	STRNCPY(p1, string, len);
977 	p1[len] = NUL;
978 	for (p2 = p1; *p2; ++p2)
979 	    if (*p2 == '\\' && *(p2 + 1) != NUL)
980 		STRCPY(p2, p2 + 1);
981     }
982     return p1;
983 }
984 #endif
985 
986 /*
987  * Same as vim_strsave(), but any characters found in esc_chars are preceded
988  * by a backslash.
989  */
990     char_u *
991 vim_strsave_escaped(string, esc_chars)
992     char_u	*string;
993     char_u	*esc_chars;
994 {
995     return vim_strsave_escaped_ext(string, esc_chars, FALSE);
996 }
997 
998 /*
999  * Same as vim_strsave_escaped(), but when "bsl" is TRUE also escape
1000  * characters where rem_backslash() would remove the backslash.
1001  */
1002     char_u *
1003 vim_strsave_escaped_ext(string, esc_chars, bsl)
1004     char_u	*string;
1005     char_u	*esc_chars;
1006     int		bsl;
1007 {
1008     char_u	*p;
1009     char_u	*p2;
1010     char_u	*escaped_string;
1011     unsigned	length;
1012 #ifdef FEAT_MBYTE
1013     int		l;
1014 #endif
1015 
1016     /*
1017      * First count the number of backslashes required.
1018      * Then allocate the memory and insert them.
1019      */
1020     length = 1;				/* count the trailing NUL */
1021     for (p = string; *p; p++)
1022     {
1023 #ifdef FEAT_MBYTE
1024 	if (has_mbyte && (l = (*mb_ptr2len_check)(p)) > 1)
1025 	{
1026 	    length += l;		/* count a multibyte char */
1027 	    p += l - 1;
1028 	    continue;
1029 	}
1030 #endif
1031 	if (vim_strchr(esc_chars, *p) != NULL || (bsl && rem_backslash(p)))
1032 	    ++length;			/* count a backslash */
1033 	++length;			/* count an ordinary char */
1034     }
1035     escaped_string = alloc(length);
1036     if (escaped_string != NULL)
1037     {
1038 	p2 = escaped_string;
1039 	for (p = string; *p; p++)
1040 	{
1041 #ifdef FEAT_MBYTE
1042 	    if (has_mbyte && (l = (*mb_ptr2len_check)(p)) > 1)
1043 	    {
1044 		mch_memmove(p2, p, (size_t)l);
1045 		p2 += l;
1046 		p += l - 1;		/* skip multibyte char  */
1047 		continue;
1048 	    }
1049 #endif
1050 	    if (vim_strchr(esc_chars, *p) != NULL || (bsl && rem_backslash(p)))
1051 		*p2++ = '\\';
1052 	    *p2++ = *p;
1053 	}
1054 	*p2 = NUL;
1055     }
1056     return escaped_string;
1057 }
1058 
1059 /*
1060  * Like vim_strsave(), but make all characters uppercase.
1061  * This uses ASCII lower-to-upper case translation, language independent.
1062  */
1063     char_u *
1064 vim_strsave_up(string)
1065     char_u	*string;
1066 {
1067     char_u *p1;
1068 
1069     p1 = vim_strsave(string);
1070     vim_strup(p1);
1071     return p1;
1072 }
1073 
1074 /*
1075  * Like vim_strnsave(), but make all characters uppercase.
1076  * This uses ASCII lower-to-upper case translation, language independent.
1077  */
1078     char_u *
1079 vim_strnsave_up(string, len)
1080     char_u	*string;
1081     int		len;
1082 {
1083     char_u *p1;
1084 
1085     p1 = vim_strnsave(string, len);
1086     vim_strup(p1);
1087     return p1;
1088 }
1089 
1090 /*
1091  * ASCII lower-to-upper case translation, language independent.
1092  */
1093     void
1094 vim_strup(p)
1095     char_u	*p;
1096 {
1097     char_u  *p2;
1098     int	    c;
1099 
1100     if (p != NULL)
1101     {
1102 	p2 = p;
1103 	while ((c = *p2) != NUL)
1104 #ifdef EBCDIC
1105 	    *p2++ = isalpha(c) ? toupper(c) : c;
1106 #else
1107 	    *p2++ = (c < 'a' || c > 'z') ? c : (c - 0x20);
1108 #endif
1109     }
1110 }
1111 
1112 /*
1113  * copy a space a number of times
1114  */
1115     void
1116 copy_spaces(ptr, count)
1117     char_u	*ptr;
1118     size_t	count;
1119 {
1120     size_t	i = count;
1121     char_u	*p = ptr;
1122 
1123     while (i--)
1124 	*p++ = ' ';
1125 }
1126 
1127 #if defined(FEAT_VISUALEXTRA) || defined(PROTO)
1128 /*
1129  * Copy a character a number of times.
1130  * Does not work for multi-byte charactes!
1131  */
1132     void
1133 copy_chars(ptr, count, c)
1134     char_u	*ptr;
1135     size_t	count;
1136     int		c;
1137 {
1138     size_t	i = count;
1139     char_u	*p = ptr;
1140 
1141     while (i--)
1142 	*p++ = c;
1143 }
1144 #endif
1145 
1146 /*
1147  * delete spaces at the end of a string
1148  */
1149     void
1150 del_trailing_spaces(ptr)
1151     char_u	*ptr;
1152 {
1153     char_u	*q;
1154 
1155     q = ptr + STRLEN(ptr);
1156     while (--q > ptr && vim_iswhite(q[0]) && q[-1] != '\\' && q[-1] != Ctrl_V)
1157 	*q = NUL;
1158 }
1159 
1160 /*
1161  * This is here because strncpy() does not guarantee successful results when
1162  * the to and from strings overlap.  It is only currently called from
1163  * nextwild() which copies part of the command line to another part of the
1164  * command line.  This produced garbage when expanding files etc in the middle
1165  * of the command line (on my terminal, anyway) -- webb.
1166  * Note: strncpy() pads the remainder of the buffer with NUL bytes,
1167  * vim_strncpy() doesn't do that.
1168  */
1169     void
1170 vim_strncpy(to, from, len)
1171     char_u *to;
1172     char_u *from;
1173     int len;
1174 {
1175     int i;
1176 
1177     if (to <= from)
1178     {
1179 	while (len-- && *from)
1180 	    *to++ = *from++;
1181 	if (len >= 0)
1182 	    *to = *from;    /* Copy NUL */
1183     }
1184     else
1185     {
1186 	for (i = 0; i < len; i++)
1187 	{
1188 	    to++;
1189 	    if (*from++ == NUL)
1190 	    {
1191 		i++;
1192 		break;
1193 	    }
1194 	}
1195 	for (; i > 0; i--)
1196 	    *--to = *--from;
1197     }
1198 }
1199 
1200 /*
1201  * Isolate one part of a string option where parts are separated with
1202  * "sep_chars".
1203  * The part is copied into buf[maxlen].
1204  * "*option" is advanced to the next part.
1205  * The length is returned.
1206  */
1207     int
1208 copy_option_part(option, buf, maxlen, sep_chars)
1209     char_u	**option;
1210     char_u	*buf;
1211     int		maxlen;
1212     char	*sep_chars;
1213 {
1214     int	    len = 0;
1215     char_u  *p = *option;
1216 
1217     /* skip '.' at start of option part, for 'suffixes' */
1218     if (*p == '.')
1219 	buf[len++] = *p++;
1220     while (*p != NUL && vim_strchr((char_u *)sep_chars, *p) == NULL)
1221     {
1222 	/*
1223 	 * Skip backslash before a separator character and space.
1224 	 */
1225 	if (p[0] == '\\' && vim_strchr((char_u *)sep_chars, p[1]) != NULL)
1226 	    ++p;
1227 	if (len < maxlen - 1)
1228 	    buf[len++] = *p;
1229 	++p;
1230     }
1231     buf[len] = NUL;
1232 
1233     if (*p != NUL && *p != ',')	/* skip non-standard separator */
1234 	++p;
1235     p = skip_to_option_part(p);	/* p points to next file name */
1236 
1237     *option = p;
1238     return len;
1239 }
1240 
1241 /*
1242  * replacement for free() that ignores NULL pointers
1243  */
1244     void
1245 vim_free(x)
1246     void *x;
1247 {
1248     if (x != NULL)
1249     {
1250 #ifdef MEM_PROFILE
1251 	mem_pre_free(&x);
1252 #endif
1253 	free(x);
1254     }
1255 }
1256 
1257 #ifndef HAVE_MEMSET
1258     void *
1259 vim_memset(ptr, c, size)
1260     void    *ptr;
1261     int	    c;
1262     size_t  size;
1263 {
1264     char *p = ptr;
1265 
1266     while (size-- > 0)
1267 	*p++ = c;
1268     return ptr;
1269 }
1270 #endif
1271 
1272 #ifdef VIM_MEMCMP
1273 /*
1274  * Return zero when "b1" and "b2" are the same for "len" bytes.
1275  * Return non-zero otherwise.
1276  */
1277     int
1278 vim_memcmp(b1, b2, len)
1279     void    *b1;
1280     void    *b2;
1281     size_t  len;
1282 {
1283     char_u  *p1 = (char_u *)b1, *p2 = (char_u *)b2;
1284 
1285     for ( ; len > 0; --len)
1286     {
1287 	if (*p1 != *p2)
1288 	    return 1;
1289 	++p1;
1290 	++p2;
1291     }
1292     return 0;
1293 }
1294 #endif
1295 
1296 #ifdef VIM_MEMMOVE
1297 /*
1298  * Version of memmove() that handles overlapping source and destination.
1299  * For systems that don't have a function that is guaranteed to do that (SYSV).
1300  */
1301     void
1302 mch_memmove(dst_arg, src_arg, len)
1303     void    *src_arg, *dst_arg;
1304     size_t  len;
1305 {
1306     /*
1307      * A void doesn't have a size, we use char pointers.
1308      */
1309     char *dst = dst_arg, *src = src_arg;
1310 
1311 					/* overlap, copy backwards */
1312     if (dst > src && dst < src + len)
1313     {
1314 	src += len;
1315 	dst += len;
1316 	while (len-- > 0)
1317 	    *--dst = *--src;
1318     }
1319     else				/* copy forwards */
1320 	while (len-- > 0)
1321 	    *dst++ = *src++;
1322 }
1323 #endif
1324 
1325 #if (!defined(HAVE_STRCASECMP) && !defined(HAVE_STRICMP)) || defined(PROTO)
1326 /*
1327  * Compare two strings, ignoring case, using current locale.
1328  * Doesn't work for multi-byte characters.
1329  * return 0 for match, < 0 for smaller, > 0 for bigger
1330  */
1331     int
1332 vim_stricmp(s1, s2)
1333     char	*s1;
1334     char	*s2;
1335 {
1336     int		i;
1337 
1338     for (;;)
1339     {
1340 	i = (int)TOLOWER_LOC(*s1) - (int)TOLOWER_LOC(*s2);
1341 	if (i != 0)
1342 	    return i;			    /* this character different */
1343 	if (*s1 == NUL)
1344 	    break;			    /* strings match until NUL */
1345 	++s1;
1346 	++s2;
1347     }
1348     return 0;				    /* strings match */
1349 }
1350 #endif
1351 
1352 #if (!defined(HAVE_STRNCASECMP) && !defined(HAVE_STRNICMP)) || defined(PROTO)
1353 /*
1354  * Compare two strings, for length "len", ignoring case, using current locale.
1355  * Doesn't work for multi-byte characters.
1356  * return 0 for match, < 0 for smaller, > 0 for bigger
1357  */
1358     int
1359 vim_strnicmp(s1, s2, len)
1360     char	*s1;
1361     char	*s2;
1362     size_t	len;
1363 {
1364     int		i;
1365 
1366     while (len > 0)
1367     {
1368 	i = (int)TOLOWER_LOC(*s1) - (int)TOLOWER_LOC(*s2);
1369 	if (i != 0)
1370 	    return i;			    /* this character different */
1371 	if (*s1 == NUL)
1372 	    break;			    /* strings match until NUL */
1373 	++s1;
1374 	++s2;
1375 	--len;
1376     }
1377     return 0;				    /* strings match */
1378 }
1379 #endif
1380 
1381 #if 0	/* currently not used */
1382 /*
1383  * Check if string "s2" appears somewhere in "s1" while ignoring case.
1384  * Return NULL if not, a pointer to the first occurrence if it does.
1385  */
1386     char_u *
1387 vim_stristr(s1, s2)
1388     char_u	*s1;
1389     char_u	*s2;
1390 {
1391     char_u	*p;
1392     int		len = STRLEN(s2);
1393     char_u	*end = s1 + STRLEN(s1) - len;
1394 
1395     for (p = s1; p <= end; ++p)
1396 	if (STRNICMP(p, s2, len) == 0)
1397 	    return p;
1398     return NULL;
1399 }
1400 #endif
1401 
1402 /*
1403  * Version of strchr() and strrchr() that handle unsigned char strings
1404  * with characters above 128 correctly. Also it doesn't return a pointer to
1405  * the NUL at the end of the string.
1406  */
1407     char_u  *
1408 vim_strchr(string, c)
1409     char_u	*string;
1410     int		c;
1411 {
1412     char_u	*p;
1413     int		b;
1414 
1415     p = string;
1416 #ifdef FEAT_MBYTE
1417     if (enc_utf8 && c >= 0x80)
1418     {
1419 	while (*p != NUL)
1420 	{
1421 	    if (utf_ptr2char(p) == c)
1422 		return p;
1423 	    p += (*mb_ptr2len_check)(p);
1424 	}
1425 	return NULL;
1426     }
1427     if (enc_dbcs != 0 && c > 255)
1428     {
1429 	int	n2 = c & 0xff;
1430 
1431 	c = ((unsigned)c >> 8) & 0xff;
1432 	while ((b = *p) != NUL)
1433 	{
1434 	    if (b == c && p[1] == n2)
1435 		return p;
1436 	    p += (*mb_ptr2len_check)(p);
1437 	}
1438 	return NULL;
1439     }
1440     if (has_mbyte)
1441     {
1442 	while ((b = *p) != NUL)
1443 	{
1444 	    if (b == c)
1445 		return p;
1446 	    p += (*mb_ptr2len_check)(p);
1447 	}
1448 	return NULL;
1449     }
1450 #endif
1451     while ((b = *p) != NUL)
1452     {
1453 	if (b == c)
1454 	    return p;
1455 	++p;
1456     }
1457     return NULL;
1458 }
1459 
1460 /*
1461  * Search for last occurrence of "c" in "string".
1462  * return NULL if not found.
1463  * Does not handle multi-byte!
1464  */
1465     char_u  *
1466 vim_strrchr(string, c)
1467     char_u	*string;
1468     int		c;
1469 {
1470     char_u	*retval = NULL;
1471 
1472     while (*string)
1473     {
1474 	if (*string == c)
1475 	    retval = string;
1476 #ifdef FEAT_MBYTE
1477 	if (has_mbyte)
1478 	    string += (*mb_ptr2len_check)(string);
1479 	else
1480 #endif
1481 	    ++string;
1482     }
1483     return retval;
1484 }
1485 
1486 /*
1487  * Vim's version of strpbrk(), in case it's missing.
1488  * Don't generate a prototype for this, causes problems when it's not used.
1489  */
1490 #ifndef PROTO
1491 # ifndef HAVE_STRPBRK
1492 #  ifdef vim_strpbrk
1493 #   undef vim_strpbrk
1494 #  endif
1495     char_u *
1496 vim_strpbrk(s, charset)
1497     char_u	*s;
1498     char_u	*charset;
1499 {
1500     while (*s)
1501     {
1502 	if (vim_strchr(charset, *s) != NULL)
1503 	    return s;
1504 #ifdef FEAT_MBYTE
1505 	if (has_mbyte)
1506 	    s += (*mb_ptr2len_check)(s);
1507 	else
1508 #endif
1509 	    ++s;
1510     }
1511     return NULL;
1512 }
1513 # endif
1514 #endif
1515 
1516 /*
1517  * Vim has its own isspace() function, because on some machines isspace()
1518  * can't handle characters above 128.
1519  */
1520     int
1521 vim_isspace(x)
1522     int	    x;
1523 {
1524     return ((x >= 9 && x <= 13) || x == ' ');
1525 }
1526 
1527 /************************************************************************
1528  * Functions for hanlding growing arrays.
1529  */
1530 
1531 /*
1532  * Clear an allocated growing array.
1533  */
1534     void
1535 ga_clear(gap)
1536     garray_T *gap;
1537 {
1538     vim_free(gap->ga_data);
1539     ga_init(gap);
1540 }
1541 
1542 /*
1543  * Clear a growing array that contains a list of strings.
1544  */
1545     void
1546 ga_clear_strings(gap)
1547     garray_T *gap;
1548 {
1549     int		i;
1550 
1551     for (i = 0; i < gap->ga_len; ++i)
1552 	vim_free(((char_u **)(gap->ga_data))[i]);
1553     ga_clear(gap);
1554 }
1555 
1556 /*
1557  * Initialize a growing array.	Don't forget to set ga_itemsize and
1558  * ga_growsize!  Or use ga_init2().
1559  */
1560     void
1561 ga_init(gap)
1562     garray_T *gap;
1563 {
1564     gap->ga_data = NULL;
1565     gap->ga_room = 0;
1566     gap->ga_len = 0;
1567 }
1568 
1569     void
1570 ga_init2(gap, itemsize, growsize)
1571     garray_T	*gap;
1572     int		itemsize;
1573     int		growsize;
1574 {
1575     ga_init(gap);
1576     gap->ga_itemsize = itemsize;
1577     gap->ga_growsize = growsize;
1578 }
1579 
1580 /*
1581  * Make room in growing array "gap" for at least "n" items.
1582  * Return FAIL for failure, OK otherwise.
1583  */
1584     int
1585 ga_grow(gap, n)
1586     garray_T	*gap;
1587     int		n;
1588 {
1589     size_t	len;
1590     char_u	*pp;
1591 
1592     if (gap->ga_room < n)
1593     {
1594 	if (n < gap->ga_growsize)
1595 	    n = gap->ga_growsize;
1596 	len = gap->ga_itemsize * (gap->ga_len + n);
1597 	pp = alloc_clear((unsigned)len);
1598 	if (pp == NULL)
1599 	    return FAIL;
1600 	gap->ga_room = n;
1601 	if (gap->ga_data != NULL)
1602 	{
1603 	    mch_memmove(pp, gap->ga_data,
1604 				      (size_t)(gap->ga_itemsize * gap->ga_len));
1605 	    vim_free(gap->ga_data);
1606 	}
1607 	gap->ga_data = pp;
1608     }
1609     return OK;
1610 }
1611 
1612 /*
1613  * Concatenate a string to a growarray which contains characters.
1614  * Note: Does NOT copy the NUL at the end!
1615  */
1616     void
1617 ga_concat(gap, s)
1618     garray_T	*gap;
1619     char_u	*s;
1620 {
1621     int    len = (int)STRLEN(s);
1622 
1623     if (ga_grow(gap, len) == OK)
1624     {
1625 	mch_memmove((char *)gap->ga_data + gap->ga_len, s, (size_t)len);
1626 	gap->ga_len += len;
1627 	gap->ga_room -= len;
1628     }
1629 }
1630 
1631 /*
1632  * Append one byte to a growarray which contains bytes.
1633  */
1634     void
1635 ga_append(gap, c)
1636     garray_T	*gap;
1637     int		c;
1638 {
1639     if (ga_grow(gap, 1) == OK)
1640     {
1641 	*((char *)gap->ga_data + gap->ga_len) = c;
1642 	++gap->ga_len;
1643 	--gap->ga_room;
1644     }
1645 }
1646 
1647 /************************************************************************
1648  * functions that use lookup tables for various things, generally to do with
1649  * special key codes.
1650  */
1651 
1652 /*
1653  * Some useful tables.
1654  */
1655 
1656 static struct modmasktable
1657 {
1658     short	mod_mask;	/* Bit-mask for particular key modifier */
1659     short	mod_flag;	/* Bit(s) for particular key modifier */
1660     char_u	name;		/* Single letter name of modifier */
1661 } mod_mask_table[] =
1662 {
1663     {MOD_MASK_ALT,		MOD_MASK_ALT,		(char_u)'M'},
1664     {MOD_MASK_CTRL,		MOD_MASK_CTRL,		(char_u)'C'},
1665     {MOD_MASK_SHIFT,		MOD_MASK_SHIFT,		(char_u)'S'},
1666     {MOD_MASK_MULTI_CLICK,	MOD_MASK_2CLICK,	(char_u)'2'},
1667     {MOD_MASK_MULTI_CLICK,	MOD_MASK_3CLICK,	(char_u)'3'},
1668     {MOD_MASK_MULTI_CLICK,	MOD_MASK_4CLICK,	(char_u)'4'},
1669 #ifdef MACOS
1670     {MOD_MASK_CMD,		MOD_MASK_CMD,		(char_u)'D'},
1671 #endif
1672     /* 'A' must be the last one */
1673     {MOD_MASK_ALT,		MOD_MASK_ALT,		(char_u)'A'},
1674     {0, 0, NUL}
1675 };
1676 
1677 /*
1678  * Shifted key terminal codes and their unshifted equivalent.
1679  * Don't add mouse codes here, they are handled seperately!
1680  */
1681 #define MOD_KEYS_ENTRY_SIZE 5
1682 
1683 static char_u modifier_keys_table[] =
1684 {
1685 /*  mod mask	    with modifier		without modifier */
1686     MOD_MASK_SHIFT, '&', '9',			'@', '1',	/* begin */
1687     MOD_MASK_SHIFT, '&', '0',			'@', '2',	/* cancel */
1688     MOD_MASK_SHIFT, '*', '1',			'@', '4',	/* command */
1689     MOD_MASK_SHIFT, '*', '2',			'@', '5',	/* copy */
1690     MOD_MASK_SHIFT, '*', '3',			'@', '6',	/* create */
1691     MOD_MASK_SHIFT, '*', '4',			'k', 'D',	/* delete char */
1692     MOD_MASK_SHIFT, '*', '5',			'k', 'L',	/* delete line */
1693     MOD_MASK_SHIFT, '*', '7',			'@', '7',	/* end */
1694     MOD_MASK_CTRL,  KS_EXTRA, (int)KE_C_END,	'@', '7',	/* end */
1695     MOD_MASK_SHIFT, '*', '9',			'@', '9',	/* exit */
1696     MOD_MASK_SHIFT, '*', '0',			'@', '0',	/* find */
1697     MOD_MASK_SHIFT, '#', '1',			'%', '1',	/* help */
1698     MOD_MASK_SHIFT, '#', '2',			'k', 'h',	/* home */
1699     MOD_MASK_CTRL,  KS_EXTRA, (int)KE_C_HOME,	'k', 'h',	/* home */
1700     MOD_MASK_SHIFT, '#', '3',			'k', 'I',	/* insert */
1701     MOD_MASK_SHIFT, '#', '4',			'k', 'l',	/* left arrow */
1702     MOD_MASK_CTRL,  KS_EXTRA, (int)KE_C_LEFT,	'k', 'l',	/* left arrow */
1703     MOD_MASK_SHIFT, '%', 'a',			'%', '3',	/* message */
1704     MOD_MASK_SHIFT, '%', 'b',			'%', '4',	/* move */
1705     MOD_MASK_SHIFT, '%', 'c',			'%', '5',	/* next */
1706     MOD_MASK_SHIFT, '%', 'd',			'%', '7',	/* options */
1707     MOD_MASK_SHIFT, '%', 'e',			'%', '8',	/* previous */
1708     MOD_MASK_SHIFT, '%', 'f',			'%', '9',	/* print */
1709     MOD_MASK_SHIFT, '%', 'g',			'%', '0',	/* redo */
1710     MOD_MASK_SHIFT, '%', 'h',			'&', '3',	/* replace */
1711     MOD_MASK_SHIFT, '%', 'i',			'k', 'r',	/* right arr. */
1712     MOD_MASK_CTRL,  KS_EXTRA, (int)KE_C_RIGHT,	'k', 'r',	/* right arr. */
1713     MOD_MASK_SHIFT, '%', 'j',			'&', '5',	/* resume */
1714     MOD_MASK_SHIFT, '!', '1',			'&', '6',	/* save */
1715     MOD_MASK_SHIFT, '!', '2',			'&', '7',	/* suspend */
1716     MOD_MASK_SHIFT, '!', '3',			'&', '8',	/* undo */
1717     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_UP,	'k', 'u',	/* up arrow */
1718     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_DOWN,	'k', 'd',	/* down arrow */
1719 
1720 								/* vt100 F1 */
1721     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF1,	KS_EXTRA, (int)KE_XF1,
1722     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF2,	KS_EXTRA, (int)KE_XF2,
1723     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF3,	KS_EXTRA, (int)KE_XF3,
1724     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF4,	KS_EXTRA, (int)KE_XF4,
1725 
1726     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F1,	'k', '1',	/* F1 */
1727     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F2,	'k', '2',
1728     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F3,	'k', '3',
1729     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F4,	'k', '4',
1730     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F5,	'k', '5',
1731     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F6,	'k', '6',
1732     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F7,	'k', '7',
1733     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F8,	'k', '8',
1734     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F9,	'k', '9',
1735     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F10,	'k', ';',	/* F10 */
1736 
1737     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F11,	'F', '1',
1738     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F12,	'F', '2',
1739     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F13,	'F', '3',
1740     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F14,	'F', '4',
1741     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F15,	'F', '5',
1742     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F16,	'F', '6',
1743     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F17,	'F', '7',
1744     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F18,	'F', '8',
1745     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F19,	'F', '9',
1746     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F20,	'F', 'A',
1747 
1748     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F21,	'F', 'B',
1749     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F22,	'F', 'C',
1750     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F23,	'F', 'D',
1751     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F24,	'F', 'E',
1752     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F25,	'F', 'F',
1753     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F26,	'F', 'G',
1754     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F27,	'F', 'H',
1755     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F28,	'F', 'I',
1756     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F29,	'F', 'J',
1757     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F30,	'F', 'K',
1758 
1759     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F31,	'F', 'L',
1760     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F32,	'F', 'M',
1761     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F33,	'F', 'N',
1762     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F34,	'F', 'O',
1763     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F35,	'F', 'P',
1764     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F36,	'F', 'Q',
1765     MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F37,	'F', 'R',
1766 
1767 							    /* TAB pseudo code*/
1768     MOD_MASK_SHIFT, 'k', 'B',			KS_EXTRA, (int)KE_TAB,
1769 
1770     NUL
1771 };
1772 
1773 static struct key_name_entry
1774 {
1775     int	    key;	/* Special key code or ascii value */
1776     char_u  *name;	/* Name of key */
1777 } key_names_table[] =
1778 {
1779     {' ',		(char_u *)"Space"},
1780     {TAB,		(char_u *)"Tab"},
1781     {K_TAB,		(char_u *)"Tab"},
1782     {NL,		(char_u *)"NL"},
1783     {NL,		(char_u *)"NewLine"},	/* Alternative name */
1784     {NL,		(char_u *)"LineFeed"},	/* Alternative name */
1785     {NL,		(char_u *)"LF"},	/* Alternative name */
1786     {CAR,		(char_u *)"CR"},
1787     {CAR,		(char_u *)"Return"},	/* Alternative name */
1788     {CAR,		(char_u *)"Enter"},	/* Alternative name */
1789     {K_BS,		(char_u *)"BS"},
1790     {K_BS,		(char_u *)"BackSpace"},	/* Alternative name */
1791     {ESC,		(char_u *)"Esc"},
1792     {CSI,		(char_u *)"CSI"},
1793     {K_CSI,		(char_u *)"xCSI"},
1794     {'|',		(char_u *)"Bar"},
1795     {'\\',		(char_u *)"Bslash"},
1796     {K_DEL,		(char_u *)"Del"},
1797     {K_DEL,		(char_u *)"Delete"},	/* Alternative name */
1798     {K_KDEL,		(char_u *)"kDel"},
1799     {K_UP,		(char_u *)"Up"},
1800     {K_DOWN,		(char_u *)"Down"},
1801     {K_LEFT,		(char_u *)"Left"},
1802     {K_RIGHT,		(char_u *)"Right"},
1803 
1804     {K_F1,		(char_u *)"F1"},
1805     {K_F2,		(char_u *)"F2"},
1806     {K_F3,		(char_u *)"F3"},
1807     {K_F4,		(char_u *)"F4"},
1808     {K_F5,		(char_u *)"F5"},
1809     {K_F6,		(char_u *)"F6"},
1810     {K_F7,		(char_u *)"F7"},
1811     {K_F8,		(char_u *)"F8"},
1812     {K_F9,		(char_u *)"F9"},
1813     {K_F10,		(char_u *)"F10"},
1814 
1815     {K_F11,		(char_u *)"F11"},
1816     {K_F12,		(char_u *)"F12"},
1817     {K_F13,		(char_u *)"F13"},
1818     {K_F14,		(char_u *)"F14"},
1819     {K_F15,		(char_u *)"F15"},
1820     {K_F16,		(char_u *)"F16"},
1821     {K_F17,		(char_u *)"F17"},
1822     {K_F18,		(char_u *)"F18"},
1823     {K_F19,		(char_u *)"F19"},
1824     {K_F20,		(char_u *)"F20"},
1825 
1826     {K_F21,		(char_u *)"F21"},
1827     {K_F22,		(char_u *)"F22"},
1828     {K_F23,		(char_u *)"F23"},
1829     {K_F24,		(char_u *)"F24"},
1830     {K_F25,		(char_u *)"F25"},
1831     {K_F26,		(char_u *)"F26"},
1832     {K_F27,		(char_u *)"F27"},
1833     {K_F28,		(char_u *)"F28"},
1834     {K_F29,		(char_u *)"F29"},
1835     {K_F30,		(char_u *)"F30"},
1836 
1837     {K_F31,		(char_u *)"F31"},
1838     {K_F32,		(char_u *)"F32"},
1839     {K_F33,		(char_u *)"F33"},
1840     {K_F34,		(char_u *)"F34"},
1841     {K_F35,		(char_u *)"F35"},
1842     {K_F36,		(char_u *)"F36"},
1843     {K_F37,		(char_u *)"F37"},
1844 
1845     {K_XF1,		(char_u *)"xF1"},
1846     {K_XF2,		(char_u *)"xF2"},
1847     {K_XF3,		(char_u *)"xF3"},
1848     {K_XF4,		(char_u *)"xF4"},
1849 
1850     {K_HELP,		(char_u *)"Help"},
1851     {K_UNDO,		(char_u *)"Undo"},
1852     {K_INS,		(char_u *)"Insert"},
1853     {K_INS,		(char_u *)"Ins"},	/* Alternative name */
1854     {K_KINS,		(char_u *)"kInsert"},
1855     {K_HOME,		(char_u *)"Home"},
1856     {K_KHOME,		(char_u *)"kHome"},
1857     {K_XHOME,		(char_u *)"xHome"},
1858     {K_END,		(char_u *)"End"},
1859     {K_KEND,		(char_u *)"kEnd"},
1860     {K_XEND,		(char_u *)"xEnd"},
1861     {K_PAGEUP,		(char_u *)"PageUp"},
1862     {K_PAGEDOWN,	(char_u *)"PageDown"},
1863     {K_KPAGEUP,		(char_u *)"kPageUp"},
1864     {K_KPAGEDOWN,	(char_u *)"kPageDown"},
1865 
1866     {K_KPLUS,		(char_u *)"kPlus"},
1867     {K_KMINUS,		(char_u *)"kMinus"},
1868     {K_KDIVIDE,		(char_u *)"kDivide"},
1869     {K_KMULTIPLY,	(char_u *)"kMultiply"},
1870     {K_KENTER,		(char_u *)"kEnter"},
1871     {K_KPOINT,		(char_u *)"kPoint"},
1872 
1873     {K_K0,		(char_u *)"k0"},
1874     {K_K1,		(char_u *)"k1"},
1875     {K_K2,		(char_u *)"k2"},
1876     {K_K3,		(char_u *)"k3"},
1877     {K_K4,		(char_u *)"k4"},
1878     {K_K5,		(char_u *)"k5"},
1879     {K_K6,		(char_u *)"k6"},
1880     {K_K7,		(char_u *)"k7"},
1881     {K_K8,		(char_u *)"k8"},
1882     {K_K9,		(char_u *)"k9"},
1883 
1884     {'<',		(char_u *)"lt"},
1885 
1886     {K_MOUSE,		(char_u *)"Mouse"},
1887     {K_NETTERM_MOUSE,	(char_u *)"NetMouse"},
1888     {K_DEC_MOUSE,	(char_u *)"DecMouse"},
1889     {K_JSBTERM_MOUSE,	(char_u *)"JsbMouse"},
1890     {K_PTERM_MOUSE,	(char_u *)"PtermMouse"},
1891     {K_LEFTMOUSE,	(char_u *)"LeftMouse"},
1892     {K_LEFTMOUSE_NM,	(char_u *)"LeftMouseNM"},
1893     {K_LEFTDRAG,	(char_u *)"LeftDrag"},
1894     {K_LEFTRELEASE,	(char_u *)"LeftRelease"},
1895     {K_LEFTRELEASE_NM,	(char_u *)"LeftReleaseNM"},
1896     {K_MIDDLEMOUSE,	(char_u *)"MiddleMouse"},
1897     {K_MIDDLEDRAG,	(char_u *)"MiddleDrag"},
1898     {K_MIDDLERELEASE,	(char_u *)"MiddleRelease"},
1899     {K_RIGHTMOUSE,	(char_u *)"RightMouse"},
1900     {K_RIGHTDRAG,	(char_u *)"RightDrag"},
1901     {K_RIGHTRELEASE,	(char_u *)"RightRelease"},
1902     {K_MOUSEDOWN,	(char_u *)"MouseDown"},
1903     {K_MOUSEUP,		(char_u *)"MouseUp"},
1904     {K_X1MOUSE,		(char_u *)"X1Mouse"},
1905     {K_X1DRAG,		(char_u *)"X1Drag"},
1906     {K_X1RELEASE,		(char_u *)"X1Release"},
1907     {K_X2MOUSE,		(char_u *)"X2Mouse"},
1908     {K_X2DRAG,		(char_u *)"X2Drag"},
1909     {K_X2RELEASE,		(char_u *)"X2Release"},
1910     {K_DROP,		(char_u *)"Drop"},
1911     {K_ZERO,		(char_u *)"Nul"},
1912 #ifdef FEAT_EVAL
1913     {K_SNR,		(char_u *)"SNR"},
1914 #endif
1915     {K_PLUG,		(char_u *)"Plug"},
1916     {0,			NULL}
1917 };
1918 
1919 #define KEY_NAMES_TABLE_LEN (sizeof(key_names_table) / sizeof(struct key_name_entry))
1920 
1921 #ifdef FEAT_MOUSE
1922 static struct mousetable
1923 {
1924     int	    pseudo_code;	/* Code for pseudo mouse event */
1925     int	    button;		/* Which mouse button is it? */
1926     int	    is_click;		/* Is it a mouse button click event? */
1927     int	    is_drag;		/* Is it a mouse drag event? */
1928 } mouse_table[] =
1929 {
1930     {(int)KE_LEFTMOUSE,		MOUSE_LEFT,	TRUE,	FALSE},
1931 #ifdef FEAT_GUI
1932     {(int)KE_LEFTMOUSE_NM,	MOUSE_LEFT,	TRUE,	FALSE},
1933 #endif
1934     {(int)KE_LEFTDRAG,		MOUSE_LEFT,	FALSE,	TRUE},
1935     {(int)KE_LEFTRELEASE,	MOUSE_LEFT,	FALSE,	FALSE},
1936 #ifdef FEAT_GUI
1937     {(int)KE_LEFTRELEASE_NM,	MOUSE_LEFT,	FALSE,	FALSE},
1938 #endif
1939     {(int)KE_MIDDLEMOUSE,	MOUSE_MIDDLE,	TRUE,	FALSE},
1940     {(int)KE_MIDDLEDRAG,	MOUSE_MIDDLE,	FALSE,	TRUE},
1941     {(int)KE_MIDDLERELEASE,	MOUSE_MIDDLE,	FALSE,	FALSE},
1942     {(int)KE_RIGHTMOUSE,	MOUSE_RIGHT,	TRUE,	FALSE},
1943     {(int)KE_RIGHTDRAG,		MOUSE_RIGHT,	FALSE,	TRUE},
1944     {(int)KE_RIGHTRELEASE,	MOUSE_RIGHT,	FALSE,	FALSE},
1945     {(int)KE_X1MOUSE,		MOUSE_X1,	TRUE,	FALSE},
1946     {(int)KE_X1DRAG,		MOUSE_X1,	FALSE,	TRUE},
1947     {(int)KE_X1RELEASE,		MOUSE_X1,	FALSE,	FALSE},
1948     {(int)KE_X2MOUSE,		MOUSE_X2,	TRUE,	FALSE},
1949     {(int)KE_X2DRAG,		MOUSE_X2,	FALSE,	TRUE},
1950     {(int)KE_X2RELEASE,		MOUSE_X2,	FALSE,	FALSE},
1951     /* DRAG without CLICK */
1952     {(int)KE_IGNORE,		MOUSE_RELEASE,	FALSE,	TRUE},
1953     /* RELEASE without CLICK */
1954     {(int)KE_IGNORE,		MOUSE_RELEASE,	FALSE,	FALSE},
1955     {0,				0,		0,	0},
1956 };
1957 #endif /* FEAT_MOUSE */
1958 
1959 /*
1960  * Return the modifier mask bit (MOD_MASK_*) which corresponds to the given
1961  * modifier name ('S' for Shift, 'C' for Ctrl etc).
1962  */
1963     int
1964 name_to_mod_mask(c)
1965     int	    c;
1966 {
1967     int	    i;
1968 
1969     c = TOUPPER_ASC(c);
1970     for (i = 0; mod_mask_table[i].mod_mask != 0; i++)
1971 	if (c == mod_mask_table[i].name)
1972 	    return mod_mask_table[i].mod_flag;
1973     return 0;
1974 }
1975 
1976 #if 0 /* not used */
1977 /*
1978  * Decide whether the given key code (K_*) is a shifted special
1979  * key (by looking at mod_mask).  If it is, then return the appropriate shifted
1980  * key code, otherwise just return the character as is.
1981  */
1982     int
1983 check_shifted_spec_key(c)
1984     int	    c;
1985 {
1986     return simplify_key(c, &mod_mask);
1987 }
1988 #endif
1989 
1990 /*
1991  * Check if if there is a special key code for "key" that includes the
1992  * modifiers specified.
1993  */
1994     int
1995 simplify_key(key, modifiers)
1996     int	    key;
1997     int	    *modifiers;
1998 {
1999     int	    i;
2000     int	    key0;
2001     int	    key1;
2002 
2003     if (*modifiers & (MOD_MASK_SHIFT | MOD_MASK_CTRL | MOD_MASK_ALT))
2004     {
2005 	/* TAB is a special case */
2006 	if (key == TAB && (*modifiers & MOD_MASK_SHIFT))
2007 	{
2008 	    *modifiers &= ~MOD_MASK_SHIFT;
2009 	    return K_S_TAB;
2010 	}
2011 	key0 = KEY2TERMCAP0(key);
2012 	key1 = KEY2TERMCAP1(key);
2013 	for (i = 0; modifier_keys_table[i] != NUL; i += MOD_KEYS_ENTRY_SIZE)
2014 	    if (key0 == modifier_keys_table[i + 3]
2015 		    && key1 == modifier_keys_table[i + 4]
2016 		    && (*modifiers & modifier_keys_table[i]))
2017 	    {
2018 		*modifiers &= ~modifier_keys_table[i];
2019 		return TERMCAP2KEY(modifier_keys_table[i + 1],
2020 						   modifier_keys_table[i + 2]);
2021 	    }
2022     }
2023     return key;
2024 }
2025 
2026 /*
2027  * Return a string which contains the name of the given key when the given
2028  * modifiers are down.
2029  */
2030     char_u *
2031 get_special_key_name(c, modifiers)
2032     int	    c;
2033     int	    modifiers;
2034 {
2035     static char_u string[MAX_KEY_NAME_LEN + 1];
2036 
2037     int	    i, idx;
2038     int	    table_idx;
2039     char_u  *s;
2040 
2041     string[0] = '<';
2042     idx = 1;
2043 
2044     /* Key that stands for a normal character. */
2045     if (IS_SPECIAL(c) && KEY2TERMCAP0(c) == KS_KEY)
2046 	c = KEY2TERMCAP1(c);
2047 
2048     /*
2049      * Translate shifted special keys into unshifted keys and set modifier.
2050      * Same for CTRL and ALT modifiers.
2051      */
2052     if (IS_SPECIAL(c))
2053     {
2054 	for (i = 0; modifier_keys_table[i] != 0; i += MOD_KEYS_ENTRY_SIZE)
2055 	    if (       KEY2TERMCAP0(c) == (int)modifier_keys_table[i + 1]
2056 		    && (int)KEY2TERMCAP1(c) == (int)modifier_keys_table[i + 2])
2057 	    {
2058 		modifiers |= modifier_keys_table[i];
2059 		c = TERMCAP2KEY(modifier_keys_table[i + 3],
2060 						   modifier_keys_table[i + 4]);
2061 		break;
2062 	    }
2063     }
2064 
2065     /* try to find the key in the special key table */
2066     table_idx = find_special_key_in_table(c);
2067 
2068     /*
2069      * When not a known special key, and not a printable character, try to
2070      * extract modifiers.
2071      */
2072     if (c > 0
2073 #ifdef FEAT_MBYTE
2074 	    && (*mb_char2len)(c) == 1
2075 #endif
2076        )
2077     {
2078 	if (table_idx < 0
2079 		&& (!vim_isprintc(c) || (c & 0x7f) == ' ')
2080 		&& (c & 0x80))
2081 	{
2082 	    c &= 0x7f;
2083 	    modifiers |= MOD_MASK_ALT;
2084 	    /* try again, to find the un-alted key in the special key table */
2085 	    table_idx = find_special_key_in_table(c);
2086 	}
2087 	if (table_idx < 0 && !vim_isprintc(c) && c < ' ')
2088 	{
2089 #ifdef EBCDIC
2090 	    c = CtrlChar(c);
2091 #else
2092 	    c += '@';
2093 #endif
2094 	    modifiers |= MOD_MASK_CTRL;
2095 	}
2096     }
2097 
2098     /* translate the modifier into a string */
2099     for (i = 0; mod_mask_table[i].name != 'A'; i++)
2100 	if ((modifiers & mod_mask_table[i].mod_mask)
2101 						== mod_mask_table[i].mod_flag)
2102 	{
2103 	    string[idx++] = mod_mask_table[i].name;
2104 	    string[idx++] = (char_u)'-';
2105 	}
2106 
2107     if (table_idx < 0)		/* unknown special key, may output t_xx */
2108     {
2109 	if (IS_SPECIAL(c))
2110 	{
2111 	    string[idx++] = 't';
2112 	    string[idx++] = '_';
2113 	    string[idx++] = KEY2TERMCAP0(c);
2114 	    string[idx++] = KEY2TERMCAP1(c);
2115 	}
2116 	/* Not a special key, only modifiers, output directly */
2117 	else
2118 	{
2119 #ifdef FEAT_MBYTE
2120 	    if (has_mbyte && (*mb_char2len)(c) > 1)
2121 		idx += (*mb_char2bytes)(c, string + idx);
2122 	    else
2123 #endif
2124 	    if (vim_isprintc(c))
2125 		string[idx++] = c;
2126 	    else
2127 	    {
2128 		s = transchar(c);
2129 		while (*s)
2130 		    string[idx++] = *s++;
2131 	    }
2132 	}
2133     }
2134     else		/* use name of special key */
2135     {
2136 	STRCPY(string + idx, key_names_table[table_idx].name);
2137 	idx = (int)STRLEN(string);
2138     }
2139     string[idx++] = '>';
2140     string[idx] = NUL;
2141     return string;
2142 }
2143 
2144 /*
2145  * Try translating a <> name at (*srcp)[] to dst[].
2146  * Return the number of characters added to dst[], zero for no match.
2147  * If there is a match, srcp is advanced to after the <> name.
2148  * dst[] must be big enough to hold the result (up to six characters)!
2149  */
2150     int
2151 trans_special(srcp, dst, keycode)
2152     char_u	**srcp;
2153     char_u	*dst;
2154     int		keycode; /* prefer key code, e.g. K_DEL instead of DEL */
2155 {
2156     int		modifiers = 0;
2157     int		key;
2158     int		dlen = 0;
2159 
2160     key = find_special_key(srcp, &modifiers, keycode);
2161     if (key == 0)
2162 	return 0;
2163 
2164     /* Put the appropriate modifier in a string */
2165     if (modifiers != 0)
2166     {
2167 	dst[dlen++] = K_SPECIAL;
2168 	dst[dlen++] = KS_MODIFIER;
2169 	dst[dlen++] = modifiers;
2170     }
2171 
2172     if (IS_SPECIAL(key))
2173     {
2174 	dst[dlen++] = K_SPECIAL;
2175 	dst[dlen++] = KEY2TERMCAP0(key);
2176 	dst[dlen++] = KEY2TERMCAP1(key);
2177     }
2178 #ifdef FEAT_MBYTE
2179     else if (has_mbyte && !keycode)
2180 	dlen += (*mb_char2bytes)(key, dst + dlen);
2181 #endif
2182     else if (keycode)
2183 	dlen = (int)(add_char2buf(key, dst + dlen) - dst);
2184     else
2185 	dst[dlen++] = key;
2186 
2187     return dlen;
2188 }
2189 
2190 /*
2191  * Try translating a <> name at (*srcp)[], return the key and modifiers.
2192  * srcp is advanced to after the <> name.
2193  * returns 0 if there is no match.
2194  */
2195     int
2196 find_special_key(srcp, modp, keycode)
2197     char_u	**srcp;
2198     int		*modp;
2199     int		keycode; /* prefer key code, e.g. K_DEL instead of DEL */
2200 {
2201     char_u	*last_dash;
2202     char_u	*end_of_name;
2203     char_u	*src;
2204     char_u	*bp;
2205     int		modifiers;
2206     int		bit;
2207     int		key;
2208     long_u	n;
2209 
2210     src = *srcp;
2211     if (src[0] != '<')
2212 	return 0;
2213 
2214     /* Find end of modifier list */
2215     last_dash = src;
2216     for (bp = src + 1; *bp == '-' || vim_isIDc(*bp); bp++)
2217     {
2218 	if (*bp == '-')
2219 	{
2220 	    last_dash = bp;
2221 	    if (bp[1] != NUL && bp[2] == '>')
2222 		++bp;	/* anything accepted, like <C-?> */
2223 	}
2224 	if (bp[0] == 't' && bp[1] == '_' && bp[2] && bp[3])
2225 	    bp += 3;	/* skip t_xx, xx may be '-' or '>' */
2226     }
2227 
2228     if (*bp == '>')	/* found matching '>' */
2229     {
2230 	end_of_name = bp + 1;
2231 
2232 	if (STRNICMP(src + 1, "char-", 5) == 0 && VIM_ISDIGIT(src[6]))
2233 	{
2234 	    /* <Char-123> or <Char-033> or <Char-0x33> */
2235 	    vim_str2nr(src + 6, NULL, NULL, TRUE, TRUE, NULL, &n);
2236 	    *modp = 0;
2237 	    *srcp = end_of_name;
2238 	    return (int)n;
2239 	}
2240 
2241 	/* Which modifiers are given? */
2242 	modifiers = 0x0;
2243 	for (bp = src + 1; bp < last_dash; bp++)
2244 	{
2245 	    if (*bp != '-')
2246 	    {
2247 		bit = name_to_mod_mask(*bp);
2248 		if (bit == 0x0)
2249 		    break;	/* Illegal modifier name */
2250 		modifiers |= bit;
2251 	    }
2252 	}
2253 
2254 	/*
2255 	 * Legal modifier name.
2256 	 */
2257 	if (bp >= last_dash)
2258 	{
2259 	    /*
2260 	     * Modifier with single letter, or special key name.
2261 	     */
2262 	    if (modifiers != 0 && last_dash[2] == '>')
2263 		key = last_dash[1];
2264 	    else
2265 		key = get_special_key_code(last_dash + 1);
2266 
2267 	    /*
2268 	     * get_special_key_code() may return NUL for invalid
2269 	     * special key name.
2270 	     */
2271 	    if (key != NUL)
2272 	    {
2273 		/*
2274 		 * Only use a modifier when there is no special key code that
2275 		 * includes the modifier.
2276 		 */
2277 		key = simplify_key(key, &modifiers);
2278 
2279 		if (!keycode)
2280 		{
2281 		    /* don't want keycode, use single byte code */
2282 		    if (key == K_BS)
2283 			key = BS;
2284 		    else if (key == K_DEL || key == K_KDEL)
2285 			key = DEL;
2286 		}
2287 
2288 		/*
2289 		 * Normal Key with modifier: Try to make a single byte code.
2290 		 */
2291 		if (!IS_SPECIAL(key))
2292 		    key = extract_modifiers(key, &modifiers);
2293 
2294 		*modp = modifiers;
2295 		*srcp = end_of_name;
2296 		return key;
2297 	    }
2298 	}
2299     }
2300     return 0;
2301 }
2302 
2303 /*
2304  * Try to include modifiers in the key.
2305  * Changes "Shift-a" to 'A', "Alt-A" to 0xc0, etc.
2306  */
2307     int
2308 extract_modifiers(key, modp)
2309     int	    key;
2310     int	    *modp;
2311 {
2312     int	modifiers = *modp;
2313 
2314 #ifdef MACOS
2315     /* Command-key really special, No fancynest */
2316     if (!(modifiers & MOD_MASK_CMD))
2317 #endif
2318     if ((modifiers & MOD_MASK_SHIFT) && ASCII_ISALPHA(key))
2319     {
2320 	key = TOUPPER_ASC(key);
2321 	modifiers &= ~MOD_MASK_SHIFT;
2322     }
2323     if ((modifiers & MOD_MASK_CTRL)
2324 #ifdef EBCDIC
2325 	    /* * TODO: EBCDIC Better use:
2326 	     * && (Ctrl_chr(key) || key == '?')
2327 	     * ???  */
2328 	    && strchr("?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_", key)
2329 						       != NULL
2330 #else
2331 	    && ((key >= '?' && key <= '_') || ASCII_ISALPHA(key))
2332 #endif
2333 	    )
2334     {
2335 	key = Ctrl_chr(key);
2336 	modifiers &= ~MOD_MASK_CTRL;
2337 	/* <C-@> is <Nul> */
2338 	if (key == 0)
2339 	    key = K_ZERO;
2340     }
2341 #ifdef MACOS
2342     /* Command-key really special, No fancynest */
2343     if (!(modifiers & MOD_MASK_CMD))
2344 #endif
2345     if ((modifiers & MOD_MASK_ALT) && key < 0x80
2346 #ifdef FEAT_MBYTE
2347 	    && !enc_dbcs		/* avoid creating a lead byte */
2348 #endif
2349 	    )
2350     {
2351 	key |= 0x80;
2352 	modifiers &= ~MOD_MASK_ALT;	/* remove the META modifier */
2353     }
2354 
2355     *modp = modifiers;
2356     return key;
2357 }
2358 
2359 /*
2360  * Try to find key "c" in the special key table.
2361  * Return the index when found, -1 when not found.
2362  */
2363     int
2364 find_special_key_in_table(c)
2365     int	    c;
2366 {
2367     int	    i;
2368 
2369     for (i = 0; key_names_table[i].name != NULL; i++)
2370 	if (c == key_names_table[i].key)
2371 	    break;
2372     if (key_names_table[i].name == NULL)
2373 	i = -1;
2374     return i;
2375 }
2376 
2377 /*
2378  * Find the special key with the given name (the given string does not have to
2379  * end with NUL, the name is assumed to end before the first non-idchar).
2380  * If the name starts with "t_" the next two characters are interpreted as a
2381  * termcap name.
2382  * Return the key code, or 0 if not found.
2383  */
2384     int
2385 get_special_key_code(name)
2386     char_u  *name;
2387 {
2388     char_u  *table_name;
2389     char_u  string[3];
2390     int	    i, j;
2391 
2392     /*
2393      * If it's <t_xx> we get the code for xx from the termcap
2394      */
2395     if (name[0] == 't' && name[1] == '_' && name[2] != NUL && name[3] != NUL)
2396     {
2397 	string[0] = name[2];
2398 	string[1] = name[3];
2399 	string[2] = NUL;
2400 	if (add_termcap_entry(string, FALSE) == OK)
2401 	    return TERMCAP2KEY(name[2], name[3]);
2402     }
2403     else
2404 	for (i = 0; key_names_table[i].name != NULL; i++)
2405 	{
2406 	    table_name = key_names_table[i].name;
2407 	    for (j = 0; vim_isIDc(name[j]) && table_name[j] != NUL; j++)
2408 		if (TOLOWER_ASC(table_name[j]) != TOLOWER_ASC(name[j]))
2409 		    break;
2410 	    if (!vim_isIDc(name[j]) && table_name[j] == NUL)
2411 		return key_names_table[i].key;
2412 	}
2413     return 0;
2414 }
2415 
2416 #ifdef FEAT_CMDL_COMPL
2417     char_u *
2418 get_key_name(i)
2419     int	    i;
2420 {
2421     if (i >= KEY_NAMES_TABLE_LEN)
2422 	return NULL;
2423     return  key_names_table[i].name;
2424 }
2425 #endif
2426 
2427 #ifdef FEAT_MOUSE
2428 /*
2429  * Look up the given mouse code to return the relevant information in the other
2430  * arguments.  Return which button is down or was released.
2431  */
2432     int
2433 get_mouse_button(code, is_click, is_drag)
2434     int	    code;
2435     int	    *is_click;
2436     int	    *is_drag;
2437 {
2438     int	    i;
2439 
2440     for (i = 0; mouse_table[i].pseudo_code; i++)
2441 	if (code == mouse_table[i].pseudo_code)
2442 	{
2443 	    *is_click = mouse_table[i].is_click;
2444 	    *is_drag = mouse_table[i].is_drag;
2445 	    return mouse_table[i].button;
2446 	}
2447     return 0;	    /* Shouldn't get here */
2448 }
2449 
2450 /*
2451  * Return the appropriate pseudo mouse event token (KE_LEFTMOUSE etc) based on
2452  * the given information about which mouse button is down, and whether the
2453  * mouse was clicked, dragged or released.
2454  */
2455     int
2456 get_pseudo_mouse_code(button, is_click, is_drag)
2457     int	    button;	/* eg MOUSE_LEFT */
2458     int	    is_click;
2459     int	    is_drag;
2460 {
2461     int	    i;
2462 
2463     for (i = 0; mouse_table[i].pseudo_code; i++)
2464 	if (button == mouse_table[i].button
2465 	    && is_click == mouse_table[i].is_click
2466 	    && is_drag == mouse_table[i].is_drag)
2467 	{
2468 #ifdef FEAT_GUI
2469 	    /* Trick: a non mappable left click and release has mouse_col < 0.
2470 	     * Used for 'mousefocus' in gui_mouse_moved() */
2471 	    if (mouse_col < 0)
2472 	    {
2473 		mouse_col = 0;
2474 		if (mouse_table[i].pseudo_code == (int)KE_LEFTMOUSE)
2475 		    return (int)KE_LEFTMOUSE_NM;
2476 		if (mouse_table[i].pseudo_code == (int)KE_LEFTRELEASE)
2477 		    return (int)KE_LEFTRELEASE_NM;
2478 	    }
2479 #endif
2480 	    return mouse_table[i].pseudo_code;
2481 	}
2482     return (int)KE_IGNORE;	    /* not recongnized, ignore it */
2483 }
2484 #endif /* FEAT_MOUSE */
2485 
2486 /*
2487  * Return the current end-of-line type: EOL_DOS, EOL_UNIX or EOL_MAC.
2488  */
2489     int
2490 get_fileformat(buf)
2491     buf_T	*buf;
2492 {
2493     int		c = *buf->b_p_ff;
2494 
2495     if (buf->b_p_bin || c == 'u')
2496 	return EOL_UNIX;
2497     if (c == 'm')
2498 	return EOL_MAC;
2499     return EOL_DOS;
2500 }
2501 
2502 /*
2503  * Like get_fileformat(), but override 'fileformat' with "p" for "++opt=val"
2504  * argument.
2505  */
2506     int
2507 get_fileformat_force(buf, eap)
2508     buf_T	*buf;
2509     exarg_T	*eap;	    /* can be NULL! */
2510 {
2511     int		c;
2512 
2513     if (eap != NULL && eap->force_ff != 0)
2514 	c = eap->cmd[eap->force_ff];
2515     else
2516     {
2517 	if ((eap != NULL && eap->force_bin != 0)
2518 			       ? (eap->force_bin == FORCE_BIN) : buf->b_p_bin)
2519 	    return EOL_UNIX;
2520 	c = *buf->b_p_ff;
2521     }
2522     if (c == 'u')
2523 	return EOL_UNIX;
2524     if (c == 'm')
2525 	return EOL_MAC;
2526     return EOL_DOS;
2527 }
2528 
2529 /*
2530  * Set the current end-of-line type to EOL_DOS, EOL_UNIX or EOL_MAC.
2531  * Sets both 'textmode' and 'fileformat'.
2532  * Note: Does _not_ set global value of 'textmode'!
2533  */
2534     void
2535 set_fileformat(t, opt_flags)
2536     int		t;
2537     int		opt_flags;	/* OPT_LOCAL and/or OPT_GLOBAL */
2538 {
2539     char	*p = NULL;
2540 
2541     switch (t)
2542     {
2543     case EOL_DOS:
2544 	p = FF_DOS;
2545 	curbuf->b_p_tx = TRUE;
2546 	break;
2547     case EOL_UNIX:
2548 	p = FF_UNIX;
2549 	curbuf->b_p_tx = FALSE;
2550 	break;
2551     case EOL_MAC:
2552 	p = FF_MAC;
2553 	curbuf->b_p_tx = FALSE;
2554 	break;
2555     }
2556     if (p != NULL)
2557 	set_string_option_direct((char_u *)"ff", -1, (char_u *)p,
2558 							OPT_FREE | opt_flags);
2559 #ifdef FEAT_WINDOWS
2560     check_status(curbuf);
2561 #endif
2562 #ifdef FEAT_TITLE
2563     need_maketitle = TRUE;	    /* set window title later */
2564 #endif
2565 }
2566 
2567 /*
2568  * Return the default fileformat from 'fileformats'.
2569  */
2570     int
2571 default_fileformat()
2572 {
2573     switch (*p_ffs)
2574     {
2575 	case 'm':   return EOL_MAC;
2576 	case 'd':   return EOL_DOS;
2577     }
2578     return EOL_UNIX;
2579 }
2580 
2581 /*
2582  * Call shell.	Calls mch_call_shell, with 'shellxquote' added.
2583  */
2584     int
2585 call_shell(cmd, opt)
2586     char_u	*cmd;
2587     int		opt;
2588 {
2589     char_u	*ncmd;
2590     int		retval;
2591 
2592     if (p_verbose > 3)
2593     {
2594 	msg_str((char_u *)_("Calling shell to execute: \"%s\""),
2595 						    cmd == NULL ? p_sh : cmd);
2596 	out_char('\n');
2597 	cursor_on();
2598     }
2599 
2600     if (*p_sh == NUL)
2601     {
2602 	EMSG(_(e_shellempty));
2603 	retval = -1;
2604     }
2605     else
2606     {
2607 #ifdef FEAT_GUI_MSWIN
2608 	/* Don't hide the pointer while executing a shell command. */
2609 	gui_mch_mousehide(FALSE);
2610 #endif
2611 #ifdef FEAT_GUI
2612 	++hold_gui_events;
2613 #endif
2614 	/* The external command may update a tags file, clear cached tags. */
2615 	tag_freematch();
2616 
2617 	if (cmd == NULL || *p_sxq == NUL)
2618 	    retval = mch_call_shell(cmd, opt);
2619 	else
2620 	{
2621 	    ncmd = alloc((unsigned)(STRLEN(cmd) + STRLEN(p_sxq) * 2 + 1));
2622 	    if (ncmd != NULL)
2623 	    {
2624 		STRCPY(ncmd, p_sxq);
2625 		STRCAT(ncmd, cmd);
2626 		STRCAT(ncmd, p_sxq);
2627 		retval = mch_call_shell(ncmd, opt);
2628 		vim_free(ncmd);
2629 	    }
2630 	    else
2631 		retval = -1;
2632 	}
2633 #ifdef FEAT_GUI
2634 	--hold_gui_events;
2635 #endif
2636 	/*
2637 	 * Check the window size, in case it changed while executing the
2638 	 * external command.
2639 	 */
2640 	shell_resized_check();
2641     }
2642 
2643 #ifdef FEAT_EVAL
2644     set_vim_var_nr(VV_SHELL_ERROR, (long)retval);
2645 #endif
2646 
2647     return retval;
2648 }
2649 
2650 /*
2651  * VISUAL and OP_PENDING State are never set, they are equal to NORMAL State
2652  * with a condition.  This function returns the real State.
2653  */
2654     int
2655 get_real_state()
2656 {
2657     if (State & NORMAL)
2658     {
2659 #ifdef FEAT_VISUAL
2660 	if (VIsual_active)
2661 	    return VISUAL;
2662 	else
2663 #endif
2664 	    if (finish_op)
2665 	    return OP_PENDING;
2666     }
2667     return State;
2668 }
2669 
2670 #if defined(FEAT_SESSION) || defined(MSWIN) || defined(FEAT_GUI_MAC) \
2671 	|| ((defined(FEAT_GUI_GTK) || defined(FEAT_GUI_KDE)) \
2672 			&& ( defined(FEAT_WINDOWS) || defined(FEAT_DND)) ) \
2673 	|| defined(FEAT_SUN_WORKSHOP) || defined(FEAT_NETBEANS_INTG) \
2674 	|| defined(PROTO)
2675 /*
2676  * Change to a file's directory.
2677  * Caller must call shorten_fnames()!
2678  * Return OK or FAIL.
2679  */
2680     int
2681 vim_chdirfile(fname)
2682     char_u	*fname;
2683 {
2684     char_u	temp_string[MAXPATHL];
2685     char_u	*p;
2686     char_u	*t;
2687 
2688     STRCPY(temp_string, fname);
2689     p = get_past_head(temp_string);
2690     t = gettail(temp_string);
2691     while (t > p && vim_ispathsep(t[-1]))
2692 	--t;
2693     *t = NUL; /* chop off end of string */
2694 
2695     return mch_chdir((char *)temp_string) == 0 ? OK : FAIL;
2696 }
2697 #endif
2698 
2699 #if defined(STAT_IGNORES_SLASH) || defined(PROTO)
2700 /*
2701  * Check if "name" ends in a slash and is not a directory.
2702  * Used for systems where stat() ignores a trailing slash on a file name.
2703  * The Vim code assumes a trailing slash is only ignored for a directory.
2704  */
2705     int
2706 illegal_slash(name)
2707     char *name;
2708 {
2709     if (name[0] == NUL)
2710 	return FALSE;	    /* no file name is not illegal */
2711     if (name[strlen(name) - 1] != '/')
2712 	return FALSE;	    /* no trailing slash */
2713     if (mch_isdir((char_u *)name))
2714 	return FALSE;	    /* trailing slash for a directory */
2715     return TRUE;
2716 }
2717 #endif
2718 
2719 #if defined(CURSOR_SHAPE) || defined(PROTO)
2720 
2721 /*
2722  * Handling of cursor and mouse pointer shapes in various modes.
2723  */
2724 
2725 cursorentry_T shape_table[SHAPE_IDX_COUNT] =
2726 {
2727     /* The values will be filled in from the 'guicursor' and 'mouseshape'
2728      * defaults when Vim starts.
2729      * Adjust the SHAPE_IDX_ defines when making changes! */
2730     {0,	0, 0, 700L, 400L, 250L, 0, 0, "n", SHAPE_CURSOR+SHAPE_MOUSE},
2731     {0,	0, 0, 700L, 400L, 250L, 0, 0, "v", SHAPE_CURSOR+SHAPE_MOUSE},
2732     {0,	0, 0, 700L, 400L, 250L, 0, 0, "i", SHAPE_CURSOR+SHAPE_MOUSE},
2733     {0,	0, 0, 700L, 400L, 250L, 0, 0, "r", SHAPE_CURSOR+SHAPE_MOUSE},
2734     {0,	0, 0, 700L, 400L, 250L, 0, 0, "c", SHAPE_CURSOR+SHAPE_MOUSE},
2735     {0,	0, 0, 700L, 400L, 250L, 0, 0, "ci", SHAPE_CURSOR+SHAPE_MOUSE},
2736     {0,	0, 0, 700L, 400L, 250L, 0, 0, "cr", SHAPE_CURSOR+SHAPE_MOUSE},
2737     {0,	0, 0, 700L, 400L, 250L, 0, 0, "o", SHAPE_CURSOR+SHAPE_MOUSE},
2738     {0,	0, 0, 700L, 400L, 250L, 0, 0, "ve", SHAPE_CURSOR+SHAPE_MOUSE},
2739     {0,	0, 0,   0L,   0L,   0L, 0, 0, "e", SHAPE_MOUSE},
2740     {0,	0, 0,   0L,   0L,   0L, 0, 0, "s", SHAPE_MOUSE},
2741     {0,	0, 0,   0L,   0L,   0L, 0, 0, "sd", SHAPE_MOUSE},
2742     {0,	0, 0,   0L,   0L,   0L, 0, 0, "vs", SHAPE_MOUSE},
2743     {0,	0, 0,   0L,   0L,   0L, 0, 0, "vd", SHAPE_MOUSE},
2744     {0,	0, 0,   0L,   0L,   0L, 0, 0, "m", SHAPE_MOUSE},
2745     {0,	0, 0,   0L,   0L,   0L, 0, 0, "ml", SHAPE_MOUSE},
2746     {0,	0, 0, 100L, 100L, 100L, 0, 0, "sm", SHAPE_CURSOR},
2747 };
2748 
2749 #ifdef FEAT_MOUSESHAPE
2750 /*
2751  * Table with names for mouse shapes.  Keep in sync with all the tables for
2752  * mch_set_mouse_shape()!.
2753  */
2754 static char * mshape_names[] =
2755 {
2756     "arrow",	/* default, must be the first one */
2757     "blank",	/* hidden */
2758     "beam",
2759     "updown",
2760     "udsizing",
2761     "leftright",
2762     "lrsizing",
2763     "busy",
2764     "no",
2765     "crosshair",
2766     "hand1",
2767     "hand2",
2768     "pencil",
2769     "question",
2770     "rightup-arrow",
2771     "up-arrow",
2772     NULL
2773 };
2774 #endif
2775 
2776 /*
2777  * Parse the 'guicursor' option ("what" is SHAPE_CURSOR) or 'mouseshape'
2778  * ("what" is SHAPE_MOUSE).
2779  * Returns error message for an illegal option, NULL otherwise.
2780  */
2781     char_u *
2782 parse_shape_opt(what)
2783     int		what;
2784 {
2785     char_u	*modep;
2786     char_u	*colonp;
2787     char_u	*commap;
2788     char_u	*slashp;
2789     char_u	*p, *endp;
2790     int		idx = 0;		/* init for GCC */
2791     int		all_idx;
2792     int		len;
2793     int		i;
2794     long	n;
2795     int		found_ve = FALSE;	/* found "ve" flag */
2796     int		round;
2797 
2798     /*
2799      * First round: check for errors; second round: do it for real.
2800      */
2801     for (round = 1; round <= 2; ++round)
2802     {
2803 	/*
2804 	 * Repeat for all comma separated parts.
2805 	 */
2806 #ifdef FEAT_MOUSESHAPE
2807 	if (what == SHAPE_MOUSE)
2808 	    modep = p_mouseshape;
2809 	else
2810 #endif
2811 	    modep = p_guicursor;
2812 	while (*modep != NUL)
2813 	{
2814 	    colonp = vim_strchr(modep, ':');
2815 	    if (colonp == NULL)
2816 		return (char_u *)N_("E545: Missing colon");
2817 	    if (colonp == modep)
2818 		return (char_u *)N_("E546: Illegal mode");
2819 	    commap = vim_strchr(modep, ',');
2820 
2821 	    /*
2822 	     * Repeat for all mode's before the colon.
2823 	     * For the 'a' mode, we loop to handle all the modes.
2824 	     */
2825 	    all_idx = -1;
2826 	    while (modep < colonp || all_idx >= 0)
2827 	    {
2828 		if (all_idx < 0)
2829 		{
2830 		    /* Find the mode. */
2831 		    if (modep[1] == '-' || modep[1] == ':')
2832 			len = 1;
2833 		    else
2834 			len = 2;
2835 		    if (len == 1 && TOLOWER_ASC(modep[0]) == 'a')
2836 			all_idx = SHAPE_IDX_COUNT - 1;
2837 		    else
2838 		    {
2839 			for (idx = 0; idx < SHAPE_IDX_COUNT; ++idx)
2840 			    if (STRNICMP(modep, shape_table[idx].name, len)
2841 									 == 0)
2842 				break;
2843 			if (idx == SHAPE_IDX_COUNT
2844 				   || (shape_table[idx].used_for & what) == 0)
2845 			    return (char_u *)N_("E546: Illegal mode");
2846 			if (len == 2 && modep[0] == 'v' && modep[1] == 'e')
2847 			    found_ve = TRUE;
2848 		    }
2849 		    modep += len + 1;
2850 		}
2851 
2852 		if (all_idx >= 0)
2853 		    idx = all_idx--;
2854 		else if (round == 2)
2855 		{
2856 #ifdef FEAT_MOUSESHAPE
2857 		    if (what == SHAPE_MOUSE)
2858 		    {
2859 			/* Set the default, for the missing parts */
2860 			shape_table[idx].mshape = 0;
2861 		    }
2862 		    else
2863 #endif
2864 		    {
2865 			/* Set the defaults, for the missing parts */
2866 			shape_table[idx].shape = SHAPE_BLOCK;
2867 			shape_table[idx].blinkwait = 700L;
2868 			shape_table[idx].blinkon = 400L;
2869 			shape_table[idx].blinkoff = 250L;
2870 		    }
2871 		}
2872 
2873 		/* Parse the part after the colon */
2874 		for (p = colonp + 1; *p && *p != ','; )
2875 		{
2876 #ifdef FEAT_MOUSESHAPE
2877 		    if (what == SHAPE_MOUSE)
2878 		    {
2879 			for (i = 0; ; ++i)
2880 			{
2881 			    if (mshape_names[i] == NULL)
2882 			    {
2883 				if (!VIM_ISDIGIT(*p))
2884 				    return (char_u *)N_("E547: Illegal mouseshape");
2885 				if (round == 2)
2886 				    shape_table[idx].mshape =
2887 					      getdigits(&p) + MSHAPE_NUMBERED;
2888 				else
2889 				    (void)getdigits(&p);
2890 				break;
2891 			    }
2892 			    len = (int)STRLEN(mshape_names[i]);
2893 			    if (STRNICMP(p, mshape_names[i], len) == 0)
2894 			    {
2895 				if (round == 2)
2896 				    shape_table[idx].mshape = i;
2897 				p += len;
2898 				break;
2899 			    }
2900 			}
2901 		    }
2902 		    else /* if (what == SHAPE_MOUSE) */
2903 #endif
2904 		    {
2905 			/*
2906 			 * First handle the ones with a number argument.
2907 			 */
2908 			i = *p;
2909 			len = 0;
2910 			if (STRNICMP(p, "ver", 3) == 0)
2911 			    len = 3;
2912 			else if (STRNICMP(p, "hor", 3) == 0)
2913 			    len = 3;
2914 			else if (STRNICMP(p, "blinkwait", 9) == 0)
2915 			    len = 9;
2916 			else if (STRNICMP(p, "blinkon", 7) == 0)
2917 			    len = 7;
2918 			else if (STRNICMP(p, "blinkoff", 8) == 0)
2919 			    len = 8;
2920 			if (len != 0)
2921 			{
2922 			    p += len;
2923 			    if (!VIM_ISDIGIT(*p))
2924 				return (char_u *)N_("E548: digit expected");
2925 			    n = getdigits(&p);
2926 			    if (len == 3)   /* "ver" or "hor" */
2927 			    {
2928 				if (n == 0)
2929 				    return (char_u *)N_("E549: Illegal percentage");
2930 				if (round == 2)
2931 				{
2932 				    if (TOLOWER_ASC(i) == 'v')
2933 					shape_table[idx].shape = SHAPE_VER;
2934 				    else
2935 					shape_table[idx].shape = SHAPE_HOR;
2936 				    shape_table[idx].percentage = n;
2937 				}
2938 			    }
2939 			    else if (round == 2)
2940 			    {
2941 				if (len == 9)
2942 				    shape_table[idx].blinkwait = n;
2943 				else if (len == 7)
2944 				    shape_table[idx].blinkon = n;
2945 				else
2946 				    shape_table[idx].blinkoff = n;
2947 			    }
2948 			}
2949 			else if (STRNICMP(p, "block", 5) == 0)
2950 			{
2951 			    if (round == 2)
2952 				shape_table[idx].shape = SHAPE_BLOCK;
2953 			    p += 5;
2954 			}
2955 			else	/* must be a highlight group name then */
2956 			{
2957 			    endp = vim_strchr(p, '-');
2958 			    if (commap == NULL)		    /* last part */
2959 			    {
2960 				if (endp == NULL)
2961 				    endp = p + STRLEN(p);   /* find end of part */
2962 			    }
2963 			    else if (endp > commap || endp == NULL)
2964 				endp = commap;
2965 			    slashp = vim_strchr(p, '/');
2966 			    if (slashp != NULL && slashp < endp)
2967 			    {
2968 				/* "group/langmap_group" */
2969 				i = syn_check_group(p, (int)(slashp - p));
2970 				p = slashp + 1;
2971 			    }
2972 			    if (round == 2)
2973 			    {
2974 				shape_table[idx].id = syn_check_group(p,
2975 							     (int)(endp - p));
2976 				shape_table[idx].id_lm = shape_table[idx].id;
2977 				if (slashp != NULL && slashp < endp)
2978 				    shape_table[idx].id = i;
2979 			    }
2980 			    p = endp;
2981 			}
2982 		    } /* if (what != SHAPE_MOUSE) */
2983 
2984 		    if (*p == '-')
2985 			++p;
2986 		}
2987 	    }
2988 	    modep = p;
2989 	    if (*modep == ',')
2990 		++modep;
2991 	}
2992     }
2993 
2994     /* If the 's' flag is not given, use the 'v' cursor for 's' */
2995     if (!found_ve)
2996     {
2997 #ifdef FEAT_MOUSESHAPE
2998 	if (what == SHAPE_MOUSE)
2999 	{
3000 	    shape_table[SHAPE_IDX_VE].mshape = shape_table[SHAPE_IDX_V].mshape;
3001 	}
3002 	else
3003 #endif
3004 	{
3005 	    shape_table[SHAPE_IDX_VE].shape = shape_table[SHAPE_IDX_V].shape;
3006 	    shape_table[SHAPE_IDX_VE].percentage =
3007 					 shape_table[SHAPE_IDX_V].percentage;
3008 	    shape_table[SHAPE_IDX_VE].blinkwait =
3009 					  shape_table[SHAPE_IDX_V].blinkwait;
3010 	    shape_table[SHAPE_IDX_VE].blinkon =
3011 					    shape_table[SHAPE_IDX_V].blinkon;
3012 	    shape_table[SHAPE_IDX_VE].blinkoff =
3013 					   shape_table[SHAPE_IDX_V].blinkoff;
3014 	    shape_table[SHAPE_IDX_VE].id = shape_table[SHAPE_IDX_V].id;
3015 	    shape_table[SHAPE_IDX_VE].id_lm = shape_table[SHAPE_IDX_V].id_lm;
3016 	}
3017     }
3018 
3019     return NULL;
3020 }
3021 
3022 /*
3023  * Return the index into shape_table[] for the current mode.
3024  * When "mouse" is TRUE, consider indexes valid for the mouse pointer.
3025  */
3026     int
3027 get_shape_idx(mouse)
3028     int	mouse;
3029 {
3030 #ifdef FEAT_MOUSESHAPE
3031     if (mouse && (State == HITRETURN || State == ASKMORE))
3032     {
3033 # ifdef FEAT_GUI
3034 	if (Y_2_ROW(gui_mch_get_mouse_y()) == Rows - 1)
3035 	    return SHAPE_IDX_MOREL;
3036 # endif
3037 	return SHAPE_IDX_MORE;
3038     }
3039     if (mouse && drag_status_line)
3040 	return SHAPE_IDX_SDRAG;
3041 # ifdef FEAT_VERTSPLIT
3042     if (mouse && drag_sep_line)
3043 	return SHAPE_IDX_VDRAG;
3044 # endif
3045 #endif
3046     if (!mouse && State == SHOWMATCH)
3047 	return SHAPE_IDX_SM;
3048 #ifdef FEAT_VREPLACE
3049     if (State & VREPLACE_FLAG)
3050 	return SHAPE_IDX_R;
3051 #endif
3052     if (State & REPLACE_FLAG)
3053 	return SHAPE_IDX_R;
3054     if (State & INSERT)
3055 	return SHAPE_IDX_I;
3056     if (State & CMDLINE)
3057     {
3058 	if (cmdline_at_end())
3059 	    return SHAPE_IDX_C;
3060 	if (cmdline_overstrike())
3061 	    return SHAPE_IDX_CR;
3062 	return SHAPE_IDX_CI;
3063     }
3064     if (finish_op)
3065 	return SHAPE_IDX_O;
3066 #ifdef FEAT_VISUAL
3067     if (VIsual_active)
3068     {
3069 	if (*p_sel == 'e')
3070 	    return SHAPE_IDX_VE;
3071 	else
3072 	    return SHAPE_IDX_V;
3073     }
3074 #endif
3075     return SHAPE_IDX_N;
3076 }
3077 
3078 # if defined(FEAT_MOUSESHAPE) || defined(PROTO)
3079 static int old_mouse_shape = 0;
3080 
3081 /*
3082  * Set the mouse shape:
3083  * If "shape" is -1, use shape depending on the current mode,
3084  * depending on the current state.
3085  * If "shape" is -2, only update the shape when it's CLINE or STATUS (used
3086  * when the mouse moves off the status or command line).
3087  */
3088     void
3089 update_mouseshape(shape_idx)
3090     int	shape_idx;
3091 {
3092     int new_mouse_shape;
3093 
3094     /* Only works in GUI mode. */
3095     if (!gui.in_use)
3096 	return;
3097 
3098     /* Postpone the updating when more is to come.  Speeds up executing of
3099      * mappings. */
3100     if (shape_idx == -1 && char_avail())
3101     {
3102 	postponed_mouseshape = TRUE;
3103 	return;
3104     }
3105 
3106     if (shape_idx == -2
3107 	    && old_mouse_shape != shape_table[SHAPE_IDX_CLINE].mshape
3108 	    && old_mouse_shape != shape_table[SHAPE_IDX_STATUS].mshape
3109 	    && old_mouse_shape != shape_table[SHAPE_IDX_VSEP].mshape)
3110 	return;
3111     if (shape_idx < 0)
3112 	new_mouse_shape = shape_table[get_shape_idx(TRUE)].mshape;
3113     else
3114 	new_mouse_shape = shape_table[shape_idx].mshape;
3115     if (new_mouse_shape != old_mouse_shape)
3116     {
3117 	mch_set_mouse_shape(new_mouse_shape);
3118 	old_mouse_shape = new_mouse_shape;
3119     }
3120     postponed_mouseshape = FALSE;
3121 }
3122 # endif
3123 
3124 #endif /* CURSOR_SHAPE */
3125 
3126 
3127 #ifdef FEAT_CRYPT
3128 /*
3129  * Optional encryption suypport.
3130  * Mohsin Ahmed, [email protected], 98-09-24
3131  * Based on zip/crypt sources.
3132  *
3133  * NOTE FOR USA: Since 2000 exporting this code from the USA is allowed to
3134  * most countries.  There are a few exceptions, but that still should not be a
3135  * problem since this code was originally created in Europe and India.
3136  */
3137 
3138 /* from zip.h */
3139 
3140 typedef unsigned short ush;	/* unsigned 16-bit value */
3141 typedef unsigned long  ulg;	/* unsigned 32-bit value */
3142 
3143 static void make_crc_tab __ARGS((void));
3144 
3145 ulg crc_32_tab[256];
3146 
3147 /*
3148  * Fill the CRC table.
3149  */
3150     static void
3151 make_crc_tab()
3152 {
3153     ulg		s,t,v;
3154     static int	done = FALSE;
3155 
3156     if (done)
3157 	return;
3158     for (t = 0; t < 256; t++)
3159     {
3160 	v = t;
3161 	for (s = 0; s < 8; s++)
3162 	    v = (v >> 1) ^ ((v & 1) * (ulg)0xedb88320L);
3163 	crc_32_tab[t] = v;
3164     }
3165     done = TRUE;
3166 }
3167 
3168 #define CRC32(c, b) (crc_32_tab[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8))
3169 
3170 
3171 static ulg keys[3]; /* keys defining the pseudo-random sequence */
3172 
3173 /*
3174  * Return the next byte in the pseudo-random sequence
3175  */
3176     int
3177 decrypt_byte()
3178 {
3179     ush temp;
3180 
3181     temp = (ush)keys[2] | 2;
3182     return (int)(((unsigned)(temp * (temp ^ 1)) >> 8) & 0xff);
3183 }
3184 
3185 /*
3186  * Update the encryption keys with the next byte of plain text
3187  */
3188     int
3189 update_keys(c)
3190     int c;			/* byte of plain text */
3191 {
3192     keys[0] = CRC32(keys[0], c);
3193     keys[1] += keys[0] & 0xff;
3194     keys[1] = keys[1] * 134775813L + 1;
3195     keys[2] = CRC32(keys[2], (int)(keys[1] >> 24));
3196     return c;
3197 }
3198 
3199 /*
3200  * Initialize the encryption keys and the random header according to
3201  * the given password.
3202  * If "passwd" is NULL or empty, don't do anything.
3203  */
3204     void
3205 crypt_init_keys(passwd)
3206     char_u *passwd;		/* password string with which to modify keys */
3207 {
3208     if (passwd != NULL && *passwd != NUL)
3209     {
3210 	make_crc_tab();
3211 	keys[0] = 305419896L;
3212 	keys[1] = 591751049L;
3213 	keys[2] = 878082192L;
3214 	while (*passwd != '\0')
3215 	    update_keys((int)*passwd++);
3216     }
3217 }
3218 
3219 /*
3220  * Ask the user for a crypt key.
3221  * When "store" is TRUE, the new key in stored in the 'key' option, and the
3222  * 'key' option value is returned: Don't free it.
3223  * When "store" is FALSE, the typed key is returned in allocated memory.
3224  * Returns NULL on failure.
3225  */
3226     char_u *
3227 get_crypt_key(store, twice)
3228     int		store;
3229     int		twice;	    /* Ask for the key twice. */
3230 {
3231     char_u	*p1, *p2 = NULL;
3232     int		round;
3233 
3234     for (round = 0; ; ++round)
3235     {
3236 	cmdline_star = TRUE;
3237 	cmdline_row = msg_row;
3238 	p1 = getcmdline_prompt(NUL, round == 0
3239 		? (char_u *)_("Enter encryption key: ")
3240 		: (char_u *)_("Enter same key again: "), 0);
3241 	cmdline_star = FALSE;
3242 
3243 	if (p1 == NULL)
3244 	    break;
3245 
3246 	if (round == twice)
3247 	{
3248 	    if (p2 != NULL && STRCMP(p1, p2) != 0)
3249 	    {
3250 		MSG(_("Keys don't match!"));
3251 		vim_free(p1);
3252 		vim_free(p2);
3253 		p2 = NULL;
3254 		round = -1;		/* do it again */
3255 		continue;
3256 	    }
3257 	    if (store)
3258 	    {
3259 		set_option_value((char_u *)"key", 0L, p1, OPT_LOCAL);
3260 		vim_free(p1);
3261 		p1 = curbuf->b_p_key;
3262 	    }
3263 	    break;
3264 	}
3265 	p2 = p1;
3266     }
3267 
3268     /* since the user typed this, no need to wait for return */
3269     need_wait_return = FALSE;
3270     msg_didout = FALSE;
3271 
3272     vim_free(p2);
3273     return p1;
3274 }
3275 
3276 #endif /* FEAT_CRYPT */
3277 
3278 /* TODO: make some #ifdef for this */
3279 /*--------[ file searching ]-------------------------------------------------*/
3280 /*
3281  * File searching functions for 'path', 'tags' and 'cdpath' options.
3282  * External visible functions:
3283  * vim_findfile_init()		creates/initialises the search context
3284  * vim_findfile_free_visited()	free list of visited files/dirs of search
3285  *				context
3286  * vim_findfile()		find a file in the search context
3287  * vim_findfile_cleanup()	cleanup/free search context created by
3288  *				vim_findfile_init()
3289  *
3290  * All static functions and variables start with 'ff_'
3291  *
3292  * In general it works like this:
3293  * First you create yourself a search context by calling vim_findfile_init().
3294  * It is possible to give a search context from a previous call to
3295  * vim_findfile_init(), so it can be reused. After this you call vim_findfile()
3296  * until you are satisfied with the result or it returns NULL. On every call it
3297  * returns the next file which matches the conditions given to
3298  * vim_findfile_init(). If it doesn't find a next file it returns NULL.
3299  *
3300  * It is possible to call vim_findfile_init() again to reinitialise your search
3301  * with some new parameters. Don't forget to pass your old search context to
3302  * it, so it can reuse it and especially reuse the list of already visited
3303  * directories. If you want to delete the list of already visited directories
3304  * simply call vim_findfile_free_visited().
3305  *
3306  * When you are done call vim_findfile_cleanup() to free the search context.
3307  *
3308  * The function vim_findfile_init() has a long comment, which describes the
3309  * needed parameters.
3310  *
3311  *
3312  *
3313  * ATTENTION:
3314  * ==========
3315  *	Also we use an allocated search context here, this functions ARE NOT
3316  *	thread-safe!!!!!
3317  *
3318  *	To minimize parameter passing (or because I'm to lazy), only the
3319  *	external visible functions get a search context as a parameter. This is
3320  *	then assigned to a static global, which is used throughout the local
3321  *	functions.
3322  */
3323 
3324 /*
3325  * type for the directory search stack
3326  */
3327 typedef struct ff_stack
3328 {
3329     struct ff_stack	*ffs_prev;
3330 
3331     /* the fix part (no wildcards) and the part containing the wildcards
3332      * of the search path
3333      */
3334     char_u		*ffs_fix_path;
3335 #ifdef FEAT_PATH_EXTRA
3336     char_u		*ffs_wc_path;
3337 #endif
3338 
3339     /* files/dirs found in the above directory, matched by the first wildcard
3340      * of wc_part
3341      */
3342     char_u		**ffs_filearray;
3343     int			ffs_filearray_size;
3344     char_u		ffs_filearray_cur;   /* needed for partly handled dirs */
3345 
3346     /* to store status of partly handled directories
3347      * 0: we work the on this directory for the first time
3348      * 1: this directory was partly searched in an earlier step
3349     */
3350     int			ffs_stage;
3351 
3352     /* How deep are we in the directory tree?
3353      * Counts backward from value of level parameter to vim_findfile_init
3354      */
3355     int			ffs_level;
3356 
3357     /* Did we already expand '**' to an empty string? */
3358     int			ffs_star_star_empty;
3359 } ff_stack_T;
3360 
3361 /*
3362  * type for already visited directories or files.
3363  */
3364 typedef struct ff_visited
3365 {
3366     struct ff_visited	*ffv_next;
3367 
3368 #ifdef FEAT_PATH_EXTRA
3369     /* Visited directories are different if the wildcard string are
3370      * different. So we have to save it.
3371      */
3372     char_u		*ffv_wc_path;
3373 #endif
3374     /* for unix use inode etc for comparison (needed because of links), else
3375      * use filename.
3376      */
3377 #ifdef UNIX
3378     int			ffv_dev;	/* device number (-1 if not set) */
3379     ino_t		ffv_ino;	/* inode number */
3380 #endif
3381     /* The memory for this struct is allocated according to the length of
3382      * ffv_fname.
3383      */
3384     char_u		ffv_fname[1];	/* actually longer */
3385 } ff_visited_T;
3386 
3387 /*
3388  * We might have to manage several visited lists during a search.
3389  * This is expecially needed for the tags option. If tags is set to:
3390  *      "./++/tags,./++/TAGS,++/tags"  (replace + with *)
3391  * So we have to do 3 searches:
3392  *   1) search from the current files directory downward for the file "tags"
3393  *   2) search from the current files directory downward for the file "TAGS"
3394  *   3) search from Vims current directory downwards for the file "tags"
3395  * As you can see, the first and the third search are for the same file, so for
3396  * the third search we can use the visited list of the first search. For the
3397  * second search we must start from a empty visited list.
3398  * The struct ff_visited_list_hdr is used to manage a linked list of already
3399  * visited lists.
3400  */
3401 typedef struct ff_visited_list_hdr
3402 {
3403     struct ff_visited_list_hdr	*ffvl_next;
3404 
3405     /* the filename the attached visited list is for */
3406     char_u			*ffvl_filename;
3407 
3408     ff_visited_T		*ffvl_visited_list;
3409 
3410 } ff_visited_list_hdr_T;
3411 
3412 
3413 /*
3414  * '**' can be expanded to several directory levels.
3415  * Set the default maximium depth.
3416  */
3417 #define FF_MAX_STAR_STAR_EXPAND ((char_u)30)
3418 /*
3419  * The search context:
3420  *   ffsc_stack_ptr:	the stack for the dirs to search
3421  *   ffsc_visited_list: the currently active visited list
3422  *   ffsc_dir_visited_list: the currently active visited list for search dirs
3423  *   ffsc_visited_lists_list: the list of all visited lists
3424  *   ffsc_dir_visited_lists_list: the list of all visited lists for search dirs
3425  *   ffsc_file_to_search:     the file to search for
3426  *   ffsc_start_dir:	the starting directory, if search path was relative
3427  *   ffsc_fix_path:	the fix part of the given path (without wildcards)
3428  *			Needed for upward search.
3429  *   ffsc_wc_path:	the part of the given path containing wildcards
3430  *   ffsc_level:	how many levels of dirs to search downwards
3431  *   ffsc_stopdirs_v:	array of stop directories for upward search
3432  *   ffsc_need_dir:	TRUE if we search for a directory
3433  */
3434 typedef struct ff_search_ctx_T
3435 {
3436      ff_stack_T			*ffsc_stack_ptr;
3437      ff_visited_list_hdr_T	*ffsc_visited_list;
3438      ff_visited_list_hdr_T	*ffsc_dir_visited_list;
3439      ff_visited_list_hdr_T	*ffsc_visited_lists_list;
3440      ff_visited_list_hdr_T	*ffsc_dir_visited_lists_list;
3441      char_u			*ffsc_file_to_search;
3442      char_u			*ffsc_start_dir;
3443      char_u			*ffsc_fix_path;
3444 #ifdef FEAT_PATH_EXTRA
3445      char_u			*ffsc_wc_path;
3446      int			ffsc_level;
3447      char_u			**ffsc_stopdirs_v;
3448 #endif
3449      int			ffsc_need_dir;
3450 }ff_search_ctx_T;
3451 static ff_search_ctx_T *ff_search_ctx = NULL;
3452 
3453 /* used for expanding filenames */
3454 static char_u		*ff_expand_buffer = NULL;
3455 
3456 /* locally needed functions */
3457 #ifdef FEAT_PATH_EXTRA
3458 static int ff_check_visited __ARGS((ff_visited_T **, char_u *, char_u *));
3459 #else
3460 static int ff_check_visited __ARGS((ff_visited_T **, char_u *));
3461 #endif
3462 static void vim_findfile_free_visited_list __ARGS((ff_visited_list_hdr_T **list_headp));
3463 static void ff_free_visited_list __ARGS((ff_visited_T *vl));
3464 static ff_visited_list_hdr_T* ff_get_visited_list __ARGS((char_u *, ff_visited_list_hdr_T **list_headp));
3465 #ifdef FEAT_PATH_EXTRA
3466 static int ff_wc_equal __ARGS((char_u *s1, char_u *s2));
3467 #endif
3468 
3469 static void ff_push __ARGS((ff_stack_T *));
3470 static ff_stack_T * ff_pop __ARGS((void));
3471 static void ff_clear __ARGS((void));
3472 static void ff_free_stack_element __ARGS((ff_stack_T *));
3473 #ifdef FEAT_PATH_EXTRA
3474 static ff_stack_T *ff_create_stack_element __ARGS((char_u *, char_u *, int, int));
3475 #else
3476 static ff_stack_T *ff_create_stack_element __ARGS((char_u *, int, int));
3477 #endif
3478 #ifdef FEAT_PATH_EXTRA
3479 static int ff_path_in_stoplist __ARGS((char_u *, int, char_u **));
3480 #endif
3481 
3482 #ifdef FEAT_SEARCHPATH
3483 static char_u *find_file_in_path_option __ARGS((char_u *ptr, int len, int options, int first, char_u *path_option, int need_dir, char_u *rel_fname));
3484 #endif
3485 
3486 #if 0
3487 /*
3488  * if someone likes findfirst/findnext, here are the functions
3489  * NOT TESTED!!
3490  */
3491 
3492 static void *ff_fn_search_context = NULL;
3493 
3494     char_u *
3495 vim_findfirst(path, filename, level)
3496     char_u	*path;
3497     char_u	*filename;
3498     int		level;
3499 {
3500     ff_fn_search_context =
3501 	vim_findfile_init(path, filename, NULL, level, TRUE, FALSE,
3502 		ff_fn_search_context, rel_fname);
3503     if (NULL == ff_fn_search_context)
3504 	return NULL;
3505     else
3506 	return vim_findnext()
3507 }
3508 
3509     char_u *
3510 vim_findnext()
3511 {
3512     char_u *ret = vim_findfile(ff_fn_search_context);
3513 
3514     if (NULL == ret)
3515     {
3516 	vim_findfile_cleanup(ff_fn_search_context);
3517 	ff_fn_search_context = NULL;
3518     }
3519     return ret;
3520 }
3521 #endif
3522 
3523 /*
3524  * Initialization routine for vim_findfile.
3525  *
3526  * Returns the newly allocated search context or NULL if an error occured.
3527  *
3528  * Don't forget to clean up by calling vim_findfile_cleanup() if you are done
3529  * with the search context.
3530  *
3531  * Find the file 'filename' in the directory 'path'.
3532  * The parameter 'path' may contain wildcards. If so only search 'level'
3533  * directories deep. The parameter 'level' is the absolute maximum and is
3534  * not related to restricts given to the '**' wildcard. If 'level' is 100
3535  * and you use '**200' vim_findfile() will stop after 100 levels.
3536  *
3537  * If 'stopdirs' is not NULL and nothing is found downward, the search is
3538  * restarted on the next higher directory level. This is repeated until the
3539  * start-directory of a search is contained in 'stopdirs'. 'stopdirs' has the
3540  * format ";*<dirname>*\(;<dirname>\)*;\=$".
3541  *
3542  * If the 'path' is relative, the starting dir for the search is either VIM's
3543  * current dir or if the path starts with "./" the current files dir.
3544  * If the 'path' is absolut, the starting dir is that part of the path before
3545  * the first wildcard.
3546  *
3547  * Upward search is only done on the starting dir.
3548  *
3549  * If 'free_visited' is TRUE the list of already visited files/directories is
3550  * cleared. Set this to FALSE if you just want to search from another
3551  * directory, but want to be sure that no directory from a previous search is
3552  * searched again. This is useful if you search for a file at different places.
3553  * The list of visited files/dirs can also be cleared with the function
3554  * vim_findfile_free_visited().
3555  *
3556  * Set the parameter 'need_dir' to TRUE if you want to search for a directory
3557  * instead of a file.
3558  *
3559  * A search context returned by a previous call to vim_findfile_init() can be
3560  * passed in the parameter 'search_ctx'. This context is than reused and
3561  * reinitialized with the new parameters. The list of already viseted
3562  * directories from this context is only deleted if the parameter
3563  * 'free_visited' is true. Be aware that the passed search_context is freed if
3564  * the reinitialization fails.
3565  *
3566  * If you don't have a search context from a previous call 'search_ctx' must be
3567  * NULL.
3568  *
3569  * This function silently ignores a few errors, vim_findfile() will have
3570  * limited functionality then.
3571  */
3572 /*ARGSUSED*/
3573     void *
3574 vim_findfile_init(path, filename, stopdirs, level, free_visited, need_dir,
3575 						search_ctx, tagfile, rel_fname)
3576     char_u	*path;
3577     char_u	*filename;
3578     char_u	*stopdirs;
3579     int		level;
3580     int		free_visited;
3581     int		need_dir;
3582     void	*search_ctx;
3583     int		tagfile;
3584     char_u	*rel_fname;	/* file name to use for "." */
3585 {
3586 #ifdef FEAT_PATH_EXTRA
3587     char_u	*wc_part;
3588 #endif
3589     ff_stack_T	*sptr;
3590 
3591     /* If a search context is given by the caller, reuse it, else allocate a
3592      * new one.
3593      */
3594     if (search_ctx != NULL)
3595 	ff_search_ctx = search_ctx;
3596     else
3597     {
3598 	ff_search_ctx = (ff_search_ctx_T*)alloc(
3599 					   (unsigned)sizeof(ff_search_ctx_T));
3600 	if (ff_search_ctx == NULL)
3601 	    goto error_return;
3602 	memset(ff_search_ctx, 0, sizeof(ff_search_ctx_T));
3603     }
3604 
3605     /* clear the search context, but NOT the visited lists */
3606     ff_clear();
3607 
3608     /* clear visited list if wanted */
3609     if (free_visited == TRUE)
3610 	vim_findfile_free_visited(ff_search_ctx);
3611     else
3612     {
3613 	/* Reuse old visited lists. Get the visited list for the given
3614 	 * filename. If no list for the current filename exists, creates a new
3615 	 * one.
3616 	 */
3617 	ff_search_ctx->ffsc_visited_list = ff_get_visited_list(filename,
3618 				     &ff_search_ctx->ffsc_visited_lists_list);
3619 	if (ff_search_ctx->ffsc_visited_list == NULL)
3620 	    goto error_return;
3621 	ff_search_ctx->ffsc_dir_visited_list = ff_get_visited_list(filename,
3622 				 &ff_search_ctx->ffsc_dir_visited_lists_list);
3623 	if (ff_search_ctx->ffsc_dir_visited_list == NULL)
3624 	    goto error_return;
3625     }
3626 
3627     if (ff_expand_buffer == NULL)
3628     {
3629 	ff_expand_buffer = (char_u*)alloc(MAXPATHL);
3630 	if (ff_expand_buffer == NULL)
3631 	    goto error_return;
3632     }
3633 
3634     /* Store information on starting dir now if path is relative.
3635      * If path is absolute, we do that later.
3636      */
3637     if (path[0] == '.'
3638 	    && (vim_ispathsep(path[1]) || path[1] == NUL)
3639 	    && (!tagfile || vim_strchr(p_cpo, CPO_DOTTAG) == NULL)
3640 	    && rel_fname != NULL)
3641     {
3642 	int	len = (int)(gettail(rel_fname) - rel_fname);
3643 
3644 	if (!vim_isAbsName(rel_fname) && len + 1 < MAXPATHL)
3645 	{
3646 	    /* Make the start dir an absolute path name. */
3647 	    STRNCPY(ff_expand_buffer, rel_fname, len);
3648 	    ff_expand_buffer[len] = NUL;
3649 	    ff_search_ctx->ffsc_start_dir = FullName_save(ff_expand_buffer,
3650 								       FALSE);
3651 	}
3652 	else
3653 	    ff_search_ctx->ffsc_start_dir = vim_strnsave(rel_fname, len);
3654 	if (ff_search_ctx->ffsc_start_dir == NULL)
3655 	    goto error_return;
3656 	if (*++path != NUL)
3657 	    ++path;
3658     }
3659     else if (*path == NUL || !vim_isAbsName(path))
3660     {
3661 #ifdef BACKSLASH_IN_FILENAME
3662 	/* "c:dir" needs "c:" to be expanded, otherwise use current dir */
3663 	if (*path != NUL && path[1] == ':')
3664 	{
3665 	    char_u  drive[3];
3666 
3667 	    drive[0] = path[0];
3668 	    drive[1] = ':';
3669 	    drive[2] = NUL;
3670 	    if (vim_FullName(drive, ff_expand_buffer, MAXPATHL, TRUE) == FAIL)
3671 		goto error_return;
3672 	    path += 2;
3673 	}
3674 	else
3675 #endif
3676 	if (mch_dirname(ff_expand_buffer, MAXPATHL) == FAIL)
3677 	    goto error_return;
3678 
3679 	ff_search_ctx->ffsc_start_dir = vim_strsave(ff_expand_buffer);
3680 	if (ff_search_ctx->ffsc_start_dir == NULL)
3681 	    goto error_return;
3682 
3683 #ifdef BACKSLASH_IN_FILENAME
3684 	/* A path that starts with "/dir" is relative to the drive, not to the
3685 	 * directory (but not for "//machine/dir").  Only use the drive name. */
3686 	if ((*path == '/' || *path == '\\')
3687 		&& path[1] != path[0]
3688 		&& ff_search_ctx->ffsc_start_dir[1] == ':')
3689 	    ff_search_ctx->ffsc_start_dir[2] = NUL;
3690 #endif
3691     }
3692 
3693 #ifdef FEAT_PATH_EXTRA
3694     /*
3695      * If stopdirs are given, split them into an array of pointers.
3696      * If this fails (mem allocation), there is no upward search at all or a
3697      * stop directory is not recognized -> continue silently.
3698      * If stopdirs just contains a ";" or is empty,
3699      * ff_search_ctx->ffsc_stopdirs_v will only contain a  NULL pointer. This
3700      * is handled as unlimited upward search.  See function
3701      * ff_path_in_stoplist() for details.
3702      */
3703     if (stopdirs != NULL)
3704     {
3705 	char_u	*walker = stopdirs;
3706 	int	dircount;
3707 
3708 	while (*walker == ';')
3709 	    walker++;
3710 
3711 	dircount = 1;
3712 	ff_search_ctx->ffsc_stopdirs_v =
3713 	    (char_u **)alloc((unsigned)sizeof(char_u *));
3714 
3715 	if (ff_search_ctx->ffsc_stopdirs_v != NULL)
3716 	{
3717 	    do
3718 	    {
3719 		char_u	*helper;
3720 		void	*ptr;
3721 
3722 		helper = walker;
3723 		ptr = vim_realloc(ff_search_ctx->ffsc_stopdirs_v,
3724 					   (dircount + 1) * sizeof(char_u *));
3725 		if (ptr)
3726 		    ff_search_ctx->ffsc_stopdirs_v = ptr;
3727 		else
3728 		    /* ignore, keep what we have and continue */
3729 		    break;
3730 		walker = vim_strchr(walker, ';');
3731 		if (walker)
3732 		{
3733 		    ff_search_ctx->ffsc_stopdirs_v[dircount-1] =
3734 			vim_strnsave(helper, (int)(walker - helper));
3735 		    walker++;
3736 		}
3737 		else
3738 		    /* this might be "", which means ascent till top
3739 		     * of directory tree.
3740 		     */
3741 		    ff_search_ctx->ffsc_stopdirs_v[dircount-1] =
3742 			vim_strsave(helper);
3743 
3744 		dircount++;
3745 
3746 	    } while (walker != NULL);
3747 	    ff_search_ctx->ffsc_stopdirs_v[dircount-1] = NULL;
3748 	}
3749     }
3750 #endif
3751 
3752 #ifdef FEAT_PATH_EXTRA
3753     ff_search_ctx->ffsc_level = level;
3754 
3755     /* split into:
3756      *  -fix path
3757      *  -wildcard_stuff (might be NULL)
3758      */
3759     wc_part = vim_strchr(path, '*');
3760     if (wc_part != NULL)
3761     {
3762 	int	llevel;
3763 	int	len;
3764 	char_u	*errpt;
3765 
3766 	/* save the fix part of the path */
3767 	ff_search_ctx->ffsc_fix_path = vim_strnsave(path,
3768 						       (int)(wc_part - path));
3769 
3770 	/*
3771 	 * copy wc_path and add restricts to the '**' wildcard.
3772 	 * The octett after a '**' is used as a (binary) counter.
3773 	 * So '**3' is transposed to '**^C' ('^C' is ASCII value 3)
3774 	 * or '**76' is transposed to '**N'( 'N' is ASCII value 76).
3775 	 * For EBCDIC you get different character values.
3776 	 * If no restrict is given after '**' the default is used.
3777 	 * Due to this technic the path looks awful if you print it as a
3778 	 * string.
3779 	 */
3780 	len = 0;
3781 	while (*wc_part != NUL)
3782 	{
3783 	    if (STRNCMP(wc_part, "**", 2) == 0)
3784 	    {
3785 		ff_expand_buffer[len++] = *wc_part++;
3786 		ff_expand_buffer[len++] = *wc_part++;
3787 
3788 		llevel = strtol((char *)wc_part, (char **)&errpt, 10);
3789 		if (errpt != wc_part && llevel > 0 && llevel < 255)
3790 		    ff_expand_buffer[len++] = llevel;
3791 		else if (errpt != wc_part && llevel == 0)
3792 		    /* restrict is 0 -> remove already added '**' */
3793 		    len -= 2;
3794 		else
3795 		    ff_expand_buffer[len++] = FF_MAX_STAR_STAR_EXPAND;
3796 		wc_part = errpt;
3797 		if (*wc_part != PATHSEP && *wc_part != NUL)
3798 		{
3799 		    EMSG2(_("E343: Invalid path: '**[number]' must be at the end of the path or be followed by '%s'."), PATHSEPSTR);
3800 		    goto error_return;
3801 		}
3802 	    }
3803 	    else
3804 		ff_expand_buffer[len++] = *wc_part++;
3805 	}
3806 	ff_expand_buffer[len] = NUL;
3807 	ff_search_ctx->ffsc_wc_path =
3808 	    vim_strsave(ff_expand_buffer);
3809 
3810 	if (ff_search_ctx->ffsc_wc_path == NULL)
3811 	    goto error_return;
3812     }
3813     else
3814 #endif
3815 	ff_search_ctx->ffsc_fix_path = vim_strsave(path);
3816 
3817     if (ff_search_ctx->ffsc_start_dir == NULL)
3818     {
3819 	/* store the fix part as startdir.
3820 	 * This is needed if the parameter path is fully qualified.
3821 	 */
3822 	ff_search_ctx->ffsc_start_dir = vim_strsave(ff_search_ctx->ffsc_fix_path);
3823 	if (ff_search_ctx->ffsc_start_dir)
3824 	    ff_search_ctx->ffsc_fix_path[0] = NUL;
3825     }
3826 
3827     /* create an absolute path */
3828     STRCPY(ff_expand_buffer, ff_search_ctx->ffsc_start_dir);
3829     add_pathsep(ff_expand_buffer);
3830     STRCAT(ff_expand_buffer, ff_search_ctx->ffsc_fix_path);
3831     add_pathsep(ff_expand_buffer);
3832 
3833     sptr = ff_create_stack_element(ff_expand_buffer,
3834 #ifdef FEAT_PATH_EXTRA
3835 	    ff_search_ctx->ffsc_wc_path,
3836 #endif
3837 	    level, 0);
3838 
3839     if (sptr == NULL)
3840 	goto error_return;
3841 
3842     ff_push(sptr);
3843 
3844     ff_search_ctx->ffsc_file_to_search = vim_strsave(filename);
3845     if (ff_search_ctx->ffsc_file_to_search == NULL)
3846 	goto error_return;
3847 
3848     return ff_search_ctx;
3849 
3850 error_return:
3851     /*
3852      * We clear the search context now!
3853      * Even when the caller gave us a (perhaps valid) context we free it here,
3854      * as we might have already destroyed it.
3855      */
3856     vim_findfile_cleanup(ff_search_ctx);
3857     return NULL;
3858 }
3859 
3860 #if defined(FEAT_PATH_EXTRA) || defined(PROTO)
3861 /*
3862  * Get the stopdir string.  Check that ';' is not escaped.
3863  */
3864     char_u *
3865 vim_findfile_stopdir(buf)
3866     char_u	*buf;
3867 {
3868     char_u	*r_ptr = buf;
3869 
3870     while (*r_ptr != NUL && *r_ptr != ';')
3871     {
3872 	if (r_ptr[0] == '\\' && r_ptr[1] == ';')
3873 	{
3874 	    /* overwrite the escape char,
3875 	     * use STRLEN(r_ptr) to move the trailing '\0'
3876 	     */
3877 	    mch_memmove(r_ptr, r_ptr + 1, STRLEN(r_ptr));
3878 	    r_ptr++;
3879 	}
3880 	r_ptr++;
3881     }
3882     if (*r_ptr == ';')
3883     {
3884 	*r_ptr = 0;
3885 	r_ptr++;
3886     }
3887     else if (*r_ptr == NUL)
3888 	r_ptr = NULL;
3889     return r_ptr;
3890 }
3891 #endif
3892 
3893 /* Clean up the given search context. Can handle a NULL pointer */
3894     void
3895 vim_findfile_cleanup(ctx)
3896     void	*ctx;
3897 {
3898     if (NULL == ctx)
3899 	return;
3900 
3901     ff_search_ctx = ctx;
3902 
3903     vim_findfile_free_visited(ctx);
3904     ff_clear();
3905     vim_free(ctx);
3906     ff_search_ctx = NULL;
3907 }
3908 
3909 /*
3910  * Find a file in a search context.
3911  * The search context was created with vim_findfile_init() above.
3912  * Return a pointer to an allocated file name or NULL if nothing found.
3913  * To get all matching files call this function until you get NULL.
3914  *
3915  * If the passed search_context is NULL, it the returns NULL.
3916  *
3917  * The search algorithm is depth first. To change this replace the
3918  * stack with a list (don't forget to leave partly searched directories on the
3919  * top of the list).
3920  */
3921     char_u *
3922 vim_findfile(search_ctx)
3923     void	*search_ctx;
3924 {
3925     char_u	*file_path;
3926 #ifdef FEAT_PATH_EXTRA
3927     char_u	*rest_of_wildcards;
3928     char_u	*path_end = NULL;
3929 #endif
3930     ff_stack_T	*ctx;
3931 #if defined(FEAT_SEARCHPATH) || defined(FEAT_PATH_EXTRA)
3932     int		len;
3933 #endif
3934     int		i;
3935     char_u	*p;
3936 #ifdef FEAT_SEARCHPATH
3937     char_u	*suf;
3938 #endif
3939 
3940     if (search_ctx == NULL)
3941 	return NULL;
3942 
3943     ff_search_ctx = (ff_search_ctx_T*)search_ctx;
3944 
3945     /*
3946      * filepath is used as buffer for various actions and as the storage to
3947      * return a found filename.
3948      */
3949     if ((file_path = alloc((int)MAXPATHL)) == NULL)
3950 	return NULL;
3951 
3952 #ifdef FEAT_PATH_EXTRA
3953     /* store the end of the start dir -- needed for upward search */
3954     if (ff_search_ctx->ffsc_start_dir != NULL)
3955 	path_end = &ff_search_ctx->ffsc_start_dir[STRLEN(ff_search_ctx->ffsc_start_dir)];
3956 #endif
3957 
3958 #ifdef FEAT_PATH_EXTRA
3959     /* upward search loop */
3960     for (;;)
3961     {
3962 #endif
3963 	/* downward search loop */
3964 	for (;;)
3965 	{
3966 	    /* check if user user wants to stop the search*/
3967 	    ui_breakcheck();
3968 	    if (got_int)
3969 		break;
3970 
3971 	    /* get directory to work on from stack */
3972 	    ctx = ff_pop();
3973 	    if (ctx == NULL)
3974 		break;
3975 
3976 	    /*
3977 	     * TODO: decide if we leave this test in
3978 	     *
3979 	     * GOOD: don't search a directory(-tree) twice.
3980 	     * BAD:  - check linked list for every new directory entered.
3981 	     *       - check for double files also done below
3982 	     *
3983 	     * Here we check if we already searched this directory.
3984 	     * We already searched a directory if:
3985 	     * 1) The directory is the same.
3986 	     * 2) We would use the same wildcard string.
3987 	     *
3988 	     * Good if you have links on same directory via several ways
3989 	     *  or you have selfreferences in directories (e.g. SuSE Linux 6.3:
3990 	     *  /etc/rc.d/init.d is linked to /etc/rc.d -> endless loop)
3991 	     *
3992 	     * This check is only needed for directories we work on for the
3993 	     * first time (hence ctx->ff_filearray == NULL)
3994 	     */
3995 	    if (ctx->ffs_filearray == NULL
3996 		    && ff_check_visited(&ff_search_ctx->ffsc_dir_visited_list
3997 							  ->ffvl_visited_list,
3998 			ctx->ffs_fix_path
3999 #ifdef FEAT_PATH_EXTRA
4000 			, ctx->ffs_wc_path
4001 #endif
4002 			) == FAIL)
4003 	    {
4004 #ifdef FF_VERBOSE
4005 		if (p_verbose >= 5)
4006 		{
4007 		    /* always scroll up, don't overwrite */
4008 		    msg_scroll = TRUE;
4009 		    smsg((char_u *)"Already Searched: %s (%s)",
4010 					   ctx->ffs_fix_path, ctx->ffs_wc_path);
4011 		    /* don't overwrite this either */
4012 		    msg_puts((char_u *)"\n");
4013 		    cmdline_row = msg_row;
4014 		}
4015 #endif
4016 		ff_free_stack_element(ctx);
4017 		continue;
4018 	    }
4019 #ifdef FF_VERBOSE
4020 	    else if (p_verbose >= 5)
4021 	    {
4022 		/* always scroll up, don't overwrite */
4023 		msg_scroll = TRUE;
4024 		smsg((char_u *)"Searching: %s (%s)", ctx->ffs_fix_path,
4025 			ctx->ffs_wc_path);
4026 		/* don't overwrite this either */
4027 		msg_puts((char_u *)"\n");
4028 		cmdline_row = msg_row;
4029 	    }
4030 #endif
4031 
4032 	    /* check depth */
4033 	    if (ctx->ffs_level <= 0)
4034 	    {
4035 		ff_free_stack_element(ctx);
4036 		continue;
4037 	    }
4038 
4039 	    file_path[0] = NUL;
4040 
4041 	    /*
4042 	     * If no filearray till now expand wildcards
4043 	     * The function expand_wildcards() can handle an array of paths
4044 	     * and all possible expands are returned in one array. We use this
4045 	     * to handle the expansion of '**' into an empty string.
4046 	     */
4047 	    if (ctx->ffs_filearray == NULL)
4048 	    {
4049 		char_u *dirptrs[2];
4050 
4051 		/* we use filepath to build the path expand_wildcards() should
4052 		 * expand.
4053 		 */
4054 		dirptrs[0] = file_path;
4055 		dirptrs[1] = NULL;
4056 
4057 		/* if we have a start dir copy it in */
4058 		if (!vim_isAbsName(ctx->ffs_fix_path)
4059 			&& ff_search_ctx->ffsc_start_dir)
4060 		{
4061 		    STRCPY(file_path, ff_search_ctx->ffsc_start_dir);
4062 		    add_pathsep(file_path);
4063 		}
4064 
4065 		/* append the fix part of the search path */
4066 		STRCAT(file_path, ctx->ffs_fix_path);
4067 		add_pathsep(file_path);
4068 
4069 #ifdef FEAT_PATH_EXTRA
4070 		rest_of_wildcards = ctx->ffs_wc_path;
4071 		if (*rest_of_wildcards != NUL)
4072 		{
4073 		    len = (int)STRLEN(file_path);
4074 		    if (STRNCMP(rest_of_wildcards, "**", 2) == 0)
4075 		    {
4076 			/* pointer to the restrict byte
4077 			 * The restrict byte is not a character!
4078 			 */
4079 			p = rest_of_wildcards + 2;
4080 
4081 			if (*p > 0)
4082 			{
4083 			    (*p)--;
4084 			    file_path[len++] = '*';
4085 			}
4086 
4087 			if (*p == 0)
4088 			{
4089 			    /* remove '**<numb> from wildcards */
4090 			    mch_memmove(rest_of_wildcards,
4091 				    rest_of_wildcards + 3,
4092 				    STRLEN(rest_of_wildcards + 3) + 1);
4093 			}
4094 			else
4095 			    rest_of_wildcards += 3;
4096 
4097 			if (ctx->ffs_star_star_empty == 0)
4098 			{
4099 			    /* if not done before, expand '**' to empty */
4100 			    ctx->ffs_star_star_empty = 1;
4101 			    dirptrs[1] = ctx->ffs_fix_path;
4102 			}
4103 		    }
4104 
4105 		    /*
4106 		     * Here we copy until the next path separator or the end of
4107 		     * the path. If we stop at a path separator, there is
4108 		     * still somthing else left. This is handled below by
4109 		     * pushing every directory returned from expand_wildcards()
4110 		     * on the stack again for further search.
4111 		     */
4112 		    while (*rest_of_wildcards
4113 			    && !vim_ispathsep(*rest_of_wildcards))
4114 			file_path[len++] = *rest_of_wildcards++;
4115 
4116 		    file_path[len] = NUL;
4117 		    if (vim_ispathsep(*rest_of_wildcards))
4118 			rest_of_wildcards++;
4119 		}
4120 #endif
4121 
4122 		/*
4123 		 * Expand wildcards like "*" and "$VAR".
4124 		 * If the path is a URL don't try this.
4125 		 */
4126 		if (path_with_url(dirptrs[0]))
4127 		{
4128 		    ctx->ffs_filearray = (char_u **)
4129 					      alloc((unsigned)sizeof(char *));
4130 		    if (ctx->ffs_filearray != NULL
4131 			    && (ctx->ffs_filearray[0]
4132 				= vim_strsave(dirptrs[0])) != NULL)
4133 			ctx->ffs_filearray_size = 1;
4134 		    else
4135 			ctx->ffs_filearray_size = 0;
4136 		}
4137 		else
4138 		    expand_wildcards((dirptrs[1] == NULL) ? 1 : 2, dirptrs,
4139 			    &ctx->ffs_filearray_size,
4140 			    &ctx->ffs_filearray,
4141 			    EW_DIR|EW_ADDSLASH|EW_SILENT);
4142 
4143 		ctx->ffs_filearray_cur = 0;
4144 		ctx->ffs_stage = 0;
4145 	    }
4146 #ifdef FEAT_PATH_EXTRA
4147 	    else
4148 		rest_of_wildcards = &ctx->ffs_wc_path[STRLEN(ctx->ffs_wc_path)];
4149 #endif
4150 
4151 	    if (ctx->ffs_stage == 0)
4152 	    {
4153 		/* this is the first time we work on this directory */
4154 #ifdef FEAT_PATH_EXTRA
4155 		if (*rest_of_wildcards == NUL)
4156 #endif
4157 		{
4158 		    /*
4159 		     * we don't have further wildcards to expand, so we have to
4160 		     * check for the final file now
4161 		     */
4162 		    for (i = ctx->ffs_filearray_cur;
4163 					     i < ctx->ffs_filearray_size; ++i)
4164 		    {
4165 			if (!path_with_url(ctx->ffs_filearray[i])
4166 					 && !mch_isdir(ctx->ffs_filearray[i]))
4167 			    continue;   /* not a directory */
4168 
4169 			/* prepare the filename to be checked for existance
4170 			 * below */
4171 			STRCPY(file_path, ctx->ffs_filearray[i]);
4172 			add_pathsep(file_path);
4173 			STRCAT(file_path, ff_search_ctx->ffsc_file_to_search);
4174 
4175 			/*
4176 			 * Try without extra suffix and then with suffixes
4177 			 * from 'suffixesadd'.
4178 			 */
4179 #ifdef FEAT_SEARCHPATH
4180 			len = (int)STRLEN(file_path);
4181 			suf = curbuf->b_p_sua;
4182 			for (;;)
4183 #endif
4184 			{
4185 			    /* if file exists and we didn't already find it */
4186 			    if ((path_with_url(file_path)
4187 					|| (mch_getperm(file_path) >= 0
4188 					    && (!ff_search_ctx->ffsc_need_dir
4189 						|| mch_isdir(file_path))))
4190 #ifndef FF_VERBOSE
4191 				    && (ff_check_visited(
4192 					    &ff_search_ctx->ffsc_visited_list->ffvl_visited_list,
4193 					    file_path
4194 #ifdef FEAT_PATH_EXTRA
4195 					    , (char_u *)""
4196 #endif
4197 					    ) == OK)
4198 #endif
4199 			       )
4200 			    {
4201 #ifdef FF_VERBOSE
4202 				if (ff_check_visited(
4203 					    &ff_search_ctx->ffsc_visited_list->ffvl_visited_list,
4204 					    file_path
4205 #ifdef FEAT_PATH_EXTRA
4206 					    , (char_u *)""
4207 #endif
4208 						    ) == FAIL)
4209 				{
4210 				    if (p_verbose >= 5)
4211 				    {
4212 					/* always scroll up, don't overwrite */
4213 					msg_scroll = TRUE;
4214 					msg_str((char_u *)"Already: %s",
4215 								   file_path);
4216 					/* don't overwrite this either */
4217 					msg_puts((char_u *)"\n");
4218 					cmdline_row = msg_row;
4219 				    }
4220 				    continue;
4221 				}
4222 #endif
4223 
4224 				/* push dir to examine rest of subdirs later */
4225 				ctx->ffs_filearray_cur = i + 1;
4226 				ff_push(ctx);
4227 
4228 				simplify_filename(file_path);
4229 				if (mch_dirname(ff_expand_buffer, MAXPATHL)
4230 									== OK)
4231 				{
4232 				    p = shorten_fname(file_path,
4233 							    ff_expand_buffer);
4234 				    if (p != NULL)
4235 					mch_memmove(file_path, p,
4236 							       STRLEN(p) + 1);
4237 				}
4238 #ifdef FF_VERBOSE
4239 				if (p_verbose >= 5)
4240 				{
4241 				    /* always scroll up, don't overwrite */
4242 				    msg_scroll = TRUE;
4243 				    msg_str((char_u *)"HIT: %s", file_path);
4244 				    /* don't overwrite this either */
4245 				    msg_puts((char_u *)"\n");
4246 				    cmdline_row = msg_row;
4247 				}
4248 #endif
4249 				return file_path;
4250 			    }
4251 
4252 #ifdef FEAT_SEARCHPATH
4253 			    /* Not found or found already, try next suffix. */
4254 			    if (*suf == NUL)
4255 				break;
4256 			    copy_option_part(&suf, file_path + len,
4257 							 MAXPATHL - len, ",");
4258 #endif
4259 			}
4260 		    }
4261 		}
4262 #ifdef FEAT_PATH_EXTRA
4263 		else
4264 		{
4265 		    /*
4266 		     * still wildcards left, push the directories for further
4267 		     * search
4268 		     */
4269 		    for (i = ctx->ffs_filearray_cur; i < ctx->ffs_filearray_size;
4270 									  ++i)
4271 		    {
4272 			if (!mch_isdir(ctx->ffs_filearray[i]))
4273 			    continue;	/* not a directory */
4274 
4275 			ff_push(ff_create_stack_element(ctx->ffs_filearray[i],
4276 				      rest_of_wildcards, ctx->ffs_level - 1, 0));
4277 		    }
4278 		}
4279 #endif
4280 		ctx->ffs_filearray_cur = 0;
4281 		ctx->ffs_stage = 1;
4282 	    }
4283 
4284 #ifdef FEAT_PATH_EXTRA
4285 	    /*
4286 	     * if wildcards contains '**' we have to descent till we reach the
4287 	     * leaves of the directory tree.
4288 	     */
4289 	    if (STRNCMP(ctx->ffs_wc_path, "**", 2) == 0)
4290 	    {
4291 		for (i = ctx->ffs_filearray_cur; i < ctx->ffs_filearray_size; ++i)
4292 		{
4293 		    if (fnamecmp(ctx->ffs_filearray[i], ctx->ffs_fix_path) == 0)
4294 			continue; /* don't repush same directory */
4295 		    if (!mch_isdir(ctx->ffs_filearray[i]))
4296 			continue;   /* not a directory */
4297 		    ff_push(ff_create_stack_element(ctx->ffs_filearray[i],
4298 				ctx->ffs_wc_path, ctx->ffs_level - 1, 1));
4299 		}
4300 	    }
4301 #endif
4302 
4303 	    /* we are done with the current directory */
4304 	    ff_free_stack_element(ctx);
4305 
4306 	}
4307 
4308 #ifdef FEAT_PATH_EXTRA
4309 	/* If we reached this, we didn't find anything downwards.
4310 	 * Let's check if we should do an upward search.
4311 	 */
4312 	if (ff_search_ctx->ffsc_start_dir
4313 		&& ff_search_ctx->ffsc_stopdirs_v != NULL && !got_int)
4314 	{
4315 	    ff_stack_T  *sptr;
4316 
4317 	    /* is the last starting directory in the stop list? */
4318 	    if (ff_path_in_stoplist(ff_search_ctx->ffsc_start_dir,
4319 		       (int)(path_end - ff_search_ctx->ffsc_start_dir),
4320 		       ff_search_ctx->ffsc_stopdirs_v) == TRUE)
4321 		break;
4322 
4323 	    /* cut of last dir */
4324 	    while (path_end > ff_search_ctx->ffsc_start_dir
4325 		    && *path_end == PATHSEP)
4326 		path_end--;
4327 	    while (path_end > ff_search_ctx->ffsc_start_dir
4328 		    && *(path_end-1) != PATHSEP)
4329 		path_end--;
4330 	    *path_end = 0;
4331 	    path_end--;
4332 
4333 	    if (*ff_search_ctx->ffsc_start_dir == 0)
4334 		break;
4335 
4336 	    STRCPY(file_path, ff_search_ctx->ffsc_start_dir);
4337 	    add_pathsep(file_path);
4338 	    STRCAT(file_path, ff_search_ctx->ffsc_fix_path);
4339 
4340 	    /* create a new stack entry */
4341 	    sptr = ff_create_stack_element(file_path,
4342 		    ff_search_ctx->ffsc_wc_path, ff_search_ctx->ffsc_level, 0);
4343 	    if (sptr == NULL)
4344 		break;
4345 	    ff_push(sptr);
4346 	}
4347 	else
4348 	    break;
4349     }
4350 #endif
4351 
4352     vim_free(file_path);
4353     return NULL;
4354 }
4355 
4356 /*
4357  * Free the list of lists of visited files and directories
4358  * Can handle it if the passed search_context is NULL;
4359  */
4360     void
4361 vim_findfile_free_visited(search_ctx)
4362     void	*search_ctx;
4363 {
4364     if (search_ctx == NULL)
4365 	return;
4366 
4367     ff_search_ctx = (ff_search_ctx_T *)search_ctx;
4368 
4369     vim_findfile_free_visited_list(&ff_search_ctx->ffsc_visited_lists_list);
4370     vim_findfile_free_visited_list(&ff_search_ctx->ffsc_dir_visited_lists_list);
4371 }
4372 
4373     static void
4374 vim_findfile_free_visited_list(list_headp)
4375     ff_visited_list_hdr_T	**list_headp;
4376 {
4377     ff_visited_list_hdr_T *vp;
4378 
4379     while (*list_headp != NULL)
4380     {
4381 	vp = (*list_headp)->ffvl_next;
4382 	ff_free_visited_list((*list_headp)->ffvl_visited_list);
4383 
4384 	vim_free((*list_headp)->ffvl_filename);
4385 	vim_free(*list_headp);
4386 	*list_headp = vp;
4387     }
4388     *list_headp = NULL;
4389 }
4390 
4391     static void
4392 ff_free_visited_list(vl)
4393     ff_visited_T *vl;
4394 {
4395     ff_visited_T *vp;
4396 
4397     while (vl != NULL)
4398     {
4399 	vp = vl->ffv_next;
4400 #ifdef FEAT_PATH_EXTRA
4401 	vim_free(vl->ffv_wc_path);
4402 #endif
4403 	vim_free(vl);
4404 	vl = vp;
4405     }
4406     vl = NULL;
4407 }
4408 
4409 /*
4410  * Returns the already visited list for the given filename. If none is found it
4411  * allocates a new one.
4412  */
4413     static ff_visited_list_hdr_T*
4414 ff_get_visited_list(filename, list_headp)
4415     char_u			*filename;
4416     ff_visited_list_hdr_T	**list_headp;
4417 {
4418     ff_visited_list_hdr_T  *retptr = NULL;
4419 
4420     /* check if a visited list for the given filename exists */
4421     if (*list_headp != NULL)
4422     {
4423 	retptr = *list_headp;
4424 	while (retptr != NULL)
4425 	{
4426 	    if (fnamecmp(filename, retptr->ffvl_filename) == 0)
4427 	    {
4428 #ifdef FF_VERBOSE
4429 		if (p_verbose >= 5)
4430 		{
4431 		    /* always scroll up, don't overwrite */
4432 		    msg_scroll = TRUE;
4433 		    msg_str((char_u *)"ff_get_visited_list: FOUND list for %s",
4434 								    filename);
4435 		    /* don't overwrite this either */
4436 		    msg_puts((char_u *)"\n");
4437 		    cmdline_row = msg_row;
4438 		}
4439 #endif
4440 		return retptr;
4441 	    }
4442 	    retptr = retptr->ffvl_next;
4443 	}
4444     }
4445 
4446 #ifdef FF_VERBOSE
4447     if (p_verbose >= 5)
4448     {
4449 	/* always scroll up, don't overwrite */
4450 	msg_scroll = TRUE;
4451 	msg_str((char_u *)"ff_get_visited_list: new list for %s", filename);
4452 	/* don't overwrite this either */
4453 	msg_puts((char_u *)"\n");
4454 	cmdline_row = msg_row;
4455     }
4456 #endif
4457 
4458     /*
4459      * if we reach this we didn't find a list and we have to allocate new list
4460      */
4461     retptr = (ff_visited_list_hdr_T*)alloc((unsigned)sizeof(*retptr));
4462     if (retptr == NULL)
4463 	return NULL;
4464 
4465     retptr->ffvl_visited_list = NULL;
4466     retptr->ffvl_filename = vim_strsave(filename);
4467     if (retptr->ffvl_filename == NULL)
4468     {
4469 	vim_free(retptr);
4470 	return NULL;
4471     }
4472     retptr->ffvl_next = *list_headp;
4473     *list_headp = retptr;
4474 
4475     return retptr;
4476 }
4477 
4478 #ifdef FEAT_PATH_EXTRA
4479 /*
4480  * check if two wildcard paths are equal. Returns TRUE or FALSE.
4481  * They are equal if:
4482  *  - both paths are NULL
4483  *  - they have the same length
4484  *  - char by char comparison is OK
4485  *  - the only differences are in the counters behind a '**', so
4486  *    '**\20' is equal to '**\24'
4487  */
4488     static int
4489 ff_wc_equal(s1, s2)
4490     char_u	*s1;
4491     char_u	*s2;
4492 {
4493     int		i;
4494 
4495     if (s1 == s2)
4496 	return TRUE;
4497 
4498     if (s1 == NULL || s2 == NULL)
4499 	return FALSE;
4500 
4501     if (STRLEN(s1) != STRLEN(s2))
4502 	return FAIL;
4503 
4504     for (i = 0; s1[i] != NUL && s2[i] != NUL; i++)
4505     {
4506 	if (s1[i] != s2[i]
4507 #ifdef CASE_INSENSITIVE_FILENAME
4508 		&& TOUPPER_LOC(s1[i]) != TOUPPER_LOC(s2[i])
4509 #endif
4510 		)
4511 	{
4512 	    if (i >= 2)
4513 		if (s1[i-1] == '*' && s1[i-2] == '*')
4514 		    continue;
4515 		else
4516 		    return FAIL;
4517 	    else
4518 		return FAIL;
4519 	}
4520     }
4521     return TRUE;
4522 }
4523 #endif
4524 
4525 /*
4526  * maintains the list of already visited files and dirs
4527  * returns FAIL if the given file/dir is already in the list
4528  * returns OK if it is newly added
4529  *
4530  * TODO: What to do on memory allocation problems?
4531  *	 -> return TRUE - Better the file is found several times instead of
4532  *	    never.
4533  */
4534     static int
4535 ff_check_visited(visited_list, fname
4536 #ifdef FEAT_PATH_EXTRA
4537 	, wc_path
4538 #endif
4539 	)
4540     ff_visited_T	**visited_list;
4541     char_u		*fname;
4542 #ifdef FEAT_PATH_EXTRA
4543     char_u		*wc_path;
4544 #endif
4545 {
4546     ff_visited_T	*vp;
4547 #ifdef UNIX
4548     struct stat		st;
4549     int			url = FALSE;
4550 #endif
4551 
4552     /* For an URL we only compare the name, otherwise we compare the
4553      * device/inode (unix) or the full path name (not Unix). */
4554     if (path_with_url(fname))
4555     {
4556 	STRNCPY(ff_expand_buffer, fname, MAXPATHL);
4557 #ifdef UNIX
4558 	url = TRUE;
4559 #endif
4560     }
4561     else
4562     {
4563 	ff_expand_buffer[0] = NUL;
4564 #ifdef UNIX
4565 	if (mch_stat((char *)fname, &st) < 0)
4566 #else
4567 	if (vim_FullName(fname, ff_expand_buffer, MAXPATHL, TRUE) == FAIL)
4568 #endif
4569 	    return FAIL;
4570     }
4571 
4572     /* check against list of already visited files */
4573     for (vp = *visited_list; vp != NULL; vp = vp->ffv_next)
4574     {
4575 	if (
4576 #ifdef UNIX
4577 		!url
4578 		    ? (vp->ffv_dev == st.st_dev
4579 			&& vp->ffv_ino == st.st_ino)
4580 		    :
4581 #endif
4582 		fnamecmp(vp->ffv_fname, ff_expand_buffer) == 0
4583 	   )
4584 	{
4585 #ifdef FEAT_PATH_EXTRA
4586 	    /* are the wildcard parts equal */
4587 	    if (ff_wc_equal(vp->ffv_wc_path, wc_path) == TRUE)
4588 #endif
4589 		/* already visited */
4590 		return FAIL;
4591 	}
4592     }
4593 
4594     /*
4595      * New file/dir.  Add it to the list of visited files/dirs.
4596      */
4597     vp = (ff_visited_T *)alloc((unsigned)(sizeof(ff_visited_T)
4598 						 + STRLEN(ff_expand_buffer)));
4599 
4600     if (vp != NULL)
4601     {
4602 #ifdef UNIX
4603 	if (!url)
4604 	{
4605 	    vp->ffv_ino = st.st_ino;
4606 	    vp->ffv_dev = st.st_dev;
4607 	    vp->ffv_fname[0] = NUL;
4608 	}
4609 	else
4610 	{
4611 	    vp->ffv_ino = 0;
4612 	    vp->ffv_dev = -1;
4613 #endif
4614 	    STRCPY(vp->ffv_fname, ff_expand_buffer);
4615 #ifdef UNIX
4616 	}
4617 #endif
4618 #ifdef FEAT_PATH_EXTRA
4619 	if (wc_path != NULL)
4620 	    vp->ffv_wc_path = vim_strsave(wc_path);
4621 	else
4622 	    vp->ffv_wc_path = NULL;
4623 #endif
4624 
4625 	vp->ffv_next = *visited_list;
4626 	*visited_list = vp;
4627     }
4628 
4629     return OK;
4630 }
4631 
4632 /*
4633  * create stack element from given path pieces
4634  */
4635     static ff_stack_T *
4636 ff_create_stack_element(fix_part,
4637 #ifdef FEAT_PATH_EXTRA
4638 	wc_part,
4639 #endif
4640 	level, star_star_empty)
4641     char_u	*fix_part;
4642 #ifdef FEAT_PATH_EXTRA
4643     char_u	*wc_part;
4644 #endif
4645     int		level;
4646     int		star_star_empty;
4647 {
4648     ff_stack_T	*new;
4649 
4650     new = (ff_stack_T *)alloc((unsigned)sizeof(ff_stack_T));
4651     if (new == NULL)
4652 	return NULL;
4653 
4654     new->ffs_prev	   = NULL;
4655     new->ffs_filearray	   = NULL;
4656     new->ffs_filearray_size = 0;
4657     new->ffs_filearray_cur  = 0;
4658     new->ffs_stage	   = 0;
4659     new->ffs_level	   = level;
4660     new->ffs_star_star_empty = star_star_empty;;
4661 
4662     /* the following saves NULL pointer checks in vim_findfile */
4663     if (fix_part == NULL)
4664 	fix_part = (char_u *)"";
4665     new->ffs_fix_path = vim_strsave(fix_part);
4666 
4667 #ifdef FEAT_PATH_EXTRA
4668     if (wc_part == NULL)
4669 	wc_part  = (char_u *)"";
4670     new->ffs_wc_path = vim_strsave(wc_part);
4671 #endif
4672 
4673     if (new->ffs_fix_path == NULL
4674 #ifdef FEAT_PATH_EXTRA
4675 	    || new->ffs_wc_path == NULL
4676 #endif
4677 	    )
4678     {
4679 	ff_free_stack_element(new);
4680 	new = NULL;
4681     }
4682 
4683     return new;
4684 }
4685 
4686 /*
4687  * push a dir on the directory stack
4688  */
4689     static void
4690 ff_push(ctx)
4691     ff_stack_T *ctx;
4692 {
4693     /* check for NULL pointer, not to return an error to the user, but
4694      * to prevent a crash
4695      */
4696     if (ctx != NULL)
4697     {
4698 	ctx->ffs_prev   = ff_search_ctx->ffsc_stack_ptr;
4699 	ff_search_ctx->ffsc_stack_ptr = ctx;
4700     }
4701 }
4702 
4703 /*
4704  * pop a dir from the directory stack
4705  * returns NULL if stack is empty
4706  */
4707     static ff_stack_T *
4708 ff_pop()
4709 {
4710     ff_stack_T  *sptr;
4711 
4712     sptr = ff_search_ctx->ffsc_stack_ptr;
4713     if (ff_search_ctx->ffsc_stack_ptr != NULL)
4714 	ff_search_ctx->ffsc_stack_ptr = ff_search_ctx->ffsc_stack_ptr->ffs_prev;
4715 
4716     return sptr;
4717 }
4718 
4719 /*
4720  * free the given stack element
4721  */
4722     static void
4723 ff_free_stack_element(ctx)
4724     ff_stack_T  *ctx;
4725 {
4726     /* vim_free handles possible NULL pointers */
4727     vim_free(ctx->ffs_fix_path);
4728 #ifdef FEAT_PATH_EXTRA
4729     vim_free(ctx->ffs_wc_path);
4730 #endif
4731 
4732     if (ctx->ffs_filearray != NULL)
4733 	FreeWild(ctx->ffs_filearray_size, ctx->ffs_filearray);
4734 
4735     vim_free(ctx);
4736 }
4737 
4738 /*
4739  * clear the search context
4740  */
4741     static void
4742 ff_clear()
4743 {
4744     ff_stack_T   *sptr;
4745 
4746     /* clear up stack */
4747     while ((sptr = ff_pop()) != NULL)
4748 	ff_free_stack_element(sptr);
4749 
4750     vim_free(ff_search_ctx->ffsc_file_to_search);
4751     vim_free(ff_search_ctx->ffsc_start_dir);
4752     vim_free(ff_search_ctx->ffsc_fix_path);
4753 #ifdef FEAT_PATH_EXTRA
4754     vim_free(ff_search_ctx->ffsc_wc_path);
4755 #endif
4756 
4757 #ifdef FEAT_PATH_EXTRA
4758     if (ff_search_ctx->ffsc_stopdirs_v != NULL)
4759     {
4760 	int  i = 0;
4761 
4762 	while (ff_search_ctx->ffsc_stopdirs_v[i] != NULL)
4763 	{
4764 	    vim_free(ff_search_ctx->ffsc_stopdirs_v[i]);
4765 	    i++;
4766 	}
4767 	vim_free(ff_search_ctx->ffsc_stopdirs_v);
4768     }
4769     ff_search_ctx->ffsc_stopdirs_v = NULL;
4770 #endif
4771 
4772     /* reset everything */
4773     ff_search_ctx->ffsc_file_to_search	= NULL;
4774     ff_search_ctx->ffsc_start_dir	= NULL;
4775     ff_search_ctx->ffsc_fix_path	= NULL;
4776 #ifdef FEAT_PATH_EXTRA
4777     ff_search_ctx->ffsc_wc_path		= NULL;
4778     ff_search_ctx->ffsc_level		= 0;
4779 #endif
4780 }
4781 
4782 #ifdef FEAT_PATH_EXTRA
4783 /*
4784  * check if the given path is in the stopdirs
4785  * returns TRUE if yes else FALSE
4786  */
4787     static int
4788 ff_path_in_stoplist(path, path_len, stopdirs_v)
4789     char_u	*path;
4790     int		path_len;
4791     char_u	**stopdirs_v;
4792 {
4793     int		i = 0;
4794 
4795     /* eat up trailing path separators, except the first */
4796     while (path_len > 1 && path[path_len - 1] == PATHSEP)
4797 	path_len--;
4798 
4799     /* if no path consider it as match */
4800     if (path_len == 0)
4801 	return TRUE;
4802 
4803     for (i = 0; stopdirs_v[i] != NULL; i++)
4804     {
4805 	if ((int)STRLEN(stopdirs_v[i]) > path_len)
4806 	{
4807 	    /* match for parent directory. So '/home' also matches
4808 	     * '/home/rks'. Check for PATHSEP in stopdirs_v[i], else
4809 	     * '/home/r' would also match '/home/rks'
4810 	     */
4811 	    if (fnamencmp(stopdirs_v[i], path, path_len) == 0
4812 		    && stopdirs_v[i][path_len] == PATHSEP)
4813 		return TRUE;
4814 	}
4815 	else
4816 	{
4817 	    if (fnamecmp(stopdirs_v[i], path) == 0)
4818 		return TRUE;
4819 	}
4820     }
4821     return FALSE;
4822 }
4823 #endif
4824 
4825 #if defined(FEAT_SEARCHPATH) || defined(PROTO)
4826 /*
4827  * Find the file name "ptr[len]" in the path.
4828  *
4829  * On the first call set the parameter 'first' to TRUE to initialize
4830  * the search.  For repeating calls to FALSE.
4831  *
4832  * Repeating calls will return other files called 'ptr[len]' from the path.
4833  *
4834  * Only on the first call 'ptr' and 'len' are used.  For repeating calls they
4835  * don't need valid values.
4836  *
4837  * If nothing found on the first call the option FNAME_MESS will issue the
4838  * message:
4839  *	    'Can't find file "<file>" in path'
4840  * On repeating calls:
4841  *	    'No more file "<file>" found in path'
4842  *
4843  * options:
4844  * FNAME_MESS	    give error message when not found
4845  *
4846  * Uses NameBuff[]!
4847  *
4848  * Returns an allocated string for the file name.  NULL for error.
4849  *
4850  */
4851     char_u *
4852 find_file_in_path(ptr, len, options, first, rel_fname)
4853     char_u	*ptr;		/* file name */
4854     int		len;		/* length of file name */
4855     int		options;
4856     int		first;		/* use count'th matching file name */
4857     char_u	*rel_fname;	/* file name searching relative to */
4858 {
4859     return find_file_in_path_option(ptr, len, options, first,
4860 	    *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path,
4861 	    FALSE, rel_fname);
4862 }
4863 
4864 /*
4865  * Find the directory name "ptr[len]" in the path.
4866  *
4867  * options:
4868  * FNAME_MESS	    give error message when not found
4869  *
4870  * Uses NameBuff[]!
4871  *
4872  * Returns an allocated string for the file name.  NULL for error.
4873  */
4874     char_u *
4875 find_directory_in_path(ptr, len, options, rel_fname)
4876     char_u	*ptr;		/* file name */
4877     int		len;		/* length of file name */
4878     int		options;
4879     char_u	*rel_fname;	/* file name searching relative to */
4880 {
4881     return find_file_in_path_option(ptr, len, options, TRUE, p_cdpath,
4882 							     TRUE, rel_fname);
4883 }
4884 
4885     static char_u *
4886 find_file_in_path_option(ptr, len, options, first, path_option, need_dir, rel_fname)
4887     char_u	*ptr;		/* file name */
4888     int		len;		/* length of file name */
4889     int		options;
4890     int		first;		/* use count'th matching file name */
4891     char_u	*path_option;	/* p_path or p_cdpath */
4892     int		need_dir;	/* looking for directory name */
4893     char_u	*rel_fname;	/* file name we are looking relative to. */
4894 {
4895     static void		*search_ctx = NULL;
4896     static char_u	*dir;
4897     static char_u	*file_to_find = NULL;
4898     static int		did_findfile_init = FALSE;
4899     char_u		save_char;
4900     char_u		*file_name = NULL;
4901     char_u		*buf = NULL;
4902     int			rel_to_curdir;
4903 #ifdef AMIGA
4904     struct Process	*proc = (struct Process *)FindTask(0L);
4905     APTR		save_winptr = proc->pr_WindowPtr;
4906 
4907     /* Avoid a requester here for a volume that doesn't exist. */
4908     proc->pr_WindowPtr = (APTR)-1L;
4909 #endif
4910 
4911     if (first == TRUE)
4912     {
4913 	/* copy file name into NameBuff, expanding environment variables */
4914 	save_char = ptr[len];
4915 	ptr[len] = NUL;
4916 	expand_env(ptr, NameBuff, MAXPATHL);
4917 	ptr[len] = save_char;
4918 
4919 	vim_free(file_to_find);
4920 	file_to_find = vim_strsave(NameBuff);
4921 	if (file_to_find == NULL)	/* out of memory */
4922 	{
4923 	    file_name = NULL;
4924 	    goto theend;
4925 	}
4926     }
4927 
4928     rel_to_curdir = (file_to_find[0] == '.'
4929 		    && (file_to_find[1] == NUL
4930 			|| vim_ispathsep(file_to_find[1])
4931 			|| (file_to_find[1] == '.'
4932 			    && (file_to_find[2] == NUL
4933 				|| vim_ispathsep(file_to_find[2])))));
4934     if (vim_isAbsName(file_to_find)
4935 	    /* "..", "../path", "." and "./path": don't use the path_option */
4936 	    || rel_to_curdir
4937 #if defined(MSWIN) || defined(MSDOS) || defined(OS2)
4938 	    /* handle "\tmp" as absolute path */
4939 	    || vim_ispathsep(file_to_find[0])
4940 	    /* handle "c:name" as absulute path */
4941 	    || (file_to_find[0] != NUL && file_to_find[1] == ':')
4942 #endif
4943 #ifdef AMIGA
4944 	    /* handle ":tmp" as absolute path */
4945 	    || file_to_find[0] == ':'
4946 #endif
4947        )
4948     {
4949 	/*
4950 	 * Absolute path, no need to use "path_option".
4951 	 * If this is not a first call, return NULL.  We already returned a
4952 	 * filename on the first call.
4953 	 */
4954 	if (first == TRUE)
4955 	{
4956 	    int		l;
4957 	    int		run;
4958 
4959 	    if (path_with_url(file_to_find))
4960 	    {
4961 		file_name = vim_strsave(file_to_find);
4962 		goto theend;
4963 	    }
4964 
4965 	    /* When FNAME_REL flag given first use the directory of the file.
4966 	     * Otherwise or when this fails use the current directory. */
4967 	    for (run = 1; run <= 2; ++run)
4968 	    {
4969 		l = (int)STRLEN(file_to_find);
4970 		if (run == 1
4971 			&& rel_to_curdir
4972 			&& (options & FNAME_REL)
4973 			&& rel_fname != NULL
4974 			&& STRLEN(rel_fname) + l < MAXPATHL)
4975 		{
4976 		    STRCPY(NameBuff, rel_fname);
4977 		    STRCPY(gettail(NameBuff), file_to_find);
4978 		    l = (int)STRLEN(NameBuff);
4979 		}
4980 		else
4981 		{
4982 		    STRCPY(NameBuff, file_to_find);
4983 		    run = 2;
4984 		}
4985 
4986 		/* When the file doesn't exist, try adding parts of
4987 		 * 'suffixesadd'. */
4988 		buf = curbuf->b_p_sua;
4989 		for (;;)
4990 		{
4991 		    if (
4992 #ifdef DJGPP
4993 			    /* "C:" by itself will fail for mch_getperm(),
4994 			     * assume it's always valid. */
4995 			    (need_dir && NameBuff[0] != NUL
4996 				  && NameBuff[1] == ':'
4997 				  && NameBuff[2] == NUL) ||
4998 #endif
4999 			    (mch_getperm(NameBuff) >= 0
5000 				       && (!need_dir || mch_isdir(NameBuff))))
5001 		    {
5002 			file_name = vim_strsave(NameBuff);
5003 			goto theend;
5004 		    }
5005 		    if (*buf == NUL)
5006 			break;
5007 		    copy_option_part(&buf, NameBuff + l, MAXPATHL - l, ",");
5008 		}
5009 	    }
5010 	}
5011     }
5012     else
5013     {
5014 	/*
5015 	 * Loop over all paths in the 'path' or 'cdpath' option.
5016 	 * When "first" is set, first setup to the start of the option.
5017 	 * Otherwise continue to find the next match.
5018 	 */
5019 	if (first == TRUE)
5020 	{
5021 	    /* vim_findfile_free_visited can handle a possible NULL pointer */
5022 	    vim_findfile_free_visited(search_ctx);
5023 	    dir = path_option;
5024 	    did_findfile_init = FALSE;
5025 	}
5026 
5027 	for (;;)
5028 	{
5029 	    if (did_findfile_init)
5030 	    {
5031 		ff_search_ctx->ffsc_need_dir = need_dir;
5032 		file_name = vim_findfile(search_ctx);
5033 		ff_search_ctx->ffsc_need_dir = FALSE;
5034 		if (file_name != NULL)
5035 		    break;
5036 
5037 		did_findfile_init = FALSE;
5038 	    }
5039 	    else
5040 	    {
5041 		char_u  *r_ptr;
5042 
5043 		if (dir == NULL || *dir == NUL)
5044 		{
5045 		    /* We searched all paths of the option, now we can
5046 		     * free the search context. */
5047 		    vim_findfile_cleanup(search_ctx);
5048 		    search_ctx = NULL;
5049 		    break;
5050 		}
5051 
5052 		if ((buf = alloc((int)(MAXPATHL))) == NULL)
5053 		    break;
5054 
5055 		/* copy next path */
5056 		buf[0] = 0;
5057 		copy_option_part(&dir, buf, MAXPATHL, " ,");
5058 
5059 #ifdef FEAT_PATH_EXTRA
5060 		/* get the stopdir string */
5061 		r_ptr = vim_findfile_stopdir(buf);
5062 #else
5063 		r_ptr = NULL;
5064 #endif
5065 		search_ctx = vim_findfile_init(buf, file_to_find, r_ptr, 100,
5066 				   FALSE, TRUE, search_ctx, FALSE, rel_fname);
5067 		if (search_ctx != NULL)
5068 		    did_findfile_init = TRUE;
5069 		vim_free(buf);
5070 	    }
5071 	}
5072     }
5073     if (file_name == NULL && (options & FNAME_MESS))
5074     {
5075 	if (first == TRUE)
5076 	{
5077 	    if (need_dir)
5078 		EMSG2(_("E344: Can't find directory \"%s\" in cdpath"),
5079 			file_to_find);
5080 	    else
5081 		EMSG2(_("E345: Can't find file \"%s\" in path"),
5082 			file_to_find);
5083 	}
5084 	else
5085 	{
5086 	    if (need_dir)
5087 		EMSG2(_("E346: No more directory \"%s\" found in cdpath"),
5088 			file_to_find);
5089 	    else
5090 		EMSG2(_("E347: No more file \"%s\" found in path"),
5091 			file_to_find);
5092 	}
5093     }
5094 
5095 theend:
5096 #ifdef AMIGA
5097     proc->pr_WindowPtr = save_winptr;
5098 #endif
5099     return file_name;
5100 }
5101 
5102 #endif /* FEAT_SEARCHPATH */
5103 
5104 /*
5105  * Change directory to "new_dir".  If FEAT_SEARCHPATH is defined, search
5106  * 'cdpath' for relative directory names, otherwise just mch_chdir().
5107  */
5108     int
5109 vim_chdir(new_dir)
5110     char_u	*new_dir;
5111 {
5112 #ifndef FEAT_SEARCHPATH
5113     return mch_chdir((char *)new_dir);
5114 #else
5115     char_u	*dir_name;
5116     int		r;
5117 
5118     dir_name = find_directory_in_path(new_dir, (int)STRLEN(new_dir),
5119 						FNAME_MESS, curbuf->b_ffname);
5120     if (dir_name == NULL)
5121 	return -1;
5122     r = mch_chdir((char *)dir_name);
5123     vim_free(dir_name);
5124     return r;
5125 #endif
5126 }
5127 
5128 /*
5129  * Get user name from machine-specific function and cache it.
5130  * Returns the user name in "buf[len]".
5131  * Some systems are quite slow in obtaining the user name (Windows NT).
5132  * Returns OK or FAIL.
5133  */
5134     int
5135 get_user_name(buf, len)
5136     char_u	*buf;
5137     int		len;
5138 {
5139     static char_u	*name = NULL;
5140 
5141     if (name == NULL)
5142     {
5143 	if (mch_get_user_name(buf, len) == FAIL)
5144 	    return FAIL;
5145 	name = vim_strsave(buf);
5146     }
5147     else
5148 	STRNCPY(buf, name, len);
5149     return OK;
5150 }
5151 
5152 #ifndef HAVE_QSORT
5153 /*
5154  * Our own qsort(), for systems that don't have it.
5155  * It's simple and slow.  From the K&R C book.
5156  */
5157     void
5158 qsort(base, elm_count, elm_size, cmp)
5159     void	*base;
5160     size_t	elm_count;
5161     size_t	elm_size;
5162     int (*cmp) __ARGS((const void *, const void *));
5163 {
5164     char_u	*buf;
5165     char_u	*p1;
5166     char_u	*p2;
5167     int		i, j;
5168     int		gap;
5169 
5170     buf = alloc((unsigned)elm_size);
5171     if (buf == NULL)
5172 	return;
5173 
5174     for (gap = elm_count / 2; gap > 0; gap /= 2)
5175 	for (i = gap; i < elm_count; ++i)
5176 	    for (j = i - gap; j >= 0; j -= gap)
5177 	    {
5178 		/* Compare the elements. */
5179 		p1 = (char_u *)base + j * elm_size;
5180 		p2 = (char_u *)base + (j + gap) * elm_size;
5181 		if ((*cmp)((void *)p1, (void *)p2) <= 0)
5182 		    break;
5183 		/* Exchange the elemets. */
5184 		mch_memmove(buf, p1, elm_size);
5185 		mch_memmove(p1, p2, elm_size);
5186 		mch_memmove(p2, buf, elm_size);
5187 	    }
5188 
5189     vim_free(buf);
5190 }
5191 #endif
5192 
5193 #if defined(FEAT_EX_EXTRA) || defined(FEAT_CMDL_COMPL) || defined(PROTO)
5194 /*
5195  * Sort an array of strings.
5196  */
5197 static int
5198 #ifdef __BORLANDC__
5199 _RTLENTRYF
5200 #endif
5201 sort_compare __ARGS((const void *s1, const void *s2));
5202 
5203     static int
5204 #ifdef __BORLANDC__
5205 _RTLENTRYF
5206 #endif
5207 sort_compare(s1, s2)
5208     const void	*s1;
5209     const void	*s2;
5210 {
5211     return STRCMP(*(char **)s1, *(char **)s2);
5212 }
5213 
5214     void
5215 sort_strings(files, count)
5216     char_u	**files;
5217     int		count;
5218 {
5219     qsort((void *)files, (size_t)count, sizeof(char_u *), sort_compare);
5220 }
5221 #endif
5222 
5223 #if !defined(NO_EXPANDPATH) || defined(PROTO)
5224 /*
5225  * Compare path "p[]" to "q[]".
5226  * Return value like strcmp(p, q), but consider path separators.
5227  */
5228     int
5229 pathcmp(p, q)
5230     const char *p, *q;
5231 {
5232     int		i;
5233     const char	*s;
5234 
5235     for (i = 0; ; ++i)
5236     {
5237 	/* End of "p": check if "q" also ends or just has a slash. */
5238 	if (p[i] == NUL)
5239 	{
5240 	    if (q[i] == NUL)  /* full match */
5241 		return 0;
5242 	    s = q;
5243 	    break;
5244 	}
5245 
5246 	/* End of "q": check if "p" just has a slash. */
5247 	if (q[i] == NUL)
5248 	{
5249 	    s = p;
5250 	    break;
5251 	}
5252 
5253 	if (
5254 #ifdef CASE_INSENSITIVE_FILENAME
5255 		TOUPPER_LOC(p[i]) != TOUPPER_LOC(q[i])
5256 #else
5257 		p[i] != q[i]
5258 #endif
5259 #ifdef BACKSLASH_IN_FILENAME
5260 		/* consider '/' and '\\' to be equal */
5261 		&& !((p[i] == '/' && q[i] == '\\')
5262 		    || (p[i] == '\\' && q[i] == '/'))
5263 #endif
5264 		)
5265 	{
5266 	    if (vim_ispathsep(p[i]))
5267 		return -1;
5268 	    if (vim_ispathsep(q[i]))
5269 		return 1;
5270 	    return ((char_u *)p)[i] - ((char_u *)q)[i];	    /* no match */
5271 	}
5272     }
5273 
5274     /* ignore a trailing slash, but not "//" or ":/" */
5275     if (s[i + 1] == NUL && i > 0 && !vim_ispathsep(s[i - 1])
5276 #ifdef BACKSLASH_IN_FILENAME
5277 	    && (s[i] == '/' || s[i] == '\\')
5278 #else
5279 	    && s[i] == '/'
5280 #endif
5281        )
5282 	return 0;   /* match with trailing slash */
5283     if (s == q)
5284 	return -1;	    /* no match */
5285     return 1;
5286 }
5287 #endif
5288 
5289 #if defined(FEAT_PRINTER) || defined(PROTO)
5290 /*
5291  * Parse a list of options in the form
5292  * option:value,option:value,option:value
5293  *
5294  * "value" can start with a number which is parsed out, e.g.
5295  * margin:12mm
5296  *
5297  * Returns error message for an illegal option, NULL otherwise.
5298  * Only used for the printer at the moment...
5299  */
5300     char_u *
5301 parse_list_options(option_str, table, table_size)
5302     char_u		*option_str;
5303     option_table_T	*table;
5304     int			table_size;
5305 {
5306     char_u	*stringp;
5307     char_u	*colonp;
5308     char_u	*commap;
5309     char_u	*p;
5310     int		idx = 0;		/* init for GCC */
5311     int		len;
5312 
5313     for (idx = 0; idx < table_size; ++idx)
5314 	table[idx].present = FALSE;
5315 
5316     /*
5317      * Repeat for all comma separated parts.
5318      */
5319     stringp = option_str;
5320     while (*stringp)
5321     {
5322 	colonp = vim_strchr(stringp, ':');
5323 	if (colonp == NULL)
5324 	    return (char_u *)N_("E550: Missing colon");
5325 	commap = vim_strchr(stringp, ',');
5326 	if (commap == NULL)
5327 	    commap = option_str + STRLEN(option_str);
5328 
5329 	len = (int)(colonp - stringp);
5330 
5331 	for (idx = 0; idx < table_size; ++idx)
5332 	    if (STRNICMP(stringp, table[idx].name, len) == 0)
5333 		break;
5334 
5335 	if (idx == table_size)
5336 	    return (char_u *)N_("E551: Illegal component");
5337 
5338 	p = colonp + 1;
5339 	table[idx].present = TRUE;
5340 
5341 	if (table[idx].hasnum)
5342 	{
5343 	    if (!VIM_ISDIGIT(*p))
5344 		return (char_u *)N_("E552: digit expected");
5345 
5346 	    table[idx].number = getdigits(&p); /*advances p*/
5347 	}
5348 
5349 	table[idx].string = p;
5350 	table[idx].strlen = (int)(commap - p);
5351 
5352 	stringp = commap;
5353 	if (*stringp == ',')
5354 	    ++stringp;
5355     }
5356 
5357     return NULL;
5358 }
5359 
5360 
5361 #endif /*FEAT_PRINTER*/
5362 
5363 /*
5364  * The putenv() implementation below comes from the "screen" program.
5365  * Included with permission from Juergen Weigert.
5366  * See pty.c for the copyright notice.
5367  */
5368 
5369 /*
5370  *  putenv  --	put value into environment
5371  *
5372  *  Usage:  i = putenv (string)
5373  *    int i;
5374  *    char  *string;
5375  *
5376  *  where string is of the form <name>=<value>.
5377  *  Putenv returns 0 normally, -1 on error (not enough core for malloc).
5378  *
5379  *  Putenv may need to add a new name into the environment, or to
5380  *  associate a value longer than the current value with a particular
5381  *  name.  So, to make life simpler, putenv() copies your entire
5382  *  environment into the heap (i.e. malloc()) from the stack
5383  *  (i.e. where it resides when your process is initiated) the first
5384  *  time you call it.
5385  *
5386  *  (history removed, not very interesting.  See the "screen" sources.)
5387  */
5388 
5389 #if !defined(HAVE_SETENV) && !defined(HAVE_PUTENV)
5390 
5391 #define EXTRASIZE 5		/* increment to add to env. size */
5392 
5393 static int  envsize = -1;	/* current size of environment */
5394 #ifndef MACOS_CLASSIC
5395 extern
5396 #endif
5397        char **environ;		/* the global which is your env. */
5398 
5399 static int  findenv __ARGS((char *name)); /* look for a name in the env. */
5400 static int  newenv __ARGS((void));	/* copy env. from stack to heap */
5401 static int  moreenv __ARGS((void));	/* incr. size of env. */
5402 
5403     int
5404 putenv(string)
5405     const char *string;
5406 {
5407     int	    i;
5408     char    *p;
5409 
5410     if (envsize < 0)
5411     {				/* first time putenv called */
5412 	if (newenv() < 0)	/* copy env. to heap */
5413 	    return -1;
5414     }
5415 
5416     i = findenv((char *)string); /* look for name in environment */
5417 
5418     if (i < 0)
5419     {				/* name must be added */
5420 	for (i = 0; environ[i]; i++);
5421 	if (i >= (envsize - 1))
5422 	{			/* need new slot */
5423 	    if (moreenv() < 0)
5424 		return -1;
5425 	}
5426 	p = (char *)alloc((unsigned)(strlen(string) + 1));
5427 	if (p == NULL)		/* not enough core */
5428 	    return -1;
5429 	environ[i + 1] = 0;	/* new end of env. */
5430     }
5431     else
5432     {				/* name already in env. */
5433 	p = vim_realloc(environ[i], strlen(string) + 1);
5434 	if (p == NULL)
5435 	    return -1;
5436     }
5437     sprintf(p, "%s", string);	/* copy into env. */
5438     environ[i] = p;
5439 
5440     return 0;
5441 }
5442 
5443     static int
5444 findenv(name)
5445     char *name;
5446 {
5447     char    *namechar, *envchar;
5448     int	    i, found;
5449 
5450     found = 0;
5451     for (i = 0; environ[i] && !found; i++)
5452     {
5453 	envchar = environ[i];
5454 	namechar = name;
5455 	while (*namechar && *namechar != '=' && (*namechar == *envchar))
5456 	{
5457 	    namechar++;
5458 	    envchar++;
5459 	}
5460 	found = ((*namechar == '\0' || *namechar == '=') && *envchar == '=');
5461     }
5462     return found ? i - 1 : -1;
5463 }
5464 
5465     static int
5466 newenv()
5467 {
5468     char    **env, *elem;
5469     int	    i, esize;
5470 
5471 #ifdef MACOS
5472     /* for Mac a new, empty environment is created */
5473     i = 0;
5474 #else
5475     for (i = 0; environ[i]; i++)
5476 	;
5477 #endif
5478     esize = i + EXTRASIZE + 1;
5479     env = (char **)alloc((unsigned)(esize * sizeof (elem)));
5480     if (env == NULL)
5481 	return -1;
5482 
5483 #ifndef MACOS
5484     for (i = 0; environ[i]; i++)
5485     {
5486 	elem = (char *)alloc((unsigned)(strlen(environ[i]) + 1));
5487 	if (elem == NULL)
5488 	    return -1;
5489 	env[i] = elem;
5490 	strcpy(elem, environ[i]);
5491     }
5492 #endif
5493 
5494     env[i] = 0;
5495     environ = env;
5496     envsize = esize;
5497     return 0;
5498 }
5499 
5500     static int
5501 moreenv()
5502 {
5503     int	    esize;
5504     char    **env;
5505 
5506     esize = envsize + EXTRASIZE;
5507     env = (char **)vim_realloc((char *)environ, esize * sizeof (*env));
5508     if (env == 0)
5509 	return -1;
5510     environ = env;
5511     envsize = esize;
5512     return 0;
5513 }
5514 
5515 # ifdef USE_VIMPTY_GETENV
5516     char_u *
5517 vimpty_getenv(string)
5518     const char_u *string;
5519 {
5520     int i;
5521     char_u *p;
5522 
5523     if (envsize < 0)
5524 	return NULL;
5525 
5526     i = findenv((char *)string);
5527 
5528     if (i < 0)
5529 	return NULL;
5530 
5531     p = vim_strchr((char_u *)environ[i], '=');
5532     return (p + 1);
5533 }
5534 # endif
5535 
5536 #endif /* !defined(HAVE_SETENV) && !defined(HAVE_PUTENV) */
5537 
5538 /*
5539  * Print a message with one string argument.
5540  * Make sure that the result fits in IObuff.
5541  * This is not in message.c, because the prototype for smsg() isn't used
5542  * there.
5543  */
5544     void
5545 msg_str(s, arg)
5546     char_u	*s;
5547     char_u	*arg;
5548 {
5549     int		ls = STRLEN(s);
5550     int		larg = STRLEN(arg);
5551 
5552     if (ls + larg >= IOSIZE)
5553 	smsg(s, arg + (ls + larg - IOSIZE));
5554     else
5555 	smsg(s, arg);
5556 }
5557