glbl.c revision 1297
1231200Smm/* glob.c: This file contains the global command routines for the ed line
2231200Smm   editor */
3231200Smm/*-
4231200Smm * Copyright (c) 1993 Andrew Moore, Talke Studio.
5231200Smm * All rights reserved.
6231200Smm *
7231200Smm * Redistribution and use in source and binary forms, with or without
8231200Smm * modification, are permitted provided that the following conditions
9231200Smm * are met:
10231200Smm * 1. Redistributions of source code must retain the above copyright
11231200Smm *    notice, this list of conditions and the following disclaimer.
12231200Smm * 2. Redistributions in binary form must reproduce the above copyright
13231200Smm *    notice, this list of conditions and the following disclaimer in the
14231200Smm *    documentation and/or other materials provided with the distribution.
15231200Smm *
16231200Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17231200Smm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18231200Smm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19231200Smm * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20231200Smm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21231200Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22231200Smm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23231200Smm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24231200Smm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25231200Smm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26238856Smm * SUCH DAMAGE.
27231200Smm */
28231200Smm
29231200Smm#ifndef lint
30231200Smmstatic char *rcsid = "@(#)glob.c,v 1.1 1994/02/01 00:34:40 alm Exp";
31231200Smm#endif /* not lint */
32231200Smm
33231200Smm#include <sys/ioctl.h>
34231200Smm#include <sys/wait.h>
35231200Smm
36231200Smm#include "ed.h"
37231200Smm
38231200Smm
39231200Smm/* build_active_list:  add line matching a pattern to the global-active list */
40231200Smmint
41231200Smmbuild_active_list(isgcmd)
42231200Smm	int isgcmd;
43231200Smm{
44231200Smm	pattern_t *pat;
45231200Smm	line_t *lp;
46231200Smm	long n;
47231200Smm	char *s;
48231200Smm	char delimiter;
49231200Smm
50231200Smm	if ((delimiter = *ibufp) == ' ' || delimiter == '\n') {
51231200Smm		sprintf(errmsg, "invalid pattern delimiter");
52231200Smm		return ERR;
53231200Smm	} else if ((pat = get_compiled_pattern()) == NULL)
54231200Smm		return ERR;
55238856Smm	else if (*ibufp == delimiter)
56238856Smm		ibufp++;
57231200Smm	clear_active_list();
58231200Smm	lp = get_addressed_line_node(first_addr);
59231200Smm	for (n = first_addr; n <= second_addr; n++, lp = lp->q_forw) {
60231200Smm		if ((s = get_sbuf_line(lp)) == NULL)
61231200Smm			return ERR;
62231200Smm		if (isbinary)
63231200Smm			NUL_TO_NEWLINE(s, lp->len);
64231200Smm		if (!regexec(pat, s, 0, NULL, 0) == isgcmd &&
65231200Smm		    set_active_node(lp) < 0)
66231200Smm			return ERR;
67231200Smm	}
68231200Smm	return 0;
69231200Smm}
70231200Smm
71231200Smm
72231200Smm/* exec_global: apply command list in the command buffer to the active
73231200Smm   lines in a range; return command status */
74231200Smmlong
75231200Smmexec_global(interact, gflag)
76231200Smm	int interact;
77231200Smm	int gflag;
78231200Smm{
79231200Smm	static char *ocmd = NULL;
80231200Smm	static int ocmdsz = 0;
81231200Smm
82231200Smm	line_t *lp = NULL;
83231200Smm	int status;
84231200Smm	int n;
85231200Smm	char *cmd = NULL;
86231200Smm
87231200Smm#ifdef BACKWARDS
88231200Smm	if (!interact)
89231200Smm		if (!strcmp(ibufp, "\n"))
90231200Smm			cmd = "p\n";		/* null cmd-list == `p' */
91231200Smm		else if ((cmd = get_extended_line(&n, 0)) == NULL)
92231200Smm			return ERR;
93231200Smm#else
94231200Smm	if (!interact && (cmd = get_extended_line(&n, 0)) == NULL)
95231200Smm		return ERR;
96231200Smm#endif
97231200Smm	clear_undo_stack();
98231200Smm	while ((lp = next_active_node()) != NULL) {
99231200Smm		if ((current_addr = get_line_node_addr(lp)) < 0)
100231200Smm			return ERR;
101231200Smm		if (interact) {
102231200Smm			/* print current_addr; get a command in global syntax */
103231200Smm			if (display_lines(current_addr, current_addr, gflag) < 0)
104231200Smm				return ERR;
105231200Smm			while ((n = get_tty_line()) > 0 &&
106231200Smm			    ibuf[n - 1] != '\n')
107231200Smm				clearerr(stdin);
108231200Smm			if (n < 0)
109231200Smm				return ERR;
110231200Smm			else if (n == 0) {
111231200Smm				sprintf(errmsg, "unexpected end-of-file");
112231200Smm				return ERR;
113231200Smm			} else if (n == 1 && !strcmp(ibuf, "\n"))
114231200Smm				continue;
115231200Smm			else if (n == 2 && !strcmp(ibuf, "&\n")) {
116231200Smm				if (cmd == NULL) {
117231200Smm					sprintf(errmsg, "no previous command");
118231200Smm					return ERR;
119231200Smm				} else cmd = ocmd;
120231200Smm			} else if ((cmd = get_extended_line(&n, 0)) == NULL)
121231200Smm				return ERR;
122231200Smm			else {
123231200Smm				REALLOC(ocmd, ocmdsz, n + 1, ERR);
124231200Smm				memcpy(ocmd, cmd, n + 1);
125231200Smm				cmd = ocmd;
126231200Smm			}
127231200Smm
128231200Smm		}
129231200Smm		ibufp = cmd;
130231200Smm		for (; *ibufp;)
131231200Smm			if ((status = extract_addr_range()) < 0 ||
132231200Smm			    (status = exec_command()) < 0 ||
133231200Smm			    status > 0 && (status = display_lines(
134231200Smm			    current_addr, current_addr, status)) < 0)
135231200Smm				return status;
136231200Smm	}
137231200Smm	return 0;
138231200Smm}
139231200Smm
140231200Smm
141231200Smmline_t **active_list;		/* list of lines active in a global command */
142231200Smmlong active_last;		/* index of last active line in active_list */
143231200Smmlong active_size;		/* size of active_list */
144231200Smmlong active_ptr;		/* active_list index (non-decreasing) */
145231200Smmlong active_ndx;		/* active_list index (modulo active_last) */
146231200Smm
147231200Smm/* set_active_node: add a line node to the global-active list */
148231200Smmint
149231200Smmset_active_node(lp)
150231200Smm	line_t *lp;
151231200Smm{
152231200Smm	if (active_last + 1 > active_size) {
153231200Smm		int ti = active_size;
154231200Smm		line_t **ts;
155231200Smm		SPL1();
156231200Smm#if defined(sun) || defined(NO_REALLOC_NULL)
157231200Smm		if (active_list != NULL) {
158231200Smm#endif
159231200Smm			if ((ts = (line_t **) realloc(active_list,
160231200Smm			    (ti += MINBUFSZ) * sizeof(line_t **))) == NULL) {
161231200Smm				fprintf(stderr, "%s\n", strerror(errno));
162231200Smm				sprintf(errmsg, "out of memory");
163231200Smm				SPL0();
164231200Smm				return ERR;
165231200Smm			}
166231200Smm#if defined(sun) || defined(NO_REALLOC_NULL)
167231200Smm		} else {
168231200Smm			if ((ts = (line_t **) malloc((ti += MINBUFSZ) *
169231200Smm			    sizeof(line_t **))) == NULL) {
170231200Smm				fprintf(stderr, "%s\n", strerror(errno));
171231200Smm				sprintf(errmsg, "out of memory");
172231200Smm				SPL0();
173231200Smm				return ERR;
174231200Smm			}
175231200Smm		}
176231200Smm#endif
177231200Smm		active_size = ti;
178231200Smm		active_list = ts;
179231200Smm		SPL0();
180231200Smm	}
181231200Smm	active_list[active_last++] = lp;
182231200Smm	return 0;
183231200Smm}
184231200Smm
185231200Smm
186231200Smm/* unset_active_nodes: remove a range of lines from the global-active list */
187231200Smmvoid
188231200Smmunset_active_nodes(np, mp)
189231200Smm	line_t *np, *mp;
190231200Smm{
191231200Smm	line_t *lp;
192231200Smm	long i;
193231200Smm
194231200Smm	for (lp = np; lp != mp; lp = lp->q_forw)
195231200Smm		for (i = 0; i < active_last; i++)
196231200Smm			if (active_list[active_ndx] == lp) {
197231200Smm				active_list[active_ndx] = NULL;
198231200Smm				active_ndx = INC_MOD(active_ndx, active_last - 1);
199231200Smm				break;
200231200Smm			} else	active_ndx = INC_MOD(active_ndx, active_last - 1);
201231200Smm}
202231200Smm
203231200Smm
204231200Smm/* next_active_node: return the next global-active line node */
205231200Smmline_t *
206231200Smmnext_active_node()
207231200Smm{
208231200Smm	while (active_ptr < active_last && active_list[active_ptr] == NULL)
209231200Smm		active_ptr++;
210	return (active_ptr < active_last) ? active_list[active_ptr++] : NULL;
211}
212
213
214/* clear_active_list: clear the global-active list */
215void
216clear_active_list()
217{
218	SPL1();
219	active_size = active_last = active_ptr = active_ndx = 0;
220	free(active_list);
221	active_list = NULL;
222	SPL0();
223}
224