FIX: array initialized from parenthesized string constant (compilation)
[quvi-tool.git] / src / util / xchg.c
blobd60ee2fad9df45f11bcd8f01cff0e22f6a42a379
1 /* quvi
2 * Copyright (C) 2012 Toni Gundogdu <legatvs@gmail.com>
4 * This file is part of quvi <http://quvi.sourceforge.net/>.
6 * This program is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU Affero General Public
8 * License as published by the Free Software Foundation, either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
16 * You should have received a copy of the GNU Affero General
17 * Public License along with this program. If not, see
18 * <http://www.gnu.org/licenses/>.
21 #include "config.h"
23 #include <stdlib.h>
24 #include <glib/gi18n.h>
25 #include <quvi.h>
27 #include "lutil.h"
29 typedef enum {TSTRING, TDOUBLE} PropertyType;
31 struct _media_xchg_table_s
33 const QuviMediaProperty qmp;
34 const PropertyType type;
35 const gchar *seq;
38 static const struct _media_xchg_table_s media_xchg_table[] =
40 {QUVI_MEDIA_PROPERTY_START_TIME_MS, TDOUBLE, "%s"},
41 {QUVI_MEDIA_PROPERTY_THUMBNAIL_URL, TSTRING, "%T"},
42 {QUVI_MEDIA_PROPERTY_DURATION_MS, TDOUBLE, "%d"},
43 {QUVI_MEDIA_STREAM_PROPERTY_URL, TSTRING, "%u"},
44 {QUVI_MEDIA_STREAM_PROPERTY_ID, TSTRING, "%I"},
45 {QUVI_MEDIA_PROPERTY_TITLE, TSTRING, "%t"},
46 {QUVI_MEDIA_PROPERTY_ID, TSTRING, "%i"},
47 {0, 0, NULL}
50 static const gchar *default_str = N_("default");
52 /* Return a media property value. */
53 static gchar *_qm_get(quvi_media_t qm, const gint i)
55 gchar *r = NULL;
57 switch (media_xchg_table[i].type)
59 case TSTRING:
61 gchar *s;
62 quvi_media_get(qm, media_xchg_table[i].qmp, &s);
64 if (s != NULL && strlen(s) >0)
65 r = g_strdup(s);
67 break;
69 case TDOUBLE:
71 gdouble d;
72 quvi_media_get(qm, media_xchg_table[i].qmp, &d);
73 return (g_strdup_printf("%.0f", d));
75 break;
77 default:
78 g_warning("[%s] invalid media xchg table type (%d)",
79 __func__, media_xchg_table[i].type);
80 return (NULL);
82 return ((r == NULL) ? g_strdup(default_str):r);
85 /* Regexp eval-callback. */
86 static gboolean _eval_cb(const GMatchInfo *i, GString *r, gpointer p)
88 gchar *m, *s;
90 m = g_match_info_fetch(i, 0);
91 s = g_hash_table_lookup((GHashTable*) p, m);
92 g_string_append(r, s);
93 g_free(m);
95 return (FALSE);
98 /* Append a sequence to the replace-pattern. */
99 static void _pattern_append(GString *p, const gchar *s)
101 if (p->len >0)
102 g_string_append(p, "|");
103 g_string_append(p, s);
106 /* Return a new regex cache. */
107 static GSList *_regex_cache_new(const gchar **output_regex)
109 lutil_regex_op_t op;
110 GSList *r;
111 gint i;
113 if (output_regex == NULL)
114 return(NULL);
116 for (i=0, r=NULL; output_regex[i] != NULL; ++i)
118 op = lutil_regex_op_new(output_regex[i], NULL);
119 if (op != NULL)
120 r = g_slist_prepend(r, op);
122 return (g_slist_reverse(r));
125 /* Release regex cache. */
126 static void _regex_cache_free(GSList *l)
128 if (l == NULL)
129 return;
131 lutil_slist_free_full(l, (GFunc) lutil_regex_op_free);
134 /* Apply regex onto the media property value. */
135 static gchar *_apply_regex(GSList *l, const gchar *seq, gchar *s)
137 GSList *curr = l;
138 while (curr != NULL)
140 lutil_regex_op_t op = (lutil_regex_op_t) curr->data;
141 if (g_strcmp0(op->sequence, seq) ==0)
143 gchar *r = lutil_regex_op_apply(op, s);
144 if (r != NULL)
146 g_free(s);
147 s = r;
150 curr = g_slist_next(curr);
152 return (s);
155 /* Return a new sequence handle. */
156 static lutil_xchg_seq_t _new(GSList **regex_cache, const gchar **output_regex,
157 const lutil_cb_printerr xperr, GString **p)
159 lutil_xchg_seq_t x = g_new0(struct _lutil_xchg_seq_s, 1);
161 x->htable = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
162 x->printerr = xperr;
164 *regex_cache = _regex_cache_new(output_regex);
165 *p = g_string_new(NULL);
167 return (x);
170 /* Insert media property value into hash table. */
171 static void _insert(lutil_xchg_seq_t x, GSList *regex_cache,
172 const gchar *seq, gchar *s, GString *p)
174 if (s == NULL)
175 return;
177 if (regex_cache != NULL)
178 s = _apply_regex(regex_cache, seq, s);
180 g_hash_table_insert(x->htable, (gchar*) seq, s);
181 _pattern_append(p, seq);
184 /* Create a new regex instance used to replace the sequences. */
185 static lutil_xchg_seq_t _new_regex(lutil_xchg_seq_t x, GString *p, GSList *c)
187 GError *e = NULL;
189 x->re = g_regex_new(p->str, 0, 0, &e);
190 if (e != NULL)
192 x->printerr(_("while creating sequence regex: %s"), e->message);
193 lutil_xchg_seq_free(x);
194 g_error_free(e);
195 x = NULL;
198 g_string_free(p, TRUE);
199 _regex_cache_free(c);
201 return (x);
204 /* Return a new sequence handle. */
205 lutil_xchg_seq_t lutil_xchg_seq_new(const lutil_xchg_seq_opts_t xopts)
207 lutil_xchg_seq_t x;
208 GString *p;
209 GSList *c;
210 gint i;
212 g_assert(xopts->xperr != NULL);
213 g_assert(xopts->qm != NULL);
215 x = _new(&c, xopts->output_regex, xopts->xperr, &p);
217 for (i=0; media_xchg_table[i].seq != NULL; ++i)
218 _insert(x, c, media_xchg_table[i].seq, _qm_get(xopts->qm,i), p);
220 if (xopts->file_ext != NULL)
221 _insert(x, c, "%e", g_strdup(xopts->file_ext), p);
223 if (xopts->fpath != NULL)
224 _insert(x, c, "%f", g_strdup(xopts->fpath), p);
226 return (_new_regex(x, p, c));
229 /* Return a new sequence handle -- without quvi_media_t and quvi_metainfo_t */
230 lutil_xchg_seq_t lutil_xchg_seq_noq_new(lutil_xchg_seq_noq_t noq,
231 const lutil_cb_printerr xperr,
232 const gchar **output_regex)
234 lutil_xchg_seq_t x;
235 GString *p;
236 GSList *c;
237 gchar *s;
238 gint i;
240 g_assert(xperr != NULL);
241 g_assert(noq != NULL);
243 x = _new(&c, output_regex, xperr, &p);
245 for (i=0; noq[i].seq != NULL; ++i)
247 s = g_strdup( (noq[i].val ==NULL || strlen(s) ==0)
248 ? default_str
249 : noq[i].val);
250 _insert(x, c, noq[i].seq, s, p);
252 return (_new_regex(x, p, c));
255 /* Free sequence handle. */
256 void lutil_xchg_seq_free(lutil_xchg_seq_t p)
258 if (p == NULL)
259 return;
261 g_hash_table_destroy(p->htable);
262 g_regex_unref(p->re);
263 g_free(p);
265 memset(p, 0, sizeof(struct _lutil_xchg_seq_s));
268 /* Replace the sequences in the given string (g_free the returned string). */
269 gchar *lutil_xchg_seq_apply(lutil_xchg_seq_t p, const gchar *s)
271 GError *e;
272 gchar *r;
274 r = NULL;
275 e = NULL;
277 r = g_regex_replace_eval(p->re, s, -1, 0, 0, _eval_cb, p->htable, &e);
278 if (e != NULL)
280 p->printerr(_("while replacing sequences: %s"), e->message);
281 g_error_free(e);
282 return (NULL);
284 return (r);
287 /* vim: set ts=2 sw=2 tw=72 expandtab: */