Metropoli BBS
VIEWER: stochain.asm MODE: TEXT (CP437)
                 PAGE 60,132 
                ;program to chain and form DOS storage blocks
                ; Usage is: STOCHAIN 

sb              SEGMENT AT 0       ;map of storage block header paragraph
sbkind          DB      ' '        ;Type of storage block: M or Z
sbpsp           DW       0         ;PSP segment address
sblength        DW       0         ;SB length in paragraphs
sbfill          DB       11 DUP(0) ;filler



                ORG      sbkind
pspretint       DW       ?          ;int 20
pspmemsize      DW       ?          ;size of memory in paragraphs
pspresv         DB       ?
                ORG      5h
pspcalldosfunct DB       ?          ;long call to dos function dispatcher
pspdosfunct     DD       ?          ;IP:CS of dos function dispatcher
                ORG      0Ah
pspdosterminate DD       ?          ;IP:CS of:dos terminate 
                ORG      0Eh
pspdosctrlbreak DD       ?          ;         ctrl break address
                ORG      12h
pspdoscrtclerr  DD       ?          ;         critical error handler
                ORG      18h
pspdosdefhandle DD       20 dup(?)  ;         DOS 2.0 - 20 file handles
                                    ;         DOS 3.0 - default file handles
                ORG      2Ch
pspenv          DW       ?          ;segment address of environment
                ORG      32h
psphandlecount  DW       ?          ;number of handles in table (DOS 3.0)
                ORG      34h
psphandles      DW       ?          ;offset of handle table in CS (DOS 3.0)
                ORG      50h
pspdosfunction  DW       ?          ;invoke dos function dispatcher
                ORG      5Ch
pspfcb1         DB       ?          ;first fcb
                ORG      6Ch
pspfcb2         DB       ?          ;second fcb
                ORG      80h
pspparm         DB       ?          ;unformatted paramter area
                ORG      0FFh
pspend          EQU      $

sb              ENDS

code_seg        SEGMENT

                ASSUME    CS:code_seg,DS:code_seg,ES:sb

cr              equ       13
lf              equ       10

myretint        DW       ?          ;int 20
                ORG      50h
mydosfunction   DW       ?          ;invoke dos function dispatcher
                ORG       100h

code            PROC      far

                jmp       program
                db        'Copyright 1986 by Arnold B. Krueger GPW MI, 48236'
typestring      proc near 
                push ax
                mov  ax,0900h
                int  21h
                pop  ax
                ret
typestring      endp

getfirstsb      PROC near       ;get first storage block, ES will point to it
                PUSH AX
                PUSH BX
                MOV  AX,5200h       
                INT  21h        ;ES:BX points to memory block anchor+2
                DEC  BX
                DEC  BX
                MOV  ES,ES:[BX] ;get first memory block address into ES
                POP  BX
                POP  AX
                RET
getfirstsb      ENDP

getnextsb       PROC near
                PUSH AX
                MOV  AX,ES             ;get current paragraph
                ADD  AX,[SBLENGTH]     ;add in number of paragraphs
                INC  AX                ;add 1 for header
                MOV  ES,AX             ;set new extra segment address
                POP  AX
                RET
getnextsb       ENDP

hexformat       equ  $
hexaddrhi       dw   0
hexaddrlo       dw   0
                db   ':0  '
hexdata         dw   18 dup(0) 
hexdataend      db   '*$'
hexend          db   '*'
crlf            db   cr,lf,'$'
indent          db   5 dup(' '),'$'

asciizl         proc near              ;string, length in CX
                                       ; at ES:DI searched for 0h
                                       ;new length in CX
                push  ax
                xor   al,al            ;search for zero
                call  charstrl
                pop   ax

                ret

asciizl         endp

charstrl        proc  near             ;string length in CX
                                       ;string at ES:DI searched for char in AL
                                       ;new length in CX
                push  ax
                push  di               ;save register

                push  cx               ;save cx
                repnz scasb            ;do search
                jcxz  charsterror      ;if cx exhausted, may be error
charsthit:
                mov   ax,cx            ;save count remaining
                pop   cx               ;restore old cx
                sub   cx,ax            ;subtract length
                dec   cx               ;knock off 1 for failed test
                jcxz  charstnull       ;if zero length, error
                clc                    ;clear carry flag
                jmp   charstexit       ;and exit
                
charsterror:
                dec   di               ;back up
                cmp   al,es:[di]       ;check last byte 
                je    charsthit        ;if what we want, use it

                pop   cx               ;pull off saved cx
charstnull:
                stc                    ;set error flag
charstexit:     
                pop   di               ;restore registers
                pop   ax
                ret

charstrl        endp

hextocharlist   db   '0123456789ABCDEF'

hextochar       PROC near              ;AL (hex) -> AX (characters)
                PUSH SI
                PUSH DX
                PUSH CX
                PUSH AX
                XOR  DX,DX
                AND  AX,0fh            ;isolate low nibble
                ADD  AX,offset hextocharlist
                MOV  SI,AX             ;get address of character
                MOV  DH,[SI]           ;get character
                POP  AX
                AND  AX,0f0h           ;isolate high nibble
                MOV  CL,4
                SHR  AX,CL
                ADD  AX,offset hextocharlist
                MOV  SI,AX             ;get address of character
                OR   DL,[SI]           ;get character
                MOV  AX,DX
                POP  CX
                POP  DX
                POP  SI
                RET
hextochar       ENDP 

Hexline         proc near         ;type paragraph at ES: in hex
                push si
                push cx
                push ax
                push es
                pop  ax
                call hextochar    ;get low byte
                mov  hexaddrlo,ax
                push es
                pop  ax
                mov  al,ah        ;get high byte
                call hextochar
                mov  hexaddrhi,ax
                xor  si,si
                mov  di,offset hexdata
                mov  cx,4
hexparaloop:                      ;loop 4 times per paragraph
                push cx
                mov  cx,4
hexwordloop:                      ;loop 4 times per doubleword
                mov  al,es:[si]
                call hextochar
                mov  ds:[di],ax
                inc  di
                inc  di
                inc  si
                loop hexwordloop 

                mov  byte ptr ds:[di],' '
                inc  di
                pop  cx
                loop hexparaloop

                pop  ax
                pop  cx
                pop  si
                ret
hexline         endp 
 
chartype        proc near          ;type CX bytes at ES:DI if typable
                stc                ;possible error
                jcxz chartypeexit  ;if nothing to type, exit
                push ax
                push cx
                push dx
                push di
chartypeloop:
                mov  dl,es:[di]
                cmp  dl,126        ;printer/console
;               cmp  dl,254        ;console only
                ja   chartypefix               
                cmp  dl,31
                ja   chartypeit
                jmp  chartypefix   ;printer/console
                cmp  dl,26         ;console only
                ja   chartypefix
                cmp  dl,13
                ja   chartypeit
                cmp  dl,6
                ja   chartypefix
                cmp  dl,0
                ja   chartypeit

chartypefix:    mov  dl,'.'
chartypeit:     mov  ax,0200h
                int  21h
                inc  di
                loop chartypeloop

                clc                ;no error

                pop  di
                pop  dx
                pop  cx
                pop  ax
chartypeexit:
                ret
chartype        endp     

hextype         proc near       ;proc to hex type data at ES:0
                push ax
                push cx 
                push dx
                push di
                call hexline
                mov  dx,offset hexformat
                call typestring
                mov  cx,16
                xor  di,di
                call chartype
                mov  dx,offset hexend
                call typestring
                pop  di
                pop  dx
                pop  cx
                pop  ax
                ret
hextype         endp

sbbackup       proc  near           ;decrement es by one
               push   ax            ;save work register

               push   es            ;back up
               pop    ax
               dec    ax            ;and address storage block header
               push   ax
               pop    es

               pop    ax            ;restore work register
               ret
sbbackup       endp               

sbinc          proc  near           ;increment es by one
               push   ax            ;save work register

               push   es            
               pop    ax
               inc    ax            ;and address storage block contents
               push   ax                                       
               pop    es

               pop    ax            ;restore work register
               ret
sbinc       endp               


progenvmsg     db   'Program environment block questionable',cr,lf,'$'

progenvend     proc near            ;find end of environment in ES:0
               push   ax            ;update DI, remaining length in CX
               push   bx
               push   dx
               push   es

               call   sbbackup      ;backup over storage block header
               mov    bx,[sblength] ;get length of storage block
               pop    es            ;restore ES
               push   es            ;restore stack
               mov    cl,4          ;multiply BX by 16
               shl    bx,cl
               mov    cx,bx         ;number of words in environment
               xor    di,di
               xor    ax,ax
               cld                  ;scan forward
progenvscan:                        ;loop through environment
               scasw                ;compare a word at ES:DI
               jz     progenvfinis  ;if equal, exit loop
               dec    di            ;go forward only 1 byte
               loop   progenvscan   ;and scan on
progenvfinis:
               jcxz   progenvshort  ;if we ran out, error
               dec    di            ;back up a byte
               mov    ax,1          ;now look for '0001'h
progenvedit:
               scasw
               jz     progenvprog   ;got one? then go on
               dec    di            ;back up a byte
               loop   progenvedit
               jcxz   progenvshort
progenvprog:
               clc                  ;clear carry flag
                                    ;ES:DI points to program name
               jmp    progenvexit   

progenvshort:
               mov    dx,offset progenvmsg
progenverror:
               call   typestring
               stc                  ;set carry flag
progenvexit:             
               pop    es            ;restore registers
               pop    dx
               pop    bx
               pop    ax
               ret
progenvend     endp

progtypedos2msg    db   'Program name not available in DOS 2.0',cr,lf,'$'
progtypeformat     db   'Program name:$'
progtypenameover   db   '     program name overlaid',cr,lf,'$'

progtypename   proc   near          ;es points to environment
               push  dx
               push  bx
               push  ax
               mov   ah,30h         ;get release number
               int   21h
               cmp   al,02h         ;above dos 2.0?
               jna   progtypedos2

               call progenvend      ;find environment end in ES:DI, length: CX

               jc   progtypenoname  ;if not found, just exit

               mov  dx,offset progtypeformat  ;type out header
               call typestring
               mov  dx,offset indent
               call typestring
               call asciizl         ;length of asciiz string at ES:DI to CX
               jc   progtypenoname

               cmp  cx,3              ;minimum length of individual item
               jb   progtypenoname

               cmp  cx,255            ;maximum length of individual item
               ja   progtypenoname

               call chartype

               mov  dx,offset crlf
               call typestring
               clc
               jmp  progtypenameexit

progtypedos2:
               mov  dx,offset progtypedos2msg
               call typestring
               stc
               jmp  progtypenameexit

progtypenoname:
               mov  dx,offset progtypenameover
               call typestring
               stc

progtypenameexit:
               pop  ax 
               pop  bx
               pop  dx
               ret

progtypename   endp

progtypeenvformat  db   'Program environment string at: '
progtypeenvaddhi   dw   0
progtypeenvaddlo   dw   0
                   db   ':0',cr,lf,'$'

progtypeenvbadmsg  db   'Program environment string overlaid',cr,lf,'$'

progtypeenv    proc near            ;type out environment strings at ES:0

               push ax
               push cx
               push di
               push dx

               push es
               pop  ax
               call hextochar 
               mov  progtypeenvaddlo,ax
               push es
               pop  ax
               mov  al,ah
               call hextochar 
               mov  progtypeenvaddhi,ax

               mov  dx,offset progtypeenvformat
               call typestring

               xor  di,di           ;type out environment strings

               cmp  byte ptr es:[di],0  ;common type of trashing of environment
               je   progtypeenvbad

               xor  ax,ax           ;make ax zero for end of environment search

progtypeenvloop:
               mov  dx,offset indent  ;print out some blanks
               call typestring
               mov  cx,128            ;search a ways
               call asciizl           ;get length of asciiz string
               jc   progtypeenvbad    ;if error, skip out

               cmp  cx,3              ;minimum length of individual item
               jb   progtypeenvbad

               cmp  cx,255            ;maximum length of individual item
               ja   progtypeenvbad
               
               call chartype          ;type it out
               jc   progtypeenvbad    ;if error, skip out

               add  di,cx             ;add in its length
               mov  dx,offset crlf    ;print out a cr, lf
               call typestring

               scasw                  ;look at next word
               jz   progtypeenvend    ;if zero, end of environment
               dec  di                ;otherwise back up a byte
               jmp  progtypeenvloop   ;and look again

progtypeenvbad:
               mov  dx,offset progtypeenvbadmsg  ;complain about environment
               call typestring
               stc                     ;return error

progtypeenvend:
               pop  dx
               pop  di
               pop  cx
               pop  ax
               ret

progtypeenv    endp 

progtypeparmformat db   'Program calling parameters: $'
progtypeparmnone   db   '(none)',cr,lf,'$'

progtypeparm   proc near         ;type out parm area of PSP at ES:0
               push ax
               push cx
               push di
               push dx

               mov  dx,offset progtypeparmformat
               call typestring        ;print out heading

               mov  di,offset pspparm   ;ES:DI to parameter list
               mov  al,es:[di]          ;get parm length
               cmp  al,127              ;if impossible, skip out
               ja   progtypenoparm    

               inc  di                ;now look at actual data
               mov  cx,255 
               mov  al,cr             ;look for carriage return
               call charstrl          ;get actual length of parms
               jc   progtypenoparm    ;error detected, forget it

               jcxz progtypenoparm    ;if null parm,  skip out
               cmp  cx,127            ;if impossible, skip out
               ja   progtypenoparm

               call chartype          ;if good, type out

               mov  dx,offset crlf
               call typestring
               clc
               jmp  progtypeparmexit

progtypenoparm:      ;no parms
               mov  dx,offset progtypeparmnone
               call typestring
               stc

progtypeparmexit:
               pop  dx
               pop  di
               pop  cx
               pop  ax
               ret
progtypeparm   endp

progtypenoenvmsg   db   'Program has no environment block',cr,lf,'$'
progtypefirstprog  db   0
yes                equ  1
progtypedospsp     dw   0    ;segment address of first command.com resident part

progtype       proc near         ;format program storage block at ES:0
               push ax

               push bx
               push cx
               push dx
               push es

               clc
               call sbinc        ;program follows SB header
               push es           ;save ES in BX
               pop  bx

               mov  ax,[mydosfunction] 
               cmp  ax,[pspdosfunction] ;check PSP validity                
               jne  progtypenoenv       ;around byte 0h

               mov  ax,[myretint]
               cmp  ax,[pspretint]      ;check PSP validity
               jne  progtypenoenv       ;if invalid, skip looking for env

               cmp  progtypefirstprog,yes  ;is this the first program
               je   progtypenotdos
               mov  progtypefirstprog,yes
               push ES
               pop  AX
               mov  progtypedospsp,AX   ;save first resident command.com

progtypenotdos:
               mov  ax,[pspenv]         ;get environment of program
               cmp  ax,0
               je   progtypenoenv       ;if no environment, say so
               push ax
               pop  es                  ;ES points to environment

               call progtypename        ;format program name from environment

               call progtypeenv         ;format environment strings

               push bx
               pop  es                  ;back to looking at program PSP

               call progtypeparm        ;format program parm area

               jmp  progtypeend


progtypenoenv: ;no environment (!!)
               mov  dx,offset progtypenoenvmsg
               call typestring
               stc

progtypeend:
               pop  es
               pop  dx
               pop  cx
               pop  bx
               pop  ax

               ret
progtype       endp

sbformat       equ  $
               db   'Storage block at:'
sbaddrhi       dw   0
sbaddrlo       dw   0
               db   ':0  PSP of owner at:' 
sbpsphi        dw   0
sbpsplo        dw   0
               db   ':0  Block length:' 
sblengthhi     dw   0
sblengthlo     dw   0
sbcrlf         db   cr,lf,'$'

sbglobalmsg    db   'Storage block is the global environment',cr,lf,'$'
sbnotprogmsg   db   'Storage block is not a program',cr,lf,'$'
sbsystemmsg    db   'Storage block is system owned',cr,lf,'$'
sbfreemsg      db   'Storage block is free',cr,lf,'$'
sbconfigmsg    db   'Storage block belongs to CONFIG.SYS',cr,lf,'$'
sbprogmsg      db   'Storage block is a program',cr,lf,'$'
sbproghead     db   'Program PSP contents:',cr,lf,'$'
sbdatahead     db   'Storage block contents: (first 128 bytes)',cr,lf,'$'
sbhead         db   'Storage header contents:',cr,lf,'$'

sbtype          proc  near        ;format out block
                push ax           ;save registers
                push cx
                push dx
                push es                    ;format out block header
                pop  ax                    ;format block address
                call hextochar                 ;get low byte
                mov  sbaddrlo,ax
                push es
                pop  ax
                mov  al,ah                     ;get high byte
                call hextochar
                mov  sbaddrhi,ax

                mov  al,byte ptr sblength  ;format block length
                call hextochar 
                mov  sblengthlo,ax
                mov  al,byte ptr sblength+1 
                call hextochar 
                mov  sblengthhi,ax

                mov  al,byte ptr sbpsp     ;format block psp pointer
                call hextochar 
                mov  sbpsplo,ax
                mov  al,byte ptr sbpsp+1 
                call hextochar 
                mov  sbpsphi,ax

                mov  dx,offset sbformat    ;type out formatted data
                call typestring

                mov  ax,[sbpsp]            ;get PSP of owner
                cmp  ax,0                  ;if zero, it is free
                je   sbfree

                cmp  ax,8                  ;if PSP of owner is at 8
                je   sbconfig              ;block owned by config.sys

                cmp  ax,progtypedospsp     ;is owner command.com
                je   sbglobalenv
                                           ;get address of SB
                push es
                pop  ax

                cmp  ax,[sbpsp]            ;compare to address of owner
                ja   sbsystem              ;if owner below SB, system-owned

                add  ax,[sblength]         ;add in length
                cmp  ax,[sbpsp]            ;compare to owner's PSP
                JB   sbnotprogram          ;if end below owner PSP, no program
                cmp  [sblength],10         ;is block long enough to have a psp?
                jbe  sbnotprogram          ;if not, no program

                mov  dx,offset sbprogmsg   ;type out formatted data
                call typestring

                call progtype

                mov  dx,offset sbproghead   ;type out formatted data
                jmp  sbjoin                                              

sbglobalenv:      
                mov  dx,offset sbglobalmsg   ;say it is global envrionment
                call typestring
                push es
                call sbinc
                call progtypeenv             ;type out environment
                pop  es                     
                mov  dx,offset sbdatahead    ;type heading for hex data
                jmp  sbjoin                                              
sbsystem:      
                mov  dx,offset sbsystemmsg   ;say it belongs to the system
                call typestring
                mov  dx,offset sbdatahead    ;type heading for hex data
                jmp  sbjoin                                              

sbnotprogram:
                mov  dx,offset sbnotprogmsg   ;say it is not a program
                call typestring
                mov  dx,offset sbdatahead     ;type heading for hex data
                jmp  sbjoin                                              
sbfree:
                mov  dx,offset sbfreemsg      ;say it is free storage
                call typestring
                mov  dx,offset sbdatahead     ;type heading for hex data
                jmp  sbjoin                                              

sbconfig:
                mov  dx,offset sbconfigmsg     ;say it belongs to config.sys
                call typestring
                mov  dx,offset sbdatahead      ;type heading for hex data

sbjoin:
                call typestring

sbdisplay:
                mov  cx,[sblength]         ;format first 16 or less paragraphs
                cmp  cx,16
                jb   sbsmall
                mov  cx,16
sbsmall:        
                push es                    ;save ES:
sbloop:         
                mov  ax,es
                inc  ax 
                mov  es,ax
                call hextype
                loop sbloop

sbexit:

                pop  es                    ;restore registers
                pop  dx
                pop  cx
                pop  ax
                ret

sbtype          endp

badblok_msg     db    'Bad storage block encountered',cr,lf,'$'
lastblok_msg    db    'End of storage block chain reached',cr,lf,'$'
baddos_msg      db    'Must be running under DOS 2.0 or above',cr,lf,'$'

program:              ;this is the actual main line program

                mov   ah,30h         ;get release number
                int   21h
                cmp   al,01h         ;above dos 1.x?
                jna   baddos

                cld              ;clear direction flag
                call  getfirstsb  ;ES points to first SB

sblook:                          ;loop all storage blocks
                MOV   al,sbkind   ;get storage block type byte
                cmp   al,04dh     ;ordinary storage block
                je    gotblok 

                cmp   al,05ah
                je    lastblok    ;last storage block

                jmp   badblok
gotblok:       

                mov   dx,offset sbhead      ;type out formatted data 
                call  typestring 

                call  hextype

                call  sbtype

                call  getnextsb

                mov   dx,offset  crlf
                call  typestring

                jmp   sblook 
lastblok:
                call  hextype

                call  sbtype

                mov   dx,offset lastblok_msg
                jmp   sendmsg

baddos:
                mov   dx,offset baddos_msg
                jmp   sendmsg

badblok:
                call  hextype

                mov   dx,offset badblok_msg
sendmsg:             
                call  typestring
                
                INT   20h                                 
      code      ENDP
      code_seg  ENDS
                END   code







]├Uï∞ï∩≤3▓√Cèëùë>wë6y╬ë{úâ3╔█u1╟ü
Φrêuï6yΦñ
u≈â  u≈┴BtÇ╔0íàïç├ëüΦ$ëuVΦ▀ 7Ç╔0δ%Ç╔0¥u≈█≈à▀
[ RETURN TO DIRECTORY ]