]> Dogcows Code - chaz/openbox/blob - obt/ddfile.c
add beginning of .desktop file parsing, grabs a line of text from the input file...
[chaz/openbox] / obt / ddfile.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3 obt/ddfile.c for the Openbox window manager
4 Copyright (c) 2009 Dana Jansens
5
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.
10
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.
15
16 See the COPYING file for a copy of the GNU General Public License.
17 */
18
19 #include "obt/ddfile.h"
20 #include <glib.h>
21 #ifdef HAVE_STRING_H
22 #include <string.h>
23 #endif
24 #ifdef HAVE_STDIO_H
25 #include <stdio.h>
26 #endif
27
28 typedef struct _ObtDDParse {
29 gchar *filename;
30 gulong lineno;
31 } ObtDDParse;
32
33 typedef enum {
34 DATA_STRING,
35 DATA_LOCALESTRING,
36 DATA_BOOLEAN,
37 DATA_NUMERIC,
38 NUM_DATA_TYPES
39 } ObtDDDataType;
40
41 struct _ObtDDFile {
42 guint ref;
43
44 ObtDDFileType type;
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 */
49
50 union _ObtDDFileData {
51 struct {
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;
56
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 */
60
61 ObtDDFileAppStartup startup;
62 gchar *startup_wmclass;
63 } app;
64 struct {
65 gchar *url;
66 } link;
67 struct {
68 } dir;
69 } d;
70 };
71
72 static void parse_error(const gchar *m, const ObtDDParse *const parse,
73 gboolean *error)
74 {
75 if (!parse->filename)
76 g_warning("%s at line %lu of input\n", m, parse->lineno);
77 else
78 g_warning("%s at line %lu of file %s\n",
79 m, parse->lineno, parse->filename);
80 if (error) *error = TRUE;
81 }
82
83 /* reads an input string, strips out invalid stuff, and parses
84 backslash-stuff */
85 static gchar* parse_string(const gchar *in, gboolean locale,
86 const ObtDDParse *const parse,
87 gboolean *error)
88 {
89 const gint bytes = strlen(in);
90 gboolean backslash;
91 gchar *out, *o;
92 const gchar *end, *i;
93
94 g_return_val_if_fail(in != NULL, NULL);
95
96 if (!locale) {
97 end = in + bytes;
98 for (i = in; i < end; ++i) {
99 if (*i > 127) {
100 end = i;
101 parse_error("Invalid bytes in string", parse, error);
102 break;
103 }
104 }
105 }
106 else if (!g_utf8_validate(in, bytes, &end))
107 parse_error("Invalid bytes in localestring", parse, error);
108
109 out = g_new(char, bytes + 1);
110 i = in; o = out;
111 backslash = FALSE;
112 while (i < end) {
113 const gchar *next = locale ? g_utf8_find_next_char(i, end) : i+1;
114 if (backslash) {
115 switch(*i) {
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;
121 default:
122 parse_error((locale ?
123 "Invalid escape sequence in localestring" :
124 "Invalid escape sequence in string"),
125 parse, error);
126 }
127 backslash = FALSE;
128 }
129 else if (*i == '\\')
130 backslash = TRUE;
131 else {
132 memcpy(o, i, next-i);
133 o += next-i;
134 }
135 i = next;
136 }
137 *o = '\0';
138 return o;
139 }
140
141 static gboolean parse_bool(const gchar *in, const ObtDDParse *const parse,
142 gboolean *error)
143 {
144 if (strcmp(in, "true") == 0)
145 return TRUE;
146 else if (strcmp(in, "false") != 0)
147 parse_error("Invalid boolean value", parse, error);
148 return FALSE;
149 }
150
151 static float parse_numeric(const gchar *in, const ObtDDParse *const parse,
152 gboolean *error)
153 {
154 float out = 0;
155 if (sscanf(in, "%f", &out) == 0)
156 parse_error("Invalid numeric value", parse, error);
157 return out;
158 }
159
160 gboolean parse_file_line(FILE *f, gchar **buf, gulong *size, gulong *read,
161 ObtDDParse *parse, gboolean *error)
162 {
163 const gulong BUFMUL = 80;
164 size_t ret;
165 gulong i, null;
166
167 if (*size == 0) {
168 g_assert(*read == 0);
169 *size = BUFMUL;
170 *buf = g_new(char, *size);
171 }
172
173 /* remove everything up to a null zero already in the buffer and shift
174 the rest to the front */
175 null = *size;
176 for (i = 0; i < *read; ++i) {
177 if (null < *size)
178 (*buf)[i-null-1] = (*buf)[i];
179 else if ((*buf)[i] == '\0')
180 null = i;
181 }
182 if (null < *size)
183 *read -= null + 1;
184
185 /* is there already a newline in the buffer? */
186 for (i = 0; i < *read; ++i)
187 if ((*buf)[i] == '\n') {
188 /* turn it into a null zero and done */
189 (*buf)[i] = '\0';
190 return TRUE;
191 }
192
193 /* we need to read some more to find a newline */
194 while (TRUE) {
195 gulong eol;
196 gchar *newread;
197
198 newread = *buf + *read;
199 ret = fread(newread, sizeof(char), *size-*read, f);
200 if (ret < *size - *read && !feof(f)) {
201 parse_error("Error reading", parse, error);
202 return FALSE;
203 }
204 *read += ret;
205
206 /* strip out null zeros in the input and look for an endofline */
207 null = 0;
208 eol = *size;
209 for (i = newread-*buf; i < *read; ++i) {
210 if (null > 0)
211 (*buf)[i] = (*buf)[i+null];
212 if ((*buf)[i] == '\0') {
213 ++null;
214 --(*read);
215 --i; /* try again */
216 }
217 else if ((*buf)[i] == '\n' && eol == *size) {
218 eol = i;
219 /* turn it into a null zero */
220 (*buf)[i] = '\0';
221 }
222 }
223
224 if (eol != *size)
225 /* found an endofline, done */
226 break;
227 else if (feof(f) && *read < *size) {
228 /* found the endoffile, done (if there is space) */
229 if (*read > 0) {
230 /* stick a null zero on if there is test on the last line */
231 (*buf)[(*read)++] = '\0';
232 }
233 break;
234 }
235 else {
236 /* read more */
237 size += BUFMUL;
238 *buf = g_renew(char, *buf, *size);
239 }
240 }
241 return *read > 0;
242 }
243
244 static gboolean parse_file(ObtDDFile *dd, FILE *f, ObtDDParse *parse)
245 {
246 gchar *buf = NULL;
247 gulong bytes = 0, read = 0;
248 gboolean error = FALSE;
249
250 while (parse_file_line(f, &buf, &bytes, &read, parse, &error)) {
251 /* XXX use the string in buf */
252 ++parse->lineno;
253 }
254
255 if (buf) g_free(buf);
256 return !error;
257 }
258
259 ObtDDFile* obt_ddfile_new_from_file(const gchar *name, GSList *paths)
260 {
261 ObtDDFile *dd;
262 ObtDDParse parse;
263 GSList *it;
264 FILE *f;
265
266 dd = g_slice_new(ObtDDFile);
267 dd->ref = 1;
268
269 f = NULL;
270 for (it = paths; it && !f; it = g_slist_next(it)) {
271 gchar *path = g_strdup_printf("%s/%s", (char*)it->data, name);
272 if ((f = fopen(path, "r"))) {
273 parse.filename = path;
274 parse.lineno = 0;
275 if (!parse_file(dd, f, &parse)) f = NULL;
276 }
277 }
278 if (!f) {
279 obt_ddfile_unref(dd);
280 dd = NULL;
281 }
282 return dd;
283 }
284
285 void obt_ddfile_ref(ObtDDFile *dd)
286 {
287 ++dd->ref;
288 }
289
290 void obt_ddfile_unref(ObtDDFile *dd)
291 {
292 if (--dd->ref < 1) {
293 g_slice_free(ObtDDFile, dd);
294 }
295 }
This page took 0.044025 seconds and 4 git commands to generate.