Imported Upstream version 2.7
[debian/cpmtools] / cpmcp.c
1 /* #includes */ /*{{{C}}}*//*{{{*/
2 #include "config.h"
3
4 #include <sys/stat.h>
5 #include <ctype.h>
6 #include <errno.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <fcntl.h>
10 #include <limits.h>
11 #include <stdlib.h>
12
13 #include "getopt.h"
14 #include "cpmfs.h"
15
16 #ifdef USE_DMALLOC
17 #include <dmalloc.h>
18 #endif
19 /*}}}*/
20
21 const char cmd[]="cpmcp";
22 static int text=0;
23
24 /**
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.
28  */
29 static int userNumber(const char *s) /*{{{*/
30 {
31   if (isdigit(*s) && *(s+1)==':') return (*s-'0');
32   if (isdigit(*s) && isdigit(*(s+1)) && *(s+2)==':') return (10*(*s-'0')+(*(s+1)));
33   return -1;
34 }
35 /*}}}*/
36
37 /**
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.
43  */
44 static int cpmToUnix(const struct cpmInode *root, const char *src, const char *dest) /*{{{*/
45 {
46   struct cpmInode ino;
47   int exitcode=0;
48
49       if (cpmNamei(root,src,&ino)==-1) { fprintf(stderr,"%s: can not open %s: %s\n",cmd,src,boo); exitcode=1; }
50       else
51       {
52         struct cpmFile file;
53         FILE *ufp;
54
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; }
57         else
58         {
59           int crpending=0;
60           int ohno=0;
61           int res;
62           char buf[4096];
63
64           while ((res=cpmRead(&file,buf,sizeof(buf)))!=0)
65           {
66             int j;
67
68             for (j=0; j<res; ++j)
69             {
70               if (text)
71               {
72                 if (buf[j]=='\032') goto endwhile;
73                 if (crpending)
74                 {
75                   if (buf[j]=='\n') 
76                   {
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; }
78                     crpending=0;
79                   }
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');
82                 }
83                 else
84                 {
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; }
87                 }
88               }
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; }
90             }
91           }
92           endwhile:
93           if (fclose(ufp)==EOF && !ohno) { fprintf(stderr,"%s: can not close %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; }
94         }
95         cpmClose(&file);
96       }
97       return exitcode;
98 }
99 /*}}}*/
100
101 static void usage(void) /*{{{*/
102 {
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);
107   exit(1);
108 }
109 /*}}}*/
110
111 int main(int argc, char *argv[])
112 {
113   /* variables */ /*{{{*/
114   const char *err;
115   const char *image;
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;
121   int exitcode=0;
122   /*}}}*/
123
124   /* parse options */ /*{{{*/
125   while ((c=getopt(argc,argv,"T:f:h?t"))!=EOF) switch(c)
126   {
127     case 'T': devopts=optarg; break;
128     case 'f': format=optarg; break;
129     case 'h':
130     case '?': usage(); break;
131     case 't': text=1; break;
132   }
133   /*}}}*/
134   /* parse arguments */ /*{{{*/
135   if ((optind+2)>=argc) usage();
136   image=argv[optind];
137
138   if (userNumber(argv[optind+1])>=0) /* cpm -> unix? */ /*{{{*/
139   {
140     int i;
141     struct stat statbuf;
142
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();
147     readcpm=1;
148   }
149   /*}}}*/
150   else if (userNumber(argv[argc-1])>=0) /* unix -> cpm */ /*{{{*/
151   {
152     int i;
153
154     todir=0;
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;
158     readcpm=0;
159   }
160   /*}}}*/
161   else usage();
162   /*}}}*/
163   /* open image file */ /*{{{*/
164   if ((err=Device_open(&super.dev,image,readcpm ? O_RDONLY : O_RDWR, devopts)))
165   {
166     fprintf(stderr,"%s: can not open %s (%s)\n",cmd,image,err);
167     exit(1);
168   }
169   cpmReadSuper(&super,&root,format);
170   /*}}}*/
171   if (readcpm) /* copy from CP/M to UNIX */ /*{{{*/
172   {
173     int i,count,total=0;
174     char src[2+8+1+3+1];
175     struct cpmFile dir;
176     struct cpmDirent dirent;
177
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)
180     {
181       cpmOpendir(&root,&dir);
182       count=0;
183       while (cpmReaddir(&dir,&dirent)) if (match(dirent.name,argv[i])) ++count;
184       if (count==0) ++total; else total+=count;
185       cpmClose(&dir);
186     }
187     if (total>1 && !todir) usage();
188     /*}}}*/
189
190     for (i=optind+1; i<(argc-1); ++i)
191     {
192       char dest[_POSIX_PATH_MAX];
193
194       count=0;
195       cpmOpendir(&root,&dir);
196       while (cpmReaddir(&dir,&dirent))
197       {
198         if (match(dirent.name,argv[i]))
199         {
200           if (todir)
201           {
202             strcpy(dest,argv[argc-1]);
203             strcat(dest,"/");
204             strcat(dest,dirent.name+2);
205           }
206           else strcpy(dest,argv[argc-1]);
207           if (cpmToUnix(&root,dirent.name,dest)) exitcode=1;
208           ++count;
209         }
210       }
211       cpmClose(&dir);
212       if (count==0) /* try the pattern itself and find it does not work :) */ /*{{{*/
213       {
214         if (todir)
215         {
216           strcpy(dest,argv[argc-1]);
217           strcat(dest,"/");
218           strcat(dest,src+2);
219         }
220         else strcpy(dest,argv[argc-1]);
221         if (cpmToUnix(&root,src,dest)) exitcode=1;
222       }
223       /*}}}*/
224     }
225   }
226   /*}}}*/
227   else /* copy from UNIX to CP/M */ /*{{{*/
228   {
229     int i;
230
231     for (i=optind+1; i<(argc-1); ++i)
232     {
233       /* variables */ /*{{{*/
234       char *dest=(char*)0;
235       FILE *ufp;
236       /*}}}*/
237
238       if ((ufp=fopen(argv[i],"r"))==(FILE*)0) /* cry a little */ /*{{{*/
239       {
240         fprintf(stderr,"%s: can not open %s: %s\n",cmd,argv[i],strerror(errno));
241         exitcode=1;
242       }
243       /*}}}*/
244       else
245       {
246         struct cpmInode ino;
247         char cpmname[2+8+3+1]; /* 00foobarxy.zzy\0 */
248
249         if (todir)
250         {
251           if ((dest=strrchr(argv[i],'/'))!=(char*)0) ++dest; else dest=argv[i];
252           sprintf(cpmname,"%02d%s",userNumber(argv[argc-1]),dest);
253         }
254         else
255         {
256           sprintf(cpmname,"%02d%s",userNumber(argv[argc-1]),strchr(argv[argc-1],':')+1);
257         }
258         if (cpmCreat(&root,cpmname,&ino,0666)==-1) /* just cry */ /*{{{*/
259         {
260           fprintf(stderr,"%s: can not create %s: %s\n",cmd,cpmname,boo);
261           exitcode=1;
262         }
263         /*}}}*/
264         else
265         {
266           struct cpmFile file;
267           int ohno=0;
268           char buf[4096+1];
269
270           cpmOpen(&ino,&file,O_WRONLY);
271           do
272           {
273             int j;
274
275             for (j=0; j<(sizeof(buf)/2) && (c=getc(ufp))!=EOF; ++j)
276             {
277               if (text && c=='\n') buf[j++]='\r';
278               buf[j]=c;
279             }
280             if (text && c==EOF) buf[j++]='\032';
281             if (cpmWrite(&file,buf,j)!=j)
282             {
283               fprintf(stderr,"%s: can not write %s: %s\n",cmd,dest,boo);
284               ohno=1;
285               exitcode=1;
286               break;
287             }
288           } while (c!=EOF);
289           if (cpmClose(&file)==EOF && !ohno) /* I just can't hold back the tears */ /*{{{*/
290           {
291             fprintf(stderr,"%s: can not close %s: %s\n",cmd,dest,boo);
292             exitcode=1;
293           }
294           /*}}}*/
295         }
296         fclose(ufp);
297       }
298     }
299   }
300   /*}}}*/
301   cpmUmount(&super);
302   exit(exitcode);
303 }