W kolejnym odcinku cyklu "MS-DOS" od środka omawiamy dalsze wywołania funkcji obsługi zbiorów i urządzeń zewnętrznych oraz wywołania funkcji zarządzających programami.
Funkcje obsługi zbiorów i urządzeń zewnętrznych.
Funkcja 45h - otwiera drugi kanał logiczny (handle) umożliwiający dostęp do otwartego wcześniej urządzenia lub zbioru. Wszystkie operacje wykonywane w jednym kanale będą automatycznie odwzorowane w drugim. Nowy kanał nie umożliwia więc niezależnego manipulowania zbiorem czy urządzeniem. W szczególności w przypadku zbioru, wskaźnik odczytu/zapisu w obu kanałach jest zawsze identyczny! Podczas wywołania funkcji w rejestrze BX należy umieścić numer kanału, który został przyporządkowany zbiorowi (urządzeniu) przy jego otwieraniu. Jeśli nie wystąpi żaden błąd, to system otworzy drugi kanał i poda jego numer w rejestrze AX. W przeciwnym wypadku mogą pojawić się dwa błędy: 4 - zbyt dużo otwartych zbiorów oraz 6 - zły numer kanału (kanał o podanym w BX numerze nie istnieje lub nie został otwarty).
Funkcja 46h - także otwiera drugi kanał logiczny, tym razem jednak numer drugiego kanału ustalany jest przez użytkownika, a nie przez system. Dzięki temu funkcja może być stosowana do re-definicji przypisania kanału. Użytkownik wywołując funkcje podaje numer pierwszego kanału w rejestrze BX i numer drugiego kanału w CX. Jeżeli kanał wybrany w rejestrze CX jest już wykorzystywany dla innego zbioru (urządzenia), to najpierw następuje zamknięcie tego zbioru. Możliwe błędy pojawiające się przy wywołaniu to: 4 - zbyt dużo otwartych zbiorów, 6 - zły numer kanału. Funkcję 46h można wykorzystać do zmiany standardowego przyporządkowania kanałów logicznych urządzeniom zewnętrznym. Przypuśćmy, że program wysyła dane na drukarkę (to znaczy do kanału logicznego 4). Chcąc spowodować wyprowadzenie ich do określonego zbioru należy najpierw otworzyć ten zbiór i uzyskać w BX numer przyporządkowanego zbiorowi kanału. Dla zachowania możliwości ponownego przypisania kanału 4 drukarce, należy otworzyć jeszcze jeden kanał jej przyporządkowany (funkcja 45h) i zapamiętać jego numer. Następnie do CX wpisać 4 i wywołać funkcję 46h, co spowoduje zamknięcie kanału 4 dla drukarki i otwarcie go dla nowego zbioru. Gdy dane w kanale 4 zechcemy ponownie wysłać na drukarkę, wystarczy w rejestrze BX umieścić zapamiętany na wstępie numer, a w rejestrze CX - 4, i wywołać funkcję 46h.
Funkcja 47h - podaje ścieżkę dostępu do wybranego katalogu w postaci ciągu ASCIIZ (znaki ASCII zakończone bajtem 00). Nie jest podawany symbol wybranego napędu dyskowego, ani też znak początkowy \ (backslash). Oznacza to, że gdy wybrany jest akurat katalog główny, funkcja poda pusty ciąg znaków. Rejestry DS:SI powinny zawierać adres przynajmniej 64-bajtowego obszaru pamięci, w którym system umieści ciąg ASCIIZ, zaś rejestr DL - liczbę kodującą napęd dyskowy (0 - napęd aktualny, 1 - napęd A:, itd). Może wystąpić tylko jeden błąd - 0Fh (złu numer napędu w DL). Dwie kolejne funkcję umożliwiają przeszukiwanie katalogu.
Funkcja 4Eh - służy do poszukiwania w katalogu pierwszego zbioru o podanej nazwie (może ona zawierać symbole wieloznaczne * i ?). Rejestry DS:DX powinny wskazywać na ciąg ASCIIZ określający ścieżkę dostępu do zbioru. Rejestr CL powinien specyfikować atrybuty poszukiwanego zbioru. Jeśli zbiór zostanie znaleziony, system wpisuje do aktualnego obszaru DTA 43 bajty zawierające informacje o zbiorze (tab.1). Znajduje się tam między innymi ciąg ASCIIZ będący nazwą zbioru wraz z rozszerzeniem i oddzielającą je kropką. Jeśli rozszerzenia brak, kropka nie występuje. Podanie w rejestrze CX dowolnej kombinacji bitów, określających zbiór jako hidden, system lub directory, sprawia, że poszukiwane będą zarówno zbiory o podanych atrybutach jak i atrybucie normal. Jeśli mamy atrybut : volume label, poszukiwana będzie tylko pozycja będąca etykietą. Atrybuty archiv i read only są ignorowane. Atrybuty volume label, directory i read only nie są analizowane w wersjach systemu starszych od DOS 2.00. Możliwe są dwa błędy: 2 - nie znaleziono zbioru (podano złą ścieżkę dostępu); 12h - brak dalszych zbiorów (nie znaleziono zbioru o podanej nazwie). Uwaga : w przypadku błędu, wskaźnik przeniesienia nie jest ustawiany. O błędzie świadczy niezerowa zawartość rejestru AX.
Tabela 1. informacje o znalezionym zbiorze podawane przez system w obszarze DTA po powrocie z wywołania funkcji 4Eh
| Przemieszczenie | Opis |
| 00h ... 14h | obszar używany przez DOS do dalszych poszukiwań (za pomocą funkcji 4Fh) - nie może być zmieniany przez użytkownika |
| 15h | atrybuty znalezionego pliku |
| 16h ... 17h | czas ostatniego dostępu |
| 18h ... 19h | data ostatniego dostępu |
| 1Ah ... 1Dh | wielkość zbioru (w bajtach; 1Ah - najmniej znaczący bajt) |
Funkcja 4Fh - kontynuuje poszukiwanie zbiorów o podanej (wieloznacznej) nazwie. Korzysta z informacji wpisanej do obszaru DTA przez funkcję 4Eh (która musi zostać wcześniej wywołana) i umieszcza w tym obszarze informacje o zbiorze identycznie, jak funkcja 4Eh (tab.1). Jedyny możliwy błąd to 18 - nie znaleziono dalszych zbiorów. Uwaga : podobnie jak przy poprzedniej funkcji, wskaźnik przeniesienia nie sygnalizuje błędu.
Funkcja 56h - umożliwia zmianę nazwy zbioru. Rejestry DS:DX powinny wskazywać na starą nazwę, a ES:DI - na nową. Obie nazwy należy podać w postaci ciągów ASCIIZ, określając również ścieżki dostępu (na tym samym dysku). Jeśli obie ścieżki określają zbiory w dwóch różnych katalogach, to zbiór zostanie przepisany ze starego katalogu do nowego. Mogą wystąpić błędy: 2 - nie znaleziono zbioru, 3 - nie znaleziono ścieżki dostępu, 5 - dostęp niemożliwy i błąd 17 - podano różne napędy. Na wydruku 1 przedstawiono program wykorzystujący funkcje rozszerzone do zmiany przyporządkowania urządzeń fizycznych kanałom logicznym
Funkcje zarządzające programami
Funkcja 00h - umożliwia zakończenie programu, to znaczy przekazanie sterowania do programu wywołującego. Jest ona wywoływana bezpośrednio (INT 21h z AX = 0) lubprzez przerwanie programowe 20h. Wykorzystanie funkcji 00h nie jest jednak najlepszym sposobem kończenia programu (przynajmniej w przypadku programów typu .EXE), gdyż trzeba spełnić szereg warunków - m.in. w rejestrze CS musi być podany adres segmentu (z przesunięciem 0) zawierającego PSP (porównaj - MS-DOS od środka (2), mikroklan 6/87). Lepiej jest kończyć program przy użyciu funkcji 4Ch, gdyż po wykonaniu funkcji 00h wektory przerwań 22h, 23h i 24h ustawiane są zgodnie z adresami zapamiętanymi w obszarze PSP (przesunięcie 0Ah do 15h). A zatem, nawet jeśli zakończony program zmienił te wektory, funkcja ta przywróci ich wartości początkowe.
Funkcja 4Bh - pozwala załadować program lub podprogram do pamięci i ewentualnie go wykonać. DS:DX powinna wskazywać na ciąg ASCIIZ, opisujący ścieżkę dostępu do pliku zawierającego program, zaś para rejestrów ES:BX - na blok parametrów opisujących sposób ładowania programu (tab.3 i 3). Jeśli przy wywołaniu funkcji AL = 0, to blok wskazywany przez ES:BX składa się z 14 bajtów. Po załadowaniu podprogramu, w czasie jego wykonywania, kanały logiczne (ang. handle), otwarte przez program wywołujący, są dostępne dla podprogramu wywoływanego. Program wywołujący może zmienić przyporządkowanie kanałów logicznych urządzeniom fizycznym i w ten sposób wpływać na sposób wykonania wywoływanego podprogramu. Przed użyciem tej funkcji warto upewnić się, czy w systemie jest dostateczny obszar wolnej pamięci (funkcja 4Ah).
Tabela 2. Informacje zawarte w bloku sterującym wykorzystywanym przez funkcję 4Bh przy AL = 0
| Przemieszczenie | Opis |
| 00h ... 01h | adres segmentowy* ciągów ASCIIZ opisujących otoczenie (ang. environment string) |
| 02h ... 05h | adres segmentowy wiersza poleceń |
| 06h ... 09h | adres segmentowy pierwszego systemowego bloku FCB |
| 0Ah ... 0Dh | adres segmentowy drugiego systemowego bloku FCB |
| *) adres segmentowy oznacza 4 bajty (adres segmentu i przemieszczenie w ramach segmentu) | |
Tabela 3. Informacje zawarte w bloku sterującym wykorzystywanym przez funkcję 4Bh przy AL = 3
| Przemieszczenie | Opis |
| 00h ... 01h | adres segmentu, do którego ma być załadowany abiór (z przemieszczeniem 0) |
| 01h ... 02h | współczynnik relokacji (istotny tylko dla zbiorów typu EXE; najczęściej równy adresowi segmentu) |
Do programów, które można załadować i wykonać, należy m.in. interpreter poleceń DOS. Możemy mu wskazać ciąg znaków będących poleceniem do wykonania. Z kolei to polecenie może powodować wykonanie pliku zawierającego polecenia (ang. batch file), z których ostatnim powinno być polecenie EXIT, powodujące zakończenie wykonywania interpretera poleceń. W tym momencie kontrolę przejmuje na powrót program wywołujący. Jeśli AL = 3, to nie następuje automatyczne przejście do wykonywania programu i nie jest tworzony nagłówek PSP. W ten sposób najczęściej ładuje się nakładki programowe. Jest to również prosty i efektywny sposób ładowania danych do pamięci. Uwaga : Funkcja 4Bh niszczy zawartość większości rejestrów, łącznie z rejestrami stos-owymi - SS:SP. Aby zachować wartość rejestrów po załadowaniu i wykonaniu programu, należy więc zapamiętać je w pamięci dostępnej tylko dla programu wywołującego (np. w pamięci przechowującej kod tego programu), a po zakończeniu programu odzyskać je. Użycie do tego celu stosu nie jest możliwe. Mogą wystąpić następujące błędy: 1 - zły numer funkcji, 2 - nie znaleziono zbioru, 5 - dostęp niedozwolony, 8 - zbyt mało pamięci, 10 - złe otoczenie i 11 - zły format.
Funkcja 4Ch - umożliwia w prosty sposób zakończenie programu i przekazanie kodu zwrotnego (return code) - czyli wartości, jaka przy wyjściu z programu znajduje się w rejestrze AL. Jeśli program był wywołany z pliku zawierającego polecenia (ang. batch file), wartość kodu zwrotnego można testować za pomocą operacji DOS ERROR LEVEL. Przy zakończeniu programu automatycznie zamykane są wszystkie zbiory otwarte za pomocą funkcji 3DF lub 3EH. Podobnie jak w przypadku funkcji 00h, przywracane są wektory przerwań 22h, 23h i 24h.
Funkcja 4Dh - umożliwia jednorazowe sprawdzenie kodu zwrotnego i sposobu zakończenia programu, (który przedtem załadowano i wykonano za pomocą funkcji 4Bh). System podaje w AL kod zwrotny wysłany przez program, zaś w AH - sposób zakończenia. AH = 0 oznacza zakończenie normalne, AH = 1 - zakończenie spowodowane wciśnięciem CTRL-BREAK, AH = 2 - zakończenie z powodu krytycznego błędu urządzenia, zaś AH = 3 - zakończenie przez wywołanie funkcji 31h (zakończenie programu i nie usuwanie go z pamięci).
NAME ATTRIB
; Za pomocą polecenia ATTRIB można zmieniać (ustawiać lub zerować)
; atrybuty. Zbiór może być niewidoczny (Hidden), lub systemowy (System),
; tylko do odczytu (Read only), zaznaczony jako już archiwizowany
; (Archiv). Nazwy wszystkich zbiorów, których atrybuty ulegają
; zmianie, są wyprowadzane na ekran albo (w przypadku użycia /P na
; drukarkę. Jeśli operator wprowadzi polecenie w złej postaci,
; a konsolę zostanie wysłany komunikat o błędzie oraz wzór
; prawidłowej postaci polecenia.
STACK SEGMENT STACK
DW 20 DUP(?) ; definicja segmentu stosu
STACK ENDS
CODE SEGMENT 'CODE'
ASSUME CS:CODE, DS:CODE, ES:NOTHING, SS:STACK
BELL EQU 07h ; kod ASCII sygnału akustycznego
CHANGE_MODE EQU 43h ; DOS: odczyt/zapis atrybutów
CON_OUT_HANDLE EQU 01h ; zdefiniowany początkowo przez DOS
; kanał wyprowadzania na konsolę
CR EQU 0Dh ; kod ASCII RETURN
DOS EQU 21h ; przerwanie dla wywoływania funkcji
DUPLICATE EQU 45h ; DOS: włączenie drugiego kanału
FALSE EQU 00h ; stała logiczna
FIND_FIRST EQU 4Eh ; DOS: poszukiwanie pierwszego zbioru
FIND_NEXT EQU 4Fh ; DOS: poszukiwanie kolejnego zbioru
FORCE_HANDLE EQU 46h ; DOS: przełączenie kanału
GET_DTA EQU 2fh ; DOS: odczyt adresu DTA (buf. dyskowego)
LF EQU 0Ah ; kod ASCII LINE FEED
PARSE EQU 29h ; DOS: szukanie nazwy zbioru(ów)
PRINTER_CHANNEL EQU 04h ; zdefiniowany początkowo przez DOS
; kanał wyprowadzania na drukarkę
SET_DTA EQU 1Ah ; DOS: ustalenie adresu bufora DTA
TERMINATE EQU 4Ch ; DOS: zakończenie programu
TRUE EQU FFh ; stała logiczna
WRITE_HANDLE EQU 40h ; DOS: wyprowadzenie ciągu znaków
HELP_TEXT DB CR,LF,'Źle wprowadzono dane!',BELL,CR,LF,LF
DB 'Użycie ATTRIB:',CR,LF,LF
DB 'ATTRIB file /A(rchiv)<+,-> /H(ide)<+,->'
DB '/R(ead only)<+,-> /S(ystem)<+,-> /P(rint)'
DB CR,LF
DB ' + oznacza: ustawić atrybut',CR,LF
DB ' - oznacza: wyzerować atrybut',CR,LF,LF,0
COMMANDS DB 'A','H','P','R','S',0 ; lista poleceń
COMMAND_MASK DB 00100000b,00000010b,TRUE,00000001b,00000100b,0
; maski definiujące (za wyjątkiem /P) bity określ. poszczególne atrybuty
NEW_LINE DB CR, LF ; ciąg RETURN, LINE FEED
ATTRIBUTE_MASK1 DB FALSE ; znacznik 'atrybut ma być ustawiony'
ATTRIBUTE_MASK2 DB FALSE ; znacznik 'atrybut ma być wyzerowany
COMMAND_BUFFER DB 128 DUP(?) ; kopia wprowadzonego wiersza polecenia
COMMAND_LENGTH DB ? ; długość wiersza polecenia'
DUMMY_FCB DB 37 DUP(?) ; funkcja PARSE wymaga istnienia FCB
; (który jednak nie jest tu używany)
FILE_LENGTH DB ? ; długość nazwy znalezionego zbioru
FILE_NAME DB 13 DUP(?) ; bufor na nazwę zbioru
OUT_HANDLE DW ? ; komórka na zapamiętanie numeru kanału
; związanego z wyprowadzaniem
PRINT_FLAG DB FALSE ; znacznik określający miejsce wyprowadzania
; (FALSE -> CON:, TRUE -> PRN:)
SECOND_HANDLE DW ? ; miejsce na zapamiętanie numeru kanału
; związanego z konsolą - umożliwia
; przywrócenie drukowania na drukarce
START:
MOV AH, GET_DTA ; DOS: pobranie adresu bufora dyskowego
; (znajduje się tam wiersz polecenia)
INT DOS
MOV AX, ES ; ustalenie adresu oryg. wiersza poleceń
MOV DS, AX
MOV SI, BX
MOV AX, CS ; ustal. adresu kopii wiersza polecenia
MOV ES, AX
MOV DI, OFFSET COMMAND_BUFFER
MOV CX, SIZE COMMAND_BUFFER ; liczba znaków do skopiowania
REP MOVSB ; skopiowanie polecenia do bufora
MOV AX, CS ; przestawienie segmentu danych (DS=CS)
MOV DS, AX ; (dane są teraz w tym samym segmencie)
MOV AX, CON_OUT_HANDLE ; wpisanie jako kanału wyprowadzania
; standardowego wyjścia na konsolę
MOV OUT_HANDLE, AX
XOR CH, CH
MOV DI, OFFSET COMMAND_BUFFER
MOV CL, BYTE PTR [DI]
MOV COMMAND_LENGTH, CL ; zapamiętanie długości polecenia
TEST CL, FFh ; wprow. tekst po nazwie polecenia?
CALL OUTPUT_HELP ; gdy nie, to wyprowadź HELP i kończ
INC DI ; pierwszy bajt DTA zawiera liczbę
; wprowadzonych znaków
CLD
MOV AL, ; przeskoczenie początkowych spacji
REPE SCASB
INC CX ; korekcja rejestrów
DEC DI
PUSH DI ; ochrona adresu pierwszego znaku
MOV COMMAND_LENGTH, CL ; zapamiętanie długości ciągu znaków
CMP CL,0 ; czy są jakieś znaki?
CALL OUTPUT_HELP ; jeśli nie, to obsłuż błąd
MOV SI, DI ; jeśli są, to przyg. dane dla PARSE
MOV DI, OFFSET DUMMY_PCB
MOV DX, SI ; oblicz adres końc. wiersza z polec.
ADD DX, CX
MOV AL, 0 ; tryb 0 funkcji PARSE
MOV AH, PARSE ; DOS: analiza wiersza polecenia
INT DOS
CMP SI, DX ; czy były jakieś znaki?
CALL OUTPUT_HELP ; gdy nie, to wyprowadź HELP i kończ
CMP BYTE PTR [DI+1] ; zły numer napędu ?
CALL OUTPUT_HELP ; gdy nie, to wyprowadź help i kończ
SUB DX, SI ; oblicz liczbę pozostałych znaków
MOV CX, DX
XCHG COMMAND_LENGTH, CL ; i zapamiętaj ją
SUB CL, COMMAND_LENGTH ; oblicz długość nazwy zbioru
MOV FILE_LENGTH, CL
POP SI ; zał. adres początkowy nazwy zbioru
MOV DI, OFFSET FILE_NAME ; załaduj adres końcowy nazwy zbioru
REP MOVSB ; przekopiuj nazwę zbioru
MOV BYTE PTR [DI], 00h ; wpisz terminator nazwy zbioru
MOV DI, SI
MOV CL, COMMAND_LENGTH ; analiza pozostałych znaków
MOV AL, '/' ; poszukiwanie '/'
REPNE SCASB
CMP CL, 0 ; znaleziono ?
CALL OUTPUT_HELP ; gdy nie, to wyprowadź HELP i kończ
MOV SI, DI ; SI = DI
PUSH DI ; zapamiętaj adres ciągu poleceń
MOV BX, CX
; w pozost. części prog. następuje usunięcie z polecenia wszystkich spacji.
; Do BX wpisuje 1. pozost. zmakow. "Małe" litery zamieniane są na "duże".
LOOP:
LODSB ; pobranie znaku
CMP AL, ' ' ; spacja?
JZ BLANK
CMP AL, 'a' ; nie, czy znak ASCII < 'a'?
JL STORE
CMP AL, 'z' ; nie, czy znak ASCII > 'z'?
JG STORE
AND AL, 11011111b ; zmień "małą" literę na "dużą"
STORE:
STOSB ; nie spacja, dołącz znak do ciągu
JMP END_LOOP
BLANK:
DEC BX ; spacja, nie dołączaj do ciągu
END_LOOP:
LOOP LOOP ; pozostań w pętli, aż nie będzie
; więcej znaków (CX=0)
MOV BYTE PTR[DI], '/' ; zakończ ciąg znakiem '/'
CMP BX, 0 ; czy są dalsze polecenia?
CALL OUTPUT_HELP ; gdy nie, to wyprowadź HELP i kończ
INC BX ; dolicz '/' do liczby znaków
POP DI ; odzyskaj począt. adres ciągu znaków
DECODE:
MOV AL,[DI] ; pobierz znak polecenia (A,R,H,P,S)
PUSH DI ; zapamiętaj adres znaku polecenia
MOV DI, OFFSET COMMANDS ; adres ważnego polecenia
MOV CX, OFFSET END_COMMANDS + 1
SUB CX, DI ; oblicz dług. tabeli poleceń + 1
REPNE SCASB ; przeszukaj tabelę poleceń
CMP CX, 0 ; znaleziono polecenie?
CALL OUTPUT_HELP ; gdy nie, to wyprowadź HELP i kończ
POP DI ; odtworzenie adresu polecenia
MOV SI, OFFSET END_MASK ; obliczenie adresu maski atrybutów
SUB SI, CX
MOV AL, [SI] ; pobranie maski atrybutów
CALL SET_MASK ; zmienienie wskaźnika atrybutów
; albo 'przełączenie' wy na drukarkę
CMP BX, 0 ; czy koniec ciągu poleceń?
JNZ DECODE ; jeśli nie, to analizuj dalej
CALL REDIRECT_IO ; jeśli tak, to dla PRINT_FLAG = TRUE
; przełącz wyprowadzanie na drukarkę
CALL PROCESS_FILES ; przełącz atrybuty
CALL RESTORE_IO ; przełącz wy z powrotem na konsolę
XOR AL, AL ; kod powrotu = 00h
MOV AH, TERMINATE ; DOS: zakończ program
INT DOS
OUTPUT_HELP PROC NEAR
; jeśli nie jest ustaw. znacznik zera, następuje powrót do proc głównej
; w przeciwnym wyp. wyprowadzany jest tekst HELP i następuje zakoń. prog.
JNZ NO_TEXT
MOV BX, OUT_HANDLE
MOV CX, OFFSET END_HELP ; obliczenie długości HELP_TEXT
MOV DX, OFFSET HELP_TEXT ; DX zawiera adr. pocz. HELP_TEXT
SUB CX, DX
MOV AH, WRITE_HANDLE ; DOS: wyprowadzenie ciągu znaków
INT DOS
XOR AL, AL ; kod powrotu = 00h
MOV AH, TERMINATE ; DOS: zakończenie programu
INT DOS
NO_TEXT:
RET ; powrót do programu głównego
OUTPUT_HELP ENDP
SET_MASK PROC NEAR
; ustaw maskę(i) zgodnie z poleceniami
; /P ustawia PRINT_FLAG; + ustawia ATTRIBUTE_MASK1; - ustawia ATTRIBUTE_MASK2
CMP AL, TRUE ; czy polecenie /P ?
JNZ SET_ATTRIBUTE ; jeśli nie, to ustaw atrybut
MOV PRINT_FLAG, AL ; jeśli tak, to ustaw znacznik drukow.
MOV BP, 1 ; dostęp następnego '/' od P
JMP COMMON_SET ; analizuj dalsze znaki
SET_ATTRIBUTE:
CMP BYTE PTR [DI+1], '+' ; czy po literze polecenia jest '+' ?
JNZ CHECK_MINUS ; nie - sprawdź czy minus
OR ATTRIBUTE_MASK1, AL ; był '+', trzeba ustawić atrybut
JMP NEXT_COMMAND
;
CHECK_MINUS:
CMP BYTE PTR [DI+1], '-' ; czy po literze polecenia jest '-' ?
JZ RESET_ATTRIBUTE ; był '-', trzeba wyzerować atrybut
;
OUT_HELP:
TEST AL, 0 ; ani '+', ani '-', więc wyprowadź
CALL OUTPUT_HELP ; HELP i wróć do programu głównego
;
RESET_ATTRIBUTE:
OR ATTRIBUTE_MASK2, AL ; wyzerowanie atrybutu
;
NEXT_COMMAND:
MOV BP, 2 ; odstęp następnego '/' od polecenia
;
COMMON_SET:
CMP BYTE PTR DS:[DI+BP], '/'
JNZ OUT_HELP ; jeśli kolejne znaki nie zaczynają
INC BP ; się od '/', to wyprow. tekst HELP
AND DI, BP ; adres następnego polecenia
SUB BX, BP ; liczba pozostałych znaków
RET
;
SET_MASK ENDP
REDIRECT_IO PROC NEAR
; przełączenie kanału wyprowadzania na drukarkę
CMP PRINT_FLAG, TRUE ; czy wyprowadzanie na drukarkę ?
JNZ END_REDIRECT ; nie - to wróć
MOV AH, DUPLICATE ; DOS: otwórz drugi kanał wyprowadz.
MOV BX, OUT_HANDLE
INT DOS
JC ERROR_HANDLE ; jeśli błąd - to obsłuż
MOV SECOND_HANDLE, AX ; zapamiętaj numer drug. kan. wypr.
MOV AH, FORCE_HANDLE ; DOS: wymuszenie przełączenia
MOV BX, PRINTER_CHANNEL ; kanału wyprowadz. na drukarkę
MOV CX, OUT_HANDLE
INT DOS
JNC END_REDIRECT ; jeśli bez błędu - to wróć
ERROR_HANDLE:
CALL PROCESS_ERROR ; obsługa błędu
;
END_REDIRECT:
RET
;
REDIRECT_IO ENDP
RESTORE_IO PROC NEAR
; odtworzenie połączenia logicznego kanału wyprowadzania
CMP PRINT_FLAG, TRUE ; czy wyprowadzanie na drukarkę ?
JNZ END_RESTORE ; nie - to wróć
MOV AH, FORCE_HANDLE ; DOS: wymuszenie przełączania
MOV BX, SECOND_HANDLE ; kanału wyprowadzania na poprze-
MOV CX, OUT_HANDLE ; dni związany z konsolą
INT DOS
JNC END_RESTORE ; jeśli bez błędu - to wróć
CALL PROCESS_ERROR ; jeśli błąd - to obsłuż
END_RESTORE:
RET
RESTORE_IO ENDP
PROCESS_ERROR PROC NEAR
; obsługa błędów ogranicza się do przekazania w AL kodu błędu
MOV AH, TERMINATE ; DOS: zakończenie programu
INT DOS
PROCESS_ERROR ENDP
PROCESS_FILES PROC NEAR
MOV AH, SET_DTA ; DOS: przełączenie bufora dyskowego
MOV DX, OFFSET COMMAND_BUFFER
INT DOS
MOV DX, OFFSET FILE_NAME ; ustalenie adresu nazwy zbioru
MOV CX, 00100111b ; atrybuty dla funkcji poszukującej
MOV AH, FIND_FIRST ; DOS: poszukiw. pierwszego zbioru
INT DOS
JC FIND_ERROR ; jeśli był błąd, to go obsłuż
FINT_LOOP: ; pętla poszukiwania zbiorów
MOV DX, OFFSET COMMAND_BUFFER + 1Eh ; adres znalezionej nazwy zb.
MOV AL, 00h ; funkcja: odczytanie atrybutów
MOV AH, CHANGE_MODE ; DOS: odczytanie/zapisanie atrybutów
INT DOS
JC CHANGE_ERROR ; jeśli błąd, to go obsłuż
MOV AL, ATTRIBUTE_MASK2 ; zaneguj maskę zerowania atrybutu
NOT AL
AND CL, AL
OR ATTRIBUTE_MASK1 ; ustawienie odpowiedniego atrybutu
MOV AL, 1 ; funkcja: zapisanie atrybutów
MOV AH, CHANGE_MODE ; DOS: odczytanie/zapisanie atrybutów
INT DOS
JC CHANGE_ERROR ; jeśli błąd, to go obsłuż
MOV DI, OFFSET COMMAND_BUFFER + 1Eh
MOV DX, DI ; ustalenie adresu nazwy zbioru
MOV AL, 0
MOV CX, 13 ; maksymalna długość nazwy zbioru
REPNE SCASB ; poszukiwanie końca nazwy zbioru
DEC DI
SUB DI, DX
MOV CX, DI
MOV BX, OUT_HANDLE ; wybranie kan. wypr. nazwy zbioru
MOV AH, WRITE_HANDLE ; DOS: wyprowadzenie ciągu znaków
INT DOS
MOV DX, OFFSET NEW_LINE ; wyprowadzenie CR,LF
MOV CX, 2
MOV BX, OUT_HANDLE
MOV AH, WRITE_HANDLE ; DOS: wyprowadzenie ciągu znaków
INT DOS
MOV AH, FIND_NEXT ; DOS: poszukiw. następnego zbioru
INT DOS
JNC FIND_LOOP ; obsłuż znaleziony zbiór
JMP END_SET ; jesli błąd to wróć
;
FIND_ERROR:
CHANGE_ERROR:
CALL PROCES_ERROR ; obsługa błedu
;
END_SET:
RET
PROCESS_FILES ENDP
CODE ENDS
END START
opr. Zbigniew Pojmański
Mikroklan - Luty 1988r.