Annotation of src/usr.bin/vim/cmdcmds.c, Revision 1.3
1.3 ! downsj 1: /* $OpenBSD: cmdcmds.c,v 1.2 1996/09/21 06:22:52 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));
344: return OK;
345: }
346:
347: /*
348: * :copy command - copy lines line1-line2 to line n
349: */
350: void
351: do_copy(line1, line2, n)
352: linenr_t line1;
353: linenr_t line2;
354: linenr_t n;
355: {
356: linenr_t lnum;
357: char_u *p;
358:
359: mark_adjust(n + 1, MAXLNUM, line2 - line1 + 1, 0L);
360:
361: /*
362: * there are three situations:
363: * 1. destination is above line1
364: * 2. destination is between line1 and line2
365: * 3. destination is below line2
366: *
367: * n = destination (when starting)
368: * curwin->w_cursor.lnum = destination (while copying)
369: * line1 = start of source (while copying)
370: * line2 = end of source (while copying)
371: */
372: if (u_save(n, n + 1) == FAIL)
373: return;
374: curwin->w_cursor.lnum = n;
375: lnum = line2 - line1 + 1;
376: while (line1 <= line2)
377: {
378: /* need to use strsave() because the line will be unlocked
379: within ml_append */
380: p = strsave(ml_get(line1));
381: if (p != NULL)
382: {
383: ml_append(curwin->w_cursor.lnum, p, (colnr_t)0, FALSE);
384: vim_free(p);
385: }
386: /* situation 2: skip already copied lines */
387: if (line1 == n)
388: line1 = curwin->w_cursor.lnum;
389: ++line1;
390: if (curwin->w_cursor.lnum < line1)
391: ++line1;
392: if (curwin->w_cursor.lnum < line2)
393: ++line2;
394: ++curwin->w_cursor.lnum;
395: }
396: CHANGED;
397: msgmore((long)lnum);
398: }
399:
400: /*
401: * Handle the ":!cmd" command. Also for ":r !cmd" and ":w !cmd"
402: * Bangs in the argument are replaced with the previously entered command.
403: * Remember the argument.
404: */
405: void
406: do_bang(addr_count, line1, line2, forceit, arg, do_in, do_out)
407: int addr_count;
408: linenr_t line1, line2;
409: int forceit;
410: char_u *arg;
411: int do_in, do_out;
412: {
413: static char_u *prevcmd = NULL; /* the previous command */
414: char_u *newcmd = NULL; /* the new command */
415: int ins_prevcmd;
416: char_u *t;
417: char_u *p;
418: char_u *trailarg;
419: int len;
420: int scroll_save = msg_scroll;
421:
422: /*
423: * Disallow shell commands from .exrc and .vimrc in current directory for
424: * security reasons.
425: */
426: if (secure)
427: {
428: secure = 2;
429: emsg(e_curdir);
430: return;
431: }
432:
433: if (addr_count == 0) /* :! */
434: {
435: msg_scroll = FALSE; /* don't scroll here */
436: autowrite_all();
437: msg_scroll = scroll_save;
438: }
439:
440: /*
441: * Try to find an embedded bang, like in :!<cmd> ! [args]
442: * (:!! is indicated by the 'forceit' variable)
443: */
444: ins_prevcmd = forceit;
445: trailarg = arg;
446: do
447: {
448: len = STRLEN(trailarg) + 1;
449: if (newcmd != NULL)
450: len += STRLEN(newcmd);
451: if (ins_prevcmd)
452: {
453: if (prevcmd == NULL)
454: {
455: emsg(e_noprev);
456: vim_free(newcmd);
457: return;
458: }
459: len += STRLEN(prevcmd);
460: }
461: if ((t = alloc(len)) == NULL)
462: {
463: vim_free(newcmd);
464: return;
465: }
466: *t = NUL;
467: if (newcmd != NULL)
468: STRCAT(t, newcmd);
469: if (ins_prevcmd)
470: STRCAT(t, prevcmd);
471: p = t + STRLEN(t);
472: STRCAT(t, trailarg);
473: vim_free(newcmd);
474: newcmd = t;
475:
476: /*
477: * Scan the rest of the argument for '!', which is replaced by the
478: * previous command. "\!" is replaced by "!" (this is vi compatible).
479: */
480: trailarg = NULL;
481: while (*p)
482: {
483: if (*p == '!')
484: {
485: if (p > newcmd && p[-1] == '\\')
486: vim_memmove(p - 1, p, (size_t)(STRLEN(p) + 1));
487: else
488: {
489: trailarg = p;
490: *trailarg++ = NUL;
491: ins_prevcmd = TRUE;
492: break;
493: }
494: }
495: ++p;
496: }
497: } while (trailarg != NULL);
498:
499: vim_free(prevcmd);
500: prevcmd = newcmd;
501:
502: if (bangredo) /* put cmd in redo buffer for ! command */
503: {
504: AppendToRedobuff(prevcmd);
505: AppendToRedobuff((char_u *)"\n");
506: bangredo = FALSE;
507: }
1.2 downsj 508: /*
509: * Add quotes around the command, for shells that need them.
510: */
511: if (*p_shq != NUL)
512: {
513: newcmd = alloc((unsigned)(STRLEN(prevcmd) + 2 * STRLEN(p_shq) + 1));
514: if (newcmd == NULL)
515: return;
516: STRCPY(newcmd, p_shq);
517: STRCAT(newcmd, prevcmd);
518: STRCAT(newcmd, p_shq);
519: }
1.1 downsj 520: if (addr_count == 0) /* :! */
521: {
522: /* echo the command */
523: msg_start();
524: msg_outchar(':');
525: msg_outchar('!');
1.2 downsj 526: msg_outtrans(newcmd);
1.1 downsj 527: msg_clr_eos();
528: windgoto(msg_row, msg_col);
529:
1.2 downsj 530: do_shell(newcmd);
1.1 downsj 531: }
532: else /* :range! */
1.2 downsj 533: do_filter(line1, line2, newcmd, do_in, do_out);
534: if (newcmd != prevcmd)
535: vim_free(newcmd);
1.1 downsj 536: }
537:
538: /*
539: * call a shell to execute a command
540: */
541: void
542: do_shell(cmd)
543: char_u *cmd;
544: {
545: BUF *buf;
546: int save_nwr;
547:
548: /*
549: * Disallow shell commands from .exrc and .vimrc in current directory for
550: * security reasons.
551: */
552: if (secure)
553: {
554: secure = 2;
555: emsg(e_curdir);
556: msg_end();
557: return;
558: }
559:
560: #ifdef WIN32
561: /*
562: * Check if external commands are allowed now.
563: */
564: if (can_end_termcap_mode(TRUE) == FALSE)
565: return;
566: #endif
567:
568: /*
569: * For autocommands we want to get the output on the current screen, to
570: * avoid having to type return below.
571: */
572: msg_outchar('\r'); /* put cursor at start of line */
573: #ifdef AUTOCMD
574: if (!autocmd_busy)
575: #endif
576: stoptermcap();
577: msg_outchar('\n'); /* may shift screen one line up */
578:
579: /* warning message before calling the shell */
580: if (p_warn
581: #ifdef AUTOCMD
582: && !autocmd_busy
583: #endif
584: )
585: for (buf = firstbuf; buf; buf = buf->b_next)
586: if (buf->b_changed)
587: {
588: MSG_OUTSTR("[No write since last change]\n");
589: break;
590: }
591:
592: /* This windgoto is required for when the '\n' resulted in a "delete line 1"
593: * command to the terminal. */
594:
595: windgoto(msg_row, msg_col);
596: cursor_on();
597: (void)call_shell(cmd, SHELL_COOKED);
598: need_check_timestamps = TRUE;
599:
600: /*
601: * put the message cursor at the end of the screen, avoids wait_return() to
602: * overwrite the text that the external command showed
603: */
604: msg_pos((int)Rows - 1, 0);
605:
606: #ifdef AUTOCMD
1.2 downsj 607: if (autocmd_busy)
608: must_redraw = CLEAR;
609: else
1.1 downsj 610: #endif
611: {
612: /*
613: * If K_TI is defined, we assume that we switch screens when
614: * starttermcap() is called. In that case we really want to wait for
615: * "hit return to continue".
616: */
617: save_nwr = no_wait_return;
618: if (*T_TI != NUL)
619: no_wait_return = FALSE;
620: #ifdef AMIGA
621: wait_return(term_console ? -1 : TRUE); /* see below */
622: #else
623: wait_return(TRUE);
624: #endif
625: no_wait_return = save_nwr;
626: starttermcap(); /* start termcap if not done by wait_return() */
627:
628: /*
629: * In an Amiga window redrawing is caused by asking the window size.
630: * If we got an interrupt this will not work. The chance that the
631: * window size is wrong is very small, but we need to redraw the
632: * screen. Don't do this if ':' hit in wait_return(). THIS IS UGLY
633: * but it saves an extra redraw.
634: */
635: #ifdef AMIGA
636: if (skip_redraw) /* ':' hit in wait_return() */
637: must_redraw = CLEAR;
638: else if (term_console)
639: {
640: OUTSTR("\033[0 q"); /* get window size */
641: if (got_int)
642: must_redraw = CLEAR; /* if got_int is TRUE, redraw needed */
643: else
644: must_redraw = 0; /* no extra redraw needed */
645: }
646: #endif /* AMIGA */
647: }
648: }
649:
650: /*
651: * do_filter: filter lines through a command given by the user
652: *
653: * We use temp files and the call_shell() routine here. This would normally
654: * be done using pipes on a UNIX machine, but this is more portable to
655: * non-unix machines. The call_shell() routine needs to be able
656: * to deal with redirection somehow, and should handle things like looking
657: * at the PATH env. variable, and adding reasonable extensions to the
658: * command name given by the user. All reasonable versions of call_shell()
659: * do this.
660: * We use input redirection if do_in is TRUE.
661: * We use output redirection if do_out is TRUE.
662: */
1.2 downsj 663: static void
1.1 downsj 664: do_filter(line1, line2, buff, do_in, do_out)
665: linenr_t line1, line2;
666: char_u *buff;
667: int do_in, do_out;
668: {
1.2 downsj 669: char_u *itmp = NULL;
670: char_u *otmp = NULL;
1.1 downsj 671: linenr_t linecount;
672: FPOS cursor_save;
1.2 downsj 673: #ifdef AUTOCMD
674: BUF *old_curbuf = curbuf;
675: #endif
1.1 downsj 676:
677: /*
678: * Disallow shell commands from .exrc and .vimrc in current directory for
679: * security reasons.
680: */
681: if (secure)
682: {
683: secure = 2;
684: emsg(e_curdir);
685: return;
686: }
687: if (*buff == NUL) /* no filter command */
688: return;
689:
690: #ifdef WIN32
691: /*
692: * Check if external commands are allowed now.
693: */
694: if (can_end_termcap_mode(TRUE) == FALSE)
695: return;
696: #endif
697:
698: cursor_save = curwin->w_cursor;
699: linecount = line2 - line1 + 1;
700: curwin->w_cursor.lnum = line1;
701: curwin->w_cursor.col = 0;
702:
703: /*
704: * 1. Form temp file names
705: * 2. Write the lines to a temp file
706: * 3. Run the filter command on the temp file
707: * 4. Read the output of the command into the buffer
708: * 5. Delete the original lines to be filtered
709: * 6. Remove the temp files
710: */
711:
1.2 downsj 712: if ((do_in && (itmp = vim_tempname('i')) == NULL) ||
713: (do_out && (otmp = vim_tempname('o')) == NULL))
1.1 downsj 714: {
715: emsg(e_notmp);
1.2 downsj 716: goto filterend;
1.1 downsj 717: }
718:
719: /*
720: * The writing and reading of temp files will not be shown.
721: * Vi also doesn't do this and the messages are not very informative.
722: */
723: ++no_wait_return; /* don't call wait_return() while busy */
724: if (do_in && buf_write(curbuf, itmp, NULL, line1, line2,
1.2 downsj 725: FALSE, FALSE, FALSE, TRUE) == FAIL)
1.1 downsj 726: {
727: msg_outchar('\n'); /* keep message from buf_write() */
728: --no_wait_return;
729: (void)emsg2(e_notcreate, itmp); /* will call wait_return */
730: goto filterend;
731: }
1.2 downsj 732: #ifdef AUTOCMD
733: if (curbuf != old_curbuf)
734: goto filterend;
735: #endif
736:
1.1 downsj 737: if (!do_out)
738: msg_outchar('\n');
739:
740: #if (defined(UNIX) && !defined(ARCHIE)) || defined(OS2)
741: /*
742: * put braces around the command (for concatenated commands)
743: */
744: sprintf((char *)IObuff, "(%s)", (char *)buff);
745: if (do_in)
746: {
747: STRCAT(IObuff, " < ");
748: STRCAT(IObuff, itmp);
749: }
750: #else
751: /*
752: * for shells that don't understand braces around commands, at least allow
753: * the use of commands in a pipe.
754: */
755: STRCPY(IObuff, buff);
756: if (do_in)
757: {
758: char_u *p;
759: /*
1.2 downsj 760: * If there is a pipe, we have to put the '<' in front of it.
761: * Don't do this when 'shellquote' is not empty, otherwise the redirection
762: * would be inside the quotes.
1.1 downsj 763: */
764: p = vim_strchr(IObuff, '|');
1.2 downsj 765: if (p && *p_shq == NUL)
1.1 downsj 766: *p = NUL;
767: STRCAT(IObuff, " < ");
768: STRCAT(IObuff, itmp);
769: p = vim_strchr(buff, '|');
1.2 downsj 770: if (p && *p_shq == NUL)
1.1 downsj 771: STRCAT(IObuff, p);
772: }
773: #endif
774: if (do_out)
775: {
776: char_u *p;
777:
778: if ((p = vim_strchr(p_srr, '%')) != NULL && p[1] == 's')
779: {
780: p = IObuff + STRLEN(IObuff);
781: *p++ = ' '; /* not really needed? Not with sh, ksh or bash */
782: sprintf((char *)p, (char *)p_srr, (char *)otmp);
783: }
784: else
785: sprintf((char *)IObuff + STRLEN(IObuff), " %s %s",
786: (char *)p_srr, (char *)otmp);
787: }
788:
789: windgoto((int)Rows - 1, 0);
790: cursor_on();
791:
792: /*
793: * When not redirecting the output the command can write anything to the
794: * screen. If 'shellredir' is equal to ">", screen may be messed up by
795: * stderr output of external command. Clear the screen later.
796: * If do_in is FALSE, this could be something like ":r !cat", which may
797: * also mess up the screen, clear it later.
798: */
799: if (!do_out || STRCMP(p_srr, ">") == 0 || !do_in)
800: must_redraw = CLEAR;
801: else
802: redraw_later(NOT_VALID);
803:
804: /*
805: * When call_shell() fails wait_return() is called to give the user a
806: * chance to read the error messages. Otherwise errors are ignored, so you
807: * can see the error messages from the command that appear on stdout; use
808: * 'u' to fix the text
809: * Switch to cooked mode when not redirecting stdin, avoids that something
810: * like ":r !cat" hangs.
811: */
812: if (call_shell(IObuff, SHELL_FILTER | SHELL_COOKED) == FAIL)
813: {
814: must_redraw = CLEAR;
815: wait_return(FALSE);
816: }
817: need_check_timestamps = TRUE;
818:
819: if (do_out)
820: {
821: if (u_save((linenr_t)(line2), (linenr_t)(line2 + 1)) == FAIL)
822: {
823: goto error;
824: }
825: if (readfile(otmp, NULL, line2, FALSE, (linenr_t)0, MAXLNUM, TRUE)
826: == FAIL)
827: {
828: msg_outchar('\n');
829: emsg2(e_notread, otmp);
830: goto error;
831: }
1.2 downsj 832: #ifdef AUTOCMD
833: if (curbuf != old_curbuf)
834: goto filterend;
835: #endif
1.1 downsj 836:
837: if (do_in)
838: {
839: /* put cursor on first filtered line for ":range!cmd" */
840: curwin->w_cursor.lnum = line1;
841: dellines(linecount, TRUE, TRUE);
842: curbuf->b_op_start.lnum -= linecount; /* adjust '[ */
843: curbuf->b_op_end.lnum -= linecount; /* adjust '] */
1.2 downsj 844: write_lnum_adjust(-linecount); /* adjust last line
845: for next write */
1.1 downsj 846: }
847: else
848: {
849: /* put cursor on last new line for ":r !cmd" */
850: curwin->w_cursor.lnum = curbuf->b_op_end.lnum;
851: linecount = curbuf->b_op_end.lnum - curbuf->b_op_start.lnum + 1;
852: }
853: beginline(TRUE); /* cursor on first non-blank */
854: --no_wait_return;
855:
856: if (linecount > p_report)
857: {
858: if (do_in)
859: {
860: sprintf((char *)msg_buf, "%ld lines filtered", (long)linecount);
861: if (msg(msg_buf) && !msg_scroll)
862: keep_msg = msg_buf; /* display message after redraw */
863: }
864: else
865: msgmore((long)linecount);
866: }
867: }
868: else
869: {
870: error:
871: /* put cursor back in same position for ":w !cmd" */
872: curwin->w_cursor = cursor_save;
873: --no_wait_return;
874: wait_return(FALSE);
875: }
876:
877: filterend:
878:
1.2 downsj 879: #ifdef AUTOCMD
880: if (curbuf != old_curbuf)
1.1 downsj 881: {
1.2 downsj 882: --no_wait_return;
883: EMSG("*Filter* Autocommands must not change current buffer");
1.1 downsj 884: }
1.2 downsj 885: #endif
886: if (itmp != NULL)
887: vim_remove(itmp);
888: if (otmp != NULL)
889: vim_remove(otmp);
890: vim_free(itmp);
891: vim_free(otmp);
1.1 downsj 892: }
893:
894: #ifdef VIMINFO
895:
896: static int no_viminfo __ARGS((void));
1.2 downsj 897: static int viminfo_errcnt;
1.1 downsj 898:
899: static int
900: no_viminfo()
901: {
902: /* "vim -i NONE" does not read or write a viminfo file */
903: return (use_viminfo != NULL && STRCMP(use_viminfo, "NONE") == 0);
904: }
905:
906: /*
1.2 downsj 907: * Report an error for reading a viminfo file.
908: * Count the number of errors. When there are more than 10, return TRUE.
909: */
910: int
911: viminfo_error(message, line)
912: char *message;
913: char_u *line;
914: {
915: sprintf((char *)IObuff, "viminfo: %s in line: ", message);
916: STRNCAT(IObuff, line, IOSIZE - STRLEN(IObuff));
917: emsg(IObuff);
918: if (++viminfo_errcnt >= 10)
919: {
920: EMSG("viminfo: Too many errors, skipping rest of file");
921: return TRUE;
922: }
923: return FALSE;
924: }
925:
926: /*
1.1 downsj 927: * read_viminfo() -- Read the viminfo file. Registers etc. which are already
928: * set are not over-written unless force is TRUE. -- webb
929: */
930: int
1.2 downsj 931: read_viminfo(file, want_info, want_marks, forceit)
1.1 downsj 932: char_u *file;
933: int want_info;
934: int want_marks;
1.2 downsj 935: int forceit;
1.1 downsj 936: {
937: FILE *fp;
938:
939: if (no_viminfo())
940: return FAIL;
941:
942: file = viminfo_filename(file); /* may set to default if NULL */
943: if ((fp = fopen((char *)file, READBIN)) == NULL)
944: return FAIL;
945:
1.2 downsj 946: viminfo_errcnt = 0;
947: do_viminfo(fp, NULL, want_info, want_marks, forceit);
1.1 downsj 948:
949: fclose(fp);
950:
951: return OK;
952: }
953:
954: /*
955: * write_viminfo() -- Write the viminfo file. The old one is read in first so
956: * that effectively a merge of current info and old info is done. This allows
957: * multiple vims to run simultaneously, without losing any marks etc. If
1.2 downsj 958: * forceit is TRUE, then the old file is not read in, and only internal info is
1.1 downsj 959: * written to the file. -- webb
960: */
961: void
1.2 downsj 962: write_viminfo(file, forceit)
1.1 downsj 963: char_u *file;
1.2 downsj 964: int forceit;
1.1 downsj 965: {
966: FILE *fp_in = NULL;
967: FILE *fp_out = NULL;
1.2 downsj 968: char_u *tempname = NULL;
1.1 downsj 969:
970: if (no_viminfo())
971: return;
972:
973: file = viminfo_filename(file); /* may set to default if NULL */
974: file = strsave(file); /* make a copy, don't want NameBuff */
975: if (file != NULL)
976: {
977: fp_in = fopen((char *)file, READBIN);
978: if (fp_in == NULL)
979: fp_out = fopen((char *)file, WRITEBIN);
1.2 downsj 980: else if ((tempname = vim_tempname('o')) != NULL)
981: fp_out = fopen((char *)tempname, WRITEBIN);
1.1 downsj 982: }
983: if (file == NULL || fp_out == NULL)
984: {
985: EMSG2("Can't write viminfo file %s!", file == NULL ? (char_u *)"" :
1.2 downsj 986: fp_in == NULL ? file : tempname);
1.1 downsj 987: if (fp_in != NULL)
988: fclose(fp_in);
1.2 downsj 989: goto end;
1.1 downsj 990: }
991:
1.2 downsj 992: viminfo_errcnt = 0;
993: do_viminfo(fp_in, fp_out, !forceit, !forceit, FALSE);
1.1 downsj 994:
995: fclose(fp_out); /* errors are ignored !? */
996: if (fp_in != NULL)
997: {
998: fclose(fp_in);
1.2 downsj 999: /*
1000: * In case of an error, don't overwrite the original viminfo file.
1001: */
1002: if (viminfo_errcnt || vim_rename(tempname, file) == -1)
1003: vim_remove(tempname);
1.1 downsj 1004: }
1.2 downsj 1005: end:
1.1 downsj 1006: vim_free(file);
1.2 downsj 1007: vim_free(tempname);
1.1 downsj 1008: }
1009:
1010: static char_u *
1011: viminfo_filename(file)
1012: char_u *file;
1013: {
1014: if (file == NULL || *file == NUL)
1015: {
1016: expand_env(use_viminfo == NULL ? (char_u *)VIMINFO_FILE : use_viminfo,
1017: NameBuff, MAXPATHL);
1018: return NameBuff;
1019: }
1020: return file;
1021: }
1022:
1023: /*
1024: * do_viminfo() -- Should only be called from read_viminfo() & write_viminfo().
1025: */
1026: static void
1027: do_viminfo(fp_in, fp_out, want_info, want_marks, force_read)
1028: FILE *fp_in;
1029: FILE *fp_out;
1030: int want_info;
1031: int want_marks;
1032: int force_read;
1033: {
1034: int count = 0;
1035: int eof = FALSE;
1036: char_u *line;
1037:
1038: if ((line = alloc(LSIZE)) == NULL)
1039: return;
1040:
1041: if (fp_in != NULL)
1042: {
1043: if (want_info)
1044: eof = read_viminfo_up_to_marks(line, fp_in, force_read);
1045: else
1046: /* Skip info, find start of marks */
1047: while (!(eof = vim_fgets(line, LSIZE, fp_in)) && line[0] != '>')
1048: ;
1049: }
1050: if (fp_out != NULL)
1051: {
1052: /* Write the info: */
1053: fprintf(fp_out, "# This viminfo file was generated by vim\n");
1054: fprintf(fp_out, "# You may edit it if you're careful!\n\n");
1055: write_viminfo_search_pattern(fp_out);
1056: write_viminfo_sub_string(fp_out);
1057: write_viminfo_history(fp_out);
1058: write_viminfo_registers(fp_out);
1059: write_viminfo_filemarks(fp_out);
1060: count = write_viminfo_marks(fp_out);
1061: }
1062: if (fp_in != NULL && want_marks)
1063: copy_viminfo_marks(line, fp_in, fp_out, count, eof);
1064: vim_free(line);
1065: }
1066:
1067: /*
1068: * read_viminfo_up_to_marks() -- Only called from do_viminfo(). Reads in the
1069: * first part of the viminfo file which contains everything but the marks that
1070: * are local to a file. Returns TRUE when end-of-file is reached. -- webb
1071: */
1072: static int
1.2 downsj 1073: read_viminfo_up_to_marks(line, fp, forceit)
1.1 downsj 1074: char_u *line;
1075: FILE *fp;
1.2 downsj 1076: int forceit;
1.1 downsj 1077: {
1078: int eof;
1079:
1.2 downsj 1080: prepare_viminfo_history(forceit ? 9999 : 0);
1.1 downsj 1081: eof = vim_fgets(line, LSIZE, fp);
1082: while (!eof && line[0] != '>')
1083: {
1084: switch (line[0])
1085: {
1086: case NUL:
1087: case '\r':
1088: case '\n':
1089: case '#': /* A comment */
1090: eof = vim_fgets(line, LSIZE, fp);
1091: break;
1092: case '"':
1.2 downsj 1093: eof = read_viminfo_register(line, fp, forceit);
1.1 downsj 1094: break;
1095: case '/': /* Search string */
1096: case '&': /* Substitute search string */
1097: case '~': /* Last search string, followed by '/' or '&' */
1.2 downsj 1098: eof = read_viminfo_search_pattern(line, fp, forceit);
1.1 downsj 1099: break;
1100: case '$':
1.2 downsj 1101: eof = read_viminfo_sub_string(line, fp, forceit);
1.1 downsj 1102: break;
1103: case ':':
1104: case '?':
1105: eof = read_viminfo_history(line, fp);
1106: break;
1107: case '\'':
1108: /* How do we have a file mark when the file is not in the
1109: * buffer list?
1110: */
1.2 downsj 1111: eof = read_viminfo_filemark(line, fp, forceit);
1.1 downsj 1112: break;
1113: #if 0
1114: case '+':
1115: /* eg: "+40 /path/dir file", for running vim with no args */
1116: eof = vim_fgets(line, LSIZE, fp);
1117: break;
1118: #endif
1119: default:
1.2 downsj 1120: if (viminfo_error("Illegal starting char", line))
1121: eof = TRUE;
1122: else
1123: eof = vim_fgets(line, LSIZE, fp);
1.1 downsj 1124: break;
1125: }
1126: }
1127: finish_viminfo_history();
1128: return eof;
1129: }
1130:
1131: /*
1132: * check string read from viminfo file
1133: * remove '\n' at the end of the line
1134: * - replace CTRL-V CTRL-V with CTRL-V
1135: * - replace CTRL-V 'n' with '\n'
1136: */
1137: void
1138: viminfo_readstring(p)
1139: char_u *p;
1140: {
1141: while (*p != NUL && *p != '\n')
1142: {
1143: if (*p == Ctrl('V'))
1144: {
1145: if (p[1] == 'n')
1146: p[0] = '\n';
1147: vim_memmove(p + 1, p + 2, STRLEN(p));
1148: }
1149: ++p;
1150: }
1151: *p = NUL;
1152: }
1153:
1154: /*
1155: * write string to viminfo file
1156: * - replace CTRL-V with CTRL-V CTRL-V
1157: * - replace '\n' with CTRL-V 'n'
1158: * - add a '\n' at the end
1159: */
1160: void
1161: viminfo_writestring(fd, p)
1162: FILE *fd;
1163: char_u *p;
1164: {
1165: register int c;
1166:
1167: while ((c = *p++) != NUL)
1168: {
1169: if (c == Ctrl('V') || c == '\n')
1170: {
1171: putc(Ctrl('V'), fd);
1172: if (c == '\n')
1173: c = 'n';
1174: }
1175: putc(c, fd);
1176: }
1177: putc('\n', fd);
1178: }
1179: #endif /* VIMINFO */
1180:
1181: /*
1182: * Implementation of ":fixdel", also used by get_stty().
1183: * <BS> resulting <Del>
1184: * ^? ^H
1185: * not ^? ^?
1186: */
1187: void
1188: do_fixdel()
1189: {
1190: char_u *p;
1191:
1192: p = find_termcode((char_u *)"kb");
1193: add_termcode((char_u *)"kD", p != NULL && *p == 0x7f ?
1194: (char_u *)"\010" : (char_u *)"\177");
1195: }
1196:
1.3 ! downsj 1197: static void
! 1198: print_line_no_prefix(lnum, use_number)
1.1 downsj 1199: linenr_t lnum;
1200: int use_number;
1201: {
1202: char_u numbuf[20];
1203:
1204: if (curwin->w_p_nu || use_number)
1205: {
1206: sprintf((char *)numbuf, "%7ld ", (long)lnum);
1207: set_highlight('n'); /* Highlight line numbers */
1208: start_highlight();
1209: msg_outstr(numbuf);
1210: stop_highlight();
1211: }
1212: msg_prt_line(ml_get(lnum));
1213: }
1214:
1.3 ! downsj 1215: void
! 1216: print_line(lnum, use_number)
! 1217: linenr_t lnum;
! 1218: int use_number;
! 1219: {
! 1220: msg_outchar('\n');
! 1221: print_line_no_prefix (lnum, use_number);
! 1222: }
! 1223:
! 1224: void
! 1225: print_line_cr(lnum, use_number)
! 1226: linenr_t lnum;
! 1227: int use_number;
! 1228: {
! 1229: msg_outchar('\r');
! 1230: print_line_no_prefix (lnum, use_number);
! 1231: }
! 1232:
1.1 downsj 1233: /*
1.2 downsj 1234: * Implementation of ":file[!] [fname]".
1.1 downsj 1235: */
1236: void
1237: do_file(arg, forceit)
1238: char_u *arg;
1239: int forceit;
1240: {
1241: char_u *fname, *sfname;
1242: BUF *buf;
1243:
1244: if (*arg != NUL)
1245: {
1246: /*
1247: * The name of the current buffer will be changed.
1248: * A new buffer entry needs to be made to hold the old
1249: * file name, which will become the alternate file name.
1250: */
1251: fname = curbuf->b_filename;
1252: sfname = curbuf->b_sfilename;
1253: curbuf->b_filename = NULL;
1254: curbuf->b_sfilename = NULL;
1255: if (setfname(arg, NULL, TRUE) == FAIL)
1256: {
1257: curbuf->b_filename = fname;
1258: curbuf->b_sfilename = sfname;
1259: return;
1260: }
1261: curbuf->b_notedited = TRUE;
1262: buf = buflist_new(fname, sfname, curwin->w_cursor.lnum, FALSE);
1263: if (buf != NULL)
1264: curwin->w_alt_fnum = buf->b_fnum;
1265: vim_free(fname);
1266: vim_free(sfname);
1267: }
1268: /* print full filename if :cd used */
1269: fileinfo(did_cd, FALSE, forceit);
1.3 ! downsj 1270: }
! 1271:
! 1272: /*
! 1273: * do the Ex mode :insert and :append commands
! 1274: */
! 1275:
! 1276: void
! 1277: ex_insert (int before, linenr_t whatline)
! 1278: {
! 1279: /* put the cursor somewhere sane if we insert nothing */
! 1280:
! 1281: if (whatline > curbuf->b_ml.ml_line_count) {
! 1282: curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
! 1283: } else {
! 1284: curwin->w_cursor.lnum = whatline;
! 1285: }
! 1286:
! 1287: while (1) {
! 1288: char_u *theline;
! 1289:
! 1290: if (((theline = getcmdline (' ', 1L)) == 0) ||
! 1291: ((theline[0] == '.') && (theline[1] == 0))) {
! 1292: break;
! 1293: }
! 1294:
! 1295: if (before) {
! 1296: mark_adjust (whatline, MAXLNUM, 1, 0L);
! 1297: ml_append (whatline - 1, theline, (colnr_t) 0, FALSE);
! 1298: curwin->w_cursor.lnum = whatline;
! 1299: } else {
! 1300: mark_adjust (whatline + 1, MAXLNUM, 1, 0L);
! 1301: ml_append (whatline, theline, (colnr_t) 0, FALSE);
! 1302: curwin->w_cursor.lnum = whatline + 1;
! 1303: }
! 1304:
! 1305: vim_free (theline);
! 1306: whatline++;
! 1307: }
! 1308:
! 1309: CHANGED;
! 1310: beginline (MAYBE);
! 1311: updateScreen (NOT_VALID);
! 1312: }
! 1313:
! 1314: /*
! 1315: * do the Ex mode :change command
! 1316: */
! 1317:
! 1318: void
! 1319: ex_change (linenr_t start, linenr_t end)
! 1320: {
! 1321: while (end >= start) {
! 1322: ml_delete (start, FALSE);
! 1323: end--;
! 1324: }
! 1325:
! 1326: ex_insert (TRUE, start);
! 1327: }
! 1328:
! 1329: void
! 1330: ex_z (linenr_t line, char_u *arg)
! 1331: {
! 1332: char_u *x;
! 1333: int bigness = curwin->w_height - 3;
! 1334: char_u kind;
! 1335: int minus = 0;
! 1336: linenr_t start, end, curs, i;
! 1337:
! 1338: if (arg == 0) { /* is this possible? I don't remember */
! 1339: arg = "";
! 1340: }
! 1341:
! 1342: if (bigness < 1) {
! 1343: bigness = 1;
! 1344: }
! 1345:
! 1346: x = arg;
! 1347: if (*x == '-' || *x == '+' || *x == '=' || *x == '^' || *x == '.') x++;
! 1348:
! 1349: if (*x != 0) {
! 1350: if (!isdigit (*x)) {
! 1351: EMSG ("non-numeric argument to :z");
! 1352: return;
! 1353: } else {
! 1354: bigness = atoi (x);
! 1355: }
! 1356: }
! 1357:
! 1358: kind = *arg;
! 1359:
! 1360: switch (kind) {
! 1361: case '-':
! 1362: start = line - bigness;
! 1363: end = line;
! 1364: curs = line;
! 1365: break;
! 1366:
! 1367: case '=':
! 1368: start = line - bigness / 2 + 1;
! 1369: end = line + bigness / 2 - 1;
! 1370: curs = line;
! 1371: minus = 1;
! 1372: break;
! 1373:
! 1374: case '^':
! 1375: start = line - bigness * 2;
! 1376: end = line - bigness;
! 1377: curs = line - bigness;
! 1378: break;
! 1379:
! 1380: case '.':
! 1381: start = line - bigness / 2;
! 1382: end = line + bigness / 2;
! 1383: curs = end;
! 1384: break;
! 1385:
! 1386: default: /* '+' */
! 1387: start = line;
! 1388: end = line + bigness;
! 1389: curs = end;
! 1390: break;
! 1391: }
! 1392:
! 1393: if (start < 1) {
! 1394: start = 1;
! 1395: }
! 1396:
! 1397: if (end > curbuf->b_ml.ml_line_count) {
! 1398: end = curbuf->b_ml.ml_line_count;
! 1399: }
! 1400:
! 1401: if (curs > curbuf->b_ml.ml_line_count) {
! 1402: curs = curbuf->b_ml.ml_line_count;
! 1403: }
! 1404:
! 1405: for (i = start; i <= end; i++) {
! 1406: int j;
! 1407:
! 1408: if (minus && (i == line)) {
! 1409: msg_outchar ('\n');
! 1410:
! 1411: for (j = 1; j < Columns; j++) {
! 1412: msg_outchar ('-');
! 1413: }
! 1414: }
! 1415:
! 1416: print_line (i, FALSE);
! 1417:
! 1418: if (minus && (i == line)) {
! 1419: msg_outchar ('\n');
! 1420:
! 1421: for (j = 1; j < Columns; j++) {
! 1422: msg_outchar ('-');
! 1423: }
! 1424: }
! 1425: }
! 1426:
! 1427: curwin->w_cursor.lnum = curs;
1.1 downsj 1428: }