The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 4,261 other subscribers

Delphi – class helper to get SourceFileName from an EAssertionFailed

Posted by jpluimers on 2009/05/06

In one of our applications, we have a default Config.xml file that is in our source tree, but it can be overridden by a Config.xml file relative to the application’s .EXE file.
So we have a two step process looking for the Config.xml, and we’d like to have the full path to the source file where the sources were build.
It seems the only way to get that, is by looking inside the Message of an EAssertionFailed exception.

So I wrote yet another class helper to get this code to work:

function GetConfigPathName(const Application: TApplication): string; overload;
var
  TriedFileNames: IStringListWrapper;
  SourceFileName: string;
begin
  TriedFileNames := TStringListWrapper.Create();
  Result := FindConfigPathName(Application, TriedFileNames);
  try
    AssertConfigFileNameExists(Result, Application.ExeName, TriedFileNames);
  except
    on E: EAssertionFailed do
    begin
      SourceFileName := E.GetSourceFileName();
      Result := FindConfigPathName(SourceFileName, TriedFileNames);
      AssertConfigFileNameExists(Result, Application.ExeName, SourceFileName, TriedFileNames);
    end;
  end;
end;

Note the IStringListWrapper; I’ll get back to that in a later blog-post.

The full code of the class helper is right below.
Just a few remarks:

  1. EAssertionFailed is in the SysUtils unit, and builds its Message by formatting a string using the SAssertError const in the SysConst unit as a mask.
  2. We use that mask to “parse” the Message from right to left. Parsing from left to right is virtually impossible, as the first string is the assertion message itself, and we don’t know how that looks like.
  3. If you are not using Delphi 2009, then replace the CharInSet call with a regular set check.
unit AssertionFailedHelperUnit;

interface

uses
  SysUtils;

type
  TAssertionFailedHelper = class helper for EAssertionFailed
  public
    function GetSourceFileName: string;
  end;

implementation

uses
  SysConst;

function TAssertionFailedHelper.GetSourceFileName: string;
var
  Mask: string;
  ExceptionMessage: string;
  OpeningParenthesesPosition: Integer;
begin
  //no valid configuration file found relative to C:\Program Files\CodeGear\RAD Studio\6.0\bin\bds.exe (C:\develop\ActiveMQDemo\common\src\ConfigHelperUnit.pas, line 84)
  //  SAssertError = '%s (%s, line %d)';
  // now create this string " (, line 0)" and use it to parse from right to left
  Mask := Format(SAssertError, ['', '', 0]);
  ExceptionMessage := Self.Message;
  // remove the closing ")"
  if (ExceptionMessage <> '') then
  begin
    Delete(ExceptionMessage, Length(ExceptionMessage), 1);
    Delete(Mask, Length(Mask), 1);
    // remove the "0" from the Mask
    Delete(Mask, Length(Mask), 1);
  end;
  while (ExceptionMessage <> '') and (CharInSet(ExceptionMessage[Length(ExceptionMessage)], ['0'..'9'])) do
    Delete(ExceptionMessage, Length(ExceptionMessage), 1);
  // from the right side, remove the ", line " portion
  while (ExceptionMessage <> '') and (ExceptionMessage[Length(ExceptionMessage)] = Mask[Length(Mask)]) do
  begin
    Delete(ExceptionMessage, Length(ExceptionMessage), 1);
    Delete(Mask, Length(Mask), 1);
  end;
  // now find the opening "("
  OpeningParenthesesPosition := Length(ExceptionMessage);
  while (ExceptionMessage <> '') and (ExceptionMessage[OpeningParenthesesPosition] <> '(') do
    Dec(OpeningParenthesesPosition);
  Delete(ExceptionMessage, 1, OpeningParenthesesPosition);
  Result := ExceptionMessage;
end;

end.

One Response to “Delphi – class helper to get SourceFileName from an EAssertionFailed”

  1. […] The Wiert Corner: getting SoureFileName from EAssertionFailed […]

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.