xref: /csrg-svn/contrib/ed/g.c (revision 60663)
157686Sbostic /*-
2*60663Sbostic  * Copyright (c) 1992, 1993
3*60663Sbostic  *	The Regents of the University of California.  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*60663Sbostic static char sccsid[] = "@(#)g.c	8.1 (Berkeley) 05/31/93";
1357686Sbostic #endif /* not lint */
1457686Sbostic 
1557710Sbostic #include <sys/types.h>
1657710Sbostic 
1758315Sbostic #include <limits.h>
1857710Sbostic #include <regex.h>
1957710Sbostic #include <setjmp.h>
2057710Sbostic #include <stdio.h>
2157710Sbostic #include <stdlib.h>
2257710Sbostic #include <stdlib.h>
2357710Sbostic #include <string.h>
2457710Sbostic #include <unistd.h>
2557710Sbostic 
2658315Sbostic #ifdef DBI
2758315Sbostic #include <db.h>
2858315Sbostic #endif
2958315Sbostic 
3057686Sbostic #include "ed.h"
3157710Sbostic #include "extern.h"
3257686Sbostic 
3357710Sbostic static int	find_line __P((LINE *));
3457710Sbostic static void	w_cmd_l_file __P((FILE *, FILE *, int *));
3557710Sbostic 
3657686Sbostic /*
3757686Sbostic  * Find a line that we noted matched the RE earlier in the current
3857686Sbostic  * buffer (it may have disappeared because of the commands in the
3957686Sbostic  * command list).
4057686Sbostic  */
4158315Sbostic static int
find_line(dot)4257686Sbostic find_line(dot)
4357710Sbostic 	LINE *dot;
4457686Sbostic {
4557710Sbostic 	LINE *l_cl;
4657686Sbostic 
4757710Sbostic 	l_cl = top;
4857710Sbostic 	for (;;) {
4957710Sbostic 		if (l_cl == dot)
5057710Sbostic 			return (1);
5157710Sbostic 		if (l_cl == bottom)
5257710Sbostic 			return (0);
5357710Sbostic 		l_cl = l_cl->below;
5457710Sbostic 	}
5557710Sbostic }
5657686Sbostic 
5757686Sbostic /*
5857686Sbostic  * Write the command line to a STDIO tmp file. See g() below.
5957686Sbostic  * This allows us to use cmd_loop to run the command list because
6057686Sbostic  * we "trick" cmd_loop into reading a STDIO file instead of stdin.
6157686Sbostic  */
6259475Sbostic 
6358315Sbostic static void
w_cmd_l_file(fp,inputt,errnum)6457686Sbostic w_cmd_l_file(fp, inputt, errnum)
6557710Sbostic 	FILE *fp, *inputt;
6657710Sbostic 	int *errnum;
6757686Sbostic {
6859475Sbostic 	int sl=0, jmp_flag, l_cnt=0;
6957686Sbostic 
7059475Sbostic 	if (jmp_flag = setjmp(ctrl_position3))
7159475Sbostic 		return;
7259475Sbostic 
7357710Sbostic 	for (;;) {
7459475Sbostic 		sigspecial3 = 1;
7557710Sbostic 		ss = getc(inputt);
7659475Sbostic 		sigspecial3 = 0;
7759475Sbostic skip1:
7859475Sbostic 		if (ss == EOF)
7959475Sbostic 			goto skip2;
8059475Sbostic 		else if (ss == '\n') {
8159475Sbostic 			if (sl != '\\') {
8259475Sbostic skip2:
8359475Sbostic 				if (l_cnt == 0)
8459475Sbostic 					fputc('p', fp);
8559475Sbostic 				else
8659475Sbostic 					fputc(sl, fp);
8759475Sbostic 				break;
8859475Sbostic 			}
8957710Sbostic 		}
9059475Sbostic 		else if ((ss == '\\') && (sl == '\\')) {
9159475Sbostic 			sigspecial3 = 1;
9259475Sbostic 			sl = getc(inputt);
9359475Sbostic 			sigspecial3 = 0;
9459475Sbostic 			if (sl == '\\') {
9559475Sbostic 				sigspecial3 = 1;
9659475Sbostic 				sl = getc(inputt);
9759475Sbostic 				sigspecial3 = 0;
9859475Sbostic 				if (sl == EOF)
9959475Sbostic 					goto skip2;
10059475Sbostic 				if (sl == '\n') {
10159475Sbostic 					fputc('\\', fp);
10259475Sbostic 					ss = sl;
10359475Sbostic 				}
10459475Sbostic 				else {
10559475Sbostic 					fputc('\\', fp);
10659475Sbostic 					fputc('\\', fp);
10759475Sbostic 					ss = sl;
10859475Sbostic 					sl = '\\';
10959475Sbostic 					goto skip1;
11059475Sbostic 				}
11159475Sbostic 			}
11259475Sbostic 			else {
11359475Sbostic 				fputc('\\', fp);
11459475Sbostic 				fputc('\\', fp);
11559475Sbostic 				if ((sl == '\n') || (sl == EOF))
11659475Sbostic 					goto skip2;
11759475Sbostic 				else
11859475Sbostic 					ss = sl;
11959475Sbostic 			}
12057710Sbostic 		}
12159475Sbostic 		else if (l_cnt)
12259475Sbostic 			fputc(sl, fp);
12359475Sbostic 		sl = ss;
12457710Sbostic 		l_cnt++;
12557710Sbostic 	}
12659558Sbostic 
12759558Sbostic 	fputc('\n', fp);
12857710Sbostic 	if (ss == EOF)
12957710Sbostic 		clearerr(inputt);
13057710Sbostic }
13157686Sbostic 
13259475Sbostic 
13357686Sbostic /*
13457686Sbostic  * The global function. All global commands (g, G, v, and V) are handled
13557686Sbostic  * in here. The lines to be affected by the command list are 1st noted
13657686Sbostic  * and then the command list is invoked for each line matching the RE.
13757686Sbostic  * Note the trick of how the command list is executed. Saves a lot of
13857686Sbostic  * code (and allows for \n's in substitutions).
13957686Sbostic  */
14057686Sbostic void
g(inputt,errnum)14157686Sbostic g(inputt, errnum)
14257710Sbostic 	FILE *inputt;
14357710Sbostic 	int *errnum;
14457686Sbostic {
14557710Sbostic 	static char *l_template_g;
14659915Sbostic 	char *l_patt;
14757710Sbostic 	static int l_template_flag = 0;
14859475Sbostic 	int l_re_success, l_flag_v = 0, l_err, l_num;
14959475Sbostic 	register l_gut_cnt, a;
15059475Sbostic 	register LINE **l_gut=gut;
15157710Sbostic 	FILE *l_fp;
15257686Sbostic #ifdef POSIX
15357710Sbostic 	LINE *l_posix_cur;
15457686Sbostic #endif
15557686Sbostic 
15658564Sralph 	if (Start_default && End_default) {
15758564Sralph 		Start = top;
15857710Sbostic 		End = bottom;
15957710Sbostic 	} else
16058564Sralph 		if (Start_default)
16158564Sralph 			Start = End;
16258564Sralph 	if (Start == NULL) {
16358315Sbostic 		strcpy(help_msg, "buffer empty");
16457710Sbostic 		*errnum = -1;
16557710Sbostic 		return;
16657710Sbostic 	}
16757686Sbostic 
16857710Sbostic 	if (l_template_flag == 0) {
16958315Sbostic 		sigspecial++;
17057710Sbostic 		l_template_flag = 1;
17157710Sbostic 		l_template_g = calloc(FILENAME_LEN, sizeof(char));
17258315Sbostic 		sigspecial--;
17358315Sbostic 		if (sigint_flag && (!sigspecial))
17458315Sbostic 			SIGINT_ACTION;
17557710Sbostic 		if (l_template_g == NULL) {
17657710Sbostic 			*errnum = -1;
17757710Sbostic 			strcpy(help_msg, "out of memory error");
17857710Sbostic 			return;
17957710Sbostic 		}
18057710Sbostic 	}
18157710Sbostic 	/* set up the STDIO command list file */
18259482Sbostic 	memmove(l_template_g, "/tmp/_4.4bsd_ed_g_XXXXXX\0", 24);
18357710Sbostic 	mktemp(l_template_g);
18457686Sbostic 
18557710Sbostic 	if ((ss == 'v') || (ss == 'V'))
18657710Sbostic 		l_flag_v = 1;
18757686Sbostic 
18857710Sbostic 	if ((ss == 'G') || (ss == 'V')) {
18957710Sbostic 		/*
19057710Sbostic 		 * If it's an interactive global command we use stdin, not a
19157710Sbostic 		 * file.
19257710Sbostic 		 */
19357710Sbostic 		GV_flag = 1;
19457710Sbostic 		l_fp = stdin;
19557710Sbostic 	} else {
19658315Sbostic 		sigspecial++;
19757710Sbostic 		if ((l_fp = fopen(l_template_g, "w+")) == NULL) {
19858315Sbostic 			perror("ed: file I/O error, save buffer in ed.hup");
19958315Sbostic 			do_hup(); /* does not return */
20058710Sbostic 		}
20158315Sbostic 		sigspecial--;
20258315Sbostic 		if (sigint_flag && (!sigspecial))
20358315Sbostic 			goto point;
20457710Sbostic 	}
20557686Sbostic 
20657710Sbostic 	ss = getc(inputt);
20757686Sbostic 
20857710Sbostic 	/* Get the RE for the global command. */
20957710Sbostic 	l_patt = get_pattern(ss, inputt, errnum, 0);
21058315Sbostic 
21157710Sbostic 	/* Instead of: if ((*errnum == -1) && (ss == '\n'))... */
21257710Sbostic 	if (*errnum < -1)
21357710Sbostic 		return;
21457710Sbostic 	*errnum = 0;
21557710Sbostic 	if ((l_patt[1] == '\0') && (RE_flag == 0)) {
21657710Sbostic 		*errnum = -1;
21757710Sbostic 		ungetc(ss, inputt);
21857710Sbostic 		return;
21957710Sbostic 	} else
22057710Sbostic 		if (l_patt[1] || (RE_patt == NULL)) {
22158315Sbostic 			sigspecial++;
22257710Sbostic 			free(RE_patt);
22357710Sbostic 			RE_patt = l_patt;
22458315Sbostic 			sigspecial--;
22558315Sbostic 			if (sigint_flag && (!sigspecial))
22658315Sbostic 				goto point;
22757710Sbostic 		}
22857710Sbostic 	RE_sol = (RE_patt[1] == '^') ? 1 : 0;
22957710Sbostic 	if ((RE_patt[1]) &&
23057710Sbostic 	    (regfree(&RE_comp), l_err = regcomp(&RE_comp, &RE_patt[1], 0))) {
23157710Sbostic 		regerror(l_err, &RE_comp, help_msg, 128);
23257710Sbostic 		*errnum = -1;
23357710Sbostic 		RE_flag = 0;
23457710Sbostic 		ungetc(ss, inputt);
23557710Sbostic 		return;
23657710Sbostic 	}
23757710Sbostic 	RE_flag = 1;
23858315Sbostic 
23958315Sbostic 	if (GV_flag)
24058315Sbostic 		ss = getc(inputt);
24158315Sbostic 
24257686Sbostic #ifdef POSIX
24357710Sbostic 	l_posix_cur = current;
24457686Sbostic #endif
24558564Sralph 	current = Start;
24657686Sbostic 
24758315Sbostic 	sigspecial++;
24858315Sbostic 
24959475Sbostic 	if ((l_num = line_number(bottom)) > gut_num) {
25059475Sbostic 		sigspecial++;
25159475Sbostic 		gut_num = l_num + 512;
25259475Sbostic 		free(l_gut);
25359558Sbostic 		gut = l_gut = malloc(sizeof(LINE **) * gut_num);
25459475Sbostic 		sigspecial--;
25559475Sbostic 		if (l_gut == NULL) {
25659475Sbostic 			*errnum = -1;
25759475Sbostic 			strcpy(help_msg, "out of memory error");
25859475Sbostic #ifdef POSIX
25959475Sbostic 			current = l_posix_cur;
26059475Sbostic #endif
26159558Sbostic 			ungetc('\n', inputt);
26259475Sbostic 			return;
26359475Sbostic 		}
26459475Sbostic 	}
26559475Sbostic 	l_gut_cnt = 0;
26659475Sbostic 
26757710Sbostic 	for (;;) {
26857710Sbostic 		/*
26957710Sbostic 		 * Find the lines in the buffer that the global command wants
27057710Sbostic 		 * to work with.
27157710Sbostic 		 */
27257710Sbostic 		get_line(current->handle, current->len);
27358315Sbostic 		if (sigint_flag && (!sigspecial))
27458315Sbostic 			goto point;
27557710Sbostic 		l_re_success =
27657710Sbostic 		    regexec(&RE_comp, text, (size_t) RE_SEC, RE_match, 0);
27757710Sbostic 		/* l_re_success=0 => success */
27859475Sbostic 		if ( (l_re_success == 0 && l_flag_v == 0) ||
27959475Sbostic 			(l_re_success && l_flag_v)) {
28059475Sbostic 				l_gut[l_gut_cnt++] = current;
28157710Sbostic 		}
28257710Sbostic 		if (End == current)
28357710Sbostic 			break;
28457710Sbostic 		current = current->below;
28557710Sbostic 	}
28658315Sbostic 	sigspecial--;
28758315Sbostic 	if (sigint_flag && (!sigspecial))
28858315Sbostic 		goto point;
28957686Sbostic 
29059475Sbostic 	if (l_gut_cnt == 0) {
29157710Sbostic 		strcpy(help_msg, "no matches found");
29257686Sbostic #ifdef POSIX
29357710Sbostic 		current = l_posix_cur;
29457686Sbostic #endif
29557710Sbostic 		return;
29657710Sbostic 	}
29757710Sbostic 	/* if non-interactive, get the command list */
29858315Sbostic 	if (GV_flag == 0) {
29958315Sbostic 		sigspecial++;
30057710Sbostic 		w_cmd_l_file(l_fp, inputt, errnum);
30158315Sbostic 		sigspecial--;
30259475Sbostic 		if (sigint_flag)
30358315Sbostic 			goto point;
30458315Sbostic 	}
30557686Sbostic 
30657710Sbostic 	if (g_flag == 0)
30757710Sbostic 		u_clr_stk();
30857686Sbostic 
30958315Sbostic 	sigspecial++;
31059475Sbostic 	for (a=0; a<l_gut_cnt; a++) {
31157710Sbostic 		/*
31257710Sbostic 		 * Execute the command list on the lines that still exist that
31357710Sbostic 		 * we indicated earlier that global wants to work with.
31457710Sbostic 		 */
31559475Sbostic 		if (sigint_flag)
31657710Sbostic 			goto point;
31757710Sbostic 		if (GV_flag == 0)
31857710Sbostic 			fseek(l_fp, (off_t)0, 0);
31959475Sbostic 		if (find_line(l_gut[a])) {
32059475Sbostic 			current = (l_gut[a]);
32157710Sbostic 			get_line(current->handle, current->len);
32259475Sbostic 			if (sigint_flag)
32358315Sbostic 				goto point;
32457710Sbostic 			if (GV_flag == 1)
32557710Sbostic 				printf("%s\n", text);
32657710Sbostic 			g_flag++;
32757710Sbostic 			explain_flag--;
32858315Sbostic 			sigspecial--;
32957710Sbostic 			cmd_loop(l_fp, errnum);
33058315Sbostic 			sigspecial++;
33157710Sbostic 			explain_flag++;
33257710Sbostic 			g_flag--;
33357710Sbostic 			if ((GV_flag == 1) && (*errnum < 0)) {
33457710Sbostic 				ungetc('\n', l_fp);
33557710Sbostic 				break;
33657710Sbostic 			}
33757710Sbostic 			*errnum = 0;
33857710Sbostic 		}
33957710Sbostic 	}
34057686Sbostic 
34157710Sbostic point:
34257710Sbostic 	if (GV_flag == 0) {
34357710Sbostic 		fclose(l_fp);
34457710Sbostic 		unlink(l_template_g);
34557710Sbostic 	}
34658316Sbostic 	else
34758316Sbostic 		ungetc('\n', inputt);
34858316Sbostic 
34957710Sbostic 	GV_flag = 0;
35059475Sbostic 
35157686Sbostic #ifdef POSIX
35257710Sbostic 	current = l_posix_cur;
35357686Sbostic #endif
35458315Sbostic 	sigspecial--;
35559475Sbostic 	if (sigint_flag)
35658315Sbostic 		SIGINT_ACTION;
35757710Sbostic }
358