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