XVIII.  

JEDNOTKA  DOS


Jednotka Dos implementuje řadu podprogramů na bázi rutin operačního systému, především pro práci se soubory na disku. Tato kapitola uvádí jejich vybranou podmnožinu.

XVIII.1. 

Ošetření chybových stavů

Chybové stavy procedur a funkcí implementovaných jednotkou Dos jsou automaticky ošetřeny tak, že nenastane chyba běhu programu (program běží dál) a číslo chybového stavu je uloženo do proměnné DosError. Další ošetření chyby je tak zcela v kompetenci programu.

var DosError: Integer;

Obsahuje číslo chyby, vrácené operačním systémem při posledním volání některého z podprogramů jednotky Dos. Nejčastější hodnoty jsou:

  kód     popis chyby  
žádná chyba, vše v pořádku
soubor nenalezen
cesta nenalezena
přístup zakázán
nedostatečná paměť
18  další soubory neexistují

XVIII.2. 

Ovládání systémových hodin

Následujícími procedurami jednotky Dos lze zjišťovat i nastavovat datum a čas na systémových hodinách počítače.

procedure GetTime (var Hod, Min, Sec, Sec100: Word);
procedure SetTime (Hod, Min, Sec, Sec100: Word);

Procedura GetTime resp. SetTime čte resp. nastavuje aktuální čas, vyjádřený čtveřicí celočíselných parametrů: Hod (hodina, 0 .. 23), Min (minuta, 0 .. 59), Sec (sekunda, 0 .. 59) a Sec100 (setina sekundy, 0 .. 99). Pokus o nastavení neplatného času, kdy je hodnota některého z parametrů mimo uvedený rozsah, nemá žádný efekt.

procedure GetDate (var Rok, Mes, Den, DenTydne: Word);
procedure SetDate (Rok, Mes, Den: Word);

Procedura GetDate resp. SetDate čte resp. nastavuje aktuální datum, vyjádřené čtveřicí resp. trojicí celočíselných parametrů: Rok (rok, 1980 .. 2099), Mes (měsíc, 1 .. 12), Den (den, 1 .. 31) a DenTydne (pořadí dne v týdnu, 0 .. 6, kde 0 je neděle). Pokus o nastavení neplatného data (například 29.2.1993) nemá žádný efekt.


PŘÍKLAD: Program DateTimeInfo vypíše na displej informaci o aktuálním stavu systémových hodin (čas i datum).

{======================================================================}
program DateTimeInfo;
{======================================================================}

 uses Dos;

 const Tyden : array [0..6] of string[7]     { názvy dnů, odpovídající }
             = ('neděle', 'pondělí', 'úterý',{ číslům dnů v týdnu,     }
                'středa', 'čtvrtek', 'pátek',{ vráceným procedurou     }
                'sobota');                   { GetDate                 }

 var   Rok, Mes, Den, DenTydne,              { rok, měsíc, den         }
                                             { a pořadí dne v týdnu    }
       Hod, Min, Sec, Sec100    : Word;      { hodina, minuta, sekunda }
                                             { a setina sekundy        }

begin { program }
 GetDate(Rok, Mes, Den, DenTydne);           { načtení data a času ze  }
 GetTime(Hod, Min, Sec, Sec100);             { systémových hodin       }
 WriteLn(Hod, ':', Min, ':', Sec, ',',       { výpis                   }
         Sec100, ' hodin, ', Tyden[DenTydne],
         ' ', Den, '.', Mes, '.', Rok)
end. { program }

XVIII.3. 

Atributy diskových souborů

Obsah diskového adresáře definuje operační systém seznamem jistých položek. Položka identifikuje diskový soubor, adresář nebo návěští disku (definované například systémovým příkazem label). Základní vlastnosti — atributy — položky definuje její byte atributů:

  bit     atribut  
0 pouze pro čtení (read-only)
1 skrytý (hidden)
2 systémový (system)
3 návěští disku (volume label)
4 adresář (directory)
5 archivní (archive)

Atribut je nastaven, pokud odpovídající bit má hodnotu 1. Například soubor, jehož byte atributů má hodnotu 35 (tj. binárně 00100011), má nastaveny atributy pouze pro čtení, skrytýarchivní.

Význam jednotlivých atributů definuje operační systém. Nastavený atribut pouze pro čtení znemožňuje modifikaci souboru (používá se především pro ochranu souboru před nechtěným smazáním), skrytý umožňuje skrýt soubor před vyhledáním (například příkazem dir), atributem systémový jsou označeny soubory, obsahující operační systém (tento atribut rovněž činí soubor neviditelným při vyhledávání), atribut návěští disku resp. adresář oznamuje, že daná položka není soubor, nýbrž návěští disku resp. adresář, a atribut archivní se používá pro označení datových souborů, určených pro archivaci (příkazem backup operačního systému). Soubory mohou mít nastaveny jen atributy pouze pro čtení, skrytý, systémovýarchivní, kdežto adresáře resp. návěští disku mají vždy nastaven pouze atribut adresář resp. návěští disku.

Čtení a modifikaci hodnoty bytu atributů vybraného souboru umožňují procedury GetFAttrSetFAttr jednotky Dos.

procedure GetFAttr (var F: soubor; var Atribut: Word);
procedure SetFAttr (var F: soubor; Atribut: Word);

Procedura GetFAttr resp. SetFAttr přečte do parametru Atribut resp. nastaví na hodnotu parametru Atribut byte atributů diskového souboru (nebo adresáře), spojeného s proměnnou F (libovolného typu soubor).

const ReadOnly  = $01;     { 00000001 - pouze pro čtení }
      Hidden    = $02;     { 00000010 - skrytý          }
      SysFile   = $04;     { 00000100 - systémový       }
      VolumeID  = $08;     { 00001000 - návěští disku   }
      Directory = $10;     { 00010000 - adresář         }
      Archive   = $20;     { 00100000 - archivní        }
      AnyFile   = $3F;     { 00111111 - libovolný       }

Výše uvedené konstanty (deklarované jednotkou Dos) mohou být využity pro snadné nastavení nebo testování hodnoty bytu atributů. Kombinaci dílčích atributů lze získat součtem příslušných konstant. Například hodnotou výrazu ReadOnly + Archive je číslo $21 (binárně tedy 00100001), odpovídající současně nastaveným atributům pouze pro čteníarchivní.


PŘÍKLAD: Vstupem následujícího programu je systémová specifikace souboru nebo adresáře. Program se pokusí zjistit hodnotu jeho bytu atributů a v případě úspěchu (tj. při platnosti DosError = 0) vypíše seznam nastavených atributů.

{======================================================================}
program TestAtributu;
{======================================================================}

 uses Dos;
 var  Spec  : string;         { cesta k diskovému soboru nebo adresáři }
      F     : file;           { identifikace souboru nebo adresáře     }
      A     : Word;           { byte atributů                          }
      Bin   : string [6];     { znaky binární reprezentace atributů    }
      AA, I : Byte;           { pomocné proměnné                       }

begin { program }
 WriteLn;                                 { titulek programu           }
 WriteLn('ATRIBUTY SOUBORU');
 WriteLn;
 Write('soubor   : ');                    { inicializace souboru F     }
 ReadLn(Spec);
 Assign(F, Spec);
 GetFAttr(F, A);                          { pokus o načtení atributů   }
 if DosError = 0 then                     { byl-li úspěšný             }
  begin
   AA := A;
   Write('atributy : ');                  { výpis binární reprezentace }
   for I := 6 downto 1 do                 { šesti významných bitů bytu }
    begin                                 { atributů                   }
     Bin[I] := Chr(AA mod 2 + Ord('0'));
     AA := AA div 2
    end;
   Bin[0] := #6;
   Write(Bin);
   if A and Directory <> 0 then           { je-li F adresář            }
    Write(' Directory ')
   else                                   { je-li F soubor             }
    begin
     if A and ReadOnly <> 0 then          { ReadOnly                   }
      Write(' ReadOnly ');
     if A and Hidden   <> 0 then          { Hidden                     }
      Write(' Hidden ');
     if A and SysFile  <> 0 then          { SysFile                    }
      Write(' SysFile ');
     if A and Archive  <> 0 then          { Archive                    }
      Write(' Archive ')
    end;
   WriteLn
  end
 else
  WriteLn('chyba ', DosError)             { výpis čísla chyby          }
end. { program }

XVIII.4. 

Prohledávání adresářů

Položky lze vyhledávat na disku podle jejich systémové specifikace a atributů. Vyhledávací rutiny operačního systému lze volat procedurami FindFirstFindNext jednotky Dos, které vracejí údaje o nalezené položce v parametru typu SearchRec, rovněž deklarovaného jednotkou Dos.

type SearchRec = record
                  Fill: array [1..21] of Byte;
                  Attr: Byte;
                  Time: LongInt;
                  Size: LongInt;
                  Name: string [12]
                 end;

Name obsahuje jméno nalezené položky (včetně přípony), Size velikost nalezeného souboru v bytech (resp. nulu, pokud je nalezenou položkou adresář nebo návěští disku), Time časový údaj o poslední modifikaci položky (v komprimovaném tvaru) a Attr její byte atributů. Pole Fill slouží pro vnitřní potřeby vyhledávacích rutin operačního systému.

procedure FindFirst (Spec: string; Atribut: Word; var Info: SearchRec);

Vyhledá na disku první výskyt položky, vyhovující vyhledávacímu kritériu, definovanému zadanými hodnotami parametrů SpecAtribut. Při kladném výsledku hledání je hodnotou proměnné DosError nula a procedura vrací údaje o nalezené položce v parametru Info. Pokud naopak vyhovující položka v prohledávaném adresáři neexistuje (DosError = 18) nebo byla v parametru Spec (viz níže) zadána chybná či neexistující cesta (DosError = 3), je hodnota parametru Info nedefinovaná.

Hodnotou parametru Spec je maska systémové specifikace hledané položky — cesta k prohledávanému adresáři a maska jména a přípony jeho hledané položky, která smí na rozdíl od konkrétního jména a přípony obsahovat i expanzní znaky operačního systému (wildcards) hvězdička a otazník. Například masce 'c:\b??k.*' vyhovují všechny položky kořenového adresáře na disku C, jejichž jméno je tvořeno čtyřmi znaky, z nichž první je písmeno „b“ a poslední písmeno „k“. Dva prostřední znaky a celá přípona jména položky mohou být libovolné.

Hodnotou parametru Atribut je maska bytu atributů hledané položky. Významné jsou pouze atributy skrytý, systémový, adresářnávěští disku (na hodnotách atributů pouze pro čteníarchivní nezáleží). „Obyčejné“ soubory jsou tedy vyhledávány vždy, kdežto vyhledávání „speciálních“ souborů skrytých resp. systémových, adresářů a položky návěští disku je nutno povolit nastavením příslušného atributu v masce.

Při prohledávání kořenového adresáře disku mohou být nalezeny v něm uložené soubory, jeho podadresáře i návěští disku. Položkou ostatních adresářů návěští disku není, zato výčet jejich podadresářů je rozšířen o dvě položky, které kořenový adresář neobsahuje — odkaz na nadřízený adresář (..) a odkaz na kořenový adresář (.).


POZNÁMKA: Návěští disku může být standardně nalezeno pouze v kořenovém adresáři disku, spolu s ostatními vyhovujícími položkami. Pokud však maska bytu atributů obsahuje (z významných atributů) pouze atribut návěští disku, vyhledávání ostatních vyhovujících položek (souborů a adresářů) se neprovádí a cesta v masce systémové specifikace je ignorována — návěští pak může být nalezeno i v jiných adresářích disku (vyhovuje-li zbytku masky systémové specifikace).

procedure FindNext (var Info: SearchRec);

Vyhledá další vyhovující položku podle kritéria, definovaného ve volání procedury FindFirst (potřebné údaje jsou při postupném vyhledávání položek průběžně uchovávány a aktualizovány v položce Fill parametru Info. Pokud další vyhovující položka neexistuje, je nastavena hodnota proměnné DosError na 18.

Typický způsob použití vyhledávacích procedur FindFirstFindNext demonstruje následující schéma:

uses Dos;
var  Info: SearchRec;
...
FindFirst (..., Info);  { vyhledání první položky   }
while DosError = 0 do   { dokud je položka nalezena }
 begin
  ...                   { zpracování údajů Info     }
                        { o nalezené položce        }
  FindNext (Info)       { vyhledání další položky   }
 end;
...

XVIII.5. 

Časový údaj o poslední aktualizaci souboru

Pro zpřístupnění časového údaje o vytvoření resp. poslední aktualizaci souboru a jeho převodu ze zkomprimovaného do nezkomprimovaného tvaru a naopak (údaj je na disku uchováván z úsporných důvodů v komprimovaném tvaru) jsou jednotkou Dos implementovány následující prostředky:

procedure GetFTime (var F: soubor; var DatCas: LongInt);
procedure SetFTime (var F: soubor; DatCas: LongInt);

Procedura GetFTime resp. SetFTime přečte do parametru DatCas resp. aktualizuje jeho hodnotou komprimovaný časový údaj o poslední aktualizaci souboru, spojeného s parametrem F (proměnná libovolného typu soubor). Soubor musí být v okamžiku volání procedury otevřen (jinak není vrácený údaj platný resp. k aktualizaci nedojde).

type DateTime = record
                 Year, Month, Day,
                 Hour, Min,   Sec: Word
                end;

Typ DateTime popisuje strukturu časového údaje o poslední aktualizaci souboru, dekomprimovaného procedurou UnPackTime nebo předávaného ke komprimaci proceduře PackTime.

procedure UnpackTime (Zapak: LongInt; var Rozpak: DateTime);
procedure PackTime (var Rozpak: DateTime; var Zapak: LongInt);

Procedura UnPackTime konvertuje hodnotu vstupního zkomprimovaného časového údaje Zapak na dekomprimovaný tvar, který vrací v parametru Rozpak. Procedura PackTime provádí obrácenou konverzi.

XVIII.6. 

Zpracování systémové specifikace souboru

Úplná systémová specifikace diskového souboru se skládá ze tří částí — cesty k adresáři, jména a přípony. V programech se poměrně často vyskytuje potřeba rozložit uživatelem zadanou specifikaci na uvedené části a zpracovat je odděleně. Pro tyto případy implementuje jednotka Dos následující prostředky:

type PathStr : string [79];   { úplná syst. specifikace }
     DirStr  : string [67];   { cesta k adresáři        }
     NameStr : string [8];    { jméno souboru           }
     ExtStr  : string [4];    { přípona (včetně tečky)  }

Jednotkou předdeklarované řetězcové typy pro popis systémové specifikace a jejích částí, které využívají procedury FSplitFExpand.

procedure FSplit (Spec: PathStr; var Cesta: DirStr;
                  var Jmeno: NameStr; var Prip: ExtStr);

Rozloží zadanou systémovou specifikaci souboru na adresář, jméno a příponu. Není kontrolována syntax ani existence cesty.

function FExpand (Spec: PathStr): PathStr;

Vrací úplnou systémovou specifikaci souboru, získanou rozšířením zadané specifikace Spec podle skutečné struktury adresářů na disku (chybějící části cesty doplní podle cesty k aktuálnímu adresáři aktuálního disku). Parametr smí obsahovat i expanzní znaky (wildcards) hvězdička a otazník.


PŘÍKLAD: Následující program je inspirován systémovým příkazem dir. Z příkazové řádky převezme masku souboru, vypíše návěští disku, expandovanou masku a odpovídající seznam souborů a podadresářů. Každému souboru odpovídá ve výpisu jedna řádka, obsahující jeho jméno a příponu, nastavení atributů, datum a čas poslední aktualizace a velikost v bytech. Ve výpisu podadresáře je namísto seznamu atributů uvedeno označení <DIR>.

{======================================================================}
program Dir;
{======================================================================}

 uses Dos;
 var  S       : SearchRec;               { vyhledávací proměnná        }
      Maska   : string;                  { maska systémové specifikace }
                                         { vyhledávaných položek       }
      Adresar : DirStr;                  { cesta k adresáři            }
      Jmeno   : NameStr;                 { jméno                       }
      Pripona : ExtStr;                  { přípona                     }
      T       : DateTime;                { datum a čas poslední        }
                                         { aktualizace souboru         }

begin { program }
 WriteLn;                                { prázdná řádka               }
 Maska := ParamStr(1);                   { převzetí masky z příkazové  }
 if Maska = '' then                      { řádky resp. nastavení její  }
  Maska := '*.*';                        { implicitní hodnoty          }
 FSplit(FExpand(Maska),                  { rozložení expandované masky }
        Adresar, Jmeno, Pripona);        { na adresář, jméno a příponu }
 WriteLn('soubory ',                     { výpis expandované masky     }
         Adresar, Jmeno, Pripona);
 FindFirst(Adresar + '*.*', VolumeID, S);{ vyhledání návěští disku     }
 if (DosError <> 0) and (DosError <> 18) { vyskytla se nějaká chyba    }
  then                                   { (např. není disk v jednotce)}
   begin
    WriteLn('chyba ', DosError, ' !');   { výpis chybového hlášení     }
    Halt                                 { ukončení běhu programu      }
   end;
 Write('disk v jednotce ', Adresar[1],   { výpis úvodní části údaje    }
       ' je ');                          { o návěští disku             }
 if DosError = 0 then                    { bylo-li návěští nalezeno    }
  with S do
   begin
    Delete(Name, 9, 1);                  { odstranění tečky přípony    }
                                         { z návěští                   }
    WriteLn(Name);                       { výpis návěští               }
   end
 else { DosError = 18 }                  { nebylo-li návěští nalezeno  }
  WriteLn('nepojmenovaný');
 WriteLn;                                { prázdná řádka               }
 FindFirst(Maska, AnyFile - VolumeID, S);{ vyhledání první vyhovující  }
                                         { položky                     }
 while DosError = 0 do                   { dokud položka existuje      }
  begin
   with S do
    begin
     Write(Name, '':15 - Length(Name));  { tisk jména položky a mezery }
     if Attr and Directory <> 0 then     { je-li položka adresářem     }
      Write('<DIR>')                     { tisk označení <DIR>         }
     else                                { položka je soubor           }
      begin                              { tisk atributů souboru       }
       if Attr and Archive <> 0          { archivní                    }
        then Write('A')
        else Write('-');
       if Attr and SysFile <> 0          { systémový                   }
        then Write('S')
        else Write('-');
       if Attr and Hidden <> 0           { skrytý                      }
        then Write('H')
        else Write('-');
       if Attr and ReadOnly <> 0         { pouze pro čtení             }
        then Write('R')
        else Write('-');
       Write(' ')                        { dorovnání na šířku <DIR>    }
      end;
     Write('':3);                        { mezera                      }
     UnpackTime(Time, T);                { dekomprimace časového údaje }
                                         { o poslední aktualizaci      }
     with T do
      begin                              { zarovnaný výpis údaje       }
       if Day < 10 then Write('0');      { datum                       }
       Write(Day, '.');
       if Month < 10 then Write('0');
       Write(Month, '.', Year, '':3);
       if Hour < 10 then Write('0');     { čas                         }
       Write(Hour, ':');
       if Min < 10 then Write('0');
       Write(Min, ':');
       if Sec < 10 then Write('0');
       Write(Sec, '':3)
      end;
     Write(Size:8, 'B');                 { výpis velikosti položky     }
     WriteLn                             { konec řádky tabulky         }
    end;
   FindNext(S)                           { vyhledání další položky     }
  end;                                   { konec cyklu while           }
 if (DosError <> 18) then                { vyskytla se nějaká chyba    }
  WriteLn('chyba ', DosError, ' !');     { při vyhledávání položek     }
 WriteLn                                 { prázdná řádka               }
end. { program }

Příklad výpisu :

soubory C:\*.*
disk v jednotce C je SYSTEM DISK

IO.SYS         -SHR    09.04.1991   05:00:00      33430B
MSDOS.SYS      -SHR    09.04.1991   05:00:00      37394B
COMMAND.COM    ----    09.04.1991   05:00:00      47845B
NC             <DIR>   09.01.1991   11:31:56          0B
SYSTEM         <DIR>   20.11.1990   10:16:12          0B
UT             <DIR>   20.11.1990   10:18:46          0B
CONFIG.SYS     A---    23.01.1992   14:07:00        128B
BAT            <DIR>   08.03.1991   14:43:52          0B
NET            <DIR>   21.01.1992   11:41:18          0B
CONFIG.WIN     A--R    24.01.1992   09:49:08        149B
CONFIG.VPP     A--R    23.01.1992   14:07:00        128B
AUTOEXEC.BAT   A---    22.11.1992   22:30:54        144B

XVIII.7. 

Volání přerušení

Součástí operačního systému je řada užitečných nízkoúrovňových rutin, které jsou programům přístupné voláním odpovídajícího přerušení (seznamy těchto rutin a jim přidělených čísel přerušení lze nalézt v programátorsky orientovaných příručkách k operačnímu systému DOS). Nízkoúrovňová je i komunikace rutin s programem, většina dat je předávána přímo v registrech procesoru.

Pro tento způsob volání podprogramů a předávání dat je samozřejmě nejjednodušším a nejpřehlednějším způsobem zápisu příslušné části programu použití instrukcí assembleru (Turbo Pascal umožňuje jejich vkládání přímo do zdrojového textu programu). Pro ty, kteří assembler neovládají, poskytuje dostatečně jednoduché a přehledné prostředky k volání přerušení jednotka Dos.

type Registers = record
                  case Integer of
                   0: (AX, BX, CX, DX, BP, SI,
                       DI, DS, ES, Flags       : Word);
                   1: (AL, AH, BL, BH, CL, CH,
                       DL, DH                  : Byte)
                 end;

Typ Registers je implementován pro předávání hodnot registrů procesoru mezi programem a rutinami operačního systému. Vstupní parametry rutin se namísto do registrů procesoru vkládají do stejnojmenných položek pomocné proměnné typu Registers, která se pak použije jako parametr procedury volání přerušení. Procedura zkopíruje hodnoty položek do příslušných registrů procesoru, zavolá požadované přerušení a po jeho skončení zkopíruje případné výstupní hodnoty z registrů do položek parametru, odkud si je může program vyzvednout.

Položky druhé varianty záznamu umožňují ovládání položek AX, BX, CXDX první varianty (a potažmo datových registrů ax, bx, cx a dx procesoru) po jednotlivých bytech. Například AL resp. AH je nižší resp. vyšší byte položky AX atd.

procedure Intr (Cislo: Byte; var R: Registers);

Naplní registry procesoru hodnotami položek parametru R, vyvolá přerušení číslo Cislo a po jeho skončení naplní položky parametru R aktuálními hodnotami registrů procesoru.

procedure MsDos (var R: Registers);

Pracuje podobně jako Intr, avšak místo obecného přerušení volá speciálně přerušení $21, tzv. „služby operačního systému“. Volání MsDos (R) je tedy ekvivalentní volání Intr ($21, R).


PŘÍKLAD: Program DemoIntr implementuje proceduru Videomod a funkci VerzeDOS. Procedura volá funkci 0 (registr ah) přerušení $10, která nastaví požadovaný videomód (registr al) obrazovky. Funkce VerzeDOS volá službu $30 (registr ah) jádra operačního systému, která vrací číslo verze (registr ah) a subverze (registr al) DOSu.

{======================================================================}
program DemoIntr;
{======================================================================}

 uses Dos;

 procedure Videomod (VM: Byte);      { nastaví videomód displeje podle }
 {----------------------------}      { hodnoty parametru VM            }

  var R: Registers;

 begin { Videomod }
  R.AH := 0;                         { výběr funkce: nastav videomód   }
  R.AL := VM;                        { výběr videomódu                 }
  Intr($10, R)                       { volání funkce                   }
 end; { VideoMod }

 function VerzeDOS: string;          { vrací řetězec identifikačního   }
 {------------------------}          { čísla verze DOSu                }

  var R        : Registers;
      Verze,                         { řetězcový tvar čísla verze      }
      Subverze : string [1];         { řetězcový tvar čísla subverze   }

 begin { VerzeDOS }
  R.AH := $30;                       { výběr služby: vrať číslo verze  }
  MsDos(R);                          { volání služby                   }
  Str(R.AL, Verze);                  { převod vrácených čísel hlavní   }
  Str(R.AH, SubVerze);               { verze a subverze na řetězce     }
  VerzeDOS := Verze + '.' + Subverze { sloučení do výstupního řetězce  }
 end; { VerzeDOS }

begin { program }
 Videomod(0);                        { textový mód 25 řádek x 40 znaků }
 Writeln('aktuální videomód: ', 0);  { výpis čísla videomódu a verze   }
 WriteLn('verze DOSu: ', VerzeDOS);  { operačního systému              }
 Writeln;
 Write('Stiskni ENTER:');
 ReadLn;                             { čekání na stisk klávesy ENTER   }
 Videomod(3);                        { textový mód 25 řádek x 80 znaků }
 Writeln('aktuální videomód: ', 3);  { výpis čísla videomódu a verze   }
 WriteLn('verze DOSu: ', VerzeDOS);  { operačního systému              }
 Writeln;
 Write('Stiskni ENTER:');
 ReadLn                              { čekání na stisk klávesy ENTER   }
end. { program }

XVIII.8. 

Spuštění externího programu

Mezi prostředky, poskytovanými aplikačním programům jednotkou Dos, náleží i procedura Exec, pomocí níž lze z hostitelského programu spustit zvolený program externí. Správné prostředí pro spouštěný program zajistí procedura SwapVectors a základní informaci o výsledku jeho výpočtu a způsobu ukončení poskytne funkce DosExitCode.

procedure Exec (Prg, Param: string);

Zavede do paměti spustitelný program, uložený v diskovém souboru se systémovou specifikací Prg a předá mu řízení. Řetězec Param obsahuje případné parametry spouštěného programu ve formátu příkazové řádky operačního systému (pokud spouštěný program parametry nemá, je tento řetězec prázdný).

Po skončení volaného programu nebo neúspěšném pokusu o jeho zavedení vrátí operační systém řízení programu volajícímu. Pokud volaný program nemohl být z nějakého důvodu zaveden, obsahuje proměnná DosError kód příslušné chyby. Typickou příčinou neúspěchu při zavádění programu do paměti je její nedostatečná kapacita (DosError = 8), způsobená absencí omezení velikosti heapu volajícího programu (viz požadavek na přidělení paměti).

Rezidentní příkazy operačního systému (dir, chdir, copy apod.) a dávkové (.bat) soubory lze spouštět pouze jako parametry interpretru příkazů command.com:

Exec ('c:\command.com', '/C dir *.pas')
Přepínač /C způsobí ukončení činnosti interpretru ihned po provedení zadaného příkazu (v tomto případě příkazu dir *.pas). Pokud by nebyl uveden, ponechá si command.com řízení až do uvedení příkazu k jeho ukončení (exit) z příkazové řádky.

procedure SwapVectors;

Operační systém implementuje obslužné rutiny různých událostí, jejichž adresy jsou uloženy v tzv. tabulce vektorů přerušení na začátku operační paměti. Turbopascalské programy však instalují vlastní obsluhu některých událostí — uschovají aktuální hodnotu příslušného vektoru a nahradí ji adresou vlastní obslužné rutiny. Pokud má externí program, spouštěný z prostředí turbopascalského programu, pracovat v původním prostředí DOSu, je nutno před jeho spuštěním procedurou Exec i po jeho skončení zaměnit pomocí procedury SwapVectors hodnoty aktuálních a uložených přerušovacích vektorů.

function DosExitCode: Word;

Poskytne dvoubytovou hodnotu, kterou vrací operační systém po ukončení běhu externího programu, spuštěného předchozím voláním procedury Exec. Nižší byte vrácené hodnoty obsahuje výstupní kód programu a vyšší byte indikuje způsob jeho ukončení:

  kód     způsob ukončení programu  
0 normální ukončení
1 povel CTRL+BREAK z klávesnice
2 chyba zařízení
3 ponechán v paměti jako rezidentní


PŘÍKLAD: Program ExecDemo spouští externí program, jehož systémovou specifikaci a parametry si vyžádá z klávesnice. V případě neúspěchu při zavádění externího programu do paměti je vypsáno číslo vzniklé chyby, jinak je vypsáno číslo způsobu jeho ukončení i výstupní kód.

{======================================================================}
program ExecDemo;
{======================================================================}

{$M 1024, 0, 0}                      { minimální zásobník, žádný heap  }

 uses Dos;
 var  Prg,                           { specifikace souboru s programem }
      Par      : string;             { specifikace parametrů programu  }
      Vysledek : Word;               { hodnota vrácená DosExitCode     }

begin { program }
 WriteLn;                            { titulek                         }
 WriteLn('EXECDEMO');
 WriteLn;
 Write('spustit program: ');         { načtení specifikace programu    }
 ReadLn(Prg);                        { jeho parametrů                  }
 Write('s parametry    : ');
 ReadLn(Par);
 SwapVectors;                        { nastavení vektorů přerušení DOS }
 Exec(Prg, Par);                     { pokus o zavedení a spuštění Prg }
 SwapVectors;                        { obnova vektorů přerušení        }
 if DosError <> 0 then               { došlo při zavádění k chybě?     }
  WriteLn('chyba ', DosError, '!')   { ano - výpis čísla chyby         }
 else                                { ne                              }
  begin                              { výpis hodnoty DosExitCode       }
   Vysledek := DosExitCode;
   WriteLn('způsob ukončení: ',      { - vyšší byte                    }
           Hi(Vysledek));
   WriteLn('výstupní kód   : ',
           Lo(Vysledek))             { - nižší byte                    }
  end;
 WriteLn
end. { program }