Task: XXXX redacted
C: #include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>

typedef enum {
    whole_word = 1,
    overkill = 2,
    case_insensitive = 4
} redact_options;

bool is_word_char(char ch) {
    return ch == '-' || isalpha((unsigned char)ch);
}


void redact(char* text, const char* target, redact_options options) {
    size_t target_length = strlen(target);
    if (target_length == 0)
        return;
    char* start = text;
    char* end = text + strlen(text);
    while (start < end) {
        
        
        char* str = (options & case_insensitive) ? strcasestr(start, target)
                        : strstr(start, target);
        if (str == NULL)
            break;
        char* word_start = str;
        char* word_end = str + target_length;
        if (options & (overkill | whole_word)) {
            while (word_start > start && is_word_char(*(word_start - 1)))
                --word_start;
            while (word_end < end && is_word_char(*word_end))
                ++word_end;
        }
        if (!(options & whole_word) ||
            (word_start == str && word_end == str + target_length))
            memset(word_start, 'X', word_end - word_start);
        start = word_end;
    }
}

void do_basic_test(const char* target, redact_options options) {
    char text[] = "Tom? Toms bottom tomato is in his stomach while playing the "
        "\"Tom-tom\" brand tom-toms. That's so tom.";
    redact(text, target, options);
    printf("[%c|%c|%c]: %s\n", (options & whole_word) ? 'w' : 'p',
           (options & case_insensitive) ? 'i' : 's',
           (options & overkill) ? 'o' : 'n', text);
}

void do_basic_tests(const char* target) {
    printf("Redact '%s':\n", target);
    do_basic_test(target, whole_word);
    do_basic_test(target, whole_word | case_insensitive);
    do_basic_test(target, 0);
    do_basic_test(target, case_insensitive);
    do_basic_test(target, overkill);
    do_basic_test(target, case_insensitive | overkill);
}

int main() {
    do_basic_tests("Tom");
    printf("\n");
    do_basic_tests("tom");
    return 0;
}

C#: #include <iostream>

using namespace std;

string redact(const string &source, const string &word, bool partial, bool insensitive, bool overkill) {
    string temp = source;

    auto different = [insensitive](char s, char w) {
        if (insensitive) {
            return toupper(s) != toupper(w);
        } else {
            return s != w;
        }
    };

    auto isWordChar = [](char c) {
        return c == '-' || isalpha(c);
    };

    for (size_t i = 0; i < temp.length() - word.length() + 1; i++) {
        bool match = true;
        for (size_t j = 0; j < word.length(); j++) {
            if (different(temp[i + j], word[j])) {
                match = false;
                break;
            }
        }
        if (match) {
            auto beg = i;
            auto end = i + word.length();

            if (!partial) {
                if (beg > 0 && isWordChar(temp[beg - 1])) {
                    continue;
                }
                if (end < temp.length() && isWordChar(temp[end])) {
                    continue;
                }
            }
            if (overkill) {
                while (beg > 0 && isWordChar(temp[beg - 1])) {
                    beg--;
                }
                while (end < temp.length() && isWordChar(temp[end])) {
                    end++;
                }
            }

            for (size_t k = beg; k < end; k++) {
                temp[k] = 'X';
            }
        }
    }

    return temp;
}

void example(const string &source, const string &word) {
    std::cout << "Redact " << word << '\n';
    std::cout << "[w|s|n] " << redact(source, word, false, false, false) << '\n';
    std::cout << "[w|i|n] " << redact(source, word, false, true, false) << '\n';
    std::cout << "[p|s|n] " << redact(source, word, true, false, false) << '\n';
    std::cout << "[p|i|n] " << redact(source, word, true, true, false) << '\n';
    std::cout << "[p|s|o] " << redact(source, word, true, false, true) << '\n';
    std::cout << "[p|i|o] " << redact(source, word, true, true, true) << '\n';
    std::cout << '\n';
}

int main() {
    string text = "Tom? Toms bottom tomato is in his stomach while playing the \"Tom-tom\" brand tom-toms. That's so tom";
    example(text, "Tom");
    example(text, "tom");
    return 0;
}