char * single_path_relocation(const char *from, const char *to) { #if defined(__MINGW32__) char exe_path[PATH_MAX]; get_executable_path (NULL, &exe_path[0], sizeof(exe_path)/sizeof(exe_path[0])); if (strrchr (exe_path, '/') != NULL) { strrchr (exe_path, '/')[1] = '\0'; } char * rel_to_datadir = get_relative_path (from, to); strcat (exe_path, rel_to_datadir); simplify_path (&exe_path[0]); return malloc_copy_string(exe_path); #else return malloc_copy_string(to); #endif }
void simplify_path_debug (const char * input, const char * expected) { char * input_copy = malloc_copy_string (input); if ( input_copy == NULL ) { _exit(1); } simplify_path (input_copy); int ok = (strcmp(input_copy, expected) == 0) ? 1 : 0; if (ok) { printf ("PASS: %s simplifies to %s\n", input, input_copy); } else { printf ("FAIL: %s simplifies to %s, should be %s\n", input, input_copy, expected); _exit(1); } free ((void *)input_copy); }
char * get_relative_path(char const * from_in, char const * to_in) { size_t from_size = (from_in == NULL) ? 0 : strlen (from_in); size_t to_size = (to_in == NULL) ? 0 : strlen (to_in); size_t max_size = (from_size + to_size) * 2 + 4; char * scratch_space = (char *) alloca (from_size + 1 + to_size + 1 + max_size + max_size); char * from; char * to; char * common_part; char * result; size_t count; /* No to, return "./" */ if (to_in == NULL) { return malloc_copy_string ("./"); } /* If alloca failed or no from was given return a copy of to */ if ( from_in == NULL || scratch_space == NULL ) { return malloc_copy_string (to_in); } from = scratch_space; strcpy (from, from_in); to = from + from_size + 1; strcpy (to, to_in); common_part = to + to_size + 1; result = common_part + max_size; simplify_path (from); simplify_path (to); result[0] = '\0'; size_t match_size_dirsep = 0; /* The match size up to the last /. Always wind back to this - 1 */ size_t match_size = 0; /* The running (and final) match size. */ size_t largest_size = (from_size > to_size) ? from_size : to_size; int to_final_is_slash = (to[to_size-1] == '/') ? 1 : 0; char from_c; char to_c; for (match_size = 0; match_size < largest_size; ++match_size) { /* To simplify the logic, always pretend the strings end with '/' */ from_c = (match_size < from_size) ? from[match_size] : '/'; to_c = (match_size < to_size) ? to[match_size] : '/'; if (from_c != to_c) { if (from_c != '\0' || to_c != '\0') { match_size = match_size_dirsep; } break; } else if (from_c == '/') { match_size_dirsep = match_size; } } strncpy (common_part, from, match_size); common_part[match_size] = '\0'; from += match_size; to += match_size; size_t ndotdots = 0; char const* from_last = from + strlen(from) - 1; while ((from = strchr (from, '/')) && from != from_last) { ++ndotdots; ++from; } for (count = 0; count < ndotdots; ++count) { strcat(result, "../"); } if (strlen(to) > 0) { strcat(result, to+1); } /* Make sure that if to ends with '/' result does the same, and vice-versa. */ size_t size_result = strlen(result); if ((to_final_is_slash == 1) && (!size_result || result[size_result-1] != '/')) { strcat (result, "/"); } else if (!to_final_is_slash && size_result && result[size_result-1] == '/') { result[size_result-1] = '\0'; } return malloc_copy_string (result); }