/* Forms new line with highlights of matcher of the re regular expression using * escape sequences that invert colors. Returns NULL when no match found or * memory allocation error occured. */ static char * add_pattern_highlights(const char line[], size_t len, const char no_esc[], const int offsets[], const regex_t *re) { regmatch_t match; char *next = NULL; char *processed; int shift = 0; int overhead = 0; if(regexec(re, no_esc, 1, &match, 0) != 0) { return NULL; } if((processed = malloc(len + 1)) == NULL) { return NULL; } /* Before the first match. */ strncpy(processed, line, offsets[match.rm_so]); next = processed + offsets[match.rm_so]; /* All matches. */ do { size_t match_len; size_t new_overhead; int so_offset; void *ptr; const int empty_match = (match.rm_so == match.rm_eo); match.rm_so += shift; match.rm_eo += shift; so_offset = offsets[match.rm_so]; if(empty_match) { if(no_esc[match.rm_eo] == '\0') { shift = match.rm_eo; break; } } /* Between matches. */ if(shift != 0) { const int corrected = correct_offset(line, offsets, shift); strncpy(next, line + corrected, so_offset - corrected); } if(empty_match) { const int corrected = (shift == 0) ? (size_t)(next - processed) : correct_offset(line, offsets, shift); const int len = offsets[match.rm_so + 1] - corrected; strncpy(next, line + corrected, len); next += len; ++shift; } else { new_overhead = INV_OVERHEAD*count_substr_chars(no_esc, &match); len += new_overhead; if((ptr = realloc(processed, len + 1)) == NULL) { free(processed); return NULL; } processed = ptr; match_len = correct_offset(line, offsets, match.rm_eo) - so_offset; next = processed + so_offset + overhead; next = add_highlighted_substr(line + so_offset, match_len, next); shift = match.rm_eo; overhead += new_overhead; } } while(regexec(re, no_esc + shift, 1, &match, 0) == 0); /* Abort if there were no non-empty matches. */ if(next == NULL) { free(processed); return 0; } /* After the last match. */ strcpy(next, line + (shift == 0 ? 0 : correct_offset(line, offsets, shift))); return processed; }
/* Forms new line with highlights of matcher of the re regular expression using * escape sequences that invert colors. Returns NULL when no match found or * memory allocation error occurred. */ static char * add_pattern_highlights(const char line[], size_t len, const char no_esc[], const int offsets[], const regex_t *re) { /* XXX: this might benefit from a rewrite, logic of when escape sequences are * copied is unclear (sometimes along with first matched character, * sometimes before the match). */ regmatch_t match; char *next; char *processed; int no_esc_pos = 0; int overhead = 0; int offset; if(regexec(re, no_esc, 1, &match, 0) != 0) { return NULL; } if((processed = malloc(len + 1)) == NULL) { return NULL; } /* Before the first match. */ if(match.rm_so != 0 && no_esc[match.rm_so] == '\0') { /* This is needed to handle possibility of immediate break from the loop * below. */ offset = correct_offset(line, offsets, match.rm_so); } else { offset = offsets[match.rm_so]; } strncpy(processed, line, offset); next = processed + offset; /* All matches. */ do { int so_offset; void *ptr; const int empty_match = (match.rm_so == match.rm_eo); match.rm_so += no_esc_pos; match.rm_eo += no_esc_pos; so_offset = offsets[match.rm_so]; if(empty_match) { if(no_esc[match.rm_eo] == '\0') { no_esc_pos = match.rm_eo; break; } } /* Between matches. */ if(no_esc_pos != 0) { const int corrected = correct_offset(line, offsets, no_esc_pos); strncpy(next, line + corrected, so_offset - corrected); } if(empty_match) { /* Copy single character after the match to advance forward. */ /* Position inside the line string. */ const int esc_pos = (no_esc_pos == 0) ? (size_t)(next - processed) : correct_offset(line, offsets, no_esc_pos); /* Number of characters to copy from the line string. */ const int len = (match.rm_so == 0) ? utf8_chrw(no_esc) : correct_offset(line, offsets, match.rm_so + 1) - esc_pos; strncpy(next, line + esc_pos, len); next += len; no_esc_pos += utf8_chrw(&no_esc[no_esc_pos]); } else { size_t new_overhead; size_t match_len; new_overhead = INV_OVERHEAD*count_substr_chars(no_esc, &match); len += new_overhead; if((ptr = realloc(processed, len + 1)) == NULL) { free(processed); return NULL; } processed = ptr; match_len = correct_offset(line, offsets, match.rm_eo) - so_offset; next = processed + so_offset + overhead; next = add_highlighted_substr(line + so_offset, match_len, next); no_esc_pos = match.rm_eo; overhead += new_overhead; } } while(regexec(re, no_esc + no_esc_pos, 1, &match, 0) == 0); /* Abort if there were no non-empty matches. */ if(overhead == 0) { free(processed); return 0; } /* After the last match. */ strcpy(next, line + (no_esc_pos == 0 ? (size_t)(next - processed) : correct_offset(line, offsets, no_esc_pos))); return processed; }