   #Start Prev Next Contents

   Jak pisac programy w jezyku asembler?

Czesc 12 - Czego od nas pragna, czyli linia polecen programu. Zmienne
srodowiska

   Teraz zajmiemy sie dosc istotna sprawa z punktu widzenia programisty i
   uzytkownika oprogramowania: linia polecen. Nie wszyscy lubia podawac
   dane programowi w czasie jego pracy i odpowiadac na pytania o dane.
   Czesto (o ile jest to mozliwe) mozna tego oszczedzic i zamiast
   bezustannie zadawac uzytkownikowi pytania, przeczytac, co wpisano nam
   w linie polecen. Umozliwia to pisanie programow, ktore raz uruchomione
   z prawidlowa linia polecen nie pytaja juz sie o nic a tylko wykonuja
   swoja prace bez przeszkadzania uzytkownikom.

   Przejdzmy wiec do szczegolow. Wszystkie operacje, ktore wykonamy, beda
   sie opierac na zalozeniu, ze w swoim programie nie zrobiliscie
   absolutnie nic z rejestrem DS. Jesli go zmieniliscie, to uzyjcie tej
   funkcji (opis oczywiscie z Listy Przerwan Ralfa Brown'a):
   (przeskocz int 21h, ah=62h)
        INT 21 - DOS 3.0+ - GET CURRENT PSP ADDRESS
                AH = 62h
        Return: BX = segment of PSP for current process

   i otrzymana w BX wartosc wpiszcie do DS.

   Majac oryginalny DS (wtedy pokazuje on na Program Segment Prefix -
   PSP), mozna w nim znalezc wiele ciekawych informacji:
     * bajt pod [ds:80h] mowi nam, ile znakow znajduje sie na linii
       polecen, bez konczacego znaku nowej linii (Enter = 13 ASCII).
     * od [ds:81h] do [ds:0FFh] jest linia polecen. Jak widac, ma ona
       dlugosc 128 znakow i tylko tyle mozemy wpisac, uruchamiajac nasz
       program. Teraz rowniez widac, dlaczego programy typu COM zaczynaja
       sie od adresu 100h - po prostu wczesniej nie moga, bo CS=DS.
     * pod [ds:2ch] znajduje sie numer segmentu, w ktorym umieszczono
       kopie zmiennych srodowiskowych (tych ustawianych komenda SET, na
       przyklad w autoexec.bat) do wykorzystania przez nasz program.
       Zmienne srodowiskowe zapisane sa od poczatku segmentu i oddzielone
       od siebie bajtami zerowymi. Dwa bajty zerowe pod rzad oznaczaja
       koniec zmiennych.

   Wszystko ladnie wyglada w teorii, ale jak tego uzywac? Aby
   odpowiedziec na to pytanie, napisalem ten oto krotki programik.
   Jedynym celem jego zycia jest wyswietlenie dlugosci jego linii
   polecen, samej linii polecen, numerow segmentow: kodu, danych i
   srodowiska (dla porownania), oraz samych zmiennych srodowiskowych
   (jesli wyswietla sie za duzo lub za malo, mozna zmienic liczbe na
   koncu programu - pokaze, ktora).

   Oto kod (NASM):
   (przeskocz kod programu)
; Program wyswietla wlasna linie polecen i zmienne srodowiskowe.
;
; Autor: Bogdan D.
; kontakt: bogdandr (at) op (dot) pl
;
; kompilacja NASM:
;   nasm -O999 -o liniap.obj -f obj liniap.asm
;   alink liniap.obj  bibl\lib\bibldos.lib -c- -oEXE -m-
; kompilacja FASM (stary format biblioteki - OMF):
;   fasm liniap.asm liniap.obj
;   alink liniap.obj  bibl\lib\bibldos.lib -c- -entry _start -oEXE -m-
; kompilacja FASM (nowy format biblioteki - COFF):
;   fasm liniap.asm liniap.obj
;   ld -s -o liniap.exe liniap.obj bibl\lib\bibldos.a

; dolaczamy moja biblioteczke
%include "bibl\incl\dosbios\nasm\std_bibl.inc"
%include "bibl\incl\dosbios\nasm\do_nasma.inc"

.stack 400h                     ; program typu EXE musi miec stos

; FASM (stary format biblioteki - OMF):
; format coff
; include "bibl\incl\dosbios\fasm\std_bibl.inc"
; use16
; public start
; public _start
; i nic poza tym

; FASM (nowy format biblioteki - COFF):
; format coff
; include "bibl\incl\dosbios\fasm32\std_bibl.inc"
; public start
; public _start
; i nic poza tym


start:
_start:
..start:                        ; miejsce startu programu
        mov     si, 80h ; [ds:80h] - dlugosc linii polecen bez Entera
        xor     eax, eax
        mov     al, [si]        ; AL = dlugosc linii polecen
        pisz
        db      "Dlugosc linii polecen: ", 0
        pisz8                   ; wypisujemy AL
        nwln                    ; przechodzimy do nowej linii

        mov     cx, ax          ; CX=dlugosc linii polecen,
                                ; abysmy wiedzieli,
                                ; ile znakow nalezy wyswietlic
        inc     si              ; SI=81h. [ds:81h] to poczatek
                                ; linii polecen
        pisz
        db      "Linia polecen=", 0
        pisz_dl                 ; wypisujemy CX znakow spod DS:SI,
                                ; czyli cala linie polecen
        nwln

        mov     ax, cs
        pisz
        db      "Segment kodu programu CS=", 0
        pisz16                  ; wyswietlamy AX=CS
        nwln
        mov     ax, ds
        pisz
        db      "Segment danych DS=", 0
        pisz16                  ; wyswietlamy AX=DS
        nwln

        mov     ax, [ds:2ch]
        pisz
        db      "Segment zmiennych srodowiskowych: DS:[2ch]=",0
        pisz16                  ; wyswietlamy AX=segment srodowiska
        nwln

        ; wylaczyc ponizsze linie az do "wypisz_srod" w przypadku FASMa z
        ; nowym formatem biblioteki (32-bitowy COFF nie pozwala na
        ; manipulacje segmentami)
        mov     ds, ax          ; DS = segment srodowiska
        xor     si, si          ; SI = poczatek segmentu
        pisz
        db      "Zmienne srodowiskowe: ", 0

        mov     ah, 0eh         ; funckja wypisywania znaku
        dec     si              ; tylko po to, aby najblizsze INC SI
                                ; zadzialalo prawidlowo i ustawilo nas z
                                ; powrotem na 0
wypisz_srod:
        nwln                    ; przejdz do nowej linii
wypisz:
        inc     si              ; SI teraz pokazuje na kolejny znak
        cmp     si, 400 ; zeby nie bylo za dlugo -
                        ; to te liczbe MOZNA ZMIENIC
        ja      koniec

        mov     al, [si]        ; pobierz znak spod [DS:SI]
        test    al, al          ; czy bajt zerowy?
        jz      sprawdz         ; jesli tak, to sprawdzimy,
                                ; czy nie dwa pod rzad

        int     10h             ; wypisz znak
        jmp     short   wypisz  ; i w kolko od nowa

sprawdz:
        cmp     byte [si+1], 0
        jne     wypisz_srod

koniec:
        wyjscie

   Jak widac, nie bylo to az takie trudne jak sie moglo zdawac na
   poczatku. Wlasnie poznaliscie kolejna rzecz, ktora jest latwa w
   uzyciu, a mozliwosci ktorej sa duze. Teraz bedziecie mogli smialo
   zaczac pisac programy, ktorych jedynym kanalem komunikacyjnym z
   uzytkownikiem bedzie linia polecen, co znacznie uprosci ich obsluge.
   Tylko pamietajcie o dodaniu kodu wyswietlajacego sposob uzycia
   programu, gdy nie podano mu zadnych parametrow.

   Poprzednia czesc kursu (klawisz dostepu 3)
   Kolejna czesc kursu (klawisz dostepu 4)
   Spis tresci off-line (klawisz dostepu 1)
   Spis tresci on-line (klawisz dostepu 2)
   Ulatwienia dla niepelnosprawnych (klawisz dostepu 0)
     _________________________________________________________________

Cwiczenia

    1. Napisz program, ktory utworzy plik podany jako parametr. Jesli
       podano drugi parametr (oddzielony od pierwszego spacja), zapisz
       jego wartosc do tego pliku. Jesli nie podano zadnych parametrow,
       niech program wypisze stosowna wiadomosc.
    2. Napisz program, ktory oblicza NWD (patrz czesc 8) dwoch liczb
       podanych na linii polecen. Jesli nie podano wystarczajacej liczby
       parametrow, niech program wyswietli stosowna wiadomosc.
