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