xref: /csrg-svn/contrib/ed/sub.c (revision 58315)
157705Sbostic /*-
257705Sbostic  * Copyright (c) 1992 The Regents of the University of California.
357705Sbostic  * All rights reserved.
457705Sbostic  *
557705Sbostic  * This code is derived from software contributed to Berkeley by
657705Sbostic  * Rodney Ruddock of the University of Guelph.
757705Sbostic  *
857705Sbostic  * %sccs.include.redist.c%
957705Sbostic  */
1057705Sbostic 
1157705Sbostic #ifndef lint
12*58315Sbostic static char sccsid[] = "@(#)sub.c	5.3 (Berkeley) 02/28/93";
1357705Sbostic #endif /* not lint */
1457705Sbostic 
1557710Sbostic #include <sys/types.h>
1657710Sbostic 
1757710Sbostic #include <regex.h>
1857710Sbostic #include <setjmp.h>
1957710Sbostic #include <stdio.h>
2057710Sbostic #include <stdlib.h>
2157710Sbostic #include <string.h>
2257710Sbostic 
23*58315Sbostic #ifdef DBI
24*58315Sbostic #include <db.h>
25*58315Sbostic #endif
26*58315Sbostic 
2757705Sbostic #include "ed.h"
2857710Sbostic #include "extern.h"
2957705Sbostic 
3057705Sbostic /*
3157705Sbostic  * The substitute command. It's big because of the backward compatability.
3257705Sbostic  */
3357705Sbostic void
3457705Sbostic s(inputt, errnum)
3557710Sbostic 	FILE *inputt;
3657710Sbostic 	int *errnum;
3757705Sbostic {
3857710Sbostic 	static int l_count2 = 1, l_global = 0, l_print = 0;
3957710Sbostic 	static int l_first_pass_flag = 0;
4057710Sbostic 	static char *l_match = NULL, *l_repl = NULL;
4157710Sbostic 	LINE *l_s_ret, *l_temp_line, *l_temp_line2, *l_kval, *l_last;
4257710Sbostic 	int l_s_flag, l_count, l_matched, l_nflag, l_cnt, yy, l_sr_flag = 0;
4357710Sbostic 	int l_err, l_sl;
4457710Sbostic 	char *l_match2 = NULL, *l_local = NULL, *l_local_temp = NULL;
4557705Sbostic #ifndef REG_STARTEND
4657710Sbostic 	size_t l_offset = 0;
4757705Sbostic #endif
4857705Sbostic 
4957710Sbostic 	if (start_default && End_default)
5057710Sbostic 		start = End = current;
5157710Sbostic 	else
5257710Sbostic 		if (start_default)
5357710Sbostic 			start = End;
5457710Sbostic 	if (start == NULL) {
5557710Sbostic 		*errnum = -1;
5657710Sbostic 		return;
5757710Sbostic 	}
5857710Sbostic 	start_default = End_default = 0;
5957705Sbostic 
6057710Sbostic 	l_sl = ss = getc(inputt);
6157710Sbostic 	if (l_first_pass_flag == 0)
6257710Sbostic 		l_match = l_repl = NULL;
6357710Sbostic 	l_match2 = get_pattern(l_sl, inputt, errnum, 0);
64*58315Sbostic 
6557710Sbostic 	if (*errnum < 0) {
6657710Sbostic 		if ((*errnum == -2) && (l_sl != '\n'))
6757710Sbostic 			return;
6857710Sbostic 		if ((l_match2 == NULL) ||
6957710Sbostic 		    (strlen(l_match2) > 4) || (l_first_pass_flag == 0))
7057710Sbostic 			return;
7157710Sbostic 		*errnum = 0;
7257710Sbostic 		l_sr_flag = -1;
7357710Sbostic 		for (yy = 0; yy < (strlen(l_match2)); yy++) {
7457710Sbostic 			switch (l_match2[yy]) {
7557710Sbostic 			case '\n':
7657710Sbostic 				ss = getc(inputt);
7757710Sbostic 				goto bcg1;
7857710Sbostic 				break;
7957710Sbostic 			case 'r':
8057710Sbostic 				l_sr_flag = 1;
8157710Sbostic 				break;
8257710Sbostic 			case 'p':
8357710Sbostic 				l_print = (l_print) ? 0 : 1;
8457710Sbostic 				break;
8557710Sbostic 			case 'g':
8657710Sbostic 				l_global = (l_global) ? 0 : 1;
8757710Sbostic 				break;
8857710Sbostic 			case 'N':
8957710Sbostic 				l_count2 = 1;
9057710Sbostic 				break;
9157710Sbostic 			default:
9257710Sbostic 				*errnum = -1;
9357710Sbostic 				strcpy(help_msg, "illegal modifier to s");
9457710Sbostic 				return;
9557710Sbostic 			}
9657710Sbostic 		}
9757710Sbostic 		ss = getc(inputt);
9857710Sbostic 		if (l_sr_flag == 1)
9957710Sbostic 			goto bcg2;
10057710Sbostic 		else
10157710Sbostic 			goto bcg1;
10257710Sbostic 	}
10357710Sbostic 	if (l_first_pass_flag) {
10457710Sbostic 		free(l_match);
10557710Sbostic 		free(l_repl);
10657710Sbostic 	} else
10757710Sbostic 		l_first_pass_flag = 1;
10857710Sbostic 	l_match = l_match2;
10957710Sbostic 	*errnum = 0;
11057710Sbostic 	l_repl = get_pattern(ss, inputt, errnum, 1);
111*58315Sbostic 	if (sigint_flag && (!sigspecial))
11257710Sbostic 		SIGINT_ACTION;
11357710Sbostic 	l_global = l_print = 0;
11457710Sbostic 	if (*errnum < 0)
11557710Sbostic 		if ((*errnum == -1) && (ss == '\n'))
11657710Sbostic 			/* Note, \n still in stream for next getc. */
11757710Sbostic 			l_print = 1;
11857710Sbostic 		else
11957710Sbostic 			return;
12057710Sbostic 	*errnum = 0;
12157705Sbostic 
12257710Sbostic 	l_count2 = 1;
12357705Sbostic 
12457710Sbostic 	while (((ss = getc(inputt)) != '\n') && (ss != EOF))
12557710Sbostic 		if (ss == 'g')
12657710Sbostic 			l_global = 1;
12757710Sbostic 		else
12857710Sbostic 			switch (ss) {
12957710Sbostic 			case 'p':
13057710Sbostic 				l_print = (l_print | (int) 1);
13157710Sbostic 				break;
13257710Sbostic 			case 'n':
13357710Sbostic 				l_print = (l_print | (int) 2);
13457710Sbostic 				break;
13557710Sbostic 			case 'l':
13657710Sbostic 				l_print = (l_print | (int) 4);
13757710Sbostic 				break;
13857710Sbostic 			default:
13957710Sbostic 				if ((ss > ('0' - 1)) && (ss < ('9' + 1)))
14057710Sbostic 					l_count2 = dig_num_conv(inputt, errnum);
14157710Sbostic 				else {
14257710Sbostic 					*errnum = -1;
14357710Sbostic 					strcpy(help_msg,
14457710Sbostic 					    "illegal command option");
14557710Sbostic 					return;
14657710Sbostic 				}
14757710Sbostic 		}
14857705Sbostic 
14957705Sbostic bcg1:
15057710Sbostic 	if ((RE_flag == 0) && (l_match[1] == '\0')) {
15157710Sbostic 		*errnum = -1;
15257710Sbostic 		ungetc(ss, inputt);
15357710Sbostic 		return;
15457710Sbostic 	} else
15557710Sbostic 		if ((l_sr_flag == 0) && (l_match[1] || (RE_patt == NULL))) {
156*58315Sbostic 			int l_m_len = 2 + strlen(l_match);
157*58315Sbostic 			sigspecial++;
15857710Sbostic 			free(RE_patt);
159*58315Sbostic 			RE_patt = malloc(sizeof(char) * (l_m_len));
160*58315Sbostic 			bcopy(l_match, RE_patt, l_m_len);
161*58315Sbostic 			sigspecial--;
162*58315Sbostic 			if (sigint_flag && (!sigspecial))
163*58315Sbostic 				SIGINT_ACTION;
16457710Sbostic 		}
16557710Sbostic 	RE_sol = (l_match[1] == '^') ? 1 : 0;
16657710Sbostic 	if ((l_match[1]) &&
16757710Sbostic 	    (regfree(&RE_comp), l_err = regcomp(&RE_comp, &l_match[1], 0))) {
16857710Sbostic 		regerror(l_err, &RE_comp, help_msg, 128);
16957710Sbostic 		*errnum = -1;
17057710Sbostic 		RE_flag = 0;
17157710Sbostic 		ungetc(ss, inputt);
17257710Sbostic 		return;
17357710Sbostic 	}
17457710Sbostic 	RE_flag = 1;
175*58315Sbostic 	if (sigint_flag && (!sigspecial))
17657710Sbostic 		SIGINT_ACTION;
17757705Sbostic bcg2:
17857710Sbostic 	current = start;
17957710Sbostic 	l_s_flag = 0;
18057710Sbostic 	do {
18157710Sbostic 		RE_match[0].rm_eo = 0;
18257710Sbostic 		get_line(current->handle, current->len);
183*58315Sbostic 		if (sigint_flag && (!sigspecial))
184*58315Sbostic 			SIGINT_ACTION;
18557710Sbostic 		l_count = l_count2;
18657710Sbostic 		l_local = text;
18757705Sbostic #ifndef REG_STARTEND
18857710Sbostic 		l_offset = 0;
18957705Sbostic #endif
19057710Sbostic 		do {
19157710Sbostic 			RE_match[0].rm_so = RE_match[0].rm_eo;
19257705Sbostic #ifdef REG_STARTEND
19357710Sbostic 			l_matched = regexec_n(&RE_comp, l_local,
19457710Sbostic 			    (size_t)RE_SEC, RE_match, 0, l_count,
19557710Sbostic 			    (size_t)current->len, 0);
19657705Sbostic #else
19757710Sbostic 			l_matched = regexec_n(&RE_comp, l_local,
19857710Sbostic 			    (size_t)RE_SEC, RE_match, 0, l_count,
19957710Sbostic 			    &l_offset, 0);
20057705Sbostic #endif
20157710Sbostic 			if (l_matched == 0) {
20257710Sbostic 				if ((l_s_flag == 0) && (g_flag == 0))
20357710Sbostic 					u_clr_stk();
20457710Sbostic 				l_count = l_s_flag = 1;
20557710Sbostic 				/*
20657710Sbostic 				 * The l_local passed into re_replace is not
20757710Sbostic 				 * freed in re_replace because it is "text",
20857710Sbostic 				 * the global line holder, for the first pass
20957710Sbostic 				 * through this loop. The value returned by
21057710Sbostic 				 * re_replace is a new string (with the first
21157710Sbostic 				 * replacement in it). If the 'g' flag was
21257710Sbostic 				 * set with substitute then this new string
21357710Sbostic 				 * is passed in for the second pass and can
21457710Sbostic 				 * be freed once re_replace is done with it.
21557710Sbostic 				 * (...and so on for the rest of the 'g'
21657710Sbostic 				 * passes. RE_match[0].rm_eo is changed in
21757710Sbostic 				 * re_replace to be the new location of the
21857710Sbostic 				 * next character immediately after the
21957710Sbostic 				 * replacement since it is likely the
22057710Sbostic 				 * position of that character has changed
22157710Sbostic 				 * because of the replacement.
22257710Sbostic 				 */
22357705Sbostic #ifdef REG_STARTEND
22457710Sbostic 				l_local = re_replace(l_local,
22557710Sbostic 				    (size_t)(RE_SEC - 1), RE_match, &l_repl[1]);
22657705Sbostic #else
22757710Sbostic 				l_local = re_replace(l_local,
22857710Sbostic 				    (size_t)(RE_SEC - 1), RE_match, &l_repl[1],
22957710Sbostic 				    l_offset);
23057705Sbostic #endif
23157710Sbostic 			}
23257710Sbostic 			if (l_global == 0)
23357710Sbostic 				break;
23457710Sbostic 			if (l_local[RE_match[0].rm_eo] == '\0')
23557710Sbostic 				break;
23657710Sbostic 		} while (!l_matched);
23757705Sbostic 
23857710Sbostic 		l_cnt = l_nflag = 0;
23957710Sbostic 		l_kval = current;
24057710Sbostic 		l_temp_line = current->above;
24157710Sbostic 		l_temp_line2 = current->below;
24257710Sbostic 		l_local_temp = l_local;
243*58315Sbostic 		sigspecial++;
24457710Sbostic 		for (;;) {
24557710Sbostic 			/*
24657710Sbostic 			 * Make the new string the one for this line.  Check if
24757710Sbostic 			 * it needs to be split.
24857710Sbostic 			 */
24957710Sbostic 			if (l_local[l_cnt] == '\n' || l_local[l_cnt] == '\0') {
25057710Sbostic 				if (l_local[l_cnt] == '\0')
25157710Sbostic 					l_nflag = 1;
25257710Sbostic 				l_local[l_cnt] = '\0';
25357710Sbostic 				l_s_ret = malloc(sizeof(LINE));
25457710Sbostic 				if (l_s_ret == NULL) {
25557710Sbostic 					*errnum = -1;
25657710Sbostic 					strcpy(help_msg, "out of memory error");
25757710Sbostic 					return;
25857710Sbostic 				}
25957710Sbostic 				(l_s_ret->len) = strlen(l_local);
26057710Sbostic 				(l_s_ret->handle) = add_line(l_local, l_s_ret->len);
26157710Sbostic 				(l_s_ret->above) = l_temp_line;
26257710Sbostic 				(l_s_ret->below) = NULL;
26357710Sbostic 				if (l_temp_line == NULL)
26457710Sbostic 					top = l_s_ret;
26557710Sbostic 				else {
26657710Sbostic 					u_add_stk(&(l_temp_line->below));
26757710Sbostic 					(l_temp_line->below) = l_s_ret;
26857710Sbostic 				}
26957710Sbostic 				l_temp_line = l_s_ret;
27057710Sbostic 				if ((l_local[l_cnt] == '\0') && (l_nflag == 1))
27157710Sbostic 					break;
27257710Sbostic 				else {
27357710Sbostic 					l_local = &(l_local[l_cnt + 1]);
27457710Sbostic 					l_cnt = 0;
27557710Sbostic 				}
27657710Sbostic 			} else
27757710Sbostic 				l_cnt++;
27857710Sbostic 		}
27957710Sbostic 		(l_s_ret->below) = l_temp_line2;
28057710Sbostic 		ku_chk(current, current, l_kval->below);
28157710Sbostic 		if (current == End)
28257710Sbostic 			End = l_s_ret;
28357710Sbostic 		current = l_s_ret;
28457710Sbostic 		l_last = current;
28557710Sbostic 		if (l_temp_line2 == NULL)
28657710Sbostic 			bottom = l_s_ret;
28757710Sbostic 		else {
28857710Sbostic 			u_add_stk(&(l_temp_line2->above));
28957710Sbostic 			(l_temp_line2->above) = current;
29057710Sbostic 		}
291*58315Sbostic 		sigspecial--;
292*58315Sbostic 		if (sigint_flag && (!sigspecial))
293*58315Sbostic 			SIGINT_ACTION;
29457710Sbostic 		if (l_local_temp != text)
29557710Sbostic 			free(l_local_temp);
29657710Sbostic 		current = current->below;
29757710Sbostic 	} while (current != (End->below));
29857705Sbostic 
29957710Sbostic 	if (l_s_flag == 0) {
30057710Sbostic 		current = start;
30157710Sbostic 		strcpy(help_msg, "no matches found for substitution");
30257710Sbostic 		*errnum = -1;
30357710Sbostic 		ungetc('\n', inputt);
30457710Sbostic 		return;
30557710Sbostic 	}
30657710Sbostic 	change_flag = 1;
30757710Sbostic 	current = l_last;
30857705Sbostic 
30957710Sbostic 	if (l_print > 0) {
31057710Sbostic 		start = End = current;
31157710Sbostic 		ungetc(ss, inputt);
31257710Sbostic 		if (l_print == (l_print | (int) 1))
31357710Sbostic 			p(inputt, errnum, 0);
31457710Sbostic 		if (l_print == (l_print | (int) 2))
31557710Sbostic 			p(inputt, errnum, 1);
31657710Sbostic 		if (l_print == (l_print | (int) 4))
31757710Sbostic 			l(inputt, errnum);
31857710Sbostic 		if (*errnum < 0)
31957710Sbostic 			return;
32057710Sbostic 	}
32157710Sbostic 	if (l_sr_flag == -1) {
32257710Sbostic 		regfree(&RE_comp);
32357710Sbostic 		regcomp(&RE_comp, &RE_patt[1], 0);
32457710Sbostic 	}
32557710Sbostic 	*errnum = 1;
32657710Sbostic }
327