libidav/utils.c

changeset 576
62cc92445234
parent 575
f746f601c35c
child 578
bb1e60fada74
--- a/libidav/utils.c	Tue Apr 16 11:46:53 2019 +0200
+++ b/libidav/utils.c	Sat Apr 20 12:31:08 2019 +0200
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2018 Olaf Wintermann. All rights reserved.
+ * Copyright 2019 Olaf Wintermann. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -455,6 +455,68 @@
     return space;
 }
 
+char* util_create_relative_path(const char *abspath, const char *base) {
+    size_t path_len = strlen(abspath);
+    size_t base_len = strlen(base);
+    
+    if(abspath[path_len-1] == '/') {
+        path_len--;
+    }
+    if(base[base_len-1] == '/') {
+        base_len--;
+    }
+    // get base parent
+    for(int i=base_len-1;i>=0;i--) {
+        if(base[i] == '/') {
+            base_len = i+1;
+            break;
+        }
+    }
+    
+    size_t max = path_len > base_len ? base_len : path_len;
+    
+    // get prefix of abspath and base
+    // this dir is the root of the link
+    size_t i;
+    size_t last_dir = 0;
+    for(i=0;i<max;i++) {
+        char c = abspath[i];
+        if(c != base[i]) {
+            break;
+        } else if(c == '/') {
+            last_dir = i;
+        }
+    }
+    
+    char *ret = NULL;
+    UcxBuffer *out = NULL;
+    if(last_dir+1 < base_len) {
+        // base is deeper than the link root, we have to go backwards
+        int dircount = 0;
+        for(int i=last_dir+1;i<base_len;i++) {
+            if(base[i] == '/') {
+                dircount++;
+            }
+        }
+        
+        out = ucx_buffer_new(NULL, dircount*3+path_len-last_dir, UCX_BUFFER_AUTOEXTEND);
+        
+        for(int i=0;i<dircount;i++) {
+            ucx_buffer_puts(out, "../");
+        }
+    } else {
+        out = ucx_buffer_new(NULL, 1024, path_len - last_dir);
+    }
+    
+    ucx_buffer_puts(out, abspath + last_dir + 1);
+    ucx_buffer_putc(out, 0);
+    out->flags = 0;
+    ret = out->space;
+    ucx_buffer_free(out);
+    
+    return ret;
+}
+
 
 void util_capture_header(CURL *handle, UcxMap* map) {
     if(map) {

mercurial