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