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*59915Sbostic static char sccsid[] = "@(#)sub.c 5.8 (Berkeley) 05/11/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 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; 41*59915Sbostic 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; 43*59915Sbostic 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: 178*59915Sbostic 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; 196*59915Sbostic if (l_nudge) 197*59915Sbostic RE_match[0].rm_so++; 198*59915Sbostic 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) { 209*59915Sbostic if ((l_s_flag == 0) && (g_flag == 0)) { 210*59915Sbostic current = l_cur; 21157710Sbostic u_clr_stk(); 212*59915Sbostic current = Start; 213*59915Sbostic } 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 */ 234*59915Sbostic if (RE_match[0].rm_so == RE_match[0].rm_eo) 235*59915Sbostic 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; 327*59915Sbostic if (!g_flag) { 328*59915Sbostic strcpy(help_msg, "no matches found for substitution"); 329*59915Sbostic *errnum = -1; 330*59915Sbostic ungetc('\n', inputt); 331*59915Sbostic } 332*59915Sbostic else 333*59915Sbostic *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