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; |
36 | keywordlist *kl = mknew(keywordlist); |
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 | |
71 | kw = mknew(keyword); |
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; |
85 | kl->looseends = resize(kl->looseends, kl->looseendssize); |
86 | } |
87 | kl->looseends[kl->nlooseends++] = source->kwtext; |
88 | } |
89 | } |
90 | |
91 | number_free(n); |
92 | |
93 | if (errors) { |
94 | free_keywords(kl); |
95 | return NULL; |
96 | } |
97 | |
98 | return kl; |
99 | } |
100 | |
101 | void free_keywords(keywordlist *kl) { |
102 | keyword *kw; |
103 | while (kl->nlooseends) |
104 | free_word_list(kl->looseends[--kl->nlooseends]); |
105 | sfree(kl->looseends); |
106 | while ( (kw = index234(kl->keys, 0)) != NULL) { |
107 | delpos234(kl->keys, 0); |
108 | free_word_list(kw->text); |
109 | sfree(kw); |
110 | } |
111 | freetree234(kl->keys); |
112 | sfree(kl); |
113 | } |
114 | |
115 | void subst_keywords(paragraph *source, keywordlist *kl) { |
116 | for (; source; source = source->next) { |
117 | word *ptr; |
118 | for (ptr = source->words; ptr; ptr = ptr->next) { |
119 | if (ptr->type == word_UpperXref || |
120 | ptr->type == word_LowerXref) { |
121 | keyword *kw; |
122 | word **endptr, *close, *subst; |
123 | |
124 | kw = kw_lookup(kl, ptr->text); |
125 | if (!kw) { |
126 | error(err_nosuchkw, &ptr->fpos, ptr->text); |
127 | subst = NULL; |
128 | } else |
129 | subst = dup_word_list(kw->text); |
130 | |
131 | if (subst && ptr->type == word_LowerXref && |
132 | kw->para->type != para_Biblio && |
133 | kw->para->type != para_BiblioCited) |
134 | ustrlow(subst->text); |
135 | |
136 | close = mknew(word); |
137 | close->text = NULL; |
138 | close->alt = NULL; |
139 | close->type = word_XrefEnd; |
140 | close->fpos = ptr->fpos; |
141 | |
142 | close->next = ptr->next; |
143 | ptr->next = subst; |
144 | |
145 | for (endptr = &ptr->next; *endptr; endptr = &(*endptr)->next) |
146 | (*endptr)->fpos = ptr->fpos; |
147 | |
148 | *endptr = close; |
149 | ptr = close; |
150 | } |
151 | } |
152 | } |
153 | } |