include BDSYM.EQU include EPDATA IOBUFSIZ equ 2+2+2+SECSIZ .comment ` /* FGET.C - file stack functions for EP */ /* flnum should be set to 0 before 1st call */ struct _ebuf { int _fd; int _nleft; char *_nextp; char _buff[SECSIZ]; /* char _flags;*/ }; struct _ebuf fl[8]; int flnum; fopen(filename) char *filename; { struct _ebuf *iobuf; iobuf = fl[flnum]; if ((iobuf -> _fd = open(filename,0))<0) return ERROR; iobuf -> _nleft = 0; /* iobuf -> _flags = _READ;*/ flnum++; return iobuf -> _fd; } ` fopen:: pop d pop h push h push d ;unlike C version, open the file first, so don't have to save *filename lxi d,0 push d push h call open## pop d pop d ;check for error mov a,h ora a rm ;can assume HL = -1 if error ;ok, so save FD push h ; iobuf = fl[flnum]; lhld _flnum push h mov a,l cpi 8 cnc eperror## pop h lxi d,IOBUFSIZ ;86H call usmul lxi d,fl dad d shld _iob ; ; if ((iobuf -> _fd = open(filename,0))<0) return ERROR; ;already open -- stow the FD pop d mov m,e inx h mov m,d ; iobuf -> _nleft = 0; inx h xra a mov m,a inx h mov m,a ; flnum++; ;now treat as byte var. lxi h,_flnum inr m ; return iobuf -> _fd; ;DE still has FD ;} xchg ret _iob: dw 0 _flnum: dw 0 .comment ` getc() { struct _ebuf *iobuf; char c; while (flnum>0) { iobuf = fl[flnum-1]; if (!iobuf->_nleft--) /* if buffer empty, fill it up first */ { if (read(iobuf -> _fd, iobuf -> _buff, 1) <= 0) { fabort(iobuf -> _fd); flnum--; continue; } iobuf -> _nleft = SECSIZ - 1; iobuf -> _nextp = iobuf -> _buff; } if ((c = *iobuf->_nextp++) != CPMEOF) return c; else flnum--; } return EOF; } ` getc:: ; while (flnum>0) ; { .ge1: lxi h,-1 ;for error ret lda _flnum ora a rz ; iobuf = fl[flnum-1]; ;assume current value in _iob is valid ; ; if (!iobuf->_nleft--) /* if buffer empty, fill it up first */ lhld _iob inx h ;past _fd inx h mov e,m ;load _nleft inx h mov d,m ;DE = *_nleft and HL = ->_nleft + 1 ;check here for none mov a,d ora e jnz .ge3 ;*_nleft now updated at .ge3 ; { ; if (read(iobuf -> _fd, iobuf -> _buff, 1) <= 0) lxi d,1 push d ; lhld _iob ; lxi d,6 ; dad d inx h ;past high byte of _nleft inx h ;past _nextp inx h push h ;this is _buff lhld _iob mov e,m ;load _fd inx h mov d,m push d call read## pop d pop d pop d ;HL = 0 for eof? go read embedding file ;HL = ERROR? same (but this is not right) dcx h mov a,h ora a ;if ok, go update pointers and return the character jp .ge2 ; { fabort(iobuf -> _fd); ;to here when can't read any more chars, or get CPMEOF .ge4: lhld _iob ; mov d,m ; inx h ; mov e,m ; push d mov a,m call fabort## ; pop d ; flnum--; lxi h,_flnum dcr m ;also update _iob lhld _iob lxi d,-IOBUFSIZ dad d shld _iob ; continue; ; } jmp .ge1 ; iobuf -> _nleft = SECSIZ - 1; .ge2: lhld _iob inx h inx h mvi m,SECSIZ - 1 inx h mvi m,0 ; iobuf -> _nextp = iobuf -> _buff; ; } inx h ;HL = ->_nextp mov d,h mov e,l inx d inx d ;DE = ->_buff ;we may as well go ahead and load the character ldax d inx d mov m,e inx h mov m,d ;go directly to check for CPMEOF with char in A jmp .ge3x ; if ((c = *iobuf->_nextp++) != CPMEOF) return c; .ge3: ;now DE = *_nleft and HL = ->_nleft + 1 ;decr *_nleft dcx d ;and store mov m,d dcx h mov m,e ;move pointer to _nextp and load inx h inx h mov e,m inx h mov d,m ;get char at _nextp ldax d ;incr *_nextp inx d ;and store back mov m,d dcx h mov m,e .ge3x: cpi 1AH jz .ge4 mov l,a mvi h,0 ret ; else flnum--; ; } ;.ge4: cf. above .comment ` /****************************************************************/ /* Modified version of standard library function 'fgets'. */ /* (Needed to prevent overflow when dealing with WordStar */ /* document files, since b7 of CR or LF may be set, and */ /* this conceals the end of line from regular fgets.) */ /****************************************************************/ char *fgets(s) char *s; { int count, c; char *cptr; count = MAXLINE - 2; cptr = s; if ( (c = getc()) == EOF ) return NULL; /* This way, the 8A page break is effaced. Change this if need it. */ do { if (c == SOFTSP) continue; if ((*cptr++ = (c & 0x7F)) == '\n') { if (cptr>s+1 && *(cptr-2) == '\r') *(--cptr - 1) = '\n'; break; } } while (count-- && (c=getc()) != EOF ); /*if (c == CPMEOF) ungetc(c,iobuf); push back control-Z */ /* right-trim blanks and tabs */ while (cptr>s+1 && ((c = *(cptr-2)) == ' ') || c == '\t') *(--cptr - 1) = '\n'; *cptr = '\0'; return s; } ` fgets:: pop d pop h push h push d push b ;C holds c ;B holds the last c gotten, or 0 if none mvi b,0 ;no last c, so far shld _fgs shld _cptr ;cf. below ; count = MAXLINE - 2; lxi h,MAXLINE-2 shld _count ; cptr = s; ; if ( (c = getc()) == EOF ) return NULL; call getc mov c,l inx h mov a,h ora l jnz .fg1 ;(HL = NULL = 0) pop b ret ;/* This way, the 8A page break is effaced. Change this if need it. */ ; do ; { if (c == SOFTSP) continue; .fg1: mov a,c cpi SOFTSP jz .fg4 ; if ((*cptr++ = (c & 0x7F)) == '\n') .fg2: ani 7fh lhld _cptr mov m,a inx h shld _cptr cpi 0ah jnz .fg4 ; { if (cptr>s+1 && *(cptr-2) == '\r') ;If this is the first time through the loop, ; cptr = s+1, but then the last c in B will be zero. ;Also, *(cptr-2) is the last c, so the above conditions ; are met iff B = 0dh. mov a,b cpi 0dh jnz .fg5 ; lhld _cptr ; xchg ; lhld _fgs ; inx h ; call agbu ; jnc .fg3 (== .fg5) ; ; lhld _cptr ; dcx h ; dcx h ; mov a,m ; cpi 0DH ; jnz .fg3 ; *(--cptr - 1) = '\n'; ; break; ; } ; lhld _cptr ;here we got a CR-LF ;point to the LF dcx h ;now this is the end of the string shld _cptr ;point to the CR dcx h ;write a LF over it mvi m,0ah jmp .fg5 ; } while (count-- && (c=getc()) != EOF ); .fg4: lhld _count mov a,h ora l dcx h shld _count ; jz .fg5 ;(don't try to trim over long lines) jz .fg7 ;last c = old c mov b,c call getc mov c,l inx h ;check for eof or error mov a,h ora l jnz .fg1 ;To get here, the file must not have been terminated with CR-LF. ;This is not in the c-version, but the best thing seems to add a NL: lhld _cptr mvi m,0ah inx h shld _cptr ; ;/* right-trim blanks and tabs */ ; while (cptr>s+1 && ((c = *(cptr-2)) == ' ') || c == '\t') ; *(--cptr - 1) = '\n'; ; .fg5: ;We depart from the c-version: ; ;First, mark before the beginning of the string with a nul, ; saving the byte here lhld _fgs dcx h mov c,m mvi m,0 xchg ;Then starting at the last c stored, which was a LF, at cptr-1, ... lhld _cptr dcx h .fgtrim: ;go back until preceding is not blank or tab dcx h mov a,m cpi ' ' jz .fgtrim cpi 9 jz .fgtrim ;write LF over last blank or tab char, or over LF itself if there were none inx h mvi m,0ah ;and cptr points after the LF inx h shld _cptr ;Restore the byte before the string xchg mov m,c ; *cptr = '\0'; .fg7: lhld _cptr mvi m,0 ; ; return s; lhld _fgs ;} .fg8: pop b ret _fgs: dw 0 _count: dw 0 _cptr: dw 0 end