2 * contents.c: build a table of contents
11 struct numberstate_Tag
{
16 paragraph
**currentsects
;
21 wchar_t *chaptertext
; /* the word for a chapter */
22 wchar_t *sectiontext
; /* the word for a section */
23 wchar_t *apptext
; /* the word for an appendix */
26 numberstate
*number_init(void) {
27 numberstate
*ret
= mknew(numberstate
);
29 ret
->appendixnum
= -1;
31 ret
->oklevel
= -1; /* not even in a chapter yet */
32 ret
->maxsectlevel
= 32;
33 ret
->sectionlevels
= mknewa(int, ret
->maxsectlevel
);
34 ret
->currentsects
= mknewa(paragraph
*, ret
->maxsectlevel
+1);
35 memset(ret
->currentsects
, 0, (ret
->maxsectlevel
+1)*sizeof(paragraph
*));
41 void number_free(numberstate
*state
) {
42 sfree(state
->sectionlevels
);
43 sfree(state
->currentsects
);
47 static void dotext(word
***wret
, wchar_t *text
) {
48 word
*mnewword
= mknew(word
);
49 mnewword
->text
= ustrdup(text
);
50 mnewword
->type
= word_Normal
;
52 mnewword
->next
= NULL
;
54 *wret
= &mnewword
->next
;
57 static void dospace(word
***wret
) {
58 word
*mnewword
= mknew(word
);
59 mnewword
->text
= NULL
;
60 mnewword
->type
= word_WhiteSpace
;
62 mnewword
->next
= NULL
;
64 *wret
= &mnewword
->next
;
67 static void donumber(word
***wret
, int num
) {
69 wchar_t *p
= text
+ sizeof(text
);
73 *--p
= L
"0123456789"[num
% 10];
79 static void doanumber(word
***wret
, int num
) {
88 if (aton
< INT_MAX
/26)
89 aton
= (aton
+1) * 26 - 1;
93 p
= text
+ sizeof(text
);
97 *--p
= L
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"[num
% 26];
103 void number_cfg(numberstate
*state
, paragraph
*source
) {
107 state
->chaptertext
= L
"Chapter";
108 state
->sectiontext
= L
"Section";
109 state
->apptext
= L
"Appendix";
111 for (; source
; source
= source
->next
) {
112 if (source
->type
== para_Config
) {
113 if (!ustricmp(source
->keyword
, L
"chapter")) {
114 state
->chaptertext
= uadv(source
->keyword
);
115 } else if (!ustricmp(source
->keyword
, L
"section")) {
116 state
->sectiontext
= uadv(source
->keyword
);
117 } else if (!ustricmp(source
->keyword
, L
"appendix")) {
118 state
->apptext
= uadv(source
->keyword
);
124 word
*number_mktext(numberstate
*state
, paragraph
*p
, wchar_t *category
,
125 int prev
, int *errflag
) {
131 level
= -2; /* default for non-section-heading */
135 for (i
= 0; i
< state
->maxsectlevel
; i
++)
136 state
->sectionlevels
[i
] = 0;
137 dotext(&pret
, category ? category
: state
->chaptertext
);
140 donumber(&pret
, state
->chapternum
);
141 state
->ischapter
= 1;
147 level
= (p
->type
== para_Heading ?
0 : p
->aux
);
148 if (level
> state
->oklevel
) {
149 error(err_sectjump
, &p
->fpos
);
154 state
->oklevel
= level
+1;
155 if (state
->maxsectlevel
<= level
) {
156 state
->maxsectlevel
= level
+ 32;
157 state
->sectionlevels
= resize(state
->sectionlevels
,
158 state
->maxsectlevel
);
160 state
->sectionlevels
[level
]++;
161 for (i
= level
+1; i
< state
->maxsectlevel
; i
++)
162 state
->sectionlevels
[i
] = 0;
163 dotext(&pret
, category ? category
: state
->sectiontext
);
166 if (state
->ischapter
)
167 donumber(&pret
, state
->chapternum
);
169 doanumber(&pret
, state
->appendixnum
);
170 for (i
= 0; i
<= level
; i
++) {
172 if (state
->sectionlevels
[i
] == 0)
173 state
->sectionlevels
[i
] = 1;
174 donumber(&pret
, state
->sectionlevels
[i
]);
178 state
->appendixnum
++;
179 for (i
= 0; i
< state
->maxsectlevel
; i
++)
180 state
->sectionlevels
[i
] = 0;
181 dotext(&pret
, category ? category
: state
->apptext
);
184 doanumber(&pret
, state
->appendixnum
);
185 state
->ischapter
= 0;
189 case para_UnnumberedChapter
:
192 case para_NumberedList
:
194 if (prev
!= para_NumberedList
)
197 donumber(&pret
, state
->listitem
);
202 * Now set up parent, child and sibling links.
204 p
->parent
= p
->child
= p
->sibling
= NULL
;
206 if (state
->currentsects
[level
+1])
207 state
->currentsects
[level
+1]->sibling
= p
;
208 if (level
>= 0 && state
->currentsects
[level
]) {
209 p
->parent
= state
->currentsects
[level
];
210 if (!state
->currentsects
[level
]->child
)
211 state
->currentsects
[level
]->child
= p
;
213 state
->currentsects
[level
+1] = state
->lastsect
= p
;
214 for (i
= level
+2; i
< state
->maxsectlevel
+1; i
++)
215 state
->currentsects
[i
] = NULL
;
217 p
->parent
= state
->lastsect
;