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[] = "@(#)re.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 * This finds the n-th occurrence of an RE in a line. If '^' was at the start 29 * of the RE then look once (in case n=1). There is no standard RE interface 30 * to do this. Returns 0 for success. NOTE: the #ifdef REG_STARTEND is if 31 * the regex package has the BSD extensions to it. 32 */ 33 int 34 #ifdef REG_STARTEND 35 regexec_n(reprecomp, strg, num_subexp, reprematch, flags, n, len, pass) 36 #else 37 regexec_n(reprecomp, strg, num_subexp, reprematch, flags, n, offset, pass) 38 #endif 39 regex_t *reprecomp; 40 char *strg; 41 size_t num_subexp; 42 regmatch_t reprematch[]; 43 int flags, n; 44 #ifdef REG_STARTEND 45 size_t len; 46 #else 47 size_t *offset; 48 #endif 49 int pass; /* if pass == 0 .rm_so user set, else set default */ 50 { 51 int l_cnt; 52 #ifndef REG_STARTEND 53 char *l_offset = strg; 54 #endif 55 56 if (n <= 0) 57 return (REG_NOMATCH); 58 #ifdef REG_STARTEND 59 flags = (flags | REG_STARTEND); 60 if (pass) 61 reprematch[0].rm_so = 0; 62 reprematch[0].rm_eo = len; 63 #else 64 strg = &strg[offset]; 65 #endif 66 for (l_cnt = 0;;) { 67 if (regexec(reprecomp, 68 strg, num_subexp, reprematch, flags) == 0) 69 l_cnt++; 70 else 71 return (REG_NOMATCH); 72 if (l_cnt >= n) 73 break; 74 #ifdef REG_STARTEND 75 reprematch[0].rm_so = reprematch[0].rm_eo; 76 reprematch[0].rm_eo = len; 77 #else 78 strg = &strg[reprematch[0].rm_eo]; 79 #endif 80 /* if a "^" started the current RE we only loop once */ 81 if (RE_sol) 82 return (REG_NOMATCH); 83 } 84 #ifndef REG_STARTEND 85 *offset = (size_t) (strg - l_offset); 86 #endif 87 return (0); /* success */ 88 } 89 90 /* 91 * Replace in the line specified at the found locations with the 92 * specified replacement. There is no standard RE interface to do 93 * this. 94 */ 95 char * 96 #ifdef REG_STARTEND 97 re_replace(line, num_subexp, repmatch, replacer) 98 #else 99 re_replace(line, num_subexp, repmatch, replacer, offset) 100 #endif 101 char *line; 102 size_t num_subexp; 103 regmatch_t repmatch[]; 104 char *replacer; 105 #ifndef REG_STARTEND 106 size_t offset; 107 #endif 108 { 109 static char *l_prev_r = NULL; 110 static int l_prev_r_flag = 0; 111 regoff_t l_len_before, l_len_whole, l_slen[RE_SEC]; 112 int l_cnt, l_len_new = 0, l_new_rm_eo = 0; 113 char *l_string, *l_head; 114 115 if (l_prev_r_flag == 0) { 116 l_prev_r_flag = 1; 117 l_prev_r = NULL; 118 } 119 l_head = replacer; 120 /* Length of what stays the same before. */ 121 l_len_before = (repmatch[0].rm_so); 122 l_len_whole = strlen(line); 123 if (num_subexp > RE_SEC - 1) 124 num_subexp = RE_SEC - 1; 125 for (l_cnt = 0; l_cnt <= num_subexp; l_cnt++) 126 l_slen[l_cnt] = 127 (repmatch[l_cnt].rm_eo) - (repmatch[l_cnt].rm_so); 128 129 /* 130 * l_slen[0] == len of what is to be replaced. 131 * l_slen[1-9] == len of each backref. 132 */ 133 if ((*replacer == '%') && (replacer[1] == 1)) { 134 l_string = calloc(l_len_whole - l_slen[0] + 135 (strlen(l_prev_r)) + 2, sizeof(char)); 136 if (l_string == NULL) { 137 /* *errnum = -1; */ 138 strcpy(help_msg, "out of memory error"); 139 return (NULL); 140 } 141 #ifdef REG_STARTEND 142 bcopy(line, l_string, (int) l_len_before); 143 #else 144 bcopy(line, l_string, (int) l_len_before + offset); 145 #endif 146 #ifdef REG_STARTEND 147 l_string[l_len_before] = '\0'; 148 #else 149 l_string[l_len_before + offset] = '\0'; 150 #endif 151 strcat(l_string, l_prev_r); 152 #ifdef REG_STARTEND 153 strcat(l_string, &line[repmatch[0].rm_eo]); 154 #else 155 strcat(l_string, &line[repmatch[0].rm_eo + offset]); 156 #endif 157 return (l_string); 158 } 159 160 /* Figure out length of new line first. */ 161 while (*replacer != '\0') { 162 /* Add in the length of the RE match. */ 163 if (*replacer == '&') 164 l_len_new = l_len_new + l_slen[0]; 165 /* Add in the length of a backref. */ 166 else if (*replacer == '\\') { 167 replacer++; 168 if ((*replacer > '0') && 169 (*replacer < ('9' + 1)) && 170 (repmatch[*replacer - '0'].rm_so > -1)) 171 /* -1 - -1 = 0 */ 172 l_len_new = l_len_new + l_slen[*replacer - '0']; 173 else 174 l_len_new++; 175 } else 176 l_len_new++; 177 replacer++; 178 } 179 180 /* Create the line of an appropriate length. */ 181 l_string = 182 calloc(l_len_whole - l_slen[0] + l_len_new + 2, sizeof(char)); 183 if (l_string == NULL) { 184 strcpy(help_msg, "out of memory error"); 185 return (NULL); 186 } 187 if (l_prev_r != NULL) 188 free(l_prev_r); 189 l_prev_r = calloc(l_len_new + 2, sizeof(char)); 190 if (l_prev_r == NULL) { 191 strcpy(help_msg, "out of memory error"); 192 return (NULL); 193 } 194 /* Copy over what doesn't change before the chars to be replaced. */ 195 #ifdef REG_STARTEND 196 bcopy(line, l_string, (int) l_len_before); 197 #else 198 bcopy(line, l_string, l_len_before + offset); 199 #endif 200 #ifdef REG_STARTEND 201 l_string[l_len_before] = '\0'; 202 #else 203 l_string[l_len_before + offset] = '\0'; 204 #endif 205 l_prev_r[0] = '\0'; 206 207 /* Make the replacement. */ 208 replacer = l_head; 209 while (*replacer != '\0') { 210 /* Put what matched the RE into the replacement. */ 211 if (*replacer == '&') { 212 #ifdef REG_STARTEND 213 strncat(l_string, 214 &line[repmatch[0].rm_so], (int)l_slen[0]); 215 strncat(l_prev_r, 216 &line[repmatch[0].rm_so], (int) l_slen[0]); 217 #else 218 strncat(l_string, 219 &line[repmatch[0].rm_so + offset], (int) l_slen[0]); 220 strncat(l_prev_r, 221 &line[repmatch[0].rm_so + offset], (int) l_slen[0]); 222 #endif 223 } else if (*replacer == '\\') { 224 /* Likely a backref to be included. */ 225 replacer++; 226 if ((*replacer > '0') && (*replacer < ('9' + 1)) && 227 (repmatch[*replacer - '0'].rm_so > -1)) { 228 #ifdef REG_STARTEND 229 strncat(l_string, 230 &line[repmatch[*replacer - '0'].rm_so], 231 (int) l_slen[*replacer - '0']); 232 strncat(l_prev_r, 233 &line[repmatch[*replacer - '0'].rm_so], 234 (int) l_slen[*replacer - '0']); 235 #else 236 strncat(l_string, 237 &line[repmatch[*replacer - '0'].rm_so + 238 offset], (int) l_slen[*replacer - '0']); 239 strncat(l_prev_r, 240 &line[repmatch[*replacer - '0'].rm_so + 241 offset], (int) l_slen[*replacer - '0']); 242 #endif 243 } 244 /* Put the replacement in. */ 245 else { 246 strncat(l_string, replacer, 1); 247 strncat(l_prev_r, replacer, 1); 248 } 249 } 250 /* Put the replacement in. */ 251 else { 252 strncat(l_string, replacer, 1); 253 strncat(l_prev_r, replacer, 1); 254 } 255 replacer++; 256 } 257 258 l_new_rm_eo = strlen(l_string); 259 260 /* Copy over what was after the chars to be replaced to the new line. */ 261 #ifdef REG_STARTEND 262 strcat(l_string, &line[repmatch[0].rm_eo]); 263 #else 264 strcat(l_string, &line[repmatch[0].rm_eo + offset]); 265 #endif 266 267 repmatch[0].rm_eo = l_new_rm_eo; /* Update rm_eo. */ 268 #ifndef REG_STARTEND 269 offset += l_new_rm_eo; /* Update offset. */ 270 #endif 271 return (l_string); /* Return the new line. */ 272 } 273