KiCad PCB EDA Suite
string.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2004-2017 KiCad Developers, see AUTHORS.txt for contributors.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
29 #include <fctsys.h>
30 #include <macros.h>
31 #include <richio.h> // StrPrintf
32 #include <kicad_string.h>
33 
34 
40 static const char illegalFileNameChars[] = "\\/:\"<>|";
41 
42 
43 int ReadDelimitedText( wxString* aDest, const char* aSource )
44 {
45  std::string utf8; // utf8 but without escapes and quotes.
46  bool inside = false;
47  const char* start = aSource;
48  char cc;
49 
50  while( (cc = *aSource++) != 0 )
51  {
52  if( cc == '"' )
53  {
54  if( inside )
55  break; // 2nd double quote is end of delimited text
56 
57  inside = true; // first delimiter found, make note, do not copy
58  }
59 
60  else if( inside )
61  {
62  if( cc == '\\' )
63  {
64  cc = *aSource++;
65 
66  if( !cc )
67  break;
68 
69  // do no copy the escape byte if it is followed by \ or "
70  if( cc != '"' && cc != '\\' )
71  utf8 += '\\';
72 
73  utf8 += cc;
74  }
75  else
76  {
77  utf8 += cc;
78  }
79  }
80  }
81 
82  *aDest = FROM_UTF8( utf8.c_str() );
83 
84  return aSource - start;
85 }
86 
87 
88 int ReadDelimitedText( char* aDest, const char* aSource, int aDestSize )
89 {
90  if( aDestSize <= 0 )
91  return 0;
92 
93  bool inside = false;
94  const char* start = aSource;
95  char* limit = aDest + aDestSize - 1;
96  char cc;
97 
98  while( (cc = *aSource++) != 0 && aDest < limit )
99  {
100  if( cc == '"' )
101  {
102  if( inside )
103  break; // 2nd double quote is end of delimited text
104 
105  inside = true; // first delimiter found, make note, do not copy
106  }
107 
108  else if( inside )
109  {
110  if( cc == '\\' )
111  {
112  cc = *aSource++;
113 
114  if( !cc )
115  break;
116 
117  // do no copy the escape byte if it is followed by \ or "
118  if( cc != '"' && cc != '\\' )
119  *aDest++ = '\\';
120 
121  if( aDest < limit )
122  *aDest++ = cc;
123  }
124  else
125  {
126  *aDest++ = cc;
127  }
128  }
129  }
130 
131  *aDest = 0;
132 
133  return aSource - start;
134 }
135 
136 
137 std::string EscapedUTF8( const wxString& aString )
138 {
139  std::string utf8 = TO_UTF8( aString );
140 
141  std::string ret;
142 
143  ret += '"';
144 
145  for( std::string::const_iterator it = utf8.begin(); it!=utf8.end(); ++it )
146  {
147  // this escaping strategy is designed to be compatible with ReadDelimitedText():
148  if( *it == '"' )
149  {
150  ret += '\\';
151  ret += '"';
152  }
153  else if( *it == '\\' )
154  {
155  ret += '\\'; // double it up
156  ret += '\\';
157  }
158  else
159  {
160  ret += *it;
161  }
162  }
163 
164  ret += '"';
165 
166  return ret;
167 }
168 
169 
170 wxString EscapedHTML( const wxString& aString )
171 {
172  wxString converted;
173 
174  for( wxUniChar c: aString )
175  {
176  if( c == '\"' )
177  converted += "&quot;";
178  else if( c == '\'' )
179  converted += "&apos;";
180  else if( c == '&' )
181  converted += "&amp;";
182  else if( c == '<' )
183  converted += "&lt;";
184  else if( c == '>' )
185  converted += "&gt;";
186  else
187  converted += c;
188  }
189 
190  return converted;
191 }
192 
193 
194 char* StrPurge( char* text )
195 {
196  static const char whitespace[] = " \t\n\r\f\v";
197 
198  if( text )
199  {
200  while( *text && strchr( whitespace, *text ) )
201  ++text;
202 
203  char* cp = text + strlen( text ) - 1;
204 
205  while( cp >= text && strchr( whitespace, *cp ) )
206  *cp-- = '\0';
207  }
208 
209  return text;
210 }
211 
212 
213 char* GetLine( FILE* File, char* Line, int* LineNum, int SizeLine )
214 {
215  do {
216  if( fgets( Line, SizeLine, File ) == NULL )
217  return NULL;
218 
219  if( LineNum )
220  *LineNum += 1;
221 
222  } while( Line[0] == '#' || Line[0] == '\n' || Line[0] == '\r' || Line[0] == 0 );
223 
224  strtok( Line, "\n\r" );
225  return Line;
226 }
227 
228 
229 wxString DateAndTime()
230 {
231  wxDateTime datetime = wxDateTime::Now();
232 
233  datetime.SetCountry( wxDateTime::Country_Default );
234  return datetime.Format( wxDefaultDateTimeFormat, wxDateTime::Local );
235 }
236 
237 
238 int StrNumCmp( const wxString& aString1, const wxString& aString2, int aLength, bool aIgnoreCase )
239 {
240  int i;
241  int nb1 = 0, nb2 = 0;
242 
243  wxString::const_iterator str1 = aString1.begin(), str2 = aString2.begin();
244 
245  if( ( str1 == aString1.end() ) || ( str2 == aString2.end() ) )
246  return 0;
247 
248  for( i = 0; i < aLength; i++ )
249  {
250  if( isdigit( *str1 ) && isdigit( *str2 ) ) /* digit found */
251  {
252  nb1 = 0;
253  nb2 = 0;
254 
255  while( isdigit( *str1 ) )
256  {
257  nb1 = nb1 * 10 + (int) *str1 - '0';
258  ++str1;
259  }
260 
261  while( isdigit( *str2 ) )
262  {
263  nb2 = nb2 * 10 + (int) *str2 - '0';
264  ++str2;
265  }
266 
267  if( nb1 < nb2 )
268  return -1;
269 
270  if( nb1 > nb2 )
271  return 1;
272  }
273 
274  if( aIgnoreCase )
275  {
276  if( toupper( *str1 ) < toupper( *str2 ) )
277  return -1;
278 
279  if( toupper( *str1 ) > toupper( *str2 ) )
280  return 1;
281 
282  if( ( *str1 == 0 ) && ( *str2 == 0 ) )
283  return 0;
284  }
285  else
286  {
287  if( *str1 < *str2 )
288  return -1;
289 
290  if( *str1 > *str2 )
291  return 1;
292 
293  if( ( str1 == aString1.end() ) && ( str2 == aString2.end() ) )
294  return 0;
295  }
296 
297  ++str1;
298  ++str2;
299  }
300 
301  return 0;
302 }
303 
304 
305 bool WildCompareString( const wxString& pattern, const wxString& string_to_tst,
306  bool case_sensitive )
307 {
308  const wxChar* cp = NULL, * mp = NULL;
309  const wxChar* wild, * string;
310  wxString _pattern, _string_to_tst;
311 
312  if( case_sensitive )
313  {
314  wild = pattern.GetData();
315  string = string_to_tst.GetData();
316  }
317  else
318  {
319  _pattern = pattern;
320  _pattern.MakeUpper();
321  _string_to_tst = string_to_tst;
322  _string_to_tst.MakeUpper();
323  wild = _pattern.GetData();
324  string = _string_to_tst.GetData();
325  }
326 
327  while( ( *string ) && ( *wild != '*' ) )
328  {
329  if( ( *wild != *string ) && ( *wild != '?' ) )
330  return false;
331 
332  wild++; string++;
333  }
334 
335  while( *string )
336  {
337  if( *wild == '*' )
338  {
339  if( !*++wild )
340  return 1;
341  mp = wild;
342  cp = string + 1;
343  }
344  else if( ( *wild == *string ) || ( *wild == '?' ) )
345  {
346  wild++;
347  string++;
348  }
349  else
350  {
351  wild = mp;
352  string = cp++;
353  }
354  }
355 
356  while( *wild == '*' )
357  {
358  wild++;
359  }
360 
361  return !*wild;
362 }
363 
364 
365 int RefDesStringCompare( const wxString& strFWord, const wxString& strSWord )
366 {
367  // The different sections of the first string
368  wxString strFWordBeg, strFWordMid, strFWordEnd;
369 
370  // The different sections of the second string
371  wxString strSWordBeg, strSWordMid, strSWordEnd;
372 
373  int isEqual = 0; // The numerical results of a string compare
374  int iReturn = 0; // The variable that is being returned
375 
376  long lFirstDigit = 0; // The converted middle section of the first string
377  long lSecondDigit = 0; // The converted middle section of the second string
378 
379  // Split the two strings into separate parts
380  SplitString( strFWord, &strFWordBeg, &strFWordMid, &strFWordEnd );
381  SplitString( strSWord, &strSWordBeg, &strSWordMid, &strSWordEnd );
382 
383  // Compare the Beginning section of the strings
384  isEqual = strFWordBeg.CmpNoCase( strSWordBeg );
385 
386  if( isEqual > 0 )
387  iReturn = 1;
388  else if( isEqual < 0 )
389  iReturn = -1;
390  else
391  {
392  // If the first sections are equal compare their digits
393  strFWordMid.ToLong( &lFirstDigit );
394  strSWordMid.ToLong( &lSecondDigit );
395 
396  if( lFirstDigit > lSecondDigit )
397  iReturn = 1;
398  else if( lFirstDigit < lSecondDigit )
399  iReturn = -1;
400  else
401  {
402  // If the first two sections are equal compare the endings
403  isEqual = strFWordEnd.CmpNoCase( strSWordEnd );
404 
405  if( isEqual > 0 )
406  iReturn = 1;
407  else if( isEqual < 0 )
408  iReturn = -1;
409  else
410  iReturn = 0;
411  }
412  }
413 
414  return iReturn;
415 }
416 
417 
418 int SplitString( wxString strToSplit,
419  wxString* strBeginning,
420  wxString* strDigits,
421  wxString* strEnd )
422 {
423  // Clear all the return strings
424  strBeginning->Empty();
425  strDigits->Empty();
426  strEnd->Empty();
427 
428  // There no need to do anything if the string is empty
429  if( strToSplit.length() == 0 )
430  return 0;
431 
432  // Starting at the end of the string look for the first digit
433  int ii;
434 
435  for( ii = (strToSplit.length() - 1); ii >= 0; ii-- )
436  {
437  if( isdigit( strToSplit[ii] ) )
438  break;
439  }
440 
441  // If there were no digits then just set the single string
442  if( ii < 0 )
443  {
444  *strBeginning = strToSplit;
445  }
446  else
447  {
448  // Since there is at least one digit this is the trailing string
449  *strEnd = strToSplit.substr( ii + 1 );
450 
451  // Go to the end of the digits
452  int position = ii + 1;
453 
454  for( ; ii >= 0; ii-- )
455  {
456  if( !isdigit( strToSplit[ii] ) )
457  break;
458  }
459 
460  // If all that was left was digits, then just set the digits string
461  if( ii < 0 )
462  *strDigits = strToSplit.substr( 0, position );
463 
464  /* We were only looking for the last set of digits everything else is
465  * part of the preamble */
466  else
467  {
468  *strDigits = strToSplit.substr( ii + 1, position - ii - 1 );
469  *strBeginning = strToSplit.substr( 0, ii + 1 );
470  }
471  }
472 
473  return 0;
474 }
475 
476 
478 {
480 }
481 
482 
483 bool ReplaceIllegalFileNameChars( std::string* aName, int aReplaceChar )
484 {
485  bool changed = false;
486  std::string result;
487 
488  for( std::string::iterator it = aName->begin(); it != aName->end(); ++it )
489  {
490  if( strchr( illegalFileNameChars, *it ) )
491  {
492  if( aReplaceChar )
493  StrPrintf( &result, "%c", aReplaceChar );
494  else
495  StrPrintf( &result, "%%%02x", *it );
496 
497  changed = true;
498  }
499  else
500  {
501  result += *it;
502  }
503  }
504 
505  if( changed )
506  *aName = result;
507 
508  return changed;
509 }
int RefDesStringCompare(const wxString &strFWord, const wxString &strSWord)
Function RefDesStringCompare acts just like the strcmp function but treats numbers within the string ...
Definition: string.cpp:365
static const char illegalFileNameChars[]
Illegal file name characters used to insure file names will be valid on all supported platforms...
Definition: string.cpp:40
int SplitString(wxString strToSplit, wxString *strBeginning, wxString *strDigits, wxString *strEnd)
Function SplitString breaks a string into three parts.
Definition: string.cpp:418
static wxString FROM_UTF8(const char *cstring)
function FROM_UTF8 converts a UTF8 encoded C string to a wxString for all wxWidgets build modes...
Definition: macros.h:53
char * StrPurge(char *text)
Function StrPurge removes leading and training spaces, tabs and end of line chars in text return a po...
Definition: string.cpp:194
wxString EscapedHTML(const wxString &aString)
Return a new wxString escaped for embedding in HTML.
Definition: string.cpp:170
bool ReplaceIllegalFileNameChars(std::string *aName, int aReplaceChar)
Function ReplaceIllegalFileNameChars checks aName for illegal file name characters.
Definition: string.cpp:483
This file contains miscellaneous commonly used macros and functions.
int StrPrintf(std::string *result, const char *format,...)
Function StrPrintf is like sprintf() but the output is appended to a std::string instead of to a char...
Definition: richio.cpp:74
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes...
Definition: macros.h:47
std::string EscapedUTF8(const wxString &aString)
Function EscapedUTF8 returns an 8 bit UTF8 string given aString in unicode form.
Definition: string.cpp:137
bool WildCompareString(const wxString &pattern, const wxString &string_to_tst, bool case_sensitive)
Function WildCompareString compares a string against wild card (* and ?) pattern using the usual rule...
Definition: string.cpp:305
wxString GetIllegalFileNameWxChars()
Function GetIllegalFileNameWxChars.
Definition: string.cpp:477
char * GetLine(FILE *File, char *Line, int *LineNum, int SizeLine)
Function GetLine reads one line line from aFile.
Definition: string.cpp:213
int StrNumCmp(const wxString &aString1, const wxString &aString2, int aLength, bool aIgnoreCase)
Function StrLenNumCmp is a routine compatible with qsort() to sort by alphabetical order...
Definition: string.cpp:238
int ReadDelimitedText(wxString *aDest, const char *aSource)
Function ReadDelimitedText copies bytes from aSource delimited string segment to aDest wxString...
Definition: string.cpp:43
wxString DateAndTime()
Function DateAndTime.
Definition: string.cpp:229