17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bdstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bdstevel@tonic-gate * (the "License").  You may not use this file except in compliance
77c478bdstevel@tonic-gate * with the License.
87c478bdstevel@tonic-gate *
97c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bdstevel@tonic-gate * See the License for the specific language governing permissions
127c478bdstevel@tonic-gate * and limitations under the License.
137c478bdstevel@tonic-gate *
147c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bdstevel@tonic-gate *
207c478bdstevel@tonic-gate * CDDL HEADER END
217c478bdstevel@tonic-gate */
22f6db9f2cf/*
23f6db9f2cf * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24f6db9f2cf * Use is subject to license terms.
25f6db9f2cf */
26f6db9f2cf
277c478bdstevel@tonic-gate/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
287c478bdstevel@tonic-gate/*	  All Rights Reserved  	*/
297c478bdstevel@tonic-gate
307c478bdstevel@tonic-gate
317c478bdstevel@tonic-gate/* Copyright (c) 1981 Regents of the University of California */
327c478bdstevel@tonic-gate
337c478bdstevel@tonic-gate#include "ex.h"
347c478bdstevel@tonic-gate#include "ex_re.h"
357c478bdstevel@tonic-gate
367c478bdstevel@tonic-gate/*
377c478bdstevel@tonic-gate * Routines for address parsing and assignment and checking of address bounds
387c478bdstevel@tonic-gate * in command mode.  The routine address is called from ex_cmds.c
397c478bdstevel@tonic-gate * to parse each component of a command (terminated by , ; or the beginning
407c478bdstevel@tonic-gate * of the command itself.  It is also called by the scanning routine
417c478bdstevel@tonic-gate * in ex_voperate.c from within open/visual.
427c478bdstevel@tonic-gate *
437c478bdstevel@tonic-gate * Other routines here manipulate the externals addr1 and addr2.
447c478bdstevel@tonic-gate * These are the first and last lines for the current command.
457c478bdstevel@tonic-gate *
467c478bdstevel@tonic-gate * The variable bigmove remembers whether a non-local glitch of . was
477c478bdstevel@tonic-gate * involved in an address expression, so we can set the previous context
487c478bdstevel@tonic-gate * mark '' when such a motion occurs.
497c478bdstevel@tonic-gate */
507c478bdstevel@tonic-gate
517c478bdstevel@tonic-gatestatic	bool bigmove;
527c478bdstevel@tonic-gate
537c478bdstevel@tonic-gate/*
547c478bdstevel@tonic-gate * Set up addr1 and addr2 for commands whose default address is dot.
557c478bdstevel@tonic-gate */
56f6db9f2cfvoid
57f6db9f2cfsetdot(void)
587c478bdstevel@tonic-gate{
597c478bdstevel@tonic-gate
607c478bdstevel@tonic-gate	setdot1();
617c478bdstevel@tonic-gate	if (bigmove)
627c478bdstevel@tonic-gate		markDOT();
637c478bdstevel@tonic-gate}
647c478bdstevel@tonic-gate
657c478bdstevel@tonic-gate/*
667c478bdstevel@tonic-gate * Call setdot1 to set up default addresses without ever
677c478bdstevel@tonic-gate * setting the previous context mark.
687c478bdstevel@tonic-gate */
69f6db9f2cfvoid
70f6db9f2cfsetdot1(void)
717c478bdstevel@tonic-gate{
727c478bdstevel@tonic-gate
737c478bdstevel@tonic-gate	if (addr2 == 0)
747c478bdstevel@tonic-gate		addr1 = addr2 = dot;
757c478bdstevel@tonic-gate	if (addr1 > addr2) {
767c478bdstevel@tonic-gate		notempty();
777c478bdstevel@tonic-gate		error(value(vi_TERSE) ?
787c478bdstevel@tonic-gate			gettext("Addr1 > addr2") :
797c478bdstevel@tonic-gate			gettext("First address exceeds second"));
807c478bdstevel@tonic-gate	}
817c478bdstevel@tonic-gate}
827c478bdstevel@tonic-gate
837c478bdstevel@tonic-gate/*
847c478bdstevel@tonic-gate * Ex allows you to say
857c478bdstevel@tonic-gate *	delete 5
867c478bdstevel@tonic-gate * to delete 5 lines, etc.
877c478bdstevel@tonic-gate * Such nonsense is implemented by setcount.
887c478bdstevel@tonic-gate */
89f6db9f2cfvoid
90f6db9f2cfsetcount(void)
917c478bdstevel@tonic-gate{
92f6db9f2cf	int cnt;
937c478bdstevel@tonic-gate
947c478bdstevel@tonic-gate	pastwh();
957c478bdstevel@tonic-gate	if (!isdigit(peekchar())) {
967c478bdstevel@tonic-gate		setdot();
977c478bdstevel@tonic-gate		return;
987c478bdstevel@tonic-gate	}
997c478bdstevel@tonic-gate	addr1 = addr2;
1007c478bdstevel@tonic-gate	setdot();
1017c478bdstevel@tonic-gate	cnt = getnum();
1027c478bdstevel@tonic-gate	if (cnt <= 0)
1037c478bdstevel@tonic-gate		error(value(vi_TERSE) ?
1047c478bdstevel@tonic-gate			gettext("Bad count") :
1057c478bdstevel@tonic-gate			gettext("Nonzero count required"));
1067c478bdstevel@tonic-gate	addr2 += cnt - 1;
1077c478bdstevel@tonic-gate	if (addr2 > dol)
1087c478bdstevel@tonic-gate		addr2 = dol;
1097c478bdstevel@tonic-gate	nonzero();
1107c478bdstevel@tonic-gate}
1117c478bdstevel@tonic-gate
1127c478bdstevel@tonic-gate#ifdef XPG4
1137c478bdstevel@tonic-gate/*
1147c478bdstevel@tonic-gate * setcount2():	a version of setcount() which sets addr2 based on addr1 + cnt.
1157c478bdstevel@tonic-gate * description:
1167c478bdstevel@tonic-gate *	this routine is responsible for setting addr1 (possibly) and addr2
1177c478bdstevel@tonic-gate *	(always); using the [count] to compute addr2.
1187c478bdstevel@tonic-gate *
1197c478bdstevel@tonic-gate *	this is similar setcount(), but it differs in that setcount() sets
1207c478bdstevel@tonic-gate *	addr1 based upon addr2; here we set addr2 based upon addr1 and the
1217c478bdstevel@tonic-gate *	[count].
1227c478bdstevel@tonic-gate *
1237c478bdstevel@tonic-gate *	the reason for this is because some commands, of the form:
1247c478bdstevel@tonic-gate *		[range] command [count]
1257c478bdstevel@tonic-gate *	will use [count] to modify the range. E.g.:
1267c478bdstevel@tonic-gate *		change, delete, join, list, yank.
1277c478bdstevel@tonic-gate */
128f6db9f2cfvoid
129f6db9f2cfsetcount2(void)
1307c478bdstevel@tonic-gate{
131f6db9f2cf	int cnt;
1327c478bdstevel@tonic-gate
1337c478bdstevel@tonic-gate	pastwh();
1347c478bdstevel@tonic-gate	if (!isdigit(peekchar())) {
1357c478bdstevel@tonic-gate		setdot();
1367c478bdstevel@tonic-gate		return;
1377c478bdstevel@tonic-gate	}
1387c478bdstevel@tonic-gate	setdot();
1397c478bdstevel@tonic-gate	cnt = getnum();
1407c478bdstevel@tonic-gate	if (cnt <= 0)
1417c478bdstevel@tonic-gate		error(value(vi_TERSE) ?
1427c478bdstevel@tonic-gate			gettext("Bad count") :
1437c478bdstevel@tonic-gate			gettext("Nonzero count required"));
1447c478bdstevel@tonic-gate	addr2 = addr1 + (cnt - 1);
1457c478bdstevel@tonic-gate	if (addr2 > dol)
1467c478bdstevel@tonic-gate		addr2 = dol;
1477c478bdstevel@tonic-gate	if (addr2 < zero) {
1487c478bdstevel@tonic-gate		addr1 = addr2 = zero;
1497c478bdstevel@tonic-gate	}
1507c478bdstevel@tonic-gate	nonzero();
1517c478bdstevel@tonic-gate}
1527c478bdstevel@tonic-gate
1537c478bdstevel@tonic-gate#endif /* XPG4 */
1547c478bdstevel@tonic-gate
1557c478bdstevel@tonic-gate/*
1567c478bdstevel@tonic-gate * Parse a number out of the command input stream.
1577c478bdstevel@tonic-gate */
158f6db9f2cfint
159f6db9f2cfgetnum(void)
1607c478bdstevel@tonic-gate{
161f6db9f2cf	int cnt;
1627c478bdstevel@tonic-gate
1637c478bdstevel@tonic-gate	/*CSTYLED*/
1647c478bdstevel@tonic-gate	for (cnt = 0; isdigit(peekcd());)
1657c478bdstevel@tonic-gate		cnt = cnt * 10 + getchar() - '0';
1667c478bdstevel@tonic-gate	return (cnt);
1677c478bdstevel@tonic-gate}
1687c478bdstevel@tonic-gate
1697c478bdstevel@tonic-gate/*
1707c478bdstevel@tonic-gate * Set the default addresses for commands which use the whole
1717c478bdstevel@tonic-gate * buffer as default, notably write.
1727c478bdstevel@tonic-gate */
173f6db9f2cfvoid
174f6db9f2cfsetall(void)
1757c478bdstevel@tonic-gate{
1767c478bdstevel@tonic-gate
1777c478bdstevel@tonic-gate	if (addr2 == 0) {
1787c478bdstevel@tonic-gate		addr1 = one;
1797c478bdstevel@tonic-gate		addr2 = dol;
1807c478bdstevel@tonic-gate		if (dol == zero) {
1817c478bdstevel@tonic-gate			dot = zero;
1827c478bdstevel@tonic-gate			return;
1837c478bdstevel@tonic-gate		}
1847c478bdstevel@tonic-gate	}
1857c478bdstevel@tonic-gate	/*
1867c478bdstevel@tonic-gate	 * Don't want to set previous context mark so use setdot1().
1877c478bdstevel@tonic-gate	 */
1887c478bdstevel@tonic-gate	setdot1();
1897c478bdstevel@tonic-gate}
1907c478bdstevel@tonic-gate
1917c478bdstevel@tonic-gate/*
1927c478bdstevel@tonic-gate * No address allowed on, e.g. the file command.
1937c478bdstevel@tonic-gate */
194f6db9f2cfvoid
195f6db9f2cfsetnoaddr(void)
1967c478bdstevel@tonic-gate{
1977c478bdstevel@tonic-gate
1987c478bdstevel@tonic-gate	if (addr2 != 0)
1997c478bdstevel@tonic-gate		error(value(vi_TERSE) ?
2007c478bdstevel@tonic-gate			gettext("No address allowed") :
2017c478bdstevel@tonic-gate			gettext("No address allowed on this command"));
2027c478bdstevel@tonic-gate}
2037c478bdstevel@tonic-gate
2047c478bdstevel@tonic-gate/*
2057c478bdstevel@tonic-gate * Parse an address.
2067c478bdstevel@tonic-gate * Just about any sequence of address characters is legal.
2077c478bdstevel@tonic-gate *
2087c478bdstevel@tonic-gate * If you are tricky you can use this routine and the = command
2097c478bdstevel@tonic-gate * to do simple addition and subtraction of cardinals less
2107c478bdstevel@tonic-gate * than the number of lines in the file.
2117c478bdstevel@tonic-gate */
2127c478bdstevel@tonic-gateline *
2137c478bdstevel@tonic-gateaddress(inputline)
2147c478bdstevel@tonic-gate	unsigned char *inputline;
2157c478bdstevel@tonic-gate{
216f6db9f2cf	line *addr;
217f6db9f2cf	int offset, c;
2187c478bdstevel@tonic-gate	short lastsign;
2197c478bdstevel@tonic-gate
2207c478bdstevel@tonic-gate	bigmove = 0;
2217c478bdstevel@tonic-gate	lastsign = 0;
2227c478bdstevel@tonic-gate	offset = 0;
2237c478bdstevel@tonic-gate	addr = 0;
2247c478bdstevel@tonic-gate	for (;;) {
2257c478bdstevel@tonic-gate		if (isdigit(peekcd())) {
2267c478bdstevel@tonic-gate			if (addr == 0) {
2277c478bdstevel@tonic-gate				addr = zero;
2287c478bdstevel@tonic-gate				bigmove = 1;
2297c478bdstevel@tonic-gate			}
2307c478bdstevel@tonic-gate			loc1 = 0;
2317c478bdstevel@tonic-gate			addr += offset;
2327c478bdstevel@tonic-gate			offset = getnum();
2337c478bdstevel@tonic-gate			if (lastsign >= 0)
2347c478bdstevel@tonic-gate				addr += offset;
2357c478bdstevel@tonic-gate			else
2367c478bdstevel@tonic-gate				addr -= offset;
2377c478bdstevel@tonic-gate			lastsign = 0;
2387c478bdstevel@tonic-gate			offset = 0;
2397c478bdstevel@tonic-gate		}
2407c478bdstevel@tonic-gate		switch (c = getcd()) {
2417c478bdstevel@tonic-gate
2427c478bdstevel@tonic-gate		case '?':
2437c478bdstevel@tonic-gate		case '/':
2447c478bdstevel@tonic-gate		case '$':
2457c478bdstevel@tonic-gate		case '\'':
2467c478bdstevel@tonic-gate		case '\\':
2477c478bdstevel@tonic-gate			bigmove++;
2489097ca5Toomas Soome			/* FALLTHROUGH */
2497c478bdstevel@tonic-gate		case '.':
2507c478bdstevel@tonic-gate			if (addr || offset)
2517c478bdstevel@tonic-gate				error(gettext("Badly formed address"));
2527c478bdstevel@tonic-gate		}
2537c478bdstevel@tonic-gate		offset += lastsign;
2547c478bdstevel@tonic-gate		lastsign = 0;
2557c478bdstevel@tonic-gate		switch (c) {
2567c478bdstevel@tonic-gate
2577c478bdstevel@tonic-gate		case ' ':
2587c478bdstevel@tonic-gate		case '\t':
2597c478bdstevel@tonic-gate			continue;
2607c478bdstevel@tonic-gate		case ':':
2617c478bdstevel@tonic-gate			while (peekchar() == ':')
2627c478bdstevel@tonic-gate				ignchar();
2637c478bdstevel@tonic-gate			continue;
2647c478bdstevel@tonic-gate		case '+':
2657c478bdstevel@tonic-gate			lastsign = 1;
2667c478bdstevel@tonic-gate			if (addr == 0)
2677c478bdstevel@tonic-gate				addr = dot;
2687c478bdstevel@tonic-gate			continue;
2697c478bdstevel@tonic-gate
2707c478bdstevel@tonic-gate		case '^':
2717c478bdstevel@tonic-gate		case '-':
2727c478bdstevel@tonic-gate			lastsign = -1;
2737c478bdstevel@tonic-gate			if (addr == 0)
2747c478bdstevel@tonic-gate				addr = dot;
2757c478bdstevel@tonic-gate			continue;
2767c478bdstevel@tonic-gate
2777c478bdstevel@tonic-gate		case '\\':
2787c478bdstevel@tonic-gate		case '?':
2797c478bdstevel@tonic-gate		case '/':
2807c478bdstevel@tonic-gate			c = vi_compile(c, 1);
2817c478bdstevel@tonic-gate			notempty();
2827c478bdstevel@tonic-gate			savere(&scanre);
2837c478bdstevel@tonic-gate			addr = dot;
2847c478bdstevel@tonic-gate			if (inputline && execute(0, dot)) {
2857c478bdstevel@tonic-gate				if (c == '/') {
2867c478bdstevel@tonic-gate					while (loc1 <= (char *)inputline) {
2877c478bdstevel@tonic-gate						if (loc1 == loc2)
2887c478bdstevel@tonic-gate							loc2++;
2897c478bdstevel@tonic-gate						if (!execute(1))
2907c478bdstevel@tonic-gate							goto nope;
2917c478bdstevel@tonic-gate					}
2927c478bdstevel@tonic-gate					break;
2937c478bdstevel@tonic-gate				} else if (loc1 < (char *)inputline) {
2947c478bdstevel@tonic-gate					unsigned char *last;
2957c478bdstevel@tonic-gatedoques:
2967c478bdstevel@tonic-gate
2977c478bdstevel@tonic-gate					do {
2987c478bdstevel@tonic-gate						last = (unsigned char *)loc1;
2997c478bdstevel@tonic-gate						if (loc1 == loc2)
3007c478bdstevel@tonic-gate							loc2++;
3017c478bdstevel@tonic-gate						if (!execute(1))
3027c478bdstevel@tonic-gate							break;
3037c478bdstevel@tonic-gate					} while (loc1 < (char *)inputline);
3047c478bdstevel@tonic-gate					loc1 = (char *)last;
3057c478bdstevel@tonic-gate					break;
3067c478bdstevel@tonic-gate				}
3077c478bdstevel@tonic-gate			}
3087c478bdstevel@tonic-gatenope:
3097c478bdstevel@tonic-gate			for (;;) {
3107c478bdstevel@tonic-gate				if (c == '/') {
3117c478bdstevel@tonic-gate					addr++;
3127c478bdstevel@tonic-gate					if (addr > dol) {
3137c478bdstevel@tonic-gate						if (value(vi_WRAPSCAN) == 0)
3147c478bdstevel@tonic-gateerror(value(vi_TERSE) ?
3157c478bdstevel@tonic-gate	gettext("No match to BOTTOM") :
3167c478bdstevel@tonic-gate	gettext("Address search hit BOTTOM without matching pattern"));
3177c478bdstevel@tonic-gate						addr = zero;
3187c478bdstevel@tonic-gate					}
3197c478bdstevel@tonic-gate				} else {
3207c478bdstevel@tonic-gate					addr--;
3217c478bdstevel@tonic-gate					if (addr < zero) {
3227c478bdstevel@tonic-gate						if (value(vi_WRAPSCAN) == 0)
3237c478bdstevel@tonic-gateerror(value(vi_TERSE) ?
3247c478bdstevel@tonic-gate	gettext("No match to TOP") :
3257c478bdstevel@tonic-gate	gettext("Address search hit TOP without matching pattern"));
3267c478bdstevel@tonic-gate						addr = dol;
3277c478bdstevel@tonic-gate					}
3287c478bdstevel@tonic-gate				}
3297c478bdstevel@tonic-gate				if (execute(0, addr)) {
3307c478bdstevel@tonic-gate					if (inputline && c == '?') {
3317c478bdstevel@tonic-gate						inputline = &linebuf[LBSIZE];
3327c478bdstevel@tonic-gate						goto doques;
3337c478bdstevel@tonic-gate					}
3347c478bdstevel@tonic-gate					break;
3357c478bdstevel@tonic-gate				}
3367c478bdstevel@tonic-gate				if (addr == dot)
3377c478bdstevel@tonic-gate					error(value(vi_TERSE) ?
3387c478bdstevel@tonic-gate						gettext("Fail") :
3397c478bdstevel@tonic-gate						gettext("Pattern not found"));
3407c478bdstevel@tonic-gate			}
3417c478bdstevel@tonic-gate			continue;
3427c478bdstevel@tonic-gate
3437c478bdstevel@tonic-gate		case '$':
3447c478bdstevel@tonic-gate			addr = dol;
3457c478bdstevel@tonic-gate			continue;
3467c478bdstevel@tonic-gate
3477c478bdstevel@tonic-gate		case '.':
3487c478bdstevel@tonic-gate			addr = dot;
3497c478bdstevel@tonic-gate			continue;
3507c478bdstevel@tonic-gate
3517c478bdstevel@tonic-gate		case '\'':
3527c478bdstevel@tonic-gate			c = markreg(getchar());
3537c478bdstevel@tonic-gate			if (c == 0)
3547c478bdstevel@tonic-gate				error(gettext("Marks are ' and a-z"));
3557c478bdstevel@tonic-gate			addr = getmark(c);
3567c478bdstevel@tonic-gate			if (addr == 0)
3577c478bdstevel@tonic-gate				error(value(vi_TERSE) ?
3587c478bdstevel@tonic-gate				    gettext("Undefined mark") :
3597c478bdstevel@tonic-gate				    gettext("Undefined mark referenced"));
3607c478bdstevel@tonic-gate			break;
3617c478bdstevel@tonic-gate
3627c478bdstevel@tonic-gate		default:
3637c478bdstevel@tonic-gate			ungetchar(c);
3647c478bdstevel@tonic-gate			if (offset) {
3657c478bdstevel@tonic-gate				if (addr == 0)
3667c478bdstevel@tonic-gate					addr = dot;
3677c478bdstevel@tonic-gate				addr += offset;
3687c478bdstevel@tonic-gate				loc1 = 0;
3697c478bdstevel@tonic-gate			}
3707c478bdstevel@tonic-gate			if (addr == 0) {
3717c478bdstevel@tonic-gate				bigmove = 0;
3727c478bdstevel@tonic-gate				return (0);
3737c478bdstevel@tonic-gate			}
3747c478bdstevel@tonic-gate			if (addr != zero)
3757c478bdstevel@tonic-gate				notempty();
3767c478bdstevel@tonic-gate			addr += lastsign;
3777c478bdstevel@tonic-gate			if (addr < zero)
3787c478bdstevel@tonic-gate				error(value(vi_TERSE) ?
3797c478bdstevel@tonic-gate				    gettext("Negative address") :
3807c478bdstevel@tonic-gate				    gettext("Negative address - "
3817c478bdstevel@tonic-gate					"first buffer line is 1"));
3827c478bdstevel@tonic-gate			if (addr > dol)
3837c478bdstevel@tonic-gate				error(value(vi_TERSE) ?
3847c478bdstevel@tonic-gate				    gettext("Not that many lines") :
3857c478bdstevel@tonic-gate				    gettext("Not that many lines in buffer"));
3867c478bdstevel@tonic-gate			return (addr);
3877c478bdstevel@tonic-gate		}
3887c478bdstevel@tonic-gate	}
3897c478bdstevel@tonic-gate}
3907c478bdstevel@tonic-gate
3917c478bdstevel@tonic-gate/*
3927c478bdstevel@tonic-gate * Abbreviations to make code smaller
3937c478bdstevel@tonic-gate * Left over from squashing ex version 1.1 into
3947c478bdstevel@tonic-gate * 11/34's and 11/40's.
3957c478bdstevel@tonic-gate */
396f6db9f2cfvoid
397f6db9f2cfsetCNL(void)
3987c478bdstevel@tonic-gate{
3997c478bdstevel@tonic-gate
4007c478bdstevel@tonic-gate	setcount();
4017c478bdstevel@tonic-gate	donewline();
4027c478bdstevel@tonic-gate}
4037c478bdstevel@tonic-gate
404f6db9f2cfvoid
405f6db9f2cfsetNAEOL(void)
4067c478bdstevel@tonic-gate{
4077c478bdstevel@tonic-gate
4087c478bdstevel@tonic-gate	setnoaddr();
4097c478bdstevel@tonic-gate	eol();
4107c478bdstevel@tonic-gate}
411