xref: /plan9/sys/src/cmd/gs/src/gp_dosfe.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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