Annotation of src/usr.bin/vim/cmdcmds.c, Revision 1.4
1.4 ! downsj 1: /* $OpenBSD: cmdcmds.c,v 1.3 1996/09/22 01:17:58 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: * cmdcmds.c: functions for command line commands
12: */
13:
14: #include "vim.h"
15: #include "globals.h"
16: #include "proto.h"
17: #include "option.h"
18:
1.2 downsj 19: static void do_filter __ARGS((linenr_t line1, linenr_t line2,
20: char_u *buff, int do_in, int do_out));
1.1 downsj 21: #ifdef VIMINFO
22: static char_u *viminfo_filename __ARGS((char_u *));
1.2 downsj 23: static void do_viminfo __ARGS((FILE *fp_in, FILE *fp_out, int want_info,
24: int want_marks, int force_read));
25: static int read_viminfo_up_to_marks __ARGS((char_u *line, FILE *fp,
26: int forceit));
1.1 downsj 27: #endif /* VIMINFO */
28:
29: void
30: do_ascii()
31: {
32: int c;
33: char buf1[20];
34: char buf2[20];
35: char_u buf3[3];
36:
37: c = gchar_cursor();
1.2 downsj 38: if (c == NUL)
39: {
40: MSG("empty line");
41: return;
42: }
1.1 downsj 43: if (c == NL) /* NUL is stored as NL */
44: c = NUL;
45: if (isprintchar(c) && (c < ' ' || c > '~'))
46: {
47: transchar_nonprint(buf3, c);
48: sprintf(buf1, " <%s>", (char *)buf3);
49: }
50: else
51: buf1[0] = NUL;
52: if (c >= 0x80)
53: sprintf(buf2, " <M-%s>", transchar(c & 0x7f));
54: else
55: buf2[0] = NUL;
56: sprintf((char *)IObuff, "<%s>%s%s %d, Hex %02x, Octal %03o",
57: transchar(c), buf1, buf2, c, c, c);
58: msg(IObuff);
59: }
60:
61: /*
62: * align text:
63: * type = -1 left aligned
64: * type = 0 centered
65: * type = 1 right aligned
66: */
67: void
68: do_align(start, end, width, type)
69: linenr_t start;
70: linenr_t end;
71: int width;
72: int type;
73: {
74: FPOS pos;
75: int len;
76: int indent = 0;
77: int new_indent = 0; /* init for GCC */
78: char_u *first;
79: char_u *last;
80: int save;
81:
82: #ifdef RIGHTLEFT
83: if (curwin->w_p_rl)
84: type = -type; /* switch left and right aligning */
85: #endif
86:
87: pos = curwin->w_cursor;
88: if (type == -1) /* left align: width is used for new indent */
89: {
90: if (width >= 0)
91: indent = width;
92: }
93: else
94: {
95: /*
96: * if 'textwidth' set, use it
97: * else if 'wrapmargin' set, use it
98: * if invalid value, use 80
99: */
100: if (width <= 0)
101: width = curbuf->b_p_tw;
102: if (width == 0 && curbuf->b_p_wm > 0)
103: width = Columns - curbuf->b_p_wm;
104: if (width <= 0)
105: width = 80;
106: }
107:
108: if (u_save((linenr_t)(start - 1), (linenr_t)(end + 1)) == FAIL)
109: return;
110: for (curwin->w_cursor.lnum = start;
111: curwin->w_cursor.lnum <= end; ++curwin->w_cursor.lnum)
112: {
113: /* find the first non-blank character */
114: first = skipwhite(ml_get_curline());
115: /* find the character after the last non-blank character */
116: for (last = first + STRLEN(first);
117: last > first && vim_iswhite(last[-1]); --last)
118: ;
119: save = *last;
120: *last = NUL;
121: len = linetabsize(first); /* get line length */
122: *last = save;
123: if (len == 0) /* skip blank lines */
124: continue;
125: switch (type)
126: {
127: case -1: new_indent = indent; /* left align */
128: break;
129: case 0: new_indent = (width - len) / 2; /* center */
130: break;
131: case 1: new_indent = width - len; /* right align */
132: break;
133: }
134: if (new_indent < 0)
135: new_indent = 0;
136: set_indent(new_indent, TRUE); /* set indent */
137: }
138: curwin->w_cursor = pos;
139: beginline(TRUE);
140: updateScreen(NOT_VALID);
141: }
142:
143: void
1.2 downsj 144: do_retab(start, end, new_ts, forceit)
1.1 downsj 145: linenr_t start;
146: linenr_t end;
147: int new_ts;
1.2 downsj 148: int forceit;
1.1 downsj 149: {
150: linenr_t lnum;
151: int got_tab = FALSE;
152: long num_spaces = 0;
153: long num_tabs;
154: long len;
155: long col;
156: long vcol;
157: long start_col = 0; /* For start of white-space string */
158: long start_vcol = 0; /* For start of white-space string */
159: int temp;
160: long old_len;
161: char_u *ptr;
162: char_u *new_line = (char_u *)1; /* init to non-NULL */
163: int did_something = FALSE;
164: int did_undo; /* called u_save for current line */
165:
166: if (new_ts == 0)
167: new_ts = curbuf->b_p_ts;
168: for (lnum = start; !got_int && lnum <= end; ++lnum)
169: {
170: ptr = ml_get(lnum);
171: col = 0;
172: vcol = 0;
173: did_undo = FALSE;
174: for (;;)
175: {
176: if (vim_iswhite(ptr[col]))
177: {
178: if (!got_tab && num_spaces == 0)
179: {
180: /* First consecutive white-space */
181: start_vcol = vcol;
182: start_col = col;
183: }
184: if (ptr[col] == ' ')
185: num_spaces++;
186: else
187: got_tab = TRUE;
188: }
189: else
190: {
1.2 downsj 191: if (got_tab || (forceit && num_spaces > 1))
1.1 downsj 192: {
193: /* Retabulate this string of white-space */
194:
195: /* len is virtual length of white string */
196: len = num_spaces = vcol - start_vcol;
197: num_tabs = 0;
198: if (!curbuf->b_p_et)
199: {
200: temp = new_ts - (start_vcol % new_ts);
201: if (num_spaces >= temp)
202: {
203: num_spaces -= temp;
204: num_tabs++;
205: }
206: num_tabs += num_spaces / new_ts;
207: num_spaces -= (num_spaces / new_ts) * new_ts;
208: }
209: if (curbuf->b_p_et || got_tab ||
210: (num_spaces + num_tabs < len))
211: {
212: if (did_undo == FALSE)
213: {
214: did_undo = TRUE;
215: if (u_save((linenr_t)(lnum - 1),
216: (linenr_t)(lnum + 1)) == FAIL)
217: {
218: new_line = NULL; /* flag out-of-memory */
219: break;
220: }
221: }
222:
223: /* len is actual number of white characters used */
224: len = num_spaces + num_tabs;
225: old_len = STRLEN(ptr);
226: new_line = lalloc(old_len - col + start_col + len + 1,
227: TRUE);
228: if (new_line == NULL)
229: break;
230: if (start_col > 0)
231: vim_memmove(new_line, ptr, (size_t)start_col);
232: vim_memmove(new_line + start_col + len,
233: ptr + col, (size_t)(old_len - col + 1));
234: ptr = new_line + start_col;
235: for (col = 0; col < len; col++)
236: ptr[col] = (col < num_tabs) ? '\t' : ' ';
237: ml_replace(lnum, new_line, FALSE);
238: did_something = TRUE;
239: ptr = new_line;
240: col = start_col + len;
241: }
242: }
243: got_tab = FALSE;
244: num_spaces = 0;
245: }
246: if (ptr[col] == NUL)
247: break;
248: vcol += chartabsize(ptr[col++], (colnr_t)vcol);
249: }
250: if (new_line == NULL) /* out of memory */
251: break;
252: line_breakcheck();
253: }
254: if (got_int)
255: emsg(e_interr);
256: if (did_something)
257: CHANGED;
258: curbuf->b_p_ts = new_ts;
259: coladvance(curwin->w_curswant);
260: }
261:
262: /*
263: * :move command - move lines line1-line2 to line n
264: *
265: * return FAIL for failure, OK otherwise
266: */
267: int
268: do_move(line1, line2, n)
269: linenr_t line1;
270: linenr_t line2;
271: linenr_t n;
272: {
273: char_u *str;
274: linenr_t l;
275: linenr_t extra; /* Num lines added before line1 */
276: linenr_t num_lines; /* Num lines moved */
277: linenr_t last_line; /* Last line in file after adding new text */
278: int has_mark;
279:
280: if (n >= line1 && n < line2)
281: {
282: EMSG("Move lines into themselves");
283: return FAIL;
284: }
285:
286: num_lines = line2 - line1 + 1;
287:
288: /*
289: * First we copy the old text to its new location -- webb
290: */
291: if (u_save(n, n + 1) == FAIL)
292: return FAIL;
293: for (extra = 0, l = line1; l <= line2; l++)
294: {
295: str = strsave(ml_get(l + extra));
296: if (str != NULL)
297: {
298: has_mark = ml_has_mark(l + extra);
299: ml_append(n + l - line1, str, (colnr_t)0, FALSE);
300: vim_free(str);
301: if (has_mark)
302: ml_setmarked(n + l - line1 + 1);
303: if (n < line1)
304: extra++;
305: }
306: }
307:
308: /*
309: * Now we must be careful adjusting our marks so that we don't overlap our
310: * mark_adjust() calls.
311: *
312: * We adjust the marks within the old text so that they refer to the
313: * last lines of the file (temporarily), because we know no other marks
314: * will be set there since these line numbers did not exist until we added
315: * our new lines.
316: *
317: * Then we adjust the marks on lines between the old and new text positions
318: * (either forwards or backwards).
319: *
320: * And Finally we adjust the marks we put at the end of the file back to
321: * their final destination at the new text position -- webb
322: */
323: last_line = curbuf->b_ml.ml_line_count;
324: mark_adjust(line1, line2, last_line - line2, 0L);
325: if (n >= line2)
326: mark_adjust(line2 + 1, n, -num_lines, 0L);
327: else
328: mark_adjust(n + 1, line1 - 1, num_lines, 0L);
329: mark_adjust(last_line - num_lines + 1, last_line,
330: -(last_line - n - extra), 0L);
331:
332: /*
333: * Now we delete the original text -- webb
334: */
335: if (u_save(line1 + extra - 1, line2 + extra + 1) == FAIL)
336: return FAIL;
337:
338: for (l = line1; l <= line2; l++)
339: ml_delete(line1 + extra, TRUE);
340:
341: CHANGED;
342: if (!global_busy && num_lines > p_report)
343: smsg((char_u *)"%ld line%s moved", num_lines, plural(num_lines));
1.4 ! downsj 344:
! 345: /*
! 346: * Leave the cursor on the last of the moved lines.
! 347: */
! 348: if (n >= line1)
! 349: curwin->w_cursor.lnum = n;
! 350: else
! 351: curwin->w_cursor.lnum = n + (line2 - line1) + 1;
! 352:
1.1 downsj 353: return OK;
354: }
355:
356: /*
357: * :copy command - copy lines line1-line2 to line n
358: */
359: void
360: do_copy(line1, line2, n)
361: linenr_t line1;
362: linenr_t line2;
363: linenr_t n;
364: {
365: linenr_t lnum;
366: char_u *p;
367:
368: mark_adjust(n + 1, MAXLNUM, line2 - line1 + 1, 0L);
369:
370: /*
371: * there are three situations:
372: * 1. destination is above line1
373: * 2. destination is between line1 and line2
374: * 3. destination is below line2
375: *
376: * n = destination (when starting)
377: * curwin->w_cursor.lnum = destination (while copying)
378: * line1 = start of source (while copying)
379: * line2 = end of source (while copying)
380: */
381: if (u_save(n, n + 1) == FAIL)
382: return;
383: curwin->w_cursor.lnum = n;
384: lnum = line2 - line1 + 1;
385: while (line1 <= line2)
386: {
387: /* need to use strsave() because the line will be unlocked
388: within ml_append */
389: p = strsave(ml_get(line1));
390: if (p != NULL)
391: {
392: ml_append(curwin->w_cursor.lnum, p, (colnr_t)0, FALSE);
393: vim_free(p);
394: }
395: /* situation 2: skip already copied lines */
396: if (line1 == n)
397: line1 = curwin->w_cursor.lnum;
398: ++line1;
399: if (curwin->w_cursor.lnum < line1)
400: ++line1;
401: if (curwin->w_cursor.lnum < line2)
402: ++line2;
403: ++curwin->w_cursor.lnum;
404: }
405: CHANGED;
406: msgmore((long)lnum);
407: }
408:
409: /*
410: * Handle the ":!cmd" command. Also for ":r !cmd" and ":w !cmd"
411: * Bangs in the argument are replaced with the previously entered command.
412: * Remember the argument.
413: */
414: void
415: do_bang(addr_count, line1, line2, forceit, arg, do_in, do_out)
416: int addr_count;
417: linenr_t line1, line2;
418: int forceit;
419: char_u *arg;
420: int do_in, do_out;
421: {
422: static char_u *prevcmd = NULL; /* the previous command */
423: char_u *newcmd = NULL; /* the new command */
424: int ins_prevcmd;
425: char_u *t;
426: char_u *p;
427: char_u *trailarg;
428: int len;
429: int scroll_save = msg_scroll;
430:
431: /*
432: * Disallow shell commands from .exrc and .vimrc in current directory for
433: * security reasons.
434: */
435: if (secure)
436: {
437: secure = 2;
438: emsg(e_curdir);
439: return;
440: }
441:
442: if (addr_count == 0) /* :! */
443: {
444: msg_scroll = FALSE; /* don't scroll here */
445: autowrite_all();
446: msg_scroll = scroll_save;
447: }
448:
449: /*
450: * Try to find an embedded bang, like in :!<cmd> ! [args]
451: * (:!! is indicated by the 'forceit' variable)
452: */
453: ins_prevcmd = forceit;
454: trailarg = arg;
455: do
456: {
457: len = STRLEN(trailarg) + 1;
458: if (newcmd != NULL)
459: len += STRLEN(newcmd);
460: if (ins_prevcmd)
461: {
462: if (prevcmd == NULL)
463: {
464: emsg(e_noprev);
465: vim_free(newcmd);
466: return;
467: }
468: len += STRLEN(prevcmd);
469: }
470: if ((t = alloc(len)) == NULL)
471: {
472: vim_free(newcmd);
473: return;
474: }
475: *t = NUL;
476: if (newcmd != NULL)
477: STRCAT(t, newcmd);
478: if (ins_prevcmd)
479: STRCAT(t, prevcmd);
480: p = t + STRLEN(t);
481: STRCAT(t, trailarg);
482: vim_free(newcmd);
483: newcmd = t;
484:
485: /*
486: * Scan the rest of the argument for '!', which is replaced by the
487: * previous command. "\!" is replaced by "!" (this is vi compatible).
488: */
489: trailarg = NULL;
490: while (*p)
491: {
492: if (*p == '!')
493: {
494: if (p > newcmd && p[-1] == '\\')
495: vim_memmove(p - 1, p, (size_t)(STRLEN(p) + 1));
496: else
497: {
498: trailarg = p;
499: *trailarg++ = NUL;
500: ins_prevcmd = TRUE;
501: break;
502: }
503: }
504: ++p;
505: }
506: } while (trailarg != NULL);
507:
508: vim_free(prevcmd);
509: prevcmd = newcmd;
510:
511: if (bangredo) /* put cmd in redo buffer for ! command */
512: {
513: AppendToRedobuff(prevcmd);
514: AppendToRedobuff((char_u *)"\n");
515: bangredo = FALSE;
516: }
1.2 downsj 517: /*
518: * Add quotes around the command, for shells that need them.
519: */
520: if (*p_shq != NUL)
521: {
522: newcmd = alloc((unsigned)(STRLEN(prevcmd) + 2 * STRLEN(p_shq) + 1));
523: if (newcmd == NULL)
524: return;
525: STRCPY(newcmd, p_shq);
526: STRCAT(newcmd, prevcmd);
527: STRCAT(newcmd, p_shq);
528: }
1.1 downsj 529: if (addr_count == 0) /* :! */
530: {
531: /* echo the command */
532: msg_start();
533: msg_outchar(':');
534: msg_outchar('!');
1.2 downsj 535: msg_outtrans(newcmd);
1.1 downsj 536: msg_clr_eos();
537: windgoto(msg_row, msg_col);
538:
1.2 downsj 539: do_shell(newcmd);
1.1 downsj 540: }
541: else /* :range! */
1.2 downsj 542: do_filter(line1, line2, newcmd, do_in, do_out);
543: if (newcmd != prevcmd)
544: vim_free(newcmd);
1.1 downsj 545: }
546:
547: /*
548: * call a shell to execute a command
549: */
550: void
551: do_shell(cmd)
552: char_u *cmd;
553: {
554: BUF *buf;
555: int save_nwr;
556:
557: /*
558: * Disallow shell commands from .exrc and .vimrc in current directory for
559: * security reasons.
560: */
561: if (secure)
562: {
563: secure = 2;
564: emsg(e_curdir);
565: msg_end();
566: return;
567: }
568:
569: #ifdef WIN32
570: /*
571: * Check if external commands are allowed now.
572: */
573: if (can_end_termcap_mode(TRUE) == FALSE)
574: return;
575: #endif
576:
577: /*
578: * For autocommands we want to get the output on the current screen, to
579: * avoid having to type return below.
580: */
581: msg_outchar('\r'); /* put cursor at start of line */
582: #ifdef AUTOCMD
583: if (!autocmd_busy)
584: #endif
585: stoptermcap();
586: msg_outchar('\n'); /* may shift screen one line up */
587:
588: /* warning message before calling the shell */
589: if (p_warn
590: #ifdef AUTOCMD
591: && !autocmd_busy
592: #endif
593: )
594: for (buf = firstbuf; buf; buf = buf->b_next)
595: if (buf->b_changed)
596: {
597: MSG_OUTSTR("[No write since last change]\n");
598: break;
599: }
600:
601: /* This windgoto is required for when the '\n' resulted in a "delete line 1"
602: * command to the terminal. */
603:
604: windgoto(msg_row, msg_col);
605: cursor_on();
606: (void)call_shell(cmd, SHELL_COOKED);
607: need_check_timestamps = TRUE;
608:
609: /*
610: * put the message cursor at the end of the screen, avoids wait_return() to
611: * overwrite the text that the external command showed
612: */
613: msg_pos((int)Rows - 1, 0);
614:
615: #ifdef AUTOCMD
1.2 downsj 616: if (autocmd_busy)
617: must_redraw = CLEAR;
618: else
1.1 downsj 619: #endif
620: {
621: /*
622: * If K_TI is defined, we assume that we switch screens when
623: * starttermcap() is called. In that case we really want to wait for
624: * "hit return to continue".
625: */
626: save_nwr = no_wait_return;
627: if (*T_TI != NUL)
628: no_wait_return = FALSE;
629: #ifdef AMIGA
630: wait_return(term_console ? -1 : TRUE); /* see below */
631: #else
632: wait_return(TRUE);
633: #endif
634: no_wait_return = save_nwr;
635: starttermcap(); /* start termcap if not done by wait_return() */
636:
637: /*
638: * In an Amiga window redrawing is caused by asking the window size.
639: * If we got an interrupt this will not work. The chance that the
640: * window size is wrong is very small, but we need to redraw the
641: * screen. Don't do this if ':' hit in wait_return(). THIS IS UGLY
642: * but it saves an extra redraw.
643: */
644: #ifdef AMIGA
645: if (skip_redraw) /* ':' hit in wait_return() */
646: must_redraw = CLEAR;
647: else if (term_console)
648: {
649: OUTSTR("\033[0 q"); /* get window size */
650: if (got_int)
651: must_redraw = CLEAR; /* if got_int is TRUE, redraw needed */
652: else
653: must_redraw = 0; /* no extra redraw needed */
654: }
655: #endif /* AMIGA */
656: }
657: }
658:
659: /*
660: * do_filter: filter lines through a command given by the user
661: *
662: * We use temp files and the call_shell() routine here. This would normally
663: * be done using pipes on a UNIX machine, but this is more portable to
664: * non-unix machines. The call_shell() routine needs to be able
665: * to deal with redirection somehow, and should handle things like looking
666: * at the PATH env. variable, and adding reasonable extensions to the
667: * command name given by the user. All reasonable versions of call_shell()
668: * do this.
669: * We use input redirection if do_in is TRUE.
670: * We use output redirection if do_out is TRUE.
671: */
1.2 downsj 672: static void
1.1 downsj 673: do_filter(line1, line2, buff, do_in, do_out)
674: linenr_t line1, line2;
675: char_u *buff;
676: int do_in, do_out;
677: {
1.2 downsj 678: char_u *itmp = NULL;
679: char_u *otmp = NULL;
1.1 downsj 680: linenr_t linecount;
681: FPOS cursor_save;
1.2 downsj 682: #ifdef AUTOCMD
683: BUF *old_curbuf = curbuf;
684: #endif
1.1 downsj 685:
686: /*
687: * Disallow shell commands from .exrc and .vimrc in current directory for
688: * security reasons.
689: */
690: if (secure)
691: {
692: secure = 2;
693: emsg(e_curdir);
694: return;
695: }
696: if (*buff == NUL) /* no filter command */
697: return;
698:
699: #ifdef WIN32
700: /*
701: * Check if external commands are allowed now.
702: */
703: if (can_end_termcap_mode(TRUE) == FALSE)
704: return;
705: #endif
706:
707: cursor_save = curwin->w_cursor;
708: linecount = line2 - line1 + 1;
709: curwin->w_cursor.lnum = line1;
710: curwin->w_cursor.col = 0;
711:
712: /*
713: * 1. Form temp file names
714: * 2. Write the lines to a temp file
715: * 3. Run the filter command on the temp file
716: * 4. Read the output of the command into the buffer
717: * 5. Delete the original lines to be filtered
718: * 6. Remove the temp files
719: */
720:
1.2 downsj 721: if ((do_in && (itmp = vim_tempname('i')) == NULL) ||
722: (do_out && (otmp = vim_tempname('o')) == NULL))
1.1 downsj 723: {
724: emsg(e_notmp);
1.2 downsj 725: goto filterend;
1.1 downsj 726: }
727:
728: /*
729: * The writing and reading of temp files will not be shown.
730: * Vi also doesn't do this and the messages are not very informative.
731: */
732: ++no_wait_return; /* don't call wait_return() while busy */
733: if (do_in && buf_write(curbuf, itmp, NULL, line1, line2,
1.2 downsj 734: FALSE, FALSE, FALSE, TRUE) == FAIL)
1.1 downsj 735: {
736: msg_outchar('\n'); /* keep message from buf_write() */
737: --no_wait_return;
738: (void)emsg2(e_notcreate, itmp); /* will call wait_return */
739: goto filterend;
740: }
1.2 downsj 741: #ifdef AUTOCMD
742: if (curbuf != old_curbuf)
743: goto filterend;
744: #endif
745:
1.1 downsj 746: if (!do_out)
747: msg_outchar('\n');
748:
749: #if (defined(UNIX) && !defined(ARCHIE)) || defined(OS2)
750: /*
751: * put braces around the command (for concatenated commands)
752: */
753: sprintf((char *)IObuff, "(%s)", (char *)buff);
754: if (do_in)
755: {
756: STRCAT(IObuff, " < ");
757: STRCAT(IObuff, itmp);
758: }
759: #else
760: /*
761: * for shells that don't understand braces around commands, at least allow
762: * the use of commands in a pipe.
763: */
764: STRCPY(IObuff, buff);
765: if (do_in)
766: {
767: char_u *p;
768: /*
1.2 downsj 769: * If there is a pipe, we have to put the '<' in front of it.
770: * Don't do this when 'shellquote' is not empty, otherwise the redirection
771: * would be inside the quotes.
1.1 downsj 772: */
773: p = vim_strchr(IObuff, '|');
1.2 downsj 774: if (p && *p_shq == NUL)
1.1 downsj 775: *p = NUL;
776: STRCAT(IObuff, " < ");
777: STRCAT(IObuff, itmp);
778: p = vim_strchr(buff, '|');
1.2 downsj 779: if (p && *p_shq == NUL)
1.1 downsj 780: STRCAT(IObuff, p);
781: }
782: #endif
783: if (do_out)
784: {
785: char_u *p;
786:
787: if ((p = vim_strchr(p_srr, '%')) != NULL && p[1] == 's')
788: {
789: p = IObuff + STRLEN(IObuff);
790: *p++ = ' '; /* not really needed? Not with sh, ksh or bash */
791: sprintf((char *)p, (char *)p_srr, (char *)otmp);
792: }
793: else
794: sprintf((char *)IObuff + STRLEN(IObuff), " %s %s",
795: (char *)p_srr, (char *)otmp);
796: }
797:
798: windgoto((int)Rows - 1, 0);
799: cursor_on();
800:
801: /*
802: * When not redirecting the output the command can write anything to the
803: * screen. If 'shellredir' is equal to ">", screen may be messed up by
804: * stderr output of external command. Clear the screen later.
805: * If do_in is FALSE, this could be something like ":r !cat", which may
806: * also mess up the screen, clear it later.
807: */
808: if (!do_out || STRCMP(p_srr, ">") == 0 || !do_in)
809: must_redraw = CLEAR;
810: else
811: redraw_later(NOT_VALID);
812:
813: /*
814: * When call_shell() fails wait_return() is called to give the user a
815: * chance to read the error messages. Otherwise errors are ignored, so you
816: * can see the error messages from the command that appear on stdout; use
817: * 'u' to fix the text
818: * Switch to cooked mode when not redirecting stdin, avoids that something
819: * like ":r !cat" hangs.
820: */
821: if (call_shell(IObuff, SHELL_FILTER | SHELL_COOKED) == FAIL)
822: {
823: must_redraw = CLEAR;
824: wait_return(FALSE);
825: }
826: need_check_timestamps = TRUE;
827:
828: if (do_out)
829: {
830: if (u_save((linenr_t)(line2), (linenr_t)(line2 + 1)) == FAIL)
831: {
832: goto error;
833: }
834: if (readfile(otmp, NULL, line2, FALSE, (linenr_t)0, MAXLNUM, TRUE)
835: == FAIL)
836: {
837: msg_outchar('\n');
838: emsg2(e_notread, otmp);
839: goto error;
840: }
1.2 downsj 841: #ifdef AUTOCMD
842: if (curbuf != old_curbuf)
843: goto filterend;
844: #endif
1.1 downsj 845:
846: if (do_in)
847: {
848: /* put cursor on first filtered line for ":range!cmd" */
849: curwin->w_cursor.lnum = line1;
850: dellines(linecount, TRUE, TRUE);
851: curbuf->b_op_start.lnum -= linecount; /* adjust '[ */
852: curbuf->b_op_end.lnum -= linecount; /* adjust '] */
1.2 downsj 853: write_lnum_adjust(-linecount); /* adjust last line
854: for next write */
1.1 downsj 855: }
856: else
857: {
858: /* put cursor on last new line for ":r !cmd" */
859: curwin->w_cursor.lnum = curbuf->b_op_end.lnum;
860: linecount = curbuf->b_op_end.lnum - curbuf->b_op_start.lnum + 1;
861: }
862: beginline(TRUE); /* cursor on first non-blank */
863: --no_wait_return;
864:
865: if (linecount > p_report)
866: {
867: if (do_in)
868: {
869: sprintf((char *)msg_buf, "%ld lines filtered", (long)linecount);
870: if (msg(msg_buf) && !msg_scroll)
871: keep_msg = msg_buf; /* display message after redraw */
872: }
873: else
874: msgmore((long)linecount);
875: }
876: }
877: else
878: {
879: error:
880: /* put cursor back in same position for ":w !cmd" */
881: curwin->w_cursor = cursor_save;
882: --no_wait_return;
883: wait_return(FALSE);
884: }
885:
886: filterend:
887:
1.2 downsj 888: #ifdef AUTOCMD
889: if (curbuf != old_curbuf)
1.1 downsj 890: {
1.2 downsj 891: --no_wait_return;
892: EMSG("*Filter* Autocommands must not change current buffer");
1.1 downsj 893: }
1.2 downsj 894: #endif
895: if (itmp != NULL)
896: vim_remove(itmp);
897: if (otmp != NULL)
898: vim_remove(otmp);
899: vim_free(itmp);
900: vim_free(otmp);
1.1 downsj 901: }
902:
903: #ifdef VIMINFO
904:
905: static int no_viminfo __ARGS((void));
1.2 downsj 906: static int viminfo_errcnt;
1.1 downsj 907:
908: static int
909: no_viminfo()
910: {
911: /* "vim -i NONE" does not read or write a viminfo file */
912: return (use_viminfo != NULL && STRCMP(use_viminfo, "NONE") == 0);
913: }
914:
915: /*
1.2 downsj 916: * Report an error for reading a viminfo file.
917: * Count the number of errors. When there are more than 10, return TRUE.
918: */
919: int
920: viminfo_error(message, line)
921: char *message;
922: char_u *line;
923: {
924: sprintf((char *)IObuff, "viminfo: %s in line: ", message);
925: STRNCAT(IObuff, line, IOSIZE - STRLEN(IObuff));
926: emsg(IObuff);
927: if (++viminfo_errcnt >= 10)
928: {
929: EMSG("viminfo: Too many errors, skipping rest of file");
930: return TRUE;
931: }
932: return FALSE;
933: }
934:
935: /*
1.1 downsj 936: * read_viminfo() -- Read the viminfo file. Registers etc. which are already
937: * set are not over-written unless force is TRUE. -- webb
938: */
939: int
1.2 downsj 940: read_viminfo(file, want_info, want_marks, forceit)
1.1 downsj 941: char_u *file;
942: int want_info;
943: int want_marks;
1.2 downsj 944: int forceit;
1.1 downsj 945: {
946: FILE *fp;
947:
948: if (no_viminfo())
949: return FAIL;
950:
951: file = viminfo_filename(file); /* may set to default if NULL */
952: if ((fp = fopen((char *)file, READBIN)) == NULL)
953: return FAIL;
954:
1.2 downsj 955: viminfo_errcnt = 0;
956: do_viminfo(fp, NULL, want_info, want_marks, forceit);
1.1 downsj 957:
958: fclose(fp);
959:
960: return OK;
961: }
962:
963: /*
964: * write_viminfo() -- Write the viminfo file. The old one is read in first so
965: * that effectively a merge of current info and old info is done. This allows
966: * multiple vims to run simultaneously, without losing any marks etc. If
1.2 downsj 967: * forceit is TRUE, then the old file is not read in, and only internal info is
1.1 downsj 968: * written to the file. -- webb
969: */
970: void
1.2 downsj 971: write_viminfo(file, forceit)
1.1 downsj 972: char_u *file;
1.2 downsj 973: int forceit;
1.1 downsj 974: {
975: FILE *fp_in = NULL;
976: FILE *fp_out = NULL;
1.2 downsj 977: char_u *tempname = NULL;
1.1 downsj 978:
979: if (no_viminfo())
980: return;
981:
982: file = viminfo_filename(file); /* may set to default if NULL */
983: file = strsave(file); /* make a copy, don't want NameBuff */
984: if (file != NULL)
985: {
986: fp_in = fopen((char *)file, READBIN);
987: if (fp_in == NULL)
988: fp_out = fopen((char *)file, WRITEBIN);
1.2 downsj 989: else if ((tempname = vim_tempname('o')) != NULL)
990: fp_out = fopen((char *)tempname, WRITEBIN);
1.1 downsj 991: }
992: if (file == NULL || fp_out == NULL)
993: {
994: EMSG2("Can't write viminfo file %s!", file == NULL ? (char_u *)"" :
1.2 downsj 995: fp_in == NULL ? file : tempname);
1.1 downsj 996: if (fp_in != NULL)
997: fclose(fp_in);
1.2 downsj 998: goto end;
1.1 downsj 999: }
1000:
1.2 downsj 1001: viminfo_errcnt = 0;
1002: do_viminfo(fp_in, fp_out, !forceit, !forceit, FALSE);
1.1 downsj 1003:
1004: fclose(fp_out); /* errors are ignored !? */
1005: if (fp_in != NULL)
1006: {
1007: fclose(fp_in);
1.2 downsj 1008: /*
1009: * In case of an error, don't overwrite the original viminfo file.
1010: */
1011: if (viminfo_errcnt || vim_rename(tempname, file) == -1)
1012: vim_remove(tempname);
1.1 downsj 1013: }
1.2 downsj 1014: end:
1.1 downsj 1015: vim_free(file);
1.2 downsj 1016: vim_free(tempname);
1.1 downsj 1017: }
1018:
1019: static char_u *
1020: viminfo_filename(file)
1021: char_u *file;
1022: {
1023: if (file == NULL || *file == NUL)
1024: {
1025: expand_env(use_viminfo == NULL ? (char_u *)VIMINFO_FILE : use_viminfo,
1026: NameBuff, MAXPATHL);
1027: return NameBuff;
1028: }
1029: return file;
1030: }
1031:
1032: /*
1033: * do_viminfo() -- Should only be called from read_viminfo() & write_viminfo().
1034: */
1035: static void
1036: do_viminfo(fp_in, fp_out, want_info, want_marks, force_read)
1037: FILE *fp_in;
1038: FILE *fp_out;
1039: int want_info;
1040: int want_marks;
1041: int force_read;
1042: {
1043: int count = 0;
1044: int eof = FALSE;
1045: char_u *line;
1046:
1047: if ((line = alloc(LSIZE)) == NULL)
1048: return;
1049:
1050: if (fp_in != NULL)
1051: {
1052: if (want_info)
1053: eof = read_viminfo_up_to_marks(line, fp_in, force_read);
1054: else
1055: /* Skip info, find start of marks */
1056: while (!(eof = vim_fgets(line, LSIZE, fp_in)) && line[0] != '>')
1057: ;
1058: }
1059: if (fp_out != NULL)
1060: {
1061: /* Write the info: */
1062: fprintf(fp_out, "# This viminfo file was generated by vim\n");
1063: fprintf(fp_out, "# You may edit it if you're careful!\n\n");
1064: write_viminfo_search_pattern(fp_out);
1065: write_viminfo_sub_string(fp_out);
1066: write_viminfo_history(fp_out);
1067: write_viminfo_registers(fp_out);
1068: write_viminfo_filemarks(fp_out);
1069: count = write_viminfo_marks(fp_out);
1070: }
1071: if (fp_in != NULL && want_marks)
1072: copy_viminfo_marks(line, fp_in, fp_out, count, eof);
1073: vim_free(line);
1074: }
1075:
1076: /*
1077: * read_viminfo_up_to_marks() -- Only called from do_viminfo(). Reads in the
1078: * first part of the viminfo file which contains everything but the marks that
1079: * are local to a file. Returns TRUE when end-of-file is reached. -- webb
1080: */
1081: static int
1.2 downsj 1082: read_viminfo_up_to_marks(line, fp, forceit)
1.1 downsj 1083: char_u *line;
1084: FILE *fp;
1.2 downsj 1085: int forceit;
1.1 downsj 1086: {
1087: int eof;
1088:
1.2 downsj 1089: prepare_viminfo_history(forceit ? 9999 : 0);
1.1 downsj 1090: eof = vim_fgets(line, LSIZE, fp);
1091: while (!eof && line[0] != '>')
1092: {
1093: switch (line[0])
1094: {
1095: case NUL:
1096: case '\r':
1097: case '\n':
1098: case '#': /* A comment */
1099: eof = vim_fgets(line, LSIZE, fp);
1100: break;
1101: case '"':
1.2 downsj 1102: eof = read_viminfo_register(line, fp, forceit);
1.1 downsj 1103: break;
1104: case '/': /* Search string */
1105: case '&': /* Substitute search string */
1106: case '~': /* Last search string, followed by '/' or '&' */
1.2 downsj 1107: eof = read_viminfo_search_pattern(line, fp, forceit);
1.1 downsj 1108: break;
1109: case '$':
1.2 downsj 1110: eof = read_viminfo_sub_string(line, fp, forceit);
1.1 downsj 1111: break;
1112: case ':':
1113: case '?':
1114: eof = read_viminfo_history(line, fp);
1115: break;
1116: case '\'':
1117: /* How do we have a file mark when the file is not in the
1118: * buffer list?
1119: */
1.2 downsj 1120: eof = read_viminfo_filemark(line, fp, forceit);
1.1 downsj 1121: break;
1122: #if 0
1123: case '+':
1124: /* eg: "+40 /path/dir file", for running vim with no args */
1125: eof = vim_fgets(line, LSIZE, fp);
1126: break;
1127: #endif
1128: default:
1.2 downsj 1129: if (viminfo_error("Illegal starting char", line))
1130: eof = TRUE;
1131: else
1132: eof = vim_fgets(line, LSIZE, fp);
1.1 downsj 1133: break;
1134: }
1135: }
1136: finish_viminfo_history();
1137: return eof;
1138: }
1139:
1140: /*
1141: * check string read from viminfo file
1142: * remove '\n' at the end of the line
1143: * - replace CTRL-V CTRL-V with CTRL-V
1144: * - replace CTRL-V 'n' with '\n'
1145: */
1146: void
1147: viminfo_readstring(p)
1148: char_u *p;
1149: {
1150: while (*p != NUL && *p != '\n')
1151: {
1152: if (*p == Ctrl('V'))
1153: {
1154: if (p[1] == 'n')
1155: p[0] = '\n';
1156: vim_memmove(p + 1, p + 2, STRLEN(p));
1157: }
1158: ++p;
1159: }
1160: *p = NUL;
1161: }
1162:
1163: /*
1164: * write string to viminfo file
1165: * - replace CTRL-V with CTRL-V CTRL-V
1166: * - replace '\n' with CTRL-V 'n'
1167: * - add a '\n' at the end
1168: */
1169: void
1170: viminfo_writestring(fd, p)
1171: FILE *fd;
1172: char_u *p;
1173: {
1174: register int c;
1175:
1176: while ((c = *p++) != NUL)
1177: {
1178: if (c == Ctrl('V') || c == '\n')
1179: {
1180: putc(Ctrl('V'), fd);
1181: if (c == '\n')
1182: c = 'n';
1183: }
1184: putc(c, fd);
1185: }
1186: putc('\n', fd);
1187: }
1188: #endif /* VIMINFO */
1189:
1190: /*
1191: * Implementation of ":fixdel", also used by get_stty().
1192: * <BS> resulting <Del>
1193: * ^? ^H
1194: * not ^? ^?
1195: */
1196: void
1197: do_fixdel()
1198: {
1199: char_u *p;
1200:
1201: p = find_termcode((char_u *)"kb");
1202: add_termcode((char_u *)"kD", p != NULL && *p == 0x7f ?
1203: (char_u *)"\010" : (char_u *)"\177");
1204: }
1205:
1.3 downsj 1206: static void
1207: print_line_no_prefix(lnum, use_number)
1.1 downsj 1208: linenr_t lnum;
1209: int use_number;
1210: {
1211: char_u numbuf[20];
1212:
1213: if (curwin->w_p_nu || use_number)
1214: {
1215: sprintf((char *)numbuf, "%7ld ", (long)lnum);
1216: set_highlight('n'); /* Highlight line numbers */
1217: start_highlight();
1218: msg_outstr(numbuf);
1219: stop_highlight();
1220: }
1221: msg_prt_line(ml_get(lnum));
1222: }
1223:
1.3 downsj 1224: void
1225: print_line(lnum, use_number)
1226: linenr_t lnum;
1227: int use_number;
1228: {
1229: msg_outchar('\n');
1230: print_line_no_prefix (lnum, use_number);
1231: }
1232:
1233: void
1234: print_line_cr(lnum, use_number)
1235: linenr_t lnum;
1236: int use_number;
1237: {
1238: msg_outchar('\r');
1239: print_line_no_prefix (lnum, use_number);
1240: }
1241:
1.1 downsj 1242: /*
1.2 downsj 1243: * Implementation of ":file[!] [fname]".
1.1 downsj 1244: */
1245: void
1246: do_file(arg, forceit)
1247: char_u *arg;
1248: int forceit;
1249: {
1250: char_u *fname, *sfname;
1251: BUF *buf;
1252:
1253: if (*arg != NUL)
1254: {
1255: /*
1256: * The name of the current buffer will be changed.
1257: * A new buffer entry needs to be made to hold the old
1258: * file name, which will become the alternate file name.
1259: */
1260: fname = curbuf->b_filename;
1261: sfname = curbuf->b_sfilename;
1262: curbuf->b_filename = NULL;
1263: curbuf->b_sfilename = NULL;
1264: if (setfname(arg, NULL, TRUE) == FAIL)
1265: {
1266: curbuf->b_filename = fname;
1267: curbuf->b_sfilename = sfname;
1268: return;
1269: }
1270: curbuf->b_notedited = TRUE;
1271: buf = buflist_new(fname, sfname, curwin->w_cursor.lnum, FALSE);
1272: if (buf != NULL)
1273: curwin->w_alt_fnum = buf->b_fnum;
1274: vim_free(fname);
1275: vim_free(sfname);
1276: }
1277: /* print full filename if :cd used */
1278: fileinfo(did_cd, FALSE, forceit);
1.3 downsj 1279: }
1280:
1281: /*
1282: * do the Ex mode :insert and :append commands
1283: */
1284:
1285: void
1286: ex_insert (int before, linenr_t whatline)
1287: {
1288: /* put the cursor somewhere sane if we insert nothing */
1289:
1290: if (whatline > curbuf->b_ml.ml_line_count) {
1291: curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
1292: } else {
1293: curwin->w_cursor.lnum = whatline;
1294: }
1295:
1296: while (1) {
1297: char_u *theline;
1298:
1299: if (((theline = getcmdline (' ', 1L)) == 0) ||
1300: ((theline[0] == '.') && (theline[1] == 0))) {
1301: break;
1302: }
1303:
1304: if (before) {
1305: mark_adjust (whatline, MAXLNUM, 1, 0L);
1306: ml_append (whatline - 1, theline, (colnr_t) 0, FALSE);
1307: curwin->w_cursor.lnum = whatline;
1308: } else {
1309: mark_adjust (whatline + 1, MAXLNUM, 1, 0L);
1310: ml_append (whatline, theline, (colnr_t) 0, FALSE);
1311: curwin->w_cursor.lnum = whatline + 1;
1312: }
1313:
1314: vim_free (theline);
1315: whatline++;
1316: }
1317:
1318: CHANGED;
1319: beginline (MAYBE);
1320: updateScreen (NOT_VALID);
1321: }
1322:
1323: /*
1324: * do the Ex mode :change command
1325: */
1326:
1327: void
1328: ex_change (linenr_t start, linenr_t end)
1329: {
1330: while (end >= start) {
1331: ml_delete (start, FALSE);
1332: end--;
1333: }
1334:
1335: ex_insert (TRUE, start);
1336: }
1337:
1338: void
1339: ex_z (linenr_t line, char_u *arg)
1340: {
1341: char_u *x;
1342: int bigness = curwin->w_height - 3;
1343: char_u kind;
1344: int minus = 0;
1345: linenr_t start, end, curs, i;
1346:
1347: if (arg == 0) { /* is this possible? I don't remember */
1348: arg = "";
1349: }
1350:
1351: if (bigness < 1) {
1352: bigness = 1;
1353: }
1354:
1355: x = arg;
1356: if (*x == '-' || *x == '+' || *x == '=' || *x == '^' || *x == '.') x++;
1357:
1358: if (*x != 0) {
1359: if (!isdigit (*x)) {
1360: EMSG ("non-numeric argument to :z");
1361: return;
1362: } else {
1363: bigness = atoi (x);
1364: }
1365: }
1366:
1367: kind = *arg;
1368:
1369: switch (kind) {
1370: case '-':
1371: start = line - bigness;
1372: end = line;
1373: curs = line;
1374: break;
1375:
1376: case '=':
1377: start = line - bigness / 2 + 1;
1378: end = line + bigness / 2 - 1;
1379: curs = line;
1380: minus = 1;
1381: break;
1382:
1383: case '^':
1384: start = line - bigness * 2;
1385: end = line - bigness;
1386: curs = line - bigness;
1387: break;
1388:
1389: case '.':
1390: start = line - bigness / 2;
1391: end = line + bigness / 2;
1392: curs = end;
1393: break;
1394:
1395: default: /* '+' */
1396: start = line;
1397: end = line + bigness;
1398: curs = end;
1399: break;
1400: }
1401:
1402: if (start < 1) {
1403: start = 1;
1404: }
1405:
1406: if (end > curbuf->b_ml.ml_line_count) {
1407: end = curbuf->b_ml.ml_line_count;
1408: }
1409:
1410: if (curs > curbuf->b_ml.ml_line_count) {
1411: curs = curbuf->b_ml.ml_line_count;
1412: }
1413:
1414: for (i = start; i <= end; i++) {
1415: int j;
1416:
1417: if (minus && (i == line)) {
1418: msg_outchar ('\n');
1419:
1420: for (j = 1; j < Columns; j++) {
1421: msg_outchar ('-');
1422: }
1423: }
1424:
1425: print_line (i, FALSE);
1426:
1427: if (minus && (i == line)) {
1428: msg_outchar ('\n');
1429:
1430: for (j = 1; j < Columns; j++) {
1431: msg_outchar ('-');
1432: }
1433: }
1434: }
1435:
1436: curwin->w_cursor.lnum = curs;
1.1 downsj 1437: }