install.pas 15 KB

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