xref: /csrg-svn/contrib/ed/sub.c (revision 60663)
157705Sbostic /*-
2*60663Sbostic  * Copyright (c) 1992, 1993
3*60663Sbostic  *	The Regents of the University of California.  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*60663Sbostic static char sccsid[] = "@(#)sub.c	8.1 (Berkeley) 05/31/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 
2358315Sbostic #ifdef DBI
2458315Sbostic #include <db.h>
2558315Sbostic #endif
2658315Sbostic 
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
s(inputt,errnum)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;
4159915Sbostic 	LINE *l_s_ret, *l_temp_line, *l_temp_line2, *l_kval, *l_last, *l_cur;
4257710Sbostic 	int l_s_flag, l_count, l_matched, l_nflag, l_cnt, yy, l_sr_flag = 0;
4359915Sbostic 	int l_err, l_sl, l_rep_flag, l_u_reuse_flag=0, l_local_len, l_nudge=0;
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 
4958564Sralph 	if (Start_default && End_default)
5058564Sralph 		Start = End = current;
5157710Sbostic 	else
5258564Sralph 		if (Start_default)
5358564Sralph 			Start = End;
5458564Sralph 	if (Start == NULL) {
5557710Sbostic 		*errnum = -1;
5657710Sbostic 		return;
5757710Sbostic 	}
5858564Sralph 	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);
6458315Sbostic 
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);
11158315Sbostic 	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))) {
15658315Sbostic 			int l_m_len = 2 + strlen(l_match);
15758315Sbostic 			sigspecial++;
15857710Sbostic 			free(RE_patt);
15958315Sbostic 			RE_patt = malloc(sizeof(char) * (l_m_len));
16059483Sbostic 			memmove(RE_patt, l_match, l_m_len);
16158315Sbostic 			sigspecial--;
16258315Sbostic 			if (sigint_flag && (!sigspecial))
16358315Sbostic 				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;
17558315Sbostic 	if (sigint_flag && (!sigspecial))
17657710Sbostic 		SIGINT_ACTION;
17757705Sbostic bcg2:
17859915Sbostic 	l_cur = current;
17958564Sralph 	current = Start;
18057710Sbostic 	l_s_flag = 0;
18157710Sbostic 	do {
18257710Sbostic 		RE_match[0].rm_eo = 0;
18357710Sbostic 		get_line(current->handle, current->len);
18458315Sbostic 		if (sigint_flag && (!sigspecial))
18558315Sbostic 			SIGINT_ACTION;
18657710Sbostic 		l_count = l_count2;
18757710Sbostic 		l_local = text;
18859475Sbostic 		l_rep_flag = 1;
18957705Sbostic #ifndef REG_STARTEND
19057710Sbostic 		l_offset = 0;
19159558Sbostic #else
19259558Sbostic 		l_local_len = current->len;
19357705Sbostic #endif
19457710Sbostic 		do {
19557710Sbostic 			RE_match[0].rm_so = RE_match[0].rm_eo;
19659915Sbostic 			if (l_nudge)
19759915Sbostic 				RE_match[0].rm_so++;
19859915Sbostic 			l_nudge = 0;
19957705Sbostic #ifdef REG_STARTEND
20057710Sbostic 			l_matched = regexec_n(&RE_comp, l_local,
20157710Sbostic 			    (size_t)RE_SEC, RE_match, 0, l_count,
20259558Sbostic 			    (size_t)l_local_len, 0);
20357705Sbostic #else
20457710Sbostic 			l_matched = regexec_n(&RE_comp, l_local,
20557710Sbostic 			    (size_t)RE_SEC, RE_match, 0, l_count,
20657710Sbostic 			    &l_offset, 0);
20757705Sbostic #endif
20857710Sbostic 			if (l_matched == 0) {
20959915Sbostic 				if ((l_s_flag == 0) && (g_flag == 0)) {
21059915Sbostic 					current = l_cur;
21157710Sbostic 					u_clr_stk();
21259915Sbostic 					current = Start;
21359915Sbostic 				}
21457710Sbostic 				l_count = l_s_flag = 1;
21559475Sbostic 				l_rep_flag = 0;
21657710Sbostic 				/*
21757710Sbostic 				 * The l_local passed into re_replace is not
21857710Sbostic 				 * freed in re_replace because it is "text",
21957710Sbostic 				 * the global line holder, for the first pass
22057710Sbostic 				 * through this loop. The value returned by
22157710Sbostic 				 * re_replace is a new string (with the first
22257710Sbostic 				 * replacement in it). If the 'g' flag was
22357710Sbostic 				 * set with substitute then this new string
22457710Sbostic 				 * is passed in for the second pass and can
22557710Sbostic 				 * be freed once re_replace is done with it.
22657710Sbostic 				 * (...and so on for the rest of the 'g'
22757710Sbostic 				 * passes. RE_match[0].rm_eo is changed in
22857710Sbostic 				 * re_replace to be the new location of the
22957710Sbostic 				 * next character immediately after the
23057710Sbostic 				 * replacement since it is likely the
23157710Sbostic 				 * position of that character has changed
23257710Sbostic 				 * because of the replacement.
23357710Sbostic 				 */
23459915Sbostic 				if (RE_match[0].rm_so == RE_match[0].rm_eo)
23559915Sbostic 					l_nudge = 1;
23657705Sbostic #ifdef REG_STARTEND
23757710Sbostic 				l_local = re_replace(l_local,
23857710Sbostic 				    (size_t)(RE_SEC - 1), RE_match, &l_repl[1]);
23959558Sbostic 				l_local_len = strlen(l_local);
24057705Sbostic #else
24157710Sbostic 				l_local = re_replace(l_local,
24257710Sbostic 				    (size_t)(RE_SEC - 1), RE_match, &l_repl[1],
24357710Sbostic 				    l_offset);
24457705Sbostic #endif
24557710Sbostic 			}
24657710Sbostic 			if (l_global == 0)
24757710Sbostic 				break;
24857710Sbostic 			if (l_local[RE_match[0].rm_eo] == '\0')
24957710Sbostic 				break;
25057710Sbostic 		} while (!l_matched);
25157705Sbostic 
25259475Sbostic 		if (l_rep_flag)
25359475Sbostic 			goto next;
25457710Sbostic 		l_cnt = l_nflag = 0;
25557710Sbostic 		l_kval = current;
25657710Sbostic 		l_temp_line = current->above;
25757710Sbostic 		l_temp_line2 = current->below;
25857710Sbostic 		l_local_temp = l_local;
25958315Sbostic 		sigspecial++;
26057710Sbostic 		for (;;) {
26157710Sbostic 			/*
26257710Sbostic 			 * Make the new string the one for this line.  Check if
26357710Sbostic 			 * it needs to be split.
26457710Sbostic 			 */
26557710Sbostic 			if (l_local[l_cnt] == '\n' || l_local[l_cnt] == '\0') {
26657710Sbostic 				if (l_local[l_cnt] == '\0')
26757710Sbostic 					l_nflag = 1;
26857710Sbostic 				l_local[l_cnt] = '\0';
26957710Sbostic 				l_s_ret = malloc(sizeof(LINE));
27057710Sbostic 				if (l_s_ret == NULL) {
27157710Sbostic 					*errnum = -1;
27257710Sbostic 					strcpy(help_msg, "out of memory error");
27357710Sbostic 					return;
27457710Sbostic 				}
27557710Sbostic 				(l_s_ret->len) = strlen(l_local);
27657710Sbostic 				(l_s_ret->handle) = add_line(l_local, l_s_ret->len);
27757710Sbostic 				(l_s_ret->above) = l_temp_line;
27857710Sbostic 				(l_s_ret->below) = NULL;
27957710Sbostic 				if (l_temp_line == NULL)
28057710Sbostic 					top = l_s_ret;
28157710Sbostic 				else {
28259475Sbostic 					if ((current != Start) &&
28359475Sbostic 						((&(current->above)) == u_stk->cell))
28459475Sbostic 						l_u_reuse_flag = 1;
28559475Sbostic 					else {
28659475Sbostic 						u_add_stk(&(l_temp_line->below));
28759475Sbostic 						l_u_reuse_flag = 0;
28859475Sbostic 					}
28957710Sbostic 					(l_temp_line->below) = l_s_ret;
29057710Sbostic 				}
29157710Sbostic 				l_temp_line = l_s_ret;
29257710Sbostic 				if ((l_local[l_cnt] == '\0') && (l_nflag == 1))
29357710Sbostic 					break;
29457710Sbostic 				else {
29557710Sbostic 					l_local = &(l_local[l_cnt + 1]);
29657710Sbostic 					l_cnt = 0;
29757710Sbostic 				}
29857710Sbostic 			} else
29957710Sbostic 				l_cnt++;
30057710Sbostic 		}
30157710Sbostic 		(l_s_ret->below) = l_temp_line2;
30257710Sbostic 		ku_chk(current, current, l_kval->below);
30357710Sbostic 		if (current == End)
30457710Sbostic 			End = l_s_ret;
30557710Sbostic 		current = l_s_ret;
30657710Sbostic 		l_last = current;
30757710Sbostic 		if (l_temp_line2 == NULL)
30857710Sbostic 			bottom = l_s_ret;
30957710Sbostic 		else {
31059475Sbostic 			if (l_u_reuse_flag)
31159475Sbostic 				u_pop_n_swap(&(l_temp_line2->above));
31259475Sbostic 			else
31359475Sbostic 				u_add_stk(&(l_temp_line2->above));
31457710Sbostic 			(l_temp_line2->above) = current;
31557710Sbostic 		}
31658315Sbostic 		sigspecial--;
31758315Sbostic 		if (sigint_flag && (!sigspecial))
31858315Sbostic 			SIGINT_ACTION;
31957710Sbostic 		if (l_local_temp != text)
32057710Sbostic 			free(l_local_temp);
32159475Sbostic next:
32257710Sbostic 		current = current->below;
32357710Sbostic 	} while (current != (End->below));
32457705Sbostic 
32557710Sbostic 	if (l_s_flag == 0) {
32658564Sralph 		current = Start;
32759915Sbostic 		if (!g_flag) {
32859915Sbostic 			strcpy(help_msg, "no matches found for substitution");
32959915Sbostic 			*errnum = -1;
33059915Sbostic 			ungetc('\n', inputt);
33159915Sbostic 		}
33259915Sbostic 		else
33359915Sbostic 			*errnum = 0;
33457710Sbostic 		return;
33557710Sbostic 	}
33657710Sbostic 	change_flag = 1;
33757710Sbostic 	current = l_last;
33857705Sbostic 
33957710Sbostic 	if (l_print > 0) {
34059475Sbostic 		Start = End = l_s_ret; /*current;*/
34157710Sbostic 		ungetc(ss, inputt);
34257710Sbostic 		if (l_print == (l_print | (int) 1))
34357710Sbostic 			p(inputt, errnum, 0);
34457710Sbostic 		if (l_print == (l_print | (int) 2))
34557710Sbostic 			p(inputt, errnum, 1);
34657710Sbostic 		if (l_print == (l_print | (int) 4))
34757710Sbostic 			l(inputt, errnum);
34857710Sbostic 		if (*errnum < 0)
34957710Sbostic 			return;
35057710Sbostic 	}
35157710Sbostic 	if (l_sr_flag == -1) {
35257710Sbostic 		regfree(&RE_comp);
35357710Sbostic 		regcomp(&RE_comp, &RE_patt[1], 0);
35457710Sbostic 	}
35557710Sbostic 	*errnum = 1;
35657710Sbostic }
357