1 /* #includes */ /*{{{C}}}*//*{{{*/
3 #define _POSIX_SOURCE 1
5 #define _POSIX_C_SOURCE 2
25 const char cmd[]="cpmcp";
29 * Return the user number.
30 * @param s CP/M filename in 0[0]:aaaaaaaa.bbb format.
31 * @returns The user number or -1 for no match.
33 static int userNumber(const char *s) /*{{{*/
35 if (isdigit(*s) && *(s+1)==':') return (*s-'0');
36 if (isdigit(*s) && isdigit(*(s+1)) && *(s+2)==':') return (10*(*s-'0')+(*(s+1)));
42 * Copy one file from CP/M to UNIX.
43 * @param root The inode for the root directory.
44 * @param src The CP/M filename in 00aaaaaaaabbb format.
45 * @param dest The UNIX filename.
46 * @returns 0 for success, 1 for error.
48 static int cpmToUnix(const struct cpmInode *root, const char *src, const char *dest) /*{{{*/
53 if (cpmNamei(root,src,&ino)==-1) { fprintf(stderr,"%s: can not open %s: %s\n",cmd,src,boo); exitcode=1; }
59 cpmOpen(&ino,&file,O_RDONLY);
60 if ((ufp=fopen(dest,text ? "w" : "wb"))==(FILE*)0) { fprintf(stderr,"%s: can not create %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; }
68 while ((res=cpmRead(&file,buf,sizeof(buf)))!=0)
76 if (buf[j]=='\032') goto endwhile;
81 if (putc('\n',ufp)==EOF) { fprintf(stderr,"%s: can not write %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; ohno=1; goto endwhile; }
84 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; }
85 crpending=(buf[j]=='\r');
89 if (buf[j]=='\r') crpending=1;
90 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 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; }
97 if (fclose(ufp)==EOF && !ohno) { fprintf(stderr,"%s: can not close %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; }
105 static void usage(void) /*{{{*/
107 fprintf(stderr,"Usage: %s [-f format] [-t] image 0:file file\n",cmd);
108 fprintf(stderr," %s [-f format] [-t] image 0:file ... directory\n",cmd);
109 fprintf(stderr," %s [-f format] [-t] image file 0:file\n",cmd);
110 fprintf(stderr," %s [-f format] [-t] image file ... 0:\n",cmd);
115 int main(int argc, char *argv[])
117 /* variables */ /*{{{*/
120 const char *format=FORMAT;
121 const char *devopts=NULL;
122 int c,readcpm=-1,todir=-1;
123 struct cpmInode root;
124 struct cpmSuperBlock super;
128 /* parse options */ /*{{{*/
129 while ((c=getopt(argc,argv,"T:f:h?t"))!=EOF) switch(c)
131 case 'T': devopts=optarg; break;
132 case 'f': format=optarg; break;
134 case '?': usage(); break;
135 case 't': text=1; break;
138 /* parse arguments */ /*{{{*/
139 if ((optind+2)>=argc) usage();
142 if (userNumber(argv[optind+1])>=0) /* cpm -> unix? */ /*{{{*/
147 for (i=optind+1; i<(argc-1); ++i) if (userNumber(argv[i])==-1) usage();
148 todir=((argc-optind-1)>2);
149 if (stat(argv[argc-1],&statbuf)==-1) { if (todir) usage(); }
150 else if (S_ISDIR(statbuf.st_mode)) todir=1; else if (todir) usage();
154 else if (userNumber(argv[argc-1])>=0) /* unix -> cpm */ /*{{{*/
159 for (i=optind+1; i<(argc-1); ++i) if (userNumber(argv[i])>=0) usage();
160 if ((argc-optind-1)>2 && *(strchr(argv[argc-1],':')+1)!='\0') usage();
161 if (*(strchr(argv[argc-1],':')+1)=='\0') todir=1;
167 /* open image file */ /*{{{*/
168 if ((err=Device_open(&super.dev,image,readcpm ? O_RDONLY : O_RDWR, devopts)))
170 fprintf(stderr,"%s: can not open %s (%s)\n",cmd,image,err);
173 cpmReadSuper(&super,&root,format);
175 if (readcpm) /* copy from CP/M to UNIX */ /*{{{*/
180 struct cpmDirent dirent;
182 /* expand pattern and check if we try to copy multiple files to a file */ /*{{{*/
183 for (i=optind+1,total=0; i<(argc-1); ++i)
185 cpmOpendir(&root,&dir);
187 while (cpmReaddir(&dir,&dirent)) if (match(dirent.name,argv[i])) ++count;
188 if (count==0) ++total; else total+=count;
191 if (total>1 && !todir) usage();
194 for (i=optind+1; i<(argc-1); ++i)
196 char dest[_POSIX_PATH_MAX];
199 cpmOpendir(&root,&dir);
200 while (cpmReaddir(&dir,&dirent))
202 if (match(dirent.name,argv[i]))
206 strcpy(dest,argv[argc-1]);
208 strcat(dest,dirent.name+2);
210 else strcpy(dest,argv[argc-1]);
211 if (cpmToUnix(&root,dirent.name,dest)) exitcode=1;
216 if (count==0) /* try the pattern itself and find it does not work :) */ /*{{{*/
220 strcpy(dest,argv[argc-1]);
224 else strcpy(dest,argv[argc-1]);
225 if (cpmToUnix(&root,src,dest)) exitcode=1;
231 else /* copy from UNIX to CP/M */ /*{{{*/
235 for (i=optind+1; i<(argc-1); ++i)
237 /* variables */ /*{{{*/
242 if ((ufp=fopen(argv[i],"r"))==(FILE*)0) /* cry a little */ /*{{{*/
244 fprintf(stderr,"%s: can not open %s: %s\n",cmd,argv[i],strerror(errno));
251 char cpmname[2+8+3+1]; /* 00foobarxy.zzy\0 */
255 if ((dest=strrchr(argv[i],'/'))!=(char*)0) ++dest; else dest=argv[i];
256 sprintf(cpmname,"%02d%s",userNumber(argv[argc-1]),dest);
260 sprintf(cpmname,"%02d%s",userNumber(argv[argc-1]),strchr(argv[argc-1],':')+1);
262 if (cpmCreat(&root,cpmname,&ino,0666)==-1) /* just cry */ /*{{{*/
264 fprintf(stderr,"%s: can not create %s: %s\n",cmd,cpmname,boo);
274 cpmOpen(&ino,&file,O_WRONLY);
279 for (j=0; j<(sizeof(buf)/2) && (c=getc(ufp))!=EOF; ++j)
281 if (text && c=='\n') buf[j++]='\r';
284 if (text && c==EOF) buf[j++]='\032';
285 if (cpmWrite(&file,buf,j)!=j)
287 fprintf(stderr,"%s: can not write %s: %s\n",cmd,dest,boo);
293 if (cpmClose(&file)==EOF && !ohno) /* I just can't hold back the tears */ /*{{{*/
295 fprintf(stderr,"%s: can not close %s: %s\n",cmd,dest,boo);