3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
7 * \author Martin Vermeer
9 * \author Richard Heck (roman numerals)
11 * Full author contact details are available in file CREDITS.
19 #include "support/lstrings.h"
20 #include "support/convert.h"
22 #include <boost/assert.hpp>
27 using std::ostringstream
;
32 using support::lowercase
;
40 Counter::Counter(docstring
const & mc
, docstring
const & ls
,
41 docstring
const & lsa
)
42 : master_(mc
), labelstring_(ls
), labelstringappendix_(lsa
)
48 void Counter::set(int v
)
54 void Counter::addto(int v
)
60 int Counter::value() const
78 docstring
const & Counter::master() const
84 docstring
const & Counter::labelString() const
90 docstring
const & Counter::labelStringAppendix() const
92 return labelstringappendix_
;
96 void Counters::newCounter(docstring
const & newc
,
97 docstring
const & masterc
,
99 docstring
const & lsa
)
101 if (!masterc
.empty() && !hasCounter(masterc
)) {
102 lyxerr
<< "Master counter does not exist: "
107 counterList
[newc
] = Counter(masterc
, ls
, lsa
);
111 bool Counters::hasCounter(docstring
const & c
) const
113 return counterList
.find(c
) != counterList
.end();
117 void Counters::set(docstring
const & ctr
, int const val
)
119 CounterList::iterator
const it
= counterList
.find(ctr
);
120 if (it
== counterList
.end()) {
121 lyxerr
<< "set: Counter does not exist: "
122 << to_utf8(ctr
) << endl
;
129 void Counters::addto(docstring
const & ctr
, int const val
)
131 CounterList::iterator
const it
= counterList
.find(ctr
);
132 if (it
== counterList
.end()) {
133 lyxerr
<< "addto: Counter does not exist: "
134 << to_utf8(ctr
) << endl
;
137 it
->second
.addto(val
);
141 int Counters::value(docstring
const & ctr
) const
143 CounterList::const_iterator
const cit
= counterList
.find(ctr
);
144 if (cit
== counterList
.end()) {
145 lyxerr
<< "value: Counter does not exist: "
146 << to_utf8(ctr
) << endl
;
149 return cit
->second
.value();
153 void Counters::step(docstring
const & ctr
)
155 CounterList::iterator it
= counterList
.find(ctr
);
156 if (it
== counterList
.end()) {
157 lyxerr
<< "step: Counter does not exist: "
158 << to_utf8(ctr
) << endl
;
163 it
= counterList
.begin();
164 CounterList::iterator
const end
= counterList
.end();
165 for (; it
!= end
; ++it
) {
166 if (it
->second
.master() == ctr
) {
173 void Counters::reset()
176 current_float_
.erase();
177 CounterList::iterator it
= counterList
.begin();
178 CounterList::iterator
const end
= counterList
.end();
179 for (; it
!= end
; ++it
) {
185 void Counters::reset(docstring
const & match
)
187 BOOST_ASSERT(!match
.empty());
189 CounterList::iterator it
= counterList
.begin();
190 CounterList::iterator end
= counterList
.end();
191 for (; it
!= end
; ++it
) {
192 if (it
->first
.find(match
) != string::npos
)
198 void Counters::copy(Counters
& from
, Counters
& to
, docstring
const & match
)
200 CounterList::iterator it
= counterList
.begin();
201 CounterList::iterator end
= counterList
.end();
202 for (; it
!= end
; ++it
) {
203 if (it
->first
.find(match
) != string::npos
|| match
== "") {
204 to
.set(it
->first
, from
.value(it
->first
));
212 char loweralphaCounter(int const n
)
220 char alphaCounter(int const n
)
228 char hebrewCounter(int const n
)
230 static const char hebrew
[22] = {
231 '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7', '\xe8',
232 '\xe9', '\xeb', '\xec', '\xee', '\xf0', '\xf1', '\xf2', '\xf4', '\xf6',
233 '\xf7', '\xf8', '\xf9', '\xfa'
238 return hebrew
[n
- 1];
243 //On the special cases, see http://mathworld.wolfram.com/RomanNumerals.html
244 //and for a list of roman numerals up to and including 3999, see
245 //http://www.research.att.com/~njas/sequences/a006968.txt. (Thanks to Joost
247 docstring
const romanCounter(int const n
)
249 static char const * const ones
[9] = {
250 "I", "II", "III", "IV", "V",
251 "VI", "VII", "VIII", "IX"
254 static char const * const tens
[9] = {
255 "X", "XX", "XXX", "XL", "L",
256 "LX", "LXX", "LXXX", "XC"
259 static char const * const hunds
[9] = {
260 "C", "CC", "CCC", "CD", "D",
261 "DC", "DCC", "DCCC", "CM"
264 if (n
> 1000 || n
< 1)
265 return from_ascii("??");
279 int hundreds
= val
/ 100;
280 roman
= hunds
[hundreds
- 1];
287 roman
= roman
+ "XC";
291 int tensnum
= val
/ 10;
292 roman
= roman
+ tens
[tensnum
- 1];
297 roman
= roman
+ ones
[val
-1];
299 return from_ascii(roman
);
303 docstring
const lowerromanCounter(int const n
)
305 return support::lowercase(romanCounter(n
));
311 docstring
Counters::labelItem(docstring
const & ctr
,
312 docstring
const & numbertype
)
314 CounterList::const_iterator
const cit
= counterList
.find(ctr
);
315 if (cit
== counterList
.end()) {
318 << " does not exist." << endl
;
322 int val
= cit
->second
.value();
324 if (numbertype
== "hebrew")
325 return docstring(1, hebrewCounter(val
));
327 if (numbertype
== "alph")
328 return docstring(1, loweralphaCounter(val
));
330 if (numbertype
== "Alph")
331 return docstring(1, alphaCounter(val
));
333 if (numbertype
== "roman")
334 return lowerromanCounter(val
);
336 if (numbertype
== "Roman")
337 return romanCounter(val
);
339 return convert
<docstring
>(val
);
343 docstring
Counters::theCounter(docstring
const & counter
)
345 if (!hasCounter(counter
))
346 return from_ascii("??");
348 Counter
const & c
= counterList
[counter
];
349 docstring ls
= appendix() ? c
.labelStringAppendix() : c
.labelString();
352 if (!c
.master().empty())
353 ls
= from_ascii("\\the") + c
.master() + from_ascii(".");
354 ls
+= from_ascii("\\arabic{") + counter
+ "}";
356 return counterLabel(ls
);
360 docstring
Counters::counterLabel(docstring
const & format
)
362 docstring label
= format
;
364 // FIXME: Using regexps would be better, but we compile boost without
365 // wide regexps currently.
368 //lyxerr << "label=" << to_utf8(label) << endl;
369 size_t const i
= label
.find(from_ascii("\\the"), 0);
370 if (i
== docstring::npos
)
374 while (k
< label
.size() && lowercase(label
[k
]) >= 'a'
375 && lowercase(label
[k
]) <= 'z')
377 docstring counter
= label
.substr(j
, k
- j
);
378 docstring repl
= theCounter(counter
);
379 label
.replace(i
, k
- j
+ 4, repl
);
383 //lyxerr << "label=" << to_utf8(label) << endl;
385 size_t const i
= label
.find('\\', 0);
386 if (i
== docstring::npos
)
388 size_t const j
= label
.find('{', i
+ 1);
389 if (j
== docstring::npos
)
391 size_t const k
= label
.find('}', j
+ 1);
392 if (k
== docstring::npos
)
394 docstring
const numbertype(label
, i
+ 1, j
- i
- 1);
395 docstring
const counter(label
, j
+ 1, k
- j
- 1);
396 docstring
const rep
= labelItem(counter
, numbertype
);
397 label
= docstring(label
, 0, i
) + rep
398 + docstring(label
, k
+ 1, docstring::npos
);
400 //lyxerr << "DONE! label=" << to_utf8(label) << endl;