mirror of https://github.com/wwarthen/RomWBW.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
299 lines
8.2 KiB
299 lines
8.2 KiB
/* #includes */ /*{{{C}}}*//*{{{*/
|
|
#include "config.h"
|
|
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
#include <stdlib.h>
|
|
#include <utime.h>
|
|
|
|
#include "getopt_.h"
|
|
#include "cpmfs.h"
|
|
|
|
#ifdef USE_DMALLOC
|
|
#include <dmalloc.h>
|
|
#endif
|
|
/*}}}*/
|
|
|
|
const char cmd[]="cpmcp";
|
|
static int text=0;
|
|
static int preserve=0;
|
|
|
|
/**
|
|
* Return the user number.
|
|
* @param s CP/M filename in 0[0]:aaaaaaaa.bbb format.
|
|
* @returns The user number or -1 for no match.
|
|
*/
|
|
static int userNumber(const char *s) /*{{{*/
|
|
{
|
|
if (isdigit(*s) && *(s+1)==':') return (*s-'0');
|
|
if (isdigit(*s) && isdigit(*(s+1)) && *(s+2)==':') return (10*(*s-'0')+(*(s+1)-'0'));
|
|
return -1;
|
|
}
|
|
/*}}}*/
|
|
|
|
/**
|
|
* Copy one file from CP/M to UNIX.
|
|
* @param root The inode for the root directory.
|
|
* @param src The CP/M filename in 00aaaaaaaabbb format.
|
|
* @param dest The UNIX filename.
|
|
* @returns 0 for success, 1 for error.
|
|
*/
|
|
static int cpmToUnix(const struct cpmInode *root, const char *src, const char *dest) /*{{{*/
|
|
{
|
|
struct cpmInode ino;
|
|
int exitcode=0;
|
|
|
|
if (cpmNamei(root,src,&ino)==-1) { fprintf(stderr,"%s: can not open `%s': %s\n",cmd,src,boo); exitcode=1; }
|
|
else
|
|
{
|
|
struct cpmFile file;
|
|
FILE *ufp;
|
|
|
|
cpmOpen(&ino,&file,O_RDONLY);
|
|
if ((ufp=fopen(dest,text ? "w" : "wb"))==(FILE*)0) { fprintf(stderr,"%s: can not create %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; }
|
|
else
|
|
{
|
|
int crpending=0;
|
|
int ohno=0;
|
|
int res;
|
|
char buf[4096];
|
|
|
|
while ((res=cpmRead(&file,buf,sizeof(buf)))>0)
|
|
{
|
|
int j;
|
|
|
|
for (j=0; j<res; ++j)
|
|
{
|
|
if (text)
|
|
{
|
|
if (buf[j]=='\032') goto endwhile;
|
|
if (crpending)
|
|
{
|
|
if (buf[j]=='\n')
|
|
{
|
|
if (putc('\n',ufp)==EOF) { fprintf(stderr,"%s: can not write %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; ohno=1; goto endwhile; }
|
|
crpending=0;
|
|
}
|
|
else if (putc('\r',ufp)==EOF) { fprintf(stderr,"%s: can not write %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; ohno=1; goto endwhile; }
|
|
crpending=(buf[j]=='\r');
|
|
}
|
|
else
|
|
{
|
|
if (buf[j]=='\r') crpending=1;
|
|
else if (putc(buf[j],ufp)==EOF) { fprintf(stderr,"%s: can not write %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; ohno=1; goto endwhile; }
|
|
}
|
|
}
|
|
else if (putc(buf[j],ufp)==EOF) { fprintf(stderr,"%s: can not write %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; ohno=1; goto endwhile; }
|
|
}
|
|
}
|
|
endwhile:
|
|
if (res==-1 && !ohno) { fprintf(stderr,"%s: can not read %s (%s)\n",cmd,src,boo); exitcode=1; ohno=1; }
|
|
if (fclose(ufp)==EOF && !ohno) { fprintf(stderr,"%s: can not close %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; ohno=1; }
|
|
if (preserve && !ohno && (ino.atime || ino.mtime))
|
|
{
|
|
struct utimbuf ut;
|
|
|
|
if (ino.atime) ut.actime=ino.atime; else time(&ut.actime);
|
|
if (ino.mtime) ut.modtime=ino.mtime; else time(&ut.modtime);
|
|
if (utime(dest,&ut)==-1) { fprintf(stderr,"%s: can change timestamps of %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; ohno=1; }
|
|
}
|
|
}
|
|
cpmClose(&file);
|
|
}
|
|
return exitcode;
|
|
}
|
|
/*}}}*/
|
|
|
|
static void usage(void) /*{{{*/
|
|
{
|
|
fprintf(stderr,"Usage: %s [-f format] [-p] [-t] image user:file file\n",cmd);
|
|
fprintf(stderr," %s [-f format] [-p] [-t] image user:file ... directory\n",cmd);
|
|
fprintf(stderr," %s [-f format] [-p] [-t] image file user:file\n",cmd);
|
|
fprintf(stderr," %s [-f format] [-p] [-t] image file ... user:\n",cmd);
|
|
exit(1);
|
|
}
|
|
/*}}}*/
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
/* variables */ /*{{{*/
|
|
const char *err;
|
|
const char *image;
|
|
const char *format;
|
|
const char *devopts=NULL;
|
|
int c,readcpm=-1,todir=-1;
|
|
struct cpmInode root;
|
|
struct cpmSuperBlock super;
|
|
int exitcode=0;
|
|
int gargc;
|
|
char **gargv;
|
|
/*}}}*/
|
|
|
|
/* parse options */ /*{{{*/
|
|
if (!(format=getenv("CPMTOOLSFMT"))) format=FORMAT;
|
|
while ((c=getopt(argc,argv,"T:f:h?pt"))!=EOF) switch(c)
|
|
{
|
|
case 'T': devopts=optarg; break;
|
|
case 'f': format=optarg; break;
|
|
case 'h':
|
|
case '?': usage(); break;
|
|
case 'p': preserve=1; break;
|
|
case 't': text=1; break;
|
|
}
|
|
/*}}}*/
|
|
/* parse arguments */ /*{{{*/
|
|
if ((optind+2)>=argc) usage();
|
|
image=argv[optind++];
|
|
|
|
if (userNumber(argv[optind])>=0) /* cpm -> unix? */ /*{{{*/
|
|
{
|
|
int i;
|
|
struct stat statbuf;
|
|
|
|
for (i=optind; i<(argc-1); ++i) if (userNumber(argv[i])==-1) usage();
|
|
todir=((argc-optind)>2);
|
|
if (stat(argv[argc-1],&statbuf)==-1) { if (todir) usage(); }
|
|
else if (S_ISDIR(statbuf.st_mode)) todir=1; else if (todir) usage();
|
|
readcpm=1;
|
|
}
|
|
/*}}}*/
|
|
else if (userNumber(argv[argc-1])>=0) /* unix -> cpm */ /*{{{*/
|
|
{
|
|
int i;
|
|
|
|
todir=0;
|
|
for (i=optind; i<(argc-1); ++i) if (userNumber(argv[i])>=0) usage();
|
|
if ((argc-optind)>2 && *(strchr(argv[argc-1],':')+1)!='\0') usage();
|
|
if (*(strchr(argv[argc-1],':')+1)=='\0') todir=1;
|
|
readcpm=0;
|
|
}
|
|
/*}}}*/
|
|
else usage();
|
|
/*}}}*/
|
|
/* open image file */ /*{{{*/
|
|
if ((err=Device_open(&super.dev,image,readcpm ? O_RDONLY : O_RDWR, devopts)))
|
|
{
|
|
fprintf(stderr,"%s: cannot open %s (%s)\n",cmd,image,err);
|
|
exit(1);
|
|
}
|
|
if (cpmReadSuper(&super,&root,format)==-1)
|
|
{
|
|
fprintf(stderr,"%s: cannot read superblock (%s)\n",cmd,boo);
|
|
exit(1);
|
|
}
|
|
/*}}}*/
|
|
if (readcpm) /* copy from CP/M to UNIX */ /*{{{*/
|
|
{
|
|
int i;
|
|
char *last=argv[argc-1];
|
|
|
|
cpmglob(optind,argc-1,argv,&root,&gargc,&gargv);
|
|
/* trying to copy multiple files to a file? */
|
|
if (gargc>1 && !todir) usage();
|
|
for (i=0; i<gargc; ++i)
|
|
{
|
|
char dest[_POSIX_PATH_MAX];
|
|
|
|
if (todir)
|
|
{
|
|
strcpy(dest,last);
|
|
strcat(dest,"/");
|
|
strcat(dest,gargv[i]+2);
|
|
}
|
|
else strcpy(dest,last);
|
|
if (cpmToUnix(&root,gargv[i],dest)) exitcode=1;
|
|
}
|
|
}
|
|
/*}}}*/
|
|
else /* copy from UNIX to CP/M */ /*{{{*/
|
|
{
|
|
int i;
|
|
|
|
for (i=optind; i<(argc-1); ++i)
|
|
{
|
|
/* variables */ /*{{{*/
|
|
char *dest=(char*)0;
|
|
FILE *ufp;
|
|
/*}}}*/
|
|
|
|
if ((ufp=fopen(argv[i],"rb"))==(FILE*)0) /* cry a little */ /*{{{*/
|
|
{
|
|
fprintf(stderr,"%s: can not open %s: %s\n",cmd,argv[i],strerror(errno));
|
|
exitcode=1;
|
|
}
|
|
/*}}}*/
|
|
else
|
|
{
|
|
struct cpmInode ino;
|
|
char cpmname[2+8+1+3+1]; /* 00foobarxy.zzy\0 */
|
|
struct stat st;
|
|
|
|
stat(argv[i],&st);
|
|
|
|
if (todir)
|
|
{
|
|
if ((dest=strrchr(argv[i],'/'))!=(char*)0) ++dest; else dest=argv[i];
|
|
snprintf(cpmname,sizeof(cpmname),"%02d%s",userNumber(argv[argc-1]),dest);
|
|
}
|
|
else
|
|
{
|
|
snprintf(cpmname,sizeof(cpmname),"%02d%s",userNumber(argv[argc-1]),strchr(argv[argc-1],':')+1);
|
|
}
|
|
if (cpmCreat(&root,cpmname,&ino,0666)==-1) /* just cry */ /*{{{*/
|
|
{
|
|
fprintf(stderr,"%s: can not create %s: %s\n",cmd,cpmname,boo);
|
|
exitcode=1;
|
|
}
|
|
/*}}}*/
|
|
else
|
|
{
|
|
struct cpmFile file;
|
|
int ohno=0;
|
|
char buf[4096+1];
|
|
|
|
cpmOpen(&ino,&file,O_WRONLY);
|
|
do
|
|
{
|
|
unsigned int j;
|
|
|
|
for (j=0; j<(sizeof(buf)/2) && (c=getc(ufp))!=EOF; ++j)
|
|
{
|
|
if (text && c=='\n') buf[j++]='\r';
|
|
buf[j]=c;
|
|
}
|
|
if (text && c==EOF) buf[j++]='\032';
|
|
if (cpmWrite(&file,buf,j)!=(ssize_t)j)
|
|
{
|
|
fprintf(stderr,"%s: can not write %s: %s\n",cmd,dest,boo);
|
|
ohno=1;
|
|
exitcode=1;
|
|
break;
|
|
}
|
|
} while (c!=EOF);
|
|
if (cpmClose(&file)==EOF && !ohno) /* I just can't hold back the tears */ /*{{{*/
|
|
{
|
|
fprintf(stderr,"%s: can not close %s: %s\n",cmd,dest,boo);
|
|
exitcode=1;
|
|
}
|
|
/*}}}*/
|
|
if (preserve && !ohno)
|
|
{
|
|
struct utimbuf times;
|
|
times.actime=st.st_atime;
|
|
times.modtime=st.st_mtime;
|
|
cpmUtime(&ino,×);
|
|
}
|
|
}
|
|
fclose(ufp);
|
|
}
|
|
}
|
|
}
|
|
/*}}}*/
|
|
cpmUmount(&super);
|
|
exit(exitcode);
|
|
}
|
|
|