1 /* #includes */ /*{{{C}}}*//*{{{*/
18 const char cmd[]="cpmcp";
20 static int preserve=0;
23 * Return the user number.
24 * @param s CP/M filename in 0[0]:aaaaaaaa.bbb format.
25 * @returns The user number or -1 for no match.
27 static int userNumber(const char *s) /*{{{*/
29 if (isdigit(*s) && *(s+1)==':') return (*s-'0');
30 if (isdigit(*s) && isdigit(*(s+1)) && *(s+2)==':') return (10*(*s-'0')+(*(s+1)-'0'));
36 * Copy one file from CP/M to UNIX.
37 * @param root The inode for the root directory.
38 * @param src The CP/M filename in 00aaaaaaaabbb format.
39 * @param dest The UNIX filename.
40 * @returns 0 for success, 1 for error.
42 static int cpmToUnix(const struct cpmInode *root, const char *src, const char *dest) /*{{{*/
47 if (cpmNamei(root,src,&ino)==-1) { fprintf(stderr,"%s: can not open `%s': %s\n",cmd,src,boo); exitcode=1; }
53 cpmOpen(&ino,&file,O_RDONLY);
54 if ((ufp=fopen(dest,text ? "w" : "wb"))==(FILE*)0) { fprintf(stderr,"%s: can not create %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; }
62 while ((res=cpmRead(&file,buf,sizeof(buf)))>0)
70 if (buf[j]=='\032') goto endwhile;
75 if (putc('\n',ufp)==EOF) { fprintf(stderr,"%s: can not write %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; ohno=1; goto endwhile; }
78 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; }
79 crpending=(buf[j]=='\r');
83 if (buf[j]=='\r') crpending=1;
84 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; }
87 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; }
91 if (res==-1 && !ohno) { fprintf(stderr,"%s: can not read %s (%s)\n",cmd,src,boo); exitcode=1; ohno=1; }
92 if (fclose(ufp)==EOF && !ohno) { fprintf(stderr,"%s: can not close %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; ohno=1; }
93 if (preserve && !ohno && (ino.atime || ino.mtime))
97 if (ino.atime) ut.actime=ino.atime; else time(&ut.actime);
98 if (ino.mtime) ut.modtime=ino.mtime; else time(&ut.modtime);
99 if (utime(dest,&ut)==-1) { fprintf(stderr,"%s: can change timestamps of %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; ohno=1; }
108 static void usage(void) /*{{{*/
110 fprintf(stderr,"Usage: %s [-f format] [-p] [-t] image user:file file\n",cmd);
111 fprintf(stderr," %s [-f format] [-p] [-t] image user:file ... directory\n",cmd);
112 fprintf(stderr," %s [-f format] [-p] [-t] image file user:file\n",cmd);
113 fprintf(stderr," %s [-f format] [-p] [-t] image file ... user:\n",cmd);
118 int main(int argc, char *argv[])
120 /* variables */ /*{{{*/
124 const char *devopts=NULL;
126 int c,readcpm=-1,todir=-1;
127 struct cpmInode root;
128 struct cpmSuperBlock super;
134 /* parse options */ /*{{{*/
135 if (!(format=getenv("CPMTOOLSFMT"))) format=FORMAT;
136 while ((c=getopt(argc,argv,"T:f:ptuh?"))!=EOF) switch(c)
138 case 'T': devopts=optarg; break;
139 case 'f': format=optarg; break;
140 case 'p': preserve=1; break;
141 case 't': text=1; break;
142 case 'u': uppercase=1; break;
144 case '?': usage(); break;
147 /* parse arguments */ /*{{{*/
148 if ((optind+2)>=argc) usage();
149 image=argv[optind++];
151 if (userNumber(argv[optind])>=0) /* cpm -> unix? */ /*{{{*/
156 for (i=optind; i<(argc-1); ++i) if (userNumber(argv[i])==-1) usage();
157 todir=((argc-optind)>2);
158 if (stat(argv[argc-1],&statbuf)==-1) { if (todir) usage(); }
159 else if (S_ISDIR(statbuf.st_mode)) todir=1; else if (todir) usage();
163 else if (userNumber(argv[argc-1])>=0) /* unix -> cpm */ /*{{{*/
168 for (i=optind; i<(argc-1); ++i) if (userNumber(argv[i])>=0) usage();
169 if ((argc-optind)>2 && *(strchr(argv[argc-1],':')+1)!='\0') usage();
170 if (*(strchr(argv[argc-1],':')+1)=='\0') todir=1;
176 /* open image file */ /*{{{*/
177 if ((err=Device_open(&super.dev,image,readcpm ? O_RDONLY : O_RDWR, devopts)))
179 fprintf(stderr,"%s: cannot open %s (%s)\n",cmd,image,err);
182 if (cpmReadSuper(&super,&root,format,uppercase)==-1)
184 fprintf(stderr,"%s: cannot read superblock (%s)\n",cmd,boo);
188 if (readcpm) /* copy from CP/M to UNIX */ /*{{{*/
191 char *last=argv[argc-1];
193 cpmglob(optind,argc-1,argv,&root,&gargc,&gargv);
194 /* trying to copy multiple files to a file? */
195 if (gargc>1 && !todir) usage();
196 for (i=0; i<gargc; ++i)
198 char dest[_POSIX_PATH_MAX];
206 translate=dest+strlen(dest);
207 strcat(dest,gargv[i]+2);
208 while ((translate=strchr(translate,'/'))) *translate=',';
210 else strcpy(dest,last);
211 if (cpmToUnix(&root,gargv[i],dest)) exitcode=1;
215 else /* copy from UNIX to CP/M */ /*{{{*/
219 for (i=optind; i<(argc-1); ++i)
221 /* variables */ /*{{{*/
226 if ((ufp=fopen(argv[i],"rb"))==(FILE*)0) /* cry a little */ /*{{{*/
228 fprintf(stderr,"%s: can not open %s: %s\n",cmd,argv[i],strerror(errno));
235 char cpmname[2+8+1+3+1]; /* 00foobarxy.zzy\0 */
243 if ((dest=strrchr(argv[i],'/'))!=(char*)0) ++dest; else dest=argv[i];
244 snprintf(cpmname,sizeof(cpmname),"%02d%s",userNumber(argv[argc-1]),dest);
248 snprintf(cpmname,sizeof(cpmname),"%02d%s",userNumber(argv[argc-1]),strchr(argv[argc-1],':')+1);
252 while ((translate=strchr(translate,','))) *translate='/';
254 if (cpmCreat(&root,cpmname,&ino,0666)==-1) /* just cry */ /*{{{*/
256 fprintf(stderr,"%s: can not create %s: %s\n",cmd,cpmname,boo);
266 cpmOpen(&ino,&file,O_WRONLY);
271 for (j=0; j<((ssize_t)sizeof(buf)/2) && (c=getc(ufp))!=EOF; ++j)
273 if (text && c=='\n') buf[j++]='\r';
276 if (text && c==EOF) buf[j++]='\032';
277 if (cpmWrite(&file,buf,j)!=j)
279 fprintf(stderr,"%s: can not write %s: %s\n",cmd,dest,boo);
285 if (cpmClose(&file)==EOF && !ohno) /* I just can't hold back the tears */ /*{{{*/
287 fprintf(stderr,"%s: can not close %s: %s\n",cmd,dest,boo);
291 if (preserve && !ohno)
293 struct utimbuf times;
294 times.actime=st.st_atime;
295 times.modtime=st.st_mtime;
296 cpmUtime(&ino,×);
299 if (fclose(ufp)==EOF)
301 fprintf(stderr,"%s: can not close %s: %s\n",cmd,dest,strerror(errno));
308 if (cpmUmount(&super)==-1)
310 fprintf(stderr,"%s: can not umount device: %s\n",cmd,boo);