/* * Very RAW xP/M i/o routines... * * FILE: XPMIO.C * * Copyright (c) 1984,1985,1986 Tim Gary * All rights reserved. * * * 08/14/86 free_space() fixed.. * 09/02/85 Added routine to return amount of free disk space.. (in K) * 01/30/85 Allow getchar/putchar, etc.. with a single define.. default is * to exclude those routines.. * 10/28/84 uread function bug fixed (wrong byte_rem_count). * * User area for each file is kept track of for all reads/writes, not * just set when file was opened. * * If the macro MULTI_USER is defined, then file operations are for * MP/M and TURBODOS Multi-user operating systems. * * CP/M and MP/M are registered trademarks of Digital Research. * TURBODOS is a registered trademark of Software 2000, Inc. */ #define XPMIO #include "xpm.h" #define NULL 0 /* bdos call numbers.... */ #define DIRIO 6 #define SELDRV 14 /* file i/o stuff */ #define OPNFIL 15 #define CLSFIL 16 #define DELFIL 19 #define MAKFIL 22 #define SETDMA 26 #define GETALV 27 #define GETDPB 31 #define SETUSR 32 #define READRN 33 #define WRITRN 34 #define FILSIZ 35 #define SETREC 36 #define kbhit() bdos(CONSTAT,0) /* console status.. */ /* open a file .. direct cpm open, allocates a buffer for FCB/record inform of * FILE... If file exists, a simple open is done.. * if non-existant, a file is made.. * if couldn't make.. then return NULL as error... * Try and be sure to close opened files (assuming they were successfully * opened), since buffer space is dynamically allocated. */ FILE *open(name,mode) register char *name; register int mode; /* see xpm.h for modes.. */ { register FILE *fd; int err_code; /* from open file function */ if ((fd=malloc(sizeof(FILE)+1))!=NULL) { setmem(fd,sizeof(FILE),0); /* alloc memory for fcb */ setusr(fd->_user=fcbinit(name,fd)); /* setup fcb, get user area */ #ifdef MULTI_USER /* the following applies to multiuser ONLY */ if (mode & F_UNLOCK) fd->f_name[4]|=0x80; if (mode & F_RO) fd->f_name[5]|=0x80; #endif /* multi user */ fd->_bp=fd->_buffer; /* set up current char position */ if ( (err_code=bdos(OPNFIL,&fd->_fcb)) >3 || err_code<0) /* hanging to next statement set.. */ #ifdef MULTI_USER if (err_code==5) { /* file locked.. wait */ unsigned u; while (bdoshl(OPNFIL,&fd->_fcb)==5) { printf("\nQueued. "); for (u=0; u<50000; u++); } } else #endif /* multi user */ if (mode & F_RW) { if (bdos(MAKFIL,&fd->_fcb)==0xff) { close(fd); /* free up space */ fd=NULL; } } else { close(fd); fd=NULL; } } else printf("\nUnable to alloc space for file: %s\nStack near %xh ",name,&err_code); return (fd); /* return pointer to the fcb */ } /* close a file... and free up allocated space... */ close(fd) register FILE *fd; { register int code; if ((fd->_bp==NULL) || (fd==NULL)) return 0; /* 0=ok.. but no file there. */ setusr(fd->_user); /* restore file's user area */ code=bdos(CLSFIL,&fd->_fcb); /* CP/M close file */ free(fd); fd->_bp=NULL; /* in case close again */ return code==0xff ? ERROR : NULL; } /* random xP/M read.. and optional increment of record position... * if rinc=0 then no increment.. else increment by rinc sectors * The record is placed in the files buffer space (bufloc(fd)). */ read(fd,rinc) /* read one cp/m sector (128 bytes) and return # bytes read */ register FILE *fd; unsigned rinc; /* record increment.. used so can read without advance */ { register int code; bdos(SETDMA,(fd->_bp=fd->_buffer)); /* set DMA to file buffer area */ setusr(fd->_user); /* restore file user number */ if ((code=bdos(READRN,&fd->_fcb))>0) return (code); /* read random record.. */ fd->_fcb.f_record+=rinc; /* incrememt record count... */ setbuf(fd,0); /* set this to zero */ return 128; /* 128 bytes read */ } /************************************************* * Unix style read into buffer, for size bytes.. * *************************************************/ uread(fd,buf,size) FILE *fd; char *buf; unsigned size; { register unsigned rec_count,byte_rem_count; /* # of whole records, and of remaining bytes after the whole records */ setusr(fd->_user); /* restore file user number */ rec_count=(((size+128)-getbuf(fd))/128); if (rec_count!=0) rec_count--; byte_rem_count=(getbuf(fd)+size)%128; /* printf("\nrec_count=%d getbuf(fd)=%xh byte_rem_count=%d ", rec_count,getbuf(fd),byte_rem_count); */ if (getbuf(fd)!=0 && getbuf(fd)!=128) { if (size<=128-getbuf(fd)) { movmem(bufloc(fd)+getbuf(fd),buf,size); setbuf(fd,getbuf(fd)+size); return size; } else { movmem(bufloc(fd)+getbuf(fd),buf,128-getbuf(fd)); buf+=(128-getbuf(fd)); } } while (rec_count--) { bdos(SETDMA,buf); if (bdos(READRN,&fd->_fcb)>0) return ERROR; fd->_fcb.f_record++; /* incrememt record count... */ buf+=128; /* bump buffer one records worth */ } if (byte_rem_count) { if (read(fd,1)!=128) return ERROR; movmem(bufloc(fd),buf,byte_rem_count); /* mov in last bytes */ setbuf(fd,byte_rem_count); } else setbuf(fd,0); /* at zero */ return size; } /* write sector.. rinc same format as read... Writes from files buffer space */ write(fd,rinc) /* write random.. */ register FILE *fd; unsigned rinc; { register int code; /* eror return code. */ setusr(fd->_user); /* restore file user number */ bdos(SETDMA,(fd->_bp=fd->_buffer)); if ((code=bdos(WRITRN,&fd->_fcb))>0) return (code); fd->_fcb.f_record+=rinc; return 128; } rename(old, new) char *old, *new; { auto char buff[60]; register int user; user = fcbinit(old,buff); fcbinit(new,buff+16); setusr(user); if (bdos(15,buff+16) != 0xff) { bdos(16,buff+16); bdos(19,buff+16); /* delete file if was there.. */ } bdos(23,buff); /* rename */ } /* primative getc/putc function */ getc(fd) register FILE *fd; { register char ch; if (eobuf(fd)) if (read(fd,1)!=128) return EOF; /* end of file */ ch=gchar(fd); return ch!=0x1a ? ch : EOF; /* also cp/m EOF ^Z */ } putc(ch,fd) register char ch; register FILE *fd; { if (ch=='\n') putc('\r',fd); /* recursive cr/lf */ if (eobuf(fd)) if (write(fd,1)!=128) return ERROR; return pchar(fd,ch); } fputs(s,fd) register char *s; register FILE *fd; { while (*s) putc(*s++,fd); } fgets(s,fd) register char *s; register FILE *fd; { register int i; char *cp; cp=s; while ((i=getc(fd))!='\r' && i!=EOF) *cp++=i; *cp='\0'; return(s); } /* function to return amount of free disk space on logged drive..(in K) */ unsigned free_space(drive) int drive; { register struct _dpb *dpb; int tdrive; char *av; unsigned count,all; tdrive=bdos(0x19,0); bdos(0x0e,drive-1); /* remember old, select new drive */ dpb=bdoshl(GETDPB,0); av=bdoshl(GETALV,0); bdos(0x0e,tdrive); /* restore old drive */ for (all=0; all<16; all++) if ( !bit_test(&dpb->dir1_alloc,all) ) break; for (count=0; all<=(dpb->max_alloc); all++) if ( !bit_test(av,all) ) ++count; return count << (dpb->blk_shift-3); /* Return number of K free */ } bit_test(bv,bit) char *bv; unsigned bit; { return bv[bit >> 3] & (128 >> (bit & 7)); } /* further i/o defines are set up in cpm.h ... they include routines for * the following.. get buffer location * get/put char within buffer * get/set char POSition within buffer * absolute record seek (from begin of file) * relative record seek (from current pos) * detect end of buffer condition (used after get/put) * all seek positions are by 128 byte cp/m records.. */ #ifdef CON_IO /* some new char i/o routines.. NOT USED WITH METAL! */ getchar() { register int ch; while((ch=bdos(6,0xff))==0); putchar(ch); return ch; } putchar(ch) register int ch; { if (ch=='\n') bdos(6,'\r'); bdos(6,ch); return ch; } char *gets(s) char *s; { register char *cp; register int i; cp=s; while ((i=getchar()) != '\r') *cp++=i; *cp='\0'; return s; } puts(s) char *s; { while (*s) putchar(*s++); return putchar('\n'); } #endif /* CON_IO */ /* EOF xpmio.c */