| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719 | unit System;interface{$define FPC_IS_SYSTEM}{ The heap for MSDOS is implemented  in tinyheap.inc include file,  but it uses default SysGetMem names }{$define HAS_MEMORYMANAGER}{ define TEST_FPU_INT10 to force keeping local int10,  for testing purpose only }{$DEFINE FPC_INCLUDE_SOFTWARE_MUL}{$DEFINE FPC_INCLUDE_SOFTWARE_MOD_DIV}{$DEFINE FPC_USE_SMALL_DEFAULTSTACKSIZE}{ To avoid warnings in thread.inc code,  but value must be really given after  systemh.inc is included otherwise the  $mode switch is not effective }{ Use AnsiChar for files }{$define FPC_ANSI_TEXTFILEREC}{$define FPC_STDOUT_TRUE_ALIAS}{$ifdef NO_WIDESTRINGS}  { Do NOT use wide AnsiChar for files }  {$undef FPC_HAS_FEATURE_WIDESTRINGS}{$endif NO_WIDESTRINGS}{$I systemh.inc}{$I tnyheaph.inc}{$I portsh.inc}const  LineEnding = #13#10;  { LFNSupport is a variable here, defined below!!! }  DirectorySeparator = '\';  DriveSeparator = ':';  ExtensionSeparator = '.';  PathSeparator = ';';  AllowDirectorySeparators : set of AnsiChar = ['\','/'];  AllowDriveSeparators : set of AnsiChar = [':'];  { FileNameCaseSensitive and FileNameCasePreserving are defined separately below!!! }  maxExitCode = 255;  MaxPathLen = 256;const{ Default filehandles }  UnusedHandle    = $ffff;{ instead of -1, as it is a word value}  StdInputHandle  = 0;  StdOutputHandle = 1;  StdErrorHandle  = 2;  FileNameCaseSensitive : boolean = false;  FileNameCasePreserving: boolean = false;  CtrlZMarksEOF: boolean = true; (* #26 is considered as end of file *)  sLineBreak = LineEnding;  DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;{ Default memory segments (Tp7 compatibility) }  seg0040: Word = $0040;  segA000: Word = $A000;  segB000: Word = $B000;  segB800: Word = $B800;{ The value that needs to be added to the segment to move the pointer by  64K bytes (BP7 compatibility) }  SelectorInc: Word = $1000;var{ Mem[] support }  mem  : array[0..$7fff-1] of byte absolute $0:$0;  memw : array[0..($7fff div sizeof(word))-1] of word absolute $0:$0;  meml : array[0..($7fff div sizeof(longint))-1] of longint absolute $0:$0;{ C-compatible arguments and environment }  argc:smallint; //!! public name 'operatingsystem_parameter_argc';  argv:PPAnsiChar; //!! public name 'operatingsystem_parameter_argv';{ The DOS Program Segment Prefix segment (TP7 compatibility) }  PrefixSeg:Word;public name '__fpc_PrefixSeg';  SaveInt00: FarPointer;public name '__SaveInt00';  SaveInt10: FarPointer;public name '__SaveInt10';  SaveInt75: FarPointer;public name '__SaveInt75';  fpu_status: word;public name '__fpu_status';  AllFilesMask: string [3];{$ifndef RTLLITE}{ System info }  LFNSupport : boolean;{$ELSE RTLLITE}const  LFNSupport = false;{$endif RTLLITE}implementationprocedure DebugWrite(const S: shortstring); forward;procedure DebugWriteLn(const S: shortstring); forward;const  fCarry = 1;  { used for an offset fixup for accessing the proc parameters in asm routines    that use nostackframe. We can't use the parameter name directly, because    i8086 doesn't support sp relative addressing. }{$ifdef FPC_X86_CODE_FAR}  extra_param_offset = 2;{$else FPC_X86_CODE_FAR}  extra_param_offset = 0;{$endif FPC_X86_CODE_FAR}{$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}  extra_data_offset = 2;{$else}  extra_data_offset = 0;{$endif}type  PFarByte = ^Byte;far;  PFarChar = ^AnsiChar;far;  PFarWord = ^Word;far;  PPFarChar = ^PFarChar;var  __stktop : pointer;public name '__stktop';  __stkbottom : pointer;public name '__stkbottom';  __nearheap_start: pointer;public name '__nearheap_start';  __nearheap_end: pointer;public name '__nearheap_end';  dos_version:Word;public name 'dos_version';  dos_env_count:smallint;public name '__dos_env_count';  dos_argv0 : PFarChar;public name '__fpc_dos_argv0';{$I registers.inc}procedure Intr(IntNo: Byte; var Regs: Registers); external name 'FPC_INTR';procedure MsDos(var Regs: Registers); external name 'FPC_MSDOS';{ invokes int 21h with the carry flag set on entry; used for the LFN functions  to ensure that the carry flag is set on exit on older DOS versions which don't  support them }procedure MsDos_Carry(var Regs: Registers); external name 'FPC_MSDOS_CARRY';procedure InstallInterruptHandlers; external name 'FPC_INSTALL_INTERRUPT_HANDLERS';procedure RestoreInterruptHandlers; external name 'FPC_RESTORE_INTERRUPT_HANDLERS';function CheckNullArea: Boolean; external name 'FPC_CHECK_NULLAREA';var  test_fpu_jmpbuf : jmp_buf;Procedure InterceptInvalidInstruction;begin  longjmp(test_fpu_jmpbuf, 1);end;{ Use msdos int21 set/get Interrupt address  to check if coprocessor is present }{$define FPC_SYSTEM_HAS_SYSINITFPU}Procedure SysInitFPU;  const    CR0_NE = $20;    CR0_NOT_NE = $FFFF - CR0_NE;  var    prevInt06 : FarPointer;    _newcr0_lw : word;    restore_old_int10 : boolean;  begin    restore_old_int10:=false;    asm      fninit      fldcw   Default8087CW      fwait    end;    if Test8087 < 3 then { i8087/i80287 do not have "native" exception mode (CR0:NE) }      begin        restore_old_int10:=true;      end    else      begin        asm          push es          push ds          { Get previous interrupt 06 handler }          mov ax, $3506          int $21          mov word [prevInt06],bx          mov dx,es          mov word [prevInt06+2],dx          { Install local interrupt 06 handler }    {$ifdef FPC_MM_TINY}          { Do not use SEG here, as this introduces a relocation that            is incompatible with COM executable generation }          mov dx, cs    {$else FPC_MM_TINY}          mov dx, SEG InterceptInvalidInstruction    {$endif FPC_MM_TINY}          mov ds, dx          mov dx, Offset InterceptInvalidInstruction          mov ax, $2506          int $21          pop ds          pop es        end;        if setjmp(test_fpu_jmpbuf)=0 then          begin            asm              db $0f, $20, $c0 { mov eax,cr0 }              { Reset CR0  Numeric Error bit,                to trigger IRQ13 - interrupt $75,                and thus avoid the generation of a $10 trap                which iterferes with video interrupt handler }              and ax,CR0_NOT_NE              db $0f, $22, $c0 { mov cr0,eax }            end;            //writeln(stderr,'Change of cr0 succeeded');            // Test that NE bit is indeed reset            asm              db $0f, $20, $c0 { mov eax,cr0 }              mov _newcr0_lw, ax            end;            if (_newcr0_lw and CR0_NE) = 0 then              restore_old_int10:=true;          end        else          begin            //writeln(stderr,'Change of cr0 failed');          end;        { Restore previous interrupt 06 handler }        asm          push ds          mov ax, $2506          lds dx,[prevInt06]          int $21          pop ds        end;      end;      { Special handler of interrupt $10        not needed anymore        Restore previous interrupt $10 handler }      {$ifndef TEST_FPU_INT10}      if restore_old_int10 then        asm          push ds          mov ax, $2510          lds dx,[SaveInt10]          int $21          pop ds        end;      {$endif ndef TEST_FPU_INT10}  end;{$I system.inc}{$I tinyheap.inc}{$I ports.inc}procedure DebugWrite(const S: shortstring);begin  asm{$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}    push ds	lds si, S{$else}    mov si, S{$endif}{$ifdef FPC_ENABLED_CLD}    cld{$endif FPC_ENABLED_CLD}    lodsb    mov cl, al    xor ch, ch    jcxz @@zero_length    mov ah, 2@@1:    lodsb    mov dl, al    int 21h    loop @@1@@zero_length:{$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}    pop ds{$endif}  end ['ax','bx','cx','dx','si','di'];end;procedure DebugWriteLn(const S: shortstring);begin  DebugWrite(S);  DebugWrite(#13#10);end;{*****************************************************************************                              ParamStr/Randomize*****************************************************************************}var  internal_envp : PPFarChar = nil;procedure setup_environment;var  env_count : smallint;  cp, dos_env: PFarChar;begin  env_count:=0;  dos_env:=Ptr(MemW[PrefixSeg:$2C], 0);  cp:=dos_env;  while cp^<>#0 do    begin      inc(env_count);      while (cp^ <> #0) do        inc(cp); { skip to NUL }      inc(cp); { skip to next character }    end;  internal_envp := getmem((env_count+1) * sizeof(PFarChar));  cp:=dos_env;  env_count:=0;  while cp^<>#0 do    begin      internal_envp[env_count] := cp;      inc(env_count);      while (cp^ <> #0) do        inc(cp); { skip to NUL }      inc(cp); { skip to next character }    end;  internal_envp[env_count]:=nil;  dos_env_count := env_count;  if dos_version >= $300 then    begin      if cp=dos_env then        inc(cp);      inc(cp, 3);      dos_argv0 := cp;    end  else    dos_argv0 := nil;end;function envp:PPFarChar;public name '__fpc_envp';begin  if not assigned(internal_envp) then    setup_environment;  envp:=internal_envp;end;procedure setup_arguments;var  I: SmallInt;  pc: PAnsiChar;  pfc: PFarChar;  quote: AnsiChar;  count: SmallInt;  arglen, argv0len: SmallInt;  argblock: PAnsiChar;  arg: PAnsiChar;  doscmd   : string[129];  { Dos commandline copied from PSP, max is 128 chars +1 for terminating zero }begin  { force environment to be setup so dos_argv0 is loaded }  envp;  { load commandline from psp }  SetLength(doscmd, Mem[PrefixSeg:$80]);  for I := 1 to length(doscmd) do    doscmd[I] := Chr(Mem[PrefixSeg:$80+I]);  doscmd[length(doscmd)+1]:=#0;{$IfDef SYSTEM_DEBUG_STARTUP}  Writeln(stderr,'Dos command line is #',doscmd,'# size = ',length(doscmd));{$EndIf }  { find argv0len }  argv0len:=0;  if dos_argv0<>nil then    begin      pfc:=dos_argv0;      while pfc^<>#0 do        begin          Inc(argv0len);          Inc(pfc);        end;    end;  { parse dos commandline }  pc:=@doscmd[1];  count:=1;  { calc total arguments length and count }  arglen:=argv0len+1;  while pc^<>#0 do    begin      { skip leading spaces }      while pc^ in [#1..#32] do        inc(pc);      if pc^=#0 then        break;      { calc argument length }      quote:=' ';      while (pc^<>#0) do        begin          case pc^ of            #1..#32 :              begin                if quote<>' ' then                  inc(arglen)                else                  break;              end;            '"' :              begin                if quote<>'''' then                  begin                    if PAnsiChar(pc+1)^<>'"' then                      begin                        if quote='"' then                          quote:=' '                        else                          quote:='"';                      end                    else                     inc(pc);                  end                else                  inc(arglen);              end;            '''' :              begin                if quote<>'"' then                  begin                    if PAnsiChar(pc+1)^<>'''' then                      begin                        if quote=''''  then                         quote:=' '                        else                         quote:='''';                      end                    else                      inc(pc);                  end                else                  inc(arglen);              end;            else              inc(arglen);          end;          inc(pc);        end;      inc(arglen);  { for the null terminator }      inc(count);    end;  { set argc and allocate argv }  argc:=count;  argv:=AllocMem((count+1)*SizeOf(PAnsiChar));  { allocate a single memory block for all arguments }  argblock:=GetMem(arglen);  { create argv[0] }  argv[0]:=argblock;  arg:=argblock;  if dos_argv0<>nil then    begin      pfc:=dos_argv0;      while pfc^<>#0 do        begin          arg^:=pfc^;          Inc(arg);          Inc(pfc);        end;    end;  arg^:=#0;  Inc(arg);  pc:=@doscmd[1];  count:=1;  while pc^<>#0 do    begin      { skip leading spaces }      while pc^ in [#1..#32] do        inc(pc);      if pc^=#0 then        break;      { copy argument }      argv[count]:=arg;      quote:=' ';      while (pc^<>#0) do        begin          case pc^ of            #1..#32 :              begin                if quote<>' ' then                  begin                    arg^:=pc^;                    inc(arg);                  end                else                  break;              end;            '"' :              begin                if quote<>'''' then                  begin                    if PAnsiChar(pc+1)^<>'"' then                      begin                        if quote='"' then                          quote:=' '                        else                          quote:='"';                      end                    else                      inc(pc);                  end                else                  begin                    arg^:=pc^;                    inc(arg);                  end;              end;            '''' :              begin                if quote<>'"' then                  begin                    if PAnsiChar(pc+1)^<>'''' then                      begin                        if quote=''''  then                          quote:=' '                        else                          quote:='''';                      end                    else                      inc(pc);                  end                else                  begin                    arg^:=pc^;                    inc(arg);                  end;              end;            else              begin                arg^:=pc^;                inc(arg);              end;          end;          inc(pc);        end;      arg^:=#0;      Inc(arg); {$IfDef SYSTEM_DEBUG_STARTUP}      Writeln(stderr,'dos arg ',count,' #',strlen(argv[count]),'#',argv[count],'#'); {$EndIf SYSTEM_DEBUG_STARTUP}      inc(count);    end;end;function paramcount : longint;begin  if argv=nil then    setup_arguments;  paramcount := argc - 1;end;function paramstr(l : longint) : shortstring;begin  if argv=nil then    setup_arguments;  if (l>=0) and (l+1<=argc) then    paramstr:=strpas(argv[l])  else    paramstr:='';end;procedure randomize;var  hl   : longint;  regs : Registers;begin  regs.AH:=$2C;  MsDos(regs);  hl:=regs.DX;  randseed:=hl*$10000+ regs.CX;end;{*****************************************************************************                         System Dependent Exit code*****************************************************************************}procedure system_exit;var  h : byte;begin  RestoreInterruptHandlers;  for h:=0 to max_files-1 do    if openfiles[h] then      begin{$ifdef SYSTEMDEBUG}         writeln(stderr,'file ',h,' "',opennames[h],'" not closed at exit');{$endif SYSTEMDEBUG}         if h>=5 then           do_close(h);      end;{$ifndef FPC_MM_TINY}  if not CheckNullArea then    writeln(stderr, 'Nil pointer assignment');{$endif FPC_MM_TINY}  asm    mov al, byte [exitcode]    mov ah, 4Ch    int 21h  end;end;{*****************************************************************************                         SystemUnit Initialization*****************************************************************************}procedure InitDosHeap;type{$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}  TPointerArithmeticType = HugePointer;{$else}  TPointerArithmeticType = Pointer;{$endif}begin  RegisterTinyHeapBlock_Simple_Prealigned(__nearheap_start, TPointerArithmeticType(__nearheap_end) - TPointerArithmeticType(__nearheap_start));end;function CheckLFN:boolean;var  regs     : Registers;  RootName : PAnsiChar;  buf      : array [0..31] of AnsiChar;begin{ Check LFN API on drive c:\ }  RootName:='C:\';{ Call 'Get Volume Information' ($71A0) }  regs.AX:=$71a0;  regs.ES:=Seg(buf);  regs.DI:=Ofs(buf);  regs.CX:=32;  regs.DS:=Seg(RootName^);  regs.DX:=Ofs(RootName^);  MsDos_Carry(regs);{ If carryflag=0 and LFN API bit in ebx is set then use Long file names }  CheckLFN:=(regs.Flags and fCarry=0) and (regs.BX and $4000=$4000);end;procedure SysInitStdIO;begin  OpenStdIO(Input,fmInput,StdInputHandle);  OpenStdIO(Output,fmOutput,StdOutputHandle);  OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);{$ifndef FPC_STDOUT_TRUE_ALIAS}  OpenStdIO(StdOut,fmOutput,StdOutputHandle);  OpenStdIO(StdErr,fmOutput,StdErrorHandle);{$endif FPC_STDOUT_TRUE_ALIAS}end;function GetProcessID: SizeUInt;begin  GetProcessID := PrefixSeg;end;function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;begin  result := stklen;end;begin  StackBottom := __stkbottom;  StackLength := __stktop - __stkbottom;  InstallInterruptHandlers;  DetectFPU;  if Test8087>0 then    SysInitFPU;  { To be set if this is a GUI or console application }  IsConsole := TRUE;{$ifdef FPC_HAS_FEATURE_DYNLIBS}  { If dynlibs feature is disabled,    IsLibrary is a constant, which can thus not be set to a value }  { To be set if this is a library and not a program  }  IsLibrary := FALSE;{$endif def FPC_HAS_FEATURE_DYNLIBS}{ Setup heap }  InitDosHeap;  SysInitExceptions;{$ifdef FPC_HAS_FEATURE_UNICODESTRINGS}  initunicodestringmanager;{$endif def FPC_HAS_FEATURE_UNICODESTRINGS}{ Setup stdin, stdout and stderr }  SysInitStdIO;{ Setup environment and arguments }  { Done on  request only Setup_Environment; }  { Done on request only Setup_Arguments; }{$ifndef RTLLITE}{ Use LFNSupport LFN }  LFNSupport:=CheckLFN;  if LFNSupport then   begin    FileNameCasePreserving:=true;    AllFilesMask := '*';   end  else{$endif ndef RTLLITE}   AllFilesMask := '*.*';{ Reset IO Error }  InOutRes:=0;{$ifdef FPC_HAS_FEATURE_THREADING}  InitSystemThreads;{$endif}end.
 |