2 * contents.c: build a table of contents
11 struct numberstate_Tag
{
16 paragraph
**currentsects
;
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 */
27 numberstate
*number_init(void) {
28 numberstate
*ret
= snew(numberstate
);
30 ret
->appendixnum
= -1;
32 ret
->oklevel
= -1; /* not even in a chapter yet */
33 ret
->maxsectlevel
= 32;
34 ret
->sectionlevels
= snewn(ret
->maxsectlevel
, int);
35 ret
->currentsects
= snewn(ret
->maxsectlevel
+1, paragraph
*);
36 memset(ret
->currentsects
, 0, (ret
->maxsectlevel
+1)*sizeof(paragraph
*));
39 ret
->listitem_stack
= stk_new();
43 void number_free(numberstate
*state
) {
44 stk_free(state
->listitem_stack
);
45 sfree(state
->sectionlevels
);
46 sfree(state
->currentsects
);
50 static void dotext(word
***wret
, wchar_t *text
) {
51 word
*mnewword
= snew(word
);
52 mnewword
->text
= ustrdup(text
);
53 mnewword
->type
= word_Normal
;
55 mnewword
->next
= NULL
;
57 *wret
= &mnewword
->next
;
60 static void dospace(word
***wret
) {
61 word
*mnewword
= snew(word
);
62 mnewword
->text
= NULL
;
63 mnewword
->type
= word_WhiteSpace
;
65 mnewword
->next
= NULL
;
67 *wret
= &mnewword
->next
;
70 static void donumber(word
***wret
, int num
) {
72 wchar_t *p
= text
+ sizeof(text
);
76 *--p
= L
"0123456789"[num
% 10];
82 static void doanumber(word
***wret
, int num
) {
91 if (aton
< INT_MAX
/26)
92 aton
= (aton
+1) * 26 - 1;
96 p
= text
+ sizeof(text
);
100 *--p
= L
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"[num
% 26];
106 void number_cfg(numberstate
*state
, paragraph
*source
) {
110 state
->chaptertext
= L
"Chapter";
111 state
->sectiontext
= L
"Section";
112 state
->apptext
= L
"Appendix";
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
);
127 word
*number_mktext(numberstate
*state
, paragraph
*p
, wchar_t *category
,
128 int *prev
, int *errflag
) {
132 int i
, level
, thistype
;
133 struct listitem_stack_entry
{
138 level
= -2; /* default for non-section-heading */
143 for (i
= 0; i
< state
->maxsectlevel
; i
++)
144 state
->sectionlevels
[i
] = 0;
145 dotext(&pret
, category ? category
: state
->chaptertext
);
148 donumber(&pret
, state
->chapternum
);
149 state
->ischapter
= 1;
155 level
= (p
->type
== para_Heading ?
0 : p
->aux
);
156 if (level
> state
->oklevel
) {
157 error(err_sectjump
, &p
->fpos
);
162 state
->oklevel
= level
+1;
163 if (state
->maxsectlevel
<= level
) {
164 state
->maxsectlevel
= level
+ 32;
165 state
->sectionlevels
= sresize(state
->sectionlevels
,
166 state
->maxsectlevel
, int);
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
);
174 if (state
->ischapter
)
175 donumber(&pret
, state
->chapternum
);
177 doanumber(&pret
, state
->appendixnum
);
178 for (i
= 0; i
<= level
; i
++) {
180 if (state
->sectionlevels
[i
] == 0)
181 state
->sectionlevels
[i
] = 1;
182 donumber(&pret
, state
->sectionlevels
[i
]);
186 state
->appendixnum
++;
187 for (i
= 0; i
< state
->maxsectlevel
; i
++)
188 state
->sectionlevels
[i
] = 0;
189 dotext(&pret
, category ? category
: state
->apptext
);
192 doanumber(&pret
, state
->appendixnum
);
193 state
->ischapter
= 0;
197 case para_UnnumberedChapter
:
200 case para_NumberedList
:
202 if (*prev
!= para_NumberedList
)
205 donumber(&pret
, state
->listitem
);
208 lse
= snew(struct listitem_stack_entry
);
209 lse
->listitem
= state
->listitem
;
211 stk_push(state
->listitem_stack
, lse
);
215 lse
= (struct listitem_stack_entry
*)stk_pop(state
->listitem_stack
);
216 state
->listitem
= lse
->listitem
;
217 thistype
= lse
->prev
;
223 * Now set up parent, child and sibling links.
225 p
->parent
= p
->child
= p
->sibling
= NULL
;
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
;
234 state
->currentsects
[level
+1] = state
->lastsect
= p
;
235 for (i
= level
+2; i
< state
->maxsectlevel
+1; i
++)
236 state
->currentsects
[i
] = NULL
;
238 p
->parent
= state
->lastsect
;