dos.pas 31 KB

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