-------------------------------------------------------------------------------- LibDoc documentation for LogicLib.dpk Created 8/8/2022 11:09:25 AM -------------------------------------------------------------------------------- LogicLib ©2007-2022 Illuminated Logic, LLC. / Ray Marron https://www.illuminatedlogic.com https://www.raymarron.com Portions retrieved and adapted from public sources (llPrinting.pas). 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 unit you're working in. License Agreement: You may use LogicLib to build open- or closed-source, free or commercial products without restriction. If you wish to re-release the original or modified library source code, it is released under the Creative Commons Attribution-ShareAlike license (CC BY-SA). I gave it to you free, so you give it to others for free and tell them where you got it. All other rights, including copyright, are reserved by the author. Warranty: 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 -------------------------------------------------------------------------------- function AddDot(const AExt: string): string; Adds a dot to the beginning of an extension if one is not already present. A blank string will not be modified. llFiles -------------------------------------------------------------------------------- function AddSlash(const APath: string): string; Just a shorter way to write IncludeTrailingPathDelimiter. llFiles -------------------------------------------------------------------------------- function AdjustDate(const AAging: string; var VDate: TDateTime): Boolean; Adjusts the given date based on the aging string. The aging string is a value or combination of values specifying what to add or subtract from the supplied date/time. The function returns a boolean indicating whether a valid aging string was supplied and VDate was updated. Aging syntax: NOW | #A | [+|-]#[X][#X...][#T|Z][F|L] If the aging string is the constant "NOW", the date is set to the current system date/time. Otherwise, # is a number and X represents one of the following letters: A - Absolute date/time in the form of YYYYMMDDHHNNSSZZZ (or a subset) S - Seconds N - miNutes H - Hours D - Days M - Months Y - Years T - Change the Time to the given HHNNSSZZZ value (or a subset). Z - Zero out the time/change to midnight (Equivalent to "00T"). W - Change the Weekday of the date (1..7 = Sunday..Saturday). F - Change the date to the First of the month. L - Change the date to the Last of the month. If the aging string does not start with a plus or minus, minus is assumed. If only a number is supplied, it is assumed to be a number of days. The calculations are applied in the order listed above. If the resulting date has an invalid day of the month (e.g. Feb 29 in a non-leap year, Dec 31 minus one month, etc.) the day of the month is set to the last valid day. Milliseconds can only be adjusted by time replacement (T) or truncation (Z). When changing the Weekday, if the date lands on the specified day of the week after the other adjustments, it is not changed. Otherwise, the date will be adjusted to the previous/next matching weekday. Aging examples: 1D7H Subtracts 1 day and 7 hours (subtraction is assumed). +1DZ Adjusts the date to tomorrow at midnight. -1D1430T Adjusts the date to yesterday at 2:30PM. -1MF Adjusts the date to the first of last month. 20160802A Changes the date to the absolute value 2016-08-02 00:00:00.000. +2W If not already a Monday, adjust to the next Monday. +1D2W Adjust to next Monday. 7 Subtracts 7 days (subtraction and days are assumed). See also: DateMath, StoD, StoT llDates -------------------------------------------------------------------------------- function AgeOnDate(const ADOB, ADate: TDateTime): Integer; Returns a person's age on a given date as an integer number of years. See also: DateDiff llDates -------------------------------------------------------------------------------- const DefaultQuoteChar = '"'; ALPHA_LOWER = 'abcdefghijklmnopqrstuvwxyz'; ALPHA_UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; ALPHA_BOTH = ALPHA_UPPER + ALPHA_LOWER; DIGIT_CHARS = '0123456789'; ALPHA_NUMERIC = ALPHA_BOTH + DIGIT_CHARS; UTF8_BOM = #$EF#$BB#$BF; // Also defined in llFileUtils UTF8_BOM_LENGTH = 3; PairOpen = '({[<'; PairClose = ')}]>'; Handy constants including digits, the lower & upper case alphabets, and the UTF8 Byte-order-marker, which I have to skip over when working with some text files (especially csv files created by SQL Server). llStrings -------------------------------------------------------------------------------- function AnsiDate(const DT: TDateTime): string; Just a quicker way to write FormatDateTime('yyyy-mm-dd', DT) Constants for use with FormatDateTime are also available: ANSI_DATE = 'yyyy-mm-dd'; ANSI_DATETIME = ANSI_DATE + ' hh:nn:ss'; ANSI_DATETIMEZ = ANSI_DATETIME + '.zzz'; See also: AnsiDateTime llDates -------------------------------------------------------------------------------- function AnsiDateTime(const DT: TDateTime): string; Just a quicker way to write FormatDateTime('yyyy-mm-dd hh:nn:ss', DT) Constants for use with FormatDateTime are also available: ANSI_DATE = 'yyyy-mm-dd'; ANSI_DATETIME = ANSI_DATE + ' hh:nn:ss'; ANSI_DATETIMEZ = ANSI_DATETIME + '.zzz'; See also: AnsiDate llDates -------------------------------------------------------------------------------- function AnyChecked(Lbx: TCheckListBox): Boolean; Returns True if any of the items in the TCheckListBox are checked. llControls -------------------------------------------------------------------------------- function ASCIIToBytes(const ASCII: string): TBytes; Converts a string in Delphi-style ASCII notation (e.g. '#13#10') into an array of bytes. Invalid input will raise an EConvertError exception. See also: BytesToASCII llBytes -------------------------------------------------------------------------------- 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. llDates -------------------------------------------------------------------------------- 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 or faReadOnly): AttributeStr(Attr) -> 'AR' AttributeStr(Attr, 'adhrs ') -> 'a r ' AttributeStr(Attr, 'DHRSA-') -> '--R-A' See also: StrToAttribute llFiles -------------------------------------------------------------------------------- function Base64ToBytes(const ABase64: string): TBytes; Decodes a Base64 string into an array of bytes. Invalid input will raise an EConvertError exception. See also: BytesToBase64, IsBase64 llBytes -------------------------------------------------------------------------------- function BinStrToCardinal(const S: string): Cardinal; function BinStrToInt(const S: string): Integer; function BinStrToInt64(const S: string): Int64; Converts a binary string (e.g. '0101') into a number. If the string is smaller than the number of bits in the result type, the string is right- justified into the least significant bits of the number. If the string is longer than the size of the result, only the rightmost characters are used. See also: IntToBinStr llNumbers -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- 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. llBool -------------------------------------------------------------------------------- function BuildCSV(AFields: TStrings; const QS: TCSVQuotingStyle): string; overload; function BuildCSV(AFields: TStrings; const AForceQuote: Boolean = False): string; overload; deprecated; Works like TStrings.DelimitedText, but sometimes you need to force quoting of certain values or all fields. The quoting style argument controls what fields get quoted: qsNormal: Only fields that contain QuoteChar or Delimiter. qsSpaces: As above, but also includes spaces and tabs. qsEverything: All fields are quoted, including empty ones. The QuoteChar and Delimiter are determined by the AFields properties of the same names. The deprecated boolean overload version works like qsSpaces unless ForceQuote is True, when it works like qsEverything. llCSV -------------------------------------------------------------------------------- function BytesToASCII(const ABytes: TBytes): string; Converts an array of bytes into a Delphi-style ASCII string (i.e. '#13#10'). Empty input results in empty output. See also: ASCIIToBytes llBytes -------------------------------------------------------------------------------- function BytesToBase64(const ABytes: TBytes): string; Encodes an array of bytes as a Base64 string. Empty input results in empty output. See also: Base64ToBytes, IsBase64 llBytes -------------------------------------------------------------------------------- function BytesToHex(const ABytes: TBytes): string; Returns a string of hex characters representing the array of bytes passed in. See also: HexToBytes, HtoI, IsHex llBytes -------------------------------------------------------------------------------- function CardinalToIPv4(const AIP: Cardinal; const ABigEndian: Boolean = False): string; Converts a Cardinal into a dotted-decimal IPv4 address string. If ABigEndian is True, the bytes will be reversed first. See also: Int64toIPv4, IPv4toCardinal, IPv4toInt64, IsValidIPv4, SwapEndianCardinal llNetwork -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- function ChangeCase(const S: string; const ACase: TllCharCase): string; Changes the case of a string based on the value of the second argument. If ACase is ecNormal, the string is unchanged. Using ecStartCase will change the first letter of each word to uppercase and the rest to lower. TllCharCase = (ecNormal, ecUpperCase, ecLowerCase, ecStartCase); See also: TllCharCase, StartCase llStrings -------------------------------------------------------------------------------- function ChangePrinterBin(const ABin: Integer): Integer; Changes the paper source bin of the currently selected printer. See the GetBinNames procedure for info on retrieving the valid bin numbers. This procedure must be called *before* Printer.BeginDoc to take effect. I changed it to a function to return the current bin value before the change. Retrieved from the Delphi newsgroup archives, originally by Peter Below and originally called "SelectPrinterBin". llPrinting -------------------------------------------------------------------------------- function CharsOnly(const AInput, AValid: string; const MostlyGood: Boolean = True): string; Strips any characters from AInput that don't appear in AValid. The comparison is case-sensitive. There are two shorthand values available for the valid 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' See also: DigitsOnly, IsCharsOnly llStrings -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- procedure CheckListCheckObject(const Lbx: TCheckListBox; const AValue: Integer; const ACheck: Boolean = True); Checks an item in a TCheckListBox whose integer Object value matches AValue. If ACheck is False, the item is un-checked. If there is more than one matching object in the list, they will all be [un-]checked. llControls -------------------------------------------------------------------------------- function CIDRv4Range(const AMask: string; out OMin, OMax: Cardinal): Integer; Takes a string IPv4 CIDR mask and calculates the lowest and highest Cardinal IP addresses it contains and places them into the variable arguments. The function returns the number of bits the mask covers, or -1 if the mask is not valid. llNetwork -------------------------------------------------------------------------------- procedure CleanMRUList(const AList: TStrings); Removes items from an MRU list of filenames where the file no longer exists. llMRU -------------------------------------------------------------------------------- procedure CloneDataset(ASource: TDataset; ATarget: TClientDataSet; const AFieldDefsOnly: Boolean = False); Copies the field definitions 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 -------------------------------------------------------------------------------- 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 See also: FindPairPos llStrings -------------------------------------------------------------------------------- function Coalesce(const S: array of string): string; Much like the SQL function of the same name, it returns the first non-blank value from a list of strings. If none qualify, an empty string is returned. See also: IsBlank llStrings -------------------------------------------------------------------------------- function CommonCIDRv4(const AIPList: TStrings; out OMask: Int64; out OBits: Integer): string; Takes a list of string IPv4 addresses as input and calculates their shared network mask using the highest number of bits all the addresses have in common. The Mask and Bits are updated in the numeric output parameters, and the CIDR string (e.g. "172.16.0.0/24") is the return value. If the list is empty or any address in the list is invalid, the function will return an empty string. The content of the output parameters is undefined. If the addresses have absolutely no bits in common (for example, 10.x.x.x and 192.168.x.x), the output parameters will be zero and the return string will be "0.0.0.0/0". llNetwork -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- function CountIn(const APart, AWhole: string): Integer; Counts the number of times a substring appears in a string. If the substring is a repeating value like 'aa', every possible instance of the value will be counted, for example CountIn('aa', 'aaaa') == 3. llStrings -------------------------------------------------------------------------------- procedure CountUniqueStrings(const AList: TStrings; const AValue: string; const AModifier: Cardinal = 0); Keep a count of unique strings in a TStrings.Objects properties. Pass the list and a string value. If the value does not yet appear in the list, it will be added with a count of 1 in the Object value. Otherwise, the count in the Object value will be incremented. If AModifier is > 0, the count will always be at least AModifier + 1. This is typically a very high number, so you can distinguish the modifier from the actual count. llStrings -------------------------------------------------------------------------------- function CreateEmptyFile(const AFile: string): Boolean; Creates a zero byte file, returning True if successful. If the file already exists, it will be overwritten/truncated. Actually just calls CreateSimpleFile with no content. See also: CreateSimpleFile, ReadSimpleFile llFileUtils -------------------------------------------------------------------------------- function CreateSimpleFile(const AFile, AContent: string): Boolean; Creates a file with a simple string for content, returning a boolean success. If the file already exists, it will be overwritten/truncated. If AContent is blank, the file will have zero bytes. The file is written using UTF-8 encoding without a BOM. See also: CreateEmptyFile, ReadSimpleFile llFileUtils -------------------------------------------------------------------------------- function DateDiff(const AUnit: TDateTimePrecision; const AStart, AEnd: TDateTime): Int64; Calculates the difference between two dates as an integer number of units, where the unit is determined by the AUnit TDateTimePrecision argument. Any fractional unit is discarded by truncation or rounding (ms). For example, if AUnit is dtpDay and the dates are 2 days and 20 hours apart, the result will be 2. Units larger than dtpYear (dtpDecade, etc.) are just treated as dtpYear. See also: AgeOnDate, MonthDiff llDates -------------------------------------------------------------------------------- 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 day of the month will be truncated to the last valid day of the month. 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> See also: AdjustDate llDates -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- function Dequote(const S: string; const AQuote: Char = DefaultQuoteChar): 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 -------------------------------------------------------------------------------- function DequoteStr(const S: string): string; Works just like Dequote, but uses the first character of the string as the quote character. If the string does not start AND end with the same non- alphanumeric character, it will be returned unchanged. See also: StripParens llStrings -------------------------------------------------------------------------------- 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. The sum of these rolls is returned. Optionally, the sum can be modified by adding the value of , which may be negative. If only the number of rolls is given, an unmodified 6-sided die is assumed. llDice -------------------------------------------------------------------------------- function Dice(const ADiceStr: string): Integer; overload; Nerd alert! Accepts a string in "gaming notation", such as "3d6" or "2d4+1" and returns the integer sum of the dice roll(s). Returns zero on blank input and raises an EConvertError on bad input. Input without a "d" in it (case insensitive) is considered a constant and will simply be converted to an integer. Examples: Dice('3d6') -> 3..18 Dice('2d4+2') -> (2..8)+2 (modifier is added to the final sum) Dice('d%') -> 1..100 (1 roll assumed, "%" is shorthand for 100) Dice('10') -> 10 Dice('foo') -> EConvertError You may nest rolls by using parentheses. For example, if you wanted to roll 3d6 and then roll that many 12-sided dice, you could use "(3d6)d12". Anywhere in the string where you would put a number can be replaced by another roll in parentheses. Nesting is effectively unlimited. The notation also allows for "rules" which are added after the die string and are separated with periods. Each rule name or its abbreviation is immediately followed by a number. Where it makes sense, this number may be negative. Multiple rules can be combined and are applied in the order shown in the following table: Rule (abbr) Notes ---------------------------------------------------------------------------- premod (b)* Adds # to each die roll before any other rules. reroll (rr) If a die roll is <= #, the die is rerolled. extra (x) If a die roll is >= #, an extra die is rolled. postmod (a)* Adds # to each die roll after any reroll/extra rules. max (hi) Sets the maximum for any single die roll to # after mods. min (lo) Sets the minimum for any single die roll to # after mods. retry (rm) Retry misses up to # times. Requires the "hits" rule. drophigh (dh) Drops (discards) the highest # rolls. droplow (dl) Drops the lowest # rolls. keephigh (kh) Keeps only the highest # rolls. keeplow (kl) Keeps only the lowest # rolls. hits (h) Returns the count of hits (rolls >= #) instead of the sum. fails (f) Returns the count of fails (rolls <= #) instead of the sum. totalmax (th) Sets the maximum total after all rules/modifiers to #. totalmin (tl) Sets the minimum total after all rules/modifiers to #. ---------------------------------------------------------------------------- *The premod and postmod abbreviations of "m" and "mm" have been deprecated in favor of "b" and "a" (before and after), respectively. The hits and fails rules are mutually exclusive. A modifier (the "+2" in "2d4+2") affects the final result, regardless of whether it is the sum of the rolls or a count of hits/fails. The modifier operator can be "+" (addition), "-" (subtraction), "*" (multiplication), or "/" (integer division). The totalmax and totalmin rules are applied AFTER the modifier. Examples: 4d6.droplow1 (rolls 4d6, drops lowest roll) 3d6.reroll2 (rolls 3d6, rerolling any ones or twos) 8d6.hits5 (rolls 8d6, returns the count of "hit" rolls >= 5) 4d8.premod-2.min1 (rolls 4d8, subtracts 2 from each roll, with a minimum individual roll of 1) Example: You are playing Dust Tactics and your laser squad is firing. You have 8 total dice of lasers to fire. Hits are two of six sides on a Dust die, so hits5 is used to count a hit whenever a roll is 5 or 6. Lasers are special in that they "burn through", so each hit rolls an extra die that may result in another hit, ad infinitum. The extra5 rule is used so that any hit gets to roll an extra die. The final dice string is "8d6.hits5.extra5". Retrying misses allows additional rolls for any misses up to # of times. Using 4d6.hits5.retry2 as an example, the 4d6 rolls are 1,5,6,4 - two hits, two misses. The first retry re-rolls the two misses (1,4) resulting in 6,3. The second retry allows the 3 from the first retry attempt to be re-rolled. See also: TryDice llDice -------------------------------------------------------------------------------- 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 is needed so frequently, it's more optimized than calling CharsOnly(AInput, '##'). Example: DigitsOnly('1(800)555-1212') -> '18005551212' See also: CharsOnly, IsNumeric llStrings -------------------------------------------------------------------------------- function DirectoryIsEmpty(const ADir: string): Boolean; Returns True if the directory in question contains no files or subdirectories. It will also return True if the directory doesn't exist, so watch for that. llFiles -------------------------------------------------------------------------------- function DiskFreeByFile(const AFile: string): Int64; Calls DiskFree(n) for the drive letter specified in the path of the argument. If the filename does not include a path, the current directory is assumed. If the call fails on a UNC path, the function returns -1. llFiles -------------------------------------------------------------------------------- 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-neutral format is handy for storage or transmission and sorts naturally. The inverse of DtoS is the StoD function. 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'. See also: StoD, StoDDef, TryStoD, TtoS llDates -------------------------------------------------------------------------------- function Ellipsis(const S: string; const ALength: Integer; const ARight: Boolean = True): string; If a string is longer than the desired length, it is shortened and has an ellipsis (...) placed at the end. If ARight is False, the ellipsis will be placed on the left (beginning) of the string. llStrings -------------------------------------------------------------------------------- function EllipsisPath(const APath: string; const ALength: Integer): string; If a path string is longer than the desired length, middle subdirectories are replaced with an ellipsis until the total length is under the limit. Example: EllipsisPath('C:\Foo\BarBaz\Ray01.txt', 20) -> "C:\Foo\...\Ray01.txt" If there isn't enough room for even the final directory or file name, the left side will be truncated and replaced with an ellipsis, e.g. "...SuperLongDir\". The smallest possible return value is "..." for lengths <= 3. llFiles -------------------------------------------------------------------------------- function EncodeURLParam(const S: string): string; Encodes a URL parameter with percent/hex escaping after first converting to UTF-8. Meant for single parameters only, not entire URLs because it encodes things like equal signs and ampersands, which are used to separate parameters in a URL. llBytes -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- function Enquote(const S: string; const AQuote: Char = DefaultQuoteChar): string; Works much like QuotedStr & AnsiQuotedStr, but in one convenient function with a nice, short name. See also: Dequote llStrings -------------------------------------------------------------------------------- function EraseRegStrings(const ARegKey: string; const AList: TStrings): Boolean; Takes a list of name-value pairs and deletes the values with the same names from an HKCU registry key. Returns a boolean indicating the successful deletion of all the existing named settings. If the registry key does not exist, it will also return True. TStrings.Values doesn't work on blanks -- it removes the name from the list when the value is set to an empty string. Any values you want to erase that don't currently have a value can just be added to AList as a name without an equal sign. See Also: SaveRegStrings, LoadRegStrings llSettings -------------------------------------------------------------------------------- function EscapedReplace(const ASource, AOld, ANew, AEsc: string; const AFlags: TReplaceFlags; const ARemoveEsc: Boolean): string; Works just like StringReplace, but allows for escaped values to be skipped in the replacement. The escape value can be a single character or a string. Any AOld value that is preceeded by the AEsc string is not replaced with ANew. After completing your replacements, you will want to remove your escape sequence from the string as well. Set ARemoveEsc to True to have it removed. It is not done automatically in case you have multiple escaped values to replace. It only replaces AEsc+AOld with AOld, not every instance of AEsc. Known limitation: Escaped escape characters are not supported. llStrings -------------------------------------------------------------------------------- function EvalBoolExpr(const ABoolOp: TBooleanOperator; const A, B: Boolean): Boolean; The function returns the boolean result of (A operator B) except in the case of boNOT, when it returns (not A). If the operator is boNOOP, the function just returns A. TBooleanOperator = (boNOOP, boNOT, boAND, boOR, boXOR); See also: StrToBoolOp llBool -------------------------------------------------------------------------------- function EvalComparison(const ACompOp: TComparisonOperator; const A, B: string): Boolean; overload; function EvalComparison(const ACompOp: TComparisonOperator; const A, B: Integer): Boolean; overload; function EvalComparison(const ACompOp: TComparisonOperator; const A, B: Int64): Boolean; overload; function EvalComparison(const ACompOp: TComparisonOperator; const A, B: Extended): Boolean; overload; function EvalComparison(const ACompOp: TComparisonOperator; const A, B: Currency): Boolean; overload; The overloaded EvalComparison functions let you compare two values using a comparison operator and returns the boolean result of the expression (A operator B). If the operator is coNOOP, the function always returns True. TComparisonOperator = (coNOOP, coEQ, coNE, coLT, coGT, coLE, coGE); The Extended version works for Single, Double, Extended and TDateTime. Normal cautions apply when comparing floating point values for [in]equality. String comparisons are case sensitive. Examples: EvalComparison(coEQ, 0, 1) -> (0 = 1 evaluates to False) EvalComparison(coLT, 0, 1) -> (0 < 1 evaluates to True) See also: StrToCompOp llBool -------------------------------------------------------------------------------- function ExecuteCommand(const ACommand: string; const AWaitMS: Integer; const AShowWindow: Word = SW_SHOWNORMAL; const ACreateFlags: Cardinal = CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS): Cardinal; overload; function ExecuteCommand(const ACommand: string; const AWait: Boolean; const AShowWindow: Word = SW_SHOWNORMAL; const ACreateFlags: Cardinal = CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS): Cardinal; overload; Executes a command and optionally waits for it to finish. If waiting, the function returns the exit code of the process or WAIT_TIMEOUT if it times out before finishing. Otherwise, it returns zero (NO_ERROR, ERROR_SUCCESS) or GetLastError based on the success of CreateProcess. There are two overloads: An integer AWaitMS argument, and a boolean AWait. The integer variation takes the number of milliseconds to wait, 0 to not wait, or -1 to wait forever. The boolean overload calls the integer one using -1 for True and 0 for False. Adapted from Peter Below's WinExecAndWait32V2. See also: GetLastErrorStr llWinAPI -------------------------------------------------------------------------------- function ExpandEnvars(const S: string): string; A handy string-based wrapper around ExpandEnvironmentStrings. Turns things like "%SystemRoot%" into "C:\WINDOWS", etc. llWinAPI -------------------------------------------------------------------------------- function ExtractFileExtNoDot(const AFile: string): string; Just like ExtractFileExt, but removes the leading dot if present. llFiles -------------------------------------------------------------------------------- function ExtractFileNameNoExt(const AFile: string): string; Like ExtractFileName, but also removes any file extension. Example: ExtractFileNameNoExt('d:\path\file.ext') -> 'file' llFiles -------------------------------------------------------------------------------- function ExtractTZ(var VDate: string): string; Extracts a time zone from a DtoS-type string and returns it. The original input is updated by having the time zone removed. If there is no time zone, the result is blank and the argument remains unchanged. See also: DtoS llDates -------------------------------------------------------------------------------- function FFDate(const AFile: string; const Attr: Integer = 0): TDateTime; Retrieves a file's modified date/time from FindFirst, or zero if not found. Supply Attr if you need to find hidden files, etc. Directories are ignored. If given a wildcard instead of a single filename, the date of the newest file will be returned. See also: FileTimeToDateTime, FFSize, FFSize64 llFiles -------------------------------------------------------------------------------- function FFSize(const AFile: string; const Attr: Integer = 0): Integer; This actually just calls FFSize64 and caps the result at MaxInt. See also: FFSize64, FFDate llFiles -------------------------------------------------------------------------------- function FFSize64(const AFile: string; const Attr: Integer = 0): Int64; Unlike the FileSize function that requires a handle to an open file, this one just gets it from FindFirst. Supply Attr if you need to find hidden files, etc. Directories are ignored. Returns the size of the file(s) in bytes or -1 if not found. If given a wildcard instead of a filename, the sum of the sizes is returned. See also: FFSize, FFDate llFiles -------------------------------------------------------------------------------- function FileCopy(const ASource, ATarget: string; const APreserveAttr: Boolean = False; const APreserveTimes: Boolean = False; const AMove: Boolean = False): Boolean; Copies a file and returns True if successful. If the target file exists, it will be overwritten. If AMove is set to True, the original will be deleted after a successful copy. The Windows.CopyFile function copies a file along with its existing file attributes, last modified date, and encryption (if any, and assuming the target drive supports it). By default, this copies a file without all that extra baggage and sets the creation and last modified times to current. The attributes and/or file times CAN be preserved on the copy if either of the two optional arguments are set to True. llFiles -------------------------------------------------------------------------------- function FileTimeToDateTime(const AFileTime: TFileTime): TDateTime; Converts a TSearchRec.FindData file time to a TDateTime, adjusting for the local time zone. See also: TFileInfo, FFDate llFiles -------------------------------------------------------------------------------- function FindInPath(const AFile: string; out OResult: string): Boolean; Checks for the existence of a file in the current directory and PATH environment variable, returning True if found. The fully qualified name of the found file is placed into OResult. If found in the current directory, OResult will not contain a path, just the filename. If the input filename contains a path, it will be ignored/removed. llFiles -------------------------------------------------------------------------------- function FindPairPos(const S: string; const AIndex: Integer): Integer; Given a string and the index of a character of a matched pair (i.e. parentheses, square brackets, curly braces, or angle brackets) the function returns the index of its matching opposite, fully allowing for nested pairs. The function returns zero if the matching opposite is not found. If the character at the index is an opening pair character, the function seeks forward in the string for the closing character. If it is a closing pair character, it seeks backwards for the opening character. 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: FindPairPos('r = ((x + 5) * (y - z)) / 2', 5) -> 23 ^ ^ given this it finds this Formerly known as CloseBracketPos and ClosePairPos. See also: FindUnquotedPairPos, CloseQuotePos llStrings -------------------------------------------------------------------------------- function FindUnquotedPairPos(const S: string; const AIndex: Integer; const AQuote: Char = DefaultQuoteChar): Integer; Works just like FindPairPos, but makes sure the matching pair character is not inside a quoted section of the string. The character at the starting index is assumed to not be quoted. See also: FindPairPos, UnquotedPos, CloseQuotePos llStrings -------------------------------------------------------------------------------- function FirstOfMonth(const ADate: TDateTime): TDateTime; Returns the TDateTime argument adjusted to the first of the given month. The time remains unchanged. llDates -------------------------------------------------------------------------------- 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' A blank filename will result in blank output. See also: SameFile llFiles -------------------------------------------------------------------------------- function FormatDateTimeEx(const AFormat: string; ADateTime: TDateTime): string; Adds a few new specifiers on top of those supported by FormatDateTime: Spec Displays xd Day of the year (001..366) xi ISO8601 day of the week (1..7, starting Monday) xk Day of the week (1..7, starting Sunday) xq Quarter (1..4) xw Week of the year (01..53) xy Year that goes with xw (4-digit) xz Year that goes with xw (2-digit) See also: ReplaceDateTokens llDates -------------------------------------------------------------------------------- function FormatDigits(const ADigits, AFormat: string; const AEscape: Char = '\'): string; Right-justifies/overlays a string of characters (usually digits) into a format string. Especially handy for phone number/SSN 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('bar', 'foo') -> '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. To output a literal 0 or 9, precede it with the escape character. The default escape character is a backslash, but it can be changed if you need backslashes in your output. Example: FormatDigits('123456', '999\0999') -> '1230456' llStrings -------------------------------------------------------------------------------- function GCD(const a, b: Integer): Integer; Calculates the greatest common divisor of two integers (Euclidean algorithm). llNumbers -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- procedure GetBinNames(BinStrings: TStrings); Fills a TStrings variable with the names of the available paper sources (bins) for the currently selected printer. The bin numbers that you can pass to the ChangePrinterBin() function are stored in the Objects part of the list. Retrieved from the Delphi newsgroup archives, originally by Peter Below. llPrinting -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- function GetLastErrorStr(const AErrNo: Cardinal = 0; const AIncludeErrNo: Boolean = False): 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. If AIncludeErrNo is True, the error number will be appended in parentheses. llWinAPI -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- function GetTCPTableData(const ACSVData: TStringList; const AOption: TTCPTableOption = ttoAll): Cardinal; Gets Netstat-like info on TCP connections in a simple CSV format: LocalIp,LocalPort,RemoteIp,RemotePort,StateString,State,PID Returns an error code, or zero if successful. The AOption argument specifies whether you want only listening, only established connections, or all TCP connections (the default). TTCPTableOption = (ttoListener, ttoConnections, ttoAll); This unit contains all the types needed to work with the GetExtendedTcpTable API function. This function is primarily here as an example but can be useful as a "quickie". This function loads the dll, gets the proc address, and then calls the GetTCPTableDataF function that takes the function pointer as the first argument. If you have loaded the dll and proc address on your own (if making repeated calls), you can just call that function directly. See also: GetTCPTableDataF llNetwork -------------------------------------------------------------------------------- function GetTCPTableDataF(const AFunction: TGetExtendedTcpTable; const ACSVData: TStringList; const AOption: TTCPTableOption = ttoAll): Cardinal; The workhorse behind GetTCPTableData, used when you already have the dll loaded and the GetExtendedTcpTable function pointer available. See also: GetTCPTableData llNetwork -------------------------------------------------------------------------------- function GetTempDir(const ASlash: Boolean = False): string; Just a wrapper around the Windows.GetTempPath function that returns a string so you don't have to declare a buffer. ASlash determines if the result ends with a trailing backslash. llWinAPI -------------------------------------------------------------------------------- function GetTempFile(const APath: string; const APrefix: string = 'TMP'): string; Wrapper around GetTempFileName() that conveniently returns a string. llWinAPI -------------------------------------------------------------------------------- function GetWinCompName: string; Returns the current Windows computer name or a null string if unsuccessful. llWinAPI -------------------------------------------------------------------------------- function GetWinDir(const Slash: Boolean = False): string; Wrapper around GetWindowsDirectory() that conveniently returns a string. The Slash argument will add a trailing backslash if True, and remove one if False (the default). llWinAPI -------------------------------------------------------------------------------- function GetWinUserName: string; Returns the current Windows username or a null string if unsuccessful. llWinAPI -------------------------------------------------------------------------------- function HasChars(const S, AChars: string): Boolean; Returns True if the string contains at least one of the characters present in AChars. It can contain other characters as well. Returns False if AChars is blank. llStrings -------------------------------------------------------------------------------- function HexToBytes(const AHex: string): TBytes; Converts a string of hex characters into an array of bytes. The input MUST be an even number of hex characters. Raises an EConvertError on invalid input. See also: BytesToHex, HtoI, IsHex llBytes -------------------------------------------------------------------------------- function HtoI(const AHexChar: Char): Integer; Returns a value 0..15 for a valid hex character, or -1 otherwise. Case insensitive. See also: IsHex, BytesToHex, HexToBytes llBytes -------------------------------------------------------------------------------- function IIf(const ABool: Boolean; const ATrue, AFalse: string): string; overload; function IIf(const ABool: Boolean; const ATrue, AFalse: Integer): Integer; overload; function IIf(const ABool: Boolean; const ATrue, AFalse: Int64): Int64; overload; function IIf(const ABool: Boolean; const ATrue, AFalse: Extended): Extended; overload; function IIf(const ABool: Boolean; const ATrue, AFalse: Currency): Currency; overload; Inline-If functions overloaded for common data types. The Extended version works for Single, Double, Extended and TDateTime. llBool -------------------------------------------------------------------------------- function IndexOfPartial(const AItems: TStrings; const AValue: string; const ADefault: Integer = -1; const ACaseSensitive: Boolean = True): Integer; Returns the index of the first value in AItems that starts with AValue. If there is no match, the function returns ADefault (-1). See also: IndexOfPrefix, StartsWith llStrings -------------------------------------------------------------------------------- function IndexOfPrefix(const AItems: TStrings; const AValue: string; const ADefault: Integer = -1; const ACaseSensitive: Boolean = True): Integer; Returns the index of the AItems value that is the prefix/start of AValue. If AValue does not start with any of the AItems strings, the function returns ADefault (-1). See also: IndexOfPartial, StartsWith llStrings -------------------------------------------------------------------------------- function Int64toIPv4(const AIP: Int64): string; Converts an Int64 into a dotted-decimal IPv4 address string. If the numeric IP is out of range (0..MaxIPv4) the function returns an empty string. MaxIPv4 is a constant representing High(Cardinal). See also: CardinaltoIPv4, IPv4toCardinal, IPv4toInt64, IsValidIPv4 llNetwork -------------------------------------------------------------------------------- function InterleaveStrings(const S1, S2: string): string; Combines two strings by alternating characters. Example: InterleaveStrings('abc', '1234') -> 'a1b2c34' llStrings -------------------------------------------------------------------------------- function IntervalStr(const AInterval: TDateTime; const LoP: TDateTimePrecision = dtpHour; const HiP: TDateTimePrecision = dtpSecond; const ADaySeparator: string = 'd'): string; Converts a TDateTime into an interval string representing its duration since zero. 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 result in a format of "hh:nn:ss". 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 dtpDay the format will have the number of days and the day separator string ("d" by default) prepended, e.g. "1d04:13:22". Otherwise, the hour value will be as large as it needs to be, e.g. "48:56:13". Another common day separator might be a period, "1.04:13:22". If LoP is dtpMonth, 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. If LoP is dtpYear, the format will be the same as setting LoP to dtpDay if the interval is greater than 24 hours, otherwise dtpHour. If LoP is dtpDecade or less, the format will be the smallest possible value of the format "0d0h0m0.000s" up to HiP. If LoP is dtpCentury or less, spaces will be added between each separator: "0d 0h 0m 0.000s". If ADaySeparator is a comma-separated list of four values, those will be used as the separators regardless of LoP. The following constants are available to make the options easier to remember: lopTrimZeros = dtpMonth; // Synonyms for IntervalStr lopDayOrHour = dtpYear; lopSmallSeps = dtpDecade; lopSpaceSeps = dtpCentury; llDates -------------------------------------------------------------------------------- function IntToBinStr(const Value: Integer; const Bits: Integer = 0): string; overload; function IntToBinStr(const Value: Cardinal; const Bits: Integer = 0): string; overload; function IntToBinStr(const Value: Int64; const Bits: Integer = 0): string; overload; Converts an integer type number into a binary string (e.g. '0101'). If the number of Bits is not supplied or is less than 1, the default size of the input numeric is used. See also: BinStrToCardinal, BinStrToInt, BinStrToInt64 llNumbers -------------------------------------------------------------------------------- function IPv4toCardinal(const AIP: string; const ABigEndian: Boolean = False): Cardinal; Converts a dotted-decimal IPv4 address string into a Cardinal. If the string is not a valid IP, the function returns zero. Note that 0.0.0.0 is a valid IP address, but will also return zero. If you are expecting that, IPv4toInt64 may be a better choice as it will return -1 for an invalid address. If ABigEndian is True, the bytes will be reversed in the result. See also: CardinaltoIPv4, Int64toIPv4, IPv4toInt64, IsValidIPv4, SwapEndianCardinal llNetwork -------------------------------------------------------------------------------- function IPv4toInt64(const AIP: string): Int64; Converts a dotted-decimal IPv4 address string into an Int64. If the string is not a valid IP, the function returns -1. See also: CardinaltoIPv4, Int64toIPv4, IPv4toCardinal, IsValidIPv4 llNetwork -------------------------------------------------------------------------------- function IsAlpha(const S: string; const Index: Integer = 0; const AllowSpace: Boolean = False): Boolean; Returns True if the character at the requested Index is an ASCII letter, or a space if AllowSpace is True. If Index is zero, the entire string is checked. A blank string always returns False. See also: IsCharsOnly, IsDigit, IsNumeric llStrings -------------------------------------------------------------------------------- function IsBase64(const ABase64: string): Boolean; Returns True if the input string contains only valid Base64 characters with a legal length. See also: BytesToBase64, Base64ToBytes llBytes -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- function IsCharsOnly(const S, AValid: string; const AIndex: Integer = 0): Boolean; Returns a boolean indicating whether the string would be returned unchanged from a call to CharsOnly. In other words, it contains only the characters in AValid. If AIndex is non-zero, only the character at the given index is checked. An empty string returns False. See also: CharsOnly, IsAlpha, IsDigit, IsNumeric llStrings -------------------------------------------------------------------------------- function IsDigit(const S: string; const Index: Integer): Boolean; Returns true if the character at the given index is a number 0-9. An empty string or index out of range returns False. If you want to check the whole string, use IsNumeric. llStrings -------------------------------------------------------------------------------- function IsDotDir(const SR: TSearchRec): Boolean; Returns True if the TSearchRec is the . or .. directory. See also: IsSubDir llFiles -------------------------------------------------------------------------------- function IsHex(const AHex: string): Boolean; Returns True if the input string contains only valid hex characters. An empty string returns True. Case insensitive. See also: HtoI, BytesToHex, HexToBytes llBytes -------------------------------------------------------------------------------- function IsLegalFilename(const S: string): Boolean; Returns True if the filename does not contain any of the reserved characters or names that are not valid for a Windows filename. The function expects the filename ONLY -- do not include the path because slashes are reserved characters. This can also be used for a directory name as long as it is passed by itself. Blank input returns False. The list of reserved characters, names and other rules according to MSDN: < (less than) > (greater than) : (colon) " (double quote) / (forward slash) \ (backslash) | (vertical bar or pipe) ? (question mark) * (asterisk) Any character with an ASCII value 0..31. Reserved names: CON, PRN, AUX, NUL, COM1..COM9, and LPT1..LPT9 Do not end a file or directory name with a space or a period. 2017-05-26: Added reserved name $MFT after reading about a crash bug when used as a directory name. llFiles -------------------------------------------------------------------------------- function IsNumeric(const S: string; const Index: Integer = 0; const AllowSymbols: Boolean = False): Boolean; Returns True if the character at the given Index is a numeric digit. If the AllowSymbols argument is True, it also allows a decimal and leading +/-. If Index is zero, the entire string is checked. An empty string returns False. See also: IsCharsOnly, IsDigit, DigitsOnly llStrings -------------------------------------------------------------------------------- function ISO8601Date(const S: string; const LocalOffset: TDateTime = 0): TDateTime; Converts a string in ISO 8601 format (yyyy-mm-ddThh:nn:ss.zzz) into a TDateTime. The time separator can be either a "T" or a space. It handles both extended (with separators) and basic (no separators) formats. If a time zone specifier is present (Z, +, -) the time will be converted to UTC and then local time based on the given offset (or not, if zero). Time zones offsets can appear in any of the following formats: Z, +00, +05, -07:00, +0600 See also: ISO8601Str llDates -------------------------------------------------------------------------------- function ISO8601Str(const D: TDateTime; const P: TDateTimePrecision; const UseT: Boolean = True; const Basic: Boolean = False): string; Converts a TDateTime into an ISO 8601 format date string, carried out to the precision specified by P. If UseT is True, the string will contain "T" between the date and time elements (yyyy-mm-ddThh:nn:ss.zzz). If Basic is True, no separators will be used in the output (yyyymmddThhnnss). If the value holds only a time, the date portion will not be output. If you want a timezone offset, you need to add it yourself. See also: ISO8601Date, TimeZoneStr llDates -------------------------------------------------------------------------------- function IsPrivateIPv4(const AIP: Int64): Boolean; overload; function IsPrivateIPv4(const AIP: string): Boolean; overload; Returns True if the IP argument is within one of the private IP ranges: 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 See also: MatchesCIDRv4 llNetwork -------------------------------------------------------------------------------- function IsSubDir(const SR: TSearchRec): Boolean; Returns True if the TSearchRec contains a directory that is neither . nor .. See also: IsDotDir llFiles -------------------------------------------------------------------------------- function IsValidIPv4(const AIP: Int64): Boolean; overload; function IsValidIPv4(const AIP: string): Boolean; overload; Returns True if the IP argument is valid. "0.0.0.0" to "255.255.255.255" for strings, or 0..MaxIPv4 for Int64. See also: IPv4toCardinal, IPv4toInt64 llNetwork -------------------------------------------------------------------------------- function IsValidTimeZone(const ATZ: string; const AllowZulu: Boolean = True; const AllowColon: Boolean = True; const AllowHourOnly: Boolean = True): Boolean; Validates a time zone string in +/-HH[[:]MM] format. A blank is always valid. If AllowZulu is True, it may be "Z". If AllowColon is False, a colon separator is not allowed. If AllowHourOnly is False, minutes are required even if zero. llDates -------------------------------------------------------------------------------- function KillDirectory(const ADir: string): Boolean; Removes a directory and anything it may contain, including subdirectories. Returns a boolean indicating success. llWinAPI -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- function LastOfMonth(const ADate: TDateTime): TDateTime; Returns the TDateTime argument adjusted to the last day of the given month. llDates -------------------------------------------------------------------------------- function LastPos(const Substr, S: string; const Offset: Integer = 0): Integer; Essentially a backwards-looking PosEx. Returns the position of the last occurrence 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 See also: UnquotedLastPos llStrings -------------------------------------------------------------------------------- function Leftmost(const S: string; const ACount: Integer): string; Returns the leftmost characters of the input string. If the input is shorter than the count, all of the input will be returned. Sounds just like the Copy function, right? Not quite! A negative count will return all but the right # characters. Examples: Leftmost('foobar', 3) = 'foo' Leftmost('foobar', 10) = 'foobar' Leftmost('foobar', -1) = 'fooba' See also: Rightmost llStrings -------------------------------------------------------------------------------- function ListFiles(const AList: TStrings; const Path: string; const Attr: Integer = 0; const IncludePath: Boolean = False; const Recurse: Boolean = False; const UseFileInfo: Boolean = False): Integer; Adds filenames to a TStrings/TStringList list and returns the count of files added. Directories are excluded from the list. The TStringList.Object of each file is set to the TSearchrec.Time value to allow you to filter or sort on the time after retrieving the list. If UseFileInfo is set to True, Objects will instead be filled with TFileInfo objects. IMPORTANT: The caller is responsible for freeing these objects! 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 *only* files with the archive attribute, use -faArchive. By default the filenames are added to the list without modification. If IncludePath is True, the filenames will be fully qualified based on the Path. If you want the function to recurse subdirectories, set Recurse to True. All subdirectories are followed, not just those matching the wildcard. Recursion forces IncludePath to True. Hidden subdirectories will be recursed if the main Attr argument includes faHidden. See also: StringListIntObjectSortCompare, SortFileInfoByDate/Size, TFileInfo, TRecurser llFiles -------------------------------------------------------------------------------- function ListSubdirs(const AList: TStrings; const ADir: string; const IncludeHidden: Boolean = False; const IncludePath: Boolean = False): Integer; Adds the subdirectories of ADir to a TStrings/TStringList list and returns the count of subdirectories added. Set IncludeHidden to True if you want hidden directories included in the list. Set IncludePath to True if you want the fully qualified pathname added to the list. If False (the default), just the subdirectory names will be added. llFiles -------------------------------------------------------------------------------- function LoadFormPos(const ARegKey: string; const AForm: TForm; const AOtherInfo: TStrings = nil; const APrefix: string = ''; const APosOnly: Boolean = False): Boolean; overload; function LoadFormPos(const AReg: TRegistry; const AForm: TForm; const AOtherInfo: TStrings = nil; const APrefix: string = ''; const APosOnly: Boolean = False): Boolean; overload; Loads a form's position and size from registry settings previously saved to HKCU by the SaveFormPos function. Returns True if the settings were present and loaded. If there are no saved settings and the form has an owner, it centers the form over its owner. If AOtherInfo is provided as a list of name-value pairs, matching items in the registry key will be retrieved and written to the list. Missing AOtherInfo values do not affect the function's boolean return value, so it is suggested that you preload the list with sensible default values. APrefix is a string tacked on to the beginning of the registry entries so you can store more than one form's position in the same key. A common usage would be the form's ClassName. APrefix does not apply to AOtherInfo value names. If APosOnly is True, only the form's position will be retrieved, not its size. There are two overloaded versions of the function - One that takes a registry key name, and one that takes an already open TRegistry object. The former will open the key, call the latter, then close the key. See also: SaveFormPos llSettings -------------------------------------------------------------------------------- function LoadRegStrings(const ARegKey: string; const AList: TStrings): Boolean; Takes a list of name-value pairs and loads the values with the same names from an HKCU registry key. Returns a boolean indicating success in opening the key. Missing registry values simply leave the default value alone and do not affect the return value. TStrings.Values doesn't work on blanks -- it removes the name from the list when the value is set to an empty string. Any values you want to read that don't currently have a value can just be added to AList as a name followed by an equal sign. Likewise, any blank values read in are stored in the list this way. See Also: SaveRegStrings, EraseRegStrings llSettings -------------------------------------------------------------------------------- function LoadStream(const FS: TFileStream; const ATrimEOF: Boolean = True; const ATrimBOM: Boolean = True): string; Reads an entire file stream into a string and returns the result. Clearly, this is meant for small files. Handles non-ASCII files (UTF-8, etc.). The file stream is assumed to be open and positioned at zero. Otherwise you will just get the rest of the file starting at the current position without benefit of any BOM if available. If ATrimEOF is True (the default), trailing EOF characters (0x1A, ASCII 26) will be removed from the result if present. If ATrimBOM is True (the default), a byte order marker will be removed from the start of the result if present. llFileUtils -------------------------------------------------------------------------------- function LoadStrings(const AFile: string; const AList: TStrings): Boolean; This function is a substitute for TStrings.LoadFromFile when the file may be in use by a program that is writing to it, such as a busy log file. TStrings.LoadFromFile opens the file with fmShareDenyWrite and raises an exception if unable to open the file with those rights. This function uses fmShareDenyNone and then calls TStrings.LoadFromStream, returning True if successful. See also: FSReadLn, FSReadLnGetEOL llFiles -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- function MatchesCIDRv4(const AAddr, AMask, ABits: Int64): Boolean; overload; function MatchesCIDRv4(const AAddr, AMask: string): Boolean; overload; Returns a boolean indicating if the IPv4 dotted-decimal IP Address (or Int64 equivalent) matches the CIDR-format network mask. Example: MatchesCIDRv4('192.168.1.1', '192.168.0.0/16') --> True If the string mask does not include a number of bits after a slash, it is assumed to be "/0". A zero bit mask simply checks for an exact match. A 32 bit mask matches *anything* (always returns True). If either value is not a valid IP or the number of bits is not 0..32, the function will return False. See also: IPv4toCardinal, IPv4toInt64, IsValidIPv4 llNetwork -------------------------------------------------------------------------------- function MatchingMonthDay(const ADate: TDateTime; const ADay: Integer): Boolean; Returns True if the given date matches the specified day of the month. 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: MatchingMonthDay(<2008-09-24>, 15) -> False (no match) MatchingMonthDay(<2008-09-24>, 24) -> True (match) MatchingMonthDay(<2008-09-30>, 31) -> True (match, last DOM) See Also: NextMonthDay, PrevMonthDay Formerly known as "ValidMonthDay" which was too vague. llDates -------------------------------------------------------------------------------- function MinMax(const AMin, AValue, AMax: Integer): Integer; overload; function MinMax(const AMin, AValue, AMax: Cardinal): Cardinal; 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 -------------------------------------------------------------------------------- function MinutesToTime(const AMinutes: Cardinal): TDateTime; Turns a positive integer number of minutes into the fractional part of a TDateTime. The integer portion of the result will always be zero, even if the input is greater than the number of minutes in a day (MinsPerDay=1440). See also: TimeToMinutes llDates -------------------------------------------------------------------------------- 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. Personally, I don't think there is a definitive way to calculate this. 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. See also: DateDiff, AgeOnDate llDates -------------------------------------------------------------------------------- function MonthStrToInt(const AMonth: string): Integer; Returns the integer month number 1..12 of the given month string. It is case-insensitive and works with full month names or their abbreviations as defined by the ShortMonthNames variable. Returns zero if the string is not valid. Example: MonthStrToInt('January') -> 1 llDates -------------------------------------------------------------------------------- procedure MsgAlert(const Text: string; const Caption: string = ''; AForm: TForm = nil); Shows a CenteredMsgDlg with a warning icon and an OK button. llMsgDlg -------------------------------------------------------------------------------- procedure MsgError(const Text: string; const Caption: string = ''; AForm: TForm = nil); Shows a CenteredMsgDlg with an error icon and an OK button. llMsgDlg -------------------------------------------------------------------------------- procedure MsgInfo(const Text: string; const Caption: string = ''; AForm: TForm = nil); Shows a CenteredMsgDlg with an information icon and an OK button. llMsgDlg -------------------------------------------------------------------------------- function MsgOKCancel(const Text: string; const Caption: string = ''; AForm: TForm = nil): Boolean; Returns a True/False answer to an OK/Cancel CenteredMsgDlg. llMsgDlg -------------------------------------------------------------------------------- function MsgRetryCancel(const Text: string; const Caption: string = ''; AForm: TForm = nil): Boolean; Returns a True/False answer to a Retry/Cancel CenteredMsgDlg. llMsgDlg -------------------------------------------------------------------------------- function MsgYesNo(const Text: string; const Caption: string = ''; AForm: TForm = nil): Boolean; Returns a True/False answer to a Yes/No CenteredMsgDlg. llMsgDlg -------------------------------------------------------------------------------- function MsgYesNoCancel(const Text: string; const Caption: string = ''; AForm: TForm = nil): Integer; Returns mrYes, mrNo or mrCancel in response to a CenteredMsgDlg. llMsgDlg -------------------------------------------------------------------------------- function MStoTime(const AMS: Cardinal): TDateTime; Turns a positive integer number of milliseconds into the fractional part of a TDateTime. The integer portion of the result will always be zero, even if the input is greater than the number of milliseconds in a day. See also: TimeToMS, TimeToSeconds, MinutesToTime, TimeToMinutes llDates -------------------------------------------------------------------------------- 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. The time, if any, is unchanged. 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, MatchingMonthDay llDates -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- function OrdinalStr(const AInt: Integer): string; Returns the number as an ordinal, like '1st', '2nd', '3rd', '4th', etc. Negative values are converted to positive. llNumbers -------------------------------------------------------------------------------- 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. If is negative, the string will only be padded if shorter than the desired length. Longer strings will be left alone. See also: PadL, PadR llStrings -------------------------------------------------------------------------------- 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. If is negative, the string will only be padded if shorter than the desired length. Longer strings will be left alone. See also: PadC, PadR llStrings -------------------------------------------------------------------------------- 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. If is negative, the string will only be padded if shorter than the desired length. Longer strings will be left alone. See also: PadC, PadL llStrings -------------------------------------------------------------------------------- function ParseCSVLine(const ALine: string; Fields: TStrings; var MultiLine: Boolean; const EatWhitespace: Boolean = False; const AQuote: Char = '"'; const ADelim: Char = ','; const ANewline: string = #10; const APreserveQuoting: Boolean = False): 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/CRLF) when storing multiline fields in the Fields stringlist. Default=#10/LF. Other possible values: '\r\n', '
', etc. APreserveQuoting - If set to True, quoting will not be stripped out of the fields parsed from the line of text. The Fields data will contain the raw data, with any surrounding quotes and doubled literals still present. --- 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, something fairly common like "\r\n", 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]); The CSV RFC: http://www.ietf.org/rfc/rfc4180.txt See Also: SimpleCSV, TokenList llCSV -------------------------------------------------------------------------------- procedure PostKey(hWindow: HWND; Key: Word); Sends a WM_KEYDOWN & WM_KEYUP to a window/control/component. llWinAPI -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- function PrettySize(const ASize: Int64): string; Turns a file size into a "pretty" string in one of these formats: 999 B 999 KB 999[.9] MB 999[.9] GB The default size strings are B, KB, MB and GB, all preceded by a space. You can change these defaults by assigning new values to the PrettySizeB|KB|MB|GB variables. The default values are defined as the constants DefaultPrettySizeB|KB|MB|GB. The number of decimal places on MB & GB values is determined by the PrettySizeDecimals variable, which defaults to 1 (DefaultPrettySizeDecimals). Setting it to zero will just round to the nearest whole number. 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 PrettySizeKilo. Its default value is the constant DefaultPrettySizeKilo. llFiles -------------------------------------------------------------------------------- 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: MatchingMonthDay, NextMonthDay llDates -------------------------------------------------------------------------------- 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+. llDice -------------------------------------------------------------------------------- function ReadSimpleFile(const AFile: string; out OContent: string): Boolean; The counterpart to CreateSimpleFile. If the file exists and can be read, the function returns True and OContent will contain the file contents. If the file does not exist or cannot be opened, the function returns False. See also: CreateEmptyFile, CreateSimpleFile, LoadStream llFileUtils -------------------------------------------------------------------------------- function ReadStreamLine(const FS: TFileStream; var VEncoding: TEncoding; out OLine, OEOL: string): Boolean; overload; function ReadStreamLine(const FS: TFileStream; var VEncoding: TEncoding; out OLine: string): Boolean; overload; Reads the next line of text from an open TFileStream and places it into the OLine argument. The function returns True if a line was read, False if at EOF. The file stream's position is left at the start of the next line of text. The function properly handles non-ASCII (UTF-8, etc.) files, and accepts any combination of end-of-line characters: CRLF, LF, or CR. The EOL character(s) found at the end of the current line are placed into the OEOL argument (if using that version of the overloaded function). If the line was ended by the end of the file, OEOL will be blank. VEncoding should be set to nil on the first call for a given file. The first read will look for a BOM and set VEncoding so it can be used on all subsequent calls. See also: ReadStreamLineEOL llFileUtils -------------------------------------------------------------------------------- function ReadStreamLineEOL(const FS: TFileStream; const EOL: string; var VEncoding: TEncoding; out OLine: string): Boolean; Just like ReadStreamLine, but you specify the exact end-of-line character(s) to look for. EOL can be virtually any string of single-byte characters, but must match exactly. The function returns True if a line was read, False if at EOF. VEncoding should be set to nil on the first call for a given file. The first read will look for a BOM and set VEncoding so it can be used on all subsequent calls. See also: ReadStreamLine llFileUtils -------------------------------------------------------------------------------- function RecycleFile(const AFile: string): Boolean; Silently deletes a file and allows it to be recovered from the Recycle Bin. Returns a boolean indicating success. Note that this doesn't work from a service. It only works when called from an interactive user session. llWinAPI -------------------------------------------------------------------------------- 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. The tokens ARE case-sensitive: %y=Year, 2-digit %Y=Year, 4-digit %m=Month 01..12 %M=Month abbreviation Jan..Dec %L=Month name January..December %d=Day of the month 01..31 %D=Day of the year 001..366 %h=Hour 00..23 %H=Hour 01..12 %n=Minute 00..59 %s=Second 00..59 %z=Millisecond 000..999 %I=ISO8601 day of the week 1..7 (starting Monday) %J=Day of the week Sunday..Saturday %k=Day of the week 1..7 (starting Sunday) %K=Day of the week abbreviation Sun..Sat %p=a/p %P=AM/PM (based on locale) %q=Quarter 1..4 %w=Week of the Year 01..53 %x=Year that goes with week#, 2-digit %X=Year that goes with week#, 4-digit %C=Force any words returned to upper-case (e.g. Wed -> WED) %c=Force any words returned to lower-case (e.g. Wed -> wed) See also: FormatDateTimeEx llDates -------------------------------------------------------------------------------- function ReplaceFile(const ATarget, ASource: string): Boolean; Replaces the target file with the source file and returns a boolean indicating success. The following sequence of operations is used to prevent loss of the original in case anything goes wrong: 1. Rename Target to Temp filename (if it exists) 2. Move Source to Target (works even if across volumes) 3. Delete Temp file (if needed) llWinAPI -------------------------------------------------------------------------------- procedure ReverseStringList(const AList: TStringList); Simply reverses the order of a TStringList. Handy if you need a list sorted in descending order, but don't want to write a custom sort function. If AList.Sorted is True when called, it will be set to False. See also: StringListIntObjectSortCompare, StringListStringObjectSortCompare llStrings -------------------------------------------------------------------------------- function Rightmost(const S: string; const ACount: Integer): string; Similar to the D7+ StrUtils.RightStr function, this returns the rightmost characters of the input string. If the input is shorter than the count, all of the input will be returned. This variation also allows for a negative count that returns all but the left # characters. Examples: Rightmost('foobar', 3) = 'bar' Rightmost('foobar', 10) = 'foobar' Rightmost('foobar', -1) = 'oobar' See also: Leftmost llStrings -------------------------------------------------------------------------------- function RotL(const AValue: Word; const ABits: Integer): Word; overload; function RotL(const AValue, ABits: Integer): Integer; overload; function RotL(const AValue: Cardinal; const ABits: Integer): Cardinal; overload; function RotL(const AValue: Int64; const ABits: Integer): Int64; overload; function RotR(const AValue: Word; const ABits: Integer): Word; overload; function RotR(const AValue, ABits: Integer): Integer; overload; function RotR(const AValue: Cardinal; const ABits: Integer): Cardinal; overload; function RotR(const AValue: Int64; const ABits: Integer): Int64; overload; Bitwise left/right rotation function for various integer types. llNumbers -------------------------------------------------------------------------------- function SameFile(const F1, F2: string; const APath: string = ''): Boolean; Takes two filenames and returns a boolean indicating whether the two strings actually refer to the same file. Internally, it uses FixFilePath to do so. If you do not supply the APath argument, it defaults to the current directory. Example: SameFile('foo.txt', '.\Foo.txt') -> True The function will return True if both filenames are blank. See also: FixFilePath llFiles -------------------------------------------------------------------------------- function SameTime(const d1, d2: TDateTime): Boolean; Compares two TDateTime values numerically, and returns True if the difference between them is less than one millisecond. Handy constant: OneMillisecond llDates -------------------------------------------------------------------------------- function SaveFormPos(const ARegKey: string; const AForm: TForm; const AOtherInfo: TStrings = nil; const APrefix: string = ''; const ASaveFlag: Integer = sfpDefault): Boolean; overload; function SaveFormPos(const AReg: TRegistry; const AForm: TForm; const AOtherInfo: TStrings = nil; const APrefix: string = ''; const ASaveFlag: Integer = sfpDefault): Boolean; overload; Saves a form's position and size to HKCU. Values named Top, Left, Height, Width, and Maximized are saved. Use LoadFormPos to read these settings back. If you plan on storing the position of more than one form, give each a unique registry key or use APrefix to differentiate the values. A common value for APrefix would be the form's ClassName. A boolean value in this key called "SaveWindowPos" (sfpFlagName) controls whether these settings get saved or not. It defaults to True. You can change this value (e.g. make it a user preference) with the ASaveFlag argument and handy constants: sfpTrue - Set it to True sfpDefault - Use the currently stored value or create it as True sfpFalse - Set it to False (LoadFormPos still reads previously saved values) sfpDelete - Set it to False and delete any saved values including AOtherInfo The function returns True if the save flag ends up True and the settings were saved. The optional AOtherInfo argument allows you to provide a tag-along list of name-value pairs that will be stored as strings to the same registry key and can later be retrieved using LoadFormPos. This is handy for other window state information like splitter positions, etc. Note that APrefix does NOT apply to the value names in AOtherInfo. If an AOtherInfo value is set to the special constant sfpOtherInfoDelete, its registry entry will be removed if present. There are two overloaded versions of the function - One that takes a registry key name, and one that takes an already open TRegistry object. The former will open the key, call the latter, then close the key. See also: LoadFormPos llSettings -------------------------------------------------------------------------------- function SaveRegStrings(const ARegKey: string; const AList: TStrings): Boolean; Takes a list of name-value pairs and saves them to an HKCU registry key as strings. Returns a boolean indicating the success of opening the registry key. TStrings.Values doesn't work on blanks -- it removes the name from the list when the value is set to an empty string. If you want to save a blank value, just add the item name to the list without an equal sign/value. See Also: LoadRegStrings, EraseRegStrings llSettings -------------------------------------------------------------------------------- procedure ScrollToEnd(AMemo: TMemo); Moves the cursor position and scrolls to the end of the text in a TMemo. llControls -------------------------------------------------------------------------------- procedure ScrollToTop(AMemo: TMemo); Moves the cursor position and scrolls to the start of the text in a TMemo. llControls -------------------------------------------------------------------------------- function SecondsToTime(const ASeconds: Cardinal): TDateTime; Turns a positive integer number of seconds into the fractional part of a TDateTime. The integer portion of the result will always be zero, even if the input is greater than the number of seconds in a day (SecsPerDay=86400). See also: TimeToSeconds, MinutesToTime, TimeToMinutes llDates -------------------------------------------------------------------------------- function SecureDelete(const AFile: string; const APasses: Integer = 1): Boolean; Deletes a file after overwriting it. Returns a boolean indicating success. The file will be overwritten APasses times, alternating between zeros and ones. llFiles -------------------------------------------------------------------------------- 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 llStrings.IndexOfPartial to find partial matches. llControls -------------------------------------------------------------------------------- procedure SetTabStops(const AMemo: TMemo; const ATabChars: Integer); Sets the approximate size of a tab stop in a TMemo. llControls -------------------------------------------------------------------------------- function SimpleCSV(const ALine: string; Fields: TStrings; const EatWhitespace: Boolean = True): Boolean; This is a simplified wrapper to ParseCSVLine. You need not provide a boolean MultiLine variable and EatWhitespace is set to True by default. 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. See also: ParseCSVLine, TokenList llCSV -------------------------------------------------------------------------------- function SimpleDecode(const AValue: string): string; Reverses the encoding done by SimpleEncode. Example: SimpleDecode('foo\0x0D0A\bar') -> 'foo'#13#10'bar' See also: SimpleEncode llStrings -------------------------------------------------------------------------------- function SimpleEncode(const AValue: string): string; Changes any low binary characters (under ASCII 32/Hex 0x20) to encoded values, leaving the string as human-readable as possible. The low binary characters are encoded as hex and surrounded by "\0x" and "\". Multiple adjacent characters will create a run of encoding between a single set of start/end markers. Example: SimpleEncode('foo'#13#10'bar') -> 'foo\0x0D0A\bar' See also: SimpleDecode llStrings -------------------------------------------------------------------------------- procedure SizeMemoLines(Canvas: TCanvas; Lines: TStrings; const MMLength, MMIndent: Integer); Given a stringlist full of text, the function will adjust the length of each line to best fit/wrap on a line of a given length in millimeters. When finished, this same stringlist will contain the adjusted lines. If desired, the first line can be indented (shortened) by a certain length in millimeters by supplying a MMIndent value > 0. To indent all lines except the first, pass a negative MMIndent value. llPrinting -------------------------------------------------------------------------------- function SlashPath(const APath: string; const ASlash: Boolean): string; Calls AddSlash/StripSlash based on a True/False value, respectively. llFiles -------------------------------------------------------------------------------- function SortFileInfoByTime(List: TStringList; Index1, Index2: Integer): Integer; function SortFileInfoByTimeDesc(List: TStringList; Index1, Index2: Integer): Integer; function SortFileInfoBySize(List: TStringList; Index1, Index2: Integer): Integer; function SortFileInfoBySizeDesc(List: TStringList; Index1, Index2: Integer): Integer; Use with TStringList.CustomSort after calling ListFiles with FileInfo to sort the list by the files' date or size. Items that compare equally on the main comparison will be compared by string value and will honor the list's CaseSensitive setting. See also: ListFiles, ReverseStringList, TFileInfo llFiles -------------------------------------------------------------------------------- function Spaces(const ALen: Integer): string; Returns a string of spaces. llStrings -------------------------------------------------------------------------------- function StartCase(const S: string): string; Capitalizes the first letter of each word in a string. Words are assumed to be separated by whitespace. Characters other than the first of each word are not modified. If you want the other characters in each word set to lower case, provide the function with all lower case input, i.e. StartCase(LowerCase(S)). Note: It is not called TitleCase since that technically doesn't capitalize some words (see Wikipedia article "Letter case"). See also: TllCharCase, ChangeCase llStrings -------------------------------------------------------------------------------- function StartsWith(const APart, AWhole: string; const CaseSensitive: Boolean = True): Boolean; Returns True if is the beginning of . It will also return True if is null (''). CaseSensitive is self-explanatory. llStrings -------------------------------------------------------------------------------- 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. The case-insensitive True values are anything that starts with Y, T, +, *, or a non-zero numeric. llBool -------------------------------------------------------------------------------- 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. The minimum accepted input is a 4-digit year. Invalid input will raise an EConvertError exception. See StoDDef and TryStoD for additional options when dealing with untrusted input. See also: DtoS, StoDDef, TryStoD llDates -------------------------------------------------------------------------------- function StoDDef(const DS: string; const ADefault: TDateTime): TDateTime; StoDDef is to StoD as StrToIntDef is to StrToInt. See also: DtoS, StoD, TryStoD llDates -------------------------------------------------------------------------------- function StoDTP(const S: string; const ADefault: TDateTimePrecision): TDateTimePrecision; Finds a string in the dtpWords array, or a single character in the dtpLetters array and returns the corresponding TDateTimePrecision. Matching is case insensitive. The default value is returned if no match is found. See also: TDateTimePrecision llDates -------------------------------------------------------------------------------- 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. It is the inverse of the TtoS function. Input strings shorter than the length of the full format will have their missing values defaulted to zero. Any extra digits beyond 9 are simply ignored (HL7 time values often have milliseconds carried out to four places). Invalid input will raise an EConvertError exception. See StoTDef and TryStoT for additional options when dealing with untrusted input. See also: TtoS, StoTDef, TryStoT llDates -------------------------------------------------------------------------------- function StoTDef(const TS: string; const ADefault: TDateTime): TDateTime; StoTDef is to StoT as StrToIntDef is to StrToInt. See also: TtoS, StoT, TryStoT llDates -------------------------------------------------------------------------------- procedure StringListDeepFree(const AList: TStringList; const AMaxDepth: Integer); Traverses a TStringList, freeing any assigned objects and emptying the list. If AMaxDepth is > 0, it also recurses into those objects that are TStringLists and does the same until AMaxDepth is reached. If AMaxDepth is negative, recursion continues until the bottom is reached. llStrings -------------------------------------------------------------------------------- function StringListIntObjectSortCompare(List: TStringList; Index1, Index2: Integer): Integer; Use with TStringList.CustomSort to sort a stringlist by the integer values of its Objects properties. Items that compare equally on the object value will be compared by string value and will honor the list's CaseSensitive setting. To sort descending, just follow the sort with a call to ReverseStringList. See also: ReverseStringList, StringListStringObjectSortCompare, ListFiles llStrings -------------------------------------------------------------------------------- function StringListStringObjectSortCompare(List: TStringList; Index1, Index2: Integer): Integer; Use with TStringList.CustomSort to sort a stringlist by the TStringObject values of its Objects properties. Items that compare equally on the object value will be compared by string value. Both comparisons will honor the list's CaseSensitive setting. Unassigned objects will be compared as if they contain an empty string. See also: TStringObject, ReverseStringList, StringListIntObjectSortCompare llStrings -------------------------------------------------------------------------------- function StripDot(const AExt: string): string; Removes a dot from the beginning of an extension if present. llFiles -------------------------------------------------------------------------------- function StripExt(const AFile: string): string; Just an easy-to-type wrapper for ChangeFileExt(AFilename, ''); llFiles -------------------------------------------------------------------------------- function StripParens(const S: string): string; Strips parentheses, square brackets, curly braces, angle brackets or quote characters from the input string if the first character in the string is one of those characters and the last character is the matching pair. See also: DequoteStr llStrings -------------------------------------------------------------------------------- function StripSlash(const APath: string): string; Just a shorter way to write ExcludeTrailingPathDelimiter. llFiles -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- function StrToBoolOp(const S: string): TBooleanOperator; Takes a string and returns the TBooleanOperator equivalent. The comparison is case-insensitive. If a blank or other invalid value is supplied, the function returns boNOOP. TBooleanOperator = (boNOOP, boNOT, boAND, boOR, boXOR); The following constant arrays define the valid input for this function, and can also be used to convert a TBooleanOperator to a string: BoolOpWords: array[TBooleanOperator] of string = ('', 'NOT', 'AND', 'OR', 'XOR'); BoolOpSymbols: array[TBooleanOperator] of string = ('', '!', '&&', '||', '^'); See also: EvalBoolExpr llBool -------------------------------------------------------------------------------- function StrToCompOp(const S: string): TComparisonOperator; Takes a string and returns the equivalent TComparisonOperator. The comparison is case-insensitive. If a blank or other invalid value is supplied, the function returns coNOOP. TComparisonOperator = (coNOOP, coEQ, coNE, coLT, coGT, coLE, coGE); The following constant arrays define the valid input for this function, and can also be used to convert a TComparisonOperator to a string: CompOpLetters: array[TComparisonOperator] of string = ('', 'EQ', 'NE', 'LT', 'GT', 'LE', 'GE'); CompOpWords: array[TComparisonOperator] of string = ('', 'Equal', 'Not equal', 'Less than', 'Greater than', 'Less than or equal', 'Greater than or equal'); CompOpSymbols: array[TComparisonOperator] of string = ('', '=', '<>', '<', '>', '<=', '>='); CompOpAltSymbols: array[TComparisonOperator] of string = ('', '==', '!=', '<', '>', '<=', '>='); See also: EvalComparison llBool -------------------------------------------------------------------------------- function SwapEndianCardinal(const AValue: Cardinal): Cardinal; register; Reverses the bytes in a 32-bit Cardinal. See also: SwapEndianInt llNumbers -------------------------------------------------------------------------------- function SwapEndianInt(const AValue: Integer): Integer; register; Reverses the bytes in a 32-bit Integer. See also: SwapEndianCardinal llNumbers -------------------------------------------------------------------------------- TCSVQuotingStyle = (qsNormal, qsSpaces, qsEverything); TCSVFile = class(TObject) public constructor Create; overload; destructor Destroy; override; // Property defaults: property DataError: string read FDataError; // '' property Delimiter: Char read GetDelim write SetDelim; // comma (,) property EatWhitespace: Boolean read FEatWS write FEatWS; // False property Filename: string read FFilename write FFilename; // '' property HasHeader: Boolean read FHasHeader write SetHasHeader; // False property HasMultiLine: Boolean read FHasMultiLine; property NewLine: string read FNewLine write SetNewLine; // '\r\n' property QuoteChar: Char read GetQuote write SetQuote; // double quote (") property QuotingStyle: TCSVQuotingStyle read FQStyle write SetQStyle; // qsNormal property RowCount: Integer read GetRowCount; property CountsDifferAtRow: Integer read FDiffRow write FDiffRow; procedure AddField(const ARow: Integer; const Value: string); procedure AddRow; procedure ChangeDelimiters(const ANewQuote, ANewDelim: Char); procedure ClearRow(const ARow: Integer); procedure DeleteField(const ARow, ACol: Integer); procedure DeleteRow(const ARow: Integer); function FieldCount(const ARow: Integer): Integer; function GetColByName(const AName: string): Integer; function GetFieldName(const ACol: Integer): string; function GetValue(const ARow, ACol: Integer): string; procedure InsertField(const ARow, ACol: Integer; const Value: string); procedure InsertRow(const ARow: Integer); procedure LoadFromFile(const AFilename: string; const AHasHeader: Boolean); procedure MoveField(const ARow, AFrom, ATo: Integer); procedure MoveRow(const AFrom, ATo: Integer); function RowText(const ARow: Integer): string; procedure Save(const ASplitMultiLine: Boolean = False); procedure SaveToFile(const AFilename: string; const ASplitMultiLine: Boolean = False); procedure SetFieldName(const ACol: Integer; const AName: string); procedure SetValue(const ARow, ACol: Integer; const Value: string); end; TCSVFile is a utility class for working with CSV files. It uses the other CSV utility routines to parse and store the data. It loads the whole file and keeps it in memory using a TStringList, so be sensible about the size of files you load. It's not designed for giant files! The file is parsed entirely when loaded to check for errors. If DataError is non-blank after calling LoadFromFile, you have bad data. Parsing stops as soon as the first error is encountered, so the data should not be used. If all of the rows in the file don't have the same field count, the CountsDifferAtRow property will contain the row index of the first row that has a different count than previous rows. This is only checked at load time. During the load, any multi-line fields are put back together using the NewLine property. When saving, set the ASplitMultiLine argument to True to have them broken back out into multiple lines at each instance of NewLine. The HasMultiLine property will be set to True after loading if any of these were found. Only one row is kept parsed into fields at a time. Trying to group all field operations for a given row together will minimize the need to re-parse the data. The methods related to Field Names only work when HasHeader is True. Calling GetColByName without a header will return -1. A number of the methods that operate on fields can operate over the whole file if the ARow argument is set to -1. The following methods allow this: AddField DeleteField InsertField MoveField SetValue (Doesn't affect row zero if HasHeader is True) The quote and delimiter characters can be changed by setting the respective properties. If changing both at the same time, the ChangeDelimiters method is less expensive. The QuotingStyle only affects how the data is stored and written. Any quoting style can be read regardless of what the current setting is. qsNormal quotes only values that contain the delimiter or other quotes (standard DelimitedText style). qsSpaces will also quote any fields that contain spaces or tabs (uses BuildCSV), since these confuse TStringList.CommaText without StrictDelimiter. qsEverything will quote every field (using BuildCSV with ForceQuote=True). The ClearRow method deletes the data from the fields in a row, but leaves the fields there (1,2,3 -> ,,) while DeleteRow removes the row entirely. The Add/ InsertRow methods create new rows with the correct number of empty fields. The RowText function returns an entire row as it is currently stored, with quoting and delimiters. See also: BuildCSV, ParseCSVLine llCSV -------------------------------------------------------------------------------- TDateTimePrecision = (dtpMillennium, dtpCentury, dtpDecade, dtpYear, dtpMonth, dtpDay, dtpHour, dtpMinute, dtpSecond, dtpMillisecond, dtpE = 0, dtpC = 1, dtpX = 2, dtpY = 3, dtpM = 4, dtpD = 5, dtpH = 6, dtpN = 7, dtpS = 8, dtpZ = 9, dtpMSec = 9); const dtpWords: array[TDateTimePrecision] of string = ('Millennium', 'Century', 'Decade', 'Year', 'Month', 'Day', 'Hour', 'Minute', 'Second', 'Millisecond'); dtpLetters: array[TDateTimePrecision] of Char = ('E', 'C', 'X', 'Y', 'M', 'D', 'H', 'N', 'S', 'Z'); // E=Epoch, X=Roman ten The TDateTimePrecision enumeration is used by various functions in the llDates unit. The dtpMillisecond and dtpMSec values are synonyms, as are the shortened variations that match the format string letters (dtpY, dtpM, etc.). See also: StoDTP llDates -------------------------------------------------------------------------------- TDayOfWeek = (dowAnyDay, dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday, dowAny = 0, dowSun = 1, dowMon = 2, dowTue = 3, dowWed = 4, dowThu = 5, dowFri = 6, dowSat = 7); The ordinal values of the TDayOfWeek enumeration equate to the return values of the DayOfWeek function for dowSunday..dowSaturday. The abbreviated names are equivalent to their longer counterparts. dowAny[Day] is a custom value (0) used by the WeekdayOfMonth function. See also: WeekdayOfMonth llDates -------------------------------------------------------------------------------- TFileInfo = class(TObject) public constructor Create; constructor CreateSR(const APath: string; const SR: TSearchRec); property Filename: string read GetFilename write SetFilename; // with path property Path: string read FPath write SetPath; property Name: string read FName write FName; property Time: Integer read FTime write FTime; property Size: Int64 read FSize write FSize; property Attr: Integer read FAttr write FAttr; property Timestamp: TDateTime read FModified write FModified; // Synonym property Modified: TDateTime read FModified write FModified; property Created: TDateTime read FCreated write FCreated; property Accessed: TDateTime read FAccessed write FAccessed; procedure Clone(const ASource: TFileInfo); procedure Update(const APath: string; const SR: TSearchRec); function UpdateFromFile(const AFile: string): Boolean; end; A TObject-based version of TSearchRec that includes a path and pre-converted file times. When storing these in TStringList.Objects, you can use the following functions with TStringList.CustomSort to sort them by time or size: SortFileInfoByTime SortFileInfoByTimeDesc SortFileInfoBySize SortFileInfoBySizeDesc See also: TRecurser llFiles -------------------------------------------------------------------------------- function TimeToMinutes(const ATime: TDateTime): Cardinal; Takes the time portion of a TDateTime and turns it into a positive integer number of minutes past midnight 0..1439. See also: MinutesToTime, SecondsToTime, TimeToSeconds llDates -------------------------------------------------------------------------------- function TimeToMS(const ATime: TDateTime): Cardinal; Takes the time portion of a TDateTime and turns it into a positive integer number of milliseconds past midnight. See also: MStoTime, SecondsToTime, MinutesToTime, TimeToMinutes llDates -------------------------------------------------------------------------------- function TimeToSeconds(const ATime: TDateTime): Cardinal; Takes the time portion of a TDateTime and turns it into a positive integer number of seconds past midnight 0..86399 See also: SecondsToTime, MinutesToTime, TimeToMinutes llDates -------------------------------------------------------------------------------- function TimeZoneOffset(const ATimeZoneStr: string): TDateTime; Converts a time zone string in +/-hh[[:]mm] format into a TDateTime UTC offset value. If the input is blank or "Z", the offset is zero. This offset is added to local time to convert to UTC. See also: TimeZoneStr llDates -------------------------------------------------------------------------------- function TimeZoneStr(const ALocalOffset: TDateTime; const AZulu: Boolean = True; const AColon: Boolean = True; const AHourOnly: Boolean = True): string; Converts a local UTC offset TDateTime into a string in ISO 8601 format, suitable for concatenation to an ISO8601 date/time string. The default format is "+/-hh[:mm]", returning "Z" if the offset is zero. Set AZulu to False if you want "+00[:00]" instead of "Z". Setting AColon to False excludes the colon separator, like "+0700". If AHourOnly is set to False, the minutes will always be included, zero or otherwise. By default, minutes are only included when non-zero. See also: ISO8601Str, TimeZoneOffset llDates -------------------------------------------------------------------------------- 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 IndexOfEx(const Value, Offset: 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 -------------------------------------------------------------------------------- TLikePattern = class(TObject) public constructor Create; destructor Destroy; override; // defaults: property AnyChar: Char read FAnyChar write SetAnyChar; // % property OneChar: Char read FOneChar write SetOneChar; // _ property EscChar: Char read FEscChar write SetEscChar; // \ property CaseSensitive: Boolean read FCaseSen write SetCaseSen; // True property Pattern: string read FPattern write SetPattern; property ErrorOnBlankPattern: Boolean read FBlankError write FBlankError; function Matches(const S: string): Boolean; procedure Reset; // Resets to default state, blank pattern function TryPattern(const APattern: string; out OError: 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). Setting an invalid pattern (e.g. conflicting wildcards, no text, etc.) will raise an ELikePatternError exception. The TryPattern function allows you to attempt setting the pattern from untrusted input to see if it is valid without having to set up your own try/except. If the function returns False, the error message will be in the OError argument. Changing the wildcards or escape character will clear the current pattern, so set the pattern last after changing the other settings. Spaces and letters are not allowed as wildcard/escape characters. Attempting to set an invalid wildcard character will silently leave the character unchanged. The CaseSensitive property is True by default. This setting can be changed without losing the current pattern, but it does cause it to be re-parsed. Calling Matches against a blank/unassigned pattern will raise an exception by default. The ErrorOnBlankPattern property controls this. If the property is set to False, calling Matches against a blank or failed pattern will just return False instead of raising an exception. Usage example: LP := TLikePattern.Create; try LP.Pattern := '%ray%'; if LP.Matches(sSomeString) then ... finally LP.Free; end; llLike -------------------------------------------------------------------------------- TllCharCase = (ecNormal, ecUpperCase, ecLowerCase, ecStartCase); Based on StdCtrls.TEditCharCase for use with the ChangeCase function. This variation adds ecStartCase to capitalize the first letter of each word. It is not called ecTitleCase since that technically doesn't capitalize some words (see Wikipedia article "Letter case"). llStrings -------------------------------------------------------------------------------- TllPrefs = class(TObject) public constructor Create; destructor Destroy; override; property Count: Integer read GetCount; property Items[AName: string]: TllPrefItem read GetItemByName; default; property RegKey: string read FRegKey write FRegKey; function Add(const AName: string; const AType: TllPrefType): TllPrefItem; procedure Clear; procedure Delete(const AName: string; const ADeleteFromRegistry: Boolean); function ItemByIndex(const AIndex: Integer): TllPrefItem; function IndexOfName(const AName: string): Integer; // -1 if not found function Load: Boolean; function LoadPrefsFromKey: Boolean; function Save: Boolean; end; Maintains a list of values stored in the registry. Example usage: Prefs := TllPrefs.Create; Prefs.RegKey := 'Software\RayMarron\LogicLib'; // Required Prefs.Add('Max', ptInteger).AsInt := 10; // Set a default value when added Prefs.Add('Title', ptString).AsStr := 'foo'; Prefs.Load; ... Label.Caption := Prefs['Title'].AsStr; ... Prefs.Save; Prefs.Free; Each preference's Name must be unique (case-insensitive). An assertion will be raised if a duplicate name is added. Each preference's PrefType property is one of the following values: TllPrefType = (ptBoolean, ptCurrency, ptDateTime, ptFloat, ptInteger, ptString, ptEncodedString); An encoded string is stored/retrieved using SimpleEncode/SimpleDecode. Get/Set the preference's value using one of the As... properties: AsBool, AsCurr, AsDate, AsFloat, AsInt, and AsStr. The Load/Save functions return True if successful. Only defined values are loaded and saved. If a value does not exist in the registry, it defaults to its current value; Assign each value a sensible default when Added. Set the MemoryOnly property if a value should not be saved to the registry. See also: TllRegistry, SimpleDecode, SimpleEncode llSettings -------------------------------------------------------------------------------- TllRegistry = class(TRegistry) public function DefBool(const AName: string; const ADefault: Boolean): Boolean; function DefCurr(const AName: string; const ADefault: Currency): Currency; function DefDate(const AName: string; const ADefault: TDateTime): TDateTime; function DefFloat(const AName: string; const ADefault: Double): Double; function DefInt(const AName: string; const ADefault: Integer): Integer; function DefStr(const AName, ADefault: string): string; end; A subclass of TRegistry that adds some default read methods with nice, short names. If the value does not exist, the default value is returned. Internally, they all work like this (DefStr example): if ValueExists(AName) then Result := ReadString(AName) else Result := ADefault; llSettings -------------------------------------------------------------------------------- TLogicIni = class(TObject) public constructor Create; overload; constructor Create(const AFileName: string; const AWantComments: Boolean = True; const APreserveWhitespace: Boolean = False); overload; destructor Destroy; override; property CaseSensitive: Boolean read GetCaseSensitive write SetCaseSensitive; property Dirty: Boolean read FDirty; property FileName: string read FFileName write FFileName; property OldDateTimeFormat: Boolean read FOldDates write FOldDates; property PreserveWhitespace: Boolean read FPreserveWS write FPreserveWS; property SectionCount: Integer read GetSectionCount; property SectionName[Index: Integer]: string read GetSectionName; property Sorted: Boolean read GetSorted write SetSorted; property WantComments: Boolean read FWantComments write SetWantComments; procedure Clear; procedure ClearSection(const Section: string); // Leaves empty section function CopySection(const Source, Target: string): Boolean; procedure DeleteKey(const Section, Ident: string); procedure DeleteValue(const Section, Ident: string); procedure EraseSection(const Section: string); // Removes completely procedure GetStrings(Strings: TStrings; const AWantComments: Boolean); procedure LoadFromFile(const AFileName: string); function ReadBool(const Section, Ident: string; Default: Boolean): Boolean; function ReadDate(const Section, Ident: string; Default: TDateTime): TDateTime; function ReadDateTime(const Section, Ident: string; Default: TDateTime): TDateTime; function ReadFloat(const Section, Ident: string; Default: Double): Double; function ReadInteger(const Section, Ident: string; Default: Longint): Longint; function ReadInt64(const Section, Ident: string; Default: Int64): Int64; procedure ReadSections(Strings: TStrings); procedure ReadSectionValues(const Section: string; Strings: TStrings; const AWantComments: Boolean = True); function ReadString(const Section, Ident, Default: string): string; function ReadTime(const Section, Ident: string; Default: TDateTime): TDateTime; function RenameSection(const AOld, ANew: string): Boolean; procedure SaveToFile(const AFileName: string); function SectionExists(const Section: string): Boolean; procedure SetStrings(Strings: TStrings); procedure SortSections; procedure SortValues; procedure UpdateFile; function ValueExists(const Section, Ident: string): Boolean; procedure WriteBool(const Section, Ident: string; Value: Boolean); procedure WriteDate(const Section, Ident: string; Value: TDateTime); procedure WriteDateTime(const Section, Ident: string; Value: TDateTime; const P: TDateTimePrecision = dtpSecond); procedure WriteFloat(const Section, Ident: string; Value: Double); procedure WriteInteger(const Section, Ident: string; Value: Longint); procedure WriteInt64(const Section, Ident: string; Value: Int64); procedure WriteSectionValues(const Section: string; Strings: TStrings); procedure WriteString(const Section, Ident, Value: string); 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 and related 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 (''). When reading a value, the default is only returned if the value is not present in the ini file at all. If present and set to blank, the blank (or data type equivalent) is returned. This allows you to distinguish between a missing value and one deliberately set to blank. Because TStringLists remove a name when the value is set to blank, values that are set to blank are stored as empty double quotes (""), defined in the handy constant IniBlankValue. When you read and write individual values, blanks are automatically translated from/to this value. To remove a value completely, use the DeleteValue method. When you read a whole section, blanks will still be listed with the empty quotes. 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. If you want the name remembered for later UpdateFile calls, set FileName as well. 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 -------------------------------------------------------------------------------- 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; procedure RemoveDeletedFiles; 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. Changing the ParentMenu property after creation will re-load the MRU from the current registry key. 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). Setting the RegistryKey property after creation will re-load the MRU from the new location. Set the OnClick event to be notified when the user clicks on one of the items in the MRU. The Sender will be the menuitem that was clicked, and the Caption of that menu item contains the selected value. It is not necessary (but harmless) to call Update when responding to this event - the MRU already did so prior to firing it. By default, AutoSave is False, and you must call the Save method to save the state of the MRU (usually in OnCloseQuery) to the registry. If set to True, the MRU will automatically save its data to the registry whenever it is updated. The Erase method deletes any previously stored registry values and sets AutoSave to False. If you want to be notified when the MRU list changes, assign the OnChange event. In your program, whenever you open a file (the MRU can be used to keep track of anything, not just files), just call the Update method with the text of the item you just selected/opened. The item will be added to the MRU or moved to the top if already present. 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. You can also call the RemoveDeletedFiles procedure to easily check for and get rid of deleted files. llMRU -------------------------------------------------------------------------------- procedure TokenList(const AText, AToken: string; const AList: TStrings); overload; procedure TokenList(const AText, AToken: string; const AList: TStrings; const AQuote: Char); overload; Breaks up a string at each occurrence of and adds these substrings to a TStrings descendant, . The list is not cleared first, so do this manually if desired. If the input is blank, nothing is added to the list. Tokens longer than a single character are fully supported. The two overloaded versions control how quoting is handled. In the version without a quote character, quoting is totally ignored and the string is split at every instance of the token. The version with a quote character will ignore quoted instances of the token and preserves all quoting and spaces when adding items to the list. Contrast with ParseCSVLine, which unquotes and optionally trims the separated values. See also: ParseCSVLine, SimpleCSV llStrings -------------------------------------------------------------------------------- TRecurser = class(TObject) public constructor Create; property Wildcard: string read GetWildcard write SetWildcard; property Attr: Integer read GetAttr write SetAttr; property MinDepth: Integer read FMinDepth write FMinDepth; property MaxDepth: Integer read FMaxDepth write FMaxDepth; property Sorting: TFileSorting read FSorting write FSorting; property SortDescending: Boolean read FSortDesc write FSortDesc; property CustomSort: TStringListSortCompare read FCustomSort write FCustomSort; property OnFile: TNotifyEvent read FOnFile write FOnFile; property OnBeforeSub: TNotifyEvent read FOnBeforeSub write FOnBeforeSub; property OnAfterSub: TNotifyEvent read FOnAfterSub write FOnAfterSub; property Cancelled: Boolean read FCancel write FCancel; property Skip: Boolean read FSkip write FSkip; property FullPath: string read FFullPath; property FileInfo: TFileInfo read FFileInfo; property Event: Char read FEvent; property Depth: Integer read FDepth; property Bottom: Integer read FBottom; property ErrorStr: string read FError; function Process: Boolean; end; Use TRecurser to perform actions on files and/or subdirectories while recursing a directory tree. Set Wildcard to the starting directory and file wildcard you want to process, controls the filenames that are processed. Subdirectories are processed in alphabetical order. The OnFile action is called for every file that matches the wildcard, in the order determined by the Sorting option. The OnBeforeSub action is called before each subdirectory is entered. The OnAfterSub action is called after processing a subdirectory, and could be used if you wanted to do something like remove empty subdirectories after deleting files. ----- Read/Write Properties (default) Wildcard Set this to the initial directory and file wildcard, e.g. 'D\Path\*.*'. If a path is not included, the current directory (at the time the property is set) is assumed. Attr (0) This value is passed as the Attr argument to FindFirst to control what types of files you want to find based on file attributes. It defaults to zero, which is all normal files. Hidden subdirectories will be recursed if Attr includes faHidden. If Attr is negative, only files that match the attribute mask exactly will be added to the list. For example, to *only* include files with the archive attribute set, use -faArchive. MinDepth (-1) If you don't want to start processing until you get to a certain level of subdirectory, set this. The initial directory has a depth of zero. For example, if you wanted to skip files in the starting directory and process them in subdirectories only, set MinDepth := 1. Defaults to -1 (no minimum). MaxDepth (MaxInt) If you want to recurse only to a certain subdirectory depth, set this. The initial directory has a depth of zero. Defaults to MaxInt (no maximum). Sorting (sortNatural) Choose the order that files from a directory are sorted in before calling the OnFile events. The TFileSorting options are sortNatural (the order they are returned by FindFirst/FindNext), sortName, sortTime, sortSize, or sortCustom. If custom, the CustomSort procedure must also be assigned. SortDescending (False) Set to True if you want the files sorted in descending order based on the Sorting option. This is done by simply reversing the stringlist's order after sorting in ascending order. SortDescending is ignored when Sorting is sortNatural. CustomSort (nil) A TStringListSortCompare function to use when Sorting is set to sortCustom. The list's Objects are populated with TFileInfo objects. If SortDescending is True, the list will be reversed after sorting with this function. OnFile Set this to a standard TNotifyEvent procedure to call for each file found. It is passed a reference to the TRecurser as Sender. FullPath will be set to the fully qualified filename. If you need additional information about the file (date, size, etc.), reference the FileInfo property. OnBeforeSub OnAfterSub Set these to a TNotifyEvent procedure to call before and/or after processing a subdirectory, respectively. These procs are not called on the starting directory, only subdirectories. The proc is passed a reference to the TRecurser object as Sender. FullPath will be set to the fully qualified subdirectory name including a trailing backslash. Cancelled (False) Cancelled can be set in any of the event procedures to cancel the process and return. If cancelled, the Process function returns False and ErrorStr will be set to 'Cancelled'. Skip Skip can be set in the OnFile or OnBeforeSub events to skip processing of the current directory and its children. Sibling directories and their children will continue to be processed. Setting it during OnFile will stop processing any remaining files from the current directory, and won't enter any of its subdirectories. Setting it from OnBeforeSub will prevent entering that particular subdirectory and will skip the call to OnAfterSub. ----- Readonly Properties FullPath Reference this during an event procedure to get the name of the file or subdirectory being processed. Directory names will always have a trailing backslash. If Process fails, FullPath can tell you where it stopped. FileInfo This TFileInfo object contains information about the current file being processed. It is available only during the OnFile event, and is otherwise unassigned. Event If you wanted to use a single procedure for all three events, this character can be used to tell you which one is currently being called: F=OnFile, B=OnBeforeSub, A=OnAfterSub. Depth The current depth of the directory being processed. The starting directory has a depth of zero. In the OnBeforeSub and OnAfterSub events, Depth is the depth of the subdirectory's parent, not the depth inside the subdirectory. Example: Wildcard='D:\Foo\*.*', OnAfterSub for D:\Foo\Bar\ reports a Depth of 0, the depth of D:\Foo where Bar lives. In the OnFile event for D:\Foo\Bar\test.txt, Depth would be 1. Bottom The highest depth reached during the process. If read during an event before Process has finished, it is the highest depth reached *so far*. ErrorStr If Process returns False, this will be set to the error that caused it to fail. If Cancelled was set to True, ErrorStr will be 'Cancelled'. ----- Methods Process After setting the other properties, call Process to begin the recursion. If successful, the function will return True. If it fails or is cancelled, it will return False and ErrorStr will contain the reason why. See also: TFileInfo llFiles -------------------------------------------------------------------------------- function TruncateLog(const AFile: string; const AMaxBytes: Int64; const APercentKept: Cardinal = 75; const ATextMarker: string = ''): Boolean; 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 or a bit less (up to the next end-of-line) to ensure that the log does not start with a partial line. Selecting a APercentKept to a value less than 100% is advised to reduce how often the file needs to be shortened. If ATextMarker is supplied, additional lines will be deleted until one that starts with ATextMarker is found (case-sensitive). If the text marker is not found at all, the log file will just be shortened as if it were not supplied. Returns a boolean indicating success. Not needing to shorten the file also counts as success. llFileUtils -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- function TryDice(const ADiceStr: string; out Value: Integer): Boolean; TryDice is to Dice as TryStrToInt is to StrToInt. llDice -------------------------------------------------------------------------------- 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. Limitation: It doesn't currently handle single- or double-quoted literals. llDates -------------------------------------------------------------------------------- function TryStoD(const DS: string; out ADate: TDateTime): Boolean; TryStoD is to StoD as TryStrToInt is to StrToInt. See also: DtoS, StoD, StoDDef llDates -------------------------------------------------------------------------------- function TryStoT(const TS: string; out ATime: TDateTime): Boolean; TryStoT is to StoT as TryStrToInt is to StrToInt. See also: DtoT, StoT, StoTDef llDates -------------------------------------------------------------------------------- TSimpleSchedule = class(TObject) public constructor Create; property AlwaysOn: Boolean read GetAlwaysOn; property CurrentState: Boolean read GetCurrentState; property ScheduleStr: string read GetScheduleStr; property StartMinute: Cardinal read FStartMin; property OnMinutes: Cardinal read FOnMin; property OffMinutes: Cardinal read FOffMin; function SetSchedule(const AStartMin, AOnMin, AOffMin: Cardinal): Boolean; function StateAt(const AWhen: TDateTime; out OUntil: TDateTime): Boolean; end; TSimpleSchedule is a class to define and monitor a simple schedule with a resolution of a minute. The primary application is inside a loop such as a service's Execute loop. There are three types of schedules: Always on, Start/Stop and Cycle. Always on is the default state of the schedule. A Start/Stop schedule is when the schedule starts at a given time and stops at another, once per day. A cycle schedule is where it is ON for a number of minutes and then OFF for a number of minutes, over and over. StartMinute is the number of minutes past midnight that the schedule starts. The schedule is always ON at the start time. OnMinutes is how long the schedule is ON, starting at the start time. When Always on, this value would be 1440 - the number of minutes in a day. OffMinutes is how long the schedule is OFF after being on. When Always on, this value is zero. On a Start/Stop schedule, the On+Off minutes must add up to 1440. On a cycle schedule, On+Off must be an even divisor of 1440 so the schedule starts at the same time each day. Use SetSchedule to assign the schedule values. They must all be set at once to properly validate them. The function will return True if the values are valid and the schedule was updated. If False, the schedule is not changed. Examples Start On Off ScheduleStr --------------------------------------------------------------- Always on 0 1440 0 Always on 09:00-17:00 540 480 960 Start 09:00 Stop 17:00 15 minute cycle 0 15 15 Start 00:00 On 15 Off 15 --------------------------------------------------------------- The StateAt function will return the state of the schedule at a given time (usually Now) where True is on and False is off. The output parameter OUntil will be set to the next time the schedule state will change. If the schedule is Always on, OUntil will be set to zero. If you just want the state of the schedule at the current time and don't care about when it will change next, read the CurrentState property. However, using StateAt and checking OUntil against the current time is more efficient in a tight loop. Usage example: var MySched: TSimpleSchedule; bState: Boolean; dtUntil: TDateTime; begin MySched := TSimpleSchedule.Create; try if not MySched.SetSchedule(FSchedStart, FSchedOn, FSchedOff) then raise Exception.Create('Invalid schedule!'); bState = MySched.StateAt(Now, dtUntil); // dtUntil = 0 when Always On repeat if bState then DoSomething; if (dtUntil > 0) and (Now >= dtUntil) then bState := MySched.StateAt(Now, dtUntil); Sleep(500); until Terminated; finally MySched.Free; end; end; The llSimpleSchedEdit unit contains a form that can be used to edit a schedule. Here is a usage example: var EditForm: TSchedEditForm; begin EditForm := TSchedEditForm.Create(Self); try EditForm.SetSchedule(FSchedStart, FSchedOn, FSchedOff); if EditForm.ShowModal = mrOk then begin EditForm.GetSchedule(FSchedStart, FSchedOn, FSchedOff); ScheduleLabel.Caption := EditForm.ScheduleStr; end; finally EditForm.Free; end; end; llSimpleSched -------------------------------------------------------------------------------- TStringObject = class(TObject) public Value: string; end; A simple object that contains only a string. Handy for storing a string in an Object property. See also: StringListStringObjectSortCompare llStrings -------------------------------------------------------------------------------- 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. See also: StoT, StoTDef, TryStoT llDates -------------------------------------------------------------------------------- function UniqueFileName(const AFile: string): string; Takes a fully qualified filename and if it exists, adds a number to the end of it until it no longer exists and returns the new filename. If the file does not exist, the filename is returned unchanged. Useful for exports and backups 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 -------------------------------------------------------------------------------- function UnquotedLastPos(const Substr, S: string; const Offset: Integer = 0; const AQuote: Char = DefaultQuoteChar): Integer; Works just like LastPos, but finds only substrings that are not contained in quotes. The quote character defaults to ". The substring at the starting offset is assumed to not be quoted. See also: LastPos llStrings -------------------------------------------------------------------------------- function UnquotedPos(const APart, AWhole: string; const AQuote: Char = DefaultQuoteChar; const AOffset: Integer = 1): Integer; Returns the position of the substring within the larger string, but only if the substring is not enclosed in quotes. The function returns zero if not found. The quote character defaults to ". Example: UnquotedPos('foo', '"foobar"=foo') -> 10 llStrings -------------------------------------------------------------------------------- function UnquotedWordPos(const AWord, AText: string; const AOffset: Integer = 1; const AQuote: Char = DefaultQuoteChar; const AWordChars: string = ''): Integer; A combination of UnquotedPos and WordPos to find the position of AWord within AText as an unquoted, separate word. See the other functions for argument information. Returns 0 if not found. See also: UnquotedPos, WordPos llStrings -------------------------------------------------------------------------------- function UnusedFileName(const AFile: string): string; deprecated; Deprecated. Use UniqueFileName instead. llFiles -------------------------------------------------------------------------------- procedure UpdateMRUList(const AList: TStrings; const AValue: string; const AMax: Integer = 0; const ACaseSensitive: Boolean = False); Updates a list of strings like a Most-Recently-Used list by inserting or moving the given value to the top of the list, and removing the oldest (last) entry if the list is full (AMax > 0). llMRU -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- function WeekdayNum(const ADate: TDateTime): Integer; Returns an integer indicating which weekday of the month the given date falls on. For example, 2017-01-22 is the 4th Sunday in January, so the function will return 4. Use DayOfWeek to find out which day of the week it is. See also: WeekdayOfMonth llDates -------------------------------------------------------------------------------- function WeekdayOfMonth(const ADate: TDateTime; const Nth: Integer; const DOW: TDayOfWeek): 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 (1), second (2), etc. If this value is greater than the actual number of times the weekday occurs in the given month, the last 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> See also: WeekdayNum llDates -------------------------------------------------------------------------------- function WildCopy(const ASource, ATarget: string; const Attr: Integer = 0; const ARecurse: Boolean = False; const APreserveAttr: Boolean = False; const APreserveTimes: Boolean = False; const ACopyEmptySubDirs: Boolean = False): Boolean; A wildcard copy function that returns a boolean indicating success. It uses the FileCopy function and its options to copy the files. It is always best to use fully qualified path names for both ASource and ATarget. ATarget can be just a directory where you want the files copied to, or it may include a filename wildcard. The target wildcard can be used to rename the files as they are copied (e.g. copy *.txt to *.bak). The root target directory must already exist, but any recursed subdirectories will be created if needed. The Attr argument is used when calling FindFirst, and will recurse into hidden subdirectories if it contains faHidden. See also: FileCopy, ListSubDirs, WildExists llFiles -------------------------------------------------------------------------------- function WildExists(const AFileSpec: string; const Attr: Integer = 0; const ARecurse: Boolean = False): Boolean; Given a wildcard filespec (and optional attribute), it will return true if any file specified by the wildcard exists, including looking in subdirectories if ARecurse is True. Also works as a substitute for FileExists. llFiles -------------------------------------------------------------------------------- function WordPos(const AWord, AText: string; const AOffset: Integer = 1; const AWordChars: 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 --------------------------------------------------------------------------------