1 /* librepo - A library providing (libcURL like) API to downloading repository
2  * Copyright (C) 2012  Tomas Mlcoch
3  *
4  * Licensed under the GNU Lesser General Public License Version 2.1
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
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library 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 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 Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <glib.h>
22 #include <assert.h>
23 #include <ctype.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include "url_substitution.h"
27 #include "util.h"
28 
29 static LrVar *
lr_var_new(const char * var,const char * val)30 lr_var_new(const char *var, const char *val)
31 {
32     LrVar *var_val = lr_malloc0(sizeof(LrVar));
33     var_val->var = g_strdup(var);
34     var_val->val = g_strdup(val);
35     return var_val;
36 }
37 
38 static void
lr_var_free(LrVar * var)39 lr_var_free(LrVar *var)
40 {
41     lr_free(var->var);
42     lr_free(var->val);
43     lr_free(var);
44 }
45 
46 LrUrlVars *
lr_urlvars_set(LrUrlVars * list,const char * var,const char * value)47 lr_urlvars_set(LrUrlVars *list, const char *var, const char *value)
48 {
49     LrUrlVars *ret = list;
50 
51     assert(var);
52 
53     if (!value) {
54         // Remove var from the list
55         for (LrUrlVars *elem = list; elem; elem = g_slist_next(elem)) {
56             LrVar *var_val = elem->data;
57             if (!strcmp(var, var_val->var)) {
58                 ret = g_slist_remove(list, var_val);
59                 lr_var_free(var_val);
60                 return ret;
61             }
62         }
63     } else {
64         // Replace var
65         for (LrUrlVars *elem = list; elem; elem = g_slist_next(elem)) {
66             LrVar *var_val = elem->data;
67             if (!strcmp(var, var_val->var)) {
68                 lr_free(var_val->val);
69                 var_val->val = g_strdup(value);
70                 return ret;
71             }
72         }
73 
74         // Add var
75         LrVar *var_val = lr_var_new(var, value);
76         ret = g_slist_prepend(list, var_val);
77     }
78 
79     return ret;
80 }
81 
82 void
lr_urlvars_free(LrUrlVars * list)83 lr_urlvars_free(LrUrlVars *list)
84 {
85     if (!list)
86         return;
87     for (LrUrlVars *elem = list; elem; elem = g_slist_next(elem))
88         lr_var_free(elem->data);
89     g_slist_free(list);
90 }
91 
92 char *
lr_url_substitute(const char * url,LrUrlVars * list)93 lr_url_substitute(const char *url, LrUrlVars *list)
94 {
95     const char *cur = url;
96     const char *p = url;
97 
98     if (!url)
99         return NULL;
100 
101     if (!list)
102         return g_strdup(url);
103 
104     char *res = g_strdup("");
105 
106     while (*cur != '\0') {
107         if (*cur == '$') {
108             // Adds unprocessed text before the variable to the "res".
109             if (cur-p) {
110                 char *tmp = g_strndup(p, cur-p);
111                 char *tmp_res = g_strconcat(res, tmp, NULL);
112                 g_free(tmp);
113                 g_free(res);
114                 res = tmp_res;
115                 p = cur;
116             }
117 
118             // Tries to substitute the variable and store result to the "res".
119             gboolean bracket;
120             if (*++cur == '{') {
121                 bracket = TRUE;
122                 ++cur;
123             } else {
124                 bracket = FALSE;
125             }
126             const char *varname = cur;
127             for (; isalnum(*cur) || (*cur == '_' && isalnum(*(cur + 1))); ++cur);
128             if (cur != varname && (!bracket || *cur == '}')) {
129                 for (LrUrlVars *elem = list; elem; elem = g_slist_next(elem)) {
130                     LrVar *var_val = elem->data;
131                     size_t var_len = strlen(var_val->var);
132                     if (var_len == cur - varname && strncmp(var_val->var, varname, var_len) == 0) {
133                         if (bracket)
134                             ++cur;
135                         p = cur;
136                         char *tmp_res = g_strconcat(res, var_val->val, NULL);
137                         g_free(res);
138                         res = tmp_res;
139                         break;
140                     }
141                 }
142             }
143         } else {
144             ++cur;
145         }
146     }
147 
148     // Adds remaining text to the "res".
149     if (*p != '\0') {
150         char *tmp_res = g_strconcat(res, p, NULL);
151         g_free(res);
152         res = tmp_res;
153     }
154 
155     return res;
156 }
157