Dostęp do plików

From Atariki

(Różnice między wersjami)
Jump to: navigation, search
Wersja z dnia 22:29, 18 wrz 2017
KMK (Dyskusja | wkład)
(Odczyt bloku danych binarnych)
← Previous diff
Wersja z dnia 22:30, 18 wrz 2017
KMK (Dyskusja | wkład)

Next diff →
Linia 153: Linia 153:
sta icbufl+1,x sta icbufl+1,x
jsr ciov jsr ciov
 + ...
</pre> </pre>
Linia 179: Linia 180:
sta icbufl+1,x sta icbufl+1,x
jsr ciov jsr ciov
 + ...
</pre> </pre>
Linia 209: Linia 211:
sta icbufl+1,x sta icbufl+1,x
jsr ciov jsr ciov
 + ...
</pre> </pre>
Linia 230: Linia 233:
pla pla
jsr ciov jsr ciov
 + ...
</pre> </pre>
Linia 254: Linia 258:
sta icbufl+1,x sta icbufl+1,x
jsr ciov jsr ciov
 + ...
</pre> </pre>
Linia 279: Linia 284:
sta icax2,x sta icax2,x
jsr ciov jsr ciov
 + ...
</pre> </pre>
Linia 293: Linia 299:
sta iccmd,x sta iccmd,x
jsr ciov jsr ciov
 + ...
</pre> </pre>

Wersja z dnia 22:30, 18 wrz 2017

Jak napisano w haśle CIO, z dostępem do plików związane są w Atari tak zwane bloki kontroli wejścia i wyjścia (ang. Input/Output Control Blocks, albo IOCB). Jest ich osiem, każdy liczy 16 bajtów, ulokowane są w pamięci RAM, w obszarze od $0340 do $03BF. Ich struktura opisana jest w wyżej wymienionym haśle CIO, opis ten tutaj zostanie zatem pominięty. Wystarczy napisać, że block IOCB służy do zdefiniowania operacji na pliku i nadaniu jej parametrów wejściowych a także - odebraniu wyników (na ogół: kodu statusu).

Spis treści

Adresowanie IOCB

Bloki IOCB konwencjonalnie adresuje się podając adres wewnątrz pierwszego z nich - czyli $034x - jako argument rozkazu w trybie absolutnym indeksowanym X, przy czym w rejestrze X powinien znajdować się numer bloku IOCB (z zakresu od 0 do 7), pomnożony przez 16. Numer kanału IOCB, pełniący rolę uchwytu (ang. handle) pliku, powinien zostać właśnie w tej postaci, i w tym rejestrze, przekazany do głównej procedury CIO (CIOV lub JCIOMAIN, $E456) przy jej wywoływaniu.

Etykiety IOCB

icchid = $0340
icdno  = $0341
iccmd  = $0342
icstat = $0343
icbufa = $0344
icputb = $0346
icbufl = $0348
icax1  = $034a
icax2  = $034b
icax3  = $034c
icax4  = $034d
icax5  = $034e
icax6  = $034f

Z całego bloku dla omawianego tu zagadnienia istotne są:

  • ICCMD - zapisuje się w nim jeden bajt symbolizujący rodzaj operacji (OPEN, CLOSE itd.)
  • ICBUFA - to adres bufora
  • ICBUFL - to wielkość bufora w bajtach
  • ICAX1/2 - to bajty pomocnicze, zawierające różne dodatkowe parametry

Czasem przydaje się też ICSTAT, po zakończeniu operacji zawiera bowiem jej status (czyli $01 albo kod błędu). Ale rzadko się tę wartość odczytuje stamtąd, bo przekazywana jest też przez OS bezpośrednio w rejestrze Y.

Reszty bajtów IOCB nie dotykamy i w ogóle (na ogół) nie zawracamy sobie nimi głowy.

Funkcje IOCB

W teorii wszystkie bloki mają to samo przeznaczenie: każdy służy jako deskryptor pojedynczego, otwartego pliku. Wynika z tego, że w teorii można otworzyć do ośmiu plików na raz. W praktyce jeden blok - IOCB #$00 - jest defaultowo otwarty dla edytora ekranowego. Można go wprawdzie zamknąć i wykorzystać do czegoś innego, ale nie ma potrzeby tego czynić, gdyż przeciętny DOS nie pozwoli otworzyć więcej niż 3-4 pliki na raz.

Bloki IOCB służą tylko do przekazywania parametrów do DOS-u, nie są zaś właściwymi deskryptorami plików. Dlatego nie da się przeskoczyć limitu jednocześnie otwartych plików przez sprytną podmianę zawartości IOCB i zastąpienie jej przechowywanymi gdzieś indziej danymi innego otwartego pliku - żaden DOS nie da się tak oszukać.

Pierwszy wolny IOCB to IOCB #1, i ten właśnie będzie używany w przykładach.

Otwarcie pliku

W Atari można otworzyć plik dyskowy do odczytu, zapisu, wymiany danych (naprzemiennego odczytu i zapisu) oraz dopisywania. Ogólne zasady są takie, jak wszędzie indziej, to znaczy:

  • plik otwierany do odczytu musi istnieć, w przeciwnym wypadku wystąpi błąd 170 (FILE NOT FOUND);
  • plik otwierany do zapisu, jeśli nie istnieje, zostanie utworzony, natomiast jeśli istnieje, jego dotychczasowa zawartość zostanie skasowana i zostanie on otwarty;
  • plik otwierany do odczytu i zapisu, jeśli istnieje, zostanie otwarty; jeśli nie istnieje, pod niektórymi DOS-ami (np. DOS 2.5, DOS XL) wystąpi błąd 170 (FILE NOT FOUND), natomiast pod innymi (np. SpartaDOS, SpartaDOS X) plik zostanie utworzony (i otwarty);
  • plik otwierany do dopisywania jeśli istnieje, zostanie otwarty, a wskaźnik miejsca, do którego trafią zapisywane dane, zostanie ustawiony na jego końcu; jeśli zaś taki plik nie istnieje, pod niektórymi DOS-ami (np. DOS 2.5, DOS XL) wystąpi błąd 170 (FILE NOT FOUND), natomiast pod innymi (np. SpartaDOS, SpartaDOS X) plik zostanie utworzony (i otwarty).

Kod:

 ; OPEN #1,xx,0,"D:FOOBAR12.DAT"

 ciov = $e456
 
 fname .byte "D:FOOBAR12.DAT",$9b
 
 open_file
       ldx #$10            ;IOCB #1
       lda #$03            ;komenda: OPEN
       sta iccmd,x
       lda #<fname         ;adres nazwy pliku
       sta icbufa,x
       lda #>fname
       sta icbufa+1,x
       lda #$xx            ;kod dostępu: $04 odczyt, $08 zapis, $09 dopisywanie, $0c odczyt/zapis
       sta icax1,x
       lda #$00            ;dodatkowy parametr, $00 jest zawsze dobre
       sta icax2,x 
       jsr ciov
       ...

Nazwa pliku musi spełniać następujące warunki:

  • na początku musi się znajdować specyfikacja urządzenia, na ogół będzie to "D:", co oznacza stację dysków (a ściślej: DOS). Można tu podać numer stacji, np. "D2:", jednak najlepiej poprzestać na "D:" - pozwala to bardziej zaawansowanym DOS-om na zapis tego pliku do bieżącego podkatalogu, czyli na ogół tego, w którym użytkownik trzyma cały program.
  • za dwukropkiem podajemy nazwę pliku w konwencji "8.3", tj. składającą się z najwyżej ośmiu znaków nazwę właściwą, kropkę oraz liczące do trzech znaków rozszerzenie. Znakami dopuszczalnymi w nazwie są duże litery alfabetu angielskiego (A-Z) i cyfry (0-9). Niektóre DOS-y (w tym SpartaDOS i MyDOS) dopuszczają również znak podkreślenia (_) i "małpę" (@). Część DOS-ów wymaga, żeby pierwszym znakiem całej nazwy była litera.
  • za ostatnim znakiem nazwy pliku obowiązkowo powinien się znaleźć znak EOL (Return, kod ASCII $9B).

Po wywołaniu jsr open_file w rejestrze X będzie się znajdował (nadal) numer kanału pomnożony przez 16, a w rejestrze Y kod statusu, natomiast bit N rejstru znaczników będzie odzwierciedlał stan rejestru Y: jeśli N=1, to znaczy, że wystąpił błąd o kodzie przekazanym w Y. W przeciwnim wypadku (N=0) operacja się powiodła.

UWAGA: specyfiką Atari jest to, że po każdym OPEN, nawet jeśli zakończyło się błędem, kanał IOCB pozostaje otwarty i trzeba go zamknąć do ponownego użycia. Zakończenie programu nie powoduje automatycznego zamknięcia otwartych kanałów.

Zamknięcie pliku

Jedynym parametrem wymaganym tutaj jest numer kanału IOCB pomnożony przez 16, czyli "uchwyt pliku". Kod:

 ; CLOSE #1

 ciov = $e456
 
 close_file
       ldx #$10            ;IOCB #1
       lda #$0c            ;komenda: CLOSE
       sta iccmd,x
       jsr ciov
       ...

Zamknięcie kanału już zamkniętego nie powoduje błędu.

Odczyt z pliku

Plik otwarty do odczytu będzie czytany sekwencyjnie od początku do końca. Jeśli nie wystąpią żadne błędy, i odczytano wszystkie dane z pliku, następna próba odczytu zwróci błąd nr 136 (EOF). Ważne jest, żeby status operacji testować na okoliczność wystąpienia błędu (N=1, Y>127), a nie na okoliczność powodzenia (Y=$01), gdyż część DOS-ów w pewnych warunkach zwraca wartość $03 jako status dla udanej operacji odczytu.

Ponadto, po powrocie z systemu ICBUFL,X i ICBUFL+1,X (odpowiednio: młodszy i starszy bajt) zawiera liczbę bajtów odczytanych do bufora, którego adres (nadal) znajduje się w ICBUFA,X i ICBUFA+1,X.

Odczyt bloku danych binarnych

Kod:

 ; BGET #1,buffer,buflen

 ciov = $e456
 
 read_binary
       ldx #$10            ;IOCB #1
       lda #$07            ;komenda: GET BYTES / BINARY READ
       sta iccmd,x
       lda #<buffer        ;adres w pamieci, gdzie maja trafic dane
       sta icbufa,x
       lda #>buffer
       sta icbufa+1,x
       lda #<buflen        ;wielkosc bloku danych w bajtach
       sta icbufl,x
       lda #>buflen
       sta icbufl+1,x
       jsr ciov
       ...

Odczyt pojedynczego bajtu

Do odczytania pojedynczego bajtu nie potrzeba deklarować bufora: jeśli zadeklarujemy zerową wielkość bufora, system odczyta 1 bajt i przekaże go w akumulatorze:

 ; GET #1,A

 ciov = $e456
 
 read_one_byte
       ldx #$10            ;IOCB #1
       lda #$07            ;komenda: GET BYTES / BINARY READ
       sta iccmd,x
       lda #$00
       sta icbufl,x
       sta icbufl+1,x
       jsr ciov
       ...

Odczyt rekordu tekstowego

Rekord tekstowy jest to ciąg znaków ATASCII zakończony znakiem Return (EOL, ASCII $9B). Rekord musi mieścić się w zadeklarowanym buforze, jeśli bufor zapełni się zanim odczytany zostanie znak EOL, wystąpi błąd 137 (TRUNCATED RECORD).

Kod jest prawie taki sam, jak w przypadku danych binarnych, różni się tylko kodem operacji:

 ; INPUT #1,buffer$

 ciov = $e456
 
 read_text
       ldx #$10            ;IOCB #1
       lda #$05            ;komenda: GET RECORD
       sta iccmd,x
       lda #<buffer        ;adres w pamieci, gdzie maja trafic dane
       sta icbufa,x
       lda #>buffer
       sta icbufa+1,x
       lda #<buflen        ;wielkosc rekordu w bajtach
       sta icbufl,x
       lda #>buflen
       sta icbufl+1,x
       jsr ciov
       ...

Zapis do pliku

Zapis przeprowadza się analogicznie do odczytu, może się jedynie zmieniać miejsce, gdzie dane zostaną zapisane. Jest to zależne od trybu otwarcia pliku: przy zwykłym zapisie (tryb otwarcia 8) lub wymianie danych (tryb otwarcia 12) dane będą wpisywane do pliku sekwencyjnie od początku. Przy dopisywaniu (tryb 9) wpisane do pliku dane znajdą się na jego końcu.

Po powrocie z systemu ICBUFL,X i ICBUFL+1,X (odpowiednio: młodszy i starszy bajt) zawiera liczbę bajtów zapisanych do pliku z bufora, którego adres (nadal) znajduje się w ICBUFA,X i ICBUFA+1,X.

UWAGA: po zapisie wszystkich danych plik należy obowiązkowo zamknąć, dopiero wtedy DOS zapisuje do niego wszystkie dane, jakie ewentualnie może jeszcze tymczasowo trzymać w buforach, oraz uaktualnia wpis w katalogu.

Zapis bloku danych binarnych

 ; BPUT #1,buffer,buflen

 ciov = $e456
 
 write_binary
       ldx #$10            ;IOCB #1
       lda #$0b            ;komenda: PUT BYTES / BINARY WRITE
       sta iccmd,x
       lda #<buffer        ;adres w pamieci, gdzie znajduja sie dane
       sta icbufa,x
       lda #>buffer
       sta icbufa+1,x
       lda #<buflen        ;wielkosc bloku danych w bajtach
       sta icbufl,x
       lda #>buflen
       sta icbufl+1,x
       jsr ciov
       ...

Zapis pojedynczego bajtu

Analogicznie jak przy odczycie, zdefiniowanie zerowej wielkości bufora spowoduje, że do pliku zostanie zapisana zawartość akumulatora:

 ; PUT #1,A

 ciov = $e456
 
 write_one_byte
       pha
       ldx #$10            ;IOCB #1
       lda #$0b            ;komenda: PUT BYTES / WRITE BINARY
       sta iccmd,x
       lda #$00
       sta icbufl,x
       sta icbufl+1,x
       pla
       jsr ciov
       ...

Zapis rekordu tekstowego

Na końcu bufora danych powinien się znajdować znak EOL (ASCII $9B). Zadeklarowana wielkość bufora powinna być większa lub równa liczbie zapisywanych danych. Kod:

 ; PRINT #1,buffer$

 ciov = $e456
 
 write_text
       ldx #$10            ;IOCB #1
       lda #$09            ;komenda: PUT RECORD
       sta iccmd,x
       lda #<buffer        ;adres w pamieci, skad maja byc pobrane dane
       sta icbufa,x
       lda #>buffer
       sta icbufa+1,x
       lda #<buflen        ;wielkosc rekordu w bajtach
       sta icbufl,x
       lda #>buflen
       sta icbufl+1,x
       jsr ciov
       ...

Status pliku

Odczyt statusu pliku ma na celu stwierdzenie jego dostępności bez konieczności robienia OPEN. Wynikiem jest $01 (sukces), gdy plik jest dostępny, lub odpowiedni kod błędu, gdy nie jest. Niektóre DOS-y zwracają kod błędu 167 (FILE LOCKED), kiedy plik istnieje, lecz jest zabezpieczony przed zapisem.

 ; XIO 13,#1,0,0,"D:FOOBAR12.DAT"

 ciov = $e456
 
 fname .byte "D:FOOBAR12.DAT",$9b
 
 get_status
       ldx #$10            ;IOCB #1
       lda #$0d            ;komenda: STATUS
       sta iccmd,x
       lda #<fname         ;adres nazwy pliku
       sta icbufa,x
       lda #>fname
       sta icbufa+1,x
       lda #$00
       sta icax1,x
       sta icax2,x 
       jsr ciov
       ...

Odczyt statusu można też przeprowadzić dla otwartego pliku. Podawanie jego nazwy i innych parametrów jest wtedy zbędne:

 ; STATUS #1,A

 ciov = $e456
 
 get_status
       ldx #$10            ;IOCB #1
       lda #$0d            ;komenda: STATUS
       sta iccmd,x
       jsr ciov
       ...

Wywołanie operacji STATUS dla urządzenia C: da zawsze wynik $01 niezależnie od tego, czy magnetofon jest rzeczywiście podłączony.

Personal tools