static int path_init(PathPathObject *self, PyObject *args, PyObject *kwds) { int w, h; if (!PyArg_ParseTuple(args, "(ii)", &w, &h)) return -1; self->path = pathNew(w,h); if (self->path == NULL) { PyErr_SetString(PyExc_ValueError, "invalid dimensions"); return -1; } return 0; }
void pathNormalize(Path* path) { // Split the path into components. Slice components[MAX_COMPONENTS]; int numComponents = 0; char* start = path->chars; char* end = path->chars; // Split into parts and handle "." and "..". int leadingDoubles = 0; for (;;) { if (*end == '\0' || isSeparator(*end)) { // Add the current component. if (start != end) { size_t length = end - start; if (length == 1 && start[0] == '.') { // Skip "." components. } else if (length == 2 && start[0] == '.' && start[1] == '.') { // Walk out of directories on "..". if (numComponents > 0) { // Discard the previous component. numComponents--; } else { // Can't back out any further, so preserve the "..". leadingDoubles++; } } else { if (numComponents >= MAX_COMPONENTS) { fprintf(stderr, "Path cannot have more than %d path components.\n", MAX_COMPONENTS); exit(1); } components[numComponents].start = start; components[numComponents].end = end; numComponents++; } } // Skip over separators. while (*end != '\0' && isSeparator(*end)) end++; start = end; if (*end == '\0') break; } end++; } // Preserve the path type. We don't want to turn, say, "./foo" into "foo" // because that changes the semantics of how that path is handled when used // as an import string. bool needsSeparator = false; Path* result = pathNew(""); size_t prefixLength = absolutePrefixLength(path->chars); if (prefixLength > 0) { // It's an absolute path, so preserve the absolute prefix. Slice slice; slice.start = path->chars; slice.end = path->chars + prefixLength; appendSlice(result, slice); } else if (leadingDoubles > 0) { // Add any leading "..". for (int i = 0; i < leadingDoubles; i++) { if (needsSeparator) pathAppendChar(result, '/'); pathAppendString(result, ".."); needsSeparator = true; } } else if (path->chars[0] == '.' && isSeparator(path->chars[1])) { // Preserve a leading "./", since we use that to distinguish relative from // logical imports. pathAppendChar(result, '.'); needsSeparator = true; } for (int i = 0; i < numComponents; i++) { if (needsSeparator) pathAppendChar(result, '/'); appendSlice(result, components[i]); needsSeparator = true; } if (result->length == 0) pathAppendChar(result, '.'); // Copy back into the original path. free(path->chars); path->capacity = result->capacity; path->chars = result->chars; path->length = result->length; }