1 #define PERL_NO_GET_CONTEXT
9 #define MY_CXT_KEY "File::Glob::_guts" XS_VERSION
19 #define GLOB_ERROR (MY_CXT.x_GLOB_ERROR)
21 #include "const-c.inc"
27 errfunc(const char *foo, int bar) {
29 return !(bar == EACCES || bar == ENOENT || bar == ENOTDIR);
34 doglob(pTHX_ const char *pattern, int flags)
45 memset(&pglob, 0, sizeof(glob_t));
46 retval = bsd_glob(pattern, flags, errfunc, &pglob);
49 /* return any matches found */
50 EXTEND(sp, pglob.gl_pathc);
51 for (i = 0; i < pglob.gl_pathc; i++) {
52 /* printf("# bsd_glob: %s\n", pglob.gl_pathv[i]); */
53 tmp = newSVpvn_flags(pglob.gl_pathv[i], strlen(pglob.gl_pathv[i]),
65 /* borrowed heavily from gsar's File::DosGlob, but translated into C */
83 /* assume global context if not provided one */
85 if (SvOK(cxixsv)) cxixpv = SvPV_nomg(cxixsv, cxixlen);
86 else cxixpv = "_G_", cxixlen = 3;
88 if (!MY_CXT.x_GLOB_ITER) MY_CXT.x_GLOB_ITER = newHV();
89 itersv = *(hv_fetch(MY_CXT.x_GLOB_ITER, cxixpv, cxixlen, 1));
90 if (!SvOK(itersv)) sv_setiv(itersv,0);
92 if (!MY_CXT.x_GLOB_ENTRIES) MY_CXT.x_GLOB_ENTRIES = newHV();
93 entriesv = *(hv_fetch(MY_CXT.x_GLOB_ENTRIES, cxixpv, cxixlen, 1));
95 /* if we're just beginning, do it all first */
100 const char *piece = NULL;
103 (int)SvIV(get_sv("File::Glob::DEFAULT_FLAGS", GV_ADD));
106 /* glob without args defaults to $_ */
110 && (patsv = DEFSV, SvGETMAGIC(patsv), !SvOK(patsv))
112 pat = "", len = 0, is_utf8 = 0;
113 else pat = SvPV_nomg(patsv,len), is_utf8 = !!SvUTF8(patsv);
116 /* extract patterns */
117 /* XXX this is needed for compatibility with the csh
118 * implementation in Perl. Need to support a flag
119 * to disable this behavior.
122 while (++s < patend) {
130 if (is_utf8) SvUTF8_on(word);
132 if (piece) sv_catpvn(word, piece, s-piece);
134 while (++s <= patend)
136 else if (*s == *(piece-1)) {
137 sv_catpvn(word, piece, s-piece);
142 if (!found) { /* unmatched quote */
143 /* Give up on tokenisation and treat the whole string
144 as a single token, but with whitespace stripped. */
146 while (isSPACE(*pat)) pat++;
147 while (isSPACE(*(patend-1))) patend--;
148 /* bsd_glob expects a trailing null, but we cannot mod-
150 if (patend < SvEND(patsv)) {
151 if (word) sv_setpvn(word, pat, patend-pat);
153 word = newSVpvn_flags(
154 pat, patend-pat, SVf_UTF8*is_utf8
159 if (word) SvREFCNT_dec(word), word=NULL;
167 case '\\': if (!piece) piece = s; s++; break;
172 word = newSVpvn(piece,s-piece);
173 if (is_utf8) SvUTF8_on(word);
175 else sv_catpvn(word, piece, s-piece);
178 if (!patav) patav = (AV *)sv_2mortal((SV *)newAV());
179 av_push(patav, word);
183 else if (!piece) piece = s;
189 assert(!SvROK(entriesv));
190 entries = (AV *)newSVrv(entriesv,NULL);
191 sv_upgrade((SV *)entries, SVt_PVAV);
194 I32 items = AvFILLp(patav) + 1;
195 SV **svp = AvARRAY(patav);
199 doglob(aTHX_ SvPVXx(*svp++), flags);
205 av_push(entries, SvREFCNT_inc_simple_NN(*MARK));
210 /* piece is set at this point if there is no trailing whitespace.
211 It is the beginning of the last token or quote-delimited
212 piece thereof. word is set at this point if the last token has
213 multiple quoted pieces. */
216 if (piece) sv_catpvn(word, piece, s-piece);
221 doglob(aTHX_ piece, flags);
222 if (word) SvREFCNT_dec(word);
228 av_push(entries, SvREFCNT_inc_simple_NN(*MARK));
229 /* short-circuit here for a fairly common case */
230 if (!patav && gimme == G_ARRAY) goto return_list;
237 /* chuck it all out, quick or slow */
238 assert(SvROK(entriesv));
239 if (!entries) entries = (AV *)SvRV(entriesv);
240 if (gimme == G_ARRAY) {
241 Copy(AvARRAY(entries), SP+1, AvFILLp(entries)+1, SV *);
242 SP += AvFILLp(entries)+1;
244 hv_delete(MY_CXT.x_GLOB_ITER, cxixpv, cxixlen, G_DISCARD);
245 /* No G_DISCARD here! It will free the stack items. */
246 hv_delete(MY_CXT.x_GLOB_ENTRIES, cxixpv, cxixlen, 0);
249 if (AvFILLp(entries) + 1) {
250 sv_setiv(itersv, AvFILLp(entries) + 1);
251 mPUSHs(av_shift(entries));
254 /* return undef for EOL */
255 hv_delete(MY_CXT.x_GLOB_ITER, cxixpv, cxixlen, G_DISCARD);
256 hv_delete(MY_CXT.x_GLOB_ENTRIES, cxixpv, cxixlen, G_DISCARD);
263 MODULE = File::Glob PACKAGE = File::Glob
275 bsd_glob(pattern,...)
287 /* allow for optional flags argument */
289 flags = (int) SvIV(ST(1));
290 /* remove unsupported flags */
291 flags &= ~(GLOB_APPEND | GLOB_DOOFFS | GLOB_ALTDIRFUNC | GLOB_MAGCHAR);
293 flags = (int) SvIV(get_sv("File::Glob::DEFAULT_FLAGS", GV_ADD));
297 doglob(aTHX_ pattern, flags);
305 /* For backward-compatibility with the original Perl function, we sim-
306 * ply take the first two arguments, regardless of how many there are.
308 if (items >= 2) SP += 2;
311 XPUSHs(&PL_sv_undef);
312 if (!items) XPUSHs(&PL_sv_undef);
320 #ifndef PERL_EXTERNAL_GLOB
321 /* Don’t do this at home! The globhook interface is highly volatile. */
322 PL_globhook = csh_glob;
331 MY_CXT.x_GLOB_ITER = MY_CXT.x_GLOB_ENTRIES = NULL;
335 INCLUDE: const-xs.inc