initial import
[slovak-l10n] / ukeyboard / ukbdcreator / compiler.c
1 /*
2  *  Copyright (c) 2008 Jiri Benc <jbenc@upir.cz>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License version 2 as
6  *  published by the Free Software Foundation.
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License
14  *  along with this program; if not, write to the Free Software
15  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
16  */
17
18 #include <sys/types.h>
19 #include <sys/wait.h>
20 #include <unistd.h>
21 #include <stdlib.h>
22 #include <gtk/gtk.h>
23 #include <glib/gstdio.h>
24 #include <gconf/gconf.h>
25 #include <gconf/gconf-client.h>
26 #include "../vkb_compiler.h"
27 #include "ukbdcreator.h"
28
29 static gchar *saved_layout = NULL;
30 static gchar *saved_lang = NULL;
31 static gchar *act_layout = NULL;
32
33 struct priv {
34         char *buf;
35         size_t pos;
36         int fout;
37         gchar *lang;
38 };
39
40 static void error(void *p, int line, char *msg)
41 {
42         (void)p;
43         disp_compile_error(line, msg);
44 }
45
46 static int warning(void *p, int line, char *msg)
47 {
48         (void)p;
49         disp_compile_error(line, msg);
50         return -1;
51 }
52
53 static int get_line(void *p, void *buf, size_t size)
54 {
55         struct priv *priv = p;
56         size_t dpos = 0;
57         char *dbuf = buf;
58
59         while (priv->buf[priv->pos]) {
60                 if (dpos + 1 < size)
61                         dbuf[dpos++] = priv->buf[priv->pos];
62                 if (priv->buf[priv->pos++] == '\n')
63                         break;
64         }
65         dbuf[dpos] = '\0';
66         return (priv->buf[priv->pos] || dpos) ? 0 : -1;
67 }
68
69 static int write_buf(void *p, void *buf, size_t size)
70 {
71         struct priv *priv = p;
72
73         if (write(priv->fout, buf, size) != (ssize_t)size) {
74                 disp_error("Error writing temporary file");
75                 return -1;
76         }
77         return 0;
78 }
79
80 static off_t tell_buf(void *p)
81 {
82         struct priv *priv = p;
83
84         return lseek(priv->fout, 0, SEEK_CUR);
85 }
86
87 static void seek_buf(void *p, off_t pos)
88 {
89         struct priv *priv = p;
90
91         lseek(priv->fout, pos, SEEK_SET);
92 }
93
94 static void return_lang(void *p, char *lang)
95 {
96         struct priv *priv = p;
97
98         priv->lang = g_strdup(lang);
99 }
100
101 static struct compiler_ops ops = {
102         .get_line = get_line,
103         .write = write_buf,
104         .tell = tell_buf,
105         .seek = seek_buf,
106         .error = error,
107         .warning = warning,
108         .return_lang = return_lang,
109 };
110
111 gboolean compile_layout(gchar *buf, gchar **fname, gchar **lang)
112 {
113         struct priv priv;
114         int res;
115
116         priv.buf = buf;
117         priv.pos = 0;
118         priv.lang = NULL;
119
120         *fname = g_build_filename(g_get_tmp_dir(), "ukbdXXXXXX", NULL);
121         priv.fout = g_mkstemp(*fname);
122         if (priv.fout < 0) {
123                 g_free(*fname);
124                 disp_error("Error creating temporary file");
125                 return FALSE;
126         }
127         res = compile(&ops, &priv);
128         close(priv.fout);
129         if (res < 0) {
130                 g_unlink(*fname);
131                 g_free(*fname);
132                 g_free(priv.lang);
133                 return FALSE;
134         }
135         *lang = priv.lang;
136         return TRUE;
137 }
138
139 static gchar *get_lang(GConfClient *conf)
140 {
141         return gconf_client_get_string(conf,
142                 "/apps/osso/inputmethod/hildon-im-languages/language-0", NULL);
143 }
144
145 static void set_lang(GConfClient *conf, gchar *val)
146 {
147         gconf_client_set_string(conf,
148                 "/apps/osso/inputmethod/hildon-im-languages/language-0", val, NULL);
149 }
150
151 void test_layout(GConfClient *conf, gchar *fname, gchar *lang)
152 {
153         gchar *cmd;
154         int res;
155
156         if (saved_lang)
157                 restore_layout(conf, FALSE);
158         cmd = g_strdup_printf("sudo /usr/libexec/ukeyboard-set -s %s %s", fname, lang);
159         res = system(cmd);
160         g_free(cmd);
161         if (!WIFEXITED(res)) {
162                 disp_error("Cannot execute helper script");
163                 return;
164         }
165         res = WEXITSTATUS(res);
166         if (res == 2) {
167                 disp_error("Redefining a system language is not possible");
168                 return;
169         }
170         if (res) {
171                 disp_error("Activating of the layout failed");
172                 return;
173         }
174         saved_lang = g_strdup(lang);
175         saved_layout = get_lang(conf);
176         set_lang(conf, "en_GB");
177         set_lang(conf, lang);
178         if (act_layout) {
179                 g_unlink(act_layout);
180                 g_free(act_layout);
181         }
182         act_layout = g_strdup(fname);
183         disp_info("Layout activated");
184 }
185
186 void restore_layout(GConfClient *conf, gboolean warn)
187 {
188         gchar *cmd;
189         int res;
190
191         if (!saved_lang) {
192                 if (warn)
193                         disp_info("No layout to restore");
194                 return;
195         }
196         cmd = g_strdup_printf("sudo /usr/libexec/ukeyboard-set -r %s", saved_lang);
197         res = system(cmd);
198         g_free(cmd);
199         if (!WIFEXITED(res)) {
200                 disp_error("Cannot execute helper script");
201                 return;
202         }
203         res = WEXITSTATUS(res);
204         if (res) {
205                 disp_error("Restoring of original layout failed");
206                 return;
207         }
208         set_lang(conf, "en_GB");
209         set_lang(conf, saved_layout);
210         g_free(saved_lang);
211         g_free(saved_layout);
212         saved_lang = saved_layout = NULL;
213         if (act_layout) {
214                 g_unlink(act_layout);
215                 g_free(act_layout);
216                 act_layout = NULL;
217         }
218         if (warn)
219                 disp_info("Layout restored");
220 }
221