Switch to configure and make based build

Also removed excessive use of std.regex in esvapi.d and
made it actually compile -_-
This commit is contained in:
Jeremy Baxter 2023-09-24 10:31:12 +13:00
parent 7ebc0d7b66
commit 6efe117545
5 changed files with 254 additions and 68 deletions

1
.gitignore vendored
View file

@ -2,3 +2,4 @@
*.so *.so
*.a *.a
esv esv
Makefile

View file

@ -1,32 +0,0 @@
IMPORT = import
PREFIX = /usr/local
MANPREFIX = /usr/share/man
DC = ldc2
CFLAGS = -O -I${IMPORT} -release -w
OBJS = main.o esvapi.o ini.o
all: esv
esv: ${OBJS}
${DC} ${CFLAGS} -of$@ ${OBJS}
# main executable
main.o: main.d esvapi.o
${DC} ${CFLAGS} -of$@ -c main.d
esvapi.o: esvapi.d
${DC} ${CFLAGS} -of$@ -c esvapi.d
ini.o: ${IMPORT}/dini/*.d
${DC} ${CFLAGS} -of$@ -c ${IMPORT}/dini/*.d
clean:
rm -f esv ${OBJS}
install: esv
install -m755 esv ${DESTDIR}${PREFIX}/bin/esv
cp -f esv.1 ${DESTDIR}${MANPREFIX}/man1
cp -f esv.conf.5 ${DESTDIR}${MANPREFIX}/man5
.PHONY: all clean install

View file

@ -2,8 +2,8 @@
*Read the Bible from your terminal* *Read the Bible from your terminal*
`esv` is a utility that displays passages of the English Standard Bible on your terminal. `esv` is a utility that displays passages of the English Standard Bible
It connects to the ESV web API to retrieve the passages, on your terminal. It connects to the ESV web API to retrieve the passages,
and allows configuration through command-line options and the configuration file. and allows configuration through command-line options and the configuration file.
Example usage: Example usage:
@ -20,18 +20,20 @@ A Psalm of David.
He makes me lie down in green pastures.... He makes me lie down in green pastures....
``` ```
If the requested passage is over 32 lines long, `esv` will pipe it through a pager If the requested passage is over 32 lines long, `esv` will pipe it through
(default less). The pager being used can be changed through the `ESV_PAGER` a pager (default less). The pager being used can be changed through the
environment variable or just disabled altogether by passing the -P option. `ESV_PAGER` environment variable or just disabled altogether by passing the
-P option.
The names of Bible books are not case sensitive, so John, john, JOHN and jOhN The names of Bible books are not case sensitive, so John, john, and JOHN
are all accepted. are all accepted.
## Audio ## Audio
`esv` supports playing audio passages through the -a option. `esv` supports playing audio passages through the -a option.
The `mpg123` audio/video player is utilised here and so it is therefore required The `mpg123` audio/video player is utilised here and so it required if you
if you want to use audio mode. want to play audio passages. If you prefer, you can use a different player
(such as mpv) by editing config.di.
Audio usage is the same as normal text usage. `esv -a Matthew 5-7` will play Audio usage is the same as normal text usage. `esv -a Matthew 5-7` will play
an audio passage of Matthew 5-7. an audio passage of Matthew 5-7.
@ -40,10 +42,13 @@ an audio passage of Matthew 5-7.
To install `esv`, first make sure you have the To install `esv`, first make sure you have the
[LLVM D compiler (ldc)](https://github.com/ldc-developers/ldc#installation) [LLVM D compiler (ldc)](https://github.com/ldc-developers/ldc#installation)
installed on your system. You should also have Phobos (the D standard library, comes included with LDC) installed on your system.
installed as a dynamic library in order to run the executable.
First clone the source code repository: Commands prefixed with a dollar sign ($) are intended to be run as
a standard user, and commands prefixed with a hash sign (#) are intended
to be run as the root user.
First, get the source code:
``` ```
$ git clone https://codeberg.org/jtbx/esv $ git clone https://codeberg.org/jtbx/esv
@ -53,13 +58,15 @@ $ cd esv
Now, compile and install: Now, compile and install:
``` ```
$ ./configure
$ make $ make
# make install # make install
``` ```
By default the Makefile guesses that the ldc executable is named `ldc2`. If it is installed <!--
under a different name, or if you wish to use a different compiler, use `make DC=compiler` By default the configure script looks for ldc and dmd in your PATH
(where `compiler` is your compiler) instead. and optimises the command-line arguments based on the compiler.
-->
## Documentation ## Documentation

187
configure vendored Executable file
View file

@ -0,0 +1,187 @@
#!/usr/bin/env sh
# simple and flexible configure script for people who don't like to waste time
# licensed to the public domain
set -e
IMPORT=import
mkf=Makefile
cflags=-I"$IMPORT"
objs='esv.o esvapi.o'
srcs='esv.d esvapi.d'
makefile='
IMPORT = '"$IMPORT"'
PREFIX = /usr/local
MANPREFIX = ${PREFIX}/man
DC = ${_DC}
CFLAGS = ${_CFLAGS}
OBJS = ${_OBJS} ini.o
all: esv
esv: ${OBJS}
${DC} ${_LDFLAGS} -of=$@ ${OBJS}
.SUFFIXES: .d .o
.d.o:
${DC} ${CFLAGS} -c $<
ini.o: ${IMPORT}/dini/*.d
${DC} ${CFLAGS} -of=ini.o -c ${IMPORT}/dini/*.d
clean:
rm -f esv ${OBJS}
install: esv
install -m755 esv ${DESTDIR}${PREFIX}/bin/esv
cp -f esv.1 ${DESTDIR}${MANPREFIX}/man1
cp -f esv.conf.5 ${DESTDIR}${MANPREFIX}/man5
.PHONY: all clean install
'
# utility functions
present () {
command -v "$1" 1>/dev/null 2>/dev/null
}
using () {
>&2 printf "using $1\n"
}
error () {
>&2 printf "$(basename $0): $1\n"
exit 1
}
# generators
## D compiler
gen_DC () {
if ! [ -z "$dc" ]; then
using "$dc"
return 0
fi
if present ldc2; then
dc=ldc2
using ldc2
elif present dmd; then
dc=dmd
using dmd
else
error "D compiler not found; install ldc or dmd"
fi
}
## flags used in the compilation step
gen_CFLAGS () {
if [ -z "$debug" ]; then
case "$dc" in
ldc2) cflags="-Oz";;
dmd) cflags="-O";;
esac
using "$cflags"
else
fdebugsymbols="-g"
using "$fdebugsymbols"
case "$dc" in
ldc2)
fdebug="-d-debug"
using "$fdebug"
foptimisation="-O0"
using "$foptimisation"
;;
dmd) fdebug="-debug";;
esac
cflags="$fdebugsymbols $fdebug"
unset fdebug
unset fdebugsymbols
unset foptimisation
fi
}
## flags used in the linking step
gen_LDFLAGS () {
if [ "$dc" = ldc2 ]; then
if present ld.lld; then
ldflags="-linker=lld"
using "$ldflags"
elif present ld.gold; then
ldflags="-linker=gold"
using "$ldflags"
fi
fi
}
# command line interface
while getopts c:dhr ch; do
case "$ch" in
c)
case "$OPTARG" in
ldc2) dc="ldc2" ;;
dmd) dc="dmd" ;;
*) error "unknown D compiler '$OPTARG' specified (valid options: ldc2, dmd)" ;;
esac
;;
d) debug=1 ;;
r) unset debug ;;
h)
cat <<EOF
configure: create an optimised makefile for the current environment
options:
-c: force use of a particular compiler (dmd or ldc2)
-d: build in debug mode, with debug symbols and statements enabled
-r: build in release mode with optimisation flags enabled (default)
-h: show this help message
EOF
exit 0
;;
?) exit 1 ;;
:) exit 1 ;;
esac
done
# creating the makefile
u_cflags="$cflags"
unset cflags
gen_DC
gen_CFLAGS
gen_LDFLAGS
rm -f "$mkf"
printf '# begin generated definitions' >>"$mkf"
printf '
_DC = %s
_CFLAGS = %s
_LDFLAGS = %s
' \
"$dc" \
"$cflags $u_cflags" \
"$ldflags" \
>>"$mkf"
## generate obj list
printf '_OBJS =' >>"$mkf"
for obj in $objs; do
printf " $obj" >>"$mkf"
done
printf '\n' >>"$mkf"
printf '# end generated definitions\n' >>"$mkf"
printf "$makefile" >>"$mkf"
## generate dependency list
>&2 printf "generating dependency list\n"
printf '\n# begin generated dependencies\n' >>"$mkf"
i=1
for obj in $objs; do
"$dc" $u_cflags -O0 -o- -makedeps \
"$(printf "$srcs" | awk '{print $'"$i"'}')" >>"$mkf"
i="$(($i + 1))"
done
printf '# end generated dependencies\n' >>"$mkf"

View file

@ -25,9 +25,9 @@ import std.exception : basicExceptionCtors, enforce;
import std.file : tempDir, write; import std.file : tempDir, write;
import std.format : format; import std.format : format;
import std.json : JSONValue, parseJSON; import std.json : JSONValue, parseJSON;
import std.regex : regex, matchAll, replaceAll; import std.regex : regex, matchAll;
import std.stdio : File; import std.stdio : File;
import std.string : capitalize; import std.string : capitalize, tr;
import std.net.curl : HTTP; import std.net.curl : HTTP;
enum ESVIndent enum ESVIndent
@ -162,8 +162,6 @@ bool verseValid(in char[] verse) @safe
return false; return false;
} }
}
class ESVApi class ESVApi
{ {
protected { protected {
@ -234,32 +232,51 @@ class ESVApi
params = []; params = [];
{ {
(char[])[] parambuf; void *o;
string[] parambuf;
foreach (string opt; ESVAPI_PARAMETERS) { foreach (string opt; ESVAPI_PARAMETERS) {
bool bo;
int io;
switch (opt) { switch (opt) {
case "indent-using": case "indent-using":
o = opts.indent_using; o = cast(void *)opts.indent_using;
break; break;
case "indent-poetry": case "indent-poetry":
case "include-passage-references":
case "include-verse-numbers":
case "include-first-verse-numbers":
case "include-footnotes":
case "include-footnote-body":
case "include-headings":
case "include-short-copyright":
case "include-copyright":
case "include-passage-horizontal-lines":
case "include-heading-horizontal-lines":
case "include-selahs":
o = cast(void *)opts.b[opt];
break;
case "line-length":
case "horizontal-line-length":
case "indent-paragraphs":
case "indent-poetry-lines":
case "indent-declares":
case "indent-psalm-doxology":
o = cast(void *)opts.i[opt];
break;
default: break;
} }
!opt.matchAll("^include-").empty) { parambuf[parambuf.length] = format!"&%s=%s"(
o = opts.b[opt]; opt,
} else if (opt == "line-length" || opt == "indent-using" ?
opt == "horizontal-line-length" || opts.indent_using == ESVIndent.TAB ? "tab" : "space"
!opt.matchAll("^indent-").empty) { : o.to!string()
o = opts.i[opt]; );
}
params = format!"%s&%s=%s"(params, opt, o.to!string());
} }
} }
request = HTTP( request = HTTP(format!"%s/text/?q=%s+%s%s%s"(
format!"%s/text/?q=%s+%s%s%s"(_url, book _url,
book
.capitalize() .capitalize()
.replaceAll(regex(" "), "+"), .tr(" ", "+"),
verse, params, extraParameters) verse, params, extraParameters)
); );
request.onProgress = onProgress; request.onProgress = onProgress;
@ -290,7 +307,12 @@ class ESVApi
File tmpFile; File tmpFile;
auto request = HTTP(format!"%s/audio/?q=%s+%s"( auto request = HTTP(format!"%s/audio/?q=%s+%s"(
_url, book.capitalize().replaceAll(regex(" "), "+"), verse)); _url,
book
.capitalize()
.tr(" ", "+"),
verse)
);
request.onProgress = onProgress; request.onProgress = onProgress;
request.onReceive = request.onReceive =
(ubyte[] data) (ubyte[] data)
@ -320,7 +342,8 @@ class ESVApi
JSONValue json; JSONValue json;
request = HTTP(format!"%s/search/?q=%s"( request = HTTP(format!"%s/search/?q=%s"(
_url, query.replaceAll(regex(" "), "+"))); _url, query.tr(" ", "+"))
);
request.onProgress = onProgress; request.onProgress = onProgress;
request.onReceive = request.onReceive =
(ubyte[] data) (ubyte[] data)