Lei Zhang : shell32: Add xdg-user-dirs lookup code.

Alexandre Julliard julliard at winehq.org
Wed Mar 12 06:44:28 CDT 2008


Module: wine
Branch: master
Commit: f5ba1c21bea6a66455a478910575fcad9c9024a4
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=f5ba1c21bea6a66455a478910575fcad9c9024a4

Author: Lei Zhang <thestig at google.com>
Date:   Mon Mar 10 17:59:48 2008 -0700

shell32: Add xdg-user-dirs lookup code.

---

 dlls/shell32/xdg.c |  255 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 dlls/shell32/xdg.h |    1 +
 2 files changed, 256 insertions(+), 0 deletions(-)

diff --git a/dlls/shell32/xdg.c b/dlls/shell32/xdg.c
index 3b1a1bc..b541aa7 100644
--- a/dlls/shell32/xdg.c
+++ b/dlls/shell32/xdg.c
@@ -16,10 +16,38 @@
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ *
+ * XDG_UserDirLookup() and helper functions are based on code from:
+ * http://www.freedesktop.org/wiki/Software/xdg-user-dirs
+ *
+ * Copyright (c) 2007 Red Hat, inc
+ *
+ * From the xdg-user-dirs license:
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
  */
 
 #include "config.h"
 
+#include <stdio.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
@@ -712,3 +740,230 @@ char *XDG_GetStringValue(XDG_PARSED_FILE *file, const char *group_name, const ch
     
     return NULL;
 }
+
+/* Get the name of the xdg configuration file.
+ *
+ * [in] home_dir - $HOME
+ * [out] config_file - the name of the configuration file
+ */
+static HRESULT get_xdg_config_file(char * home_dir, char ** config_file)
+{
+    char *config_home;
+
+    config_home = getenv("XDG_CONFIG_HOME");
+    if (!config_home || !config_home[0])
+    {
+        *config_file = HeapAlloc(GetProcessHeap(), 0, strlen(home_dir) + strlen("/.config/user-dirs.dirs") + 1);
+        if (!*config_file)
+            return E_OUTOFMEMORY;
+
+        strcpy(*config_file, home_dir);
+        strcat(*config_file, "/.config/user-dirs.dirs");
+    }
+    else
+    {
+        *config_file = HeapAlloc(GetProcessHeap(), 0, strlen(config_home) + strlen("/user-dirs.dirs") + 1);
+        if (!*config_file)
+            return E_OUTOFMEMORY;
+
+        strcpy(*config_file, config_home);
+        strcat(*config_file, "/user-dirs.dirs");
+    }
+    return S_OK;
+}
+
+/* Parse the key in a line in the xdg-user-dir config file.
+ * i.e. XDG_PICTURES_DIR="$HOME/Pictures"
+ *      ^                ^
+ *
+ * [in] xdg_dirs - array of xdg directories to look for
+ * [in] num_dirs - number of elements in xdg_dirs
+ * [in/out] p_ptr - pointer to where we are in the buffer
+ * Returns the index to xdg_dirs if we find the key, or -1 on error.
+ */
+static int parse_config1(const char ** xdg_dirs, const unsigned int num_dirs, char ** p_ptr)
+{
+    char *p;
+    int i;
+
+    p = *p_ptr;
+    while (*p == ' ' || *p == '\t')
+        p++;
+    if (strncmp(p, "XDG_", 4))
+        return -1;
+
+    p += 4;
+    for (i = 0; i < num_dirs; i++)
+    {
+        if (!strncmp(p, xdg_dirs[i], strlen(xdg_dirs[i])))
+        {
+            p += strlen(xdg_dirs[i]);
+            break;
+        }
+    }
+    if (i == num_dirs)
+        return -1;
+    if (strncmp(p, "_DIR", 4))
+        return -1;
+    p += 4;
+    while (*p == ' ' || *p == '\t')
+        p++;
+    if (*p != '=')
+        return -1;
+    p++;
+    while (*p == ' ' || *p == '\t')
+        p++;
+    if (*p != '"')
+        return -1;
+    p++;
+
+    *p_ptr = p;
+    return i;
+}
+
+/* Parse the value in a line in the xdg-user-dir config file.
+ * i.e. XDG_PICTURES_DIR="$HOME/Pictures"
+ *                        ^             ^
+ *
+ * [in] p - pointer to the buffer
+ * [in] home_dir - $HOME
+ * [out] out_ptr - the directory name
+ */
+static HRESULT parse_config2(char * p, const char * home_dir, char ** out_ptr)
+{
+    BOOL relative;
+    char *out, *d;
+
+    relative = FALSE;
+
+    if (!strncmp(p, "$HOME/", 6))
+    {
+        p += 6;
+        relative = TRUE;
+    }
+    else if (*p != '/')
+        return E_FAIL;
+
+    if (relative)
+    {
+        out = HeapAlloc(GetProcessHeap(), 0, strlen(home_dir) + strlen(p) + 2);
+        if (!out)
+            return E_OUTOFMEMORY;
+
+        strcpy(out, home_dir);
+        strcat(out, "/");
+    }
+    else
+    {
+        out = HeapAlloc(GetProcessHeap(), 0, strlen(p) + 1);
+        if (!out)
+            return E_OUTOFMEMORY;
+        *out = 0;
+    }
+
+    d = out + strlen(out);
+    while (*p && *p != '"')
+    {
+        if ((*p == '\\') && (*(p + 1) != 0))
+            p++;
+        *d++ = *p++;
+    }
+    *d = 0;
+    *out_ptr = out;
+    return S_OK;
+}
+
+/* Parse part of a line in the xdg-user-dir config file.
+ * i.e. XDG_PICTURES_DIR="$HOME/Pictures"
+ *                        ^             ^
+ *
+ * The calling function is responsible for freeing all elements of out_ptr as
+ * well as out_ptr itself.
+ *
+ * [in] xdg_dirs - array of xdg directories to look for
+ * [in] num_dirs - number of elements in xdg_dirs
+ * [out] out_ptr - an array of the xdg directories names
+ */
+HRESULT XDG_UserDirLookup(const char ** xdg_dirs, const unsigned int num_dirs, char *** out_ptr)
+{
+    FILE *file;
+    char **out;
+    char *home_dir, *config_file;
+    char buffer[512];
+    int i, len;
+    HRESULT hr;
+
+    *out_ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, num_dirs * sizeof(char *));
+    out = *out_ptr;
+    if (!out)
+        return E_OUTOFMEMORY;
+
+    home_dir = getenv("HOME");
+    if (!home_dir)
+    {
+        hr = E_FAIL;
+        goto xdg_user_dir_lookup_error;
+    }
+
+    hr = get_xdg_config_file(home_dir, &config_file);
+    if (FAILED(hr))
+        goto xdg_user_dir_lookup_error;
+
+    file = fopen(config_file, "r");
+    HeapFree(GetProcessHeap(), 0, config_file);
+    if (!file)
+    {
+        hr = E_HANDLE;
+        goto xdg_user_dir_lookup_error;
+    }
+
+    while (fgets(buffer, sizeof(buffer), file))
+    {
+        int idx;
+        char *p;
+
+        /* Remove newline at end */
+        len = strlen(buffer);
+        if (len > 0 && buffer[len-1] == '\n')
+            buffer[len-1] = 0;
+
+        /* Parse the key */
+        p = buffer;
+        idx = parse_config1(xdg_dirs, num_dirs, &p);
+        if (idx < 0)
+            continue;
+        if (out[idx])
+            continue;
+
+        /* Parse the value */
+        hr = parse_config2(p, home_dir, &out[idx]);
+        if (FAILED(hr))
+        {
+            if (hr == E_OUTOFMEMORY)
+                goto xdg_user_dir_lookup_error;
+            continue;
+        }
+    }
+    hr = S_OK;
+
+    /* Remove entries for directories that do no exist */
+    for (i = 0; i <  num_dirs; i++)
+    {
+        struct stat statFolder;
+
+        if (!out[i])
+            continue;
+        if (!stat(out[i], &statFolder) && S_ISDIR(statFolder.st_mode))
+            continue;
+        HeapFree(GetProcessHeap(), 0, out[i]);
+        out[i] = NULL;
+    }
+
+xdg_user_dir_lookup_error:
+    if (FAILED(hr))
+    {
+        for (i = 0; i < num_dirs; i++) HeapFree(GetProcessHeap(), 0, out[i]);
+        HeapFree(GetProcessHeap(), 0, out_ptr);
+    }
+    return hr;
+}
diff --git a/dlls/shell32/xdg.h b/dlls/shell32/xdg.h
index 6c083c6..9ae2872 100644
--- a/dlls/shell32/xdg.h
+++ b/dlls/shell32/xdg.h
@@ -47,5 +47,6 @@ HRESULT TRASH_UnpackItemID(LPCSHITEMID id, TRASH_ELEMENT *element, WIN32_FIND_DA
 HRESULT TRASH_EnumItems(LPITEMIDLIST **pidls, int *count);
 void TRASH_DisposeElement(TRASH_ELEMENT *element);
 
+HRESULT XDG_UserDirLookup(const char ** xdg_dirs, const unsigned int num_dirs, char *** out_ptr);
 
 #endif /* ndef __XDG_H__ */




More information about the wine-cvs mailing list