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