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