regex - Search and replace within a file using PCRE in C -
i want parse shell style key-value config file c , replace values needed. example file like
foo="test" some_key="some value here" another_key="here.we.go" something="0" foo_bar_baz="2"
to find value, want use regular expressions. i'm beginner pcre library created code test around. application takes 2 arguments: first 1 key search for. second 1 value fill double quotes.
#include <pcre.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #define oveccount 30 int main(int argc, char **argv){ const char *error; int erroffset; pcre *re; int rc; int i; int ovector[oveccount]; char regex[64]; sprintf(regex,"(?<=^%s=\\\").+(?<!\\\")", argv[1]); char *str; file *conf; conf = fopen("test.conf", "rw"); fseek(conf, 0, seek_end); int confsize = ftell(conf)+1; rewind(conf); str = malloc(confsize); fread(str, 1, confsize, conf); fclose(conf); str[confsize-1] = '\n'; re = pcre_compile ( regex, /* pattern */ pcre_caseless | pcre_multiline, /* default options */ &error, /* error message */ &erroffset, /* error offset */ 0); /* use default character tables */ if (!re) { printf("pcre_compile failed (offset: %d), %s\n", erroffset, error); return -1; } rc = pcre_exec ( re, /* compiled pattern */ 0, /* no data - pattern not studied */ str, /* string match */ confsize, /* length of string */ 0, /* start @ offset 0 in subject */ 0, /* default options */ ovector, /* output vector substring information */ oveccount); /* number of elements in output vector */ if (rc < 0) { switch (rc) { case pcre_error_nomatch: printf("string didn't match"); break; default: printf("error while matching: %d\n", rc); break; } free(re); return -1; } (i = 0; < rc; i++) { printf("========\nlength of vector: %d\nvector[0..1]: %d %d\nchars @ start/end: %c %c\n", ovector[2*i+1] - ovector[2*i], ovector[0], ovector[1], str[ovector[0]], str[ovector[1]]); printf("file content length %d\n========\n", strlen(str)); } int newcontentlen = strlen(argv[2])+1; char *newcontent = calloc(newcontentlen,1); memcpy(newcontent, argv[2], newcontentlen); char *before = malloc(ovector[0]); memcpy(before, str, ovector[0]); int afterlen = confsize-ovector[1]; char *after = malloc(afterlen); memcpy(after, str+ovector[1],afterlen); int newfilelen = newcontentlen+ovector[0]+afterlen; char *newfile = calloc(newfilelen,1); sprintf(newfile,"%s%s%s", before,newcontent, after); printf("%s\n", newfile); return 0; }
this code working in cases if want replace foo
or another_key
theres fishy.
$ ./search_replace.out foo baz ======== length of vector: 5 vector[0..1]: 5 10 chars @ start/end: b " file content length 94 ======== foo="9@baz" some_key="some value here" another_key="here.we.go" something="0" foo_bar_baz="2" $ ./search_replace.out another_key insert ======== length of vector: 10 vector[0..1]: 52 62 chars @ start/end: h " file content length 94 ======== foo="baaar" some_key="some value here" another_key=")insert" something="0" foo_bar_baz="2"
now if change format of input file to
test="new inserted" foo="test" some_key="some value here" another_key="here.we.go" something="0" foo_bar_baz="2"
the code working fine. don't why code behaves differently here.
the characters before substituted text come not null-terminating before
string. (just hadn't null-terminated whole buffer str
, paul r has pointed out.) so:
char *before = malloc(ovector[0] + 1); memcpy(before, str, ovector[0]); before[ovector[0]] = '\0';
anyway, business of allocating substrings , copying contents seems needlessly complicated , prone errors. example, somethinglen
variables count terminating null character or not? do, don't. i'd recommend pick 1 representation , use consistently. (and should free
allocated buffers after no longer using them , clean compiled regex.)
you replacement 1 allocation target buffer using precision field of %s
format specifier on "before" part:
int cutlen = ovector[1] - ovector[0]; int newfilelen = confsize + strlen(argv[2]) - cutlen; char *newfile = malloc(newfilelen + 1); snprintf(newfile, newfilelen + 1, "%.*s%s%s", ovector[0], str, argv[2], str + ovector[1]);
or use fprintf
ther target file if don't need temporary buffer.
Comments
Post a Comment