summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/doc/latex/songs/songidx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/doc/latex/songs/songidx')
-rw-r--r--Master/texmf-dist/doc/latex/songs/songidx/Makefile16
-rw-r--r--Master/texmf-dist/doc/latex/songs/songidx/authidx.c488
-rw-r--r--Master/texmf-dist/doc/latex/songs/songidx/bible.can2
-rw-r--r--Master/texmf-dist/doc/latex/songs/songidx/catholic.can2
-rw-r--r--Master/texmf-dist/doc/latex/songs/songidx/chars.h137
-rw-r--r--Master/texmf-dist/doc/latex/songs/songidx/fileio.c122
-rw-r--r--Master/texmf-dist/doc/latex/songs/songidx/fileio.h54
-rw-r--r--Master/texmf-dist/doc/latex/songs/songidx/greek.can2
-rw-r--r--Master/texmf-dist/doc/latex/songs/songidx/protestant.can2
-rw-r--r--Master/texmf-dist/doc/latex/songs/songidx/scripidx.c1105
-rw-r--r--Master/texmf-dist/doc/latex/songs/songidx/songidx.c270
-rw-r--r--Master/texmf-dist/doc/latex/songs/songidx/songidx.h53
-rw-r--r--Master/texmf-dist/doc/latex/songs/songidx/songidx.lua1070
-rw-r--r--Master/texmf-dist/doc/latex/songs/songidx/songsort.c162
-rw-r--r--Master/texmf-dist/doc/latex/songs/songidx/tanakh.can2
-rw-r--r--Master/texmf-dist/doc/latex/songs/songidx/titleidx.c379
-rw-r--r--Master/texmf-dist/doc/latex/songs/songidx/vsconfig.h116
17 files changed, 1075 insertions, 2907 deletions
diff --git a/Master/texmf-dist/doc/latex/songs/songidx/Makefile b/Master/texmf-dist/doc/latex/songs/songidx/Makefile
deleted file mode 100644
index d8cd7cf226a..00000000000
--- a/Master/texmf-dist/doc/latex/songs/songidx/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-srcdir = .
-CC = cc
-CFLAGS = -I$(srcdir)
-LDFLAGS =
-
-all: songidx
-
-.SUFFIXES:
-.SUFFIXES: .c .o
-
-songidx: *.h $(patsubst %.c,%.o,$(wildcard *.c))
- $(CC) $(CFLAGS) $(LDFLAGS) $(filter %.o,$^) -o $@
-
-clean:
- -rm $(DESTDIR)*.o $(DESTDIR)songidx
-
diff --git a/Master/texmf-dist/doc/latex/songs/songidx/authidx.c b/Master/texmf-dist/doc/latex/songs/songidx/authidx.c
deleted file mode 100644
index 2f6a7e1e00b..00000000000
--- a/Master/texmf-dist/doc/latex/songs/songidx/authidx.c
+++ /dev/null
@@ -1,488 +0,0 @@
-/* Copyright (C) 2012 Kevin W. Hamlen
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * The latest version of this program can be obtained from
- * http://songs.sourceforge.net.
- */
-
-
-/* Create a LaTeX author index file from an author .dat file. */
-
-#if HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "vsconfig.h"
-#endif
-
-#include "chars.h"
-#include "songidx.h"
-#include "fileio.h"
-
-#if HAVE_STRING_H
-# include <string.h>
-#elif HAVE_STRINGS_H
-# include <strings.h>
-#endif
-
-typedef struct wordlist
-{
- struct wordlist *next;
- WCHAR *w;
-}
-WORDLIST;
-
-WORDLIST wl_and = { NULL, ws_lit("and") };
-WORDLIST wl_by = { NULL, ws_lit("by") };
-WORDLIST wl_unknown = { NULL, ws_lit("unknown") };
-
-/* wl_insert(<wordlist>,<word>)
- * Insert a word onto the head of a wordlist. */
-static void
-wl_insert(wl,w)
- WORDLIST **wl;
- const WCHAR *w;
-{
- WORDLIST *head = (WORDLIST *) malloc(sizeof(WORDLIST));
- head->next = ((*wl==&wl_and) || (*wl==&wl_by) || (*wl==&wl_unknown)) ?
- NULL : *wl;
- head->w = (WCHAR *) calloc(ws_strlen(w)+1, sizeof(WCHAR));
- ws_strcpy(head->w, w);
- *wl = head;
-}
-
-/* matchany(<string>,<wordlist>)
- * If a word in <wordlist> case-insensitively matches to a prefix of <string>,
- * and if the match concludes with whitespace, then return the length of the
- * match plus 1. Otherwise return 0.
- */
-static size_t
-matchany(s,wl)
- const WCHAR *s;
- WORDLIST *wl;
-{
- const WCHAR *s2, *w2;
-
- for (; wl; wl=wl->next)
- {
- for (s2=s, w2=wl->w; *w2; ++s2, ++w2)
- if (wc_tolower(*s2)!=wc_tolower(*w2)) break;
- if ((*w2 == wc_null) && wc_isspace(*s2)) return s2-s+1;
- }
- return 0;
-}
-
-/* matchwithin(<string>,<wordlist>)
- * Return 1 if any word in <wordlist> appears in <string> (case insensitive
- * match). */
-static char
-matchwithin(s,wl)
- const WCHAR *s;
- WORDLIST *wl;
-{
- const WCHAR *s2, *w2;
-
- for (; wl; wl=wl->next)
- {
- for (; *s; ++s)
- {
- for (s2=s, w2=wl->w; *w2; ++s2, ++w2)
- if (wc_tolower(*s2)!=wc_tolower(*w2)) break;
- if (*w2 == wc_null) return 1;
- }
- }
- return 0;
-}
-
-/* partofword(<char>)
- * Return 0 if <char> is a word-delimiter and 1 otherwise. Word-delimiters
- * are anything other than alphabetic characters, hyphens, apostrophes,
- * backslashes, and braces.
- */
-static int
-partofword(c)
- WCHAR c;
-{
- return (wc_isalpha(c) || (c==wc_apostrophe) || (c==wc_backquote)
- || (c==wc_backslash) || (c==wc_lbrace) || (c==wc_rbrace));
-}
-
-/* isjrsuffix(<string>)
- * Return 1 if <string> points to the name suffix "Jr" and 0 otherwise. */
-static int
-isjrsuffix(s)
- const WCHAR *s;
-{
- WCHAR buf[3];
-
- if (!partofword(*s) || !partofword(*(s+1)) || partofword(*(s+2)))
- return 0;
- buf[0] = *s;
- buf[1] = *(s+1);
- buf[2] = wc_null;
- return !ws_coll(buf, ws_lit("Jr"));
-}
-
-/* grabauthor(<string>,<seplist>,<afterlist>,<ignorelist>)
- * Return a string of the form "Sirname, Restofname" denoting the full name
- * of the first author found in <string>; or return NULL if no author name
- * can be found. Set <string> to point to the suffix of <string> that was
- * not parsed. The string returned (if any) is static, so successive calls
- * will overwrite it.
- *
- * Heuristics:
- * * Names are separated by punctuation (other than hyphens, periods,
- * apostrophes, or backslashes) or by the word "and" (or whatever words
- * are in seplist).
- * Special case: If a comma is followed by the abbreviation "Jr" or by a
- * roman numeral, then the comma does NOT end the author's name.
- * * If a name contains the word "by" (or anything in afterlist), then
- * everything before it is not considered part of the name. (Let's hope
- * nobody is named "By".)
- * * The author's last name is always the last capitalized word in the
- * name unless the last capitalized word is "Jr." or a roman numeral.
- * In that case the author's last name is the second-last capitalized
- * word.
- * * If an author appears to have only a first name, or if the last name
- * found according to the above heuristics is an abbreviation (ending in
- * a period), look ahead in <string> until we find someone with a last
- * name and use that one. This allows us to identify the first author in
- * a string like "Joe, Billy E., and Bob Smith" to be "Joe Smith".
- * * If the resultant name contains the word "unknown" (or any word in
- * unknownlist), it's probably not a real name. Recursively attempt to
- * parse the next author. */
-static WCHAR *
-grabauthor(authline,seplist,afterlist,unknownlist)
- const WCHAR **authline;
- WORDLIST *seplist;
- WORDLIST *afterlist;
- WORDLIST *unknownlist;
-{
- static WCHAR buf[MAXLINELEN+2], *bp;
- const WCHAR *first, *last, *suffix, *next, *scanahead, *endp;
- size_t len;
-
- /* Point "first" to the first character of the name, "last" to the first
- * character of the sirname, "suffix" to any suffix like "Jr." or "III"
- * (or NULL if there is none), and "next" to the first character beyond the
- * end of the name. */
- if (!authline) return NULL;
- for (first=*authline; (*first!=wc_null) && !partofword(*first); ++first) ;
- if (((len = matchany(first,seplist)) > 0) ||
- ((len = matchany(first,afterlist)) > 0))
- first += len;
- if (*first==wc_null) return NULL;
- last=suffix=NULL;
- for (next=first; *next; ++next)
- {
- skipesc(&next);
- if (*next==wc_comma)
- {
- for (scanahead = next+1; *scanahead==wc_space; ++scanahead) ;
- if (isjrsuffix(scanahead)) continue;
- if (ws_strchr(ws_lit("XVI"), *scanahead) &&
- !partofword(*(scanahead+ws_strspn(scanahead, ws_lit("XVI")))))
- continue;
- *authline = next+1;
- break;
- }
- else if (wc_ispunct(*next) && (*next!=wc_hyphen) && (*next!=wc_period) &&
- (*next!=wc_apostrophe) && (*next!=wc_backquote) &&
- (*next!=wc_backslash))
- {
- *authline = next+1;
- break;
- }
- if (*next == wc_space)
- {
- for (++next; *next==wc_space; ++next) ;
- if ((len = matchany(next,seplist)) > 0)
- {
- *authline=next+len;
- break;
- }
- if ((len = matchany(next,afterlist)) > 0)
- {
- first = next+len;
- next += len-1;
- last = suffix = NULL;
- continue;
- }
- if (isjrsuffix(next))
- suffix=next;
- else if (ws_strchr(ws_lit("XVI"), *next) &&
- !partofword(*(next+ws_strspn(next, ws_lit("XVI")))))
- suffix=next;
- else
- {
- scanahead = next;
- skipesc(&scanahead);
- if (wc_isupper(*scanahead))
- {
- last = next;
- suffix = NULL;
- }
- }
- --next;
- }
- }
- if (*next==wc_null) *authline = next;
-
- /* Put the sirname into the buffer first. */
- endp = NULL;
- if (last)
- {
- endp = (suffix ? suffix : next)-1;
- if (endp<last) abort();
- for (; (endp>last) && ((*endp==wc_space) || (*endp==wc_comma)); --endp) ;
- }
- if (!endp || (*endp==wc_period))
- {
- /* Here's where it gets tough. We either have a single-word name, or the
- * last name ends in a "." which means maybe it's just a middle initial or
- * other abbreviation. We could be dealing with a line like, "Billy,
- * Joe E., and Bob Smith", in which case we have to go searching for the
- * real last name. To handle this case, we will try a recursive call. */
- scanahead = *authline;
- if (grabauthor(&scanahead,seplist,afterlist,unknownlist) &&
- ((bp = ws_strchr(buf, wc_comma)) != NULL))
- /* got it! Make our old last name part of the first name. */
- last = NULL;
- else if (last)
- {
- /* Couldn't find a last name. Just use this one and hope it's okay. */
- ws_strncpy(buf, last, endp-last+1);
- bp = buf+(endp-last+1);
- }
- else
- bp = buf;
- }
- else
- {
- ws_strncpy(buf, last, endp-last+1);
- bp = buf+(endp-last+1);
- }
-
- /* Next, put the first name into the buffer. */
- endp = (last ? last : (suffix ? suffix : next))-1;
- if (endp<first) abort();
- for (; (endp>=first) && ((*endp==wc_space) || (*endp==wc_comma)); --endp) ;
- ++endp;
- if (endp>first)
- {
- if (bp > buf)
- {
- *bp++ = wc_comma;
- *bp++ = wc_space;
- }
- ws_strncpy(bp, first, endp-first);
- bp += endp-first;
- }
-
- /* Finally, put the suffix (if any) into the buffer. */
- if (suffix)
- {
- for (endp=next-1;
- (endp>=suffix) && ((*endp==wc_space) || (*endp==wc_comma));
- --endp) ;
- ++endp;
- if (endp>suffix)
- {
- if (bp > buf) *bp++ = wc_space;
- ws_strncpy(bp, suffix, endp-suffix);
- bp += endp-suffix;
- }
- }
-
- *bp = wc_null;
- if (matchwithin(buf, unknownlist))
- return grabauthor(authline,seplist,afterlist,unknownlist);
- return buf;
-}
-
-/* genauthorindex(<file>,<inname>,<outname>)
- * Read author data from file handle <file> and generate from it a LaTeX
- * author index file named <outname>.
- * Return 0 on success, 1 on warnings, or 2 on error. */
-int
-genauthorindex(fs,outname)
- FSTATE *fs;
- const char *outname;
-{
- FILE *f;
- int eof = 0;
- int arraysize, numauthors, i;
- WORDLIST *seplist=&wl_and, *afterlist=&wl_by, *ignorelist=&wl_unknown;
- SONGENTRY **authors;
- WCHAR authorbuf[MAXLINELEN], *bp;
- WCHAR songnumbuf[MAXLINELEN], linknamebuf[MAXLINELEN];
- WCHAR *thisnum, *thislink;
- const WCHAR *auth;
-
- fprintf(stderr, "songidx: Parsing author index data file %s...\n",
- fs->filename);
-
- eof = 0;
- authors = NULL;
- for (arraysize=numauthors=i=0; !eof; ++i)
- {
- if (!filereadln(fs,authorbuf,&eof)) return 2;
- if (eof) break;
- if (authorbuf[0] == wc_percent)
- {
- if (!ws_strncmp(authorbuf, ws_lit("%sep "), 5))
- wl_insert(&seplist, authorbuf + 5);
- else if (!ws_strncmp(authorbuf, ws_lit("%after "), 7))
- wl_insert(&afterlist, authorbuf + 7);
- else if (!ws_strncmp(authorbuf, ws_lit("%ignore "), 8))
- wl_insert(&ignorelist, authorbuf + 8);
- --i;
- continue;
- }
- if (!filereadln(fs,songnumbuf,&eof))
- {
- fileclose(fs);
- return 2;
- }
- if (eof)
- {
- fprintf(stderr, "songidx:%s:%d: incomplete author entry"
- " (orphan byline)\n", fs->filename, fs->lineno);
- fileclose(fs);
- return 2;
- }
- if (!filereadln(fs,linknamebuf,&eof))
- {
- fileclose(fs);
- return 2;
- }
- if (eof)
- {
- fprintf(stderr, "songidx:%s:%d: incomplete author entry"
- " (missing hyperlink)\n", fs->filename, fs->lineno);
- fileclose(fs);
- return 2;
- }
- if (((thisnum = (WCHAR *) calloc(ws_strlen(songnumbuf)+1,
- sizeof(WCHAR))) == NULL) ||
- ((thislink = (WCHAR *) calloc(ws_strlen(linknamebuf)+1,
- sizeof(WCHAR))) == NULL))
- {
- fprintf(stderr, "songidx:%s:%d: song number/link too long"
- " (out of memory)\n", fs->filename, fs->lineno);
- return 2;
- }
- ws_strcpy(thisnum, songnumbuf);
- ws_strcpy(thislink, linknamebuf);
-
- for (bp=authorbuf;
- (auth=grabauthor((const WCHAR **) &bp, seplist, afterlist,
- ignorelist)) != NULL;
- ++numauthors)
- {
- if (numauthors >= arraysize)
- {
- SONGENTRY **temp;
- arraysize *= 2;
- if (arraysize==0) arraysize=64;
- temp = (SONGENTRY **) realloc(authors,arraysize*sizeof(SONGENTRY *));
- if (!temp)
- {
- fprintf(stderr, "songidx:%s:%d: too many song authors"
- " (out of memory)\n", fs->filename, fs->lineno);
- return 2;
- }
- authors = temp;
- }
- if ((authors[numauthors] = (SONGENTRY *)
- malloc(sizeof(SONGENTRY))) == NULL)
- {
- fprintf(stderr, "songidx:%s:%d: too many song authors"
- " (out of memory)\n", fs->filename, fs->lineno);
- return 2;
- }
- if ((authors[numauthors]->title =
- (WCHAR *) calloc(ws_strlen(auth)+1, sizeof(WCHAR))) == NULL)
- {
- fprintf(stderr, "songidx:%s:%d: author name too long (out of memory)\n",
- fs->filename, fs->lineno);
- return 2;
- }
- ws_strcpy(authors[numauthors]->title, auth);
- authors[numauthors]->num = thisnum;
- authors[numauthors]->linkname = thislink;
- authors[numauthors]->idx = i;
- }
- }
- fileclose(fs);
-
- /* Sort the array by author. */
- qsort(authors, numauthors, sizeof(*authors), songcmp);
-
- /* Generate an author index LaTeX file from the sorted data.
- * Combine any entries with the same author name into a single index entry. */
- fprintf(stderr, "songidx: Generating author index TeX file %s...\n", outname);
- if (strcmp(outname,"-"))
- {
- if ((f = fopen(outname, "w")) == NULL)
- {
- fprintf(stderr, "songidx: Unable to open %s for writing.\n", outname);
- return 2;
- }
- }
- else
- {
- f = stdout;
- outname = "stdout";
- }
-
-#define TRYWRITE(x) \
- if (!(x)) \
- { \
- fprintf(stderr, "songidx:%s: write error\n", outname); \
- if (f == stdout) fflush(f); else fclose(f); \
- return 2; \
- }
-
- TRYWRITE(ws_fputs(ws_lit("\\begin{idxblock}{"), f) >= 0)
- for (i=0; i<numauthors; ++i)
- {
- if ((i>0) && !ws_coll(authors[i]->title, authors[i-1]->title))
- {
- TRYWRITE(ws_fputs(ws_lit("\\\\"), f) >= 0)
- }
- else
- {
- TRYWRITE((ws_fputs(ws_lit("}\n\\idxentry{"), f) >= 0) &&
- (ws_fputs(authors[i]->title, f) >= 0) &&
- (ws_fputs(ws_lit("}{"), f) >= 0))
- }
- TRYWRITE((ws_fputs(ws_lit("\\hyperlink{"), f) >= 0) &&
- (ws_fputs(authors[i]->linkname, f) >= 0) &&
- (ws_fputs(ws_lit("}{"), f) >= 0) &&
- (ws_fputs(authors[i]->num, f) >= 0) &&
- (ws_fputs(ws_lit("}"), f) >= 0))
- }
- TRYWRITE(ws_fputs(ws_lit("}\n\\end{idxblock}\n"), f) >= 0)
-
-#undef TRYWRITE
-
- if (f == stdout)
- fflush(f);
- else
- fclose(f);
- return 0;
-}
diff --git a/Master/texmf-dist/doc/latex/songs/songidx/bible.can b/Master/texmf-dist/doc/latex/songs/songidx/bible.can
index ed2059ec2e6..e88b292e8c4 100644
--- a/Master/texmf-dist/doc/latex/songs/songidx/bible.can
+++ b/Master/texmf-dist/doc/latex/songs/songidx/bible.can
@@ -1,4 +1,4 @@
-# Copyright (C) 2012 Kevin W. Hamlen
+# Copyright (C) 2017 Kevin W. Hamlen
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
diff --git a/Master/texmf-dist/doc/latex/songs/songidx/catholic.can b/Master/texmf-dist/doc/latex/songs/songidx/catholic.can
index 19b23f87729..d39988b5d3b 100644
--- a/Master/texmf-dist/doc/latex/songs/songidx/catholic.can
+++ b/Master/texmf-dist/doc/latex/songs/songidx/catholic.can
@@ -1,4 +1,4 @@
-# Copyright (C) 2012 Kevin W. Hamlen
+# Copyright (C) 2017 Kevin W. Hamlen
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
diff --git a/Master/texmf-dist/doc/latex/songs/songidx/chars.h b/Master/texmf-dist/doc/latex/songs/songidx/chars.h
deleted file mode 100644
index 375b0a0b4b1..00000000000
--- a/Master/texmf-dist/doc/latex/songs/songidx/chars.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/* Copyright (C) 2012 Kevin W. Hamlen
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * The latest version of this program can be obtained from
- * http://songs.sourceforge.net.
- */
-
-#ifndef CHARS_H
-#define CHARS_H
-
-#if HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "vsconfig.h"
-#endif
-
-#if HAVE_STDLIB_H
-# include <stdlib.h>
-#endif
-#if HAVE_WCHAR_H
-# include <wchar.h>
-#endif
-#if HAVE_WCTYPE_H
-# include <wctype.h>
-#endif
-
-#if HAVE_WCHAR_T
-
-typedef wchar_t WCHAR;
-
-#define wc_lit(c) (L ## c)
-#define wc_isalpha(c) iswalpha((c))
-#define wc_ispunct(c) iswpunct((c))
-#define wc_isupper(c) iswupper((c))
-#define wc_isspace(c) iswspace((c))
-#define wc_isdigit(c) iswdigit((c))
-#define wc_tolower(c) towlower((c))
-#define wc_toupper(c) towupper((c))
-
-#define ws_lit(s) ws_lit2(s)
-#define ws_lit2(s) (L ## s)
-#define ws_strlen(p) wcslen((p))
-#define ws_strcmp(p1,p2) wcscmp((p1),(p2))
-#define ws_strncmp(p1,p2,n) wcsncmp((p1),(p2),(n))
-#define ws_strcpy(p1,p2) wcscpy((p1),(p2))
-#define ws_strncpy(p1,p2,n) wcsncpy((p1),(p2),(n))
-#define ws_memmove(p1,p2,n) wmemmove((p1),(p2),(n))
-#define ws_strchr(p,c) wcschr((p),(c))
-#define ws_strspn(p1,p2) wcsspn((p1),(p2))
-#define ws_strpbrk(p1,p2) wcspbrk((p1),(p2))
-#define ws_strtol(p1,p2,n) wcstol((p1),(p2),(n))
-#define ws_coll(p1,p2) wcscoll((p1),(p2))
-#define ws_fprintf1(fh,fs,x) fwprintf((fh),(fs),(x))
-#define ws_fprintf2(fh,fs,x,y) fwprintf((fh),(fs),(x),(y))
-#define ws_fprintf3(fh,fs,x,y,z) fwprintf((fh),(fs),(x),(y),(z))
-#define ws_fgets(p,n,fh) fgetws((p),(n),(fh))
-#define ws_fputs(s,fh) fputws((s),(fh))
-#define ws_fputc(c,fh) fputwc((c),(fh))
-
-#else
-
-#include <ctype.h>
-#if HAVE_STRING_H
-# include <string.h>
-#elif HAVE_STRINGS_H
-# include <strings.h>
-#endif
-
-typedef char WCHAR;
-
-#define wc_lit(c) (c)
-#define wc_isalpha(c) isalpha((c))
-#define wc_ispunct(c) ispunct((c))
-#define wc_isupper(c) isupper((c))
-#define wc_isspace(c) isspace((c))
-#define wc_isdigit(c) isdigit((c))
-#define wc_tolower(c) tolower((c))
-#define wc_toupper(c) toupper((c))
-
-#define ws_lit(s) (s)
-#define ws_strlen(p) strlen((p))
-#define ws_strcmp(p1,p2) strcmp((p1),(p2))
-#define ws_strncmp(p1,p2,n) strncmp((p1),(p2),(n))
-#define ws_strcpy(p1,p2) strcpy((p1),(p2))
-#define ws_strncpy(p1,p2,n) strncpy((p1),(p2),(n))
-#define ws_memmove(p1,p2,n) memmove((p1),(p2),(n))
-#define ws_strchr(p,c) strchr((p),(c))
-#define ws_strspn(p1,p2) strspn((p1),(p2))
-#define ws_strpbrk(p1,p2) strpbrk((p1),(p2))
-#define ws_strtol(p1,p2,n) strtol((p1),(p2),(n))
-#define ws_coll(p1,p2) strcoll((p1),(p2))
-#define ws_fprintf1(fh,fs,x) fprintf((fh),(fs),(x))
-#define ws_fprintf2(fh,fs,x,y) fprintf((fh),(fs),(x),(y))
-#define ws_fprintf3(fh,fs,x,y,z) fprintf((fh),(fs),(x),(y),(z))
-#define ws_fgets(p,n,fh) fgets((p),(n),(fh))
-#define ws_fputs(s,fh) fputs((s),(fh))
-#define ws_fputc(c,fh) fputc((c),(fh))
-
-#endif
-
-#define wc_null wc_lit('\0')
-#define wc_hyphen wc_lit('-')
-#define wc_apostrophe wc_lit('\'')
-#define wc_backquote wc_lit('`')
-#define wc_backslash wc_lit('\\')
-#define wc_lbrace wc_lit('{')
-#define wc_rbrace wc_lit('}')
-#define wc_comma wc_lit(',')
-#define wc_period wc_lit('.')
-#define wc_space wc_lit(' ')
-#define wc_newline wc_lit('\n')
-#define wc_cr wc_lit('\r')
-#define wc_asterisk wc_lit('*')
-#define wc_hash wc_lit('#')
-#define wc_pipe wc_lit('|')
-#define wc_colon wc_lit(':')
-#define wc_semicolon wc_lit(';')
-#define wc_capA wc_lit('A')
-#define wc_percent wc_lit('%')
-#define wc_tilda wc_lit('~')
-
-#endif
-
diff --git a/Master/texmf-dist/doc/latex/songs/songidx/fileio.c b/Master/texmf-dist/doc/latex/songs/songidx/fileio.c
deleted file mode 100644
index 26bf56fcf37..00000000000
--- a/Master/texmf-dist/doc/latex/songs/songidx/fileio.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/* Copyright (C) 2012 Kevin W. Hamlen
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * The latest version of this program can be obtained from
- * http://songs.sourceforge.net.
- */
-
-#if HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "vsconfig.h"
-#endif
-
-#include "chars.h"
-#include "songidx.h"
-#include "fileio.h"
-
-#if HAVE_STRING_H
-# include <string.h>
-#endif
-
-/* fileopen(<fstate>,<filename>)
- * Open <filename> for reading, storing the file handle in <fstate>. Return
- * 1 on success or 0 on failure.
- */
-int
-fileopen(fs,fnam)
- FSTATE *fs;
- const char *fnam;
-{
- if (strcmp(fnam,"-"))
- {
- fs->f = fopen(fnam, "r");
- if (!fs->f)
- {
- fprintf(stderr, "songidx: Unable to open %s for reading.\n", fnam);
- return 0;
- }
- }
- else
- {
- fs->f = stdin;
- fnam = "stdin";
- }
- fs->filename = (char *) calloc(strlen(fnam)+1, sizeof(char));
- if (!fs->filename)
- {
- fprintf(stderr, "songidx: Out of memory!\n");
- fclose(fs->f);
- return 0;
- }
- strcpy(fs->filename, fnam);
- fs->lineno = 0;
- return 1;
-}
-
-/* fileclose(<fstate>)
- * Close file handle <fstate>.
- */
-void
-fileclose(fs)
- FSTATE *fs;
-{
- if (fs->f != stdin) fclose(fs->f);
- free(fs->filename);
- fs->f = NULL;
- fs->filename = NULL;
- fs->lineno = 0;
-}
-
-/* filereadln(<fstate>,<buffer>,<eof flag>)
- * Read a line of output into <buffer>, which should be at least MAXLINELEN
- * wide-characters in size. If the line is too long to fit into the buffer,
- * close the file and report an error. Eliminate the trailing \n from the
- * returned line. Return 1 on success or end-of-line, or 0 on failure. If
- * end-of-line, set <eof flag> to 1. */
-int
-filereadln(fs,buf,eof)
- FSTATE *fs;
- WCHAR *buf;
- int *eof;
-{
- size_t n;
-
- ++fs->lineno;
- if (!ws_fgets(buf, MAXLINELEN, fs->f))
- {
- if (!ferror(fs->f))
- {
- *eof=1;
- return 1;
- }
- fprintf(stderr, "songidx:%s:%d: read error\n", fs->filename, fs->lineno);
- fileclose(fs);
- return 0;
- }
- n = ws_strlen(buf);
- if ((n==0) || ((buf[n-1] != wc_newline) && (buf[n-1] != wc_cr)))
- {
- fprintf(stderr, "songidx:%s:%d: line too long\n", fs->filename, fs->lineno);
- fileclose(fs);
- return 0;
- }
- buf[n-1] = wc_null;
- if ((n>=2) && ((buf[n-2] == wc_newline) || (buf[n-2] == wc_cr)))
- buf[n-2] = wc_null;
- return 1;
-}
diff --git a/Master/texmf-dist/doc/latex/songs/songidx/fileio.h b/Master/texmf-dist/doc/latex/songs/songidx/fileio.h
deleted file mode 100644
index 327f5d59581..00000000000
--- a/Master/texmf-dist/doc/latex/songs/songidx/fileio.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Copyright (C) 2012 Kevin W. Hamlen
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * The latest version of this program can be obtained from
- * http://songs.sourceforge.net.
- */
-
-#ifndef FILEIO_H
-#define FILEIO_H
-
-#if HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "vsconfig.h"
-#endif
-
-#include "chars.h"
-
-#if HAVE_STDIO_H
-# include <stdio.h>
-#endif
-
-/* Define the maximum length of lines found in the input file */
-#define MAXLINELEN 1024
-
-/* FSTATE structures model the state of a FILE */
-typedef struct
-{
- FILE *f;
- char *filename;
- int lineno;
-}
-FSTATE;
-
-/* The following functions are in fileio.c */
-extern int fileopen(FSTATE *fs, const char *fnam);
-extern void fileclose(FSTATE *fs);
-extern int filereadln(FSTATE *fs, WCHAR *buf, int *eof);
-
-#endif
diff --git a/Master/texmf-dist/doc/latex/songs/songidx/greek.can b/Master/texmf-dist/doc/latex/songs/songidx/greek.can
index 289d5e2d21c..93b85c4146b 100644
--- a/Master/texmf-dist/doc/latex/songs/songidx/greek.can
+++ b/Master/texmf-dist/doc/latex/songs/songidx/greek.can
@@ -1,4 +1,4 @@
-# Copyright (C) 2012 Kevin W. Hamlen
+# Copyright (C) 2017 Kevin W. Hamlen
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
diff --git a/Master/texmf-dist/doc/latex/songs/songidx/protestant.can b/Master/texmf-dist/doc/latex/songs/songidx/protestant.can
index fab28005f98..f86cce40e4c 100644
--- a/Master/texmf-dist/doc/latex/songs/songidx/protestant.can
+++ b/Master/texmf-dist/doc/latex/songs/songidx/protestant.can
@@ -1,4 +1,4 @@
-# Copyright (C) 2012 Kevin W. Hamlen
+# Copyright (C) 2017 Kevin W. Hamlen
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
diff --git a/Master/texmf-dist/doc/latex/songs/songidx/scripidx.c b/Master/texmf-dist/doc/latex/songs/songidx/scripidx.c
deleted file mode 100644
index 1a2189ac617..00000000000
--- a/Master/texmf-dist/doc/latex/songs/songidx/scripidx.c
+++ /dev/null
@@ -1,1105 +0,0 @@
-/* Copyright (C) 2012 Kevin W. Hamlen
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * The latest version of this program can be obtained from
- * http://songs.sourceforge.net.
- */
-
-
-/* Create a LaTeX scripture index file from a scripture index .dat file. */
-
-#if HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "vsconfig.h"
-#endif
-
-#include "chars.h"
-#include "songidx.h"
-#include "fileio.h"
-
-#if HAVE_STRING_H
-# include <string.h>
-#else
-# if HAVE_STRINGS_H
-# include <strings.h>
-# endif
-#endif
-
-/* The following constant should be a large integer (but not greater than
- * INT_MAX) limiting the maximum number of verses in a single chapter of the
- * bible. */
-#define MAXVERSES 999
-
-/* A BBOOK struct describes a book of the Bible, including:
- * name: a \0-separated string of names (the first one is the name used when
- * printing the scripture index)
- * verses: an array of numbers giving the number of verses in each chapter
- * aliases: the number of names in the name field
- * chapters: the number of chapters in the book */
-typedef struct
-{
- WCHAR *name;
- int *verses;
- int aliases;
- int chapters;
-}
-BBOOK;
-
-/* A VERSE struct refers to a verse in a book of the Bible.
- * chapter: the integral chapter number of the verse (1 if the book has only
- * one chapter)
- * verse: the integral verse number */
-typedef struct
-{
- int chapter, verse;
-}
-VERSE;
-
-/* A SONGLIST is a list of songs
- * num: a string denoting the song number (e.g. "3" or "H10")
- * link: a string denoting the hyperlink label for the song
- * int: an integer key used to order songs when sorting
- * next: next pointer */
-typedef struct songliststruct
-{
- WCHAR *num;
- WCHAR *link;
- int key;
- struct songliststruct *next;
-}
-SONGLIST;
-
-/* A VERSELIST is the list of verses in a particular book of the Bible at which
- * the set of songs referencing that verse differs from the set of songs
- * referencing the previous verse in the book. Such a list allows us to
- * sparsely represent the set of songs referencing each verse in the book
- * without having to create a distinct list entry for each verse in the entire
- * book. For example, if song "H1" references verses 3:1-10, that would
- * represented by a two-element list:
- * [ {v={chapter=3, verse=1}, adds=[H1], drops=[]};
- * {v={chapter=3, verse=10}, adds=[], drops=[H1]} ]
- * This is more reasonable than creating ten list items to refer to such a
- * range.
- * v: the verse at which the set of song references is changing
- * adds: a list of songs that refer to this verse but not the previous one
- * drops: a list of songs that refer to this verse but not the next one
- * next: pointer to next verse at which the set of references changes */
-typedef struct verseliststruct
-{
- VERSE v;
- SONGLIST *adds, *drops;
- struct verseliststruct *next;
-}
-VERSELIST;
-
-/* The bible global variable stores the array of bible books being used to
- * generate the scripture index. The numbooks variable stores the number of
- * elements in the bible array. */
-BBOOK *bible = NULL;
-int numbooks = 0;
-
-/* free_bible()
- * Free the bible array, set it to NULL, and set numbooks to 0. */
-static void
-free_bible()
-{
- int i;
-
- if (!bible) return;
- for (i=0; i<numbooks; ++i)
- {
- if (bible[i].name) free(bible[i].name);
- if (bible[i].verses) free(bible[i].verses);
- }
- free(bible);
- bible = NULL;
- numbooks = 0;
-}
-
-/* free_songlist(<slist>)
- * Free song list <slist>. */
-static void
-free_songlist(sl)
- SONGLIST *sl;
-{
- SONGLIST *next;
-
- for (; sl; sl=next)
- {
- if (sl->num) free(sl->num);
- if (sl->link) free(sl->link);
- next = sl->next;
- free(sl);
- }
-}
-
-/* free_verselist(<vlist>)
- * Free verse list <vlist>. */
-static void
-free_verselist(vl)
- VERSELIST *vl;
-{
- VERSELIST *next;
-
- for (; vl; vl=next)
- {
- free_songlist(vl->adds);
- free_songlist(vl->drops);
- next = vl->next;
- free(vl);
- }
-}
-
-/* freeidxarray(<array>,<len>)
- * Free the array of verselists given by <array>. The array should have
- * length <len>. */
-static void
-freeidxarray(idx,len)
- VERSELIST **idx;
- int len;
-{
- int i;
-
- if (!idx) return;
- for (i=0; i<len; ++i) free_verselist(idx[i]);
- free(idx);
-}
-
-/* readbible(<filename>)
- * Read bible data file <filename> into the bible array and set numbooks to
- * the number of books read. Return 0 on error or 1 on success. */
-static int
-readbible(filename)
- const char *filename;
-{
- FSTATE fs;
- int eof = 0;
- WCHAR buf[MAXLINELEN];
- int verses[MAXLINELEN/2+1];
- int arraysize, j;
- WCHAR *p1, *p2;
-
- if (!fileopen(&fs,filename)) return 0;
-
- bible = NULL;
- eof = 0;
- for (arraysize=numbooks=0; !eof; ++numbooks)
- {
- if (!filereadln(&fs,buf,&eof))
- {
- free_bible();
- return 0;
- }
- if (eof) break;
- if (*buf == wc_hash)
- {
- --numbooks;
- continue;
- }
- if (numbooks >= arraysize)
- {
- BBOOK *temp;
- arraysize *= 2;
- if (arraysize==0) arraysize=64;
- temp = (BBOOK *) realloc(bible,arraysize*sizeof(BBOOK));
- if (!temp)
- {
- fprintf(stderr, "songidx:%s:%d: too many bible books (out of memory)\n",
- fs.filename, fs.lineno);
- free_bible();
- return 0;
- }
- bible = temp;
- }
- if ((bible[numbooks].name =
- (WCHAR *) calloc(ws_strlen(buf)+1,sizeof(WCHAR))) == NULL)
- {
- fprintf(stderr, "songidx:%s:%d: bible book name too large"
- " (out of memory)\n", fs.filename, fs.lineno);
- fileclose(&fs);
- free_bible();
- return 0;
- }
- for(j=1, p1=buf, p2=bible[numbooks].name; *p1!=wc_null; ++p1, ++p2)
- {
- if (*p1 == wc_pipe)
- {
- ++j;
- *p2=wc_null;
- }
- else *p2=*p1;
- }
- *p2 = wc_null;
- if (j == 0)
- {
- fprintf(stderr, "songidx:%s:%d: bible book has no name\n",
- fs.filename, fs.lineno);
- free(bible[numbooks].name);
- fileclose(&fs);
- free_bible();
- return 0;
- }
- bible[numbooks].aliases = j;
- do
- {
- if (!filereadln(&fs,buf,&eof))
- {
- free_bible();
- return 0;
- }
- if (eof)
- {
- fprintf(stderr, "songidx:%s:%d: incomplete bible book entry (book"
- " title with no verses)\n", fs.filename, fs.lineno);
- free_bible();
- return 0;
- }
- }
- while (*buf == wc_hash);
- for (j=0, p1=buf; *p1!=wc_null; ++j)
- {
- long v = ws_strtol(p1, &p1, 10);
- if ((v<=0) || (v>MAXVERSES))
- {
- fprintf(stderr, "songidx:%s:%d: illegal verse count for chapter %d\n",
- fs.filename, fs.lineno, j+1);
- fileclose(&fs);
- free_bible();
- return 0;
- }
- verses[j] = (int) v;
- }
- if (j == 0)
- {
- fprintf(stderr, "songidx:%s:%d: book ", fs.filename, fs.lineno);
- ws_fputs(bible[numbooks].name, stderr);
- fprintf(stderr, " has no chapters\n");
- fileclose(&fs);
- free_bible();
- return 0;
- }
- bible[numbooks].chapters = j;
- if ((bible[numbooks].verses = (int *) calloc(j, sizeof(int))) == NULL)
- {
- fprintf(stderr, "songidx:%s:%d: too many verses (out of memory)\n",
- fs.filename, fs.lineno);
- fileclose(&fs);
- free_bible();
- return 0;
- }
- for (j=0; j<bible[numbooks].chapters; ++j)
- bible[numbooks].verses[j] = verses[j];
- }
-
- fileclose(&fs);
- return 1;
-}
-
-/* ws_stricmp(<string1>,<string2>)
- * Case-insensitive, wide-string comparison function. (Some standard C libs
- * already have one of these, but not all do; for compatibility I have to
- * write my own.) */
-static int
-ws_stricmp(p1,p2)
- const WCHAR *p1;
- const WCHAR *p2;
-{
- for (;;)
- {
- int diff = wc_tolower(*p1) - wc_tolower(*p2);
- if (diff != 0) return diff;
- if (*p1 == wc_null) return 0;
- ++p1; ++p2;
- }
-}
-
-/* parseref(<string>,<book>,<verse>)
- * Interpret <string> as a scripture reference, and store the NUMBER of the
- * book of the Bible it refers to in <book>, and the chapter and verse that
- * it refers to in <verse>. Return a pointer into <string> to the suffix of
- * <string> that was not parsed. The <book> and <verse> should hold the book
- * and verse of the PREVIOUS scripture reference (if any) on entry to the
- * function. If book or chapter information is missing, they will be drawn
- * from this info. That way, successive calls can correctly parse a run-on
- * string like "Philippians 3:1,5; 4:3", inferring that "5" refers to
- * "Philippians 3" and "4:3" refers to "Philippians". If the parser
- * encounters an error in processing the book name (e.g., a book name was
- * specified but not recognized), <book> is set to numbooks. If no chapter
- * or no verse is provided (e.g., the reference is just "Philippians" or
- * "Philippians 3") then the chapter and/or verse fields of <verse> are set
- * to -1. */
-static WCHAR *
-parseref(r,book,v)
- WCHAR *r;
- int *book;
- VERSE *v;
-{
- WCHAR *p;
- WCHAR c;
- int i;
- const WCHAR *a;
-
- while (*r==wc_space) ++r;
- p = ws_strpbrk(r, ws_lit(",;-"));
- if (!p) p=r+ws_strlen(r);
- if (p>r) --p;
- while ((p>r) && (*p==wc_space)) --p;
- while ((p>r) && (wc_isdigit(*p) || (*p==wc_colon))) --p;
- if (p>r)
- {
- if (*p==wc_space)
- {
- *p++ = wc_null;
- for (*book=0; *book<numbooks; ++(*book))
- {
- for (i=0, a=bible[*book].name;
- i<bible[*book].aliases;
- ++i, a+=ws_strlen(a)+1)
- if (!ws_stricmp(r,a)) break;
- if (i<bible[*book].aliases) break;
- }
- }
- else
- {
- *book=numbooks;
- }
- r=p;
- v->chapter = v->verse = -1;
- }
- while (wc_isdigit(*p)) ++p;
- if (*p==wc_colon)
- {
- *p++ = wc_null;
- v->chapter = ws_strtol(r,NULL,10);
- r=p;
- while (wc_isdigit(*p)) ++p;
- }
- if (r==p) return NULL;
- c = *p;
- *p = wc_null;
- if ((v->chapter < 0) && (*book>=0) && (*book<numbooks) &&
- (bible[*book].chapters == 1))
- {
- /* Special case: This book only has one chapter. */
- v->chapter = 1;
- }
- if (v->chapter < 0)
- v->chapter = ws_strtol(r,NULL,10);
- else
- v->verse = ws_strtol(r,NULL,10);
- *p = c;
- while (*p==wc_space) ++p;
- if (*p && (*p!=wc_comma) && (*p!=wc_semicolon) && (*p!=wc_hyphen))
- return NULL;
- return p;
-}
-
-/* vlt(<v1>,<v2>)
- * Return 1 if verse <v1> precedes <v2> and 0 otherwise. */
-static int
-vlt(v1,v2)
- const VERSE v1;
- const VERSE v2;
-{
- return ((v1.chapter == v2.chapter) ? (v1.verse < v2.verse)
- : (v1.chapter < v2.chapter));
-}
-
-/* vcpy(<vdest>,<vsrc>)
- * Copy the data from verse <vsrc> into verse <vdest>. */
-static void
-vcpy(vdest,vsrc)
- VERSE *vdest;
- const VERSE vsrc;
-{
- vdest->chapter = vsrc.chapter;
- vdest->verse = vsrc.verse;
-}
-
-/* getvcount(<book>,<chapter>)
- * Return the number of verses in chapter <chapter> of book number <book> of
- * the Bible. */
-static int
-getvcount(book,chapter)
- int book;
- int chapter;
-{
- if ((book<0) || (book>=numbooks))
- {
- /* This should never happen. */
- fprintf(stderr, "songidx: Internal error (getvcount):"
- " Book %d out of range.\n", book);
- return 0;
- }
- if ((chapter<1) || (chapter > bible[book].chapters))
- return 0;
- return bible[book].verses[chapter-1];
-}
-
-/* vinc(<book>,<verse>)
- * Return a reference to the verse immediately following <verse> in book
- * number <book> of the Bible. The verse returned is static, so successive
- * calls will overwrite it. If <verse> is the last verse in <book>, the
- * return value will reference verse 1 of a non-existant chapter. */
-static VERSE
-vinc(book,v)
- int book;
- const VERSE v;
-{
- static VERSE vret;
- int cnt;
-
- vret.chapter = v.chapter;
- vret.verse = v.verse + 1;
- cnt = getvcount(book, vret.chapter);
- if (cnt <= 0)
- {
- /* This should never happen. */
- fprintf(stderr, "songidx: Internal Error (vinc): Book ");
- ws_fputs(bible[book].name, stderr);
- fprintf(stderr, " has no chapter %d.\n", vret.chapter);
- }
- else if (vret.verse > cnt)
- {
- ++vret.chapter;
- vret.verse = 1;
- }
- return vret;
-}
-
-/* vdec(<book>,<verse>)
- * Return a reference to the verse immediately preceding <verse> in book
- * number <book> of the Bible. The verse returned is static, so successive
- * calls will overwrite it. If <verse> is the first verse in <book>, the
- * return value will reference chapter -1 and an error message will be
- * printed to stderr. */
-static VERSE
-vdec(book,v)
- int book;
- const VERSE v;
-{
- static VERSE vret;
- vret.chapter = v.chapter;
- vret.verse = v.verse - 1;
- if (vret.verse < 1)
- {
- --vret.chapter;
- vret.verse = getvcount(book, vret.chapter);
- if (vret.verse <= 0)
- {
- /* This should never happen. */
- fprintf(stderr, "songidx: Internal Error (vdec): Book ");
- ws_fputs(bible[book].name, stderr);
- fprintf(stderr, " has no chapter %d.\n", vret.chapter);
- vret.verse = -1;
- }
- }
- return vret;
-}
-
-/* addref(<reflist>,<song>,<link>,<key>)
- * Add a reference to song (<song>,<link>,<key>) to REFLIST <reflist>. The
- * <reflist> is assumed to be sorted by <key>. If a reference with the same
- * <key> already exists, <reflist> is left unchanged. Both <song> and
- * <link> are COPIED into the list. Return 1 on success or 0 on failure. */
-static int
-addref(sl,n,l,key)
- SONGLIST **sl;
- const WCHAR *n;
- const WCHAR *l;
- int key;
-{
- SONGLIST *newsong;
-
- for (; *sl; sl=&((*sl)->next))
- if ((*sl)->key >= key) break;
- if (*sl && ((*sl)->key == key)) return 1;
-
- if ((newsong = (SONGLIST *) malloc(sizeof(SONGLIST))) == NULL)
- {
- fprintf(stderr, "songidx: too many scripture references (out of memory)\n");
- return 0;
- }
- newsong->num = newsong->link = NULL;
- if (((newsong->num = (WCHAR *) calloc(ws_strlen(n)+1,
- sizeof(WCHAR))) == NULL) ||
- ((newsong->link = (WCHAR *) calloc(ws_strlen(l)+1,
- sizeof(WCHAR))) == NULL))
- {
- fprintf(stderr, "songidx: too many scripture references (out of memory)\n");
- if (newsong->num) free(newsong->num);
- if (newsong->link) free(newsong->link);
- free(newsong);
- return 0;
- }
- ws_strcpy(newsong->num, n);
- ws_strcpy(newsong->link, l);
- newsong->key = key;
- newsong->next = *sl;
- *sl = newsong;
- return 1;
-}
-
-/* insertref(<type>,<verselist>,<verse>,<song>,<link>,<key>)
- * If <type> is INSERT_ADD, then insert song (<song>,<link>,<key>) into the
- * set of "adds" for verse <verse> in <verselist>. If <type> is INSERT_DROP,
- * then insert the song into the set of "drops" for verse <verse>. In either
- * case, create a new entry for <verse> in <verselist> if it doesn't already
- * exist. Return 1 on success or 0 on failure. */
-#define INSERT_ADD 1
-#define INSERT_DROP 0
-
-static int
-insertref(type,vpp,v,n,l,key)
- char type;
- VERSELIST **vpp;
- const VERSE v;
- const WCHAR *n;
- const WCHAR *l;
- int key;
-{
- for (;;)
- {
- if (!*vpp || vlt(v, (*vpp)->v))
- {
- VERSELIST *vnew = NULL;
- SONGLIST *sl = NULL;
- if (((vnew = (VERSELIST *) malloc(sizeof(VERSELIST))) == NULL) ||
- ((sl = (SONGLIST *) malloc(sizeof(SONGLIST))) == NULL))
- {
- fprintf(stderr, "songidx: too many scripture references"
- " (out of memory)\n");
- if (vnew) free(vnew);
- if (sl) free(sl);
- return 0;
- }
- sl->num = sl->link = NULL;
- if (((sl->num = (WCHAR *) calloc(ws_strlen(n)+1,
- sizeof(WCHAR))) == NULL) ||
- ((sl->link = (WCHAR *) calloc(ws_strlen(l)+1,
- sizeof(WCHAR))) == NULL))
- {
- fprintf(stderr, "songidx: too many scripture references"
- " (out of memory)\n");
- if (sl->num) free(sl->num);
- if (sl->link) free(sl->link);
- free(vnew);
- free(sl);
- return 0;
- }
- ws_strcpy(sl->num, n);
- ws_strcpy(sl->link, l);
- sl->key = key;
- sl->next = NULL;
- vcpy(&(vnew->v), v);
- if (type)
- {
- vnew->adds = sl;
- vnew->drops = NULL;
- }
- else
- {
- vnew->adds = NULL;
- vnew->drops = sl;
- }
- vnew->next = *vpp;
- *vpp = vnew;
- return 1;
- }
- else if (!vlt((*vpp)->v, v))
- {
- return addref(type ? &((*vpp)->adds) : &((*vpp)->drops), n, l, key);
- }
- vpp=&((*vpp)->next);
- }
-}
-
-/* addrefs(<dest>,<src>)
- * Take the union of SONGLIST <dest> and SONGLIST <src>, storing the result
- * in <dest>. Return 1 on success, or 0 on failure. */
-static int
-addrefs(dest,src)
- SONGLIST **dest;
- const SONGLIST *src;
-{
- for (; src; src=src->next)
- if (!addref(dest, src->num, src->link, src->key)) return 0;
- return 1;
-}
-
-/* removerefs(<dest>,<src>)
- * Take the set difference between SONGLIST <dest> and SONGLIST <src>,
- * storing the result in <dest>. */
-static void
-removerefs(dest,src)
- SONGLIST **dest;
- const SONGLIST *src;
-{
- SONGLIST **sl;
-
- for (; src; src=src->next)
- {
- for (sl=dest; *sl; sl=&((*sl)->next))
- if ((*sl)->key >= src->key) break;
- if (*sl && ((*sl)->key == src->key))
- {
- SONGLIST *temp = (*sl)->next;
- free((*sl)->num);
- free((*sl)->link);
- free(*sl);
- *sl = temp;
- }
- }
-}
-
-/* slcmp(<slist1>,<slist2>)
- * Compare SONGLIST's <slist1> and <slist2>, returning 1 if they are
- * different and 0 if they are the same. */
-static int
-slcmp(s1,s2)
- const SONGLIST *s1;
- const SONGLIST *s2;
-{
- for (; s1 && s2; s1=s1->next, s2=s2->next)
- if (s1->key != s2->key) return 1;
- return (s1 || s2);
-}
-
-/* print_vrange(<file>,<book>,<verse1>,<verse2>,<lastchapter>)
- * Output LaTeX material to file handle <file> for verse range
- * <verse1>-<verse2> of book number <book>. Depending on <lastchapter>,
- * the outputted material might be the start of a new index entry or the
- * continuation of a previous entry. If <lastchapter> is 0, start a new
- * index entry. If <lastchapter> is >0, continue the previous entry and
- * print the chapter of <verse1> only if it differs from <lastchapter>.
- * If <lastchapter> is <0, continue the previous entry and always print the
- * chapter number of <verse1>. Return 0 on success or -1 on failure. */
-static int
-print_vrange(f,book,v1,v2,lastchapter)
- FILE *f;
- int book;
- const VERSE v1;
- const VERSE v2;
- int lastchapter;
-{
- if (ws_fputs(lastchapter ? ws_lit(",") : ws_lit("\\idxentry{"), f) < 0)
- return -1;
- if (v1.verse <= 0)
- {
- if (ws_fprintf1(f, lastchapter ? ws_lit("\\thinspace %d") : ws_lit("%d"),
- v1.chapter) < 0)
- return -1;
- }
- else if ((book>=0) && (book<numbooks) && (bible[book].chapters == 1))
- {
- /* This book has only one chapter. */
- if (ws_fprintf1(f, lastchapter ? ws_lit("\\thinspace %d") : ws_lit("%d"),
- v1.verse) < 0)
- return -1;
- }
- else if ((lastchapter<=0) || (lastchapter!=v1.chapter) ||
- (v1.chapter!=v2.chapter))
- {
- if (ws_fprintf2(f, lastchapter ? ws_lit(" %d:%d") : ws_lit("%d:%d"),
- v1.chapter, v1.verse) < 0)
- return -1;
- }
- else
- {
- if (ws_fprintf1(f, lastchapter ? ws_lit("\\thinspace %d") : ws_lit("%d"),
- v1.verse) < 0)
- return -1;
- }
-
- if (vlt(v1,v2))
- {
- if (v2.verse <= 0)
- {
- if (ws_fprintf1(f, ws_lit("--%d"), v2.chapter) < 0) return -1;
- }
- else if (v1.chapter!=v2.chapter)
- {
- if (ws_fprintf2(f, ws_lit("--%d:%d"), v2.chapter, v2.verse) < 0)
- return -1;
- }
- else
- {
- if (ws_fprintf1(f, ws_lit("--%d"), v2.verse) < 0) return -1;
- }
- }
- return 0;
-}
-
-/* print_reflist(<file>,<slist>)
- * Output the list of song references given by <slist> to file handle <file>.
- * Return 0 on success or -1 on failure. */
-static int
-print_reflist(f,sp)
- FILE *f;
- const SONGLIST *sp;
-{
- char first;
- for (first=1; sp; sp=sp->next)
- {
- if (!first)
- {
- if (ws_fputs(ws_lit("\\\\"), f) < 0) return -1;
- }
- first = 0;
- if ((ws_fputs(ws_lit("\\hyperlink{"), f) < 0) ||
- (ws_fputs(sp->link, f) < 0) ||
- (ws_fputs(ws_lit("}{"), f) < 0) ||
- (ws_fputs(sp->num, f) < 0) ||
- (ws_fputs(ws_lit("}"), f) < 0))
- return -1;
- }
- return 0;
-}
-
-/* genscriptureindex(<fstate>,<outname>,<biblename>)
- * Generate a LaTeX file named <outname> containing material suitable to
- * typeset the scripture index data found in input file handle <file>.
- * Input Bible data from an ascii file named <biblename>. Return 0 on
- * success, 1 if there were warnings, and 2 if there was a fatal error. */
-int
-genscriptureindex(fs,outname,biblename)
- FSTATE *fs;
- const char *outname;
- const char *biblename;
-{
- FILE *f;
- int eof = 0;
- VERSELIST **idx;
- int book, book2;
- WCHAR ref[MAXLINELEN], songnum[MAXLINELEN], linkname[MAXLINELEN];
- int songcount;
- WCHAR *p;
- VERSE v1, v2;
- char hadwarnings = 0;
-
- fprintf(stderr, "songidx: Parsing scripture index data file %s...\n",
- fs->filename);
-
- /* Read the bible data file into the bible array. */
- if (!readbible(biblename)) return 2;
- if ((idx = (VERSELIST **) calloc(numbooks, sizeof(VERSELIST *))) == NULL)
- {
- fprintf(stderr, "songidx: too many books of the bible (out of memory)\n");
- free_bible();
- return 2;
- }
- for (book=0; book<numbooks; ++book) idx[book] = NULL;
-
- /* Walk through the input file and construct a VERSELIST for each book
- * of the Bible. Each VERSELIST represents the set of verses in that book
- * referred to by songs in the song book. */
- songcount = 0;
- book = -1;
- v1.chapter = -1;
- v1.verse = -1;
- for (;;)
- {
- /* Get the next song data record. */
- if (!filereadln(fs,ref,&eof))
- {
- freeidxarray(idx,numbooks);
- free_bible();
- return 2;
- }
- if (eof) break;
- if (!filereadln(fs,songnum,&eof) || eof ||
- !filereadln(fs,linkname,&eof) || eof)
- {
- if (eof)
- {
- fprintf(stderr, "songidx:%s:%d: incomplete entry\n",
- fs->filename, fs->lineno);
- fileclose(fs);
- }
- freeidxarray(idx,numbooks);
- free_bible();
- return 2;
- }
-
- /* Add all scripture references for this song to the VERSELIST array */
- p = ref;
- while (*p != wc_null)
- {
- /* Parse the next reference. */
- p = parseref(p, &book, &v1);
- if (!p)
- {
- fprintf(stderr, "songidx:%s:%d: WARNING: Malformed scripture reference"
- " for song ", fs->filename, fs->lineno);
- ws_fputs(songnum, stderr);
- fprintf(stderr, ". Ignoring it.\n");
- hadwarnings = 1;
- break;
- }
- if (book<0)
- {
- fprintf(stderr, "songidx:%s:%d: WARNING: Scripture reference for song ",
- fs->filename, fs->lineno);
- ws_fputs(songnum, stderr);
- fprintf(stderr, " doesn't include a book name. Ignoring it.\n");
- hadwarnings = 1;
- break;
- }
- if (book>=numbooks)
- {
- fprintf(stderr, "songidx:%s:%d: WARNING: Scripture reference for song ",
- fs->filename, fs->lineno);
- ws_fputs(songnum, stderr);
- fprintf(stderr, " references unknown book. Ignoring it.\n");
- hadwarnings = 1;
- break;
- }
- if (v1.chapter < 1)
- {
- fprintf(stderr, "songidx:%s:%d: WARNING: Scripture reference for song ",
- fs->filename, fs->lineno);
- ws_fputs(songnum, stderr);
- fprintf(stderr, " has no chapter or verse. Ignoring it.\n");
- hadwarnings = 1;
- break;
- }
- /* Unless the reference ended in a "-", it consists of just one verse. */
- v2.chapter = v1.chapter;
- v2.verse = v1.verse;
- if (*p==wc_hyphen)
- {
- /* This reference ended in a "-", which means it starts a range.
- * Parse the next reference to find the range's end. */
- book2 = book;
- p = parseref(++p, &book2, &v2);
- if (!p)
- {
- fprintf(stderr, "songidx:%s:%d: WARNING: Malformed scripture"
- " reference for song ", fs->filename, fs->lineno);
- ws_fputs(songnum, stderr);
- fprintf(stderr, ". Ignoring it.\n");
- hadwarnings = 1;
- break;
- }
- if (book2!=book)
- {
- fprintf(stderr, "songidx:%s:%d: WARNING: Scripture reference for"
- " song ", fs->filename, fs->lineno);
- ws_fputs(songnum, stderr);
- fprintf(stderr, " appears to span books! Ignoring it.\n");
- hadwarnings = 1;
- break;
- }
- }
- if (*p!=wc_null) ++p;
- /* If either the start or end references of the range were incomplete
- * (e.g., the range was something like "Philippians 3", where the verse
- * numbers are not explicit), try to fill in the missing information
- * based on how many verses are in the chapter and how many chapters are
- * in the book. */
- if (v1.verse <= 0) v1.verse = 1;
- if (v2.verse <= 0)
- {
- v2.verse = getvcount(book,v2.chapter);
- if (v2.verse <= 0)
- {
- fprintf(stderr, "songidx:%s:%d: WARNING: Scripture reference for "
- " song ", fs->filename, fs->lineno);
- ws_fputs(songnum, stderr);
- fprintf(stderr, " refers implicitly to chapter %d of ", v2.chapter);
- ws_fputs(bible[book].name, stderr);
- fprintf(stderr, ", which doesn't exist. Ignoring it.\n");
- hadwarnings = 1;
- break;
- }
- }
- if (v1.verse > getvcount(book,v1.chapter))
- {
- fprintf(stderr, "songidx:%s:%d: WARNING: Song ",
- fs->filename, fs->lineno);
- ws_fputs(songnum, stderr);
- fprintf(stderr, " references ");
- ws_fputs(bible[book].name, stderr);
- fprintf(stderr, " %d:%d, which doesn't exist! Ignoring it.\n",
- v1.chapter, v1.verse);
- hadwarnings = 1;
- break;
- }
- if (v2.verse > getvcount(book,v2.chapter))
- {
- fprintf(stderr, "songidx:%s:%d: WARNING: Song ",
- fs->filename, fs->lineno);
- ws_fputs(songnum, stderr);
- fprintf(stderr, " references ");
- ws_fputs(bible[book].name, stderr);
- fprintf(stderr, " %d:%d, which doesn't exist! Ignoring it.\n",
- v2.chapter, v2.verse);
- hadwarnings = 1;
- break;
- }
-
- /* Add the range to the SONGLIST array. */
- if (!insertref(INSERT_ADD, &(idx[book]), v1, songnum, linkname,
- songcount) ||
- !insertref(INSERT_DROP, &(idx[book]), v2, songnum, linkname,
- songcount))
- {
- fileclose(fs);
- freeidxarray(idx,numbooks);
- free_bible();
- return 2;
- }
- }
- /* finished adding all refs for this song */
- ++songcount;
- }
- /* finished adding all refs for all songs */
- fileclose(fs);
-
- /* Now create the index .sbx file */
- fprintf(stderr, "songidx: Generating scripture index TeX file %s...\n",
- outname);
- if (strcmp(outname,"-"))
- {
- if ((f = fopen(outname, "w")) == NULL)
- {
- fprintf(stderr, "songidx: Unable to open %s for writing.\n", outname);
- freeidxarray(idx,numbooks);
- free_bible();
- return 2;
- }
- }
- else
- {
- f = stdout;
- outname = "stdout";
- }
-
-#define TRYWRITE(x) \
- if (!(x)) \
- { \
- fprintf(stderr, "songidx:%s: write error\n", outname); \
- if (f == stdout) fflush(f); else fclose(f); \
- freeidxarray(idx,numbooks); \
- free_bible(); \
- return 2; \
- }
-
- /* For each book of the Bible that has songs that reference it, go through
- * its VERSELIST and generate a sequence of index entries. Wherever
- * possible, compact adjacent entries that have identical SONGLISTS so that
- * we never have two consecutive index entries with identical right-hand
- * sides. */
- for (book=0; book<numbooks; ++book)
- if (idx[book])
- {
- VERSE vrstart;
- VERSELIST *vp;
- SONGLIST *sl = NULL;
- int lastchapter; /* 0=none, -1=force printing of chapter */
-
- TRYWRITE((ws_fputs(ws_lit("\\begin{idxblock}{"), f) >=0)
- && (ws_fputs(bible[book].name, f) >= 0)
- && (ws_fputs(ws_lit("}\n"), f) >=0))
- lastchapter = 0;
- vcpy(&vrstart, idx[book]->v);
- for (vp=idx[book]; vp; vp=vp->next)
- {
- if (!addrefs(&sl, vp->adds))
- {
- fclose(f);
- freeidxarray(idx,numbooks);
- free_bible();
- return 2;
- }
- if (!slcmp(vp->drops, vp->next ? vp->next->adds : NULL))
- {
- /* Set of drops here equals set of adds next time. There's at least
- * a chance that we can combine this item and the next one into a
- * single index entry. */
- if (vp->next && !vlt(vinc(book,vp->v), vp->next->v))
- {
- /* If the next item is adjacent to this one, do nothing. Just let
- * the range in progress be extended. We'll output a single entry
- * for all of these adjacent verses when we reach the end. */
- continue;
- }
- else if (vp->next && !slcmp(sl, vp->drops))
- {
- /* Otherwise, if the next item is not adjacent but all refs are
- * dropped here, then print a partial entry to be continued with a
- * comma next time. */
- TRYWRITE(print_vrange(f, book, vrstart, vp->v, lastchapter) >= 0)
- lastchapter = (vrstart.chapter != vp->v.chapter) ?
- -1 : vp->v.chapter;
- vcpy(&vrstart, vp->next->v);
- continue;
- }
- }
- if (vp->drops)
- {
- /* Some songs get dropped here, and either the next item is not
- * adjacent to this one, or it's adjacent and the set of adds is not
- * the same. In either case, that means the set of refs changes at
- * this point, so we need to output a full entry (or finish the one
- * in progress). */
- TRYWRITE((print_vrange(f, book, vrstart, vp->v, lastchapter) >= 0) &&
- (ws_fputs(ws_lit("}{"), f) >= 0) &&
- (print_reflist(f, sl) >= 0) &&
- (ws_fputs(ws_lit("}\n"), f) >= 0))
- removerefs(&sl, vp->drops);
- lastchapter = 0;
- vcpy(&vrstart, (!sl && vp->next) ? vp->next->v : vinc(book,vp->v));
- }
- if (sl && vp->next && vp->next->adds && vlt(vrstart, vp->next->v))
- {
- /* There are verses between this item and the next which have refs,
- * but the refs change at the beginning of the next item. Make an
- * entry for the intermediate block of verses. */
- VERSE vrend;
- vcpy(&vrend, vdec(book,vp->next->v));
- TRYWRITE((print_vrange(f, book, vrstart, vrend, lastchapter) >= 0) &&
- (ws_fputs(ws_lit("}{"), f) >= 0) &&
- (print_reflist(f, sl) >= 0) &&
- (ws_fputs(ws_lit("}\n"), f) >= 0))
- lastchapter = 0;
- vcpy(&vrstart, vp->next->v);
- }
- }
- if (sl)
- {
- fprintf(stderr, "songidx: scripture references in ");
- ws_fputs(bible[book].name, stderr);
- fprintf(stderr, " appear to extend past the end of the book!"
- " Aborting.\n");
- fclose(f);
- freeidxarray(idx,numbooks);
- free_bible();
- return 2;
- }
- TRYWRITE(ws_fputs(ws_lit("\\end{idxblock}\n"), f) >= 0)
- }
-
-#undef TRYWRITE
-
- fclose(f);
- freeidxarray(idx,numbooks);
- free_bible();
-
- return hadwarnings;
-}
diff --git a/Master/texmf-dist/doc/latex/songs/songidx/songidx.c b/Master/texmf-dist/doc/latex/songs/songidx/songidx.c
deleted file mode 100644
index 20c08e62df8..00000000000
--- a/Master/texmf-dist/doc/latex/songs/songidx/songidx.c
+++ /dev/null
@@ -1,270 +0,0 @@
-/* Copyright (C) 2012 Kevin W. Hamlen
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * The latest version of this program can be obtained from
- * http://songs.sourceforge.net.
- *
- *
- * This program generates an index.sbx file from an index.sxd file. Index.sxd
- * files are generated by the song book LaTeX files while you compile a song
- * book. They contain lists of all the song titles, song numbers, and
- * scripture references. Once the .sxd files exist, run this program to
- * convert them in to .sbx files. This program will sort the song titles
- * alphabetically, group all the scripture entries into the appropriate
- * chunks, etc. The TeX files that it creates are then used by the LaTeX
- * files next time you compile the song book.
- *
- * The syntax for running the program is:
- * songidx input.sxd output.sbx
- * or, if you're compiling a scripture index:
- * songidx -b bible.can input.sxd output.sbx
- *
- * The program should compile on unix with
- *
- * cc *.c -o songidx
- *
- * On Windows, you'll need to find a C compiler in order to compile it,
- * or go to http://songs.sourceforge.net to obtain a Windows self-installer
- * with pre-compiled binaries.
- */
-
-#if HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "vsconfig.h"
-#endif
-
-#include "chars.h"
-#include "songidx.h"
-#include "fileio.h"
-
-#if HAVE_STRING_H
-# include <string.h>
-#elif HAVE_STRINGS_H
-# include <strings.h>
-#endif
-
-#if HAVE_SETLOCALE
-#if HAVE_LOCALE_H
-# include <locale.h>
-#endif
-#endif
-
-extern int gentitleindex(FSTATE *fs, const char *outname);
-extern int genscriptureindex(FSTATE *fs, const char *outname,
- const char *biblename);
-extern int genauthorindex(FSTATE *fs, const char *outname);
-
-#define BIBLEDEFAULT "bible.can"
-
-#if HAVE_STRRCHR
-# define STRRCHR(x,y) strrchr((x),(y))
-#else
-# define STRRCHR(x,y) local_strrchr((x),(y))
-char *
-local_strrchr(s,c)
- const char *s;
- int c;
-{
- const char *t;
- if (!s) return NULL;
- for (t=s; *t; ++s) ;
- for (; t>=s; --s)
- if (*t == c) return t;
- return NULL;
-}
-#endif
-
-int
-main(argc,argv)
- int argc;
- char *argv[];
-{
- FSTATE fs;
- int eof = 0;
- WCHAR buf[MAXLINELEN];
- int retval;
- const char *bible, *inname, *outname, *locale;
- int i;
-
- bible = inname = outname = locale = NULL;
- for (i=1; i<argc; ++i)
- {
- if (!strcmp(argv[i],"-v") || !strcmp(argv[i],"--version"))
- {
- printf("songidx " VERSION "\n"
- "Copyright (C) 2012 Kevin W. Hamlen\n"
- "License GPLv2: GNU GPL version 2 or later"
- " <http://gnu.org/licenses/gpl.html>\n"
- "This is free software: you are free to change and redistribute it.\n"
- "There is NO WARRANTY, to the extent permitted by law.\n");
- return 0;
- }
- else if (!strcmp(argv[i],"-h") || !strcmp(argv[i],"--help"))
- {
- printf("Syntax: %s [options] input.sxd [output.sbx]\n", argv[0]);
- printf(
- "Available options:\n"
- " -b FILE Sets the bible format when generating a\n"
- " --bible FILE scripture index (default: " BIBLEDEFAULT ")\n"
- "\n"
- " -l LOCALE Overrides the default system locale (affects\n"
- " --locale LOCALE (how non-English characters are parsed).\n"
- " See local system help for valid LOCALE's.\n"
- "\n"
- " -h Displays this help file and stops.\n"
- " --help\n"
- "\n"
- " -o FILE Sets the output filename.\n"
- " --output FILE\n"
- "\n"
- " -v Print version information and stop.\n"
- " --version\n"
- "\n"
- "If omitted, [output.sbx] defaults to the input filename but with\n"
- "the file extension renamed to '.sbx'. To read or write to stdin or\n"
- "stdout, use '-' in place of input.sxd or output.sbx.\n"
- "\n"
- "See http://songs.sourceforge.net for support.\n");
- return 0;
- }
- else if (!strcmp(argv[i],"-b") || !strcmp(argv[i],"--bible"))
- {
- if (bible)
- {
- fprintf(stderr, "songidx: multiple bible files specified\n");
- return 2;
- }
- else if (++i < argc)
- bible = argv[i];
- else
- {
- fprintf(stderr, "songidx: %s option requires an argument\n", argv[i-1]);
- return 2;
- }
- }
- else if (!strcmp(argv[i],"-l") || !strcmp(argv[i],"--locale"))
- {
- if (locale)
- {
- fprintf(stderr, "songidx: multiple locales specified\n");
- return 2;
- }
- else if (++i < argc)
- locale = argv[i];
- else
- {
- fprintf(stderr, "songidx: %s option requires an argument\n", argv[i-1]);
- return 2;
- }
- }
- else if (!strcmp(argv[i],"-o") || !strcmp(argv[i],"--output"))
- {
- if (outname)
- {
- fprintf(stderr, "songidx: multiple output files specified\n");
- return 2;
- }
- else if (++i < argc)
- outname = argv[i];
- else
- {
- fprintf(stderr, "songidx: %s option requires an argument\n", argv[i-1]);
- return 2;
- }
- }
- else if ((argv[i][0] == '-') && (argv[i][1] != '\0'))
- {
- fprintf(stderr, "songidx: unknown option %s\n", argv[i]);
- return 2;
- }
- else if (!inname) inname=argv[i];
- else if (!outname) outname=argv[i];
- else
- {
- fprintf(stderr, "songidx: too many command line arguments\n");
- return 2;
- }
- }
-
-#if HAVE_SETLOCALE
- if (!locale)
- (void) setlocale(LC_ALL, "");
- else if (!setlocale(LC_ALL, locale))
- {
- fprintf(stderr, "songidx: invalid locale: %s\n", locale);
- return 2;
- }
-#endif
-
- if (!inname)
- {
- fprintf(stderr, "songidx: no input file specified\n");
- return 2;
- }
- if (!outname)
- {
- if (!strcmp(inname,"-"))
- outname = "-";
- else
- {
- char *b;
- const char *p1 = STRRCHR(inname,'.');
- if ((p1 < STRRCHR(inname,'/')) || (p1 < STRRCHR(inname,'\\')))
- p1 = inname+strlen(inname);
- b = (char *) malloc(p1-inname+5);
- strncpy(b,inname,p1-inname);
- strcpy(b+(p1-inname),".sbx");
- outname = b;
- }
- }
- if (!bible) bible = BIBLEDEFAULT;
-
- if (!fileopen(&fs, inname)) return 2;
-
- /* The first line of the input file is a header line that dictates which kind
- * of index the data file is for. */
- if (!filereadln(&fs, buf, &eof)) return 2;
- retval = 2;
- if (eof)
- {
- fprintf(stderr, "songidx:%s: file is empty\n", fs.filename);
- fileclose(&fs);
- }
- else if (!ws_strcmp(buf, ws_lit("TITLE INDEX DATA FILE")))
- retval = gentitleindex(&fs, outname);
- else if (!ws_strcmp(buf, ws_lit("SCRIPTURE INDEX DATA FILE")))
- retval = genscriptureindex(&fs, outname, bible);
- else if (!ws_strcmp(buf, ws_lit("AUTHOR INDEX DATA FILE")))
- retval = genauthorindex(&fs, outname);
- else
- {
- fprintf(stderr, "songidx:%s:%d: file has unrecognized format\n",
- fs.filename, fs.lineno);
- fileclose(&fs);
- }
-
- /* Report the outcome to the user. */
- if (retval == 0)
- fprintf(stderr, "songidx: Done!\n");
- else if (retval == 1)
- fprintf(stderr, "songidx: COMPLETED WITH ERRORS. SEE ABOVE.\n");
- else
- fprintf(stderr, "songidx: FAILED. SEE ERROR MESSAGES ABOVE.\n");
-
- return retval;
-}
diff --git a/Master/texmf-dist/doc/latex/songs/songidx/songidx.h b/Master/texmf-dist/doc/latex/songs/songidx/songidx.h
deleted file mode 100644
index 42dd130b1cd..00000000000
--- a/Master/texmf-dist/doc/latex/songs/songidx/songidx.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* Copyright (C) 2012 Kevin W. Hamlen
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * The latest version of this program can be obtained from
- * http://songs.sourceforge.net.
- */
-
-#ifndef SONGIDX_H
-#define SONGIDX_H
-
-#if HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "vsconfig.h"
-#endif
-
-#include "chars.h"
-
-/* A SONGENTRY struct consists of three fields:
- * title: a string representing the title of the song
- * num: a string representing the song's number in the book (might be
- * something like "H10")
- * linkname: a string denoting the internal hyperlink label for this song
- * idx: a unique integer key that should be used to sort songs with
- * identical titles */
-typedef struct
-{
- WCHAR *title;
- WCHAR *num;
- WCHAR *linkname;
- int idx;
-}
-SONGENTRY;
-
-/* The following functions are in songsort.c */
-extern void skipesc(const WCHAR **p);
-extern int songcmp(const void *s1, const void *s2);
-
-#endif
diff --git a/Master/texmf-dist/doc/latex/songs/songidx/songidx.lua b/Master/texmf-dist/doc/latex/songs/songidx/songidx.lua
new file mode 100644
index 00000000000..bc50b597c45
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/songs/songidx/songidx.lua
@@ -0,0 +1,1070 @@
+-- Copyright (C) 2017 Kevin W. Hamlen
+--
+-- 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.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+-- MA 02110-1301, USA.
+--
+-- The latest version of this program can be obtained from
+-- http://songs.sourceforge.net.
+
+
+VERSION = "3.0"
+BIBLEDEFAULT = "bible.can"
+
+-- fileopen(<filename>)
+-- Open <filename> for reading, returning a filestate table on success or
+-- nil on failure.
+function fileopen(fnam)
+ local handle
+ if fnam ~= "-" then
+ local msg,errno
+ handle,msg,errno = io.open(fnam, "r")
+ if not handle then
+ io.stderr:write("songidx: Unable to open ",fnam," for reading.\n",
+ "Error ",errno,": ",msg,"\n")
+ return nil
+ end
+ else
+ handle = io.stdin
+ fnam = "stdin"
+ end
+ return { f=handle, filename=fnam, lineno=0 }
+end
+
+-- filereadln(<fstate>)
+-- Read a line of input, returning the string or nil if at file-end.
+function filereadln(fs)
+ fs["lineno"] = fs["lineno"] + 1
+ local s = fs["f"]:read()
+ if not s then return nil end
+ return s
+end
+
+-- closeout(<handle>)
+-- Close an output file <handle>.
+function closeout(handle)
+ if handle == io.stdout then handle:flush()
+ else handle:close() end
+end
+
+-- errorout(<handle>)
+-- Respond to a write failure to <handle>.
+function errorout(handle)
+ closeout(handle)
+ io.stderr:write("songidx: Error writing to output file. Aborting.\n")
+ return 2
+ end
+
+-- fileclose(<fstate>)
+-- Close file table <fstate>.
+function fileclose(fs)
+ if (fs["f"] ~= io.stdin) then fs["f"]:close() end
+ fs["f"] = nil
+ fs["filename"] = nil
+ fs["lineno"] = 0
+end
+
+-- numprefix(<string>)
+-- Find the longest prefix of <string> that represents a number (according to
+-- the current locale) and contains no whitespace. Return the number and the
+-- suffix of <string> not parsed. If there is no such prefix, return false
+-- and the original <string>.
+function numprefix(s)
+ local _, len = unicode.utf8.find(s,"^%S*")
+ for i=len, 1, -1 do
+ local n = tonumber(s:sub(1,i))
+ if n then return n, s:sub(i+1) end
+ end
+ return false, s
+end
+
+-- cleantitle(<song>)
+-- Remove macros and braces from <song>'s title, and convert it to uppercase.
+-- Macro-spaces ("\ ") are converted to regular spaces (" "). Cache the
+-- result to avoid re-cleaning during sorting.
+function cleantitle(s)
+ if not s["clean"] then
+ local t = s["title"]:gsub("\\[^%a%s]","")
+ :gsub("\\(%s)","%1")
+ :gsub("\\%a+%s*","")
+ :gsub("{%s*","")
+ :gsub("}","")
+ s["clean"] = unicode.utf8.upper(t)
+ end
+ return s["clean"]
+end
+
+-- songcmp(<song1>,<song2>)
+-- Return true if <song1> is less than <song2>, and false otherwise. The
+-- ordering is first by title, then by index. This function is suitable for
+-- use with table.sort().
+function songcmp(s1,s2)
+ local t1 = cleantitle(s1)
+ local t2 = cleantitle(s2)
+
+ while true do
+ -- Find the next word or number in each string.
+ t1, t2 = unicode.utf8.match(t1,"%w.*"), unicode.utf8.match(t2,"%w.*")
+
+ -- If there is no next word/number in both, sort by index. If there is
+ -- no next word/number in one but not the other, sort the shorter string
+ -- before the longer one.
+ if not t1 then
+ if not t2 then break end
+ return true
+ elseif not t2 then return false end
+
+ -- If one is a number, sort the number before the word. If both are
+ -- numbers (and are not equal), then sort in numerical order.
+ local n1, n2
+ n1, t1 = numprefix(t1)
+ n2, t2 = numprefix(t2)
+ if n1 then
+ if not n2 or n1 < n2 then return true end
+ if n1 > n2 then return false end
+ elseif n2 then return false
+ else
+ -- Otherwise, both are words. Lexicographically compare the words
+ -- according to the current locale's collation conventions. If the
+ -- locale considers them "equal" (i.e., w1<w2 is false but w1<=w2 is true)
+ -- then continue the loop to consider the next pair of words.
+ local w1, w2 = unicode.utf8.match(t1,"^[%a'`]*"),
+ unicode.utf8.match(t2,"^[%a'`]*")
+ local diff = w1 < w2
+ if diff or not (w1 <= w2) then return diff end
+ t1, t2 = t1:sub(#w1+1), t2:sub(#w2+1)
+ end
+ end
+
+ -- If all corresponding words/numbers are equal, then sort alternate-form
+ -- entries (e.g., lyrics) after normal entries (e.g., titles)
+ local alt1, alt2 = s1["title"]:sub(1,1), s2["title"]:sub(1,1)
+ if alt1 == "*" and alt2 ~= "*" then return false end
+ if alt1 ~= "*" and alt2 == "*" then return true end
+
+ -- If everything is the same, sort by the right-hand sides of the index
+ -- entries (e.g., the song or page numbers).
+ return s1["idx"] < s2["idx"]
+end
+
+-- setstartchars(<array>)
+-- Try to find canonical "start characters" for each block of songs in a
+-- sorted <array> of songs. Since Lua doesn't currently have any means of
+-- imparting a locale's alphabet, we adopt the following strategy: Extract
+-- the first unicode character from each title in the sorted list of titles
+-- until reaching one that the locale's collation algorithm says is "bigger"
+-- than the last. Find the "smallest" first character in that set using
+-- NON-UNICODE lexicographic sort. This tends to be the most canonical one,
+-- since unicode tends to put canonical (e.g., no-accent) glyphs at lower
+-- code points than non-canonical (e.g., accented) ones. (Unfortunately, if
+-- none of the titles in the block start with the desired canonical glyph,
+-- there's no way to guess it; we just use the best one available.)
+function setstartchars(songs)
+ local start = 1
+ local best
+
+ for i=1, #songs do
+ local c = unicode.utf8.match(cleantitle(songs[i]),"%w")
+ if c then
+ c = unicode.utf8.upper(c)
+ if not best then
+ songs[start]["newblk"], start, best = "\\#", i, c
+ elseif best < c then
+ songs[start]["newblk"], start, best = best, i, c
+ elseif #c < #best then best = c
+ elseif #c == #best then
+ for j=1,#c do
+ if c:byte(j) < best:byte(j) then best = c; break
+ elseif c:byte(j) > best:byte(j) then break end
+ end
+ end
+ elseif best then
+ songs[start]["newblk"], start, best = best, i, nil
+ end
+ end
+
+ if start <= #songs then
+ if best then
+ songs[start]["newblk"] = best
+ else
+ songs[start]["newblk"] = "\\#"
+ end
+ end
+end
+
+prelist = { A=true, THE=true }
+wt_and = { AND=true }
+wt_by = { BY=true }
+wt_unknown = { UNKNOWN=true }
+
+-- rotate(<title>)
+-- If the first word of <title> is any word in prelist, then shift that word
+-- to the end of the string, preceded by a comma and a space. So for example,
+-- if prelist contains "The", then rotate("The title") returns "Title, The".
+-- Words in prelist are matched case-insensitively, and the new first word
+-- becomes capitalized. If <title> begins with the marker character '*',
+-- that character is ignored and left unchanged.
+function rotate(s)
+ local t = unicode.utf8.upper(s)
+ local n = 0
+ if s:sub(1,1) == "*" then n = 1 end
+ for pre in pairs(prelist) do
+ if t:sub(1+n,n+#pre) == pre and
+ unicode.utf8.find(t, "^%s+%S", n+#pre+1) then
+ local len = unicode.utf8.len(pre)
+ local x, y, z = unicode.utf8.match(unicode.utf8.sub(s,n+len+1),"^%s+(%W*)(%w?)(.*)$")
+ return s:sub(1,n) .. x .. unicode.utf8.upper(y) .. z:gsub("\\%s","%0\1"):match("^(.-)%s*$"):gsub("\1","") .. ",~" .. unicode.utf8.sub(s,1+n,n+len)
+ end
+ end
+ return s
+end
+
+-- matchany(<string>,<init>,<wordtable>)
+-- If a word in <wordtable> case-insensitively matches to <string> starting
+-- at index <init>, and if the match concludes with whitespace, then return
+-- the index of the whitespace; otherwise return <init>.
+function matchany(s,init,wt)
+ local t = s:sub(init)
+ local u = unicode.utf8.upper(t)
+ for w,_ in pairs(wt) do
+ if u:sub(1,#w) == w and
+ (#w == #u or unicode.utf8.find(u, "^%s", #w+1)) then
+ return init + #(unicode.utf8.sub(t,1,unicode.utf8.len(w)))
+ end
+ end
+ return init
+end
+
+-- issuffix(<string>,<init>)
+-- Return true if the abbreviation "Jr" or a roman numeral (followed by
+-- nothing, space, period, comma, or semicolon) appears at position <init>
+-- within <string>. Return false otherwise.
+function issuffix(s,i)
+ return unicode.utf8.find(s, "^Jr$", i) or
+ unicode.utf8.find(s, "^Jr[%s,;%.]", i) or
+ unicode.utf8.find(s, "^[IVX]+$", i) or
+ unicode.utf8.find(s, "^[IVX]+[%s,;%.]", i)
+end
+
+-- grabauthor(<string>)
+-- Return a string of the form "Sirname, Restofname" denoting the full name
+-- of the first author found in <string>; or return nil if no author name
+-- can be found. Also return an index to the suffix of <string> that was
+-- not parsed, and just the "Sirname" part as a stand-alone string.
+--
+-- Precondition: Caller must first sanitize <string> as follows:
+-- <string>:gsub("[\1\2\3]","")
+-- :gsub("\\\\","\\\1"):gsub("\\{","\\\2"):gsub("\\}","\\\3")
+--
+-- Postcondition: Caller must then unsanitize the returned <string> with:
+-- <string>:gsub("\1","\\"):gsub("\2","{"):gsub("\3","}")
+--
+-- This is to allow grabauthor() to safely use Lua's %b pattern to find
+-- balanced brace pairs without getting confused by escaped braces.
+--
+-- Heuristics:
+-- * Names are separated by punctuation (other than hyphens, periods,
+-- apostrophes, or backslashes) or by the word "and" (or whatever words
+-- are in wt_and).
+-- Special case: If a comma is followed by the abbreviation "Jr" or by a
+-- roman numeral, then the comma does NOT end the author's name.
+-- * If a name contains the word "by" (or anything in wt_by), then
+-- everything before it is not considered part of the name. (Let's hope
+-- nobody is named "By".)
+-- * The author's last name is always the last capitalized word in the
+-- name unless the last capitalized word is "Jr." or a roman numeral.
+-- In that case the author's last name is the penultimate captialized
+-- word.
+-- * If an author appears to have only a first name, or if the last name
+-- found according to the above heuristics is an abbreviation (ending in
+-- a period), look ahead in <string> until we find someone with a last
+-- name and use that one. This allows us to identify the first author in
+-- a string like "Joe, Billy E., and Bob Smith" to be "Joe Smith".
+-- * If the resultant name contains the word "unknown" (or any word in
+-- wt_unknown), it's probably not a real name. Recursively attempt
+-- to parse the next author.
+function grabauthor(authline,i)
+ i = unicode.utf8.find(authline, "[^%s,;]", i)
+ if not i then return nil end
+ i = unicode.utf8.find(authline, "%S", matchany(authline,i,wt_and))
+ if not i then return nil end
+ i = unicode.utf8.find(authline, "%S", matchany(authline,i,wt_by))
+ if not i then return nil end
+ local skip = (matchany(authline,i,wt_unknown) > i)
+
+ -- Set "first" to the index of the start of the first name, "last" to the
+ -- index of the start of the sirname, "suffix" to the index of any suffix
+ -- like "Jr." or "III" (or nil if there is none), and i to the index of the
+ -- first character beyond the end of this author's name.
+ local first,last,suffix = i,nil,nil
+ while i <= #authline do
+ while true do
+ local j = select(2,authline:find("^\\%A", i)) or
+ select(2,authline:find("^\\%a+%s*", i)) or
+ select(2,authline:find("^%b{}", i))
+ if not j then break end
+ i = j + 1
+ end
+ if i > #authline then break
+ elseif authline:sub(i,i) == "," then
+ local j = unicode.utf8.find(authline, "%S", i+1)
+ if j and issuffix(authline,j) then i = i + 1
+ else break end
+ elseif authline:sub(i,i) == ";" then break
+ elseif unicode.utf8.find(authline, "^%s", i) then
+ i = unicode.utf8.find(authline, "%S", i)
+ if not i then i = #authline + 1; break end
+ if matchany(authline, i, wt_and) > i then break end
+ skip = skip or (matchany(authline, i, wt_unknown) > i)
+ local j = matchany(authline, i, wt_by)
+ if j > i then
+ j = unicode.utf8.find(authline, "%S", j)
+ if not j then last = i; break end -- last name of "By"?
+ i,first,last,suffix = j,j,nil,nil
+ elseif issuffix(authline,i) then
+ suffix = i
+ elseif unicode.utf8.find(authline:sub(i):gsub("\\%A",""):gsub("\\%a+%s*",""),"^[%s{}'`\"]*%u") then
+ last,suffix = i,nil
+ end
+ else
+ i = select(2, unicode.utf8.find(authline, ".", i)) + 1
+ end
+ end
+
+ -- If an "unknown" word appeared, skip this entry and parse the next.
+ if skip then return grabauthor(authline,i) end
+
+ -- Find the sirname.
+ local sirname, fullname
+ if last then
+ sirname = unicode.utf8.gsub(authline:sub(last,(suffix or i)-1),
+ "([^%s,;\\])[%s,;]+$", "%1")
+ end
+ if not sirname or unicode.utf8.find(sirname, "%a%.$") then
+ -- Here's where it gets tough. We either have a single-word name, or the
+ -- last name ends in a "." which means maybe it's just a middle initial or
+ -- other abbreviation. We could be dealing with a line like, "Billy,
+ -- Joe E., and Bob Smith", in which case we have to go searching for the
+ -- real last name. To handle this case, we will try a recursive call.
+ local _,_,r = grabauthor(authline,i)
+ if r or not sirname then
+ fullname = unicode.utf8.gsub(authline:sub(first,i-1),
+ "([^%s,;\\])[%s,;]+$", "%1")
+ if r then return (r .. ", " .. fullname), i, r
+ else return fullname, i, nil end
+ end
+ end
+
+ -- Add the first name.
+ fullname = sirname .. ", " ..
+ unicode.utf8.gsub(authline:sub(first,(last or suffix or i)-1),
+ "([^%s,;\\])[%s,;]+$", "%1")
+
+ -- Add the suffix, if any.
+ if suffix then
+ fullname = fullname .. " " ..
+ unicode.utf8.gsub(authline:sub(suffix,i-1), "([^%s,;\\])[%s,;]+$", "%1")
+ end
+
+ return fullname, i, sirname
+end
+
+-- genindex(<fstate>,<outname>)
+-- Reads a title (if <authorindex>=false) or author (if <authorindex>=true)
+-- index data file from file table <fstate> and generates a new file named
+-- <outfile> containing a LaTeX title/author index.
+-- Return Value: 0 on success, 1 on warnings, or 2 on failure
+function genindex(fs,outname,authorindex)
+ local songs = {}
+ local seen = {}
+ local wt = { wt_sep, wt_after, wt_prefix, wt_ignore }
+ local typ = authorindex and "author" or "title"
+
+ io.stderr:write("songidx: Parsing ",typ," index data file ",fs["filename"],"...\n")
+
+ while true do
+ local buf = filereadln(fs)
+ if not buf then break end
+ if buf:sub(1,1) == "%" then
+ local j = buf:match("^()%%sep ") or
+ buf:match("^%%()after ") or
+ buf:match("^%%p()refix ") or
+ buf:match("^%%ig()nore ")
+ if j then
+ if not seen[j] then wt[j], seen[j] = {}, true end
+ wt[j][unicode.utf8.upper(buf:sub(buf:find(" ")+1))] = true
+ end
+ else
+ local snum = filereadln(fs)
+ if not snum then
+ io.stderr:write("songidx:",fs["filename"],":",fs["lineno"],": incomplete song entry (orphan ",typ,")\n")
+ return 2
+ end
+ local link = filereadln(fs)
+ if not link then
+ io.stderr:write("songidx:",fs["filename"],":",fs["lineno"],": incomplete song entry (missing hyperlink)\n")
+ return 2
+ end
+ if authorindex then
+ local i,a = 1
+ buf = buf:gsub("[\1\2\3]",""):gsub("\\\\","\\\1")
+ :gsub("\\{","\\\2"):gsub("\\}","\\\3")
+ while true do
+ a,i = grabauthor(buf, i)
+ if not a then break end
+ a = a:gsub("\1","\\"):gsub("\2","{"):gsub("\3","}")
+ table.insert(songs, {title=a, num=snum, linkname=link, idx=#songs})
+ end
+ else
+ buf = rotate(unicode.utf8.gsub(unicode.utf8.gsub(buf,"([^%s\\])%s+$","%1"),"^(%*?)%s+","%1"))
+ table.insert(songs, {title=buf, num=snum, linkname=link, idx=#songs})
+ end
+ end
+ end
+ fileclose(fs)
+
+ -- Sort the song table.
+ table.sort(songs, songcmp)
+ -- Find the index blocks.
+ setstartchars(songs)
+
+ -- Write the sorted data out to the output file.
+ io.stderr:write("songidx: Generating ",typ," index TeX file ",outname,"...\n")
+ local f,msg,errno
+ if outname == "-" then
+ f, outname = io.stdout, "stdout"
+ else
+ f,msg,errno = io.open(outname, "w")
+ if not f then
+ io.stderr:write("songidx: Unable to open ",outname," for writing.\n",
+ "Error ",errno,": ",msg,"\n")
+ return 2
+ end
+ end
+ for i=1, #songs do
+ if i>1 and songs[i]["title"] == songs[i-1]["title"] then
+ if not f:write("\\\\\\songlink{",songs[i]["linkname"],"}{",songs[i]["num"],"}") then return errorout(f) end
+ else
+ if songs[i]["newblk"] then
+ if i>1 then
+ if not f:write("}\n\\end{idxblock}\n") then return errorout(f) end
+ end
+ if not f:write("\\begin{idxblock}{",songs[i]["newblk"]) then return errorout(f) end
+ end
+ if songs[i]["title"]:find("^%*") then
+ if not f:write("}\n\\idxaltentry{",songs[i]["title"]:sub(2)) then return errorout(f) end
+ else
+ if not f:write("}\n\\idxentry{",songs[i]["title"]) then return errorout(f) end
+ end
+ if not f:write("}{\\songlink{",songs[i]["linkname"],"}{",songs[i]["num"],"}") then return errorout(f) end
+ end
+ end
+ if #songs > 0 then
+ if not f:write("}\n\\end{idxblock}\n") then return errorout(f) end
+ end
+
+ return 0
+end
+
+bible = {}
+chapX = 0
+
+-- readbible(<filename>)
+-- Read bible data file <filename> into the bible table. Return nil on error
+-- or true on success.
+function readbible(filename)
+ local fs = fileopen(filename)
+ if not fs then return nil end
+ bible = {}
+
+ while true do
+ local buf = filereadln(fs)
+ if not buf then break end
+ if buf:sub(1,1) ~= "#" and buf:find("%S") then
+ local t, vbuf = { name = buf:match("^[^|]*"),
+ aliases = "|" .. unicode.utf8.upper(buf) .. "|" }
+ repeat
+ vbuf = filereadln(fs)
+ if not vbuf then
+ io.stderr:write("songidx:",fs["filename"],":",fs["lineno"],": incomplete bible book entry (book title with no verses)\n")
+ fileclose(fs)
+ return nil
+ end
+ until vbuf:sub(1,1) ~= "#" and buf:find("%S")
+ if vbuf:find("[^%d%s]") then
+ io.stderr:write("songidx:",fs["filename"],":",fs["lineno"],": verse count includes a non-digit\n")
+ fileclose(fs)
+ return nil
+ end
+ for n in vbuf:gmatch("%d+") do
+ local i = tonumber(n)
+ if not i then
+ io.stderr:write("songidx:",fs["filename"],":",fs["lineno"],": invalid number ",n,"\n")
+ fileclose(fs)
+ return nil
+ end
+ i = math.floor(i)
+ if chapX < i+1 then chapX = i+1 end
+ table.insert(t, i)
+ end
+ table.insert(bible, t)
+ end
+ end
+
+ fileclose(fs)
+ return true
+end
+
+-- parseref(<string>,<init>,<book>,<chapter>)
+-- Interpret the characters starting at index <init> of <string> as a
+-- scripture reference, and return four values: (1) the index of the first
+-- character after <init> not parsed, (2) the book number parsed, (3) the
+-- chapter number parsed (or 1 if the book has only verses), and (4) the
+-- verse number parsed. Arguments <book> and <chapter> are the PREVIOUS book
+-- number and chapter parsed, or -1 if none. If book or chapter information
+-- is missing from <string>, they will be drawn from <book> and <chapter>.
+-- That way, successive calls can correctly parse a run-on string like
+-- "Philippians 3:1,5; 4:3", infering that "5" refers to "Philippians 3" and
+-- "4:3" refers to "Philippians". If the parser encounters an error in
+-- processing the book name (e.g., a book name was specified but not
+-- recognized), then #bible+1 is returned for the book. If no chapter or no
+-- verse is provided (e.g., the reference is just "Philippians" or
+-- "Philippians 3") then the chapter and/or verse are returned as -1.
+function parseref(s,i,book,ch)
+ local v = -1
+ i = unicode.utf8.find(s,"%S",i)
+ if not i then return nil end
+ local j = unicode.utf8.find(s,"[%d:]*%s*[,;%-]",i) or
+ unicode.utf8.find(s,"[%d:]*%s*$",i)
+ local bookname = "|" .. unicode.utf8.upper(unicode.utf8.match(s:sub(i,j-1), "(.-)%s*$")) .. "|"
+ i = j
+ if bookname ~= "||" then
+ book, ch = #bible+1, -1
+ for b,t in pairs(bible) do
+ if t["aliases"]:find(bookname, 1, true) then book = b; break end
+ end
+ end
+ j = unicode.utf8.find(s,"%D",i) or (#s+1)
+ if s:sub(j,j) == ":" then
+ ch, i = (tonumber(s:sub(i,j-1)) or -1), j+1
+ j = unicode.utf8.find(s,"%D",i) or (#s+1)
+ end
+ if ch<=0 and book>0 and #bible[book] == 1 then
+ -- Special case: This book has only one chapter.
+ ch = 1
+ end
+ if ch <= 0 then
+ ch = tonumber(s:sub(i,j-1)) or -1
+ else
+ v = tonumber(s:sub(i,j-1)) or -1
+ end
+ i = unicode.utf8.find(s,"%S",j)
+ if not i then i = #s+1
+ elseif not s:find("^[,;%-]",i) then return nil end
+ return i, book, ch, v
+end
+
+-- vlt(<chapter1>,<verse1>,<chapter2>,<verse2>)
+-- Return true if <chapter1>:<verse1> precedes <chapter2>:<verse2> and false
+-- otherwise.
+function vlt(ch1,v1,ch2,v2)
+ return ch1 < ch2 or (ch1 == ch2 and v1 < v2)
+end
+
+-- vinc(<book>,<chapter>,<verse>)
+-- Return the chapter,verse pair of the verse immediately following
+-- <chapter>:<verse> in <book>. If <chapter>:<verse> is the last verse in
+-- <book>, the returned chapter will not exist in <book>.
+function vinc(book,ch,v)
+ if v < bible[book][ch] then return ch, v+1 end
+ return ch+1, 1
+end
+
+-- vdec(<book>,<chapter>,<verse>)
+-- Return the chapter,verse pair of the verse immediately preceding
+-- <chapter>:<verse> in <book>. If <chapter> and <verse> are both 1,
+-- then 0,nil will be returned.
+function vdec(book,ch,v)
+ if v > 1 then return ch, v-1 end
+ return ch-1, bible[book][ch-1]
+end
+
+-- unpack_cv(<cv>)
+-- Decompose a chapter-verse key (computed as cv*chapX+v) into the original
+-- chapter and verse numbers.
+function unpack_cv(cv)
+ local v = cv % chapX
+ return (cv-v)/chapX, v
+end
+
+-- eqdom(<table1>,<table2>)
+-- Return true if two tables have identical domains; false otherwise.
+function eqdom(t1,t2)
+ for k,_ in pairs(t1) do if not t2[k] then return false end end
+ for k,_ in pairs(t2) do if not t1[k] then return false end end
+ return true
+end
+
+-- insertref(<is_add>,<changeset>,<chapter>,<verse>,<song>,<link>,<key>)
+-- Insert song <song>,<link>,<key> into the set of "adds" (if <is_add>=true)
+-- or "drops" (if <is_add>=false) for verse <chapter>:<verse> in <changeset>.
+-- A <changeset> is a table that maps cv's to {adds=<refset>, drops=<refset>}
+-- tables, where cv's are chapter-verse pairs encoded as chapter*chapX+verse.
+-- Each such entry denotes a verse where the set of songs that reference it
+-- changes. The "adds" field lists the songs that refer to this verse but
+-- not the previous one. The "drops" field lists the songs that refer to
+-- this verse but not the next. This formulation allows us to efficiently
+-- represent range-references (e.g., "Psalms 1:1-8") without creating a
+-- separate table entry for each verse in the range.
+-- Create a new entry for <chapter>:<verse> in <changeset> if it doesn't
+-- already exist. Return the new <changeset>.
+function insertref(is_add,set,ch,v,n,l,k)
+ if not set then set = {} end
+ local cv = ch*chapX+v
+ if not set[cv] then set[cv] = { adds={}, drops={} } end
+ set[cv][is_add and "adds" or "drops"][k] = { num=n, link=l }
+ return set
+end
+
+-- print_vrange(<file>,<book>,<ch1>,<v1>,<ch2>,<v2>,<lastchapter>)
+-- Output LaTeX material to file <file> for verse range <ch1>:<v1>--<ch2>:<v2>
+-- of book number <book>. Depending on <lastchapter>, the outputted material
+-- might be the start of a new index entry or the continuation of a previous
+-- entry. If <lastchapter> is positive, continue the previous entry and
+-- print the chapter of <ch1>:<v1> only if it differs from <lastchapter>. If
+-- <lastchapter> is negative, continue the previous entry and always print
+-- the chapter number of <ch1>:<v1>.
+function print_vrange(f,b,ch1,v1,ch2,v2,lch)
+ local r = f:write(lch == 0 and "\\idxentry{" or ",")
+
+ if v1 <= 0 then
+ if lch ~= 0 then r = r and f:write("\\thinspace ") end
+ r = r and f:write(ch1)
+ elseif 0 <= b and b < #bible and #bible[b] == 1 then
+ -- This book has only one chapter.
+ if lch ~= 0 then r = r and f:write("\\thinspace ") end
+ r = r and f:write(v1)
+ elseif lch <= 0 or lch ~= ch1 or ch1 ~= ch2 then
+ if lch ~= 0 then r = r and f:write(" ") end
+ r = r and f:write(ch1,":",v1)
+ else
+ if lch ~= 0 then r = r and f:write("\\thinspace ") end
+ r = r and f:write(v1)
+ end
+
+ if vlt(ch1,v1,ch2,v2) then
+ if v2 <= 0 then
+ r = r and f:write("--",ch2)
+ elseif ch1 ~= ch2 then
+ r = r and f:write("--",ch2,":",v2)
+ else
+ r = r and f:write("--",v2)
+ end
+ end
+
+ return r
+end
+
+-- print_reflist(<file>,<refset>)
+-- Output the list of song references given by <refset> in sorted order
+-- to file <file>.
+function print_reflist(f,t)
+ local r = true
+ local s = {}
+ for k,_ in pairs(t) do table.insert(s,k) end
+ table.sort(s)
+
+ local first = true
+ for _,k in ipairs(s) do
+ if first then first = false else r = r and f:write("\\\\") end
+ r = r and f:write("\\songlink{",t[k]["link"],"}{",t[k]["num"],"}")
+ end
+ return r
+end
+
+function debug_print_reflist(r)
+ local first = true
+ io.stderr:write("{")
+ for k,_ in pairs(r) do
+ if first then first=false else io.stderr:write(",") end
+ io.stderr:write(k)
+ end
+ io.stderr:write("}")
+end
+
+function debug_print_changeset(x)
+ if not x then io.stderr:write("nil") else
+ for cv,r in pairs(x) do
+ local ch,v = unpack_cv(cv)
+ io.stderr:write("{",ch,":",v," --> adds=")
+ debug_print_reflist(r["adds"])
+ io.stderr:write(", drops=")
+ debug_print_reflist(r["drops"])
+ io.stderr:write("}")
+ end
+ end
+end
+
+-- genscriptureindex(<fstate>,<outname>,<biblename>)
+-- Generate a LaTeX file named <outname> containing material suitable to
+-- typeset the scripture index data found in input file <fstate>. Input
+-- bible data from an ascii file named <biblename>. Return 0 on success,
+-- 1 if there were warnings, and 2 if there was a fatal error.
+function genscriptureindex(fs,outname,biblename)
+ local hadwarnings = 0
+ local idx = {}
+
+ io.stderr:write("songidx: Parsing scripture index data file ",fs["filename"],"...\n")
+
+ -- Read the bible data file into the bible array.
+ if not readbible(biblename) then return 2 end
+
+ -- Walk through the input file and construct a <changeset> for each book
+ -- of the bible. Each changeset represents the set of verses in that book
+ -- referred to by songs in the song book.
+ local key = 0
+ while true do
+ local ref = filereadln(fs)
+ if not ref then break end
+ local n = filereadln(fs)
+ if not n then
+ io.stderr:write("songidx:",fs["filename"],":",fs["lineno"],": incomplete song entry (orphan reference line)\n")
+ fileclose(fs)
+ return 2
+ end
+ local l = filereadln(fs)
+ if not l then
+ io.stderr:write("songidx:",fs["filename"],":",fs["lineno"],": incomplete song entry (missing hyperlink)\n")
+ fileclose(fs)
+ return 2
+ end
+ key = key + 1
+
+ local i = 1
+ local book, ch1, v1, ch2, v2 = -1, -1, -1, -1, -1
+ while i <= #ref do
+ i,book,ch1,v1 = parseref(ref,i,book,ch1)
+ ch2,v2 = ch1,v1
+ if not i then
+ io.stderr:write("songidx:",fs["filename"],":",fs["lineno"],": WARNING: Malformed scripture reference for song ",n,". Ignoring it.\n")
+ hadwarnings = 1
+ break
+ end
+ if book < 1 then
+ io.stderr:write("songidx:",fs["filename"],":",fs["lineno"],": WARNING: Scripture reference for song ",n," doesn't include a book name. Ignoring it.\n")
+ hadwarnings = 1
+ break
+ end
+ if book > #bible then
+ io.stderr:write("songidx:",fs["filename"],":",fs["lineno"],": WARNING: Scripture reference for song ",n," references unknown book. Ignoring it.\n")
+ hadwarnings = 1
+ break
+ end
+ if ch1 < 1 then ch1 = 1 end
+ if ch1 > #bible[book] then
+ io.stderr:write("songidx:",fs["filename"],":",fs["lineno"],": WARNING: Scripture reference for song ",n," refers to ",bible[book]["name"]," ",ch1,", which doesn't exist. Ignoring it.\n")
+ hadwarnings = 1
+ break
+ end
+ if v1 < 1 then v1 = 1 end
+ if v1 > bible[book][ch1] then
+ io.stderr:write("songidx:",fs["filename"],":",fs["lineno"],": WARNING: Scripture reference for song ",n," refers to ",bible[book]["name"]," ",ch1,":",v1,", which doesn't exist. Ignoring it.\n")
+ hadwarnings = 1
+ break
+ end
+
+ if ref:sub(i,i) == "-" then
+ -- If the reference ends in a "-", it starts an explicit range.
+ -- Parse the next reference to find the range's end.
+ i = unicode.utf8.find(ref, "[^%s%-]", i)
+ if not i then
+ io.stderr:write("songidx:",fs["filename"],":",fs["lineno"],": WARNING: Scripture reference for song ",n," has range with no limit. Ignoring it.\n")
+ hadwarnings = 1
+ break
+ end
+ local book2
+ i,book2,ch2,v2 = parseref(ref,i,book,ch1)
+ if not i then
+ io.stderr:write("songidx:",fs["filename"],":",fs["lineno"],": WARNING: Malformed scripture reference for song ",n,". Ignoring it.\n")
+ hadwarnings = 1
+ break
+ end
+ if book2 ~= book then
+ io.stderr:write("songidx:",fs["filename"],":",fs["lineno"],": WARNING: Scripture reference for song ",n," appears to span books! Ignoring it.\n")
+ hadwarnings = 1
+ break
+ end
+ end
+ if ch2 < 1 then ch2 = #bible[book] end
+ if ch2 > #bible[book] then
+ io.stderr:write("songidx:",fs["filename"],":",fs["lineno"],": WARNING: Scripture reference for song ",n," refers implicitly to ",bible[book]["name"]," ",ch2,", which doesn't exist. Ignoring it.\n")
+ hadwarnings = 1
+ break
+ end
+ if v2 < 1 then v2 = bible[book][ch2]
+ elseif v2 > bible[book][ch2] then
+ io.stderr:write("songidx:",fs["filename"],":",fs["lineno"],": WARNING: Scripture reference for song ",n," refers implicitly to chapter ",ch2," of ",bible[book]["name"],", which doesn't exist. Ignoring it.\n")
+ hadwarnings = 1
+ break
+ end
+ if vlt(ch2,v2,ch1,v1) then
+ io.stderr:write("songidx:",fs["filename"],":",fs["lineno"],": WARNING: Scripture reference for song ",n," contains backwards range ",bible[book]["name"]," ",ch1,":",v1,"-",ch2,":",v2,". Ignoring it.\n")
+ hadwarnings = 1
+ break
+ end
+ if i < #ref then i = i + 1 end
+
+ idx[book] = insertref(true, idx[book], ch1, v1, n, l, key)
+ idx[book] = insertref(false, idx[book], ch2, v2, n, l, key)
+ end
+ end
+ fileclose(fs)
+
+ -- Now create the index .sbx file.
+ io.stderr:write("songidx: Generating scripture index TeX file ",outname,"...\n")
+ local f,msg,errno
+ if outname == "-" then
+ f, outname = io.stdout, "stdout"
+ else
+ f,msg,errno = io.open(outname, "w")
+ if not f then
+ io.stderr:write("songidx: Unable to open ",outname," for writing.\n",
+ "Error ",errno,": ",msg,"\n")
+ return 2
+ end
+ end
+
+ -- For each book of the bible the has songs that reference it, go through its
+ -- <changeset> and generate a sequence of index entries. Wherever possible,
+ -- compact adjacent entries that have identical <refset>'s so that we never
+ -- have two consecutive index entries with identical right-hand sides.
+ for b=1,#bible do
+ local x = idx[b]
+ if x then
+ -- io.stderr:write("idx[",b,"] = ")
+ -- debug_print_changeset(x)
+ local s, t = {}, {}
+ for cv,_ in pairs(x) do table.insert(s,cv) end
+ table.sort(s)
+ local lch = 0 -- 0=none, -1=force printing of chapter
+ local cv1 = s[1]
+ local ch1,v1 = unpack_cv(cv1)
+ if not f:write("\\begin{idxblock}{",bible[b]["name"],"}\n") then return errorout(f) end
+ for i,cv in ipairs(s) do
+ local this = x[cv]
+ local ch,v = unpack_cv(cv)
+ local ncv,nxt,nch,nv = s[i+1]
+ if ncv then
+ nxt,nch,nv = x[ncv], unpack_cv(ncv)
+ end
+ for k,r in pairs(this["adds"]) do t[k] = r end
+ local skip = false
+ if ncv and eqdom(this["drops"], nxt["adds"]) then
+ -- Set of drops here equals set of adds next time. There's at least
+ -- a chance that we can combine this item and the next one into a
+ -- single index entry.
+ local ch2, v2 = vinc(b,ch,v)
+ if not vlt(ch2,v2, nch,nv) then
+ -- If the next item is adjacent to this one, do nothing. Just let
+ -- the range in progress be extended. We'll output a single entry
+ -- for all of these adjacent verses when we reach the end.
+ skip = true
+ elseif eqdom(t, this["drops"]) then
+ -- Otherwise, if the next item is not adjacent but all refs are
+ -- dropped here, then print a partial entry to be continued with a
+ -- comma next time.
+ if not print_vrange(f,b,ch1,v1,ch,v,lch) then return errorout(f) end
+ lch = (ch1 == ch) and ch or -1
+ ch1, v1 = nch, nv
+ skip = true
+ end
+ end
+ if not skip then
+ if next(this["drops"]) then
+ -- Some songs get dropped here, and either the next item is not
+ -- adjacent to this one, or it's adjacent and the set of adds is not
+ -- the same. In either case, that means the set of refs changes at
+ -- this point, so we need to output a full entry (or finish the one
+ -- in progress).
+ if not (print_vrange(f,b,ch1,v1,ch,v,lch) and
+ f:write("}{") and
+ print_reflist(f,t) and
+ f:write("}\n")) then return errorout(f) end
+ for k,_ in pairs(this["drops"]) do t[k] = nil end
+ lch = 0
+ if not next(t) and ncv then
+ ch1, v1 = nch, nv
+ else
+ ch1, v1 = vinc(b,ch,v)
+ end
+ end
+ if next(t) and ncv and next(nxt["adds"]) and vlt(ch1,v1,nch,nv) then
+ -- There are verses between this item and the next which have refs,
+ -- but the refs change at the beginning of the next item. Make an
+ -- entry for the intermediate block of verses.
+ local ch2, v2 = vdec(b,nch,nv)
+ if not (print_vrange(f,b,ch1,v1,ch2,v2,lch) and
+ f:write("}{") and
+ print_reflist(f,t) and
+ f:write("}\n")) then return errorout(f) end
+ lch, ch1, v1 = 0, nch, nv
+ end
+ end
+ end
+ if not f:write("\\end{idxblock}\n") then return errorout(f) end
+ end
+ end
+
+ closeout(f)
+ return hadwarnings
+end
+
+-- Main program entry point
+function main()
+ local fs, biblename, inname, outname, locale
+
+ local i = 1
+ while arg[i] do
+ if arg[i] == "-v" or arg[i] == "--version" then
+ io.write("songidx ", VERSION, "\n",
+ "Copyright (C) 2017 Kevin W. Hamlen\n",
+ "License GPLv2: GNU GPL version 2 or later",
+ " <http://gnu.org/licenses/gpl.html>\n",
+ "This is free software: you are free to change and redistribute it.\n",
+ "There is NO WARRANTY, to the extent permitted by law.\n")
+ return 0
+ elseif arg[i] == "-h" or arg[i] == "--help" then
+ io.write("Syntax: ",arg[-1]," ",arg[0]," [options] input.sxd [output.sbx]\n",
+"Available options:\n",
+" -b FILE Set the bible format when generating a scripture index\n",
+" --bible FILE (default: ", BIBLEDEFAULT, ")\n",
+"\n",
+" -l LOCALE Override the default system locale (affecting how non-\n",
+" --locale LOCALE English characters are sorted). See your system help\n",
+" for valid LOCALEs.\n",
+"\n",
+" -h Display this help file and stop.\n",
+" --help\n",
+"\n",
+" -v Print version information and stop.\n",
+" --version\n",
+"\n",
+"If omitted, [output.sbx] defaults to the input filename but with the file\n",
+"extension renamed to '.sbx'. To read or write to stdin or stdout, use '-'\n",
+"in place of input.sxd or output.sbx.\n",
+"\n",
+"See http://songs.sourceforge.net for support.\n")
+ return 0
+ elseif arg[i] == "-b" or arg[i] == "--bible" then
+ if biblename then
+ io.stderr:write("songidx: multiple bible files specified\n")
+ return 2
+ end
+ i = i + 1
+ if arg[i] then
+ biblename = arg[i]
+ else
+ io.stderr:write("songidx: ",arg[i-1]," option requires an argument\n")
+ return 2
+ end
+ elseif arg[i] == "-l" or arg[i] == "--locale" then
+ if locale then
+ io.stderr:write("songidx: multiple locales specified\n")
+ return 2
+ end
+ i = i + 1
+ if arg[i] then
+ locale = arg[i]
+ else
+ io.stderr:write("songidx: ",arg[i-1]," requires an argument\n")
+ return 2
+ end
+ elseif arg[i] == "-o" or arg[i] == "--output" then
+ if outname then
+ io.stderr:write("songidx: multiple output files specified\n")
+ return 2
+ end
+ i = i + 1
+ if arg[i] then
+ outname = arg[i]
+ else
+ io.stderr:write("songidx: ",arg[i-1]," option requires an argument\n")
+ return 2
+ end
+ elseif arg[i]:sub(1,1) == "-" and arg[i] ~= "-" then
+ io.stderr:write("songidx: unknown option ",arg[i],"\n")
+ return 2
+ elseif not inname then inname = arg[i]
+ elseif not outname then outname = arg[i]
+ else
+ io.stderr:write("songidx: too many command line arguments\n")
+ return 2
+ end
+ i = i + 1
+ end
+
+ if not locale then
+ os.setlocale("")
+ elseif not os.setlocale(locale) then
+ io.stderr:write("songidx: invalid locale: ",locale,"\n")
+ return 2
+ end
+
+ if not inname then
+ io.stderr:write("songidx: no input file specified\n")
+ return 2
+ end
+ if not outname then
+ if inname == "-" then
+ outname = "-"
+ else
+ local n
+ outname,n = inname:gsub("%.[^%./\\]*$", ".sbx")
+ if n == 0 then outname = inname .. ".sbx" end
+ end
+ end
+ if not biblename then biblename = BIBLEDEFAULT end
+
+ fs = fileopen(inname)
+ if not fs then return 2 end
+
+ local retval = 2
+ local buf = filereadln(fs)
+ if not buf then
+ io.stderr:write("songidx:",fs["filename"],": file is empty\n")
+ fileclose(fs)
+ elseif buf == "TITLE INDEX DATA FILE" then
+ retval = genindex(fs,outname,false)
+ elseif buf == "SCRIPTURE INDEX DATA FILE" then
+ retval = genscriptureindex(fs,outname,biblename)
+ elseif buf == "AUTHOR INDEX DATA FILE" then
+ retval = genindex(fs,outname,true)
+ else
+ io.stderr:write("songidx:",fs["filename"],":",fs["lineno"],": file has unrecognized format\n")
+ fileclose(fs)
+ end
+
+ if retval == 0 then
+ io.stderr:write("songidx: Done!\n")
+ elseif retval == 1 then
+ io.stderr:write("songidx: COMPLETED WITH ERRORS. SEE ABOVE.\n")
+ else
+ io.stderr:write("songidx: FAILED. SEE ERROR MESSAGES ABOVE.\n")
+ end
+
+ return retval
+end
+
+os.exit(main())
+
diff --git a/Master/texmf-dist/doc/latex/songs/songidx/songsort.c b/Master/texmf-dist/doc/latex/songs/songidx/songsort.c
deleted file mode 100644
index 22825733727..00000000000
--- a/Master/texmf-dist/doc/latex/songs/songidx/songsort.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/* Copyright (C) 2012 Kevin W. Hamlen
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * The latest version of this program can be obtained from
- * http://songs.sourceforge.net.
- */
-
-
-#if HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "vsconfig.h"
-#endif
-
-#include "chars.h"
-#include "songidx.h"
-#include "fileio.h"
-
-/* skipesc_sp(<ptr>,<flag>)
- * Walk <ptr> past any LaTeX macros or braces until we reach the next "real"
- * character. If <flag> is 1, then make an exception for space-macros.
- * The space macro "\ " causes p to stop on the space. */
-void
-skipesc_sp(p, stop_on_space)
- const WCHAR **p;
- int stop_on_space;
-{
- for (;;)
- {
- if (**p == wc_backslash)
- {
- ++(*p);
- if (stop_on_space && wc_isspace(**p)) return;
- if (wc_isalpha(**p)) while (wc_isalpha(**p)) ++(*p);
- else if (**p) ++(*p);
- while (wc_isspace(**p)) ++(*p);
- }
- else if (**p == wc_lbrace)
- {
- ++(*p);
- while (wc_isspace(**p)) ++(*p);
- }
- else if (**p == wc_rbrace)
- ++(*p);
- else
- break;
- }
-}
-
-/* skipesc(<ptr>)
- * Walk <ptr> past any LaTeX macros or braces until we reach the next "real"
- * character. */
-void
-skipesc(p)
- const WCHAR **p;
-{
- skipesc_sp(p,0);
-}
-
-/* inword(<char>)
- * Return 0 if <char> is a word-delimiter (for sorting purposes) and 1
- * otherwise. Other than TeX macros (which are handled by skipesc above),
- * words only have alphabetics and apostrophes. */
-static int
-inword(c)
- WCHAR c;
-{
- return (wc_isalpha(c) || (c==wc_apostrophe) || (c==wc_backquote));
-}
-
-/* songcmp(<song1>,<song2>)
- * Return a negative number if <song1> is less than <song2>, a positive
- * number if <song1> is greater than <song2>, and 0 if <song1> and <song2>
- * are equal. The ordering is first by title, then by index. This function
- * is suitable for use with qsort(). */
-int
-songcmp(s1,s2)
- const void *s1;
- const void *s2;
-{
- static WCHAR buf1[MAXLINELEN+1], *bp1;
- static WCHAR buf2[MAXLINELEN+1], *bp2;
- const WCHAR *t1 = (*((const SONGENTRY **) s1))->title;
- const WCHAR *t2 = (*((const SONGENTRY **) s2))->title;
- int diff;
-
- for (;;)
- {
- /* Find the next word or number in each string. */
- skipesc(&t1);
- while(*t1 && !wc_isalpha(*t1) && !wc_isdigit(*t1))
- {
- ++t1;
- skipesc(&t1);
- }
- skipesc(&t2);
- while(*t2 && !wc_isalpha(*t2) && !wc_isdigit(*t2))
- {
- ++t2;
- skipesc(&t2);
- }
-
- /* If there is no next word/number in one or both, sort the shorter
- * string before the longer one. */
- if ((*t1==wc_null) || (*t2==wc_null))
- {
- if ((*t1==wc_null) && (*t2==wc_null)) break;
- return (t1!=wc_null) ? 1 : -1;
- }
-
- /* If one is a number, sort the number before the word. If both are
- * numbers, sort in numerical order. */
- if (wc_isdigit(*t1) || wc_isdigit(*t2))
- {
- long n1, n2;
- WCHAR *p1, *p2;
- if (!wc_isdigit(*t1)) return 1;
- if (!wc_isdigit(*t2)) return -1;
- n1 = ws_strtol(t1, &p1, 10);
- t1 = p1;
- n2 = ws_strtol(t2, &p2, 10);
- t2 = p2;
- if (n1 == n2) continue;
- return n1-n2;
- }
-
- /* Otherwise, both are words. Copy the words into scratch buffers,
- * omitting any macros or braces. Then lexographically compare the buffer
- * contents to determine how the original strings should be sorted. */
- for (bp1=buf1; inword(*t1); skipesc_sp(&t1,1)) *bp1++=wc_tolower(*t1++);
- for (bp2=buf2; inword(*t2); skipesc_sp(&t2,1)) *bp2++=wc_tolower(*t2++);
- *bp1 = *bp2 = wc_null;
- if ((diff = ws_coll(buf1,buf2)) != 0) return diff;
- }
-
- /* If each corresponding word/number is identical, then sort alternate-
- * form entries (e.g., lyrics) after normal entries (e.g., titles). */
- if (((*((const SONGENTRY **) s1))->title[0] == wc_asterisk)
- && ((*((const SONGENTRY **) s2))->title[0] != wc_asterisk))
- return 1;
- if (((*((const SONGENTRY **) s1))->title[0] != wc_asterisk)
- && ((*((const SONGENTRY **) s2))->title[0] == wc_asterisk))
- return -1;
-
- /* If everything is the same, sort by the right-hand sides of the index
- * entries (e.g., the song or page numbers). */
- return (*((const SONGENTRY **) s1))->idx - (*((const SONGENTRY **) s2))->idx;
-}
diff --git a/Master/texmf-dist/doc/latex/songs/songidx/tanakh.can b/Master/texmf-dist/doc/latex/songs/songidx/tanakh.can
index 6a3053c94eb..4e941a1fe1a 100644
--- a/Master/texmf-dist/doc/latex/songs/songidx/tanakh.can
+++ b/Master/texmf-dist/doc/latex/songs/songidx/tanakh.can
@@ -1,4 +1,4 @@
-# Copyright (C) 2012 Kevin W. Hamlen
+# Copyright (C) 2017 Kevin W. Hamlen
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
diff --git a/Master/texmf-dist/doc/latex/songs/songidx/titleidx.c b/Master/texmf-dist/doc/latex/songs/songidx/titleidx.c
deleted file mode 100644
index cde08511a0c..00000000000
--- a/Master/texmf-dist/doc/latex/songs/songidx/titleidx.c
+++ /dev/null
@@ -1,379 +0,0 @@
-/* Copyright (C) 2012 Kevin W. Hamlen
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * The latest version of this program can be obtained from
- * http://songs.sourceforge.net.
- */
-
-
-/* Create a LaTeX title index file from a title .sxd file. */
-
-#if HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "vsconfig.h"
-#endif
-
-#include "chars.h"
-#include "songidx.h"
-#include "fileio.h"
-
-#if HAVE_STRING_H
-# include <string.h>
-#elif HAVE_STRINGS_H
-# include <strings.h>
-#endif
-
-/* By convention, some word prefixes always get moved to the end of a title
- * before it is indexed. For example, in English "The Song Title" becomes
- * "Song Title, The". The following structure stores the list of these prefix
- * words. The default is "The" and "A". */
-typedef struct prefix
-{
- struct prefix *next;
- WCHAR *s;
-}
-PREFIX;
-
-PREFIX pre_A = { NULL, ws_lit("A") };
-PREFIX pre_defaults = { &pre_A, ws_lit("The") };
-
-/* freeprefixes(<list>)
- * Free prefix list <list>. */
-static void
-freeprefixes(pl)
- PREFIX *pl;
-{
- if (pl == &pre_defaults) return;
- while (pl)
- {
- PREFIX *nxt = pl->next;
- free(pl->s);
- free(pl);
- pl = nxt;
- }
-}
-
-/* rotate(<title>, <prelist>)
- * If the first word of <title> is any word in list <prelist>, then <title>
- * is modified in-place so that the word is shifted to the end of the string
- * and preceded by a comma and a space. So for example, rotate("The Title",
- * <prelist>) where <prelist> is the default results in "Title, The". Words
- * in <prelist> are matched case-insensitively. If <title> begins with the
- * marker character '*', that character is ignored and left unchanged. Note
- * that <title> MUST be allocated with ONE EXTRA WCHAR OF STORAGE in order
- * to leave room for the extra comma.
- * Return Value: 1 if <title> was modified and 0 otherwise. */
-static int
-rotate(s,pl)
- WCHAR *s;
- PREFIX *pl;
-{
- const WCHAR *s2, *w2;
-
- w2 = NULL;
- if (*s==wc_asterisk) ++s;
- for (; pl; pl=pl->next)
- {
- for (s2=s, w2=pl->s; *w2; ++s2, ++w2)
- if (wc_tolower(*s2)!=wc_tolower(*w2)) break;
- if ((*w2 == wc_null) && (*s2 != wc_null) && !wc_isalpha(*s2)) break;
- }
- if (pl)
- {
- WCHAR buf[MAXLINELEN];
- size_t slen = ws_strlen(s);
- size_t wlen = w2 - pl->s;
- ws_strncpy(buf, s, wlen);
- buf[wlen] = wc_null;
- ws_memmove(s, s+wlen+1, slen-wlen-1);
- *s = wc_toupper(*s);
- *(s+slen-wlen-1) = wc_comma;
- *(s+slen-wlen) = wc_tilda;
- ws_strcpy(s+slen-wlen+1, buf);
- return 1;
- }
- return 0;
-}
-
-/* getstartchar(<string>,<default>)
- * Returns the first non-escaped, alphabetic character of <string>. If
- * <string> has no non-escaped, alphabetic characters, <default> is returned
- * instead. */
-static WCHAR
-getstartchar(s,def)
- const WCHAR *s;
- WCHAR def;
-{
- if (!s) return def;
- skipesc(&s);
- while ((*s!=wc_null) && !wc_isalpha(*s))
- {
- ++s;
- skipesc(&s);
- }
- return (*s!=wc_null) ? wc_toupper(*s) : def;
-}
-
-/* freesongarray(<array>,<len>)
- * Free song array <array>, which should have length <len>. */
-static void
-freesongarray(songs,len)
- SONGENTRY **songs;
- int len;
-{
- int i;
-
- if (!songs) return;
- for (i=0; i<len; ++i)
- {
- if (songs[i])
- {
- if (songs[i]->title) free(songs[i]->title);
- if (songs[i]->num) free(songs[i]->num);
- if (songs[i]->linkname) free(songs[i]->linkname);
- free(songs[i]);
- }
- }
- free(songs);
-}
-
-/* gentitleindex(<file>,<outname>)
- * Reads a title index data file from file handle <file> and generates a new
- * file named <outfile> containing a LaTeX title index.
- * Return Value: 0 on success, 1 on warnings, or 2 on failure */
-int
-gentitleindex(fs,outname)
- FSTATE *fs;
- const char *outname;
-{
- FILE *f;
- int eof = 0;
- int numsongs, arraysize, i;
- PREFIX *prelist = &pre_defaults;
- SONGENTRY **songs;
- WCHAR buf[MAXLINELEN], *bp;
- WCHAR startchar;
-
- fprintf(stderr, "songidx: Parsing title index data file %s...\n",
- fs->filename);
-
- songs = NULL;
- eof = 0;
- for (arraysize=numsongs=0; !eof; ++numsongs)
- {
- if (!filereadln(fs,buf,&eof))
- {
- freesongarray(songs,numsongs);
- return 2;
- }
- if (eof) break;
- if (buf[0] == wc_percent)
- {
- if (!ws_strncmp(buf, wc_lit("%prefix "), 8))
- {
- PREFIX *temp = (prelist==&pre_defaults) ? NULL : prelist;
- prelist = (PREFIX *) malloc(sizeof(PREFIX));
- prelist->next = temp;
- prelist->s = (WCHAR *) calloc(ws_strlen(buf)-7, sizeof(WCHAR));
- ws_strcpy(prelist->s, buf+8);
- }
- --numsongs;
- continue;
- }
- if (numsongs >= arraysize)
- {
- SONGENTRY **temp;
- arraysize *= 2;
- if (arraysize==0) arraysize=64;
- temp = (SONGENTRY **) realloc(songs,arraysize*sizeof(SONGENTRY *));
- if (!temp)
- {
- fprintf(stderr, "songidx:%s:%d: too many songs (out of memory)\n",
- fs->filename, fs->lineno);
- freeprefixes(prelist);
- freesongarray(songs,numsongs);
- return 2;
- }
- songs = temp;
- }
- if ((songs[numsongs] = (SONGENTRY *) malloc(sizeof(SONGENTRY))) == NULL)
- {
- fprintf(stderr, "songidx:%s:%d: too many songs (out of memory)\n",
- fs->filename, fs->lineno);
- freeprefixes(prelist);
- freesongarray(songs,numsongs);
- return 2;
- }
- songs[numsongs]->title = songs[numsongs]->num =
- songs[numsongs]->linkname = NULL;
- for (bp=buf+ws_strlen(buf)-1; (bp > buf) && wc_isspace(*bp); --bp) ;
- if (wc_isspace(*bp)) *bp = wc_null;
- for (bp=buf; wc_isspace(*bp); ++bp) ;
- /* The following allocates one extra char of storage because we might add
- * a comma later. */
- if ((songs[numsongs]->title =
- (WCHAR *) calloc(ws_strlen(bp)+2, sizeof(WCHAR))) == NULL)
- {
- fprintf(stderr, "songidx:%s:%d: too many songs (out of memory)\n",
- fs->filename, fs->lineno);
- freeprefixes(prelist);
- freesongarray(songs,numsongs+1);
- return 2;
- }
- ws_strcpy(songs[numsongs]->title, bp);
- rotate(songs[numsongs]->title, prelist);
- if (!filereadln(fs,buf,&eof))
- {
- freeprefixes(prelist);
- freesongarray(songs,numsongs+1);
- return 2;
- }
- if (eof)
- {
- fprintf(stderr, "songidx:%s:%d: incomplete song entry (orphan title)\n",
- fs->filename, fs->lineno);
- freeprefixes(prelist);
- freesongarray(songs,numsongs+1);
- return 2;
- }
- if ((songs[numsongs]->num =
- (WCHAR *) calloc(ws_strlen(buf)+1, sizeof(WCHAR))) == NULL)
- {
- fprintf(stderr, "songidx:%s:%d: too many songs (out of memory)\n",
- fs->filename, fs->lineno);
- freeprefixes(prelist);
- freesongarray(songs,numsongs+1);
- return 2;
- }
- ws_strcpy(songs[numsongs]->num, buf);
- if (!filereadln(fs,buf,&eof))
- {
- freeprefixes(prelist);
- freesongarray(songs,numsongs+1);
- return 2;
- }
- if (eof)
- {
- fprintf(stderr, "songidx:%s:%d: incomplete song entry"
- " (missing hyperlink)\n", fs->filename, fs->lineno);
- freeprefixes(prelist);
- freesongarray(songs,numsongs+1);
- return 2;
- }
- if ((songs[numsongs]->linkname =
- (WCHAR *) calloc(ws_strlen(buf)+1, sizeof(WCHAR))) == NULL)
- {
- fprintf(stderr, "songidx:%s:%d: too many songs (out of memory)\n",
- fs->filename, fs->lineno);
- freeprefixes(prelist);
- freesongarray(songs,numsongs);
- return 2;
- }
- ws_strcpy(songs[numsongs]->linkname, buf);
- songs[numsongs]->idx = numsongs;
- }
- fileclose(fs);
- freeprefixes(prelist);
-
- /* Sort the song array */
- qsort(songs, numsongs, sizeof(*songs), songcmp);
-
- /* Write the sorted data out to the output file. */
- fprintf(stderr, "songidx: Generating title index TeX file %s...\n", outname);
- if (strcmp(outname,"-"))
- {
- if ((f = fopen(outname, "w")) == NULL)
- {
- fprintf(stderr, "songidx: Unable to open %s for writing.\n", outname);
- return 2;
- }
- }
- else
- {
- f = stdout;
- outname = "stdout";
- }
-
-#define TRYWRITE(x) \
- if (!(x)) \
- { \
- fprintf(stderr, "songidx:%s: write error\n", outname); \
- if (f == stdout) fflush(f); else fclose(f); \
- freesongarray(songs,numsongs); \
- return 2; \
- }
-
- startchar = 'A';
- if (numsongs>0)
- {
- startchar = getstartchar(songs[0]->title, wc_capA);
- TRYWRITE((ws_fputs(ws_lit("\\begin{idxblock}{"), f) >= 0) &&
- (ws_fputc(startchar, f)==startchar))
- }
- for (i=0; i<numsongs; ++i)
- {
- WCHAR c = getstartchar(songs[i]->title, startchar);
- if ((i>0) && !ws_coll(songs[i]->title, songs[i-1]->title))
- {
- TRYWRITE((ws_fputs(ws_lit("\\\\\\hyperlink{"), f) >= 0) &&
- (ws_fputs(songs[i]->linkname, f) >= 0) &&
- (ws_fputs(ws_lit("}{"), f) >= 0) &&
- (ws_fputs(songs[i]->num, f) >= 0) &&
- (ws_fputs(ws_lit("}"), f) >= 0))
- continue;
- }
- else
- {
- TRYWRITE(ws_fputs(ws_lit("}\n"), f) >= 0)
- }
- if (startchar != c)
- {
- startchar = c;
- TRYWRITE((ws_fputs(ws_lit("\\end{idxblock}\n\\begin{idxblock}{"), f) >= 0)
- && (ws_fputc(startchar, f)==startchar)
- && (ws_fputs(ws_lit("}\n"), f) >= 0))
- }
- if (songs[i]->title[0] == wc_asterisk)
- {
- TRYWRITE((ws_fputs(ws_lit("\\idxaltentry{"), f) >= 0) &&
- (ws_fputs(songs[i]->title+1, f) >= 0) &&
- (ws_fputs(ws_lit("}{\\hyperlink{"), f) >= 0) &&
- (ws_fputs(songs[i]->linkname, f) >= 0) &&
- (ws_fputs(ws_lit("}{"), f) >= 0) &&
- (ws_fputs(songs[i]->num, f) >= 0) &&
- (ws_fputs(ws_lit("}"), f) >= 0))
- }
- else
- {
- TRYWRITE((ws_fputs(ws_lit("\\idxentry{"), f) >= 0) &&
- (ws_fputs(songs[i]->title, f) >= 0) &&
- (ws_fputs(ws_lit("}{\\hyperlink{"), f) >= 0) &&
- (ws_fputs(songs[i]->linkname, f) >= 0) &&
- (ws_fputs(ws_lit("}{"), f) >= 0) &&
- (ws_fputs(songs[i]->num, f) >= 0) &&
- (ws_fputs(ws_lit("}"), f) >= 0))
- }
- }
- TRYWRITE(ws_fputs(ws_lit("}\n\\end{idxblock}\n"), f) >= 0)
-
-#undef TRYWRITE
-
- if (f == stdout) fflush(f); else fclose(f);
- freesongarray(songs,numsongs);
- return 0;
-}
diff --git a/Master/texmf-dist/doc/latex/songs/songidx/vsconfig.h b/Master/texmf-dist/doc/latex/songs/songidx/vsconfig.h
deleted file mode 100644
index f8793af2fa4..00000000000
--- a/Master/texmf-dist/doc/latex/songs/songidx/vsconfig.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/* Copyright (C) 2012 Kevin W. Hamlen
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * The latest version of this program can be obtained from
- * http://songs.sourceforge.net.
- */
-
-/* This configuration file should work as-is for any system that has standard
- * C libraries. It has been tested successfully on Visual Studio and Linux.
- * If your system is non-standard, follow the directions below to customize it
- * for your system. */
-
-#ifndef CONFIG_H
-#define CONFIG_H
-
-
-/* Define to 1 if you have the <inttypes.h> header file. */
-/* #undef HAVE_INTTYPES_H */
-
-/* Define to 1 if you have the <locale.h> header file. */
-#define HAVE_LOCALE_H 1
-
-/* Define to 1 if you have the <memory.h> header file. */
-#define HAVE_MEMORY_H 1
-
-/* Define to 1 if your system has a GNU libc compatible `realloc' function,
- and to 0 otherwise. */
-#define HAVE_REALLOC 1
-
-/* Define to 1 if you have the `setlocale' function. */
-#define HAVE_SETLOCALE 1
-
-/* Define to 1 if you have the <stdint.h> header file. */
-/* #undef HAVE_STDINT_H */
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#define HAVE_STDLIB_H 1
-
-/* Define to 1 if you have the <stdio.h> header file. */
-#define HAVE_STDIO_H 1
-
-/* Define to 1 if you have the <strings.h> header file. */
-/* #undef HAVE_STRINGS_H */
-
-/* Define to 1 if you have the <string.h> header file. */
-#define HAVE_STRING_H 1
-
-/* Define to 1 if you have the `strrchr' function. */
-#define HAVE_STRRCHR 1
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#define HAVE_SYS_STAT_H 1
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#define HAVE_SYS_TYPES_H 1
-
-/* Define to 1 if you have the <unistd.h> header file. */
-/* #undef HAVE_UNISTD_H */
-
-/* Define to 1 if you have the <wchar.h> header file. */
-#define HAVE_WCHAR_H 1
-
-/* Define to 1 if you have the wchar_t type. */
-#define HAVE_WCHAR_T 1
-
-/* Define to 1 if you have the <wctype.h> header file. */
-#define HAVE_WCTYPE_H 1
-
-/* Name of package */
-#define PACKAGE "songs"
-
-/* Define to the address where bug reports for this package should be sent. */
-#define PACKAGE_BUGREPORT ""
-
-/* Define to the full name of this package. */
-#define PACKAGE_NAME "songs"
-
-/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "songs 2.14"
-
-/* Define to the one symbol short name of this package. */
-#define PACKAGE_TARNAME "songs"
-
-/* Define to the version of this package. */
-#define PACKAGE_VERSION "2.14"
-
-/* Define to 1 if you have the ANSI C header files. */
-#define STDC_HEADERS 1
-
-/* Version number of package */
-#define VERSION "2.14"
-
-/* Define to empty if `const' does not conform to ANSI C. */
-/* #undef const */
-
-/* Define to rpl_realloc if the replacement function should be used. */
-/* #undef realloc */
-
-/* Define to `unsigned int' if <sys/types.h> does not define. */
-/* #undef size_t */
-
-#endif