Do not define function g_thread_init_glib, if not G_THREADS_ENABLED. It's
[platform/upstream/glib.git] / glib / gfileutils.c
1 /* gfileutils.c - File utility functions
2  *
3  *  Copyright 2000 Red Hat, Inc.
4  *
5  * GLib is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * GLib is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with GLib; see the file COPYING.LIB.  If not,
17  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  *   Boston, MA 02111-1307, USA.
19  */
20
21 #include "config.h"
22
23 #include "glib.h"
24
25 #include <sys/stat.h>
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <stdlib.h>
38
39 #ifdef G_OS_WIN32
40 #include <io.h>
41 #ifndef F_OK
42 #define F_OK 0
43 #define X_OK 1
44 #define W_OK 2
45 #define R_OK 4
46 #endif /* !F_OK */
47
48 #ifndef S_ISREG
49 #define S_ISREG(mode) ((mode)&_S_IFREG)
50 #endif
51
52 #ifndef S_ISDIR
53 #define S_ISDIR(mode) ((mode)&_S_IFDIR)
54 #endif
55
56 #endif /* G_OS_WIN32 */
57
58 #ifndef S_ISLNK
59 #define S_ISLNK(x) 0
60 #endif
61
62 #ifndef O_BINARY
63 #define O_BINARY 0
64 #endif
65
66 #include "glibintl.h"
67
68 /**
69  * g_file_test:
70  * @filename: a filename to test
71  * @test: bitfield of #GFileTest flags
72  * 
73  * Returns %TRUE if any of the tests in the bitfield @test are
74  * %TRUE. For example, <literal>(G_FILE_TEST_EXISTS | 
75  * G_FILE_TEST_IS_DIR)</literal> will return %TRUE if the file exists; 
76  * the check whether it's a directory doesn't matter since the existence 
77  * test is %TRUE. With the current set of available tests, there's no point
78  * passing in more than one test at a time.
79  * 
80  * Apart from %G_FILE_TEST_IS_SYMLINK all tests follow symbolic links,
81  * so for a symbolic link to a regular file g_file_test() will return
82  * %TRUE for both %G_FILE_TEST_IS_SYMLINK and %G_FILE_TEST_IS_REGULAR.
83  *
84  * Note, that for a dangling symbolic link g_file_test() will return
85  * %TRUE for %G_FILE_TEST_IS_SYMLINK and %FALSE for all other flags.
86  *
87  * You should never use g_file_test() to test whether it is safe
88  * to perform an operaton, because there is always the possibility
89  * of the condition changing before you actually perform the operation.
90  * For example, you might think you could use %G_FILE_TEST_IS_SYMLINK
91  * to know whether it is is safe to write to a file without being
92  * tricked into writing into a different location. It doesn't work!
93  *
94  * <informalexample><programlisting>
95  * /&ast; DON'T DO THIS &ast;/
96  *  if (!g_file_test (filename, G_FILE_TEST_IS_SYMLINK)) {
97  *    fd = open (filename, O_WRONLY);
98  *    /&ast; write to fd &ast;/
99  *  }
100  * </programlisting></informalexample>
101  *
102  * Another thing to note is that %G_FILE_TEST_EXISTS and
103  * %G_FILE_TEST_IS_EXECUTABLE are implemented using the access()
104  * system call. This usually doesn't matter, but if your program
105  * is setuid or setgid it means that these tests will give you
106  * the answer for the real user ID and group ID , rather than the
107  * effective user ID and group ID.
108  *
109  * Return value: whether a test was %TRUE
110  **/
111 gboolean
112 g_file_test (const gchar *filename,
113              GFileTest    test)
114 {
115   if ((test & G_FILE_TEST_EXISTS) && (access (filename, F_OK) == 0))
116     return TRUE;
117   
118   if ((test & G_FILE_TEST_IS_EXECUTABLE) && (access (filename, X_OK) == 0))
119     {
120 #ifndef G_OS_WIN32
121       if (getuid () != 0)
122 #endif  
123         return TRUE;
124
125       /* For root, on some POSIX systems, access (filename, X_OK)
126        * will succeed even if no executable bits are set on the
127        * file. We fall through to a stat test to avoid that.
128        */
129     }
130   else
131     test &= ~G_FILE_TEST_IS_EXECUTABLE;
132
133   if (test & G_FILE_TEST_IS_SYMLINK)
134     {
135 #ifdef G_OS_WIN32
136       /* no sym links on win32, no lstat in msvcrt */
137 #else
138       struct stat s;
139
140       if ((lstat (filename, &s) == 0) && S_ISLNK (s.st_mode))
141         return TRUE;
142 #endif
143     }
144   
145   if (test & (G_FILE_TEST_IS_REGULAR |
146               G_FILE_TEST_IS_DIR |
147               G_FILE_TEST_IS_EXECUTABLE))
148     {
149       struct stat s;
150       
151       if (stat (filename, &s) == 0)
152         {
153           if ((test & G_FILE_TEST_IS_REGULAR) && S_ISREG (s.st_mode))
154             return TRUE;
155           
156           if ((test & G_FILE_TEST_IS_DIR) && S_ISDIR (s.st_mode))
157             return TRUE;
158
159 #ifndef G_OS_WIN32
160           /* The extra test for root when access (file, X_OK) succeeds.
161            * Probably only makes sense on Unix.
162            */
163           if ((test & G_FILE_TEST_IS_EXECUTABLE) &&
164               ((s.st_mode & S_IXOTH) ||
165                (s.st_mode & S_IXUSR) ||
166                (s.st_mode & S_IXGRP)))
167             return TRUE;
168 #endif
169         }
170     }
171
172   return FALSE;
173 }
174
175 GQuark
176 g_file_error_quark (void)
177 {
178   static GQuark q = 0;
179   if (q == 0)
180     q = g_quark_from_static_string ("g-file-error-quark");
181
182   return q;
183 }
184
185 /**
186  * g_file_error_from_errno:
187  * @err_no: an "errno" value
188  * 
189  * Gets a #GFileError constant based on the passed-in @errno.
190  * For example, if you pass in %EEXIST this function returns
191  * #G_FILE_ERROR_EXIST. Unlike @errno values, you can portably
192  * assume that all #GFileError values will exist.
193  *
194  * Normally a #GFileError value goes into a #GError returned
195  * from a function that manipulates files. So you would use
196  * g_file_error_from_errno() when constructing a #GError.
197  * 
198  * Return value: #GFileError corresponding to the given @errno
199  **/
200 GFileError
201 g_file_error_from_errno (gint err_no)
202 {
203   switch (err_no)
204     {
205 #ifdef EEXIST
206     case EEXIST:
207       return G_FILE_ERROR_EXIST;
208       break;
209 #endif
210
211 #ifdef EISDIR
212     case EISDIR:
213       return G_FILE_ERROR_ISDIR;
214       break;
215 #endif
216
217 #ifdef EACCES
218     case EACCES:
219       return G_FILE_ERROR_ACCES;
220       break;
221 #endif
222
223 #ifdef ENAMETOOLONG
224     case ENAMETOOLONG:
225       return G_FILE_ERROR_NAMETOOLONG;
226       break;
227 #endif
228
229 #ifdef ENOENT
230     case ENOENT:
231       return G_FILE_ERROR_NOENT;
232       break;
233 #endif
234
235 #ifdef ENOTDIR
236     case ENOTDIR:
237       return G_FILE_ERROR_NOTDIR;
238       break;
239 #endif
240
241 #ifdef ENXIO
242     case ENXIO:
243       return G_FILE_ERROR_NXIO;
244       break;
245 #endif
246
247 #ifdef ENODEV
248     case ENODEV:
249       return G_FILE_ERROR_NODEV;
250       break;
251 #endif
252
253 #ifdef EROFS
254     case EROFS:
255       return G_FILE_ERROR_ROFS;
256       break;
257 #endif
258
259 #ifdef ETXTBSY
260     case ETXTBSY:
261       return G_FILE_ERROR_TXTBSY;
262       break;
263 #endif
264
265 #ifdef EFAULT
266     case EFAULT:
267       return G_FILE_ERROR_FAULT;
268       break;
269 #endif
270
271 #ifdef ELOOP
272     case ELOOP:
273       return G_FILE_ERROR_LOOP;
274       break;
275 #endif
276
277 #ifdef ENOSPC
278     case ENOSPC:
279       return G_FILE_ERROR_NOSPC;
280       break;
281 #endif
282
283 #ifdef ENOMEM
284     case ENOMEM:
285       return G_FILE_ERROR_NOMEM;
286       break;
287 #endif
288
289 #ifdef EMFILE
290     case EMFILE:
291       return G_FILE_ERROR_MFILE;
292       break;
293 #endif
294
295 #ifdef ENFILE
296     case ENFILE:
297       return G_FILE_ERROR_NFILE;
298       break;
299 #endif
300
301 #ifdef EBADF
302     case EBADF:
303       return G_FILE_ERROR_BADF;
304       break;
305 #endif
306
307 #ifdef EINVAL
308     case EINVAL:
309       return G_FILE_ERROR_INVAL;
310       break;
311 #endif
312
313 #ifdef EPIPE
314     case EPIPE:
315       return G_FILE_ERROR_PIPE;
316       break;
317 #endif
318
319 #ifdef EAGAIN
320     case EAGAIN:
321       return G_FILE_ERROR_AGAIN;
322       break;
323 #endif
324
325 #ifdef EINTR
326     case EINTR:
327       return G_FILE_ERROR_INTR;
328       break;
329 #endif
330
331 #ifdef EIO
332     case EIO:
333       return G_FILE_ERROR_IO;
334       break;
335 #endif
336
337 #ifdef EPERM
338     case EPERM:
339       return G_FILE_ERROR_PERM;
340       break;
341 #endif
342       
343     default:
344       return G_FILE_ERROR_FAILED;
345       break;
346     }
347 }
348
349 static gboolean
350 get_contents_stdio (const gchar *filename,
351                     FILE        *f,
352                     gchar      **contents,
353                     gsize       *length, 
354                     GError     **error)
355 {
356   gchar buf[2048];
357   size_t bytes;
358   char *str;
359   size_t total_bytes;
360   size_t total_allocated;
361   
362   g_assert (f != NULL);
363
364 #define STARTING_ALLOC 64
365   
366   total_bytes = 0;
367   total_allocated = STARTING_ALLOC;
368   str = g_malloc (STARTING_ALLOC);
369   
370   while (!feof (f))
371     {
372       bytes = fread (buf, 1, 2048, f);
373
374       while ((total_bytes + bytes + 1) > total_allocated)
375         {
376           total_allocated *= 2;
377           str = g_try_realloc (str, total_allocated);
378
379           if (str == NULL)
380             {
381               g_set_error (error,
382                            G_FILE_ERROR,
383                            G_FILE_ERROR_NOMEM,
384                            _("Could not allocate %lu bytes to read file \"%s\""),
385                            (gulong) total_allocated, filename);
386               goto error;
387             }
388         }
389       
390       if (ferror (f))
391         {
392           g_set_error (error,
393                        G_FILE_ERROR,
394                        g_file_error_from_errno (errno),
395                        _("Error reading file '%s': %s"),
396                        filename, g_strerror (errno));
397
398           goto error;
399         }
400
401       memcpy (str + total_bytes, buf, bytes);
402       total_bytes += bytes;
403     }
404
405   fclose (f);
406
407   str[total_bytes] = '\0';
408   
409   if (length)
410     *length = total_bytes;
411   
412   *contents = str;
413   
414   return TRUE;
415
416  error:
417
418   g_free (str);
419   fclose (f);
420   
421   return FALSE;  
422 }
423
424 #ifndef G_OS_WIN32
425
426 static gboolean
427 get_contents_regfile (const gchar *filename,
428                       struct stat *stat_buf,
429                       gint         fd,
430                       gchar      **contents,
431                       gsize       *length,
432                       GError     **error)
433 {
434   gchar *buf;
435   size_t bytes_read;
436   size_t size;
437   size_t alloc_size;
438   
439   size = stat_buf->st_size;
440
441   alloc_size = size + 1;
442   buf = g_try_malloc (alloc_size);
443
444   if (buf == NULL)
445     {
446       g_set_error (error,
447                    G_FILE_ERROR,
448                    G_FILE_ERROR_NOMEM,
449                    _("Could not allocate %lu bytes to read file \"%s\""),
450                    (gulong) alloc_size, filename);
451
452       goto error;
453     }
454   
455   bytes_read = 0;
456   while (bytes_read < size)
457     {
458       gssize rc;
459           
460       rc = read (fd, buf + bytes_read, size - bytes_read);
461
462       if (rc < 0)
463         {
464           if (errno != EINTR) 
465             {
466               g_free (buf);
467                   
468               g_set_error (error,
469                            G_FILE_ERROR,
470                            g_file_error_from_errno (errno),
471                            _("Failed to read from file '%s': %s"),
472                            filename, g_strerror (errno));
473
474               goto error;
475             }
476         }
477       else if (rc == 0)
478         break;
479       else
480         bytes_read += rc;
481     }
482       
483   buf[bytes_read] = '\0';
484
485   if (length)
486     *length = bytes_read;
487   
488   *contents = buf;
489
490   close (fd);
491
492   return TRUE;
493
494  error:
495
496   close (fd);
497   
498   return FALSE;
499 }
500
501 static gboolean
502 get_contents_posix (const gchar *filename,
503                     gchar      **contents,
504                     gsize       *length,
505                     GError     **error)
506 {
507   struct stat stat_buf;
508   gint fd;
509   
510   /* O_BINARY useful on Cygwin */
511   fd = open (filename, O_RDONLY|O_BINARY);
512
513   if (fd < 0)
514     {
515       g_set_error (error,
516                    G_FILE_ERROR,
517                    g_file_error_from_errno (errno),
518                    _("Failed to open file '%s': %s"),
519                    filename, g_strerror (errno));
520
521       return FALSE;
522     }
523
524   /* I don't think this will ever fail, aside from ENOMEM, but. */
525   if (fstat (fd, &stat_buf) < 0)
526     {
527       close (fd);
528       
529       g_set_error (error,
530                    G_FILE_ERROR,
531                    g_file_error_from_errno (errno),
532                    _("Failed to get attributes of file '%s': fstat() failed: %s"),
533                    filename, g_strerror (errno));
534
535       return FALSE;
536     }
537
538   if (stat_buf.st_size > 0 && S_ISREG (stat_buf.st_mode))
539     {
540       return get_contents_regfile (filename,
541                                    &stat_buf,
542                                    fd,
543                                    contents,
544                                    length,
545                                    error);
546     }
547   else
548     {
549       FILE *f;
550
551       f = fdopen (fd, "r");
552       
553       if (f == NULL)
554         {
555           g_set_error (error,
556                        G_FILE_ERROR,
557                        g_file_error_from_errno (errno),
558                        _("Failed to open file '%s': fdopen() failed: %s"),
559                        filename, g_strerror (errno));
560           
561           return FALSE;
562         }
563   
564       return get_contents_stdio (filename, f, contents, length, error);
565     }
566 }
567
568 #else  /* G_OS_WIN32 */
569
570 static gboolean
571 get_contents_win32 (const gchar *filename,
572                     gchar      **contents,
573                     gsize       *length,
574                     GError     **error)
575 {
576   FILE *f;
577
578   /* I guess you want binary mode; maybe you want text sometimes? */
579   f = fopen (filename, "rb");
580
581   if (f == NULL)
582     {
583       g_set_error (error,
584                    G_FILE_ERROR,
585                    g_file_error_from_errno (errno),
586                    _("Failed to open file '%s': %s"),
587                    filename, g_strerror (errno));
588       
589       return FALSE;
590     }
591   
592   return get_contents_stdio (filename, f, contents, length, error);
593 }
594
595 #endif
596
597 /**
598  * g_file_get_contents:
599  * @filename: a file to read contents from
600  * @contents: location to store an allocated string
601  * @length: location to store length in bytes of the contents
602  * @error: return location for a #GError
603  * 
604  * Reads an entire file into allocated memory, with good error
605  * checking. If @error is set, %FALSE is returned, and @contents is set
606  * to %NULL. If %TRUE is returned, @error will not be set, and @contents
607  * will be set to the file contents.  The string stored in @contents
608  * will be nul-terminated, so for text files you can pass %NULL for the
609  * @length argument.  The error domain is #G_FILE_ERROR. Possible
610  * error codes are those in the #GFileError enumeration.
611  *
612  * Return value: %TRUE on success, %FALSE if error is set
613  **/
614 gboolean
615 g_file_get_contents (const gchar *filename,
616                      gchar      **contents,
617                      gsize       *length,
618                      GError     **error)
619 {  
620   g_return_val_if_fail (filename != NULL, FALSE);
621   g_return_val_if_fail (contents != NULL, FALSE);
622
623   *contents = NULL;
624   if (length)
625     *length = 0;
626
627 #ifdef G_OS_WIN32
628   return get_contents_win32 (filename, contents, length, error);
629 #else
630   return get_contents_posix (filename, contents, length, error);
631 #endif
632 }
633
634 /*
635  * mkstemp() implementation is from the GNU C library.
636  * Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc.
637  */
638 /**
639  * g_mkstemp:
640  * @tmpl: template filename
641  *
642  * Opens a temporary file. See the <function>mkstemp()</function> documentation
643  * on most UNIX-like systems. This is a portability wrapper, which simply calls 
644  * <function>mkstemp()</function> on systems that have it, and implements 
645  * it in GLib otherwise.
646  *
647  * The parameter is a string that should match the rules for
648  * <function>mkstemp()</function>, i.e. end in "XXXXXX". The X string will 
649  * be modified to form the name of a file that didn't exist.
650  *
651  * Return value: A file handle (as from <function>open()</function>) to the file
652  * opened for reading and writing. The file is opened in binary mode
653  * on platforms where there is a difference. The file handle should be
654  * closed with <function>close()</function>. In case of errors, -1 is returned.
655  */
656 int
657 g_mkstemp (char *tmpl)
658 {
659 #ifdef HAVE_MKSTEMP
660   return mkstemp (tmpl);
661 #else
662   int len;
663   char *XXXXXX;
664   int count, fd;
665   static const char letters[] =
666     "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
667   static const int NLETTERS = sizeof (letters) - 1;
668   glong value;
669   GTimeVal tv;
670   static int counter = 0;
671
672   len = strlen (tmpl);
673   if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
674     return -1;
675
676   /* This is where the Xs start.  */
677   XXXXXX = &tmpl[len - 6];
678
679   /* Get some more or less random data.  */
680   g_get_current_time (&tv);
681   value = (tv.tv_usec ^ tv.tv_sec) + counter++;
682
683   for (count = 0; count < 100; value += 7777, ++count)
684     {
685       glong v = value;
686
687       /* Fill in the random bits.  */
688       XXXXXX[0] = letters[v % NLETTERS];
689       v /= NLETTERS;
690       XXXXXX[1] = letters[v % NLETTERS];
691       v /= NLETTERS;
692       XXXXXX[2] = letters[v % NLETTERS];
693       v /= NLETTERS;
694       XXXXXX[3] = letters[v % NLETTERS];
695       v /= NLETTERS;
696       XXXXXX[4] = letters[v % NLETTERS];
697       v /= NLETTERS;
698       XXXXXX[5] = letters[v % NLETTERS];
699
700       fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
701
702       if (fd >= 0)
703         return fd;
704       else if (errno != EEXIST)
705         /* Any other error will apply also to other names we might
706          *  try, and there are 2^32 or so of them, so give up now.
707          */
708         return -1;
709     }
710
711   /* We got out of the loop because we ran out of combinations to try.  */
712   return -1;
713 #endif
714 }
715
716 /**
717  * g_file_open_tmp:
718  * @tmpl: Template for file name, as in g_mkstemp(), basename only
719  * @name_used: location to store actual name used
720  * @error: return location for a #GError
721  *
722  * Opens a file for writing in the preferred directory for temporary
723  * files (as returned by g_get_tmp_dir()). 
724  *
725  * @tmpl should be a string ending with six 'X' characters, as the
726  * parameter to g_mkstemp() (or <function>mkstemp()</function>). 
727  * However, unlike these functions, the template should only be a 
728  * basename, no directory components are allowed. If template is %NULL, 
729  * a default template is used.
730  *
731  * Note that in contrast to g_mkstemp() (and <function>mkstemp()</function>) 
732  * @tmpl is not modified, and might thus be a read-only literal string.
733  *
734  * The actual name used is returned in @name_used if non-%NULL. This
735  * string should be freed with g_free() when not needed any longer.
736  *
737  * Return value: A file handle (as from <function>open()</function>) to 
738  * the file opened for reading and writing. The file is opened in binary 
739  * mode on platforms where there is a difference. The file handle should be
740  * closed with <function>close()</function>. In case of errors, -1 is returned 
741  * and @error will be set.
742  **/
743 int
744 g_file_open_tmp (const char *tmpl,
745                  char      **name_used,
746                  GError    **error)
747 {
748   int retval;
749   const char *tmpdir;
750   char *sep;
751   char *fulltemplate;
752
753   if (tmpl == NULL)
754     tmpl = ".XXXXXX";
755
756   if (strchr (tmpl, G_DIR_SEPARATOR)
757 #ifdef G_OS_WIN32
758       || strchr (tmpl, '/')
759 #endif
760                                     )
761     {
762       g_set_error (error,
763                    G_FILE_ERROR,
764                    G_FILE_ERROR_FAILED,
765                    _("Template '%s' invalid, should not contain a '%s'"),
766                    tmpl, G_DIR_SEPARATOR_S);
767
768       return -1;
769     }
770   
771   if (strlen (tmpl) < 6 ||
772       strcmp (tmpl + strlen (tmpl) - 6, "XXXXXX") != 0)
773     {
774       g_set_error (error,
775                    G_FILE_ERROR,
776                    G_FILE_ERROR_FAILED,
777                    _("Template '%s' doesn't end with XXXXXX"),
778                    tmpl);
779       return -1;
780     }
781
782   tmpdir = g_get_tmp_dir ();
783
784   if (tmpdir [strlen (tmpdir) - 1] == G_DIR_SEPARATOR)
785     sep = "";
786   else
787     sep = G_DIR_SEPARATOR_S;
788
789   fulltemplate = g_strconcat (tmpdir, sep, tmpl, NULL);
790
791   retval = g_mkstemp (fulltemplate);
792
793   if (retval == -1)
794     {
795       g_set_error (error,
796                    G_FILE_ERROR,
797                    g_file_error_from_errno (errno),
798                    _("Failed to create file '%s': %s"),
799                    fulltemplate, g_strerror (errno));
800       g_free (fulltemplate);
801       return -1;
802     }
803
804   if (name_used)
805     *name_used = fulltemplate;
806   else
807     g_free (fulltemplate);
808
809   return retval;
810 }
811
812 static gchar *
813 g_build_pathv (const gchar *separator,
814                const gchar *first_element,
815                va_list      args)
816 {
817   GString *result;
818   gint separator_len = strlen (separator);
819   gboolean is_first = TRUE;
820   gboolean have_leading = FALSE;
821   const gchar *single_element = NULL;
822   const gchar *next_element;
823   const gchar *last_trailing = NULL;
824
825   result = g_string_new (NULL);
826
827   next_element = first_element;
828
829   while (TRUE)
830     {
831       const gchar *element;
832       const gchar *start;
833       const gchar *end;
834
835       if (next_element)
836         {
837           element = next_element;
838           next_element = va_arg (args, gchar *);
839         }
840       else
841         break;
842
843       /* Ignore empty elements */
844       if (!*element)
845         continue;
846       
847       start = element;
848
849       if (separator_len)
850         {
851           while (start &&
852                  strncmp (start, separator, separator_len) == 0)
853             start += separator_len;
854         }
855
856       end = start + strlen (start);
857       
858       if (separator_len)
859         {
860           while (end >= start + separator_len &&
861                  strncmp (end - separator_len, separator, separator_len) == 0)
862             end -= separator_len;
863           
864           last_trailing = end;
865           while (last_trailing >= element + separator_len &&
866                  strncmp (last_trailing - separator_len, separator, separator_len) == 0)
867             last_trailing -= separator_len;
868
869           if (!have_leading)
870             {
871               /* If the leading and trailing separator strings are in the
872                * same element and overlap, the result is exactly that element
873                */
874               if (last_trailing <= start)
875                 single_element = element;
876                   
877               g_string_append_len (result, element, start - element);
878               have_leading = TRUE;
879             }
880           else
881             single_element = NULL;
882         }
883
884       if (end == start)
885         continue;
886
887       if (!is_first)
888         g_string_append (result, separator);
889       
890       g_string_append_len (result, start, end - start);
891       is_first = FALSE;
892     }
893
894   if (single_element)
895     {
896       g_string_free (result, TRUE);
897       return g_strdup (single_element);
898     }
899   else
900     {
901       if (last_trailing)
902         g_string_append (result, last_trailing);
903   
904       return g_string_free (result, FALSE);
905     }
906 }
907
908 /**
909  * g_build_path:
910  * @separator: a string used to separator the elements of the path.
911  * @first_element: the first element in the path
912  * @Varargs: remaining elements in path, terminated by %NULL
913  * 
914  * Creates a path from a series of elements using @separator as the
915  * separator between elements. At the boundary between two elements,
916  * any trailing occurrences of separator in the first element, or
917  * leading occurrences of separator in the second element are removed
918  * and exactly one copy of the separator is inserted.
919  *
920  * Empty elements are ignored.
921  *
922  * The number of leading copies of the separator on the result is
923  * the same as the number of leading copies of the separator on
924  * the first non-empty element.
925  *
926  * The number of trailing copies of the separator on the result is
927  * the same as the number of trailing copies of the separator on
928  * the last non-empty element. (Determination of the number of
929  * trailing copies is done without stripping leading copies, so
930  * if the separator is <literal>ABA</literal>, <literal>ABABA</literal>
931  * has 1 trailing copy.)
932  *
933  * However, if there is only a single non-empty element, and there
934  * are no characters in that element not part of the leading or
935  * trailing separators, then the result is exactly the original value
936  * of that element.
937  *
938  * Other than for determination of the number of leading and trailing
939  * copies of the separator, elements consisting only of copies
940  * of the separator are ignored.
941  * 
942  * Return value: a newly-allocated string that must be freed with g_free().
943  **/
944 gchar *
945 g_build_path (const gchar *separator,
946               const gchar *first_element,
947               ...)
948 {
949   gchar *str;
950   va_list args;
951
952   g_return_val_if_fail (separator != NULL, NULL);
953
954   va_start (args, first_element);
955   str = g_build_pathv (separator, first_element, args);
956   va_end (args);
957
958   return str;
959 }
960
961 /**
962  * g_build_filename:
963  * @first_element: the first element in the path
964  * @Varargs: remaining elements in path, terminated by %NULL
965  * 
966  * Creates a filename from a series of elements using the correct
967  * separator for filenames. This function behaves identically
968  * to <literal>g_build_path (G_DIR_SEPARATOR_S, first_element, ....)</literal>.
969  *
970  * No attempt is made to force the resulting filename to be an absolute
971  * path. If the first element is a relative path, the result will
972  * be a relative path. 
973  * 
974  * Return value: a newly-allocated string that must be freed with g_free().
975  **/
976 gchar *
977 g_build_filename (const gchar *first_element, 
978                   ...)
979 {
980   gchar *str;
981   va_list args;
982
983   va_start (args, first_element);
984   str = g_build_pathv (G_DIR_SEPARATOR_S, first_element, args);
985   va_end (args);
986
987   return str;
988 }