d7482997 |
1 | /* |
2 | * keywords.c: keep track of all cross-reference keywords |
3 | */ |
4 | |
5 | #include <stdio.h> |
6 | #include <stdlib.h> |
7 | #include <assert.h> |
8 | #include "halibut.h" |
9 | |
10 | static int kwcmp(void *av, void *bv) |
11 | { |
12 | const keyword *a = (const keyword *)av; |
13 | const keyword *b = (const keyword *)bv; |
14 | return ustrcmp(a->key, b->key); |
15 | } |
16 | |
17 | static int kwfind(void *av, void *bv) |
18 | { |
19 | wchar_t *a = (wchar_t *)av; |
20 | const keyword *b = (const keyword *)bv; |
21 | return ustrcmp(a, b->key); |
22 | } |
23 | |
24 | keyword *kw_lookup(keywordlist *kl, wchar_t *str) { |
25 | return find234(kl->keys, str, kwfind); |
26 | } |
27 | |
28 | /* |
29 | * This function reads through source form and collects the |
30 | * keywords. They get collected in a heap, sorted by Unicode |
31 | * collation, last at the top (so that we can Heapsort them when we |
32 | * finish). |
33 | */ |
34 | keywordlist *get_keywords(paragraph *source) { |
35 | int errors = FALSE; |
f1530049 |
36 | keywordlist *kl = snew(keywordlist); |
d7482997 |
37 | numberstate *n = number_init(); |
38 | int prevpara = para_NotParaType; |
39 | |
40 | number_cfg(n, source); |
41 | |
42 | kl->size = 0; |
43 | kl->keys = newtree234(kwcmp); |
44 | kl->nlooseends = kl->looseendssize = 0; |
45 | kl->looseends = NULL; |
46 | for (; source; source = source->next) { |
47 | wchar_t *p, *q; |
48 | p = q = source->keyword; |
49 | |
50 | /* |
51 | * Look for the section type override (`example', |
52 | * `question' or whatever - to replace `chapter' or |
53 | * `section' on a per-section basis). |
54 | */ |
55 | if (q) { |
56 | q = uadv(q); /* point q at the word beyond */ |
57 | if (!*q) q = NULL; |
58 | } |
59 | |
60 | /* |
61 | * Number the chapter / section / list-item / whatever. |
62 | * This also sets up the `parent', `child' and `sibling' |
63 | * links. |
64 | */ |
96f3af16 |
65 | source->kwtext = number_mktext(n, source, q, &prevpara, &errors); |
d7482997 |
66 | |
67 | if (p && *p) { |
68 | if (source->kwtext || source->type == para_Biblio) { |
69 | keyword *kw, *ret; |
70 | |
f1530049 |
71 | kw = snew(keyword); |
d7482997 |
72 | kw->key = p; |
73 | kw->text = source->kwtext; |
74 | kw->para = source; |
75 | ret = add234(kl->keys, kw); |
76 | if (ret != kw) { |
77 | error(err_multikw, &source->fpos, &ret->para->fpos, p); |
78 | sfree(kw); |
79 | /* FIXME: what happens to kw->text? Does it leak? */ |
80 | } |
81 | } |
82 | } else { |
83 | if (kl->nlooseends >= kl->looseendssize) { |
84 | kl->looseendssize = kl->nlooseends + 32; |
f1530049 |
85 | kl->looseends = sresize(kl->looseends, kl->looseendssize, |
86 | word *); |
d7482997 |
87 | } |
88 | kl->looseends[kl->nlooseends++] = source->kwtext; |
89 | } |
90 | } |
91 | |
92 | number_free(n); |
93 | |
94 | if (errors) { |
95 | free_keywords(kl); |
96 | return NULL; |
97 | } |
98 | |
99 | return kl; |
100 | } |
101 | |
102 | void free_keywords(keywordlist *kl) { |
103 | keyword *kw; |
104 | while (kl->nlooseends) |
105 | free_word_list(kl->looseends[--kl->nlooseends]); |
106 | sfree(kl->looseends); |
107 | while ( (kw = index234(kl->keys, 0)) != NULL) { |
108 | delpos234(kl->keys, 0); |
109 | free_word_list(kw->text); |
110 | sfree(kw); |
111 | } |
112 | freetree234(kl->keys); |
113 | sfree(kl); |
114 | } |
115 | |
116 | void subst_keywords(paragraph *source, keywordlist *kl) { |
117 | for (; source; source = source->next) { |
118 | word *ptr; |
119 | for (ptr = source->words; ptr; ptr = ptr->next) { |
120 | if (ptr->type == word_UpperXref || |
121 | ptr->type == word_LowerXref) { |
122 | keyword *kw; |
123 | word **endptr, *close, *subst; |
124 | |
125 | kw = kw_lookup(kl, ptr->text); |
126 | if (!kw) { |
127 | error(err_nosuchkw, &ptr->fpos, ptr->text); |
128 | subst = NULL; |
129 | } else |
130 | subst = dup_word_list(kw->text); |
131 | |
132 | if (subst && ptr->type == word_LowerXref && |
133 | kw->para->type != para_Biblio && |
134 | kw->para->type != para_BiblioCited) |
135 | ustrlow(subst->text); |
136 | |
f1530049 |
137 | close = snew(word); |
d7482997 |
138 | close->text = NULL; |
139 | close->alt = NULL; |
140 | close->type = word_XrefEnd; |
141 | close->fpos = ptr->fpos; |
142 | |
143 | close->next = ptr->next; |
144 | ptr->next = subst; |
145 | |
146 | for (endptr = &ptr->next; *endptr; endptr = &(*endptr)->next) |
147 | (*endptr)->fpos = ptr->fpos; |
148 | |
149 | *endptr = close; |
150 | ptr = close; |
151 | } |
152 | } |
153 | } |
154 | } |