/* TODO maybe try not to use string port? */ static SgObject normalise_path(SgObject fullpath) { SgStringPort sp; SgObject out = Sg_InitStringOutputPort(&sp, SG_STRING_SIZE(fullpath)); int64_t pos = 0; int i = 0; while (i < SG_STRING_SIZE(fullpath)) { SgChar c = SG_STRING_VALUE_AT(fullpath, i++); if (c == '.') { if (i != SG_STRING_SIZE(fullpath)) { SgChar c2 = SG_STRING_VALUE_AT(fullpath, i++); if (c2 == '.') { if (SG_STRING_VALUE_AT(fullpath, i) == '/' || SG_STRING_SIZE(fullpath) == i) { if (pos-2 > 0) { SgObject tmp = Sg_GetStringFromStringPort(out); /* skip previous '.' and '/' */ pos = search_separator(tmp, pos-2); } else { pos = 1; /* root */ } if (pos <= 0) pos = 1; /* root */ Sg_SetPortPosition(out, pos, SG_BEGIN); if (pos == 1) i++; } else { /* ok just a file named '..?' or longer*/ Sg_PutcUnsafe(out, '.'); Sg_PutcUnsafe(out, '.'); pos += 2; for (; i < SG_STRING_SIZE(fullpath); i++) { SgChar c3 = SG_STRING_VALUE_AT(fullpath, i); if (c3 != '.') break; Sg_PutcUnsafe(out, c3); pos++; } } } else if (c2 != '/') { Sg_PutcUnsafe(out, '.'); Sg_PutcUnsafe(out, c2); pos += 2; } } } else { Sg_PutcUnsafe(out, c); pos++; } } return strip_trailing_slash(Sg_GetStringFromStringPort(out)); }
static SgString* utf16ToUtf32WithRegion(wchar_t *s, wchar_t *e) { const SgChar offset = (0xd800 << 10UL) + 0xdc00 - 0x10000; SgPort *out; SgStringPort tp; SgObject r; out = Sg_InitStringOutputPort(&tp, (int)((e - s) * 2)); while (s < e) { SgChar c0 = *s++; if (isLead(c0)) { SgChar c1; if (s < e && isTrail((c1 = *s))) { s++; c0 = (c0 << 10) + c1 - offset; } else { return SG_MAKE_STRING("bad char"); } } Sg_PutcUnsafe(out, c0); } r = Sg_GetStringFromStringPort(&tp); SG_CLEAN_STRING_PORT(&tp); return r; }
static SgString* utf16ToUtf32(wchar_t *s) { const SgChar offset = (0xd800 << 10UL) + 0xdc00 - 0x10000; size_t i = 0, n = wcslen(s); SgPort *out; SgStringPort tp; SgObject r; out = Sg_InitStringOutputPort(&tp, (int)n); while (i < n) { SgChar c0 = s[i++]; if (isLead(c0)) { SgChar c1; if (i < n && isTrail((c1 = s[i]))) { i++; c0 = (c0 << 10) + c1 - offset; } else { return SG_MAKE_STRING("bad char"); } } Sg_PutcUnsafe(out, c0); } r = Sg_GetStringFromStringPort(&tp); SG_CLEAN_STRING_PORT(&tp); return r; }
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; }
static SgObject brace_expand(SgString *str, int flags) { const int escape = !(flags & SG_NOESCAPE); int lbrace = 0, rbrace = 0, nest = 0, i; int haslb = FALSE, hasrb = FALSE; /* find { and }*/ for (i = 0; i < SG_STRING_SIZE(str); i++) { if (SG_STRING_VALUE_AT(str, i) == '{' && nest++ == 0) { lbrace = i; haslb = TRUE; } if (SG_STRING_VALUE_AT(str, i) == '}' && --nest == 0) { rbrace = i; hasrb = TRUE; break; } if (SG_STRING_VALUE_AT(str, i) == '\\' && escape) { if (++i == SG_STRING_SIZE(str)) break; } } /* make "foo/{a,b}" to ("foo/a" "foo/b") */ if (haslb && hasrb) { SgObject h = SG_NIL, t = SG_NIL; SgPort *out; SgStringPort tp; int i; /* copy value until the first '{' */ out = Sg_InitStringOutputPort(&tp, 255); for (i = 0; i < lbrace; i++) { Sg_PutcUnsafe(out, SG_STRING_VALUE_AT(str, i)); } /* skip '{' */ i++; while (i < rbrace) { /* now we need to copy one by one */ int nest = 0, j; SgObject tmp; for (;SG_STRING_VALUE_AT(str, i) != ',' || nest != 0; i++) { if (i >= rbrace) break; if (SG_STRING_VALUE_AT(str, i) == '{') nest++; if (SG_STRING_VALUE_AT(str, i) == '}') nest--; if (SG_STRING_VALUE_AT(str, i) == '\\' && escape) { if (++i == rbrace) break; } Sg_PutcUnsafe(out, SG_STRING_VALUE_AT(str, i)); } /* skip ',' */ i++; /* copy after the '}' */ for (j = rbrace+1; j < SG_STRING_SIZE(str); j++) { Sg_PutcUnsafe(out, SG_STRING_VALUE_AT(str, j)); } tmp = Sg_GetStringFromStringPort(&tp); SG_APPEND(h, t, brace_expand(tmp, flags)); /* back to the starting position */ Sg_SetPortPosition(out, lbrace, SG_BEGIN); } SG_CLEAN_STRING_PORT(&tp); return h; } else { return SG_LIST1(str); } }