source: trunk/gtk/util.c @ 1125

Last change on this file since 1125 was 760, checked in by joshe, 15 years ago

Change all my 2-clause BSD licenses to the same MIT/X11 license as libtransmission.

  • Property svn:keywords set to Date Rev Author Id
File size: 8.4 KB
Line 
1/******************************************************************************
2 * $Id: util.c 760 2006-08-13 00:26:52Z livings124 $
3 *
4 * Copyright (c) 2005-2006 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <errno.h>
28#include <signal.h>
29#include <stdarg.h>
30#include <string.h>
31#include <unistd.h>
32
33#include <gtk/gtk.h>
34#include <glib/gi18n.h>
35
36#include "tr_torrent.h"
37#include "util.h"
38
39#define BESTDECIMAL(d)          (10.0 > (d) ? 2 : (100.0 > (d) ? 1 : 0))
40
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) {
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", BESTDECIMAL(small), small,
80                         gettext(sizestrs[ii]));
81}
82
83#define SECONDS(s)              ((s) % 60)
84#define MINUTES(s)              ((s) / 60 % 60)
85#define HOURS(s)                ((s) / 60 / 60 % 24)
86#define DAYS(s)                 ((s) / 60 / 60 / 24 % 7)
87#define WEEKS(s)                ((s) / 60 / 60 / 24 / 7)
88
89char *
90readabletime(int secs) {
91  if(60 > secs)
92    return g_strdup_printf(_("%i %s"),
93      SECONDS(secs), ngettext("second", "seconds", SECONDS(secs)));
94  else if(60 * 60 > secs)
95    return g_strdup_printf(_("%i %s %i %s"),
96      MINUTES(secs), ngettext("minute", "minutes", MINUTES(secs)),
97      SECONDS(secs), ngettext("second", "seconds", SECONDS(secs)));
98  else if(60 * 60 * 24 > secs)
99    return g_strdup_printf(_("%i %s %i %s"),
100      HOURS(secs),   ngettext("hour", "hours", HOURS(secs)),
101      MINUTES(secs), ngettext("minute", "minutes", MINUTES(secs)));
102  else if(60 * 60 * 24 * 7 > secs)
103    return g_strdup_printf(_("%i %s %i %s"),
104      DAYS(secs),    ngettext("day", "days", DAYS(secs)),
105      HOURS(secs),   ngettext("hour", "hours", HOURS(secs)));
106  else
107    return g_strdup_printf(_("%i %s %i %s"),
108      WEEKS(secs),   ngettext("week", "weeks", WEEKS(secs)),
109      DAYS(secs),    ngettext("hour", "hours", DAYS(secs)));
110}
111
112char *
113ratiostr(guint64 down, guint64 up) {
114  double ratio;
115
116  if(0 == up && 0 == down)
117    return g_strdup(_("N/A"));
118
119  if(0 == down)
120    /* this is a UTF-8 infinity symbol */
121    return g_strdup(_("\xE2\x88\x9E"));
122
123  ratio = (double)up / (double)down;
124
125  return g_strdup_printf("%.*f", BESTDECIMAL(ratio), ratio);
126}
127
128gboolean
129mkdir_p(const char *name, mode_t mode) {
130  struct stat sb;
131  char *parent;
132  gboolean ret;
133  int oerrno;
134
135  if(0 != stat(name, &sb)) {
136    if(ENOENT != errno)
137      return FALSE;
138    parent = g_path_get_dirname(name);
139    ret = mkdir_p(parent, mode);
140    oerrno = errno;
141    g_free(parent);
142    errno = oerrno;
143    return (ret ? (0 == mkdir(name, mode)) : FALSE);
144  }
145
146  if(!S_ISDIR(sb.st_mode)) {
147    errno = ENOTDIR;
148    return FALSE;
149  }
150
151  return TRUE;
152}
153
154char *
155joinstrlist(GList *list, char *sep) {
156  GList *ii;
157  int len;
158  char *ret, *dest;
159
160  if(0 > (len = strlen(sep) * (g_list_length(list) - 1)))
161    return NULL;
162
163  for(ii = g_list_first(list); NULL != ii; ii = ii->next)
164    len += strlen(ii->data);
165
166  dest = ret = g_new(char, len + 1);
167
168  for(ii = g_list_first(list); NULL != ii; ii = ii->next) {
169    dest = g_stpcpy(dest, ii->data);
170    if(NULL != ii->next)
171      dest = g_stpcpy(dest, sep);
172  }
173
174  return ret;
175}
176
177void
178freestrlist(GList *list) {
179  GList *ii;
180
181  if(NULL != list) {
182    for(ii = g_list_first(list); NULL != ii; ii = ii->next)
183      g_free(ii->data);
184    g_list_free(list);
185  }
186}
187
188char *
189urldecode(const char *str, int len) {
190  int ii, jj;
191  char *ret;
192  char buf[3];
193
194  if(0 >= len)
195    len = strlen(str);
196
197  for(ii = jj = 0; ii < len; ii++, jj++)
198    if('%' == str[ii])
199      ii += 2;
200
201  ret = g_new(char, jj + 1);
202
203  buf[2] = '\0';
204  for(ii = jj = 0; ii < len; ii++, jj++) {
205    switch(str[ii]) {
206      case '%':
207        if(ii + 2 < len) {
208          buf[0] = str[ii+1];
209          buf[1] = str[ii+2];
210          ret[jj] = g_ascii_strtoull(buf, NULL, 16);
211        }
212        ii += 2;
213        break;
214      case '+':
215        ret[jj] = ' ';
216      default:
217        ret[jj] = str[ii];
218    }
219  }
220  ret[jj] = '\0';
221
222  return ret;
223}
224
225GList *
226checkfilenames(int argc, char **argv) {
227  char *pwd = g_get_current_dir();
228  int ii, cd;
229  char *dirstr, *filestr;
230  GList *ret = NULL;
231
232  for(ii = 0; ii < argc; ii++) {
233    dirstr = g_path_get_dirname(argv[ii]);
234    if(!g_path_is_absolute(argv[ii])) {
235      filestr = g_build_filename(pwd, dirstr, NULL);
236      g_free(dirstr);
237      dirstr = filestr;
238    }
239    cd = chdir(dirstr);
240    g_free(dirstr);
241    if(0 > cd)
242      continue;
243    dirstr = g_get_current_dir();
244    filestr = g_path_get_basename(argv[ii]);
245    ret = g_list_append(ret, g_build_filename(dirstr, filestr, NULL));
246    g_free(dirstr);
247    g_free(filestr);
248  }
249
250  chdir(pwd);
251  g_free(pwd);
252
253  return ret;
254}
255
256guint
257addactionflag(const char *action) {
258  if(NULL == action)
259    return TR_TORNEW_SAVE_COPY;
260  else if(0 == strcmp("copy", action))
261    return TR_TORNEW_SAVE_COPY;
262  else if(0 == strcmp("move", action))
263    return TR_TORNEW_SAVE_MOVE;
264  else
265    return 0;
266}
267
268const char *
269addactionname(guint flag) {
270  static char name[6];
271
272  if(TR_TORNEW_SAVE_COPY & flag)
273    strcpy(name, "copy");
274  else if(TR_TORNEW_SAVE_MOVE & flag)
275    strcpy(name, "move");
276  else
277    strcpy(name, "leave");
278
279  return name;
280}
281
282GList *
283makeglist(void *ptr, ...) {
284  va_list ap;
285  GList *ret;
286
287  ret = g_list_append(NULL, ptr);
288
289  va_start(ap, ptr); 
290  while(NULL != (ptr = va_arg(ap, void*)))
291    ret = g_list_append(ret, ptr);
292  va_end(ap);
293
294  return ret;
295}
296
297GtkWidget *
298errmsg(GtkWindow *wind, const char *format, ...) {
299  GtkWidget *dialog;
300  va_list ap;
301
302  va_start(ap, format);
303  dialog = verrmsg(wind, NULL, NULL, format, ap);
304  va_end(ap);
305
306  return dialog;
307}
308
309GtkWidget *
310errmsg_full(GtkWindow *wind, callbackfunc_t func, void *data,
311            const char *format, ...) {
312  GtkWidget *dialog;
313  va_list ap;
314
315  va_start(ap, format);
316  dialog = verrmsg(wind, func, data, format, ap);
317  va_end(ap);
318
319  return dialog;
320}
321
322GtkWidget *
323verrmsg(GtkWindow *wind, callbackfunc_t func, void *data,
324        const char *format, va_list ap) {
325  GtkWidget *dialog;
326  char *msg;
327  GList *funcdata;
328
329  msg = g_strdup_vprintf(format, ap);
330
331  if(NULL == wind)
332    dialog = gtk_message_dialog_new(
333      NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", msg);
334  else
335    dialog = gtk_message_dialog_new(wind,
336      GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
337      GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", msg);
338
339  if(NULL == func)
340    funcdata = NULL;
341  else
342    funcdata = g_list_append(g_list_append(NULL, func), data);
343  g_signal_connect(dialog, "response", G_CALLBACK(errcb), funcdata);
344  if(NULL != wind)
345    gtk_widget_show(dialog);
346  g_free(msg);
347
348  return dialog;
349}
350
351static void
352errcb(GtkWidget *widget, int resp SHUTUP, gpointer data) {
353  GList *funcdata;
354  callbackfunc_t func;
355
356  if(NULL != data) {
357    funcdata = g_list_first(data);
358    func = funcdata->data;
359    data = funcdata->next->data;
360    func(data);
361    g_list_free(funcdata);
362  }
363
364  gtk_widget_destroy(widget);
365}
Note: See TracBrowser for help on using the repository browser.