{
    $Id$
    This unit mimics the DOS unit for Win32 
    This file is part of the Free Pascal run time library.
    Copyright (c) 1998 by the Free Pascal development team.

    See the file COPYING.FPC, included in this distribution,
    for details about the copyright.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

 **********************************************************************}

{$I os.inc}

unit dos;

  interface

    uses
       strings;

    const
       { bit masks for CPU flags}
       fcarry = $0001;
       fparity = $0004;
       fauxiliary = $0010;
       fzero = $0040;
       fsign = $0080;
       foverflow  = $0800;

       { bit masks for file attributes }
       readonly = $01;
       hidden = $02;
       sysfile = $04;
       volumeid = $08;
       directory = $10;
       archive = $20;
       anyfile = $3F;
       fmclosed = $D7B0;
       fminput = $D7B1;
       fmoutput = $D7B2;
       fminout = $D7B3;

    type
       { some string types }
       comstr = string[127];        { command line string }
       pathstr = string[79];        { string for a file path }
       dirstr = string[67];         { string for a directory }
       namestr = string[8];         { string for a file name }
       extstr = string[4];          { string for an extension }

       { search record which is used by findfirst and findnext }
{$ifndef GO32V2}
{$PACKRECORDS 1}
       searchrec = record
          fill : array[1..21] of byte;
          attr : byte;
          time : longint;
          reserved : word; { requires the DOS extender (DJ GNU-C) }
          size : longint;
          name : string[15]; { the same size as declared by (DJ GNU C) }
       end;
{$else GO32V2}
{$PACKRECORDS 1}
       searchrec = record
          fill : array[1..21] of byte;
          attr : byte;
          time : longint;
          { reserved : word; not in DJGPP V2 }
          size : longint;
          name : string[12]; { the same size as declared by (DJ GNU C) }
       end;
{$endif GO32V2}
{$PACKRECORDS 2}

       { file record for untyped files comes from filerec.inc}
       {$i filerec.inc}

       { file record for text files  comes from textrec.inc}
       {$i textrec.inc}

{$ifdef GO32V1}
       { data structure for the registers needed by msdos and intr }
       { Go32 V2 follows trealregs of go32 }

       registers = record
         case i : integer of
            0 : (ax,f1,bx,f2,cx,f3,dx,f4,bp,f5,si,f51,di,f6,ds,f7,es,f8,flags,fs,gs : word);
            1 : (al,ah,f9,f10,bl,bh,f11,f12,cl,ch,f13,f14,dl,dh : byte);
            2 : (eax,  ebx,  ecx,  edx,  ebp,  esi,  edi : longint);
       end;
{$endif GO32V1}

{$ifdef GO32V2}
       { data structure for the registers needed by msdos and intr }
       { Go32 V2 follows trealregs of go32 }

       registers = go32.registers;

{$endif GO32V2}

{$PACKRECORDS 1}
       { record for date and time }
       datetime = record
          year,month,day,hour,min,sec : word;
       end;

    var
       { error variable }
       doserror : integer;

    procedure getdate(var year,month,day,dayofweek : word);
    procedure gettime(var hour,minute,second,sec100 : word);
    function dosversion : word;
    procedure setdate(year,month,day : word);
    procedure settime(hour,minute,second,sec100 : word);
    procedure getcbreak(var breakvalue : boolean);
    procedure setcbreak(breakvalue : boolean);
    procedure getverify(var verify : boolean);
    procedure setverify(verify : boolean);
    function diskfree(drive : byte) : longint;
    function disksize(drive : byte) : longint;
    procedure findfirst(const path : pathstr;attr : word;var f : searchRec);
    procedure findnext(var f : searchRec);

    { is a dummy in win32 }
    procedure swapvectors;

{   not supported:
    procedure getintvec(intno : byte;var vector : pointer);
    procedure setintvec(intno : byte;vector : pointer);
    procedure keep(exitcode : word);
    procedure msdos(var regs : registers);
    procedure intr(intno : byte;var regs : registers);
}

    procedure getfattr(var f;var attr : word);
    procedure setfattr(var f;attr : word);

    function fsearch(const path : pathstr;dirlist : string) : pathstr;
    procedure getftime(var f;var time : longint);
    procedure setftime(var f;time : longint);
    procedure packtime (var d: datetime; var time: longint);
    procedure unpacktime (time: longint; var d: datetime);
    function fexpand(const path : pathstr) : pathstr;
    procedure fsplit(path : pathstr;var dir : dirstr;var name : namestr;
      var ext : extstr);
    procedure exec(const path : pathstr;const comline : comstr);
    function dosexitcode : word;
    function envcount : longint;
    function envstr(index : longint) : string;
    function getenv(const envvar : string): string;

  implementation

    { taken from the DOS version }
    function fsearch(const path : pathstr;dirlist : string) : pathstr;

      var
         newdir : pathstr;
         i,p1 : byte;
         s : searchrec;

      begin
         if (pos('?',path)<>0) or (pos('*',path)<>0) then
           { No wildcards allowed in these things }
           fsearch:=''
         else
           begin
              { allow slash as backslash }
              for i:=1 to length(dirlist) do
                if dirlist[i]='/' then dirlist[i]:='\';

              repeat
                { get first path }
                p1:=pos(';',dirlist);
                if p1>0 then
                  begin
                     newdir:=copy(dirlist,1,p1-1);
                     delete(dirlist,1,p1)
                  end
                else
                  begin
                     newdir:=dirlist;
                     dirlist:=''
                  end;
                if (newdir[length(newdir)]<>'\') and
                   (newdir[length(newdir)]<>':') then
                   newdir:=newdir+'\';
                findfirst(newdir+path,anyfile,s);
                if doserror=0 then
                  begin
                     { this should be newdir:=newdir+path
                     because path can contain a path part !! }
                     {newdir:=newdir+s.name;}
                     newdir:=newdir+path;
                     { this was for LINUX:
                     if pos('.\',newdir)=1 then
                       delete(newdir, 1, 2)
                      DOS strips off an initial .\
                     }
                  end
                else newdir:='';
              until(dirlist='') or (length(newdir)>0);
              fsearch:=newdir;
           end;
      end;

    procedure getftime(var f;var time : longint);

      begin
         dosregs.bx:=textrec(f).handle;
         dosregs.ax:=$5700;
         msdos(dosregs);
         time:=(dosregs.dx shl 16)+dosregs.cx;
         doserror:=dosregs.al;
      end;

   procedure setftime(var f;time : longint);

      begin
         dosregs.bx:=textrec(f).handle;
         dosregs.ecx:=time;
         dosregs.ax:=$5701;
         msdos(dosregs);
         doserror:=dosregs.al;
      end;

    procedure msdos(var regs : registers);

      begin
         intr($21,regs);
      end;
{$ifdef GO32V2}
    procedure intr(intno : byte;var regs : registers);

      begin
         realintr(intno,regs);
      end;
{$else GO32V2}
    procedure intr(intno : byte;var regs : registers);

      begin
         asm
            .data
    int86:
            .byte        0xcd
    int86_vec:
            .byte        0x03
            jmp        int86_retjmp

            .text
            movl        8(%ebp),%eax
            movb        %al,int86_vec

            movl        10(%ebp),%eax
            // do not use first int
            addl        $2,%eax

            movl        4(%eax),%ebx
            movl        8(%eax),%ecx
            movl        12(%eax),%edx
            movl        16(%eax),%ebp
            movl        20(%eax),%esi
            movl        24(%eax),%edi
            movl        (%eax),%eax

            jmp        int86
    int86_retjmp:
            pushf
            pushl	%ebp
            pushl       %eax
            movl        %esp,%ebp
            // calc EBP new
            addl        $12,%ebp
            movl        10(%ebp),%eax
            // do not use first int
            addl        $2,%eax

            popl        (%eax)
            movl        %ebx,4(%eax)
            movl        %ecx,8(%eax)
            movl        %edx,12(%eax)
            // restore EBP
            popl	%edx
            movl	%edx,16(%eax)
            movl        %esi,20(%eax)
            movl        %edi,24(%eax)
            // ignore ES and DS
            popl        %ebx        /* flags */
            movl        %ebx,32(%eax)
            // FS and GS too
         end;
      end;
{$endif GO32V2}
    var
       lastdosexitcode : word;
{$ifdef GO32V2}

    { this code is just the most basic part of dosexec.c from
    the djgpp code }

    procedure exec(const path : pathstr;const comline : comstr);

      procedure do_system(p,c : string);

      {
        Table 0931
        Format of EXEC parameter block for AL=00h,01h,04h:
        Offset	Size	Description
         00h	WORD	segment of environment to copy for child process (copy caller's
		          environment if 0000h)
         this does not seem to work (PM)
         02h	DWORD	pointer to command tail to be copied into child's PSP
         06h	DWORD	pointer to first FCB to be copied into child's PSP
         0Ah	DWORD	pointer to second FCB to be copied into child's PSP
         0Eh	DWORD	(AL=01h) will hold subprogram's initial SS:SP on return
         12h	DWORD	(AL=01h) will hold entry point (CS:IP) on return
        INT 21 4B--

        Copied from Ralf Brown's Interrupt List
      }

      type
         realptr = record
	    ofs,seg : word;
  	 end;

         texecblock = record
	    envseg : word;
	    comtail : realptr;
	    firstFCB : realptr;
	    secondFCB : realptr;
	    iniStack : realptr;
	    iniCSIP : realptr;
 	 end;

      var current_dos_buffer_pos : longint;
      function paste_to_dos(src : string) : boolean;
        var c : array[0..255] of char;
        begin
           paste_to_dos:=false;
           if current_dos_buffer_pos+length(src)+1>transfer_buffer+tb_size then
             begin
              doserror:=200;{ what value should we use here ? }
              exit;
             end;
           move(src[1],c[0],length(src));
           c[length(src)]:=#0;
           seg_move(get_ds,longint(@c),dosmemselector,current_dos_buffer_pos,length(src)+1);
           current_dos_buffer_pos:=current_dos_buffer_pos+length(src)+1;
           paste_to_dos:=true;
        end;
      var
         i,la_env,la_p,la_c,la_e,fcb1_la,fcb2_la : longint;
         arg_ofs : longint;
	      execblock : texecblock;

      begin
         la_env:=transfer_buffer;
         while (la_env mod 16)<>0 do inc(la_env);
         current_dos_buffer_pos:=la_env;
         for i:=1 to envcount do
           begin
              paste_to_dos(envstr(i));
           end;
         paste_to_dos(''); { adds a double zero at the end }
         { allow slash as backslash }
         for i:=1 to length(p) do
           if p[i]='/' then p[i]:='\';
         la_p:=current_dos_buffer_pos;
         paste_to_dos(p);
         la_c:=current_dos_buffer_pos;
         paste_to_dos(c);
	      la_e:=current_dos_buffer_pos;
         fcb1_la:=la_e;
         la_e:=la_e+16;
         fcb2_la:=la_e;
         la_e:=la_e+16;
         { allocate FCB see dosexec code }
         dosregs.ax:=$2901;
         arg_ofs:=1;
         while (c[arg_ofs]=' ') or (c[arg_ofs]=#9) do inc(arg_ofs);
         dosregs.ds:=(la_c+arg_ofs) div 16;
         dosregs.si:=(la_c+arg_ofs) mod 16;
         dosregs.es:=fcb1_la div 16;
         dosregs.di:=fcb1_la mod 16;
         msdos(dosregs);
         repeat
            inc(arg_ofs);
         until (c[arg_ofs]=' ') or
               (c[arg_ofs]=#9) or
               (c[arg_ofs]=#13);
         if c[arg_ofs]<>#13 then
           begin
              inc(arg_ofs);
              while (c[arg_ofs]=' ') or (c[arg_ofs]=#9) do inc(arg_ofs);
           end;
         { allocate second FCB see dosexec code }
         dosregs.ax:=$2901;
         dosregs.ds:=(la_c+arg_ofs) div 16;
         dosregs.si:=(la_c+arg_ofs) mod 16;
         dosregs.es:=fcb2_la div 16;
         dosregs.di:=fcb2_la mod 16;
         msdos(dosregs);
     	   with execblock do
      	  begin
      	     envseg:=la_env div 16;
      	     comtail.seg:=la_c div 16;
      	     comtail.ofs:=la_c mod 16;
      	     firstFCB.seg:=fcb1_la div 16;
      	     firstFCB.ofs:=fcb1_la mod 16;
      	     secondFCB.seg:=fcb2_la div 16;
      	     secondFCB.ofs:=fcb2_la mod 16;
      	  end;
       	seg_move(get_ds,longint(@execblock),dosmemselector,la_e,sizeof(texecblock));
         dosregs.edx:=la_p mod 16;
         dosregs.ds:=la_p div 16;
         dosregs.ebx:=la_e mod 16;
         dosregs.es:=la_e div 16;
         dosregs.ax:=$4b00;
         msdos(dosregs);
         if (dosregs.flags and 1) <> 0 then
           begin
              doserror:=dosregs.ax;
   	        lastdosexitcode:=0;
              exit;
           end
         else
           begin
              dosregs.ax:=$4d00;
              msdos(dosregs);
              lastdosexitcode:=dosregs.al;
           end;
        end;

      { var
         p,c : array[0..255] of char; }
        var  c : string;
      begin
         doserror:=0;
         { move(path[1],p,length(path));
         p[length(path)]:=#0; }
         move(comline[0],c[1],length(comline)+1);
         c[length(comline)+2]:=#13;
         c[0]:=char(length(comline)+2);
         do_system(path,c);
      end;

{$else GO32V2}

    procedure exec(const path : pathstr;const comline : comstr);

      procedure do_system(p : pchar);
        begin
           asm
              movl 12(%ebp),%ebx
              movw $0xff07,%ax
              int $0x21
              movw %ax,_LASTDOSEXITCODE
           end;
        end;

      var
         i : longint;
         execute : string;
         b : array[0..255] of char;

      begin
         doserror:=0;
         execute:=path+' '+comline;
         { allow slash as backslash for the program name only }
         for i:=1 to length(path) do
           if execute[i]='/' then execute[i]:='\';
         move(execute[1],b,length(execute));
         b[length(execute)]:=#0;
         do_system(b);
      end;

{$endif GO32V2}

    function dosexitcode : word;

      begin
         dosexitcode:=lastdosexitcode;
      end;

    function dosversion : word;

      begin
         dosregs.ax:=$3000;
         msdos(dosregs);
         dosversion:=dosregs.ax;
      end;

    procedure getdate(var year,month,day,dayofweek : word);

      begin
         dosregs.ax:=$2a00;
         msdos(dosregs);
         dayofweek:=dosregs.al;
         year:=dosregs.cx;
         month:=dosregs.dh;
         day:=dosregs.dl;
      end;

    procedure setdate(year,month,day : word);

      begin
         dosregs.cx:=year;
         dosregs.dx:=month*$100+day;
         dosregs.ah:=$2b;
         msdos(dosregs);
         doserror:=dosregs.al;
      end;

    procedure gettime(var hour,minute,second,sec100 : word);

      begin
         dosregs.ah:=$2c;
         msdos(dosregs);
         hour:=dosregs.ch;
         minute:=dosregs.cl;
         second:=dosregs.dh;
         sec100:=dosregs.dl;
      end;

    procedure settime(hour,minute,second,sec100 : word);

      begin
         dosregs.cx:=hour*$100+minute;
         dosregs.dx:=second*$100+sec100;
         dosregs.ah:=$2d;
         msdos(dosregs);
         doserror:=dosregs.al;
      end;

    procedure getcbreak(var breakvalue : boolean);

      begin
         dosregs.ax:=$3300;
         msdos(dosregs);
         breakvalue:=dosregs.dl<>0;
      end;

    procedure setcbreak(breakvalue : boolean);

      begin
         dosregs.ax:=$3301;
         dosregs.dl:=ord(breakvalue);
         msdos(dosregs);
      end;

    procedure getverify(var verify : boolean);

      begin
         dosregs.ah:=$54;
         msdos(dosregs);
         verify:=dosregs.al<>0;
      end;

    procedure setverify(verify : boolean);

      begin
         dosregs.ah:=$2e;
         dosregs.al:=ord(verify);
         msdos(dosregs);
      end;

    function diskfree(drive : byte) : longint;

      begin
         dosregs.dl:=drive;
         dosregs.ah:=$36;
         msdos(dosregs);
         if dosregs.ax<>$FFFF then
           begin
              diskfree:=dosregs.ax;
              diskfree:=diskfree*dosregs.bx;
              diskfree:=diskfree*dosregs.cx;
           end
         else
           diskfree:=-1;
      end;

    function disksize(drive : byte) : longint;

      begin
         dosregs.dl:=drive;
         dosregs.ah:=$36;
         msdos(dosregs);
         if dosregs.ax<>$FFFF then
           begin
              disksize:=dosregs.ax;
              disksize:=disksize*dosregs.cx;
              disksize:=disksize*dosregs.dx;
           end
         else
           disksize:=-1;
      end;

    procedure searchrec2dossearchrec(var f : searchrec);

      var
         l,i : longint;

      begin
         l:=length(f.name);
         for i:=1 to 12 do
           f.name[i-1]:=f.name[i];
         f.name[l]:=#0;
      end;

    procedure dossearchrec2searchrec(var f : searchrec);

      var
         l,i : longint;

      begin
         l:=12;
         for i:=0 to 12 do
           if f.name[i]=#0 then
             begin
                l:=i;
                break;
             end;
         for i:=11 downto 0 do
           f.name[i+1]:=f.name[i];
         f.name[0]:=chr(l);
      end;

    procedure findfirst(const path : pathstr;attr : word;var f : searchRec);

{$ifdef GO32V2}

      procedure _findfirst(path : pchar;attr : word;var f : searchrec);

        var
           i : longint;
        begin
           { allow slash as backslash }
           for i:=0 to strlen(path) do
             if path[i]='/' then path[i]:='\';
           copytodos(f,sizeof(searchrec));
           dosregs.edx:=transfer_buffer mod 16;
           dosregs.ds:=transfer_buffer div 16;
           dosregs.ah:=$1a;
           msdos(dosregs);
           dosregs.ecx:=attr;
           dosregs.edx:=(transfer_buffer mod 16) + Sizeof(searchrec)+1;
           dosmemput(transfer_buffer div 16,
             (transfer_buffer mod 16) +Sizeof(searchrec)+1,path^,strlen(path)+1);
           dosregs.ds:=transfer_buffer div 16;
	   dosregs.ah:=$4e;
           msdos(dosregs);
           copyfromdos(f,sizeof(searchrec));
           if dosregs.flags and carryflag<>0 then
             doserror:=dosregs.ax;
        end;

{$else GO32V2}

      procedure _findfirst(path : pchar;attr : word;var f : searchrec);

        var
           i : longint;
        begin
           { allow slash as backslash }
           for i:=0 to strlen(path) do
             if path[i]='/' then path[i]:='\';
           asm
              movl 18(%ebp),%edx
              movb $0x1a,%ah
              int $0x21
              movl 12(%ebp),%edx
              movzwl 16(%ebp),%ecx
              movb $0x4e,%ah
              int $0x21
              jnc .LFF
              movw %ax,U_DOS_DOSERROR
           .LFF:
           end;
        end;

{$endif GO32V2}

      var
         path0 : array[0..80] of char;

      begin
         { no error }
         doserror:=0;
         strpcopy(path0,path);
         _findfirst(path0,attr,f);
         dossearchrec2searchrec(f);
      end;

    procedure findnext(var f : searchRec);

{$ifdef GO32V2}

      procedure _findnext(var f : searchrec);

        begin
           copytodos(f,sizeof(searchrec));
           dosregs.edx:=transfer_buffer mod 16;
           dosregs.ds:=transfer_buffer div 16;
	        dosregs.ah:=$1a;
           msdos(dosregs);
	        dosregs.ah:=$4f;
           msdos(dosregs);
           copyfromdos(f,sizeof(searchrec));
           if dosregs.flags and carryflag <> 0 then
             doserror:=dosregs.ax;
        end;

{$else GO32V2}

      procedure _findnext(var f : searchrec);

        begin
           asm
              movl 12(%ebp),%edx
              movb $0x1a,%ah
              int $0x21
              movb $0x4f,%ah
              int $0x21
              jnc .LFN
              movw %ax,U_DOS_DOSERROR
           .LFN:
           end;
        end;

{$endif GO32V2}

      begin
         { no error }
         doserror:=0;
         searchrec2dossearchrec(f);
         _findnext(f);
         dossearchrec2searchrec(f);
      end;

    procedure swapvectors;

{$ifdef go32v2}
{ uses four global symbols from v2prt0.as
  to be able to know the current exception state
  without using dpmiexcp unit }
      begin
         asm
            movl _exception_exit,%eax
            orl  %eax,%eax
            je   .Lno_excep
            movl _v2prt0_exceptions_on,%eax
            orl  %eax,%eax
            je   .Lexceptions_off
            movl _swap_out,%eax
            call *%eax
            jmp  .Lno_excep
         .Lexceptions_off:
            movl _swap_in,%eax
            call *%eax
         .Lno_excep:
         end;
      end;
{$else not go32v2}
      begin
         { only a dummy }
      end;
{$endif go32v2}

    type
       ppchar = ^pchar;

{$ifdef GO32V1}

    function envs : ppchar;

      begin
         asm
            movl _environ,%eax
            leave
            ret
         end ['EAX'];
      end;

{$endif}

    function envcount : longint;

      var
         hp : ppchar;

      begin
{$ifdef GO32V2}
         hp:=environ;
{$else GO32V2}
         hp:=envs;
{$endif}
         envcount:=0;
         while assigned(hp^) do
           begin
              { not the best solution, but quite understandable }
              inc(envcount);
              hp:=hp+4;
           end;
      end;

    function envstr(index : longint) : string;

      var
         hp : ppchar;

      begin
         if (index<=0) or (index>envcount) then
           begin
              envstr:='';
              exit;
           end;
{$ifdef GO32V2}
         hp:=environ+4*(index-1);
{$else GO32V2}
         hp:=envs+4*(index-1);
{$endif GO32V2}
         envstr:=strpas(hp^);
      end;

    function getenv(const envvar : string) : string;

      var
         hs,_envvar : string;
         eqpos,i : longint;

      begin
         _envvar:=upcase(envvar);
         getenv:='';
         for i:=1 to envcount do
           begin
              hs:=envstr(i);
              eqpos:=pos('=',hs);
              if copy(hs,1,eqpos-1)=_envvar then
                begin
                   getenv:=copy(hs,eqpos+1,length(hs)-eqpos);
                   exit;
                end;
           end;
      end;

    procedure fsplit(path : pathstr;var dir : dirstr;var name : namestr;
      var ext : extstr);

      var
         p1 : byte;
         i : longint;
      begin
         { allow slash as backslash }
         for i:=1 to length(path) do
             if path[i]='/' then path[i]:='\';
         { get drive name }
         p1:=pos(':',path);
         if p1>0 then
           begin
              dir:=path[1]+':';
              delete(path,1,p1);
           end
         else
           dir:='';
         { split the path and the name, there are no more path informtions }
         { if path contains no backslashes                                 }
         while true do
           begin
              p1:=pos('\',path);
              if p1=0 then
                break;
              dir:=dir+copy(path,1,p1);
              delete(path,1,p1);
           end;
         { try to find out a extension }
         p1:=pos('.',path);
         if p1>0 then
           begin
              ext:=copy(path,p1,4);
              delete(path,p1,length(path)-p1+1);
           end
         else
           ext:='';
         name:=path;
      end;

    function fexpand(const path : pathstr) : pathstr;

      function get_current_drive : byte;
      
        var
           r : registers;
           
        begin
           r.ah:=$19;
           msdos(r);
           get_current_drive:=r.al;
        end;           

       var
          s,pa : string[79];
          i,j : byte;

       begin
          { There are differences between FPKPascal and Turbo Pascal
            e.g. for the string 'D:\DEMO\..\HELLO' which isn't handled }
          getdir(0,s);
          pa:=upcase(path);
          { allow slash as backslash }
          for i:=1 to length(pa) do
             if pa[i]='/' then pa[i]:='\';
          if (ord(pa[0])>1) and (((pa[1]>='A') and (pa[1]<='Z')) and (pa[2]=':')) then
            begin
               { we must get the right directory }
               getdir(ord(pa[1])-ord('A')+1,s);
               if (ord(pa[0])>2) and (pa[3]<>'\') then
                 if pa[1]=s[1] then
                   pa:=s+'\'+copy (pa,3,length(pa))
                 else
                   pa:=pa[1]+':\'+copy (pa,3,length(pa))
            end
          else
            if pa[1]='\' then 
              pa:=s[1]+':'+pa
            else if s[0]=#3 then
              pa:=s+pa
            else
              pa:=s+'\'+pa;
        {First remove all references to '\.\'}
          while pos ('\.\',pa)<>0 do
           delete (pa,pos('\.\',pa),2);
        {Now remove also all references to '\..\' + of course previous dirs..}
          repeat
            i:=pos('\..\',pa);
            j:=i-1;
            while (j>1) and (pa[j]<>'\') do
             dec (j);
            delete (pa,j,i-j+3);
          until i=0;
        {Remove End . and \}
          if (length(pa)>0) and (pa[length(pa)]='.') then
           dec(byte(pa[0]));
          if (length(pa)>0) and (pa[length(pa)]='\') then
           dec(byte(pa[0]));
          fexpand:=pa;
       end;

     procedure packtime(var d : datetime;var time : longint);

       var
          zs : longint;

       begin
          time:=-1980;
          time:=time+d.year and 127;
          time:=time shl 4;
          time:=time+d.month;
          time:=time shl 5;
          time:=time+d.day;
          time:=time shl 16;
          zs:=d.hour;
          zs:=zs shl 6;
          zs:=zs+d.min;
          zs:=zs shl 5;
          zs:=zs+d.sec div 2;
          time:=time+(zs and $ffff);
       end;

     procedure unpacktime (time: longint; var d: datetime);

       begin
          d.sec:=(time and 31) * 2;
          time:=time shr 5;
          d.min:=time and 63;
          time:=time shr 6;
          d.hour:=time and 31;
          time:=time shr 5;
          d.day:=time and 31;
          time:=time shr 5;
          d.month:=time and 15;
          time:=time shr 4;
          d.year:=time + 1980;
       end;

{$ifdef GO32V2}

    procedure getfattr(var f;var attr : word);

      var
         r : registers;

      begin
         copytodos(filerec(f).name,strlen(filerec(f).name)+1);
         r.ax:=$4300;
         r.edx:=transfer_buffer mod 16;
         r.ds:=transfer_buffer div 16;
         msdos(r);
         if (r.flags and carryflag) <> 0 then
           doserror:=r.ax;
         attr:=r.cx;
      end;

    procedure setfattr(var f;attr : word);

      var
         r : registers;

      begin
         copytodos(filerec(f).name,strlen(filerec(f).name)+1);
         r.ax:=$4301;
         r.edx:=transfer_buffer mod 16;
         r.ds:=transfer_buffer div 16;
         r.cx:=attr;
         msdos(r);
         if (r.flags and carryflag) <> 0 then
           doserror:=r.ax;
      end;

{$else GO32V2}

    procedure getfattr(var f;var attr : word);

      var
         { to avoid problems }
         n : array[0..255] of char;
         r : registers;

      begin
         strpcopy(n,filerec(f).name);
         r.ax:=$4300;
         r.edx:=longint(@n);
         msdos(r);
         attr:=r.cx;
      end;

    procedure setfattr(var f;attr : word);

      var
         { to avoid problems }
         n : array[0..255] of char;
         r : registers;

      begin
         strpcopy(n,filerec(f).name);
         r.ax:=$4301;
         r.edx:=longint(@n);
         r.cx:=attr;
         msdos(r);
      end;

{$endif GO32V2}

end.

{
  $Log$
  Revision 1.1  1998-03-25 11:18:47  root
  Initial revision

  Revision 1.2  1998/03/10 13:23:56  florian
    * just a few things adapted to win32

  Revision 1.1  1998/03/09 23:19:12  florian
    + Initial revision, just copied from the DOS version
}
