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