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