1 #define PERL_NO_GET_CONTEXT
9 #define MY_CXT_KEY "File::Glob::_guts" XS_VERSION
18 #define GLOB_ERROR (MY_CXT.x_GLOB_ERROR)
20 #include "const-c.inc"
26 errfunc(const char *foo, int bar) {
28 return !(bar == EACCES || bar == ENOENT || bar == ENOTDIR);
33 doglob(pTHX_ const char *pattern, int flags)
44 memset(&pglob, 0, sizeof(glob_t));
45 retval = bsd_glob(pattern, flags, errfunc, &pglob);
48 /* return any matches found */
49 EXTEND(sp, pglob.gl_pathc);
50 for (i = 0; i < pglob.gl_pathc; i++) {
51 /* printf("# bsd_glob: %s\n", pglob.gl_pathv[i]); */
52 tmp = newSVpvn_flags(pglob.gl_pathv[i], strlen(pglob.gl_pathv[i]),
65 iterate(pTHX_ bool(*globber)(pTHX_ AV *entries, SV *patsv))
70 SV * const cxixsv = POPs;
74 U32 const gimme = GIMME_V;
76 bool on_stack = FALSE;
78 /* assume global context if not provided one */
80 if (SvOK(cxixsv)) cxixpv = SvPV_nomg(cxixsv, cxixlen);
81 else cxixpv = "_G_", cxixlen = 3;
83 if (!MY_CXT.x_GLOB_ENTRIES) MY_CXT.x_GLOB_ENTRIES = newHV();
84 entries = (AV *)*(hv_fetch(MY_CXT.x_GLOB_ENTRIES, cxixpv, cxixlen, 1));
86 /* if we're just beginning, do it all first */
87 if (SvTYPE(entries) != SVt_PVAV) {
89 on_stack = globber(aTHX_ entries, patsv);
93 /* chuck it all out, quick or slow */
94 if (gimme == G_ARRAY) {
96 Copy(AvARRAY(entries), SP+1, AvFILLp(entries)+1, SV *);
97 SP += AvFILLp(entries)+1;
99 /* No G_DISCARD here! It will free the stack items. */
100 hv_delete(MY_CXT.x_GLOB_ENTRIES, cxixpv, cxixlen, 0);
103 if (AvFILLp(entries) + 1) {
104 mPUSHs(av_shift(entries));
107 /* return undef for EOL */
108 hv_delete(MY_CXT.x_GLOB_ENTRIES, cxixpv, cxixlen, G_DISCARD);
115 /* returns true if the items are on the stack already, but only in
118 csh_glob(pTHX_ AV *entries, SV *patsv)
124 const char *s = NULL;
125 const char *piece = NULL;
128 (int)SvIV(get_sv("File::Glob::DEFAULT_FLAGS", GV_ADD));
131 U32 const gimme = GIMME_V;
133 /* glob without args defaults to $_ */
137 && (patsv = DEFSV, SvGETMAGIC(patsv), !SvOK(patsv))
139 pat = "", len = 0, is_utf8 = 0;
140 else pat = SvPV_nomg(patsv,len), is_utf8 = !!SvUTF8(patsv);
143 /* extract patterns */
145 while (++s < patend) {
151 const char quote = *s;
154 if (is_utf8) SvUTF8_on(word);
156 if (piece) sv_catpvn(word, piece, s-piece);
161 /* If the backslash is here to escape a quote,
163 if (s < patend && *s == quote)
164 sv_catpvn(word, piece, s-piece-1), piece = s;
166 else if (*s == quote) {
167 sv_catpvn(word, piece, s-piece);
172 if (!found) { /* unmatched quote */
173 /* Give up on tokenisation and treat the whole string
174 as a single token, but with whitespace stripped. */
176 while (isSPACE(*pat)) pat++;
177 while (isSPACE(*(patend-1))) patend--;
178 /* bsd_glob expects a trailing null, but we cannot mod-
180 if (patend < SvEND(patsv)) {
181 if (word) sv_setpvn(word, pat, patend-pat);
183 word = newSVpvn_flags(
184 pat, patend-pat, SVf_UTF8*is_utf8
189 if (word) SvREFCNT_dec(word), word=NULL;
198 if (!piece) piece = s;
200 /* If the backslash is here to escape a quote,
202 if (s < patend && (*s == '"' || *s == '\'')) {
204 word = newSVpvn(piece,s-piece-1);
205 if (is_utf8) SvUTF8_on(word);
207 else sv_catpvn(word, piece, s-piece-1);
215 word = newSVpvn(piece,s-piece);
216 if (is_utf8) SvUTF8_on(word);
218 else sv_catpvn(word, piece, s-piece);
221 if (!patav) patav = (AV *)sv_2mortal((SV *)newAV());
222 av_push(patav, word);
226 else if (!piece) piece = s;
232 assert(SvTYPE(entries) != SVt_PVAV);
233 sv_upgrade((SV *)entries, SVt_PVAV);
236 I32 items = AvFILLp(patav) + 1;
237 SV **svp = AvARRAY(patav);
241 doglob(aTHX_ SvPVXx(*svp++), flags);
247 av_push(entries, SvREFCNT_inc_simple_NN(*MARK));
252 /* piece is set at this point if there is no trailing whitespace.
253 It is the beginning of the last token or quote-delimited
254 piece thereof. word is set at this point if the last token has
255 multiple quoted pieces. */
258 if (piece) sv_catpvn(word, piece, s-piece);
263 doglob(aTHX_ piece, flags);
264 if (word) SvREFCNT_dec(word);
269 /* short-circuit here for a fairly common case */
270 if (!patav && gimme == G_ARRAY) { PUTBACK; return TRUE; }
272 av_push(entries, SvREFCNT_inc_simple_NN(*MARK));
284 iterate(aTHX_ csh_glob);
287 /* wrapper around doglob that can be passed to the iterator */
289 doglob_iter_wrapper(pTHX_ AV *entries, SV *patsv)
294 (int)SvIV(get_sv("File::Glob::DEFAULT_FLAGS", GV_ADD));
299 && (patsv = DEFSV, SvGETMAGIC(patsv), !SvOK(patsv))
302 else pattern = SvPV_nomg_nolen(patsv);
306 doglob(aTHX_ pattern, flags);
311 if (GIMME_V == G_ARRAY) { PUTBACK; return TRUE; }
312 sv_upgrade((SV *)entries, SVt_PVAV);
314 av_push(entries, SvREFCNT_inc_simple_NN(*MARK));
320 MODULE = File::Glob PACKAGE = File::Glob
332 bsd_glob(pattern,...)
338 /* allow for optional flags argument */
340 flags = (int) SvIV(ST(1));
341 /* remove unsupported flags */
342 flags &= ~(GLOB_APPEND | GLOB_DOOFFS | GLOB_ALTDIRFUNC | GLOB_MAGCHAR);
344 flags = (int) SvIV(get_sv("File::Glob::DEFAULT_FLAGS", GV_ADD));
348 doglob(aTHX_ pattern, flags);
356 /* For backward-compatibility with the original Perl function, we sim-
357 * ply take the first two arguments, regardless of how many there are.
359 if (items >= 2) SP += 2;
362 XPUSHs(&PL_sv_undef);
363 if (!items) XPUSHs(&PL_sv_undef);
370 bsd_glob_override(...)
372 if (items >= 2) SP += 2;
375 XPUSHs(&PL_sv_undef);
376 if (!items) XPUSHs(&PL_sv_undef);
379 iterate(aTHX_ doglob_iter_wrapper);
384 #ifndef PERL_EXTERNAL_GLOB
385 /* Don't do this at home! The globhook interface is highly volatile. */
386 PL_globhook = csh_glob_iter;
395 MY_CXT.x_GLOB_ENTRIES = NULL;
399 INCLUDE: const-xs.inc