source: trunk/gtk/util.c @ 320

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

Add support to the GTK GUI for saving private copies of torrent files.
The prefs dialog for this sucks, but it should work.

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