dos.pas 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260
  1. {****************************************************************************
  2. $Id$
  3. Free Pascal Runtime-Library
  4. DOS unit for OS/2
  5. Copyright (c) 1997,1999-2000 by Daniel Mantione,
  6. member of the Free Pascal development team
  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. unit dos;
  14. {$ASMMODE ATT}
  15. {***************************************************************************}
  16. interface
  17. {***************************************************************************}
  18. {$PACKRECORDS 1}
  19. uses strings;
  20. const {Bit masks for CPU flags.}
  21. fcarry = $0001;
  22. fparity = $0004;
  23. fauxiliary = $0010;
  24. fzero = $0040;
  25. fsign = $0080;
  26. foverflow = $0800;
  27. {Bit masks for file attributes.}
  28. readonly = $01;
  29. hidden = $02;
  30. sysfile = $04;
  31. volumeid = $08;
  32. directory = $10;
  33. archive = $20;
  34. anyfile = $3F;
  35. fmclosed = $D7B0;
  36. fminput = $D7B1;
  37. fmoutput = $D7B2;
  38. fminout = $D7B3;
  39. type {Some string types:}
  40. comstr=string; {Filenames can be long in OS/2.}
  41. pathstr=string; {String for pathnames.}
  42. dirstr=string; {String for a directory}
  43. namestr=string; {String for a filename.}
  44. extstr=string[40]; {String for an extension. Can be 253
  45. characters long, in theory, but let's
  46. say fourty will be enough.}
  47. {Search record which is used by findfirst and findnext:}
  48. searchrec=record
  49. case boolean of
  50. false: (handle:longint; {Used in os_OS2 mode}
  51. fill2:array[1..21-SizeOf(longint)] of byte;
  52. attr2:byte;
  53. time2:longint;
  54. size2:longint;
  55. name2:string); {Filenames can be long in OS/2!}
  56. true: (fill:array[1..21] of byte;
  57. attr:byte;
  58. time:longint;
  59. size:longint;
  60. name:string); {Filenames can be long in OS/2!}
  61. end;
  62. {$i filerec.inc}
  63. {$i textrec.inc}
  64. {Data structure for the registers needed by msdos and intr:}
  65. registers=record
  66. case i:integer of
  67. 0:(ax,f1,bx,f2,cx,f3,dx,f4,bp,f5,si,f51,di,f6,ds,f7,es,
  68. f8,flags,fs,gs:word);
  69. 1:(al,ah,f9,f10,bl,bh,f11,f12,cl,ch,f13,f14,dl,dh:byte);
  70. 2:(eax,ebx,ecx,edx,ebp,esi,edi:longint);
  71. end;
  72. {Record for date and time:}
  73. datetime=record
  74. year,month,day,hour,min,sec:word;
  75. end;
  76. {Flags for the exec procedure:
  77. Starting the program:
  78. efwait: Wait until program terminates.
  79. efno_wait: Don't wait until the program terminates. Does not work
  80. in dos, as DOS cannot multitask.
  81. efoverlay: Terminate this program, then execute the requested
  82. program. WARNING: Exit-procedures are not called!
  83. efdebug: Debug program. Details are unknown.
  84. efsession: Do not execute as child of this program. Use a seperate
  85. session instead.
  86. efdetach: Detached. Function unknown. Info wanted!
  87. efpm: Run as presentation manager program.
  88. Determining the window state of the program:
  89. efdefault: Run the pm program in it's default situation.
  90. efminimize: Run the pm program minimized.
  91. efmaximize: Run the pm program maximized.
  92. effullscreen: Run the non-pm program fullscreen.
  93. efwindowed: Run the non-pm program in a window.
  94. Other options are not implemented defined because lack of
  95. knowledge about what they do.}
  96. type execrunflags=(efwait,efno_wait,efoverlay,efdebug,efsession,
  97. efdetach,efpm);
  98. execwinflags=(efdefault,efminimize,efmaximize,effullscreen,
  99. efwindowed);
  100. const
  101. (* For compatibility with VP/2, used for runflags in Exec procedure. *)
  102. ExecFlags: cardinal = ord (efwait);
  103. var doserror:integer;
  104. dosexitcode:word;
  105. procedure getdate(var year,month,day,dayofweek:word);
  106. procedure gettime(var hour,minute,second,sec100:word);
  107. function dosversion:word;
  108. procedure setdate(year,month,day:word);
  109. procedure settime(hour,minute,second,sec100:word);
  110. procedure getcbreak(var breakvalue:boolean);
  111. procedure setcbreak(breakvalue:boolean);
  112. procedure getverify(var verify:boolean);
  113. procedure setverify(verify : boolean);
  114. {$IFDEF INT64}
  115. function DiskFree (Drive: byte) : int64;
  116. function DiskSize (Drive: byte) : int64;
  117. {$ELSE}
  118. function DiskFree (Drive: byte) : longint;
  119. function DiskSize (Drive: byte) : longint;
  120. {$ENDIF}
  121. procedure findfirst(const path:pathstr;attr:word;var f:searchRec);
  122. procedure findnext(var f:searchRec);
  123. procedure findclose(var f:searchRec);
  124. {Is a dummy:}
  125. procedure swapvectors;
  126. {Not supported:
  127. procedure getintvec(intno:byte;var vector:pointer);
  128. procedure setintvec(intno:byte;vector:pointer);
  129. procedure keep(exitcode:word);
  130. }
  131. procedure msdos(var regs:registers);
  132. procedure intr(intno : byte;var regs:registers);
  133. procedure getfattr(var f;var attr:word);
  134. procedure setfattr(var f;attr:word);
  135. function fsearch(path:pathstr;dirlist:string):pathstr;
  136. procedure getftime(var f;var time:longint);
  137. procedure setftime(var f;time:longint);
  138. procedure packtime (var d:datetime; var time:longint);
  139. procedure unpacktime (time:longint; var d:datetime);
  140. function fexpand(const path:pathstr):pathstr;
  141. procedure fsplit(path:pathstr;var dir:dirstr;var name:namestr;
  142. var ext:extstr);
  143. procedure exec(const path:pathstr;const comline:comstr);
  144. function exec(path:pathstr;runflags:execrunflags;winflags:execwinflags;
  145. const comline:comstr):longint;
  146. function envcount:longint;
  147. function envstr(index:longint) : string;
  148. function getenv(const envvar:string): string;
  149. implementation
  150. uses DosCalls;
  151. var LastSR: SearchRec;
  152. type TBA = array [1..SizeOf (SearchRec)] of byte;
  153. PBA = ^TBA;
  154. {Import syscall to call it nicely from assembler procedures.}
  155. procedure syscall;external name '___SYSCALL';
  156. function fsearch(path:pathstr;dirlist:string):pathstr;
  157. var i,p1:longint;
  158. newdir:pathstr;
  159. {$ASMMODE INTEL}
  160. function CheckFile (FN: ShortString):boolean; assembler;
  161. asm
  162. mov ax, 4300h
  163. mov edx, FN
  164. inc edx
  165. call syscall
  166. mov ax, 0
  167. jc @LCFstop
  168. test cx, 18h
  169. jnz @LCFstop
  170. inc ax
  171. @LCFstop:
  172. end;
  173. {$ASMMODE ATT}
  174. begin
  175. { check if the file specified exists }
  176. if CheckFile (Path + #0) then
  177. FSearch := Path
  178. else
  179. begin
  180. {No wildcards allowed in these things:}
  181. if (pos('?',path)<>0) or (pos('*',path)<>0) then
  182. fsearch:=''
  183. else
  184. begin
  185. { allow slash as backslash }
  186. for i:=1 to length(dirlist) do
  187. if dirlist[i]='/' then dirlist[i]:='\';
  188. repeat
  189. p1:=pos(';',dirlist);
  190. if p1<>0 then
  191. begin
  192. newdir:=copy(dirlist,1,p1-1);
  193. delete(dirlist,1,p1);
  194. end
  195. else
  196. begin
  197. newdir:=dirlist;
  198. dirlist:='';
  199. end;
  200. if (newdir<>'') and
  201. not (newdir[length(newdir)] in ['\',':']) then
  202. newdir:=newdir+'\';
  203. if CheckFile (NewDir + Path + #0) then
  204. NewDir := NewDir + Path
  205. else
  206. NewDir := '';
  207. until (DirList = '') or (NewDir <> '');
  208. FSearch := NewDir;
  209. end;
  210. end;
  211. end;
  212. procedure getftime(var f;var time:longint);
  213. begin
  214. asm
  215. {Load handle}
  216. movl f,%ebx
  217. movw (%ebx),%bx
  218. {Get date}
  219. movw $0x5700,%ax
  220. call syscall
  221. shll $16,%edx
  222. movw %cx,%dx
  223. movl time,%ebx
  224. movl %edx,(%ebx)
  225. xorb %ah,%ah
  226. movw %ax,doserror
  227. end;
  228. end;
  229. procedure SetFTime (var F; Time: longint);
  230. var FStat: PFileStatus0;
  231. RC: longint;
  232. begin
  233. if os_mode = osOS2 then
  234. begin
  235. New (FStat);
  236. RC := DosQueryFileInfo (TextRec (F).Handle, ilStandard, FStat,
  237. SizeOf (FStat^));
  238. if RC = 0 then
  239. begin
  240. FStat^.DateLastAccess := Hi (Time);
  241. FStat^.DateLastWrite := Hi (Time);
  242. FStat^.TimeLastAccess := Lo (Time);
  243. FStat^.TimeLastWrite := Lo (Time);
  244. RC := DosSetFileInfo (TextRec (F).Handle, ilStandard,
  245. FStat, SizeOf (FStat^));
  246. end;
  247. Dispose (FStat);
  248. end
  249. else
  250. asm
  251. {Load handle}
  252. movl f,%ebx
  253. movw (%ebx),%bx
  254. movl time,%ecx
  255. shldl $16,%ecx,%edx
  256. {Set date}
  257. movw $0x5701,%ax
  258. call syscall
  259. xorb %ah,%ah
  260. movw %ax,doserror
  261. end;
  262. end;
  263. procedure msdos(var regs:registers);
  264. {Not recommended for EMX. Only works in DOS mode, not in OS/2 mode.}
  265. begin
  266. intr($21,regs);
  267. end;
  268. {$ASMMODE DIRECT}
  269. procedure intr(intno:byte;var regs:registers);
  270. {Not recommended for EMX. Only works in DOS mode, not in OS/2 mode.}
  271. begin
  272. asm
  273. .data
  274. int86:
  275. .byte 0xcd
  276. int86_vec:
  277. .byte 0x03
  278. jmp int86_retjmp
  279. .text
  280. movl 8(%ebp),%eax
  281. movb %al,int86_vec
  282. movl 10(%ebp),%eax
  283. {Do not use first int}
  284. incl %eax
  285. incl %eax
  286. movl 4(%eax),%ebx
  287. movl 8(%eax),%ecx
  288. movl 12(%eax),%edx
  289. movl 16(%eax),%ebp
  290. movl 20(%eax),%esi
  291. movl 24(%eax),%edi
  292. movl (%eax),%eax
  293. jmp int86
  294. int86_retjmp:
  295. pushf
  296. pushl %ebp
  297. pushl %eax
  298. movl %esp,%ebp
  299. {Calc EBP new}
  300. addl $12,%ebp
  301. movl 10(%ebp),%eax
  302. {Do not use first int}
  303. incl %eax
  304. incl %eax
  305. popl (%eax)
  306. movl %ebx,4(%eax)
  307. movl %ecx,8(%eax)
  308. movl %edx,12(%eax)
  309. {Restore EBP}
  310. popl %edx
  311. movl %edx,16(%eax)
  312. movl %esi,20(%eax)
  313. movl %edi,24(%eax)
  314. {Ignore ES and DS}
  315. popl %ebx {Flags.}
  316. movl %ebx,32(%eax)
  317. {FS and GS too}
  318. end;
  319. end;
  320. {$ASMMODE ATT}
  321. procedure exec(const path:pathstr;const comline:comstr);
  322. {Execute a program.}
  323. begin
  324. dosexitcode:=exec(path,execrunflags(ExecFlags),efdefault,comline);
  325. end;
  326. function exec(path:pathstr;runflags:execrunflags;winflags:execwinflags;
  327. const comline:comstr):longint;
  328. {Execute a program. More suitable for OS/2 than the exec above.}
  329. {512 bytes should be enough to contain the command-line.}
  330. type bytearray=array[0..8191] of byte;
  331. Pbytearray=^bytearray;
  332. execstruc=record
  333. argofs,envofs,nameofs:pointer;
  334. argseg,envseg,nameseg:word;
  335. numarg,sizearg,
  336. numenv,sizeenv:word;
  337. mode1,mode2:byte;
  338. end;
  339. var args:Pbytearray;
  340. env:Pbytearray;
  341. i,j:word;
  342. es:execstruc;
  343. esadr:pointer;
  344. d:dirstr;
  345. n:namestr;
  346. e:extstr;
  347. begin
  348. getmem(args,512);
  349. getmem(env,8192);
  350. j:=1;
  351. {Now setup the arguments. The first argument should be the program
  352. name without directory and extension.}
  353. fsplit(path,d,n,e);
  354. es.numarg:=1;
  355. args^[0]:=$80;
  356. for i:=1 to length(n) do
  357. begin
  358. args^[j]:=byte(n[i]);
  359. inc(j);
  360. end;
  361. args^[j]:=0;
  362. inc(j);
  363. {Now do the real arguments.}
  364. i:=1;
  365. while i<=length(comline) do
  366. begin
  367. if comline[i]<>' ' then
  368. begin
  369. {Commandline argument found. Copy it.}
  370. inc(es.numarg);
  371. args^[j]:=$80;
  372. inc(j);
  373. while (i<=length(comline)) and (comline[i]<>' ') do
  374. begin
  375. args^[j]:=byte(comline[i]);
  376. inc(j);
  377. inc(i);
  378. end;
  379. args^[j]:=0;
  380. inc(j);
  381. end;
  382. inc(i);
  383. end;
  384. args^[j]:=0;
  385. inc(j);
  386. {Commandline ready, now build the environment.
  387. Oh boy, I always had the opinion that executing a program under Dos
  388. was a hard job!}
  389. {$ASMMODE DIRECT}
  390. asm
  391. movl env,%edi {Setup destination pointer.}
  392. movl _envc,%ecx {Load number of arguments in edx.}
  393. movl _environ,%esi {Load env. strings.}
  394. xorl %edx,%edx {Count environment size.}
  395. exa1:
  396. lodsl {Load a Pchar.}
  397. xchgl %eax,%ebx
  398. exa2:
  399. movb (%ebx),%al {Load a byte.}
  400. incl %ebx {Point to next byte.}
  401. stosb {Store it.}
  402. incl %edx {Increase counter.}
  403. cmpb $0,%al {Ready ?.}
  404. jne exa2
  405. loop exa1 {Next argument.}
  406. stosb {Store an extra 0 to finish. (AL is now 0).}
  407. incl %edx
  408. movl %edx,(24)es {Store environment size.}
  409. end;
  410. {$ASMMODE ATT}
  411. {Environment ready, now set-up exec structure.}
  412. es.argofs:=args;
  413. es.envofs:=env;
  414. asm
  415. leal path,%esi
  416. lodsb
  417. movzbl %al,%eax
  418. addl %eax,%esi
  419. movb $0,(%esi)
  420. end;
  421. es.nameofs:=pointer(longint(@path)+1);
  422. asm
  423. movw %ss,es.argseg
  424. movw %ss,es.envseg
  425. movw %ss,es.nameseg
  426. end;
  427. es.sizearg:=j;
  428. es.numenv:=0;
  429. {Typecasting of sets in FPC is a bit hard.}
  430. es.mode1:=byte(runflags);
  431. es.mode2:=byte(winflags);
  432. {Now exec the program.}
  433. asm
  434. leal es,%edx
  435. mov $0x7f06,%ax
  436. call syscall
  437. xorl %edi,%edi
  438. jnc .Lexprg1
  439. xchgl %eax,%edi
  440. xorl %eax,%eax
  441. decl %eax
  442. .Lexprg1:
  443. movw %di,doserror
  444. movl %eax,__RESULT
  445. end;
  446. freemem(args,512);
  447. freemem(env,8192);
  448. {Phew! That's it. This was the most sophisticated procedure to call
  449. a system function I ever wrote!}
  450. end;
  451. function dosversion:word;assembler;
  452. {Returns DOS version in DOS and OS/2 version in OS/2}
  453. asm
  454. movb $0x30,%ah
  455. call syscall
  456. end;
  457. procedure GetDate (var Year, Month, Day, DayOfWeek: word);
  458. begin
  459. asm
  460. movb $0x2a, %ah
  461. call syscall
  462. xorb %ah, %ah
  463. movl DayOfWeek, %edi
  464. stosw
  465. movl Day, %edi
  466. movb %dl, %al
  467. stosw
  468. movl Month, %edi
  469. movb %dh, %al
  470. stosw
  471. movl Year, %edi
  472. xchgw %ecx, %eax
  473. stosw
  474. end;
  475. end;
  476. procedure SetDate (Year, Month, Day: word);
  477. var DT: TDateTime;
  478. begin
  479. if os_mode = osOS2 then
  480. begin
  481. DosGetDateTime (DT);
  482. DT.Year := Year;
  483. DT.Month := Month;
  484. DT.Day := Day;
  485. DosSetDateTime (DT);
  486. end
  487. else
  488. asm
  489. movw Year, %cx
  490. movb Month, %dh
  491. movb Day, %dl
  492. movb $0x2b, %ah
  493. call syscall
  494. (* SetDate isn't supposed to change DosError!!!
  495. xorb %ah,%ah
  496. movw %ax,doserror
  497. *)
  498. end;
  499. end;
  500. procedure GetTime (var Hour, Minute, Second, Sec100: word); assembler;
  501. asm
  502. movb $0x2c, %ah
  503. call syscall
  504. xorb %ah, %ah
  505. movl Sec100, %edi
  506. movb %dl, %al
  507. stosw
  508. movl Second, %edi
  509. movb %dh,%al
  510. stosw
  511. movl Minute, %edi
  512. movb %cl,%al
  513. stosw
  514. movl Hour, %edi
  515. movb %ch,%al
  516. stosw
  517. end;
  518. procedure SetTime (Hour, Minute, Second, Sec100: word);
  519. var DT: TDateTime;
  520. begin
  521. if os_mode = osOS2 then
  522. begin
  523. DosGetDateTime (DT);
  524. DT.Hour := Hour;
  525. DT.Minute := Minute;
  526. DT.Second := Second;
  527. DT.Sec100 := Sec100;
  528. DosSetDateTime (DT);
  529. end
  530. else
  531. asm
  532. movb Hour, %ch
  533. movb Minute ,%cl
  534. movb Second, %dh
  535. movb Sec100, %dl
  536. movb $0x2d, %ah
  537. call syscall
  538. (* SetTime isn't supposed to change DosError!!!
  539. xorb %ah, %ah
  540. movw %ax, DosError
  541. *)
  542. end;
  543. end;
  544. procedure getcbreak(var breakvalue:boolean);
  545. begin
  546. {! Do not use in OS/2. Also not recommended in DOS. Use
  547. signal handling instead.}
  548. asm
  549. movw $0x3300,%ax
  550. call syscall
  551. movl 8(%ebp),%eax
  552. movb %dl,(%eax)
  553. end;
  554. end;
  555. procedure setcbreak(breakvalue:boolean);
  556. begin
  557. {! Do not use in OS/2. Also not recommended in DOS. Use
  558. signal handling instead.}
  559. asm
  560. movb 8(%ebp),%dl
  561. movw $0x3301,%ax
  562. call syscall
  563. end;
  564. end;
  565. procedure getverify(var verify:boolean);
  566. begin
  567. {! Do not use in OS/2.}
  568. asm
  569. movb $0x54,%ah
  570. call syscall
  571. movl 8(%ebp),%edi
  572. stosb
  573. end;
  574. end;
  575. procedure setverify(verify:boolean);
  576. begin
  577. {! Do not use in OS/2.}
  578. asm
  579. movb 8(%ebp),%al
  580. movb $0x2e,%ah
  581. call syscall
  582. end;
  583. end;
  584. {$IFDEF INT64}
  585. function DiskFree (Drive: byte): int64;
  586. var FI: TFSinfo;
  587. RC: longint;
  588. begin
  589. if (os_mode = osDOS) or (os_mode = osDPMI) then
  590. {Function 36 is not supported in OS/2.}
  591. asm
  592. movb 8(%ebp),%dl
  593. movb $0x36,%ah
  594. call syscall
  595. cmpw $-1,%ax
  596. je .LDISKFREE1
  597. mulw %cx
  598. mulw %bx
  599. shll $16,%edx
  600. movw %ax,%dx
  601. xchgl %edx,%eax
  602. leave
  603. ret
  604. .LDISKFREE1:
  605. cltd
  606. leave
  607. ret
  608. end
  609. else
  610. {In OS/2, we use the filesystem information.}
  611. begin
  612. RC := DosQueryFSInfo (Drive, 1, FI, SizeOf (FI));
  613. if RC = 0 then
  614. DiskFree := int64 (FI.Free_Clusters) *
  615. int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
  616. else
  617. DiskFree := -1;
  618. end;
  619. end;
  620. function DiskSize (Drive: byte): int64;
  621. var FI: TFSinfo;
  622. RC: longint;
  623. begin
  624. if (os_mode = osDOS) or (os_mode = osDPMI) then
  625. {Function 36 is not supported in OS/2.}
  626. asm
  627. movb 8(%ebp),%dl
  628. movb $0x36,%ah
  629. call syscall
  630. movw %dx,%bx
  631. cmpw $-1,%ax
  632. je .LDISKSIZE1
  633. mulw %cx
  634. mulw %bx
  635. shll $16,%edx
  636. movw %ax,%dx
  637. xchgl %edx,%eax
  638. leave
  639. ret
  640. .LDISKSIZE1:
  641. cltd
  642. leave
  643. ret
  644. end
  645. else
  646. {In OS/2, we use the filesystem information.}
  647. begin
  648. RC := DosQueryFSinfo (Drive, 1, FI, SizeOf (FI));
  649. if RC = 0 then
  650. DiskSize := int64 (FI.Total_Clusters) *
  651. int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
  652. else
  653. DiskSize := -1;
  654. end;
  655. end;
  656. {$ELSE}
  657. function DiskFree (Drive: byte): longint;
  658. var FI: TFSinfo;
  659. RC: longint;
  660. begin
  661. if (os_mode = osDOS) or (os_mode = osDPMI) then
  662. {Function 36 is not supported in OS/2.}
  663. asm
  664. movb 8(%ebp),%dl
  665. movb $0x36,%ah
  666. call syscall
  667. cmpw $-1,%ax
  668. je .LDISKFREE1
  669. mulw %cx
  670. mulw %bx
  671. shll $16,%edx
  672. movw %ax,%dx
  673. xchgl %edx,%eax
  674. leave
  675. ret
  676. .LDISKFREE1:
  677. cltd
  678. leave
  679. ret
  680. end
  681. else
  682. {In OS/2, we use the filesystem information.}
  683. begin
  684. RC := DosQueryFSInfo (Drive, 1, FI, SizeOf (FI));
  685. if RC = 0 then
  686. DiskFree := FI.Free_Clusters *
  687. FI.Sectors_Per_Cluster * FI.Bytes_Per_Sector
  688. else
  689. DiskFree := -1;
  690. end;
  691. end;
  692. function DiskSize (Drive: byte): longint;
  693. var FI: TFSinfo;
  694. RC: longint;
  695. begin
  696. if (os_mode = osDOS) or (os_mode = osDPMI) then
  697. {Function 36 is not supported in OS/2.}
  698. asm
  699. movb 8(%ebp),%dl
  700. movb $0x36,%ah
  701. call syscall
  702. movw %dx,%bx
  703. cmpw $-1,%ax
  704. je .LDISKSIZE1
  705. mulw %cx
  706. mulw %bx
  707. shll $16,%edx
  708. movw %ax,%dx
  709. xchgl %edx,%eax
  710. leave
  711. ret
  712. .LDISKSIZE1:
  713. cltd
  714. leave
  715. ret
  716. end
  717. else
  718. {In OS/2, we use the filesystem information.}
  719. begin
  720. RC := DosQueryFSinfo (Drive, 1, FI, SizeOf (FI));
  721. if RC = 0 then
  722. DiskSize := FI.Total_Clusters *
  723. FI.Sectors_Per_Cluster * FI.Bytes_Per_Sector
  724. else
  725. DiskSize := -1;
  726. end;
  727. end;
  728. {$ENDIF}
  729. procedure SearchRec2DosSearchRec (var F: SearchRec);
  730. const NameSize = 255;
  731. var L, I: longint;
  732. begin
  733. if os_mode <> osOS2 then
  734. begin
  735. I := 1;
  736. while (I <= SizeOf (LastSR))
  737. and (PBA (@F)^ [I] = PBA (@LastSR)^ [I]) do Inc (I);
  738. { Raise "Invalid file handle" RTE if nested FindFirst calls were used. }
  739. if I <= SizeOf (LastSR) then RunError (6);
  740. l:=length(f.name);
  741. for i:=1 to namesize do
  742. f.name[i-1]:=f.name[i];
  743. f.name[l]:=#0;
  744. end;
  745. end;
  746. procedure DosSearchRec2SearchRec (var F: SearchRec; FStat: PFileFindBuf3);
  747. const NameSize=255;
  748. var L, I: longint;
  749. type TRec = record
  750. T, D: word;
  751. end;
  752. begin
  753. if os_mode = osOS2 then with F do
  754. begin
  755. Name := FStat^.Name;
  756. Size := FStat^.FileSize;
  757. Attr := FStat^.AttrFile;
  758. TRec (Time).T := FStat^.TimeLastWrite;
  759. TRec (Time).D := FStat^.DateLastWrite;
  760. end else
  761. begin
  762. for i:=0 to namesize do
  763. if f.name[i]=#0 then
  764. begin
  765. l:=i;
  766. break;
  767. end;
  768. for i:=namesize-1 downto 0 do
  769. f.name[i+1]:=f.name[i];
  770. f.name[0]:=char(l);
  771. Move (F, LastSR, SizeOf (LastSR));
  772. end;
  773. end;
  774. procedure FindFirst (const Path: PathStr; Attr: word; var F: SearchRec);
  775. procedure _findfirst(path:pchar;attr:word;var f:searchrec);
  776. begin
  777. asm
  778. movl 12(%esp),%edx
  779. movw 16(%esp),%cx
  780. {No need to set DTA in EMX. Just give a pointer in ESI.}
  781. movl 18(%ebp),%esi
  782. movb $0x4e,%ah
  783. call syscall
  784. jnc .LFF
  785. movw %ax,doserror
  786. .LFF:
  787. end;
  788. end;
  789. const
  790. FStat: PFileFindBuf3 = nil;
  791. var path0: array[0..255] of char;
  792. Count: longint;
  793. begin
  794. {No error.}
  795. DosError := 0;
  796. if os_mode = osOS2 then
  797. begin
  798. New (FStat);
  799. F.Handle := $FFFFFFFF;
  800. Count := 1;
  801. DosError := DosFindFirst (Path, F.Handle, Attr, FStat,
  802. SizeOf (FStat^), Count, ilStandard);
  803. if (DosError = 0) and (Count = 0) then DosError := 18;
  804. end else
  805. begin
  806. strPcopy(path0,path);
  807. _findfirst(path0,attr,f);
  808. end;
  809. DosSearchRec2SearchRec (F, FStat);
  810. if os_mode = osOS2 then Dispose (FStat);
  811. end;
  812. procedure FindNext (var F: SearchRec);
  813. var FStat: PFileFindBuf3;
  814. Count: longint;
  815. procedure _findnext(var f : searchrec);
  816. begin
  817. asm
  818. movl 12(%ebp),%esi
  819. movb $0x4f,%ah
  820. call syscall
  821. jnc .LFN
  822. movw %ax,doserror
  823. .LFN:
  824. end;
  825. end;
  826. begin
  827. {No error}
  828. DosError := 0;
  829. SearchRec2DosSearchRec (F);
  830. if os_mode = osOS2 then
  831. begin
  832. New (FStat);
  833. Count := 1;
  834. DosError := DosFindNext (F.Handle, FStat, SizeOf (FStat), Count);
  835. if (DosError = 0) and (Count = 0) then DosError := 18;
  836. end else _findnext (F);
  837. DosSearchRec2SearchRec (F, FStat);
  838. if os_mode = osOS2 then Dispose (FStat);
  839. end;
  840. procedure FindClose (var F: SearchRec);
  841. begin
  842. if os_mode = osOS2 then
  843. begin
  844. DosError := DosFindClose (F.Handle);
  845. end;
  846. end;
  847. procedure swapvectors;
  848. {For TP compatibility, this exists.}
  849. begin
  850. end;
  851. type PPchar=^Pchar;
  852. {$ASMMODE DIRECT}
  853. function envs:PPchar;assembler;
  854. asm
  855. movl _environ,%eax
  856. end ['EAX'];
  857. function envcount:longint;assembler;
  858. var hp : ppchar;
  859. asm
  860. movl _envc,%eax
  861. end ['EAX'];
  862. {$ASMMODE ATT}
  863. function envstr(index : longint) : string;
  864. var hp:PPchar;
  865. begin
  866. if (index<=0) or (index>envcount) then
  867. begin
  868. envstr:='';
  869. exit;
  870. end;
  871. hp:=PPchar(cardinal(envs)+4*(index-1));
  872. envstr:=strpas(hp^);
  873. end;
  874. function getenv(const envvar : string) : string;
  875. var hs,_envvar : string;
  876. eqpos,i : longint;
  877. begin
  878. _envvar:=upcase(envvar);
  879. getenv:='';
  880. for i:=1 to envcount do
  881. begin
  882. hs:=envstr(i);
  883. eqpos:=pos('=',hs);
  884. if copy(hs,1,eqpos-1)=_envvar then
  885. begin
  886. getenv:=copy(hs,eqpos+1,length(hs)-eqpos);
  887. exit;
  888. end;
  889. end;
  890. end;
  891. procedure fsplit(path:pathstr;var dir:dirstr;var name:namestr;
  892. var ext:extstr);
  893. var p1,i : longint;
  894. begin
  895. {Get drive name}
  896. p1:=pos(':',path);
  897. if p1>0 then
  898. begin
  899. dir:=path[1]+':';
  900. delete(path,1,p1);
  901. end
  902. else
  903. dir:='';
  904. { split the path and the name, there are no more path informtions }
  905. { if path contains no backslashes }
  906. while true do
  907. begin
  908. p1:=pos('\',path);
  909. if p1=0 then
  910. p1:=pos('/',path);
  911. if p1=0 then
  912. break;
  913. dir:=dir+copy(path,1,p1);
  914. delete(path,1,p1);
  915. end;
  916. {Try to find an extension.}
  917. ext:='';
  918. for i:=length(path) downto 1 do
  919. if path[i]='.' then
  920. begin
  921. ext:=copy(path,i,high(extstr));
  922. delete(path,i,length(path)-i+1);
  923. break;
  924. end;
  925. name:=path;
  926. end;
  927. function fexpand(const path:pathstr):pathstr;
  928. function get_current_drive:byte;assembler;
  929. asm
  930. movb $0x19,%ah
  931. call syscall
  932. end;
  933. var s,pa:string;
  934. i,j:longint;
  935. begin
  936. getdir(0,s);
  937. if FileNameCaseSensitive then
  938. pa := path
  939. else
  940. pa:=upcase(path);
  941. {Allow slash as backslash}
  942. for i:=1 to length(pa) do
  943. if pa[i]='/' then
  944. pa[i]:='\';
  945. if (length(pa)>1) and (pa[1] in ['A'..'Z']) and (pa[2]=':') then
  946. begin
  947. {We must get the right directory}
  948. getdir(byte(pa[1])-byte('A')+1,s);
  949. if (byte(pa[0])>2) and (pa[3]<>'\') then
  950. if pa[1]=s[1] then
  951. pa:=s+'\'+copy (pa,3,length(pa))
  952. else
  953. pa:=pa[1]+':\'+copy (pa,3,length(pa))
  954. end
  955. else
  956. if pa[1]='\' then
  957. pa:=s[1]+':'+pa
  958. else if s[0]=#3 then
  959. pa:=s+pa
  960. else
  961. pa:=s+'\'+pa;
  962. {First remove all references to '\.\'}
  963. i:=pos('\.\',pa);
  964. while i<>0 do
  965. begin
  966. delete(pa,i,2);
  967. i:=pos('\.\',pa);
  968. end;
  969. {Now remove also all references to '\..\' + of course previous dirs..}
  970. repeat
  971. i:=pos('\..\',pa);
  972. if i<>0 then
  973. begin
  974. j:=i-1;
  975. while (j>1) and (pa[j]<>'\') do
  976. dec(j);
  977. delete (pa,j,i-j+3);
  978. end;
  979. until i=0;
  980. {Remove End . and \}
  981. if (length(pa)>0) and (pa[length(pa)]='.') then
  982. dec(byte(pa[0]));
  983. if (length(pa)>0) and (pa[length(pa)]='\') then
  984. dec(byte(pa[0]));
  985. fexpand:=pa;
  986. end;
  987. procedure packtime(var d:datetime;var time:longint);
  988. var zs:longint;
  989. begin
  990. time:=-1980;
  991. time:=time+d.year and 127;
  992. time:=time shl 4;
  993. time:=time+d.month;
  994. time:=time shl 5;
  995. time:=time+d.day;
  996. time:=time shl 16;
  997. zs:=d.hour;
  998. zs:=zs shl 6;
  999. zs:=zs+d.min;
  1000. zs:=zs shl 5;
  1001. zs:=zs+d.sec div 2;
  1002. time:=time+(zs and $ffff);
  1003. end;
  1004. procedure unpacktime (time:longint;var d:datetime);
  1005. begin
  1006. d.sec:=(time and 31) * 2;
  1007. time:=time shr 5;
  1008. d.min:=time and 63;
  1009. time:=time shr 6;
  1010. d.hour:=time and 31;
  1011. time:=time shr 5;
  1012. d.day:=time and 31;
  1013. time:=time shr 5;
  1014. d.month:=time and 15;
  1015. time:=time shr 4;
  1016. d.year:=time+1980;
  1017. end;
  1018. procedure getfattr(var f;var attr : word);assembler;
  1019. asm
  1020. movw $0x4300,%ax
  1021. movl f,%edx
  1022. {addl $filerec.name,%edx Doesn't work!!}
  1023. addl $60,%edx
  1024. call syscall
  1025. movl attr,%ebx
  1026. movw %cx,(%ebx)
  1027. xorb %ah,%ah
  1028. movw %ax,doserror
  1029. end;
  1030. procedure setfattr(var f;attr : word);assembler;
  1031. asm
  1032. movw $0x4301,%ax
  1033. movl f,%edx
  1034. {addl $filerec.name,%edx Doesn't work!!}
  1035. addl $60,%edx
  1036. movw attr,%cx
  1037. call syscall
  1038. xorb %ah,%ah
  1039. movw %ax,doserror
  1040. end;
  1041. end.
  1042. {
  1043. $Log$
  1044. Revision 1.28 2000-07-06 18:57:40 hajny
  1045. * SetFTime for OS/2 mode corrected
  1046. Revision 1.27 2000/06/05 18:50:55 hajny
  1047. * SetDate, SetTime corrected
  1048. Revision 1.26 2000/06/01 18:38:46 hajny
  1049. * warning about SetDate added (TODO)
  1050. Revision 1.25 2000/05/28 18:20:16 hajny
  1051. * DiskFree/DiskSize updated
  1052. Revision 1.24 2000/05/21 16:06:38 hajny
  1053. + FSearch and Find* reworked
  1054. Revision 1.23 2000/04/18 20:30:02 hajny
  1055. * FSearch with given path corrected
  1056. Revision 1.22 2000/03/12 18:32:17 hajny
  1057. * missing parentheses added
  1058. Revision 1.21 2000/03/05 19:00:37 hajny
  1059. * DiskFree, DiskSize - int64 result, fix for osDPMI mode
  1060. Revision 1.20 2000/02/09 16:59:33 peter
  1061. * truncated log
  1062. Revision 1.19 2000/01/09 20:51:03 hajny
  1063. * FPK changed to FPC
  1064. Revision 1.18 2000/01/07 16:41:45 daniel
  1065. * copyright 2000
  1066. Revision 1.17 1999/10/13 12:21:56 daniel
  1067. * OS/2 compiler works again.
  1068. Revision 1.16 1999/09/13 18:21:02 hajny
  1069. * again didn't manage to read docu for DosFindFirst properly :-(
  1070. Revision 1.15 1999/09/13 17:56:26 hajny
  1071. * another correction to FSearch fix - mistyping
  1072. Revision 1.14 1999/09/13 17:35:15 hajny
  1073. * little addition/correction to FSearch fix
  1074. Revision 1.13 1999/09/09 09:20:43 hajny
  1075. * FSearch under OS/2 fixed
  1076. }