;NOTE1-3.ASM by Jerry Haigwood ;Assemble with ASM.COM there is no Z80 code. ; NOTE is a simple program intend for use on a RCP/M system. It al- ;lows the user of the system to type a note to the SYSOP. The note is ;stored on disk, presumably in a private area, for read back or later ;printing. The default name of the created text file is NOTE. If you ;decided to change the name, make sure all unused name positions are ;filled with spaces. If you are using a BBS, check the name of the ;"LASTCALR" file and change it to match your file name. The default ;location for NOTE and LASTCALR is A14: but can be changed easily by ;setting the equates to match your system. A maximum of 50 lines are ;allowed to be entered, and can also be changed to suit your taste. ;The user is warned at 5 lines < max (WARN5 equ) that only 5 lines are ;left. A total of 77 characters/line are allowed (can also be changed ;by NUMCR equ). ; ; The only edit keys allowed are the CR, LF (acts just like a CR), BS ;and TAB. This means only the current line being entered can be edited. ;To exit NOTE, the user types two CR's back to back. He is asked if he ;would like to logoff. A "Y" or "y" pokes a 0CDH into beginning of mem- ;ory (0000H) to "kill" BYE. If you aren't using BYE change this routine ;to prevent your system from going nuts. Any other character returns ;the user to the drive/user area he entered from. ; ; - Jerry Haigwood ; ; ;Please leave any hacks on AMPRO System One at (408) 258-8128 ; ;-------------------------------------------------------------------- ;REVISION LOG: ; ;04/22/84 Fixed 2 minor bugs (1st -Jerry Haigwood ; V1.3 line would only allow 75 ; chars. (prevented user ; from backspacing over ; name/date signon). ; ;04/19/84 Added a EOF (^Z) to end of -Jerry Haigwood ; V1.2 text file. This was needed ; by some TYPE programs. ; ;03/24/84 Added "LASTCALR" support. -Jerry Haigwood ; V1.1 ; ;03/22/84 Initial Version. -Jerry Haigwood ; V1.0 ;-------------------------------------------------------------------- ; YES: EQU 0FFH NO: EQU 0 ; Conditional assembly switches MBBS: EQU NO ;yes if MBBS system OXGATE: EQU NO ;yes if OXGATE system ;======================================================================= ; Pick only one of the following, NOT both... ASKNAM: EQU NO ;yes if ask user's name GETCALR:EQU YES ;yes to enable feature to get ; name from LASTCALR ; Define drive and user area if GETCALR is set to YES IF GETCALR LASTUSR:EQU 14 ;user area of LASTCALR LASTDRV:EQU 'A'-41H ;Drive of LASTCALR file ENDIF ; ;======================================================================= ; FCB: EQU 5CH ;CCP file control block DMAADR: EQU 80H ;Default DMA buffer address CR: EQU 13 ;carrige return LF: EQU 10 ;line feed TAB: EQU 9 ;tab BS: EQU 8 ;back space BASE: EQU 0 ;standard CP/M DRIVE: EQU 'A'-41H ;drive to write note to USER: EQU 14 ;user area to write note to BDOS: EQU BASE+5 ;location of BDOS NUMCR: EQU 77 ;number of characters/line NUMLN: EQU 50 ;total number of lines allowed WARN5: EQU NUMLN-5 ;number of lines to count before warning ; BDOS functions SELDSK: EQU 14 ;select disk FOPEN: EQU 15 ;file open FREAD: EQU 20 ;file read RTNDSK: EQU 25 ;return current disk SETDMA: EQU 26 ;set dma address SETUSR: EQU 32 ;get/set user number ORG BASE+100H ;======================================================================= ; ; Program starts here ; ;======================================================================= START: LXI H,0 ;zero out h&l DAD SP ;add sp to hl SHLD OLDSP ;save it LXI SP,STACK ;set up new stack IF ASKNAM LDA 4 ;get current drive/user STA DRV ;save it for later ENDIF ;ASKNAM ; Get caller's name from LASTCALR, or ask for it IF GETCALR LOAD: MVI E,0FFH ;get current user # MVI C,SETUSR CALL BDOS STA CURUSR ;save current user MVI E,LASTUSR MVI C,SETUSR ;set user of LASTCALR CALL BDOS MVI C,RTNDSK ;get current disk CALL BDOS STA CURDSK MVI E,LASTDRV ;set drive of LASTCALR MVI C,SELDSK CALL BDOS LXI D,LFCB ;open LASTCALR MVI C,FOPEN CALL BDOS INR A ;Check if file not found (FFH) JZ GETEND ;if not found, then signon XRA A ;else we must STA FAIL ;clear the fail counter LXI D,DMAADR MVI C,SETDMA ;make sure DMA is default addr CALL BDOS LXI D,LFCB MVI C,FREAD ;fill default buffer CALL BDOS ENDIF ;GETCALR IF GETCALR AND (NOT MBBS) LXI H,DMAADR ENDIF ;GETCALR AND (NOT MBBS) IF GETCALR AND MBBS LXI H,DMAADR+11 ENDIF ;GETCALR AND MBBS IF GETCALR PUSH H LHLD DMAPT XCHG POP H GETNAM: MOV A,M ;get name from LASTCALR file CPI LF ;use LF as delimiter PUSH PSW CPI ',' ;mask off any commas CZ ADD20H STAX D ;store the character INX H ;fix the pointers INX D XCHG SHLD DMAPT XCHG LDA CHRCT ;get character counter INR A ;roll up CHRCT STA CHRCT ;save it POP PSW JNZ GETNAM XRA A STA LINE1 GETEND: LDA FAIL ;see if CPI 1 ;fail counter JZ ASK ;is set LXI D,SIGNON ;point to signon message CALL PRINT ; LXI D,PROMPT CALL PRINT JMP CONIN ;done ADD20H: MVI A,20H RET ENDIF ;GETCALR ; If LASTCALR was unsucessfull, then ask for name/date ASK: LXI D,SIGNON ;point to signon message CALL PRINT ; LXI D,UR$NAME ;point to name/date CALL PRINT ;print it LHLD DMAPT ;point to buffer MVI M,LF ;store character INX H ;roll up hl SHLD DMAPT ;store it away LDA CHRCT ;get character counter INR A ;roll up CHRCT STA CHRCT ;save it CONIN: CALL GETIT ;get character STA AREG ;store the char in temp buffer SUI 20H ;is it a control chacater? JM CONTROL ;jump if minus CPI 7FH ;del? JZ CONIN ;loop LXI D,AREG ;point to character CALL PRINT ;print the character MOVE: LDA AREG ;get character STA CRSET ;set the cr counter LHLD DMAPT ;point to buffer MOV M,A ;store character INX H ;roll up hl SHLD DMAPT ;store it away COUNT: LDA CHRCT1 ;get char/line counter INR A ;roll up counter STA CHRCT1 ;store it CPI NUMCR ;compare JP SBELL ;if true send bell LDA LINE1 ;line 1 counter CPI 0 ;is this the name/date line? JNZ NAMDAT ;see if line 1 full INRCT: LDA CHRCT ;get character counter INR A ;roll up CHRCT STA CHRCT ;save it CPI 128 ;compare it CZ INCREC ;if true go fix DMA pointer JMP CONIN GETIT: PUSH H ;save MVI E,0FFH ; MVI C,6 ;input function CALL BDOS ;get character POP H ;get location back ORA A ;anything there? JZ GETIT ;loop if not ANI 7FH ;make it ascii RET NAMDAT: LDA CHRCT1 ;get characters/line CPI NUMCR-31 ;long name/date JNZ INRCT ;if true get another character else JZ SBELL ;prevent a line wrap CONTROL: LDA AREG ; CPI CR ;was it a carrige return? JZ ADDCR ;if true add a LF CPI LF ;was it a LF? JZ ADDCR ;if true then add a LF STA CRSET ;set CRSET CPI TAB ;was it a tab? JZ TABSET ; CPI BS ;was it a backspace? JNZ CONIN ;if not, must be a control character BCKUP: LHLD DMAPT ;don't allow a DCX H ;backspace as MOV A,M ;the first CPI LF ;character of JZ CONIN ;a line SBKSP: LXI D,BKSP CALL PRINT FIXCT: LHLD DMAPT ;fix up the counters MVI M,0 ;put a null in place of character DCX H SHLD DMAPT LDA CHRCT DCR A STA CHRCT LDA CHRCT1 DCR A STA CHRCT1 JMP CONIN ;go get another character TABSET: LHLD DMAPT ;move 8 spaces MVI B,8 ;into file LOOP: PUSH B ;save counter LXI D,SENDSP ;point to space CALL PRINT ;send 8 spaces POP B ; MVI M,20H ; INX H ;roll up DMA SHLD DMAPT ; LDA CHRCT ;get character counter INR A ;roll up CHRCT CPI 128 ;compare it CZ INCREC ;if true go fix DMA pointer STA CHRCT ;save it LDA CHRCT1 ;check to INR A ;see if line CPI NUMCR ;is full JP SBELL ;let user know its full STA CHRCT1 DCR B JNZ LOOP JMP CONIN ;get another character SBELL: LXI D,BELL ;point to bell CALL PRINT ; CALL GETIT ;get input CPI BS ;bs? JZ SBKSP ; CPI CR ;compare if CR JZ ADDCR ;if true add a CR to DMA CPI LF ;compare if LF JZ ADDCR ;if true send a CR JMP SBELL ;else do it again ADDCR: LHLD DMAPT ;now put MVI M,CR ;cr in memory INX H ;roll up pointer SHLD DMAPT ;store it LDA LINES ;number of lines used INR A ;roll it up STA LINES ;store it away CPI WARN5 ;warning number CZ PWARN ;send warning CPI NUMLN ;all used? JZ LFLF ;if true start write ; ;Add a LF and compare if the last character was ;a CR. IF true then write the note to disk. ; ADDLF: XRA A ;zero A STA LINE1 ;zero out line 1 counter STA CHRCT1 ;zero out char/line counter LDA CHRCT ;get character counter INR A ;roll up CHRCT STA CHRCT ;save it CPI 128 ;compare it CZ INCREC ;if true go fix record counter LXI D,SENDLF ;point to LF CALL PRINT ;send it LHLD DMAPT ; MVI M,LF ;put one in the DMA also INX H ;roll up H for next character SHLD DMAPT ; LDA CHRCT ;get character counter INR A ;roll up CHRCT STA CHRCT ;save it CPI 128 ;compare it CZ INCREC ;if true go fix DMA pointer LDA CRSET ;get CR counter CPI CR ;was the last character a CR? JZ SDEND ;start the write operation MVI A,CR ; STA CRSET ;set the counter JMP CONIN PWARN: LXI D,SWARN CALL PRINT RET ; ;Increc increments the record counter. ; INCREC: LDA RCNUM ;get record counter INR A ;roll it up STA RCNUM ;store it away XRA A ;zero out A STA CHRCT ;set character counter to 0 RET LFLF: LDA CHRCT ;get char counter CPI 128 ;see if record is full CZ INCREC ; MVI M,LF ;add a lf INX H ; SHLD DMAPT ; SDEND: LXI D,ENDMSG ;send end message CALL PRINT FILL: LHLD DMAPT LDA CHRCT ;get char counter CPI 128 ;see if record is full CZ INCREC ; DASH: MVI B,10 ;10 DLOOP: MVI M,45 ;dashs separates the comments INX H ; LDA CHRCT ; INR A ;roll up STA CHRCT ;store it CPI 128 ;compare it CZ INCREC ;record is full DCR B ;decrement b JNZ DLOOP ;loop til done and fall thru to LFEED: MVI M,CR ;add a cr INX H ; LDA CHRCT ; INR A ;roll up STA CHRCT CPI 128 ;compare it CZ INCREC ;record is full MVI M,LF ;add a lf INX H ; LDA CHRCT INR A ;roll up STA CHRCT CPI 128 ;compare it CZ INCREC ;record is full NULL: MVI M,0 ;fill out record with nulls INX H ;roll up DMA pointer LDA CHRCT INR A ;roll up chrct STA CHRCT CPI 127 ;compare it JNZ NULL ;do it until record is filled MVI M,26 ;^Z eof ; ;Begin the write operation here. ; SETUP: MVI E,USER ;load desired user area MVI C,SETUSR ;set user function CALL BDOS ; MVI E,DRIVE ;set drive to write MVI C,SELDSK CALL BDOS OPEN: LXI D,WFCB ;point to WFCB MVI C,FOPEN ;open file CALL BDOS ; INR A ;FF=file not found CPI 0 ;was the file there? JZ MAKE ;if true then better make one CALL READ ;read file to update record pointer STWRT: CALL STDMA ;set the DMA CALL WRITE ;write 2nd+ records LDA RCNUM ;get record counter CPI 0 ;are we finished? JZ CLOSE ;if true then close file DCR A ; STA RCNUM ;store away records left to write CALL XBUF ;roll up DMA pointer JMP STWRT ;loop until done XBUF: LHLD BDMA ;get DMA pointer LXI D,128 ; DAD D ;add 1 record SHLD BDMA ;store it away RET MAKE: LXI D,WFCB ;point to write FCB MVI C,22 ;create file function CALL BDOS ; CALL XBUF ;roll up dma pointer JMP STWRT ;go write it ; ;Use the read function to update the record counter. ;There's probably a better way but I uses whatest I's knows... ; READ: LXI D,RDMA ;point to read DMA MVI C,SETDMA ;set DMA function CALL BDOS ; LXI D,WFCB ;point to FCB MVI C,FREAD ;read function CALL BDOS ; CPI 0 ;are we done? JZ READ ;do it until A not 0 LXI H,RDMA+127 ;point to last byte in record MVI M,0 ;overwrite the ^Z eof marker LDA WFCB+32 ;get sequential record number DCR A ;decrement it STA WFCB+32 ;store it away again LDA WFCB+15 ;get the number of records DCR A ;and subtract 1 STA WFCB+15 ;store it away CALL INCREC ;add one more record RET STDMA: LHLD BDMA ;point to beginning of DMA XCHG ;HL=>DE MVI C,SETDMA ;set DMA function CALL BDOS ; RET WRITE: LXI D,WFCB ;point to WFCB MVI C,21 ;write sequential function CALL BDOS ; INR A ;FF=file not written LXI D,WTERR ;point to write error msg CPI 0 ;error? CZ PRINT1 ; RET CLOSE: LXI D,WFCB ;point to WFCB MVI C,16 ;close file function CALL BDOS ; INR A ;FF=file not closed LXI D,WTERR ;point to close error CPI 0 ;error? CZ PRINT1 ;if true then quit ; ;Ask the user if he's through. ; ASKUR: LXI D,MSG ;point to end message CALL PRINT ; ; ;Get the users answer. ; INPUT: MVI C,1 ;input function CALL BDOS ;get choice ANI 5FH ;force upper case CPI 'Y' ;y? JZ EXIT ;go kill bye ; ;fall through to.. ; SETUSER: LXI D,ADLN ;send a lf CALL PRINT IF ASKNAM LDA DRV ;get the drive/user back ANI 0F0H ;strip the drive RAR ;move the RAR ;user number RAR ;into the RAR ;lower nibble MOV E,A ;load desired user area ENDIF ;ASKNAM IF GETCALR LDA CURUSR MOV E,A ENDIF ;GETCALR MVI C,32 ;set user function CALL BDOS ; IF ASKNAM LDA DRV ;get drive user back ANI 0FH ;strip off the user MOV E,A ; ENDIF ;ASKNAM IF GETCALR LDA CURDSK ;get current drive MOV E,A ; ENDIF ;GETCALR MVI C,SELDSK ;select the current drive CALL BDOS ; QUIT: LHLD OLDSP ;get stack back SPHL ; RET ;return to BYE PRINT: PUSH H ;save MVI C,9 ;print string function CALL BDOS ; POP H ; RET ; PRINT1: PUSH H ;save MVI C,9 ;print string function CALL BDOS ; POP H ;and fall through to EXIT: MVI A,0CDH ;kill bye STA 0 ; JMP 0 ;hangup caller ; ;Temporary registers/counters... ; LINE1: DB 1 ;The first line counter CHRCT: DB 0 ;The character counter CHRCT1: DB 0 ;characters/line counter CRSET: DB 0 ;The CR counter RCNUM: DB 0 ;The record counter LINES: DB 0 ;The number of lines used DMAPT: DW BUFF AREG: DB 0,'$' ;temporary character storage DRV: DB 0 FAIL: DB 1 ;The open LASTCALR fail register IF GETCALR LFCB: DB 0 ENDIF ;GETCALR IF GETCALR AND (NOT MBBS) AND (NOT OXGATE) DB 'LASTCALR ' ;file containing name of last caller ENDIF ;GETCALR AND (NOT MBBS) IF GETCALR AND MBBS DB 'LASTCALRBBS' ENDIF ;GETCALR AND MBBS IF GETCALR AND OXGATE DB 'LASTCALRDAT' ENDIF ;GETCALR AND OXGATE IF GETCALR DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 SECND: DB 0 CURDSK: DB 0 CURUSR: DB 0 ENDIF ;GETCALR WFCB: DB 0,'NOTE ',0,0,0,0 DS 16 DB 0,0,0,0 ENDMSG: DB CR,LF,'End of Note $' PROMPT: DB '> $' SENDLF: DB CR,LF,'> $' ADLN: DB CR,LF,'$' SENDSP: DB 20H,'$' BELL: DB 7,'$' BKSP: DB BS,20H,BS,'$' SIGNON: DB CR,LF,'Note to the SYSOP - Hit twice ' DB 'to exit.',CR,LF,LF DB ' 1--------I---------I---------I---------I--' DB '-------I---------I---------I-----77',CR,LF,LF,'$' UR$NAME:DB 'Enter your Name and Today''s Date: $' SWARN: DB 7,CR,LF,LF,'WARNING! Only 5 lines left.',CR,LF,'$' MSG: DB CR,LF,'Do you want to LOG OFF now? (Y/N)? $' WTERR: DB CR,LF,'Write Error - Cannot close file $' OLDSP: DS 2 DS 16 STACK: BDMA: DW RDMA ;point to buffer RDMA: DS 128 ;the read buffer area BUFF: EQU $ ;start the file buffer here END START