xref: /csrg-svn/contrib/ed/g.c (revision 57710)
157686Sbostic /*-
257686Sbostic  * Copyright (c) 1992 The Regents of the University of California.
357686Sbostic  * All rights reserved.
457686Sbostic  *
557686Sbostic  * This code is derived from software contributed to Berkeley by
657686Sbostic  * Rodney Ruddock of the University of Guelph.
757686Sbostic  *
857686Sbostic  * %sccs.include.redist.c%
957686Sbostic  */
1057686Sbostic 
1157686Sbostic #ifndef lint
12*57710Sbostic static char sccsid[] = "@(#)g.c	5.2 (Berkeley) 01/23/93";
1357686Sbostic #endif /* not lint */
1457686Sbostic 
15*57710Sbostic #include <sys/types.h>
16*57710Sbostic 
17*57710Sbostic #include <db.h>
18*57710Sbostic #include <regex.h>
19*57710Sbostic #include <setjmp.h>
20*57710Sbostic #include <stdio.h>
21*57710Sbostic #include <stdlib.h>
22*57710Sbostic #include <stdlib.h>
23*57710Sbostic #include <string.h>
24*57710Sbostic #include <unistd.h>
25*57710Sbostic 
2657686Sbostic #include "ed.h"
27*57710Sbostic #include "extern.h"
2857686Sbostic 
29*57710Sbostic static int	find_line __P((LINE *));
30*57710Sbostic static void	w_cmd_l_file __P((FILE *, FILE *, int *));
31*57710Sbostic 
3257686Sbostic /*
3357686Sbostic  * Find a line that we noted matched the RE earlier in the current
3457686Sbostic  * buffer (it may have disappeared because of the commands in the
3557686Sbostic  * command list).
3657686Sbostic  */
3757686Sbostic int
3857686Sbostic find_line(dot)
39*57710Sbostic 	LINE *dot;
4057686Sbostic {
41*57710Sbostic 	LINE *l_cl;
4257686Sbostic 
43*57710Sbostic 	l_cl = top;
44*57710Sbostic 	for (;;) {
45*57710Sbostic 		if (l_cl == dot)
46*57710Sbostic 			return (1);
47*57710Sbostic 		if (l_cl == bottom)
48*57710Sbostic 			return (0);
49*57710Sbostic 		l_cl = l_cl->below;
50*57710Sbostic 	}
51*57710Sbostic }
5257686Sbostic 
5357686Sbostic /*
5457686Sbostic  * Write the command line to a STDIO tmp file. See g() below.
5557686Sbostic  * This allows us to use cmd_loop to run the command list because
5657686Sbostic  * we "trick" cmd_loop into reading a STDIO file instead of stdin.
5757686Sbostic  */
5857686Sbostic void
5957686Sbostic w_cmd_l_file(fp, inputt, errnum)
60*57710Sbostic 	FILE *fp, *inputt;
61*57710Sbostic 	int *errnum;
6257686Sbostic {
63*57710Sbostic 	int l_esc = 0, l_cnt = 0;
6457686Sbostic 
65*57710Sbostic 	for (;;) {
66*57710Sbostic 		ss = getc(inputt);
67*57710Sbostic 		if (ss == '\\') {
68*57710Sbostic 			l_esc = 1;
69*57710Sbostic 			ss = getc(inputt);
70*57710Sbostic 		}
71*57710Sbostic 		if (((ss == '\n') && (l_esc == 0)) || (ss == EOF)) {
72*57710Sbostic 			/* if no command list default command list to 'p' */
73*57710Sbostic 			if (l_cnt == 0)
74*57710Sbostic 				fputc('p', fp);
75*57710Sbostic 			break;
76*57710Sbostic 		}
77*57710Sbostic 		l_esc = 0;
78*57710Sbostic 		fputc(ss, fp);
79*57710Sbostic 		l_cnt++;
80*57710Sbostic 	}
81*57710Sbostic 	if (ss == EOF)
82*57710Sbostic 		clearerr(inputt);
83*57710Sbostic }
8457686Sbostic 
8557686Sbostic /*
8657686Sbostic  * The global function. All global commands (g, G, v, and V) are handled
8757686Sbostic  * in here. The lines to be affected by the command list are 1st noted
8857686Sbostic  * and then the command list is invoked for each line matching the RE.
8957686Sbostic  * Note the trick of how the command list is executed. Saves a lot of
9057686Sbostic  * code (and allows for \n's in substitutions).
9157686Sbostic  */
9257686Sbostic void
9357686Sbostic g(inputt, errnum)
94*57710Sbostic 	FILE *inputt;
95*57710Sbostic 	int *errnum;
9657686Sbostic {
97*57710Sbostic 	struct g_list *l_Head, *l_Foot, *l_gut, *l_old;
98*57710Sbostic 	static char *l_template_g;
99*57710Sbostic 	char *l_patt;
100*57710Sbostic 	static int l_template_flag = 0;
101*57710Sbostic 	int l_re_success, l_flag_v = 0, l_err;
102*57710Sbostic 	FILE *l_fp;
10357686Sbostic #ifdef POSIX
104*57710Sbostic 	LINE *l_posix_cur;
10557686Sbostic #endif
10657686Sbostic 
107*57710Sbostic 	if (start_default && End_default) {
108*57710Sbostic 		start = top;
109*57710Sbostic 		End = bottom;
110*57710Sbostic 	} else
111*57710Sbostic 		if (start_default)
112*57710Sbostic 			start = End;
113*57710Sbostic 	if (start == NULL) {
114*57710Sbostic 		strcpy(help_msg, "bad address");
115*57710Sbostic 		*errnum = -1;
116*57710Sbostic 		return;
117*57710Sbostic 	}
118*57710Sbostic 	if (sigint_flag)
119*57710Sbostic 		SIGINT_ACTION;
12057686Sbostic 
121*57710Sbostic 	if (l_template_flag == 0) {
122*57710Sbostic 		l_template_flag = 1;
123*57710Sbostic 		l_template_g = calloc(FILENAME_LEN, sizeof(char));
124*57710Sbostic 		if (l_template_g == NULL) {
125*57710Sbostic 			*errnum = -1;
126*57710Sbostic 			strcpy(help_msg, "out of memory error");
127*57710Sbostic 			return;
128*57710Sbostic 		}
129*57710Sbostic 	}
130*57710Sbostic 	/* set up the STDIO command list file */
131*57710Sbostic 	bcopy("/tmp/_4.4bsd_ed_g_XXXXXX\0", l_template_g, 24);
132*57710Sbostic 	mktemp(l_template_g);
13357686Sbostic 
134*57710Sbostic 	l_Head = l_Foot = l_gut = l_old = NULL;
13557686Sbostic 
136*57710Sbostic 	if ((ss == 'v') || (ss == 'V'))
137*57710Sbostic 		l_flag_v = 1;
13857686Sbostic 
139*57710Sbostic 	if ((ss == 'G') || (ss == 'V')) {
140*57710Sbostic 		/*
141*57710Sbostic 		 * If it's an interactive global command we use stdin, not a
142*57710Sbostic 		 * file.
143*57710Sbostic 		 */
144*57710Sbostic 		GV_flag = 1;
145*57710Sbostic 		l_fp = stdin;
146*57710Sbostic 	} else {
147*57710Sbostic 		if ((l_fp = fopen(l_template_g, "w+")) == NULL) {
148*57710Sbostic 			perror("ed: file I/O error");
149*57710Sbostic 			exit(1);
150*57710Sbostic 		}
151*57710Sbostic 	}
15257686Sbostic 
153*57710Sbostic 	ss = getc(inputt);
15457686Sbostic 
155*57710Sbostic 	/* Get the RE for the global command. */
156*57710Sbostic 	l_patt = get_pattern(ss, inputt, errnum, 0);
157*57710Sbostic 	if (sigint_flag)
158*57710Sbostic 		SIGINT_ACTION;
159*57710Sbostic 	/* Instead of: if ((*errnum == -1) && (ss == '\n'))... */
160*57710Sbostic 	if (*errnum < -1)
161*57710Sbostic 		return;
162*57710Sbostic 	*errnum = 0;
163*57710Sbostic 	if ((l_patt[1] == '\0') && (RE_flag == 0)) {
164*57710Sbostic 		*errnum = -1;
165*57710Sbostic 		ungetc(ss, inputt);
166*57710Sbostic 		return;
167*57710Sbostic 	} else
168*57710Sbostic 		if (l_patt[1] || (RE_patt == NULL)) {
169*57710Sbostic 			free(RE_patt);
170*57710Sbostic 			RE_patt = l_patt;
171*57710Sbostic 		}
172*57710Sbostic 	RE_sol = (RE_patt[1] == '^') ? 1 : 0;
173*57710Sbostic 	if ((RE_patt[1]) &&
174*57710Sbostic 	    (regfree(&RE_comp), l_err = regcomp(&RE_comp, &RE_patt[1], 0))) {
175*57710Sbostic 		regerror(l_err, &RE_comp, help_msg, 128);
176*57710Sbostic 		*errnum = -1;
177*57710Sbostic 		RE_flag = 0;
178*57710Sbostic 		ungetc(ss, inputt);
179*57710Sbostic 		return;
180*57710Sbostic 	}
181*57710Sbostic 	RE_flag = 1;
182*57710Sbostic 	if (sigint_flag)
183*57710Sbostic 		SIGINT_ACTION;
18457686Sbostic #ifdef POSIX
185*57710Sbostic 	l_posix_cur = current;
18657686Sbostic #endif
187*57710Sbostic 	current = start;
18857686Sbostic 
189*57710Sbostic 	for (;;) {
190*57710Sbostic 		/*
191*57710Sbostic 		 * Find the lines in the buffer that the global command wants
192*57710Sbostic 		 * to work with.
193*57710Sbostic 		 */
194*57710Sbostic 		if (sigint_flag)
195*57710Sbostic 			goto point;
196*57710Sbostic 		get_line(current->handle, current->len);
197*57710Sbostic 		l_re_success =
198*57710Sbostic 		    regexec(&RE_comp, text, (size_t) RE_SEC, RE_match, 0);
199*57710Sbostic 		/* l_re_success=0 => success */
200*57710Sbostic 		if ((l_re_success != 0 && l_flag_v == 1) ||
201*57710Sbostic 		    (l_re_success == 0 && l_flag_v == 0)) {
202*57710Sbostic 			if (l_Head == NULL) {
203*57710Sbostic 				l_gut = malloc(sizeof(struct g_list));
204*57710Sbostic 				if (l_gut == NULL) {
205*57710Sbostic 					*errnum = -1;
206*57710Sbostic 					strcpy(help_msg, "out of memory error");
20757686Sbostic #ifdef POSIX
208*57710Sbostic 					current = l_posix_cur;
20957686Sbostic #endif
210*57710Sbostic 					return;
211*57710Sbostic 				}
212*57710Sbostic 				(l_gut->next) = NULL;
213*57710Sbostic 				(l_gut->cell) = current;
214*57710Sbostic 				l_Foot = l_Head = l_gut;
215*57710Sbostic 			} else {
216*57710Sbostic 				(l_gut->next) = malloc(sizeof(struct g_list));
217*57710Sbostic 				if ((l_gut->next) == NULL) {
218*57710Sbostic 					*errnum = -1;
219*57710Sbostic 					strcpy(help_msg, "out of memory error");
220*57710Sbostic 					goto clean;
221*57710Sbostic 				}
222*57710Sbostic 				l_gut = l_gut->next;
223*57710Sbostic 				(l_gut->cell) = current;
224*57710Sbostic 				(l_gut->next) = NULL;
225*57710Sbostic 				l_Foot = l_gut;
226*57710Sbostic 			}
227*57710Sbostic 		}
228*57710Sbostic 		if (End == current)
229*57710Sbostic 			break;
230*57710Sbostic 		current = current->below;
231*57710Sbostic 	}
23257686Sbostic 
233*57710Sbostic 	if (l_Head == NULL) {
234*57710Sbostic 		strcpy(help_msg, "no matches found");
235*57710Sbostic 		*errnum = -1;
23657686Sbostic #ifdef POSIX
237*57710Sbostic 		current = l_posix_cur;
23857686Sbostic #endif
239*57710Sbostic 		return;
240*57710Sbostic 	}
241*57710Sbostic 	/* if non-interactive, get the command list */
242*57710Sbostic 	if (GV_flag == 0)
243*57710Sbostic 		w_cmd_l_file(l_fp, inputt, errnum);
244*57710Sbostic 	l_gut = l_Head;
24557686Sbostic 
246*57710Sbostic 	if (g_flag == 0)
247*57710Sbostic 		u_clr_stk();
24857686Sbostic 
249*57710Sbostic 	for (;;) {
250*57710Sbostic 		/*
251*57710Sbostic 		 * Execute the command list on the lines that still exist that
252*57710Sbostic 		 * we indicated earlier that global wants to work with.
253*57710Sbostic 		 */
254*57710Sbostic 		if (sigint_flag)
255*57710Sbostic 			goto point;
256*57710Sbostic 		if (GV_flag == 0)
257*57710Sbostic 			fseek(l_fp, (off_t)0, 0);
258*57710Sbostic 		if (find_line(l_gut->cell)) {
259*57710Sbostic 			current = (l_gut->cell);
260*57710Sbostic 			get_line(current->handle, current->len);
261*57710Sbostic 			if (GV_flag == 1)
262*57710Sbostic 				printf("%s\n", text);
263*57710Sbostic 			g_flag++;
264*57710Sbostic 			explain_flag--;
265*57710Sbostic 			cmd_loop(l_fp, errnum);
266*57710Sbostic 			explain_flag++;
267*57710Sbostic 			g_flag--;
268*57710Sbostic 			if ((GV_flag == 1) && (*errnum < 0)) {
269*57710Sbostic 				ungetc('\n', l_fp);
270*57710Sbostic 				break;
271*57710Sbostic 			}
272*57710Sbostic 			*errnum = 0;
273*57710Sbostic 			if (l_gut == l_Foot)
274*57710Sbostic 				break;
275*57710Sbostic 			l_gut = l_gut->next;
276*57710Sbostic 		}
277*57710Sbostic 	}
27857686Sbostic 
279*57710Sbostic point:
280*57710Sbostic 	if (GV_flag == 0) {
281*57710Sbostic 		fclose(l_fp);
282*57710Sbostic 		unlink(l_template_g);
283*57710Sbostic 	}
284*57710Sbostic 	GV_flag = 0;
28557686Sbostic clean:
286*57710Sbostic 	/* clean up */
287*57710Sbostic 	l_gut = l_Head;
288*57710Sbostic 	while (1) {
289*57710Sbostic 		if (l_gut == NULL)
290*57710Sbostic 			break;
291*57710Sbostic 		l_old = l_gut;
292*57710Sbostic 		l_gut = l_gut->next;
293*57710Sbostic 		free(l_old);
294*57710Sbostic 	}
29557686Sbostic #ifdef POSIX
296*57710Sbostic 	current = l_posix_cur;
29757686Sbostic #endif
298*57710Sbostic }
299