home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / advmsdos / chap08 / dump.asm next >
Encoding:
Assembly Source File  |  1988-10-01  |  11.0 KB  |  437 lines

  1.         title   DUMP --- display file contents
  2.         page    55,132
  3.  
  4. ;  DUMP --- Display contents of file in hex and ASCII
  5. ;
  6. ;  Build:   C>MASM DUMP;
  7. ;           C>LINK DUMP;
  8. ;  Usage:   C>DUMP unit:\path\filename.exe [ >device ]
  9. ;  Copyright 1988 Ray Duncan
  10.  
  11. cr      equ     0dh             ; ASCII carriage return
  12. lf      equ     0ah             ; ASCII line feed
  13. tab    equ    09h        ; ASCII tab code
  14. blank    equ    20h        ; ASCII space code
  15.  
  16. cmd     equ     80h             ; buffer for command tail
  17.  
  18. blksize equ     16        ; input file record size
  19.  
  20. stdin    equ    0        ; standard input handle
  21. stdout     equ     1                 ; standard output handle
  22. stderr     equ     2        ; standard error handle
  23.  
  24.  
  25. _TEXT    segment    word public 'CODE'
  26.  
  27.         assume  cs:_TEXT,ds:_DATA,es:_DATA,ss:STACK
  28.  
  29.  
  30. dump    proc    far         ; entry point from MS-DOS
  31.  
  32.         push    ds              ; save DS:0000 for final
  33.         xor     ax,ax           ; return to MS-DOS, in case
  34.         push    ax        ; Function 4CH can't be used.    
  35.  
  36.         mov     ax,_DATA        ; make our data segment
  37.         mov     ds,ax           ; addressable via DS register.
  38.  
  39.                 ; check MS-DOS version
  40.         mov     ax,3000h    ; Fxn 30H = get version
  41.         int     21h        ; transfer to MS-DOS
  42.         cmp     al,2        ; major version 2 or later?
  43.         jae     dump1           ; yes, proceed
  44.  
  45.                 ; if MS-DOS 1.x, display
  46.                 ; error message and exit
  47.         mov     dx,offset msg3  ; DS:DX = message address
  48.     mov    ah,9        ; Fxn 9 = print string
  49.     int    21h        ; transfer to MS-DOS
  50.     ret            ; then exit the old way
  51.  
  52. dump1:              ; check if filename present
  53.     mov    bx,offset cmd    ; ES:BX = command tail
  54.     call    argc        ; count command arguments
  55.     cmp    ax,2        ; are there 2 arguments?
  56.     je    dump2        ; yes, proceed
  57.  
  58.                 ; missing filename, display
  59.                 ; error message and exit
  60.         mov     dx,offset msg2  ; DS:DX = message address
  61.     mov    cx,msg2_len    ; CX = message length
  62.         jmp     dump9           ; go display it
  63.  
  64. dump2:                ; get address of filename
  65.     mov    ax,1        ; AX = argument number
  66.                 ; ES:BX still = command tail
  67.     call    argv        ; returns ES:BX = address,
  68.                 ; and AX = length
  69.  
  70.     mov    di,offset fname    ; copy filename to buffer
  71.     mov    cx,ax        ; CX = length
  72.  
  73. dump3:    mov    al,es:[bx]    ; copy one byte
  74.     mov    [di],al
  75.     inc    bx            ; bump string pointers
  76.     inc    di
  77.     loop    dump3        ; loop until string done
  78.     mov    byte ptr [di],0    ; add terminal null byte
  79.  
  80.     mov    ax,ds        ; make our data segment
  81.     mov    es,ax        ; addressable by ES too
  82.  
  83.                 ; now open the file
  84.     mov    ax,3d00h    ; Fxn 3DH = open file
  85.                 ; mode 0 = read only
  86.     mov    dx,offset fname    ; DS:DX = filename
  87.     int    21h        ; transfer to MS-DOS
  88.     jnc    dump4        ; jump, open successful
  89.  
  90.                 ; open failed, display
  91.                 ; error message and exit
  92.     mov    dx,offset msg1    ; DS:DX = message address
  93.     mov    cx,msg1_len    ; CX = message length
  94.     jmp    dump9        ; go display it
  95.  
  96. dump4:    mov    fhandle,ax    ; save file handle
  97.  
  98. dump5:              ; read block of file data
  99.     mov    bx,fhandle    ; BX = file handle
  100.     mov    cx,blksize    ; CX = record length
  101.     mov    dx,offset fbuff    ; DS:DX = buffer
  102.     mov    ah,3fh        ; Fxn 3FH = read
  103.     int    21h        ; transfer to MS-DOS
  104.  
  105.     mov    flen,ax        ; save actual length
  106.     cmp    ax,0        ; end of file reached?
  107.     jne    dump6        ; no, proceed
  108.  
  109.     cmp    word ptr fptr,0    ; was this the first read?
  110.     jne    dump8        ; no, exit normally
  111.  
  112.                 ; display empty file
  113.                 ; message and exit
  114.     mov    dx,offset msg4    ; DS:DX = message address
  115.     mov    cx,msg4_len    ; CX = length
  116.     jmp    dump9        ; go display it
  117.  
  118. dump6:                ; display heading at 
  119.                 ; each 128 byte boundary
  120.     test    fptr,07fh    ; time for a heading?
  121.     jnz    dump7        ; no, proceed
  122.  
  123.                 ; display a heading    
  124.     mov    dx,offset hdg    ; DS:DX = heading address
  125.     mov    cx,hdg_len    ; CX = heading length
  126.     mov    bx,stdout    ; BX = standard output
  127.     mov    ah,40h        ; Fxn 40H = write
  128.     int    21h        ; transfer to MS-DOS
  129.  
  130. dump7:    call    conv        ; convert binary record
  131.                 ; to formatted ASCII
  132.     
  133.                 ; display formatted output
  134.     mov    dx,offset fout    ; DX:DX = output address
  135.     mov    cx,fout_len    ; CX = output length
  136.     mov    bx,stdout    ; BX = standard output
  137.     mov    ah,40h        ; Fxn 40H = write
  138.     int    21h        ; transfer to MS-DOS
  139.  
  140.     jmp    dump5        ; go get another record
  141.  
  142. dump8:                ; close input file
  143.     mov    bx,fhandle    ; BX = file handle
  144.     mov    ah,3eh        ; Fxn 3EH = close
  145.     int    21h        ; transfer to MS-DOS
  146.  
  147.     mov    ax,4c00h    ; Fxn 4CH = terminate,
  148.                 ; return code = 0
  149.     int    21h        ; transfer to MS-DOS
  150.  
  151. dump9:                          ; display message on
  152.                 ; standard error device
  153.                 ; DS:DX = message address
  154.                 ; CX = message length
  155.     mov    bx,stderr    ; standard error handle
  156.     mov    ah,40h        ; Fxn 40H = write
  157.     int    21h        ; transfer to MS-DOS
  158.  
  159.     mov    ax,4c01h    ; Fxn 4CH = terminate,
  160.                 ; return code = 1
  161.     int    21h        ; transfer to MS-DOS
  162.     
  163. dump    endp
  164.  
  165.  
  166. conv     proc    near        ; convert block of data
  167.                 ; from input file
  168.  
  169.     mov    di,offset fout     ; clear output format 
  170.     mov    cx,fout_len-2    ; area to blanks
  171.     mov    al,blank
  172.     rep stosb
  173.  
  174.     mov    di,offset fout     ; convert file offset
  175.     mov    ax,fptr        ; to ASCII for output
  176.     call    w2a
  177.  
  178.     mov    bx,0        ; init. buffer pointer
  179.  
  180. conv1:    mov    al,[fbuff+bx]    ; fetch byte from buffer
  181.     mov    di,offset foutb    ; point to output area
  182.             
  183.                 ; format ASCII part...
  184.                 ; store '.' as default
  185.     mov    byte ptr [di+bx],'.'
  186.  
  187.     cmp    al,blank    ; in range 20H - 7EH?
  188.     jb    conv2        ; jump, not alphanumeric.
  189.  
  190.     cmp    al,7eh        ; in range 20H - 7EH?
  191.     ja    conv2        ; jump, not alphanumeric.
  192.  
  193.     mov    [di+bx],al    ; store ASCII character.
  194.  
  195. conv2:                ; format hex part...
  196.     mov    di,offset fouta ; point to output area
  197.     add    di,bx        ; base addr + (offset*3)
  198.     add    di,bx
  199.     add    di,bx
  200.     call    b2a        ; convert byte to hex 
  201.  
  202.     inc    bx        ; advance through record
  203.     cmp    bx,flen        ; entire record converted?
  204.     jne    conv1        ; no, get another byte
  205.  
  206.                 ; update file pointer
  207.     add    word ptr fptr,blksize
  208.  
  209.     ret
  210.  
  211. conv    endp
  212.  
  213.  
  214. w2a    proc    near        ; convert word to hex ASCII
  215.                 ; call with AX = value
  216.                 ;           DI = addr for string
  217.                 ; returns AX, DI, CX destroyed
  218.  
  219.     push    ax        ; save copy of value        
  220.     mov    al,ah
  221.     call    b2a        ; convert upper byte    
  222.  
  223.     pop    ax        ; get back copy
  224.     call    b2a        ; convert lower byte
  225.     ret
  226.  
  227. w2a    endp
  228.  
  229.  
  230. b2a    proc    near              ; convert byte to hex ASCII
  231.                                 ; call with AL=binary value
  232.                 ;           DI=addr for string
  233.                                 ; returns   AX, DI, CX modified 
  234.  
  235.     sub    ah,ah        ; clear upper byte
  236.     mov    cl,16
  237.     div    cl        ; divide byte by 16
  238.     call    ascii        ; quotient becomes the first
  239.     stosb            ; ASCII character
  240.     mov    al,ah
  241.     call    ascii        ; remainder becomes the
  242.     stosb            ; second ASCII character
  243.     ret
  244.  
  245. b2a    endp
  246.  
  247.  
  248. ascii   proc     near        ; convert value 0-0FH in AL 
  249.                 ; into "hex ASCII" character
  250.         
  251.         add     al,'0'        ; offset to range 0-9
  252.         cmp     al,'9'        ; is it > 9?
  253.         jle     ascii2        ; no, jump
  254.         add     al,'A'-'9'-1    ; offset to range A-F,
  255.  
  256. ascii2:    ret            ; return AL = ASCII char.
  257.  
  258. ascii    endp
  259.  
  260.  
  261. argc    proc    near        ; count command line arguments
  262.                 ; call with ES:BX = command line
  263.                 ; returns   AX = argument count
  264.  
  265.     push    bx        ; save original BX and CX 
  266.     push    cx        ;  for later
  267.     mov    ax,1        ; force count >= 1
  268.  
  269. argc1:    mov    cx,-1        ; set flag = outside argument
  270.  
  271. argc2:    inc    bx        ; point to next character 
  272.     cmp    byte ptr es:[bx],cr
  273.     je    argc3        ; exit if carriage return
  274.     cmp    byte ptr es:[bx],blank
  275.     je    argc1        ; outside argument if ASCII blank
  276.     cmp    byte ptr es:[bx],tab    
  277.     je    argc1        ; outside argument if ASCII tab
  278.  
  279.                 ; otherwise not blank or tab,
  280.     jcxz    argc2        ; jump if already inside argument
  281.  
  282.     inc    ax        ; else found argument, count it
  283.     not    cx        ; set flag = inside argument
  284.     jmp    argc2        ; and look at next character
  285.  
  286. argc3:    pop    cx        ; restore original BX and CX
  287.     pop    bx
  288.     ret            ; return AX = argument count
  289.  
  290. argc    endp
  291.  
  292.  
  293. argv    proc    near        ; get address & length of
  294.                 ; command line argument
  295.                 ; call with ES:BX = command line
  296.                 ;           AX    = argument no.
  297.                 ; returns   ES:BX = address
  298.                 ;           AX    = length
  299.  
  300.     push    cx        ; save original CX and DI 
  301.     push    di
  302.  
  303.     or    ax,ax        ; is it argument 0?
  304.     jz    argv8        ; yes, jump to get program name
  305.  
  306.     xor    ah,ah        ; initialize argument counter
  307.  
  308. argv1:    mov    cx,-1        ; set flag = outside argument
  309.  
  310. argv2:    inc    bx        ; point to next character 
  311.     cmp    byte ptr es:[bx],cr
  312.     je    argv7        ; exit if carriage return
  313.     cmp    byte ptr es:[bx],blank
  314.     je    argv1        ; outside argument if ASCII blank
  315.     cmp    byte ptr es:[bx],tab    
  316.     je    argv1        ; outside argument if ASCII tab
  317.  
  318.                 ; if not blank or tab...
  319.     jcxz    argv2        ; jump if already inside argument
  320.  
  321.     inc    ah        ; else count arguments found
  322.     cmp    ah,al        ; is this the one we're looking for?
  323.     je    argv4        ; yes, go find its length
  324.     not    cx        ; no, set flag = inside argument
  325.     jmp    argv2        ; and look at next character
  326.  
  327. argv4:                ; found desired argument, now
  328.                 ; determine its length...
  329.     mov    ax,bx        ; save param. starting address 
  330.  
  331. argv5:    inc    bx        ; point to next character
  332.     cmp    byte ptr es:[bx],cr
  333.     je    argv6        ; found end if carriage return
  334.     cmp    byte ptr es:[bx],blank
  335.     je    argv6        ; found end if ASCII blank
  336.     cmp    byte ptr es:[bx],tab    
  337.     jne    argv5        ; found end if ASCII tab
  338.  
  339. argv6:    xchg    bx,ax        ; set ES:BX = argument address
  340.     sub    ax,bx        ; and AX = argument length
  341.     jmp    argvx        ; return to caller
  342.  
  343. argv7:    xor    ax,ax        ; set AX = 0, argument not found
  344.     jmp    argvx        ; return to caller
  345.  
  346. argv8:                ; special handling for argv=0
  347.     mov    ax,3000h    ; check if DOS 3.0 or later
  348.     int    21h        ; (force AL=0 in case DOS 1)
  349.     cmp    al,3
  350.     jb    argv7        ; DOS 1 or 2, return null param.
  351.     mov    es,es:[2ch]    ; get environment segment from PSP
  352.     xor    di,di        ; find the program name by
  353.     xor    al,al        ; first skipping over all the
  354.     mov    cx,-1        ; environment variables...
  355.     cld
  356. argv9:    repne scasb        ; scan for double null (can't use
  357.     scasb            ; (SCASW since might be odd addr.)
  358.     jne    argv9        ; loop if it was a single null
  359.     add    di,2        ; skip count word in environment
  360.     mov    bx,di        ; save program name address
  361.     mov    cx,-1        ; now find its length... 
  362.     repne scasb        ; scan for another null byte
  363.     not    cx        ; convert CX to length 
  364.     dec    cx
  365.     mov    ax,cx        ; return length in AX
  366.  
  367. argvx:                ; common exit point
  368.     pop    di        ; restore original CX and DI
  369.     pop    cx
  370.     ret            ; return to caller
  371.  
  372. argv    endp
  373.  
  374. _TEXT    ends
  375.  
  376.  
  377. _DATA   segment word public 'DATA'
  378.  
  379. fname     db    64 dup (0)      ; buffer for input filespec
  380.  
  381. fhandle    dw    0               ; token from PCDOS for input file.
  382.  
  383. flen    dw    0        ; actual length read
  384.  
  385. fptr    dw    0        ; relative address in file 
  386.  
  387. fbuff    db    blksize dup (?)    ; data from input file
  388.  
  389. fout    db    'nnnn'        ; formatted output area
  390.     db    blank,blank
  391. fouta    db    16 dup ('nn',blank)
  392.     db    blank
  393. foutb    db    16 dup (blank),cr,lf
  394. fout_len equ    $-fout
  395.  
  396. hdg    db    cr,lf        ; heading for each 128 bytes
  397.     db    7 dup (blank)    ; of formatted output
  398.     db    '0  1  2  3  4  5  6  7  '
  399.     db    '8  9  A  B  C  D  E  F',cr,lf
  400. hdg_len equ    $-hdg
  401.  
  402.  
  403. msg1    db    cr,lf
  404.         db      'dump: file not found'
  405.     db    cr,lf
  406. msg1_len equ    $-msg1
  407.  
  408. msg2    db      cr,lf
  409.     db    'dump: missing file name'
  410.     db    cr,lf
  411. msg2_len equ    $-msg2
  412.  
  413. msg3    db      cr,lf
  414.     db      'dump: wrong MS-DOS version'
  415.     db      cr,lf,'$'
  416.  
  417. msg4    db    cr,lf
  418.     db    'dump: empty file'
  419.     db    cr,lf
  420. msg4_len equ    $-msg4
  421.  
  422. _DATA     ends    
  423.  
  424.  
  425. STACK    segment para stack 'STACK'
  426.  
  427.         db      64 dup (?)
  428.  
  429. STACK    ends
  430.  
  431.         end     dump
  432.  
  433.