Introduce the idea of a filename encoding, which is *literally* the
[platform/upstream/glib.git] / glib / gdir.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * gdir.c: Simplified wrapper around the DIRENT functions.
5  *
6  * Copyright 2001 Hans Breuer
7  * Copyright 2004 Tor Lillqvist
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 #include "config.h"
26
27 #include <errno.h>
28 #include <string.h> /* strcmp */
29
30 #ifdef HAVE_DIRENT_H
31 #include <sys/types.h>
32 #include <dirent.h>
33 #endif
34
35 #include "galias.h"
36 #include "glib.h"
37 #include "gdir.h"
38
39 #include "glibintl.h"
40
41 struct _GDir
42 {
43   union {
44     DIR *dirp;
45 #ifdef G_OS_WIN32
46     _WDIR *wdirp;
47 #endif
48   } u;
49 #ifdef G_OS_WIN32
50   gchar utf8_buf[FILENAME_MAX*4];
51 #endif
52 };
53
54 /**
55  * g_dir_open:
56  * @path: the path to the directory you are interested in. On Unix
57  *         in the on-disk encoding. On Windows in UTF-8
58  * @flags: Currently must be set to 0. Reserved for future use.
59  * @error: return location for a #GError, or %NULL.
60  *         If non-%NULL, an error will be set if and only if
61  *         g_dir_open_fails.
62  *
63  * Opens a directory for reading. The names of the files in the
64  * directory can then be retrieved using g_dir_read_name().
65  *
66  * Return value: a newly allocated #GDir on success, %NULL on failure.
67  *   If non-%NULL, you must free the result with g_dir_close()
68  *   when you are finished with it.
69  **/
70 GDir *
71 g_dir_open (const gchar  *path,
72             guint         flags,
73             GError      **error)
74 {
75   GDir *dir;
76 #ifndef G_OS_WIN32
77   gchar *utf8_path;
78 #endif
79
80   g_return_val_if_fail (path != NULL, NULL);
81
82 #ifdef G_OS_WIN32
83   if (G_WIN32_HAVE_WIDECHAR_API ())
84     {
85       wchar_t *wpath = g_utf8_to_utf16 (path, -1, NULL, NULL, error);
86   
87       if (wpath == NULL)
88         return NULL;
89
90       dir = g_new (GDir, 1);
91
92       dir->u.wdirp = _wopendir (wpath);
93       g_free (wpath);
94   
95       if (dir->u.wdirp)
96         return dir;
97     }
98   else
99     {
100       gchar *cp_path = g_locale_from_utf8 (path, -1, NULL, NULL, error);
101
102       if (cp_path == NULL)
103         return NULL;
104
105       dir = g_new (GDir, 1);
106
107       dir->u.dirp = opendir (cp_path);
108
109       g_free (cp_path);
110
111       if (dir->u.dirp)
112         return dir;
113     }
114
115   /* error case */
116
117   g_set_error (error,
118                G_FILE_ERROR,
119                g_file_error_from_errno (errno),
120                _("Error opening directory '%s': %s"),
121                path, g_strerror (errno));
122   
123   g_free (dir);
124       
125   return NULL;
126 #else
127   dir = g_new (GDir, 1);
128
129   dir->u.dirp = opendir (path);
130
131   if (dir->u.dirp)
132     return dir;
133
134   /* error case */
135   utf8_path = g_filename_to_utf8 (path, -1,
136                                   NULL, NULL, NULL);
137   g_set_error (error,
138                G_FILE_ERROR,
139                g_file_error_from_errno (errno),
140                _("Error opening directory '%s': %s"),
141                utf8_path, g_strerror (errno));
142
143   g_free (utf8_path);
144   g_free (dir);
145
146   return NULL;
147 #endif
148 }
149
150 #ifdef G_OS_WIN32
151
152 /* The above function actually is called g_dir_open_utf8, and it's
153  * that what applications compiled with this GLib version will
154  * use.
155  */
156
157 #undef g_dir_open
158
159 /* Binary compatibility version. Not for newly compiled code. */
160
161 GDir *
162 g_dir_open (const gchar  *path,
163             guint         flags,
164             GError      **error)
165 {
166   gchar *utf8_path = g_locale_to_utf8 (path, -1, NULL, NULL, error);
167   GDir *retval;
168
169   if (utf8_path == NULL)
170     return NULL;
171
172   retval = g_dir_open_utf8 (utf8_path, flags, error);
173
174   g_free (utf8_path);
175
176   return retval;
177 }
178 #endif
179
180 /**
181  * g_dir_read_name:
182  * @dir: a #GDir* created by g_dir_open()
183  *
184  * Retrieves the name of the next entry in the directory.  The '.' and
185  * '..' entries are omitted. On Windows, the returned name is in
186  * UTF-8. On Unix, it is in the on-disk encoding.
187  *
188  * Return value: The entry's name or %NULL if there are no 
189  *   more entries. The return value is owned by GLib and
190  *   must not be modified or freed.
191  **/
192 G_CONST_RETURN gchar*
193 g_dir_read_name (GDir *dir)
194 {
195   struct dirent *entry;
196
197   g_return_val_if_fail (dir != NULL, NULL);
198
199 #ifdef G_OS_WIN32
200   if (G_WIN32_HAVE_WIDECHAR_API ())
201     {
202       gchar *utf8_name;
203       struct _wdirent *wentry;
204
205       while (1)
206         {
207           wentry = _wreaddir (dir->u.wdirp);
208           while (wentry 
209                  && (0 == wcscmp (wentry->d_name, L".") ||
210                      0 == wcscmp (wentry->d_name, L"..")))
211             wentry = _wreaddir (dir->u.wdirp);
212           
213           if (wentry == NULL)
214             return NULL;
215           
216           utf8_name = g_utf16_to_utf8 (wentry->d_name, -1, NULL, NULL, NULL);
217
218           if (utf8_name == NULL)
219             continue;           /* Huh, impossible? Skip it anyway */
220           
221           strcpy (dir->utf8_buf, utf8_name);
222           g_free (utf8_name);
223           
224           return dir->utf8_buf;
225         }
226     }
227   else
228     {
229       while (1)
230         {
231           gchar *utf8_name;
232       
233           entry = readdir (dir->u.dirp);
234           while (entry 
235                  && (0 == strcmp (entry->d_name, ".") ||
236                      0 == strcmp (entry->d_name, "..")))
237             entry = readdir (dir->u.dirp);
238
239           if (entry == NULL)
240             return NULL;
241
242           utf8_name = g_locale_to_utf8 (entry->d_name, -1, NULL, NULL, NULL);
243
244           if (utf8_name != NULL)
245             {
246               strcpy (dir->utf8_buf, utf8_name);
247               g_free (utf8_name);
248               
249               return dir->utf8_buf;
250             }
251         }
252     }
253 #else
254   entry = readdir (dir->u.dirp);
255   while (entry 
256          && (0 == strcmp (entry->d_name, ".") ||
257              0 == strcmp (entry->d_name, "..")))
258     entry = readdir (dir->u.dirp);
259
260   if (entry)
261     return entry->d_name;
262   else
263     return NULL;
264 #endif
265 }
266
267 #ifdef G_OS_WIN32
268
269 /* Ditto for g_dir_read_name */
270
271 #undef g_dir_read_name
272
273 /* Binary compatibility version. Not for newly compiled code. */
274
275 G_CONST_RETURN gchar*
276 g_dir_read_name (GDir *dir)
277 {
278   while (1)
279     {
280       const gchar *utf8_name = g_dir_read_name_utf8 (dir);
281       gchar *retval;
282       
283       if (utf8_name == NULL)
284         return NULL;
285
286       retval = g_locale_from_utf8 (utf8_name, -1, NULL, NULL, NULL);
287
288       if (retval != NULL)
289         {
290           strcpy (dir->utf8_buf, retval);
291           g_free (retval);
292
293           return dir->utf8_buf;
294         }
295     }
296 }
297
298 #endif
299
300 /**
301  * g_dir_rewind:
302  * @dir: a #GDir* created by g_dir_open()
303  *
304  * Resets the given directory. The next call to g_dir_read_name()
305  * will return the first entry again.
306  **/
307 void
308 g_dir_rewind (GDir *dir)
309 {
310   g_return_if_fail (dir != NULL);
311   
312 #ifdef G_OS_WIN32
313   if (G_WIN32_HAVE_WIDECHAR_API ())
314     {
315       _wrewinddir (dir->u.wdirp);
316       return;
317     }
318 #endif
319
320   rewinddir (dir->u.dirp);
321 }
322
323 /**
324  * g_dir_close:
325  * @dir: a #GDir* created by g_dir_open()
326  *
327  * Closes the directory and deallocates all related resources.
328  **/
329 void
330 g_dir_close (GDir *dir)
331 {
332   g_return_if_fail (dir != NULL);
333
334 #ifdef G_OS_WIN32
335   if (G_WIN32_HAVE_WIDECHAR_API ())
336     {
337       _wclosedir (dir->u.wdirp);
338       g_free (dir);
339       return;
340     }
341 #endif
342
343   closedir (dir->u.dirp);
344   g_free (dir);
345 }