1 /*
2  * biblio.c: process the bibliography
3  */
4 
5 #include <assert.h>
6 #include "halibut.h"
7 
gentext(int num)8 static wchar_t *gentext(int num) {
9     wchar_t text[22];
10     wchar_t *p = text + lenof(text);
11     *--p = L'\0';
12     *--p = L']';
13     while (num != 0) {
14 	assert(p > text);
15 	*--p = L"0123456789"[num % 10];
16 	num /= 10;
17     }
18     assert(p > text);
19     *--p = L'[';
20     return ustrdup(p);
21 }
22 
cite_biblio(keywordlist * kl,wchar_t * key,filepos fpos)23 static void cite_biblio(keywordlist *kl, wchar_t *key, filepos fpos) {
24     keyword *kw = kw_lookup(kl, key);
25     if (!kw)
26 	err_nosuchkw(&fpos, key);
27     else {
28 	/*
29 	 * We've found a \k reference. If it's a
30 	 * bibliography entry ...
31 	 */
32 	if (kw->para->type == para_Biblio) {
33 	    /*
34 	     * ... then mark the paragraph as cited.
35 	     */
36 	    kw->para->type = para_BiblioCited;
37 	}
38     }
39 }
40 
41 /*
42  * Make a pass through the source form, generating citation formats
43  * for bibliography entries and also marking which bibliography
44  * entries are actually cited (or \nocite-ed).
45  */
46 
gen_citations(paragraph * source,keywordlist * kl)47 void gen_citations(paragraph *source, keywordlist *kl) {
48     paragraph *para;
49     int bibnum = 0;
50 
51     for (para = source; para; para = para->next) {
52 	word *ptr;
53 
54 	/*
55 	 * \BR and \nocite paragraphs get special processing here.
56 	 */
57 	if (para->type == para_BR) {
58 	    keyword *kw = kw_lookup(kl, para->keyword);
59 	    if (!kw) {
60 		err_nosuchkw(&para->fpos, para->keyword);
61 	    } else if (kw->text) {
62 		err_multiBR(&para->fpos, para->keyword);
63 	    } else {
64 		kw->text = dup_word_list(para->words);
65 	    }
66 	} else if (para->type == para_NoCite) {
67 	    wchar_t *wp = para->keyword;
68 	    while (*wp) {
69 		cite_biblio(kl, wp, para->fpos);
70 		wp = uadv(wp);
71 	    }
72 	}
73 
74 	/*
75 	 * Scan for keyword references.
76 	 */
77 	for (ptr = para->words; ptr; ptr = ptr->next) {
78 	    if (ptr->type == word_UpperXref ||
79 		ptr->type == word_LowerXref)
80 		cite_biblio(kl, ptr->text, ptr->fpos);
81 	}
82     }
83 
84     /*
85      * We're now almost done; all that remains is to scan through
86      * the cited bibliography entries and invent default citation
87      * texts for the ones that don't already have explicitly
88      * provided \BR text.
89      */
90     for (para = source; para; para = para->next) {
91 	if (para->type == para_BiblioCited) {
92 	    keyword *kw = kw_lookup(kl, para->keyword);
93 	    assert(kw != NULL);
94 	    if (!kw->text) {
95 		word *wd = smalloc(sizeof(word));
96 		wd->text = gentext(++bibnum);
97 		wd->type = word_Normal;
98 		wd->breaks = FALSE;
99 		wd->alt = NULL;
100 		wd->next = NULL;
101 		wd->aux = 0;
102 		kw->text = wd;
103 	    }
104 	    para->kwtext = kw->text;
105 	}
106     }
107 }
108