1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #ifndef lint 8 static char *sccsid = "@(#)ex_addr.c 7.5 (Berkeley) 07/22/88"; 9 #endif not lint 10 11 #include "ex.h" 12 #include "ex_re.h" 13 14 /* 15 * Routines for address parsing and assignment and checking of address bounds 16 * in command mode. The routine address is called from ex_cmds.c 17 * to parse each component of a command (terminated by , ; or the beginning 18 * of the command itself. It is also called by the scanning routine 19 * in ex_voperate.c from within open/visual. 20 * 21 * Other routines here manipulate the externals addr1 and addr2. 22 * These are the first and last lines for the current command. 23 * 24 * The variable bigmove remembers whether a non-local glitch of . was 25 * involved in an address expression, so we can set the previous context 26 * mark '' when such a motion occurs. 27 */ 28 29 static bool bigmove; 30 31 /* 32 * Set up addr1 and addr2 for commands whose default address is dot. 33 */ 34 setdot() 35 { 36 37 setdot1(); 38 if (bigmove) 39 markDOT(); 40 } 41 42 /* 43 * Call setdot1 to set up default addresses without ever 44 * setting the previous context mark. 45 */ 46 setdot1() 47 { 48 49 if (addr2 == 0) 50 addr1 = addr2 = dot; 51 if (addr1 > addr2) { 52 notempty(); 53 error("Addr1 > addr2|First address exceeds second"); 54 } 55 } 56 57 /* 58 * Ex allows you to say 59 * delete 5 60 * to delete 5 lines, etc. 61 * Such nonsense is implemented by setcount. 62 */ 63 setcount() 64 { 65 register int cnt; 66 67 pastwh(); 68 if (!isdigit(peekchar())) { 69 setdot(); 70 return; 71 } 72 addr1 = addr2; 73 setdot(); 74 cnt = getnum(); 75 if (cnt <= 0) 76 error("Bad count|Nonzero count required"); 77 addr2 += cnt - 1; 78 if (addr2 > dol) 79 addr2 = dol; 80 nonzero(); 81 } 82 83 /* 84 * Parse a number out of the command input stream. 85 */ 86 getnum() 87 { 88 register int cnt; 89 90 for (cnt = 0; isdigit(peekcd());) 91 cnt = cnt * 10 + ex_getchar() - '0'; 92 return (cnt); 93 } 94 95 /* 96 * Set the default addresses for commands which use the whole 97 * buffer as default, notably write. 98 */ 99 setall() 100 { 101 102 if (addr2 == 0) { 103 addr1 = one; 104 addr2 = dol; 105 if (dol == zero) { 106 dot = zero; 107 return; 108 } 109 } 110 /* 111 * Don't want to set previous context mark so use setdot1(). 112 */ 113 setdot1(); 114 } 115 116 /* 117 * No address allowed on, e.g. the file command. 118 */ 119 setnoaddr() 120 { 121 122 if (addr2 != 0) 123 error("No address allowed@on this command"); 124 } 125 126 /* 127 * Parse an address. 128 * Just about any sequence of address characters is legal. 129 * 130 * If you are tricky you can use this routine and the = command 131 * to do simple addition and subtraction of cardinals less 132 * than the number of lines in the file. 133 */ 134 line * 135 address(inputline) 136 char *inputline; 137 { 138 register line *addr; 139 register int offset, c; 140 short lastsign; 141 142 bigmove = 0; 143 lastsign = 0; 144 offset = 0; 145 addr = 0; 146 for (;;) { 147 if (isdigit(peekcd())) { 148 if (addr == 0) { 149 addr = zero; 150 bigmove = 1; 151 } 152 loc1 = 0; 153 addr += offset; 154 offset = getnum(); 155 if (lastsign >= 0) 156 addr += offset; 157 else 158 addr -= offset; 159 lastsign = 0; 160 offset = 0; 161 } 162 switch (c = getcd()) { 163 164 case '?': 165 case '/': 166 case '$': 167 case '\'': 168 case '\\': 169 bigmove++; 170 case '.': 171 if (addr || offset) 172 error("Badly formed address"); 173 } 174 offset += lastsign; 175 lastsign = 0; 176 switch (c) { 177 178 case ' ': 179 case '\t': 180 continue; 181 182 case '+': 183 lastsign = 1; 184 if (addr == 0) 185 addr = dot; 186 continue; 187 188 case '^': 189 case '-': 190 lastsign = -1; 191 if (addr == 0) 192 addr = dot; 193 continue; 194 195 case '\\': 196 case '?': 197 case '/': 198 c = compile(c, 1); 199 notempty(); 200 savere(scanre); 201 addr = dot; 202 if (inputline && execute(0, dot)) { 203 if (c == '/') { 204 while (loc1 <= inputline) { 205 if (loc1 == loc2) 206 loc2++; 207 if (!execute(1)) 208 goto nope; 209 } 210 break; 211 } else if (loc1 < inputline) { 212 char *last; 213 doques: 214 215 do { 216 last = loc1; 217 if (loc1 == loc2) 218 loc2++; 219 if (!execute(1)) 220 break; 221 } while (loc1 < inputline); 222 loc1 = last; 223 break; 224 } 225 } 226 nope: 227 for (;;) { 228 if (c == '/') { 229 addr++; 230 if (addr > dol) { 231 if (value(WRAPSCAN) == 0) 232 error("No match to BOTTOM|Address search hit BOTTOM without matching pattern"); 233 addr = zero; 234 } 235 } else { 236 addr--; 237 if (addr < zero) { 238 if (value(WRAPSCAN) == 0) 239 error("No match to TOP|Address search hit TOP without matching pattern"); 240 addr = dol; 241 } 242 } 243 if (execute(0, addr)) { 244 if (inputline && c == '?') { 245 inputline = &linebuf[LBSIZE]; 246 goto doques; 247 } 248 break; 249 } 250 if (addr == dot) 251 error("Fail|Pattern not found"); 252 } 253 continue; 254 255 case '$': 256 addr = dol; 257 continue; 258 259 case '.': 260 addr = dot; 261 continue; 262 263 case '\'': 264 c = markreg(ex_getchar()); 265 if (c == 0) 266 error("Marks are ' and a-z"); 267 addr = getmark(c); 268 if (addr == 0) 269 error("Undefined mark@referenced"); 270 break; 271 272 default: 273 ungetchar(c); 274 if (offset) { 275 if (addr == 0) 276 addr = dot; 277 addr += offset; 278 loc1 = 0; 279 } 280 if (addr == 0) { 281 bigmove = 0; 282 return (0); 283 } 284 if (addr != zero) 285 notempty(); 286 addr += lastsign; 287 if (addr < zero) 288 error("Negative address@- first buffer line is 1"); 289 if (addr > dol) 290 error("Not that many lines@in buffer"); 291 return (addr); 292 } 293 } 294 } 295 296 /* 297 * Abbreviations to make code smaller 298 * Left over from squashing ex version 1.1 into 299 * 11/34's and 11/40's. 300 */ 301 setCNL() 302 { 303 304 setcount(); 305 newline(); 306 } 307 308 setNAEOL() 309 { 310 311 setnoaddr(); 312 eol(); 313 } 314