2 #include <stdio.h> /* for FILE */
3 #include <stdlib.h> /* for malloc */
4 #include <string.h> /* for string ops */
6 #include <sys/types.h> /* for stat */
7 #include <sys/stat.h> /* for stat */
8 #include <unistd.h> /* for stat */
11 #include "pnd_pathiter.h"
12 #include "pnd_tinyxml.h"
13 #include "pnd_logger.h"
15 pnd_pxml_handle *pnd_pxml_fetch ( char *fullpath ) {
21 f = fopen ( fullpath, "r" );
27 fseek ( f, 0, SEEK_END );
31 fseek ( f, 0, SEEK_SET );
37 b = (char*) malloc ( len + 1 );
44 fread ( b, 1, len, f );
48 h = pnd_pxml_fetch_buffer ( fullpath, b );
54 pnd_pxml_handle *pnd_pxml_fetch_buffer ( char *filename, char *buffer ) {
56 pnd_pxml_t **p = malloc ( sizeof(pnd_pxml_t*) * PXML_MAXAPPS );
57 memset ( p, '\0', sizeof(pnd_pxml_t*) * PXML_MAXAPPS );
59 if ( ! pnd_pxml_parse ( filename, buffer, strlen ( buffer ), p ) ) {
63 return ( (pnd_pxml_handle*) p );
66 void pnd_pxml_delete ( pnd_pxml_handle h ) {
67 pnd_pxml_t *p = (pnd_pxml_t*) h;
71 for (i = 0; i < p->titles_c; i++)
73 free(p->titles[i].language);
74 free(p->titles[i].string);
79 if (p->descriptions) {
80 for (i = 0; i < p->descriptions_c; i++)
82 free(p->descriptions[i].language);
83 free(p->descriptions[i].string);
85 free(p->descriptions);
88 if ( p -> unique_id ) {
89 free ( p -> unique_id );
91 if ( p -> package_id ) {
92 free ( p -> package_id );
94 if ( p -> standalone ) {
95 free ( p -> standalone );
100 if ( p -> previewpic1 ) {
101 free ( p -> previewpic1 );
103 if ( p -> previewpic2 ) {
104 free ( p -> previewpic2 );
106 if ( p -> author_name ) {
107 free ( p -> author_name );
109 if ( p -> author_website ) {
110 free ( p -> author_website );
112 if ( p -> version_major ) {
113 free ( p -> version_major );
115 if ( p -> version_minor ) {
116 free ( p -> version_minor );
118 if ( p -> version_release ) {
119 free ( p -> version_release );
121 if ( p -> version_build ) {
122 free ( p -> version_build );
127 if ( p -> main_category ) {
128 free ( p -> main_category );
130 if ( p -> subcategory1 ) {
131 free ( p -> subcategory1 );
133 if ( p -> subcategory2 ) {
134 free ( p -> subcategory2 );
136 if ( p -> altcategory ) {
137 free ( p -> altcategory );
139 if ( p -> altsubcategory1 ) {
140 free ( p -> altsubcategory1 );
142 if ( p -> altsubcategory2 ) {
143 free ( p -> altsubcategory2 );
145 if ( p -> osversion_major ) {
146 free ( p -> osversion_major );
148 if ( p -> osversion_minor ) {
149 free ( p -> osversion_minor );
151 if ( p -> osversion_release ) {
152 free ( p -> osversion_release );
154 if ( p -> osversion_build ) {
155 free ( p -> osversion_build );
157 if ( p -> associationitem1_name ) {
158 free ( p -> associationitem1_name );
160 if ( p -> associationitem1_filetype ) {
161 free ( p -> associationitem1_filetype );
163 if ( p -> associationitem1_command ) {
164 free ( p -> associationitem1_command );
166 if ( p -> associationitem1_args ) {
167 free ( p -> associationitem1_args );
169 if ( p -> associationitem2_name ) {
170 free ( p -> associationitem2_name );
172 if ( p -> associationitem2_filetype ) {
173 free ( p -> associationitem2_filetype );
175 if ( p -> associationitem2_command ) {
176 free ( p -> associationitem2_command );
178 if ( p -> associationitem2_args ) {
179 free ( p -> associationitem2_args );
181 if ( p -> associationitem3_name ) {
182 free ( p -> associationitem3_name );
184 if ( p -> associationitem1_filetype ) {
185 free ( p -> associationitem3_filetype );
187 if ( p -> associationitem1_command ) {
188 free ( p -> associationitem3_command );
190 if ( p -> associationitem1_args ) {
191 free ( p -> associationitem3_args );
193 if ( p -> clockspeed ) {
194 free ( p -> clockspeed );
196 if ( p -> background ) {
197 free ( p -> background );
199 if ( p -> startdir ) {
200 free ( p -> startdir );
202 if ( p -> appdata_dirname ) {
203 free ( p -> appdata_dirname );
205 if ( p -> info_name ) {
206 free ( p -> info_name );
208 if ( p -> info_filename ) {
209 free ( p -> info_filename );
211 if ( p -> info_type ) {
212 free ( p -> info_type );
214 if ( p -> exec_no_x11 ) {
215 free ( p -> exec_no_x11 );
217 if ( p -> execargs ) {
218 free ( p -> execargs );
220 if ( p -> mkdir_sp ) {
221 free ( p -> mkdir_sp );
223 if ( p -> package_version_major ) {
224 free ( p -> package_version_major );
226 if ( p -> package_version_minor ) {
227 free ( p -> package_version_minor );
229 if ( p -> package_version_release ) {
230 free ( p -> package_version_release );
232 if ( p -> package_version_build ) {
233 free ( p -> package_version_build );
236 free(p); /*very important!*/
241 void pnd_pxml_set_app_name ( pnd_pxml_handle h, char *v ) {
243 * Please do not use this function if it can be avoided; it is only here for compatibility.
244 * The function might fail on low memory, and there's no way for the user to know when this happens.
246 pnd_pxml_t *p = (pnd_pxml_t*) h;
247 char has_en_field = 0;
250 if (!v) return; /*TODO: add error information? Make it possible to set the string to NULL?*/
252 for (i = 0; i < p->titles_c; i++)
254 if (strncmp("en", p->titles[i].language, 2) == 0) /*strict comparison; match "en_US", "en_GB" etc... All these are set.*/
256 free(p->titles[i].string);
257 p->titles[i].string = strdup(v);
265 if (p->titles_c > p->titles_alloc_c) //we don't have enough strings allocated
267 p->titles_alloc_c <<= 1;
268 p->titles = (pnd_localized_string_t *)realloc((void*)p->titles, p->titles_alloc_c);
269 if (!p->titles) return; //errno = ENOMEM
271 p->titles[p->titles_c - 1].language = "en_US";
272 p->titles[p->titles_c - 1].string = strdup(v);
278 unsigned char pnd_is_pxml_valid_app ( pnd_pxml_handle h ) {
279 //pnd_pxml_t *p = (pnd_pxml_t*) h; //unused atm
281 // for now, lets just verify the exec-path is valid
283 //printf ( "exec is '%s'\n", p -> exec );
287 // even this is complicated by pnd_run.sh semantics .. can't check if it exists
288 // during discovery, since it is not mounted yet..
291 if ( stat ( p -> exec, &buf ) == 0 ) {
292 return ( 1 ); // path is present
299 signed char pnd_pxml_merge_override ( pnd_pxml_handle h, char *searchpath ) {
300 // the pxml includes a unique-id; use this value to attempt to find an
301 // override in the given searchpath
302 signed char retval = 0;
304 #if 0 // TODO: Unfinished entirely now
305 pnd_pxml_handle mergeh;
307 if ( ! pnd_pxml_get_unique_id ( h ) ) {
308 return ( -1 ); // no unique-id present, so can't use it to name potential override files
315 strncat ( buffer, "/", FILENAME_MAX );
316 strncat ( buffer, pnd_pxml_get_unique_id ( h ), FILENAME_MAX );
317 strncat ( buffer, ".xml", FILENAME_MAX );
318 //printf ( " Path to seek merges: '%s'\n", buffer );
320 // TODO: handle multiple subapps!
321 mergeh = pnd_pxml_fetch ( buffer );
325 // TODO: handle all the various data bits
326 if ( pnd_pxml_get_app_name_en ( mergeh ) ) {
327 pnd_pxml_set_app_name ( h, pnd_pxml_get_app_name_en ( mergeh ) );
330 pnd_pxml_delete ( mergeh );
340 char *pnd_pxml_get_best_localized_string(pnd_localized_string_t strings[], int strings_c, char *iso_lang)
343 int similarity_weight = 0xffff; /*Set to something Really Bad in the beginning*/
344 char *best_match = NULL;
346 for(i = 0; i < strings_c; i++)
348 // factor in the length -- if we're given 'en' and have a string 'en_US', thats better than 'de_something'; if we don't
349 // use length, then en_US and de_FO are same to 'en'.
350 int maxcount = strlen ( strings[i].language ) < strlen ( iso_lang ) ? strlen ( strings[i].language ) : strlen ( iso_lang );
351 int new_weight = abs(strncmp(strings[i].language, iso_lang, maxcount));
352 //pnd_log ( PND_LOG_DEFAULT, "looking for lang %s, looking at lang %s (weight %d, old %d): %s\n",
353 // iso_lang, strings [ i ].language, new_weight, similarity_weight, strings [ i ].string );
354 if (new_weight < similarity_weight)
356 similarity_weight = new_weight;
357 best_match = strings[i].string;
362 //pnd_log ( PND_LOG_DEFAULT, "best match: %s\n", best_match );
363 return strdup(best_match);
366 //pnd_log ( PND_LOG_DEFAULT, "best match: FAIL\n" );
371 char *pnd_pxml_get_package_id ( pnd_pxml_handle h ) {
372 pnd_pxml_t *p = (pnd_pxml_t*) h;
373 return ( p -> package_id );
376 char *pnd_pxml_get_app_name ( pnd_pxml_handle h, char *iso_lang ) {
377 pnd_pxml_t *p = (pnd_pxml_t *) h;
378 return pnd_pxml_get_best_localized_string(p->titles, p->titles_c, iso_lang);
381 char *pnd_pxml_get_app_name_en ( pnd_pxml_handle h ) {
382 return pnd_pxml_get_app_name(h, "en");
385 char *pnd_pxml_get_app_name_de ( pnd_pxml_handle h ) {
386 return pnd_pxml_get_app_name(h, "de");
389 char *pnd_pxml_get_app_name_it ( pnd_pxml_handle h ) {
390 return pnd_pxml_get_app_name(h, "it");
393 char *pnd_pxml_get_app_name_fr ( pnd_pxml_handle h ) {
394 return pnd_pxml_get_app_name(h, "fr");
396 char *pnd_pxml_get_unique_id ( pnd_pxml_handle h ) {
397 pnd_pxml_t *p = (pnd_pxml_t*) h;
398 return ( p -> unique_id );
401 char *pnd_pxml_get_appdata_dirname ( pnd_pxml_handle h ) {
402 pnd_pxml_t *p = (pnd_pxml_t*) h;
403 return ( p -> appdata_dirname );
406 char *pnd_pxml_get_standalone ( pnd_pxml_handle h ) {
407 pnd_pxml_t *p = (pnd_pxml_t*) h;
408 return ( p -> standalone );
411 char *pnd_pxml_get_icon ( pnd_pxml_handle h ) {
412 pnd_pxml_t *p = (pnd_pxml_t*) h;
413 return ( p -> icon );
416 // this guy's func name is 'out of sync' with the family of functions below; but since it
417 // exists, rather than just remove it and break someones code, will add in the appropriate
418 // function wrapper; the header only specifies the other guy (always did), so the header
419 // was already on the right path.
420 char *pnd_pxml_get_app_description ( pnd_pxml_handle h, char *iso_lang ) {
421 pnd_pxml_t *p = (pnd_pxml_t *) h;
422 return pnd_pxml_get_best_localized_string(p->descriptions, p->descriptions_c, iso_lang);
425 char *pnd_pxml_get_description_en ( pnd_pxml_handle h ) {
426 return pnd_pxml_get_app_description(h, "en");
429 char *pnd_pxml_get_description_de ( pnd_pxml_handle h ) {
430 return pnd_pxml_get_app_description(h, "de");
433 char *pnd_pxml_get_description_it ( pnd_pxml_handle h ) {
434 return pnd_pxml_get_app_description(h, "it");
437 char *pnd_pxml_get_description_fr ( pnd_pxml_handle h ) {
438 return pnd_pxml_get_app_description(h, "fr");
441 // wrapper added so family of function names is consistent; see comment for pnd_pxml_get_app_description() above
442 char *pnd_pxml_get_description ( pnd_pxml_handle h, char *iso_lang) {
443 return ( pnd_pxml_get_app_description ( h, iso_lang ) );
446 char *pnd_pxml_get_previewpic1 ( pnd_pxml_handle h ) {
447 pnd_pxml_t *p = (pnd_pxml_t*) h;
448 return ( p -> previewpic1 );
451 char *pnd_pxml_get_previewpic2 ( pnd_pxml_handle h ) {
452 pnd_pxml_t *p = (pnd_pxml_t*) h;
453 return ( p -> previewpic2 );
456 char *pnd_pxml_get_author_name ( pnd_pxml_handle h ) {
457 pnd_pxml_t *p = (pnd_pxml_t*) h;
458 return ( p -> author_name );
461 char *pnd_pxml_get_author_website ( pnd_pxml_handle h ) {
462 pnd_pxml_t *p = (pnd_pxml_t*) h;
463 return ( p -> author_website );
466 char *pnd_pxml_get_version_major ( pnd_pxml_handle h ) {
467 pnd_pxml_t *p = (pnd_pxml_t*) h;
468 return ( p -> version_major );
471 char *pnd_pxml_get_version_minor ( pnd_pxml_handle h ) {
472 pnd_pxml_t *p = (pnd_pxml_t*) h;
473 return ( p -> version_minor );
476 char *pnd_pxml_get_version_release ( pnd_pxml_handle h ) {
477 pnd_pxml_t *p = (pnd_pxml_t*) h;
478 return ( p -> version_release );
481 char *pnd_pxml_get_version_build ( pnd_pxml_handle h ) {
482 pnd_pxml_t *p = (pnd_pxml_t*) h;
483 return ( p -> version_build );
486 char *pnd_pxml_get_exec ( pnd_pxml_handle h ) {
487 pnd_pxml_t *p = (pnd_pxml_t*) h;
488 return ( p -> exec );
491 char *pnd_pxml_get_execargs ( pnd_pxml_handle h ) {
492 pnd_pxml_t *p = (pnd_pxml_t*) h;
493 return ( p -> execargs );
496 char *pnd_pxml_get_exec_option_no_x11 ( pnd_pxml_handle h ) {
497 pnd_pxml_t *p = (pnd_pxml_t*) h;
498 return ( p -> exec_no_x11 );
501 char *pnd_pxml_get_main_category ( pnd_pxml_handle h ) {
502 pnd_pxml_t *p = (pnd_pxml_t*) h;
503 return ( p -> main_category );
506 char *pnd_pxml_get_subcategory1 ( pnd_pxml_handle h ) {
507 pnd_pxml_t *p = (pnd_pxml_t*) h;
508 return ( p -> subcategory1 );
511 char *pnd_pxml_get_subcategory2 ( pnd_pxml_handle h ) {
512 pnd_pxml_t *p = (pnd_pxml_t*) h;
513 return ( p -> subcategory2 );
516 char *pnd_pxml_get_altcategory ( pnd_pxml_handle h ) {
517 pnd_pxml_t *p = (pnd_pxml_t*) h;
518 return ( p -> altcategory );
521 char *pnd_pxml_get_altsubcategory1 ( pnd_pxml_handle h ) {
522 pnd_pxml_t *p = (pnd_pxml_t*) h;
523 return ( p -> altsubcategory1 );
526 char *pnd_pxml_get_altsubcategory2 ( pnd_pxml_handle h ) {
527 pnd_pxml_t *p = (pnd_pxml_t*) h;
528 return ( p -> altsubcategory2 );
531 char *pnd_pxml_get_osversion_major ( pnd_pxml_handle h ) {
532 pnd_pxml_t *p = (pnd_pxml_t*) h;
533 return ( p -> osversion_major );
536 char *pnd_pxml_get_osversion_minor ( pnd_pxml_handle h ) {
537 pnd_pxml_t *p = (pnd_pxml_t*) h;
538 return ( p -> osversion_minor );
541 char *pnd_pxml_get_osversion_release ( pnd_pxml_handle h ) {
542 pnd_pxml_t *p = (pnd_pxml_t*) h;
543 return ( p -> osversion_release );
546 char *pnd_pxml_get_osversion_build ( pnd_pxml_handle h ) {
547 pnd_pxml_t *p = (pnd_pxml_t*) h;
548 return ( p -> osversion_build );
551 char *pnd_pxml_get_associationitem1_name ( pnd_pxml_handle h ) {
552 pnd_pxml_t *p = (pnd_pxml_t*) h;
553 return ( p -> associationitem1_name );
556 char *pnd_pxml_get_associationitem1_filetype ( pnd_pxml_handle h ) {
557 pnd_pxml_t *p = (pnd_pxml_t*) h;
558 return ( p -> associationitem1_filetype );
561 char *pnd_pxml_get_associationitem1_command ( pnd_pxml_handle h ) {
562 pnd_pxml_t *p = (pnd_pxml_t*) h;
563 return ( p -> associationitem1_command );
566 char *pnd_pxml_get_associationitem1_args ( pnd_pxml_handle h ) {
567 pnd_pxml_t *p = (pnd_pxml_t*) h;
568 return ( p -> associationitem1_args );
571 char *pnd_pxml_get_associationitem2_name ( pnd_pxml_handle h ) {
572 pnd_pxml_t *p = (pnd_pxml_t*) h;
573 return ( p -> associationitem2_name );
576 char *pnd_pxml_get_associationitem2_filetype ( pnd_pxml_handle h ) {
577 pnd_pxml_t *p = (pnd_pxml_t*) h;
578 return ( p -> associationitem2_filetype );
581 char *pnd_pxml_get_associationitem2_command ( pnd_pxml_handle h ) {
582 pnd_pxml_t *p = (pnd_pxml_t*) h;
583 return ( p -> associationitem2_command );
586 char *pnd_pxml_get_associationitem2_args ( pnd_pxml_handle h ) {
587 pnd_pxml_t *p = (pnd_pxml_t*) h;
588 return ( p -> associationitem2_args );
591 char *pnd_pxml_get_associationitem3_name ( pnd_pxml_handle h ) {
592 pnd_pxml_t *p = (pnd_pxml_t*) h;
593 return ( p -> associationitem3_name );
596 char *pnd_pxml_get_associationitem3_filetype ( pnd_pxml_handle h ) {
597 pnd_pxml_t *p = (pnd_pxml_t*) h;
598 return ( p -> associationitem3_filetype );
601 char *pnd_pxml_get_associationitem3_command ( pnd_pxml_handle h ) {
602 pnd_pxml_t *p = (pnd_pxml_t*) h;
603 return ( p -> associationitem3_command );
606 char *pnd_pxml_get_associationitem3_args ( pnd_pxml_handle h ) {
607 pnd_pxml_t *p = (pnd_pxml_t*) h;
608 return ( p -> associationitem3_args );
611 char *pnd_pxml_get_clockspeed ( pnd_pxml_handle h ) {
612 pnd_pxml_t *p = (pnd_pxml_t*) h;
613 return ( p -> clockspeed );
616 char *pnd_pxml_get_background ( pnd_pxml_handle h ) {
617 pnd_pxml_t *p = (pnd_pxml_t*) h;
618 return ( p -> background );
621 char *pnd_pxml_get_startdir ( pnd_pxml_handle h ) {
622 pnd_pxml_t *p = (pnd_pxml_t*) h;
623 return ( p -> startdir );
626 char *pnd_pxml_get_mkdir ( pnd_pxml_handle h ) {
627 pnd_pxml_t *p = (pnd_pxml_t*) h;
628 return ( p -> mkdir_sp );
631 char *pnd_pxml_get_package_version_major ( pnd_pxml_handle h ) {
632 pnd_pxml_t *p = (pnd_pxml_t*) h;
633 return ( p -> package_version_major );
636 char *pnd_pxml_get_package_version_minor ( pnd_pxml_handle h ) {
637 pnd_pxml_t *p = (pnd_pxml_t*) h;
638 return ( p -> package_version_minor );
641 char *pnd_pxml_get_package_version_release ( pnd_pxml_handle h ) {
642 pnd_pxml_t *p = (pnd_pxml_t*) h;
643 return ( p -> package_version_release );
646 char *pnd_pxml_get_package_version_build ( pnd_pxml_handle h ) {
647 pnd_pxml_t *p = (pnd_pxml_t*) h;
648 return ( p -> package_version_build );
651 unsigned char pnd_pxml_is_affirmative ( char *v ) {
657 if ( ( v [ 0 ] == 'Y' ) ||
658 ( v [ 0 ] == 'y' ) ||
667 pnd_pxml_x11_req_e pnd_pxml_get_x11 ( char *pxmlvalue ) {
670 return ( pnd_pxml_x11_ignored );
671 } else if ( strcasecmp ( pxmlvalue, "req" ) == 0 ) {
672 return ( pnd_pxml_x11_required );
673 } else if ( strcasecmp ( pxmlvalue, "stop" ) == 0 ) {
674 return ( pnd_pxml_x11_stop );
675 } else if ( strcasecmp ( pxmlvalue, "ignore" ) == 0 ) {
676 return ( pnd_pxml_x11_ignored );
679 return ( pnd_pxml_x11_ignored ); // default
682 char *pnd_pxml_get_info_name ( pnd_pxml_handle h ) {
683 pnd_pxml_t *p = (pnd_pxml_t*) h;
684 return ( p -> info_name );
687 char *pnd_pxml_get_info_type ( pnd_pxml_handle h ) {
688 pnd_pxml_t *p = (pnd_pxml_t*) h;
689 return ( p -> info_type );
692 char *pnd_pxml_get_info_src ( pnd_pxml_handle h ) {
693 pnd_pxml_t *p = (pnd_pxml_t*) h;
694 return ( p -> info_filename );