1 {
2 ***************************************************************************
3 *                                                                         *
4 *   This source is free software; you can redistribute it and/or modify   *
5 *   it under the terms of the GNU General Public License as published by  *
6 *   the Free Software Foundation; either version 2 of the License, or     *
7 *   (at your option) any later version.                                   *
8 *                                                                         *
9 *   This code is distributed in the hope that it will be useful, but      *
10 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
11 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
12 *   General Public License for more details.                              *
13 *                                                                         *
14 *   A copy of the GNU General Public License is available on the World    *
15 *   Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also      *
16 *   obtain it by writing to the Free Software Foundation,                 *
17 *   Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA.   *
18 *                                                                         *
19 ***************************************************************************
20 
21   Author: Mattias: Gaertner
22 
23   Abstract:
24     When a new unit is created check if compiler options in lpi and main source
25     differ. This is a common mistake when upgrading old projects.
26 }
27 unit CheckCompOptsForNewUnitDlg;
28 
29 {$mode objfpc}{$H+}
30 
31 interface
32 
33 uses
34   Classes, SysUtils, LCLProc, FileUtil, Forms, Controls, Graphics, Dialogs,
35   StdCtrls, ExtCtrls, ButtonPanel,
36   CodeToolManager, BasicCodeTools, DefineTemplates,
37   CompOptsIntf, ProjectIntf, IDEDialogs,
38   InputHistory, TransferMacros, Project, LazarusIDEStrConsts;
39 
40 type
41 
42   { TCheckCompOptsForNewUnitDialog }
43 
44   TCheckCompOptsForNewUnitDialog = class(TForm)
45     AnsistringCheckBox: TCheckBox;
46     ButtonPanel1: TButtonPanel;
47     DoNotWarnCheckBox: TCheckBox;
48     ModeComboBox: TComboBox;
49     ModeLabel: TLabel;
50     NoteLabel: TLabel;
51     procedure FormCreate(Sender: TObject);
52     procedure OkButtonClick(Sender: TObject);
53   private
54     FMainAnsistring: char;
55     FMainMode: string;
56   public
57     CompOpts: TLazCompilerOptions;
58     procedure UpdateOptions;
59     property MainMode: string read FMainMode write FMainMode;
60     property MainAnsistring: char read FMainAnsistring write FMainAnsistring;
61   end;
62 
CheckCompOptsAndMainSrcForNewUnitnull63 function CheckCompOptsAndMainSrcForNewUnit(CompOpts: TLazCompilerOptions): TModalResult;
GetIgnorePathForCompOptsAndMainSrcDiffernull64 function GetIgnorePathForCompOptsAndMainSrcDiffer(CompOpts: TLazCompilerOptions): string;
65 
66 implementation
67 
CheckCompOptsAndMainSrcForNewUnitnull68 function CheckCompOptsAndMainSrcForNewUnit(CompOpts: TLazCompilerOptions): TModalResult;
69 var
70   ProjCompOpts: TProjectCompilerOptions;
71   MainUnit: TUnitInfo;
72   Src: String;
73   StartPos: Integer;
74   p: PChar;
75   Mode: String;
76   AnsistringMode: Char;
77   NestedComments: Boolean;
78   Dlg: TCheckCompOptsForNewUnitDialog;
79   IgnoreIdentifier: String;
80 begin
81   Result:=mrOK;
82   if CompOpts is TProjectCompilerOptions then
83   begin
84     ProjCompOpts:=TProjectCompilerOptions(CompOpts);
85     if (ProjCompOpts.LazProject=nil) then exit;
86     MainUnit:=ProjCompOpts.LazProject.MainUnitInfo;
87     if (MainUnit=nil) or (MainUnit.Source=nil) then exit;
88 
89     // check if this question should be ignored
90     IgnoreIdentifier:=GetIgnorePathForCompOptsAndMainSrcDiffer(CompOpts);
91     if (IgnoreIdentifier<>'')
92     and (InputHistories.Ignores.Find(IgnoreIdentifier)<>nil) then
93       exit;
94 
95     Src:=MainUnit.Source.Source;
96     Mode:='';
97     AnsistringMode:=#0;
98     StartPos:=1;
99     NestedComments:=false;
100     repeat
101       StartPos:=FindNextCompilerDirective(Src,StartPos,NestedComments);
102       if StartPos>length(Src) then break;
103       p:=@Src[StartPos];
104       StartPos:=FindCommentEnd(Src,StartPos,NestedComments);
105       if p^<>'{' then continue;
106       inc(p);
107       if p^<>'$' then continue;
108       inc(p);
109       if (Mode='') and (CompareIdentifiers(p,'mode')=0) then begin
110         // mode directive
111         inc(p,4);
112         while p^ in [' ',#9] do inc(p);
113         Mode:=GetIdentifier(p);
114       end
115       else if (AnsistringMode=#0) and (p^='H') and (p[1] in ['+','-']) then begin
116         // ansistring directive
117         AnsistringMode:=p[1];
118       end;
119     until false;
120     //debugln(['CheckCompOptsAndMainSrcForNewUnit Mode=',Mode,' ProjMode=',ProjCompOpts.SyntaxMode,' Str=',AnsistringMode='+',' ProjStr=',ProjCompOpts.UseAnsiStrings]);
121     if ((Mode<>'') and (SysUtils.CompareText(Mode,ProjCompOpts.SyntaxMode)<>0))
122     or ((AnsistringMode<>#0) and ((AnsistringMode='+')<>ProjCompOpts.UseAnsiStrings))
123     then begin
124       Dlg:=TCheckCompOptsForNewUnitDialog.Create(nil);
125       try
126         Dlg.CompOpts:=CompOpts;
127         Dlg.MainMode:=Mode;
128         Dlg.MainAnsistring:=AnsistringMode;
129         Dlg.UpdateOptions;
130         if Dlg.ShowModal<>mrOk then
131           Result:=mrCancel;
132       finally
133         Dlg.Free;
134       end;
135     end;
136   end;
137 end;
138 
GetIgnorePathForCompOptsAndMainSrcDiffernull139 function GetIgnorePathForCompOptsAndMainSrcDiffer(CompOpts: TLazCompilerOptions
140   ): string;
141 var
142   ProjCompOpts: TProjectCompilerOptions;
143 begin
144   Result:='';
145   if (CompOpts is TProjectCompilerOptions) then
146   begin
147     ProjCompOpts:=TProjectCompilerOptions(CompOpts);
148     if ProjCompOpts.LazProject<>nil then
149       Result:='NewUnitProjOptsAndMainSrcDiffer/'+ProjCompOpts.LazProject.ProjectInfoFile;
150   end;
151 end;
152 
153 {$R *.lfm}
154 
155 { TCheckCompOptsForNewUnitDialog }
156 
157 procedure TCheckCompOptsForNewUnitDialog.FormCreate(Sender: TObject);
158 var
159   i: Integer;
160 begin
161   Caption:=lisDirectivesForNewUnit;
162   ButtonPanel1.OKButton.Caption:=lisContinue;
163   ModeLabel.Caption:=lisSyntaxMode;
164   for i:=low(FPCSyntaxModes) to high(FPCSyntaxModes) do
165     ModeComboBox.Items.Add(FPCSyntaxModes[i]);
166   AnsistringCheckBox.Caption:=lisUseAnsistrings;
167   DoNotWarnCheckBox.Caption:=lisDoNotShowThisDialogForThisProject;
168 end;
169 
170 procedure TCheckCompOptsForNewUnitDialog.OkButtonClick(Sender: TObject);
171 var
172   NewMode: String;
173   i: Integer;
174   IgnoreIdentifier: String;
175 begin
176   NewMode:=ModeComboBox.Text;
177   if SysUtils.CompareText(CompOpts.SyntaxMode,NewMode)<>0 then
178   begin
179     i:=low(FPCSyntaxModes);
180     while (i<=High(FPCSyntaxModes))
181     and (SysUtils.CompareText(FPCSyntaxModes[i],NewMode)<>0) do
182       inc(i);
183     if i>High(FPCSyntaxModes) then
184     begin
185       IDEMessageDialog(lisCCOErrorCaption, Format(lisInvalidMode, [NewMode]),
186         mtError, [mbCancel]);
187       exit;
188     end;
189   end;
190 
191   if (CompOpts.UseAnsiStrings<>AnsistringCheckBox.Checked)
192   or (CompOpts.SyntaxMode<>NewMode) then
193   begin
194     CompOpts.UseAnsiStrings:=AnsistringCheckBox.Checked;
195     CompOpts.SyntaxMode:=NewMode;
196     IncreaseCompilerParseStamp;
197   end;
198 
199   if DoNotWarnCheckBox.Checked then
200   begin
201     IgnoreIdentifier:=GetIgnorePathForCompOptsAndMainSrcDiffer(CompOpts);
202     if IgnoreIdentifier<>'' then;
203       InputHistories.Ignores.Add(IgnoreIdentifier,iiidForever);
204   end;
205 
206   ModalResult:=mrOk;
207 end;
208 
209 procedure TCheckCompOptsForNewUnitDialog.UpdateOptions;
210 begin
211   NoteLabel.Caption:=lisTheProjectCompilerOptionsAndTheDirectivesInTheMain;
212   AnsistringCheckBox.Checked:=CompOpts.UseAnsiStrings;
213   ModeComboBox.Text:=CompOpts.SyntaxMode;
214 end;
215 
216 end.
217 
218