11297Salm/* glob.c: This file contains the global command routines for the ed line
21297Salm   editor */
31297Salm/*-
41297Salm * Copyright (c) 1993 Andrew Moore, Talke Studio.
51297Salm * All rights reserved.
61297Salm *
71297Salm * Redistribution and use in source and binary forms, with or without
81297Salm * modification, are permitted provided that the following conditions
91297Salm * are met:
101297Salm * 1. Redistributions of source code must retain the above copyright
111297Salm *    notice, this list of conditions and the following disclaimer.
121297Salm * 2. Redistributions in binary form must reproduce the above copyright
131297Salm *    notice, this list of conditions and the following disclaimer in the
141297Salm *    documentation and/or other materials provided with the distribution.
151297Salm *
161297Salm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
171297Salm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
181297Salm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
191297Salm * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
201297Salm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
211297Salm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
221297Salm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
231297Salm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
241297Salm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
251297Salm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261297Salm * SUCH DAMAGE.
271297Salm */
281297Salm
2999109Sobrien#include <sys/cdefs.h>
3099109Sobrien__FBSDID("$FreeBSD$");
311297Salm
3267183Sbrian#include <sys/types.h>
331297Salm#include <sys/ioctl.h>
341297Salm#include <sys/wait.h>
351297Salm
361297Salm#include "ed.h"
371297Salm
381297Salm
391297Salm/* build_active_list:  add line matching a pattern to the global-active list */
401297Salmint
4190109Simpbuild_active_list(int isgcmd)
421297Salm{
431297Salm	pattern_t *pat;
441297Salm	line_t *lp;
451297Salm	long n;
461297Salm	char *s;
471297Salm	char delimiter;
481297Salm
491297Salm	if ((delimiter = *ibufp) == ' ' || delimiter == '\n') {
5081220Smike		errmsg = "invalid pattern delimiter";
511297Salm		return ERR;
521297Salm	} else if ((pat = get_compiled_pattern()) == NULL)
531297Salm		return ERR;
541297Salm	else if (*ibufp == delimiter)
551297Salm		ibufp++;
561297Salm	clear_active_list();
571297Salm	lp = get_addressed_line_node(first_addr);
581297Salm	for (n = first_addr; n <= second_addr; n++, lp = lp->q_forw) {
591297Salm		if ((s = get_sbuf_line(lp)) == NULL)
601297Salm			return ERR;
611297Salm		if (isbinary)
621297Salm			NUL_TO_NEWLINE(s, lp->len);
631297Salm		if (!regexec(pat, s, 0, NULL, 0) == isgcmd &&
641297Salm		    set_active_node(lp) < 0)
651297Salm			return ERR;
661297Salm	}
671297Salm	return 0;
681297Salm}
691297Salm
701297Salm
711297Salm/* exec_global: apply command list in the command buffer to the active
721297Salm   lines in a range; return command status */
731297Salmlong
7490109Simpexec_global(int interact, int gflag)
751297Salm{
761297Salm	static char *ocmd = NULL;
771297Salm	static int ocmdsz = 0;
781297Salm
791297Salm	line_t *lp = NULL;
801297Salm	int status;
811297Salm	int n;
821297Salm	char *cmd = NULL;
831297Salm
841297Salm#ifdef BACKWARDS
851297Salm	if (!interact)
861297Salm		if (!strcmp(ibufp, "\n"))
871297Salm			cmd = "p\n";		/* null cmd-list == `p' */
881297Salm		else if ((cmd = get_extended_line(&n, 0)) == NULL)
891297Salm			return ERR;
901297Salm#else
911297Salm	if (!interact && (cmd = get_extended_line(&n, 0)) == NULL)
921297Salm		return ERR;
931297Salm#endif
941297Salm	clear_undo_stack();
951297Salm	while ((lp = next_active_node()) != NULL) {
961297Salm		if ((current_addr = get_line_node_addr(lp)) < 0)
971297Salm			return ERR;
981297Salm		if (interact) {
991297Salm			/* print current_addr; get a command in global syntax */
1001297Salm			if (display_lines(current_addr, current_addr, gflag) < 0)
1011297Salm				return ERR;
1021297Salm			while ((n = get_tty_line()) > 0 &&
1031297Salm			    ibuf[n - 1] != '\n')
1041297Salm				clearerr(stdin);
1051297Salm			if (n < 0)
1061297Salm				return ERR;
1071297Salm			else if (n == 0) {
10881220Smike				errmsg = "unexpected end-of-file";
1091297Salm				return ERR;
1101297Salm			} else if (n == 1 && !strcmp(ibuf, "\n"))
1111297Salm				continue;
1121297Salm			else if (n == 2 && !strcmp(ibuf, "&\n")) {
1131297Salm				if (cmd == NULL) {
11481220Smike					errmsg = "no previous command";
1151297Salm					return ERR;
1161297Salm				} else cmd = ocmd;
1171297Salm			} else if ((cmd = get_extended_line(&n, 0)) == NULL)
1181297Salm				return ERR;
1191297Salm			else {
1201297Salm				REALLOC(ocmd, ocmdsz, n + 1, ERR);
1211297Salm				memcpy(ocmd, cmd, n + 1);
1221297Salm				cmd = ocmd;
1231297Salm			}
1241297Salm
1251297Salm		}
1261297Salm		ibufp = cmd;
1271297Salm		for (; *ibufp;)
1281297Salm			if ((status = extract_addr_range()) < 0 ||
1291297Salm			    (status = exec_command()) < 0 ||
1307165Sjoerg			    (status > 0 && (status = display_lines(
1317165Sjoerg			    current_addr, current_addr, status)) < 0))
1321297Salm				return status;
1331297Salm	}
1341297Salm	return 0;
1351297Salm}
1361297Salm
1371297Salm
138241720Sedstatic line_t **active_list;	/* list of lines active in a global command */
139241720Sedstatic long active_last;	/* index of last active line in active_list */
140241720Sedstatic long active_size;	/* size of active_list */
141241720Sedstatic long active_ptr;		/* active_list index (non-decreasing) */
142241720Sedstatic long active_ndx;		/* active_list index (modulo active_last) */
1431297Salm
1441297Salm/* set_active_node: add a line node to the global-active list */
1451297Salmint
14690109Simpset_active_node(line_t *lp)
1471297Salm{
1481297Salm	if (active_last + 1 > active_size) {
1491297Salm		int ti = active_size;
1501297Salm		line_t **ts;
1511297Salm		SPL1();
1521297Salm#if defined(sun) || defined(NO_REALLOC_NULL)
1531297Salm		if (active_list != NULL) {
1541297Salm#endif
1558855Srgrimes			if ((ts = (line_t **) realloc(active_list,
1561297Salm			    (ti += MINBUFSZ) * sizeof(line_t **))) == NULL) {
1571297Salm				fprintf(stderr, "%s\n", strerror(errno));
15881220Smike				errmsg = "out of memory";
1591297Salm				SPL0();
1601297Salm				return ERR;
1611297Salm			}
1621297Salm#if defined(sun) || defined(NO_REALLOC_NULL)
1631297Salm		} else {
1648855Srgrimes			if ((ts = (line_t **) malloc((ti += MINBUFSZ) *
1651297Salm			    sizeof(line_t **))) == NULL) {
1661297Salm				fprintf(stderr, "%s\n", strerror(errno));
16781220Smike				errmsg = "out of memory";
1681297Salm				SPL0();
1691297Salm				return ERR;
1701297Salm			}
1711297Salm		}
1721297Salm#endif
1731297Salm		active_size = ti;
1741297Salm		active_list = ts;
1751297Salm		SPL0();
1761297Salm	}
1771297Salm	active_list[active_last++] = lp;
1781297Salm	return 0;
1791297Salm}
1801297Salm
1811297Salm
1821297Salm/* unset_active_nodes: remove a range of lines from the global-active list */
1831297Salmvoid
18490109Simpunset_active_nodes(line_t *np, line_t *mp)
1851297Salm{
1861297Salm	line_t *lp;
1871297Salm	long i;
1881297Salm
1891297Salm	for (lp = np; lp != mp; lp = lp->q_forw)
1901297Salm		for (i = 0; i < active_last; i++)
1911297Salm			if (active_list[active_ndx] == lp) {
1921297Salm				active_list[active_ndx] = NULL;
1931297Salm				active_ndx = INC_MOD(active_ndx, active_last - 1);
1941297Salm				break;
1951297Salm			} else	active_ndx = INC_MOD(active_ndx, active_last - 1);
1961297Salm}
1971297Salm
1981297Salm
1991297Salm/* next_active_node: return the next global-active line node */
2001297Salmline_t *
20190109Simpnext_active_node(void)
2021297Salm{
2031297Salm	while (active_ptr < active_last && active_list[active_ptr] == NULL)
2041297Salm		active_ptr++;
2051297Salm	return (active_ptr < active_last) ? active_list[active_ptr++] : NULL;
2061297Salm}
2071297Salm
2081297Salm
2091297Salm/* clear_active_list: clear the global-active list */
2101297Salmvoid
21190109Simpclear_active_list(void)
2121297Salm{
2131297Salm	SPL1();
2141297Salm	active_size = active_last = active_ptr = active_ndx = 0;
2151297Salm	free(active_list);
2161297Salm	active_list = NULL;
2171297Salm	SPL0();
2181297Salm}
219