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