Title 'Time stamp vers: 03.11 date: 10/11/83 time: 22:37:17' ;************************ ; * ; timestamp3 * ; * ; version, date & time * ; stamp * ; for cp/m+ * ; * ;************************ ; by dick lieber - Bridgeport RCP/M+ (Chicago) 312-326-4392 ; based on a program by Eric Forbes ; ; version 3.12 fix leap year bug rcl ; version 3.11 fix wrong data for July & Nov in months table ; version 3.1 don't abort if file not found so a new file ; can be created with editor. ; ; if assembled as a transient program ; ; A>ts3 name.typ [o] ; ; Will increment the minor version number & date/time stamp the file ; name.typ if the strings: ; ; "vers:" ; "time:" ; "date:" ; ; are found in the first 128 bytes of the file. Be sure ; to allow enough blank space after each string for the ; information shown! ; ; [o] is an option: ; ; where o=N to leave old version number ; o=M to increment major version number ; and zero minor version number ; ; if assembled as a patch and SIDed onto an editor ; the same functions will take place automatically ; before the actual edit: ; ; A>edit name.typ [o] ; ; an additional option is added with the patched version: ; ; [z] will cause the timestamp patch to not modify the ; file at all ; ; To attach the patched version of timestamp: ; ; A>mac ts3 <= assemble "patched" version ; CP/M MACRO ASSEM 2.0 ; 2B2E ; 024H USE FACTOR ; END OF ASSEMBLY ; A>sid ws.com <= load your editor ; CP/M 3 SID - Version 3.0 ; NEXT MSZE PC END ; 2700 2700 0100 CEFF ; #rts3.hex <= load ts3 patch ; NEXT MSZE PC END ; 2B2E 2B2E 0100 CEF <= note the NEXT address ; #wwsts.com,100,2b2e <= save patched editpor ; 0055h record(s) written. ; #^C ; Use and enjoy you new editor that automatically ; updates version etc. ; maclib z80 ;as supplied with cp/m+ no: equ 0 yes: equ not no patched: equ yes ;yes to attach to an editor ;no to make transient command opt$del: equ '[' ;option delimiter recsiz: equ 128 ;record length cr: equ 0dh lf: equ 0ah bell: equ 7 if patched ;into an editor ; ; these equates define interface of ; this program to the editor ; ; values show are for Wordmaster endasm: equ 2700h ;where this program will live oldjmp: equ 269h ;used to restore the jump at the ;start of the assembler jmpadd: equ 0100h ;address of the JP (C3h) used to get ;to this program assemb: equ 0100h ;address to return to when finished ;updating the file ; ; this will patch the hook from the editor ; to this porgram. it gets restored automatically ; when when version info has been updated ; org jmpadd + 1 dw endasm ;patch hook to this program else endasm equ 100h ;org if stand alone fcb equ 5ch ;work at default fcb cause ;we don't care if it's altered endif org endasm ;end of assembler or tpa start: lxi d,crlf mvi c,prstr ;new line call bdos ; ; check version ; mvi c,getvers call bdos lxi d,bad$ver$mess mov a,h cpi 1 ;check if mp/m jrz version$ok mov a,l cpi 31h jc exit ;below cp/m+ version$ok: if patched ;into an editor ; ; copy name to timestamp's fcb ; lxi h,5ch ;default fcb set up by ccp lxi d,fcb lxi b,15 ;length of drive & name ldir ;move it endif ;patched ; ; copy password to dma ; lda 53h ;get password length ora a ;set flags jrz no$password mov c,a ;get length of password mvi b,0 lhld 51h ;get password address (source) lxi d,buff ;(dest) ldir ;move password to dma ;password must be in dma ;on open call if file is ;read protected no$password: mvi a,' ' ;no option sta option lda 80h ;get command tail length mov c,a mvi b,0 lxi h,81h ;start of tail dad b ;point to end of tail mvi a,opt$del ccdr ;search for delimeter jpo option$done inx h! inx h ;point to option byte mov a,m sta option cpi 'N' ;keep old version option jrz option$done cpi 'M' ;major version update option jrz option$done if patched cpi 'Z' ;no change at all option mvi a,0 ;no abort lxi d,as$is$msg jz exit endif ;patched lxi d,bad$opt$msg mvi a,0ffh ;abort flag jmp exit option$done: ; ; open file ; lxi d,buff mvi c,setdma call bdos lxi d,fcb mvi c,15 call bdos lxi d,nofile ;report if can't open and inr a if patched mvi a,0 ;reset abort flag else mvi a,0ffh ;set abort flag endif jz exit ; ; zero record number ; lxi h,fcb+33 mvi b,2 rn$loop: mvi m,0 dcr b inx h jrnz rn$loop lxi d,fcb mvi c,readran ;read record 1st record (0) call bdos lxi d,verstx call find ;update version lxi d,novers cnz print cz versn lxi d,datetx call find ;update date lxi d,nodate cnz print cz date lxi d,timetx call find ;update time lxi d,notime cnz print cz time ; ; write record back into file and exit to editor or CP/M ; mvi c,writeran ;random write lxi d,fcb call bdos mvi c,closef lxi d,fcb call bdos lxi d,done$msg exit: call print ;print error message and exit. ora a ;a=ff means abort after message jnz 0 ;abort if error if patched ;into editor ; ; Restore the editor to it's original condition and jump to it ; lxi h,oldjmp ;restore value in hl shld jmpadd+1 ;restore old jump address jmp assemb ;jump to the assembler else ret ;to cp/m+ endif ;patched ; ; print a string (de) and file name ; print: push psw mvi c,prstr call bdos lxi h,fcb+1 lxi d,prtnam lxi b,11 ldir lxi d,prtfil mvi c,prstr call bdos pop psw ret ; ;Increment the version number ; versn: inx h ;hl --> units of major change lda option ;is a major change requested cpi 'M' cz twoinc ;inc major change number jrz zeromn ;zero minor change number cpi 'N' ;do not change version if rz ;'n' option given inx h inx h inx h ;hl --> units of vers no. twoinc: push psw ;increment a 2 digit field push h mvi b,2 mvi a,'9'+1 ;hl --> units position two1: inr m cmp m jrnz twox ;exit if not > 9 ascii mvi m,'0' ;else zero the units dcx h ;and inc the tens djnz two1 twox: pop h pop psw ret zeromn: inx h ;zero minor version inx h mvi m,'0' ;used when major changes inx h mvi m,'0' ret ; ; insert new date into buffer at hl ; date: call get$clock push h lhld datepb ;get days since 1/1/78 call cnvday ;convert to month,day, year pop h lda months call putbcd mvi m,'/' inx h lda days call putbcd mvi m,'/' inx h lda years call putbcd ret ; ; convert bcd in a to two ascii charcters at hl ; putbcd: push psw rrc ! rrc ! rrc ! rrc ;get high nibble call putnib pop psw call putnib ret ; ; make ascii & put into buffer ; putnib: ani 0fh ori '0' mov m,a inx h ;next buffer location ret ; ; insert time into buffer at hl ; time: call get$clock lxi d,datepb+2 ;point to seconds byte sta datepb+4 ;put seconds in date parm block mvi b,2 time1: ldax d inx d call putbcd ;insert hh:mm: mvi m,':' inx h djnz time1 ldax d call putbcd ;insert seconds ret ; ; get time from cp/m+ ; get$clock: push h ; ; this bios call is needed because the bdos rdtime ; function doesn't call bios to update the clock data ; in the scb ; mvi c,drbios ;direct bios call lxi d,biospb ;read time function call bdos mvi c,rdtime ;get date/time lxi d,datepb ;where to put date call bdos pop h ret biospb: db 26 ;time function db 0 ;value for A ; ; find the first character of string in de (V, D or T) ; find: lxi h,buff ;de = compare string lxi b,recsiz ;limit search to 1 rec trynxt: ldax d ;get 1st char to find ccir rpo ;ret nz set = not found ; ; see if the rest of the string compares equal. Retry ; until we get to the end of the buffer ; push b push d mvi b,5 ;compare next 5 chars find2: inx d ldax d cmp m jrnz tryagn ;try for another string inx h djnz find2 ;keep comparing til b = 0 pop d pop b ret ;ret with z set tryagn: pop d ;Found the 1st character, but pop b ;there was a bad compare in jr trynxt ;the next 6 characters. ;************************************************ ; * ; cnvdate * ; * ; routine to convert cp/m or mp/m date * ; from days since 1/1/78 to month, day & * ; year. * ; * ; * ;************************************************ ; ; year equ 365 ;leap year gets adjusted for ; ; count up until goal days exceeded ; cnvday: shld goaldays ;save as goal to reach mvi a,1 ;initial values sta days sta months ;month counter (jan is one) lxi h,0 shld dayscnt ;start at zero lxi d,year ;one year of days mvi a,78h ;the first year (bcd) sta years ;save year value ; ; it's much eaiser to detect leap years in binary ; mvi a,78 ;1st year (binary) sta years$bin ;for leap year determination yearloop: lhld dayscnt dad d ;trial add one year of days call ckleap jrnz no$leap inx h ;was a leap year no$leap: call ckgoal jnc yeardone ;year over flowed lda years cmc ;daa screws up if carry is set inr a ;add one to the year count daa ;make bcd sta years ;save years jz done ;exact match shld dayscnt ;year was ok to add lxi h,years$bin inr m jr yearloop ; yeardone: ; ; see if this is a leap year and adjust Feb if required ; call ckleap lxi h,feb ;point to feburary mvi m,28 jrnz not$leap ;no, don't adjust feb inr m ;make 29 not$leap: lxi d,montbl ;point to month table monthloop: lhld dayscnt ldax d ;get month mov c,a mvi b,0 dad b call ckgoal jnc monthdone push psw cmc lda months inr a ;count to next month daa sta months pop psw jrz done ;exact (on the first of the month) shld dayscnt inx d ;point to next month jr monthloop monthdone: ; ; continue counting until day of month attained ; lhld dayscnt daysloop: inx h ;add one day call ckgoal jnc done cmc ;zero carry bit so daa is screwed up lda days inr a daa sta days jr daysloop done: ret ;leave module ; ; compare count (in hl) with goal ; C if count < goal ; Z if count = goal ; ckgoal: push d lded goaldays mov a,h cmp d jrnz ckend mov a,l cmp e ckend: pop d ret ; ; check for leap year ; return z if leap year ; ckleap: lda years$bin ;get years ani 03h ret montbl: db 31 ;jan feb: db 28 ;feb db 31 ;mar db 30 ;apr db 31 ;may db 30 ;jun db 31 ;jul db 31 ;aug db 30 ;sep db 31 ;oct db 30 ;nov db 31 ;dec ; dseg ; ; these values are the output of this module ; days: ds 1 ;counts days in month (bcd) months: ds 1 ;counts months in year (bcd) years: ds 1 ;counts years (starts at 78) (bcd) ; ; cnvdays ram area ; years$bin: ds 1 ;years in binary (for leap year calc) dayscnt: ds 2 ;counts days goaldays: ds 2 ;days since 1/1/78 done$msg: db 'Version Update$' nofile: db 'File not found$' novers: db 'No ' verstx: db 'vers: ' db 'in$' nodate: db 'No ' datetx: db 'date: ' db 'in$' notime: db 'No ' timetx: db 'time: ' db 'in$' crlf: db cr,lf,'$' if patched ;transient version uses def fcb fcb: db 0 rept 35 db 0 endm endif option: ds 1 ;saved option byte buff: rept recsiz ;fill with blanks so password db ' ' ;is set in blanks endm prtfil: db ' File:- ' prtnam: db ' ',cr,lf,lf,'$' datepb: ds 5 ;date parameter block bad$ver$mess: db 'Requires CP/M version 3', cr, lf, '$' bad$opt$msg: db 'Bad timestamp option.',cr,lf db 'Options are:',cr,lf db 9,'[N] for no version update.',cr,lf db 9,'[M] to increment major version.',cr,lf if patched db 9,'[Z] to not alter version or timestamping',cr,lf endif db '$' if patched as$is$msg: db 'Version & time unchanged.',cr,lf,'$' endif ; ; bdos functions (cp/m 3.0) ; bdos equ 5 sysrst equ 0 ;warmstart rdcon equ 1 ;wait for & read console character wrcon equ 2 ;write to console rdaux equ 3 ;wait for & read aux wraux equ 4 ;write to aux list equ 5 ;write to list device drcon equ 6 ;direct console i/o character or ; ff=read ; fe=status only ; fd=wait for input auxinst equ 7 ;aux in status auxotst equ 8 ;aux out status prstr equ 9 ;de=string rdbuff equ 10 ;de=buffer max, count, c1,c2,... const equ 11 ;console in status getvers equ 12 ;return version in HL dskrst equ 13 ;reset disk system seldsk equ 14 ;select disk 0=a: openf equ 15 ;open file de=fcb closef equ 16 ;close file searchf equ 17 ;search for first occurance searchn equ 18 ;find next occurance delete equ 19 ;delete file read equ 20 ;read sequential write equ 21 ;write sequential make equ 22 ;make file rename equ 23 ;rename file new name at fcb+16 loginv equ 24 ;return login vector in hl curdsk equ 25 ;return current disk in a setdma equ 26 ;set new dma getalv equ 27 ;get allocation vector address wrtprt equ 28 ;write protect current disk rovec equ 29 ;get r/o vector in hl setflag equ 30 ;set file attributes getdpb equ 31 ;return dpb address user equ 32 ;get/set user ff=get readran equ 33 ;read random record writeran equ 34 ;write random record flsize equ 35 ;compute file size setran equ 36 ;set random record from last sequential read rstdrv equ 37 ;reset drive accdrv equ 38 ;mpm only - access drive freedrv equ 39 ;mpm only - free drive wrran0 equ 40 ;fill a random record with 0 tstwrt equ 41 ;mpm only - test and write lock equ 42 ;mpm only - lock record unlock equ 43 ;mpm only - unlock record multi equ 44 ;set multi sector count errmd equ 45 ;set bdos error mode freesp equ 46 ;return free space in 1st 3 bytes of dma chain equ 47 ;chain to pgm name in def buff (80h) flush equ 48 ;flush buffers scb equ 49 ;get set scb de=.scb pb db offset ; db ffh set byte ; feh set word ; 00h get ; dw value drbios equ 50 ;direct bios call de=.bios pb db bios func # ; db = A ; dw =BC ; dw =DE ; dw =HL ldovl equ 59 ;load overlay calrsx equ 60 ;call rsx de=.rsx pb db rsx func # ; db # of word parameters ; dw p1 ; dw p2 frblks equ 98 ;free temporary blocks trunf equ 99 ;truncate file setdirl equ 100 ;set driectory label dirl equ 101 ;return directory label data e=drive rdstamp equ 102 ;read file stamps & password mode wrxfcb equ 103 setdate equ 104 rdtime equ 105 defpwd equ 106 ;set def password retsn equ 107 ;return serial number address retcode equ 108 ;get/set return code conmode equ 109 ;get/set console mode delim equ 110 ;get/set string output delimiter prtblk equ 111 ;print block de = ccb dw=address ; dw=length lstblk equ 112 ;list block parse equ 152 ;parse file name de=pfcb dw=input addr ; dw=fcb addr end length lstblk equ 112 ;list block parse equ 152 ;parse file name de=pfcb dw=input a