Subversion Repositories SvarDOS

Rev

Rev 421 | Rev 502 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 421 Rev 501
1
/* This file is part of the SvarCOM project and is published under the terms
1
/* This file is part of the SvarCOM project and is published under the terms
2
 * of the MIT license.
2
 * of the MIT license.
3
 *
3
 *
4
 * Copyright (C) 2021 Mateusz Viste
4
 * Copyright (C) 2021 Mateusz Viste
5
 *
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a
6
 * Permission is hereby granted, free of charge, to any person obtaining a
7
 * copy of this software and associated documentation files (the "Software"),
7
 * copy of this software and associated documentation files (the "Software"),
8
 * to deal in the Software without restriction, including without limitation
8
 * to deal in the Software without restriction, including without limitation
9
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
 * and/or sell copies of the Software, and to permit persons to whom the
10
 * and/or sell copies of the Software, and to permit persons to whom the
11
 * Software is furnished to do so, subject to the following conditions:
11
 * Software is furnished to do so, subject to the following conditions:
12
 *
12
 *
13
 * The above copyright notice and this permission notice shall be included in
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
14
 * all copies or substantial portions of the Software.
15
 *
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
 * DEALINGS IN THE SOFTWARE.
22
 * DEALINGS IN THE SOFTWARE.
23
 */
23
 */
24
 
24
 
25
/*
25
/*
26
 * copy
26
 * copy
27
 */
27
 */
28
 
28
 
29
/* /A - Used to copy ASCII files. Applies to the filename preceding it and to
29
/* /A - Used to copy ASCII files. Applies to the filename preceding it and to
30
 * all following filenames. Files will be copied until an end-of-file mark is
30
 * all following filenames. Files will be copied until an end-of-file mark is
31
 * encountered in the file being copied. If an end-of-file mark is encountered
31
 * encountered in the file being copied. If an end-of-file mark is encountered
32
 * in the file, the rest of the file is not copied. DOS will append an EOF
32
 * in the file, the rest of the file is not copied. DOS will append an EOF
33
 * mark at the end of the copied file.
33
 * mark at the end of the copied file.
34
 *
34
 *
35
 * /B - Used to copy binary files. Applies to the filename preceding it and to
35
 * /B - Used to copy binary files. Applies to the filename preceding it and to
36
 * all following filenames. Copied files will be read by size (according to
36
 * all following filenames. Copied files will be read by size (according to
37
 * the number of bytes indicated in the file`s directory listing). An EOF mark
37
 * the number of bytes indicated in the file`s directory listing). An EOF mark
38
 * is not placed at the end of the copied file.
38
 * is not placed at the end of the copied file.
39
 *
39
 *
40
 * /V - Checks after the copy to assure that a file was copied correctly. If
40
 * /V - Checks after the copy to assure that a file was copied correctly. If
41
 * the copy cannot be verified, the program will display an error message.
41
 * the copy cannot be verified, the program will display an error message.
42
 * Using this option will result in a slower copying process.
42
 * Using this option will result in a slower copying process.
43
 *
43
 *
44
 * special case: "COPY A+B+C+D" means "append B, C and D files to the A file"
44
 * special case: "COPY A+B+C+D" means "append B, C and D files to the A file"
45
 * if A does not exist, then "append C and D to B", etc.
45
 * if A does not exist, then "append C and D to B", etc.
46
 */
46
 */
47
 
47
 
48
struct copy_setup {
48
struct copy_setup {
49
  const char *src[64];
49
  const char *src[64];
50
  unsigned short src_count; /* how many sources are declared */
50
  unsigned short src_count; /* how many sources are declared */
51
  char dst[256];
51
  char dst[256];
52
  unsigned short dstlen;
52
  unsigned short dstlen;
53
  char src_asciimode[64];
53
  char src_asciimode[64];
54
  char dst_asciimode;
54
  char dst_asciimode;
55
  char last_asciimode; /* /A or /B impacts the file preceding it and becomes the new default for all files that follow */
55
  char last_asciimode; /* /A or /B impacts the file preceding it and becomes the new default for all files that follow */
56
  char verifyflag;
56
  char verifyflag;
57
  char lastitemwasplus;
57
  char lastitemwasplus;
-
 
58
  unsigned short databufsz;
58
  char databuf[BUFFER_SIZE - 1024];
59
  char databuf[1];
59
};
60
};
60
 
61
 
61
 
62
 
62
/* copies src to dst, overwriting or appending to the destination.
63
/* copies src to dst, overwriting or appending to the destination.
63
 * - copy is performed in ASCII mode if asciiflag set (stop at first EOF in src
64
 * - copy is performed in ASCII mode if asciiflag set (stop at first EOF in src
64
 *   and append an EOF in dst).
65
 *   and append an EOF in dst).
65
 * - returns zero on success, DOS error code on error */
66
 * - returns zero on success, DOS error code on error */
66
unsigned short cmd_copy_internal(const char *dst, char dstascii, const char *src, char srcascii, unsigned char appendflag, void *buff, unsigned short buffsz) {
67
unsigned short cmd_copy_internal(const char *dst, char dstascii, const char *src, char srcascii, unsigned char appendflag, void *buff, unsigned short buffsz) {
67
  unsigned short errcode = 0;
68
  unsigned short errcode = 0;
68
  unsigned short srch = 0xffff, dsth = 0xffff;
69
  unsigned short srch = 0xffff, dsth = 0xffff;
69
  _asm {
70
  _asm {
70
 
71
 
71
    /* open src */
72
    /* open src */
72
    OPENSRC:
73
    OPENSRC:
73
    mov ax, 0x3d00 /* DOS 2+ -- open an existing file, read access mode */
74
    mov ax, 0x3d00 /* DOS 2+ -- open an existing file, read access mode */
74
    mov dx, src    /* ASCIIZ fname */
75
    mov dx, src    /* ASCIIZ fname */
75
    int 0x21       /* CF clear on success, handle in AX */
76
    int 0x21       /* CF clear on success, handle in AX */
76
    mov [srch], ax /* store src handle in memory */
77
    mov [srch], ax /* store src handle in memory */
77
 
78
 
78
    /* check appendflag so I know if I have to try opening dst for append */
79
    /* check appendflag so I know if I have to try opening dst for append */
79
    xor al, al
80
    xor al, al
80
    or al, [appendflag]
81
    or al, [appendflag]
81
    jz CREATEDST
82
    jz CREATEDST
82
 
83
 
83
    /* try opening dst first if appendflag set */
84
    /* try opening dst first if appendflag set */
84
    mov ax, 0x3d01 /* DOS 2+ -- open an existing file, write access mode */
85
    mov ax, 0x3d01 /* DOS 2+ -- open an existing file, write access mode */
85
    mov dx, dst    /* ASCIIZ fname */
86
    mov dx, dst    /* ASCIIZ fname */
86
    int 0x21       /* CF clear on success, handle in AX */
87
    int 0x21       /* CF clear on success, handle in AX */
87
    jc CREATEDST   /* failed to open file (file does not exist) */
88
    jc CREATEDST   /* failed to open file (file does not exist) */
88
    mov [dsth], ax /* store dst handle in memory */
89
    mov [dsth], ax /* store dst handle in memory */
89
 
90
 
90
    /* got file open, LSEEK to end of it now so future data is appended */
91
    /* got file open, LSEEK to end of it now so future data is appended */
91
    mov bx, ax     /* file handle in BX (was still in AX) */
92
    mov bx, ax     /* file handle in BX (was still in AX) */
92
    mov ax, 0x4202 /* DOS 2+ -- set file pointer to end of file + CX:DX */
93
    mov ax, 0x4202 /* DOS 2+ -- set file pointer to end of file + CX:DX */
93
    xor cx, cx     /* offset zero */
94
    xor cx, cx     /* offset zero */
94
    xor dx, dx     /* offset zero */
95
    xor dx, dx     /* offset zero */
95
    int 0x21       /* CF set on error */
96
    int 0x21       /* CF set on error */
96
    jc FAIL
97
    jc FAIL
97
    jmp COPY
98
    jmp COPY
98
 
99
 
99
    /* create dst */
100
    /* create dst */
100
    CREATEDST:
101
    CREATEDST:
101
    mov ah, 0x3c   /* DOS 2+ -- create a file */
102
    mov ah, 0x3c   /* DOS 2+ -- create a file */
102
    mov dx, dst
103
    mov dx, dst
103
    xor cx, cx     /* zero out attributes */
104
    xor cx, cx     /* zero out attributes */
104
    int 0x21       /* handle in AX on success, CF set on error */
105
    int 0x21       /* handle in AX on success, CF set on error */
105
    jc FAIL
106
    jc FAIL
106
    mov [dsth], ax /* store dst handle in memory */
107
    mov [dsth], ax /* store dst handle in memory */
107
 
108
 
108
    /* perform actual copy */
109
    /* perform actual copy */
109
    COPY:
110
    COPY:
110
    /* read a block from src */
111
    /* read a block from src */
111
    mov ah, 0x3f   /* DOS 2+ -- read from file */
112
    mov ah, 0x3f   /* DOS 2+ -- read from file */
112
    mov bx, [srch]
113
    mov bx, [srch]
113
    mov cx, [buffsz]
114
    mov cx, [buffsz]
114
    mov dx, [buff] /* DX points to buffer */
115
    mov dx, [buff] /* DX points to buffer */
115
    int 0x21       /* CF set on error, bytes read in AX (0=EOF) */
116
    int 0x21       /* CF set on error, bytes read in AX (0=EOF) */
116
    jc FAIL        /* abort on error */
117
    jc FAIL        /* abort on error */
117
    /* EOF? (ax == 0) */
118
    /* EOF? (ax == 0) */
118
    test ax, ax
119
    test ax, ax
119
    jz ENDOFFILE
120
    jz ENDOFFILE
120
    /* write block of AX bytes to dst */
121
    /* write block of AX bytes to dst */
121
    mov cx, ax     /* block length */
122
    mov cx, ax     /* block length */
122
    mov ah, 0x40   /* DOS 2+ -- write to file (CX bytes from DS:DX) */
123
    mov ah, 0x40   /* DOS 2+ -- write to file (CX bytes from DS:DX) */
123
    mov bx, [dsth] /* file handle */
124
    mov bx, [dsth] /* file handle */
124
    /* mov dx, [buff] */ /* DX points to buffer already */
125
    /* mov dx, [buff] */ /* DX points to buffer already */
125
    int 0x21       /* CF clear and AX=CX on success */
126
    int 0x21       /* CF clear and AX=CX on success */
126
    jc FAIL
127
    jc FAIL
127
    cmp ax, cx     /* sould be equal, otherwise failed */
128
    cmp ax, cx     /* sould be equal, otherwise failed */
128
    mov ax, 0x08   /* preset to DOS error "Insufficient memory" */
129
    mov ax, 0x08   /* preset to DOS error "Insufficient memory" */
129
    jne FAIL
130
    jne FAIL
130
    jmp COPY
131
    jmp COPY
131
 
132
 
132
    ENDOFFILE:
133
    ENDOFFILE:
133
    /* if dst ascii mode -> add an EOF (ASCII mode not supported for the time being) */
134
    /* if dst ascii mode -> add an EOF (ASCII mode not supported for the time being) */
134
 
135
 
135
    jmp CLOSESRC
136
    jmp CLOSESRC
136
 
137
 
137
    FAIL:
138
    FAIL:
138
    mov [errcode], ax
139
    mov [errcode], ax
139
 
140
 
140
    CLOSESRC:
141
    CLOSESRC:
141
    /* close src and dst */
142
    /* close src and dst */
142
    mov bx, [srch]
143
    mov bx, [srch]
143
    cmp bx, 0xffff
144
    cmp bx, 0xffff
144
    je CLOSEDST
145
    je CLOSEDST
145
    mov ah, 0x3e   /* DOS 2+ -- close a file handle */
146
    mov ah, 0x3e   /* DOS 2+ -- close a file handle */
146
    int 0x21
147
    int 0x21
147
 
148
 
148
    CLOSEDST:
149
    CLOSEDST:
149
    mov bx, [dsth]
150
    mov bx, [dsth]
150
    cmp bx, 0xffff
151
    cmp bx, 0xffff
151
    je DONE
152
    je DONE
152
    mov ah, 0x3e   /* DOS 2+ -- close a file handle */
153
    mov ah, 0x3e   /* DOS 2+ -- close a file handle */
153
    int 0x21
154
    int 0x21
154
 
155
 
155
    DONE:
156
    DONE:
156
  }
157
  }
157
  return(errcode);
158
  return(errcode);
158
}
159
}
159
 
160
 
160
 
161
 
161
static int cmd_copy(struct cmd_funcparam *p) {
162
static int cmd_copy(struct cmd_funcparam *p) {
162
  struct copy_setup *setup = (void *)(p->BUFFER);
163
  struct copy_setup *setup = (void *)(p->BUFFER);
163
  unsigned short i;
164
  unsigned short i;
164
  unsigned short copiedcount_in = 0, copiedcount_out = 0; /* number of input/output copied files */
165
  unsigned short copiedcount_in = 0, copiedcount_out = 0; /* number of input/output copied files */
165
  struct DTA *dta = (void *)0x80; /* use DTA at default location in PSP */
166
  struct DTA *dta = (void *)0x80; /* use DTA at default location in PSP */
166
 
167
 
167
  if (cmd_ishlp(p)) {
168
  if (cmd_ishlp(p)) {
168
    outputnl("Copies one or more files to another location.");
169
    outputnl("Copies one or more files to another location.");
169
    outputnl("");
170
    outputnl("");
170
    outputnl("COPY [/A|/B] source [/A|/B] [+source [/A|/B] [+...]] [destination [/A|/B]] [/V]");
171
    outputnl("COPY [/A|/B] source [/A|/B] [+source [/A|/B] [+...]] [destination [/A|/B]] [/V]");
171
    outputnl("");
172
    outputnl("");
172
    outputnl("source       Specifies the file or files to be copied");
173
    outputnl("source       Specifies the file or files to be copied");
173
    outputnl("/A           Indicates an ASCII text file");
174
    outputnl("/A           Indicates an ASCII text file");
174
    outputnl("/B           Indicates a binary file");
175
    outputnl("/B           Indicates a binary file");
175
    outputnl("destination  Specifies the directory and/or filename for the new file(s)");
176
    outputnl("destination  Specifies the directory and/or filename for the new file(s)");
176
    outputnl("/V           Verifies that new files are written correctly");
177
    outputnl("/V           Verifies that new files are written correctly");
177
    outputnl("");
178
    outputnl("");
178
    outputnl("To append files, specify a single file for destination, but multiple files");
179
    outputnl("To append files, specify a single file for destination, but multiple files");
179
    outputnl("for source (using wildcards or file1+file2+file3 format).");
180
    outputnl("for source (using wildcards or file1+file2+file3 format).");
180
    outputnl("");
181
    outputnl("");
181
    outputnl("NOTE: /A and /B are no-ops (ignored), provided only for compatibility reasons.");
182
    outputnl("NOTE: /A and /B are no-ops (ignored), provided only for compatibility reasons.");
182
    return(-1);
183
    return(-1);
183
  }
184
  }
184
 
185
 
185
  /* parse cmdline and fill the setup struct accordingly */
186
  /* parse cmdline and fill the setup struct accordingly */
186
 
187
 
187
  memset(setup, 0, sizeof(*setup));
188
  memset(setup, 0, sizeof(*setup));
-
 
189
  setup->databufsz = p->BUFFERSZ - sizeof(*setup);
188
 
190
 
189
  for (i = 0; i < p->argc; i++) {
191
  for (i = 0; i < p->argc; i++) {
190
 
192
 
191
    /* switch? */
193
    /* switch? */
192
    if (p->argv[i][0] == '/') {
194
    if (p->argv[i][0] == '/') {
193
      if ((imatch(p->argv[i], "/a")) || (imatch(p->argv[i], "/b"))) {
195
      if ((imatch(p->argv[i], "/a")) || (imatch(p->argv[i], "/b"))) {
194
        setup->last_asciimode = 'b';
196
        setup->last_asciimode = 'b';
195
        if (imatch(p->argv[i], "/a")) setup->last_asciimode = 'a';
197
        if (imatch(p->argv[i], "/a")) setup->last_asciimode = 'a';
196
        /* */
198
        /* */
197
        if (setup->dst[0] != 0) {
199
        if (setup->dst[0] != 0) {
198
          setup->dst_asciimode = setup->last_asciimode;
200
          setup->dst_asciimode = setup->last_asciimode;
199
        } else if (setup->src_count != 0) {
201
        } else if (setup->src_count != 0) {
200
          setup->src_asciimode[setup->src_count - 1] = setup->last_asciimode;
202
          setup->src_asciimode[setup->src_count - 1] = setup->last_asciimode;
201
        }
203
        }
202
      } else if (imatch(p->argv[i], "/v")) {
204
      } else if (imatch(p->argv[i], "/v")) {
203
        setup->verifyflag = 1;
205
        setup->verifyflag = 1;
204
      } else {
206
      } else {
205
        outputnl("Invalid switch");
207
        outputnl("Invalid switch");
206
        return(-1);
208
        return(-1);
207
      }
209
      }
208
      continue;
210
      continue;
209
    }
211
    }
210
 
212
 
211
    /* not a switch - must be either a source, a destination or a + */
213
    /* not a switch - must be either a source, a destination or a + */
212
    if (p->argv[i][0] == '+') {
214
    if (p->argv[i][0] == '+') {
213
      /* a plus cannot appear after destination or before first source */
215
      /* a plus cannot appear after destination or before first source */
214
      if ((setup->dst[0] != 0) || (setup->src_count == 0)) {
216
      if ((setup->dst[0] != 0) || (setup->src_count == 0)) {
215
        outputnl("Invalid syntax");
217
        outputnl("Invalid syntax");
216
        return(-1);
218
        return(-1);
217
      }
219
      }
218
      setup->lastitemwasplus = 1;
220
      setup->lastitemwasplus = 1;
219
      /* a plus may be immediately followed by a filename - if so, emulate
221
      /* a plus may be immediately followed by a filename - if so, emulate
220
       * a new argument */
222
       * a new argument */
221
      if (p->argv[i][1] != 0) {
223
      if (p->argv[i][1] != 0) {
222
        p->argv[i] += 1;
224
        p->argv[i] += 1;
223
        i--;
225
        i--;
224
      }
226
      }
225
      continue;
227
      continue;
226
    }
228
    }
227
 
229
 
228
    /* src? (first non-switch or something that follows a +) */
230
    /* src? (first non-switch or something that follows a +) */
229
    if ((setup->lastitemwasplus) || (setup->src_count == 0)) {
231
    if ((setup->lastitemwasplus) || (setup->src_count == 0)) {
230
      setup->src[setup->src_count] = p->argv[i];
232
      setup->src[setup->src_count] = p->argv[i];
231
      setup->src_asciimode[setup->src_count] = setup->last_asciimode;
233
      setup->src_asciimode[setup->src_count] = setup->last_asciimode;
232
      setup->src_count++;
234
      setup->src_count++;
233
      setup->lastitemwasplus = 0;
235
      setup->lastitemwasplus = 0;
234
      continue;
236
      continue;
235
    }
237
    }
236
 
238
 
237
    /* must be a dst then */
239
    /* must be a dst then */
238
    if (setup->dst[0] != 0) {
240
    if (setup->dst[0] != 0) {
239
      outputnl("Invalid syntax");
241
      outputnl("Invalid syntax");
240
      return(-1);
242
      return(-1);
241
    }
243
    }
242
    if (file_truename(p->argv[i], setup->dst) != 0) {
244
    if (file_truename(p->argv[i], setup->dst) != 0) {
243
      outputnl("Invalid destination");
245
      outputnl("Invalid destination");
244
      return(-1);
246
      return(-1);
245
    }
247
    }
246
    setup->dst_asciimode = setup->last_asciimode;
248
    setup->dst_asciimode = setup->last_asciimode;
247
    /* if dst is a directory then append a backslash */
249
    /* if dst is a directory then append a backslash */
248
    setup->dstlen = path_appendbkslash_if_dir(setup->dst);
250
    setup->dstlen = path_appendbkslash_if_dir(setup->dst);
249
  }
251
  }
250
 
252
 
251
  /* DEBUG: output setup content ("if 1" to enable) */
253
  /* DEBUG: output setup content ("if 1" to enable) */
252
  #if 0
254
  #if 0
253
  printf("src: ");
255
  printf("src: ");
254
  for (i = 0; i < setup->src_count; i++) {
256
  for (i = 0; i < setup->src_count; i++) {
255
    if (i != 0) printf(", ");
257
    if (i != 0) printf(", ");
256
    printf("%s [%c]", setup->src[i], setup->src_asciimode[i]);
258
    printf("%s [%c]", setup->src[i], setup->src_asciimode[i]);
257
  }
259
  }
258
  printf("\r\n");
260
  printf("\r\n");
259
  printf("dst: %s [%c]\r\n", setup->dst, setup->dst_asciimode);
261
  printf("dst: %s [%c]\r\n", setup->dst, setup->dst_asciimode);
260
  printf("verify: %s\r\n", (setup->verifyflag)?"ON":"OFF");
262
  printf("verify: %s\r\n", (setup->verifyflag)?"ON":"OFF");
261
  #endif
263
  #endif
262
 
264
 
263
  /* must have at least one source */
265
  /* must have at least one source */
264
  if (setup->src_count == 0) {
266
  if (setup->src_count == 0) {
265
    outputnl("Required parameter missing");
267
    outputnl("Required parameter missing");
266
    return(-1);
268
    return(-1);
267
  }
269
  }
268
 
270
 
269
  /* perform the operation based on setup directives:
271
  /* perform the operation based on setup directives:
270
   * iterate over every source and copy it to dest */
272
   * iterate over every source and copy it to dest */
271
 
273
 
272
  for (i = 0; i < setup->src_count; i++) {
274
  for (i = 0; i < setup->src_count; i++) {
273
    unsigned short t;
275
    unsigned short t;
274
    unsigned short databuflen;
276
    unsigned short databuflen;
275
    unsigned short pathendoffset;
277
    unsigned short pathendoffset;
276
 
278
 
277
    /* resolve truename of src and write it to buffer */
279
    /* resolve truename of src and write it to buffer */
278
    t = file_truename(setup->src[i], setup->databuf);
280
    t = file_truename(setup->src[i], setup->databuf);
279
    if (t != 0) {
281
    if (t != 0) {
280
      output(setup->src[i]);
282
      output(setup->src[i]);
281
      output(" - ");
283
      output(" - ");
282
      outputnl(doserr(t));
284
      outputnl(doserr(t));
283
      continue;
285
      continue;
284
    }
286
    }
285
    databuflen = strlen(setup->databuf); /* remember databuf length */
287
    databuflen = strlen(setup->databuf); /* remember databuf length */
286
 
288
 
287
    /* if length zero, skip (not sure why this would be possible, though) */
289
    /* if length zero, skip (not sure why this would be possible, though) */
288
    if (databuflen == 0) continue;
290
    if (databuflen == 0) continue;
289
 
291
 
290
    /* if src does not end with a backslash AND it is a directory then append a backslash */
292
    /* if src does not end with a backslash AND it is a directory then append a backslash */
291
    databuflen = path_appendbkslash_if_dir(setup->databuf);
293
    databuflen = path_appendbkslash_if_dir(setup->databuf);
292
 
294
 
293
    /* if src ends with a '\' then append *.* */
295
    /* if src ends with a '\' then append *.* */
294
    if (setup->databuf[databuflen - 1] == '\\') {
296
    if (setup->databuf[databuflen - 1] == '\\') {
295
      strcat(setup->databuf, "*.*");
297
      strcat(setup->databuf, "*.*");
296
    }
298
    }
297
 
299
 
298
    /* remember where the path in databuf ends */
300
    /* remember where the path in databuf ends */
299
    for (t = 0; setup->databuf[t] != 0; t++) {
301
    for (t = 0; setup->databuf[t] != 0; t++) {
300
      if (setup->databuf[t] == '\\') pathendoffset = t + 1;
302
      if (setup->databuf[t] == '\\') pathendoffset = t + 1;
301
    }
303
    }
302
 
304
 
303
    /* */
305
    /* */
304
    if (findfirst(dta, setup->databuf, 0) != 0) {
306
    if (findfirst(dta, setup->databuf, 0) != 0) {
305
      continue;
307
      continue;
306
    }
308
    }
307
 
309
 
308
    do {
310
    do {
309
      char appendflag;
311
      char appendflag;
310
      if (dta->attr & DOS_ATTR_DIR) continue; /* skip directories */
312
      if (dta->attr & DOS_ATTR_DIR) continue; /* skip directories */
311
 
313
 
312
      /* compute full path/name of the file */
314
      /* compute full path/name of the file */
313
      strcpy(setup->databuf + pathendoffset, dta->fname);
315
      strcpy(setup->databuf + pathendoffset, dta->fname);
314
 
316
 
315
      /* if there was no destination, then YOU are the destination now!
317
      /* if there was no destination, then YOU are the destination now!
316
       * this handles situations like COPY a.txt+b.txt+c.txt */
318
       * this handles situations like COPY a.txt+b.txt+c.txt */
317
      if (setup->dst[0] == NULL) {
319
      if (setup->dst[0] == NULL) {
318
        strcpy(setup->dst, setup->databuf);
320
        strcpy(setup->dst, setup->databuf);
319
        setup->dstlen = strlen(setup->dst);
321
        setup->dstlen = strlen(setup->dst);
320
        copiedcount_in++;
322
        copiedcount_in++;
321
        copiedcount_out++;
323
        copiedcount_out++;
322
        continue;
324
        continue;
323
      }
325
      }
324
 
326
 
325
      /* is dst ending with a backslash? then append fname to it */
327
      /* is dst ending with a backslash? then append fname to it */
326
      if (setup->dst[setup->dstlen - 1] == '\\') strcpy(setup->dst + setup->dstlen, dta->fname);
328
      if (setup->dst[setup->dstlen - 1] == '\\') strcpy(setup->dst + setup->dstlen, dta->fname);
327
 
329
 
328
      /* now databuf contains the full source and dst contains the full dest... COPY TIME! */
330
      /* now databuf contains the full source and dst contains the full dest... COPY TIME! */
329
 
331
 
330
      /* if dst file exists already -> overwrite it or append?
332
      /* if dst file exists already -> overwrite it or append?
331
          - if dst is a dir (dstlen-1 points at a \\) -> overwrite
333
          - if dst is a dir (dstlen-1 points at a \\) -> overwrite
332
          - otherwise: if copiedcount_in==0 overwrite, else append */
334
          - otherwise: if copiedcount_in==0 overwrite, else append */
333
      output(setup->databuf);
335
      output(setup->databuf);
334
      if ((setup->dst[setup->dstlen - 1] == '\\') || (copiedcount_in == 0)) {
336
      if ((setup->dst[setup->dstlen - 1] == '\\') || (copiedcount_in == 0)) {
335
        appendflag = 0;
337
        appendflag = 0;
336
        output(" > ");
338
        output(" > ");
337
        copiedcount_out++;
339
        copiedcount_out++;
338
      } else {
340
      } else {
339
        appendflag = 1;
341
        appendflag = 1;
340
        output(" >> ");
342
        output(" >> ");
341
      }
343
      }
342
      outputnl(setup->dst);
344
      outputnl(setup->dst);
343
 
345
 
-
 
346
      // TODO: reusing setup->databuf not good idea: when 2+ files are being copied, the content of the first one overwrites the pathname of the second one!
344
      t = cmd_copy_internal(setup->dst, 0, setup->databuf, 0, appendflag, setup->databuf, sizeof(setup->databuf));
347
      t = cmd_copy_internal(setup->dst, 0, setup->databuf, 0, appendflag, setup->databuf, setup->databufsz);
345
      if (t != 0) {
348
      if (t != 0) {
346
        outputnl(doserr(t));
349
        outputnl(doserr(t));
347
        return(-1);
350
        return(-1);
348
      }
351
      }
349
 
352
 
350
      copiedcount_in++;
353
      copiedcount_in++;
351
    } while (findnext(dta) == 0);
354
    } while (findnext(dta) == 0);
352
 
355
 
353
  }
356
  }
354
 
357
 
355
  sprintf(setup->databuf, "%u file(s) copied", copiedcount_out);
358
  sprintf(setup->databuf, "%u file(s) copied", copiedcount_out);
356
  outputnl(setup->databuf);
359
  outputnl(setup->databuf);
357
 
360
 
358
  return(-1);
361
  return(-1);
359
}
362
}
360
 
363