Back
1 //------------------------------------------------------------------------------
2 // Module StyleFile.cpp //
3 // //
4 // Class TStyleFile which encapsulates several TItemStyle objects which //
5 // are loaded from style file //
6 // //
7 // Copyright (c) 2000-2004 by Lars Haendel //
8 // Home: http://www.newty.de //
9 // //
10 // This program is free software and can be used under the terms of the //
11 // GNU licence. See header-file for further information and disclaimer. //
12 // //
13 //------------------------------------------------------------------------------
14
15
16 #include <iomanip> // due to: setw()
17
18 #include "StyleFile.h"
19 #include "FileUtil.h" // skipws() ...
20 #include "NameUtil.h" // SizeOfString() ...
21 #include "ErrText.h" // TErrText
22 #include "defines.h" // program name ...
23
24
25 #define MODULE "TStyleFile"
26 #define VERSION "v2.0b"
27 #define WIDTH 12 // width used to left justify item names
28
29
30
31
32 //----------------------------------------------------------------------------------------------------------------------
33 // Utility-function: check if given string is a valid color string like "#aa00dd" for example.
34 bool CheckColorString(const char*const& szString)
35 {
36 // a) check length - there must be 7 characters
37 if(SizeOfString(szString)!=7)
38 return false;
39
40
41 // b) check format - the string must begin with '#'
42 if(szString[0]!='#')
43 return false;
44
45
46 //c) check 'inner' part - only hex values (0..9, a..f, A..F) are allowed
47 for(int i=1;i<7;i++)
48 if(!IsDigit(szString[i]) && !IsHexAlpha(szString[i]))
49 return false;
50
51 // d) all checks passed: return true
52 return true;
53 }
54
55
56 //----------------------------------------------------------------------------------------------------------------------
57 // get style id by name
58 int TStyleFile::GetStyleId(const char*const& szName)
59 {
60 for(int i=0;i<styles.Size();i++) // iterate list
61 if(strcmp(styles.Get(i).szName, szName)==0)
62 return i; // style found, return id
63 return -1; // style not found, return -1
64 }
65
66
67 //----------------------------------------------------------------------------------------------------------------------
68 // Return style by its name. Return NULL if no style is found.
69 TItemStyle* TStyleFile::GetStyle(const char*const& szName)
70 {
71 for(int i=0;i<styles.Size();i++) // iterate list
72 if(strcmp(styles.Get(i).szName, szName)==0)
73 return &styles.Get(i); // style found, return it
74 return NULL; // style not found, return NULL
75 }
76
77
78 //----------------------------------------------------------------------------------------------------------------------
79 // Load styles from style file
80 void TStyleFile::Load(const char*const& szFileName)
81 {
82 // 1. try to open file and check success
83 ifstream file(szFileName, ios::in);
84
85 if(!file)
86 throw TErrText("Unable to open file: ", szFileName);
87
88
89 // 2. initialize
90 styles.Clear(); // clear style list
91 TItemStyle* style = NULL; // temporary style object which is read and then inserted in the list
92 int line = 1; // line counter
93 char szString[STS];
94 bool f_SkippingBasics = false; // flag indicates the skipping of obsolete section '[Basics]'
95 // Note: Options have been moved to file INI_FILENAME
96
97
98 // 3. read file
99 // mechanism: I. Skip all comments and read a string. Goto II. if it's not a section else ...
100 // a) set skip section flag if it's the section '[Basics]'
101 // b) otherwise take the section name as name for a style
102 // Continue with I.
103 //
104 // II. Skip if skip section flag is set. Else interpret as item name: read highlighting
105 // specifications for the specified item until endl.
106 // Continue with I.
107 try
108 {
109 // note: unnecessary loop cause loop is breaked if eof is encountered
110 do
111 {
112 // I.
113 line += skipwsEx(file); // skip all whitespaces/comments
114 int delimiter = ReadString(file, szString, STS); // read string ...
115 int _len = SizeOfString(szString); // ... and determine its length
116
117 if(delimiter == EOF) // break if eof is reached
118 break;
119
120
121 // a) try to interpret as section '[Basics]'
122 if(strcmp(szString, "[Basics]")==0)
123 f_SkippingBasics = true; // set skip section flag
124 else
125 // b) try to interpret as a style
126 if(szString[0] =='[' && szString[_len-1] == ']') // create new style object
127 {
128 f_SkippingBasics = false; // reset flag
129
130 if(style) // if one exists ...
131 styles.Ins(*style); // ... insert last style in list ... (it will be copied)
132
133 delete style; // delete
134 style = new TItemStyle; // create new one
135
136 // the section name is the style's name: copy it without '[' and ']' exchanging '_' with a space
137 for(int i=0;i<_len-2;i++)
138 {
139 if(szString[i+1]=='_')
140 style->szName[i] = ' ';
141 else
142 style->szName[i] = szString[i+1];
143 }
144
145 style->szName[_len-2] = '\0'; // terminate string
146 }
147 // II. Skip section if flag is set or try to interpret as item name
148 else
149 {
150 // a) skip section if flag is set
151 if(f_SkippingBasics)
152 {
153 file.get(szString, STS); // remove rest of line
154 line += skipwsExEndl(file); // remove endl throwing an exception if there is none
155 }
156
157 // b) else: try to interpret as item name
158 else
159 {
160 // 1. if no style object exists (no section, i.e. style's name, has been read so far): throw error
161 if(!style)
162 throw TErrText("Section key expected!", line);
163
164
165 // 2. try to identify as item name
166 int id = IdentifyItemName(szString);
167
168 // if failed: throw error
169 if(id == -1)
170 throw TErrText("Unidentified item name ", line, szString);
171
172
173 // 3. remove '=': skip all ws/comments throwing an exception if an endl occurs or if the next
174 // character is not an '='
175 if(skipwsEx(file)!=0 || file.get()!='=')
176 throw TErrText("There is no '=' after the item ", line, szString);
177
178
179 // remove ws/comments and throw an exception if an endl occurs
180 if(skipwsEx(file)!=0)
181 throw TErrText("Specifications missing for item ", line, szString);
182
183
184 // 4. read color, bold and italic for specified item
185 int lf;
186
187 // read and interprete all strings in line ...
188 do
189 {
190 ReadString(file, szString, STS); // read string ...
191
192 // ... and try to identify it either as color ...
193 if(CheckColorString(szString))
194 strcpy(style->szColor[id], szString);
195 else
196 // ... or as bold flag ...
197 if(strcmp(szString, "bold")==0)
198 {
199 if(id == TItemStyle::Identifier || id == TItemStyle::Bkgnd)
200 throw TErrText("Bold style specified for item 'identifier' or 'bkgnd' in style ", line, style->szName);
201 style->f_Bold[id] = true;
202 }
203 else
204 // ... or as italic flag ...
205 if(strcmp(szString, "italic")==0)
206 {
207 if(id == TItemStyle::Identifier || id == TItemStyle::Bkgnd)
208 throw TErrText("Italic style specified for item 'identifier' or 'bkgnd' in style ", line, style->szName);
209
210 style->f_Italic[id] = true;
211 }
212 else
213 // ... or as exception :-)
214 throw TErrText("Unidentified style specification ", line, szString);
215
216 lf = skipwsEx(file); // skip all whitespaces and comments
217 line +=lf; // track line number
218
219 } while(lf==0); // ... continue while no linefeed occured
220
221 } // end: try to interpret as item name
222 } // end: II. Skip section if flag is set or try to interpret as item name
223
224 } while(file.fail()==0);
225 }
226 catch(int errNo) // handle/re-throw errors thrown from file utility functions like skipws()
227 {
228 throw TErrText(GetLastError(errNo), line);
229 }
230
231
232 // 4. eof has been reached. Add last style to list if there is one.
233 if(style)
234 {
235 styles.Ins(*style); // insert the last (temporary) style object in list ... (it will be copied)
236 delete style; // and delete
237 }
238 }
239
240
241 //----------------------------------------------------------------------------------------------------------------------
242 // Save styles to style file. The style with the number 'moveToFirst' is saved first if this number is
243 // within valid range.
244 void TStyleFile::Save(const char*const& szFileName, const int& moveToFirst)
245 {
246 // a) open file for output and check success
247 ofstream file(szFileName, ios::out);
248
249 if(!file)
250 throw TErrText("Unable to open file for output: ", szFileName);
251
252
253 // b) write header
254 file << "# Highlighting styles for " << SZ_PRGNAME << " " << SZ_VERSION;
255 file << " written by " << MODULE << " " << VERSION << endl;
256 file << "# Notes: Do not edit while the programs runs!" << endl;
257 file << "# The section names must not have any whitespaces inside!" << endl << endl << endl;
258
259
260 // c) if specified and within legal range : write the style with number 'moveToFirst' first
261 if(moveToFirst>=0 && moveToFirst<styles.Size())
262 WriteStyle2File(styles.Get(moveToFirst), file);
263
264
265 // d) write all style object of the list
266 for(int i=0;i<styles.Size();i++)
267 if(i!=moveToFirst) // skip the style that was already saved
268 WriteStyle2File(styles.Get(i), file);
269 }
270
271
272 //----------------------------------------------------------------------------------------------------------------------
273 // Utility function: Write the given style to the given file
274 void TStyleFile::WriteStyle2File(const TItemStyle& style, ofstream& file)
275 {
276 // 1. write style's name as section
277 file << "[";
278
279 // before saving style name to disk: exchange whitespaces with '_'
280 int i=0;
281 while(style.szName[i]!='\0')
282 {
283 if(isspace(style.szName[i]))
284 file << '_'; // exchange whitespaces with '_'
285 else
286 file << style.szName[i];
287
288 i++;
289 }
290 file << "]" << endl;
291
292
293 // 2. write item style
294 for(int i=0;i<nItemType;i++)
295 {
296 // item name and color
297 file << setiosflags(ios::left) << setw(WIDTH) << setfill(' ') << GetItemName((TItemStyle::ItemType) i) << " = \"";
298 file << style.szColor[i] << "\" ";
299
300 // bold and italic flags
301 if(style.f_Bold[i]) file << "bold ";
302 if(style.f_Italic[i]) file << "italic";
303 file << endl;
304 }
305
306 file << endl;
307 }
Top |