/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=2 et sw=2 tw=80: */ /* Copyright 2013-2021 The Libfossil Authors, see LICENSES/BSD-2-Clause.txt SPDX-License-Identifier: BSD-2-Clause-FreeBSD SPDX-FileCopyrightText: 2021 The Libfossil Authors SPDX-ArtifactOfProjectName: Libfossil SPDX-FileType: Code Heavily indebted to the Fossil SCM project (https://fossil-scm.org). */ /****************************************************************** This file implements some test/demo code for working with wiki pages. */ #include "libfossil.h" static struct { const char * pageName; const char * outFilename; const char * inFilename; const char * mimetype; bool listNamesOnly; bool utcTime; bool allowNew; bool dryRun; } WikiApp = { NULL/*pageName*/, NULL/*outFilename*/, NULL/*inFilename*/, NULL/*mimetype*/, false/*lsNames*/, false/*utcTime*/, false/*allowNew*/, false/*dryRun*/ }; static int fcli_flag_callback_f_mimetype(fcli_cliflag const * x){ const char * m = *((char const **)x->flagValue); if(0==fsl_strcmp("markdown",m)) m = "text/x-markdown"; else if(0==fsl_strcmp("fossil",m)) m = "text/x-fossil-wiki"; else if(0==fsl_strcmp("plain",m)) m = "text/plain"; if(0!=fsl_strcmp(m,"text/x-markdown") && 0!=fsl_strcmp(m,"text/x-fossil-wiki") && 0!=fsl_strcmp(m,"text/plain")){ return fcli_err_set(FSL_RC_MISUSE, "Unknown mimetype [%s]. Use one of: " "text/x-fossil-wiki (alias=fossil), " "text/x-markdown (alias=markdown), " "or text/plain (alias=plain)", m); } WikiApp.mimetype = m; return 0; } static fcli_cliflag cliFlagsLs[] = { FCLI_FLAG_BOOL("n","names",&WikiApp.listNamesOnly, "Lists only the page names, not other info."), FCLI_FLAG_BOOL(0,"utc",&WikiApp.utcTime, "Use UTC instead of local time."), fcli_cliflag_empty_m }; static fcli_cliflag cliFlagsExport[] = { FCLI_FLAG("p","page","PageName",&WikiApp.pageName, "Optionally specified as first non-flag option."), FCLI_FLAG("o","output-file","file",&WikiApp.outFilename, "Optionally specified as second non-flag option."), fcli_cliflag_empty_m }; static fcli_cliflag cliFlagsSave[] = { FCLI_FLAG("p","page","PageName",&WikiApp.pageName, "Optionally specified as first non-flag option."), FCLI_FLAG("f","input-file","file",&WikiApp.inFilename, "Optionally specified as second non-flag option."), FCLI_FLAG_BOOL("n","dry-run",&WikiApp.dryRun, "Dry-run mode."), FCLI_FLAG_BOOL(0,"new",&WikiApp.allowNew, "Specifies that the page should be created if " "it does not exist."), FCLI_FLAG_X("t","mimetype","mimetype-string",&WikiApp.mimetype, fcli_flag_callback_f_mimetype, "Specify mimetype as one of: " "text/x-fossil-wiki (default), text/x-markdown, text/plain"), fcli_cliflag_empty_m }; int32_t wiki_page_count(){ return fsl_db_g_int32(fsl_cx_db_repo(fcli_cx()), -1, "SELECT count(*) FROM tag " "WHERE tagname GLOB 'wiki-*'"); } /** A fsl_deck_visitor_f() impl which expects d to be a WIKI artifact, and it outputs various info about it. */ static int cb_f_wiki_list( fsl_cx * const f, fsl_deck * const d, void * state ){ int * counter = (int*)state; if(WikiApp.listNamesOnly){ f_out("%s\n", d->L); }else{ fsl_db * db = fsl_cx_db_repo(fcli_cx()); char * ts = fsl_db_julian_to_iso8601(db, d->D, 0, !WikiApp.utcTime); unsigned short const vbose = fcli_is_verbose(); assert(ts && 'T'==ts[10]); ts[10] = ' '; if(0 == (*counter)++){ if(vbose){ f_out("RID "); } f_out("%-20s %-13s %-6s Name\n", (WikiApp.utcTime ? "Time (UTC)" : "Time (local time)"), "UUID", "Size"); } if(vbose){ f_out("%-6"FSL_ID_T_PFMT" ", d->rid); } f_out("%-20s %.*z %-6"FSL_SIZE_T_PFMT" %s\n", ts, 12, fsl_rid_to_uuid(f, d->rid), (fsl_size_t)d->W.used, d->L); fsl_free(ts); } #if defined(DEBUG) { int rc; fsl_id_t ridCheck = 0; rc = fsl_wiki_latest_rid(f, d->L, &ridCheck); assert(!rc); if(d->rid!=ridCheck){ f_out("unexpected version mismatch in page [%s]: " "d->rid=%"FSL_ID_T_PFMT", ridCheck=%"FSL_ID_T_PFMT"\n", d->L, d->rid, ridCheck); } assert(d->rid==ridCheck); } #endif return 0; } static int fcmd_wiki_list(){ fsl_cx * f = fcli_cx(); int counter = 0; int rc = fcli_process_flags(cliFlagsLs); if(rc || (rc = fcli_has_unused_flags(0))){ return rc; } if(WikiApp.listNamesOnly){ fsl_list li = fsl_list_empty; fsl_size_t i; rc = fsl_wiki_names_get(f, &li); for( i = 0; !rc && (itype), 8, fsl_rid_to_uuid(d->f, d->rid), d->rid)); return *((char const *)state) /* demonstrate what happens when crosslinking fails. */ ? FSL_RC_NYI : 0; } int main(int argc, char const * const * argv ){ int rc; fcli_cliflag const dummyFlags[] = {/*porting kludge*/fcli_cliflag_empty_m}; fcli_help_info const FCliHelp = { "List, export, and import fossil repository wiki content.", "ls|save|export [options]", fcli_local_help }; rc = fcli_setup_v2(argc, argv, dummyFlags, &FCliHelp); if(!rc){ if(!fsl_cx_db_repo(fcli_cx())){ rc = fcli_err_set(FSL_RC_MISUSE, "This app requires a repository db."); } else{ bool failCrosslink = fcli_flag2("fx", "fail-xlink", NULL);; fsl_xlink_listener( fcli_cx(), fcli.appName, wiki_xlink_f, &failCrosslink ); rc = fcli_dispatch_commands(aCommandsWiki, 0); } } return fcli_end_of_main(rc); }