C言語でWordPressのフィルターフックを真似する

232, 2019-10-24

PHPのWordPress(WP)にはフィルターフックなるものがあります。
ユーザー定義のフィルター用の関数を登録しておくと、WP側でそのフィルターを適用してから出力してくれます。
Cで真似してみました。

関数ポインタ配列の管理。
DisplayFilterはフィルター用関数のインターフェース。

/* My display filter */

#include <stdio.h>
#include <string.h>
#include <ctype.h>

typedef char* (*DisplayFilter)(char*, size_t, char const*);

enum { NFILTERS = 10, };
static size_t filters_length;
static DisplayFilter filters[NFILTERS];

void
my_display_filters_push_back(DisplayFilter filter) {
    if (filters_length >= NFILTERS) {
        return;
    }
    filters[filters_length++] = filter;
}

size_t
my_display_filters_length(void) {
    return filters_length;
}

DisplayFilter
my_display_filters_get(size_t index) {
    if (index < filters_length) {
        return filters[index];
    }
    return NULL;
}

出力用。
ユーザ定義のフィルター群を適用してから出力。

/* My display */

#include <stdio.h>
#include <string.h>

enum { NDST = 256, };

void
my_display(char const* src, FILE* stream) {
    // Filter?
    if (my_display_filters_length() == 0) {
        // Display
        fprintf(stream, "[%s]\n", src);
    } else {
        // Filtering
        char dst1[NDST];
        char dst2[NDST];
        char* a = dst1;
        char const* b = src;

        for (int i = 0, len = my_display_filters_length(); i < len; ++i) {
            DisplayFilter filter = my_display_filters_get(i);
            filter(a, NDST, b);

            // ユーザーの為にコピー領域が重なっていないことを保証する。
            b = a;
            a = (a == dst1 ? dst2 : dst1);
        }
        a = (a == dst1 ? dst2 : dst1);

        // Display
        fprintf(stream, "[%s]\n", a);
    }
}

ここからユーザー定義のフィルターとテスト内容。
コピーのみ、英文字を大文字に変換、改行とタブをエスケープするフィルターを定義して登録。

/* My test */

#include <stdio.h>

// User's filter
static char*
test_display_filter_toupper(char* dst, size_t dstsize, char const* src) {
    char* dstcur = dst;
    char* dstend = dst + dstsize - 1;

    for (; dstcur < dstend && *src; ++dstcur, ++src) {
        if (*src == '\\') {
            *dstcur = *src;
            if (*++src == '\0') {
                break;
            }
            if (++dstcur >= dstend) {
                break;
            }
            *dstcur = *src;
            continue;
        }

        if (islower(*src)) {
            *dstcur = toupper(*src);
        } else {
            *dstcur = *src;
        }
    }

    *dstcur = '\0';
    return dst;
}

// User's filter
static char*
test_display_filter_escape(char* dst, size_t dstsize, char const* src) {
    char* dstcur = dst;
    char* dstend = dst + dstsize - 1;

    for (; dstcur < dstend && *src; ++dstcur, ++src) {
        switch (*src) {
        default:
            *dstcur = *src;
            break;
        case '\n':
            if (dstcur + 1 < dstend) {
                *dstcur++ = '\\';
                *dstcur = 'n';
            }
            break;
        case '\t':
            if (dstcur + 1 < dstend) {
                *dstcur++ = '\\';
                *dstcur = 't';
            }
            break;
        }
    }

    *dstcur = '\0';
    return dst;
}

// User's filter
static char*
test_display_filter_nope(char* dst, size_t dstsize, char const* src) {
    snprintf(dst, dstsize, "%s", src);
    return dst;
}

int
main(int argc, char* argv[]) {
    // Initialize program
    my_display_filters_push_back(test_display_filter_nope);
    my_display_filters_push_back(test_display_filter_toupper);
    my_display_filters_push_back(test_display_filter_escape);

    // Read and write with filtering
    char buf[128];
    for (; fgets(buf, sizeof buf, stdin); ) {
        my_display(buf, stdout);
    }

    return 0;
}
$ ./a.out
123 abc Def 456
[123\tABC\tDEF\t456\n]

静的な配列だとフィルタリングで容量が足りなくなったりならなかったり。

投稿者名です。64字以内で入力してください。

必要な場合はEメールアドレスを入力してください(全体に公開されます)。

投稿する内容です。

スポンサーリンク

スポンサーリンク

スポンサーリンク

スポンサーリンク