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