1 /*- 2 * Copyright (c) 1992, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 1992, 1993, 1994, 1995, 1996 5 * Keith Bostic. All rights reserved. 6 * 7 * See the LICENSE file for redistribution information. 8 */ 9 10 #include "config.h" 11 12 #ifndef lint 13 static const char sccsid[] = "@(#)ex_append.c 10.30 (Berkeley) 10/23/96"; 14 #endif /* not lint */ 15 16 #include <sys/types.h> 17 #include <sys/queue.h> 18 19 #include <bitstring.h> 20 #include <limits.h> 21 #include <stdio.h> 22 #include <string.h> 23 #include <unistd.h> 24 25 #include "../common/common.h" 26 27 enum which {APPEND, CHANGE, INSERT}; 28 29 static int ex_aci __P((SCR *, EXCMD *, enum which)); 30 31 /* 32 * ex_append -- :[line] a[ppend][!] 33 * Append one or more lines of new text after the specified line, 34 * or the current line if no address is specified. 35 * 36 * PUBLIC: int ex_append __P((SCR *, EXCMD *)); 37 */ 38 int 39 ex_append(sp, cmdp) 40 SCR *sp; 41 EXCMD *cmdp; 42 { 43 return (ex_aci(sp, cmdp, APPEND)); 44 } 45 46 /* 47 * ex_change -- :[line[,line]] c[hange][!] [count] 48 * Change one or more lines to the input text. 49 * 50 * PUBLIC: int ex_change __P((SCR *, EXCMD *)); 51 */ 52 int 53 ex_change(sp, cmdp) 54 SCR *sp; 55 EXCMD *cmdp; 56 { 57 return (ex_aci(sp, cmdp, CHANGE)); 58 } 59 60 /* 61 * ex_insert -- :[line] i[nsert][!] 62 * Insert one or more lines of new text before the specified line, 63 * or the current line if no address is specified. 64 * 65 * PUBLIC: int ex_insert __P((SCR *, EXCMD *)); 66 */ 67 int 68 ex_insert(sp, cmdp) 69 SCR *sp; 70 EXCMD *cmdp; 71 { 72 return (ex_aci(sp, cmdp, INSERT)); 73 } 74 75 /* 76 * ex_aci -- 77 * Append, change, insert in ex. 78 */ 79 static int 80 ex_aci(sp, cmdp, cmd) 81 SCR *sp; 82 EXCMD *cmdp; 83 enum which cmd; 84 { 85 CHAR_T *p, *t; 86 GS *gp; 87 TEXT *tp; 88 TEXTH tiq; 89 recno_t cnt, lno; 90 size_t len; 91 u_int32_t flags; 92 int need_newline; 93 94 gp = sp->gp; 95 NEEDFILE(sp, cmdp); 96 97 /* 98 * If doing a change, replace lines for as long as possible. Then, 99 * append more lines or delete remaining lines. Changes to an empty 100 * file are appends, inserts are the same as appends to the previous 101 * line. 102 * 103 * !!! 104 * Set the address to which we'll append. We set sp->lno to this 105 * address as well so that autoindent works correctly when get text 106 * from the user. 107 */ 108 lno = cmdp->addr1.lno; 109 sp->lno = lno; 110 if ((cmd == CHANGE || cmd == INSERT) && lno != 0) 111 --lno; 112 113 /* 114 * !!! 115 * If the file isn't empty, cut changes into the unnamed buffer. 116 */ 117 if (cmd == CHANGE && cmdp->addr1.lno != 0 && 118 (cut(sp, NULL, &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE) || 119 del(sp, &cmdp->addr1, &cmdp->addr2, 1))) 120 return (1); 121 122 /* 123 * !!! 124 * Anything that was left after the command separator becomes part 125 * of the inserted text. Apparently, it was common usage to enter: 126 * 127 * :g/pattern/append|stuff1 128 * 129 * and append the line of text "stuff1" to the lines containing the 130 * pattern. It was also historically legal to enter: 131 * 132 * :append|stuff1 133 * stuff2 134 * . 135 * 136 * and the text on the ex command line would be appended as well as 137 * the text inserted after it. There was an historic bug however, 138 * that the user had to enter *two* terminating lines (the '.' lines) 139 * to terminate text input mode, in this case. This whole thing 140 * could be taken too far, however. Entering: 141 * 142 * :append|stuff1\ 143 * stuff2 144 * stuff3 145 * . 146 * 147 * i.e. mixing and matching the forms confused the historic vi, and, 148 * not only did it take two terminating lines to terminate text input 149 * mode, but the trailing backslashes were retained on the input. We 150 * match historic practice except that we discard the backslashes. 151 * 152 * Input lines specified on the ex command line lines are separated by 153 * <newline>s. If there is a trailing delimiter an empty line was 154 * inserted. There may also be a leading delimiter, which is ignored 155 * unless it's also a trailing delimiter. It is possible to encounter 156 * a termination line, i.e. a single '.', in a global command, but not 157 * necessary if the text insert command was the last of the global 158 * commands. 159 */ 160 if (cmdp->save_cmdlen != 0) { 161 for (p = cmdp->save_cmd, 162 len = cmdp->save_cmdlen; len > 0; p = t) { 163 for (t = p; len > 0 && t[0] != '\n'; ++t, --len); 164 if (t != p || len == 0) { 165 if (F_ISSET(sp, SC_EX_GLOBAL) && 166 t - p == 1 && p[0] == '.') { 167 ++t; 168 if (len > 0) 169 --len; 170 break; 171 } 172 if (db_append(sp, 1, lno++, p, t - p)) 173 return (1); 174 } 175 if (len != 0) { 176 ++t; 177 if (--len == 0 && 178 db_append(sp, 1, lno++, "", 0)) 179 return (1); 180 } 181 } 182 /* 183 * If there's any remaining text, we're in a global, and 184 * there's more command to parse. 185 * 186 * !!! 187 * We depend on the fact that non-global commands will eat the 188 * rest of the command line as text input, and before getting 189 * any text input from the user. Otherwise, we'd have to save 190 * off the command text before or during the call to the text 191 * input function below. 192 */ 193 if (len != 0) 194 cmdp->save_cmd = t; 195 cmdp->save_cmdlen = len; 196 } 197 198 if (F_ISSET(sp, SC_EX_GLOBAL)) { 199 if ((sp->lno = lno) == 0 && db_exist(sp, 1)) 200 sp->lno = 1; 201 return (0); 202 } 203 204 /* 205 * If not in a global command, read from the terminal. 206 * 207 * If this code is called by vi, we want to reset the terminal and use 208 * ex's line get routine. It actually works fine if we use vi's get 209 * routine, but it doesn't look as nice. Maybe if we had a separate 210 * window or something, but getting a line at a time looks awkward. 211 * However, depending on the screen that we're using, that may not 212 * be possible. 213 */ 214 if (F_ISSET(sp, SC_VI)) { 215 if (gp->scr_screen(sp, SC_EX)) { 216 ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON); 217 return (1); 218 } 219 220 /* If we're still in the vi screen, move out explicitly. */ 221 need_newline = !F_ISSET(sp, SC_SCR_EXWROTE); 222 F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE); 223 if (need_newline) 224 (void)ex_puts(sp, "\n"); 225 226 /* 227 * !!! 228 * Users of historical versions of vi sometimes get confused 229 * when they enter append mode, and can't seem to get out of 230 * it. Give them an informational message. 231 */ 232 (void)ex_puts(sp, 233 msg_cat(sp, "273|Entering ex input mode.", NULL)); 234 (void)ex_puts(sp, "\n"); 235 (void)ex_fflush(sp); 236 } 237 238 /* 239 * Set input flags; the ! flag turns off autoindent for append, 240 * change and insert. 241 */ 242 LF_INIT(TXT_DOTTERM | TXT_NUMBER); 243 if (!FL_ISSET(cmdp->iflags, E_C_FORCE) && O_ISSET(sp, O_AUTOINDENT)) 244 LF_SET(TXT_AUTOINDENT); 245 if (O_ISSET(sp, O_BEAUTIFY)) 246 LF_SET(TXT_BEAUTIFY); 247 248 /* 249 * This code can't use the common screen TEXTH structure (sp->tiq), 250 * as it may already be in use, e.g. ":append|s/abc/ABC/" would fail 251 * as we are only halfway through the text when the append code fires. 252 * Use a local structure instead. (The ex code would have to use a 253 * local structure except that we're guaranteed to finish remaining 254 * characters in the common TEXTH structure when they were inserted 255 * into the file, above.) 256 */ 257 memset(&tiq, 0, sizeof(TEXTH)); 258 CIRCLEQ_INIT(&tiq); 259 260 if (ex_txt(sp, &tiq, 0, flags)) 261 return (1); 262 263 for (cnt = 0, tp = tiq.cqh_first; 264 tp != (TEXT *)&tiq; ++cnt, tp = tp->q.cqe_next) 265 if (db_append(sp, 1, lno++, tp->lb, tp->len)) 266 return (1); 267 268 /* 269 * Set sp->lno to the final line number value (correcting for a 270 * possible 0 value) as that's historically correct for the final 271 * line value, whether or not the user entered any text. 272 */ 273 if ((sp->lno = lno) == 0 && db_exist(sp, 1)) 274 sp->lno = 1; 275 276 return (0); 277 } 278