O? $X;save#d:MDOS2.M65 MYDOS module9X; Copyright 1984, Charles Marslett, Wordmark SystemsX;(IX; Permission is granted by the author for any use whatsoever of this2HX; code, so long as this notice remains in the source code, and so<LX; long as the source to this routine, however modified or unmodified,F.X; is made available for a nominal cost.PX;ZX; DISK OPEN ROUTINEdX;n'DKOPEN WBITMP;;fix that nasty bug!x( SETUP;;SET UP BUFFER POINTERS, ETC.2 GETFNM;;GET DRIVE ID OR FILE NAME FROM BUFFER'QICAX1Z;;GET TYPE OF OPEN FROM IOCB PFCBOTC9!M>;;TEST DIRECTORY READ FLAG FDKOPN13!LSTDIR;;IF SET, GO HANDLE DIRECTORY FORMATTINGX;DKOPN1PSAVSEC9PSAVSEC9;;ZERO SAVSEC SFDIR6;;SAVE STATUS RETURNED EOPNEW*Q>;;MAKE SURE THIS IS NOT A DIRECTORY GETFLAG4HDIROPN;;IF A DIRECTORY, GO HANDLE IT SEPERATELYOPNEW%ICAX1Z")>,FOPNOP;;IF OPEN FOR OUTPUT6)>@FOPNIN;;IF OPEN FOR INPUTJ)> T+FOPNUP;;IF OPEN FOR READ/WRITE (UPDATE)^)> hFOPNAP;;IF OPEN AND APPENDr.DIROPN!ERRCMD;;OTHERWISE, IT IS AN ERROR!|X;OPNAP8;;OPEN APPEND EOPNCR0 TSTLOK- INITYP;;READ ALL THE SECTORS IN THE FILEQDIRBUF8 PSECCNT9QDIRBUF8PSECCNT9APPRD RDNXTS$DAPPRD;;IF NOT EOF, READ ANOTHER QMAXLEN9# LENSET;;SET LENGTHS FOR OUTPUT QSECCNT9 HSGLDEC"SECCNT9/SGLDEC"SECCNT9;;ALLOW FOR SECTOR REWRITTEN& !OPOUTX0X;: OPNUP8;;OPEN UPDATE (OUTPUT)D EOPNER1N TSTLOKXOPNOWR INSTRTb !DONElX;vOPNIN8;;OPEN INPUT DOPNOWROPNER1Q>;;FILE NOT FOUND GEROXITX; OPNOP8;;OPEN (NORMAL) OUTPUT EOPNCR REMOVE !GET1STX;OPNCR0"FCBOTC9OPNCRQHOLFN PCURFNO GOPDIRFGET1ST ALLOC X;$QICAX2Z;;IF OUTPUT, TYPE OF FILE "M>$;;SAVE LOCKED & FORMAT BITS*1N>C;;MERGE IN DEFAULT CODE (DOS II, UNLOCKED)4%MAPBUF;;WHICH TYPE DISK?>)>;;IF >2 THEN MYDOSH DLLINKSRL>\X;f LLINKS5p. RDCFNO;;SELECT PROPER SECTOR IN DIRECTORYz; ENTNAME;;ENTER NAME INTO ITQLNKSEC9PDIRBUF8 QLNKSEC9PDIRBUF87 SAVFLAG INITYP TONXTOPOUTXQ> PFCBFLG9! TSTDOS;;FILE NAME = DOS.SYS? HJDONE %CURSEC9QCURSEC9' SETDOS;;IF SO, UPDATE BOOT SECTORS$X;. QDOSAD8 PFMSZPGB QDOSADLPFMSZPGV0HOWTDOS;;NOTE: DOS CANNOT START ON ZERO-PAGE`X;jOPDIRFQ>tEROXIT!AEXIT~X;3LWTDOS WRNXTS;;AUTOMATICALLY WRITE DOS.SYS OUT/OWTDOS%>;; IF WE OPEN IT FOR WRITE (THIS5CDOSBFQ@FMSZPG7;; IS BECAUSE DOS 2.0 WOULD BLOW1P@FMSBPT7;; ITSELF AWAY IF A REAL WRITE FROM&3;; THE DOS CODE WAS ATTEMPTED AND1)DLINK;; WE ARE GOING TO REMAIN COMPATIBLE). DCDOSBFC PCURLEN9 MVBUFR )DOSENDSDOSEND DLWTDOS JDONE!DONEX;X; READ DATA FROM A FILE(X;2/DKREAD SETUP;;SET UP BUFFER POINTERS, ETC.< QFCBOTC9F&M>;;TEST THE DIRECTORY INPUT FLAGP!FRDFILE;;SO WE CAN HANDLE THEZ.!DIRRD;; SPECIAL CASE OF A DIRECTORY READdX;nRDFILEQCURLEN9x RMAXLEN9;DRDSGBT;;IF NOT AT SECTOR BOUND., READ A BYTE AT A TIME6ERDASNT;;ELSE, CHECK FOR READ MODE AND BUFFER SIZEX;RDASLPQICCOMZM>4FRDSGBT;;IF NOT BINARY I/O READ A BYTE AT A TIME %DLINK1?RDSCLPQ@FMSBPT7;;SIMULATED BURST I/O (USING UNROLLED LOOP) P@ICBALZ71 Q@FMSBPT7 P@ICBALZ71 Q@FMSBPT7 P@ICBALZ7"1, Q@FMSBPT76 P@ICBALZ7@1J HRDSCLPT0Q@FMSBPT7;;DATA AREA IS MULTIPLE OF 4 PLUS 1^ P@ICBALZ7h0 BUFADJ;;ADJUST BUFFER POINTER BY 125 OR 253r(RDASNT RDNXTS;;READ THE NEXT SECTOR|*ERETEOF;;REPORT EOF/ERROR IF NECESSARYQICBLLZ;;AND REPORT LAST BYTE IF IT IS SO! ,X;&)RETEOFQ>;;RETURN END OF FILE STATUS0 !AEXIT:X;DX; WRITE DATA TO A FILENX;X,DKWRITPDATBYT;;SAVE DATA BYTE (PERHAPS)b %ICDNO9l5'ICDNOZ;;INSURE ICDNOZ IS SET UP (BASIC DOES NOT)v. SETUPW;;SET UP REST OF FLAGS AND POINTERS QFCBOTC9M>8FCANTWR;;ERROR OUT IF WRITE IS ILLEGAL (BASIC AGAIN) QCURLEN9? RMAXLEN98DSKBURST;;SKIP AROUND IF NOT WRITING END OF A SECTORX;*WRASLP WRNXTS;;WRITE A SECTOR OF DATA,ERETEOF;;ERROR OUT IF NO MORE DISK SPACE %STKPSVQ8R>;;IF FROM BASICDBASWRT;;PASS SINGLE BYTES !QFCBOTC9;;fix open for updateM>;;bug in burst I/O  HBASWRT* QICCOMZ4M>;;AND IF RECORD I/O>FBASWRT;;PASS SINGLE BYTESH0%ICBLLZ;;AND IF THE BUFFER IS < 256 BYTESRFBASWRT;;PASS SINGLE BYTES\ %MAXLEN9f1p1WRSCLPQ@ICBALZ7;;ELSE DO SIMULATED BURST I/Oz$P@FMSBPT7;;BY UNROLLING THE LOOP1 Q@ICBALZ7 P@FMSBPT71 HWRSCLP-Q@ICBALZ7;;BUT ONLY 2 ENTRIES FOR WRITING P@FMSBPT7 BUFADJ Q@ICBALZ7 PDATBYT !WRASLPX;BASWRT%> SKBURSTQDATBYT #CURLEN9 P@FMSBPT7$ Q>@. :LFCBFLG9;;FOR UPDATE, SAY THE SECTOR HAS BEEN MODIFIED8 PFCBFLG9B HTODONE;;BRANCH ALWAYS!L X;V CANTWR!ERRCMD` X;j BUFADJ,t QMAXLEN9~ PCURLEN9 OICBALZ PICBALZ DRBAOK #ICBALZ RBAOK; QICBLLZ SMAXLEN9 PICBLLZ ERBLOK "ICBLLZ RBLOK: X; X; RETURN FILE STATUS X; .DKSTAT SETUP;;SET UP RETURN ADDRESS, ETC. ( LFFILE;;FIND IF FILE IS THERE, ETC.(  TSTLOK;;IS IT LOCKED?2 "TODONE!DONE;;RETURN TO CALLER< X;F -X; CLOSE FILE (WRITING ANY PENDING SECTOR)P X;Z DKCLOS SETUPd QFCBOTC9n M>;;OUTPUT ALLOWED?x FCLROTC;;IF NOT, JUST EXIT UFCBFLG9 DCKFLSC $ REWRIT;;REWRITE THE LAST SECTOR RRDIR QSECCNT9 %DIRDSP PDIRBUF8 QSECCNT9 PDIRBUF8 QDIRBUF8 %M>;;NOT OPEN FOR OUTPUT ANY MORE SAVFLAG QSAVSEC9 LSAVSEC9 FCLROTC (LSTIOCB" FFAPPD, ' INITYP;;READ ALL THE SECTORS AGAIN6 APPLP RDNXTS@ DAPPLP;;NOT EOF YETJ ETIELNKT FAPPDQLSTSEC^ PCURSEC9h QLSTSECr PCURSEC9| TIELNK, RWDISK QDLINK PCURLEN9 QSAVSEC9 %SAVSEC9 SAVLNK CLROTEICLROTC "Q>;;FAILURE IS A SYSTEM ERROR !AEXIT CLROTCQ> PICHID9 Q> PFCBOTC9 !FREDON X; CKFLSCUFCBFLG9& DCLROTC0 WRDISK: !CLROTED X;N INITYPQ>X GETFLAGb V?l W?v W? W? LFCBOTC9 PFCBOTC9 QDIRBUF8 PLNKSEC9 QDIRBUF8 PLNKSEC9 QCURFNO PFCBFNO9 Q> PFCBFLG9 PCURLEN9 PSECCNT9 PSECCNT9 : X; X; DOS XIO ROUTINES* X;4 X;> LX; Sorry about the lack of comments in this file and some of the others,H HX; I just never had to figure this code out after I wrote it (:-)!R X;\ $NODIRFQ>;;FILE NOT A DIRECTORYf !AEXITp X;z PIKDIR%> Q> : FDVND3 R@ICBALZ7 HFDVND 3 Q@ICBALZ7 R> @ DSETRDIR R> Z DGFNDIR R> _ DSETRDIR R> z ESETRDIR.GFNDIR LFFILE;;FIND NEW DEFAULT DIRECTORY INITYP$ TONXDR.FNODIRF;;IF NOT A DIRECTORY8QDIRBAS9B?L QDIRBAS9V-SAVDEF'CDIREC;;UPDATE ADDRESS OF DIR.` PCDIRECj QICDNOZt PDEFAULT;;UPDATE UNIT NUMBER~ ITOFDNX;SETRDIRQ>i %>i ISAVDEFX;1RENAME LFFILE;;GET OLD NAME, DRIVE, VALIDATE%> STEMPLQFNAME8PMAPBUF81 HSTEMPL+RNLOOP TSTLOK;;CANNOT RENAME IF LOCKED TDDOS;;TEST FOR DOS GONE!  %TMP2 GETNAM;;GET NEW NAME,($ ENTNAME;;OVERWRITE NAME IN DIR.2& WDIRBK;;REWRITE DIRECTORY TO DISK<X;F TSTDOS;;NEW NAME DOS.SYS?PHREPLDS;;NO, LOOK AT NEXTZ %DIRDSPdQDIRBUF8n5xQDIRBUF8?7& SETDOS;;ELSE, UPDATE BOOT SECTORSREPLDS%> RTEMPLQMAPBUF8PFNAME81 HRTEMPL CSFDIR;;TO RENAME DRNLOOP ETOFDNX;DELETE LFFILE$DELLP REMOVE;;FLUSH THE SECTORS" RRDIR;;REREAD DIRECTORY BLOCK TDDOS;;DOS.SYS DELETED?"Q>,% SAVFLAG;;REWRITE DIRECTORY BLOCK6 CSFDIR@DDELLP;;IF ANOTHER FOUND,J)TOFDN!FREDON;;ELSE, WRAP UP AND EXITTX;^0REMOVE TSTLOK;;ONCE HAD 'OPVTOC' CALL FIRSTh INITYPr TONXDR| HDELDIR CHASEX;D0C6C FREE RDNXTS DD0C6C:X;'INVDELQ>;;DIRECTORY NOT DELETABLE !AEXITX; LOCKQ>  ,;;BIT ABS (SKIP 2 BYTES)X;UNLOCKQ> PDATBYT* LFFILE;;FIND FILE AND VERIFY WRITABLE&#LKULKLQ>;;STRIP OFF OLD BIT 50 GETFLAG:!LDATBYT;;AND REPLACE WITH NEWD SAVFLAGN CSFDIRX DLKULKLb ETOFDNlX;vDELDIR%> Q> ?DELSETPFNAME 83 HDELSET SFDIR DINVDELX;Q> PDATBYT TONXTDELDRL FREE INCCSEC "DATBYT HDELDRL  !GETFNMX; POINT%FCBFLG9* GERRCMD4X;>QICSPR9HRCURSEC9R HPNTREAD\ QICSPR9f RCURSEC9p FPNTSMEz PNTREADC!FPNTCLN;;IF SECTOR UNMODIFIED WRDISKQ> PFCBFLG9PNTCLNQICSPR9PLNKSEC9 QICSPR9 PLNKSEC9" CHASE;;READ SECTOR POINTED TO EBADPNTX;PNTSMEQICSPR9 RMAXLEN9 EPNTEQLPNTLSTPCURLEN9 !DONE$X;.,PNTEQLFPNTLST;;IF POINTING AT LAST BYTE8&BADPNTQ>;;INVALID POINT LOCATIONB LX;V&ERRCMDQ>;;INVALID IOCB PARAMETER` !AEXITjX;tNOTEQCURSEC9~ PICSPR9QCURSEC9PICSPR9 QCURLEN9PICSPR9 !DONEX;DKXIO SETUPQICCOMZ;;GET COMMAND BYTER> FFORMATR>+EERRCMD;;IF INVALID COMMAND S>   DERRCMD? QVECTBH8(52 QVECTBL8<5F:;;VECTOR TO PROPER ROUTINEPX;Z,VECTBH RENAME =DELETE d" MKDIR =LOCK n$ UNLOCK =POINT x# NOTE =DKLOAD % DKLOAD =PIKDIR  MKDIR X;*VECTBL RENAME =DELETE  MKDIR =LOCK " UNLOCK =POINT ! NOTE =DKLOAD # DKLOAD =PIKDIR  MKDIR X;X; DOS FORMAT ROUTINESX;X;6FORMAT WBITMP;;WRITE OUT ANY PENDING VTOC SECTORS%> %WOTCOPY2QWOTDCB8;;set up DCB for"PDDEVIC8;;density stuff,16 IWOTCOPY2@ $ICDNOZJ (RAMDKUT%FWOTRAM;;don't do it for RAMdisks^%SECSIZ9hQDRVDEF9r SETDRV;;set density|!WOTRAM$CURFCB;;restore X reg%>(C;;THEN INITIALIZE NEW BIT MAP (VTOC)CLRMAPPMAPBUF8PMAPBUF83)HCLRMAP;;ALLOCATING ALL POSSIBLE BITSX;Q>(PMAPBUF;;DEFINE IT AS A DOS 2.0 DISKQ> P@FMSBPT73=P@FMSBPT7;;PRESUME NO BAD SECTORS IF BUFFER IS UNMODIFIED %ICDNOZ )RAMDKU(FRAMFMT;;IF RAMDISK, SKIP EVERYTHING&QFMSBPT0(%FMSBPT;;call density junk for patch:/ BUFSET;;SET UP BUFFER POINTER FOR SIO CALLD$>N&TMP1;;ALLOW ONE TRY ONLYX(Q>";;PRESUME 1050 D/D FORMAT REQUESTb%ICAX2Z;;THEN GET AUX2 BYTEl(GFMTOK;;MINUS --> NO FORMAT REQUIREDv HNMLFMT%ICAX1Z;;(AUX2,AUX1) = 1?1.FFT1050;;YES, FORMAT WITH $22 COMMAND BYTENMLFMT$DUNITQSECSIZ9>+Q>FMTCMD;;AUX IS 0, must not be 1050 dd*FT1050PDAUX1;;MAKE SURE WE SECTOR > 34%DSKTIM;;DISK TIMEOUT VALUE (RETURNED IN STATUS)& DKFME;;ENTER DKIO AT FORMAT ENTRY#IFMTOK;;delete bad sector check*FMEXIT!AEXIT;;ELSE, RETURN ERROR CODEX;?RAMFMTPCURSEC9;;STUFF PROPER NUMBER OF SECTORS INTO CURSEC 3,;;(256-BYTE PAGES * 2 SINCE SECTOR SIZE IS 128) ORDKLMT V?* WCURSEC94,HNOTDEF;;FAIL IF NOT 256 SECTORS OR MORE>X;H8X; SUCCESSFUL FORMAT, CREATE VTOC AND EMPTY DIRECTORYRX;\%FMTOK%>;;check for a bad formatf Q@FMSBPT7p#M@FMSBPT7;;first two bytes $FF?zR>FFMTOK2;;yep, continueQ>;;otherwise format error HFMEXIT.FMTOK2 INVUNIT;;MAKE SURE WE CAN DO THIS!- DELDOS;;DELETE ANY CURRENT DOS BOOT FILE QICAX1Z PCURSEC9 QICAX2Z#M>;;DISK MUST HAVE 256 SECTORS&HNOTDEF;;IF SIZE SPECIFIED, USE IT %ICDNOZ.QHDTAB8;;IF NOT AND THIS IS A HARD DISK"PCURSEC9;;USE THE DEFINED SIZEQHDTAB8 HNOTDEF&*DVSTAT;;ELSE, IS IT A 1050 DRIVE?$!IFIGSIZ;;NO, FIGURE SIZE THEN.'Q>;;YES, FORCE TO 1040 SECTORS8 PCURSEC9B Q>L HNOTDEFVX;`FIGSIZQDRVDEF8j"M>1;;EXTRACT TRACK COUNT FLAGStV?~6V?V??0QNOSECS8;;AND USE DRIVE DEFAULT SECTOR COUNT PCURSEC9QNOSECS88,DNOTDEF;;IF NOT DOUBLE SIDED, THIS IS IT TCURSEC9U?;;ELSE, DOUBLE ITX;NOTDEFPCURSEC9R>;;NEED 16 BIT LINKS?  DSHORTS;;NO, SHORT FORMAT OK*#MAPBUF;;YES, FORCE LONG FORMAT (DOS3),SHORTS FNDBIT;;FIND LAST BIT MAP SECTOR( QTMP22"HGT246;;IF PAST 256TH MAP BYTE<*DLINK;;SINGLE DENSITY?F GFDBDENP)>Z IFDBDENdGT246PMAP2n,xO> PMAPBUFFDBDENQ> PMAPBUF Q> 2PMAPBUF;;START WITH 9 FREE SECTORS UN-FREE!FLOOP FMTFRE DECCSECR>;;BOOT SECTORS YET?)HFLOOP;;IF NOT, CONTINUE DEALLOCATINGQCURSEC9 HFLOOPX;Q>;;success)PFMSBPT;;bad sector code deleted hereX;Q>">PMAPBUF7;;ALLOCATE THE ROOT DIRECTORY AND BASE VTOC SEC.,*Q>;; NOTE: ALWAYS THE SAME 9 SECTORS6PMAPBUF8@"%>,;;START ALLOC. OF VTOC HEREJ QMAPBUFT;^S>;;GET NUMBER OF SECTORSh*DLINK;;(SINGLE DENSITY?)rGMPNSD;;IF NOT, M-3|T?;;IF SO, M*2-5 MPNSD>0;;MOVE COUNT TO XX;ALCMPLQ> ALCMAP0 GSMBSIZ5 DECCNT7T? HALCMAPPMAPBUF 81IALCMPL;;BRANCH ALWAYS!X;SMBSIZPMAPBUF 8&$QMAPBUF;;MARK EMPTY SIZE, TOO0PMAPBUF:QMAPBUFDPMAPBUFN FMTMAP;;WRITE MAP TO DISKXX;b X; CREATE AN EMPTY DIRECTORYlX;v Q>i %>i3CLRDIR SETDIR;;RESET THE DIRECTORY BASE SECTORC$CLRDLPPDIRBUF8;;ZERO THE BUFFER3 HCLRDLPX;Q> PDIRSEC1CLRDL2 WDIRBK;;THEN WRITE 8 SECTORS OF ZEROS "DIRSEC ICLRDL2 %BUFNO9Q>  PBUFNO92PBUFFLG8;;DONE, SO FREE UP INTERNAL BUFFERS  QFMSBPT* !AEXIT4X;>"NOSECS #=(=P=MHX;RSETDIRPDIRBAS9\CfPDIRBAS9p%>z:X;X; DOS BINARY LOAD CODEX;X;.X; LOAD AND EXECUTE A BINARY FILE (PROGRAM)X;DKLOADQICAX1Z-PICPTLZ;;SAVE PROGRAM NAME BUFFER POINTERR>#ETOERRC;;IF WRITE, REPORT ERRORX;Q>TORTS PRUNADR-Q>TORTS;;ASSUME RUN ADDRESS IS ABSENTPRUNADRQ>$ PICAX1Z.QICHID9;;IOCB OPEN?8 ICCFILEB DKOPEN;;IF NOT, OPEN ITL GDKLERVV WDREAD;;READ A HEADER WORD` FCCFILEj+%>;;NO $FFFF, REPORT HEADER ERROR CODEt GDKLERV~X;TOERRC%>;;INVALID IOCB:X;GETTXTQ>TORTS PINIADR:Q>TORTS;;FOR EACH SEGMENT, RE-FORCE NULL INIT CODEPINIADRTXTLP DKREADDKLERVGDKLERR%> P@ICBALZ7 #ICBALZ HDECLEN  #ICBAHZDECLENQICBLLZ HDECLOW( "ICBLHZ2DECLOW"ICBLLZ< HTXTLPF QICBLHZP HTXTLPZ QICBAHZdR>INIADRn HCCFILExX;QICPTLZ;;IF NO INITS,V?ECCFILE;;SKIP TO NEXT PAGEA;;ELSE SAVE IOCB5 %> CPSICBQICHIDZ 8$PICHID9;;SAVE 12 BYTE IOCB ENTRY23 HCPSICB7>5# DOINIT;;AND CALL INIT FUNCTION7">,56 %> @1CPRICBQICHID9;;THEN RESTORE THE 12 BYTE IOCBJPICHIDZ 8T2^3h HCPRICBr7|>X;&CCFILE WDREAD;;READ START ADDRESS FCCFILE PICBALZ 'ICBAHZ WDREAD;;READ END ADDRESS;O> DCCSUBT3 CCSUBT;!SICBALZ;;CALCULATE THE LENGTH PICBLLZ C SICBAHZ PICBLHZ& 0EGETTXT;;BRANCH IF A VALID LENGTH (GET DATA)0 %%>;;ELSE, MEMORY WRAP ERROR CODE: GDKLERRD X;N WDXIT7X 7b DKLERRCl 5v  DKCLOS;;CLOSE PROGRAM FILE 7 (?;;AND RETURN HIS ERROR CODE (IF ANY) : X; BX; READ A WORD FROM THE PROGRAM FILE AND COMPARE IT WITH $FFFF X; WDREADQ> PICBLLZ PICBLHZ;;SET LENGTH TO ZERO  DKREAD;;READ A BYTE GWDEOF 5  DKREAD;;READ THE SECOND! GWDEOF1 !?!7 !)>;;UPPER BYTE $FF?*!,HTORTS;;IF NOT, TOTAL VALUE IS NOT $FFFF4!%R>;;UPPER OK, IS LOWER BYTE $FF?>!.TORTS:;;RETURN ZERO FLAG IF WORD WAS $FFFFH!X;R! WDEOF17\!#WDEOF)>;;IS THIS END OF FILE?f!%HWDXIT;;IF NOT, RETURN ERROR CODEp!7z!"7;;ELSE, GET RID OF RETURN ADDR! QICPTLZ!V?!V?!6!# DKCLOS;;CLOSE FILE AND SET Y=1!8!$ETORTS;;EXIT IF NO-RUN SPECIFIED!+!@RUNADR:;;OTHERWISE, GO TO RUN ADDRESS!X;!FX; INVOKE INIT FOR EVERY BLOCK OF INPUT CODE (USUALLY JUST AN RTS)!X;!#DOINIT!@INIADR:;;CALL INDIRECT