--- item-ext.c.~1.1~ Tue Jul 10 11:33:09 2001 +++ item-ext.c Mon Jul 9 15:11:42 2001 @@ -1317,12 +1317,12 @@ char *search, *replace; { int i,did; - char *sp, *start = NULL; + char *sp, *origin, *start = NULL; struct Item *ip; struct Item *oldCurrentLinePtr; regex_t rx,rxcache; - regmatch_t match,matchcheck; - size_t nmatch = 1; + regmatch_t *match,matchcheck; + size_t nmatch; EditVerbose("Checking for replace/%s/%s\n",search,replace); @@ -1331,6 +1331,13 @@ return false; } +/* Get the number of parenthesised subexpressions + (the first one is for the full match): */ + nmatch = rxcache.re_nsub; + /* And allocate room to store information on them: */ + match = (regmatch_t *) calloc(sizeof(regmatch_t), nmatch); + Debug("%d subexpressions found.\n",nmatch); + for (ip = *liststart; ip != NULL; ip=ip->next) { if (ip->name == NULL) @@ -1340,44 +1347,97 @@ bcopy(&rxcache,&rx,sizeof(rx)); /* To fix a bug on some implementations where rx gets emptied */ - if (regexec(&rx,ip->name,1,&match,0) == 0) + /* Point to the string we match in: */ + origin = ip->name; + /* Match the regex in the current line: */ + if (regexec(&rx,ip->name,nmatch,match,0) == 0) { - start = ip->name + match.rm_so; + Debug("Regex \"%s\" found in line \"%s\"\n", search, ip->name); + start = ip->name + match[0].rm_so; } else { + /* Regex not found. */ continue; } bzero(VBUFF,bufsize); i = 0; - + /* Replace the matching elements in the target: */ for (sp = ip->name; *sp != '\0'; sp++) { if (sp != start) { - VBUFF[i] = *sp; + /* Copy verbatim the source to the target: */ + VBUFF[i++] = *sp; } - else - { - sp += match.rm_eo - match.rm_so - 1; - VBUFF[i] = '\0'; - strcat(VBUFF,replace); - i += strlen(replace)-1; + else { + int j; + /* Skip the pattern size in the source:*/ + sp += match[0].rm_eo - match[0].rm_so - 1; + /* replace the pattern with '\D' and '\\' interpretation: */ + for (j = 0; replace[j] != '\0'; j++) { + if (replace[j] == '\\') { + /* Look up for next character: */ + if (replace[j+1] == '\\') { + /* Well, a double backslash is indeed a backslash: */ + VBUFF[i++] = '\\'; + /* Skip the second backslash too: */ + j++; + } + else if (replace[j+1] >= '0' && replace[j+1] <= '9') { + /* Ask for replacing with a numbered matching subexpression: */ + int subexp = replace[j+1] - '0'; + /* Skip the number too: */ + j++; + if (subexp >= nmatch) { + snprintf(OUTPUT, + bufsize*2, + "WARNING: impossible to access subexpression \"%d\" because only %d are defined !", + subexp, + nmatch); + CfLog(cferror, OUTPUT, ""); + snprintf(OUTPUT, bufsize*2, "Line begins [%.40s]", ip->name); + CfLog(cferror, OUTPUT, ""); + CfLog(cferror, "Edit was not done",""); + return false; + } + VBUFF[i] = '\0'; + /* Insert in the target the subexpression: */ + Debug("Regex %d at %d, %d\n", + subexp, + match[subexp].rm_so, + match[subexp].rm_eo); + strncat(VBUFF, + origin + match[subexp].rm_so, + match[subexp].rm_eo - match[subexp].rm_so); + i += match[subexp].rm_eo - match[subexp].rm_so; + } + else + /* Just understand the '\\' as a plain character + and copy it: */ + VBUFF[i++] = replace[j]; + } + else + /* A plain character: just copy it: */ + VBUFF[i++] = replace[j]; + } + /* Look for other matches on the same line if any: */ bcopy(&rxcache,&rx,sizeof(rx)); /* To fix a bug on some implementations where rx gets emptied */ - if (regexec(&rx,sp,1,&match,0) == 0) + /* Point to the string we match in: */ + origin = sp; + if (regexec(&rx,sp,nmatch,match,0) == 0) { - start = sp + match.rm_so; + start = sp + match[0].rm_so; } else { - start = 0; + /* Resume to the end the verbatim copy. */ + start = NULL; } } - - i++; } Debug("Replace:\n (%s)\nwith (%s)\n",ip->name,VBUFF); @@ -1399,6 +1459,7 @@ ip = oldCurrentLinePtr; } + free((void *) match); regfree(&rx); return true; }