install.pas 15 KB

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