source: trunk/third/gnome-vfs/libgnomevfs/gnome-vfs-uri.c @ 15497

Revision 15497, 36.0 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r15496, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2/* gnome-vfs-uri.c - URI handling for the GNOME Virtual File System.
3
4   Copyright (C) 1999 Free Software Foundation
5
6   The Gnome Library is free software; you can redistribute it and/or
7   modify it under the terms of the GNU Library General Public License as
8   published by the Free Software Foundation; either version 2 of the
9   License, or (at your option) any later version.
10
11   The Gnome Library is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   Library General Public License for more details.
15
16   You should have received a copy of the GNU Library General Public
17   License along with the Gnome Library; see the file COPYING.LIB.  If not,
18   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19   Boston, MA 02111-1307, USA.
20
21   Author: Ettore Perazzoli <ettore@gnu.org>
22
23*/
24
25#ifdef HAVE_CONFIG_H
26#include <config.h>
27#endif
28
29#include <ctype.h>
30#include <stdio.h>
31#include <string.h>
32
33#include "gnome-vfs.h"
34#include "gnome-vfs-private.h"
35
36/* FIXME bugzilla.eazel.com 2762: The uri->parent field is always NULL; we should get rid of it. */
37
38/*
39   split_toplevel_uri
40
41   Extract hostname and username from "path" with length "path_len"
42
43   examples:
44       sunsite.unc.edu/pub/linux
45       miguel@sphinx.nuclecu.unam.mx/c/nc
46       tsx-11.mit.edu:8192/
47       joe@foo.edu:11321/private
48       joe:password@foo.se
49
50   This function implements the following regexp: (whitespace for clarity)
51
52   ( ( ([^:@]*) (:[^@]*)? @ )? ([^/:]+) (:([0-9]*)?) )?  (/.*)?
53   ( ( ( user ) (  pw  )?   )?   (host)    (port)?   )? (path <return value>)?
54
55  It returns NULL if neither <host> nor <path> could be matched.
56
57  port is checked to ensure that it does not exceed 0xffff.
58
59  return value is <path> or is "/" if the path portion is not present
60  All other arguments are set to 0 or NULL if their portions are not present
61
62  pedantic: this function ends up doing an unbounded lookahead, making it
63  potentially O(n^2) instead of O(n).  This could be avoided.  Realistically, though,
64  its just the password field.
65
66  Differences between the old and the new implemention:
67
68                     Old                     New
69  localhost:8080     host="localhost:8080"   host="localhost" port=8080
70  /Users/mikef       host=""                 host=NULL
71
72*/
73
74
75#define URI_MOVE_PAST_DELIMITER \
76        do {                                                    \
77                cur_tok_start = (++cur);                        \
78                if (path_end == cur) {                          \
79                        success = FALSE;                        \
80                        goto done;                              \
81                }                                               \
82        } while (0);
83
84
85#define uri_strlen_to(from, to)  ( (to) - (from) )
86#define uri_strdup_to(from, to)  g_strndup ((from), uri_strlen_to((from), (to)))
87
88typedef struct {
89        const char *chrs;
90        gboolean primed;
91        char bv[32];
92} UriStrspnSet;
93
94UriStrspnSet uri_strspn_sets[] = {
95        {":@" GNOME_VFS_URI_PATH_STR, FALSE, ""},
96        {"@", FALSE, ""},
97        {":" GNOME_VFS_URI_PATH_STR, FALSE, ""}
98};
99
100#define URI_DELIMITER_ALL_SET (uri_strspn_sets + 0)
101#define URI_DELIMITER_USER_SET (uri_strspn_sets + 1)
102#define URI_DELIMITER_HOST_SET (uri_strspn_sets + 2)
103
104#define BV_SET(bv, idx) (bv)[((guchar)(idx))>>3] |= (1 << ( (idx) & 7) )
105#define BV_IS_SET(bv, idx) ((bv)[(idx)>>3] & (1 << ( (idx) & 7)))
106
107static const char *
108uri_strspn_to(const char *str, UriStrspnSet *set, const char *path_end)
109{
110        const char *cur;
111        const char *cur_chr;
112
113        if (!set->primed) {
114                memset (set->bv, 0, sizeof(set->bv));
115       
116                for (cur_chr = set->chrs; '\0' != *cur_chr; cur_chr++) {
117                        BV_SET (set->bv, *cur_chr);
118                }
119
120                BV_SET (set->bv, '\0');
121                set->primed = TRUE;
122        }
123       
124        for (cur = str; cur < path_end && ! BV_IS_SET (set->bv, *cur); cur++)
125                ;
126
127        if (cur >= path_end || '\0' == *cur) {
128                return NULL;
129        }
130
131        return cur;
132}
133
134
135static gchar *
136split_toplevel_uri (const gchar *path, guint path_len,
137                    gchar **host_return, gchar **user_return,
138                    guint *port_return, gchar **password_return)
139{
140        const char *path_end;
141        const char *cur_tok_start;
142        const char *cur;
143        char *ret;
144        gboolean success;
145
146        g_assert (host_return != NULL);
147        g_assert (user_return != NULL);
148        g_assert (port_return != NULL);
149        g_assert (password_return != NULL);
150
151        *host_return = NULL;
152        *user_return = NULL;
153        *port_return = 0;
154        *password_return = NULL;
155        ret = NULL;
156
157        success = FALSE;
158
159        if (path == NULL || path_len == 0) {
160                return NULL;
161        }
162       
163
164        path_end = path + path_len;
165
166        cur_tok_start = path;
167        cur = uri_strspn_to (cur_tok_start, URI_DELIMITER_ALL_SET, path_end);
168
169        if (cur != NULL
170                && (*cur == '@'
171                    || uri_strspn_to (cur, URI_DELIMITER_USER_SET, path_end) != NULL)) {
172                /* *cur == ':' or '@' and string contains @ */
173
174                if (uri_strlen_to (cur_tok_start, cur) > 0) {
175                        *user_return = uri_strdup_to (cur_tok_start,cur);
176                }
177
178                if (*cur == ':') {
179                        URI_MOVE_PAST_DELIMITER;
180
181                        cur = uri_strspn_to(cur_tok_start, URI_DELIMITER_USER_SET, path_end);
182
183                        if (cur == NULL || *cur != '@') {
184                                success = FALSE;
185                                goto done;
186                        } else if (uri_strlen_to (cur_tok_start, cur) > 0) {
187                                *password_return = uri_strdup_to (cur_tok_start,cur);
188                        }
189                }
190
191                if (*cur != '/') {
192                        URI_MOVE_PAST_DELIMITER;
193                        cur = uri_strspn_to (cur_tok_start, URI_DELIMITER_HOST_SET, path_end);
194                } else {
195                        cur_tok_start = cur;
196                }
197        }
198
199        if (cur == NULL) {
200                /* [^:/]+$ */
201                if (uri_strlen_to (cur_tok_start, path_end) > 0) {
202                        *host_return = uri_strdup_to (cur_tok_start, path_end);
203                        if (*(path_end - 1) == GNOME_VFS_URI_PATH_CHR) {
204                                ret = g_strdup (GNOME_VFS_URI_PATH_STR);
205                        } else {
206                                ret = g_strdup ("");
207                        }
208                        success = TRUE;
209                } else { /* No host, no path */
210                        success = FALSE;
211                }
212
213                goto done;
214
215        } else if (*cur == ':') {
216                guint port;
217                /* [^:/]*:.* */
218
219                if (uri_strlen_to (cur_tok_start, cur) > 0) {
220                        *host_return = uri_strdup_to (cur_tok_start, cur);
221                } else {
222                        success = FALSE;
223                        goto done;      /*No host but a port?*/
224                }
225
226                URI_MOVE_PAST_DELIMITER;
227
228                port = 0;
229
230                for ( ; cur < path_end && '\0' != *cur && isdigit (*cur); cur++) {
231                        port *= 10;
232                        port += *cur - '0';
233                }
234
235                /* We let :(/.*)$ be treated gracefully */
236                if (*cur != '\0' && *cur != GNOME_VFS_URI_PATH_CHR) {
237                        success = FALSE;
238                        goto done;      /* ...but this would be an error */
239                }
240
241                if (port > 0xffff) {
242                        success = FALSE;
243                        goto done;
244                }
245
246                *port_return = port;
247
248                cur_tok_start = cur;
249               
250        } else /* GNOME_VFS_URI_PATH_CHR == *cur */ {
251                /* ^[^:@/]+/.*$ */
252
253                if (uri_strlen_to (cur_tok_start, cur) > 0) {
254                        *host_return = uri_strdup_to (cur_tok_start, cur);
255                } else if (*user_return != NULL || *password_return != NULL ) {
256                        /* If we got a user / password but no host, that's an error */
257                        success = FALSE;
258                        goto done;     
259                }
260
261                cur_tok_start = cur;
262        }
263
264        if (*cur_tok_start != '\0' && uri_strlen_to (cur_tok_start, path_end) > 0) {
265                ret = uri_strdup_to(cur, path_end);
266        } else if (*host_return != NULL) {
267                ret = g_strdup (GNOME_VFS_URI_PATH_STR);
268        }
269
270        success = TRUE;
271done:
272
273        /* If we didn't complete our mission, discard all the partials */
274        if (!success) {
275                g_free (*host_return);
276                g_free (*user_return);
277                g_free (*password_return);
278                g_free (ret);
279
280                *host_return = NULL;
281                *user_return = NULL;
282                *port_return = 0;
283                *password_return = NULL;
284                ret = NULL;
285        }
286
287        return ret;
288}
289
290
291static void
292set_uri_element (GnomeVFSURI *uri,
293                 const gchar *text,
294                 guint len)
295{
296        char *escaped_text;
297
298        if (text == NULL || len == 0) {
299                uri->text = NULL;
300                return;
301        }
302
303        if (uri->parent == NULL && text[0] == '/' && text[1] == '/') {
304                GnomeVFSToplevelURI *toplevel;
305
306                toplevel = (GnomeVFSToplevelURI *) uri;
307                uri->text = split_toplevel_uri (text + 2, len - 2,
308                                                &toplevel->host_name,
309                                                &toplevel->user_name,
310                                                &toplevel->host_port,
311                                                &toplevel->password);
312        } else {
313                uri->text = g_strndup (text, len);
314        }
315
316        /* FIXME: this should be handled/supported by the specific method.
317         * This is a quick and dirty hack to minimize the amount of changes
318         * right before a milestone release.
319         *
320         * Do some method specific escaping. This for instance converts
321         * '?' to %3F in every method except "http" where it has a special
322         * meaning.
323         */
324        if ( ! (strcmp (uri->method_string, "http") == 0
325                || strcmp (uri->method_string, "eazel-services") == 0 )) {
326
327                escaped_text = gnome_vfs_escape_set (uri->text, ";?&=+$,");
328                g_free (uri->text);
329                uri->text = escaped_text;
330        }
331       
332        gnome_vfs_remove_optional_escapes (uri->text);
333        gnome_vfs_canonicalize_pathname (uri->text);
334}
335
336static const gchar *
337get_method_string (const gchar *substring, gchar **method_string)
338{
339        const gchar *p;
340       
341        for (p = substring;
342             isalnum ((unsigned char)*p) || *p == '+' || *p == '-' || *p == '.';
343             p++)
344                ;
345
346        if (*p == ':') {
347                /* Found toplevel method specification.  */
348                *method_string = g_strndup (substring, p - substring);
349                g_strdown (*method_string);
350                p++;
351        } else {
352                *method_string = g_strdup ("file");
353                p = substring;
354        }
355        return p;
356}
357
358static GnomeVFSURI *
359parse_uri_substring (const gchar *substring, GnomeVFSURI *parent)
360{
361        GnomeVFSMethod *method;
362        GnomeVFSURI *uri, *child_uri;
363        gchar *method_string;
364        const gchar *method_scanner;
365        const gchar *extension_scanner;
366
367        if (substring == NULL || *substring == '\0') {
368                return NULL;
369        }
370       
371        method_scanner = get_method_string (substring, &method_string);
372
373        method = gnome_vfs_method_get (method_string);
374        if (!method) {
375                g_free (method_string);
376                return NULL;
377        }
378
379        uri = g_new0 (GnomeVFSURI, 1);
380        uri->method = method;
381        uri->method_string = method_string;
382        uri->ref_count = 1;
383        uri->parent = parent;
384
385        extension_scanner = strchr (method_scanner, GNOME_VFS_URI_MAGIC_CHR);
386
387        if (extension_scanner == NULL) {
388                set_uri_element (uri, method_scanner, strlen (method_scanner));
389                return uri;
390        }
391
392        /* handle '#' */
393        set_uri_element (uri, method_scanner, extension_scanner - method_scanner);
394
395        if (strchr (extension_scanner, ':') == NULL) {
396                /* extension is a fragment identifier */
397                uri->fragment_id = g_strdup (extension_scanner + 1);
398                return uri;
399        }
400
401        /* extension is a uri chain */
402        child_uri = parse_uri_substring (extension_scanner + 1, uri);
403
404        if (child_uri != NULL) {
405                return child_uri;
406        }
407
408        return uri;
409}
410
411/**
412 * gnome_vfs_uri_new:
413 * @text_uri: A string representing a URI.
414 *
415 * Create a new URI from @text_uri.
416 *
417 * Return value: The new URI.
418 **/
419GnomeVFSURI *
420gnome_vfs_uri_new (const gchar *text_uri)
421{
422        return gnome_vfs_uri_new_private (text_uri, FALSE);
423}
424
425GnomeVFSURI *
426gnome_vfs_uri_new_private (const gchar *text_uri, gboolean allow_unknown_methods)
427{
428        GnomeVFSMethod *method;
429        GnomeVFSTransform *trans;
430        GnomeVFSToplevelURI *toplevel;
431        GnomeVFSURI *uri, *child_uri;
432        const gchar *method_scanner, *extension_scanner;
433        gchar *method_string;
434        gchar *new_uri_string = NULL;
435
436        g_return_val_if_fail (text_uri != NULL, NULL);
437
438        if (text_uri[0] == '\0') {
439                return NULL;
440        }
441
442        toplevel = g_new (GnomeVFSToplevelURI, 1);
443        toplevel->host_name = NULL;
444        toplevel->host_port = 0;
445        toplevel->user_name = NULL;
446        toplevel->password = NULL;
447
448        uri = (GnomeVFSURI *) toplevel;
449        uri->parent = NULL;
450
451        method_scanner = get_method_string (text_uri, &method_string);
452        trans = gnome_vfs_transform_get (method_string);
453        if (trans != NULL && trans->transform) {
454                GnomeVFSContext *context;
455
456                context = gnome_vfs_context_new ();
457                (* trans->transform) (trans, method_scanner, &new_uri_string, context);
458                gnome_vfs_context_unref (context);
459                if (new_uri_string != NULL) {
460                        toplevel->urn = g_strdup (text_uri);
461                        g_free (method_string);
462                        method_scanner = get_method_string (new_uri_string, &method_string);
463                }
464        }
465       
466        method = gnome_vfs_method_get (method_string);
467        /* The toplevel URI element is special, as it also contains host/user
468           information.  */
469        uri->method = method;
470        uri->ref_count = 1;
471        uri->method_string = method_string;
472        uri->text = NULL;
473        uri->fragment_id = NULL;
474        if (method == NULL && !allow_unknown_methods) {
475                g_free (new_uri_string);
476                gnome_vfs_uri_unref (uri);
477                return NULL;
478        }
479
480        extension_scanner = strchr (method_scanner, GNOME_VFS_URI_MAGIC_CHR);
481        if (extension_scanner == NULL) {
482                set_uri_element (uri, method_scanner, strlen (method_scanner));
483                g_free (new_uri_string);
484                return uri;
485        }
486
487        /* handle '#' */
488        set_uri_element (uri, method_scanner, extension_scanner - method_scanner);
489
490        if (strchr (extension_scanner, ':') == NULL) {
491                /* extension is a fragment identifier */
492                uri->fragment_id = g_strdup (extension_scanner + 1);
493                g_free (new_uri_string);
494                return uri;
495        }
496
497        /* extension is a uri chain */
498        child_uri = parse_uri_substring (extension_scanner + 1, uri);
499
500        g_free (new_uri_string);
501
502        if (child_uri != NULL) {
503                return child_uri;
504        }
505       
506        return uri;
507}
508
509/* Destroy an URI element, but not its parent.  */
510static void
511destroy_element (GnomeVFSURI *uri)
512{
513        g_free (uri->text);
514        g_free (uri->fragment_id);
515        g_free (uri->method_string);
516
517        if (uri->parent == NULL) {
518                GnomeVFSToplevelURI *toplevel;
519
520                toplevel = (GnomeVFSToplevelURI *) uri;
521                g_free (toplevel->host_name);
522                g_free (toplevel->user_name);
523                g_free (toplevel->password);
524        }
525
526        g_free (uri);
527}
528
529/**
530 * gnome_vfs_uri_ref:
531 * @uri: A GnomeVFSURI.
532 *
533 * Increment @uri's reference count.
534 *
535 * Return value: @uri.
536 **/
537GnomeVFSURI *
538gnome_vfs_uri_ref (GnomeVFSURI *uri)
539{
540        GnomeVFSURI *p;
541
542        g_return_val_if_fail (uri != NULL, NULL);
543
544        for (p = uri; p != NULL; p = p->parent)
545                p->ref_count++;
546
547        return uri;
548}
549
550/**
551 * gnome_vfs_uri_unref:
552 * @uri: A GnomeVFSURI.
553 *
554 * Decrement @uri's reference count.  If the reference count reaches zero,
555 * @uri is destroyed.
556 **/
557void
558gnome_vfs_uri_unref (GnomeVFSURI *uri)
559{
560        GnomeVFSURI *p, *parent;
561
562        g_return_if_fail (uri != NULL);
563        g_return_if_fail (uri->ref_count > 0);
564
565        for (p = uri; p != NULL; p = parent) {
566                parent = p->parent;
567                g_assert (p->ref_count > 0);
568                p->ref_count--;
569                if (p->ref_count == 0)
570                        destroy_element (p);
571        }
572}
573
574/**
575 * gnome_vfs_uri_dup:
576 * @uri: A GnomeVFSURI.
577 *
578 * Duplicate @uri.
579 *
580 * Return value: A pointer to a new URI that is exactly the same as @uri.
581 **/
582GnomeVFSURI *
583gnome_vfs_uri_dup (const GnomeVFSURI *uri)
584{
585        const GnomeVFSURI *p;
586        GnomeVFSURI *new_uri, *child;
587
588        if (uri == NULL) {
589                return NULL;
590        }
591
592        new_uri = NULL;
593        child = NULL;
594        for (p = uri; p != NULL; p = p->parent) {
595                GnomeVFSURI *new_element;
596
597                if (p->parent == NULL) {
598                        GnomeVFSToplevelURI *toplevel;
599                        GnomeVFSToplevelURI *new_toplevel;
600
601                        toplevel = (GnomeVFSToplevelURI *) p;
602                        new_toplevel = g_new (GnomeVFSToplevelURI, 1);
603
604                        new_toplevel->host_name = g_strdup (toplevel->host_name);
605                        new_toplevel->host_port = toplevel->host_port;
606                        new_toplevel->user_name = g_strdup (toplevel->user_name);
607                        new_toplevel->password = g_strdup (toplevel->password);
608
609                        new_element = (GnomeVFSURI *) new_toplevel;
610                } else {
611                        new_element = g_new (GnomeVFSURI, 1);
612                }
613
614                new_element->ref_count = 1;
615                new_element->text = g_strdup (p->text);
616                new_element->fragment_id = g_strdup (p->fragment_id);
617                new_element->method_string = g_strdup (p->method_string);
618                new_element->method = p->method;
619                new_element->parent = NULL;
620
621                if (child != NULL) {
622                        child->parent = new_element;
623                } else {
624                        new_uri = new_element;
625                }
626                       
627                child = new_element;
628        }
629
630        return new_uri;
631}
632
633/**
634 * gnome_vfs_uri_append_string:
635 * @uri: A GnomeVFSURI.
636 * @uri_fragment_string: A piece of a URI (ie a fully escaped partial path)
637 *
638 * Create a new URI obtained by appending @path to @uri.  This will take care
639 * of adding an appropriate directory separator between the end of @uri and
640 * the start of @path if necessary.
641 *
642 * Return value: The new URI obtained by combining @uri and @path.
643 **/
644GnomeVFSURI *
645gnome_vfs_uri_append_string (const GnomeVFSURI *uri,
646                             const gchar *uri_part_string)
647{
648        gchar *uri_string;
649        GnomeVFSURI *new_uri;
650        gchar *new_string;
651        guint len;
652
653        g_return_val_if_fail (uri != NULL, NULL);
654        g_return_val_if_fail (uri_part_string != NULL, NULL);
655
656        uri_string = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE);
657        len = strlen (uri_string);
658        if (len == 0) {
659                g_free (uri_string);
660                return gnome_vfs_uri_new (uri_part_string);
661        }
662
663        len--;
664        while (uri_string[len] == GNOME_VFS_URI_PATH_CHR && len > 0) {
665                len--;
666        }
667
668        uri_string[len + 1] = '\0';
669
670        while (*uri_part_string == GNOME_VFS_URI_PATH_CHR) {
671                uri_part_string++;
672        }
673
674        if (uri_part_string[0] != GNOME_VFS_URI_MAGIC_CHR) {
675                new_string = g_strconcat (uri_string, GNOME_VFS_URI_PATH_STR, uri_part_string, NULL);
676        } else {
677                new_string = g_strconcat (uri_string, uri_part_string, NULL);
678        }
679        new_uri = gnome_vfs_uri_new (new_string);
680
681        g_free (new_string);
682        g_free (uri_string);
683
684        return new_uri;
685}
686
687/**
688 * gnome_vfs_uri_append_path:
689 * @uri: A GnomeVFSURI.
690 * @path: A non-escaped file path
691 *
692 * Create a new URI obtained by appending @path to @uri.  This will take care
693 * of adding an appropriate directory separator between the end of @uri and
694 * the start of @path if necessary as well as escaping @path as necessary.
695 *
696 * Return value: The new URI obtained by combining @uri and @path.
697 **/
698GnomeVFSURI *
699gnome_vfs_uri_append_path (const GnomeVFSURI *uri,
700                           const gchar *path)
701{
702        gchar *escaped_string;
703        GnomeVFSURI *new_uri;
704       
705        escaped_string = gnome_vfs_escape_path_string (path);
706        new_uri = gnome_vfs_uri_append_string (uri, escaped_string);
707        g_free (escaped_string);
708        return new_uri;
709}
710
711/**
712 * gnome_vfs_uri_append_file_name:
713 * @uri: A GnomeVFSURI.
714 * @path: any "regular" file name (can include #, /, etc)
715 *
716 * Create a new URI obtained by appending @file_name to @uri.  This will take care
717 * of adding an appropriate directory separator between the end of @uri and
718 * the start of @file_name if necessary.
719 *
720 * Return value: The new URI obtained by combining @uri and @path.
721 **/
722GnomeVFSURI *
723gnome_vfs_uri_append_file_name (const GnomeVFSURI *uri,
724                                const gchar *file_name)
725{
726        gchar *escaped_string;
727        GnomeVFSURI *new_uri;
728       
729        escaped_string = gnome_vfs_escape_string (file_name);
730        new_uri = gnome_vfs_uri_append_string (uri, escaped_string);
731        g_free (escaped_string);
732        return new_uri;
733}
734
735
736/**
737 * gnome_vfs_uri_to_string:
738 * @uri: A GnomeVFSURI.
739 * @hide_options: Bitmask specifying what URI elements (e.g. password,
740 * user name etc.) should not be represented in the returned string.
741 *
742 * Translate @uri into a printable string.  The string will not contain the
743 * URI elements specified by @hide_options.
744 *
745 * Return value: A malloced printable string representing @uri.
746 **/
747gchar *
748gnome_vfs_uri_to_string (const GnomeVFSURI *uri,
749                         GnomeVFSURIHideOptions hide_options)
750{
751        GString *string;
752        gchar *result;
753
754        string = g_string_new(uri->method_string);
755        g_string_append_c (string, ':');
756
757        if (uri->parent == NULL) {
758                GnomeVFSToplevelURI *top_level_uri = (GnomeVFSToplevelURI *)uri;
759                gboolean shown_user_pass = FALSE;
760
761                if (top_level_uri->user_name != NULL
762                        || top_level_uri->host_name != NULL
763                        || (uri->text != NULL && uri->text[0] == GNOME_VFS_URI_PATH_CHR)) {
764                        /* don't append '//' for uris such as pipe:foo */
765                        g_string_append (string, "//");
766                }
767
768                if ((hide_options & GNOME_VFS_URI_HIDE_TOPLEVEL_METHOD) != 0) {
769                        g_string_free (string, TRUE); /* throw away method */
770                        string = g_string_new ("");
771                }
772
773                if (top_level_uri->user_name != NULL
774                        && (hide_options & GNOME_VFS_URI_HIDE_USER_NAME) == 0) {
775                        g_string_append (string, top_level_uri->user_name);
776                        shown_user_pass = TRUE;
777                }
778
779                if (top_level_uri->password != NULL
780                        && (hide_options & GNOME_VFS_URI_HIDE_PASSWORD) == 0) {
781                        g_string_append_c (string, ':');
782                        g_string_append (string, top_level_uri->password);
783                        shown_user_pass = TRUE;
784                }
785
786                if (shown_user_pass) {
787                        g_string_append_c (string, '@');
788                }
789
790                if (top_level_uri->host_name != NULL
791                        && (hide_options & GNOME_VFS_URI_HIDE_HOST_NAME) == 0) {
792                        g_string_append (string, top_level_uri->host_name);
793                }
794               
795                if (top_level_uri->host_port > 0
796                        && (hide_options & GNOME_VFS_URI_HIDE_HOST_PORT) == 0) {
797                        gchar tmp[128];
798                        sprintf (tmp, ":%d", top_level_uri->host_port);
799                        g_string_append (string, tmp);
800                }
801
802        }
803       
804        if (uri->text != NULL) {
805                g_string_append (string, uri->text);
806        }
807
808        if (uri->fragment_id != NULL
809                && (hide_options & GNOME_VFS_URI_HIDE_FRAGMENT_IDENTIFIER) == 0) {
810                g_string_append_c (string, '#');
811                g_string_append (string, uri->fragment_id);
812        }
813
814        if (uri->parent != NULL) {
815                g_string_prepend_c (string, '#');
816                g_string_prepend (string, gnome_vfs_uri_to_string (uri->parent,
817                                                                   hide_options));
818        }
819
820        result = string->str;
821        g_string_free (string, FALSE);
822
823        return result;
824}
825
826/**
827 * gnome_vfs_uri_is_local:
828 * @uri: A GnomeVFSURI.
829 *
830 * Check if @uri is a local (native) file system.
831 *
832 * Return value: %FALSE if @uri is not a local file system, %TRUE otherwise.
833 **/
834gboolean
835gnome_vfs_uri_is_local (const GnomeVFSURI *uri)
836{
837        g_return_val_if_fail (uri != NULL, FALSE);
838
839        /* It's illegal to have is_local be NULL in a method.
840         * That's why we fail here. If we decide that it's legal,
841         * then we can change this into an if statement.
842         */
843        g_return_val_if_fail (uri->method->is_local != NULL, FALSE);
844
845        return uri->method->is_local (uri->method, uri);
846}
847
848/**
849 * gnome_vfs_uri_has_parent:
850 * @uri: A GnomeVFSURI.
851 *
852 * Check if URI has a parent or not.
853 *
854 * Return value: %TRUE if @uri has a parent, %FALSE otherwise.
855 **/
856gboolean
857gnome_vfs_uri_has_parent (const GnomeVFSURI *uri)
858{
859        GnomeVFSURI *parent;
860
861        parent = gnome_vfs_uri_get_parent (uri);
862        if (parent == NULL) {
863                return FALSE;
864        }
865
866        gnome_vfs_uri_unref (parent);
867        return TRUE;
868}
869
870/**
871 * gnome_vfs_uri_get_parent:
872 * @uri: A GnomeVFSURI.
873 *
874 * Retrieve @uri's parent URI.
875 *
876 * Return value: A pointer to @uri's parent URI.
877 **/
878GnomeVFSURI *
879gnome_vfs_uri_get_parent (const GnomeVFSURI *uri)
880{
881        g_return_val_if_fail (uri != NULL, NULL);
882
883        if (uri->text != NULL && strchr (uri->text, GNOME_VFS_URI_PATH_CHR) != NULL) {
884                gchar *p;
885                guint len;
886
887                len = strlen (uri->text);
888                p = uri->text + len - 1;
889
890                /* Skip trailing slashes  */
891                while (p != uri->text && *p == GNOME_VFS_URI_PATH_CHR)
892                        p--;
893
894                /* Search backwards to the next slash.  */
895                while (p != uri->text && *p != GNOME_VFS_URI_PATH_CHR)
896                        p--;
897
898                /* Get the parent without slashes  */
899                while (p > uri->text + 1 && p[-1] == GNOME_VFS_URI_PATH_CHR)
900                        p--;
901
902                if (p[1] != '\0') {
903                        GnomeVFSURI *new_uri;
904                        char *new_uri_text;
905                        int length;
906
907                        /* build a new parent text */
908                        length = p - uri->text;                 
909                        if (length == 0) {
910                                new_uri_text = g_strdup (GNOME_VFS_URI_PATH_STR);
911                        } else {
912                                new_uri_text = g_malloc (length + 1);
913                                memcpy (new_uri_text, uri->text, length);
914                                new_uri_text[length] = '\0';
915                        }
916
917                        /* copy the uri and replace the uri text with the new parent text */
918                        new_uri = gnome_vfs_uri_dup (uri);
919                        g_free (new_uri->text);
920                        new_uri->text = new_uri_text;
921                       
922                        return new_uri;
923                }
924        }
925
926        return gnome_vfs_uri_dup (uri->parent);
927}
928
929/**
930 * gnome_vfs_uri_get_toplevel:
931 * @uri: A GnomeVFSURI.
932 *
933 * Retrieve the toplevel URI in @uri.
934 *
935 * Return value: A pointer to the toplevel URI object.
936 **/
937GnomeVFSToplevelURI *
938gnome_vfs_uri_get_toplevel (const GnomeVFSURI *uri)
939{
940        const GnomeVFSURI *p;
941
942        g_return_val_if_fail (uri != NULL, NULL);
943
944        for (p = uri; p->parent != NULL; p = p->parent)
945                ;
946
947        return (GnomeVFSToplevelURI *) p;
948}
949
950/**
951 * gnome_vfs_uri_get_host_name:
952 * @uri: A GnomeVFSURI.
953 *
954 * Retrieve the host name for @uri.
955 *
956 * Return value: A string representing the host name.
957 **/
958const gchar *
959gnome_vfs_uri_get_host_name (const GnomeVFSURI *uri)
960{
961        GnomeVFSToplevelURI *toplevel;
962
963        g_return_val_if_fail (uri != NULL, NULL);
964
965        toplevel = gnome_vfs_uri_get_toplevel (uri);
966        return toplevel->host_name;
967}
968
969/**
970 * gnome_vfs_uri_get_scheme:
971 * @uri: A GnomeVFSURI
972 *
973 * Retrieve the scheme used for @uri
974 *
975 * Return value: A string representing the scheme
976 **/
977const gchar *
978gnome_vfs_uri_get_scheme (const GnomeVFSURI *uri)
979{
980        return uri->method_string;
981}
982
983/**
984 * gnome_vfs_uri_get_host_port:
985 * @uri: A GnomeVFSURI.
986 *
987 * Retrieve the host port number in @uri.
988 *
989 * Return value: The host port number used by @uri.  If the value is zero, the
990 * default port value for the specified toplevel access method is used.
991 **/
992guint
993gnome_vfs_uri_get_host_port (const GnomeVFSURI *uri)
994{
995        GnomeVFSToplevelURI *toplevel;
996
997        g_return_val_if_fail (uri != NULL, 0);
998
999        toplevel = gnome_vfs_uri_get_toplevel (uri);
1000        return toplevel->host_port;
1001}
1002
1003/**
1004 * gnome_vfs_uri_get_user_name:
1005 * @uri: A GnomeVFSURI.
1006 *
1007 * Retrieve the user name in @uri.
1008 *
1009 * Return value: A string representing the user name in @uri.
1010 **/
1011const gchar *
1012gnome_vfs_uri_get_user_name (const GnomeVFSURI *uri)
1013{
1014        GnomeVFSToplevelURI *toplevel;
1015
1016        g_return_val_if_fail (uri != NULL, NULL);
1017
1018        toplevel = gnome_vfs_uri_get_toplevel (uri);
1019        return toplevel->user_name;
1020}
1021
1022/**
1023 * gnome_vfs_uri_get_password:
1024 * @uri: A GnomeVFSURI.
1025 *
1026 * Retrieve the password for @uri.
1027 *
1028 * Return value: The password for @uri.
1029 **/
1030const gchar *
1031gnome_vfs_uri_get_password (const GnomeVFSURI *uri)
1032{
1033        GnomeVFSToplevelURI *toplevel;
1034
1035        g_return_val_if_fail (uri != NULL, NULL);
1036
1037        toplevel = gnome_vfs_uri_get_toplevel (uri);
1038        return toplevel->password;
1039}
1040
1041/**
1042 * gnome_vfs_uri_set_host_name:
1043 * @uri: A GnomeVFSURI.
1044 * @host_name: A string representing a host name.
1045 *
1046 * Set @host_name as the host name accessed by @uri.
1047 **/
1048void
1049gnome_vfs_uri_set_host_name (GnomeVFSURI *uri,
1050                             const gchar *host_name)
1051{
1052        GnomeVFSToplevelURI *toplevel;
1053
1054        g_return_if_fail (uri != NULL);
1055
1056        toplevel = gnome_vfs_uri_get_toplevel (uri);
1057
1058        if (toplevel->host_name != NULL)
1059                g_free (toplevel->host_name);
1060        toplevel->host_name = g_strdup (host_name);
1061}
1062
1063/**
1064 * gnome_vfs_uri_set_host_port:
1065 * @uri: A GnomeVFSURI.
1066 * @host_port: A TCP/IP port number.
1067 *
1068 * Set the host port number in @uri.  If @host_port is zero, the default port
1069 * for @uri's toplevel access method is used.
1070 **/
1071void
1072gnome_vfs_uri_set_host_port (GnomeVFSURI *uri,
1073                             guint host_port)
1074{
1075        GnomeVFSToplevelURI *toplevel;
1076
1077        g_return_if_fail (uri != NULL);
1078
1079        toplevel = gnome_vfs_uri_get_toplevel (uri);
1080
1081        toplevel->host_port = host_port;
1082}
1083
1084/**
1085 * gnome_vfs_uri_set_user_name:
1086 * @uri: A GnomeVFSURI.
1087 * @user_name: A string representing a user name on the host accessed by @uri.
1088 *
1089 * Set @user_name as the user name for @uri.
1090 **/
1091void
1092gnome_vfs_uri_set_user_name (GnomeVFSURI *uri,
1093                             const gchar *user_name)
1094{
1095        GnomeVFSToplevelURI *toplevel;
1096
1097        g_return_if_fail (uri != NULL);
1098
1099        toplevel = gnome_vfs_uri_get_toplevel (uri);
1100
1101        if (toplevel->user_name != NULL)
1102                g_free (toplevel->user_name);
1103        toplevel->host_name = g_strdup (user_name);
1104}
1105
1106/**
1107 * gnome_vfs_uri_set_password:
1108 * @uri: A GnomeVFSURI.
1109 * @password: A password string.
1110 *
1111 * Set @password as the password for @uri.
1112 **/
1113void
1114gnome_vfs_uri_set_password (GnomeVFSURI *uri,
1115                            const gchar *password)
1116{
1117        GnomeVFSToplevelURI *toplevel;
1118
1119        g_return_if_fail (uri != NULL);
1120
1121        toplevel = gnome_vfs_uri_get_toplevel (uri);
1122
1123        if (toplevel->password != NULL)
1124                g_free (toplevel->password);
1125        toplevel->host_name = g_strdup (password);
1126}
1127
1128static gboolean
1129string_match (const gchar *a, const gchar *b)
1130{
1131        if (a == NULL || *a == '\0') {
1132                return b == NULL || *b == '\0';
1133        }
1134
1135        if (a == NULL || b == NULL)
1136                return FALSE;
1137
1138        return strcmp (a, b) == 0;
1139}
1140
1141static gboolean
1142compare_elements (const GnomeVFSURI *a,
1143                  const GnomeVFSURI *b)
1144{
1145        if (!string_match (a->text, b->text)
1146                || !string_match (a->method_string, b->method_string))
1147                return FALSE;
1148
1149        /* The following should never fail, but we make sure anyway. */
1150        return a->method == b->method;
1151}
1152
1153/**
1154 * gnome_vfs_uri_equal:
1155 * @a: A GnomeVFSURI.
1156 * @b: A GnomeVFSURI.
1157 *
1158 * Compare @a and @b.
1159 *
1160 * Return value: %TRUE if @a and @b are equal, %FALSE otherwise.
1161 *
1162 * FIXME: This comparison should take into account the possiblity
1163 * that unreserved characters may be escaped.
1164 * ...or perhaps gnome_vfs_uri_new should unescape unreserved characters?
1165 **/
1166gboolean
1167gnome_vfs_uri_equal (const GnomeVFSURI *a,
1168                     const GnomeVFSURI *b)
1169{
1170        const GnomeVFSToplevelURI *toplevel_a;
1171        const GnomeVFSToplevelURI *toplevel_b;
1172
1173        g_return_val_if_fail (a != NULL, FALSE);
1174        g_return_val_if_fail (b != NULL, FALSE);
1175
1176        /* First check non-toplevel elements.  */
1177        while (a->parent != NULL && b->parent != NULL) {
1178                if (!compare_elements (a, b)) {
1179                        return FALSE;
1180                }
1181        }
1182
1183        /* Now we should be at toplevel for both.  */
1184        if (a->parent != NULL || b->parent != NULL) {
1185                return FALSE;
1186        }
1187
1188        if (!compare_elements (a, b)) {
1189                return FALSE;
1190        }
1191
1192        toplevel_a = (GnomeVFSToplevelURI *) a;
1193        toplevel_b = (GnomeVFSToplevelURI *) b;
1194
1195        /* Finally, compare the extra toplevel members.  */
1196        return toplevel_a->host_port == toplevel_b->host_port
1197            && string_match (toplevel_a->host_name, toplevel_b->host_name)
1198            && string_match (toplevel_a->user_name, toplevel_b->user_name)
1199            && string_match (toplevel_a->password, toplevel_b->password);
1200}
1201
1202/**
1203 * gnome_vfs_uri_is_parent:
1204 * @possible_parent: A GnomeVFSURI.
1205 * @possible_child: A GnomeVFSURI.
1206 * @recursive: a flag to turn recursive check on.
1207 *
1208 * Check if @possible_child is contained by @possible_parent.
1209 * If @recursive is FALSE, just try the immediate parent directory, else
1210 * search up through the hierarchy.
1211 *
1212 * Return value: %TRUE if @possible_child is contained in  @possible_child.
1213 **/
1214gboolean
1215gnome_vfs_uri_is_parent (const GnomeVFSURI *possible_parent,
1216                         const GnomeVFSURI *possible_child,
1217                         gboolean recursive)
1218{
1219        gboolean result;
1220        GnomeVFSURI *item_parent_uri;
1221        GnomeVFSURI *item;
1222
1223        if (!recursive) {
1224                item_parent_uri = gnome_vfs_uri_get_parent (possible_child);
1225
1226                if (item_parent_uri == NULL) {
1227                        return FALSE;
1228                }
1229
1230                result = gnome_vfs_uri_equal (item_parent_uri, possible_parent);       
1231                gnome_vfs_uri_unref (item_parent_uri);
1232
1233                return result;
1234        }
1235       
1236        item = gnome_vfs_uri_dup (possible_child);
1237        for (;;) {
1238                item_parent_uri = gnome_vfs_uri_get_parent (item);
1239                gnome_vfs_uri_unref (item);
1240               
1241                if (item_parent_uri == NULL) {
1242                        return FALSE;
1243                }
1244
1245                result = gnome_vfs_uri_equal (item_parent_uri, possible_parent);
1246       
1247                if (result) {
1248                        gnome_vfs_uri_unref (item_parent_uri);
1249                        break;
1250                }
1251
1252                item = item_parent_uri;
1253        }
1254
1255        return result;
1256}
1257
1258/**
1259 * gnome_vfs_uri_get_path:
1260 * @uri: A GnomeVFSURI
1261 *
1262 * Retrieve full path name for @uri.
1263 *
1264 * Return value: A pointer to the full path name in @uri.  Notice that the
1265 * pointer points to the name store in @uri, so the name returned must not
1266 * be modified nor freed.
1267 **/
1268const gchar *
1269gnome_vfs_uri_get_path (const GnomeVFSURI *uri)
1270{
1271        /* FIXME bugzilla.eazel.com 1472 */
1272        /* this is based on the assumtion that uri->text won't contain the
1273         * query string.
1274         */
1275        g_return_val_if_fail (uri != NULL, NULL);
1276
1277        return uri->text;
1278}
1279
1280/**
1281 * gnome_vfs_uri_get_fragment_id:
1282 * @uri: A GnomeVFSURI
1283 *
1284 * Retrieve the optional fragment identifier for @uri.
1285 *
1286 * Return value: A pointer to the fragment identifier for the uri or NULL.
1287 **/
1288const gchar *
1289gnome_vfs_uri_get_fragment_identifier (const GnomeVFSURI *uri)
1290{
1291        g_return_val_if_fail (uri != NULL, NULL);
1292
1293        return uri->fragment_id;
1294}
1295
1296/**
1297 * gnome_vfs_uri_get_basename:
1298 * @uri: A GnomeVFSURI
1299 *
1300 * Retrieve base file name for @uri.
1301 *
1302 * Return value: A pointer to the base file name in @uri.  Notice that the
1303 * pointer points to the name store in @uri, so the name returned must not
1304 * be modified nor freed.
1305 **/
1306const gchar *
1307gnome_vfs_uri_get_basename (const GnomeVFSURI *uri)
1308{
1309        /* FIXME bugzilla.eazel.com 1472: query parts of URIs aren't handled */
1310        gchar *p;
1311
1312        g_return_val_if_fail (uri != NULL, NULL);
1313
1314        if (uri->text == NULL) {
1315                return NULL;
1316        }
1317
1318        p = strrchr (uri->text, GNOME_VFS_URI_PATH_CHR);
1319        if (p == NULL) {
1320                return NULL;
1321        }
1322
1323        p++;
1324        if (*p == '\0') {
1325                return NULL;
1326        }
1327
1328        return p;
1329}
1330
1331/**
1332 * gnome_vfs_uri_extract_dirname:
1333 * @uri: A GnomeVFSURI
1334 *
1335 * Extract the name of the directory in which the file pointed to by @uri is
1336 * stored as a newly allocated string.  The string will end with a
1337 * GNOME_VFS_URI_PATH_CHR.
1338 *
1339 * Return value: A pointer to the newly allocated string representing the
1340 * parent directory.
1341 **/
1342gchar *
1343gnome_vfs_uri_extract_dirname (const GnomeVFSURI *uri)
1344{
1345        const gchar *base;
1346
1347        g_return_val_if_fail (uri != NULL, NULL);
1348
1349        base = gnome_vfs_uri_get_basename (uri);
1350        if (base == NULL || base == uri->text) {
1351                return g_strdup (GNOME_VFS_URI_PATH_STR);
1352        }
1353
1354        return g_strndup (uri->text, base - uri->text);
1355}
1356
1357/**
1358 * gnome_vfs_uri_extract_short_name:
1359 * @uri: A GnomeVFSURI
1360 *
1361 * Retrieve base file name for @uri, ignoring any trailing path separators.
1362 * This matches the XPG definition of basename, but not g_basename. This is
1363 * often useful when you want the name of something that's pointed to by a
1364 * uri, and don't care whether the uri has a directory or file form.
1365 * If @uri points to the root of a domain, returns the host name. If there's
1366 * no host name, returns GNOME_VFS_URI_PATH_STR.
1367 *
1368 * See also: gnome_vfs_uri_extract_short_path_name.
1369 *
1370 * Return value: A pointer to the newly allocated string representing the
1371 * unescaped short form of the name.
1372 **/
1373gchar *
1374gnome_vfs_uri_extract_short_name (const GnomeVFSURI *uri)
1375{
1376        gchar *escaped_short_path_name, *short_path_name;
1377        const gchar *host_name;
1378
1379        escaped_short_path_name = gnome_vfs_uri_extract_short_path_name (uri);
1380        short_path_name = gnome_vfs_unescape_string (escaped_short_path_name, "/");
1381        g_free (escaped_short_path_name);
1382
1383        host_name = NULL;
1384        if (short_path_name != NULL
1385                && strcmp (short_path_name, GNOME_VFS_URI_PATH_STR) == 0) {
1386                host_name = gnome_vfs_uri_get_host_name (uri);
1387        }
1388
1389        if (host_name == NULL || strlen (host_name) == 0) {
1390                return short_path_name;
1391        }
1392
1393        g_free (short_path_name);
1394        return g_strdup (host_name);
1395}
1396
1397/**
1398 * gnome_vfs_uri_extract_short_path_name:
1399 * @uri: A GnomeVFSURI
1400 *
1401 * Retrieve base file name for @uri, ignoring any trailing path separators.
1402 * This matches the XPG definition of basename, but not g_basename. This is
1403 * often useful when you want the name of something that's pointed to by a
1404 * uri, and don't care whether the uri has a directory or file form.
1405 * If @uri points to the root (including the root of any domain),
1406 * returns GNOME_VFS_URI_PATH_STR.
1407 *
1408 * See also: gnome_vfs_uri_extract_short_name.
1409 *
1410 * Return value: A pointer to the newly allocated string representing the
1411 * escaped short form of the name.
1412 **/
1413gchar *
1414gnome_vfs_uri_extract_short_path_name (const GnomeVFSURI *uri)
1415{
1416        const gchar *p, *short_name_start, *short_name_end;
1417
1418        g_return_val_if_fail (uri != NULL, NULL);
1419
1420        if (uri->text == NULL) {
1421                return NULL;
1422        }
1423
1424        /* Search for the last run of non-'/' characters. */
1425        p = uri->text;
1426        short_name_start = NULL;
1427        short_name_end = p;
1428        do {
1429                if (*p == '\0' || *p == GNOME_VFS_URI_PATH_CHR) {
1430                        /* While we are in a run of non-separators, short_name_end is NULL. */
1431                        if (short_name_end == NULL)
1432                                short_name_end = p;
1433                } else {
1434                        /* While we are in a run of separators, short_name_end is not NULL. */
1435                        if (short_name_end != NULL) {
1436                                short_name_start = p;
1437                                short_name_end = NULL;
1438                        }
1439                }
1440        } while (*p++ != '\0');
1441        g_assert (short_name_end != NULL);
1442       
1443        /* If we never found a short name, that means that the string is all
1444           directory separators. Since it can't be an empty string, that means
1445           it points to the root, so "/" is a good result.
1446        */
1447        if (short_name_start == NULL) {
1448                return g_strdup (GNOME_VFS_URI_PATH_STR);
1449        }
1450
1451        /* Return a copy of the short name. */
1452        return g_strndup (short_name_start, short_name_end - short_name_start);
1453}
1454
1455/* The following functions are useful for creating URI hash tables.  */
1456
1457gint
1458gnome_vfs_uri_hequal (gconstpointer a,
1459                      gconstpointer b)
1460{
1461        return gnome_vfs_uri_equal (a, b);
1462}
1463
1464guint
1465gnome_vfs_uri_hash (gconstpointer p)
1466{
1467        const GnomeVFSURI *uri;
1468        const GnomeVFSURI *uri_p;
1469        guint hash_value;
1470
1471#define HASH_STRING(value, string)              \
1472        if ((string) != NULL)                   \
1473                (value) ^= g_str_hash (string);
1474
1475#define HASH_NUMBER(value, number)              \
1476        (value) ^= number;
1477
1478        uri = (const GnomeVFSURI *) p;
1479        hash_value = 0;
1480
1481        for (uri_p = uri; uri_p != NULL; uri_p = uri_p->parent) {
1482                HASH_STRING (hash_value, uri_p->text);
1483                HASH_STRING (hash_value, uri_p->method_string);
1484
1485                if (uri_p->parent != NULL) {
1486                        const GnomeVFSToplevelURI *toplevel;
1487
1488                        toplevel = (const GnomeVFSToplevelURI *) uri_p;
1489
1490                        HASH_STRING (hash_value, toplevel->host_name);
1491                        HASH_NUMBER (hash_value, toplevel->host_port);
1492                        HASH_STRING (hash_value, toplevel->user_name);
1493                        HASH_STRING (hash_value, toplevel->password);
1494                }
1495        }
1496
1497        return hash_value;
1498
1499#undef HASH_STRING
1500#undef HASH_NUMBER
1501}
1502
1503GList *
1504gnome_vfs_uri_list_ref (GList *list)
1505{
1506        g_list_foreach (list, (GFunc) gnome_vfs_uri_ref, NULL);
1507        return list;
1508}
1509
1510GList *
1511gnome_vfs_uri_list_unref (GList *list)
1512{
1513        g_list_foreach (list, (GFunc) gnome_vfs_uri_unref, NULL);
1514        return list;
1515}
1516
1517GList *
1518gnome_vfs_uri_list_copy (GList *list)
1519{
1520        return g_list_copy (gnome_vfs_uri_list_ref (list));
1521}
1522
1523void
1524gnome_vfs_uri_list_free (GList *list)
1525{
1526        g_list_free (gnome_vfs_uri_list_unref (list));
1527}
Note: See TracBrowser for help on using the repository browser.