cpm: tools for working with CP/M media
authorAlan Cox <alan@linux.intel.com>
Wed, 27 Jun 2018 21:35:57 +0000 (22:35 +0100)
committerAlan Cox <alan@linux.intel.com>
Wed, 27 Jun 2018 21:35:57 +0000 (22:35 +0100)
These need some work but the architecture is clean and they are small unlike
some of the modern tooling.

25 files changed:
Applications/cpmfs/COPYRIGHT [new file with mode: 0644]
Applications/cpmfs/README [new file with mode: 0644]
Applications/cpmfs/cpm.1 [new file with mode: 0644]
Applications/cpmfs/src/bitmap.c [new file with mode: 0644]
Applications/cpmfs/src/blockio.c [new file with mode: 0644]
Applications/cpmfs/src/cclose.c [new file with mode: 0644]
Applications/cpmfs/src/ccreat.c [new file with mode: 0644]
Applications/cpmfs/src/cfillbuf.c [new file with mode: 0644]
Applications/cpmfs/src/cflsbuf.c [new file with mode: 0644]
Applications/cpmfs/src/cmdhdl.c [new file with mode: 0644]
Applications/cpmfs/src/command.h [new file with mode: 0644]
Applications/cpmfs/src/copen.c [new file with mode: 0644]
Applications/cpmfs/src/copy.c [new file with mode: 0644]
Applications/cpmfs/src/cpm.c [new file with mode: 0644]
Applications/cpmfs/src/cpm.h [new file with mode: 0644]
Applications/cpmfs/src/delete.c [new file with mode: 0644]
Applications/cpmfs/src/dirhdl.c [new file with mode: 0644]
Applications/cpmfs/src/extent.c [new file with mode: 0644]
Applications/cpmfs/src/ffc.c [new file with mode: 0644]
Applications/cpmfs/src/gensktab.c [new file with mode: 0644]
Applications/cpmfs/src/hexdmp.c [new file with mode: 0644]
Applications/cpmfs/src/interact.c [new file with mode: 0644]
Applications/cpmfs/src/physio.c [new file with mode: 0644]
Applications/cpmfs/src/pip.c [new file with mode: 0644]
Applications/cpmfs/src/rename.c [new file with mode: 0644]

diff --git a/Applications/cpmfs/COPYRIGHT b/Applications/cpmfs/COPYRIGHT
new file mode 100644 (file)
index 0000000..4f8c313
--- /dev/null
@@ -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 (file)
index 0000000..3ef19b5
--- /dev/null
@@ -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 (file)
index 0000000..427d399
--- /dev/null
@@ -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 (file)
index 0000000..7788e24
--- /dev/null
@@ -0,0 +1,156 @@
+/*     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
+}
diff --git a/Applications/cpmfs/src/blockio.c b/Applications/cpmfs/src/blockio.c
new file mode 100644 (file)
index 0000000..394add6
--- /dev/null
@@ -0,0 +1,67 @@
+/*     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;
+}
diff --git a/Applications/cpmfs/src/cclose.c b/Applications/cpmfs/src/cclose.c
new file mode 100644 (file)
index 0000000..038383f
--- /dev/null
@@ -0,0 +1,51 @@
+/*     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;
+}
diff --git a/Applications/cpmfs/src/ccreat.c b/Applications/cpmfs/src/ccreat.c
new file mode 100644 (file)
index 0000000..7b30fed
--- /dev/null
@@ -0,0 +1,75 @@
+/*     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;
+}
diff --git a/Applications/cpmfs/src/cfillbuf.c b/Applications/cpmfs/src/cfillbuf.c
new file mode 100644 (file)
index 0000000..6227cba
--- /dev/null
@@ -0,0 +1,28 @@
+/*     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);
+}
diff --git a/Applications/cpmfs/src/cflsbuf.c b/Applications/cpmfs/src/cflsbuf.c
new file mode 100644 (file)
index 0000000..c996297
--- /dev/null
@@ -0,0 +1,81 @@
+/*     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;
+}
diff --git a/Applications/cpmfs/src/cmdhdl.c b/Applications/cpmfs/src/cmdhdl.c
new file mode 100644 (file)
index 0000000..7847328
--- /dev/null
@@ -0,0 +1,154 @@
+/*     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--;
+       }
+}
diff --git a/Applications/cpmfs/src/command.h b/Applications/cpmfs/src/command.h
new file mode 100644 (file)
index 0000000..a4b2560
--- /dev/null
@@ -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 (file)
index 0000000..91bed6c
--- /dev/null
@@ -0,0 +1,71 @@
+/*     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);
+}
diff --git a/Applications/cpmfs/src/copy.c b/Applications/cpmfs/src/copy.c
new file mode 100644 (file)
index 0000000..55bdcb4
--- /dev/null
@@ -0,0 +1,89 @@
+/*     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);
+}
diff --git a/Applications/cpmfs/src/cpm.c b/Applications/cpmfs/src/cpm.c
new file mode 100644 (file)
index 0000000..a7d3d74
--- /dev/null
@@ -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 <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);
+}
diff --git a/Applications/cpmfs/src/cpm.h b/Applications/cpmfs/src/cpm.h
new file mode 100644 (file)
index 0000000..726cdbc
--- /dev/null
@@ -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 (file)
index 0000000..07513f6
--- /dev/null
@@ -0,0 +1,38 @@
+/*     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);
+}
diff --git a/Applications/cpmfs/src/dirhdl.c b/Applications/cpmfs/src/dirhdl.c
new file mode 100644 (file)
index 0000000..fd38948
--- /dev/null
@@ -0,0 +1,105 @@
+/*     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;
+}
diff --git a/Applications/cpmfs/src/extent.c b/Applications/cpmfs/src/extent.c
new file mode 100644 (file)
index 0000000..c5b13ae
--- /dev/null
@@ -0,0 +1,65 @@
+/*     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;
+}
diff --git a/Applications/cpmfs/src/ffc.c b/Applications/cpmfs/src/ffc.c
new file mode 100644 (file)
index 0000000..9287d2f
--- /dev/null
@@ -0,0 +1,33 @@
+#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;
+}
diff --git a/Applications/cpmfs/src/gensktab.c b/Applications/cpmfs/src/gensktab.c
new file mode 100644 (file)
index 0000000..ab78d84
--- /dev/null
@@ -0,0 +1,41 @@
+/*     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;
+                       }
+               }
+       }
+}
diff --git a/Applications/cpmfs/src/hexdmp.c b/Applications/cpmfs/src/hexdmp.c
new file mode 100644 (file)
index 0000000..34e3883
--- /dev/null
@@ -0,0 +1,69 @@
+/*     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");
+}
diff --git a/Applications/cpmfs/src/interact.c b/Applications/cpmfs/src/interact.c
new file mode 100644 (file)
index 0000000..1c241c3
--- /dev/null
@@ -0,0 +1,100 @@
+/*     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);
+}
diff --git a/Applications/cpmfs/src/physio.c b/Applications/cpmfs/src/physio.c
new file mode 100644 (file)
index 0000000..de33916
--- /dev/null
@@ -0,0 +1,82 @@
+/*     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;
+}
diff --git a/Applications/cpmfs/src/pip.c b/Applications/cpmfs/src/pip.c
new file mode 100644 (file)
index 0000000..e669e36
--- /dev/null
@@ -0,0 +1,76 @@
+/*     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;
+               }
+       }
+}
diff --git a/Applications/cpmfs/src/rename.c b/Applications/cpmfs/src/rename.c
new file mode 100644 (file)
index 0000000..f2507ad
--- /dev/null
@@ -0,0 +1,48 @@
+/*     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;
+}