page 60,132 ;TITLE (C) Copyright CAPROCK SYSTEMS, INC. 1982 ;SUBTTL small-c:PC PC-DOS RUN TIME LIBRARY ; ; DATASEG SEGMENT BYTE PUBLIC 'code' DB '(C) Copyright CAPROCK SYSTEMS, INC. 1982' ; ; ; ;FOR I/O BUFFERS FCBSIZE EQU 40 ;PCDOS FCB SIZE + 3 BUFFER EQU 4 ;SPACE NEEDED FOR NEXT PTR AND UNUSED CNT BUFSIZ EQU 512 ;DISK BLOCK SIZE NEXTP EQU 0 ;OFFSET IN BUFFER OF NEXT CHAR PTR UNUSED EQU 2 ;OFFSET IN BUFFER OF REMAINING CHARS FLAG EQU 37 ;OFFSET IN FCB OF FLAG TYPING AN FCB NBUFS EQU 4 ;NUMBER OF IOBUFS (SEE BELOW) FREEFLG EQU 128 ;FCB NOT ALLOCATED EOFFLG EQU 2 ;EOF ENCOUNTERED ON FILE WRTFLG EQU 1 ;FILE OPENED FOR WRITING CTRLZ EQU 26 EOL EQU 13 ;END OF LINE CHARACTER LF EQU 10 ;LINE FEED ; ;PCDOS INT 21H FUNCTION CODES ; GETCH EQU 1 PUTCH EQU 2 GETSTR EQU 10 SELECT EQU 14 DMA EQU 26 OPEN EQU 15 DELETE EQU 19 CREATE EQU 22 CLOSE EQU 16 SEQREAD EQU 20 SEQWRITE EQU 21 GETDFLT EQU 25 ;GET CURRENT LOGGED DRIVE PARSE EQU 41 ; ; ; FCB STORAGE AND I/O BUFFERS ; DFLTDSK DB 0 ;BYTE FOR DEFAULT DISK IOBUFS DB FCBSIZE-3 DUP(?) DB FREEFLG,0,0 DB BUFFER+BUFSIZ DUP(?) ; DB FCBSIZE-3 DUP(?) DB FREEFLG,0,0 DB BUFFER+BUFSIZ DUP(?) ; DB FCBSIZE-3 DUP(?) DB FREEFLG,0,0 DB BUFFER+BUFSIZ DUP(?) ; DB FCBSIZE-3 DUP(?) DB FREEFLG,0,0 DB BUFFER+BUFSIZ DUP(?) DATASEG ENDS ; ; ; CSEG SEGMENT BYTE PUBLIC 'code' ASSUME CS:CSEG,DS:DATASEG ;------------------------------------------------- ; ; Small-C:PC Run Time Library for IBM PC-DOS ; ; V1 As of June, 1982 ; ;-------------------------------------------------- db '(C) Copyright CAPROCK SYSTEMS, INC. 1982' ; ; ; Fetch byte at offset BX in Stack Segment (SS) and sign extend into BX ; PUBLIC CCGCHAR CCGCHAR: MOV BP,BX MOV AL,[BP] CBW MOV BX,AX RET ; ; Fetch a 16-bit integer at offset BX in SS into BX ; PUBLIC CCGINT CCGINT: MOV BP,BX MOV BX,[BP] RET ; ; Store BL into SS at offset in DX ; PUBLIC CCPCHAR CCPCHAR: MOV BP,DX MOV [BP],BL RET ; ; Store BX into SS at Offset in DX ; PUBLIC CCPINT CCPINT: MOV BP,DX MOV [BP],BX RET ; ; Multiply DX by BX and return result in BX ; PUBLIC CCMULT CCMULT: MOV AX,DX IMUL BX MOV BX,AX RET ; ; Divide DX by BX, return quotient in BX, remaint in BX ; PUBLIC CCMULT CCMULT: MOV AX,DX IMUL BX MOV BX,AX RET ; ; Divide DX by BX, return quotient in BX, remainder in DX ; PUBLIC CCDIV CCDIV: MOV AX,DX MOV CX,1 IMUL CX IDIV BX MOV BX,AX RET ; ; Unsigned compare of DX to BX, carry set if DX < BX ; PUBLIC CCUCMP CCUCMP: CMP DH,BH JNZ CC@1 CMP DL,BL CC@1: MOV BX,1 RET ; ; Test if DX >= BX (Unsigned) ; PUBLIC CCUGE CCUGE: CALL CCUCMP JNC CC@2 DEC BX CC@2: RET ; ; Test if DX < BX (Unsigned) ; PUBLIC CCULT CCULT: CALL CCUCMP JC CC@3 DEC BX CC@3: RET ; ; Test if DX > BX (Unsigned) ; PUBLIC CCUGT CCUGT: XCHG BX,DX CALL CCULT RET ; ; Test if DX <= BX (Unsigned) ; PUBLIC CCULE CCULE: XCHG BX,DX CALL CCUGE RET ; ; Signed Compare of DX and BX ; ; carry set if DX < BX, zero/non-zero set for equality ; PUBLIC CCCMP CCCMP: SUB DL,BL SBB DH,BH MOV BX,1 JS CCCMP1 OR DH,DL RET CCCMP1: OR DH,DL STC RET ; ; Test if DX = BX and set BX=1 if true, else 0 ; PUBLIC CCEQ CCEQ: CALL CCCMP JZ CC@4 DEC BX CC@4: RET ; ; ; Test if DX != BX ; PUBLIC CCNE CCNE: CALL CCCMP JNZ CC@5 DEC BX CC@5: RET ; ; Test if DX < BX ; PUBLIC CCLT CCLT: CALL CCCMP JC CC@6 DEC BX CC@6: RET ; ; Test if DX > BX ; PUBLIC CCGT CCGT: XCHG BX,DX CALL CCLT RET ; ; Test if DX <= BX ; PUBLIC CCLE CCLE: CALL CCCMP JC CC@7 JZ CC@7 DEC BX CC@7: RET ; ; Test if DX >= BX ; PUBLIC CCGE CCGE: XCHG BX,DX CALL CCLE RET ; ;------------------------------------------------- ; ; PC-DOS I/O MODULES ; (C) CAPROCK SYSTEMS, INC. ; P.O. BOX 13814 ; ARLINGTON, TEXAS 76013 ; ;------------------------------------------------- ; ; ; ; pcdos(ah,dx) ; PUBLIC QZPCDOS QZPCDOS: POP CX POP DX POP AX PUSH AX PUSH DX PUSH CX MOV AH,AL INT 21H CBW MOV BX,AX RET ; ; ; ouDOS QZPCDOS: POP CX POP DX POP AX PUSH AX PUSH DX PUSH CX MOV AH,AL INT 21H CBW MOV BX,AX RET ; ; ; out808X(port,AL) ; ; PUBLIC QZOUT808X QZOUT808X: POP CX POP AX POP DX PUSH DX PUSH AX OUT DX,AL JMP CX ; ; ; int var = in808X(port) ; ; PUBLIC QZIN808X QZIN808X: POP CX POP DX PUSH DX IN AL,DX CBW MOV BX,AX JMP CX ; ; ; VIDEO I/O THRU ROM BIOS ; ; int10(AH,AL,BH,BL,CH,CL,DH,DL); ; ; PUBLIC QZINT10 QZINT10: POP SI POP DX POP AX MOV DH,AL POP CX POP AX MOV CH,AL POP BX POP AX MOV BH,AL MOV DI,BX POP AX POP BX MOV AH,BL MOV BX,DI PUSH AX PUSH AX PUSH BX PUSH BX PUSH CX PUSH CX PUSH DX PUSH DX PUSH SI INT 10H RET ; ; ; ASYNC I/O THRU ROM BIOS ; ; BX = INT14(AH,AL,DX) ; PUBLIC QZINT14 QZINT14: POP CX POP DX POP BX POP AX PUSH AX PUSH BX PUSH DX MOV AH,AL MOV AL,BL INT 14H MOV BX,AX JMP CX ; ; ; copy program prefix to stack area ; ; copyprefix(ptr); ; PUBLIC QZCOPYPREF QZCOPYPREF: POP CX POP DI ;OFFSET INTO STACK OF DESTINATION PUSH DI PUSH CX MOV AX,SS PUSH ES MOV ES,AX ;PREPARE FOR MOVE MOV SI,0 CLD MOV CX,128 ;NUMBER WORDS TO MOVE REP MOVSW POP ES RET ; ; ; SOUND BELL ; ; bell() ; PUBLIC QZBELL QZBELL: MOV AX,7 ;BELL CHARACTER PUSH AX CALL QZPUTCHAR ;SOUND IT POP AX RET ; ; ; CLEAR SCREEN ; ; clrscreen(); ; PUBLIC QZCLRSCREE QZCLRSCREE: INT 11H ;EQUIPMENT MOV SI,AX AND SI,30H MOV AX,0B800H ;COLOR CARD RAM MOV CX,8192 ;WORD COUNT CMP SI,30H JNE CC@8 MOV AX,0B000H ;BW CARD RAM MOV CX,2048 ;WORD COUNT CC@8: MOV ES,AX MOV AH,15 ;VIDEO STATE INT 10H CMP AL,4 ;GRAPHICS MODE? JC CC@9 CMP SI,30H ;BW CARD? JE CC@9 XOR AX,AX ;FILL WORD JMP SHORT CC@10 CC@9: MOV AX,' '+7*256 ;FILL WORD CC@10: XOR DI,DI CLD REP STOSW ;CLEAR VIDEO MEMORY MOV AH,2 ;MOVE CURSOR XOR DX,DX ;0,0 (HOME) XOR BH,BH ;ACTIVE PAGE INT 10H RET ; ; ; ; gets(buff) ; ; PUBLIC QZGETS QZGETS: POP BX POP DX PUSH DX PUSH BX SUB DX,2 MOV BP,DX MOV CX,[BP] MOV AX,004FH ;ASSUMED LENGTH = 80 CHARS - 1 FOR EOL MOV [BP],AX ;SET UP BUFFER THE WAY PC-DOS WANTS IT PUSH DS MOV AX,SS MOV DS,AX MOV AH,GETSTR INT 21H POP DS MOV AX,[BP] ;LENGTH IN AH MOV [BP],CX ;RESTORE SAVED BYTES ADD BP,2 MOV BX,BP MOV AL,AH CBW ADD BP,AX XOR AL,AL MOV [BP],AL ;INSERT C:PC STRING TERMINATOR CALL PUTLF RET ; PUTLF: MOV AH,PUTCH MOV DL,LF INT 21H RET ; ; ; getchar() ; ; PUBLIC QZGETCHAR QZGETCHAR: MOV AH,GETCH INT 21H MOV BL,AL XOR BH,BH CMP AL,CTRLZ JNZ GETC1 MOV BX,-1 GETC1: CMP AL,EOL JNZ GC2 CALL PUTLF GC2: RET ; ; ; putchar(c) ; ; PUBLIC QZPUTCHAR QZPUTCHAR: POP BX POP DX PUSH DX PUSH BX MOV AH,PUTCH INT 21H MOV BL,DL CMP DL,EOL JNZ PUTC1 CALL PUTLF PUTC1: XOR BH,BH RET ; ; ; puts(cp) ; ; PUBLIC QZPUTS QZPUTS: POP CX POP BP PUSH BP PUSH CX MOV AH,PUTLF PUTC1: XOR BH,BH RET ; ; ; puts(cp) ; ; PUBLIC QZPUTS QZPUTS: POP CX POP BP PUSH BP PUSH CX MOV AH,PUTCH PS1: MOV DL,[BP] OR DL,DL JNZ PS2 RET PS2: INC BP INT 21H JMP PS1 ; ; ; Run Time Initialize ; ; CCGO: MOV CL,4 ;SHIFT COUNT MOV AX,STACK MOV SS,AX MOV BX,DS SUB AX,BX SAL AX,CL ;MAKE DIFF 16 BITS NEG AX ADD AX,DS:6 MOV SP,AX ;MAX STACK POINTER PUSH DS ;SAVE PREFIX ADDR SUB AX,AX PUSH AX ;LONG EXIT ADDRESS IS NOW ON TOP MOV AX,DATASEG PUSH DS MOV DS,AX MOV AH,GETDFLT INT 21H INC AL MOV BX,OFFSET DFLTDSK MOV [BX],AL POP DS EXTRN QZMAIN:NEAR CALL QZMAIN ;EXECUTE USER'S small-c:PC PROGRAM ; FALL THRU TO EXIT CODE ; ; ; exit() ; PUBLIC QZEXIT QZEXIT: MOV CL,4 MOV AX,SS MOV BX,DS SUB AX,BX SAL AX,CL NEG AX ADD AX,DS:6 SUB AX,4 MOV SP,AX ;PRUNE STACK MOV AX,DATASEG PUSH DS MOV DS,AX MOV BX,OFFSET DFLTDSK MOV DL,[BX] DEC DL MOV AH,SELECT INT 21H POP DS DB 0CBH ;LONG RETURN TO DOS ; ; ; fopen(name,mode) ; PUBLIC QZFOPEN QZFOPEN: POP AX POP CX ;MODE POP SI ;PREPARE FOR PARSE PUSH SI PUSH CX PUSH AX PUSH CX ;SAVE MODE CALL GRABIO ;GET FCB POP CX ;RESTORE MODE FOR LATER USE OR BX,BX ;ANY LUCK IN GETTING AN FCB? JNZ FO1 RET ;NOPE FO1: MOV DX,BX ;SAVE OFFSET PUSH DS ;SAVE CALLER'S DS MOV AX,DATASEG MOV DS,AX ;ADDRESS OUR DATA SEGMENT ADD BX,FCBSIZE ;OFFSET OF BUFFER MOV AX,BX ADD AX,BUFFER ;IO AREA OFFSET MOV [BX]+NEXTP,AX ;NEXT AVAILABLE CHAR PUSH DS MOV AX,DS MOV ES,AX MOV DI,DX ;ES:DI -> FCB MOV AX,SS MOV DS,AX ;DS:SI -> NAME MOV AH,PARSE XOR AL,AL ;PARSE WITHOUT SKIPPING ANYTHING INT 21H POP DS ;RESTORE OUR DS OR AL,AL ;ANY LUCK? JNZ FORET ;JUMP IF NOT MOV AL,[DI]+1 ;SEE IF WE HAD A VALID FILENAME CMP AL,20H ;BLANK? JNZ FO2 ;NOPE, SO IT MUST BE SOMETHING THERE FORET: POP DS ;RESTORE CALLER'S DS XOR BX,BX ;SET RETURN STATUS RET ;LEAVE FO2: MOV BX,DX ;RESTORE OFFSET OF FCB MOV AL,[BX] ;DRIVE PUSH DX ;SAVE ACCROSS CALL PUSH CX PUSH AX CALL PCDOSDSK ;SELECT IT POP AX POP BP ;MODE OFFSET INTO BP FOR STACK ACCESS POP DX MOV AL,[BP] ;GET MODE CHAR CMP AL,72H ;MODE='r' JZ FO3 CMP AL,52H ;MODE='R' JNZ FO5 FO3: MOV AH,OPEN INT 21H ;OPEN THE FILE OR AL,AL JZ FO4 ;NO ERROR JUMP FO3@1: PUSH DX ;FCB OFFSET CALL FREEIO ;GIVE IT UP POP DX JMP FORET FO4: XOR AX,AX FO4@1: MOV [BX]+FCBSIZE+UNUSED,AX ;SET UNUSED BUFFER BYTES XOR AX,AX MOV [BX]+32,AL ;INIT SOME FCB FIELDS MOV [BX]+33,AX MOV [BX]+35,AX MOV AX,BUFSIZ MOV [BX]+14,AX POP DS ;RESTORE CALLER'S DS RET ;LEAVE WITH BX SET TO FCB OFFSET FO5: CMP AL,77H ;MODE='w' JZ FO6 CMP AL,57H ;MODE='W' JNZ FO3@1 ;TAKE ERROR EXIT FO6: MOV AH,DELETE INT 21H ;DELETE FILE IF IT CURRENTLY EXISTS MOV AH,CREATE INT 21H ;CREATE IT OR AL,AL ;OK? JNZ FO3@1 ;TAKE ERROR EXIT IF NOT MOV BX,DX MOV AL,WRTFLG MOV [BX]+FLAG,AL ;INDICATE HOW FILE IS OPENED MOV AX,BUFSIZ ;NUMBER OF UNUSED BUFFER POSITIONS JMP FO4@1 ; ; ; ; grabio() ; ; GRABIO: PUSH DS MOV AX,DATASEG MOV DS,AX MOV BX,OFFSET IOBUFS+FLAG MOV CX,NBUFS MOV AL,FREEFLG GI1: CMP AL,[BX] JZ GI2 ADD BX,FCBSIZE+BUFFER+BUFSIZ LOOP GI1 XOR BX,BX JMP GI3 GI2: XOR AL,AL MOV [BX],AL SUB BX,FLAG GI3: POP DS RET ; ; ; ; freeio(unit) ; ; FREEIO: POP CX POP BX PUSH BX MOV AL,FREEFLG MOV [BX]+FLAG,AL XOR BX,BX JMP CX ; ; ; ; pcdosdsk(drive) ; ; PCDOSDSK: POP CX POP DX PUSH DX OR DL,DL JNZ PD1 ; SELECT DEFAULT DRIVE PUSH BX MOV BX,OFFSET DFLTDSK MOV DL,[BX] POP BX PD1: DEC DL MOV AH,SELECT INT 21H JMP CX ; ; ; ; fclose(unit) ; ; PUBLIC QZFCLOSE QZFCLOSE: POP CX POP BX ;FCB OFFSET PUSH BX PUSH CX MOV SI,1 ;DEFAULT RETURN CODE PUSH DS ;SAVE CALLER'S DS MOV AX,DATASEG MOV DS,AX MOV AL,WRTFLG AND AL,[BX]+FLAG ;OPENED FOR WRITE? JZ FC3 ;JUMP IF NOT MOV AX,CTRLZ PUSH AX ;CHAR TO WRITE PUSH BX ;UNIT TO GO TO CALL QZPUTC ;CTRLZ AT FILE END POP BX POP AX ; FILL BUFFER WITH FILL CHAR MOV DX,BX MOV AX,[BX]+FCBSIZE+NEXTP ;OFFSET OF NEXT AVAILABLE CHAR MOV CX,DX ADD CX,FCBSIZE+BUFFER+BUFSIZ ;OFFSET PAST LAST IOAREA BYTE SUB CX,AX ;NUMBER OF CHARS TO FILL PUSH CX ;SAVE UNUSED BYTE COUNT JLE FC0 ;JUMP IF NONE MOV DI,AX ;START ADDRESS ES:DI MOV AX,DS MOV ES,AX MOV AL,0 ;FILL CHAR CLD ;LEFT TO RIGHT REP STOSB ;FILL BUFFER FC0: MOV AX,SEQWRITE PUSH AX PUSH DX ;FUNCTION AND UNIT NOW ON STACK CALL PCDOSIO ;WRITE SECTOR MOV AX,BX ;SAVE RETURN CODE POP BX ;RESTORE UNIT POP CX OR AX,AX JNS FC1 MOV SI,0 FC1: POP CX ;RESTORE UNUSED COUNT NEG CX ;PREPARE TO REDUCE DOS COUNT JNS FC3 ;NO SIGN IMPLIES DOS COUNT IS OK MOV AX,1 ;PREPARE FOR OVERFLOW ADD [BX]+16,CX ;NEW LOW PART JNO FC3 ;NO OVERFLOW => NO HIGH PART CHANGE ADD [BX]+18,AX ;NEW HIGH PART FC3: MOV DX,BX MOV AH,CLOSE INT 21H ;CLOSE FILE OR AL,AL JNS FC2 MOV SI,0 FC2: PUSH BX CALL FREEIO POP BX POP DS MOV BX,SI RET ; ; ; ; pcdosio(fn,unit) ; ; PCDOSIO: POP CX POP DX ;UNIT= OFFSET IN DS OF FCB POP BX ;FUNCTION WANTED PUSH BX PUSH DX PUSH CX PUSH DS ;SAVE CALLER' POP CX POP DX ;UNIT= OFFSET IN DS OF FCB POP BX ;FUNCTION WANTED PUSH BX PUSH DX PUSH CX PUSH DS ;SAVE CALLER'S DS MOV AX,DATASEG MOV DS,AX XOR AH,AH XCHG BX,DX MOV AL,[BX] ;DRIVE NUMBER XCHG BX,DX PUSH DX PUSH AX CALL PCDOSDSK ;SELECT IT POP AX POP DX MOV CX,DX ;SAVE UNIT ADD DX,FCBSIZE+BUFFER ;IO AREA OFFSET MOV AH,DMA INT 21H ;SET TRANSFER ADDRESS MOV DX,CX ;DS:DX = FCB ADDRESS MOV AH,BL ;FUNCTION CODE INT 21H MOV CL,AL ;STATUS MOV AH,DMA POP DS ;RESET DS TO PREFIX MOV DX,80H INT 21H ;DMA BACK TO DEFAULT MOV AL,BL ;SAVE FUNCTION XOR BX,BX OR CL,CL JZ PDI1 CMP AL,SEQREAD ;DID USER READ? JNZ PDI0 ;CONSIDER IT AN ERROR CMP CL,03H ;PARTIALLY FULL BUFFER? JZ PDI1 ;THAT'S OK PDI0: NOT BX PDI1: RET ; ; ; ; getc (unit) ; ; PUBLIC QZGETC QZGETC: POP CX POP BX ;UNIT PUSH BX PUSH CX PUSH BX CALL CGET ;GET NEXT CHARACTER POP DX ;UNIT CMP BL,EOL ;END OF LINE JNZ GC1 ;GO ON BACK IF NOT PUSH BX ;SAVE EOL ON STACK PUSH DX ;UNIT CALL CGET ;ABSORB LF POP DX POP BX ;RETURN EOL GC1: RET ; ; ; ; cget(unit) ; ; CGET: POP CX POP BX MOV DX,BX PUSH BX PUSH CX PUSH DS MOV AX,DATASEG MOV DS,AX MOV AL,EOFFLG AND AL,[BX]+FLAG ;END OF FILE EXIST? JZ CG1 ;NOPE CG0: POP DS MOV BX,-1 ;ERROR RETURN RET CG1: MOV AX,[BX]+FCBSIZE+NEXTP ;BUFFER OFFSET OF NEXT CHARACTER MOV CX,[BX]+FCBSIZE+UNUSED ;NUM CHARS REMAINING IN BUF OR CX,CX JNZ CG2 ;SOME LEFT ;READ NEW SECTOR MOV AX,SEQREAD PUSH AX ;FUNCTION PUSH DX ;UNIT CALL PCDOSIO ;READ SECTOR POP DX POP AX OR BH,BL ;OK? JNZ CG0 ;JUMP IF NOT MOV BX,DX ;RESTORE UNIT MOV CX,BUFSIZ ;NEW COUNT MOV AX,DX ADD AX,FCBSIZE+BUFFER ;NEW NEXT CHAR OFFSET CG2: DEC CX ;REDUCE UNUSED MOV [BX]+FCBSIZE+UNUSED,CX MOV CX,AX INC CX ;BUMP UP NEXT CHAR POINTER MOV [BX]+FCBSIZE+NEXTP,CX MOV BX,AX ;OFFSET OF CHAR TO RETURN MOV AL,[BX] CMP AL,CTRLZ ;IS IT EOF MARKER? JNZ CG3 ;JUMP IF NOT MOV BX,DX ;UNIT MOV AH,EOFFLG OR [BX]+FLAG,AH ;SET END OF FILE IN FCB JMP CG0 CG3: MOV BL,AL ;CHAR TO RETURN XOR BH,BH POP DS RET ; ; ; ; putc(char,unit) ; ; ; PUBLIC QZPUTC QZPUTC: POP CX POP BX ;UNIT POP AX ;CHAR PUSH AX PUSH BX PUSH CX PUSH AX ;CHAR PUSH BX ;UNIT CALL CPUT ;PUT OUT CHAR POP DX ;UNIT ;LEAVE CHAR ON STACK AS RETURN VALUE OR BH,BH ;ERROR? JS PC2 ;JUMP IF SO CMP BL,EOL ;DID EOL GO OUT? JNZ PC1 ;JUMP IF NOT MOV AX,LF ;PUT OUT LF ALSO PUSH AX PUSH DX CALL CPUT POP DX POP AX OR BH,BH ;ERROR? JS PC2 ;JUMP IF SO PC1: POP BX ;RETURN CHAR PASSED IN RET PC2: POP CX ;CLEAR CHAR OFF STACK MOV BX,-1 ;ERROR RETURN RET ; ; ; ; cput(c,unit) ; ; CPUT: POP CX POP BX ;UNIT POP SI ;CHAR PUSH SI PUSH BX PUSH CX PUSH DS MOV AX,DATASEG MOV DS,AX MOV DX,BX MOV AX,[BX]+FCBSIZE+NEXTP ;NEXT CHAR OFFSET MOV CX,[BX]+FCBSIZE+UNUSED ;UNUSED CHAR COUNT OR CX,CX JNZ CP2 ;JUMP IF ROOM AVAILABLE MOV AX,SEQWRITE PUSH AX ;FUNCTION PUSH DX ;UNIT CALL PCDOSIO ;SECTOR WRITE POP DX POP AX OR BH,BL JZ CP1 ;JUMP IF OK CP0: POP DS MOV BX,-1 ;ERROR RETURN RET CP1: MOV CX,BUFSIZ MOV AX,DX ADD AX,FCBSIZE+BUFFER MOV BX,DX CP2: DEC CX ;REDUCE UNUSED MOV [BX]+FCBSIZE+UNUSED,CX MOV CX,AX INC CX MOV [BX]+FCBSIZE+NEXTP,CX ;NEW NEXT CHAR OFFSET MOV BX,AX MOV AX,SI ;CHAR TO PUT MOV [BX],AL ;BUFFER CHARACTER MOV BX,AX POP DS RET ; CSEG ENDS STACK SEGMENT BYTE PUBLIC 'stack' STACK ENDS DUMMY SEGMENT BYTE STACK 'dummy' DB 128 DUP(?) DUMMY ENDS END CCGO Y ENDS END CCGO