1 /*- 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. 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 8.1 (Berkeley) 05/31/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, *l_cur; 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, l_local_len, l_nudge=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 l_cur = current; 179 current = Start; 180 l_s_flag = 0; 181 do { 182 RE_match[0].rm_eo = 0; 183 get_line(current->handle, current->len); 184 if (sigint_flag && (!sigspecial)) 185 SIGINT_ACTION; 186 l_count = l_count2; 187 l_local = text; 188 l_rep_flag = 1; 189 #ifndef REG_STARTEND 190 l_offset = 0; 191 #else 192 l_local_len = current->len; 193 #endif 194 do { 195 RE_match[0].rm_so = RE_match[0].rm_eo; 196 if (l_nudge) 197 RE_match[0].rm_so++; 198 l_nudge = 0; 199 #ifdef REG_STARTEND 200 l_matched = regexec_n(&RE_comp, l_local, 201 (size_t)RE_SEC, RE_match, 0, l_count, 202 (size_t)l_local_len, 0); 203 #else 204 l_matched = regexec_n(&RE_comp, l_local, 205 (size_t)RE_SEC, RE_match, 0, l_count, 206 &l_offset, 0); 207 #endif 208 if (l_matched == 0) { 209 if ((l_s_flag == 0) && (g_flag == 0)) { 210 current = l_cur; 211 u_clr_stk(); 212 current = Start; 213 } 214 l_count = l_s_flag = 1; 215 l_rep_flag = 0; 216 /* 217 * The l_local passed into re_replace is not 218 * freed in re_replace because it is "text", 219 * the global line holder, for the first pass 220 * through this loop. The value returned by 221 * re_replace is a new string (with the first 222 * replacement in it). If the 'g' flag was 223 * set with substitute then this new string 224 * is passed in for the second pass and can 225 * be freed once re_replace is done with it. 226 * (...and so on for the rest of the 'g' 227 * passes. RE_match[0].rm_eo is changed in 228 * re_replace to be the new location of the 229 * next character immediately after the 230 * replacement since it is likely the 231 * position of that character has changed 232 * because of the replacement. 233 */ 234 if (RE_match[0].rm_so == RE_match[0].rm_eo) 235 l_nudge = 1; 236 #ifdef REG_STARTEND 237 l_local = re_replace(l_local, 238 (size_t)(RE_SEC - 1), RE_match, &l_repl[1]); 239 l_local_len = strlen(l_local); 240 #else 241 l_local = re_replace(l_local, 242 (size_t)(RE_SEC - 1), RE_match, &l_repl[1], 243 l_offset); 244 #endif 245 } 246 if (l_global == 0) 247 break; 248 if (l_local[RE_match[0].rm_eo] == '\0') 249 break; 250 } while (!l_matched); 251 252 if (l_rep_flag) 253 goto next; 254 l_cnt = l_nflag = 0; 255 l_kval = current; 256 l_temp_line = current->above; 257 l_temp_line2 = current->below; 258 l_local_temp = l_local; 259 sigspecial++; 260 for (;;) { 261 /* 262 * Make the new string the one for this line. Check if 263 * it needs to be split. 264 */ 265 if (l_local[l_cnt] == '\n' || l_local[l_cnt] == '\0') { 266 if (l_local[l_cnt] == '\0') 267 l_nflag = 1; 268 l_local[l_cnt] = '\0'; 269 l_s_ret = malloc(sizeof(LINE)); 270 if (l_s_ret == NULL) { 271 *errnum = -1; 272 strcpy(help_msg, "out of memory error"); 273 return; 274 } 275 (l_s_ret->len) = strlen(l_local); 276 (l_s_ret->handle) = add_line(l_local, l_s_ret->len); 277 (l_s_ret->above) = l_temp_line; 278 (l_s_ret->below) = NULL; 279 if (l_temp_line == NULL) 280 top = l_s_ret; 281 else { 282 if ((current != Start) && 283 ((&(current->above)) == u_stk->cell)) 284 l_u_reuse_flag = 1; 285 else { 286 u_add_stk(&(l_temp_line->below)); 287 l_u_reuse_flag = 0; 288 } 289 (l_temp_line->below) = l_s_ret; 290 } 291 l_temp_line = l_s_ret; 292 if ((l_local[l_cnt] == '\0') && (l_nflag == 1)) 293 break; 294 else { 295 l_local = &(l_local[l_cnt + 1]); 296 l_cnt = 0; 297 } 298 } else 299 l_cnt++; 300 } 301 (l_s_ret->below) = l_temp_line2; 302 ku_chk(current, current, l_kval->below); 303 if (current == End) 304 End = l_s_ret; 305 current = l_s_ret; 306 l_last = current; 307 if (l_temp_line2 == NULL) 308 bottom = l_s_ret; 309 else { 310 if (l_u_reuse_flag) 311 u_pop_n_swap(&(l_temp_line2->above)); 312 else 313 u_add_stk(&(l_temp_line2->above)); 314 (l_temp_line2->above) = current; 315 } 316 sigspecial--; 317 if (sigint_flag && (!sigspecial)) 318 SIGINT_ACTION; 319 if (l_local_temp != text) 320 free(l_local_temp); 321 next: 322 current = current->below; 323 } while (current != (End->below)); 324 325 if (l_s_flag == 0) { 326 current = Start; 327 if (!g_flag) { 328 strcpy(help_msg, "no matches found for substitution"); 329 *errnum = -1; 330 ungetc('\n', inputt); 331 } 332 else 333 *errnum = 0; 334 return; 335 } 336 change_flag = 1; 337 current = l_last; 338 339 if (l_print > 0) { 340 Start = End = l_s_ret; /*current;*/ 341 ungetc(ss, inputt); 342 if (l_print == (l_print | (int) 1)) 343 p(inputt, errnum, 0); 344 if (l_print == (l_print | (int) 2)) 345 p(inputt, errnum, 1); 346 if (l_print == (l_print | (int) 4)) 347 l(inputt, errnum); 348 if (*errnum < 0) 349 return; 350 } 351 if (l_sr_flag == -1) { 352 regfree(&RE_comp); 353 regcomp(&RE_comp, &RE_patt[1], 0); 354 } 355 *errnum = 1; 356 } 357