Browse Source

Import most components (GCC/GAS patches, IDE, tigcc.exe, hsf2RC, ld-tigcc, tprbuilder).

git-svn-id: file:///var/svn/tigccpp/trunk/tigcc/ide@9 9552661e-59e3-4036-b4f2-dbe53926924f
kevinkofler 19 years ago
commit
81dce58c49
70 changed files with 16488 additions and 0 deletions
  1. BIN
      AboutUnit.dfm
  2. 55 0
      AboutUnit.pas
  3. 15 0
      CalcUnit.pas
  4. 494 0
      CodeCompletion/CodeCompletion.pas
  5. BIN
      CodeCompletion/CompletionForm.dfm
  6. 776 0
      CodeCompletion/CompletionForm.pas
  7. BIN
      CodeCompletion/Editor/uBatch.dfm
  8. 129 0
      CodeCompletion/Editor/uBatch.pas
  9. BIN
      CodeCompletion/Editor/uEditor.dfm
  10. 490 0
      CodeCompletion/Editor/uEditor.pas
  11. 189 0
      CodeCompletion/Editor/uHSFParser.pas
  12. 196 0
      CodeCompletion/HtFormatting.pas
  13. BIN
      CodeCompletion/PrefFrame.dfm
  14. 108 0
      CodeCompletion/PrefFrame.pas
  15. BIN
      CodeCompletion/TmpltForm.dfm
  16. 200 0
      CodeCompletion/TmpltForm.pas
  17. BIN
      ColorsUnit.dfm
  18. 120 0
      ColorsUnit.pas
  19. BIN
      CustomStyleUnit.dfm
  20. 114 0
      CustomStyleUnit.pas
  21. 72 0
      FolderUnit.pas
  22. BIN
      FunctionsWinUnit.dfm
  23. 48 0
      FunctionsWinUnit.pas
  24. 36 0
      IDE.cfg
  25. 104 0
      IDE.dof
  26. 65 0
      IDE.dpr
  27. 127 0
      IDE.dsk
  28. BIN
      IDE.res
  29. 77 0
      LinkDLLUnit.pas
  30. 682 0
      LinkUnit.pas
  31. BIN
      MainUnit.dfm
  32. 5363 0
      MainUnit.pas
  33. 735 0
      MasterUnit.pas
  34. BIN
      NewFolderUnit.dfm
  35. 33 0
      NewFolderUnit.pas
  36. BIN
      NewsUnit.dfm
  37. 250 0
      NewsUnit.pas
  38. BIN
      OpenFileStatusUnit.dfm
  39. 33 0
      OpenFileStatusUnit.pas
  40. 598 0
      ParsingUnit.pas
  41. BIN
      PreferencesUnit.dfm
  42. 491 0
      PreferencesUnit.pas
  43. 281 0
      ProcessUnit.pas
  44. BIN
      ProgramOptionsUnit.dfm
  45. 202 0
      ProgramOptionsUnit.pas
  46. BIN
      ProgramOutputUnit.dfm
  47. 33 0
      ProgramOutputUnit.pas
  48. BIN
      ProjectOptionsUnit.dfm
  49. 262 0
      ProjectOptionsUnit.pas
  50. BIN
      SendProgressUnit.dfm
  51. 51 0
      SendProgressUnit.pas
  52. 2655 0
      SourceFileUnit.pas
  53. BIN
      SourceFileWinUnit.dfm
  54. 789 0
      SourceFileWinUnit.pas
  55. BIN
      StartupScreenUnit.dfm
  56. 58 0
      StartupScreenUnit.pas
  57. BIN
      StartupUnit.dfm
  58. BIN
      StyleSelectionUnit.dfm
  59. 75 0
      StyleSelectionUnit.pas
  60. BIN
      SyntaxProgressUnit.dfm
  61. BIN
      ToolPropertiesUnit.dfm
  62. 82 0
      ToolPropertiesUnit.pas
  63. 40 0
      ToolsListUnit.pas
  64. BIN
      ToolsUnit.dfm
  65. 179 0
      ToolsUnit.pas
  66. BIN
      VTIStartUnit.dfm
  67. 76 0
      VTIStartUnit.pas
  68. 12 0
      VersionUnit.pas
  69. BIN
      WordListUnit.dfm
  70. 93 0
      WordListUnit.pas

BIN
AboutUnit.dfm


+ 55 - 0
AboutUnit.pas

@@ -0,0 +1,55 @@
+unit AboutUnit;
+
+interface
+
+uses
+	Windows, SysUtils, Classes, Graphics, Forms, Controls, StdCtrls,
+  Buttons, ExtCtrls, URLLabelUnit;
+
+type
+  TAboutForm = class(TForm)
+    FramePanel: TPanel;
+    ProgramIcon: TImage;
+    ProductNameLabel: TLabel;
+    VersionLabel: TLabel;
+    OKButton: TButton;
+    Label2: TLabel;
+    Label3: TLabel;
+    Label4: TLabel;
+    Label5: TLabel;
+    Label6: TLabel;
+    URLLabel1: TURLLabel;
+    URLLabel2: TURLLabel;
+    URLLabel3: TURLLabel;
+    URLLabel4: TURLLabel;
+    URLLabel5: TURLLabel;
+    Label1: TLabel;
+    URLLabel6: TURLLabel;
+    CopyrightLabel: TLabel;
+    Label8: TLabel;
+    Label9: TLabel;
+    URLLabel7: TURLLabel;
+    Label10: TLabel;
+    URLLabel8: TURLLabel;
+    Label7: TLabel;
+    URLLabel9: TURLLabel;
+    procedure FormCreate(Sender: TObject);
+  private
+	public
+	end;
+
+implementation
+
+{$R *.DFM}
+
+uses
+	VersionUnit;
+
+procedure TAboutForm.FormCreate(Sender: TObject);
+begin
+	PixelsPerInch := 96;
+	VersionLabel.Caption := 'Version ' + TIGCCLongVersion;
+end;
+
+end.
+ 

+ 15 - 0
CalcUnit.pas

@@ -0,0 +1,15 @@
+unit CalcUnit;
+
+interface
+
+type
+	TCalcDest = (cdTI89, cdTI89Titanium, cdTI92Plus, cdV200, cdTI92);
+	TCalcDests = set of TCalcDest;
+
+const
+	FirstCalcDest = cdTI89;
+	LastCalcDest = cdTI92;
+
+implementation
+
+end.

+ 494 - 0
CodeCompletion/CodeCompletion.pas

@@ -0,0 +1,494 @@
+unit CodeCompletion;
+
+interface
+
+uses SysUtils, SourceFileUnit, Dialogs, Classes, MainUnit;
+
+const
+  DefautDesc = '';
+  CCFVersion: Byte = 2;
+  //  Zero: Cardinal = 0;
+
+type
+  TOnNeedFile = procedure(const FileName: string; out CCFData: string) of object;
+
+  TCompletionItem = class(TObject)
+  public
+    Left, Right: string;
+    Description: string;
+
+    Line: Cardinal;
+
+    // Not Saved
+    SourceFileName: string;
+
+    procedure ReadFromStream(F: TStream);
+    procedure WriteToStream(F: TStream);
+  end;
+
+  TCompletionList = class(TStringList)
+  protected
+    FIncluded: TStringList;
+    FOnNeed: TOnNeedFile;
+
+    function aGetObject(Index: Integer): TCompletionItem;
+    procedure aSetObject(Index: Integer; const Value: TCompletionItem);
+  public
+    constructor Create; reintroduce;
+    destructor Destroy; override;
+    function AddObject(const Symbol: string; Info: TCompletionItem): Integer; reintroduce;
+    procedure Clear; override;
+    property Completion[Index: Integer]: TCompletionItem read aGetObject write aSetObject;
+
+    procedure AddCompletion(CCFData: TStream); overload;
+    procedure AddCompletion(const CCFData: string); overload;
+
+    // Completion state
+    property IncludedFiles: TStringList read FIncluded;
+
+    // When a file is needed
+    property OnNeedFile: TOnNeedFile read FOnNeed write FOnNeed;
+  end;
+
+function ReadString(F: TStream; var S: string): Boolean;
+function WriteString(F: TStream; const S: string): Boolean;
+
+function FileToString(const FileName: string): string;
+
+// Remove comments from a C Source
+function GetIdent(const S: string; var aPos: Integer): string;
+procedure FilterComment(Src, Dst: TStrings);
+
+// Parse a C Source
+function MakeCCF_C(const UnitName: string; Src: TSourceTextSourceFile): string;
+
+// Parse an Header Source
+function MakeCCF_H(const UnitName: string; Lines: TStrings; FilterTo: TStrings = nil): string;
+
+implementation
+
+uses StrUtils, UtilsDos;
+
+// Routines
+
+function GetIdent(const S: string; var aPos: Integer): string;
+var
+  i, l: Integer;
+begin
+  i := aPos;
+  l := Length(S);
+  while (i <= l) and (S[i] = ' ') do
+    Inc(i);
+  while (i <= l) and (S[i] in ['a'..'z', 'A'..'Z', '0'..'9', '_', '#']) do
+    Inc(i);
+  Result := Copy(S, aPos, i - aPos);
+  aPos := i;
+end;
+
+function ReadString(F: TStream; var S: string): Boolean;
+var
+  B: Byte;
+begin
+  if F.Read(B, 1) = 1 then
+  begin
+    Setlength(S, B);
+    Result := F.Read(S[1], B) = B;
+  end
+  else
+  begin
+    Result := False;
+    S := '';
+  end;
+end;
+
+function WriteString(F: TStream; const S: string): Boolean;
+var
+  B: Byte;
+begin
+  B := Length(S);
+  Result := False;
+  if F.Write(B, 1) = 1 then
+    Result := F.Write(S[1], B) = B;
+end;
+
+function FileToString(const FileName: string): string;
+var
+  F: TFileStream;
+  c1, c2: Integer;
+begin
+  Result := '';
+  try
+    F := TFileStream.Create(FileName, fmOpenRead);
+    try
+      c1 := F.Size;
+      SetLength(Result, c1);
+      c2 := F.Read(Result[1], c1);
+      if c1 <> c2 then
+        SetLength(Result, c2);
+    finally
+      F.Free;
+    end;
+  except
+  end;
+end;
+
+procedure FilterComment(Src, Dst: TStrings);
+var
+  S, S2: string;
+  i, p: Integer;
+  InComment: Boolean;
+begin
+  InComment := False;
+  for i := 0 to Src.Count - 1 do
+  begin
+    S := Trim(Src[i]);
+
+    // Check end of comment
+    if InComment then
+    begin
+      p := Pos('*/', S);
+      if p = 0 then
+      begin
+        Dst.Add('');
+        Continue;
+      end
+      else
+      begin
+        InComment := False;
+        S := Copy(S, p + 2, MaxInt);
+      end;
+    end;
+
+    // Check line comment
+    p := Pos('//', S);
+    if p = 1 then
+    begin
+      Dst.Add('');
+      Continue;
+    end
+    else if p <> 0 then
+      S := Copy(S, 1, p - 1);
+
+    // Check start of comment
+    p := Pos('/*', S);
+    if p <> 0 then
+    begin
+      S2 := S;
+      S := Copy(S, 1, p - 1);
+      p := PosEx('*/', S2, p + 2);
+      InComment := p = 0;
+      if not InComment then
+      begin
+        InComment := False;
+        S := S + Copy(S2, p + 2, MaxInt);
+      end;
+    end;
+
+    // Add result
+    Dst.Add(S);
+  end;
+end;
+
+procedure ParseIncludes(Src, Dst: TStrings);
+var
+  i, p: Integer;
+  Line: string;
+begin
+  // find line which starts with '#include'
+  for i := 0 to Src.Count - 1 do
+  begin
+    Line := Trim(Src[i]);
+    if AnsiStartsText('#include', Line) then
+    begin
+      p := Pos('"', Line);
+      if P <> 0 then
+      begin
+        Line := Copy(Line, p + 1, MaxInt);
+        Line := Copy(Line, 1, Pos('"', Line) - 1);
+        Dst.Add(Trim(Line));
+      end
+      else
+      begin
+        p := Pos('<', Line);
+        if P <> 0 then
+        begin
+          Line := Copy(Line, p + 1, MaxInt);
+          Line := Copy(Line, 1, Pos('>', Line) - 1);
+          Dst.Add(Trim(Line));
+        end;
+      end;
+    end;
+  end;
+end;
+
+function MakeCCF_C(const UnitName: string; Src: TSourceTextSourceFile): string;
+var
+  Dst: TMemoryStream;
+
+  // Parse files included in the Source unit
+  procedure ParseInc;
+  var
+    Included: TStringList;
+    w: Word;
+    i: Integer;
+    Source: TStrings;
+  begin
+    Source := TStringList.Create;
+    FilterComment(Src.SourceEditor.Lines, Source);
+    Included := TStringList.Create;
+    Included.Sorted := True;
+    Included.Duplicates := dupIgnore;
+    ParseIncludes(Source, Included);
+    w := Included.Count;
+    // write result to stream
+    Dst.Write(w, 2);
+    for i := 0 to Included.Count - 1 do
+      WriteString(Dst, Included[i]);
+    Included.Free;
+    Source.Free;
+  end;
+  // Parse Functions
+  procedure ParseFuncs;
+  var
+    Funcs: TSourceFileFunctions;
+    Func: TSourceFileFunction;
+    i, p, c, l: Integer;
+    S: string;
+    Source: TStrings;
+  begin
+    Source := Src.SourceEditor.Lines;
+    Funcs := Src.GetFunctions;
+    c := Source.Count;
+    for i := 0 to Length(Funcs) - 1 do
+    begin
+      Func := Funcs[i];
+      if Func.Name <> '' then
+      begin
+        if (Func.ImplementationLine > 0) and (Func.ImplementationLine <= c) then
+          l := Func.ImplementationLine - 1
+        else if (Func.PrototypeLine > 0) and (Func.PrototypeLine <= c) then
+          l := Func.PrototypeLine - 1
+        else
+          l := -1;
+        if l > -1 then
+          S := Source[l];
+        if S <> '' then
+        begin
+          p := Pos(Func.Name, S);
+          WriteString(Dst, Func.Name);
+          Dst.Write(l, 4);
+          WriteString(Dst, '<c:Teal>func <c:Blue>' + Trim(Copy(S, 1, p - 1)));
+          WriteString(Dst, Trim(Copy(S, p + Length(Func.Name), MaxInt)));
+          WriteString(Dst, DefautDesc);
+        end;
+      end;
+    end;
+  end;
+begin
+  Dst := TMemoryStream.Create;
+  Dst.Write(CCFVersion, SizeOf(CCFVersion));
+  WriteString(Dst, UnitName);
+  ParseInc;
+  ParseFuncs;
+  SetString(Result, PChar(Dst.Memory), Dst.Size);
+  Dst.Free;
+end;
+
+function MakeCCF_H(const UnitName: string; Lines: TStrings; FilterTo: TStrings = nil): string;
+var
+  Dst: TMemoryStream;
+  Source: TStrings;
+
+  // Parse files included in the Source unit
+  procedure ParseInc;
+  var
+    Included: TStringList;
+    w: Word;
+    i: Integer;
+  begin
+    Included := TStringList.Create;
+    Included.Sorted := True;
+    Included.Duplicates := dupIgnore;
+    ParseIncludes(Source, Included);
+    w := Included.Count;
+    // write result to stream
+    Dst.Write(w, 2);
+    for i := 0 to Included.Count - 1 do
+      WriteString(Dst, Included[i]);
+    Included.Free;
+  end;
+
+  procedure ParseHeader;
+  var
+    i, p, c: Integer;
+    S, S2, Ident: string;
+  begin
+    c := Source.Count;
+    i := 0;
+    while i < c do
+    begin
+      S := Source[i];
+      if AnsiStartsText('#define', S) then
+      begin
+        p := 9;
+        Ident := GetIdent(S, p);
+        S2 := Trim(Copy(S, p, MaxInt));
+        if S2 <> '' then
+        begin
+          WriteString(Dst, Ident);
+          Dst.Write(i, 4);
+          WriteString(Dst, '<c:Green>macro');
+          WriteString(Dst, S2);
+          WriteString(Dst, '');
+        end
+      end
+      else
+      begin
+        // terminer cette partie du code :)
+      end;
+      Inc(i);
+    end;
+  end;
+
+begin
+  Dst := TMemoryStream.Create;
+  Dst.Write(CCFVersion, SizeOf(CCFVersion));
+
+  if Assigned(FilterTo) then
+    Source := FilterTo
+  else
+    Source := TStringList.Create;
+  Source.Clear;
+
+  FilterComment(Lines, Source);
+  WriteString(Dst, UnitName);
+  ParseInc;
+  ParseHeader;
+  SetString(Result, PChar(Dst.Memory), Dst.Size);
+
+  if FilterTo = nil then
+    Source.Free;
+  Dst.Free;
+end;
+
+{ TCompletionList }
+
+constructor TCompletionList.Create;
+begin
+	inherited;
+	CaseSensitive := True;
+	Sorted := True;
+  Duplicates := dupAccept;
+  FIncluded := TStringList.Create;
+  FIncluded.Sorted := True;
+  FIncluded.Duplicates := dupIgnore;
+end;
+
+destructor TCompletionList.Destroy;
+begin
+  Clear;
+  inherited;
+end;
+
+function TCompletionList.AddObject(const Symbol: string;
+  Info: TCompletionItem): Integer;
+begin
+  Result := inherited AddObject(Symbol, Info);
+end;
+
+procedure TCompletionList.Clear;
+var
+  i: Integer;
+begin
+  IncludedFiles.Clear;
+  for i := 0 to Count - 1 do
+    Objects[i].Free;
+  inherited;
+end;
+
+function TCompletionList.aGetObject(Index: Integer): TCompletionItem;
+begin
+  Result := TCompletionItem(Objects[Index]);
+end;
+
+procedure TCompletionList.aSetObject(Index: Integer;
+  const Value: TCompletionItem);
+begin
+  Objects[Index] := Value;
+end;
+
+procedure TCompletionList.AddCompletion(CCFData: TStream);
+var
+  aStream: TStream;
+  UnitName, S1, S2: string;
+  i, w: Word;
+  C: TCompletionItem;
+  B: Byte;
+begin
+  if (CCFData.Read(B, 1) <> 1) or (B <> CCFVersion) then
+    Exit; // Wrong Version
+  if ReadString(CCFData, UnitName) and (IncludedFiles.IndexOf(UnitName) = -1) and (CCFData.Read(w, 2) = 2) then
+  begin
+    IncludedFiles.Add(UnitName);
+    // Check for included files
+    for i := 1 to w do
+    begin
+      if ReadString(CCFData, S1) then
+      begin
+        if (IncludedFiles.IndexOf(S1) = -1) and Assigned(OnNeedFile) then
+        begin
+          OnNeedFile(S1, S2);
+          if S2 <> '' then
+          begin
+            aStream := TStringStream.Create(S2);
+            AddCompletion(aStream);
+            aStream.Free;
+          end;
+        end;
+      end
+      else
+        Exit;
+    end;
+    // Add completion info
+    while ReadString(CCFData, S1) do
+    begin
+      C := TCompletionItem.Create;
+      C.ReadFromStream(CCFData);
+      C.SourceFileName := UnitName;
+      if S1 <> '' then
+        AddObject(S1, C)
+      else
+        C.Free;
+    end;
+  end;
+end;
+
+procedure TCompletionList.AddCompletion(const CCFData: string);
+var
+  S: TStringStream;
+begin
+  S := TStringStream.Create(CCFData);
+  AddCompletion(S);
+  S.Free;
+end;
+
+{ TCompletionItem }
+
+procedure TCompletionItem.ReadFromStream(F: TStream);
+begin
+  F.Read(Line, SizeOf(Line));
+  ReadString(F, Left);
+  ReadString(F, Right);
+  ReadString(F, Description);
+end;
+
+procedure TCompletionItem.WriteToStream(F: TStream);
+begin
+  F.Write(Line, SizeOf(Line));
+  WriteString(F, Left);
+  WriteString(F, Right);
+  WriteString(F, Description);
+end;
+
+end.
+

BIN
CodeCompletion/CompletionForm.dfm


+ 776 - 0
CodeCompletion/CompletionForm.pas

@@ -0,0 +1,776 @@
+unit CompletionForm;
+
+interface
+
+uses
+	Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, MasterUnit,
+	Dialogs, StdCtrls, ComCtrls, CodeCompletion, SourceFileUnit, UtilsDos, MemoComponentUnit,
+	HtFormatting, Menus, ActnList;
+
+const
+	SymbolFileNotFound = 'Symbol %s is declared in %s, but file can''t be found!';
+	AddTemplatesMsg = 'To add templates, go to Preferences->Coding';
+
+type
+	TCompForm = class(TForm)
+		CompList: TListBox;
+		CompStatus: TStatusBar;
+		procedure FormCreate(Sender: TObject);
+		procedure FormDestroy(Sender: TObject);
+		procedure FormDeactivate(Sender: TObject);
+		procedure CompListDrawItem(Control: TWinControl; Index: Integer;
+			Rect: TRect; State: TOwnerDrawState);
+		procedure CompListDblClick(Sender: TObject);
+		procedure CompListKeyDown(Sender: TObject; var Key: Word;
+			Shift: TShiftState);
+		procedure CompListKeyUp(Sender: TObject; var Key: Word;
+			Shift: TShiftState);
+		procedure CompListKeyPress(Sender: TObject; var Key: Char);
+	private
+		procedure SetEditor(const Value: TMemoComponent);
+	protected
+		{ Déclarations protégées }
+		C: TCompletionList;
+		CompRow: Integer;
+		StopKey: Boolean;
+		HintWindow: THtHintWindow;
+
+		FSourceFile: TSourceFile;
+		FEditor: TMemoComponent;
+
+		procedure CreateParams(var Params: TCreateParams); override;
+		function GetFileData(const F: string): string;
+		procedure NeedFile(const FileName: string; out CCFData: string);
+
+	protected
+		// Be informed when active control change :)
+
+		OldActiveControlChange: TNotifyEvent;
+		procedure ActiveControlChange(Sender: TObject);
+	public
+		{ Déclarations publiques }
+
+		// Get & Replace word under caret
+		procedure DelimitateWord(const Line: string; var StartPos: Integer; out EndPos: Integer);
+		function GetWord(Full, RemoveSpace: Boolean): string;
+		procedure SetWord(const Value: string);
+
+		// Show Completion Windows
+		property List: TCompletionList read C;
+		procedure RebuildList;
+		procedure ShowCompletion;
+		procedure CloseCompletion;
+		procedure ApplyCompletion;
+
+		// Show an hint window about the symbol Symbol, or symbol under caret if ''
+		function ShowSymbolInfo(Symbol: string = ''): Boolean;
+		procedure CloseSymbolInfo;
+
+		// Find symbol declaration
+		procedure FindSymbolDecl;
+
+	protected
+		OldChange: TNotifyEvent;
+		OldKeyDown: TKeyEvent;
+		OldKeyPress: TKeyPressEvent;
+
+		// Redirect Event from Editor
+		procedure Editor_Enter(Sender: TMemoComponent);
+		procedure Editor_Exit(Sender: TObject);
+		procedure Editor_KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+		procedure Editor_KeyPress(Sender: TObject; var Key: Char);
+		procedure Editor_Change(Sender: TObject);
+
+	public
+		property Editor: TMemoComponent read FEditor write SetEditor;
+	end;
+
+var
+	CompForm: TCompForm;
+
+	// TIGCC integration
+function SourceFileFromEditor(M: TMemoComponent): TSourceFile;
+
+procedure InsertAction(Owner: TComponent; After: TMenuItem; Action: TBasicAction);
+procedure InsertsAction(Owner: TComponent; const Afters: array of TMenuItem; Action: TBasicAction);
+
+implementation
+
+uses Types, StrUtils, Math, TmpltForm, MainUnit;
+
+{$R *.dfm}
+
+function SourceFileFromEditor(M: TMemoComponent): TSourceFile;
+var
+	i: Integer;
+	Lst: TSourceFiles;
+	Src: TSourceFile;
+begin
+	Lst := MainForm.SourceFiles;
+	for i := 0 to Lst.Count - 1 do
+	begin
+		Src := TSourceFile(Lst.Items[i]);
+		if Src.Editor = M then
+		begin
+			Result := Src;
+			Exit;
+		end;
+	end;
+	Result := nil;
+end;
+
+procedure InsertAction(Owner: TComponent; After: TMenuItem; Action: TBasicAction);
+var
+	Item: TMenuItem;
+begin
+	Item := TMenuItem.Create(Owner);
+	Item.Action := Action;
+	with After.Parent do
+		Insert(IndexOf(After) + 1, Item);
+end;
+
+procedure InsertsAction(Owner: TComponent; const Afters: array of TMenuItem; Action: TBasicAction);
+var
+	i: Integer;
+begin
+	for i := Low(Afters) to High(Afters) do
+		InsertAction(Owner, Afters[i], Action);
+end;
+
+// GUI Methods
+
+procedure TCompForm.FormCreate(Sender: TObject);
+begin
+	C := TCompletionList.Create;
+	C.OnNeedFile := NeedFile;
+	HintWindow := THtHintWindow.Create(Self);
+	OldActiveControlChange := Screen.OnActiveControlChange;
+	Screen.OnActiveControlChange := ActiveControlChange;
+end;
+
+procedure TCompForm.FormDestroy(Sender: TObject);
+begin
+	if Assigned(Screen.OnActiveControlChange) then
+		Screen.OnActiveControlChange := OldActiveControlChange;
+	HintWindow.Free;
+	C.Free;
+end;
+
+procedure TCompForm.FormDeactivate(Sender: TObject);
+var
+	M: TMemoComponent;
+begin
+	M := Editor;
+	if (M = nil) or (not M.Focused) then
+		CloseCompletion;
+end;
+
+procedure TCompForm.CreateParams(var Params: TCreateParams);
+begin
+	inherited;
+	Params.Style := WS_POPUP or WS_SYSMENU or WS_THICKFRAME;
+end;
+
+procedure TCompForm.CompListDrawItem(Control: TWinControl; Index: Integer;
+	Rect: TRect; State: TOwnerDrawState);
+const
+	MinWidth = 62;
+var
+	C: TCompletionItem;
+	S: string;
+	Cnv: TCanvas;
+	Selected: Boolean;
+	W: Integer;
+begin
+	if (Index >= 0) and (Index < List.Count) then
+	begin
+		Cnv := CompList.Canvas;
+		Selected := odSelected in State;
+		C := List.Completion[Index];
+		S := List[Index];
+		if Assigned(C) then
+		begin
+			Cnv.Font.Style := [];
+			DrawHtText(C.Left, Rect, Cnv, W, Selected);
+			Inc(Rect.Left, W);
+		end;
+		if Rect.Left < MinWidth then
+			Rect.Left := MinWidth;
+		Inc(Rect.Left, 2);
+		Cnv.Font.Style := [fsBold];
+		DrawHtText(S, Rect, Cnv, W, Selected);
+		Inc(Rect.Left, W + 2);
+		if Assigned(C) then
+		begin
+			Cnv.Font.Style := [];
+			DrawHtText(C.Right, Rect, CompList.Canvas, Rect.Left, Selected);
+			if Selected then
+				CompStatus.SimpleText := C.Description;
+		end;
+	end;
+end;
+
+procedure TCompForm.CompListDblClick(Sender: TObject);
+begin
+	ApplyCompletion;
+end;
+
+// Completion Tools
+
+procedure TCompForm.RebuildList;
+var
+	S: TSourceFile;
+begin
+	List.Clear;
+	S := SourceFileFromEditor(Editor);
+	if Assigned(S) then
+	begin
+		if S is TCSourceFile then
+			List.AddCompletion(MakeCCF_C(ExtractFileName(S.FileName), TCSourceFile(S)))
+		else if S is THeaderSourceFile then
+			List.AddCompletion(MakeCCF_H(ExtractFileName(S.FileName), THeaderSourceFile(S).SourceEditor.Lines));
+	end;
+	CompList.Count := List.Count;
+end;
+
+procedure TCompForm.ShowCompletion;
+var
+	M: TMemoComponent;
+	P: TPoint;
+	i: Integer;
+begin
+	M := Editor;
+	CloseSymbolInfo;
+	if Assigned(M) then
+	begin
+		RebuildList;
+		CompRow := M.Selection.StartRowCol.Row;
+		P := M.Selection.StartPoint;
+		P := M.ClientToScreen(P);
+		Left := P.X + 4;
+		Top := P.Y + 20;
+		List.Find(GetWord(True, False), i);
+		CompList.ItemIndex := i;
+		LockWindowUpdate(M.ParentWindow);
+		Show;
+		M.SetFocus;
+		LockWindowUpdate(0);
+	end;
+end;
+
+procedure TCompForm.CloseCompletion;
+begin
+	Hide;
+end;
+
+function TCompForm.ShowSymbolInfo(Symbol: string = ''): Boolean;
+	function Similarity(const A, B: string): Integer;
+	var
+		i, l: Integer;
+	begin
+		l := Min(Length(A), Length(B));
+		i := 1;
+		while (i <= l) and (UpCase(A[i]) = UpCase(B[i])) do
+			Inc(i);
+		Result := Abs(i - l);
+	end;
+	function Similar(const A, B: string): Boolean;
+	var
+		l: Integer;
+	begin
+		l := Min(Length(A), Length(B));
+		Result := Similarity(A, B) < (l shr 1);
+	end;
+var
+	M: TMemoComponent;
+	P: TPoint;
+	R: TRect;
+	i: Integer;
+	C: TCompletionItem;
+	T: string;
+begin
+	CloseCompletion;
+	Result := False;
+	if Symbol = '' then
+		Symbol := GetWord(False, True);
+	if Symbol = '' then
+	begin
+		CloseSymbolInfo;
+		Exit;
+	end;
+
+	M := Editor;
+	if Assigned(M) then
+	begin
+		RebuildList;
+
+		// Find Symbol
+		if List.Find(Symbol, i) then
+			T := ''
+		else if (i >= 0) and (i < List.Count) then
+		begin
+			if i = 0 then
+			begin
+				if Similar(Symbol, List[i]) then
+					T := List[i] + ' ?'#13#10
+				else
+					Exit;
+			end
+			else
+			begin
+				if Similarity(Symbol, List[i - 1]) > Similarity(Symbol, List[i]) then
+					Dec(i);
+				if Similar(Symbol, List[i]) then
+					T := List[i] + ' ?'#13#10
+				else
+					Exit;
+			end;
+		end
+		else
+			Exit;
+
+		// Show Symbol info
+		C := List.Completion[i];
+		if Assigned(C) then
+		begin
+			T := T + C.Left + ' ' + C.Right + #13#10 + C.Description;
+			// Calc hint window position
+			CompRow := M.Selection.StartRowCol.Row;
+			P := M.ClientToScreen(M.Selection.StartPoint);
+			R := HintWindow.CalcHintRect(Screen.Width, T, nil);
+			Inc(R.Left, P.X + 4);
+			Inc(R.Right, P.X + 4);
+			Inc(R.Top, P.Y + 20);
+			Inc(R.Bottom, P.Y + 20);
+			LockWindowUpdate(M.ParentWindow);
+			HintWindow.ActivateHint(R, T);
+			Result := True;
+			M.SetFocus;
+
+			// Bug with TSourceFileForm ??!!
+			if Assigned(M.Parent) and (M.Parent is TForm) then
+				M.Parent.BringToFront;
+			LockWindowUpdate(0);
+		end;
+	end;
+end;
+
+procedure TCompForm.CloseSymbolInfo;
+begin
+	if IsWindowVisible(HintWindow.Handle) then
+		ShowWindow(HintWindow.Handle, SW_HIDE);
+end;
+
+procedure TCompForm.ApplyCompletion;
+var
+	i: Integer;
+begin
+	i := CompList.ItemIndex;
+	if (i >= 0) and (i < List.Count) then
+	begin
+		SetWord(List[i]);
+		CloseCompletion;
+	end;
+end;
+
+// Find Files
+
+function TCompForm.GetFileData(const F: string): string;
+var
+	S: TSourceFile;
+	Folder: string;
+begin
+	S := MainForm.SourceFiles.FindFileNameOnly(F);
+	Folder := WithBackslash(TIGCCFolder);
+	if Assigned(S) and (S is TSourceTextSourceFile) then
+		Result := TSourceTextSourceFile(S).Content
+	else if FileExists(ExpandFileName(F)) then
+		Result := FileToString(ExpandFileName(F))
+	else if FileExists(Folder + CIncludeLocation + F) then
+		Result := FileToString(Folder + CIncludeLocation + F)
+	else if FileExists(Folder + ASMIncludeLocation + F) then
+		Result := FileToString(Folder + ASMIncludeLocation + F)
+	else
+		Result := '';
+end;
+
+procedure TCompForm.NeedFile(const FileName: string; out CCFData: string);
+var
+	CCFName: string;
+	Lst: TStringList;
+begin
+	// Search CCF file
+	CCFName := WithBackslash(TIGCCFolder) + CompletionLocation + ChangeFileExt(FileName, '.ccf');
+	if FileExists(CCFName) then
+		CCFData := FileToString(CCFName)
+	else
+	begin
+		// No CCF ? Generate info from header...
+		if UpperCase(ExtractFileExt(FileName)) = '.H' then
+		begin
+			Lst := TStringList.Create;
+			Lst.Text := GetFileData(FileName);
+			if Lst.Count > 0 then
+				CCFData := MakeCCF_H(FileName, Lst);
+			Lst.Free;
+		end;
+	end;
+end;
+
+// Word manipulations
+
+procedure TCompForm.DelimitateWord(const Line: string; var StartPos: Integer; out EndPos: Integer);
+const
+	ValidChars = ['A'..'Z', 'a'..'z', '0'..'9', '_', '$', '#'];
+var
+	i, j, l: Integer;
+begin
+	i := StartPos - 1;
+	j := StartPos - 1;
+	l := Length(Line);
+	// Find start pos
+	while (i > 0) and (i <= l) and (Line[i] in ValidChars) do
+		Dec(i);
+	// Find end pos
+	while (j > 0) and (j <= l) and (Line[j] in ValidChars) do
+		Inc(j);
+	if j = StartPos - 1 then
+	begin
+		j := StartPos;
+		while (j > 0) and (j <= l) and (Line[j] in ValidChars) do
+			Inc(j);
+	end;
+	Dec(j);
+	Inc(i);
+	StartPos := i;
+	EndPos := j;
+end;
+
+function TCompForm.GetWord(Full, RemoveSpace: Boolean): string;
+var
+	M: TMemoComponent;
+	S: string;
+	T: TTextCell;
+	StPos, EndPos, l: Integer;
+begin
+	M := Editor;
+	Result := '';
+	if Assigned(M) then
+	begin
+		T := M.Selection.StartRowCol;
+		if (T.Row > 0) and (T.Row <= M.LineCount) then
+		begin
+			S := M.Lines[T.Row - 1];
+			StPos := T.Col;
+			l := Length(S);
+			if RemoveSpace and (StPos > 1) and (StPos <= l) then
+			begin
+				if S[StPos - 1] = ' ' then
+					Dec(StPos);
+				while (StPos > 1) and (S[StPos] in ['(', ' ']) do
+					Dec(StPos);
+			end;
+			DelimitateWord(S, StPos, EndPos);
+			if Full then
+				Result := Trim(Copy(S, StPos, EndPos - StPos + 1))
+			else
+				Result := Trim(Copy(S, StPos, T.Col - StPos));
+		end;
+	end;
+end;
+
+procedure TCompForm.SetWord(const Value: string);
+var
+	M: TMemoComponent;
+begin
+	M := Editor;
+	if Assigned(M) then
+	begin
+		with M.Selection do
+		begin
+			SelectWord;
+			Text := Value;
+		end;
+	end;
+end;
+
+// Editor Events
+
+procedure TCompForm.Editor_KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+	procedure Select(Direction, Page: Boolean);
+	var
+		HowMany, i, c: Integer;
+	begin
+		i := CompList.ItemIndex;
+		c := List.Count;
+		if Page then
+			HowMany := CompList.Height div CompList.ItemHeight
+		else
+			HowMany := 1;
+		if Direction then
+			Inc(i, HowMany)
+		else
+			Dec(i, HowMany);
+		if i <= 0 then
+			CompList.ItemIndex := 0
+		else if i >= c then
+			CompList.ItemIndex := c - 1
+		else
+			CompList.ItemIndex := i;
+	end;
+var
+	NewKey: Word;
+begin
+	if Assigned(OldKeyDown) then
+		OldKeyDown(Sender, Key, Shift);
+	if Visible then
+	begin
+		NewKey := 0;
+		case Key of
+			VK_ESCAPE: Close;
+			VK_RETURN:
+				begin
+					ApplyCompletion;
+					StopKey := True;
+				end;
+			VK_UP: Select(False, False);
+			VK_DOWN: Select(True, False);
+			VK_PRIOR: Select(False, True);
+			VK_NEXT: Select(True, True);
+			VK_HOME: CompList.ItemIndex := 0;
+			VK_END: CompList.ItemIndex := List.Count - 1;
+			VK_LEFT, VK_RIGHT:
+				begin
+					Editor_Change(Sender);
+					NewKey := Key;
+				end;
+		else
+			NewKey := Key;
+		end;
+		Key := NewKey;
+	end
+	else if (ssCtrl in Shift) and (Key = VK_SPACE) then
+	begin
+		Key := 0;
+		StopKey := True;
+		ShowCompletion;
+	end
+	else if (ssCtrl in Shift) and (Key = Ord('J')) then
+	begin
+		Key := 0;
+		StopKey := True;
+		if TemplateForm.Templates.Count > 0 then
+			TemplateForm.Show
+		else
+			ShowMessage(AddTemplatesMsg);
+	end
+	else if (Key in [VK_BACK, VK_ESCAPE]) then // or not (Key in [Ord('A')..Ord('Z'), Ord('0')..Ord('9')
+		CloseSymbolInfo;
+end;
+
+procedure TCompForm.Editor_KeyPress(Sender: TObject; var Key: Char);
+begin
+	if Assigned(OldKeyPress) then
+		OldKeyPress(Sender, Key);
+	if StopKey then
+	begin
+		Key := #0;
+		StopKey := False;
+	end
+	else
+	begin
+		case Key of
+			'(': if Visible or not IsWindowVisible(HintWindow.Handle) then ShowSymbolInfo;
+			')': CloseSymbolInfo;
+		end;
+	end;
+end;
+
+procedure TCompForm.Editor_Change(Sender: TObject);
+var
+	i: Integer;
+	M: TMemoComponent;
+begin
+	if Assigned(OldChange) then
+		OldChange(Sender);
+	M := Editor;
+	if Visible then
+	begin
+		if Assigned(M) then
+		begin
+			if CompRow <> M.Selection.StartRowCol.Row then
+				CloseCompletion
+			else
+			begin
+				List.Find(GetWord(False, False), i);
+				CompList.ItemIndex := i;
+			end;
+		end
+		else
+			CloseCompletion;
+	end
+	else if Assigned(M) and (CompRow <> M.Selection.StartRowCol.Row) then
+		CloseSymbolInfo;
+end;
+
+procedure TCompForm.Editor_Enter(Sender: TMemoComponent);
+begin
+	if Assigned(Sender) then
+	begin
+		FEditor := Sender;
+
+		CloseCompletion;
+		CloseSymbolInfo;
+
+		OldKeyDown := Editor.OnKeyDown;
+		OldKeyPress := Editor.OnKeyPress;
+		OldChange := Editor.OnChange;
+
+		Editor.OnKeyDown := Editor_KeyDown;
+		Editor.OnKeyPress := Editor_KeyPress;
+		Editor.OnChange := Editor_Change;
+		Editor.OnSelectionChange := Editor_Change;
+	end
+	else
+	begin
+		FEditor := nil;
+		OldKeyDown := nil;
+		OldKeyPress := nil;
+		OldChange := nil;
+	end;
+end;
+
+procedure TCompForm.Editor_Exit(Sender: TObject);
+begin
+	if Assigned(Editor) then
+	begin
+		Editor.OnKeyDown := OldKeyDown;
+		Editor.OnKeyPress := OldKeyPress;
+		Editor.OnChange := OldChange;
+		Editor.OnSelectionChange := OldChange;
+	end;
+	CloseSymbolInfo;
+	if not Focused then
+	begin
+		FEditor := nil;
+		CloseCompletion;
+	end;
+end;
+
+procedure TCompForm.CompListKeyDown(Sender: TObject; var Key: Word;
+	Shift: TShiftState);
+var
+	M: TMemoComponent;
+begin
+	M := Editor;
+	if Assigned(M) then
+	begin
+		M.HandleKeyDown(Key, Shift);
+		M.SetFocus;
+		Key := 0;
+	end
+	else
+		CloseCompletion;
+end;
+
+procedure TCompForm.CompListKeyUp(Sender: TObject; var Key: Word;
+	Shift: TShiftState);
+var
+	M: TMemoComponent;
+begin
+	M := Editor;
+	if Assigned(M) then
+	begin
+		M.HandleKeyUp(Key, Shift);
+		M.SetFocus;
+		Key := 0;
+	end
+	else
+		CloseCompletion;
+end;
+
+procedure TCompForm.CompListKeyPress(Sender: TObject; var Key: Char);
+var
+	M: TMemoComponent;
+begin
+	M := Editor;
+	if Assigned(M) then
+	begin
+		M.HandleKeyPress(Key);
+		M.SetFocus;
+	end;
+end;
+
+procedure TCompForm.FindSymbolDecl;
+var
+	i, p: Integer;
+	Symbol, S: string;
+	C: TCompletionItem;
+	SourceFile: TSourceFile;
+begin
+	RebuildList;
+	Symbol := GetWord(True, True);
+	if (Symbol <> '') and List.Find(Symbol, i) then
+	begin
+		C := List.Completion[i];
+		if Assigned(C) and (C.SourceFileName <> '') then
+		begin
+			SourceFile := MainForm.SourceFiles.FindFileNameOnly(C.SourceFileName);
+			if SourceFile = nil then
+			begin
+				if FileExists(ExpandFileName(C.SourceFileName)) then
+					SourceFile := MainForm.AddSourceFile(ExpandFileName(C.SourceFileName), True)
+				else if FileExists(WithBackslash(TIGCCFolder) + CIncludeLocation + C.SourceFileName) then
+					SourceFile := MainForm.AddSourceFile(WithBackslash(TIGCCFolder) + CIncludeLocation + C.SourceFileName, True)
+				else if FileExists(WithBackslash(TIGCCFolder) + ASMIncludeLocation + C.SourceFileName) then
+					SourceFile := MainForm.AddSourceFile(WithBackslash(TIGCCFolder) + ASMIncludeLocation + C.SourceFileName, True)
+			end;
+			if Assigned(SourceFile) and (SourceFile is TTextSourceFile) then
+				with TTextSourceFile(SourceFile).TextEditor do
+				begin
+					if (C.Line < Cardinal(Lines.Count)) then
+					begin
+						S := Lines[C.Line];
+						p := Pos(Symbol, S);
+						if p = 0 then
+							p := 1;
+					end
+					else
+						p := 1;
+					Selection.StartRowCol := TextCell(C.Line + 1, p);
+					Selection.RLength := 0;
+					Selection.ScrollInView(4);
+				end
+			else
+				ShowMessageFmt(SymbolFileNotFound, [Symbol, C.SourceFileName]);
+		end;
+	end;
+end;
+
+procedure TCompForm.ActiveControlChange(Sender: TObject);
+var
+	W: TWinControl;
+begin
+	W := Screen.ActiveControl;
+	if (W = Editor) or (W = Self) or (W = CompList) or (W = TemplateForm) or (W = TemplateForm.TmpltList) then
+		Exit;
+	if Assigned(W) and (W is TMemoComponent) then
+		Editor := TMemoComponent(W)
+	else
+		Editor := nil;
+	if Assigned(OldActiveControlChange) then
+		OldActiveControlChange(Sender);
+end;
+
+procedure TCompForm.SetEditor(const Value: TMemoComponent);
+begin
+	if Value <> FEditor then
+	begin
+		Editor_Exit(Self);
+		Editor_Enter(Value);
+		FEditor := Value;
+	end;
+end;
+
+end.
+

BIN
CodeCompletion/Editor/uBatch.dfm


+ 129 - 0
CodeCompletion/Editor/uBatch.pas

@@ -0,0 +1,129 @@
+unit uBatch;
+
+interface
+
+uses
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, FileCtrl, uEditor, uHSFParser, MasterUnit;
+
+const
+  BrowseCaption = 'Select Directory';
+
+type
+  TBatchEdit = class(TForm)
+    WorkDirLbl: TLabel;
+    WorkDirEdit: TEdit;
+    WorkDirBtn: TButton;
+    HsfDirLbl: TLabel;
+    HsfDirEdit: TEdit;
+    HsfDirBtn: TButton;
+    GoBtn: TButton;
+    LogMemo: TMemo;
+    EnumCheck: TCheckBox;
+    procedure GoBtnClick(Sender: TObject);
+    procedure WorkDirBtnClick(Sender: TObject);
+    procedure HsfDirBtnClick(Sender: TObject);
+    procedure FormCreate(Sender: TObject);
+  private
+    { Déclarations privées }
+  public
+    { Déclarations publiques }
+    Editor: TCEditorForm;
+  end;
+
+var
+  BatchEdit: TBatchEdit;
+
+implementation
+
+{$R *.dfm}
+
+procedure TBatchEdit.GoBtnClick(Sender: TObject);
+
+  procedure Log(const S: string);
+  begin
+    LogMemo.Lines.Add(S);
+  end;
+
+const
+  Valids = faAnyFile and not (faDirectory or faSysFile or faHidden);
+var
+  Sr: TSearchRec;
+  Path, HSFs: string;
+  F: TFileStream;
+begin
+  DoEnum := EnumCheck.Checked;
+  LogMemo.Clear;
+  if Editor = nil then
+    Exit;
+
+  Path := IncludeTrailingPathDelimiter(WorkDirEdit.Text);
+  HSFs := IncludeTrailingPathDelimiter(HsfDirEdit.Text);
+  Log('Start processing...');
+  if FindFirst(Path + '*.h', Valids, Sr) = 0 then
+  begin
+    repeat
+      Log('Found: ' + Sr.Name);
+      Editor.Clear;
+      if Editor.ParseH(Path + Sr.Name) then
+      begin
+        Log('Processing ' + Sr.Name + ' ...');
+        if DirectoryExists(HSFs + Sr.Name) then
+        begin
+          ClearCompletion(Editor.Lst);
+          ImportDir(HSFs + Sr.Name, Editor, Editor.GetLine);
+          Log('Found HSF Files ...');
+        end;
+        try
+          F := TFileStream.Create(Path + ChangeFileExt(Sr.Name, '.ccf'), fmCreate);
+          try
+            Editor.SaveToStream(F);
+          finally
+            F.Free;
+          end;
+        except
+          Log('Error while saving ccf for ' + Sr.Name);
+        end;
+      end;
+      Editor.Modified := False;
+      Log('');
+    until FindNext(Sr) <> 0;
+    FindClose(Sr);
+  end;
+  Editor.Modified := False;
+  Log('Finished!');
+  DoEnum := True;
+end;
+
+procedure TBatchEdit.WorkDirBtnClick(Sender: TObject);
+var
+  Dir: string;
+begin
+  Dir := WorkDirEdit.Text;
+  if SelectDirectory(BrowseCaption, '', Dir) then
+    WorkDirEdit.Text := Dir;
+end;
+
+procedure TBatchEdit.HsfDirBtnClick(Sender: TObject);
+var
+  Dir: string;
+begin
+  Dir := HsfDirEdit.Text;
+  if SelectDirectory(BrowseCaption, '', Dir) then
+    HsfDirEdit.Text := Dir;
+end;
+
+procedure TBatchEdit.FormCreate(Sender: TObject);
+var
+  Folder: string;
+begin
+  Folder := IncludeTrailingPathDelimiter(TIGCCFolder);
+  WorkDirEdit.Text := Folder + CIncludeLocation;
+  Folder := Folder + 'Src\doc\System\Include';
+  if DirectoryExists(Folder) then
+    HsfDirEdit.Text := Folder
+  else
+    HsfDirEdit.Text := TIGCCFolder;
+end;
+
+end.

BIN
CodeCompletion/Editor/uEditor.dfm


+ 490 - 0
CodeCompletion/Editor/uEditor.pas

@@ -0,0 +1,490 @@
+unit uEditor;
+
+interface
+
+uses
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, ExtCtrls, StdCtrls, Buttons, Grids, ValEdit, Menus, FileCtrl,
+  ComCtrls, CodeCompletion, HtFormatting;
+
+const
+  DefautCaption = 'Completion Editor';
+  Cell_Left = ' Left';
+  Cell_Right = ' Right';
+  Cell_Name = ' Name';
+  Cell_Desc = ' Description';
+  Cell_Line = ' Line';
+  SaveModif = 'Save modifications ?';
+  SaveError = 'Error %s:'#13#10'%s';
+  PreviewLBl = 'Preview:';
+  BrowseHSF = 'Select Directory where HSF files are stored';
+  LoadingError = 'Error while loading! (%s error: %s)';
+
+type
+  TCEditorForm = class(TForm)
+    MenuPnl: TPanel;
+    NewBtn: TSpeedButton;
+    SaveBtn: TSpeedButton;
+    OpenBtn: TSpeedButton;
+    OpenDialog: TOpenDialog;
+    SaveDialog: TSaveDialog;
+    ToolsBtn: TSpeedButton;
+    ToolsMenu: TPopupMenu;
+    ParseHSF: TMenuItem;
+    MainPageControl: TPageControl;
+    InfoTab: TTabSheet;
+    ItemsTab: TTabSheet;
+    ItemsLbl: TLabel;
+    ItemsList: TListBox;
+    ItemBox: TGroupBox;
+    ItemEditor: TValueListEditor;
+    ApplyBtn: TButton;
+    UNameLbl: TLabel;
+    UNameEdit: TEdit;
+    IncludeLbl: TLabel;
+    IncludeMemo: TMemo;
+    DelBtn: TButton;
+    ParseHeader: TMenuItem;
+    OpenHeaderDialog: TOpenDialog;
+    N1: TMenuItem;
+    Batch1: TMenuItem;
+    PreviewBox: TPaintBox;
+    procedure NewBtnClick(Sender: TObject);
+    procedure FormCreate(Sender: TObject);
+    procedure FormDestroy(Sender: TObject);
+    procedure ApplyBtnClick(Sender: TObject);
+    procedure OpenBtnClick(Sender: TObject);
+    procedure SaveBtnClick(Sender: TObject);
+    procedure DelBtnClick(Sender: TObject);
+    procedure ItemsListClick(Sender: TObject);
+    procedure ItemEditorStringsChange(Sender: TObject);
+    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    procedure ToolsBtnClick(Sender: TObject);
+    procedure ParseHSFClick(Sender: TObject);
+    procedure ParseHeaderClick(Sender: TObject);
+    procedure PreviewBoxPaint(Sender: TObject);
+    procedure ItemsListData(Control: TWinControl; Index: Integer;
+      var Data: string);
+    procedure Batch1Click(Sender: TObject);
+    procedure SetModified(Sender: TObject);
+  private
+    { Déclarations privées }
+  public
+    { Déclarations publiques }
+    Filename: string;
+    Locked, Modified: Boolean;
+    Lst, LastHeader: TStringList;
+    HSFDir: string;
+    procedure UpdatePreview;
+    procedure SetItem(const Name, Left, Right, Description: string; Line: Cardinal);
+
+    // Stream methods
+    procedure Clear;
+    procedure LoadFromStream(F: TStream);
+    procedure SaveToStream(F: TStream);
+
+    // Tools Method
+    function ParseH(const FileName: string): Boolean;
+
+    // Add Symbol Line
+    function GetLine(const Symbol: string): Integer;
+  end;
+
+var
+  CEditorForm: TCEditorForm;
+
+procedure ClearCompletion(Lst: TStrings);
+
+implementation
+
+{$R *.dfm}
+
+uses uHSFParser, Math, uBatch;
+
+procedure ClearCompletion(Lst: TStrings);
+var
+  i: Integer;
+begin
+  for i := 0 to Lst.Count - 1 do
+    Lst.Objects[i].Free;
+  Lst.Clear;
+end;
+
+procedure TCEditorForm.UpdatePreview;
+begin
+  PreviewBox.Repaint;
+end;
+
+procedure TCEditorForm.NewBtnClick(Sender: TObject);
+begin
+  Clear;
+end;
+
+procedure TCEditorForm.FormCreate(Sender: TObject);
+begin
+  LastHeader := TStringList.Create;
+  Lst := TStringList.Create;
+  Lst.Sorted := True;
+  ItemEditor.ColWidths[0] := 96;
+  ItemEditor.Strings.Clear;
+  ItemEditor.Strings.Add(Cell_Name + '=');
+  ItemEditor.Strings.Add(Cell_Left + '=');
+  ItemEditor.Strings.Add(Cell_Right + '=');
+  ItemEditor.Strings.Add(Cell_Desc + '=');
+  ItemEditor.Strings.Add(Cell_Line + '=');
+  Modified := False;
+  Clear;
+end;
+
+procedure TCEditorForm.FormDestroy(Sender: TObject);
+begin
+  ClearCompletion(Lst);
+  Lst.Free;
+  LastHeader.Free;
+end;
+
+procedure TCEditorForm.ApplyBtnClick(Sender: TObject);
+begin
+  SetItem(ItemEditor.Values[Cell_Name],
+    ItemEditor.Values[Cell_Left],
+    ItemEditor.Values[Cell_Right],
+    ItemEditor.Values[Cell_Desc],
+    StrToIntDef(ItemEditor.Values[Cell_Line], 0));
+end;
+
+procedure TCEditorForm.OpenBtnClick(Sender: TObject);
+var
+  F: TFileStream;
+begin
+  if CloseQuery and OpenDialog.Execute then
+  try
+    Lst.Clear;
+    IncludeMemo.Clear;
+    F := TFileStream.Create(OpenDialog.FileName, fmOpenRead);
+    try
+      LoadFromStream(F);
+      Filename := OpenDialog.FileName;
+      Caption := DefautCaption + ' - ' + ExtractFileName(Filename);
+    finally
+      F.Free;
+    end;
+  except
+    on E: Exception do
+      ShowMessageFmt(LoadingError, [E.ClassName, E.Message]);
+  end;
+  ItemsList.Count := Lst.Count;
+end;
+
+procedure TCEditorForm.SaveBtnClick(Sender: TObject);
+var
+  F: TFileStream;
+begin
+  if FileExists(Filename) or SaveDialog.Execute then
+  try
+    F := TFileStream.Create(SaveDialog.FileName, fmCreate);
+    SaveToStream(F);
+    F.Free;
+    Filename := SaveDialog.FileName;
+    Caption := DefautCaption + ' - ' + ExtractFileName(Filename);
+    Modified := False;
+  except
+    on E: Exception do
+      ShowMessageFmt(SaveError, [E.ClassName, E.Message]);
+  end;
+end;
+
+procedure TCEditorForm.DelBtnClick(Sender: TObject);
+var
+  i: Integer;
+begin
+  for i := Lst.Count - 1 downto 0 do
+    if ItemsList.Selected[i] then
+    begin
+      Lst.Objects[i].Free;
+      Lst.Delete(i);
+    end;
+  ItemsList.Count := Lst.Count;
+end;
+
+procedure TCEditorForm.ItemsListClick(Sender: TObject);
+var
+  i: Integer;
+  O: TCompletionItem;
+begin
+  if ItemsList.SelCount > 0 then
+  begin
+    i := ItemsList.ItemIndex;
+    ItemEditor.Strings.BeginUpdate;
+    ItemEditor.Values[Cell_Name] := Lst[i];
+    O := TCompletionItem(Lst.Objects[i]);
+    if Assigned(O) then
+    begin
+      ItemEditor.Values[Cell_Left] := O.Left;
+      ItemEditor.Values[Cell_Right] := O.Right;
+      ItemEditor.Values[Cell_Desc] := O.Description;
+      ItemEditor.Values[Cell_Line] := IntToStr(O.Line);
+    end;
+    ItemEditor.Strings.EndUpdate;
+    UpdatePreview;
+  end;
+end;
+
+procedure TCEditorForm.ItemEditorStringsChange(Sender: TObject);
+begin
+  UpdatePreview;
+  SetModified(Sender);
+end;
+
+procedure TCEditorForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+begin
+  CanClose := True;
+  if Modified then
+    case MessageDlg(SaveModif, mtConfirmation, mbYesNoCancel, 0) of
+      mrYes: SaveBtn.Click;
+      mrNo: ;
+    else
+      CanClose := False;
+    end;
+end;
+
+procedure TCEditorForm.ToolsBtnClick(Sender: TObject);
+var
+  P: TPoint;
+begin
+  P := Point(0, ToolsBtn.Height);
+  P := ToolsBtn.ClientToScreen(P);
+  ToolsMenu.Popup(P.X, P.Y);
+end;
+
+procedure TCEditorForm.ParseHeaderClick(Sender: TObject);
+begin
+  if OpenHeaderDialog.Execute then
+    ParseH(OpenHeaderDialog.FileName);
+end;
+
+procedure TCEditorForm.ParseHSFClick(Sender: TObject);
+begin
+  if SelectDirectory(BrowseHSF, '', HSFDir) then
+  begin
+    Locked := True;
+    Lst.BeginUpdate;
+    ImportDir(HSFDir, Self, GetLine);
+    Lst.EndUpdate;
+    Locked := False;
+    ItemsList.Count := Lst.Count;
+  end;
+end;
+
+procedure TCEditorForm.SetItem(const Name, Left, Right, Description: string; Line: Cardinal);
+var
+  i: Integer;
+  O: TCompletionItem;
+begin
+  if (Name <> '') then
+  begin
+    i := Lst.IndexOf(Name);
+    if i = -1 then
+    begin
+      O := TCompletionItem.Create;
+      i := Lst.AddObject(Name, O);
+    end
+    else
+      O := TCompletionItem(Lst.Objects[i]);
+    O.Left := Left;
+    O.Right := Right;
+    O.Description := Description;
+    O.Line := Line;
+    if not Locked then
+    begin
+      ItemsList.Count := Lst.Count;
+      ItemsList.ItemIndex := i;
+    end;
+    Modified := True;
+  end;
+end;
+
+procedure TCEditorForm.LoadFromStream(F: TStream);
+var
+  S: string;
+  i, W: Word;
+  C: TCompletionItem;
+  B: Byte;
+begin
+  if (F.Read(B, 1) = 1) and (B = CCFVersion) and ReadString(F, S) then
+  begin
+    // Set Unit Name
+    UNameEdit.Text := S;
+    if F.Read(W, 2) = 2 then
+    begin
+      // Load Includes List
+      IncludeMemo.Lines.Clear;
+      for i := 1 to W do
+      begin
+        if ReadString(F, S) then
+          IncludeMemo.Lines.Add(S)
+        else
+          Break;
+      end;
+      // Load Symbols List
+      while ReadString(F, S) do
+      begin
+        C := TCompletionItem.Create;
+        C.ReadFromStream(F);
+        Lst.AddObject(S, C);
+      end;
+    end;
+    ItemsList.Count := Lst.Count;
+  end;
+end;
+
+procedure TCEditorForm.PreviewBoxPaint(Sender: TObject);
+var
+  H, W: Integer;
+  C: TCanvas;
+  R: TRect;
+begin
+  C := PreviewBox.Canvas;
+  R := PreviewBox.ClientRect;
+  H := C.TextHeight(PreviewLbl) + 2;
+
+  try
+    C.FillRect(R);
+    // Draw Preview
+    C.TextRect(R, R.Left, R.Top, PreviewLbl);
+    Inc(R.Top, H);
+
+    // Draw Left
+    DrawHtText(ItemEditor.Values[Cell_Left], R, C, W, False);
+    Inc(R.Top, H);
+
+    // Draw Name
+    C.Font.Style := [fsBold];
+    C.TextRect(R, R.Left, R.Top, ItemEditor.Values[Cell_Name]);
+    C.Font.Style := [];
+    Inc(R.Top, H);
+
+    // Draw Right
+    DrawHtText(ItemEditor.Values[Cell_Right], R, C, W, False);
+    Inc(R.Top, H);
+
+    // Draw Description
+    C.TextRect(R, R.Left, R.Top, ItemEditor.Values[Cell_Desc]);
+    Inc(R.Top, H);
+
+  except
+    C.Font.Style := [];
+  end;
+end;
+
+procedure TCEditorForm.SaveToStream(F: TStream);
+var
+  i: Integer;
+  W: Word;
+begin
+  try
+    // Write CCF Version
+    F.Write(CCFVersion, SizeOf(CCFVersion));
+    // Write Unit Name
+    WriteString(F, UNameEdit.Text);
+    // Write Included Units
+    W := IncludeMemo.Lines.Count;
+    if F.Write(W, 2) = 2 then
+      for i := 0 to W - 1 do
+        if not WriteString(F, Trim(IncludeMemo.Lines[i])) then
+          Break;
+    // Write Symbols
+    for i := 0 to Lst.Count - 1 do
+    begin
+      if WriteString(F, Lst[i]) then
+        TCompletionItem(Lst.Objects[i]).WriteToStream(F)
+      else
+        Break;
+    end;
+  except
+  end;
+end;
+
+function TCEditorForm.ParseH(const FileName: string): Boolean;
+var
+  Src: TStringList;
+  S: TStream;
+begin
+  Src := TStringList.Create;
+  try
+    try
+      Src.LoadFromFile(FileName);
+      S := TStringStream.Create(MakeCCF_H(ExtractFileName(FileName), Src, LastHeader));
+      try
+        LoadFromStream(S);
+      finally
+        S.Free;
+      end;
+    finally
+      Src.Free;
+    end;
+    Result := True;
+  except
+    Result := False;
+  end;
+end;
+
+procedure TCEditorForm.Clear;
+begin
+  if CloseQuery then
+  begin
+    LastHeader.Clear;
+    Caption := DefautCaption;
+    Filename := '';
+    UNameEdit.Text := '';
+    IncludeMemo.Text := '';
+    ClearCompletion(Lst);
+    ItemsList.Count := 0;
+  end;
+end;
+
+procedure TCEditorForm.ItemsListData(Control: TWinControl; Index: Integer;
+  var Data: string);
+begin
+  if (Index >= 0) and (Index < Lst.Count) then
+    Data := Lst[Index]
+  else
+    ItemsList.Count := Lst.Count;
+end;
+
+procedure TCEditorForm.Batch1Click(Sender: TObject);
+var
+  B: TBatchEdit;
+begin
+  Locked := True;
+  B := TBatchEdit.Create(Self);
+  B.Editor := Self;
+  B.ShowModal;
+  B.Free;
+  Locked := False;
+end;
+
+procedure TCEditorForm.SetModified(Sender: TObject);
+begin
+  Modified := True;
+end;
+
+function TCEditorForm.GetLine(const Symbol: string): Integer;
+var
+  i, p: Integer;
+  S: string;
+begin
+  for i := 0 to LastHeader.Count - 1 do
+  begin
+    S := LastHeader[i];
+    p := Pos(Symbol, S);
+    if not ((p = 0) or ((p > 1) and (S[p - 1] in ['a'..'z', 'A'..'Z', '0'..'9', '$', '_']))) then
+      if GetIdent(S, p) = Symbol then
+      begin
+        Result := i;
+        Exit;
+      end;
+  end;
+  Result := 0;
+end;
+
+end.

+ 189 - 0
CodeCompletion/Editor/uHSFParser.pas

@@ -0,0 +1,189 @@
+unit uHSFParser;
+
+interface
+
+uses Classes, uEditor;
+
+type
+  TOnGetLine = function(const Symbol: string): Integer of object;
+
+procedure ImportFile(const FileName: string; F: TCEditorForm; GetLine: TOnGetLine);
+procedure ImportDir(Dir: string; F: TCEditorForm; GetLine: TOnGetLine);
+
+function SimplifyType(T: string): string;
+function SimplifyLeft(T: string; out Right: string): string;
+function FilterComment(const Comment: string): string;
+function FilterDesc(const Def: string): string;
+
+var
+  DoEnum: Boolean;
+
+implementation
+
+uses SysUtils, StrUtils, UtilsDos;
+
+function SimplifyType(T: string): string;
+begin
+  T := Trim(T);
+  if T = 'Type' then
+    Result := '<c:Olive>type'
+  else if T = 'Function' then
+    Result := '<c:Teal>func'
+  else if T = 'Constant' then
+    Result := '<c:Green>const'
+  else if T = 'Variable' then
+    Result := '<c:Maroon>var'
+  else if T = 'Enum' then
+    Result := '<c:Olive>enum'
+  else
+    Result := T;
+end;
+
+function SimplifyLeft(T: string; out Right: string): string;
+begin
+  T := Trim(T);
+  if AnsiStartsText('typedef', T) then
+  begin
+    Right := Copy(T, 9, MaxInt);
+    Result := '';
+  end
+  else if AnsiStartsText('CALLBACK', T) then
+  begin
+    Result := '<i>callback';
+    Right := Trim(Copy(T, 10, MaxInt)) + ' | ';
+  end
+  else if T = 'unknown_retval' then
+    Result := '?'
+  else if T = '#define' then
+    Result := ''
+  else
+    Result := T;
+end;
+
+function FilterComment(const Comment: string): string;
+var
+  i, j: Integer;
+begin
+  Result := '';
+  i := Pos('/*', Comment);
+  j := -1;
+  while i <> 0 do
+  begin
+    Result := Result + Copy(Comment, j + 2, i - j - 1);
+    j := PosEx('*/', Comment, i);
+    if j = 0 then
+    begin
+      j := MaxInt;
+      Break;
+    end;
+    i := PosEx('/*', Comment, j);
+  end;
+  Result := Result + Copy(Comment, j + 2, MaxInt);
+end;
+
+function FilterDesc(const Def: string): string;
+var
+  i, j: Integer;
+begin
+  Result := '';
+  i := Pos('<', Def);
+  j := 0;
+  while i <> 0 do
+  begin
+    Result := Result + Copy(Def, j + 1, i - j - 1);
+    j := PosEx('>', Def, i);
+    if j = 0 then
+    begin
+      j := MaxInt;
+      Break;
+    end;
+    i := PosEx('<', Def, j);
+  end;
+  Result := Result + Copy(Def, j + 1, MaxInt);
+end;
+
+procedure FilterEnum(const Definition, Description: string; F: TCEditorForm; Line: Integer);
+var
+  Items: TStringList;
+  i, p: Integer;
+  L, R, S: string;
+begin
+  Items := TStringList.Create;
+  p := Pos('{', Definition);
+  if p <> 0 then
+  begin
+    Inc(p);
+    Items.CommaText := Copy(Definition, p, PosEx('}', Definition, p) - p);
+    L := '<c:Olive>' + Trim(Copy(Definition, 1, p - 2));
+    for i := 0 to Items.Count - 1 do
+    begin
+      S := Trim(Items[i]);
+      p := Pos('=', S);
+      if P <> 0 then
+      begin
+        R := Trim(Copy(S, p + 1, MaxInt));
+        S := Trim(Copy(S, 1, p - 1));
+      end
+      else
+        R := '';
+      F.SetItem(S, L, R, Description, Line);
+    end;
+  end;
+  Items.Free;
+
+end;
+
+procedure ImportFile(const FileName: string; F: TCEditorForm; GetLine: TOnGetLine);
+var
+  Lst: TStringList;
+  Name, Left, Right, Description, Definition, Tmp: string;
+  i, Line: Integer;
+begin
+  Lst := TStringList.Create;
+  Lst.LoadFromFile(FileName);
+
+  Name := Lst.Values['Name'];
+  Definition := Lst.Values['Definition'];
+  Left := FilterComment(SimplifyType(Lst.Values['Type']) + ' <c:Blue>' + SimplifyLeft(Copy(Definition, 1, Pos(Name, Definition) - 1), Tmp));
+  Right := Tmp + Trim(Copy(Definition, Pos(Name, Definition) + Length(Name), MaxInt));
+
+  i := Lst.IndexOf('[Description]');
+  if i <> -1 then
+    Description := FilterDesc(Lst[i + 1])
+  else
+    Description := '';
+
+  if Assigned(GetLine) then
+    Line := GetLine(Name)
+  else
+    Line := 0;
+
+  F.SetItem(Name, Left, Right, Description, Line);
+
+  if DoEnum and (Lst.Values['SubType'] = 'Enumeration') then
+    FilterEnum(Definition, Description, F, Line);
+
+  Lst.Free;
+end;
+
+procedure ImportDir(Dir: string; F: TCEditorForm; GetLine: TOnGetLine);
+var
+  SR: TSearchRec;
+begin
+  Dir := IncludeTrailingPathDelimiter(Dir);
+  if FindFirst(Dir + '*.*', faAnyFile, SR) = 0 then
+  begin
+    repeat
+      if SR.Name[1] <> '.' then
+      begin
+        if SR.Attr and faDirectory = faDirectory then
+          ImportDir(Dir + SR.Name, F, GetLine)
+        else if UpperCase(ExtractFileExt(SR.Name)) = '.HSF' then
+          ImportFile(Dir + SR.Name, F, GetLine);
+      end;
+    until FindNext(SR) <> 0;
+    FindClose(SR);
+  end;
+end;
+
+end.

+ 196 - 0
CodeCompletion/HtFormatting.pas

@@ -0,0 +1,196 @@
+unit HtFormatting;
+
+interface
+
+uses Windows, Types, Classes, Graphics, Forms, Controls;
+
+// Show an hint window with formatted text
+
+type
+  THtHintWindow = class(THintWindow)
+  protected
+    procedure Paint; override;
+  public
+    function CalcHintRect(MaxWidth: Integer; const AHint: string;
+      AData: Pointer): TRect; override;
+  end;
+
+  // Draw text with a small HTML-like formatting
+  // Tags: B (bold), I (italic), U (underline) or S (strike-out)
+  //
+  // You can also use <C:Color> for changing text color
+
+procedure DrawHtTextEx(const Text: string; out PlainText: string; Rect: TRect; Cnv: TCanvas; var Width, Height: Integer; NoColor: Boolean);
+procedure DrawHtText(const Text: string; Rect: TRect; Cnv: TCanvas; var Width: Integer; NoColor: Boolean);
+
+procedure DrawMultiLineHtTextEx(const Text: string; out PlainText: string; Rect: TRect; Cnv: TCanvas; var Width, Height: Integer; NoColor: Boolean);
+procedure DrawMultiLineHtText(const Text: string; Rect: TRect; Cnv: TCanvas; var Width: Integer; NoColor: Boolean);
+
+implementation
+
+uses StrUtils, MaskUtils, UtilsDos;
+
+procedure DrawHtTextEx(const Text: string; out PlainText: string; Rect: TRect; Cnv: TCanvas; var Width, Height: Integer; NoColor: Boolean);
+var
+  i, l, p: Integer;
+  S: string;
+  X, BWidth: Integer;
+  C: Char;
+  OriginalColor: TColor;
+  OriginalStyle: TFontStyles;
+  Size: tagSIZE;
+begin
+  OriginalColor := Cnv.Font.Color;
+  OriginalStyle := Cnv.Font.Style;
+  l := Length(Text);
+  p := 0;
+  X := Rect.Left;
+  Height := 0;
+  PlainText := '';
+  BWidth := Cnv.TextWidth('<');
+  while p < l do
+  begin
+    i := p + 1;
+    p := PosEx('<', Text, i);
+    if p = 0 then
+      p := l + 1;
+
+    // Draw Text
+    S := Copy(Text, i, p - i);
+    Cnv.TextRect(Rect, Rect.Left, Rect.Top, S);
+    PlainText := PlainText + S;
+
+    // Update Size
+    Size := Cnv.TextExtent(S);
+    Inc(Rect.Left, Size.cx);
+    if Size.cy > Height then
+      Height := Size.cy;
+
+    if p <> l then
+    begin
+      C := UpCase(Text[p + 1]);
+      if C <> 'C' then
+      begin
+        case C of
+          'B': Cnv.Font.Style := Cnv.Font.Style + [fsBold];
+          'U': Cnv.Font.Style := Cnv.Font.Style + [fsItalic];
+          'I': Cnv.Font.Style := Cnv.Font.Style + [fsUnderline];
+          'S': Cnv.Font.Style := Cnv.Font.Style + [fsStrikeOut];
+          '/':
+            if p + 1 < l then
+            begin
+              case UpCase(Text[p + 2]) of
+                'B': Cnv.Font.Style := Cnv.Font.Style - [fsBold];
+                'U': Cnv.Font.Style := Cnv.Font.Style - [fsItalic];
+                'I': Cnv.Font.Style := Cnv.Font.Style - [fsUnderline];
+                'S': Cnv.Font.Style := Cnv.Font.Style - [fsStrikeOut];
+              end;
+            end;
+          '<':
+            begin
+              Cnv.TextRect(Rect, Rect.Left, Rect.Top, '<');
+              Inc(Rect.Left, BWidth);
+            end;
+        end;
+        p := PosEx('>', Text, p + 1);
+        if p = 0 then
+          p := l;
+      end
+      else
+      begin
+        Inc(P, 3);
+        i := PosEx('>', Text, p);
+        if i = 0 then
+          p := l
+        else
+        begin
+          S := Copy(Text, p, i - p);
+          if S <> '' then
+          begin
+            if not (S[1] in ['0'..'9', '$']) then
+              S := 'cl' + S;
+            try
+              if not NoColor then
+                Cnv.Font.Color := StringToColor(S);
+            except
+            end;
+          end;
+          p := i;
+        end;
+      end;
+    end
+    else
+      Break;
+  end;
+  Width := Rect.Left - X;
+  Cnv.Font.Color := OriginalColor;
+  Cnv.Font.Style := OriginalStyle;
+end;
+
+procedure DrawMultiLineHtTextEx(const Text: string; out PlainText: string; Rect: TRect; Cnv: TCanvas; var Width, Height: Integer; NoColor: Boolean);
+var
+  Lst: TStringList;
+  S: string;
+  i, W, H: Integer;
+begin
+  Lst := TStringList.Create;
+  Lst.Text := Text;
+  Height := 0;
+  Width := 0;
+  for i := 0 to Lst.Count - 1 do
+  begin
+    DrawHtTextEx(Lst[i], S, Rect, Cnv, W, H, NoColor);
+    if W > Width then
+      Width := W;
+    Inc(Height, H);
+    Inc(Rect.Top, H);
+    Lst[i] := S;
+  end;
+  PlainText := Lst.Text;
+  Lst.Free;
+end;
+
+procedure DrawHtText(const Text: string; Rect: TRect; Cnv: TCanvas; var Width: Integer; NoColor: Boolean);
+var
+  S: string;
+  H: Integer;
+begin
+  DrawHtTextEx(Text, S, Rect, Cnv, Width, H, NoColor);
+end;
+
+procedure DrawMultiLineHtText(const Text: string; Rect: TRect; Cnv: TCanvas; var Width: Integer; NoColor: Boolean);
+var
+  S: string;
+  H: Integer;
+begin
+  DrawMultiLineHtTextEx(Text, S, Rect, Cnv, Width, H, NoColor);
+end;
+
+{ THtHintWindow }
+
+function THtHintWindow.CalcHintRect(MaxWidth: Integer; const AHint: string;
+  AData: Pointer): TRect;
+var
+  P: string;
+  R: TRect;
+  W, H: Integer;
+begin
+  R := Rect(2, 2, 2, 2);
+  Canvas.Font.Color := Screen.HintFont.Color;
+  DrawMultiLineHtTextEx(AHint, P, R, Self.Canvas, W, H, False);
+  Result := Rect(0, 0, W + 2, H + 2);
+end;
+
+procedure THtHintWindow.Paint;
+var
+  R: TRect;
+  W: Integer;
+begin
+  R := ClientRect;
+  Inc(R.Left, 2);
+  Inc(R.Top, 2);
+  Canvas.Font.Color := Screen.HintFont.Color;
+  DrawMultiLineHtText(Caption, R, Self.Canvas, W, False);
+end;
+
+end.

BIN
CodeCompletion/PrefFrame.dfm


+ 108 - 0
CodeCompletion/PrefFrame.pas

@@ -0,0 +1,108 @@
+unit PrefFrame;
+
+interface
+
+uses
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, TmpltForm;
+
+type
+  TCodingExt = class(TFrame)
+    TemplateBox: TGroupBox;
+    CompBox: TGroupBox;
+    CompEditor: TButton;
+    TmpltList: TListBox;
+    IdLbl: TLabel;
+    CodeLbl: TLabel;
+    IdEdit: TEdit;
+    CodeMemo: TMemo;
+    ClearBtn: TButton;
+    ApplyBtn: TButton;
+    procedure CompEditorClick(Sender: TObject);
+    procedure TmpltListData(Control: TWinControl; Index: Integer;
+      var Data: string);
+    procedure ApplyBtnClick(Sender: TObject);
+    procedure ClearBtnClick(Sender: TObject);
+    procedure TmpltListClick(Sender: TObject);
+    procedure OnShow(Sender: TObject);
+  public
+    { Déclarations publiques }
+
+  end;
+
+implementation
+
+{$R *.dfm}
+
+uses uEditor;
+
+procedure TCodingExt.CompEditorClick(Sender: TObject);
+var
+  Form: TCEditorForm;
+begin
+  Form := TCEditorForm.Create(Self);
+  Form.ShowModal;
+  Form.Free;
+end;
+
+procedure TCodingExt.TmpltListData(Control: TWinControl; Index: Integer;
+  var Data: string);
+begin
+  if (Index >= 0) and (Index < TemplateForm.Templates.Count) then
+    Data := TemplateForm.Templates[Index];
+end;
+
+procedure TCodingExt.ApplyBtnClick(Sender: TObject);
+var
+  Id: string;
+  T: TTemplate;
+  i: Integer;
+begin
+  Id := Trim(IdEdit.Text);
+  if Id <> '' then
+  begin
+    if TemplateForm.Templates.Find(Id, i) then
+      TTemplate(TemplateForm.Templates.Objects[i]).Text := CodeMemo.Text
+    else
+    begin
+      T := TTemplate.Create;
+      T.Text := CodeMemo.Text;
+      TemplateForm.Templates.AddObject(Id, T);
+    end;
+  end;
+  TmpltList.Count := TemplateForm.Templates.Count;
+end;
+
+procedure TCodingExt.ClearBtnClick(Sender: TObject);
+var
+  i: Integer;
+begin
+  for i := TemplateForm.Templates.Count - 1 downto 0 do
+    if TmpltList.Selected[i] then
+    begin
+      TemplateForm.Templates.Objects[i].Free;
+      TemplateForm.Templates.Delete(i);
+    end;
+  TmpltList.Count := TemplateForm.Templates.Count;
+end;
+
+procedure TCodingExt.TmpltListClick(Sender: TObject);
+var
+  Index: Integer;
+begin
+  if TmpltList.SelCount > 0 then
+  begin
+    Index := TmpltList.ItemIndex;
+    IdEdit.Text := TemplateForm.Templates[Index];
+    CodeMemo.Text := TTemplate(TemplateForm.Templates.Objects[Index]).Text;
+  end;
+end;
+
+procedure TCodingExt.OnShow(Sender: TObject);
+begin
+  if TmpltList.Count <> TemplateForm.Templates.Count then
+    TmpltList.Count := TemplateForm.Templates.Count;
+end;
+
+end.
+

BIN
CodeCompletion/TmpltForm.dfm


+ 200 - 0
CodeCompletion/TmpltForm.pas

@@ -0,0 +1,200 @@
+unit TmpltForm;
+
+interface
+
+uses
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, MemoComponentUnit;
+
+type
+	TTemplate = class(TObject)
+	public
+		Text: string;
+		procedure Apply(Dest: TMemoComponent);
+	end;
+
+	TTemplateForm = class(TForm)
+		TmpltList: TListBox;
+		procedure FormDeactivate(Sender: TObject);
+		procedure TmpltListData(Control: TWinControl; Index: Integer;
+			var Data: string);
+		procedure FormCreate(Sender: TObject);
+		procedure FormDestroy(Sender: TObject);
+		procedure TmpltListDblClick(Sender: TObject);
+		procedure TmpltListKeyDown(Sender: TObject; var Key: Word;
+			Shift: TShiftState);
+		procedure FormActivate(Sender: TObject);
+	public
+		{ Déclarations publiques }
+		Templates: TStringList;
+		procedure Select;
+	end;
+
+var
+	TemplateForm: TTemplateForm;
+
+implementation
+
+{$R *.dfm}
+
+uses MasterUnit, UtilsDos, CodeCompletion, CompletionForm;
+
+{ TTemplate }
+
+procedure TTemplate.Apply(Dest: TMemoComponent);
+var
+  St: Integer;
+  i, p: Integer;
+  S, Before: string;
+  Lst: TStringList;
+  T: TTextCell;
+begin
+  // Indent template
+  T := Dest.Selection.StartRowCol;
+  Before := Copy(Dest.Lines[T.Row - 1], 1, T.Col - 1);
+  Lst := TStringList.Create;
+  Lst.Text := Text;
+  for i := 1 to Lst.Count - 1 do
+    Lst[i] := Before + Lst[i];
+	S := Lst.Text;
+	if (Copy(S, Length(S) - 1, 2) = #13#10) and (Copy(Text, Length(Text) - 1, 2) <> #13#10) then
+		Delete(S, Length(S) - 1, 2);
+	Lst.Free;
+
+  p := Pos('|', S);
+
+  st := Dest.Selection.RStart;
+  if p = 0 then
+    Dest.Selection.Text := S
+  else
+  begin
+    Delete(S, p, 1);
+    Dest.Selection.Text := S;
+    Inc(St, p - 1);
+  end;
+  Dest.Selection.RStart := st;
+  Dest.Selection.RLength := 0;
+end;
+
+{ TTemplateForm }
+
+procedure TTemplateForm.FormDeactivate(Sender: TObject);
+begin
+  Hide;
+end;
+
+procedure TTemplateForm.TmpltListData(Control: TWinControl; Index: Integer;
+  var Data: string);
+begin
+  if (Index >= 0) and (Index < Templates.Count) then
+    Data := Templates[Index];
+end;
+
+procedure TTemplateForm.FormCreate(Sender: TObject);
+var
+  T: TTemplate;
+  F: TStream;
+  S: string;
+begin
+  Templates := TStringList.Create;
+  Templates.Sorted := True;
+	S := WithBackslash(TIGCCFolder) + TemplatesLocation + 'templates.dat';
+  if FileExists(S) then
+  try
+    F := TFileStream.Create(S, fmOpenRead);
+    try
+      while ReadString(F, S) do
+      begin
+        T := TTemplate.Create;
+        ReadString(F, T.Text);
+        Templates.AddObject(S, T);
+      end;
+    finally
+      F.Free;
+    end;
+  except
+  end;
+end;
+
+procedure TTemplateForm.FormDestroy(Sender: TObject);
+var
+  i: Integer;
+  F: TStream;
+  T: TTemplate;
+begin
+  try
+    F := TFileStream.Create(WithBackslash(TIGCCFolder) + TemplatesLocation + 'templates.dat', fmCreate);
+    try
+      for i := 0 to Templates.Count - 1 do
+      begin
+        T := TTemplate(Templates.Objects[i]);
+        if Assigned(T) then
+        begin
+          WriteString(F, Templates[i]);
+          WriteString(F, T.Text);
+        end;
+      end;
+    finally
+      F.Free;
+    end;
+  except
+  end;
+  for i := 0 to Templates.Count - 1 do
+    Templates.Objects[i].Free;
+  Templates.Free;
+end;
+
+procedure TTemplateForm.TmpltListDblClick(Sender: TObject);
+begin
+  Select;
+end;
+
+procedure TTemplateForm.TmpltListKeyDown(Sender: TObject; var Key: Word;
+  Shift: TShiftState);
+begin
+  case Key of
+    VK_RETURN:
+      Select;
+    VK_ESCAPE, VK_CLEAR, VK_BACK, VK_DELETE:
+      Hide;
+  end;
+
+end;
+
+procedure TTemplateForm.Select;
+var
+  Idx: Integer;
+  M: TMemoComponent;
+  T: TTemplate;
+begin
+  M := CompForm.Editor;
+  if Assigned(M) then
+  begin
+    Idx := TmpltList.ItemIndex;
+    if (Idx >= 0) and (Idx < Templates.Count) then
+    begin
+      T := TTemplate(Templates.Objects[Idx]);
+      if Assigned(T) then
+        T.Apply(M);
+    end;
+  end;
+  Hide;
+end;
+
+procedure TTemplateForm.FormActivate(Sender: TObject);
+var
+  M: TMemoComponent;
+  P: TPoint;
+begin
+	TmpltList.Count := Templates.Count;
+	M := CompForm.Editor;
+	if Assigned(M) then
+	begin
+		TmpltList.ItemIndex := 0;
+		P := M.ClientToScreen(M.Selection.StartPoint);
+		Left := P.X + 4;
+		Top := P.Y + 20;
+	end;
+end;
+
+end.

BIN
ColorsUnit.dfm


+ 120 - 0
ColorsUnit.pas

@@ -0,0 +1,120 @@
+unit ColorsUnit;
+
+interface
+
+uses
+  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+  ExtCtrls, StdCtrls;
+
+type
+  TMultipleColorsForm = class(TForm)
+    ColorBox: TListBox;
+    Button1: TButton;
+    Button2: TButton;
+    Button3: TButton;
+    Bevel1: TBevel;
+    Button4: TButton;
+    Button5: TButton;
+    ColorDlg: TColorDialog;
+    procedure ColorBoxDrawItem(Control: TWinControl; Index: Integer;
+      Rect: TRect; State: TOwnerDrawState);
+    procedure EditColor(Sender: TObject);
+    procedure Button1Click(Sender: TObject);
+    procedure Button2Click(Sender: TObject);
+    procedure ColorBoxKeyDown(Sender: TObject; var Key: Word;
+      Shift: TShiftState);
+    procedure UpdateButtons(Sender: TObject);
+  private
+	public
+	end;
+
+implementation
+
+{$R *.DFM}
+
+procedure TMultipleColorsForm.ColorBoxDrawItem(Control: TWinControl; Index: Integer;
+	Rect: TRect; State: TOwnerDrawState);
+begin
+	with Control as TListBox do begin
+		if odSelected in State then
+			Canvas.Pen.Color := clHighlight
+		else
+			Canvas.Pen.Color := Color;
+		Canvas.MoveTo (Rect.Left, Rect.Top);
+		Canvas.LineTo (Rect.Right, Rect.Top);
+		Canvas.MoveTo (Rect.Left, Rect.Top + 1);
+		Canvas.LineTo (Rect.Right, Rect.Top + 1);
+		Canvas.MoveTo (Rect.Left, Rect.Bottom - 1);
+		Canvas.LineTo (Rect.Right, Rect.Bottom - 1);
+		Canvas.MoveTo (Rect.Left, Rect.Bottom - 2);
+		Canvas.LineTo (Rect.Right, Rect.Bottom - 2);
+		Canvas.MoveTo (Rect.Left, Rect.Top);
+		Canvas.LineTo (Rect.Left, Rect.Bottom);
+		Canvas.MoveTo (Rect.Left + 1, Rect.Top);
+		Canvas.LineTo (Rect.Left + 1, Rect.Bottom);
+		Canvas.MoveTo (Rect.Right - 1, Rect.Top);
+		Canvas.LineTo (Rect.Right - 1, Rect.Bottom);
+		Canvas.MoveTo (Rect.Right - 2, Rect.Top);
+		Canvas.LineTo (Rect.Right - 2, Rect.Bottom);
+		Inc (Rect.Left, 2);
+		Inc (Rect.Top, 2);
+		Dec (Rect.Right, 2);
+		Dec (Rect.Bottom, 2);
+		try
+			Canvas.Brush.Color := StrToInt (Items [Index]);
+		except
+			Canvas.Brush.Color := clBlack;
+		end;
+		Canvas.Brush.Style := bsSolid;
+		Canvas.FillRect (Rect);
+	end;
+end;
+
+procedure TMultipleColorsForm.EditColor(Sender: TObject);
+begin
+	if Button3.Enabled then begin
+		try
+			ColorDlg.Color := StrToInt (ColorBox.Items [ColorBox.ItemIndex]);
+		except
+			ColorDlg.Color := clBlack;
+		end;
+		if ColorDlg.Execute then
+			ColorBox.Items [ColorBox.ItemIndex] := '$' + UpperCase (IntToHex (ColorDlg.Color, 6));
+	end;
+end;
+
+procedure TMultipleColorsForm.Button1Click(Sender: TObject);
+var
+	I: Integer;
+begin
+	if ColorDlg.Execute then begin
+		I := ColorBox.Items.Add (UpperCase (IntToHex (ColorDlg.Color, 6)));
+		if ColorBox.Items [I] [1] <> '$' then
+			ColorBox.Items [I] := '$' + ColorBox.Items [I];
+	end;
+	UpdateButtons (Sender);
+end;
+
+procedure TMultipleColorsForm.Button2Click(Sender: TObject);
+begin
+	if Button2.Enabled then
+		ColorBox.Items.Delete (ColorBox.ItemIndex);
+	UpdateButtons (Sender);
+	if Button2.Enabled then
+		ColorBox.ItemIndex := ColorBox.Items.Count - 1;
+end;
+
+procedure TMultipleColorsForm.ColorBoxKeyDown(Sender: TObject;
+	var Key: Word; Shift: TShiftState);
+begin
+	if Key = vk_Delete then
+		Button2.Click;
+end;
+
+procedure TMultipleColorsForm.UpdateButtons(Sender: TObject);
+begin
+	Button2.Enabled := ColorBox.Items.Count > 0;
+	Button3.Enabled := Button2.Enabled;
+end;
+
+end.

BIN
CustomStyleUnit.dfm


+ 114 - 0
CustomStyleUnit.pas

@@ -0,0 +1,114 @@
+unit CustomStyleUnit;
+
+interface
+
+uses
+	SourceEditUnit,
+	Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+	StdCtrls, ExtCtrls;
+
+type
+	TCustomStyleForm = class(TForm)
+		Button1: TButton;
+		Button2: TButton;
+		Bevel1: TBevel;
+		Label1: TLabel;
+		Label2: TLabel;
+		Label3: TLabel;
+		BeginEdit: TEdit;
+		EndEdit: TEdit;
+		IgnoreEdit: TEdit;
+		Bevel2: TBevel;
+		Button3: TButton;
+		Button4: TButton;
+    ColorDlg: TColorDialog;
+    SwitchableCheckBox: TCheckBox;
+		procedure FormCreate(Sender: TObject);
+    procedure FormDestroy(Sender: TObject);
+    procedure BeginEditChange(Sender: TObject);
+    procedure EndEditChange(Sender: TObject);
+		procedure IgnoreEditChange(Sender: TObject);
+		procedure SwitchableCheckBoxClick(Sender: TObject);
+		procedure Button1Click(Sender: TObject);
+		procedure Button2Click(Sender: TObject);
+		procedure FormShow(Sender: TObject);
+	private
+	public
+		Style: TCustomStyle;
+	end;
+
+implementation
+
+{$R *.DFM}
+
+uses
+	StyleSelectionUnit;
+
+procedure TCustomStyleForm.FormCreate(Sender: TObject);
+begin
+	Style := TCustomStyle.Create (nil);
+end;
+
+procedure TCustomStyleForm.FormDestroy(Sender: TObject);
+begin
+	Style.Free;
+end;
+
+procedure TCustomStyleForm.BeginEditChange(Sender: TObject);
+begin
+	Style.BeginText := BeginEdit.Text;
+end;
+
+procedure TCustomStyleForm.EndEditChange(Sender: TObject);
+begin
+	Style.EndText := EndEdit.Text;
+end;
+
+procedure TCustomStyleForm.IgnoreEditChange(Sender: TObject);
+begin
+	Style.IgnoreChar := IgnoreEdit.Text;
+end;
+
+procedure TCustomStyleForm.SwitchableCheckBoxClick(Sender: TObject);
+begin
+	Style.Switchable := SwitchableCheckBox.Checked;
+end;
+
+procedure TCustomStyleForm.Button1Click(Sender: TObject);
+begin
+	ColorDlg.Color := Style.Color;
+	if ColorDlg.Execute then begin
+		Style.Color := ColorDlg.Color;
+		Style.CustomColor := True;
+	end;
+end;
+
+procedure TCustomStyleForm.Button2Click(Sender: TObject);
+begin
+	with TStyleSelectionForm.Create (Self) do try
+		CustomStyle := Self.Style.CustomStyle;
+		Style := Self.Style.Style;
+		if ShowModal = mrOK then begin
+			Self.Style.CustomStyle := CustomStyle;
+			Self.Style.Style := Style;
+		end;
+	finally
+		Free;
+	end;
+end;
+
+procedure TCustomStyleForm.FormShow(Sender: TObject);
+begin
+	if Style.BeginText = #13 then
+		BeginEdit.Text := '#13'
+	else
+		BeginEdit.Text := Style.BeginText;
+	if Style.EndText = #13 then
+		EndEdit.Text := '#13'
+	else
+		EndEdit.Text := Style.EndText;
+	IgnoreEdit.Text := Style.IgnoreChar;
+	SwitchableCheckBox.Checked := Style.Switchable;
+end;
+
+end.

+ 72 - 0
FolderUnit.pas

@@ -0,0 +1,72 @@
+unit FolderUnit;
+
+interface
+
+uses
+	Classes, ComCtrls;
+
+type
+	TFolder = class(TObject)
+	private
+		FTreeItem: TTreeNode;
+		function GetFolderName: string;
+		procedure SetFolderName(const Value: string);
+		function GetParent: TFolder;
+    function GetPath: string;
+	public
+		property Parent: TFolder read GetParent;
+	published
+		property FolderName: string read GetFolderName write SetFolderName;
+		property Path: string read GetPath;
+		property TreeItem: TTreeNode read FTreeItem write FTreeItem;
+	end;
+
+implementation
+
+uses
+	UtilsDos;
+
+{ TFolder }
+
+function TFolder.GetFolderName: string;
+begin
+	if Assigned (TreeItem) then
+		Result := TreeItem.Text
+	else
+		Result := '';
+end;
+
+function TFolder.GetParent: TFolder;
+var
+	ParentItem: TTreeNode;
+begin
+	Result := nil;
+	if Assigned (TreeItem) then begin
+		ParentItem := TreeItem.Parent;
+		if Assigned (ParentItem) and Assigned (ParentItem.Data) and (TObject (ParentItem.Data) is TFolder) then
+			Result := ParentItem.Data;
+	end;
+end;
+
+function TFolder.GetPath: string;
+var
+	P: TFolder;
+begin
+	P := Parent;
+	if Assigned (P) and (Length (P.FolderName) > 0) then begin
+		Result := P.Path;
+		if Length (Result) > 0 then
+			Result := WithBackslash (Result) + FolderName
+		else
+			Result := FolderName;
+	end else
+		Result := FolderName;
+end;
+
+procedure TFolder.SetFolderName(const Value: string);
+begin
+	if Assigned (TreeItem) then
+		TreeItem.Text := Value;
+end;
+
+end.

BIN
FunctionsWinUnit.dfm


+ 48 - 0
FunctionsWinUnit.pas

@@ -0,0 +1,48 @@
+unit FunctionsWinUnit;
+
+interface
+
+uses
+  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+  StdCtrls, SourceFileUnit;
+
+type
+  TFunctionsForm = class(TForm)
+    FuncList: TListBox;
+    PrototypeButton: TButton;
+    ImplementationButton: TButton;
+    CancelButton: TButton;
+    procedure FuncListDblClick(Sender: TObject);
+    procedure FuncListClick(Sender: TObject);
+		procedure FuncListMouseDown(Sender: TObject; Button: TMouseButton;
+			Shift: TShiftState; X, Y: Integer);
+	private
+	public
+		Funcs: PSourceFileFunctions;
+	end;
+
+implementation
+
+{$R *.DFM}
+
+procedure TFunctionsForm.FuncListDblClick(Sender: TObject);
+begin
+	if ImplementationButton.Enabled then
+		ModalResult := mrNo
+	else if PrototypeButton.Enabled then
+		ModalResult := mrYes;
+end;
+
+procedure TFunctionsForm.FuncListClick(Sender: TObject);
+begin
+	PrototypeButton.Enabled := (FuncList.ItemIndex >= 0) and (Funcs^[Integer(FuncList.Items.Objects[FuncList.ItemIndex])].PrototypeLine > 0);
+	ImplementationButton.Enabled := (FuncList.ItemIndex >= 0) and (Funcs^[Integer(FuncList.Items.Objects[FuncList.ItemIndex])].ImplementationLine > 0);
+end;
+
+procedure TFunctionsForm.FuncListMouseDown(Sender: TObject;
+	Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+begin
+	FuncListClick (Sender);
+end;
+
+end.

+ 36 - 0
IDE.cfg

@@ -0,0 +1,36 @@
+-$A8
+-$B-
+-$C+
+-$D+
+-$E-
+-$F-
+-$G+
+-$H+
+-$I+
+-$J+
+-$K-
+-$L+
+-$M-
+-$N+
+-$O+
+-$P+
+-$Q-
+-$R-
+-$S-
+-$T-
+-$U-
+-$V+
+-$W-
+-$X+
+-$YD
+-$Z1
+-cg
+-AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
+-H+
+-W+
+-M
+-$M16384,1048576
+-K$00400000
+-LE"c:\delphi\delphi6\Projects\Bpl"
+-LN"c:\delphi\delphi6\Projects\Bpl"
+-DCanSplit;CodingExt

+ 104 - 0
IDE.dof

@@ -0,0 +1,104 @@
+[FileVersion]
+Version=6.0
+
+[Compiler]
+A=8
+B=0
+C=1
+D=1
+E=0
+F=0
+G=1
+H=1
+I=1
+J=1
+K=0
+L=1
+M=0
+N=1
+O=1
+P=1
+Q=0
+R=0
+S=0
+T=0
+U=0
+V=1
+W=0
+X=1
+Y=1
+Z=1
+ShowHints=1
+ShowWarnings=1
+UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
+
+[Linker]
+MapFile=0
+OutputObjs=0
+ConsoleApp=1
+DebugInfo=0
+RemoteSymbols=0
+MinStackSize=16384
+MaxStackSize=1048576
+ImageBase=4194304
+ExeDescription=
+
+[Directories]
+OutputDir=
+UnitOutputDir=
+PackageDLLOutputDir=
+PackageDCPOutputDir=
+SearchPath=
+Packages=VCL40;VCLX40
+Conditionals=CanSplit;CodingExt
+DebugSourceDirs=
+UsePackages=0
+
+[Parameters]
+RunParams=
+HostApplication=
+Launcher=
+UseLauncher=0
+DebugCWD=
+
+[Version Info]
+IncludeVerInfo=1
+AutoIncBuild=0
+MajorVer=2
+MinorVer=9
+Release=1
+Build=0
+Debug=0
+PreRelease=0
+Special=0
+Private=0
+DLL=0
+Locale=1033
+CodePage=1252
+
+[Version Info Keys]
+CompanyName=TIGCC Team
+FileDescription=TIGCC IDE
+FileVersion=2.9.1.0
+InternalName=IDE
+LegalCopyright=Copyright (c) Sebastian Reichelt, 2000-2002
+LegalTrademarks=
+OriginalFilename=IDE.exe
+ProductName=TIGCC
+ProductVersion=0.95
+Comments=This program is freely distributable under the terms of the GNU General Public License.  It is kept open-source, but please email me at Sebastian@tigcc.ticalc.org if you found a bug or have a patch.
+
+[Excluded Packages]
+c:\delphi\delphi6\Bin\dcl31w60.bpl=Delphi 1.0 Compatibility Components
+c:\delphi\delphi6\Bin\dclsmp60.bpl=Borland Sample Components
+c:\delphi\delphi6\Bin\dclshlctrls60.bpl=Shell Control Property and Component Editors
+c:\delphi\delphi6\Bin\dclocx60.bpl=Borland Sample Imported ActiveX Controls
+
+[HistoryLists\hlConditionals]
+Count=2
+Item0=CanSplit;CodingExt
+Item1=CanSplit
+
+[HistoryLists\hlUnitAliases]
+Count=1
+Item0=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;

+ 65 - 0
IDE.dpr

@@ -0,0 +1,65 @@
+program IDE;
+
+uses
+  Forms,
+  Controls,
+  VersionUnit in 'VersionUnit.pas',
+	SourceFileUnit in 'SourceFileUnit.pas',
+  MasterUnit in 'MasterUnit.pas',
+	ParsingUnit in 'ParsingUnit.pas',
+  ProcessUnit in 'ProcessUnit.pas',
+  ToolsListUnit in 'ToolsListUnit.pas',
+  MainUnit in 'MainUnit.pas' {MainForm},
+  ProjectOptionsUnit in 'ProjectOptionsUnit.pas' {ProjectOptionsForm},
+  PreferencesUnit in 'PreferencesUnit.pas' {PreferencesForm},
+	AboutUnit in 'AboutUnit.pas' {AboutForm},
+  ProgramOptionsUnit in 'ProgramOptionsUnit.pas' {ProgramOptionsForm},
+	StyleSelectionUnit in 'StyleSelectionUnit.pas' {StyleSelectionForm},
+  ColorsUnit in 'ColorsUnit.pas' {MultipleColorsForm},
+  CustomStyleUnit in 'CustomStyleUnit.pas' {CustomStyleForm},
+  WordListUnit in 'WordListUnit.pas' {WordListForm},
+  StartupScreenUnit in 'StartupScreenUnit.pas' {StartupScreenForm},
+  SourceFileWinUnit in 'SourceFileWinUnit.pas' {SourceFileForm},
+	FunctionsWinUnit in 'FunctionsWinUnit.pas' {FunctionsForm},
+  OpenFileStatusUnit in 'OpenFileStatusUnit.pas' {OpenFileStatusForm},
+	NewsUnit in 'NewsUnit.pas' {NewsForm},
+  SendProgressUnit in 'SendProgressUnit.pas' {SendProgressForm},
+  ToolsUnit in 'ToolsUnit.pas' {ToolsForm},
+	ToolPropertiesUnit in 'ToolPropertiesUnit.pas' {ToolPropertiesForm},
+	ProgramOutputUnit in 'ProgramOutputUnit.pas' {ProgramOutputForm},
+	VTIStartUnit in 'VTIStartUnit.pas' {VTIStartForm},
+{$IFDEF CODINGEXT}
+	CodeCompletion in 'CodeCompletion\CodeCompletion.pas',
+	CompletionForm in 'CodeCompletion\CompletionForm.pas' {CompForm},
+	HtFormatting in 'CodeCompletion\HtFormatting.pas',
+	PrefFrame in 'CodeCompletion\PrefFrame.pas' {CodingExt: TFrame},
+	TmpltForm in 'CodeCompletion\TmpltForm.pas' {TemplateForm},
+	uBatch in 'CodeCompletion\Editor\uBatch.pas' {BatchEdit},
+	uEditor in 'CodeCompletion\Editor\uEditor.pas' {CEditorForm},
+	uHSFParser in 'CodeCompletion\Editor\uHSFParser.pas',
+{$ENDIF}
+	LinkDLLUnit in 'LinkDLLUnit.pas',
+	FolderUnit in 'FolderUnit.pas',
+	LinkUnit in 'LinkUnit.pas',
+	CalcUnit in 'CalcUnit.pas';
+
+{$R *.RES}
+
+begin
+	Application.Initialize;
+	Application.Title := 'TIGCC IDE';
+	Screen.Cursor := crAppStart;
+	StartupScreenForm := TStartupScreenForm.Create (Application);
+	StartupScreenForm.Show;
+	StartupScreenForm.Update;
+	StartupScreenForm.DisplayText := 'Creating Main Window...';
+	Application.CreateForm(TMainForm, MainForm);
+{$IFDEF CODINGEXT}
+	Application.CreateForm(TCompForm, CompForm);
+	Application.CreateForm(TTemplateForm, TemplateForm);
+{$ENDIF}
+	StartupScreenForm.Free;
+	StartupScreenForm := nil;
+	Screen.Cursor := crDefault;
+	Application.Run;
+end.

File diff suppressed because it is too large
+ 127 - 0
IDE.dsk


BIN
IDE.res


+ 77 - 0
LinkDLLUnit.pas

@@ -0,0 +1,77 @@
+unit LinkDLLUnit;
+
+interface
+
+uses
+	Classes;
+
+const
+	LinkLibCurInterfaceVersion = 17;
+
+	llcdTI92         =  $01;
+	llcdTI89         =  $02;
+	llcdTI92Plus     =  $04;
+	llcdV200         =  $08;
+	llcdFlagTitanium = $100;
+
+	llffTIOS        = 0;
+	llffTIOSUpgrade = 1;
+
+	llfrMain = 0;
+	llfrData = 1;
+
+	llmtError   = 0;
+	llmtWarning = 1;
+
+type
+	TLinkLibDestFile = packed record
+		Data: Pointer;
+	end;
+
+	TLinkLibDataVarInfo = packed record
+		VarName: PChar;
+		CreateCopy,
+		CopyOnlyIfArchived: WordBool;
+	end;
+
+	TLinkLibOptimizeInfo = packed record
+		RemoveUnused,
+		OptimizeRelocs,
+		OptimizeNOPs,
+		OptimizeReturns,
+		OptimizeBranches,
+		OptimizeMoves,
+		OptimizeTests,
+		OptimizeCalcs,
+		UseFLineJumps,
+		Use4ByteFLineJumps,
+		CutRanges,
+		ReorderSections,
+		MergeConstants: WordBool;
+		ProgramSize,
+		DataSize,
+		BSSSize,
+		RelocCount,
+		NativeRelocCount,
+		OptimizeBranchesResult,
+		OptimizeMovesResult,
+		OptimizeTestsResult,
+		OptimizeCalcsResult,
+		UseFLineJumpsResult,
+		CutRangesResult,
+		NearAssemblyResult: LongInt;
+	end;
+
+	PCharArray = array [0..MaxListSize-1] of PChar;
+	PPChar = ^PCharArray;
+
+	TLinkLibGetInterfaceVersion = function: LongInt; cdecl;
+	TLinkLibGetOutputFile = function (var DestFile: TLinkLibDestFile; FileSize, DestCalc, FileRole, FileFormat, FileType: LongInt; Extension: PChar; Executable: WordBool; var EffectiveSize: LongInt): WordBool; cdecl;
+	TLinkLibFinalizeOutputFile = procedure (var DestFile: TLinkLibDestFile); cdecl;
+	TLinkLibError = procedure (FileName, Text: PChar; MessageType: LongInt); cdecl;
+	TLinkLibLinkFiles = function (ObjectFiles, ArchiveFiles: PPChar; ErrorMessage: TLinkLibError; GetOutputFile: TLinkLibGetOutputFile; FinalizeOutputFile: TLinkLibFinalizeOutputFile; NativeMode, FlashOS, Fargo: WordBool; var DataVarInfo: TLinkLibDataVarInfo; var OptimizeInfo: TLinkLibOptimizeInfo; OmitBSSInitialization: WordBool): ShortInt; cdecl;
+	TLinkLibCreateArchive = function (DestFile: PChar; ObjectFiles: PPChar; ErrorMessage: TLinkLibError; NoNames: WordBool): ShortInt; cdecl;
+
+implementation
+
+end.

+ 682 - 0
LinkUnit.pas

@@ -0,0 +1,682 @@
+unit LinkUnit;
+
+{	Uncomment to enable logging of all bytes sent and received to
+	C:\Linklog.txt. }
+(* {$DEFINE LOGLINK} *)
+
+interface
+
+uses
+	CalcUnit,
+	Windows, Classes;
+
+{ Calculator-specific Types }
+type
+	{ Enumeration Types }
+	TLinkPortType = (lpCOM);
+	TLinkCableType = (lcBlack, lcGray);
+	TCalcVarTypeID = Byte;
+
+	TLinkPort = record
+		PortType: TLinkPortType;
+		PortNumber: Cardinal;
+	end;
+
+	TLinkConnection = record
+		Port: TLinkPort;
+		CableType: TLinkCableType;
+		CalcType: TCalcDest;
+		Open: Boolean;
+		PortHandle: THandle;
+	end;
+
+	{	Variable or Folder Name }
+	TCalcVarName = array [0..9] of Char;
+
+	{	Variable Structure }
+	TCalcVar = record
+		CalcType: TCalcDest;
+		Folder,
+		Name: TCalcVarName;
+		TypeID: TCalcVarTypeID;
+		Size: LongWord;
+	end;
+
+	{	Progress callback function
+		Should return False if cancelled, True otherwise }
+	TProgressCallBack = function(ID: Pointer; Progress: PDWord): Boolean; 
+
+	{	Variable list callback function
+		This type is called by GetVarList on every item found }
+	TVarListCallBack = function(ID: Pointer; const NewVar: TCalcVar): Boolean; 
+
+{ Exported Functions }
+function CreateConnection(var Connection: TLinkConnection): Boolean;
+function OpenConnection(var Connection: TLinkConnection): Boolean;
+procedure CloseConnection(var Connection: TLinkConnection);
+
+function CalcReady(var Connection: TLinkConnection): Boolean; 
+
+function SendAck(var Connection: TLinkConnection): Boolean; 
+function SendWait(var Connection: TLinkConnection): Boolean; 
+function SendByte(var Connection: TLinkConnection; Value: Byte; CheckSum: PWord = nil): Boolean; 
+function SendWord(var Connection: TLinkConnection; Value: Word; CheckSum: PWord = nil): Boolean; 
+function SendLongWord(var Connection: TLinkConnection; Value: LongWord; CheckSum: PWord = nil): Boolean;
+function SendString(var Connection: TLinkConnection; Value: PChar; CheckSum: PWord = nil): Boolean;
+function SendKey(var Connection: TLinkConnection; Key: Char): Boolean;  overload;
+function SendKey(var Connection: TLinkConnection; Key: Word): Boolean;  overload;
+function SendKeys(var Connection: TLinkConnection; const Keys: string): Boolean;
+function SendVar(var Connection: TLinkConnection; Folder, Name: PChar; Buffer: Pointer; BufSize: Cardinal; Progress: PDWord = nil; ProgressCallBack: TProgressCallBack = nil; ID: Pointer = nil): Boolean;
+function SendFile(var Connection: TLinkConnection; Folder, Name: PChar; const FileName: string; Progress: PDWord = nil; ProgressCallBack: TProgressCallBack = nil; ID: Pointer = nil): Boolean;
+function ExecuteHomeLine(var Connection: TLinkConnection; const Line: string): Boolean;
+
+function CheckFileFormat(var Connection: TLinkConnection; const FileName: string; Folder: PChar = nil; Name: PChar = nil; Size: PWord = nil): Boolean;
+
+function WaitForAck(var Connection: TLinkConnection; LastResult: PByte = nil): Boolean;
+function CalcWaiting(var Connection: TLinkConnection; LastResult: PByte = nil): Boolean;
+function ReceiveByte(var Connection: TLinkConnection; out Value: Byte; CheckSum: PWord = nil): Boolean;
+function ReceiveWord(var Connection: TLinkConnection; out Value: Word; CheckSum: PWord = nil): Boolean;
+function ReceiveLongWord(var Connection: TLinkConnection; out Value: LongWord; CheckSum: PWord = nil): Boolean;
+
+function GetCalcType(var Connection: TLinkConnection): Boolean;
+
+implementation
+
+uses
+	SysUtils, Registry, ComServ;
+
+const
+	SendRetry = 1;
+	SendTimeout = 500;
+	ReceiveTimeout = 2000;
+	SleepBetweenReady = 500;
+	FirstReadyTimeout = 5000;
+	NormalReadyTimeout = 5000;
+	SendVarTimeout = 2000;
+	ProgressInterval = 100;
+	NonBlockingRead = False;
+	NonBlockingWrite = True;
+
+{$IFDEF LOGLINK}
+var
+	LogFile: Text;
+	LogSend: Boolean;
+{$ENDIF}
+
+var
+	OpenedOnce: Boolean = False;
+
+function GetPortState(Handle: THandle): Cardinal; forward;
+procedure SetPortState(Handle: THandle; State: Cardinal); forward;
+function GetPortName(const Port: TLinkPort): string; forward;
+function IsValidAck(Value: Byte): Boolean; forward;
+
+{	Creates a connection, opening the link port, but does not transfer any
+	data. }
+function CreateConnection(var Connection: TLinkConnection): Boolean; 
+var
+	NewHandle: THandle;
+	Settings: TDCB;
+	Timeouts: TCommTimeouts;
+begin
+	Result := False;
+	NewHandle := CreateFile (PChar (GetPortName (Connection.Port) + ':'), GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+	if NewHandle = INVALID_HANDLE_VALUE then
+		Exit;
+	if Connection.CableType = lcBlack then begin
+		if not SetCommBreak (NewHandle) then begin
+			CloseHandle (NewHandle);
+			Exit;
+		end;
+	end else begin
+		if not SetupComm (NewHandle, 1024, 1024) then begin
+			CloseHandle (NewHandle);
+			Exit;
+		end;
+		FillChar (Settings, SizeOf (Settings), 0);
+		with Settings do begin
+			DCBLength := SizeOf (Settings);
+			BaudRate := CBR_9600;
+			ByteSize := 8;
+			StopBits := ONESTOPBIT;
+			Flags := $00001001;
+		end;
+		if not SetCommState (NewHandle, Settings) then begin
+			CloseHandle (NewHandle);
+			Exit;
+		end;
+		FillChar (Timeouts, SizeOf (Timeouts), 0);
+		with Timeouts do begin
+			ReadIntervalTimeout := MaxDWord;
+			if not NonBlockingRead then
+				ReadTotalTimeoutConstant := ReceiveTimeout;
+			if not NonBlockingWrite then
+				WriteTotalTimeoutConstant := SendTimeOut;
+		end;
+		if not SetCommTimeouts (NewHandle, Timeouts) then begin
+			CloseHandle (NewHandle);
+			Exit;
+		end;
+	end;
+	Connection.PortHandle := NewHandle;
+	Result := True;
+end;
+
+{	Opens a connection if it is not already open. }
+function OpenConnection(var Connection: TLinkConnection): Boolean; 
+var
+	Timeout,
+	StartTime: Cardinal;
+begin
+	if Connection.Open then
+		Result := True
+	else begin
+		{$IFDEF LOGLINK}
+			AssignFile (LogFile, 'C:\Linklog.txt');
+			ReWrite (LogFile);
+			Write (LogFile, ' - Calculator Link Log - ');
+			LogSend := False;
+		{$ENDIF}
+		Connection.Open := True;
+		if OpenedOnce then
+			Timeout := NormalReadyTimeout
+		else
+			Timeout := FirstReadyTimeout;
+		StartTime := GetTickCount;
+		repeat
+			Result := CalcReady (Connection);
+			if not Result then
+				Sleep (SleepBetweenReady);
+		until Result or (GetTickCount - StartTime > Timeout);
+		OpenedOnce := True;
+		if not Result then
+			Connection.Open := False;
+	end;
+end;
+
+{	Closes a connection if it is open, and frees the handle. }
+procedure CloseConnection(var Connection: TLinkConnection);
+begin
+	if Connection.CableType = lcBlack then
+		SetPortState (Connection.PortHandle, 0);
+	CloseHandle (Connection.PortHandle);
+	{$IFDEF LOGLINK}
+		CloseFile (LogFile);
+	{$ENDIF}
+end;
+
+procedure ResetConnection(var Connection: TLinkConnection);
+begin
+	if Connection.CableType = lcBlack then
+		SetPortState (Connection.PortHandle, 0);
+end;
+
+function WaitForAck(var Connection: TLinkConnection; LastResult: PByte = nil): Boolean;
+var
+	TempResult: Byte;
+begin
+	Result :=
+		ReceiveByte (Connection, TempResult) and IsValidAck (TempResult) and
+		ReceiveByte (Connection, TempResult) and (TempResult = $56) and
+		ReceiveByte (Connection, TempResult) and
+		ReceiveByte (Connection, TempResult);
+	if Assigned (LastResult) then
+		LastResult^ := TempResult;
+end;
+
+function CalcReady(var Connection: TLinkConnection): Boolean;
+var
+	TempResult: Byte;
+begin
+	Result := False;
+	if not
+		(SendByte (Connection, $09) and
+		SendByte (Connection, $68) and
+		SendByte (Connection, $00) and
+		SendByte (Connection, $00) and
+		WaitForAck (Connection) and
+		SendByte (Connection, $08) and
+		SendByte (Connection, $68) and
+		SendByte (Connection, $00) and
+		SendByte (Connection, $00) and
+		ReceiveByte (Connection, TempResult) and IsValidAck (TempResult)) then
+		Exit;
+	case TempResult of
+		$98, $89: Connection.CalcType := cdTI89;
+		$88:      Connection.CalcType := cdTI92Plus;
+		else Exit;
+	end;
+	Result :=
+		ReceiveByte (Connection, TempResult) and (TempResult = $56) and
+		ReceiveByte (Connection, TempResult) and
+		ReceiveByte (Connection, TempResult);
+end;
+
+function CalcWaiting(var Connection: TLinkConnection; LastResult: PByte = nil): Boolean;
+var
+	TempResult: Byte;
+begin
+	Result :=
+		ReceiveByte (Connection, TempResult) and IsValidAck (TempResult) and
+		ReceiveByte (Connection, TempResult) and (TempResult = $09) and
+		ReceiveByte (Connection, TempResult) and
+		ReceiveByte (Connection, TempResult);
+	if Assigned (LastResult) then
+		LastResult^ := TempResult;
+end;
+
+function SendAck(var Connection: TLinkConnection): Boolean;
+begin
+	Result :=
+		SendByte (Connection, $08) and
+		SendByte (Connection, $56) and
+		SendByte (Connection, $00) and
+		SendByte (Connection, $00);
+end;
+
+function SendWait(var Connection: TLinkConnection): Boolean; 
+begin
+	Result :=
+		SendByte (Connection, $08) and
+		SendByte (Connection, $09) and
+		SendByte (Connection, $00) and
+		SendByte (Connection, $00);
+end;
+
+function SendByte(var Connection: TLinkConnection; Value: Byte; CheckSum: PWord = nil): Boolean;
+var
+	I: Cardinal;
+	StartTime: Cardinal;
+	RetryCount: Integer;
+	State: Cardinal;
+begin
+	Result := OpenConnection (Connection);
+	if Result then begin
+		{$IFDEF LOGLINK}
+			if not LogSend then begin
+				WriteLn (LogFile);
+				WriteLn (LogFile, 'Sending:');
+				LogSend := True;
+			end;
+			Write (LogFile, ' ' + IntToHex (Value, 2));
+		{$ENDIF}
+		if Connection.CableType = lcGray then
+			Result := WriteFile (Connection.PortHandle, Value, 1, I, nil)
+		else begin
+			StartTime := GetTickCount;
+			for I := 0 to 7 do begin
+				for RetryCount := 0 to SendRetry do begin
+					if ((Value and (1 shl I)) <> 0) then
+						SetPortState (Connection.PortHandle, 2)
+					else
+						SetPortState (Connection.PortHandle, 1);
+					repeat
+						State := GetPortState (Connection.PortHandle);
+						if GetTickCount - StartTime > SendTimeout then
+							Break;
+					until State = 0;
+					if State = 0 then
+						break;
+				end;
+				if State <> 0 then begin
+					Result := False;
+					Exit;
+				end;
+				for RetryCount := 0 to SendRetry do begin
+					SetPortState (Connection.PortHandle, 3);
+					repeat
+						State := GetPortState (Connection.PortHandle);
+						if GetTickCount - StartTime > SendTimeout then
+							Break;
+					until State = 3;
+					if State = 3 then
+						break;
+				end;
+				if State <> 3 then begin
+					Result := False;
+					Exit;
+				end;
+			end;
+		end;
+		if Assigned (CheckSum) then
+			Inc (CheckSum^, Value);
+	end;
+end;
+
+function SendWord(var Connection: TLinkConnection; Value: Word; CheckSum: PWord = nil): Boolean; 
+begin
+	Result :=
+		SendByte (Connection, Value, CheckSum) and
+		SendByte (Connection, (Value shr (SizeOf (Value) * 4)), CheckSum);
+end;
+
+function SendLongWord(var Connection: TLinkConnection; Value: LongWord; CheckSum: PWord = nil): Boolean; 
+begin
+	Result :=
+		SendWord (Connection, Value, CheckSum) and
+		SendWord (Connection, (Value shr (SizeOf (Value) * 4)), CheckSum);
+end;
+
+function SendString(var Connection: TLinkConnection; Value: PChar; CheckSum: PWord = nil): Boolean;
+begin
+	Result := True;
+	while Value [0] <> #0 do begin
+		Result := Result and SendByte (Connection, Byte (Value [0]), CheckSum);
+		Value := @(Value[1]);
+	end;
+end;
+
+function SendKey(var Connection: TLinkConnection; Key: Char): Boolean;  overload;
+begin
+	Result :=
+		SendByte (Connection, $09) and
+		SendByte (Connection, $87) and
+		SendWord (Connection, Byte (Key)) and
+		WaitForAck (Connection);
+end;
+
+function SendKey(var Connection: TLinkConnection; Key: Word): Boolean;  overload;
+begin
+	Result :=
+		SendByte (Connection, $09) and
+		SendByte (Connection, $87) and
+		SendWord (Connection, Key) and
+		WaitForAck (Connection);
+end;
+
+function SendKeys(var Connection: TLinkConnection; const Keys: string): Boolean;
+var
+	I: Integer;
+begin
+	Result := OpenConnection (Connection);
+	for I := 1 to Length (Keys) do begin
+		Result := SendKey (Connection, Keys [I]);
+		if not Result then
+			Break;
+	end;
+end;
+
+function SendVar(var Connection: TLinkConnection; Folder, Name: PChar; Buffer: Pointer; BufSize: Cardinal; Progress: PDWord = nil; ProgressCallBack: TProgressCallBack = nil; ID: Pointer = nil): Boolean;
+var
+	I: Cardinal;
+	Buf: PByteArray;
+	FileType: Byte;
+	FileSize,
+	BlockSize: Word;
+	Sum: Word;
+	TempProgress: DWord;
+	StartTime: Cardinal;
+begin
+	Result := BufSize >= 88;
+	if not Result then
+		Exit;
+	if not Assigned (Progress) then
+		Progress := @TempProgress;
+	Buf := Buffer;
+	FileType := Buf [72];
+	Buf [72] := 0;
+	FileSize := Buf [86] shl 8 + Buf [87] + 2;
+	if not Assigned (Folder) then
+		Folder := @(Buf[10]);
+	Folder [8] := #0;
+	if not Assigned (Name) then
+		Name := @(Buf[64]);
+	Name [8] := #0;
+	{$IFDEF LOGLINK}
+		WriteLn (LogFile);
+		WriteLn (LogFile);
+		WriteLn (LogFile, AnsiString (Folder), '\', AnsiString (Name), ': ', FileSize, ' (', IntToHex (FileSize, 4), ') Bytes');
+	{$ENDIF}
+	Sum := 0;
+	StartTime := GetTickCount;
+	repeat until CalcReady (Connection) or (GetTickCount - StartTime > SendVarTimeout);
+	Result :=
+		SendKey (Connection, 264) and
+		SendKey (Connection, 264) and
+		SendKey (Connection, 277) and
+		SendByte (Connection, $08) and
+		SendByte (Connection, $06) and
+		SendWord (Connection, StrLen (Folder) + StrLen (Name) + 8) and
+		SendLongWord (Connection, FileSize, @Sum) and
+		SendByte (Connection, FileType, @Sum) and
+		SendByte (Connection, StrLen (Folder) + StrLen (Name) + 1, @Sum) and
+		SendString (Connection, Folder, @Sum) and
+		SendString (Connection, '\', @Sum) and
+		SendString (Connection, Name, @Sum) and
+		SendByte (Connection, $00) and
+		SendWord (Connection, Sum) and
+		WaitForAck (Connection) and
+		CalcWaiting (Connection) and
+		SendAck (Connection) and
+		SendByte (Connection, $08) and
+		SendByte (Connection, $15) and
+		SendWord (Connection, FileSize + 4) and
+		SendLongWord (Connection, 0);
+	if not Result then
+		Exit;
+	BlockSize := FileSize - 2;
+	Sum := 0;
+	Result :=
+		SendByte (Connection, BlockSize and $FF00 shr 8, @Sum) and
+		SendByte (Connection, BlockSize and $00FF, @Sum);
+	Inc (Progress^, 2);
+	if not Result then
+		Exit;
+	for I := 0 to BlockSize - 1 do begin
+		if (I < BufSize) and SendByte (Connection, Buf [I + 88], @Sum) then
+			Inc (Progress^)
+		else begin
+			Result := False;
+			Break;
+		end;
+		if ((I + 2) mod ProgressInterval = 0) and Assigned (ProgressCallBack) and (not ProgressCallBack (ID, Progress)) then begin
+			Result := False;
+			Break;
+		end;
+	end;
+	if not Result then
+		Exit;
+	Result :=
+		SendWord (Connection, Sum) and
+		WaitForAck (Connection) and
+		SendByte (Connection, $08) and
+		SendByte (Connection, $92) and
+		SendByte (Connection, $00) and
+		SendByte (Connection, $00) and
+		WaitForAck (Connection);
+end;
+
+function SendFile(var Connection: TLinkConnection; Folder, Name: PChar; const FileName: string; Progress: PDWord = nil; ProgressCallBack: TProgressCallBack = nil; ID: Pointer = nil): Boolean;
+var
+	FHandle: HFile;
+	Buffer: Pointer;
+	Size,
+	Read: Cardinal;
+begin
+	FHandle := CreateFile (PChar (FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0);
+	Result := FHandle <> 0;
+	if not Result then
+		Exit;
+	Size := GetFileSize (FHandle, nil);
+	Buffer := AllocMem (Size);
+	Result := Assigned (Buffer);
+	if not Result then begin
+		CloseHandle (FHandle);
+		Exit;
+	end;
+	Result := ReadFile (FHandle, Buffer^, Size, Read, nil);
+	CloseHandle (FHandle);
+	if Result then
+		Result := SendVar (Connection, Folder, Name, Buffer, Size, Progress, ProgressCallBack, ID);
+	FreeMem (Buffer);
+end;
+
+function CheckFileFormat(var Connection: TLinkConnection; const FileName: string; Folder: PChar = nil; Name: PChar = nil; Size: PWord = nil): Boolean;
+var
+	FHandle: HFile;
+	Buffer: array [0..4] of Char;
+	Read: Cardinal;
+begin
+	FHandle := CreateFile (PChar (FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
+	Result :=
+		(FHandle <> 0) and
+		ReadFile (FHandle, Buffer, 4, Read, nil);
+	if not Result then
+		Exit;
+	Buffer [4] := #0;
+	Result := Buffer = '**TI';
+	if not Result then
+		Exit;
+	if Assigned (Folder) then begin
+		SetFilePointer (FHandle, 10, nil, FILE_BEGIN);
+		Result := ReadFile (FHandle, Folder^, 8, Read, nil) and Result;
+		Folder [8] := #0;
+	end;
+	if Assigned (Name) then begin
+		SetFilePointer (FHandle, 64, nil, FILE_BEGIN);
+		Result := ReadFile (FHandle, Name^, 8, Read, nil) and Result;
+		Name [8] := #0;
+	end;
+	if Assigned (Size) then begin
+		SetFilePointer (FHandle, 86, nil, FILE_BEGIN);
+		Result := ReadFile (FHandle, Buffer, 2, Read, nil) and Result;
+		Size^ := Byte (Buffer [0]) shl 8 + Byte (Buffer [1]) + 2;
+	end;
+	if FHandle <> 0 then
+		CloseHandle (FHandle);
+end;
+
+function ExecuteHomeLine(var Connection: TLinkConnection; const Line: string): Boolean;
+begin
+	Result :=
+		SendKey (Connection, 264) and
+		SendKey (Connection, 264) and
+		SendKey (Connection, 277) and
+		SendKey (Connection, 263) and
+		SendKey (Connection, 263) and
+		SendKeys (Connection, Line) and
+		SendKey (Connection, 13);
+end;
+
+function ReceiveByte(var Connection: TLinkConnection; out Value: Byte; CheckSum: PWord = nil): Boolean;
+var
+	I,
+	State: Cardinal;
+	StartTime: Cardinal;
+begin
+	Value := 0;
+	Result := OpenConnection (Connection);
+	if Result then begin
+		if Connection.CableType = lcGray then begin
+			StartTime := GetTickCount;
+			repeat
+				Result := ReadFile (Connection.PortHandle, Value, 1, I, nil);
+			until Result or (GetTickCount - StartTime > ReceiveTimeout);
+		end else begin
+			StartTime := GetTickCount;
+			for I := 0 to 7 do begin
+				repeat
+					State := GetPortState (Connection.PortHandle);
+					if (State = 3) and (GetTickCount - StartTime > ReceiveTimeout) then begin
+						Result := False;
+						Exit;
+					end;
+				until State <> 3;
+				if State = 1 then begin
+					Value := Value or (1 shl I);
+					SetPortState (Connection.PortHandle, 1);
+					State := 2;
+				end else begin
+					SetPortState (Connection.PortHandle, 2);
+					State := 1;
+				end;
+				while (GetPortState (Connection.PortHandle) and State) = 0 do
+					if GetTickCount - StartTime > ReceiveTimeout then begin
+						Result := False;
+						Exit;
+					end;
+				SetPortState (Connection.PortHandle, 3);
+			end;
+		end;
+		if Assigned (CheckSum) then
+			Inc (CheckSum^, Value);
+		{$IFDEF LOGLINK}
+			if LogSend then begin
+				WriteLn (LogFile);
+				WriteLn (LogFile, 'Receiving:');
+				LogSend := False;
+			end;
+			Write (LogFile, ' ' + IntToHex (Value, 2));
+		{$ENDIF}
+	end;
+end;
+
+function ReceiveWord(var Connection: TLinkConnection; out Value: Word; CheckSum: PWord = nil): Boolean;
+var
+	Temp1,
+	Temp2: Byte;
+begin
+	Result :=
+		ReceiveByte (Connection, Temp1, CheckSum) and
+		ReceiveByte (Connection, Temp2, CheckSum);
+	Value := Temp1 or (Temp2 shl (SizeOf (Temp1) * 8));
+end;
+
+function ReceiveLongWord(var Connection: TLinkConnection; out Value: LongWord; CheckSum: PWord = nil): Boolean;
+var
+	Temp1,
+	Temp2: Word;
+begin
+	Result :=
+		ReceiveWord (Connection, Temp1, CheckSum) and
+		ReceiveWord (Connection, Temp2, CheckSum);
+	Value := Temp1 or (Temp2 shl (SizeOf (Temp1) * 8));
+end;
+
+function GetCalcType(var Connection: TLinkConnection): Boolean;
+begin
+	Result := OpenConnection (Connection);
+end;
+
+function GetPortState(Handle: THandle): Cardinal;
+var
+	InternalState: Cardinal;
+begin
+	GetCommModemStatus (Handle, InternalState);
+	Result := 0;
+	if (InternalState and MS_CTS_ON) <> 0 then
+		Inc (Result, 1);
+	if (InternalState and MS_DSR_ON) <> 0 then
+		Inc (Result, 2);
+end;
+
+procedure SetPortState(Handle: THandle; State: Cardinal);
+procedure Send(Func: Cardinal);
+begin
+	EscapeCommFunction (Handle, Func);
+end;
+begin
+	if (State and 2) <> 0 then
+		Send (SETRTS)
+	else
+		Send (CLRRTS);
+	if (State and 1) <> 0 then
+		Send (SETDTR)
+	else
+		Send (CLRDTR);
+end;
+
+function GetPortName(const Port: TLinkPort): string;
+begin
+	case Port.PortType of
+		lpCOM: Result := 'COM' + IntToStr (Port.PortNumber);
+		else   Result := '';
+	end;
+end;
+
+function IsValidAck(Value: Byte): Boolean;
+begin
+	Result := Value in [$88, $89, $98];
+end;
+
+end.

BIN
MainUnit.dfm


+ 5363 - 0
MainUnit.pas

@@ -0,0 +1,5363 @@
+unit MainUnit;
+
+interface
+
+uses
+	MasterUnit, SourceFileUnit, FolderUnit, ToolsListUnit, LinkDLLUnit,
+	Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+	Menus, StdCtrls, ExtCtrls, ImgList, ComCtrls, Buttons, ActnList, ToolWin,
+	Printers, SourceEditUnit, HTMLHelpUnit, MemoComponentUnit, ScktComp;
+
+type
+	TMainForm = class(TForm)
+		ProjectTree: TTreeView;
+		LittleIcons: TImageList;
+		TreeEditorSplitter: TSplitter;
+		MainMenu: TMainMenu;
+		MainMenuFile: TMenuItem;
+		MenuFileNew: TMenuItem;
+		Project1: TMenuItem;
+		AssemblerSource1: TMenuItem;
+		Open1: TMenuItem;
+		Save1: TMenuItem;
+		SaveAs1: TMenuItem;
+		N1: TMenuItem;
+		Exit1: TMenuItem;
+		CSourceFile1: TMenuItem;
+		MainMenuEdit: TMenuItem;
+		Undo1: TMenuItem;
+		N2: TMenuItem;
+		Delete1: TMenuItem;
+		Cut1: TMenuItem;
+		Copy1: TMenuItem;
+		Paste1: TMenuItem;
+		AddFiles1: TMenuItem;
+		MenuCompileLine: TMenuItem;
+		MainMenuProject: TMenuItem;
+		Compile1: TMenuItem;
+		Link1: TMenuItem;
+		N4: TMenuItem;
+		Options1: TMenuItem;
+		AddFileDlg: TOpenDialog;
+		N5: TMenuItem;
+		Preferences1: TMenuItem;
+		N6: TMenuItem;
+		HeaderFile1: TMenuItem;
+		SourceFilePopup: TPopupMenu;
+		Compile2: TMenuItem;
+		N7: TMenuItem;
+		Remove1: TMenuItem;
+		Delete2: TMenuItem;
+		Splitter2: TSplitter;
+		ErrWinPanel: TPanel;
+		ErrorPanel: TPanel;
+		CloseErrorsButton: TSpeedButton;
+		ErrorList: TListView;
+		Label1: TLabel;
+		Label2: TLabel;
+		ErrorsLabel: TLabel;
+		WarningsLabel: TLabel;
+		Save2: TMenuItem;
+		SaveAs2: TMenuItem;
+		N8: TMenuItem;
+		MainMenuHelp: TMenuItem;
+		Build1: TMenuItem;
+		N9: TMenuItem;
+		SelectAll1: TMenuItem;
+		OpenProjectDlg: TOpenDialog;
+		SaveProjectDlg: TSaveDialog;
+		N10: TMenuItem;
+		About1: TMenuItem;
+		StatusBar: TStatusBar;
+		ToolBarImages: TImageList;
+		FileNewPopup: TPopupMenu;
+		HeaderFile2: TMenuItem;
+		Actions: TActionList;
+		ActionFileNewProject: TAction;
+		ActionFileNewCHeaderFile: TAction;
+		ActionFileNewGNUAsmHeaderFile: TAction;
+		ActionFileNewA68kAsmHeaderFile: TAction;
+		ActionFileNewCFile: TAction;
+		ActionFileNewGNUAsmFile: TAction;
+		ActionFileNewA68kAsmFile: TAction;
+		ActionFileOpen: TAction;
+		ActionFileSave: TAction;
+		ActionFileSaveAs: TAction;
+		ActionFilePreferences: TAction;
+		ActionFileExit: TAction;
+		ActionEditUndo: TAction;
+		ActionEditDelete: TAction;
+		ActionEditCut: TAction;
+		ActionEditCopy: TAction;
+		ActionEditPaste: TAction;
+		ActionEditSelectAll: TAction;
+		ActionProjectAddFiles: TAction;
+		ActionProjectCompile: TAction;
+		ActionProjectMake: TAction;
+		ActionProjectBuild: TAction;
+		ActionProjectOptions: TAction;
+		ActionHelpDocumentation: TAction;
+		ActionHelpAbout: TAction;
+		ActionTreeItemSave: TAction;
+		ActionTreeItemSaveAs: TAction;
+		ActionTreeItemCompile: TAction;
+		ActionTreeItemRemove: TAction;
+		ActionTreeItemDelete: TAction;
+		CSourceFile2: TMenuItem;
+		AssemblerSourceFile1: TMenuItem;
+		Project3: TMenuItem;
+		N11: TMenuItem;
+		ActionProjectShowErrors: TAction;
+		ErrorsandWarnings1: TMenuItem;
+		N12: TMenuItem;
+		MainMenuFind: TMenuItem;
+		ActionFindFind: TAction;
+		ActionFindReplace: TAction;
+		ActionFindOpenFile: TAction;
+		Find2: TMenuItem;
+		Replace1: TMenuItem;
+		OpenFileAtCursor1: TMenuItem;
+		N13: TMenuItem;
+		FindDlg: TFindDialog;
+		ReplaceDlg: TReplaceDialog;
+		ToolBarImagesDisabled: TImageList;
+		PrintDlg: TPrintDialog;
+		ActionFilePrint: TAction;
+		Print1: TMenuItem;
+		N14: TMenuItem;
+		ActionFilePrintQuickly: TAction;
+		ErrorListIcons: TImageList;
+		DocFile: THTMLHelp;
+		ActionHelpContents: TAction;
+		ActionHelpIndex: TAction;
+		ActionHelpSearch: TAction;
+		ActionTreeItemRename: TAction;
+		N19: TMenuItem;
+		Rename1: TMenuItem;
+		Contents1: TMenuItem;
+		Index1: TMenuItem;
+		Search1: TMenuItem;
+		EditorPopup: TPopupMenu;
+		Undo2: TMenuItem;
+		N16: TMenuItem;
+		Clear1: TMenuItem;
+		Cut2: TMenuItem;
+		Copy2: TMenuItem;
+		Paste2: TMenuItem;
+		N17: TMenuItem;
+		SelectAll2: TMenuItem;
+		MainToolBar: TToolBar;
+		ToolBarNewButton: TToolButton;
+		ToolButton2: TToolButton;
+		ToolButton3: TToolButton;
+		ToolButton4: TToolButton;
+		ToolButton23: TToolButton;
+		ToolButton24: TToolButton;
+		ToolButton6: TToolButton;
+		ToolButton7: TToolButton;
+		ToolButton8: TToolButton;
+		ToolButton9: TToolButton;
+		ToolButton10: TToolButton;
+		ToolButton5: TToolButton;
+		ToolButton11: TToolButton;
+		ToolButton20: TToolButton;
+		ToolButton21: TToolButton;
+		ToolBarCompileLine1: TToolButton;
+		ToolBarCompileButton: TToolButton;
+		ToolButton15: TToolButton;
+		ToolBarCompileLine2: TToolButton;
+		ToolButton18: TToolButton;
+		ToolButton19: TToolButton;
+		ActionEditRedo: TAction;
+		Redo1: TMenuItem;
+		Redo2: TMenuItem;
+		EditorPanel: TPanel;
+		NoEditor: TPanel;
+		FunctionPopup: TPopupMenu;
+		ActionFindFunctions: TAction;
+		N15: TMenuItem;
+		Functions1: TMenuItem;
+		ToolButton25: TToolButton;
+		NoFunctionsItem: TMenuItem;
+		ActionFileNewTextFile: TAction;
+		TextFile1: TMenuItem;
+		TextFile2: TMenuItem;
+		ActionEditIncreaseIndent: TAction;
+		ActionEditDecreaseIndent: TAction;
+		N18: TMenuItem;
+		IncreaseIndent1: TMenuItem;
+		DecreaseIndent1: TMenuItem;
+		N20: TMenuItem;
+		IncreaseIndent2: TMenuItem;
+		DecreaseIndent2: TMenuItem;
+		N21: TMenuItem;
+		OpenFileatCursor2: TMenuItem;
+		GNUAssemblySourceFile1: TMenuItem;
+		GNUAssemblySourceFile2: TMenuItem;
+		ActionFileNewQuillFile: TAction;
+		QuillSourceFile1: TMenuItem;
+		QuillSourceFile2: TMenuItem;
+		ActionProjectStopCompilation: TAction;
+		ActionProjectForceQuitCompiler: TAction;
+		ToolButton16: TToolButton;
+		ToolButton17: TToolButton;
+		StopCompilation1: TMenuItem;
+		ForceQuitCompiler1: TMenuItem;
+		ActionHelpNews: TAction;
+		N3: TMenuItem;
+		News1: TMenuItem;
+		ActionDebugRun: TAction;
+		ActionDebugPause: TAction;
+		ActionDebugReset: TAction;
+		MainMenuDebug: TMenuItem;
+		Run1: TMenuItem;
+		N22: TMenuItem;
+		Pause1: TMenuItem;
+		Reset1: TMenuItem;
+		ToolBarRunButton: TToolButton;
+		ToolBarDebugLine: TToolButton;
+		ToolBarPauseButton: TToolButton;
+		ToolButton12: TToolButton;
+		ToolButton13: TToolButton;
+		ChangeNotificationTimer: TTimer;
+		ToolBarBevel: TBevel;
+		ToolBarEndLine: TToolButton;
+		RecentFilesLine: TMenuItem;
+		RecentFilesPopup: TPopupMenu;
+		NoFilesItem: TMenuItem;
+		ActionToolsConfigure: TAction;
+		MainMenuTools: TMenuItem;
+		Configure1: TMenuItem;
+		ToolsLine: TMenuItem;
+		ActionProjectShowProgramOutput: TAction;
+		ProgramOutput1: TMenuItem;
+		ActionFileNewFolder: TAction;
+		N23: TMenuItem;
+		Folder1: TMenuItem;
+		N24: TMenuItem;
+		Folder2: TMenuItem;
+		FolderPopup: TPopupMenu;
+    MenuItem6: TMenuItem;
+    MenuItem9: TMenuItem;
+    CategoryPopup: TPopupMenu;
+		ActionFileNewFile: TAction;
+    File1: TMenuItem;
+    Folder3: TMenuItem;
+    N25: TMenuItem;
+    Folder4: TMenuItem;
+    File2: TMenuItem;
+    ActionTreeItemNewFolder: TAction;
+    ActionTreeItemNewFile: TAction;
+		GNUAssemblyHeaderFile1: TMenuItem;
+		GNUAssemblyHeaderFile2: TMenuItem;
+		A68kAssemblyHeaderFile1: TMenuItem;
+    A68kAssemblyHeaderFile2: TMenuItem;
+		procedure FormCreate(Sender: TObject);
+		procedure FormDestroy(Sender: TObject);
+		procedure AppException(Sender: TObject; E: Exception);
+		procedure ProjectTreeEditing(Sender: TObject; Node: TTreeNode;
+			var AllowEdit: Boolean);
+		procedure ProjectAddFiles(Sender: TObject);
+		procedure ProjectTreeChange(Sender: TObject; Node: TTreeNode);
+		procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+		procedure ProjectTreeDeletion(Sender: TObject; Node: TTreeNode);
+		procedure FileExit(Sender: TObject);
+		procedure FileNewProject(Sender: TObject);
+		procedure TreeItemRemove(Sender: TObject);
+		procedure TreeItemDelete(Sender: TObject);
+		procedure TreeItemCompile(Sender: TObject);
+		procedure CloseErrorsButtonClick(Sender: TObject);
+		procedure ErrorListDeletion(Sender: TObject; Item: TListItem);
+		procedure TreeItemSave(Sender: TObject);
+		procedure HelpDocumentation(Sender: TObject);
+		procedure EditorEnter(Sender: TObject);
+		procedure EditorExit(Sender: TObject);
+		procedure EditUndo(Sender: TObject);
+		procedure EditRedo(Sender: TObject);
+		procedure EditClear(Sender: TObject);
+		procedure EditCut(Sender: TObject);
+		procedure EditCopy(Sender: TObject);
+		procedure EditPaste(Sender: TObject);
+		procedure EditSelectAll(Sender: TObject);
+		procedure ProjectCompile(Sender: TObject);
+		procedure ProjectMake(Sender: TObject);
+		procedure FileOpenProject(Sender: TObject);
+		procedure FileSaveAll(Sender: TObject);
+		procedure FileSaveProjectAs(Sender: TObject);
+		procedure EditorKeyDown(Sender: TObject; var Key: Word;
+			Shift: TShiftState);
+		procedure ProjectBuild(Sender: TObject);
+		procedure ProjectTreeKeyDown(Sender: TObject; var Key: Word;
+			Shift: TShiftState);
+		procedure ProjectTreeMouseUp(Sender: TObject; Button: TMouseButton;
+			Shift: TShiftState; X, Y: Integer);
+		procedure ProjectTreeEdited(Sender: TObject; Node: TTreeNode;
+			var S: String);
+		procedure ProjectOptions(Sender: TObject);
+		procedure FilePreferences(Sender: TObject);
+		procedure FileNewHeaderFile(Sender: TObject);
+		procedure FileNewCSourceFile(Sender: TObject);
+		procedure FileNewGNUAssemblerSourceFile(Sender: TObject);
+		procedure FileNewAssemblerSourceFile(Sender: TObject);
+		procedure FileNewQuillSourceFile(Sender: TObject);
+		procedure FileNewTextFile(Sender: TObject);
+		procedure TreeItemSaveAs(Sender: TObject);
+		procedure HelpAbout(Sender: TObject);
+		procedure DisplayHint(Sender: TObject);
+		procedure ShowHideErrors(Sender: TObject);
+		procedure FindString(Sender: TObject; AllFiles: Boolean);
+		procedure ReplaceDlgReplace(Sender: TObject);
+		procedure FindText(Sender: TObject);
+		procedure ReplaceText(Sender: TObject);
+		procedure FindOpenFile(Sender: TObject);
+		procedure FindDlgFind(Sender: TObject);
+		procedure ActionsExecute(Action: TBasicAction; var Handled: Boolean);
+		procedure ProjectTreeEnter(Sender: TObject);
+		procedure ProjectTreeExit(Sender: TObject);
+		procedure ProjectTreeChanging(Sender: TObject; Node: TTreeNode;
+			var AllowChange: Boolean);
+		procedure EditorChange(Sender: TObject);
+		procedure FilePrint(Sender: TObject);
+		procedure FilePrintQuickly(Sender: TObject);
+		procedure TreeItemRename(Sender: TObject);
+		procedure HelpContents(Sender: TObject);
+		procedure HelpIndex(Sender: TObject);
+		procedure HelpSearch(Sender: TObject);
+		procedure SplitterMoved(Sender: TObject);
+		procedure ProjectTreeMouseDown(Sender: TObject; Button: TMouseButton;
+			Shift: TShiftState; X, Y: Integer);
+		procedure ToolBarManagerBandMove(Sender: TObject; Control: TControl;
+			var ARect: TRect);
+		procedure ProjectTreeDragOver(Sender, Source: TObject; X, Y: Integer;
+			State: TDragState; var Accept: Boolean);
+		procedure ProjectTreeDragDrop(Sender, Source: TObject; X, Y: Integer);
+		procedure ErrorListClick(Sender: TObject);
+		procedure DeleteError(Sender: TObject);
+		procedure FunctionPopupPopup(Sender: TObject);
+		procedure FindFunctions(Sender: TObject);
+		procedure FindFunctionFromPopup(Sender: TObject);
+		procedure IncreaseIndent(Sender: TObject);
+		procedure DecreaseIndent(Sender: TObject);
+		procedure ProjectStopCompilation(Sender: TObject);
+		procedure ProjectForceQuitCompiler(Sender: TObject);
+		procedure HelpNews(Sender: TObject);
+		procedure DebugRun(Sender: TObject);
+		procedure DebugPause(Sender: TObject);
+		procedure DebugReset(Sender: TObject);
+		procedure FormKeyDown(Sender: TObject; var Key: Word;
+			Shift: TShiftState);
+		procedure ChangeNotificationTick(Sender: TObject);
+		procedure RecentFileClick(Sender: TObject);
+		procedure ToolsConfigure(Sender: TObject);
+		procedure ToolClick(Sender: TObject);
+		procedure ProjectTreeStartDrag(Sender: TObject;
+			var DragObject: TDragObject);
+		procedure ShowProgramOutput(Sender: TObject);
+		procedure FileNewFolder(Sender: TObject);
+    procedure FileNewFile(Sender: TObject);
+    procedure ErrorListKeyDown(Sender: TObject; var Key: Word;
+      Shift: TShiftState);
+	private
+		EditorToHide: TWinControl;
+		TempLockHandle: THandle;
+		FModified: Boolean;
+		FInvalidated: Boolean;
+		FProjectFile: string;
+		InChangeNotification: Boolean;
+		procedure WMDropFiles(var Msg: TMessage); message WM_DROPFILES;
+		procedure SetProjectFile(const Value: string);
+		procedure SetModified(const Value: Boolean);
+		function GetCurrentEditor: TMemoComponent;
+		function GetInvalidated: Boolean;
+	public
+		TopNode: TTreeNode;
+		OriginalCaption: string;
+		LinkLibHandle: HModule;
+		LinkLibGetInterfaceVersion: TLinkLibGetInterfaceVersion;
+		LinkLibLinkFiles: TLinkLibLinkFiles;
+		LinkLibCreateArchive: TLinkLibCreateArchive;
+		SourceFiles: TSourceFiles;
+		JumpToError,
+		OpenFolderMessage,
+		AutoSave,
+		DeleteErrors,
+		StartingAppNow,
+		OpeningProjectNow,
+		NoHideEditor: Boolean;
+		PreviousNode: TTreeNode;
+		SyntaxCBackup: TSyntaxColoring;
+		SyntaxAsmGNUBackup: TSyntaxColoring;
+		SyntaxAsmBackup: TSyntaxColoring;
+		SyntaxQuillBackup: TSyntaxColoring;
+		Closing: Boolean;
+		ProgSize: Integer;
+		OptimizeInfo: TLinkLibOptimizeInfo;
+		Funcs: TSourceFileFunctions;
+		CurrentStrings: TMemoryStream;
+		CurVTIType: TCurVTIType;
+		RecentFiles: TStringList;
+		ToolsList: TToolsList;
+		property ProjectFile: string read FProjectFile write SetProjectFile;
+		property Modified: Boolean read FModified write SetModified;
+		property Invalidated: Boolean read GetInvalidated write FInvalidated;
+		property CurrentEditor: TMemoComponent read GetCurrentEditor;
+		procedure Modify;
+		procedure WarnIfModified;
+		procedure FileNew;
+		procedure FileClear;
+		procedure FileLoad;
+		procedure FileOpen(const FN: string);
+		procedure FileSave;
+		procedure FileSaveAs(const FN: string);
+		procedure ResetProjectSettings;
+		procedure AppCompStartFile;
+		procedure AppCompStop;
+		procedure AppCompSetMessage(const Msg: string);
+		procedure AppCompUpdate;
+		procedure UpdateProgramOutput;
+		procedure CopyHeaders;
+		procedure DeleteHeaders;
+		procedure ClearErrors;
+		procedure HideErrors;
+		procedure ShowErrors;
+		procedure UpdateErrorWindow;
+		procedure AddError(const Line: string; BugTp: TBugType; SourceF: string; ErrFunc: string; ErrMessage: string; SourceLn: Integer; Offset: Integer);
+		procedure CompileProject;
+		procedure MakeFileWrapped;
+		procedure MakeFile;
+		function AddSourceFile(const FN: string; OpenOnly: Boolean = False; SourceFileClass: TSourceFileClass = nil; Folder: TFolder = nil): TSourceFile;
+		function GetNewFileName(const FolderPath, Ext: string): string;
+		procedure LoadPreferences;
+		procedure SavePreferences;
+		procedure BeginCompilation;
+		procedure EndCompilation;
+		procedure RecompileFiles;
+		procedure UpdateEditButtons;
+		procedure UpdateStatusBar;
+		procedure UpdateFuncs;
+		procedure UpdateDebugSettings;
+		procedure SortFiles;
+		procedure DisplayFolderMessage;
+		procedure ClearDebugInfo;
+		function GetVTIWindow: HWnd;
+		procedure SendFiles(FNList: array of string);
+		procedure ExecuteCommandLine(const Line: string);
+		procedure SelectNode(Node: TTreeNode);
+		procedure AddToRecent(const FileName: string);
+		procedure UpdateRecent;
+		procedure AddTool(const Title, CommandLine, WorkingDir: string; WindowState: TWindowState);
+		function GetSourceTypeFolder(Node: TTreeNode): TTreeNode;
+		function FindFileInsertionPoint(ParentNode: TTreeNode): TTreeNode;
+		function CreateFileNode(ParentNode: TTreeNode; SourceFile: TSourceFile): TTreeNode;
+		function GetSelectedFolder(SourceClass: TSourceFileClass): TFolder;
+{$IFDEF CODINGEXT}
+		procedure InitCodingExt;
+		procedure ActionFindSymbolExecute(Sender: TObject);
+{$ENDIF}
+	end;
+
+var
+	MainForm: TMainForm;
+
+type
+	TRecentFileMenuItem = class(TObject)
+		FileMenuItem: TMenuItem;
+		PopupMenuItem: TMenuItem;
+	public
+		destructor Destroy; override;
+	end;
+
+const
+	MaxRecentFiles = 4;
+
+type
+	TNoImageDragObject = class(TDragControlObject)
+	public
+		function GetDragImages: TDragImageList; override;
+		procedure HideDragImage; override;
+		procedure ShowDragImage; override;
+	end;
+
+procedure LinkLibError(FileName, Text: PChar; MessageType: LongInt); cdecl;
+function LinkLibGetOutputFile(var DestFile: TLinkLibDestFile; FileSize, DestCalc, FileRole, FileFormat, FileType: LongInt; Extension: PChar; Executable: WordBool; var EffectiveSize: LongInt): WordBool; cdecl;
+
+implementation
+
+{$R *.DFM}
+
+uses
+	CalcUnit, ParsingUnit, ProcessUnit,
+	StartupScreenUnit, PreferencesUnit, ProjectOptionsUnit,
+	AboutUnit, SourceFileWinUnit, FunctionsWinUnit,
+	OpenFileStatusUnit, NewsUnit, SendProgressUnit, ToolsUnit,
+	ProgramOutputUnit, VTIStartUnit,
+	LinkUnit,
+	UtilsDos, UtilsWin, HandleWaitThreadUnit, FileReadToBufferThreadUnit,
+	ShellAPI, ShlObj, IniFiles, Registry, WinSpool, ClipBrd{$IFDEF CODINGEXT}, CompletionForm{$ENDIF};
+
+const
+	RegKey = '\Software\SeReSoft\TI-GCC IDE';
+
+type
+	TFileRole = (frMain, frData);
+	TLinkOutputFile = record
+		Data: TMemoryStream;
+		Tag: Byte;
+		VarExt: string;
+		ExeFile,
+		OSUpgrade: Boolean;
+	end;
+
+var
+	ProcID: Cardinal;
+	SendWin: HWnd;
+	LinkOutputFiles: array [TCalcDest, TFileRole] of TLinkOutputFile;
+
+function EnumWindowsFunc(Win: HWnd; Param: Integer): Bool; stdcall;
+var
+	Name: array [0..32] of Char;
+	NewProcID: DWord;
+begin
+	Result := True;
+	GetWindowThreadProcessID (Win, @NewProcID);
+	if NewProcID = ProcID then begin
+		GetClassName (Win, Name, 32);
+		if Name = '#32770' then begin
+			Result := False;
+			SendWin := Win;
+		end;
+	end;
+end;
+
+procedure ErrorMessage(const Msg: string);
+begin
+	if UpperCase (Copy (Msg, 1, Length ('ERROR:'))) = 'ERROR:' then
+		MainForm.AddError (Msg, btError, '', '', Trim (Copy (Msg, Length ('ERROR:') + 1, Length (Msg))), 0, 0)
+	else if UpperCase (Copy (Msg, 1, Length ('WARNING:'))) = 'WARNING:' then
+		MainForm.AddError (Msg, btWarning, '', '', Trim (Copy (Msg, Length ('WARNING:') + 1, Length (Msg))), 0, 0);
+end;
+
+procedure LinkLibError(FileName, Text: PChar; MessageType: LongInt); cdecl;
+var
+	BugTp: TBugType;
+	ErrorLine: string;
+begin
+	if MessageType = llmtError then
+		BugTp := btError
+	else
+		BugTp := btWarning;
+	ErrorLine := StringReplace (StrPas (Text), '`', '''', [rfReplaceAll]);
+	MainForm.AddError (ErrorLine, BugTp, FileName, '', ErrorLine, 0, 0);
+end;
+
+function LinkLibGetOutputFile(var DestFile: TLinkLibDestFile; FileSize, DestCalc, FileRole, FileFormat, FileType: LongInt; Extension: PChar; Executable: WordBool; var EffectiveSize: LongInt): WordBool; cdecl;
+var
+	CalcDest: TCalcDest;
+	CalcFileRole: TFileRole;
+begin
+	Result := False;
+	case FileFormat of
+		llffTIOS:
+			EffectiveSize := 2 + FileSize + 1;
+		llffTIOSUpgrade:
+			EffectiveSize := FileSize + SizeOf (TCalcOSFooter);
+		else
+			Exit;
+	end;
+	case DestCalc of
+		llcdTI89:                     CalcDest := cdTI89;
+		llcdTI89 or llcdFlagTitanium: CalcDest := cdTI89Titanium;
+		llcdTI92Plus:                 CalcDest := cdTI92Plus;
+		llcdV200:                     CalcDest := cdV200;
+		llcdTI92:                     CalcDest := cdTI92;
+		else
+			Exit;
+	end;
+	case FileRole of
+		llfrMain: CalcFileRole := frMain;
+		llfrData: CalcFileRole := frData;
+		else
+			Exit;
+	end;
+	with LinkOutputFiles [CalcDest, CalcFileRole] do begin
+		if not Assigned (Data) then
+			Data := TMemoryStream.Create;
+		Data.Size := FileSize;
+		DestFile.Data := Data.Memory;
+		Tag := FileType;
+		if Assigned (Extension) then begin
+			VarExt := Extension;
+			Inc (EffectiveSize, Length (VarExt) + 2);
+		end else
+			VarExt := '';
+		ExeFile := Executable;
+		OSUpgrade := (FileFormat = llffTIOSUpgrade);
+	end;
+	Result := True;
+end;
+
+{ TRecentFileMenuItem }
+
+destructor TRecentFileMenuItem.Destroy;
+begin
+	FileMenuItem.Free;
+	PopupMenuItem.Free;
+	inherited;
+end;
+
+{ TNoImageDragObject }
+
+function TNoImageDragObject.GetDragImages: TDragImageList;
+begin
+	Result := nil;
+end;
+
+procedure TNoImageDragObject.HideDragImage;
+begin
+end;
+
+procedure TNoImageDragObject.ShowDragImage;
+begin
+end;
+
+{ TMainForm }
+
+procedure TMainForm.Modify;
+begin
+	Modified := True;
+end;
+
+procedure TMainForm.FormCreate(Sender: TObject);
+var
+	TempDir: array [0..255] of Char;
+	S: string;
+	TempLockData: TWin32FindData;
+begin
+	StartingAppNow := True;
+	try
+		if Assigned (StartupScreenForm) then
+			StartupScreenForm.DisplayText := 'Setting Up Environment...';
+		Application.OnException := AppException;
+		WindowState := wsMaximized;
+		RecentFiles := TStringList.Create;
+		ToolsList := TToolsList.Create (Self, TToolsListItem);
+		TIGCCFolder := ExtractFilePath (ParamStr (0));
+		Delete (TIGCCFolder, Pos (UpperCase (IDELocation), UpperCase (TIGCCFolder)), Length (TIGCCFolder));
+		with TRegistry.Create do try
+			RootKey := HKey_Local_Machine;
+			if OpenKeyReadOnly ('\Software\TIGCC Team\TIGCC') then try
+				if ValueExists ('Program Folder') then
+					TIGCCFolder := ReadString ('Program Folder');
+			except end;
+		finally
+			Free;
+		end;
+		try
+			if FileExists (WithBackslash (TIGCCFolder) + A68kLocation + 'A68k.exe') then
+				Include (SpecialSupport, ssA68k);
+		except end;
+		try
+			if FileExists (WithBackslash (TIGCCFolder) + QuillIncludeLocation + 'Quill.drv')
+				or FileExists (WithBackslash (TIGCCFolder) + CIncludeLocation + 'Quill.drv')
+				or FileExists (WithBackslash (TIGCCFolder) + GCCLocation + 'Quill.drv') then
+				Include (SpecialSupport, ssQuill);
+		except end;
+		try
+			if FileExists (WithBackslash (TIGCCFolder) + PackLocation + 'Pack.exe') then
+				Include (SpecialSupport, ssPack);
+		except end;
+		try
+			if FileExists (WithBackslash (TIGCCFolder) + StdLibLocation + 'flashos.a') then
+				Include (SpecialSupport, ssFlashOS);
+		except end;
+		try
+			if FileExists (WithBackslash (TIGCCFolder) + StdLibLocation + 'fargo.a') then
+				Include (SpecialSupport, ssFargo);
+		except end;
+		CompStartFile := AppCompStartFile;
+		CompStop := AppCompStop;
+		CompSetMessage := AppCompSetMessage;
+		CompUpdate := AppCompUpdate;
+		CompUpdateProgramOutput := UpdateProgramOutput;
+		LinkLibHandle := LoadLibrary (PChar (WithBackslash (TIGCCFolder) + LinkLibLocation + 'Link.dll'));
+		if LinkLibHandle <> 0 then begin
+			LinkLibGetInterfaceVersion := GetProcAddress (LinkLibHandle, 'GetInterfaceVersion');
+			if Assigned (LinkLibGetInterfaceVersion) and (LinkLibGetInterfaceVersion = LinkLibCurInterfaceVersion) then begin
+				LinkLibLinkFiles := GetProcAddress (LinkLibHandle, 'LinkFiles');
+				LinkLibCreateArchive := GetProcAddress (LinkLibHandle, 'CreateArchive');
+			end;
+		end;
+		SourceFiles := TSourceFiles.Create;
+		SyntaxCBackup := TSyntaxColoring.Create (nil);
+		SyntaxCBackup.Assign (SyntaxC);
+		SyntaxAsmGNUBackup := TSyntaxColoring.Create (nil);
+		SyntaxAsmGNUBackup.Assign (SyntaxAsmGNU);
+		SyntaxAsmBackup := TSyntaxColoring.Create (nil);
+		if ssA68k in SpecialSupport then
+			SyntaxAsmBackup.Assign (SyntaxAsm);
+		SyntaxQuillBackup := TSyntaxColoring.Create (nil);
+		if ssQuill in SpecialSupport then
+			SyntaxQuillBackup.Assign (SyntaxQuill);
+		TopNode := ProjectTree.Items.Item [0];
+		SourceFileUnit.AppNode := TopNode;
+		SourceFileUnit.NoEditor := NoEditor;
+		OriginalCaption := Caption;
+		Application.OnHint := DisplayHint;
+		if ssA68k in SpecialSupport then begin
+			ActionFileNewA68kAsmHeaderFile.Visible := True;
+			ActionFileNewA68kAsmFile.Visible := True;
+			with ProjectTree.Items.Insert (TopNode.Item [TAsmSourceFile.GetClassTreeIndex], 'A68k Assembly Files') do begin
+				ImageIndex    := TopNode.Item[0].ImageIndex;
+				SelectedIndex := TopNode.Item[0].SelectedIndex;
+			end;
+		end;
+		if ssQuill in SpecialSupport then begin
+			ActionFileNewQuillFile.Visible := True;
+			S := OpenProjectDlg.Filter;
+			Insert (TQuillSourceFile.GetClassFilter + '|', S, Pos (TNormalTextSourceFile.GetClassFilter, S));
+			while Pos ('*.asm;*.txt', S) > 0 do
+				Insert (';*.qll', S, Pos ('*.asm;*.txt', S) + Length ('*.asm'));
+			OpenProjectDlg.Filter := S;
+			OpenProjectDlg.FilterIndex := OpenProjectDlg.FilterIndex + 1;
+			S := AddFileDlg.Filter;
+			Insert (TQuillSourceFile.GetClassFilter + '|', S, Pos (TObjectSourceFile.GetClassFilter, S));
+			while Pos ('*.asm;*.o', S) > 0 do
+				Insert (';*.qll', S, Pos ('*.asm;*.o', S) + Length ('*.asm'));
+			AddFileDlg.Filter := S;
+			AddFileDlg.FilterIndex := AddFileDlg.FilterIndex + 1;
+			with ProjectTree.Items.Insert (TopNode.Item [TQuillSourceFile.GetClassTreeIndex], 'Quill Files') do begin
+				ImageIndex    := TopNode.Item[0].ImageIndex;
+				SelectedIndex := TopNode.Item[0].SelectedIndex;
+			end;
+		end;
+		ProjectTree.FullExpand;
+		ResetProjectSettings;
+		AssumeUndefined := False;
+		AutoSave := True;
+		AutoNews := False;
+		LastNewsDate := 0;
+		GetTempPath (SizeOf (TempDir), TempDir);
+		Temp := AnsiString (TempDir);
+		if (Length (Temp) <= 0) or (not DirExists (Temp)) then begin
+			GetEnvironmentVariable ('TMP', TempDir, SizeOf (TempDir));
+			Temp := AnsiString (TempDir);
+		end;
+		if (Length (Temp) <= 0) or (not DirExists (Temp)) then begin
+			GetEnvironmentVariable ('TEMP', TempDir, SizeOf (TempDir));
+			Temp := AnsiString (TempDir);
+		end;
+		if (Length (Temp) <= 0) or (Length (Temp) > 30) or (Pos (' ', Temp) > 0) or (Pos ('TEMP', UpperCase (Temp)) <= 0) then begin
+			GetWindowsDirectory (TempDir, SizeOf (TempDir));
+			Temp := WithBackslash (AnsiString (TempDir)) + 'TEMP\';
+			if not DirExists (Temp) then try
+				MkDir (Temp);
+			except end;
+		end;
+		if (Length (Temp) <= 0) or (Length (Temp) > 30) or (Pos (' ', Temp) > 0) then begin
+			Temp := 'C:\TEMP\';
+			if not DirExists (Temp) then try
+				MkDir (Temp);
+			except end;
+		end;
+		Temp := WithBackslash (Temp) + IntToHex (GetCurrentProcessID, 8) + '\';
+		if not DirExists (Temp) then try
+			MkDir (Temp);
+		except end;
+		TempLockHandle := Windows.FindFirstFile (PChar (Temp + '*.*'), TempLockData);
+		StopOnErrors := False;
+		JumpToError := True;
+		OpenFolderMessage := True;
+		DeleteAssemblyFiles := True;
+		DeleteObjectFiles := False;
+{$IFDEF CanSplit}
+		SplitFiles := True;
+{$ENDIF}
+		DeleteErrors := True;
+		TransferTarget := ttVTI;
+		LinkPort.PortType := lpCOM;
+		LinkPort.PortNumber := 1;
+		LinkCable := lcBlack;
+		TabSizeAsm := 8;
+		TabSizeC := 2;
+		AutoBlocks := True;
+		EditorOnFly := True;
+		EditorDragDrop := True;
+		if Assigned (StartupScreenForm) then
+			StartupScreenForm.DisplayText := 'Loading Preferences...';
+		try
+			LoadPreferences;
+		except
+			ShowDefaultMessageBox ('An error occured while loading the preferences. Some parts of the program may not be configured correctly.', 'Error', mtProgramError);
+		end;
+		DocFile.FileName := WithBackslash (TIGCCFolder) + DocLocation + 'TIGCC.chm';
+		if DirExists (WithBackslash (TIGCCFolder) + ProjectsLocation) then
+			OpenProjectDlg.InitialDir := WithBackslash (TIGCCFolder) + ProjectsLocation
+		else
+			OpenProjectDlg.InitialDir := TIGCCFolder;
+		SaveProjectDlg.InitialDir := OpenProjectDlg.InitialDir;
+		AddFileDlg.InitialDir := OpenProjectDlg.InitialDir;
+		DragAcceptFiles (Handle, True);
+		ParsingUnit.ErrorMessageProc := ErrorMessage;
+		S := '';
+		if ParamCount > 0 then begin
+			if LowerCase (ExtractFileExt (ParamStr (1))) = LowerCase (ProjectFileExt) then
+				ProjectFile := ExpandFileName (ParamStr (1))
+			else
+				S := ExpandFileName (ParamStr (1));
+		end;
+		if Length (ProjectFile) > 0 then begin
+			if Assigned (StartupScreenForm) then
+				StartupScreenForm.DisplayText := 'Opening Project...';
+			FileLoad;
+		end;
+		if Length (S) > 0 then
+			AddSourceFile (S, True);
+		if AutoNews then begin
+			if Assigned (StartupScreenForm) then
+				StartupScreenForm.DisplayText := 'Downloading Headlines...';
+			with TNewsForm.Create (Self) do begin
+				SilentConnect := True;
+				Connect;
+			end;
+		end;
+	except
+		ShowDefaultMessageBox ('An error occured while setting up the application. Some parts of the program may not be configured correctly.', 'Error', mtProgramError);
+	end;
+	StartingAppNow := False;
+
+{$IFDEF CODINGEXT}
+  InitCodingExt;
+{$ENDIF}
+end;
+
+procedure TMainForm.FormDestroy(Sender: TObject);
+var
+	I: Integer;
+begin
+	Closing := True;
+	ClearDebugInfo;
+	ErrorList.Items.Clear;
+	SourceFiles.Free;
+	SyntaxQuillBackup.Free;
+	SyntaxAsmBackup.Free;
+	SyntaxAsmGNUBackup.Free;
+	SyntaxCBackup.Free;
+	if LinkLibHandle <> 0 then
+		FreeLibrary (LinkLibHandle);
+	if TempLockHandle <> INVALID_HANDLE_VALUE then
+		Windows.FindClose (TempLockHandle);
+	try
+		RmDir (Temp);
+	except end;
+	ToolsList.Free;
+	with RecentFiles do begin
+		for I := Count - 1 downto 0 do
+			Objects[I].Free;
+		Free;
+	end;
+end;
+
+procedure TMainForm.AppException(Sender: TObject; E: Exception);
+begin
+	if not (E is ESocketError) then
+		ShowDefaultMessageBox ('Internal Error: Exception ' + E.ClassName + ', Message "' + E.Message + '"'#13#10#13#10'Please fill out a bug report form at http://tigcc.ticalc.org/.', 'Internal Error', mtProgramError);
+end;
+
+procedure TMainForm.ProjectTreeEditing(Sender: TObject; Node: TTreeNode;
+	var AllowEdit: Boolean);
+begin
+	AllowEdit := Assigned (Node.Data) or not Assigned (Node.Parent);
+end;
+
+procedure TMainForm.ProjectAddFiles(Sender: TObject);
+var
+	I: Integer;
+	F: TSourceFile;
+begin
+	if AddFileDlg.Execute then begin
+		for I := AddFileDlg.Files.Count - 1 downto 0 do begin
+			F := AddSourceFile(ExpandFileName(AddFileDlg.Files[I]));
+			if (I = 0) and Assigned (F) and Assigned (F.TreeItem) then
+				SelectNode (F.TreeItem);
+		end;
+		Modify;
+	end else
+		Abort;
+end;
+
+procedure TMainForm.ProjectTreeChange(Sender: TObject; Node: TTreeNode);
+var
+	NewSelection: TTreeNode;
+	NewEditor: TWinControl;
+	IsMemo,
+	DataItem,
+	BinaryType: Boolean;
+begin
+	NewSelection := ProjectTree.Selected;
+	PreviousNode := NewSelection;
+	if not Closing then begin
+		if Assigned (NewSelection) and Assigned (NewSelection.Data) and (TObject (NewSelection.Data) is TSourceFile) then
+			NewEditor := TSourceFile(NewSelection.Data).Editor
+		else
+			NewEditor := NoEditor;
+		if Assigned (EditorToHide) and (EditorToHide <> NewEditor) then
+			EditorToHide.Align := alNone;
+		if NewEditor.Parent <> EditorPanel then
+			NewEditor.Parent := EditorPanel;
+		if NewEditor.Align <> alClient then
+			NewEditor.Align := alClient;
+		IsMemo := NewEditor is TMemoComponent;
+		if IsMemo then begin
+			with TMemoComponent (NewEditor) do begin
+				DrawingSuspended := True;
+				OnEnter := EditorEnter;
+				OnExit := EditorExit;
+				OnKeyDown := EditorKeyDown;
+				OnChange := EditorChange;
+				OnSelectionChange := EditorChange;
+				PopupMenu := EditorPopup;
+			end;
+		end;
+		NewEditor.Show;
+		Update;
+		if IsMemo then
+			with TMemoComponent (NewEditor) do begin
+				DrawingSuspended := False;
+				Repaint;
+			end;
+		if Assigned (EditorToHide) and (EditorToHide <> NewEditor) then
+			EditorToHide.Hide;
+		EditorToHide := nil;
+		DataItem := Assigned (NewSelection) and Assigned (NewSelection.Data);
+		Node := GetSourceTypeFolder (NewSelection);
+		BinaryType := Assigned (Node) and ((Node.Index = TObjectSourceFile.GetClassTreeIndex) or (Node.Index = TArchiveSourceFile.GetClassTreeIndex) or (Node.Index = TOtherSourceFile.GetClassTreeIndex));
+		ActionFileNewFolder.Enabled := Assigned (NewSelection) and Assigned (NewSelection.Parent);
+		ActionTreeItemNewFolder.Enabled := ActionFileNewFolder.Enabled;
+		ActionFileNewFile.Enabled := ActionFileNewFolder.Enabled and (not BinaryType);
+		ActionTreeItemNewFile.Enabled := ActionFileNewFile.Enabled;
+		if ActiveControl = ProjectTree then
+			ActionEditDelete.Enabled := DataItem;
+		ActionFilePrint.Enabled := DataItem and (TObject (NewSelection.Data) is TSourceFile) and TSourceFile(NewSelection.Data).Printable and (Printer.Printers.Count > 0);
+		ActionFilePrintQuickly.Enabled := ActionFilePrint.Enabled;
+		ActionFindFunctions.Enabled := DataItem and (TObject (NewSelection.Data) is TSourceTextSourceFile);
+		UpdateStatusBar;
+	end;
+end;
+
+procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+begin
+	if Compiling then
+		CanClose := False
+	else
+		try
+			WarnIfModified;
+			SavePreferences;
+		except
+			CanClose := False;
+		end;
+end;
+
+procedure TMainForm.WarnIfModified;
+var
+	I: Integer;
+begin
+	if Modified then
+		case ShowDefaultMessageBox
+			('The current project has been modified.  Do you want to save the changes?',
+			'Project Modified', mtQuestion, True) of
+			idYes: FileSave;
+			idCancel: Abort;
+		end;
+	with SourceFiles do
+		for I := 0 to Count - 1 do
+			with Items [I] as TSourceFile do
+				WarnIfModified;
+end;
+
+procedure TMainForm.FileLoad;
+function StringToRelocFormat(const S: string): TRelocFormat;
+begin
+	if S = 'None' then
+		Result := rfNone
+	else if S = 'Direct' then
+		Result := rfDirect
+	else if S = 'AMS' then
+		Result := rfAMS
+	else if S = 'Kernel' then
+		Result := rfKernel
+	else if S = 'Compressed' then
+		Result := rfCompressed
+	else if S = 'F-Line' then
+		Result := rfFLine
+	else
+		Result := rfUnknown;
+end;
+var
+	F: TOpenFileStatusForm;
+	I,
+	J,
+	Ps: Integer;
+	S,
+	P: string;
+	SL: TStringList;
+	Folder: TFolder;
+	Node,
+	SubNode: TTreeNode;
+	CurrentFile: TSourceFile;
+begin
+	if not Compiling then begin
+		WarnIfModified;
+		Modified := False;
+		OpeningProjectNow := True;
+		Update;
+		F := nil;
+		ProjectTree.Items.BeginUpdate;
+		S := ProjectFile;
+		try
+			FileClear;
+			if (Length (S) > 0) and FileExists (S) then begin
+				if not StartingAppNow then begin
+					try
+						F := TOpenFileStatusForm.Create (Self);
+					except
+						F := nil;
+					end;
+					if Assigned (F) then begin
+						P := ExtractFileName (S);
+						F.FileNameLabel.Caption := 'Opening Project ''' + Copy (P, 1, LastPos ('.', P) - 1) + '''...';
+						F.Show;
+						F.Update;
+					end;
+				end;
+				SHAddToRecentDocs(SHARD_PATH, PChar (S));
+				with TIniFile.Create (S) do try
+					TopNode.Text          := ReadString ('Settings', 'Project Name',                   'Project1');
+					ProjectFile := S;
+					if                       ReadBool   ('Settings', 'Archive',                        False) then
+						ProjectTarget := ptArchive
+					else if                  ReadBool   ('Settings', 'Flash OS',                       False) then
+						ProjectTarget := ptFlashOS
+					else if                  ReadBool   ('Settings', 'Fargo',                          False) then
+						ProjectTarget := ptFargo;
+					UseDataVar            := ReadBool   ('Settings', 'Use Data Variable',              False);
+					DataVar               := ReadString ('Settings', 'Data Variable',                  '');
+					DataVarCopy           := ReadBool   ('Settings', 'Copy Data Variable',             True);
+					DataVarCopyIfArchived := ReadBool   ('Settings', 'Copy Data Variable if Archived', True);
+					Pack                  := ReadBool   ('Settings', 'Pack',                           False);
+					PackVar               := ReadString ('Settings', 'Packed Variable',                '');
+					GCCSwitches           := ReadString ('Settings', 'GCC Switches',                   '');
+					AsSwitches            := ReadString ('Settings', 'GNU Assembler Switches',         '');
+					AsmSwitches           := ReadString ('Settings', 'Assembler Switches',             '');
+					DebugInfo             := ReadBool   ('Settings', 'Debug Info',                     False);
+					StdLib                := ReadBool   ('Settings', 'Standard Library',               True);
+					InitBSS               := ReadBool   ('Settings', 'Initialize BSS',                 True);
+					OptimizeNOPs          := ReadBool   ('Settings', 'Optimize NOPs',                  True);
+					OptimizeReturns       := ReadBool   ('Settings', 'Optimize Returns',               True);
+					OptimizeBranches      := ReadBool   ('Settings', 'Optimize Branches',              True);
+					OptimizeMoves         := ReadBool   ('Settings', 'Optimize Moves',                 True);
+					OptimizeTests         := ReadBool   ('Settings', 'Optimize Tests',                 True);
+					OptimizeCalculations  := ReadBool   ('Settings', 'Optimize Calculations',          True);
+					RemoveUnusedSections  := ReadBool   ('Settings', 'Remove Unused Sections',         True);
+					CutUnusedRanges       := ReadBool   ('Settings', 'Cut Unused Ranges',              True);
+					ReorderSections       := ReadBool   ('Settings', 'Reorder Sections',               True);
+					MergeConstants        := ReadBool   ('Settings', 'Merge Constants',                True);
+					OutputBin             := ReadBool   ('Settings', 'Binary Output',                  False);
+					CommandLine           := ReadString ('Settings', 'Command Line',                   '');
+					PostBuildProcessFile  := ReadString ('Settings', 'Post-Build Process',             '');
+					while Pos ('`', PostBuildProcessFile) > 0 do
+						PostBuildProcessFile [Pos ('`', PostBuildProcessFile)] := '"';
+					if Assigned (PredefinedLibOptions) then
+						with PredefinedLibOptions do begin
+							CalcDests := [];
+							if                                     ReadBool   ('Library Options', 'Use TI-89',                    False) then
+								Include (CalcDests, cdTI89);
+							if                                     ReadBool   ('Library Options', 'Use TI-92 Plus',               False) then
+								Include (CalcDests, cdTI92Plus);
+							if                                     ReadBool   ('Library Options', 'Use V200',                     False) then
+								Include (CalcDests, cdV200);
+							OptimizeCalcConsts                  := ReadBool   ('Library Options', 'Optimize Calc Consts',         False);
+							if                                     ReadBool   ('Library Options', 'Use PreOS',                    False) then
+								KernelFormat := kfCompressedTables
+							else if                                ReadBool   ('Library Options', 'Use Kernel',                   False) then
+								KernelFormat := kfStandard
+							else
+								KernelFormat := kfNone;
+							UseMinAMS                           := ReadBool   ('Library Options', 'Minimum AMS Version Defined',  False);
+							MinAMS                              := ReadString ('Library Options', 'Minimum AMS Version',          '1.00');
+							UnofficialOSSupport                 := ReadBool   ('Library Options', 'Unofficial OS Support',        False);
+							RelocFormat    := StringToRelocFormat (ReadString ('Library Options', 'Reloc Format',                 ''));
+							ROMCallFormat  := StringToRelocFormat (ReadString ('Library Options', 'ROM Call Format',              ''));
+							BSSRefFormat   := StringToRelocFormat (ReadString ('Library Options', 'BSS Ref Format',               ''));
+							DataRefFormat  := StringToRelocFormat (ReadString ('Library Options', 'Data Ref Format',              ''));
+							UseFLineJumps                       := ReadBool   ('Library Options', 'Use F-Line Jumps',             False);
+							Use4ByteFLineJumps                  := ReadBool   ('Library Options', 'Use 4-Byte F-Line Jumps',      False);
+							OptimizeROMCalls                    := ReadBool   ('Library Options', 'Optimize ROM Calls',           False);
+							UseInternalFLineEmulator            := ReadBool   ('Library Options', 'Use Internal F-Line Emulator', False);
+							UseReturnValue                      := ReadBool   ('Library Options', 'Use Return Value',             False);
+							EnableErrorReturn                   := ReadBool   ('Library Options', 'Enable Error Return',          False);
+							SaveScreen                          := ReadBool   ('Library Options', 'Save Screen',                  False);
+						end;
+					SL := TStringList.Create;
+					try
+						ReadSection ('Included Files', SL);
+						for I := 0 to SL.Count - 1 do begin
+							P := SL.Strings [I];
+							S := ReadString ('Included Files', P, '');
+							if Length (S) > 0 then begin
+								if Copy (P, Length (P) - Length (' Folder') + 1, Length (P)) = ' Folder' then begin
+									Delete (P, Length (P) - Length (' Folder') + 1, Length (P));
+									J := SL.IndexOf (P);
+									if J >= 0 then begin
+										Node := TopNode.Item [TSourceFile.GetAppropriateClassFromName (Copy (P, 1, LastPos (' ', P) - 1)).GetClassTreeIndex];
+										repeat
+											Ps := Pos ('\', S);
+											if Ps > 0 then
+												P := Copy (S, 1, Ps - 1)
+											else
+												P := S;
+											SubNode := Node.GetFirstChild;
+											while Assigned (SubNode) and ((not Assigned (SubNode.Data)) or (not (TObject (SubNode.Data) is TFolder)) or (SubNode.Text <> P)) do
+												SubNode := SubNode.GetNextSibling;
+											if Assigned (SubNode) then
+												Node := SubNode
+											else begin
+												Folder := TFolder.Create;
+												Node := ProjectTree.Items.AddChildObject (Node, P, Folder);
+												Folder.TreeItem := Node;
+												with Node do begin
+													ImageIndex    := 0;
+													SelectedIndex := 1;
+												end;
+											end;
+											Delete (S, 1, Length (P) + 1);
+										until Length (S) <= 0;
+										SL.Objects [J] := Node.Data;
+									end;
+								end;
+							end;
+						end;
+						for I := 0 to SL.Count - 1 do begin
+							P := SL.Strings [I];
+							S := ReadString ('Included Files', P, '');
+							if Length (S) > 0 then begin
+								if Copy (P, Length (P) - Length (' Folder') + 1, Length (P)) <> ' Folder' then begin
+									if Pos (':', S) <= 0 then
+										S := ExtractFilePath (ProjectFile) + S;
+									if FileExists (S) then
+										AddSourceFile (S, False, TSourceFile.GetAppropriateClassFromName (Copy (P, 1, LastPos (' ', P) - 1)), TFolder (SL.Objects [I]))
+									else
+										ShowDefaultMessageBox ('File not found:'#13#10#13#10 + S, 'Error', mtProgramError);
+								end;
+							end;
+						end;
+					finally
+						SL.Free;
+					end;
+					S := ReadString ('File Editing', 'Open File', '');
+					if Length (S) > 0 then begin
+						CurrentFile := SourceFiles.FindFile (S);
+						if Assigned (CurrentFile) then
+							CurrentFile.Edit;
+					end;
+				finally
+					Free;
+				end;
+				ProjectTree.FullExpand;
+				NoEditor.Show;
+				UpdateDebugSettings;
+				AddToRecent (ProjectFile);
+			end;
+			SortFiles;
+		finally
+			ProjectTree.Items.EndUpdate;
+			OpeningProjectNow := False;
+			if Assigned (F) then
+				F.Free;
+		end;
+		Modified := False;
+	end;
+end;
+
+procedure TMainForm.FileNew;
+begin
+	if not Compiling then begin
+		WarnIfModified;
+		Modified := False;
+		ProjectFile := '';
+		FileClear;
+	end;
+end;
+
+procedure TMainForm.FileClear;
+procedure TryDeleteNode(Node: TTreeNode);
+var
+	I: Integer;
+begin
+	with Node do begin
+		for I := Count - 1 downto 0 do
+			TryDeleteNode (Item [I]);
+		if Assigned (Data) then
+			Delete;
+	end;
+end;
+begin
+	if not Compiling then begin
+		WarnIfModified;
+		Modified := False;
+		Invalidated := True;
+		ActiveControl := ProjectTree;
+		ErrorList.Items.BeginUpdate;
+		ErrorList.Items.Clear;
+		ErrorList.Items.EndUpdate;
+		ProjectTree.Items.BeginUpdate;
+		ClearDebugInfo;
+		TopNode.Text := 'Project1';
+		SelectNode (TopNode);
+		TryDeleteNode (TopNode);
+		ProjectTree.FullExpand;
+		ProjectTree.Items.EndUpdate;
+		ResetProjectSettings;
+		NoEditor.Show;
+		UpdateDebugSettings;
+		Update;
+		Modified := False;
+	end;
+end;
+
+procedure TMainForm.FileOpen(const FN: string);
+begin
+	if not Compiling then begin
+		WarnIfModified;
+		Modified := False;
+		ProjectTree.Items.BeginUpdate;
+		ProjectFile := FN;
+		FileLoad;
+		ProjectTree.Items.EndUpdate;
+	end;
+end;
+
+procedure TMainForm.FileSave;
+function RelocFormatToString(RelocFormat: TRelocFormat): string;
+begin
+	case RelocFormat of
+		rfNone:        Result := 'None';
+		rfDirect:      Result := 'Direct';
+		rfAMS:         Result := 'AMS';
+		rfKernel:      Result := 'Kernel';
+		rfCompressed:  Result := 'Compressed';
+		rfFLine:       Result := 'F-Line';
+		else           Result := 'Unknown';
+	end;
+end;
+var
+	I,
+	ClassCount: Integer;
+	S: string;
+	SL: TStringList;
+begin
+	if ProjectFile = '' then
+		FileSaveProjectAs (Self)
+	else begin
+		try
+			with SourceFiles do
+				for I := 0 to Count - 1 do
+					with Items [I] as TSourceFile do begin
+						if UpperCase (ExtractFilePath (FileName)) = 'C:\' then
+							FileName := ExtractFilePath (ProjectFile) + LogicalFileName;
+						if Modified or not FileExists (FileName) then
+							Save;
+					end;
+			with TIniFile.Create (ProjectFile) do try
+				WriteBool   ('Settings', 'Archive',                        ProjectTarget = ptArchive);
+				WriteBool   ('Settings', 'Flash OS',                       ProjectTarget = ptFlashOS);
+				WriteBool   ('Settings', 'Fargo',                          ProjectTarget = ptFargo);
+				WriteBool   ('Settings', 'Use Data Variable',              UseDataVar);
+				WriteString ('Settings', 'Data Variable',                  DataVar);
+				WriteBool   ('Settings', 'Copy Data Variable',             DataVarCopy);
+				WriteBool   ('Settings', 'Copy Data Variable if Archived', DataVarCopyIfArchived);
+				WriteBool   ('Settings', 'Pack',                           Pack);
+				WriteString ('Settings', 'Packed Variable',                PackVar);
+				WriteString ('Settings', 'Project Name',                   TopNode.Text);
+				WriteString ('Settings', 'GCC Switches',                   GCCSwitches);
+				WriteString ('Settings', 'GNU Assembler Switches',         AsSwitches);
+				WriteString ('Settings', 'Assembler Switches',             AsmSwitches);
+				WriteBool   ('Settings', 'Debug Info',                     DebugInfo);
+				WriteBool   ('Settings', 'Standard Library',               StdLib);
+				WriteBool   ('Settings', 'Initialize BSS',                 InitBSS);
+				WriteBool   ('Settings', 'Optimize NOPs',                  OptimizeNOPs);
+				WriteBool   ('Settings', 'Optimize Returns',               OptimizeReturns);
+				WriteBool   ('Settings', 'Optimize Branches',              OptimizeBranches);
+				WriteBool   ('Settings', 'Optimize Moves',                 OptimizeMoves);
+				WriteBool   ('Settings', 'Optimize Tests',                 OptimizeTests);
+				WriteBool   ('Settings', 'Optimize Calculations',          OptimizeCalculations);
+				WriteBool   ('Settings', 'Remove Unused Sections',         RemoveUnusedSections);
+				WriteBool   ('Settings', 'Cut Unused Ranges',              CutUnusedRanges);
+				WriteBool   ('Settings', 'Reorder Sections',               ReorderSections);
+				WriteBool   ('Settings', 'Merge Constants',                MergeConstants);
+				WriteBool   ('Settings', 'Binary Output',                  OutputBin);
+				WriteString ('Settings', 'Command Line',                   CommandLine);
+				S := PostBuildProcessFile;
+				while Pos ('"', S) > 0 do
+					S [Pos ('"', S)] := '`';
+				WriteString ('Settings', 'Post-Build Process',             S);
+				if Assigned (PredefinedLibOptions) then
+					with PredefinedLibOptions do begin
+						WriteBool   ('Library Options', 'Use TI-89',                    cdTI89     in CalcDests);
+						WriteBool   ('Library Options', 'Use TI-92 Plus',               cdTI92Plus in CalcDests);
+						WriteBool   ('Library Options', 'Use V200',                     cdV200     in CalcDests);
+						WriteBool   ('Library Options', 'Optimize Calc Consts',         OptimizeCalcConsts);
+						WriteBool   ('Library Options', 'Use Kernel',                   KernelFormat <> kfNone);
+						WriteBool   ('Library Options', 'Use PreOS',                    KernelFormat = kfCompressedTables);
+						WriteBool   ('Library Options', 'Minimum AMS Version Defined',  UseMinAMS);
+						WriteString ('Library Options', 'Minimum AMS Version',          MinAMS);
+						WriteBool   ('Library Options', 'Unofficial OS Support',        UnofficialOSSupport);
+						WriteString ('Library Options', 'Reloc Format',                 RelocFormatToString (RelocFormat));
+						WriteString ('Library Options', 'ROM Call Format',              RelocFormatToString (ROMCallFormat));
+						WriteString ('Library Options', 'BSS Ref Format',               RelocFormatToString (BSSRefFormat));
+						WriteString ('Library Options', 'Data Ref Format',              RelocFormatToString (DataRefFormat));
+						WriteBool   ('Library Options', 'Use F-Line Jumps',             UseFLineJumps);
+						WriteBool   ('Library Options', 'Use 4-Byte F-Line Jumps',      Use4ByteFLineJumps);
+						WriteBool   ('Library Options', 'Optimize ROM Calls',           OptimizeROMCalls);
+						WriteBool   ('Library Options', 'Use Internal F-Line Emulator', UseInternalFLineEmulator);
+						WriteBool   ('Library Options', 'Use Return Value',             UseReturnValue);
+						WriteBool   ('Library Options', 'Enable Error Return',          EnableErrorReturn);
+						WriteBool   ('Library Options', 'Save Screen',                  SaveScreen);
+					end;
+				EraseSection ('Included Files');
+				SL := TStringList.Create;
+				try
+					with SourceFiles do
+						for I := 0 to Count - 1 do
+							with Items [I] as TSourceFile do
+								if InProject then begin
+									S := SL.Values [ClassItemName];
+									if Length (S) > 0 then
+										ClassCount := StrToInt (S) + 1
+									else
+										ClassCount := 1;
+									SL.Values [ClassItemName] := IntToStr (ClassCount);
+									WriteString ('Included Files', ClassItemName + ' ' + IntToStr (ClassCount), DynamicName);
+									S := FolderPath;
+									if Length (S) > 0 then
+										WriteString ('Included Files', ClassItemName + ' ' + IntToStr (ClassCount) + ' Folder', S);
+								end;
+				finally
+					SL.Free;
+				end;
+				S := '';
+				if Assigned (ProjectTree.Selected) and Assigned (ProjectTree.Selected.Data) and (TObject (ProjectTree.Selected.Data) is TSourceFile) then
+					S := TSourceFile(ProjectTree.Selected.Data).FileName;
+				WriteString ('File Editing', 'Open File', S);
+				UpdateFile;
+			finally
+				Free;
+			end;
+			Modified := False;
+		except
+			ShowDefaultMessageBox ('Error saving project file.', 'Error', mtProgramError);
+		end;
+		AddToRecent (ProjectFile);
+	end;
+end;
+
+procedure TMainForm.FileSaveAs(const FN: string);
+var
+	I: Integer;
+begin
+	with SourceFiles do
+		for I := 0 to Count - 1 do
+			with Items [I] as TSourceFile do
+				if Pos ('\', DynamicName) <= 0 then
+					WriteToFile (ExtractFilePath (FN) + DynamicName, True);
+	ProjectFile := FN;
+	FileSave;
+end;
+
+procedure TMainForm.ProjectTreeDeletion(Sender: TObject; Node: TTreeNode);
+begin
+	PreviousNode := nil;
+	EditorToHide := nil;
+	if Assigned (Node.Data) then
+		if TObject (Node.Data) is TSourceFile then begin
+			with TSourceFile (Node.Data) do begin
+				TreeItem := nil;
+				Free;
+			end;
+		end else
+			with TObject (Node.Data) do
+				Free;
+	ProjectTree.Invalidate;
+end;
+
+procedure TMainForm.FileExit(Sender: TObject);
+begin
+	Close;
+end;
+
+procedure TMainForm.FileNewProject(Sender: TObject);
+begin
+	WarnIfModified;
+	Modified := False;
+	FileNew;
+end;
+
+procedure TMainForm.TreeItemRemove(Sender: TObject);
+var
+	Node,
+	CurNode: TTreeNode;
+begin
+	Node := ProjectTree.Selected;
+	if (not Compiling) and Assigned (Node) and Assigned (Node.Data) then begin
+		CurNode := Node;
+		while Assigned (CurNode) and (CurNode <> Node.GetNextSibling) do begin
+			if Assigned (CurNode.Data) and (TObject (CurNode.Data) is TSourceFile) then
+				TSourceFile(CurNode.Data).WarnIfModified;
+			CurNode := CurNode.GetNext;
+			if Node.GetNextSibling = nil then
+				break;
+		end;
+		Node.Delete;
+		Modify;
+	end;
+end;
+
+procedure TMainForm.TreeItemDelete(Sender: TObject);
+var
+	Node: TTreeNode;
+begin
+	Node := ProjectTree.Selected;
+	if (not Compiling) and Assigned (Node) and Assigned (Node.Data) and (TObject (Node.Data) is TSourceFile) then begin
+		if ShowDefaultMessageBox
+			('Are you sure you want to delete this source file?  You cannot undo this operation.',
+			'Confirm Deletion', mtQuestion) = idYes then begin
+			with TSourceFile (Node.Data) do
+				if (FileName <> '') and FileExists (FileName) then
+					DeleteFile (FileName);
+			Node.Delete;
+			Modify;
+		end;
+	end;
+end;
+
+procedure TMainForm.CopyHeaders;
+var
+	I,
+	J: Integer;
+	HasA68kFiles: Boolean;
+begin
+	HasA68kFiles := False;
+	with SourceFiles do begin
+		for I := 0 to Count - 1 do
+			if Items [I] is TAsmSourceFile then begin
+				HasA68kFiles := True;
+				Break;
+			end;
+		if HasA68kFiles then
+			with TFileReferences.Create do try
+				SearchForFiles (WithBackslash (TIGCCFolder) + ASMIncludeLocation + '*.*', atAll);
+				for J := 0 to Count - 1 do
+					CopyFile (PChar (Items[J].FullName), PChar (Temp + ExtractFileName (Items[J].FullName)), False);
+			finally
+				Free;
+			end;
+		for I := 0 to Count - 1 do begin
+			if Items [I] is THeaderSourceFile then begin
+				with Items [I] as THeaderSourceFile do begin
+					if Invalidated then
+						RecompileFiles;
+					if InProject then
+						SplitAndWriteToFile (Temp + LogicalFileName);
+				end;
+			end else if Items [I] is TOtherSourceFile then
+				with Items [I] as TSourceFile do
+					if InProject then
+						WriteToFile (Temp + LogicalFileName);
+		end;
+	end;
+end;
+
+procedure TMainForm.DeleteHeaders;
+var
+	I: Integer;
+	FN: string;
+begin
+	with TFileReferences.Create do try
+		SearchForFiles (Temp + '*.h', atAll);
+		for I := 0 to Count - 1 do try
+			DeleteFile (Items[I].FullName);
+		except end;
+	finally
+		Free;
+	end;
+	with SourceFiles do
+		for I := 0 to Count - 1 do
+			if (Items [I] is THeaderSourceFile) or (Items [I] is TOtherSourceFile) then
+				with Items [I] as TSourceFile do begin
+					FN := Temp + LogicalFileName;
+					if FileExists (FN) then try
+						DeleteFile (FN);
+					except end;
+					RemovePathFor (FN, Temp);
+				end;
+end;
+
+procedure TMainForm.TreeItemCompile(Sender: TObject);
+var
+	Node: TTreeNode;
+begin
+	Node := ProjectTree.Selected;
+	if (not Compiling) and Assigned (Node) and Assigned (Node.Data) and (TObject (Node.Data) is TSourceFile) and (TSourceFile(Node.Data).Compilable) then begin
+		BeginCompilation;
+		CopyHeaders;
+		TSourceFile(Node.Data).Compile;
+		DeleteHeaders;
+		EndCompilation;
+	end;
+end;
+
+procedure TMainForm.CloseErrorsButtonClick(Sender: TObject);
+begin
+	HideErrors;
+end;
+
+procedure TMainForm.AddError(const Line: string; BugTp: TBugType; SourceF: string; ErrFunc: string; ErrMessage: string; SourceLn: Integer; Offset: Integer);
+var
+	I,
+	J: Integer;
+	O: TFoundError;
+	Ignore: Boolean;
+	Token: string;
+begin
+	ErrMessage := Trim (ErrMessage);
+	if ErrMessage <> '' then begin
+		Ignore := False;
+		if BugTp in [btWarning, btInfo] then begin
+			if ((ErrFunc = '') and (UpperCase (ErrMessage) = '''STATIC'' IS NOT AT BEGINNING OF DECLARATION'))
+				or (Pos ('__DUMMY__', UpperCase (ErrMessage)) > 0)
+				or (Pos ('''__R''', UpperCase (ErrMessage)) > 0)
+				or (Pos ('MULTI-LINE STRING LITERALS ARE DEPRECATED', UpperCase (ErrMessage)) > 0) then
+				Ignore := True;
+		end else begin
+			if (Pos ('(EACH UNDECLARED IDENTIFIER IS REPORTED ONLY ONCE', UpperCase (ErrMessage)) > 0)
+				or (Pos ('FOR EACH FUNCTION IT APPEARS IN.)', UpperCase (ErrMessage)) > 0) then
+				Ignore := True;
+		end;
+		if not Ignore then begin
+			if ErrFunc = '__main' then
+				ErrFunc := '_main';
+			if ErrFunc = '__exit' then
+				ErrFunc := '_exit';
+			ErrorList.Items.BeginUpdate;
+			try
+				ErrMessage [1] := UpCase (ErrMessage [1]);
+				O := TFoundError.Create;
+				with O do begin
+					SourceFile := nil;
+					if (Length (SourceF) > 0) and (LowerCase (ExtractFileExt (SourceF)) <> '.exe') and (LowerCase (ExtractFileExt (SourceF)) <> '.a') then try
+						if Pos ('\', SourceF) > 0 then begin
+							SourceFile := SourceFiles.FindFile (SourceF);
+							if (not Assigned (SourceFile)) and (LowerCase (ExtractFileExt (SourceF)) = '.o') then begin
+								SourceFile := SourceFiles.FindFile (ChangeFileExt (SourceF, '.c'));
+								if not Assigned (SourceFile) then
+									SourceFile := SourceFiles.FindFile (ChangeFileExt (SourceF, '.s'));
+								if not Assigned (SourceFile) then
+									SourceFile := SourceFiles.FindFile (ChangeFileExt (SourceF, '.asm'));
+							end;
+						end else begin
+							SourceFile := SourceFiles.FindFileNameOnly (SourceF);
+							if (not Assigned (SourceFile)) and (LowerCase (ExtractFileExt (SourceF)) = '.o') then begin
+								SourceFile := SourceFiles.FindFileNameOnly (ChangeFileExt (SourceF, '.c'));
+								if not Assigned (SourceFile) then
+									SourceFile := SourceFiles.FindFileNameOnly (ChangeFileExt (SourceF, '.s'));
+								if not Assigned (SourceFile) then
+									SourceFile := SourceFiles.FindFileNameOnly (ChangeFileExt (SourceF, '.asm'));
+							end;
+						end;
+						if not Assigned (SourceFile) then begin
+							if (Pos ('\', SourceF) > 0) and FileExists (SourceF) then
+								SourceFile := AddSourceFile (SourceF, True)
+							else if FileExists (WithBackslash (TIGCCFolder) + CIncludeLocation + ExtractFileName (SourceF)) then
+								SourceFile := AddSourceFile (WithBackslash (TIGCCFolder) + CIncludeLocation + ExtractFileName (SourceF), True)
+							else if FileExists (WithBackslash (TIGCCFolder) + AsmIncludeLocation + ExtractFileName (SourceF)) then
+								SourceFile := AddSourceFile (WithBackslash (TIGCCFolder) + AsmIncludeLocation + ExtractFileName (SourceF), True);
+						end;
+					except end;
+					BugType := BugTp;
+					WholeLine := Line;
+					ErrorMessage := ErrMessage;
+					ErrFunction := ErrFunc;
+					if Assigned (SourceFile) and (SourceFile is TTextSourceFile) then
+						with SourceFile as TTextSourceFile do
+							if Assigned (TextEditor) then begin
+								I := GetCompiledLineStart (SourceLn) + Offset;
+								if I > 0 then begin
+									if Pos ('''', ErrorMessage) > 0 then begin
+										Token := Copy (ErrorMessage, Pos ('''', ErrorMessage) + 1, Length (ErrorMessage));
+										Delete (Token, Pos ('''', Token), Length (Token));
+										if Length (Token) > 0 then begin
+											J := I;
+											while (J <= TextEditor.TextLength) and (TextEditor.Text [J] in [#9, #10, #13, #32]) and (Copy (TextEditor.Text, J, Length (Token)) <> Token) do
+												Inc (J);
+											if Copy (TextEditor.Text, J, Length (Token)) = Token then
+												I := J;
+										end;
+									end;
+									O.Range := TMCRange.Create (TextEditor.TrackedRanges);
+									O.Range.RStart := I;
+									O.Range.OnOverwrite := DeleteError;
+								end else
+									O.Range := nil;
+							end;
+				end;
+				with ErrorList.Items.Add do begin
+					Data := Pointer (O);
+					ImageIndex := Integer (BugTp);
+					Caption := ErrMessage;
+					if Assigned (O.SourceFile) then
+						SubItems.Add (O.SourceFile.SourceName)
+					else
+						SubItems.Add ('');
+					SubItems.Add (ErrFunc);
+					ShowErrors;
+					if JumpToError and (BugTp = btError) and (not Assigned (ErrorList.Selected)) then begin
+						Selected := True;
+						ErrorListClick (Self);
+					end;
+				end;
+			except end;
+			ErrorList.Items.EndUpdate;
+		end;
+	end;
+	UpdateErrorWindow;
+end;
+
+procedure TMainForm.ClearErrors;
+begin
+	HideErrors;
+	with ErrorList.Items do begin
+		BeginUpdate;
+		Clear;
+		EndUpdate;
+	end;
+	ActionProjectShowErrors.Enabled := False;
+end;
+
+procedure TMainForm.HideErrors;
+begin
+	Splitter2.Hide;
+	ErrWinPanel.Hide;
+	ActionProjectShowErrors.Checked := False;
+end;
+
+procedure TMainForm.ShowErrors;
+begin
+	if ErrorList.Items.Count > 0 then begin
+		ErrWinPanel.Show;
+		Splitter2.Show;
+		Splitter2.Top := ErrWinPanel.Top - Splitter2.Height;
+		ActionProjectShowErrors.Checked := True;
+		ErrorList.Refresh;
+	end;
+end;
+
+procedure TMainForm.ErrorListDeletion(Sender: TObject; Item: TListItem);
+var
+	O: TObject;
+begin
+	if Assigned (Item.Data) then begin
+		O := TObject(Item.Data);
+		Item.Data := nil;
+		O.Free;
+	end;
+end;
+
+procedure TMainForm.UpdateErrorWindow;
+var
+	I: Integer;
+	EC,
+	WC: Integer;
+begin
+	with ErrorList, Items do begin
+		EC := 0;
+		WC := 0;
+		for I := 0 to Count - 1 do
+			with TFoundError (Item[I].Data) do
+				case BugType of
+					btWarning:
+						Inc (WC);
+					btError:
+						Inc (EC);
+				end;
+		ErrorsLabel.Caption := IntToStr (EC);
+		WarningsLabel.Caption := IntToStr (WC);
+		if Count <= 0 then
+			HideErrors;
+	end;
+	ActionProjectShowErrors.Enabled := ErrorList.Items.Count > 0;
+	if not ActionProjectShowErrors.Enabled then
+		ActionProjectShowErrors.Checked := False;
+end;
+
+procedure TMainForm.TreeItemSave(Sender: TObject);
+var
+	Node: TTreeNode;
+begin
+	Node := ProjectTree.Selected;
+	if Assigned (Node) and Assigned (Node.Data) and (TObject (Node.Data) is TSourceFile) then
+		TSourceFile(Node.Data).Save;
+end;
+
+procedure TMainForm.HelpDocumentation(Sender: TObject);
+begin
+	try
+		DocFile.Display;
+	except
+		ShowDefaultMessageBox ('Error opening documentation.', 'Error', mtProgramError);
+	end;
+end;
+
+procedure TMainForm.EditorEnter(Sender: TObject);
+begin
+	ActionEditPaste.Enabled := True;
+	ActionEditSelectAll.Enabled := True;
+	ActionEditIncreaseIndent.Enabled := True;
+	ActionEditDecreaseIndent.Enabled := True;
+	ActionFindOpenFile.Enabled := True;
+	UpdateEditButtons;
+end;
+
+procedure TMainForm.EditorExit(Sender: TObject);
+begin
+	ActionEditDelete.Enabled := False;
+	ActionEditCut.Enabled := False;
+	ActionEditCopy.Enabled := False;
+	ActionEditPaste.Enabled := False;
+	ActionEditSelectAll.Enabled := False;
+	ActionEditIncreaseIndent.Enabled := False;
+	ActionEditDecreaseIndent.Enabled := False;
+	ActionFindOpenFile.Enabled := False;
+	ActionEditUndo.Enabled := False;
+	ActionEditRedo.Enabled := False;
+end;
+
+procedure TMainForm.EditUndo(Sender: TObject);
+begin
+	if Assigned (CurrentEditor) then
+		CurrentEditor.Undo;
+end;
+
+procedure TMainForm.EditRedo(Sender: TObject);
+begin
+	if Assigned (CurrentEditor) then
+		CurrentEditor.Redo;
+end;
+
+procedure TMainForm.EditClear(Sender: TObject);
+var
+	Editor: TMemoComponent;
+begin
+	Editor := CurrentEditor;
+	if Assigned (Editor) and (ActiveControl = Editor) then
+		Editor.ClearSelection
+	else if ActiveControl = ProjectTree then
+		TreeItemRemove (Sender);
+end;
+
+procedure TMainForm.EditCut(Sender: TObject);
+var
+	Editor: TMemoComponent;
+begin
+	Editor := CurrentEditor;
+	if Assigned (Editor) and (ActiveControl = Editor) then
+		Editor.CutToClipboard;
+end;
+
+procedure TMainForm.EditCopy(Sender: TObject);
+var
+	Editor: TMemoComponent;
+begin
+	Editor := CurrentEditor;
+	if Assigned (Editor) and (ActiveControl = Editor) then
+		Editor.CopyToClipboard;
+end;
+
+procedure TMainForm.EditPaste(Sender: TObject);
+var
+	Editor: TMemoComponent;
+begin
+	Editor := CurrentEditor;
+	if Assigned (Editor) and (ActiveControl = Editor) then
+		Editor.PasteFromClipboard;
+end;
+
+procedure TMainForm.EditSelectAll(Sender: TObject);
+var
+	Editor: TMemoComponent;
+begin
+	Editor := CurrentEditor;
+	if Assigned (Editor) and (ActiveControl = Editor) then
+		Editor.SelectAll;
+end;
+
+procedure TMainForm.ProjectCompile(Sender: TObject);
+var
+	I: Integer;
+begin
+	if not Compiling then begin
+		if AutoSave then
+			FileSave
+		else
+			with SourceFiles do
+				for I := 0 to Count - 1 do
+					with Items [I] as TSourceFile do
+						if not InProject then
+							Save;
+		BeginCompilation;
+		CompileProject;
+		EndCompilation;
+	end;
+end;
+
+procedure TMainForm.ProjectMake(Sender: TObject);
+begin
+	MakeFileWrapped;
+	DisplayFolderMessage;
+end;
+
+procedure TMainForm.MakeFileWrapped;
+var
+	I: Integer;
+begin
+	if not Compiling then begin
+		if AutoSave then
+			FileSave
+		else
+			with SourceFiles do
+				for I := 0 to Count - 1 do
+					with Items [I] as TSourceFile do
+						if not InProject then
+							Save;
+		OperationSuccessful := False;
+		if ProjectFile = '' then
+			ShowDefaultMessageBox ('You need to save your project before you can create executable files.', 'Project not Saved', mtProgramError)
+		else begin
+			BeginCompilation;
+			CompileProject;
+			Application.ProcessMessages;
+			if OperationSuccessful and not OperationCancelled then
+				MakeFile;
+			EndCompilation;
+		end;
+	end;
+end;
+
+procedure TMainForm.MakeFile;
+	procedure FileNotCompiled(const FileName: string);
+	begin
+		ShowDefaultMessageBox
+			('The file ''' + FileName + ''' has not been compiled.  You have to compile it first before you can link it to your project.',
+			'No Object File', mtProgramError);
+	end;
+var MainFiles: array [TCalcDest] of string;
+	procedure HandleContents(const ProjectFile, FolderName, VarName, DataFolderName, DataVarName: string; Pack: Boolean; const PackVar: string; CalcDest: TCalcDest);
+	var
+		InputStream,
+		OutputStream: TMemoryStream;
+		OutputSize: LongWord;
+		FileSize: Integer;
+		F: file;
+		B: Byte;
+	begin
+		CompUpdate;
+		OperationSuccessful := False;
+		with LinkOutputFiles [CalcDest, frMain] do
+			if Assigned (Data) then begin
+				OutputStream := TMemoryStream.Create;
+				try
+					if OSUpgrade then begin
+						OutputSize := GetOSUpgradeFileSize (Data.Size, OutputBin);
+						OutputStream.Size := OutputSize;
+						ProduceOSUpgradeFile (OutputStream.Memory, Data.Memory, Data.Size, OutputBin);
+						MainFiles [CalcDest] := ChangeFileExt (ProjectFile, GetOSUpgradeFileExt (CalcDest, OutputBin));
+						OutputStream.SaveToFile (MainFiles [CalcDest]);
+						if LongWord (ProgSize) < OutputSize then
+							ProgSize := OutputSize;
+						OperationSuccessful := True;
+					end else begin
+						FileSize := 2 + Data.Size + 1;
+						if Pack then begin
+							AssignFile (F, Temp + 'tempprog.bin');
+							Rewrite (F, 1);
+							B := (FileSize - 2) shr 8;
+							BlockWrite (F, B, 1);
+							B := (FileSize - 2);
+							BlockWrite (F, B, 1);
+							BlockWrite (F, Data.Memory^, Data.Size);
+							B := Tag;
+							BlockWrite (F, B, 1);
+							CloseFile (F);
+							MainConsole.Title := 'Compressor';
+							CompUpdate;
+							try
+								MainConsole.StartProcess (WithBackslash (TIGCCFolder) + PackLocation + 'Pack.exe', 'tempprog.bin tempprog.pck', WithoutBackslash (Temp));
+								WaitForMainConsole ('Compression');
+							except
+								ShowDefaultMessageBox ('Could not start compressor.', 'Error', mtProgramError);
+							end;
+							CompUpdate;
+							if not OperationCancelled then begin
+								if FileExists (Temp + 'tempprog.pck') then begin
+									InputStream := TMemoryStream.Create;
+									with InputStream do try
+										LoadFromFile (Temp + 'tempprog.pck');
+										OutputSize := GetTransferFileSize (Size, 'ppg', OutputBin);
+										if OutputSize > 0 then begin
+											OutputStream.Size := OutputSize;
+											ProduceTransferFile (OutputStream.Memory, Memory, Size, CalcDest, FolderName, PackVar, $F8, 'ppg', OutputBin);
+											MainFiles [CalcDest] := ChangeFileExt (ProjectFile, GetTransferFileExt (CalcDest, $F8, OutputBin));
+											OutputStream.SaveToFile (MainFiles [CalcDest]);
+											if LongWord (ProgSize) < OutputSize then
+												ProgSize := OutputSize;
+											OperationSuccessful := True;
+										end else
+											ShowDefaultMessageBox ('Compressed size of ' + IntToStr (Size) + ' bytes is too large, unexpectedly.', 'Error', mtProgramError);
+									finally
+										Free;
+									end;
+								end else
+									ShowDefaultMessageBox ('Compression failed. Please check the program size.', 'Error', mtProgramError);
+							end;
+							if FileExists (Temp + 'tempprog.bin') then
+								DeleteFile (Temp + 'tempprog.bin');
+							if FileExists (Temp + 'tempprog.pck') then
+								DeleteFile (Temp + 'tempprog.pck');
+						end else begin
+							OutputSize := GetTransferFileSize (Data.Size, VarExt, OutputBin);
+							if OutputSize > 0 then begin
+								OutputStream.Size := OutputSize;
+								ProduceTransferFile (OutputStream.Memory, Data.Memory, Data.Size, CalcDest, FolderName, VarName, Tag, VarExt, OutputBin);
+								MainFiles [CalcDest] := ChangeFileExt (ProjectFile, GetTransferFileExt (CalcDest, Tag, OutputBin));
+								OutputStream.SaveToFile (MainFiles [CalcDest]);
+								if LongWord (ProgSize) < OutputSize then
+									ProgSize := OutputSize;
+								OperationSuccessful := True;
+							end else
+								ShowDefaultMessageBox ('Variable size of ' + IntToStr (FileSize) + ' bytes is too large, unexpectedly.', 'Error', mtProgramError);
+						end;
+					end;
+				finally
+					OutputStream.Free;
+				end;
+				CompUpdate;
+			end else
+				ShowDefaultMessageBox ('Unexpected destination calculator mismatch.', 'Error', mtProgramError);
+		with LinkOutputFiles [CalcDest, frData] do
+			if Assigned (Data) and (not OSUpgrade) then begin
+				FileSize := 2 + Data.Size + 1;
+				OutputStream := TMemoryStream.Create;
+				try
+					OutputSize := GetTransferFileSize (Data.Size, VarExt, OutputBin);
+					if OutputSize > 0 then begin
+						OutputStream.Size := OutputSize;
+						ProduceTransferFile (OutputStream.Memory, Data.Memory, Data.Size, CalcDest, DataFolderName, DataVarName, Tag, VarExt, OutputBin);
+						OutputStream.SaveToFile (ChangeFileExt (ChangeFileExt (ProjectFile, '') + '-data', GetTransferFileExt (CalcDest, Tag, OutputBin)));
+						OperationSuccessful := True;
+					end else
+						ShowDefaultMessageBox ('Data variable size of ' + IntToStr (FileSize) + ' bytes is too large, unexpectedly.', 'Error', mtProgramError);
+				finally
+					OutputStream.Free;
+				end;
+				CompUpdate;
+			end;
+	end;
+	procedure CreatePackStarter(const ProjectFile, StarterFileName, FolderName, VarName, PackVar: string; CalcDests: TCalcDests);
+	var
+		CurCalcDest: TCalcDest;
+		CustomStarterObject: string;
+		ObjectFileNames: array [0..1] of PChar;
+		DataVarInfo: TLinkLibDataVarInfo;
+		OptimizeInfo: TLinkLibOptimizeInfo;
+	begin
+		CompUpdate;
+		OperationSuccessful := False;
+		for CurCalcDest := FirstCalcDest to LastCalcDest do begin
+			LinkOutputFiles[CurCalcDest,frMain].Data := nil;
+			LinkOutputFiles[CurCalcDest,frData].Data := nil;
+		end;
+		try
+			CustomStarterObject := Temp + StarterFileName;
+			if FileExists (WithBackslash (TIGCCFolder) + PStarterLocation + StarterFileName) then try
+				ParsePStarter (WithBackslash (TIGCCFolder) + PStarterLocation + StarterFileName, CustomStarterObject, PackVar);
+			except
+				ShowDefaultMessageBox ('Error processing starter object file.', 'Error', mtProgramError);
+				Exit;
+			end else begin
+				ShowDefaultMessageBox ('Cannot find starter object file.', 'Error', mtProgramError);
+				Exit;
+			end;
+			if not OperationCancelled then begin
+				ObjectFileNames [0] := PChar (CustomStarterObject);
+				ObjectFileNames [1] := nil;
+				FillChar (DataVarInfo, SizeOf (DataVarInfo), 0);
+				FillChar (OptimizeInfo, SizeOf (OptimizeInfo), 0);
+				if Assigned (LinkLibLinkFiles) then
+					OperationSuccessful := LinkLibLinkFiles (@ObjectFileNames, nil, LinkLibError, LinkLibGetOutputFile, nil, False, False, False, DataVarInfo, OptimizeInfo, False) = 0
+				else
+					ShowDefaultMessageBox ('Linker not loaded.', 'Error', mtProgramError);
+			end;
+			for CurCalcDest := cdTI89 to cdV200 do
+				if OperationSuccessful and (not OperationCancelled) and (CurCalcDest in CalcDests) then
+					HandleContents (ProjectFile, FolderName, VarName, '', '', False, '', CurCalcDest);
+		finally
+			for CurCalcDest := FirstCalcDest to LastCalcDest do begin
+				if Assigned (LinkOutputFiles[CurCalcDest,frMain].Data) then
+					LinkOutputFiles[CurCalcDest,frMain].Data.Free;
+				if Assigned (LinkOutputFiles[CurCalcDest,frData].Data) then
+					LinkOutputFiles[CurCalcDest,frData].Data.Free;
+				LinkOutputFiles[CurCalcDest,frMain].Data := nil;
+				LinkOutputFiles[CurCalcDest,frData].Data := nil;
+			end;
+			if FileExists (CustomStarterObject) then
+				DeleteFile (CustomStarterObject);
+		end;
+	end;
+var
+	FolderName,
+	VarName,
+	DataFolderName,
+	DataVarName: array [0..MaxNameLength] of Char;
+	I,
+	P: Integer;
+	S1,
+	DestFile: string;
+	Node: TTreeNode;
+	SourceFile: TSourceFile;
+	FileNameList: TStringList;
+	ObjectFileNames,
+	ArchiveFileNames: PPChar;
+	ObjectFileCount,
+	ArchiveFileCount: Integer;
+	DataVarInfo: TLinkLibDataVarInfo;
+	CalcDests: TCalcDests;
+	CurCalcDest: TCalcDest;
+	SR: TSearchRec;
+begin
+	UpdateErrorWindow;
+	OperationCancelled := False;
+	OperationSuccessful := False;
+	ProgSize := 0;
+	CalcDests := [];
+	OperationSuccessful := True;
+	with TopNode do begin
+		I := Pos ('\', Text);
+		if I > 0 then begin
+			StrPLCopy (VarName, LowerCase (Copy (Text, I + 1, MaxNameLength)), MaxNameLength);
+			StrPLCopy (FolderName, LowerCase (Copy (Text, 1, I - 1)), MaxNameLength);
+			CharLower (FolderName);
+		end else begin
+			StrPLCopy (VarName, LowerCase (Text), MaxNameLength);
+			FolderName := 'main';
+		end;
+		CharLower (VarName);
+	end;
+	with SourceFiles do
+		for I := 0 to Count - 1 do
+			with TSourceFile (Items [I]) do
+				if InProject and Compilable and (not FileExists (ChangeFileExt (FileName, '.o'))) then begin
+					OperationSuccessful := False;
+					FileNotCompiled (SourceName);
+				end;
+	I := Pos ('\', DataVar);
+	if I > 0 then begin
+		StrPLCopy (DataVarName, LowerCase (Copy (DataVar, I + 1, MaxNameLength)), MaxNameLength);
+		StrPLCopy (DataFolderName, LowerCase (Copy (DataVar, 1, I - 1)), MaxNameLength);
+		CharLower (DataFolderName);
+	end else begin
+		StrPLCopy (DataVarName, LowerCase (DataVar), MaxNameLength);
+		DataFolderName := FolderName;
+	end;
+	CharLower (DataVarName);
+	if OperationSuccessful then begin
+		OperationSuccessful := False;
+		if Assigned (LinkLibLinkFiles) and Assigned (LinkLibCreateArchive) then begin
+			CompStartFile;
+			CompSetMessage ('Linking Project ''' + WithoutExt (ExtractFileName (ProjectFile)) + '''');
+			if FileExists (ChangeFileExt (ProjectFile, '-titanium.89z')) then
+				DeleteFile (ChangeFileExt (ProjectFile, '-titanium.89z'));
+			ObjectFileCount := 0;
+			ObjectFileNames := nil;
+			ArchiveFileCount := 0;
+			ArchiveFileNames := nil;
+			FileNameList := TStringList.Create;
+			try
+				Node := TopNode;
+				while Assigned (Node) do begin
+					if Assigned (Node.Data) and (TObject (Node.Data) is TSourceFile) then begin
+						SourceFile := Node.Data;
+						if Assigned (SourceFile) then
+							with SourceFile do
+								if InProject then begin
+									if SourceFile is TArchiveSourceFile then begin
+										Inc (ArchiveFileCount);
+										ReallocMem (ArchiveFileNames, SizeOf (PChar) * (ArchiveFileCount + 1));
+										ArchiveFileNames [ArchiveFileCount - 1] := PChar (FileNameList.Strings [FileNameList.Add (FileName)]);
+										ArchiveFileNames [ArchiveFileCount - 0] := nil;
+									end else if Compilable or (SourceFile is TObjectSourceFile) then begin
+										Inc (ObjectFileCount);
+										ReallocMem (ObjectFileNames, SizeOf (PChar) * (ObjectFileCount + 1));
+										ObjectFileNames [ObjectFileCount - 1] := PChar (FileNameList.Strings [FileNameList.Add (ChangeFileExt (FileName, '.o'))]);
+										ObjectFileNames [ObjectFileCount] := nil;
+									end;
+								end;
+					end;
+					Node := Node.GetNext;
+				end;
+				if StdLib then begin
+					if ProjectTarget = ptFlashOS then
+						S1 := WithBackslash (TIGCCFolder) + StdLibLocation + 'flashos.a'
+					else if ProjectTarget = ptFargo then
+						S1 := WithBackslash (TIGCCFolder) + StdLibLocation + 'fargo.a'
+					else
+						S1 := WithBackslash (TIGCCFolder) + StdLibLocation + 'tigcc.a';
+					if FileExists (S1) then begin
+						Inc (ArchiveFileCount);
+						ReallocMem (ArchiveFileNames, SizeOf (PChar) * (ArchiveFileCount + 1));
+						ArchiveFileNames [ArchiveFileCount - 1] := PChar (FileNameList.Strings [FileNameList.Add (S1)]);
+						ArchiveFileNames [ArchiveFileCount] := nil;
+					end;
+				end;
+				if ProjectTarget = ptArchive then begin
+					DestFile := ChangeFileExt (ProjectFile, '.a');
+					OperationSuccessful := LinkLibCreateArchive (PChar (DestFile), ObjectFileNames, LinkLibError, True) = 0;
+					if OperationSuccessful then begin
+						if FindFirst (DestFile, faAnyFile, SR) = 0 then
+							ProgSize := SR.Size;
+						FindClose (SR);
+					end;
+				end else begin
+					for CurCalcDest := FirstCalcDest to LastCalcDest do begin
+						LinkOutputFiles[CurCalcDest,frMain].Data := nil;
+						LinkOutputFiles[CurCalcDest,frData].Data := nil;
+					end;
+					try
+						FillChar (DataVarInfo, SizeOf (DataVarInfo), 0);
+						FillChar (OptimizeInfo, SizeOf (OptimizeInfo), 0);
+						if UseDataVar then
+							with DataVarInfo do begin
+								VarName := PChar (LowerCase (MasterUnit.DataVar));
+								CreateCopy := MasterUnit.DataVarCopy;
+								CopyOnlyIfArchived := MasterUnit.DataVarCopyIfArchived;
+							end;
+						with OptimizeInfo do begin
+							RemoveUnused     := MasterUnit.RemoveUnusedSections;
+							OptimizeNOPs     := MasterUnit.OptimizeNOPs;
+							OptimizeReturns  := MasterUnit.OptimizeReturns;
+							OptimizeBranches := MasterUnit.OptimizeBranches;
+							OptimizeMoves    := MasterUnit.OptimizeMoves;
+							OptimizeTests    := MasterUnit.OptimizeTests;
+							OptimizeCalcs    := MasterUnit.OptimizeCalculations;
+							CutRanges        := MasterUnit.CutUnusedRanges;
+							ReorderSections  := MasterUnit.ReorderSections;
+							MergeConstants   := MasterUnit.MergeConstants;
+						end;
+						OperationSuccessful := LinkLibLinkFiles (ObjectFileNames, ArchiveFileNames, LinkLibError, LinkLibGetOutputFile, nil, False, ProjectTarget = ptFlashOS, ProjectTarget = ptFargo, DataVarInfo, OptimizeInfo, not InitBSS) = 0;
+						if OperationSuccessful and (not OperationCancelled) then begin
+							if Pack and (ssPack in SpecialSupport) then begin
+								CompStartFile;
+								CompSetMessage ('Compressing');
+							end;
+							for CurCalcDest := FirstCalcDest to LastCalcDest do
+								if Assigned (LinkOutputFiles[CurCalcDest,frMain].Data) then
+									if OperationSuccessful and (not OperationCancelled) then begin
+										Include (CalcDests, CurCalcDest);
+										HandleContents (ProjectFile, FolderName, VarName, DataFolderName, DataVarName, Pack and (ssPack in SpecialSupport) and (CurCalcDest <> cdTI92), PackVar, CurCalcDest);
+									end;
+						end;
+					finally
+						for CurCalcDest := FirstCalcDest to LastCalcDest do begin
+							if Assigned (LinkOutputFiles[CurCalcDest,frMain].Data) then
+								LinkOutputFiles[CurCalcDest,frMain].Data.Free;
+							if Assigned (LinkOutputFiles[CurCalcDest,frData].Data) then
+								LinkOutputFiles[CurCalcDest,frData].Data.Free;
+							LinkOutputFiles[CurCalcDest,frMain].Data := nil;
+							LinkOutputFiles[CurCalcDest,frData].Data := nil;
+						end;
+					end;
+				end;
+			except
+				if Assigned (ArchiveFileNames) then
+					FreeMem (ArchiveFileNames);
+				if Assigned (ObjectFileNames) then
+					FreeMem (ObjectFileNames);
+				FileNameList.Free;
+			end;
+			if OperationSuccessful and (not OperationCancelled) and Pack and (ssPack in SpecialSupport) then
+				CreatePackStarter (ProjectFile, 'PStarter.o', FolderName, VarName, PackVar, CalcDests - [cdTI92]);
+			if OperationSuccessful and (not OperationCancelled) and (Length (PostBuildProcessFile) > 0) then begin
+				CompStartFile;
+				CompSetMessage ('Calling User-Defined Program');
+				MainConsole.Title := 'User-Defined Program';
+				S1 := PostBuildProcessFile;
+				P := Pos ('($TI89FILE)', UpperCase (S1));
+				if P > 0 then begin
+					Delete (S1, P, Length ('($TI89FILE)'));
+					if cdTI89 in CalcDests then
+						Insert (MainFiles [cdTI89], S1, P);
+				end;
+				P := Pos ('($TI92PLUSFILE)', UpperCase (S1));
+				if P > 0 then begin
+					Delete (S1, P, Length ('($TI92PLUSFILE)'));
+					if cdTI92Plus in CalcDests then
+						Insert (MainFiles [cdTI92Plus], S1, P);
+				end;
+				P := Pos ('($V200FILE)', UpperCase (S1));
+				if P > 0 then begin
+					Delete (S1, P, Length ('($V200FILE)'));
+					if cdV200 in CalcDests then
+						Insert (MainFiles [cdV200], S1, P);
+				end;
+				P := Pos ('($TI92FILE)', UpperCase (S1));
+				if P > 0 then begin
+					Delete (S1, P, Length ('($TI92FILE)'));
+					if cdTI92 in CalcDests then
+						Insert (MainFiles [cdTI92], S1, P);
+				end;
+				try
+					MainConsole.StartProcess ('', S1, '');
+					WaitForMainConsole ('User-Defined');
+				except
+					ShowDefaultMessageBox ('Could not start the user-defined program.', 'Error', mtProgramError);
+					OperationSuccessful := False;
+				end;
+				UpdateProgramOutput;
+			end;
+			if not OperationSuccessful then
+				ProgSize := 0;
+			CompUpdate;
+			try
+				if FileExists (Temp + 'TEMPPROG.PCK') then
+					DeleteFile (Temp + 'TEMPPROG.PCK');
+				if OperationSuccessful and (not OperationCancelled) and DeleteAssemblyFiles and (not DebugInfo) then
+					with SourceFiles do
+						for I := 0 to Count - 1 do
+							with TSourceFile (Items [I]) do
+								if InProject and (Items [I] is TCSourceFile) then
+									if FileExists (ChangeFileExt (FileName, '.s')) then
+										DeleteFile (ChangeFileExt (FileName, '.s'));
+				if OperationSuccessful and (not OperationCancelled) and DeleteObjectFiles then
+					with SourceFiles do
+						for I := 0 to Count - 1 do
+							with TSourceFile (Items [I]) do
+								if InProject and Compilable then begin
+									Invalidate;
+									if FileExists (ChangeFileExt (FileName, '.o')) then
+										DeleteFile (ChangeFileExt (FileName, '.o'));
+								end;
+			except end;
+			UpdateErrorWindow;
+			ShowErrors;
+			CompUpdate;
+			if OperationSuccessful and (not OperationCancelled) then begin
+				Invalidated := False;
+				CompUpdate;
+			end;
+		end else
+			ShowDefaultMessageBox ('Linker not loaded.', 'Error', mtProgramError);
+	end;
+end;
+
+procedure TMainForm.FileOpenProject(Sender: TObject);
+begin
+	if OpenProjectDlg.Execute then begin
+		if LowerCase (ExtractFileExt (OpenProjectDlg.FileName)) = LowerCase (ProjectFileExt) then
+			FileOpen (ExpandFileName (OpenProjectDlg.FileName))
+		else
+			AddSourceFile (OpenProjectDlg.FileName, True);
+	end else
+		Abort;
+end;
+
+procedure TMainForm.FileSaveAll(Sender: TObject);
+begin
+	FileSave;
+end;
+
+procedure TMainForm.FileSaveProjectAs(Sender: TObject);
+begin
+	SaveProjectDlg.FileName := ProjectFile;
+	if SaveProjectDlg.Execute then
+		FileSaveAs (ExpandFileName (SaveProjectDlg.FileName))
+	else
+		Abort;
+end;
+
+procedure TMainForm.EditorKeyDown(Sender: TObject; var Key: Word;
+	Shift: TShiftState);
+var
+	I: Integer;
+	S: string;
+begin
+	if Key = vk_F1 then
+		if Sender is TMemoComponent then
+			with Sender as TMemoComponent do begin
+				S := '';
+				for I := Selection.RStart - 1 downto 1 do begin
+					if Text [I] in ['A'..'Z', 'a'..'z', '0'..'9', '_', '$', '#'] then
+						S := Text [I] + S
+					else
+						Break;
+				end;
+				for I := Selection.RStart to TextLength do begin
+					if Text [I] in ['A'..'Z', 'a'..'z', '0'..'9', '_', '$', '#'] then
+						S := S + Text [I]
+					else
+						Break;
+				end;
+				if S <> '' then begin
+					with SourceFiles do
+						for I := 0 to Count - 1 do
+							with Items [I] as TSourceFile do
+								if Assigned (ParentForm) then
+									ParentForm.WindowState := wsMinimized;
+					Application.ProcessMessages;
+					DocFile.KeywordLookup (S);
+				end;
+			end;
+end;
+
+procedure TMainForm.ProjectBuild(Sender: TObject);
+var
+	I: Integer;
+begin
+	if not Compiling then begin
+		if AutoSave then
+			FileSave
+		else
+			with SourceFiles do
+				for I := 0 to Count - 1 do
+					with Items [I] as TSourceFile do
+						if not InProject then
+							Save;
+		OperationSuccessful := False;
+		if ProjectFile = '' then
+			ShowDefaultMessageBox ('You need to save your project before you can create executable files.', 'Project not Saved', mtProgramError)
+		else begin
+			BeginCompilation;
+			RecompileFiles;
+			CompileProject;
+			Application.ProcessMessages;
+			if OperationSuccessful and not OperationCancelled then
+				MakeFile;
+			EndCompilation;
+			DisplayFolderMessage;
+		end;
+	end;
+end;
+
+procedure TMainForm.ProjectTreeKeyDown(Sender: TObject; var Key: Word;
+	Shift: TShiftState);
+begin
+	if (Key = vk_Delete) and not ProjectTree.IsEditing then
+		TreeItemRemove (Sender);
+end;
+
+procedure TMainForm.ProjectTreeMouseUp(Sender: TObject;
+	Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+begin
+	if Button = mbRight then
+		with ProjectTree do
+			if Assigned (Selected) then begin
+				if Assigned (Selected.Data) then begin
+					if TObject (Selected.Data) is TSourceFile then begin
+						with TSourceFile (Selected.Data) do begin
+							ActionTreeItemSave.Enabled := TSourceFile (Selected.Data) is TTextSourceFile;
+							ActionTreeItemSaveAs.Enabled := True;
+							ActionTreeItemCompile.Enabled := Compilable;
+						end;
+						with Mouse.CursorPos do
+							SourceFilePopup.Popup (X, Y);
+					end else if TObject (Selected.Data) is TFolder then begin
+						with Mouse.CursorPos do
+							FolderPopup.Popup (X, Y);
+					end;
+				end else if Assigned (Selected.Parent) then begin
+					with Mouse.CursorPos do
+						CategoryPopup.Popup (X, Y);
+				end;
+			end;
+end;
+
+procedure TMainForm.ProjectTreeEdited(Sender: TObject; Node: TTreeNode;
+	var S: String);
+var
+	I: Integer;
+	HasFolder,
+	NameConflict: Boolean;
+begin
+	if Node = TopNode then begin
+		if Length (S) <= 0 then
+			S := 'Project1'
+		else begin
+			HasFolder := False;
+			for I := Length (S) downto 1 do begin
+				if S [I] = '\' then begin
+					if HasFolder then
+						Delete (S, I, 1)
+					else
+						HasFolder := True;
+				end else if (not (IsCharAlphaNumeric (S [I]) or (S [I] in ['A'..'Z', 'a'..'z', '0'..'9']))) then
+					Delete (S, I, 1);
+			end;
+			if Length (S) <= 0 then
+				S := 'Project1'
+			else if not (IsCharAlpha (S [1]) or (S [1] in ['A'..'Z', 'a'..'z', '\'])) then
+				S := 'X' + S;
+			I := Pos ('\', S);
+			if I > 0 then begin
+				while I - 1 > MaxNameLength do begin
+					Delete (S, I - 1, 1);
+					Dec (I);
+				end;
+				while Length (S) - I > MaxNameLength do
+					Delete (S, Length (S), 1);
+				if I + 1 > Length (S) then
+					S := S + 'Project1'
+				else if I = 1 then
+					Delete (S, 1, 1)
+				else if not (IsCharAlpha (S [I + 1]) or (S [I + 1] in ['A'..'Z', 'a'..'z'])) then
+					Insert ('X', S, I + 1);
+			end else
+				S := Copy (S, 1, MaxNameLength);
+		end;
+		Modify;
+	end else begin
+		if Assigned (Node.Data) then begin
+			if (TObject (Node.Data) is TSourceFile) then begin
+				if S = '' then
+					S := 'File1';
+				NameConflict := False;
+				if TSourceFile(Node.Data).Compilable then
+					with SourceFiles do
+						for I := 0 to Count - 1 do
+							if Items [I] <> Node.Data then
+								with Items [I] as TSourceFile do
+									if Compilable and (LowerCase (SourceName) = LowerCase (S)) and (WithoutBackslash (FolderPath) = WithoutBackslash (TSourceFile(Node.Data).FolderPath)) then begin
+										NameConflict := True;
+										Break;
+									end;
+				if not NameConflict then try
+					if Assigned (Node.Data) then
+						TSourceFile(Node.Data).SourceName := S;
+					Modify;
+					Exit;
+				except end;
+				S := Node.Text;
+				ShowDefaultMessageBox ('The name you chose conflicts with that of another file.', 'Error', mtProgramError)
+			end else begin
+				S := StringReplace (S, ' ', '', [rfReplaceAll]);
+				if Length (S) <= 0 then
+					S := Node.Text;
+				RecompileFiles;
+			end;
+		end;
+	end;
+end;
+
+procedure TMainForm.SetProjectFile(const Value: string);
+var
+	S: string;
+	B: Boolean;
+begin
+	FProjectFile := Value;
+	MasterUnit.ProjectFileName := Value;
+	if Value = '' then
+		Caption := OriginalCaption
+	else
+		Caption := OriginalCaption + ' - ' + WithoutExt (ExtractFileName (Value));
+	Application.Title := Caption;
+	if TopNode.Text = 'Project1' then begin
+		B := Modified;
+		S := WithoutExt (ExtractFileName (Value));
+		ProjectTreeEdited (ProjectTree, TopNode, S);
+		TopNode.Text := S;
+		Modified := B;
+	end;
+	S := ExtractFilePath (Value);
+	OpenProjectDlg.InitialDir := WithoutBackslash (S);
+	OpenProjectDlg.FileName := Value;
+	SaveProjectDlg.InitialDir := WithoutBackslash (S);
+	SaveProjectDlg.FileName := Value;
+	AddFileDlg.InitialDir := S;
+end;
+
+function TMainForm.AddSourceFile(const FN: string; OpenOnly: Boolean = False; SourceFileClass: TSourceFileClass = nil; Folder: TFolder = nil): TSourceFile;
+var
+	F: TForm;
+	S: string;
+	O: TOpenFileStatusForm;
+begin
+	if Compiling and (not OpenOnly) then
+		Result := nil
+	else begin
+		Result := SourceFiles.FindFile (FN);
+		if Assigned (Result) and Result.InProject then begin
+			Result := nil;
+			ShowDefaultMessageBox ('The file ''' + ExtractFileName (FN) + ''' is already included in the project.', 'File Already Included', mtProgramError);
+		end else if OpenOnly and Assigned (Result) then begin
+			Result := nil;
+			ShowDefaultMessageBox ('The file ''' + ExtractFileName (FN) + ''' has already been opened.', 'File Already Opened', mtProgramError);
+		end else if (not OpenOnly) and (LowerCase (ExtractFileExt (FN)) = '.qll') and (Assigned (SourceFiles.FindFileOfTypeInProject (TQuillSourceFile))) then begin
+			Result := nil;
+			ShowDefaultMessageBox ('There may be only one Quill source file in each project.', 'Quill Error', mtProgramError);
+		end else begin
+			if not Assigned (Result) then begin
+				O := nil;
+				try
+					if not OpeningProjectNow then begin
+						O := TOpenFileStatusForm.Create (Self);
+						S := ExtractFileName (FN);
+						O.FileNameLabel.Caption := 'Opening File ''' + Copy (S, 1, LastPos ('.', S) - 1) + '''...';
+						O.Show;
+						O.Update;
+					end;
+					if not Assigned (SourceFileClass) then
+						SourceFileClass := TSourceFile.GetAppropriateClassFromExt (ExtractFileExt (FN));
+					Result := SourceFileClass.Create (SourceFiles);
+					Result.Folder := Folder;
+					Result.LoadFromFile (FN, True);
+					Result.OnError := AddError;
+				finally
+					if Assigned (O) then
+						O.Free;
+				end;
+				if OpenOnly and (not Assigned (Result.Editor)) then begin
+					Result.Free;
+					Result := nil;
+					ShowDefaultMessageBox ('The file ''' + ExtractFileName (FN) + ''' is not a valid file for opening.', 'Invalid File', mtProgramError);
+				end;
+			end;
+			if Assigned (Result) then
+				with Result do begin
+					ErrorList := Self.ErrorList;
+					if OpenOnly then begin
+						if not Assigned (ParentForm) then begin
+							ParentForm := TSourceFileForm.Create (nil);
+							with ParentForm as TSourceFileForm do begin
+								Enabled := False;
+								SourceFile := Result;
+								Show;
+							end;
+							if Assigned (Editor) then
+								with Editor do begin
+									Parent := ParentForm;
+									Align := alClient;
+									Show;
+									if Enabled then
+										SetFocus;
+								end;
+						end;
+					end else begin
+						if Assigned (ParentForm) then begin
+							F := ParentForm;
+							ParentForm := nil;
+							F.Free;
+						end;
+						TreeItem := CreateFileNode (TopNode.Item [ClassTreeIndex], Result);
+						with TreeItem do begin
+							ImageIndex    := ClassImageIndex;
+							SelectedIndex := ImageIndex;
+						end;
+					end;
+				end;
+		end;
+		if not OpeningProjectNow then
+			SortFiles;
+	end;
+end;
+
+procedure TMainForm.ProjectOptions(Sender: TObject);
+begin
+	with TProjectOptionsForm.Create (Self) do try
+		FlashOSRadioButton.Visible := ssFlashOS in SpecialSupport;
+		FargoRadioButton.Visible := ssFargo in SpecialSupport;
+		if ProjectTarget = ptArchive then
+			ArchiveRadioButton.Checked := True
+		else if (ProjectTarget = ptFlashOS) and (FlashOSRadioButton.Visible) then
+			FlashOSRadioButton.Checked := True
+		else if (ProjectTarget = ptFargo) and (FargoRadioButton.Visible) then
+			FargoRadioButton.Checked := True
+		else
+			ExecutableRadioButton.Checked := True;
+		DataVarCheckBox.Checked := UseDataVar;
+		DataVarEdit.Text := DataVar;
+		if DataVarCopy then begin
+			if DataVarCopyIfArchived then
+				DataVarCopyIfArchivedRadioButton.Checked := True
+			else
+				DataVarCopyAlwaysRadioButton.Checked := True;
+		end else
+			DataVarCopyNeverRadioButton.Checked := True;
+		PackCheckBox.Checked := Pack and (ssPack in SpecialSupport);
+		PackVarEdit.Text := PackVar;
+		GCCSwitchesEdit.Text := GCCSwitches;
+		AsSwitchesEdit.Text := AsSwitches;
+		AsmSwitchesEdit.Text := AsmSwitches;
+		DebugInfoCheckBox.Checked := DebugInfo;
+		OptimizeNOPsCheckBox.Checked := OptimizeNOPs;
+		OptimizeReturnsCheckBox.Checked := OptimizeReturns;
+		OptimizeBranchesCheckBox.Checked := OptimizeBranches;
+		OptimizeMovesCheckBox.Checked := OptimizeMoves;
+		OptimizeTestsCheckBox.Checked := OptimizeTests;
+		OptimizeCalculationsCheckBox.Checked := OptimizeCalculations;
+		RemoveUnusedSectionsCheckBox.Checked := RemoveUnusedSections;
+		CutUnusedRangesCheckBox.Checked := CutUnusedRanges;
+		ReorderSectionsCheckBox.Checked := ReorderSections;
+		MergeConstantsCheckBox.Checked := MergeConstants;
+		StdLibCheckBox.Checked := StdLib;
+		InitBSSCheckBox.Checked := InitBSS;
+		OutputBinCheckBox.Checked := OutputBin;
+		CommandLineEdit.Text := CommandLine;
+		ProcessFileEdit.Text := PostBuildProcessFile;
+		InitialLibOptions := PredefinedLibOptions;
+		if ShowModal = mrOK then begin
+			if ArchiveRadioButton.Checked then
+				ProjectTarget := ptArchive
+			else if FlashOSRadioButton.Checked then
+				ProjectTarget := ptFlashOS
+			else if FargoRadioButton.Checked then
+				ProjectTarget := ptFargo
+			else
+				ProjectTarget := ptRegular;
+			Pack := PackCheckBox.Checked;
+			PackVar := PackVarEdit.Text;
+			UseDataVar := DataVarCheckBox.Checked;
+			DataVar := DataVarEdit.Text;
+			DataVarCopy := False;
+			DataVarCopyIfArchived := False;
+			if DataVarCopyAlwaysRadioButton.Checked then
+				DataVarCopy := True
+			else if DataVarCopyIfArchivedRadioButton.Checked then begin
+				DataVarCopy := True;
+				DataVarCopyIfArchived := True;
+			end;
+			GCCSwitches := GCCSwitchesEdit.Text;
+			AsSwitches := AsSwitchesEdit.Text;
+			AsmSwitches := AsmSwitchesEdit.Text;
+			DebugInfo := DebugInfoCheckBox.Checked;
+			OptimizeNOPs := OptimizeNOPsCheckBox.Checked;
+			OptimizeReturns := OptimizeReturnsCheckBox.Checked;
+			OptimizeBranches := OptimizeBranchesCheckBox.Checked;
+			OptimizeMoves := OptimizeMovesCheckBox.Checked;
+			OptimizeTests := OptimizeTestsCheckBox.Checked;
+			OptimizeCalculations := OptimizeCalculationsCheckBox.Checked;
+			RemoveUnusedSections := RemoveUnusedSectionsCheckBox.Checked;
+			CutUnusedRanges := CutUnusedRangesCheckBox.Checked;
+			ReorderSections := ReorderSectionsCheckBox.Checked;
+			MergeConstants := MergeConstantsCheckBox.Checked;
+			StdLib := StdLibCheckBox.Checked;
+			InitBSS := InitBSSCheckBox.Checked;
+			OutputBin := OutputBinCheckBox.Checked;
+			CommandLine := CommandLineEdit.Text;
+			PostBuildProcessFile := ProcessFileEdit.Text;
+			if Assigned (ProgramOptionsForm) and Assigned (PredefinedLibOptions) then
+				with ProgramOptionsForm, PredefinedLibOptions do begin
+					CalcDests := [];
+					if TI89CheckBox.Checked then
+						Include (CalcDests, cdTI89);
+					if TI92PlusCheckBox.Checked then
+						Include (CalcDests, cdTI92Plus);
+					if V200CheckBox.Checked then
+						Include (CalcDests, cdV200);
+					OptimizeCalcConsts := OptimizeCalcConstsCheckBox.Checked;
+					if PreOsRadioButton.Checked then
+						KernelFormat := kfCompressedTables
+					else if DoorsRadioButton.Checked then
+						KernelFormat := kfStandard
+					else
+						KernelFormat := kfNone;
+					UseMinAMS := MinAMSCheckBox.Checked;
+					if Length (MinAMSEdit.Text) > 0 then
+						MinAMS := MinAMSEdit.Text;
+					UnofficialOSSupport := UnofficialOSSupportCheckBox.Checked;
+					if RelocKernelRadioButton.Checked then
+						RelocFormat := rfKernel
+					else if RelocCompressedRadioButton.Checked then
+						RelocFormat := rfCompressed
+					else
+						RelocFormat := rfAMS;
+					if ROMCallKernelRadioButton.Checked then
+						ROMCallFormat := rfKernel
+					else if ROMCallCompressedRadioButton.Checked then
+						ROMCallFormat := rfCompressed
+					else if ROMCallFLineRadioButton.Checked then
+						ROMCallFormat := rfFLine
+					else
+						ROMCallFormat := rfDirect;
+					if BSSKernelRadioButton.Checked then
+						BSSRefFormat := rfKernel
+					else if BSSCompressedRadioButton.Checked then
+						BSSRefFormat := rfCompressed
+					else
+						BSSRefFormat := rfNone;
+					if DataVarKernelRadioButton.Checked then
+						DataRefFormat := rfKernel
+					else if DataVarCompressedRadioButton.Checked then
+						DataRefFormat := rfCompressed
+					else
+						DataRefFormat := rfNone;
+					UseFLineJumps      := RelocFLineJumpsCheckBox.Checked;
+					Use4ByteFLineJumps := RelocFLineJumps4ByteCheckBox.Checked;
+					OptimizeROMCalls := ROMCallOptimizedCheckBox.Checked;
+					UseInternalFLineEmulator := InternalFLineEmulatorCheckBox.Checked;
+					UseReturnValue           := ReturnValueRadioButton.Checked;
+					EnableErrorReturn        := EnableErrorReturnCheckBox.Checked;
+					SaveScreen               := LCDSaveCheckBox.Checked;
+				end;
+			RecompileFiles;
+			if not DebugInfo then
+				ClearDebugInfo;
+			UpdateDebugSettings;
+			Modify;
+		end;
+	finally
+		Free;
+	end;
+end;
+
+procedure TMainForm.FilePreferences(Sender: TObject);
+var
+	I: Integer;
+begin
+	with TPreferencesForm.Create (Self) do try
+		StopCompilationBox.Checked := StopOnErrors;
+		JumpToErrorBox.Checked := JumpToError;
+		OpenFolderBox.Checked := OpenFolderMessage;
+		DeleteAssemblyFilesBox.Checked := DeleteAssemblyFiles;
+		DeleteObjectFilesBox.Checked := DeleteObjectFiles;
+{$IFDEF CanSplit}
+		SplitFilesCheckBox.Checked := SplitFiles;
+{$ENDIF}
+		AutoSaveCheckBox.Checked := AutoSave;
+		AutoNewsCheckBox.Checked := AutoNews;
+		DeleteErrorsCheckBox.Checked := DeleteErrors;
+		AllowImplicitCheckBox.Checked := not AssumeUndefined;
+		FlatButtonsCheckBox.Checked := MainToolbar.Flat;
+		MenuBitmapsCheckBox.Checked := Assigned (MainMenu.Images);
+		case TransferTarget of
+			ttVTI:
+				VTIBox.Checked := True;
+			ttCalc:
+				RealCalcBox.Checked := True;
+			else
+				NoneBox.Checked := True;
+		end;
+		VTIPathEdit.Text := VTIPath;
+		case LinkPort.PortType of
+			lpCOM: begin
+				case LinkPort.PortNumber of
+					1: PortCOM1Box.Checked := True;
+					2: PortCOM2Box.Checked := True;
+					3: PortCOM3Box.Checked := True;
+					4: PortCOM4Box.Checked := True;
+				end;
+			end;
+		end;
+		case LinkCable of
+			lcBlack: CableBlackBox.Checked := True;
+			lcGray:  CableGrayBox.Checked := True;
+		end;
+		AsmTabSizeEdit.Text := IntToStr (TabSizeAsm);
+		CTabSizeEdit.Text := IntToStr (TabSizeC);
+		BackColor := EditorColor;
+		ColorCheckBox.Checked := BackColor <> clWindow;
+		EditorFont.Assign (MasterUnit.EditorFont);
+		OnFlyCheckBox.Checked := EditorOnFly;
+		DragDropEditCheckBox.Checked := EditorDragDrop;
+		RemoveTrailingSpcCheckBox.Checked := EditorRemoveTrSp;
+		AutoBlockCheckBox.Checked := AutoBlocks;
+		SyntaxC.Assign (MasterUnit.SyntaxC);
+		SyntaxAsmGNU.Assign (MasterUnit.SyntaxAsmGNU);
+		if ssA68k in SpecialSupport then
+			SyntaxAsm.Assign (MasterUnit.SyntaxAsm);
+		if ssQuill in SpecialSupport then
+			SyntaxQuill.Assign (MasterUnit.SyntaxQuill);
+		if ShowModal = mrOK then begin
+			Screen.Cursor := crHourGlass;
+			StopOnErrors := StopCompilationBox.Checked;
+			JumpToError := JumpToErrorBox.Checked;
+			OpenFolderMessage := OpenFolderBox.Checked;
+			DeleteAssemblyFiles := DeleteAssemblyFilesBox.Checked;
+			DeleteObjectFiles := DeleteObjectFilesBox.Checked;
+{$IFDEF CanSplit}
+			SplitFiles := SplitFilesCheckBox.Checked;
+{$ENDIF}
+			AutoSave := AutoSaveCheckBox.Checked;
+			AutoNews := AutoNewsCheckBox.Checked;
+			DeleteErrors := DeleteErrorsCheckBox.Checked;
+			AssumeUndefined := not AllowImplicitCheckBox.Checked;
+			MainToolbar.Flat := FlatButtonsCheckBox.Checked;
+			if MainToolbar.Flat then
+				MainToolbar.Height := MainToolbar.ButtonHeight + 1
+			else
+				MainToolbar.Height := MainToolbar.ButtonHeight + 3;
+			if MenuBitmapsCheckBox.Checked then
+				MainMenu.Images := ToolbarImages
+			else
+				MainMenu.Images := nil;
+			if VTIBox.Checked then
+				TransferTarget := ttVTI
+			else if RealCalcBox.Checked then
+				TransferTarget := ttCalc
+			else
+				TransferTarget := ttNone;
+			VTIPath := VTIPathEdit.Text;
+			LinkPort.PortType := lpCOM;
+			if PortCOM1Box.Checked then
+				LinkPort.PortNumber := 1
+			else if PortCOM2Box.Checked then
+				LinkPort.PortNumber := 2
+			else if PortCOM3Box.Checked then
+				LinkPort.PortNumber := 3
+			else if PortCOM4Box.Checked then
+				LinkPort.PortNumber := 4;
+			if CableBlackBox.Checked then
+				LinkCable := lcBlack
+			else if CableGrayBox.Checked then
+				LinkCable := lcGray;
+			try
+				TabSizeC := StrToInt (CTabSizeEdit.Text);
+			except
+				TabSizeC := 2;
+			end;
+			try
+				TabSizeAsm := StrToInt (AsmTabSizeEdit.Text);
+			except
+				TabSizeAsm := 2;
+			end;
+			if ColorCheckBox.Checked then
+				EditorColor := BackColor
+			else
+				EditorColor := clWindow;
+			MasterUnit.EditorFont.Assign (EditorFont);
+			EditorOnFly := OnFlyCheckBox.Checked;
+			EditorDragDrop := DragDropEditCheckBox.Checked;
+			EditorRemoveTrSp := RemoveTrailingSpcCheckBox.Checked;
+			AutoBlocks := AutoBlockCheckBox.Checked;
+			with SourceFiles do
+				for I := 0 to Count - 1 do
+					if Items [I] is TTextSourceFile then
+						(Items [I] as TTextSourceFile).UpdateEditor;
+			if SyntaxTabClicked then begin
+				MasterUnit.SyntaxC.Assign (SyntaxC);
+				MasterUnit.SyntaxAsmGNU.Assign (SyntaxAsmGNU);
+				MasterUnit.SyntaxAsm.Assign (SyntaxAsm);
+				MasterUnit.SyntaxQuill.Assign (SyntaxQuill);
+				with SourceFiles do
+					for I := 0 to Count - 1 do
+						if Items [I] is TSourceTextSourceFile then
+							(Items [I] as TSourceTextSourceFile).UpdateSyntax;
+			end;
+			SavePreferences;
+			UpdateDebugSettings;
+			Screen.Cursor := crDefault;
+		end;
+	finally
+		Free;
+	end;
+end;
+
+procedure TMainForm.LoadPreferences;
+function LookBackForComponent(Stream: TMemoryStream): Integer;
+var
+	I: Integer;
+	P: PChar;
+begin
+	Result := 0;
+	with Stream do begin
+		P := Memory;
+		for I := Size - 3 downto 1 do
+			if (P [I] = 'T') and (P [I + 1] = 'P') and (P [I + 2] = 'F') then begin
+				Result := I;
+				Break;
+			end;
+	end;
+end;
+var
+	I,
+	Tmp: Integer;
+	L: TStringList;
+	Strm: TMemoryStream;
+	SyntaxCopy: TSyntaxColoringCopy;
+begin
+	with TRegistry.Create do try
+		if OpenKeyReadOnly (RegKey) then try
+			if ValueExists ('Open File') then
+				ProjectFile := ReadString ('Open File');
+			if ValueExists ('Recent Files') then begin
+				L := TStringList.Create;
+				try
+					L.CommaText := ReadString ('Recent Files');
+					for I := L.Count - 1 downto 0 do
+						AddToRecent (L.Strings [I]);
+				finally
+					L.Free;
+				end;
+			end;
+			if ValueExists ('Stop on Errors') then
+				StopOnErrors := ReadBool ('Stop on Errors');
+			if ValueExists ('Jump To First Error') then
+				JumpToError := ReadBool ('Jump To First Error');
+			if ValueExists ('Open Folder Message') then
+				OpenFolderMessage := ReadBool ('Open Folder Message');
+			if ValueExists ('Delete Assembly Files') then
+				DeleteAssemblyFiles := ReadBool ('Delete Assembly Files');
+			if ValueExists ('Delete Object Files') then
+				DeleteObjectFiles := ReadBool ('Delete Object Files');
+{$IFDEF CanSplit}
+			if ValueExists ('Split Files') then
+				SplitFiles := ReadBool ('Split Files');
+{$ENDIF}
+			if ValueExists ('AutoSave') then
+				AutoSave := ReadBool ('AutoSave');
+			if ValueExists ('AutoNews') then
+				AutoNews := ReadBool ('AutoNews');
+			if ValueExists ('Delete Errors') then
+				DeleteErrors := ReadBool ('Delete Errors');
+			if ValueExists ('Assume Undefined References') then
+				AssumeUndefined := ReadBool ('Assume Undefined References');
+			if ValueExists ('Flat Buttons') then
+				MainToolbar.Flat := ReadBool ('Flat Buttons');
+			if MainToolbar.Flat then
+				MainToolbar.Height := MainToolbar.ButtonHeight + 1
+			else
+				MainToolbar.Height := MainToolbar.ButtonHeight + 3;
+			if ValueExists ('Menu Bitmaps') then begin
+				if ReadBool ('Menu Bitmaps') then
+					MainMenu.Images := ToolbarImages
+				else
+					MainMenu.Images := nil;
+			end;
+			if ValueExists ('Transfer Target') then
+				TransferTarget := TTransferTarget (ReadInteger ('Transfer Target') + 1);
+			if ValueExists ('VTI Path') then
+				VTIPath := ReadString ('VTI Path');
+			if ValueExists ('Link Port') then
+				LinkPort.PortNumber := ReadInteger ('Link Port') and $FF;
+			if ValueExists ('Link Cable') then begin
+				if ReadInteger ('Link Cable') = 2 then
+					LinkCable := lcGray
+				else
+					LinkCable := lcBlack;
+			end;
+			if ValueExists ('ASM Tab Size') then
+				TabSizeAsm := ReadInteger ('ASM Tab Size');
+			if ValueExists ('C Tab Size') then
+				TabSizeC := ReadInteger ('C Tab Size');
+			if ValueExists ('Editor Background Color') then
+				EditorColor := ReadInteger ('Editor Background Color');
+			if ValueExists ('Editor Font') then
+				EditorFont.Name := ReadString ('Editor Font');
+			if ValueExists ('Editor Font Style Bold') then begin
+				EditorFont.Style := [];
+				if ReadBool ('Editor Font Style Bold') then
+					EditorFont.Style := EditorFont.Style + [fsBold];
+				if ReadBool ('Editor Font Style Italic') then
+					EditorFont.Style := EditorFont.Style + [fsItalic];
+				if ReadBool ('Editor Font Style Underline') then
+					EditorFont.Style := EditorFont.Style + [fsUnderline];
+				if ReadBool ('Editor Font Style StrikeOut') then
+					EditorFont.Style := EditorFont.Style + [fsStrikeOut];
+			end;
+			if ValueExists ('Editor Font Size') then
+				EditorFont.Size := ReadInteger ('Editor Font Size');
+			if ValueExists ('Editor Font Color') then
+				EditorFont.Color := ReadInteger ('Editor Font Color');
+			if ValueExists ('Editor Font Pitch') then
+				EditorFont.Pitch := TFontPitch (ReadInteger ('Editor Font Pitch'));
+			if ValueExists ('Editor Split On Fly') then
+				EditorOnFly := ReadBool ('Editor Split On Fly');
+			if ValueExists ('Editor Drag and Drop') then
+				EditorDragDrop := ReadBool ('Editor Drag and Drop');
+			if ValueExists ('Editor Remove Trailing Spaces') then
+				EditorRemoveTrSp := ReadBool ('Editor Remove Trailing Spaces');
+			if ValueExists ('AutoBlocks') then
+				AutoBlocks := ReadBool ('AutoBlocks');
+			if ValueExists ('Tree Width') then
+				ProjectTree.Width := ReadInteger ('Tree Width');
+			if ValueExists ('Error Window Height') then
+				ErrWinPanel.Height := ReadInteger ('Error Window Height');
+			if ValueExists ('Error List Message') then
+				ErrorList.Columns[0].Width := ReadInteger ('Error List Message');
+			if ValueExists ('Error List File') then
+				ErrorList.Columns[1].Width := ReadInteger ('Error List File');
+			if ValueExists ('Error List Function') then
+				ErrorList.Columns[2].Width := ReadInteger ('Error List Function');
+			if ValueExists ('Last News Update') then
+				LastNewsDate := ReadInteger ('Last News Update');
+			if ValueExists ('Proxy Name') then
+				ProxyName := ReadString ('Proxy Name');
+			if ValueExists ('Proxy Port') then
+				ProxyPort := ReadInteger ('Proxy Port');
+			Strm := TMemoryStream.Create;
+			if ValueExists ('Editor C Syntax Coloring') then try
+				SyntaxCopy := TSyntaxColoringCopy.Create (nil);
+				try
+					SyntaxCopy.Assign (SyntaxC);
+					Strm.SetSize (GetDataSize ('Editor C Syntax Coloring'));
+					if Strm.Size > 0 then begin
+						ReadBinaryData ('Editor C Syntax Coloring', Strm.Memory^, Strm.Size);
+						Strm.Position := LookBackForComponent (Strm);
+						Strm.ReadComponent (SyntaxCopy);
+						SyntaxC.Assign (SyntaxCopy);
+					end;
+				finally
+					SyntaxCopy.Free;
+				end;
+			except end;
+			if ValueExists ('Editor GNU ASM Syntax Coloring') then try
+				SyntaxCopy := TSyntaxColoringCopy.Create (nil);
+				try
+					SyntaxCopy.Assign (SyntaxAsmGNU);
+					Strm.SetSize (GetDataSize ('Editor GNU ASM Syntax Coloring'));
+					if Strm.Size > 0 then begin
+						ReadBinaryData ('Editor GNU ASM Syntax Coloring', Strm.Memory^, Strm.Size);
+						Strm.Position := LookBackForComponent (Strm);
+						Strm.ReadComponent (SyntaxCopy);
+						SyntaxAsmGNU.Assign (SyntaxCopy);
+					end;
+				finally
+					SyntaxCopy.Free;
+				end;
+			except end;
+			if (ssA68k in SpecialSupport) and ValueExists ('Editor ASM Syntax Coloring') then try
+				SyntaxCopy := TSyntaxColoringCopy.Create (nil);
+				try
+					SyntaxCopy.Assign (SyntaxAsm);
+					Strm.SetSize (GetDataSize ('Editor ASM Syntax Coloring'));
+					if Strm.Size > 0 then begin
+						ReadBinaryData ('Editor ASM Syntax Coloring', Strm.Memory^, Strm.Size);
+						Strm.Position := LookBackForComponent (Strm);
+						Strm.ReadComponent (SyntaxCopy);
+						SyntaxAsm.Assign (SyntaxCopy);
+					end;
+				finally
+					SyntaxCopy.Free;
+				end;
+			except end;
+			if (ssQuill in SpecialSupport) and ValueExists ('Editor Quill Syntax Coloring') then try
+				SyntaxCopy := TSyntaxColoringCopy.Create (nil);
+				try
+					SyntaxCopy.Assign (SyntaxQuill);
+					Strm.SetSize (GetDataSize ('Editor Quill Syntax Coloring'));
+					if Strm.Size > 0 then begin
+						ReadBinaryData ('Editor Quill Syntax Coloring', Strm.Memory^, Strm.Size);
+						Strm.Position := LookBackForComponent (Strm);
+						Strm.ReadComponent (SyntaxCopy);
+						SyntaxQuill.Assign (SyntaxCopy);
+					end;
+				finally
+					SyntaxCopy.Free;
+				end;
+			except end;
+			Strm.Free;
+			if ValueExists ('Tools Count') then begin
+				Tmp := ReadInteger ('Tools Count');
+				ToolsList.Clear;
+				for I := 1 to Tmp do
+					if OpenKeyReadOnly (RegKey + '\Tool ' + IntToStr (I)) then try
+						ToolsLine.Visible := True;
+						AddTool (ReadString ('Title'), ReadString ('Command Line'), ReadString ('Working Directory'), TWindowState (ReadInteger ('Window State')));
+					except end;
+			end;
+		except end;
+	finally
+		Free;
+		SplitterMoved (Self);
+	end;
+	with SourceFiles do
+		for I := 0 to Count - 1 do begin
+			if Items [I] is TTextSourceFile then
+				(Items [I] as TTextSourceFile).UpdateEditor;
+			if Items [I] is TSourceTextSourceFile then
+				(Items [I] as TSourceTextSourceFile).UpdateSyntax;
+		end;
+	UpdateDebugSettings;
+end;
+
+procedure TMainForm.SavePreferences;
+var
+	I: Integer;
+	Strm: TMemoryStream;
+	SyntaxCopy: TSyntaxColoringCopy;
+begin
+	with TRegistry.Create do try
+		if OpenKey (RegKey, True) then try
+			WriteString ('Open File', ProjectFile);
+			WriteString ('Recent Files', RecentFiles.CommaText);
+			WriteBool ('Stop on Errors', StopOnErrors);
+			WriteBool ('Jump To First Error', JumpToError);
+			WriteBool ('Open Folder Message', OpenFolderMessage);
+			WriteBool ('Delete Assembly Files', DeleteAssemblyFiles);
+			WriteBool ('Delete Object Files', DeleteObjectFiles);
+{$IFDEF CanSplit}
+			WriteBool ('Split Files', SplitFiles);
+{$ENDIF}
+			WriteBool ('AutoSave', AutoSave);
+			WriteBool ('AutoNews', AutoNews);
+			WriteBool ('Delete Errors', DeleteErrors);
+			WriteBool ('Assume Undefined References', AssumeUndefined);
+			WriteBool ('Flat Buttons', MainToolbar.Flat);
+			WriteBool ('Menu Bitmaps', Assigned (MainMenu.Images));
+			WriteInteger ('Transfer Target', Integer (TransferTarget) - 1);
+			WriteString ('VTI Path', VTIPath);
+			WriteInteger ('Link Port', LinkPort.PortNumber);
+			case LinkCable of
+				lcBlack: WriteInteger ('Link Cable', 1);
+				lcGray:  WriteInteger ('Link Cable', 2);
+			end;
+			WriteInteger ('ASM Tab Size', TabSizeAsm);
+			WriteInteger ('C Tab Size', TabSizeC);
+			WriteInteger ('Editor Background Color', EditorColor);
+			WriteString ('Editor Font', EditorFont.Name);
+			WriteBool ('Editor Font Style Bold', fsBold in EditorFont.Style);
+			WriteBool ('Editor Font Style Italic', fsItalic in EditorFont.Style);
+			WriteBool ('Editor Font Style Underline', fsUnderline in EditorFont.Style);
+			WriteBool ('Editor Font Style StrikeOut', fsStrikeOut in EditorFont.Style);
+			WriteInteger ('Editor Font Size', EditorFont.Size);
+			WriteInteger ('Editor Font Color', EditorFont.Color);
+			WriteInteger ('Editor Font Pitch', Integer (EditorFont.Pitch));
+			WriteBool ('Editor Split On Fly', EditorOnFly);
+			WriteBool ('Editor Drag and Drop', EditorDragDrop);
+			WriteBool ('Editor Remove Trailing Spaces', EditorRemoveTrSp);
+			WriteBool ('AutoBlocks', AutoBlocks);
+			WriteInteger ('Tree Width', ProjectTree.Width);
+			WriteInteger ('Error Window Height', ErrWinPanel.Height);
+			WriteInteger ('Error List Message', ErrorList.Columns[0].Width);
+			WriteInteger ('Error List File', ErrorList.Columns[1].Width);
+			WriteInteger ('Error List Function', ErrorList.Columns[2].Width);
+			WriteInteger ('Last News Update', LastNewsDate);
+			WriteString ('Proxy Name', ProxyName);
+			WriteInteger ('Proxy Port', ProxyPort);
+			Strm := TMemoryStream.Create;
+			try
+				SyntaxCopy := TSyntaxColoringCopy.Create (nil);
+				try
+					SyntaxCopy.Assign (SyntaxC);
+					Strm.WriteComponent (SyntaxCopy);
+					WriteBinaryData ('Editor C Syntax Coloring', Strm.Memory^, Strm.Size);
+				finally
+					SyntaxCopy.Free;
+				end;
+				Strm.Clear;
+				SyntaxCopy := TSyntaxColoringCopy.Create (nil);
+				try
+					SyntaxCopy.Assign (SyntaxAsmGNU);
+					Strm.WriteComponent (SyntaxCopy);
+					WriteBinaryData ('Editor GNU ASM Syntax Coloring', Strm.Memory^, Strm.Size);
+				finally
+					SyntaxCopy.Free;
+				end;
+				if ssA68k in SpecialSupport then begin
+					Strm.Clear;
+					SyntaxCopy := TSyntaxColoringCopy.Create (nil);
+					try
+						SyntaxCopy.Assign (SyntaxAsm);
+						Strm.WriteComponent (SyntaxCopy);
+						WriteBinaryData ('Editor ASM Syntax Coloring', Strm.Memory^, Strm.Size);
+					finally
+						SyntaxCopy.Free;
+					end;
+				end;
+				if ssQuill in SpecialSupport then begin
+					Strm.Clear;
+					SyntaxCopy := TSyntaxColoringCopy.Create (nil);
+					try
+						SyntaxCopy.Assign (SyntaxQuill);
+						Strm.WriteComponent (SyntaxCopy);
+						WriteBinaryData ('Editor Quill Syntax Coloring', Strm.Memory^, Strm.Size);
+					finally
+						SyntaxCopy.Free;
+					end;
+				end;
+			finally
+				Strm.Free;
+			end;
+			WriteInteger ('Tools Count', ToolsList.Count);
+			with ToolsList do
+				for I := 0 to Count - 1 do
+					with TToolsListItem (Items [I]) do
+						if OpenKey (RegKey + '\Tool ' + IntToStr (I + 1), True) then try
+							WriteString ('Title', Title);
+							WriteString ('Command Line', CommandLine);
+							WriteString ('Working Directory', WorkingDir);
+							WriteInteger ('Window State', Integer (WindowState));
+						except end;
+		except end;
+	finally
+		Free;
+	end;
+end;
+
+procedure TMainForm.CompileProject;
+var
+	I: Integer;
+	StopIt: Boolean;
+begin
+	OperationSuccessful := False;
+	OperationCancelled := False;
+	StopIt := True;
+	with SourceFiles do
+		for I := 0 to Count - 1 do
+			with Items [I] as TSourceFile do
+				if Compilable or (Items [I] is TObjectSourceFile) then begin
+					StopIt := False;
+					Break;
+				end;
+	if not StopIt then begin
+		OperationSuccessful := True;
+		CopyHeaders;
+		with SourceFiles do
+			for I := 0 to Count - 1 do
+				if (OperationSuccessful or not StopOnErrors) and not OperationCancelled then
+					with Items [I] as TSourceFile do
+						if Compilable and Invalidated then begin
+							Compile;
+							if not OperationSuccessful then
+								StopIt := True;
+							Application.ProcessMessages;
+						end;
+		DeleteHeaders;
+		if StopIt then
+			OperationSuccessful := False;
+	end else
+		ShowDefaultMessageBox ('There are no files to compile in the current project.', 'Error', mtProgramError);
+end;
+
+function TMainForm.GetNewFileName(const FolderPath, Ext: string): string;
+var
+	I: Integer;
+begin
+	if ProjectFile = '' then
+		Result := 'C:\New File'
+	else
+		Result := WithBackslash (ExtractFilePath (ProjectFile) + FolderPath) + 'New File';
+	if FileExists (Result + Ext) or Assigned (SourceFiles.FindFileWithoutExt (Result)) then begin
+		I := 2;
+		while FileExists (Result + ' ' + IntToStr (I) + Ext) or Assigned (SourceFiles.FindFileWithoutExt (Result + ' ' + IntToStr (I))) do
+			Inc (I);
+		Result := Result + ' ' + IntToStr (I);
+	end;
+	Result := Result + Ext;
+end;
+
+procedure TMainForm.FileNewHeaderFile(Sender: TObject);
+var
+	O: THeaderSourceFile;
+begin
+	if not Compiling then begin
+		O := THeaderSourceFile.Create (SourceFiles);
+		with O do begin
+			Folder := GetSelectedFolder (THeaderSourceFile);
+			FileName := GetNewFileName (FolderPath, '.h');
+			OnError := AddError;
+			TreeItem := CreateFileNode (TopNode.Item [ClassTreeIndex], O);
+			with TreeItem do begin
+				ImageIndex    := ClassImageIndex;
+				SelectedIndex := ImageIndex;
+			end;
+			ErrorList := Self.ErrorList;
+			if Assigned (TextEditor) then
+				with TextEditor do begin
+					Hide;
+					Parent := EditorPanel;
+					Align := alClient;
+					OnEnter := EditorEnter;
+					OnExit := EditorExit;
+					OnKeyDown := EditorKeyDown;
+					OnChange := EditorChange;
+					OnSelectionChange := EditorChange;
+					PopupMenu := EditorPopup;
+				end;
+			if (Sender = ActionFileNewGNUAsmHeaderFile) or ((Sender is TMenuItem) and (TMenuItem(Sender).Action = ActionFileNewGNUAsmHeaderFile)) then
+				Content := '| Header File'#13#10'| Created ' + DateToStr (Now) + '; ' + TimeToStr (Now) + #13#10
+			else if (Sender = ActionFileNewA68kAsmHeaderFile) or ((Sender is TMenuItem) and (TMenuItem(Sender).Action = ActionFileNewA68kAsmHeaderFile)) then
+				Content := '; Header File'#13#10'; Created ' + DateToStr (Now) + '; ' + TimeToStr (Now) + #13#10
+			else
+				Content := '// Header File'#13#10'// Created ' + DateToStr (Now) + '; ' + TimeToStr (Now) + #13#10;
+			UpdateSyntax;
+			if Assigned (TextEditor) then
+				TextEditor.ClearUndo;
+			Modified := False;
+			Invalidate;
+			SelectNode (TreeItem);
+			TreeItem.EditText;
+		end;
+	end;
+end;
+
+procedure TMainForm.FileNewCSourceFile(Sender: TObject);
+const
+	CodeStr = '// Place your code here.';
+var
+	O: TCSourceFile;
+	I,
+	P: Integer;
+	NewContent: string;
+	FirstFile: Boolean;
+begin
+	if not Compiling then begin
+		FirstFile := not Assigned (SourceFiles.FindFileOfTypeInProject (TCSourceFile));
+		O := TCSourceFile.Create (SourceFiles);
+		with O do begin
+			Folder := GetSelectedFolder (TCSourceFile);
+			FileName := GetNewFileName (FolderPath, '.c');
+			OnError := AddError;
+			TreeItem := CreateFileNode (TopNode.Item [ClassTreeIndex], O);
+			with TreeItem do begin
+				ImageIndex    := ClassImageIndex;
+				SelectedIndex := ImageIndex;
+			end;
+			ErrorList := Self.ErrorList;
+			if Assigned (TextEditor) then
+				with TextEditor do begin
+					Hide;
+					Parent := EditorPanel;
+					Align := alClient;
+					OnEnter := EditorEnter;
+					OnExit := EditorExit;
+					OnKeyDown := EditorKeyDown;
+					OnChange := EditorChange;
+					OnSelectionChange := EditorChange;
+					PopupMenu := EditorPopup;
+				end;
+			NewContent := '// C Source File'#13#10'// Created ' + DateToStr (Now) + '; ' + TimeToStr (Now) + #13#10;
+			case ProjectTarget of
+				ptRegular: begin
+					if FirstFile then begin
+						NewContent := NewContent + #13#10
+							+ '// Delete or comment out the items you do not need.'#13#10
+							+ '#define COMMENT_STRING         "Place your comment here."'#13#10
+							+ '#define COMMENT_PROGRAM_NAME   "Place your program name here."'#13#10
+							+ '#define COMMENT_VERSION_STRING "Place your version string here."'#13#10
+							+ '#define COMMENT_VERSION_NUMBER 0,0,0,0 /* major, minor, revision, subrevision */'#13#10
+							+ '#define COMMENT_BW_ICON \'#13#10
+							+ #9'{0b0000000000000000, \'#13#10;
+						for I := 1 to 14 do
+							NewContent := NewContent
+								+ #9' 0b0000000000000000, \'#13#10;
+						NewContent := NewContent
+							+ #9' 0b0000000000000000}'#13#10
+							+ '#define COMMENT_GRAY_ICON \'#13#10
+							+ #9'{0b0000000000000000, \'#13#10;
+						for I := 1 to 14 do
+							NewContent := NewContent
+								+ #9' 0b0000000000000000, \'#13#10;
+						NewContent := NewContent
+							+ #9' 0b0000000000000000}, \'#13#10
+							+ #9'{0b0000000000000000, \'#13#10;
+						for I := 1 to 14 do
+							NewContent := NewContent
+								+ #9' 0b0000000000000000, \'#13#10;
+						NewContent := NewContent
+							+ #9' 0b0000000000000000}'#13#10;
+					end;
+					NewContent := NewContent + #13#10'#include <tigcclib.h>'#13#10;
+				end;
+				ptArchive:
+					NewContent := NewContent + #13#10'#define _GENERIC_ARCHIVE'#13#10'#include <tigcclib.h>'#13#10;
+			end;
+			if FirstFile and (not (ProjectTarget in [ptFlashOS, ptArchive])) then
+				NewContent := NewContent + #13#10'// Main Function'#13#10'void _main(void)'#13#10
+					+ '{'#13#10
+					+ #9 + CodeStr + #13#10
+					+ '}'#13#10;
+			if Assigned (TextEditor) then
+				TextEditor.AllowUndo := False;
+			Content := NewContent;
+			if Assigned (TextEditor) then begin
+				TextEditor.AllowUndo := True;
+				P := Pos (CodeStr, TextEditor.Text);
+				if P > 0 then
+					with TextEditor.Selection do begin
+						RStart := P;
+						RLength := Length (CodeStr);
+					end;
+			end;
+			Modified := False;
+			Invalidate;
+			SelectNode (TreeItem);
+			TreeItem.EditText;
+		end;
+	end;
+end;
+
+procedure TMainForm.FileNewGNUAssemblerSourceFile(Sender: TObject);
+var
+	O: TGNUAsmSourceFile;
+begin
+	if not Compiling then begin
+		O := TGNUAsmSourceFile.Create (SourceFiles);
+		with O do begin
+			Folder := GetSelectedFolder (TGNUAsmSourceFile);
+			FileName := GetNewFileName (FolderPath, '.s');
+			OnError := AddError;
+			TreeItem := CreateFileNode (TopNode.Item [ClassTreeIndex], O);
+			with TreeItem do begin
+				ImageIndex    := ClassImageIndex;
+				SelectedIndex := ImageIndex;
+			end;
+			ErrorList := Self.ErrorList;
+			if Assigned (TextEditor) then
+				with TextEditor do begin
+					Hide;
+					Parent := EditorPanel;
+					Align := alClient;
+					OnEnter := EditorEnter;
+					OnExit := EditorExit;
+					OnKeyDown := EditorKeyDown;
+					OnChange := EditorChange;
+					OnSelectionChange := EditorChange;
+					PopupMenu := EditorPopup;
+				end;
+			Content := '| Assembly Source File'#13#10'| Created ' + DateToStr (Now) + '; ' + TimeToStr (Now) + #13#10;
+			if Assigned (TextEditor) then
+				TextEditor.ClearUndo;
+			Modified := False;
+			Invalidate;
+			SelectNode (TreeItem);
+			TreeItem.EditText;
+		end;
+	end;
+end;
+
+procedure TMainForm.FileNewAssemblerSourceFile(Sender: TObject);
+var
+	O: TAsmSourceFile;
+begin
+	if not Compiling then begin
+		O := TAsmSourceFile.Create (SourceFiles);
+		with O do begin
+			Folder := GetSelectedFolder (TAsmSourceFile);
+			FileName := GetNewFileName (FolderPath, '.asm');
+			OnError := AddError;
+			TreeItem := CreateFileNode (TopNode.Item [ClassTreeIndex], O);
+			with TreeItem do begin
+				ImageIndex    := ClassImageIndex;
+				SelectedIndex := ImageIndex;
+			end;
+			ErrorList := Self.ErrorList;
+			if Assigned (TextEditor) then
+				with TextEditor do begin
+					Hide;
+					Parent := EditorPanel;
+					Align := alClient;
+					OnEnter := EditorEnter;
+					OnExit := EditorExit;
+					OnKeyDown := EditorKeyDown;
+					OnChange := EditorChange;
+					OnSelectionChange := EditorChange;
+					PopupMenu := EditorPopup;
+				end;
+			Content := '; Assembly Source File'#13#10'; Created ' + DateToStr (Now) + ', ' + TimeToStr (Now) + #13#10;
+			if Assigned (TextEditor) then
+				TextEditor.ClearUndo;
+			Modified := False;
+			Invalidate;
+			SelectNode (TreeItem);
+			TreeItem.EditText;
+		end;
+	end;
+end;
+
+procedure TMainForm.FileNewQuillSourceFile(Sender: TObject);
+var
+	O: TQuillSourceFile;
+begin
+	if not Compiling then begin
+		if Assigned (SourceFiles.FindFileOfTypeInProject (TQuillSourceFile)) then
+			ShowDefaultMessageBox ('There may be only one Quill source file in each project.', 'Quill Error', mtProgramError)
+		else begin
+			O := TQuillSourceFile.Create (SourceFiles);
+			with O do begin
+				Folder := GetSelectedFolder (TQuillSourceFile);
+				FileName := GetNewFileName (FolderPath, '.qll');
+				OnError := AddError;
+				TreeItem := CreateFileNode (TopNode.Item [ClassTreeIndex], O);
+				with TreeItem do begin
+					ImageIndex    := ClassImageIndex;
+					SelectedIndex := ImageIndex;
+				end;
+				ErrorList := Self.ErrorList;
+				if Assigned (TextEditor) then
+					with TextEditor do begin
+						Hide;
+						Parent := EditorPanel;
+						Align := alClient;
+						OnEnter := EditorEnter;
+						OnExit := EditorExit;
+						OnKeyDown := EditorKeyDown;
+						OnChange := EditorChange;
+						OnSelectionChange := EditorChange;
+						PopupMenu := EditorPopup;
+					end;
+				if FileExists (WithBackslash (TIGCCFolder) + QuillIncludeLocation + 'Template.qll') then
+					LoadFromFile (WithBackslash (TIGCCFolder) + QuillIncludeLocation + 'Template.qll')
+				else if FileExists (WithBackslash (TIGCCFolder) + CIncludeLocation + 'Template.qll') then
+					LoadFromFile (WithBackslash (TIGCCFolder) + CIncludeLocation + 'Template.qll')
+				else if FileExists (WithBackslash (TIGCCFolder) + GCCLocation + 'Template.qll') then
+					LoadFromFile (WithBackslash (TIGCCFolder) + GCCLocation + 'Template.qll');
+				Content := '// Quill Source File'#13#10'// Created ' + DateToStr (Now) + '; ' + TimeToStr (Now) + #13#10#13#10 + Content;
+				if Assigned (TextEditor) then
+					TextEditor.ClearUndo;
+				Modified := False;
+				Invalidate;
+				SelectNode (TreeItem);
+				TreeItem.EditText;
+			end;
+		end;
+	end;
+end;
+
+procedure TMainForm.FileNewTextFile(Sender: TObject);
+var
+	O: TNormalTextSourceFile;
+begin
+	O := TNormalTextSourceFile.Create (SourceFiles);
+	with O do begin
+		Folder := GetSelectedFolder (TTextSourceFile);
+		FileName := GetNewFileName (FolderPath, '.txt');
+		OnError := AddError;
+		TreeItem := CreateFileNode (TopNode.Item [ClassTreeIndex], O);
+		with TreeItem do begin
+			ImageIndex    := ClassImageIndex;
+			SelectedIndex := ImageIndex;
+		end;
+		ErrorList := Self.ErrorList;
+		if Assigned (TextEditor) then
+			with TextEditor do begin
+				Hide;
+				Parent := EditorPanel;
+				Align := alClient;
+				OnEnter := EditorEnter;
+				OnExit := EditorExit;
+				OnKeyDown := EditorKeyDown;
+				OnChange := EditorChange;
+				OnSelectionChange := EditorChange;
+				PopupMenu := EditorPopup;
+			end;
+		if Assigned (TextEditor) then
+			TextEditor.ClearUndo;
+		Modified := False;
+		SelectNode (TreeItem);
+		TreeItem.EditText;
+	end;
+end;
+
+procedure TMainForm.TreeItemSaveAs(Sender: TObject);
+var
+	Node: TTreeNode;
+begin
+	Node := ProjectTree.Selected;
+	if Assigned (Node) and Assigned (Node.Data) and (TObject (Node.Data) is TSourceFile) then begin
+		TSourceFile(Node.Data).SaveAs;
+		Modify;
+		UpdateStatusBar;
+	end;
+end;
+
+procedure TMainForm.BeginCompilation;
+var
+	I: Integer;
+begin
+	ClearErrors;
+	with SourceFiles do
+		for I := 0 to Count - 1 do
+			with Items [I] as TSourceFile do
+				if not InProject then begin
+					RecompileFiles;
+					Break;
+				end;
+	OperationCancelled := False;
+	OperationSuccessful := False;
+end;
+
+procedure TMainForm.EndCompilation;
+begin
+	CompStop;
+	Application.Restore;
+	UpdateErrorWindow;
+	ShowErrors;
+end;
+
+procedure TMainForm.HelpAbout(Sender: TObject);
+begin
+	with TAboutForm.Create (Self) do try
+		ShowModal;
+	finally
+		Free;
+	end;
+end;
+
+procedure TMainForm.DisplayHint(Sender: TObject);
+begin
+	with StatusBar.Panels do begin
+		BeginUpdate;
+		with Items [0] do begin
+			if Application.Hint = '' then
+				Width := 0
+			else
+				Width := 1000000;
+			Text := Application.Hint;
+		end;
+		EndUpdate;
+	end;
+end;
+
+procedure TMainForm.ShowHideErrors(Sender: TObject);
+begin
+	with ActionProjectShowErrors do begin
+		if Checked then
+			HideErrors
+		else
+			ShowErrors;
+	end;
+end;
+
+procedure TMainForm.UpdateEditButtons;
+var
+	TextSel: Boolean;
+	Editor: TMemoComponent;
+begin
+	Editor := CurrentEditor;
+	if Assigned (Editor) then begin
+		TextSel := (Editor.SelLength > 0) and (ActiveControl = Editor);
+		ActionEditDelete.Enabled := TextSel;
+		ActionEditCut.Enabled := TextSel;
+		ActionEditCopy.Enabled := TextSel;
+		ActionEditUndo.Enabled := (ActiveControl = Editor) and Editor.CanUndo;
+		ActionEditRedo.Enabled := (ActiveControl = Editor) and Editor.CanRedo;
+	end;
+end;
+
+procedure TMainForm.RecompileFiles;
+var
+	I: Integer;
+begin
+	with SourceFiles do
+		for I := 0 to Count - 1 do
+			with Items [I] as TSourceFile do
+				if Items [I] is THeaderSourceFile then
+					Invalidated := False
+				else if Compilable then
+					Invalidate;
+end;
+
+procedure TMainForm.FindString(Sender: TObject; AllFiles: Boolean);
+var
+	P: Integer;
+	S,
+	T: string;
+	Valid: Boolean;
+	FPos: Integer;
+	Editor: TMemoComponent;
+	NewSelection: TTreeNode;
+	FirstFile: Boolean;
+begin
+	NewSelection := ProjectTree.Selected;
+	if not Assigned (NewSelection) then
+		NewSelection := TopNode;
+	Valid := False;
+	FirstFile := True;
+	repeat
+		if Assigned (NewSelection.Data) and (TObject (NewSelection.Data) is TSourceFile) then
+			if TSourceFile (NewSelection.Data) is TTextSourceFile then begin
+				Editor := TTextSourceFile(NewSelection.Data).TextEditor;
+				if Assigned (Editor) then begin
+					with Sender as TFindDialog do begin
+						if (frFindNext in Options) and FirstFile then
+							P := Editor.Selection.REnd
+						else
+							if frDown in Options then
+								P := 0
+							else
+								P := Length (Editor.Text);
+						repeat
+							if frDown in Options then
+								T := Copy (Editor.Text, P + 1, Length (Editor.Text))
+							else
+								T := Copy (Editor.Text, 1, P - 1);
+							if frMatchCase in Options then
+								S := FindText
+							else begin
+								S := UpperCase (FindText);
+								T := UpperCase (T);
+							end;
+							if frDown in Options then
+								FPos := Pos (S, T)
+							else
+								FPos := LastPos (S, T);
+							if FPos > 0 then begin
+								Valid := True;
+								if frWholeWord in Options then begin
+									if ((FPos > 1) and (T <> '') and (T [FPos - 1] in ['A'..'Z', 'a'..'z', '0'..'9', '_', '$'])) then
+										Valid := False;
+									if ((FPos + Length (S) < Length (T)) and (T <> '') and (T [FPos + Length (S)] in ['A'..'Z', 'a'..'z', '0'..'9', '_', '$'])) then
+										Valid := False;
+								end;
+								if not (frDown in Options) then
+									P := 0;
+								if not Valid then
+									Inc (P, FPos);
+							end;
+						until Valid or (FPos <= 0);
+						if Valid then begin
+							SelectNode (NewSelection);
+							with Editor do begin
+								with Selection do begin
+									DoChanging;
+									RStart := P + FPos;
+									RLength := Length (S);
+									DoChange;
+									ScrollInView (2);
+								end;
+							end;
+						end;
+					end;
+				end;
+			end;
+		if AllFiles and (not Valid) then begin
+			if frDown in (Sender as TFindDialog).Options then begin
+				NewSelection := NewSelection.GetNext;
+				if not Assigned (NewSelection) then
+					NewSelection := TopNode;
+			end else begin
+				NewSelection := NewSelection.GetPrev;
+				if not Assigned (NewSelection) then begin
+					NewSelection := TopNode;
+					while NewSelection.Count > 0 do
+						NewSelection := NewSelection.Item [NewSelection.Count - 1];
+				end;
+			end;
+			FirstFile := False;
+		end;
+	until (not AllFiles) or Valid or (NewSelection = ProjectTree.Selected);
+	if not Valid then
+		Abort;
+end;
+
+procedure TMainForm.ReplaceDlgReplace(Sender: TObject);
+var
+	Editor: TMemoComponent;
+begin
+	Editor := CurrentEditor;
+	if Assigned (Editor) then
+		with Sender as TReplaceDialog do
+			if (frReplace in Options) or (frReplaceAll in Options) then
+				repeat
+					if UpperCase (Editor.Selection.Text) = UpperCase (FindText) then
+						Editor.Selection.Text := ReplaceText;
+					Options := Options + [frFindNext];
+					FindString (Sender, False);
+				until not (frReplaceAll in Options);
+end;
+
+procedure TMainForm.FindText(Sender: TObject);
+begin
+	try
+		if Assigned (CurrentEditor) then
+			if CurrentEditor.Selection.RLength > 0 then
+				FindDlg.FindText := CurrentEditor.Selection.Text;
+		FindDlg.Execute;
+	except end;
+end;
+
+procedure TMainForm.ReplaceText(Sender: TObject);
+begin
+	try
+		if Assigned (CurrentEditor) then
+			if CurrentEditor.Selection.RLength > 0 then begin
+				ReplaceDlg.FindText := CurrentEditor.Selection.Text;
+				ReplaceDlg.ReplaceText := ReplaceDlg.FindText;
+			end;
+		ReplaceDlg.Execute;
+	except end;
+end;
+
+procedure TMainForm.FindOpenFile(Sender: TObject);
+var
+	I: Integer;
+	S: string;
+	QuotesInLine: Boolean;
+	SelectedNode: TTreeNode;
+	SourceFile: TSourceFile;
+	Editor: TMemoComponent;
+begin
+	Editor := CurrentEditor;
+	if Assigned (Editor) then begin
+		QuotesInLine := Pos ('"', Editor.Lines [Editor.Selection.StartRowCol.Row - 1]) > 0;
+		S := '';
+		for I := Editor.Selection.RStart - 1 downto 1 do begin
+			if (not QuotesInLine) and (Editor.Text [I] = ' ') then
+				Break;
+			if Editor.Text [I] in [' ', 'A'..'Z', 'a'..'z', '0'..'9', '_', '-', '.', '\', ':'] then
+				S := Editor.Text [I] + S
+			else
+				Break;
+		end;
+		for I := Editor.Selection.RStart to Length (Editor.Text) do begin
+			if (not QuotesInLine) and (Editor.Text [I] = ' ') then
+				Break;
+			if Editor.Text [I] in [' ', 'A'..'Z', 'a'..'z', '0'..'9', '_', '-', '.', '\', ':'] then
+				S := S + Editor.Text [I]
+			else
+				Break;
+		end;
+		S := Trim (S);
+		if Length (S) > 0 then begin
+			SourceFile := SourceFiles.FindFileNameOnly (S);
+			if Assigned (SourceFile) then
+				SourceFile.Edit
+			else begin
+				SelectedNode := ProjectTree.Selected;
+				if Assigned (SelectedNode) and (TObject (SelectedNode.Data) is TSourceFile) then
+					SourceFile := TSourceFile (SelectedNode.Data);
+				if FileExists (ExpandFileName (S)) then
+					AddSourceFile (ExpandFileName (S), True)
+				else if Assigned (SourceFile) and (SourceFile is TGNUAsmSourceFile) and FileExists (WithBackslash (TIGCCFolder) + GASIncludeLocation + S) then
+					AddSourceFile (WithBackslash (TIGCCFolder) + GASIncludeLocation + S, True)
+				else if Assigned (SourceFile) and (SourceFile is TAsmSourceFile) and FileExists (WithBackslash (TIGCCFolder) + ASMIncludeLocation + S) then
+					AddSourceFile (WithBackslash (TIGCCFolder) + ASMIncludeLocation + S, True)
+				else if FileExists (WithBackslash (TIGCCFolder) + CIncludeLocation + S) then
+					AddSourceFile (WithBackslash (TIGCCFolder) + CIncludeLocation + S, True)
+				else
+					ShowDefaultMessageBox ('File ''' + S + ''' not found.', 'Search Failed', mtProgramError);
+			end;
+		end;
+	end;
+end;
+
+procedure TMainForm.FindDlgFind(Sender: TObject);
+begin
+	try
+		FindString (Sender, True);
+	except
+		ShowDefaultMessageBox ('Text ''' + (Sender as TFindDialog).FindText + ''' not found.', 'Search Failed', mtProgramError);
+	end;
+end;
+
+procedure TMainForm.ActionsExecute(Action: TBasicAction;
+	var Handled: Boolean);
+begin
+	Application.ProcessMessages;
+	Handled := False;
+end;
+
+procedure TMainForm.ProjectTreeEnter(Sender: TObject);
+begin
+	ActionEditDelete.Enabled := Assigned (ProjectTree.Selected) and Assigned (ProjectTree.Selected.Data);
+end;
+
+procedure TMainForm.ProjectTreeExit(Sender: TObject);
+begin
+	ActionEditDelete.Enabled := False;
+end;
+
+procedure TMainForm.ProjectTreeChanging(Sender: TObject; Node: TTreeNode;
+	var AllowChange: Boolean);
+begin
+	if not NoHideEditor then begin
+		if Assigned (EditorToHide) then
+			EditorToHide.Hide;
+		if (not Closing) and Assigned (PreviousNode) and Assigned (PreviousNode.Data) and (TObject (PreviousNode.Data) is TSourceFile) then
+			EditorToHide := TSourceFile(PreviousNode.Data).Editor
+		else
+			EditorToHide := NoEditor;
+	end;
+end;
+
+procedure TMainForm.EditorChange(Sender: TObject);
+begin
+	if ActiveControl = Sender then
+		UpdateEditButtons;
+	UpdateStatusBar;
+end;
+
+procedure TMainForm.FilePrint(Sender: TObject);
+var
+	Node: TTreeNode;
+	Cp: Integer;
+begin
+	Node := ProjectTree.Selected;
+	if Assigned (Node) and Assigned (Node.Data) and (TObject (Node.Data) is TSourceFile) and (Printer.Printers.Count > 0) then try
+		PrintDlg.PrintRange := prAllPages;
+		PrintDlg.MaxPage := TSourceFile(Node.Data).CountPages;
+		PrintDlg.ToPage := PrintDlg.MaxPage;
+		if Assigned (CurrentEditor) then begin
+			if CurrentEditor.Selection.RLength > 0 then
+				PrintDlg.Options := PrintDlg.Options + [poSelection]
+			else
+				PrintDlg.Options := PrintDlg.Options - [poSelection];
+		end;
+		if Assigned (Sender) then begin
+			if not PrintDlg.Execute then
+				Abort;
+			Cp := PrintDlg.Copies;
+			if Cp < 1 then
+				Cp := 1;
+		end else
+			Cp := 1;
+		TSourceFile(Node.Data).Print (Cp, PrintDlg.PrintRange, PrintDlg.FromPage, PrintDlg.ToPage);
+	except
+		Abort;
+	end;
+end;
+
+procedure TMainForm.FilePrintQuickly(Sender: TObject);
+begin
+	FilePrint (nil);
+end;
+
+procedure TMainForm.TreeItemRename(Sender: TObject);
+begin
+	if Assigned (ProjectTree.Selected) then
+		ProjectTree.Selected.EditText;
+end;
+
+procedure TMainForm.HelpContents(Sender: TObject);
+begin
+	try
+		DocFile.DisplayContentsTab;
+	except
+		ShowDefaultMessageBox ('Error opening documentation.', 'Error', mtProgramError);
+	end;
+end;
+
+procedure TMainForm.HelpIndex(Sender: TObject);
+begin
+	try
+		DocFile.DisplayIndexTab;
+	except
+		ShowDefaultMessageBox ('Error opening documentation.', 'Error', mtProgramError);
+	end;
+end;
+
+procedure TMainForm.HelpSearch(Sender: TObject);
+begin
+	try
+		DocFile.DisplaySearchTab;
+	except
+		ShowDefaultMessageBox ('Error opening documentation.', 'Error', mtProgramError);
+	end;
+end;
+
+procedure TMainForm.SplitterMoved(Sender: TObject);
+begin
+	StatusBar.Panels[1].Width := ProjectTree.Width;
+	Update;
+end;
+
+procedure TMainForm.UpdateStatusBar;
+var
+	S: string;
+	I: Integer;
+	Total: Integer;
+	Cell: TTextCell;
+	Node,
+	ClassNode: TTreeNode;
+begin
+	with StatusBar.Panels do begin
+		Total := 0;
+		Node := TopNode;
+		while Assigned (Node) do begin
+			if Assigned (Node.Data) and (TObject (Node.Data) is TSourceFile) then
+				Inc (Total);
+			Node := Node.GetNext;
+		end;
+		S := IntToStr (Total) + ' File';
+		if Total <> 1 then
+			S := S + 's';
+		S := S + ' Total';
+		if Assigned (ProjectTree.Selected) then begin
+			ClassNode := GetSourceTypeFolder (ProjectTree.Selected);
+			if Assigned (ClassNode) then begin
+				Total := 0;
+				Node := ClassNode;
+				while Assigned (Node) and (Node <> ClassNode.GetNextSibling) do begin
+					if Assigned (Node.Data) and (TObject (Node.Data) is TSourceFile) then
+						Inc (Total);
+					Node := Node.GetNext;
+				end;
+				S := S + ', ' + IntToStr (Total) + ' in Category';
+			end;
+		end;
+		if Items[1].Text <> S then
+			Items[1].Text := S;
+		if Assigned (CurrentEditor) then begin
+			with CurrentEditor do begin
+				if Enabled then begin
+					if Selection.RLength > 0 then begin
+						I := Selection.RLength + Selection.StartRowCol.Row - Selection.EndRowCol.Row;
+						if Selection.EndRowCol.Col > LineLength [Selection.EndRowCol.Row] then
+							Dec (I);
+						S := IntToStr (I);
+						if Items[3].Text <> S then
+							Items[3].Text := S;
+						if Items[4].Text <> '' then
+							Items[4].Text := '';
+						if Items[3].Width <> 60 then
+							Items[3].Width := 60;
+						if Items[4].Width <> 0 then
+							Items[4].Width := 0;
+					end else begin
+						Cell := Selection.StartRowCol;
+						S := IntToStr (Cell.Row);
+						if Items[3].Text <> S then
+							Items[3].Text := S;
+						S := IntToStr (Cell.Col);
+						if Items[4].Text <> S then
+							Items[4].Text := S;
+						if Items[3].Width <> 30 then
+							Items[3].Width := 30;
+						if Items[4].Width <> 30 then
+							Items[4].Width := 30;
+					end;
+					I := TextLength - LineCount + 1;
+					S := IntToStr (I) + ' Character';
+					if I <> 1 then
+						S := S + 's';
+					if Items[11].Text <> S then
+						Items[11].Text := S;
+					if Items[10].Width <> 1 then
+						Items[10].Width := 1;
+					if Items[11].Width <> 93 then
+						Items[11].Width := 93;
+					if Items[12].Width <> 1 then
+						Items[12].Width := 1;
+				end;
+			end;
+		end else begin
+			if Items[3].Text <> '' then
+				Items[3].Text := '';
+			if Items[4].Text <> '' then
+				Items[4].Text := '';
+			if Items[11].Text <> '' then
+				Items[11].Text := '';
+			if Items[3].Width <> 0 then
+				Items[3].Width := 0;
+			if Items[4].Width <> 0 then
+				Items[4].Width := 0;
+			if Items[10].Width <> 0 then
+				Items[10].Width := 0;
+			if Items[11].Width <> 0 then
+				Items[11].Width := 0;
+			if Items[12].Width <> 0 then
+				Items[12].Width := 0;
+		end;
+		Node := ProjectTree.Selected;
+		S := '';
+		if Assigned (Node) then begin
+			if Assigned (Node.Data) and (TObject (Node.Data) is TSourceFile) then begin
+				with TSourceFile (Node.Data) do
+					if (ProjectFile = '') and (ExtractFilePath (FileName) = 'C:\') then
+						S := LogicalFileName
+					else
+						S := FileName;
+			end else
+				if Node = TopNode then
+					S := ProjectFile;
+		end;
+		if Items[13].Text <> S then
+			Items[13].Text := S;
+	end;
+	Update;
+end;
+
+procedure TMainForm.ProjectTreeMouseDown(Sender: TObject;
+	Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+begin
+	if Button = mbRight then
+		SelectNode (ProjectTree.GetNodeAt (X, Y));
+end;
+
+procedure TMainForm.SetModified(const Value: Boolean);
+begin
+	FModified := Value;
+	UpdateStatusBar;
+	if Value then
+		Invalidated := True;
+end;
+
+procedure TMainForm.ToolBarManagerBandMove(Sender: TObject;
+	Control: TControl; var ARect: TRect);
+begin
+	Update;
+end;
+
+procedure TMainForm.ProjectTreeDragOver(Sender, Source: TObject; X,
+	Y: Integer; State: TDragState; var Accept: Boolean);
+var
+	S,
+	D: TTreeNode;
+	SameType,
+	FolderDest: Boolean;
+begin
+	Accept := False;
+	with ProjectTree do begin
+		S := Selected;
+		if Assigned (S) and Assigned (S.Data) then begin
+			D := GetNodeAt (X, Y);
+			if Assigned (D) and (D <> TopNode) and (D <> S) and (D <> S.Parent) then begin
+				SameType := (GetSourceTypeFolder (S) = GetSourceTypeFolder (D));
+				FolderDest := (not Assigned (D.Data)) or (TObject (D.Data) is TFolder);
+				if TObject (S.Data) is TSourceFile then
+					Accept := SameType or FolderDest
+				else
+					Accept := SameType and FolderDest;
+			end;
+		end;
+	end;
+end;
+
+procedure TMainForm.ProjectTreeDragDrop(Sender, Source: TObject; X,
+	Y: Integer);
+var
+	S,
+	D: TTreeNode;
+	FN: string;
+	F: TSourceFile;
+	Folder: TFolder;
+begin
+	with ProjectTree do begin
+		S := Selected;
+		if Assigned (S) and Assigned (S.Data) then begin
+			D := GetNodeAt (X, Y);
+			if Assigned (D) and (D <> TopNode) then begin
+				// Handle moving within one type.
+				if GetSourceTypeFolder (S) = GetSourceTypeFolder (D) then begin
+					// Handle moving to a different folder.
+					if (not Assigned (D.Data)) or (TObject (D.Data) is TFolder) then begin
+						S.MoveTo (D, naAddChild);
+						if TObject (S.Data) is TSourceFile then
+							with TSourceFile (S.Data) do begin
+								Folder := D.Data;
+								Invalidate;
+							end;
+					// Handle moving within one folder.
+					end else begin
+						if (S <> D) and (S.Parent = D.Parent) then begin
+							if D.Index > S.Index then begin
+								if D.GetNextSibling <> nil then
+									S.MoveTo (D.GetNextSibling, naInsert)
+								else
+									S.MoveTo (D, naAdd);
+							end else
+								S.MoveTo (D, naInsert);
+						end;
+					end;
+					Modify;
+				// Handle moving to a different type.
+				end else begin
+					if S.Parent <> D then begin
+						if TObject (S.Data) is TSourceFile then begin
+							with TSourceFile (S.Data) do begin
+								if FileExists (FileName) then
+									WarnIfModified
+								else
+                  Save;
+								FN := FileName;
+							end;
+							S.Delete;
+							Folder := nil;
+							if Assigned (D.Data) and (TObject (D.Data) is TFolder) then
+								Folder := D.Data;
+							D := GetSourceTypeFolder (D);
+							if Assigned (D) then begin
+								F := AddSourceFile (FN, False, TSourceFile.GetAppropriateClassFromTreeIndex (D.Index), Folder);
+								if Assigned (F) and Assigned (F.TreeItem) then
+									SelectNode (F.TreeItem);
+							end;
+							RecompileFiles;
+							Modify;
+						end;
+					end;
+				end;
+			end;
+			if Assigned (CurrentEditor) then
+				CurrentEditor.Refresh;
+			SortFiles;
+		end;
+	end;
+end;
+
+procedure TMainForm.ErrorListClick(Sender: TObject);
+begin
+	if Enabled and Assigned (ErrorList.Selected) and (ErrorList.SelCount = 1) then
+		TFoundError(ErrorList.Selected.Data).GoToPosition;
+end;
+
+function TMainForm.GetCurrentEditor: TMemoComponent;
+var
+	Node: TTreeNode;
+begin
+	Node := ProjectTree.Selected;
+	if Assigned (Node) and Assigned (Node.Data) and (TObject (Node.Data) is TTextSourceFile) then
+		Result := TTextSourceFile(Node.Data).TextEditor
+	else
+		Result := nil;
+end;
+
+procedure TMainForm.DeleteError(Sender: TObject);
+var
+	I: Integer;
+begin
+	if DeleteErrors then begin
+		with ErrorList.Items do
+			for I := Count - 1 downto 0 do
+				if Assigned (Item[I].Data) then
+					with TFoundError (Item[I].Data) do
+						if Range = Sender then
+							Item[I].Delete;
+		UpdateErrorWindow;
+	end;
+end;
+
+procedure TMainForm.UpdateFuncs;
+var
+	Node: TTreeNode;
+begin
+	Node := ProjectTree.Selected;
+	if Assigned (Node) and Assigned (Node.Data) and (TObject (Node.Data) is TSourceTextSourceFile) then
+		with TSourceTextSourceFile (Node.Data) do
+			Funcs := GetFunctions
+	else
+		SetLength (Funcs, 0);
+end;
+
+procedure TMainForm.FunctionPopupPopup(Sender: TObject);
+var
+	I,
+	P: Integer;
+	M: TMenuItem;
+begin
+	with (Sender as TPopupMenu).Items do begin
+		for I := Count - 1 downto 0 do
+			Remove (Items [I]);
+		UpdateFuncs;
+		for I := Low (Funcs) to High (Funcs) do begin
+			M := TMenuItem.Create (Self);
+			with M do begin
+				Tag := I;
+				Caption := Funcs[I].Name;
+				OnClick := FindFunctionFromPopup;
+			end;
+			P := Pos ('main', Funcs[I].Name);
+			if (P <> 0) and (P = Length (Funcs[I].Name) - Length ('main') + 1) then
+				Insert (0, M)
+			else
+				Add (M);
+		end;
+		if Count <= 0 then
+			Add (NoFunctionsItem);
+	end;
+end;
+
+procedure TMainForm.FindFunctions(Sender: TObject);
+var
+	I: Integer;
+	Editor: TMemoComponent;
+begin
+	UpdateFuncs;
+	with TFunctionsForm.Create (Self) do try
+		Funcs := @Self.Funcs;
+		with FuncList.Items do begin
+			BeginUpdate;
+			Clear;
+			for I := Low (Self.Funcs) to High (Self.Funcs) do
+				AddObject (Self.Funcs[I].Name, TObject (I));
+			EndUpdate;
+		end;
+		FuncListClick (FuncList);
+		case ShowModal of
+			mrYes: begin
+				Editor := CurrentEditor;
+				if Assigned (Editor) then begin
+					Editor.Selection.NoSelAtPos (Editor.CellToCharIdx (TextCell (Self.Funcs[Integer(FuncList.Items.Objects[FuncList.ItemIndex])].PrototypeLine, 1)));
+					Editor.Selection.ScrollInView (5);
+				end;
+			end;
+			mrNo: begin
+				Editor := CurrentEditor;
+				if Assigned (Editor) then begin
+					Editor.Selection.NoSelAtPos (Editor.CellToCharIdx (TextCell (Self.Funcs[Integer(FuncList.Items.Objects[FuncList.ItemIndex])].ImplementationLine, 1)));
+					Editor.Selection.ScrollInView (5);
+				end;
+			end;
+		end;
+		with FuncList.Items do begin
+			BeginUpdate;
+			for I := Count - 1 downto 0 do begin
+				Objects [I] := nil;
+				Delete (I);
+			end;
+			EndUpdate;
+		end;
+	finally
+		Free;
+	end;
+end;
+
+procedure TMainForm.FindFunctionFromPopup(Sender: TObject);
+var
+	L: Integer;
+	Editor: TMemoComponent;
+begin
+	if Sender is TMenuItem then
+		with Sender as TMenuItem do begin
+			if Funcs[Tag].ImplementationLine > 0 then
+				L := Funcs[Tag].ImplementationLine
+			else
+				L := Funcs[Tag].PrototypeLine;
+			if L > 0 then begin
+				Editor := CurrentEditor;
+				if Assigned (Editor) then begin
+					Editor.Selection.NoSelAtPos (Editor.CellToCharIdx (TextCell (L, 1)));
+					Editor.Selection.ScrollInView (5);
+					if Editor.Visible and Editor.Enabled then
+						ActiveControl := Editor;
+				end;
+			end;
+		end;
+end;
+
+procedure TMainForm.IncreaseIndent(Sender: TObject);
+var
+	Editor: TMemoComponent;
+begin
+	Editor := CurrentEditor;
+	if Assigned (Editor) then
+		Editor.ChangeIndent (1);
+end;
+
+procedure TMainForm.DecreaseIndent(Sender: TObject);
+var
+	Editor: TMemoComponent;
+begin
+	Editor := CurrentEditor;
+	if Assigned (Editor) then
+		Editor.ChangeIndent (-1);
+end;
+
+procedure TMainForm.SortFiles;
+var
+	CurFileIndex: Integer;
+procedure DoSortFiles(Node: TTreeNode);
+var
+	I: Integer;
+begin
+	with Node do begin
+		if Assigned (Data) and (TObject (Data) is TSourceFile) then begin
+			with TSourceFile (Data) do
+				if Index > CurFileIndex then
+					Index := CurFileIndex;
+			Inc (CurFileIndex);
+		end;
+		for I := 0 to Count - 1 do
+			DoSortFiles (Item [I]);
+	end;
+end;
+var
+	I: Integer;
+begin
+	CurFileIndex := 0;
+	{	This is supposed to be: DoSortFiles (TopNode);
+		However, header files are dependent on the other
+		files and therefore have to be put after all the
+		others. }
+	with TopNode do begin
+		for I := 0 to Count - 1 do
+			if I <> THeaderSourceFile.GetClassTreeIndex then
+				DoSortFiles (Item [I]);
+		if Count > THeaderSourceFile.GetClassTreeIndex then
+			DoSortFiles (Item [THeaderSourceFile.GetClassTreeIndex]);
+	end;
+end;
+
+procedure TMainForm.AppCompSetMessage(const Msg: string);
+begin
+	with StatusBar do
+		Panels.Items[6].Text := Msg + '...';
+	if not Compiling then begin
+		Compiling := True;
+		CompUpdate;
+		UpdateDebugSettings;
+		with StatusBar.Panels do begin
+			Items[5].Width := 5;
+			Items[6].Width := 180;
+			Items[7].Width := 100;
+			Items[8].Width := 100;
+			Items[9].Width := 1000000;
+		end;
+	end;
+end;
+
+procedure TMainForm.AppCompStartFile;
+var
+	I: Integer;
+begin
+	Application.Hint := '';
+	CompFinishAndStop := False;
+	CompStopNow := False;
+	CompFileStartTime := Now;
+	CompLastTime := 0;
+	if not Compiling then begin
+		CompStartTime := CompFileStartTime;
+		ToolBarNewButton.Enabled := False;
+		MenuFileNew.Enabled := False;
+		ActionFileOpen.Enabled := False;
+		ActionFileExit.Enabled := False;
+		ActionProjectAddFiles.Enabled := False;
+		ActionProjectCompile.Visible := False;
+		ActionProjectMake.Visible := False;
+		ActionProjectBuild.Visible := False;
+		ActionProjectStopCompilation.Enabled := True;
+		ActionProjectForceQuitCompiler.Enabled := True;
+		ActionProjectStopCompilation.Visible := True;
+		ActionProjectForceQuitCompiler.Visible := True;
+		with RecentFiles do
+			for I := 0 to Count - 1 do
+				with TRecentFileMenuItem (Objects [I]) do begin
+					FileMenuItem.Enabled := False;
+					PopupMenuItem.Enabled := False;
+				end;
+	end;
+end;
+
+procedure TMainForm.AppCompStop;
+var
+	I: Integer;
+begin
+	if Compiling then begin
+		Compiling := False;
+		ActionProjectStopCompilation.Visible := False;
+		ActionProjectForceQuitCompiler.Visible := False;
+		ToolBarNewButton.Enabled := True;
+		MenuFileNew.Enabled := True;
+		ActionFileOpen.Enabled := True;
+		ActionFileExit.Enabled := True;
+		ActionProjectAddFiles.Enabled := True;
+		ActionProjectCompile.Visible := True;
+		ActionProjectMake.Visible := True;
+		ActionProjectBuild.Visible := True;
+		with RecentFiles do
+			for I := 0 to Count - 1 do
+				with TRecentFileMenuItem (Objects [I]) do begin
+					FileMenuItem.Enabled := True;
+					PopupMenuItem.Enabled := True;
+				end;
+		UpdateDebugSettings;
+		with StatusBar.Panels do begin
+			Items[5].Width := 0;
+			Items[6].Width := 0;
+			Items[7].Width := 0;
+			Items[8].Width := 0;
+			Items[9].Width := 0;
+		end;
+	end;
+end;
+
+procedure TMainForm.AppCompUpdate;
+const
+	SecondsPerDay = 24 * 60 * 60;
+function CustomTimeToStr(ConvTime: TDateTime): string;
+var
+	Seconds: Integer;
+	MinStr,
+	SecStr: string;
+begin
+	Seconds := Trunc (ConvTime * SecondsPerDay);
+	MinStr := IntToStr (Seconds div 60);
+	SecStr := IntToStr (Seconds mod 60);
+	while Length (SecStr) < 2 do
+		SecStr := '0' + SecStr;
+	Result := MinStr + ':' + SecStr;
+end;
+var
+	CurTime: TDateTime;
+begin
+	CurTime := Now;
+	if Trunc (CompLastTime * SecondsPerDay) <> Trunc (CurTime * SecondsPerDay) then begin
+		CompLastTime := CurTime;
+		with StatusBar, Panels do begin
+			Items[7].Text := 'File Time: ' + CustomTimeToStr (CurTime - CompFileStartTime);
+			Items[8].Text := 'Total Time: ' + CustomTimeToStr (CurTime - CompStartTime);
+			Update;
+		end;
+	end;
+end;
+
+procedure TMainForm.DisplayFolderMessage;
+var
+	S: string;
+begin
+	if OperationSuccessful and (not OperationCancelled) and OpenFolderMessage then begin
+		if ProjectTarget = ptArchive then
+			S := 'The project has been compiled successfully.'#13#10#13#10'Archive Size: ' + IntToStr (ProgSize) + ' Bytes'#13#10#13#10'Do you want to open the project folder?'
+		else
+			with OptimizeInfo do begin
+				S := 'The project has been compiled successfully.'#13#10#13#10'Program Variable Size: ' + IntToStr (ProgramSize) + ' Bytes'#13#10;
+				if DataSize > 0 then
+					S := S + 'Data Variable Size: ' + IntToStr (DataSize) + ' Bytes'#13#10;
+				if BSSSize > 0 then
+					S := S + 'BSS Size: ' + IntToStr (BSSSize) + ' Bytes'#13#10;
+				S := S + 'Absolute Relocs: ' + IntToStr (RelocCount) + #13#10'Natively Emitted Relocs: ' + IntToStr (NativeRelocCount) + #13#10;
+				if OptimizeBranchesResult > 0 then begin
+					if OptimizeBranches then
+						S := S + 'Relocs Saved'
+					else
+						S := S + 'Relocs Savable';
+					S := S + ' by Branch Optimization: ' + IntToStr (OptimizeBranchesResult) + #13#10;
+				end;
+				if OptimizeMovesResult > 0 then begin
+					if OptimizeMoves then
+						S := S + 'Relocs Saved'
+					else
+						S := S + 'Relocs Savable';
+					S := S + ' by Move Optimization: ' + IntToStr (OptimizeMovesResult) + #13#10;
+				end;
+				if OptimizeTestsResult > 0 then begin
+					if OptimizeTests then
+						S := S + 'Relocs Saved'
+					else
+						S := S + 'Relocs Savable';
+					S := S + ' by Test Optimization: ' + IntToStr (OptimizeTestsResult) + #13#10;
+				end;
+				if OptimizeCalcsResult > 0 then begin
+					if OptimizeCalcs then
+						S := S + 'Relocs Saved'
+					else
+						S := S + 'Relocs Savable';
+					S := S + ' by Calculation Optimization: ' + IntToStr (OptimizeCalcsResult) + #13#10;
+				end;
+				if UseFLineJumpsResult > 0 then begin
+					if UseFLineJumps or Use4ByteFLineJumps then
+						S := S + 'Relocs Saved'
+					else
+						S := S + 'Relocs Savable';
+					S := S + ' by F-Line Jumps: ' + IntToStr (UseFLineJumpsResult) + #13#10;
+				end;
+				if CutRangesResult > 0 then begin
+					if CutRanges then
+						S := S + 'Space Saved'
+					else
+						S := S + 'Space Savable';
+					S := S + ' by Range-Cutting: ' + IntToStr (CutRangesResult) + ' Bytes'#13#10;
+				end;
+				if NearAssemblyResult > 0 then
+					S := S + 'Space Savable by Using GNU Assembler ''-l'' Switch: ' + IntToStr (NearAssemblyResult) + ' Bytes'#13#10;
+				S := S + #13#10'Do you want to open the project folder?';
+			end;
+		if ShowDefaultMessageBox (S, 'Compilation Successful', mtQuestion) = idYes then
+			ShellExecute (0, nil, PChar (ExtractFilePath (ProjectFile)), nil, nil, sw_ShowNormal);
+	end;
+end;
+
+procedure TMainForm.ProjectStopCompilation(Sender: TObject);
+begin
+	CompFinishAndStop := True;
+	ActionProjectStopCompilation.Enabled := False;
+end;
+
+procedure TMainForm.ProjectForceQuitCompiler(Sender: TObject);
+begin
+	CompStopNow := True;
+end;
+
+procedure TMainForm.WMDropFiles(var Msg: TMessage);
+var
+	DropHandle: THandle;
+	I,
+	FileCount: Integer;
+	CurFile: array [0..512] of Char;
+begin
+	DropHandle := Msg.WParam;
+	FileCount := DragQueryFile (DropHandle, High (Cardinal), nil, 0);
+	for I := 0 to FileCount - 1 do begin
+		DragQueryFile (DropHandle, I, CurFile, SizeOf (CurFile) - 1);
+		if LowerCase (ExtractFileExt (AnsiString (CurFile))) = LowerCase (ProjectFileExt) then
+			FileOpen (AnsiString (CurFile))
+		else
+			AddSourceFile (AnsiString (CurFile), True);
+	end;
+	DragFinish (DropHandle);
+end;
+
+procedure TMainForm.HelpNews(Sender: TObject);
+begin
+	with TNewsForm.Create (Self) do try
+		Execute;
+	finally
+		Free;
+	end;
+end;
+
+function TMainForm.GetVTIWindow: HWnd;
+begin
+	CurVTIType := cvNone;
+	Result := FindWindow ('TEmuWnd', 'Virtual TI-89');
+	if Result = 0 then begin
+		Result := FindWindow ('TEmuWnd', 'Virtual TI-92+');
+		if Result = 0 then begin
+			Result := FindWindow ('TEmuWnd', 'Virtual TI-92');
+			if Result <> 0 then
+				CurVTIType := cvTI92;
+		end else
+			CurVTIType := cvTI92Plus;
+	end else
+		CurVTIType := cvTI89;
+	if Result = 0 then begin
+		if Length (VTIPath) > 0 then begin
+			with TVTIStartForm.Create (Self) do try
+				if ShowModal = mrOK then begin
+					Result := VTIWindow;
+					CurVTIType := VTIType;
+				end else
+					Abort;
+			finally
+				Free;
+			end;
+		end else begin
+			ShowDefaultMessageBox ('Virtual TI is not running.', 'Error', mtProgramError);
+			Abort;
+		end;
+	end;
+end;
+
+procedure TMainForm.SendFiles(FNList: array of string);
+var
+	Win: HWnd;
+procedure SendKey(Key: Byte);
+begin
+	PostMessage (Win, WM_KEYDOWN, Key, 0);
+	PostMessage (Win, WM_KEYUP, Key, 0);
+end;
+var
+	I: Integer;
+	EditWin,
+	ButtonWin: HWnd;
+	StartTime: Cardinal;
+	FileString: string;
+	Name: array [0..32] of Char;
+	Connection: TLinkConnection;
+	Size: Word;
+	Total: Cardinal;
+	Progress: DWord;
+	ProgressForm: TSendProgressForm;
+begin
+	OperationSuccessful := False;
+	OperationCancelled := False;
+	if Length (FNList) > 0 then begin
+		if TransferTarget = ttVTI then begin
+			Win := GetVTIWindow;
+			GetWindowThreadProcessID (Win, @ProcID);
+			SendKey (VK_SCROLL);
+			SendKey (VK_ESCAPE);
+			if CurVTIType = cvTI89 then
+				SendKey (VK_HOME);
+			SendKey (VK_F10);
+			StartTime := GetTickCount;
+			SendWin := 0;
+			repeat
+				EnumWindows (@EnumWindowsFunc, 0);
+			until (SendWin <> 0) or (GetTickCount - StartTime >= 10000);
+			if SendWin = 0 then begin
+				ShowDefaultMessageBox ('Error displaying send dialog.', 'Error', mtProgramError);
+				Abort;
+			end else begin
+				SetForegroundWindow (SendWin);
+				repeat
+					EditWin := GetWindow (SendWin, GW_CHILD);
+					GetClassName (EditWin, Name, 32);
+					while (EditWin <> 0) and (UpperCase (AnsiString (Name)) <> 'EDIT') do begin
+						EditWin := GetWindow (EditWin, GW_HWNDNEXT);
+						if EditWin <> 0 then
+							GetClassName (EditWin, Name, 32);
+					end;
+					if EditWin <> 0 then begin
+						StartTime := GetTickCount;
+						while (SendMessage (EditWin, WM_GETTEXTLENGTH, 0, 0) <= 0) and (GetTickCount - StartTime < 5000) do;
+						FileString := '';
+						for I := Low (FNList) to High (FNList) do begin
+							if CurVTIType = cvTI92Plus then
+								FNList [I] := StringReplace (FNList [I], '.89', '.9x', []);
+							if not FileExists (FNList [I]) then begin
+								ShowDefaultMessageBox ('The file "' + FNList [I] + '" could not be found.', 'Error', mtProgramError);
+								Abort;
+							end;
+							Insert ('"' + FNList [I] + '" ', FileString, Length (FileString) + 1);
+						end;
+						Delete (FileString, Length (FileString), 1);
+						SendMessage (EditWin, WM_SETTEXT, 0, Integer (PChar (FileString)));
+					end;
+					ButtonWin := GetWindow (SendWin, GW_CHILD);
+					GetClassName (ButtonWin, Name, 32);
+					while (ButtonWin <> 0) and ((UpperCase (AnsiString (Name)) <> 'BUTTON') or ((GetWindowLong (ButtonWin, GWL_STYLE) and BS_DEFPUSHBUTTON) = 0) or ((GetWindowLong (ButtonWin, GWL_STYLE) and BS_CHECKBOX) <> 0)) do begin
+						ButtonWin := GetWindow (ButtonWin, GW_HWNDNEXT);
+						if ButtonWin <> 0 then
+							GetClassName (ButtonWin, Name, 32);
+					end;
+				until SendMessage (EditWin, WM_GETTEXTLENGTH, 0, 0) >= Length (FNList [Low (FNList)]);
+				if ButtonWin <> 0 then begin
+					SendMessage (ButtonWin, WM_LBUTTONDOWN, 0, 0);
+					SendMessage (ButtonWin, WM_LBUTTONUP, 0, 0);
+				end;
+			end;
+			ShowWindow (Win, SW_SHOWNORMAL);
+			SetForegroundWindow (Win);
+		end else if TransferTarget = ttCalc then begin
+			FillChar (Connection, SizeOf (Connection), 0);
+			Connection.Port := LinkPort;
+			Connection.CableType := LinkCable;
+			if CreateConnection (Connection) then try
+				if OpenConnection (Connection) and GetCalcType (Connection) then begin
+					Total := 0;
+					for I := Low (FNList) to High (FNList) do begin
+						case Connection.CalcType of
+							cdTI92Plus:
+								FNList [I] := StringReplace (FNList [I], '.89', '.9x', []);
+							cdV200:
+								FNList [I] := StringReplace (FNList [I], '.89', '.v2', []);
+							cdTI92:
+								FNList [I] := StringReplace (FNList [I], '.89', '.92', []);
+						end;
+						if not FileExists (FNList [I]) then begin
+							ShowDefaultMessageBox ('The file "' + FNList [I] + '" could not be found.', 'Error', mtProgramError);
+							Abort;
+						end;
+						if not CheckFileFormat (Connection, PChar (FNList [I]), nil, nil, @Size) then begin
+							ShowDefaultMessageBox ('Error sending file.', 'Error', mtProgramError);
+							Abort;
+						end;
+						Inc (Total, Size);
+					end;
+					Enabled := False;
+					try
+						ProgressForm := TSendProgressForm.Create (Self);
+						with ProgressForm do try
+							ProgressBar.Max := Total;
+							Show;
+							Update;
+							Progress := 0;
+							for I := Low (FNList) to High (FNList) do begin
+								FileNameLabel.Caption := ExtractFileName (FNList [I]);
+								if not SendFile (Connection, nil, nil, PChar (FNList [I]), @Progress, ProgressProg, ProgressForm) then begin
+									if Cancelled then
+										OperationCancelled := True
+									else
+										ShowDefaultMessageBox ('Error sending file. Please check whether your calculator is on the home screen.', 'Error', mtProgramError);
+									Abort;
+								end;
+							end;
+						finally
+							CloseNow := True;
+							Free;
+						end;
+					finally
+						Enabled := True;
+					end;
+				end else begin
+					ShowDefaultMessageBox ('Error linking to calculator.', 'Error', mtProgramError);
+					Abort;
+				end;
+			finally
+				CloseConnection (Connection);
+			end else begin
+				ShowDefaultMessageBox ('Error opening link port.', 'Error', mtProgramError);
+				Abort;
+			end;
+		end;
+		OperationSuccessful := True;
+	end;
+end;
+
+procedure TMainForm.ExecuteCommandLine(const Line: string);
+var
+	Win: HWnd;
+procedure SendKey(Key: Byte);
+begin
+	SendMessage (Win, WM_KEYDOWN, Key, 0);
+	SendMessage (Win, WM_KEYUP, Key, 0);
+	Sleep (20);
+end;
+var
+	I: Integer;
+	Connection: TLinkConnection;
+begin
+	if TransferTarget = ttVTI then begin
+		Win := GetVTIWindow;
+		SendKey (VK_SCROLL);
+		SendKey (VK_ESCAPE);
+		SendKey (VK_ESCAPE);
+		if CurVTIType = cvTI89 then
+			SendKey (VK_HOME);
+		SendKey (VK_DELETE);
+		SendKey (VK_DELETE);
+		for I := 1 to Length (Line) do
+			if Line [I] in ['A'..'Z', 'a'..'z', '0'..'9'] then
+				SendKey (Byte (UpCase (Line [I])))
+			else if Line [I] = '(' then
+				SendKey ($DB)
+			else if Line [I] = ')' then
+				SendKey ($DD)
+			else if Line [I] = ',' then
+				SendKey ($BC)
+			else if Line [I] = '.' then
+				SendKey (VK_DECIMAL)
+			else if Line [I] = '+' then
+				SendKey (VK_ADD)
+			else if Line [I] = '-' then
+				SendKey (VK_SUBTRACT)
+			else if Line [I] = '*' then
+				SendKey (VK_MULTIPLY)
+			else if Line [I] = '/' then
+				SendKey (VK_DIVIDE)
+			else if Line [I] = '\' then begin
+				SendKey (VK_MENU);
+				SendKey (Byte ('2'));
+			end;
+		SendKey (VK_RETURN);
+	end else if TransferTarget = ttCalc then begin
+		FillChar (Connection, SizeOf (Connection), 0);
+		Connection.Port := LinkPort;
+		Connection.CableType := LinkCable;
+		if CreateConnection (Connection) then try
+			if OpenConnection (Connection) then
+				ExecuteHomeLine (Connection, Line)
+			else begin
+				ShowDefaultMessageBox ('Error linking to calculator.', 'Error', mtProgramError);
+				Abort;
+			end;
+		finally
+			CloseConnection (Connection);
+		end else begin
+			ShowDefaultMessageBox ('Error opening link port.', 'Error', mtProgramError);
+			Abort;
+		end;
+	end;
+end;
+
+procedure TMainForm.DebugRun(Sender: TObject);
+var
+	Files: array of string;
+begin
+	OperationSuccessful := True;
+	OperationCancelled := False;
+	if Invalidated then
+		MakeFileWrapped;
+	if OperationSuccessful and (not OperationCancelled) and (FileExists (ChangeFileExt (ProjectFile, '.89z')) or FileExists (ChangeFileExt (ProjectFile, '.9xz')) or FileExists (ChangeFileExt (ProjectFile, '.v2z')) or FileExists (ChangeFileExt (ProjectFile, '.92p'))) then begin
+		if Runnable then begin
+			SetLength (Files, 0);
+			case ProjectTarget of
+				ptRegular: begin
+					SetLength (Files, 1);
+					Files [High (Files)] := ChangeFileExt (ProjectFile, '.89z');
+					if Pack and (ssPack in SpecialSupport) then begin
+						SetLength (Files, Length (Files) + 1);
+						Files [High (Files)] := ChangeFileExt (ProjectFile, '.89y');
+					end;
+					if UseDataVar then begin
+						SetLength (Files, Length (Files) + 1);
+						Files [High (Files)] := ChangeFileExt (ProjectFile, '-data.89y');
+					end;
+				end;
+				ptFargo: begin
+					SetLength (Files, 1);
+					Files [High (Files)] := ChangeFileExt (ProjectFile, '.92p');
+				end;
+			end;
+			if Length (Files) > 0 then begin
+				SendFiles (Files);
+				if OperationSuccessful then
+					ExecuteCommandLine (TopNode.Text + '(' + CommandLine + ')');
+			end;
+		end else
+			DisplayFolderMessage;
+	end;
+end;
+
+procedure TMainForm.DebugPause(Sender: TObject);
+var
+	Win: HWnd;
+procedure SendKey(Key: Byte);
+begin
+	PostMessage (Win, WM_KEYDOWN, Key, 0);
+	PostMessage (Win, WM_KEYUP, Key, 0);
+end;
+begin
+	Win := GetVTIWindow;
+	SendKey (VK_F11);
+	ShowWindow (Win, SW_SHOWNORMAL);
+	SetForegroundWindow (Win);
+end;
+
+procedure TMainForm.DebugReset(Sender: TObject);
+var
+	Win: HWnd;
+procedure SendKey(Key: Byte);
+begin
+	PostMessage (Win, WM_KEYDOWN, Key, 0);
+	PostMessage (Win, WM_KEYUP, Key, 0);
+end;
+begin
+	Win := GetVTIWindow;
+	SendKey (VK_APPS);
+	SendKey (Byte ('T'));
+	ShowWindow (Win, SW_SHOWNORMAL);
+	SetForegroundWindow (Win);
+end;
+
+function TMainForm.GetInvalidated: Boolean;
+var
+	I: Integer;
+begin
+	Result := FInvalidated;
+	if not Result then
+		with SourceFiles do
+			for I := 0 to Count - 1 do
+				with Items [I] as TSourceFile do
+					if (Compilable or (Items [I] is THeaderSourceFile)) and Invalidated then begin
+						Result := True;
+						Break;
+					end;
+end;
+
+procedure TMainForm.UpdateDebugSettings;
+var
+	CanRun: Boolean;
+begin
+	CanRun := Runnable;
+	ActionDebugRun.Enabled := not Compiling;
+	ActionDebugPause.Enabled := (not Compiling) and (TransferTarget = ttVTI);
+	ActionDebugReset.Enabled := (not Compiling) and (TransferTarget = ttVTI);
+	MainMenuDebug.Visible := CanRun;
+	if not CanRun then
+		ToolBarDebugLine.Parent := nil;
+	ToolBarRunButton.Visible := CanRun;
+	ToolBarPauseButton.Visible := CanRun;
+	ToolBarDebugLine.Visible := CanRun;
+	if CanRun then begin
+		ToolBarDebugLine.Parent := MainToolBar;
+		ToolBarDebugLine.Left := ToolBarPauseButton.Left + ToolBarPauseButton.Width;
+	end;
+end;
+
+procedure TMainForm.FormKeyDown(Sender: TObject; var Key: Word;
+	Shift: TShiftState);
+var
+	NewSelection: TTreeNode;
+begin
+	if (Key = vk_F9) and (Shift = [ssShift, ssCtrl, ssAlt]) then begin
+		if TransferTarget = ttVTI then
+			TransferTarget := ttCalc
+		else
+			TransferTarget := ttVTI;
+		SavePreferences;
+		UpdateDebugSettings;
+	end else if (Key = vk_Tab) and (Shift = [ssCtrl]) then begin
+		NewSelection := ProjectTree.Selected;
+		if Assigned (NewSelection) then begin
+			repeat
+				NewSelection := NewSelection.GetNext;
+				if not Assigned (NewSelection) then
+					NewSelection := TopNode;
+			until (NewSelection.IsVisible and Assigned (NewSelection.Data)) or (NewSelection = ProjectTree.Selected);
+			if Assigned (NewSelection.Data) then
+				SelectNode (NewSelection);
+			if Assigned (CurrentEditor) and CurrentEditor.Enabled then try
+				CurrentEditor.SetFocus;
+			except end;
+		end;
+	end;
+end;
+
+procedure TMainForm.SelectNode(Node: TTreeNode);
+var
+	Allow: Boolean;
+begin
+	if PreviousNode <> Node then begin
+		Allow := True;
+		ProjectTreeChanging (ProjectTree, Node, Allow);
+		if Allow then begin
+			NoHideEditor := True;
+			ProjectTree.Selected := Node;
+			NoHideEditor := False;
+		end;
+	end;
+end;
+
+procedure TMainForm.ChangeNotificationTick(Sender: TObject);
+var
+	I: Integer;
+begin
+	if not InChangeNotification then begin
+		InChangeNotification := True;
+		with SourceFiles do
+			for I := 0 to Count - 1 do
+				with TSourceFile (Items [I]) do
+					TestChange;
+		InChangeNotification := False;
+	end;
+end;
+
+procedure TMainForm.ResetProjectSettings;
+begin
+	ProjectTarget         := ptRegular;
+	UseDataVar            := False;
+	DataVar               := '';
+	DataVarCopy           := True;
+	DataVarCopyIfArchived := True;
+	Pack                  := False;
+	PackVar               := '';
+	GCCSwitches           := '-Os -Wall -W -Wwrite-strings -ffunction-sections -fdata-sections';
+	AsSwitches            := '';
+	AsmSwitches           := '-g -t';
+	DebugInfo             := False;
+	StdLib                := True;
+	InitBSS               := True;
+	OptimizeNOPs          := True;
+	OptimizeReturns       := True;
+	OptimizeBranches      := True;
+	OptimizeMoves         := True;
+	OptimizeTests         := True;
+	OptimizeCalculations  := True;
+	RemoveUnusedSections  := True;
+	CutUnusedRanges       := True;
+	ReorderSections       := True;
+	MergeConstants        := True;
+	OutputBin             := False;
+	CommandLine           := '';
+	PostBuildProcessFile  := '';
+	if Assigned (PredefinedLibOptions) then
+		with PredefinedLibOptions do begin
+			CalcDests                := [cdTI89, cdTI92Plus, cdV200];
+			OptimizeCalcConsts       := False;
+			KernelFormat             := kfNone;
+			UseMinAMS                := True;
+			MinAMS                   := '1.00';
+			RelocFormat              := rfAMS;
+			ROMCallFormat            := rfDirect;
+			BSSRefFormat             := rfKernel;
+			DataRefFormat            := rfKernel;
+			UseFLineJumps            := False;
+			UseInternalFLineEmulator := False;
+			UseReturnValue           := False;
+			EnableErrorReturn        := False;
+			SaveScreen               := True;
+		end;
+end;
+
+procedure TMainForm.AddToRecent(const FileName: string);
+var
+	I: Integer;
+	O: TRecentFileMenuItem;
+begin
+	with RecentFiles do begin
+		for I := 0 to Count - 1 do
+			if (I >= MaxRecentFiles - 1) or (UpperCase (Strings [I]) = UpperCase (FileName)) then begin
+				if I = 0 then
+					Exit
+				else begin
+					Objects[I].Free;
+					Delete (I);
+					Break;
+				end;
+			end;
+		RecentFilesLine.Visible := True;
+		O := TRecentFileMenuItem.Create;
+		with O do begin
+			FileMenuItem := TMenuItem.Create (Self);
+			with FileMenuItem do begin
+				Caption := WithoutExt (ExtractFileName (FileName));
+				Hint := FileName;
+				OnClick := RecentFileClick;
+			end;
+			MainMenuFile.Insert (RecentFilesLine.MenuIndex + 1, FileMenuItem);
+			PopupMenuItem := TMenuItem.Create (Self);
+			with PopupMenuItem do begin
+				Caption := FileName;
+				Hint := FileName;
+				OnClick := RecentFileClick;
+			end;
+			RecentFilesPopup.Items.Insert (0, PopupMenuItem);
+		end;
+		InsertObject (0, FileName, O);
+	end;
+	UpdateRecent;
+end;
+
+procedure TMainForm.UpdateRecent;
+begin
+	RecentFilesLine.Visible := RecentFiles.Count > 0;
+	NoFilesItem.Visible := RecentFiles.Count <= 0;
+end;
+
+procedure TMainForm.RecentFileClick(Sender: TObject);
+var
+	I: Integer;
+	FileName: string;
+begin
+	FileName := (Sender as TMenuItem).Hint;
+	if FileExists (FileName) then
+		FileOpen (FileName)
+	else begin
+		with RecentFiles do
+			for I := 0 to Count - 1 do
+				if UpperCase (Strings [I]) = UpperCase (FileName) then begin
+					Objects[I].Free;
+					Delete (I);
+					Break;
+				end;
+		UpdateRecent;
+		ShowDefaultMessageBox ('File ''' + WithoutExt (ExtractFileName (FileName)) + ''' not found.', 'Error', mtProgramError);
+	end;
+end;
+
+procedure TMainForm.ToolsConfigure(Sender: TObject);
+var
+	I: Integer;
+begin
+	with TToolsForm.Create (Self) do try
+		with Self.ToolsList do
+			for I := 0 to Count - 1 do
+				with ToolsList.Items.Add, TToolsListItem (Items [I]) do begin
+					Caption := Title;
+					SubItems.Add (CommandLine);
+					SubItems.Add (WorkingDir);
+					SubItems.Add (WindowStateToString (WindowState));
+				end;
+		if ShowModal = mrOK then begin
+			Self.ToolsList.Clear;
+			with ToolsList.Items do begin
+				ToolsLine.Visible := Count > 0;
+				for I := 0 to Count - 1 do
+					with Item [I] do
+						AddTool (Caption, SubItems [0], SubItems [1], StringToWindowState (SubItems [2]));
+			end;
+			SavePreferences;
+		end;
+	finally
+		Free;
+	end;
+end;
+
+procedure TMainForm.ToolClick(Sender: TObject);
+var
+	WorkDir: PChar;
+	StartupInfo: TStartupInfo;
+	ProcessInfo: TProcessInformation;
+begin
+	with TToolsListItem ((Sender as TMenuItem).Tag) do begin
+		FillChar (StartupInfo, SizeOf (StartupInfo), 0);
+		StartupInfo.cb := SizeOf (StartupInfo);
+		if Length (WorkingDir) > 0 then
+			WorkDir := PChar (WorkingDir)
+		else
+			WorkDir := nil;
+		StartupInfo.dwFlags := StartF_UseShowWindow;
+		case WindowState of
+			wsMaximized:
+				StartupInfo.wShowWindow := SW_SHOWMAXIMIZED;
+			wsMinimized:
+				StartupInfo.wShowWindow := SW_SHOWMINIMIZED;
+			else
+				StartupInfo.dwFlags := 0;
+		end;
+		if CreateProcess (nil, PChar (CommandLine), nil, nil, False, CREATE_NEW_PROCESS_GROUP or DETACHED_PROCESS, nil, WorkDir, StartupInfo, ProcessInfo) then begin
+			CloseHandle (ProcessInfo.hProcess);
+			CloseHandle (ProcessInfo.hThread);
+		end else
+			ShowDefaultMessageBox ('An error occurred while trying to start the application.', 'Error', mtProgramError);
+	end;
+end;
+
+procedure TMainForm.AddTool(const Title, CommandLine, WorkingDir: string; WindowState: TWindowState);
+var
+	O: TToolsListItem;
+begin
+	O := TToolsListItem (Self.ToolsList.Add);
+	O.Title := Title;
+	O.CommandLine := CommandLine;
+	O.WorkingDir := WorkingDir;
+	O.WindowState := WindowState;
+	O.MenuItem := TMenuItem.Create (Self);
+	with O.MenuItem do begin
+		Tag := Integer (O);
+		Caption := Title;
+		Hint := CommandLine;
+		OnClick := ToolClick;
+	end;
+	MainMenuTools.Insert (MainMenuTools.Count, O.MenuItem);
+end;
+
+procedure TMainForm.ProjectTreeStartDrag(Sender: TObject;
+	var DragObject: TDragObject);
+begin
+	DragObject := TNoImageDragObject.Create (Sender as TControl);
+end;
+
+procedure TMainForm.UpdateProgramOutput;
+begin
+	ActionProjectShowProgramOutput.Enabled := (MainConsole.LastOutSize > 2) or (MainConsole.LastErrSize > 2);
+end;
+
+procedure TMainForm.ShowProgramOutput(Sender: TObject);
+begin
+	with TProgramOutputForm.Create (Self) do try
+		OutputMemo.Text := MainConsole.LastOutText;
+		ErrorMemo.Text := MainConsole.LastErrText;
+		ShowModal;
+	finally
+		Free;
+	end;
+end;
+
+procedure TMainForm.ClearDebugInfo;
+begin
+end;
+
+procedure TMainForm.FileNewFolder(Sender: TObject);
+var
+	ParentNode,
+	Node: TTreeNode;
+	Folder: TFolder;
+begin
+	ParentNode := ProjectTree.Selected;
+	while Assigned (ParentNode) and Assigned (ParentNode.Data) and (not (TObject (ParentNode.Data) is TFolder)) do
+		ParentNode := ParentNode.Parent;
+	if Assigned (ParentNode) and Assigned (ParentNode.Parent) then begin
+		Folder := TFolder.Create;
+		Node := ProjectTree.Items.AddChildObject (ParentNode, 'New Folder', Folder);
+		Folder.TreeItem := Node;
+		with Node do begin
+			ImageIndex    := 0;
+			SelectedIndex := 1;
+      Selected := True;
+			EditText;
+		end;
+	end;
+end;
+
+function TMainForm.GetSourceTypeFolder(Node: TTreeNode): TTreeNode;
+begin
+	if Assigned (Node) and Assigned (Node.Parent) then begin
+		Result := Node;
+		while Assigned (Result) and Assigned (Result.Data) do
+			Result := Result.Parent;
+	end else
+		Result := nil;
+end;
+
+function TMainForm.FindFileInsertionPoint(ParentNode: TTreeNode): TTreeNode;
+begin
+	if Assigned (ParentNode) then begin
+		Result := ParentNode.GetFirstChild;
+		while Assigned (Result) and Assigned (Result.Data) and (TObject (Result.Data) is TSourceFile) do
+			Result := Result.GetNextSibling;
+	end else
+		Result := nil;
+end;
+
+function TMainForm.CreateFileNode(ParentNode: TTreeNode; SourceFile: TSourceFile): TTreeNode;
+begin
+	if Assigned (SourceFile.Folder) then
+		ParentNode := SourceFile.Folder.TreeItem;
+	if Assigned (ParentNode) then begin
+		Result := FindFileInsertionPoint (ParentNode);
+		if Assigned (Result) then
+			Result := ProjectTree.Items.InsertObject (Result, SourceFile.SourceName, SourceFile)
+		else
+			Result := ProjectTree.Items.AddChildObject (ParentNode, SourceFile.SourceName, SourceFile);
+	end else
+		Result := nil;
+end;
+
+procedure TMainForm.FileNewFile(Sender: TObject);
+var
+	Node: TTreeNode;
+begin
+	if Assigned (ProjectTree.Selected) then begin
+		Node := GetSourceTypeFolder (ProjectTree.Selected);
+		if Assigned (Node) then
+			if Node.Index = THeaderSourceFile.GetClassTreeIndex then
+				FileNewHeaderFile (Sender)
+			else if Node.Index = TCSourceFile.GetClassTreeIndex then
+				FileNewCSourceFile (Sender)
+			else if Node.Index = TGNUAsmSourceFile.GetClassTreeIndex then
+				FileNewGNUAssemblerSourceFile (Sender)
+			else if (ssA68k in SpecialSupport) and (Node.Index = TAsmSourceFile.GetClassTreeIndex) then
+				FileNewAssemblerSourceFile (Sender)
+			else if (ssQuill in SpecialSupport) and (Node.Index = TQuillSourceFile.GetClassTreeIndex) then
+				FileNewQuillSourceFile (Sender)
+			else if Node.Index = TNormalTextSourceFile.GetClassTreeIndex then
+				FileNewTextFile (Sender);
+	end;
+end;
+
+function TMainForm.GetSelectedFolder(SourceClass: TSourceFileClass): TFolder;
+var
+	Node: TTreeNode;
+begin
+	Result := nil;
+	Node := ProjectTree.Selected;
+	while Assigned (Node) and (Node <> TopNode.Item [SourceClass.GetClassTreeIndex]) do begin
+		if (not Assigned (Result)) and Assigned (Node.Data) and (TObject (Node.Data) is TFolder) then
+			Result := Node.Data;
+		Node := Node.Parent;
+	end;
+	if not Assigned (Node) then
+		Result := nil;
+end;
+
+procedure TMainForm.ErrorListKeyDown(Sender: TObject; var Key: Word;
+	Shift: TShiftState);
+var
+	S: string;
+	Item: TListItem;
+begin
+	if ((Key = VK_INSERT) or (Key = Ord('C'))) and (Shift = [ssCtrl]) then
+		with ErrorList do begin
+			S := '';
+			Item := Selected;
+			while Assigned (Item) do begin
+				S := S + Item.Caption + #13#10;
+				Item := GetNextItem (Item, sdAll, [isSelected]);
+			end;
+			Clipboard.AsText := S;
+		end;
+end;
+
+{$IFDEF CODINGEXT}
+procedure TMainForm.InitCodingExt;
+var
+	 ActionFindSymbol: TAction;
+begin
+	// Find Symbol declaration tool
+	ActionFindSymbol := TAction.Create(Self);
+	with ActionFindSymbol do
+	begin
+		ActionList := Actions;
+		Caption := 'Find Symbol Declaration';
+		Category := 'Extension';
+		OnExecute := ActionFindSymbolExecute;
+	end;
+
+	InsertsAction(Self, [OpenFileAtCursor1, OpenFileatCursor2], ActionFindSymbol);
+end;
+
+procedure TMainForm.ActionFindSymbolExecute(Sender: TObject);
+begin
+	CompForm.FindSymbolDecl;
+end;
+{$ENDIF}
+
+end.
+

+ 735 - 0
MasterUnit.pas

@@ -0,0 +1,735 @@
+unit MasterUnit;
+
+interface
+
+uses
+	CalcUnit, ProcessUnit, ParsingUnit,
+	LinkUnit,
+	Classes, Graphics, SourceEditUnit;
+
+const
+	IDELocation          = 'Bin\';
+	LinkLibLocation      = 'Bin\';
+	GCCLocation          = 'Bin\';
+	AsLocation           = 'Bin\';
+	A68kLocation         = 'Bin\';
+	PackLocation         = 'Bin\';
+	ASMIncludeLocation   = 'Include\ASM\';
+	GASIncludeLocation   = 'Include\S\';
+	CIncludeLocation     = 'Include\C\';
+	QuillIncludeLocation = 'Include\Quill\';
+	DocLocation          = 'Doc\';
+	ProjectsLocation     = 'Projects\';
+	StdLibLocation       = 'Lib\';
+	TIPatchLocation      = 'Lib\';
+	PStarterLocation     = 'Lib\';
+	TemplatesLocation    = 'Bin\';
+	CompletionLocation   = 'Include\C\Completion\';
+
+	DefaultGCCSwitches      = '-B .\ -I- -I ..\Include\C\';
+	DefaultAsSwitches       = '-mc68000 -I ..\Include\S\';
+	DefaultA68kSwitches     = '-i..\Include\ASM';
+	SpecialQuillGCCSwitches = '-I ..\Include\Quill\';
+
+	ProjectFileExt = '.tpr';
+
+	MaxNameLength = 8;
+
+type
+	TSpecialSupportOption = (ssA68k, ssQuill, ssPack, ssFlashOS, ssFargo);
+	TSpecialSupport = set of TSpecialSupportOption;
+	TProjectTarget = (ptRegular, ptFlashOS, ptFargo, ptArchive);
+	TTransferTarget = (ttNone, ttVTI, ttCalc);
+	TCurVTIType = (cvNone, cvTI89, cvTI92Plus, cvTI92);
+	TKernelFormat = (kfUnknown, kfNone, kfStandard, kfCompressedTables);
+	TRelocFormat = (rfUnknown, rfNone, rfDirect, rfAMS, rfKernel, rfCompressed, rfFLine);
+
+	TPredefinedLibOptions = class(TObject)
+		CalcDests: TCalcDests;
+		OptimizeCalcConsts: Boolean;
+		KernelFormat: TKernelFormat;
+		UseMinAMS: Boolean;
+		MinAMS: string;
+		UnofficialOSSupport: Boolean;
+		RelocFormat,
+		ROMCallFormat,
+		BSSRefFormat,
+		DataRefFormat: TRelocFormat;
+		UseFLineJumps,
+		Use4ByteFLineJumps,
+		OptimizeROMCalls,
+		UseInternalFLineEmulator: Boolean;
+		UseReturnValue,
+		EnableErrorReturn: Boolean;
+		SaveScreen: Boolean;
+		function GetSwitches: string;
+	end;
+
+var
+	MainConsole: TProcessConsole;
+	StopOnErrors,
+	DeleteAssemblyFiles,
+	DeleteObjectFiles,
+	AssumeUndefined,
+	AutoBlocks,
+	AutoNews,
+	UseDataVar,
+	DataVarCopy,
+	DataVarCopyIfArchived,
+	Pack,
+	DebugInfo,
+	StdLib,
+	InitBSS,
+	OptimizeNOPs,
+	OptimizeReturns,
+	OptimizeBranches,
+	OptimizeMoves,
+	OptimizeTests,
+	OptimizeCalculations,
+	RemoveUnusedSections,
+	CutUnusedRanges,
+	ReorderSections,
+	MergeConstants,
+	OutputBin: Boolean;
+	ProjectTarget: TProjectTarget;
+	GCCSwitches,
+	AsSwitches,
+	AsmSwitches,
+	DataVar,
+	PackVar,
+	CommandLine,
+	PostBuildProcessFile: string;
+	PredefinedLibOptions: TPredefinedLibOptions;
+	ProxyName: string;
+	ProxyPort: Integer;
+	TIGCCFolder: string;
+	Temp: string;
+	OperationCancelled,
+	OperationSuccessful: Boolean;
+	ProjectFileName: string;
+	SyntaxC,
+	SyntaxAsmGNU,
+	SyntaxAsm,
+	SyntaxQuill: TSyntaxColoring;
+	TabSizeC,
+	TabSizeAsm: Integer;
+	EditorColor: TColor;
+	EditorFont: TFont;
+	EditorOnFly,
+	EditorDragDrop,
+	EditorRemoveTrSp: Boolean;
+	LastNewsDate: Integer;
+	TransferTarget: TTransferTarget;
+	VTIPath: string;
+	LinkPort: TLinkPort;
+	LinkCable: TLinkCableType;
+	SpecialSupport: TSpecialSupport;
+	Compiling,
+	CompFinishAndStop,
+	CompStopNow: Boolean;
+	CompStartTime,
+	CompFileStartTime,
+	CompLastTime: TDateTime;
+	CompStartFile: procedure of object;
+	CompStop: procedure of object;
+	CompSetMessage: procedure(const Msg: string) of object;
+	CompUpdate: procedure of object;
+	CompUpdateProgramOutput: procedure of object;
+
+{$IFDEF CanSplit}
+var
+	SplitFiles: Boolean;
+{$ENDIF}
+
+function StartsWith(const SubStr: string; var Str: string; CaseSensitive: Boolean = False; Remove: Boolean = False): Boolean;
+
+procedure WaitForMainConsole(const ProcessDesc: string);
+
+function Runnable: Boolean;
+
+implementation
+
+uses
+	SysUtils, Forms;
+
+procedure WaitForMainConsole(const ProcessDesc: string);
+begin
+	CompUpdate;
+	while MainConsole.Running do begin
+		CompUpdate;
+		Application.ProcessMessages;
+		if CompFinishAndStop then begin
+			OperationCancelled := True;
+			CompSetMessage ('Finishing ' + ProcessDesc + ' Process');
+		end;
+		if CompStopNow then begin
+			OperationCancelled := True;
+			MainConsole.KillProcess;
+			Break;
+		end;
+	end;
+	CompUpdate;
+end;
+
+function Runnable: Boolean;
+begin
+	Result := (ProjectTarget <> ptArchive) and (TransferTarget <> ttNone);
+end;
+
+function StartsWith(const SubStr: string; var Str: string; CaseSensitive: Boolean; Remove: Boolean): Boolean;
+begin
+	if CaseSensitive then
+		Result := Copy (Str, 1, Length (SubStr)) = SubStr
+	else
+		Result := UpperCase (Copy (Str, 1, Length (SubStr))) = UpperCase (SubStr);
+	if Remove and Result then
+		Delete (Str, 1, Length (SubStr));
+end;
+
+{ TPredefinedLibOptions }
+
+function TPredefinedLibOptions.GetSwitches: string;
+procedure AddSwitch(Define: string; const Value: string = '');
+begin
+	if Length (Result) > 0 then
+		Result := Result + ' ';
+	Define := '-D' + Define;
+	if Length (Value) > 0 then
+		Define := '"' + Define + '=' + Value + '"';
+	Result := Result + Define;
+end;
+begin
+	Result := '';
+	if cdTI92 in CalcDests then
+		AddSwitch ('USE_TI92');
+	if cdTI89 in CalcDests then
+		AddSwitch ('USE_TI89');
+	if cdTI92Plus in CalcDests then
+		AddSwitch ('USE_TI92PLUS');
+	if cdV200 in CalcDests then
+		AddSwitch ('USE_V200');
+	if OptimizeCalcConsts then
+		AddSwitch ('OPTIMIZE_CALC_CONSTS');
+	if KernelFormat in [kfStandard, kfCompressedTables] then begin
+		AddSwitch ('USE_KERNEL');
+		if KernelFormat = kfCompressedTables then
+			AddSwitch ('USE_PREOS_COMPRESSED_TABLES');
+	end;
+	if UseMinAMS then try
+		AddSwitch ('MIN_AMS', IntToStr (Round (StrToFloat (MinAMS) * 100)));
+	except end;
+	if UnofficialOSSupport then
+		AddSwitch ('UNOFFICIAL_OS_SUPPORT');
+	if KernelFormat = kfCompressedTables then begin
+		if BSSRefFormat = rfNone then
+			AddSwitch ('MERGE_BSS');
+	end else begin
+		case RelocFormat of
+			rfKernel:      AddSwitch ('KERNEL_FORMAT_RELOCS');
+			rfCompressed:  AddSwitch ('COMPRESSED_FORMAT_RELOCS');
+			rfFLine:       AddSwitch ('USE_FLINE_JUMPS');
+		end;
+		case ROMCallFormat of
+			rfKernel:      AddSwitch ('KERNEL_FORMAT_ROM_CALLS');
+			rfCompressed:  AddSwitch ('COMPRESSED_FORMAT_ROM_CALLS');
+			rfFLine: begin
+				AddSwitch ('USE_FLINE_ROM_CALLS');
+				Result := Result + ' -fno-function-cse';
+			end;
+		end;
+		case BSSRefFormat of
+			rfNone:        AddSwitch ('MERGE_BSS');
+			rfKernel:      AddSwitch ('KERNEL_FORMAT_BSS');
+			rfCompressed:  AddSwitch ('COMPRESSED_FORMAT_BSS');
+		end;
+	end;
+	case DataRefFormat of
+		rfKernel:      AddSwitch ('KERNEL_FORMAT_DATA_VAR');
+		rfCompressed:  AddSwitch ('COMPRESSED_FORMAT_DATA_VAR');
+	end;
+	if UseFLineJumps then begin
+		AddSwitch ('USE_FLINE_JUMPS');
+		if Use4ByteFLineJumps then
+			AddSwitch ('USE_4_BYTE_FLINE_JUMPS');
+	end;
+	if OptimizeROMCalls then
+		AddSwitch ('OPTIMIZE_ROM_CALLS');
+	if UseInternalFLineEmulator then
+		AddSwitch ('USE_INTERNAL_FLINE_EMULATOR');
+	if UseReturnValue then
+		AddSwitch ('RETURN_VALUE');
+	if EnableErrorReturn then
+		AddSwitch ('ENABLE_ERROR_RETURN');
+	if SaveScreen then
+		AddSwitch ('SAVE_SCREEN');
+end;
+
+initialization
+	PredefinedLibOptions := TPredefinedLibOptions.Create;
+	PredefinedLibOptions.MinAMS := '1.01';
+	MainConsole := TProcessConsole.Create;
+	SyntaxC := TSyntaxColoring.Create (nil);
+	SyntaxAsm := TSyntaxColoring.Create (nil);
+	SyntaxAsmGNU := TSyntaxColoring.Create (nil);
+	SyntaxQuill := TSyntaxColoring.Create (nil);
+	EditorFont := TFont.Create;
+	with SyntaxC do begin
+		Enabled := True;
+		SymbolColor := clOlive;
+		SymbolStyle := [fsBold];
+		SymbolCustomStyle := True;
+		NumberColor := clMaroon;
+		NumberStyle := [];
+		NumberCustomStyle := False;
+		with WordLists.Add do begin
+			Caption := 'C Keywords';
+			Words.CommaText :=
+				'__alignof__,__asm__,__attribute__,__complex__,__const__,__extension__,__imag__,__inline__,__label__,__real__,__typeof__,' +
+				'asm,auto,break,case,char,const,continue,default,do,double,else,enum,extern,float,for,goto,if,inline,int,long,register,return,short,signed,sizeof,static,struct,switch,typedef,typeof,union,unsigned,void,volatile,while';
+			CaseSensitive := True;
+			CustomColor := True;
+			Color := clBlue;
+			CustomStyle := True;
+			Style := [fsBold];
+		end;
+		with CustomStyles.Add do begin
+			Caption := 'Comment Area';
+			CustomColor := True;
+			Color := clGreen;
+			CustomStyle := True;
+			Style := [fsItalic];
+			BeginText := '/*';
+			EndText := '*/';
+			Switchable := False;
+		end;
+		with CustomStyles.Add do begin
+			Caption := 'Comment Line';
+			CustomColor := True;
+			Color := clGreen;
+			CustomStyle := True;
+			Style := [fsItalic];
+			BeginText := '//';
+			EndText := #13;
+			Switchable := False;
+		end;
+		with CustomStyles.Add do begin
+			Caption := 'String';
+			CustomColor := True;
+			Color := clMaroon;
+			CustomStyle := False;
+			Style := [];
+			BeginText := '"';
+			EndText := '"';
+			IgnoreChar := '\';
+			Switchable := False;
+		end;
+		with CustomStyles.Add do begin
+			Caption := 'Character';
+			CustomColor := True;
+			Color := clMaroon;
+			CustomStyle := False;
+			Style := [];
+			BeginText := '''';
+			EndText := '''';
+			IgnoreChar := '\';
+			Switchable := False;
+		end;
+		with CustomStyles.Add do begin
+			Caption := 'Preprocessor Directive';
+			CustomColor := True;
+			Color := clTeal;
+			CustomStyle := True;
+			Style := [fsBold];
+			BeginText := '#';
+			EndText := ' ';
+			Switchable := False;
+		end;
+		ParenthesisColors.CommaText := '$800080,$C08000,$8080FF,$008000';
+		ParenthesisStyle := [fsBold];
+		ParenthesisCustomStyle := True;
+	end;
+	with SyntaxAsmGNU do begin
+		NumberColor := SyntaxC.NumberColor;
+		NumberStyle := SyntaxC.NumberStyle;
+		NumberCustomStyle := SyntaxC.NumberCustomStyle;
+		SymbolColor := SyntaxC.SymbolColor;
+		SymbolStyle := SyntaxC.SymbolStyle;
+		SymbolCustomStyle := SyntaxC.SymbolCustomStyle;
+		ParenthesisColors.Assign (SyntaxC.ParenthesisColors);
+		ParenthesisStyle := SyntaxC.ParenthesisStyle;
+		ParenthesisCustomStyle := SyntaxC.ParenthesisCustomStyle;
+		with CustomStyles.Add do begin
+			Caption := 'Comment Area';
+			CustomColor := True;
+			Color := clGreen;
+			CustomStyle := True;
+			Style := [fsItalic];
+			BeginText := '/*';
+			EndText := '*/';
+			Switchable := False;
+		end;
+		with CustomStyles.Add do begin
+			Caption := 'Comment Line (|)';
+			CustomColor := True;
+			Color := clGreen;
+			CustomStyle := True;
+			Style := [fsItalic];
+			BeginText := '|';
+			EndText := #13;
+			Switchable := False;
+		end;
+		with CustomStyles.Add do begin
+			Caption := 'Comment Line (#)';
+			CustomColor := True;
+			Color := clGreen;
+			CustomStyle := True;
+			Style := [fsItalic];
+			BeginText := '#';
+			EndText := #13;
+			Switchable := False;
+			LineStartOnly := True;
+		end;
+		with CustomStyles.Add do begin
+			Caption := 'String';
+			CustomColor := True;
+			Color := clMaroon;
+			CustomStyle := False;
+			Style := [];
+			BeginText := '"';
+			EndText := '"';
+			IgnoreChar := '\';
+			Switchable := False;
+		end;
+		with CustomStyles.Add do begin
+			Caption := 'Character';
+			CustomColor := True;
+			Color := clMaroon;
+			CustomStyle := False;
+			Style := [];
+			BeginText := '''';
+			EndText := '''';
+			IgnoreChar := '\';
+			Switchable := False;
+		end;
+		with WordLists.Add do begin
+			Caption := 'Data Movement';
+			Words.CommaText := 'EXG,LEA,LINK,MOV,MOVE,MOVEA,MOVEM,MOVEP,MOVEQ,MOVM,MOVP,MOVQ,PEA,UNLK';
+			Color := clBlue;
+			CustomColor := True;
+			CaseSensitive := False;
+		end;
+		with WordLists.Add do begin
+			Caption := 'Integer Arithmetic';
+			Words.CommaText := 'ADD,ADDA,ADDI,ADDQ,ADDX,CLR,CMP,CMPA,CMPI,CMPM,DIVS,DIVU,EXT,MULS,MULU,NEG,NEGX,SUB,SUBA,SUBI,SUBQ,SUBX';
+			Color := clBlue;
+			CustomColor := True;
+			CaseSensitive := False;
+		end;
+		with WordLists.Add do begin
+			Caption := 'Logical Instructions';
+			Words.CommaText := 'AND,ANDI,EOR,EORI,NOT,OR,ORI';
+			Color := clBlue;
+			CustomColor := True;
+			CaseSensitive := False;
+		end;
+		with WordLists.Add do begin
+			Caption := 'Shift/Rotation Instructions';
+			Words.CommaText := 'ASL,ASR,LSL,LSR,ROL,ROR,ROXL,ROXR,SWAP';
+			Color := clBlue;
+			CustomColor := True;
+			CaseSensitive := False;
+		end;
+		with WordLists.Add do begin
+			Caption := 'Bit Manipulation';
+			Words.CommaText := 'BCHG,BCLR,BSET,BTST';
+			Color := clBlue;
+			CustomColor := True;
+			CaseSensitive := False;
+		end;
+		with WordLists.Add do begin
+			Caption := 'Program Control';
+			Words.CommaText := 'BCC,BCS,BEQ,BGE,BGT,BHI,BLE,BLS,BLT,BMI,BNE,BPL,BRA,BSR,BVC,BVS,JBCC,JBCS,JBEQ,JBGE,JBGT,JBHI,JBLE,JBLS,JBLT,JBMI,JBNE,JBPL,JBRA,JBSR,JBVC,JBVS,JSR,JRA,JMP,'
+				+ 'NOP,RTR,RTS,SCC,SCS,SEQ,SF,SGE,SGT,SHI,SLE,SLS,SLT,SMI,SNE,SPL,ST,SVC,SVS,TST,'
+				+ 'JHI,JLS,JCC,JCS,JNE,JEQ,JVC,JVS,JPL,JMI,JGE,JLT,JGT,JLE,DBHI,DBLS,DBCC,DBCS,DBNE,DBEQ,DBVC,DBVS,DBPL,DBMI,DBGE,DBLT,DBGT,DBLE,DBF,DBRA,DBT,'
+				+ 'FJNE,FJEQ,FJGE,FJLT,FJGT,FJLE,FJF,FJT,FJGL,FJGLE,FJNGE,FJNGL,FJNGLE,FJNGT,FJNLE,FJNLT,FJOGE,FJOGL,FJOGT,FJOLE,FJOLT,FJOR,FJSEQ,FJSF,FJSNE,FJST,FJUEQ,FJUGE,FJUGT,FJULE,FJULT,FJUN';
+			Color := clBlue;
+			CustomColor := True;
+			CaseSensitive := False;
+		end;
+		with WordLists.Add do begin
+			Caption := 'System Control';
+			Words.CommaText := 'ILLEGAL,RTE,TRAP';
+			Color := clBlue;
+			CustomColor := True;
+			CaseSensitive := False;
+		end;
+		with WordLists.Add do begin
+			Caption := 'Extensions';
+			Words.CommaText := 'B,L,S,W';
+			Color := $408000;
+			CustomColor := True;
+			CaseSensitive := False;
+		end;
+		with WordLists.Add do begin
+			Caption := 'Assembler Directives';
+			Words.CommaText := 'abort,align,ascii,asciz,balign,balignw,balignl,byte,comm,data,'
+				+ 'def,dim,double,eject,else,end,elseif,endef,endfunc,endif,endm,endr,equ,equiv,'
+				+ 'err,even,exitm,extern,fail,file,fill,float,func,global,hword,ident,if,include,'
+				+ 'incbin,int,irp,irpc,lcomm,lflags,line,ln,list,long,macro,mri,nolist,octa,org,'
+				+ 'p2align,p2alignw,p2alignl,print,psize,purgem,quad,rept,sbttl,scl,section,set,'
+				+ 'short,single,size,sleb128,skip,space,stabd,stabn,stabs,string,struct,tag,text,'
+				+ 'title,type,uleb128,val,vtable_entry,word';
+			Color := clBlue;
+			CustomColor := True;
+			Style := [fsBold];
+			CustomStyle := True;
+			CaseSensitive := True;
+		end;
+		with WordLists.Add do begin
+			Caption := 'Registers';
+			Words.CommaText := 'a0,a1,a2,a3,a4,a5,a6,a7,d0,d1,d2,d3,d4,d5,d6,d7,fp,pc,sp,sr';
+			Color := clRed;
+			CustomColor := True;
+			Style := [fsUnderline];
+			CustomStyle := True;
+			CaseSensitive := False;
+		end;
+	end;
+	with SyntaxAsm do begin
+		NumberColor := SyntaxC.NumberColor;
+		NumberStyle := SyntaxC.NumberStyle;
+		NumberCustomStyle := SyntaxC.NumberCustomStyle;
+		SymbolColor := SyntaxC.SymbolColor;
+		SymbolStyle := SyntaxC.SymbolStyle;
+		SymbolCustomStyle := SyntaxC.SymbolCustomStyle;
+		ParenthesisColors.Assign (SyntaxC.ParenthesisColors);
+		ParenthesisStyle := SyntaxC.ParenthesisStyle;
+		ParenthesisCustomStyle := SyntaxC.ParenthesisCustomStyle;
+		with CustomStyles.Add do begin
+			Caption := 'Comment';
+			CustomColor := True;
+			Color := clGreen;
+			CustomStyle := True;
+			Style := [fsItalic];
+			BeginText := ';';
+			EndText := #13;
+			Switchable := False;
+		end;
+		with CustomStyles.Add do begin
+			Caption := 'String (double-quoted)';
+			CustomColor := True;
+			Color := clMaroon;
+			CustomStyle := False;
+			Style := [];
+			BeginText := '"';
+			EndText := '"';
+			IgnoreChar := '';
+			Switchable := False;
+		end;
+		with CustomStyles.Add do begin
+			Caption := 'String (single-quoted)';
+			CustomColor := True;
+			Color := clMaroon;
+			CustomStyle := False;
+			Style := [];
+			BeginText := '''';
+			EndText := '''';
+			IgnoreChar := '';
+			Switchable := False;
+		end;
+		with WordLists.Add do begin
+			Caption := 'Data Movement';
+			Words.CommaText := 'EXG,LEA,LINK,MOV,MOVE,MOVEA,MOVEM,MOVEP,MOVEQ,PEA,UNLK';
+			Color := clBlue;
+			CustomColor := True;
+			CaseSensitive := False;
+		end;
+		with WordLists.Add do begin
+			Caption := 'Integer Arithmetic';
+			Words.CommaText := 'ADD,ADDA,ADDI,ADDQ,ADDX,CLR,CMP,CMPA,CMPI,CMPM,DIVS,DIVU,EXT,MULS,MULU,NEG,NEGX,SUB,SUBA,SUBI,SUBQ,SUBX';
+			Color := clBlue;
+			CustomColor := True;
+			CaseSensitive := False;
+		end;
+		with WordLists.Add do begin
+			Caption := 'Logical Instructions';
+			Words.CommaText := 'AND,ANDI,EOR,EORI,NOT,OR,ORI';
+			Color := clBlue;
+			CustomColor := True;
+			CaseSensitive := False;
+		end;
+		with WordLists.Add do begin
+			Caption := 'Shift/Rotation Instructions';
+			Words.CommaText := 'ASL,ASR,LSL,LSR,ROL,ROLX,ROR,RORX,ROXL,ROXR,SWAP';
+			Color := clBlue;
+			CustomColor := True;
+			CaseSensitive := False;
+		end;
+		with WordLists.Add do begin
+			Caption := 'Bit Manipulation';
+			Words.CommaText := 'BCHG,BCLR,BSET,BTST';
+			Color := clBlue;
+			CustomColor := True;
+			CaseSensitive := False;
+		end;
+		with WordLists.Add do begin
+			Caption := 'Program Control';
+			Words.CommaText := 'BCC,BCS,BEQ,BGE,BGT,BHI,BHS,BLE,BLO,BLS,BLT,BMI,BNE,BPL,BRA,BSR,BVC,BVS,DBCC,DBCS,DBEQ,DBF,DBGE,DBGT,DBHI,DBHS,DBLE,DBLO,DBLS,DBLT,DBMI,DBNE,DBPL,DBRA,DBT,DBVC,DBVS,JMP,JSR,NOP,RTR,RTS,'
+				+ 'SCC,SCS,SEQ,SF,SGE,SGT,SHI,SHS,SLE,SLO,SLS,SLT,SMI,SNE,SPL,ST,SVC,SVS,TST';
+			Color := clBlue;
+			CustomColor := True;
+			CaseSensitive := False;
+		end;
+		with WordLists.Add do begin
+			Caption := 'System Control';
+			Words.CommaText := 'ILLEGAL,RTE,TRAP';
+			Color := clBlue;
+			CustomColor := True;
+			CaseSensitive := False;
+		end;
+		with WordLists.Add do begin
+			Caption := 'Extensions';
+			Words.CommaText := 'B,L,S,W';
+			Color := $408000;
+			CustomColor := True;
+			CaseSensitive := False;
+		end;
+		with WordLists.Add do begin
+			Caption := 'Assembler Directives';
+			Words.CommaText := 'BSS,CNOP,CSEG,DSEG,DC,DCB,DS,END,ENDC,ENDIF,ENDM,EQU,EQUR,EVEN,FAR,IDNT,IFC,IFD,IFEQ,IFGE,IFGT,IFLE,IFLT,IFNC,IFND,IFNE,INCBIN,INCLUDE,LIST,MACRO,NEAR,NOLIST,ORG,PAGE,PUBLIC,REG,RORG,SECTION,SET,SPC,TITLE,TTL,XDEF,XREF';
+			Color := clBlue;
+			CustomColor := True;
+			Style := [fsBold];
+			CustomStyle := True;
+			CaseSensitive := False;
+		end;
+		with WordLists.Add do begin
+			Caption := 'Registers';
+			Words.CommaText := 'a0,a1,a2,a3,a4,a5,a6,a7,d0,d1,d2,d3,d4,d5,d6,d7,fp,pc,sp,sr';
+			Color := clRed;
+			CustomColor := True;
+			Style := [fsUnderline];
+			CustomStyle := True;
+			CaseSensitive := False;
+		end;
+	end;
+	SyntaxQuill.Assign (SyntaxC);
+	with SyntaxQuill do begin
+		with WordLists.Add do begin
+			Caption := 'Sections';
+			Words.CommaText := '$$ACTIONS,$$CONNECTIONS,$$END,$$END_TEST,$$EVENTS,$$EXTERN,$$LOCATIONS,$$MESSAGES,$$OBJECTS,$$OLDSTYLE_SYSTEM_MESSAGES,$$PICTURES,$$PICTURES_TEST,$$SYSTEM_MESSAGES,$$TITLE,$$VOCABULARY';
+			CaseSensitive := True;
+			CustomColor := True;
+			Color := $0000FF;
+			CustomStyle := True;
+			Style := [fsBold];
+		end;
+		with WordLists.Add do begin
+			Caption := 'Section-specific Keywords';
+			Words.CommaText := 'ACTION,BITMAP,CBLOCK,CONN,DEFINE,DRAWING,END_BITMAP,END_CBLOCK,END_DRAWING,END_PACKED_BITMAP,EVENT,FROM,LOC,MSG,OBJ,PACKED_BITMAP,WORD';
+			CaseSensitive := True;
+			CustomColor := True;
+			Color := $808040;
+			CustomStyle := True;
+			Style := [fsBold];
+		end;
+		with WordLists.Add do begin
+			Caption := 'Additional Keywords';
+			Words.CommaText := 'CONTINUE,ELSE';
+			CaseSensitive := True;
+			CustomColor := True;
+			Color := $808040;
+			CustomStyle := True;
+			Style := [fsBold];
+		end;
+		with WordLists.Add do begin
+			Caption := 'Non-functional Keywords';
+			Words.CommaText := 'BEEP,BLOCK,BORDER,BRIGHT,FLASH,INK,PAPER';
+			CaseSensitive := True;
+			CustomColor := True;
+			Color := $C0C0C0;
+			CustomStyle := True;
+			Style := [fsBold];
+		end;
+		with WordLists.Add do begin
+			Caption := 'Predefined Aliases';
+			Words.CommaText := '$ALSOSEE,$ARG,$CARRIED,$CENTER,$CNT1,$CNT2,$CNT3,$CNT4,$CONT,$CURLOC,$DARK,$DARKCNT,$DESC,$DESC_CNT,$DESC_DARKCNT,$DESC_NOLIGHTCNT,$DONE,$ENDGAME,$EXIT,$FAIL,$FONT,$FULLSCR,$GCONTROL,$LSOURCE,'
+				+ '$MAXCAR,$NOLIGHTCNT,$NOUN,$NOWHERE,$NULL,$NUMCAR,$PROMPT,$RESTART,$SCORE,$SPECIAL,$SUBROUTINE,$TURNHI,$TURNLO,$VERB,$WORN';
+			CaseSensitive := True;
+			CustomColor := True;
+			Color := $800080;
+			CustomStyle := True;
+			Style := [fsBold];
+		end;
+		with WordLists.Add do begin
+			Caption := 'Conditions';
+			Words.CommaText := 'ABSENT,AT,ATGT,ATLT,CARRIED,CHANCE,CREATED,EQ,EQWORD,EXTWORD,GT,HERE,ISAT,ISDESC,ISNOTAT,ISNOTNULL,ISNULL,LT,NEQWORD,NOTAT,NOTCARR,NOTCREATED,NOTEQ,NOTHERE,NOTSAME,NOTWORN,NOTZERO,PRESENT,SAME,TRYMOVE,WORN,ZERO';
+			CaseSensitive := True;
+			CustomColor := True;
+			Color := $FF0000;
+			CustomStyle := True;
+			Style := [fsBold];
+		end;
+		with WordLists.Add do begin
+			Caption := 'Actions';
+			Words.CommaText := 'ADD,ALSOSEE,ANYKEY,AUTOD,AUTOG,AUTOR,AUTOW,BIGFONT,CANCEL,CLEAR,CLS,COPYFF,COPYFO,COPYOF,COPYOO,CREATE,DECCAR,DESC,DESTROY,DONE,DROP,DROPALL,END,ENDDESC,EXIT,EXTERN,GET,GETWORD,GOTO,INCCAR,INVEN,LET,'
+				+ 'LISTAT,LISTOBJ,LOAD,MAXCAR,MES,MESFLAG,MESSAGE,MINUS,NEWLINE,NOTDONE,OK,PAUSE,PICNORM,PICOFF,PICON,PLACE,PLUS,PRINT,PROMPT,PUTO,QUIT,QVERSION,RAMLOAD,RAMSAVE,RANDOM,REDRAW,REMOVE,RESTART,SAVE,SCORE,'
+				+ 'SET,SETNOUN,SETVERB,SHOWLOC,SMLFONT,SUB,SWAP,SYSMESS,TURNS,WEAR,WHATO,WHEREO,ZAPSCR';
+			CaseSensitive := True;
+			CustomColor := True;
+			Color := $A00000;
+			CustomStyle := True;
+			Style := [fsBold];
+		end;
+		with WordLists.Add do begin
+			Caption := 'Drawing Primitives';
+			Words.CommaText := 'AMOVE,CALL,ELLIPSE,FILL,INV_ELLIPSE,INV_LINE,INV_PLOT,INV_RPLOT,LINE,MOVE,PLOT,RPLOT,SHADE,XOR_ELLIPSE,XOR_LINE,XOR_PLOT,XOR_RPLOT';
+			CaseSensitive := True;
+			CustomColor := True;
+			Color := $FF8000;
+			CustomStyle := True;
+			Style := [fsBold];
+		end;
+		with WordLists.Add do begin
+			Caption := 'Drawing Directions';
+			Words.CommaText := 'DOWN,DOWN_LEFT,DOWN_RIGHT,LEFT,LEFT_DOWN,LEFT_UP,RIGHT,RIGHT_DOWN,RIGHT_UP,UP,UP_LEFT,UP_RIGHT';
+			CaseSensitive := True;
+			CustomColor := True;
+			Color := $008000;
+			CustomStyle := True;
+			Style := [fsBold];
+		end;
+		with WordLists.Add do begin
+			Caption := 'Shading Patterns';
+			Words.CommaText := '$BKSLASHFILL,$BRICKFILL,$CHAINFILL,$CIRCLEFILL,$CLOSEDASHFILL,$CLOSEDOTFILL,$CLOSEWAVEFILL,$CROSSFILL,$DASHFILL,$DOTFILL,$HATCHFILL,$INTERLEAVEFILL,$LIGHTDOTFILL,$LIGHTLINEFILL,$LINEFILL,$SLASHFILL,'
+				+ '$SOLIDFILL,$SQDOTFILL,$SQUAREFILL,$THICKBKSLASHFILL,$THICKHATCHFILL,$THICKLINEFILL,$THICKSLASHFILL,$VDASHFILL,$VINTERLEAVEFILL,$VLDOTFILL,$VLIGHTLINEFILL,$VLINEFILL,$VTHICKLINEFILL,$WAVEFILL,$WIDEDOTFILL,$XMARKFILL,$ZIGZAGFILL';
+			CaseSensitive := True;
+			CustomColor := True;
+			Color := $800080;
+			CustomStyle := True;
+			Style := [fsBold];
+		end;
+		with WordLists.Add do begin
+			Caption := 'External Symbols';
+			Words.CommaText := '$ACTIONS$,$ARG$,$BMPUT$,$BPCKPUT$,$BUFFER$,$CONNECTIONS$,$EVENTS$,$EXTERN$,$FLAGS$,$FLAGS_BACKUP$,$GDF$,$GETLINE$,$LOCATIONS$,$LQL$,$MAXCAR$,$MESSAGES$,$NFLAG$,$NLOC$,$NMSG$,$NOBJ$,$NSYSMSG$,$NWORD$,'
+				+ '$OBJECTS$,$PDRAW$,$PICTURE$,$PRINT$,$RAM_SAVED$,$SCALEX$,$SCALEY$,$SSCR$,$SYSTEM_MESSAGES$,$WORDS$';
+			CaseSensitive := True;
+			CustomColor := True;
+			Color := $408000;
+			CustomStyle := True;
+			Style := [fsBold];
+		end;
+	end;
+	EditorFont.Name := 'Courier New';
+	EditorFont.Size := 10;
+	EditorColor := clWindow;
+	DecimalSeparator := '.';
+finalization
+	EditorFont.Free;
+	SyntaxQuill.Free;
+	SyntaxAsm.Free;
+	SyntaxAsmGNU.Free;
+	SyntaxC.Free;
+	MainConsole.Free;
+	PredefinedLibOptions.Free;
+end.

BIN
NewFolderUnit.dfm


+ 33 - 0
NewFolderUnit.pas

@@ -0,0 +1,33 @@
+unit NewFolderUnit;
+
+interface
+
+uses
+  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+  StdCtrls, ExtCtrls;
+
+type
+  TNewFolderForm = class(TForm)
+    Label1: TLabel;
+    InputBox: TEdit;
+    Bevel1: TBevel;
+    ButtonOK: TButton;
+    ButtonCancel: TButton;
+    procedure InputBoxChange(Sender: TObject);
+  private
+	public
+	end;
+
+var
+  NewFolderForm: TNewFolderForm;
+
+implementation
+
+{$R *.DFM}
+
+procedure TNewFolderForm.InputBoxChange(Sender: TObject);
+begin
+	ButtonOK.Enabled := InputBox.Text <> '';
+end;
+
+end.

BIN
NewsUnit.dfm


+ 250 - 0
NewsUnit.pas

@@ -0,0 +1,250 @@
+unit NewsUnit;
+
+interface
+
+uses
+	Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+	ScktComp, StdCtrls;
+
+const
+	NewsID = 'TIGCC News Format'#13#10#13#10;
+
+type
+	TNewsForm = class(TForm)
+		NewsClient: TClientSocket;
+		NewsBox: TScrollBox;
+		VisitButton: TButton;
+		CloseButton: TButton;
+		RetreiveLabel: TLabel;
+    ProxyCheckBox: TCheckBox;
+    ProxyNameEdit: TEdit;
+    Label1: TLabel;
+    ProxyPortEdit: TEdit;
+    RefreshButton: TButton;
+		procedure NewsClientError(Sender: TObject; Socket: TCustomWinSocket;
+			ErrorEvent: TErrorEvent; var ErrorCode: Integer);
+		procedure FormActivate(Sender: TObject);
+		procedure FormClose(Sender: TObject; var Action: TCloseAction);
+		procedure NewsClientConnect(Sender: TObject; Socket: TCustomWinSocket);
+		procedure NewsClientRead(Sender: TObject; Socket: TCustomWinSocket);
+		procedure ProxyCheckBoxClick(Sender: TObject);
+    procedure RefreshButtonClick(Sender: TObject);
+    procedure FormCreate(Sender: TObject);
+	private
+		FSilentConnect: Boolean;
+	public
+		Labels: array of TLabel;
+		procedure Connect;
+		function Execute: Boolean;
+		property SilentConnect: Boolean read FSilentConnect write FSilentConnect;
+	end;
+
+implementation
+
+{$R *.DFM}
+
+uses
+	MasterUnit, MainUnit,
+	UtilsWin,
+	ShellAPI, Registry;
+
+procedure TNewsForm.Connect;
+var
+	I: Integer;
+begin
+	if not NewsClient.Active then begin
+		for I := High (Labels) downto Low (Labels) do
+			Labels[I].Free;
+		SetLength (Labels, 0);
+		RetreiveLabel.Show;
+		Update;
+		try
+			with NewsClient do begin
+				if ProxyCheckBox.Checked then begin
+					Host := '';
+					Address := '';
+					if (Pos ('.', ProxyNameEdit.Text) > 0) and (ProxyNameEdit.Text [1] in ['0'..'9']) then
+						Address := ProxyNameEdit.Text
+					else
+						Host := ProxyNameEdit.Text;
+					try
+						Port := StrToInt (ProxyPortEdit.Text);
+					except
+						Port := 8080;
+					end;
+				end else begin
+					Address := '';
+					Host := 'tigcc.ticalc.org';
+					Port := 80;
+				end;
+				NewsClient.Active := True;
+			end;
+		except
+			RetreiveLabel.Hide;
+			ShowDefaultMessageBox ('Error connecting to tigcc.ticalc.org. Please check your connection.', 'Error', mtProgramError);
+			if not Visible then
+				Free;
+		end;
+	end;
+end;
+
+function TNewsForm.Execute: Boolean;
+begin
+	Result := ShowModal = mrOK;
+	if Result then
+		ShellExecute (0, nil, 'http://tigcc.ticalc.org/', nil, nil, sw_ShowMaximized);
+end;
+
+procedure TNewsForm.NewsClientError(Sender: TObject;
+	Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
+	var ErrorCode: Integer);
+begin
+	NewsClient.Active := False;
+	RetreiveLabel.Hide;
+	ShowDefaultMessageBox ('Error downloading news from tigcc.ticalc.org. Please check your connection.', 'Error', mtProgramError);
+	if not Visible then
+		Free;
+end;
+
+procedure TNewsForm.FormActivate(Sender: TObject);
+begin
+	if not SilentConnect then
+		Connect;
+end;
+
+procedure TNewsForm.FormClose(Sender: TObject; var Action: TCloseAction);
+begin
+	NewsClient.Active := False;
+	ProxyName := ProxyNameEdit.Text;
+	try
+		if Length (ProxyPortEdit.Text) > 0 then
+			ProxyPort := StrToInt (ProxyPortEdit.Text)
+		else
+			ProxyPort := 0;
+	except end;
+end;
+
+procedure TNewsForm.NewsClientConnect(Sender: TObject;
+	Socket: TCustomWinSocket);
+var
+	Line: string;
+begin
+	Line := 'GET http://tigcc.ticalc.org/newsheadlines.txt';
+	if ProxyCheckBox.Checked then
+		Line := Line + ' HTTP/1.1'#13#10'Accept: */*'#13#10'Accept-Language: en'#13#10'User-Agent: TIGCC'#13#10'Host: tigcc.ticalc.org'#13#10'Proxy-Connection: Keep-Alive'#13#10;
+	Line := Line + #13#10;
+	Socket.SendText (Line);
+end;
+
+procedure TNewsForm.NewsClientRead(Sender: TObject;
+	Socket: TCustomWinSocket);
+var
+	S: string;
+	Date,
+	LastDate: Integer;
+	CurLabel: TLabel;
+begin
+	RetreiveLabel.Hide;
+	S := Socket.ReceiveText;
+	NewsClient.Active := False;
+	if Pos (NewsID, S) > 0 then begin
+		LastDate := 0;
+		Delete (S, 1, Pos (NewsID, S) - 1 + Length (NewsID));
+		while Pos (#13#10, S) > 0 do begin
+			if S [1] = #13 then
+				Break;
+			CurLabel := TLabel.Create (Self);
+			CurLabel.Left := 2;
+			if Length (Labels) > 0 then
+				with Labels [High (Labels)] do
+					CurLabel.Top := Top + Height + 2
+			else
+				CurLabel.Top := 0;
+			try
+				Date := StrToInt (Copy (S, 1, Pos (#13#10, S) - 1));
+				if LastDate = 0 then
+					LastDate := Date;
+			except
+				Date := 0;
+			end;
+			Delete (S, 1, Pos (#13#10, S) + 1);
+			with CurLabel.Font do begin
+				Name := 'Arial';
+				Size := 9;
+				Style := [fsBold];
+				if Date > LastNewsDate then
+					Color := $0000C0
+				else
+					Color := $808080;
+			end;
+			CurLabel.Caption := Copy (S, 1, Pos (#13#10, S) - 1);
+			Delete (S, 1, Pos (#13#10, S) + 1);
+			Delete (S, 1, Pos (#13#10, S) + 1);
+			CurLabel.Parent := NewsBox;
+			CurLabel.Show;
+			SetLength (Labels, Length (Labels) + 1);
+			Labels [High (Labels)] := CurLabel;
+		end;
+		if (LastDate > LastNewsDate) and (not Visible) then
+			Execute;
+		if LastNewsDate <> LastDate then begin
+			LastNewsDate := LastDate;
+			MainForm.SavePreferences;
+		end;
+	end else
+		ShowDefaultMessageBox ('Error in news format from tigcc.ticalc.org. Please contact the site administrator.', 'Error', mtProgramError);
+	if not Visible then
+		Free;
+end;
+
+procedure TNewsForm.ProxyCheckBoxClick(Sender: TObject);
+var
+	NewProxy: string;
+begin
+	ProxyNameEdit.Enabled := ProxyCheckBox.Checked;
+	ProxyPortEdit.Enabled := ProxyCheckBox.Checked;
+	if ProxyCheckBox.Checked then begin
+		with TRegistry.Create do try
+			RootKey := HKEY_CURRENT_USER;
+			if OpenKeyReadOnly ('\Software\Microsoft\Windows\CurrentVersion\Internet Settings') then begin
+				if ValueExists ('ProxyServer') then begin
+					NewProxy := ReadString ('ProxyServer');
+					if Pos ('http=', LowerCase (NewProxy)) > 0 then begin
+						Delete (NewProxy, 1, Pos ('http=', LowerCase (NewProxy)) - 1 + Length ('http='));
+						if Pos (';', NewProxy) > 0 then
+							Delete (NewProxy, Pos (';', NewProxy), Length (NewProxy));
+					end else
+						if Pos (';', NewProxy) > 0 then
+							NewProxy := '';
+					if Pos (':', NewProxy) > 0 then begin
+						ProxyNameEdit.Text := Copy (NewProxy, 1, Pos (':', NewProxy) - 1);
+						ProxyPortEdit.Text := Copy (NewProxy, Pos (':', NewProxy) + 1, Length (NewProxy));
+					end;
+				end;
+			end;
+		finally
+			Free;
+		end;
+	end else begin
+		ProxyNameEdit.Text := '';
+		ProxyPortEdit.Text := '';
+	end;
+end;
+
+procedure TNewsForm.RefreshButtonClick(Sender: TObject);
+begin
+	NewsClient.Active := False;
+	Connect;
+end;
+
+procedure TNewsForm.FormCreate(Sender: TObject);
+begin
+	ProxyCheckBox.Checked := Length (ProxyName) > 0;
+	ProxyNameEdit.Text := ProxyName;
+	if ProxyCheckBox.Checked then
+		ProxyPortEdit.Text := IntToStr (ProxyPort)
+	else
+		ProxyPortEdit.Text := '';
+end;
+
+end.

BIN
OpenFileStatusUnit.dfm


+ 33 - 0
OpenFileStatusUnit.pas

@@ -0,0 +1,33 @@
+unit OpenFileStatusUnit;
+
+interface
+
+uses
+  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+  ComCtrls, StdCtrls, ExtCtrls;
+
+type
+	TOpenFileStatusForm = class(TForm)
+    FileAnimate: TAnimate;
+    FileNameLabel: TPanel;
+    procedure FormCreate(Sender: TObject);
+    procedure FormDestroy(Sender: TObject);
+  private
+	public
+	end;
+
+implementation
+
+{$R *.DFM}
+
+procedure TOpenFileStatusForm.FormCreate(Sender: TObject);
+begin
+	Screen.Cursor := crHourglass;
+end;
+
+procedure TOpenFileStatusForm.FormDestroy(Sender: TObject);
+begin
+	Screen.Cursor := crDefault;
+end;
+
+end.

+ 598 - 0
ParsingUnit.pas

@@ -0,0 +1,598 @@
+unit ParsingUnit;
+
+interface
+
+uses
+	CalcUnit,
+	SysUtils, Classes;
+
+const
+	LineIndicator = '#L';
+	OffsetIndicator = '#$';
+	PatchToken = '$$PATCH';
+	ErrorToken = '$$ERROR';
+	WarningToken = '$$WARNING';
+	ALineIdentifier = '_A_LINE';
+	FLineIdentifier = '_F_LINE';
+	SParseError = 'Line %d: Parse error before ''%s''';
+
+type
+	EFileParseError = class(Exception);
+
+	PBoolean = ^Boolean;
+
+	TLineChangeEvent = procedure(StartLine, Change: Integer) of object;
+	TLineContentsEvent = function(StartLine, EndLine: Integer): string of object;
+
+type
+	TCalcInt1 = packed record
+		Int: Byte;
+	end;
+	PCalcInt1 = ^TCalcInt1;
+
+	TCalcInt2 = packed record
+		Hi,
+		Lo: TCalcInt1;
+	end;
+	PCalcInt2 = ^TCalcInt2;
+
+	TCalcInt4 = packed record
+		Hi,
+		Lo: TCalcInt2;
+	end;
+	PCalcInt4 = ^TCalcInt4;
+
+	TPCInt1 = packed record
+		Int: Byte;
+	end;
+	PPCInt1 = ^TPCInt1;
+
+	TPCInt2 = packed record
+		Lo,
+		Hi: TPCInt1;
+	end;
+	PPCInt2 = ^TPCInt2;
+
+	TPCInt4 = packed record
+		Lo,
+		Hi: TPCInt2;
+	end;
+	PPCInt4 = ^TPCInt4;
+
+function ReadCalcInt(Int: TCalcInt1): Byte; overload;
+function ReadCalcInt(Int: TCalcInt2): Word; overload;
+function ReadCalcInt(Int: TCalcInt4): LongWord; overload;
+
+procedure WriteCalcInt(Input: Byte; out Int: TCalcInt1); overload;
+procedure WriteCalcInt(Input: Word; out Int: TCalcInt2); overload;
+procedure WriteCalcInt(Input: LongWord; out Int: TCalcInt4); overload;
+
+function ReadPCInt(Int: TPCInt1): Byte; overload;
+function ReadPCInt(Int: TPCInt2): Word; overload;
+function ReadPCInt(Int: TPCInt4): LongWord; overload;
+
+procedure WritePCInt(Input: Byte; out Int: TPCInt1); overload;
+procedure WritePCInt(Input: Word; out Int: TPCInt2); overload;
+procedure WritePCInt(Input: LongWord; out Int: TPCInt4); overload;
+
+type
+	TTFRes2 = array [0..1] of Byte;
+	TTFRes3 = array [0..2] of Byte;
+	TTFRes6 = array [0..5] of Byte;
+
+	TTransferFileHeader = packed record
+		Signature: array [0..7] of Char;  // "**TI92P*" or "**TI89**"
+		Reserved1: TTFRes2;               // 01 00
+		Folder: array [0..7] of Char;     // folder name
+		Desc: array [0..39] of Char;      // not used
+		Reserved2: TTFRes6;               // 01 00 52 00 00 00
+		VarName: array [0..7] of Char;    // variable name
+		LinkType: TPCInt1;                // variable link type (0C = string, 1C = other, 21 = program, ...)
+		Reserved3: TTFRes3;               // 00 00 00
+		FileSize: TPCInt4;                // file size from Signature to CheckSum
+		Reserved4: TTFRes6;               // A5 5A 00 00 00 00
+	end;
+	PTransferFileHeader = ^TTransferFileHeader;
+
+	TCalcVarHeader = packed record
+		DataSize: TCalcInt2;              // data size (including Tag)
+	end;
+	PCalcVarHeader = ^TCalcVarHeader;
+
+	TCalcVarFooter = packed record
+		Tag: TCalcInt1;                   // variable tag
+	end;
+	PCalcVarFooter = ^TCalcVarFooter;
+
+	TTransferFileFooter = packed record
+		CheckSum: TPCInt2;                // checksum from DataSize to Tag
+	end;
+	PTransferFileFooter = ^TTransferFileFooter;
+
+	TCalcOSFooter = packed record
+		CheckSum: TCalcInt4;              // encrypted checksum
+		SignatureHeader: TCalcInt2;       // 02 0D
+		SignatureType: TCalcInt1;         // 40
+		Signature: array [0..63] of Byte; // signature, encrypted using TI's private key
+	end;
+	PCalcOSFooter = ^TCalcOSFooter;
+
+	PBinData = PChar;
+
+const
+	MaxCalcAllocBlock = $FFF0;
+
+procedure ParseSFile(Contents: TStringList);
+procedure ParseDebugSFile(Contents: TStringList; OnLineChange: TLineChangeEvent; LineContents: TStringList; OnGetLineContents: TLineContentsEvent);
+procedure ParsePStarter(const InputFile: string; const OutputFile: string; const PackVar: string);
+
+procedure ParseDebugSFileDisk(Contents: TStringList; const SourceFileName: string);
+
+function GetCalcVarSize(ContentLength: LongWord; const Extension: string = ''): LongWord;
+function GetTransferFileSize(ContentLength: LongWord; const Extension: string = ''; OutputBin: Boolean = False): LongWord;
+procedure ProduceTransferFile(Output: Pointer; Contents: Pointer; ContentLength: LongWord; CalcDest: TCalcDest; const DestFolder, DestVarName: string; VarTag: Byte; const Extension: string = ''; OutputBin: Boolean = False);
+function GetTransferFileExt(CalcDest: TCalcDest; VarTag: Byte; OutputBin: Boolean = False): string;
+function GetOSUpgradeFileSize(ContentLength: LongWord; OutputBin: Boolean = True): LongWord;
+procedure ProduceOSUpgradeFile(Output: Pointer; Contents: Pointer; ContentLength: LongWord; OutputBin: Boolean = True);
+function GetOSUpgradeFileExt(CalcDest: TCalcDest; OutputBin: Boolean = False): string;
+
+var
+	ErrorMessageProc: procedure(const Msg: string) = nil;
+
+implementation
+
+uses
+	Windows, UtilsDos;
+
+{ General parsing procedures }
+
+procedure ParseSFile(Contents: TStringList);
+var
+	I,
+	P1,
+	P2: Integer;
+	RegRelative,
+	NeedFLine,
+	Changed: Boolean;
+	L: string;
+begin
+	RegRelative := False;
+	NeedFLine := False;
+	with Contents do begin
+		for I := 0 to Count - 1 do begin
+			L := Strings [I];
+			if L = #9'.set __relation,__ld_entry_point_plus_0x8000' then
+				RegRelative := True;
+			if Pos (FLineIdentifier, L) > 0 then
+				NeedFLine := True;
+			if RegRelative then begin
+				P1 := Pos ('-__relation', L);
+				while P1 > 0 do begin
+					P2 := PosEx ('_CALL_', L, P1, True);
+					if (P2 > 0) and (P2 < P1) and (P1 - P2 <= Length ('_CALL_') + 4) then begin
+						System.Delete (L, P1, Length ('-__relation') + 1);
+						while (Length (L) > 0) and (L [P1] <> ')') do
+							System.Delete (L, P1, 1);
+						System.Delete (L, P1, 1);
+						Strings [I] := L;
+					end;
+					P2 := PosEx ('_ER_CODE_', L, P1, True);
+					if (P2 > 0) and (P2 < P1) and (P1 - P2 <= Length ('_ER_CODE_') + 5) then begin
+						System.Delete (L, P1, Length ('-__relation') + 1);
+						while (Length (L) > 0) and (L [P1] <> ')') do
+							System.Delete (L, P1, 1);
+						System.Delete (L, P1, 1);
+						Strings [I] := L;
+					end;
+					P1 := PosEx ('-__relation', L, P1 + 1);
+				end;
+			end;
+			if (Copy (L, 1, Length (#9'jra _ER_CODE_')) = #9'jra _ER_CODE_') or (Copy (L, 1, Length (#9'jmp _ER_CODE_')) = #9'jmp _ER_CODE_') then begin
+				System.Delete (L, 1, Length (#9'jxx _ER_CODE_'));
+				if Length (L) <= 4 then
+					Strings [I] := #9'.word _A_LINE+' + L;
+			end else begin
+				Changed := True;
+				if (Copy (L, 1, Length (#9'jbsr')) = #9'jbsr') and (Pos ('_CALL_', L) > 0) then
+					System.Delete (L, 1 + Length (#9'j'), Length ('b'))
+				else if (Copy (L, 1, Length (#9'jra')) = #9'jra') and (Pos ('_CALL_', L) > 0) then begin
+					System.Delete (L, 1, Length (#9'jra'));
+					L := #9'jmp' + L;
+				end else if Copy (L, 1, Length (#9'move.l #__ld_calc_const_')) = #9'move.l #__ld_calc_const_' then
+					L [1 + Length (#9'move.')] := 'w'
+				else
+					Changed := False;
+				if NeedFLine and (Copy (L, 1, Length (#9'jsr _ROM_CALL_')) = #9'jsr _ROM_CALL_') then begin
+					System.Delete (L, 1, Length (#9'jsr _ROM_CALL_'));
+					if Length (L) <= 3 then
+						Strings [I] := #9'.word _F_LINE+0x' + L;
+				end else begin
+					P1 := Pos ('_ROM_CALL_', L);
+					while P1 > 0 do begin
+						P2 := P1;
+						Inc (P1, Length ('_ROM_CALL_'));
+						while (P1 <= Length (L)) and (L [P1] in ['0'..'9', 'a'..'z', 'A'..'Z', '_', '+', '-', '*', '/']) do
+							Inc (P1);
+						while (P1 <= Length (L)) and (L [P1] in [':', 'a'..'z', 'A'..'Z']) do
+							System.Delete (L, P1, 1);
+						System.Insert (':l', L, P1);
+						Inc (P1, Length (':l'));
+						if LowerCase (Copy (L, P1, Length ('(%pc)'))) = '(%pc)' then
+							System.Delete (L, P1, Length ('(%pc)'))
+						else if (LowerCase (Copy (L, P1, Length (',%pc)'))) = ',%pc)') and (P2 - 1 > 0) and (L [P2 - 1] = '(') then begin
+							System.Delete (L, P1, Length (',%pc)'));
+							System.Delete (L, P2 - 1, 1);
+						end;
+						Changed := True;
+						P1 := PosEx ('_ROM_CALL_', L, P1);
+					end;
+					P1 := Pos ('__ld_calc_const_', L);
+					while P1 > 0 do begin
+						P2 := P1;
+						Inc (P1, Length ('__ld_calc_const_'));
+						while (P1 <= Length (L)) and (L [P1] in ['0'..'9', 'a'..'z', 'A'..'Z', '_', ':']) do
+							Inc (P1);
+						if LowerCase (Copy (L, P1, Length ('(%pc)'))) = '(%pc)' then begin
+							System.Delete (L, P1, Length ('(%pc)'));
+							Changed := True;
+						end else if (LowerCase (Copy (L, P1, Length (',%pc)'))) = ',%pc)') and (P2 - 1 > 0) and (L [P2 - 1] = '(') then begin
+							System.Delete (L, P1, Length (',%pc)'));
+							System.Delete (L, P2 - 1, 1);
+							Changed := True;
+						end;
+						P1 := PosEx ('__ld_calc_const_', L, P1);
+					end;
+					if Changed then
+						Strings [I] := L;
+				end;
+			end;
+		end;
+	end;
+end;
+
+procedure ParseDebugSFile(Contents: TStringList; OnLineChange: TLineChangeEvent; LineContents: TStringList; OnGetLineContents: TLineContentsEvent);
+function GetLineContents(StartLine, EndLine: Integer): string;
+var
+	I: Integer;
+begin
+	if Assigned (OnGetLineContents) then
+		Result := OnGetLineContents (StartLine, EndLine)
+	else if Assigned (LineContents) then begin
+		Result := '';
+		for I := StartLine - 1 to EndLine - 1 do
+			if (I >= 0) and (I < LineContents.Count) then
+				Insert (LineContents.Strings [I] + #13#10, Result, Length (Result) + 1);
+		Delete (Result, Length (Result) - 1, 2);
+	end else
+		Result := '';
+end;
+var
+	I,
+	P,
+	LastLine,
+	RecontinueLine,
+	LastDebugLine,
+	CurDebugLine: Integer;
+	S: string;
+begin
+	LastLine := -1;
+	LastDebugLine := -1;
+	RecontinueLine := -1;
+	I := 0;
+	with Contents do
+		while I <= Count do begin
+			if (I < Count) and (Copy (Strings [I], 1, Length (#9'.def'#9)) = #9'.def'#9) then begin
+				Delete (I);
+				if Assigned (OnLineChange) then
+					OnLineChange (I, -1);
+				Dec (I);
+			end else if (I >= Count) or (Copy (Strings [I], 1, Length (#9'.ln'#9)) = #9'.ln'#9) then begin
+				if I < Count then begin
+					S := Strings [I];
+					System.Delete (S, 1, Length (#9'.ln'#9));
+					try
+						CurDebugLine := StrToInt (S);
+					except
+						CurDebugLine := LastDebugLine;
+					end;
+					System.Insert (LineIndicator, S, 1);
+					System.Insert (#9, S, Length (S) + 1);
+					Strings [I] := S;
+				end else
+					CurDebugLine := LastDebugLine + 1;
+				if (LastLine >= 0) and (CurDebugLine >= 0) then begin
+					S := Strings [LastLine];
+					if CurDebugLine < LastDebugLine then begin
+						System.Insert (StringReplace (Trim (GetLineContents (LastDebugLine, LastDebugLine)), #9, '', [rfReplaceAll]) + ' ...', S, Length (S) + 1);
+						RecontinueLine := LastDebugLine;
+					end else begin
+						if (RecontinueLine >= 0) and (CurDebugLine >= RecontinueLine) then begin
+							System.Insert (StringReplace (Trim (GetLineContents (LastDebugLine, LastDebugLine)) + ' ...', #9, '', [rfReplaceAll]), S, Length (S) + 1);
+							RecontinueLine := -1;
+						end else
+							System.Insert (StringReplace (Trim (GetLineContents (LastDebugLine, CurDebugLine - 1)), #9, '', [rfReplaceAll]), S, Length (S) + 1);
+					end;
+					repeat
+						P := Pos (#10, S);
+						if P <= 0 then
+							P := Pos (#13, S);
+						if P > 0 then
+							S [P] := ' ';
+					until P <= 0;
+					Strings [LastLine] := S;
+				end;
+				LastLine := I;
+				LastDebugLine := CurDebugLine;
+			end;
+			Inc (I);
+		end;
+end;
+
+procedure ParsePStarter(const InputFile: string; const OutputFile: string; const PackVar: string);
+const
+	TempProg = 'TEMPPROG';
+var
+	I: Integer;
+	ObjectFile: TMemoryStream;
+	Buf: PChar;
+	Len: Integer;
+	TempBuf: array [0..Length(TempProg)] of Char;
+begin
+	TempBuf [Length (TempProg)] := #0;
+	ObjectFile := TMemoryStream.Create;
+	try
+		ObjectFile.LoadFromFile (InputFile);
+		Buf := ObjectFile.Memory;
+		Len := ObjectFile.Size;
+		for I := 0 to Len - Length (TempProg) do
+			if UpCase (Buf [I]) = TempProg [1] then begin
+				Move (Buf [I], TempBuf, Length (TempProg));
+				if UpperCase (AnsiString (TempBuf)) = TempProg then begin
+					FillChar (Buf [I], Length (TempProg), 0);
+					StrPLCopy (PChar (@(Buf [I])), LowerCase (PackVar), Length (TempProg));
+					Break;
+				end;
+			end;
+		ObjectFile.SaveToFile (OutputFile);
+	finally
+		ObjectFile.Free;
+	end;
+end;
+
+procedure ParseDebugSFileDisk(Contents: TStringList; const SourceFileName: string);
+var
+	L: TStringList;
+begin
+	L := TStringList.Create;
+	with L do try
+		LoadFromFile (SourceFileName);
+		ParseDebugSFile (Contents, nil, L, nil);
+	finally
+		Free;
+	end;
+end;
+
+{ Functions to read integers machine-independently }
+
+function ReadCalcInt(Int: TCalcInt1): Byte;
+begin
+	Result := Int.Int;
+end;
+
+function ReadCalcInt(Int: TCalcInt2): Word;
+begin
+	Result := ReadCalcInt (Int.Hi) shl (SizeOf (Int.Lo) * 8) or ReadCalcInt (Int.Lo);
+end;
+
+function ReadCalcInt(Int: TCalcInt4): LongWord;
+begin
+	Result := ReadCalcInt (Int.Hi) shl (SizeOf (Int.Lo) * 8) or ReadCalcInt (Int.Lo);
+end;
+
+function ReadPCInt(Int: TPCInt1): Byte;
+begin
+	Result := Int.Int;
+end;
+
+function ReadPCInt(Int: TPCInt2): Word;
+begin
+	Result := ReadPCInt (Int.Hi) shl (SizeOf (Int.Lo) * 8) or ReadPCInt (Int.Lo);
+end;
+
+function ReadPCInt(Int: TPCInt4): LongWord;
+begin
+	Result := ReadPCInt (Int.Hi) shl (SizeOf (Int.Lo) * 8) or ReadPCInt (Int.Lo);
+end;
+
+{ Functions to write integers machine-independently }
+
+procedure WriteCalcInt(Input: Byte; out Int: TCalcInt1);
+begin
+	Int.Int := Input;
+end;
+
+procedure WriteCalcInt(Input: Word; out Int: TCalcInt2);
+begin
+	WriteCalcInt (Byte (Input shr (SizeOf (Int.Lo) * 8)), Int.Hi);
+	WriteCalcInt (Byte (Input), Int.Lo);
+end;
+
+procedure WriteCalcInt(Input: LongWord; out Int: TCalcInt4);
+begin
+	WriteCalcInt (Word (Input shr (SizeOf (Int.Lo) * 8)), Int.Hi);
+	WriteCalcInt (Word (Input), Int.Lo);
+end;
+
+procedure WritePCInt(Input: Byte; out Int: TPCInt1);
+begin
+	Int.Int := Input;
+end;
+
+procedure WritePCInt(Input: Word; out Int: TPCInt2);
+begin
+	WritePCInt (Byte (Input shr (SizeOf (Int.Lo) * 8)), Int.Hi);
+	WritePCInt (Byte (Input), Int.Lo);
+end;
+
+procedure WritePCInt(Input: LongWord; out Int: TPCInt4);
+begin
+	WritePCInt (Word (Input shr (SizeOf (Int.Lo) * 8)), Int.Hi);
+	WritePCInt (Word (Input), Int.Lo);
+end;
+
+{ Calculator file creation functions }
+
+function GetCalcVarSize(ContentLength: LongWord; const Extension: string = ''): LongWord;
+begin
+	Result := SizeOf (TCalcVarHeader) + ContentLength + SizeOf (TCalcVarFooter);
+	if Length (Extension) > 0 then
+		Inc (Result, Length (Extension) + 2);
+	if Result > MaxCalcAllocBlock then
+		Result := 0;
+end;
+
+function GetTransferFileSize(ContentLength: LongWord; const Extension: string = ''; OutputBin: Boolean = False): LongWord;
+begin
+	Result := GetCalcVarSize (ContentLength, Extension);
+	if (Result > 0) and (not OutputBin) then
+		Inc (Result, SizeOf (TTransferFileHeader) + SizeOf (TTransferFileFooter));
+end;
+
+procedure ProduceTransferFile(Output: Pointer; Contents: Pointer; ContentLength: LongWord; CalcDest: TCalcDest; const DestFolder, DestVarName: string; VarTag: Byte; const Extension: string = ''; OutputBin: Boolean = False);
+const
+	Res1: TTFRes2 = ($01, $00);
+	Res2: TTFRes6 = ($01, $00, $52, $00, $00, $00);
+	Res3: TTFRes3 = ($00, $00, $00);
+	Res4: TTFRes6 = ($A5, $5A, $00, $00, $00, $00);
+var
+	Size,
+	CalcSize: LongWord;
+	Header: PTransferFileHeader;
+	CalcHeader: PCalcVarHeader;
+	CalcFooter: PCalcVarFooter;
+	Footer: PTransferFileFooter;
+	Data: Pointer;
+	VarLinkType: Byte;
+	I,
+	Sum: Word;
+begin
+	CalcSize := GetCalcVarSize (ContentLength, Extension);
+	Size := GetTransferFileSize (ContentLength, Extension, OutputBin);
+	if Size > 0 then begin
+		FillChar (Output^, Size, 0);
+		if OutputBin then begin
+			CalcHeader := Output;
+			CalcFooter := Pointer (@(PBinData(Output) [Size - SizeOf (TCalcVarFooter)]));
+			Data := @(PBinData(Output) [SizeOf (TCalcVarHeader)]);
+		end else begin
+			CalcHeader := Pointer (@(PBinData(Output) [SizeOf (TTransferFileHeader)]));
+			CalcFooter := Pointer (@(PBinData(Output) [Size - SizeOf (TTransferFileFooter) - SizeOf (TCalcVarFooter)]));
+			Data := @(PBinData(Output) [SizeOf (TTransferFileHeader) + SizeOf (TCalcVarHeader)]);
+		end;
+		WriteCalcInt (CalcSize - SizeOf (TCalcInt2), CalcHeader.DataSize);
+		Move (Contents^, Data^, ContentLength);
+		if Length (Extension) > 0 then
+			StrPCopy (Pointer (@(PBinData(Data) [ContentLength + 1])), Extension);
+		WriteCalcInt (VarTag, CalcFooter.Tag);
+		if not OutputBin then begin
+			Header := Output;
+			Footer := Pointer (@(PBinData(Output) [Size - SizeOf (TTransferFileFooter)]));
+			with Header^ do begin
+				case CalcDest of
+					cdTI92:
+						Signature := '**TI92**';
+					cdTI89:
+						Signature := '**TI89**'
+					else
+						Signature := '**TI92P*';
+				end;
+				Reserved1 := Res1;
+				Reserved2 := Res2;
+				Reserved3 := Res3;
+				Reserved4 := Res4;
+				StrPLCopy (Folder, LowerCase (DestFolder), SizeOf (Folder));
+				StrPLCopy (VarName, LowerCase (DestVarName), SizeOf (VarName));
+				case VarTag of
+					$2D: VarLinkType := $0C;
+					$DC: VarLinkType := $12;
+					$F3: VarLinkType := $21;
+					$F8: VarLinkType := $1C;
+					else VarLinkType := 0;
+				end;
+				WritePCInt (VarLinkType, LinkType);
+				WritePCInt (Size, FileSize);
+			end;
+			Sum := 0;
+			for I := 0 to CalcSize - 1 do
+				Inc (Sum, Byte (PBinData(CalcHeader) [I]));
+			WritePCInt (Sum, Footer.CheckSum);
+		end;
+	end;
+end;
+
+function GetTransferFileExt(CalcDest: TCalcDest; VarTag: Byte; OutputBin: Boolean = False): string;
+var
+	TypeExt: Char;
+begin
+	case CalcDest of
+		cdTI92:
+			Result := '92';
+		cdTI89:
+			Result := '89';
+		cdTI92Plus:
+			Result := '9x';
+		cdV200:
+			Result := 'v2';
+		else
+			Result := 'xx';
+	end;
+	case VarTag of
+		$2D: TypeExt := 's';
+		$DC: TypeExt := 'p';
+		$F3: TypeExt := 'z';
+		else TypeExt := 'y';
+	end;
+	if OutputBin then
+		Result := '.' + TypeExt + Result
+	else
+		Result := '.' + Result + TypeExt;
+end;
+
+function GetOSUpgradeFileSize(ContentLength: LongWord; OutputBin: Boolean = True): LongWord;
+begin
+	Result := ContentLength + SizeOf (TCalcOSFooter);
+end;
+
+procedure ProduceOSUpgradeFile(Output: Pointer; Contents: Pointer; ContentLength: LongWord; OutputBin: Boolean = True);
+var
+	CalcFooter: PCalcOSFooter;
+begin
+	Move (Contents^, Output^, ContentLength);
+	CalcFooter := Pointer (@(PBinData(Output) [ContentLength]));
+	FillChar (CalcFooter^, SizeOf (TCalcOSFooter), 0);
+	with CalcFooter^ do begin
+		WriteCalcInt ($020D, SignatureHeader);
+		WriteCalcInt ($40,   SignatureType);
+	end;
+end;
+
+function GetOSUpgradeFileExt(CalcDest: TCalcDest; OutputBin: Boolean = False): string;
+begin
+	case CalcDest of
+		cdTI92:
+			Result := '92';
+		cdTI89:
+			Result := '89';
+		cdTI89Titanium:
+			Result := '89ti';
+		cdTI92Plus:
+			Result := '9x';
+		cdV200:
+			Result := 'v2';
+		else
+			Result := 'xx';
+	end;
+	Result := '-' + Result + '.tib';
+end;
+
+end.

BIN
PreferencesUnit.dfm


+ 491 - 0
PreferencesUnit.pas

@@ -0,0 +1,491 @@
+unit PreferencesUnit;
+
+interface
+
+uses
+	Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+  StdCtrls, ExtCtrls, ComCtrls, SourceEditUnit{$IFDEF CODINGEXT}, PrefFrame{$ENDIF};
+
+type
+  TPreferencesForm = class(TForm)
+    OKButton: TButton;
+    CancelButton: TButton;
+		ColorDlg: TColorDialog;
+    FontDlg: TFontDialog;
+    PageController: TPageControl;
+		GeneralSheet: TTabSheet;
+    StopCompilationBox: TCheckBox;
+		FlatButtonsCheckBox: TCheckBox;
+    MenuBitmapsCheckBox: TCheckBox;
+    AutoSaveCheckBox: TCheckBox;
+    EditorSheet: TTabSheet;
+		Label2: TLabel;
+		CTabSizeEdit: TEdit;
+    ColorCheckBox: TCheckBox;
+    ChangeColorButton: TButton;
+		Label3: TLabel;
+		ChangeFontButton: TButton;
+    FontLabel: TPanel;
+    SyntaxHighlightingSheet: TTabSheet;
+    Label4: TLabel;
+		ASMTabSizeEdit: TEdit;
+    LanguageSelectionBox: TComboBox;
+    Label5: TLabel;
+    SyntaxEnabledBox: TCheckBox;
+		Button1: TButton;
+    Button2: TButton;
+    Button3: TButton;
+    Button4: TButton;
+    Button5: TButton;
+		Button6: TButton;
+    ObjectTree: TTreeView;
+    Button7: TButton;
+    Button8: TButton;
+    Button9: TButton;
+    OKTimer: TTimer;
+		OpenFolderBox: TCheckBox;
+		DeleteObjectFilesBox: TCheckBox;
+    ResetButton: TButton;
+    OnFlyCheckBox: TCheckBox;
+    DeleteErrorsCheckBox: TCheckBox;
+    AutoBlockCheckBox: TCheckBox;
+    SplitFilesCheckBox: TCheckBox;
+    DeleteAssemblyFilesBox: TCheckBox;
+    AllowImplicitCheckBox: TCheckBox;
+    AutoNewsCheckBox: TCheckBox;
+    TransferSheet: TTabSheet;
+    TargetBox: TGroupBox;
+    VTIBox: TRadioButton;
+    RealCalcBox: TRadioButton;
+    PortBox: TGroupBox;
+    PortCOM1Box: TRadioButton;
+    PortCOM2Box: TRadioButton;
+    PortCOM3Box: TRadioButton;
+    PortCOM4Box: TRadioButton;
+    CableBox: TGroupBox;
+    CableBlackBox: TRadioButton;
+    CableGrayBox: TRadioButton;
+    NoneBox: TRadioButton;
+    VTIPathEdit: TEdit;
+    VTIPathBrowseButton: TButton;
+    BrowseDlg: TOpenDialog;
+    DragDropEditCheckBox: TCheckBox;
+    RemoveTrailingSpcCheckBox: TCheckBox;
+    JumpToErrorBox: TCheckBox;
+		procedure ColorCheckBoxClick(Sender: TObject);
+		procedure ChangeColorButtonClick(Sender: TObject);
+		procedure ChangeFontButtonClick(Sender: TObject);
+		procedure FormCreate(Sender: TObject);
+		procedure FormDestroy(Sender: TObject);
+		procedure FormShow(Sender: TObject);
+		procedure LanguageSelectionBoxChange(Sender: TObject);
+		procedure ObjectTreeChange(Sender: TObject; Node: TTreeNode);
+		procedure SyntaxEnabledBoxClick(Sender: TObject);
+    procedure Button1Click(Sender: TObject);
+		procedure Button3Click(Sender: TObject);
+    procedure Button2Click(Sender: TObject);
+    procedure Button4Click(Sender: TObject);
+    procedure Button6Click(Sender: TObject);
+    procedure Button5Click(Sender: TObject);
+    procedure ObjectTreeKeyDown(Sender: TObject; var Key: Word;
+      Shift: TShiftState);
+		procedure EditItem(Sender: TObject);
+		procedure Button7Click(Sender: TObject);
+    procedure Button8Click(Sender: TObject);
+    procedure ObjectTreeEdited(Sender: TObject; Node: TTreeNode;
+			var S: String);
+		procedure ObjectTreeEditing(Sender: TObject; Node: TTreeNode;
+			var AllowEdit: Boolean);
+		procedure OKTimerTimer(Sender: TObject);
+		procedure ResetButtonClick(Sender: TObject);
+		procedure PageControllerChange(Sender: TObject);
+    procedure TargetBoxClick(Sender: TObject);
+    procedure VTIPathBrowseButtonClick(Sender: TObject);
+	private
+	public
+		BackColor: TColor;
+		EditorFont: TFont;
+		SyntaxC: TSyntaxColoring;
+		SyntaxAsmGNU: TSyntaxColoring;
+		SyntaxAsm: TSyntaxColoring;
+		SyntaxQuill: TSyntaxColoring;
+		Syntax: TSyntaxColoring;
+		SyntaxTabClicked: Boolean;
+
+{$IFDEF CODINGEXT}
+    procedure InitCodingExt;
+{$ENDIF}
+	end;
+
+implementation
+
+{$R *.DFM}
+
+uses
+	MasterUnit,
+	UtilsDos, UtilsWin,
+	MainUnit, StyleSelectionUnit, ColorsUnit, CustomStyleUnit, WordListUnit;
+
+procedure TPreferencesForm.ColorCheckBoxClick(Sender: TObject);
+begin
+	ChangeColorButton.Enabled := ColorCheckBox.Checked;
+end;
+
+procedure TPreferencesForm.ChangeColorButtonClick(Sender: TObject);
+begin
+	with ColorDlg do begin
+		Color := BackColor;
+		if Execute then
+			BackColor := Color;
+	end;
+end;
+
+procedure TPreferencesForm.ChangeFontButtonClick(Sender: TObject);
+begin
+	with FontDlg do begin
+		Font.Assign (EditorFont);
+		if Execute then begin
+			EditorFont.Assign (Font);
+			FontLabel.Caption := EditorFont.Name;
+			FontLabel.Font.Assign (EditorFont);
+		end;
+	end;
+end;
+
+procedure TPreferencesForm.FormCreate(Sender: TObject);
+begin
+	EditorFont := TFont.Create;
+	SyntaxC := TSyntaxColoring.Create (nil);
+	SyntaxAsm := TSyntaxColoring.Create (nil);
+	SyntaxAsmGNU := TSyntaxColoring.Create (nil);
+	SyntaxQuill := TSyntaxColoring.Create (nil);
+	if ssA68k in SpecialSupport then
+		LanguageSelectionBox.Items.Add ('A68k ASM Files');
+	if ssQuill in SpecialSupport then
+		LanguageSelectionBox.Items.Add ('Quill Files');
+	LanguageSelectionBox.ItemIndex := 0;
+
+{$IFDEF CODINGEXT}
+  InitCodingExt;
+{$ENDIF}
+end;
+
+procedure TPreferencesForm.FormDestroy(Sender: TObject);
+begin
+	SyntaxQuill.Free;
+	SyntaxAsmGNU.Free;
+	SyntaxAsm.Free;
+	SyntaxC.Free;
+	EditorFont.Free;
+end;
+
+procedure TPreferencesForm.FormShow(Sender: TObject);
+begin
+	SyntaxTabClicked := PageController.ActivePage = SyntaxHighlightingSheet;
+	TargetBoxClick (Sender);
+	ColorCheckBoxClick (Sender);
+	FontLabel.Caption := EditorFont.Name;
+	FontLabel.Font.Assign (EditorFont);
+	LanguageSelectionBoxChange (Sender);
+end;
+
+procedure TPreferencesForm.LanguageSelectionBoxChange(Sender: TObject);
+label
+	Done;
+var
+	I: Integer;
+begin
+	I := LanguageSelectionBox.ItemIndex;
+	if I <= 0 then begin
+		Syntax := SyntaxC;
+		goto Done;
+	end;
+	Dec (I);
+	if I <= 0 then begin
+		Syntax := SyntaxAsmGNU;
+		goto Done;
+	end;
+	if ssA68k in SpecialSupport then begin
+		Dec (I);
+		if I <= 0 then begin
+			Syntax := SyntaxAsm;
+			goto Done;
+		end;
+	end;
+	if ssQuill in SpecialSupport then begin
+		Dec (I);
+		if I <= 0 then begin
+			Syntax := SyntaxQuill;
+			goto Done;
+		end;
+	end;
+	Done:
+	SyntaxEnabledBox.Checked := Syntax.Enabled;
+	SyntaxEnabledBoxClick (Sender);
+	ObjectTree.Items.BeginUpdate;
+	with ObjectTree.Items [0] do begin
+		Item[0].DeleteChildren;
+		Item[1].DeleteChildren;
+	end;
+	with Syntax do begin
+		with CustomStyles do
+			for I := 0 to Count - 1 do
+				ObjectTree.Items.AddChildObject (ObjectTree.Items[0].Item[0], Items[I].Caption, Pointer (Items [I]));
+		with WordLists do
+			for I := 0 to Count - 1 do
+				ObjectTree.Items.AddChildObject (ObjectTree.Items[0].Item[1], Items[I].Caption, Pointer (Items [I]));
+	end;
+	ObjectTree.FullExpand;
+	ObjectTree.Items.EndUpdate;
+	ObjectTreeChange (Sender, nil);
+end;
+
+procedure TPreferencesForm.ObjectTreeChange(Sender: TObject;
+	Node: TTreeNode);
+begin
+	Button9.Enabled := SyntaxEnabledBox.Checked and Assigned (ObjectTree.Selected) and Assigned (ObjectTree.Selected.Data);
+end;
+
+procedure TPreferencesForm.SyntaxEnabledBoxClick(Sender: TObject);
+begin
+	Syntax.Enabled := SyntaxEnabledBox.Checked;
+	Button1.Enabled := SyntaxEnabledBox.Checked;
+	Button2.Enabled := SyntaxEnabledBox.Checked;
+	Button3.Enabled := SyntaxEnabledBox.Checked;
+	Button4.Enabled := SyntaxEnabledBox.Checked;
+	Button5.Enabled := SyntaxEnabledBox.Checked;
+	Button6.Enabled := SyntaxEnabledBox.Checked;
+	Button7.Enabled := SyntaxEnabledBox.Checked;
+	Button8.Enabled := SyntaxEnabledBox.Checked;
+	ObjectTree.Enabled := SyntaxEnabledBox.Checked;
+	ObjectTreeChange (Sender, nil);
+end;
+
+procedure TPreferencesForm.Button1Click(Sender: TObject);
+begin
+	ColorDlg.Color := Syntax.NumberColor;
+	if ColorDlg.Execute then
+		Syntax.NumberColor := ColorDlg.Color;
+end;
+
+procedure TPreferencesForm.Button3Click(Sender: TObject);
+begin
+	ColorDlg.Color := Syntax.SymbolColor;
+	if ColorDlg.Execute then
+		Syntax.SymbolColor := ColorDlg.Color;
+end;
+
+procedure TPreferencesForm.Button2Click(Sender: TObject);
+begin
+	with TStyleSelectionForm.Create (Self) do try
+		CustomStyle := Syntax.NumberCustomStyle;
+		Style := Syntax.NumberStyle;
+		if ShowModal = mrOK then begin
+			Syntax.NumberCustomStyle := CustomStyle;
+			Syntax.NumberStyle := Style;
+		end;
+	finally
+		Free;
+	end;
+end;
+
+procedure TPreferencesForm.Button4Click(Sender: TObject);
+begin
+	with TStyleSelectionForm.Create (Self) do try
+		CustomStyle := Syntax.SymbolCustomStyle;
+		Style := Syntax.SymbolStyle;
+		if ShowModal = mrOK then begin
+			Syntax.SymbolCustomStyle := CustomStyle;
+			Syntax.SymbolStyle := Style;
+		end;
+	finally
+		Free;
+	end;
+end;
+
+procedure TPreferencesForm.Button6Click(Sender: TObject);
+begin
+	with TStyleSelectionForm.Create (Self) do try
+		CustomStyle := Syntax.ParenthesisCustomStyle;
+		Style := Syntax.ParenthesisStyle;
+		if ShowModal = mrOK then begin
+			Syntax.ParenthesisCustomStyle := CustomStyle;
+			Syntax.ParenthesisStyle := Style;
+		end;
+	finally
+		Free;
+	end;
+end;
+
+procedure TPreferencesForm.Button5Click(Sender: TObject);
+begin
+	with TMultipleColorsForm.Create (Self) do try
+		ColorBox.Items.Assign (Syntax.ParenthesisColors);
+		if ShowModal = mrOK then
+			Syntax.ParenthesisColors.Assign (ColorBox.Items);
+	finally
+		Free;
+	end;
+end;
+
+procedure TPreferencesForm.ObjectTreeKeyDown(Sender: TObject;
+	var Key: Word; Shift: TShiftState);
+var
+	ItemData: TCollectionItem;
+begin
+	if Key = vk_Delete then begin
+		if Assigned (ObjectTree.Selected) and Assigned (ObjectTree.Selected.Data) then begin
+			ItemData := TCollectionItem (ObjectTree.Selected.Data);
+			ObjectTree.Selected.Delete;
+			ItemData.Free;
+		end;
+	end;
+end;
+
+procedure TPreferencesForm.EditItem(Sender: TObject);
+var
+	ItemData: TCollectionItem;
+begin
+	if Assigned (ObjectTree.Selected) and Assigned (ObjectTree.Selected.Data) then begin
+		ItemData := TCollectionItem (ObjectTree.Selected.Data);
+		if ItemData is TCustomStyle then
+			with TCustomStyleForm.Create (Self) do try
+				Style.Assign (ItemData);
+				if ShowModal = mrOK then
+					ItemData.Assign (Style);
+			finally
+				Free;
+			end
+		else if ItemData is TWordList then
+			with TWordListForm.Create (Self) do try
+				List.Assign (ItemData);
+				if ShowModal = mrOK then
+					ItemData.Assign (List);
+			finally
+				Free;
+			end;
+	end;
+end;
+
+procedure TPreferencesForm.Button7Click(Sender: TObject);
+var
+	ItemData: TCustomStyle;
+begin
+	if ObjectTree.Enabled then
+		ObjectTree.SetFocus;
+	ItemData := Syntax.CustomStyles.Add;
+	ItemData.Caption := 'New Style';
+	with ObjectTree.Items.AddChildObject (ObjectTree.Items[0].Item[0], ItemData.Caption, Pointer (ItemData)) do begin
+		MakeVisible;
+		EditText;
+	end;
+end;
+
+procedure TPreferencesForm.Button8Click(Sender: TObject);
+var
+	ItemData: TWordList;
+begin
+	if ObjectTree.Enabled then
+		ObjectTree.SetFocus;
+	ItemData := Syntax.WordLists.Add;
+	ItemData.Caption := 'New List';
+	with ObjectTree.Items.AddChildObject (ObjectTree.Items[0].Item[1], ItemData.Caption, Pointer (ItemData)) do begin
+		MakeVisible;
+		EditText;
+	end;
+end;
+
+procedure TPreferencesForm.ObjectTreeEdited(Sender: TObject;
+	Node: TTreeNode; var S: String);
+var
+	ItemData: TCollectionItem;
+begin
+	OKButton.Enabled := True;
+	if Assigned (Node.Data) then begin
+		ItemData := TCollectionItem (Node.Data);
+		if ItemData is TCustomStyle then
+			TCustomStyle(ItemData).Caption := S;
+		if ItemData is TWordList then
+			TWordList(ItemData).Caption := S;
+	end;
+	ObjectTree.Selected := Node;
+end;
+
+procedure TPreferencesForm.ObjectTreeEditing(Sender: TObject;
+	Node: TTreeNode; var AllowEdit: Boolean);
+begin
+	AllowEdit := Assigned (Node.Data);
+	if AllowEdit then begin
+		OKButton.Enabled := False;
+		OKTimer.Enabled := True;
+	end;
+end;
+
+procedure TPreferencesForm.OKTimerTimer(Sender: TObject);
+begin
+	if not ObjectTree.IsEditing then begin
+		OKButton.Enabled := True;
+		OKTimer.Enabled := False;
+	end;
+end;
+
+procedure TPreferencesForm.ResetButtonClick(Sender: TObject);
+begin
+	if Syntax = SyntaxC then
+		Syntax.Assign (MainForm.SyntaxCBackup)
+	else if Syntax = SyntaxAsmGNU then
+		Syntax.Assign (MainForm.SyntaxAsmGNUBackup)
+	else if Syntax = SyntaxAsm then
+		Syntax.Assign (MainForm.SyntaxAsmBackup)
+	else if Syntax = SyntaxQuill then
+		Syntax.Assign (MainForm.SyntaxQuillBackup);
+	LanguageSelectionBoxChange (Sender);
+end;
+
+procedure TPreferencesForm.PageControllerChange(Sender: TObject);
+begin
+	if PageController.ActivePage = SyntaxHighlightingSheet then
+		SyntaxTabClicked := True;
+end;
+
+procedure TPreferencesForm.TargetBoxClick(Sender: TObject);
+begin
+	VTIPathEdit.Enabled := VTIBox.Checked;
+	VTIPathBrowseButton.Enabled := VTIPathEdit.Enabled;
+	PortBox.Enabled := RealCalcBox.Checked;
+	PortCOM1Box.Enabled := PortBox.Enabled;
+	PortCOM2Box.Enabled := PortBox.Enabled;
+	PortCOM3Box.Enabled := PortBox.Enabled;
+	PortCOM4Box.Enabled := PortBox.Enabled;
+	CableBox.Enabled := PortBox.Enabled;
+	CableBlackBox.Enabled := CableBox.Enabled;
+	CableGrayBox.Enabled := CableBox.Enabled;
+end;
+
+procedure TPreferencesForm.VTIPathBrowseButtonClick(Sender: TObject);
+begin
+	with BrowseDlg do begin
+		FileName := VTIPathEdit.Text;
+		if Execute then
+			VTIPathEdit.Text := FileName;
+	end;
+end;
+
+{$IFDEF CODINGEXT}
+procedure TPreferencesForm.InitCodingExt;
+var
+  Tab: TTabSheet;
+  Frame: TCodingExt;
+begin
+  Tab := TTabSheet.Create(Self);
+  Tab.PageControl := PageController;
+  Tab.Caption := 'Coding';
+
+  Frame := TCodingExt.Create(Self);
+  Frame.Parent := Tab;
+  Tab.OnShow := Frame.OnShow;
+end;
+{$ENDIF}
+
+end.
+

+ 281 - 0
ProcessUnit.pas

@@ -0,0 +1,281 @@
+unit ProcessUnit;
+
+interface
+
+uses
+	HandleWaitThreadUnit, FileReadToBufferThreadUnit,
+	Windows, Classes;
+
+type
+	TRedirect = class;
+
+	TProcessConsole = class(TObject)
+	private
+		FTitle: string;
+		FProcessInfo: TProcessInformation;
+		FStdOut: TRedirect;
+		FStdErr: TRedirect;
+		FWaitThread: THandleWaitThread;
+		FPriorityClass: DWord;
+		function GetLastOutText: string;
+		function GetLastErrText: string;
+		function GetRunning: Boolean;
+    function GetLastErrSize: Integer;
+    function GetLastOutSize: Integer;
+	protected
+		property StdOut: TRedirect read FStdOut;
+		property StdErr: TRedirect read FStdErr;
+		property ProcessInfo: TProcessInformation read FProcessInfo;
+		property WaitThread: THandleWaitThread read FWaitThread;
+	public
+		constructor Create;
+		destructor Destroy; override;
+		procedure StartProcess(const ProgramFile, Parameters, HomeDir: string);
+		procedure KillProcess;
+		procedure KillProcessAndWait;
+		procedure WaitForTermination;
+		property Running: Boolean read GetRunning;
+		property LastOutText: string read GetLastOutText;
+		property LastErrText: string read GetLastErrText;
+		property LastOutSize: Integer read GetLastOutSize;
+		property LastErrSize: Integer read GetLastErrSize;
+	published
+		property Title: string read FTitle write FTitle;
+		property PriorityClass: DWord read FPriorityClass write FPriorityClass;
+	end;
+
+	TRedirect = class(TObject)
+	private
+		FProgramOutputHandle: HFile;
+		FPipe: HFile;
+		FThread: TFileReadToBufferThread;
+		FStream: TMemoryStream;
+		FFinish: Boolean;
+		function GetText: string;
+		function GetOutputSize: Integer;
+	public
+		constructor Create;
+		destructor Destroy; override;
+		procedure Clear;
+		procedure Finish;
+		property Stream: TMemoryStream read FStream;
+		property Thread: TFileReadToBufferThread read FThread;
+		property Pipe: HFile read FPipe;
+		property ProgramOutputHandle: HFile read FProgramOutputHandle;
+		property Text: string read GetText;
+		property OutputSize: Integer read GetOutputSize;
+	end;
+
+implementation
+
+uses
+	SysUtils, UtilsWin;
+
+{ TProcessConsole }
+
+constructor TProcessConsole.Create;
+begin
+	inherited;
+	FStdOut := TRedirect.Create;
+	FStdErr := TRedirect.Create;
+	Title := 'Console';
+	PriorityClass := HIGH_PRIORITY_CLASS;
+end;
+
+destructor TProcessConsole.Destroy;
+begin
+	KillProcessAndWait;
+	FStdErr.Free;
+	FStdOut.Free;
+	inherited;
+end;
+
+function TProcessConsole.GetLastErrSize: Integer;
+begin
+	Result := StdErr.OutputSize;
+end;
+
+function TProcessConsole.GetLastErrText: string;
+begin
+	Result := StdErr.Text;
+end;
+
+function TProcessConsole.GetLastOutSize: Integer;
+begin
+	Result := StdOut.OutputSize;
+end;
+
+function TProcessConsole.GetLastOutText: string;
+begin
+	Result := StdOut.Text;
+end;
+
+function TProcessConsole.GetRunning: Boolean;
+var
+	T: TThread;
+begin
+	if Assigned (WaitThread) then begin
+		Result := not WaitThread.HasTerminated;
+		if not Result then begin
+			T := FWaitThread;
+			FWaitThread := nil;
+			T.Free;
+			with FProcessInfo do begin
+				CloseHandle (hProcess);
+				CloseHandle (hThread);
+				hProcess := 0;
+				hThread := 0;
+			end;
+			StdOut.Finish;
+			StdErr.Finish;
+		end;
+	end else
+		Result := False;
+end;
+
+procedure TProcessConsole.KillProcess;
+begin
+	if Running then begin
+		TerminateProcess (ProcessInfo.hProcess, 1);
+		if Assigned (WaitThread) then
+			WaitThread.Terminate;
+	end;
+end;
+
+procedure TProcessConsole.KillProcessAndWait;
+begin
+	KillProcess;
+	WaitForTermination;
+end;
+
+procedure TProcessConsole.StartProcess(const ProgramFile, Parameters, HomeDir: string);
+var
+	StartupInfo: TStartupInfo;
+	CommandLine: string;
+	HomeDirPC: PChar;
+begin
+	if Running then
+		raise EFOpenError.Create ('Another process is still running')
+	else begin
+		StdOut.Clear;
+		StdErr.Clear;
+		FillChar (StartupInfo, SizeOf (StartupInfo), 0);
+		with StartupInfo do begin
+			cb := SizeOf (StartupInfo);
+			lpTitle := PChar (Title);
+			wShowWindow := sw_Hide;
+			hStdOutput := StdOut.ProgramOutputHandle;
+			hStdError := StdErr.ProgramOutputHandle;
+			dwFlags := StartF_UseShowWindow or StartF_UseStdHandles;
+		end;
+		if Length (ProgramFile) > 0 then
+			CommandLine := '"' + ProgramFile + '" ' + Parameters
+		else
+			CommandLine := Parameters;
+		if Length (HomeDir) > 0 then
+			HomeDirPC := PChar (HomeDir)
+		else
+			HomeDirPC := nil;
+		if CreateProcess (nil, PChar (CommandLine), nil, nil, True, PriorityClass, nil, HomeDirPC, StartupInfo, FProcessInfo) then begin
+			FWaitThread := THandleWaitThread.Create (ProcessInfo.hProcess);
+		end else
+			raise EFOpenError.Create ('Could not start process');
+	end;
+end;
+
+procedure TProcessConsole.WaitForTermination;
+begin
+	if Assigned (WaitThread) then
+		WaitThread.WaitFor;
+end;
+
+{ TRedirect }
+
+procedure TRedirect.Clear;
+begin
+	FFinish := False;
+	Thread.Lock.BeginWrite;
+	Stream.Clear;
+	Thread.Lock.EndWrite;
+end;
+
+constructor TRedirect.Create;
+var
+	Attr: TSecurityAttributes;
+	TempPipe: HFile;
+begin
+	inherited;
+	FillChar (Attr, SizeOf (Attr), 0);
+	with Attr do begin
+		nLength := SizeOf (Attr);
+		lpSecurityDescriptor := nil;
+		bInheritHandle := True;
+	end;
+	CreatePipe (TempPipe, FProgramOutputHandle, @Attr, 0);
+	DuplicateHandle (GetCurrentProcess, TempPipe, GetCurrentProcess, @FPipe, 0, False, Duplicate_Close_Source or Duplicate_Same_Access);
+	FStream := TMemoryStream.Create;
+	FThread := TFileReadToBufferThread.Create (Pipe, Stream);
+end;
+
+destructor TRedirect.Destroy;
+begin
+	if Assigned (Thread) then
+		Thread.Terminate;
+	Finish;
+	CloseHandle (FProgramOutputHandle);
+	if Assigned (Thread) then begin
+		Thread.WaitFor;
+		FThread.Free;
+	end;
+	if Assigned (Stream) then
+		FStream.Free;
+	CloseHandle (FPipe);
+	inherited;
+end;
+
+procedure TRedirect.Finish;
+const
+	B: Byte = 0;
+var
+	BW: Cardinal;
+begin
+	if not FFinish then begin
+		FFinish := True;
+		WriteFile (ProgramOutputHandle, B, 1, BW, nil);
+	end;
+end;
+
+function TRedirect.GetOutputSize: Integer;
+begin
+	Thread.Lock.BeginRead;
+	Result := Stream.Size;
+	Thread.Lock.EndRead;
+end;
+
+function TRedirect.GetText: string;
+var
+	Finished: Boolean;
+begin
+	if FFinish then begin
+		repeat
+			Thread.Lock.BeginRead;
+			with Stream do
+				Finished := (Size > 0) and (PChar(Memory) [Size - 1] = #0);
+			Thread.Lock.EndRead;
+			if not Finished then
+				Sleep (100);
+		until Finished;
+		Result := AnsiString (PChar (Stream.Memory));
+	end else begin
+		Thread.Lock.BeginWrite;
+		with Stream do begin
+			Size := Size + 1;
+			PChar(Memory) [Size - 1] := #0;
+			Result := AnsiString (PChar (Memory));
+			Size := Size - 1;
+		end;
+		Thread.Lock.EndWrite;
+	end;
+end;
+
+end.

BIN
ProgramOptionsUnit.dfm


+ 202 - 0
ProgramOptionsUnit.pas

@@ -0,0 +1,202 @@
+unit ProgramOptionsUnit;
+
+interface
+
+uses
+	Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+	StdCtrls, ExtCtrls, ComCtrls;
+
+type
+	TProgramOptionsForm = class(TForm)
+    CloseButton: TButton;
+		PageController: TPageControl;
+		CalculatorSheet: TTabSheet;
+    Label2: TLabel;
+		TI89CheckBox: TCheckBox;
+		TI92PlusCheckBox: TCheckBox;
+    V200CheckBox: TCheckBox;
+    Label5: TLabel;
+    OSSheet: TTabSheet;
+		Label3: TLabel;
+    NoStubRadioButton: TRadioButton;
+    DoorsRadioButton: TRadioButton;
+    PreOSRadioButton: TRadioButton;
+    MinAMSCheckBox: TCheckBox;
+    MinAMSEdit: TEdit;
+		RelocFormatSheet: TTabSheet;
+		Panel2: TPanel;
+    Label4: TLabel;
+    RelocAMSRadioButton: TRadioButton;
+		RelocKernelRadioButton: TRadioButton;
+		RelocCompressedRadioButton: TRadioButton;
+    Panel3: TPanel;
+    Label15: TLabel;
+    ROMCallDirectRadioButton: TRadioButton;
+		ROMCallKernelRadioButton: TRadioButton;
+		ROMCallCompressedRadioButton: TRadioButton;
+    ROMCallFLineRadioButton: TRadioButton;
+    InternalFLineEmulatorCheckBox: TCheckBox;
+		BSSFormatSheet: TTabSheet;
+		HomeScreenSheet: TTabSheet;
+		LCDSaveCheckBox: TCheckBox;
+		EnableErrorReturnCheckBox: TCheckBox;
+		Label11: TLabel;
+		ReturnValueRadioButton: TRadioButton;
+		ReturnDoneRadioButton: TRadioButton;
+		Label10: TLabel;
+		Label7: TLabel;
+    Panel1: TPanel;
+		Label6: TLabel;
+    BSSKernelRadioButton: TRadioButton;
+    BSSCompressedRadioButton: TRadioButton;
+    BSSMergeRadioButton: TRadioButton;
+    Panel4: TPanel;
+    Label8: TLabel;
+		DataVarKernelRadioButton: TRadioButton;
+		DataVarCompressedRadioButton: TRadioButton;
+		WelcomeSheet: TTabSheet;
+		Label1: TLabel;
+		Label9: TLabel;
+		OptimizeCalcConstsCheckBox: TCheckBox;
+		Label12: TLabel;
+		RelocFLineJumpsCheckBox: TCheckBox;
+		UnofficialOSSupportCheckBox: TCheckBox;
+		RelocFLineJumps4ByteCheckBox: TCheckBox;
+    ROMCallOptimizedCheckBox: TCheckBox;
+		procedure FormShow(Sender: TObject);
+		procedure ShellRadioButtonClick(Sender: TObject);
+		procedure MinAMSCheckBoxClick(Sender: TObject);
+		procedure RelocRadioButtonClick(Sender: TObject);
+		procedure ItemMouseDown(Sender: TObject; Button: TMouseButton;
+			Shift: TShiftState; X, Y: Integer);
+		procedure CalcCheckBoxClick(Sender: TObject);
+		procedure RelocFLineJumpsCheckBoxClick(Sender: TObject);
+	private
+	public
+	end;
+
+implementation
+
+uses
+	MainUnit;
+
+{$R *.DFM}
+
+procedure TProgramOptionsForm.FormShow(Sender: TObject);
+begin
+	ActiveControl := PageController;
+	CalcCheckBoxClick            (Sender);
+	ShellRadioButtonClick        (Sender);
+	MinAMSCheckBoxClick          (Sender);
+	RelocRadioButtonClick        (Sender);
+	RelocFLineJumpsCheckBoxClick (Sender);
+end;
+
+procedure TProgramOptionsForm.ShellRadioButtonClick(Sender: TObject);
+begin
+	with LCDSaveCheckBox do begin
+		Enabled := NostubRadioButton.Checked;
+		if not Enabled then
+			Checked := True;
+	end;
+	with RelocAMSRadioButton do begin
+		Enabled := NostubRadioButton.Checked;
+		if Checked and not Enabled then
+			RelocKernelRadioButton.Checked := True;
+	end;
+	with RelocKernelRadioButton do begin
+		Enabled := not PreOSRadioButton.Checked;
+		if Checked and not Enabled then
+			RelocCompressedRadioButton.Checked := True;
+	end;
+	with RelocCompressedRadioButton do begin
+		Enabled := not DoorsRadioButton.Checked;
+		if Checked and not Enabled then
+			RelocKernelRadioButton.Checked := True;
+	end;
+	with ROMCallDirectRadioButton do begin
+		Enabled := NostubRadioButton.Checked;
+		if Checked and not Enabled then
+			ROMCallKernelRadioButton.Checked := True;
+	end;
+	with ROMCallKernelRadioButton do begin
+		Enabled := not PreOSRadioButton.Checked;
+		if Checked and not Enabled then
+			ROMCallCompressedRadioButton.Checked := True;
+	end;
+	with ROMCallCompressedRadioButton do begin
+		Enabled := not DoorsRadioButton.Checked;
+		if Checked and not Enabled then
+			ROMCallKernelRadioButton.Checked := True;
+	end;
+	with BSSKernelRadioButton do begin
+		Enabled := not PreOSRadioButton.Checked;
+		if Checked and not Enabled then
+			BSSCompressedRadioButton.Checked := True;
+	end;
+	with BSSCompressedRadioButton do begin
+		Enabled := not DoorsRadioButton.Checked;
+		if Checked and not Enabled then
+			BSSKernelRadioButton.Checked := True;
+	end;
+	RelocRadioButtonClick (Sender);
+end;
+
+procedure TProgramOptionsForm.MinAMSCheckBoxClick(Sender: TObject);
+begin
+	MinAMSEdit.Enabled := MinAMSCheckBox.Checked;
+end;
+
+procedure TProgramOptionsForm.RelocRadioButtonClick(Sender: TObject);
+begin
+	with InternalFLineEmulatorCheckBox do begin
+		Enabled := (RelocFLineJumpsCheckBox.Checked or ROMCallFLineRadioButton.Checked) and (not RelocFLineJumps4ByteCheckBox.Checked);
+		if not Enabled then
+			Checked := RelocFLineJumps4ByteCheckBox.Checked;
+	end;
+	with ROMCallOptimizedCheckBox do begin
+		Enabled := (ROMCallDirectRadioButton.Checked or ROMCallFLineRadioButton.Checked) and NostubRadioButton.Checked;
+		if not Enabled then
+			Checked := False;
+	end;
+end;
+
+procedure TProgramOptionsForm.ItemMouseDown(Sender: TObject;
+	Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+begin
+	if Button = mbRight then
+		if Sender is TControl then
+			with TControl (Sender) do
+				MainForm.DocFile.KeywordLookup (Hint);
+end;
+
+procedure TProgramOptionsForm.CalcCheckBoxClick(Sender: TObject);
+var
+	CalcCount: Integer;
+begin
+	CalcCount := 0;
+	if TI89CheckBox.Checked then
+		Inc (CalcCount);
+	if TI92PlusCheckBox.Checked then
+		Inc (CalcCount);
+	if V200CheckBox.Checked then
+		Inc (CalcCount);
+	with OptimizeCalcConstsCheckBox do begin
+		Enabled := CalcCount > 1;
+		if not Enabled then
+			Checked := CalcCount = 1;
+	end;
+end;
+
+procedure TProgramOptionsForm.RelocFLineJumpsCheckBoxClick(
+	Sender: TObject);
+begin
+	with RelocFLineJumps4ByteCheckBox do begin
+		Enabled := RelocFLineJumpsCheckBox.Checked;
+		if not Enabled then
+			Checked := False;
+	end;
+	RelocRadioButtonClick (Sender);
+end;
+
+end.

BIN
ProgramOutputUnit.dfm


+ 33 - 0
ProgramOutputUnit.pas

@@ -0,0 +1,33 @@
+unit ProgramOutputUnit;
+
+interface
+
+uses
+  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+  ExtCtrls, MemoComponentUnit;
+
+type
+  TProgramOutputForm = class(TForm)
+    OutputMemo: TMemoComponent;
+    ErrorMemo: TMemoComponent;
+		Splitter: TSplitter;
+		Panel1: TPanel;
+    Panel2: TPanel;
+    procedure FormShow(Sender: TObject);
+  private
+	public
+	end;
+
+implementation
+
+{$R *.DFM}
+
+procedure TProgramOutputForm.FormShow(Sender: TObject);
+begin
+	OutputMemo.Selection.RStart := OutputMemo.TextLength + 1;
+	OutputMemo.Selection.ScrollInView (0);
+	ErrorMemo.Selection.RStart := ErrorMemo.TextLength + 1;
+	ErrorMemo.Selection.ScrollInView (0);
+end;
+
+end.

BIN
ProjectOptionsUnit.dfm


+ 262 - 0
ProjectOptionsUnit.pas

@@ -0,0 +1,262 @@
+unit ProjectOptionsUnit;
+
+interface
+
+uses
+	MasterUnit, ParsingUnit, ProgramOptionsUnit,
+	Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+	StdCtrls, ExtCtrls, ComCtrls;
+
+type
+	TProjectOptionsForm = class(TForm)
+		OKButton: TButton;
+		CancelButton: TButton;
+		PageController: TPageControl;
+		GeneralSheet: TTabSheet;
+		CompilationSheet: TTabSheet;
+		LinkingSheet: TTabSheet;
+		PostBuildSheet: TTabSheet;
+		TargetGroupBox: TGroupBox;
+		PackVarEditLabel: TLabel;
+		ExecutableRadioButton: TRadioButton;
+    FlashOSRadioButton: TRadioButton;
+		FargoRadioButton: TRadioButton;
+		ArchiveRadioButton: TRadioButton;
+		PackCheckBox: TCheckBox;
+		PackVarEdit: TEdit;
+		SwitchesGroupBox: TGroupBox;
+		GCCSwitchesEditLabel: TLabel;
+		GCCSwitchesEdit: TEdit;
+		AsSwitchesEditLabel: TLabel;
+		AsSwitchesEdit: TEdit;
+		AsmSwitchesEditLabel: TLabel;
+		AsmSwitchesEdit: TEdit;
+		DebugInfoCheckBox: TCheckBox;
+		OptimizationGroupBox: TGroupBox;
+		OptimizeNOPsCheckBox: TCheckBox;
+		OptimizeReturnsCheckBox: TCheckBox;
+		OptimizeBranchesCheckBox: TCheckBox;
+		OptimizeMovesCheckBox: TCheckBox;
+		OptimizeTestsCheckBox: TCheckBox;
+		OptimizeCalculationsCheckBox: TCheckBox;
+		RemoveUnusedSectionsCheckBox: TCheckBox;
+    ReorderSectionsCheckBox: TCheckBox;
+		CutUnusedRangesCheckBox: TCheckBox;
+		StdLibCheckBox: TCheckBox;
+		OutputBinCheckBox: TCheckBox;
+		BrowseDialog: TOpenDialog;
+		ProcessFileGroupBox: TGroupBox;
+		ProcessFileEditLabel: TLabel;
+		ProcessFileEdit: TEdit;
+		BrowseButton: TButton;
+		ExecutionGroupBox: TGroupBox;
+		CommandLineEditLabel: TLabel;
+		CommandLineEdit: TEdit;
+		DataVarCheckBox: TCheckBox;
+		DataVarEditLabel: TLabel;
+		DataVarEdit: TEdit;
+		DataVarCopyLabel: TLabel;
+		DataVarCopyPanel: TPanel;
+		DataVarCopyNeverRadioButton: TRadioButton;
+		DataVarCopyIfArchivedRadioButton: TRadioButton;
+		DataVarCopyAlwaysRadioButton: TRadioButton;
+		ProgramOptionsButton: TButton;
+    MergeConstantsCheckBox: TCheckBox;
+    InitBSSCheckBox: TCheckBox;
+		procedure FormDestroy(Sender: TObject);
+		procedure FormShow(Sender: TObject);
+		procedure DataVarCheckBoxClick(Sender: TObject);
+		procedure PackCheckBoxClick(Sender: TObject);
+		procedure VarEditChange(Sender: TObject);
+		procedure TargetRadioButtonClick(Sender: TObject);
+		procedure BrowseButtonClick(Sender: TObject);
+		procedure ProgramOptionsButtonClick(Sender: TObject);
+	private
+	public
+		InitialLibOptions: TPredefinedLibOptions;
+		ProgramOptionsForm: TProgramOptionsForm;
+	end;
+
+implementation
+
+{$R *.DFM}
+
+uses
+	CalcUnit,
+	MainUnit;
+
+procedure TProjectOptionsForm.FormDestroy(Sender: TObject);
+begin
+	if Assigned (ProgramOptionsForm) then
+		ProgramOptionsForm.Free;
+end;
+
+procedure TProjectOptionsForm.FormShow(Sender: TObject);
+begin
+	TargetRadioButtonClick (Sender);
+end;
+
+procedure TProjectOptionsForm.DataVarCheckBoxClick(Sender: TObject);
+begin
+	DataVarEdit.Enabled := DataVarCheckBox.Checked;
+	DataVarEditLabel.Enabled := DataVarEdit.Enabled;
+	DataVarCopyPanel.Enabled := DataVarEdit.Enabled;
+	DataVarCopyNeverRadioButton.Enabled := DataVarEdit.Enabled;
+	DataVarCopyIfArchivedRadioButton.Enabled := DataVarEdit.Enabled;
+	DataVarCopyAlwaysRadioButton.Enabled := DataVarEdit.Enabled;
+	DataVarCopyLabel.Enabled := DataVarEdit.Enabled;
+	VarEditChange (Sender);
+end;
+
+procedure TProjectOptionsForm.PackCheckBoxClick(Sender: TObject);
+begin
+	PackVarEdit.Enabled := PackCheckBox.Checked;
+	PackVarEditLabel.Enabled := PackVarEdit.Enabled;
+	VarEditChange (Sender);
+end;
+
+procedure TProjectOptionsForm.VarEditChange(Sender: TObject);
+var
+	S: string;
+	I: Integer;
+	OK,
+	HasFolder: Boolean;
+begin
+	if PackCheckBox.Checked then begin
+		S := PackVarEdit.Text;
+		OK := (Length (S) > 0) and (Length (S) <= 8) and (IsCharAlpha (S [1]) or (S [1] in ['A'..'Z', 'a'..'z'])) and (LowerCase (S) <> LowerCase (MainForm.TopNode.Text));
+		if OK then
+			for I := Length (S) downto 1 do
+				if (not (IsCharAlphaNumeric (S [I]) or (S [I] in ['A'..'Z', 'a'..'z', '0'..'9', '_']))) or ((I = 1) and (S [I] = '_')) then begin
+					OK := False;
+					Break;
+				end;
+	end else
+		OK := True;
+	if OK then begin
+		if DataVarCheckBox.Checked then begin
+			S := DataVarEdit.Text;
+			if PackCheckBox.Checked and (LowerCase (DataVarEdit.Text) = LowerCase (PackVarEdit.Text)) then
+				OK := False
+			else begin
+				OK := (Length (S) > 0) and (IsCharAlpha (S [1]) or (S [1] in ['A'..'Z', 'a'..'z'])) and (LowerCase (S) <> LowerCase (MainForm.TopNode.Text));
+				if OK then begin
+					HasFolder := False;
+					for I := Length (S) downto 1 do begin
+						if S [I] = '\' then begin
+							if HasFolder then begin
+								OK := False;
+								Break;
+							end else
+								HasFolder := True;
+						end else if (not (IsCharAlphaNumeric (S [I]) or (S [I] in ['A'..'Z', 'a'..'z', '0'..'9', '_']))) or ((I = 1) and (S [I] = '_')) then begin
+							OK := False;
+							Break;
+						end;
+					end;
+					I := Pos ('\', S);
+					if I > 0 then begin
+						if (I - 1 > MaxNameLength) or (Length (S) - I > MaxNameLength) or (I + 1 > Length (S)) or (not (IsCharAlpha (S [I + 1]) or (S [I + 1] in ['A'..'Z', 'a'..'z']))) then
+							OK := False;
+					end else begin
+						if Length (S) > MaxNameLength then
+							OK := False;
+					end;
+				end;
+			end;
+		end;
+	end;
+	OKButton.Enabled := OK;
+end;
+
+procedure TProjectOptionsForm.TargetRadioButtonClick(Sender: TObject);
+begin
+	LinkingSheet.TabVisible := ExecutableRadioButton.Checked or FlashOSRadioButton.Checked or FargoRadioButton.Checked;
+	PostBuildSheet.TabVisible := LinkingSheet.TabVisible;
+	DataVarCheckBox.Enabled := ExecutableRadioButton.Checked and (ssPack in SpecialSupport);
+	if not DataVarCheckBox.Enabled then
+		DataVarCheckBox.Checked := False;
+	PackCheckBox.Enabled := ExecutableRadioButton.Checked and (ssPack in SpecialSupport);
+	if not PackCheckBox.Enabled then
+		PackCheckBox.Checked := False;
+	OutputBinCheckBox.Enabled := not FlashOSRadioButton.Checked;
+	if not OutputBinCheckBox.Enabled then
+		OutputBinCheckBox.Checked := True;
+	DataVarCheckBoxClick (Sender);
+	PackCheckBoxClick (Sender);
+	ProgramOptionsButton.Visible := ExecutableRadioButton.Checked;
+end;
+
+procedure TProjectOptionsForm.BrowseButtonClick(Sender: TObject);
+var
+	S: string;
+begin
+	with BrowseDialog do begin
+		S := ProcessFileEdit.Text;
+		if (Length (S) > 0) and ((S [1] = '"') or (Pos (' ', S) <= 0)) then begin
+			if S [1] = '"' then begin
+				Delete (S, 1, 1);
+				if Pos ('"', S) > 0 then
+					Delete (S, Pos ('"', S), Length (S));
+			end;
+			FileName := S;
+		end;
+		if Execute then
+			ProcessFileEdit.Text := '"' + FileName + '" "($TI89File)" "($TI92PlusFile)" "($V200File)"';
+	end;
+end;
+
+procedure TProjectOptionsForm.ProgramOptionsButtonClick(Sender: TObject);
+begin
+	if not Assigned (ProgramOptionsForm) then begin
+		ProgramOptionsForm := TProgramOptionsForm.Create(Self);
+		if Assigned (InitialLibOptions) then
+			with ProgramOptionsForm, InitialLibOptions do begin
+				TI89CheckBox.Checked     := cdTI89     in CalcDests;
+				TI92PlusCheckBox.Checked := cdTI92Plus in CalcDests;
+				V200CheckBox.Checked     := cdV200     in CalcDests;
+				OptimizeCalcConstsCheckBox.Checked := OptimizeCalcConsts;
+				case KernelFormat of
+					kfNone:             NoStubRadioButton.Checked := True;
+					kfStandard:         DoorsRadioButton.Checked  := True;
+					kfCompressedTables: PreOsRadioButton.Checked  := True;
+				end;
+				MinAMSCheckBox.Checked := UseMinAMS;
+				MinAMSEdit.Text        := MinAMS;
+				UnofficialOSSupportCheckBox.Checked := UnofficialOSSupport;
+				case RelocFormat of
+					rfAMS:         RelocAMSRadioButton.Checked          := True;
+					rfKernel:      RelocKernelRadioButton.Checked       := True;
+					rfCompressed:  RelocCompressedRadioButton.Checked   := True;
+				end;
+				case ROMCallFormat of
+					rfDirect:      ROMCallDirectRadioButton.Checked     := True;
+					rfKernel:      ROMCallKernelRadioButton.Checked     := True;
+					rfCompressed:  ROMCallCompressedRadioButton.Checked := True;
+					rfFLine:       ROMCallFLineRadioButton.Checked      := True;
+				end;
+				case BSSRefFormat of
+					rfNone:        BSSMergeRadioButton.Checked          := True;
+					rfKernel:      BSSKernelRadioButton.Checked         := True;
+					rfCompressed:  BSSCompressedRadioButton.Checked     := True;
+				end;
+				case DataRefFormat of
+					rfKernel:      DataVarKernelRadioButton.Checked     := True;
+					rfCompressed:  DataVarCompressedRadioButton.Checked := True;
+				end;
+				RelocFLineJumpsCheckBox.Checked      := UseFLineJumps;
+				RelocFLineJumps4ByteCheckBox.Checked := Use4ByteFLineJumps;
+				ROMCallOptimizedCheckBox.Checked := OptimizeROMCalls;
+				InternalFLineEmulatorCheckBox.Checked := UseInternalFLineEmulator;
+				if UseReturnValue then
+					ReturnValueRadioButton.Checked := True
+				else
+					ReturnDoneRadioButton.Checked  := True;
+				EnableErrorReturnCheckBox.Checked := EnableErrorReturn;
+				LCDSaveCheckBox.Checked           := SaveScreen;
+			end;
+	end;
+	ProgramOptionsForm.ShowModal;
+end;
+
+end.

BIN
SendProgressUnit.dfm


+ 51 - 0
SendProgressUnit.pas

@@ -0,0 +1,51 @@
+unit SendProgressUnit;
+
+interface
+
+uses
+	LinkUnit,
+	Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+	StdCtrls, ComCtrls;
+
+type
+	TSendProgressForm = class(TForm)
+		ProgressBar: TProgressBar;
+		FileNameLabel: TLabel;
+		CancelButton: TButton;
+		procedure CancelButtonClick(Sender: TObject);
+		procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+	private
+	public
+		Cancelled: Boolean;
+		CloseNow: Boolean;
+	end;
+
+function ProgressProg(ID: Pointer; Progress: PDWord): Boolean;
+
+implementation
+
+{$R *.DFM}
+
+function ProgressProg(ID: Pointer; Progress: PDWord): Boolean;
+begin
+	with TSendProgressForm (ID) do begin
+		ProgressBar.Position := Progress^;
+		Result := not Cancelled;
+	end;
+	Application.ProcessMessages;
+end;
+
+procedure TSendProgressForm.CancelButtonClick(Sender: TObject);
+begin
+	Cancelled := True;
+end;
+
+procedure TSendProgressForm.FormCloseQuery(Sender: TObject;
+	var CanClose: Boolean);
+begin
+	CanClose := CloseNow;
+	if not CanClose then
+		Cancelled := True;
+end;
+
+end.

+ 2655 - 0
SourceFileUnit.pas

@@ -0,0 +1,2655 @@
+unit SourceFileUnit;
+
+interface
+
+uses
+	FolderUnit,
+	Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+	StdCtrls, ExtCtrls, ComCtrls,
+	MemoComponentUnit, SourceEditUnit;
+
+type
+	TSourceFile = class;
+
+	TSourceFileType = (ftCFile, ftGNUAsmFile, ftA68kAsmFile, ftQuillFile, ftOther);
+	TBugType = (btError, btWarning, btInfo);
+	TErrorCallback = procedure(const Line: string; BugTp: TBugType; SourceF: string; ErrFunc: string; ErrMessage: string; SourceLn: Integer; Offset: Integer) of object;
+	TSourceFileFunction = record
+		Name: string;
+		PrototypeLine,
+		ImplementationLine: Integer;
+	end;
+	TSourceFileFunctions = array of TSourceFileFunction;
+	PSourceFileFunctions = ^TSourceFileFunctions;
+
+	TSourceFileClass = class of TSourceFile;
+
+	TSourceFiles = class(TCollection)
+	public
+		constructor Create;
+		function FindFile(const FN: string): TSourceFile;
+		function FindFileWithoutExt(const FN: string): TSourceFile;
+		function FindFileNameOnly(const FN: string): TSourceFile;
+		function FindFileOfType(FileType: TSourceFileClass): TSourceFile;
+		function FindFileOfTypeInProject(FileType: TSourceFileClass): TSourceFile;
+	end;
+
+	TSourceFile = class(TCollectionItem)
+	private
+		FFileName: string;
+		FParentForm: TForm;
+		FTreeItem: TTreeNode;
+		FInvalidated: Boolean;
+		FOnError: TErrorCallback;
+		FErrorList: TListView;
+		FModified: Boolean;
+		FFolder: TFolder;
+		function GetSourceName: string;
+		procedure SetSourceName(const Value: string);
+		function GetEditing: Boolean;
+		function GetDynamicName: string;
+		procedure SetEditing(const Value: Boolean);
+		procedure SetCaption(const Value: TCaption);
+		function GetCaption: TCaption;
+		function GetLogicalFileName: string;
+		function GetFolderPath: string;
+	protected
+		Modifying: Boolean;
+		FLastChangeTime: Integer;
+		class function GetCompilable: Boolean; virtual;
+		class function GetPrintable: Boolean; virtual;
+		function GetInProject: Boolean; virtual;
+		procedure SetFileName(const Value: string); virtual;
+		procedure SetModified(const Value: Boolean); virtual;
+		function GetEditor: TWinControl; virtual;
+		procedure ProcessErrors(const ErrText: string); virtual;
+		procedure ProcessErrorLine(Line: string); dynamic;
+	public
+		class function GetClassFilter: string; virtual;
+		class function GetClassItemName: string; virtual;
+		class function GetClassTreeIndex: Integer; virtual;
+		class function GetClassImageIndex: Integer; virtual;
+		destructor Destroy; override;
+		class function GetAppropriateClassFromName(ItemNm: string): TSourceFileClass;
+		class function GetAppropriateClassFromExt(Ext: string): TSourceFileClass;
+		class function GetAppropriateClassFromTreeIndex(Index: Integer): TSourceFileClass;
+		procedure WriteToFile(const FN: string = ''; SetFN: Boolean = False); virtual;
+		procedure LoadFromFile(const FN: string = ''; SetFN: Boolean = False); virtual;
+		procedure Save; virtual;
+		procedure SaveAs; virtual;
+		class function CanSave: Boolean; virtual;
+		procedure Compile; virtual;
+		procedure Print(Copies: Integer; PrintRange: TPrintRange; FromPage, ToPage: Integer); virtual;
+		function CountPages: Integer; virtual;
+		procedure Modify;
+		procedure WarnIfModified;
+		procedure Invalidate;
+		procedure Edit; virtual;
+		procedure TestChange; virtual;
+		procedure UpdateProgramOutput; virtual;
+		property ClassFilter: string read GetClassFilter;
+		property ClassItemName: string read GetClassItemName;
+		property ClassTreeIndex: Integer read GetClassTreeIndex;
+		property ClassImageIndex: Integer read GetClassImageIndex;
+		property Compilable: Boolean read GetCompilable;
+		property Printable: Boolean read GetPrintable;
+		property InProject: Boolean read GetInProject;
+		property Editor: TWinControl read GetEditor;
+		property SourceName: string read GetSourceName write SetSourceName;
+		property DynamicName: string read GetDynamicName;
+	published
+		property FileName: string read FFileName write SetFileName;
+		property Editing: Boolean read GetEditing write SetEditing;
+		property Modified: Boolean read FModified write SetModified;
+		property Invalidated: Boolean read FInvalidated write FInvalidated;
+		property TreeItem: TTreeNode read FTreeItem write FTreeItem;
+		property ParentForm: TForm read FParentForm write FParentForm;
+		property ErrorList: TListView read FErrorList write FErrorList;
+		property Caption: TCaption read GetCaption write SetCaption;
+		property OnError: TErrorCallback read FOnError write FOnError;
+		property Folder: TFolder read FFolder write FFolder;
+		property FolderPath: string read GetFolderPath;
+		property LogicalFileName: string read GetLogicalFileName;
+	end;
+
+	TTextSourceFile = class(TSourceFile)
+	private
+		FModifyLevel: Integer;
+	protected
+		LineStartList: TIntegerList;
+		FTempContent: string;
+		class function GetPrintable: Boolean; override;
+		function GetEditor: TWinControl; override;
+		function GetTextEditor: TMemoComponent; virtual; abstract;
+		function GetInternalTextEditor: TMemoComponent; virtual; abstract;
+		function GetContent: string; virtual;
+		procedure SetContent(const Value: string); virtual;
+		procedure SetModified(const Value: Boolean); override;
+		procedure Change(Sender: TObject); virtual;
+		procedure ReplaceText(Sender: TObject; Pos, Change: Integer); virtual;
+		procedure SetParentForm(const Value: TForm); virtual;
+		property InternalTextEditor: TMemoComponent read GetInternalTextEditor;
+	public
+		destructor Destroy; override;
+		procedure WriteToFile(const FN: string = ''; SetFN: Boolean = False); override;
+		procedure LoadFromFile(const FN: string = ''; SetFN: Boolean = False); override;
+		procedure Print(Copies: Integer; PrintRange: TPrintRange; FromPage, ToPage: Integer); override;
+		function CountPages: Integer; override;
+		procedure TestChange; override;
+		procedure AskForReload; virtual;
+		procedure UpdateEditor; virtual;
+		function GetLineContents(StartLine, EndLine: Integer): string;
+		function GetCompiledLineStart(Line: Integer): Integer; virtual;
+		property TextEditor: TMemoComponent read GetTextEditor;
+		property Content: string read GetContent write SetContent;
+	end;
+
+	TBinarySourceFile = class(TSourceFile)
+	public
+		class function CanSave: Boolean; override;
+		procedure WriteToFile(const FN: string = ''; SetFN: Boolean = False); override;
+	end;
+
+	TNormalTextSourceFile = class(TTextSourceFile)
+	private
+		FEditor: TMemoComponent;
+	protected
+		function GetTextEditor: TMemoComponent; override;
+		function GetInternalTextEditor: TMemoComponent; override;
+	public
+		class function GetClassFilter: string; override;
+		class function GetClassItemName: string; override;
+		class function GetClassTreeIndex: Integer; override;
+		class function GetClassImageIndex: Integer; override;
+		destructor Destroy; override;
+	end;
+
+	TSourceTextSourceFile = class(TTextSourceFile)
+	private
+		FEditor: TSourceEdit;
+		function GetSourceEditor: TSourceEdit;
+	protected
+		function GetTextEditor: TMemoComponent; override;
+		function GetInternalTextEditor: TMemoComponent; override;
+		function GetContentType: TSourceFileType; virtual;
+		property InternalSourceEditor: TSourceEdit read FEditor;
+	public
+		destructor Destroy; override;
+		procedure UpdateSyntax; virtual; abstract;
+		procedure UpdateEditor; override;
+		procedure SplitAndWriteToFile(const FN: string); virtual;
+		function GetFunctions: TSourceFileFunctions; virtual;
+		property SourceEditor: TSourceEdit read GetSourceEditor;
+		property ContentType: TSourceFileType read GetContentType;
+	end;
+
+	THeaderSourceFile = class(TSourceTextSourceFile)
+	protected
+		procedure SetContent(const Value: string); override;
+		procedure SetModified(const Value: Boolean); override;
+		function GetContentType: TSourceFileType; override;
+	public
+		class function GetClassFilter: string; override;
+		class function GetClassItemName: string; override;
+		class function GetClassTreeIndex: Integer; override;
+		class function GetClassImageIndex: Integer; override;
+		procedure UpdateSyntax; override;
+		procedure UpdateEditor; override;
+		procedure UpdateContentType(CT: TSourceFileType); virtual;
+	end;
+
+	TCSourceFile = class(TSourceTextSourceFile)
+	private
+		FSFileChangedLines: TIntegerList;
+		FSFileLineChanges: TIntegerList;
+	protected
+		CurErrFunction: string;
+		InAssemblingState: Boolean;
+		SpecialSwitches: string;
+		class function GetCompilable: Boolean; override;
+		procedure SetModified(const Value: Boolean); override;
+		function GetContentType: TSourceFileType; override;
+		procedure SFileLineChange(StartLine, Change: Integer);
+		procedure SFileMapLine(var Line: Integer);
+		procedure SFileClear;
+		procedure ProcessErrorLine(Line: string); override;
+		procedure ProcessSFile(const SourceFile, DestFile: string);
+	public
+		destructor Destroy; override;
+		class function GetClassFilter: string; override;
+		class function GetClassItemName: string; override;
+		class function GetClassTreeIndex: Integer; override;
+		class function GetClassImageIndex: Integer; override;
+		procedure Save; override;
+		procedure Compile; override;
+		procedure UpdateSyntax; override;
+		procedure UpdateEditor; override;
+	end;
+
+	TGNUAsmSourceFile = class(TSourceTextSourceFile)
+	protected
+		class function GetCompilable: Boolean; override;
+		procedure SetModified(const Value: Boolean); override;
+		function GetContentType: TSourceFileType; override;
+		procedure ProcessErrorLine(Line: string); override;
+	public
+		class function GetClassFilter: string; override;
+		class function GetClassItemName: string; override;
+		class function GetClassTreeIndex: Integer; override;
+		class function GetClassImageIndex: Integer; override;
+		procedure Save; override;
+		procedure Compile; override;
+		procedure UpdateSyntax; override;
+		procedure UpdateEditor; override;
+	end;
+
+	TAsmSourceFile = class(TSourceTextSourceFile)
+	protected
+		class function GetCompilable: Boolean; override;
+		procedure SetModified(const Value: Boolean); override;
+		function GetContentType: TSourceFileType; override;
+	public
+		class function GetClassFilter: string; override;
+		class function GetClassItemName: string; override;
+		class function GetClassTreeIndex: Integer; override;
+		class function GetClassImageIndex: Integer; override;
+		procedure Save; override;
+		procedure Compile; override;
+		procedure UpdateSyntax; override;
+		procedure UpdateEditor; override;
+	end;
+
+	TQuillSourceFile = class(TCSourceFile)
+	protected
+		function GetContentType: TSourceFileType; override;
+	public
+		class function GetClassFilter: string; override;
+		class function GetClassItemName: string; override;
+		class function GetClassTreeIndex: Integer; override;
+		class function GetClassImageIndex: Integer; override;
+		procedure Compile; override;
+		procedure UpdateSyntax; override;
+	end;
+
+	TObjectSourceFile = class(TBinarySourceFile)
+	public
+		class function GetClassFilter: string; override;
+		class function GetClassItemName: string; override;
+		class function GetClassTreeIndex: Integer; override;
+		class function GetClassImageIndex: Integer; override;
+	end;
+
+	TArchiveSourceFile = class(TBinarySourceFile)
+	public
+		class function GetClassFilter: string; override;
+		class function GetClassItemName: string; override;
+		class function GetClassTreeIndex: Integer; override;
+		class function GetClassImageIndex: Integer; override;
+	end;
+
+	TOtherSourceFile = class(TBinarySourceFile)
+	public
+		class function GetClassFilter: string; override;
+		class function GetClassItemName: string; override;
+		class function GetClassTreeIndex: Integer; override;
+		class function GetClassImageIndex: Integer; override;
+	end;
+
+	TFoundError = class(TObject)
+	public
+		WholeLine: string;
+		BugType: TBugType;
+		ErrFunction: string;
+		ErrorMessage: string;
+		SourceFile: TSourceFile;
+		Range: TMCRange;
+		destructor Destroy; override;
+		procedure GoToPosition;
+	end;
+
+var
+	AppNode: TTreeNode;
+	NoEditor: TWinControl;
+
+implementation
+
+uses
+	Printers,
+	MasterUnit, ParsingUnit, ProcessUnit,
+	UtilsDos, UtilsWin,
+	HandleWaitThreadUnit, FileReadToBufferThreadUnit;
+
+const
+	CSingleSymbols: set of Char = [',', ';', '(', ')', '[', ']', '{', '}'];
+	AdditionalLinesPerPage = 4;
+
+{ TFoundError }
+
+destructor TFoundError.Destroy;
+begin
+	if Assigned (Range) then begin
+		Range.Free;
+		Range := nil;
+	end;
+	inherited;
+end;
+
+procedure TFoundError.GoToPosition;
+begin
+	if Assigned (SourceFile) then begin
+		with SourceFile do begin
+			if Assigned (Editor) then begin
+				Edit;
+				if SourceFile is TSourceTextSourceFile then
+					with SourceFile as TSourceTextSourceFile do
+						with SourceEditor do begin
+							if Assigned (Range) then begin
+								with Selection do begin
+									Assign (Range);
+									ScrollInView (5);
+								end;
+								SetFocus;
+							end;
+						end;
+			end;
+		end;
+	end else
+		AppNode.Selected := True;
+end;
+
+{ TSourceFiles }
+
+constructor TSourceFiles.Create;
+begin
+	inherited Create (TSourceFile);
+end;
+
+function TSourceFiles.FindFile(const FN: string): TSourceFile;
+var
+	I: Integer;
+begin
+	Result := nil;
+	for I := 0 to Count - 1 do
+		with Items [I] as TSourceFile do
+			if UpperCase (FN) = UpperCase (FileName) then begin
+				Result := Items [I] as TSourceFile;
+				Break;
+			end;
+end;
+
+function TSourceFiles.FindFileNameOnly(const FN: string): TSourceFile;
+var
+	I: Integer;
+begin
+	Result := nil;
+	for I := 0 to Count - 1 do
+		with Items [I] as TSourceFile do
+			if UpperCase (FN) = UpperCase (ExtractFileName (FileName)) then begin
+				Result := Items [I] as TSourceFile;
+				Break;
+			end;
+end;
+
+function TSourceFiles.FindFileOfType(FileType: TSourceFileClass):
+	TSourceFile;
+var
+	I: Integer;
+begin
+	Result := nil;
+	for I := 0 to Count - 1 do
+		if Items [I] is FileType then begin
+			Result := Items [I] as TSourceFile;
+			Break;
+		end;
+end;
+
+function TSourceFiles.FindFileOfTypeInProject(FileType: TSourceFileClass):
+	TSourceFile;
+var
+	I: Integer;
+begin
+	Result := nil;
+	for I := 0 to Count - 1 do
+		if (Items [I] is FileType) and (Items [I] as TSourceFile).InProject then begin
+			Result := Items [I] as TSourceFile;
+			Break;
+		end;
+end;
+
+function TSourceFiles.FindFileWithoutExt(const FN: string): TSourceFile;
+var
+	I: Integer;
+begin
+	Result := nil;
+	for I := 0 to Count - 1 do
+		with Items [I] as TSourceFile do
+			if UpperCase (FN) = UpperCase (WithoutExt (FileName)) then begin
+				Result := Items [I] as TSourceFile;
+				Break;
+			end;
+end;
+
+{ TSourceFile }
+
+class function TSourceFile.CanSave: Boolean;
+begin
+	Result := True;
+end;
+
+procedure TSourceFile.Compile;
+begin
+end;
+
+function TSourceFile.CountPages: Integer;
+begin
+	Result := 0;
+end;
+
+destructor TSourceFile.Destroy;
+var
+	I: Integer;
+	F: TForm;
+	N: TTreeNode;
+begin
+	if Assigned (ErrorList) then
+		with ErrorList.Items do begin
+			BeginUpdate;
+			for I := Count - 1 downto 0 do
+				if Assigned (Item[I].Data) then
+					with TFoundError (Item[I].Data) do
+						if SourceFile = Self then begin
+							Range := nil;
+							Item[I].Delete;
+						end;
+			EndUpdate;
+		end;
+	if Assigned (OnError) then
+		OnError ('', btWarning, FileName, '', '', 0, 0);
+	if Assigned (ParentForm) then begin
+		F := ParentForm;
+		ParentForm := nil;
+		F.Free;
+	end;
+	if Assigned (TreeItem) then begin
+		N := TreeItem;
+		TreeItem := nil;
+		N.Data := nil;
+		N.Free;
+	end;
+	inherited;
+end;
+
+procedure TSourceFile.Edit;
+begin
+	if Assigned (TreeItem) then
+		TreeItem.Selected := True
+	else if Assigned (ParentForm) then begin
+		ParentForm.Show;
+		ParentForm.SetFocus;
+	end;
+end;
+
+class function TSourceFile.GetAppropriateClassFromExt(Ext: string): TSourceFileClass;
+begin
+	Ext := LowerCase (Ext);
+	if (Length (Ext) > 0) and (Ext [1] <> '.') then
+		Ext := '.' + Ext;
+	if Ext = '.h' then
+		Result := THeaderSourceFile
+	else if Ext = '.c' then
+		Result := TCSourceFile
+	else if Ext = '.s' then
+		Result := TGNUAsmSourceFile
+	else if Ext = '.asm' then begin
+		if ssA68k in SpecialSupport then
+			Result := TAsmSourceFile
+		else
+			Result := TGNUAsmSourceFile;
+	end else if (Ext = '.qll') and (ssQuill in SpecialSupport) then
+		Result := TQuillSourceFile
+	else if Ext = '.o' then
+		Result := TObjectSourceFile
+	else if Ext = '.a' then
+		Result := TArchiveSourceFile
+	else if Ext = '.txt' then
+		Result := TNormalTextSourceFile
+	else
+		Result := TOtherSourceFile;
+end;
+
+class function TSourceFile.GetAppropriateClassFromName(ItemNm: string): TSourceFileClass;
+procedure CheckClass(AClass: TSourceFileClass);
+begin
+	if (not Assigned (Result)) and (ItemNm = UpperCase (AClass.GetClassItemName)) then
+		Result := AClass;
+end;
+begin
+	ItemNm := UpperCase (ItemNm);
+	Result := nil;
+	CheckClass (THeaderSourceFile);
+	CheckClass (TCSourceFile);
+	CheckClass (TGNUAsmSourceFile);
+	CheckClass (TAsmSourceFile);
+	CheckClass (TQuillSourceFile);
+	CheckClass (TObjectSourceFile);
+	CheckClass (TArchiveSourceFile);
+	CheckClass (TNormalTextSourceFile);
+	CheckClass (TOtherSourceFile);
+	if (Result = TAsmSourceFile) and (not (ssA68k in SpecialSupport)) then
+		Result := TGNUAsmSourceFile
+	else if (Result = TQuillSourceFile) and (not (ssQuill in SpecialSupport)) then
+		Result := TQuillSourceFile;
+end;
+
+class function TSourceFile.GetAppropriateClassFromTreeIndex(Index: Integer): TSourceFileClass;
+procedure CheckClass(AClass: TSourceFileClass);
+begin
+	if (not Assigned (Result)) and (Index = AClass.GetClassTreeIndex) then
+		Result := AClass;
+end;
+begin
+	Result := nil;
+	CheckClass (THeaderSourceFile);
+	CheckClass (TCSourceFile);
+	CheckClass (TGNUAsmSourceFile);
+	if ssA68k in SpecialSupport then
+		CheckClass (TAsmSourceFile);
+	if ssQuill in SpecialSupport then
+		CheckClass (TQuillSourceFile);
+	CheckClass (TObjectSourceFile);
+	CheckClass (TArchiveSourceFile);
+	CheckClass (TNormalTextSourceFile);
+	CheckClass (TOtherSourceFile);
+end;
+
+function TSourceFile.GetCaption: TCaption;
+begin
+	if Assigned (TreeItem) then
+		Result := TreeItem.Text
+	else if Assigned (ParentForm) then
+		Result := ParentForm.Caption
+	else
+		Result := '';
+end;
+
+class function TSourceFile.GetClassFilter: string;
+begin
+	Result := 'Abstract Files (*.*)|*.*';
+end;
+
+class function TSourceFile.GetClassImageIndex: Integer;
+begin
+	Result := -1;
+end;
+
+class function TSourceFile.GetClassItemName: string;
+begin
+	Result := 'Abstract File';
+end;
+
+class function TSourceFile.GetClassTreeIndex: Integer;
+begin
+	Result := -1;
+end;
+
+class function TSourceFile.GetCompilable: Boolean;
+begin
+	Result := False;
+end;
+
+function TSourceFile.GetDynamicName: string;
+var
+	S: string;
+begin
+	S := ExtractFilePath (FileName);
+	if StartsWith (ExtractFilePath (ProjectFileName), S) then
+		Result := Copy (FileName, Length (ExtractFilePath (ProjectFileName)) + 1, Length (FileName))
+	else
+		Result := FileName;
+end;
+
+function TSourceFile.GetEditing: Boolean;
+begin
+	if Assigned (TreeItem) then
+		Result := TreeItem.Selected
+	else if Assigned (ParentForm) then
+		Result := ParentForm.Visible
+	else
+		Result := False;
+end;
+
+function TSourceFile.GetEditor: TWinControl;
+begin
+	if Assigned (TreeItem) then
+		Result := NoEditor
+	else
+		Result := nil;
+end;
+
+function TSourceFile.GetFolderPath: string;
+begin
+	if Assigned (Folder) then
+		Result := Folder.Path
+	else
+		Result := '';
+end;
+
+function TSourceFile.GetInProject: Boolean;
+begin
+	Result := Assigned (TreeItem);
+end;
+
+function TSourceFile.GetLogicalFileName: string;
+var
+	Path: string;
+begin
+	Result := ExtractFileName (FileName);
+	Path := FolderPath;
+	if Length (Path) > 0 then
+		Result := WithBackslash (Path) + Result;
+end;
+
+class function TSourceFile.GetPrintable: Boolean;
+begin
+	Result := False;
+end;
+
+function TSourceFile.GetSourceName: string;
+begin
+	Result := WithoutExt (ExtractFileName (FileName));
+end;
+
+procedure TSourceFile.Invalidate;
+begin
+	Invalidated := True;
+end;
+
+procedure TSourceFile.LoadFromFile(const FN: string; SetFN: Boolean);
+begin
+	if SetFN and (Length (FN) > 0) then
+		FFileName := FN; 
+	Modified := False;
+end;
+
+procedure TSourceFile.Modify;
+begin
+	Modified := True;
+	Invalidate;
+end;
+
+procedure TSourceFile.Print(Copies: Integer; PrintRange: TPrintRange; FromPage, ToPage: Integer);
+begin
+end;
+
+procedure TSourceFile.ProcessErrorLine(Line: string);
+begin
+end;
+
+procedure TSourceFile.ProcessErrors(const ErrText: string);
+var
+	I: Integer;
+	LL: TStringList;
+begin
+	UpdateProgramOutput;
+	if not OperationCancelled then begin
+		LL := TStringList.Create;
+		with LL do try
+			Text := ErrText;
+			if Count > 0 then begin
+				if Assigned (ErrorList) then
+					ErrorList.Items.BeginUpdate;
+				try
+					for I := 0 to Count - 1 do
+						ProcessErrorLine (Strings [I]);
+				finally
+					if Assigned (ErrorList) then
+						ErrorList.Items.EndUpdate;
+				end;
+			end;
+		except end;
+		LL.Free;
+		CompUpdate;
+	end;
+end;
+
+procedure TSourceFile.Save;
+begin
+	if (ProjectFileName = '') and (ExtractFilePath (FileName) = 'C:\') then
+		SaveAs
+	else begin
+		FLastChangeTime := 0;
+		WriteToFile;
+		Modified := False;
+	end;
+end;
+
+procedure TSourceFile.SaveAs;
+var
+	S: string;
+begin
+	with TSaveDialog.Create (Application.MainForm) do try
+		Title := 'Save Source File';
+		S := ClassFilter + '|All Files (*.*)|*.*';
+		if S [1] = '|' then
+			Delete (S, 1, 1);
+		Filter := S;
+		FilterIndex := 0;
+		DefaultExt := Copy (ExtractFileExt (Self.FileName), 2, Length (Self.FileName));
+		FileName := Self.FileName;
+		Options := [ofOverwritePrompt, ofHideReadOnly, ofPathMustExist];
+		if Execute then
+			WriteToFile (FileName, True)
+		else
+			Abort;
+	finally
+		Free;
+	end;
+end;
+
+procedure TSourceFile.SetCaption(const Value: TCaption);
+begin
+	if Value <> Caption then begin
+		if Assigned (TreeItem) then
+			TreeItem.Text := Value;
+		if Assigned (ParentForm) then
+			ParentForm.Caption := Value;
+	end;
+end;
+
+procedure TSourceFile.SetEditing(const Value: Boolean);
+begin
+	if Value then
+		Edit
+	else
+		AppNode.Selected := True;
+end;
+
+procedure TSourceFile.SetFileName(const Value: string);
+begin
+	if FFileName <> Value then begin
+		if FileExists (Value) then
+			raise EWriteError.Create ('The file "' + Value + '" already exists.')
+		else
+			if FileExists (FFileName) then begin
+				RenameFile (FFileName, Value);
+				if (LowerCase (ExtractFileExt (FFileName)) <> '.o') and FileExists (ChangeFileExt (FFileName, '.o')) then
+					RenameFile (ChangeFileExt (FFileName, '.o'), ChangeFileExt (Value, '.o'));
+				if (LowerCase (ExtractFileExt (FFileName)) <> '.s') and FileExists (ChangeFileExt (FFileName, '.s')) then
+					RenameFile (ChangeFileExt (FFileName, '.s'), ChangeFileExt (Value, '.s'));
+			end;
+		FFileName := Value;
+	end;
+end;
+
+procedure TSourceFile.SetModified(const Value: Boolean);
+begin
+	FModified := Value;
+	Invalidated := False;
+end;
+
+procedure TSourceFile.SetSourceName(const Value: string);
+begin
+	FileName := WithBackslash (ExtractFilePath (FileName)) + Value + ExtractFileExt (FileName);
+end;
+
+procedure TSourceFile.TestChange;
+begin
+end;
+
+procedure TSourceFile.UpdateProgramOutput;
+begin
+	if Assigned (CompUpdateProgramOutput) then
+		CompUpdateProgramOutput;
+end;
+
+procedure TSourceFile.WarnIfModified;
+begin
+	if Modified then
+		case ShowDefaultMessageBox
+			('The file ''' + SourceName + ''' has been modified.  Do you want to save the changes?',
+			'File Modified', mtQuestion, True) of
+			idYes: Save;
+			idNo: Modified := False;
+			idCancel: Abort;
+		end;
+end;
+
+procedure TSourceFile.WriteToFile(const FN: string; SetFN: Boolean);
+begin
+	if SetFN and (Length (FN) > 0) then
+		FFileName := FN;
+	if SetFN or (Length (FN) <= 0) then begin
+		FLastChangeTime := 0;
+		Caption := SourceName;
+		Modified := False;
+	end;
+end;
+
+{ TTextSourceFile }
+
+procedure TTextSourceFile.AskForReload;
+begin
+	if ShowDefaultMessageBox ('The File "' + SourceName + '" has been changed by another program. Do you want to reload it?', 'File Changed', mtQuestion) = idYes then begin
+		try
+			LoadFromFile;
+		except end;
+		Invalidate;
+	end;
+end;
+
+procedure TTextSourceFile.Change(Sender: TObject);
+begin
+	if (FModifyLevel <= 0) and (not Modifying) then
+		Modify;
+end;
+
+function TTextSourceFile.CountPages: Integer;
+var
+	FontHeight,
+	LinesPerPage: Integer;
+begin
+	if Assigned (TextEditor) then begin
+		Printer.Canvas.Font.Assign (TextEditor.Font);
+		FontHeight := Printer.Canvas.TextHeight ('Gg');
+		LinesPerPage := Printer.PageHeight div FontHeight - AdditionalLinesPerPage;
+		Result := TextEditor.LineCount div LinesPerPage + 1;
+	end else
+		Result := 0;
+end;
+
+destructor TTextSourceFile.Destroy;
+begin
+	if Assigned (LineStartList) then begin
+		LineStartList.Free;
+		LineStartList := nil;
+	end;
+	inherited;
+end;
+
+function TTextSourceFile.GetCompiledLineStart(Line: Integer): Integer;
+begin
+	if (Line > 0) and Assigned (TextEditor) then begin
+		if Assigned (LineStartList) then
+			with LineStartList do begin
+				if Line >= Count then
+					Result := TextEditor.TextLength + 1
+				else
+					Result := Items [Line];
+			end
+		else
+			Result := TextEditor.CellToCharIdx (TextCell (Line, 1));
+	end else
+		Result := 0;
+end;
+
+function TTextSourceFile.GetContent: string;
+begin
+	if Assigned (InternalTextEditor) then
+		Result := InternalTextEditor.Text
+	else
+		Result := FTempContent;
+end;
+
+function TTextSourceFile.GetEditor: TWinControl;
+begin
+	Result := TextEditor;
+end;
+
+function TTextSourceFile.GetLineContents(StartLine, EndLine: Integer): string;
+var
+	Start: Integer;
+begin
+	if Assigned (TextEditor) then begin
+		Start := GetCompiledLineStart (StartLine);
+		Result := Copy (TextEditor.Text, Start, GetCompiledLineStart (EndLine + 1) - Start);
+	end else
+		Result := '';
+end;
+
+class function TTextSourceFile.GetPrintable: Boolean;
+begin
+	Result := True;
+end;
+
+procedure TTextSourceFile.LoadFromFile(const FN: string; SetFN: Boolean);
+begin
+	if Assigned (InternalTextEditor) then
+		InternalTextEditor.AllowUndo := False;
+	Inc (FModifyLevel);
+	try
+		with TMemoryStream.Create do try
+			if Length (FN) > 0 then
+				LoadFromFile (FN)
+			else
+				LoadFromFile (FileName);
+			Size := Size + 1;
+			PChar (Memory) [Size - 1] := #0;
+			Content := AnsiString (PChar (Memory));
+		finally
+			Free;
+		end;
+	finally
+		Dec (FModifyLevel);
+		if Assigned (InternalTextEditor) then
+			InternalTextEditor.AllowUndo := True;
+		inherited;
+		if Compilable then begin
+			if FileExists (ChangeFileExt (FileName, '.o')) then
+				Invalidated := FileAge (ChangeFileExt (FileName, '.o')) < FileAge (FileName)
+			else
+				Invalidated := True;
+		end else
+			Invalidated := False;
+	end;
+end;
+
+procedure TTextSourceFile.Print(Copies: Integer; PrintRange: TPrintRange; FromPage, ToPage: Integer);
+var
+	CurPage,
+	CurPageLine,
+	CurY,
+	FontHeight,
+	LinesPerPage: Integer;
+	procedure StartPage;
+	var
+		PrevStyle: TFontStyles;
+		PageStr: string;
+	begin
+		Inc (CurPage);
+		if CurPage in [FromPage..ToPage] then
+			with Printer.Canvas do begin
+				PrevStyle := Font.Style;
+				Font.Style := PrevStyle + [fsBold];
+				TextOut (0, FontHeight, '  ' + ExtractFileName (FileName));
+				PageStr := 'Page ' + IntToStr (CurPage) + '  ';
+				TextOut (Printer.PageWidth - TextWidth (PageStr), FontHeight, PageStr);
+				Font.Style := PrevStyle;
+			end;
+		CurY := FontHeight * 3;
+		CurPageLine := 1;
+	end;
+var
+	Remaining,
+	S: string;
+	P,
+	Ps,
+	NextPs: Integer;
+begin
+	if Assigned (TextEditor) then begin
+		Printer.Title := 'TIGCC IDE - ' + ExtractFileName (FileName);
+		Printer.Copies := Copies;
+		Printer.BeginDoc;
+		try
+			Printer.Canvas.Font.Assign (TextEditor.Font);
+			FontHeight := Printer.Canvas.TextHeight ('Gg');
+			LinesPerPage := Printer.PageHeight div FontHeight - AdditionalLinesPerPage;
+			if PrintRange <> prPageNums then begin
+				FromPage := 1;
+				ToPage := High (ToPage);
+			end;
+			if PrintRange = prSelection then
+				Remaining := TextEditor.Selection.Text
+			else
+				Remaining := Content;
+			CurPage := 0;
+			StartPage;
+			while (Length (Remaining) > 0) and (CurPage <= ToPage) do begin
+				P := Pos (#13#10, Remaining);
+				if P <= 0 then
+					P := Length (Remaining) + 1;
+				S := Copy (Remaining, 1, P - 1);
+				Delete (Remaining, 1, P + 1);
+				Ps := 1;
+				while Ps <= Length (S) do begin
+					if S [Ps] = #9 then begin
+						NextPs := ((Ps - 1) div TextEditor.TabSize + 1) * TextEditor.TabSize + 1;
+						System.Delete (S, Ps, 1);
+						System.Insert (StringOfChar (' ', NextPs - Ps), S, Ps);
+						Ps := NextPs;
+					end else
+						Inc (Ps);
+				end;
+				if CurPage in [FromPage..ToPage] then
+					Printer.Canvas.TextOut (0, CurY, '  ' + S);
+				Inc (CurPageLine);
+				if CurPageLine > LinesPerPage then begin
+					if CurPage in [FromPage..(ToPage-1)] then
+						Printer.NewPage;
+					StartPage;
+				end else
+					Inc (CurY, FontHeight);
+			end;
+		finally
+			Printer.EndDoc;
+		end;
+	end;
+end;
+
+procedure TTextSourceFile.ReplaceText(Sender: TObject; Pos,
+	Change: Integer);
+var
+	I,
+	FirstChangeI,
+	FirstChangePos: Integer;
+begin
+	if Assigned (LineStartList) then
+		with LineStartList do begin
+			FirstChangeI := -1;
+			FirstChangePos := -1;
+			for I := 0 to Count - 1 do
+				if Items [I] > Pos then begin
+					FirstChangeI := I;
+					FirstChangePos := Items [I];
+					Break;
+				end;
+			if FirstChangeI >= 0 then begin
+				for I := FirstChangeI to Count - 1 do
+					Items [I] := Items [I] + Change;
+				for I := FirstChangeI to Count - 1 do begin
+					if Items [I] >= FirstChangePos then
+						Break;
+					Items [I] := FirstChangePos;
+				end;
+			end;
+		end;
+end;
+
+procedure TTextSourceFile.SetContent(const Value: string);
+begin
+	if Assigned (InternalTextEditor) then begin
+		with InternalTextEditor do
+			Text := Value;
+	end else
+		FTempContent := Value;
+end;
+
+procedure TTextSourceFile.SetModified(const Value: Boolean);
+begin
+	if not Modifying then begin
+		Modifying := True;
+		FModified := Value;
+		Invalidated := False;
+		Modifying := False;
+	end;
+end;
+
+procedure TTextSourceFile.SetParentForm(const Value: TForm);
+begin
+	inherited;
+	if Assigned (TextEditor) then
+		with TextEditor do begin
+			Parent := Value;
+			if Value <> nil then
+				Show;
+		end;
+end;
+
+procedure TTextSourceFile.TestChange;
+var
+	NewTime: Integer;
+	TimeChanged: Boolean;
+begin
+	if (Length (FileName) > 0) and FileExists (FileName) then begin
+		NewTime := FileAge (FileName);
+		TimeChanged := (FLastChangeTime <> 0) and (FLastChangeTime <> NewTime);
+		FLastChangeTime := NewTime;
+		if TimeChanged then
+			AskForReload;
+	end;
+end;
+
+procedure TTextSourceFile.UpdateEditor;
+begin
+	if Assigned (TextEditor) then
+		with TextEditor do begin
+			Color := EditorColor;
+			Font.Assign (EditorFont);
+			DragDropEditing := EditorDragDrop;
+			RemoveTrailingSpaces := EditorRemoveTrSp;
+		end;
+end;
+
+procedure TTextSourceFile.WriteToFile(const FN: string; SetFN: Boolean);
+var
+	WriteFile: string;
+begin
+	if Assigned (TextEditor) then try
+		if Length (FN) > 0 then
+			WriteFile := FN
+		else
+			WriteFile := FileName;
+		CreatePathFor (WriteFile);
+		with TFileStream.Create (WriteFile, fmCreate or fmShareExclusive) do try
+			Write (PChar(TextEditor.Text)^, TextEditor.TextLength);
+		finally
+			Free;
+		end;
+		inherited;
+	except
+		ShowDefaultMessageBox ('Error saving source file.', 'Error', mtProgramError);
+	end;
+end;
+
+{ TBinarySourceFile }
+
+class function TBinarySourceFile.CanSave: Boolean;
+begin
+	Result := False;
+end;
+
+procedure TBinarySourceFile.WriteToFile(const FN: string; SetFN: Boolean);
+begin
+	if Length (FN) > 0 then
+		CopyFile (PChar (FileName), PChar (FN), False);
+	inherited;
+end;
+
+{ THeaderSourceFile }
+
+class function THeaderSourceFile.GetClassFilter: string;
+begin
+	Result := 'Header Files (*.h)|*.h';
+end;
+
+class function THeaderSourceFile.GetClassImageIndex: Integer;
+begin
+	Result := 3;
+end;
+
+class function THeaderSourceFile.GetClassItemName: string;
+begin
+	Result := 'Header File';
+end;
+
+class function THeaderSourceFile.GetClassTreeIndex: Integer;
+begin
+	Result := 0;
+end;
+
+function THeaderSourceFile.GetContentType: TSourceFileType;
+begin
+	Result := ftOther;
+	if Content <> '' then begin
+		if Content [1] = '/' then
+			Result := ftCFile
+		else if Content [1] = '|' then
+			Result := ftGNUAsmFile
+		else if Content [1] = ';' then
+			Result := ftA68kAsmFile;
+	end;
+	if Result = ftOther then
+		if Assigned (Collection) and (Collection is TSourceFiles) then
+			with Collection as TSourceFiles do
+				if Assigned (FindFileOfType (TCSourceFile)) then
+					Result := ftCFile
+				else if Assigned (FindFileOfType (TGNUAsmSourceFile)) then
+					Result := ftGNUAsmFile
+				else if Assigned (FindFileOfType (TAsmSourceFile)) then
+					Result := ftA68kAsmFile
+				else if Assigned (FindFileOfType (TQuillSourceFile)) then
+					Result := ftQuillFile;
+end;
+
+procedure THeaderSourceFile.SetContent(const Value: string);
+begin
+	if Length (Value) > 0 then begin
+		if Value [1] = '/' then
+			UpdateContentType (ftCFile)
+		else if Value [1] = '|' then
+			UpdateContentType (ftGNUAsmFile)
+		else if Value [1] = ';' then
+			UpdateContentType (ftA68kAsmFile);
+	end;
+	inherited;
+end;
+
+procedure THeaderSourceFile.SetModified(const Value: Boolean);
+begin
+	if not Modifying then begin
+		Modifying := True;
+		FModified := Value;
+		if Value then
+			Invalidate;
+		Modifying := False;
+	end;
+end;
+
+procedure THeaderSourceFile.UpdateContentType(CT: TSourceFileType);
+begin
+	if Assigned (InternalSourceEditor) then
+		with InternalSourceEditor do begin
+			if CT = ftGNUAsmFile then begin
+				SyntaxColoring.Assign (SyntaxAsmGNU);
+				TabSize := TabSizeAsm;
+			end else if CT = ftA68kAsmFile then begin
+				SyntaxColoring.Assign (SyntaxAsm);
+				TabSize := TabSizeAsm;
+			end else if CT = ftQuillFile then begin
+				SyntaxColoring.Assign (SyntaxQuill);
+				TabSize := TabSizeC;
+			end else begin
+				SyntaxColoring.Assign (SyntaxC);
+				TabSize := TabSizeC;
+			end;
+			AutoIndentIncrease := AutoBlocks and (CT = ftCFile);
+		end;
+end;
+
+procedure THeaderSourceFile.UpdateEditor;
+begin
+	inherited;
+	if Assigned (SourceEditor) then begin
+		if ContentType = ftCFile then begin
+			SourceEditor.TabSize := TabSizeC;
+			SourceEditor.AutoIndentIncrease := AutoBlocks;
+		end else if ContentType = ftCFile then
+			SourceEditor.TabSize := TabSizeC
+		else
+			SourceEditor.TabSize := TabSizeAsm;
+	end;
+end;
+
+procedure THeaderSourceFile.UpdateSyntax;
+begin
+	UpdateContentType (ContentType);
+end;
+
+{ TSourceTextSourceFile }
+
+destructor TSourceTextSourceFile.Destroy;
+var
+	PrevEditor: TSourceEdit;
+begin
+	if Assigned (FEditor) then begin
+		PrevEditor := FEditor;
+		FEditor := nil;
+		PrevEditor.Free;
+	end;
+	inherited;
+end;
+
+function TSourceTextSourceFile.GetContentType: TSourceFileType;
+begin
+	Result := ftOther;
+end;
+
+function TSourceTextSourceFile.GetFunctions: TSourceFileFunctions;
+var
+	Editor: TSourceEdit;
+	TextLength,
+	I,
+	J,
+	CurPos,
+	WordIndex: Integer;
+	Text,
+	LastWord,
+	FirstWord: string;
+	InFunc,
+	InAsm,
+	InCompSM,
+	InSpace,
+	LineDone: Boolean;
+begin
+	SetLength (Result, 0);
+	Editor := SourceEditor;
+	if not Assigned (Editor) then
+		Exit;
+	Text := Content;
+	TextLength := Length (Text);
+	InFunc := False;
+	InAsm := False;
+	InCompSM := False;
+	case ContentType of
+		ftCFile:
+			for I := 1 to Editor.LineCount do begin
+				CurPos := Editor.CellToCharIdx (TextCell (I, 1));
+				if (CurPos <= TextLength) and (Text [CurPos] <> #13) and (Text [CurPos] <> '*') then begin
+					if InCompSM and (CurPos - 3 >= 1) and (Text [CurPos - 3] <> '\') then
+						InCompSM := False;
+					if not InCompSM then begin
+						if Text [CurPos] = '{' then
+							InFunc := True;
+						if InFunc then begin
+							if Text [CurPos] = '}' then
+								InFunc := False;
+						end else begin
+							if (Copy (Text, CurPos, 5) = 'asm("') or (Copy (Text, CurPos, 6) = 'asm ("') then
+								InAsm := True;
+							if InAsm then begin
+								if Pos ('")', Copy (Text, CurPos, Editor.CellToCharIdx (TextCell (I + 1, 1)) - CurPos)) > 0 then
+									InAsm := False;
+							end else begin
+								LineDone := False;
+								LastWord := '';
+								WordIndex := 0;
+								InSpace := True;
+								while (CurPos <= TextLength) and (not LineDone) do begin
+									case Text [CurPos] of
+										'A'..'Z', 'a'..'z', '0'..'9', '_', '$', ':': begin
+											if InSpace and (Text [CurPos] = '_') and (Copy (Text, CurPos, Length ('__attribute__')) = '__attribute__') then begin
+												Inc (CurPos, Length ('__attribute__'));
+												while (CurPos <= TextLength) and (Text [CurPos] in [#32, #9]) do
+													Inc (CurPos);
+												if (CurPos <= TextLength) and (Text [CurPos] = '(') then begin
+													Inc (CurPos);
+													J := 1;
+													while (CurPos <= TextLength) and (J > 0) do begin
+														case Text [CurPos] of
+															'(': Inc (J);
+															')': Dec (J);
+														end;
+														Inc (CurPos);
+													end;
+												end else
+													Dec (CurPos);
+											end else begin
+												if InSpace then begin
+													LastWord := '';
+													InSpace := False;
+													Inc (WordIndex);
+												end;
+												LastWord := LastWord + Text [CurPos];
+												if WordIndex <= 1 then
+													FirstWord := LastWord;
+											end;
+										end;
+										#32, #9, #0, '*', '&': begin
+											InSpace := True;
+											if (Pos (':', LastWord) > 0) and (Pos ('::', LastWord) <= 0) then
+												LineDone := True;
+										end;
+										'#': begin
+											InCompSM := True;
+											LineDone := True;
+										end;
+										else
+											LineDone := True;
+									end;
+									Inc (CurPos);
+								end;
+								if (WordIndex >= 2) and (WordIndex <= 4) and (CurPos - 1 <= TextLength) and (Text [CurPos - 1] = '(') and (((FirstWord <> 'struct') and (FirstWord <> 'union') and (FirstWord <> 'enum')) or (WordIndex > 2)) then begin
+									while (CurPos <= TextLength) and (Text [CurPos] <> ')') do
+										Inc (CurPos);
+									Inc (CurPos);
+									if (CurPos <= TextLength) and (Text [CurPos] <> '(') then begin
+										LineDone := (CurPos <= TextLength) and (Text [CurPos] = ';');
+										if not LineDone then begin
+											J := CurPos;
+											while (J <= TextLength) and (not (Text [J] in [';', '{', '=', #13, #10])) do
+												Inc (J);
+											if (J <= TextLength) and (Text [J] = ';') then
+												LineDone := True;
+										end;
+										if LineDone then
+											for J := Low (Result) to High (Result) do
+												if Result[J].Name = LastWord then begin
+													LineDone := False;
+													Break;
+												end;
+										if LineDone then begin
+											SetLength (Result, Length (Result) + 1);
+											with Result [High (Result)] do begin
+												Name := LastWord;
+												PrototypeLine := I;
+												ImplementationLine := 0;
+											end;
+										end else begin
+											for J := Low (Result) to High (Result) do
+												if Result[J].Name = LastWord then begin
+													Result[J].ImplementationLine := I;
+													InFunc := True;
+													LineDone := True;
+													Break;
+												end;
+											if not LineDone then begin
+												while (CurPos <= TextLength) and (not (Text [CurPos] in ['{', ';', '='])) do
+													Inc (CurPos);
+												if (CurPos <= TextLength) and (Text [CurPos] <> '=') then begin
+													SetLength (Result, Length (Result) + 1);
+													with Result [High (Result)] do begin
+														Name := LastWord;
+														PrototypeLine := 0;
+														ImplementationLine := I;
+														InFunc := True;
+													end;
+												end;
+											end;
+										end;
+									end;
+								end;
+							end;
+						end;
+					end;
+				end;
+			end;
+		ftGNUAsmFile, ftA68kAsmFile:
+			for I := 1 to Editor.LineCount do begin
+				CurPos := Editor.CellToCharIdx (TextCell (I, 1));
+				LineDone := False;
+				LastWord := '';
+				while (CurPos <= TextLength) and (not LineDone) do begin
+					if Text [CurPos] in ['A'..'Z', 'a'..'z', '0'..'9', '_', '$'] then
+						LastWord := LastWord + Text [CurPos]
+					else
+						LineDone := True;
+					Inc (CurPos);
+				end;
+				if (CurPos - 1 <= TextLength) and (Text [CurPos - 1] = ':') then begin
+					SetLength (Result, Length (Result) + 1);
+					with Result [High (Result)] do begin
+						Name := LastWord;
+						PrototypeLine := 0;
+						ImplementationLine := I;
+					end;
+				end;
+			end;
+	end;
+end;
+
+function TSourceTextSourceFile.GetInternalTextEditor: TMemoComponent;
+begin
+	Result := FEditor;
+end;
+
+function TSourceTextSourceFile.GetSourceEditor: TSourceEdit;
+begin
+	if not Assigned (FEditor) then begin
+		FEditor := TSourceEdit.Create (Application.MainForm);
+		with FEditor do begin
+			AllowUndo := False;
+			Text := FTempContent;
+		end;
+		UpdateEditor;
+		UpdateSyntax;
+		FTempContent := '';
+		with FEditor do begin
+			OnChangePrivate := Change;
+			OnReplaceText := ReplaceText;
+			AllowUndo := True;
+		end;
+	end;
+	Result := FEditor;
+end;
+
+function TSourceTextSourceFile.GetTextEditor: TMemoComponent;
+begin
+	Result := SourceEditor;
+end;
+
+procedure TSourceTextSourceFile.SplitAndWriteToFile(const FN: string);
+type
+	TCharMode = (cmNone, cmNormalText, cmNumber, cmMultiSymbol, cmString, cmChar, cmComment, cmUnchangableLine, cmExtUnchangableLine, cmTrigraph);
+var
+	S: string;
+{$IFDEF CanSplit}
+	C: Char;
+	CurPos: Integer;
+	CurMode: TCharMode;
+	AtLineStart: Boolean;
+	Stream: TStream;
+procedure InsertChar(Ch: Char);
+begin
+	Stream.Write (Ch, SizeOf (Char));
+end;
+procedure InsertString(const Str: string);
+begin
+	Stream.Write (PChar(Str)^, Length (Str));
+end;
+procedure AddLine(Offset: Integer = 0);
+begin
+	LineStartList.Add (CurPos + Offset);
+	AtLineStart := True;
+end;
+procedure NewLine;
+begin
+	if (not (AtLineStart or (Copy (S, CurPos, 1) = #13))) or (Copy (S, CurPos, 1) = '#') then begin
+		InsertString (#13#10);
+		AddLine;
+	end;
+	CurMode := cmNone;
+end;
+procedure SetMultiCharMode(Mode: TCharMode);
+begin
+	if CurMode <> Mode then begin
+		NewLine;
+		CurMode := Mode;
+	end;
+end;
+var
+	I: Integer;
+	B,
+	NoInsert: Boolean;
+{$ENDIF}
+begin
+	try
+{$IFDEF CanSplit}
+		if SplitFiles then begin
+			case ContentType of
+				ftCFile: begin
+					if not Assigned (LineStartList) then
+						LineStartList := TIntegerList.Create;
+					LineStartList.Clear;
+					LineStartList.Add (1);
+					CurPos := 1;
+					AddLine;
+					AtLineStart := True;
+					S := Content;
+					CreatePathFor (FN);
+					Stream := TFileStream.Create (FN, fmCreate or fmShareExclusive);
+					try
+						for CurPos := 1 to Length (S) do begin
+							NoInsert := False;
+							C := S [CurPos];
+							if C = #13 then
+								AddLine (2);
+							case CurMode of
+								cmString:
+									if (C = '"') then begin
+										B := True;
+										I := CurPos - 1;
+										while (I >= 1) and ((S [I] = '\') or (Copy (S, I - 2, 3) = '??/')) do begin
+											B := not B;
+											if S [I] = '\' then
+												Dec (I)
+											else
+												Dec (I, 3);
+										end;
+										if B then begin
+											CurMode := cmNone;
+											NoInsert := True;
+											InsertString (C + #13#10);
+											AtLineStart := True;
+											AddLine (1);
+										end;
+									end;
+								cmChar:
+									if (C = '''') then begin
+										B := True;
+										I := CurPos - 1;
+										while (I >= 1) and ((S [I] = '\') or (Copy (S, I - 2, 3) = '??/')) do begin
+											B := not B;
+											if S [I] = '\' then
+												Dec (I)
+											else
+												Dec (I, 3);
+										end;
+										if B then
+											CurMode := cmNone;
+									end;
+								cmComment: begin
+									if (C = '/') and (S [CurPos - 1] = '*') then
+										CurMode := cmNone;
+								end;
+								cmUnchangableLine:
+									if C = #13 then
+										CurMode := cmNone;
+								cmExtUnchangableLine:
+									if (C = #13) and (S [CurPos - 1] <> '\') then
+										CurMode := cmNone;
+								cmTrigraph:
+									if (C <> '?') and ((CurPos + 1 > Length (S)) or (S [CurPos + 1] <> '?')) then
+										CurMode := cmNone;
+								else begin
+									if Copy (S, CurPos, 2) = '//' then
+										SetMultiCharMode (cmUnchangableLine)
+									else if Copy (S, CurPos, 2) = '/*' then
+										SetMultiCharMode (cmComment)
+									else if Copy (S, CurPos, 2) = '??=' then
+										SetMultiCharMode (cmExtUnchangableLine)
+									else if (Copy (S, CurPos, 2) = '??') and (Length (S) >= CurPos + 2) and (S [CurPos + 2] in ['(', ')', '/', '''', '<', '>', '!', '-']) then
+										SetMultiCharMode (cmTrigraph)
+									else
+										case C of
+											#32, #9:
+												if (CurPos > 1) and (not (S [CurPos - 1] in [#32, #9])) then
+													NewLine;
+											'A'..'Z', 'a'..'z', '0'..'9', '_', '$':
+												if not (CurMode in [cmNormalText, cmNumber]) then begin
+													NewLine;
+													if C in ['0'..'9'] then
+														CurMode := cmNumber
+													else
+														CurMode := cmNormalText;
+												end;
+											'"':
+												SetMultiCharMode (cmString);
+											'''':
+												SetMultiCharMode (cmChar);
+											'#':
+												SetMultiCharMode (cmExtUnchangableLine);
+											'.':
+												if CurMode <> cmNumber then begin
+													if (Length (S) >= CurPos + 1) and (S [CurPos + 1] in ['0'..'9']) then begin
+														NewLine;
+														CurMode := cmNumber;
+													end else
+														SetMultiCharMode (cmMultiSymbol);
+												end;
+											'+', '-':
+												if (CurMode <> cmNumber) or (CurPos - 1 <= 1) or (not (S [CurPos - 1] in ['e', 'E', 'p', 'P'])) then
+													SetMultiCharMode (cmMultiSymbol);
+											else
+												if C in CSingleSymbols then begin
+													if CurMode <> cmNone then begin
+														NewLine;
+														CurMode := cmNone;
+													end;
+													if (CurPos + 1 <= Length (S)) and (S [CurPos + 1] <> #13) then begin
+														NoInsert := True;
+														InsertString (C + #13#10);
+														AddLine (1);
+													end;
+												end else
+													SetMultiCharMode (cmMultiSymbol);
+										end;
+								end;
+							end;
+							if not NoInsert then begin
+								InsertChar (C);
+								if not (C in [#13, #10]) then
+									AtLineStart := False;
+							end;
+						end;
+						NewLine;
+					finally
+						Stream.Free;
+					end;
+				end;
+				else
+					WriteToFile (FN);
+			end;
+		end else
+{$ENDIF}
+		begin
+			S := Content;
+			CreatePathFor (FN);
+			with TFileStream.Create (FN, fmCreate or fmShareExclusive) do try
+				Write (PChar(S)^, Length (S));
+				if ContentType = ftCFile then
+					Write (PChar(#13#10)^, 2);
+			finally
+				Free;
+			end;
+		end;
+	except
+		ShowDefaultMessageBox ('Error writing temporary source file.', 'Error', mtProgramError);
+	end;
+end;
+
+procedure TSourceTextSourceFile.UpdateEditor;
+begin
+	inherited;
+	if Assigned (SourceEditor) then
+		with SourceEditor do
+			SplitOnFly := EditorOnFly;
+end;
+
+{ TCSourceFile }
+
+procedure TCSourceFile.Compile;
+var
+	Folder,
+	Switches: string;
+begin
+	CompStartFile;
+	OperationCancelled := False;
+	OperationSuccessful := False;
+	if FileExists (WithBackslash (TIGCCFolder) + GCCLocation + 'GCC.exe') then begin
+		CompSetMessage ('Compiling File ''' + SourceName + '''');
+		Folder := WithBackslash (Temp + FolderPath);
+		CurErrFunction := '';
+		InAssemblingState := False;
+		if FileExists (Folder + 'TEMPPROG.S') then
+			DeleteFile (Folder + 'TEMPPROG.S');
+		if FileExists (Temp + 'TEMPPROG.O') then
+			DeleteFile (Temp + 'TEMPPROG.O');
+		SplitAndWriteToFile (Folder + 'TEMPPROG.C');
+		MainConsole.Title := 'Compiler';
+		Switches := DefaultGCCSwitches + ' ' + GCCSwitches + ' ' + SpecialSwitches;
+		if UseDataVar then
+			Switches := Switches + ' -mno-merge-sections';
+		if AssumeUndefined then
+			Switches := Switches + ' -Werror-implicit-function-declaration';
+		if DebugInfo then
+			Switches := Switches + ' -gcoff -mcoff-abslines';
+		if ProjectTarget = ptFargo then
+			Switches := Switches + ' -DFARGO'
+		else if ProjectTarget = ptFlashOS then
+			Switches := Switches + ' -DFLASH_OS'
+		else if Assigned (PredefinedLibOptions) and (ProjectTarget = ptRegular) then
+			Switches := Switches + ' ' + PredefinedLibOptions.GetSwitches;
+		CompUpdate;
+		try
+			MainConsole.StartProcess (WithBackslash (TIGCCFolder) + GCCLocation + 'GCC.exe', '-S -I ' + Folder + ' ' + Switches + ' "' + Folder + 'tempprog.c" -o "' + Folder + 'tempprog.s"', WithoutBackslash (WithBackslash (TIGCCFolder) + GCCLocation));
+			WaitForMainConsole ('Compilation');
+		except
+			ShowDefaultMessageBox ('Could not start compiler.', 'Error', mtProgramError);
+		end;
+		OperationSuccessful := True;
+		ProcessErrors (MainConsole.LastErrText);
+		if OperationSuccessful then begin
+			OperationSuccessful := False;
+			if not OperationCancelled then
+				if FileExists (Folder + 'TEMPPROG.S') then begin
+					OperationSuccessful := True;
+					ProcessSFile (Folder + 'TEMPPROG.S', ChangeFileExt (FileName, '.s'));
+				end;
+		end;
+		if OperationSuccessful then begin
+			OperationSuccessful := False;
+			CurErrFunction := '';
+			InAssemblingState := True;
+			CompUpdate;
+			Switches := DefaultAsSwitches + ' ' + AsSwitches;
+			if CutUnusedRanges or (ProjectTarget = ptArchive) then
+				Switches := Switches + ' --all-relocs';
+			if OptimizeReturns or (ProjectTarget = ptArchive) then
+				Switches := Switches + ' --keep-locals';
+			try
+				MainConsole.StartProcess (WithBackslash (TIGCCFolder) + AsLocation + 'As.exe', '-I ' + Folder + ' ' + Switches + ' "' + Folder + 'tempprog.s" -o ' + Temp + 'tempprog.o', WithoutBackslash (WithBackslash (TIGCCFolder) + AsLocation));
+				WaitForMainConsole ('Compilation');
+			except
+				ShowDefaultMessageBox ('Could not start assembler.', 'Error', mtProgramError);
+			end;
+			if FileExists (Temp + 'TEMPPROG.O') then begin
+				if not OperationCancelled then begin
+					CopyFile (PChar (Temp + 'TEMPPROG.O'), PChar (ChangeFileExt (FileName, '.o')), False);
+					OperationSuccessful := True;
+				end;
+				DeleteFile (Temp + 'TEMPPROG.O');
+			end;
+			ProcessErrors (MainConsole.LastErrText);
+		end;
+		SFileClear;
+		CompUpdate;
+		try
+			if FileExists (Folder + 'TEMPPROG.C') then
+				DeleteFile (Folder + 'TEMPPROG.C');
+			if FileExists (Folder + 'TEMPPROG.S') then
+				DeleteFile (Folder + 'TEMPPROG.S');
+			RemovePath (Folder, Temp);
+		except end;
+		CompUpdate;
+	end else
+		ShowDefaultMessageBox ('Cannot find compiler.', 'Error', mtProgramError);
+	if OperationSuccessful and not OperationCancelled then
+		Invalidated := False;
+end;
+
+destructor TCSourceFile.Destroy;
+begin
+	SFileClear;
+	inherited;
+end;
+
+class function TCSourceFile.GetClassFilter: string;
+begin
+	Result := 'C Files (*.c)|*.c';
+end;
+
+class function TCSourceFile.GetClassImageIndex: Integer;
+begin
+	Result := 4;
+end;
+
+class function TCSourceFile.GetClassItemName: string;
+begin
+	Result := 'C File';
+end;
+
+class function TCSourceFile.GetClassTreeIndex: Integer;
+begin
+	Result := 1;
+end;
+
+class function TCSourceFile.GetCompilable: Boolean;
+begin
+	Result := True;
+end;
+
+function TCSourceFile.GetContentType: TSourceFileType;
+begin
+	Result := ftCFile;
+end;
+
+procedure TCSourceFile.ProcessErrorLine(Line: string);
+var
+	Whole: string;
+	P,
+	Ofs: Integer;
+	S: string;
+	FN: string;
+	Tp: TBugType;
+	CurErrFile: string;
+begin
+	if not Assigned (OnError) then
+		Exit;
+	P := Pos (#10, Line);
+	if P > 0 then begin
+		ProcessErrorLine (Copy (Line, 1, P - 1));
+		ProcessErrorLine (Copy (Line, P + 1, Length (Line)));
+	end else begin
+		repeat
+			P := Pos ('`', Line);
+			if P > 0 then
+				Line [P] := '''';
+		until P <= 0;
+		repeat
+			P := Pos ('´', Line);
+			if P > 0 then
+				Line [P] := '''';
+		until P <= 0;
+		repeat
+			P := Pos ('"', Line);
+			if P > 0 then
+				Line [P] := '''';
+		until P <= 0;
+		Line := Trim (Line);
+		if (Pos ('ASSEMBLER MESSAGES:', UpperCase (Line)) > 0) or
+			StartsWith ('FROM ', Line) or
+			(AssumeUndefined and
+			((Pos ('PREVIOUS IMPLICIT DECLARATION', UpperCase (Line)) > 0) or
+			(Pos ('PREVIOUSLY IMPLICITLY DECLARED', UpperCase (Line)) > 0))) then
+			Exit;
+		Whole := Line;
+		FN := '';
+		CurErrFile := '';
+		if StartsWith ('IN FILE', Line) then
+			CurErrFunction := ''
+		else begin
+			P := Pos (':', Line);
+			while (P > 0) and (Length (Line) > P) and (Line [P + 1] in ['\', '/']) do begin
+				Ofs := Pos (':', Copy (Line, P + 1, Length (Line)));
+				if Ofs > 0 then
+					Inc (P, Ofs)
+				else begin
+					P := 0;
+					Break;
+				end;
+			end;
+			if P > 0 then
+				FN := Copy (Line, 1, P - 1);
+			if Length (FN) > 0 then begin
+				Delete (Line, 1, Length (FN) + 1);
+				repeat
+					P := Pos ('/', FN);
+					if P > 0 then
+						FN [P] := '\';
+				until P <= 0;
+				if InAssemblingState then begin
+					if Pos ('TEMPPROG', UpperCase (FN)) > 0 then
+						CurErrFile := ChangeFileExt (FileName, '.s')
+					else
+						CurErrFile := ExtractFileName (FN);
+				end else begin
+					if UpperCase (ExtractFileExt (FN)) = '.S' then begin
+						FN := '';
+						CurErrFunction := '';
+					end else begin
+						if Pos ('TEMPPROG', UpperCase (FN)) > 0 then
+							CurErrFile := FileName
+						else
+							CurErrFile := ExtractFileName (FN);
+					end;
+				end;
+				P := 0;
+				Ofs := 0;
+				if (Length (Line) > 0) and (Line [1] in ['0'..'9']) then begin
+					try
+						S := Copy (Line, 1, Pos (':', Line) - 1);
+						P := StrToInt (S);
+						if InAssemblingState then
+							SFileMapLine (P);
+						Delete (Line, 1, Length (S) + 1);
+						if (Length (Line) > 0) and (Line [1] in ['0'..'9']) then try
+							S := Copy (Line, 1, Pos (':', Line) - 1);
+							Ofs := StrToInt (S) - 1;
+							Delete (Line, 1, Length (S) + 1);
+						except end;
+					except end;
+					Line := Trim (Line);
+					if StartsWith ('WARNING:', Line, False, True) then
+						Tp := btWarning
+					else begin
+						StartsWith ('ERROR:', Line, False, True);
+						Tp := btError;
+						OperationSuccessful := False;
+					end;
+					Line := Trim (Line);
+					if StartsWith ('#WARNING ', Line, False, True) then
+						Tp := btWarning;
+					StartsWith ('#ERROR ', Line, False, True);
+					if StartsWith ('PREVIOUS DECLARATION OF ', Line) or
+						StartsWith ('POSSIBLE REAL START OF ', Line) or
+						StartsWith ('UNUSED VARIABLE ', Line) or
+						StartsWith ('UNUSED PARAMETER ', Line) or
+						(Pos ('PREVIOUSLY DECLARED HERE', UpperCase (Line)) > 0) or
+						(Pos ('LOCATION OF THE PREVIOUS DEFINITION', UpperCase (Line)) > 0) then
+						Tp := btInfo;
+					if AssumeUndefined and StartsWith ('Implicit declaration of ', Line, False, True) then begin
+						Insert ('Undefined reference to ', Line, 1);
+						Tp := btError;
+						OperationSuccessful := False;
+					end;
+					if (Length (CurErrFile) <= 0) and (P > 0) and (Length (FN) > 0) then
+						Line := UpperCase (ExtractFileName (FN)) + ' Line ' + IntToStr (P) + ' - ' + Line;
+					Line := Trim (Line);
+					if (Length (Line) > 0) and (Line [Length (Line)] <> '.') then
+						Line := Line + '.';
+					OnError (Whole, Tp, CurErrFile, CurErrFunction, Line, P, Ofs);
+					if Tp = btError then
+						OperationSuccessful := False;
+				end else begin
+					if StartsWith (' IN FUNCTION ''', Line, False, True) then
+						CurErrFunction := Copy (Line, 1, Pos ('''', Line) - 1)
+					else if StartsWith (' AT TOP LEVEL', Line) then
+						CurErrFunction := ''
+					else
+						OnError (Whole, btError, FileName, '', Line, 0, 0);
+				end;
+			end else begin
+				Tp := btError;
+				if StartsWith ('PLEASE FILL OUT ', Line) then
+					Tp := btInfo;
+				OnError (Whole, Tp, '', '', Whole, 0, 0);
+			end;
+		end;
+	end;
+end;
+
+procedure TCSourceFile.ProcessSFile(const SourceFile, DestFile: string);
+var
+	L: TStringList;
+begin
+	L := TStringList.Create;
+	with L do try
+		LoadFromFile (SourceFile);
+		if (Count > 0) and (Copy (LowerCase (Strings [0]), 1, Length (#9'.file')) = #9'.file') then
+			Strings [0] := #9'.file'#9'"' + ExtractFileName (FileName) + '"';
+		try
+			ParseSFile (L);
+		except
+			OperationSuccessful := False;
+		end;
+		SaveToFile (SourceFile);
+		if DebugInfo then
+			ParseDebugSFile (L, SFileLineChange, nil, GetLineContents);
+		SaveToFile (DestFile);
+	finally
+		Free;
+	end;
+end;
+
+procedure TCSourceFile.Save;
+var
+	FH: THandle;
+begin
+	inherited;
+	if (not Invalidated) and FileExists (ChangeFileExt (FileName, '.o')) then begin
+		FH := FileOpen (ChangeFileExt (FileName, '.o'), fmOpenReadWrite + fmShareExclusive);
+		FileSetDate (FH, FileAge (FileName));
+		FileClose (FH);
+	end;
+end;
+
+procedure TCSourceFile.SetModified(const Value: Boolean);
+begin
+	if not Modifying then begin
+		Modifying := True;
+		FModified := Value;
+		if Value then
+			Invalidate;
+		Modifying := False;
+	end;
+end;
+
+procedure TCSourceFile.SFileClear;
+begin
+	if Assigned (FSFileChangedLines) then
+		FSFileChangedLines.Free;
+	if Assigned (FSFileLineChanges) then
+		FSFileLineChanges.Free;
+	FSFileChangedLines := nil;
+	FSFileLineChanges := nil;
+end;
+
+procedure TCSourceFile.SFileLineChange(StartLine, Change: Integer);
+begin
+	if not Assigned (FSFileChangedLines) then
+		FSFileChangedLines := TIntegerList.Create;
+	if not Assigned (FSFileLineChanges) then
+		FSFileLineChanges := TIntegerList.Create;
+	FSFileChangedLines.Add (StartLine);
+	FSFileLineChanges.Add (Change);
+end;
+
+procedure TCSourceFile.SFileMapLine(var Line: Integer);
+var
+	I: Integer;
+begin
+	if Assigned (FSFileChangedLines) and Assigned (FSFileLineChanges) then
+		for I := 0 to FSFileChangedLines.Count - 1 do
+			if Line > FSFileChangedLines.Items [I] then
+				Inc (Line, FSFileLineChanges.Items [I]);
+end;
+
+procedure TCSourceFile.UpdateEditor;
+begin
+	inherited;
+	if Assigned (SourceEditor) then begin
+		SourceEditor.TabSize := TabSizeC;
+		SourceEditor.AutoIndentIncrease := AutoBlocks;
+	end;
+end;
+
+procedure TCSourceFile.UpdateSyntax;
+begin
+	if Assigned (SourceEditor) then
+		with SourceEditor do
+			SyntaxColoring.Assign (SyntaxC);
+end;
+
+{ TGNUAsmSourceFile }
+
+procedure TGNUAsmSourceFile.Compile;
+var
+	Folder,
+	Switches: string;
+begin
+	CompStartFile;
+	OperationCancelled := False;
+	OperationSuccessful := False;
+	if FileExists (WithBackslash (TIGCCFolder) + AsLocation + 'As.exe') then begin
+		CompSetMessage ('Assembling File ''' + SourceName + '''');
+		Folder := WithBackslash (Temp + FolderPath);
+		if FileExists (Temp + 'TEMPPROG.O') then
+			DeleteFile (Temp + 'TEMPPROG.O');
+		SplitAndWriteToFile (Folder + 'TEMPPROG.S');
+		Switches := DefaultAsSwitches + ' ' + AsSwitches;
+		if CutUnusedRanges or (ProjectTarget = ptArchive) then
+			Switches := Switches + ' --all-relocs';
+		if OptimizeReturns or (ProjectTarget = ptArchive) then
+			Switches := Switches + ' --keep-locals';
+		MainConsole.Title := 'Assembler';
+		try
+			MainConsole.StartProcess (WithBackslash (TIGCCFolder) + AsLocation + 'As.exe', '-I ' + Folder + ' ' + Switches + ' "' + Folder + 'tempprog.s" -o ' + Temp + 'tempprog.o', WithoutBackslash (WithBackslash (TIGCCFolder) + AsLocation));
+			WaitForMainConsole ('Assembling');
+		except
+			ShowDefaultMessageBox ('Could not start assembler.', 'Error', mtProgramError);
+		end;
+		if FileExists (Temp + 'TEMPPROG.O') then begin
+			if not OperationCancelled then begin
+				CopyFile (PChar (Temp + 'TEMPPROG.O'), PChar (ChangeFileExt (FileName, '.o')), False);
+				OperationSuccessful := True;
+			end;
+			DeleteFile (Temp + 'TEMPPROG.O');
+		end;
+		ProcessErrors (MainConsole.LastErrText);
+		try
+			if FileExists (Folder + 'TEMPPROG.S') then
+				DeleteFile (Folder + 'TEMPPROG.S');
+			RemovePath (Folder, Temp);
+		except end;
+		CompUpdate;
+	end else
+		ShowDefaultMessageBox ('Cannot find assembler.', 'Error', mtProgramError);
+	if OperationSuccessful and not OperationCancelled then
+		Invalidated := False;
+end;
+
+class function TGNUAsmSourceFile.GetClassFilter: string;
+begin
+	Result := 'GNU Assembly Files (*.s)|*.s';
+end;
+
+class function TGNUAsmSourceFile.GetClassImageIndex: Integer;
+begin
+	Result := 5;
+end;
+
+class function TGNUAsmSourceFile.GetClassItemName: string;
+begin
+	Result := 'GNU Assembler File';
+end;
+
+class function TGNUAsmSourceFile.GetClassTreeIndex: Integer;
+begin
+	Result := 2;
+end;
+
+class function TGNUAsmSourceFile.GetCompilable: Boolean;
+begin
+	Result := True;
+end;
+
+function TGNUAsmSourceFile.GetContentType: TSourceFileType;
+begin
+	Result := ftGNUAsmFile;
+end;
+
+procedure TGNUAsmSourceFile.ProcessErrorLine(Line: string);
+var
+	Whole: string;
+	P,
+	Ofs: Integer;
+	S: string;
+	FN: string;
+	Tp: TBugType;
+	CurErrFile: string;
+begin
+	P := Pos (#10, Line);
+	if P > 0 then begin
+		ProcessErrorLine (Copy (Line, 1, P - 1));
+		ProcessErrorLine (Copy (Line, P + 1, Length (Line)));
+	end else begin
+		repeat
+			P := Pos ('`', Line);
+			if P > 0 then
+				Line [P] := '''';
+		until P <= 0;
+		repeat
+			P := Pos ('´', Line);
+			if P > 0 then
+				Line [P] := '''';
+		until P <= 0;
+		repeat
+			P := Pos ('"', Line);
+			if P > 0 then
+				Line [P] := '''';
+		until P <= 0;
+		if (Pos ('ASSEMBLER MESSAGES:', UpperCase (Line)) > 0) or
+			(Pos ('IN FILE', UpperCase (Line)) > 0) then
+			Exit;
+		Whole := Line;
+		FN := '';
+		CurErrFile := '';
+		P := Pos (':', Line);
+		while (Length (Line) > P) and (Line [P + 1] in ['\', '/']) do
+			Inc (P, Pos (':', Copy (Line, P + 1, Length (Line))));
+		FN := Copy (Line, 1, P - 1);
+		if Length (FN) > 0 then begin
+			Delete (Line, 1, Length (FN) + 1);
+			repeat
+				P := Pos ('/', FN);
+				if P > 0 then
+					FN [P] := '\';
+			until P <= 0;
+			if (UpperCase (ExtractFileExt (FN)) = '.C') or (Pos ('TEMPPROG', UpperCase (FN)) > 0) then
+				CurErrFile := FileName
+			else
+				CurErrFile := ExtractFileName (FN);
+			P := 0;
+			Ofs := 0;
+			if (Length (Line) > 0) and (Line [1] in ['0'..'9']) then begin
+				try
+					S := Copy (Line, 1, Pos (':', Line) - 1);
+					P := StrToInt (S);
+					Delete (Line, 1, Length (S) + 1);
+					if (Length (Line) > 0) and (Line [1] in ['0'..'9']) then try
+						S := Copy (Line, 1, Pos (':', Line) - 1);
+						Ofs := StrToInt (S) - 1;
+						Delete (Line, 1, Length (S) + 1);
+					except end;
+				except end;
+				Line := Trim (Line);
+				if StartsWith ('WARNING:', Line, False, True) then
+					Tp := btWarning
+				else begin
+					StartsWith ('ERROR:', Line, False, True);
+					Tp := btError;
+					OperationSuccessful := False;
+				end;
+				Line := Trim (Line);
+				if (Length (CurErrFile) <= 0) and (P > 0) and (Length (FN) > 0) then
+					Line := UpperCase (ExtractFileName (FN)) + ' Line ' + IntToStr (P) + ' - ' + Line;
+				if Assigned (OnError) then
+					OnError (Whole, Tp, CurErrFile, '', Line, P, Ofs);
+			end else begin
+				if Assigned (OnError) then
+					OnError (Whole, btError, FileName, '', Line, 0, 0);
+			end;
+		end else
+			if Assigned (OnError) then
+				OnError (Whole, btError, '', '', Whole, 0, 0);
+	end;
+end;
+
+procedure TGNUAsmSourceFile.Save;
+var
+	FH: THandle;
+begin
+	inherited;
+	if (not Invalidated) and FileExists (ChangeFileExt (FileName, '.o')) then begin
+		FH := FileOpen (ChangeFileExt (FileName, '.o'), fmOpenReadWrite + fmShareExclusive);
+		FileSetDate (FH, FileAge (FileName));
+		FileClose (FH);
+	end;
+end;
+
+procedure TGNUAsmSourceFile.SetModified(const Value: Boolean);
+begin
+	if not Modifying then begin
+		Modifying := True;
+		FModified := Value;
+		if Value then
+			Invalidate;
+		Modifying := False;
+	end;
+end;
+
+procedure TGNUAsmSourceFile.UpdateEditor;
+begin
+	inherited;
+	if Assigned (SourceEditor) then begin
+		SourceEditor.TabSize := TabSizeAsm;
+		SourceEditor.AutoIndentIncrease := False;
+	end;
+end;
+
+procedure TGNUAsmSourceFile.UpdateSyntax;
+begin
+	if Assigned (SourceEditor) then
+		with SourceEditor do begin
+			SyntaxColoring.Assign (SyntaxAsmGNU);
+			TabSize := TabSizeAsm;
+			AutoIndentIncrease := False;
+		end;
+end;
+
+{ TAsmSourceFile }
+
+procedure TAsmSourceFile.Compile;
+var
+	Folder,
+	Switches: string;
+	FPos: Integer;
+	CurErrFile,
+	S: string;
+	CurErrLine,
+	P: Integer;
+	EmptyLn: Boolean;
+	LL: TStringList;
+begin
+	CompStartFile;
+	OperationCancelled := False;
+	OperationSuccessful := False;
+	if FileExists (WithBackslash (TIGCCFolder) + A68kLocation + 'A68k.exe') then begin
+		CompSetMessage ('Assembling File ''' + SourceName + '''');
+		Folder := WithBackslash (Temp + FolderPath);
+		if FileExists (WithBackslash (TIGCCFolder) + GCCLocation + 'TEMPPROG.O') then
+			DeleteFile (WithBackslash (TIGCCFolder) + GCCLocation + 'TEMPPROG.O');
+		if FileExists (Temp + 'TEMPPROG.O') then
+			DeleteFile (Temp + 'TEMPPROG.O');
+		SplitAndWriteToFile (Folder + 'TEMPPROG.ASM');
+		Switches := DefaultA68kSwitches + ' ' + AsmSwitches;
+		if CutUnusedRanges or (ProjectTarget = ptArchive) then
+			Switches := Switches + ' -a';
+		if OptimizeReturns or (ProjectTarget = ptArchive) then
+			Switches := Switches + ' -d';
+		MainConsole.Title := 'Assembler';
+		try
+			MainConsole.StartProcess (WithBackslash (TIGCCFolder) + A68kLocation + 'A68k.exe', '"' + Folder + 'tempprog.asm" ' + Switches, WithoutBackslash (Temp));
+			WaitForMainConsole ('Assembling');
+		except
+			ShowDefaultMessageBox ('Could not start assembler.', 'Error', mtProgramError);
+		end;
+		UpdateProgramOutput;
+		if not OperationCancelled then begin
+			if Assigned (ErrorList) then
+				ErrorList.Items.BeginUpdate;
+			try
+				LL := TStringList.Create;
+				try
+					LL.Text := MainConsole.LastOutText;
+					EmptyLn := False;
+					FPos := 0;
+					while FPos < LL.Count do begin
+						S := LL [FPos];
+						Inc (FPos);
+						CurErrLine := 0;
+						if (Length (S) <= 0) or (Pos ('ASSEMBLING', UpperCase (S)) > 0) then
+							EmptyLn := True
+						else begin
+							if EmptyLn then begin
+								EmptyLn := False;
+								while (FPos < LL.Count) and (Pos ('TEMPPROG.ASM LINE ', UpperCase (S)) <= 0) do begin
+									if (Length (S) > 0) and (Pos ('(USER MACRO)', UpperCase (S)) <= 0) then begin
+										if Length (CurErrFile) <= 0 then begin
+											while Pos ('/', S) > 0 do
+												S [Pos ('/', S)] := '\';
+											P := Pos ('LINE ', UpperCase (S));
+											if P > 0 then begin
+												CurErrFile := ExtractFileName (Copy (S, 1, P - 2));
+												try
+													CurErrLine := StrToInt (Copy (S, P + Length ('LINE '), Length (S)));
+												except
+													CurErrLine := 0;
+												end;
+											end;
+										end;
+									end;
+									S := LL [FPos];
+									Inc (FPos);
+								end;
+								if FPos < LL.Count then begin
+									if Length (CurErrFile) <= 0 then begin
+										Delete (S, 1, Pos ('TEMPPROG.ASM LINE ', UpperCase (S)) + Length ('TEMPPROG.ASM LINE ') - 1);
+										try
+											CurErrLine := StrToInt (S);
+										except
+											CurErrLine := 0;
+										end;
+									end;
+									Inc (FPos);
+									if FPos < LL.Count then begin
+										S := LL [FPos];
+										Inc (FPos);
+										S := Copy (S, FirstNonWhiteSpace (S), Length (S));
+										StartsWith ('^ ', S, True, True);
+										if S [Length (S)] = '.' then
+											Delete (S, Length (S), 1);
+										OperationSuccessful := False;
+										if Length (CurErrFile) <= 0 then
+											CurErrFile := FileName;
+										if Assigned (OnError) then
+											OnError (IntToStr (CurErrLine) + ': ' + S, btError, CurErrFile, '', S, CurErrLine, 0);
+										CurErrFile := '';
+									end;
+								end;
+							end;
+						end;
+					end;
+				except end;
+				LL.Free;
+			finally
+				if Assigned (ErrorList) then
+					ErrorList.Items.EndUpdate;
+			end;
+		end;
+		CompUpdate;
+		if FileExists (Temp + 'TEMPPROG.O') then begin
+			if not OperationCancelled then begin
+				CopyFile (PChar (Temp + 'TEMPPROG.O'), PChar (ChangeFileExt (FileName, '.o')), False);
+				OperationSuccessful := True;
+			end;
+			DeleteFile (Temp + 'TEMPPROG.O');
+		end;
+		try
+			if FileExists (Folder + 'TEMPPROG.ASM') then
+				DeleteFile (Folder + 'TEMPPROG.ASM');
+			RemovePath (Folder, Temp);
+		except end;
+		CompUpdate;
+	end else
+		ShowDefaultMessageBox ('Cannot find assembler.', 'Error', mtProgramError);
+	if OperationSuccessful and not OperationCancelled then
+		Invalidated := False;
+end;
+
+class function TAsmSourceFile.GetClassFilter: string;
+begin
+	Result := 'A68k Assembly Files (*.asm)|*.asm';
+end;
+
+class function TAsmSourceFile.GetClassImageIndex: Integer;
+begin
+	Result := 5;
+end;
+
+class function TAsmSourceFile.GetClassItemName: string;
+begin
+	Result := 'Assembler File';
+end;
+
+class function TAsmSourceFile.GetClassTreeIndex: Integer;
+begin
+	Result := 3;
+end;
+
+class function TAsmSourceFile.GetCompilable: Boolean;
+begin
+	Result := True;
+end;
+
+function TAsmSourceFile.GetContentType: TSourceFileType;
+begin
+	Result := ftA68kAsmFile;
+end;
+
+procedure TAsmSourceFile.Save;
+var
+	FH: THandle;
+begin
+	inherited;
+	if (not Invalidated) and FileExists (ChangeFileExt (FileName, '.o')) then begin
+		FH := FileOpen (ChangeFileExt (FileName, '.o'), fmOpenReadWrite + fmShareExclusive);
+		FileSetDate (FH, FileAge (FileName));
+		FileClose (FH);
+	end;
+end;
+
+procedure TAsmSourceFile.SetModified(const Value: Boolean);
+begin
+	if not Modifying then begin
+		Modifying := True;
+		FModified := Value;
+		if Value then
+			Invalidate;
+		Modifying := False;
+	end;
+end;
+
+procedure TAsmSourceFile.UpdateEditor;
+begin
+	inherited;
+	if Assigned (SourceEditor) then begin
+		SourceEditor.TabSize := TabSizeAsm;
+		SourceEditor.AutoIndentIncrease := False;
+	end;
+end;
+
+procedure TAsmSourceFile.UpdateSyntax;
+begin
+	if Assigned (SourceEditor) then
+		with SourceEditor do begin
+			SyntaxColoring.Assign (SyntaxAsm);
+			TabSize := TabSizeAsm;
+			AutoIndentIncrease := False;
+		end;
+end;
+
+{ TQuillSourceFile }
+
+procedure TQuillSourceFile.Compile;
+var
+	QuillDrv: string;
+begin
+	QuillDrv := WithBackslash (TIGCCFolder) + QuillIncludeLocation + 'Quill.drv';
+	if not FileExists (QuillDrv) then begin
+		QuillDrv := WithBackslash (TIGCCFolder) + CIncludeLocation + 'Quill.drv';
+		if not FileExists (QuillDrv) then begin
+			QuillDrv := WithBackslash (TIGCCFolder) + GCCLocation + 'Quill.drv';
+			if not FileExists (QuillDrv) then
+				QuillDrv := 'Quill.drv';
+		end;
+	end;
+	SpecialSwitches := SpecialQuillGCCSwitches + ' -include "' + QuillDrv + '"';
+	inherited;
+end;
+
+class function TQuillSourceFile.GetClassFilter: string;
+begin
+	Result := 'Quill Files (*.qll)|*.qll';
+end;
+
+class function TQuillSourceFile.GetClassImageIndex: Integer;
+begin
+	Result := 4;
+end;
+
+class function TQuillSourceFile.GetClassItemName: string;
+begin
+	Result := 'Quill File';
+end;
+
+class function TQuillSourceFile.GetClassTreeIndex: Integer;
+begin
+	Result := 3;
+	if ssA68k in SpecialSupport then
+		Inc (Result);
+end;
+
+function TQuillSourceFile.GetContentType: TSourceFileType;
+begin
+	Result := ftQuillFile;
+end;
+
+procedure TQuillSourceFile.UpdateSyntax;
+begin
+	if Assigned (SourceEditor) then
+		with SourceEditor do
+			SyntaxColoring.Assign (SyntaxQuill);
+end;
+
+{ TObjectSourceFile }
+
+class function TObjectSourceFile.GetClassFilter: string;
+begin
+	Result := 'Object Files (*.o)|*.o';
+end;
+
+class function TObjectSourceFile.GetClassImageIndex: Integer;
+begin
+	Result := 6;
+end;
+
+class function TObjectSourceFile.GetClassItemName: string;
+begin
+	Result := 'Object File';
+end;
+
+class function TObjectSourceFile.GetClassTreeIndex: Integer;
+begin
+	Result := 3;
+	if ssA68k in SpecialSupport then
+		Inc (Result);
+	if ssQuill in SpecialSupport then
+		Inc (Result);
+end;
+
+{ TArchiveSourceFile }
+
+class function TArchiveSourceFile.GetClassFilter: string;
+begin
+	Result := 'Archive Files (*.a)|*.a';
+end;
+
+class function TArchiveSourceFile.GetClassImageIndex: Integer;
+begin
+	Result := 6;
+end;
+
+class function TArchiveSourceFile.GetClassItemName: string;
+begin
+	Result := 'Archive File';
+end;
+
+class function TArchiveSourceFile.GetClassTreeIndex: Integer;
+begin
+	Result := 4;
+	if ssA68k in SpecialSupport then
+		Inc (Result);
+	if ssQuill in SpecialSupport then
+		Inc (Result);
+end;
+
+{ TNormalTextSourceFile }
+
+destructor TNormalTextSourceFile.Destroy;
+var
+	PrevEditor: TMemoComponent;
+begin
+	if Assigned (FEditor) then begin
+		PrevEditor := FEditor;
+		FEditor := nil;
+		PrevEditor.Free;
+	end;
+	inherited;
+end;
+
+class function TNormalTextSourceFile.GetClassFilter: string;
+begin
+	Result := 'Text Files (*.txt)|*.txt';
+end;
+
+class function TNormalTextSourceFile.GetClassImageIndex: Integer;
+begin
+	Result := 7;
+end;
+
+class function TNormalTextSourceFile.GetClassItemName: string;
+begin
+	Result := 'Text File';
+end;
+
+class function TNormalTextSourceFile.GetClassTreeIndex: Integer;
+begin
+	Result := 5;
+	if ssA68k in SpecialSupport then
+		Inc (Result);
+	if ssQuill in SpecialSupport then
+		Inc (Result);
+end;
+
+function TNormalTextSourceFile.GetInternalTextEditor: TMemoComponent;
+begin
+	Result := FEditor;
+end;
+
+function TNormalTextSourceFile.GetTextEditor: TMemoComponent;
+begin
+	if not Assigned (FEditor) then begin
+		FEditor := TMemoComponent.Create (Application.MainForm);
+		with FEditor do begin
+			AllowUndo := False;
+			TabSize := 8;
+			Text := FTempContent;
+		end;
+		UpdateEditor;
+		FTempContent := '';
+		with FEditor do begin
+			OnChangePrivate := Change;
+			OnReplaceText := ReplaceText;
+			AllowUndo := True;
+		end;
+	end;
+	Result := FEditor;
+end;
+
+{ TOtherSourceFile }
+
+class function TOtherSourceFile.GetClassFilter: string;
+begin
+	Result := '';
+end;
+
+class function TOtherSourceFile.GetClassImageIndex: Integer;
+begin
+	Result := 8;
+end;
+
+class function TOtherSourceFile.GetClassItemName: string;
+begin
+	Result := 'Other File';
+end;
+
+class function TOtherSourceFile.GetClassTreeIndex: Integer;
+begin
+	Result := 6;
+	if ssA68k in SpecialSupport then
+		Inc (Result);
+	if ssQuill in SpecialSupport then
+		Inc (Result);
+end;
+
+end.

BIN
SourceFileWinUnit.dfm


+ 789 - 0
SourceFileWinUnit.pas

@@ -0,0 +1,789 @@
+unit SourceFileWinUnit;
+
+interface
+
+uses
+	SourceFileUnit,
+	Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+  ComCtrls, Menus, ActnList, ToolWin, MemoComponentUnit, ExtCtrls{$IFDEF CODINGEXT}, CompletionForm{$ENDIF};
+
+type
+	TSourceFileForm = class(TForm)
+    Actions: TActionList;
+    ActionFilePrint: TAction;
+    ActionFilePrintQuickly: TAction;
+		ActionFileClose: TAction;
+		ActionEditUndo: TAction;
+    ActionEditRedo: TAction;
+    ActionEditDelete: TAction;
+    ActionEditCut: TAction;
+    ActionEditCopy: TAction;
+    ActionEditPaste: TAction;
+    ActionEditSelectAll: TAction;
+    ActionFindFind: TAction;
+    ActionFindReplace: TAction;
+    ActionFindOpenFile: TAction;
+    ActionFindFunctions: TAction;
+    ActionEditIncreaseIndent: TAction;
+    ActionEditDecreaseIndent: TAction;
+		MainMenu: TMainMenu;
+    File1: TMenuItem;
+		Print1: TMenuItem;
+    Edit1: TMenuItem;
+    Undo1: TMenuItem;
+    Redo1: TMenuItem;
+    N2: TMenuItem;
+    Delete1: TMenuItem;
+    Cut1: TMenuItem;
+    Copy1: TMenuItem;
+    Paste1: TMenuItem;
+    N9: TMenuItem;
+    SelectAll1: TMenuItem;
+    N18: TMenuItem;
+		IncreaseIndent1: TMenuItem;
+    DecreaseIndent1: TMenuItem;
+    Find1: TMenuItem;
+		Find2: TMenuItem;
+    Replace1: TMenuItem;
+    N13: TMenuItem;
+    Functions1: TMenuItem;
+    N15: TMenuItem;
+    OpenFileAtCursor1: TMenuItem;
+    ActionFileSave: TAction;
+    ActionFileSaveAs: TAction;
+    ActionFileCompile: TAction;
+    Save1: TMenuItem;
+    SaveAs1: TMenuItem;
+		N1: TMenuItem;
+		Compile1: TMenuItem;
+		N3: TMenuItem;
+		N4: TMenuItem;
+		Close1: TMenuItem;
+		StatusBar: TStatusBar;
+    EditorToolBar: TToolBar;
+    ToolButton3: TToolButton;
+    ToolButton4: TToolButton;
+    ToolButton23: TToolButton;
+    ToolButton24: TToolButton;
+    ToolButton6: TToolButton;
+    ToolButton7: TToolButton;
+    ToolButton8: TToolButton;
+		ToolButton9: TToolButton;
+    ToolButton10: TToolButton;
+    ToolButton5: TToolButton;
+    ToolButton19: TToolButton;
+    ToolButton11: TToolButton;
+		ToolButton20: TToolButton;
+    ToolButton21: TToolButton;
+    ToolButton25: TToolButton;
+    ToolButton22: TToolButton;
+    ToolButton13: TToolButton;
+    ToolBarBevel: TBevel;
+    ToolButton1: TToolButton;
+    EditorPopup: TPopupMenu;
+    Undo2: TMenuItem;
+		Redo2: TMenuItem;
+    N16: TMenuItem;
+    Clear1: TMenuItem;
+    Cut2: TMenuItem;
+    Copy2: TMenuItem;
+    Paste2: TMenuItem;
+		N17: TMenuItem;
+    SelectAll2: TMenuItem;
+    N20: TMenuItem;
+    IncreaseIndent2: TMenuItem;
+    DecreaseIndent2: TMenuItem;
+		N5: TMenuItem;
+		OpenFileatCursor2: TMenuItem;
+		FindDlg: TFindDialog;
+		ReplaceDlg: TReplaceDialog;
+		FunctionPopup: TPopupMenu;
+		NoFunctionsItem: TMenuItem;
+		ActionFileAddToProject: TAction;
+		AddtoProject1: TMenuItem;
+		N6: TMenuItem;
+		ToolButton2: TToolButton;
+		procedure FormClose(Sender: TObject; var Action: TCloseAction);
+		procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+		procedure FormCreate(Sender: TObject);
+		procedure ActionFileCloseExecute(Sender: TObject);
+		procedure FileSave(Sender: TObject);
+		procedure FileSaveAs(Sender: TObject);
+		procedure FileCompile(Sender: TObject);
+		procedure FilePrint(Sender: TObject);
+		procedure FilePrintQuickly(Sender: TObject);
+		procedure EditorChange(Sender: TObject);
+		procedure EditUndo(Sender: TObject);
+		procedure EditRedo(Sender: TObject);
+		procedure EditDelete(Sender: TObject);
+		procedure EditCut(Sender: TObject);
+		procedure EditCopy(Sender: TObject);
+		procedure EditPaste(Sender: TObject);
+		procedure EditSelectAll(Sender: TObject);
+		procedure EditIncreaseIndent(Sender: TObject);
+		procedure EditDecreaseIndent(Sender: TObject);
+		procedure FindDlgFind(Sender: TObject);
+		procedure ReplaceDlgReplace(Sender: TObject);
+		procedure FindString(Sender: TObject);
+		procedure FindFind(Sender: TObject);
+		procedure FindReplace(Sender: TObject);
+		procedure FindOpenFile(Sender: TObject);
+		procedure FunctionPopupPopup(Sender: TObject);
+		procedure FindFunctions(Sender: TObject);
+		procedure FindFunctionFromPopup(Sender: TObject);
+		procedure FileAddToProject(Sender: TObject);
+		procedure FormEnable(Sender: TObject);
+		procedure FormShow(Sender: TObject);
+    procedure FindDlgClose(Sender: TObject);
+	private
+		FSourceFile: TSourceFile;
+		procedure SetSourceFile(const Value: TSourceFile);
+		function GetEditor: TMemoComponent;
+	protected
+		procedure CreateParams(var Params: TCreateParams); override;
+	public
+		OriginalCaption: string;
+		EnableTimer: TTimer;
+		Funcs: TSourceFileFunctions;
+		procedure UpdateCaption;
+		procedure UpdateEditButtons;
+		procedure UpdateStatusBar;
+		procedure UpdateFuncs;
+		property SourceFile: TSourceFile read FSourceFile write SetSourceFile;
+		property Editor: TMemoComponent read GetEditor;
+{$IFDEF CODINGEXT}
+		procedure InitCodingExt;
+		procedure ActionFindSymbolExecute(Sender: TObject);
+{$ENDIF}
+	end;
+
+implementation
+
+{$R *.DFM}
+
+uses
+	Printers,
+	UtilsDos, UtilsWin,
+	MasterUnit,
+	MainUnit, FunctionsWinUnit;
+
+procedure TSourceFileForm.SetSourceFile(const Value: TSourceFile);
+begin
+	FSourceFile := Value;
+	UpdateCaption;
+	if Assigned (SourceFile) and (SourceFile is TTextSourceFile) then
+		with SourceFile as TTextSourceFile do
+			if Assigned (TextEditor) then
+				with TextEditor do begin
+					OnKeyDown := MainForm.EditorKeyDown;
+					OnChange := EditorChange;
+					OnSelectionChange := EditorChange;
+					PopupMenu := EditorPopup;
+				end;
+	ActionFileCompile.Enabled := Assigned (SourceFile) and SourceFile.Compilable;
+	ActionFilePrint.Enabled := Assigned (SourceFile) and SourceFile.Printable and (Printer.Printers.Count > 0);
+	ActionFilePrintQuickly.Enabled := ActionFilePrint.Enabled;
+	ActionFindFunctions.Enabled := Assigned (SourceFile) and (SourceFile is TSourceTextSourceFile);
+	EditorChange (Editor);
+end;
+
+procedure TSourceFileForm.UpdateCaption;
+begin
+	if Assigned (SourceFile) then begin
+		Caption := OriginalCaption + ' - ' + SourceFile.SourceName;
+		if (MainForm.ProjectFile = '') and (ExtractFilePath (SourceFile.FileName) = 'C:\') then
+			StatusBar.Panels.Items[5].Text := ExtractFileName (SourceFile.FileName)
+		else
+			StatusBar.Panels.Items[5].Text := SourceFile.FileName;
+	end else
+		Caption := OriginalCaption;
+end;
+
+function TSourceFileForm.GetEditor: TMemoComponent;
+begin
+	if Assigned (SourceFile) and (SourceFile is TTextSourceFile) then
+		Result := (SourceFile as TTextSourceFile).TextEditor
+	else
+		Result := nil;
+end;
+
+procedure TSourceFileForm.FormClose(Sender: TObject;
+	var Action: TCloseAction);
+begin
+	if Assigned (SourceFile) and (SourceFile.ParentForm = Self) then begin
+		SourceFile.ParentForm := nil;
+		SourceFile.Free;
+	end;
+	Action := caFree;
+end;
+
+procedure TSourceFileForm.FormCloseQuery(Sender: TObject;
+	var CanClose: Boolean);
+begin
+	if Compiling then
+		CanClose := False
+	else if Assigned (SourceFile) and (SourceFile.ParentForm = Self) then
+		SourceFile.WarnIfModified;
+end;
+
+procedure TSourceFileForm.FormCreate(Sender: TObject);
+begin
+	OriginalCaption := Caption;
+{$IFDEF CODINGEXT}
+  InitCodingExt;
+{$ENDIF}
+end;
+
+procedure TSourceFileForm.ActionFileCloseExecute(Sender: TObject);
+begin
+	if not Compiling then
+		Close;
+end;
+
+procedure TSourceFileForm.FileSave(Sender: TObject);
+begin
+	if Assigned (SourceFile) then begin
+		SourceFile.Save;
+		UpdateCaption;
+	end;
+end;
+
+procedure TSourceFileForm.FileSaveAs(Sender: TObject);
+begin
+	if Assigned (SourceFile) then begin
+		SourceFile.SaveAs;
+		UpdateCaption;
+		UpdateStatusBar;
+	end;
+end;
+
+procedure TSourceFileForm.FileCompile(Sender: TObject);
+begin
+	if (not Compiling) and Assigned (SourceFile) then
+		with MainForm do begin
+			BeginCompilation;
+			CopyHeaders;
+			Self.SourceFile.Compile;
+			DeleteHeaders;
+			EndCompilation;
+		end;
+end;
+
+procedure TSourceFileForm.FilePrint(Sender: TObject);
+var
+	Cp: Integer;
+begin
+	if Assigned (SourceFile) and (Printer.Printers.Count > 0) then
+		with MainForm do try
+			PrintDlg.PrintRange := prAllPages;
+			PrintDlg.MaxPage := TSourceFile(ProjectTree.Selected.Data).CountPages;
+			PrintDlg.ToPage := PrintDlg.MaxPage;
+			if Assigned (CurrentEditor) then begin
+				if CurrentEditor.Selection.RLength > 0 then
+					PrintDlg.Options := PrintDlg.Options + [poSelection]
+				else
+					PrintDlg.Options := PrintDlg.Options - [poSelection];
+			end;
+			if Assigned (Sender) then begin
+				if not PrintDlg.Execute then
+					Abort;
+				Cp := PrintDlg.Copies;
+				if Cp < 1 then
+					Cp := 1;
+			end else
+				Cp := 1;
+			SourceFile.Print (Cp, PrintDlg.PrintRange, PrintDlg.FromPage, PrintDlg.ToPage);
+		except
+			Abort;
+		end;
+end;
+
+procedure TSourceFileForm.FilePrintQuickly(Sender: TObject);
+begin
+	FilePrint (nil);
+end;
+
+procedure TSourceFileForm.EditorChange(Sender: TObject);
+begin
+	UpdateEditButtons;
+	UpdateStatusBar;
+end;
+
+procedure TSourceFileForm.UpdateEditButtons;
+var
+	TextSel: Boolean;
+begin
+	if Assigned (Editor) then begin
+		TextSel := Editor.SelLength > 0;
+		ActionEditDelete.Enabled := TextSel;
+		ActionEditCut.Enabled := TextSel;
+		ActionEditCopy.Enabled := TextSel;
+		ActionEditUndo.Enabled := Editor.CanUndo;
+		ActionEditRedo.Enabled := Editor.CanRedo;
+	end;
+end;
+
+procedure TSourceFileForm.UpdateStatusBar;
+var
+	S: string;
+	I: Integer;
+	Cell: TTextCell;
+begin
+	with StatusBar.Panels do begin
+		if Assigned (Editor) then begin
+			with Editor do begin
+				if Enabled then begin
+					if Selection.RLength > 0 then begin
+						I := Selection.RLength + Selection.StartRowCol.Row - Selection.EndRowCol.Row;
+						if Selection.EndRowCol.Col > LineLength [Selection.EndRowCol.Row] then
+							Dec (I);
+						S := IntToStr (I);
+						if Items[0].Text <> S then
+							Items[0].Text := S;
+						if Items[1].Text <> '' then
+							Items[1].Text := '';
+						if Items[0].Width <> 60 then
+							Items[0].Width := 60;
+						if Items[1].Width <> 0 then
+							Items[1].Width := 0;
+					end else begin
+						Cell := Selection.StartRowCol;
+						S := IntToStr (Cell.Row);
+						if Items[0].Text <> S then
+							Items[0].Text := S;
+						S := IntToStr (Cell.Col);
+						if Items[1].Text <> S then
+							Items[1].Text := S;
+						if Items[0].Width <> 30 then
+							Items[0].Width := 30;
+						if Items[1].Width <> 30 then
+							Items[1].Width := 30;
+					end;
+					I := TextLength - LineCount + 1;
+					S := IntToStr (I) + ' Character';
+					if I <> 1 then
+						S := S + 's';
+					if Items[3].Text <> S then
+						Items[3].Text := S;
+					if Items[2].Width <> 1 then
+						Items[2].Width := 1;
+					if Items[3].Width <> 93 then
+						Items[3].Width := 93;
+					if Items[2].Width <> 1 then
+						Items[2].Width := 1;
+				end;
+			end;
+		end else begin
+			if Items[0].Text <> '' then
+				Items[0].Text := '';
+			if Items[1].Text <> '' then
+				Items[1].Text := '';
+			if Items[3].Text <> '' then
+				Items[3].Text := '';
+			if Items[0].Width <> 0 then
+				Items[0].Width := 0;
+			if Items[1].Width <> 0 then
+				Items[1].Width := 0;
+			if Items[2].Width <> 0 then
+				Items[2].Width := 0;
+			if Items[3].Width <> 0 then
+				Items[3].Width := 0;
+			if Items[4].Width <> 0 then
+				Items[4].Width := 0;
+		end;
+	end;
+	Update;
+end;
+
+procedure TSourceFileForm.EditUndo(Sender: TObject);
+begin
+	if Assigned (Editor) then
+		Editor.Undo;
+end;
+
+procedure TSourceFileForm.EditRedo(Sender: TObject);
+begin
+	if Assigned (Editor) then
+		Editor.Redo;
+end;
+
+procedure TSourceFileForm.EditDelete(Sender: TObject);
+begin
+	if Assigned (Editor) then
+		Editor.ClearSelection;
+end;
+
+procedure TSourceFileForm.EditCut(Sender: TObject);
+begin
+	if Assigned (Editor) then
+		Editor.CutToClipboard;
+end;
+
+procedure TSourceFileForm.EditCopy(Sender: TObject);
+begin
+	if Assigned (Editor) then
+		Editor.CopyToClipboard;
+end;
+
+procedure TSourceFileForm.EditPaste(Sender: TObject);
+begin
+	if Assigned (Editor) then
+		Editor.PasteFromClipboard;
+end;
+
+procedure TSourceFileForm.EditSelectAll(Sender: TObject);
+begin
+	if Assigned (Editor) then
+		Editor.SelectAll;
+end;
+
+procedure TSourceFileForm.EditIncreaseIndent(Sender: TObject);
+begin
+	if Assigned (Editor) then
+		Editor.ChangeIndent (1);
+end;
+
+procedure TSourceFileForm.EditDecreaseIndent(Sender: TObject);
+begin
+	if Assigned (Editor) then
+		Editor.ChangeIndent (-1);
+end;
+
+procedure TSourceFileForm.FindDlgFind(Sender: TObject);
+begin
+	try
+		FindString (Sender);
+	except
+		ShowDefaultMessageBox ('Text ''' + (Sender as TFindDialog).FindText + ''' not found.', 'Search Failed', mtProgramError);
+	end;
+end;
+
+procedure TSourceFileForm.ReplaceDlgReplace(Sender: TObject);
+begin
+	if Assigned (Editor) then
+		with Sender as TReplaceDialog do
+			repeat
+				if UpperCase (Editor.Selection.Text) = UpperCase (FindText) then
+					Editor.Selection.Text := ReplaceText;
+				Options := Options + [frFindNext];
+				FindString (Sender);
+			until not (frReplaceAll in Options);
+end;
+
+procedure TSourceFileForm.FindString(Sender: TObject);
+var
+	P: Integer;
+	S,
+	T: string;
+	Valid: Boolean;
+	FPos: Integer;
+begin
+	if Assigned (Editor) then begin
+		with Sender as TFindDialog do begin
+			if frFindNext in Options then
+				P := Editor.SelStart + 1
+			else
+				if frDown in Options then
+					P := 1
+				else
+					P := Length (Editor.Text);
+			repeat
+				Valid := False;
+				if frDown in Options then
+					T := Copy (Editor.Text, P + 1, Length (Editor.Text))
+				else
+					T := Copy (Editor.Text, 1, P - 1);
+				if frMatchCase in Options then
+					S := FindText
+				else begin
+					S := UpperCase (FindText);
+					T := UpperCase (T);
+				end;
+				if frDown in Options then
+					FPos := Pos (S, T)
+				else
+					FPos := LastPos (S, T);
+				if FPos > 0 then begin
+					Valid := True;
+					if frWholeWord in Options then begin
+						if ((FPos > 1) and (T <> '') and (T [FPos - 1] in ['A'..'Z', 'a'..'z', '0'..'9', '_', '$'])) then
+							Valid := False;
+						if ((FPos + Length (S) < Length (T)) and (T <> '') and (T [FPos + Length (S)] in ['A'..'Z', 'a'..'z', '0'..'9', '_', '$'])) then
+							Valid := False;
+					end;
+					if not (frDown in Options) then
+						P := 0;
+					if not Valid then
+						Inc (P, FPos);
+				end;
+			until Valid or (FPos <= 0);
+			if Valid then begin
+				with Editor.Selection do begin
+					DoChanging;
+					RStart := P + FPos;
+					RLength := Length (S);
+					DoChange;
+					ScrollInView (2);
+				end;
+				SetFocus;
+			end else
+				Abort;
+		end;
+	end;
+end;
+
+procedure TSourceFileForm.FindFind(Sender: TObject);
+begin
+	FindDlg.Execute;
+	SetFocus;
+end;
+
+procedure TSourceFileForm.FindReplace(Sender: TObject);
+begin
+	ReplaceDlg.Execute;
+	SetFocus;
+end;
+
+procedure TSourceFileForm.FindOpenFile(Sender: TObject);
+var
+	I: Integer;
+	S: string;
+	QuotesInLine: Boolean;
+	SourceFile: TSourceFile;
+begin
+	if Assigned (Editor) then begin
+		QuotesInLine := Pos ('"', Editor.Lines [Editor.Selection.StartRowCol.Row - 1]) > 0;
+		S := '';
+		for I := Editor.Selection.RStart - 1 downto 1 do begin
+			if (not QuotesInLine) and (Editor.Text [I] = ' ') then
+				Break;
+			if Editor.Text [I] in [' ', 'A'..'Z', 'a'..'z', '0'..'9', '_', '-', '.', '\', ':'] then
+				S := Editor.Text [I] + S
+			else
+				Break;
+		end;
+		for I := Editor.Selection.RStart to Length (Editor.Text) do begin
+			if (not QuotesInLine) and (Editor.Text [I] = ' ') then
+				Break;
+			if Editor.Text [I] in [' ', 'A'..'Z', 'a'..'z', '0'..'9', '_', '-', '.', '\', ':'] then
+				S := S + Editor.Text [I]
+			else
+				Break;
+		end;
+		S := Trim (S);
+		if Length (S) > 0 then begin
+			SourceFile := MainForm.SourceFiles.FindFileNameOnly (S);
+			if Assigned (SourceFile) then
+				SourceFile.Edit
+			else begin
+				SourceFile := Self.SourceFile;
+				if FileExists (ExpandFileName (S)) then
+					MainForm.AddSourceFile (ExpandFileName (S), True)
+				else if Assigned (SourceFile) and (SourceFile is TGNUAsmSourceFile) and FileExists (WithBackslash (TIGCCFolder) + GASIncludeLocation + S) then
+					MainForm.AddSourceFile (WithBackslash (TIGCCFolder) + GASIncludeLocation + S, True)
+				else if Assigned (SourceFile) and (SourceFile is TAsmSourceFile) and FileExists (WithBackslash (TIGCCFolder) + ASMIncludeLocation + S) then
+					MainForm.AddSourceFile (WithBackslash (TIGCCFolder) + ASMIncludeLocation + S, True)
+				else if FileExists (WithBackslash (TIGCCFolder) + CIncludeLocation + S) then
+					MainForm.AddSourceFile (WithBackslash (TIGCCFolder) + CIncludeLocation + S, True)
+				else
+					ShowDefaultMessageBox ('File ''' + S + ''' not found.', 'Search Failed', mtProgramError);
+			end;
+		end;
+	end;
+end;
+
+procedure TSourceFileForm.FunctionPopupPopup(Sender: TObject);
+var
+	I: Integer;
+	M: TMenuItem;
+begin
+	with (Sender as TPopupMenu).Items do begin
+		for I := Count - 1 downto 0 do
+			Remove (Items [I]);
+		UpdateFuncs;
+		for I := Low (Funcs) to High (Funcs) do begin
+			M := TMenuItem.Create (Self);
+			with M do begin
+				Tag := I;
+				Caption := Funcs[I].Name;
+				OnClick := FindFunctionFromPopup;
+			end;
+			if (Pos ('main', Funcs[I].Name) > 0) and (Pos ('main', Funcs[I].Name) = Length (Funcs[I].Name) - Length ('main') + 1) then
+				Insert (0, M)
+			else
+				Add (M);
+		end;
+		if Count <= 0 then
+			Add (NoFunctionsItem);
+	end;
+end;
+
+procedure TSourceFileForm.FindFunctions(Sender: TObject);
+var
+	I: Integer;
+begin
+	UpdateFuncs;
+	with TFunctionsForm.Create (Self) do try
+		Funcs := @Self.Funcs;
+		with FuncList.Items do begin
+			BeginUpdate;
+			Clear;
+			for I := Low (Self.Funcs) to High (Self.Funcs) do
+				AddObject (Self.Funcs[I].Name, TObject (I));
+			EndUpdate;
+		end;
+		FuncListClick (FuncList);
+		case ShowModal of
+			mrYes: begin
+				if Assigned (Editor) then begin
+					Editor.Selection.NoSelAtPos (Editor.CellToCharIdx (TextCell (Self.Funcs[Integer(FuncList.Items.Objects[FuncList.ItemIndex])].PrototypeLine, 1)));
+					Editor.Selection.ScrollInView (5);
+				end;
+			end;
+			mrNo: begin
+				if Assigned (Editor) then begin
+					Editor.Selection.NoSelAtPos (Editor.CellToCharIdx (TextCell (Self.Funcs[Integer(FuncList.Items.Objects[FuncList.ItemIndex])].ImplementationLine, 1)));
+					Editor.Selection.ScrollInView (5);
+				end;
+			end;
+		end;
+		with FuncList.Items do begin
+			BeginUpdate;
+			for I := Count - 1 downto 0 do begin
+				Objects [I] := nil;
+				Delete (I);
+			end;
+			EndUpdate;
+		end;
+	finally
+		Free;
+	end;
+end;
+
+procedure TSourceFileForm.UpdateFuncs;
+begin
+	if Assigned (SourceFile) and (SourceFile is TSourceTextSourceFile) then
+		with SourceFile as TSourceTextSourceFile do
+			Funcs := GetFunctions
+	else
+		SetLength (Funcs, 0);
+end;
+
+procedure TSourceFileForm.FindFunctionFromPopup(Sender: TObject);
+var
+	L: Integer;
+begin
+	if Sender is TMenuItem then
+		with Sender as TMenuItem do begin
+			if Funcs[Tag].ImplementationLine > 0 then
+				L := Funcs[Tag].ImplementationLine
+			else
+				L := Funcs[Tag].PrototypeLine;
+			if L > 0 then begin
+				if Assigned (Editor) then begin
+					Editor.Selection.NoSelAtPos (Editor.CellToCharIdx (TextCell (L, 1)));
+					Editor.Selection.ScrollInView (5);
+				end;
+			end;
+		end;
+end;
+
+procedure TSourceFileForm.FileAddToProject(Sender: TObject);
+var
+	N: TTreeNode;
+begin
+	if (not Compiling) and Assigned (SourceFile) then
+		with MainForm, SourceFile do begin
+			ParentForm := nil;
+			N := ProjectTree.Items.AddChildObject (TopNode.Item [ClassTreeIndex], SourceName, Pointer (SourceFile));
+			with N do begin
+				ImageIndex := ClassImageIndex;
+				SelectedIndex := ImageIndex;
+			end;
+			TreeItem := N;
+			if Assigned (Editor) then
+				with Editor do begin
+					Hide;
+					Parent := EditorPanel;
+					Align := alClient;
+				end;
+			if SourceFile is TTextSourceFile then
+				with SourceFile as TTextSourceFile do
+					if Assigned (TextEditor) then
+						with TextEditor do begin
+							OnEnter := EditorEnter;
+							OnExit := EditorExit;
+							OnKeyDown := EditorKeyDown;
+							OnChange := EditorChange;
+							OnSelectionChange := EditorChange;
+							PopupMenu := EditorPopup;
+						end;
+			SortFiles;
+			MainForm.Modify;
+			ProjectTree.Selected := N;
+			SourceFile := nil;
+			Self.Close;
+		end;
+end;
+
+procedure TSourceFileForm.FormEnable(Sender: TObject);
+begin
+	if Assigned (EnableTimer) then begin
+		EnableTimer.Free;
+		EnableTimer := nil;
+	end;
+	Enabled := True;
+	if Assigned (Editor) then begin
+		Editor.Enabled := False;
+		Editor.Enabled := True;
+		ActiveControl := Editor;
+	end;
+	SetFocus;
+end;
+
+procedure TSourceFileForm.FormShow(Sender: TObject);
+begin
+	if not (Enabled or Assigned (EnableTimer)) then begin
+		EnableTimer := TTimer.Create (Self);
+		EnableTimer.OnTimer := FormEnable;
+		EnableTimer.Interval := 100;
+		EnableTimer.Enabled := True;
+	end;
+end;
+
+procedure TSourceFileForm.CreateParams(var Params: TCreateParams);
+begin
+	inherited;
+	Params.WndParent := GetDesktopWindow;
+end;
+
+{$IFDEF CODINGEXT}
+procedure TSourceFileForm.InitCodingExt;
+var
+	ActionFindSymbol: TAction;
+begin
+	// Find Symbol declaration tool
+	ActionFindSymbol := TAction.Create(Self);
+	with ActionFindSymbol do begin
+		ActionList := Actions;
+		Caption := 'Find Symbol Declaration';
+		Category := 'Extension';
+		OnExecute := ActionFindSymbolExecute;
+	end;
+
+	InsertsAction(Self, [OpenFileAtCursor1, OpenFileatCursor2], ActionFindSymbol);
+end;
+
+procedure TSourceFileForm.ActionFindSymbolExecute(Sender: TObject);
+begin
+	CompForm.FindSymbolDecl;
+end;
+{$ENDIF}
+
+procedure TSourceFileForm.FindDlgClose(Sender: TObject);
+begin
+	SetFocus;
+end;
+
+end.
+

BIN
StartupScreenUnit.dfm


+ 58 - 0
StartupScreenUnit.pas

@@ -0,0 +1,58 @@
+unit StartupScreenUnit;
+
+interface
+
+uses
+	Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+	StdCtrls, ExtCtrls;
+
+type
+	TStartupScreenForm = class(TForm)
+		FramePanel: TPanel;
+		BackgroundPanel: TPanel;
+		BackgroundImage: TImage;
+		VersionLabel: TLabel;
+		NameLabel1: TLabel;
+		NameLabel3: TLabel;
+		NameLabel4: TLabel;
+		NameLabel5: TLabel;
+		NameLabel6: TLabel;
+		NameLabel7: TLabel;
+		NameLabel8: TLabel;
+    StartupStatusDisplay: TLabel;
+		procedure FormCreate(Sender: TObject);
+	private
+		function GetDisplayText: string;
+		procedure SetDisplayText(const Value: string);
+	public
+		property DisplayText: string read GetDisplayText write SetDisplayText;
+	end;
+
+var
+	StartupScreenForm: TStartupScreenForm;
+
+implementation
+
+{$R *.DFM}
+
+uses
+	VersionUnit;
+
+procedure TStartupScreenForm.FormCreate(Sender: TObject);
+begin
+	PixelsPerInch := 96;
+	VersionLabel.Caption := TIGCCShortVersion;
+end;
+
+function TStartupScreenForm.GetDisplayText: string;
+begin
+	Result := StartupStatusDisplay.Caption;
+end;
+
+procedure TStartupScreenForm.SetDisplayText(const Value: string);
+begin
+	StartupStatusDisplay.Caption := Value;
+	Update;
+end;
+
+end.

BIN
StartupUnit.dfm


BIN
StyleSelectionUnit.dfm


+ 75 - 0
StyleSelectionUnit.pas

@@ -0,0 +1,75 @@
+unit StyleSelectionUnit;
+
+interface
+
+uses
+  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+  StdCtrls, ExtCtrls;
+
+type
+  TStyleSelectionForm = class(TForm)
+    CheckBox1: TCheckBox;
+    CheckBox2: TCheckBox;
+    CheckBox3: TCheckBox;
+    CheckBox4: TCheckBox;
+    CheckBox5: TCheckBox;
+    Bevel1: TBevel;
+    Button1: TButton;
+    Button2: TButton;
+    procedure CheckBox1Click(Sender: TObject);
+    procedure FormShow(Sender: TObject);
+    procedure FormClose(Sender: TObject; var Action: TCloseAction);
+  private
+	public
+		Style: TFontStyles;
+		CustomStyle: Boolean;
+	end;
+
+implementation
+
+{$R *.DFM}
+
+procedure TStyleSelectionForm.CheckBox1Click(Sender: TObject);
+begin
+	CheckBox2.Enabled := CheckBox1.Checked;
+	CheckBox3.Enabled := CheckBox1.Checked;
+	CheckBox4.Enabled := CheckBox1.Checked;
+	CheckBox5.Enabled := CheckBox1.Checked;
+	if not CheckBox2.Enabled then
+		CheckBox2.Checked := False;
+	if not CheckBox3.Enabled then
+		CheckBox3.Checked := False;
+	if not CheckBox4.Enabled then
+		CheckBox4.Checked := False;
+	if not CheckBox5.Enabled then
+		CheckBox5.Checked := False;
+end;
+
+procedure TStyleSelectionForm.FormShow(Sender: TObject);
+begin
+	CheckBox1.Checked := CustomStyle;
+	CheckBox2.Checked := fsBold in Style;
+	CheckBox3.Checked := fsItalic in Style;
+	CheckBox4.Checked := fsUnderline in Style;
+	CheckBox5.Checked := fsStrikeOut in Style;
+	CheckBox1Click (Sender);
+end;
+
+procedure TStyleSelectionForm.FormClose(Sender: TObject;
+	var Action: TCloseAction);
+begin
+	CustomStyle := CheckBox1.Checked;
+	if CustomStyle then begin
+		Style := [];
+		if CheckBox2.Checked then
+			Include (Style, fsBold);
+		if CheckBox3.Checked then
+			Include (Style, fsItalic);
+		if CheckBox4.Checked then
+			Include (Style, fsUnderline);
+		if CheckBox5.Checked then
+			Include (Style, fsStrikeOut);
+	end;
+end;
+
+end.

BIN
SyntaxProgressUnit.dfm


BIN
ToolPropertiesUnit.dfm


+ 82 - 0
ToolPropertiesUnit.pas

@@ -0,0 +1,82 @@
+unit ToolPropertiesUnit;
+
+interface
+
+uses
+  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+  StdCtrls, ExtCtrls;
+
+type
+  TToolPropertiesForm = class(TForm)
+    Label1: TLabel;
+    Label2: TLabel;
+    Label3: TLabel;
+    Label4: TLabel;
+    TitleEdit: TEdit;
+    CommandLineEdit: TEdit;
+    WorkingDirEdit: TEdit;
+    Bevel1: TBevel;
+    OKButton: TButton;
+    CancelButton: TButton;
+    WindowStateEdit: TComboBox;
+    CommandLineBrowseButton: TButton;
+    WorkingDirBrowseButton: TButton;
+    BrowseDialog: TOpenDialog;
+    procedure EditChange(Sender: TObject);
+    procedure CommandLineBrowseButtonClick(Sender: TObject);
+    procedure WorkingDirBrowseButtonClick(Sender: TObject);
+  private
+	public
+	end;
+
+implementation
+
+{$R *.DFM}
+
+uses
+	ShlObj;
+
+procedure TToolPropertiesForm.EditChange(Sender: TObject);
+begin
+	OKButton.Enabled := (Length (TitleEdit.Text) > 0) and (Length (CommandLineEdit.Text) > 0);
+end;
+
+procedure TToolPropertiesForm.CommandLineBrowseButtonClick(Sender: TObject);
+var
+	S: string;
+begin
+	with BrowseDialog do begin
+		S := CommandLineEdit.Text;
+		if (Length (S) > 0) and ((S [1] = '"') or (Pos (' ', S) <= 0)) then begin
+			if S [1] = '"' then begin
+				Delete (S, 1, 1);
+				if Pos ('"', S) > 0 then
+					Delete (S, Pos ('"', S), Length (S));
+			end;
+			FileName := S;
+		end;
+		if Execute then
+			CommandLineEdit.Text := '"' + FileName + '"';
+	end;
+end;
+
+procedure TToolPropertiesForm.WorkingDirBrowseButtonClick(Sender: TObject);
+var
+	Info: TBrowseInfo;
+	Path: PItemIDList;
+	FolderName: array [0..MAX_PATH] of Char;
+begin
+	FillChar (Info, SizeOf (Info), 0);
+	with Info do begin
+		hwndOwner := Handle;
+		lpszTitle := 'Browse';
+		ulFlags := BIF_RETURNONLYFSDIRS;
+	end;
+	Path := SHBrowseForFolder (Info);
+	if Assigned (Path) then begin
+		if SHGetPathFromIDList (Path, FolderName) then
+			WorkingDirEdit.Text := FolderName;
+	end;
+end;
+
+end.

+ 40 - 0
ToolsListUnit.pas

@@ -0,0 +1,40 @@
+unit ToolsListUnit;
+
+interface
+
+uses
+	ObjList,
+	Classes, Controls, Forms, Menus;
+
+type
+	TToolsList = class(TFastObjectContainer);
+
+	TToolsListItem = class(TFastContainerItem)
+	private
+		FWorkingDir: string;
+		FCommandLine: string;
+		FTitle: TCaption;
+		FWindowState: TWindowState;
+    FMenuItem: TMenuItem;
+	public
+		destructor Destroy; override;
+		property MenuItem: TMenuItem read FMenuItem write FMenuItem;
+	published
+		property Title: TCaption read FTitle write FTitle;
+		property CommandLine: string read FCommandLine write FCommandLine;
+		property WorkingDir: string read FWorkingDir write FWorkingDir;
+		property WindowState: TWindowState read FWindowState write FWindowState;
+	end;
+
+implementation
+
+{ TToolsListItem }
+
+destructor TToolsListItem.Destroy;
+begin
+	if Assigned (MenuItem) then
+		MenuItem.Free;
+	inherited;
+end;
+
+end.

BIN
ToolsUnit.dfm


+ 179 - 0
ToolsUnit.pas

@@ -0,0 +1,179 @@
+unit ToolsUnit;
+
+interface
+
+uses
+	Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+	StdCtrls, ComCtrls;
+
+type
+	TToolsForm = class(TForm)
+		ToolsList: TListView;
+		AddButton: TButton;
+		EditButton: TButton;
+		RemoveButton: TButton;
+		OKButton: TButton;
+		CancelButton: TButton;
+		procedure AddButtonClick(Sender: TObject);
+		procedure EditButtonClick(Sender: TObject);
+		procedure RemoveButtonClick(Sender: TObject);
+		procedure ToolsListSelectItem(Sender: TObject; Item: TListItem;
+			Selected: Boolean);
+		procedure ToolsListKeyDown(Sender: TObject; var Key: Word;
+			Shift: TShiftState);
+		procedure ToolsListDragDrop(Sender, Source: TObject; X, Y: Integer);
+		procedure ToolsListDragOver(Sender, Source: TObject; X, Y: Integer;
+			State: TDragState; var Accept: Boolean);
+	private
+	public
+		function WindowStateToString(WindowState: TWindowState): string;
+		function StringToWindowState(const S: string): TWindowState;
+	end;
+
+const
+	NormalString = 'Normal';
+	MaximizedString = 'Maximized';
+	MinimizedString = 'Minimized';
+
+implementation
+
+{$R *.DFM}
+
+uses
+	ToolPropertiesUnit;
+
+procedure TToolsForm.AddButtonClick(Sender: TObject);
+begin
+	with TToolPropertiesForm.Create (Self) do try
+		WindowStateEdit.ItemIndex := 0;
+		if ShowModal = mrOK then begin
+			with ToolsList.Items.Add do begin
+				Caption := TitleEdit.Text;
+				SubItems.Add (CommandLineEdit.Text);
+				SubItems.Add (WorkingDirEdit.Text);
+				SubItems.Add (WindowStateEdit.Text);
+			end;
+		end;
+	finally
+		Free;
+	end;
+end;
+
+procedure TToolsForm.EditButtonClick(Sender: TObject);
+begin
+	if Assigned (ToolsList.Selected) then
+		with TToolPropertiesForm.Create (Self) do try
+			with ToolsList.Selected do begin
+				TitleEdit.Text := Caption;
+				CommandLineEdit.Text := SubItems [0];
+				WorkingDirEdit.Text := SubItems [1];
+				case StringToWindowState (SubItems [2]) of
+					wsMaximized:
+						WindowStateEdit.ItemIndex := 1;
+					wsMinimized:
+						WindowStateEdit.ItemIndex := 2;
+					else
+						WindowStateEdit.ItemIndex := 0;
+				end;
+			end;
+			if ShowModal = mrOK then begin
+				with ToolsList.Selected do begin
+					Caption := TitleEdit.Text;
+					SubItems [0] := CommandLineEdit.Text;
+					SubItems [1] := WorkingDirEdit.Text;
+					case WindowStateEdit.ItemIndex of
+						1:
+							SubItems [2] := MaximizedString;
+						2:
+							SubItems [2] := MinimizedString;
+						else
+							SubItems [2] := NormalString;
+					end;
+				end;
+			end;
+		finally
+			Free;
+		end;
+end;
+
+procedure TToolsForm.RemoveButtonClick(Sender: TObject);
+begin
+	if Assigned (ToolsList.Selected) then
+		ToolsList.Selected.Free;
+end;
+
+procedure TToolsForm.ToolsListSelectItem(Sender: TObject; Item: TListItem; Selected: Boolean);
+begin
+	EditButton.Enabled := Assigned (ToolsList.Selected);
+	RemoveButton.Enabled := Assigned (ToolsList.Selected);
+end;
+
+procedure TToolsForm.ToolsListKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+begin
+	if Key = vk_Delete then
+		RemoveButtonClick (Sender);
+end;
+
+procedure TToolsForm.ToolsListDragDrop(Sender, Source: TObject; X, Y: Integer);
+var
+	S,
+	D: TListItem;
+	DIndex: Integer;
+begin
+	with ToolsList do begin
+		S := Selected;
+		if Assigned (S) then begin
+			D := GetItemAt (X, Y);
+			if Assigned (D) and (S <> D) then begin
+				DIndex := D.Index;
+				if DIndex > S.Index then
+					Inc (DIndex);
+				with Items.Insert (DIndex) do begin
+					Caption := S.Caption;
+					SubItems.Assign (S.SubItems);
+				end;
+				S.Free;
+			end;
+		end;
+	end;
+end;
+
+procedure TToolsForm.ToolsListDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean);
+var
+	S,
+	D: TListItem;
+begin
+	Accept := False;
+	with ToolsList do begin
+		S := Selected;
+		if Assigned (S) then begin
+			D := GetItemAt (X, Y);
+			if Assigned (D) and (S <> D) then
+				Accept := True;
+		end;
+	end;
+end;
+
+function TToolsForm.WindowStateToString(WindowState: TWindowState): string;
+begin
+	case WindowState of
+		wsMaximized:
+			Result := MaximizedString;
+		wsMinimized:
+			Result := MinimizedString;
+		else
+			Result := NormalString;
+	end;
+end;
+
+function TToolsForm.StringToWindowState(const S: string): TWindowState;
+begin
+	if S = MaximizedString then
+		Result := wsMaximized
+	else if S = MinimizedString then
+		Result := wsMinimized
+	else
+		Result := wsNormal;
+end;
+
+end.

BIN
VTIStartUnit.dfm


+ 76 - 0
VTIStartUnit.pas

@@ -0,0 +1,76 @@
+unit VTIStartUnit;
+
+interface
+
+uses
+	MasterUnit,
+	Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+	StdCtrls, ExtCtrls;
+
+type
+	TVTIStartForm = class(TForm)
+		Label1: TLabel;
+		CancelButton: TButton;
+    FindTimer: TTimer;
+		procedure FormShow(Sender: TObject);
+		procedure FormClose(Sender: TObject; var Action: TCloseAction);
+    procedure FindTimerTimer(Sender: TObject);
+	private
+		ProcessHandle: THandle;
+	public
+		VTIWindow: HWnd;
+		VTIType: TCurVTIType;
+	end;
+
+implementation
+
+{$R *.DFM}
+
+uses
+	UtilsWin;
+
+procedure TVTIStartForm.FormShow(Sender: TObject);
+var
+	StartupInfo: TStartupInfo;
+	ProcessInfo: TProcessInformation;
+begin
+	FillChar (StartupInfo, SizeOf (StartupInfo), 0);
+	StartupInfo.cb := SizeOf (StartupInfo);
+	if CreateProcess (nil, PChar (VTIPath), nil, nil, False, CREATE_NEW_PROCESS_GROUP or DETACHED_PROCESS, nil, PChar (ExtractFilePath (VTIPath)), StartupInfo, ProcessInfo) then begin
+		ProcessHandle := ProcessInfo.hProcess;
+		CloseHandle (ProcessInfo.hThread);
+	end else begin
+		ShowDefaultMessageBox ('An error occurred while trying to start Virtual TI.', 'Error', mtProgramError);
+		ModalResult := mrAbort;
+	end;
+end;
+
+procedure TVTIStartForm.FormClose(Sender: TObject;
+	var Action: TCloseAction);
+begin
+	if ProcessHandle <> 0 then
+		CloseHandle (ProcessHandle);
+end;
+
+procedure TVTIStartForm.FindTimerTimer(Sender: TObject);
+var
+	ExitCode: Cardinal;
+begin
+	if GetExitCodeProcess (ProcessHandle, ExitCode) then begin
+		if ExitCode <> STILL_ACTIVE then begin
+			ModalResult := mrAbort;
+			Exit;
+		end;
+	end;
+	VTIWindow := FindWindow ('TEmuWnd', 'Virtual TI-89');
+	if VTIWindow = 0 then begin
+		VTIWindow := FindWindow ('TEmuWnd', 'Virtual TI-92+');
+		if VTIWindow <> 0 then
+			VTIType := cvTI92Plus;
+	end else
+		VTIType := cvTI89;
+	if VTIWindow <> 0 then
+		ModalResult := mrOK;
+end;
+
+end.

+ 12 - 0
VersionUnit.pas

@@ -0,0 +1,12 @@
+unit VersionUnit;
+{ This file is generated automatically. }
+
+interface
+
+const
+	TIGCCShortVersion = '0.95';
+	TIGCCLongVersion = '0.95';
+
+implementation
+
+end.

BIN
WordListUnit.dfm


+ 93 - 0
WordListUnit.pas

@@ -0,0 +1,93 @@
+unit WordListUnit;
+
+interface
+
+uses
+	SourceEditUnit,
+	Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+  StdCtrls, ExtCtrls;
+
+type
+	TWordListForm = class(TForm)
+    Button1: TButton;
+    Button2: TButton;
+    ColorDlg: TColorDialog;
+    Bevel1: TBevel;
+    Bevel2: TBevel;
+    Button3: TButton;
+    Button4: TButton;
+    ListStrings: TMemo;
+    CaseSensitiveBox: TCheckBox;
+		procedure FormCreate(Sender: TObject);
+		procedure FormDestroy(Sender: TObject);
+    procedure Button1Click(Sender: TObject);
+    procedure Button2Click(Sender: TObject);
+    procedure FormShow(Sender: TObject);
+    procedure FormClose(Sender: TObject; var Action: TCloseAction);
+    procedure CaseSensitiveBoxClick(Sender: TObject);
+	private
+	public
+		List: TWordList;
+	end;
+
+var
+	WordListForm: TWordListForm;
+
+implementation
+
+{$R *.DFM}
+
+uses
+	StyleSelectionUnit;
+
+procedure TWordListForm.FormCreate(Sender: TObject);
+begin
+	List := TWordList.Create (nil);
+end;
+
+procedure TWordListForm.FormDestroy(Sender: TObject);
+begin
+	List.Free;
+end;
+
+procedure TWordListForm.Button1Click(Sender: TObject);
+begin
+	ColorDlg.Color := List.Color;
+	if ColorDlg.Execute then begin
+		List.Color := ColorDlg.Color;
+		List.CustomColor := True;
+	end;
+end;
+
+procedure TWordListForm.Button2Click(Sender: TObject);
+begin
+	with TStyleSelectionForm.Create (Self) do try
+		CustomStyle := List.CustomStyle;
+		Style := List.Style;
+		if ShowModal = mrOK then begin
+			List.CustomStyle := CustomStyle;
+			List.Style := Style;
+		end;
+	finally
+		Free;
+	end;
+end;
+
+procedure TWordListForm.FormShow(Sender: TObject);
+begin
+	ListStrings.Lines.Assign (List.Words);
+	CaseSensitiveBox.Checked := List.CaseSensitive;
+end;
+
+procedure TWordListForm.FormClose(Sender: TObject;
+	var Action: TCloseAction);
+begin
+	List.Words.Assign (ListStrings.Lines);
+end;
+
+procedure TWordListForm.CaseSensitiveBoxClick(Sender: TObject);
+begin
+	List.CaseSensitive := CaseSensitiveBox.Checked;
+end;
+
+end.

Some files were not shown because too many files changed in this diff