Source code of Windows XP (NT5)
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.

513 lines
9.5 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1997
  6. //
  7. // File: bnstr.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. //
  11. // BNSTR.CPP
  12. //
  13. #include <stdarg.h>
  14. #include <ctype.h>
  15. #include "bnstr.h"
  16. SZC BNSTR :: _pmt = "" ;
  17. static SZ SzCopy(SZC szc)
  18. {
  19. SZ szNew = szc ? new char[::strlen(szc) + 1] : NULL;
  20. return szNew ? ::strcpy(szNew, szc) : NULL;
  21. }
  22. BNSTR :: BNSTR ( SZC sz )
  23. : _cchMax( 0 ),
  24. _cchStr( 0 ),
  25. _sz( const_cast<SZ>(_pmt) )
  26. {
  27. if ( sz )
  28. {
  29. Update( sz ) ;
  30. }
  31. }
  32. BNSTR :: BNSTR ( const BNSTR & str )
  33. : _cchMax( str._cchStr ),
  34. _cchStr( str._cchStr ),
  35. _sz( const_cast<SZ>(_pmt) )
  36. {
  37. if ( str._sz != _pmt )
  38. {
  39. _sz = ::SzCopy( str._sz ) ;
  40. }
  41. }
  42. BNSTR :: ~ BNSTR ()
  43. {
  44. Reset() ;
  45. }
  46. void BNSTR :: Reset ()
  47. {
  48. DeleteSz() ;
  49. _sz = const_cast<SZ>(_pmt) ;
  50. _cchStr = 0 ;
  51. _cchMax = 0 ;
  52. }
  53. // Protectively delete either the given string or the
  54. // private string.
  55. void BNSTR :: DeleteSz ()
  56. {
  57. if ( _sz != NULL && _sz != _pmt )
  58. {
  59. delete [] _sz ;
  60. _sz = NULL ;
  61. }
  62. }
  63. // Release the current buffer; reset the BNSTR.
  64. SZ BNSTR::Transfer ()
  65. {
  66. SZ sz = _sz ;
  67. _sz = NULL ;
  68. Reset() ;
  69. return sz = _pmt ? NULL : sz ;
  70. }
  71. // Give the current buffer to a new string, reset *this.
  72. void BNSTR :: Transfer ( BNSTR & str )
  73. {
  74. str.Reset() ;
  75. str._sz = _sz ;
  76. str._cchMax = _cchMax ;
  77. str._cchStr = _cchStr ;
  78. _sz = NULL ;
  79. Reset() ;
  80. }
  81. void BNSTR :: Trunc ( UINT cchLen )
  82. {
  83. if ( _sz == _pmt )
  84. return ;
  85. if ( cchLen < _cchStr )
  86. _sz[cchLen] = 0 ;
  87. }
  88. // Update the pointed string. Since this routine is
  89. // used by the assignment operator, it's written to allow
  90. // for the new string being part of the old string.
  91. bool BNSTR :: Update ( SZC sz )
  92. {
  93. bool bResult = true ;
  94. UINT cch = sz ? ::strlen( sz ) : 0 ;
  95. if ( cch > _cchMax )
  96. {
  97. SZ szNew = ::SzCopy( sz ) ;
  98. if ( bResult = szNew != NULL )
  99. {
  100. DeleteSz() ;
  101. _sz = szNew ;
  102. _cchMax = _cchStr = cch ;
  103. }
  104. }
  105. else
  106. if ( cch == 0 )
  107. {
  108. Reset() ;
  109. }
  110. else
  111. {
  112. // REVIEW: this assumes that ::strcpy() handles overlapping regions correctly.
  113. ::strcpy( _sz, sz ) ;
  114. _cchStr = cch ;
  115. }
  116. return bResult ;
  117. }
  118. // Grow the string. if 'cchNewSize' == 0, expand by 50%.
  119. // If 'ppszNew' is given, store the new string there (for efficiency in
  120. // Prefix); note that this requires that we reallocate.
  121. bool BNSTR :: Grow ( UINT cchNewSize, SZ * ppszNew )
  122. {
  123. UINT cchNew = cchNewSize == 0
  124. ? (_cchMax + (_cchMax/2))
  125. : cchNewSize ;
  126. bool bResult = true ;
  127. if ( cchNew > _cchMax || ppszNew )
  128. {
  129. SZ sz = new char [cchNew+1] ;
  130. if ( bResult = sz != NULL )
  131. {
  132. _cchMax = cchNew ;
  133. if ( ppszNew )
  134. {
  135. *ppszNew = sz ;
  136. }
  137. else
  138. {
  139. ::strcpy( sz, _sz ) ;
  140. DeleteSz() ;
  141. _sz = sz ;
  142. }
  143. }
  144. }
  145. return bResult ;
  146. }
  147. // Expand the string to the given length; make it a blank, null terminated
  148. // string.
  149. bool BNSTR :: Pad ( UINT cchLength )
  150. {
  151. // Expand as necessary
  152. if ( ! Grow( cchLength + 1 ) )
  153. return false ;
  154. // If expanding, pad the string with spaces.
  155. while ( _cchStr < cchLength )
  156. {
  157. _sz[_cchStr++] = ' ' ;
  158. }
  159. // Truncate to proper length
  160. _sz[_cchStr = cchLength] = 0 ;
  161. return true ;
  162. }
  163. bool BNSTR :: Assign ( SZC szcData, UINT cchLen )
  164. {
  165. if ( ! Grow( cchLen + 1 ) )
  166. return false ;
  167. ::memcpy( _sz, szcData, cchLen ) ;
  168. _sz[cchLen] = 0 ;
  169. _cchMax = _cchStr = cchLen ;
  170. return true ;
  171. }
  172. SZC BNSTR :: Prefix ( SZC szPrefix )
  173. {
  174. assert( szPrefix != NULL ) ;
  175. UINT cch = ::strlen( szPrefix ) ;
  176. SZ sz ;
  177. if ( ! Grow( _cchStr + cch + 1, & sz ) )
  178. return NULL ;
  179. ::strcpy( sz, szPrefix ) ;
  180. ::strcpy( sz + cch, _sz ) ;
  181. DeleteSz();
  182. _cchStr += cch ;
  183. return _sz = sz ;
  184. }
  185. SZC BNSTR :: Suffix ( SZC szSuffix )
  186. {
  187. if ( szSuffix )
  188. {
  189. UINT cch = ::strlen( szSuffix ) ;
  190. if ( ! Grow( _cchStr + cch + 1 ) )
  191. return NULL ;
  192. ::strcpy( _sz + _cchStr, szSuffix ) ;
  193. _cchStr += cch ;
  194. }
  195. return *this ;
  196. }
  197. SZC BNSTR :: Suffix ( char chSuffix )
  198. {
  199. char rgch[2] ;
  200. rgch[0] = chSuffix ;
  201. rgch[1] = 0 ;
  202. return Suffix( rgch );
  203. }
  204. INT BNSTR :: Compare ( SZC szSource, bool bIgnoreCase ) const
  205. {
  206. return bIgnoreCase
  207. ? ::stricmp( _sz, szSource )
  208. : ::strcmp( _sz, szSource );
  209. }
  210. // Comparison
  211. bool BNSTR :: operator == ( SZC szcSource ) const
  212. {
  213. return Compare( szcSource ) == 0 ;
  214. }
  215. bool BNSTR :: operator != ( SZC szSource ) const
  216. {
  217. return ! ((*this) == szSource) ;
  218. }
  219. char BNSTR :: operator [] ( UINT iChar ) const
  220. {
  221. assert( iChar < Length() ) ;
  222. return _sz[iChar] ;
  223. }
  224. bool BNSTR :: Vsprintf ( SZC szcFmt, va_list valist )
  225. {
  226. // Attempt to "sprintf" the buffer. If it fails, reallocate
  227. // a larger buffer and try again.
  228. UINT cbMaxNew = ( _cchMax < 50
  229. ? 50
  230. : _cchMax ) + 1 ;
  231. do {
  232. if ( ! Grow( cbMaxNew ) )
  233. {
  234. Reset() ;
  235. return false ;
  236. }
  237. // Cause buffer to grow by 50% on the next cycle (if necessary)
  238. cbMaxNew = 0 ;
  239. // Problem: If the buffer is not big enough, _sz may not have a '\0', and Grow()
  240. // will subsequently barf on the ::strcpy(). Quick fix:
  241. _sz[_cchMax] = '\0';
  242. } while ( ::_vsnprintf( _sz, _cchMax, szcFmt, valist ) < 0 ) ;
  243. _sz[ _cchMax ] = '\0' ; // 'cause _vsnprintf, like _strncpy, doesn't always append this
  244. // Update the string length member
  245. _cchStr = ::strlen( _sz ) ;
  246. return true ;
  247. }
  248. bool BNSTR :: Sprintf ( SZC szcFmt, ... )
  249. {
  250. va_list valist;
  251. va_start( valist, szcFmt );
  252. bool bOk = Vsprintf( szcFmt, valist ) ;
  253. va_end( valist );
  254. return bOk ;
  255. }
  256. bool BNSTR :: SprintfAppend ( SZC szcFmt, ... )
  257. {
  258. BNSTR strTemp ;
  259. va_list valist;
  260. va_start( valist, szcFmt );
  261. bool bOk = strTemp.Vsprintf( szcFmt, valist ) ;
  262. va_end( valist );
  263. if ( bOk )
  264. bOk = Suffix( strTemp ) != NULL ;
  265. return bOk ;
  266. }
  267. // Cr/Lf expansion or contraction
  268. bool BNSTR :: ExpandNl ()
  269. {
  270. UINT iCh ;
  271. BNSTR str ;
  272. Transfer( str ) ;
  273. for ( iCh = 0 ; iCh < str.Length() ; iCh++ )
  274. {
  275. char ch = str[iCh];
  276. if ( ch == '\n' )
  277. {
  278. if ( Suffix( '\r' ) == NULL )
  279. return false ;
  280. }
  281. if ( Suffix( ch ) == NULL )
  282. return false ;
  283. }
  284. return true ;
  285. }
  286. bool BNSTR :: ContractNl ()
  287. {
  288. UINT iCh ;
  289. BNSTR str ;
  290. Transfer( str ) ;
  291. for ( iCh = 0 ; iCh < str.Length() ; iCh++ )
  292. {
  293. char ch = str[iCh];
  294. if ( ch != '\r' )
  295. {
  296. if ( Suffix( ch ) == NULL )
  297. return false ;
  298. }
  299. }
  300. return true ;
  301. }
  302. static char rgchEsc [][2] =
  303. {
  304. { '\a', 'a' },
  305. { '\b', 'b' },
  306. { '\f', 'f' },
  307. { '\n', 'n' },
  308. { '\r', 'r' },
  309. { '\t', 't' },
  310. { '\v', 'v' },
  311. { '\'', '\'' },
  312. { '\"', '\"' },
  313. { '\?', '\?' },
  314. { '\\', '\\' },
  315. { 0, 0 }
  316. };
  317. bool BNSTR :: ContractEscaped ()
  318. {
  319. UINT iCh ;
  320. BNSTR str ;
  321. Transfer( str ) ;
  322. for ( iCh = 0 ; iCh < str.Length() ; iCh++ )
  323. {
  324. char ch = str[iCh];
  325. if ( ch == '\\' && str.Length() - iCh > 1 )
  326. {
  327. char chEsc = 0;
  328. for ( UINT ie = 0 ; rgchEsc[ie][0] ; ie++ )
  329. {
  330. if ( rgchEsc[ie][1] == ch )
  331. break;
  332. }
  333. if ( chEsc = rgchEsc[ie][0] )
  334. {
  335. iCh++;
  336. ch = chEsc;
  337. }
  338. }
  339. if ( Suffix( ch ) == NULL )
  340. return false ;
  341. }
  342. return true ;
  343. }
  344. // Convert unprintable characters to their escaped versions
  345. bool BNSTR :: ExpandEscaped ()
  346. {
  347. UINT iCh ;
  348. BNSTR str ;
  349. Transfer( str ) ;
  350. for ( iCh = 0 ; iCh < str.Length() ; iCh++ )
  351. {
  352. char ch = str[iCh];
  353. if ( ! isalnum(ch) )
  354. {
  355. char chEsc = 0;
  356. for ( UINT ie = 0 ; rgchEsc[ie][0] ; ie++ )
  357. {
  358. if ( rgchEsc[ie][0] == ch )
  359. break;
  360. }
  361. if ( chEsc = rgchEsc[ie][1] )
  362. {
  363. if ( Suffix('\\') == NULL )
  364. return false;
  365. ch = chEsc;
  366. }
  367. }
  368. if ( Suffix( ch ) == NULL )
  369. return false ;
  370. }
  371. return true ;
  372. }
  373. // Change all alphabetic characters to the given case
  374. void BNSTR :: UpCase ( bool bToUpper )
  375. {
  376. if ( bToUpper )
  377. ::strupr( _sz );
  378. else
  379. ::strlwr( _sz );
  380. }
  381. //
  382. // If the given expression string contains the symbolic name,
  383. // reconstruct it with the replacement name.
  384. bool BNSTR :: ReplaceSymName (
  385. SZC szcSymName,
  386. SZC szcSymNameNew,
  387. bool bCaseInsensitive )
  388. {
  389. SZC szcFound ;
  390. int cFound = 0 ;
  391. UINT cchOffset = 0 ;
  392. // Make a working copy of the sought symbolic name
  393. BNSTR strSym( szcSymName );
  394. if ( bCaseInsensitive )
  395. strSym.UpCase();
  396. do
  397. {
  398. BNSTR strTemp( Szc() );
  399. if ( bCaseInsensitive )
  400. strTemp.UpCase() ;
  401. // Locate the symbolic name in the temporary copy.
  402. szcFound = ::strstr( strTemp.Szc()+cchOffset, strSym ) ;
  403. // If not found, we're done
  404. if ( szcFound == NULL )
  405. break ;
  406. // Check to see if it's really a valid token; i.e., it's delimited.
  407. if ( ( szcFound == strTemp.Szc()
  408. || ! iscsym(*(szcFound-1)) )
  409. && ( szcFound >= strTemp.Szc()+strTemp.Length()-strSym.Length()
  410. || ! iscsym(*(szcFound+strSym.Length())) )
  411. )
  412. {
  413. // Build new string from preceding characters, the new sym name
  414. // and trailing chars.
  415. BNSTR strExprNew ;
  416. UINT cchFound = szcFound - strTemp.Szc() ;
  417. strExprNew.Assign( Szc(), cchFound );
  418. strExprNew += szcSymNameNew ;
  419. cchOffset = strExprNew.Length();
  420. strExprNew += Szc() + cchFound + strSym.Length() ;
  421. Assign( strExprNew );
  422. cFound++ ;
  423. }
  424. else
  425. {
  426. // It was imbedded in another token. Skip over it.
  427. cchOffset = szcFound - strTemp.Szc() + strSym.Length() ;
  428. }
  429. } while ( true );
  430. return cFound > 0 ;
  431. }
  432. // Find the next occurrence of the given character in the string;
  433. // Return -1 if not found.
  434. INT BNSTR :: Index ( char chFind, UINT uiOffset ) const
  435. {
  436. if ( uiOffset >= _cchStr )
  437. return -1 ;
  438. SZC szcFound = ::strchr( _sz, chFind );
  439. return szcFound
  440. ? szcFound - _sz
  441. : -1 ;
  442. }
  443. // Convert the string to a floating-point number.
  444. double BNSTR :: Atof ( UINT uiOffset ) const
  445. {
  446. return uiOffset < _cchStr
  447. ? ::atof( _sz + uiOffset )
  448. : -1 ;
  449. }
  450. // End of BNSTR.CXX