install.pas 59 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1993-2015 by Florian Klaempfl
  4. member of the Free Pascal development team
  5. This is the install program for the DOS and OS/2 versions of Free Pascal
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. program install;
  13. { $DEFINE DLL} (* TH - if defined, UNZIP32.DLL library is used to unpack. *)
  14. { $DEFINE DOSSTUB} (* TH - should _not_ be defined unless creating a bound DOS and OS/2 installer!!! *)
  15. (* Defining DOSSTUB causes adding a small piece of code *)
  16. (* for starting the OS/2 part from the DOS part of a bound *)
  17. (* application if running in OS/2 VDM (DOS) window. Used *)
  18. (* only if compiling with TP/BP (see conditionals below). *)
  19. {$IFDEF OS2}
  20. {$DEFINE DLL}
  21. {$ENDIF DLL}
  22. {$IFDEF VER60}
  23. {$DEFINE TP}
  24. {$ENDIF}
  25. {$IFDEF VER70}
  26. {$DEFINE TP}
  27. {$ENDIF}
  28. {$IFNDEF TP}
  29. {$UNDEF DOSSTUB}
  30. {$ELSE}
  31. {$IFDEF OS2}
  32. {$UNDEF DOSSTUB}
  33. {$ENDIF}
  34. {$ENDIF}
  35. {$IFDEF DPMI}
  36. {$UNDEF DOSSTUB}
  37. {$ENDIF}
  38. {$ifdef go32v2}
  39. {$define MAYBE_LFN}
  40. {$endif}
  41. {$ifdef debug}
  42. {$ifdef win32}
  43. {$define MAYBE_LFN}
  44. {$endif win32}
  45. {$endif debug}
  46. {$ifdef TP}
  47. {$define MAYBE_LFN}
  48. {$endif}
  49. uses
  50. {$IFDEF OS2}
  51. {$IFDEF FPC}
  52. DosCalls,
  53. {$ELSE FPC}
  54. {$IFDEF VirtualPascal}
  55. OS2Base,
  56. {$ELSE VirtualPascal}
  57. BseDos,
  58. {$ENDIF VirtualPascal}
  59. {$ENDIF FPC}
  60. {$ENDIF OS2}
  61. {$IFDEF GO32V2}
  62. emu387,
  63. {$ENDIF}
  64. {$ifdef HEAPTRC}
  65. heaptrc,
  66. {$endif HEAPTRC}
  67. strings,dos,objects,drivers,
  68. {$IFNDEF FVISION}
  69. commands,
  70. HelpCtx,
  71. {$ENDIF}
  72. unzip51g,ziptypes,
  73. {$IFDEF DLL}
  74. unzipdll,
  75. {$ENDIF}
  76. app,dialogs,views,menus,msgbox,colortxt,tabs,scroll,
  77. WHTMLScn,insthelp;
  78. const
  79. installerversion='3.0.4';
  80. installercopyright='Copyright (c) 1993-2017 Florian Klaempfl';
  81. maxpacks=20;
  82. maxpackages=32;
  83. maxdefcfgs=1024;
  84. HTMLIndexExt = '.htx';
  85. CfgExt = '.dat';
  86. MaxStatusPos = 4;
  87. StatusChars: string [MaxStatusPos] = '/-\|';
  88. StatusPos: byte = 1;
  89. { this variable is set to true if an ide is installed }
  90. haside : boolean = false;
  91. hashtmlhelp : boolean = false;
  92. {$ifdef Unix}
  93. DirSep='/';
  94. {$else}
  95. DirSep='\';
  96. {$endif}
  97. type
  98. tpackage=record
  99. name : string[60];
  100. zip : string[40]; { default zipname }
  101. zipshort : string[12]; { 8.3 zipname }
  102. diskspace : int64; { diskspace required }
  103. end;
  104. tpack=record
  105. name : string[12];
  106. binsub : string[40];
  107. ppc386 : string[20];
  108. targetname : string[40];
  109. defidecfgfile,
  110. defideinifile,
  111. defcfgfile,
  112. setpathfile : string[12];
  113. include : boolean;
  114. { filechk : string[40]; Obsolete }
  115. packages : longint;
  116. package : array[1..maxpackages] of tpackage;
  117. end;
  118. tcfgarray = array[1..maxdefcfgs] of pstring;
  119. cfgrec=record
  120. title : string[80];
  121. version : string[20];
  122. helpidx,
  123. docsub,
  124. basepath : DirStr;
  125. packs : word;
  126. pack : array[1..maxpacks] of tpack;
  127. defideinis,
  128. defidecfgs,
  129. defcfgs,
  130. defsetpaths : longint;
  131. defideini,
  132. defidecfg,
  133. defcfg,
  134. defsetpath : tcfgarray;
  135. end;
  136. datarec=record
  137. basepath : DirStr;
  138. cfgval : word;
  139. packmask : array[1..maxpacks] of sw_word;
  140. end;
  141. punzipdialog=^tunzipdialog;
  142. tunzipdialog=object(tdialog)
  143. filetext : pstatictext;
  144. extractfiletext : pstatictext;
  145. currentfile : string;
  146. constructor Init(var Bounds: TRect; ATitle: TTitleStr);
  147. procedure do_unzip(s,topath:string);
  148. end;
  149. penddialog = ^tenddialog;
  150. tenddialog = object(tdialog)
  151. constructor init;
  152. end;
  153. pinstalldialog = ^tinstalldialog;
  154. tinstalldialog = object(tdialog)
  155. constructor init;
  156. procedure handleevent(var event : tevent);virtual;
  157. end;
  158. PFPHTMLFileLinkScanner = ^TFPHTMLFileLinkScanner;
  159. TFPHTMLFileLinkScanner = object(THTMLFileLinkScanner)
  160. function CheckURL(const URL: string): boolean; virtual;
  161. function CheckText(const Text: string): boolean; virtual;
  162. procedure ProcessDoc(Doc: PHTMLLinkScanFile); virtual;
  163. end;
  164. phtmlindexdialog = ^thtmlindexdialog;
  165. thtmlindexdialog = object(tdialog)
  166. text : pstatictext;
  167. constructor init(var Bounds: TRect; ATitle: TTitleStr);
  168. end;
  169. tapp = object(tapplication)
  170. procedure initmenubar;virtual;
  171. procedure initstatusline;virtual;
  172. procedure handleevent(var event : tevent);virtual;
  173. procedure do_installdialog;
  174. procedure readcfg(const fn:string);
  175. procedure checkavailpack;
  176. end;
  177. PSpecialInputLine= ^TSpecialInputLine;
  178. TSpecialInputLine = object (TInputLine)
  179. procedure GetData(var Rec); virtual;
  180. end;
  181. {$IFDEF DOSSTUB}
  182. PByte = ^byte;
  183. PRunBlock = ^TRunBlock;
  184. TRunBlock = record
  185. Length: word;
  186. Dependent: word;
  187. Background: word;
  188. TraceLevel: word;
  189. PrgTitle: PChar;
  190. PrgName: PChar;
  191. Args: PChar;
  192. TermQ: longint;
  193. Environment: pointer;
  194. Inheritance: word;
  195. SesType: word;
  196. Icon: pointer;
  197. PgmHandle: longint;
  198. PgmControl: word;
  199. Column: word;
  200. Row: word;
  201. Width: word;
  202. Height: word;
  203. end;
  204. {$ENDIF}
  205. var
  206. installapp : tapp;
  207. startpath : string;
  208. successfull : boolean;
  209. cfg : cfgrec;
  210. data : datarec;
  211. CfgName: NameStr;
  212. DStr: DirStr;
  213. EStr: ExtStr;
  214. UnzDlg : punzipdialog;
  215. log : text;
  216. createlog : boolean;
  217. {$IFNDEF DLL}
  218. const
  219. UnzipErr: longint = 0;
  220. {$ENDIF}
  221. {$ifdef MAYBE_LFN}
  222. const
  223. locallfnsupport : boolean = false;
  224. {$endif MAYBE_LFN}
  225. {*****************************************************************************
  226. Helpers
  227. *****************************************************************************}
  228. procedure errorhalt;
  229. begin
  230. installapp.done;
  231. if CreateLog then
  232. begin
  233. WriteLn (Log, 'Installation hasn''t been completed.');
  234. Close (Log);
  235. end;
  236. halt(1);
  237. end;
  238. procedure WriteLog (const S: string);
  239. begin
  240. if CreateLog then
  241. begin
  242. WriteLn (Log, S);
  243. Flush (Log);
  244. end;
  245. end;
  246. function packagemask(i:longint):longint;
  247. begin
  248. packagemask:=1 shl (i-1);
  249. end;
  250. function upper(const s : string):string;
  251. var
  252. i : integer;
  253. begin
  254. for i:=1 to length(s) do
  255. if s[i] in ['a'..'z'] then
  256. upper[i]:=chr(ord(s[i])-32)
  257. else
  258. upper[i]:=s[i];
  259. upper[0]:=s[0];
  260. end;
  261. procedure Replace(var s:string;const s1,s2:string);
  262. var
  263. i : longint;
  264. begin
  265. repeat
  266. i:=pos(s1,s);
  267. if i>0 then
  268. begin
  269. Delete(s,i,length(s1));
  270. Insert(s2,s,i);
  271. end;
  272. until i=0;
  273. end;
  274. function DotStr(l:longint):string;
  275. var
  276. TmpStr : string[32];
  277. i : longint;
  278. begin
  279. Str(l,TmpStr);
  280. i:=Length(TmpStr);
  281. while (i>3) do
  282. begin
  283. i:=i-3;
  284. if TmpStr[i]<>'-' then
  285. Insert('.',TmpStr,i+1);
  286. end;
  287. DotStr:=TmpStr;
  288. end;
  289. function file_exists(const f : string;const path : string) : boolean;
  290. begin
  291. file_exists:=fsearch(f,path)<>'';
  292. end;
  293. function createdir(s:string):boolean;
  294. var
  295. s1,start : string;
  296. err : boolean;
  297. i : longint;
  298. begin
  299. err:=false;
  300. {$I-}
  301. getdir(0,start);
  302. {$ifndef Unix}
  303. if (s[2]=':') and (s[3]=DirSep) then
  304. begin
  305. chdir(Copy(s,1,3));
  306. Delete(S,1,3);
  307. end;
  308. {$endif}
  309. repeat
  310. i:=Pos(DirSep,s);
  311. if i=0 then
  312. i:=255;
  313. s1:=Copy(s,1,i-1);
  314. Delete(s,1,i);
  315. ChDir(s1);
  316. if ioresult<>0 then
  317. begin
  318. mkdir(s1);
  319. chdir(s1);
  320. if ioresult<>0 then
  321. begin
  322. err:=true;
  323. break;
  324. end;
  325. end;
  326. until s='';
  327. chdir(start);
  328. {$I+}
  329. createdir:=err;
  330. end;
  331. function DiskSpaceN(const zipfile : string) : longint;
  332. var
  333. compressed,uncompressed : longint;
  334. s : string;
  335. begin
  336. s:=zipfile+#0;
  337. if not (IsZip (@S [1])) then
  338. DiskSpaceN := -1
  339. else
  340. begin
  341. Uncompressed:=UnzipSize(@s[1],compressed);
  342. DiskSpaceN:=uncompressed shr 10;
  343. end;
  344. end;
  345. function diskspacestr(uncompressed : longint) : string;
  346. begin
  347. if Uncompressed = -1 then
  348. DiskSpacestr := ' [INVALID]'
  349. else
  350. diskspacestr:=' ('+DotStr(uncompressed)+' KB)';
  351. end;
  352. function createinstalldir(s : string) : boolean;
  353. var
  354. err : boolean;
  355. dir : searchrec;
  356. params : array[0..0] of pointer;
  357. begin
  358. if s[length(s)]=DirSep then
  359. dec(s[0]);
  360. FindFirst(s,AnyFile,dir);
  361. if doserror=0 then
  362. begin
  363. if Dir.Attr and Directory = 0 then
  364. begin
  365. messagebox('A file with the name chosen as the installation '+
  366. 'directory exists already. Cannot create this directory!',nil,
  367. mferror+mfokbutton);
  368. createinstalldir:=false;
  369. end else
  370. createinstalldir:=messagebox('The installation directory exists already. '+
  371. 'Do you want to continue ?',nil,
  372. mferror+mfyesbutton+mfnobutton)=cmYes;
  373. exit;
  374. end;
  375. err:=Createdir(s);
  376. if err then
  377. begin
  378. params[0]:=@s;
  379. messagebox('The installation directory %s couldn''t be created',
  380. @params,mferror+mfokbutton);
  381. createinstalldir:=false;
  382. exit;
  383. end;
  384. {$ifndef TP}
  385. {$IFNDEF OS2}
  386. FindClose (dir);
  387. {$ENDIF}
  388. {$endif}
  389. createinstalldir:=true;
  390. end;
  391. function GetProgDir: DirStr;
  392. var
  393. D: DirStr;
  394. N: NameStr;
  395. E: ExtStr;
  396. begin
  397. FSplit (FExpand (ParamStr (0)), D, N, E);
  398. if (D [0] <> #0) and (D [byte (D [0])] = '\') then Dec (D [0]);
  399. GetProgDir := D;
  400. end;
  401. function GetZipErrorInfo(error : longint) : string;
  402. var
  403. ErrorStr : string;
  404. begin
  405. case error of
  406. unzip_CRCErr : GetZipErrorInfo:='CRC error';
  407. unzip_WriteErr : GetZipErrorInfo:='Write error';
  408. unzip_ReadErr : GetZipErrorInfo:='Read error';
  409. unzip_ZipFileErr : GetZipErrorInfo:='ZipFile erroe';
  410. unzip_UserAbort : GetZipErrorInfo:='User abort';
  411. unzip_NotSupported : GetZipErrorInfo:='Not supported';
  412. unzip_Encrypted : GetZipErrorInfo:='File is encrypted';
  413. unzip_InUse : GetZipErrorInfo:='Fie is in use';
  414. unzip_InternalError : GetZipErrorInfo:='Internal error'; {Error in zip format}
  415. unzip_NoMoreItems : GetZipErrorInfo:='No more items';
  416. unzip_FileError : GetZipErrorInfo:='File error'; {Error Accessing file}
  417. unzip_NotZipfile : GetZipErrorInfo:='Not a zipfile'; {not a zip file}
  418. unzip_SeriousError : GetZipErrorInfo:='Serious error'; {serious error}
  419. unzip_MissingParameter : GetZipErrorInfo:='Missing parameter'; {missing parameter}
  420. else
  421. begin
  422. Str(Error,ErrorStr);
  423. GetZipErrorInfo:='Unknown error '+errorstr;
  424. end;
  425. end;
  426. end;
  427. {*****************************************************************************
  428. HTML-Index Generation
  429. *****************************************************************************}
  430. var
  431. indexdlg : phtmlindexdialog;
  432. constructor thtmlindexdialog.Init(var Bounds: TRect; ATitle: TTitleStr);
  433. var
  434. r : trect;
  435. begin
  436. inherited init(bounds,atitle);
  437. Options:=Options or ofCentered;
  438. R.Assign (4, 2,bounds.B.X-Bounds.A.X-2, 4);
  439. text:=new(pstatictext,init(r,'Please wait ...'));
  440. insert(text);
  441. end;
  442. procedure TFPHTMLFileLinkScanner.ProcessDoc(Doc: PHTMLLinkScanFile);
  443. var
  444. oldtext : pstring;
  445. begin
  446. oldtext:=indexdlg^.text^.text;
  447. indexdlg^.text^.text:=newstr('Processing '+Doc^.GetDocumentURL);
  448. indexdlg^.text^.drawview;
  449. inherited ProcessDoc(Doc);
  450. disposestr(indexdlg^.text^.text);
  451. indexdlg^.text^.text:=oldtext;
  452. indexdlg^.text^.drawview;
  453. end;
  454. function TFPHTMLFileLinkScanner.CheckURL(const URL: string): boolean;
  455. var OK: boolean;
  456. const HTTPPrefix = 'http:';
  457. FTPPrefix = 'ftp:';
  458. begin
  459. OK:=inherited CheckURL(URL);
  460. if OK then OK:=DirAndNameOf(URL)<>'';
  461. if OK then OK:=CompareText(copy(ExtOf(URL),1,4),'.HTM')=0;
  462. if OK then OK:=CompareText(copy(URL,1,length(HTTPPrefix)),HTTPPrefix)<>0;
  463. if OK then OK:=CompareText(copy(URL,1,length(FTPPrefix)),FTPPrefix)<>0;
  464. CheckURL:=OK;
  465. end;
  466. function TFPHTMLFileLinkScanner.CheckText(const Text: string): boolean;
  467. var OK: boolean;
  468. S: string;
  469. begin
  470. S:=Trim(Text);
  471. OK:=(S<>'') and (copy(S,1,1)<>'[');
  472. CheckText:=OK;
  473. end;
  474. procedure writehlpindex(filename : string);
  475. var
  476. LS : PFPHTMLFileLinkScanner;
  477. BS : PBufStream;
  478. Re : Word;
  479. params : array[0..0] of pointer;
  480. dir : searchrec;
  481. r : trect;
  482. begin
  483. r.assign(10,10,70,15);
  484. indexdlg:=new(phtmlindexdialog,init(r,'Creating HTML index file, please wait ...'));
  485. desktop^.insert(indexdlg);
  486. { warning FIXME !!!!, don't know what is to fix here ... PM }
  487. New(LS, Init(DirOf(FileName)));
  488. LS^.ProcessDocument(FileName,[soSubDocsOnly]);
  489. if LS^.GetDocumentCount=0 then
  490. begin
  491. params[0]:=@filename;
  492. MessageBox('Problem creating help index %1, aborting',@params,
  493. mferror+mfokbutton);
  494. end
  495. else
  496. begin
  497. FileName:=DirAndNameOf(FileName)+HTMLIndexExt;
  498. findfirst(filename,AnyFile,dir);
  499. if doserror=0 then
  500. begin
  501. params[0]:=@filename;
  502. Re:=MessageBox('Help index %s already exists, overwrite it?',@params,
  503. mfinformation+mfyesbutton+mfnobutton);
  504. end
  505. else
  506. Re:=cmYes;
  507. if Re<>cmNo then
  508. begin
  509. New(BS, Init(FileName, stCreate, 4096));
  510. if Assigned(BS)=false then
  511. begin
  512. MessageBox('Error while writing help index! '+
  513. 'No help index is created',@params,
  514. mferror+mfokbutton);
  515. Re:=cmCancel;
  516. end
  517. else
  518. begin
  519. LS^.StoreDocuments(BS^);
  520. if BS^.Status<>stOK then
  521. begin
  522. MessageBox('Error while writing help index!'#13+
  523. 'No help index is created',@params,
  524. mferror+mfokbutton);
  525. Re:=cmCancel;
  526. end;
  527. Dispose(BS, Done);
  528. end;
  529. end;
  530. end;
  531. Dispose(LS, Done);
  532. desktop^.delete(indexdlg);
  533. dispose(indexdlg,done);
  534. end;
  535. {*****************************************************************************
  536. Writing of fpc.cfg
  537. *****************************************************************************}
  538. procedure writedefcfg(const fn:string;const cfgdata : tcfgarray;count : longint;const targetname : string);
  539. var
  540. t : text;
  541. i : longint;
  542. s : string;
  543. dir : searchrec;
  544. params : array[0..0] of pointer;
  545. d : dirstr;
  546. n : namestr;
  547. e : extstr;
  548. begin
  549. { already exists }
  550. findfirst(fn,AnyFile,dir);
  551. if doserror=0 then
  552. begin
  553. params[0]:=@fn;
  554. if MessageBox('Config %s already exists, continue writing default config?',@params,
  555. mfinformation+mfyesbutton+mfnobutton)=cmNo then
  556. exit;
  557. end;
  558. { create directory }
  559. fsplit(fn,d,n,e);
  560. createdir(d);
  561. { create the fpc.cfg }
  562. assign(t,fn);
  563. {$I-}
  564. rewrite(t);
  565. {$I+}
  566. if ioresult<>0 then
  567. begin
  568. params[0]:=@fn;
  569. MessageBox(#3'A config not written.'#13#3'%s'#13#3'couldn''t be created',@params,mfinformation+mfokbutton);
  570. exit;
  571. end;
  572. for i:=1 to count do
  573. if assigned(cfgdata[i]) then
  574. begin
  575. s:=cfgdata[i]^;
  576. Replace(s,'%basepath%',data.basepath);
  577. Replace(s,'%targetname%',targetname);
  578. if pos('-',targetname)=0 then
  579. begin
  580. Replace(s,'%targetos%',targetname);
  581. Replace(s,'%fpctargetmacro%','$FPCOS')
  582. end
  583. else
  584. begin
  585. Replace(s,'%targetos%',Copy(targetname,pos('-',targetname)+1,255));
  586. Replace(s,'%fpctargetmacro%','$FPCTARGET');
  587. end;
  588. writeln(t,s);
  589. end
  590. else
  591. writeln(t,'');
  592. close(t);
  593. end;
  594. {*****************************************************************************
  595. TUnZipDialog
  596. *****************************************************************************}
  597. constructor tunzipdialog.Init(var Bounds: TRect; ATitle: TTitleStr);
  598. var
  599. r : trect;
  600. begin
  601. inherited init(bounds,atitle);
  602. Options:=Options or ofCentered;
  603. (* R.Assign (11, 4, 38, 6);*)
  604. R.Assign (1, 4,bounds.B.X-Bounds.A.X-2, 6);
  605. filetext:=new(pstatictext,init(r,#3'File: '));
  606. insert(filetext);
  607. R.Assign (1, 7,bounds.B.X-Bounds.A.X-2, 9);
  608. extractfiletext:=new(pstatictext,init(r,#3' '));
  609. insert(extractfiletext);
  610. end;
  611. {$IFNDEF DLL}
  612. procedure UnzipCheckFn (Retcode: longint; Rec: pReportRec );{$ifdef Delphi32}STDCALL;{$endif}
  613. {$ifndef fpc}{$IFNDEF BIT32} FAR;{$ENDIF BIT32}{$endif}
  614. var
  615. name : string;
  616. begin
  617. case Rec^.Status of
  618. unzip_starting:
  619. UnzipErr := 0;
  620. file_starting:
  621. begin
  622. with UnzDlg^.extractfiletext^ do
  623. begin
  624. Disposestr(text);
  625. name:=Strpas(Rec^.FileName);
  626. UnzDlg^.currentfile:=name;
  627. Text:=NewStr(#3+name);
  628. DrawView;
  629. end;
  630. end;
  631. file_failure:
  632. UnzipErr := RetCode;
  633. file_unzipping:
  634. begin
  635. with UnzDlg^.FileText^ do
  636. begin
  637. Inc (StatusPos);
  638. if StatusPos > MaxStatusPos then StatusPos := 1;
  639. Text^ [Length (Text^)] := StatusChars [StatusPos];
  640. DrawView;
  641. end;
  642. end;
  643. end;
  644. end;
  645. {$ENDIF}
  646. procedure tunzipdialog.do_unzip(s,topath : string);
  647. var
  648. {$ifdef MAYBE_LFN}
  649. p : pathstr;
  650. n : namestr;
  651. e : extstr;
  652. islfn : boolean;
  653. {$endif MAYBE_LFN}
  654. again : boolean;
  655. st2,fn,dir,wild : string;
  656. begin
  657. Disposestr(filetext^.text);
  658. filetext^.Text:=NewStr(#3'File: '+s + #13#3' ');
  659. filetext^.drawview;
  660. if not(file_exists(s,startpath)) then
  661. begin
  662. messagebox('File "'+s+'" missing for the selected installation. '+
  663. 'Installation hasn''t been completed.',nil,mferror+mfokbutton);
  664. WriteLog ('File "' + S +
  665. '" missing for the selected installation!');
  666. errorhalt;
  667. end;
  668. {$IFNDEF DLL}
  669. {$IFDEF FPC}
  670. SetUnzipReportProc (@UnzipCheckFn);
  671. {$ELSE FPC}
  672. SetUnzipReportProc (UnzipCheckFn);
  673. {$ENDIF FPC}
  674. {$ENDIF DLL}
  675. WriteLog ('Unpacking ' + AllFiles + ' from '
  676. + StartPath + DirSep + S + ' to ' + ToPath);
  677. repeat
  678. fn:=startpath+DirSep+s+#0;
  679. dir:=topath+#0;
  680. wild:=AllFiles + #0;
  681. again:=false;
  682. FileUnzipEx(@fn[1],@dir[1],@wild[1]);
  683. if (UnzipErr <> 0) and (UnzipErr <> 1) then
  684. begin
  685. if CreateLog then
  686. begin
  687. WriteLn (Log, 'Error ', UnzipErr, ' while unpacking!');
  688. Flush (Log);
  689. end;
  690. s:=GetZipErrorInfo(UnzipErr);
  691. { Str(UnzipErr,s);}
  692. st2:='';
  693. if UnzipErr=unzip_WriteErr then
  694. begin
  695. {$ifdef MAYBE_LFN}
  696. if not(locallfnsupport) then
  697. begin
  698. islfn:=false;
  699. fsplit(currentfile,p,n,e);
  700. if (length(n)>8) or (length(e)>4) or
  701. (pos('.',n)>0) or (upper(p+n+e)<>upper(currentfile)) then
  702. islfn:=true;
  703. if islfn then
  704. begin
  705. WriteLog ('Error while extracting ' +
  706. CurrentFile + ' because of missing LFN support,' +
  707. LineEnding + ' skipping rest of ZIP file.');
  708. messagebox('Error while extracting '+currentfile+
  709. #13#3'because of missing lfn support'+
  710. #13#3'skipping rest of zipfile '+s
  711. ,nil,mferror+mfOkButton);
  712. again:=false;
  713. exit;
  714. end;
  715. end
  716. else
  717. {$endif MAYBE_LFN}
  718. st2:=' Disk full?';
  719. end;
  720. if CreateLog then
  721. WriteLog ('Error (' + S + ') while extracting.' + ST2);
  722. if messagebox('Error (' + S + ') while extracting.'+st2+#13+
  723. #13#3'Try again?',nil,mferror+mfyesbutton+mfnobutton)=cmYes then
  724. again:=true
  725. else
  726. errorhalt;
  727. end;
  728. until not again;
  729. end;
  730. {*****************************************************************************
  731. TEndDialog
  732. *****************************************************************************}
  733. constructor tenddialog.init;
  734. var
  735. R : TRect;
  736. P : PStaticText;
  737. Control : PButton;
  738. YB: word;
  739. {$IFNDEF UNIX}
  740. i : longint;
  741. S: string;
  742. WPath: boolean;
  743. MixedCasePath: boolean;
  744. {$ENDIF}
  745. {$IFDEF OS2}
  746. ErrPath: array [0..259] of char;
  747. Handle: longint;
  748. WLibPath: boolean;
  749. const
  750. EMXName: array [1..4] of char = 'EMX'#0;
  751. BFD2EName: array [1..6] of char = 'BFD2E'#0;
  752. {$ENDIF}
  753. begin
  754. if haside then
  755. YB := 15
  756. else
  757. YB := 14;
  758. {$IFNDEF UNIX}
  759. s:='';
  760. for i:=1 to cfg.packs do
  761. if cfg.pack[i].binsub<>'' then
  762. begin
  763. if s<>'' then
  764. s:=s+';';
  765. S := s+Data.BasePath + Cfg.pack[i].BinSub;
  766. end;
  767. if Pos (Upper (S), Upper (GetEnv ('PATH'))) = 0 then
  768. begin
  769. WPath := true;
  770. Inc (YB, 3);
  771. end
  772. else
  773. WPath := false;
  774. { look if path is set as Path,
  775. this leads to problems for mingw32 make PM }
  776. MixedCasePath:=false;
  777. for i:=1 to EnvCount do
  778. begin
  779. if Pos('PATH=',Upper(EnvStr(i)))=1 then
  780. if Pos('PATH=',EnvStr(i))<>1 then
  781. Begin
  782. MixedCasePath:=true;
  783. Inc(YB, 2);
  784. End;
  785. end;
  786. {$IFDEF OS2}
  787. if DosLoadModule (@ErrPath, SizeOf (ErrPath), @EMXName, Handle) = 0 then
  788. begin
  789. WLibPath := false;
  790. DosFreeModule (Handle);
  791. if DosLoadModule (@ErrPath, SizeOf (ErrPath), @BFD2EName, Handle) = 0 then
  792. begin
  793. WLibPath := false;
  794. DosFreeModule (Handle);
  795. end
  796. else
  797. begin
  798. WLibPath := true;
  799. Inc (YB, 2);
  800. end;
  801. end
  802. else
  803. begin
  804. WLibPath := true;
  805. Inc (YB, 2);
  806. end;
  807. {$ENDIF}
  808. {$ENDIF}
  809. R.Assign(6, 6, 74, YB);
  810. inherited init(r,'Installation successful.');
  811. Options:=Options or ofCentered;
  812. {$IFNDEF UNIX}
  813. if WPath then
  814. begin
  815. R.Assign(2, 3, 64, 5);
  816. P:=new(pstatictext,init(r,'Extend your PATH variable with '''+S+''''));
  817. insert(P);
  818. end;
  819. {$IFDEF OS2}
  820. if WLibPath then
  821. begin
  822. if WPath then
  823. S := 'and your LIBPATH with ''' + S
  824. else
  825. S := 'Extend your LIBPATH with ''' + S;
  826. System.Delete (S, Length (S) - 6, 7);
  827. S := S + 'dll''';
  828. R.Assign (2, YB - 15, 64, YB - 13);
  829. P := New (PStaticText, Init (R, S));
  830. Insert (P);
  831. end;
  832. {$ELSE OS2}
  833. if MixedCasePath then
  834. begin
  835. R.Assign(2, 5, 64, 6);
  836. P:=new(pstatictext,init(r,'You need to use setpath.bat file if you want to use Makefiles'));
  837. insert(P);
  838. end;
  839. {$ENDIF OS2}
  840. {$ENDIF}
  841. R.Assign(2, YB - 13, 64, YB - 12);
  842. P:=new(pstatictext,init(r,'To compile files enter ''fpc [file]'''));
  843. insert(P);
  844. if haside then
  845. begin
  846. R.Assign(2, YB - 12, 64, YB - 10);
  847. P:=new(pstatictext,init(r,'To start the IDE (Integrated Development Environment) type ''fp'' at a command line prompt'));
  848. insert(P);
  849. end;
  850. R.Assign (29, YB - 9, 39, YB - 7);
  851. Control := New (PButton, Init (R,'~O~k', cmOK, bfDefault));
  852. Insert (Control);
  853. end;
  854. {*****************************************************************************
  855. TInstallDialog
  856. *****************************************************************************}
  857. {$ifdef MAYBE_LFN}
  858. var
  859. islfn : boolean;
  860. procedure lfnreport( Retcode : longint;Rec : pReportRec );
  861. var
  862. p : pathstr;
  863. n : namestr;
  864. e : extstr;
  865. begin
  866. fsplit(strpas(rec^.Filename),p,n,e);
  867. if (length(n)>8) or (length(e)>4) or
  868. (pos('.',n)>0) or (upper(p+n+e)<>upper(strpas(rec^.Filename))) then
  869. islfn:=true;
  870. end;
  871. function haslfn(const zipfile : string) : boolean;
  872. var
  873. buf : array[0..255] of char;
  874. begin
  875. strpcopy(buf,zipfile);
  876. islfn:=false;
  877. {$ifdef FPC}
  878. ViewZip(buf,AllFiles,@lfnreport);
  879. {$else FPC}
  880. ViewZip(buf,AllFiles,lfnreport);
  881. {$endif FPC}
  882. haslfn:=islfn;
  883. end;
  884. {$endif MAYBE_LFN}
  885. var
  886. AllFilesPresent : boolean;
  887. procedure presentreport( Retcode : longint;Rec : pReportRec );
  888. var
  889. st : string;
  890. f : file;
  891. size,time : longint;
  892. p : pathstr;
  893. n : namestr;
  894. e : extstr;
  895. begin
  896. if not ALLFilesPresent then
  897. exit;
  898. st:=Data.BasePath+strpas(rec^.Filename);
  899. fsplit(st,p,n,e);
  900. if not file_exists(n+e,p) then
  901. AllFilesPresent:=false
  902. else
  903. begin
  904. Assign(f,st);
  905. Reset(f,1);
  906. if IOresult<>0 then
  907. begin
  908. ALLfilesPresent:=false;
  909. exit;
  910. end;
  911. GetFtime(f,time);
  912. size:=FileSize(f);
  913. if (rec^.Time<>time) or (rec^.size<>size) then
  914. ALLFilesPresent:=false;
  915. close(f);
  916. end;
  917. end;
  918. function AreAllFilesPresent(const zipfile : string) : boolean;
  919. var
  920. buf : array[0..255] of char;
  921. begin
  922. strpcopy(buf,zipfile);
  923. AllFilesPresent:=true;
  924. {$ifdef FPC}
  925. ViewZip(buf,AllFiles,@presentreport);
  926. {$else FPC}
  927. ViewZip(buf,AllFiles,presentreport);
  928. {$endif FPC}
  929. AreAllFilesPresent:=AllFilesPresent;
  930. end;
  931. constructor tinstalldialog.init;
  932. const
  933. width = 76;
  934. height = 20;
  935. x1 = (79-width) div 2;
  936. y1 = (23-height) div 2;
  937. x2 = x1+width;
  938. y2 = y1+height;
  939. var
  940. tabr,tabir,r : trect;
  941. packmask : array[1..maxpacks] of longint;
  942. enabmask : array[1..maxpacks] of longint;
  943. i,line,j : integer;
  944. items : array[1..maxpacks] of psitem;
  945. f : pview;
  946. found : boolean;
  947. okbut,cancelbut : pbutton;
  948. firstitem : array[1..maxpacks] of integer;
  949. packcbs : array[1..maxpacks] of pcheckboxes;
  950. packtd : ptabdef;
  951. labpath : plabel;
  952. ilpath : pspecialinputline;
  953. tab : ptab;
  954. titletext : pcoloredtext;
  955. labcfg : plabel;
  956. cfgcb : pcheckboxes;
  957. scrollbox: pscrollbox;
  958. sbr,sbsbr: trect;
  959. sbsb: pscrollbar;
  960. zipfile : string;
  961. begin
  962. f:=nil;
  963. { walk packages reverse and insert a newsitem for each, and set the mask }
  964. for j:=1 to cfg.packs do
  965. with cfg.pack[j] do
  966. begin
  967. firstitem[j]:=0;
  968. items[j]:=nil;
  969. packmask[j]:=0;
  970. enabmask[j]:=0;
  971. for i:=packages downto 1 do
  972. begin
  973. zipfile:='';
  974. if file_exists(package[i].zip,startpath) then
  975. zipfile:=startpath+DirSep+package[i].zip
  976. else if file_exists(package[i].zipshort,startpath) then
  977. begin
  978. zipfile:=startpath+DirSep+package[i].zipshort;
  979. { update package to replace the full zipname with the short name }
  980. package[i].zip:=package[i].zipshort;
  981. end;
  982. if zipfile<>'' then
  983. begin
  984. { get diskspace required }
  985. package[i].diskspace:=diskspaceN(zipfile);
  986. {$ifdef MAYBE_LFN}
  987. if not(locallfnsupport) then
  988. begin
  989. if not(haslfn(zipfile)) then
  990. begin
  991. items[j]:=newsitem(package[i].name+diskspacestr(package[i].diskspace),items[j]);
  992. packmask[j]:=packmask[j] or packagemask(i);
  993. enabmask[j]:=enabmask[j] or packagemask(i);
  994. firstitem[j]:=i-1;
  995. WriteLog ('Checking lfn usage for ' + zipfile + ' ... no lfn');
  996. end
  997. else
  998. begin
  999. items[j]:=newsitem(package[i].name+' (requires LFN support)',items[j]);
  1000. enabmask[j]:=enabmask[j] or packagemask(i);
  1001. firstitem[j]:=i-1;
  1002. WriteLog ('Checking lfn usage for ' + zipfile + ' ... uses lfn');
  1003. end;
  1004. end
  1005. else
  1006. {$endif MAYBE_LFN}
  1007. begin
  1008. items[j]:=newsitem(package[i].name+diskspacestr(package[i].diskspace)
  1009. {$ifdef DEBUG}
  1010. +' ('+dotstr(i)+')'
  1011. {$endif DEBUG}
  1012. ,items[j]);
  1013. packmask[j]:=packmask[j] or packagemask(i);
  1014. enabmask[j]:=enabmask[j] or packagemask(i);
  1015. firstitem[j]:=i-1;
  1016. end;
  1017. end
  1018. else
  1019. items[j]:=newsitem(package[i].name
  1020. {$ifdef DEBUG}
  1021. +' ('+dotstr(i)+')'
  1022. {$endif DEBUG}
  1023. ,items[j]);
  1024. end;
  1025. end;
  1026. { If no component found abort }
  1027. found:=false;
  1028. for j:=1 to cfg.packs do
  1029. if packmask[j]<>0 then
  1030. found:=true;
  1031. if not found then
  1032. begin
  1033. messagebox('No components found to install, aborting.',nil,mferror+mfokbutton);
  1034. if CreateLog then
  1035. WriteLog ('No components found to install, aborting.');
  1036. errorhalt;
  1037. end;
  1038. r.assign(x1,y1,x2,y2);
  1039. inherited init(r,'');
  1040. Options:=Options or ofCentered;
  1041. GetExtent(R);
  1042. R.Grow(-2,-1);
  1043. Dec(R.B.Y,2);
  1044. TabR.Copy(R);
  1045. TabIR.Copy(R);
  1046. TabIR.Grow(-2,-2);
  1047. TabIR.Move(-2,0);
  1048. {-------- General Sheets ----------}
  1049. R.Copy(TabIR);
  1050. r.move(0,1);
  1051. r.b.x:=r.a.x+40;
  1052. r.b.y:=r.a.y+1;
  1053. new(titletext,init(r,cfg.title,$71));
  1054. r.move(0,2);
  1055. r.b.x:=r.a.x+40;
  1056. new(labpath,init(r,'~B~ase path',f));
  1057. r.move(0,1);
  1058. r.b.x:=r.a.x+40;
  1059. r.b.y:=r.a.y+1;
  1060. new(ilpath,init(r,high(DirStr)));
  1061. r.move(0,2);
  1062. r.b.x:=r.a.x+40;
  1063. new(labcfg,init(r,'Con~f~ig',f));
  1064. r.move(0,1);
  1065. r.b.x:=r.a.x+40;
  1066. r.b.y:=r.a.y+1;
  1067. new(cfgcb,init(r,newsitem('create fpc.cfg',nil)));
  1068. data.cfgval:=1;
  1069. {-------- Pack Sheets ----------}
  1070. for j:=1 to cfg.packs do
  1071. begin
  1072. R.Copy(TabIR);
  1073. if R.A.Y+cfg.pack[j].packages>R.B.Y then
  1074. R.B.Y:=R.A.Y+cfg.pack[j].packages;
  1075. new(packcbs[j],init(r,items[j]));
  1076. if data.packmask[j]=high(sw_word) then
  1077. data.packmask[j]:=packmask[j];
  1078. packcbs[j]^.enablemask:={$ifdef DEV}$7fffffff{$else}enabmask[j]{$endif};
  1079. packcbs[j]^.sel:=firstitem[j];
  1080. end;
  1081. {--------- Main ---------}
  1082. packtd:=nil;
  1083. sbr.assign(1,3,tabr.b.x-tabr.a.x-3,tabr.b.y-tabr.a.y-1);
  1084. for j:=cfg.packs downto 1 do
  1085. begin
  1086. if (sbr.b.y-sbr.a.y)<cfg.pack[j].packages then
  1087. begin
  1088. sbsbr.assign(sbr.b.x,sbr.a.y,sbr.b.x+1,sbr.b.y);
  1089. sbsb:=CreateIdScrollBar (sbsbr.a.x, sbsbr.a.y,sbsbr.b.y-sbsbr.a.y,j,false);
  1090. sbsb^.SetRange(0,cfg.pack[j].packages-(sbsbr.b.y-sbsbr.a.y)-1);
  1091. sbsb^.SetStep(5,1);
  1092. //New(sbsb, init(sbsbr));
  1093. end
  1094. else
  1095. sbsb:=nil;
  1096. New(ScrollBox, Init(sbr, nil, sbsb));
  1097. PackCbs[j]^.MoveTo(0,0);
  1098. ScrollBox^.Insert(PackCbs[j]);
  1099. packtd:=NewTabDef(
  1100. cfg.pack[j].name,ScrollBox,
  1101. NewTabItem(sbsb,
  1102. NewTabItem(ScrollBox,
  1103. nil)),
  1104. packtd);
  1105. end;
  1106. New(Tab, Init(TabR,
  1107. NewTabDef('~G~eneral',IlPath,
  1108. NewTabItem(TitleText,
  1109. NewTabItem(LabPath,
  1110. NewTabItem(ILPath,
  1111. NewTabItem(LabCfg,
  1112. NewTabItem(CfgCB,
  1113. nil))))),
  1114. packtd)
  1115. ));
  1116. Tab^.GrowMode:=0;
  1117. Insert(Tab);
  1118. line:=tabr.b.y;
  1119. r.assign((width div 2)-18,line,(width div 2)-4,line+2);
  1120. new(okbut,init(r,'~C~ontinue',cmok,bfdefault));
  1121. Insert(OkBut);
  1122. r.assign((width div 2)+4,line,(width div 2)+14,line+2);
  1123. new(cancelbut,init(r,'~Q~uit',cmcancel,bfnormal));
  1124. Insert(CancelBut);
  1125. Tab^.Select;
  1126. end;
  1127. procedure tinstalldialog.handleevent(var event : tevent);
  1128. begin
  1129. if event.what=evcommand then
  1130. if event.command=cmquit then
  1131. begin
  1132. putevent(event);
  1133. event.command:=cmCancel;
  1134. end;
  1135. inherited handleevent(event);
  1136. end;
  1137. {*****************************************************************************
  1138. TSpecialInputLine
  1139. *****************************************************************************}
  1140. { this should use AreAllFilesPresent if the base dir is changed...
  1141. but what if the installer has already choosen which files he wants ... }
  1142. procedure TSpecialInputLine.GetData(var Rec);
  1143. begin
  1144. inherited GetData(Rec);
  1145. end;
  1146. {*****************************************************************************
  1147. TApp
  1148. *****************************************************************************}
  1149. const
  1150. cmstart = 1000;
  1151. procedure tapp.do_installdialog;
  1152. var
  1153. p : pinstalldialog;
  1154. p3 : penddialog;
  1155. r : trect;
  1156. result,
  1157. c : word;
  1158. i,j : longint;
  1159. found : boolean;
  1160. {$ifndef Unix}
  1161. DSize,Space,ASpace : int64;
  1162. S: DirStr;
  1163. {$endif}
  1164. procedure doconfigwrite;
  1165. var
  1166. i : longint;
  1167. begin
  1168. for i:=1 to cfg.packs do
  1169. begin
  1170. if cfg.pack[i].defcfgfile<>'' then
  1171. writedefcfg(data.basepath+cfg.pack[i].binsub+DirSep+cfg.pack[i].defcfgfile,cfg.defcfg,cfg.defcfgs,cfg.pack[i].targetname);
  1172. if cfg.pack[i].setpathfile<>'' then
  1173. writedefcfg(data.basepath+cfg.pack[i].binsub+DirSep+cfg.pack[i].setpathfile,cfg.defsetpath,cfg.defsetpaths,cfg.pack[i].targetname);
  1174. end;
  1175. if haside then
  1176. begin
  1177. for i:=1 to cfg.packs do
  1178. if cfg.pack[i].defidecfgfile<>'' then
  1179. writedefcfg(data.basepath+cfg.pack[i].binsub+DirSep+cfg.pack[i].defidecfgfile,cfg.defidecfg,cfg.defidecfgs,cfg.pack[i].targetname);
  1180. for i:=1 to cfg.packs do
  1181. if cfg.pack[i].defideinifile<>'' then
  1182. writedefcfg(data.basepath+cfg.pack[i].binsub+DirSep+cfg.pack[i].defideinifile,cfg.defideini,cfg.defideinis,cfg.pack[i].targetname);
  1183. if hashtmlhelp then
  1184. writehlpindex(data.basepath+DirSep+cfg.DocSub+DirSep+cfg.helpidx);
  1185. end;
  1186. end;
  1187. begin
  1188. data.basepath:=cfg.basepath;
  1189. data.cfgval:=0;
  1190. for j:=1 to cfg.packs do
  1191. data.packmask[j]:=high(sw_word);
  1192. repeat
  1193. { select components }
  1194. p:=new(pinstalldialog,init);
  1195. c:=executedialog(p,@data);
  1196. if (c=cmok) then
  1197. begin
  1198. if Data.BasePath = '' then
  1199. messagebox('Please, choose the directory for installation first.',nil,mferror+mfokbutton)
  1200. else
  1201. begin
  1202. Data.BasePath := FExpand (Data.BasePath);
  1203. if Data.BasePath [Length (Data.BasePath)] = DirSep then
  1204. Dec (Data.BasePath [0]);
  1205. found:=false;
  1206. for j:=1 to cfg.packs do
  1207. if data.packmask[j]>0 then
  1208. found:=true;
  1209. if found then
  1210. begin
  1211. {$IFNDEF UNIX}
  1212. { TH - check the available disk space here }
  1213. DSize := 0;
  1214. for j:=1 to cfg.packs do
  1215. with cfg.pack[j] do
  1216. begin
  1217. for i:=1 to packages do
  1218. begin
  1219. if data.packmask[j] and packagemask(i)<>0 then
  1220. begin
  1221. ASpace := package[i].diskspace;
  1222. if ASpace = -1 then
  1223. begin
  1224. MessageBox ('File ' + package[i].zip +
  1225. ' is probably corrupted!', nil,
  1226. mferror + mfokbutton);
  1227. WriteLog ('File ' + package[i].zip +
  1228. ' is probably corrupted!');
  1229. end
  1230. else Inc (DSize, ASpace);
  1231. end;
  1232. end;
  1233. end;
  1234. WriteLog ('Diskspace needed: ' + DotStr (DSize) + ' Kb');
  1235. S := Data.BasePath;
  1236. Space := DiskFree (byte (Upcase(S [1])) - 64);
  1237. { -1 means that the drive is invalid }
  1238. if Space=-1 then
  1239. begin
  1240. WriteLog ('The drive ' + S [1] + ': is not valid');
  1241. if messagebox('The drive '+S[1]+': is not valid. Do you ' +
  1242. 'want to change the installation path?',nil,
  1243. mferror+mfyesbutton+mfnobutton) = cmYes then
  1244. Continue;
  1245. Space:=0;
  1246. end;
  1247. Space := Space shr 10;
  1248. WriteLog ('Free space on drive ' + S [1] + ': ' +
  1249. DotStr (Space) + ' Kb');
  1250. if Space < DSize then
  1251. S := 'is not '
  1252. else
  1253. S := '';
  1254. if (Space < DSize + 500) then
  1255. begin
  1256. if S = '' then
  1257. S := 'might not be ';
  1258. if messagebox('There ' + S + 'enough space on the target ' +
  1259. 'drive for all the selected components. Do you ' +
  1260. 'want to change the installation path?',nil,
  1261. mferror+mfyesbutton+mfnobutton) = cmYes then
  1262. Continue;
  1263. end;
  1264. {$ENDIF}
  1265. if createinstalldir(data.basepath) then
  1266. break;
  1267. end
  1268. else
  1269. begin
  1270. { maybe only config }
  1271. if (data.cfgval and 1)<>0 then
  1272. begin
  1273. result:=messagebox('No components selected.'#13#13'Create a configfile ?',nil,
  1274. mfinformation+mfyesbutton+mfnobutton);
  1275. if (result=cmYes) and createinstalldir(data.basepath) then
  1276. doconfigwrite;
  1277. exit;
  1278. end
  1279. else
  1280. begin
  1281. result:=messagebox('No components selected.'#13#13'Abort installation?',nil,
  1282. mferror+mfyesbutton+mfnobutton);
  1283. if result=cmYes then
  1284. exit;
  1285. end;
  1286. end;
  1287. end;
  1288. end
  1289. else
  1290. exit;
  1291. until false;
  1292. { extract packages }
  1293. for j:=1 to cfg.packs do
  1294. with cfg.pack[j] do
  1295. begin
  1296. r.assign(10,7,70,18);
  1297. UnzDlg:=new(punzipdialog,init(r,'Extracting Packages'));
  1298. desktop^.insert(UnzDlg);
  1299. for i:=1 to packages do
  1300. begin
  1301. if data.packmask[j] and packagemask(i)<>0 then
  1302. begin
  1303. UnzDlg^.do_unzip(package[i].zip,data.basepath);
  1304. { gather some information about the installed files }
  1305. if copy(package[i].zip,1,3)='ide' then
  1306. haside:=true;
  1307. if copy(package[i].zip,1,7)='doc-htm' then
  1308. begin
  1309. hashtmlhelp:=true;
  1310. { correct the fpctoc file name if .html files are used }
  1311. if package[i].zip='doc-html.zip' then
  1312. if copy(cfg.helpidx,length(cfg.helpidx)-3,4)='.htm' then
  1313. cfg.helpidx:=cfg.helpidx+'l';
  1314. end;
  1315. end;
  1316. end;
  1317. desktop^.delete(UnzDlg);
  1318. dispose(UnzDlg,done);
  1319. end;
  1320. { write config }
  1321. if (data.cfgval and 1)<>0 then
  1322. doconfigwrite;
  1323. { show end message }
  1324. p3:=new(penddialog,init);
  1325. executedialog(p3,nil);
  1326. end;
  1327. procedure tapp.readcfg(const fn:string);
  1328. var
  1329. t : text;
  1330. i,j,k,
  1331. line : longint;
  1332. item,
  1333. s,hs : string;
  1334. params : array[0..0] of pointer;
  1335. {$ifndef FPC}
  1336. procedure readln(var t:text;var s:string);
  1337. var
  1338. c : char;
  1339. i : longint;
  1340. begin
  1341. c:=#0;
  1342. i:=0;
  1343. while (not eof(t)) and (c<>#10) do
  1344. begin
  1345. read(t,c);
  1346. if c<>#10 then
  1347. begin
  1348. inc(i);
  1349. s[i]:=c;
  1350. end;
  1351. end;
  1352. if (i>0) and (s[i]=#13) then
  1353. dec(i);
  1354. s[0]:=chr(i);
  1355. end;
  1356. {$endif}
  1357. begin
  1358. assign(t,StartPath + DirSep + fn);
  1359. {$I-}
  1360. reset(t);
  1361. {$I+}
  1362. if ioresult<>0 then
  1363. begin
  1364. StartPath := GetProgDir;
  1365. assign(t,StartPath + DirSep + fn);
  1366. {$I-}
  1367. reset(t);
  1368. {$I+}
  1369. if ioresult<>0 then
  1370. begin
  1371. params[0]:=@fn;
  1372. messagebox('File %s not found!',@params,mferror+mfokbutton);
  1373. WriteLog ('File "' + fn + '" not found!');
  1374. errorhalt;
  1375. end;
  1376. end;
  1377. line:=0;
  1378. while not eof(t) do
  1379. begin
  1380. readln(t,s);
  1381. inc(line);
  1382. if (s<>'') and not(s[1] in ['#',';']) then
  1383. begin
  1384. i:=pos('=',s);
  1385. if i>0 then
  1386. begin
  1387. item:=upper(Copy(s,1,i-1));
  1388. system.delete(s,1,i);
  1389. if item='VERSION' then
  1390. cfg.version:=s
  1391. else
  1392. if item='TITLE' then
  1393. cfg.title:=s
  1394. else
  1395. if item='BASEPATH' then
  1396. cfg.basepath:=s
  1397. else
  1398. if item='HELPIDX' then
  1399. cfg.helpidx:=s
  1400. else
  1401. if item='DOCSUB' then
  1402. cfg.docsub:=s
  1403. else
  1404. if item='DEFAULTCFG' then
  1405. begin
  1406. repeat
  1407. readln(t,s);
  1408. if upper(s)='ENDCFG' then
  1409. break;
  1410. if cfg.defcfgs<maxdefcfgs then
  1411. begin
  1412. inc(cfg.defcfgs);
  1413. cfg.defcfg[cfg.defcfgs]:=newstr(s);
  1414. end;
  1415. until false;
  1416. end
  1417. else
  1418. if item='DEFAULTIDECFG' then
  1419. begin
  1420. repeat
  1421. readln(t,s);
  1422. if upper(s)='ENDCFG' then
  1423. break;
  1424. if cfg.defidecfgs<maxdefcfgs then
  1425. begin
  1426. inc(cfg.defidecfgs);
  1427. cfg.defidecfg[cfg.defidecfgs]:=newstr(s);
  1428. end;
  1429. until false;
  1430. end
  1431. else
  1432. if item='DEFAULTSETPATH' then
  1433. begin
  1434. repeat
  1435. readln(t,s);
  1436. if upper(s)='ENDCFG' then
  1437. break;
  1438. if cfg.defsetpaths<maxdefcfgs then
  1439. begin
  1440. inc(cfg.defsetpaths);
  1441. cfg.defsetpath[cfg.defsetpaths]:=newstr(s);
  1442. end;
  1443. until false;
  1444. end
  1445. else
  1446. if item='DEFAULTIDEINI' then
  1447. begin
  1448. repeat
  1449. readln(t,s);
  1450. if upper(s)='ENDCFG' then
  1451. break;
  1452. if cfg.defideinis<maxdefcfgs then
  1453. begin
  1454. inc(cfg.defideinis);
  1455. cfg.defideini[cfg.defideinis]:=newstr(s);
  1456. end;
  1457. until false;
  1458. end
  1459. else
  1460. if item='PACK' then
  1461. begin
  1462. inc(cfg.packs);
  1463. if cfg.packs>maxpacks then
  1464. begin
  1465. MessageBox ('Too many packs!', nil,
  1466. mfError + mfOkButton);
  1467. if CreateLog then
  1468. begin
  1469. WriteLn (Log, 'Too many packs');
  1470. close(log);
  1471. end;
  1472. halt(1);
  1473. end;
  1474. cfg.pack[cfg.packs].name:=s;
  1475. end
  1476. else
  1477. if item='CFGFILE' then
  1478. begin
  1479. if cfg.packs=0 then
  1480. begin
  1481. MessageBox ('No pack set found!', nil,
  1482. mfError + mfOkButton);
  1483. if CreateLog then
  1484. begin
  1485. WriteLn (Log, 'No pack set');
  1486. close(Log);
  1487. end;
  1488. halt(1);
  1489. end;
  1490. cfg.pack[cfg.packs].defcfgfile:=s
  1491. end
  1492. else
  1493. if item='IDECFGFILE' then
  1494. begin
  1495. if cfg.packs=0 then
  1496. begin
  1497. MessageBox ('No pack set found!', nil,
  1498. mfError + mfOkButton);
  1499. if CreateLog then
  1500. begin
  1501. WriteLn (Log, 'No pack set');
  1502. Close(Log);
  1503. end;
  1504. halt(1);
  1505. end;
  1506. cfg.pack[cfg.packs].defidecfgfile:=s
  1507. end
  1508. else
  1509. if item='SETPATHFILE' then
  1510. begin
  1511. if cfg.packs=0 then
  1512. begin
  1513. MessageBox ('No pack set found!', nil,
  1514. mfError + mfOkButton);
  1515. if CreateLog then
  1516. begin
  1517. WriteLn (Log, 'No pack set');
  1518. close(Log);
  1519. end;
  1520. halt(1);
  1521. end;
  1522. cfg.pack[cfg.packs].setpathfile:=s
  1523. end
  1524. else
  1525. if item='IDEINIFILE' then
  1526. begin
  1527. if cfg.packs=0 then
  1528. begin
  1529. MessageBox ('No pack set found!', nil,
  1530. mfError + mfOkButton);
  1531. if CreateLog then
  1532. begin
  1533. WriteLn (Log, 'No pack set');
  1534. Close(Log);
  1535. end;
  1536. halt(1);
  1537. end;
  1538. cfg.pack[cfg.packs].defideinifile:=s
  1539. end
  1540. else
  1541. if item='PPC386' then
  1542. begin
  1543. if cfg.packs=0 then
  1544. begin
  1545. MessageBox ('No pack set found!', nil,
  1546. mfError + mfOkButton);
  1547. if CreateLog then
  1548. begin
  1549. WriteLn (Log, 'No pack set');
  1550. Close(Log);
  1551. end;
  1552. halt(1);
  1553. end;
  1554. cfg.pack[cfg.packs].ppc386:=s;
  1555. end
  1556. else
  1557. if item='BINSUB' then
  1558. begin
  1559. if cfg.packs=0 then
  1560. begin
  1561. MessageBox ('No pack set found!', nil,
  1562. mfError + mfOkButton);
  1563. if CreateLog then
  1564. begin
  1565. WriteLn (Log, 'No pack set');
  1566. Close(Log);
  1567. end;
  1568. halt(1);
  1569. end;
  1570. cfg.pack[cfg.packs].binsub:=s;
  1571. end
  1572. {else: Obsolete PM }
  1573. { if item='FILECHECK' then
  1574. begin
  1575. if cfg.packs=0 then
  1576. begin
  1577. MessageBox ('No pack set found!', nil,
  1578. mfError + mfOkButton);
  1579. if CreateLog then
  1580. WriteLn (Log, 'No pack set');
  1581. halt(1);
  1582. end;
  1583. cfg.pack[cfg.packs].filechk:=s;
  1584. end }
  1585. else
  1586. if item='TARGETNAME' then
  1587. begin
  1588. if cfg.packs=0 then
  1589. begin
  1590. MessageBox ('No pack set found!', nil,
  1591. mfError + mfOkButton);
  1592. if CreateLog then
  1593. begin
  1594. WriteLn (Log, 'No pack set');
  1595. Close(Log);
  1596. end;
  1597. halt(1);
  1598. end;
  1599. cfg.pack[cfg.packs].targetname:=s;
  1600. end
  1601. else
  1602. if item='PACKAGE' then
  1603. begin
  1604. if cfg.packs=0 then
  1605. begin
  1606. MessageBox ('No pack set found!', nil,
  1607. mfError + mfOkButton);
  1608. if CreateLog then
  1609. begin
  1610. WriteLn (Log, 'No pack set');
  1611. Close(Log);
  1612. end;
  1613. halt(1);
  1614. end;
  1615. with cfg.pack[cfg.packs] do
  1616. begin
  1617. j:=pos(',',s);
  1618. if (j>0) and (packages<maxpackages) then
  1619. begin
  1620. inc(packages);
  1621. hs:=copy(s,1,j-1);
  1622. k:=pos('[',hs);
  1623. if (k>0) then
  1624. begin
  1625. package[packages].zip:=Copy(hs,1,k-1);
  1626. package[packages].zipshort:=Copy(hs,k+1,length(hs)-k-1);
  1627. end
  1628. else
  1629. package[packages].zip:=hs;
  1630. package[packages].name:=copy(s,j+1,255);
  1631. end;
  1632. package[packages].diskspace:=-1;
  1633. end;
  1634. end
  1635. end;
  1636. end;
  1637. end;
  1638. close(t);
  1639. end;
  1640. procedure tapp.checkavailpack;
  1641. var
  1642. i, j : longint;
  1643. one_found : boolean;
  1644. begin
  1645. { check the packages }
  1646. j:=0;
  1647. while (j<cfg.packs) do
  1648. begin
  1649. inc(j);
  1650. one_found:=false;
  1651. {if cfg.pack[j].filechk<>'' then}
  1652. for i:=1 to cfg.pack[j].packages do
  1653. begin
  1654. if file_exists(cfg.pack[j].package[i].zip,startpath) or
  1655. file_exists(cfg.pack[j].package[i].zipshort,startpath) then
  1656. begin
  1657. one_found:=true;
  1658. break;
  1659. end;
  1660. end;
  1661. if not one_found then
  1662. begin
  1663. { remove the package }
  1664. move(cfg.pack[j+1],cfg.pack[j],sizeof(tpack)*(cfg.packs-j));
  1665. dec(cfg.packs);
  1666. dec(j);
  1667. end;
  1668. end;
  1669. end;
  1670. procedure tapp.initmenubar;
  1671. var
  1672. r : trect;
  1673. begin
  1674. getextent(r);
  1675. r.b.y:=r.a.y+1;
  1676. menubar:=new(pmenubar,init(r,newmenu(
  1677. newsubmenu('Free Pascal Installer',hcnocontext,newmenu(nil
  1678. ),
  1679. nil))));
  1680. end;
  1681. procedure tapp.initstatusline;
  1682. var
  1683. R: TRect;
  1684. begin
  1685. GetExtent(R);
  1686. R.A.Y := R.B.Y - 1;
  1687. //R.B.X := R.B.X - 2;
  1688. New(StatusLine,
  1689. Init(R,
  1690. NewStatusDef(0, $EFFF,nil,nil
  1691. )
  1692. )
  1693. );
  1694. end;
  1695. procedure tapp.handleevent(var event : tevent);
  1696. begin
  1697. inherited handleevent(event);
  1698. if event.what=evcommand then
  1699. if event.command=cmstart then
  1700. begin
  1701. clearevent(event);
  1702. do_installdialog;
  1703. if successfull then
  1704. begin
  1705. event.what:=evcommand;
  1706. event.command:=cmquit;
  1707. handleevent(event);
  1708. end;
  1709. end;
  1710. end;
  1711. {$IFDEF DOSSTUB}
  1712. function CheckOS2: boolean;
  1713. var
  1714. OwnName: PathStr;
  1715. OwnDir: DirStr;
  1716. Name: NameStr;
  1717. Ext: ExtStr;
  1718. DosV, W: word;
  1719. P: PChar;
  1720. const
  1721. Title: string [15] = 'FPC Installer'#0;
  1722. RunBlock: TRunBlock = (Length: $32;
  1723. Dependent: 0;
  1724. Background: 0;
  1725. TraceLevel: 0;
  1726. PrgTitle: @Title [1];
  1727. PrgName: nil;
  1728. Args: nil;
  1729. TermQ: 0;
  1730. Environment: nil;
  1731. Inheritance: 0;
  1732. SesType: 2;
  1733. Icon: nil;
  1734. PgmHandle: 0;
  1735. PgmControl: 2;
  1736. Column: 0;
  1737. Row: 0;
  1738. Width: 80;
  1739. Height: 25);
  1740. begin
  1741. CheckOS2 := false;
  1742. asm
  1743. mov ah, 30h
  1744. int 21h
  1745. xchg ah, al
  1746. mov DosV, ax
  1747. mov ax, 4010h
  1748. int 2Fh
  1749. cmp ax, 4010h
  1750. jnz @0
  1751. xor bx, bx
  1752. @0:
  1753. mov W, bx
  1754. end;
  1755. if DosV > 3 shl 8 then
  1756. begin
  1757. OwnName := FExpand (ParamStr (0));
  1758. FSplit (OwnName, OwnDir, Name, Ext);
  1759. if (DosV >= 20 shl 8 + 10) and (W >= 20 shl 8 + 10) then
  1760. (* OS/2 version 2.1 or later running (double-checked) *)
  1761. begin
  1762. OwnName [Succ (byte (OwnName [0]))] := #0;
  1763. RunBlock.PrgName := @OwnName [1];
  1764. P := Ptr (PrefixSeg, $80);
  1765. if PByte (P)^ <> 0 then
  1766. begin
  1767. Inc (P);
  1768. RunBlock.Args := Ptr (PrefixSeg, $81);
  1769. end;
  1770. asm
  1771. mov ax, 6400h
  1772. mov bx, 0025h
  1773. mov cx, 636Ch
  1774. mov si, offset RunBlock
  1775. int 21h
  1776. jc @0
  1777. mov DosV, 0
  1778. @0:
  1779. end;
  1780. CheckOS2 := DosV = 0;
  1781. end;
  1782. end;
  1783. end;
  1784. {$ENDIF}
  1785. procedure usagescreen;
  1786. begin
  1787. writeln('FPC Installer ',installerversion,' ',installercopyright);
  1788. writeln('Command line options:');
  1789. writeln(' -l create log file');
  1790. {$ifdef MAYBE_LFN}
  1791. writeln(' --nolfn force installation with short file names');
  1792. {$endif MAYBE_LFN}
  1793. writeln;
  1794. writeln(' -h displays this help');
  1795. end;
  1796. var
  1797. OldExit: pointer;
  1798. procedure NewExit;
  1799. begin
  1800. ExitProc := OldExit;
  1801. if CreateLog then
  1802. begin
  1803. {$I-}
  1804. if ErrorAddr <> nil then
  1805. begin
  1806. WriteLn (Log, 'Installer crashed with RTE ', ExitCode);
  1807. Close (Log);
  1808. end
  1809. else
  1810. if ExitCode <> 0 then
  1811. begin
  1812. WriteLn (Log, 'Installer ended with non-zero exit code ', ExitCode);
  1813. Close (Log);
  1814. end
  1815. {$I+}
  1816. end;
  1817. end;
  1818. var
  1819. i : longint;
  1820. { vm : tvideomode;}
  1821. begin
  1822. OldExit := ExitProc;
  1823. ExitProc := @NewExit;
  1824. { register objects for help streaming }
  1825. RegisterWHTMLScan;
  1826. {$IFDEF OS2}
  1827. { TH - no error boxes if checking an inaccessible disk etc. }
  1828. {$IFDEF FPC}
  1829. DosCalls.DosError (0);
  1830. {$ELSE FPC}
  1831. {$IFDEF VirtualPascal}
  1832. OS2Base.DosError (ferr_DisableHardErr);
  1833. {$ELSE VirtualPascal}
  1834. BseDos.DosError (0);
  1835. {$ENDIF VirtualPascal}
  1836. {$ENDIF FPC}
  1837. {$ENDIF}
  1838. {$IFDEF DOSSTUB}
  1839. if CheckOS2 then Halt;
  1840. {$ENDIF}
  1841. createlog:=false;
  1842. {$ifdef MAYBE_LFN}
  1843. locallfnsupport:=system.lfnsupport;
  1844. {$endif MAYBE_LFN}
  1845. for i:=1 to paramcount do
  1846. begin
  1847. if paramstr(i)='-l' then
  1848. createlog:=true
  1849. {$ifdef MAYBE_LFN}
  1850. else if paramstr(i)='--nolfn' then
  1851. begin
  1852. locallfnsupport:=false;
  1853. {$ifdef GO32V2}
  1854. { lfnsupport is a const in win32 RTL }
  1855. system.lfnsupport:=locallfnsupport;
  1856. {$endif GO32V2}
  1857. end
  1858. {$endif MAYBE_LFN}
  1859. else if paramstr(i)='-h' then
  1860. begin
  1861. usagescreen;
  1862. halt(0);
  1863. end
  1864. else
  1865. begin
  1866. usagescreen;
  1867. halt(1);
  1868. end;
  1869. end;
  1870. if createlog then
  1871. begin
  1872. assign(log,'install.log');
  1873. rewrite(log);
  1874. {$ifdef MAYBE_LFN}
  1875. if not(locallfnsupport) then
  1876. WriteLog ('OS doesn''t have LFN support');
  1877. {$endif}
  1878. end;
  1879. getdir(0,startpath);
  1880. successfull:=false;
  1881. fillchar(cfg, SizeOf(cfg), 0);
  1882. fillchar(data, SizeOf(data), 0);
  1883. installapp.init;
  1884. { vm.col:=80;
  1885. vm.row:=25;
  1886. vm.color:=true;
  1887. installapp.SetScreenVideoMode(vm);
  1888. }
  1889. FSplit (FExpand (ParamStr (0)), DStr, CfgName, EStr);
  1890. installapp.readcfg(CfgName + CfgExt);
  1891. installapp.checkavailpack;
  1892. { installapp.readcfg(startpath+dirsep+cfgfile);}
  1893. {$ifdef GO32V2}
  1894. if not(lfnsupport) then
  1895. MessageBox('The operating system doesn''t support LFN (long file names),'+
  1896. ' so some packages will get shorten filenames when installed',nil,mfinformation or mfokbutton);
  1897. {$endif}
  1898. installapp.do_installdialog;
  1899. installapp.done;
  1900. if createlog then
  1901. close(log);
  1902. end.