Add an error check for correct formatting in Deflate uncompressed
[sgt/halibut] / contents.c
CommitLineData
d7482997 1/*
2 * contents.c: build a table of contents
3 */
4
5#include <stdio.h>
6#include <stdlib.h>
7#include <assert.h>
8#include <limits.h>
9#include "halibut.h"
10
11struct numberstate_Tag {
12 int chapternum;
13 int appendixnum;
14 int ischapter;
15 int *sectionlevels;
16 paragraph **currentsects;
17 paragraph *lastsect;
18 int oklevel;
19 int maxsectlevel;
20 int listitem;
96f3af16 21 stack listitem_stack;
d7482997 22 wchar_t *chaptertext; /* the word for a chapter */
23 wchar_t *sectiontext; /* the word for a section */
24 wchar_t *apptext; /* the word for an appendix */
25};
26
27numberstate *number_init(void) {
f1530049 28 numberstate *ret = snew(numberstate);
d7482997 29 ret->chapternum = 0;
30 ret->appendixnum = -1;
31 ret->ischapter = 1;
32 ret->oklevel = -1; /* not even in a chapter yet */
33 ret->maxsectlevel = 32;
f1530049 34 ret->sectionlevels = snewn(ret->maxsectlevel, int);
35 ret->currentsects = snewn(ret->maxsectlevel+1, paragraph *);
d7482997 36 memset(ret->currentsects, 0, (ret->maxsectlevel+1)*sizeof(paragraph *));
37 ret->lastsect = NULL;
38 ret->listitem = -1;
96f3af16 39 ret->listitem_stack = stk_new();
d7482997 40 return ret;
41}
42
43void number_free(numberstate *state) {
96f3af16 44 stk_free(state->listitem_stack);
d7482997 45 sfree(state->sectionlevels);
46 sfree(state->currentsects);
47 sfree(state);
48}
49
50static void dotext(word ***wret, wchar_t *text) {
f1530049 51 word *mnewword = snew(word);
d7482997 52 mnewword->text = ustrdup(text);
53 mnewword->type = word_Normal;
54 mnewword->alt = NULL;
55 mnewword->next = NULL;
56 **wret = mnewword;
57 *wret = &mnewword->next;
58}
59
60static void dospace(word ***wret) {
f1530049 61 word *mnewword = snew(word);
d7482997 62 mnewword->text = NULL;
63 mnewword->type = word_WhiteSpace;
64 mnewword->alt = NULL;
65 mnewword->next = NULL;
66 **wret = mnewword;
67 *wret = &mnewword->next;
68}
69
70static void donumber(word ***wret, int num) {
71 wchar_t text[20];
8798374d 72 wchar_t *p = text + lenof(text);
d7482997 73 *--p = L'\0';
74 while (num != 0) {
75 assert(p > text);
76 *--p = L"0123456789"[num % 10];
77 num /= 10;
78 }
79 dotext(wret, p);
80}
81
82static void doanumber(word ***wret, int num) {
83 wchar_t text[20];
84 wchar_t *p;
85 int nletters, aton;
86 nletters = 1;
87 aton = 25;
88 while (num > aton) {
89 nletters++;
90 num -= aton+1;
91 if (aton < INT_MAX/26)
92 aton = (aton+1) * 26 - 1;
93 else
94 aton = INT_MAX;
95 }
8798374d 96 p = text + lenof(text);
d7482997 97 *--p = L'\0';
98 while (nletters--) {
99 assert(p > text);
100 *--p = L"ABCDEFGHIJKLMNOPQRSTUVWXYZ"[num % 26];
101 num /= 26;
102 }
103 dotext(wret, p);
104}
105
106void number_cfg(numberstate *state, paragraph *source) {
107 /*
108 * Defaults
109 */
110 state->chaptertext = L"Chapter";
111 state->sectiontext = L"Section";
112 state->apptext = L"Appendix";
113
114 for (; source; source = source->next) {
115 if (source->type == para_Config) {
116 if (!ustricmp(source->keyword, L"chapter")) {
117 state->chaptertext = uadv(source->keyword);
118 } else if (!ustricmp(source->keyword, L"section")) {
119 state->sectiontext = uadv(source->keyword);
120 } else if (!ustricmp(source->keyword, L"appendix")) {
121 state->apptext = uadv(source->keyword);
122 }
123 }
124 }
125}
126
127word *number_mktext(numberstate *state, paragraph *p, wchar_t *category,
96f3af16 128 int *prev, int *errflag) {
d7482997 129 word *ret = NULL;
130 word **ret2 = &ret;
131 word **pret = &ret;
96f3af16 132 int i, level, thistype;
133 struct listitem_stack_entry {
134 int listitem;
135 int prev;
136 } *lse;
d7482997 137
138 level = -2; /* default for non-section-heading */
96f3af16 139 thistype = p->type;
d7482997 140 switch (p->type) {
141 case para_Chapter:
142 state->chapternum++;
143 for (i = 0; i < state->maxsectlevel; i++)
144 state->sectionlevels[i] = 0;
145 dotext(&pret, category ? category : state->chaptertext);
146 dospace(&pret);
147 ret2 = pret;
148 donumber(&pret, state->chapternum);
149 state->ischapter = 1;
150 state->oklevel = 0;
151 level = -1;
152 break;
153 case para_Heading:
154 case para_Subsect:
155 level = (p->type == para_Heading ? 0 : p->aux);
156 if (level > state->oklevel) {
157 error(err_sectjump, &p->fpos);
158 *errflag = TRUE;
159 ret = NULL;
160 break;
161 }
162 state->oklevel = level+1;
163 if (state->maxsectlevel <= level) {
164 state->maxsectlevel = level + 32;
f1530049 165 state->sectionlevels = sresize(state->sectionlevels,
166 state->maxsectlevel, int);
d7482997 167 }
168 state->sectionlevels[level]++;
169 for (i = level+1; i < state->maxsectlevel; i++)
170 state->sectionlevels[i] = 0;
171 dotext(&pret, category ? category : state->sectiontext);
172 dospace(&pret);
173 ret2 = pret;
174 if (state->ischapter)
175 donumber(&pret, state->chapternum);
176 else
177 doanumber(&pret, state->appendixnum);
178 for (i = 0; i <= level; i++) {
179 dotext(&pret, L".");
180 if (state->sectionlevels[i] == 0)
181 state->sectionlevels[i] = 1;
182 donumber(&pret, state->sectionlevels[i]);
183 }
184 break;
185 case para_Appendix:
186 state->appendixnum++;
187 for (i = 0; i < state->maxsectlevel; i++)
188 state->sectionlevels[i] = 0;
189 dotext(&pret, category ? category : state->apptext);
190 dospace(&pret);
191 ret2 = pret;
192 doanumber(&pret, state->appendixnum);
193 state->ischapter = 0;
194 state->oklevel = 0;
195 level = -1;
196 break;
197 case para_UnnumberedChapter:
198 level = -1;
199 break;
200 case para_NumberedList:
201 ret2 = pret;
96f3af16 202 if (*prev != para_NumberedList)
d7482997 203 state->listitem = 0;
204 state->listitem++;
205 donumber(&pret, state->listitem);
206 break;
96f3af16 207 case para_LcontPush:
f1530049 208 lse = snew(struct listitem_stack_entry);
96f3af16 209 lse->listitem = state->listitem;
210 lse->prev = *prev;
211 stk_push(state->listitem_stack, lse);
212 state->listitem = 0;
213 break;
214 case para_LcontPop:
215 lse = (struct listitem_stack_entry *)stk_pop(state->listitem_stack);
216 state->listitem = lse->listitem;
217 thistype = lse->prev;
218 sfree(lse);
219 break;
d7482997 220 }
221
222 /*
223 * Now set up parent, child and sibling links.
224 */
225 p->parent = p->child = p->sibling = NULL;
226 if (level != -2) {
227 if (state->currentsects[level+1])
228 state->currentsects[level+1]->sibling = p;
229 if (level >= 0 && state->currentsects[level]) {
230 p->parent = state->currentsects[level];
231 if (!state->currentsects[level]->child)
232 state->currentsects[level]->child = p;
233 }
234 state->currentsects[level+1] = state->lastsect = p;
235 for (i = level+2; i < state->maxsectlevel+1; i++)
236 state->currentsects[i] = NULL;
237 } else {
238 p->parent = state->lastsect;
239 }
240
241 p->kwtext2 = *ret2;
96f3af16 242 *prev = thistype;
d7482997 243 return ret;
244}