/* 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 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); } }