1 /* #includes */ /*{{{C}}}*//*{{{*/
23 const char cmd[]="cpmcp";
25 static int preserve=0;
28 * Return the user number.
29 * @param s CP/M filename in 0[0]:aaaaaaaa.bbb format.
30 * @returns The user number or -1 for no match.
32 static int userNumber(const char *s) /*{{{*/
34 if (isdigit(*s) && *(s+1)==':') return (*s-'0');
35 if (isdigit(*s) && isdigit(*(s+1)) && *(s+2)==':') return (10*(*s-'0')+(*(s+1)));
41 * Copy one file from CP/M to UNIX.
42 * @param root The inode for the root directory.
43 * @param src The CP/M filename in 00aaaaaaaabbb format.
44 * @param dest The UNIX filename.
45 * @returns 0 for success, 1 for error.
47 static int cpmToUnix(const struct cpmInode *root, const char *src, const char *dest) /*{{{*/
52 if (cpmNamei(root,src,&ino)==-1) { fprintf(stderr,"%s: can not open `%s': %s\n",cmd,src,boo); exitcode=1; }
58 cpmOpen(&ino,&file,O_RDONLY);
59 if ((ufp=fopen(dest,text ? "w" : "wb"))==(FILE*)0) { fprintf(stderr,"%s: can not create %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; }
67 while ((res=cpmRead(&file,buf,sizeof(buf)))!=0)
75 if (buf[j]=='\032') goto endwhile;
80 if (putc('\n',ufp)==EOF) { fprintf(stderr,"%s: can not write %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; ohno=1; goto endwhile; }
83 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; }
84 crpending=(buf[j]=='\r');
88 if (buf[j]=='\r') crpending=1;
89 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; }
92 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; }
96 if (fclose(ufp)==EOF && !ohno) { fprintf(stderr,"%s: can not close %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; ohno=1; }
97 if (preserve && !ohno && (ino.atime || ino.mtime))
101 if (ino.atime) ut.actime=ino.atime; else time(&ut.actime);
102 if (ino.mtime) ut.modtime=ino.mtime; else time(&ut.modtime);
103 if (utime(dest,&ut)==-1) { fprintf(stderr,"%s: can change timestamps of %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; ohno=1; }
112 static void usage(void) /*{{{*/
114 fprintf(stderr,"Usage: %s [-f format] [-p] [-t] image user:file file\n",cmd);
115 fprintf(stderr," %s [-f format] [-p] [-t] image user:file ... directory\n",cmd);
116 fprintf(stderr," %s [-f format] [-p] [-t] image file user:file\n",cmd);
117 fprintf(stderr," %s [-f format] [-p] [-t] image file ... user:\n",cmd);
122 int main(int argc, char *argv[])
124 /* variables */ /*{{{*/
127 const char *format=FORMAT;
128 const char *devopts=NULL;
129 int c,readcpm=-1,todir=-1;
130 struct cpmInode root;
131 struct cpmSuperBlock super;
137 /* parse options */ /*{{{*/
138 while ((c=getopt(argc,argv,"T:f:h?pt"))!=EOF) switch(c)
140 case 'T': devopts=optarg; break;
141 case 'f': format=optarg; break;
143 case '?': usage(); break;
144 case 'p': preserve=1; break;
145 case 't': text=1; break;
148 /* parse arguments */ /*{{{*/
149 if ((optind+2)>=argc) usage();
150 image=argv[optind++];
152 if (userNumber(argv[optind])>=0) /* cpm -> unix? */ /*{{{*/
157 for (i=optind; i<(argc-1); ++i) if (userNumber(argv[i])==-1) usage();
158 todir=((argc-optind)>2);
159 if (stat(argv[argc-1],&statbuf)==-1) { if (todir) usage(); }
160 else if (S_ISDIR(statbuf.st_mode)) todir=1; else if (todir) usage();
164 else if (userNumber(argv[argc-1])>=0) /* unix -> cpm */ /*{{{*/
169 for (i=optind; i<(argc-1); ++i) if (userNumber(argv[i])>=0) usage();
170 if ((argc-optind)>2 && *(strchr(argv[argc-1],':')+1)!='\0') usage();
171 if (*(strchr(argv[argc-1],':')+1)=='\0') todir=1;
177 /* open image file */ /*{{{*/
178 if ((err=Device_open(&super.dev,image,readcpm ? O_RDONLY : O_RDWR, devopts)))
180 fprintf(stderr,"%s: can not open %s (%s)\n",cmd,image,err);
183 cpmReadSuper(&super,&root,format);
185 if (readcpm) /* copy from CP/M to UNIX */ /*{{{*/
188 char *last=argv[argc-1];
190 cpmglob(optind,argc-1,argv,&root,&gargc,&gargv);
191 /* trying to copy multiple files to a file? */
192 if (gargc>1 && !todir) usage();
193 for (i=0; i<gargc; ++i)
195 char dest[_POSIX_PATH_MAX];
201 strcat(dest,gargv[i]+2);
203 else strcpy(dest,last);
204 if (cpmToUnix(&root,gargv[i],dest)) exitcode=1;
208 else /* copy from UNIX to CP/M */ /*{{{*/
212 for (i=optind; i<(argc-1); ++i)
214 /* variables */ /*{{{*/
219 if ((ufp=fopen(argv[i],"rb"))==(FILE*)0) /* cry a little */ /*{{{*/
221 fprintf(stderr,"%s: can not open %s: %s\n",cmd,argv[i],strerror(errno));
228 char cpmname[2+8+1+3+1]; /* 00foobarxy.zzy\0 */
232 if ((dest=strrchr(argv[i],'/'))!=(char*)0) ++dest; else dest=argv[i];
233 sprintf(cpmname,"%02d%s",userNumber(argv[argc-1]),dest);
237 sprintf(cpmname,"%02d%s",userNumber(argv[argc-1]),strchr(argv[argc-1],':')+1);
239 if (cpmCreat(&root,cpmname,&ino,0666)==-1) /* just cry */ /*{{{*/
241 fprintf(stderr,"%s: can not create %s: %s\n",cmd,cpmname,boo);
251 cpmOpen(&ino,&file,O_WRONLY);
256 for (j=0; j<(sizeof(buf)/2) && (c=getc(ufp))!=EOF; ++j)
258 if (text && c=='\n') buf[j++]='\r';
261 if (text && c==EOF) buf[j++]='\032';
262 if (cpmWrite(&file,buf,j)!=j)
264 fprintf(stderr,"%s: can not write %s: %s\n",cmd,dest,boo);
270 if (cpmClose(&file)==EOF && !ohno) /* I just can't hold back the tears */ /*{{{*/
272 fprintf(stderr,"%s: can not close %s: %s\n",cmd,dest,boo);