/*- * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Rodney Ruddock of the University of Guelph. * * %sccs.include.redist.c% */ #ifndef lint static char sccsid[] = "@(#)sub.c 5.4 (Berkeley) 03/08/93"; #endif /* not lint */ #include #include #include #include #include #include #ifdef DBI #include #endif #include "ed.h" #include "extern.h" /* * The substitute command. It's big because of the backward compatability. */ void s(inputt, errnum) FILE *inputt; int *errnum; { static int l_count2 = 1, l_global = 0, l_print = 0; static int l_first_pass_flag = 0; static char *l_match = NULL, *l_repl = NULL; LINE *l_s_ret, *l_temp_line, *l_temp_line2, *l_kval, *l_last; int l_s_flag, l_count, l_matched, l_nflag, l_cnt, yy, l_sr_flag = 0; int l_err, l_sl; char *l_match2 = NULL, *l_local = NULL, *l_local_temp = NULL; #ifndef REG_STARTEND size_t l_offset = 0; #endif if (Start_default && End_default) Start = End = current; else if (Start_default) Start = End; if (Start == NULL) { *errnum = -1; return; } Start_default = End_default = 0; l_sl = ss = getc(inputt); if (l_first_pass_flag == 0) l_match = l_repl = NULL; l_match2 = get_pattern(l_sl, inputt, errnum, 0); if (*errnum < 0) { if ((*errnum == -2) && (l_sl != '\n')) return; if ((l_match2 == NULL) || (strlen(l_match2) > 4) || (l_first_pass_flag == 0)) return; *errnum = 0; l_sr_flag = -1; for (yy = 0; yy < (strlen(l_match2)); yy++) { switch (l_match2[yy]) { case '\n': ss = getc(inputt); goto bcg1; break; case 'r': l_sr_flag = 1; break; case 'p': l_print = (l_print) ? 0 : 1; break; case 'g': l_global = (l_global) ? 0 : 1; break; case 'N': l_count2 = 1; break; default: *errnum = -1; strcpy(help_msg, "illegal modifier to s"); return; } } ss = getc(inputt); if (l_sr_flag == 1) goto bcg2; else goto bcg1; } if (l_first_pass_flag) { free(l_match); free(l_repl); } else l_first_pass_flag = 1; l_match = l_match2; *errnum = 0; l_repl = get_pattern(ss, inputt, errnum, 1); if (sigint_flag && (!sigspecial)) SIGINT_ACTION; l_global = l_print = 0; if (*errnum < 0) if ((*errnum == -1) && (ss == '\n')) /* Note, \n still in stream for next getc. */ l_print = 1; else return; *errnum = 0; l_count2 = 1; while (((ss = getc(inputt)) != '\n') && (ss != EOF)) if (ss == 'g') l_global = 1; else switch (ss) { case 'p': l_print = (l_print | (int) 1); break; case 'n': l_print = (l_print | (int) 2); break; case 'l': l_print = (l_print | (int) 4); break; default: if ((ss > ('0' - 1)) && (ss < ('9' + 1))) l_count2 = dig_num_conv(inputt, errnum); else { *errnum = -1; strcpy(help_msg, "illegal command option"); return; } } bcg1: if ((RE_flag == 0) && (l_match[1] == '\0')) { *errnum = -1; ungetc(ss, inputt); return; } else if ((l_sr_flag == 0) && (l_match[1] || (RE_patt == NULL))) { int l_m_len = 2 + strlen(l_match); sigspecial++; free(RE_patt); RE_patt = malloc(sizeof(char) * (l_m_len)); bcopy(l_match, RE_patt, l_m_len); sigspecial--; if (sigint_flag && (!sigspecial)) SIGINT_ACTION; } RE_sol = (l_match[1] == '^') ? 1 : 0; if ((l_match[1]) && (regfree(&RE_comp), l_err = regcomp(&RE_comp, &l_match[1], 0))) { regerror(l_err, &RE_comp, help_msg, 128); *errnum = -1; RE_flag = 0; ungetc(ss, inputt); return; } RE_flag = 1; if (sigint_flag && (!sigspecial)) SIGINT_ACTION; bcg2: current = Start; l_s_flag = 0; do { RE_match[0].rm_eo = 0; get_line(current->handle, current->len); if (sigint_flag && (!sigspecial)) SIGINT_ACTION; l_count = l_count2; l_local = text; #ifndef REG_STARTEND l_offset = 0; #endif do { RE_match[0].rm_so = RE_match[0].rm_eo; #ifdef REG_STARTEND l_matched = regexec_n(&RE_comp, l_local, (size_t)RE_SEC, RE_match, 0, l_count, (size_t)current->len, 0); #else l_matched = regexec_n(&RE_comp, l_local, (size_t)RE_SEC, RE_match, 0, l_count, &l_offset, 0); #endif if (l_matched == 0) { if ((l_s_flag == 0) && (g_flag == 0)) u_clr_stk(); l_count = l_s_flag = 1; /* * The l_local passed into re_replace is not * freed in re_replace because it is "text", * the global line holder, for the first pass * through this loop. The value returned by * re_replace is a new string (with the first * replacement in it). If the 'g' flag was * set with substitute then this new string * is passed in for the second pass and can * be freed once re_replace is done with it. * (...and so on for the rest of the 'g' * passes. RE_match[0].rm_eo is changed in * re_replace to be the new location of the * next character immediately after the * replacement since it is likely the * position of that character has changed * because of the replacement. */ #ifdef REG_STARTEND l_local = re_replace(l_local, (size_t)(RE_SEC - 1), RE_match, &l_repl[1]); #else l_local = re_replace(l_local, (size_t)(RE_SEC - 1), RE_match, &l_repl[1], l_offset); #endif } if (l_global == 0) break; if (l_local[RE_match[0].rm_eo] == '\0') break; } while (!l_matched); l_cnt = l_nflag = 0; l_kval = current; l_temp_line = current->above; l_temp_line2 = current->below; l_local_temp = l_local; sigspecial++; for (;;) { /* * Make the new string the one for this line. Check if * it needs to be split. */ if (l_local[l_cnt] == '\n' || l_local[l_cnt] == '\0') { if (l_local[l_cnt] == '\0') l_nflag = 1; l_local[l_cnt] = '\0'; l_s_ret = malloc(sizeof(LINE)); if (l_s_ret == NULL) { *errnum = -1; strcpy(help_msg, "out of memory error"); return; } (l_s_ret->len) = strlen(l_local); (l_s_ret->handle) = add_line(l_local, l_s_ret->len); (l_s_ret->above) = l_temp_line; (l_s_ret->below) = NULL; if (l_temp_line == NULL) top = l_s_ret; else { u_add_stk(&(l_temp_line->below)); (l_temp_line->below) = l_s_ret; } l_temp_line = l_s_ret; if ((l_local[l_cnt] == '\0') && (l_nflag == 1)) break; else { l_local = &(l_local[l_cnt + 1]); l_cnt = 0; } } else l_cnt++; } (l_s_ret->below) = l_temp_line2; ku_chk(current, current, l_kval->below); if (current == End) End = l_s_ret; current = l_s_ret; l_last = current; if (l_temp_line2 == NULL) bottom = l_s_ret; else { u_add_stk(&(l_temp_line2->above)); (l_temp_line2->above) = current; } sigspecial--; if (sigint_flag && (!sigspecial)) SIGINT_ACTION; if (l_local_temp != text) free(l_local_temp); current = current->below; } while (current != (End->below)); if (l_s_flag == 0) { current = Start; strcpy(help_msg, "no matches found for substitution"); *errnum = -1; ungetc('\n', inputt); return; } change_flag = 1; current = l_last; if (l_print > 0) { Start = End = current; ungetc(ss, inputt); if (l_print == (l_print | (int) 1)) p(inputt, errnum, 0); if (l_print == (l_print | (int) 2)) p(inputt, errnum, 1); if (l_print == (l_print | (int) 4)) l(inputt, errnum); if (*errnum < 0) return; } if (l_sr_flag == -1) { regfree(&RE_comp); regcomp(&RE_comp, &RE_patt[1], 0); } *errnum = 1; }