source: trunk/gtk/util.c @ 242

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

Add IPC code for another process to communicate with a running

transmission-gtk instance.

Try to add any filenames found on the command-line, using IPC if

transmission-gtk is already running.

Some minor code cleanups.
Remove lockfile on a normal exit, justfor the sake of being tidy.

File size: 6.6 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#include <unistd.h>
34
35#include <gtk/gtk.h>
36#include <glib/gi18n.h>
37
38#include "util.h"
39
40#define BESTDECIMAL(d)          (10.0 > (d) ? 2 : (100.0 > (d) ? 1 : 0))
41
42static void
43errcb(GtkWidget *wind, int resp, gpointer data);
44
45gboolean
46strbool(const char *str) {
47  switch(str[0]) {
48    case 'y':
49    case 'Y':
50    case '1':
51    case 'j':
52    case 'e':
53      return TRUE;
54    default:
55      if(0 == g_ascii_strcasecmp("on", str))
56        return TRUE;
57      break;
58  }
59
60  return FALSE;
61}
62
63static const char *sizestrs[] = {
64  N_("B"), N_("KiB"), N_("MiB"), N_("GiB"), N_("TiB"), N_("PiB"), N_("EiB"),
65};
66
67char *
68readablesize(guint64 size) {
69  unsigned int ii;
70  double small = size;
71
72  for(ii = 0; ii + 1 < ALEN(sizestrs) && 1024.0 <= small / 1024.0; ii++)
73    small /= 1024.0;
74
75  if(1024.0 <= small) {
76    small /= 1024.0;
77    ii++;
78  }
79
80  return g_strdup_printf("%.*f %s", BESTDECIMAL(small), small,
81                         gettext(sizestrs[ii]));
82}
83
84char *
85ratiostr(guint64 down, guint64 up) {
86  double ratio;
87
88  if(0 == up && 0 == down)
89    return g_strdup(_("N/A"));
90
91  if(0 == down)
92    /* this is a UTF-8 infinity symbol */
93    return g_strdup(_("\xE2\x88\x9E"));
94
95  ratio = (double)up / (double)down;
96
97  return g_strdup_printf("%.*f", BESTDECIMAL(ratio), ratio);
98}
99
100gboolean
101mkdir_p(const char *name, mode_t mode) {
102  struct stat sb;
103  char *parent;
104  gboolean ret;
105  int oerrno;
106
107  if(0 != stat(name, &sb)) {
108    if(ENOENT != errno)
109      return FALSE;
110    parent = g_path_get_dirname(name);
111    ret = mkdir_p(parent, mode);
112    oerrno = errno;
113    g_free(parent);
114    errno = oerrno;
115    return (ret ? (0 == mkdir(name, mode)) : FALSE);
116  }
117
118  if(!S_ISDIR(sb.st_mode)) {
119    errno = ENOTDIR;
120    return FALSE;
121  }
122
123  return TRUE;
124}
125
126char *
127joinstrlist(GList *list, char *sep) {
128  GList *ii;
129  int len;
130  char *ret, *dest;
131
132  if(0 > (len = strlen(sep) * (g_list_length(list) - 1)))
133    return NULL;
134
135  for(ii = g_list_first(list); NULL != ii; ii = ii->next)
136    len += strlen(ii->data);
137
138  dest = ret = g_new(char, len + 1);
139
140  for(ii = g_list_first(list); NULL != ii; ii = ii->next) {
141    dest = g_stpcpy(dest, ii->data);
142    if(NULL != ii->next)
143      dest = g_stpcpy(dest, sep);
144  }
145
146  return ret;
147}
148
149void
150freestrlist(GList *list) {
151  GList *ii;
152
153  if(NULL != list) {
154    for(ii = g_list_first(list); NULL != ii; ii = ii->next)
155      g_free(ii->data);
156    g_list_free(list);
157  }
158}
159
160char *
161urldecode(const char *str, int len) {
162  int ii, jj;
163  char *ret;
164  char buf[3];
165
166  if(0 >= len)
167    len = strlen(str);
168
169  for(ii = jj = 0; ii < len; ii++, jj++)
170    if('%' == str[ii])
171      ii += 2;
172
173  ret = g_new(char, jj + 1);
174
175  buf[2] = '\0';
176  for(ii = jj = 0; ii < len; ii++, jj++) {
177    switch(str[ii]) {
178      case '%':
179        if(ii + 2 < len) {
180          buf[0] = str[ii+1];
181          buf[1] = str[ii+2];
182          ret[jj] = g_ascii_strtoull(buf, NULL, 16);
183        }
184        ii += 2;
185        break;
186      case '+':
187        ret[jj] = ' ';
188      default:
189        ret[jj] = str[ii];
190    }
191  }
192  ret[jj] = '\0';
193
194  return ret;
195}
196
197GList *
198checkfilenames(int argc, char **argv) {
199  char *pwd = g_get_current_dir();
200  int ii, cd;
201  char *dirstr, *filestr;
202  GList *ret = NULL;
203
204  for(ii = 0; ii < argc; ii++) {
205    dirstr = g_path_get_dirname(argv[ii]);
206    if(!g_path_is_absolute(argv[ii])) {
207      filestr = g_build_filename(pwd, dirstr, NULL);
208      g_free(dirstr);
209      dirstr = filestr;
210    }
211    cd = chdir(dirstr);
212    g_free(dirstr);
213    if(0 > cd)
214      continue;
215    dirstr = g_get_current_dir();
216    filestr = g_path_get_basename(argv[ii]);
217    ret = g_list_append(ret, g_build_filename(dirstr, filestr, NULL));
218    g_free(dirstr);
219    g_free(filestr);
220  }
221
222  chdir(pwd);
223  g_free(pwd);
224
225  return ret;
226}
227
228GtkWidget *
229errmsg(GtkWindow *wind, const char *format, ...) {
230  GtkWidget *dialog;
231  va_list ap;
232
233  va_start(ap, format);
234  dialog = verrmsg(wind, NULL, NULL, format, ap);
235  va_end(ap);
236
237  return dialog;
238}
239
240GtkWidget *
241errmsg_full(GtkWindow *wind, callbackfunc_t func, void *data,
242            const char *format, ...) {
243  GtkWidget *dialog;
244  va_list ap;
245
246  va_start(ap, format);
247  dialog = verrmsg(wind, func, data, format, ap);
248  va_end(ap);
249
250  return dialog;
251}
252
253GtkWidget *
254verrmsg(GtkWindow *wind, callbackfunc_t func, void *data,
255        const char *format, va_list ap) {
256  GtkWidget *dialog;
257  char *msg;
258  GList *funcdata;
259
260  msg = g_strdup_vprintf(format, ap);
261
262  if(NULL == wind)
263    dialog = gtk_message_dialog_new(
264      NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", msg);
265  else
266    dialog = gtk_message_dialog_new(wind,
267      GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
268      GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", msg);
269
270  if(NULL == func)
271    funcdata = NULL;
272  else
273    funcdata = g_list_append(g_list_append(NULL, func), data);
274  g_signal_connect(dialog, "response", G_CALLBACK(errcb), funcdata);
275  if(NULL != wind)
276    gtk_widget_show(dialog);
277  g_free(msg);
278
279  return dialog;
280}
281
282static void
283errcb(GtkWidget *widget, int resp SHUTUP, gpointer data) {
284  GList *funcdata;
285  callbackfunc_t func;
286
287  if(NULL != data) {
288    funcdata = g_list_first(data);
289    func = funcdata->data;
290    data = funcdata->next->data;
291    func(data);
292    g_list_free(funcdata);
293  }
294
295  gtk_widget_destroy(widget);
296}
Note: See TracBrowser for help on using the repository browser.