; Вариант 19
; Еникеев И.Р.  2084/1
.286
.model tiny
.data
org 100h
start:  
        cmp byte ptr [from], 0  ; Test input string to non-empty
        jnz $+5
        jmp no_string

        xor cx, cx              ; Begin of work
        not cx
        mov di, offset from     
        mov al, ' '
        repz scasb              ; Skip all spaces at the beginning
        dec di
        mov real_ofs, di        ; Save offset of first non-space character

        xor ax, ax
        xor cx, cx
        not cx
        repnz scasb             ; Search for tailing zero

        dec di
        dec di                  ; di - points to last non-zero char

        not cx
        dec cx
        push cx                 ; Save full length of string

        std                     ; Change direction flag to backwards
        mov al, ' '
        xor cx, cx
        not cx
        repz scasb              ; Search for non-space charecter at the end of string

        inc di
        inc di                  ; di points to next after last non-space
        mov byte ptr [di], 0    ; Discard tailing spaces

        not cx
        dec cx                  ; Get count of tailing spaces

        pop ax                  
        sub ax, cx              ; Calculate length of trimmed string (without leading and tailing spaces)
        jg  $+5                 ; If length is positive - countinue work
        jmp no_string

        cld                     ; Restore normal direction flag
        mov cx, ax              ; Set trimmed length
        mov di, real_ofs        ; Set pointer to the beginng of string


        xor bx, bx              ; bx holds non-space chars count
        xor dx, dx              ; dx holds word count-1

word_loop:                      ; loop for calculate word and non-space char count in sentence
        mov al, [di]            ; get char from string
        test al, al             ; test for EOS
        jz next_1               ; If so - we are reached end of string
        cmp al, ' '             ; Compare with space
        jz inloop1              ; if so - skip all following spaces and inc word count
        inc bx                  ; Increment letters count
        inc di                  ; advance pointer
        dec cx                  ; decrement residuary string length
        jnz word_loop           ; if we got non-tested chars - continue loop
        jmp next_1              ; if not - end our loop

inloop1:                        ; If we've found space in input string
        inc dx                  ; Increment word count
        inc cx                  ; Inc string's length for next line's right work
        repz scasb              ; Skip all following spaces in input string
        dec di                  ; Adjust pointer to point to first non-space char
        jmp word_loop           ; Countinue loop
                
next_1: mov ax, need_len        ; Get our required output string length
        sub ax, bx              ; Decrease this length by total count of letters
                                ; to get count of spaces, that we need to arrange
                                ; between words

        cmp ax, dx              ; if that count is less than spaces we've got to put
                                ; betten words to save them separated then
        jl bad_len              ; Show error message
        
        mov bx, dx              ; bx will hold count of gaps between words
        test bx, bx             ; if we've got only one word - so we don't need any gaps
        jz just_copy

        xor dx, dx              ; clear dx for normal div's work
        div bx                  ; AX - holds count of spaces, bx - count of gaps, so
        mov toins, ax           ; new ax - holds space count in each gap, and 
                                ; dx - remainder of division

just_copy:                      ; Prepare of our main loop of creation of output string
        mov si, real_ofs        ; Source - input string
        mov di, offset to       ; Destination - memory to hold output string
        
main_loop:                      ; Here comes the main loop
        mov al, [si]            ; get character
        test al, al             ; if we're reached end of string
        jz wr_out               ; goto write output

        cmp al, ' '             ; if we got space - 
        jz space                ; work with this gap

        movsb                   ; else just copy character from input to output
        jmp main_loop           ; continue loop

space:                          ; if we've got space - skip all following in input 
                                ; and add needed space count in gap in output
        xor cx, cx
        not cx
        xchg si, di             ; scas works with di - so we need to put si there
        repz scasb              ; al - hold ' ' (by that reason we are here)
        dec di                  ; so we've skipped all following spaces in input

        xchg di, si             ; return poiners at their normal state 

        mov cx, toins           ; put needed space count in output string
        rep stosb               ; in al we're still got ' '

        test dx, dx             ; if our remainder are zero
        jz main_loop            ; - continue loop
        stosb                   ; else - put one more space in current gap
        dec dx                  ; and decrease remainder
        jmp main_loop           ; and of course continue our loop
        
wr_out:                         ; Now we're reached final touches to our prog 
        xor ax, ax              ; We're going to search for tailing null char
                                ; (we could skip this line because the only way to get here
                                ;  is only from testing al to zero, so it DEFINITLY zero)
        mov di, offset to       ; point to output string
        xor cx, cx              ; Search for FFFF chars
        not cx                  ;
        repnz scasb             ; Search tailing zero
        dec di                  ; And put
        mov al, '$'             ; '$'
        stosb                   ; instead of it

        mov ah, 9               ; Use DOS's help
        mov dx, offset to       ; to write output 
        int 21h                 ; to user's eyes

        jmp norm_out            ; output is OK!
bad_len:
        mov ah, 9h
        mov dx, offset bad_len_str
        int 21h
        jmp short norm_out
no_string:
        mov ah, 9h
        mov dx, offset no_input_str
        int 21h
        jmp short norm_out

norm_out:
        mov ah, 4ch
        int 21h

toins   dw 0
divis   dw 0
wordcnt dw 0
need_len dw 30
real_ofs dw 0
        dw 0    ; front border of string
from    db '   so      hello my dear world   ',0
        db 100-($-from) dup (0)
to      db 100 dup (0)
bad_len_str db 'Input string length exceeds needed length$'
no_input_str db 'No input string entred$'
end start
