install.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1993-98 by Florian Klaempfl
  5. member of the Free Pascal development team
  6. This is the install program for the DOS version of Free Pascal
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. program install;
  14. {$DEFINE FV}
  15. {$IFDEF OS2}
  16. {$UNDEF FV}
  17. {$ENDIF}
  18. uses
  19. {$IFDEF OS2}
  20. {$IFDEF FPC}
  21. DosCalls,
  22. {$ELSE FPC}
  23. {$IFDEF VirtualPascal}
  24. OS2Base,
  25. {$ELSE VirtualPascal}
  26. BseDos,
  27. {$ENDIF VirtualPascal}
  28. {$ENDIF FPC}
  29. {$ENDIF OS2}
  30. strings,dos,objects,drivers,
  31. {$IFDEF FV}
  32. commands,
  33. {$ENDIF}
  34. app,dialogs,views,menus,msgbox,
  35. unzip,ziptypes;
  36. const
  37. maxpackages=20;
  38. maxdefcfgs=200;
  39. cfgfile='install.dat';
  40. type
  41. tpackage=record
  42. name : string[60];
  43. zip : string[12];
  44. end;
  45. cfgrec=record
  46. title : string[80];
  47. version : string[20];
  48. basepath : DirStr;
  49. binsub : string[12];
  50. ppc386 : string[12];
  51. packages : longint;
  52. package : array[1..maxpackages] of tpackage;
  53. defcfgfile : string[12];
  54. defcfgs : longint;
  55. defcfg : array[1..maxdefcfgs] of pstring;
  56. end;
  57. datarec=packed record
  58. basepath : DirStr;
  59. mask : word;
  60. end;
  61. punzipdialog=^tunzipdialog;
  62. tunzipdialog=object(tdialog)
  63. filetext : pstatictext;
  64. constructor Init(var Bounds: TRect; ATitle: TTitleStr);
  65. procedure do_unzip(s,topath:string);
  66. end;
  67. penddialog = ^tenddialog;
  68. tenddialog = object(tdialog)
  69. constructor init;
  70. end;
  71. pinstalldialog = ^tinstalldialog;
  72. tinstalldialog = object(tdialog)
  73. constructor init;
  74. end;
  75. tapp = object(tapplication)
  76. procedure initmenubar;virtual;
  77. procedure handleevent(var event : tevent);virtual;
  78. procedure do_installdialog;
  79. procedure readcfg(const fn:string);
  80. end;
  81. var
  82. installapp : tapp;
  83. startpath : string;
  84. successfull : boolean;
  85. cfg : cfgrec;
  86. data : datarec;
  87. {*****************************************************************************
  88. Helpers
  89. *****************************************************************************}
  90. procedure errorhalt;
  91. begin
  92. installapp.done;
  93. halt(1);
  94. end;
  95. function packagemask(i:longint):longint;
  96. begin
  97. packagemask:=1 shl (i-1);
  98. end;
  99. function upper(const s : string):string;
  100. var
  101. i : integer;
  102. begin
  103. for i:=1 to length(s) do
  104. if s[i] in ['a'..'z'] then
  105. upper[i]:=chr(ord(s[i])-32)
  106. else
  107. upper[i]:=s[i];
  108. upper[0]:=s[0];
  109. end;
  110. function lower(const s : string):string;
  111. var
  112. i : integer;
  113. begin
  114. for i:=1 to length(s) do
  115. if s[i] in ['A'..'Z'] then
  116. lower[i]:=chr(ord(s[i])+32)
  117. else
  118. lower[i]:=s[i];
  119. lower[0]:=s[0];
  120. end;
  121. procedure Replace(var s:string;const s1,s2:string);
  122. var
  123. i : longint;
  124. begin
  125. repeat
  126. i:=pos(s1,s);
  127. if i>0 then
  128. begin
  129. Delete(s,i,length(s1));
  130. Insert(s2,s,i);
  131. end;
  132. until i=0;
  133. end;
  134. function file_exists(const f : string;const path : string) : boolean;
  135. begin
  136. file_exists:=fsearch(f,path)<>'';
  137. end;
  138. function diskspace(const zipfile : string) : string;
  139. var
  140. compressed,uncompressed : longint;
  141. s : string;
  142. begin
  143. s:=zipfile+#0;
  144. uncompressed:=UnzipSize(@s[1],compressed);
  145. uncompressed:=uncompressed shr 10;
  146. str(uncompressed,s);
  147. diskspace:=' ('+s+' Kb)';
  148. end;
  149. function createdir(s : string) : boolean;
  150. var
  151. start,
  152. s1 : string;
  153. i,result : longint;
  154. err : boolean;
  155. dir : searchrec;
  156. params : array[0..0] of pointer;
  157. begin
  158. if s[length(s)]=DirSep then
  159. dec(s[0]);
  160. FindFirst(s,AnyFile,dir);
  161. if doserror=0 then
  162. begin
  163. result:=messagebox('The installation directory exists already. '+
  164. 'Do you want to enter a new installation directory ?',nil,
  165. mferror+mfyesbutton+mfnobutton);
  166. createdir:=(result=cmNo);
  167. exit;
  168. end;
  169. err:=false;
  170. {$I-}
  171. getdir(0,start);
  172. {$ifndef linux}
  173. if (s[2]=':') and (s[3]=DirSep) then
  174. begin
  175. chdir(Copy(s,1,3));
  176. Delete(S,1,3);
  177. end;
  178. {$endif}
  179. repeat
  180. i:=Pos(DirSep,s);
  181. if i=0 then
  182. i:=255;
  183. s1:=Copy(s,1,i-1);
  184. Delete(s,1,i);
  185. ChDir(s1);
  186. if ioresult<>0 then
  187. begin
  188. mkdir(s1);
  189. chdir(s1);
  190. if ioresult<>0 then
  191. begin
  192. err:=true;
  193. break;
  194. end;
  195. end;
  196. until s='';
  197. chdir(start);
  198. {$I+}
  199. if err then
  200. begin
  201. params[0]:=@s;
  202. messagebox('The installation directory %s couldn''t be created',
  203. @params,mferror+mfokbutton);
  204. createdir:=false;
  205. exit;
  206. end;
  207. {$ifndef TP}
  208. FindClose (dir);
  209. {$endif}
  210. createdir:=true;
  211. end;
  212. {*****************************************************************************
  213. Writing of ppc386.cfg
  214. *****************************************************************************}
  215. procedure writedefcfg(const fn:string);
  216. var
  217. t : text;
  218. i : longint;
  219. s : string;
  220. dir : searchrec;
  221. params : array[0..0] of pointer;
  222. begin
  223. findfirst(fn,$ff,dir);
  224. if doserror=0 then
  225. begin
  226. params[0]:=@fn;
  227. MessageBox(#3'Default config not written.'#13#3'%s'#13#3'already exists',@params,mfinformation+mfokbutton);
  228. exit;
  229. end;
  230. assign(t,fn);
  231. {$I-}
  232. rewrite(t);
  233. {$I+}
  234. if ioresult<>0 then
  235. begin
  236. params[0]:=@fn;
  237. MessageBox(#3'Default config not written.'#13#3'%s'#13#3'couldn''t be created',@params,mfinformation+mfokbutton);
  238. exit;
  239. end;
  240. for i:=1to cfg.defcfgs do
  241. if assigned(cfg.defcfg[i]) then
  242. begin
  243. s:=cfg.defcfg[i]^;
  244. Replace(s,'$1',data.basepath);
  245. writeln(t,s);
  246. end
  247. else
  248. writeln(t,'');
  249. close(t);
  250. end;
  251. {*****************************************************************************
  252. TUnZipDialog
  253. *****************************************************************************}
  254. constructor tunzipdialog.Init(var Bounds: TRect; ATitle: TTitleStr);
  255. var
  256. r : trect;
  257. begin
  258. inherited init(bounds,atitle);
  259. R.Assign(11, 4, 38, 5);
  260. filetext:=new(pstatictext,init(r,'File: '));
  261. insert(filetext);
  262. end;
  263. procedure tunzipdialog.do_unzip(s,topath : string);
  264. var
  265. fn,dir,wild : string;
  266. begin
  267. Disposestr(filetext^.text);
  268. filetext^.Text:=NewStr('File: '+s);
  269. filetext^.drawview;
  270. if not(file_exists(s,startpath)) then
  271. begin
  272. messagebox('File: '+s+' missed for the selected installation. '+
  273. 'Installation doesn''t becomes complete',nil,mferror+mfokbutton);
  274. errorhalt;
  275. end;
  276. fn:=startpath+DirSep+s+#0;
  277. dir:=topath+#0;
  278. wild:=AllFiles + #0;
  279. FileUnzipEx(@fn[1],@dir[1],@wild[1]);
  280. if doserror<>0 then
  281. begin
  282. messagebox('Error when extracting. Disk full?',nil,mferror+mfokbutton);
  283. errorhalt;
  284. end;
  285. end;
  286. {*****************************************************************************
  287. TEndDialog
  288. *****************************************************************************}
  289. constructor tenddialog.init;
  290. var
  291. R : TRect;
  292. P : PStaticText;
  293. Control : PButton;
  294. begin
  295. R.Assign(6, 6, 74, 16);
  296. inherited init(r,'Installation Successfull');
  297. R.Assign(2, 2, 64, 5);
  298. P:=new(pstatictext,init(r,'Extend your PATH variable with '''+data.basepath+cfg.binsub+''''));
  299. insert(P);
  300. R.Assign(2, 4, 64, 5);
  301. P:=new(pstatictext,init(r,'To compile files enter '''+cfg.ppc386+' [file]'''));
  302. insert(P);
  303. R.Assign (29, 7, 39, 9);
  304. Control := New (PButton, Init (R,'~O~k', cmOK, bfDefault));
  305. Insert (Control);
  306. end;
  307. {*****************************************************************************
  308. TInstallDialog
  309. *****************************************************************************}
  310. constructor tinstalldialog.init;
  311. var
  312. r : trect;
  313. mask_components : longint;
  314. i,line : integer;
  315. items : psitem;
  316. p,f : pview;
  317. const
  318. width = 76;
  319. height = 20;
  320. x1 = (79-width) div 2;
  321. y1 = (23-height) div 2;
  322. x2 = x1+width;
  323. y2 = y1+height;
  324. begin
  325. r.assign(x1,y1,x2,y2);
  326. inherited init(r,cfg.title+' Installation');
  327. line:=2;
  328. r.assign(3,line+1,28,line+2);
  329. f:=new(pinputline,init(r,high(DirStr)));
  330. insert(f);
  331. r.assign(3,line,8,line+1);
  332. insert(new(plabel,init(r,'~P~ath',f)));
  333. { walk packages reverse and insert a newsitem for each, and set the mask }
  334. items:=nil;
  335. mask_components:=0;
  336. for i:=cfg.packages downto 1 do
  337. begin
  338. if file_exists(cfg.package[i].zip,startpath) then
  339. begin
  340. items:=newsitem(cfg.package[i].name+diskspace(startpath+DirSep+cfg.package[i].zip),items);
  341. mask_components:=mask_components or packagemask(i);
  342. end
  343. else
  344. begin
  345. items:=newsitem(cfg.package[i].name,items);
  346. end;
  347. end;
  348. { If no component found abort }
  349. if mask_components=0 then
  350. begin
  351. messagebox('No components found to install, aborting.',nil,mferror+mfokbutton);
  352. errorhalt;
  353. end;
  354. inc(line,3);
  355. r.assign(3,line+1,width-3,line+cfg.packages+1);
  356. p:=new(pcheckboxes,init(r,items));
  357. r.assign(3,line,14,line+1);
  358. insert(new(plabel,init(r,'~C~omponents',p)));
  359. pcluster(p)^.enablemask:=mask_components;
  360. insert(p);
  361. inc(line,cfg.packages+2);
  362. r.assign((width div 2)-14,line,(width div 2)-4,line+2);
  363. insert(new(pbutton,init(r,'~O~k',cmok,bfdefault)));
  364. r.assign((width div 2)+4,line,(width div 2)+14,line+2);
  365. insert(new(pbutton,init(r,'~C~ancel',cmcancel,bfnormal)));
  366. f^.select;
  367. end;
  368. {*****************************************************************************
  369. TApp
  370. *****************************************************************************}
  371. const
  372. cmstart = 1000;
  373. procedure tapp.do_installdialog;
  374. var
  375. p : pinstalldialog;
  376. p2 : punzipdialog;
  377. p3 : penddialog;
  378. r : trect;
  379. result,
  380. c : word;
  381. i : longint;
  382. begin
  383. data.basepath:=cfg.basepath;
  384. data.mask:=0;
  385. repeat
  386. { select components }
  387. p:=new(pinstalldialog,init);
  388. c:=executedialog(p,@data);
  389. if (c=cmok) then
  390. begin
  391. if (data.mask>0) then
  392. begin
  393. if createdir(data.basepath) then
  394. break;
  395. end
  396. else
  397. begin
  398. result:=messagebox('No components selected.'#13#13'Abort installation?',nil,
  399. mferror+mfyesbutton+mfnobutton);
  400. if result=cmYes then
  401. exit;
  402. end;
  403. end
  404. else
  405. exit;
  406. until false;
  407. { extract }
  408. r.assign(20,7,60,16);
  409. p2:=new(punzipdialog,init(r,'Extracting files'));
  410. desktop^.insert(p2);
  411. for i:=1to cfg.packages do
  412. begin
  413. if data.mask and packagemask(i)<>0 then
  414. p2^.do_unzip(cfg.package[i].zip,data.basepath);
  415. end;
  416. desktop^.delete(p2);
  417. dispose(p2,done);
  418. { write config }
  419. writedefcfg(data.basepath+cfg.binsub+DirSep+cfg.defcfgfile);
  420. { show end message }
  421. p3:=new(penddialog,init);
  422. executedialog(p3,nil);
  423. end;
  424. procedure tapp.readcfg(const fn:string);
  425. var
  426. t : text;
  427. i,j,
  428. line : longint;
  429. item,
  430. s : string;
  431. params : array[0..0] of pointer;
  432. {$ifndef FPC}
  433. procedure readln(var t:text;var s:string);
  434. var
  435. c : char;
  436. i : longint;
  437. begin
  438. c:=#0;
  439. i:=0;
  440. while (not eof(t)) and (c<>#10) do
  441. begin
  442. read(t,c);
  443. if c<>#10 then
  444. begin
  445. inc(i);
  446. s[i]:=c;
  447. end;
  448. end;
  449. if (i>0) and (s[i]=#13) then
  450. dec(i);
  451. s[0]:=chr(i);
  452. end;
  453. {$endif}
  454. begin
  455. assign(t,fn);
  456. {$I-}
  457. reset(t);
  458. {$I+}
  459. if ioresult<>0 then
  460. begin
  461. params[0]:=@fn;
  462. messagebox('File %s not found!',@params,mferror+mfokbutton);
  463. errorhalt;
  464. end;
  465. line:=0;
  466. while not eof(t) do
  467. begin
  468. readln(t,s);
  469. inc(line);
  470. if (s<>'') and not(s[1] in ['#',';']) then
  471. begin
  472. i:=pos('=',s);
  473. if i>0 then
  474. begin
  475. item:=upper(Copy(s,1,i-1));
  476. system.delete(s,1,i);
  477. if item='VERSION' then
  478. cfg.version:=s
  479. else
  480. if item='TITLE' then
  481. cfg.title:=s
  482. else
  483. if item='BASEPATH' then
  484. cfg.basepath:=s
  485. else
  486. if item='PPC386' then
  487. cfg.ppc386:=s
  488. else
  489. if item='BINSUB' then
  490. cfg.binsub:=s
  491. else
  492. if item='CFGFILE' then
  493. cfg.defcfgfile:=s
  494. else
  495. if item='DEFAULTCFG' then
  496. begin
  497. repeat
  498. readln(t,s);
  499. if upper(s)='ENDCFG' then
  500. break;
  501. if cfg.defcfgs<maxdefcfgs then
  502. begin
  503. inc(cfg.defcfgs);
  504. cfg.defcfg[cfg.defcfgs]:=newstr(s);
  505. end;
  506. until false;
  507. end
  508. else
  509. if item='PACKAGE' then
  510. begin
  511. j:=pos(',',s);
  512. if (j>0) and (cfg.packages<maxpackages) then
  513. begin
  514. inc(cfg.packages);
  515. cfg.package[cfg.packages].zip:=copy(s,1,j-1);
  516. cfg.package[cfg.packages].name:=copy(s,j+1,255);
  517. end;
  518. end;
  519. end;
  520. end;
  521. end;
  522. close(t);
  523. end;
  524. procedure tapp.initmenubar;
  525. var
  526. r : trect;
  527. begin
  528. getextent(r);
  529. r.b.y:=r.a.y+1;
  530. menubar:=new(pmenubar,init(r,newmenu(
  531. newsubmenu('~F~ree Pascal '+cfg.version,hcnocontext,newmenu(nil
  532. ),
  533. nil))));
  534. end;
  535. procedure tapp.handleevent(var event : tevent);
  536. begin
  537. inherited handleevent(event);
  538. if event.what=evcommand then
  539. if event.command=cmstart then
  540. begin
  541. clearevent(event);
  542. do_installdialog;
  543. if successfull then
  544. begin
  545. event.what:=evcommand;
  546. event.command:=cmquit;
  547. handleevent(event);
  548. end;
  549. end;
  550. end;
  551. begin
  552. {$IFDEF OS2}
  553. {$IFDEF FPC}
  554. DosCalls.DosError (0);
  555. {$ELSE FPC}
  556. {$IFDEF VirtualPascal}
  557. OS2Base.DosError (ferr_DisableHardErr);
  558. {$ELSE VirtualPascal}
  559. BseDos.DosError (0);
  560. {$ENDIF VirtualPascal}
  561. {$ENDIF FPC}
  562. {$ENDIF}
  563. getdir(0,startpath);
  564. successfull:=false;
  565. fillchar(cfg, SizeOf(cfg), 0);
  566. fillchar(data, SizeOf(data), 0);
  567. installapp.init;
  568. installapp.readcfg(cfgfile);
  569. installapp.do_installdialog;
  570. installapp.done;
  571. end.
  572. {
  573. $Log$
  574. Revision 1.14 1998-12-22 22:47:34 peter
  575. * updates for OS2
  576. * small fixes
  577. Revision 1.13 1998/12/21 13:11:39 peter
  578. * updates for 0.99.10
  579. Revision 1.12 1998/12/16 00:25:34 peter
  580. * updated for 0.99.10
  581. * new end dialogbox
  582. Revision 1.11 1998/11/01 20:32:25 peter
  583. * packed record
  584. Revision 1.10 1998/10/25 23:38:35 peter
  585. * removed warnings
  586. Revision 1.9 1998/10/23 16:57:40 pierre
  587. * compiles without -So option
  588. * the main dialog init was buggy !!
  589. Revision 1.8 1998/09/22 21:10:31 jonas
  590. * initialize cfg and data with 0 at startup
  591. Revision 1.7 1998/09/16 16:46:37 peter
  592. + updates
  593. Revision 1.6 1998/09/15 13:11:14 pierre
  594. small fix to cleanup if no package
  595. Revision 1.5 1998/09/15 12:06:06 peter
  596. * install updated to support w32 and dos and config file
  597. Revision 1.4 1998/09/10 10:50:49 florian
  598. * DOS install program updated
  599. Revision 1.3 1998/09/09 13:39:58 peter
  600. + internal unzip
  601. * dialog is showed automaticly
  602. Revision 1.2 1998/04/07 22:47:57 florian
  603. + version/release/patch numbers as string added
  604. }