[monkey-bubble: 666/753] Bring back sane versions of these files. Will be marked as deprecated
- From: Sven Herzberg <herzi src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [monkey-bubble: 666/753] Bring back sane versions of these files. Will be marked as deprecated
- Date: Wed, 14 Jul 2010 22:51:40 +0000 (UTC)
commit 2c257a00cfab3740573fd336b83fae23d3b6e0f4
Author: George Lebl <jirka 5z com>
Date: Sun Aug 26 07:41:14 2001 +0000
Bring back sane versions of these files. Will be marked as deprecated
Sun Aug 26 07:29:59 2001 George Lebl <jirka 5z com>
* Makefile.am, gnome-config.[ch], parse-path.cP, gnome-sound.[ch],
gnome-triggersP.h, gnome-triggers.[ch], gnome-i18n.[ch],
gnome-i18nP.h, libgnome.h: Bring back sane versions of these files.
Will be marked as deprecated where appropriate later after some more
discussion. In gnome-i18n, don't bring back the broken and
unused crap (preffered language and get_language)
* gnome-i18nP.h, gnome-exec.c, gnome-init.c, gnome-program.c,
gnome-url.c, test-libgnome.c: Make translations works once more
* gnome-util.c: paranoia fix, setuid/setgid programs can't use
getenv ("SHELL") (for obvious reasons).
libgnome/ChangeLog | 15 +
libgnome/Makefile.am | 12 +-
libgnome/gnome-config.c | 2144 ++++++++++++++++++++++++++++++++++++++++++++
libgnome/gnome-config.h | 291 ++++++
libgnome/gnome-exec.c | 2 +
libgnome/gnome-i18n.c | 375 ++++++++
libgnome/gnome-i18n.h | 49 +-
libgnome/gnome-i18nP.h | 57 ++
libgnome/gnome-init.c | 1 +
libgnome/gnome-program.c | 4 +
libgnome/gnome-sound.c | 516 +++++++++++
libgnome/gnome-sound.h | 50 +
libgnome/gnome-triggers.c | 605 +++++++++++++
libgnome/gnome-triggers.h | 84 ++
libgnome/gnome-triggersP.h | 40 +
libgnome/gnome-url.c | 2 +
libgnome/gnome-util.c | 8 +-
libgnome/libgnome.h | 5 +
libgnome/test-libgnome.c | 2 +
19 files changed, 4253 insertions(+), 9 deletions(-)
---
diff --git a/libgnome/ChangeLog b/libgnome/ChangeLog
index e9ab741..e9d6fc0 100644
--- a/libgnome/ChangeLog
+++ b/libgnome/ChangeLog
@@ -1,3 +1,18 @@
+Sun Aug 26 07:29:59 2001 George Lebl <jirka 5z com>
+
+ * Makefile.am, gnome-config.[ch], parse-path.cP, gnome-sound.[ch],
+ gnome-triggersP.h, gnome-triggers.[ch], gnome-i18n.[ch],
+ gnome-i18nP.h, libgnome.h: Bring back sane versions of these files.
+ Will be marked as deprecated where appropriate later after some more
+ discussion. In gnome-i18n, don't bring back the broken and
+ unused crap (preffered language and get_language)
+
+ * gnome-i18nP.h, gnome-exec.c, gnome-init.c, gnome-program.c,
+ gnome-url.c, test-libgnome.c: Make translations works once more
+
+ * gnome-util.c: paranoia fix, setuid/setgid programs can't use
+ getenv ("SHELL") (for obvious reasons).
+
Thu Aug 23 23:23:42 2001 George Lebl <jirka 5z com>
* gnome-exec.c: fix a 64bit issue with a format string (remember
diff --git a/libgnome/Makefile.am b/libgnome/Makefile.am
index 02add92..c82f0cc 100644
--- a/libgnome/Makefile.am
+++ b/libgnome/Makefile.am
@@ -50,8 +50,14 @@ $(CORBA_SOURCE): $(idls) $(ORBIT_IDL)
libgnome_src = \
libgnometypebuiltins.h \
libgnometypebuiltins.c \
+ gnome-config.c \
+ gnome-sound.c \
+ gnome-triggers.c \
+ gnome-triggersP.h \
gnome-program.c \
gnome-exec.c \
+ gnome-i18n.c \
+ gnome-i18nP.h \
gnome-url.c \
gnome-util.c \
gnome-preferences.c \
@@ -69,6 +75,9 @@ libinclude_HEADERS = \
libgnome.h
libgnome_headers = \
+ gnome-config.h \
+ gnome-sound.h \
+ gnome-triggers.h \
gnome-program.h \
gnome-i18n.h \
gnome-exec.h \
@@ -151,7 +160,8 @@ $(srcdir)/gnome-marshal.c: @REBUILD@ Makefile.am gnome-marshal.list
EXTRA_DIST = \
libgnome-2.0.pc.in \
gnome-marshal.list \
- gnome-marshal.c
+ gnome-marshal.c \
+ parse-path.cP
BUILT_SOURCES = \
libgnometypebuiltins.h \
diff --git a/libgnome/gnome-config.c b/libgnome/gnome-config.c
new file mode 100644
index 0000000..d701b32
--- /dev/null
+++ b/libgnome/gnome-config.c
@@ -0,0 +1,2144 @@
+/*
+ * Configuration-File Functions.
+ *
+ * Copyright 1993, 1994, 1997 The Free Software Foundation
+ *
+ * Authors: Miguel de Icaza
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License
+ as published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ The Gnome Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+/*
+ @NOTATION@
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* AIX requires this to be the first thing in the file. */
+#ifndef __GNUC__
+# if HAVE_ALLOCA_H
+# include <alloca.h>
+# else
+# ifdef _AIX
+ #pragma alloca
+# else
+# ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+# endif
+# endif
+# endif
+#endif
+
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include <unistd.h> /* unlink() */
+#include <stdlib.h> /* atoi() */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <glib.h>
+#include <ctype.h> /* tolower() */
+
+#include "gnome-i18nP.h"
+#include "gnome-util.h"
+#include "gnome-config.h"
+
+#ifdef HAVE_STRNDUP
+#include <string.h>
+#else
+/* Like strdup, but only copy N chars. */
+extern char *strndup (const char *s, size_t n);
+#endif
+
+#if !defined getc_unlocked && !defined HAVE_GETC_UNLOCKED
+# define getc_unlocked(fp) getc (fp)
+#endif
+
+#define STRSIZE 4096
+#define overflow (next == &CharBuffer [STRSIZE-1])
+
+enum {
+ FirstBrace,
+ OnSecHeader,
+ IgnoreToEOL,
+ IgnoreToEOLFirst,
+ KeyDef,
+ KeyDefOnKey,
+ KeyValue
+};
+
+typedef struct {
+ int type;
+ void *value;
+} iterator_type;
+
+typedef enum {
+ LOOKUP,
+ SET
+} access_type;
+
+typedef struct TKeys {
+ char *key_name;
+ char *value;
+ struct TKeys *link;
+} TKeys;
+
+typedef struct TSecHeader {
+ char *section_name;
+ TKeys *keys;
+ struct TSecHeader *link;
+} TSecHeader;
+
+typedef struct TProfile {
+ char *filename;
+ TSecHeader *section;
+ struct TProfile *link;
+ time_t last_checked;
+ time_t mtime;
+ gboolean written_to;
+ gboolean to_be_deleted;
+} TProfile;
+
+/*
+ * Prefix for all the configuration operations
+ * iff the path does not begin with / or with #
+ */
+
+#define prefix (prefix_list ? prefix_list->data : NULL)
+
+static GSList *prefix_list = NULL;
+
+static TProfile *Current = 0;
+
+/*
+ * This one keeps track of all of the opened files
+ */
+static TProfile *Base = 0;
+
+/* The `release_path' and `parsed_path' routines are inside the
+ following file. It is in a separate file to allow the test-suite
+ to get at it, without needing to export special symbols.
+
+ typedef struct {
+ char *file, *section, *key, *def;
+ char *path, *opath;
+ } ParsedPath;
+
+ static void release_path (ParsedPath *p);
+ static ParsedPath *parse_path (const char *path, gboolean priv); */
+#include "parse-path.cP"
+
+static void
+free_keys (TKeys *p)
+{
+ if (!p)
+ return;
+ free_keys (p->link);
+ g_free (p->key_name);
+ g_free (p->value);
+ g_free (p);
+}
+
+static void
+free_sections (TSecHeader *p)
+{
+ if (!p)
+ return;
+ free_sections (p->link);
+ free_keys (p->keys);
+ g_free (p->section_name);
+ p->link = 0;
+ p->keys = 0;
+ g_free (p);
+}
+
+static void
+free_profile (TProfile *p)
+{
+ if (!p)
+ return;
+ if(Current == p)
+ Current = NULL;
+ free_profile (p->link);
+ free_sections (p->section);
+ g_free (p->filename);
+ g_free (p);
+}
+
+static int
+is_loaded (const char *filename, TSecHeader **section)
+{
+ TProfile *p = Base;
+ TProfile *lastp = NULL;
+ struct stat st;
+
+ /*
+ * if the last one we accessed was this one we don't want to
+ * search
+ */
+ if (Current && strcasecmp (filename, Current->filename) == 0){
+ if (Current->last_checked != time (NULL)){
+ if (stat (filename, &st) == -1)
+ st.st_mtime = 0;
+ if (Current->mtime != st.st_mtime) {
+ free_sections (Current->section);
+ Current->section = NULL;
+ Current->filename[0] = '\0';
+ Current->written_to = TRUE;
+ Current->to_be_deleted = FALSE;
+ Current = NULL;
+ return 0;
+ }
+ Current->last_checked = time (NULL);
+ }
+ *section = Current->section;
+ return 1;
+ }
+
+ while (p){
+ /*search and destroy empty nodes*/
+ if (p->filename[0]=='\0') {
+ TProfile *next = p->link;
+ if(lastp)
+ lastp->link = next;
+ else /*the next one is the first one actually*/
+ Base = next;
+ g_free(p->filename);
+ g_free(p);
+ p = next;
+ } else if (strcasecmp (filename, p->filename) == 0){
+ if (p->last_checked != time (NULL)){
+ if (stat (filename, &st) == -1)
+ st.st_mtime = 0;
+ if (p->mtime != st.st_mtime) {
+ if(p == Current)
+ Current = NULL;
+ free_sections (p->section);
+ p->section = NULL;
+ p->filename[0] = '\0';
+ p->written_to = TRUE;
+ p->to_be_deleted = FALSE;
+ return 0;
+ }
+ p->last_checked = time (NULL);
+ }
+ Current = p;
+ *section = p->section;
+ return 1;
+ } else {
+ lastp = p;
+ p = p->link;
+ }
+ }
+ return 0;
+}
+
+static char *
+decode_string_and_dup (char *s)
+{
+ char *p = g_malloc (strlen (s) + 1);
+ char *q = p;
+
+ do {
+ if (*s == '\\'){
+ switch (*(++s)){
+ case 'n':
+ *p++ = '\n';
+ break;
+ case '\\':
+ *p++ = '\\';
+ break;
+ case 'r':
+ *p++ = '\r';
+ break;
+ default:
+ *p++ = '\\';
+ *p++ = *s;
+ }
+ } else
+ *p++ = *s;
+ } while (*s++);
+ return q;
+}
+
+static char *
+escape_string_and_dup (char *s)
+{
+ char *return_value, *p = s;
+ int len = 0;
+
+ if(!s)
+ return g_strdup("");
+
+ while (*p){
+ len++;
+ if (*p == '\n' || *p == '\\' || *p == '\r' || *p == '\0')
+ len++;
+ p++;
+ }
+ return_value = p = (char *) g_malloc (len + 1);
+ if (!return_value)
+ return 0;
+ do {
+ switch (*s){
+ case '\n':
+ *p++ = '\\';
+ *p++ = 'n';
+ break;
+ case '\r':
+ *p++ = '\\';
+ *p++ = 'r';
+ break;
+ case '\\':
+ *p++ = '\\';
+ *p++ = '\\';
+ break;
+ default:
+ *p++ = *s;
+ }
+ } while (*s++);
+ return return_value;
+}
+
+static TSecHeader *
+load (const char *file)
+{
+ FILE *f;
+ int state;
+ TSecHeader *SecHeader = 0;
+ char CharBuffer [STRSIZE];
+ char *next = ""; /* Not needed */
+ int c;
+
+ if ((f = fopen (file, "r"))==NULL)
+ return NULL;
+
+ state = FirstBrace;
+ while ((c = getc_unlocked (f)) != EOF){
+ if (c == '\r') /* Ignore Carriage Return */
+ continue;
+
+ switch (state){
+
+ case OnSecHeader:
+ if (c == ']' || overflow){
+ *next = '\0';
+ next = CharBuffer;
+ SecHeader->section_name = g_strdup (CharBuffer);
+ state = IgnoreToEOL;
+ } else
+ *next++ = c;
+ break;
+
+ case IgnoreToEOL:
+ case IgnoreToEOLFirst:
+ if (c == '\n'){
+ if (state == IgnoreToEOLFirst)
+ state = FirstBrace;
+ else
+ state = KeyDef;
+ next = CharBuffer;
+ }
+ break;
+
+ case FirstBrace:
+ case KeyDef:
+ case KeyDefOnKey:
+ if (c == '#') {
+ if (state == FirstBrace)
+ state = IgnoreToEOLFirst;
+ else
+ state = IgnoreToEOL;
+ break;
+ }
+
+ if (c == '[' && state != KeyDefOnKey){
+ TSecHeader *temp;
+
+ temp = SecHeader;
+ SecHeader = (TSecHeader *) g_malloc (sizeof (TSecHeader));
+ SecHeader->link = temp;
+ SecHeader->keys = 0;
+ state = OnSecHeader;
+ next = CharBuffer;
+ break;
+ }
+ /* On first pass, don't allow dangling keys */
+ if (state == FirstBrace)
+ break;
+
+ if ((c == ' ' && state != KeyDefOnKey) || c == '\t')
+ break;
+
+ if (c == '\n' || overflow) { /* Abort Definition */
+ next = CharBuffer;
+ state = KeyDef;
+ break;
+ }
+
+ if (c == '=' || overflow){
+ TKeys *temp;
+
+ temp = SecHeader->keys;
+ *next = '\0';
+ SecHeader->keys = (TKeys *) g_malloc (sizeof (TKeys));
+ SecHeader->keys->link = temp;
+ SecHeader->keys->key_name = g_strdup (CharBuffer);
+ state = KeyValue;
+ next = CharBuffer;
+ } else {
+ *next++ = c;
+ state = KeyDefOnKey;
+ }
+ break;
+
+ case KeyValue:
+ if (overflow || c == '\n'){
+ *next = '\0';
+ SecHeader->keys->value = decode_string_and_dup (CharBuffer);
+ state = c == '\n' ? KeyDef : IgnoreToEOL;
+ next = CharBuffer;
+#ifdef GNOME_ENABLE_DEBUG
+#endif
+ } else
+ *next++ = c;
+ break;
+
+ } /* switch */
+
+ } /* while ((c = getc_unlocked (f)) != EOF) */
+ if (c == EOF && state == KeyValue){
+ *next = '\0';
+ SecHeader->keys->value = decode_string_and_dup (CharBuffer);
+ }
+ fclose (f);
+ return SecHeader;
+}
+
+static void
+new_key (TSecHeader *section, const char *key_name, const char *value)
+{
+ TKeys *key;
+
+ key = (TKeys *) g_malloc (sizeof (TKeys));
+ key->key_name = g_strdup (key_name);
+ key->value = g_strdup (value);
+ key->link = section->keys;
+ section->keys = key;
+}
+
+static const char *
+access_config (access_type mode, const char *section_name,
+ const char *key_name, const char *def, const char *filename,
+ gboolean *def_used)
+{
+
+ TProfile *New;
+ TSecHeader *section;
+ TKeys *key;
+
+ if (def_used)
+ *def_used = FALSE;
+ if (!is_loaded (filename, §ion)){
+ struct stat st;
+
+ if (stat (filename, &st) == -1)
+ st.st_mtime = 0;
+
+ New = (TProfile *) g_malloc (sizeof (TProfile));
+ New->link = Base;
+ New->filename = g_strdup (filename);
+ New->section = load (filename);
+ New->mtime = st.st_mtime;
+ New->written_to = FALSE;
+ New->to_be_deleted = FALSE;
+ New->last_checked = time (NULL);
+ Base = New;
+ section = New->section;
+ Current = New;
+ }
+
+ /* Start search */
+ for (; section; section = section->link){
+ /*if section name empty or deleted or not the one we're
+ looking for, then search on*/
+ if (!section->section_name ||
+ !*section->section_name ||
+ strcasecmp (section->section_name, section_name))
+ continue;
+
+ for (key = section->keys; key; key = key->link){
+ if (strcasecmp (key->key_name, key_name))
+ continue;
+ if (mode == SET){
+ g_free (key->value);
+ key->value = g_strdup (def);
+ Current->written_to = TRUE;
+ }
+ return key->value;
+ }
+
+ /* No key found */
+ if (mode == SET){
+ new_key (section, key_name, def);
+ Current->written_to = TRUE;
+ return 0;
+ }
+ }
+
+ /* Non existent section */
+ if ((mode == SET) && def){
+ section = (TSecHeader *) g_malloc (sizeof (TSecHeader));
+ section->section_name = g_strdup (section_name);
+ section->keys = 0;
+ new_key (section, key_name, def);
+ section->link = Current->section;
+ Current->section = section;
+ Current->written_to = TRUE;
+ }
+ if (def_used)
+ *def_used = TRUE;
+ return def;
+}
+
+/* an extended version of access_config for looking up values in ~/.gnome.
+ * For writes it falls through to the standard behaviour.
+ * For lookups, it first checks for the value in
+ * $(datadir)/gnome/config-override, and if it isn't there in ~/.gnome,
+ * then checks $(datadir)/gnome/config, and as a last fallback uses def.
+ * This gives system administrators high level control over the default
+ * configuration values for GNOME
+ *
+ * Note that it doesn't really make sense to have system wide defaults for
+ * ~/.gnome_private data (IMHO), so I haven't addressed it in this
+ * interface. It probably isn't suitable for absolute config file names */
+static const char *
+access_config_extended (access_type mode, const char *section_name,
+ const char *key_name, const char *def,
+ const char *rel_file, gboolean *def_used)
+{
+ char *tmp, *filename;
+ const char *ret_val;
+ gboolean internal_def;
+
+ static time_t cache_time = 0;
+ static char *cache_filename = NULL;
+ static char *cache_overrride_filename = NULL;
+ static char *cache_global_filename = NULL;
+ gboolean cache_valid;
+ time_t now;
+
+ switch (mode) {
+ case SET:
+ /* fall through to normal behaviour */
+ filename = gnome_util_home_file (rel_file);
+ ret_val = access_config (mode, section_name, key_name, def,
+ filename, def_used);
+ g_free(filename);
+ cache_time = 0; /* Invalidate cache. */
+ return ret_val;
+ case LOOKUP:
+ now = time (NULL);
+ cache_valid = (cache_filename &&
+ strcmp (cache_filename, rel_file) == 0 &&
+ now - cache_time <= 2);
+ if (!cache_valid) {
+ if (cache_filename)
+ g_free (cache_filename);
+
+ cache_filename = g_strdup (rel_file);
+ cache_time = now;
+
+ if (cache_overrride_filename)
+ g_free (cache_overrride_filename);
+
+ tmp = g_concat_dir_and_file ("gnome/config-override",rel_file);
+ filename = gnome_program_locate_file
+ (gnome_program_get (), GNOME_FILE_DOMAIN_CONFIG,
+ tmp, TRUE, NULL);
+ g_free (tmp);
+ cache_overrride_filename = filename ? g_strdup (filename) : NULL;
+
+ if (cache_global_filename)
+ g_free (cache_global_filename);
+
+ tmp = g_concat_dir_and_file ("gnome/config", rel_file);
+ filename = gnome_program_locate_file
+ (gnome_program_get (), GNOME_FILE_DOMAIN_CONFIG,
+ tmp, TRUE, NULL);
+ g_free (tmp);
+ cache_global_filename = filename ? g_strdup (filename) : NULL;
+ }
+
+ if (cache_overrride_filename) {
+ /* the required config file exists */
+ ret_val = access_config (mode, section_name, key_name,
+ NULL,
+ cache_overrride_filename,
+ &internal_def);
+ if (!internal_def) {
+ if (def_used)
+ *def_used = FALSE;
+ return ret_val;
+ }
+ g_assert (ret_val == NULL);
+ }
+
+ /* fall through to the user config section */
+ filename = gnome_util_home_file (rel_file);
+ ret_val = access_config (mode, section_name, key_name, NULL,
+ filename, &internal_def);
+ g_free (filename);
+ if (!internal_def) {
+ if (def_used)
+ *def_used = FALSE;
+ return ret_val;
+ }
+ g_assert (ret_val == NULL);
+
+ /* fall through to the system wide config default tree */
+ if (cache_global_filename) {
+ /* the file exists */
+ ret_val = access_config (mode, section_name, key_name,
+ def,
+ cache_global_filename,
+ def_used);
+ return ret_val;
+ } else {
+ /* it doesn't -- use the default value */
+ if (def_used)
+ *def_used = TRUE;
+ return def;
+ }
+ }
+ g_assert_not_reached ();
+
+ /* keep the compiler happy */
+ if (def_used)
+ *def_used = TRUE;
+ return def;
+}
+
+static void
+dump_keys (FILE *profile, TKeys *p)
+{
+ if (!p)
+ return;
+ dump_keys (profile, p->link);
+ if (*p->key_name) {
+ char *t = escape_string_and_dup (p->value);
+ fprintf (profile, "%s=%s\n", p->key_name, t);
+ g_free (t);
+ }
+}
+
+static void
+dump_sections (FILE *profile, TSecHeader *p)
+{
+ if (!p)
+ return;
+ dump_sections (profile, p->link);
+ if (p->section_name && p->section_name [0]){
+ fprintf (profile, "\n[%s]\n", p->section_name);
+ dump_keys (profile, p->keys);
+ }
+}
+
+/*check the path and if we need to create directories create them with
+ mode newmode, it needs an absolute path name or it will fail, it
+ needs to be passed the dir and the filename since it will take the
+ filename off*/
+static gint
+check_path(char *path, mode_t newmode)
+{
+ gchar *dirpath;
+ gchar *p;
+ GString *newpath;
+ struct stat s;
+ char *tokp;
+
+ g_return_val_if_fail (path != NULL, FALSE);
+
+ if(strchr(path,'/')==NULL)
+ return FALSE;
+
+ dirpath = strcpy (alloca (strlen (path) + 1), path);
+ g_return_val_if_fail (dirpath != NULL, FALSE);
+
+ if (*dirpath == '\0')
+ return FALSE;
+
+ /*not absolute, we refuse to work*/
+ if (dirpath[0] != '/')
+ return FALSE;
+
+ p = strrchr(dirpath,'/');
+ *p='\0';
+
+ /*special case if directory exists, this is probably gonna happen
+ a lot so we don't want to go though checking it part by part*/
+ if (stat(dirpath, &s) == 0) {
+ /*check if a directory*/
+ if (!S_ISDIR(s.st_mode))
+ return FALSE;
+ else
+ return TRUE;
+ }
+
+
+ /*skip leading '/'*/
+ p = dirpath;
+ while(*p == '/')
+ p++;
+
+ p = strtok_r(p, "/", &tokp);
+ newpath = g_string_new("");
+ do {
+ newpath = g_string_append_c(newpath,'/');
+ newpath = g_string_append(newpath,p);
+ if(stat(newpath->str,&s)==0) {
+ /*check if a directory*/
+ if(!S_ISDIR(s.st_mode)) {
+ g_string_free(newpath,TRUE);
+ return FALSE;
+ }
+ } else {
+ /*we couldn't stat it .. let's try making the
+ directory*/
+ if(mkdir(newpath->str,newmode)!=0) {
+ /*error, return false*/
+ g_string_free(newpath,TRUE);
+ return FALSE;
+ }
+ }
+
+ } while ((p = strtok_r(NULL, "/", &tokp)) != NULL);
+
+ g_string_free(newpath,TRUE);
+
+ return TRUE;
+}
+
+
+
+static gboolean
+dump_profile (TProfile *p, gboolean one_only)
+{
+ gboolean ret = TRUE;
+ FILE *profile;
+
+ if (!p)
+ return ret;
+ if(!one_only) {
+ if(!dump_profile (p->link, FALSE))
+ ret = FALSE;
+ }
+
+ /*
+ * was this profile written to?, if not it's not necessary to dump
+ * it to disk
+ */
+ if (!p->to_be_deleted && !p->written_to)
+ return ret;
+
+ /* .ado: p->filename can be empty, it's better to jump over */
+ if (p->filename[0] != '\0') {
+
+ /*
+ * this file was added to after it was cleaned so it doesn't
+ * want to be deleted
+ */
+ if(p->to_be_deleted && p->section)
+ p->to_be_deleted = FALSE;
+ if(p->to_be_deleted) {
+ /*remove the file and remove all it's ramaints
+ from memory*/
+ unlink(p->filename);
+ /* this already must have been true */
+ /*p->section = 0;*/
+ p->filename [0] = '\0';
+ p->written_to = TRUE;
+ p->to_be_deleted = FALSE;
+ if(p==Current)
+ Current = NULL;
+ } else if (check_path(p->filename,0755) &&
+ (profile = fopen (p->filename, "w")) != NULL){
+ dump_sections (profile, p->section);
+ fclose (profile);
+ } else {
+ /* we failed at actually writing to the file */
+ ret = FALSE;
+ }
+ }
+
+ /*mark this to not be dumped any more*/
+ p->written_to = FALSE;
+
+ return ret;
+}
+
+/**
+ * gnome_config_sync:
+ *
+ * Writes all of the information modified by gnome-config to the
+ * disk.
+ *
+ * Note: the gnome_config code does not write anything to the
+ * configuration files until this routine is actually invoked.
+ *
+ * Returns: %TRUE if everything went well. %FALSE if any file
+ * could not be written to disk.
+ */
+gboolean
+gnome_config_sync (void)
+{
+ gboolean ret;
+ ret = dump_profile (Base, FALSE);
+ gnome_config_drop_all();
+ return ret;
+}
+
+/**
+ * gnome_config_sync_file:
+ * @path: A gnome-config path
+ *
+ * Writes all of the information modified by gnome-config to the
+ * disk for the given file.
+ *
+ * Note: the gnome_config code does not write anything to the
+ * configuration files until this routine or gnome_config_sync
+ * is actually invoked.
+ */
+/**
+ * gnome_config_private_sync_file:
+ * @path: A gnome-config path
+ *
+ * Writes all of the information modified by gnome-config to the
+ * disk for the given private file.
+ *
+ * Note: the gnome_config code does not write anything to the
+ * configuration files until this routine or gnome_config_sync
+ * is actually invoked.
+ *
+ * Returns: %TRUE if everything went well, %FALSE if the file
+ * could not be written to for some reason. %FALSE is only returned
+ * when a write was actually attempted and failed.
+ */
+gboolean
+_gnome_config_sync_file (char *path, gboolean priv)
+{
+ gboolean ret = TRUE;
+ TProfile *p;
+ ParsedPath *pp;
+ char *fake_path;
+
+ if (!path)
+ return ret;
+
+ fake_path = g_concat_dir_and_file (path, "section/key");
+ pp = parse_path (fake_path, priv);
+ g_free (fake_path);
+
+ for (p = Base; p; p = p->link){
+ if (strcmp (pp->file, p->filename) != 0)
+ continue;
+ if(!p->written_to)
+ break;
+ if(!dump_profile (p, TRUE))
+ ret = FALSE;
+ gnome_config_drop_file(path);
+ break;
+ }
+ release_path (pp);
+
+ return ret;
+}
+
+/**
+ * gnome_config_clean_file:
+ * @path: A gnome-config path
+ *
+ * Cleans up the configuration file specified by @path from any
+ * configuration information.
+ *
+ * Changes will take place after #gnome_config_sync has been invoked.
+ */
+/**
+ * gnome_config_private_clean_file:
+ * @path: A gnome-config path
+ *
+ * Cleans up the private configuration file specified by @path from
+ * any configuration information.
+ *
+ * Changes will take place after #gnome_config_sync has been invoked.
+ */
+void
+_gnome_config_clean_file (const char *path, gboolean priv)
+{
+ TProfile *p;
+ ParsedPath *pp;
+ char *fake_path;
+
+ if (!path)
+ return;
+
+ fake_path = g_concat_dir_and_file (path, "section/key");
+ pp = parse_path (fake_path, priv);
+ g_free (fake_path);
+
+ Current = NULL;
+
+ for (p = Base; p; p = p->link){
+ if (strcmp (pp->file, p->filename) != 0)
+ continue;
+
+ free_sections (p->section);
+ p->section = NULL;
+ p->written_to = TRUE;
+ p->to_be_deleted = TRUE;
+ release_path (pp);
+ return;
+ }
+ release_path (pp);
+}
+
+/**
+ * gnome_config_drop_file:
+ * @path: A gnome-config path
+ *
+ * Releases any memory resources that were allocated from accessing
+ * the configuration file in @path. Changes will take place after
+ * #gnome_config_sync has been invoked
+ */
+/**
+ * gnome_config_private_drop_file:
+ * @path: A gnome-config path
+ *
+ * Releases any memory resources that were allocated from accessing the
+ * private configuration file in @path.
+ */
+void
+_gnome_config_drop_file (const char *path, gboolean priv)
+{
+ TProfile *p;
+ TProfile *last;
+ ParsedPath *pp;
+ char *fake_path;
+
+ if (!path)
+ return;
+
+ fake_path = g_concat_dir_and_file (path, "section/key");
+ pp = parse_path (fake_path, priv);
+ g_free (fake_path);
+
+ Current = NULL;
+
+ for (last = NULL,p = Base; p; last = p, p = p->link){
+ if (strcmp (pp->file, p->filename) != 0)
+ continue;
+
+ if(last)
+ last->link = p->link;
+ else
+ Base = p->link;
+
+ free_sections (p->section);
+ g_free(p->filename);
+ g_free(p);
+ release_path (pp);
+ return;
+ }
+ release_path (pp);
+}
+
+/**
+ * gnome_config_init_iterator:
+ * @path: A gnome configuration path for a section.
+ *
+ * Creates an iterator handle that can be used to
+ * iterate over the keys in a section in a gnome configuration
+ * file. @path must refer to a section. The returned value
+ * can be used as an iterator for #gnome_config_iterator_next().
+ *
+ * Returns the iterator handle.
+ */
+/**
+ * gnome_config_private_init_iterator:
+ * @path: A gnome configuration path for a section.
+ *
+ * Creates an iterator handle that can be used to
+ * iterate over the keys in a section in a private gnome configuration
+ * file. @path must refer to a section. The returned value
+ * can be used as an iterator for #gnome_config_iterator_next().
+ *
+ * Returns the iterator handle.
+ */
+void *
+_gnome_config_init_iterator (const char *path, gboolean priv)
+{
+ TProfile *New;
+ TSecHeader *section;
+ ParsedPath *pp;
+ char *fake_path;
+ iterator_type *iter;
+
+
+ fake_path = g_concat_dir_and_file (path, "key");
+ pp = parse_path (fake_path, priv);
+ g_free (fake_path);
+
+ if (!is_loaded (pp->file, §ion)){
+ struct stat st;
+
+ if (stat (pp->file, &st) == -1){
+ st.st_mtime = 0;
+ }
+
+ New = (TProfile *) g_malloc (sizeof (TProfile));
+ New->link = Base;
+ New->filename = g_strdup (pp->file);
+ New->section = load (pp->file);
+ New->mtime = st.st_mtime;
+ New->last_checked = time (NULL);
+ New->written_to = FALSE;
+ New->to_be_deleted = FALSE;
+ Base = New;
+ section = New->section;
+ Current = New;
+ }
+ for (; section; section = section->link){
+ if (strcasecmp (section->section_name, pp->section))
+ continue;
+ iter = g_new (iterator_type, 1);
+ iter->type = 0;
+ iter->value = section->keys;
+ release_path (pp);
+ return iter;
+ }
+ release_path (pp);
+ return 0;
+}
+
+
+/**
+ * gnome_config_init_iterator_sections:
+ * @path: A gnome configuration path for a file.
+ *
+ * Creates an iterator handle that can be used to iterate over the
+ * sections in a gnome configuration file. @path must refer to a
+ * gnome configuration file. The returned value can be used as an
+ * iterator for #gnome_config_iterator_next().
+ *
+ * Returns the iterator handle.
+ */
+/**
+ * gnome_config_private_init_iterator_sections:
+ * @path: A gnome configuration path for a file
+ *
+ * Creates an iterator handle that can be used to iterate over the
+ * sections in a private gnome configuration file. @path must refer to a
+ * gnome configuration file. The returned value can be used as an
+ * iterator for #gnome_config_iterator_next().
+ *
+ * Returns the iterator handle.
+ */
+void *
+_gnome_config_init_iterator_sections (const char *path, gboolean priv)
+{
+ TProfile *New;
+ TSecHeader *section;
+ ParsedPath *pp;
+ char *fake_path;
+ iterator_type *iter;
+
+
+ fake_path = g_concat_dir_and_file (path, "section/key");
+ pp = parse_path (fake_path, priv);
+ g_free (fake_path);
+
+ if (!is_loaded (pp->file, §ion)){
+ struct stat st;
+
+ if (stat (pp->file, &st) == -1)
+ st.st_mtime = 0;
+
+ New = (TProfile *) g_malloc (sizeof (TProfile));
+ New->link = Base;
+ New->filename = g_strdup (pp->file);
+ New->section = load (pp->file);
+ New->mtime = st.st_mtime;
+ New->last_checked = time (NULL);
+ New->written_to = FALSE;
+ New->to_be_deleted = FALSE;
+ Base = New;
+ section = New->section;
+ Current = New;
+ }
+ iter = g_new (iterator_type, 1);
+ iter->type = 1;
+ iter->value = section;
+ release_path (pp);
+ return iter;
+}
+
+/**
+ * gnome_config_iterator_next:
+ * @iterator_handle: A gnome configu iterator handle, returned from any
+ * iteration start routine or this routine.
+ * @key: Address where the key gets stored.
+ * @value: Address where the value gets stored.
+ *
+ *
+ * Returns a new iterator handle.
+ *
+ * If @key is non-NULL, then @key will point to a g_malloc()ed region that
+ * holds the key.
+ *
+ * If @value is non-NULL, then @value will point to a g_malloc()ed region that
+ * holds the key.
+ *
+ */
+void *
+gnome_config_iterator_next (void *iterator_handle, char **key, char **value)
+{
+ iterator_type *iter = iterator_handle;
+
+ /*
+ * g_return_if_fail is not appropriate since this is not
+ * really a failure, but passing in an "empty" iterator (we
+ * return NULL at times)
+ */
+ if(!iterator_handle)
+ return NULL;
+
+ if (key)
+ *key = NULL;
+ if (value)
+ *value = NULL;
+
+ if (iter->type == 0){
+ TKeys *keys;
+ keys = iter->value;
+ if (keys){
+ if (key)
+ *key = g_strdup (keys->key_name);
+ if (value)
+ *value = g_strdup (keys->value);
+ keys = keys->link;
+ iter->value = keys;
+ return iter;
+ } else {
+ g_free (iter);
+ return 0;
+ }
+ } else {
+ TSecHeader *section;
+ section = iter->value;
+
+ if (section){
+ if (key)
+ *key = g_strdup (section->section_name);
+ section = section->link;
+ iter->value = section;
+ return iter;
+ } else {
+ g_free (iter);
+ return 0;
+ }
+ }
+}
+
+/**
+ * gnome_config_clean_section:
+ * @path: a gnome configuration path to a section.
+ *
+ * Cleans up the section specified by @path from any
+ * configuration information. Changes will only take place
+ * after #gnome_config_sync has been invoked.
+ */
+/**
+ * gnome_config_private_clean_section:
+ * @path: a gnome configuration path to a section.
+ *
+ * Cleans up the section specified by @path in a private file from any
+ * configuration information. Changes will only take place after
+ * #gnome_config_sync has been invoked.
+ */
+void
+_gnome_config_clean_section (const char *path, gboolean priv)
+{
+ TProfile *New;
+ TSecHeader *section;
+ ParsedPath *pp;
+ char *fake_path;
+
+ fake_path = g_concat_dir_and_file (path, "key");
+ pp = parse_path (fake_path, priv);
+ g_free (fake_path);
+
+ if (!is_loaded (pp->file, §ion)){
+ struct stat st;
+
+ if (stat (pp->file, &st) == -1)
+ st.st_mtime = 0;
+
+ New = (TProfile *) g_malloc (sizeof (TProfile));
+ New->link = Base;
+ New->filename = g_strdup (pp->file);
+ New->section = load (pp->file);
+ New->mtime = st.st_mtime;
+ New->last_checked = time (NULL);
+ New->written_to = FALSE;
+ New->to_be_deleted = FALSE;
+ Base = New;
+ section = New->section;
+ Current = New;
+ }
+ /* We only disable the section, so it will still be g_freed, but it */
+ /* won't be found by further walks of the structure */
+
+ for (; section; section = section->link){
+ if (strcasecmp (section->section_name, pp->section))
+ continue;
+ section->section_name [0] = '\0';
+ Current->written_to = TRUE;
+ }
+ release_path (pp);
+}
+
+/**
+ * gnome_config_clean_key:
+ * @path: a gnome configuration path to a key.
+ *
+ * Removes the definition for the key on a gnome configuration file.
+ *
+ * Changes will take place after #gnome_config_sync has been invoked.
+ */
+/**
+ * gnome_config_private_clean_key:
+ * @path: a gnome configuration path to a key.
+ *
+ * Removes the definition for the key on a private gnome configuration
+ * file.
+ *
+ * Changes will take place after #gnome_config_sync has been invoked.
+ */
+void
+_gnome_config_clean_key (const char *path, gboolean priv)
+ /* *section_name, char *file */
+{
+ TProfile *New;
+ TSecHeader *section;
+ TKeys *key;
+ ParsedPath *pp;
+
+ pp = parse_path (path, priv);
+
+ if (!is_loaded (pp->file, §ion)){
+ struct stat st;
+
+ if (stat (pp->file, &st) == -1)
+ st.st_mtime = 0;
+
+ New = (TProfile *) g_malloc (sizeof (TProfile));
+ New->link = Base;
+ New->filename = g_strdup (pp->file);
+ New->section = load (pp->file);
+ New->mtime = st.st_mtime;
+ New->written_to = FALSE;
+ New->last_checked = time (NULL);
+ New->to_be_deleted = FALSE;
+ Base = New;
+ section = New->section;
+ Current = New;
+ }
+ for (; section; section = section->link){
+ if (strcasecmp (section->section_name, pp->section))
+ continue;
+ for (key = section->keys; key; key = key->link){
+ if (strcasecmp (key->key_name, pp->key))
+ continue;
+ key->key_name [0] = 0;
+ Current->written_to = TRUE;
+ }
+ }
+ release_path (pp);
+}
+
+/**
+ * gnome_config_has_section:
+ * @path: A gnome configuration path to a section
+ *
+ * Queries the gnome configuration file for the presence
+ * of the section specified in @path.
+ *
+ * Returns TRUE if the section exists. FALSE otherwise.
+ */
+/**
+ * gnome_config_private_has_section:
+ * @path: A gnome configuration path to a section
+ *
+ * Queries the private gnome configuration file for the presence
+ * of the section specified in @path.
+ *
+ * Returns TRUE if the section exists. FALSE otherwise.
+ */
+gboolean
+_gnome_config_has_section (const char *path, gboolean priv)
+ /* char *section_name, char *profile */
+{
+ TProfile *New;
+ TSecHeader *section;
+ ParsedPath *pp;
+ char *fake_path;
+
+ fake_path = g_concat_dir_and_file (path, "key");
+ pp = parse_path (fake_path,priv);
+ g_free (fake_path);
+
+ if (!is_loaded (pp->file, §ion)){
+ struct stat st;
+
+ if (stat (pp->file, &st) == -1)
+ st.st_mtime = 0;
+
+ New = (TProfile *) g_malloc (sizeof (TProfile));
+ New->link = Base;
+ New->filename = g_strdup (pp->file);
+ New->section = load (pp->file);
+ New->mtime = st.st_mtime;
+ New->written_to = FALSE;
+ New->last_checked = time (NULL);
+ New->to_be_deleted = FALSE;
+ Base = New;
+ section = New->section;
+ Current = New;
+ }
+ for (; section; section = section->link){
+ if (strcasecmp (section->section_name, pp->section))
+ continue;
+ release_path (pp);
+ return 1;
+ }
+ release_path (pp);
+ return 0;
+}
+
+/**
+ * gnome_config_drop_all:
+ *
+ * Drops any information cached in memory that was fetched with
+ * gnome config. Any pending information that has not been
+ * written to disk is discarded.
+ */
+void
+gnome_config_drop_all (void)
+{
+ free_profile (Base);
+ Base = NULL;
+ Current = NULL;
+}
+
+/**
+ * gnome_config_get_int:
+ * @path: A gnome configuration path to an item.
+ *
+ * Retrieves & returns the value of a configuration item as an integer.
+ */
+/**
+ * gnome_config_private_get_int:
+ * @path: A gnome configuration path to an item in the user-private namespace.
+ *
+ * Retrieves & returns the value of a configuration item as an integer.
+ * The item is retrieved from the user's private configuration storage area.
+ */
+/**
+ * gnome_config_get_int_with_default:
+ * @path: A gnome configuration path to an item.
+ * @def: A pointer to a flag that will be set if the default value for the item
+ * is returned.
+ *
+ * Retrieves & returns the value of a configuration item as an integer.
+ */
+/**
+ * gnome_config_private_get_int_with_default:
+ * @path: A gnome configuration path to an item in the user-private namespace.
+ * @def: A pointer to a flag that will be set if the default value for the item
+ * is returned.
+ *
+ * Retrieves & returns the value of a configuration item as an integer.
+ * The item is retrieved from the user's private configuration storage area.
+ */
+gint
+_gnome_config_get_int_with_default (const char *path, gboolean *def, gboolean priv)
+{
+ ParsedPath *pp;
+ const char *r;
+ int v;
+
+ pp = parse_path (path, priv);
+ /*is there a better way to check if an absolute path has been given?*/
+ if (!priv && pp->opath[0] != '=')
+ r = access_config_extended (LOOKUP, pp->section, pp->key,
+ pp->def, pp->path, def);
+ else
+ r = access_config (LOOKUP, pp->section, pp->key, pp->def,
+ pp->file, def);
+
+ /* It isn't an error if the key is not found. */
+ if (r == NULL) {
+ release_path (pp);
+ return 0;
+ }
+
+ v = atoi (r);
+ release_path (pp);
+ return v;
+}
+
+/**
+ * gnome_config_get_float:
+ * @path: A gnome configuration path to an item.
+ *
+ * Retrieves & returns the value of a configuration item as a floating-point
+ * number.
+ */
+/**
+ * gnome_config_private_get_float:
+ * @path: A gnome configuration path to an item in the user-private namespace.
+ *
+ * Retrieves & returns the value of a configuration item as a floating-point number.
+ * The item is retrieved from the user's private configuration storage area.
+ */
+/**
+ * gnome_config_get_float_with_default:
+ * @path: A gnome configuration path to an item.
+ * @def: A pointer to a flag that will be set if the default value for the item
+ * is returned.
+ *
+ * Retrieves & returns the value of a configuration item as a floating-point number.
+ */
+/**
+ * gnome_config_private_get_float_with_default:
+ * @path: A gnome configuration path to an item in the user-private namespace.
+ * @def: A pointer to a flag that will be set if the default value for the item
+ * is returned.
+ *
+ * Retrieves & returns the value of a configuration item as a floating-point number.
+ * The item is retrieved from the user's private configuration storage area.
+ */
+gdouble
+_gnome_config_get_float_with_default (const char *path, gboolean *def, gboolean priv)
+{
+ ParsedPath *pp;
+ const char *r;
+ gdouble v;
+
+ pp = parse_path (path, priv);
+ if (!priv && pp->opath[0] != '=')
+ r = access_config_extended (LOOKUP, pp->section, pp->key,
+ pp->def, pp->path, def);
+ else
+ r = access_config (LOOKUP, pp->section, pp->key, pp->def,
+ pp->file, def);
+
+ /* It isn't an error if the key is not found. */
+ if (r == NULL) {
+ release_path (pp);
+ return 0;
+ }
+
+ /* make sure we read values in a consistent manner */
+ gnome_i18n_push_c_numeric_locale ();
+ v = strtod(r, NULL);
+ gnome_i18n_pop_c_numeric_locale ();
+
+ release_path (pp);
+ return v;
+}
+
+/*
+ * same as _gnome_config_get_string_with_default, but using (ParsedPath *)
+ */
+static char *
+get_string_with_default_from_pp (ParsedPath *pp, gboolean *def, gboolean priv)
+{
+ const char *r;
+ char *ret = NULL;
+
+ if (!priv && pp->opath[0] != '=')
+ r = access_config_extended (LOOKUP, pp->section, pp->key,
+ pp->def, pp->path, def);
+ else
+ r = access_config (LOOKUP, pp->section, pp->key, pp->def,
+ pp->file, def);
+ if (r)
+ ret = g_strdup (r);
+ return ret;
+}
+
+/*
+ * like get_string_with_default_from_pp but with language
+ * This is because we must work on the parsed path to add the language
+ * thingie.
+ */
+static char *
+get_string_with_default_from_pp_with_lang (ParsedPath *pp,
+ const char *lang,
+ gboolean *def,
+ gboolean priv)
+{
+ char *value;
+ char *oldkey;
+
+ /* switch the key in the key from underneath it, then
+ * return it back */
+ oldkey = pp->key;
+ pp->key = g_strconcat (oldkey, "[", lang, "]", NULL);
+ value = get_string_with_default_from_pp (pp, def, priv);
+ g_free (pp->key);
+ pp->key = oldkey;
+
+ return value;
+}
+
+/**
+ * gnome_config_get_translated_string:
+ * @path: A gnome configuration path to an item.
+ *
+ * Retrieves & returns the value of a configuration item as a string
+ * appropriate for the current language. The returned value should be
+ * g_free()'d when no longer needed.
+ */
+/**
+ * gnome_config_private_get_translated_string:
+ * @path: A gnome configuration path to an item in the user-private namespace.
+ *
+ * Retrieves & returns the value of a configuration item as a string appropriate for the current language. The returned value should be
+ * g_free()'d when no longer needed.
+ * The item is retrieved from the user's private configuration storage area.
+ */
+/**
+ * gnome_config_get_translated_string_with_default:
+ * @path: A gnome configuration path to an item.
+ * @def: A pointer to a flag that will be set if the default value for the item
+ * is returned.
+ *
+ * Retrieves & returns the value of a configuration item as a string appropriate for the current language. The returned value should be
+ * g_free()'d when no longer needed.
+ */
+/**
+ * gnome_config_private_get_translated_string_with_default:
+ * @path: A gnome configuration path to an item in the user-private namespace.
+ * @def: A pointer to a flag that will be set if the default value for the item
+ * is returned.
+ *
+ * Retrieves & returns the value of a configuration item as a string appropriate for the current language. The returned value should be
+ * g_free()'d when no longer needed.
+ * The item is retrieved from the user's private configuration storage area.
+ */
+char *
+_gnome_config_get_translated_string_with_default (const char *path,
+ gboolean *def,
+ gboolean priv)
+{
+ ParsedPath *pp;
+ const GList *language_list;
+ gboolean local_def = FALSE;
+
+ char *value= NULL;
+
+ language_list = gnome_i18n_get_language_list ("LC_MESSAGES");
+
+ pp = parse_path (path, priv);
+
+ while (!value && language_list) {
+ const char *lang= language_list->data;
+
+ value = get_string_with_default_from_pp_with_lang
+ (pp, lang, &local_def, priv);
+
+ if (local_def || !value || *value == '\0') {
+ size_t n;
+
+ g_free (value);
+ value= NULL;
+
+ /* Sometimes the locale info looks
+ like `pt_PT verbose'. In this case
+ we want to try `pt' as a backup. */
+ n = strcspn (lang, "@_");
+ if (lang[n]) {
+ char *copy = g_strndup (lang, n);
+
+ value = get_string_with_default_from_pp_with_lang (pp, copy, &local_def, priv);
+ g_free (copy);
+ if (local_def || ! value || *value == '\0') {
+ g_free (value);
+ value = NULL;
+ }
+ }
+ }
+ language_list = language_list->next;
+ }
+
+ if (def != NULL) {
+ *def = local_def;
+ }
+
+ if (!value){
+ value = get_string_with_default_from_pp (pp, def, priv);
+
+ if (!value || *value == '\0'){
+ g_free (value);
+ value = NULL;
+ }
+ }
+
+ release_path (pp);
+
+ return value;
+}
+
+/**
+ * gnome_config_get_string:
+ * @path: A gnome configuration path to an item.
+ *
+ * Retrieves & returns the value of a configuration item as a string.
+ * The returned value should be
+ * g_free()'d when no longer needed.
+ */
+/**
+ * gnome_config_private_get_string:
+ * @path: A gnome configuration path to an item in the user-private namespace.
+ *
+ * Retrieves & returns the value of a configuration item as a
+ * string. The returned value should be g_free()'d when no longer
+ * needed. The item is retrieved from the user's private
+ * configuration storage area.
+ */
+/**
+ * gnome_config_get_string_with_default:
+ * @path: A gnome configuration path to an item.
+ * @def: A pointer to a flag that will be set if the default value for the item
+ * is returned.
+ *
+ * Retrieves & returns the value of a configuration item as a string.
+ * The returned value should be g_free()'d when no longer needed.
+ *
+ */
+/**
+ * gnome_config_private_get_string_with_default:
+ * @path: A gnome configuration path to an item in the user-private namespace.
+ * @def: A pointer to a flag that will be set if the default value for the item
+ * is returned.
+ *
+ * Retrieves & returns the value of a configuration item as a string.
+ * The returned value should be g_free()'d when no longer needed. The
+ * item is retrieved from the user's private configuration storage
+ * area.
+ *
+ */
+char *
+_gnome_config_get_string_with_default (const char *path, gboolean *def,
+ gboolean priv)
+{
+ ParsedPath *pp;
+ char *ret;
+
+ pp = parse_path (path, priv);
+ ret = get_string_with_default_from_pp (pp, def, priv);
+ release_path (pp);
+
+ return ret;
+}
+
+/**
+ * gnome_config_get_bool:
+ * @path: A gnome configuration path to an item.
+ *
+ * Retrieves & returns the value of a configuration item as a boolean.
+ */
+/**
+ * gnome_config_private_get_bool:
+ * @path: A gnome configuration path to an item in the user-private namespace.
+ *
+ * Retrieves & returns the value of a configuration item as a boolean.
+ * The item is retrieved from the user's private configuration storage area.
+ */
+/**
+ * gnome_config_get_bool_with_default:
+ * @path: A gnome configuration path to an item.
+ * @def: A pointer to a flag that will be set if the default value for the item
+ * is returned.
+ *
+ * Retrieves & returns the value of a configuration item as a boolean.
+ */
+/**
+ * gnome_config_private_get_bool_with_default:
+ * @path: A gnome configuration path to an item in the user-private namespace.
+ * @def: A pointer to a flag that will be set if the default value for the item
+ * is returned.
+ *
+ * Retrieves & returns the value of a configuration item as a boolean.
+ * The item is retrieved from the user's private configuration storage area.
+ */
+gboolean
+_gnome_config_get_bool_with_default (const char *path, gboolean *def,
+ gboolean priv)
+{
+ ParsedPath *pp;
+ const char *r;
+ int v;
+
+ pp = parse_path (path, priv);
+ if (!priv && pp->opath[0] != '=')
+ r = access_config_extended (LOOKUP, pp->section, pp->key,
+ pp->def, pp->path, def);
+ else
+ r = access_config (LOOKUP, pp->section, pp->key, pp->def,
+ pp->file, def);
+
+ /* It isn't an error if the key is not found. */
+ if (r == NULL) {
+ release_path (pp);
+ return 0;
+ }
+
+ if (tolower(*r) == 't' || tolower(*r) == 'y' || atoi(r)) {
+ v = 1;
+ } else {
+ /* If it's not true it has to be false :) */
+ v = 0;
+ }
+ release_path (pp);
+ return v;
+}
+
+/**
+ * gnome_config_make_vector:
+ * @string: The stringified vector to decode into 'argcp' and 'argvp'
+ * @argcp: Returns the number of elements in 'argvp'
+ * @argvp: Returns the array of strings found in 'rr'.
+ *
+ * Creates a new vector from a string as it stored in the config file,
+ * breaks the string on spaces except if the space is escaped with a
+ * backslash.
+ *
+ */
+void
+gnome_config_make_vector (const char *string, int *argcp, char ***argvp)
+{
+ char *p;
+ int count, esc_spcs;
+ int space_seen;
+
+ /* Figure out how large to make return vector. Start at 2
+ * because we want to make NULL-terminated array, and because
+ * the loop doesn't count the final element.
+ */
+ count = 2;
+ space_seen = 0;
+ for (p = (char *) string; *p; ++p) {
+ if (*p == '\\' && *(p+1)) {
+ ++p;
+ if (space_seen){
+ count++;
+ space_seen = 0;
+ }
+ } else if (*p == ' ') {
+ space_seen = 1;
+ } else if (space_seen){
+ count++;
+ space_seen = 0;
+ }
+ }
+
+ *argcp = count - 1;
+ *argvp = (char **) g_malloc0 (count * sizeof (char *));
+
+ p = (char *) string;
+ count = 0;
+ do {
+ char *s, *tmp = p;
+
+ esc_spcs = 0;
+ while (*p && (esc_spcs ? 1 : (*p != ' '))){
+ esc_spcs = 0;
+ if (*p == '\\')
+ esc_spcs = 1;
+ p++;
+ }
+
+ s = (char *) g_strndup (tmp, p - tmp);
+
+ (*argvp)[count++] = tmp = s;
+
+ while (*s) {
+ if (*s == '\\')
+ s++;
+ if (!*s) break;
+ *tmp++ = *s++;
+ }
+ *tmp = '\0';
+
+ while (*p && *p == ' ')
+ p++;
+ } while (*p);
+}
+
+/**
+ * gnome_config_get_vector:
+ * @path: A gnome configuration path to an item.
+ * @argcp: Number of elements in the vector
+ * @argvp: Vector of strings
+ *
+ * Retrieves & returns the value of a configuration item as a string array.
+ * The returned value should be
+ * g_free()'d when no longer needed.
+ */
+/**
+ * gnome_config_private_get_vector:
+ * @path: A gnome configuration path to an item in the user-private namespace.
+ * @argcp: Number of elements in the vector
+ * @argvp: Vector of strings
+ *
+ * Retrieves & returns the value of a configuration item as a
+ * string. The returned value should be g_free()'d when no longer
+ * needed. The item is retrieved from the user's private
+ * configuration storage area.
+ */
+/**
+ * gnome_config_get_vector_with_default:
+ * @path: A gnome configuration path to an item.
+ * @argcp: Number of elements in the vector
+ * @argvp: Vector of strings
+ * @def: A pointer to a flag that will be set if the default value for the item
+ * is returned.
+ *
+ * Retrieves & returns the value of a configuration item as a string array.
+ * The returned value should be g_free()'d when no longer needed.
+ *
+ */
+/**
+ * gnome_config_private_get_vector_with_default:
+ * @path: A gnome configuration path to an item in the user-private namespace.
+ * @argcp: Number of elements in the vector
+ * @argvp: Vector of strings
+ * @def: A pointer to a flag that will be set if the default value for the item
+ * is returned.
+ *
+ * Retrieves & returns the value of a configuration item as a string array.
+ * The returned value should be g_free()'d when no longer needed. The
+ * item is retrieved from the user's private configuration storage
+ * area.
+ *
+ */
+void
+_gnome_config_get_vector_with_default (const char *path, int *argcp,
+ char ***argvp, gboolean *def, gboolean priv)
+{
+ ParsedPath *pp;
+ const char *rr;
+
+ pp = parse_path (path, priv);
+ if (!priv && pp->opath[0] != '=')
+ rr = access_config_extended (LOOKUP, pp->section, pp->key,
+ pp->def, pp->path, def);
+ else
+ rr = access_config (LOOKUP, pp->section, pp->key, pp->def,
+ pp->file, def);
+
+ if (rr == NULL) {
+ *argvp = NULL;
+ *argcp = 0;
+ } else
+ gnome_config_make_vector (rr, argcp, argvp);
+ release_path (pp);
+}
+
+/**
+ * gnome_config_set_translated_string:
+ * @path: a gnome configuration path to a key
+ * @value: a string value to set.
+ *
+ * Stores the string value @new_value in the file/section/key defined
+ * by the @path on the proper section for the current language set by
+ * by the user.
+ */
+void
+_gnome_config_set_translated_string (const char *path, const char *value,
+ gboolean priv)
+{
+ const GList *language_list;
+ const char *lang;
+ char *tkey;
+
+ language_list = gnome_i18n_get_language_list("LC_MESSAGES");
+
+ lang= language_list ? language_list->data : NULL;
+
+ if (lang && (strcmp (lang, "C") != 0)) {
+ tkey = g_strconcat (path, "[", lang, "]", NULL);
+ _gnome_config_set_string(tkey, value, priv);
+ g_free (tkey);
+ } else
+ _gnome_config_set_string (path, value, priv);
+}
+
+/**
+ * gnome_config_set_string:
+ * @path: a gnome configuration path to a key
+ * @new_value: a string value to set.
+ *
+ * Stores the string value @new_value in the file/section/key
+ * defined by the @path
+ */
+void
+_gnome_config_set_string (const char *path, const char *new_value, gboolean priv)
+{
+ ParsedPath *pp;
+ const char *r;
+
+ pp = parse_path (path, priv);
+ r = access_config (SET, pp->section, pp->key, new_value, pp->file,
+ NULL);
+ release_path (pp);
+}
+
+/**
+ * gnome_config_set_int:
+ * @path: a gnome configuration path to a key
+ * @new_value: a int value to set.
+ *
+ * Stores the integer value @new_value in the file/section/key
+ * defined by the @path
+ */
+void
+_gnome_config_set_int (const char *path, int new_value, gboolean priv)
+{
+ ParsedPath *pp;
+ char intbuf [40];
+ const char *r;
+
+ pp = parse_path (path, priv);
+ g_snprintf (intbuf, sizeof(intbuf), "%d", new_value);
+ r = access_config (SET, pp->section, pp->key, intbuf, pp->file,
+ NULL);
+ release_path (pp);
+}
+
+/**
+ * gnome_config_set_float:
+ * @path: a gnome configuration path to a key
+ * @new_value: a double value to set.
+ *
+ * Stores the double value @new_value in the file/section/key
+ * defined by the @path
+ */
+void
+_gnome_config_set_float (const char *path, gdouble new_value, gboolean priv)
+{
+ ParsedPath *pp;
+ char floatbuf [40];
+ const char *r;
+
+ pp = parse_path (path, priv);
+
+ /* make sure we write values in a consistent manner */
+ gnome_i18n_push_c_numeric_locale ();
+ g_snprintf (floatbuf, sizeof(floatbuf), "%.17g", new_value);
+ gnome_i18n_pop_c_numeric_locale ();
+
+ r = access_config (SET, pp->section, pp->key, floatbuf, pp->file,
+ NULL);
+ release_path (pp);
+}
+
+/**
+ * gnome_config_set_bool:
+ * @path: a gnome configuration path to a key
+ * @new_value: a boolean value to set
+ *
+ * Stores boolean value @new_value in the file/section/key defined by
+ * @path.
+ */
+void
+_gnome_config_set_bool (const char *path, gboolean new_value, gboolean priv)
+{
+ ParsedPath *pp;
+ const char *r;
+
+ pp = parse_path (path, priv);
+ r = access_config (SET, pp->section, pp->key,
+ new_value ? "true" : "false", pp->file, NULL);
+ release_path (pp);
+}
+
+/**
+ * gnome_config_assemble_vector:
+ * @argc: Number of elements in the @argv string array.
+ * @argv: An array of strings.
+ *
+ * This routine returns the the strings in the array contactenated by
+ * spaces.
+ *
+ * Returns: a g_malloc()ed string with the concatenation results.
+ */
+char *
+gnome_config_assemble_vector (int argc, const char *const argv [])
+{
+ char *value, *p;
+ const char *s;
+ int i;
+ size_t len;
+
+ /*
+ * Compute length of quoted string. We cheat and just use
+ * twice the sum of the lengths of all the strings.
+ */
+ len = 1;
+ for (i = 0; i < argc; ++i)
+ len += 2 * strlen (argv [i]) + 1 + argc;
+
+ p = value = g_malloc (len);
+ for (i = 0; i < argc; ++i) {
+ for (s = argv [i]; *s; ++s) {
+ if (*s == ' ' || *s == '\\')
+ *p++ = '\\';
+ *p++ = *s;
+ }
+ *p++ = ' ';
+ }
+ *p = '\0';
+
+ return value;
+}
+
+/**
+ * gnome_config_set_vector:
+ * @path: a gnome configuration path to a key
+ * @argc: the number of elements in @argv
+ * @argv: a string array holding the data to store.
+ *
+ * Stores vector @argv in the file/section/key defined by
+ * @path.
+ */
+void
+_gnome_config_set_vector (const char *path, int argc,
+ const char *const argv[],
+ gboolean priv)
+{
+ ParsedPath *pp;
+ char *s;
+
+ pp = parse_path (path, priv);
+ s = gnome_config_assemble_vector (argc, argv);
+ access_config (SET, pp->section, pp->key, s, pp->file, NULL);
+ g_free (s);
+ release_path (pp);
+}
+
+/**
+ * gnome_config_push_prefix:
+ * @path: a gnome configuration path prefix
+ *
+ * @path is a prefix that will be prepended automatically to any
+ * non-absolute configuration path in gnome config.
+ *
+ * This is used to simplify application loading code.
+ *
+ * Library code will usually have to set the prefix before doing
+ * any gnome-configuration access, since the application might
+ * be using their own prefix.
+ */
+void
+gnome_config_push_prefix (const char *path)
+{
+ prefix_list = g_slist_prepend(prefix_list, g_strdup(path));
+}
+
+/**
+ * gnome_config_pop_prefix:
+ *
+ * Call this routine to remove the current configuration prefix from the stack.
+ */
+void
+gnome_config_pop_prefix (void)
+{
+ if(prefix_list) {
+ GSList *plist = prefix_list;
+ g_free(prefix_list->data);
+ prefix_list = prefix_list->next;
+ g_slist_free_1(plist);
+ }
+}
+
+/**
+ * gnome_config_set_set_handler
+ * @func: Obsolete
+ * @data: Obsolete
+ *
+ * Internal Obsolete.
+ */
+void
+gnome_config_set_set_handler(void (*func)(void *),void *data)
+{
+ g_warning("gnome_config_set_set_handler is obscolete and has no replacement");
+}
+
+/**
+ * gnome_config_set_sync_handler
+ * @func: obsolete
+ * @data: obsolete
+ *
+ * Internal routine
+ */
+void
+gnome_config_set_sync_handler(void (*func)(void *),void *data)
+{
+ g_warning("gnome_config_set_sync_handler is obscolete and has no replacement");
+}
+
+#ifdef TEST
+
+static
+x (char *str, char *file, char *sec, char *key, char *val)
+{
+ ParsedPath *pp;
+
+ printf ("%s\n", str);
+ pp = parse_path (str, FALSE);
+ printf (" file: %s [%s]\n", pp->file, file);
+ printf (" sect: %s [%s]\n", pp->section, sec);
+ printf (" key: %s [%s]\n", pp->key, key);
+ printf (" def: %s [%s]\n", pp->def, val);
+}
+
+
+main ()
+{
+ gnome_user_dir = "USERDIR";
+ x ("=/tmp/file=seccion/llave=valor", "/tmp/file", "seccion", "llave", "valor");
+ x ("=/tmp/file=seccion/llave", "/tmp/file", "seccion", "llave", NULL);
+ x ("/file/seccion/llave=valor", "USERDIR/file", "seccion", "llave", "valor");
+ x ("/file/seccion/llave", "USERDIR/file", "seccion", "llave", NULL);
+ x ("/file/archivo/archivo/seccion/llave", "USERDIR/file/archivo/archivo", "seccion", "llave", NULL);
+ x ("/file/archivo/archivo/seccion/llave=valor", "USERDIR/file/archivo/archivo", "seccion", "llave", "valor");
+
+}
+#endif
diff --git a/libgnome/gnome-config.h b/libgnome/gnome-config.h
new file mode 100644
index 0000000..443eb5d
--- /dev/null
+++ b/libgnome/gnome-config.h
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 1993, 1994, 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+
+#ifndef GNOME_CONFIG_H
+#define GNOME_CONFIG_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+/* Prototypes for the profile management functions */
+
+/*
+ * DOC: gnome configuration routines.
+ *
+ * All of the routines receive a pathname, the pathname has the following
+ * form:
+ *
+ * /filename/section/key[=default]
+ *
+ * This format reprensents: a filename relative to the Gnome config
+ * directory called filename (ie, ~/.gnome/filename), in that file there
+ * is a section called [section] and key is the left handed side of the
+ * values.
+ *
+ * If default is provided, it cane be used to return a default value
+ * if none is specified on the config file.
+ *
+ * Examples:
+ *
+ * /gmix/Balance/Ratio=0.5
+ * /filemanager/Panel Display/html=1
+ *
+ * If the pathname starts with '=', then instead of being a ~/.gnome relative
+ * file, it is an abolute pathname, example:
+ *
+ * =/home/miguel/.mc.ini=/Left Panel/reverse=1
+ *
+ * This reprensents the config file: /home/miguel/.mc.ini, section [Left Panel],
+ * variable reverse.
+ */
+
+/* These functions look for the config option named in PATH. If the
+ option does not exist, and a default is specified in PATH, then the
+ default will be returned. In all cases, *DEF is set to 1 if the
+ default was return, 0 otherwise. If DEF is NULL then it will not
+ be set. */
+
+/*use the wrappers below*/
+char *_gnome_config_get_string_with_default (const char *path,
+ gboolean *def,
+ gboolean priv);
+char *_gnome_config_get_translated_string_with_default(const char *path,
+ gboolean *def,
+ gboolean priv);
+gint _gnome_config_get_int_with_default (const char *path,
+ gboolean *def,
+ gboolean priv);
+gdouble _gnome_config_get_float_with_default (const char *path,
+ gboolean *def,
+ gboolean priv);
+gboolean _gnome_config_get_bool_with_default (const char *path,
+ gboolean *def,
+ gboolean priv);
+void _gnome_config_get_vector_with_default (const char *path, gint *argcp,
+ char ***argvp,
+ gboolean *def,
+ gboolean priv);
+
+/*these just call the above functions, but devide them into two groups,
+ in the future these may be different functions, so use these defines*/
+/*normal functions*/
+#define gnome_config_get_string_with_default(path,def) \
+ (_gnome_config_get_string_with_default((path),(def),FALSE))
+#define gnome_config_get_translated_string_with_default(path,def) \
+ (_gnome_config_get_translated_string_with_default((path),(def),FALSE))
+#define gnome_config_get_int_with_default(path,def) \
+ (_gnome_config_get_int_with_default((path),(def),FALSE))
+#define gnome_config_get_float_with_default(path,def) \
+ (_gnome_config_get_float_with_default((path),(def),FALSE))
+#define gnome_config_get_bool_with_default(path,def) \
+ (_gnome_config_get_bool_with_default((path),(def),FALSE))
+#define gnome_config_get_vector_with_default(path, argcp, argvp, def) \
+ (_gnome_config_get_vector_with_default ((path),(argcp),(argvp), \
+ (def),FALSE))
+
+/*private functions*/
+#define gnome_config_private_get_string_with_default(path,def) \
+ (_gnome_config_get_string_with_default((path),(def),TRUE))
+#define gnome_config_private_get_translated_string_with_default(path,def) \
+ (_gnome_config_get_translated_string_with_default((path), (def),TRUE))
+#define gnome_config_private_get_int_with_default(path,def) \
+ (_gnome_config_get_int_with_default((path),(def),TRUE))
+#define gnome_config_private_get_float_with_default(path,def) \
+ (_gnome_config_get_int_with_default((path),(def),TRUE))
+#define gnome_config_private_get_bool_with_default(path,def) \
+ (_gnome_config_get_bool_with_default((path),(def),TRUE))
+#define gnome_config_private_get_vector_with_default(path, argcp, argvp, def) \
+ (_gnome_config_get_vector_with_default ((path),(argcp), (argvp), \
+ (def), TRUE))
+
+/* Convenience wrappers for the case when you don't care if you see
+ the default. */
+/*normal functions*/
+#define gnome_config_get_string(path) \
+ (_gnome_config_get_string_with_default ((path), NULL, FALSE))
+#define gnome_config_get_translated_string(path) \
+ (_gnome_config_get_translated_string_with_default ((path), NULL, FALSE))
+#define gnome_config_get_int(path) \
+ (_gnome_config_get_int_with_default ((path), NULL, FALSE))
+#define gnome_config_get_float(path) \
+ (_gnome_config_get_float_with_default ((path), NULL, FALSE))
+#define gnome_config_get_bool(path) \
+ (_gnome_config_get_bool_with_default ((path), NULL, FALSE))
+#define gnome_config_get_vector(path, argcp, argvp) \
+ (_gnome_config_get_vector_with_default ((path), (argcp), (argvp), \
+ NULL, FALSE))
+
+/*private functions*/
+#define gnome_config_private_get_string(path) \
+ (_gnome_config_get_string_with_default ((path), NULL, TRUE))
+#define gnome_config_private_get_translated_string(path) \
+ (_gnome_config_get_translated_string_with_default ((path), NULL, TRUE))
+#define gnome_config_private_get_int(path) \
+ (_gnome_config_get_int_with_default ((path), NULL, TRUE))
+#define gnome_config_private_get_float(path) \
+ (_gnome_config_get_float_with_default ((path), NULL, TRUE))
+#define gnome_config_private_get_bool(path) \
+ (_gnome_config_get_bool_with_default ((path), NULL, TRUE))
+#define gnome_config_private_get_vector(path, argcp, argvp) \
+ (_gnome_config_get_vector_with_default ((path), (argcp), (argvp), \
+ NULL, TRUE))
+
+/* Set a config variable. Use the warppers below*/
+void _gnome_config_set_string (const char *path, const char *value,
+ gboolean priv);
+void _gnome_config_set_translated_string (const char *path, const char *value,
+ gboolean priv);
+void _gnome_config_set_int (const char *path, int value,
+ gboolean priv);
+void _gnome_config_set_float (const char *path, gdouble value,
+ gboolean priv);
+void _gnome_config_set_bool (const char *path, gboolean value,
+ gboolean priv);
+void _gnome_config_set_vector (const char *path,
+ int argc,
+ const char * const argv[],
+ gboolean priv);
+
+
+/* normal functions */
+#define gnome_config_set_string(path,new_value) \
+ (_gnome_config_set_string((path),(new_value),FALSE))
+#define gnome_config_set_translated_string(path,value) \
+ (_gnome_config_set_translated_string((path),(value),FALSE))
+#define gnome_config_set_int(path,new_value) \
+ (_gnome_config_set_int((path),(new_value),FALSE))
+#define gnome_config_set_float(path,new_value) \
+ (_gnome_config_set_float((path),(new_value),FALSE))
+#define gnome_config_set_bool(path,new_value) \
+ (_gnome_config_set_bool((path),(new_value),FALSE))
+#define gnome_config_set_vector(path,argc,argv) \
+ (_gnome_config_set_vector((path),(argc),(argv),FALSE))
+
+/* private functions */
+#define gnome_config_private_set_string(path,new_value) \
+ (_gnome_config_set_string((path),(new_value),TRUE))
+#define gnome_config_private_set_translated_string(path,new_value) \
+ (_gnome_config_set_translated_string((path),(new_value),TRUE))
+#define gnome_config_private_set_int(path,new_value) \
+ (_gnome_config_set_int((path),(new_value),TRUE))
+#define gnome_config_private_set_float(path,new_value) \
+ (_gnome_config_set_float((path),(new_value),TRUE))
+#define gnome_config_private_set_bool(path,new_value) \
+ (_gnome_config_set_bool((path),(new_value),TRUE))
+#define gnome_config_private_set_vector(path,argc,argv) \
+ (_gnome_config_set_vector((path),(argc),(argv),TRUE))
+
+/* Returns true if /path/section is defined */
+gboolean _gnome_config_has_section (const char *path, gboolean priv);
+#define gnome_config_has_section(path) \
+ (_gnome_config_has_section((path),FALSE))
+#define gnome_config_private_has_section(path) \
+ (_gnome_config_has_section((path),TRUE))
+
+/* Returns a pointer for iterating on /file/section contents */
+void *_gnome_config_init_iterator (const char *path, gboolean priv);
+#define gnome_config_init_iterator(path) \
+ (_gnome_config_init_iterator((path),FALSE))
+#define gnome_config_private_init_iterator(path) \
+ (_gnome_config_init_iterator((path),TRUE))
+
+/* Returns a pointer for iterating on /file contents */
+void *_gnome_config_init_iterator_sections (const char *path, gboolean priv);
+#define gnome_config_init_iterator_sections(path) \
+ (_gnome_config_init_iterator_sections((path),FALSE))
+#define gnome_config_private_init_iterator_sections(path) \
+ (_gnome_config_init_iterator_sections((path),TRUE))
+
+/* Get next key and value value from a section */
+void *gnome_config_iterator_next (void *iterator_handle, char **key, char **value);
+
+void gnome_config_drop_all (void);
+
+gboolean gnome_config_sync (void);
+
+/* sync's data for one file only */
+gboolean _gnome_config_sync_file (char *path, gboolean priv);
+#define gnome_config_sync_file(path) \
+ (_gnome_config_sync_file((path),FALSE))
+#define gnome_config_private_sync_file(path) \
+ (_gnome_config_sync_file((path),TRUE))
+
+/* This routine drops the information about /file, meaning changes
+ done to this file will be dropped, it will no delete the file */
+void _gnome_config_drop_file (const char *path, gboolean priv);
+#define gnome_config_drop_file(path) \
+ (_gnome_config_drop_file((path),FALSE))
+#define gnome_config_private_drop_file(path) \
+ (_gnome_config_drop_file((path),TRUE))
+
+/* This routine actually removes /file on sync (not right away, you
+ can still save it by dropping it)*/
+void _gnome_config_clean_file (const char *path, gboolean priv);
+#define gnome_config_clean_file(path) \
+ (_gnome_config_clean_file((path),FALSE))
+#define gnome_config_private_clean_file(path) \
+ (_gnome_config_clean_file((path),TRUE))
+
+/* This routine drops all of the information related to /file/section
+ this will actually remove the section */
+void _gnome_config_clean_section (const char *path, gboolean priv);
+#define gnome_config_clean_section(path) \
+ (_gnome_config_clean_section((path),FALSE))
+#define gnome_config_private_clean_section(path) \
+ (_gnome_config_clean_section((path),TRUE))
+
+/* Drops the information for a specific key, this will actually remove
+ the key */
+void _gnome_config_clean_key (const char *path, gboolean priv);
+#define gnome_config_clean_key(path) \
+ (_gnome_config_clean_key((path),FALSE))
+#define gnome_config_private_clean_key(path) \
+ (_gnome_config_clean_key((path),TRUE))
+
+/* returns the true filename of the config file */
+#define gnome_config_get_real_path(path) \
+ (g_concat_dir_and_file (gnome_user_dir,(path)))
+#define gnome_config_private_get_real_path(path) \
+ (g_concat_dir_and_file (gnome_user_private_dir,(path)))
+
+/* Set an active prefix and remove an active prefix */
+void gnome_config_push_prefix (const char *path);
+void gnome_config_pop_prefix (void);
+
+/*
+ * Internal routines that we export
+ * Used to go from string->vector and from vector->string
+ */
+void gnome_config_make_vector (const char *string, int *argcp, char ***argvp);
+char *gnome_config_assemble_vector (int argc, const char *const argv []);
+
+/* these two are absolutely obscolete and should not be used */
+void gnome_config_set_set_handler(void (*func)(void *),void *data);
+void gnome_config_set_sync_handler(void (*func)(void *),void *data);
+
+G_END_DECLS
+
+#endif
diff --git a/libgnome/gnome-exec.c b/libgnome/gnome-exec.c
index 93d73dd..85207fc 100644
--- a/libgnome/gnome-exec.c
+++ b/libgnome/gnome-exec.c
@@ -25,6 +25,8 @@
# include <config.h>
#endif
+#include "gnome-i18nP.h"
+
#include <libgnome/gnome-exec.h>
#include <libgnome/gnome-util.h>
#include <libgnome/gnome-i18n.h>
diff --git a/libgnome/gnome-i18n.c b/libgnome/gnome-i18n.c
new file mode 100644
index 0000000..8abad02
--- /dev/null
+++ b/libgnome/gnome-i18n.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+
+#include <config.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "gnome-i18nP.h"
+
+static GHashTable *alias_table = NULL;
+
+/*read an alias file for the locales*/
+static void
+read_aliases (char *file)
+{
+ FILE *fp;
+ char buf[256];
+ if (!alias_table)
+ alias_table = g_hash_table_new (g_str_hash, g_str_equal);
+ fp = fopen (file,"r");
+ if (!fp)
+ return;
+ while (fgets (buf,256,fp))
+ {
+ char *p;
+ g_strstrip(buf);
+ if (buf[0]=='#' || buf[0]=='\0')
+ continue;
+ p = strtok (buf,"\t ");
+ if (!p)
+ continue;
+ p = strtok (NULL,"\t ");
+ if(!p)
+ continue;
+ if (!g_hash_table_lookup (alias_table, buf))
+ g_hash_table_insert (alias_table, g_strdup(buf), g_strdup(p));
+ }
+ fclose (fp);
+}
+
+/*return the un-aliased language as a newly allocated string*/
+static char *
+unalias_lang (char *lang)
+{
+ char *p;
+ int i;
+ if (!alias_table)
+ {
+ read_aliases ("/usr/share/locale/locale.alias");
+ read_aliases ("/usr/local/share/locale/locale.alias");
+ read_aliases ("/usr/lib/X11/locale/locale.alias");
+ read_aliases ("/usr/openwin/lib/locale/locale.alias");
+ }
+ i = 0;
+ while ((p=g_hash_table_lookup(alias_table,lang)) && strcmp(p, lang))
+ {
+ lang = p;
+ if (i++ == 30)
+ {
+ static gboolean said_before = FALSE;
+ if (!said_before)
+ g_warning (_("Too many alias levels for a locale, "
+ "may indicate a loop"));
+ said_before = TRUE;
+ return lang;
+ }
+ }
+ return lang;
+}
+
+/* Mask for components of locale spec. The ordering here is from
+ * least significant to most significant
+ */
+enum
+{
+ COMPONENT_CODESET = 1 << 0,
+ COMPONENT_TERRITORY = 1 << 1,
+ COMPONENT_MODIFIER = 1 << 2
+};
+
+/* Break an X/Open style locale specification into components
+ */
+static guint
+explode_locale (const gchar *locale,
+ gchar **language,
+ gchar **territory,
+ gchar **codeset,
+ gchar **modifier)
+{
+ const gchar *uscore_pos;
+ const gchar *at_pos;
+ const gchar *dot_pos;
+
+ guint mask = 0;
+
+ uscore_pos = strchr (locale, '_');
+ dot_pos = strchr (uscore_pos ? uscore_pos : locale, '.');
+ at_pos = strchr (dot_pos ? dot_pos : (uscore_pos ? uscore_pos : locale), '@');
+
+ if (at_pos)
+ {
+ mask |= COMPONENT_MODIFIER;
+ *modifier = g_strdup (at_pos);
+ }
+ else
+ at_pos = locale + strlen (locale);
+
+ if (dot_pos)
+ {
+ mask |= COMPONENT_CODESET;
+ *codeset = g_new (gchar, 1 + at_pos - dot_pos);
+ strncpy (*codeset, dot_pos, at_pos - dot_pos);
+ (*codeset)[at_pos - dot_pos] = '\0';
+ }
+ else
+ dot_pos = at_pos;
+
+ if (uscore_pos)
+ {
+ mask |= COMPONENT_TERRITORY;
+ *territory = g_new (gchar, 1 + dot_pos - uscore_pos);
+ strncpy (*territory, uscore_pos, dot_pos - uscore_pos);
+ (*territory)[dot_pos - uscore_pos] = '\0';
+ }
+ else
+ uscore_pos = dot_pos;
+
+ *language = g_new (gchar, 1 + uscore_pos - locale);
+ strncpy (*language, locale, uscore_pos - locale);
+ (*language)[uscore_pos - locale] = '\0';
+
+ return mask;
+}
+
+/*
+ * Compute all interesting variants for a given locale name -
+ * by stripping off different components of the value.
+ *
+ * For simplicity, we assume that the locale is in
+ * X/Open format: language[_territory][ codeset][ modifier]
+ *
+ * TODO: Extend this to handle the CEN format (see the GNUlibc docs)
+ * as well. We could just copy the code from glibc wholesale
+ * but it is big, ugly, and complicated, so I'm reluctant
+ * to do so when this should handle 99% of the time...
+ */
+static GList *
+compute_locale_variants (const gchar *locale)
+{
+ GList *retval = NULL;
+
+ gchar *language;
+ gchar *territory;
+ gchar *codeset;
+ gchar *modifier;
+
+ guint mask;
+ guint i;
+
+ g_return_val_if_fail (locale != NULL, NULL);
+
+ mask = explode_locale (locale, &language, &territory, &codeset, &modifier);
+
+ /* Iterate through all possible combinations, from least attractive
+ * to most attractive.
+ */
+ for (i=0; i<=mask; i++)
+ if ((i & ~mask) == 0)
+ {
+ gchar *val = g_strconcat(language,
+ (i & COMPONENT_TERRITORY) ? territory : "",
+ (i & COMPONENT_CODESET) ? codeset : "",
+ (i & COMPONENT_MODIFIER) ? modifier : "",
+ NULL);
+ retval = g_list_prepend (retval, val);
+ }
+
+ g_free (language);
+ if (mask & COMPONENT_CODESET)
+ g_free (codeset);
+ if (mask & COMPONENT_TERRITORY)
+ g_free (territory);
+ if (mask & COMPONENT_MODIFIER)
+ g_free (modifier);
+
+ return retval;
+}
+
+/* The following is (partly) taken from the gettext package.
+ Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc. */
+
+static const gchar *
+guess_category_value (const gchar *categoryname)
+{
+ const gchar *retval;
+
+ /* The highest priority value is the `LANGUAGE' environment
+ variable. This is a GNU extension. */
+ retval = g_getenv ("LANGUAGE");
+ if (retval != NULL && retval[0] != '\0')
+ return retval;
+
+ /* `LANGUAGE' is not set. So we have to proceed with the POSIX
+ methods of looking to `LC_ALL', `LC_xxx', and `LANG'. On some
+ systems this can be done by the `setlocale' function itself. */
+
+ /* Setting of LC_ALL overwrites all other. */
+ retval = g_getenv ("LC_ALL");
+ if (retval != NULL && retval[0] != '\0')
+ return retval;
+
+ /* Next comes the name of the desired category. */
+ retval = g_getenv (categoryname);
+ if (retval != NULL && retval[0] != '\0')
+ return retval;
+
+ /* Last possibility is the LANG environment variable. */
+ retval = g_getenv ("LANG");
+ if (retval != NULL && retval[0] != '\0')
+ return retval;
+
+ return NULL;
+}
+
+
+static GHashTable *category_table= NULL;
+
+
+/**
+ * gnome_i18n_get_language_list:
+ * @category_name: Name of category to look up, e.g. "LC_MESSAGES".
+ *
+ * This computes a list of language strings. It searches in the
+ * standard environment variables to find the list, which is sorted
+ * in order from most desirable to least desirable. The `C' locale
+ * is appended to the list if it does not already appear (other routines depend on this behaviour).
+ * If @category_name is %NULL, then LC_ALL is assumed.
+ *
+ * Return value: the list of languages, this list should not be freed as it is owned by gnome-i18n
+ **/
+const GList *
+gnome_i18n_get_language_list (const gchar *category_name)
+{
+ GList *list;
+
+ if (!category_name)
+ category_name= "LC_ALL";
+
+ if (category_table)
+ {
+ list= g_hash_table_lookup (category_table, (const gpointer) category_name);
+ }
+ else
+ {
+ category_table= g_hash_table_new (g_str_hash, g_str_equal);
+ list= NULL;
+ }
+
+ if (!list)
+ {
+ gint c_locale_defined= FALSE;
+
+ const gchar *category_value;
+ gchar *category_memory, *orig_category_memory;
+
+ category_value = guess_category_value (category_name);
+ if (! category_value)
+ category_value = "C";
+ orig_category_memory = category_memory =
+ g_malloc (strlen (category_value)+1);
+
+ while (category_value[0] != '\0')
+ {
+ while (category_value[0] != '\0' && category_value[0] == ':')
+ ++category_value;
+
+ if (category_value[0] != '\0')
+ {
+ char *cp= category_memory;
+
+ while (category_value[0] != '\0' && category_value[0] != ':')
+ *category_memory++= *category_value++;
+
+ category_memory[0]= '\0';
+ category_memory++;
+
+ cp = unalias_lang(cp);
+
+ if (strcmp (cp, "C") == 0)
+ c_locale_defined= TRUE;
+
+ list= g_list_concat (list, compute_locale_variants (cp));
+ }
+ }
+
+ g_free (orig_category_memory);
+
+ if (!c_locale_defined)
+ list= g_list_append (list, "C");
+
+ g_hash_table_insert (category_table, (gpointer) category_name, list);
+ }
+
+ return list;
+}
+
+static GList *numeric_locale_stack = NULL;
+
+/**
+ * gnome_i18n_push_c_numeric_locale:
+ *
+ * Description: Pushes the current LC_NUMERIC locale onto a stack, then
+ * sets LC_NUMERIC to "C". This way you can safely read write flaoting
+ * point numbers all in the same format. You should make sure that
+ * code between #gnome_i18n_push_c_numeric_locale and
+ * #gnome_i18n_pop_c_numeric_locale doesn't do any setlocale calls or locale
+ * may end up in a strange setting. Also make sure to always pop the
+ * c numeric locale after you've pushed it.
+ **/
+void
+gnome_i18n_push_c_numeric_locale (void)
+{
+ char *current;
+
+ current = g_strdup (setlocale (LC_NUMERIC, NULL));
+ numeric_locale_stack = g_list_prepend (numeric_locale_stack,
+ current);
+ setlocale (LC_NUMERIC, "C");
+}
+
+/**
+ * gnome_i18n_pop_c_numeric_locale:
+ *
+ * Description: Pops the last LC_NUMERIC locale from the stack (where
+ * it was put with #gnome_i18n_push_c_numeric_locale). Then resets the
+ * current locale to that one.
+ **/
+void
+gnome_i18n_pop_c_numeric_locale (void)
+{
+ char *old;
+
+ if (numeric_locale_stack == NULL)
+ return;
+
+ old = numeric_locale_stack->data;
+
+ setlocale (LC_NUMERIC, old);
+
+ numeric_locale_stack = g_list_remove (numeric_locale_stack, old);
+
+ g_free (old);
+}
diff --git a/libgnome/gnome-i18n.h b/libgnome/gnome-i18n.h
index e8b22fe..f610a7f 100644
--- a/libgnome/gnome-i18n.h
+++ b/libgnome/gnome-i18n.h
@@ -28,15 +28,14 @@
* Author: Tom Tromey <tromey creche cygnus com>
*/
-#ifndef __LIBGNOME_I18N_H__
-#define __LIBGNOME_I18N_H__ 1
-
-#include <glib/gmacros.h>
+#ifndef __GNOME_I18N_H__
+#define __GNOME_I18N_H__ 1
+#include <glib.h>
G_BEGIN_DECLS
-#if !defined(__LIBGNOME_I18NP_H__)
+#if !defined(__GNOME_I18NP_H__)
#ifdef ENABLE_NLS
# include <libintl.h>
@@ -64,6 +63,44 @@ G_BEGIN_DECLS
#endif
+/* 'gnome_i18n_get_language_list' returns a list of language strings.
+ *
+ * It searches for one of following environment variables:
+ * LANGUAGE
+ * LC_ALL
+ * 'category_name'
+ * LANG
+ *
+ * If one of these environment variables was found, it is split into
+ * pieces, whereever a ':' is found. When the environment variable included
+ * no C locale, the C locale is appended to the list of languages.
+ *
+ * Assume, you have the following environment variables set:
+ *
+ * LC_MONETARY="de_DE:es"
+ * LANG="de_DE:de:C:en"
+ *
+ * In this case 'gnome_i18n_get_language_list ("LC_COLLATE")' returns the
+ * list: ("de_DE" "de" "C" "en").
+ *
+ * 'gnome_i18n_get_language_list ("LC_MONETARY")' returns:
+ * ("de_DE" "es" "C")
+ *
+ * The returned list must not be changed.
+ */
+
+const GList * gnome_i18n_get_language_list (const gchar *category_name);
+
+/* Push "C" numeric locale. Do this before doing any floating
+ * point to/from string conversions, if those are to be done in
+ * a portable manner. This is a hack really, and there is
+ * no need to generalize it to other cathegories. But it is
+ * needed whenever things like printing scanning floats from or
+ * to files or other places where you'd like to read them back
+ * later. */
+void gnome_i18n_push_c_numeric_locale (void);
+void gnome_i18n_pop_c_numeric_locale (void);
+
G_END_DECLS
-#endif /* __LIBGNOME_I18N_H__ */
+#endif /* __GNOME_UTIL_H__ */
diff --git a/libgnome/gnome-i18nP.h b/libgnome/gnome-i18nP.h
new file mode 100644
index 0000000..bbfd7d8
--- /dev/null
+++ b/libgnome/gnome-i18nP.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+
+/*
+ * Handles i18n for the Gnome libraries. Libraries need to use
+ * dgettext in order to use a non-default translation domain.
+ * Author: Tom Tromey <tromey creche cygnus com>
+ */
+
+#ifndef __GNOME_I18NP_H__
+#define __GNOME_I18NP_H__ 1
+
+#ifdef ENABLE_NLS
+# include <libintl.h>
+# undef _
+# define _(String) dgettext (PACKAGE, String)
+# ifdef gettext_noop
+# define N_(String) gettext_noop (String)
+# else
+# define N_(String) (String)
+# endif
+#else
+/* Stubs that do something close enough. */
+# define textdomain(String) (String)
+# define gettext(String) (String)
+# define dgettext(Domain,Message) (Message)
+# define dcgettext(Domain,Message,Type) (Message)
+# define bindtextdomain(Domain,Directory) (Domain)
+# define _(String) (String)
+# define N_(String) (String)
+#endif
+
+#include "gnome-i18n.h"
+
+#endif /* __GNOME_I18NP_H__ */
diff --git a/libgnome/gnome-init.c b/libgnome/gnome-init.c
index 8de83ac..ba556d2 100644
--- a/libgnome/gnome-init.c
+++ b/libgnome/gnome-init.c
@@ -37,6 +37,7 @@
#include <sys/stat.h>
#include <glib.h>
+#include "gnome-i18nP.h"
#include <libgnome/gnome-init.h>
#include <libgnome/gnome-util.h>
diff --git a/libgnome/gnome-program.c b/libgnome/gnome-program.c
index b18ae8e..5a1bbd6 100644
--- a/libgnome/gnome-program.c
+++ b/libgnome/gnome-program.c
@@ -29,11 +29,15 @@
/* This module takes care of handling application and library
initialization and command line parsing */
+#include <config.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gmodule.h>
+
+#include "gnome-i18nP.h"
+
#include <libgnome/gnome-program.h>
#include <libgnome/gnome-init.h>
#include <libgnome/gnome-i18n.h>
diff --git a/libgnome/gnome-sound.c b/libgnome/gnome-sound.c
new file mode 100644
index 0000000..a5b98aa
--- /dev/null
+++ b/libgnome/gnome-sound.c
@@ -0,0 +1,516 @@
+/*
+ * Copyright (C) 1997-1998 Stuart Parmenter and Elliot Lee
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+
+#include "config.h"
+
+#include "libgnome.h"
+#include "gnome-sound.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+
+#ifdef HAVE_ESD
+#include <esd.h>
+#endif
+
+#ifdef HAVE_ESD
+static char *esound_hostname = NULL;
+int gnome_sound_connection = -1;
+#endif
+
+typedef struct _sample
+ {
+ int rate, format, samples, id, size;
+ short *data;
+ }
+GnomeSoundSample;
+
+#ifndef HAVE_LIBAUDIOFILE
+typedef struct _WAVFormatChunk
+ {
+ char chunkID[4];
+ int chunkSize;
+
+ unsigned int dwSamplesPerSec;
+ unsigned int dwAvgBytesPerSec;
+ short wFormatTag;
+ unsigned short wChannels;
+ unsigned short wBlockAlign;
+ unsigned short wBitsPerSample;
+ }
+WAVFormatChunk;
+
+#ifdef WORDS_BIGENDIAN
+#define SWAP_SHORT( x ) x = ( ( x & 0x00ff ) << 8 ) | ( ( x >> 8 ) & 0x00ff )
+#define SWAP_LONG( x ) x = ( ( ( x & 0x000000ff ) << 24 ) |\
+( ( x & 0x0000ff00 ) << 8 ) |\
+( ( x & 0x00ff0000 ) >> 8 ) |\
+( ( x & 0xff000000 ) >> 24 ) )
+#endif
+
+/**
+ * gnome_sound_sample_load_wav:
+ * @file: filename to try loading a WAV file from.
+ *
+ * Used to load a .wav file into esound.
+ *
+ * Returns a GnomeSoundSample or NULL if file did not exist.
+ *
+ */
+#ifdef HAVE_ESD
+static GnomeSoundSample *
+gnome_sound_sample_load_wav(const char *file)
+{
+ FILE *f;
+ GnomeSoundSample *s;
+ char buf[4];
+ WAVFormatChunk fmt;
+ int skipl = 0;
+ int skipr = 0;
+ char bytes = 0;
+ char stereo = 0;
+ int len;
+
+ /* int count; */
+
+ f = fopen (file, "r");
+ if (!f)
+ return NULL;
+ s = g_malloc (sizeof (GnomeSoundSample));
+ if (!s)
+ {
+ fclose (f);
+ return NULL;
+ }
+ s->rate = 44100;
+ s->format = ESD_STREAM | ESD_PLAY;
+ s->samples = 0;
+ s->data = NULL;
+ s->id = 0;
+ fread (buf, 1, 4, f);
+ if ((buf[0] != 'R') ||
+ (buf[1] != 'I') ||
+ (buf[2] != 'F') ||
+ (buf[3] != 'F'))
+ {
+ /* not a RIFF WAV file */
+ fclose (f);
+ g_free (s);
+ return NULL;
+ }
+ fread (buf, 1, 4, f);
+ fread (buf, 1, 4, f);
+ fread (fmt.chunkID, 1, 4, f);
+ fread (&(fmt.chunkSize), 1, 4, f);
+
+#ifdef WORDS_BIGENDIAN
+ SWAP_LONG (fmt.chunkSize);
+#endif
+
+ if ((fmt.chunkID[0] == 'f') &&
+ (fmt.chunkID[1] == 'm') &&
+ (fmt.chunkID[2] == 't') &&
+ (fmt.chunkID[3] == ' ') &&
+ 16 == fmt.chunkSize)
+ /* fmt chunk */
+ {
+ fread (&(fmt.wFormatTag), 1, 2, f);
+ fread (&(fmt.wChannels), 1, 2, f);
+ fread (&(fmt.dwSamplesPerSec), 1, 4, f);
+ fread (&(fmt.dwAvgBytesPerSec), 1, 4, f);
+ fread (&(fmt.wBlockAlign), 1, 2, f);
+ fread (&(fmt.wBitsPerSample), 1, 2, f);
+#ifdef WORDS_BIGENDIAN
+ SWAP_SHORT (fmt.wFormatTag);
+ SWAP_SHORT (fmt.wChannels);
+ SWAP_LONG (fmt.dwSamplesPerSec);
+ SWAP_LONG (fmt.dwAvgBytesPerSec);
+ SWAP_SHORT (fmt.wBlockAlign);
+ SWAP_SHORT (fmt.wBitsPerSample);
+#endif
+
+ if (fmt.wFormatTag != 1)
+ {
+ /* unknown WAV encoding format - exit */
+ fclose (f);
+ g_free (s);
+ return NULL;
+ }
+ skipl = 0;
+ skipr = 0;
+ bytes = 0;
+ stereo = 0;
+ if (fmt.wChannels == 1)
+ s->format |= ESD_MONO;
+ else if (fmt.wChannels == 2)
+ {
+ stereo = 1;
+ s->format |= ESD_STEREO;
+ }
+ else
+ {
+ stereo = 1;
+ s->format |= ESD_STEREO;
+ if (fmt.wChannels == 3)
+ {
+ skipl = 0;
+ skipr = 1;
+ }
+ else if (fmt.wChannels == 4)
+ {
+ skipl = 0;
+ skipr = 2;
+ }
+ else if (fmt.wChannels == 4)
+ {
+ skipl = 0;
+ skipr = 2;
+ }
+ else if (fmt.wChannels == 6)
+ {
+ skipl = 3;
+ skipr = 1;
+ }
+ else
+ {
+ /* unknown channel encoding */
+ fclose (f);
+ g_free (s);
+ return NULL;
+ }
+ }
+ s->rate = fmt.dwSamplesPerSec;
+ if (fmt.wBitsPerSample <= 8)
+ {
+ bytes = 1;
+ s->format |= ESD_BITS8;
+ }
+ else if (fmt.wBitsPerSample <= 16)
+ s->format |= ESD_BITS16;
+ else
+ {
+ /* unknown bits encoding encoding */
+ fclose (f);
+ g_free (s);
+ return NULL;
+ }
+ }
+ for (;;)
+ {
+ if (fread (buf, 1, 4, f) &&
+ fread (&len, 4, 1, f))
+ {
+#ifdef WORDS_BIGENDIAN
+ SWAP_LONG (len);
+#endif
+
+ if ((buf[0] != 'd') ||
+ (buf[1] != 'a') ||
+ (buf[2] != 't') ||
+ (buf[3] != 'a'))
+ fseek (f, len, SEEK_CUR);
+ else
+ {
+ s->data = g_malloc (len);
+ if (!s->data)
+ {
+ fclose (f);
+ g_free (s);
+ return NULL;
+ }
+ if ((skipl == 0) && (skipr == 0))
+ {
+ fread (s->data, len, 1, f);
+#ifdef WORDS_BIGENDIAN
+ if (fmt.wBitsPerSample > 8 && fmt.wBitsPerSample <= 16)
+ {
+ char *tmp;
+ char tmpval;
+ int i;
+
+ tmp = (char *) (s->data);
+
+ for (i = 0; i < len; i++)
+ {
+ tmpval = tmp[i];
+ tmp[i] = tmp[i + 1];
+ tmp[i + 1] = tmpval;
+ }
+ }
+#endif
+ }
+ else
+ {
+ }
+ s->samples = len;
+ if (stereo)
+ s->samples /= 2;
+ if (!bytes)
+ s->samples /= 2;
+ fclose (f);
+ return s;
+ }
+ }
+ else
+ {
+ fclose (f);
+ return NULL;
+ }
+ }
+ fclose (f);
+ g_free (s);
+ if (s->data)
+ g_free (s->data);
+
+ return NULL;
+}
+#endif
+#endif
+
+#ifdef HAVE_ESD
+/*
+ * This does delayed initialization of Esound
+ */
+static gboolean
+use_sound (void)
+{
+ if (gnome_sound_connection == -1){
+ if (esound_hostname){
+ gnome_sound_connection = esd_open_sound (esound_hostname);
+ if (gnome_sound_connection == -1){
+ g_free (esound_hostname);
+ esound_hostname = NULL;
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+}
+#endif
+
+#if defined(HAVE_LIBAUDIOFILE) && defined(HAVE_ESD)
+#include <audiofile.h>
+
+static GnomeSoundSample *
+gnome_sound_sample_load_audiofile(const char *file)
+{
+ AFfilehandle in_file;
+ GnomeSoundSample *s;
+ int in_format, in_width, in_channels;
+ double in_rate;
+ int bytes_per_frame;
+ AFframecount frame_count, frames_read;
+
+ int out_bits, out_channels, out_rate;
+ int out_mode = ESD_STREAM, out_func = ESD_PLAY;
+ esd_format_t out_format;
+
+ in_file = afOpenFile(file, "r", NULL);
+ if(!in_file)
+ return NULL;
+
+ frame_count = afGetFrameCount(in_file, AF_DEFAULT_TRACK);
+ in_channels = afGetChannels(in_file, AF_DEFAULT_TRACK);
+ in_rate = afGetRate (in_file, AF_DEFAULT_TRACK);
+ afGetSampleFormat (in_file, AF_DEFAULT_TRACK, &in_format, &in_width);
+ if (in_width == 8)
+ out_bits = ESD_BITS8;
+ else if (in_width == 16)
+ out_bits = ESD_BITS16;
+ else {
+ g_warning ("only sample widths of 8 and 16 supported");
+ return NULL;
+ }
+
+ bytes_per_frame = in_width / 8;
+
+ if (in_channels == 1)
+ out_channels = ESD_MONO;
+ else if (in_channels == 2)
+ out_channels = ESD_STEREO;
+ else {
+ g_warning ("only 1 or 2 channel samples supported");
+ return NULL;
+ }
+
+ out_format = out_bits | out_channels | out_mode | out_func;
+
+ out_rate = (int) in_rate;
+
+ s = g_new0 (GnomeSoundSample, 1);
+
+ s->rate = out_rate;
+ s->format = out_format;
+ s->samples = frame_count;
+ s->data = g_malloc(frame_count * in_channels * bytes_per_frame);
+ s->id = 0;
+
+ frames_read = afReadFrames(in_file, AF_DEFAULT_TRACK, s->data,
+ frame_count * in_channels);
+
+ afCloseFile(in_file);
+
+ return s;
+}
+#endif
+
+
+/**
+ * gnome_sound_sample_load:
+ * @sample_name: the name of the sample
+ * @filename: the filename where the audio is stored
+ *
+ * Loads the audio on @filename and XXXX
+ *
+ * Returns: a sample_id, or a negative number otherwise.
+ */
+int
+gnome_sound_sample_load(const char *sample_name, const char *filename)
+{
+#ifdef HAVE_ESD
+ GnomeSoundSample *s = NULL;
+ int sample_id;
+ int size;
+ int confirm = 0;
+
+ if (!use_sound ())
+ return -2;
+
+ if(!filename || !*filename)
+ return -2;
+
+#ifdef HAVE_LIBAUDIOFILE
+ s = gnome_sound_sample_load_audiofile(filename);
+#else
+ s = gnome_sound_sample_load_wav(filename);
+#endif
+ if(s)
+ goto playsamp;
+
+ /* XXX: Add handlers for more formats here */
+
+ playsamp:
+ if (!s)
+ return -1;
+
+ size = s->samples;
+ if (s->format & ESD_STEREO)
+ size *= 2;
+ if (s->format & ESD_BITS16)
+ size *= 2;
+
+ if (gnome_sound_connection >= 0)
+ {
+ if (s->data)
+ {
+ /* "name" of all samples is currently "E", should be name of sound
+ * file, or event type, for later identification */
+ s->id = esd_sample_cache (gnome_sound_connection, s->format, s->rate,
+ size, (char *)sample_name);
+ write (gnome_sound_connection, s->data, size);
+ confirm = esd_confirm_sample_cache (gnome_sound_connection);
+ if (s->id <= 0 || confirm != s->id)
+ {
+ g_warning ("error caching sample <%d>!\n", s->id);
+ s->id = 0;
+ }
+ g_free (s->data);
+ s->data = NULL;
+ }
+ }
+
+ sample_id = s->id;
+
+ g_free(s->data); g_free(s);
+
+ return sample_id;
+#else
+ return -1;
+#endif
+}
+
+/**
+ * gnome_sound_play:
+ * @filename: file containing the sound sample
+ *
+ * Plays the audio stored in @filename
+ */
+void
+gnome_sound_play (const char * filename)
+{
+#ifdef HAVE_ESD
+ char buf[23];
+ int sample;
+
+ if(!use_sound ())
+ return;
+
+ srand(time(NULL));
+ g_snprintf(buf, sizeof(buf), "%d-%d", getpid(), rand());
+ sample = gnome_sound_sample_load (buf, filename);
+
+ esd_sample_play(gnome_sound_connection, sample);
+ fsync (gnome_sound_connection);
+ esd_sample_free(gnome_sound_connection, sample);
+#endif
+}
+
+/**
+ * gnome_sound_init:
+ * @hostname: hostname where esd daemon resides.
+ *
+ * Initialize esd connection
+ */
+void
+gnome_sound_init(const char *hostname)
+{
+#ifdef HAVE_ESD
+ if (gnome_sound_connection < 0) {
+ g_free (esound_hostname);
+ esound_hostname = g_strdup (hostname);
+ gnome_sound_connection = esd_open_sound((char *)hostname);
+ }
+#endif
+}
+
+/**
+ * gnome_sound_shutdown:
+ *
+ * shuts down the gnome sound support
+ */
+void
+gnome_sound_shutdown(void)
+{
+#ifdef HAVE_ESD
+ if(gnome_sound_connection >= 0){
+ esd_close(gnome_sound_connection);
+ gnome_sound_connection = -1;
+ g_free (esound_hostname);
+ esound_hostname = NULL;
+ }
+#endif
+}
diff --git a/libgnome/gnome-sound.h b/libgnome/gnome-sound.h
new file mode 100644
index 0000000..06ace7d
--- /dev/null
+++ b/libgnome/gnome-sound.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 1997-1998 Stuart Parmenter and Elliot Lee
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+
+#ifndef __GNOME_SOUND_H__
+#define __GNOME_SOUND_H__ 1
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+/* Use this with the Esound functions */
+extern int gnome_sound_connection;
+
+/* Initialize esd connection */
+void gnome_sound_init(const char *hostname);
+
+/* Closes esd connection */
+void gnome_sound_shutdown(void);
+
+/* Returns the Esound sample ID for the sample */
+int gnome_sound_sample_load(const char *sample_name, const char *filename);
+
+/* Loads sample, plays sample, frees sample */
+void gnome_sound_play (const char * filename);
+
+G_END_DECLS
+
+#endif /* __GNOME_SOUND_H__ */
diff --git a/libgnome/gnome-triggers.c b/libgnome/gnome-triggers.c
new file mode 100644
index 0000000..b67c558
--- /dev/null
+++ b/libgnome/gnome-triggers.c
@@ -0,0 +1,605 @@
+/*
+ * Copyright (C) 1997, 1998 Elliot Lee
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+
+#include "config.h"
+
+/* By Elliot Lee */
+
+#include "gnome-triggers.h"
+#include "gnome-triggersP.h"
+#include "gnome-config.h"
+#include "gnome-util.h"
+#if 0
+#include "gnome-sound.h"
+
+#ifdef HAVE_ESD
+#include <esd.h>
+#endif
+#endif
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <glib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <dirent.h>
+
+/* TYPE DECLARATIONS */
+
+typedef void (*GnomeTriggerTypeFunction)(GnomeTrigger *t, char *msg, char *level, char *supinfo[]);
+
+/* PROTOTYPES */
+static GnomeTrigger* gnome_trigger_dup(GnomeTrigger *dupme);
+static GnomeTriggerList* gnome_triggerlist_new(char *nodename);
+static void gnome_triggerlist_free(GnomeTriggerList* t);
+static void gnome_trigger_free(GnomeTrigger* t);
+static void gnome_trigger_do(GnomeTrigger* t, const char *msg, const char *level,
+ const char *supinfo[]);
+static void gnome_trigger_do_function(GnomeTrigger* t,
+ const char *msg, const char *level,
+ const char *supinfo[]);
+static void gnome_trigger_do_command(GnomeTrigger* t,
+ const char *msg, const char *level,
+ const char *supinfo[]);
+static void gnome_trigger_do_mediaplay(GnomeTrigger* t,
+ const char *msg,
+ const char *level,
+ const char *supinfo[]);
+
+/* FILEWIDE VARIABLES */
+
+static GnomeTriggerList* gnome_triggerlist_topnode = NULL;
+
+static const GnomeTriggerTypeFunction actiontypes[] =
+/* This list should have entries for all the trigger types in
+ gnome-triggers.h */
+{
+ (GnomeTriggerTypeFunction)NULL,
+ (GnomeTriggerTypeFunction)gnome_trigger_do_function,
+ (GnomeTriggerTypeFunction)gnome_trigger_do_command,
+ (GnomeTriggerTypeFunction)gnome_trigger_do_mediaplay,
+ (GnomeTriggerTypeFunction)NULL
+};
+
+/* IMPLEMENTATIONS */
+void
+gnome_triggers_init(void)
+{
+}
+
+#if 0
+/* snarfed almost directly from sound-properties. */
+static gint
+gnome_triggers_read_path(const char *config_path)
+{
+ DIR *dirh;
+ char *category_name, *sample_name, *sample_file, *ctmp;
+ gpointer top_iter, event_iter;
+ struct dirent *dent;
+ GnomeTrigger nt;
+ GString *tmpstr;
+
+ nt.type = GTRIG_MEDIAPLAY;
+ nt.level = NULL;
+ nt.u.media.cache_id = -1;
+
+ dirh = opendir(config_path);
+ if(!dirh)
+ return -1;
+
+ tmpstr = g_string_new(NULL);
+
+ while((dent = readdir(dirh))) {
+ /* ignore no-good dir entries.
+ We ignore "gnome" because the system sounds are listed in there.
+ */
+ if (!strcmp(dent->d_name, ".")
+ || !strcmp(dent->d_name, "..")
+ || !strcmp(dent->d_name, "gnome")
+ || !strcmp(dent->d_name, "gnome.soundlist"))
+ continue;
+
+ g_string_sprintf(tmpstr, "=%s/%s=", config_path, dent->d_name);
+
+ gnome_config_push_prefix(tmpstr->str);
+
+ event_iter = gnome_config_init_iterator_sections(tmpstr->str);
+ while((event_iter = gnome_config_iterator_next(event_iter,
+ &sample_name, NULL))) {
+ if(!strcmp(sample_name, "__section_info__"))
+ goto continue_loop;
+
+ g_string_sprintf(tmpstr, "%s/file", sample_name);
+ sample_file = gnome_config_get_string(tmpstr->str);
+
+ if(!sample_file || !*sample_file) {
+ g_free(sample_name);
+ continue;
+ }
+
+ if(*sample_file != '/') {
+ char *tmp = gnome_sound_file(sample_file);
+ g_free(sample_file);
+ sample_file = tmp;
+ }
+
+ ctmp = g_strdup(dent->d_name);
+ if(strstr(ctmp, ".soundlist"))
+ *strstr(ctmp, ".soundlist") = '\0';
+
+ nt.u.media.file = sample_file;
+ gnome_triggers_add_trigger(&nt, ctmp, sample_name, NULL);
+
+ g_free(ctmp);
+
+ continue_loop:
+ g_free(sample_name);
+ }
+
+ gnome_config_pop_prefix();
+ }
+ closedir(dirh);
+
+ g_string_free(tmpstr, TRUE);
+
+ return 0;
+}
+/**
+ * gnome_triggers_readfile:
+ * @infilename: A file listing triggers to install in the currently
+ * running program.
+ *
+ * The file should be of the format:
+ *
+ * level section type params
+ *
+ * Where 'level' indicates the message severity at which this trigger
+ * should be activated, 'section' is a colon-separated list indicating
+ * which part of the "message classification tree" this trigger will
+ * be activated for, 'type' is either "command" (run the command
+ * specified in 'params') or 'play' (play the esd sound sample named
+ * 'params').
+ *
+ * Returns 0 on success. 1 otherwise.
+ *
+ */
+gint
+gnome_triggers_readfile(const char *infilename)
+{
+ GnomeTrigger* nt;
+ char aline[512];
+ char **subnames = NULL;
+ char **parts = NULL;
+ FILE *infile;
+ int i;
+
+ infile = fopen(infilename, "r");
+ if(infile == NULL)
+ return 1;
+
+ nt = gnome_trigger_dup(NULL);
+ while(fgets(aline, sizeof(aline), infile)) {
+ i = strlen(aline) - 1;
+ while(isspace(aline[i])) aline[i--] = '\0';
+
+ if(aline[0] == '\0' || aline[0] == '#')
+ continue;
+
+ parts = g_strsplit(aline, " ", 4);
+ if(!parts || !parts[0] || !parts[1] || !parts[2] || !parts[3]) {
+ g_strfreev(parts);
+ g_warning("Invalid triggers line \'%s\'\n", aline);
+ continue;
+ }
+
+ if(!strcmp(parts[1], "NULL")) {
+ subnames = g_malloc(sizeof(gchar *));
+ subnames[0] = NULL;
+ } else
+ subnames = g_strsplit(parts[1], ":", -1);
+
+ if(!strcmp(parts[2], "command"))
+ nt->type = GTRIG_COMMAND;
+ else if(!strcmp(parts[2], "play"))
+ nt->type = GTRIG_MEDIAPLAY;
+ nt->u.command = parts[3];
+ if(!strcmp(parts[0], "NULL"))
+ nt->level = NULL;
+ else
+ nt->level = parts[0];
+ gnome_triggers_vadd_trigger(nt, subnames);
+
+ g_strfreev(subnames);
+ g_strfreev(parts);
+ }
+ g_free(nt);
+ fclose(infile);
+
+ return 0;
+}
+#endif
+
+/**
+ * gnome_triggers_add_trigger:
+ * @nt: Information on the new trigger to be added.
+ * @...: the 'section' to add the trigger under (see gnome_triggers_readfile())
+ *
+ * Similar to gnome_triggers_readfile(), but gets the trigger information
+ * from the file 'nt' structure and the varargs, instead of from a file.
+ */
+void gnome_triggers_add_trigger(GnomeTrigger* nt, ...)
+{
+ va_list l;
+ gint nstrings, i;
+ gchar **strings;
+
+ /* Count number of strings */
+
+ va_start(l, nt);
+ for (nstrings = 0; va_arg(l, gchar *); nstrings++);
+ va_end(l);
+
+ /* Build list */
+
+ strings = g_new(gchar *, nstrings + 1);
+
+ va_start(l, nt);
+
+ for (i = 0; i < nstrings; i++)
+ strings[i] = va_arg(l, gchar *);
+ strings[i] = NULL;
+
+ va_end(l);
+
+ /* And pass them to the real function */
+
+ gnome_triggers_vadd_trigger(nt, strings);
+
+ g_free (strings);
+}
+
+static GnomeTrigger*
+gnome_trigger_dup(GnomeTrigger* dupme)
+{
+ GnomeTrigger* retval;
+ retval = g_malloc(sizeof(struct _GnomeTrigger));
+ if(dupme) {
+ *retval = *dupme;
+ if(dupme->level)
+ retval->level = g_strdup(dupme->level);
+ else
+ retval->level = NULL;
+ switch(retval->type) {
+ case GTRIG_COMMAND:
+ retval->u.command = g_strdup(dupme->u.command);
+ break;
+ default:
+ break;
+ }
+ } else {
+ retval->level = NULL;
+ retval->type = GTRIG_NONE;
+ memset(&retval->u, 0, sizeof(retval->u));
+ }
+ return retval;
+}
+
+static GnomeTriggerList*
+gnome_triggerlist_new(char *nodename)
+{
+ GnomeTriggerList* retval;
+ retval = g_malloc0(sizeof(GnomeTriggerList));
+ retval->nodename = g_strdup(nodename);
+ return retval;
+}
+
+/**
+ * gnome_triggers_vadd_trigger:
+ * @nt: Information on the new trigger to be added.
+ * @supinfo: the 'section' to add the trigger under (see gnome_triggers_readfile())
+ *
+ * Similar to gnome_triggers_readfile(), but gets the trigger information
+ * from the file 'nt' structure and 'supinfo', instead of from a file.
+ */
+void gnome_triggers_vadd_trigger(GnomeTrigger* nt,
+ char *supinfo[])
+{
+ g_return_if_fail(nt != NULL);
+ if(!gnome_triggerlist_topnode)
+ gnome_triggerlist_topnode = gnome_triggerlist_new(NULL);
+
+ if(supinfo == NULL || supinfo[0] == NULL) {
+ gnome_triggerlist_topnode->actions = g_realloc(gnome_triggerlist_topnode->actions, ++gnome_triggerlist_topnode->numactions);
+ gnome_triggerlist_topnode->actions[gnome_triggerlist_topnode->numactions - 1] = gnome_trigger_dup(nt);
+ } else {
+ int i, j;
+ GnomeTriggerList* curnode;
+
+ for(i = 0, curnode = gnome_triggerlist_topnode;
+ supinfo[i]; i++) {
+ for(j = 0;
+ j < curnode->numsubtrees
+ && strcmp(curnode->subtrees[j]->nodename, supinfo[i]);
+ j++) /* Do nothing */ ;
+
+ if(j < curnode->numsubtrees) {
+ curnode = curnode->subtrees[j];
+ } else {
+ curnode->subtrees = g_realloc(curnode->subtrees,
+ ++curnode->numsubtrees
+ * sizeof(GnomeTriggerList*));
+ curnode->subtrees[curnode->numsubtrees - 1] =
+ gnome_triggerlist_new(supinfo[i]);
+ curnode = curnode->subtrees[curnode->numsubtrees - 1];
+ } /* end for j */
+ } /* end for i */
+
+ curnode->actions = g_realloc(curnode->actions,
+ ++curnode->numactions
+ * sizeof(GnomeTrigger));
+ curnode->actions[curnode->numactions - 1] = gnome_trigger_dup(nt);
+ } /* end if */
+}
+
+/**
+ * gnome_triggers_do:
+ * @msg: The human-readable message describing the event. (Can be NULL).
+ * @level: The level of severity of the event, or NULL.
+ * @...: The classification of the event.
+ *
+ * Notifies GNOME about an event happening, so GNOME can do cool things.
+ */
+void
+gnome_triggers_do(const char *msg, const char *level, ...)
+{
+ va_list l;
+ gint nstrings, i;
+ gchar **strings;
+
+ /* Count number of strings */
+ va_start(l, level);
+ for (nstrings = 0; va_arg(l, gchar *); nstrings++);
+ va_end(l);
+
+ /* Build list */
+
+ strings = g_new (gchar *, nstrings + 1);
+
+ va_start(l, level);
+
+ for (i = 0; i < nstrings; i++)
+ strings[i] = va_arg(l, gchar *);
+ strings[i] = NULL;
+
+ va_end(l);
+
+ /* And pass them to the real function */
+
+ gnome_triggers_vdo(msg, level, (const char **)strings);
+
+ g_free (strings);
+}
+
+/* The "add one to the sample ID" is because sample ID's start at 0,
+ and we need a way to distinguish between "not found in sound_ids"
+ and "sample #0" */
+static void
+gnome_triggers_play_sound(const char *sndname)
+{
+#if defined(HAVE_ESD) && 0
+ int sid;
+ static GHashTable *sound_ids = NULL;
+
+ if(gnome_sound_connection < 0) return;
+
+ if(!sound_ids)
+ sound_ids = g_hash_table_new(g_str_hash, g_str_equal);
+
+ sid = GPOINTER_TO_INT(g_hash_table_lookup(sound_ids, sndname));
+
+ if(!sid) {
+ sid = esd_sample_getid(gnome_sound_connection, sndname);
+ if(sid >= 0) sid++;
+ g_hash_table_insert(sound_ids, g_strdup(sndname), GINT_TO_POINTER(sid));
+ }
+
+ if(sid < 0) return;
+ sid--;
+ esd_sample_play(gnome_sound_connection, sid);
+#endif
+ /* If there's no esound, this is just a no-op */
+}
+
+/**
+ * gnome_triggers_vdo:
+ * @msg: The human-readable message describing the event. (Can be NULL).
+ * @level: The level of severity of the event, or NULL.
+ * @supinfo: The classification of the event (NULL terminated array).
+ *
+ * Notifies GNOME about an event happening, so GNOME can do cool things.
+ */
+void
+gnome_triggers_vdo(const char *msg, const char *level, const char *supinfo[])
+{
+ GnomeTriggerList* curnode = gnome_triggerlist_topnode;
+ int i, j;
+ char buf[256], *ctmp;
+
+ if(level) {
+ g_snprintf(buf, sizeof(buf), "gnome/%s", level);
+ gnome_triggers_play_sound(buf);
+ }
+
+ if(!supinfo)
+ return;
+
+ ctmp = g_strjoinv("/", (char **)supinfo);
+ gnome_triggers_play_sound(ctmp);
+ g_free(ctmp);
+
+ for(i = 0; curnode && supinfo[i]; i++)
+ {
+
+ for(j = 0; j < curnode->numactions; j++)
+ {
+ if(!curnode->actions[j]->level
+ || !level
+ || !strcmp(level, curnode->actions[j]->level))
+ gnome_trigger_do(curnode->actions[j], msg, level, supinfo);
+ }
+
+ for(j = 0;
+ j < curnode->numsubtrees
+ && strcmp(curnode->subtrees[j]->nodename,supinfo[i]);
+ j++)
+ /* Do nothing */ ;
+ if(j < curnode->numsubtrees)
+ curnode = curnode->subtrees[j];
+ else
+ curnode = NULL;
+ }
+ if(curnode)
+ {
+ for(j = 0; j < curnode->numactions; j++)
+ {
+ if(!curnode->actions[j]->level
+ || !level
+ || !strcmp(level, curnode->actions[j]->level))
+ gnome_trigger_do(curnode->actions[j], msg, level, supinfo);
+ }
+ }
+}
+
+static void
+gnome_trigger_free(GnomeTrigger* t)
+{
+ if(t->level)
+ g_free(t->level);
+ switch(t->type) {
+ case GTRIG_COMMAND:
+ g_free(t->u.command); break;
+ case GTRIG_MEDIAPLAY:
+ g_free(t->u.media.file); break;
+ default:
+ break;
+ }
+ g_free(t);
+}
+
+static void
+gnome_triggerlist_free(GnomeTriggerList* t)
+{
+ int i;
+
+ g_free(t->nodename);
+
+ for(i = 0; i < t->numsubtrees; i++) {
+ gnome_triggerlist_free(t->subtrees[i]);
+ }
+ g_free(t->subtrees);
+
+ for(i = 0; i < t->numactions; i++) {
+ gnome_trigger_free(t->actions[i]);
+ }
+ g_free(t->actions);
+
+ g_free(t);
+}
+
+static void
+gnome_trigger_do(GnomeTrigger* t,
+ const char *msg,
+ const char * level,
+ const char *supinfo[])
+{
+ g_return_if_fail(t != NULL);
+
+ actiontypes[t->type](t, (char *)msg, (char *)level, (char **)supinfo);
+}
+
+static void
+gnome_trigger_do_function(GnomeTrigger* t,
+ const char *msg,
+ const char *level,
+ const char *supinfo[])
+{
+ t->u.function((char *)msg, (char *)level, (char **)supinfo);
+}
+
+static void
+gnome_trigger_do_command(GnomeTrigger* t,
+ const char *msg,
+ const char *level,
+ const char *supinfo[])
+{
+ char **argv;
+ int nsupinfos, i;
+
+ for(nsupinfos = 0; supinfo[nsupinfos]; nsupinfos++);
+
+ argv = g_malloc(sizeof(char *) * (nsupinfos + 4));
+ argv[0] = (char *)t->u.command;
+ argv[1] = (char *)msg;
+ argv[2] = (char *)level;
+
+ for(i = 0; supinfo[i]; i++) {
+ argv[i + 3] = (char *)supinfo[i];
+ }
+ argv[i + 3] = NULL;
+
+ /* We're all set, let's do it */
+ {
+ pid_t childpid;
+ int status;
+ childpid = fork();
+ if(childpid)
+ waitpid(childpid, &status, 0);
+ else
+ execv(t->u.command, argv);
+ }
+
+ g_free(argv);
+}
+
+static void
+gnome_trigger_do_mediaplay(GnomeTrigger* t,
+ const char *msg,
+ const char *level,
+ const char *supinfo[])
+{
+#if defined(HAVE_ESD) && 0
+ if(gnome_sound_connection == -1)
+ return;
+
+ if(t->u.media.cache_id >= 0)
+ esd_sample_play(gnome_sound_connection, t->u.media.cache_id);
+ else if(t->u.media.cache_id == -1)
+ gnome_sound_play(t->u.media.file);
+#endif
+}
diff --git a/libgnome/gnome-triggers.h b/libgnome/gnome-triggers.h
new file mode 100644
index 0000000..5afb019
--- /dev/null
+++ b/libgnome/gnome-triggers.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 1997, 1998 Elliot Lee
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+
+#ifndef __GNOME_TRIGGERS_H__
+#define __GNOME_TRIGGERS_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+ GTRIG_NONE,
+ GTRIG_FUNCTION,
+ GTRIG_COMMAND,
+ GTRIG_MEDIAPLAY
+} GnomeTriggerType;
+
+typedef void (*GnomeTriggerActionFunction)(char *msg, char *level, char *supinfo[]);
+
+struct _GnomeTrigger {
+ GnomeTriggerType type;
+ union {
+ /*
+ * These will be passed the same info as
+ * gnome_triggers_do got
+ */
+ GnomeTriggerActionFunction function;
+ gchar *command;
+ struct {
+ gchar *file;
+ int cache_id;
+ } media;
+ } u;
+ gchar *level;
+};
+typedef struct _GnomeTrigger GnomeTrigger;
+
+void gnome_triggers_init (void);
+gint gnome_triggers_readfile (const char *infilename);
+
+/*
+ * The optional arguments in some of these functions are just
+ * a list of strings that help us know
+ * what type of event happened. For example,
+ *
+ * gnome_triggers_do("System is out of disk space on /dev/hda1!",
+ * "warning", "system", "device", "disk", "/dev/hda1");
+ */
+
+void gnome_triggers_add_trigger (GnomeTrigger *nt, ...);
+void gnome_triggers_vadd_trigger (GnomeTrigger *nt,
+ char *supinfo[]);
+
+void gnome_triggers_do (const char *msg,
+ const char *level, ...);
+
+void gnome_triggers_vdo (const char *msg, const char *level,
+ const char *supinfo[]);
+
+G_END_DECLS
+
+#endif /* __GNOME_TRIGGERS_H__ */
diff --git a/libgnome/gnome-triggersP.h b/libgnome/gnome-triggersP.h
new file mode 100644
index 0000000..cd8cd8a
--- /dev/null
+++ b/libgnome/gnome-triggersP.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 1997, 1998 Elliot Lee
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+
+#ifndef GNOME_TRIGGERSP_H
+#define GNOME_TRIGGERSP_H 1
+
+/* Yes, this mechanism is lame, that's why it's hidden :) */
+typedef struct _GnomeTriggerList GnomeTriggerList;
+
+struct _GnomeTriggerList {
+ char *nodename;
+ GnomeTriggerList **subtrees;
+ GnomeTrigger **actions;
+ gint numsubtrees;
+ gint numactions;
+};
+
+#endif
diff --git a/libgnome/gnome-url.c b/libgnome/gnome-url.c
index b7393e5..2f3d0ed 100644
--- a/libgnome/gnome-url.c
+++ b/libgnome/gnome-url.c
@@ -32,6 +32,8 @@
#include <unistd.h>
#include <errno.h>
+#include "gnome-i18nP.h"
+
#include <bonobo/bonobo-property-bag-client.h>
#include <libgnome/gnome-exec.h>
#include <libgnome/gnome-util.h>
diff --git a/libgnome/gnome-util.c b/libgnome/gnome-util.c
index 80058b7..004a353 100644
--- a/libgnome/gnome-util.c
+++ b/libgnome/gnome-util.c
@@ -94,8 +94,12 @@ gnome_util_user_shell (void)
"/bin/csh", "/bin/sh", 0
};
- if ((shell = g_getenv ("SHELL"))){
- return g_strdup (shell);
+ if (geteuid () == getuid () &&
+ getegid () == getgid ()) {
+ /* only in non-setuid */
+ if ((shell = g_getenv ("SHELL"))){
+ return g_strdup (shell);
+ }
}
pw = getpwuid(getuid());
if (pw && pw->pw_shell) {
diff --git a/libgnome/libgnome.h b/libgnome/libgnome.h
index c66eb2b..8115bb1 100644
--- a/libgnome/libgnome.h
+++ b/libgnome/libgnome.h
@@ -29,6 +29,11 @@
#include <libgnome/gnome-program.h>
#include <libgnome/gnome-i18n.h>
+#include <libgnome/gnome-config.h>
+
+#include <libgnome/gnome-triggers.h>
+#include <libgnome/gnome-sound.h>
+
#include <libgnome/gnome-exec.h>
#include <libgnome/gnome-util.h>
diff --git a/libgnome/test-libgnome.c b/libgnome/test-libgnome.c
index 007994a..390f736 100644
--- a/libgnome/test-libgnome.c
+++ b/libgnome/test-libgnome.c
@@ -7,6 +7,8 @@
#include <unistd.h>
#include <string.h>
+#include "gnome-i18nP.h"
+
#include "libgnome.h"
#include <libgnome/gnome-url.h>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]