-- *********************************************************************** -- -- Module to display the King James Bible -- Copyright 2021 by Sean Conner. -- -- This program is free software: you can redistribute it and/or modify it -- under the terms of the GNU General Public License as published by the -- Free Software Foundation, either version 3 of the License, or (at your -- option) any later version. -- -- This program is distributed in the hope that it will be useful, but -- WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -- Public License for more details. -- -- You should have received a copy of the GNU General Public License along -- with this program. If not, see . -- -- Comments, questions and criticisms can be sent to: sean@conman.org -- *********************************************************************** -- luacheck: globals CONF tumbler init bookend read_entry entries -- luacheck: globals filename day_titles -- luacheck: ignore 611 local fsys = require "org.conman.fsys" local date = require "org.conman.date" local ENTITIES = require "org.conman.const.entity" local lpeg = require "lpeg" local io = require "io" local os = require "os" local utf8 = require "utf8" local string = require "string" local math = require "math" local table = require "table" local loadfile = loadfile local require = require local setmetatable = setmetatable local type = type local _ENV = {} tumbler = require "org.conman.app.mod_blog.tumbler" CONF = { require = setmetatable( {}, { __index = function(s) return s end, __call = function(s) return s end, } ), } -- *********************************************************************** local function date_cmp(d1,d2) local rc rc = d1.year - d2.year if rc ~= 0 then return rc end rc = d1.month - d2.month if rc ~= 0 then return rc end rc = d1.day - d2.day if rc ~= 0 then return rc end return d1.part - d2.part end -- *********************************************************************** local function swap_endpoints(range) local start = {} local stop = {} start.year = range.stop.year start.month = range.stop.month stop.year = range.start.year stop.month = range.start.month if range.ustart == 'month' then stop.day = 31 stop.part = 23 elseif range.ustart == 'day' then stop.day = range.start.day stop.part = 23 elseif range.ustart == 'part' then stop.day = range.start.day stop.part = range.start.part elseif range.ustart == 'year' then assert(false) end if range.ustop == 'month' then start.day = 1 start.part = 1 elseif range.ustop == 'day' then start.day = range.stop.day start.part = 1 elseif range.ustop == 'part' then start.day = range.stop.day start.part = range.stop.part elseif range.ustop == 'year' then assert(false) end range.start = stop range.stop = start end -- *********************************************************************** local function when_to_filename(w) return string.format("%s/%4d/%02d/%02d/%d",CONF.basedir,w.year,w.month,w.day,w.part) end -- *********************************************************************** local function when_to_meta(w,meta) return string.format("%s/%4d/%02d/%02d/%s",CONF.basedir,w.year,w.month,w.day,meta) end -- *********************************************************************** local parse_date = lpeg.Ct( lpeg.Cg(lpeg.R"09"^1 / math.tointeger,"year") * lpeg.P"/" * lpeg.Cg(lpeg.R"09"^1 / math.tointeger,"month") * lpeg.P"/" * lpeg.Cg(lpeg.R"09"^1 / math.tointeger,"day") * lpeg.P"." * lpeg.Cg(lpeg.R"09"^1 / math.tointeger,"part") ) -- *********************************************************************** local deent do local char = lpeg.P"&#" * lpeg.C(lpeg.R"09"^1) * lpeg.P";" / utf8.char + lpeg.P"&" * lpeg.C(lpeg.R("az","AZ","09")^1) * lpeg.P";" / ENTITIES + lpeg.S" \t\r\n"^1 / " " + lpeg.P(1) deent = lpeg.Cs(char^0) end -- *********************************************************************** function init(config) config = config or os.getenv("BLOG_CONFIG") if not config then return end local f = loadfile(config,"t",CONF) if not f then return end f() return CONF end -- *********************************************************************** function bookend(which) local file = io.open(CONF.basedir .. "/." .. which) local line = file:read("l") local when = parse_date:match(line) file:close() return when end -- *********************************************************************** function read_entry(when) local function get_meta(meta) local f = io.open(when_to_meta(when,meta),"r") local l = 0 local line if not f then return "" end repeat line = f:read("l") l = l + 1 until l == when.part f:close() return line and deent:match(line) or "" end local filename = when_to_filename(when) if fsys.access(filename,"r") then local entry = {} entry.when = { year = when.year , month = when.month , day = when.day , part = when.part } entry.title = get_meta("titles") entry.class = get_meta("class") entry.author = get_meta("authors") entry.status = get_meta("status") entry.adtag = get_meta("adtag") entry._filename = filename local f = io.open(filename,"r") entry.body = f:read("a") f:close() return entry end end -- *********************************************************************** function entries(range) if type(range) == 'string' then range = tumbler.new(range,bookend "first", bookend "last") end if date_cmp(range.start,range.stop) <= 0 then local function nup(state) if date_cmp(state.start,state.stop) > 0 then return end local entry = read_entry(state.start) if entry then state.start.part = state.start.part + 1 return entry end state.start.part = 1 state.start.day = state.start.day + 1 if state.start.day > date.daysinmonth(state.start) then state.start.day = 1 state.start.month = state.start.month + 1 if state.start.month == 13 then state.start.month = 1 state.start.year = state.start.year + 1 end end return nup(state) end return nup,range else swap_endpoints(range) range.start.part = range.start.part + 1 local function ndown(state) state.start.part = state.start.part - 1 if state.start.part == 0 then state.start.part = 23 state.start.day = state.start.day - 1 if state.start.day == 0 then state.start.day = 31 state.start.month = state.start.month - 1 if state.start.month == 0 then state.start.month = 12 state.start.year = state.start.year - 1 end end end if date_cmp(state.start,state.stop) < 0 then return end local entry = read_entry(state.start) if entry then return entry end return ndown(state) end return ndown,range end end -- *********************************************************************** function filename(tuple) return string.format( "%s/%04d/%02d/%02d/%s", CONF.basedir, tuple.start.year, tuple.start.month, tuple.start.day, tuple.filename ) end -- *********************************************************************** function day_titles(when) local res = {} local filename = when_to_meta(when,"titles") if filename and fsys.access(filename,"r") then for title in io.lines(filename) do table.insert(res,deent:match(title)) end end return res end -- *********************************************************************** return _ENV gemini://gemini.conman.org/extensions/mod_blog.lua

-- Leo's gemini proxy

-- Connecting to gemini.conman.org:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/plain; charset=us-ascii

-- Response ended

-- Page fetched on Sun May 5 15:21:07 2024