1 /* #includes */ /*{{{C}}}*//*{{{*/
21 const char cmd[]="cpmcp";
25 * Return the user number.
26 * @param s CP/M filename in 0[0]:aaaaaaaa.bbb format.
27 * @returns The user number or -1 for no match.
29 static int userNumber(const char *s) /*{{{*/
31 if (isdigit(*s) && *(s+1)==':') return (*s-'0');
32 if (isdigit(*s) && isdigit(*(s+1)) && *(s+2)==':') return (10*(*s-'0')+(*(s+1)));
38 * Copy one file from CP/M to UNIX.
39 * @param root The inode for the root directory.
40 * @param src The CP/M filename in 00aaaaaaaabbb format.
41 * @param dest The UNIX filename.
42 * @returns 0 for success, 1 for error.
44 static int cpmToUnix(const struct cpmInode *root, const char *src, const char *dest) /*{{{*/
49 if (cpmNamei(root,src,&ino)==-1) { fprintf(stderr,"%s: can not open %s: %s\n",cmd,src,boo); exitcode=1; }
55 cpmOpen(&ino,&file,O_RDONLY);
56 if ((ufp=fopen(dest,text ? "w" : "wb"))==(FILE*)0) { fprintf(stderr,"%s: can not create %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; }
64 while ((res=cpmRead(&file,buf,sizeof(buf)))!=0)
72 if (buf[j]=='\032') goto endwhile;
77 if (putc('\n',ufp)==EOF) { fprintf(stderr,"%s: can not write %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; ohno=1; goto endwhile; }
80 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; }
81 crpending=(buf[j]=='\r');
85 if (buf[j]=='\r') crpending=1;
86 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; }
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; }
93 if (fclose(ufp)==EOF && !ohno) { fprintf(stderr,"%s: can not close %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; }
101 static void usage(void) /*{{{*/
103 fprintf(stderr,"Usage: %s [-f format] [-t] image 0:file file\n",cmd);
104 fprintf(stderr," %s [-f format] [-t] image 0:file ... directory\n",cmd);
105 fprintf(stderr," %s [-f format] [-t] image file 0:file\n",cmd);
106 fprintf(stderr," %s [-f format] [-t] image file ... 0:\n",cmd);
111 int main(int argc, char *argv[])
113 /* variables */ /*{{{*/
116 const char *format=FORMAT;
117 const char *devopts=NULL;
118 int c,readcpm=-1,todir=-1;
119 struct cpmInode root;
120 struct cpmSuperBlock super;
124 /* parse options */ /*{{{*/
125 while ((c=getopt(argc,argv,"T:f:h?t"))!=EOF) switch(c)
127 case 'T': devopts=optarg; break;
128 case 'f': format=optarg; break;
130 case '?': usage(); break;
131 case 't': text=1; break;
134 /* parse arguments */ /*{{{*/
135 if ((optind+2)>=argc) usage();
138 if (userNumber(argv[optind+1])>=0) /* cpm -> unix? */ /*{{{*/
143 for (i=optind+1; i<(argc-1); ++i) if (userNumber(argv[i])==-1) usage();
144 todir=((argc-optind-1)>2);
145 if (stat(argv[argc-1],&statbuf)==-1) { if (todir) usage(); }
146 else if (S_ISDIR(statbuf.st_mode)) todir=1; else if (todir) usage();
150 else if (userNumber(argv[argc-1])>=0) /* unix -> cpm */ /*{{{*/
155 for (i=optind+1; i<(argc-1); ++i) if (userNumber(argv[i])>=0) usage();
156 if ((argc-optind-1)>2 && *(strchr(argv[argc-1],':')+1)!='\0') usage();
157 if (*(strchr(argv[argc-1],':')+1)=='\0') todir=1;
163 /* open image file */ /*{{{*/
164 if ((err=Device_open(&super.dev,image,readcpm ? O_RDONLY : O_RDWR, devopts)))
166 fprintf(stderr,"%s: can not open %s (%s)\n",cmd,image,err);
169 cpmReadSuper(&super,&root,format);
171 if (readcpm) /* copy from CP/M to UNIX */ /*{{{*/
176 struct cpmDirent dirent;
178 /* expand pattern and check if we try to copy multiple files to a file */ /*{{{*/
179 for (i=optind+1,total=0; i<(argc-1); ++i)
181 cpmOpendir(&root,&dir);
183 while (cpmReaddir(&dir,&dirent)) if (match(dirent.name,argv[i])) ++count;
184 if (count==0) ++total; else total+=count;
187 if (total>1 && !todir) usage();
190 for (i=optind+1; i<(argc-1); ++i)
192 char dest[_POSIX_PATH_MAX];
195 cpmOpendir(&root,&dir);
196 while (cpmReaddir(&dir,&dirent))
198 if (match(dirent.name,argv[i]))
202 strcpy(dest,argv[argc-1]);
204 strcat(dest,dirent.name+2);
206 else strcpy(dest,argv[argc-1]);
207 if (cpmToUnix(&root,dirent.name,dest)) exitcode=1;
212 if (count==0) /* try the pattern itself and find it does not work :) */ /*{{{*/
216 strcpy(dest,argv[argc-1]);
220 else strcpy(dest,argv[argc-1]);
221 if (cpmToUnix(&root,src,dest)) exitcode=1;
227 else /* copy from UNIX to CP/M */ /*{{{*/
231 for (i=optind+1; i<(argc-1); ++i)
233 /* variables */ /*{{{*/
238 if ((ufp=fopen(argv[i],"r"))==(FILE*)0) /* cry a little */ /*{{{*/
240 fprintf(stderr,"%s: can not open %s: %s\n",cmd,argv[i],strerror(errno));
247 char cpmname[2+8+3+1]; /* 00foobarxy.zzy\0 */
251 if ((dest=strrchr(argv[i],'/'))!=(char*)0) ++dest; else dest=argv[i];
252 sprintf(cpmname,"%02d%s",userNumber(argv[argc-1]),dest);
256 sprintf(cpmname,"%02d%s",userNumber(argv[argc-1]),strchr(argv[argc-1],':')+1);
258 if (cpmCreat(&root,cpmname,&ino,0666)==-1) /* just cry */ /*{{{*/
260 fprintf(stderr,"%s: can not create %s: %s\n",cmd,cpmname,boo);
270 cpmOpen(&ino,&file,O_WRONLY);
275 for (j=0; j<(sizeof(buf)/2) && (c=getc(ufp))!=EOF; ++j)
277 if (text && c=='\n') buf[j++]='\r';
280 if (text && c==EOF) buf[j++]='\032';
281 if (cpmWrite(&file,buf,j)!=j)
283 fprintf(stderr,"%s: can not write %s: %s\n",cmd,dest,boo);
289 if (cpmClose(&file)==EOF && !ohno) /* I just can't hold back the tears */ /*{{{*/
291 fprintf(stderr,"%s: can not close %s: %s\n",cmd,dest,boo);