Initial commit! Testing remote repository access.

This commit is contained in:
Paul Mosier 2021-09-08 23:28:35 -04:00
parent c1629d92b7
commit 443e2fbb35
14 changed files with 2044 additions and 62 deletions

1
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1 @@
See the code of conduct section in README.md

1
CONTRIBUTING.md Normal file
View File

@ -0,0 +1 @@
See the contributing section in README.md

2
COPYING Normal file
View File

@ -0,0 +1,2 @@
Copy and use freely under the terms of the GNU General Public License
as stated in the LICENSE file in this same directory

353
LICENSE
View File

@ -1,117 +1,350 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
The SWORD Project is (c) 1994-2014 The CrossWire Bible Society, under the
terms of the GNU GPL, as stated below.
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
NOTE: The text of the GNU GPL license is copyrighted by the Free Software
Foundation, Inc., but The SWORD Project is copyrighted corporately by:
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
CrossWire Bible Society
P. O. Box 2528
Tempe, AZ 85280-2528
Preamble
_________________________________________________________________
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too.
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
Preamble
To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
The precise terms and conditions for copying, distribution and modification follow.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
The precise terms and conditions for copying, distribution and
modification follow.
Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
NO WARRANTY
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
NO WARRANTY
END OF TERMS AND CONDITIONS
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
How to Apply These Terms to Your New Programs
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
END OF TERMS AND CONDITIONS
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
How to Apply These Terms to Your New Programs
one line to give the program's name and an idea of what it does. Copyright (C) yyyy name of author
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
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 2 of the License, or (at your option) any later version.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
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.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Also add information on how to contact you by electronic and paper mail.
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 2 of the License, or
(at your option) any later version.
If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
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.
Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker.
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
signature of Ty Coon, 1 April 1989 Ty Coon, President of Vice
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

34
Makefile Normal file
View File

@ -0,0 +1,34 @@
PREFIX = /usr/local
CC = clang
CCFLAGS = -Wall
TARGET = scriptura
INCLUDES = -I/usr/include/sword -I/usr/include/ncursesw
LDFLAGS = -lmenuw -lformw -lncursesw -lsword -lstdc++
SOURCE = free.cpp scabbard.cpp pane.cpp scriptura.cpp
$(TARGET): sword
$(CC) $(CCFLAGS) -o $(TARGET) $(INCLUDES) $(SOURCE) $(LDFLAGS)
debug: CCFLAGS += -g
debug: $(TARGET)
sword:
ifeq ($(wildcard /usr/include/sword),)
echo "Error: sword-devel not installed."
exit 1
endif
install:
cp -v scriptura $PREFIX/bin
uninstall:
rm -v $PREFIX/bin
clean:
rm -f $(TARGET)

View File

@ -1,3 +1,59 @@
# scriptura
# Scriptura
A ncurses-based frontend to the SWORD project, the CrossWire Bible Society's Bible software project.
A ncurses frontend to the SWORD project.
This program was written to scratch a personal itch. I do a lot of daily computer work in the command line, I wanted something more feature-rich than libsword's diatheke, and I wanted to sharpen my C skills. I imagine there are probably a single-digit's amount of people in the world who are interested in doing their Bible study from a command line terminal. If you happen to be one of them, please feel free to use this program. Its layout and interface are very loosely based on OliveTree, a Bible study app popular on the Android platform.
## Dependencies
* libsword and its development libraries (often available in most distributions' standard repos)
* ncurses and its development libraries (any modern Linux version should work)
* clang
## Getting started
To install scriptura:
> git clone https://tildegit.org/paladin1/scriptura.git
> cd scriptura
> make
> make install
On first run, scriptura assumes that a King James module is intalled and available. Many modules from CrossWire are [available here](https://www.crosswire.org/ftpmirror/pub/sword/packages/rawzip/) and other frontends have their own repos. To install them from the command line:
> mkdir -p $HOME/.sword/
> cd $HOME/.sword/
> curl https://www.crosswire.org/ftpmirror/pub/sword/packages/rawzip/KJVA.zip
> unzip KJVA.zip
A configuration file will be created at $HOME/.config/scriptura.ini. You can see the sample config file in the codebase for available options.
When the software is running, the '?' key will give you the list of commands available. Open any module you have installed and you can go to or search any text.
## Known issues
Menus and forms will not render correctly if your terminal window is too narrow. Resize the terminal and this should work.
## Contributing
Thanks for being willing to expand on this project. For feature requests, bug reports, or other support see the section below.
For code submissions, please keep to a similar indentation & coding style (tabstop to 4, 1TBS indentation). I didn't use the C++ standard library in my coding to see if I could make the project work without it; don't feel constrained to the same.
You can submit pull requests through tildegit for review. You must be willing to have all code submissions become GPL licensed.
## Feedback / Support
Please use the tildegit project forum page to submit any feature requests, bug reports, or other feedback. For bugs, please include the descriptions of whatever module was used and relevant config/environment settings, and a list of steps to reproduce the problem. Please also adhere to the code of conduct, given in the section below.
Other means of contact [can be found here](https://keyoxide.org/hkp/paladin1%40sdf.org)
This project is basically a one-man operation. If you'd like to show your support financially, you can contribute via:
- /Paypal - paladin1/ at /sdf.org/
- /BTC - bc1q9dfau346z38jth35gkaxacd3fljvfgw6cqcyyv/
## Code of Conduct
"Do unto others as you would have them do unto you."
All abuse or malign speech will be ignored or censored.
## Disclaimer
I'm not a programmer by day. While I have tested this thing and believe it to be beta-worthy, I assume no responsibility if it crashes your computer, ruins your holiday, or kicks your dog.

103
free.cpp Normal file
View File

@ -0,0 +1,103 @@
// Part of the Scriptura program
// free.cpp - free functions / globals
#include <ncurses.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <wchar.h>
#include <swbuf.h>
#include "free.h"
char CLITEXT[] =
"Scriptura - a ncurses-based Bible study program.\n"
" -h / --help - this help message\n"
" -c <file> - alternate config file to load\n"
"\0";
char HELPTEXT[] =
"Scriptura\n\n"
"Key bindings:\n"
" ? this help message\n"
" q quit\n\n"
" ESC close floating window\n"
" TAB change active window\n"
" g go to a specific passage\n"
" o open a new module in the active window\n"
" s search\n"
" arrow up/dn scroll up/down one line\n"
" page up/dn scroll up/down one page\n"
"\n"
"Formatting changes\n"
" (takes effect at next search/go to, and depends on loaded module)\n"
" f toggle footnotes\n"
" n toggle non-textual words\n"
" r toggle red letters\n"
" t toggle Strong's numbers\n"
" w toggle raw text (straight from the module)\n"
"\n(Press any key to return to the main screen)\n"
"\0";
void wrapup(int exitval, const char* str) {
endwin();
if (str != NULL) perror(str);
exit(exitval);
}
void trim(char* str) {
size_t len;
len = strlen(str);
while (len-- && isspace(str[len])) str[len] = 0;
}
int strmatch(wchar_t text[], const wchar_t* key, int matchnow) {
int retval = -1;
int length = wcslen(key);
wchar_t* substr = (wchar_t*) malloc((length + 1) * sizeof(wchar_t));
wmemset(substr, L'\0', length + 1);
if (! substr) wrapup(1, "Error allocating memory in strmatch.\n");
int i = 0;
int textlen = wcslen(text);
while ((text[i] != '\0') && (i < (textlen - length))) {
wmemcpy(substr, &text[i], length);
if (! wcscmp(substr, key)) {
retval = i;
break;
}
if (matchnow) break;
i++;
}
free(substr);
return retval;
}
int parseConf(sword::SWBuf buf) {
return (buf.length() == 1 ? (int) buf.c_str()[0] - 48 : 0);
}
starray stappend(starray arr, const char* newstr) {
arr.length++;
if (arr.length == 1) {
free(arr.strings); // needed due to stinit()'s malloc(0)
arr.strings = (const char**) malloc(sizeof(char*));
} else {
arr.strings = (const char**)
realloc(arr.strings, arr.length * sizeof(char*));
}
if (! arr.strings) wrapup(1, "Error resizing memory in stappend.\n");
(arr.strings)[arr.length - 1] = newstr;
return arr;
}
starray stinit(starray arr) {
arr.length = 0;
arr.strings = (const char**) malloc(0);
return arr;
}

61
free.h Normal file
View File

@ -0,0 +1,61 @@
// Part of the Scriptura program
// free.h - free functions / globals
#ifndef SCRIPT_GLOBAL
#define SCRIPT_GLOBAL
#include <swconfig.h>
#include <swbuf.h>
// structure for management of list of strings
typedef struct arraystruct {
int length; // number of elements
const char ** strings; // list of strings
} starray;
// structure to hold a module ID & search key
typedef struct modst {
const char* modname; // name of module
const char* searchkey; // our search key for the module
int keytype; // 0 - versekey, 1 - treekey, 2 - direct
int searchtype; // type of search to be performed, if any
const char* scope; // scope of search, if any
} modkey;
// strings for holding various large texts
extern char HELPTEXT[];
extern char CLITEXT[];
// global copy of configuration settings
extern sword::SWConfig config;
/* wrapup
* close out of ncurses gracefully, display an exit message if we have one, and
* quit */
void wrapup(int exitval, const char* str);
/* trim
* trim trailing whitespace for a string */
void trim(char* str);
/* parseConf
* parse through a configuration setting from SWConfig */
int parseConf(sword::SWBuf buf);
/* strmatch
* determine if a substring is present at either the beginning of a string or
* at any point within it, depending on a toggle for a flag -- return integer
* of matching index */
int strmatch(wchar_t text[], const wchar_t* key, int matchnow);
/* stappend
* append a new string to a starray */
starray stappend(starray arr, const char* newstr);
/* stinit
* initialize a new starray */
starray stinit(starray arr);
#endif

590
pane.cpp Normal file
View File

@ -0,0 +1,590 @@
/* Part of the Scriptura software
* pane.cpp - class to handle pane layout */
#include <stdlib.h>
#include <ncurses.h>
#include <menu.h>
#include <form.h>
#include <string.h>
#include <wchar.h>
#include "pane.h"
// constructor
pane::pane(int starty, int startx, int lines, int cols, const char* title) {
buflocx = buflocy = 0;
hasFocus = false;
rawtext = NULL;
// set some default search parameters
mod.modname = config["defaults"]["module"];
mod.searchkey = config["defaults"]["searchkey"];
mod.keytype = 0;
mod.searchtype = 0;
mod.scope = config["defaults"]["scope"];
setTitle(title);
// set up the window -- resize will give us some initializing
pad = NULL;
resize(starty, startx, lines, cols);
redraw(true);
}
// handle pane resizing
void pane::resize(int starty, int startx, int lines, int cols) {
y = starty;
x = startx;
height = lines;
width = cols;
win = newwin(height, width, y, x);
/* if pad is a curses subwindow (made by derwin) then we close it rather than
* resize it, so we only check for pads proper to manage text handling */
if (is_pad(pad)) renderText();
}
/* trap new text to render, and then pass along to our render function */
void pane::loadText(const char* stext) {
free(rawtext);
rawtext = (char*) malloc(sizeof(char*) * strlen(stext) + 1);
if (! rawtext) wrapup(1, "Error allocating memory in loadText.\n");
memset(rawtext, '\0', strlen(stext) + 1);
strncpy(rawtext, stext, strlen(stext));
free((void*) stext); // alloc'd in scabbard::getSpan
renderText();
}
/* create a new pad with the boundaries tightly fitting around a block of
* formatted text */
void pane::renderText() {
// pad is an ncurses pad - set what dimensions we know right now
pady = y + 1;
padx = x + 1;
padrows = height - 2;
padcols = width - 2;
bufsizex = padcols;
buflocx = 0;
buflocy = 0;
// here we define some counters & flags
int length = strlen(rawtext);
int numlines = 0; // number of newlines
int linelength = 0; // how long the current line is
int lastspaceidx = 0; // where was the last space relative to the string
int printable = 0; // index of printed characters
int lastprintspace = 0; // where was the last space relative to printed chars
int inmarkup = 0; // are we in a non-printed markup block
int makered = 0; // redletter flag
int makeital = 0; // italic flag
// pull config variables
int rawonly = parseConf(config["markup"]["rawtext"]);
int redletter = parseConf(config["markup"]["redletters"]);
int strongs = parseConf(config["markup"]["strongs"]);
int nontextual = parseConf(config["markup"]["nontextual"]);
// int footnotes = 0; not implemented yet
// convert input to wide characters for proper rendering
wchar_t* text = (wchar_t*) malloc(sizeof(wchar_t) * (length + 1));
if (! text) wrapup(1, "Error allocating memory in renderText.\n");
wmemset(text, L'\0', length + 1);
// some typographical quotes won't go through mbstowcs, so alter those
for (int i = 0; i < length; i++) {
int converted = mbstowcs(text, rawtext, i);
if (converted == -1) strncpy(&(rawtext[i-1]), "'", 1);
}
/*
mbstowcs(text, rawtext, length + 1);
for (int foo = 0; foo < length + 2; foo++) {
int converted = mbstowcs(text, rawtext, foo);
if (converted == -1) {
fprintf(stderr, "codes: %x\n", rawtext[foo-1]);
break;
}
}*/
//fprintf(stderr, "length: %d\n", length);
//fprintf(stderr, "rawtext: %s\n", rawtext);
//fprintf(stderr, "text: %ls\n\n", text);
// kept for debugging
//fwprintf(stderr, L"(O): %ls\n\n", text);
/* here's the workhorse - loop through the text twice: first to alter the
* text for word wrapping and to count the number of lines we have so we
* can define the pad size; second to print the text with the correct
* markup */
for (int p = 0; p < 2; p++) {
// loop through the text
for (int i = 0; i < length; i++) {
/* check if we're in markup - it's not printed and it doesn't
* affect our line lengths, so spin through it */
if (inmarkup) {
if (text[i] == '>') inmarkup = 0;
continue;
}
// check if we're entering markup - if so, figure out what
if ((text[i] == '<') && (! rawonly)) {
inmarkup = 1;
if ((! strmatch(&text[i], L"</q>", 1)) && (p == 1)) {
// end of redletter bracket
makered = 0;
} else if ((! strmatch(&text[i], L"</transChange>", 1))
&& (p == 1)) {
// end of interpretive text bracket
makeital = 0;
} else if ((! strmatch(&text[i], L"<p>", 1)) && (p == 0)) {
// paragraph break - replace </p> with </>'\n'
int endindex = strmatch(&text[i], L"</p>", 0);
if (endindex != -1)
wmemcpy(&text[i + endindex + 2], L">\n", 2);
} else if ((! strmatch(&text[i], L"<w savlm=", 1))
&& (p == 0) && (strongs == 1)) {
/* Strong's number - the format is below, but note
* there may be 1+ strong:[G|H]NNNN(N)'s to find,
* and other junk to ignore both within the same
* parameter, and before the word
* <w savlm="strong:[G|H]NNNN(N)">word</w> */
// 1. get boundary of open tag
int endbracket = strmatch(&text[i], L">", 0);
// 2. get Strong's parameters
wchar_t* num = (wchar_t*) malloc(sizeof(wchar_t*)
* 100);
if (! num) wrapup(1,
"Error declaring memory in renderText.\n");
int numidx = 0;
int strnum = strmatch(&text[i], L"strong:", 0) + 7;
while ((strnum < endbracket) && (strnum != -1)) {
int nextspace = strmatch(&text[i+strnum], L" ", 0);
int space1 = strmatch(&text[i+strnum], L"\"", 0);
int len = ((nextspace == -1) || (space1 < nextspace)
? space1
: nextspace);
if (numidx != 0) wmemcpy(&num[numidx++], L" ", 1);
wmemcpy(&num[numidx], &text[i+strnum], len);
numidx += len;
int nextnum =
strmatch(&text[i+strnum], L"strong:", 0);
strnum = (nextnum != -1
? strnum + nextnum + 7
: -1);
}
/* 3. determine if tag is empty closed-element,
* if so, rewrite in place by making wordlen
* below zero, otherwise get word boundaries */
int wordstart = endbracket + 1;
int endtag =
(endbracket > strmatch(&text[i], L"/", 0)
? endbracket + 1
: strmatch(&text[i], L"</w>", 0));
// 4. determine word boundaries & rewrite
int wordlen = endtag - wordstart;
wchar_t* word = (wchar_t*) malloc(sizeof(wchar_t*)
* (wordlen == 0 ? 1 : wordlen));
if (! word) wrapup(1,
"Error rewriting markup in renderText.\n");
wmemcpy(word, &text[i+wordstart], wordlen);
// rewrite
int start = i + endtag - wordlen - numidx - 4;
wmemcpy(&text[start], L"\"", 1);
wmemcpy(&text[start + 1], L">", 1);
wmemcpy(&text[start + 2], word, wordlen);
wmemcpy(&text[start + 2 + wordlen], L"[", 1);
wmemcpy(&text[start + 3 + wordlen], num, numidx);
wmemcpy(&text[start + 3 + wordlen + numidx], L"]", 1);
// clean up so we can do this again
free(num);
free(word);
// kept for debugging
//fwprintf(stderr, L"(I): %ls\n", text);
} else if ((! strmatch(&text[i], L"<q marker", 1))
&& (p == 1) && (redletter == 1)) {
// start of redletter bracket
makered = 1;
} else if ((! strmatch(&text[i], L"<transChange type=\"added\"", 1))
&& (p == 1) && (nontextual == 1)) {
// start of interpretive text bracket
makeital = 1;
}
// don't print the angle bracket
continue;
} // markup check
if (p == 0) {
// handle word wrapping
if (text[i] == ' ') {
/* if under the buffer width, note index & continue
* if over, set the preceeding space to a newline */
if (linelength >= bufsizex) {
text[lastspaceidx] = '\n';
numlines++;
// start counting from the beginning of the last word
linelength = printable - lastprintspace;
} else {
lastspaceidx = i;
lastprintspace = printable;
}
}
// reset for newlines
if (text[i] == '\n') {
/* check to see if we're still over the length but hit a
* newline before a space */
if (linelength >= bufsizex) {
text[lastspaceidx] = '\n';
numlines++;
}
numlines++;
linelength = 0;
lastspaceidx = i;
lastprintspace = printable;
}
linelength++;
// various word wrapping debugging statements
//fprintf(stderr, "[ %c ] : 0x%X\n", text[i], text[i]);
//fprintf(stderr, "Char: %c I: %d Numlines: %d "
// "Linelength: %d Lastspaceidx: %d\n",
// text[i], printable, numlines, linelength, lastspaceidx);
} else {
// printing -- pull out the single character we care about
wchar_t single[] = L"\0\0";
wcsncpy(&single[0], &text[i], 1);
wattrset(pad, COLOR_PAIR(makered)
| (makeital ? A_ITALIC : 0));
waddwstr(pad, single);
}
printable++;
} // text loop
// text rewriting debugging
//fwprintf(stderr, L"\n(F): %ls\n\n\n", text);
if (p == 0) {
// now that we have the number of newlines, create the pad to fit
bufsizey = numlines;
pad = newpad(bufsizey + 1, bufsizex);
if (! pad) wrapup(1, "Error constructing pad in renderText.\n");
scrollok(pad, true);
wmove(pad, 0, 0);
}
} // workhorse
free(text);
redraw();
}
void pane::setTitle(const char* newtitle) {
// NOTE -- hardcoded length for title string
if (strlen(newtitle) < 40) {
strcpy(titlebar, newtitle);
} else {
strncpy(titlebar, newtitle, 36);
strcpy(titlebar+36, "...");
}
}
void pane::retitle() {
(hasFocus ? wattrset(win, A_STANDOUT) : standend());
mvwprintw(win, 0, 1, "%s", " ");
mvwprintw(win, 0, 3, "%s", titlebar);
mvwprintw(win, 0, 3+strlen(titlebar), "%s", " ");
wstandend(win);
}
void pane::redraw(bool borders) {
if (borders) {
box(win, 0, 0);
retitle();
}
wrefresh(win);
if (is_pad(pad)) {
prefresh(pad, buflocy, buflocx, pady, padx, pady + height - 3,
padx + width - 1);
} else {
wrefresh(pad);
}
}
void pane::nextPage() {
buflocy = (bufsizey - buflocy > 2 * padrows
? buflocy + padrows - 1
: bufsizey - padrows);
redraw();
}
void pane::scrollDown() {
if (bufsizey - buflocy > padrows) buflocy++;
redraw();
}
void pane::scrollUp() {
if (buflocy > 0) buflocy--;
redraw();
}
void pane::prevPage() {
buflocy = (buflocy > padrows ? buflocy - padrows : 0);
redraw();
}
void pane::toggleFocus() {
hasFocus = !hasFocus;
retitle();
redraw();
}
int pane::loadMenu(starray opts) {
// instruction text
const char* inst = "(Up/Down - scroll PgUp/PgDn - page up/down"
" Enter - select ESC - cancel)";
pady = printInstructions(2, inst);
// construct list of items
ITEM **items = (ITEM**) malloc(sizeof(ITEM*) * (opts.length+1));
if (! items) wrapup(1, "Error allocating memory in loadMenu.\n");
for (int i = 0; i < opts.length; i++)
items[i] = new_item((opts.strings)[i], (opts.strings)[i]);
items[opts.length] = (ITEM*) NULL;
// pad is a ncurses subwindow - set coords relative to win's X & Y
pady++;
padx = 4;
padrows = height - 6;
padcols = width - 6;
pad = derwin(win, padrows, padcols, pady, padx);
keypad(pad, true);
// create the menu & header
MENU *menu = new_menu((ITEM**) items);
menu_opts_off(menu, O_SHOWDESC);
set_menu_win(menu, win);
set_menu_sub(menu, pad);
set_menu_mark(menu, "-> ");
set_menu_format(menu, padrows, 1); // set scrolling
post_menu(menu);
redraw();
// hit escape to exit without a choice
int ch;
while (((ch = getch()) != 27) && (ch != KEY_RESIZE)) {
switch (ch) {
case KEY_PPAGE:
menu_driver(menu, REQ_SCR_UPAGE);
break;
case KEY_UP:
menu_driver(menu, REQ_UP_ITEM);
break;
case KEY_DOWN:
menu_driver(menu, REQ_DOWN_ITEM);
break;
case KEY_NPAGE:
menu_driver(menu, REQ_SCR_DPAGE);
break;
case '\n': // enter
int retval = item_index(current_item(menu));
menuClean(menu, items, opts.length);
return retval;
break;
}
redraw();
}
// user backed out, return nothing
menuClean(menu, items, opts.length);
return (ch == KEY_RESIZE ? -2 : -1);
}
int pane::printInstructions(int y, const char* inst) {
// NOTE -- starting indentation is hardcoded at two characters in
int strctr = 0;
int line = width - 3;
while (strlen(&inst[strctr]) > line) {
// set write length to be up to the last space, for word wrapping
while ((inst[line] != ' ') && (line > 0)) line--;
if (line == 0) line = width - 3;
mvwaddnstr(win, y++, 2, &inst[strctr], line);
strctr += line;
line = width - 3;
}
if (strlen(inst) != strctr)
mvwaddnstr(win, y++, 2, &inst[strctr], -1);
return y;
}
starray pane::loadForm(starray inputs, const char* secondinst) {
/* instruction text -- add text using mvwaddnstr because we don't know how
* large the window is */
const char* firstinst = "(Up/Down - scroll Enter - select ESC - cancel)";
pady = printInstructions(2, firstinst);
pady = printInstructions(pady, secondinst);
// pad is a ncurses subwindow - set coords relative to win's X & Y
padx = 40;
padrows = height - 5;
padcols = width - 45;
pad = derwin(win, padrows, padcols, pady, padx);
keypad(win, true);
curs_set(1);
// find out how many valid fields we have
int validfields = 1;
for (int i = 0; i < inputs.length; i++) {
// find out how many extra lines we'll need to put in the form
if (strcmp((inputs.strings)[i], "SPACE") != 0) validfields++;
}
FIELD *fields[validfields];
// construct list of fields
int yoffset = 1;
int fieldnum = 0;
for (int i = 0; i < inputs.length; i++) {
if (strcmp((inputs.strings)[i], "SPACE") == 0) {
// put in the space
yoffset++;
continue;
}
fields[fieldnum] = new_field(1, 30, yoffset, 1, 0, 0);
mvwprintw(win, yoffset + pady, 2, "%s", (inputs.strings)[i]);
yoffset++;
set_field_back(fields[fieldnum], A_UNDERLINE);
field_opts_off(fields[fieldnum], O_AUTOSKIP);
fieldnum++;
}
fields[validfields-1] = NULL;
// create the form
FORM *form = new_form(fields);
set_form_win(form, win);
set_form_sub(form, pad);
post_form(form);
// show everything
redraw();
// hit escape or resize terminal to exit without a choice
int ch;
starray retval;
retval = stinit(retval);
while (((ch = wgetch(win)) != 27) && (ch != KEY_RESIZE)) {
switch (ch) {
case KEY_UP:
form_driver(form, REQ_PREV_FIELD);
form_driver(form, REQ_END_LINE);
break;
case KEY_DOWN:
form_driver(form, REQ_NEXT_FIELD);
form_driver(form, REQ_END_LINE);
break;
case KEY_BACKSPACE:
case 127: // these are all backspace - it's terminfo dependent
case '\b':
form_driver(form, REQ_DEL_PREV);
break;
case '\n': // enter key - exit out here
// force validation to ensure last field is written to buffer
form_driver(form, REQ_VALIDATION);
// get inputs
for (int i = 0; i < validfields-1; i++) {
char* inp = strdup(field_buffer(fields[i], 0));
trim(inp);
retval = stappend(retval, inp);
}
// clean up
formClean(form, fields, validfields);
return retval;
break;
default:
// add character to input
form_driver(form, ch);
break;
}
}
// user backed out, return nothing
formClean(form, fields, validfields);
if (ch == KEY_RESIZE) retval.length = -1;
return retval;
}
void pane::menuClean(MENU* menu, ITEM** items, int numitems) {
unpost_menu(menu);
free_menu(menu);
for (int i = 0; i < numitems + 1; i++) free_item(items[i]);
free(items);
}
void pane::formClean(FORM* form, FIELD** fields, int numfields) {
unpost_form(form);
free_form(form);
curs_set(0);
for (int i = 0; i < numfields; i++) free_field(fields[i]);
}
void pane::setModule(const char* newtitle, const char* newmod,
int keytype) {
mod.modname = newmod;
mod.keytype = keytype;
setTitle(newtitle);
// update titlebar
redraw(true);
}
void pane::setKey(const char* newkey) {
mod.searchkey = newkey;
setSearch(0, "Gen 1:1 - Rev 22:21");
}
void pane::setSearch(int type, const char* scope) {
mod.searchtype = type;
mod.scope = scope;
}
modkey pane::getModkey() {
return mod;
}

121
pane.h Normal file
View File

@ -0,0 +1,121 @@
// Part of the Scriptura program
// pane.h -- header file for pane class
#ifndef PANE
#define PANE
#include <menu.h>
#include <form.h>
#include <string>
#include <swconfig.h>
#include "free.h"
// pane - defines a window complex to display data retrieved from sword
class pane {
WINDOW *win; // the window drawing the bounding box
char titlebar[40]; // window titlebar
bool hasFocus; // holds window focus status
WINDOW *pad; /* typically a pad holding buffer text, but may
* instead be a window holding a menu or form */
int padx, pady; // the pad bounding box upper left corner
int padrows, padcols; // the pad bounding box dimensions
// if pad is an ncurses pad, then:
int buflocx, buflocy; // the pad buffer location (ie. where we are)
int bufsizex, bufsizey; // the pad buffer size (height & width)
modkey mod; // module key associated with this pane
char* rawtext; // copy of unprocessed text the pane is showing
/* retitle
* refresh the title of the window */
void retitle();
/* renderText
* take a text to display and format it for display, also creating the pad
* to hold it */
void renderText();
/* printInstructions
* for floating panes, print out instruction lines that fit in the window
* bounds - returns the next available row in the window to print on */
int printInstructions(int y, const char* inst);
public:
int x, y; // starting X & Y locations on screen
int height, width; // size of pane (the outer window)
/* constructor
* Takes as input the upper left (Y,X) coord for the window, its number of
* lines & columns, and the text for the titlebar */
pane(int starty, int startx, int lines, int cols, const char* title);
/* resize
* resize the window & pad, in the case of terminal resizing */
void resize(int starty, int startx, int lines, int cols);
/* setTitle
* sets the title of the window & truncates if too long */
void setTitle(const char* newtitle);
/* loadText
* Loads text into the panel. */
void loadText(const char* stext);
/* redraw
* Update the window whenever there is a change to make. Optionally takes a
* boolean that will refresh the outer window border */
void redraw(bool borders = false);
/* pagination functions - move up or down a line or a page in the window */
void nextPage();
void scrollDown();
void scrollUp();
void prevPage();
/* toggleFocus
* Toggles whether the pane has focus. Will refresh the window titlebar. */
void toggleFocus();
/* loadMenu
* given an option list, create a menu and return the selected list index */
int loadMenu(starray opts);
/* loadForm
* given an array of strings, and an instruction line, create a form and
* return the entered text - will return with starray.length = 0 if user
* backs out */
starray loadForm(starray inputs, const char* secondinst);
/* menuclean
* given a menu, list of items, and number of items, unpost & free up
* allocated memory */
void menuClean(MENU* menu, ITEM** items, int numitems);
/* formClean
* given a form, fields, and number of fields, free up allocated memory */
void formClean(FORM* form, FIELD** fields, int numfields);
/* setModule
* change the module associated with this pane - stores the module index
* and switches the pane title to be something else */
void setModule(const char* newtitle, const char* newmod, int keytype);
/* setKey
* change the searchkey associated with this pane */
void setKey(const char* newkey);
/* setSearch
* set the search parameters stored in the modkey for this pane */
void setSearch(int type, const char* scope);
/* getModkey
* gets the modkey associated with this pane */
modkey getModkey();
};
#endif

216
scabbard.cpp Normal file
View File

@ -0,0 +1,216 @@
// Part of the Scriptura program
// scabbard.cpp - manage interface to Sword
// it's funny, right?
#include <iostream>
#include <string.h>
#include "scabbard.h"
scabbard::scabbard() {
/* store what markup information the user has requested be shown
* SWBuf.c_str() returns the ascii code 48 for '0', so we have to do some
* math to get the proper boolean setting */
markred = parseConf(config["markup"]["redletters"]);
markstrongs = parseConf(config["markup"]["strongs"]);
markfoot = parseConf(config["markup"]["footnotes"]);
/* everything following is based on constructing the menu used to display
* to the reader about what modules the system has - start with a
* temporary array of module types */
int tmpnum = 4;
modtype tmpmods[4];
strcpy(tmpmods[0].label, "Generic Books");
tmpmods[0].keytype = 1;
strcpy(tmpmods[1].label, "Biblical Texts");
tmpmods[1].keytype = 0;
strcpy(tmpmods[2].label, "Lexicons / Dictionaries");
tmpmods[2].keytype = 2;
strcpy(tmpmods[3].label, "Commentaries");
tmpmods[3].keytype = 0;
// need some throwaway ints
int index[tmpnum];
for (int i = 0; i < tmpnum; i++) index[i] = 0;
// initialize other parts of modtype struct
for (int i = 0; i < tmpnum; i++) {
tmpmods[i].modlen = 1;
tmpmods[i].modlist =
(sword::SWModule**) malloc(sizeof(sword::SWModule));
if (! tmpmods[i].modlist)
wrapup(1, "Error allocating memory for scabbard\n");
}
// get list of installed tmpmods and store
for (iter = swrd.Modules.begin(); iter != swrd.Modules.end(); iter++) {
sword::SWBuf modName = iter->first;
sword::SWModule *mod = iter->second;
for (int i = 0; i < tmpnum; i++) {
// determine which classification of module this is
if (! strcmp(mod->getType(), tmpmods[i].label)) {
// increase array size if needed
if (tmpmods[i].modlen == index[i]) {
void* extarray = realloc(tmpmods[i].modlist,
sizeof(sword::SWModule) * (tmpmods[i].modlen+1));
if (extarray != NULL) {
tmpmods[i].modlist = (sword::SWModule**) extarray;
} else {
wrapup(1, "Error allocating memory for scabbard\n");
}
tmpmods[i].modlen++;
}
// catalog the module
(tmpmods[i].modlist)[index[i]] = mod;
index[i]++;
}
}
}
/* if a module type has no modules in it, we don't want to look at it again
* - do this by copying our temp array to the final array if elements
* exist */
nummods = 0;
for (int i = 0; i < tmpnum; i++) {
if (index[i] > 0) {
modules[nummods] = tmpmods[i];
nummods++;
}
}
}
const char* scabbard::parseVerses(sword::SWModule *text, sword::ListKey lk) {
// set output filters for text based on what we want to have
if (markred) {
text->addRenderFilter(new sword::OSISRedLetterWords());
text->addRenderFilter(new sword::GBFRedLetterWords());
}
if (markstrongs) text->addRenderFilter(new sword::OSISStrongs());
if (markfoot) {
text->addRenderFilter(new sword::OSISFootnotes());
text->addRenderFilter(new sword::GBFFootnotes());
}
// retrieve
sword::SWBuf excerpt = sword::SWBuf("", 0);
for (lk = sword::SW_POSITION(POS_TOP); !lk.popError(); lk++) {
text->setKey(lk);
// add verse heading
excerpt.append(lk.getShortText());
sword::VerseKey vk = (sword::VerseKey) lk.getElement();
if (vk.getVerse() < 10) excerpt.append(" ");
excerpt.append(" -- ");
/* if no filters selected, use stripText, otherwise we have as the
* default content whatever filters are written into the module */
if (markred + markstrongs + markfoot == 0) {
excerpt.append(text->stripText());
} else {
excerpt.append(text->renderText());
}
excerpt.append("\n");
}
excerpt.append("\0");
// excerpt will free itself on exit, make a copy to send back
const char* retval = strdup(excerpt.c_str());
return retval;
}
const char* scabbard::directSearch(sword::SWModule *text, modkey mod) {
text->setKey(mod.searchkey);
text->renderText(); // give the best fit to the searchkey
sword::SWBuf buf = sword::SWBuf("", 0);
buf.append(text->getKeyText());
buf.append("\n");
buf.append(text->getRawEntry());
buf.append("\0");
// buf will free itself on exit, make a copy
const char* retval = strdup(buf.c_str());
return retval;
}
starray scabbard::getModClassifications() {
starray retval;
retval = stinit(retval);
for (int i = 0; i < nummods; i++)
retval = stappend(retval, modules[i].label);
return retval;
}
starray scabbard::getModDescriptions(int type) {
starray retval;
retval = stinit(retval);
for (int i = 0; i < modules[type].modlen; i++)
retval = stappend(retval,
(modules[type].modlist)[i]->getDescription());
return retval;
}
const char* scabbard::getModName(int modt, int mod) {
return (modules[modt].modlist)[mod]->getName();
}
const char* scabbard::getModDescription(int modt, int mod) {
return (modules[modt].modlist)[mod]->getDescription();
}
int scabbard::getKeyType(int modt) {
return modules[modt].keytype;
}
const char* scabbard::getSpan(modkey mod) {
// get module and material specified
sword::SWModule *text = swrd.getModule(mod.modname);
// with the absence of certain config settings, getModule may return 0
if (text == 0) return "";
if (mod.keytype == 0) {
sword::VerseKey *key = (sword::VerseKey*) text->createKey();
sword::ListKey lk =
key->parseVerseList(mod.searchkey, mod.searchkey, true);
delete(key);
return parseVerses(text, lk);
} else return directSearch(text, mod);
}
const char* scabbard::search(modkey mod) {
sword::SWModule *text = swrd.getModule(mod.modname);
// with the absence of certain config settings, getModule may return 0
if (text == 0) return "";
if (mod.keytype == 0) {
sword::VerseKey *key = (sword::VerseKey*) text->createKey();
sword::SWKey *clone =
(key->parseVerseList(mod.scope, mod.scope, true)).clone();
sword::ListKey lk =
text->search(mod.searchkey, mod.searchtype, 0, clone);
const char* retval = parseVerses(text, lk);
delete(text);
delete(key);
delete(clone);
return retval;
} else return directSearch(text, mod);
}
/* really old code in case we need to pull output from diatheke
FILE *modlist = popen("diatheke -b system -k modulelist", "r");
char buf[1024];
fread(buf, sizeof(char), 1024, modlist);
pclose(modlist); */

110
scabbard.h Normal file
View File

@ -0,0 +1,110 @@
// Part of the Scriptura program
// scabbard.h -- header for Scabbard
#ifndef SCABBARD
#define SCABBARD
#include <swmgr.h>
#include <swmodule.h>
#include <swconfig.h>
#include <swbuf.h>
#include <versekey.h>
#include <treekey.h>
#include <osisredletterwords.h>
#include <osisstrongs.h>
#include <osisfootnotes.h>
#include <gbfredletterwords.h>
#include <gbffootnotes.h>
// unimplemented extras
//#include <osismorph.h>
//#include <osislemma.h>
//#include <osisheadings.h>
#include "free.h"
// structure for associating a Sword module type to a list of modules
typedef struct modstruct {
char label[25]; // the module type
int keytype; // 0 - versekey, 1 - treekey, 2 - direct
int modlen; // length of module list
sword::SWModule ** modlist; // list of modules
} modtype;
// scabbard - handles our interface to the Sword library
class scabbard {
// Sword-specific data structures
sword::SWMgr swrd;
sword::ModMap::iterator iter;
/* module data fields of interest
* name - internal name
* description - full text name
* type - class of module */
int nummods; // number of module types that contain modules
// flags for various forms of markup for output text
int markred;
int markstrongs;
int markfoot;
/* parseVerses
* given a ListKey, parse it and return the text of the passages
* contained therein */
const char* parseVerses(sword::SWModule *text, sword::ListKey lk);
/* directSearch
* for modules not keyed to verse, return the closest (or exact) match in
* the module to the search term specified in modkey */
const char* directSearch(sword::SWModule *text, modkey mod);
public:
/* constructor - takes as input various preferences on text markup from
* our config file */
scabbard();
/* struct to hold listing of different modules - each modtype corresponds
* to a different type of module - see comments above */
modtype modules[4];
/* getModClassifications
* returns the list of the module types known to the system */
starray getModClassifications();
/* getModDescriptions
* given an integer index from getModClassification, return the module
* descriptions for all modules of that type */
starray getModDescriptions(int type);
/* getModName
* given integer indices from getModClassifications and getModDescriptions,
* return the module name for the module in question */
const char* getModName(int modt, int mod);
/* getModDescription
* given integer indices from getModClassifications and getModDescriptions,
* return the module description for the module */
const char* getModDescription(int modt, int mod);
/* getKeyType
* given an integer index from getModClassifications, return the flag for
* which key type for searching we're supposed to use */
int getKeyType(int modt);
/* getSpan
* given a modkey, return the chapter containing the passage */
const char* getSpan(modkey mod);
/* search
* given a modkey containing a search term, return the search results */
const char* search(modkey mod);
};
#endif

419
scriptura.cpp Normal file
View File

@ -0,0 +1,419 @@
/* Scriptura - ncurses based Bible study software using libsword
* Authored by Paul Mosier */
// system
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ncurses.h>
#include <unistd.h>
#include <locale.h>
// third-party
#include <swconfig.h>
// mine
#include "free.h"
#include "pane.h"
#include "scabbard.h"
/* --[ ASSISTS / GLOBALS ]-- */
int NUMPANES;
int halfcols, halflines;
int floatx, floaty, floatheight, floatwidth;
int startx1, starty1, startx2, starty2;
int panelength, panewidth;
sword::SWConfig config;
// refresh every portion of a list of panes we are given
void wipeit(pane* panes) {
for (int i = 0; i < NUMPANES; i++) panes[i].redraw(true);
}
// display a form field
starray showForm(const char* title, starray inputs, const char* secondinst,
int floaty, int floatx, int floatheight, int floatwidth) {
// pull up the floating form
pane form = {floaty, floatx, floatheight, floatwidth, title};
starray ret = form.loadForm(inputs, secondinst);
// sanitize input? -- if (ret.length != 0)
return ret;
}
// save the config array -- we abstract this out in case this changes
void saveit(char* configfile) {
/* This is clumsy but we have to use this particular constructor for
* config() so we can save to disk. The global config object uses a
* different constructor. */
sword::SWConfig newconfig(configfile);
newconfig.augment(config);
newconfig.save();
}
// set various standard screen landmarks
void landmarks() {
// place background text
mvprintw(LINES - 1 , COLS - 20, "%s", "? - help q - quit");
refresh();
// split up the screen
halfcols = COLS / 2;
halflines = LINES / 2;
// floating window measurements
floatx = 3;
floaty = 3;
floatheight = LINES - 6;
floatwidth = COLS - 6;
// define our main windows and their borders
if (! strcmp(config["layout"]["panels"], "v")) {
// vertical layout
startx1 = starty1 = startx2 = 0;
starty2 = halflines;
panelength = LINES - halflines - 1;
panewidth = COLS;
} else {
// horizontal layout
startx1 = starty1 = starty2 = 0;
startx2 = halfcols;
panelength = LINES - 1;
panewidth = COLS - halfcols;
}
}
// resize the standard screen
void doresize(pane* p) {
// terminal window was resized
clear();
// reset standard screen landmarks
landmarks();
// reset and refresh main panes
p[0].resize(starty1, startx1, panelength, panewidth);
p[1].resize(starty2, startx2, panelength, panewidth);
wipeit(p);
}
/* --[ MAIN ]-- */
int main(int argc, char** argv) {
// if help argument supplied, give text & exit
if ((argc > 1) &&
((! strcmp(argv[1], "-h")) || (! strcmp(argv[1], "--help")))) {
printf("%s\n", CLITEXT);
exit(0);
}
// read in our configuration file, or whatever the user supplies
char* homedir = getenv("HOME");
if (homedir == NULL) {
printf("No home directory, pilgrim.\n");
perror("(Could not find $HOME.)\n");
return -1;
}
char* configfile;
asprintf(&configfile, "%s%s", homedir, "/.config/scriptura.ini");
if ((argc > 2) && (! strcmp(argv[1], "-c"))) {
free(configfile);
configfile = argv[2];
if (access(configfile, R_OK|W_OK) == -1) {
perror("Error loading supplied configuration file");
return -1;
}
} else {
// configfile remains default
if (access(configfile, R_OK|W_OK) == -1) {
printf("Creating new configuration file...");
FILE *cnf = fopen(configfile, "w");
if (cnf == NULL) {
printf("\nCould not create new config file $HOME/.config/scriptura.ini\n");
printf("Please ensure this directory exists and is writable.\n");
return -1;
}
// set default module and other fields to avoid crashing
fprintf(cnf, "[defaults]\n");
fprintf(cnf, "scope=Gen 1:1 - Rev 22:21\n");
fprintf(cnf, "searchkey=2 Tim 1:7\n");
fprintf(cnf, "module=KJV\n");
fclose(cnf);
printf("done.\n");
}
}
sword::SWConfig tempconfig(configfile);
config.augment(tempconfig);
// ensure some needed config settings are in place
if (! strcmp(config["defaults"]["scope"], ""))
config["defaults"]["scope"] = "Gen 1:1 - Rev 22:21";
if (! strcmp(config["defaults"]["searchkey"], ""))
config["defaults"]["searchkey"] = "2 Tim 1:;7";
if (! strcmp(config["defaults"]["module"], ""))
config["defaults"]["module"] = "KJV";
saveit(configfile);
// NOTE -- anything after this point must use our defined exit wrapup()
/* start ncurses, disable line buffering hide cursor, and allow for fancy
* keys & so on */
initscr();
cbreak();
curs_set(0);
noecho();
start_color();
keypad(stdscr, true);
setlocale(LC_ALL, "");
// get color settings
if (! strcmp(config["markup"]["lettercolor"], "green")) {
init_pair(1, COLOR_GREEN, COLOR_BLACK);
} else if (! strcmp(config["markup"]["lettercolor"], "yellow")) {
init_pair(1, COLOR_YELLOW, COLOR_BLACK);
} else if (! strcmp(config["markup"]["lettercolor"], "magenta")) {
init_pair(1, COLOR_MAGENTA, COLOR_BLACK);
} else if (! strcmp(config["markup"]["lettercolor"], "blue")) {
init_pair(1, COLOR_BLUE, COLOR_BLACK);
} else if (! strcmp(config["markup"]["lettercolor"], "cyan")) {
init_pair(1, COLOR_CYAN, COLOR_BLACK);
} else {
init_pair(1, COLOR_RED, COLOR_BLACK);
}
// two main panes
NUMPANES = 2;
landmarks();
pane* p = (pane*) malloc(sizeof(pane) * NUMPANES);
const char* title = "Window";
if (! p) wrapup(1, "Error allocating memory for panes.\n");
p[0] = { starty1, startx1, panelength, panewidth, title };
p[1] = { starty2, startx2, panelength, panewidth, title };
pane* focustab;
focustab = &(p[0]);
focustab->toggleFocus();
/* load up a scabbard & set blank starting data - scabbard args are
* sanitized in the constructor */
scabbard scab = {};
char blank[] = "Open a text to use this window.\0";
for (int i = 0; i < NUMPANES; i++) {
if (config["defaults"]["module"] && config["defaults"]["searchkey"]) {
// this isn't technically the title, but it's what we have now
p[i].setTitle(config["defaults"]["module"]);
p[i].loadText(scab.getSpan(p[i].getModkey()));
} else {
p[i].loadText(blank);
}
}
wipeit(p);
// loop for input
int ch;
while ((ch = getch()) != 'q') {
switch (ch) {
case '\t': {
// switch pane focus
focustab->toggleFocus();
focustab = (focustab == &(p[0]) ? &(p[1]) : &(p[0]));
focustab->toggleFocus();
break; }
case KEY_NPAGE:
focustab->nextPage();
break;
case KEY_DOWN:
focustab->scrollDown();
break;
case KEY_UP:
focustab->scrollUp();
break;
case KEY_PPAGE:
focustab->prevPage();
break;
case KEY_RESIZE:
doresize(p);
break;
case 'f': {
// toggle footnotes
int footnotes = ! parseConf(config["markup"]["footnotes"]);
config["markup"]["footnotes"] = footnotes + '0';
wipeit(p);
saveit(configfile);
break; }
case 'g': {
// go to a particular passage
starray goinst;
goinst = stinit(goinst);
goinst = stappend(goinst, "Go to: ");
const char* gotitle = "Go to passage";
const char* secondinst = "Enter passage to retrieve; "
"abbreviations & disjoint passage selections are okay.";
starray ret = showForm(gotitle, goinst, secondinst, floaty,
floatx, floatheight, floatwidth);
if (ret.length == -1) {
doresize(p);
break;
}
if ((ret.length != 0) && (strlen((ret.strings)[0]) > 0)) {
// user entered something that's not a blank string
focustab->setKey((ret.strings)[0]);
focustab->loadText(scab.getSpan(focustab->getModkey()));
}
wipeit(p);
break; }
case 'n': {
// toggle non-textual words
int textual = ! parseConf(config["markup"]["nontextual"]);
config["markup"]["nontextual"] = textual + '0';
wipeit(p);
saveit(configfile);
break; }
case 'o': {
// load a module into the current pane
const char* typetitle = "Choose a module type";
pane menupane = {floaty, floatx, floatheight, floatwidth,
typetitle };
starray mc = scab.getModClassifications();
int modclass = menupane.loadMenu(mc);
if (modclass == -1) {
wipeit(p);
break;
} else if (modclass == -2) {
doresize(p);
break;
}
const char* modtitle = "Choose a module";
menupane = {floaty, floatx, floatheight, floatwidth, modtitle};
starray mds = scab.getModDescriptions(modclass);
int mod = menupane.loadMenu(mds);
if (mod == -1) {
wipeit(p);
break;
} else if (mod == -2) {
doresize(p);
break;
}
focustab->setModule(scab.getModDescription(modclass, mod),
scab.getModName(modclass, mod),
scab.getKeyType(modclass));
focustab->loadText(scab.getSpan(focustab->getModkey()));
wipeit(p);
break; }
case 'r': {
// toggle redletter
int redletter = ! parseConf(config["markup"]["redletters"]);
config["markup"]["redletters"] = redletter + '0';
wipeit(p);
saveit(configfile);
break; }
case 's': {
// search
starray inst;
inst = stinit(inst);
/* these happen to be in the same order as the integer key used
* by Sword to determine the search type, and this may be
* subject to breakage if those integer values change */
inst = stappend(inst, "Search for this word or part:");
inst = stappend(inst, "Search for this phrase:");
inst = stappend(inst, "Search for multiple words:");
inst = stappend(inst, "Search for attribute (eg Strongs#):");
inst = stappend(inst, "SPACE");
inst = stappend(inst, "Restrict search to this text:");
const char* title = "Search";
const char* secondinst = "Enter your search on the correct line"
" and specify the scope if needed.";
starray ret = showForm(title, inst, secondinst, floaty,
floatx, floatheight, floatwidth);
if (ret.length == -1) {
doresize(p);
break;
}
if (ret.length != 0) {
/* user entered something - get first field with data and
* the search scope (the last item), if any */
int i = 0;
for (i = 0; i < ret.length-1; i++) {
// user entered a scope but no search
//if (i == ret.length - 1) break;
if (strcmp((ret.strings)[i], "") != 0) {
focustab->setKey((ret.strings)[i]);
focustab->setSearch(i * -1,
(ret.strings)[ret.length-1]);
break;
}
}
if (i != ret.length - 1)
focustab->loadText(scab.search(focustab->getModkey()));
}
wipeit(p);
break; }
case 't': {
// toggle Strong's numbers
int strongs = ! parseConf(config["markup"]["strongs"]);
config["markup"]["strongs"] = strongs + '0';
wipeit(p);
saveit(configfile);
break; }
case 'w': {
// toggle raw text
int raw = ! parseConf(config["markup"]["rawtext"]);
config["markup"]["rawtext"] = raw + '0';
wipeit(p);
saveit(configfile);
break; }
case '?': {
// display help text
clear();
addstr(HELPTEXT);
getch();
wipeit(p);
break; }
case 'q':
// quit - we shouldn't get here
break;
} // switch
} // input loop
// go away cleanly
wrapup(0, NULL);
// shouldn't get here
return 0;
}

35
scriptura.ini Normal file
View File

@ -0,0 +1,35 @@
# Default configuration file
# Part of the Scriptura project
# default section must be present and is reverified on every run
[defaults]
# which module to load by default - this should be the abbreviation used by the Sword module
module=KJV
# When searching the Bible, what default portions are you searching - should be in standard Biblical notation format
scope=Gen 1:1 - Rev 22:21
# What verse are you loading on startup - also standard Biblical notation
searchkey=Mat 5:5
# general ncurses layout
[layout]
# should panels be arranged vertically 'v' or horizontally 'h'
panels=v
# text markup options - most of these can be set during runtime, and are dependent on what data is present in the module
[markup]
# show footnotes (0 or 1)
footnotes=1
# if showing the words of Jesus in a different color, what color is used - this should be a standard ncurses color
lettercolor=cyan
# if a translation has identified words as not part of the original text, do we italicize it (0 or 1)
nontextual=0
# ignore all other markup options and give us the raw text stored in the module (0 or 1)
rawtext=0
# do we show the words of Jesus in a separate color (0 or 1)
redletters=1
# if the module contains Strong's numbers, do we display them (0 or 1)
strongs=0