gout

A static git page generator
git clone https://git.bracken.jp/gout.git
Log | Files | Refs | README | LICENSE

commit 3e04dc09b619fdad56e07fd9fe03d30b3ca687ec
parent f4a2c59b7cf12d727e11f12d98ccb0688c3070f0
Author: Chris Bracken <chris@bracken.jp>
Date:   Fri, 20 Feb 2026 19:01:18 +0900

writer: extract ops vtable

Diffstat:
Msrc/writer/index_writer.c | 115++++++++++++++++++++++++++-----------------------------------------------------
Msrc/writer/repo_writer.c | 168++++++++++++++++++++++++++++---------------------------------------------------
2 files changed, 98 insertions(+), 185 deletions(-)

diff --git a/src/writer/index_writer.c b/src/writer/index_writer.c @@ -8,36 +8,49 @@ #include "writer/gopher/index_writer.h" #include "writer/html/index_writer.h" -typedef void (*IndexWriterVoidFunc)(void* impl); -typedef void (*IndexWriterStringFunc)(void* impl, const char* url); -typedef void (*IndexWriterRepoInfoFunc)(void* impl, const GitRepo* repo); +typedef struct IndexWriterOps { + void (*set_me_url)(void* impl, const char* url); + void (*begin)(void* impl); + void (*add_repo)(void* impl, const GitRepo* repo); + void (*end)(void* impl); + void (*free)(void* impl); +} IndexWriterOps; struct IndexWriter { - /* Writer implementation. */ - IndexWriterType type; + const IndexWriterOps* ops; void* impl; - - /* Writer operations. */ - IndexWriterStringFunc set_me_url; - IndexWriterVoidFunc begin; - IndexWriterRepoInfoFunc add_repo; - IndexWriterVoidFunc end; }; -static IndexWriter* htmlindexwriter_create(FILE* out); -static void htmlindexwriter_free(IndexWriter* writer); +static const IndexWriterOps kHtmlIndexWriterOps = { + .set_me_url = (void (*)(void*, const char*))html_indexwriter_set_me_url, + .begin = (void (*)(void*))html_indexwriter_begin, + .add_repo = (void (*)(void*, const GitRepo*))html_indexwriter_add_repo, + .end = (void (*)(void*))html_indexwriter_end, + .free = (void (*)(void*))html_indexwriter_free, +}; -static IndexWriter* gopherindexwriter_create(FILE* out); -static void gopherindexwriter_free(IndexWriter* writer); +static const IndexWriterOps kGopherIndexWriterOps = { + .set_me_url = NULL, + .begin = (void (*)(void*))gopher_indexwriter_begin, + .add_repo = (void (*)(void*, const GitRepo*))gopher_indexwriter_add_repo, + .end = (void (*)(void*))gopher_indexwriter_end, + .free = (void (*)(void*))gopher_indexwriter_free, +}; IndexWriter* indexwriter_create(IndexWriterType type, FILE* out) { assert(out != NULL); + IndexWriter* writer = ecalloc(1, sizeof(IndexWriter)); switch (type) { case kIndexWriterTypeHtml: - return htmlindexwriter_create(out); + writer->ops = &kHtmlIndexWriterOps; + writer->impl = html_indexwriter_create(out); + return writer; case kIndexWriterTypeGopher: - return gopherindexwriter_create(out); + writer->ops = &kGopherIndexWriterOps; + writer->impl = gopher_indexwriter_create(out); + return writer; } + free(writer); errx(1, "unknown IndexWriterType %d", type); } @@ -45,83 +58,31 @@ void indexwriter_free(IndexWriter* writer) { if (!writer) { return; } - switch (writer->type) { - case kIndexWriterTypeHtml: - htmlindexwriter_free(writer); - return; - case kIndexWriterTypeGopher: - gopherindexwriter_free(writer); - return; - } - errx(1, "unknown IndexWriterType %d", writer->type); + writer->ops->free(writer->impl); + writer->impl = NULL; + free(writer); } void indexwriter_set_me_url(IndexWriter* writer, const char* url) { assert(writer != NULL); assert(url != NULL); - if (writer->set_me_url) { - writer->set_me_url(writer->impl, url); + if (writer->ops->set_me_url) { + writer->ops->set_me_url(writer->impl, url); } } void indexwriter_begin(IndexWriter* writer) { assert(writer != NULL); - writer->begin(writer->impl); + writer->ops->begin(writer->impl); } void indexwriter_add_repo(IndexWriter* writer, const GitRepo* repo) { assert(writer != NULL); assert(repo != NULL); - writer->add_repo(writer->impl, repo); + writer->ops->add_repo(writer->impl, repo); } void indexwriter_end(IndexWriter* writer) { assert(writer != NULL); - writer->end(writer->impl); -} - -/* HtmlIndexWriter setup/teardown. */ - -static IndexWriter* htmlindexwriter_create(FILE* out) { - IndexWriter* writer = ecalloc(1, sizeof(IndexWriter)); - HtmlIndexWriter* html_writer = html_indexwriter_create(out); - writer->type = kIndexWriterTypeHtml; - writer->impl = html_writer; - writer->set_me_url = (IndexWriterStringFunc)html_indexwriter_set_me_url; - writer->begin = (IndexWriterVoidFunc)html_indexwriter_begin; - writer->add_repo = (IndexWriterRepoInfoFunc)html_indexwriter_add_repo; - writer->end = (IndexWriterVoidFunc)html_indexwriter_end; - return writer; -} - -static void htmlindexwriter_free(IndexWriter* writer) { - if (!writer) { - return; - } - html_indexwriter_free(writer->impl); - writer->impl = NULL; - free(writer); -} - -/* GopherIndexWriter setup/teardown. */ - -static IndexWriter* gopherindexwriter_create(FILE* out) { - IndexWriter* writer = ecalloc(1, sizeof(IndexWriter)); - GopherIndexWriter* gopher_writer = gopher_indexwriter_create(out); - writer->type = kIndexWriterTypeGopher; - writer->impl = gopher_writer; - writer->set_me_url = NULL; - writer->begin = (IndexWriterVoidFunc)gopher_indexwriter_begin; - writer->add_repo = (IndexWriterRepoInfoFunc)gopher_indexwriter_add_repo; - writer->end = (IndexWriterVoidFunc)gopher_indexwriter_end; - return writer; -} - -static void gopherindexwriter_free(IndexWriter* writer) { - if (!writer) { - return; - } - gopher_indexwriter_free(writer->impl); - writer->impl = NULL; - free(writer); + writer->ops->end(writer->impl); } diff --git a/src/writer/repo_writer.c b/src/writer/repo_writer.c @@ -8,51 +8,71 @@ #include "writer/gopher/repo_writer.h" #include "writer/html/repo_writer.h" -typedef void (*RepoWriterSetLogCachefile)(void* writer, const char* cachefile); -typedef void (*RepoWriterSetLogCommitLimit)(void* writer, size_t count); -typedef void (*RepoWriterSetBaseurl)(void* writer, const char* baseurl); -typedef void (*RepoWriterBegin)(void* writer); -typedef void (*RepoWriterAddCommit)(void* writer, const GitCommit* commit); -typedef void (*RepoWriterAddReference)(void* writer, const GitReference* ref); -typedef void (*RepoWriterAddFile)(void* writer, const GitFile* file); -typedef void (*RepoWriterEnd)(void* writer); +typedef struct RepoWriterOps { + void (*set_log_cachefile)(void* writer, const char* cachefile); + void (*set_log_commit_limit)(void* writer, size_t count); + void (*set_baseurl)(void* writer, const char* baseurl); + void (*begin)(void* writer); + void (*add_commit)(void* writer, const GitCommit* commit); + void (*add_reference)(void* writer, const GitReference* ref); + void (*add_file)(void* writer, const GitFile* file); + void (*end)(void* writer); + void (*free)(void* writer); +} RepoWriterOps; struct RepoWriter { - /* Writer implementation. */ - RepoWriterType type; + const RepoWriterOps* ops; void* impl; - const FileSystem* fs; - - /* Writer configuration. */ - RepoWriterSetLogCachefile set_log_cachefile; - RepoWriterSetLogCommitLimit set_log_commit_limit; - RepoWriterSetBaseurl set_baseurl; - - /* Writer operations. */ - RepoWriterBegin begin; - RepoWriterAddCommit add_commit; - RepoWriterAddReference add_reference; - RepoWriterAddFile add_file; - RepoWriterEnd end; }; -static RepoWriter* htmlrepowriter_create(GitRepo* repo, const FileSystem* fs); -static void htmlrepowriter_free(RepoWriter* writer); +static const RepoWriterOps kHtmlRepoWriterOps = { + .set_log_cachefile = + (void (*)(void*, const char*))html_repowriter_set_log_cachefile, + .set_log_commit_limit = + (void (*)(void*, size_t))html_repowriter_set_log_commit_limit, + .set_baseurl = (void (*)(void*, const char*))html_repowriter_set_baseurl, + .begin = (void (*)(void*))html_repowriter_begin, + .add_commit = (void (*)(void*, const GitCommit*))html_repowriter_add_commit, + .add_reference = + (void (*)(void*, const GitReference*))html_repowriter_add_reference, + .add_file = (void (*)(void*, const GitFile*))html_repowriter_add_file, + .end = (void (*)(void*))html_repowriter_end, + .free = (void (*)(void*))html_repowriter_free, +}; -static RepoWriter* gopherrepowriter_create(GitRepo* repo, const FileSystem* fs); -static void gopherrepowriter_free(RepoWriter* writer); +static const RepoWriterOps kGopherRepoWriterOps = { + .set_log_cachefile = + (void (*)(void*, const char*))gopher_repowriter_set_log_cachefile, + .set_log_commit_limit = + (void (*)(void*, size_t))gopher_repowriter_set_log_commit_limit, + .set_baseurl = (void (*)(void*, const char*))gopher_repowriter_set_baseurl, + .begin = (void (*)(void*))gopher_repowriter_begin, + .add_commit = + (void (*)(void*, const GitCommit*))gopher_repowriter_add_commit, + .add_reference = + (void (*)(void*, const GitReference*))gopher_repowriter_add_reference, + .add_file = (void (*)(void*, const GitFile*))gopher_repowriter_add_file, + .end = (void (*)(void*))gopher_repowriter_end, + .free = (void (*)(void*))gopher_repowriter_free, +}; RepoWriter* repowriter_create(RepoWriterType type, GitRepo* repo, const FileSystem* fs) { assert(repo != NULL); assert(fs != NULL); + RepoWriter* writer = ecalloc(1, sizeof(RepoWriter)); switch (type) { case kRepoWriterTypeHtml: - return htmlrepowriter_create(repo, fs); + writer->ops = &kHtmlRepoWriterOps; + writer->impl = html_repowriter_create(repo, fs); + return writer; case kRepoWriterTypeGopher: - return gopherrepowriter_create(repo, fs); + writer->ops = &kGopherRepoWriterOps; + writer->impl = gopher_repowriter_create(repo, fs); + return writer; } + free(writer); errx(1, "unknown RepoWriterType %d", type); } @@ -60,120 +80,52 @@ void repowriter_free(RepoWriter* writer) { if (!writer) { return; } - switch (writer->type) { - case kRepoWriterTypeHtml: - htmlrepowriter_free(writer); - return; - case kRepoWriterTypeGopher: - gopherrepowriter_free(writer); - return; - } - errx(1, "unknown RepoWriterType %d", writer->type); + writer->ops->free(writer->impl); + writer->impl = NULL; + free(writer); } void repowriter_set_log_cachefile(RepoWriter* writer, const char* cachefile) { assert(writer != NULL); assert(cachefile != NULL); - writer->set_log_cachefile(writer->impl, cachefile); + writer->ops->set_log_cachefile(writer->impl, cachefile); } void repowriter_set_log_commit_limit(RepoWriter* writer, size_t count) { assert(writer != NULL); - writer->set_log_commit_limit(writer->impl, count); + writer->ops->set_log_commit_limit(writer->impl, count); } void repowriter_set_baseurl(RepoWriter* writer, const char* baseurl) { assert(writer != NULL); assert(baseurl != NULL); - writer->set_baseurl(writer->impl, baseurl); + writer->ops->set_baseurl(writer->impl, baseurl); } void repowriter_begin(RepoWriter* writer) { assert(writer != NULL); - writer->begin(writer->impl); + writer->ops->begin(writer->impl); } void repowriter_add_commit(RepoWriter* writer, const GitCommit* commit) { assert(writer != NULL); assert(commit != NULL); - writer->add_commit(writer->impl, commit); + writer->ops->add_commit(writer->impl, commit); } void repowriter_add_reference(RepoWriter* writer, const GitReference* ref) { assert(writer != NULL); assert(ref != NULL); - writer->add_reference(writer->impl, ref); + writer->ops->add_reference(writer->impl, ref); } void repowriter_add_file(RepoWriter* writer, const GitFile* file) { assert(writer != NULL); assert(file != NULL); - writer->add_file(writer->impl, file); + writer->ops->add_file(writer->impl, file); } void repowriter_end(RepoWriter* writer) { assert(writer != NULL); - writer->end(writer->impl); -} - -/* HtmlRepoWriter setup/teardown. */ - -static RepoWriter* htmlrepowriter_create(GitRepo* repo, const FileSystem* fs) { - RepoWriter* writer = ecalloc(1, sizeof(RepoWriter)); - HtmlRepoWriter* html_writer = html_repowriter_create(repo, fs); - writer->type = kRepoWriterTypeHtml; - writer->impl = html_writer; - writer->fs = fs; - writer->set_log_cachefile = - (RepoWriterSetLogCachefile)html_repowriter_set_log_cachefile; - writer->set_log_commit_limit = - (RepoWriterSetLogCommitLimit)html_repowriter_set_log_commit_limit; - writer->set_baseurl = (RepoWriterSetBaseurl)html_repowriter_set_baseurl; - writer->begin = (RepoWriterBegin)html_repowriter_begin; - writer->add_commit = (RepoWriterAddCommit)html_repowriter_add_commit; - writer->add_reference = (RepoWriterAddReference)html_repowriter_add_reference; - writer->add_file = (RepoWriterAddFile)html_repowriter_add_file; - writer->end = (RepoWriterEnd)html_repowriter_end; - return writer; -} - -static void htmlrepowriter_free(RepoWriter* writer) { - if (!writer) { - return; - } - html_repowriter_free(writer->impl); - writer->impl = NULL; - free(writer); -} - -/* GopherRepoWriter setup/teardown. */ - -static RepoWriter* gopherrepowriter_create(GitRepo* repo, - const FileSystem* fs) { - RepoWriter* writer = ecalloc(1, sizeof(RepoWriter)); - GopherRepoWriter* gopher_writer = gopher_repowriter_create(repo, fs); - writer->type = kRepoWriterTypeGopher; - writer->impl = gopher_writer; - writer->fs = fs; - writer->set_log_cachefile = - (RepoWriterSetLogCachefile)gopher_repowriter_set_log_cachefile; - writer->set_log_commit_limit = - (RepoWriterSetLogCommitLimit)gopher_repowriter_set_log_commit_limit; - writer->set_baseurl = (RepoWriterSetBaseurl)gopher_repowriter_set_baseurl; - writer->begin = (RepoWriterBegin)gopher_repowriter_begin; - writer->add_commit = (RepoWriterAddCommit)gopher_repowriter_add_commit; - writer->add_reference = - (RepoWriterAddReference)gopher_repowriter_add_reference; - writer->add_file = (RepoWriterAddFile)gopher_repowriter_add_file; - writer->end = (RepoWriterEnd)gopher_repowriter_end; - return writer; -} - -static void gopherrepowriter_free(RepoWriter* writer) { - if (!writer) { - return; - } - gopher_repowriter_free(writer->impl); - writer->impl = NULL; - free(writer); + writer->ops->end(writer->impl); }