+ return talloc_asprintf(url, "%s://%s%s", scheme->str,
+ scheme->has_host ? url->host : "", url->path);
+}
+
+static void pb_url_update_full(struct pb_url *url)
+{
+ talloc_free(url->full);
+ url->full = pb_url_to_string(url);
+}
+
+static struct pb_url *pb_url_copy(void *ctx, const struct pb_url *url)
+{
+ struct pb_url *new_url;
+
+ new_url = talloc(ctx, struct pb_url);
+ new_url->scheme = url->scheme;
+ new_url->full = talloc_strdup(new_url, url->full);
+
+ new_url->host = url->host ? talloc_strdup(new_url, url->host) : NULL;
+ new_url->port = url->port ? talloc_strdup(new_url, url->port) : NULL;
+ new_url->path = url->path ? talloc_strdup(new_url, url->path) : NULL;
+ new_url->dir = url->dir ? talloc_strdup(new_url, url->dir) : NULL;
+ new_url->file = url->file ? talloc_strdup(new_url, url->file) : NULL;
+
+ return new_url;
+}
+
+struct pb_url *pb_url_join(void *ctx, const struct pb_url *url, const char *s)
+{
+ struct pb_url *new_url;
+
+ /* complete url: just parse all info from s */
+ if (is_url(s))
+ return pb_url_parse(ctx, s);
+
+ new_url = pb_url_copy(ctx, url);
+
+ if (s[0] == '/') {
+ /* absolute path: replace path of new_url */
+ talloc_free(new_url->path);
+ new_url->path = talloc_strdup(new_url, s);
+
+ } else {
+ /* relative path: join s to existing path. We know that
+ * url->dir ends with a slash. */
+ char *tmp = new_url->path;
+ new_url->path = talloc_asprintf(new_url, "%s%s", url->dir, s);
+ talloc_free(tmp);
+ }
+
+ /* replace ->dir and ->file with components from ->path */
+ pb_url_parse_path(new_url);
+
+ /* and re-generate the full URL */
+ pb_url_update_full(new_url);
+
+ return new_url;
+}
+
+const char *pb_url_scheme_name(enum pb_url_scheme scheme)
+{
+ const struct pb_scheme_info *info = pb_url_scheme_info(scheme);
+ return info ? info->str : NULL;