1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 obt/ddfile.c for the Openbox window manager
4 Copyright (c) 2009 Dana Jansens
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 See the COPYING file for a copy of the GNU General Public License.
19 #include "obt/ddfile.h"
28 typedef struct _ObtDDParse {
45 gchar *name; /*!< Specific name for the object (eg Firefox) */
46 gchar *generic; /*!< Generic name for the object (eg Web Browser) */
47 gchar *comment; /*!< Comment/description to display for the object */
48 gchar *icon; /*!< Name/path for an icon for the object */
50 union _ObtDDFileData {
52 gchar *exec; /*!< Executable to run for the app */
53 gchar *wdir; /*!< Working dir to run the app in */
54 gboolean term; /*!< Run the app in a terminal or not */
55 ObtDDFileAppOpen open;
57 /* XXX gchar**? or something better, a mime struct.. maybe
58 glib has something i can use. */
59 gchar **mime; /*!< Mime types the app can open */
61 ObtDDFileAppStartup startup;
62 gchar *startup_wmclass;
72 static void parse_error(const gchar *m, const ObtDDParse *const parse,
76 g_warning("%s at line %lu of input\n", m, parse->lineno);
78 g_warning("%s at line %lu of file %s\n",
79 m, parse->lineno, parse->filename);
80 if (error) *error = TRUE;
83 /* reads an input string, strips out invalid stuff, and parses
85 static gchar* parse_string(const gchar *in, gboolean locale,
86 const ObtDDParse *const parse,
89 const gint bytes = strlen(in);
94 g_return_val_if_fail(in != NULL, NULL);
98 for (i = in; i < end; ++i) {
99 if (*i > 126 || *i < 32) { /* non-control character ascii */
101 parse_error("Invalid bytes in string", parse, error);
106 else if (!g_utf8_validate(in, bytes, &end))
107 parse_error("Invalid bytes in localestring", parse, error);
109 out = g_new(char, bytes + 1);
113 const gchar *next = locale ? g_utf8_find_next_char(i, end) : i+1;
116 case 's': *o++ = ' '; break;
117 case 'n': *o++ = '\n'; break;
118 case 't': *o++ = '\t'; break;
119 case 'r': *o++ = '\r'; break;
120 case '\\': *o++ = '\\'; break;
122 parse_error((locale ?
123 "Invalid escape sequence in localestring" :
124 "Invalid escape sequence in string"),
131 else if (*i >= 127 || *i < 32) { /* avoid ascii control characters */
132 parse_error("Found control character in string", parse, error);
136 memcpy(o, i, next-i);
145 static gboolean parse_bool(const gchar *in, const ObtDDParse *const parse,
148 if (strcmp(in, "true") == 0)
150 else if (strcmp(in, "false") != 0)
151 parse_error("Invalid boolean value", parse, error);
155 static float parse_numeric(const gchar *in, const ObtDDParse *const parse,
159 if (sscanf(in, "%f", &out) == 0)
160 parse_error("Invalid numeric value", parse, error);
164 gboolean parse_file_line(FILE *f, gchar **buf, gulong *size, gulong *read,
165 ObtDDParse *parse, gboolean *error)
167 const gulong BUFMUL = 80;
172 g_assert(*read == 0);
174 *buf = g_new(char, *size);
177 /* remove everything up to a null zero already in the buffer and shift
178 the rest to the front */
180 for (i = 0; i < *read; ++i) {
182 (*buf)[i-null-1] = (*buf)[i];
183 else if ((*buf)[i] == '\0')
189 /* is there already a newline in the buffer? */
190 for (i = 0; i < *read; ++i)
191 if ((*buf)[i] == '\n') {
192 /* turn it into a null zero and done */
197 /* we need to read some more to find a newline */
202 newread = *buf + *read;
203 ret = fread(newread, sizeof(char), *size-*read, f);
204 if (ret < *size - *read && !feof(f)) {
205 parse_error("Error reading", parse, error);
210 /* strip out null zeros in the input and look for an endofline */
213 for (i = newread-*buf; i < *read; ++i) {
215 (*buf)[i] = (*buf)[i+null];
216 if ((*buf)[i] == '\0') {
221 else if ((*buf)[i] == '\n' && eol == *size) {
223 /* turn it into a null zero */
229 /* found an endofline, done */
231 else if (feof(f) && *read < *size) {
232 /* found the endoffile, done (if there is space) */
234 /* stick a null zero on if there is test on the last line */
235 (*buf)[(*read)++] = '\0';
242 *buf = g_renew(char, *buf, *size);
248 static gboolean parse_file(ObtDDFile *dd, FILE *f, ObtDDParse *parse)
251 gulong bytes = 0, read = 0;
252 gboolean error = FALSE;
254 while (parse_file_line(f, &buf, &bytes, &read, parse, &error)) {
255 /* XXX use the string in buf */
259 if (buf) g_free(buf);
263 ObtDDFile* obt_ddfile_new_from_file(const gchar *name, GSList *paths)
270 dd = g_slice_new(ObtDDFile);
274 for (it = paths; it && !f; it = g_slist_next(it)) {
275 gchar *path = g_strdup_printf("%s/%s", (char*)it->data, name);
276 if ((f = fopen(path, "r"))) {
277 parse.filename = path;
279 if (!parse_file(dd, f, &parse)) f = NULL;
283 obt_ddfile_unref(dd);
289 void obt_ddfile_ref(ObtDDFile *dd)
294 void obt_ddfile_unref(ObtDDFile *dd)
297 g_slice_free(ObtDDFile, dd);