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