#asm ; ;------------------------------------------------------------------ ; Small-C Run-time Library (ASM Version) ; ; ; V3b As of June 9, 1980 12pm (rj) ; corrected cp to chp in @gets ; changed lower case to hex constants in @fopen and fcb ; V4 As of June 26, 1980 12:15pm (gtf) ; Changed all @'s and ?'s to "QZ" for ASM compatibility ; V4b As of July 7, 1980 3:00 pm (gtf) ; Changed putc() to test code returned by cput() ; V4c As of July 9, 1980 9:15 pm (gtf) ; Fixed bug in CPMIO which returned wrong error status. ; Added PUTS() function ; Un-hardwired I/O buffer count. ; Made GETCHAR() print LF after reading CR. ; Made GETCHAR() return -1 on EOF (=CTRL-Z) ; Added EOL and LF equates, instead of magic numbers ; V4d As of July 16, 1980 9:00 pm (gtf) ; Added EXIT() function ; V5 As of April 12, 1983 12:30 am (br) ; Modified to reuse package for Small-C, ver 2. ; Removed "QZ" in front of names. ; Added runtime initialization and command line ; processing from RUNTIM.MAC [by Bill Danielson, 3/83]. ; Added I/O redirection for stdin and stdout. ; Added FPUTS(), FGETS(), DOLDDR(), DOLDIR(), ; UNLINK() and ABORT() functions. ; V5a As of April 14, 1983 12:55 pm (br) ; Masked parity bit in compares for EOL, LF & ^Z. ; V5b As of July 19, 1983 9:50 pm (br) ; Fixed bug in FCLOSE(). ; V5c As of July 27, 1983 9:55 pm (br) ; Fixed bug in initialization of RSTDIN and RSTDOUT. ; Fixed bug in PUTS(). ; V5d As of July 29, 1983 7:47am (br) ; Fixed GETC()/CGET() so it skips check for CR when ; calling GETCHAR(). ;------------------------------------------------------------------ ; ; *** may need following statement when using ASM *** ORG 100H ; *** ; JMP START ; ; *** delete following extern when using ASM *** ; EXTRN MAIN, CCDSGI, CCSXT ; *** ; ; ======================================== ; I/O subroutines for CP/M ; By Glen Fisher ; The Code Works(tm) ; [modified by Bill Randle] ; ======================================== ; NULL EQU 0 ;pointer to nothing FCBSIZE EQU 36 ;size, in bytes, of an FCB NEXTP EQU 0 ;offset to next-character pointer in I/O structure UNUSED EQU 2 ;offset to unused-positions-count in I/O structure BUFFER EQU 4 ;offset to disk sector buffer in I/O structure FLAG EQU 33 ;file-type flag byte (in unused part of FCB) FREEFLG EQU 128 ;This I/O structure is available for the taking EOFFLG EQU 2 ;The end of this file has been hit WRTFLG EQU 1 ;This file open for writing BUFSIZ EQU 128 ;how long the sector buffer is NBUFS EQU 4 ;number of I/O buffers (change buffer declarations, too) ; CP/M system call codes CLOSE EQU 16 ;close a file CPMSTR EQU 9 ;print '$' delimited string on console CREATE EQU 22 ;make a file DMA EQU 26 ;set DMA (I/O address) DELETE EQU 19 ;delete a file GETCH EQU 1 ;read character from console GETSTR EQU 10 ;read string from console LSTOUT EQU 5 ;write character to list device OPEN EQU 15 ;open a file PUTCH EQU 2 ;write character to console QUERY EQU 25 ;get logged-in drive id READ EQU 20 ;read a sector SELECT EQU 14 ;log-in a drive WRITE EQU 21 ;write a sector ; LF EQU 10 ;line feed EOL EQU 13 ;end-of-line character (=carriage return) CTRLZ EQU 26 ;end-of-file mark for text files TBUFF EQU 80H ;address of default I/O address BDOS EQU 5 ;Entry point to CP/M BDOS CPMARG EQU 80H ;CP/M command line MAXARG EQU 32 ;Maximum number of args in input line STDIN EQU 0 ;Default for stdin STDOUT EQU 1 ;Default for stdout STDERR EQU 2 ;Default for stderr STDLIST EQU 4 ;Default for stdlist ; DFLTDSK: DS 1 ;drive to use if no drive is named UNIT: DS 2 ;I/O structure address to act on IP: DS 2 ;int *ip; CHP: DS 2 ;char *chp; DP: DS 2 ;char *dp; FILE: DS 2 ;file name MODE: DS 2 ;char *mode;(read or write) ZCH: DS 2 ;char ch; ZT: DS 2 ;int t; FN: DS 2 ;int fn; i/o function (for cpmio) ; SVCHP: DS 2 ;char *svchp; saved character pointer RSTDIN: DS 2 ;int rstdin; unit of redirected stdin RSTDOUT: DS 2 ;int rstdout; unit of redirected stdout ; ; First thing, we save CPM's stack pointer and current disk and ; init stdin and stdout. ; Second thing, we run through the CPM input line and ; modify it so that we can pass the C program the ; command line in the argc, argv form that it expects ; HL = pointer to next argv entry ; DE = pointer to next character in command line ; B = number of characters left in line ; C = argument count (argc) START: LXI H,0 ; Get CPM's stack pointer DAD SP SHLD STACK ; Save it for later MVI C,QUERY ; get logged-in disk CALL BDOS INR A ; make it so it will work in fcb STA DFLTDSK LDA BDOS+2 ; Get base of BDOS MOV H,A ; Save page in HL MVI L,0 SPHL ; Set stack pointer LXI H,STDIN SHLD RSTDIN ; Init rstdin LXI H,STDOUT SHLD RSTDOUT ; Init rstdout MVI C,0 ; Init argc LXI H,ARGV ; Pointer to first entry of argv array ; Unfortunately, CPM does not tell us what the first word of ; the command line was (the name of pgm), so we fake ; it by pointing it to a ascii string with 'pgmname' in it LXI D,PGM ; Pointer to 'pgmname' string CALL SVARG ; Save next argument ; Ok, now for the real stuff. Set DE pair to point to ; CPM command line and start searching for arguments LXI D,CPMARG ; Pointer to CPM arg line LDAX D ; Load # character in line MOV B,A ; Save it in B NXTSP: INX D ; Point to next character DCR B ; Decrement character count JM ENDCMD ; End of cmd line LDAX D ; Load next character in line CPI ' ' ; Space? JZ NXTSP ; Yes...continue searching CPI '>' ; Redirect output? JZ RDOUT ; Yes...open the file for output CPI '<' ; Redirect input? JZ RDINP ; Yes...open the file for input CALL SVARG ; Nope, save starting point of this arg ; Loop looking for either end of line of a space NXTCH: INX D ; Point to next character DCR B ; Decrement character count JM ENDWRD ; End of cmd line, but need to end arg LDAX D ; Load next character in line CPI ' ' ; Space? JNZ NXTCH ; Nope...keep looking MVI A,0 ; Yes, replace it with a zero byte STAX D JMP NXTSP ; Look for start of next arg ENDWRD: MVI A,0 STAX D ENDCMD: MVI B,0 ; Zero B (BC now is 16 bit argc) PUSH B ; First arg to main procedure LXI H,ARGV ; Point to argv array PUSH H ; Second argument to main procedure MVI A,2 ; Load up the argument count CALL MAIN ; Transfer to the C world.... JMP EXIT ; Return to CPM SVARG: MOV M,E ; Save pointer to start of string INX H MOV M,D INX H INR C ; Increment argc RET ARGV: DS MAXARG*2 PGM: DB 'PGMNAME',0 RDINP: CALL DEBLNK ; Skip leading spaces JM RDERR ; End of line reached PUSH H CALL CPYNAM ; Copy filename to temp buffer PUSH D ; Save registers PUSH B LXI H,NAMBUF ; Begining of filename PUSH H LXI H,RDOPN ; Mode PUSH H CALL FOPEN ; Open the file POP D POP D MOV A,H ORA L ; Check return status JZ RDERR SHLD RSTDIN ; Save unit for redirected input POP B ; Restore registers POP D POP H MVI A,0FFH CMP B ; End of command line? JZ ENDCMD JMP NXTSP ; Get next argument RDOUT: CALL DEBLNK ; Skip leading spaces JM RDERR ; End of line reached PUSH H CALL CPYNAM ; Copy filename to temp buffer PUSH D ; Save registers PUSH B LXI H,NAMBUF ; Begining of filename PUSH H LXI H,WROPN ; Mode PUSH H CALL FOPEN ; Open the file POP D POP D MOV A,H ORA L ; Check return status JZ RDERR SHLD RSTDOUT ; Save unit for redirected input POP B ; Restore registers POP D POP H MVI A,0FFH CMP B ; End of command line? JZ ENDCMD JMP NXTSP ; Get next argument DEBLNK: INX D ; Skip leading spaces DCR B RM ; End of line reached LDAX D CPI ' ' JZ DEBLNK RET CPYNAM: LXI H,NAMBUF ; Copy filename to temp buffer PUSH B ; Save reg C MVI C,16 ; Maximum filename length CPY1: MOV M,A INX D INX H DCR B JM ENDNAM DCR C JZ RDERR LDAX D CPI ' ' JNZ CPY1 ENDNAM: MVI M,0 POP H MOV C,L ; Restore reg C RET RDERR: LXI D,RDEMSG ; Error message MVI C,CPMSTR CALL BDOS ; Make sure it gets put on the terminal JMP EXIT RDOPN: DB 'r',0 WROPN: DB 'w',0 NAMBUF: DS 16 RDEMSG: DB 'iolib: Unable to open < or > file$' ; lddr(source, dest, n) DOLDDR: INX SP ; Skip over return address INX SP POP B ; Load n POP D ; Load destination POP H ; Load source DB 0EDH, 0B8H ; Do LDDR instruction PUSH H ; Restore stack PUSH D PUSH B DCX SP DCX SP RET ; doldir(source, dest, n) DOLDIR: INX SP ; Skip over return address INX SP POP B ; Load n POP D ; Load destination POP H ; Load source DB 0EDH, 0B0H ; Do LDIR instruction PUSH H ; Restore stack PUSH D PUSH B DCX SP DCX SP RET ; End of memory function ; Returns top memory location in HL TOPOFMEM: LDA BDOS+2 ; Get base of BDOS MOV H,A ; Save page in HL MVI L,0 RET ; Return the first free location FIRSTFREE: LHLD MEMRY$ RET MEMRY$:DW 0 ; This assembly routine allows CPM calls from Small C. ; ; cpm(cpmfunction#, inputparameter) ; ; Since this function returns whatever is returned in register ; it cannot be used to call ReturnVersionNumber, ReturnLoginVector, ; WriteProtectDisk, or GetAddr. CPM: POP H ; Pop rtn address POP D ; Pop input parameter in DE register pair POP B ; Pop function code into C register PUSH B ; Restore stack PUSH D PUSH H CALL BDOS ; Call CPM MOV L,A ; Sign extend A into HL register pair RLC SBB A MOV H,A RET ; exit() ; ; Stop execution of the program, ; restore the logged-in drive, ; and re-boot CP/M ; EXIT: LHLD RSTDOUT MOV A,H ORA A ; See if stdout has been redirected JZ EXIT1 PUSH H CALL FCLOSE ; If so, close the file POP B EXIT1: LDA DFLTDSK ; Grab orig. logged-in disk MOV E,A DCR E ; (cvt. back to 0-n) MVI C,SELECT ; and log it in again CALL BDOS LHLD STACK ; Load stack pointer SPHL JMP 0 ; return to CP/M STACK: DW 0 ; ; abort(reason) ; ABORT: POP B POP D PUSH D PUSH B PUSH D ; error code LXI H,ABTMSG ; Load abort message PUSH H LXI H,STDERR PUSH H CALL FPUTS POP B POP B LXI H,2 CALL CCDSGI PUSH H ; Someday this should write out the correct error code ; CALL OUTDEC## ; Inside C compiler POP B JMP EXIT ABTMSG: DB 0DH, 0DH, 'Aborted, reason = ',0 ; ; grabio() ; ; find an input buffer, and return its address. ; if there isn't one, return a NULL. ; GRABIO: ;6 May 80 rj MVI B,NBUFS LXI H,IOBUFS+FLAG LXI D,FCBSIZE+BUFFER+BUFSIZ MVI A,FREEFLG GRAB2: CMP M ;flag byte == freeflg? JZ GRAB3 ;if so, found a free buffer DAD D ;on to next buffer DCR B JNZ GRAB2 ;if there is one... LXI H,NULL ;there ain't RET ;give up GRAB3: MVI M,0 ;mark buffer as taken LXI D,-FLAG ;back up to buffer start DAD D RET ;and hand it back ; ; freeio(unit) ; ; mark a buffer as free. ; FREEIO: ;Mod 6 May 80 rj POP B ;save rtn addr POP H ;get buffer addr PUSH H ;put the stack back together PUSH B LXI D,FLAG ;find flag byte DAD D MVI M,FREEFLG ;mark buffer as 'free' LXI H,NULL ;return something RET IOBUFS: DS FCBSIZE-3 DB FREEFLG,0,0 DS BUFFER+BUFSIZ DS FCBSIZE-3 DB FREEFLG,0,0 DS BUFFER+BUFSIZ DS FCBSIZE-3 DB FREEFLG,0,0 DS BUFFER+BUFSIZ DS FCBSIZE-3 ;mod 4 May 80 rj DB FREEFLG,0,0 DS BUFFER+BUFSIZ ; ; fopen(name,mode) ; FOPEN: POP B ;get args POP H ;mode SHLD MODE POP D XCHG SHLD FILE PUSH H PUSH D PUSH B CALL GRABIO ; unit = grabio(); SHLD UNIT MOV A,H ; if(unit==NULL) ORA L ; return(NULL); RZ LXI D,FCBSIZE ; ip = unit+FCBSIZE; DAD D SHLD IP LHLD IP ; ip[NEXTP] = &ip[BUFFER]; LXI D,BUFFER DAD D XCHG LHLD IP LXI B,NEXTP DAD B MOV M,E INX H MOV M,D LHLD UNIT ; fcb(unit,name); PUSH H LHLD FILE PUSH H CALL FCB POP H POP H LHLD UNIT ; cpmdisk(*unit); MOV L,M MVI H,0 PUSH H CALL CPMDISK POP H LHLD MODE ; if(*mode=='r' || *mode=='R'){ MOV A,M CPI 72H ; 'r' ? 9 Jun 80 rj JZ FOPIF0 CPI 52H ; 'R' ? 9 Jun 80 rj JNZ FOPIF1 FOPIF0: MVI C,OPEN ; if(cpm(OPEN,unit)<0){ LHLD UNIT XCHG CALL BDOS ORA A JP FOPIF2 LHLD UNIT ; freeio(unit); PUSH H CALL FREEIO POP H LXI H,NULL ; return(NULL); RET ; } FOPIF2: LHLD IP ; ip[UNUSED] = 0; LXI D,UNUSED DAD D LXI D,0 MOV M,E INX H MOV M,D ; } JMP FOPIF4 FOPIF1: ; else if(*mode=='w' || *mode=='W'){ LHLD MODE MOV A,M CPI 77H ; 'w' 9 Jun 80 rj JZ FOPIFA CPI 57H ; 'W' 9 Jun 80 rj JNZ FOPIF5 FOPIFA: MVI C,DELETE ; cpm(DELETE,unit); LHLD UNIT XCHG CALL BDOS MVI C,CREATE ; if(cpm(CREATE,unit)<0){ LHLD UNIT XCHG CALL BDOS ORA A JP FOPIF3 LHLD UNIT ; freeio(unit); PUSH H CALL FREEIO POP H LXI H,NULL ; return(NULL); RET ; } FOPIF3: LHLD IP ; ip[UNUSED] = BUFSIZ; LXI D,UNUSED DAD D LXI D,BUFSIZ MOV M,E INX H MOV M,D LHLD UNIT ; unit[FLAG] = WRITE_FL; LXI D,FLAG DAD D MVI A,WRTFLG ORA M MOV M,A JMP FOPIF4 ; } FOPIF5: LHLD UNIT ; else{ freeio(unit); PUSH H CALL FREEIO POP H LXI H,NULL ; return(NULL); RET ; } FOPIF4: LHLD UNIT ; return(unit); RET ; ; fclose(unit) ; FCLOSE: POP B POP H SHLD UNIT PUSH H PUSH B MOV A,H ; if (unit<256) ORA A ; /* assume stdin, stdout, etc. */ MVI L,0 RZ ; return NULL; LXI H,1 ; t = 1; SHLD ZT LHLD UNIT ; if(unit[FLAG] & WRITE_FL){ LXI D,FLAG DAD D MOV A,M ANI WRTFLG JZ FCLIF1 LXI H,CTRLZ ; putc(CTRL_Z,unit); PUSH H LHLD UNIT PUSH H CALL PUTC POP H POP H LHLD UNIT ; ip = unit + FCBSIZE; LXI D,FCBSIZE DAD D SHLD IP LHLD IP ; cp = ip[NEXTP]; LXI D,NEXTP DAD D MOV E,M INX H MOV D,M XCHG SHLD CHP LHLD IP ; dp = &ip[BUFFER]+BUFSIZ; LXI D,BUFFER+BUFSIZ DAD D SHLD DP FCLWH1: ; while(cp'a'-'A') /* lower case? */ 9 Jun 80 rj JC FCBIF2 SUI 61H-41H ; A -= 'a'-'A'; 9 Jun 80 rj JMP FCBIF2 ; } FCBIF1: LDA DFLTDSK ; else A = default_drive; FCBIF2: STAX B ; *fp++ = A; INX B MVI H,' ' ; fp = fcbfill(fp,name,' ',8); MVI L,8 CALL FCBFILL MVI L,3 ; fp = fcbfill(fp,name,' ',3); CALL FCBFILL MVI H,0 ; fp = fcbpad(fp,0,4); MVI L,4 CALL FCBPAD LXI H,16 ; fp[16] = 0; DAD B MVI M,0 RET ; return; ; ; fcbfill(dest,name,pad,size) ; B D H L ; FCBFILL: MOV A,L ; while(L>0 && (A= *D)~='.' && A~=0){ ORA A JZ FILL2 LDAX D CPI '.' JZ FILL2 CPI 0 JZ FILL2 CPI 61H ; if(A>='a' && A<='z') JC FILL1 CPI 7AH+1 ; 'z' 9 Jun 80 rj JNC FILL1 SUI 61H-41H ; A = A - 'a' + 'A'; FILL1: STAX B ; *B++ = A; INX B INX D ; D++; DCR L ; L--; JMP FCBFILL ; } FILL2: LDAX D ; while(*D~='.' && *D~=0) CPI '.' JZ FILL3 CPI 0 JZ FILL3 INX D ; D++; JMP FILL2 FILL3: CPI '.' ; if(*D=='.') JNZ FILL4 INX D ; D++; FILL4: ; fall into... ; ; fcbpad(dest,pad,size) ; B H L ; FCBPAD: MOV A,L ; while(L>0){ ORA A JZ PAD2 MOV A,H ; *B++ = H; STAX B INX B DCR L ; L--; JMP FCBPAD ; } PAD2: RET ; return; ; ; getc(unit) ; FGETC: GETC: POP B POP H ; get args PUSH H PUSH B ; c=cget(unit); PUSH H CALL CGET POP D MOV A,L ; if(c=='\r') ANI 7FH ; /* mask parity in compare */ CPI EOL JNZ GETCRET PUSH H ; cget(unit); PUSH D ; /* to skip LF */ CALL CGET POP H POP H GETCRET: RET ; ; cget(unit) ; CGET: POP D POP H PUSH H PUSH D MOV A,H ORA A ; if(unit < 256) { JNZ CGET1 ; /* assume stdin */ CALL GETCHAR ; getchar(); POP D ; /* return to caller of getc() POP D ; to bypass CR check */ RET ; return; } CGET1: SHLD UNIT LXI D,FLAG ; if(unit[FLAG] & EOF_FL) DAD D MOV A,M ANI EOFFLG JZ GTCIF1 LXI H,-1 ; return(-1); RET GTCIF1: LHLD UNIT ; ip = unit + FCBSIZE; LXI D,FCBSIZE DAD D SHLD IP LXI D,NEXTP ; cp = ip[NEXTP]; DAD D MOV E,M INX H MOV D,M XCHG SHLD CHP LHLD IP ; if(ip[UNUSED]==0){ LXI D,UNUSED DAD D MOV A,M INX H ORA M JNZ GTCIF2 LXI H,READ ; if(cpmio(READ,unit)~=0) PUSH H LHLD UNIT PUSH H CALL CPMIO POP D POP D MOV A,H ORA L JZ GTCIF3 LXI H,-1 ; return(-1); RET GTCIF3: LHLD IP ; else { ip[UNUSED] = BUFSIZ; LXI D,UNUSED DAD D LXI D,BUFSIZ MOV M,E INX H MOV M,D LHLD IP ; cp = &ip[BUFFER]; LXI D,BUFFER DAD D SHLD CHP ; } ; } GTCIF2: LHLD IP ; ip[UNUSED]--; LXI D,UNUSED DAD D MOV E,M INX H MOV D,M DCX D MOV M,D DCX H MOV M,E LHLD CHP ; ip[NEXTP] = cp+1; INX H XCHG LHLD IP LXI B,NEXTP DAD B MOV M,E INX H MOV M,D LHLD CHP ; if(*cp==CTRL_Z){ MOV A,M ANI 7FH ; /* mask parity in compare */ CPI CTRLZ JNZ GTCIF4 LHLD UNIT ; unit[FLAG] |= EOF_FL; LXI D,FLAG DAD D MOV A,M ORI EOFFLG MOV M,A LXI H,-1 ; return(-1); RET ; } GTCIF4: MOV A,M MOV L,A ; return(*cp & 0377); MVI H,0 RET ; ; getchar() ; GETCHAR: LHLD RSTDIN ; if(rdstdin >= 256) { MOV A,H ; /* stdin has been redirected */ ORA A JZ GETCHR1 PUSH H CALL GETC ; getc(rdstdin); POP B ; return; RET GETCHR1: ; } else { /* read from console */ MVI C,GETCH ; t = cpm(GETCH,0) & 0377; CALL BDOS MOV L,A MVI H,0 ANI 7FH ; /* mask parity in compare */ CPI CTRLZ ; if(t==CTRLZ) JNZ GET1CHAR LXI H,-1 ; t = -1; GET1CHAR: CPI EOL ; if(t==EOL) JNZ GET2CHAR PUSH H ; putchar('\n'); MVI C,PUTCH MVI E,LF CALL BDOS POP H GET2CHAR: ; return(t); RET ; } ; ; gets(buff) ; GETS: POP B POP H PUSH H PUSH B PUSH H ; buff LHLD RSTDIN ; if(rstdin >= 256) { MOV A,H ORA A JZ GETS1 XCHG LXI H,80 PUSH H ; len PUSH D ; unit CALL FGETS ; return(fgets(buff, 80, rstdin)); POP B POP B POP B RET GETS1: POP H ; } else { SHLD CHP DCX H ; save = buff[-1]; save2 = buff[-2]; MOV D,M ; buff[-1] = 0; buff[-2] = 79; MVI M,0 DCX H MOV E,M MVI M,79 ;6 May 80 rj PUSH H PUSH D XCHG ; cpm(GETSTR,buff-2); MVI C,GETSTR CALL BDOS LHLD CHP ; buff[buff[-1]] = 0; (9 Jun 80. Was cp) DCX H MOV E,M INX H MVI D,0 DAD D MVI M,0 POP D ; buff[-1] = save; buff[-2] = save2; POP H MOV M,E INX H MOV M,D INX H MVI C,PUTCH ; putchar('\n'); MVI E,LF CALL BDOS LHLD CHP ; return(buff); RET ; } ; ; fgets(cp,len,unit) ; FGETS: INX SP ; skip rtn addr INX SP POP B ; unit POP D ; length POP H ; cp PUSH H PUSH D PUSH B DCX SP DCX SP MOV A,B ; if(unit < 256) { ORA A ; /* assume stdin */ JNZ FGETS1 PUSH H CALL GETS ; gets(cp) POP B ; return (cp); RET ; } else { FGETS1: SHLD SVCHP ; save_cp = cp; PUSH D ; keep stack right FGETS2: POP D DCX D ; while (--len) { PUSH D MOV A,D ORA E JZ FGETS4 PUSH H ; save cp PUSH B ; unit CALL GETC ; c = getc(unit); POP B MOV A,H ; if(c==EOF) /* c>255 */ ORA A JZ FGETS3 POP D ; cp LHLD SVCHP ; if (cp<>save_cp) XCHG ; /* read something */ MOV A,H CMP D JNZ FGETS4 ; goto fgets4; MOV A,L CMP E JNZ FGETS4 ; else LXI H,0 ; /* no characters */ POP D ; fix stack RET ; return (NULL); FGETS3: MOV A,L ; else { POP H MOV M,A ; *cp++ = c; INX H ANI 7FH ; /* mask parity in compare */ CPI LF ; if(c=='\n') JNZ FGETS2 FGETS4: MVI M,0 ; *cp='\0'; POP D ; fix stack LHLD SVCHP ; return save_cp; RET ; } } } } ; ; putc(c,unit) ; FPUTC: PUTC: POP B ;rtn addr POP D ;unit POP H ;c PUSH H PUSH D PUSH B MOV A,D ORA A ; if(unit < 256) { JNZ PUTC4 ; /* assume stdout, stderr */ MOV A,E ; /* or stdlist. */ CPI STDOUT ; if(unit == stdout) { JNZ PUTC1 PUSH H CALL PUTCHAR ; putchar(c); POP H RET ; return;} PUTC1: CPI STDERR ; elseif(unit == stderr) { JNZ PUTC2 CALL PUTCON ; putconsole(c); RET ; return;} PUTC2: CPI STDLIST ; elseif(unit == stdlist) { JNZ PUTC3 PUSH H CALL PUTLST ; putlist(c); POP H RET ; return;} PUTC3: JMP PTCER1 ; else goto putcerr; } PUTC4: PUSH H ; if(cput(c,unit)<0) PUSH D ; goto putcerr; CALL CPUT POP D MOV A,H ORA A JM PUTCERR MOV A,L ; if(c=='\r') CPI EOL JNZ PUTCRET LXI H,LF ; cput('\n',unit); PUSH H PUSH D CALL CPUT POP D POP D MOV A,H ORA A JM PUTCERR PUTCRET: POP H ; return(c); RET PUTCERR: ;putcerr: POP B ; return(-1); PTCER1: LXI H,-1 RET ; ; putlist(c) ; PUTLST: POP B POP D PUSH D PUSH B SHLD ZCH MVI C,LSTOUT ; cpm(LSTOUT,c); CALL BDOS LDA ZCH CPI EOL ; if(c==EOL) JNZ PUTLS1 MVI E,LF ; cpm(LSTOUT,LF); MVI C,LSTOUT CALL BDOS PUTLS1: LHLD ZCH ; return(c & 0377) MVI H,0 RET ; ; cput(c,unit) ; CPUT: POP B POP D POP H PUSH H PUSH D PUSH B SHLD ZCH XCHG SHLD UNIT LXI D,FCBSIZE ; ip = unit + FCBSIZE; DAD D SHLD IP LXI D,NEXTP ; cp = ip[NEXTP]; DAD D MOV E,M INX H MOV D,M XCHG SHLD CHP LHLD IP ; if(ip[UNUSED]==0){ LXI D,UNUSED DAD D MOV A,M INX H ORA M JNZ PTCIF1 LXI H,WRITE ; if(cpmio(WRITE,unit)~=0) PUSH H LHLD UNIT PUSH H CALL CPMIO POP D POP D MOV A,H ORA L JZ PTCIF2 LXI H,-1 ; return(-1); RET PTCIF2: LHLD IP ; else { ip[UNUSED] = BUFSIZ; LXI D,UNUSED DAD D LXI D,BUFSIZ MOV M,E INX H MOV M,D LHLD IP ; cp = &ip[BUFFER]; LXI D,BUFFER DAD D SHLD CHP ; } ; } PTCIF1: LHLD IP LXI D,UNUSED ; ip[UNUSED]--; DAD D MOV E,M INX H MOV D,M DCX D MOV M,D DCX H MOV M,E LHLD CHP ; ip[NEXTP] = cp+1; INX H XCHG LHLD IP LXI B,NEXTP DAD B MOV M,E INX H MOV M,D LDA ZCH ; return((*cp = c) & 0377); LHLD CHP MOV M,A MVI H,0 MOV L,A RET ; ; putchar(c) ; PUTCHAR: POP B POP H PUSH H PUSH B PUSH H LHLD RSTDOUT ; if(rdstdout >= 256) { MOV A,H ; /* stdout has been redirected */ ORA A JZ PUTCHR1 PUSH H CALL PUTC ; putc(c, rdstdout); POP B POP B ; return; RET PUTCHR1: ; } else { POP H PUTCON: SHLD ZCH ; /* send to console */ XCHG ; cpm(PUTCH,c); MVI C,PUTCH CALL BDOS LDA ZCH ; if(c==EOL) ANI 7FH ; /* mask parity in compare */ CPI EOL JNZ PUTCHIF1 MVI E,LF ; cpm(PUTCH,LF); MVI C,PUTCH CALL BDOS PUTCHIF1: LHLD ZCH ; return(c & 0377); MVI H,0 RET ; } ; ; puts(cp) ; PUTS: POP B ; get args POP H PUSH H PUSH B PUSH H ; cp LHLD RSTDOUT MOV A,H ; if(rstdout >= 256) { ORA A JZ PUTS1 PUSH H CALL FPUTS ; return (fputs(cp, rstdout)); POP B POP B RET PUTS1: POP H ; } else { MOV A,M ; while(*cp) ORA A JZ PUTSRET MOV E,M ; putchar(*cp++); INX H PUSH H MVI C,PUTCH CALL BDOS JMP PUTS1 PUTSRET: ; return; RET ; } ; ; fputs(cp,unit) ; FPUTS: POP B POP D ; unit POP H ; cp PUSH H PUSH D PUSH B FPUTS1: MOV A,M ; while((c=*cp++) <> NULL) { INX H ORA A JZ FPUTS3 PUSH H MOV C,A MVI B,0 PUSH B PUSH D CALL PUTC ; if(putc(c,unit)==EOF) POP D POP B MOV A,H ORA A JZ FPUTS2 POP B RET ; return(EOF); FPUTS2: POP H JMP FPUTS1 ; } FPUTS3: LXI H,0 RET ; return(NULL); ; ; cpmio(fn,unit) ; CPMIO: POP B POP D POP H SHLD FN XCHG SHLD UNIT PUSH D PUSH H PUSH B LHLD UNIT ; cpmdisk(*unit); MOV L,M MVI H,0 PUSH H CALL CPMDISK POP H LHLD UNIT ; ip = unit+FCBSIZE; LXI D,FCBSIZE ; cpm(DMA,&ip[BUFFER]); DAD D LXI D,BUFFER DAD D XCHG MVI C,DMA CALL BDOS LHLD FN ; t = cpm(fn,unit); MOV C,L LHLD UNIT XCHG CALL BDOS CALL CCSXT SHLD ZT MVI C,DMA ; cpm(DMA,TBUFF); LXI D,TBUFF CALL BDOS LHLD ZT ; if(t~=0) return(-1); MOV A,H ; else return(0); ORA L JNZ CPMIF1 LXI H,0 JMP CPMIF2 CPMIF1: LXI H,-1 CPMIF2: RET ; ; cpmdisk(disk) ; CPMDISK: POP D POP H PUSH H PUSH D MOV A,L ; if(d~=0) ORA H JZ DISKIF1 XCHG ; cpm(SELECT,d-1); DCX D MVI C,SELECT CALL BDOS DISKIF1: RET ; ;----------- End of Small-c library ----------- ; #endasm LECT,d-1); DCX D MVI C,SELECT CALL BDOS DISKIF1: RET ; ;----------- End of Small-