Remove distinction of widget's version
[src/app-framework-main.git] / src / wgt-info.c
1 /*
2  Copyright (C) 2015-2020 IoT.bzh
3
4  author: José Bollo <jose.bollo@iot.bzh>
5
6  Licensed under the Apache License, Version 2.0 (the "License");
7  you may not use this file except in compliance with the License.
8  You may obtain a copy of the License at
9
10      http://www.apache.org/licenses/LICENSE-2.0
11
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  See the License for the specific language governing permissions and
16  limitations under the License.
17 */
18
19 #include <stdlib.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <assert.h>
23 #include <ctype.h>
24
25 #include <libxml/tree.h>
26
27 #include "verbose.h"
28 #include "wgt.h"
29 #include "wgt-config.h"
30 #include "wgt-strings.h"
31 #include "wgt-info.h"
32
33 struct wgt_info {
34         int refcount;
35         struct wgt *wgt;
36         struct wgt_desc desc;
37 };
38
39 static int getpropbool(xmlNodePtr node, const char *prop, int def)
40 {
41         int result;
42         char *val = xmlGetProp(node, prop);
43         if (!val)
44                 result = def;
45         else {
46                 if (!strcmp(val, "true"))
47                         result = 1;
48                 else if (!strcmp(val, "false"))
49                         result = 0;
50                 else
51                         result = def;
52                 xmlFree(val);
53         }
54         return result;
55 }
56
57 static int getpropnum(xmlNodePtr node, const char *prop, int def)
58 {
59         int result;
60         char *val = xmlGetProp(node, prop);
61         if (!val)
62                 result = def;
63         else {
64                 result = atoi(val);
65                 xmlFree(val);
66         }
67         return result;
68 }
69
70 static xmlChar *optprop(xmlNodePtr node, const char *prop)
71 {
72         return node ? xmlGetProp(node, prop) : NULL;
73 }
74
75 static xmlChar *optcontent(xmlNodePtr node)
76 {
77         return node ? xmlNodeGetContent(node) : NULL;
78 }
79
80 static char *mkver(char *version)
81 {
82         unsigned int lver;
83         char c, *r;
84         if (version) {
85                 c = version[lver = 0];
86                 while(c && c != ' ' && c != '.')
87                         c = version[++lver];
88                 if (c == '.') {
89                         c = version[++lver];
90                         while(c && c != ' ' && c != '.')
91                                 c = version[++lver];
92                 }
93                 r = malloc(lver + 1);
94                 if (r) {
95                         memcpy(r, version, lver);
96                         r[lver] = 0;
97                         return r;
98                 }
99         }
100         return NULL;
101 }
102
103 static char *mkidaver(char *id, char *ver)
104 {
105 #if DISTINCT_VERSIONS
106         size_t lid, lver;
107         char *r;
108         if (id && ver) {
109                 lid = strlen(id);
110                 lver = strlen(ver);
111                 r = malloc(2 + lid + lver);
112                 if (r) {
113                         memcpy(r, id, lid);
114                         r[lid] = '@';
115                         memcpy(r + lid + 1, ver, lver);
116                         r[lid + lver + 1] = 0;
117                         return r;
118                 }
119         }
120         return NULL;
121 #else
122         return strdup(id);
123 #endif
124 }
125
126 static void make_lowercase(char *s)
127 {
128         if (s) {
129                 while(*s) {
130                         *s = (char)tolower(*s);
131                         s++;
132                 }
133         }
134 }
135
136 static int fill_desc(struct wgt_desc *desc, int want_icons, int want_features, int want_preferences)
137 {
138         xmlNodePtr node, pnode;
139         struct wgt_desc_icon *icon, **icontail;
140         struct wgt_desc_feature *feature, **featuretail;
141         struct wgt_desc_preference *preference, **preferencetail;
142         struct wgt_desc_param *param, **paramtail;
143
144         node = wgt_config_widget();
145         if (!node) {
146                 WARNING("no widget");
147                 errno = EINVAL;
148                 return -1;
149         }
150         desc->id = xmlGetProp(node, string_id);
151         make_lowercase(desc->id);
152         desc->version = xmlGetProp(node, string_version);
153         desc->ver = mkver(desc->version);
154         make_lowercase(desc->ver);
155         desc->idaver = mkidaver(desc->id, desc->ver);
156         desc->width = getpropnum(node, string_width, 0);
157         desc->height = getpropnum(node, string_height, 0);
158         desc->viewmodes = xmlGetProp(node, string_viewmodes);
159         desc->defaultlocale = xmlGetProp(node, string_defaultlocale);
160
161         node = wgt_config_name();
162         desc->name = optcontent(node);
163         desc->name_short = optprop(node, string_short);
164
165         node = wgt_config_description();
166         desc->description = optcontent(node);
167
168         node = wgt_config_author();
169         desc->author = optcontent(node);
170         desc->author_href = optprop(node, string_href);
171         desc->author_email = optprop(node, string_email);
172
173         node = wgt_config_license();
174         desc->license = optcontent(node);
175         desc->license_href = optprop(node, string_href);
176         
177         node = wgt_config_content();
178         desc->content_src = optprop(node, string_src);
179         if (node && desc->content_src == NULL) {
180                 WARNING("content without src");
181                 errno = EINVAL;
182                 return -1;
183         }
184         desc->content_type = optprop(node, string_type);
185         desc->content_encoding = optprop(node, string_encoding);
186
187         if (want_icons) {
188                 icontail = &desc->icons;
189                 node = wgt_config_first_icon();
190                 while (node) {
191                         icon = malloc(sizeof * icon);
192                         if (icon == NULL) {
193                                 errno = ENOMEM;
194                                 return -1;
195                         }
196                         icon->src = xmlGetProp(node, string_src);
197                         icon->width = getpropnum(node, string_width, 0);
198                         icon->height = getpropnum(node, string_height, 0);
199
200                         icon->next = NULL;
201                         *icontail = icon;
202
203                         if (icon->src == NULL) {
204                                 WARNING("icon without src");
205                                 errno = EINVAL;
206                                 return -1;
207                         }
208                         icontail = &icon->next;
209                         node = wgt_config_next_icon(node);
210                 }
211         }
212
213         if (want_features) {
214                 featuretail = &desc->features;
215                 node = wgt_config_first_feature();
216                 while (node) {
217                         feature = malloc(sizeof * feature);
218                         if (feature == NULL) {
219                                 errno = ENOMEM;
220                                 return -1;
221                         }
222                         feature->name = xmlGetProp(node, string_name);
223                         feature->required = getpropbool(node, string_required, 1);
224                         feature->params = NULL;
225
226                         feature->next = NULL;
227                         *featuretail = feature;
228
229                         if (feature->name == NULL) {
230                                 WARNING("feature without name");
231                                 errno = EINVAL;
232                                 return -1;
233                         }
234
235                         paramtail = &feature->params;
236                         pnode = wgt_config_first_param(node);
237                         while (pnode) {
238                                 param = malloc(sizeof * param);
239                                 if (param == NULL) {
240                                         errno = ENOMEM;
241                                         return -1;
242                                 }
243                                 param->name = xmlGetProp(pnode, string_name);
244                                 param->value = xmlGetProp(pnode, string_value);
245
246                                 param->next = NULL;
247                                 *paramtail = param;
248
249                                 if (param->name == NULL || param->value == NULL) {
250                                         WARNING("param without name or value");
251                                         errno = EINVAL;
252                                         return -1;
253                                 }
254
255                                 paramtail = &param->next;
256                                 pnode = wgt_config_next_param(pnode);
257                         }
258
259                         featuretail = &feature->next;
260                         node = wgt_config_next_feature(node);
261                 }
262         }
263
264         if (want_preferences) {
265                 preferencetail = &desc->preferences;
266                 node = wgt_config_first_preference();
267                 while (node) {
268                         preference = malloc(sizeof * preference);
269                         if (preference == NULL) {
270                                 errno = ENOMEM;
271                                 return -1;
272                         }
273                         preference->name = xmlGetProp(node, string_name);
274                         preference->value = xmlGetProp(node, string_value);
275                         preference->readonly = getpropbool(node, string_readonly, 0);
276
277                         *preferencetail = preference;
278                         preference->next = NULL;
279
280                         if (preference->name == NULL) {
281                                 WARNING("preference without name");
282                                 errno = EINVAL;
283                                 return -1;
284                         }
285
286                         preferencetail = &preference->next;
287                         node = wgt_config_next_preference(node);
288                 }
289         }
290         return 0;
291 }
292
293 static void free_desc(struct wgt_desc *desc)
294 {
295         struct wgt_desc_icon *icon;
296         struct wgt_desc_feature *feature;
297         struct wgt_desc_preference *preference;
298         struct wgt_desc_param *param;
299
300         xmlFree(desc->id);
301         xmlFree(desc->version);
302         free(desc->ver);
303         free(desc->idaver);
304         xmlFree(desc->viewmodes);
305         xmlFree(desc->defaultlocale);
306         xmlFree(desc->name);
307         xmlFree(desc->name_short);
308         xmlFree(desc->description);
309         xmlFree(desc->author);
310         xmlFree(desc->author_href);
311         xmlFree(desc->author_email);
312         xmlFree(desc->license);
313         xmlFree(desc->license_href);
314         xmlFree(desc->content_src);
315         xmlFree(desc->content_type);
316         xmlFree(desc->content_encoding);
317
318         while(desc->icons) {
319                 icon = desc->icons;
320                 desc->icons = icon->next;
321                 xmlFree(icon->src);
322                 free(icon);
323         }
324
325         while(desc->features) {
326                 feature = desc->features;
327                 desc->features = feature->next;
328                 xmlFree(feature->name);
329                 while(feature->params) {
330                         param = feature->params;
331                         feature->params = param->next;
332                         xmlFree(param->name);
333                         xmlFree(param->value);
334                         free(param);
335                 }
336                 free(feature);
337         }
338
339         while(desc->preferences) {
340                 preference = desc->preferences;
341                 desc->preferences = preference->next;
342                 xmlFree(preference->name);
343                 xmlFree(preference->value);
344                 free(preference);
345         }
346 }
347
348 static void dump_desc(struct wgt_desc *desc, FILE *f, const char *prefix)
349 {
350         struct wgt_desc_icon *icon;
351         struct wgt_desc_feature *feature;
352         struct wgt_desc_preference *preference;
353         struct wgt_desc_param *param;
354
355         if (desc->id) fprintf(f, "%sid: %s\n", prefix, desc->id);
356         if (desc->version) fprintf(f, "%sversion: %s\n", prefix, desc->version);
357         if (desc->ver) fprintf(f, "%sver: %s\n", prefix, desc->ver);
358         if (desc->idaver) fprintf(f, "%sidaver: %s\n", prefix, desc->idaver);
359         if (desc->width) fprintf(f, "%swidth: %d\n", prefix, desc->width);
360         if (desc->height) fprintf(f, "%sheight: %d\n", prefix, desc->height);
361         if (desc->viewmodes) fprintf(f, "%sviewmodes: %s\n", prefix, desc->viewmodes);
362         if (desc->defaultlocale) fprintf(f, "%sdefaultlocale: %s\n", prefix, desc->defaultlocale);
363         if (desc->name) fprintf(f, "%sname: %s\n", prefix, desc->name);
364         if (desc->name_short) fprintf(f, "%sname_short: %s\n", prefix, desc->name_short);
365         if (desc->description) fprintf(f, "%sdescription: %s\n", prefix, desc->description);
366         if (desc->author) fprintf(f, "%sauthor: %s\n", prefix, desc->author);
367         if (desc->author_href) fprintf(f, "%sauthor_href: %s\n", prefix, desc->author_href);
368         if (desc->author_email) fprintf(f, "%sauthor_email: %s\n", prefix, desc->author_email);
369         if (desc->license) fprintf(f, "%slicense: %s\n", prefix, desc->license);
370         if (desc->license_href) fprintf(f, "%slicense_href: %s\n", prefix, desc->license_href);
371         if (desc->content_src) fprintf(f, "%scontent_src: %s\n", prefix, desc->content_src);
372         if (desc->content_type) fprintf(f, "%scontent_type: %s\n", prefix, desc->content_type);
373         if (desc->content_encoding) fprintf(f, "%scontent_encoding: %s\n", prefix, desc->content_encoding);
374
375         icon = desc->icons;
376         while(icon) {
377                 fprintf(f, "%s+ icon src: %s\n", prefix, icon->src);
378                 if (icon->width) fprintf(f, "%s       width: %d\n", prefix, icon->width);
379                 if (icon->height) fprintf(f, "%s       height: %d\n", prefix, icon->height);
380                 icon = icon->next;
381         }
382
383         feature = desc->features;
384         while(feature) {
385                 fprintf(f, "%s+ feature name: %s\n", prefix, feature->name);
386                 fprintf(f, "%s          required: %s\n", prefix, feature->required ? "true" : "false");
387                 param = feature->params;
388                 while(param) {
389                         fprintf(f, "%s          + param name: %s\n", prefix, param->name);
390                         fprintf(f, "%s                  value: %s\n", prefix, param->value);
391                         param = param->next;
392                 }
393                 feature = feature->next;
394         }
395
396         preference = desc->preferences;
397         while(preference) {
398                 fprintf(f, "%s+ preference name: %s\n", prefix, preference->name);
399                 if (preference->value) fprintf(f, "%s             value: %s\n", prefix, preference->value);
400                 fprintf(f, "%s             readonly: %s\n", prefix, preference->readonly ? "true" : "false");
401                 preference = preference->next;
402         }
403 }
404
405 struct wgt_info *wgt_info_create(struct wgt *wgt, int icons, int features, int preferences)
406 {
407         int rc;
408         struct wgt_info *result;
409
410         assert(wgt);
411         assert(wgt_is_connected(wgt));
412         rc = wgt_config_open(wgt);
413         if (rc) {
414                 errno = EINVAL;
415                 return NULL;
416         }
417
418         result = calloc(sizeof * result, 1);
419         if (!result) {
420                 wgt_config_close();
421                 errno = ENOMEM;
422                 return NULL;
423         }
424         result->refcount = 1;
425         result->wgt = wgt;
426         wgt_addref(wgt);
427
428         rc = fill_desc(&result->desc, icons, features, preferences);
429         wgt_config_close();
430         if (rc) {
431                 wgt_info_unref(result);
432                 return NULL;
433         }
434         return result;
435 }
436
437 struct wgt_info *wgt_info_createat(int dirfd, const char *pathname, int icons, int features, int preferences)
438 {
439         struct wgt_info *result = NULL;
440         struct wgt *wgt = wgt_createat(dirfd, pathname);
441         if (wgt) {
442                 result = wgt_info_create(wgt, icons, features, preferences);
443                 wgt_unref(wgt);
444         }
445         return result;
446 }
447
448 const struct wgt_desc *wgt_info_desc(struct wgt_info *ifo)
449 {
450         assert(ifo);
451         return &ifo->desc;
452 }
453
454 struct wgt *wgt_info_wgt(struct wgt_info *ifo)
455 {
456         assert(ifo);
457         assert(ifo->wgt);
458         return ifo->wgt;
459 }
460
461 void wgt_info_addref(struct wgt_info *ifo)
462 {
463         assert(ifo);
464         assert(ifo->refcount > 0);
465         ifo->refcount++;
466 }
467
468 void wgt_info_unref(struct wgt_info *ifo)
469 {
470         assert(ifo);
471         assert(ifo->refcount > 0);
472         if (--ifo->refcount)
473                 return;
474
475         free_desc(&ifo->desc);
476         wgt_unref(ifo->wgt);
477         free(ifo);
478 }
479
480 void wgt_info_dump(struct wgt_info *ifo, int fd, const char *prefix)
481 {
482         FILE *f;
483
484         assert(ifo);
485         f = fdopen(fd, "w");
486         if (f == NULL)
487                 WARNING("can't fdopen in wgt_info_dump");
488         else {
489                 dump_desc(&ifo->desc, f, prefix);
490                 fclose(f);
491         }
492 }
493
494 const struct wgt_desc_feature *wgt_info_feature(struct wgt_info *ifo, const char *name)
495 {
496         const struct wgt_desc_feature *result = ifo->desc.features;
497         while(result && strcmp(result->name, name))
498                 result = result->next;
499         return result;
500 }
501
502 const char *wgt_info_param(const struct wgt_desc_feature *feature, const char *name)
503 {
504         const struct wgt_desc_param *param = feature->params;
505         while(param) {
506                 if (0 == strcmp(name, param->name))
507                         return param->value;
508                 param = param->next;
509         }
510         return NULL;
511 }
512