static SgObject convert_star(SgObject p) { /* for may laziness, we use regular expression for '*' */ SgObject h = SG_NIL, t = SG_NIL; int has_star = FALSE; SG_FOR_EACH(p, p) { if (SG_EQ(SG_CAR(p), STAR)) { has_star = TRUE; break; } SG_APPEND1(h, t, SG_CAR(p)); } if (has_star) { /* TODO should we use AST directly to save some memory? */ SgPort *out; SgStringPort tp; /* copy value until the first '{' */ out = Sg_InitStringOutputPort(&tp, 255); Sg_PutzUnsafe(out, ".*"); SG_FOR_EACH(p, SG_CDR(p)) { if (SG_STRINGP(SG_CAR(p))) { Sg_PutsUnsafe(out, SG_STRING(SG_CAR(p))); } else if (SG_CHAR_SET_P(SG_CAR(p))) { Sg_PutsUnsafe(out, Sg_CharSetToRegexString(SG_CAR(p), FALSE)); } else if (SG_EQ(SG_CAR(p), STAR)) { Sg_PutzUnsafe(out, ".*"); } else { Sg_Error(UC("[Internal] Unknown pattern '%S'"), SG_CAR(p)); } } Sg_PutcUnsafe(out, '$'); SG_APPEND1(h, t, Sg_CompileRegex(Sg_GetStringFromStringPort(&tp), 0, FALSE)); SG_CLEAN_STRING_PORT(&tp); return h; } /* FIXME: we don't want to allocate memory in this case */ return h; }
SgObject Sg_ReadDirectory(SgString *path) { DIR* dir; struct dirent* entry; SgObject h = SG_NIL, t = SG_NIL; if (NULL == (dir = opendir(Sg_Utf32sToUtf8s(path)))) { return SG_FALSE; } for (entry = readdir(dir); entry != NULL; entry = readdir(dir)) { SG_APPEND1(h, t, Sg_Utf8sToUtf32s(entry->d_name, strlen(entry->d_name))); } closedir(dir); return h; }
static SgObject glob_make_pattern(SgString *path, int flags) { const int escape = !(flags & SG_NOESCAPE); SgObject h = SG_NIL, t = SG_NIL, h1 = SG_NIL, t1 = SG_NIL; int i, start; #define emit() \ do { \ if (start != i) { \ SgObject tmp = Sg_Substring(path, start, i); \ if (escape) tmp = remove_backslashes(tmp); \ SG_APPEND1(h1, t1, tmp); \ } \ start = i+1; \ } while (0) for (i = 0, start = 0; i < SG_STRING_SIZE(path);) { SgChar c = SG_STRING_VALUE_AT(path, i); switch (c) { case '[': { int s = i, e; e = find_close_bracket(path, start, flags); if (s != e) { emit(); SG_APPEND1(h1, t1, Sg_ParseCharSetString(path, FALSE, s, i=++e)); start = i; } i++; } break; case '/': /* next */ emit(); /* if the path starts with '/', then this can be null */ if (!SG_NULLP(h1)) { SG_APPEND1(h, t, convert_star(h1)); } h1 = t1 = SG_NIL; /* reset it */ /* this need to be updated */ start = ++i; break; case '*': { int has = (start != i); emit(); /* merge it if it's there */ if (!has && SG_STRING_SIZE(path) - i >= 3 && SG_STRING_VALUE_AT(path, i+1) == '*' && SG_STRING_VALUE_AT(path, i+2) == '/') { do { i += 3; /* skip '/' */ while (SG_STRING_VALUE_AT(path, i) == '/') i++; } while (SG_STRING_VALUE_AT(path, i) == '*' && SG_STRING_VALUE_AT(path, i+1) == '*' && SG_STRING_VALUE_AT(path, i+2) == '/'); SG_APPEND1(h1, t1, STAR_SLASH); SG_APPEND1(h, t, h1); h1 = t1 = SG_NIL; /* reset it */ start = i; } else { SG_APPEND1(h1, t1, STAR); while (SG_STRING_VALUE_AT(path, i) == '*') i++; } break; } case '?': emit(); SG_APPEND1(h1, t1, FULL_CHARSET); i++; break; default: i++; break; } } emit(); if (!SG_NULLP(h1)) { SG_APPEND1(h, t, convert_star(h1)); SG_APPEND1(h, t, SG_LIST1(ANY)); } else { SG_APPEND1(h, t, SG_LIST1(DIR)); } #undef emit return h; }