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