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