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