1*e0b8e63eSJohn Marino /*- 2*e0b8e63eSJohn Marino * Copyright (c) 1992, 1993, 1994 3*e0b8e63eSJohn Marino * The Regents of the University of California. All rights reserved. 4*e0b8e63eSJohn Marino * Copyright (c) 1992, 1993, 1994, 1995, 1996 5*e0b8e63eSJohn Marino * Keith Bostic. All rights reserved. 6*e0b8e63eSJohn Marino * 7*e0b8e63eSJohn Marino * See the LICENSE file for redistribution information. 8*e0b8e63eSJohn Marino */ 9*e0b8e63eSJohn Marino 10*e0b8e63eSJohn Marino #include "config.h" 11*e0b8e63eSJohn Marino 12*e0b8e63eSJohn Marino #ifndef lint 13*e0b8e63eSJohn Marino static const char sccsid[] = "$Id: v_itxt.c,v 10.21 2001/06/25 15:19:32 skimo Exp $"; 14*e0b8e63eSJohn Marino #endif /* not lint */ 15*e0b8e63eSJohn Marino 16*e0b8e63eSJohn Marino #include <sys/types.h> 17*e0b8e63eSJohn Marino #include <sys/queue.h> 18*e0b8e63eSJohn Marino #include <sys/time.h> 19*e0b8e63eSJohn Marino 20*e0b8e63eSJohn Marino #include <bitstring.h> 21*e0b8e63eSJohn Marino #include <ctype.h> 22*e0b8e63eSJohn Marino #include <errno.h> 23*e0b8e63eSJohn Marino #include <limits.h> 24*e0b8e63eSJohn Marino #include <stdio.h> 25*e0b8e63eSJohn Marino #include <stdlib.h> 26*e0b8e63eSJohn Marino #include <string.h> 27*e0b8e63eSJohn Marino 28*e0b8e63eSJohn Marino #include "../common/common.h" 29*e0b8e63eSJohn Marino #include "vi.h" 30*e0b8e63eSJohn Marino 31*e0b8e63eSJohn Marino /* 32*e0b8e63eSJohn Marino * !!! 33*e0b8e63eSJohn Marino * Repeated input in the historic vi is mostly wrong and this isn't very 34*e0b8e63eSJohn Marino * backward compatible. For example, if the user entered "3Aab\ncd" in 35*e0b8e63eSJohn Marino * the historic vi, the "ab" was repeated 3 times, and the "\ncd" was then 36*e0b8e63eSJohn Marino * appended to the result. There was also a hack which I don't remember 37*e0b8e63eSJohn Marino * right now, where "3o" would open 3 lines and then let the user fill them 38*e0b8e63eSJohn Marino * in, to make screen movements on 300 baud modems more tolerable. I don't 39*e0b8e63eSJohn Marino * think it's going to be missed. 40*e0b8e63eSJohn Marino * 41*e0b8e63eSJohn Marino * !!! 42*e0b8e63eSJohn Marino * There's a problem with the way that we do logging for change commands with 43*e0b8e63eSJohn Marino * implied motions (e.g. A, I, O, cc, etc.). Since the main vi loop logs the 44*e0b8e63eSJohn Marino * starting cursor position before the change command "moves" the cursor, the 45*e0b8e63eSJohn Marino * cursor position to which we return on undo will be where the user entered 46*e0b8e63eSJohn Marino * the change command, not the start of the change. Several of the following 47*e0b8e63eSJohn Marino * routines re-log the cursor to make this work correctly. Historic vi tried 48*e0b8e63eSJohn Marino * to do the same thing, and mostly got it right. (The only spectacular way 49*e0b8e63eSJohn Marino * it fails is if the user entered 'o' from anywhere but the last character of 50*e0b8e63eSJohn Marino * the line, the undo returned the cursor to the start of the line. If the 51*e0b8e63eSJohn Marino * user was on the last character of the line, the cursor returned to that 52*e0b8e63eSJohn Marino * position.) We also check for mapped keys waiting, i.e. if we're in the 53*e0b8e63eSJohn Marino * middle of a map, don't bother logging the cursor. 54*e0b8e63eSJohn Marino */ 55*e0b8e63eSJohn Marino #define LOG_CORRECT { \ 56*e0b8e63eSJohn Marino if (!MAPPED_KEYS_WAITING(sp)) \ 57*e0b8e63eSJohn Marino (void)log_cursor(sp); \ 58*e0b8e63eSJohn Marino } 59*e0b8e63eSJohn Marino 60*e0b8e63eSJohn Marino static u_int32_t set_txt_std(SCR *, VICMD *, u_int32_t); 61*e0b8e63eSJohn Marino 62*e0b8e63eSJohn Marino /* 63*e0b8e63eSJohn Marino * v_iA -- [count]A 64*e0b8e63eSJohn Marino * Append text to the end of the line. 65*e0b8e63eSJohn Marino * 66*e0b8e63eSJohn Marino * PUBLIC: int v_iA(SCR *, VICMD *); 67*e0b8e63eSJohn Marino */ 68*e0b8e63eSJohn Marino int 69*e0b8e63eSJohn Marino v_iA(SCR *sp, VICMD *vp) 70*e0b8e63eSJohn Marino { 71*e0b8e63eSJohn Marino size_t len; 72*e0b8e63eSJohn Marino 73*e0b8e63eSJohn Marino if (!db_get(sp, vp->m_start.lno, 0, NULL, &len)) 74*e0b8e63eSJohn Marino sp->cno = len == 0 ? 0 : len - 1; 75*e0b8e63eSJohn Marino 76*e0b8e63eSJohn Marino LOG_CORRECT; 77*e0b8e63eSJohn Marino 78*e0b8e63eSJohn Marino return (v_ia(sp, vp)); 79*e0b8e63eSJohn Marino } 80*e0b8e63eSJohn Marino 81*e0b8e63eSJohn Marino /* 82*e0b8e63eSJohn Marino * v_ia -- [count]a 83*e0b8e63eSJohn Marino * [count]A 84*e0b8e63eSJohn Marino * Append text to the cursor position. 85*e0b8e63eSJohn Marino * 86*e0b8e63eSJohn Marino * PUBLIC: int v_ia(SCR *, VICMD *); 87*e0b8e63eSJohn Marino */ 88*e0b8e63eSJohn Marino int 89*e0b8e63eSJohn Marino v_ia(SCR *sp, VICMD *vp) 90*e0b8e63eSJohn Marino { 91*e0b8e63eSJohn Marino size_t len; 92*e0b8e63eSJohn Marino u_int32_t flags; 93*e0b8e63eSJohn Marino int isempty; 94*e0b8e63eSJohn Marino CHAR_T *p; 95*e0b8e63eSJohn Marino 96*e0b8e63eSJohn Marino flags = set_txt_std(sp, vp, 0); 97*e0b8e63eSJohn Marino sp->showmode = SM_APPEND; 98*e0b8e63eSJohn Marino sp->lno = vp->m_start.lno; 99*e0b8e63eSJohn Marino 100*e0b8e63eSJohn Marino /* Move the cursor one column to the right and repaint the screen. */ 101*e0b8e63eSJohn Marino if (db_eget(sp, sp->lno, &p, &len, &isempty)) { 102*e0b8e63eSJohn Marino if (!isempty) 103*e0b8e63eSJohn Marino return (1); 104*e0b8e63eSJohn Marino len = 0; 105*e0b8e63eSJohn Marino LF_SET(TXT_APPENDEOL); 106*e0b8e63eSJohn Marino } else if (len) { 107*e0b8e63eSJohn Marino if (len == sp->cno + 1) { 108*e0b8e63eSJohn Marino sp->cno = len; 109*e0b8e63eSJohn Marino LF_SET(TXT_APPENDEOL); 110*e0b8e63eSJohn Marino } else 111*e0b8e63eSJohn Marino ++sp->cno; 112*e0b8e63eSJohn Marino } else 113*e0b8e63eSJohn Marino LF_SET(TXT_APPENDEOL); 114*e0b8e63eSJohn Marino 115*e0b8e63eSJohn Marino return (v_txt(sp, vp, NULL, p, len, 116*e0b8e63eSJohn Marino 0, OOBLNO, F_ISSET(vp, VC_C1SET) ? vp->count : 1, flags)); 117*e0b8e63eSJohn Marino } 118*e0b8e63eSJohn Marino 119*e0b8e63eSJohn Marino /* 120*e0b8e63eSJohn Marino * v_iI -- [count]I 121*e0b8e63eSJohn Marino * Insert text at the first nonblank. 122*e0b8e63eSJohn Marino * 123*e0b8e63eSJohn Marino * PUBLIC: int v_iI(SCR *, VICMD *); 124*e0b8e63eSJohn Marino */ 125*e0b8e63eSJohn Marino int 126*e0b8e63eSJohn Marino v_iI(SCR *sp, VICMD *vp) 127*e0b8e63eSJohn Marino { 128*e0b8e63eSJohn Marino sp->cno = 0; 129*e0b8e63eSJohn Marino if (nonblank(sp, vp->m_start.lno, &sp->cno)) 130*e0b8e63eSJohn Marino return (1); 131*e0b8e63eSJohn Marino 132*e0b8e63eSJohn Marino LOG_CORRECT; 133*e0b8e63eSJohn Marino 134*e0b8e63eSJohn Marino return (v_ii(sp, vp)); 135*e0b8e63eSJohn Marino } 136*e0b8e63eSJohn Marino 137*e0b8e63eSJohn Marino /* 138*e0b8e63eSJohn Marino * v_ii -- [count]i 139*e0b8e63eSJohn Marino * [count]I 140*e0b8e63eSJohn Marino * Insert text at the cursor position. 141*e0b8e63eSJohn Marino * 142*e0b8e63eSJohn Marino * PUBLIC: int v_ii(SCR *, VICMD *); 143*e0b8e63eSJohn Marino */ 144*e0b8e63eSJohn Marino int 145*e0b8e63eSJohn Marino v_ii(SCR *sp, VICMD *vp) 146*e0b8e63eSJohn Marino { 147*e0b8e63eSJohn Marino size_t len; 148*e0b8e63eSJohn Marino u_int32_t flags; 149*e0b8e63eSJohn Marino int isempty; 150*e0b8e63eSJohn Marino CHAR_T *p; 151*e0b8e63eSJohn Marino 152*e0b8e63eSJohn Marino flags = set_txt_std(sp, vp, 0); 153*e0b8e63eSJohn Marino sp->showmode = SM_INSERT; 154*e0b8e63eSJohn Marino sp->lno = vp->m_start.lno; 155*e0b8e63eSJohn Marino 156*e0b8e63eSJohn Marino if (db_eget(sp, sp->lno, &p, &len, &isempty)) { 157*e0b8e63eSJohn Marino if (!isempty) 158*e0b8e63eSJohn Marino return (1); 159*e0b8e63eSJohn Marino len = 0; 160*e0b8e63eSJohn Marino } 161*e0b8e63eSJohn Marino 162*e0b8e63eSJohn Marino if (len == 0) 163*e0b8e63eSJohn Marino LF_SET(TXT_APPENDEOL); 164*e0b8e63eSJohn Marino return (v_txt(sp, vp, NULL, p, len, 165*e0b8e63eSJohn Marino 0, OOBLNO, F_ISSET(vp, VC_C1SET) ? vp->count : 1, flags)); 166*e0b8e63eSJohn Marino } 167*e0b8e63eSJohn Marino 168*e0b8e63eSJohn Marino enum which { o_cmd, O_cmd }; 169*e0b8e63eSJohn Marino static int io(SCR *, VICMD *, enum which); 170*e0b8e63eSJohn Marino 171*e0b8e63eSJohn Marino /* 172*e0b8e63eSJohn Marino * v_iO -- [count]O 173*e0b8e63eSJohn Marino * Insert text above this line. 174*e0b8e63eSJohn Marino * 175*e0b8e63eSJohn Marino * PUBLIC: int v_iO(SCR *, VICMD *); 176*e0b8e63eSJohn Marino */ 177*e0b8e63eSJohn Marino int 178*e0b8e63eSJohn Marino v_iO(SCR *sp, VICMD *vp) 179*e0b8e63eSJohn Marino { 180*e0b8e63eSJohn Marino return (io(sp, vp, O_cmd)); 181*e0b8e63eSJohn Marino } 182*e0b8e63eSJohn Marino 183*e0b8e63eSJohn Marino /* 184*e0b8e63eSJohn Marino * v_io -- [count]o 185*e0b8e63eSJohn Marino * Insert text after this line. 186*e0b8e63eSJohn Marino * 187*e0b8e63eSJohn Marino * PUBLIC: int v_io(SCR *, VICMD *); 188*e0b8e63eSJohn Marino */ 189*e0b8e63eSJohn Marino int 190*e0b8e63eSJohn Marino v_io(SCR *sp, VICMD *vp) 191*e0b8e63eSJohn Marino { 192*e0b8e63eSJohn Marino return (io(sp, vp, o_cmd)); 193*e0b8e63eSJohn Marino } 194*e0b8e63eSJohn Marino 195*e0b8e63eSJohn Marino static int 196*e0b8e63eSJohn Marino io(SCR *sp, VICMD *vp, enum which cmd) 197*e0b8e63eSJohn Marino { 198*e0b8e63eSJohn Marino recno_t ai_line, lno; 199*e0b8e63eSJohn Marino size_t len; 200*e0b8e63eSJohn Marino u_int32_t flags; 201*e0b8e63eSJohn Marino CHAR_T *p; 202*e0b8e63eSJohn Marino 203*e0b8e63eSJohn Marino flags = set_txt_std(sp, vp, TXT_ADDNEWLINE | TXT_APPENDEOL); 204*e0b8e63eSJohn Marino sp->showmode = SM_INSERT; 205*e0b8e63eSJohn Marino 206*e0b8e63eSJohn Marino if (sp->lno == 1) { 207*e0b8e63eSJohn Marino if (db_last(sp, &lno)) 208*e0b8e63eSJohn Marino return (1); 209*e0b8e63eSJohn Marino if (lno != 0) 210*e0b8e63eSJohn Marino goto insert; 211*e0b8e63eSJohn Marino p = NULL; 212*e0b8e63eSJohn Marino len = 0; 213*e0b8e63eSJohn Marino ai_line = OOBLNO; 214*e0b8e63eSJohn Marino } else { 215*e0b8e63eSJohn Marino insert: p = L(""); 216*e0b8e63eSJohn Marino sp->cno = 0; 217*e0b8e63eSJohn Marino LOG_CORRECT; 218*e0b8e63eSJohn Marino 219*e0b8e63eSJohn Marino if (cmd == O_cmd) { 220*e0b8e63eSJohn Marino if (db_insert(sp, sp->lno, p, 0)) 221*e0b8e63eSJohn Marino return (1); 222*e0b8e63eSJohn Marino if (db_get(sp, sp->lno, DBG_FATAL, &p, &len)) 223*e0b8e63eSJohn Marino return (1); 224*e0b8e63eSJohn Marino ai_line = sp->lno + 1; 225*e0b8e63eSJohn Marino } else { 226*e0b8e63eSJohn Marino if (db_append(sp, 1, sp->lno, p, 0)) 227*e0b8e63eSJohn Marino return (1); 228*e0b8e63eSJohn Marino if (db_get(sp, ++sp->lno, DBG_FATAL, &p, &len)) 229*e0b8e63eSJohn Marino return (1); 230*e0b8e63eSJohn Marino ai_line = sp->lno - 1; 231*e0b8e63eSJohn Marino } 232*e0b8e63eSJohn Marino } 233*e0b8e63eSJohn Marino return (v_txt(sp, vp, NULL, p, len, 234*e0b8e63eSJohn Marino 0, ai_line, F_ISSET(vp, VC_C1SET) ? vp->count : 1, flags)); 235*e0b8e63eSJohn Marino } 236*e0b8e63eSJohn Marino 237*e0b8e63eSJohn Marino /* 238*e0b8e63eSJohn Marino * v_change -- [buffer][count]c[count]motion 239*e0b8e63eSJohn Marino * [buffer][count]C 240*e0b8e63eSJohn Marino * [buffer][count]S 241*e0b8e63eSJohn Marino * Change command. 242*e0b8e63eSJohn Marino * 243*e0b8e63eSJohn Marino * PUBLIC: int v_change(SCR *, VICMD *); 244*e0b8e63eSJohn Marino */ 245*e0b8e63eSJohn Marino int 246*e0b8e63eSJohn Marino v_change(SCR *sp, VICMD *vp) 247*e0b8e63eSJohn Marino { 248*e0b8e63eSJohn Marino size_t blen, len; 249*e0b8e63eSJohn Marino u_int32_t flags; 250*e0b8e63eSJohn Marino int isempty, lmode, rval; 251*e0b8e63eSJohn Marino CHAR_T *bp; 252*e0b8e63eSJohn Marino CHAR_T *p; 253*e0b8e63eSJohn Marino 254*e0b8e63eSJohn Marino /* 255*e0b8e63eSJohn Marino * 'c' can be combined with motion commands that set the resulting 256*e0b8e63eSJohn Marino * cursor position, i.e. "cG". Clear the VM_RCM flags and make the 257*e0b8e63eSJohn Marino * resulting cursor position stick, inserting text has its own rules 258*e0b8e63eSJohn Marino * for cursor positioning. 259*e0b8e63eSJohn Marino */ 260*e0b8e63eSJohn Marino F_CLR(vp, VM_RCM_MASK); 261*e0b8e63eSJohn Marino F_SET(vp, VM_RCM_SET); 262*e0b8e63eSJohn Marino 263*e0b8e63eSJohn Marino /* 264*e0b8e63eSJohn Marino * Find out if the file is empty, it's easier to handle it as a 265*e0b8e63eSJohn Marino * special case. 266*e0b8e63eSJohn Marino */ 267*e0b8e63eSJohn Marino if (vp->m_start.lno == vp->m_stop.lno && 268*e0b8e63eSJohn Marino db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) { 269*e0b8e63eSJohn Marino if (!isempty) 270*e0b8e63eSJohn Marino return (1); 271*e0b8e63eSJohn Marino return (v_ia(sp, vp)); 272*e0b8e63eSJohn Marino } 273*e0b8e63eSJohn Marino 274*e0b8e63eSJohn Marino flags = set_txt_std(sp, vp, 0); 275*e0b8e63eSJohn Marino sp->showmode = SM_CHANGE; 276*e0b8e63eSJohn Marino 277*e0b8e63eSJohn Marino /* 278*e0b8e63eSJohn Marino * Move the cursor to the start of the change. Note, if autoindent 279*e0b8e63eSJohn Marino * is turned on, the cc command in line mode changes from the first 280*e0b8e63eSJohn Marino * *non-blank* character of the line, not the first character. And, 281*e0b8e63eSJohn Marino * to make it just a bit more exciting, the initial space is handled 282*e0b8e63eSJohn Marino * as auto-indent characters. 283*e0b8e63eSJohn Marino */ 284*e0b8e63eSJohn Marino lmode = F_ISSET(vp, VM_LMODE) ? CUT_LINEMODE : 0; 285*e0b8e63eSJohn Marino if (lmode) { 286*e0b8e63eSJohn Marino vp->m_start.cno = 0; 287*e0b8e63eSJohn Marino if (O_ISSET(sp, O_AUTOINDENT)) { 288*e0b8e63eSJohn Marino if (nonblank(sp, vp->m_start.lno, &vp->m_start.cno)) 289*e0b8e63eSJohn Marino return (1); 290*e0b8e63eSJohn Marino LF_SET(TXT_AICHARS); 291*e0b8e63eSJohn Marino } 292*e0b8e63eSJohn Marino } 293*e0b8e63eSJohn Marino sp->lno = vp->m_start.lno; 294*e0b8e63eSJohn Marino sp->cno = vp->m_start.cno; 295*e0b8e63eSJohn Marino 296*e0b8e63eSJohn Marino LOG_CORRECT; 297*e0b8e63eSJohn Marino 298*e0b8e63eSJohn Marino /* 299*e0b8e63eSJohn Marino * If not in line mode and changing within a single line, copy the 300*e0b8e63eSJohn Marino * text and overwrite it. 301*e0b8e63eSJohn Marino */ 302*e0b8e63eSJohn Marino if (!lmode && vp->m_start.lno == vp->m_stop.lno) { 303*e0b8e63eSJohn Marino /* 304*e0b8e63eSJohn Marino * !!! 305*e0b8e63eSJohn Marino * Historic practice, c did not cut into the numeric buffers, 306*e0b8e63eSJohn Marino * only the unnamed one. 307*e0b8e63eSJohn Marino */ 308*e0b8e63eSJohn Marino if (cut(sp, 309*e0b8e63eSJohn Marino F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, 310*e0b8e63eSJohn Marino &vp->m_start, &vp->m_stop, lmode)) 311*e0b8e63eSJohn Marino return (1); 312*e0b8e63eSJohn Marino if (len == 0) 313*e0b8e63eSJohn Marino LF_SET(TXT_APPENDEOL); 314*e0b8e63eSJohn Marino LF_SET(TXT_EMARK | TXT_OVERWRITE); 315*e0b8e63eSJohn Marino return (v_txt(sp, vp, &vp->m_stop, p, len, 316*e0b8e63eSJohn Marino 0, OOBLNO, F_ISSET(vp, VC_C1SET) ? vp->count : 1, flags)); 317*e0b8e63eSJohn Marino } 318*e0b8e63eSJohn Marino 319*e0b8e63eSJohn Marino /* 320*e0b8e63eSJohn Marino * It's trickier if in line mode or changing over multiple lines. If 321*e0b8e63eSJohn Marino * we're in line mode delete all of the lines and insert a replacement 322*e0b8e63eSJohn Marino * line which the user edits. If there was leading whitespace in the 323*e0b8e63eSJohn Marino * first line being changed, we copy it and use it as the replacement. 324*e0b8e63eSJohn Marino * If we're not in line mode, we delete the text and start inserting. 325*e0b8e63eSJohn Marino * 326*e0b8e63eSJohn Marino * !!! 327*e0b8e63eSJohn Marino * Copy the text. Historic practice, c did not cut into the numeric 328*e0b8e63eSJohn Marino * buffers, only the unnamed one. 329*e0b8e63eSJohn Marino */ 330*e0b8e63eSJohn Marino if (cut(sp, 331*e0b8e63eSJohn Marino F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, 332*e0b8e63eSJohn Marino &vp->m_start, &vp->m_stop, lmode)) 333*e0b8e63eSJohn Marino return (1); 334*e0b8e63eSJohn Marino 335*e0b8e63eSJohn Marino /* If replacing entire lines and there's leading text. */ 336*e0b8e63eSJohn Marino if (lmode && vp->m_start.cno) { 337*e0b8e63eSJohn Marino /* 338*e0b8e63eSJohn Marino * Get a copy of the first line changed, and copy out the 339*e0b8e63eSJohn Marino * leading text. 340*e0b8e63eSJohn Marino */ 341*e0b8e63eSJohn Marino if (db_get(sp, vp->m_start.lno, DBG_FATAL, &p, &len)) 342*e0b8e63eSJohn Marino return (1); 343*e0b8e63eSJohn Marino GET_SPACE_RETW(sp, bp, blen, vp->m_start.cno); 344*e0b8e63eSJohn Marino MEMMOVE(bp, p, vp->m_start.cno); 345*e0b8e63eSJohn Marino } else 346*e0b8e63eSJohn Marino bp = NULL; 347*e0b8e63eSJohn Marino 348*e0b8e63eSJohn Marino /* Delete the text. */ 349*e0b8e63eSJohn Marino if (del(sp, &vp->m_start, &vp->m_stop, lmode)) 350*e0b8e63eSJohn Marino return (1); 351*e0b8e63eSJohn Marino 352*e0b8e63eSJohn Marino /* If replacing entire lines, insert a replacement line. */ 353*e0b8e63eSJohn Marino if (lmode) { 354*e0b8e63eSJohn Marino if (db_insert(sp, vp->m_start.lno, bp, vp->m_start.cno)) 355*e0b8e63eSJohn Marino return (1); 356*e0b8e63eSJohn Marino sp->lno = vp->m_start.lno; 357*e0b8e63eSJohn Marino len = sp->cno = vp->m_start.cno; 358*e0b8e63eSJohn Marino } 359*e0b8e63eSJohn Marino 360*e0b8e63eSJohn Marino /* Get the line we're editing. */ 361*e0b8e63eSJohn Marino if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) { 362*e0b8e63eSJohn Marino if (!isempty) 363*e0b8e63eSJohn Marino return (1); 364*e0b8e63eSJohn Marino len = 0; 365*e0b8e63eSJohn Marino } 366*e0b8e63eSJohn Marino 367*e0b8e63eSJohn Marino /* Check to see if we're appending to the line. */ 368*e0b8e63eSJohn Marino if (vp->m_start.cno >= len) 369*e0b8e63eSJohn Marino LF_SET(TXT_APPENDEOL); 370*e0b8e63eSJohn Marino 371*e0b8e63eSJohn Marino rval = v_txt(sp, vp, NULL, p, len, 372*e0b8e63eSJohn Marino 0, OOBLNO, F_ISSET(vp, VC_C1SET) ? vp->count : 1, flags); 373*e0b8e63eSJohn Marino 374*e0b8e63eSJohn Marino if (bp != NULL) 375*e0b8e63eSJohn Marino FREE_SPACEW(sp, bp, blen); 376*e0b8e63eSJohn Marino return (rval); 377*e0b8e63eSJohn Marino } 378*e0b8e63eSJohn Marino 379*e0b8e63eSJohn Marino /* 380*e0b8e63eSJohn Marino * v_Replace -- [count]R 381*e0b8e63eSJohn Marino * Overwrite multiple characters. 382*e0b8e63eSJohn Marino * 383*e0b8e63eSJohn Marino * PUBLIC: int v_Replace(SCR *, VICMD *); 384*e0b8e63eSJohn Marino */ 385*e0b8e63eSJohn Marino int 386*e0b8e63eSJohn Marino v_Replace(SCR *sp, VICMD *vp) 387*e0b8e63eSJohn Marino { 388*e0b8e63eSJohn Marino size_t len; 389*e0b8e63eSJohn Marino u_int32_t flags; 390*e0b8e63eSJohn Marino int isempty; 391*e0b8e63eSJohn Marino CHAR_T *p; 392*e0b8e63eSJohn Marino 393*e0b8e63eSJohn Marino flags = set_txt_std(sp, vp, 0); 394*e0b8e63eSJohn Marino sp->showmode = SM_REPLACE; 395*e0b8e63eSJohn Marino 396*e0b8e63eSJohn Marino if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) { 397*e0b8e63eSJohn Marino if (!isempty) 398*e0b8e63eSJohn Marino return (1); 399*e0b8e63eSJohn Marino len = 0; 400*e0b8e63eSJohn Marino LF_SET(TXT_APPENDEOL); 401*e0b8e63eSJohn Marino } else { 402*e0b8e63eSJohn Marino if (len == 0) 403*e0b8e63eSJohn Marino LF_SET(TXT_APPENDEOL); 404*e0b8e63eSJohn Marino LF_SET(TXT_OVERWRITE | TXT_REPLACE); 405*e0b8e63eSJohn Marino } 406*e0b8e63eSJohn Marino vp->m_stop.lno = vp->m_start.lno; 407*e0b8e63eSJohn Marino vp->m_stop.cno = len ? len - 1 : 0; 408*e0b8e63eSJohn Marino 409*e0b8e63eSJohn Marino return (v_txt(sp, vp, &vp->m_stop, p, len, 410*e0b8e63eSJohn Marino 0, OOBLNO, F_ISSET(vp, VC_C1SET) ? vp->count : 1, flags)); 411*e0b8e63eSJohn Marino } 412*e0b8e63eSJohn Marino 413*e0b8e63eSJohn Marino /* 414*e0b8e63eSJohn Marino * v_subst -- [buffer][count]s 415*e0b8e63eSJohn Marino * Substitute characters. 416*e0b8e63eSJohn Marino * 417*e0b8e63eSJohn Marino * PUBLIC: int v_subst(SCR *, VICMD *); 418*e0b8e63eSJohn Marino */ 419*e0b8e63eSJohn Marino int 420*e0b8e63eSJohn Marino v_subst(SCR *sp, VICMD *vp) 421*e0b8e63eSJohn Marino { 422*e0b8e63eSJohn Marino size_t len; 423*e0b8e63eSJohn Marino u_int32_t flags; 424*e0b8e63eSJohn Marino int isempty; 425*e0b8e63eSJohn Marino CHAR_T *p; 426*e0b8e63eSJohn Marino 427*e0b8e63eSJohn Marino flags = set_txt_std(sp, vp, 0); 428*e0b8e63eSJohn Marino sp->showmode = SM_CHANGE; 429*e0b8e63eSJohn Marino 430*e0b8e63eSJohn Marino if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) { 431*e0b8e63eSJohn Marino if (!isempty) 432*e0b8e63eSJohn Marino return (1); 433*e0b8e63eSJohn Marino len = 0; 434*e0b8e63eSJohn Marino LF_SET(TXT_APPENDEOL); 435*e0b8e63eSJohn Marino } else { 436*e0b8e63eSJohn Marino if (len == 0) 437*e0b8e63eSJohn Marino LF_SET(TXT_APPENDEOL); 438*e0b8e63eSJohn Marino LF_SET(TXT_EMARK | TXT_OVERWRITE); 439*e0b8e63eSJohn Marino } 440*e0b8e63eSJohn Marino 441*e0b8e63eSJohn Marino vp->m_stop.lno = vp->m_start.lno; 442*e0b8e63eSJohn Marino vp->m_stop.cno = 443*e0b8e63eSJohn Marino vp->m_start.cno + (F_ISSET(vp, VC_C1SET) ? vp->count - 1 : 0); 444*e0b8e63eSJohn Marino if (vp->m_stop.cno > len - 1) 445*e0b8e63eSJohn Marino vp->m_stop.cno = len - 1; 446*e0b8e63eSJohn Marino 447*e0b8e63eSJohn Marino if (p != NULL && cut(sp, 448*e0b8e63eSJohn Marino F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, 449*e0b8e63eSJohn Marino &vp->m_start, &vp->m_stop, 0)) 450*e0b8e63eSJohn Marino return (1); 451*e0b8e63eSJohn Marino 452*e0b8e63eSJohn Marino return (v_txt(sp, vp, &vp->m_stop, p, len, 0, OOBLNO, 1, flags)); 453*e0b8e63eSJohn Marino } 454*e0b8e63eSJohn Marino 455*e0b8e63eSJohn Marino /* 456*e0b8e63eSJohn Marino * set_txt_std -- 457*e0b8e63eSJohn Marino * Initialize text processing flags. 458*e0b8e63eSJohn Marino */ 459*e0b8e63eSJohn Marino static u_int32_t 460*e0b8e63eSJohn Marino set_txt_std(SCR *sp, VICMD *vp, u_int32_t flags) 461*e0b8e63eSJohn Marino { 462*e0b8e63eSJohn Marino LF_SET(TXT_CNTRLT | 463*e0b8e63eSJohn Marino TXT_ESCAPE | TXT_MAPINPUT | TXT_RECORD | TXT_RESOLVE); 464*e0b8e63eSJohn Marino 465*e0b8e63eSJohn Marino if (F_ISSET(vp, VC_ISDOT)) 466*e0b8e63eSJohn Marino LF_SET(TXT_REPLAY); 467*e0b8e63eSJohn Marino 468*e0b8e63eSJohn Marino if (O_ISSET(sp, O_ALTWERASE)) 469*e0b8e63eSJohn Marino LF_SET(TXT_ALTWERASE); 470*e0b8e63eSJohn Marino if (O_ISSET(sp, O_AUTOINDENT)) 471*e0b8e63eSJohn Marino LF_SET(TXT_AUTOINDENT); 472*e0b8e63eSJohn Marino if (O_ISSET(sp, O_BEAUTIFY)) 473*e0b8e63eSJohn Marino LF_SET(TXT_BEAUTIFY); 474*e0b8e63eSJohn Marino if (O_ISSET(sp, O_SHOWMATCH)) 475*e0b8e63eSJohn Marino LF_SET(TXT_SHOWMATCH); 476*e0b8e63eSJohn Marino if (F_ISSET(sp, SC_SCRIPT)) 477*e0b8e63eSJohn Marino LF_SET(TXT_CR); 478*e0b8e63eSJohn Marino if (O_ISSET(sp, O_TTYWERASE)) 479*e0b8e63eSJohn Marino LF_SET(TXT_TTYWERASE); 480*e0b8e63eSJohn Marino 481*e0b8e63eSJohn Marino /* 482*e0b8e63eSJohn Marino * !!! 483*e0b8e63eSJohn Marino * Mapped keys were sometimes unaffected by the wrapmargin option 484*e0b8e63eSJohn Marino * in the historic 4BSD vi. Consider the following commands, where 485*e0b8e63eSJohn Marino * each is executed on an empty line, in an 80 column screen, with 486*e0b8e63eSJohn Marino * the wrapmargin value set to 60. 487*e0b8e63eSJohn Marino * 488*e0b8e63eSJohn Marino * aABC DEF <ESC>.... 489*e0b8e63eSJohn Marino * :map K aABC DEF ^V<ESC><CR>KKKKK 490*e0b8e63eSJohn Marino * :map K 5aABC DEF ^V<ESC><CR>K 491*e0b8e63eSJohn Marino * 492*e0b8e63eSJohn Marino * The first and second commands are affected by wrapmargin. The 493*e0b8e63eSJohn Marino * third is not. (If the inserted text is itself longer than the 494*e0b8e63eSJohn Marino * wrapmargin value, i.e. if the "ABC DEF " string is replaced by 495*e0b8e63eSJohn Marino * something that's longer than 60 columns from the beginning of 496*e0b8e63eSJohn Marino * the line, the first two commands behave as before, but the third 497*e0b8e63eSJohn Marino * command gets fairly strange.) The problem is that people wrote 498*e0b8e63eSJohn Marino * macros that depended on the third command NOT being affected by 499*e0b8e63eSJohn Marino * wrapmargin, as in this gem which centers lines: 500*e0b8e63eSJohn Marino * 501*e0b8e63eSJohn Marino * map #c $mq81a ^V^[81^V^V|D`qld0:s/ / /g^V^M$p 502*e0b8e63eSJohn Marino * 503*e0b8e63eSJohn Marino * For compatibility reasons, we try and make it all work here. I 504*e0b8e63eSJohn Marino * offer no hope that this is right, but it's probably pretty close. 505*e0b8e63eSJohn Marino * 506*e0b8e63eSJohn Marino * XXX 507*e0b8e63eSJohn Marino * Once I work my courage up, this is all gonna go away. It's too 508*e0b8e63eSJohn Marino * evil to survive. 509*e0b8e63eSJohn Marino */ 510*e0b8e63eSJohn Marino if ((O_ISSET(sp, O_WRAPLEN) || O_ISSET(sp, O_WRAPMARGIN)) && 511*e0b8e63eSJohn Marino (!MAPPED_KEYS_WAITING(sp) || !F_ISSET(vp, VC_C1SET))) 512*e0b8e63eSJohn Marino LF_SET(TXT_WRAPMARGIN); 513*e0b8e63eSJohn Marino return (flags); 514*e0b8e63eSJohn Marino } 515