summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pango/pango-utils.c575
-rw-r--r--pango/pango-utils.h40
2 files changed, 615 insertions, 0 deletions
diff --git a/pango/pango-utils.c b/pango/pango-utils.c
new file mode 100644
index 00000000..13ac2c7c
--- /dev/null
+++ b/pango/pango-utils.c
@@ -0,0 +1,575 @@
+/* Pango
+ * pango-utils.c: Utilities for internal functions and modules
+ *
+ * Copyright (C) 2000 Red Hat Software
+ *
+ * This 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.
+ *
+ * This 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 this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+
+#include <config.h>
+
+#include "pango-utils.h"
+
+#ifndef HAVE_FLOCKFILE
+# define flockfile(f) (void)1
+# define funlockfile(f) (void)1
+# define getc_unlocked(f) getc(f)
+#endif /* !HAVE_FLOCKFILE */
+
+/**
+ * pango_trim_string:
+ * @str: a string
+ *
+ * Trim leading and trailing whitespace from a string.
+ *
+ * Return value: A newly allocated string that must be freed with g_free()
+ **/
+char *
+pango_trim_string (const char *str)
+{
+ int len;
+
+ g_return_val_if_fail (str != NULL, NULL);
+
+ while (*str && isspace (*str))
+ str++;
+
+ len = strlen (str);
+ while (len > 0 && isspace (str[len-1]))
+ len--;
+
+ return g_strndup (str, len);
+}
+
+/**
+ * pango_split_file_list:
+ * @str: a comma separated list of filenames
+ *
+ * Split a comma-separated list of files, stripping white space
+ * and subsituting ~/ with $HOME/
+ *
+ * Return value: a list of strings to be freed with g_strfreev()
+ **/
+char **
+pango_split_file_list (const char *str)
+{
+ int i = 0;
+ int j;
+ char **files;
+
+ files = g_strsplit (str, ":", -1);
+
+ while (files[i])
+ {
+ char *file = pango_trim_string (files[i]);
+
+ /* If the resulting file is empty, skip it */
+ if (file[0] == '\0')
+ {
+ g_free(file);
+ g_free (files[i]);
+
+ for (j = i + 1; files[j]; j++)
+ files[j - 1] = files[j];
+
+ files[j - 1] = NULL;
+
+ continue;
+ }
+
+ if (file[0] == '~' && file[1] == G_DIR_SEPARATOR)
+ {
+ char *tmp = g_strconcat (g_get_home_dir(), files + 1, NULL);
+ g_free (file);
+ file = tmp;
+ }
+
+ g_free (files[i]);
+ files[i] = file;
+
+ i++;
+ }
+
+ return files;
+}
+
+/**
+ * pango_read_line:
+ * @stream: a stdio stream
+ * @str: #GString buffer into which to write the result
+ *
+ * Read an entire line from a file into a buffer. Lines may
+ * be delimited with '\n', '\r', '\n\r', or '\r\n'. The delimiter
+ * is not written into the buffer. Text after a '#' character is treated as
+ * a comment and skipped. '\' can be used to escape a # character.
+ * '\' proceding a line delimiter combines adjacent lines. A '\' proceding
+ * any other character is ignored and written into the output buffer
+ * unmodified.
+ *
+ * Return value: %FALSE if the stream was already at an EOF character.
+ **/
+gboolean
+pango_read_line (FILE *stream, GString *str)
+{
+ gboolean quoted = FALSE;
+ gboolean comment = FALSE;
+ int n_read = 0;
+
+ flockfile (stream);
+
+ g_string_truncate (str, 0);
+
+ while (1)
+ {
+ int c;
+
+ c = getc_unlocked (stream);
+
+ if (c == EOF)
+ {
+ if (quoted)
+ g_string_append_c (str, '\\');
+
+ goto done;
+ }
+ else
+ n_read++;
+
+ if (quoted)
+ {
+ quoted = FALSE;
+
+ switch (c)
+ {
+ case '#':
+ g_string_append_c (str, '#');
+ break;
+ case '\r':
+ case '\n':
+ {
+ int next_c = getc_unlocked (stream);
+
+ if (!(c == EOF ||
+ (c == '\r' && next_c == '\n') ||
+ (c == '\n' && next_c == '\r')))
+ ungetc (next_c, stream);
+
+ break;
+ }
+ default:
+ g_string_append_c (str, '\\');
+ g_string_append_c (str, c);
+ }
+ }
+ else
+ {
+ switch (c)
+ {
+ case '#':
+ comment = TRUE;
+ break;
+ case '\\':
+ if (!comment)
+ quoted = TRUE;
+ break;
+ case '\n':
+ {
+ int next_c = getc_unlocked (stream);
+
+ if (!(c == EOF ||
+ (c == '\r' && next_c == '\n') ||
+ (c == '\n' && next_c == '\r')))
+ ungetc (next_c, stream);
+
+ goto done;
+ }
+ default:
+ if (!comment)
+ g_string_append_c (str, c);
+ }
+ }
+ }
+
+ done:
+
+ funlockfile (stream);
+
+ return n_read > 0;
+}
+
+/**
+ * pango_skip_space:
+ * @pos: in/out string position
+ *
+ * Skips 0 or more characters of white space.
+ *
+ * Return value: %FALSE if skipping the white space leaves
+ * the position at a '\0' character.
+ **/
+gboolean
+pango_skip_space (const char **pos)
+{
+ const char *p = *pos;
+
+ while (isspace (*p))
+ p++;
+
+ *pos = p;
+
+ return !(*p == '\0');
+}
+
+/**
+ * pango_scan_word:
+ * @pos: in/out string position
+ * @out: a #GString into which to write the result
+ *
+ * Scan a word into a #GString buffer. A word consists
+ * of [A-Za-z_] followed by zero or more [A-Za-z_0-9]
+ * Leading white space is skipped.
+ *
+ * Return value: %FALSE if a parse error occured.
+ **/
+gboolean
+pango_scan_word (const char **pos, GString *out)
+{
+ const char *p = *pos;
+
+ while (isspace (*p))
+ p++;
+
+ if (!((*p >= 'A' && *p <= 'Z') ||
+ (*p >= 'a' && *p <= 'z') ||
+ *p == '_'))
+ return FALSE;
+
+ g_string_truncate (out, 0);
+ g_string_append_c (out, *p);
+ p++;
+
+ while ((*p >= 'A' && *p <= 'Z') ||
+ (*p >= 'a' && *p <= 'z') ||
+ (*p >= '0' && *p <= '9') ||
+ *p == '_')
+ {
+ g_string_append_c (out, *p);
+ p++;
+ }
+
+ *pos = p;
+
+ return TRUE;
+}
+
+/**
+ * pango_scan_string:
+ * @pos: in/out string position
+ * @out: a #GString into which to write the result
+ *
+ * Scan a string into a #GString buffer. The string may either
+ * be a sequence of non-white-space characters, or a quoted
+ * string with '"'. Instead a quoted string, '\"' represents
+ * a literal quote. Leading white space outside of quotes is skipped.
+ *
+ * Return value: %FALSE if a parse error occured.
+ **/
+gboolean
+pango_scan_string (const char **pos, GString *out)
+{
+ const char *p = *pos;
+
+ while (isspace (*p))
+ p++;
+
+ if (!*p)
+ return FALSE;
+ else if (*p == '"')
+ {
+ gboolean quoted = FALSE;
+ g_string_truncate (out, 0);
+
+ p++;
+
+ while (TRUE)
+ {
+ if (quoted)
+ {
+ int c = *p;
+
+ switch (c)
+ {
+ case '\0':
+ return FALSE;
+ case 'n':
+ c = '\n';
+ break;
+ case 't':
+ c = '\t';
+ break;
+ }
+
+ quoted = FALSE;
+ g_string_append_c (out, c);
+ }
+ else
+ {
+ switch (*p)
+ {
+ case '\0':
+ return FALSE;
+ case '\\':
+ quoted = TRUE;
+ break;
+ case '"':
+ p++;
+ goto done;
+ default:
+ g_string_append_c (out, *p);
+ break;
+ }
+ }
+ p++;
+ }
+ done:
+ }
+ else
+ {
+ g_string_truncate (out, 0);
+
+ while (*p && !isspace (*p))
+ {
+ g_string_append_c (out, *p);
+ p++;
+ }
+ }
+
+ *pos = p;
+
+ return TRUE;
+}
+
+gboolean
+pango_scan_int (const char **pos, int *out)
+{
+ int i = 0;
+ char buf[32];
+ const char *p = *pos;
+
+ while (isspace (*p))
+ p++;
+
+ if (*p < '0' || *p > '9')
+ return FALSE;
+
+ while ((*p >= '0') && (*p <= '9') && i < sizeof(buf))
+ {
+ buf[i] = *p;
+ i++;
+ p++;
+ }
+
+ if (i == sizeof(buf))
+ return FALSE;
+ else
+ buf[i] = '\0';
+
+ *out = atoi (buf);
+
+ return TRUE;
+}
+
+static GHashTable *config_hash = NULL;
+
+static void
+read_config_file (const char *filename, gboolean enoent_error)
+{
+ FILE *file;
+
+ GString *line_buffer = g_string_new (NULL);
+ GString *tmp_buffer1 = g_string_new (NULL);
+ GString *tmp_buffer2 = g_string_new (NULL);
+ char *errstring = NULL;
+ const char *pos;
+ char *section = NULL;
+ int line = 0;
+
+ file = fopen (filename, "r");
+ if (!file)
+ {
+ if (errno != ENOENT || enoent_error)
+ fprintf (stderr, "Pango:%s: Error opening config file: %s\n",
+ filename, g_strerror (errno));
+ return;
+ }
+
+ while (pango_read_line (file, line_buffer))
+ {
+ line++;
+
+ pos = line_buffer->str;
+ if (!pango_skip_space (&pos))
+ continue;
+
+ if (*pos == '[') /* Section */
+ {
+ pos++;
+ if (!pango_skip_space (&pos) ||
+ !pango_scan_word (&pos, tmp_buffer1) ||
+ !pango_skip_space (&pos) ||
+ *(pos++) != ']' ||
+ pango_skip_space (&pos))
+ {
+ errstring = g_strdup ("Error parsing [SECTION] declaration");
+ goto error;
+ }
+
+ section = g_strdup (tmp_buffer1->str);
+ }
+ else /* Key */
+ {
+ gboolean empty = FALSE;
+ gboolean append = FALSE;
+ char *k, *v;
+
+ if (!section)
+ {
+ errstring = g_strdup ("A [SECTION] declaration must occur first");
+ goto error;
+ }
+
+ if (!pango_scan_word (&pos, tmp_buffer1) ||
+ !pango_skip_space (&pos))
+ {
+ errstring = g_strdup ("Line is not of the form KEY=VALUE or KEY+=VALUE");
+ goto error;
+ }
+ if (*pos == '+')
+ {
+ append = TRUE;
+ pos++;
+ }
+
+ if (*(pos++) != '=')
+ {
+ errstring = g_strdup ("Line is not of the form KEY=VALUE or KEY+=VALUE");
+ goto error;
+ }
+
+ if (!pango_skip_space (&pos))
+ {
+ empty = TRUE;
+ }
+ else
+ {
+ if (!pango_scan_string (&pos, tmp_buffer2))
+ {
+ errstring = g_strdup ("Error parsing value string");
+ goto error;
+ }
+ if (pango_skip_space (&pos))
+ {
+ errstring = g_strdup ("Junk after value string");
+ goto error;
+ }
+ }
+
+ g_string_prepend_c (tmp_buffer1, '/');
+ g_string_prepend (tmp_buffer1, section);
+
+ /* Remove any existing values */
+ if (g_hash_table_lookup_extended (config_hash, tmp_buffer1->str,
+ (gpointer *)&k, (gpointer *)&v))
+ {
+ g_free (k);
+ if (append)
+ {
+ g_string_prepend (tmp_buffer2, v);
+ g_free (v);
+ }
+ }
+
+ if (!empty)
+ {
+ g_hash_table_insert (config_hash,
+ g_strdup (tmp_buffer1->str),
+ g_strdup (tmp_buffer2->str));
+ }
+ }
+ }
+
+ if (ferror (file))
+ errstring = g_strdup ("g_strerror(errno)");
+
+ error:
+
+ if (errstring)
+ {
+ fprintf (stderr, "Pango:%s:%d: %s\n", filename, line, errstring);
+ g_free (errstring);
+ }
+
+ g_free (section);
+ g_string_free (line_buffer, TRUE);
+ g_string_free (tmp_buffer1, TRUE);
+ g_string_free (tmp_buffer2, TRUE);
+
+ fclose (file);
+}
+
+static void
+read_config ()
+{
+ if (!config_hash)
+ {
+ char *filename;
+
+ config_hash = g_hash_table_new (g_str_hash, g_str_equal);
+ read_config_file (SYSCONFDIR "/" "pango/pangorc", FALSE);
+
+ filename = g_strconcat (g_get_home_dir (), "/.pangorc", NULL);
+ read_config_file (filename, FALSE);
+ g_free (filename);
+
+ filename = g_getenv ("PANGO_RC_FILE");
+ if (filename)
+ read_config_file (filename, TRUE);
+ }
+}
+
+/**
+ * pango_config_key_get:
+ * @key: Key to look up, in the form "SECTION/KEY".
+ *
+ * Look up a key in the pango config database
+ * (pseudo-win.ini style, read from $sysconfdir/pango/pangorc,
+ * ~/.pangorc, and getenv (PANGO_RC_FILE).)
+ *
+ * Return value: the value, if found, otherwise %NULL. The value is a
+ * newly-allocated string and must be freed with g_free().
+ **/
+char *
+pango_config_key_get (const char *key)
+{
+ g_return_val_if_fail (key != NULL, NULL);
+
+ read_config ();
+
+ return g_strdup (g_hash_table_lookup (config_hash, key));
+}
diff --git a/pango/pango-utils.h b/pango/pango-utils.h
new file mode 100644
index 00000000..fe4f638d
--- /dev/null
+++ b/pango/pango-utils.h
@@ -0,0 +1,40 @@
+/* Pango
+ * pango-utils.c: Utilities for internal functions and modules
+ *
+ * Copyright (C) 2000 Red Hat Software
+ *
+ * This 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.
+ *
+ * This 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 this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <glib.h>
+
+char *pango_trim_string (const char *str);
+char ** pango_split_file_list (const char *str);
+
+gboolean pango_read_line (FILE *stream,
+ GString *str);
+
+gboolean pango_skip_space (const char **pos);
+gboolean pango_scan_word (const char **pos,
+ GString *out);
+gboolean pango_scan_string (const char **pos,
+ GString *out);
+gboolean pango_scan_int (const char **pos,
+ int *out);
+
+char * pango_config_key_get (const char *key);
+