home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PROGRAMS / UTILS / DOS_HELP / ADVMSDOS.ZIP / QCLEAN.ASM < prev    next >
Encoding:
Assembly Source File  |  1986-06-19  |  10.6 KB  |  427 lines

  1.     name    qclean
  2.     page    55,132
  3.     title    'QCLEAN --- Quick cleanup of text file'
  4.  
  5. ;
  6. ; QCLEAN --- a utility to clean up document files.
  7. ;
  8. ; This program removes all control codes except for line feeds, 
  9. ; carriage returns, and form feeds, strips off the high bit of all 
  10. ; characters, and expands tabs.  Can be used to make a Wordstar
  11. ; file acceptable for other screen or line editors, and vice versa.  
  12. ; Works very similarly to the CLEAN filter from the book Advanced 
  13. ; MS-DOS, but it needs a filename on the command line, and writes 
  14. ; the output to a new file with the same name but the extension 
  15. ; "CLN", and runs several times faster!
  16. ;
  17. ; Copyright (C) 1983 by Ray Duncan
  18. ;
  19. ; To assemble, link, and convert this program into 
  20. ; an EXE file, follow these steps:
  21. ;
  22. ;    C>MASM QCLEAN;
  23. ;     C>LINK QCLEAN;
  24. ;
  25.  
  26. cr    equ    0dh        ;ASCII carriage return
  27. lf    equ    0ah        ;ASCII line feed
  28. ff    equ    0ch        ;ASCII form feed
  29. eof    equ    01ah        ;End of file marker
  30. tab    equ    09h        ;ASCII tab character
  31.  
  32. command    equ    80h        ;buffer for command tail
  33.  
  34. blksize    equ    1024        ;blocking/deblocking size
  35.  
  36.  
  37. cseg    segment    para public 'CODE'
  38.  
  39.     assume    cs:cseg,ds:data,es:data,ss:stack
  40.  
  41.  
  42. clean    proc    far        ;entry point from PC-DOS
  43.  
  44.     push    ds        ;save DS:0000 for final
  45.     xor    ax,ax        ;return to PC-DOS
  46.     push    ax
  47.     mov    ax,data        ;make our data segment
  48.     mov    es,ax        ;addressable via ES register
  49.     call    infile        ;get path and file spec.
  50.                 ;for input file
  51.     mov    ax,es        ;set DS=ES for remainder
  52.     mov    ds,ax        ;of program
  53.     jnc    clean1        ;jump, got acceptable name
  54.     mov    dx,offset msg4    ;missing or illegal filespec,
  55.     jmp    clean9        ;print error message and exit.
  56.  
  57. clean1:    call    outfile        ;set up output file name
  58.     call    open_input    ;now try to open input file
  59.     jnc    clean2        ;jump,opened input ok
  60.     mov    dx,offset msg1    ;open of input file failed,
  61.     jmp    clean9        ;print error msg and exit.
  62.  
  63. clean2:
  64.     call    open_output    ;try to open output file.
  65.     jnc    clean25        ;jump,opened ok
  66.     mov    dx,offset msg2    ;open of output file failed,
  67.     jmp    clean9        ;print error message and exit.
  68.  
  69. clean25:            ;set up buffers
  70.     call    init_buffs
  71.     call    sign_on        ;print ident and file names
  72.  
  73.                 ;files successfully opened,        
  74. clean3:                ;now filter the file.  
  75.     call    get_char    ;read 1 character from input.
  76.     and    al,07fh        ;strip off the high bit
  77.     cmp    al,20h        ;is it a control code?
  78.     jae    clean4        ;no,write it to new file    
  79.                 ;yes it is control code,
  80.     cmp    al,eof        ;is it end of file marker?
  81.     je    clean6        ;yes,jump to close files.
  82.     cmp    al,tab        ;is it a tab command?
  83.     jz    clean5        ;yes,jump to special processing.
  84.     cmp    al,cr        ;if control code other than
  85.     je    clean35        ;tab or end-of-file mark, throw 
  86.     cmp    al,ff        ;it away unless it is a 
  87.     je    clean35        ;form feed, carriage return,
  88.     cmp    al,lf        ;or line feed.
  89.     jne    clean3        
  90. clean35:            ;If it is one of those three,
  91.     mov    column,0    ;incidentally initialize
  92.     jmp    clean45        ;column count for tab processor.
  93.  
  94. clean4:                ;count alphanumeric chars. sent.
  95.     inc    column
  96.  
  97. clean45:            ;write this character to 
  98.     call    put_char    ;output file,
  99.     jnc    clean3        ;if CY not set, write was
  100.                 ;ok so go get next char.
  101. clean47:
  102.     call    close_input    ;if CY set, disk is full
  103.     call    close_output    ;so close files and exit
  104.     mov    dx,offset msg5  ;with error message.
  105.     jmp    clean9
  106.  
  107. clean5:                ;process tab character
  108.     mov    ax,column    ;let DX:AX=column count
  109.     cwd
  110.     mov    cx,8        ;divide it by eight...
  111.     idiv    cx
  112.     sub    cx,dx        ;remainder is in DX.
  113.     add    column,cx    ;update column pointer.
  114. clean55:            ;8 minus the remainder 
  115.     push    cx        ;gives us the number of
  116.     mov    al,20h        ;spaces to send out to
  117.     call    put_char    ;move to the next tab position
  118.     pop    cx        ;restore space count
  119.     jc    clean47        ;jump if disk is full
  120.     loop    clean55
  121.     jmp    short clean3    ;get next character 
  122.  
  123. clean6:                ;end of file detected,
  124.     call    put_char    ;write end-of-file marker,
  125.     jc    clean47        ;jump if disk was full
  126.     call    flush_buffs    ;write remaining data to disk
  127.     jc    clean47        ;if CY set,disk was full
  128.                 ;otherwise file was written ok    
  129.     call    close_input    ;close input and output 
  130.     call    close_output    ;files.
  131.     mov    dx,offset msg3    ;addr of success message,
  132.  
  133. clean9:                ;print message and return
  134.     mov    ah,9        ;control to PC-DOS
  135.     int    21h
  136.     ret
  137.  
  138. clean    endp
  139.  
  140.  
  141. infile    proc    near        ;process name of input file
  142.                 ;DS:SI <- addr command line    
  143.     mov    si,offset command
  144.                 ;ES:DI <- addr filespec buffer
  145.     mov    di,offset input_name
  146.     cld
  147.     lodsb            ;any command line present?
  148.     or    al,al        ;return error status if not.
  149.     jz    infile4
  150. infile1:                 ;scan over leading blanks
  151.     lodsb            ;to file name
  152.     cmp    al,cr        ;if we hit carriage return
  153.     jz    infile4     ;filename is missing.
  154.     cmp    al,20h        ;is this a blank?
  155.     jz    infile1        ;if so keep scanning.
  156.  
  157. infile2:             ;found first char of name,
  158.     stosb            ;move last char. to output
  159.                 ;file name buffer. 
  160.     lodsb            ;check next character, found
  161.     cmp    al,cr        ;carriage return yet?      
  162.     je    infile3        ;yes,exit with success code
  163.     cmp    al,20h        ;is this a blank?
  164.     jne     infile2        ;if not keep moving chars.
  165.  
  166. infile3:             ;exit with carry =0
  167.     clc            ;for success flag
  168.     ret
  169.  
  170. infile4:             ;exit with carry =1
  171.     stc            ;for error flag
  172.     ret
  173. infile  endp 
  174.  
  175. outfile    proc    near        ;set up path and file
  176.     cld            ;name for output file.
  177.     mov    cx,64        ;length to move
  178.     mov    si,offset input_name  ;source addr
  179.     mov    di,offset output_name ;dest addr
  180.     rep movsb        ;transfer the string
  181.     mov    di,offset output_name
  182. outfile1:            ;scan string looking for
  183.     mov    al,[di]     ;"." marking start of extension
  184.     or    al,al        ;or zero byte marking name end.
  185.     jz    outfile2    ;if either is found,jump.
  186.     cmp    al,'.'
  187.     je    outfile2    ;bump string pointer, loop
  188.     inc    di        ;if neither '.' or zero found.
  189.     jmp    outfile1    
  190. outfile2:            ;found zero or '.',force the
  191.                 ;extension of the output file    
  192.                 ;to '.CLN'
  193.     mov    si,offset outfile_ext
  194.     mov    cx,5
  195.     rep movsb
  196.     ret            ;back to caller
  197. outfile endp
  198.  
  199. open_input proc near        ;open input file
  200.                 ;DS:DX=addr filename
  201.     mov    dx,offset input_name
  202.     mov    al,0        ;AL=0 for read only
  203.     mov    ah,3dh        ;function 3dh=open
  204.     int     21h        ;handle returned in AX,
  205.     mov    input_handle,ax ;save it for later.
  206.     ret            ;CY is set if error
  207. open_input endp
  208.  
  209. open_output proc near        ;open output file
  210.                 ;DS:DX=addr filename
  211.     mov    dx,offset output_name
  212.     mov    al,1        ;AL=1 for write    only
  213.     mov    ah,3ch        ;function 3ch=MAKE or
  214.     int    21h        ;truncate existing file
  215.                 ;handle returned in AX
  216.     mov    output_handle,ax;save it for later.
  217.     ret            ;return CY=true if error
  218. open_output endp
  219.  
  220. close_input proc near        ;close input file
  221.     mov    bx,input_handle ;BX=handle
  222.     mov    ah,3eh
  223.     int    21h
  224.     ret
  225. close_input endp
  226.  
  227. close_output proc near        ;close output file
  228.     mov    bx,output_handle;BX=handle
  229.     mov    ah,3eh
  230.     int    21h
  231.     ret
  232. close_output endp
  233.  
  234. get_char proc     near        ;get one character from input buffer
  235.     mov    bx,input_ptr
  236.     cmp    bx,blksize
  237.     jne    get_char1
  238.     call    read_block
  239.     mov    bx,0
  240. get_char1:
  241.     mov    al,[input_buffer+bx]
  242.     inc    bx
  243.     mov    input_ptr,bx
  244.     ret
  245. get_char endp    
  246.  
  247. put_char proc    near        ;put one character into output buffer
  248.     mov    bx,output_ptr
  249.     mov    [output_buffer+bx],al
  250.     inc    bx
  251.     mov    output_ptr,bx
  252.     cmp    bx,blksize    ;buffer full yet?
  253.     jne    put_char1    ;no,jump
  254.     call    write_block    ;yes,write the block
  255.     ret            ;return CY as status code
  256. put_char1:
  257.     clc            ;return CY clear for OK status
  258.     ret
  259. put_char endp
  260.  
  261. read_block proc near
  262.     mov    bx,input_handle ;read first block of input
  263.     mov    cx,blksize
  264.     mov    dx,offset input_buffer
  265.     mov    ah,3fh
  266.     int    21h
  267.     jnc    read_block1    ;jump if no error status
  268.     mov    ax,0        ;simulate a zero length read if error
  269. read_block1:            
  270.     cmp    ax,blksize    ;was full buffer read in?
  271.     je    read_block2    ;yes,jump
  272.     mov    bx,ax        ;no, store End-of-File mark
  273.     mov    byte ptr [input_buffer+bx],eof
  274. read_block2:
  275.     xor    ax,ax        ;initialize input buffer pointer
  276.     mov    input_ptr,ax    
  277.     ret
  278. read_block endp
  279.  
  280. write_block proc near        ;write blocked output (blksize bytes)
  281.     mov    dx,offset output_buffer
  282.     mov    cx,blksize
  283.     mov    bx,output_handle
  284.     mov    ah,40h
  285.     int    21h
  286.     xor    bx,bx        ;initialize pointer to blocking buffer
  287.     mov    output_ptr,bx
  288.     cmp    ax,blksize    ;was correct length written?
  289.     jne    write_block1    ;no,disk must be full
  290.     clc            ;yes,return CY=0 indicating all OK
  291.     ret
  292. write_block1:            ;disk is full, return CY =1
  293.     stc            ;as error code
  294.     ret
  295. write_block endp
  296.  
  297. init_buffs proc near
  298.     call    read_block    ;read 1st block of input
  299.     xor    ax,ax        ;initialize pointer to output
  300.     mov    output_ptr,ax    ;output blocking buffer
  301.     ret
  302. init_buffs endp
  303.  
  304. flush_buffs proc near        ;write any data in output buffer to disk
  305.     mov    cx,output_ptr
  306.     or    cx,cx
  307.     jz    flush_buffs1    ;jump,buffer is empty
  308.     mov    bx,output_handle
  309.     mov    dx,offset output_buffer
  310.     mov    ah,40h
  311.     int    21h
  312.     cmp    ax,output_ptr    ;was write successful?
  313.     jnz    flush_buffs2    ;no,jump
  314. flush_buffs1: 
  315.     clc            ;yes,return CY=0 for
  316.     ret            ;success flag
  317. flush_buffs2:            ;disk was full so write failed,
  318.     stc            ;return CY=1 as error flag
  319.     ret
  320. flush_buffs endp
  321.  
  322. sign_on proc    near        ;print sign-on message
  323.     mov    dx,offset msg6    ;title...
  324.     mov    ah,9
  325.     int    21h
  326.     mov    dx,offset msg7    ;input file:
  327.     mov    ah,9
  328.     int    21h
  329.     mov    dx,offset input_name
  330.     call    pasciiz
  331.     mov    dx,offset msg8    ;output file:
  332.     mov    ah,9
  333.     int    21h
  334.     mov    dx,offset output_name
  335.     call    pasciiz
  336.     mov    dx,offset msg9
  337.     mov    ah,9
  338.     int    21h
  339.     ret
  340. sign_on    endp
  341.  
  342. pasciiz    proc    near        ;call DX=offset of ASCIIZ string
  343.     mov    bx,dx        ;which will be printed on standard output
  344. pasciiz1:
  345.     mov    dl,[bx]
  346.     or    dl,dl
  347.     jz    pasciiz9
  348.     cmp    dl,'A'
  349.     jb    pasciiz2
  350.     cmp    dl,'Z'
  351.     ja    pasciiz2
  352.     or    dl,20h
  353. pasciiz2:
  354.     mov    ah,2
  355.     int    21h
  356.     inc    bx
  357.     jmp    pasciiz1
  358. pasciiz9:
  359.     ret
  360. pasciiz endp
  361.  
  362. cseg    ends
  363.  
  364.  
  365. data    segment    para public 'DATA'
  366.  
  367. input_name    db    64 dup (0)    ;buffer for input filespec
  368. output_name    db    64 dup (0)    ;buffer for output filespec    
  369.  
  370. input_handle    dw    0        ;token returned by PCDOS
  371. output_handle    dw    0        ;token returned by PCDOS
  372.  
  373. input_ptr    dw    0        ;pointer to input blocking buffer
  374. output_ptr    dw    0        ;pointer to output blocking buffer
  375.  
  376. outfile_ext    db     '.CLN',0    ;extension for filtered file
  377.  
  378. column        dw    0        ;column count for tab processing
  379.  
  380. msg1        db    cr,lf
  381.         db    'Cannot find input file.'
  382.         db    cr,lf,'$'
  383.  
  384. msg2        db    cr,lf
  385.         db    'Failed to open output file.'
  386.         db    cr,lf,'$'
  387.  
  388. msg3        db    cr,lf
  389.         db    'File processing completed'
  390.         db    cr,lf,'$'
  391.  
  392. msg4        db    cr,lf
  393.         db    'Missing file name.'
  394.         db    cr,lf,'$'
  395.  
  396. msg5        db    cr,lf
  397.         db    'Disk is full.'
  398.         db    cr,lf,'$'
  399.  
  400. msg6        db    cr,lf
  401.         db    'Clean Word Processing File'
  402.         db    cr,lf
  403.         db    'Copyright (c) 1983 Ray Duncan'
  404.         db    cr,lf,'$'
  405.  
  406. msg7        db    cr,lf,'Input file:   $'
  407.  
  408. msg8        db    cr,lf,'Output file:  $'
  409.  
  410. msg9        db    cr,lf,'$'
  411.  
  412.  
  413. input_buffer    db    blksize dup (?)    ;buffer for deblocking of data
  414.                     ;from input file
  415.  
  416. output_buffer    db    blksize dup (?)    ;buffer for blocking of data
  417.                     ;sent to output file
  418.  
  419. data     ends    
  420.  
  421.  
  422. stack    segment    para stack 'STACK'
  423.     db    64 dup (?)
  424. stack    ends
  425.  
  426.     end    clean
  427.