home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
cpm
/
bdsc
/
bdsc-4
/
ucsdtran.c
< prev
next >
Wrap
Text File
|
1994-07-13
|
15KB
|
577 lines
/*********************************************************************
* ucsdtran -- ucsd to cp/m transfer *
**********************************************************************
* Copyright (c) 1983 Ben Goldfarb, Orlando, FL *
* All rights reserved *
* *
* Permission is hereby granted to copy and distribute all parts *
* of this software program and associated documents for any *
* non-commercial purpose. Any use of this material for *
* commercial advantage without prior written consent of *
* the author is prohibited. *
**********************************************************************
* This program is designed to read files from a 8" (3740) floppy *
* disk that has been formatted and written by a UCSD Pascal *
* System and write them to files on the CP/M system. Following *
* is the sequence of actions: *
* o Get drive designation for UCSD disk & set up drives *
* o Read and print UCSD disk directory *
* o Get filename of file to transfer and target file *
* o Do the transfer *
* o Repeat the above til done *
* *
* UCSDTRAN properly handles UCSD Textfiles, converting them *
* to CP/M-compatible ascii files. Compressed blanks are *
* expanded and the editor formatting is undone. No conversion *
* is done to UCSD Codefiles, Datafiles, etc. *
* *
* *
* Installation requires BDS C Version 1.42 or later. If *
* a version prior to 1.50 is used, delete '#include <hardware.h>'*
* *
* *
* UCSDTRAN makes use of the alloc() function for dynamic memory *
* allocation, so be certain this feature is enabled in your *
* BDS C compiler before you attempt to compile the program. *
* (See the BDS C compiler documentation.) *
* *
* Customization: The only #define that may be necessary to *
* change is SECT0. If your disk system calls the first sector *
* on each track '0', rather than '1', you must leave SECT0 *
* defined. Otherwise, comment it out or delete the #define. *
* This is necessary because the program directly addresses the *
* appropriate track and sector on the UCSD disk; all mapping is *
* done by the program. The Godbout DISK 1 controller numbers *
* sectors from 0; most others we've seen in CP/M systems start *
* with 1. *
* *
**********************************************************************
* UCSD is a registered trademark of the Regents of the *
* University of California. *
* CP/M is a trademark of Digital Research, Inc. *
* BDS is a trademark of BD Software, Inc. *
* *
**********************************************************************
* *
* Author: Ben Goldfarb *
* Orlando, FL *
* *
* Date: 02/11/83 *
* *
* Bug reports, comments, and suggestions for improvements to: *
* USENET: ...!duke!ucf-cs!goldfarb *
* ARPANET: goldfarb.ucf-cs@Rand-Relay *
* *
**********************************************************************/
/*
* Revision Log
*
* $Log: /usr1/grad/goldfarb/cpm/src/ucsdtran.c,v $
* Revision 1.2 83/04/06 14:31:51 goldfarb
* Added facility for transferring non-Textfiles. Previously, only
* Textfiles were handled, so code was added to circumvent reformatting
* of editor text 'pages.' Type of file is detected by examining the
* 'kind' field in the UCSD directory entry for the file in question.
*
* Revision 1.1 83/04/06 13:54:34 goldfarb
* Initial revision
*
*/
#include <bdscio.h>
#include <hardware.h>
#define VERSION 12
/*
* Godbout controller kludge (see title page)
*/
#define SECT0
/* for versions with no screen handling */
#ifdef VANILLA
#undef CLEARS
#undef INTOREV
#undef OUTAREV
#define CLEARS ""
#define INTOREV ""
#define OUTAREV ""
#endif
/* Misc. ASCII defines */
#define DLE 0x10
#define CR 0x0d
#define LF 0x0a
/*
* Definitions for various CP/M 2.2 data structures.
*/
/* Absolute memory loocations */
#define BIOS_LOC 0x0001
#define IOBYTE 0x0003
#define LOGDRV 0x0004
#define BDOS_LOC 0x0006
#define FCB_1 0x005c
#define TBUFF 0x0080
/* Disk Parameter Block */
struct dpb {
unsigned spt;
char bsf;
char bm;
char nm;
unsigned dsk_siz;
unsigned dir_max;
char al0;
char al1;
unsigned chk_siz;
unsigned trk_ofs;
};
/* Disk Parameter Header */
struct dph {
char *pst_tab;
int scratch[3];
char *pdir_buf;
struct dpb *pdpb;
char *pchk;
char *ppalv;
};
/* BIOS calls */
#define SEL_DSK 9
#define SET_TRK 10
#define SET_SEC 11
#define READ 13
#define WRITE 14
/* BDOS calls */
#define INIT_BDOS 13
#define SEL_BDOS 14
#define SET_DMA 26
/* Miscellaneous CP/M constants */
#define LOG 0
#define NO_LOG 255
/* Miscellaneous UCSD constants */
#define PAGESIZE 1024
#define DIRENTRIES 77
#define DIRENTSIZE 26
/* UCSD directory structures */
struct direntry {
int firstblk, lastblk, kind;
char title[16];
int bytesinlast;
char moddate[2];
};
struct dirhdr {
int dfirstblk, dlastblk, dkind;
char dtitle[8];
int lastblkvol, filesindir, loadtime, access;
char pad[4];
};
/*
* Global Variables
*/
int ucsddrive, cpmdrive; /* Disk drive codes */
int Godbout; /* Kludge for Disk 1 */
char string[16]; /* Misc. string space */
int dirp; /* Ptr. to current dir. entry */
struct dph *pdph; /* Ptr. to disk parm header */
char buff[PAGESIZE]; /* Input buffer */
char cpmbuff[BUFSIZ]; /* Output buffer */
struct direntry dir[DIRENTRIES - 1]; /* Directory buffer */
struct dirhdr volid; /* Directory header */
main()
{
char c, error, morefiles;
/* Print program ident */
printf(CLEARS);
printf("\n\nUCSDtran version %d.%d\n",VERSION/10,VERSION%10);
printf("\n\nUCSD Pascal to CP/M transfer utility.\n\n");
printf("Copyright (c) 1983, Ben Goldfarb, Orlando, FL.\n\n");
#ifdef SECT0
Godbout = TRUE;
#else
Godbout = FALSE;
#endif
/* Initialize alligator */
_allocp = 0;
/* Input drive names */
ucsddrive = getdrive("UCSD");
cpmdrive = getdrive("CP/M");
/* Tell user where to go and reset system */
do {
error = FALSE;
printf("\n\nPut UCSD disk in Drive %c: ", ucsddrive + 'A');
printf("and CP/M disk in Drive %c:", cpmdrive + 'A');
printf("\nHit <CR> when ready: ");
while((c = getchar()) != '\n');
if ((pdph = seldsk(ucsddrive, LOG)) == NULL) {
printf("Message from drive %c: ", ucsddrive + 'A');
eprint("You better put it in!");
error = TRUE;
}
else {
if (pdph->pdpb->spt != 26 || pdph->pdpb->dsk_siz > 243 ) {
eprint("UCSD disk must be standard 3740.");
error = TRUE;
continue;
}
}
} while (error);
readdir(); /* get UCSD directory */
morefiles = TRUE;
do {
error = FALSE;
do {
printf(CLEARS);
printdir(); /* print directory */
printf("Transfer what file: ");
if ((dirp = getucsd()) == -1) {
printf("\007No such file\n");
error = TRUE;
}
} while (error);
tocpm();
printf("Transfer more files? ");
morefiles = yesno();
} while (morefiles);
}
tocpm() /* Transfer UCSD file to CP/M file */
{
char name[30], istext;
int fd, i, n;
unsigned track, sect, nsects;
/* note: skip first 1024 byte "page" of text file */
nsects = ((dir[dirp].lastblk - dir[dirp].firstblk ) * 4);
if (istext = (dir[dirp].kind == 3))
/* skip editor page for Textfile */
nsects -= 8;
block(dir[dirp].firstblk + (istext ? 2 : 0), &track, §);
/* Get filename and set up file */
printf("\nEnter CP/M file name: ");
gets(name);
printf("Creating %s...",name);
if ((fd = fcreat(name, cpmbuff)) < 0) {
printf("\n\007Can't create %s.\n",name);
return(eprint(""));
}
/* Perform the transfer */
while (nsects > 0) {
if (rwfor(&track, §, buff, (istext ? 8 : 4), READ) < 0)
return(eprint("Read error on UCSD disk."));
if (istext) /* do textfile conversion */
cpmconvert();
else /* copy raw data */
for (i = 0; i < 512; i++) putc(buff[i], cpmbuff);
nsects -= (istext? 8 : 4);
}
if (istext) putc(CPMEOF, cpmbuff);
fflush(cpmbuff);
printf("\nTransfer complete\n");
fclose(cpmbuff);
}
cpmconvert() /* output translated UCSD 1024 byte buffer to cp/m file */
{
int i, nospaces, bufptr;
char c;
bufptr = 0;
while (bufptr < 1024) {
switch(c = buff[bufptr++]) {
case DLE:
nospaces = buff[bufptr++] - 32;
for (i = 0; i < nospaces; i++)
putc(' ', cpmbuff);
break;
case CR:
putc(c, cpmbuff);
putc(LF, cpmbuff);
break;
case '\0':
break; /* ignore */
default:
putc(c, cpmbuff);
break;
}
}
}
rwfor(t,s,buff,n,rw) /* Read or write a sector from UCSD disk */
unsigned *t,*s,n,rw;
char *buff;
{
char *buffa;
/* Reset buffer */
buffa = buff;
/* Select UCSD Disk */
seldsk(ucsddrive, NO_LOG);
/* Now read or write n sectors */
while (n-- > 0) {
register unsigned ps;
bios(SET_TRK, *t);
ps = map(*s, *t);
/* Set sector (note Godbout kludge) */
bios(SET_SEC, ps + ((Godbout) ? 0 : 1));
bdos(SET_DMA, buffa);
if ((bios(rw, 0) & 1) == 1)
return(ERROR);
/* Bump track, if necessary */
if (++(*s) > 25) {
*s = 0;
(*t)++;
}
buffa += 128;
}
bdos(SET_DMA, buff);
seldsk(cpmdrive, NO_LOG);
return(OK);
}
getdrive(s) /* get disk drive designation and validate */
char *s;
{
char c;
for (;;) { /* until the dummy gets it right! */
printf("\n\nDrive for %s disk: (A - P) ", s);
if ((c = toupper(getchar())) > 'P' || c < 'A')
eprint("Drive value out of range!");
else
return(c - 'A');
}
}
yesno() /* ask for a response and return true for 'yes' */
{
char c;
return(((c = toupper(getchar())) == 'Y') ? TRUE : FALSE);
}
eprint(s) /* Print error message, hold screen, and return error */
char *s;
{
printf("\n\007");
rprintf(s);
printf("\nHit <CR> to continue: ");
getchar();
bdos(INIT_BDOS);
return(ERROR);
}
rprintf(s) /* Print in reverse video */
char *s;
{
printf(INTOREV);
printf(s);
printf(OUTAREV);
}
struct dph
*seldsk(dn, log) /* BIOS function to select drive and return dph */
char dn, log;
{
unsigned *pbios;
unsigned *psel_dsk;
pbios = BIOS_LOC;
psel_dsk = *pbios + 0x0019;
return(call(*psel_dsk, dn, 0, dn, log));
}
block(blk, track, sect) /* translates UCSD block to logical track/sector */
int blk, *track, *sect;
{
int abssector;
abssector = blk * 4;
*track = (abssector / 26) + 1;
*sect = abssector % 26;
}
map(secno, trkno) /* maps logical to physical sector */
int secno, trkno;
{
int s;
if (secno > 12)
s = ((secno * 2) + 1 + ((trkno-1) * 6 )) % 26;
else
s = ((secno * 2) + ((trkno-1) * 6)) % 26;
return(s);
}
readdir() /* read the directory on the UCSD disk */
{
int track, sect;
char *alloc(), *dirbuf;
if ((dirbuf = alloc(DIRENTRIES * DIRENTSIZE)) == 0) {
printf("Not enough memory -- aborting.\n");
exit(ERROR);
}
block(2, &track, §); /* 2 is the directory block */
rwfor(&track, §, dirbuf, 4*4, READ);
/* big kludge because no casts in BDS */
movmem(dirbuf, &volid, DIRENTSIZE);
movmem(dirbuf + DIRENTSIZE, &dir[0], (DIRENTRIES - 1) * DIRENTSIZE);
free(dirbuf);
}
printdir() /* print UCSD disk's directory */
{
int i;
char *s;
printf("Volume ID: %s\n", makestr(volid.dtitle));
for (i = 0; i < volid.filesindir; i++) {
printf("%-14s\t%3d", makestr(dir[i].title),
dir[i].lastblk - dir[i].firstblk);
printf("\t");
printdate(dir[i].moddate);
printf("\t");
switch(dir[i].kind) { /* Ain't BDS nice ? */
case 0: printf("Datafile"); break;
case 1: printf("Xdskfile"); break;
case 2: printf("Codefile"); break;
case 3: printf("Textfile"); break;
case 4: printf("Infofile"); break;
case 5: printf("Datafile"); break;
case 6: printf("Graffile"); break;
case 7: printf("Fotofile"); break;
default: printf("Foofile"); break;
}
printf("\n");
}
printf("\n");
}
char *
makestr(s) /* make a C string from UCSD variable string */
char *s;
{
int i;
char *t;
t = &string[0];
for (i = 0; i < s[0]; i++)
t[i] = s[i+1];
t[i] = '\0';
return(&string[0]);
}
printdate(d) /* prints a UCSD date record */
char d[];
{
int t1;
/*
* The UCSD format is:
*
* DATEREC = PACKED RECORD
* MONTH: 0..12;
* DAY: 0..31;
* YEAR: 0..100
* END;
*
* This routine expects a char[2] array with the
* information stored as above.
*/
t1 = (d[0] >> 4) | ((d[1] & 1) << 4);
printf("%2d", t1);
t1 = d[0] & 0x0f;
printf("-");
switch (t1) { /* because of no init in BDS */
case 1: printf("Jan"); break;
case 2: printf("Feb"); break;
case 3: printf("Mar"); break;
case 4: printf("Apr"); break;
case 5: printf("May"); break;
case 6: printf("Jun"); break;
case 7: printf("Jul"); break;
case 8: printf("Aug"); break;
case 9: printf("Sep"); break;
case 10: printf("Oct"); break;
case 11: printf("Nov"); break;
case 12: printf("Dec"); break;
default: printf("Foo"); break;
}
printf("-");
t1 = d[1] >> 1;
printf("%02d", t1);
}
getucsd() /* returns a ptr to dir entry if valid, else -1 */
{
char temp[81];
int i, j, l, found;
gets(temp);
/* see if we can find it in dir */
for (i = 0; i < volid.filesindir; i++) {
if ((l = strlen(temp)) != dir[i].title[0])
continue;
else {
found = TRUE;
for (j = 1; j <= l; j++) {
if (toupper(temp[j-1]) != dir[i].title[j]){
found = FALSE;
break;
}
}
if (found) return(i);
}
}
return(-1);
}