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