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 bool ApplyModifier( double& value, const wxString& aString )
366 {
367  static const wxString modifiers( wxT( "pnumkKM" ) );
368 
369  if( !aString.length() )
370  return false;
371 
372  wxChar modifier;
373  wxString units;
374 
375  if( modifiers.Find( aString[ 0 ] ) >= 0 )
376  {
377  modifier = aString[ 0 ];
378  units = aString.Mid( 1 ).Trim();
379  }
380  else
381  {
382  modifier = ' ';
383  units = aString.Mid( 0 ).Trim();
384  }
385 
386  if( units.length()
387  && !units.CmpNoCase( wxT( "F" ) )
388  && !units.CmpNoCase( wxT( "hz" ) )
389  && !units.CmpNoCase( wxT( "W" ) )
390  && !units.CmpNoCase( wxT( "V" ) )
391  && !units.CmpNoCase( wxT( "H" ) ) )
392  return false;
393 
394  if( modifier == 'p' )
395  value *= 1.0e-12;
396  if( modifier == 'n' )
397  value *= 1.0e-9;
398  else if( modifier == 'u' )
399  value *= 1.0e-6;
400  else if( modifier == 'm' )
401  value *= 1.0e-3;
402  else if( modifier == 'k' || modifier == 'K' )
403  value *= 1.0e3;
404  else if( modifier == 'M' )
405  value *= 1.0e6;
406  else if( modifier == 'G' )
407  value *= 1.0e9;
408 
409  return true;
410 }
411 
412 
413 // Should handle:
414 // a) Purely numerical e.g. '22'
415 // b) Numerical with included units e.g. '15uF'
416 // c) Numerical with included prefix but no units e.g. '20n'
417 // d) Numerical with prefix inside number e.g. '4K7'
418 // e) Other, e.g. 'MAX232'
419 //
420 // TODO: case (d) unimplemented !!!
421 //
422 int ValueStringCompare( const wxString& strFWord, const wxString& strSWord )
423 {
424  // The different sections of the two strings
425  wxString strFWordBeg, strFWordMid, strFWordEnd;
426  wxString strSWordBeg, strSWordMid, strSWordEnd;
427 
428  // Split the two strings into separate parts
429  SplitString( strFWord, &strFWordBeg, &strFWordMid, &strFWordEnd );
430  SplitString( strSWord, &strSWordBeg, &strSWordMid, &strSWordEnd );
431 
432  // Compare the Beginning section of the strings
433  int isEqual = strFWordBeg.CmpNoCase( strSWordBeg );
434 
435  if( isEqual > 0 )
436  return 1;
437  else if( isEqual < 0 )
438  return -1;
439  else
440  {
441  // If the first sections are equal compare their digits
442  double lFirstNumber = 0;
443  double lSecondNumber = 0;
444  bool endingIsModifier = false;
445 
446  strFWordMid.ToDouble( &lFirstNumber );
447  strSWordMid.ToDouble( &lSecondNumber );
448 
449  endingIsModifier |= ApplyModifier( lFirstNumber, strFWordEnd );
450  endingIsModifier |= ApplyModifier( lSecondNumber, strSWordEnd );
451 
452  if( lFirstNumber > lSecondNumber )
453  return 1;
454  else if( lFirstNumber < lSecondNumber )
455  return -1;
456  // If the first two sections are equal and the endings are modifiers then compare them
457  else if( !endingIsModifier )
458  return strFWordEnd.CmpNoCase( strSWordEnd );
459  // Ran out of things to compare; they must match
460  else
461  return 0;
462  }
463 }
464 
465 
466 int RefDesStringCompare( const wxString& strFWord, const wxString& strSWord )
467 {
468  // The different sections of the two strings
469  wxString strFWordBeg, strFWordMid, strFWordEnd;
470  wxString strSWordBeg, strSWordMid, strSWordEnd;
471 
472  // Split the two strings into separate parts
473  SplitString( strFWord, &strFWordBeg, &strFWordMid, &strFWordEnd );
474  SplitString( strSWord, &strSWordBeg, &strSWordMid, &strSWordEnd );
475 
476  // Compare the Beginning section of the strings
477  int isEqual = strFWordBeg.CmpNoCase( strSWordBeg );
478 
479  if( isEqual > 0 )
480  return 1;
481  else if( isEqual < 0 )
482  return -1;
483  else
484  {
485  // If the first sections are equal compare their digits
486  long lFirstDigit = 0;
487  long lSecondDigit = 0;
488 
489  strFWordMid.ToLong( &lFirstDigit );
490  strSWordMid.ToLong( &lSecondDigit );
491 
492  if( lFirstDigit > lSecondDigit )
493  return 1;
494  else if( lFirstDigit < lSecondDigit )
495  return -1;
496  // If the first two sections are equal compare the endings
497  else
498  return strFWordEnd.CmpNoCase( strSWordEnd );
499  }
500 }
501 
502 
503 int SplitString( wxString strToSplit,
504  wxString* strBeginning,
505  wxString* strDigits,
506  wxString* strEnd )
507 {
508  static const wxString separators( wxT( ".," ) );
509 
510  // Clear all the return strings
511  strBeginning->Empty();
512  strDigits->Empty();
513  strEnd->Empty();
514 
515  // There no need to do anything if the string is empty
516  if( strToSplit.length() == 0 )
517  return 0;
518 
519  // Starting at the end of the string look for the first digit
520  int ii;
521 
522  for( ii = (strToSplit.length() - 1); ii >= 0; ii-- )
523  {
524  if( isdigit( strToSplit[ii] ) )
525  break;
526  }
527 
528  // If there were no digits then just set the single string
529  if( ii < 0 )
530  {
531  *strBeginning = strToSplit;
532  }
533  else
534  {
535  // Since there is at least one digit this is the trailing string
536  *strEnd = strToSplit.substr( ii + 1 );
537 
538  // Go to the end of the digits
539  int position = ii + 1;
540 
541  for( ; ii >= 0; ii-- )
542  {
543  if( !isdigit( strToSplit[ii] ) && separators.Find( strToSplit[ii] ) < 0 )
544  break;
545  }
546 
547  // If all that was left was digits, then just set the digits string
548  if( ii < 0 )
549  *strDigits = strToSplit.substr( 0, position );
550 
551  /* We were only looking for the last set of digits everything else is
552  * part of the preamble */
553  else
554  {
555  *strDigits = strToSplit.substr( ii + 1, position - ii - 1 );
556  *strBeginning = strToSplit.substr( 0, ii + 1 );
557  }
558  }
559 
560  return 0;
561 }
562 
563 
565 {
567 }
568 
569 
570 bool ReplaceIllegalFileNameChars( std::string* aName, int aReplaceChar )
571 {
572  bool changed = false;
573  std::string result;
574  result.reserve( aName->length() );
575 
576  for( std::string::iterator it = aName->begin(); it != aName->end(); ++it )
577  {
578  if( strchr( illegalFileNameChars, *it ) )
579  {
580  if( aReplaceChar )
581  StrPrintf( &result, "%c", aReplaceChar );
582  else
583  StrPrintf( &result, "%%%02x", *it );
584 
585  changed = true;
586  }
587  else
588  {
589  result += *it;
590  }
591  }
592 
593  if( changed )
594  *aName = result;
595 
596  return changed;
597 }
598 
599 
600 bool ReplaceIllegalFileNameChars( wxString& aName, int aReplaceChar )
601 {
602  bool changed = false;
603  wxString result;
604  result.reserve( aName.Length() );
605  wxString illWChars = GetIllegalFileNameWxChars();
606 
607  for( wxString::iterator it = aName.begin(); it != aName.end(); ++it )
608  {
609  if( illWChars.Find( *it ) != wxNOT_FOUND )
610  {
611  if( aReplaceChar )
612  result += aReplaceChar;
613  else
614  result += wxString::Format( "%%%02x", *it );
615 
616  changed = true;
617  }
618  else
619  {
620  result += *it;
621  }
622  }
623 
624  if( changed )
625  aName = result;
626 
627  return changed;
628 }
int ValueStringCompare(const wxString &strFWord, const wxString &strSWord)
Function ValueStringCompare acts just like the strcmp function but handles numbers and modifiers with...
Definition: string.cpp:422
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:466
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:503
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:570
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:564
char * GetLine(FILE *File, char *Line, int *LineNum, int SizeLine)
Function GetLine reads one line line from aFile.
Definition: string.cpp:213
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
size_t i
Definition: json11.cpp:597
int StrNumCmp(const wxString &aString1, const wxString &aString2, int aLength, bool aIgnoreCase)
Function StrNumCmp 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
bool ApplyModifier(double &value, const wxString &aString)
Definition: string.cpp:365
wxString DateAndTime()
Function DateAndTime.
Definition: string.cpp:229