;[toed.xkl.com]DXX:<MM>GRIPE.MAC.2, 12-Nov-96 17:32:03, Edit by ALDERSON
; Add "COMMENT" as third entry name for this program

; GRIPE parses a topic name, and calls MM using RSCAN%, to mail to
; BUG-<topic> with the subject TOPIC [GRIPE, TTYnn].  The list of topics
; is built from the system mailing list file.  If invoked as SUGGEST
; it will put "Suggestion" in the subject line, and mail to the same list.

       TITLE GRIPE
       SEARCH MONSYM,MACSYM
       .TEXT "GRIPE/SAVE"
       .TEXT "/NOINITIAL"      ;Suppress loading of JOBDAT
       ASUPPRESS

A=:1                            ;Scratch registers
B=:2
C=:3
D=:4

GRIPTR=:7                       ;Pointer to gripe topic keyword
GRIPNM=:10                      ;Pointer to subject line

P=:17                           ;Main stack pointer

DEFINE ERNOP <ERJMP .+1>

; Constants and data for system mailing-list file
; These must match the definitions in MMAILBOX!

       BINPAG==100             ;Where <SYSTEM>MAILING.LISTS-BIN mapped
       FREPAG==200             ;Where to start making strings
BINADR=BINPAG*1000
BINFID=BINADR                   ;Should contain SIXBIT /MMLBX/
WRTTIM=BINFID+1                 ;Time of last write on text file
HSHMOD=WRTTIM+1                 ;Hash modulus
HSHTAB=HSHMOD+1                 ;The hash table itself
HSHEND=BINADR+111777            ;End of hash table

; Impure data

       PDLEN==10               ;Length of the stack
PDL:    BLOCK PDLEN             ;The stack itself

RBUF:   BLOCK 40                ;RSCAN buffer for mail program

NPAGES: 0                       ;Number of pages in MAILING-LISTS.BIN
BINJFN: 0                       ;Place to save JFN on bin file
FREPTR: 0                       ;Address of next word in string space

       BUFLEN==20              ;Length of main command buffer
CSBUF:  BLOCK BUFLEN            ;Command buffer
ATMBF:  BLOCK BUFLEN            ;Atom buffer

CSB:    0                       ;COMND state block for gripe topics
       .PRIIN,,.PRIOU          ;Command JFNs
       0                       ;Prompt - filled in later
       POINT 7,CSBUF           ;Command buffer
       POINT 7,CSBUF           ;Next input
       BUFLEN*5                ;Space left in buffer
       0                       ;Unparsed input count
       POINT 7,ATMBF           ;Atom buffer pointer
       BUFLEN*5                ;Atom buffer size

; COMND stuff for gripe topic
; These topics will be filled in from the ones which appear
; as Bug-TOPIC in MMAILBOX's forwarding file.

       MAXG==200               ;Maximum expected number of topics
GRIPTB: 0,,MAXG                 ;No keys now, but expandable to MAXG
       BLOCK MAXG              ;Provide space for the table

PNTAB:  NPNAM,,NPNAM            ;Table of program names and strings for them
       [ASCIZ/COMMENT/],,[ASCIZ/ [Comment/]
       [ASCIZ/GRIPE/],,[ASCIZ/ [Gripe/]
       [ASCIZ/SUGGEST/],,[ASCIZ/ [Suggestion/]
NPNAM==.-PNTAB-1

START:  RESET%                  ;Initialize the world
       MOVE P,[IOWD PDLEN,PDL] ;Build a stack
       CALL BLDTAB             ;Build the table of gripe topics
       CALL GETSUB             ;Get the gripe topic.
       CALL MAKHDR             ;Make the RSCAN buffer to pass on to MM
       TMSG <
Enter your gripe, comment, or suggestion.
>
       JRST SNDMAI             ;Send this mail by chaining to MM

; Build the table of possible topics

; Table of possible mailing-list binfile names
; Luckily XMAILBOX format is the same as MMAILBOX format.
BINFNS: [ASCIZ/MAIL:MAILING-LISTS.BIN/]
       [ASCIZ/SYSTEM:MAILING-LISTS.BIN/]
       [ASCIZ/MAIL:MAILING.LISTS-BIN/]
       [ASCIZ/SYSTEM:MAILING.LISTS-BIN/]
NBINFN==.-BINFNS

BLDTAB: MOVEI A,FREPAG*1000     ;Get first free string word
       MOVEM A,FREPTR          ;Save it
       MOVEI A,MAXG            ;Get first word for gripe table
       MOVEM A,GRIPTB          ;Save it

       MOVSI C,-NBINFN         ;Set up AOBJN pointer over binfile names
       DO.
         MOVX A,GJ%SHT!GJ%OLD  ;Old file, short form JFN
         HRRO B,BINFNS(C)      ;With the string at that table position
         GTJFN%                ;Get a JFN on the binfile
         IFNSK.
           AOBJN C,TOP.        ;Failed, try for another
           JRST NOBIN          ;No more, make up small table
         ENDIF.
       ENDDO.

       MOVEM A,BINJFN          ;Save the JFN
       MOVX B,OF%RD            ;Read access
       OPENF%                  ;Open the file
        ERJMP NOBIN
       SIZEF%                  ;Get the size (number of pages in C)
        ERJMP NOBIN
       MOVEM C,NPAGES          ;Save it for unmap
       HRLZS A                 ;Move JFN to left half (file page in right)
       MOVE B,[.FHSLF,,BINPAG] ;Process and process page in B
       TXO C,PM%CNT!PM%RD      ;Multiple page map, read access
       PMAP%                   ;Map it in
        ERJMP NOBIN
       MOVE A,BINFID           ;Get file ID
       CAMN A,[SIXBIT/MMLBX/]  ;Is it MMAILBOX format?
       IFSKP.
         TMSG <?Unknown format for binfile -- contact a wizard>
         JRST UNMAP            ;Unmap binfile and go on without it
       ENDIF.

       MOVE D,[-<HSHEND-HSHTAB>,,HSHTAB] ;Make AOBJN pointer over hash table
       DO.
         HRRZ B,(D)            ;Get value at this hash
         IFN. B                ;Make sure there is something there
           MOVE A,(B)          ;Get first word of string
           TLZ A,201004        ;Capitalize first three letters
           CAML A,[ASCII/BUG-/]  ;Is it in range
            CAML A,[ASCII/BUG./] ;to be a BUG-FOO name?
         ANSKP.
           HRLI B,(POINT 7,,27) ;Turn into a byte pointer
           HRRO A,FREPTR       ;Get pointer to free string space
           CALL CPYSTR         ;Copy it
           IBP A               ;Make space for null
           MOVEI C,1(A)        ;Save updated address
           HRL B,FREPTR        ;Get table entry (string,,0)
           MOVEM C,FREPTR      ;Save new string space pointer
           CALL ADDKEY         ;Add key to topic table
         ENDIF.
         AOBJN D,TOP.          ;If more, go back and do the next
       ENDDO.

       MOVEI A,GRIPTB          ;Get address of table
       HRROI B,[ASCIZ/Random-Program/]
       TBLUK%                  ;Look up "Bug-Random-Program"
       IFNJE.
         TXNN B,TL%EXM         ;Was an exact match found?
       ANSKP.
         MOVE B,A              ;Move address into B
         MOVEI A,GRIPTB        ;With table again
         TBDEL%                ;Remove that keyword
          ERNOP
       ENDIF.
UNMAP:  SETO A,                 ;Unmapping
       MOVE B,[.FHSLF,,BINPAG] ;From binfile page of our own fork
       MOVE C,NPAGES           ;Get number of pages to unmap
       TXO C,PM%CNT            ;Multiple-page unmap
       PMAP%                   ;Do it
        ERNOP
CLSBIN: MOVE A,BINJFN           ;Get JFN again
       CLOSF%                  ;Close and release it
        ERNOP
       HRLZI B,[ASCIZ/Other/]  ;Always have "Bug-Other"
                               ;Fall through to add it in
ADDKEY: MOVEI A,GRIPTB          ;Get address of topic table
       TBADD%                  ;Add it to the table
        IFNJE. <RET>
       MOVX A,.FHSLF           ;TBADD failed.  On ourself
       GETER%                  ;Get error condition
        ERCAL ERROR
       HRRZS B                 ;Flush fork handle
       CAIN B,TADDX2           ;Is the problem a duplicate entry?
        RET                    ;If so, just ignore the error
       CAIE B,TADDX1           ;Is it table full?
        CALL ERROR             ;No, die horribly
       TMSG <?Topic table full -- contact a wizard>
       SETZ D,                 ;Make AOBJN fail next time
       RET


; Here when there was no mailing list file or we found an error in it

NOBIN:  TMSG <?Couldn't find mailing-list binfile -- contact a wizard>
       JRST CLSBIN

; Get the gripe subject from the terminal
; returns +1/always
;    GRIPTR/ pointer to gripe-subject table
;    table entry is of form:  addr(subject name),,addr(file name)

GETSUB: HRROI GRIPNM,[ASCIZ/ [Gripe/] ;Default topic.
       MOVX A,.RSINI
       RSCAN%                  ;Set up to read JCL
       IFNJE.
       ANDN. A                 ;Only read JCL if there are chars in buffer
         HRROI A,[ASCIZ//]     ;Get null prompt
         CALL CMDINI           ;Initialize command parsing
         MOVEI B,[FLDDB. .CMKEY,,PNTAB]
         CALL .COMND           ;Parse table of possible program names
       ANSKP.
         HRRO GRIPNM,(B)       ;Yes, get string for topic
         MOVEI B,[FLDDB. .CMKEY,,GRIPTB]
         CALL .COMND           ;Parse subject
       ANSKP.
         MOVE GRIPTR,B         ;Yes, save subject
         MOVEI B,[FLDDB. .CMCFM]
         CALL CONFRM           ;Finish parse
          RET                  ;All done
       ENDIF.

       DO.
         HRROI A,[ASCIZ//]     ;Point to an empty string
         RSCAN%                ;Clear the RSCAN buffer
          ERNOP
         TMSG <
Please enter the topic of your suggestion. (type ? for a list of choices)

>
         HRROI A,[ASCIZ/Topic:  /] ;Point to prompt
         CALL CMDINI           ;Initialize command parse
         MOVEI B,[FLDDB. .CMKEY,,GRIPTB,<
(Just press the RETURN key if none of the topics seems suitable)
>,OTHER]
         CALL .COMND           ;Parse a topic
         IFSKP.
           MOVE GRIPTR,B       ;Yes, save the pointer
           MOVEI B,[FLDDB. .CMCFM]
           CALL CONFRM         ;Finish command parse
            RET                ;All done
         ENDIF.
         TMSG <
? No topic by that name; type a "?" for a list of topics,
or just type RETURN if no topic is suitable.
>                               ;Complain at user
         LOOP.                 ;and go re-ask question
       ENDDO.

; COMND jsys subroutines

; Initialize command parse
; Call with A/prompt string pointer

CMDINI: POP P,CSB+.CMFLG        ;Save reparse address
       MOVEM A,CSB+.CMRTY      ;And prompt string
       MOVEI B,[FLDDB. .CMINI]
       CALL .COMND             ;Initialize command parser
        CALL ERROR             ;Can't get a misparse
       JRST @CSB+.CMFLG        ;Now go back and parse it


; Here to finish command parse
; Returns +1/success, +2/failure (note strange return convention)

CONFRM: MOVEI B,[FLDDB. .CMCFM] ;FDB to confirm
       CALL .COMND             ;Parse it
        RETSKP                 ;Not parsed, return +2
       RET


; Here to parse a random FDB
; returns +1/misparse, +2/success

COMND:  MOVEI A,CSB             ;Get CSB back
       COMND%                  ;Parse the FDB
       TXNE A,CM%NOP           ;Parsed?
        RET                    ;No, fail
       RETSKP

; Build a mail command in rescan buffer

MAKHDR: GJINF%                  ;Tty # in D, job # in C, user # in A
       PUSH P,D                ;Save terminal #
       HRROI A,RBUF
       HRROI B,[ASCIZ/MAIL Bug-/]
       CALL CPYSTR             ;Put in first part
       HLRO B,(GRIPTR)         ;Get -1,,addr of topic data
       CALL CPYSTR             ;Put topic name after "BUG-"
       HRROI B,[ASCIZ /
/]
       CALL CPYSTR             ;Put in a new line
       HLRO B,(GRIPTR)         ;Point to topic name again
       CALL CPYSTR             ;Add it in as subject
       MOVE B,GRIPNM           ;" [Gripe" or " [Suggestion"
       CALL CPYSTR
       HRROI B,[ASCIZ/, TTY/]
       CALL CPYSTR             ;", TTY"
       POP P,B                 ;Terminal # to B
       MOVEI C,10              ;Octal
       NOUT%                   ;Add in tty number
        ERNOP
       HRROI B,[ASCIZ/:]
/]                              ;Close bracket, ^R so subject line is displayed
       CALL CPYSTR
       IDPB C,A                ;Tie off with null
       HRROI A,RBUF
       RSCAN%                  ;Set it all up as JCL for MM
        ERCAL ERROR
       RET

; Send mail by chaining to MM at the ordinary entry point

SNDMAI: MOVX A,GJ%SHT!GJ%OLD    ;Short form GTJFN on an old file
       HRROI B,[ASCIZ/SYS:MM.EXE/]
       GTJFN%                  ;Find MM.EXE
        ERCAL ERROR
       HRLI A,.FHSLF
       MOVE D,A                ;Save pointer to ourself, JFN of program
       MOVE B,[STRTCD,,5]
       BLT B,5+LCD-1           ;Get ready to run in the ACs
       SETO A,                 ;Unmapping
       MOVE B,[.FHSLF,,1]      ;From our own first page
       MOVE C,[PM%CNT!777]     ;Multiple page unmap on all pages
       JRST 5                  ;Go do it in ACs

STRTCD: PHASE 5
       PMAP%                   ;  5  Do the unmap
       MOVE A,D                ;  6  Into ourself with the JFN on MM
       GET%                    ;  7  Load core image into this fork
       MOVEI A,.FHSLF          ; 10 a := our frk handle
       CLZFF%                  ; 11 Cleanup outstanding files
       MOVEI B,0               ; 12 Start at entry vec
       SFRKV%                  ; 13
       HALTF%                  ; 14 ???
       DEPHASE
LCD==.-STRTCD

; CPYSTR -- copy a string.  Terminates on 0 byte
; call: A/ destination byte-pointer, or -1,,addr, or JFN
;       B/ source byte-pointer, or -1,,addr
; ret:  +1 always, with updated string pointers in A and B, and null in C

CPYSTR: TLNE A,-1               ;Is left half zero?
       IFSKP.                  ;Yes, must be a JFN
         SETZ C,               ;End on a null
         SOUT                  ;Do SOUT
         RET
       ENDIF.
       TLC A,-1                ;Convert to real byte pointer if necessary
       TLCN A,-1
        HRLI A,(POINT 7,0)
       TLC B,-1                ;Same for source pointer
       TLCN B,-1
        HRLI B,(POINT 7,0)
       DO.
         ILDB C,B              ;Get byte
         JUMPE C,R             ;If null, done
         IDPB C,A              ;Else drop it in
         LOOP.                 ;And go back for more
       ENDDO.

; Here on a fatal (i.e. totally unexpected) jsys error

ERROR:  EXCH D,(P)              ;Save D register, put pushed loc in D
       PUSH P,A                ;Save the other registers
       PUSH P,B
       PUSH P,C
       HRROI A,[ASCIZ/Unexpected error in GRIPE!
Please report this by sending MAIL to BUG-GRIPE-PROGRAM.
Error was: /]
       ESOUT%                  ;Start error message
       MOVX A,.PRIOU           ;To the terminal
       HRLOI B,.FHSLF          ;With last error on our own fork
       SETZ C,                 ;No limit
       ERSTR%                  ;Print error string
        ERJMP ERRERR           ;Undefined error number
        ERJMP ERRERR           ;Other error
       TMSG < at location >
       MOVX A,.PRIOU           ;More terminal output
       HRRZ B,D                ;Get caller's address
       SUBI B,2                ;Subtract two from this to point to JSYS
       MOVEI C,^D8             ;Radix octal
       NOUT%                   ;Output location
        ERJMP ERRERR
       POP P,C                 ;Now restore all saved registers
       POP P,B
       POP P,A
       POP P,D

STOP:   HALTF%                  ;Stop
       HRROI A,[ASCIZ/Can't continue/]
       ESOUT%                  ;Complain if continued
       JRST STOP               ;Go back and stop again

ERRERR: HRROI A,[ASCIZ/Error within an error/]
       ESOUT%                  ;Error handler couldn't do it
       JRST STOP               ;So complain again and die

RSKP:   AOS (P)                 ;We don't have macrel, so add these labels
R:      RET

; Give literals nice disassembly

LIT:    LIT

       END START