/* ** CSYSLIB -- System-Level Library Functions ** ** Copyright 1984 L. E. Payne and J. E. Hendrix ** ** Keyed in from DDJ by Earl Boebert ** ** References to auxbuf() deleted. */ #include stdio.h #include clib.def #define NOCCARGC /*no argument count passing*/ #define DIR /*compile directory option*/ /* ***************************System Variables********************** */ int _cnt=1, /*arg count for main*/ _vec[20], /*arg vectors for main*/ _status[MAXFILES] = {RDBIT, WRTBIT, RDBIT|WRTBIT}, /*status of respective file*/ _device[MAXFILES] = {CPMCON, CPMCON, CPMCON}, /*non-disk device assignments*/ _nextc[MAXFILES] = {EOF, EOF, EOF}, /*pigeonhole for ungetc bytes*/ _fcbptr[MAXFILES], /*FCB pointers for open files*/ _bufptr[MAXFILES], /*buffer pointers for files*/ _chrpos[MAXFILES], /*character position in buffer*/ _dirty[MAXFILES]; /*"true" if changed buffer*/ char *_memptr, /*pointer to free memory*/ _arg1[]="*"; /*first arg for main*/ /* ********************System-Level Functions***************** */ /* ** -- Process Command Line, Execute main(), and Exit to CP/M */ _main() { _parse(); main(_cnt,_vec); exit(0); } /* ** Parse command line and set up argc and argv. */ _parse() { char *count, *ptr; count = 128; /*CP/M command buffer address*/ ptr = _alloc(count = *count&255, YES); strncpy(ptr, 130, count-1); _vec[0]=_arg1; /*first arg="*"*/ while (*ptr) { if(isspace(*ptr)) {++ptr; continue;} switch(*ptr) { case '<': ptr = _redirect(ptr, "r", stdin); continue; case '>': if(*(ptr+1) == '>') ptr = _redirect(ptr+1, "a", stdout); else ptr = _redirect(ptr, "w", stdout); continue; default: if(_cnt < 20) _vec[_cnt++] = ptr; ptr = _field(ptr); } } } /* ** Isolate next command-line field. */ _field(ptr) char *ptr; { while(*ptr) { if(isspace(*ptr)) { *ptr = NULL; return (++ptr); } ++ptr; } return (ptr); } /* ** Redirect stdin or stdout */ _redirect(ptr, mode, std) char *ptr, *mode; int std; { char *fn; fn = ++ptr; ptr = _field(ptr); if (_open(fn, mode, std)==ERR) exit('R'); return (ptr); } /* ** ----------------File Open */ /* ** Open file on specified fd. */ _open(fn, mode, fd) char *fn, *mode; int fd; { char *fcb; if(!strchr("rwa", *mode)) return (ERR); _nextc[fd] = EOF; if(strcmp(fn,"CON:")==0) { _device[fd]=CPMCON; _status[fd]=RDBIT|WRTBIT; return (fd); } if(strcmp(fn,"RDR:")==0) { _device[fd]=CPMRDR; _status[fd]=RDBIT; return (fd); } if(strcmp(fn,"PUN:")==0) { _device[fd]=CPMPUN; _status[fd]=WRTBIT; return (fd); } if(strcmp(fn,"LST:")==0) { _device[fd]=CPMLST; _status[fd]=WRTBIT; return (fd); } if(fcb = _fcbptr[fd]) pad(fcb, NULL, FCBSIZE); else { if((fcb = _fcbptr[fd] = _alloc(FCBSIZE, YES)) == NULL || (_bufptr[fd] = _alloc(BUFSIZE, YES)) == NULL) return (ERR); } pad(_bufptr[fd], CPMEOF, BUFSIZE); _dirty[fd] = _device[fd] = _chrpos[fd] = 0; #ifdef DIR if(fn[1] == ':' && fn[2] == NULL) { /*directory file*/ pad(fcb, NULL, FCBSIZE); pad(fcb+NAMEOFF, '?', NTSIZE); if(toupper(fn[0]) != 'X') *fcb = toupper(fn[0]) - 64; _chrpos[fd] = BUFSIZE; _device[fd] = FNDFIL; _status[fd] = RDBIT; return (fd); } #endif /*DIR*/ if(!_newfcb(fn,fcb)) return (ERR); switch(*mode) { case 'r' : { if(_bdos(OPNFIL,fcb) == 255) return (ERR); _status[fd] = RDBIT; if(_sector(fd, RDRND)) _seteof(fd); break; } case 'w' : { if(_bdos(FNDFIL,fcb)!=255) _bdos(DELFIL,fcb); create: if(_bdos(MAKFIL,fcb)==255) return (ERR); _status[fd] = EOFBIT|WRTBIT; break; } default: { /*append mode*/ if(_bdos(OPNFIL,fcb)==255) goto create; _status[fd] = RDBIT; cseek(fd, -1, 2); while(fgetc(fd)!=EOF) ; _status[fd] = EOFBIT|WRTBIT; } } if(*(mode+1)=='+') _status[fd] |= RDBIT|WRTBIT; return (fd); } /* ** Create CP/M file control block from file name. ** Entry: fn = Legal CP/M file name (null terminated) ** May be prefixed by letter of drive. ** fcb = Pointer to memory space for CP/M fcb. ** Returns the pointer to the fcb. */ _newfcb(fn, fcb) char *fn, *fcb; { char *fnptr; pad(fcb+1, SPACE, NTSIZE); if(*(fn + 1) == ':') { *fcb = toupper(*fn) - 64; fnptr = fn + 2; } else fnptr = fn; if (*fnptr == NULL) return (NO); fnptr = _loadfn(fcb + NAMEOFF, fnptr, NAMESIZE); if(*fnptr == '.') ++fnptr; else if(*fnptr) return NO; fnptr = _loadfn(fcb + TYPEOFF, fnptr, TYPESIZE); if(*fnptr) return (NO); return (YES); } /* ** Load into fcb and validate file name */ _loadfn(dest, sour, max) char *dest, *sour; int max; { while(*sour && !strchr("<>.,;:=?*[]", *sour)){ if(max--) *dest++ = toupper(*sour++); else break; } return (sour); } /* ** ---------------------File Input */ /* ** Binary-stream input of one byte from fd. */ _read(fd) int fd; { char *bufloc; int ch; switch(_mode(fd)) { default: _seterr(fd); return (EOF); case RDBIT: case RDBIT|WRTBIT: } if((ch = _nextc[fd]) != EOF) { _nextc[fd] = EOF; return (ch); } switch(_device[fd]) { /*PUN & LST can't occur since they are write mode*/ case CPMCON: return(_conin()); case CPMRDR: return(_bdos(RDRINP,NULL)); default: if(_chrpos[fd]>=BUFSIZE && !_getsec(fd)) return (EOF); bufloc = _bufptr[fd] + _chrpos[fd]++; return (*bufloc); } } /* ** Console character input. */ _conin() { int ch; while(!(ch = _bdos(DCONIO, 255))); switch(ch) { case ABORT: exit(0); case LF: case CR: _conout(LF); return (_conout(CR)); case DEL: ch = RUB; default: if(ch < 32) {_conout('^'); _conout(ch+64);} else _conout(ch); return (ch); } } /* ** Read one sector from fd. */ _getsec(fd) int fd; { #ifdef DIR if(_device[fd]) { /*directory file*/ char *bp, *name, *type, *end; _bdos(SETDMA, 128); if ((name = _bdos(_device[fd], _fcbptr[fd])) == 255) { _seteof(fd); return(NO); } _device[fd] = FNDNXT; name = (name << 5) + (128 + NAMEOFF); type = name + NAMESIZE; end = name + NTSIZE; bp = _bufptr[fd] + BUFSIZE; *--bp = CR; while(--end >= name) { /*put name at end of buffer*/ if(*end == 'SPACE') continue; /*bug in DDJ*/ *--bp = *end; if (end == type) *--bp = '.'; } _chrpos[fd] = bp - _bufptr[fd]; return (YES); } #endif /*DIR*/ if (fflush(fd)) return (NO); _advance (fd); if(_sector(fd,RDRND)) { pad(_bufptr[fd], CPMEOF, BUFSIZE); _seteof(fd); return (NO); } return (YES); } /* ** ----------------File Output */ /* ** Binary-stream output of one byte to fd. */ _write(ch, fd) int ch, fd; { char *bufloc; switch (_mode(fd)) { default: _seterr(fd); return (EOF); case WRTBIT: case WRTBIT|RDBIT: case WRTBIT|EOFBIT: case WRTBIT|EOFBIT|RDBIT: } switch(_device[fd]) { /*RDR can't occur since it is read mode*/ case CPMCON: return(_conout(ch)); case CPMPUN: case CPMLST: _bdos(_device[fd], ch); break; default: if(_chrpos[fd]>=BUFSIZE && !_putsec(fd)) return (EOF); bufloc = _bufptr[fd] + _chrpos[fd]++; *bufloc = ch; _dirty[fd] = YES; } return (ch); } /* ** Console character output. */ _conout(ch) int ch; { _bdos(DCONIO, ch); return (ch); } /* ** Write one sector to fd. */ _putsec(fd) int fd; { if(fflush(fd)) return (NO); _advance(fd); pad(_bufptr[fd], CPMEOF, BUFSIZE); return (YES); } /* **---------------------Buffer Service */ /* ** Advance to next sector. */ _advance(fd) int fd; { int *rrn; rrn = _fcbptr[fd] + RRNOFF; ++(*rrn); _chrpos[fd] = 0; } /* ** Sector I/O. */ _sector(fd, func) int fd, func; { int error; _bdos(SETDMA, _bufptr[fd]); error = _bdos(func, _fcbptr[fd]); _bdos(SETDMA, 128); _dirty[fd] = NO; return (error); } /* **------------------File Status */ /* ** Return fd's open mode, else NULL. */ _mode(fd) char *fd; { if(fd < MAXFILES) return (_status[fd]); return (NULL); } /* ** Set eof status for fd and ** disable future i/o unless writing is allowed. */ _seteof(fd) int fd; { _status[fd] |= EOFBIT; } /* ** Clear eof status for fd. */ _clreof(fd) int fd; { _status[fd] &= ~EOFBIT; } /* ** Set error status for fd. */ _seterr(fd) int fd; { _status[fd] |= ERRBIT; } /* **----------------Memory Allocation */ /* ** Allocate n bytes of (possibly zeroed) memory. ** Entry: n = size of the items in bytes, ** clear = "true" if clearing is desired. ** Returns the address of the allocated block of memory ** or NULL if the requested amount of space is not availiable. */ _alloc(n, clear) char *n; int clear; { char *oldptr; if(n < avail(YES)) { if(clear) pad(_memptr, NULL, n); oldptr = _memptr; _memptr += n; return (oldptr); } return (NULL); } /* **----------------CP/M Interface */ /* ** Issue CP/M function and return result. ** Entry: c: CP/M function code (register C). ** de = CP/M parameter (register DE or E). ** Returns the CP/M return code (register A). */ _bdos(c,de) int c, de; { #asm pop h ;hold return address pop d ;load CP/M function parameter pop b ;load CP/M function number push b ;restore push d ; the push h ; stack call 5 ;call bdos mvi h,0 ; mov l,a ;return the CP/M response #endasm }