2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 // $TOG: autoNumber.C /main/6 1998/04/17 11:47:13 mgreess $
27 #if defined(CSRG_BASED)
28 #define MAXINT INT_MAX
33 #include "HardCopy/autoNumber.h"
34 #include "HardCopy/FPExceptions.h"
36 buffer autoNumber::f_buf(128);
38 autoNumber::autoNumber(const char* nm, enum autoNumberType t, int delta, const char* prefix, const char* postfix) :
39 f_name(strdup(nm)), f_type(t), f_delta(delta),
40 f_prefix(strdup(prefix)), f_postfix(strdup(postfix)),
43 int x = strlen(prefix) + strlen(postfix) + 12;
44 if ( x > f_buf.buf_sz() )
45 f_buf.expand_chunk(x);
48 autoNumber::~autoNumber()
54 while (f_values.entries())
56 while (f_serial_nums.entries())
60 void autoNumber::setNumTagsSeen()
62 if (f_serial_nums.entries() > 0 && f_serial_nums.top() < MAXINT)
63 f_serial_nums.top()++;
69 // reset stack of values
70 while (f_values.entries() > 1) // leave one entry for re-use
72 f_values.top() = f_initialValue;
74 // reset stack of serial numbers
75 while (f_serial_nums.entries() > 1) // leave one entry for re-use
77 f_serial_nums.top() = 0;
83 f_values.push(f_initialValue);
84 f_serial_nums.push(0);
90 if (f_values.entries() > 1)
92 if (f_serial_nums.entries() > 1)
96 unsigned int autoNumber::operator==(const autoNumber&)
101 ostream& operator<<(ostream& out, const autoNumber& an)
103 debug(cerr, an.f_name);
104 debug(cerr, an.f_delta);
105 debug(cerr, an.f_prefix);
106 debug(cerr, an.f_postfix);
107 debug(cerr, an.f_type);
108 debug(cerr, an.f_serial_nums.top());
112 //////////////////////////////////////////////////
114 //////////////////////////////////////////////////
116 autoNumberNumeric::autoNumberNumeric(const char* nm, int delta, int inv,
117 const char* prefix, const char* postfix) :
118 autoNumber(nm, NUMERIC, delta, prefix, postfix)
120 f_initialValue = inv;
122 f_values.push(f_initialValue);
123 f_serial_nums.push(0);
126 autoNumberNumeric::~autoNumberNumeric()
130 void autoNumberNumeric::setNextValue()
132 if (f_serial_nums.entries() && f_values.entries())
134 if (f_serial_nums.top() >= 2)
135 f_values.top() += f_delta;
140 autoNumberNumeric::getValue()
142 char* ptr = f_buf.get_base();
143 int ptrlen = f_buf.buf_sz();
145 if (f_values.entries())
146 snprintf(ptr, ptrlen, "%s",
147 form("%s%d%s", f_prefix, f_values.top(), f_postfix));
154 //////////////////////////////////////////////////
156 //////////////////////////////////////////////////
158 autoNumberCased::autoNumberCased(const char* nm, autoNumberType an_t,
159 int delta, enum CaseType ct, const char* prefix, const char* postfix) :
160 autoNumber(nm, an_t, delta, prefix, postfix), f_case(ct)
164 autoNumberCased::~autoNumberCased()
168 //////////////////////////////////////////////////
170 //////////////////////////////////////////////////
172 char autoNumberAlphabetic::f_lowerCaseLetters[26] =
174 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
175 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
179 char autoNumberAlphabetic::f_upperCaseLetters[26] =
181 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
182 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'T', 'T', 'U', 'V',
186 autoNumberAlphabetic::autoNumberAlphabetic(
190 const char* InitialValue, const char* prefix, const char* postfix
192 autoNumberCased(nm, ALPHABETIC, delta, ct, prefix, postfix)
194 f_initialValue = alphaToInt(InitialValue, f_case);
196 f_values.push(f_initialValue);
197 f_serial_nums.push(0);
200 autoNumberAlphabetic::~autoNumberAlphabetic()
204 static const int base = 26;
206 int autoNumberAlphabetic::alphaToInt(const char* alpha, enum CaseType a_case)
208 int digits = strlen(alpha);
214 for (i=0; i<digits; i++)
215 if ( isupper(alpha[i]) == 0 ) {
217 "Initial alphabetic autonumber value is not capitalized");
218 throw(CASTHCREXCEPT hardCopyRendererException());
223 for (i=0; i<digits; i++)
224 if ( islower(alpha[i]) == 0 ) {
226 "Initial alphabetic autonumber value is not in small case");
227 throw(CASTHCREXCEPT hardCopyRendererException());
234 int expansionFactor = 1;
235 for ( i=digits-1; i>=0; i-- ) {
236 x += (alpha[i] - offset)*expansionFactor;
237 expansionFactor *= base;
240 x += int((pow((double)base, digits)-1) / (base-1)) - 1;
245 // Algorithm: converting integer values to/from alphabetic autonumbers
247 // The alphabetic autonumbers are grouped into blocks where each
248 // block represents autonumbers with same number of digits. The size
249 // of a block of d digts = 26^d. Now assigning a sequece number (an integer)
250 // to each autonumber in blocks. This number in fact is the integer
251 // value (internal) of the autonumber.
253 // block 1: [a, b, c, ..., z]
254 // seq num: [0, 1, 2, 25]
256 // block 2: [aa, ab, ac, ..., zz]
257 // seq num: [26, 27, 28, 701]
259 // In general, the 1st sequence number in a block for d digits:
260 // x = int((pow(26, d)-1) / (26-1)) - 1;
262 // given an integer x, its number of ditigs when converted to an autonumber:
263 // digits = int(log((26-1)*x + 26) / log(26));
266 const char* autoNumberAlphabetic::intToAlpha(int x, enum CaseType a_case)
269 MESSAGE(cerr, "Negaitve alphabetic autonumber value");
270 throw(CASTHCREXCEPT hardCopyRendererException());
273 int digits = int(log((double)(base-1)*x + base) / log((double)base));
276 MESSAGE(cerr, "alphabetic autonumber value too large");
277 throw(CASTHCREXCEPT hardCopyRendererException());
280 //debug(cerr, digits);
281 //debug(cerr, (pow(base, digits)-1) / (25) -1);
283 x -= int((pow((double)base, digits)-1) / (base-1)) - 1;
286 (a_case == UPPER ) ? f_upperCaseLetters : f_lowerCaseLetters;
289 static char buf[51], buf1[51];
295 buf1[i++] = letters[y];
302 for (k=0; k<digits-i; k++ )
315 void autoNumberAlphabetic::setNextValue()
317 if (f_serial_nums.entries() && f_values.entries())
319 if (f_serial_nums.top() >= 2)
320 f_values.top() += f_delta;
324 const char* autoNumberAlphabetic::getValue()
326 char* ptr = f_buf.get_base();
327 int ptrlen = f_buf.buf_sz();
329 if (f_values.entries())
330 snprintf(ptr, ptrlen, "%s", form("%s%s%s", f_prefix,
331 intToAlpha(f_values.top(), f_case), f_postfix));
339 //////////////////////////////////////////////////
341 //////////////////////////////////////////////////
343 char autoNumberRoman::RomanNumberBuf[256];
345 autoNumberRoman::autoNumberRoman(
349 const char* InitialValue, const char* prefix, const char* postfix
351 autoNumberCased(nm, ROMAN, delta, ct, prefix, postfix)
353 f_initialValue = RomanToArabic(InitialValue);
355 f_values.push(f_initialValue);
356 f_serial_nums.push(0);
359 autoNumberRoman::~autoNumberRoman()
363 void autoNumberRoman::setNextValue()
365 if (f_serial_nums.entries() && f_values.entries())
367 if (f_serial_nums.top() >= 2) {
368 f_values.top() += f_delta;
370 if (f_values.top() < 1) {
371 MESSAGE(cerr, "Value too small.");
372 throw(CASTHCREXCEPT hardCopyRendererException());
378 const char* autoNumberRoman::getValue()
382 if (f_values.entries())
383 return ArabicToRoman(f_values.top());
385 ptr = f_buf.get_base();
392 int autoNumberRoman::getDigit(const char*& p)
398 if ( p[1] != 0 && p[1] == 'V' ) {
410 if ( p[1] != 0 && p[1] == 'I' ) {
418 if ( p[1] != 0 && p[1] == 'X' ) {
426 if ( p[1] != 0 && p[1] == 'X' ) {
434 if ( p[1] != 0 && p[1] == 'C' ) {
442 if ( p[1] != 0 && p[1] == 'C' ) {
449 MESSAGE(cerr, "unknown roman numeral letter");
450 throw(CASTHCREXCEPT hardCopyRendererException());
456 int autoNumberRoman::RomanToArabic(const char* romanString)
459 const char* bound = romanString + strlen(romanString);
460 const char* p = (char*)romanString;
462 while ( p != bound ) {
468 const char* romanCardinals[4][9] =
470 { "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" },
471 { "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC" },
472 { "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM" },
473 { "M", "MM", "MMM", "MV", "V", "VM", "VMM", "VMMM", "MX" }
477 autoNumberRoman::ArabicToRoman(int x)
479 unsigned int len, slen;
481 RomanNumberBuf[0] = 0;
483 MESSAGE(cerr, "Value too large.");
484 throw(CASTHCREXCEPT hardCopyRendererException());
487 char* buf = form("%d", x);
490 for ( unsigned int i=0; i<strlen(buf); i++ ) {
493 const char* romanCardinal = romanCardinals[j][buf[i]-'1'];
494 char precise_romanCardinal[8];
497 if (f_case == UPPER) {
498 for (k=0; romanCardinal[k]; k++)
499 precise_romanCardinal[k] = romanCardinal[k];
500 precise_romanCardinal[k] = 0;
503 for (k=0; romanCardinal[k]; k++)
504 precise_romanCardinal[k] = tolower(romanCardinal[k]);
505 precise_romanCardinal[k] = 0;
508 slen = strlen(RomanNumberBuf);
509 len = MIN(strlen(precise_romanCardinal), 256 - 1 - slen);
510 *((char *) memcpy(RomanNumberBuf + slen,
511 precise_romanCardinal, len) + len) = '\0';
516 return RomanNumberBuf;
520 ////////////////////////////////////////////////////
522 ////////////////////////////////////////////////////
524 autoNumberListT::operator==(const autoNumberListT&)