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