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