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 ) {
20 f = fopen ( fullpath, "r" );
26 fseek ( f, 0, SEEK_END );
30 fseek ( f, 0, SEEK_SET );
36 b = (char*) malloc ( len + 1 );
43 fread ( b, 1, len, f );
47 return ( pnd_pxml_fetch_buffer ( fullpath, b ) );
50 pnd_pxml_handle *pnd_pxml_fetch_buffer ( char *filename, char *buffer ) {
52 pnd_pxml_t **p = malloc ( sizeof(pnd_pxml_t*) * PXML_MAXAPPS );
53 memset ( p, '\0', sizeof(pnd_pxml_t*) * PXML_MAXAPPS );
55 if ( ! pnd_pxml_parse ( filename, buffer, strlen ( buffer ), p ) ) {
59 return ( (pnd_pxml_handle*) p );
62 void pnd_pxml_delete ( pnd_pxml_handle h ) {
63 pnd_pxml_t *p = (pnd_pxml_t*) h;
67 for (i = 0; i < p->titles_c; i++)
69 free(p->titles[i].language);
70 free(p->titles[i].string);
75 if (p->descriptions) {
76 for (i = 0; i < p->descriptions_c; i++)
78 free(p->descriptions[i].language);
79 free(p->descriptions[i].string);
81 free(p->descriptions);
84 if ( p -> unique_id ) {
85 free ( p -> unique_id );
87 if ( p -> package_id ) {
88 free ( p -> package_id );
90 if ( p -> standalone ) {
91 free ( p -> standalone );
96 if ( p -> previewpic1 ) {
97 free ( p -> previewpic1 );
99 if ( p -> previewpic2 ) {
100 free ( p -> previewpic2 );
102 if ( p -> author_name ) {
103 free ( p -> author_name );
105 if ( p -> author_website ) {
106 free ( p -> author_website );
108 if ( p -> version_major ) {
109 free ( p -> version_major );
111 if ( p -> version_minor ) {
112 free ( p -> version_minor );
114 if ( p -> version_release ) {
115 free ( p -> version_release );
117 if ( p -> version_build ) {
118 free ( p -> version_build );
123 if ( p -> main_category ) {
124 free ( p -> main_category );
126 if ( p -> subcategory1 ) {
127 free ( p -> subcategory1 );
129 if ( p -> subcategory2 ) {
130 free ( p -> subcategory2 );
132 if ( p -> altcategory ) {
133 free ( p -> altcategory );
135 if ( p -> altsubcategory1 ) {
136 free ( p -> altsubcategory1 );
138 if ( p -> altsubcategory2 ) {
139 free ( p -> altsubcategory2 );
141 if ( p -> osversion_major ) {
142 free ( p -> osversion_major );
144 if ( p -> osversion_minor ) {
145 free ( p -> osversion_minor );
147 if ( p -> osversion_release ) {
148 free ( p -> osversion_release );
150 if ( p -> osversion_build ) {
151 free ( p -> osversion_build );
153 if ( p -> associationitem1_name ) {
154 free ( p -> associationitem1_name );
156 if ( p -> associationitem1_filetype ) {
157 free ( p -> associationitem1_filetype );
159 if ( p -> associationitem1_parameter ) {
160 free ( p -> associationitem1_parameter );
162 if ( p -> associationitem2_name ) {
163 free ( p -> associationitem2_name );
165 if ( p -> associationitem2_filetype ) {
166 free ( p -> associationitem2_filetype );
168 if ( p -> associationitem2_parameter ) {
169 free ( p -> associationitem2_parameter );
171 if ( p -> associationitem3_name ) {
172 free ( p -> associationitem3_name );
174 if ( p -> associationitem1_filetype ) {
175 free ( p -> associationitem3_filetype );
177 if ( p -> associationitem1_parameter ) {
178 free ( p -> associationitem3_parameter );
180 if ( p -> clockspeed ) {
181 free ( p -> clockspeed );
183 if ( p -> background ) {
184 free ( p -> background );
186 if ( p -> startdir ) {
187 free ( p -> startdir );
189 if ( p -> appdata_dirname ) {
190 free ( p -> appdata_dirname );
192 if ( p -> info_name ) {
193 free ( p -> info_name );
195 if ( p -> info_filename ) {
196 free ( p -> info_filename );
198 if ( p -> info_type ) {
199 free ( p -> info_type );
201 if ( p -> exec_no_x11 ) {
202 free ( p -> exec_no_x11 );
204 if ( p -> execargs ) {
205 free ( p -> execargs );
208 free(p); /*very important!*/
213 void pnd_pxml_set_app_name ( pnd_pxml_handle h, char *v ) {
215 * Please do not use this function if it can be avoided; it is only here for compatibility.
216 * The function might fail on low memory, and there's no way for the user to know when this happens.
218 pnd_pxml_t *p = (pnd_pxml_t*) h;
219 char has_en_field = 0;
222 if (!v) return; /*TODO: add error information? Make it possible to set the string to NULL?*/
224 for (i = 0; i < p->titles_c; i++)
226 if (strncmp("en", p->titles[i].language, 2) == 0) /*strict comparison; match "en_US", "en_GB" etc... All these are set.*/
228 free(p->titles[i].string);
229 p->titles[i].string = strdup(v);
237 if (p->titles_c > p->titles_alloc_c) //we don't have enough strings allocated
239 p->titles_alloc_c <<= 1;
240 p->titles = (pnd_localized_string_t *)realloc((void*)p->titles, p->titles_alloc_c);
241 if (!p->titles) return; //errno = ENOMEM
243 p->titles[p->titles_c - 1].language = "en_US";
244 p->titles[p->titles_c - 1].string = strdup(v);
250 unsigned char pnd_is_pxml_valid_app ( pnd_pxml_handle h ) {
251 //pnd_pxml_t *p = (pnd_pxml_t*) h; //unused atm
253 // for now, lets just verify the exec-path is valid
255 //printf ( "exec is '%s'\n", p -> exec );
259 // even this is complicated by pnd_run.sh semantics .. can't check if it exists
260 // during discovery, since it is not mounted yet..
263 if ( stat ( p -> exec, &buf ) == 0 ) {
264 return ( 1 ); // path is present
271 signed char pnd_pxml_merge_override ( pnd_pxml_handle h, char *searchpath ) {
272 // the pxml includes a unique-id; use this value to attempt to find an
273 // override in the given searchpath
274 signed char retval = 0;
276 #if 0 // TODO: Unfinished entirely now
277 pnd_pxml_handle mergeh;
279 if ( ! pnd_pxml_get_unique_id ( h ) ) {
280 return ( -1 ); // no unique-id present, so can't use it to name potential override files
287 strncat ( buffer, "/", FILENAME_MAX );
288 strncat ( buffer, pnd_pxml_get_unique_id ( h ), FILENAME_MAX );
289 strncat ( buffer, ".xml", FILENAME_MAX );
290 //printf ( " Path to seek merges: '%s'\n", buffer );
292 // TODO: handle multiple subapps!
293 mergeh = pnd_pxml_fetch ( buffer );
297 // TODO: handle all the various data bits
298 if ( pnd_pxml_get_app_name_en ( mergeh ) ) {
299 pnd_pxml_set_app_name ( h, pnd_pxml_get_app_name_en ( mergeh ) );
302 pnd_pxml_delete ( mergeh );
312 char *pnd_pxml_get_best_localized_string(pnd_localized_string_t strings[], int strings_c, char *iso_lang)
315 int similarity_weight = 0xffff; /*Set to something Really Bad in the beginning*/
316 char *best_match = NULL;
318 for(i = 0; i < strings_c; i++)
320 // factor in the length -- if we're given 'en' and have a string 'en_US', thats better than 'de_something'; if we don't
321 // use length, then en_US and de_FO are same to 'en'.
322 int maxcount = strlen ( strings[i].language ) < strlen ( iso_lang ) ? strlen ( strings[i].language ) : strlen ( iso_lang );
323 int new_weight = abs(strncmp(strings[i].language, iso_lang, maxcount));
324 //pnd_log ( PND_LOG_DEFAULT, "looking for lang %s, looking at lang %s (weight %d, old %d): %s\n",
325 // iso_lang, strings [ i ].language, new_weight, similarity_weight, strings [ i ].string );
326 if (new_weight < similarity_weight)
328 similarity_weight = new_weight;
329 best_match = strings[i].string;
334 //pnd_log ( PND_LOG_DEFAULT, "best match: %s\n", best_match );
335 return strdup(best_match);
338 //pnd_log ( PND_LOG_DEFAULT, "best match: FAIL\n" );
343 char *pnd_pxml_get_package_id ( pnd_pxml_handle h ) {
344 pnd_pxml_t *p = (pnd_pxml_t*) h;
345 return ( p -> package_id );
348 char *pnd_pxml_get_app_name ( pnd_pxml_handle h, char *iso_lang ) {
349 pnd_pxml_t *p = (pnd_pxml_t *) h;
350 return pnd_pxml_get_best_localized_string(p->titles, p->titles_c, iso_lang);
353 char *pnd_pxml_get_app_name_en ( pnd_pxml_handle h ) {
354 return pnd_pxml_get_app_name(h, "en");
357 char *pnd_pxml_get_app_name_de ( pnd_pxml_handle h ) {
358 return pnd_pxml_get_app_name(h, "de");
361 char *pnd_pxml_get_app_name_it ( pnd_pxml_handle h ) {
362 return pnd_pxml_get_app_name(h, "it");
365 char *pnd_pxml_get_app_name_fr ( pnd_pxml_handle h ) {
366 return pnd_pxml_get_app_name(h, "fr");
368 char *pnd_pxml_get_unique_id ( pnd_pxml_handle h ) {
369 pnd_pxml_t *p = (pnd_pxml_t*) h;
370 return ( p -> unique_id );
373 char *pnd_pxml_get_appdata_dirname ( pnd_pxml_handle h ) {
374 pnd_pxml_t *p = (pnd_pxml_t*) h;
375 return ( p -> appdata_dirname );
378 char *pnd_pxml_get_standalone ( pnd_pxml_handle h ) {
379 pnd_pxml_t *p = (pnd_pxml_t*) h;
380 return ( p -> standalone );
383 char *pnd_pxml_get_icon ( pnd_pxml_handle h ) {
384 pnd_pxml_t *p = (pnd_pxml_t*) h;
385 return ( p -> icon );
388 // this guy's func name is 'out of sync' with the family of functions below; but since it
389 // exists, rather than just remove it and break someones code, will add in the appropriate
390 // function wrapper; the header only specifies the other guy (always did), so the header
391 // was already on the right path.
392 char *pnd_pxml_get_app_description ( pnd_pxml_handle h, char *iso_lang ) {
393 pnd_pxml_t *p = (pnd_pxml_t *) h;
394 return pnd_pxml_get_best_localized_string(p->descriptions, p->descriptions_c, iso_lang);
397 char *pnd_pxml_get_description_en ( pnd_pxml_handle h ) {
398 return pnd_pxml_get_app_description(h, "en");
401 char *pnd_pxml_get_description_de ( pnd_pxml_handle h ) {
402 return pnd_pxml_get_app_description(h, "de");
405 char *pnd_pxml_get_description_it ( pnd_pxml_handle h ) {
406 return pnd_pxml_get_app_description(h, "it");
409 char *pnd_pxml_get_description_fr ( pnd_pxml_handle h ) {
410 return pnd_pxml_get_app_description(h, "fr");
413 // wrapper added so family of function names is consistent; see comment for pnd_pxml_get_app_description() above
414 char *pnd_pxml_get_description ( pnd_pxml_handle h, char *iso_lang) {
415 return ( pnd_pxml_get_app_description ( h, iso_lang ) );
418 char *pnd_pxml_get_previewpic1 ( pnd_pxml_handle h ) {
419 pnd_pxml_t *p = (pnd_pxml_t*) h;
420 return ( p -> previewpic1 );
423 char *pnd_pxml_get_previewpic2 ( pnd_pxml_handle h ) {
424 pnd_pxml_t *p = (pnd_pxml_t*) h;
425 return ( p -> previewpic2 );
428 char *pnd_pxml_get_author_name ( pnd_pxml_handle h ) {
429 pnd_pxml_t *p = (pnd_pxml_t*) h;
430 return ( p -> author_name );
433 char *pnd_pxml_get_author_website ( pnd_pxml_handle h ) {
434 pnd_pxml_t *p = (pnd_pxml_t*) h;
435 return ( p -> author_website );
438 char *pnd_pxml_get_version_major ( pnd_pxml_handle h ) {
439 pnd_pxml_t *p = (pnd_pxml_t*) h;
440 return ( p -> version_major );
443 char *pnd_pxml_get_version_minor ( pnd_pxml_handle h ) {
444 pnd_pxml_t *p = (pnd_pxml_t*) h;
445 return ( p -> version_minor );
448 char *pnd_pxml_get_version_release ( pnd_pxml_handle h ) {
449 pnd_pxml_t *p = (pnd_pxml_t*) h;
450 return ( p -> version_release );
453 char *pnd_pxml_get_version_build ( pnd_pxml_handle h ) {
454 pnd_pxml_t *p = (pnd_pxml_t*) h;
455 return ( p -> version_build );
458 char *pnd_pxml_get_exec ( pnd_pxml_handle h ) {
459 pnd_pxml_t *p = (pnd_pxml_t*) h;
460 return ( p -> exec );
463 char *pnd_pxml_get_execargs ( pnd_pxml_handle h ) {
464 pnd_pxml_t *p = (pnd_pxml_t*) h;
465 return ( p -> execargs );
468 char *pnd_pxml_get_exec_option_no_x11 ( pnd_pxml_handle h ) {
469 pnd_pxml_t *p = (pnd_pxml_t*) h;
470 return ( p -> exec_no_x11 );
473 char *pnd_pxml_get_main_category ( pnd_pxml_handle h ) {
474 pnd_pxml_t *p = (pnd_pxml_t*) h;
475 return ( p -> main_category );
478 char *pnd_pxml_get_subcategory1 ( pnd_pxml_handle h ) {
479 pnd_pxml_t *p = (pnd_pxml_t*) h;
480 return ( p -> subcategory1 );
483 char *pnd_pxml_get_subcategory2 ( pnd_pxml_handle h ) {
484 pnd_pxml_t *p = (pnd_pxml_t*) h;
485 return ( p -> subcategory2 );
488 char *pnd_pxml_get_altcategory ( pnd_pxml_handle h ) {
489 pnd_pxml_t *p = (pnd_pxml_t*) h;
490 return ( p -> altcategory );
493 char *pnd_pxml_get_altsubcategory1 ( pnd_pxml_handle h ) {
494 pnd_pxml_t *p = (pnd_pxml_t*) h;
495 return ( p -> altsubcategory1 );
498 char *pnd_pxml_get_altsubcategory2 ( pnd_pxml_handle h ) {
499 pnd_pxml_t *p = (pnd_pxml_t*) h;
500 return ( p -> altsubcategory2 );
503 char *pnd_pxml_get_osversion_major ( pnd_pxml_handle h ) {
504 pnd_pxml_t *p = (pnd_pxml_t*) h;
505 return ( p -> osversion_major );
508 char *pnd_pxml_get_osversion_minor ( pnd_pxml_handle h ) {
509 pnd_pxml_t *p = (pnd_pxml_t*) h;
510 return ( p -> osversion_minor );
513 char *pnd_pxml_get_osversion_release ( pnd_pxml_handle h ) {
514 pnd_pxml_t *p = (pnd_pxml_t*) h;
515 return ( p -> osversion_release );
518 char *pnd_pxml_get_osversion_build ( pnd_pxml_handle h ) {
519 pnd_pxml_t *p = (pnd_pxml_t*) h;
520 return ( p -> osversion_build );
523 char *pnd_pxml_get_associationitem1_name ( pnd_pxml_handle h ) {
524 pnd_pxml_t *p = (pnd_pxml_t*) h;
525 return ( p -> associationitem1_name );
528 char *pnd_pxml_get_associationitem1_filetype ( pnd_pxml_handle h ) {
529 pnd_pxml_t *p = (pnd_pxml_t*) h;
530 return ( p -> associationitem1_filetype );
533 char *pnd_pxml_get_associationitem1_parameter ( pnd_pxml_handle h ) {
534 pnd_pxml_t *p = (pnd_pxml_t*) h;
535 return ( p -> associationitem1_parameter );
538 char *pnd_pxml_get_associationitem2_name ( pnd_pxml_handle h ) {
539 pnd_pxml_t *p = (pnd_pxml_t*) h;
540 return ( p -> associationitem2_name );
543 char *pnd_pxml_get_associationitem2_filetype ( pnd_pxml_handle h ) {
544 pnd_pxml_t *p = (pnd_pxml_t*) h;
545 return ( p -> associationitem2_filetype );
548 char *pnd_pxml_get_associationitem2_parameter ( pnd_pxml_handle h ) {
549 pnd_pxml_t *p = (pnd_pxml_t*) h;
550 return ( p -> associationitem2_parameter );
553 char *pnd_pxml_get_associationitem3_name ( pnd_pxml_handle h ) {
554 pnd_pxml_t *p = (pnd_pxml_t*) h;
555 return ( p -> associationitem3_name );
558 char *pnd_pxml_get_associationitem3_filetype ( pnd_pxml_handle h ) {
559 pnd_pxml_t *p = (pnd_pxml_t*) h;
560 return ( p -> associationitem3_filetype );
563 char *pnd_pxml_get_associationitem3_parameter ( pnd_pxml_handle h ) {
564 pnd_pxml_t *p = (pnd_pxml_t*) h;
565 return ( p -> associationitem3_parameter );
568 char *pnd_pxml_get_clockspeed ( pnd_pxml_handle h ) {
569 pnd_pxml_t *p = (pnd_pxml_t*) h;
570 return ( p -> clockspeed );
573 char *pnd_pxml_get_background ( pnd_pxml_handle h ) {
574 pnd_pxml_t *p = (pnd_pxml_t*) h;
575 return ( p -> background );
578 char *pnd_pxml_get_startdir ( pnd_pxml_handle h ) {
579 pnd_pxml_t *p = (pnd_pxml_t*) h;
580 return ( p -> startdir );
583 char *pnd_pxml_get_mkdir ( pnd_pxml_handle h ) {
584 pnd_pxml_t *p = (pnd_pxml_t*) h;
585 return ( p -> mkdir_sp );
588 unsigned char pnd_pxml_is_affirmative ( char *v ) {
594 if ( ( v [ 0 ] == 'Y' ) ||
595 ( v [ 0 ] == 'y' ) ||
604 pnd_pxml_x11_req_e pnd_pxml_get_x11 ( char *pxmlvalue ) {
607 return ( pnd_pxml_x11_ignored );
608 } else if ( strcasecmp ( pxmlvalue, "req" ) == 0 ) {
609 return ( pnd_pxml_x11_required );
610 } else if ( strcasecmp ( pxmlvalue, "stop" ) == 0 ) {
611 return ( pnd_pxml_x11_stop );
612 } else if ( strcasecmp ( pxmlvalue, "ignore" ) == 0 ) {
613 return ( pnd_pxml_x11_ignored );
616 return ( pnd_pxml_x11_ignored ); // default
619 char *pnd_pxml_get_info_name ( pnd_pxml_handle h ) {
620 pnd_pxml_t *p = (pnd_pxml_t*) h;
621 return ( p -> info_name );
624 char *pnd_pxml_get_info_type ( pnd_pxml_handle h ) {
625 pnd_pxml_t *p = (pnd_pxml_t*) h;
626 return ( p -> info_type );
629 char *pnd_pxml_get_info_src ( pnd_pxml_handle h ) {
630 pnd_pxml_t *p = (pnd_pxml_t*) h;
631 return ( p -> info_filename );