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