Back
1 //------------------------------------------------------------------------------
2 // Module WordList.cpp //
3 // //
4 // Simple class which encapsulates a (keyword-)word list //
5 // //
6 // Copyright (c) 2000-2004 by Lars Haendel //
7 // Home: http://www.newty.de //
8 // //
9 // This program is free software and can be used under the terms of the //
10 // GNU licence. See header-file for further information and disclaimer. //
11 // //
12 //------------------------------------------------------------------------------
13
14
15 #include <stdlib> // due to: bsearch() etc.
16 #include <limits> // INT_MAX
17 #include <iomanip> // setw()
18
19 #include "WordList.h"
20 #include "ErrText.h" // TErrText
21 #include "FileUtil.h" // SearchKey() ...
22 #include "NameUtil.h" // filename utilities
23
24
25 #define RIGHT_MARGIN 16000 // note: feature deactivated
26
27 //-------------------------------------------------------------------------------------
28 // case sensitive comparision function for qsort()
29 int CmpFunc1(const void* _a, const void* _b)
30 {
31 // explicit typecast
32 const char** a = (const char**) _a;
33 const char** b = (const char**) _b;
34
35 // compare case sensitive
36 return strcmp(*a, *b);
37 }
38
39 //-------------------------------------------------------------------------------------
40 // not case sensitive comparision function for qsort()
41 int CmpFunc2(const void* _a, const void* _b)
42 {
43 // explicit typecast
44 const char** a = (const char**) _a;
45 const char** b = (const char**) _b;
46
47 // compare ignoring case
48 return strcmpi(*a, *b);
49 }
50
51
52
53 //----------------------------------------------------------------------------------------------------------------------
54 // constructor
55 TWordList::TWordList()
56 {
57 words = NULL; // ini
58 _n = 0;
59 randomize();
60 }
61
62
63 //----------------------------------------------------------------------------------------------------------------------
64 // destructor
65 TWordList::~TWordList()
66 {
67 Release();
68 }
69
70
71 //----------------------------------------------------------------------------------------------------------------------
72 // release memory
73 void TWordList::Release()
74 {
75 // release word list memory
76 for(int i=0;i<_n;i++)
77 delete[] words[i];
78 delete[] words;
79
80 words = NULL; // ini
81 _n = 0;
82 }
83
84
85 //----------------------------------------------------------------------------------------------------------------------
86 // load words from file
87 void TWordList::Load(ifstream& file, const char*const& szKey, const bool& f_CaseSensitive)
88 {
89 Release(); // release memory
90 if(f_CaseSensitive) // initialize pointer to comparison function
91 CmpFunc = &CmpFunc1; // case sensitive
92 else
93 CmpFunc = &CmpFunc2; // not case sensitive
94
95
96 streampos curpos = file.tellg(); // store actual stream position
97 try
98 {
99 //----------------------------------------------------------------------------------------------------------------
100 // position to value of key 'szKey'
101 try
102 {
103 SearchKey(file, szKey, INT_MAX, '['); // search key, but only within current section
104 }
105 catch(int errNo) { throw 0; }
106
107 if(file.get()!='=') // if next character is not '=' -> return
108 throw 0;
109
110 if(skipws(file)!=0) // remove whitespaces
111 throw ValueMissing;
112
113 if(file.get()!='"') // if next character is not '"' -> throw exception
114 throw 1;
115
116
117 //----------------------------------------------------------------------------------------------------------------
118 // determine number of keywords
119 streampos begin = file.tellg(); // store actual stream position
120
121 // count number of (white-)space seperated strings
122 char c, szTmp[MAX_WORD_LEN];
123 int line, __n = 0;
124 do
125 {
126 c = ReadString(file, szTmp, MAX_WORD_LEN, '"'); // read string, additional delimiter is '"'
127 line = skipws(file); // remove all whitespaces
128 __n++; // increment string counter if string is not empty
129 } while(c!='"' && file.peek() !='"' && line<2); // repeat as long as delimiter was not '"' and there was at most one line feed
130
131 if(szTmp[0]=='\0') // decrement string counter by one if string is empty
132 __n--; // Note: may happen if whitespaces are before terminating quote
133 file.seekg(begin); // restore stream position
134
135
136 //----------------------------------------------------------------------------------------------------------------
137 // allocate memory
138 _n = __n;
139 words = new char*[_n];
140 for(int i=0;i<_n;i++)
141 words[i] = new char[MAX_WORD_LEN];
142
143
144
145 //----------------------------------------------------------------------------------------------------------------
146 // read all (white-)space seperated strings and sort them
147 for(int i=0;i<_n;i++)
148 {
149 ReadString(file, words[i], MAX_WORD_LEN, '"'); // read string, additional delimiter is '"'
150 skipws(file); // remove all whitespaces
151 }
152 char s=file.get();
153 if(s!='"') // remove and check the delimiter, must be '"'
154 throw 2;
155
156
157 // sort the keywords in alphabetical order
158 qsort((void*) words, _n, sizeof(char*), CmpFunc);
159
160 }
161 catch(int errNo)
162 {
163 Release(); // release memory again
164
165 if(errNo>0)
166 {
167 // compose error text
168 char szText[STS];
169
170 switch(errNo)
171 {
172 case 1 : sprintf(szText, "reading key '%s': Value of key must be enclosed within quotes", GetLastKey()); break;
173 case 2 : sprintf(szText, "reading key '%s': Value of key must be enclosed within quotes", GetLastKey()); break;
174 default : sprintf(szText, "reading key '%s': %s", GetLastKey(), GetLastError(errNo));
175 }
176
177 file.seekg(curpos); // restore stream position
178 throw TErrText(szText); // propagate exception
179 }
180 }
181
182 file.seekg(curpos); // restore stream position
183 }
184
185
186 //----------------------------------------------------------------------------------------------------------------------
187 // returns true, if <szWord> is in word list
188 bool TWordList::IsInList(const char*const& szWord) const
189 {
190 if(bsearch((const void*) &szWord, (const void*) words, _n, sizeof(char*), CmpFunc))
191 return true;
192
193 return false; // no match found: return false
194 }
195
196
197 //----------------------------------------------------------------------------------------------------------------------
198 // save words to file
199 void TWordList::Save(ofstream& file, const char*const& szKey, const int& width) const
200 {
201 if(_n==0) // return if word list is empty
202 return;
203
204 file << setw(width) << szKey << " = \""; // write key
205
206 // write all keywords to file
207 int nChars = 0;
208 for(int i=0;i<_n;i++)
209 {
210 nChars += SizeOfString(words[i]); // sum up number of characters written in current line so far
211 if(nChars > RIGHT_MARGIN) // check right margin and start new line if necessary
212 {
213 nChars = 0; // reset
214 file << endl; // linefeed
215 file << setw(width) << " " << " "; // indent
216 }
217 file << words[i] << " ";
218 }
219 file << "\"" << endl;
220 }
221
222
223 //----------------------------------------------------------------------------------------------------------------------
224 // return random word from list or NULL if list is empty
225 const char* TWordList::GetRandom() const
226 {
227 if(_n>0)
228 return words[random(_n)];
229 else
230 return NULL;
231 }
Top |