From: Alan Cox Date: Wed, 27 Jun 2018 21:35:57 +0000 (+0100) Subject: cpm: tools for working with CP/M media X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=0c29d7cb60739fcd26a49cd6d38cb3455d015012;p=FUZIX.git cpm: tools for working with CP/M media These need some work but the architecture is clean and they are small unlike some of the modern tooling. --- diff --git a/Applications/cpmfs/COPYRIGHT b/Applications/cpmfs/COPYRIGHT new file mode 100644 index 00000000..4f8c3137 --- /dev/null +++ b/Applications/cpmfs/COPYRIGHT @@ -0,0 +1,33 @@ +/* + * Copyright (c) 1982, 1983, 1994 Helge Skrivervik + * + * All rights reserved. + * + * This program is free software. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Joerg Wunsch + * 4. The name of the developer may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/Applications/cpmfs/README b/Applications/cpmfs/README new file mode 100644 index 00000000..3ef19b52 --- /dev/null +++ b/Applications/cpmfs/README @@ -0,0 +1,20 @@ +Title: CPM + +Author: Helge Skrivervik + bergensveien 8, N - Oslo 9, Norway + (obsoleted) + +Net address: helge@berkeley + helge@nta-vax (norway) + now (1994) helge@mellvik.no + +Description: + +Cpm lets UNIX users read and write standard cp/m 8" floppy disks and +provides a cp/m like user interface for manipulating cp/m files. + + +Somewhat cleaned up and ANSIfied by Alan Cox for Fuzix + +This is WIP for 16bit int, a lot of type clean up is needed to begin with so +use with care and don't expect it to work on larger media types. \ No newline at end of file diff --git a/Applications/cpmfs/cpm.1 b/Applications/cpmfs/cpm.1 new file mode 100644 index 00000000..427d3997 --- /dev/null +++ b/Applications/cpmfs/cpm.1 @@ -0,0 +1,188 @@ +.TH CPM 1 "3 May 1983" +.UC 4 +.SH NAME +cpm \- read and write CP/M\*R floppy disks +.SH SYNOPSIS +.B cpm +[ options ] [ filename ] +.SH DESCRIPTION +.PP +.I Cpm +reads and writes files with an internal structure +like a CP/M file system. By default +.I cpm +assumes that the specified file has the parameters of a standard IBM format +single sided single density 8" CP/M floppy disk, i.e., 2002 records +containing 128 bytes each, of which 52 are reserved for system use and +16 (2 blocks) are used by the directory (maximum 64 directory entries). +These parameters may be changed by +specifying the appropriate flags (see below). Thus, various double +density formats may also be read and written, provided that the hardware +can handle the actual format. +.PP +The specified file may be a floppy disk drive (e.g., /dev/floppy on +an 11/780 or /dev/rrx?b if rx02 drives are available on your system), +or a standard UNIX\(tm file with the appropriate structure. Since +it may be inconvenient (and slow) to access the device directly, in +particular the console floppy on an 11/780, it is always a good idea to +copy the contents of the diskette into a standard file using +\fIdd\fP(1), e.g., +.sp +.nf + dd if=/dev/floppy of=yourfile bs=128 count=2002 +.fi +.PP +On most systems you have to be superuser to access the console +floppy and to be able to write to rx02's. +.PP +Flags: +.TP 20 +.BR \-d +display directory on standard output +.TP +.BR \-B +the files specified with the \fBc\fR or \fBC\fR flag contain binary +code rather than plain text (default) +.TP +\fB\-c \fIname1 name2\fR +copy the CP/M file \fIname1\fR to the UNIX file \fIname2\fR +.TP +\fB\-C \fIname1 name2\fR +copy the UNIX file \fIname1\fR to the CP/M file \fIname2\fR +.TP +\fB\-p \fIname\fR +copy the specified CP/M file to standard output +.TP +.BR \-i +enter interactive mode (all the above flags are turned off) +.TP +.BR \-I +force initializtion of the specified CP/M file (e.g., delete all files) +.TP +.BI \-s n +skew factor (sector interleaving); default is 6 +.TP +.BI \-b n +block size (in bytes); default is 1K bytes +.TP +.BI \-m n +max number of directory entries; default is 64 +.TP +.BI \-l n +sector size (in bytes); default is 128 +.TP +.BI \-r n +number of sectors per track; default is 26 +.TP +.BI \-t n +number of tracks; default is 77 +.TP +.BI \-R n +number of reserved tracks (i.\& e., for the bootstrap system); default is 2 +.PP +If the +.B \-i +flag is specified, the filename argument must always be present. +If the specified file does not exist, a +new file will be initialized. The +.B \-C, +.B \-c +and +.B \-p +flags are mutually exclusive. +.PP +The following commands are available in interactive mode: +.TP 24 +\fBccopyin \fIunixfile cpmfile\fR +copy UNIX binary file to CP/M +.TP +\fBccopyout \fIcpmfile unixfile\fR +copy CP/M binary file to UNIX +.TP +\fBcopyin \fIunixfile cpmfile\fR +copy UNIX text file to CP/M +.TP +\fBcopyout \fIcpmfile unixfile\fR +copy CP/M text file to UNIX +.TP +\fBdel\fR[ete] \fIfilename\fR +a synonym for \fIerase\fR +.TP +\fBdir\fR[ectory] or \fBls\fP +display directory +.TP +\fBera\fR[se] \fIfilename\fR +delete the given file +.TP +\fBhel\fR[p] +print a short description of each command +.TP +\fBlog\fR[out] or \fBexi\fR[t] +terminate, return to the shell +.TP +\fBren\fR[ame] \fIfile1 file2\fR +rename \fIfile1\fR to \fIfile2\fR +.TP +\fBtyp\fR[e] \fIfilename\fR +print CP/M file to console; if the environment variable +\fBPAGER\fR exists, it is interpreted as a command to +pipe the output through +.PP +.sp +The commands may be abbreviated as indicated by brackets. +CP/M file names are automatically converted to upper case. +The copy commands refuse to overwrite any existing files. +.PP +If the CP/M floppy file becomes full during a file transfer from UNIX, +the file is closed and the command terminated. +The data already written to the CP/M file will be saved. +.PP +The +.I copyout +command assumes that CP/M text files +have cr+lf as line terminators and removes carriage returns. +.I Copyin +adds a carriage return in front of each line-feed, and adds +a ^Z to the end of the file. The binary copy commands provide +for ``raw'' file copying, thus making it possible to copy code files +to and from diskettes. +.PP +Interrupts are recognized in interactive mode, and will return you to +the command level. +.SH FILES +/dev/floppy +.br +/dev/rrx?b +.br +/usr/new/lib/cpm.hlp +.SH SEE ALSO +dd(1), rx(4v) +.SH BUGS +CP/M user numbers are ignored, files written +to the CP/M floppy file will always have user number 0. +.PP +CP/M filename extensions containing more than 3 characters will quietly be +truncated. +.PP +Wildcards are not supported. +.PP +Binary input/output is always handled in multiples of the physical +sector size; CP/M handles it in multiples of 128 byte records. +.SH TRADEMARKS +CP/M is a registered trademark of Digital Research, Inc. +.br +UNIX is a trademark of AT&T Bell Labs. +.SH HISTORY +The original program has been written in 1982 and 1983 by +Helge Skrivervik at the University of California, Berkeley. +It has been adapted by +.if t J\(:org Wunsch +.if n Joerg Wunsch +(joerg_wunsch@uriah.sax.de), +to make it work with double density disks, especially with those having +block numbers > 255. After getting written permission by +Helge Skrivervik to redistribute the program under a Berkeley-style +Copyright, it has been made available with the FreeBSD distribution +in 1994. +.SH AUTHOR +Helge Skrivervik (now [1994] helge@mellvik.no) diff --git a/Applications/cpmfs/src/bitmap.c b/Applications/cpmfs/src/bitmap.c new file mode 100644 index 00000000..7788e24e --- /dev/null +++ b/Applications/cpmfs/src/bitmap.c @@ -0,0 +1,156 @@ +/* bitmap.c 1.9 83/05/13 */ + +#include +#include +#include +#include + +#include "cpm.h" + +int bm_size; + +/* + * Bit map handling routines; + * - build the disk allocation bit map + * - allocate a new block + * - dump the bitmap in hex to stdout (debugging) + * - count the number of blocks in use + * Note: the first block is number zero and the + * directory always occupies the first few blocks, + * depending on the disk format. For a standard + * SSSD disk the blocks are numbered 0 thru 243 and + * the directory occupies blocks 0 and 1. + */ + +/* + * Allocate a new disk block, return NULL if disk full + */ +int alloc(void) +{ + int i, j, blk; + + /* FIXME use ptr and ++ for bitmap */ + for (i = 0; i < bm_size; i++) { + j = ffc(0, INTSIZE, *(bitmap + i)); + if (j < INTSIZE) + break; + } + blk = i * INTSIZE + j; + if (blk >= (seclth * sectrk * (tracks - 2)) / blksiz) + return ('\0'); + *(bitmap + i) |= (1 << j); /* set the appropriate bit in the bitmap */ +#ifdef DEBUG + printf("block number allocated: %d (0x%x)\n", blk, blk); + dbmap("new bitmap:"); +#endif + return blk; +} + + +/* + * Dump the bitmap in hex to stdout, used only for debugging + */ + +void dbmap(const char *str) +{ +#ifdef DEBUG + + int i; + + printf("%s\n", str); + for (i = 0; i < bm_size; i++) + printf("%.8x\n", *(bitmap + i)); +#endif +} + +/* + * Return the number of bloks used in the + * directory, including the directory blocks + */ + +int blks_used(void) +{ + + int j, i, temp; + int buse = 0; + + for (i = 0; i < bm_size; i++) { + if (*(bitmap + i) == 0) + continue; + if (*(bitmap + i) == -1) { + buse += INTSIZE; + } else { + temp = *(bitmap + i); + for (j = 0; j < INTSIZE; j++) { + if (1 & temp) + ++buse; + temp >>= 1; + } + } + } + return buse; +} + + +void build_bmap(void) +{ + + int i, j, offset, block; + + bm_size = 1 + ((seclth * sectrk * (tracks - restrk)) / blksiz) / INTSIZE; + + if (!bitmap) { + if ((bitmap = malloc(bm_size * 4)) == NULL) { + printf("can't allocate memory for bitmap\n"); + exit(1); + } + } + /* + * clear bitmap + */ + for (i = 0; i < bm_size; i++) + bitmap[i] = 0; + + /* i equals the number of blocks occupied by the directory */ + i = (maxdir * 32) / blksiz; + + /* set the directory blocks busy in the bitmap */ + *bitmap = (1 << i) - 1; + for (i = 0; i < maxdir; i++) { + if ((dirbuf + i)->status != (char) 0xe5) { +#ifdef DEBUG + printf("%d ->%8s\n", i, (dirbuf + i)->name); +#endif + if (use16bitptrs) + for (j = 0; (j < 8) && (((dirbuf + i)->pointers[2 * j] != '\0') + || ((dirbuf + i)->pointers[2 * j + 1] != '\0')); j++) { + block = (0xff & (int) (dirbuf + i)->pointers[2 * j]) + + (0xff00 & ((int) (dirbuf + i)->pointers[2 * j + 1] << 8)); + offset = block / INTSIZE; +#ifdef DEBUG + printf("blk:%d, offs:%d, bit:%d\n", block, offset, block % INTSIZE); +#endif + if (offset < 0 || offset > bm_size * 4) { + fprintf(stderr, "bad offset into bitmap, wrong format?\n"); + exit(2); + } + *(bitmap + offset) |= (1 << block % INTSIZE); + } else + for (j = 0; (j < 16) && ((dirbuf + i)->pointers[j] != '\0'); j++) { + block = 0xff & (int) (dirbuf + i)->pointers[j]; + offset = block / INTSIZE; +#ifdef DEBUG + printf("blk:%d, offs:%d, bit:%d\n", block, offset, block % INTSIZE); +#endif + if (offset < 0 || offset > bm_size * 4) { + fprintf(stderr, "bad offset into bitmap, wrong format?\n"); + exit(2); + } + *(bitmap + offset) |= (1 << block % INTSIZE); + } + } + } +#ifdef DEBUG + dbmap("initial bit map:"); +#endif +} diff --git a/Applications/cpmfs/src/blockio.c b/Applications/cpmfs/src/blockio.c new file mode 100644 index 00000000..394add65 --- /dev/null +++ b/Applications/cpmfs/src/blockio.c @@ -0,0 +1,67 @@ +/* blockio.c 1.4 83/05/13 */ + +#include +#include +#include "cpm.h" + +/* + * Get a full block or a part of a block from floppy disk file + * nsect gives the actual number of physical sectors to read. + * if nsect is negative then always read a full block. + */ + +int getblock(int blockno, char *buffer, int nsect) +{ + + int sect, track, counter; + +#ifdef DEBUG + printf("block: %d\n", blockno); +#endif + if (nsect < 0) + nsect = blksiz / seclth; + + /* Translate block number into logical track/sector address */ + sect = (blockno * (blksiz / seclth) + sectrk * restrk) % sectrk + 1; + track = (blockno * (blksiz / seclth) + sectrk * restrk) / sectrk; + /* read the block */ + for (counter = 0; counter < nsect; counter++) { + if (getpsect(track, skewtab[sect++ - 1], buffer + (seclth * counter)) + == EOF) + return EOF; + if (sect > sectrk) { + sect = 1; + track++; + } + } + return 0; +} + +/* + * Save a full block or a part of a block in floppy disk file + * If nsects is negative, write a full block. + */ + +int putblock(int blockno, char *buffer, int nsect) +{ + + int sect, track, counter; + + if (nsect < 0) + nsect = blksiz / seclth; + + /* Translate block number into logical track/sector address */ + sect = (blockno * (blksiz / seclth) + sectrk * restrk) % sectrk + 1; + track = (blockno * (blksiz / seclth) + sectrk * restrk) / sectrk; + /* write the block */ + for (counter = 0; counter < nsect; counter++) { + if (putpsect(track, skewtab[sect++ - 1], buffer + (seclth * counter)) + == EOF) + return EOF; + if (sect > sectrk) { + sect = 1; + track++; + } + } + return 0; +} diff --git a/Applications/cpmfs/src/cclose.c b/Applications/cpmfs/src/cclose.c new file mode 100644 index 00000000..038383f8 --- /dev/null +++ b/Applications/cpmfs/src/cclose.c @@ -0,0 +1,51 @@ +/* cclose.c 1.10 83/05/13 */ + +#include +#include +#include +#include "cpm.h" + +/* + * Close cp/m file + * If the file was opened for write, flush + * buffer to disk and update directory + */ + +int c_close(C_FILE * fptr) +{ + int scts = 0; + +#ifdef DEBUG + printf("c_close: cnt: %d\n", fptr->c_cnt); +#endif + if (fptr->c_flag & WRITE) { + scts = (blksiz - fptr->c_cnt) / seclth + 1; + if (fptr->c_cnt % seclth == 0) + scts--; + fptr->c_dirp->blkcnt = seclth / CPMSECSIZ * (scts + fptr->c_seccnt); + if (fptr->c_cnt < blksiz) { + /* + * zero fill to end, and flush + * the block to disk + */ + if ((fptr->c_flag & BINARY) == 0) { + /* + * add cp/m eof mark (ctrl-z) if the file + * is not a binary file + */ + *(fptr->c_buf++) = '\032'; + fptr->c_cnt--; + } + while (fptr->c_cnt-- > 0) + *(fptr->c_buf++) = '\0'; + } + if (putblock(blockno(fptr->c_blk), fptr->c_base, scts) == EOF) + return EOF; + savedir(); + } + + /* deallocate buffer memory and file descriptor */ + fptr->c_flag = 0; + free(fptr->c_base); + return 0; +} diff --git a/Applications/cpmfs/src/ccreat.c b/Applications/cpmfs/src/ccreat.c new file mode 100644 index 00000000..7b30fed1 --- /dev/null +++ b/Applications/cpmfs/src/ccreat.c @@ -0,0 +1,75 @@ +/* ccreat.c 1.9 83/05/13 */ +#include +#include +#include +#include +#include "cpm.h" + +/* + * Create cp/m file with the given file name and extension, return + * file pointer. A null pointer is returned if the file could not + * be created or if the file already exists. + */ + +C_FILE *c_creat(const char *name, const char *ext, int flag) +{ + + int i, index; + register C_FILE *fptr; + + if (searchdir(name, ext) != -1) { + fprintf(stderr, "file already exists: %s %s\n", name, ext); + return NULL; + } + if ((index = creext(-1)) < 0) { + fprintf(stderr, "c_creat: no directory space\n"); + return NULL; + } +#ifdef DEBUG + printf("directory index: %d\n", index); +#endif + + /* find free slot for file descriptor */ + for ((i = 0, fptr = c_iob); i < C_NFILE; i++, fptr++) { + if (!(fptr->c_flag)) + break; + } + if (i == C_NFILE) { + fprintf(stderr, "c_creat: too many open files\n"); + return NULL; + } + + /* + * Free file descriptor slot found, initialize and allocate buffer + * memory + */ + if ((fptr->c_buf = malloc(blksiz)) == NULL) { + fprintf(stderr, "c_creat: no memory!\n"); + return NULL; + } + fptr->c_dirp = dirbuf + index; + if ((i = alloc()) == '\0') { + fprintf(stderr, "c_creat: disk full\n"); + return NULL; + } + if (use16bitptrs) { + fptr->c_dirp->pointers[0] = i & 0xff; + fptr->c_dirp->pointers[1] = (i >> 8) & 0xff; + } else + fptr->c_dirp->pointers[0] = i; + fptr->c_dirp->status = '\0'; + fptr->c_dirp->extno = '\0'; + fptr->c_dirp->notused[0] = '\0'; + fptr->c_dirp->notused[1] = '\0'; + strncpy(fptr->c_dirp->name, name, 8); + strncpy(fptr->c_dirp->ext, ext, 3); + fptr->c_dirp->blkcnt = '\0'; + fptr->c_blk = 0; + fptr->c_base = fptr->c_buf; + fptr->c_flag = WRITE | flag; + fptr->c_ext = index; + fptr->c_seccnt = 0; + fptr->c_cnt = blksiz; + fptr->c_extno = 0; + return fptr; +} diff --git a/Applications/cpmfs/src/cfillbuf.c b/Applications/cpmfs/src/cfillbuf.c new file mode 100644 index 00000000..6227cba3 --- /dev/null +++ b/Applications/cpmfs/src/cfillbuf.c @@ -0,0 +1,28 @@ +/* cfillbuf.c 1.6 83/05/13 */ + +#include +#include "cpm.h" + +int c_fillbuf(C_FILE * fptr) +{ + + int nsect; + + if (++fptr->c_blk == (use16bitptrs ? 8 : 16)) + if (fptr->c_dirp->blkcnt == (char) 0x80) { + /* find next extent (if it exists) */ + if (getnext(fptr) == NULL) + return EOF; + } else + return EOF; + /* This seems to reccur - uninline ? */ + nsect = (fptr->c_seccnt > blksiz / seclth) ? blksiz / seclth : fptr->c_seccnt; + if (nsect == 0) + return EOF; + fptr->c_seccnt -= nsect; + if (getblock(blockno(fptr->c_blk), fptr->c_base, nsect) == EOF) + return EOF; + fptr->c_buf = fptr->c_base; + fptr->c_cnt = nsect * seclth - 1; + return (*fptr->c_buf++ & 0xff); +} diff --git a/Applications/cpmfs/src/cflsbuf.c b/Applications/cpmfs/src/cflsbuf.c new file mode 100644 index 00000000..c9962973 --- /dev/null +++ b/Applications/cpmfs/src/cflsbuf.c @@ -0,0 +1,81 @@ +/* cflsbuf.c 1.10 83/05/13 */ + +#include +#include "cpm.h" + +/* + * Flush a full block to floppy disk file + * (these routines are never called unless a full block is + * to be written) + * Create a new extent if required + */ + +int c_flush(C_FILE * fptr) +{ + + int it; + + if (!(fptr->c_flag & WRITE)) { + fprintf(stderr, "no write access"); + return EOF; + } + fptr->c_seccnt += blksiz / seclth; + /* caution: blockno() might evaluate its argument twice */ + if (putblock(blockno(fptr->c_blk), fptr->c_base, -1) == EOF) + return EOF; + fptr->c_blk++; + if (fptr->c_blk == (use16bitptrs ? 8 : 16)) { + fptr->c_dirp->blkcnt = (char) 0x80; + savedir(); + /* create new extent */ + if ((it = creext(fptr->c_ext)) == NULL) { + fprintf(stderr, "can't create new extent, current: %d\n", fptr->c_ext); + return EOF; + } + fptr->c_dirp = dirbuf + it; + fptr->c_ext = it; + fptr->c_blk = 0; + fptr->c_seccnt = 0; + fptr->c_extno++; + fptr->c_dirp->extno = fptr->c_extno; + } + fptr->c_buf = fptr->c_base; + fptr->c_cnt = blksiz; + if ((it = alloc()) == '\0') { + fprintf(stderr, "disk full\n"); + return EOF; + } + if (use16bitptrs) { + fptr->c_dirp->pointers[2 * fptr->c_blk] = it & 0xff; + fptr->c_dirp->pointers[2 * fptr->c_blk + 1] = (it >> 8) & 0xff; + } else + fptr->c_dirp->pointers[fptr->c_blk] = it; + return 0; +} + +int c_flsbuf(int c, C_FILE * fptr) +{ + if (c_flush(fptr) == EOF) + return EOF; + *(fptr->c_buf++) = c; + fptr->c_cnt--; + return c; +} + +/* + * move the contents of 'buf' into the cpm block buffer, + * flush the buffer if full (for binary file transfers) + */ + +int c_write(C_FILE * fptr, char *buf, int cnt) +{ + int i = cnt; + + while (i-- > 0) { + *(fptr->c_buf++) = *(buf++); + if (--fptr->c_cnt == 0) + if (c_flush(fptr) == EOF) + return EOF; + } + return cnt; +} diff --git a/Applications/cpmfs/src/cmdhdl.c b/Applications/cpmfs/src/cmdhdl.c new file mode 100644 index 00000000..7847328c --- /dev/null +++ b/Applications/cpmfs/src/cmdhdl.c @@ -0,0 +1,154 @@ +/* cmdhdl.c 1.10 83/07/27 */ + +#include +#include +#include +#include +#include "cpm.h" + +#ifndef HELPFILE +#define HELPFILE "/usr/local/lib/cpm.hlp" +#endif + +/* + * Write prompt to stdout. + * Read command from stdin. + * return the number of characters read. + */ + +int cmdinp(char *cmd) +{ + + int cnt = 0, c; + + while (cnt == 0) { + printf("cpm> "); + /* BUFFER OVERFLOW FIXME */ + while ((c = getchar()) != EOF && c != '\n') + cmd[cnt++] = c; + if (c == EOF) + exit(0); + cmd[cnt] = '\0'; + } + return cnt; +} + +/* + * Compare the command pointed to by cmd to the table of defined + * commands in defcmd, return the command index if found, null + * otherwise. + */ + +struct command { + char *cmd; + int lth, abbr; +} defcmd[] = { + { "directory", 9, 1}, /* 1 */ + { "rename", 6, 1}, /* 2 */ + { "copyin", 6, 0}, /* 3 */ + { "delete", 6, 1}, /* 4 */ + { "erase", 5, 1}, /* 5 */ + { "exit", 4, 1}, /* 6 */ + { "type", 4, 1}, /* 7 */ + { "help", 4, 1}, /* 8 */ + { "ls ", 2, 0}, /* 9 */ + { "logout", 6, 1}, /* 10 */ + { "ccopyin", 7, 0}, /* 11 */ + { "ccopyout", 8, 0}, /* 12 */ + { "copyout", 7, 0}, /* 13 */ + { "dump", 4, 1}, /* 14 */ + { "!! ", 2, 0}, /* 15 */ + { "", 0 } +}; + +int chkcmd(const char *cmd) +{ + int index, len; + + len = strlen(cmd); + for (index = 0; *defcmd[index].cmd != '\0'; index++) { + if ((len == 3) && defcmd[index].abbr) { + if (strncmp(defcmd[index].cmd, cmd, 3) == 0) + goto ok; + } else { + if (strncmp(defcmd[index].cmd, cmd, defcmd[index].lth) + == 0) + goto ok; + } + } + return 0; + + ok: + if (len > defcmd[index].lth) + return 0; + else + return ++index; +} + +void help(void) +{ + + FILE *fd; + int c; + + if ((fd = fopen(HELPFILE, "r")) == NULL) + printf("Can't find help file (cpm.hlp) \n"); + else /* FIXME: perf ?? */ + while ((c = getc(fd)) != EOF) + putchar(c); +} + + +/* + * Separate fname into name and extension, return 0 if + * bad file name, otherwise 1. + */ + +int namesep(const char *fname, char *name, char *ext) +{ + + int i = 0; + + strncpy(name, " ", 9); + strncpy(ext, " ", 4); + while (i < 8 && !(iscntrl(fname[i])) && fname[i] != '.') { + name[i] = fname[i]; + i++; + } +#ifdef DEBUG + printf("namesep: name=%s, len=%d ", name, i); +#endif + clean(name, 8); + if (fname[i] == '.') { + strncpy(ext, fname + i + 1, 3); + clean(ext, 3); + } else { + if (fname[i] != ' ' && fname[i] != '\0') { + fprintf(stderr, "Illegal filename\n"); + return 0; + } + } +#ifdef DEBUG + printf("name: %s, ext: %s\n", name, ext); +#endif + if (!(isalnum(name[0]))) { + fprintf(stderr, "Illegal filename\n"); + return 0; + } + return 1; +} + +void clean(char *str, int len) +{ + str[len] = '\0'; + /* Use pointers FIXME */ + while (len-- > 0) { + if (!(isspace(str[len])) && !(iscntrl(str[len]))) + break; + str[len] = ' '; + } + while (len >= 0) { + str[len] = islower(str[len]) ? toupper(str[len]) : str[len]; + len--; + } +} diff --git a/Applications/cpmfs/src/command.h b/Applications/cpmfs/src/command.h new file mode 100644 index 00000000..a4b2560e --- /dev/null +++ b/Applications/cpmfs/src/command.h @@ -0,0 +1,19 @@ +/* command.h 1.5 83/05/13 */ +/* + * Symbolic names for command indices + */ + +#define CMD_DIR 1 +#define CMD_RENAME 2 +#define CMD_ICOPY 3 +#define CMD_DELETE 4 +#define CMD_ERASE 5 +#define CMD_EXIT 6 +#define CMD_TYPE 7 +#define CMD_HELP 8 +#define CMD_LS 9 +#define CMD_LOGOUT 10 +#define CMD_ICCOPY 11 +#define CMD_OCCOPY 12 +#define CMD_OCOPY 13 +#define CMD_DUMP 14 diff --git a/Applications/cpmfs/src/copen.c b/Applications/cpmfs/src/copen.c new file mode 100644 index 00000000..91bed6cc --- /dev/null +++ b/Applications/cpmfs/src/copen.c @@ -0,0 +1,71 @@ +/* copen.c 1.7 83/05/13 */ + +#include +#include +#include "cpm.h" + +/* + * Open cp/m file with the given file name and extension, return + * file pointer. A null pointer is returned if the file could not + * be opened. mode tells whether the file is to be read, written + * or both. + */ + +C_FILE *c_open(const char *name, const char *ext, int mode) +{ + + int i, index, scnt; + register C_FILE *fptr; + + if ((index = searchdir(name, ext)) == -1) { + fnfound(name, ext); + return NULL; + } + /* test for legal mode */ + if (!(mode & RW)) { + fprintf(stderr, "open: illegal mode - %d\n", mode); + return NULL; + } +#ifdef DEBUG + printf("directory index: %d\n", index); +#endif + for ((i = 0, fptr = c_iob); i < C_NFILE; i++, fptr++) + if (!(fptr->c_flag)) + break; + if (i == C_NFILE) { + fprintf(stderr, "too many open files\n"); + return NULL; + } + +/* + * Free file descriptor slot found, initialize field, allocate + * memory and read first block. + */ + if ((fptr->c_buf = malloc(blksiz)) == NULL) { + printf("c_open: no memory!\n"); + return NULL; + } + fptr->c_extno = 0; + fptr->c_base = fptr->c_buf; + fptr->c_flag = mode; + fptr->c_blk = 0; + fptr->c_ext = index; + fptr->c_dirp = dirbuf + index; + fptr->c_seccnt = ((0xff & (dirbuf + index)->blkcnt) + (seclth / CPMSECSIZ) - 1) + / (seclth / CPMSECSIZ); + scnt = (fptr->c_seccnt > blksiz / seclth) ? blksiz / seclth : fptr->c_seccnt; +#ifdef DEBUG + printf("c_open: scnt=%d\n", scnt); +#endif + if (getblock(blockno(0), fptr->c_buf, scnt) == EOF) + return NULL; + fptr->c_cnt = seclth * scnt; + fptr->c_seccnt -= scnt; + return fptr; +} + +void fnfound(const char *name, const char *ext) +{ + printf("file not found: %s.%s\n", *name == ' '? "" : name, + *ext == ' ' ? "" : ext); +} diff --git a/Applications/cpmfs/src/copy.c b/Applications/cpmfs/src/copy.c new file mode 100644 index 00000000..55bdcb4f --- /dev/null +++ b/Applications/cpmfs/src/copy.c @@ -0,0 +1,89 @@ +/* copy.c 1.8 83/05/13 */ + +#include +#include +#include +#include +#include +#include "cpm.h" + +#define CTRL_Z 0x1a /* CP/M end-of-file */ + +/* + * copy cpmfile to unix file + */ + +void copyc(char *cmdline, int bin) +{ + + char *i; + + if ((i = strchr(cmdline, ' ')) == NULL) { + printf("too few arguments: %s\n", cmdline); + return; + } + *i = '\0'; + copy(cmdline, i + 1, bin); +} + +void copy(char *cpmfile, char *unixfile, int bin) +{ + FILE *ufid; + char name[9], ext[4]; + char *pager = 0; + C_FILE *cid; + + if (!(namesep(cpmfile, name, ext))) + return; + if ((cid = c_open(name, ext, READ)) == NULL) + return; + + if (unixfile == NULL) { + if ((pager = getenv("PAGER")) != 0 && *pager) { + /* try opening a pipe to the pager */ + if ((ufid = popen(pager, "w")) == NULL) + /* failed, use stdout */ + ufid = stdout; + } else + ufid = stdout; + } else { + if (access(unixfile, 0) == 0) { + printf("%s already exists\n", unixfile); + return; + } + if ((ufid = fopen(unixfile, "w")) == NULL) { + printf("can't open %s\n", unixfile); + return; + } + } + if (bin) + copybin(cid, ufid); + else + copytext(cid, ufid); + c_close(cid); + if (pager && *pager) + pclose(ufid); +} + +void copytext(C_FILE * cid, FILE * ufid) +{ + int c = 0; + + while (((c = c_getc(cid)) != EOF) && (c != CTRL_Z)) { + if (c != '\r') + putc(c, ufid); + } + if (isatty(fileno(ufid))) + printf("\n"); + else + fclose(ufid); +} + +void copybin(C_FILE * cid, FILE * ufid) +{ + int c = 0; + + while ((c = c_getc(cid)) != EOF) + putc(c, ufid); + fclose(ufid); +} diff --git a/Applications/cpmfs/src/cpm.c b/Applications/cpmfs/src/cpm.c new file mode 100644 index 00000000..a7d3d74f --- /dev/null +++ b/Applications/cpmfs/src/cpm.c @@ -0,0 +1,378 @@ +/* cpm.c 1.15 83/06/20 */ +/* + * This original copyright has been obsoleted, and is mentioned only + * for completeness here. - jw + */ +/* + Copyright (c) 1982, 1983 by + Helge Skrivervik, UCB. + All rights reserved. + Permission granted for use by UNIX* licencees. + UNIX is a trademark of Bell Labs. + +*/ +/* the actual copyright notice: */ +/* + * Copyright (c) 1982, 1983, 1994 Helge Skrivervik + * + * All rights reserved. + * + * This program is free software. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Joerg Wunsch + * 4. The name of the developer may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include "cpm.h" + +#define BIG 2147483647UL + +C_FILE c_iob[C_NFILE]; +int fid; + + +int dflag, cflag, iflag, tflag; +int blksiz = 1024; /* default block size */ +int tracks = 77; /* default number of tracks */ +int maxdir = 64; /* default number of directory slots per disk */ +int seclth = 128; /* default sector length [bytes] */ +int sectrk = 26; /* default number of sectors per track */ +int skew = 6; /* default sector skew factor */ +int restrk = 2; /* reserved tracks (for system) */ + +int *bitmap = 0; +struct directory *dirbuf; +int use16bitptrs; /* use 16-bit pointers in directory */ + +char *string; + +int main(int argc, char *argv[]) +{ + + char *cpmname = NULL, *unixname = NULL ; + int xflag = 0, stat = 0, Cflag = 0, Iflag = 0, Bflag = 0; + + if (argc == 1) + usage(); + for (; argc > 1 && argv[1][0] == '-'; argc--, argv++) { + switch (argv[1][1]) { + + case 0: + break; + + case 'B': + Bflag++; + continue; + + case 'd': + dflag++; + continue; + + case 'c': + if (Cflag) + stat++; + cpmname = argv[2]; + unixname = argv[3]; + argc -= 2; + argv += 2; + cflag++; + continue; + + case 'i': + if (isatty(0) && isatty(1)) + iflag++; + continue; + + case 'p': + cpmname = argv[2]; + ++argv; + --argc; + tflag++; + continue; + + case 's': + string = argv[2]; + ++argv; + skew = number(BIG); + argc--; + if ((skew < 1) || (skew > 10)) { + printf("skew factor out of range\n"); + exit(1); + } + continue; + + case 'b': + string = argv[2]; + ++argv; + blksiz = number(BIG); + argc--; + if (blksiz & 0xc3) { + printf("illegal block size: %d\n", blksiz); + exit(1); + } + continue; + + case 'm': + string = argv[2]; + ++argv; + maxdir = number(BIG); + argc--; + if ((maxdir < 64) || (tracks > 1024)) { + printf("illegal value of m-flag: %d\n", maxdir); + exit(1); + } + continue; + + case 'l': + string = argv[2]; + ++argv; + seclth = number(BIG); + argc--; + if ((seclth < 128) || (tracks > 1024)) { + printf("illegal sector length: %d\n", seclth); + exit(1); + } + continue; + + case 'R': + string = argv[2]; + ++argv; + restrk = number(BIG); + argc--; + if (restrk < 0) { + printf("illegal # res'd tracks: %d\n", restrk); + exit(1); + } + continue; + + case 't': + string = argv[2]; + ++argv; + tracks = number(BIG); + argc--; + if (tracks < 0 || tracks > 1024) { + printf("illegal # of tracks: %d\n", tracks); + exit(1); + } + continue; + + case 'r': + string = argv[2]; + ++argv; + sectrk = number(BIG); + argc--; + if (sectrk > 48) { + printf("illegal r-flag: %d\n", sectrk); + exit(1); + } + continue; + + case 'C': + if (cflag) + stat++; + cpmname = argv[3]; + unixname = argv[2]; + argc -= 2; + argv += 2; + Cflag++; + continue; + + case 'I': + Iflag++; + continue; + +#ifdef DEBUG + case 'x': + xflag++; + continue; +#endif + + default: + printf("Illegal flag: -%c\n", argv[1][1]); + stat++; + } + break; + } + if (stat > 0) { + } + /* 16-bit pointers are used if the number of blocks exceeds 255 */ + use16bitptrs = ((tracks - restrk) * sectrk * seclth) / blksiz > 255; + + if (argc <= 1 && iflag) { + printf("cpm: can't copy from stdin in interactive mode\n"); + exit(1); + } else { + if (argc <= 1) + fid = fileno(stdin); + else { + int ic, mode = O_RDWR; + argv++; + again: + if ((fid = open(*argv, mode)) == -1) { + if (errno == ENOENT) { + /* + * The specified input file does not exist, + * does the user want to initialize a new + * file? + */ + + printf("Input file \"%s\" does not exist.\n", *argv); + printf("Initialize new floppy file? (y/n)?"); + if ((ic = getchar()) != 'y' && ic != 'Y') + exit(1); + fid = initcpm(*argv); + ic = getchar(); /* get */ + } else { + if (mode == O_RDWR) { + fprintf(stderr, "Cannot open input file \"%s\" read/write, trying read-only\n", *argv); + mode = O_RDONLY; + goto again; + } + perror("Cannot open input file"); + exit(1); + } + } else { + if (Iflag) { + printf("Initialize floppy file? (y/n)?"); + if ((ic = getchar()) != 'y' && ic != 'Y') + exit(1); + fid = initcpm(*argv); + ic = getchar(); /* get */ + } + } + } + } + /* allocate memory for the directory buffer */ + if ((dirbuf = (struct directory *) malloc(maxdir * 32)) == NULL) { + printf("can't allocate memory for directory\n"); + exit(1); + } + gen_sktab(); + getdir(); + build_bmap(); +#ifdef DEBUG + if (xflag > 0) { + int i; + char ch; + + dbmap("current bitmap:\n"); + for (i = (int) dirbuf; i < (int) dirbuf + maxdir * 32; i++) { + ch = *(char *) i; + putchar((int) ch); + } + } +#endif + + /* ignore broken pipes (could happen if someone aborts a PAGER) */ + signal(SIGPIPE, SIG_IGN); + + if (iflag > 0) { + interact(); + exit(0); + } + if (dflag > 0) + dispdir(); + if (cflag > 0) { + if (cpmname == NULL || unixname == NULL) + usage(); + copy(cpmname, unixname, Bflag); + exit(0); + } + if (Cflag > 0) { + if (cpmname == NULL || unixname == NULL) + usage(); + pipc(unixname, cpmname, Bflag); + exit(0); + } + if (tflag > 0) { + if (cpmname == NULL) + usage(); + copy(cpmname, NULL, 0); + exit(0); + } +} + + +/* Look at needed types carefully - uint16_t or uint32_t ?? */ +int number(int big) +{ + register char *cs; + long n; + + cs = string; + n = 0; + while (*cs >= '0' && *cs <= '9') + n = n * 10 + *cs++ - '0'; + for (;;) + switch (*cs++) { + + case 'k': + n *= 1024; + continue; + + case 'w': + n *= sizeof(int); + continue; + + case 'b': + n *= 512; + continue; + + case '*': + case 'x': + string = cs; + n *= number(BIG); + + case '\0': + if (n >= big || n < 0) { + fprintf(stderr, "number: argument %D out of range\n", n); + exit(1); + } + return (n); + } +} + +void usage(void) +{ + printf("Usage: cpm [-i][-d][-p name][-c|C name1 name2] file-name\n"); + printf("Disk geometry options:\n"); + printf(" -s skew [6]\n"); + printf(" -b block size [1k]\n"); + printf(" -m max dir ents [64]\n"); + printf(" -l sec size [128]\n"); + printf(" -r secs per trk [26]\n"); + printf(" -t tracks [77]\n"); + printf(" -R resvd trks [2]\n"); + exit(1); +} diff --git a/Applications/cpmfs/src/cpm.h b/Applications/cpmfs/src/cpm.h new file mode 100644 index 00000000..726cdbcb --- /dev/null +++ b/Applications/cpmfs/src/cpm.h @@ -0,0 +1,118 @@ +/* cpmio.h 1.4 83/05/13 */ +#define INTSIZE 16 /* number of bits per integer on this particular machine */ + +extern int fid; + +/* FIXME force packed */ +extern struct directory { + char status; /* status of this entry; equals 0xe5 if */ + /* free to use, otherwise contains the */ + /* user number (owner) (0 - 15) */ + char name[8]; /* File name, padded with blanks */ + char ext[3]; /* file name extension, padded with blanks */ + char extno; /* extent number */ + char notused[2]; /* unused */ + char blkcnt; /* record count, number of 128 byte records */ + /* in this extent */ + char pointers[16]; /* pointers to the individual blocks */ +} *dirbuf; + +#define CPMSECSIZ 128 /* number of bytes per sector in CP/M terms */ + +/* FIXME: uninline for size */ +#define blockno(i) (use16bitptrs? \ + (0xff & (int)fptr->c_dirp->pointers[2*(i)]) + \ + ((0xff & (int)fptr->c_dirp->pointers[2*(i)+1]) << 8): \ + 0xff & (int)fptr->c_dirp->pointers[i]) + +extern int dflag, cflag, iflag, tflag; +extern int blksiz; +extern int tracks; +extern int maxdir; + +extern int seclth; +extern int sectrk; +extern int skew; +extern int restrk; /* reserved tracks (for system) */ + +extern int *bitmap, *skewtab; +extern int bm_size; +extern int use16bitptrs; +/* cpmfio.h 1.5 83/05/13 */ + +#define C_NFILE 5 /* max number of concurrently open cp/m files */ + +typedef struct c_iobuf { + int c_cnt; /* bytes left in buffer */ + int c_blk; /* block number within the current extent */ + /* (starting at 0) */ + int c_seccnt; /* number of physical sectors left in */ + /* the current extent */ + int c_ext; /* current extent's directory index */ + int c_extno; /* extent number within current file */ + char *c_buf; /* next character position */ + char *c_base; /* location of buffer */ + short c_flag; /* access mode (READ or WRITE) */ + struct directory *c_dirp; /* pointer to the current */ + /* extent's directory entry */ +} C_FILE; +extern C_FILE c_iob[C_NFILE]; + +#define c_getc(p) (--(p)->c_cnt>=0 ? *(p)->c_buf++&0377 : c_fillbuf(p)) +#define c_putc(x,p) (--(p)->c_cnt>=0 ? ((int)(*(p)->c_buf++=(unsigned)(x))) : c_flsbuf((unsigned)(x), p)) + +#define READ 0x01 +#define WRITE 0x02 +#define RW 0x03 +#define MODFLG 0x08 +#define BINARY 0x10 + +extern int alloc(void); +extern void dbmap(const char *str); +extern int blks_used(void); +extern void build_bmap(void); + +extern int getblock(int blockno, char *buffer, int nsect); +extern int putblock(int blockno, char *buffer, int nsect); + +extern int c_close(C_FILE * fptr); +extern C_FILE *c_creat(const char *name, const char *ext, int flag); +extern int c_fillbuf(C_FILE * fptr); +extern int c_flush(C_FILE * fptr); +extern int c_flsbuf(int c, C_FILE * fptr); +extern int c_write(C_FILE * fptr, char *buf, int cnt); +extern int cmdinp(const char *cmd); +extern int chkcmd(const char *cmd); +extern void help(void); +extern int namesep(const char *fname, char *name, char *ext); +extern void clean(char *str, int len); +extern C_FILE *c_open(const char *name, const char *ext, int mode); +extern void fnfound(const char *name, const char *ext); +extern void copyc(char *cmdline, int bin); +extern void copy(char *cpmfile, char *unixfile, int bin); +extern void copytext(C_FILE * cid, FILE * ufid); +extern void copybin(C_FILE * cid, FILE * ufid); +extern int number(int big); +extern void usage(void); +extern void delete(const char *cmdline); +extern void dispdir(void); +extern void getdir(void); +extern void savedir(void); +extern int searchdir(const char *name, const char *ext); +extern int creext(int curext); +extern int getnext(C_FILE * cur); +extern int ffc(int start, int len, long field); +extern void gen_sktab(void); +extern void dump(const char *cmdline); +extern void hexdump(C_FILE * fp); +extern void printline(FILE * piped, int *cbuf, int nc); +extern void interact(void); +extern void intrpt(int sig); +extern int putpsect(int tr, int sect, const char *buf); +extern int getpsect(int tr, int sect, const char *buf); +extern int initcpm(const char *name); +extern void pip(char *cmdline, int bin); +extern void pipc(const char *unixfile, const char *cpmfile, int bin); +extern void piptext(C_FILE * cid, FILE * ufid); +extern void pipbin(C_FILE * cid, FILE * ufid); +extern int Rename(char *cmdline); diff --git a/Applications/cpmfs/src/delete.c b/Applications/cpmfs/src/delete.c new file mode 100644 index 00000000..07513f6f --- /dev/null +++ b/Applications/cpmfs/src/delete.c @@ -0,0 +1,38 @@ +/* delete.c 1.6 83/05/13 */ + +#include +#include +#include "cpm.h" + +/* + * Delete cp/m file + */ + +void delete(const char *cmdline) +{ + + char name[9], ext[4]; + C_FILE *cio; + + if (!(namesep(cmdline, name, ext))) + return; + if (searchdir(name, ext) != -1) { + cio = c_open(name, ext, READ); + cio->c_dirp->status = (char) 0xe5; + while (cio->c_dirp->blkcnt == (char) 0x80 && getnext(cio) != 0) + cio->c_dirp->status = (char) 0xe5; + } else { + printf("File not found: %s %s\n", name, ext); + return; + } + savedir(); + c_close(cio); + /* + * rebuild the bitmap completely instead of recovering + * each block as they are deleted + */ + build_bmap(); + if (ext[0] == ' ') + ext[0] = '\0'; + printf("%s %s deleted\n", name, ext); +} diff --git a/Applications/cpmfs/src/dirhdl.c b/Applications/cpmfs/src/dirhdl.c new file mode 100644 index 00000000..fd389487 --- /dev/null +++ b/Applications/cpmfs/src/dirhdl.c @@ -0,0 +1,105 @@ +/* dirhdl.c 1.7 83/05/13 */ + +#include +#include +#include +#include +#include "cpm.h" + +/* Display cp/m directory on stdout */ + +void dispdir(void) +{ + + int cnt, i; + int filecnt = 0; + int blkcnt; + char name[8], ext[3]; + + for (cnt = 0; cnt < maxdir; cnt++) { + if ((dirbuf + cnt)->status != (char) 0xe5) { + if ((dirbuf + cnt)->extno == '\0') { + strncpy(name, (dirbuf + cnt)->name, 8); + strncpy(ext, (dirbuf + cnt)->ext, 3); + for (i = 0; i < 8; i++) + name[i] &= 0x7f; + for (i = 0; i < 3; i++) + ext[i] &= 0x7f; + printf("%.8s %.3s", name, ext); + if (++filecnt % 4 == 0) + printf("\n"); + else + printf(" : "); + } + } + } + blkcnt = blks_used(); + if (filecnt % 4 > 0) + printf("\n"); + if (filecnt == 0) + printf("No files\n"); + else + printf("Total of %d files. %d blocks used, %d blocks free.\n", filecnt, blkcnt, seclth * sectrk * (tracks - 2) / blksiz - blkcnt); +} + +void getdir(void) +{ + int bl, blks; + int offset = 0; + + blks = maxdir * 32 / blksiz; + if ((maxdir * 32) % blksiz > 0) + ++blks; + for (bl = 0; blks > 0; bl++, blks--) { + if (getblock(bl, ((char *)dirbuf) + offset, -1) == EOF) { + fprintf(stderr, "getdir: fatal error\n"); + exit(0); + } + offset += blksiz / 32; + } +} + + +void savedir(void) +{ + + int bl, blks; + int offset = 0; + + blks = maxdir * 32 / blksiz; + if ((maxdir * 32) % blksiz > 0) + ++blks; + for (bl = 0; blks > 0; bl++, blks--) { + if (putblock(bl, ((char *)dirbuf) + offset, -1) == EOF) { + fprintf(stderr, "savedir: fatal error\n"); + exit(0); + } + offset += blksiz / 32; + } +} + +/* Search the cp/m directory for the file given by the input + * parameters, return -1 if not found, + * directory index to the file's first extent is + * returned if found. + */ + +int searchdir(const char *name, const char *ext) +{ + int ind, i; + char cname[8], cext[3]; + + for (ind = 0; ind < maxdir; ++ind) { + strncpy(cname, (dirbuf + ind)->name, 8); + strncpy(cext, (dirbuf + ind)->ext, 3); + for (i = 0; i < 8; i++) + cname[i] &= 0x7f; + for (i = 0; i < 3; i++) + cext[i] &= 0x7f; + if ((dirbuf + ind)->status == (char) 0xe5) + continue; + if ((strncmp(name, cname, 8) == 0) && (strncmp(ext, cext, 3) == 0) && ((dirbuf + ind)->extno == '\0')) + return ind; + } + return -1; +} diff --git a/Applications/cpmfs/src/extent.c b/Applications/cpmfs/src/extent.c new file mode 100644 index 00000000..c5b13ae1 --- /dev/null +++ b/Applications/cpmfs/src/extent.c @@ -0,0 +1,65 @@ +/* extent.c 1.7 83/05/13 */ + +#include +#include +#include "cpm.h" + +/* + * Allocate a new extent to the file pointed to by curext, + * or, if curext < 0, return the index of the first free + * directory slot. + * Return a negative pointer if no directory space, otherwise + * the index to the new extent. + */ + +int creext(int curext) +{ + + int i, j; + + for (i = 0; i < maxdir; i++) + if ((dirbuf + i)->status == (char) 0xe5) + break; + if (i == maxdir) + return EOF; + if (curext >= 0) + *(((char *)dirbuf) + i) = *(((char *)dirbuf) + curext); + + /* clear all file pointers */ + for (j = 0; j < 16; j++) + (dirbuf + i)->pointers[j] = '\0'; + +#ifdef DEBUG + printf("extent allocated: %d (old: %d)\n", i, curext); + printf("extent data: 0x%x, name: %s\n", (dirbuf + i)->status, (dirbuf + i)->name); +#endif + return i; +} + + +/* + * Find next extent of the file pointed to by file pointer 'current', + * return the new extent's index if found, otherwise NULL. + */ + +int getnext(C_FILE * cur) +{ + + int ind; + + cur->c_extno++; + for (ind = 0; ind < maxdir; ind++) + if ((strncmp(cur->c_dirp->name, (dirbuf + ind)->name, 8) == 0) && (strncmp((dirbuf + ind)->ext, cur->c_dirp->ext, 3) == 0) && ((dirbuf + ind)->extno == cur->c_extno)) { + cur->c_ext = ind; + cur->c_seccnt = ((0xff & (int) (dirbuf + ind)->blkcnt) + + (seclth / CPMSECSIZ) - 1) + / (seclth / CPMSECSIZ); + cur->c_dirp = dirbuf + ind; + cur->c_blk = 0; +#ifdef DEBUG + printf("getnext: dir. index: %d\n", ind); +#endif + return ind; + } + return 0; +} diff --git a/Applications/cpmfs/src/ffc.c b/Applications/cpmfs/src/ffc.c new file mode 100644 index 00000000..9287d2fc --- /dev/null +++ b/Applications/cpmfs/src/ffc.c @@ -0,0 +1,33 @@ +#include +#include +#include "cpm.h" + +/* ffc.c 1.4 83/05/13 */ + +/* + * If used on a vax (i.e., VAX is defined), this routine simply executes + * the VAX find-first-set instruction. + * Usage: + * int startbit, field_lth, field, result; + * result = ffc(startbit,field_lth,field); + * + * startbit is the bit number of the field to start the search, + * the rightmost bit is number one. + * field_lth is the length of the field in bits. + * field is the actual field + * result is the resulting bit number, + * e.g. the number of the first clear bit in the field. + * hs 10/29/82 + */ + +int ffc(int start, int len, long field) +{ /* can this be uint16_t */ + register int i; + + for (i = start; i < len; i++) { + if ((field & 1) == 0) + break; + field >>= 1; + } + return i; +} diff --git a/Applications/cpmfs/src/gensktab.c b/Applications/cpmfs/src/gensktab.c new file mode 100644 index 00000000..ab78d843 --- /dev/null +++ b/Applications/cpmfs/src/gensktab.c @@ -0,0 +1,41 @@ +/* gensktab.c 1.4 83/05/13 */ +#include +#include +#include "cpm.h" + +extern int skew; +int *skewtab; + +/* + * Generate a skew factor table in skewtab according to the + * global parameters given by skew and sectrk. + * This routine must be called before any disk (or virtual disk) + * accesses are attempted. + */ + +void gen_sktab(void) +{ + + int *i, *j; + + if ((skewtab = (int *) malloc(sectrk * 4)) == NULL) { + fprintf(stderr, "can't allocate memory for skew sector table\n"); + exit(1); + } + *skewtab = 1; + for (i = skewtab + 1; i < skewtab + sectrk; i++) { + *i = *(i - 1) + skew; + if (*i > sectrk) { + *i -= sectrk; + L1: + for (j = skewtab; j < i; j++) { + if (*j == *i) + break; + } + if (j < i) { + ++*i; + goto L1; + } + } + } +} diff --git a/Applications/cpmfs/src/hexdmp.c b/Applications/cpmfs/src/hexdmp.c new file mode 100644 index 00000000..34e38830 --- /dev/null +++ b/Applications/cpmfs/src/hexdmp.c @@ -0,0 +1,69 @@ +/* hexdmp.c 1.5 83/05/13 */ + +#include +#include +#include +#include "cpm.h" + +void dump(const char *cmdline) +{ + char name[9], ext[4]; + C_FILE *cid; + + if (!cmdline) { + printf("missing argument (file name)\n"); + return; + } + if (!(namesep(cmdline, name, ext))) + return; + if ((cid = c_open(name, ext, READ)) == NULL) + return; + hexdump(cid); + c_close(cid); +} + +void hexdump(C_FILE * fp) +{ + int c, nc = 0, cbuf[16], blcnt = 0; + char *pager; + FILE *piped; + + printf("\n"); + if ((pager = getenv("PAGER")) != 0) { + /* try opening a pipe */ + if ((piped = popen(pager, "w")) == NULL) + piped = stdout; + } else + piped = stdout; + + /* FIX to uint8_t */ + while ((c = c_getc(fp)) != EOF) { + cbuf[nc % 16] = c; + if (nc % 128 == 0) + fprintf(piped, "\n Block %04d\n", blcnt++); + if (nc % 16 == 0) + fprintf(piped, "%04x ", nc); + ++nc; + fprintf(piped, "%02x ", c); + if (nc % 16 == 0) + printline(piped, cbuf, 16); + } + if (nc % 16 != 0) + printline(piped, cbuf, nc % 16); + fprintf(piped, "\n"); + if (piped != stdout) + pclose(piped); +} + +void printline(FILE * piped, int *cbuf, int nc) +{ + int i1; + + for (i1 = 0; i1 < nc; ++i1) { + if (cbuf[i1] > 31 && cbuf[i1] < 127) + fprintf(piped, "%c", cbuf[i1]); + else + fprintf(piped, "."); + } + fprintf(piped, "\n"); +} diff --git a/Applications/cpmfs/src/interact.c b/Applications/cpmfs/src/interact.c new file mode 100644 index 00000000..1c241c38 --- /dev/null +++ b/Applications/cpmfs/src/interact.c @@ -0,0 +1,100 @@ +/* interact.c 1.8 83/07/27 */ +#include +#include +#include +#include +#include "command.h" +#include "cpm.h" + +#define errinp { printf("??\n"); break; } + +jmp_buf env; +int firsttime = 0; + +void interact(void) +{ + + int i; + char cmd[80], *rest; + + for (;;) { + if (firsttime++ == 0) { + signal(SIGINT, intrpt); + (void) setjmp(env); + } + if (cmdinp(cmd) < 0) + return; + rest = strchr(cmd, ' '); + if (rest) + *rest++ = '\0'; + i = chkcmd(cmd); +#ifdef DEBUG + printf("command: %s, ind: %d\n", cmd, i); +#endif + + switch (i) { + default: + errinp; + break; + case CMD_DIR: + case CMD_LS: + dispdir(); + break; + + case CMD_RENAME: + Rename(rest); + break; + + case CMD_OCOPY: + copyc(rest, 0); + break; + + case CMD_ICOPY: + pip(rest, 0); + break; + + case CMD_DELETE: + case CMD_ERASE: + delete(rest); + break; + + case CMD_EXIT: + case CMD_LOGOUT: + return; + + case CMD_TYPE: + copy(rest, NULL, 0); + break; + + case CMD_HELP: + help(); + break; + + case CMD_OCCOPY: + copyc(rest, 1); + break; + + case CMD_ICCOPY: + pip(rest, 1); + break; + + case CMD_DUMP: + dump(rest); + break; + + } + } +} + +/* + * handle interrupts (in interactive mode only), + * just (long)jump back to command input mode + */ + +void intrpt(int sig) +{ + /* FIXME: restore signal handler! */ + firsttime = 0; + printf("\n"); + longjmp(env, 0); +} diff --git a/Applications/cpmfs/src/physio.c b/Applications/cpmfs/src/physio.c new file mode 100644 index 00000000..de33916b --- /dev/null +++ b/Applications/cpmfs/src/physio.c @@ -0,0 +1,82 @@ +/* physio.c 1.6 83/07/18 */ + +#include +#include +#include +#include +#include "cpm.h" + +/* Again look at sizes - think we need uint16_t's */ +/* + * Write physical sector to floppy disk file + */ + +int putpsect(int tr, int sect, const char *buf) +{ + + long newpos; + + if (sect > sectrk || sect < 1) { + fprintf(stderr, "putpsect: sector number out of range: %d\n", sect); + return EOF; + } + newpos = (long) (sect + (tr * sectrk) - 1) * seclth; + if (lseek(fid, newpos, 0) == -1) { + perror("putpsect"); + return EOF; + } + if (write(fid, buf, seclth) == seclth) + return 1; + perror("putpsect"); + fprintf(stderr, "track %d, sect %d\n", tr, sect); + return EOF; +} + +/* + * Read physical sector from floppy disk file + */ + +int getpsect(int tr, int sect, const char *buf) +{ + + long newpos; + + if (sect > sectrk || sect < 1) { + fprintf(stderr, "getpsect: sector number out of range: %d\n", sect); + return EOF; + } + newpos = (long) (sect + (tr * sectrk) - 1) * seclth; + if (lseek(fid, newpos, 0) == -1) { + perror("getpsect"); + return EOF; + } + if (read(fid, buf, seclth) != seclth) { + perror("getpsect"); + fprintf(stderr, "track %d, sect %d\n", tr, sect); + return EOF; + } + return 1; +} + +/* + * Initialize a new floppy disk file in "name", + * return its file pointer. + */ + +int initcpm(const char *name) +{ + int f, i; + char buf[512]; + + if ((f = open(name, O_CREAT | O_RDWR, 0644)) < 0) + return EOF; + for (i = 0; i < 512; i++) + buf[i] = '\345'; + /* + * Initialize (with 0xe5) the first four tracks + * on the `floppy' + */ + for (i = 0; i < (4 * seclth * sectrk); i += 512) + write(f, buf, 512); + return f; +} diff --git a/Applications/cpmfs/src/pip.c b/Applications/cpmfs/src/pip.c new file mode 100644 index 00000000..e669e360 --- /dev/null +++ b/Applications/cpmfs/src/pip.c @@ -0,0 +1,76 @@ +/* pip.c 1.5 83/05/13 */ + +#include +#include +#include +#include +#include "cpm.h" + +/* + * Copy unix file to cpm + */ + +void pip(char *cmdline, int bin) +{ + + char *i; + + if ((i = strchr(cmdline, ' ')) == NULL) { + printf("too few arguments: %s\n", cmdline); + return; + } + *i = '\0'; + pipc(cmdline, i + 1, bin); +} + +void pipc(const char *unixfile, const char *cpmfile, int bin) +{ + + FILE *ufid; + char name[9], ext[4]; + C_FILE *cid; + int flag = 0; + + if ((ufid = fopen(unixfile, "r")) == NULL) { + printf("can't open %s\n", unixfile); + return; + } + if (!(namesep(cpmfile, name, ext))) + return; + if (bin) + flag = BINARY; + if ((cid = c_creat(name, ext, flag)) == NULL) + return; + if (bin) + pipbin(cid, ufid); + else + piptext(cid, ufid); + c_close(cid); + fclose(ufid); +} + +void piptext(C_FILE * cid, FILE * ufid) +{ + int c = 0; + + while ((c = getc(ufid)) != EOF) { + if (c == '\n') { + if (c_putc('\r', cid) == EOF) + break; + } + if (c_putc(c, cid) == EOF) + break; + } +} + +void pipbin(C_FILE * cid, FILE * ufid) +{ + char buf[128]; + + while (read(fileno(ufid), buf, 128) != 0) { + if (c_write(cid, buf, 128) != 128) { + fprintf(stderr, "pipbin: write error\n"); + return; + } + } +} diff --git a/Applications/cpmfs/src/rename.c b/Applications/cpmfs/src/rename.c new file mode 100644 index 00000000..f2507adf --- /dev/null +++ b/Applications/cpmfs/src/rename.c @@ -0,0 +1,48 @@ +/* rename.c 1.8 83/05/13 */ + +#include +#include +#include "cpm.h" + +/* + * Rename a cp/m file + * returns: 1 = failure, 0 = success + */ + +int Rename(char *cmdline) +{ + + C_FILE *cio; + char oldname[9], oldext[4], newname[9], newext[4]; + char *secarg; + + + if ((secarg = strchr(cmdline, ' ')) == NULL) { + printf("rename: too few arguments\n"); + return 1; + } + *secarg++ = '\0'; + if (!(namesep(cmdline, oldname, oldext))) + return 1; + if (!(namesep(secarg, newname, newext))) + return 1; + + if (searchdir(oldname, oldext) != -1) { + cio = c_open(oldname, oldext, READ); + do { + strncpy(cio->c_dirp->name, newname, 8); + strncpy(cio->c_dirp->ext, newext, 3); + } while (getnext(cio) != NULL); + } else { + fnfound(oldname, oldext); + return 1; + } + if (newext[0] == ' ') + newext[0] = '\0'; + if (oldext[0] == ' ') + oldext[0] = '\0'; + printf("renamed %s %s to %s %s\n", oldname, oldext, newname, newext); + savedir(); + c_close(cio); + return 0; +}