; ; MENU.ASM Version 2.0 as of April 26, 1981 ; ; Original Program by: James J. Frantz, May 31, 1979 ; ;Menu Program Selection for '.BAS', '.INT' or '.COM' Files ; ; ; Modified from original by: Kelly Smith ; ; Version 2.0 contains the following modifications: ; ;(1) Made CP/M 2.x compatible; previous version would ; "clobber" the '$' string delimiter in filename and ; would display filenames and garbage memory 'ad ; nauseum'. ; ;(2) Added equates for either MBASIC or CBASIC assembly ; function, and corresponding 'heading'. ; ; Note: You must have MBASIC.COM on the currently ; logged diskette if 'mbasic$program' equate is ; true, and it will expect files of type '.BAS'. ; If 'cbasic$program' equate is true, you must ; have CRUN.COM on the currently logged ; diskette, and it will expect files of type ; '.INT'. If neither is equated to true, '.COM' ; filetypes are assumed. ; ;(3) Added command option to select drive for user ; requested MENU. (i.e., MENU B:). If corresponding ; filetype is not found for assembled MENU type (.BAS, ; .INT or .COM), MENU will display "+++ File Not Found ; +++" and return to the default drive. ; ;(4) Added "Disk Drive - X:" to heading display, where 'X' ; is the selected drive. ; ;(5) Added conditional assembly switches for 'upper' ; (uppercase only terminals), 'stdcpm' (standard CP/M), ; 'altcpm' (alternate CP/M). ; ;(6) Added conditional assembly switch for 'no$sys$files', ; to inhibit display of CP/M 2.X 'SYS' files. Handy, if ; running a Remote CP/M System and you don't want to let ; the whole world know whats 'hidden'... ; ;(7) Stripped MSB "tag bit" for files set-up for Remote ; CP/M Systems as "not for distribution". Files would ; not be sorted in proper order for display without ; this. ; ;(8) Fixed bug when MENU is set for BASIC file (either ; MBASIC or CBASIC) and is in B: (or greater drive) and ; attempting to load the MBASIC (or CRUN) and THEN the ; '.BAS' (or '.INT') file...now looks on same diskette ; that MENU is on. ; ;(9) Added 'widecrt' equate for two CRT terminal display ; formats. Set the equate 'widecrt' to true if your CRT ; terminal can display 80 columns by 24 rows. If ; 'widecrt' is false, the default display is 64 columns ; by 16 rows. ; ; As supplied, MENU.ASM is set-up for the following system ;configuration and display format: ; ; Lowercase terminal display: upper = false ; ; 80 column by 24 row display: widecrt = true ; ; Standard CP/M: stdcpm = true ; altcpm = false ; ; Display '.COM' Menu: mbasic$program = false ; cbasic$program = false ; ; No display of 'SYS' files: no$sys$files = true ; ; ; ; A Generalized Suggestions for Using MENU ; ; If you have kids that love to play games on your system, ;this is perhaps the most 'protective' way to keep there ;"busy little hands" out of the CP/M operating ;system...Just set them up with a GAMES diskette that ;AUTOLOAD's the MENU program, and never ever again will you ;hear "Gee Dad, I tried ERA *.* and now nuthi'n works...". ; ; ; true equ -1 ;define true false equ not true;define false ; mbasic$program equ false ;true = .BAS cbasic$program equ false ;true = .INT ; ;Note: Only one may be true, and ; both false = .COM ; no$sys$files equ true ;true = no SYS display, false = SYS display ; upper equ false ;true if uppercase only terminal widecrt equ false ;true if 80 column/24 row terminal ; stdcpm equ true ;true if standard CP/M (base address 0000h) altcpm equ false ;true if alternate CP/M (base address 4200h) ; if stdcpm ;if standard CP/M... base equ 0000h ;base for standard CP/M system endif ;end if... ; if altcpm ;if alternate CP/M... base equ 4200h ;base for H8 or TRS-80 CP/M system endif ;end if... ; bdos equ base+5 ;CP/M BDOS entry address for function call tfcb equ base+5ch;transient file control block base address ; nbr$col equ 4 ;number of columns to display if widecrt ;if 80 column/24 row crt terminal... screen$size equ 24 ;terminal has 24 lines/screen display screen$hgt equ 80 ;terminal has 80 rows/screen display endif ;end if... if not widecrt ;if 64 column/16 row crt terminal... screen$size equ 16 ;terminal has 16 lines/screen display screen$hgt equ 64 ;terminal has 64 rows/screen display endif ;end if... ; ccp$len equ 3c06h-3400h ;calculate CCP length ; bel equ 007h ;(^g) bell - human attention required lf equ 00ah ;(^j) line feed cr equ 00dh ;(^m) carriage return org base+100h start: lxi sp,stack$area ;set up a stack lda tfcb ;get drive specification ora a ;was drive explicity requested? jnz drive$request ;if yes, skip interrogate disk request mvi c,25 ;'interrogate disk' function call bdos ;find out which disk we're on... inr a ;make A: = 1 ; drive$request: ; adi 'A'-1 ;make it ASCII sta driveid ;save the ASCII drive identification sbi '@' ;make it HEX sta srch$fcb ;set selection for requested or default drive 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 jz kludge ;do not set file found, if zero sta file$found ;set file found flag kludge: 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 ani 7fh ;mask-off high bit 'cause may be ;"tagged" as 'not for distribution' for RCPM's 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: ; if no$sys$files ;if no SYStem files to be displayed... push b ;save pointer to table entry push d ;save pointer to file name xchg lxi d,9 ;add bias for "SYS" flag character dad d mov a,m ;get character ani 80h ;mask for "SYS" flag pop d ;adjust stack, in case we take the next jump pop b ;...or we really need the pointers jnz abort ;abort this filename, if "SYS" endif ;end if... ldax d ;get first byte of filename ani 7fh ;mask-off high bit 'cause may be ;"tagged" as 'not for distribution' for RCPM's stax d ;and save back, so proper file sort display 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 abort: 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 lda file$found ;get file$found flag ora a ;and set psw flags jz exit ;if zero, no files of this type found 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 if widecrt ;if 80 column/24 row crt terminal... lxi d,doubl$space ;print 2 spaces mvi c,9 ;'print buffer' command call bdos ;use CP/M endif ;end if... lxi d,doubl$space ;print 2 spaces 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 number ; 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 lxi d,prompt ;point instruction message mvi c,9 call bdos lxi d,input$buff mvi a,10 ;10 characters maximum stax d mvi c,10 ;'read buffer' command call bdos lxi h,input$buff+1 ;point to character 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 number jc reprint1 ;redisplay menu if illegal lxi d,14 ;increment between names lxi h,dir$table-14 ;point dummy 0th entry ; find$name: ; dad d ;add offset b times dcr b jnz find$name push d ;found filename, tidy-up screen... push h lxi d,crlfmsg mvi c,9 call bdos pop h pop d xchg ;save pointer to file name lhld base+6 ;get bdos entry point lxi b,-ccp$len ;offset to start of CP/M dad b push h ;save CP/M entry point ;on stack for branch lxi b,8 ;offset to command buffer "autoload" dad b ;(hl) points place to put name of ;.BAS, .INT, or .COM file to be ;executed push d ;save pointer to file name xchg ;(de) points to command buffer lxi h,128 ;offset to end of command buffer ;where pointer is stored dad d ;(hl) points to storage place mov m,e ;update buffer pointer to inx h ;the start of the command mov m,d ;buffer so CP/M will read lda driveid ;get selected drive identification stax d ;store at start of command buffer inx d ;bump for ':' delimeter position mvi a,':' ;make delimeter stax d ;and store it... inx d ;bump for destination pointer to filename if mbasic$program or cbasic$program ;if BASIC program... lxi h,command$name ;point command name mvi c,len$cmd$name ;length of command name call block$move lda driveid ;get selected drive identification stax d ;store at start of command buffer inx d ;bump for ':' delimeter position mvi a,':' ;make delimeter stax d ;and store it... inx d ;bump for destination pointer to filename endif ;end if... pop h ;point selected file name mvi c,8 ;length of file name call block$move if mbasic$program or cbasic$program ;if BASIC program... lxi h, spec$type mvi c,4 call block$move endif ;end if... xra a ;needs a 0 at end stax d ;of command line ret ; 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 ; exit: lxi d,nofile ;indicate no files present mvi c,9 call bdos jmp base ;and exit to CP/M via "warm boot" ; if upper ;if uppercase only terminal... nofile: db cr,lf,lf,'+++ FILE NOT FOUND! +++',cr,lf,'$' endif if not upper ;if not uppercase only terminal... nofile: db cr,lf,lf,'+++ File Not Found! +++',cr,lf,'$' endif crlfmsg: db cr,lf,'$' ; heading: db cr,lf,lf if widecrt and mbasic$program db ' ' endif if not widecrt and mbasic$program db ' ' endif if upper and mbasic$program db 'MICROSOFT COMPATIBLE BASIC FILE MENU' endif if not upper and mbasic$program db 'Microsoft Compatible BASIC File Menu' endif if widecrt and cbasic$program db ' ' endif if not widecrt and cbasic$program db ' ' endif if upper and cbasic$program db 'COMPILER SYSTEMS COMPATIBLE BASIC FILE MENU' endif if not upper and cbasic$program db 'Compiler Systems Compatible BASIC File Menu' endif if widecrt and not mbasic$program and not cbasic$program db ' ' endif if not widecrt and not mbasic$program and not cbasic$program db ' ' endif if upper and not mbasic$program and not cbasic$program db 'CP/M COMMAND FILE MENU' endif if not upper and not mbasic$program and not cbasic$program db 'CP/M Command File Menu' endif db cr,lf if widecrt ;if 80 column/24 row crt terminal... db ' ' endif ;end if... if not widecrt ;if 64 column/16 row crt terminal db ' ' endif ;end if... if upper ;if uppercase only terminal... db 'DISK DRIVE - ' endif ;end if... if not upper ;if not uppercase only terminal db 'Disk Drive - ' endif ;end if... driveid:ds 1 ;current logged ASCII drive identification db ':',cr,lf,lf,'$' if upper ;if uppercase only terminal prompt: db cr,lf,bel,' ENTER MENU NUMBER, AND PRESS RETURN: $' endif ;end if... if not upper ;if not uppercase only terminal... prompt: db cr,lf,bel,' Enter menu number, and press return: $' endif ;end if... if mbasic$program ;if MBASIC program... command$name: db 'MBASIC ' ;Microsoft BASIC ; len$cmd$name equ $-command$name ; spec$type: db '.BAS' endif ;end if... if cbasic$program ;if CBASIC program... command$name: db 'CRUN ' ;Compiler Systems BASIC ; len$cmd$name equ $-command$name ; spec$type: db '.INT' endif ;end if... doubl$space: db ' $' ; menu$buff: db ' - 00$' ; 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 ; file$found: db 0 ;file found flag if mbasic$program ;if MBASIC program... srch$fcb: db 0,'????????BAS',0,0,0,0 endif ;end if... if cbasic$program ;if CBASIC program... srch$fcb: db 0,'????????INT',0,0,0,0 endif ;end if... if not mbasic$program and not cbasic$program ;if not BASIC program... srch$fcb: db 0,'????????COM',0,0,0,0 endif ;end if... dir$table: db 255 ; stack$area equ 200*14 + 30 ; input$buff equ stack$area ; end start