1*57705Sbostic /*- 2*57705Sbostic * Copyright (c) 1992 The Regents of the University of California. 3*57705Sbostic * All rights reserved. 4*57705Sbostic * 5*57705Sbostic * This code is derived from software contributed to Berkeley by 6*57705Sbostic * Rodney Ruddock of the University of Guelph. 7*57705Sbostic * 8*57705Sbostic * %sccs.include.redist.c% 9*57705Sbostic */ 10*57705Sbostic 11*57705Sbostic #ifndef lint 12*57705Sbostic static char sccsid[] = "@(#)sub.c 5.1 (Berkeley) 01/23/93"; 13*57705Sbostic #endif /* not lint */ 14*57705Sbostic 15*57705Sbostic #include "ed.h" 16*57705Sbostic 17*57705Sbostic /* 18*57705Sbostic * The substitute command. It's big because of the backward compatability. 19*57705Sbostic */ 20*57705Sbostic 21*57705Sbostic void 22*57705Sbostic s(inputt, errnum) 23*57705Sbostic 24*57705Sbostic FILE *inputt; 25*57705Sbostic int *errnum; 26*57705Sbostic 27*57705Sbostic { 28*57705Sbostic static int l_count2=1, l_global=0, l_print=0, l_first_pass_flag=0; 29*57705Sbostic static char *l_match=NULL, *l_repl=NULL; 30*57705Sbostic int l_s_flag, l_count, l_matched, l_nflag, l_cnt, yy, l_sr_flag=0, l_err, l_sl; 31*57705Sbostic char *l_match2=NULL, *l_local=NULL, *l_local_temp=NULL; 32*57705Sbostic LINE *l_s_ret, *l_temp_line, *l_temp_line2, *l_kval, *l_last; 33*57705Sbostic #ifndef REG_STARTEND 34*57705Sbostic size_t l_offset=0; 35*57705Sbostic #endif 36*57705Sbostic 37*57705Sbostic if (start_default && End_default) 38*57705Sbostic start = End = current; 39*57705Sbostic else if (start_default) 40*57705Sbostic start = End; 41*57705Sbostic if (start == NULL) 42*57705Sbostic { 43*57705Sbostic *errnum = -1; 44*57705Sbostic return; 45*57705Sbostic } 46*57705Sbostic start_default = End_default = 0; 47*57705Sbostic 48*57705Sbostic l_sl = ss = getc(inputt); 49*57705Sbostic if (l_first_pass_flag == 0) 50*57705Sbostic l_match = l_repl = NULL; 51*57705Sbostic l_match2 = get_pattern(l_sl, inputt, errnum, 0); 52*57705Sbostic if (sigint_flag) 53*57705Sbostic SIGINT_ACTION; 54*57705Sbostic if (*errnum < 0) 55*57705Sbostic { 56*57705Sbostic if ((*errnum == -2) && (l_sl != '\n')) 57*57705Sbostic return; 58*57705Sbostic if ((l_match2 == NULL) || (strlen(l_match2) > 4) || (l_first_pass_flag == 0)) 59*57705Sbostic return; 60*57705Sbostic *errnum = 0; 61*57705Sbostic l_sr_flag = -1; 62*57705Sbostic for (yy=0; yy<(strlen(l_match2)); yy++) 63*57705Sbostic { 64*57705Sbostic switch (l_match2[yy]) 65*57705Sbostic { 66*57705Sbostic case '\n': ss = getc(inputt); 67*57705Sbostic goto bcg1; 68*57705Sbostic break; 69*57705Sbostic case 'r': l_sr_flag = 1; 70*57705Sbostic break; 71*57705Sbostic case 'p': l_print = (l_print)?0:1; 72*57705Sbostic break; 73*57705Sbostic case 'g': l_global = (l_global)?0:1; 74*57705Sbostic break; 75*57705Sbostic case 'N': l_count2 = 1; 76*57705Sbostic break; 77*57705Sbostic default: *errnum = -1; 78*57705Sbostic strcpy(help_msg, "illegal modifier to s"); 79*57705Sbostic return; 80*57705Sbostic } /* end-switch */ 81*57705Sbostic } /* end-for */ 82*57705Sbostic ss = getc(inputt); 83*57705Sbostic if (l_sr_flag == 1) 84*57705Sbostic goto bcg2; 85*57705Sbostic else 86*57705Sbostic goto bcg1; 87*57705Sbostic } 88*57705Sbostic 89*57705Sbostic if (l_first_pass_flag) 90*57705Sbostic { 91*57705Sbostic free(l_match); 92*57705Sbostic free(l_repl); 93*57705Sbostic } 94*57705Sbostic else 95*57705Sbostic l_first_pass_flag = 1; 96*57705Sbostic l_match = l_match2; 97*57705Sbostic *errnum = 0; 98*57705Sbostic l_repl = get_pattern(ss, inputt, errnum, 1); 99*57705Sbostic if (sigint_flag) 100*57705Sbostic SIGINT_ACTION; 101*57705Sbostic l_global = l_print = 0; 102*57705Sbostic if (*errnum < 0) 103*57705Sbostic { 104*57705Sbostic if ((*errnum == -1) && (ss == '\n')) 105*57705Sbostic l_print = (int)1; /* note: \n still in stream for next getc */ 106*57705Sbostic else 107*57705Sbostic return; 108*57705Sbostic } 109*57705Sbostic *errnum = 0; 110*57705Sbostic 111*57705Sbostic l_count2 = 1; 112*57705Sbostic 113*57705Sbostic while (((ss=getc(inputt)) != '\n') && (ss != EOF)) 114*57705Sbostic { 115*57705Sbostic if (ss == 'g') 116*57705Sbostic l_global = 1; 117*57705Sbostic else if (ss == 'p') 118*57705Sbostic l_print = (l_print | (int)1); 119*57705Sbostic else if (ss == 'n') 120*57705Sbostic l_print = (l_print | (int)2); 121*57705Sbostic else if (ss == 'l') 122*57705Sbostic l_print = (l_print | (int)4); 123*57705Sbostic else if ((ss > ('0'-1)) && (ss < ('9'+1))) 124*57705Sbostic l_count2 = dig_num_conv(inputt, errnum); 125*57705Sbostic else 126*57705Sbostic { 127*57705Sbostic *errnum = -1; 128*57705Sbostic strcpy(help_msg, "illegal command option"); 129*57705Sbostic return; 130*57705Sbostic } 131*57705Sbostic } 132*57705Sbostic 133*57705Sbostic bcg1: 134*57705Sbostic if ((RE_flag == 0) && (l_match[1] == '\0')) 135*57705Sbostic { 136*57705Sbostic *errnum = -1; 137*57705Sbostic ungetc(ss, inputt); 138*57705Sbostic return; 139*57705Sbostic } 140*57705Sbostic else if ((l_sr_flag == 0) && (l_match[1] || (RE_patt == NULL))) 141*57705Sbostic { 142*57705Sbostic free(RE_patt); 143*57705Sbostic RE_patt = (char *)malloc(sizeof(char)*(2+strlen(l_match))); 144*57705Sbostic bcopy(l_match, RE_patt); 145*57705Sbostic } 146*57705Sbostic RE_sol = (l_match[1] == '^')?1:0; 147*57705Sbostic if ((l_match[1]) && (regfree(&RE_comp), l_err = regcomp(&RE_comp, &l_match[1], 0))) 148*57705Sbostic { 149*57705Sbostic regerror(l_err, &RE_comp, help_msg, 128); 150*57705Sbostic *errnum = -1; 151*57705Sbostic RE_flag = 0; 152*57705Sbostic ungetc(ss, inputt); 153*57705Sbostic return; 154*57705Sbostic } 155*57705Sbostic RE_flag = 1; 156*57705Sbostic if (sigint_flag) 157*57705Sbostic SIGINT_ACTION; 158*57705Sbostic bcg2: 159*57705Sbostic current = start; 160*57705Sbostic l_s_flag = 0; 161*57705Sbostic do 162*57705Sbostic { 163*57705Sbostic if (sigint_flag) 164*57705Sbostic SIGINT_ACTION; 165*57705Sbostic RE_match[0].rm_eo = 0; 166*57705Sbostic get_line(current->handle, current->len); 167*57705Sbostic l_count = l_count2; 168*57705Sbostic l_local = text; 169*57705Sbostic #ifndef REG_STARTEND 170*57705Sbostic l_offset = 0; 171*57705Sbostic #endif 172*57705Sbostic do 173*57705Sbostic { 174*57705Sbostic RE_match[0].rm_so = RE_match[0].rm_eo; 175*57705Sbostic #ifdef REG_STARTEND 176*57705Sbostic l_matched = regexec_n(&RE_comp, l_local, (size_t)RE_SEC, RE_match, 0, l_count, (size_t)current->len, 0); 177*57705Sbostic #else 178*57705Sbostic l_matched = regexec_n(&RE_comp, l_local, (size_t)RE_SEC, RE_match, 0, l_count, &l_offset, 0); 179*57705Sbostic #endif 180*57705Sbostic if (l_matched == 0) 181*57705Sbostic { 182*57705Sbostic if ((l_s_flag == 0) && (g_flag == 0)) 183*57705Sbostic u_clr_stk(); 184*57705Sbostic l_count = l_s_flag = 1; 185*57705Sbostic /* the l_local passed into re_replace is not freed in re_replace 186*57705Sbostic * because it is "text", the global line holder, for the first 187*57705Sbostic * pass through this loop. The value returned by re_replace is 188*57705Sbostic * a new string (with the first replacement in it). If the 'g' 189*57705Sbostic * flag was set with substitute then this new string is passed in 190*57705Sbostic * for the second pass and can be freed once re_replace is done 191*57705Sbostic * with it. (...and so on for the rest of the 'g' passes. 192*57705Sbostic * RE_match[0].rm_eo is changed in re_replace to be the 193*57705Sbostic * new location of the next character immediately after 194*57705Sbostic * the replacement since it is likely the position of that 195*57705Sbostic * character has changed because of the replacement. 196*57705Sbostic */ 197*57705Sbostic #ifdef REG_STARTEND 198*57705Sbostic l_local = re_replace(l_local, (size_t)(RE_SEC-1), RE_match, &l_repl[1]); 199*57705Sbostic #else 200*57705Sbostic l_local = re_replace(l_local, (size_t)(RE_SEC-1), RE_match, &l_repl[1], l_offset); 201*57705Sbostic #endif 202*57705Sbostic } 203*57705Sbostic if (l_global == 0) 204*57705Sbostic break; 205*57705Sbostic if (l_local[RE_match[0].rm_eo] == '\0') 206*57705Sbostic break; 207*57705Sbostic } while (!l_matched); 208*57705Sbostic 209*57705Sbostic l_cnt = l_nflag = 0; 210*57705Sbostic l_kval = current; 211*57705Sbostic l_temp_line = current->above; 212*57705Sbostic l_temp_line2 = current->below; 213*57705Sbostic l_local_temp = l_local; 214*57705Sbostic while (1) 215*57705Sbostic { 216*57705Sbostic /* make the new string the one for this line. Check if 217*57705Sbostic * it needs to be split. 218*57705Sbostic */ 219*57705Sbostic if ((l_local[l_cnt] == '\n') || (l_local[l_cnt] == '\0')) 220*57705Sbostic { 221*57705Sbostic if (l_local[l_cnt] == '\0') 222*57705Sbostic l_nflag = 1; 223*57705Sbostic l_local[l_cnt] = '\0'; 224*57705Sbostic l_s_ret = (LINE *)malloc(sizeof(LINE)); 225*57705Sbostic if (l_s_ret == NULL) 226*57705Sbostic { 227*57705Sbostic *errnum = -1; 228*57705Sbostic strcpy(help_msg, "out of memory error"); 229*57705Sbostic return; 230*57705Sbostic } 231*57705Sbostic (l_s_ret->len) = strlen(l_local); 232*57705Sbostic (l_s_ret->handle) = add_line(l_local, l_s_ret->len); 233*57705Sbostic (l_s_ret->above) = l_temp_line; 234*57705Sbostic (l_s_ret->below) = NULL; 235*57705Sbostic if (l_temp_line == NULL) 236*57705Sbostic top = l_s_ret; 237*57705Sbostic else 238*57705Sbostic { 239*57705Sbostic u_add_stk(&(l_temp_line->below)); 240*57705Sbostic (l_temp_line->below) = l_s_ret; 241*57705Sbostic } 242*57705Sbostic l_temp_line = l_s_ret; 243*57705Sbostic if ((l_local[l_cnt] == '\0') && (l_nflag == 1)) 244*57705Sbostic break; 245*57705Sbostic else 246*57705Sbostic { 247*57705Sbostic l_local = &(l_local[l_cnt+1]); 248*57705Sbostic l_cnt = 0; 249*57705Sbostic } 250*57705Sbostic } /* end-if */ 251*57705Sbostic else 252*57705Sbostic l_cnt++; 253*57705Sbostic } /* end-while */ 254*57705Sbostic (l_s_ret->below) = l_temp_line2; 255*57705Sbostic ku_chk(current, current, l_kval->below); 256*57705Sbostic if (current == End) 257*57705Sbostic End = l_s_ret; 258*57705Sbostic current = l_s_ret; 259*57705Sbostic l_last = current; 260*57705Sbostic if (l_temp_line2 == NULL) 261*57705Sbostic bottom = l_s_ret; 262*57705Sbostic else 263*57705Sbostic { 264*57705Sbostic u_add_stk(&(l_temp_line2->above)); 265*57705Sbostic (l_temp_line2->above) = current; 266*57705Sbostic } 267*57705Sbostic if (l_local_temp != text) 268*57705Sbostic free(l_local_temp); 269*57705Sbostic current = current->below; 270*57705Sbostic } while (current != (End->below)); 271*57705Sbostic 272*57705Sbostic if (l_s_flag == 0) 273*57705Sbostic { 274*57705Sbostic current = start; 275*57705Sbostic strcpy(help_msg, "no matches found for substitution"); 276*57705Sbostic *errnum = -1; 277*57705Sbostic ungetc('\n', inputt); 278*57705Sbostic return; 279*57705Sbostic } 280*57705Sbostic 281*57705Sbostic change_flag = 1; 282*57705Sbostic current = l_last; 283*57705Sbostic 284*57705Sbostic if (l_print > 0) 285*57705Sbostic { 286*57705Sbostic start = End = current; 287*57705Sbostic ungetc(ss, inputt); 288*57705Sbostic if (l_print == (l_print | (int)1)) 289*57705Sbostic p(inputt, errnum, 0); 290*57705Sbostic if (l_print == (l_print | (int)2)) 291*57705Sbostic p(inputt, errnum, 1); 292*57705Sbostic if (l_print == (l_print | (int)4)) 293*57705Sbostic l(inputt, errnum); 294*57705Sbostic if (*errnum < 0) 295*57705Sbostic return; 296*57705Sbostic } 297*57705Sbostic 298*57705Sbostic if (l_sr_flag == -1) 299*57705Sbostic { 300*57705Sbostic regfree(&RE_comp); 301*57705Sbostic regcomp(&RE_comp, &RE_patt[1], 0); 302*57705Sbostic } 303*57705Sbostic *errnum = 1; 304*57705Sbostic } /* end-s */ 305