; MENU PROGRAM ; FOR ; MACHINE LANGUAGE OR BASIC PROGRAMS ; ; BY ; JAMES J. FRANTZ ; MAY 31, 1979 ; ; ORG 0100H ; ; BASIC$PROG EQU 0 ;SET TO 0 FOR MACHINE ; LXI SP,STACK$AREA ;SET UP A STACK MVI C,17 ;'SEARCH FIRST' COMMAND ; SORT$LOOP: LXI D,SRCH$FCB ;POINT FILE CONTROL BLOCK CALL BDOS ;USE CP/M ENTRY POINT ; ; ORA A ;TEST FOR -1 JM ASSIGN$MENU$NBR ;PRINT EMPTY RRC ;THIS IS THE SAME AS RRC ;5 "ADD A'S" RRC ANI 60H ;MASK CORRECT BITS ADI 80H ;ADD BASE ADDRESS(0080H) MOV E,A ;PUT POINTER IN (DE) MVI D,0 ;AS 16 BIT VALUE LXI H,DIRTABLE ;POINT START OF TABLE OF ;SORTED NAMES INX D ;POINT PAST ERASE FIELD ; COMPARE$LOOP: ; PUSH D ;SAVE POINTER TO NEXT ;ENTRY FROM DISK DIRECTORY MVI C,8 ;LENGTH OF COMPARE PUSH H ;SAVE POINTER TO TABLE ; COMPARE1: LDAX D ;GET TRIAL NAME CHAR CMP M ;MATCH? JNZ END$COMPARE ;IF NOT, TRY NEXT ENTRY INX H ;ADVANCE POINTERS INX D DCR C ;ONE LESS CHAR TO COMPARE JNZ COMPARE1 ;KEEP TESTING END$COMPARE: POP B ;RESTORE TABLE POINTER JC INSERT$NAME ;DIRECTORY NAME GOES IN ;FRONT OF CURRENT TABLE ;ENTRY IF LOWER(CY=1) LXI H,14 ;LENGTH OF TABLE ENTRY DAD B ;(HL) TO NEXT TABLE ENTRY POP D ;RECOVER TRAILER NAME POINT JMP COMPARE$LOOP ;LOOP AGAIN ; ; INSERT$NAME: LXI H,FILE$COUNT ;COUNT THE NUMBER OF FILES INR M ;TO BE DISPLAYED LHLD END$OF$TABLE ;GET POINTER TO TABLE XCHG LXI H,14 ;DISTANCE TO MOVE DAD D ;(HL) POINT DESTINATION SHLD END$OF$TABLE ;SAVE THE NEW END OF TABLE INX H INX D MOVE$UP: DCX D DCX H LDAX D ;GET BYTE TO MOVE MOV M,A ;PUT IN NEW SPOT MOV A,C ;TEST FOR DONE CMP E ;(BC)=(DE)? JNZ MOVE$UP MOV A,B CMP D JNZ MOVE$UP POP H ;RECOVER POINTER MVI C,8 CALL BLOCK$MOVE ;INSERT NAME IN TABLE ; LXI H,MENU$BUFF ;POINT MENU NUMBER BLOCK MVI C,6 ;LENGTH OF MOVEK CALL BLOCK$MOVE ;INSERT TEXT IN TABLE ; MVI C,18 ;'SEARCH NEXT' COMMAND JMP SORT$LOOP ; ASSIGN$MENU$NBR: LDA FILE$COUNT MOV B,A ;SAVE IN (B) PUSH PSW ;AND ON STACK MVI C,0 ;INITIAL FILE NUMBER LXI H,DIRTABLE+11 ;POINT FIRST FILE NUMBER LXI D,13 ;OFFSET TO OTHER NUMBERS ; NUMBER$FILES: MOV A,C ;PUT FILE NUMBER IN (A) ADI 1 ;INCREMENT DAA ;DECIMAL CONVERT MOV C,A ;RESAVE IN (C) RRC ;GET TENS DIGIT INTO RRC ;PROPER PLACE RRC ; RRC ANI 0FH ;ADD MASK JZ USE$BLANK ;SUPRESS LEADING ZERO BY ADI 10H ;ADD EITHER 20H(ASCII ' ') USE$BLANK: ADI ' ' ;OR 20H + 10H FOR NUMERAL MOV M,A ;PUT IN TEXT STREAM MOV A,C ;GET UNITS PORTION ANI 0FH ;MASK OFF TENS PORTION ADI '0' ;CONVERT TO ASCII INX H MOV M,A DAD D ;REPEAT UNTIL ALL FILES DCR B ;ARE SEQUENTIALLY NUMBERED JNZ NUMBER$FILES ; POP PSW ;GET FILE$COUNT FROM STACK PUSH PSW ;AND SAVE AGAIN FOR LATER ; ; ADI NBR$COL-1 MVI B,255 ;(B) ACCUMULATES QUOTIENT ;SO SET TO -1 FOR AT LEAST ;1 PASS THRU GIVES 0 ; DIVX: INR B ; SUI NBR$COL ;DIVIDE (FILE$COUNT+3)BY ;FOUT TO GET OFFSET1 ; JP DIVX ADI NBR$COL ;SUBSTRACTED ONCE TOO MUCH ;SO ADD IT BACK ON LXI H,OFFSET1 MOV M,B ;INSERT OFFSET1 INTO TABLE INX H ;POINT OFFSET2 LOCATION JNZ SETOFFSET2 ;SAME AS OFFSET1 IF NON- ;ZERO REMAINDER DCR B ;ELSE OFFSET2=OFFSET1-1 ;: SETOFFSET2: MOV M,B ;PUT OFFSET2 IN TABLE INX H ;POINT OFFSET FOR COL 3 DCR A ;TEST FOR REMAINDER OF 1 JNZ SETOFFSET3 ;IF REMAINDER <> 1, USE ;OFFSET3=OFFSET2-1 DCR B ;ELSE OFFSET3=OFFSET2-1Y ; SETOFFSET3: MOV M,B ;ELSE OFFSET TO COLUMN 4 ; ; REPRINT: POP PSW ;RECOVER FILE COUNT ; REPRINT1: PUSH PSW ;SAVE AGAIN FOR LATER USE STA FILE$COUNT ;SAVE FOR COUNTING MVI A,SCREEN$HGT ;SET FOR VIDEO DISPLAY SIZE STA LINE$COUNT ; LXI D,HEADING MVI C,9 ;BUFFER PRINTER COMMAND CALL BDOS ;CP/M PRINTS HEADING ; LXI H,DIR$TABLE - 14 ;POINT DUMMY 0TH ENTRY ; PRINT$LINE: PUSH H ;SAVE BASE ADDRESS LXI D,OFFSET0 ;POINT OFFSET TABLE MVI A,NBR$COL ;4 COLUMN PER LINE ; PRINT$NAME: STA COLUMN$CNT ;SAVE COUNT OF COLUMNS PUSH H ;SAVE CURRENT NAME POINTER PUSH D ;SAVE OFFSET TABLE POINTER LXI D,DOUBL$SPACE ;PRINT 2 BLANKS MVI C,9 ;'PRINT BUFFER' COMMAND CALL BDOS ;USE CP/M POP D ;GET OFFSET TABLE POINTER POP H ;GET NAME POINTER LDAX D ;GET OFFSET VALUE ; LXI B,14 ;EACH NAME IS 14 LONG ; MULT$14: DAD B ;ADD 14 FOR EACH OFFSET DCR A ;UNTIL OFFSET = 0 JNZ MULT$14 PUSH H ;SAVE NEW NAME POINTER PUSH D ;SAVE OFFSET POINTER XCHG ;POINTER NAME TO PRINT W/(DE) MVI C,9 ;PRINT BUFFER CALL BDOS ;PRINT FILE NAME ;AND IT'S MENU NO. ; TEST$FINISH: LXI H,FILE$COUNT ;SEE IF DONE PRINTING DCR M ;BY TESTING COUNT OF FILES POP D ;GET OFFSET POINTER POP H ;GET POINTER TO LAST NAME JZ FINISH ;NO MORE TO PRINT INX D ;ADVANCE OFFSET POINTER LDA COLUMN$CNT DCR A ;SEE IF COLUMN LEFT = 0 JNZ PRINT$NAME ;PRINT ANOTHER SAVE LINE CALL CRLF POP H ;GET BASE OF PREVIOUS LINE LXI D,14 ;ADD OFFSET DAD D JMP PRINT$LINE ; ; ; FINISH: POP H ;UNJUNK STACK ; LF$LOOP: CALL CRLF JP LF$LOOP ;OMIT THIS LINE IF DESIRED LXI D,PROMPT ;POINT INSTRUCTION MESSAGE MVI C,9 CALL BDOS LXI D,INPUT$BUFF MVI A,10 ;10 CHRS MAX STAX D MVI C,10 ;'READ BUFFER' COMMAND CALL BDOS ; ; ; LXI H,INPUT$BUFF+1 ;POINT TO CHR COUNTER MOV A,M ;GET IT AND SEE IF >2 CPI 3 JNC REPRINT ;REPRINT THE MENU MOV C,A ;COUNT OF DIGITS TO (C) MVI B,0 ; GET$MENU$NBR: INX H ;POINT ASCII DIGIT MOV A,M ;GET IT CALL ASCII$CONVERT ;CONVERT TO BINARY JC REPRINT ;RE-DISPLAY ON ERROR DCR C JNZ GET$MENU$NBR ; ; POP PSW ;RECOVER FILE COUNTER CMP B ;FILE$ COUNT- REQUEST NO. JC REPRINT1 ;REDISPLAY MENU IF ILLEGAL ; LXI D,14 ;INC BETWEEN NAMES LXI H,DIR$TABLE-14 ;POINT DUMMY 0TH ENTRY ; FIND$NAME: DAD D ;ADD OFFSET B TIMES DCR B JNZ FIND$NAME ; ; XCHG ;SAVE POINTER TO FILE NAME LHLD 6 ;GET BDOS ENTRY POINT LXI B,-CCP$LEN ;OFFSET TO START OF CM/M DAD B PUSH H ;SAVE CP/M ENTRY POINT ;ON STACK FOR BRANCH LXI B,8 ;OFFSET TO COMMAND BUFFER DAD B ;(HL) POINTS PLACE TO PUT ;NAME OF .COM FILE TO BE ;EXECUTED PUSH D ;SAVE POINTER TO FILE NAME XCHG ;(DE) POINTS COMMAND BUDFER ; ; ; LXI H,128 ;OFFSET TO END OF CMD BUFF ;WHERE POINTER IS STORED DAD D ;(HL) POIN TS STORAGE PLACE MOV M,E ;UPDATE BUFFER POINTER TO INX H ;THE START OF THE COMMAND MOV M,D ;BUFF SO CP/M WILL READ ; IF BASIC$PROG ; LXI H,COMMAND$NAME ;POINT COMMAND NAME MVI C,LEN$CMD$NAME ;LENGHT OF COMMAND NAME CALL BLOCK$MOVE ; ENDIF ; POP H ;POINT SELECTED FILE NAME MVI C,8 ;LENGTH OF FILE NAME CALL BLOCK$MOVE ; ; IF BASIC$PROG ; LXI H, SPEC$TYPE MVI C,4 CALL BLOCK$MOVE ; ENDIF ; XRA A ;NEEDS A 0 AT END STAX D ;OF COMMAND LINE ; RET ; ; ;SUBROUTINES ; BLOCK$MOVE: MOV A,M STAX D INX D INX H DCR C JNZ BLOCK$MOVE RET ; ASCII$CONVERT: SUI '0' ;SUBTRACT ASCII BIAS CPI 9+1 ;BE SURE IT'S NUMERIC CMC RC MOV D,A MOV A,B RLC RLC RLC ADD B RC ADD B RC ADD D MOV B,A RET ; CRLF: LXI D,CRLFMSG MVI C,9 CALL BDOS LXI H,LINE$COUNT DCR M RET ; ; CRLFMSG DB 0DH,0AH,'$' ; HEADING DB 0AH,9,9,9,' MENU',0DH,0AH,0AH,'$' ; IF BASIC$PROG ; COMMAND$NAME: DB 'BASIC ' ; LEN$CMD$NAME EQU $-COMMAND$NAME ; SPEC$TYPE: DB '.BAS' ; ENDIF ; PROMPT: DB 'ENTER MENU NUMBER & PRESS RETURN''$' ; DOUBL$SPACE: DB ' $' ; MENU$BUFF: DB ' - 0$' ; OFFSET0 DB 1 OFFSET1 DB 0,0,0 ; END$OF$TABLE: DW DIRTABLE ; FILE$COUNT: DB 0 COLUMN$CNT: DB 4 LINE$COUNT: DB 0 ; IF BASIC$PROG ; SRCH$FCB: DB 0,'????????BAS',0 ; ENDIF ; SRCH$FCB: DB 0,'????????COM',0 ; ; DIR$TABLE: DB 255 ; STACK$AREA EQU 200*14 + 30 ; INPUT$BUFF EQU STACK$AREA ; ; ; EQUATES: ; BDOS EQU 5 NBR$COL EQU 4 CCP$LEN EQU 3C06H-3400H SCREEN$SIZE EQU 24 SCREEN$HGT EQU 80 ; ; ; ; END