diff options
Diffstat (limited to 'Master/texmf-dist/doc/latex/songs/songidx/authidx.c')
-rw-r--r-- | Master/texmf-dist/doc/latex/songs/songidx/authidx.c | 488 |
1 files changed, 0 insertions, 488 deletions
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; -} |