1 /* Copyright (C) 1994 artofcode LLC. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify it
4 under the terms of the GNU General Public License as published by the
5 Free Software Foundation; either version 2 of the License, or (at your
6 option) any later version.
7
8 This program is distributed in the hope that it will be useful, but
9 WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16
17 */
18
19 /*$Id: gp_dosfe.c,v 1.2.6.2.2.1 2003/01/17 00:49:02 giles Exp $ */
20 /* MS-DOS file enumeration. */
21 #include "stdio_.h"
22 #include <fcntl.h>
23 #include "dos_.h"
24 #include "memory_.h"
25 #include "string_.h"
26 #include "gstypes.h"
27 #include "gsmemory.h"
28 #include "gsstruct.h"
29 #include "gp.h"
30 #include "gsutil.h"
31
32 struct file_enum_s {
33 ff_struct_t ffblk;
34 char *pattern; /* orig pattern + modified pattern */
35 int patlen; /* orig pattern length */
36 int pat_size; /* allocate space for pattern */
37 int head_size; /* pattern length through last */
38 /* :, / or \ */
39 int first_time;
40 gs_memory_t *memory;
41 };
42 gs_private_st_ptrs1(st_file_enum, struct file_enum_s, "file_enum",
43 file_enum_enum_ptrs, file_enum_reloc_ptrs, pattern);
44
45 /* Initialize an enumeration. Note that * and ? in a directory */
46 /* don't work, and \ is taken literally unless a second \ follows. */
47 file_enum *
gp_enumerate_files_init(const char * pat,uint patlen,gs_memory_t * mem)48 gp_enumerate_files_init(const char *pat, uint patlen, gs_memory_t * mem)
49 {
50 file_enum *pfen = gs_alloc_struct(mem, file_enum, &st_file_enum, "gp_enumerate_files");
51 int pat_size = 2 * patlen + 1;
52 char *pattern;
53 char *p;
54 int hsize = 0;
55 int i;
56 int dot = 0;
57
58 if (pfen == 0)
59 return 0;
60
61 /* pattern could be allocated as a string, */
62 /* but it's simpler for GC and freeing to allocate it as bytes. */
63
64 pattern = (char *)gs_alloc_bytes(mem, pat_size,
65 "gp_enumerate_files(pattern)");
66 if (pattern == 0)
67 return 0;
68 memcpy(pattern, pat, patlen);
69 p = pattern + patlen;
70 for (i = 0; i < patlen; i++) {
71 switch (pat[i]) {
72 case '*':
73 /* Skip to . or end of string so DOS can do it. */
74 *p++ = '*';
75 while (i < patlen && pat[i] != '.')
76 i++;
77 if (i == patlen && !dot) { /* DOS doesn't interpret * alone as */
78 /* matching all files; we need *.*. */
79 *p++ = '.';
80 *p++ = '*';
81 }
82 i--;
83 continue;
84 case '.':
85 dot = 1;
86 break;
87 case '\\':
88 if (i + 1 < patlen && pat[i + 1] == '\\')
89 i++;
90 /* falls through */
91 case ':':
92 case '/':
93 hsize = p + 1 - (pattern + patlen);
94 dot = 0;
95 }
96 *p++ = pat[i];
97 }
98 *p = 0;
99 pfen->pattern = pattern;
100 pfen->patlen = patlen;
101 pfen->pat_size = pat_size;
102 pfen->head_size = hsize;
103 pfen->memory = mem;
104 pfen->first_time = 1;
105 return pfen;
106 }
107
108 /* Enumerate the next file. */
109 private const string_match_params smp_file =
110 {'*', '?', -1, true, true};
111
112 uint
gp_enumerate_files_next(file_enum * pfen,char * ptr,uint maxlen)113 gp_enumerate_files_next(file_enum * pfen, char *ptr, uint maxlen)
114 {
115 int code;
116 char *p, *q;
117 uint len;
118 const char *fpat = pfen->pattern + pfen->patlen;
119
120 top:if (pfen->first_time) {
121 code = dos_findfirst(fpat, &pfen->ffblk);
122 pfen->first_time = 0;
123 } else
124 code = dos_findnext(&pfen->ffblk);
125 if (code != 0) { /* All done, clean up. */
126 gp_enumerate_files_close(pfen);
127 return ~(uint) 0;
128 }
129 if (maxlen < 13 + pfen->head_size)
130 return maxlen + 1; /* cop out! */
131 memcpy(ptr, fpat, pfen->head_size);
132 for (p = &pfen->ffblk.ff_name[0], q = ptr + pfen->head_size; *p; p++)
133 if (*p != ' ')
134 *q++ = *p;
135 len = q - ptr;
136 /* Make sure this file really matches the pattern. */
137 if (!string_match(ptr, len, pfen->pattern, pfen->patlen, &smp_file))
138 goto top;
139 return len;
140 }
141
142 /* Clean up the file enumeration. */
143 void
gp_enumerate_files_close(file_enum * pfen)144 gp_enumerate_files_close(file_enum * pfen)
145 {
146 gs_memory_t *mem = pfen->memory;
147
148 gs_free_object(mem, pfen->pattern,
149 "gp_enumerate_files_close(pattern)");
150 gs_free_object(mem, pfen, "gp_enumerate_files_close");
151 }
152