You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

509 lines
12 KiB

15 years ago
15 years ago
  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. /**
  24. * @file string.cpp
  25. * @brief Some useful functions to handle strings.
  26. */
  27. #include <fctsys.h>
  28. #include <macros.h>
  29. #include <richio.h> // StrPrintf
  30. #include <kicad_string.h>
  31. /**
  32. * Illegal file name characters used to insure file names will be valid on all supported
  33. * platforms. This is the list of illegal file name characters for Windows which includes
  34. * the illegal file name characters for Linux and OSX.
  35. */
  36. static const char illegalFileNameChars[] = "\\/:\"<>|";
  37. int ReadDelimitedText( wxString* aDest, const char* aSource )
  38. {
  39. std::string utf8; // utf8 but without escapes and quotes.
  40. bool inside = false;
  41. const char* start = aSource;
  42. char cc;
  43. while( (cc = *aSource++) != 0 )
  44. {
  45. if( cc == '"' )
  46. {
  47. if( inside )
  48. break; // 2nd double quote is end of delimited text
  49. inside = true; // first delimiter found, make note, do not copy
  50. }
  51. else if( inside )
  52. {
  53. if( cc == '\\' )
  54. {
  55. cc = *aSource++;
  56. if( !cc )
  57. break;
  58. // do no copy the escape byte if it is followed by \ or "
  59. if( cc != '"' && cc != '\\' )
  60. utf8 += '\\';
  61. utf8 += cc;
  62. }
  63. else
  64. {
  65. utf8 += cc;
  66. }
  67. }
  68. }
  69. *aDest = FROM_UTF8( utf8.c_str() );
  70. return aSource - start;
  71. }
  72. int ReadDelimitedText( char* aDest, const char* aSource, int aDestSize )
  73. {
  74. if( aDestSize <= 0 )
  75. return 0;
  76. bool inside = false;
  77. const char* start = aSource;
  78. char* limit = aDest + aDestSize - 1;
  79. char cc;
  80. while( (cc = *aSource++) != 0 && aDest < limit )
  81. {
  82. if( cc == '"' )
  83. {
  84. if( inside )
  85. break; // 2nd double quote is end of delimited text
  86. inside = true; // first delimiter found, make note, do not copy
  87. }
  88. else if( inside )
  89. {
  90. if( cc == '\\' )
  91. {
  92. cc = *aSource++;
  93. if( !cc )
  94. break;
  95. // do no copy the escape byte if it is followed by \ or "
  96. if( cc != '"' && cc != '\\' )
  97. *aDest++ = '\\';
  98. if( aDest < limit )
  99. *aDest++ = cc;
  100. }
  101. else
  102. {
  103. *aDest++ = cc;
  104. }
  105. }
  106. }
  107. *aDest = 0;
  108. return aSource - start;
  109. }
  110. std::string EscapedUTF8( const wxString& aString )
  111. {
  112. std::string utf8 = TO_UTF8( aString );
  113. std::string ret;
  114. ret += '"';
  115. for( std::string::const_iterator it = utf8.begin(); it!=utf8.end(); ++it )
  116. {
  117. // this escaping strategy is designed to be compatible with ReadDelimitedText():
  118. if( *it == '"' )
  119. {
  120. ret += '\\';
  121. ret += '"';
  122. }
  123. else if( *it == '\\' )
  124. {
  125. ret += '\\'; // double it up
  126. ret += '\\';
  127. }
  128. else
  129. {
  130. ret += *it;
  131. }
  132. }
  133. ret += '"';
  134. return ret;
  135. }
  136. wxString EscapedHTML( const wxString& aString )
  137. {
  138. wxString converted;
  139. for( wxUniChar c: aString )
  140. {
  141. if( c == '\"' )
  142. converted += "&quot;";
  143. else if( c == '\'' )
  144. converted += "&apos;";
  145. else if( c == '&' )
  146. converted += "&amp;";
  147. else if( c == '<' )
  148. converted += "&lt;";
  149. else if( c == '>' )
  150. converted += "&gt;";
  151. else
  152. converted += c;
  153. }
  154. return converted;
  155. }
  156. char* StrPurge( char* text )
  157. {
  158. static const char whitespace[] = " \t\n\r\f\v";
  159. if( text )
  160. {
  161. while( *text && strchr( whitespace, *text ) )
  162. ++text;
  163. char* cp = text + strlen( text ) - 1;
  164. while( cp >= text && strchr( whitespace, *cp ) )
  165. *cp-- = '\0';
  166. }
  167. return text;
  168. }
  169. char* GetLine( FILE* File, char* Line, int* LineNum, int SizeLine )
  170. {
  171. do {
  172. if( fgets( Line, SizeLine, File ) == NULL )
  173. return NULL;
  174. if( LineNum )
  175. *LineNum += 1;
  176. } while( Line[0] == '#' || Line[0] == '\n' || Line[0] == '\r' || Line[0] == 0 );
  177. strtok( Line, "\n\r" );
  178. return Line;
  179. }
  180. wxString DateAndTime()
  181. {
  182. wxDateTime datetime = wxDateTime::Now();
  183. datetime.SetCountry( wxDateTime::Country_Default );
  184. return datetime.Format( wxDefaultDateTimeFormat, wxDateTime::Local );
  185. }
  186. int StrNumCmp( const wxString& aString1, const wxString& aString2, int aLength, bool aIgnoreCase )
  187. {
  188. int i;
  189. int nb1 = 0, nb2 = 0;
  190. wxString::const_iterator str1 = aString1.begin(), str2 = aString2.begin();
  191. if( ( str1 == aString1.end() ) || ( str2 == aString2.end() ) )
  192. return 0;
  193. for( i = 0; i < aLength; i++ )
  194. {
  195. if( isdigit( *str1 ) && isdigit( *str2 ) ) /* digit found */
  196. {
  197. nb1 = 0;
  198. nb2 = 0;
  199. while( isdigit( *str1 ) )
  200. {
  201. nb1 = nb1 * 10 + (int) *str1 - '0';
  202. ++str1;
  203. }
  204. while( isdigit( *str2 ) )
  205. {
  206. nb2 = nb2 * 10 + (int) *str2 - '0';
  207. ++str2;
  208. }
  209. if( nb1 < nb2 )
  210. return -1;
  211. if( nb1 > nb2 )
  212. return 1;
  213. }
  214. if( aIgnoreCase )
  215. {
  216. if( toupper( *str1 ) < toupper( *str2 ) )
  217. return -1;
  218. if( toupper( *str1 ) > toupper( *str2 ) )
  219. return 1;
  220. if( ( *str1 == 0 ) && ( *str2 == 0 ) )
  221. return 0;
  222. }
  223. else
  224. {
  225. if( *str1 < *str2 )
  226. return -1;
  227. if( *str1 > *str2 )
  228. return 1;
  229. if( ( str1 == aString1.end() ) && ( str2 == aString2.end() ) )
  230. return 0;
  231. }
  232. ++str1;
  233. ++str2;
  234. }
  235. return 0;
  236. }
  237. bool WildCompareString( const wxString& pattern, const wxString& string_to_tst,
  238. bool case_sensitive )
  239. {
  240. const wxChar* cp = NULL, * mp = NULL;
  241. const wxChar* wild, * string;
  242. wxString _pattern, _string_to_tst;
  243. if( case_sensitive )
  244. {
  245. wild = pattern.GetData();
  246. string = string_to_tst.GetData();
  247. }
  248. else
  249. {
  250. _pattern = pattern;
  251. _pattern.MakeUpper();
  252. _string_to_tst = string_to_tst;
  253. _string_to_tst.MakeUpper();
  254. wild = _pattern.GetData();
  255. string = _string_to_tst.GetData();
  256. }
  257. while( ( *string ) && ( *wild != '*' ) )
  258. {
  259. if( ( *wild != *string ) && ( *wild != '?' ) )
  260. return false;
  261. wild++; string++;
  262. }
  263. while( *string )
  264. {
  265. if( *wild == '*' )
  266. {
  267. if( !*++wild )
  268. return 1;
  269. mp = wild;
  270. cp = string + 1;
  271. }
  272. else if( ( *wild == *string ) || ( *wild == '?' ) )
  273. {
  274. wild++;
  275. string++;
  276. }
  277. else
  278. {
  279. wild = mp;
  280. string = cp++;
  281. }
  282. }
  283. while( *wild == '*' )
  284. {
  285. wild++;
  286. }
  287. return !*wild;
  288. }
  289. int RefDesStringCompare( const wxString& strFWord, const wxString& strSWord )
  290. {
  291. // The different sections of the first string
  292. wxString strFWordBeg, strFWordMid, strFWordEnd;
  293. // The different sections of the second string
  294. wxString strSWordBeg, strSWordMid, strSWordEnd;
  295. int isEqual = 0; // The numerical results of a string compare
  296. int iReturn = 0; // The variable that is being returned
  297. long lFirstDigit = 0; // The converted middle section of the first string
  298. long lSecondDigit = 0; // The converted middle section of the second string
  299. // Split the two strings into separate parts
  300. SplitString( strFWord, &strFWordBeg, &strFWordMid, &strFWordEnd );
  301. SplitString( strSWord, &strSWordBeg, &strSWordMid, &strSWordEnd );
  302. // Compare the Beginning section of the strings
  303. isEqual = strFWordBeg.CmpNoCase( strSWordBeg );
  304. if( isEqual > 0 )
  305. iReturn = 1;
  306. else if( isEqual < 0 )
  307. iReturn = -1;
  308. else
  309. {
  310. // If the first sections are equal compare their digits
  311. strFWordMid.ToLong( &lFirstDigit );
  312. strSWordMid.ToLong( &lSecondDigit );
  313. if( lFirstDigit > lSecondDigit )
  314. iReturn = 1;
  315. else if( lFirstDigit < lSecondDigit )
  316. iReturn = -1;
  317. else
  318. {
  319. // If the first two sections are equal compare the endings
  320. isEqual = strFWordEnd.CmpNoCase( strSWordEnd );
  321. if( isEqual > 0 )
  322. iReturn = 1;
  323. else if( isEqual < 0 )
  324. iReturn = -1;
  325. else
  326. iReturn = 0;
  327. }
  328. }
  329. return iReturn;
  330. }
  331. int SplitString( wxString strToSplit,
  332. wxString* strBeginning,
  333. wxString* strDigits,
  334. wxString* strEnd )
  335. {
  336. // Clear all the return strings
  337. strBeginning->Empty();
  338. strDigits->Empty();
  339. strEnd->Empty();
  340. // There no need to do anything if the string is empty
  341. if( strToSplit.length() == 0 )
  342. return 0;
  343. // Starting at the end of the string look for the first digit
  344. int ii;
  345. for( ii = (strToSplit.length() - 1); ii >= 0; ii-- )
  346. {
  347. if( isdigit( strToSplit[ii] ) )
  348. break;
  349. }
  350. // If there were no digits then just set the single string
  351. if( ii < 0 )
  352. {
  353. *strBeginning = strToSplit;
  354. }
  355. else
  356. {
  357. // Since there is at least one digit this is the trailing string
  358. *strEnd = strToSplit.substr( ii + 1 );
  359. // Go to the end of the digits
  360. int position = ii + 1;
  361. for( ; ii >= 0; ii-- )
  362. {
  363. if( !isdigit( strToSplit[ii] ) )
  364. break;
  365. }
  366. // If all that was left was digits, then just set the digits string
  367. if( ii < 0 )
  368. *strDigits = strToSplit.substr( 0, position );
  369. /* We were only looking for the last set of digits everything else is
  370. * part of the preamble */
  371. else
  372. {
  373. *strDigits = strToSplit.substr( ii + 1, position - ii - 1 );
  374. *strBeginning = strToSplit.substr( 0, ii + 1 );
  375. }
  376. }
  377. return 0;
  378. }
  379. wxString GetIllegalFileNameWxChars()
  380. {
  381. return FROM_UTF8( illegalFileNameChars );
  382. }
  383. bool ReplaceIllegalFileNameChars( std::string* aName, int aReplaceChar )
  384. {
  385. bool changed = false;
  386. std::string result;
  387. for( std::string::iterator it = aName->begin(); it != aName->end(); ++it )
  388. {
  389. if( strchr( illegalFileNameChars, *it ) )
  390. {
  391. if( aReplaceChar )
  392. StrPrintf( &result, "%c", aReplaceChar );
  393. else
  394. StrPrintf( &result, "%%%02x", *it );
  395. changed = true;
  396. }
  397. else
  398. {
  399. result += *it;
  400. }
  401. }
  402. if( changed )
  403. *aName = result;
  404. return changed;
  405. }