/// A return value of true means all is well (even if no replacements were performed), false /// indicates an unrecoverable error. bool regex_replacer_t::replace_matches(const wchar_t *arg) { if (regex.code == 0) { // pcre2_compile() failed return false; } uint32_t options = PCRE2_SUBSTITUTE_OVERFLOW_LENGTH | PCRE2_SUBSTITUTE_EXTENDED | (opts.all ? PCRE2_SUBSTITUTE_GLOBAL : 0); size_t arglen = wcslen(arg); PCRE2_SIZE bufsize = (arglen == 0) ? 16 : 2 * arglen; wchar_t *output = (wchar_t *)malloc(sizeof(wchar_t) * bufsize); int pcre2_rc; bool done = false; while (!done) { if (output == NULL) { DIE_MEM(); } PCRE2_SIZE outlen = bufsize; pcre2_rc = pcre2_substitute(regex.code, PCRE2_SPTR(arg), arglen, 0, // start offset options, regex.match, 0, // match context PCRE2_SPTR(replacement.c_str()), PCRE2_ZERO_TERMINATED, (PCRE2_UCHAR *)output, &outlen); if (pcre2_rc != PCRE2_ERROR_NOMEMORY || bufsize >= outlen) { done = true; } else { bufsize = outlen; // cppcheck-suppress memleakOnRealloc output = (wchar_t *)realloc(output, sizeof(wchar_t) * bufsize); } } bool rc = true; if (pcre2_rc < 0) { string_error(streams, _(L"%ls: Regular expression substitute error: %ls\n"), argv0, pcre2_strerror(pcre2_rc).c_str()); rc = false; } else { if (!opts.quiet) { streams.out.append(output); streams.out.append(L'\n'); } total_replaced += pcre2_rc; } free(output); return rc; }
char *preg_replace(char *re, char *replacement, char *subject) { int rc; pcre2_code *compiled_re = get_compiled_re(re); PCRE2_SPTR pcre2_subject = (PCRE2_SPTR)subject; size_t subject_length = strlen((char *)subject); PCRE2_SPTR pcre2_replacement = (PCRE2_SPTR)replacement; size_t replacement_length = strlen((char *)replacement); PCRE2_UCHAR output[256]; size_t output_length = 256; rc = pcre2_substitute( compiled_re, pcre2_subject, subject_length, 0, PCRE2_SUBSTITUTE_GLOBAL, NULL, NULL, pcre2_replacement, replacement_length, output, &output_length ); if (rc < 0) { switch(rc) { case PCRE2_ERROR_NOMEMORY: printf("Output buffer not large enough\n"); break; case PCRE2_ERROR_BADREPLACEMENT: printf("Invalid replacement string %s\n", replacement); break; default: printf("Unknown error %d \n", rc); break; } exit(1); } return strndup((char *)output, output_length); }
tb_char_t const* tb_regex_replace(tb_regex_ref_t self, tb_char_t const* cstr, tb_size_t size, tb_size_t start, tb_char_t const* replace_cstr, tb_size_t replace_size, tb_size_t* plength) { // check tb_regex_t* regex = (tb_regex_t*)self; tb_assert_and_check_return_val(regex && regex->code && cstr && replace_cstr, tb_null); // done tb_char_t const* result = tb_null; do { // clear length first if (plength) *plength = 0; // end? tb_check_break(start < size); // init options #ifdef __tb_debug__ tb_uint32_t options = 0; #else tb_uint32_t options = PCRE2_NO_UTF_CHECK; #endif if (regex->mode & TB_REGEX_MODE_GLOBAL) options |= PCRE2_SUBSTITUTE_GLOBAL; // init buffer if (!regex->buffer_data) { regex->buffer_maxn = tb_max(size + replace_size + 64, 256); regex->buffer_data = (PCRE2_UCHAR*)tb_malloc_bytes(regex->buffer_maxn); } tb_assert_and_check_break(regex->buffer_data); // done tb_long_t ok = -1; PCRE2_SIZE length = 0; while (1) { // replace it length = (PCRE2_SIZE)regex->buffer_maxn; ok = pcre2_substitute(regex->code, (PCRE2_SPTR)cstr, (PCRE2_SIZE)size, (PCRE2_SIZE)start, options, tb_null, tb_null, (PCRE2_SPTR)replace_cstr, (PCRE2_SIZE)replace_size, regex->buffer_data, &length); // no space? if (ok == PCRE2_ERROR_NOMEMORY) { // grow buffer regex->buffer_maxn <<= 1; regex->buffer_data = (PCRE2_UCHAR*)tb_ralloc_bytes(regex->buffer_data, regex->buffer_maxn); tb_assert_and_check_break(regex->buffer_data); } // failed else if (ok < 0) { #if defined(__tb_debug__) && !defined(TB_CONFIG_OS_WINDOWS) // get error info PCRE2_UCHAR info[256]; pcre2_get_error_message(ok, info, sizeof(info)); // trace tb_trace_d("replace failed at offset %lu: error: %ld, %s\n", start, ok, info); #endif // end break; } else break; } // check tb_check_break(ok > 0); tb_assert_and_check_break(length < regex->buffer_maxn); // end regex->buffer_data[length] = '\0'; // trace tb_trace_d(" replace: [%lu]: %s", length, regex->buffer_data); // save length if (plength) *plength = (tb_size_t)length; // ok result = (tb_char_t const*)regex->buffer_data; } while (0); // ok? return result; }
bool replace_matches(const wchar_t *arg) { // A return value of true means all is well (even if no replacements // were performed), false indicates an unrecoverable error. if (regex.code == 0) { // pcre2_compile() failed return false; } uint32_t options = opts.all ? PCRE2_SUBSTITUTE_GLOBAL : 0; size_t arglen = wcslen(arg); PCRE2_SIZE bufsize = (arglen == 0) ? 16 : 2 * arglen; wchar_t *output = (wchar_t *)malloc(sizeof(wchar_t) * bufsize); if (output == 0) { DIE_MEM(); } int pcre2_rc = 0; for (;;) { PCRE2_SIZE outlen = bufsize; pcre2_rc = pcre2_substitute( regex.code, PCRE2_SPTR(arg), arglen, 0, // start offset options, regex.match, 0, // match context PCRE2_SPTR(replacement.c_str()), PCRE2_ZERO_TERMINATED, (PCRE2_UCHAR *)output, &outlen); if (pcre2_rc == PCRE2_ERROR_NOMEMORY) { if (bufsize < MAX_REPLACE_SIZE) { bufsize = std::min(2 * bufsize, MAX_REPLACE_SIZE); output = (wchar_t *)realloc(output, sizeof(wchar_t) * bufsize); if (output == 0) { DIE_MEM(); } continue; } string_error(streams, _(L"%ls: Replacement string too large\n"), argv0); free(output); return false; } break; } bool rc = true; if (pcre2_rc < 0) { string_error(streams, _(L"%ls: Regular expression substitute error: %ls\n"), argv0, pcre2_strerror(pcre2_rc).c_str()); rc = false; } else { if (!opts.quiet) { streams.out.append(output); streams.out.append(L'\n'); } total_replaced += pcre2_rc; } free(output); return rc; }