1 #define PERL_NO_GET_CONTEXT
9 #define MY_CXT_KEY "File::Glob::_guts" XS_VERSION
17 Perl_ophook_t x_GLOB_OLD_OPHOOK;
22 #define GLOB_ERROR (MY_CXT.x_GLOB_ERROR)
24 #include "const-c.inc"
30 errfunc(const char *foo, int bar) {
32 return !(bar == EACCES || bar == ENOENT || bar == ENOTDIR);
37 doglob(pTHX_ const char *pattern, int flags)
48 memset(&pglob, 0, sizeof(glob_t));
49 retval = bsd_glob(pattern, flags, errfunc, &pglob);
52 /* return any matches found */
53 EXTEND(sp, pglob.gl_pathc);
54 for (i = 0; i < pglob.gl_pathc; i++) {
55 /* printf("# bsd_glob: %s\n", pglob.gl_pathv[i]); */
56 tmp = newSVpvn_flags(pglob.gl_pathv[i], strlen(pglob.gl_pathv[i]),
69 iterate(pTHX_ bool(*globber)(pTHX_ AV *entries, const char *pat, STRLEN len, bool is_utf8))
74 const char * const cxixpv = (char *)&PL_op;
75 STRLEN const cxixlen = sizeof(OP *);
77 U32 const gimme = GIMME_V;
79 bool on_stack = FALSE;
81 if (!MY_CXT.x_GLOB_ENTRIES) MY_CXT.x_GLOB_ENTRIES = newHV();
82 entries = (AV *)*(hv_fetch(MY_CXT.x_GLOB_ENTRIES, cxixpv, cxixlen, 1));
84 /* if we're just beginning, do it all first */
85 if (SvTYPE(entries) != SVt_PVAV) {
90 /* glob without args defaults to $_ */
94 && (patsv = DEFSV, SvGETMAGIC(patsv), !SvOK(patsv))
101 pat = SvPV_nomg(patsv,len);
102 is_utf8 = !!SvUTF8(patsv);
105 if (!IS_SAFE_SYSCALL(pat, len, "pattern", "glob")) {
106 if (gimme != G_ARRAY)
113 on_stack = globber(aTHX_ entries, pat, len, is_utf8);
117 /* chuck it all out, quick or slow */
118 if (gimme == G_ARRAY) {
120 EXTEND(SP, AvFILLp(entries)+1);
121 Copy(AvARRAY(entries), SP+1, AvFILLp(entries)+1, SV *);
122 SP += AvFILLp(entries)+1;
124 /* No G_DISCARD here! It will free the stack items. */
125 hv_delete(MY_CXT.x_GLOB_ENTRIES, cxixpv, cxixlen, 0);
128 if (AvFILLp(entries) + 1) {
129 mPUSHs(av_shift(entries));
132 /* return undef for EOL */
133 hv_delete(MY_CXT.x_GLOB_ENTRIES, cxixpv, cxixlen, G_DISCARD);
140 /* returns true if the items are on the stack already, but only in
143 csh_glob(pTHX_ AV *entries, const char *pat, STRLEN len, bool is_utf8)
148 const char *s = NULL;
149 const char *piece = NULL;
152 (int)SvIV(get_sv("File::Glob::DEFAULT_FLAGS", GV_ADD));
153 U32 const gimme = GIMME_V;
157 assert(SvTYPE(entries) != SVt_PVAV);
158 sv_upgrade((SV *)entries, SVt_PVAV);
160 /* extract patterns */
162 while (++s < patend) {
168 const char quote = *s;
171 if (is_utf8) SvUTF8_on(word);
173 if (piece) sv_catpvn(word, piece, s-piece);
178 /* If the backslash is here to escape a quote,
180 if (s < patend && *s == quote)
181 sv_catpvn(word, piece, s-piece-1), piece = s;
183 else if (*s == quote) {
184 sv_catpvn(word, piece, s-piece);
189 if (!found) { /* unmatched quote */
190 /* Give up on tokenisation and treat the whole string
191 as a single token, but with whitespace stripped. */
193 while (isSPACE(*pat)) pat++;
194 while (isSPACE(*(patend-1))) patend--;
195 /* bsd_glob expects a trailing null, but we cannot mod-
197 if (patend < pat + len) {
198 if (word) sv_setpvn(word, pat, patend-pat);
200 word = newSVpvn_flags(
201 pat, patend-pat, SVf_UTF8*is_utf8
206 if (word) SvREFCNT_dec(word), word=NULL;
215 if (!piece) piece = s;
217 /* If the backslash is here to escape a quote,
219 if (s < patend && (*s == '"' || *s == '\'')) {
221 word = newSVpvn(piece,s-piece-1);
222 if (is_utf8) SvUTF8_on(word);
224 else sv_catpvn(word, piece, s-piece-1);
232 word = newSVpvn(piece,s-piece);
233 if (is_utf8) SvUTF8_on(word);
235 else sv_catpvn(word, piece, s-piece);
238 if (!patav) patav = (AV *)sv_2mortal((SV *)newAV());
239 av_push(patav, word);
243 else if (!piece) piece = s;
250 I32 items = AvFILLp(patav) + 1;
251 SV **svp = AvARRAY(patav);
255 doglob(aTHX_ SvPVXx(*svp++), flags);
261 av_push(entries, SvREFCNT_inc_simple_NN(*MARK));
266 /* piece is set at this point if there is no trailing whitespace.
267 It is the beginning of the last token or quote-delimited
268 piece thereof. word is set at this point if the last token has
269 multiple quoted pieces. */
272 if (piece) sv_catpvn(word, piece, s-piece);
277 doglob(aTHX_ piece, flags);
278 if (word) SvREFCNT_dec(word);
283 /* short-circuit here for a fairly common case */
284 if (!patav && gimme == G_ARRAY) { PUTBACK; return TRUE; }
286 av_push(entries, SvREFCNT_inc_simple_NN(*MARK));
298 iterate(aTHX_ csh_glob);
301 /* wrapper around doglob that can be passed to the iterator */
303 doglob_iter_wrapper(pTHX_ AV *entries, const char *pattern, STRLEN len, bool is_utf8)
307 (int)SvIV(get_sv("File::Glob::DEFAULT_FLAGS", GV_ADD));
311 doglob(aTHX_ pattern, flags);
316 if (GIMME_V == G_ARRAY) { PUTBACK; return TRUE; }
317 sv_upgrade((SV *)entries, SVt_PVAV);
319 av_push(entries, SvREFCNT_inc_simple_NN(*MARK));
326 glob_ophook(pTHX_ OP *o)
328 if (PL_dirty) return;
331 if (MY_CXT.x_GLOB_ENTRIES
332 && (o->op_type == OP_GLOB || o->op_type == OP_ENTERSUB))
333 hv_delete(MY_CXT.x_GLOB_ENTRIES, (char *)&o, sizeof(OP *),
335 if (MY_CXT.x_GLOB_OLD_OPHOOK) MY_CXT.x_GLOB_OLD_OPHOOK(aTHX_ o);
339 MODULE = File::Glob PACKAGE = File::Glob
351 bsd_glob(pattern_sv,...)
359 pattern = SvPV(pattern_sv, len);
360 if (!IS_SAFE_SYSCALL(pattern, len, "pattern", "bsd_glob"))
362 /* allow for optional flags argument */
364 flags = (int) SvIV(ST(1));
365 /* remove unsupported flags */
366 flags &= ~(GLOB_APPEND | GLOB_DOOFFS | GLOB_ALTDIRFUNC | GLOB_MAGCHAR);
368 flags = (int) SvIV(get_sv("File::Glob::DEFAULT_FLAGS", GV_ADD));
372 doglob(aTHX_ pattern, flags);
380 /* For backward-compatibility with the original Perl function, we sim-
381 * ply take the first argument, regardless of how many there are.
385 XPUSHs(&PL_sv_undef);
392 bsd_glob_override(...)
396 XPUSHs(&PL_sv_undef);
399 iterate(aTHX_ doglob_iter_wrapper);
407 HV *glob_entries_clone = NULL;
409 PERL_UNUSED_ARG(items);
412 if ( MY_CXT.x_GLOB_ENTRIES ) {
414 param.stashes = NULL;
416 param.proto_perl = MY_CXT.interp;
418 glob_entries_clone = MUTABLE_HV(sv_dup_inc((SV*)MY_CXT.x_GLOB_ENTRIES, ¶m));
423 MY_CXT.x_GLOB_ENTRIES = glob_entries_clone;
424 MY_CXT.interp = aTHX;
431 #ifndef PERL_EXTERNAL_GLOB
432 /* Don't do this at home! The globhook interface is highly volatile. */
433 PL_globhook = csh_glob_iter;
442 MY_CXT.x_GLOB_ENTRIES = NULL;
443 MY_CXT.x_GLOB_OLD_OPHOOK = PL_opfreehook;
445 MY_CXT.interp = aTHX;
447 PL_opfreehook = glob_ophook;
451 INCLUDE: const-xs.inc