1 /* Copyright (C) 1994 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: gp_dosfe.c,v 1.5 2002/02/21 22:24:52 giles Exp $ */
18 /* MS-DOS file enumeration. */
19 #include "stdio_.h"
20 #include <fcntl.h>
21 #include "dos_.h"
22 #include "memory_.h"
23 #include "string_.h"
24 #include "gstypes.h"
25 #include "gsmemory.h"
26 #include "gsstruct.h"
27 #include "gp.h"
28 #include "gsutil.h"
29
30 struct file_enum_s {
31 ff_struct_t ffblk;
32 char *pattern; /* orig pattern + modified pattern */
33 int patlen; /* orig pattern length */
34 int pat_size; /* allocate space for pattern */
35 int head_size; /* pattern length through last */
36 /* :, / or \ */
37 int first_time;
38 gs_memory_t *memory;
39 };
40 gs_private_st_ptrs1(st_file_enum, struct file_enum_s, "file_enum",
41 file_enum_enum_ptrs, file_enum_reloc_ptrs, pattern);
42
43 /* Initialize an enumeration. Note that * and ? in a directory */
44 /* don't work, and \ is taken literally unless a second \ follows. */
45 file_enum *
gp_enumerate_files_init(const char * pat,uint patlen,gs_memory_t * mem)46 gp_enumerate_files_init(const char *pat, uint patlen, gs_memory_t * mem)
47 {
48 file_enum *pfen = gs_alloc_struct(mem, file_enum, &st_file_enum, "gp_enumerate_files");
49 int pat_size = 2 * patlen + 1;
50 char *pattern;
51 char *p;
52 int hsize = 0;
53 int i;
54 int dot = 0;
55
56 if (pfen == 0)
57 return 0;
58
59 /* pattern could be allocated as a string, */
60 /* but it's simpler for GC and freeing to allocate it as bytes. */
61
62 pattern = (char *)gs_alloc_bytes(mem, pat_size,
63 "gp_enumerate_files(pattern)");
64 if (pattern == 0)
65 return 0;
66 memcpy(pattern, pat, patlen);
67 p = pattern + patlen;
68 for (i = 0; i < patlen; i++) {
69 switch (pat[i]) {
70 case '*':
71 /* Skip to . or end of string so DOS can do it. */
72 *p++ = '*';
73 while (i < patlen && pat[i] != '.')
74 i++;
75 if (i == patlen && !dot) { /* DOS doesn't interpret * alone as */
76 /* matching all files; we need *.*. */
77 *p++ = '.';
78 *p++ = '*';
79 }
80 i--;
81 continue;
82 case '.':
83 dot = 1;
84 break;
85 case '\\':
86 if (i + 1 < patlen && pat[i + 1] == '\\')
87 i++;
88 /* falls through */
89 case ':':
90 case '/':
91 hsize = p + 1 - (pattern + patlen);
92 dot = 0;
93 }
94 *p++ = pat[i];
95 }
96 *p = 0;
97 pfen->pattern = pattern;
98 pfen->patlen = patlen;
99 pfen->pat_size = pat_size;
100 pfen->head_size = hsize;
101 pfen->memory = mem;
102 pfen->first_time = 1;
103 return pfen;
104 }
105
106 /* Enumerate the next file. */
107 private const string_match_params smp_file =
108 {'*', '?', -1, true, true};
109
110 uint
gp_enumerate_files_next(file_enum * pfen,char * ptr,uint maxlen)111 gp_enumerate_files_next(file_enum * pfen, char *ptr, uint maxlen)
112 {
113 int code;
114 char *p, *q;
115 uint len;
116 const char *fpat = pfen->pattern + pfen->patlen;
117
118 top:if (pfen->first_time) {
119 code = dos_findfirst(fpat, &pfen->ffblk);
120 pfen->first_time = 0;
121 } else
122 code = dos_findnext(&pfen->ffblk);
123 if (code != 0) { /* All done, clean up. */
124 gp_enumerate_files_close(pfen);
125 return ~(uint) 0;
126 }
127 if (maxlen < 13 + pfen->head_size)
128 return maxlen + 1; /* cop out! */
129 memcpy(ptr, fpat, pfen->head_size);
130 for (p = &pfen->ffblk.ff_name[0], q = ptr + pfen->head_size; *p; p++)
131 if (*p != ' ')
132 *q++ = *p;
133 len = q - ptr;
134 /* Make sure this file really matches the pattern. */
135 if (!string_match(ptr, len, pfen->pattern, pfen->patlen, &smp_file))
136 goto top;
137 return len;
138 }
139
140 /* Clean up the file enumeration. */
141 void
gp_enumerate_files_close(file_enum * pfen)142 gp_enumerate_files_close(file_enum * pfen)
143 {
144 gs_memory_t *mem = pfen->memory;
145
146 gs_free_object(mem, pfen->pattern,
147 "gp_enumerate_files_close(pattern)");
148 gs_free_object(mem, pfen, "gp_enumerate_files_close");
149 }
150