dos.pas 29 KB

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