--- /dev/null
+/*
+ * 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.
+ */
--- /dev/null
+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
--- /dev/null
+.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)
--- /dev/null
+/* bitmap.c 1.9 83/05/13 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#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
+}
--- /dev/null
+/* blockio.c 1.4 83/05/13 */
+
+#include <stdio.h>
+#include <stdint.h>
+#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;
+}
--- /dev/null
+/* cclose.c 1.10 83/05/13 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#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;
+}
--- /dev/null
+/* ccreat.c 1.9 83/05/13 */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#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;
+}
--- /dev/null
+/* cfillbuf.c 1.6 83/05/13 */
+
+#include <stdio.h>
+#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);
+}
--- /dev/null
+/* cflsbuf.c 1.10 83/05/13 */
+
+#include <stdio.h>
+#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;
+}
--- /dev/null
+/* cmdhdl.c 1.10 83/07/27 */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#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--;
+ }
+}
--- /dev/null
+/* 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
--- /dev/null
+/* copen.c 1.7 83/05/13 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#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);
+}
--- /dev/null
+/* copy.c 1.8 83/05/13 */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#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);
+}
--- /dev/null
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#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 <eol> */
+ } 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 <eol> */
+ }
+ }
+ }
+ }
+ /* 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);
+}
--- /dev/null
+/* 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);
--- /dev/null
+/* delete.c 1.6 83/05/13 */
+
+#include <stdio.h>
+#include <stdint.h>
+#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);
+}
--- /dev/null
+/* dirhdl.c 1.7 83/05/13 */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#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;
+}
--- /dev/null
+/* extent.c 1.7 83/05/13 */
+
+#include <stdio.h>
+#include <string.h>
+#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;
+}
--- /dev/null
+#include <stdio.h>
+#include <stdint.h>
+#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;
+}
--- /dev/null
+/* gensktab.c 1.4 83/05/13 */
+#include <stdio.h>
+#include <stdlib.h>
+#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;
+ }
+ }
+ }
+}
--- /dev/null
+/* hexdmp.c 1.5 83/05/13 */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#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");
+}
--- /dev/null
+/* interact.c 1.8 83/07/27 */
+#include <stdio.h>
+#include <string.h>
+#include <setjmp.h>
+#include <signal.h>
+#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);
+}
--- /dev/null
+/* physio.c 1.6 83/07/18 */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <unistd.h>
+#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;
+}
--- /dev/null
+/* pip.c 1.5 83/05/13 */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#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;
+ }
+ }
+}
--- /dev/null
+/* rename.c 1.8 83/05/13 */
+
+#include <stdio.h>
+#include <string.h>
+#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;
+}