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.

485 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 KiCad Developers, see change_log.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. char* StrPurge( char* text )
  137. {
  138. static const char whitespace[] = " \t\n\r\f\v";
  139. if( text )
  140. {
  141. while( *text && strchr( whitespace, *text ) )
  142. ++text;
  143. char* cp = text + strlen( text ) - 1;
  144. while( cp >= text && strchr( whitespace, *cp ) )
  145. *cp-- = '\0';
  146. }
  147. return text;
  148. }
  149. char* GetLine( FILE* File, char* Line, int* LineNum, int SizeLine )
  150. {
  151. do {
  152. if( fgets( Line, SizeLine, File ) == NULL )
  153. return NULL;
  154. if( LineNum )
  155. *LineNum += 1;
  156. } while( Line[0] == '#' || Line[0] == '\n' || Line[0] == '\r' || Line[0] == 0 );
  157. strtok( Line, "\n\r" );
  158. return Line;
  159. }
  160. wxString DateAndTime()
  161. {
  162. wxDateTime datetime = wxDateTime::Now();
  163. datetime.SetCountry( wxDateTime::Country_Default );
  164. return datetime.Format( wxDefaultDateTimeFormat, wxDateTime::Local );
  165. }
  166. int StrNumCmp( const wxString& aString1, const wxString& aString2, int aLength, bool aIgnoreCase )
  167. {
  168. int i;
  169. int nb1 = 0, nb2 = 0;
  170. wxString::const_iterator str1 = aString1.begin(), str2 = aString2.begin();
  171. if( ( str1 == aString1.end() ) || ( str2 == aString2.end() ) )
  172. return 0;
  173. for( i = 0; i < aLength; i++ )
  174. {
  175. if( isdigit( *str1 ) && isdigit( *str2 ) ) /* digit found */
  176. {
  177. nb1 = 0;
  178. nb2 = 0;
  179. while( isdigit( *str1 ) )
  180. {
  181. nb1 = nb1 * 10 + (int) *str1 - '0';
  182. ++str1;
  183. }
  184. while( isdigit( *str2 ) )
  185. {
  186. nb2 = nb2 * 10 + (int) *str2 - '0';
  187. ++str2;
  188. }
  189. if( nb1 < nb2 )
  190. return -1;
  191. if( nb1 > nb2 )
  192. return 1;
  193. }
  194. if( aIgnoreCase )
  195. {
  196. if( toupper( *str1 ) < toupper( *str2 ) )
  197. return -1;
  198. if( toupper( *str1 ) > toupper( *str2 ) )
  199. return 1;
  200. if( ( *str1 == 0 ) && ( *str2 == 0 ) )
  201. return 0;
  202. }
  203. else
  204. {
  205. if( *str1 < *str2 )
  206. return -1;
  207. if( *str1 > *str2 )
  208. return 1;
  209. if( ( str1 == aString1.end() ) && ( str2 == aString2.end() ) )
  210. return 0;
  211. }
  212. ++str1;
  213. ++str2;
  214. }
  215. return 0;
  216. }
  217. bool WildCompareString( const wxString& pattern, const wxString& string_to_tst,
  218. bool case_sensitive )
  219. {
  220. const wxChar* cp = NULL, * mp = NULL;
  221. const wxChar* wild, * string;
  222. wxString _pattern, _string_to_tst;
  223. if( case_sensitive )
  224. {
  225. wild = pattern.GetData();
  226. string = string_to_tst.GetData();
  227. }
  228. else
  229. {
  230. _pattern = pattern;
  231. _pattern.MakeUpper();
  232. _string_to_tst = string_to_tst;
  233. _string_to_tst.MakeUpper();
  234. wild = _pattern.GetData();
  235. string = _string_to_tst.GetData();
  236. }
  237. while( ( *string ) && ( *wild != '*' ) )
  238. {
  239. if( ( *wild != *string ) && ( *wild != '?' ) )
  240. return false;
  241. wild++; string++;
  242. }
  243. while( *string )
  244. {
  245. if( *wild == '*' )
  246. {
  247. if( !*++wild )
  248. return 1;
  249. mp = wild;
  250. cp = string + 1;
  251. }
  252. else if( ( *wild == *string ) || ( *wild == '?' ) )
  253. {
  254. wild++;
  255. string++;
  256. }
  257. else
  258. {
  259. wild = mp;
  260. string = cp++;
  261. }
  262. }
  263. while( *wild == '*' )
  264. {
  265. wild++;
  266. }
  267. return !*wild;
  268. }
  269. int RefDesStringCompare( const wxString& strFWord, const wxString& strSWord )
  270. {
  271. // The different sections of the first string
  272. wxString strFWordBeg, strFWordMid, strFWordEnd;
  273. // The different sections of the second string
  274. wxString strSWordBeg, strSWordMid, strSWordEnd;
  275. int isEqual = 0; // The numerical results of a string compare
  276. int iReturn = 0; // The variable that is being returned
  277. long lFirstDigit = 0; // The converted middle section of the first string
  278. long lSecondDigit = 0; // The converted middle section of the second string
  279. // Split the two strings into separate parts
  280. SplitString( strFWord, &strFWordBeg, &strFWordMid, &strFWordEnd );
  281. SplitString( strSWord, &strSWordBeg, &strSWordMid, &strSWordEnd );
  282. // Compare the Beginning section of the strings
  283. isEqual = strFWordBeg.CmpNoCase( strSWordBeg );
  284. if( isEqual > 0 )
  285. iReturn = 1;
  286. else if( isEqual < 0 )
  287. iReturn = -1;
  288. else
  289. {
  290. // If the first sections are equal compare their digits
  291. strFWordMid.ToLong( &lFirstDigit );
  292. strSWordMid.ToLong( &lSecondDigit );
  293. if( lFirstDigit > lSecondDigit )
  294. iReturn = 1;
  295. else if( lFirstDigit < lSecondDigit )
  296. iReturn = -1;
  297. else
  298. {
  299. // If the first two sections are equal compare the endings
  300. isEqual = strFWordEnd.CmpNoCase( strSWordEnd );
  301. if( isEqual > 0 )
  302. iReturn = 1;
  303. else if( isEqual < 0 )
  304. iReturn = -1;
  305. else
  306. iReturn = 0;
  307. }
  308. }
  309. return iReturn;
  310. }
  311. int SplitString( wxString strToSplit,
  312. wxString* strBeginning,
  313. wxString* strDigits,
  314. wxString* strEnd )
  315. {
  316. // Clear all the return strings
  317. strBeginning->Empty();
  318. strDigits->Empty();
  319. strEnd->Empty();
  320. // There no need to do anything if the string is empty
  321. if( strToSplit.length() == 0 )
  322. return 0;
  323. // Starting at the end of the string look for the first digit
  324. int ii;
  325. for( ii = (strToSplit.length() - 1); ii >= 0; ii-- )
  326. {
  327. if( isdigit( strToSplit[ii] ) )
  328. break;
  329. }
  330. // If there were no digits then just set the single string
  331. if( ii < 0 )
  332. {
  333. *strBeginning = strToSplit;
  334. }
  335. else
  336. {
  337. // Since there is at least one digit this is the trailing string
  338. *strEnd = strToSplit.substr( ii + 1 );
  339. // Go to the end of the digits
  340. int position = ii + 1;
  341. for( ; ii >= 0; ii-- )
  342. {
  343. if( !isdigit( strToSplit[ii] ) )
  344. break;
  345. }
  346. // If all that was left was digits, then just set the digits string
  347. if( ii < 0 )
  348. *strDigits = strToSplit.substr( 0, position );
  349. /* We were only looking for the last set of digits everything else is
  350. * part of the preamble */
  351. else
  352. {
  353. *strDigits = strToSplit.substr( ii + 1, position - ii - 1 );
  354. *strBeginning = strToSplit.substr( 0, ii + 1 );
  355. }
  356. }
  357. return 0;
  358. }
  359. wxString GetIllegalFileNameWxChars()
  360. {
  361. return FROM_UTF8( illegalFileNameChars );
  362. }
  363. bool ReplaceIllegalFileNameChars( std::string* aName, int aReplaceChar )
  364. {
  365. bool changed = false;
  366. std::string result;
  367. for( std::string::iterator it = aName->begin(); it != aName->end(); ++it )
  368. {
  369. if( strchr( illegalFileNameChars, *it ) )
  370. {
  371. if( aReplaceChar )
  372. StrPrintf( &result, "%c", aReplaceChar );
  373. else
  374. StrPrintf( &result, "%%%02x", *it );
  375. changed = true;
  376. }
  377. else
  378. {
  379. result += *it;
  380. }
  381. }
  382. if( changed )
  383. *aName = result;
  384. return changed;
  385. }