Annotation of src/usr.bin/vim/cmdline.c, Revision 1.1.1.1
1.1 downsj 1: /* $OpenBSD$ */
2: /* vi:set ts=4 sw=4:
3: *
4: * VIM - Vi IMproved by Bram Moolenaar
5: *
6: * Do ":help uganda" in Vim to read copying and usage conditions.
7: * Do ":help credits" in Vim to see a list of people who contributed.
8: */
9:
10: /*
11: * cmdline.c: functions for reading in the command line and executing it
12: */
13:
14: #include "vim.h"
15: #include "globals.h"
16: #include "proto.h"
17: #include "option.h"
18: #include "cmdtab.h"
19: #include "ops.h" /* included because we call functions in ops.c */
20: #ifdef HAVE_FCNTL_H
21: # include <fcntl.h> /* for chdir() */
22: #endif
23:
24: /*
25: * variables shared between getcmdline() and redrawcmdline()
26: */
27: static char_u *cmdbuff; /* pointer to command line buffer */
28: static int cmdbufflen; /* length of cmdbuff */
29: static int cmdlen; /* number of chars on command line */
30: static int cmdpos; /* current cursor position */
31: static int cmdspos; /* cursor column on screen */
32: static int cmdfirstc; /* ':', '/' or '?' */
33:
34: /*
35: * Typing mode on the command line. Shared by getcmdline() and
36: * put_on_cmdline().
37: */
38: static int overstrike = FALSE; /* typing mode */
39:
40: /*
41: * The next two variables contain the bounds of any range given in a command.
42: * They are set by do_cmdline().
43: */
44: static linenr_t line1, line2;
45:
46: static int forceit;
47: static int regname;
48: static int quitmore = 0;
49: static int cmd_numfiles = -1; /* number of files found by
50: filename completion */
51: /*
52: * There are two history tables:
53: * 0: colon commands
54: * 1: search commands
55: */
56: static char_u **(history[2]) = {NULL, NULL}; /* history tables */
57: static int hisidx[2] = {-1, -1}; /* last entered entry */
58: static int hislen = 0; /* actual lengt of history tables */
59:
60: #ifdef RIGHTLEFT
61: static int cmd_hkmap = 0; /* Hebrew mapping during command line */
62: #endif
63:
64: static void init_history __ARGS((void));
65:
66: static int is_in_history __ARGS((int, char_u *, int));
67: static void putcmdline __ARGS((int));
68: static void redrawcmd __ARGS((void));
69: static void cursorcmd __ARGS((void));
70: static int ccheck_abbr __ARGS((int));
71: static char_u *do_one_cmd __ARGS((char_u **, int *, int));
72: static int buf_write_all __ARGS((BUF *));
73: static int do_write __ARGS((char_u *, int));
74: static char_u *getargcmd __ARGS((char_u **));
75: static void backslash_halve __ARGS((char_u *p, int expand_wildcards));
76: static void do_make __ARGS((char_u *));
77: static int do_arglist __ARGS((char_u *));
78: static int is_backslash __ARGS((char_u *str));
79: static int check_readonly __ARGS((void));
80: static int check_changed __ARGS((BUF *, int, int));
81: static int check_changed_any __ARGS((void));
82: static int check_more __ARGS((int));
83: static void vim_strncpy __ARGS((char_u *, char_u *, int));
84: static int nextwild __ARGS((int));
85: static int showmatches __ARGS((char_u *));
86: static linenr_t get_address __ARGS((char_u **));
87: static void set_expand_context __ARGS((int, char_u *));
88: static char_u *set_one_cmd_context __ARGS((int, char_u *));
89: static int ExpandFromContext __ARGS((char_u *, int *, char_u ***, int, int));
90: static int ExpandCommands __ARGS((regexp *, int *, char_u ***));
91:
92: /*
93: * init_history() - initialize the command line history
94: */
95: static void
96: init_history()
97: {
98: int newlen; /* new length of history table */
99: char_u **temp;
100: register int i;
101: int j;
102: int type;
103:
104: /*
105: * If size of history table changed, reallocate it
106: */
107: newlen = (int)p_hi;
108: if (newlen != hislen) /* history length changed */
109: {
110: for (type = 0; type <= 1; ++type) /* adjust both history tables */
111: {
112: if (newlen)
113: temp = (char_u **)lalloc((long_u)(newlen * sizeof(char_u *)),
114: TRUE);
115: else
116: temp = NULL;
117: if (newlen == 0 || temp != NULL)
118: {
119: if (hisidx[type] < 0) /* there are no entries yet */
120: {
121: for (i = 0; i < newlen; ++i)
122: temp[i] = NULL;
123: }
124: else if (newlen > hislen) /* array becomes bigger */
125: {
126: for (i = 0; i <= hisidx[type]; ++i)
127: temp[i] = history[type][i];
128: j = i;
129: for ( ; i <= newlen - (hislen - hisidx[type]); ++i)
130: temp[i] = NULL;
131: for ( ; j < hislen; ++i, ++j)
132: temp[i] = history[type][j];
133: }
134: else /* array becomes smaller or 0 */
135: {
136: j = hisidx[type];
137: for (i = newlen - 1; ; --i)
138: {
139: if (i >= 0) /* copy newest entries */
140: temp[i] = history[type][j];
141: else /* remove older entries */
142: vim_free(history[type][j]);
143: if (--j < 0)
144: j = hislen - 1;
145: if (j == hisidx[type])
146: break;
147: }
148: hisidx[type] = newlen - 1;
149: }
150: vim_free(history[type]);
151: history[type] = temp;
152: }
153: }
154: hislen = newlen;
155: }
156: }
157:
158: /*
159: * check if command line 'str' is already in history
160: * 'type' is 0 for ':' commands, '1' for search commands
161: * if 'move_to_front' is TRUE, matching entry is moved to end of history
162: */
163: static int
164: is_in_history(type, str, move_to_front)
165: int type;
166: char_u *str;
167: int move_to_front; /* Move the entry to the front if it exists */
168: {
169: int i;
170: int last_i = -1;
171:
172: if (hisidx[type] < 0)
173: return FALSE;
174: i = hisidx[type];
175: do
176: {
177: if (history[type][i] == NULL)
178: return FALSE;
179: if (STRCMP(str, history[type][i]) == 0)
180: {
181: if (!move_to_front)
182: return TRUE;
183: last_i = i;
184: break;
185: }
186: if (--i < 0)
187: i = hislen - 1;
188: } while (i != hisidx[type]);
189:
190: if (last_i >= 0)
191: {
192: str = history[type][i];
193: while (i != hisidx[type])
194: {
195: if (++i >= hislen)
196: i = 0;
197: history[type][last_i] = history[type][i];
198: last_i = i;
199: }
200: history[type][i] = str;
201: return TRUE;
202: }
203: return FALSE;
204: }
205:
206: /*
207: * Add the given string to the given history. If the string is already in the
208: * history then it is moved to the front. histype may be 0 for the ':'
209: * history, or 1 for the '/' history.
210: */
211: void
212: add_to_history(histype, new_entry)
213: int histype;
214: char_u *new_entry;
215: {
216: if (hislen != 0 && !is_in_history(histype, new_entry, TRUE))
217: {
218: if (++hisidx[histype] == hislen)
219: hisidx[histype] = 0;
220: vim_free(history[histype][hisidx[histype]]);
221: history[histype][hisidx[histype]] = strsave(new_entry);
222: }
223: }
224:
225:
226: /*
227: * getcmdline() - accept a command line starting with ':', '/', or '?'
228: *
229: * The line is collected in cmdbuff, which is reallocated to fit the command
230: * line.
231: *
232: * Return pointer to allocated string if there is a commandline, NULL
233: * otherwise.
234: */
235:
236: char_u *
237: getcmdline(firstc, count)
238: int firstc; /* either ':', '/', or '?' */
239: long count; /* only used for incremental search */
240: {
241: register int c;
242: #ifdef DIGRAPHS
243: int cc;
244: #endif
245: register int i;
246: int j;
247: char_u *p;
248: int hiscnt; /* current history line in use */
249: char_u *lookfor = NULL; /* string to match */
250: int gotesc = FALSE; /* TRUE when <ESC> just typed */
251: int do_abbr; /* when TRUE check for abbr. */
252: int histype; /* history type to be used */
253: FPOS old_cursor;
254: colnr_t old_curswant;
255: int did_incsearch = FALSE;
256: int incsearch_postponed = FALSE;
257: int save_msg_scroll = msg_scroll;
258: int some_key_typed = FALSE; /* one of the keys was typed */
259: #ifdef USE_MOUSE
260: /* mouse drag and release events are ignored, unless they are
261: * preceded with a mouse down event */
262: int ignore_drag_release = TRUE;
263: #endif
264:
265: overstrike = FALSE; /* always start in insert mode */
266: old_cursor = curwin->w_cursor; /* needs to be restored later */
267: old_curswant = curwin->w_curswant;
268: /*
269: * set some variables for redrawcmd()
270: */
271: cmdfirstc = firstc;
272: alloc_cmdbuff(0); /* allocate initial cmdbuff */
273: if (cmdbuff == NULL)
274: return NULL; /* out of memory */
275: cmdlen = cmdpos = 0;
276: cmdspos = 1;
277: State = CMDLINE;
278: #ifdef USE_MOUSE
279: setmouse();
280: #endif
281: gotocmdline(TRUE);
282: msg_outchar(firstc);
283: /*
284: * Avoid scrolling when called by a recursive do_cmdline(), e.g. when doing
285: * ":@0" when register 0 doesn't contain a CR.
286: */
287: msg_scroll = FALSE;
288:
289: init_history();
290: hiscnt = hislen; /* set hiscnt to impossible history value */
291: histype = (firstc == ':' ? 0 : 1);
292:
293: #ifdef DIGRAPHS
294: do_digraph(-1); /* init digraph typahead */
295: #endif
296:
297: /* collect the command string, handling editing keys */
298: for (;;)
299: {
300: cursorcmd(); /* set the cursor on the right spot */
301: c = vgetc();
302: if (KeyTyped)
303: {
304: some_key_typed = TRUE;
305: #ifdef RIGHTLEFT
306: if (cmd_hkmap)
307: c = hkmap(c);
308: #endif
309: }
310: if (c == Ctrl('C'))
311: got_int = FALSE; /* ignore got_int when CTRL-C was typed here */
312:
313: /* free old command line when finished moving around in the
314: * history list */
315: if (lookfor && c != K_S_DOWN && c != K_S_UP &&
316: c != K_DOWN && c != K_UP &&
317: c != K_PAGEDOWN && c != K_PAGEUP &&
318: (cmd_numfiles > 0 || (c != Ctrl('P') && c != Ctrl('N'))))
319: {
320: vim_free(lookfor);
321: lookfor = NULL;
322: }
323:
324: /*
325: * <S-Tab> works like CTRL-P (unless 'wc' is <S-Tab>).
326: */
327: if (c != p_wc && c == K_S_TAB)
328: c = Ctrl('P');
329:
330: /* free expanded names when finished walking through matches */
331: if (cmd_numfiles != -1 && !(c == p_wc && KeyTyped) && c != Ctrl('N') &&
332: c != Ctrl('P') && c != Ctrl('A') && c != Ctrl('L'))
333: (void)ExpandOne(NULL, NULL, 0, WILD_FREE);
334:
335: #ifdef DIGRAPHS
336: c = do_digraph(c);
337: #endif
338:
339: if (c == '\n' || c == '\r' || (c == ESC && (!KeyTyped ||
340: vim_strchr(p_cpo, CPO_ESC) != NULL)))
341: {
342: if (ccheck_abbr(c + ABBR_OFF))
343: goto cmdline_changed;
344: outchar('\r'); /* show that we got the return */
345: screen_cur_col = 0;
346: flushbuf();
347: break;
348: }
349:
350: /* hitting <ESC> twice means: abandon command line */
351: /* wildcard expansion is only done when the key is really typed,
352: * not when it comes from a macro */
353: if (c == p_wc && !gotesc && KeyTyped)
354: {
355: if (cmd_numfiles > 0) /* typed p_wc twice */
356: i = nextwild(WILD_NEXT);
357: else /* typed p_wc first time */
358: i = nextwild(WILD_EXPAND_KEEP);
359: if (c == ESC)
360: gotesc = TRUE;
361: if (i)
362: goto cmdline_changed;
363: }
364: gotesc = FALSE;
365:
366: if (c == NUL || c == K_ZERO) /* NUL is stored as NL */
367: c = NL;
368:
369: do_abbr = TRUE; /* default: check for abbreviation */
370: switch (c)
371: {
372: case K_BS:
373: case Ctrl('H'):
374: case K_DEL:
375: case Ctrl('W'):
376: /*
377: * delete current character is the same as backspace on next
378: * character, except at end of line
379: */
380: if (c == K_DEL && cmdpos != cmdlen)
381: ++cmdpos;
382: if (cmdpos > 0)
383: {
384: j = cmdpos;
385: if (c == Ctrl('W'))
386: {
387: while (cmdpos && vim_isspace(cmdbuff[cmdpos - 1]))
388: --cmdpos;
389: i = iswordchar(cmdbuff[cmdpos - 1]);
390: while (cmdpos && !vim_isspace(cmdbuff[cmdpos - 1]) &&
391: iswordchar(cmdbuff[cmdpos - 1]) == i)
392: --cmdpos;
393: }
394: else
395: --cmdpos;
396: cmdlen -= j - cmdpos;
397: i = cmdpos;
398: while (i < cmdlen)
399: cmdbuff[i++] = cmdbuff[j++];
400: redrawcmd();
401: }
402: else if (cmdlen == 0 && c != Ctrl('W'))
403: {
404: vim_free(cmdbuff); /* no commandline to return */
405: cmdbuff = NULL;
406: msg_pos(-1, 0);
407: msg_outchar(' '); /* delete ':' */
408: redraw_cmdline = TRUE;
409: goto returncmd; /* back to cmd mode */
410: }
411: goto cmdline_changed;
412:
413: case K_INS:
414: overstrike = !overstrike;
415: /* should change shape of cursor */
416: goto cmdline_not_changed;
417:
418: /* case '@': only in very old vi */
419: case Ctrl('U'):
420: cmdpos = 0;
421: cmdlen = 0;
422: cmdspos = 1;
423: redrawcmd();
424: goto cmdline_changed;
425:
426: case ESC: /* get here if p_wc != ESC or when ESC typed twice */
427: case Ctrl('C'):
428: gotesc = TRUE; /* will free cmdbuff after putting it in
429: history */
430: goto returncmd; /* back to cmd mode */
431:
432: case Ctrl('R'): /* insert register */
433: putcmdline('"');
434: ++no_mapping;
435: c = vgetc();
436: --no_mapping;
437: if (c != ESC) /* use ESC to cancel inserting register */
438: cmdline_paste(c);
439: redrawcmd();
440: goto cmdline_changed;
441:
442: case Ctrl('D'):
443: {
444: if (showmatches(cmdbuff) == FAIL)
445: break; /* Use ^D as normal char instead */
446:
447: redrawcmd();
448: continue; /* don't do incremental search now */
449: }
450:
451: case K_RIGHT:
452: case K_S_RIGHT:
453: do
454: {
455: if (cmdpos >= cmdlen)
456: break;
457: cmdspos += charsize(cmdbuff[cmdpos]);
458: ++cmdpos;
459: }
460: while (c == K_S_RIGHT && cmdbuff[cmdpos] != ' ');
461: goto cmdline_not_changed;
462:
463: case K_LEFT:
464: case K_S_LEFT:
465: do
466: {
467: if (cmdpos <= 0)
468: break;
469: --cmdpos;
470: cmdspos -= charsize(cmdbuff[cmdpos]);
471: }
472: while (c == K_S_LEFT && cmdbuff[cmdpos - 1] != ' ');
473: goto cmdline_not_changed;
474:
475: #ifdef USE_MOUSE
476: case K_MIDDLEDRAG:
477: case K_MIDDLERELEASE:
478: case K_IGNORE:
479: goto cmdline_not_changed; /* Ignore mouse */
480:
481: case K_MIDDLEMOUSE:
482: # ifdef USE_GUI
483: /* When GUI is active, also paste when 'mouse' is empty */
484: if (!gui.in_use)
485: # endif
486: if (!mouse_has(MOUSE_COMMAND))
487: goto cmdline_not_changed; /* Ignore mouse */
488: # ifdef USE_GUI
489: if (gui.in_use && yankbuffer == 0)
490: cmdline_paste('*');
491: else
492: # endif
493: cmdline_paste(yankbuffer);
494: redrawcmd();
495: goto cmdline_changed;
496:
497: case K_LEFTDRAG:
498: case K_LEFTRELEASE:
499: case K_RIGHTDRAG:
500: case K_RIGHTRELEASE:
501: if (ignore_drag_release)
502: goto cmdline_not_changed;
503: /* FALLTHROUGH */
504: case K_LEFTMOUSE:
505: case K_RIGHTMOUSE:
506: if (c == K_LEFTRELEASE || c == K_RIGHTRELEASE)
507: ignore_drag_release = TRUE;
508: else
509: ignore_drag_release = FALSE;
510: # ifdef USE_GUI
511: /* When GUI is active, also move when 'mouse' is empty */
512: if (!gui.in_use)
513: # endif
514: if (!mouse_has(MOUSE_COMMAND))
515: goto cmdline_not_changed; /* Ignore mouse */
516: cmdspos = 1;
517: for (cmdpos = 0; cmdpos < cmdlen; ++cmdpos)
518: {
519: i = charsize(cmdbuff[cmdpos]);
520: if (mouse_row <= cmdline_row + cmdspos / Columns &&
521: mouse_col < cmdspos % Columns + i)
522: break;
523: cmdspos += i;
524: }
525: goto cmdline_not_changed;
526: #endif /* USE_MOUSE */
527:
528: #ifdef USE_GUI
529: case K_SCROLLBAR:
530: if (!msg_scrolled)
531: {
532: gui_do_scroll();
533: redrawcmd();
534: }
535: goto cmdline_not_changed;
536:
537: case K_HORIZ_SCROLLBAR:
538: if (!msg_scrolled)
539: {
540: gui_do_horiz_scroll();
541: redrawcmd();
542: }
543: goto cmdline_not_changed;
544: #endif
545:
546: case Ctrl('B'): /* begin of command line */
547: case K_HOME:
548: cmdpos = 0;
549: cmdspos = 1;
550: goto cmdline_not_changed;
551:
552: case Ctrl('E'): /* end of command line */
553: case K_END:
554: cmdpos = cmdlen;
555: cmdbuff[cmdlen] = NUL;
556: cmdspos = strsize(cmdbuff) + 1;
557: goto cmdline_not_changed;
558:
559: case Ctrl('A'): /* all matches */
560: if (!nextwild(WILD_ALL))
561: break;
562: goto cmdline_changed;
563:
564: case Ctrl('L'): /* longest common part */
565: if (!nextwild(WILD_LONGEST))
566: break;
567: goto cmdline_changed;
568:
569: case Ctrl('N'): /* next match */
570: case Ctrl('P'): /* previous match */
571: if (cmd_numfiles > 0)
572: {
573: if (!nextwild((c == Ctrl('P')) ? WILD_PREV : WILD_NEXT))
574: break;
575: goto cmdline_changed;
576: }
577:
578: case K_UP:
579: case K_DOWN:
580: case K_S_UP:
581: case K_S_DOWN:
582: case K_PAGEUP:
583: case K_PAGEDOWN:
584: if (hislen == 0) /* no history */
585: goto cmdline_not_changed;
586:
587: i = hiscnt;
588:
589: /* save current command string so it can be restored later */
590: cmdbuff[cmdpos] = NUL;
591: if (lookfor == NULL && (lookfor = strsave(cmdbuff)) == NULL)
592: goto cmdline_not_changed;
593:
594: j = STRLEN(lookfor);
595: for (;;)
596: {
597: /* one step backwards */
598: if (c == K_UP || c == K_S_UP || c == Ctrl('P') ||
599: c == K_PAGEUP)
600: {
601: if (hiscnt == hislen) /* first time */
602: hiscnt = hisidx[histype];
603: else if (hiscnt == 0 && hisidx[histype] != hislen - 1)
604: hiscnt = hislen - 1;
605: else if (hiscnt != hisidx[histype] + 1)
606: --hiscnt;
607: else /* at top of list */
608: {
609: hiscnt = i;
610: break;
611: }
612: }
613: else /* one step forwards */
614: {
615: /* on last entry, clear the line */
616: if (hiscnt == hisidx[histype])
617: {
618: hiscnt = hislen;
619: break;
620: }
621: /* not on a history line, nothing to do */
622: if (hiscnt == hislen)
623: break;
624: if (hiscnt == hislen - 1) /* wrap around */
625: hiscnt = 0;
626: else
627: ++hiscnt;
628: }
629: if (hiscnt < 0 || history[histype][hiscnt] == NULL)
630: {
631: hiscnt = i;
632: break;
633: }
634: if ((c != K_UP && c != K_DOWN) || hiscnt == i ||
635: STRNCMP(history[histype][hiscnt],
636: lookfor, (size_t)j) == 0)
637: break;
638: }
639:
640: if (hiscnt != i) /* jumped to other entry */
641: {
642: vim_free(cmdbuff);
643: if (hiscnt == hislen)
644: p = lookfor; /* back to the old one */
645: else
646: p = history[histype][hiscnt];
647:
648: alloc_cmdbuff((int)STRLEN(p));
649: if (cmdbuff == NULL)
650: goto returncmd;
651: STRCPY(cmdbuff, p);
652:
653: cmdpos = cmdlen = STRLEN(cmdbuff);
654: redrawcmd();
655: goto cmdline_changed;
656: }
657: beep_flush();
658: goto cmdline_not_changed;
659:
660: case Ctrl('V'):
661: case Ctrl('Q'):
662: #ifdef USE_MOUSE
663: ignore_drag_release = TRUE;
664: #endif
665: putcmdline('^');
666: c = get_literal(); /* get next (two) character(s) */
667: do_abbr = FALSE; /* don't do abbreviation now */
668: break;
669:
670: #ifdef DIGRAPHS
671: case Ctrl('K'):
672: #ifdef USE_MOUSE
673: ignore_drag_release = TRUE;
674: #endif
675: putcmdline('?');
676: ++no_mapping;
677: ++allow_keys;
678: c = vgetc();
679: --no_mapping;
680: --allow_keys;
681: if (c != ESC) /* ESC cancels CTRL-K */
682: {
683: if (IS_SPECIAL(c)) /* insert special key code */
684: break;
685: if (charsize(c) == 1)
686: putcmdline(c);
687: ++no_mapping;
688: ++allow_keys;
689: cc = vgetc();
690: --no_mapping;
691: --allow_keys;
692: if (cc != ESC) /* ESC cancels CTRL-K */
693: {
694: c = getdigraph(c, cc, TRUE);
695: break;
696: }
697: }
698: redrawcmd();
699: goto cmdline_not_changed;
700: #endif /* DIGRAPHS */
701:
702: #ifdef RIGHTLEFT
703: case Ctrl('_'): /* CTRL-_: switch language mode */
704: cmd_hkmap = !cmd_hkmap;
705: goto cmdline_not_changed;
706: #endif
707:
708: default:
709: /*
710: * Normal character with no special meaning. Just set mod_mask
711: * to 0x0 so that typing Shift-Space in the GUI doesn't enter
712: * the string <S-Space>. This should only happen after ^V.
713: */
714: if (!IS_SPECIAL(c))
715: mod_mask = 0x0;
716: break;
717: }
718:
719: /* we come here if we have a normal character */
720:
721: if (do_abbr && (IS_SPECIAL(c) || !iswordchar(c)) && ccheck_abbr(c))
722: goto cmdline_changed;
723:
724: /*
725: * put the character in the command line
726: */
727: if (IS_SPECIAL(c) || mod_mask != 0x0)
728: put_on_cmdline(get_special_key_name(c, mod_mask), -1, TRUE);
729: else
730: {
731: IObuff[0] = c;
732: put_on_cmdline(IObuff, 1, TRUE);
733: }
734: goto cmdline_changed;
735:
736: /*
737: * This part implements incremental searches for "/" and "?"
738: * Jump to cmdline_not_changed when a character has been read but the command
739: * line did not change. Then we only search and redraw if something changed in
740: * the past.
741: * Jump to cmdline_changed when the command line did change.
742: * (Sorry for the goto's, I know it is ugly).
743: */
744: cmdline_not_changed:
745: if (!incsearch_postponed)
746: continue;
747:
748: cmdline_changed:
749: if (p_is && (firstc == '/' || firstc == '?'))
750: {
751: /* if there is a character waiting, search and redraw later */
752: if (char_avail())
753: {
754: incsearch_postponed = TRUE;
755: continue;
756: }
757: incsearch_postponed = FALSE;
758: curwin->w_cursor = old_cursor; /* start at old position */
759:
760: /* If there is no command line, don't do anything */
761: if (cmdlen == 0)
762: i = 0;
763: else
764: {
765: cmdbuff[cmdlen] = NUL;
766: emsg_off = TRUE; /* So it doesn't beep if bad expr */
767: i = do_search(firstc, cmdbuff, count,
768: SEARCH_KEEP + SEARCH_OPT + SEARCH_NOOF);
769: emsg_off = FALSE;
770: }
771: if (i)
772: {
773: highlight_match = TRUE; /* highlight position */
774: cursupdate();
775: }
776: else
777: {
778: highlight_match = FALSE; /* don't highlight */
779: /* vim_beep(); */ /* even beeps when invalid expr, e.g. "[" */
780: }
781: updateScreen(NOT_VALID);
782: redrawcmdline();
783: did_incsearch = TRUE;
784: }
785: }
786:
787: returncmd:
788: if (did_incsearch)
789: {
790: curwin->w_cursor = old_cursor;
791: curwin->w_curswant = old_curswant;
792: highlight_match = FALSE;
793: redraw_later(NOT_VALID);
794: }
795: if (cmdbuff != NULL)
796: {
797: /*
798: * Put line in history buffer (":" only when it was typed).
799: */
800: cmdbuff[cmdlen] = NUL;
801: if (cmdlen != 0 && (some_key_typed || firstc != ':'))
802: {
803: add_to_history(histype, cmdbuff);
804: if (firstc == ':')
805: {
806: vim_free(new_last_cmdline);
807: new_last_cmdline = strsave(cmdbuff);
808: }
809: }
810:
811: if (gotesc) /* abandon command line */
812: {
813: vim_free(cmdbuff);
814: cmdbuff = NULL;
815: MSG("");
816: redraw_cmdline = TRUE;
817: }
818: }
819:
820: /*
821: * If the screen was shifted up, redraw the whole screen (later).
822: * If the line is too long, clear it, so ruler and shown command do
823: * not get printed in the middle of it.
824: */
825: msg_check();
826: msg_scroll = save_msg_scroll;
827: State = NORMAL;
828: #ifdef USE_MOUSE
829: setmouse();
830: #endif
831: return cmdbuff;
832: }
833:
834: /*
835: * Put the given string, of the given length, onto the command line.
836: * If len is -1, then STRLEN() is used to calculate the length.
837: * If 'redraw' is TRUE then the new part of the command line, and the remaining
838: * part will be redrawn, otherwise it will not. If this function is called
839: * twice in a row, then 'redraw' should be FALSE and redrawcmd() should be
840: * called afterwards.
841: */
842: int
843: put_on_cmdline(str, len, redraw)
844: char_u *str;
845: int len;
846: int redraw;
847: {
848: int i;
849:
850: if (len < 0)
851: len = STRLEN(str);
852:
853: /* Check if cmdbuff needs to be longer */
854: if (cmdlen + len + 1 >= cmdbufflen)
855: i = realloc_cmdbuff(cmdlen + len);
856: else
857: i = OK;
858: if (i == OK)
859: {
860: if (!overstrike)
861: {
862: vim_memmove(cmdbuff + cmdpos + len, cmdbuff + cmdpos,
863: (size_t)(cmdlen - cmdpos));
864: cmdlen += len;
865: }
866: else if (cmdpos + len > cmdlen)
867: cmdlen = cmdpos + len;
868: vim_memmove(cmdbuff + cmdpos, str, (size_t)len);
869: if (redraw)
870: msg_outtrans_len(cmdbuff + cmdpos, cmdlen - cmdpos);
871: cmdpos += len;
872: while (len--)
873: cmdspos += charsize(str[len]);
874: }
875: if (redraw)
876: msg_check();
877: return i;
878: }
879:
880: void
881: alloc_cmdbuff(len)
882: int len;
883: {
884: /*
885: * give some extra space to avoid having to allocate all the time
886: */
887: if (len < 80)
888: len = 100;
889: else
890: len += 20;
891:
892: cmdbuff = alloc(len); /* caller should check for out of memory */
893: cmdbufflen = len;
894: }
895:
896: /*
897: * Re-allocate the command line to length len + something extra.
898: * return FAIL for failure, OK otherwise
899: */
900: int
901: realloc_cmdbuff(len)
902: int len;
903: {
904: char_u *p;
905:
906: p = cmdbuff;
907: alloc_cmdbuff(len); /* will get some more */
908: if (cmdbuff == NULL) /* out of memory */
909: {
910: cmdbuff = p; /* keep the old one */
911: return FAIL;
912: }
913: vim_memmove(cmdbuff, p, (size_t)cmdlen);
914: vim_free(p);
915: return OK;
916: }
917:
918: /*
919: * put a character on the command line.
920: * Used for CTRL-V and CTRL-K
921: */
922: static void
923: putcmdline(c)
924: int c;
925: {
926: char_u buf[1];
927:
928: buf[0] = c;
929: msg_outtrans_len(buf, 1);
930: msg_outtrans_len(cmdbuff + cmdpos, cmdlen - cmdpos);
931: cursorcmd();
932: }
933:
934: /*
935: * this fuction is called when the screen size changes and with incremental
936: * search
937: */
938: void
939: redrawcmdline()
940: {
941: msg_scrolled = 0;
942: need_wait_return = FALSE;
943: compute_cmdrow();
944: redrawcmd();
945: cursorcmd();
946: }
947:
948: void
949: compute_cmdrow()
950: {
951: cmdline_row = lastwin->w_winpos + lastwin->w_height +
952: lastwin->w_status_height;
953: }
954:
955: /*
956: * Redraw what is currently on the command line.
957: */
958: static void
959: redrawcmd()
960: {
961: register int i;
962:
963: msg_start();
964: msg_outchar(cmdfirstc);
965: msg_outtrans_len(cmdbuff, cmdlen);
966: msg_clr_eos();
967:
968: cmdspos = 1;
969: for (i = 0; i < cmdlen && i < cmdpos; ++i)
970: cmdspos += charsize(cmdbuff[i]);
971: /*
972: * An emsg() before may have set msg_scroll and need_sleep. These are used
973: * in normal mode, in cmdline mode we can reset them now.
974: */
975: msg_scroll = FALSE; /* next message overwrites cmdline */
976: #ifdef SLEEP_IN_EMSG
977: need_sleep = FALSE; /* don't sleep */
978: #endif
979: }
980:
981: static void
982: cursorcmd()
983: {
984: msg_pos(cmdline_row + (cmdspos / (int)Columns), cmdspos % (int)Columns);
985: windgoto(msg_row, msg_col);
986: }
987:
988: /*
989: * Check the word in front of the cursor for an abbreviation.
990: * Called when the non-id character "c" has been entered.
991: * When an abbreviation is recognized it is removed from the text with
992: * backspaces and the replacement string is inserted, followed by "c".
993: */
994: static int
995: ccheck_abbr(c)
996: int c;
997: {
998: if (p_paste || no_abbr) /* no abbreviations or in paste mode */
999: return FALSE;
1000:
1001: return check_abbr(c, cmdbuff, cmdpos, 0);
1002: }
1003:
1004: /*
1005: * do_cmdline(): execute an Ex command line
1006: *
1007: * 1. If no line given, get one.
1008: * 2. Split up in parts separated with '|'.
1009: *
1010: * This function may be called recursively!
1011: *
1012: * If 'sourcing' is TRUE, the command will be included in the error message.
1013: * If 'repeating' is TRUE, there is no wait_return() and friends.
1014: *
1015: * return FAIL if commandline could not be executed, OK otherwise
1016: */
1017: int
1018: do_cmdline(cmdline, sourcing, repeating)
1019: char_u *cmdline;
1020: int sourcing;
1021: int repeating;
1022: {
1023: int cmdlinelen;
1024: char_u *nextcomm;
1025: static int recursive = 0; /* recursive depth */
1026: int got_cmdline = FALSE; /* TRUE when cmdline was typed */
1027: int msg_didout_before_start;
1028:
1029: /*
1030: * 1. If no line given: Get a line in cmdbuff.
1031: * If a line is given: Copy it into cmdbuff.
1032: * After this we don't use cmdbuff but cmdline, because of recursiveness
1033: */
1034: if (cmdline == NULL)
1035: {
1036: if ((cmdline = getcmdline(':', 1L)) == NULL)
1037: {
1038: /* don't call wait_return for aborted command line */
1039: need_wait_return = FALSE;
1040: return FAIL;
1041: }
1042: got_cmdline = TRUE;
1043: }
1044: else
1045: {
1046: /* Make a copy of the command so we can mess with it. */
1047: alloc_cmdbuff((int)STRLEN(cmdline));
1048: if (cmdbuff == NULL)
1049: return FAIL;
1050: STRCPY(cmdbuff, cmdline);
1051: cmdline = cmdbuff;
1052: }
1053: cmdlinelen = cmdbufflen; /* we need to copy it for recursiveness */
1054:
1055: /*
1056: * All output from the commands is put below each other, without waiting for a
1057: * return. Don't do this when executing commands from a script or when being
1058: * called recursive (e.g. for ":e +command file").
1059: */
1060: msg_didout_before_start = msg_didout;
1061: if (!repeating && !recursive)
1062: {
1063: msg_didany = FALSE; /* no output yet */
1064: msg_start();
1065: msg_scroll = TRUE; /* put messages below each other */
1066: #ifdef SLEEP_IN_EMSG
1067: ++dont_sleep; /* don't sleep in emsg() */
1068: #endif
1069: ++no_wait_return; /* dont wait for return until finished */
1070: ++RedrawingDisabled;
1071: }
1072:
1073: /*
1074: * 2. Loop for each '|' separated command.
1075: * do_one_cmd will set nextcomm to NULL if there is no trailing '|'.
1076: * cmdline and cmdlinelen may change, e.g. for '%' and '#' expansion.
1077: */
1078: ++recursive;
1079: for (;;)
1080: {
1081: nextcomm = do_one_cmd(&cmdline, &cmdlinelen, sourcing);
1082: if (nextcomm == NULL)
1083: break;
1084: STRCPY(cmdline, nextcomm);
1085: }
1086: --recursive;
1087: vim_free(cmdline);
1088:
1089: /*
1090: * If there was too much output to fit on the command line, ask the user to
1091: * hit return before redrawing the screen. With the ":global" command we do
1092: * this only once after the command is finished.
1093: */
1094: if (!repeating && !recursive)
1095: {
1096: --RedrawingDisabled;
1097: #ifdef SLEEP_IN_EMSG
1098: --dont_sleep;
1099: #endif
1100: --no_wait_return;
1101: msg_scroll = FALSE;
1102: if (need_wait_return || (msg_check() && !dont_wait_return))
1103: {
1104: /*
1105: * The msg_start() above clears msg_didout. The wait_return we do
1106: * here should not overwrite the command that may be shown before
1107: * doing that.
1108: */
1109: msg_didout = msg_didout_before_start;
1110: wait_return(FALSE);
1111: }
1112: }
1113:
1114: /*
1115: * If the command was typed, remember it for register :
1116: * Do this AFTER executing the command to make :@: work.
1117: */
1118: if (got_cmdline && new_last_cmdline != NULL)
1119: {
1120: vim_free(last_cmdline);
1121: last_cmdline = new_last_cmdline;
1122: new_last_cmdline = NULL;
1123: }
1124: return OK;
1125: }
1126:
1127: static char *(make_cmd_chars[6]) =
1128: { " \164\145a",
1129: "\207\171\204\170\060\175\171\174\173\117\032",
1130: " c\157\146\146e\145",
1131: "\200\174\165\161\203\165\060\171\176\203\165\202\204\060\163\177\171\176\060\204\177\060\202\205\176\060\175\161\173\165\032",
1132: " \164o\141\163t",
1133: "\136\137\122\137\124\151\060\165\210\200\165\163\204\203\060\204\170\165\060\143\200\161\176\171\203\170\060\171\176\201\205\171\203\171\204\171\177\176\061\032"
1134: };
1135:
1136: /*
1137: * Execute one Ex command.
1138: *
1139: * If 'sourcing' is TRUE, the command will be included in the error message.
1140: *
1141: * 2. skip comment lines and leading space
1142: * 3. parse range
1143: * 4. parse command
1144: * 5. parse arguments
1145: * 6. switch on command name
1146: *
1147: * This function may be called recursively!
1148: */
1149: static char_u *
1150: do_one_cmd(cmdlinep, cmdlinelenp, sourcing)
1151: char_u **cmdlinep;
1152: int *cmdlinelenp;
1153: int sourcing;
1154: {
1155: char_u *p;
1156: char_u *q;
1157: char_u *s;
1158: char_u *cmd, *arg;
1159: char_u *do_ecmd_cmd = NULL; /* +command for do_ecmd() */
1160: linenr_t do_ecmd_lnum = 0; /* lnum file for do_ecmd() */
1161: int i = 0; /* init to shut up gcc */
1162: int len;
1163: int cmdidx;
1164: long argt;
1165: register linenr_t lnum;
1166: long n = 0; /* init to shut up gcc */
1167: int addr_count; /* number of address specs */
1168: FPOS pos;
1169: int append = FALSE; /* write with append */
1170: int usefilter = FALSE; /* no read/write but filter */
1171: char_u *nextcomm = NULL; /* no next command yet */
1172: int amount = 0; /* for ":>"; init for gcc */
1173: char_u *errormsg = NULL; /* error message */
1174: WIN *old_curwin = NULL; /* init for GCC */
1175:
1176: /* when not editing the last file :q has to be typed twice */
1177: if (quitmore)
1178: --quitmore;
1179: did_emsg = FALSE; /* will be set to TRUE when emsg() used, in which
1180: * case we set nextcomm to NULL to cancel the
1181: * whole command line */
1182: /*
1183: * 2. skip comment lines and leading space and colons
1184: */
1185: for (cmd = *cmdlinep; vim_strchr((char_u *)" \t:", *cmd) != NULL; cmd++)
1186: ;
1187:
1188: if (*cmd == '"' || *cmd == NUL) /* ignore comment and empty lines */
1189: goto doend;
1190:
1191: /*
1192: * 3. parse a range specifier of the form: addr [,addr] [;addr] ..
1193: *
1194: * where 'addr' is:
1195: *
1196: * % (entire file)
1197: * $ [+-NUM]
1198: * 'x [+-NUM] (where x denotes a currently defined mark)
1199: * . [+-NUM]
1200: * [+-NUM]..
1201: * NUM
1202: *
1203: * The cmd pointer is updated to point to the first character following the
1204: * range spec. If an initial address is found, but no second, the upper bound
1205: * is equal to the lower.
1206: */
1207:
1208: addr_count = 0;
1209: --cmd;
1210: do
1211: {
1212: line1 = line2;
1213: line2 = curwin->w_cursor.lnum; /* default is current line number */
1214: cmd = skipwhite(cmd + 1); /* skip ',' or ';' and following ' ' */
1215: lnum = get_address(&cmd);
1216: if (cmd == NULL) /* error detected */
1217: goto doend;
1218: if (lnum == MAXLNUM)
1219: {
1220: if (*cmd == '%') /* '%' - all lines */
1221: {
1222: ++cmd;
1223: line1 = 1;
1224: line2 = curbuf->b_ml.ml_line_count;
1225: ++addr_count;
1226: }
1227: else if (*cmd == '*') /* '*' - visual area */
1228: {
1229: FPOS *fp;
1230:
1231: ++cmd;
1232: fp = getmark('<', FALSE);
1233: if (check_mark(fp) == FAIL)
1234: goto doend;
1235: line1 = fp->lnum;
1236: fp = getmark('>', FALSE);
1237: if (check_mark(fp) == FAIL)
1238: goto doend;
1239: line2 = fp->lnum;
1240: ++addr_count;
1241: }
1242: }
1243: else
1244: line2 = lnum;
1245: addr_count++;
1246:
1247: if (*cmd == ';')
1248: {
1249: if (line2 == 0)
1250: curwin->w_cursor.lnum = 1;
1251: else
1252: curwin->w_cursor.lnum = line2;
1253: }
1254: } while (*cmd == ',' || *cmd == ';');
1255:
1256: /* One address given: set start and end lines */
1257: if (addr_count == 1)
1258: {
1259: line1 = line2;
1260: /* ... but only implicit: really no address given */
1261: if (lnum == MAXLNUM)
1262: addr_count = 0;
1263: }
1264:
1265: /*
1266: * 4. parse command
1267: */
1268:
1269: /*
1270: * Skip ':' and any white space
1271: */
1272: cmd = skipwhite(cmd);
1273: if (*cmd == ':')
1274: cmd = skipwhite(cmd + 1);
1275:
1276: /*
1277: * If we got a line, but no command, then go to the line.
1278: * If we find a '|' or '\n' we set nextcomm.
1279: */
1280: if (*cmd == NUL || *cmd == '"' ||
1281: ((*cmd == '|' || *cmd == '\n') &&
1282: (nextcomm = cmd + 1) != NULL)) /* just an assignment */
1283: {
1284: /*
1285: * strange vi behaviour:
1286: * ":3" jumps to line 3
1287: * ":3|..." prints line 3
1288: * ":|" prints current line
1289: */
1290: if (*cmd == '|')
1291: {
1292: cmdidx = CMD_print;
1293: goto cmdswitch; /* UGLY goto */
1294: }
1295: if (addr_count != 0)
1296: {
1297: if (line2 == 0)
1298: curwin->w_cursor.lnum = 1;
1299: else if (line2 > curbuf->b_ml.ml_line_count)
1300: curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
1301: else
1302: curwin->w_cursor.lnum = line2;
1303: beginline(MAYBE);
1304: /* This causes problems for ":234", since displaying is disabled
1305: * here */
1306: /* cursupdate(); */
1307: }
1308: goto doend;
1309: }
1310:
1311: /*
1312: * Isolate the command and search for it in the command table.
1313: * Exeptions:
1314: * - the 'k' command can directly be followed by any character.
1315: * - the 's' command can be followed directly by 'c', 'g' or 'r'
1316: * but :sre[wind] is another command.
1317: */
1318: if (*cmd == 'k')
1319: {
1320: cmdidx = CMD_k;
1321: p = cmd + 1;
1322: }
1323: else if (*cmd == 's' && vim_strchr((char_u *)"cgr", cmd[1]) != NULL &&
1324: STRNCMP("sre", cmd, (size_t)3) != 0)
1325: {
1326: cmdidx = CMD_substitute;
1327: p = cmd + 1;
1328: }
1329: else
1330: {
1331: p = cmd;
1332: while (isalpha(*p))
1333: ++p;
1334: /* check for non-alpha command */
1335: if (p == cmd && vim_strchr((char_u *)"@!=><&~#", *p) != NULL)
1336: ++p;
1337: i = (int)(p - cmd);
1338:
1339: for (cmdidx = 0; cmdidx < CMD_SIZE; ++cmdidx)
1340: if (STRNCMP(cmdnames[cmdidx].cmd_name, (char *)cmd, (size_t)i) == 0)
1341: break;
1342: if (i == 0 || cmdidx == CMD_SIZE)
1343: {
1344: STRCPY(IObuff, "Not an editor command");
1345: if (!sourcing)
1346: {
1347: STRCAT(IObuff, ": ");
1348: STRNCAT(IObuff, *cmdlinep, 40);
1349: }
1350: errormsg = IObuff;
1351: goto doend;
1352: }
1353: }
1354:
1355: if (*p == '!') /* forced commands */
1356: {
1357: ++p;
1358: forceit = TRUE;
1359: }
1360: else
1361: forceit = FALSE;
1362:
1363: /*
1364: * 5. parse arguments
1365: */
1366: argt = cmdnames[cmdidx].cmd_argt;
1367:
1368: if (!(argt & RANGE) && addr_count) /* no range allowed */
1369: {
1370: errormsg = e_norange;
1371: goto doend;
1372: }
1373:
1374: if (!(argt & BANG) && forceit) /* no <!> allowed */
1375: {
1376: errormsg = e_nobang;
1377: goto doend;
1378: }
1379:
1380: /*
1381: * If the range is backwards, ask for confirmation and, if given, swap
1382: * line1 & line2 so it's forwards again.
1383: * When global command is busy, don't ask, will fail below.
1384: */
1385: if (!global_busy && line1 > line2)
1386: {
1387: if (sourcing)
1388: {
1389: errormsg = (char_u *)"Backwards range given";
1390: goto doend;
1391: }
1392: else if (ask_yesno((char_u *)"Backwards range given, OK to swap", FALSE) != 'y')
1393: goto doend;
1394: lnum = line1;
1395: line1 = line2;
1396: line2 = lnum;
1397: }
1398: /*
1399: * don't complain about the range if it is not used
1400: * (could happen if line_count is accidently set to 0)
1401: */
1402: if (line1 < 0 || line2 < 0 || line1 > line2 || ((argt & RANGE) &&
1403: !(argt & NOTADR) && line2 > curbuf->b_ml.ml_line_count))
1404: {
1405: errormsg = e_invrange;
1406: goto doend;
1407: }
1408:
1409: if ((argt & NOTADR) && addr_count == 0) /* default is 1, not cursor */
1410: line2 = 1;
1411:
1412: if (!(argt & ZEROR)) /* zero in range not allowed */
1413: {
1414: if (line1 == 0)
1415: line1 = 1;
1416: if (line2 == 0)
1417: line2 = 1;
1418: }
1419:
1420: /*
1421: * for the :make command we insert the 'makeprg' option here,
1422: * so things like % get expanded
1423: */
1424: if (cmdidx == CMD_make)
1425: {
1426: alloc_cmdbuff((int)(STRLEN(p_mp) + STRLEN(p) + 2));
1427: if (cmdbuff == NULL) /* out of memory */
1428: goto doend;
1429: /*
1430: * Check for special command characters and echo them.
1431: */
1432: for (i = 0; i < 6; i += 2)
1433: if (!STRCMP(make_cmd_chars[i], p))
1434: for (s = (char_u *)(make_cmd_chars[i + 1]); *s; ++s)
1435: msg_outchar(*s - 16);
1436: STRCPY(cmdbuff, p_mp);
1437: STRCAT(cmdbuff, " ");
1438: STRCAT(cmdbuff, p);
1439: /* 'cmd' is not set here, because it is not used at CMD_make */
1440: vim_free(*cmdlinep);
1441: *cmdlinep = cmdbuff;
1442: *cmdlinelenp = cmdbufflen;
1443: p = cmdbuff;
1444: }
1445:
1446: /*
1447: * Skip to start of argument.
1448: * Don't do this for the ":!" command, because ":!! -l" needs the space.
1449: */
1450: if (cmdidx == CMD_bang)
1451: arg = p;
1452: else
1453: arg = skipwhite(p);
1454:
1455: if (cmdidx == CMD_write)
1456: {
1457: if (*arg == '>') /* append */
1458: {
1459: if (*++arg != '>') /* typed wrong */
1460: {
1461: errormsg = (char_u *)"Use w or w>>";
1462: goto doend;
1463: }
1464: arg = skipwhite(arg + 1);
1465: append = TRUE;
1466: }
1467: else if (*arg == '!') /* :w !filter */
1468: {
1469: ++arg;
1470: usefilter = TRUE;
1471: }
1472: }
1473:
1474: if (cmdidx == CMD_read)
1475: {
1476: if (forceit)
1477: {
1478: usefilter = TRUE; /* :r! filter if forceit */
1479: forceit = FALSE;
1480: }
1481: else if (*arg == '!') /* :r !filter */
1482: {
1483: ++arg;
1484: usefilter = TRUE;
1485: }
1486: }
1487:
1488: if (cmdidx == CMD_lshift || cmdidx == CMD_rshift)
1489: {
1490: amount = 1;
1491: while (*arg == *cmd) /* count number of '>' or '<' */
1492: {
1493: ++arg;
1494: ++amount;
1495: }
1496: arg = skipwhite(arg);
1497: }
1498:
1499: /*
1500: * Check for "+command" argument, before checking for next command.
1501: * Don't do this for ":read !cmd" and ":write !cmd".
1502: */
1503: if ((argt & EDITCMD) && !usefilter)
1504: do_ecmd_cmd = getargcmd(&arg);
1505:
1506: /*
1507: * Check for '|' to separate commands and '"' to start comments.
1508: * Don't do this for ":read !cmd" and ":write !cmd".
1509: */
1510: if ((argt & TRLBAR) && !usefilter)
1511: {
1512: for (p = arg; *p; ++p)
1513: {
1514: if (*p == Ctrl('V'))
1515: {
1516: if (argt & (USECTRLV | XFILE))
1517: ++p; /* skip CTRL-V and next char */
1518: else
1519: STRCPY(p, p + 1); /* remove CTRL-V and skip next char */
1520: if (*p == NUL) /* stop at NUL after CTRL-V */
1521: break;
1522: }
1523: else if ((*p == '"' && !(argt & NOTRLCOM)) ||
1524: *p == '|' || *p == '\n')
1525: {
1526: /*
1527: * We remove the '\' before the '|', unless USECTRLV is used
1528: * AND 'b' is present in 'cpoptions'.
1529: */
1530: if ((vim_strchr(p_cpo, CPO_BAR) == NULL ||
1531: !(argt & USECTRLV)) && *(p - 1) == '\\')
1532: {
1533: STRCPY(p - 1, p); /* remove the backslash */
1534: --p;
1535: }
1536: else
1537: {
1538: if (*p == '|' || *p == '\n')
1539: nextcomm = p + 1;
1540: *p = NUL;
1541: break;
1542: }
1543: }
1544: }
1545: if (!(argt & NOTRLCOM)) /* remove trailing spaces */
1546: del_trailing_spaces(arg);
1547: }
1548:
1549: /*
1550: * Check for <newline> to end a shell command.
1551: * Also do this for ":read !cmd" and ":write !cmd".
1552: */
1553: else if (cmdidx == CMD_bang || usefilter)
1554: {
1555: for (p = arg; *p; ++p)
1556: {
1557: if (*p == '\\' && p[1])
1558: ++p;
1559: else if (*p == '\n')
1560: {
1561: nextcomm = p + 1;
1562: *p = NUL;
1563: break;
1564: }
1565: }
1566: }
1567:
1568: if ((argt & DFLALL) && addr_count == 0)
1569: {
1570: line1 = 1;
1571: line2 = curbuf->b_ml.ml_line_count;
1572: }
1573:
1574: regname = 0;
1575: /* accept numbered register only when no count allowed (:put) */
1576: if ((argt & REGSTR) && *arg != NUL && is_yank_buffer(*arg, FALSE) &&
1577: !((argt & COUNT) && isdigit(*arg)))
1578: {
1579: regname = *arg;
1580: arg = skipwhite(arg + 1);
1581: }
1582:
1583: if ((argt & COUNT) && isdigit(*arg))
1584: {
1585: n = getdigits(&arg);
1586: arg = skipwhite(arg);
1587: if (n <= 0)
1588: {
1589: errormsg = e_zerocount;
1590: goto doend;
1591: }
1592: if (argt & NOTADR) /* e.g. :buffer 2, :sleep 3 */
1593: {
1594: line2 = n;
1595: if (addr_count == 0)
1596: addr_count = 1;
1597: }
1598: else
1599: {
1600: line1 = line2;
1601: line2 += n - 1;
1602: ++addr_count;
1603: /*
1604: * Be vi compatible: no error message for out of range.
1605: */
1606: if (line2 > curbuf->b_ml.ml_line_count)
1607: line2 = curbuf->b_ml.ml_line_count;
1608: }
1609: }
1610: /* no arguments allowed */
1611: if (!(argt & EXTRA) && *arg != NUL &&
1612: vim_strchr((char_u *)"|\"", *arg) == NULL)
1613: {
1614: errormsg = e_trailing;
1615: goto doend;
1616: }
1617:
1618: if ((argt & NEEDARG) && *arg == NUL)
1619: {
1620: errormsg = e_argreq;
1621: goto doend;
1622: }
1623:
1624: /*
1625: * change '%' to curbuf->b_filename
1626: * '#' to curwin->w_altfile
1627: * '<cword>' to word under the cursor
1628: * '<cWORD>' to WORD under the cursor
1629: * '<cfile>' to path name under the cursor
1630: * '<afile>' to file name for autocommand
1631: */
1632: if (argt & XFILE)
1633: {
1634: char_u *buf = NULL;
1635: int expand_wildcards; /* need to expand wildcards */
1636: int spec_idx;
1637: static char *(spec_str[]) =
1638: {
1639: "%",
1640: #define SPEC_PERC 0
1641: "#",
1642: #define SPEC_HASH 1
1643: "<cword>", /* cursor word */
1644: #define SPEC_CWORD 2
1645: "<cWORD>", /* cursor WORD */
1646: #define SPEC_CCWORD 3
1647: "<cfile>", /* cursor path name */
1648: #define SPEC_CFILE 4
1649: "<afile>" /* autocommand file name */
1650: #define SPEC_AFILE 5
1651: };
1652: #define SPEC_COUNT 6
1653:
1654: /*
1655: * Decide to expand wildcards *before* replacing '%', '#', etc. If
1656: * the file name contains a wildcard it should not cause expanding.
1657: * (it will be expanded anyway if there is a wildcard before replacing).
1658: */
1659: expand_wildcards = mch_has_wildcard(arg);
1660: for (p = arg; *p; ++p)
1661: {
1662: /*
1663: * Check if there is something to do.
1664: */
1665: for (spec_idx = 0; spec_idx < SPEC_COUNT; ++spec_idx)
1666: {
1667: n = strlen(spec_str[spec_idx]);
1668: if (STRNCMP(p, spec_str[spec_idx], n) == 0)
1669: break;
1670: }
1671: if (spec_idx == SPEC_COUNT) /* no match */
1672: continue;
1673:
1674: /*
1675: * Skip when preceded with a backslash "\%" and "\#".
1676: * Note: In "\\%" the % is also not recognized!
1677: */
1678: if (*(p - 1) == '\\')
1679: {
1680: --p;
1681: STRCPY(p, p + 1); /* remove escaped char */
1682: continue;
1683: }
1684:
1685: /*
1686: * word or WORD under cursor
1687: */
1688: if (spec_idx == SPEC_CWORD || spec_idx == SPEC_CCWORD)
1689: {
1690: len = find_ident_under_cursor(&q, spec_idx == SPEC_CWORD ?
1691: (FIND_IDENT|FIND_STRING) : FIND_STRING);
1692: if (len == 0)
1693: goto doend;
1694: }
1695:
1696: /*
1697: * '#': Alternate file name
1698: * '%': Current file name
1699: * File name under the cursor
1700: * File name for autocommand
1701: * and following modifiers
1702: */
1703: else
1704: {
1705: switch (spec_idx)
1706: {
1707: case SPEC_PERC: /* '%': current file */
1708: if (curbuf->b_filename == NULL)
1709: {
1710: errormsg = (char_u *)"No file name to substitute for '%'";
1711: goto doend;
1712: }
1713: q = curbuf->b_xfilename;
1714: break;
1715:
1716: case SPEC_HASH: /* '#' or "#99": alternate file */
1717: q = p + 1;
1718: i = (int)getdigits(&q);
1719: n = q - p; /* length of what we expand */
1720:
1721: if (buflist_name_nr(i, &q, &do_ecmd_lnum) ==
1722: FAIL)
1723: {
1724: errormsg = (char_u *)"no alternate filename to substitute for '#'";
1725: goto doend;
1726: }
1727: break;
1728:
1729: case SPEC_CFILE: /* file name under cursor */
1730: q = file_name_at_cursor(FNAME_MESS|FNAME_HYP);
1731: if (q == NULL)
1732: goto doend;
1733: buf = q;
1734: break;
1735:
1736: case SPEC_AFILE: /* file name for autocommand */
1737: q = autocmd_fname;
1738: if (q == NULL)
1739: {
1740: errormsg = (char_u *)"no autocommand filename to substitute for \"<afile>\"";
1741: goto doend;
1742: }
1743: break;
1744: }
1745:
1746: len = STRLEN(q); /* length of new string */
1747: if (p[n] == '<') /* remove the file name extension */
1748: {
1749: ++n;
1750: if ((s = vim_strrchr(q, '.')) != NULL && s >= gettail(q))
1751: len = s - q;
1752: }
1753: else
1754: {
1755: char_u *tail;
1756:
1757: /* ":p" - full path/filename */
1758: if (p[n] == ':' && p[n + 1] == 'p')
1759: {
1760: n += 2;
1761: s = FullName_save(q);
1762: vim_free(buf); /* free any allocated file name */
1763: if (s == NULL)
1764: goto doend;
1765: q = s;
1766: len = STRLEN(q);
1767: buf = q;
1768: }
1769:
1770: tail = gettail(q);
1771:
1772: /* ":h" - head, remove "/filename" */
1773: /* ":h" can be repeated */
1774: while (p[n] == ':' && p[n + 1] == 'h')
1775: {
1776: n += 2;
1777: while (tail > q && ispathsep(tail[-1]))
1778: --tail;
1779: len = tail - q;
1780: while (tail > q && !ispathsep(tail[-1]))
1781: --tail;
1782: }
1783:
1784: /* ":t" - tail, just the basename */
1785: if (p[n] == ':' && p[n + 1] == 't')
1786: {
1787: n += 2;
1788: len -= tail - q;
1789: q = tail;
1790: }
1791:
1792: /* ":e" - extension */
1793: /* ":e" can be repeated */
1794: /* ":r" - root, without extension */
1795: /* ":r" can be repeated */
1796: while (p[n] == ':' &&
1797: (p[n + 1] == 'e' || p[n + 1] == 'r'))
1798: {
1799: /* find a '.' in the tail:
1800: * - for second :e: before the current fname
1801: * - otherwise: The last '.'
1802: */
1803: if (p[n + 1] == 'e' && q > tail)
1804: s = q - 2;
1805: else
1806: s = q + len - 1;
1807: for ( ; s > tail; --s)
1808: if (s[0] == '.')
1809: break;
1810: if (p[n + 1] == 'e') /* :e */
1811: {
1812: if (s > tail)
1813: {
1814: len += q - (s + 1);
1815: q = s + 1;
1816: }
1817: else if (q <= tail)
1818: len = 0;
1819: }
1820: else /* :r */
1821: {
1822: if (s > tail) /* remove one extension */
1823: len = s - q;
1824: }
1825: n += 2;
1826: }
1827: }
1828:
1829: /* TODO - ":s/pat/foo/" - substitute */
1830: /* if (p[n] == ':' && p[n + 1] == 's') */
1831: }
1832:
1833: /*
1834: * The new command line is build in cmdbuff[].
1835: * First allocate it.
1836: */
1837: i = STRLEN(*cmdlinep) + len + 3;
1838: if (nextcomm)
1839: i += STRLEN(nextcomm); /* add space for next command */
1840: alloc_cmdbuff(i);
1841: if (cmdbuff == NULL) /* out of memory! */
1842: goto doend;
1843:
1844: i = p - *cmdlinep; /* length of part before c */
1845: vim_memmove(cmdbuff, *cmdlinep, (size_t)i);
1846: vim_memmove(cmdbuff + i, q, (size_t)len); /* append the string */
1847: i += len; /* remember the end of the string */
1848: STRCPY(cmdbuff + i, p + n); /* append what is after '#' or '%' */
1849: p = cmdbuff + i - 1; /* remember where to continue */
1850: vim_free(buf); /* free any allocated string */
1851:
1852: if (nextcomm) /* append next command */
1853: {
1854: i = STRLEN(cmdbuff) + 1;
1855: STRCPY(cmdbuff + i, nextcomm);
1856: nextcomm = cmdbuff + i;
1857: }
1858: cmd = cmdbuff + (cmd - *cmdlinep);
1859: arg = cmdbuff + (arg - *cmdlinep);
1860: vim_free(*cmdlinep);
1861: *cmdlinep = cmdbuff;
1862: *cmdlinelenp = cmdbufflen;
1863: }
1864:
1865: /*
1866: * One file argument: expand wildcards.
1867: * Don't do this with ":r !command" or ":w !command".
1868: */
1869: if ((argt & NOSPC) && !usefilter)
1870: {
1871: #if defined(UNIX)
1872: /*
1873: * Only for Unix we check for more than one file name.
1874: * For other systems spaces are considered to be part
1875: * of the file name.
1876: * Only check here if there is no wildcard, otherwise ExpandOne
1877: * will check for errors. This allows ":e `ls ve*.c`" on Unix.
1878: */
1879: if (!expand_wildcards)
1880: for (p = arg; *p; ++p)
1881: {
1882: /* skip escaped characters */
1883: if (p[1] && (*p == '\\' || *p == Ctrl('V')))
1884: ++p;
1885: else if (vim_iswhite(*p))
1886: {
1887: errormsg = (char_u *)"Only one file name allowed";
1888: goto doend;
1889: }
1890: }
1891: #endif
1892: /*
1893: * halve the number of backslashes (this is vi compatible)
1894: */
1895: backslash_halve(arg, expand_wildcards);
1896:
1897: if (expand_wildcards)
1898: {
1899: if ((p = ExpandOne(arg, NULL, WILD_LIST_NOTFOUND,
1900: WILD_EXPAND_FREE)) == NULL)
1901: goto doend;
1902: n = arg - *cmdlinep;
1903: i = STRLEN(p) + n;
1904: if (nextcomm)
1905: i += STRLEN(nextcomm);
1906: alloc_cmdbuff(i);
1907: if (cmdbuff != NULL)
1908: {
1909: STRNCPY(cmdbuff, *cmdlinep, n);
1910: STRCPY(cmdbuff + n, p);
1911: if (nextcomm) /* append next command */
1912: {
1913: i = STRLEN(cmdbuff) + 1;
1914: STRCPY(cmdbuff + i, nextcomm);
1915: nextcomm = cmdbuff + i;
1916: }
1917: cmd = cmdbuff + (cmd - *cmdlinep);
1918: arg = cmdbuff + n;
1919: vim_free(*cmdlinep);
1920: *cmdlinep = cmdbuff;
1921: *cmdlinelenp = cmdbufflen;
1922: }
1923: vim_free(p);
1924: }
1925: }
1926: }
1927:
1928: /*
1929: * Accept buffer name. Cannot be used at the same time with a buffer
1930: * number.
1931: */
1932: if ((argt & BUFNAME) && *arg && addr_count == 0)
1933: {
1934: /*
1935: * :bdelete and :bunload take several arguments, separated by spaces:
1936: * find next space (skipping over escaped characters).
1937: * The others take one argument: ignore trailing spaces.
1938: */
1939: if (cmdidx == CMD_bdelete || cmdidx == CMD_bunload)
1940: p = skiptowhite_esc(arg);
1941: else
1942: {
1943: p = arg + STRLEN(arg);
1944: while (p > arg && vim_iswhite(p[-1]))
1945: --p;
1946: }
1947: line2 = buflist_findpat(arg, p);
1948: if (line2 < 0) /* failed */
1949: goto doend;
1950: addr_count = 1;
1951: arg = skipwhite(p);
1952: }
1953:
1954: /*
1955: * 6. switch on command name
1956: * arg points to the argument of the command
1957: * nextcomm points to the next command (if any)
1958: * cmd points to the name of the command (except for :make)
1959: * cmdidx is the index for the command
1960: * forceit is TRUE if ! present
1961: * addr_count is the number of addresses given
1962: * line1 is the first line number
1963: * line2 is the second line number or count
1964: * do_ecmd_cmd is +command argument to be used in edited file
1965: * do_ecmd_lnum is the line number in edited file
1966: * append is TRUE with ":w >>file" command
1967: * usefilter is TRUE with ":w !command" and ":r!command"
1968: * amount is number of '>' or '<' for shift command
1969: */
1970: cmdswitch:
1971: switch (cmdidx)
1972: {
1973: /*
1974: * quit current window, quit Vim if closed the last window
1975: */
1976: case CMD_quit:
1977: /* if more files or windows we won't exit */
1978: if (check_more(FALSE) == OK && only_one_window())
1979: exiting = TRUE;
1980: if (check_changed(curbuf, FALSE, FALSE) ||
1981: check_more(TRUE) == FAIL ||
1982: (only_one_window() && check_changed_any()))
1983: {
1984: exiting = FALSE;
1985: settmode(1);
1986: break;
1987: }
1988: if (only_one_window()) /* quit last window */
1989: getout(0);
1990: close_window(curwin, TRUE); /* may free buffer */
1991: break;
1992:
1993: /*
1994: * try to quit all windows
1995: */
1996: case CMD_qall:
1997: exiting = TRUE;
1998: if (!check_changed_any())
1999: getout(0);
2000: exiting = FALSE;
2001: settmode(1);
2002: break;
2003:
2004: /*
2005: * close current window, unless it is the last one
2006: */
2007: case CMD_close:
2008: close_window(curwin, FALSE); /* don't free buffer */
2009: break;
2010:
2011: /*
2012: * close all but current window, unless it is the last one
2013: */
2014: case CMD_only:
2015: close_others(TRUE);
2016: break;
2017:
2018: case CMD_stop:
2019: case CMD_suspend:
2020: #ifdef WIN32
2021: /*
2022: * Check if external commands are allowed now.
2023: */
2024: if (can_end_termcap_mode(TRUE) == FALSE)
2025: break;
2026: #endif
2027: if (!forceit)
2028: autowrite_all();
2029: windgoto((int)Rows - 1, 0);
2030: outchar('\n');
2031: flushbuf();
2032: stoptermcap();
2033: mch_restore_title(3); /* restore window titles */
2034: mch_suspend(); /* call machine specific function */
2035: maketitle();
2036: starttermcap();
2037: scroll_start(); /* scroll screen before redrawing */
2038: must_redraw = CLEAR;
2039: set_winsize(0, 0, FALSE); /* May have resized window -- webb */
2040: break;
2041:
2042: case CMD_exit:
2043: case CMD_xit:
2044: case CMD_wq:
2045: /* if more files or windows we won't exit */
2046: if (check_more(FALSE) == OK && only_one_window())
2047: exiting = TRUE;
2048: if (((cmdidx == CMD_wq || curbuf->b_changed) &&
2049: do_write(arg, FALSE) == FAIL) ||
2050: check_more(TRUE) == FAIL ||
2051: (only_one_window() && check_changed_any()))
2052: {
2053: exiting = FALSE;
2054: settmode(1);
2055: break;
2056: }
2057: if (only_one_window()) /* quit last window, exit Vim */
2058: getout(0);
2059: close_window(curwin, TRUE); /* quit current window, may free buffer */
2060: break;
2061:
2062: case CMD_xall: /* write all changed files and exit */
2063: case CMD_wqall: /* write all changed files and quit */
2064: exiting = TRUE;
2065: /* FALLTHROUGH */
2066:
2067: case CMD_wall: /* write all changed files */
2068: {
2069: BUF *buf;
2070: int error = 0;
2071:
2072: for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2073: {
2074: if (buf->b_changed)
2075: {
2076: if (buf->b_filename == NULL)
2077: {
2078: emsg(e_noname);
2079: ++error;
2080: }
2081: else if (!forceit && buf->b_p_ro)
2082: {
2083: EMSG2("\"%s\" is readonly, use ! to write anyway", buf->b_xfilename);
2084: ++error;
2085: }
2086: else if (buf_write_all(buf) == FAIL)
2087: ++error;
2088: }
2089: }
2090: if (exiting)
2091: {
2092: if (!error)
2093: getout(0); /* exit Vim */
2094: exiting = FALSE;
2095: settmode(1);
2096: }
2097: }
2098: break;
2099:
2100: case CMD_preserve: /* put everything in .swp file */
2101: ml_preserve(curbuf, TRUE);
2102: break;
2103:
2104: case CMD_recover: /* recover file */
2105: recoverymode = TRUE;
2106: if (!check_changed(curbuf, FALSE, TRUE) &&
2107: (*arg == NUL || setfname(arg, NULL, TRUE) == OK))
2108: ml_recover();
2109: recoverymode = FALSE;
2110: break;
2111:
2112: case CMD_args:
2113: /*
2114: * ":args file": handle like :next
2115: */
2116: if (*arg != NUL && *arg != '|' && *arg != '\n')
2117: goto do_next;
2118:
2119: if (arg_count == 0) /* no file name list */
2120: {
2121: if (check_fname() == OK) /* check for no file name */
2122: smsg((char_u *)"[%s]", curbuf->b_filename);
2123: break;
2124: }
2125: /*
2126: * Overwrite the command, in most cases there is no scrolling
2127: * required and no wait_return().
2128: */
2129: gotocmdline(TRUE);
2130: for (i = 0; i < arg_count; ++i)
2131: {
2132: if (i == curwin->w_arg_idx)
2133: msg_outchar('[');
2134: msg_outtrans(arg_files[i]);
2135: if (i == curwin->w_arg_idx)
2136: msg_outchar(']');
2137: msg_outchar(' ');
2138: }
2139: break;
2140:
2141: case CMD_wnext:
2142: case CMD_wNext:
2143: case CMD_wprevious:
2144: if (cmd[1] == 'n')
2145: i = curwin->w_arg_idx + (int)line2;
2146: else
2147: i = curwin->w_arg_idx - (int)line2;
2148: line1 = 1;
2149: line2 = curbuf->b_ml.ml_line_count;
2150: if (do_write(arg, FALSE) == FAIL)
2151: break;
2152: goto donextfile;
2153:
2154: case CMD_next:
2155: case CMD_snext:
2156: do_next:
2157: /*
2158: * check for changed buffer now, if this fails the
2159: * argument list is not redefined.
2160: */
2161: if (!(p_hid || cmdidx == CMD_snext) &&
2162: check_changed(curbuf, TRUE, FALSE))
2163: break;
2164:
2165: if (*arg != NUL) /* redefine file list */
2166: {
2167: if (do_arglist(arg) == FAIL)
2168: break;
2169: i = 0;
2170: }
2171: else
2172: i = curwin->w_arg_idx + (int)line2;
2173:
2174: donextfile: if (i < 0 || i >= arg_count)
2175: {
2176: if (arg_count <= 1)
2177: EMSG("There is only one file to edit");
2178: else if (i < 0)
2179: EMSG("Cannot go before first file");
2180: else
2181: EMSG("Cannot go beyond last file");
2182: break;
2183: }
2184: setpcmark();
2185: if (*cmd == 's') /* split window first */
2186: {
2187: if (win_split(0, FALSE) == FAIL)
2188: break;
2189: }
2190: else
2191: {
2192: register int other;
2193:
2194: /*
2195: * if 'hidden' set, only check for changed file when
2196: * re-editing the same buffer
2197: */
2198: other = TRUE;
2199: if (p_hid)
2200: other = otherfile(fix_fname(arg_files[i]));
2201: if ((!p_hid || !other) &&
2202: check_changed(curbuf, TRUE, !other))
2203: break;
2204: }
2205: curwin->w_arg_idx = i;
2206: if (i == arg_count - 1)
2207: arg_had_last = TRUE;
2208: (void)do_ecmd(0, arg_files[curwin->w_arg_idx],
2209: NULL, do_ecmd_cmd, p_hid, do_ecmd_lnum, FALSE);
2210: break;
2211:
2212: case CMD_previous:
2213: case CMD_sprevious:
2214: case CMD_Next:
2215: case CMD_sNext:
2216: i = curwin->w_arg_idx - (int)line2;
2217: goto donextfile;
2218:
2219: case CMD_rewind:
2220: case CMD_srewind:
2221: i = 0;
2222: goto donextfile;
2223:
2224: case CMD_last:
2225: case CMD_slast:
2226: i = arg_count - 1;
2227: goto donextfile;
2228:
2229: case CMD_argument:
2230: case CMD_sargument:
2231: if (addr_count)
2232: i = line2 - 1;
2233: else
2234: i = curwin->w_arg_idx;
2235: goto donextfile;
2236:
2237: case CMD_all:
2238: case CMD_sall:
2239: if (addr_count == 0)
2240: line2 = 9999;
2241: do_arg_all((int)line2); /* open a window for each argument */
2242: break;
2243:
2244: case CMD_buffer: /* :[N]buffer [N] to buffer N */
2245: case CMD_sbuffer: /* :[N]sbuffer [N] to buffer N */
2246: if (*arg)
2247: {
2248: errormsg = e_trailing;
2249: break;
2250: }
2251: if (addr_count == 0) /* default is current buffer */
2252: (void)do_buffer(*cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
2253: DOBUF_CURRENT, FORWARD, 0, 0);
2254: else
2255: (void)do_buffer(*cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
2256: DOBUF_FIRST, FORWARD, (int)line2, 0);
2257: break;
2258:
2259: case CMD_bmodified: /* :[N]bmod [N] to next modified buffer */
2260: case CMD_sbmodified: /* :[N]sbmod [N] to next modified buffer */
2261: (void)do_buffer(*cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
2262: DOBUF_MOD, FORWARD, (int)line2, 0);
2263: break;
2264:
2265: case CMD_bnext: /* :[N]bnext [N] to next buffer */
2266: case CMD_sbnext: /* :[N]sbnext [N] to next buffer */
2267: (void)do_buffer(*cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
2268: DOBUF_CURRENT, FORWARD, (int)line2, 0);
2269: break;
2270:
2271: case CMD_bNext: /* :[N]bNext [N] to previous buffer */
2272: case CMD_bprevious: /* :[N]bprevious [N] to previous buffer */
2273: case CMD_sbNext: /* :[N]sbNext [N] to previous buffer */
2274: case CMD_sbprevious: /* :[N]sbprevious [N] to previous buffer */
2275: (void)do_buffer(*cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
2276: DOBUF_CURRENT, BACKWARD, (int)line2, 0);
2277: break;
2278:
2279: case CMD_brewind: /* :brewind to first buffer */
2280: case CMD_sbrewind: /* :sbrewind to first buffer */
2281: (void)do_buffer(*cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
2282: DOBUF_FIRST, FORWARD, 0, 0);
2283: break;
2284:
2285: case CMD_blast: /* :blast to last buffer */
2286: case CMD_sblast: /* :sblast to last buffer */
2287: (void)do_buffer(*cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
2288: DOBUF_LAST, FORWARD, 0, 0);
2289: break;
2290:
2291: case CMD_bunload: /* :[N]bunload[!] [N] [bufname] unload buffer */
2292: case CMD_bdelete: /* :[N]bdelete[!] [N] [bufname] delete buffer */
2293: errormsg = do_bufdel(
2294: cmdidx == CMD_bdelete ? DOBUF_DEL : DOBUF_UNLOAD,
2295: arg, addr_count, (int)line1, (int)line2, forceit);
2296: break;
2297:
2298: case CMD_unhide:
2299: case CMD_sunhide: /* open a window for loaded buffers */
2300: if (addr_count == 0)
2301: line2 = 9999;
2302: (void)do_buffer_all((int)line2, FALSE);
2303: break;
2304:
2305: case CMD_ball:
2306: case CMD_sball: /* open a window for every buffer */
2307: if (addr_count == 0)
2308: line2 = 9999;
2309: (void)do_buffer_all((int)line2, TRUE);
2310: break;
2311:
2312: case CMD_buffers:
2313: case CMD_files:
2314: case CMD_ls:
2315: buflist_list();
2316: break;
2317:
2318: case CMD_write:
2319: if (usefilter) /* input lines to shell command */
2320: do_bang(1, line1, line2, FALSE, arg, TRUE, FALSE);
2321: else
2322: (void)do_write(arg, append);
2323: break;
2324:
2325: /*
2326: * set screen mode
2327: * if no argument given, just get the screen size and redraw
2328: */
2329: case CMD_mode:
2330: if (*arg == NUL || mch_screenmode(arg) != FAIL)
2331: set_winsize(0, 0, FALSE);
2332: break;
2333:
2334: /*
2335: * set, increment or decrement current window height
2336: */
2337: case CMD_resize:
2338: n = atol((char *)arg);
2339: if (*arg == '-' || *arg == '+')
2340: win_setheight(curwin->w_height + (int)n);
2341: else
2342: {
2343: if (n == 0) /* default is very high */
2344: n = 9999;
2345: win_setheight((int)n);
2346: }
2347: break;
2348:
2349: /*
2350: * :sview [+command] file split window with new file, ro
2351: * :split [[+command] file] split window with current or new file
2352: * :new [[+command] file] split window with no or new file
2353: */
2354: case CMD_sview:
2355: case CMD_split:
2356: case CMD_new:
2357: old_curwin = curwin;
2358: if (win_split(addr_count ? (int)line2 : 0, FALSE) == FAIL)
2359: break;
2360: /*FALLTHROUGH*/
2361:
2362: case CMD_edit:
2363: case CMD_ex:
2364: case CMD_visual:
2365: case CMD_view:
2366: if ((cmdidx == CMD_new) && *arg == NUL)
2367: {
2368: setpcmark();
2369: (void)do_ecmd(0, NULL, NULL, do_ecmd_cmd, TRUE,
2370: (linenr_t)1, FALSE);
2371: }
2372: else if (cmdidx != CMD_split || *arg != NUL)
2373: {
2374: n = readonlymode;
2375: if (cmdidx == CMD_view || cmdidx == CMD_sview)
2376: readonlymode = TRUE;
2377: setpcmark();
2378: (void)do_ecmd(0, arg, NULL, do_ecmd_cmd, p_hid,
2379: do_ecmd_lnum, FALSE);
2380: readonlymode = n;
2381: }
2382: else
2383: updateScreen(NOT_VALID);
2384: /* if ":split file" worked, set alternate filename in
2385: * old window to new file */
2386: if ((cmdidx == CMD_new || cmdidx == CMD_split) &&
2387: *arg != NUL && curwin != old_curwin &&
2388: old_curwin->w_buffer != curbuf)
2389: old_curwin->w_alt_fnum = curbuf->b_fnum;
2390: break;
2391:
2392: #ifdef USE_GUI
2393: /*
2394: * Change from the terminal version to the GUI version. File names may
2395: * be given to redefine the args list -- webb
2396: */
2397: case CMD_gvim:
2398: case CMD_gui:
2399: if (arg[0] == '-' && arg[1] == 'f' &&
2400: (arg[2] == NUL || vim_iswhite(arg[2])))
2401: {
2402: gui.dofork = FALSE;
2403: arg = skipwhite(arg + 2);
2404: }
2405: else
2406: gui.dofork = TRUE;
2407: if (!gui.in_use)
2408: gui_start();
2409: if (*arg != NUL && *arg != '|' && *arg != '\n')
2410: goto do_next;
2411: break;
2412: #endif
2413:
2414: case CMD_file:
2415: do_file(arg, forceit);
2416: break;
2417:
2418: case CMD_swapname:
2419: if (curbuf->b_ml.ml_mfp == NULL ||
2420: (p = curbuf->b_ml.ml_mfp->mf_fname) == NULL)
2421: MSG("No swap file");
2422: else
2423: msg(p);
2424: break;
2425:
2426: case CMD_mfstat: /* print memfile statistics, for debugging */
2427: mf_statistics();
2428: break;
2429:
2430: case CMD_read:
2431: if (usefilter) /* :r!cmd */
2432: {
2433: do_bang(1, line1, line2, FALSE, arg, FALSE, TRUE);
2434: break;
2435: }
2436: if (u_save(line2, (linenr_t)(line2 + 1)) == FAIL)
2437: break;
2438: if (*arg == NUL)
2439: {
2440: if (check_fname() == FAIL) /* check for no file name */
2441: break;
2442: i = readfile(curbuf->b_filename, curbuf->b_sfilename,
2443: line2, FALSE, (linenr_t)0, MAXLNUM, FALSE);
2444: }
2445: else
2446: {
2447: i = readfile(arg, NULL,
2448: line2, FALSE, (linenr_t)0, MAXLNUM, FALSE);
2449: }
2450: if (i == FAIL)
2451: {
2452: emsg2(e_notopen, arg);
2453: break;
2454: }
2455:
2456: updateScreen(NOT_VALID);
2457: break;
2458:
2459: case CMD_cd:
2460: case CMD_chdir:
2461: #ifdef UNIX
2462: /*
2463: * for UNIX ":cd" means: go to home directory
2464: */
2465: if (*arg == NUL) /* use NameBuff for home directory name */
2466: {
2467: expand_env((char_u *)"$HOME", NameBuff, MAXPATHL);
2468: arg = NameBuff;
2469: }
2470: #endif
2471: if (*arg != NUL)
2472: {
2473: if (!did_cd)
2474: {
2475: BUF *buf;
2476:
2477: /* use full path from now on for names of files
2478: * being edited and swap files */
2479: for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2480: {
2481: buf->b_xfilename = buf->b_filename;
2482: mf_fullname(buf->b_ml.ml_mfp);
2483: }
2484: status_redraw_all();
2485: }
2486: did_cd = TRUE;
2487: if (vim_chdir((char *)arg))
2488: emsg(e_failed);
2489: break;
2490: }
2491: /*FALLTHROUGH*/
2492:
2493: case CMD_pwd:
2494: if (mch_dirname(NameBuff, MAXPATHL) == OK)
2495: msg(NameBuff);
2496: else
2497: emsg(e_unknown);
2498: break;
2499:
2500: case CMD_equal:
2501: smsg((char_u *)"line %ld", (long)line2);
2502: break;
2503:
2504: case CMD_list:
2505: i = curwin->w_p_list;
2506: curwin->w_p_list = 1;
2507: case CMD_number: /* :nu */
2508: case CMD_pound: /* :# */
2509: case CMD_print: /* :p */
2510: for ( ;!got_int; mch_breakcheck())
2511: {
2512: print_line(line1,
2513: (cmdidx == CMD_number || cmdidx == CMD_pound));
2514: if (++line1 > line2)
2515: break;
2516: flushbuf(); /* show one line at a time */
2517: }
2518: setpcmark();
2519: curwin->w_cursor.lnum = line2; /* put cursor at last line */
2520:
2521: if (cmdidx == CMD_list)
2522: curwin->w_p_list = i;
2523:
2524: break;
2525:
2526: case CMD_shell:
2527: do_shell(NULL);
2528: break;
2529:
2530: case CMD_sleep:
2531: n = curwin->w_winpos + curwin->w_row - msg_scrolled;
2532: if (n >= 0)
2533: {
2534: windgoto((int)n, curwin->w_col);
2535: flushbuf();
2536: }
2537: mch_delay(line2 * 1000L, TRUE);
2538: break;
2539:
2540: case CMD_stag:
2541: postponed_split = TRUE;
2542: /*FALLTHROUGH*/
2543: case CMD_tag:
2544: do_tag(arg, 0, addr_count ? (int)line2 : 1);
2545: break;
2546:
2547: case CMD_pop:
2548: do_tag((char_u *)"", 1, addr_count ? (int)line2 : 1);
2549: break;
2550:
2551: case CMD_tags:
2552: do_tags();
2553: break;
2554:
2555: case CMD_marks:
2556: do_marks(arg);
2557: break;
2558:
2559: case CMD_jumps:
2560: do_jumps();
2561: break;
2562:
2563: case CMD_ascii:
2564: do_ascii();
2565: break;
2566:
2567: case CMD_checkpath:
2568: find_pattern_in_path(NULL, 0, FALSE, FALSE, CHECK_PATH, 1L,
2569: forceit ? ACTION_SHOW_ALL : ACTION_SHOW,
2570: (linenr_t)1, (linenr_t)MAXLNUM);
2571: break;
2572:
2573: case CMD_digraphs:
2574: #ifdef DIGRAPHS
2575: if (*arg)
2576: putdigraph(arg);
2577: else
2578: listdigraphs();
2579: #else
2580: EMSG("No digraphs in this version");
2581: #endif /* DIGRAPHS */
2582: break;
2583:
2584: case CMD_set:
2585: (void)do_set(arg);
2586: break;
2587:
2588: case CMD_fixdel:
2589: do_fixdel();
2590: break;
2591:
2592: #ifdef AUTOCMD
2593: case CMD_autocmd:
2594: /*
2595: * Disallow auto commands from .exrc and .vimrc in current
2596: * directory for security reasons.
2597: */
2598: if (secure)
2599: {
2600: secure = 2;
2601: errormsg = e_curdir;
2602: }
2603: else
2604: do_autocmd(arg, forceit); /* handle the auto commands */
2605: break;
2606:
2607: case CMD_doautocmd:
2608: do_doautocmd(arg); /* apply the automatic commands */
2609: do_modelines();
2610: break;
2611: #endif
2612:
2613: case CMD_abbreviate:
2614: case CMD_cabbrev:
2615: case CMD_iabbrev:
2616: case CMD_cnoreabbrev:
2617: case CMD_inoreabbrev:
2618: case CMD_noreabbrev:
2619: case CMD_unabbreviate:
2620: case CMD_cunabbrev:
2621: case CMD_iunabbrev:
2622: i = ABBREV;
2623: goto doabbr; /* almost the same as mapping */
2624:
2625: case CMD_nmap:
2626: case CMD_vmap:
2627: case CMD_cmap:
2628: case CMD_imap:
2629: case CMD_map:
2630: case CMD_nnoremap:
2631: case CMD_vnoremap:
2632: case CMD_cnoremap:
2633: case CMD_inoremap:
2634: case CMD_noremap:
2635: /*
2636: * If we are sourcing .exrc or .vimrc in current directory we
2637: * print the mappings for security reasons.
2638: */
2639: if (secure)
2640: {
2641: secure = 2;
2642: msg_outtrans(cmd);
2643: msg_outchar('\n');
2644: }
2645: case CMD_nunmap:
2646: case CMD_vunmap:
2647: case CMD_cunmap:
2648: case CMD_iunmap:
2649: case CMD_unmap:
2650: i = 0;
2651: doabbr:
2652: if (*cmd == 'c') /* cmap, cunmap, cnoremap, etc. */
2653: {
2654: i += CMDLINE;
2655: ++cmd;
2656: }
2657: else if (*cmd == 'i') /* imap, iunmap, inoremap, etc. */
2658: {
2659: i += INSERT;
2660: ++cmd;
2661: }
2662: /* nmap, nunmap, nnoremap */
2663: else if (*cmd == 'n' && *(cmd + 1) != 'o')
2664: {
2665: i += NORMAL;
2666: ++cmd;
2667: }
2668: else if (*cmd == 'v') /* vmap, vunmap, vnoremap */
2669: {
2670: i += VISUAL;
2671: ++cmd;
2672: }
2673: else if (forceit || i) /* map!, unmap!, noremap!, abbrev */
2674: i += INSERT + CMDLINE;
2675: else /* map, unmap, noremap */
2676: i += NORMAL + VISUAL;
2677: switch (do_map((*cmd == 'n') ? 2 : (*cmd == 'u'), arg, i))
2678: {
2679: case 1: emsg(e_invarg);
2680: break;
2681: case 2: emsg(e_nomap);
2682: break;
2683: case 3: emsg(e_ambmap);
2684: break;
2685: }
2686: break;
2687:
2688: case CMD_mapclear:
2689: case CMD_imapclear:
2690: case CMD_nmapclear:
2691: case CMD_vmapclear:
2692: case CMD_cmapclear:
2693: map_clear(*cmd, forceit, FALSE);
2694: break;
2695:
2696: case CMD_abclear:
2697: case CMD_iabclear:
2698: case CMD_cabclear:
2699: map_clear(*cmd, FALSE, TRUE);
2700: break;
2701:
2702: #ifdef USE_GUI
2703: case CMD_menu: case CMD_noremenu: case CMD_unmenu:
2704: case CMD_nmenu: case CMD_nnoremenu: case CMD_nunmenu:
2705: case CMD_vmenu: case CMD_vnoremenu: case CMD_vunmenu:
2706: case CMD_imenu: case CMD_inoremenu: case CMD_iunmenu:
2707: case CMD_cmenu: case CMD_cnoremenu: case CMD_cunmenu:
2708: gui_do_menu(cmd, arg, forceit);
2709: break;
2710: #endif /* USE_GUI */
2711:
2712: case CMD_display:
2713: case CMD_registers:
2714: do_dis(arg); /* display buffer contents */
2715: break;
2716:
2717: case CMD_help:
2718: do_help(arg);
2719: break;
2720:
2721: case CMD_version:
2722: do_version(arg);
2723: break;
2724:
2725: case CMD_winsize: /* obsolete command */
2726: line1 = getdigits(&arg);
2727: arg = skipwhite(arg);
2728: line2 = getdigits(&arg);
2729: set_winsize((int)line1, (int)line2, TRUE);
2730: break;
2731:
2732: case CMD_delete:
2733: case CMD_yank:
2734: case CMD_rshift:
2735: case CMD_lshift:
2736: yankbuffer = regname;
2737: curbuf->b_op_start.lnum = line1;
2738: curbuf->b_op_end.lnum = line2;
2739: op_line_count = line2 - line1 + 1;
2740: op_motion_type = MLINE;
2741: if (cmdidx != CMD_yank) /* set cursor position for undo */
2742: {
2743: setpcmark();
2744: curwin->w_cursor.lnum = line1;
2745: beginline(MAYBE);
2746: }
2747: switch (cmdidx)
2748: {
2749: case CMD_delete:
2750: do_delete();
2751: break;
2752: case CMD_yank:
2753: (void)do_yank(FALSE, TRUE);
2754: break;
2755: #ifdef RIGHTLEFT
2756: case CMD_rshift:
2757: do_shift(curwin->w_p_rl ? LSHIFT : RSHIFT, FALSE, amount);
2758: break;
2759: case CMD_lshift:
2760: do_shift(curwin->w_p_rl ? RSHIFT : LSHIFT, FALSE, amount);
2761: break;
2762: #else
2763: case CMD_rshift:
2764: do_shift(RSHIFT, FALSE, amount);
2765: break;
2766: case CMD_lshift:
2767: do_shift(LSHIFT, FALSE, amount);
2768: break;
2769: #endif
2770: }
2771: break;
2772:
2773: case CMD_put:
2774: yankbuffer = regname;
2775: curwin->w_cursor.lnum = line2;
2776: do_put(forceit ? BACKWARD : FORWARD, -1L, FALSE);
2777: break;
2778:
2779: case CMD_t:
2780: case CMD_copy:
2781: case CMD_move:
2782: n = get_address(&arg);
2783: if (arg == NULL) /* error detected */
2784: {
2785: nextcomm = NULL;
2786: break;
2787: }
2788: /*
2789: * move or copy lines from 'line1'-'line2' to below line 'n'
2790: */
2791: if (n == MAXLNUM || n < 0 || n > curbuf->b_ml.ml_line_count)
2792: {
2793: emsg(e_invaddr);
2794: break;
2795: }
2796:
2797: if (cmdidx == CMD_move)
2798: {
2799: if (do_move(line1, line2, n) == FAIL)
2800: break;
2801: }
2802: else
2803: do_copy(line1, line2, n);
2804: u_clearline();
2805: beginline(MAYBE);
2806: updateScreen(NOT_VALID);
2807: break;
2808:
2809: case CMD_and: /* :& */
2810: case CMD_tilde: /* :~ */
2811: case CMD_substitute: /* :s */
2812: do_sub(line1, line2, arg, &nextcomm,
2813: cmdidx == CMD_substitute ? 0 :
2814: cmdidx == CMD_and ? 1 : 2);
2815: break;
2816:
2817: case CMD_join:
2818: curwin->w_cursor.lnum = line1;
2819: if (line1 == line2)
2820: {
2821: if (addr_count >= 2) /* :2,2join does nothing */
2822: break;
2823: if (line2 == curbuf->b_ml.ml_line_count)
2824: {
2825: beep_flush();
2826: break;
2827: }
2828: ++line2;
2829: }
2830: do_do_join(line2 - line1 + 1, !forceit, FALSE);
2831: beginline(TRUE);
2832: break;
2833:
2834: case CMD_global:
2835: if (forceit)
2836: *cmd = 'v';
2837: case CMD_vglobal:
2838: do_glob(*cmd, line1, line2, arg);
2839: break;
2840:
2841: case CMD_at: /* :[addr]@r */
2842: curwin->w_cursor.lnum = line2;
2843: /* put the register in mapbuf */
2844: if (do_execbuf(*arg, TRUE,
2845: vim_strchr(p_cpo, CPO_EXECBUF) != NULL) == FAIL)
2846: beep_flush();
2847: else
2848: /* execute from the mapbuf */
2849: while (vpeekc() == ':')
2850: {
2851: (void)vgetc();
2852: (void)do_cmdline((char_u *)NULL, TRUE, TRUE);
2853: }
2854: break;
2855:
2856: case CMD_bang:
2857: do_bang(addr_count, line1, line2, forceit, arg, TRUE, TRUE);
2858: break;
2859:
2860: case CMD_undo:
2861: u_undo(1);
2862: break;
2863:
2864: case CMD_redo:
2865: u_redo(1);
2866: break;
2867:
2868: case CMD_source:
2869: if (forceit) /* :so! read vi commands */
2870: (void)openscript(arg);
2871: /* :so read ex commands */
2872: else if (do_source(arg, FALSE) == FAIL)
2873: emsg2(e_notopen, arg);
2874: break;
2875:
2876: #ifdef VIMINFO
2877: case CMD_rviminfo:
2878: p = p_viminfo;
2879: if (*p_viminfo == NUL)
2880: p_viminfo = (char_u *)"'100";
2881: if (read_viminfo(arg, TRUE, TRUE, forceit) == FAIL)
2882: EMSG("Cannot open viminfo file for reading");
2883: p_viminfo = p;
2884: break;
2885:
2886: case CMD_wviminfo:
2887: p = p_viminfo;
2888: if (*p_viminfo == NUL)
2889: p_viminfo = (char_u *)"'100";
2890: write_viminfo(arg, forceit);
2891: p_viminfo = p;
2892: break;
2893: #endif /* VIMINFO */
2894:
2895: case CMD_mkvimrc:
2896: if (*arg == NUL)
2897: arg = (char_u *)VIMRC_FILE;
2898: /*FALLTHROUGH*/
2899:
2900: case CMD_mkexrc:
2901: {
2902: FILE *fd;
2903:
2904: if (*arg == NUL)
2905: arg = (char_u *)EXRC_FILE;
2906: #ifdef UNIX
2907: /* with Unix it is possible to open a directory */
2908: if (mch_isdir(arg))
2909: {
2910: EMSG2("\"%s\" is a directory", arg);
2911: break;
2912: }
2913: #endif
2914: if (!forceit && vim_fexists(arg))
2915: {
2916: EMSG2("\"%s\" exists (use ! to override)", arg);
2917: break;
2918: }
2919:
2920: if ((fd = fopen((char *)arg, WRITEBIN)) == NULL)
2921: {
2922: EMSG2("Cannot open \"%s\" for writing", arg);
2923: break;
2924: }
2925:
2926: /* Write the version command for :mkvimrc */
2927: if (cmdidx == CMD_mkvimrc)
2928: {
2929: #ifdef USE_CRNL
2930: fprintf(fd, "version 4.0\r\n");
2931: #else
2932: fprintf(fd, "version 4.0\n");
2933: #endif
2934: }
2935:
2936: if (makemap(fd) == FAIL || makeset(fd) == FAIL ||
2937: fclose(fd))
2938: emsg(e_write);
2939: break;
2940: }
2941:
2942: case CMD_cc:
2943: qf_jump(0, addr_count ? (int)line2 : 0);
2944: break;
2945:
2946: case CMD_cfile:
2947: if (*arg != NUL)
2948: {
2949: /*
2950: * Great trick: Insert 'ef=' before arg.
2951: * Always ok, because "cf " must be there.
2952: */
2953: arg -= 3;
2954: arg[0] = 'e';
2955: arg[1] = 'f';
2956: arg[2] = '=';
2957: (void)do_set(arg);
2958: }
2959: if (qf_init() == OK)
2960: qf_jump(0, 0); /* display first error */
2961: break;
2962:
2963: case CMD_clist:
2964: qf_list(forceit);
2965: break;
2966:
2967: case CMD_cnext:
2968: qf_jump(FORWARD, addr_count ? (int)line2 : 1);
2969: break;
2970:
2971: case CMD_cNext:
2972: case CMD_cprevious:
2973: qf_jump(BACKWARD, addr_count ? (int)line2 : 1);
2974: break;
2975:
2976: case CMD_cquit:
2977: getout(1); /* this does not always work. why? */
2978:
2979: case CMD_mark:
2980: case CMD_k:
2981: pos = curwin->w_cursor; /* save curwin->w_cursor */
2982: curwin->w_cursor.lnum = line2;
2983: beginline(MAYBE);
2984: (void)setmark(*arg); /* set mark */
2985: curwin->w_cursor = pos; /* restore curwin->w_cursor */
2986: break;
2987:
2988: case CMD_center:
2989: case CMD_right:
2990: case CMD_left:
2991: do_align(line1, line2, atoi((char *)arg),
2992: cmdidx == CMD_center ? 0 : cmdidx == CMD_right ? 1 : -1);
2993: break;
2994:
2995: case CMD_retab:
2996: n = getdigits(&arg);
2997: do_retab(line1, line2, (int)n, forceit);
2998: u_clearline();
2999: updateScreen(NOT_VALID);
3000: break;
3001:
3002: case CMD_make:
3003: do_make(arg);
3004: break;
3005:
3006: /*
3007: * :normal[!] {commands} - execute normal mode commands
3008: * Mostly used for ":autocmd".
3009: */
3010: case CMD_normal:
3011: /*
3012: * Stuff the argument into the typeahead buffer.
3013: * Execute normal() until there is no more typeahead than
3014: * there was before this command.
3015: */
3016: len = typelen;
3017: ins_typebuf(arg, forceit ? -1 : 0, 0, TRUE);
3018: while ((!stuff_empty() ||
3019: (!typebuf_typed() && typelen > len)) && !got_int)
3020: {
3021: adjust_cursor(); /* put cursor on an existing line */
3022: cursupdate(); /* update cursor position */
3023: normal(); /* get and execute a normal mode command */
3024: }
3025: break;
3026:
3027: case CMD_isearch:
3028: case CMD_dsearch:
3029: i = ACTION_SHOW;
3030: goto find_pat;
3031:
3032: case CMD_ilist:
3033: case CMD_dlist:
3034: i = ACTION_SHOW_ALL;
3035: goto find_pat;
3036:
3037: case CMD_ijump:
3038: case CMD_djump:
3039: i = ACTION_GOTO;
3040: goto find_pat;
3041:
3042: case CMD_isplit:
3043: case CMD_dsplit:
3044: i = ACTION_SPLIT;
3045: find_pat:
3046: {
3047: int whole = TRUE;
3048:
3049: n = 1;
3050: if (isdigit(*arg)) /* get count */
3051: {
3052: n = getdigits(&arg);
3053: arg = skipwhite(arg);
3054: }
3055: if (*arg == '/') /* Match regexp, not just whole words */
3056: {
3057: whole = FALSE;
3058: ++arg;
3059: for (p = arg; *p && *p != '/'; p++)
3060: if (*p == '\\' && p[1] != NUL)
3061: p++;
3062: if (*p)
3063: {
3064: *p++ = NUL;
3065: p = skipwhite(p);
3066:
3067: /* Check for trailing illegal characters */
3068: if (*p && vim_strchr((char_u *)"|\"\n", *p) == NULL)
3069: errormsg = e_trailing;
3070: else
3071: nextcomm = p;
3072: }
3073: }
3074: find_pattern_in_path(arg, (int)STRLEN(arg), whole, !forceit,
3075: *cmd == 'd' ? FIND_DEFINE : FIND_ANY,
3076: n, i, line1, line2);
3077: }
3078: break;
3079:
3080: default:
3081: /* Normal illegal commands have already been handled */
3082: errormsg = (char_u *)"Sorry, this command is not implemented";
3083: }
3084:
3085:
3086: doend:
3087: if (errormsg != NULL)
3088: {
3089: emsg(errormsg);
3090: if (sourcing)
3091: {
3092: MSG_OUTSTR(": ");
3093: msg_outtrans(*cmdlinep);
3094: }
3095: }
3096: if (did_emsg)
3097: nextcomm = NULL; /* cancel nextcomm at an error */
3098: forceit = FALSE; /* reset now so it can be used in getfile() */
3099: if (nextcomm && *nextcomm == NUL) /* not really a next command */
3100: nextcomm = NULL;
3101: return nextcomm;
3102: }
3103:
3104: /*
3105: * If 'autowrite' option set, try to write the file.
3106: *
3107: * return FAIL for failure, OK otherwise
3108: */
3109: int
3110: autowrite(buf)
3111: BUF *buf;
3112: {
3113: if (!p_aw || (!forceit && buf->b_p_ro) || buf->b_filename == NULL)
3114: return FAIL;
3115: return buf_write_all(buf);
3116: }
3117:
3118: /*
3119: * flush all buffers, except the ones that are readonly
3120: */
3121: void
3122: autowrite_all()
3123: {
3124: BUF *buf;
3125:
3126: if (!p_aw)
3127: return;
3128: for (buf = firstbuf; buf; buf = buf->b_next)
3129: if (buf->b_changed && !buf->b_p_ro)
3130: (void)buf_write_all(buf);
3131: }
3132:
3133: /*
3134: * flush the contents of a buffer, unless it has no file name
3135: *
3136: * return FAIL for failure, OK otherwise
3137: */
3138: static int
3139: buf_write_all(buf)
3140: BUF *buf;
3141: {
3142: return (buf_write(buf, buf->b_filename, buf->b_sfilename,
3143: (linenr_t)1, buf->b_ml.ml_line_count, 0, 0, TRUE, FALSE));
3144: }
3145:
3146: /*
3147: * write current buffer to file 'fname'
3148: * if 'append' is TRUE, append to the file
3149: *
3150: * if *fname == NUL write to current file
3151: * if b_notedited is TRUE, check for overwriting current file
3152: *
3153: * return FAIL for failure, OK otherwise
3154: */
3155: static int
3156: do_write(fname, append)
3157: char_u *fname;
3158: int append;
3159: {
3160: int other;
3161: char_u *sfname = NULL; /* init to shut up gcc */
3162:
3163: if (*fname == NUL)
3164: other = FALSE;
3165: else
3166: {
3167: sfname = fname;
3168: fname = fix_fname(fname);
3169: other = otherfile(fname);
3170: }
3171:
3172: /*
3173: * if we have a new file name put it in the list of alternate file names
3174: */
3175: if (other)
3176: setaltfname(fname, sfname, (linenr_t)1);
3177:
3178: /*
3179: * writing to the current file is not allowed in readonly mode
3180: * and need a file name
3181: */
3182: if (!other && (check_readonly() || check_fname() == FAIL))
3183: return FAIL;
3184:
3185: if (!other)
3186: {
3187: fname = curbuf->b_filename;
3188: sfname = curbuf->b_sfilename;
3189: /*
3190: * Not writing the whole file is only allowed with '!'.
3191: */
3192: if ((line1 != 1 || line2 != curbuf->b_ml.ml_line_count) &&
3193: !forceit && !append && !p_wa)
3194: {
3195: EMSG("Use ! to write partial buffer");
3196: return FAIL;
3197: }
3198: }
3199:
3200: /*
3201: * write to other file or b_notedited set or not writing the whole file:
3202: * overwriting only allowed with '!'
3203: */
3204: if ((other || curbuf->b_notedited) && !forceit &&
3205: !append && !p_wa && vim_fexists(fname))
3206: { /* don't overwrite existing file */
3207: #ifdef UNIX
3208: /* with UNIX it is possible to open a directory */
3209: if (mch_isdir(fname))
3210: EMSG2("\"%s\" is a directory", fname);
3211: else
3212: #endif
3213: emsg(e_exists);
3214: return FAIL;
3215: }
3216: return (buf_write(curbuf, fname, sfname, line1, line2,
3217: append, forceit, TRUE, FALSE));
3218: }
3219:
3220: /*
3221: * start editing a new file
3222: *
3223: * fnum: file number; if zero use fname/sfname
3224: * fname: the file name
3225: * - full path if sfname used,
3226: * - any file name if sfname is NULL
3227: * - empty string to re-edit with the same file name (but may be
3228: * in a different directory)
3229: * - NULL to start an empty buffer
3230: * sfname: the short file name (or NULL)
3231: * command: the command to be executed after loading the file
3232: * hide: if TRUE don't free the current buffer
3233: * newlnum: put cursor on this line number (if possible)
3234: * set_help: set b_help flag of (new) buffer before opening file
3235: *
3236: * return FAIL for failure, OK otherwise
3237: */
3238: int
3239: do_ecmd(fnum, fname, sfname, command, hide, newlnum, set_help)
3240: int fnum;
3241: char_u *fname;
3242: char_u *sfname;
3243: char_u *command;
3244: int hide;
3245: linenr_t newlnum;
3246: int set_help;
3247: {
3248: int other_file; /* TRUE if editing another file */
3249: int oldbuf = FALSE; /* TRUE if using existing buffer */
3250: BUF *buf;
3251:
3252: if (fnum != 0)
3253: {
3254: if (fnum == curbuf->b_fnum) /* file is already being edited */
3255: return OK; /* nothing to do */
3256: other_file = TRUE;
3257: }
3258: else
3259: {
3260: /* if no short name given, use fname for short name */
3261: if (sfname == NULL)
3262: sfname = fname;
3263: #ifdef USE_FNAME_CASE
3264: # ifdef USE_LONG_FNAME
3265: if (USE_LONG_FNAME)
3266: # endif
3267: fname_case(sfname); /* set correct case for short filename */
3268: #endif
3269:
3270: if (fname == NULL)
3271: other_file = TRUE;
3272: /* there is no file name */
3273: else if (*fname == NUL && curbuf->b_filename == NULL)
3274: other_file = FALSE;
3275: else
3276: {
3277: if (*fname == NUL) /* re-edit with same file name */
3278: {
3279: fname = curbuf->b_filename;
3280: sfname = curbuf->b_sfilename;
3281: }
3282: fname = fix_fname(fname); /* may expand to full path name */
3283: other_file = otherfile(fname);
3284: }
3285: }
3286: /*
3287: * if the file was changed we may not be allowed to abandon it
3288: * - if we are going to re-edit the same file
3289: * - or if we are the only window on this file and if hide is FALSE
3290: */
3291: if ((!other_file || (curbuf->b_nwindows == 1 && !hide)) &&
3292: check_changed(curbuf, FALSE, !other_file))
3293: {
3294: if (fnum == 0 && other_file && fname != NULL)
3295: setaltfname(fname, sfname, (linenr_t)1);
3296: return FAIL;
3297: }
3298:
3299: /*
3300: * End Visual mode before switching to another buffer, so the text can be
3301: * copied into the GUI selection buffer.
3302: */
3303: if (VIsual_active)
3304: end_visual_mode();
3305:
3306: /*
3307: * If we are starting to edit another file, open a (new) buffer.
3308: * Otherwise we re-use the current buffer.
3309: */
3310: if (other_file)
3311: {
3312: curwin->w_alt_fnum = curbuf->b_fnum;
3313: buflist_altlnum();
3314:
3315: if (fnum)
3316: buf = buflist_findnr(fnum);
3317: else
3318: buf = buflist_new(fname, sfname, 1L, TRUE);
3319: if (buf == NULL)
3320: return FAIL;
3321: if (buf->b_ml.ml_mfp == NULL) /* no memfile yet */
3322: {
3323: oldbuf = FALSE;
3324: buf->b_nwindows = 1;
3325: }
3326: else /* existing memfile */
3327: {
3328: oldbuf = TRUE;
3329: ++buf->b_nwindows;
3330: buf_check_timestamp(buf);
3331: }
3332:
3333: /*
3334: * make the (new) buffer the one used by the current window
3335: * if the old buffer becomes unused, free it if hide is FALSE
3336: * If the current buffer was empty and has no file name, curbuf
3337: * is returned by buflist_new().
3338: */
3339: if (buf != curbuf)
3340: {
3341: #ifdef AUTOCMD
3342: apply_autocmds(EVENT_BUFLEAVE, NULL, NULL);
3343: #endif
3344: #ifdef VIMINFO
3345: curbuf->b_last_cursor = curwin->w_cursor;
3346: #endif
3347: buf_copy_options(curbuf, buf, TRUE);
3348: close_buffer(curwin, curbuf, !hide, FALSE);
3349: curwin->w_buffer = buf;
3350: curbuf = buf;
3351: }
3352:
3353: curwin->w_pcmark.lnum = 1;
3354: curwin->w_pcmark.col = 0;
3355: }
3356: else if (check_fname() == FAIL)
3357: return FAIL;
3358:
3359: /*
3360: * If we get here we are sure to start editing
3361: */
3362: /* don't redraw until the cursor is in the right line */
3363: ++RedrawingDisabled;
3364: if (set_help)
3365: curbuf->b_help = TRUE;
3366:
3367: /*
3368: * other_file oldbuf
3369: * FALSE FALSE re-edit same file, buffer is re-used
3370: * FALSE TRUE not posible
3371: * TRUE FALSE start editing new file, new buffer
3372: * TRUE TRUE start editing in existing buffer (nothing to do)
3373: */
3374: if (!other_file) /* re-use the buffer */
3375: {
3376: if (newlnum == 0)
3377: newlnum = curwin->w_cursor.lnum;
3378: buf_freeall(curbuf); /* free all things for buffer */
3379: buf_clear(curbuf);
3380: curbuf->b_op_start.lnum = 0; /* clear '[ and '] marks */
3381: curbuf->b_op_end.lnum = 0;
3382: }
3383:
3384: /*
3385: * Check if we are editing the w_arg_idx file in the argument list.
3386: */
3387: check_arg_idx();
3388:
3389: if (!oldbuf) /* need to read the file */
3390: (void)open_buffer();
3391: #ifdef AUTOCMD
3392: else
3393: apply_autocmds(EVENT_BUFENTER, NULL, NULL);
3394: #endif
3395: win_init(curwin);
3396: maketitle();
3397:
3398: if (command == NULL)
3399: {
3400: if (newlnum)
3401: {
3402: curwin->w_cursor.lnum = newlnum;
3403: check_cursor();
3404: beginline(MAYBE);
3405: }
3406: else
3407: beginline(TRUE);
3408: }
3409:
3410: /*
3411: * Did not read the file, need to show some info about the file.
3412: * Do this after setting the cursor.
3413: */
3414: if (oldbuf)
3415: fileinfo(did_cd, TRUE, FALSE);
3416:
3417: if (command != NULL)
3418: do_cmdline(command, TRUE, FALSE);
3419: --RedrawingDisabled;
3420: if (!skip_redraw)
3421: updateScreen(CURSUPD); /* redraw now */
3422:
3423: if (p_im)
3424: need_start_insertmode = TRUE;
3425: return OK;
3426: }
3427:
3428: /*
3429: * get + command from ex argument
3430: */
3431: static char_u *
3432: getargcmd(argp)
3433: char_u **argp;
3434: {
3435: char_u *arg = *argp;
3436: char_u *command = NULL;
3437:
3438: if (*arg == '+') /* +[command] */
3439: {
3440: ++arg;
3441: if (vim_isspace(*arg))
3442: command = (char_u *)"$";
3443: else
3444: {
3445: /*
3446: * should check for "\ " (but vi has a bug that prevents it to work)
3447: */
3448: command = arg;
3449: arg = skiptowhite(command);
3450: if (*arg)
3451: *arg++ = NUL; /* terminate command with NUL */
3452: }
3453:
3454: arg = skipwhite(arg); /* skip over spaces */
3455: *argp = arg;
3456: }
3457: return command;
3458: }
3459:
3460: /*
3461: * Halve the number of backslashes in a file name argument.
3462: * For MS-DOS we only do this if the character after the backslash
3463: * is not a normal file character.
3464: * For Unix, when wildcards are going to be expanded, don't remove
3465: * backslashes before special characters.
3466: */
3467: static void
3468: backslash_halve(p, expand_wildcards)
3469: char_u *p;
3470: int expand_wildcards; /* going to expand wildcards later */
3471: {
3472: for ( ; *p; ++p)
3473: if (is_backslash(p)
3474: #if defined(MSDOS) || defined(WIN32)
3475: && p[1] != '*' && p[1] != '?'
3476: #endif
3477: #if defined(UNIX) || defined(OS2)
3478: && !(expand_wildcards &&
3479: vim_strchr((char_u *)" *?[{`$\\", p[1]))
3480: #endif
3481: )
3482: STRCPY(p, p + 1);
3483: }
3484:
3485: static void
3486: do_make(arg)
3487: char_u *arg;
3488: {
3489: if (*p_ef == NUL)
3490: {
3491: EMSG("errorfile option not set");
3492: return;
3493: }
3494:
3495: autowrite_all();
3496: vim_remove(p_ef);
3497:
3498: sprintf((char *)IObuff, "%s %s %s", arg, p_sp, p_ef);
3499: MSG_OUTSTR(":!");
3500: msg_outtrans(IObuff); /* show what we are doing */
3501: do_shell(IObuff);
3502:
3503: #ifdef AMIGA
3504: flushbuf();
3505: /* read window status report and redraw before message */
3506: (void)char_avail();
3507: #endif
3508:
3509: if (qf_init() == OK)
3510: qf_jump(0, 0); /* display first error */
3511:
3512: vim_remove(p_ef);
3513: }
3514:
3515: /*
3516: * Redefine the argument list to 'str'.
3517: *
3518: * Return FAIL for failure, OK otherwise.
3519: */
3520: static int
3521: do_arglist(str)
3522: char_u *str;
3523: {
3524: int new_count = 0;
3525: char_u **new_files = NULL;
3526: int exp_count;
3527: char_u **exp_files;
3528: char_u **t;
3529: char_u *p;
3530: int inquote;
3531: int i;
3532:
3533: while (*str)
3534: {
3535: /*
3536: * create a new entry in new_files[]
3537: */
3538: t = (char_u **)lalloc((long_u)(sizeof(char_u *) * (new_count + 1)), TRUE);
3539: if (t != NULL)
3540: for (i = new_count; --i >= 0; )
3541: t[i] = new_files[i];
3542: vim_free(new_files);
3543: if (t == NULL)
3544: return FAIL;
3545: new_files = t;
3546: new_files[new_count++] = str;
3547:
3548: /*
3549: * isolate one argument, taking quotes
3550: */
3551: inquote = FALSE;
3552: for (p = str; *str; ++str)
3553: {
3554: /*
3555: * for MSDOS et.al. a backslash is part of a file name.
3556: * Only skip ", space and tab.
3557: */
3558: if (is_backslash(str))
3559: *p++ = *++str;
3560: else
3561: {
3562: if (!inquote && vim_isspace(*str))
3563: break;
3564: if (*str == '"')
3565: inquote ^= TRUE;
3566: else
3567: *p++ = *str;
3568: }
3569: }
3570: str = skipwhite(str);
3571: *p = NUL;
3572: }
3573:
3574: i = ExpandWildCards(new_count, new_files, &exp_count,
3575: &exp_files, FALSE, TRUE);
3576: vim_free(new_files);
3577: if (i == FAIL)
3578: return FAIL;
3579: if (exp_count == 0)
3580: {
3581: emsg(e_nomatch);
3582: return FAIL;
3583: }
3584: if (arg_exp) /* arg_files[] has been allocated, free it */
3585: FreeWild(arg_count, arg_files);
3586: else
3587: arg_exp = TRUE;
3588: arg_files = exp_files;
3589: arg_count = exp_count;
3590: arg_had_last = FALSE;
3591:
3592: /*
3593: * put all file names in the buffer list
3594: */
3595: for (i = 0; i < arg_count; ++i)
3596: (void)buflist_add(arg_files[i]);
3597:
3598: return OK;
3599: }
3600:
3601: /*
3602: * Return TRUE if "str" starts with a backslash that should be removed.
3603: * For MS-DOS, WIN32 and OS/2 this is only done when the character after the
3604: * backslash is not a normal file name character.
3605: */
3606: static int
3607: is_backslash(str)
3608: char_u *str;
3609: {
3610: #ifdef BACKSLASH_IN_FILENAME
3611: return (str[0] == '\\' && str[1] != NUL &&
3612: !(isfilechar(str[1]) && str[1] != '\\'));
3613: #else
3614: return (str[0] == '\\' && str[1] != NUL);
3615: #endif
3616: }
3617:
3618: /*
3619: * Check if we are editing the w_arg_idx file in the argument list.
3620: */
3621: void
3622: check_arg_idx()
3623: {
3624: int t;
3625:
3626: if (arg_count > 1 && (curbuf->b_filename == NULL ||
3627: curwin->w_arg_idx >= arg_count ||
3628: (t = fullpathcmp(arg_files[curwin->w_arg_idx],
3629: curbuf->b_filename)) == FPC_DIFF || t == FPC_DIFFX))
3630: curwin->w_arg_idx_invalid = TRUE;
3631: else
3632: curwin->w_arg_idx_invalid = FALSE;
3633: }
3634:
3635: void
3636: gotocmdline(clr)
3637: int clr;
3638: {
3639: msg_start();
3640: if (clr) /* clear the bottom line(s) */
3641: msg_clr_eos(); /* will reset clear_cmdline */
3642: windgoto(cmdline_row, 0);
3643: }
3644:
3645: static int
3646: check_readonly()
3647: {
3648: if (!forceit && curbuf->b_p_ro)
3649: {
3650: emsg(e_readonly);
3651: return TRUE;
3652: }
3653: return FALSE;
3654: }
3655:
3656: /*
3657: * return TRUE if buffer was changed and cannot be abandoned.
3658: */
3659: static int
3660: check_changed(buf, checkaw, mult_win)
3661: BUF *buf;
3662: int checkaw; /* do autowrite if buffer was changed */
3663: int mult_win; /* check also when several windows for the buffer */
3664: {
3665: if ( !forceit &&
3666: buf->b_changed && (mult_win || buf->b_nwindows <= 1) &&
3667: (!checkaw || autowrite(buf) == FAIL))
3668: {
3669: emsg(e_nowrtmsg);
3670: return TRUE;
3671: }
3672: return FALSE;
3673: }
3674:
3675: /*
3676: * return TRUE if any buffer was changed and cannot be abandoned.
3677: * That changed buffer becomes the current buffer.
3678: */
3679: static int
3680: check_changed_any()
3681: {
3682: BUF *buf;
3683: int save;
3684:
3685: if (!forceit)
3686: {
3687: for (buf = firstbuf; buf != NULL; buf = buf->b_next)
3688: {
3689: if (buf->b_changed)
3690: {
3691: /* There must be a wait_return for this message, do_buffer
3692: * will cause a redraw */
3693: exiting = FALSE;
3694: if (EMSG2("No write since last change for buffer \"%s\"",
3695: buf->b_xfilename == NULL ? (char_u *)"No File" :
3696: buf->b_xfilename))
3697: {
3698: save = no_wait_return;
3699: no_wait_return = FALSE;
3700: wait_return(FALSE);
3701: no_wait_return = save;
3702: }
3703: (void)do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD,
3704: buf->b_fnum, 0);
3705: return TRUE;
3706: }
3707: }
3708: }
3709: return FALSE;
3710: }
3711:
3712: /*
3713: * return FAIL if there is no filename, OK if there is one
3714: * give error message for FAIL
3715: */
3716: int
3717: check_fname()
3718: {
3719: if (curbuf->b_filename == NULL)
3720: {
3721: emsg(e_noname);
3722: return FAIL;
3723: }
3724: return OK;
3725: }
3726:
3727: /*
3728: * - if there are more files to edit
3729: * - and this is the last window
3730: * - and forceit not used
3731: * - and not repeated twice on a row
3732: * return FAIL and give error message if 'message' TRUE
3733: * return OK otherwise
3734: */
3735: static int
3736: check_more(message)
3737: int message; /* when FALSE check only, no messages */
3738: {
3739: if (!forceit && only_one_window() && arg_count > 1 && !arg_had_last &&
3740: quitmore == 0)
3741: {
3742: if (message)
3743: {
3744: EMSGN("%ld more files to edit", arg_count - curwin->w_arg_idx - 1);
3745: quitmore = 2; /* next try to quit is allowed */
3746: }
3747: return FAIL;
3748: }
3749: return OK;
3750: }
3751:
3752: /*
3753: * try to abandon current file and edit a new or existing file
3754: * 'fnum' is the number of the file, if zero use fname/sfname
3755: *
3756: * return 1 for "normal" error, 2 for "not written" error, 0 for success
3757: * -1 for succesfully opening another file
3758: * 'lnum' is the line number for the cursor in the new file (if non-zero).
3759: */
3760: int
3761: getfile(fnum, fname, sfname, setpm, lnum)
3762: int fnum;
3763: char_u *fname;
3764: char_u *sfname;
3765: int setpm;
3766: linenr_t lnum;
3767: {
3768: int other;
3769:
3770: if (fnum == 0)
3771: {
3772: fname_expand(&fname, &sfname); /* make fname full path, set sfname */
3773: other = otherfile(fname);
3774: }
3775: else
3776: other = (fnum != curbuf->b_fnum);
3777:
3778: if (other)
3779: ++no_wait_return; /* don't wait for autowrite message */
3780: if (other && !forceit && curbuf->b_nwindows == 1 &&
3781: !p_hid && curbuf->b_changed && autowrite(curbuf) == FAIL)
3782: {
3783: if (other)
3784: --no_wait_return;
3785: emsg(e_nowrtmsg);
3786: return 2; /* file has been changed */
3787: }
3788: if (other)
3789: --no_wait_return;
3790: if (setpm)
3791: setpcmark();
3792: if (!other)
3793: {
3794: if (lnum != 0)
3795: curwin->w_cursor.lnum = lnum;
3796: check_cursor();
3797: beginline(MAYBE);
3798:
3799: return 0; /* it's in the same file */
3800: }
3801: if (do_ecmd(fnum, fname, sfname, NULL, p_hid, lnum, FALSE) == OK)
3802: return -1; /* opened another file */
3803: return 1; /* error encountered */
3804: }
3805:
3806: /*
3807: * vim_strncpy()
3808: *
3809: * This is here because strncpy() does not guarantee successful results when
3810: * the to and from strings overlap. It is only currently called from nextwild()
3811: * which copies part of the command line to another part of the command line.
3812: * This produced garbage when expanding files etc in the middle of the command
3813: * line (on my terminal, anyway) -- webb.
3814: */
3815: static void
3816: vim_strncpy(to, from, len)
3817: char_u *to;
3818: char_u *from;
3819: int len;
3820: {
3821: int i;
3822:
3823: if (to <= from)
3824: {
3825: while (len-- && *from)
3826: *to++ = *from++;
3827: if (len >= 0)
3828: *to = *from; /* Copy NUL */
3829: }
3830: else
3831: {
3832: for (i = 0; i < len; i++)
3833: {
3834: to++;
3835: if (*from++ == NUL)
3836: {
3837: i++;
3838: break;
3839: }
3840: }
3841: for (; i > 0; i--)
3842: *--to = *--from;
3843: }
3844: }
3845:
3846: /*
3847: * Return FALSE if this is not an appropriate context in which to do
3848: * completion of anything, & TRUE if it is (even if there are no matches).
3849: * For the caller, this means that the character is just passed through like a
3850: * normal character (instead of being expanded). This allows :s/^I^D etc.
3851: */
3852: static int
3853: nextwild(type)
3854: int type;
3855: {
3856: int i;
3857: char_u *p1;
3858: char_u *p2;
3859: int oldlen;
3860: int difflen;
3861: int v;
3862:
3863: if (cmd_numfiles == -1)
3864: set_expand_context(cmdfirstc, cmdbuff);
3865: if (expand_context == EXPAND_UNSUCCESSFUL)
3866: {
3867: beep_flush();
3868: return OK; /* Something illegal on command line */
3869: }
3870: if (expand_context == EXPAND_NOTHING)
3871: {
3872: /* Caller can use the character as a normal char instead */
3873: return FAIL;
3874: }
3875: expand_interactively = TRUE;
3876:
3877: MSG_OUTSTR("..."); /* show that we are busy */
3878: flushbuf();
3879:
3880: i = expand_pattern - cmdbuff;
3881: oldlen = cmdpos - i;
3882:
3883: if (type == WILD_NEXT || type == WILD_PREV)
3884: {
3885: /*
3886: * Get next/previous match for a previous expanded pattern.
3887: */
3888: p2 = ExpandOne(NULL, NULL, 0, type);
3889: }
3890: else
3891: {
3892: /*
3893: * Translate string into pattern and expand it.
3894: */
3895: if ((p1 = addstar(&cmdbuff[i], oldlen)) == NULL)
3896: p2 = NULL;
3897: else
3898: {
3899: p2 = ExpandOne(p1, strnsave(&cmdbuff[i], oldlen),
3900: WILD_HOME_REPLACE, type);
3901: vim_free(p1);
3902: }
3903: }
3904:
3905: if (p2 != NULL)
3906: {
3907: if (cmdlen + (difflen = STRLEN(p2) - oldlen) > cmdbufflen - 4)
3908: v = realloc_cmdbuff(cmdlen + difflen);
3909: else
3910: v = OK;
3911: if (v == OK)
3912: {
3913: vim_strncpy(&cmdbuff[cmdpos + difflen], &cmdbuff[cmdpos],
3914: cmdlen - cmdpos);
3915: STRNCPY(&cmdbuff[i], p2, STRLEN(p2));
3916: cmdlen += difflen;
3917: cmdpos += difflen;
3918: }
3919: vim_free(p2);
3920: }
3921:
3922: redrawcmd();
3923: if (cmd_numfiles <= 0 && p2 == NULL)
3924: beep_flush();
3925: else if (cmd_numfiles == 1)
3926: (void)ExpandOne(NULL, NULL, 0, WILD_FREE); /* free expanded pattern */
3927:
3928: expand_interactively = FALSE; /* reset for next call */
3929: return OK;
3930: }
3931:
3932: #define MAXSUFLEN 30 /* maximum length of a file suffix */
3933:
3934: /*
3935: * Do wildcard expansion on the string 'str'.
3936: * Return a pointer to alloced memory containing the new string.
3937: * Return NULL for failure.
3938: *
3939: * mode = WILD_FREE: just free previously expanded matches
3940: * mode = WILD_EXPAND_FREE: normal expansion, do not keep matches
3941: * mode = WILD_EXPAND_KEEP: normal expansion, keep matches
3942: * mode = WILD_NEXT: use next match in multiple match, wrap to first
3943: * mode = WILD_PREV: use previous match in multiple match, wrap to first
3944: * mode = WILD_ALL: return all matches concatenated
3945: * mode = WILD_LONGEST: return longest matched part
3946: *
3947: * options = WILD_LIST_NOTFOUND: list entries without a match
3948: * options = WILD_HOME_REPLACE: do home_replace() for buffer names
3949: */
3950: char_u *
3951: ExpandOne(str, orig, options, mode)
3952: char_u *str;
3953: char_u *orig; /* original string which is expanded */
3954: int options;
3955: int mode;
3956: {
3957: char_u *ss = NULL;
3958: static char_u **cmd_files = NULL; /* list of input files */
3959: static int findex;
3960: static char_u *orig_save = NULL; /* kept value of orig */
3961: int i, found = 0;
3962: int multmatch = FALSE;
3963: long_u len;
3964: char_u *setsuf;
3965: int fnamelen, setsuflen;
3966: char_u suf_buf[MAXSUFLEN];
3967: char_u *p;
3968:
3969: /*
3970: * first handle the case of using an old match
3971: */
3972: if (mode == WILD_NEXT || mode == WILD_PREV)
3973: {
3974: if (cmd_numfiles > 0)
3975: {
3976: if (mode == WILD_PREV)
3977: {
3978: if (findex == -1)
3979: findex = cmd_numfiles;
3980: --findex;
3981: }
3982: else /* mode == WILD_NEXT */
3983: ++findex;
3984:
3985: /*
3986: * When wrapping around, return the original string, set findex to
3987: * -1.
3988: */
3989: if (findex < 0)
3990: {
3991: if (orig_save == NULL)
3992: findex = cmd_numfiles - 1;
3993: else
3994: findex = -1;
3995: }
3996: if (findex >= cmd_numfiles)
3997: {
3998: if (orig_save == NULL)
3999: findex = 0;
4000: else
4001: findex = -1;
4002: }
4003: if (findex == -1)
4004: return strsave(orig_save);
4005: return strsave(cmd_files[findex]);
4006: }
4007: else
4008: return NULL;
4009: }
4010:
4011: /* free old names */
4012: if (cmd_numfiles != -1 && mode != WILD_ALL && mode != WILD_LONGEST)
4013: {
4014: FreeWild(cmd_numfiles, cmd_files);
4015: cmd_numfiles = -1;
4016: vim_free(orig_save);
4017: orig_save = NULL;
4018: }
4019: findex = 0;
4020:
4021: if (mode == WILD_FREE) /* only release file name */
4022: return NULL;
4023:
4024: if (cmd_numfiles == -1)
4025: {
4026: vim_free(orig_save);
4027: orig_save = orig;
4028: if (ExpandFromContext(str, &cmd_numfiles, &cmd_files, FALSE,
4029: options) == FAIL)
4030: /* error: do nothing */;
4031: else if (cmd_numfiles == 0)
4032: {
4033: if (!expand_interactively)
4034: emsg(e_nomatch);
4035: }
4036: else
4037: {
4038: /*
4039: * If the pattern starts with a '~', replace the home diretory
4040: * with '~' again.
4041: */
4042: if (*str == '~' && (options & WILD_HOME_REPLACE))
4043: {
4044: for (i = 0; i < cmd_numfiles; ++i)
4045: {
4046: p = home_replace_save(NULL, cmd_files[i]);
4047: if (p != NULL)
4048: {
4049: vim_free(cmd_files[i]);
4050: cmd_files[i] = p;
4051: }
4052: }
4053: }
4054:
4055: /*
4056: * Insert backslashes into a file name before a space, \, %, # and
4057: * wildmatch characters, except '~'.
4058: */
4059: if (expand_interactively &&
4060: (expand_context == EXPAND_FILES ||
4061: expand_context == EXPAND_BUFFERS ||
4062: expand_context == EXPAND_DIRECTORIES))
4063: {
4064: for (i = 0; i < cmd_numfiles; ++i)
4065: {
4066: p = strsave_escaped(cmd_files[i],
4067: #ifdef BACKSLASH_IN_FILENAME
4068: (char_u *)" *?[{`$%#");
4069: #else
4070: (char_u *)" *?[{`$\\%#");
4071: #endif
4072: if (p != NULL)
4073: {
4074: vim_free(cmd_files[i]);
4075: cmd_files[i] = p;
4076: }
4077: }
4078: }
4079:
4080: if (mode != WILD_ALL && mode != WILD_LONGEST)
4081: {
4082: if (cmd_numfiles > 1) /* more than one match; check suffix */
4083: {
4084: found = -2;
4085: for (i = 0; i < cmd_numfiles; ++i)
4086: {
4087: fnamelen = STRLEN(cmd_files[i]);
4088: setsuflen = 0;
4089: for (setsuf = p_su; *setsuf; )
4090: {
4091: setsuflen = copy_option_part(&setsuf, suf_buf,
4092: MAXSUFLEN, ".,");
4093: if (fnamelen >= setsuflen && STRNCMP(suf_buf,
4094: cmd_files[i] + fnamelen - setsuflen,
4095: (size_t)setsuflen) == 0)
4096: break;
4097: setsuflen = 0;
4098: }
4099: if (setsuflen) /* suffix matched: ignore file */
4100: continue;
4101: if (found >= 0)
4102: {
4103: multmatch = TRUE;
4104: break;
4105: }
4106: found = i;
4107: }
4108: }
4109: if (multmatch || found < 0)
4110: {
4111: /* Can we ever get here unless it's while expanding
4112: * interactively? If not, we can get rid of this all
4113: * together. Don't really want to wait for this message
4114: * (and possibly have to hit return to continue!).
4115: */
4116: if (!expand_interactively)
4117: emsg(e_toomany);
4118: else
4119: beep_flush();
4120: found = 0; /* return first one */
4121: multmatch = TRUE; /* for found < 0 */
4122: }
4123: if (found >= 0 && !(multmatch && mode == WILD_EXPAND_FREE))
4124: ss = strsave(cmd_files[found]);
4125: }
4126: }
4127: }
4128:
4129: /* Find longest common part */
4130: if (mode == WILD_LONGEST && cmd_numfiles > 0)
4131: {
4132: for (len = 0; cmd_files[0][len]; ++len)
4133: {
4134: for (i = 0; i < cmd_numfiles; ++i)
4135: {
4136: #ifdef CASE_INSENSITIVE_FILENAME
4137: if ((expand_context == EXPAND_DIRECTORIES ||
4138: expand_context == EXPAND_FILES ||
4139: expand_context == EXPAND_BUFFERS) &&
4140: toupper(cmd_files[i][len]) != toupper(cmd_files[0][len]))
4141: break;
4142: else
4143: #endif
4144: if (cmd_files[i][len] != cmd_files[0][len])
4145: break;
4146: }
4147: if (i < cmd_numfiles)
4148: {
4149: vim_beep();
4150: break;
4151: }
4152: }
4153: ss = alloc((unsigned)len + 1);
4154: if (ss)
4155: {
4156: STRNCPY(ss, cmd_files[0], len);
4157: ss[len] = NUL;
4158: }
4159: findex = -1; /* next p_wc gets first one */
4160: }
4161:
4162: /* Concatenate all matching names */
4163: if (mode == WILD_ALL && cmd_numfiles > 0)
4164: {
4165: len = 0;
4166: for (i = 0; i < cmd_numfiles; ++i)
4167: len += STRLEN(cmd_files[i]) + 1;
4168: ss = lalloc(len, TRUE);
4169: if (ss)
4170: {
4171: *ss = NUL;
4172: for (i = 0; i < cmd_numfiles; ++i)
4173: {
4174: STRCAT(ss, cmd_files[i]);
4175: if (i != cmd_numfiles - 1)
4176: STRCAT(ss, " ");
4177: }
4178: }
4179: }
4180:
4181: if (mode == WILD_EXPAND_FREE || mode == WILD_ALL)
4182: {
4183: FreeWild(cmd_numfiles, cmd_files);
4184: cmd_numfiles = -1;
4185: }
4186: return ss;
4187: }
4188:
4189: /*
4190: * show all matches for completion on the command line
4191: */
4192: static int
4193: showmatches(buff)
4194: char_u *buff;
4195: {
4196: char_u *file_str;
4197: int num_files;
4198: char_u **files_found;
4199: int i, j, k;
4200: int maxlen;
4201: int lines;
4202: int columns;
4203: char_u *p;
4204: int lastlen;
4205:
4206: set_expand_context(cmdfirstc, cmdbuff);
4207: if (expand_context == EXPAND_UNSUCCESSFUL)
4208: {
4209: beep_flush();
4210: return OK; /* Something illegal on command line */
4211: }
4212: if (expand_context == EXPAND_NOTHING)
4213: {
4214: /* Caller can use the character as a normal char instead */
4215: return FAIL;
4216: }
4217: expand_interactively = TRUE;
4218:
4219: /* add star to file name, or convert to regexp if not expanding files! */
4220: file_str = addstar(expand_pattern, (int)(buff + cmdpos - expand_pattern));
4221: if (file_str == NULL)
4222: {
4223: expand_interactively = FALSE;
4224: return OK;
4225: }
4226:
4227: msg_didany = FALSE; /* lines_left will be set */
4228: msg_start(); /* prepare for paging */
4229: msg_outchar('\n');
4230: flushbuf();
4231: cmdline_row = msg_row;
4232: msg_didany = FALSE; /* lines_left will be set again */
4233: msg_start(); /* prepare for paging */
4234:
4235: /* find all files that match the description */
4236: if (ExpandFromContext(file_str, &num_files, &files_found, FALSE, 0) == FAIL)
4237: {
4238: num_files = 0;
4239: files_found = (char_u **)"";
4240: }
4241:
4242: /* find the length of the longest file name */
4243: maxlen = 0;
4244: for (i = 0; i < num_files; ++i)
4245: {
4246: if (expand_context == EXPAND_FILES || expand_context == EXPAND_BUFFERS)
4247: {
4248: home_replace(NULL, files_found[i], NameBuff, MAXPATHL);
4249: j = strsize(NameBuff);
4250: }
4251: else
4252: j = strsize(files_found[i]);
4253: if (j > maxlen)
4254: maxlen = j;
4255: }
4256:
4257: /* compute the number of columns and lines for the listing */
4258: maxlen += 2; /* two spaces between file names */
4259: columns = ((int)Columns + 2) / maxlen;
4260: if (columns < 1)
4261: columns = 1;
4262: lines = (num_files + columns - 1) / columns;
4263:
4264: (void)set_highlight('d'); /* find out highlight mode for directories */
4265:
4266: /* list the files line by line */
4267: for (i = 0; i < lines; ++i)
4268: {
4269: lastlen = 999;
4270: for (k = i; k < num_files; k += lines)
4271: {
4272: for (j = maxlen - lastlen; --j >= 0; )
4273: msg_outchar(' ');
4274: if (expand_context == EXPAND_FILES ||
4275: expand_context == EXPAND_BUFFERS)
4276: {
4277: /* highlight directories */
4278: j = (mch_isdir(files_found[k]));
4279: home_replace(NULL, files_found[k], NameBuff, MAXPATHL);
4280: p = NameBuff;
4281: }
4282: else
4283: {
4284: j = FALSE;
4285: p = files_found[k];
4286: }
4287: if (j)
4288: start_highlight();
4289: lastlen = msg_outtrans(p);
4290: if (j)
4291: stop_highlight();
4292: }
4293: msg_outchar('\n');
4294: flushbuf(); /* show one line at a time */
4295: if (got_int)
4296: {
4297: got_int = FALSE;
4298: break;
4299: }
4300: }
4301: vim_free(file_str);
4302: FreeWild(num_files, files_found);
4303:
4304: /*
4305: * we redraw the command below the lines that we have just listed
4306: * This is a bit tricky, but it saves a lot of screen updating.
4307: */
4308: cmdline_row = msg_row; /* will put it back later */
4309:
4310: expand_interactively = FALSE;
4311: return OK;
4312: }
4313:
4314: /*
4315: * Prepare a string for expansion.
4316: * When expanding file names: The string will be used with ExpandWildCards().
4317: * Copy the file name into allocated memory and add a '*' at the end.
4318: * When expanding other names: The string will be used with regcomp(). Copy
4319: * the name into allocated memory and add ".*" at the end.
4320: */
4321: char_u *
4322: addstar(fname, len)
4323: char_u *fname;
4324: int len;
4325: {
4326: char_u *retval;
4327: int i, j;
4328: int new_len;
4329: char_u *tail;
4330:
4331: if (expand_interactively && expand_context != EXPAND_FILES &&
4332: expand_context != EXPAND_DIRECTORIES)
4333: {
4334: /*
4335: * Matching will be done internally (on something other than files).
4336: * So we convert the file-matching-type wildcards into our kind for
4337: * use with vim_regcomp(). First work out how long it will be:
4338: */
4339:
4340: /* for help tags the translation is done in find_help_tags() */
4341: if (expand_context == EXPAND_HELP)
4342: retval = strnsave(fname, len);
4343: else
4344: {
4345: new_len = len + 2; /* +2 for '^' at start, NUL at end */
4346: for (i = 0; i < len; i++)
4347: {
4348: if (fname[i] == '*' || fname[i] == '~')
4349: new_len++; /* '*' needs to be replaced by ".*"
4350: '~' needs to be replaced by "\~" */
4351:
4352: /* Buffer names are like file names. "." should be literal */
4353: if (expand_context == EXPAND_BUFFERS && fname[i] == '.')
4354: new_len++; /* "." becomes "\." */
4355: }
4356: retval = alloc(new_len);
4357: if (retval != NULL)
4358: {
4359: retval[0] = '^';
4360: j = 1;
4361: for (i = 0; i < len; i++, j++)
4362: {
4363: if (fname[i] == '\\' && ++i == len) /* skip backslash */
4364: break;
4365:
4366: switch (fname[i])
4367: {
4368: case '*': retval[j++] = '.';
4369: break;
4370: case '~': retval[j++] = '\\';
4371: break;
4372: case '?': retval[j] = '.';
4373: continue;
4374: case '.': if (expand_context == EXPAND_BUFFERS)
4375: retval[j++] = '\\';
4376: break;
4377: }
4378: retval[j] = fname[i];
4379: }
4380: retval[j] = NUL;
4381: }
4382: }
4383: }
4384: else
4385: {
4386: retval = alloc(len + 4);
4387: if (retval != NULL)
4388: {
4389: STRNCPY(retval, fname, len);
4390: retval[len] = NUL;
4391: backslash_halve(retval, TRUE); /* remove some backslashes */
4392: len = STRLEN(retval);
4393:
4394: /*
4395: * Don't add a star to ~, ~user, $var or `cmd`.
4396: * ~ would be at the start of the tail.
4397: * $ could be anywhere in the tail.
4398: * ` could be anywhere in the file name.
4399: */
4400: tail = gettail(retval);
4401: if (*tail != '~' && vim_strchr(tail, '$') == NULL
4402: && vim_strchr(retval, '`') == NULL)
4403: {
4404: #ifdef MSDOS
4405: /*
4406: * if there is no dot in the file name, add "*.*" instead of
4407: * "*".
4408: */
4409: for (i = len - 1; i >= 0; --i)
4410: if (vim_strchr((char_u *)".\\/:", retval[i]) != NULL)
4411: break;
4412: if (i < 0 || retval[i] != '.')
4413: {
4414: retval[len++] = '*';
4415: retval[len++] = '.';
4416: }
4417: #endif
4418: retval[len++] = '*';
4419: }
4420: retval[len] = NUL;
4421: }
4422: }
4423: return retval;
4424: }
4425:
4426: /*
4427: * do_source: read the file "fname" and execute its lines as EX commands
4428: *
4429: * This function may be called recursively!
4430: *
4431: * return FAIL if file could not be opened, OK otherwise
4432: */
4433: int
4434: do_source(fname, check_other)
4435: register char_u *fname;
4436: int check_other; /* check for .vimrc and _vimrc */
4437: {
4438: register FILE *fp;
4439: register int len;
4440: #ifdef USE_CRNL
4441: int has_cr;
4442: int textmode = -1; /* -1 = unknown, 0 = NL, 1 = CR-NL */
4443: int error = FALSE;
4444: #endif
4445: /* use NameBuff for expanded name */
4446: expand_env(fname, NameBuff, MAXPATHL);
4447: fp = fopen((char *)NameBuff, READBIN);
4448: if (fp == NULL && check_other)
4449: {
4450: /*
4451: * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa
4452: * (if applicable)
4453: */
4454: len = STRLEN(NameBuff);
4455: if (((len > 6 && ispathsep(NameBuff[len - 7])) || len == 6) &&
4456: (NameBuff[len - 6] == '.' || NameBuff[len - 6] == '_') &&
4457: (STRCMP(&NameBuff[len - 5], "vimrc") == 0))
4458: {
4459: if (NameBuff[len - 6] == '_')
4460: NameBuff[len - 6] = '.';
4461: else
4462: NameBuff[len - 6] = '_';
4463: fp = fopen((char *)NameBuff, READBIN);
4464: }
4465: }
4466:
4467: if (fp == NULL)
4468: return FAIL;
4469:
4470: #ifdef USE_CRNL
4471: /* no automatic textmode: Set default to CR-NL */
4472: if (!p_ta)
4473: textmode = 1;
4474: #endif
4475: sourcing_name = fname;
4476: sourcing_lnum = 1;
4477: #ifdef SLEEP_IN_EMSG
4478: ++dont_sleep; /* don't call sleep() in emsg() */
4479: #endif
4480: len = 0;
4481: while (fgets((char *)IObuff + len, IOSIZE - len, fp) != NULL && !got_int)
4482: {
4483: len = STRLEN(IObuff) - 1;
4484: if (len >= 0 && IObuff[len] == '\n') /* remove trailing newline */
4485: {
4486: #ifdef USE_CRNL
4487: has_cr = (len > 0 && IObuff[len - 1] == '\r');
4488: if (textmode == -1)
4489: {
4490: if (has_cr)
4491: textmode = 1;
4492: else
4493: textmode = 0;
4494: }
4495:
4496: if (textmode)
4497: {
4498: if (has_cr) /* remove trailing CR-LF */
4499: --len;
4500: else /* lines like ":map xx yy^M" will have failed */
4501: {
4502: if (!error)
4503: EMSG("Warning: Wrong line separator, ^M may be missing");
4504: error = TRUE;
4505: textmode = 0;
4506: }
4507: }
4508: #endif
4509: /* escaped newline, read more */
4510: if (len > 0 && len < IOSIZE && IObuff[len - 1] == Ctrl('V'))
4511: {
4512: IObuff[len - 1] = '\n'; /* remove CTRL-V */
4513: ++sourcing_lnum;
4514: continue;
4515: }
4516: IObuff[len] = NUL;
4517: }
4518: /* check for ^C here, so recursive :so will be broken */
4519: mch_breakcheck();
4520: do_cmdline(IObuff, TRUE, TRUE);
4521: len = 0;
4522: ++sourcing_lnum;
4523: }
4524: fclose(fp);
4525: if (got_int)
4526: emsg(e_interr);
4527: #ifdef SLEEP_IN_EMSG
4528: --dont_sleep;
4529: #endif
4530: sourcing_name = NULL;
4531: sourcing_lnum = 0;
4532: return OK;
4533: }
4534:
4535: /*
4536: * get a single EX address
4537: *
4538: * Set ptr to the next character after the part that was interpreted.
4539: * Set ptr to NULL when an error is encountered.
4540: */
4541: static linenr_t
4542: get_address(ptr)
4543: char_u **ptr;
4544: {
4545: linenr_t cursor_lnum = curwin->w_cursor.lnum;
4546: int c;
4547: int i;
4548: long n;
4549: char_u *cmd;
4550: FPOS pos;
4551: FPOS *fp;
4552: linenr_t lnum;
4553:
4554: cmd = skipwhite(*ptr);
4555: lnum = MAXLNUM;
4556: do
4557: {
4558: switch (*cmd)
4559: {
4560: case '.': /* '.' - Cursor position */
4561: ++cmd;
4562: lnum = cursor_lnum;
4563: break;
4564:
4565: case '$': /* '$' - last line */
4566: ++cmd;
4567: lnum = curbuf->b_ml.ml_line_count;
4568: break;
4569:
4570: case '\'': /* ''' - mark */
4571: if (*++cmd == NUL || (check_mark(
4572: fp = getmark(*cmd++, FALSE)) == FAIL))
4573: goto error;
4574: lnum = fp->lnum;
4575: break;
4576:
4577: case '/':
4578: case '?': /* '/' or '?' - search */
4579: c = *cmd++;
4580: pos = curwin->w_cursor; /* save curwin->w_cursor */
4581: if (c == '/') /* forward search, start on next line */
4582: {
4583: ++curwin->w_cursor.lnum;
4584: curwin->w_cursor.col = 0;
4585: }
4586: else /* backward search, start on prev line */
4587: {
4588: --curwin->w_cursor.lnum;
4589: curwin->w_cursor.col = MAXCOL;
4590: }
4591: searchcmdlen = 0;
4592: if (!do_search(c, cmd, 1L,
4593: SEARCH_HIS + SEARCH_MSG + SEARCH_START))
4594: {
4595: cmd = NULL;
4596: curwin->w_cursor = pos;
4597: goto error;
4598: }
4599: lnum = curwin->w_cursor.lnum;
4600: curwin->w_cursor = pos;
4601: /* adjust command string pointer */
4602: cmd += searchcmdlen;
4603: break;
4604:
4605: case '\\': /* "\?", "\/" or "\&", repeat search */
4606: ++cmd;
4607: if (*cmd == '&')
4608: i = RE_SUBST;
4609: else if (*cmd == '?' || *cmd == '/')
4610: i = RE_SEARCH;
4611: else
4612: {
4613: emsg(e_backslash);
4614: cmd = NULL;
4615: goto error;
4616: }
4617:
4618: /* forward search, start on next line */
4619: if (*cmd != '?')
4620: {
4621: pos.lnum = curwin->w_cursor.lnum + 1;
4622: pos.col = 0;
4623: }
4624: /* backward search, start on prev line */
4625: else
4626: {
4627: pos.lnum = curwin->w_cursor.lnum - 1;
4628: pos.col = MAXCOL;
4629: }
4630: if (searchit(&pos, *cmd == '?' ? BACKWARD : FORWARD,
4631: (char_u *)"", 1L,
4632: SEARCH_MSG + SEARCH_START, i) == OK)
4633: lnum = pos.lnum;
4634: else
4635: {
4636: cmd = NULL;
4637: goto error;
4638: }
4639: ++cmd;
4640: break;
4641:
4642: default:
4643: if (isdigit(*cmd)) /* absolute line number */
4644: lnum = getdigits(&cmd);
4645: }
4646:
4647: for (;;)
4648: {
4649: cmd = skipwhite(cmd);
4650: if (*cmd != '-' && *cmd != '+' && !isdigit(*cmd))
4651: break;
4652:
4653: if (lnum == MAXLNUM)
4654: lnum = cursor_lnum; /* "+1" is same as ".+1" */
4655: if (isdigit(*cmd))
4656: i = '+'; /* "number" is same as "+number" */
4657: else
4658: i = *cmd++;
4659: if (!isdigit(*cmd)) /* '+' is '+1', but '+0' is not '+1' */
4660: n = 1;
4661: else
4662: n = getdigits(&cmd);
4663: if (i == '-')
4664: lnum -= n;
4665: else
4666: lnum += n;
4667: }
4668: cursor_lnum = lnum;
4669: } while (*cmd == '/' || *cmd == '?');
4670:
4671: error:
4672: *ptr = cmd;
4673: return lnum;
4674: }
4675:
4676:
4677: /*
4678: * Must parse the command line so far to work out what context we are in.
4679: * Completion can then be done based on that context.
4680: * This routine sets two global variables:
4681: * char_u *expand_pattern The start of the pattern to be expanded within
4682: * the command line (ends at the cursor).
4683: * int expand_context The type of thing to expand. Will be one of:
4684: *
4685: * EXPAND_UNSUCCESSFUL Used sometimes when there is something illegal on
4686: * the command line, like an unknown command. Caller
4687: * should beep.
4688: * EXPAND_NOTHING Unrecognised context for completion, use char like
4689: * a normal char, rather than for completion. eg
4690: * :s/^I/
4691: * EXPAND_COMMANDS Cursor is still touching the command, so complete
4692: * it.
4693: * EXPAND_BUFFERS Complete file names for :buf and :sbuf commands.
4694: * EXPAND_FILES After command with XFILE set, or after setting
4695: * with P_EXPAND set. eg :e ^I, :w>>^I
4696: * EXPAND_DIRECTORIES In some cases this is used instead of the latter
4697: * when we know only directories are of interest. eg
4698: * :set dir=^I
4699: * EXPAND_SETTINGS Complete variable names. eg :set d^I
4700: * EXPAND_BOOL_SETTINGS Complete boolean variables only, eg :set no^I
4701: * EXPAND_TAGS Complete tags from the files in p_tags. eg :ta a^I
4702: * EXPAND_HELP Complete tags from the file 'helpfile'/vim_tags
4703: * EXPAND_EVENTS Complete event names
4704: *
4705: * -- webb.
4706: */
4707: static void
4708: set_expand_context(firstc, buff)
4709: int firstc; /* either ':', '/', or '?' */
4710: char_u *buff; /* buffer for command string */
4711: {
4712: char_u *nextcomm;
4713: char_u old_char;
4714:
4715: old_char = cmdbuff[cmdpos];
4716: cmdbuff[cmdpos] = NUL;
4717: nextcomm = buff;
4718: while (nextcomm != NULL)
4719: nextcomm = set_one_cmd_context(firstc, nextcomm);
4720: cmdbuff[cmdpos] = old_char;
4721: }
4722:
4723: /*
4724: * This is all pretty much copied from do_one_cmd(), with all the extra stuff
4725: * we don't need/want deleted. Maybe this could be done better if we didn't
4726: * repeat all this stuff. The only problem is that they may not stay perfectly
4727: * compatible with each other, but then the command line syntax probably won't
4728: * change that much -- webb.
4729: */
4730: static char_u *
4731: set_one_cmd_context(firstc, buff)
4732: int firstc; /* either ':', '/', or '?' */
4733: char_u *buff; /* buffer for command string */
4734: {
4735: char_u *p;
4736: char_u *cmd, *arg;
4737: int i;
4738: int cmdidx;
4739: long argt;
4740: char_u delim;
4741: int forced = FALSE;
4742: int usefilter = FALSE; /* filter instead of file name */
4743:
4744: expand_pattern = buff;
4745: if (firstc != ':')
4746: {
4747: expand_context = EXPAND_NOTHING;
4748: return NULL;
4749: }
4750: expand_context = EXPAND_COMMANDS; /* Default until we get past command */
4751:
4752: /*
4753: * 2. skip comment lines and leading space, colons or bars
4754: */
4755: for (cmd = buff; vim_strchr((char_u *)" \t:|", *cmd) != NULL; cmd++)
4756: ;
4757: expand_pattern = cmd;
4758:
4759: if (*cmd == NUL)
4760: return NULL;
4761: if (*cmd == '"') /* ignore comment lines */
4762: {
4763: expand_context = EXPAND_NOTHING;
4764: return NULL;
4765: }
4766:
4767: /*
4768: * 3. parse a range specifier of the form: addr [,addr] [;addr] ..
4769: */
4770: /*
4771: * Backslashed delimiters after / or ? will be skipped, and commands will
4772: * not be expanded between /'s and ?'s or after "'". -- webb
4773: */
4774: while (*cmd != NUL && (vim_isspace(*cmd) || isdigit(*cmd) ||
4775: vim_strchr((char_u *)".$%'/?-+,;", *cmd) != NULL))
4776: {
4777: if (*cmd == '\'')
4778: {
4779: if (*++cmd == NUL)
4780: expand_context = EXPAND_NOTHING;
4781: }
4782: else if (*cmd == '/' || *cmd == '?')
4783: {
4784: delim = *cmd++;
4785: while (*cmd != NUL && *cmd != delim)
4786: if (*cmd++ == '\\' && *cmd != NUL)
4787: ++cmd;
4788: if (*cmd == NUL)
4789: expand_context = EXPAND_NOTHING;
4790: }
4791: if (*cmd != NUL)
4792: ++cmd;
4793: }
4794:
4795: /*
4796: * 4. parse command
4797: */
4798:
4799: cmd = skipwhite(cmd);
4800: expand_pattern = cmd;
4801: if (*cmd == NUL)
4802: return NULL;
4803: if (*cmd == '"')
4804: {
4805: expand_context = EXPAND_NOTHING;
4806: return NULL;
4807: }
4808:
4809: if (*cmd == '|' || *cmd == '\n')
4810: return cmd + 1; /* There's another command */
4811:
4812: /*
4813: * Isolate the command and search for it in the command table.
4814: * Exeptions:
4815: * - the 'k' command can directly be followed by any character.
4816: * - the 's' command can be followed directly by 'c', 'g' or 'r'
4817: */
4818: if (*cmd == 'k')
4819: {
4820: cmdidx = CMD_k;
4821: p = cmd + 1;
4822: }
4823: else
4824: {
4825: p = cmd;
4826: while (isalpha(*p) || *p == '*') /* Allow * wild card */
4827: ++p;
4828: /* check for non-alpha command */
4829: if (p == cmd && vim_strchr((char_u *)"@!=><&~#", *p) != NULL)
4830: ++p;
4831: i = (int)(p - cmd);
4832:
4833: if (i == 0)
4834: {
4835: expand_context = EXPAND_UNSUCCESSFUL;
4836: return NULL;
4837: }
4838: for (cmdidx = 0; cmdidx < CMD_SIZE; ++cmdidx)
4839: if (STRNCMP(cmdnames[cmdidx].cmd_name, cmd, (size_t)i) == 0)
4840: break;
4841: }
4842:
4843: /*
4844: * If the cursor is touching the command, and it ends in an alphabetic
4845: * character, complete the command name.
4846: */
4847: if (p == cmdbuff + cmdpos && isalpha(p[-1]))
4848: return NULL;
4849:
4850: if (cmdidx == CMD_SIZE)
4851: {
4852: if (*cmd == 's' && vim_strchr((char_u *)"cgr", cmd[1]) != NULL)
4853: {
4854: cmdidx = CMD_substitute;
4855: p = cmd + 1;
4856: }
4857: else
4858: {
4859: /* Not still touching the command and it was an illegal command */
4860: expand_context = EXPAND_UNSUCCESSFUL;
4861: return NULL;
4862: }
4863: }
4864:
4865: expand_context = EXPAND_NOTHING; /* Default now that we're past command */
4866:
4867: if (*p == '!') /* forced commands */
4868: {
4869: forced = TRUE;
4870: ++p;
4871: }
4872:
4873: /*
4874: * 5. parse arguments
4875: */
4876: argt = cmdnames[cmdidx].cmd_argt;
4877:
4878: arg = skipwhite(p);
4879:
4880: if (cmdidx == CMD_write)
4881: {
4882: if (*arg == '>') /* append */
4883: {
4884: if (*++arg == '>') /* It should be */
4885: ++arg;
4886: arg = skipwhite(arg);
4887: }
4888: else if (*arg == '!') /* :w !filter */
4889: {
4890: ++arg;
4891: usefilter = TRUE;
4892: }
4893: }
4894:
4895: if (cmdidx == CMD_read)
4896: {
4897: usefilter = forced; /* :r! filter if forced */
4898: if (*arg == '!') /* :r !filter */
4899: {
4900: ++arg;
4901: usefilter = TRUE;
4902: }
4903: }
4904:
4905: if (cmdidx == CMD_lshift || cmdidx == CMD_rshift)
4906: {
4907: while (*arg == *cmd) /* allow any number of '>' or '<' */
4908: ++arg;
4909: arg = skipwhite(arg);
4910: }
4911:
4912: /* Does command allow "+command"? */
4913: if ((argt & EDITCMD) && !usefilter && *arg == '+')
4914: {
4915: /* Check if we're in the +command */
4916: p = arg + 1;
4917: arg = skiptowhite(arg);
4918:
4919: /* Still touching the command after '+'? */
4920: if (arg >= cmdbuff + cmdpos)
4921: return p;
4922:
4923: /* Skip space after +command to get to the real argument */
4924: arg = skipwhite(arg);
4925: }
4926:
4927: /*
4928: * Check for '|' to separate commands and '"' to start comments.
4929: * Don't do this for ":read !cmd" and ":write !cmd".
4930: */
4931: if ((argt & TRLBAR) && !usefilter)
4932: {
4933: p = arg;
4934: while (*p)
4935: {
4936: if (*p == Ctrl('V'))
4937: {
4938: if (p[1] != NUL)
4939: ++p;
4940: }
4941: else if ((*p == '"' && !(argt & NOTRLCOM)) || *p == '|' || *p == '\n')
4942: {
4943: if (*(p - 1) != '\\')
4944: {
4945: if (*p == '|' || *p == '\n')
4946: return p + 1;
4947: return NULL; /* It's a comment */
4948: }
4949: }
4950: ++p;
4951: }
4952: }
4953:
4954: /* no arguments allowed */
4955: if (!(argt & EXTRA) && *arg != NUL &&
4956: vim_strchr((char_u *)"|\"", *arg) == NULL)
4957: return NULL;
4958:
4959: /* Find start of last argument (argument just before cursor): */
4960: p = cmdbuff + cmdpos;
4961: while (p != arg && *p != ' ' && *p != TAB)
4962: p--;
4963: if (*p == ' ' || *p == TAB)
4964: p++;
4965: expand_pattern = p;
4966:
4967: if (argt & XFILE)
4968: {
4969: int in_quote = FALSE;
4970: char_u *bow = NULL; /* Beginning of word */
4971:
4972: /*
4973: * Allow spaces within back-quotes to count as part of the argument
4974: * being expanded.
4975: */
4976: expand_pattern = skipwhite(arg);
4977: for (p = expand_pattern; *p; ++p)
4978: {
4979: if (*p == '\\' && p[1])
4980: ++p;
4981: #ifdef SPACE_IN_FILENAME
4982: else if (vim_iswhite(*p) && (!(argt & NOSPC) || usefilter))
4983: #else
4984: else if (vim_iswhite(*p))
4985: #endif
4986: {
4987: p = skipwhite(p);
4988: if (in_quote)
4989: bow = p;
4990: else
4991: expand_pattern = p;
4992: --p;
4993: }
4994: else if (*p == '`')
4995: {
4996: if (!in_quote)
4997: {
4998: expand_pattern = p;
4999: bow = p + 1;
5000: }
5001: in_quote = !in_quote;
5002: }
5003: }
5004:
5005: /*
5006: * If we are still inside the quotes, and we passed a space, just
5007: * expand from there.
5008: */
5009: if (bow != NULL && in_quote)
5010: expand_pattern = bow;
5011: expand_context = EXPAND_FILES;
5012: }
5013:
5014: /*
5015: * 6. switch on command name
5016: */
5017: switch (cmdidx)
5018: {
5019: case CMD_cd:
5020: case CMD_chdir:
5021: expand_context = EXPAND_DIRECTORIES;
5022: break;
5023: case CMD_global:
5024: case CMD_vglobal:
5025: delim = *arg; /* get the delimiter */
5026: if (delim)
5027: ++arg; /* skip delimiter if there is one */
5028:
5029: while (arg[0] != NUL && arg[0] != delim)
5030: {
5031: if (arg[0] == '\\' && arg[1] != NUL)
5032: ++arg;
5033: ++arg;
5034: }
5035: if (arg[0] != NUL)
5036: return arg + 1;
5037: break;
5038: case CMD_and:
5039: case CMD_substitute:
5040: delim = *arg;
5041: if (delim)
5042: ++arg;
5043: for (i = 0; i < 2; i++)
5044: {
5045: while (arg[0] != NUL && arg[0] != delim)
5046: {
5047: if (arg[0] == '\\' && arg[1] != NUL)
5048: ++arg;
5049: ++arg;
5050: }
5051: if (arg[0] != NUL) /* skip delimiter */
5052: ++arg;
5053: }
5054: while (arg[0] && vim_strchr((char_u *)"|\"#", arg[0]) == NULL)
5055: ++arg;
5056: if (arg[0] != NUL)
5057: return arg;
5058: break;
5059: case CMD_isearch:
5060: case CMD_dsearch:
5061: case CMD_ilist:
5062: case CMD_dlist:
5063: case CMD_ijump:
5064: case CMD_djump:
5065: case CMD_isplit:
5066: case CMD_dsplit:
5067: arg = skipwhite(skipdigits(arg)); /* skip count */
5068: if (*arg == '/') /* Match regexp, not just whole words */
5069: {
5070: for (++arg; *arg && *arg != '/'; arg++)
5071: if (*arg == '\\' && arg[1] != NUL)
5072: arg++;
5073: if (*arg)
5074: {
5075: arg = skipwhite(arg + 1);
5076:
5077: /* Check for trailing illegal characters */
5078: if (*arg && vim_strchr((char_u *)"|\"\n", *arg) == NULL)
5079: expand_context = EXPAND_NOTHING;
5080: else
5081: return arg;
5082: }
5083: }
5084: break;
5085: #ifdef AUTOCMD
5086: case CMD_autocmd:
5087: return set_context_in_autocmd(arg, FALSE);
5088:
5089: case CMD_doautocmd:
5090: return set_context_in_autocmd(arg, TRUE);
5091: #endif
5092: case CMD_set:
5093: set_context_in_set_cmd(arg);
5094: break;
5095: case CMD_stag:
5096: case CMD_tag:
5097: expand_context = EXPAND_TAGS;
5098: expand_pattern = arg;
5099: break;
5100: case CMD_help:
5101: expand_context = EXPAND_HELP;
5102: expand_pattern = arg;
5103: break;
5104: case CMD_bdelete:
5105: case CMD_bunload:
5106: while ((expand_pattern = vim_strchr(arg, ' ')) != NULL)
5107: arg = expand_pattern + 1;
5108: case CMD_buffer:
5109: case CMD_sbuffer:
5110: expand_context = EXPAND_BUFFERS;
5111: expand_pattern = arg;
5112: break;
5113: #ifdef USE_GUI
5114: case CMD_menu: case CMD_noremenu: case CMD_unmenu:
5115: case CMD_nmenu: case CMD_nnoremenu: case CMD_nunmenu:
5116: case CMD_vmenu: case CMD_vnoremenu: case CMD_vunmenu:
5117: case CMD_imenu: case CMD_inoremenu: case CMD_iunmenu:
5118: case CMD_cmenu: case CMD_cnoremenu: case CMD_cunmenu:
5119: return gui_set_context_in_menu_cmd(cmd, arg, forced);
5120: break;
5121: #endif
5122: default:
5123: break;
5124: }
5125: return NULL;
5126: }
5127:
5128: /*
5129: * Do the expansion based on the global variables expand_context and
5130: * expand_pattern -- webb.
5131: */
5132: static int
5133: ExpandFromContext(pat, num_file, file, files_only, options)
5134: char_u *pat;
5135: int *num_file;
5136: char_u ***file;
5137: int files_only;
5138: int options;
5139: {
5140: regexp *prog;
5141: int ret;
5142: int i;
5143: int count;
5144:
5145: if (!expand_interactively || expand_context == EXPAND_FILES)
5146: return ExpandWildCards(1, &pat, num_file, file, files_only,
5147: (options & WILD_LIST_NOTFOUND));
5148: else if (expand_context == EXPAND_DIRECTORIES)
5149: {
5150: if (ExpandWildCards(1, &pat, num_file, file, files_only,
5151: (options & WILD_LIST_NOTFOUND)) == FAIL)
5152: return FAIL;
5153: count = 0;
5154: for (i = 0; i < *num_file; i++)
5155: if (mch_isdir((*file)[i]))
5156: (*file)[count++] = (*file)[i];
5157: else
5158: vim_free((*file)[i]);
5159: if (count == 0)
5160: {
5161: vim_free(*file);
5162: *file = (char_u **)"";
5163: *num_file = -1;
5164: return FAIL;
5165: }
5166: *num_file = count;
5167: return OK;
5168: }
5169: *file = (char_u **)"";
5170: *num_file = 0;
5171: if (expand_context == EXPAND_OLD_SETTING)
5172: return ExpandOldSetting(num_file, file);
5173:
5174: if (expand_context == EXPAND_HELP)
5175: return find_help_tags(pat, num_file, file);
5176:
5177: set_reg_ic(pat); /* set reg_ic according to p_ic, p_scs and pat */
5178: #ifdef AUTOCMD
5179: if (expand_context == EXPAND_EVENTS)
5180: reg_ic = TRUE; /* always ignore case for events */
5181: #endif
5182: reg_magic = p_magic;
5183:
5184: if (expand_context == EXPAND_BUFFERS)
5185: return ExpandBufnames(pat, num_file, file, options);
5186:
5187: prog = vim_regcomp(pat);
5188: if (prog == NULL)
5189: return FAIL;
5190:
5191: if (expand_context == EXPAND_COMMANDS)
5192: ret = ExpandCommands(prog, num_file, file);
5193: else if (expand_context == EXPAND_SETTINGS ||
5194: expand_context == EXPAND_BOOL_SETTINGS)
5195: ret = ExpandSettings(prog, num_file, file);
5196: else if (expand_context == EXPAND_TAGS)
5197: ret = find_tags(NULL, prog, num_file, file, FALSE);
5198: #ifdef AUTOCMD
5199: else if (expand_context == EXPAND_EVENTS)
5200: ret = ExpandEvents(prog, num_file, file);
5201: #endif
5202: #ifdef USE_GUI
5203: else if (expand_context == EXPAND_MENUS)
5204: ret = gui_ExpandMenuNames(prog, num_file, file);
5205: #endif
5206: else
5207: ret = FAIL;
5208:
5209: vim_free(prog);
5210: return ret;
5211: }
5212:
5213: static int
5214: ExpandCommands(prog, num_file, file)
5215: regexp *prog;
5216: int *num_file;
5217: char_u ***file;
5218: {
5219: int cmdidx;
5220: int count;
5221: int round;
5222:
5223: /*
5224: * round == 1: Count the matches.
5225: * round == 2: Save the matches into the array.
5226: */
5227: for (round = 1; round <= 2; ++round)
5228: {
5229: count = 0;
5230: for (cmdidx = 0; cmdidx < CMD_SIZE; cmdidx++)
5231: if (vim_regexec(prog, cmdnames[cmdidx].cmd_name, TRUE))
5232: {
5233: if (round == 1)
5234: count++;
5235: else
5236: (*file)[count++] = strsave(cmdnames[cmdidx].cmd_name);
5237: }
5238: if (round == 1)
5239: {
5240: *num_file = count;
5241: if (count == 0 || (*file = (char_u **)
5242: alloc((unsigned)(count * sizeof(char_u *)))) == NULL)
5243: return FAIL;
5244: }
5245: }
5246: return OK;
5247: }
5248:
5249: #ifdef VIMINFO
5250: static char_u **viminfo_history[2] = {NULL, NULL};
5251: static int viminfo_hisidx[2] = {0, 0};
5252: static int viminfo_hislen = 0;
5253: static int viminfo_add_at_front = FALSE;
5254:
5255: void
5256: prepare_viminfo_history(len)
5257: int len;
5258: {
5259: int i;
5260: int num;
5261: int type;
5262:
5263: init_history();
5264: viminfo_add_at_front = (len != 0);
5265: if (len > hislen)
5266: len = hislen;
5267:
5268: for (type = 0; type <= 1; ++type)
5269: {
5270: /* If there are more spaces available than we request, then fill them
5271: * up */
5272: for (i = 0, num = 0; i < hislen; i++)
5273: if (history[type][i] == NULL)
5274: num++;
5275: if (num > len)
5276: len = num;
5277: viminfo_hisidx[type] = 0;
5278: if (len <= 0)
5279: viminfo_history[type] = NULL;
5280: else
5281: viminfo_history[type] = (char_u **)lalloc(len * sizeof(char_u *),
5282: FALSE);
5283: }
5284: viminfo_hislen = len;
5285: if (viminfo_history[0] == NULL || viminfo_history[1] == NULL)
5286: viminfo_hislen = 0;
5287: }
5288:
5289: int
5290: read_viminfo_history(line, fp)
5291: char_u *line;
5292: FILE *fp;
5293: {
5294: int type;
5295:
5296: type = (line[0] == ':' ? 0 : 1);
5297: if (viminfo_hisidx[type] != viminfo_hislen)
5298: {
5299: viminfo_readstring(line);
5300: if (!is_in_history(type, line + 1, viminfo_add_at_front))
5301: viminfo_history[type][viminfo_hisidx[type]++] = strsave(line + 1);
5302: }
5303: return vim_fgets(line, LSIZE, fp);
5304: }
5305:
5306: void
5307: finish_viminfo_history()
5308: {
5309: int idx;
5310: int i;
5311: int type;
5312:
5313: for (type = 0; type <= 1; ++type)
5314: {
5315: if (history[type] == NULL)
5316: return;
5317: idx = hisidx[type] + viminfo_hisidx[type];
5318: if (idx >= hislen)
5319: idx -= hislen;
5320: if (viminfo_add_at_front)
5321: hisidx[type] = idx;
5322: else
5323: {
5324: if (hisidx[type] == -1)
5325: hisidx[type] = hislen - 1;
5326: do
5327: {
5328: if (history[type][idx] != NULL)
5329: break;
5330: if (++idx == hislen)
5331: idx = 0;
5332: } while (idx != hisidx[type]);
5333: if (idx != hisidx[type] && --idx < 0)
5334: idx = hislen - 1;
5335: }
5336: for (i = 0; i < viminfo_hisidx[type]; i++)
5337: {
5338: history[type][idx] = viminfo_history[type][i];
5339: if (--idx < 0)
5340: idx = hislen - 1;
5341: }
5342: vim_free(viminfo_history[type]);
5343: viminfo_history[type] = NULL;
5344: }
5345: }
5346:
5347: void
5348: write_viminfo_history(fp)
5349: FILE *fp;
5350: {
5351: int i;
5352: int type;
5353: int num_saved;
5354:
5355: init_history();
5356: if (hislen == 0)
5357: return;
5358: for (type = 0; type <= 1; ++type)
5359: {
5360: num_saved = get_viminfo_parameter(type == 0 ? ':' : '/');
5361: if (num_saved == 0)
5362: continue;
5363: if (num_saved < 0) /* Use default */
5364: num_saved = hislen;
5365: fprintf(fp, "\n# %s History (newest to oldest):\n",
5366: type == 0 ? "Command Line" : "Search String");
5367: if (num_saved > hislen)
5368: num_saved = hislen;
5369: i = hisidx[type];
5370: if (i >= 0)
5371: while (num_saved--)
5372: {
5373: if (history[type][i] != NULL)
5374: {
5375: putc(type == 0 ? ':' : '?', fp);
5376: viminfo_writestring(fp, history[type][i]);
5377: }
5378: if (--i < 0)
5379: i = hislen - 1;
5380: }
5381: }
5382: }
5383: #endif /* VIMINFO */