add some functions for parsing a value in a .desktop file
[dana/openbox.git] / 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     ObtDDFileType type;
43     gchar *name; /*!< Specific name for the object (eg Firefox) */
44     gchar *generic; /*!< Generic name for the object (eg Web Browser) */
45     gchar *comment; /*!< Comment/description to display for the object */
46     gchar *icon; /*!< Name/path for an icon for the object */
47
48     union _ObtDDFileData {
49         struct {
50             gchar *exec; /*!< Executable to run for the app */
51             gchar *wdir; /*!< Working dir to run the app in */
52             gboolean term; /*!< Run the app in a terminal or not */
53             ObtDDFileAppOpen open;
54
55             /* XXX gchar**? or something better, a mime struct.. maybe
56                glib has something i can use. */
57             gchar **mime; /*!< Mime types the app can open */
58
59             ObtDDFileAppStartup startup;
60             gchar *startup_wmclass;
61         } app;
62         struct {
63             gchar *url;
64         } link;
65         struct {
66         } dir;
67     } d;
68 };
69
70 static void parse_error(const gchar *m, const ObtDDParse *const parse,
71                         gboolean *error)
72 {
73     if (!parse->filename)
74         g_warning("%s at line %lud of input\n", m, parse->lineno);
75     else
76         g_warning("%s at line %lud of file %s\n",
77                   m, parse->lineno, parse->filename);
78     if (error) *error = TRUE;
79 }
80
81 /* reads an input string, strips out invalid stuff, and parses
82    backslash-stuff */
83 static gchar* parse_string(const gchar *in, gboolean locale,
84                            const ObtDDParse *const parse,
85                            gboolean *error)
86 {
87     const gint bytes = strlen(in);
88     gboolean backslash;
89     gchar *out, *o;
90     const gchar *end, *i;
91
92     g_return_val_if_fail(in != NULL, NULL);
93
94     if (!locale) {
95         end = in + bytes;
96         for (i = in; i < end; ++i) {
97             if (*i > 127) {
98                 end = i;
99                 parse_error("Invalid bytes in string", parse, error);
100                 break;
101             }
102         }
103     }
104     else if (!g_utf8_validate(in, bytes, &end))
105         parse_error("Invalid bytes in localestring", parse, error);
106
107     out = g_new(char, bytes + 1);
108     i = in; o = out;
109     backslash = FALSE;
110     while (i < end) {
111         const gchar *next = locale ? g_utf8_find_next_char(i, end) : i+1;
112         if (backslash) {
113             switch(*i) {
114             case 's': *o++ = ' '; break;
115             case 'n': *o++ = '\n'; break;
116             case 't': *o++ = '\t'; break;
117             case 'r': *o++ = '\r'; break;
118             case '\\': *o++ = '\\'; break;
119             default:
120                 parse_error((locale ?
121                              "Invalid escape sequence in localestring" :
122                              "Invalid escape sequence in string"),
123                             parse, error);
124             }
125             backslash = FALSE;
126         }
127         else if (*i == '\\')
128             backslash = TRUE;
129         else {
130             memcpy(o, i, next-i);
131             o += next-i;
132         }
133         i = next;
134     }
135     *o = '\0';
136     return o;
137 }
138
139 static gboolean parse_bool(const gchar *in, const ObtDDParse *const parse,
140                            gboolean *error)
141 {
142     if (strcmp(in, "true") == 0)
143         return TRUE;
144     else if (strcmp(in, "false") != 0)
145         parse_error("Invalid boolean value", parse, error);
146     return FALSE;
147 }
148
149 static float parse_numeric(const gchar *in, const ObtDDParse *const parse,
150     gboolean *error)
151 {
152     float out = 0;
153     if (sscanf(in, "%f", &out) == 0)
154         parse_error("Invalid numeric value", parse, error);
155     return out;
156 }