1*c3a35c03Sdist /* 2*c3a35c03Sdist * Copyright (c) 1980 Regents of the University of California. 3*c3a35c03Sdist * All rights reserved. The Berkeley software License Agreement 4*c3a35c03Sdist * specifies the terms and conditions for redistribution. 5*c3a35c03Sdist */ 6*c3a35c03Sdist 7*c3a35c03Sdist #ifndef lint 8*c3a35c03Sdist static char sccsid[] = "@(#)ex_addr.c 5.1.1.1 (Berkeley) 05/31/85"; 9*c3a35c03Sdist #endif not lint 10*c3a35c03Sdist 11d0cad150Smark #include "ex.h" 12d0cad150Smark #include "ex_re.h" 13d0cad150Smark 14d0cad150Smark /* 15d0cad150Smark * Routines for address parsing and assignment and checking of address bounds 16d0cad150Smark * in command mode. The routine address is called from ex_cmds.c 17d0cad150Smark * to parse each component of a command (terminated by , ; or the beginning 18d0cad150Smark * of the command itself. It is also called by the scanning routine 19d0cad150Smark * in ex_voperate.c from within open/visual. 20d0cad150Smark * 21d0cad150Smark * Other routines here manipulate the externals addr1 and addr2. 22d0cad150Smark * These are the first and last lines for the current command. 23d0cad150Smark * 24d0cad150Smark * The variable bigmove remembers whether a non-local glitch of . was 25d0cad150Smark * involved in an address expression, so we can set the previous context 26d0cad150Smark * mark '' when such a motion occurs. 27d0cad150Smark */ 28d0cad150Smark 29d0cad150Smark static bool bigmove; 30d0cad150Smark 31d0cad150Smark /* 32d0cad150Smark * Set up addr1 and addr2 for commands whose default address is dot. 33d0cad150Smark */ 34d0cad150Smark setdot() 35d0cad150Smark { 36d0cad150Smark 37d0cad150Smark setdot1(); 38d0cad150Smark if (bigmove) 39d0cad150Smark markDOT(); 40d0cad150Smark } 41d0cad150Smark 42d0cad150Smark /* 43d0cad150Smark * Call setdot1 to set up default addresses without ever 44d0cad150Smark * setting the previous context mark. 45d0cad150Smark */ 46d0cad150Smark setdot1() 47d0cad150Smark { 48d0cad150Smark 49d0cad150Smark if (addr2 == 0) 50d0cad150Smark addr1 = addr2 = dot; 51d0cad150Smark if (addr1 > addr2) { 52d0cad150Smark notempty(); 53d0cad150Smark error("Addr1 > addr2|First address exceeds second"); 54d0cad150Smark } 55d0cad150Smark } 56d0cad150Smark 57d0cad150Smark /* 58d0cad150Smark * Ex allows you to say 59d0cad150Smark * delete 5 60d0cad150Smark * to delete 5 lines, etc. 61d0cad150Smark * Such nonsense is implemented by setcount. 62d0cad150Smark */ 63d0cad150Smark setcount() 64d0cad150Smark { 65d0cad150Smark register int cnt; 66d0cad150Smark 67d0cad150Smark pastwh(); 68d0cad150Smark if (!isdigit(peekchar())) { 69d0cad150Smark setdot(); 70d0cad150Smark return; 71d0cad150Smark } 72d0cad150Smark addr1 = addr2; 73d0cad150Smark setdot(); 74d0cad150Smark cnt = getnum(); 75d0cad150Smark if (cnt <= 0) 76d0cad150Smark error("Bad count|Nonzero count required"); 77d0cad150Smark addr2 += cnt - 1; 78d0cad150Smark if (addr2 > dol) 79d0cad150Smark addr2 = dol; 80d0cad150Smark nonzero(); 81d0cad150Smark } 82d0cad150Smark 83d0cad150Smark /* 84d0cad150Smark * Parse a number out of the command input stream. 85d0cad150Smark */ 86d0cad150Smark getnum() 87d0cad150Smark { 88d0cad150Smark register int cnt; 89d0cad150Smark 90d0cad150Smark for (cnt = 0; isdigit(peekcd());) 91d0cad150Smark cnt = cnt * 10 + getchar() - '0'; 92d0cad150Smark return (cnt); 93d0cad150Smark } 94d0cad150Smark 95d0cad150Smark /* 96d0cad150Smark * Set the default addresses for commands which use the whole 97d0cad150Smark * buffer as default, notably write. 98d0cad150Smark */ 99d0cad150Smark setall() 100d0cad150Smark { 101d0cad150Smark 102d0cad150Smark if (addr2 == 0) { 103d0cad150Smark addr1 = one; 104d0cad150Smark addr2 = dol; 105d0cad150Smark if (dol == zero) { 106d0cad150Smark dot = zero; 107d0cad150Smark return; 108d0cad150Smark } 109d0cad150Smark } 110d0cad150Smark /* 111d0cad150Smark * Don't want to set previous context mark so use setdot1(). 112d0cad150Smark */ 113d0cad150Smark setdot1(); 114d0cad150Smark } 115d0cad150Smark 116d0cad150Smark /* 117d0cad150Smark * No address allowed on, e.g. the file command. 118d0cad150Smark */ 119d0cad150Smark setnoaddr() 120d0cad150Smark { 121d0cad150Smark 122d0cad150Smark if (addr2 != 0) 123d0cad150Smark error("No address allowed@on this command"); 124d0cad150Smark } 125d0cad150Smark 126d0cad150Smark /* 127d0cad150Smark * Parse an address. 128d0cad150Smark * Just about any sequence of address characters is legal. 129d0cad150Smark * 130d0cad150Smark * If you are tricky you can use this routine and the = command 131d0cad150Smark * to do simple addition and subtraction of cardinals less 132d0cad150Smark * than the number of lines in the file. 133d0cad150Smark */ 134d0cad150Smark line * 135d0cad150Smark address(inline) 136d0cad150Smark char *inline; 137d0cad150Smark { 138d0cad150Smark register line *addr; 139d0cad150Smark register int offset, c; 140d0cad150Smark short lastsign; 141d0cad150Smark 142d0cad150Smark bigmove = 0; 143d0cad150Smark lastsign = 0; 144d0cad150Smark offset = 0; 145d0cad150Smark addr = 0; 146d0cad150Smark for (;;) { 147d0cad150Smark if (isdigit(peekcd())) { 148d0cad150Smark if (addr == 0) { 149d0cad150Smark addr = zero; 150d0cad150Smark bigmove = 1; 151d0cad150Smark } 152d0cad150Smark loc1 = 0; 153d0cad150Smark addr += offset; 154d0cad150Smark offset = getnum(); 155d0cad150Smark if (lastsign >= 0) 156d0cad150Smark addr += offset; 157d0cad150Smark else 158d0cad150Smark addr -= offset; 159d0cad150Smark lastsign = 0; 160d0cad150Smark offset = 0; 161d0cad150Smark } 162d0cad150Smark switch (c = getcd()) { 163d0cad150Smark 164d0cad150Smark case '?': 165d0cad150Smark case '/': 166d0cad150Smark case '$': 167d0cad150Smark case '\'': 168d0cad150Smark case '\\': 169d0cad150Smark bigmove++; 170d0cad150Smark case '.': 171d0cad150Smark if (addr || offset) 172d0cad150Smark error("Badly formed address"); 173d0cad150Smark } 174d0cad150Smark offset += lastsign; 175d0cad150Smark lastsign = 0; 176d0cad150Smark switch (c) { 177d0cad150Smark 178d0cad150Smark case ' ': 179d0cad150Smark case '\t': 180d0cad150Smark continue; 181d0cad150Smark 182d0cad150Smark case '+': 183d0cad150Smark lastsign = 1; 184d0cad150Smark if (addr == 0) 185d0cad150Smark addr = dot; 186d0cad150Smark continue; 187d0cad150Smark 188d0cad150Smark case '^': 189d0cad150Smark case '-': 190d0cad150Smark lastsign = -1; 191d0cad150Smark if (addr == 0) 192d0cad150Smark addr = dot; 193d0cad150Smark continue; 194d0cad150Smark 195d0cad150Smark case '\\': 196d0cad150Smark case '?': 197d0cad150Smark case '/': 198d0cad150Smark c = compile(c, 1); 199d0cad150Smark notempty(); 200d0cad150Smark savere(scanre); 201d0cad150Smark addr = dot; 202d0cad150Smark if (inline && execute(0, dot)) { 203d0cad150Smark if (c == '/') { 20433f18e4dSmark while (loc1 <= inline) { 20533f18e4dSmark if (loc1 == loc2) 20633f18e4dSmark loc2++; 207d0cad150Smark if (!execute(1)) 208d0cad150Smark goto nope; 20925f8d52cSmark } 21025f8d52cSmark break; 21125f8d52cSmark } else if (loc1 < inline) { 21225f8d52cSmark char *last; 21325f8d52cSmark doques: 21425f8d52cSmark 21525f8d52cSmark do { 21625f8d52cSmark last = loc1; 21725f8d52cSmark if (loc1 == loc2) 21825f8d52cSmark loc2++; 21925f8d52cSmark if (!execute(1)) 22025f8d52cSmark break; 22125f8d52cSmark } while (loc1 < inline); 22225f8d52cSmark loc1 = last; 22325f8d52cSmark break; 22425f8d52cSmark } 22525f8d52cSmark } 22625f8d52cSmark nope: 22725f8d52cSmark for (;;) { 22825f8d52cSmark if (c == '/') { 22925f8d52cSmark addr++; 23025f8d52cSmark if (addr > dol) { 23125f8d52cSmark if (value(WRAPSCAN) == 0) 23225f8d52cSmark error("No match to BOTTOM|Address search hit BOTTOM without matching pattern"); 23325f8d52cSmark addr = zero; 23425f8d52cSmark } 23525f8d52cSmark } else { 23625f8d52cSmark addr--; 23725f8d52cSmark if (addr < zero) { 23825f8d52cSmark if (value(WRAPSCAN) == 0) 23925f8d52cSmark error("No match to TOP|Address search hit TOP without matching pattern"); 24025f8d52cSmark addr = dol; 24125f8d52cSmark } 24225f8d52cSmark } 24325f8d52cSmark if (execute(0, addr)) { 24425f8d52cSmark if (inline && c == '?') { 24525f8d52cSmark inline = &linebuf[LBSIZE]; 24625f8d52cSmark goto doques; 24725f8d52cSmark } 24825f8d52cSmark break; 24925f8d52cSmark } 25025f8d52cSmark if (addr == dot) 25125f8d52cSmark error("Fail|Pattern not found"); 25225f8d52cSmark } 25325f8d52cSmark continue; 25425f8d52cSmark 25525f8d52cSmark case '$': 25625f8d52cSmark addr = dol; 25725f8d52cSmark continue; 25825f8d52cSmark 25925f8d52cSmark case '.': 26025f8d52cSmark addr = dot; 26125f8d52cSmark continue; 26225f8d52cSmark 26325f8d52cSmark case '\'': 26425f8d52cSmark c = markreg(getchar()); 26525f8d52cSmark if (c == 0) 26625f8d52cSmark error("Marks are ' and a-z"); 26725f8d52cSmark addr = getmark(c); 26825f8d52cSmark if (addr == 0) 26925f8d52cSmark error("Undefined mark@referenced"); 27025f8d52cSmark break; 27125f8d52cSmark 27225f8d52cSmark default: 27325f8d52cSmark ungetchar(c); 27425f8d52cSmark if (offset) { 27525f8d52cSmark if (addr == 0) 27625f8d52cSmark addr = dot; 27725f8d52cSmark addr += offset; 27825f8d52cSmark loc1 = 0; 27925f8d52cSmark } 28025f8d52cSmark if (addr == 0) { 28125f8d52cSmark bigmove = 0; 28225f8d52cSmark return (0); 28325f8d52cSmark } 28425f8d52cSmark if (addr != zero) 28525f8d52cSmark notempty(); 28625f8d52cSmark addr += lastsign; 28725f8d52cSmark if (addr < zero) 28825f8d52cSmark error("Negative address@- first buffer line is 1"); 28925f8d52cSmark if (addr > dol) 29025f8d52cSmark error("Not that many lines@in buffer"); 29125f8d52cSmark return (addr); 29225f8d52cSmark } 29325f8d52cSmark } 29425f8d52cSmark } 29525f8d52cSmark 29625f8d52cSmark /* 29725f8d52cSmark * Abbreviations to make code smaller 29825f8d52cSmark * Left over from squashing ex version 1.1 into 29925f8d52cSmark * 11/34's and 11/40's. 30025f8d52cSmark */ 30125f8d52cSmark setCNL() 30225f8d52cSmark { 30325f8d52cSmark 30425f8d52cSmark setcount(); 30525f8d52cSmark newline(); 30625f8d52cSmark } 30725f8d52cSmark 30825f8d52cSmark setNAEOL() 30925f8d52cSmark { 31025f8d52cSmark 31125f8d52cSmark setnoaddr(); 31225f8d52cSmark eol(); 31325f8d52cSmark } 314