                INCLUDE "exec/types.i"
                INCLUDE "exec/tasks.i"
                INCLUDE "exec/memory.i"
                INCLUDE "exec/funcdef.i"
                INCLUDE "exec/exec_lib.i"
                INCLUDE "libraries/dos_lib.i"
                INCLUDE "libraries/dos.i"
                INCLUDE "intuition/intuition.i"

                csect    wreq.o,0,0,1,2

                xdef     _autorequest
                xdef     __main

NULL            EQU      0                  ; Pointing to nowhere
absexecbase     EQU      4                  ; Adress to get the ExecBase
CR              EQU      13                 ; Carriage return
LF              EQU      10                 ; Line feed
TRUE            EQU      1                  ; Boolean TRUE-value
FALSE           EQU      0                  ; Boolean FALSE-value
autoreqoffset   EQU      $FEA4              ; Library offset
ONE             EQU      '1'                ; Primary option
TWO             EQU      '2'                ; Secondary option
HIT_RET_LEN     EQU      27                 ; Prompt lenght
UP_CASE         EQU      $DF                ; Bit 5 masked
FIRST_LEGAL     EQU      'A'                ; First alphabet
LAST_LEGAL      EQU      'Z'                ; End of range
OPT_LEN         EQU      4                  ; Lenght per option query
WRITING         EQU      10000              ; Not just measuring
ONE_LINE        EQU      20000              ; No linefeeds
MAX_COL         EQU      76                 ; Max line lenght
MAX_OPT         EQU      72                 ; Including the option
OPT_ONE_LINE    EQU      13                 ; For both in same line
LIST_LEN        EQU      64                 ; Lenght of the index list

__main          MOVEM.L  A2/D2,-(A7)        ; save registers
                MOVEA.L  absexecbase,A6     ; Exec-librarys base to use
                LEA      intuitionname(PC),A1 ; A1 = Name of the library
                MOVEQ    #0,D0              ; D0 = Version
                JSR      _LVOOpenLibrary(A6) ;Open the intuition-library
                CMPI.L   #NULL,D0           ; If the library pointer is NULL
                BEQ      s_exit             ; Then exit immediately
                MOVEA.L  D0,A2              ; Save the pointer to library
                LEA      _autorequest(PC),A0 ; Start of function
                LEA      intuitionname(PC),A1 ; End of function and data
                SUBA.L   A0,A1              ; Calculate the size
                MOVE.L   A1,D2              ; Save the size
                MOVE.L   A1,D0              ; D0 = Size in bytes
                MOVE.L   #MEMF_PUBLIC,D1    ; D1 = Requirements
                JSR      _LVOAllocMem(A6)   ; Allocate memory
                CMPI.L   #NULL,D0           ; If there was no memory
                BEQ      close              ; Then close and exit
                MOVEA.L  D0,A1              ; D0 = Pointer to memory
                SUBQ.W   #1,D2              ; Adjust the counter
                LEA      _autorequest(PC),A0 ; Pointer to function
copyfunc        MOVE.B   (A0)+,(A1)+        ; Copy bytes
                DBRA     D2,copyfunc        ; Decrement and branch
                MOVEA.L  #autoreqoffset,A0  ; A0 = library offset
                MOVEA.L  A2,A1              ; A1 = pointer to library
                JSR      _LVOSetFunction(A6) ; Replace function
close           MOVEA.L  A2,A1              ; Restore the pointer to library
                JSR      _LVOCloseLibrary(A6) ; Close intuition-library
s_exit          MOVEQ    #FALSE,D0          ; Return FALSE
                MOVEM.L  (A7)+,A2/D2        ; Restore registers
                RTS                         ; Return to caller

_autorequest    MOVEM.L  D2-D7/A2-A6,-(A7)  ; Save registers
                MOVEQ    #FALSE,D6          ; Return FALSE
                MOVE.L   A1,A4              ; A1 -> Bodytext (IntuiText)
                MOVEA.L  absexecbase,A6     ; Exec-librarys base to use
                MOVEA.L  #0,A1              ; A1 = NULL (my task)
                JSR      _LVOFindTask(A6)   ; Find the task structure
                MOVEA.L  D0,A1              ; Structure base to A1
                CMPI.B   #NT_PROCESS,LN_TYPE(A1) ;If my task is not a process
                BNE      a_exit             ; Then exit immediately
                LEA      doslibname(PC),A1  ; A1 = Name of the dos-library
                MOVEQ    #0,D0              ; D0 = Version
                JSR      _LVOOpenLibrary(A6) ;Open dos-library
                CMPI.L   #NULL,D0           ; If the library pointer is NULL
                BEQ      a_exit             ; Then exit immediately
                MOVEA.L  D0,A6              ; Dos-librarys base to use
                JSR      _LVOInput(A6)      ; Get standard input file
                CMPI.L   #NULL,D0           ; If the file pointer is NULL
                BEQ      done               ; Then do not write
                LEA      input(PC),A0       ; Get storing address
                MOVE.L   D0,(A0)            ; Save the file pointer
                MOVE.L   D0,D1              ; D1 = file pointer
                JSR      _LVOIsInteractive(A6) ;Check the input file type
                TST.L    D0                 ; If not interactive
                BEQ      done               ; Then do not write
                JSR      _LVOOutput(A6)     ; Get standard output file
                CMPI.L   #NULL,D0           ; If the file pointer is NULL
                BEQ      done               ; Then do not write
                MOVE.L   D0,D4              ; Save file pointer in D4
                CMPA.L   #NULL,A2           ; If the positive text not NULL
                BNE      may_query          ; Query is still possible
                CMPA.L   #NULL,A3           ; If the negative text not NULL
                BNE      no_options         ; No need to query
                CMPA.L   #NULL,A4           ; If the body text is also NULL
                BEQ      done               ; Then no text to display
no_options      LEA      posit(PC),A0       ; Pointer to good option
                MOVE.B   #0,(A0)+           ; Mark it meaningless
                BRA      options_set        ; Go to display text
may_query       CMPA.L   #NULL,A3           ; If the negative text not NULL
                BNE      query              ; Then read line
                MOVEQ    #TRUE,D6           ; Return TRUE
                BRA      no_options         ; No other option
query           MOVEQ    #0,D7              ; Zero the counters
                MOVEA.L  A3,A5              ; A5 = negative text
                JSR      writetext(PC)      ; Sort the text
                MOVEA.L  first(PC),A0       ; Pointer to negative string
                MOVE.L   A0,-(A7)           ; Save the negative pointer
                MOVEA.L  A2,A5              ; A5 = positive text
                JSR      writetext(PC)      ; Sort the text
                MOVEA.L  first(PC),A0       ; Pointer to positive string
                MOVEA.L  (A7)+,A1           ; Restore the negative pointer
                MOVE.B   (A0),D0            ; First character
                JSR      check_char         ; Check if legal
                TST.B    D0                 ; Was it illegal?
                BEQ      one_two            ; Then ask with numbers
                LEA      posit(PC),A0       ; Positive option = first char
                MOVE.B   D0,(A0)+           ; A0 -> negat
                MOVE.B   (A1),D0            ; First character
                JSR      check_char         ; Check if legal
                TST.B    D0                 ; Was it illegal?
                BEQ      one_two            ; Then ask with numbers
                MOVE.B   D0,(A0)+           ; Negative option = first char
                CMP.B    posit(PC),D0       ; Aren't the options identical?
                BNE      options_set        ; Then they are ok.
one_two         LEA      posit(PC),A0       ; A0 -> positive option
                MOVE.B   #ONE,(A0)+         ; Positive option = '1'
                MOVE.B   #TWO,(A0)+         ; Negative option = '2'
options_set     JSR      linefeed(PC)       ; D4 = file pointer
                MOVEQ    #0,D7              ; Zero the counter
                MOVEA.L  A4,A5              ; A5 = body text
                JSR      writetext(PC)      ; Measure text
                MOVEA.L  A4,A5              ; A5 = body text
                CMP.W    #MAX_COL,D7        ; Is it too long for one line
                BHI      high_body          ; Then use many lines
                MOVE.W   #ONE_LINE,D7       ; Use one line
                BRA      write_body         ; Go to write it
high_body       MOVE.W   #WRITING,D7        ; Set write mode
write_body      JSR      writetext(PC)      ; Write body text
                CMPI.W   #WRITING,D7        ; Is there LF already
                BEQ      ask_option         ; Then don't write an other one
                JSR      linefeed(PC)       ; D4 = file pointer
ask_option      SWAP     D6                 ; Save return value
                MOVE.W   #OPT_ONE_LINE,D6   ; Set counter starting value
                MOVEQ    #0,D7              ; Zero the counters
                MOVEA.L  A3,A5              ; A5 = negative text
                JSR      writetext(PC)      ; Measure text
                ADD.W    D7,D6              ; Add lenght to counter
                CMP.W    #MAX_OPT,D7        ; Is it too long for one line
                BHI      high_negat         ; Then use many lines
                MOVE.W   #ONE_LINE,D7       ; Use one line
                BRA      normal_negat       ; Go to write it
high_negat      MOVE.W   #WRITING,D7        ; Set write mode
normal_negat    SWAP     D7                 ; Save value
                MOVEA.L  A2,A5              ; A5 = positive text
                JSR      writetext(PC)      ; Measure text
                ADD.W    D7,D6              ; Add lenght to counter
                CMP.W    #MAX_OPT,D7        ; Is it too long for one line
                BHI      high_posit         ; Then use many lines
                MOVE.W   #ONE_LINE,D7       ; Use one line
                BRA      normal_posit       ; Go to write it
high_posit      MOVE.W   #WRITING,D7        ; Set write mode
normal_posit    MOVEQ    #0,D0              ; Get zero
                CMP.B    posit(PC),D0       ; Is option meaningless
                BEQ      reply              ; Then just wait for RETURN
                CMP.W    #MAX_COL,D6        ; Are the options too long
                BHI      too_long           ; Then use separate lines
                MOVE.W   #0,D6              ; Use one line for options
                BRA      show_options       ; Go to show the options
too_long        JSR      linefeed(PC)       ; D4 = file pointer
show_options    LEA      option(PC),A0      ; Pointer to option
                MOVE.B   posit(PC),0(A0)    ; Option is positive
                MOVEQ    #OPT_LEN,D3        ; D3 = lenght of write
                JSR      write_out(PC)      ; Write to output
                MOVEA.L  A2,A5              ; A5 = positive text
                JSR      writetext(PC)      ; Write it out
                TST.W    D6                 ; Aren't we using separate lines?
                BEQ      write_mid          ; Then separate options
                CMPI.W   #WRITING,D7        ; Is there LF already
                BEQ      show_negat         ; Then don't write an other one
                JSR      linefeed(PC)       ; D4 = file pointer
                BRA      show_negat         ; Go to show the negative option
write_mid       LEA      mid_part(PC),A0    ; Pointer to option separator
                JSR      write_two(PC)      ; Write it out
show_negat      LEA      option(PC),A0      ; Pointer option
                MOVE.B   negat(PC),0(A0)    ; Option is negative
                MOVEQ    #OPT_LEN,D3        ; D3 = lenght of write
                JSR      write_out(PC)      ; Write to output
                SWAP     D7                 ; Restore value
                MOVEA.L  A3,A5              ; A5 = negative text
                JSR      writetext(PC)      ; Write it out
                TST.W    D6                 ; Aren't we using separate lines?
                BEQ      right_after        ; Then put it right after
                CMPI.W   #WRITING,D7        ; Is there LF already
                BEQ      right_after        ; Then don't write an other one
                JSR      linefeed(PC)       ; D4 = file pointer
right_after     LEA      prompt(PC),A0      ; Pointer to prompt
                JSR      write_two(PC)      ; Write lenght of two
                BRA      wait               ; Go to wait answer
reply           MOVEA.L  A2,A5              ; A5 = positive text
                JSR      writetext(PC)      ; Write it out
                SWAP     D7                 ; Restore value
                MOVEA.L  A3,A5              ; A5 = negative text
                JSR      writetext(PC)      ; Write it out
                LEA      hit_ret(PC),A0     ; Pointer to Press RETURN text
                MOVE.L   #HIT_RET_LEN,D3    ; D3 = lenght of write
                jsr      write_out(PC)      ; Write it out
wait            MOVE.L   input(PC),D5       ; Restore input file pointer
                SWAP     D6                 ; Restore return value
                LEA      answer(PC),A0      ; Pointer to answer
                MOVE.L   D5,D1              ; D1 = pointer to file (input)
                MOVE.L   A0,D2              ; D2 = pointer to buffer
                MOVEQ    #1,D3              ; D3 = lenght of read
                JSR      _LVORead(A6)       ; Read a character
                MOVEA.L  D2,A0              ; Reastore pointer
                CMPI.B   #LF,(A0)           ; Was it end of the line
                BEQ      empty              ; Then stop reading
                LEA      bucket(PC),A0      ; Pointer to bucket
                MOVE.L   A0,D2              ; D2 = pointer to buffer
read_next       MOVE.L   D5,D1              ; D1 = pointer to file (input)
                JSR      _LVORead(A6)       ; Read a character
                MOVEA.L  D2,A0              ; Reastore pointer 
                CMPI.B   #LF,(A0)           ; Wasn't it end of the line
                BNE      read_next          ; Then read next character
empty           MOVEQ    #0,D0              ; Get zero
                CMP.B    posit(PC),D0       ; Is the option meaningless
                BEQ      done               ; Then the job is done
                MOVE.B   answer(PC),D0      ; Pointer to answer
                CMPI.B   #FIRST_LEGAL,D0    ; Can it be digit
                BLT      digit              ; Then don't modify
                ANDI.B   #UP_CASE,D0        ; Convert to upper case
digit           CMP.B    negat(PC),D0       ; Is it negative
                BEQ      done               ; Then go return FALSE
                CMP.B    posit(PC),D0       ; Isn't it positive
                BNE      ask_option         ; Then go to ask again
                MOVEQ    #TRUE,D6           ; Return TRUE
done            MOVEA.L  A6,A1              ; A1 = pointer to library (dos) 
                MOVEA.L  absexecbase,A6     ; Exec-librarys base to use
                JSR      _LVOCloseLibrary(A6) ; Close dos-library
a_exit          MOVEQ    #0,D0              ; Zero the long register
                MOVE.B   D6,D0              ; Boolean return value
                MOVEM.L  (A7)+,D2-D7/A2-A6  ; Restore registers
                RTS                         ; Return to caller

writetext       LEA      list(PC),A0        ; Pointer to index list
                MOVEA.L  A5,A1              ; Pointer to first structure
                MOVEQ    #0,D5              ; Zero the index counter
count_next      CMPA.L   #NULL,A1           ; If the IntuiText pointer is NULL
                BEQ      last               ; Then this was the last one
                MOVE.B   D5,(A0)+           ; Put index to list
                ADDQ.B   #1,D5              ; Increment the index
                CMPI.W   #LIST_LEN,D5       ; If the index is too big
                BEQ      last               ; Then this was the last one
                MOVEA.L  it_NextText(A1),A1 ; Pointer to next IntuiText
                BRA      count_next         ; Next structure
last            TST.B    D5                 ; Was there NULL-pointer
                BEQ      return             ; Then return to caller
                MOVE.L   D5,D3              ; Initialize outer counter
                SUBQ.B   #2,D3              ; Adjust the counter
                BMI      sorted             ; Nothing to sort?
outer_loop      MOVEQ    #0,D2              ; Initialize inner counter
inner_loop      LEA      list(PC,D2.W),A1   ; Pointer to current index
                ADDQ.B   #1,D2              ; Increment inner counter
                CMP.B    D5,D2              ; If counter reached max value
                BEQ      loop_end           ; Then the loop has exhausted
                MOVEQ    #0,D0              ; Zero the register
                MOVE.B   (A1)+,D0           ; Get index value
                JSR      getstruct(PC)      ; Get current structure
                MOVEQ    #0,D0              ; Zero the register
                MOVE.B   (A1),D0            ; Get next index value
                MOVEA.L  A0,A1              ; Current structure to A1
                JSR      getstruct(PC)      ; Get next structure
                MOVE.W   it_TopEdge(A0),D0  ; Get the next top edge
                CMP.W    it_TopEdge(A1),D0  ; If current < next top edge
                BLT      inner_loop         ; Then don't swap them
                BNE      swap               ; Swap only if not equal
                MOVE.W   it_LeftEdge(A0),D0 ; Get the next left edge
                CMP.W    it_LeftEdge(A1),D0 ; If current < next left edge
                BLT      inner_loop         ; Then don't swap them
swap            LEA      list(PC,D2.W),A0   ; Pointer to next index
                MOVE.B   (A0),D0            ; Get next index value
                SWAP     D0                 ; Save next index value
                MOVE.B   -(A0),D0           ; Get current index value
                SWAP     D0                 ; Swap index values
                MOVE.B   D0,(A0)+           ; Set current index value
                SWAP     D0                 ; Restore next index value
                MOVE.B   D0,(A0)+           ; Set next index value
                BRA      inner_loop         ; Continue looping
loop_end        DBRA     D3,outer_loop      ; Check if outer loop done
sorted          MOVE.L   D5,D0              ; Get counter value
                SUBQ.B   #1,D0              ; Point to last index
                MOVE.B   list(PC,D0.W),D0   ; Get last index value
                JSR      getstruct(PC)      ; Get last IntuiText structure
                LEA      first(PC),A1       ; Pointer to saving address
                MOVE.L   it_IText(A0),(A1)+ ; Save string pointer
                BRA      check_counter      ; Go to write loop

list            DS.B     LIST_LEN           ; Sorttable index list

continue        MOVEQ    #0,D0              ; Zero the register
                MOVE.B   list(PC,D5.W),D0   ; Get current index value
                JSR      getstruct(PC)      ; Get current structure
                MOVEA.L  it_IText(A0),A0    ; Pointer to string
                MOVE.L   A0,D2              ; D2 = NULL-terminated string
                MOVEQ    #-1,D3             ; D3 = lenght to be written
strlen          ADDQ.L   #1,D3              ; Increment lenght
                TST.B    (A0)+              ; While terminator not found
                BNE      strlen             ; If lenght = 0 then D3 = -1 + 1
                CMPI.W   #WRITING,D7        ; Are we actually writing this
                BGE      writing            ; Then go to write it
                ADD.W    D3,D7              ; Add lenght to counter
                ADDQ.W   #1,D7              ; Add one for space character
                BRA      check_counter      ; Continue measuring
writing         JSR      write_file(PC)     ; Write to output
                CMPI.W   #ONE_LINE,D7       ; Are we using only one line
                BEQ      put_space          ; Then don't write linefeed
writenext       JSR      linefeed(PC)       ; D4 = file pointer
check_counter   DBRA     D5,continue        ; If counter exhausted
return          RTS                         ; Then return to caller

put_space       TST.B    D5                 ; If counter exhausting
                BEQ      return             ; Then the write is done
                LEA      space(PC),A0       ; Pointer to space string
                MOVEQ    #1,D3              ; D3 = lenght of write
                JSR      write_out(PC)      ; Write the space character
                BRA      sorted             ; Continue the line

getstruct       MOVEA.L  A5,A0              ; Pointer to first structure
                BRA      dec_counter        ; Go to counting loop
next_struct     MOVEA.L  it_NextText(A0),A0 ; Pointer to next IntuiText
dec_counter     DBRA	D0,next_struct      ; If counter exhausted
                RTS                         ; Then return to caller

linefeed        LEA      crlf(PC),A0        ; Pointer to line-end string
write_two       MOVEQ    #2,D3              ; D3 = lenght to be written
write_out       MOVE.L   A0,D2              ; D2 = string (not terminated)
write_file      MOVE.L   D4,D1              ; D1 = file pointer
                JMP      _LVOWrite(A6)      ; Write to output

check_char      CMPI.B   #FIRST_LEGAL,D0    ; Is it less than 'A'
                BLT      not_a_z            ; Then it's not legal
                ANDI.B   #UP_CASE,D0        ; Convert to upper case
                CMPI.B   #LAST_LEGAL,D0     ; Is it less or equal to 'Z'
                BLE      legal              ; Then it's legal
not_a_z         MOVEQ    #0,D0              ; Zero means illegal
legal           RTS                         ; Return to caller

input           DC.L     0                  ; Pointer to input file
first           DC.L     0                  ; First IntuiText string
doslibname      DOSNAME                     ; Name of the dos-library
crlf            DC.B     CR,LF              ; End of line characters
prompt          DC.B     '?'                ; Prompt for query
space           DC.B     ' '                ; Space for separator
mid_part        DC.B     ', '               ; Option separator
option          DC.B     'X = '             ; Option expression
answer          DC.B     ' '                ; Store for the answer
bucket          DC.B     ' '                ; Store for the rest ones
posit           DC.B     0                  ; Positive option
negat           DC.B     0                  ; Negative option
hit_ret         DC.B     LF,'Press RETURN to continue! ' ;Dummy query
intuitionname   DC.B     'intuition.library',0 ; Name of the intuition-library

                END
