*####################################################################### * Program SD...Directory Utility * * Dr. David C. Wilcox * DCW Industries, Inc. * 5354 Palm Drive, La Canada, CA 91011 * 818/790-3844 * * April 13, 1986 *####################################################################### * * SPECIAL NOTE: * ============= * This sorted directory utility has been created by translating the * CP/M-80 utility of the same name created by Bruce Ratliff from 8080 * mnemonics to MC68000 mnemonics. I did the original work on a TRS-80 * Model 16 with CP/M 68k running on top of CP/M Plus. Since CP/M Plus * supports time and date stamping, I chose to display time and date * stamps via special CP/M 68k bios calls to read the CP/M Plus time and * date stamp information. I have added a trs80 conditional assembly * flag which should exclude all such calls, but I have no way of testing * to see if I've done it correctly. Please let me know if there are * any problems and I'll try to provide fixes. * D.C. Wilcox *####################################################################### * Special registers: * * a5 = address of dma buffer * a6 = address of 1st parsed fcb *####################################################################### * false equ 0 true equ $ff * * user option specifications * aopt equ true *true to allow searching all user areas dopt equ true *true to allow searching all drives on-line nopt equ true *true to allow disabling page pause option popt equ true *true to allow printer option ropt equ true *true to allow nonarchived file option sopt equ true *true to allow system file option uopt equ true *true to allow user number option * truek equ true *true to display actual file size trs80 equ false *true if TRS-80 Model 16 with CP/M Plus * break equ 03 *ascii etx (^C) tab equ 09 *horizontal tab lf equ 10 *line feed cr equ 13 *carriage return xoff equ 19 *ascii dc3 (^S) esc equ 27 *ascii escape space equ 32 *ascii space marker equ 33 *time/date stamping indicator upmask equ $5f *upper case mask * *delim equ 124 *fence (delimiter) character (vertical bar) delim equ 32 *space *delim equ 58 *colon * npl equ 02 *# of names per line (max of 2 for 80x24) margsz equ 10 *width of left margin indent lps equ 23 *# of lines per screen (max of 23 for 80x24) * drvmax equ 07 *maximum drive number (0=a:,1=b:...,7=h:) usrmax equ 15 *maximum user number (0-15) stskip equ 04 *start skipping at this drive number (1=a:,...) skipto equ 09 *and skip to this drive number (1=a:,...) * * bdos equates * boot equ 00 *warm boot rdchr equ 01 *read character from console wrchr equ 02 *write character to console listout equ 05 *output to LST: dirio equ 06 *direct console I/O pstring equ 09 *print a string const equ 11 *check console status seldsk equ 14 *select disk search equ 17 *search for first next equ 18 *search for next curdsk equ 25 *get currently logged disk name setdma equ 26 *set current dma curdpb equ 31 *get current disk parameters curusr equ 32 *get currently logged user number getfree equ 46 *get disk free space calbios equ 50 *direct bios call z80r equ $85 *read Z80 memory * bdos equ $0002 *bdos entry point bios equ $0003 *bios entry point * * Locate fcb and dma (for portability) * link a6,#0 *mark stack frame move.l 8(a6),a0 *get base page address lea $80(a0),a5 *get address of dma buffer lea $5c(a0),a6 *get address of 1st parsed file name jsr clear *Make sure key registers are clear start: move.w #$ff,d1 *get current user number move.w #curusr,d0 trap #bdos move.b d0,oldusr *initialize startup user number move.b d0,newusr *..and make new user match it ifne dopt move.b d0,basusr *save extra copy for multi-disk endc *directories move.w #curdsk,d0 trap #bdos *get current disk nr move.b d0,olddsk *save for reset if needed * * First we parse the dma to see if a user number has been entered. * If so, the fcb and dma are rewritten in normal CP/M syntax. * jsr parse * * Check to see if the fcb drive spec matches the currently logged * drive. If so, put a zero in the fcb since it's redundant. * jsr setdflt * * If at least one option is allowed, scan the command line for the * option field delimiter. Any unrecognized options or illegal user * numbers will cause the help message to print. (Note that we scan the * command line buffer rather than the 2nd default fcb because all 7 * options plus a 2 digit user number won't fit in the fcb name field). * * Search for command line delimiter. If not found, assume no options. * clr.l d2 movea.l a5,a2 *set command line buffer pointer move.b (a2)+,d2 *get length of command line buffer scndol: subq.b #1,d2 blt ckrest *exit if command line buffer empty move.b (a2)+,d0 cmpi.b #'[',d0 *option delimiter = "[" bne scndol * * Valid delimiter found. Scan the rest of the buffer for options. * Errors past this point cause an abort. * scnopt: subq.b #1,d2 *dock characters left in option field blt ckrest *if option field exhausted, exit scnagn: move.b (a2)+,d0 *get the next option character cmpi.b #space,d0 *do we have a space? beq scnopt *ignore it if so cmpi.b #',',d0 *same for comma beq scnopt cmpi.b #']',d0 *end of option list beq ckrest movea.l #otbl,a0 *get base of option lookup table subq #1,a0 move.l #oend,a1 *get length of option lookup table suba.l a0,a1 move.l a1,d1 nomach: addq #1,a0 *bump to next option table character subq.b #1,d1 *are we out of the table? beq ck4usr *if so, check for user option cmp.b (a0),d0 *compare our character with option table bne nomach *exit if no match move.b #0,(a0) *otherwise, activate the flag bra scnopt *..and go get the next option character * * If option character doesn't match the table, see if we have a user * option. * ck4usr: nop ifne uopt *check for user number option cmpi.b #'U',d0 bne clerr *last option uagn: subq #1,d2 *bump to user number digit blt clerr *error if nothing left move.b (a2)+,d0 *get decimal digit cmpi.b #space,d0 *ignore leading spaces beq uagn subi.b #$30,d0 *subtract ascii bias blt clerr *error if < 0 cmpi.b #10,d0 bgt clerr *error if > 9 move.b d0,newusr *save user number as it may be 1 digit ifne dopt move.b d0,basusr *duplicate it if multi-disk mode move.b #$ff,gotusr *set got user flag endc subq.b #1,d2 *bump to possible 2nd digit of user no. blt ckrest *if no more buffer, exit with user # move.b (a2),d0 *else, check for another digit subi.b #$30,d0 blt scnagn *if next char not numeric, it's not part cmpi.b #10,d0 *of user no. so check for another option bgt scnagn movea.l #newusr,a1 *get tens digit move.b (a1),d1 mulu #10,d1 *multiply by 10 add.b d1,d0 *combine with units digit move.b d0,(a1) *save the total user number addq #1,a2 *point to next option ifne dopt move.b d0,basusr *duplicate it if multi-disk mode endc bra scnopt *continue scanning endc *balance uopt * * If command line error occurs, say so and display instructions on * correct usage. * clerr: movea.l #synerr,a0 *display "syntax error" in reverse video jsr print bra help *..and display help message * * Options input or not specified. Get today's date & time before * proceeding any further. * ckrest: nop ifne trs80 jsr today endc * * If "A" option choosen and no user number specified * set user to zero * zusr: nop ifne aopt movea.l #gotusr,a0 *was a user specified? cmpi.b #0,(a0) bne zdrv *yes-quit now movea.l #aopflg,a0 *was "A" option specified? cmpi.b #0,(a0) bne zdrv *branch if no move.b #0,newusr *zero newusr for all users ifne dopt move.b #0,basusr *zero basusr for all users endc endc * * If "D" option choosen and no drive specified * set drive to physical zero * zdrv: move.b (a6),d0 *get drive name for directory search cmpi.b #0,d0 *any specified? bne noopt *skip next routine if drive specified ifne dopt movea.l #dopflg,a0 *else if dopt then cmpi.b #0,(a0) bne zdrv1 move.b #1,(a6) *always start with a: bra noopt endc zdrv1: movea.l #olddsk,a0 *otherwise, get default disk move.b (a0),d0 addq.b #1,d0 move.b d0,(a6) *put the absolute drive code in fcb * * Validate drive code and user area number. * noopt: movea.l #dremsg,a0 *get the drive/user error message move.b (a6),d0 *get directory drive code subq.b #1,d0 *normalize to range of 0-7 cmpi.b #drvmax,d0 *compare with maximum drives on-line bgt erxit *take drive error exit if out of range movea.l #usrmsg,a0 *switch to user # error message movea.l #maxusr,a1 move.b #usrmax,(a1) *store max user # in maxusr movea.l #newusr,a1 *point to the directory user area move.b (a1),d0 cmpi.b #usrmax,d0 *compare it with the maximum bgt erxit *take error exit if user number illegal movea.l a6,a1 *point to first character in fcb addq #1,a1 cmpi.b #'[',(a1) beq gotdl cmpi.b #space,(a1) bne gotfcb * * If no fcb...make fcb all '?' * gotdl: moveq.l #11,d2 *fn+ft count qloop: move.b #'?',(a1)+ *store '?' in fcb subq #1,d2 bne qloop gotfcb: move.b #'?',12(a6) *force wild extent jsr setsrc *set dma for bdos media change check move.b (a6),d1 *get the drive code out of the fcb subq #1,d1 *normalize drive code for select move.b #seldsk,d0 *select the directory drive to retrieve trap #bdos *..the proper allocation vector move.l #cdpb,d1 *request dpb move.w #curdpb,d0 trap #bdos * * Calculate # of kbytes free on selected drive * free: clr.l d1 move.b (a6),d1 *get drive # subq #1,d1 move.w #getfree,d0 *use compute free space bdos call trap #bdos move.l (a5),d0 divu #8,d0 *convert from sectors to kbytes move.w d0,freeby *save free space for output later * * Check for presence of time and date stamps * move.b #2,mnpl *reset column counter to 2 jsr chkstmp *check for date/time stamps movea.l #stampon,a0 cmp.b #$20,(a0) *are they present? beq settbl *yes...stay with 2 column display move.b #3,mnpl *no....change to a 3 column display * * Reenter here on subsequent passes while in the all-users mode * settbl: clr.l d2 movea.l #dirmax,a0 *get directory maximum again move.w (a0),d2 addq.w #1,d2 *directory size is dirmax+1 mulu #4,d2 *quadruple directory size movea.l #order,a1 *to get size of order table add.l d2,a1 *allocate order table movea.l #tbloc,a0 *name table begins where move.l a1,(a0) move.l a1,nextt *order table begins ifne uopt clr.l d1 movea.l #newusr,a0 *get user area for directory move.b (a0),d1 move.w #curusr,d0 *get the user function trap #bdos *..and set new user number endc * * Look up the fcb in the directory * sfirst: move.w #0,count *initialize match counter move.w #0,totfil *initialize total file counter move.w #0,totsiz *initialize total size counter jsr setsrc *set dma for directory search move.w #search,d0 *get 'search first' function bra look *..and go search for 1st match * * Read more directory entries * mordir: move.w #next,d0 *search next look: move.l a6,d1 trap #bdos *read directory entry cmpi.b #$ff,d0 *check for end ($ff) beq sprint *if no more, sort & print what we have * * Point to directory entry * some: move.b d0,tdflag *save it for retrieving date stamp mulu #32,d0 *compute directory offset movea.l a5,a2 *point to dma buffer add.l d0,a2 *point to entry adda.l #10,a2 *point to sys byte ifne ropt movea.l #ropflg,a0 *did user request unarchived cmpi.b #0,(a0) *files only? bne anyarc adda.l #1,a2 *point to arc byte btst #7,(a2) *check bit 7 of arc byte bne mordir *skip if it's archived suba.l #1,a2 *now point to sys bit for proper bra sysfok *alignment...then skip sys bit check endc anyarc: nop ifne sopt movea.l #sopflg,a0 *did user request sys files? move.b (a0),d0 cmpi.b #0,d0 beq sysfok endc btst #7,(a2) *check bit 7 of sys byte bne mordir *skip that file sysfok: suba #10,a2 *back to user number (alloc flag) movea.l #newusr,a0 *get current user cmpm.b (a0)+,(a2)+ bne mordir *ignore if different * * Move entry to table * movea.l #nextt,a0 *next table entry to... move.l (a0),a3 *register a3 moveq.l #12,d2 *entry length (name, type, extent) tmove: move.b (a2)+,(a3)+ *store entry character in table subq #1,d2 *more? bne tmove adda #2,a2 *point to sector count move.b (a2)+,(a3)+ *store in table cmpi.b #$20,stampon *check for date stamp enabled beq savdat *enabled...so retrieve date stamp adda #5,a3 *otherwise, skip over five bytes bra tmove1 savdat: movea.l #tdflag,a0 *fetch fcb number clr.l d0 move.b (a0),d0 mulu #10,d0 *calculate time/date stamp offset addi.b #101,d0 movea.l a5,a2 *point to beginning of dma buffer add d0,a2 *add time/date stamp offset moveq.l #4,d2 loopdat:move.b (a2)+,(a3)+ *copy time/date stamp data subq #1,d2 *in table bne loopdat move.b #0,(a3)+ *pad with a null byte tmove1: move.l a3,nextt *save updated table addr addq.w #1,count *bump the # of matches made bra mordir * * Sort and print * sprint: nop ifne aopt or uopt jsr setfop *return to file output dma & user # endc movea.l #count,a0 *get file name count movea.l #tcount,a4 move.w (a0)+,(a4)+ cmpi.w #0,tcount *any found? beq prtotl *exit if no files found move.b #1,supspc *enable leading zero suppression subq #2,a4 *make a4 point to tcount * * Initialize the order table * movea.l #tbloc,a0 *get start of name table move.l (a0),a2 movea.l #order,a1 *point to order table bldord: move.l a2,(a1)+ *save address adda #18,a2 *point to next entry (add 18 bytes) subq #1,(a4) *count down loop bne bldord *if nonzero, do another one movea.l #count,a0 *get count move.w (a0),scount *save as # to sort cmpi.b #1,(a0) *only 1 entry? beq noout *yes, so skip sort * * This sort routine is adapted from (8080) software tools * by Kernigan and Plaugher. I'm sure it can be improved * upon, and has probably been written for the MC68000 long * ago...BUT...each day only has 24 hours! I simply translated * the 8080 routine. * sort: clr.l d0 clr.l d1 clr.l d4 movea.l #scount,a3 *number of entries l0: clr.l d3 *clear carry move.w (a3),d3 *gap=gap/2 divu #2,d3 cmpi.w #0,d3 *is it zero? beq noout *then none left ori.b #1,d3 *make gap odd move.w d3,gap addq.w #1,d3 *i=gap+1 l2: move.w d3,i movea.l #gap,a3 move.w (a3),d4 *j=i-gap sub.w d4,d3 l3: move.w d3,j movea.l #gap,a3 *jg=j+gap move.w (a3),d4 add.w d3,d4 move.w d4,jg move.w d4,d0 move.w d3,d1 jsr compare *compare (j) and (jg) bgt l5 *if a(j)<=a(jg) movea.l #j,a3 move.w (a3),d0 movea.l #jg,a3 move.w (a3),d1 jsr swap *exchange a(j) and a(jg) movea.l #j,a3 *j=j-gap move.w (a3),d3 movea.l #gap,a3 move.w (a3),d4 sub.w d4,d3 blt l5 *if j>0 goto l3 cmpi.w #0,d3 *check for zero beq l5 bra l3 l5: movea.l #scount,a3 *for later move.w (a3),d4 movea.l #i,a3 *i=i+1 move.w (a3),d3 addq.w #1,d3 cmp.w d3,d4 *if i<=n goto l2 bge l2 movea.l #gap,a3 bra l0 * * Sort is all done - print entries * noout: movea.l #order,a3 *initialize order table pointer move.l a3,nextt jsr crlf *print "directory for ... movea.l #dirms1,a0 *at start of each section jsr print jsr prdir2 *print " drive, x user, y" ifne trs80 movea.l #datmsg,a0 *print " Date: " jsr print jsr loadtd *put today's date in appropriate memory jsr display *print today's date & time endc jsr crlf movea.l #linmsg,a0 jsr print addq.b #1,lincnt *bump line count bra newlin *start new line and output the files * * Output the directory files we've matched. * entry: subq #1,count *dock file count beq okprnt *if count=0, last file so skip compare * * Compare each entry to make sure that it isn't part of a multiple * extent file. Go only when we have the last extent of the file. * jsr ckabrt *check for abort code from keyboard movea.l #nextt,a2 move.l (a2),a3 move.l (a3)+,a1 move.l (a3),a0 jsr compr *does this entry match next one? bne okprnt *no, print it cmpi.b #$20,stampon *check for date stamps on bne nocarry jsr carry *carry date stamp forward nocarry: move.l a3,nextt *skip since highest extent comes last bra entry *loop back for next lowest extent * * Valid entry obtained - display it. * okprnt: movea.l #nextt,a2 *get order table pointer move.l (a2),a3 *get address move.l (a3)+,a1 move.l a3,nextt *save updated table pointer moveq.l #8,d2 *file name length jsr typeit *type filename move.b #'.',d1 *period after filename jsr type jsr savatrb *save attribute flags moveq.l #3,d2 *display 3 characters of filetype jsr typeit * * Compute the size of the file and update our summary datum. * move.b (a1)+,extno *get extent number move.b (a1)+,sectct *get sector count of last extent move.b (a1)+,date1 *1st date byte move.b (a1)+,date2 *2nd date byte move.b (a1)+,hour *hour move.b (a1)+,min *munute movea.l #extno,a0 clr.l d0 move.b (a0),d0 *multiply number of mulu #16,d0 *extents by 16k * ifne truek jsr calcrec *calculate number of records divu #8,d0 *convert to kbytes move.l d0,d1 swap d1 *examine remainder cmpi.w #0,d1 *is it zero? beq fini *yes...no leftover sectors addq.w #1,d0 *no....add another kbyte endc * ifeq truek movea.l #blkmsk,a0 movea.l #sectct,a1 *round last extent to block size clr.l d1 move.b (a1),d1 add.b (a0),d1 divu #8,d1 *convert from sectors to k add.b d1,d0 *add to total k clr.l d1 move.b (a0),d1 *convert sec/blk to k/blk divu #8,d1 not.b d1 *use to finish rounding and.b d1,d0 endc * fini: add.w d0,totsiz *add to total used addq.w #1,totfil *increment file count move.w d0,d4 *save it in d4 * * Output the size of the individual file. * move.b #space,d1 *begin with a space jsr type jsr decprt *print file size move.b #'k',d1 *follow with 'k' jsr type move.b #space,d1 *and conclude with a space jsr type *....................................................................... * Output the number of records of the individual file * * movea.l #numrec,a0 *point to total records * move.w (a0),d4 * jsr decprt *print number of records *....................................................................... * Display attributes * cmpi.b #$80,rorw *check RO/RW flag bne unpro move.b #'R',d1 bra syschk unpro: move.b #space,d1 syschk: jsr type cmpi.b #$80,sysdir *check Sys/Dir flag bne unsys move.b #'S',d1 bra arcchk unsys: move.b #space,d1 arcchk: jsr type cmpi.b #$80,arciv *check Archive flag bne unarc move.b #'A',d1 bra alldone unarc: move.b #space,d1 alldone: jsr type move.b #space,d1 *print a space jsr type cmpi.b #$20,stampon bne nodisp jsr display *now the date and time * * One file output - test to see if we have to output another one. * nodisp: movea.l #count,a2 *get current file counter and test it cmpi.w #0,(a2) beq prtotl *if no more files, go to summary output * * At least one more file to output - can we put it on the current line? * subq.b #1,colcnt beq nodis1 jsr fence *if room left, output column separator nodis1: cmpi.b #0,colcnt bne entry *.. and go output another file * * Current line full, start a new one. * newlin: movea.l #mnpl,a0 move.b (a0),colcnt *reset names per line counter jsr crlf *space down to next line bra entry *go back and output another file * * Print d4 in decimal with leading zero suppression * decprt: move.b #0,d5 *clear leading zero flag movea.l #supspc,a0 *get leading space suppression flag move.b (a0),d6 clr.l d3 *print 1000's digit move.w d4,d3 divu #1000,d3 move.l d3,d4 jsr digit swap d4 clr.l d3 *print 100's digit move.w d4,d3 divu #100,d3 move.l d3,d4 jsr digit swap d4 clr.l d3 *print 10's digit move.w d4,d3 divu #10,d3 move.l d3,d4 jsr digit swap d4 move.w d4,d1 *print units digit addi.b #'0',d1 bra type digit: move.b d3,d1 addi.b #'0',d1 digex: cmpi.b #'0',d1 *zero digit? bne dignz *no, type it cmpi.b #0,d5 *leading zero? bne type *print digit cmpi.b #0,d6 *is space suppression flag set? bne digsp *no....print a leading space rts *yes...don't give leading spaces digsp: bra pspace *leading zero...print space dignz: move.b #1,d5 *set leading zero flag so next zero bra type *prints, and print digit * * Show total space and files used * prtotl: move.b #0,supspc *suppress leading spaces in totals movea.l #totfil,a0 *how many files did we match? move.w (a0),d0 cmpi.w #0,d0 beq nxtusr *skip the summary if we didn't find any move.b #1,fndflg *set file found flag jsr crlf jsr prdir *print " drive, x user, y" nouser: movea.l #totms3,a0 *print " contains " jsr print clr.l d4 movea.l #totsiz,a0 *print total k used by files matched move.w (a0),d4 jsr decprt movea.l #totms4,a0 *print "k in " jsr print clr.l d4 movea.l #totfil,a0 *recall totfil move.w (a0),d4 jsr decprt *print number of files matched movea.l #totms5,a0 *print " files with " jsr print jsr prtfre *output free space remaining & " free" * * Directory for one user area completed. If all users option is * selected, then go do another directory on the next user number * until we exceed the maximum user # for the selected drive. * nxtusr: nop ifne aopt *if all users option enabled movea.l #aopflg,a0 *if not all users mode - skip next cmpi.b #0,(a0) bne goclz jsr ckabrt *check for user abort first movea.l #newusr,a1 *bump directory user number addq.b #1,(a1) cmpi.b #usrmax,(a1) *does next user # exceed maximum? blt settbl *continue if more user areas to go endc *aopt ifne dopt and aopt *if multi-disk option enabled movea.l #basusr,a0 *reset base user number for the move.b (a0),newusr *..next directory search endc *balance dopt and aopt * * We've finished all of our outputting. Flush the remainder of the * output buffer and close the file before going to exit routine. * goclz: nop * * Directory for all user areas completed. If the multi-disk option * is enabled and selected, reset to the base user area and repeat * the directory for next drive on-line until we either exceed the * drives on line, or the BDOS shuts us down with a select or bad * sector error, which will be intercepted back to the exit module. * nxtdsk: movea.l #fndflg,a0 *get file found flag move.b (a0),d0 move.b #0,(a0) *clear file found flag for next drive cmpi.b #0,d0 bne ndsk *continue if at least 1 file found move.b (a6),d0 *stash ascii directory drive addi.b #'A'-1,d0 *in no file message move.b d0,nofms2 jsr crlf movea.l #nofms1,a0 *print "no file on ? - " jsr print jsr prtfre *tag with free message ndsk: nop ifne dopt *if multi-disk option enabled movea.l #dopflg,a0 *if multi-disk not selected - skip next cmpi.b #0,(a0) bne nprt jsr ckabrt *check for user abort first addq.b #1,(a6) *bump directory fcb drive code cmpi.b #stskip,(a6) *skip if start skip bne next1 move.b #skipto,(a6) *if stskip then skipto next1: cmpi.b #drvmax,(a6) *does next disk exceed maximum? ble noopt *search next disk if not endc *balance dopt nprt: nop *if no printer, fall through to exit ifne popt *now, check if printer is in use movea.l #popflg,a0 cmpi.b #0,(a0) *printer active? bne exit *no, just exit... move.w #listout,d0 move.b #cr,d1 *print a carriage return trap #bdos move.b #lf,d1 *and a line feed trap #bdos endc *popt bra exit *all done - exit to ccp * * Print "directory for.... * prdir: movea.l #linmsg,a0 jsr print jsr crlf jsr margin *set the margin prdir2: movea.l #totms1,a0 *print " Drive " jsr print movea.l a6,a0 *point to fcb move.b (a0),d1 add.b #'A'-1,d1 jsr type *output the drive code movea.l #totms2,a0 *print ", user " jsr print jsr typusr *output the user number prdir1: rts * * Print the user number of the directory in decimal * typusr: movea.l #newusr,a0 move.b (a0),d2 cmpi.b #10,d2 *if user no. > 9 print leading 1 blt dux move.b #'1',d1 jsr type subi.b #10,d2 *extract low digit of user no. dux: addi.b #'0',d2 *make it ascii move.b d2,d1 *and display it bra type * * Force new line on video and check for page pause * crlf: move.b #cr,d1 *send cr jsr type move.b #lf,d1 *send lf bra type *exit to caller from type * * Separate the directory output on a line with two spaces, * the delimiter, followed by two more spaces. * fence: jsr pspace jsr pspace move.b #delim,d1 *fence character jsr type *print it, fall into space move.b #space,d1 jsr type pspace: move.b #space,d1 *fall through to type * * Output character in d1 to console, and optionally to printer. * type: jsr type1 *send it to console andi.b #$7f,d1 *strip parity bit on character * * Test file output mode and skip to page pause test if not active. * ifne popt *if printer option movea.l #popflg,a3 *test printer flag cmpi.b #0,(a3) bne cheklf move.w #listout,d0 *setup list output call trap #bdos *print character if flag true endc cheklf: cmpi.b #lf,d1 *do we have a lf? bne typret *exit if not ifne nopt movea.l #nopflg,a3 *is the page pause function disabled? cmpi.b #0,(a3) beq typret *exit if so endc movea.l #lincnt,a3 *get line count move.b (a3),d0 addq.b #1,d0 *bump it cmpi.b #lps,d0 *are we at the end of the screen? blt noteos *skip if not move.l #eosmsg,d1 *else, display pause message move.w #pstring,d0 *..without checking for lfs trap #bdos jsr cinput *wait for character cmpi.b #break,d0 beq exit *abort on ^C move.b #0,d0 *reset line count noteos: move.b d0,(a3) *save new line count typret: rts *exit from type * * Output character * type1: move.w #wrchr,d0 trap #bdos *call conout via the bdos rts * * Print a string at a1 of length d2 * typeit: move.b (a1)+,d1 jsr type subq #1,d2 bne typeit rts * * Print string terminated with '$' character by character. * print: move.b (a0)+,d1 *get a character cmpi.b #'$',d1 *is it the end of the string? bne print1 rts *yes...return print1: and.b #$7f,d1 *no....strip parity bit jsr type *display it bra print *and loop back for another character * * Fetch character from console (without echo) * cinput: move.w #$ff,d1 move.w #dirio,d0 trap #bdos andi.b #$7f,d0 rts * * Check for a ^C or ^S entered from the keyboard. Jump to exit * if ^C...pause on ^S. * ckabrt: move.w #$fe,d1 *check status of keyboard move.w #dirio,d0 trap #bdos cmpi.b #0,d0 *any key pressed? bne get1 rts *no, return to caller get1: jsr cinput *get character cmpi.b #break,d0 *is it ^C? beq exit *if ^C then quit cmpi.b #xoff,d0 *is it ^S? beq get2 *yes, wait for another character rts *no, return to caller get2: jsr cinput cmpi.b #break,d0 *might be ^C beq exit *exit if ^C else fall thru & continue rts * * For file output mode, return to old user area and set dma for * the file output buffer. * setfop: nop ifne uopt or aopt movea.l #oldusr,a0 *get user number at startup clr.l d1 move.b (a0),d1 move.w #curusr,d0 trap #bdos *reset the old user number endc rts * * Move disk buffer dma to default buffer for directory search operations * and bdos media change routines. * setsrc: move.l a5,d1 move.w #setdma,d0 trap #bdos clr.l d1 rts * * Print the amount of free space remaining on the selected drive. * prtfre: clr.l d4 movea.l #freeby,a0 *get space left move.w (a0),d4 jsr decprt *print k free movea.l #totms6,a0 *print " free" bra print * * Compare two consecutive files for possible multiple extents * compr: move.l #11,d2 *compare fn, ft cmplp: move.b (a0)+,d0 andi.b #$7f,d0 move.b (a1)+,d1 andi.b #$7f,d1 cmp.b d1,d0 beq domor rts domor: subq #1,d2 bne cmplp rts * * Swap entries in the order table * swap: movea.l #order-4,a2 *table base mulu #4,d0 *index x 4 move.l d0,a0 adda.l a2,a0 *+ base mulu #4,d1 *index x 4 move.l d1,a1 adda.l a2,a1 *+ base move.l (a0),d0 move.l (a1),d1 move.l d0,(a1) move.l d1,(a0) rts * * Compare routine - modified for filetype sort * compare: movea.l #order-4,a2 *table base mulu #4,d0 *index x 4 move.l d0,a3 adda.l a2,a3 *+ base move.l (a3),a0 mulu #4,d1 *index x 4 move.l d1,a4 adda.l a2,a4 *+ base move.l (a4),a1 * * Compare by filename, filetype, extent - in that order * cmpfnft: move.l #12,d2 *compare fn, ft, ex cmplpe: move.b (a0)+,d0 andi.b #$7f,d0 move.b (a1)+,d1 andi.b #$7f,d1 cmp.b d1,d0 beq domore rts domore: subq #1,d2 bne cmplpe rts * * Print a short help message * help: move.l #hlpmes,d1 move.w #pstring,d0 trap #bdos bra exit * * Error exit * erxit: jsr print *print first part of message movea.l #errms1,a0 *print " Error" jsr print jsr crlf *space down * * Exit - all done * exit: move.w #const,d0 *check console status trap #bdos cmpi.b #0,d0 *char waiting? beq exit1 *no...return to CP/M move.w #rdchr,d0 *otherwise... trap #bdos *gobble up char exit1: move.w #boot,d0 *..and return to CP/M trap #bdos * * Recovery point from intercepted bdos select and bad sector errors. * ifne dopt dskerr: bra exit *..and exit back to ccp endc * * calculate number of records in file * calcrec: mulu #8,d0 *convert extent count to records clr.l d1 movea.l #sectct,a0 *now add the # of records move.b (a0),d1 *in the final extent add.w d1,d0 *d0 now contains # of records move.w d0,numrec *save it in numrec and rts *...return * * Clear all data registers * clear: clr.l d0 clr.l d1 clr.l d2 clr.l d3 clr.l d4 clr.l d5 clr.l d6 clr.l d7 rts * * Indent left margin * margin: clr.l d2 movea.l #indent,a0 move.b (a0),d2 repeat: jsr pspace subq #1,d2 bge repeat rts * * Move d2 bytes from a1 to a0 * movmem: move.b (a1)+,(a0)+ subq #1,d2 bne movmem rts * * Save attribute flags * savatrb: movea.l a1,a2 move.b (a2)+,d0 *check RO/RW flag andi.b #$80,d0 move.b d0,rorw *save it in rorw move.b (a2)+,d0 *check Sys/Dir flag andi.b #$80,d0 move.b d0,sysdir *save it in sysdir move.b (a2)+,d0 *check Archive flag andi.b #$80,d0 move.b d0,arciv *save it in arciv rts * * Check for drivespec = logged drive and set fcb if it is * setdflt: cmpi.b #0,(a6) *is it the default drive? bne morchk *no....must check further rts *yes...return morchk: movea.l #olddsk,a4 *point to currently logged drive move.b (a4),d0 *put it in d0 addq.b #1,d0 *make it absolute cmp.b (a6),d0 *is it the same as the specified drive? beq mkdflt *yes...make the fcb contain a zero rts *no....return mkdflt: move.b #0,(a6) *first byte in fcb = 0 rts * *####################################################################### * Special DMA Parsing Subroutines *####################################################################### * * Check dma for user area specified as part of drive specification * parse: movea.l a5,a4 *point to dma move.b (a4),d7 *get length of command string cmpi.b #0,d7 *no command tail? beq finish move.b #1,d5 char1: adda #1,a4 *point to next character cmpi.b #space,(a4) *is it a space? bne gotch1 *no....mark its position addq #1,d5 *yes...bump position marker subq #1,d7 *1 less character remaining bne char1 *check next character rts *all done if no more characters gotch1: cmpi.b #'[',(a4) *is it a '['? beq finish *all done, no drive specified subq #1,d7 *dock characters remaining beq finish *all done if no more add.b d5,d6 *bump marker to next position colon: adda #1,a4 *now look for a ':' cmpi.b #':',(a4) *is it a ':'? beq gotcln *yes...mark its position cmpi.b #'[',(a4) *is it a '['? beq finish *all done, no drive specified addq #1,d6 *no...bump position marker subq #1,d7 *1 less character remaining beq finish *all done if no more characters bra colon *check next character gotcln: addq.b #1,d6 *increment marker one more time sub.b d5,d6 *compute their difference cmpi.b #1,d6 *is it 1? beq finish *yes...no rearrangement necessary try2: cmpi.b #2,d6 *is it 2? beq onedig *yes...it's a one digit user cmpi.b #3,d6 *is it 3? beq twodig *yes...it's a two digit user move.l #synerr,d1 *otherwise, we have an error move.w #pstring,d0 *say so and quit trap #bdos bra help onedig: suba #2,a4 *back up to drive designator move.b (a4)+,d0 *get drive designator move.b d0,drive *save it in drive move.b (a4)+,d0 *get user number move.b d0,tail+2 *save it move.b #']',tail+3 *append a ']' bra fixfcb *go fix up the fcb twodig: suba #3,a4 *back up to drive designator move.b (a4)+,d0 *get drive designator andi.b #upmask,d0 *make it upper case move.b d0,drive *save it in drive move.b (a4)+,d0 *get first digit of user number move.b d0,tail+2 *save it move.b (a4)+,d0 *get second digit of user number move.b d0,tail+3 *save it move.b #']',tail+4 *append a ']' fixfcb: subq #1,d7 *dock characters remaining beq stuff *no file name...go stuff the fcb movea.l #fname,a3 *point to file name storage buffer move.l #8,d2 *8 characters max getnam: adda #1,a4 *point to next character move.b (a4),d0 *get it cmpi.b #'[',d0 *is it a '['? beq stuff *yes...we have the whole file name cmpi.b #'.',d0 *is it a '.'? beq gettyp *yes...file type follows move.b d0,(a3)+ *save the character subq #1,d2 *dock file name char counter beq getdot *we have all 8 characters...strip '.' subq #1,d7 *dock characters remaining beq stuff *out of characters...go stuff the fcb bra getnam *go back for another character getdot: subq #1,d7 *dock characters remaining beq stuff *no more left...go stuff the fcb adda #1,a4 *otherwise point to next character move.b (a4),d0 *get it cmpi.b #'[',d0 *is it a '['? beq stuff *yes...go stuff the fcb cmpi.b #'.',d0 *is it a '.'? beq gettyp *yes...skip over it move.l #synerr,d1 *no....this is incorrect move.w #pstring,d0 *say so and quit trap #bdos bra help gettyp: subq #1,d7 *dock characters remaining beq stuff *no type given...go stuff the fcb movea.l #ftype,a3 *point to file type buffer move.l #3,d2 *3 characters max gettyp1:adda #1,a4 *point to next character move.b (a4),d0 *get it cmpi.b #'[',d0 *is it a '['? beq stuff *yes...we have the whole file type move.b d0,(a3)+ *save the character subq #1,d2 *dock file type char counter beq stuff *we have all 3 chars...go stuff fcb subq #1,d7 *dock characters remaining beq stuff *no more left...go stuff fcb bra gettyp1 *go back for another character stuff: movea.l #fname,a3 *parse file name and make move.l #8,d2 *upper case...also, expand '*' jsr wldfil *to a string of ?'s movea.l #ftype,a3 *parse file type and make move.l #3,d2 *upper case...also, expand '*' jsr wldfil *to a string of ?'s movea.l #drive,a1 *get drive designator subi.b #'A'-1,(a1) *make it a number move.l #12,d2 *finally, copy all to the fcb movea.l a6,a0 *point to fcb jsr movmem *and do the copy fixdma: movea.l a5,a0 *now see if we have any options move.b (a0),d7 *get character count move.b d7,d6 *save it in d6 lbrak: addq #1,a0 *point to next character cmpi.b #'[',(a0) *is it the delimiter? beq gotlb *yes...exit this loop subq #1,d7 *dock counter beq nolb *no options specified bra lbrak *go back for another character gotlb: subq #1,d7 *dock counter beq nolb *funny case...but add tail anyhow rbrak: adda #1,a0 *point to next character cmpi.b #']',(a0) *is it ']'? beq adtail *yes...go add the tail subq #1,d7 *no....dock the counter beq adtail *out of chars...add the tail bra rbrak *go back for another character adtail: movea.l #tail+1,a1 *point to user spec without '[' move.l #5,d2 jsr movmem *and copy tail to dma addi.b #4,d6 *adjust for the 4 characters appended move.b d6,(a5) *copy adjusted character count to dma rts nolb: movea.l #tail,a1 *point to user spec with '[' move.l #6,d2 jsr movmem *and copy tail to dma addi.b #5,d6 *adjust for the 5 characters appended move.b d6,(a5) *copy adjusted character count to dma finish: rts * * Parse file name or type, make upper case and expand * to trailing ?'s * wldfil: move.b (a3),d0 cmpi.b #'*',d0 beq qmfill subq #1,d2 bne upper rts upper: cmpi.b #'a',d0 blt wldnxt andi.b #upmask,d0 move.b d0,(a3) wldnxt: adda #1,a3 bra wldfil qmfill: move.b #'?',(a3)+ subq #1,d2 bne qmfill rts * *####################################################################### * Time and Date Stamping Subroutines *####################################################################### * * Carry date/time stamp forward for multiple extent file * carry: adda #2,a1 *make a1 point to date stamp adda #2,a0 *make a0 point to blank date stamp move.l #4,d2 *copy the date stamp jsr movmem *from a1 to a0 rts * * Check for time and date stamps * chkstmp:nop ifne trs80 movea.l #trkoff,a0 *determine the directory track movea.l #trakno,a1 *number and put it in #trakno clr.l d3 move.w (a0),d3 move.l d3,(a1) jsr strack *position head at the start jsr ssector *of the directory track jsr dmaset *set dma address jsr rsector *and read the first sector cmpi.b #1,d0 *any errors? bne readok movea.l #direrr,a0 *say so and quit on error bra erxit readok: movea.l #biosdma,a0 *check for stamping marker cmpi.b #marker,96(a0) *is directory properly formatted? bne noton *if not, date stamping not enabled move.b #$20,stampon rts endc noton: move.b #0,stampon rts * * Set dma address for bios calls * dmaset: move.w #calbios,d0 move.l #dmabpb,d1 trap #bdos rts dmabpb: dc.w 12 *set dma address bios parameter block dc.l biosdma *use special dma for bios calls dc.l 0 * * Read a sector * rsector: move.w #calbios,d0 move.l #rsbpb,d1 trap #bdos rts rsbpb: dc.w 13 *read sector bios parameter block dc.l 0 dc.l 0 * * Set track number * strack: move.w #calbios,d0 move.l #stbpb,d1 trap #bdos rts stbpb: dc.w 10 *set track bios parameter block trakno: dc.l 1 *default track = 1 dc.l 0 * * Set sector number * ssector: move.w #calbios,d0 move.l #ssbpb,d1 trap #bdos rts ssbpb: dc.w 11 *set sector bios parameter block sectno: dc.l 0 *default sector = 0 dc.l 0 * * Display date and time on the console * display: clr.l d6 *put number of days since 1/1/78 clr.l d7 *into register d7 movea.l #date1,a1 *point to date move.b (a1)+,d6 *low order byte -> d6 move.b (a1),d7 *high order byte -> d7 mulu #$100,d7 *multiply by $100 add.w d6,d7 *d7 now contains 16-bit # of days cmpi.w #0,d7 *is the file time/date stamped? beq nostamp *no...then display blanks jsr year *determine year jsr month *determine month moveq.l #10,d3 *make base 10 decimal move.l d4,d0 *get the month jsr prtdec0 *make it decimal and print it move.b #'/',d1 *insert a '/' jsr type move.l d5,d0 *get the day jsr prtdec *make it decimal and print it move.b #'/',d1 *insert a '/' jsr type move.l d6,d0 *get the year jsr prtdec *make it decimal and print it move.b #space,d1 *insert a space jsr type moveq.l #$10,d3 *make base 10 hexadecimal movea.l #hour,a0 *get the hour move.b (a0),d0 jsr prtdec0 *make it decimal and print it move.b #':',d1 *insert a ':' jsr type movea.l #min,a0 *get the minutes move.b (a0),d0 jsr prtdec *make it decimal and print it rts nostamp: movea.l #blnkdt,a0 *print blanks if not time/date stamped jsr print rts * * Convert from binary to hexadecimal * binhex: clr.l d2 divu #$10,d1 move.w d1,d2 mulu #10,d2 clr.w d1 swap d1 add.w d2,d1 rts * * Convert from hexadecimal to binary * hexbin: clr.l d2 divu #10,d1 move.w d1,d2 mulu #$10,d2 clr.w d1 swap d1 add.w d2,d1 rts * * Move today's date from tdate to date1 * loadtd: move.l #4,d2 movea.l #tdate,a1 movea.l #date1,a0 jsr movmem rts * * Determine month * month: moveq.l #1,d4 *initialize month register move.l d7,d0 *get number of day in current year move.l d0,d1 move.l #feb,a2 *point to number of days in February add.w d5,(a2) *adjust for leap year move.l #jan,a2 *point to number of days in January findmo: sub.w (a2)+,d1 ble donem *quit if this is the month addq #1,d4 *otherwise...increment month number move.w d1,d0 bra findmo *and repeat until month is determined donem: move.w d0,d5 *save day of current month in d5 rts * * Convert to decimal and display * prtdec: divu d3,d0 *divide by base move.w d0,d1 *put tens digit in d1 swap d0 move.w d0,d2 *put units digit in d2 addi.b #48,d1 *make tens digit ascii jsr type *and display it move.w d2,d1 *get units digit addi.b #48,d1 *make it ascii jsr type *and display it rts * * Convert to decimal and display, substituting space for * leading zero * prtdec0: divu d3,d0 *divide by base move.w d0,d1 *put tens digit in d1 swap d0 move.w d0,d2 *put units digit in d2 cmpi.b #0,d1 *is the tens digit zero? beq prtspc *yes...print a space addi.b #48,d1 *no....make tens digit ascii bra cont prtspc: move.b #space,d1 cont: jsr type *and display it move.w d2,d1 *get units digit addi.b #48,d1 *make it ascii jsr type *and display it rts * * Get today's date and time by reading the number of days since * January 1, 1978 from the CP/M Plus System Control Block * today: move.l #$daf4,d1 *Z80 address of low order date byte jsr readz80 *read it into d1 movea.l #tdate,a3 move.b d1,(a3)+ *save it in tdate move.l #$daf5,d1 *Z80 address of high order date byte jsr readz80 *read it into d1 move.b d1,(a3)+ *save it in tdate+1 move.l #$daf6,d1 *Z80 address of hour jsr readz80 *read it into d1 move.b d1,(a3)+ *save it in tdate+2 move.l #$daf7,d1 *Z80 address of minutes jsr readz80 *read it into d1 move.b d1,(a3) *save it in tdate+3 clr.l d0 *clean up registers clr.l d1 clr.l a0 clr.l a1 rts * * Read a byte of Z80 memory * readz80: swap d1 *put Z80 address in upper word move.w #z80r,d0 *and call special function trap #bios *through the BIOS rts * * Determine year * year: clr.l d1 clr.l d5 moveq.l #78,d6 *base year is 1978 move.l d7,d0 *get number of days since 1/1/78 divu #1461,d0 *home in on 4-year interval (1461 days) move.w d0,d1 mulu #4,d1 add.w d1,d6 *adjust year for 4-year interval base * swap d0 *now examine the remainder move.w d0,d1 cmpi.w #0,d1 *see if it's December 31 bne not1231 *if not...continue move.w #365,d0 *if so...adjust subq #1,d6 bra doney * not1231:subi #365,d1 *subtract 365 days ble doney *negative or zero => this is the year addq #1,d6 *otherwise add 1 to year move.w d1,d0 *save remaining number of days * subi #365,d1 *subtract another 365 days ble doney *negative or zero => this is the year addq #1,d6 *otherwise add 1 to year move.w d1,d0 *save remaining number of days * move.b #1,d5 *set the leap-year flag subi #366,d1 *subtract 366 days (leap year) ble doney *negative or zero => this is the year addq #1,d6 *otherwise add 1 to year clr.l d5 *reset the leap-year flag move.w d1,d0 *save remaining number of days * doney: move.w d0,d7 *save day of year in d7 rts *####################################################################### * * End of program code * * Initialized data area * even jan: dc.w 31 feb: dc.w 28 mar: dc.w 31 apr: dc.w 30 may: dc.w 31 jun: dc.w 30 jul: dc.w 31 aug: dc.w 31 sep: dc.w 30 oct: dc.w 31 nov: dc.w 30 dec: dc.w 31 blnkdt: dc.b ' $' direrr: dc.b cr,lf,'Directory Read$' dremsg: dc.b cr,lf,'Drive Specification$' eosmsg: dc.b ' Press ANY KEY to continue',cr,'$' errms1: dc.b space errms2: dc.b 'Error$' nofms1: dc.b 'No Matching Files on Drive ' even nofms2: dc.b ' : $' datmsg: dc.b tab,tab,tab,tab,' Date: $' dirms1: dc.b 'Directory for $' linmsg: dc.b '----------------------------------------' dc.b '---------------------------------------$' totms1: dc.b 'Drive $' totms2: dc.b ': User $' totms3: dc.b ' contains $' totms4: dc.b 'k in $' totms5: dc.b ' files with $' totms6: dc.b 'k free',cr,lf,lf,'$' usrmsg: dc.b cr,lf,'User Number$' ro: dc.b ' RO' rw: dc.b ' RW' sys: dc.b ' Sys' dir: dc.b ' Dir' arc: dc.b ' Arc' nonarc: dc.b ' ' even drive: dc.b 0 *drive fname: dc.b ' ' *file name ftype: dc.b ' ' *file type tail: dc.b '[U',0,0,0,0 *dma tail (for user number) synerr: dc.b cr,lf,lf,' Syntax Error ','$' * * Option field lookup table. * Note that you can force any of these options as a default by * changing the letter for the option into a zero (assuming that * its enabling equate is true). Each option that you hard-wire in * this manner will no longer be recognized as a command line option, * and if you redundantly key it in, SD will flag it as unrecognized. * otbl equ * *mark start of option table ifne aopt *all users-option flag aopflg: dc.b 'A' endc ifne dopt *multi-disk-option flag dopflg: dc.b 'D' endc ifne nopt *no page-pause option flag nopflg: dc.b 'N' endc ifne ropt *unarchived file option flag ropflg: dc.b 'R' endc ifne popt *printer option flag popflg: dc.b 'P' endc ifne sopt *system file option flag sopflg: dc.b 'S' endc oend equ * *mark end of option table * * End of option lookup table * even lincnt: dc.b 0 *count of lines printed on screen fndflg: dc.b 0 *flag whether any files matched gotusr dc.b 0 indent dc.b margsz *size of left margin mlps dc.b lps *lines per screen (between pauses) mnpl dc.b npl *names per line (# of columns) * hlpmes: dc.b cr,lf,lf dc.b 'Correct usage: SD {d}{u}:{filename.typ} ' dc.b '[option,option...]' dc.b cr,lf,lf,'d = Drive, u = User and filespec are optional' dc.b cr,lf,'Wildcards * and ? are supported' dc.b cr,lf,lf,'Options available are:',cr,lf dc.b cr,lf,tab,'[A]...All users ' dc.b tab,'[P]...Printed output' dc.b cr,lf,tab,'[D]...all Drives' dc.b tab,'[R]...unaRchived files' dc.b cr,lf,tab,'[N]...No paging ' dc.b tab,'[S]...System files',cr,lf,lf,'$' * * Disk parameter block * even cdpb ds.w 1 *number of 128-byte sectors on disk blkshf ds.b 1 *Block shift factor..# shifts to mult by sec/blk blkmsk ds.b 1 *Block mask...sec/blk - 1 exmsk ds.b 1 *Extent mask res168k ds.b 1 *Reserved byte blkmax ds.w 1 *highest block # on drive dirmax ds.w 1 *highest file # in directory res268k ds.w 1 *Reserved word cks ds.w 1 *length of checksum vector trkoff ds.w 1 *Track offset to disk directory * biosdma:ds.b 128 * * Uninitialized data area * basusr ds.b 1 *dupe of original directory user # to search colcnt ds.b 1 *column count count ds.w 1 *entry count freeby ds.w 1 *contains number of k left on directory drive gap ds.w 1 *sort routine storage i ds.w 1 *sort routine storage j ds.w 1 *sort routine storage jg ds.w 1 *sort routine storage maxusr ds.b 1 *maximum user # for drive from lookup table newusr ds.b 1 *contains user number selected by "U" option nextt ds.l 1 *next table entry olddsk ds.b 1 *holder for currently logged-in drive oldusr ds.b 1 *contains user number upon invocation scount ds.w 1 *# to sort supspc ds.b 1 *leading space flag for decimal routine tbloc ds.l 1 *pointer to start of name table tcount ds.w 1 *temporary file count temp ds.w 1 *save dir entry totfil ds.w 1 *total number of files totsiz ds.w 1 *total size of all files rorw ds.b 1 *RW/RO flag sysdir ds.b 1 *Sys/Dir flag arciv ds.b 1 *Archive flag stampon ds.b 1 *Date/time stamp flag tdflag ds.b 1 *FCB number flag tdate ds.b 4 *Today's date and time date1 dc.b 0 *1st byte of date from CP/M Plus SCB date2 dc.b 0 *2nd byte of date from CP/M Plus SCB hour dc.b 0 *hour from CP/M Plus SCB min dc.b 0 *minute from CP/M Plus SCB leapyr dc.b 0 *leap year flag yearda dc.w 0 *number of the day of the year extno ds.b 1 *extent number sectct ds.b 1 *sector count of last extent even numrec ds.w 1 *number of records in file order equ * *order table starts here *####################################################################### end