| 1 | /* |
| 2 | * biblio.c: process the bibliography |
| 3 | */ |
| 4 | |
| 5 | #include <assert.h> |
| 6 | #include "halibut.h" |
| 7 | |
| 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 | |
| 23 | static void cite_biblio(keywordlist *kl, wchar_t *key, filepos fpos) { |
| 24 | keyword *kw = kw_lookup(kl, key); |
| 25 | if (!kw) |
| 26 | error(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 | |
| 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 | error(err_nosuchkw, ¶->fpos, para->keyword); |
| 61 | } else if (kw->text) { |
| 62 | error(err_multiBR, ¶->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->alt = NULL; |
| 99 | wd->next = NULL; |
| 100 | kw->text = wd; |
| 101 | } |
| 102 | para->kwtext = kw->text; |
| 103 | } |
| 104 | } |
| 105 | } |