xref: /csrg-svn/contrib/ed/g.c (revision 58316)
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*58316Sbostic static char sccsid[] = "@(#)g.c	5.4 (Berkeley) 02/28/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
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  */
6258315Sbostic static void
6357686Sbostic w_cmd_l_file(fp, inputt, errnum)
6457710Sbostic 	FILE *fp, *inputt;
6557710Sbostic 	int *errnum;
6657686Sbostic {
6757710Sbostic 	int l_esc = 0, l_cnt = 0;
6857686Sbostic 
6957710Sbostic 	for (;;) {
7057710Sbostic 		ss = getc(inputt);
7157710Sbostic 		if (ss == '\\') {
7257710Sbostic 			l_esc = 1;
7357710Sbostic 			ss = getc(inputt);
7457710Sbostic 		}
7557710Sbostic 		if (((ss == '\n') && (l_esc == 0)) || (ss == EOF)) {
7657710Sbostic 			/* if no command list default command list to 'p' */
7757710Sbostic 			if (l_cnt == 0)
7857710Sbostic 				fputc('p', fp);
7957710Sbostic 			break;
8057710Sbostic 		}
8157710Sbostic 		l_esc = 0;
8257710Sbostic 		fputc(ss, fp);
8357710Sbostic 		l_cnt++;
8457710Sbostic 	}
8557710Sbostic 	if (ss == EOF)
8657710Sbostic 		clearerr(inputt);
8757710Sbostic }
8857686Sbostic 
8957686Sbostic /*
9057686Sbostic  * The global function. All global commands (g, G, v, and V) are handled
9157686Sbostic  * in here. The lines to be affected by the command list are 1st noted
9257686Sbostic  * and then the command list is invoked for each line matching the RE.
9357686Sbostic  * Note the trick of how the command list is executed. Saves a lot of
9457686Sbostic  * code (and allows for \n's in substitutions).
9557686Sbostic  */
9657686Sbostic void
9757686Sbostic g(inputt, errnum)
9857710Sbostic 	FILE *inputt;
9957710Sbostic 	int *errnum;
10057686Sbostic {
10157710Sbostic 	struct g_list *l_Head, *l_Foot, *l_gut, *l_old;
10257710Sbostic 	static char *l_template_g;
10357710Sbostic 	char *l_patt;
10457710Sbostic 	static int l_template_flag = 0;
10557710Sbostic 	int l_re_success, l_flag_v = 0, l_err;
10657710Sbostic 	FILE *l_fp;
10757686Sbostic #ifdef POSIX
10857710Sbostic 	LINE *l_posix_cur;
10957686Sbostic #endif
11057686Sbostic 
11157710Sbostic 	if (start_default && End_default) {
11257710Sbostic 		start = top;
11357710Sbostic 		End = bottom;
11457710Sbostic 	} else
11557710Sbostic 		if (start_default)
11657710Sbostic 			start = End;
11757710Sbostic 	if (start == NULL) {
11858315Sbostic 		strcpy(help_msg, "buffer empty");
11957710Sbostic 		*errnum = -1;
12057710Sbostic 		return;
12157710Sbostic 	}
12257686Sbostic 
12357710Sbostic 	if (l_template_flag == 0) {
12458315Sbostic 		sigspecial++;
12557710Sbostic 		l_template_flag = 1;
12657710Sbostic 		l_template_g = calloc(FILENAME_LEN, sizeof(char));
12758315Sbostic 		sigspecial--;
12858315Sbostic 		if (sigint_flag && (!sigspecial))
12958315Sbostic 			SIGINT_ACTION;
13057710Sbostic 		if (l_template_g == NULL) {
13157710Sbostic 			*errnum = -1;
13257710Sbostic 			strcpy(help_msg, "out of memory error");
13357710Sbostic 			return;
13457710Sbostic 		}
13557710Sbostic 	}
13657710Sbostic 	/* set up the STDIO command list file */
13757710Sbostic 	bcopy("/tmp/_4.4bsd_ed_g_XXXXXX\0", l_template_g, 24);
13857710Sbostic 	mktemp(l_template_g);
13957686Sbostic 
14057710Sbostic 	l_Head = l_Foot = l_gut = l_old = NULL;
14157686Sbostic 
14257710Sbostic 	if ((ss == 'v') || (ss == 'V'))
14357710Sbostic 		l_flag_v = 1;
14457686Sbostic 
14557710Sbostic 	if ((ss == 'G') || (ss == 'V')) {
14657710Sbostic 		/*
14757710Sbostic 		 * If it's an interactive global command we use stdin, not a
14857710Sbostic 		 * file.
14957710Sbostic 		 */
15057710Sbostic 		GV_flag = 1;
15157710Sbostic 		l_fp = stdin;
15257710Sbostic 	} else {
15358315Sbostic 		sigspecial++;
15457710Sbostic 		if ((l_fp = fopen(l_template_g, "w+")) == NULL) {
15558315Sbostic 			perror("ed: file I/O error, save buffer in ed.hup");
15658315Sbostic 			do_hup(); /* does not return */
15758315Sbostic 		sigspecial--;
15858315Sbostic 		if (sigint_flag && (!sigspecial))
15958315Sbostic 			goto point;
16057710Sbostic 		}
16157710Sbostic 	}
16257686Sbostic 
16357710Sbostic 	ss = getc(inputt);
16457686Sbostic 
16557710Sbostic 	/* Get the RE for the global command. */
16657710Sbostic 	l_patt = get_pattern(ss, inputt, errnum, 0);
16758315Sbostic 
16857710Sbostic 	/* Instead of: if ((*errnum == -1) && (ss == '\n'))... */
16957710Sbostic 	if (*errnum < -1)
17057710Sbostic 		return;
17157710Sbostic 	*errnum = 0;
17257710Sbostic 	if ((l_patt[1] == '\0') && (RE_flag == 0)) {
17357710Sbostic 		*errnum = -1;
17457710Sbostic 		ungetc(ss, inputt);
17557710Sbostic 		return;
17657710Sbostic 	} else
17757710Sbostic 		if (l_patt[1] || (RE_patt == NULL)) {
17858315Sbostic 			sigspecial++;
17957710Sbostic 			free(RE_patt);
18057710Sbostic 			RE_patt = l_patt;
18158315Sbostic 			sigspecial--;
18258315Sbostic 			if (sigint_flag && (!sigspecial))
18358315Sbostic 				goto point;
18457710Sbostic 		}
18557710Sbostic 	RE_sol = (RE_patt[1] == '^') ? 1 : 0;
18657710Sbostic 	if ((RE_patt[1]) &&
18757710Sbostic 	    (regfree(&RE_comp), l_err = regcomp(&RE_comp, &RE_patt[1], 0))) {
18857710Sbostic 		regerror(l_err, &RE_comp, help_msg, 128);
18957710Sbostic 		*errnum = -1;
19057710Sbostic 		RE_flag = 0;
19157710Sbostic 		ungetc(ss, inputt);
19257710Sbostic 		return;
19357710Sbostic 	}
19457710Sbostic 	RE_flag = 1;
19558315Sbostic 
19658315Sbostic 	if (GV_flag)
19758315Sbostic 		ss = getc(inputt);
19858315Sbostic 
19957686Sbostic #ifdef POSIX
20057710Sbostic 	l_posix_cur = current;
20157686Sbostic #endif
20257710Sbostic 	current = start;
20357686Sbostic 
20458315Sbostic 	sigspecial++;
20558315Sbostic 
20657710Sbostic 	for (;;) {
20757710Sbostic 		/*
20857710Sbostic 		 * Find the lines in the buffer that the global command wants
20957710Sbostic 		 * to work with.
21057710Sbostic 		 */
21158315Sbostic 		if (sigint_flag && (!sigspecial))
21257710Sbostic 			goto point;
21357710Sbostic 		get_line(current->handle, current->len);
21458315Sbostic 		if (sigint_flag && (!sigspecial))
21558315Sbostic 			goto point;
21657710Sbostic 		l_re_success =
21757710Sbostic 		    regexec(&RE_comp, text, (size_t) RE_SEC, RE_match, 0);
21857710Sbostic 		/* l_re_success=0 => success */
21957710Sbostic 		if ((l_re_success != 0 && l_flag_v == 1) ||
22057710Sbostic 		    (l_re_success == 0 && l_flag_v == 0)) {
22157710Sbostic 			if (l_Head == NULL) {
22257710Sbostic 				l_gut = malloc(sizeof(struct g_list));
22357710Sbostic 				if (l_gut == NULL) {
22457710Sbostic 					*errnum = -1;
22557710Sbostic 					strcpy(help_msg, "out of memory error");
22657686Sbostic #ifdef POSIX
22757710Sbostic 					current = l_posix_cur;
22857686Sbostic #endif
22957710Sbostic 					return;
23057710Sbostic 				}
23157710Sbostic 				(l_gut->next) = NULL;
23257710Sbostic 				(l_gut->cell) = current;
23357710Sbostic 				l_Foot = l_Head = l_gut;
23457710Sbostic 			} else {
23557710Sbostic 				(l_gut->next) = malloc(sizeof(struct g_list));
23657710Sbostic 				if ((l_gut->next) == NULL) {
23757710Sbostic 					*errnum = -1;
23857710Sbostic 					strcpy(help_msg, "out of memory error");
23957710Sbostic 					goto clean;
24057710Sbostic 				}
24157710Sbostic 				l_gut = l_gut->next;
24257710Sbostic 				(l_gut->cell) = current;
24357710Sbostic 				(l_gut->next) = NULL;
24457710Sbostic 				l_Foot = l_gut;
24557710Sbostic 			}
24657710Sbostic 		}
24757710Sbostic 		if (End == current)
24857710Sbostic 			break;
24957710Sbostic 		current = current->below;
25057710Sbostic 	}
25158315Sbostic 	sigspecial--;
25258315Sbostic 	if (sigint_flag && (!sigspecial))
25358315Sbostic 		goto point;
25457686Sbostic 
25557710Sbostic 	if (l_Head == NULL) {
25657710Sbostic 		strcpy(help_msg, "no matches found");
25757710Sbostic 		*errnum = -1;
25857686Sbostic #ifdef POSIX
25957710Sbostic 		current = l_posix_cur;
26057686Sbostic #endif
26157710Sbostic 		return;
26257710Sbostic 	}
26357710Sbostic 	/* if non-interactive, get the command list */
26458315Sbostic 	if (GV_flag == 0) {
26558315Sbostic 		sigspecial++;
26657710Sbostic 		w_cmd_l_file(l_fp, inputt, errnum);
26758315Sbostic 		sigspecial--;
26858315Sbostic 		if (sigint_flag && (!sigspecial))
26958315Sbostic 			goto point;
27058315Sbostic 	}
27157710Sbostic 	l_gut = l_Head;
27257686Sbostic 
27357710Sbostic 	if (g_flag == 0)
27457710Sbostic 		u_clr_stk();
27557686Sbostic 
27658315Sbostic 	sigspecial++;
27757710Sbostic 	for (;;) {
27857710Sbostic 		/*
27957710Sbostic 		 * Execute the command list on the lines that still exist that
28057710Sbostic 		 * we indicated earlier that global wants to work with.
28157710Sbostic 		 */
28258315Sbostic 		if (sigint_flag && (!sigspecial))
28357710Sbostic 			goto point;
28457710Sbostic 		if (GV_flag == 0)
28557710Sbostic 			fseek(l_fp, (off_t)0, 0);
28657710Sbostic 		if (find_line(l_gut->cell)) {
28757710Sbostic 			current = (l_gut->cell);
28857710Sbostic 			get_line(current->handle, current->len);
28958315Sbostic 			if (sigint_flag && (!sigspecial))
29058315Sbostic 				goto point;
29157710Sbostic 			if (GV_flag == 1)
29257710Sbostic 				printf("%s\n", text);
29357710Sbostic 			g_flag++;
29457710Sbostic 			explain_flag--;
29558315Sbostic 			sigspecial--;
29657710Sbostic 			cmd_loop(l_fp, errnum);
29758315Sbostic 			sigspecial++;
29857710Sbostic 			explain_flag++;
29957710Sbostic 			g_flag--;
30057710Sbostic 			if ((GV_flag == 1) && (*errnum < 0)) {
30157710Sbostic 				ungetc('\n', l_fp);
30257710Sbostic 				break;
30357710Sbostic 			}
30457710Sbostic 			*errnum = 0;
30557710Sbostic 			if (l_gut == l_Foot)
30657710Sbostic 				break;
30757710Sbostic 			l_gut = l_gut->next;
30857710Sbostic 		}
30957710Sbostic 	}
31057686Sbostic 
31157710Sbostic point:
31257710Sbostic 	if (GV_flag == 0) {
31357710Sbostic 		fclose(l_fp);
31457710Sbostic 		unlink(l_template_g);
31557710Sbostic 	}
316*58316Sbostic 	else
317*58316Sbostic 		ungetc('\n', inputt);
318*58316Sbostic 
31957710Sbostic 	GV_flag = 0;
32057686Sbostic clean:
32157710Sbostic 	/* clean up */
32257710Sbostic 	l_gut = l_Head;
32357710Sbostic 	while (1) {
32457710Sbostic 		if (l_gut == NULL)
32557710Sbostic 			break;
32657710Sbostic 		l_old = l_gut;
32757710Sbostic 		l_gut = l_gut->next;
32857710Sbostic 		free(l_old);
32957710Sbostic 	}
33057686Sbostic #ifdef POSIX
33157710Sbostic 	current = l_posix_cur;
33257686Sbostic #endif
33358315Sbostic 	sigspecial--;
33458315Sbostic 	if (sigint_flag && (!sigspecial))
33558315Sbostic 		SIGINT_ACTION;
33657710Sbostic }
337