source: trunk/gtk/util.c @ 125

Last change on this file since 125 was 125, checked in by joshe, 16 years ago

Improve libintl.h search and add a --gettext-prefix configure option.
Update a couple copyright dates that slipped through earlier.
Spell GTK as GTK+ in a couple of places.

File size: 6.9 KB
Line 
1/*
2  Copyright (c) 2005-2006 Joshua Elsasser. All rights reserved.
3   
4  Redistribution and use in source and binary forms, with or without
5  modification, are permitted provided that the following conditions
6  are met:
7   
8   1. Redistributions of source code must retain the above copyright
9      notice, this list of conditions and the following disclaimer.
10   2. Redistributions in binary form must reproduce the above copyright
11      notice, this list of conditions and the following disclaimer in the
12      documentation and/or other materials provided with the distribution.
13   
14  THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS "AS IS" AND
15  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24  POSSIBILITY OF SUCH DAMAGE.
25*/
26
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <errno.h>
30#include <signal.h>
31#include <stdarg.h>
32#include <string.h>
33
34#include <gtk/gtk.h>
35#include <glib/gi18n.h>
36
37#include "util.h"
38
39static void
40sigexithandler(int sig);
41static void
42errcb(GtkWidget *wind, int resp, gpointer data);
43
44gboolean
45strbool(const char *str) {
46  switch(str[0]) {
47    case 'y':
48    case 'Y':
49    case '1':
50    case 'j':
51    case 'e':
52      return TRUE;
53    default:
54      if(0 == g_ascii_strcasecmp("on", str))
55        return TRUE;
56      break;
57  }
58
59  return FALSE;
60}
61
62static const char *sizestrs[] = {
63  N_("B"), N_("KiB"), N_("MiB"), N_("GiB"), N_("TiB"), N_("PiB"), N_("EiB"),
64};
65
66char *
67readablesize(guint64 size, int decimals) {
68  unsigned int ii;
69  double small = size;
70
71  for(ii = 0; ii + 1 < ALEN(sizestrs) && 1024.0 <= small / 1024.0; ii++)
72    small /= 1024.0;
73
74  if(1024.0 <= small) {
75    small /= 1024.0;
76    ii++;
77  }
78
79  return g_strdup_printf("%.*f %s", decimals, small, gettext(sizestrs[ii]));
80}
81
82char *
83ratiostr(guint64 down, guint64 up) {
84  double ratio;
85
86  if(0 == up && 0 == down)
87    return g_strdup(_("N/A"));
88
89  if(0 == down)
90    /* this is a UTF-8 infinity symbol */
91    return g_strdup(_("\xE2\x88\x9E"));
92
93  ratio = (double)up / (double)down;
94
95  return g_strdup_printf("%.*f", (10.0 > ratio ? 2 : (100.0 > ratio ? 1 : 0)),
96                         ratio);
97}
98
99gboolean
100mkdir_p(const char *name, mode_t mode) {
101  struct stat sb;
102  char *parent;
103  gboolean ret;
104  int oerrno;
105
106  if(0 != stat(name, &sb)) {
107    if(ENOENT != errno)
108      return FALSE;
109    parent = g_path_get_dirname(name);
110    ret = mkdir_p(parent, mode);
111    oerrno = errno;
112    g_free(parent);
113    errno = oerrno;
114    return (ret ? (0 == mkdir(name, mode)) : FALSE);
115  }
116
117  if(!S_ISDIR(sb.st_mode)) {
118    errno = ENOTDIR;
119    return FALSE;
120  }
121
122  return TRUE;
123}
124
125char *
126joinstrlist(GList *list, char *sep) {
127  GList *ii;
128  int len;
129  char *ret, *dest;
130
131  if(0 > (len = strlen(sep) * (g_list_length(list) - 1)))
132    return NULL;
133
134  for(ii = g_list_first(list); NULL != ii; ii = ii->next)
135    len += strlen(ii->data);
136
137  dest = ret = g_new(char, len + 1);
138
139  for(ii = g_list_first(list); NULL != ii; ii = ii->next) {
140    dest = g_stpcpy(dest, ii->data);
141    if(NULL != ii->next)
142      dest = g_stpcpy(dest, sep);
143  }
144
145  return ret;
146}
147
148char *
149urldecode(const char *str, int len) {
150  int ii, jj;
151  char *ret;
152  char buf[3];
153
154  if(0 >= len)
155    len = strlen(str);
156
157  for(ii = jj = 0; ii < len; ii++, jj++)
158    if('%' == str[ii])
159      ii += 2;
160
161  ret = g_new(char, jj + 1);
162
163  buf[2] = '\0';
164  for(ii = jj = 0; ii < len; ii++, jj++) {
165    switch(str[ii]) {
166      case '%':
167        if(ii + 2 < len) {
168          buf[0] = str[ii+1];
169          buf[1] = str[ii+2];
170          ret[jj] = g_ascii_strtoull(buf, NULL, 16);
171        }
172        ii += 2;
173        break;
174      case '+':
175        ret[jj] = ' ';
176      default:
177        ret[jj] = str[ii];
178    }
179  }
180  ret[jj] = '\0';
181
182  return ret;
183}
184
185static int exit_sigs[] = {SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGUSR1, SIGUSR2};
186static callbackfunc_t exit_func = NULL;
187static void *exit_data = NULL;
188static int exit_block_level = 0;
189
190void
191setuphandlers(callbackfunc_t func, void *data) {
192  struct sigaction sa;
193  unsigned int ii;
194
195  exit_data = data;
196  exit_func = func;
197
198  bzero(&sa, sizeof(sa));
199  sa.sa_handler = sigexithandler;
200  for(ii = 0; ii < ALEN(exit_sigs); ii++)
201    sigaction(exit_sigs[ii], &sa, NULL);
202}
203
204void
205clearhandlers(void) {
206  struct sigaction sa;
207  unsigned int ii;
208
209  bzero(&sa, sizeof(sa));
210  sa.sa_handler = SIG_DFL;
211  for(ii = 0; ii < ALEN(exit_sigs); ii++)
212    sigaction(exit_sigs[ii], &sa, NULL);
213}
214
215static void
216sigexithandler(int sig) {
217  exit_func(exit_data);
218  clearhandlers();
219  raise(sig);
220}
221
222void
223blocksigs(void) {
224  sigset_t mask;
225  unsigned int ii;
226
227  if(0 < (exit_block_level++))
228    return;
229
230  sigemptyset(&mask);
231  for(ii = 0; ii < ALEN(exit_sigs); ii++)
232    sigaddset(&mask, exit_sigs[ii]);
233  sigprocmask(SIG_BLOCK, &mask, NULL);
234}
235
236void
237unblocksigs(void) {
238  sigset_t mask;
239  unsigned int ii;
240
241  if(0 < (--exit_block_level))
242    return;
243
244  sigemptyset(&mask);
245  for(ii = 0; ii < ALEN(exit_sigs); ii++)
246    sigaddset(&mask, exit_sigs[ii]);
247  sigprocmask(SIG_UNBLOCK, &mask, NULL);
248}
249
250GtkWidget *
251errmsg(GtkWindow *wind, const char *format, ...) {
252  GtkWidget *dialog;
253  va_list ap;
254
255  va_start(ap, format);
256  dialog = verrmsg(wind, NULL, NULL, format, ap);
257  va_end(ap);
258
259  return dialog;
260}
261
262GtkWidget *
263errmsg_full(GtkWindow *wind, callbackfunc_t func, void *data,
264            const char *format, ...) {
265  GtkWidget *dialog;
266  va_list ap;
267
268  va_start(ap, format);
269  dialog = verrmsg(wind, func, data, format, ap);
270  va_end(ap);
271
272  return dialog;
273}
274
275GtkWidget *
276verrmsg(GtkWindow *wind, callbackfunc_t func, void *data,
277        const char *format, va_list ap) {
278  GtkWidget *dialog;
279  char *msg;
280  GList *funcdata;
281
282  msg = g_strdup_vprintf(format, ap);
283
284  if(NULL == wind)
285    dialog = gtk_message_dialog_new(
286      NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", msg);
287  else
288    dialog = gtk_message_dialog_new(wind,
289      GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
290      GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", msg);
291
292  if(NULL == func)
293    funcdata = NULL;
294  else
295    funcdata = g_list_append(g_list_append(NULL, func), data);
296  g_signal_connect(dialog, "response", G_CALLBACK(errcb), funcdata);
297  if(NULL != wind)
298    gtk_widget_show(dialog);
299  g_free(msg);
300
301  return dialog;
302}
303
304static void
305errcb(GtkWidget *widget, int resp SHUTUP, gpointer data) {
306  GList *funcdata;
307  callbackfunc_t func;
308
309  if(NULL != data) {
310    funcdata = g_list_first(data);
311    func = funcdata->data;
312    data = funcdata->next->data;
313    func(data);
314    g_list_free(funcdata);
315  }
316
317  gtk_widget_destroy(widget);
318}
Note: See TracBrowser for help on using the repository browser.