LibDoc documentation for C:\DEV\D2006\LogicLib\Release\LogicLib.dpk Created 8/29/2010 1:22:42 PM -------------------------------------------------------------------------------- function AnyChecked(Lbx: TCheckListBox): Boolean; Returns True if any of the items in the TCheckListBox are checked. llControls.pas -------------------------------------------------------------------------------- procedure CheckListChange(Lbx: TCheckListBox; const AChange: String); Updates the check marks in a TCheckListBox depending on AChange: 'A' = All 'N' = None (default when AChange <> A or R) 'R' = Reverse llControls.pas -------------------------------------------------------------------------------- function GetItemObjectInt(Ctl: TComboBox): Integer; overload; function GetItemObjectInt(Ctl: TListBox): Integer; overload; function GetItemObjectInt(Ctl: TCheckListBox): Integer; overload; Gets an integer object value from the currently selected item in a combobox, listbox, or checklistbox. If no item is currently selected the function will return -1. Unassigned objects (nil) become zero when cast as integers. llControls.pas -------------------------------------------------------------------------------- procedure SetItemIndex(Ctl: TComboBox; const AValue: String; const ADefault: Integer = -1); overload; procedure SetItemIndex(Ctl: TListBox; const AValue: String; const ADefault: Integer = -1); overload; procedure SetItemIndex(Ctl: TCheckListBox; const AValue: String; const ADefault: Integer = -1); overload; Finds a string value in a combobox/listbox/checklistbox Items property and sets the ItemIndex to that value, or to ADefault if not found. Uses IndexOfPartial to find partial matches. llControls.pas -------------------------------------------------------------------------------- function ParseCSVLine(const ALine: String; Fields: TStrings; var MultiLine: Boolean; const EatWhitespace: Boolean = False; const AQuote: Char = '"'; const ADelim: Char = ','; const ANewline: String = #10): Boolean; Parses a string of CSV-formatted text into individual fields and places them into a TStrings list. Unlike TStringList.CommmaText/DelimitedText*, it only recognizes a single delimiter character and will not break unquoted fields that contain spaces or tabs. It can also handle fields that span multiple lines. *As of BDS2006, TStrings has a StrictDelimiter property to ignore all but the specified delimiter character. --- Returns: A boolean indicating if ALine contained properly formatted CSV data. Currently, only improperly quoted fields will trigger a False result. --- Arguments: ALine - A line of text from a CSV file. Fields - A TStrings/TStringlist object to hold the parsed fields. MultiLine - A var parameter that gets set to True when the procedure needs the next line from the CSV file to continue the current field/record. EatWhitespace - A boolean to determine behavior with regards to unquoted whitespace. If False (the default), unquoted whitespace is preserved. If True, this whitespace is discarded. Quoted whitespace is always preserved, while whitespace between quoted fields and delimiters/EOL is always discarded. Examples: Given the following input: ' aaa, bbb , "ccc" , " d " ' EatWhitespace | Input is parsed equivalent to... ---------------+---------------------------------- False | '" aaa"," bbb ","ccc"," d "' True | '"aaa","bbb","ccc"," d "' AQuote - The text quote character. Default=double quote (") ADelim - The field delimiter character. Default=comma (,) ANewline - The character(s) to be used in place of the actual end-of-line characters (i.e. #13#10) when storing multiline fields in the Fields stringlist. Default=#10 --- Usage: Initially, call the procedure with MultiLine set to False. The Fields list will be cleared and the line parsed according to the other options. If the function encounters a quoted field that is continued on the next line it will set MultiLine to True and return. The caller should then call the procedure again, passing the next line from the CSV file with MultiLine still set to True. The parsing of the record will continue where it left off, adding to the Fields list. MultiLine will be set to False when it finds the end of the record. When the field list contains multiline fields, the ANewline character(s) will be inserted in place of the actual end-of-line characters (usually #13#10 aka CRLF). Select a character or characters that won't get confused with the rest of the data and won't cause Fields.Count to be erroneously increased. It can be as simple as #10 or as wacky as a dozen alternating tildes & underscores. The caller can then replace this value with the desired line terminator using something like this: Memo.Text := StringReplace(Fields[x], ANewLine, #13#10, [rfReplaceAll]); --- See Also: The CSV RFC: http://www.ietf.org/rfc/rfc4180.txt llCSV.pas -------------------------------------------------------------------------------- function SimpleCSV(const ALine: string; Fields: TStrings): Boolean; This is a simplified wrapper to ParseCSVLine. You need not provide a boolean MultiLine variable and EatWhitespace is set to True. The quote and delimiter characters are taken directly from Fields.QuoteChar and Fields.Delimiter. The function just returns the value returned by ParseCSVLine, but will also return False if MultiLine got set to True, indicating that you're not working with simple, single-line CSV data. llCSV.pas -------------------------------------------------------------------------------- procedure CloneDataset(ASource: TDataset; ATarget: TClientDataSet; const AFieldDefsOnly: Boolean = False); Copies the field defnitions and optionally the data from a TDataSet descendant into a TClientDataSet. The data is copied from the current position in the source dataset until Eof, in case the source is using a forward-only cursor. Pre-position the source dataset using First if you want all of the data copied. The ClientDataSet has LogChanges set to False upon return from this, so if you want to use the change log, turn that back on afterwards. llDatabase.pas -------------------------------------------------------------------------------- procedure CopyRecord(ASource, ATarget: TDataSet); Copies the data in like-named fields from one TDataSet to another. The data types of the fields are assumed to be compatible. The caller is responsible for setting up the Append/Edit beforehand and the call to Post after. llDatabase.pas -------------------------------------------------------------------------------- function AgeOnDate(const ADOB, ADate: TDateTime): Integer; Returns a person's age on a given date as an integer number of years. llDates.pas -------------------------------------------------------------------------------- function AssumeCentury(const y: Integer): Integer; Given a two-digit year, use TwoDigitYearCenturyWindow to assume a century and return the adjusted year value using the logic as described in the help. TODO: An overloaded version that takes a TFormatSettings parameter? llDates.pas -------------------------------------------------------------------------------- function DateMath(const ADate: TDateTime; const y, m, d, h, n, s, z: Integer): TDateTime; Allows you to manipulate a date by applying positive or negative values to any of the parts in any combination and returns the new TDateTime value. The calculations are applied smallest to largest (milliseconds up to years). If the finally calculated date has an invalid number of days (i.e. Feb 29 in a non-leap year, Dec 31 minus one month, etc.) the days of the month will be truncated. Examples: DateMath(<2009-12-31 23:59:59.900>, 0, 0, 3, 0, 0, 0, 500) -> <2010-01-04 00:00:00.400> DateMath(<2009-12-31 00:00:00.000>, 0, -1, 0, 4, 0, 0, 0) -> <2009-11-30 04:00:00.000> llDates.pas -------------------------------------------------------------------------------- function DateTrunc(const ADate: TDateTime; const P: TDateTimePrecision): TDateTime; Truncates a date at a certain precision, similar to the PostgreSQL function called "date_trunc". Examples where ADate is 1995-10-15 09:45:30.500: DateTrunc(ADate, dtpMinute) -> 1995-10-15 09:45:00.000 DateTrunc(ADate, dtpMonth) -> 1995-10-01 00:00:00.000 DateTrunc(ADate, dtpDecade) -> 1990-01-01 00:00:00.000 llDates.pas -------------------------------------------------------------------------------- function DtoS(const DT: TDateTime; const P: TDateTimePrecision = dtpDay): String; "Date to String" - Formats a TDateTime value as a string in a 'yyyymmddhhnnsszzz' format. This locale-netural format is handy for storage or transmission and naturally lends itself to sorting. The optional TDateTimePrecision argument will determine the length of the returned string and defaults to dtpDay, or 'yyyymmdd'. Precisions lower than dtpYear are ignored. The smallest supported return value is 'yyyy'. The inverse of DtoS is the StoD function. llDates.pas -------------------------------------------------------------------------------- function EndOfDay(const DT: TDateTime): TDateTime; Returns the very last possible instant of the given day. This is useful for date range queries like " BETWEEN :Start AND :End", where :Start would be Trunc(DT) and :End would be EndOfDay(DT) (however, I find it's usually better to say " >= :Start and < :End" where End is midnight on the day AFTER the range end). llDates.pas -------------------------------------------------------------------------------- function FirstOfMonth(const ADate: TDateTime): TDateTime; Returns the TDateTime argument adjusted to the first of the given month. llDates.pas -------------------------------------------------------------------------------- function IntervalStr(const AInterval: TDateTime; const LoP: TDateTimePrecision = dtpHour; const HiP: TDateTimePrecision = dtpSecond): String; Returns the time interval between two datetime values as a string. AInterval would normally be the result of subtracting a start time from an end time. The format of the string depends on the LoP and HiP TDateTimePrecision values ("LowPrecision" and "HighPrecision", respectively). These default to dtpHours and dtpSeconds accordingly, which will return a format of "hh:nn:ss". If LoP is dtpDay the format will have the number of days and the letter 'd' prepended, e.g. "1d04:13:22". Otherwise, the hour value will be as large as it needs to be, e.g. "48:56:13". If HiP is dtpMillisecond, the format will have the milliseconds added as a decimal fraction of the seconds like "04:13:22.377" If LoP is less than dtpDay, the format will be the same as if LoP were dtpHour, but with any insignificant leading zeros removed. For example, "00:00:00.123" would become "0.123", "00:05:13" -> "5:13", etc. llDates.pas -------------------------------------------------------------------------------- function LastDOM(const ADate: TDateTime): Integer; Returns the integer last day of the month for the given date. Example: LastDOM(<2005-01-16>) -> 31 Overloaded: LastDOM(const AMonth: Integer; const AYear: Integer) llDates.pas -------------------------------------------------------------------------------- function LastDOM(const AMonth: Integer; const AYear: Integer = 0): Integer; Returns the integer last day of the given month and year. The current year is used for leap year logic if not provided. Examples: LastDOM(9) -> 30 LastDOM(2, 2004) -> 29 Overloaded: LastDOM(const ADate: TDateTime) llDates.pas -------------------------------------------------------------------------------- function LastOfMonth(const ADate: TDateTime): TDateTime; Returns the TDateTime argument adjusted to the last day of the given month. llDates.pas -------------------------------------------------------------------------------- function LocalUTCOffset: TDateTime; Get the local UTC offset from Windows using GetTimeZoneInformation. Add this value to a local time in order to convert it to UTC time. Raises an exception if GetTimeZoneInformation returns TIME_ZONE_ID_INVALID. llDates.pas -------------------------------------------------------------------------------- function MonthDiff(const AStart, AEnd: TDateTime): Currency; Calculates the difference between two dates in calendar months. A partial calendar month becomes a fraction in the form of # days divided by the total number of days in the month. For example: 2005-01-01 to 2005-02-10 = 1.3571 -> 1.0 for January plus 0.3571 for 10 out of 28 days in February. llDates.pas -------------------------------------------------------------------------------- function MonthStrToInt(const AMonth: string): Integer; Returns the integer month number 1..12 of the given month string. It works with full month names or their abbreviations as defined by the ShortMonthNames variable. It returns zero if the string is not valid. Case-insensitive. Example: MonthStrToInt('January') -> 1 llDates.pas -------------------------------------------------------------------------------- function NextMonthDay(const ADate: TDateTime; const ADay: Integer): TDateTime; Returns a TDateTime representing the given date adjusted to the nearest future date matching the desired day of the month. Examples: NextMonthDay(<2004-05-15>, 20) -> <2004-05-20> NextMonthDay(<2004-05-15>, 15) -> <2004-06-15> If the desired day would result in an invalid date, the last valid day of the month will be used: Examples: NextMonthDay(<2004-04-01>, 31) -> <2004-04-30> NextMonthDay(<2004-08-31>, 31) -> <2004-09-30> See also: PrevMonthDay, ValidMonthDay llDates.pas -------------------------------------------------------------------------------- function PrevMonthDay(const ADate: TDateTime; const ADay: Integer): TDateTime; Returns a TDateTime representing the given date adjusted to the nearest past date matching the desired day of the month, the opposite of NextMonthDay(). Examples: PrevMonthDay(<2004-05-15>, 15) -> <2004-04-15> PrevMonthDay(<2004-05-31>, 31) -> <2004-04-30> See also: ValidMonthDay llDates.pas -------------------------------------------------------------------------------- function ReplaceDateTokens(const APattern: string; const ADate: TDateTime): string; Replaces parameters in a string with values from the given date/time. Especially handy for date-based filenames. Numeric Replacements: %Y=Year, 4-digit %y=Year, 2-digit %m=Month, 01..12 %d=Day, 01..31 %H=Hour, 01..12 %h=Hour, 00..23 %n=Minute, 00..59 %s=Second, 00..59 %z=Millisecond, 000..999 %q=Quarter, 1..4 %w=Week#, 01..53 %X=Year that goes with week#, 4-digit %x=Year that goes with week#, 2-digit %D=Day of the year (001..366) %k=Day of the week (1..7) String replacements: %K=Day of the week (SUN..SAT) %M=Month, short (JAN..DEC) %P=AM/PM %p=a/p llDates.pas -------------------------------------------------------------------------------- function StoD(const DS: String): TDateTime; "String to Date" - Converts a string in 'yyyymmddhhnnsszzz' format, or a subset thereof (see DtoS) to a TDateTime. Input strings shorter than the length of the full format will have their missing values defaulted appropriately: 1 for month or day, and zero for time values. Invalid input will raise an EConvertError exception. See StoDDef and TryStoD for additional options when dealing with untrusted input. llDates.pas -------------------------------------------------------------------------------- function StoDDef(const DS: String; const ADefault: TDateTime): TDateTime; StoDDef is to StoD as StrToIntDef is to StrToInt. See also: DtoS, StoD, TryStoD llDates.pas -------------------------------------------------------------------------------- function StoT(const TS: String): TDateTime; "String to Time" - Converts a time string in 'hhnnsszzz' format, or a subset thereof (see TtoS) to a TDateTime. Input strings shorter than the length of the full format will have their missing values defaulted to zero. Invalid input will raise an EConvertError exception. See StoTDef and TryStoT for additional options when dealing with untrusted input. llDates.pas -------------------------------------------------------------------------------- function StoTDef(const TS: String; const ADefault: TDateTime): TDateTime; StoTDef is to StoT as StrToIntDef is to StrToInt. See also: TtoS, StoT, TryStoT llDates.pas -------------------------------------------------------------------------------- type TDateTimePrecision = (dtpMillennium, dtpCentury, dtpDecade, dtpYear, dtpMonth, dtpDay, dtpHour, dtpMinute, dtpSecond, dtpMillisecond, dtpMSec = 9); The TDateTimePrecision enumeration is used by various functions in the llDates unit. The dtpMillisecond and dtpMSec values are synonyms. llDates.pas -------------------------------------------------------------------------------- type TDayOfTheWeek = (dowAnyDay, dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday); llDates.pas -------------------------------------------------------------------------------- function TimeZoneStr(const LocalOffset: TDateTime): string; Converts a local UTC offset TDateTime into a string in '+/-HH:NN' format. The string is suitable for concatenation to an ISO8601 date/time string. llDates.pas -------------------------------------------------------------------------------- function TryAnyStrToDateTime(const DS: string; var DayPos: Integer; out OutDate: TDateTime): Boolean; Works like TryStrToDateTime, but does its best to decipher formats other than the current locale formats (which it tries first). It also handles non- numeric months (see MonthStrToInt) and DtoS-type strings (StoD). The DayPos argument is used to help interpret ambiguous dates where both the month and day values are <= 12. DayPos can be set to -1..3 and behaves according to the following table: -1 Tries the current locale format first, then uses the default behavior of using the first value <= 12 as the month. DayPos will not be modified by the function. 0 Like -1, but allows itself to be updated to 1-3 if a non-ambiguous date is encountered, so that the "learned" format can be used on future calls. 1-3 Uses the number to choose the first, second or third part of the date as the day value when it otherwise can't tell the month and day apart. When DayPos is > 0, the function does not try the current locale format first. Requires DateUtils, so D6+ only. llDates.pas -------------------------------------------------------------------------------- function TryFormatToDateTime(const DS, AFormat: string; out OutDate: TDateTime): Boolean; Works like TryStrToDateTime, but uses a date/time format string so it knows how to parse the string. Shorthand formats like "c" and "tt" are interpreted correctly, as are "m"s that follow "h"s. Note: The format MUST include separators or whitespace between date and time elements. Mashed-together formats like "yyyymmdd" will NOT work! Example: TryFormatToDateTime('06/30/2007 2:21 PM', 'mm/dd/yyyy h:nn ampm', D) Requires DateUtils, so D6+ only. TODO: It doesn't currently handle single- or double-quoted literals. llDates.pas -------------------------------------------------------------------------------- function TryStoD(const DS: String; out ADate: TDateTime): Boolean; TryStoD is to StoD as TryStrToInt is to StrToInt. See also: DtoS, StoD, StoDDef llDates.pas -------------------------------------------------------------------------------- function TryStoT(const TS: String; out ATime: TDateTime): Boolean; TryStoT is to StoT as TryStrToInt is to StrToInt. See also: DtoT, StoT, StoTDef llDates.pas -------------------------------------------------------------------------------- function TtoS(const DT: TDateTIme; const P: TDateTimePrecision = dtpSecond): String; "Time to String" - Works much like DtoS, but on a time value only with a 'hhnnsszzz' format. Precisions lower than dtpHour are ignored. The inverse function is StoT. llDates.pas -------------------------------------------------------------------------------- function ValidMonthDay(const ADate, ADay: Integer): Boolean; Returns True if the given date is valid for the specified day of the montn. If ADay is greater than the number of days in the given month, the function will return True if the date is the last day of its month. Examples: ValidMonthDay(<2008-09-24>, 15) -> False ValidMonthDay(<2008-09-24>, 24) -> True ValidMonthDay(<2008-09-30>, 31) -> True See Also: NextMonthDay, PrevMonthDay llDates.pas -------------------------------------------------------------------------------- function WeekDayDiff(const AStart, AEnd: TDateTime): Integer; Calculates the difference between two dates in weekdays. If the last day is not a weekday it doesn't count, for example Wednesday to Saturday = 2 (w-th, th-f) llDates.pas -------------------------------------------------------------------------------- function WeekdayOfMonth(const ADate: TDateTime; const Nth: Integer; const DOW: TDayOfTheWeek): TDateTime; Returns the date that falls on the Nth weekday of the given month. is the TDateTime that contains the month & year you wish the result to fall in. specifies which instance of the day of the week you wish to find, such as first, second, etc. If this value is greater than the actual number of times the weekday occurs in the month, the last occurrence will be returned. is the day of the week you wish to find. If dowAnyDay is given, the day of the week will be taken from the current value of ADate. Example: To find the second Sunday in the month of February 2005: WeekdayOfMonth(<2005-02-25>, 2, dowSunday) -> <2005-02-13> llDates.pas -------------------------------------------------------------------------------- function A85Decode(const S: string): string; Decodes an ASCII85 encoded string. Null input = null output. Handles data with or without the surrounding ASCII85Prefix/Suffix strings. Raises an EConvertError exception if invalid input is encountered. llEncoding.pas -------------------------------------------------------------------------------- function A85Encode(const S: string; const Bookends: Boolean): string; ASCII85 encodes a string. Set Bookends to True to have the ASCII85Prefix and ASCII85Suffix surround the output, False to leave them off (you can use the constants later). Null input = null output (plus Bookends, if requested). llEncoding.pas -------------------------------------------------------------------------------- function B16Decode(const S: string): string; Decodes a Base16 (hex) encoded string. Null input = null output. Raises an EConvertError exception on bad input. Base16Table has no effect on this function - it will correctly handle either upper- or lower-case letters A..F. llEncoding.pas -------------------------------------------------------------------------------- function B16Encode(const S: string): string; Base16 (Hex) encodes a string. Null input = null output. Set the Base16Table variable if you want an encoding alphabet other than the one defined by the Base16Default constant, which uses upper case letters. When working with PChars/Buffers, use BinToHex. llEncoding.pas -------------------------------------------------------------------------------- function B32Decode(const S: string): string; Base32 decodes a string. Null input = null output. Raises an EConvertError exception if invalid input is encountered. Set the Base32Table variable if you need an encoding alphabet different than that defined by the Base32Default constant. The 33rd character in the string is the padding character. llEncoding.pas -------------------------------------------------------------------------------- function B32Encode(const S: string): string; Base32 encodes a string. Null input = null output. Set the Base32Table variable if you need an encoding alphabet different than that defined by the Base32Default constant. The 33rd character in the string is the padding character. llEncoding.pas -------------------------------------------------------------------------------- function B64Decode(const S: String): String; Base64 decodes a string. Null input = null output. Raises an EConvertError exception if invalid input is encountered. Set the Base64Table variable if you need an encoding alphabet different than that defined by the Base64Default constant. The 65th character in the string is the padding character. llEncoding.pas -------------------------------------------------------------------------------- function B64Encode(const S: String): String; Base64 encodes a string. Null input = null output. Set the Base64Table variable if you need an encoding alphabet different than that defined by the Base64Default constant. The 65th character in the string is the padding character. llEncoding.pas -------------------------------------------------------------------------------- function DecodeString(const S: string; const Encoding: TllEncoding): string; Decodes a string using one of the encoding methods enumerated in TllEncoding. Example: DecodeString('414243', encBase16) -> 'ABC' llEncoding.pas -------------------------------------------------------------------------------- function EncodeString(const S: string; const Encoding: TllEncoding): string; Encodes a string using one of the encoding methods enumerated in TllEncoding. Example: EncodeString('ABC', Base16) -> '414243' llEncoding.pas -------------------------------------------------------------------------------- function HexCharToInt(const C: Char): Integer; Returns a value 0..15 for a valid hex character, or -1 otherwise. Case insensitive. llEncoding.pas -------------------------------------------------------------------------------- function IsValidHex(const S: string): Boolean; Returns True if the string in question contains only an even number of valid hex characters. Case insensitive. A null string returns True. If you need to check just a single character, use HexCharToInt. Written in response to HexToBin's failure (D5) to properly notify the caller of bad input. HexToBin returns a number > 0 *only* if it encounters any characters outside the range of '0'..'f'. That range still includes plenty of invalid characters (like G..Z, colon, underscore, etc.). When one of these is encountered, the value of those four bits is arbitrarily set to 15 (-1). You get junk data and no indication of a problem! See B16Decode for a string-based version of HexToBin. llEncoding.pas -------------------------------------------------------------------------------- function RotX(const S: string; const ARot: Integer = 13): string; Rotates the 7-bit letters in a string by a given number of characters. The number defaults to 13, for the common "ROT13" usage. llEncoding.pas -------------------------------------------------------------------------------- TARC4 = class(TObject) public constructor Create; overload; constructor Create(const AKey: string; const ADrop: Integer = 0); overload; property Drop: Integer read FDrop write SetDrop; procedure Reset(const AKey: string); function NextByte: Byte; end; TARC4 is an implementation of an RC4 stream cipher. After having been seeded with a key upon creation or using the Reset method, pseudo-random bytes are output (the same ones each time) using the NextByte method for use as the key for XOR-based encryption. The XCrypt function demonstrates its use. A known weakness of RC4 is that the first few bytes are "strongly non-random". This can be mitigated by discarding the initial portion of the stream, much like burn cards in blackjack. From Wikipedia: "Such a modified algorithm is traditionally called "RC4-drop[n]", where n is the number of initial keystream bytes that are dropped. The SCAN default is n = 768 bytes, but a conservative value would be n = 3072 bytes." The Drop property implements this feature. llEncoding.pas -------------------------------------------------------------------------------- type TllEncoding = (encNone, encBase16, encHex = 1, encBase32, encBase64, encASCII85); This enumeration is used by the EncodeString and DecodeString functions found in the llEncoding unit. The encBase16 and encHex values are synonyms. llEncoding.pas -------------------------------------------------------------------------------- function X16Decrypt(const sKey, sData: string): string; deprecated; Simply a combination of XCrypt(sKey, B16Decode(sData)); Deprecated - use XDecodeString instead. llEncoding.pas -------------------------------------------------------------------------------- function X16Encrypt(const sKey, sData: string): string; deprecated; Simply a combination of B16Encode(XCrypt(sKey, sData)); Deprecated - use XEncodeString instead. llEncoding.pas -------------------------------------------------------------------------------- function X32Decrypt(const sKey, sData: string): string; deprecated; Simply a combination of XCrypt(sKey, B32Decode(sData)); Deprecated - use XDecodeString instead. llEncoding.pas -------------------------------------------------------------------------------- function X32Encrypt(const sKey, sData: String): String; deprecated; Simply a combination of B32Encode(XCrypt(sKey, sData)); Deprecated - use XEncodeString instead. llEncoding.pas -------------------------------------------------------------------------------- function X64Decrypt(const sKey, sData: String): String; deprecated; Simply a combination of XCrypt(sKey, B64Decode(sData)); Deprecated - use XDecodeString instead. llEncoding.pas -------------------------------------------------------------------------------- function X64Encrypt(const sKey, sData: string): string; deprecated; Simply a combination of B64Encode(XCrypt(sKey, sData)); Deprecated - use XEncodeString instead. llEncoding.pas -------------------------------------------------------------------------------- function XCrypt(const AKey, AData: string; const ARC4Drop: Integer = -1): string; Simple XOR "encryption". The same function decrypts the data as well. If ARC4Drop is zero or more, the key and drop value are used to initialize the RC4 stream cipher that generates the bytes used for the XOR encryption. If ARC4Drop is negative, the encryption is performed using only the bytes in the key, repeated over and over. llEncoding.pas -------------------------------------------------------------------------------- function XDecodeString(const AKey, AData: string; const ARC4Drop: Integer = -1; const Encoding: TllEncoding = encBase64): string; An easy-to-use combination of XCrypt and DecodeString. The data is decoded using the specified encoding method, then unencrypted using the provided key and ARC4 option. llEncoding.pas -------------------------------------------------------------------------------- function XEncodeString(const AKey, AData: string; const ARC4Drop: Integer = -1; const Encoding: TllEncoding = encBase64): string; An easy-to-use combination of XCrypt and EncodeString. The data is encrypted using the given key and ARC4 option then encoded using one of the TllEncoding methods. llEncoding.pas -------------------------------------------------------------------------------- function AddSlash(const APath: string): string; Just a shorter way to write IncludeTrailingPathDelimiter (or IncludeTrailingBackslash in D5). llFiles.pas -------------------------------------------------------------------------------- function AttributeStr(const Attr: Integer; const AFormat: string = 'ADHRS'): string; Turns a file attribute integer (TSearchRec.Attr) into a string of letters indicating the attributes present. The order, case and positioning of the letters are determined by the AFormat argument. If AFormat has a 6th character, it is used as a placeholder in the output for missing attributes, resulting in a fixed-length return value. The first five characters of AFormat MUST be the letters 'ADHRS' in any order. Examples (where Attr is faArchive + faReadOnly): AttributeStr(Attr) -> 'AR' AttributeStr(Attr, 'adhrs ') -> 'a r ' AttributeStr(Attr, 'DHRSA-') -> '--R-A' See also: StrToAttribute llFiles.pas -------------------------------------------------------------------------------- function ExtractFileExtNoDot(const AFile: string): string; Just like ExtractFileExt, but removes the leading dot if present. llFiles.pas -------------------------------------------------------------------------------- function FFDate(const AFile: string; const Attr: Integer = 0): TDateTime; Retrieves a file's date/time from FindFirst. Returns zero if not found. Supply Attr if you need to find hidden files, etc. If you use a wildcard instead of a single filename, the date of the newest file will be returned. llFiles.pas -------------------------------------------------------------------------------- function FFSize(const AFile: string; const Attr: Integer = 0): Integer; Unlike the FileSize function that requires a handle to an open file, this one just gets it from the directory entry using FindFirst. Supply Attr if you need to find hidden files, etc. Works for a single filename or a wildcard, returning the sum of the files' sizes. Returns the size of the file(s) in bytes or -1 if not found. llFiles.pas -------------------------------------------------------------------------------- function FFSize64(const AFile: string; const Attr: Integer = 0): Int64; Just like FFSize, but returns an Int64 instead of an Integer for big files. llFiles.pas -------------------------------------------------------------------------------- function FileSizeStr(const ASize: Int64; const ADecimals: Integer = 1; const AKilo: Integer = 1024): string; Turns a file size into a "friendly" string in one of these formats: 999 B 999 KB 999[.9] MB 999[.9] GB The number of decimal places on MB & GB values is determined by ADecimals. By default, a kilobyte is 1024 bytes, a MB is 1024 KB, etc. You can change this to 1000 by assigning a new value to AKilo. llFiles.pas -------------------------------------------------------------------------------- function FixFilePath(const AFile, APath: string): string; Expands a filename based on the fully qualified path provided. Essentially, it's just like Expand[UNC]FileName, but you don't need to worry about whether it's UNC or not, and it accepts a specific path rather than expanding based on the current directory. Examples: FixFilePath('..\foo.pas', 'c:\dev\project\') -> 'c:\dev\foo.pas' FixFilePath('foo.pas', '\\ray\shared') -> \\ray\shared\foo.pas' llFiles.pas -------------------------------------------------------------------------------- procedure ListFiles(FileList: TStrings; const Path: string; const Attr: Integer = 0; const IncludePath: Boolean = False); Adds filenames to a TStrings/TStringList list. The and arguments determine what files are added to the list and equate to the FindFirst arguments of the same name. If is negative, only files that match the attribute mask will be added to the list. For example, to include both normal and hidden files, use faHidden. To list directories only, use -faDirectory. By default the filenames are added to the list without modification. If IncludePath is True, Path (less the wildcard) will be prepended to the names. llFiles.pas -------------------------------------------------------------------------------- procedure ShortenLogFile(const AFile: string; const AMaxBytes: Integer; const APercentKept: Integer = 75); If the given text file is greater than AMaxBytes in size, the file is opened and the oldest lines are removed to make room for newer log entries. The final size will be the requested percentage of AMaxBytes. Selecting a value less than 100% is advised to reduce how often the file needs to be shortened. A few extra bytes may be removed (up to the next CRLF) to ensure that the log doesn't start with a partial line. This function assumes Ansi/ASCII text (1 char=1 byte) and sizes < 2 GB. llFiles.pas -------------------------------------------------------------------------------- function SlashPath(const APath: string; const ASlash: Boolean): string; Calls AddSlash/StripSlash based on a True/False value, respectively. llFiles.pas -------------------------------------------------------------------------------- function StripExt(const AFile: string): string; Just an easy-to-type wrapper for ChangeFileExt(AFilename, ''); llFiles.pas -------------------------------------------------------------------------------- function StripSlash(const APath: string): string; Just a shorter way to write ExcludeTrailingPathDelimiter (or ExcludeTrailingBackslash in D5). llFiles.pas -------------------------------------------------------------------------------- function StrToAttribute(const S: string): Integer; Converts a string containing letters (ADHRS) into a numeric file attribute Characters other than ADHRS and * are ignored. A blank or invalid string will return a result of zero. See also: AttributeStr llFiles.pas -------------------------------------------------------------------------------- function UnusedFileName(const AFile: string): string; Takes a fully qualfied filename and if it exists, adds a number to the end of it until it no longer exists and returns the new (or unmodified) filename. Useful for exports and things where you don't want to overwrite any earlier versions of a file. The number has at least two digits (file.txt, file00.txt, file01.txt, etc.) to improve name-based sorting should there be more than nine files. llFiles.pas -------------------------------------------------------------------------------- function WildExists(const AFileSpec: string; const Attr: Integer = 0): Boolean; Given a wildcard filespec (and optional attribute), it will return true if any file specified by the wildcard exists. Can also be used as a substitute for FileExists if you wish. llFiles.pas -------------------------------------------------------------------------------- function GetSaveWindowPosFlag(const RegKey: string): Boolean; Returns the current setting of the SaveWindowPos flag used by SaveWindowPos and LoadWindowPos. llForms.pas -------------------------------------------------------------------------------- function LoadWindowPos(AForm: TForm; const RegKey: string; OtherInfo: TStrings = nil): Boolean; Loads a form's position and size from registry settings previously saved to HKCU by the SaveWindowPos function. Returns True if the settings were present and loaded. If OtherInfo is provided as a list of name-value pairs, matching items in the registry key will be retrieved and written to the list. Missing OtherInfo values do not affect the function's boolean return value, so it is suggested that you preload the list with sensible default values. llForms.pas -------------------------------------------------------------------------------- function SaveWindowPos(AForm: TForm; const RegKey: string; const ChangeSaveFlag: Integer = 0; OtherInfo: TStrings = nil): Boolean; Saves a form's position and size to HKCU. Values named Top, Left, Height, Width and Maximized are saved. If you plan on storing the position of multiple windows, give each a unique registry key. Use the LoadWindowPos function to read these settings back. A boolean value in this key called "SaveWindowPos" controls whether these settings get saved or not. You can change this value (it defaults to True) using the ChangeSaveFlag argument: 1: Change it to True 0: Use the current or default value -1: Change it to False -2: Change it to False and delete any saved values (Top, Left, etc.) ChangeSaveFlag makes it easy to make this a user configurable preference. The function returns True if SaveWindowPos ends up True and the settings were saved. The optional OtherInfo argument allows you to provide a tag-along list of name-value pairs that will be stored to the same registry key (as strings) and can later be retrieved using LoadWindowPos. This is handy for other window state information like splitter positions, etc. llForms.pas -------------------------------------------------------------------------------- TIntegerList = class(TObject) public constructor Create; overload; constructor Create(const AOwnsObjects: Boolean); overload; destructor Destroy; override; property Capacity: Integer read GetCapacity write SetCapacity; property CommaText: string read GetCommaText write SetCommaText; property Count: Integer read GetCount; property DelimitedText: string read GetDelimitedText write SetDelimitedText; property Delimiter: Char read FDelimiter write FDelimiter; property Descending: Boolean read FDescending write SetDescending; property Duplicates: TDuplicates read FDuplicates write FDuplicates; property NumberFormat: string read FNumberFormat write FNumberFormat; property Objects[Index: Integer]: TObject read GetObject write SetObject; property OnChange: TNotifyEvent read FOnChange write FOnChange; property OnChanging: TNotifyEvent read FOnChanging write FOnChanging; property OwnsObjects: Boolean read FOwnsObjects write FOwnsObjects; property QuoteChar: Char read FQuoteChar write FQuoteChar; property Sorted: Boolean read FSorted write SetSorted; property Sum: Integer read GetSum; property Sum64: Int64 read FSum64; property Values[Index: Integer]: Integer read GetValue write SetValue; default function Add(const Value: Integer): Integer; function AddObject(const Value: Integer; const AObject: TObject): Integer; procedure BeginUpdate; procedure Clear; procedure Clone(const Source: TIntegerList); procedure Delete(const Index: Integer); procedure EliminateDupes; procedure EndUpdate; procedure Exchange(const Index1, Index2: Integer); function Find(const Value: Integer; var Index: Integer): Boolean; function IndexOf(const Value: Integer): Integer; function IndexOfObject(const AObject: TObject): Integer; procedure Insert(const Index, Value: Integer); procedure InsertObject(const Index, Value: Integer; const AObject: TObject); procedure Sort; end; TIntegerList works just like TStringList, but carries Integers instead of strings. There are only a few significant differences: The Sum and Sum64 properties are the sum of all the numbers in the list as an Integer and Int64, respectively. If the actual sum overflows the range of an Integer, Sum will be set to MaxInt and Sum64 will contain the correct value. Should the sum exceed the range of an Int64, the class will fall over and die. The Descending property can be used to reverse the sorting order. Custom sorting is not supported. The OwnsObjects property allows the list's Objects to be freed automatically when deleted, just like TObjectList.OwnsObjects. When False, object lifetime is the responsibility of the programmer, as it is when using TStringList. The CommaText property allows you to get or set the list as a simple string of comma-delimited integers, such as '3,21,19,11'. Assigning a string that contains non-integer values will result in an EConvertError exception. The DelimitedText property works in a similar, but more flexible manner. When output, the NumberFormat property determines the format of each value written to the string. Set it to any valid numeric format string, e.g. '%.3d' or '%m', including non-decimal format strings. If the format string does not contain one of the decimal-format letters (d,u,x) it will be considered a float-type format. Quoting of the output is done only where required. On input, DelimitedText safely handles things like quoted values and non- numeric characters like thousands separators. Any fractional digits in the input are truncated. If the NumberFormat property contains the letter "x", the values will be interpreted as hex. Scientific notation is not supported as an input format. llIntegerList.pas -------------------------------------------------------------------------------- TLikePattern = class(TObject) public constructor Create; property AnyChar: Char read FAnyChar write SetAnyChar; // default % property OneChar: Char read FOneChar write SetOneChar; // default _ property EscChar: Char read FEscChar write SetEscChar; // default \ property Pattern: string read FPattern write SetPattern; property CaseSensitive: Boolean read FCaseSensitive write FCaseSensitive; function Matches(const S: string): Boolean; end; TLikePattern is used to do database-style LIKE pattern matching of strings. Assign a LIKE pattern using the Pattern property, then check one or more strings to see if they match the pattern using the Matches method. The method returns True when the string matches the pattern. The LIKE pattern follows the same rules as described in the PostgreSQL database docs, by default using the underscore for a one-character match (OneChar), a percent sign for a zero-or-more-character match (AnyChar) and the backslash to escape literal underscores and percent signs (EscChar). If you change the default wildcard/escape characters, you must do so BEFORE setting the Pattern. Spaces and letters are not allowed as wildcard/escape characters. The CaseSensitive property defaults to True, and can be changed at any time. The class supports any-character matches at the beginning and/or end of the pattern only. Assigning an invalid pattern will raise an ELikePatternError exception and set the pattern to blank. Attempting to match a string against a blank or unassigned pattern will always return False. Usage example: LP := TLikePattern.Create; LP.Pattern := '%ray%'; if LP.Matches(sSomeString) then ... LP.Free; llLike.pas -------------------------------------------------------------------------------- TLogicIni = class(TObject) public constructor Create; overload; constructor Create(const AFileName: string); overload; destructor Destroy; override; property FileName: string read FFileName write FFileName; property CaseSensitive: Boolean {default=False} read GetCaseSensitive write SetCaseSensitive; property Sorted: Boolean {default=False} read GetSorted write SetSorted; property WantComments: Boolean {default=True} read FWantComments write SetWantComments; property OldDateTimeFormat: Boolean {default=False} read FOldDates write FOldDates; property SectionCount: Integer read GetSectionCount; property SectionName[Index: Integer]: string read GetSectionName; property Dirty: Boolean read FDirty; procedure Clear; procedure GetStrings(Strings: TStrings); procedure SetStrings(Strings: TStrings); procedure LoadFromFile(const AFileName: string); procedure SaveToFile(const AFileName: string); procedure UpdateFile; function SectionExists(const Section: string): Boolean; procedure ClearSection(const Section: string); // Leaves empty section procedure EraseSection(const Section: string); // Removes completely procedure ReadSections(Strings: TStrings); procedure ReadSectionValues(const Section: string; Strings: TStrings); function CopySection(const Source, Target: string): Boolean; function RenameSection(const AOld, ANew: string): Boolean; function ValueExists(const Section, Ident: string): Boolean; procedure DeleteValue(const Section, Ident: string); function ReadString(const Section, Ident, Default: string): string; procedure WriteString(const Section, Ident, Value: string); function ReadInteger(const Section, Ident: string; Default: Longint): Longint; procedure WriteInteger(const Section, Ident: string; Value: Longint); function ReadBool(const Section, Ident: string; Default: Boolean): Boolean; procedure WriteBool(const Section, Ident: string; Value: Boolean); function ReadFloat(const Section, Ident: string; Default: Double): Double; procedure WriteFloat(const Section, Ident: string; Value: Double); function ReadDateTime(const Section, Ident: string; Default: TDateTime): TDate procedure WriteDateTime(const Section, Ident: string; Value: TDateTime; const P: TDateTimePrecision = dtpSecond); function ReadDate(const Section, Ident: string; Default: TDateTime): TDateTime procedure WriteDate(const Section, Ident: string; Value: TDateTime); function ReadTime(const Section, Ident: string; Default: TDateTime): TDateTime procedure WriteTime(const Section, Ident: string; Value: TDateTime; const P: TDateTimePrecision = dtpSecond); end; TLogicIni is my own take on TMemIniFile that preserves comments (if desired) and stores date and time values in a non-regional manner using the DtoS/TtoS, etc. functions from the llDates unit. It doesn't use the fancy hashing stringlist that TMemIniFile does, but slow ini lookups have never been a bottleneck for me. You can still read and write dates and times in the classic format by setting the OldDateTimeFormat property to True. The class will always *read* a date or time in the old format (by detecting the presence of separators), but it won't write them unless you tell it to. Changing this setting WILL NOT change any existing values - they will remain as-is until touched by a WriteDate/Time call. The precision arguments are ignored when using the old formats. It also includes (always) a "no-name" section that can hold comments or name- value pairs at the beginning of the file before any section headers. You can read/write values in this section using a blank section name (''). Setting the FileName property DOES NOT automatically load a new file! It just changes the filename used by UpdateFile. To load an ini file from disk after the constructor has been called you must use the LoadFromFile method. Hint: If you set Sorted to True, it is best not to refer to sections or values by index while you're changing stuff! llLogicIni.pas -------------------------------------------------------------------------------- function BtoS(const B: Boolean): string; A simpler alternative to BoolToStr. Returns '1' for True, '0' for False - the values typical to ini file booleans. llMisc.pas -------------------------------------------------------------------------------- function IIf(const ABool: Boolean; const ATrue, AFalse: string): string; overloa function IIf(const ABool: Boolean; const ATrue, AFalse: Integer): Integer; overl function IIf(const ABool: Boolean; const ATrue, AFalse: Int64): Int64; overload; function IIf(const ABool: Boolean; const ATrue, AFalse: Single): Single; overloa function IIf(const ABool: Boolean; const ATrue, AFalse: Double): Double; overloa function IIf(const ABool: Boolean; const ATrue, AFalse: Extended): Extended; ove function IIf(const ABool: Boolean; const ATrue, AFalse: Currency): Currency; ove Inline-If functions overloaded for common data types. The Double one works with TDateTime values. llMisc.pas -------------------------------------------------------------------------------- function StoB(const S: string; const BlankDefault: Boolean = False): Boolean; A simpler version of StrToBool that never raises an exception. It uses my predefined list of True values and considers anything else as False. If the input is blank (''), the function returns the BlankDefault value. Case-insensitive True values: Y/Yes, T/True, +, * or any non-zero numeric. llMisc.pas -------------------------------------------------------------------------------- TMRU = class(TObject) public constructor Create(AParentMenu: TMenuItem; const ARegKey: string); destructor Destroy; override; property Items[Index: Integer]: string read GetItemByIndex; default; property Count: Integer read GetCount; procedure Clear; procedure Erase; procedure Load; procedure Save; procedure Update(const S: string); procedure Delete(const Index: Integer); overload; procedure Delete(const S: string); overload; published property ParentMenu: TMenuItem read FMenu write SetMenu; property RegistryKey: string read FRegKey write SetRegKey; property MaxItems: Integer read FMaxItems write SetMaxItems; property AutoSave: Boolean read FAutoSave write FAutoSave; property OnChange: TNotifyEvent read FOnChange write FOnChange; property OnClick: TNotifyEvent read FOnClick write FOnClick; end; TMRU implements a Most-Recently-Used list as a submenu. Start by creating your main menu and adding a menu item that will contain the MRU items as a submenu. Caption this with text like "Recent Files..." or something. Create an instance of TMRU and attach it to this menu item using the first Create argument. You can also use a TPopupMenu.Items property in place of a regular menu item. It also needs a registry key where it can store its data (HKCU). By default, the MRU stores 10 items. Set MaxItems to change this (the value is recalled when loading a previously saved MRU). By default, AutoSave is True, which means the MRU will automatically save its data to the registry when destroyed. If you want to handle the saving yourself, set AutoSave to False and call the Save method. The Erase method deletes any previously stored registry values and sets AutoSave to False. Then, in your program, whenever you open a file (you don't have to use the MRU to keep track of files - it could be anything), just call the Update method with the text of the item you just selected/opened. The items in the MRU are maintained in a case-insensitive manner. If you need to manually remove items from the list (for example, files that no longer exist), use one of the overloaded Delete methods. To be notified when the user clicks on one of the MRU items, set the OnClick event. The Sender will be the menuitem that was clicked. It is not necessary (but harmless) to call Update when responding to this event - the MRU did so prior to firing it. If you want to be notified when the MRU list changes, use the OnChange event. llMRU.pas -------------------------------------------------------------------------------- function CenteredMsgDlg(const AMsg, ACaption: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; AForm: TForm = nil; const HelpCtx: Integer = 0; const HelpFileName: string = ''): Integer; An adaptation of Dialogs.MessageDlgPosHelp that accepts a caption, centers the dialog over the calling form, and plays a sound like Application.MessageBox. If the caption is blank, the default MessageDlg caption is used. If the form is not provided, the dialog appears in its default position of screen center. llMsgDlg.pas -------------------------------------------------------------------------------- procedure MsgAlert(const Text: String; const Caption: String = ''; AForm: TForm = nil); Shows a CenteredMsgDlg with a warning icon and an OK button. llMsgDlg.pas -------------------------------------------------------------------------------- procedure MsgError(const Text: String; const Caption: String = ''; AForm: TForm = nil); Shows a CenteredMsgDlg with an error icon and an OK button. llMsgDlg.pas -------------------------------------------------------------------------------- procedure MsgInfo(const Text: String; const Caption: String = ''; AForm: TForm = nil); Shows a CenteredMsgDlg with an information icon and an OK button. llMsgDlg.pas -------------------------------------------------------------------------------- function MsgOKCancel(const Text: String; const Caption: String = ''; AForm: TForm = nil): Boolean; Returns a True/False answer to an OK/Cancel CenteredMsgDlg. llMsgDlg.pas -------------------------------------------------------------------------------- function MsgRetryCancel(const Text: String; const Caption: String = ''; AForm: TForm = nil): Boolean; Returns a True/False answer to a Retry/Cancel CenteredMsgDlg. llMsgDlg.pas -------------------------------------------------------------------------------- function MsgYesNo(const Text: String; const Caption: String = ''; AForm: TForm = nil): Boolean; Returns a True/False answer to a Yes/No CenteredMsgDlg. llMsgDlg.pas -------------------------------------------------------------------------------- function MsgYesNoCancel(const Text: String; const Caption: String = ''; AForm: TForm = nil): Integer; Returns mrYes, mrNo or mrCancel in response to a CenteredMsgDlg. llMsgDlg.pas -------------------------------------------------------------------------------- function BinStrToInt(const S: string): Integer; Converts a binary string (e.g. '0101') into an integer value. If the string is smaller than the number of bits in an integer, the string is right- justified into the least significant bits of the number. If the string is longer than needed, only the rightmost characters are used. See also: IntToBinStr llNumbers.pas -------------------------------------------------------------------------------- function Dice(const ARolls: Integer; const ASides: Integer = 6; const AModify: Integer = 0): Integer; overload; Returns the sum of one or more virtual dice rolls (random numbers). A die of sides is rolled times. Optionally, each roll can be modified by the value of , which can be negative. The total of these rolls is returned. If only the number of rolls is given, an unmodified 6-sided die is assumed. llNumbers.pas -------------------------------------------------------------------------------- function Dice(const AStr: string): Integer; overload; Nerd alert! Accepts a string in "gaming notation", such as "3d6" or "2d4+1" and returns the integer result of said dice roll(s). Returns zero on blank input and raises an EConvertError on bad input. Input without a "d" in it is considered a constant and will simply be converted to an integer. Examples: Dice('3d6') -> 3..18 Dice('10') -> 10 Dice('foo') -> EConvertError See also: TryDice llNumbers.pas -------------------------------------------------------------------------------- function GCD(const a, b: Integer): Integer; Calculates the greatest common divisor of two integers. (The Euclidian algorithm) llNumbers.pas -------------------------------------------------------------------------------- function IntToBinStr(const Value: Integer; const Bits: Integer = 8): string; Converts an integer into a string of binary digits (e.g. '0110'). The length of the string is determined by the Bits argument and defaults to 8 (a byte). See also: BinToIntStr llNumbers.pas -------------------------------------------------------------------------------- function MinMax(const AMin, AValue, AMax: Integer): Integer; overload; function MinMax(const AMin, AValue, AMax: Int64): Int64; overload; function MinMax(const AMin, AValue, AMax: Single): Single; overload; function MinMax(const AMin, AValue, AMax: Double): Double; overload; function MinMax(const AMin, AValue, AMax: Extended): Extended; overload; function MinMax(const AMin, AValue, AMax: Currency): Currency; overload; Translates directly to Max(AMin, Min(AValue, AMax)), but with less chance of the programmer messing it up. :) Overloaded just like the Min and Max functions in the Math unit. llNumbers.pas -------------------------------------------------------------------------------- function PrettyInt(const Value: Integer): string; overload; function PrettyInt(const Value: Int64): string; overload; function PrettyInt(const Value: Cardinal): string; overload; Returns the integer as a string with thousands separators. llNumbers.pas -------------------------------------------------------------------------------- function RandRange(const ALo, AHi: Integer): Integer; Returns a random integer between and , inclusive. This is meant as an alternative to D5's System.RandomRange which is non- inclusive, and an equivalent to Math.RandomRange in D6+. llNumbers.pas -------------------------------------------------------------------------------- function TryDice(const AStr: string; out Value: Integer): Boolean; TryDice is to Dice as TryStrToInt is to StrToInt. llNumbers.pas -------------------------------------------------------------------------------- TStringBuilder = class(TObject) public constructor CreateStr(const Value: string); property AsPChar: PChar read GetPChar; property AsString: string read GetString write SetString; property Length: Integer read FLen write SetLen; property Capacity: Integer read FCapacity write SetCapacity; property Chars[Index: Integer]: Char read GetChar write SetChar; default; procedure Clear; procedure Append(const Value: string); procedure Insert(const Value: string; const Index: Integer); procedure Delete(const Index, Count: Integer); end; TStringBuilder is used to piece together strings from many smaller pieces. Compared to regular string concatenation, it does considerably less memory reallocation (and is faster) because it pre-allocates larger chunks and only trims to the actual size when it's done -- when you call AsString or AsPChar. The Append, Insert and Delete methods work exactly as you would imagine. The Chars property is used just like the characters of a regular string. An invalid index here will raise an ERangeError exception. Length returns the actual, finished length of the string. It can be set to change the length of the string. For example, set it to zero to clear the string without affecting the current capacity (this is what the Clear method does). Set it to a value larger than the current length and spaces will be added to reach the desired length. Capacity returns the amount of space allocated, and can be set if you have a good guess as to the size of the final result. Otherwise, capacity will grow as needed. llStringBuilder.pas -------------------------------------------------------------------------------- const ALPHA_LOWER = 'abcdefghijklmnopqrstuvwxyz'; ALPHA_UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; ALPHA_BOTH = ALPHA_UPPER + ALPHA_LOWER; Handy constants for the lower & upper case alphabets. llStrings.pas -------------------------------------------------------------------------------- function CharsOnly(const AInput, AAllowed: string; const MostlyGood: Boolean = True): string; Strips any characters from AInput that don't appear in AAllowed. The comparison is case-sensitive. There are two shorthand values available for the allowed characters string: @@ = All alpha characters, upper and lower ## = All numeric digits 0..9 The optional MostlyGood argument is used to select the algorithm used to do the work. By default, an algorithm optimized for mostly good input is used - the fewer bad characters, the less work it does. When False, an algorithm that does less work when more bad characters are present is used. Example: CharsOnly('FooBar1', '123abcABC') -> 'Ba1' llStrings.pas -------------------------------------------------------------------------------- function CloseBracketPos(const S: string; const AIndex: Integer; const Backwards: Boolean = False): Integer; Given a string and the index of an opening character of a bracket pair (i.e. parentheses, square brackets, curly braces, or angle brackets aka greater than/less than) the function returns the index of its matching opposite, fully allowing for nested pairs. The function returns zero if the matching bracket is not found. If Backwards is True, it looks backwards to find the matching opening bracket for the closing character at the given index. If the character at the index position is not one of the valid open/close characters, an assertion, range check, or access violation exception will be raised depending on compiler options. Example: CloseBracketPos('r = ((x + 5) * (y - z)) / 2', 5) -> 23 ^ ^ given this it finds this llStrings.pas -------------------------------------------------------------------------------- function CloseQuotePos(const S: string; const AIndex: Integer; const Backwards: Boolean = False): Integer; Given a string and an index to the opening quote mark, the function returns the index of the final closing quote character, properly skipping any doubled literals. If a closing quote can't be located, the function returns zero. If Backwards is True, the index points to the closing quote character and the function looks backwards for the opening quote. Whatever character is present at the given index is used as the quote character. It could be a single quote, double quote, asterisk, or anything. Example: CloseQuotePos('cow="moo" dog="bark"', 5) -> 9 ^ ^ given this it finds this llStrings.pas -------------------------------------------------------------------------------- function Dequote(const S: string; const AQuote: Char = '"'): string; Works just like AnsiDequotedStr, but that doesn't exist in Delphi 5. In addition, D6 & D7 have a bug where AnsiDequotedStr will return a pair of empty quotes ("" or '') unchanged instead of returning an empty string! See also: Enquote llStrings.pas -------------------------------------------------------------------------------- function DigitsOnly(const AInput: string): string; Strips everything except numeric digits from the input string. Handy for stripping punctuation from phone number strings. Since this occurs so often, it's more optimized than calling CharsOnly(AInput, '##'). Example: DigitsOnly('1(800)555-1212') -> '18005551212' llStrings.pas -------------------------------------------------------------------------------- function Enquote(const S: string; const AQuote: Char = '"'): string; Works much like QuotedStr & AnsiQuotedStr, but in one convenient function with a nice, short name. See also: Dequote llStrings.pas -------------------------------------------------------------------------------- function FormatDigits(const ADigits, AFormat: string): string; Right-justifies/overlays a string of digits into a format string. Especially handy for phone number formatting, but it could conceivably be used on any type of input. Ex: FormatDigits('6025551212', '(099)999-9999') -> '(602)555-1212' FormatDigits('5551212', '(099)999-9999') -> '555-1212' FormatDigits('6025551212', '999.999.9999') -> '602.555.1212' FormatDigits('foo', 'bar') -> 'foobar' All digit characters are always output even if the format string is shorter or blank. Output stops when you run out of digit characters, even though there may be more format string remaining. Format string rules: 9 = Replace this character with a character from the digit string. 0 = Same as 9 but always includes the next format character to the left, even if you have run out of digit characters. * = Any other character is copied to the output as a literal. Known limitations: The only way to output a literal '0' or '9' is to the immediate left of a '0' in the format string. llStrings.pas -------------------------------------------------------------------------------- function IndexOfPartial(AItems: TStrings; const AValue: String; const ADefault: Integer = -1; const CaseSensitive: Boolean = True): Integer; Finds the index of a string value in a TStrings list. Unlike TStrings.IndexOf, this will match on the partial length of AValue using StartsWith(). Returns -1 if not found or ADefault if given and valid. llStrings.pas -------------------------------------------------------------------------------- function InterleaveStrings(const S1, S2: string): string; Combines two strings by alternating characters. Example: InterleaveStrings('abc', '1234') -> 'a1b2c34' llStrings.pas -------------------------------------------------------------------------------- function IsBlank(const S: string): Boolean; Returns True if the string is empty or contains only "trimmable" characters. If you're just going to discard it if blank, why waste time creating another copy by actually trimming it? llStrings.pas -------------------------------------------------------------------------------- function LastPos(const Substr, S: string; const Offset: Integer = 0): Integer; Returns the position of the last occurence of the substring, or zero if not found. Accepts a starting offset like PosEx, the default of zero being the equivalent of Length(S). Actually, any value outside 1..Length(S) will become Length(S). Examples: LastPos('foo', 'foobarfoobar') -> 7 LastPos('foo', 'foobarfoobar', 6) -> 1 llStrings.pas -------------------------------------------------------------------------------- function PadC(const AInput: string; const ALen: Integer; const AChar: Char = ' '): string; Pads a string equally on both sides with to a length of . If is longer than , the middle characters will be returned. llStrings.pas -------------------------------------------------------------------------------- function PadL(const AInput: string; const ALen: Integer; const AChar: Char = ' '): string; Pads a string on the left with to a length of . If is longer than , the rightmost characters of will be returned. llStrings.pas -------------------------------------------------------------------------------- function PadR(const AInput: string; const ALen: Integer; const AChar: Char = ' '): string; Pads a string on the right with to a length of . If is longer than , the leftmost characters of will be returned. llStrings.pas -------------------------------------------------------------------------------- function PosEx(const Substr, S: string; Offset: Cardinal = 1): Integer; A D5/D6 equivalent of the D7+ StrUtils.PosEx function. Works just like Pos, but accepts a character offset for where to start looking. llStrings.pas -------------------------------------------------------------------------------- function ReverseString(const AInput: string): string; A D5/D6 equivalent of the D7+ StrUtils.ReverseString function. Simply returns a string reversed. llStrings.pas -------------------------------------------------------------------------------- function RightStr(const AInput: string; const ALen: Integer): string; A D5/D6 equivalent of the D7+ StrUtils.RightStr function. Returns the rightmost characters of . If is shorter than , all of will be returned. llStrings.pas -------------------------------------------------------------------------------- function Spaces(const ALen: Integer): string; Returns a string of spaces. llStrings.pas -------------------------------------------------------------------------------- function StartsWith(const APart, AWhole: string; const CaseSensitive: Boolean = True): Boolean; Returns True if is the beginning of . It will also return True if happens to be null (''). CaseSensitive is self-explanatory. llStrings.pas -------------------------------------------------------------------------------- procedure TokenList(const AText, AToken: string; AList: TStrings); Breaks up a string at each occurrence of and adds these substrings to a TStrings descendant, . Note that the list is not cleared before adding any strings, so do this manually if desired. This is handy when you have a simple delimited list, but TStrings.CommaText would blow chunks because the values contain spaces. It also works on tokens longer than a single character. Quoting is not supported. llStrings.pas -------------------------------------------------------------------------------- function WordPos(const AWord, AText: string; const Offset: Integer = 1; const WordChars: string = ''): Integer; Returns the position of the first "separate word" substring of AWord found in AText. The word must be surrounded by non-word characters to be considered separate, otherwise it is considered to be part of a larger word. By default, letters, numbers and underscores make up the characters that are considered part of "words". If you need different ones, use the optional WordChars argument to supply the entire list, including both upper and lower case letters if needed. Offset indicates where to start searching within AText, just like the Offset argument to PosEx. Examples: WordPos('delete', 'Do not delete it!') -> 8 WordPos('delete', 'I deleted it!') -> 0 (part of a larger word) llStrings.pas -------------------------------------------------------------------------------- function BrowseForFolder(const AHandle: HWND; const ACaption: string; var AFolder: string): Boolean; A handy wrapper around SHBrowseForFolder. Makes a nice, modern-looking replacement for SelectDirectory. Returns True if the user selects a directory. The initial directory is passed as AFolder, which also holds the new value when successful. llWinAPI.pas -------------------------------------------------------------------------------- function ExpandEnvars(const S: string): string; A handy string-based wrapper around ExpandEnvironmentStrings. Turns things like "%SystemRoot%" into "C:\WINDOWS", etc. llWinAPI.pas -------------------------------------------------------------------------------- function GetAssociatedProgram(const AFile: string): string; Uses the FindExecutable API function to get the program associated with the given file's extension. The file must exist and should be a fully qualified filename. Returns an empty string if unsuccessful. Note: If the file itself is executable (.exe, .bat, etc.) the return value is the filename itself (usually as a short filename using ~1 notation). llWinAPI.pas -------------------------------------------------------------------------------- function GetAssociatedProgramByExt(const AExt: string): string; Get the program associated with a given extension. The extension can be provided with or without a leading period. This actually just creates a temp file with the given extension and calls GetAssociatedProgram. llWinAPI.pas -------------------------------------------------------------------------------- function GetLastErrorStr(const AErrNo: Cardinal = 0): string; Returns the text for a system error number. If unable to get the text, the function just returns the number as a string. The function will return the text for the given error number argument, or the results of the GetLastError function if passed a zero. llWinAPI.pas -------------------------------------------------------------------------------- function GetShellFolder(const CSIDL: Integer; const Slash: Boolean = False): string; Handy wrapper around the ShGetFolderPath function that returns a string. Adds/Strips a trailing slash based on the boolean argument. Delphi6+: The CSIDL constants are declared in the SHFolder unit. Delphi5: The CSIDL constants are declared here and in ShlObj. llWinAPI.pas -------------------------------------------------------------------------------- function GetTempFile(const APath: string; const APrefix: string = 'TMP'): string; Wrapper around GetTempFileName() that conveniently returns a string. llWinAPI.pas -------------------------------------------------------------------------------- function GetWinCompName: string; Returns the current Windows computer name or a null string if unsuccessful. llWinAPI.pas -------------------------------------------------------------------------------- function GetWinDir(const Slash: Boolean = False): string; Wrapper around GetWindowsDirectory() that conveniently returns a string. The Slash argument will add a traling backslash if True, and remove one if False (the default). llWinAPI.pas -------------------------------------------------------------------------------- function GetWinUserName: string; Returns the current Windows username or a null string if unsuccessful. llWinAPI.pas -------------------------------------------------------------------------------- procedure OpenWith(const AFileName: string; const hWindow: HWND = 0; const ShowCmd: Integer = SW_SHOWNORMAL); This is a ShellExecute equivalent but shows the "Open with..." dialog on file types without an existing association. llWinAPI.pas -------------------------------------------------------------------------------- procedure PostKey(hWindow: HWND; Key: Word); Sends a WM_KEYDOWN & WM_KEYUP to a window/control/component. llWinAPI.pas -------------------------------------------------------------------------------- LogicLib ©2007-2010 Illuminated Logic, LLC. http://www.illuminatedlogic.com Installation: Installation of LogicLib is very easy and works the same in all versions of Delphi. Create a folder for LogicLib. I generally install all my components and libraries under a single directory tree so they are easy to find. Double-click LogicLib.dpk and press Compile, then Install in the package manager. Add the LogicLib folder to Delphi's library path using the Tools menu. When you want to reference a function from LogicLib, simply add the required unit name to the uses clause of the file you're working in. License Agreement: A license to use LogicLib is granted on a per-developer or site-wide basis. It may be used in any number of applications, freeware or commercial, for internal use or distributed externally in staticly-linked binary form, without any additional royalty or payment. A single developer may install the source code on multiple computers (physical or virtual) but each developer with access to the code must have their own (or a site) license. The LogicLib source code may not be distributed under any circumstances, in its original or modified form, to any non-licensed party. If you produce a work-for-hire and the customer requires a copy of all source code needed to build the application, your customer is granted a limited-use license for building the specific work-for-hire ONLY, and you may provide them with a copy of the library and any modifications you may have made to the code. Illuminated Logic will not provide support to any such 3rd-party licensee unless support or a regular license is purchased separately. All other rights, including copyright, are reserved by the author. Warranty: Legal mumbo-jumo aside, Illuminated Logic, LLC. offers a 30-day money back guarantee on all software purchases and bug fixes always have been, and always will be free. Of course, Illuminated Logic reserves the sole right to determine if any given issue brought to our attention is classified as a "bug" or not. For example, design/scope changes are NOT bugs. Illuminated Logic, LLC. does not warrant that the operation of the LogicLib code library for Delphi (SOFTWARE PRODUCT) will meet your requirements or that the operation of the software will be uninterrupted, be error free, or that defects in software will be corrected. The SOFTWARE PRODUCT is provided "AS IS" without warranty of any kind. The entire risk as to the quality and performance of the SOFTWARE PRODUCT is with the purchaser. ILLUMINATED LOGIC, LLC. MAKES NO OTHER WARRANTY, EITHER EXPRESSED OR IMPLIED, WITH RESPECT TO THIS PRODUCT. ILLUMINATED LOGIC, LLC. SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE REMEDIES PROVIDED HEREIN ARE CUSTOMER'S SOLE AND EXCLUSIVE REMEDIES. UNDER NO CIRCUMSTANCES (INCLUDING NEGLIGENCE), SHALL ILLUMINATED LOGIC, LLC. BE LIABLE FOR ANY LOST PROFITS, DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER BASED ON CONTRACT, TORT, OR ANY OTHER LEGAL THEORY, EVEN IF ILLUMINATED LOGIC, LLC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. IN NO EVENT SHALL ILLUMINATED LOGIC'S TOTAL LIABILITY FOR DAMAGES, LOSSES AND CAUSES OF ACTION, WHETHER IN CONTRACT, TORT (INCLUDING NEGLIGENCE), OR OTHERWISE, EXCEED THE AMOUNT PAID BY YOU FOR THE SOFTWARE. LogicLib.dpk --------------------------------------------------------------------------------