| [17] | 1 | Unit ACLString;
 | 
|---|
 | 2 | 
 | 
|---|
 | 3 | Interface
 | 
|---|
 | 4 | 
 | 
|---|
 | 5 | uses
 | 
|---|
 | 6 | {$Ifdef os2}
 | 
|---|
 | 7 |   BseDos,
 | 
|---|
 | 8 | {$endif}
 | 
|---|
 | 9 |   SysUtils;
 | 
|---|
 | 10 | 
 | 
|---|
 | 11 | {
 | 
|---|
 | 12 |   AString: A length-safe string class. Internally maintains
 | 
|---|
 | 13 |   a length as well as a zero terminator, so very fast for concatenation
 | 
|---|
 | 14 | 
 | 
|---|
 | 15 |   Attributes:
 | 
|---|
 | 16 |    - zero-based indexing
 | 
|---|
 | 17 |    - maintains zero terminator for passing as (readonly) c-style string (AsPChar)
 | 
|---|
 | 18 |    - fast for concatenation
 | 
|---|
 | 19 |    - no inherent length limit
 | 
|---|
 | 20 | 
 | 
|---|
 | 21 |   You can write to it as pchar by calling SetMaxLength, using AsPChar,
 | 
|---|
 | 22 |   then calling UpdateLength to set the length based on the term.
 | 
|---|
 | 23 | 
 | 
|---|
 | 24 |   For Sibyl it is clumsier but faster for concatenating
 | 
|---|
 | 25 |   than AnsiString and I trust it more...
 | 
|---|
 | 26 | 
 | 
|---|
 | 27 |   For extra safety it explicitly checks that this is a valid instance of
 | 
|---|
 | 28 |   AString on every method call (using an internal magic number)
 | 
|---|
 | 29 |     Note :- because of the exception handling this is probably quite slow.
 | 
|---|
 | 30 | 
 | 
|---|
 | 31 |   You can also call the global procedure
 | 
|---|
 | 32 |     CheckAllAStringsDestroyed
 | 
|---|
 | 33 |   at the end of the program to make sure there are no memory leaks
 | 
|---|
 | 34 |   due to AStrings not being destroyed.
 | 
|---|
 | 35 | 
 | 
|---|
 | 36 |   V1.2 28/6/00
 | 
|---|
 | 37 |     Added ReadLn and WriteLn methods (for text files)
 | 
|---|
 | 38 |     Added Character index property
 | 
|---|
 | 39 |   V1.1 27/6/00
 | 
|---|
 | 40 |     Added:
 | 
|---|
 | 41 |       Delete - delete a seciton of string
 | 
|---|
 | 42 |       Assign methods
 | 
|---|
 | 43 |       AsString property
 | 
|---|
 | 44 |       CharPosition function
 | 
|---|
 | 45 |       ExtractNextValue method
 | 
|---|
 | 46 |         This method, unlike my original string version, does not
 | 
|---|
 | 47 |         alter the main string. Rather it takes and increments
 | 
|---|
 | 48 |         a starting position.
 | 
|---|
 | 49 | 
 | 
|---|
 | 50 |   V1.0
 | 
|---|
 | 51 |     Completed basic functionality
 | 
|---|
 | 52 |     Used in NewView for decoding help topics. Fast!
 | 
|---|
 | 53 | }
 | 
|---|
 | 54 | 
 | 
|---|
 | 55 | type
 | 
|---|
 | 56 |   EAStringError = class( Exception );
 | 
|---|
 | 57 |   EAStringIndexError = class( EAStringError );
 | 
|---|
 | 58 | 
 | 
|---|
 | 59 |   TAString = class
 | 
|---|
 | 60 |   private
 | 
|---|
 | 61 |     function GetIsEmpty: boolean;
 | 
|---|
 | 62 |   protected
 | 
|---|
 | 63 |     _S: PChar;
 | 
|---|
 | 64 |     _Length: longint;
 | 
|---|
 | 65 |     _MagicNumber: longword;
 | 
|---|
 | 66 |     procedure CheckSize( const NeededLength: longint );
 | 
|---|
 | 67 |     procedure AddData( const Data: pointer;
 | 
|---|
 | 68 |                        const DataLength: longint );
 | 
|---|
 | 69 | 
 | 
|---|
 | 70 |     Procedure InsertData( const Data: pointer;
 | 
|---|
 | 71 |                           const InsertPoint: longint;
 | 
|---|
 | 72 |                           const DataLength: longint );
 | 
|---|
 | 73 | 
 | 
|---|
 | 74 |     procedure Initialise;
 | 
|---|
 | 75 | 
 | 
|---|
 | 76 |     function ValidIndex( const Index: longint ): boolean;
 | 
|---|
 | 77 |     procedure CheckIndex( const Index: longint );
 | 
|---|
 | 78 |     function GetAsString: string;
 | 
|---|
 | 79 | 
 | 
|---|
 | 80 |     procedure SetLength( NewLength: longint );
 | 
|---|
 | 81 | 
 | 
|---|
 | 82 |     function GetChar( Index: longint ): Char;
 | 
|---|
 | 83 |     procedure SetChar( Index: longint;
 | 
|---|
 | 84 |                        const Value: Char );
 | 
|---|
 | 85 | 
 | 
|---|
 | 86 |   public
 | 
|---|
 | 87 | 
 | 
|---|
 | 88 |     constructor Create;
 | 
|---|
 | 89 |     constructor CreateFrom( const S: String );
 | 
|---|
 | 90 |     constructor CreateFromPChar( const S: PChar );
 | 
|---|
 | 91 |     constructor CreateFromPCharLen( const S: PChar; const Len: longint );
 | 
|---|
 | 92 |     constructor CreateCopy( const S: TAString );
 | 
|---|
 | 93 | 
 | 
|---|
 | 94 |     // Create a AString from the given PChar and
 | 
|---|
 | 95 |     // dispose of the PChar. Useful for using when you can only
 | 
|---|
 | 96 |     // get a PChar as a newly allocated string (e.g TMemo.Lines.GetText)
 | 
|---|
 | 97 |     constructor CreateFromPCharWithDispose( const S: PChar );
 | 
|---|
 | 98 | 
 | 
|---|
 | 99 |     destructor Destroy; override;
 | 
|---|
 | 100 | 
 | 
|---|
 | 101 |     // Modifications
 | 
|---|
 | 102 |     procedure Assign( const S: TAString );
 | 
|---|
 | 103 |     procedure AssignString( const S: string );
 | 
|---|
 | 104 |     procedure AssignPChar( const S: PChar );
 | 
|---|
 | 105 |     procedure AssignPCharLen( const S: PChar; const Len: longint );
 | 
|---|
 | 106 | 
 | 
|---|
 | 107 |     procedure Add( const S: TAString );
 | 
|---|
 | 108 |     procedure AddString( const S: string );
 | 
|---|
 | 109 |     procedure AddPChar( const S: PChar );
 | 
|---|
 | 110 |     procedure AddPCharLen( const S: PChar; const Len: longint );
 | 
|---|
 | 111 |     procedure AddChar( const C: char );
 | 
|---|
 | 112 | 
 | 
|---|
 | 113 |     Procedure Insert( const InsertPoint: longword;
 | 
|---|
 | 114 |                       const S: TAString );
 | 
|---|
 | 115 |     Procedure InsertString( const InsertPoint: longword;
 | 
|---|
 | 116 |                             const S: string );
 | 
|---|
 | 117 | 
 | 
|---|
 | 118 |     procedure Trim;
 | 
|---|
 | 119 |     procedure TrimChar( CharToTrim: Char );
 | 
|---|
 | 120 |     procedure Delete( const StartingFrom: longint;
 | 
|---|
 | 121 |                       const LengthToDelete: longint );
 | 
|---|
 | 122 |     procedure Clear;
 | 
|---|
 | 123 | 
 | 
|---|
 | 124 |     // Properties
 | 
|---|
 | 125 |     property AsPChar: PChar read _S;
 | 
|---|
 | 126 |     property AsString: string read GetAsString;
 | 
|---|
 | 127 |     property Character[ Index: longint ]: Char read GetChar write SetChar; default;
 | 
|---|
 | 128 |     property Length: longint read _Length write SetLength;
 | 
|---|
 | 129 |     property IsEmpty: boolean read GetIsEmpty;
 | 
|---|
 | 130 | 
 | 
|---|
 | 131 |     // updates length based on terminator, use after writing to as pchar
 | 
|---|
 | 132 |     Procedure UpdateLength;
 | 
|---|
 | 133 | 
 | 
|---|
 | 134 |     // Queries
 | 
|---|
 | 135 |     // returns -1 if not found
 | 
|---|
 | 136 |     function CharPosition( const StartingFrom: longint;
 | 
|---|
 | 137 |                            const CharToFind: Char ): longint;
 | 
|---|
 | 138 | 
 | 
|---|
 | 139 |     function SameAs( const S: String ): boolean;
 | 
|---|
 | 140 | 
 | 
|---|
 | 141 |     // returns true if starts with S
 | 
|---|
 | 142 |     function StartsWith( const S: String ): boolean;
 | 
|---|
 | 143 | 
 | 
|---|
 | 144 |     // Extract the next value seperated by seperator
 | 
|---|
 | 145 |     // starting at StartingFrom (zero based index!)
 | 
|---|
 | 146 |     procedure ExtractNextValue( Var StartingFrom: longint;
 | 
|---|
 | 147 |                                 ExtractTo: TAString;
 | 
|---|
 | 148 |                                 const Seperator: Char );
 | 
|---|
 | 149 |     procedure GetRightFrom( const StartingFrom: longint;
 | 
|---|
 | 150 |                             Dest: TAString );
 | 
|---|
 | 151 |     procedure GetLeft( const Count: longint;
 | 
|---|
 | 152 |                        Dest: TAString );
 | 
|---|
 | 153 |     procedure GetRight( const Count: longint;
 | 
|---|
 | 154 |                         Dest: TAString );
 | 
|---|
 | 155 |     procedure ParseKeyValuePair( KeyName: TAString;
 | 
|---|
 | 156 |                                  KeyValue: TAString;
 | 
|---|
 | 157 |                                  Seperator: Char );
 | 
|---|
 | 158 | 
 | 
|---|
 | 159 |     // Make sure the string can contain at least MaxLength chars
 | 
|---|
 | 160 |     // Use before passing AsPChar to a function that writes a PChar
 | 
|---|
 | 161 |     procedure SetMaxLength( MaxLength: longint );
 | 
|---|
 | 162 | 
 | 
|---|
 | 163 |     // Read a line from the given file. Line must end
 | 
|---|
 | 164 |     // with #13 #10. ( Single #13 or #10 not recognised )
 | 
|---|
 | 165 |     procedure ReadLn( Var TheFile: TextFile );
 | 
|---|
 | 166 |     procedure WriteLn( Var TheFile: TextFile );
 | 
|---|
 | 167 | 
 | 
|---|
 | 168 | {$Ifdef os2}
 | 
|---|
 | 169 |     // Read a line from the given file handle
 | 
|---|
 | 170 |     function ReadParagraph( F: HFile ): boolean;
 | 
|---|
 | 171 | {$endif}
 | 
|---|
 | 172 |   end;
 | 
|---|
 | 173 | 
 | 
|---|
 | 174 | // call this to be sure all AStrings have been destroyed.
 | 
|---|
 | 175 | procedure CheckAllAStringsDestroyed;
 | 
|---|
 | 176 | 
 | 
|---|
 | 177 | Implementation
 | 
|---|
 | 178 | 
 | 
|---|
 | 179 | uses
 | 
|---|
 | 180 | {$Ifdef os2}
 | 
|---|
 | 181 |   OS2Def, ACLFileIOUtility,
 | 
|---|
 | 182 | {$endif}
 | 
|---|
 | 183 |   ACLUtility, ACLStringUtility;
 | 
|---|
 | 184 | 
 | 
|---|
 | 185 | const
 | 
|---|
 | 186 |   GlobalAStringCreatedCount: longint = 0;
 | 
|---|
 | 187 |   GlobalAStringDestroyedCount: longint = 0;
 | 
|---|
 | 188 | 
 | 
|---|
 | 189 | const
 | 
|---|
 | 190 |   MagicConstant = $cabba9e;
 | 
|---|
 | 191 | 
 | 
|---|
 | 192 | procedure CheckAllAStringsDestroyed;
 | 
|---|
 | 193 | begin
 | 
|---|
 | 194 |   if GlobalAStringCreatedCount > GlobalAStringDestroyedCount then
 | 
|---|
 | 195 |     raise Exception.Create( 'Not all AStrings have been destroyed ('
 | 
|---|
 | 196 |                             + IntToStr( GlobalAStringCreatedCount )
 | 
|---|
 | 197 |                             + ' created, '
 | 
|---|
 | 198 |                             + IntToStr( GlobalAStringDestroyedCount )
 | 
|---|
 | 199 |                             + ' destroyed). Possible memory leak.' );
 | 
|---|
 | 200 | end;
 | 
|---|
 | 201 | 
 | 
|---|
 | 202 | procedure CheckValid( const S: TAString );
 | 
|---|
 | 203 | var
 | 
|---|
 | 204 |   IsValid: boolean;
 | 
|---|
 | 205 | begin
 | 
|---|
 | 206 |   try
 | 
|---|
 | 207 |     IsValid:= S._MagicNumber = MagicConstant;
 | 
|---|
 | 208 |   except
 | 
|---|
 | 209 |     IsValid:= false;
 | 
|---|
 | 210 |   end;
 | 
|---|
 | 211 |   if not IsValid then
 | 
|---|
 | 212 |     raise Exception.Create( 'Reference to invalid AString' );
 | 
|---|
 | 213 | end;
 | 
|---|
 | 214 | 
 | 
|---|
 | 215 | constructor TAString.Create;
 | 
|---|
 | 216 | begin
 | 
|---|
 | 217 |   inherited Create;
 | 
|---|
 | 218 |   Initialise;
 | 
|---|
 | 219 | end;
 | 
|---|
 | 220 | 
 | 
|---|
 | 221 | procedure TAString.Initialise;
 | 
|---|
 | 222 | begin
 | 
|---|
 | 223 |   inc( GlobalAStringCreatedCount );
 | 
|---|
 | 224 |   _S:= StrAlloc( 16 );
 | 
|---|
 | 225 |   _MagicNumber:= MagicConstant;
 | 
|---|
 | 226 |   Clear;
 | 
|---|
 | 227 | end;
 | 
|---|
 | 228 | 
 | 
|---|
 | 229 | constructor TAString.CreateFrom( const S: String );
 | 
|---|
 | 230 | begin
 | 
|---|
 | 231 |   Initialise;
 | 
|---|
 | 232 |   AssignString( S );
 | 
|---|
 | 233 | end;
 | 
|---|
 | 234 | 
 | 
|---|
 | 235 | constructor TAString.CreateFromPChar( const S: PChar );
 | 
|---|
 | 236 | begin
 | 
|---|
 | 237 |   Initialise;
 | 
|---|
 | 238 |   AssignPChar( S );
 | 
|---|
 | 239 | end;
 | 
|---|
 | 240 | 
 | 
|---|
 | 241 | constructor TAString.CreateFromPCharLen( const S: PChar; const Len: longint );
 | 
|---|
 | 242 | begin
 | 
|---|
 | 243 |   Initialise;
 | 
|---|
 | 244 |   AssignPCharLen( S, Len );
 | 
|---|
 | 245 | end;
 | 
|---|
 | 246 | 
 | 
|---|
 | 247 | constructor TAString.CreateFromPCharWithDispose( const S: PChar );
 | 
|---|
 | 248 | begin
 | 
|---|
 | 249 |   Initialise;
 | 
|---|
 | 250 |   AddPChar( S );
 | 
|---|
 | 251 |   StrDispose( S );
 | 
|---|
 | 252 | end;
 | 
|---|
 | 253 | 
 | 
|---|
 | 254 | constructor TAString.CreateCopy( const S: TAString );
 | 
|---|
 | 255 | begin
 | 
|---|
 | 256 |   Initialise;
 | 
|---|
 | 257 |   Assign( S );
 | 
|---|
 | 258 | end;
 | 
|---|
 | 259 | 
 | 
|---|
 | 260 | destructor TAString.Destroy;
 | 
|---|
 | 261 | begin
 | 
|---|
 | 262 |   inc( GlobalAStringDestroyedCount );
 | 
|---|
 | 263 |   StrDispose( _S );
 | 
|---|
 | 264 |   _MagicNumber:= 0;
 | 
|---|
 | 265 |   inherited Destroy;
 | 
|---|
 | 266 | end;
 | 
|---|
 | 267 | 
 | 
|---|
 | 268 | procedure TAString.CheckSize( const NeededLength: longint );
 | 
|---|
 | 269 | var
 | 
|---|
 | 270 |   temp: PChar;
 | 
|---|
 | 271 |   NewBufferSize: longint;
 | 
|---|
 | 272 |   CurrentBufferSize: longint;
 | 
|---|
 | 273 | begin
 | 
|---|
 | 274 |   CurrentBufferSize:= StrBufSize( _S );
 | 
|---|
 | 275 |   if NeededLength + 1 > CurrentBufferSize then
 | 
|---|
 | 276 |   begin
 | 
|---|
 | 277 |     // allocate new buffer, double the size...
 | 
|---|
 | 278 |     NewBufferSize:= CurrentBufferSize * 2;
 | 
|---|
 | 279 |     // or if that's not enough...
 | 
|---|
 | 280 |     if NewBufferSize < NeededLength + 1 then
 | 
|---|
 | 281 |       // double what we are going to need
 | 
|---|
 | 282 |       NewBufferSize:= NeededLength * 2;
 | 
|---|
 | 283 | 
 | 
|---|
 | 284 |     temp:= StrAlloc( NewBufferSize );
 | 
|---|
 | 285 | 
 | 
|---|
 | 286 |     MemCopy( _S,
 | 
|---|
 | 287 |              Temp,
 | 
|---|
 | 288 |              _Length + 1 );
 | 
|---|
 | 289 | 
 | 
|---|
 | 290 |     StrDispose( _S );
 | 
|---|
 | 291 |     _S:= temp;
 | 
|---|
 | 292 |   end;
 | 
|---|
 | 293 | end;
 | 
|---|
 | 294 | 
 | 
|---|
 | 295 | procedure TAString.Clear;
 | 
|---|
 | 296 | begin
 | 
|---|
 | 297 |   CheckValid( self );
 | 
|---|
 | 298 |   _Length:= 0;
 | 
|---|
 | 299 |   _S[ 0 ]:= #0;
 | 
|---|
 | 300 | end;
 | 
|---|
 | 301 | 
 | 
|---|
 | 302 | procedure TAString.AddData( const Data: pointer;
 | 
|---|
 | 303 |                             const DataLength: longint );
 | 
|---|
 | 304 | begin
 | 
|---|
 | 305 |   if DataLength = 0 then
 | 
|---|
 | 306 |     exit;
 | 
|---|
 | 307 |   CheckSize( _Length + DataLength );
 | 
|---|
 | 308 |   MemCopy( Data, _S + _Length, DataLength );
 | 
|---|
 | 309 |   inc( _Length, DataLength );
 | 
|---|
 | 310 |   _S[ _Length ]:= #0;
 | 
|---|
 | 311 | end;
 | 
|---|
 | 312 | 
 | 
|---|
 | 313 | Procedure TAString.InsertData( const Data: pointer;
 | 
|---|
 | 314 |                                const InsertPoint: longint;
 | 
|---|
 | 315 |                                const DataLength: longint );
 | 
|---|
 | 316 | begin
 | 
|---|
 | 317 |   // we can also insert at the very end... which is not a valid index
 | 
|---|
 | 318 |   if InsertPoint <> _Length then
 | 
|---|
 | 319 |     if not ValidIndex( InsertPoint ) then
 | 
|---|
 | 320 |       exit;
 | 
|---|
 | 321 | 
 | 
|---|
 | 322 |   CheckSize( _Length + DataLength );
 | 
|---|
 | 323 | 
 | 
|---|
 | 324 |   // shift the existing text, past the insert point,
 | 
|---|
 | 325 |   // up to make room
 | 
|---|
 | 326 |   MemCopy( _S + InsertPoint,
 | 
|---|
 | 327 |            _S + InsertPoint + DataLength,
 | 
|---|
 | 328 |            _Length - InsertPoint );
 | 
|---|
 | 329 | 
 | 
|---|
 | 330 |   MemCopy( Data,
 | 
|---|
 | 331 |            _S + InsertPoint,
 | 
|---|
 | 332 |            DataLength );
 | 
|---|
 | 333 | 
 | 
|---|
 | 334 |   inc( _Length, DataLength );
 | 
|---|
 | 335 | 
 | 
|---|
 | 336 |   // zero terminate
 | 
|---|
 | 337 |   _S[ _Length ] := #0;
 | 
|---|
 | 338 | 
 | 
|---|
 | 339 | end;
 | 
|---|
 | 340 | 
 | 
|---|
 | 341 | procedure TAString.Add( const S: TAString );
 | 
|---|
 | 342 | begin
 | 
|---|
 | 343 |   CheckValid( self );
 | 
|---|
 | 344 |   CheckValid( S );
 | 
|---|
 | 345 |   AddData( S._S, S.Length );
 | 
|---|
 | 346 | end;
 | 
|---|
 | 347 | 
 | 
|---|
 | 348 | procedure TAString.AddPChar( const S: PChar );
 | 
|---|
 | 349 | begin
 | 
|---|
 | 350 |   CheckValid( self );
 | 
|---|
 | 351 |   AddData( S, StrLen( S ) );
 | 
|---|
 | 352 | end;
 | 
|---|
 | 353 | 
 | 
|---|
 | 354 | procedure TAString.AddString( const S: string );
 | 
|---|
 | 355 | begin
 | 
|---|
 | 356 |   CheckValid( self );
 | 
|---|
 | 357 | {$ifdef os2}
 | 
|---|
 | 358 |   AddData( Addr( S ) + 1, System.Length( S ) );
 | 
|---|
 | 359 | {$else}
 | 
|---|
 | 360 |   AddData( PChar( S ), System.Length( S ) );
 | 
|---|
 | 361 | {$endif}
 | 
|---|
 | 362 | end;
 | 
|---|
 | 363 | 
 | 
|---|
 | 364 | procedure TAString.AddChar( const C: char );
 | 
|---|
 | 365 | begin
 | 
|---|
 | 366 |   CheckValid( self );
 | 
|---|
 | 367 |   AddData( Addr( C ), 1 );
 | 
|---|
 | 368 | end;
 | 
|---|
 | 369 | 
 | 
|---|
 | 370 | procedure TAString.TrimChar( CharToTrim: Char );
 | 
|---|
 | 371 | var
 | 
|---|
 | 372 |   StartP: PChar;
 | 
|---|
 | 373 |   EndP: PChar;
 | 
|---|
 | 374 |   C: Char;
 | 
|---|
 | 375 | begin
 | 
|---|
 | 376 |   CheckValid( self );
 | 
|---|
 | 377 |   if _Length = 0 then
 | 
|---|
 | 378 |     exit;
 | 
|---|
 | 379 |   StartP:= _S;
 | 
|---|
 | 380 |   EndP:= _S + Length;
 | 
|---|
 | 381 | 
 | 
|---|
 | 382 |   while StartP < EndP do
 | 
|---|
 | 383 |   begin
 | 
|---|
 | 384 |     C:= StartP^;
 | 
|---|
 | 385 |     if C <> CharToTrim then
 | 
|---|
 | 386 |       break;
 | 
|---|
 | 387 |     inc( StartP );
 | 
|---|
 | 388 |   end;
 | 
|---|
 | 389 |   // StartP now points to first non-space char
 | 
|---|
 | 390 | 
 | 
|---|
 | 391 |   while EndP > StartP do
 | 
|---|
 | 392 |   begin
 | 
|---|
 | 393 |     dec( EndP );
 | 
|---|
 | 394 |     C:= EndP^;
 | 
|---|
 | 395 |     if C <> CharToTrim then
 | 
|---|
 | 396 |     begin
 | 
|---|
 | 397 |       inc( EndP );
 | 
|---|
 | 398 |       break;
 | 
|---|
 | 399 |     end;
 | 
|---|
 | 400 |   end;
 | 
|---|
 | 401 |   // EndP now points to one byte past last non-space char
 | 
|---|
 | 402 | 
 | 
|---|
 | 403 |   _Length:= PCharDiff( EndP, StartP );
 | 
|---|
 | 404 | 
 | 
|---|
 | 405 |   if _Length > 0 then
 | 
|---|
 | 406 |     if StartP > _S then
 | 
|---|
 | 407 |       MemCopy( StartP, _S, _Length );
 | 
|---|
 | 408 | 
 | 
|---|
 | 409 |   _S[ _Length ]:= #0;
 | 
|---|
 | 410 | 
 | 
|---|
 | 411 | end;
 | 
|---|
 | 412 | 
 | 
|---|
 | 413 | procedure TAString.ExtractNextValue( Var StartingFrom: longint;
 | 
|---|
 | 414 |                                      ExtractTo: TAString;
 | 
|---|
 | 415 |                                      const Seperator: Char );
 | 
|---|
 | 416 | var
 | 
|---|
 | 417 |   NextSeperatorPosition: longint;
 | 
|---|
 | 418 | begin
 | 
|---|
 | 419 |   CheckValid( self );
 | 
|---|
 | 420 |   CheckValid( ExtractTo );
 | 
|---|
 | 421 | 
 | 
|---|
 | 422 |   ExtractTo.Clear;
 | 
|---|
 | 423 |   if StartingFrom >= Length then
 | 
|---|
 | 424 |     exit;
 | 
|---|
 | 425 |   NextSeperatorPosition:= CharPosition( StartingFrom,
 | 
|---|
 | 426 |                                         Seperator );
 | 
|---|
 | 427 |   if NextSeperatorPosition > -1 then
 | 
|---|
 | 428 |   begin
 | 
|---|
 | 429 |     ExtractTo.AddData( _S + StartingFrom,
 | 
|---|
 | 430 |                        NextSeperatorPosition - StartingFrom );
 | 
|---|
 | 431 |     StartingFrom:= NextSeperatorPosition + 1;
 | 
|---|
 | 432 |   end
 | 
|---|
 | 433 |   else
 | 
|---|
 | 434 |   begin
 | 
|---|
 | 435 |     ExtractTo.AddData( _S + StartingFrom,
 | 
|---|
 | 436 |                        Length - StartingFrom );
 | 
|---|
 | 437 |     StartingFrom:= Length;
 | 
|---|
 | 438 |   end;
 | 
|---|
 | 439 |   ExtractTo.Trim;
 | 
|---|
 | 440 | 
 | 
|---|
 | 441 | end;
 | 
|---|
 | 442 | 
 | 
|---|
 | 443 | procedure TAString.Assign( const S: TAString );
 | 
|---|
 | 444 | begin
 | 
|---|
 | 445 |   Clear;
 | 
|---|
 | 446 |   Add( S );
 | 
|---|
 | 447 | end;
 | 
|---|
 | 448 | 
 | 
|---|
 | 449 | procedure TAString.AssignPChar( const S: PChar);
 | 
|---|
 | 450 | begin
 | 
|---|
 | 451 |   Clear;
 | 
|---|
 | 452 |   AddPChar( S );
 | 
|---|
 | 453 | end;
 | 
|---|
 | 454 | 
 | 
|---|
 | 455 | procedure TAString.AssignPCharLen( const S: PChar; const Len: longint );
 | 
|---|
 | 456 | begin
 | 
|---|
 | 457 |   Clear;
 | 
|---|
 | 458 |   AddPCharLen( S, Len );
 | 
|---|
 | 459 | end;
 | 
|---|
 | 460 | 
 | 
|---|
 | 461 | procedure TAString.AssignString( const S: string );
 | 
|---|
 | 462 | begin
 | 
|---|
 | 463 |   Clear;
 | 
|---|
 | 464 |   AddString( S );
 | 
|---|
 | 465 | end;
 | 
|---|
 | 466 | 
 | 
|---|
 | 467 | function TAString.CharPosition( const StartingFrom: longint;
 | 
|---|
 | 468 |                                 const CharToFind: Char ): longint;
 | 
|---|
 | 469 | var
 | 
|---|
 | 470 |   StartP: PChar;
 | 
|---|
 | 471 |   P: PChar;
 | 
|---|
 | 472 |   EndP: PChar;
 | 
|---|
 | 473 |   C: Char;
 | 
|---|
 | 474 | begin
 | 
|---|
 | 475 |   CheckValid( self );
 | 
|---|
 | 476 |   Result:= -1;
 | 
|---|
 | 477 |   if not ValidIndex( StartingFrom ) then
 | 
|---|
 | 478 |     exit;
 | 
|---|
 | 479 |   StartP:= _S + StartingFrom;
 | 
|---|
 | 480 |   EndP:= _S + Length;
 | 
|---|
 | 481 |   P:= StartP;
 | 
|---|
 | 482 | 
 | 
|---|
 | 483 |   while P < EndP do
 | 
|---|
 | 484 |   begin
 | 
|---|
 | 485 |     C:= P^;
 | 
|---|
 | 486 |     if C = CharToFind then
 | 
|---|
 | 487 |     begin
 | 
|---|
 | 488 |       Result:= PCharDiff( p, _S );
 | 
|---|
 | 489 |       break;
 | 
|---|
 | 490 |     end;
 | 
|---|
 | 491 |     inc( P );
 | 
|---|
 | 492 |   end;
 | 
|---|
 | 493 | end;
 | 
|---|
 | 494 | 
 | 
|---|
 | 495 | procedure TAString.Delete( const StartingFrom: longint;
 | 
|---|
 | 496 |                            const LengthToDelete: longint );
 | 
|---|
 | 497 | var
 | 
|---|
 | 498 |   StartP: PChar;
 | 
|---|
 | 499 |   EndP: PChar;
 | 
|---|
 | 500 |   SizeToCopy: longint;
 | 
|---|
 | 501 | begin
 | 
|---|
 | 502 |   if not ValidIndex( StartingFrom ) then
 | 
|---|
 | 503 |     exit;
 | 
|---|
 | 504 |   if LengthToDelete = 0 then
 | 
|---|
 | 505 |     exit;
 | 
|---|
 | 506 | 
 | 
|---|
 | 507 |   StartP:= _S + StartingFrom;
 | 
|---|
 | 508 |   if StartingFrom + LengthToDelete >= Length then
 | 
|---|
 | 509 |   begin
 | 
|---|
 | 510 |     SetLength( StartingFrom );
 | 
|---|
 | 511 |     exit;
 | 
|---|
 | 512 |   end;
 | 
|---|
 | 513 |   EndP:= _S + StartingFrom + LengthToDelete;
 | 
|---|
 | 514 |   SizeToCopy:= Length - ( StartingFrom + LengthToDelete );
 | 
|---|
 | 515 |   MemCopy( EndP, StartP, SizeToCopy );
 | 
|---|
 | 516 |   SetLength( Length - LengthToDelete );
 | 
|---|
 | 517 | end;
 | 
|---|
 | 518 | 
 | 
|---|
 | 519 | function TAString.ValidIndex( const Index: longint ): boolean;
 | 
|---|
 | 520 | begin
 | 
|---|
 | 521 |   Result:= ( Index >= 0 ) and ( Index < Length );
 | 
|---|
 | 522 | end;
 | 
|---|
 | 523 | 
 | 
|---|
 | 524 | function TAString.GetAsString: string;
 | 
|---|
 | 525 | begin
 | 
|---|
 | 526 |   CheckValid( self );
 | 
|---|
 | 527 | {$ifdef os2}
 | 
|---|
 | 528 |   Result:= StrPas( _S );
 | 
|---|
 | 529 | {$else}
 | 
|---|
 | 530 |   Result:= _S;
 | 
|---|
 | 531 | {$endif}
 | 
|---|
 | 532 | end;
 | 
|---|
 | 533 | 
 | 
|---|
 | 534 | procedure TAString.SetLength( NewLength: longint );
 | 
|---|
 | 535 | begin
 | 
|---|
 | 536 |   CheckValid( self );
 | 
|---|
 | 537 |   if NewLength < 0 then
 | 
|---|
 | 538 |     exit;
 | 
|---|
 | 539 |   CheckSize( NewLength );
 | 
|---|
 | 540 |   _Length:= NewLength;
 | 
|---|
 | 541 |   _S[ _Length ]:= #0;
 | 
|---|
 | 542 | 
 | 
|---|
 | 543 | end;
 | 
|---|
 | 544 | 
 | 
|---|
 | 545 | procedure TAString.ReadLn( var TheFile: TextFile );
 | 
|---|
 | 546 | Var
 | 
|---|
 | 547 |   C: Char;
 | 
|---|
 | 548 |   FoundCR: boolean;
 | 
|---|
 | 549 | Begin
 | 
|---|
 | 550 |   CheckValid( self );
 | 
|---|
 | 551 |   Clear;
 | 
|---|
 | 552 |   FoundCR:= false;
 | 
|---|
 | 553 |   while not eof( TheFile ) do
 | 
|---|
 | 554 |   begin
 | 
|---|
 | 555 |     Read( TheFile, C );
 | 
|---|
 | 556 |     if ( C = #10 ) then
 | 
|---|
 | 557 |     begin
 | 
|---|
 | 558 |       if FoundCR then
 | 
|---|
 | 559 |         exit; // reached end of line
 | 
|---|
 | 560 |     end
 | 
|---|
 | 561 |     else
 | 
|---|
 | 562 |     begin
 | 
|---|
 | 563 |       if FoundCR then
 | 
|---|
 | 564 |         // last CR was not part of CR/LF so add to string
 | 
|---|
 | 565 |         AddString( #13 );
 | 
|---|
 | 566 |     end;
 | 
|---|
 | 567 |     FoundCR:= ( C = #13 );
 | 
|---|
 | 568 |     if not FoundCR then // don't handle 13's till later
 | 
|---|
 | 569 |     begin
 | 
|---|
 | 570 |       AddString( C );
 | 
|---|
 | 571 |     end;
 | 
|---|
 | 572 |   end;
 | 
|---|
 | 573 | 
 | 
|---|
 | 574 |   if FoundCR then
 | 
|---|
 | 575 |     // CR was last char of file, but no LF so add to string
 | 
|---|
 | 576 |     AddString( #13 );
 | 
|---|
 | 577 | 
 | 
|---|
 | 578 | end;
 | 
|---|
 | 579 | 
 | 
|---|
 | 580 | procedure TAString.WriteLn( var TheFile: TextFile );
 | 
|---|
 | 581 | var
 | 
|---|
 | 582 |   P: PChar;
 | 
|---|
 | 583 |   EndP: PChar;
 | 
|---|
 | 584 |   C: Char;
 | 
|---|
 | 585 | begin
 | 
|---|
 | 586 |   CheckValid( self );
 | 
|---|
 | 587 | 
 | 
|---|
 | 588 |   P:= _S;
 | 
|---|
 | 589 |   EndP:= _S + Length;
 | 
|---|
 | 590 | 
 | 
|---|
 | 591 |   while P < EndP do
 | 
|---|
 | 592 |   begin
 | 
|---|
 | 593 |     C:= P^;
 | 
|---|
 | 594 |     Write( TheFile, C );
 | 
|---|
 | 595 |     inc( P );
 | 
|---|
 | 596 |   end;
 | 
|---|
 | 597 |   Write( TheFile, #13 );
 | 
|---|
 | 598 |   Write( TheFile, #10 );
 | 
|---|
 | 599 | end;
 | 
|---|
 | 600 | 
 | 
|---|
 | 601 | function TAString.GetChar( Index: longint ): Char;
 | 
|---|
 | 602 | begin
 | 
|---|
 | 603 |   CheckValid( self );
 | 
|---|
 | 604 |   CheckIndex( Index );
 | 
|---|
 | 605 |   Result:= _S[ Index ];
 | 
|---|
 | 606 | end;
 | 
|---|
 | 607 | 
 | 
|---|
 | 608 | procedure TAString.SetChar( Index: longint;
 | 
|---|
 | 609 |                             const Value: Char );
 | 
|---|
 | 610 | begin
 | 
|---|
 | 611 |   CheckValid( self );
 | 
|---|
 | 612 |   CheckIndex( Index );
 | 
|---|
 | 613 |   _S[ Index ]:= Value;
 | 
|---|
 | 614 | end;
 | 
|---|
 | 615 | 
 | 
|---|
 | 616 | procedure TAString.CheckIndex( const Index: longint );
 | 
|---|
 | 617 | begin
 | 
|---|
 | 618 |   if not ValidIndex( Index ) then
 | 
|---|
 | 619 |     raise EAStringIndexError( 'Index '
 | 
|---|
 | 620 |                               + IntToStr( Index )
 | 
|---|
 | 621 |                               + ' is not in valid range ( 0 - '
 | 
|---|
 | 622 |                               + IntToStr( Length - 1 )
 | 
|---|
 | 623 |                               + ') for string' );
 | 
|---|
 | 624 | 
 | 
|---|
 | 625 | end;
 | 
|---|
 | 626 | 
 | 
|---|
 | 627 | procedure TAString.ParseKeyValuePair( KeyName: TAString;
 | 
|---|
 | 628 |                                       KeyValue: TAString;
 | 
|---|
 | 629 |                                       Seperator: Char );
 | 
|---|
 | 630 | var
 | 
|---|
 | 631 |   Position: longint;
 | 
|---|
 | 632 | begin
 | 
|---|
 | 633 |   CheckValid( self );
 | 
|---|
 | 634 |   Position:= 0;
 | 
|---|
 | 635 |   ExtractNextValue( Position, KeyName, Seperator );
 | 
|---|
 | 636 |   GetRightFrom( Position, KeyValue );
 | 
|---|
 | 637 | end;
 | 
|---|
 | 638 | 
 | 
|---|
 | 639 | 
 | 
|---|
 | 640 | procedure TAString.GetLeft( const Count: longint;
 | 
|---|
 | 641 |                             Dest: TAString );
 | 
|---|
 | 642 | begin
 | 
|---|
 | 643 |   CheckValid( self );
 | 
|---|
 | 644 |   Dest.Clear;
 | 
|---|
 | 645 |   if Count >= Length then
 | 
|---|
 | 646 |     Dest.Assign( self )
 | 
|---|
 | 647 |   else if Count > 0 then
 | 
|---|
 | 648 |     Dest.AddData( _S, Count );
 | 
|---|
 | 649 | end;
 | 
|---|
 | 650 | 
 | 
|---|
 | 651 | procedure TAString.GetRight( const Count: longint;
 | 
|---|
 | 652 |                              Dest: TAString );
 | 
|---|
 | 653 | begin
 | 
|---|
 | 654 |   CheckValid( self );
 | 
|---|
 | 655 |   Dest.Clear;
 | 
|---|
 | 656 |   if Count >= Length then
 | 
|---|
 | 657 |     Dest.Assign( self )
 | 
|---|
 | 658 |   else if Count > 0 then
 | 
|---|
 | 659 |     Dest.AddData( _S + Length - Count - 1, Count );
 | 
|---|
 | 660 | end;
 | 
|---|
 | 661 | 
 | 
|---|
 | 662 | procedure TAString.GetRightFrom( const StartingFrom: longint;
 | 
|---|
 | 663 |                                  Dest: TAString );
 | 
|---|
 | 664 | begin
 | 
|---|
 | 665 |   CheckValid( self );
 | 
|---|
 | 666 |   Dest.Clear;
 | 
|---|
 | 667 |   if StartingFrom <= 0  then
 | 
|---|
 | 668 |     Dest.Assign( self )
 | 
|---|
 | 669 |   else if StartingFrom < Length then
 | 
|---|
 | 670 |     Dest.AddData( _S + StartingFrom, Length - StartingFrom );
 | 
|---|
 | 671 | end;
 | 
|---|
 | 672 | 
 | 
|---|
 | 673 | {$ifdef os2}
 | 
|---|
 | 674 | function TAString.SameAs( const S: String ): boolean;
 | 
|---|
 | 675 | var
 | 
|---|
 | 676 |   DataCompareResult: integer;
 | 
|---|
 | 677 | begin
 | 
|---|
 | 678 |   CheckValid( self );
 | 
|---|
 | 679 |   if Length <> System.Length( S ) then
 | 
|---|
 | 680 |   begin
 | 
|---|
 | 681 |     // different lengths -> strings are different
 | 
|---|
 | 682 |     result := false;
 | 
|---|
 | 683 |     exit;
 | 
|---|
 | 684 |   end;
 | 
|---|
 | 685 |   // length is same, so compare data, case insensitive
 | 
|---|
 | 686 |   DataCompareResult := StrLIComp( _S,
 | 
|---|
 | 687 |                                   Addr( S ) + 1,
 | 
|---|
 | 688 |                                   Length );
 | 
|---|
 | 689 |   Result := DataCompareResult = 0;
 | 
|---|
 | 690 | end;
 | 
|---|
 | 691 | 
 | 
|---|
 | 692 | // returns true if starts with S
 | 
|---|
 | 693 | function TAString.StartsWith( const S: String ): boolean;
 | 
|---|
 | 694 | var
 | 
|---|
 | 695 |   DataCompareResult: integer;
 | 
|---|
 | 696 | begin
 | 
|---|
 | 697 |   CheckValid( self );
 | 
|---|
 | 698 |   if System.Length( S ) > Length then
 | 
|---|
 | 699 |   begin
 | 
|---|
 | 700 |     // S is longer than us; we can't start with it
 | 
|---|
 | 701 |     result := false;
 | 
|---|
 | 702 |     exit;
 | 
|---|
 | 703 |   end;
 | 
|---|
 | 704 |   // compare data, case insensitive
 | 
|---|
 | 705 |   DataCompareResult := StrLIComp( _S,
 | 
|---|
 | 706 |                                   Addr( S ) + 1,
 | 
|---|
 | 707 |                                   System.Length( S ) );
 | 
|---|
 | 708 |   Result := DataCompareResult = 0;
 | 
|---|
 | 709 | end;
 | 
|---|
 | 710 | 
 | 
|---|
 | 711 | {$else} // win32
 | 
|---|
 | 712 | 
 | 
|---|
 | 713 | // returns true if starts with S
 | 
|---|
 | 714 | function TAString.StartsWith( const S: String ): boolean;
 | 
|---|
 | 715 | var
 | 
|---|
 | 716 |   DataCompareResult: integer;
 | 
|---|
 | 717 | begin
 | 
|---|
 | 718 |   CheckValid( self );
 | 
|---|
 | 719 |   if System.Length( S ) > Length then
 | 
|---|
 | 720 |   begin
 | 
|---|
 | 721 |     // S is longer than us; we can't start with it
 | 
|---|
 | 722 |     result := false;
 | 
|---|
 | 723 |     exit;
 | 
|---|
 | 724 |   end;
 | 
|---|
 | 725 |   // compare data, case insensitive
 | 
|---|
 | 726 |   DataCompareResult := StrLIComp( _S,
 | 
|---|
 | 727 |                                   PChar(s),
 | 
|---|
 | 728 |                                   System.Length( S ) );
 | 
|---|
 | 729 |   Result := DataCompareResult = 0;
 | 
|---|
 | 730 | end;
 | 
|---|
 | 731 | 
 | 
|---|
 | 732 | function TAString.SameAs( const S: String ): boolean;
 | 
|---|
 | 733 | begin
 | 
|---|
 | 734 |   CheckValid( self );
 | 
|---|
 | 735 |   Result:= StrIComp( _S, PChar( S ) ) = 0;
 | 
|---|
 | 736 | end;
 | 
|---|
 | 737 | {$endif}
 | 
|---|
 | 738 | 
 | 
|---|
 | 739 | function TAString.GetIsEmpty: boolean;
 | 
|---|
 | 740 | begin
 | 
|---|
 | 741 |   CheckValid( self );
 | 
|---|
 | 742 |   Result:= Length = 0;
 | 
|---|
 | 743 | end;
 | 
|---|
 | 744 | 
 | 
|---|
 | 745 | procedure TAString.Trim;
 | 
|---|
 | 746 | begin
 | 
|---|
 | 747 |   CheckValid( self );
 | 
|---|
 | 748 |   TrimChar( #32 );
 | 
|---|
 | 749 | end;
 | 
|---|
 | 750 | 
 | 
|---|
 | 751 | procedure TAString.SetMaxLength( MaxLength: longint );
 | 
|---|
 | 752 | begin
 | 
|---|
 | 753 |   CheckValid( self );
 | 
|---|
 | 754 |   CheckSize( MaxLength );
 | 
|---|
 | 755 | end;
 | 
|---|
 | 756 | 
 | 
|---|
 | 757 | procedure TAString.AddPCharLen( const S: PChar; const Len: longint );
 | 
|---|
 | 758 | begin
 | 
|---|
 | 759 |   CheckValid( self );
 | 
|---|
 | 760 |   AddData( S, Len );
 | 
|---|
 | 761 | end;
 | 
|---|
 | 762 | 
 | 
|---|
 | 763 | Procedure TAString.Insert( const InsertPoint: longword;
 | 
|---|
 | 764 |                            const S: TAString );
 | 
|---|
 | 765 | begin
 | 
|---|
 | 766 |   CheckValid( self );
 | 
|---|
 | 767 |   InsertData( S._S,
 | 
|---|
 | 768 |               InsertPoint,
 | 
|---|
 | 769 |               S._Length );
 | 
|---|
 | 770 | end;
 | 
|---|
 | 771 | 
 | 
|---|
 | 772 | Procedure TAString.InsertString( const InsertPoint: longword;
 | 
|---|
 | 773 |                                  const S: string );
 | 
|---|
 | 774 | begin
 | 
|---|
 | 775 |   CheckValid( self );
 | 
|---|
 | 776 | {$ifdef os2}
 | 
|---|
 | 777 |   InsertData( Addr( S ) + 1,
 | 
|---|
 | 778 |               InsertPoint,
 | 
|---|
 | 779 |               System.Length( S ) );
 | 
|---|
 | 780 | {$else}
 | 
|---|
 | 781 |   InsertData( PChar( S ),
 | 
|---|
 | 782 |               InsertPoint,
 | 
|---|
 | 783 |               System.Length( S ) );
 | 
|---|
 | 784 | {$endif}
 | 
|---|
 | 785 | end;
 | 
|---|
 | 786 | 
 | 
|---|
 | 787 | {$Ifdef os2}
 | 
|---|
 | 788 | function TAString.ReadParagraph( F: HFile ): boolean;
 | 
|---|
 | 789 | var
 | 
|---|
 | 790 |   C: Char;
 | 
|---|
 | 791 |   NewFilePtr: ULONG;
 | 
|---|
 | 792 | begin
 | 
|---|
 | 793 |   Clear;
 | 
|---|
 | 794 | 
 | 
|---|
 | 795 |   Result:= MyRead( F, Addr( C ), 1 );
 | 
|---|
 | 796 |   while     ( C <> #13 )
 | 
|---|
 | 797 |         and Result do
 | 
|---|
 | 798 |   begin
 | 
|---|
 | 799 |     AddChar( C );
 | 
|---|
 | 800 |     Result:= MyRead( F, Addr( C ), 1 );
 | 
|---|
 | 801 |   end;
 | 
|---|
 | 802 | 
 | 
|---|
 | 803 |   if not Result then
 | 
|---|
 | 804 |     exit;
 | 
|---|
 | 805 | 
 | 
|---|
 | 806 |   // skip #10 if found
 | 
|---|
 | 807 |   Result:= MyRead( F, Addr( C ), 1 );
 | 
|---|
 | 808 |   if Result then
 | 
|---|
 | 809 |     if C <> #10 then
 | 
|---|
 | 810 |       DosSetFilePtr( F, -1, FILE_CURRENT, NewFilePtr );
 | 
|---|
 | 811 | end;
 | 
|---|
 | 812 | {$endif}
 | 
|---|
 | 813 | 
 | 
|---|
 | 814 | // updates length based on terminator, use after writing to as pchar
 | 
|---|
 | 815 | Procedure TAString.UpdateLength;
 | 
|---|
 | 816 | begin
 | 
|---|
 | 817 |   SetLength( StrLen( _S ) );
 | 
|---|
 | 818 | end;
 | 
|---|
 | 819 | 
 | 
|---|
 | 820 | Initialization
 | 
|---|
 | 821 | End.
 | 
|---|