1 /*
2  * Copyright (C) 2010, 2011 Igalia S.L.
3  *
4  * Contact: Iago Toral Quiroga <itoral@igalia.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License
8  * as published by the Free Software Foundation; version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19  * 02110-1301 USA
20  *
21  */
22 
23 /**
24  * SECTION:grl-util
25  * @short_description: utility functions
26  */
27 
28 #include "grl-util.h"
29 #include "grl-log.h"
30 
31 #include <string.h>
32 
33 /**
34  * grl_paging_translate:
35  * @skip: number of elements to skip
36  * @count: number of elements to retrieve
37  * @max_page_size: maximum value for page size (0 for unlimited size)
38  * @page_size: optimal page size
39  * @page_number: page which contain the first element to retrieve (starting at 1)
40  * @internal_offset: in the @page_number, offset where first element can be found (starting at 0)
41  *
42  * Grilo browsing implements a paging mechanism through @skip and @count values.
43  *
44  * But there are some services (like Jamendo or Flickr) where paging is done
45  * through a page number and page size: user request all elements in a page,
46  * specifying in most cases what is the page size.
47  *
48  * This function is a helper for this task, computing from @skip and @count what
49  * is the optimal value of page size (limited by @max_page_size), which page
50  * should the user request, and where requested data start inside the page.
51  *
52  * By optimal we mean that it computes those values so only one page is required
53  * to satisfy the data, using the smallest page size. If user is limiting page
54  * size, then more requests to services might be needed. But still page size
55  * will be an optimal value.
56  *
57  * If @page_size is @NULL, then page size will be @max_page_size. If the later
58  * is also 0, then page size will be #G_MAXUINT.
59  *
60  * Since: 0.1.6
61  **/
grl_paging_translate(guint skip,guint count,guint max_page_size,guint * page_size,guint * page_number,guint * internal_offset)62 void grl_paging_translate (guint skip,
63                            guint count,
64                            guint max_page_size,
65                            guint *page_size,
66                            guint *page_number,
67                            guint *internal_offset)
68 {
69   gulong _page_size;
70   gulong last_element;
71 
72   if (!page_size) {
73     if (max_page_size > 0) {
74       _page_size = max_page_size;
75     } else {
76       _page_size = G_MAXUINT;
77     }
78   } else {
79     if (skip < count) {
80       _page_size = skip + count;
81       if (max_page_size > 0) {
82         _page_size = CLAMP (_page_size, 0, max_page_size);
83       }
84     } else {
85       _page_size = count;
86       last_element = skip + count - 1;
87       while (skip/_page_size != last_element/_page_size &&
88              (max_page_size == 0 || _page_size < max_page_size)) {
89         _page_size++;
90       }
91     }
92     _page_size = CLAMP (_page_size, 0, G_MAXUINT);
93   }
94 
95   if (page_size) {
96     *page_size = _page_size;
97   }
98 
99   if (page_number) {
100     *page_number = skip/_page_size + 1;
101   }
102 
103   if (internal_offset) {
104     *internal_offset = skip%_page_size;
105   }
106 }
107 
108 /**
109  * grl_list_from_va: (skip)
110  * @p: first pointer
111  * @...: va_list pointers
112  *
113  * Returns a #GList containing the va_list pointers. Use @NULL to finalize them,
114  *
115  * Returns: a #GList.
116  *
117  * Since: 0.1.6
118  **/
119 GList *
grl_list_from_va(gpointer p,...)120 grl_list_from_va (gpointer p, ...)
121 {
122   GList *pointer_list = NULL;
123   gpointer next_pointer;
124   va_list va_pointers;
125 
126   va_start (va_pointers, p);
127   next_pointer = p;
128   while (next_pointer) {
129     pointer_list = g_list_prepend (pointer_list, next_pointer);
130     next_pointer = va_arg (va_pointers, gpointer);
131   }
132   va_end (va_pointers);
133 
134   return g_list_reverse (pointer_list);
135 }
136 
137 /**
138  * grl_date_time_from_iso8601:
139  * @date: a date expressed in iso8601 format
140  *
141  * Returns: a newly-allocated #GDateTime set to the time corresponding to
142  * @date, or %NULL if @date could not be parsed properly.
143  *
144  * Since: 0.2.0
145  */
146 GDateTime *
grl_date_time_from_iso8601(const gchar * date)147 grl_date_time_from_iso8601 (const gchar *date)
148 {
149   GDateTime *converted;
150   gchar *date_time;
151   gint date_length;
152 
153   if (!date) {
154     return NULL;
155   }
156 
157   converted = g_date_time_new_from_iso8601 (date, NULL);
158   if (converted == NULL) {
159 
160     /* We might be in the case where there is a date alone. In that case, we
161      * take the convention of setting it to noon GMT */
162 
163     /* Date can could be YYYY, YYYY-MM, YYYY-MM-DD or YYYYMMDD */
164     date_length = strlen (date);
165     switch (date_length) {
166     case 4:
167       date_time = g_strdup_printf ("%s-01-01T12:00:00Z", date);
168       break;
169     case 7:
170       date_time = g_strdup_printf ("%s-01T12:00:00Z", date);
171       break;
172     default:
173       date_time = g_strdup_printf ("%sT12:00:00Z", date);
174     }
175     converted = g_date_time_new_from_iso8601 (date_time, NULL);
176 
177     if (converted == NULL)
178       GRL_DEBUG ("Failed to convert %s and %s to ISO8601", date, date_time);
179 
180     g_free (date_time);
181   }
182 
183   return converted;
184 }
185 
186