dos.pas 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260
  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. {OS/2 specific functions}
  73. function GetEnvPChar (EnvVar: string): PChar;
  74. const
  75. (* For compatibility with VP/2, used for runflags in Exec procedure. *)
  76. ExecFlags: cardinal = ord (efwait);
  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. {$ifdef HASTHREADVAR}
  276. threadvar
  277. {$else HASTHREADVAR}
  278. var
  279. {$endif HASTHREADVAR}
  280. LastDosExitCode: longint;
  281. procedure exec(const path:pathstr;const comline:comstr);
  282. {Execute a program.}
  283. begin
  284. LastDosExitCode := Exec (Path, ExecRunFlags (ExecFlags), efdefault, comline);
  285. end;
  286. function exec(path:pathstr;runflags:execrunflags;winflags:execwinflags;
  287. const comline:comstr):longint;
  288. {Execute a program. More suitable for OS/2 than the exec above.}
  289. type bytearray=array[0..8191] of byte;
  290. Pbytearray=^bytearray;
  291. execstruc=packed record
  292. argofs : pointer; { pointer to arguments (offset) }
  293. envofs : pointer; { pointer to environment (offset) }
  294. nameofs: pointer; { pointer to file name (offset) }
  295. argseg : word; { pointer to arguments (selector) }
  296. envseg : word; { pointer to environment (selector}
  297. nameseg: word; { pointer to file name (selector) }
  298. numarg : word; { number of arguments }
  299. sizearg : word; { size of arguments }
  300. numenv : word; { number of env strings }
  301. sizeenv:word; { size of environment }
  302. mode1,mode2:byte; { mode byte }
  303. end;
  304. var args:Pbytearray;
  305. env:Pbytearray;
  306. i,argsize:word;
  307. es:execstruc;
  308. esadr:pointer;
  309. d:dirstr;
  310. n:namestr;
  311. e:extstr;
  312. p : ppchar;
  313. j : integer;
  314. const
  315. ArgsSize = 2048; (* Amount of memory reserved for arguments in bytes. *)
  316. begin
  317. getmem(args,ArgsSize);
  318. GetMem(env, envc*sizeof(pchar)+16384);
  319. {Now setup the arguments. The first argument should be the program
  320. name without directory and extension.}
  321. fsplit(path,d,n,e);
  322. es.numarg:=1;
  323. args^[0]:=$80;
  324. argsize:=1;
  325. for i:=1 to length(n) do
  326. begin
  327. args^[argsize]:=byte(n[i]);
  328. inc(argsize);
  329. end;
  330. args^[argsize]:=0;
  331. inc(argsize);
  332. {Now do the real arguments.}
  333. i:=1;
  334. while i<=length(comline) do
  335. begin
  336. if comline[i]<>' ' then
  337. begin
  338. {Commandline argument found. Copy it.}
  339. inc(es.numarg);
  340. args^[argsize]:=$80;
  341. inc(argsize);
  342. while (i<=length(comline)) and (comline[i]<>' ') do
  343. begin
  344. args^[argsize]:=byte(comline[i]);
  345. inc(argsize);
  346. inc(i);
  347. end;
  348. args^[argsize]:=0;
  349. inc(argsize);
  350. end;
  351. inc(i);
  352. end;
  353. args^[argsize]:=0;
  354. inc(argsize);
  355. {Commandline ready, now build the environment.
  356. Oh boy, I always had the opinion that executing a program under Dos
  357. was a hard job!}
  358. asm
  359. movl env,%edi {Setup destination pointer.}
  360. movl envc,%ecx {Load number of arguments in edx.}
  361. movl envp,%esi {Load env. strings.}
  362. xorl %edx,%edx {Count environment size.}
  363. .Lexa1:
  364. lodsl {Load a Pchar.}
  365. xchgl %eax,%ebx
  366. .Lexa2:
  367. movb (%ebx),%al {Load a byte.}
  368. incl %ebx {Point to next byte.}
  369. stosb {Store it.}
  370. incl %edx {Increase counter.}
  371. cmpb $0,%al {Ready ?.}
  372. jne .Lexa2
  373. loop .Lexa1 {Next argument.}
  374. stosb {Store an extra 0 to finish. (AL is now 0).}
  375. incl %edx
  376. movw %dx,ES.SizeEnv {Store environment size.}
  377. end ['eax','ebx','ecx','edx','esi','edi'];
  378. {Environment ready, now set-up exec structure.}
  379. es.argofs:=args;
  380. es.envofs:=env;
  381. es.numenv:=envc;
  382. { set an error - path is too long }
  383. { since we must add a zero to the }
  384. { end. }
  385. if length(path) > 254 then
  386. begin
  387. exec := 8;
  388. exit;
  389. end;
  390. path[length(path)+1] := #0;
  391. es.nameofs:=pointer(longint(@path)+1);
  392. asm
  393. movw %ss,es.argseg
  394. movw %ss,es.envseg
  395. movw %ss,es.nameseg
  396. end;
  397. es.sizearg:=argsize;
  398. {Typecasting of sets in FPC is a bit hard.}
  399. es.mode1:=byte(runflags);
  400. es.mode2:=byte(winflags);
  401. {Now exec the program.}
  402. asm
  403. leal es,%edx
  404. movw $0x7f06,%ax
  405. call syscall
  406. movl $0,%edi
  407. jnc .Lexprg1
  408. xchgl %eax,%edi
  409. xorl %eax,%eax
  410. decl %eax
  411. .Lexprg1:
  412. movw %di,doserror
  413. movl %eax,__RESULT
  414. end ['eax', 'ebx', 'ecx', 'edx', 'esi', 'edi'];
  415. freemem(args,ArgsSize);
  416. FreeMem(env, envc*sizeof(pchar)+16384);
  417. {Phew! That's it. This was the most sophisticated procedure to call
  418. a system function I ever wrote!}
  419. end;
  420. function DosExitCode: word;
  421. begin
  422. DosExitCode := LastDosExitCode and $FFFF;
  423. end;
  424. function dosversion:word;assembler;
  425. {Returns DOS version in DOS and OS/2 version in OS/2}
  426. asm
  427. movb $0x30,%ah
  428. call syscall
  429. end ['eax'];
  430. procedure GetDate (var Year, Month, MDay, WDay: word);
  431. begin
  432. asm
  433. movb $0x2a, %ah
  434. call syscall
  435. xorb %ah, %ah
  436. movl WDay, %edi
  437. stosw
  438. movl MDay, %edi
  439. movb %dl, %al
  440. stosw
  441. movl Month, %edi
  442. movb %dh, %al
  443. stosw
  444. movl Year, %edi
  445. xchgw %ecx, %eax
  446. stosw
  447. end ['eax', 'ecx', 'edx'];
  448. end;
  449. {$asmmode intel}
  450. procedure SetDate (Year, Month, Day: word);
  451. var DT: TDateTime;
  452. begin
  453. if os_mode = osOS2 then
  454. begin
  455. DosGetDateTime (DT);
  456. DT.Year := Year;
  457. DT.Month := byte (Month);
  458. DT.Day := byte (Day);
  459. DosSetDateTime (DT);
  460. end
  461. else
  462. asm
  463. mov cx, Year
  464. mov dh, byte ptr Month
  465. mov dl, byte ptr Day
  466. mov ah, 2Bh
  467. call syscall
  468. end ['eax', 'ecx', 'edx'];
  469. end;
  470. {$asmmode att}
  471. procedure GetTime (var Hour, Minute, Second, Sec100: word);
  472. {$IFDEF REGCALL}
  473. begin
  474. {$ELSE REGCALL}
  475. assembler;
  476. {$ENDIF REGCALL}
  477. asm
  478. movb $0x2c, %ah
  479. call syscall
  480. xorb %ah, %ah
  481. movl Sec100, %edi
  482. movb %dl, %al
  483. stosw
  484. movl Second, %edi
  485. movb %dh,%al
  486. stosw
  487. movl Minute, %edi
  488. movb %cl,%al
  489. stosw
  490. movl Hour, %edi
  491. movb %ch,%al
  492. stosw
  493. {$IFDEF REGCALL}
  494. end ['eax', 'ecx', 'edx'];
  495. end;
  496. {$ELSE REGCALL}
  497. end {['eax', 'ecx', 'edx']};
  498. {$ENDIF REGCALL}
  499. {$asmmode intel}
  500. procedure SetTime (Hour, Minute, Second, Sec100: word);
  501. var DT: TDateTime;
  502. begin
  503. if os_mode = osOS2 then
  504. begin
  505. DosGetDateTime (DT);
  506. DT.Hour := byte (Hour);
  507. DT.Minute := byte (Minute);
  508. DT.Second := byte (Second);
  509. DT.Sec100 := byte (Sec100);
  510. DosSetDateTime (DT);
  511. end
  512. else
  513. asm
  514. mov ch, byte ptr Hour
  515. mov cl, byte ptr Minute
  516. mov dh, byte ptr Second
  517. mov dl, byte ptr Sec100
  518. mov ah, 2Dh
  519. call syscall
  520. end ['eax', 'ecx', 'edx'];
  521. end;
  522. {$asmmode att}
  523. procedure getcbreak(var breakvalue:boolean);
  524. begin
  525. breakvalue := True;
  526. end;
  527. procedure setcbreak(breakvalue:boolean);
  528. begin
  529. {! Do not use in OS/2. Also not recommended in DOS. Use
  530. signal handling instead.
  531. asm
  532. movb BreakValue,%dl
  533. movw $0x3301,%ax
  534. call syscall
  535. end ['eax', 'edx'];
  536. }
  537. end;
  538. procedure getverify(var verify:boolean);
  539. begin
  540. {! Do not use in OS/2.}
  541. if os_mode in [osDOS,osDPMI] then
  542. asm
  543. movb $0x54,%ah
  544. call syscall
  545. movl verify,%edi
  546. stosb
  547. end ['eax', 'edi']
  548. else
  549. verify := true;
  550. end;
  551. procedure setverify(verify:boolean);
  552. begin
  553. {! Do not use in OS/2!}
  554. if os_mode in [osDOS,osDPMI] then
  555. asm
  556. movb verify,%al
  557. movb $0x2e,%ah
  558. call syscall
  559. end ['eax'];
  560. end;
  561. function DiskFree (Drive: byte): int64;
  562. var FI: TFSinfo;
  563. RC: cardinal;
  564. begin
  565. if (os_mode = osDOS) or (os_mode = osDPMI) then
  566. {Function 36 is not supported in OS/2.}
  567. asm
  568. pushl %ebx
  569. movb Drive,%dl
  570. movb $0x36,%ah
  571. call syscall
  572. cmpw $-1,%ax
  573. je .LDISKFREE1
  574. mulw %cx
  575. mulw %bx
  576. shll $16,%edx
  577. movw %ax,%dx
  578. movl $0,%eax
  579. xchgl %edx,%eax
  580. jmp .LDISKFREE2
  581. .LDISKFREE1:
  582. cltd
  583. .LDISKFREE2:
  584. popl %ebx
  585. leave
  586. ret
  587. end ['eax', 'ecx', 'edx']
  588. else
  589. {In OS/2, we use the filesystem information.}
  590. begin
  591. RC := DosQueryFSInfo (Drive, 1, FI, SizeOf (FI));
  592. if RC = 0 then
  593. DiskFree := int64 (FI.Free_Clusters) *
  594. int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
  595. else
  596. DiskFree := -1;
  597. end;
  598. end;
  599. function DiskSize (Drive: byte): int64;
  600. var FI: TFSinfo;
  601. RC: cardinal;
  602. begin
  603. if (os_mode = osDOS) or (os_mode = osDPMI) then
  604. {Function 36 is not supported in OS/2.}
  605. asm
  606. pushl %ebx
  607. movb Drive,%dl
  608. movb $0x36,%ah
  609. call syscall
  610. movw %dx,%bx
  611. cmpw $-1,%ax
  612. je .LDISKSIZE1
  613. mulw %cx
  614. mulw %bx
  615. shll $16,%edx
  616. movw %ax,%dx
  617. movl $0,%eax
  618. xchgl %edx,%eax
  619. jmp .LDISKSIZE2
  620. .LDISKSIZE1:
  621. cltd
  622. .LDISKSIZE2:
  623. popl %ebx
  624. leave
  625. ret
  626. end ['eax', 'ecx', 'edx']
  627. else
  628. {In OS/2, we use the filesystem information.}
  629. begin
  630. RC := DosQueryFSinfo (Drive, 1, FI, SizeOf (FI));
  631. if RC = 0 then
  632. DiskSize := int64 (FI.Total_Clusters) *
  633. int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
  634. else
  635. DiskSize := -1;
  636. end;
  637. end;
  638. procedure SearchRec2DosSearchRec (var F: SearchRec);
  639. const NameSize = 255;
  640. var L, I: longint;
  641. begin
  642. if os_mode <> osOS2 then
  643. begin
  644. I := 1;
  645. while (I <= SizeOf (LastSR))
  646. and (PBA (@F)^ [I] = PBA (@LastSR)^ [I]) do Inc (I);
  647. { Raise "Invalid file handle" RTE if nested FindFirst calls were used. }
  648. if I <= SizeOf (LastSR) then RunError (6);
  649. l:=length(f.name);
  650. for i:=1 to namesize do
  651. f.name[i-1]:=f.name[i];
  652. f.name[l]:=#0;
  653. end;
  654. end;
  655. procedure DosSearchRec2SearchRec (var F: SearchRec);
  656. const NameSize=255;
  657. var L, I: longint;
  658. type TRec = record
  659. T, D: word;
  660. end;
  661. begin
  662. if os_mode = osOS2 then with F do
  663. begin
  664. Name := FStat^.Name;
  665. Size := FStat^.FileSize;
  666. Attr := byte(FStat^.AttrFile and $FF);
  667. TRec (Time).T := FStat^.TimeLastWrite;
  668. TRec (Time).D := FStat^.DateLastWrite;
  669. end else
  670. begin
  671. for i:=0 to namesize do
  672. if f.name[i]=#0 then
  673. begin
  674. l:=i;
  675. break;
  676. end;
  677. for i:=namesize-1 downto 0 do
  678. f.name[i+1]:=f.name[i];
  679. f.name[0]:=char(l);
  680. Move (F, LastSR, SizeOf (LastSR));
  681. end;
  682. end;
  683. procedure _findfirst(path:pchar;attr:word;var f:searchrec);
  684. begin
  685. asm
  686. pushl %esi
  687. movl path,%edx
  688. movw attr,%cx
  689. {No need to set DTA in EMX. Just give a pointer in ESI.}
  690. movl f,%esi
  691. movb $0x4e,%ah
  692. call syscall
  693. jnc .LFF
  694. movw %ax,doserror
  695. .LFF:
  696. popl %esi
  697. end ['eax', 'ecx', 'edx'];
  698. end;
  699. procedure FindFirst (const Path: PathStr; Attr: word; var F: SearchRec);
  700. var path0: array[0..255] of char;
  701. Count: cardinal;
  702. begin
  703. {No error.}
  704. DosError := 0;
  705. if os_mode = osOS2 then
  706. begin
  707. New (F.FStat);
  708. F.Handle := longint ($FFFFFFFF);
  709. Count := 1;
  710. DosError := integer (DosFindFirst (Path, F.Handle,
  711. Attr and FindResvdMask, F.FStat, SizeOf (F.FStat^),
  712. Count, ilStandard));
  713. if (DosError = 0) and (Count = 0) then DosError := 18;
  714. end else
  715. begin
  716. strPcopy(path0,path);
  717. _findfirst(path0,attr,f);
  718. end;
  719. DosSearchRec2SearchRec (F);
  720. end;
  721. procedure _findnext(var f : searchrec);
  722. begin
  723. asm
  724. pushl %esi
  725. movl f,%esi
  726. movb $0x4f,%ah
  727. call syscall
  728. jnc .LFN
  729. movw %ax,doserror
  730. .LFN:
  731. popl %esi
  732. end ['eax'];
  733. end;
  734. procedure FindNext (var F: SearchRec);
  735. var Count: cardinal;
  736. begin
  737. {No error}
  738. DosError := 0;
  739. SearchRec2DosSearchRec (F);
  740. if os_mode = osOS2 then
  741. begin
  742. Count := 1;
  743. DosError := integer (DosFindNext (F.Handle, F.FStat, SizeOf (F.FStat^),
  744. Count));
  745. if (DosError = 0) and (Count = 0) then DosError := 18;
  746. end else _findnext (F);
  747. DosSearchRec2SearchRec (F);
  748. end;
  749. procedure FindClose (var F: SearchRec);
  750. begin
  751. if os_mode = osOS2 then
  752. begin
  753. if F.Handle <> $FFFFFFFF then DosError := DosFindClose (F.Handle);
  754. Dispose (F.FStat);
  755. end;
  756. end;
  757. procedure swapvectors;
  758. {For TP compatibility, this exists.}
  759. begin
  760. end;
  761. function envcount:longint;assembler;
  762. asm
  763. movl envc,%eax
  764. end ['EAX'];
  765. function envstr(index : longint) : string;
  766. var hp:Pchar;
  767. begin
  768. if (index<=0) or (index>envcount) then
  769. begin
  770. envstr:='';
  771. exit;
  772. end;
  773. hp:=EnvP[index-1];
  774. envstr:=strpas(hp);
  775. end;
  776. function GetEnvPChar (EnvVar: string): PChar;
  777. (* The assembler version is more than three times as fast as Pascal. *)
  778. var
  779. P: PChar;
  780. begin
  781. EnvVar := UpCase (EnvVar);
  782. {$ASMMODE INTEL}
  783. asm
  784. cld
  785. mov edi, Environment
  786. lea esi, EnvVar
  787. xor eax, eax
  788. lodsb
  789. @NewVar:
  790. cmp byte ptr [edi], 0
  791. jz @Stop
  792. push eax { eax contains length of searched variable name }
  793. push esi { esi points to the beginning of the variable name }
  794. mov ecx, -1 { our character ('=' - see below) _must_ be found }
  795. mov edx, edi { pointer to beginning of variable name saved in edx }
  796. mov al, '=' { searching until '=' (end of variable name) }
  797. repne
  798. scasb { scan until '=' not found }
  799. neg ecx { what was the name length? }
  800. dec ecx { corrected }
  801. dec ecx { exclude the '=' character }
  802. pop esi { restore pointer to beginning of variable name }
  803. pop eax { restore length of searched variable name }
  804. push eax { and save both of them again for later use }
  805. push esi
  806. cmp ecx, eax { compare length of searched variable name with name }
  807. jnz @NotEqual { ... of currently found variable, jump if different }
  808. xchg edx, edi { pointer to current variable name restored in edi }
  809. repe
  810. cmpsb { compare till the end of variable name }
  811. xchg edx, edi { pointer to beginning of variable contents in edi }
  812. jz @Equal { finish if they're equal }
  813. @NotEqual:
  814. xor eax, eax { look for 00h }
  815. mov ecx, -1 { it _must_ be found }
  816. repne
  817. scasb { scan until found }
  818. pop esi { restore pointer to beginning of variable name }
  819. pop eax { restore length of searched variable name }
  820. jmp @NewVar { ... or continue with new variable otherwise }
  821. @Stop:
  822. xor eax, eax
  823. mov P, eax { Not found - return nil }
  824. jmp @End
  825. @Equal:
  826. pop esi { restore the stack position }
  827. pop eax
  828. mov P, edi { place pointer to variable contents in P }
  829. @End:
  830. end ['eax','ecx','edx','esi','edi'];
  831. GetEnvPChar := P;
  832. end;
  833. {$ASMMODE ATT}
  834. function GetEnv (EnvVar: string): string;
  835. begin
  836. GetEnv := StrPas (GetEnvPChar (EnvVar));
  837. end;
  838. procedure fsplit(path:pathstr;var dir:dirstr;var name:namestr;
  839. var ext:extstr);
  840. var p1,i : longint;
  841. dotpos : integer;
  842. begin
  843. { allow slash as backslash }
  844. for i:=1 to length(path) do
  845. if path[i]='/' then path[i]:='\';
  846. {Get drive name}
  847. p1:=pos(':',path);
  848. if p1>0 then
  849. begin
  850. dir:=path[1]+':';
  851. delete(path,1,p1);
  852. end
  853. else
  854. dir:='';
  855. { split the path and the name, there are no more path informtions }
  856. { if path contains no backslashes }
  857. while true do
  858. begin
  859. p1:=pos('\',path);
  860. if p1=0 then
  861. break;
  862. dir:=dir+copy(path,1,p1);
  863. delete(path,1,p1);
  864. end;
  865. { try to find out a extension }
  866. Ext:='';
  867. i:=Length(Path);
  868. DotPos:=256;
  869. While (i>0) Do
  870. Begin
  871. If (Path[i]='.') Then
  872. begin
  873. DotPos:=i;
  874. break;
  875. end;
  876. Dec(i);
  877. end;
  878. Ext:=Copy(Path,DotPos,255);
  879. Name:=Copy(Path,1,DotPos - 1);
  880. end;
  881. (*
  882. function FExpand (const Path: PathStr): PathStr;
  883. - declared in fexpand.inc
  884. *)
  885. {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
  886. {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
  887. const
  888. LFNSupport = true;
  889. {$I fexpand.inc}
  890. {$UNDEF FPC_FEXPAND_DRIVES}
  891. {$UNDEF FPC_FEXPAND_UNC}
  892. procedure PackTime (var T: DateTime; var P: longint);
  893. var zs:longint;
  894. begin
  895. P := -1980;
  896. P := P + T.Year and 127;
  897. P := P shl 4;
  898. P := P + T.Month;
  899. P := P shl 5;
  900. P := P + T.Day;
  901. P := P shl 16;
  902. zs:= T.hour;
  903. zs:= zs shl 6;
  904. zs:= zs + T.Min;
  905. zs:= zs shl 5;
  906. zs:= zs + T.Sec div 2;
  907. P := P + (zs and $ffff);
  908. end;
  909. procedure unpacktime (P: longint; var T: DateTime);
  910. begin
  911. T.Sec := (P and 31) * 2;
  912. P := P shr 5;
  913. T.Min := P and 63;
  914. P := P shr 6;
  915. T.Hour := P and 31;
  916. P := P shr 5;
  917. T.Day := P and 31;
  918. P := P shr 5;
  919. T.Month := P and 15;
  920. P := P shr 4;
  921. T.Year := P + 1980;
  922. end;
  923. procedure getfattr(var f;var attr : word);
  924. { Under EMX, this routine requires }
  925. { the expanded path specification }
  926. { otherwise it will not function }
  927. { properly (CEC) }
  928. var
  929. path: pathstr;
  930. buffer:array[0..255] of char;
  931. begin
  932. DosError := 0;
  933. path:='';
  934. path := StrPas(filerec(f).Name);
  935. { Takes care of slash and backslash support }
  936. path:=FExpand(path);
  937. move(path[1],buffer,length(path));
  938. buffer[length(path)]:=#0;
  939. asm
  940. pushl %ebx
  941. movw $0x4300,%ax
  942. leal buffer,%edx
  943. call syscall
  944. jnc .Lnoerror { is there an error ? }
  945. movw %ax,doserror
  946. .Lnoerror:
  947. movl attr,%ebx
  948. movw %cx,(%ebx)
  949. popl %ebx
  950. end ['eax', 'ecx', 'edx'];
  951. end;
  952. procedure setfattr(var f;attr : word);
  953. { Under EMX, this routine requires }
  954. { the expanded path specification }
  955. { otherwise it will not function }
  956. { properly (CEC) }
  957. var
  958. path: pathstr;
  959. buffer:array[0..255] of char;
  960. begin
  961. path:='';
  962. DosError := 0;
  963. path := StrPas(filerec(f).Name);
  964. { Takes care of slash and backslash support }
  965. path:=FExpand(path);
  966. move(path[1],buffer,length(path));
  967. buffer[length(path)]:=#0;
  968. asm
  969. movw $0x4301,%ax
  970. leal buffer,%edx
  971. movw attr,%cx
  972. call syscall
  973. jnc .Lnoerror
  974. movw %ax,doserror
  975. .Lnoerror:
  976. end ['eax', 'ecx', 'edx'];
  977. end;
  978. procedure InitEnvironment;
  979. var
  980. cnt : integer;
  981. ptr : pchar;
  982. base : pchar;
  983. i: integer;
  984. PIB: PProcessInfoBlock;
  985. TIB: PThreadInfoBlock;
  986. begin
  987. { We need to setup the environment }
  988. { only in the case of OS/2 }
  989. { otherwise everything is in the stack }
  990. if os_Mode in [OsDOS,osDPMI] then
  991. exit;
  992. cnt := 0;
  993. { count number of environment pointers }
  994. DosGetInfoBlocks (PPThreadInfoBlock (@TIB), PPProcessInfoBlock (@PIB));
  995. ptr := pchar(PIB^.env);
  996. { stringz,stringz...,#0 }
  997. i := 0;
  998. repeat
  999. repeat
  1000. (inc(i));
  1001. until (ptr[i] = #0);
  1002. inc(i);
  1003. { here, it may be a double null, end of environment }
  1004. if ptr[i] <> #0 then
  1005. inc(cnt);
  1006. until (ptr[i] = #0);
  1007. { save environment count }
  1008. envc := cnt;
  1009. { got count of environment strings }
  1010. GetMem(envp, cnt*sizeof(pchar)+16384);
  1011. cnt := 0;
  1012. ptr := pchar(PIB^.env);
  1013. i:=0;
  1014. repeat
  1015. envp[cnt] := ptr;
  1016. Inc(cnt);
  1017. { go to next string ... }
  1018. repeat
  1019. inc(ptr);
  1020. until (ptr^ = #0);
  1021. inc(ptr);
  1022. until ptr^ = #0;
  1023. envp[cnt] := #0;
  1024. end;
  1025. procedure DoneEnvironment;
  1026. begin
  1027. { it is allocated on the stack for DOS/DPMI }
  1028. if os_mode = osOs2 then
  1029. FreeMem(envp, envc*sizeof(pchar)+16384);
  1030. end;
  1031. var
  1032. oldexit : pointer;
  1033. {******************************************************************************
  1034. --- Not Supported ---
  1035. ******************************************************************************}
  1036. procedure Keep (ExitCode: word);
  1037. begin
  1038. end;
  1039. procedure GetIntVec (IntNo: byte; var Vector: pointer);
  1040. begin
  1041. end;
  1042. procedure SetIntVec (IntNo: byte; Vector: pointer);
  1043. begin
  1044. end;
  1045. function GetShortName(var p : String) : boolean;
  1046. begin
  1047. GetShortName:=true;
  1048. end;
  1049. function GetLongName(var p : String) : boolean;
  1050. begin
  1051. GetLongName:=true;
  1052. end;
  1053. begin
  1054. oldexit:=exitproc;
  1055. exitproc:=@doneenvironment;
  1056. InitEnvironment;
  1057. LastDosExitCode := 0;
  1058. end.
  1059. {
  1060. $Log$
  1061. Revision 1.13 2004-02-22 15:01:49 hajny
  1062. * lots of fixes (regcall, THandle, string operations in sysutils, longint2cardinal according to OS/2 docs, dosh.inc, ...)
  1063. Revision 1.12 2004/02/17 17:37:26 daniel
  1064. * Enable threadvars again
  1065. Revision 1.11 2004/02/16 22:16:58 hajny
  1066. * LastDosExitCode changed back from threadvar temporarily
  1067. Revision 1.10 2004/02/15 21:26:37 hajny
  1068. * overloaded ExecuteProcess added, EnvStr param changed to longint
  1069. Revision 1.9 2004/02/09 12:03:16 michael
  1070. + Switched to single interface in dosh.inc
  1071. Revision 1.8 2003/12/26 22:20:44 hajny
  1072. * regcall fixes
  1073. Revision 1.7 2003/10/25 22:45:37 hajny
  1074. * file handling related fixes
  1075. Revision 1.6 2003/10/07 21:33:24 hajny
  1076. * stdcall fixes and asm routines cleanup
  1077. Revision 1.5 2003/10/04 17:53:08 hajny
  1078. * stdcall changes merged to EMX
  1079. Revision 1.4 2003/06/26 17:12:29 yuri
  1080. * pmbidi added
  1081. * some cosmetic changes
  1082. Revision 1.3 2003/03/23 23:11:17 hajny
  1083. + emx target added
  1084. Revision 1.2 2002/12/15 22:50:29 hajny
  1085. * GetEnv fix merged from os2 target
  1086. Revision 1.1 2002/11/17 16:22:53 hajny
  1087. + RTL for emx target
  1088. }