/********************************************************************* * 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 '* * * * * * 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 #include #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 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 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); }  .