1 #define PERL_NO_GET_CONTEXT
9 #define MY_CXT_KEY "File::Glob::_guts" XS_VERSION
14 Perl_ophook_t x_GLOB_OLD_OPHOOK;
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]),
66 iterate(pTHX_ bool(*globber)(pTHX_ AV *entries, SV *patsv))
71 const char * const cxixpv = (char *)&PL_op;
72 STRLEN const cxixlen = sizeof(OP *);
74 U32 const gimme = GIMME_V;
76 bool on_stack = FALSE;
78 if (!MY_CXT.x_GLOB_ENTRIES) MY_CXT.x_GLOB_ENTRIES = newHV();
79 entries = (AV *)*(hv_fetch(MY_CXT.x_GLOB_ENTRIES, cxixpv, cxixlen, 1));
81 /* if we're just beginning, do it all first */
82 if (SvTYPE(entries) != SVt_PVAV) {
84 on_stack = globber(aTHX_ entries, patsv);
88 /* chuck it all out, quick or slow */
89 if (gimme == G_ARRAY) {
91 EXTEND(SP, AvFILLp(entries)+1);
92 Copy(AvARRAY(entries), SP+1, AvFILLp(entries)+1, SV *);
93 SP += AvFILLp(entries)+1;
95 /* No G_DISCARD here! It will free the stack items. */
96 hv_delete(MY_CXT.x_GLOB_ENTRIES, cxixpv, cxixlen, 0);
99 if (AvFILLp(entries) + 1) {
100 mPUSHs(av_shift(entries));
103 /* return undef for EOL */
104 hv_delete(MY_CXT.x_GLOB_ENTRIES, cxixpv, cxixlen, G_DISCARD);
111 /* returns true if the items are on the stack already, but only in
114 csh_glob(pTHX_ AV *entries, SV *patsv)
120 const char *s = NULL;
121 const char *piece = NULL;
124 (int)SvIV(get_sv("File::Glob::DEFAULT_FLAGS", GV_ADD));
127 U32 const gimme = GIMME_V;
129 /* glob without args defaults to $_ */
133 && (patsv = DEFSV, SvGETMAGIC(patsv), !SvOK(patsv))
135 pat = "", len = 0, is_utf8 = 0;
136 else pat = SvPV_nomg(patsv,len), is_utf8 = !!SvUTF8(patsv);
139 /* extract patterns */
141 while (++s < patend) {
147 const char quote = *s;
150 if (is_utf8) SvUTF8_on(word);
152 if (piece) sv_catpvn(word, piece, s-piece);
157 /* If the backslash is here to escape a quote,
159 if (s < patend && *s == quote)
160 sv_catpvn(word, piece, s-piece-1), piece = s;
162 else if (*s == quote) {
163 sv_catpvn(word, piece, s-piece);
168 if (!found) { /* unmatched quote */
169 /* Give up on tokenisation and treat the whole string
170 as a single token, but with whitespace stripped. */
172 while (isSPACE(*pat)) pat++;
173 while (isSPACE(*(patend-1))) patend--;
174 /* bsd_glob expects a trailing null, but we cannot mod-
176 if (patend < SvEND(patsv)) {
177 if (word) sv_setpvn(word, pat, patend-pat);
179 word = newSVpvn_flags(
180 pat, patend-pat, SVf_UTF8*is_utf8
185 if (word) SvREFCNT_dec(word), word=NULL;
194 if (!piece) piece = s;
196 /* If the backslash is here to escape a quote,
198 if (s < patend && (*s == '"' || *s == '\'')) {
200 word = newSVpvn(piece,s-piece-1);
201 if (is_utf8) SvUTF8_on(word);
203 else sv_catpvn(word, piece, s-piece-1);
211 word = newSVpvn(piece,s-piece);
212 if (is_utf8) SvUTF8_on(word);
214 else sv_catpvn(word, piece, s-piece);
217 if (!patav) patav = (AV *)sv_2mortal((SV *)newAV());
218 av_push(patav, word);
222 else if (!piece) piece = s;
228 assert(SvTYPE(entries) != SVt_PVAV);
229 sv_upgrade((SV *)entries, SVt_PVAV);
230 if (!IS_SAFE_SYSCALL(patsv, "pattern", "glob"))
234 I32 items = AvFILLp(patav) + 1;
235 SV **svp = AvARRAY(patav);
239 doglob(aTHX_ SvPVXx(*svp++), flags);
245 av_push(entries, SvREFCNT_inc_simple_NN(*MARK));
250 /* piece is set at this point if there is no trailing whitespace.
251 It is the beginning of the last token or quote-delimited
252 piece thereof. word is set at this point if the last token has
253 multiple quoted pieces. */
256 if (piece) sv_catpvn(word, piece, s-piece);
261 doglob(aTHX_ piece, flags);
262 if (word) SvREFCNT_dec(word);
267 /* short-circuit here for a fairly common case */
268 if (!patav && gimme == G_ARRAY) { PUTBACK; return TRUE; }
270 av_push(entries, SvREFCNT_inc_simple_NN(*MARK));
282 iterate(aTHX_ csh_glob);
285 /* wrapper around doglob that can be passed to the iterator */
287 doglob_iter_wrapper(pTHX_ AV *entries, SV *patsv)
292 (int)SvIV(get_sv("File::Glob::DEFAULT_FLAGS", GV_ADD));
297 && (patsv = DEFSV, SvGETMAGIC(patsv), !SvOK(patsv))
300 else pattern = SvPV_nomg_nolen(patsv);
304 doglob(aTHX_ pattern, flags);
309 if (GIMME_V == G_ARRAY) { PUTBACK; return TRUE; }
310 sv_upgrade((SV *)entries, SVt_PVAV);
312 av_push(entries, SvREFCNT_inc_simple_NN(*MARK));
319 glob_ophook(pTHX_ OP *o)
321 if (PL_dirty) return;
324 if (MY_CXT.x_GLOB_ENTRIES
325 && (o->op_type == OP_GLOB || o->op_type == OP_ENTERSUB))
326 hv_delete(MY_CXT.x_GLOB_ENTRIES, (char *)&o, sizeof(OP *),
328 if (MY_CXT.x_GLOB_OLD_OPHOOK) MY_CXT.x_GLOB_OLD_OPHOOK(aTHX_ o);
332 MODULE = File::Glob PACKAGE = File::Glob
344 bsd_glob(pattern,...)
350 /* allow for optional flags argument */
352 flags = (int) SvIV(ST(1));
353 /* remove unsupported flags */
354 flags &= ~(GLOB_APPEND | GLOB_DOOFFS | GLOB_ALTDIRFUNC | GLOB_MAGCHAR);
356 flags = (int) SvIV(get_sv("File::Glob::DEFAULT_FLAGS", GV_ADD));
360 doglob(aTHX_ pattern, flags);
368 /* For backward-compatibility with the original Perl function, we sim-
369 * ply take the first argument, regardless of how many there are.
373 XPUSHs(&PL_sv_undef);
380 bsd_glob_override(...)
384 XPUSHs(&PL_sv_undef);
387 iterate(aTHX_ doglob_iter_wrapper);
392 #ifndef PERL_EXTERNAL_GLOB
393 /* Don't do this at home! The globhook interface is highly volatile. */
394 PL_globhook = csh_glob_iter;
403 MY_CXT.x_GLOB_ENTRIES = NULL;
404 MY_CXT.x_GLOB_OLD_OPHOOK = PL_opfreehook;
405 PL_opfreehook = glob_ophook;
409 INCLUDE: const-xs.inc