Re: [AD] Relative paths in the grabber |
[ Thread Index |
Date Index
| More lists.liballeg.org/allegro-developers Archives
]
> And I think I found a bug in your algorithm, for example for
>
> path1 = /home/eric/
> path2 = /home/eric/src/test.c
>
> the result will lack the leading './'.
Hmm... I'm being overzealous here, the leading './' is not required so I
withdraw my objection: your algorithm is fine.
Revised path attached.
--
Eric Botcazou
--- /home/eric/cvs/allegro/src/file.c Mon May 5 18:44:04 2003
+++ allegro/src/file.c Fri May 16 10:40:39 2003
@@ -14,6 +14,10 @@
*
* _pack_fdopen() and related modifications by Annie Testes.
*
+ * Evert Glebbeek added the support for relative filenames:
+ * make_absolute_filename(), make_relative_filename() and
+ * is_relative_filename().
+ *
* See readme.txt for copyright information.
*/
@@ -328,6 +332,160 @@
}
+
+/* make_absolute_filename:
+ * Makes the absolute filename corresponding to the specified relative
+ * filename using the specified base (PATH is absolute and represents
+ * the base, FILENAME is the relative filename), stores it in DEST
+ * whose size in bytes is SIZE and returns a pointer to it.
+ * It does not append '/' to the path.
+ */
+char *make_absolute_filename(char *dest, AL_CONST char *path, AL_CONST char *filename, int size)
+{
+ char tmp[1024];
+ ASSERT(dest);
+ ASSERT(path);
+ ASSERT(filename);
+ ASSERT(size >= 0);
+
+ replace_filename(tmp, path, filename, sizeof(tmp));
+
+ fix_filename_path(dest, tmp, size);
+
+ return dest;
+}
+
+
+
+/* make_relative_filename:
+ * Makes the relative filename corresponding to the specified absolute
+ * filename using the specified base (PATH is absolute and represents
+ * the base, FILENAME is the absolute filename), stores it in DEST
+ * whose size in bytes is SIZE and returns a pointer to it, or returns
+ * NULL if it cannot do so.
+ * It does not append '/' to the path.
+ */
+char *make_relative_filename(char *dest, AL_CONST char *path, AL_CONST char *filename, int size)
+{
+ char *my_path, *my_filename;
+ char *reduced_path = NULL, *reduced_filename = NULL;
+ char *p1, *p2;
+ int c, c1, c2, pos;
+ ASSERT(dest);
+ ASSERT(path);
+ ASSERT(filename);
+ ASSERT(size >= 0);
+
+ /* The first check under DOS/Windows would be for the drive: since the
+ * paths are absolute, they will always contain a drive letter. Do this
+ * check under Unix too where the first character should always be '/'
+ * in order not to screw up existing DOS/Windows paths.
+ */
+ if (ugetc(path) != ugetc(filename))
+ return NULL;
+
+ my_path = ustrdup(path);
+ if (!my_path)
+ return NULL;
+
+ my_filename = ustrdup(filename);
+ if (!my_filename) {
+ free(my_path);
+ return NULL;
+ }
+
+ /* Strip the filenames to keep only the directories. */
+ usetc(get_filename(my_path), 0);
+ usetc(get_filename(my_filename), 0);
+
+ /* Both paths are on the same device. There are three cases:
+ * - the filename is a "child" of the path in the directory tree,
+ * - the filename is a "brother" of the path,
+ * - the filename is only a "cousin" of the path.
+ * In the two former cases, we will only need to keep a suffix of the
+ * filename. In the latter case, we will need to back-paddle through
+ * the directory tree.
+ */
+ p1 = my_path;
+ p2 = my_filename;
+ while (((c1=ugetx(&p1)) == (c2=ugetx(&p2))) && c1 && c2) {
+ if ((c1 == '/') || (c1 == OTHER_PATH_SEPARATOR)) {
+ reduced_path = p1;
+ reduced_filename = p2;
+ }
+ }
+
+ if (!c1) {
+ /* If the path is exhausted, we are in one of the two former cases. */
+
+ if (!c2) {
+ /* If the filename is also exhausted, we are in the second case.
+ * Prepend './' to the reduced filename.
+ */
+ pos = usetc(dest, '.');
+ pos += usetc(dest+pos, OTHER_PATH_SEPARATOR);
+ usetc(dest+pos, 0);
+ }
+ else {
+ /* Otherwise we are in the first case. Nothing to do. */
+ usetc(dest, 0);
+ }
+ }
+ else {
+ /* Otherwise, we are in the latter case and need to count the number
+ * of remaining directories in the reduced path and prepend the same
+ * number of '../' to the reduced filename.
+ */
+ pos = 0;
+ while ((c=ugetx(&reduced_path))) {
+ if ((c == '/') || (c == OTHER_PATH_SEPARATOR)) {
+ pos += usetc(dest+pos, '.');
+ pos += usetc(dest+pos, '.');
+ pos += usetc(dest+pos, OTHER_PATH_SEPARATOR);
+ }
+ }
+
+ usetc(dest+pos, 0);
+ }
+
+ ustrzcat(dest, size, reduced_filename);
+ ustrzcat(dest, size, get_filename(filename));
+
+ free(my_path);
+ free(my_filename);
+
+ /* Harmonize path separators. */
+ return fix_filename_slashes(dest);
+}
+
+
+
+/* is_relative_filename:
+ * Checks whether the specified filename is relative.
+ */
+int is_relative_filename(AL_CONST char *filename)
+{
+ ASSERT(filename);
+
+ /* All filenames that start with a '.' are relative. */
+ if (ugetc(filename) == '.')
+ return TRUE;
+
+ /* Filenames that contain a device separator (DOS/Windows)
+ * or start with a '/' (Unix) are considered absolute.
+ */
+#if (defined ALLEGRO_DOS) || (defined ALLEGRO_WINDOWS)
+ if (ustrchr(filename, DEVICE_SEPARATOR))
+ return FALSE;
+#endif
+
+ if ((ugetc(filename) == '/') || (ugetc(filename) == OTHER_PATH_SEPARATOR))
+ return FALSE;
+
+ return TRUE;
+}
+
+
/* replace_filename:
* Replaces filename in path with different one.
--- /home/eric/cvs/allegro/include/allegro/file.h Thu Jan 23 14:13:07 2003
+++ allegro/include/allegro/file.h Mon May 5 21:20:00 2003
@@ -28,6 +28,9 @@
AL_FUNC(char *, fix_filename_case, (char *path));
AL_FUNC(char *, fix_filename_slashes, (char *path));
AL_FUNC(char *, fix_filename_path, (char *dest, AL_CONST char *path, int size));
+AL_FUNC(char *, make_absolute_filename, (char *dest, AL_CONST char *path, AL_CONST char *filename, int size));
+AL_FUNC(char *, make_relative_filename, (char *dest, AL_CONST char *path, AL_CONST char *filename, int size));
+AL_FUNC(int, is_relative_filename, (AL_CONST char *filename));
AL_FUNC(char *, replace_filename, (char *dest, AL_CONST char *path, AL_CONST char *filename, int size));
AL_FUNC(char *, replace_extension, (char *dest, AL_CONST char *filename, AL_CONST char *ext, int size));
AL_FUNC(char *, append_filename, (char *dest, AL_CONST char *path, AL_CONST char *filename, int size));
--- /home/eric/cvs/allegro/docs/src/allegro._tx Thu May 15 23:40:40 2003
+++ allegro/docs/src/allegro._tx Fri May 16 00:51:14 2003
@@ -6320,6 +6320,22 @@
Converts a partial filename into a full path, storing at most size bytes
into the dest buffer. Returns a copy of the dest parameter.
+@@char *@make_absolute_filename(char *dest, const char *path, const char *filename, int size);
+@xref make_relative_filename, is_relative_filename
+ Makes an absolute filename from an absolute path and a relative filename,
+ storing at most size bytes into the dest buffer. Returns a copy of the
+ dest parameter.
+
+@@char *@make_relative_filename(char *dest, const char *path, const char *filename, int size);
+@xref make_absolute_filename, is_relative_filename
+ Attempts to make a relative filename from an absolute path and an absolute
+ filename, storing at most size bytes into the dest buffer. Returns a copy
+ of the dest parameter if it succeeds or NULL if it fails.
+
+@@int @is_relative_filename(const char *filename);
+@xref make_absolute_filename, make_relative_filename
+ Returns TRUE if the filename is relative or FALSE if it is absolute.
+
@\char *@replace_filename(char *dest, const char *path,
@@ const char *filename, int size);
@xref get_filename, replace_extension, append_filename