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 );
32 b = (char*) malloc ( len );
39 fread ( b, 1, len, f );
43 return ( pnd_pxml_fetch_buffer ( fullpath, b ) );
46 pnd_pxml_handle *pnd_pxml_fetch_buffer ( char *filename, char *buffer ) {
48 pnd_pxml_t **p = malloc ( sizeof(pnd_pxml_t*) * PXML_MAXAPPS );
49 memset ( p, '\0', sizeof(pnd_pxml_t*) * PXML_MAXAPPS );
51 if ( ! pnd_pxml_parse ( filename, buffer, strlen ( buffer ), p ) ) {
55 return ( (pnd_pxml_handle*) p );
58 void pnd_pxml_delete ( pnd_pxml_handle h ) {
59 pnd_pxml_t *p = (pnd_pxml_t*) h;
63 for (i = 0; i < p->titles_c; i++)
65 free(p->titles[i].language);
66 free(p->titles[i].string);
71 if (p->descriptions) {
72 for (i = 0; i < p->descriptions_c; i++)
74 free(p->descriptions[i].language);
75 free(p->descriptions[i].string);
77 free(p->descriptions);
80 if ( p -> standalone ) {
81 free ( p -> standalone );
86 if ( p -> previewpic1 ) {
87 free ( p -> previewpic1 );
89 if ( p -> previewpic2 ) {
90 free ( p -> previewpic2 );
92 if ( p -> author_name ) {
93 free ( p -> author_name );
95 if ( p -> author_website ) {
96 free ( p -> author_website );
98 if ( p -> version_major ) {
99 free ( p -> version_major );
101 if ( p -> version_minor ) {
102 free ( p -> version_minor );
104 if ( p -> version_release ) {
105 free ( p -> version_release );
107 if ( p -> version_build ) {
108 free ( p -> version_build );
113 if ( p -> main_category ) {
114 free ( p -> main_category );
116 if ( p -> subcategory1 ) {
117 free ( p -> subcategory1 );
119 if ( p -> subcategory2 ) {
120 free ( p -> subcategory2 );
122 if ( p -> altcategory ) {
123 free ( p -> altcategory );
125 if ( p -> altsubcategory1 ) {
126 free ( p -> altsubcategory1 );
128 if ( p -> altsubcategory2 ) {
129 free ( p -> altsubcategory2 );
131 if ( p -> osversion_major ) {
132 free ( p -> osversion_major );
134 if ( p -> osversion_minor ) {
135 free ( p -> osversion_minor );
137 if ( p -> osversion_release ) {
138 free ( p -> osversion_release );
140 if ( p -> osversion_build ) {
141 free ( p -> osversion_build );
143 if ( p -> associationitem1_name ) {
144 free ( p -> associationitem1_name );
146 if ( p -> associationitem1_filetype ) {
147 free ( p -> associationitem1_filetype );
149 if ( p -> associationitem1_parameter ) {
150 free ( p -> associationitem1_parameter );
152 if ( p -> associationitem2_name ) {
153 free ( p -> associationitem2_name );
155 if ( p -> associationitem2_filetype ) {
156 free ( p -> associationitem2_filetype );
158 if ( p -> associationitem2_parameter ) {
159 free ( p -> associationitem2_parameter );
161 if ( p -> associationitem3_name ) {
162 free ( p -> associationitem3_name );
164 if ( p -> associationitem1_filetype ) {
165 free ( p -> associationitem3_filetype );
167 if ( p -> associationitem1_parameter ) {
168 free ( p -> associationitem3_parameter );
170 if ( p -> clockspeed ) {
171 free ( p -> clockspeed );
173 if ( p -> background ) {
174 free ( p -> background );
176 if ( p -> startdir ) {
177 free ( p -> startdir );
179 if ( p -> appdata_dirname ) {
180 free ( p -> appdata_dirname );
183 free(p); /*very important!*/
188 void pnd_pxml_set_app_name ( pnd_pxml_handle h, char *v ) {
190 * Please do not use this function if it can be avoided; it is only here for compatibility.
191 * The function might fail on low memory, and there's no way for the user to know when this happens.
193 pnd_pxml_t *p = (pnd_pxml_t*) h;
194 char has_en_field = 0;
197 if (!v) return; /*TODO: add error information? Make it possible to set the string to NULL?*/
199 for (i = 0; i < p->titles_c; i++)
201 if (strncmp("en", p->titles[i].language, 2) == 0) /*strict comparison; match "en_US", "en_GB" etc... All these are set.*/
203 free(p->titles[i].string);
204 p->titles[i].string = strdup(v);
212 if (p->titles_c > p->titles_alloc_c) //we don't have enough strings allocated
214 p->titles_alloc_c <<= 1;
215 p->titles = (pnd_localized_string_t *)realloc((void*)p->titles, p->titles_alloc_c);
216 if (!p->titles) return; //errno = ENOMEM
218 p->titles[p->titles_c - 1].language = "en_US";
219 p->titles[p->titles_c - 1].string = strdup(v);
225 unsigned char pnd_is_pxml_valid_app ( pnd_pxml_handle h ) {
226 //pnd_pxml_t *p = (pnd_pxml_t*) h; //unused atm
228 // for now, lets just verify the exec-path is valid
230 //printf ( "exec is '%s'\n", p -> exec );
234 // even this is complicated by pnd_run.sh semantics .. can't check if it exists
235 // during discovery, since it is not mounted yet..
238 if ( stat ( p -> exec, &buf ) == 0 ) {
239 return ( 1 ); // path is present
246 signed char pnd_pxml_merge_override ( pnd_pxml_handle h, char *searchpath ) {
247 // the pxml includes a unique-id; use this value to attempt to find an
248 // override in the given searchpath
249 signed char retval = 0;
251 #if 0 // TODO: Unfinished entirely now
252 pnd_pxml_handle mergeh;
254 if ( ! pnd_pxml_get_unique_id ( h ) ) {
255 return ( -1 ); // no unique-id present, so can't use it to name potential override files
262 strncat ( buffer, "/", FILENAME_MAX );
263 strncat ( buffer, pnd_pxml_get_unique_id ( h ), FILENAME_MAX );
264 strncat ( buffer, ".xml", FILENAME_MAX );
265 //printf ( " Path to seek merges: '%s'\n", buffer );
267 // TODO: handle multiple subapps!
268 mergeh = pnd_pxml_fetch ( buffer );
272 // TODO: handle all the various data bits
273 if ( pnd_pxml_get_app_name_en ( mergeh ) ) {
274 pnd_pxml_set_app_name ( h, pnd_pxml_get_app_name_en ( mergeh ) );
277 pnd_pxml_delete ( mergeh );
287 char *pnd_pxml_get_best_localized_string(pnd_localized_string_t strings[], int strings_c, char *iso_lang)
290 int similarity_weight = 0xffff; /*Set to something Really Bad in the beginning*/
291 char *best_match = NULL;
293 for(i = 0; i < strings_c; i++)
295 // factor in the length -- if we're given 'en' and have a string 'en_US', thats better than 'de_something'; if we don't
296 // use length, then en_US and de_FO are same to 'en'.
297 int maxcount = strlen ( strings[i].language ) < strlen ( iso_lang ) ? strlen ( strings[i].language ) : strlen ( iso_lang );
298 int new_weight = abs(strncmp(strings[i].language, iso_lang, maxcount));
299 //pnd_log ( PND_LOG_DEFAULT, "looking for lang %s, looking at lang %s (weight %d, old %d): %s\n",
300 // iso_lang, strings [ i ].language, new_weight, similarity_weight, strings [ i ].string );
301 if (new_weight < similarity_weight)
303 similarity_weight = new_weight;
304 best_match = strings[i].string;
309 //pnd_log ( PND_LOG_DEFAULT, "best match: %s\n", best_match );
310 return strdup(best_match);
313 //pnd_log ( PND_LOG_DEFAULT, "best match: FAIL\n" );
318 char *pnd_pxml_get_app_name ( pnd_pxml_handle h, char *iso_lang ) {
319 pnd_pxml_t *p = (pnd_pxml_t *) h;
320 return pnd_pxml_get_best_localized_string(p->titles, p->titles_c, iso_lang);
323 char *pnd_pxml_get_app_name_en ( pnd_pxml_handle h ) {
324 return pnd_pxml_get_app_name(h, "en");
327 char *pnd_pxml_get_app_name_de ( pnd_pxml_handle h ) {
328 return pnd_pxml_get_app_name(h, "de");
331 char *pnd_pxml_get_app_name_it ( pnd_pxml_handle h ) {
332 return pnd_pxml_get_app_name(h, "it");
335 char *pnd_pxml_get_app_name_fr ( pnd_pxml_handle h ) {
336 return pnd_pxml_get_app_name(h, "fr");
339 char *pnd_pxml_get_unique_id ( pnd_pxml_handle h ) {
340 pnd_pxml_t *p = (pnd_pxml_t*) h;
341 return ( p -> unique_id );
344 char *pnd_pxml_get_appdata_dirname ( pnd_pxml_handle h ) {
345 pnd_pxml_t *p = (pnd_pxml_t*) h;
346 return ( p -> appdata_dirname );
349 char *pnd_pxml_get_standalone ( pnd_pxml_handle h ) {
350 pnd_pxml_t *p = (pnd_pxml_t*) h;
351 return ( p -> standalone );
354 char *pnd_pxml_get_icon ( pnd_pxml_handle h ) {
355 pnd_pxml_t *p = (pnd_pxml_t*) h;
356 return ( p -> icon );
359 // this guy's func name is 'out of sync' with the family of functions below; but since it
360 // exists, rather than just remove it and break someones code, will add in the appropriate
361 // function wrapper; the header only specifies the other guy (always did), so the header
362 // was already on the right path.
363 char *pnd_pxml_get_app_description ( pnd_pxml_handle h, char *iso_lang ) {
364 pnd_pxml_t *p = (pnd_pxml_t *) h;
365 return pnd_pxml_get_best_localized_string(p->descriptions, p->descriptions_c, iso_lang);
368 char *pnd_pxml_get_description_en ( pnd_pxml_handle h ) {
369 return pnd_pxml_get_app_description(h, "en");
372 char *pnd_pxml_get_description_de ( pnd_pxml_handle h ) {
373 return pnd_pxml_get_app_description(h, "de");
376 char *pnd_pxml_get_description_it ( pnd_pxml_handle h ) {
377 return pnd_pxml_get_app_description(h, "it");
380 char *pnd_pxml_get_description_fr ( pnd_pxml_handle h ) {
381 return pnd_pxml_get_app_description(h, "fr");
384 // wrapper added so family of function names is consistent; see comment for pnd_pxml_get_app_description() above
385 char *pnd_pxml_get_description ( pnd_pxml_handle h, char *iso_lang) {
386 return ( pnd_pxml_get_app_description ( h, iso_lang ) );
389 char *pnd_pxml_get_previewpic1 ( pnd_pxml_handle h ) {
390 pnd_pxml_t *p = (pnd_pxml_t*) h;
391 return ( p -> previewpic1 );
394 char *pnd_pxml_get_previewpic2 ( pnd_pxml_handle h ) {
395 pnd_pxml_t *p = (pnd_pxml_t*) h;
396 return ( p -> previewpic2 );
399 char *pnd_pxml_get_author_name ( pnd_pxml_handle h ) {
400 pnd_pxml_t *p = (pnd_pxml_t*) h;
401 return ( p -> author_name );
404 char *pnd_pxml_get_author_website ( pnd_pxml_handle h ) {
405 pnd_pxml_t *p = (pnd_pxml_t*) h;
406 return ( p -> author_website );
409 char *pnd_pxml_get_version_major ( pnd_pxml_handle h ) {
410 pnd_pxml_t *p = (pnd_pxml_t*) h;
411 return ( p -> version_major );
414 char *pnd_pxml_get_version_minor ( pnd_pxml_handle h ) {
415 pnd_pxml_t *p = (pnd_pxml_t*) h;
416 return ( p -> version_minor );
419 char *pnd_pxml_get_version_release ( pnd_pxml_handle h ) {
420 pnd_pxml_t *p = (pnd_pxml_t*) h;
421 return ( p -> version_release );
424 char *pnd_pxml_get_version_build ( pnd_pxml_handle h ) {
425 pnd_pxml_t *p = (pnd_pxml_t*) h;
426 return ( p -> version_build );
429 char *pnd_pxml_get_exec ( pnd_pxml_handle h ) {
430 pnd_pxml_t *p = (pnd_pxml_t*) h;
431 return ( p -> exec );
434 char *pnd_pxml_get_execargs ( pnd_pxml_handle h ) {
435 pnd_pxml_t *p = (pnd_pxml_t*) h;
436 return ( p -> execargs );
439 char *pnd_pxml_get_exec_option_no_x11 ( pnd_pxml_handle h ) {
440 pnd_pxml_t *p = (pnd_pxml_t*) h;
441 return ( p -> exec_no_x11 );
444 char *pnd_pxml_get_main_category ( pnd_pxml_handle h ) {
445 pnd_pxml_t *p = (pnd_pxml_t*) h;
446 return ( p -> main_category );
449 char *pnd_pxml_get_subcategory1 ( pnd_pxml_handle h ) {
450 pnd_pxml_t *p = (pnd_pxml_t*) h;
451 return ( p -> subcategory1 );
454 char *pnd_pxml_get_subcategory2 ( pnd_pxml_handle h ) {
455 pnd_pxml_t *p = (pnd_pxml_t*) h;
456 return ( p -> subcategory2 );
459 char *pnd_pxml_get_altcategory ( pnd_pxml_handle h ) {
460 pnd_pxml_t *p = (pnd_pxml_t*) h;
461 return ( p -> altcategory );
464 char *pnd_pxml_get_altsubcategory1 ( pnd_pxml_handle h ) {
465 pnd_pxml_t *p = (pnd_pxml_t*) h;
466 return ( p -> altsubcategory1 );
469 char *pnd_pxml_get_altsubcategory2 ( pnd_pxml_handle h ) {
470 pnd_pxml_t *p = (pnd_pxml_t*) h;
471 return ( p -> altsubcategory2 );
474 char *pnd_pxml_get_osversion_major ( pnd_pxml_handle h ) {
475 pnd_pxml_t *p = (pnd_pxml_t*) h;
476 return ( p -> osversion_major );
479 char *pnd_pxml_get_osversion_minor ( pnd_pxml_handle h ) {
480 pnd_pxml_t *p = (pnd_pxml_t*) h;
481 return ( p -> osversion_minor );
484 char *pnd_pxml_get_osversion_release ( pnd_pxml_handle h ) {
485 pnd_pxml_t *p = (pnd_pxml_t*) h;
486 return ( p -> osversion_release );
489 char *pnd_pxml_get_osversion_build ( pnd_pxml_handle h ) {
490 pnd_pxml_t *p = (pnd_pxml_t*) h;
491 return ( p -> osversion_build );
494 char *pnd_pxml_get_associationitem1_name ( pnd_pxml_handle h ) {
495 pnd_pxml_t *p = (pnd_pxml_t*) h;
496 return ( p -> associationitem1_name );
499 char *pnd_pxml_get_associationitem1_filetype ( pnd_pxml_handle h ) {
500 pnd_pxml_t *p = (pnd_pxml_t*) h;
501 return ( p -> associationitem1_filetype );
504 char *pnd_pxml_get_associationitem1_parameter ( pnd_pxml_handle h ) {
505 pnd_pxml_t *p = (pnd_pxml_t*) h;
506 return ( p -> associationitem1_parameter );
509 char *pnd_pxml_get_associationitem2_name ( pnd_pxml_handle h ) {
510 pnd_pxml_t *p = (pnd_pxml_t*) h;
511 return ( p -> associationitem2_name );
514 char *pnd_pxml_get_associationitem2_filetype ( pnd_pxml_handle h ) {
515 pnd_pxml_t *p = (pnd_pxml_t*) h;
516 return ( p -> associationitem2_filetype );
519 char *pnd_pxml_get_associationitem2_parameter ( pnd_pxml_handle h ) {
520 pnd_pxml_t *p = (pnd_pxml_t*) h;
521 return ( p -> associationitem2_parameter );
524 char *pnd_pxml_get_associationitem3_name ( pnd_pxml_handle h ) {
525 pnd_pxml_t *p = (pnd_pxml_t*) h;
526 return ( p -> associationitem3_name );
529 char *pnd_pxml_get_associationitem3_filetype ( pnd_pxml_handle h ) {
530 pnd_pxml_t *p = (pnd_pxml_t*) h;
531 return ( p -> associationitem3_filetype );
534 char *pnd_pxml_get_associationitem3_parameter ( pnd_pxml_handle h ) {
535 pnd_pxml_t *p = (pnd_pxml_t*) h;
536 return ( p -> associationitem3_parameter );
539 char *pnd_pxml_get_clockspeed ( pnd_pxml_handle h ) {
540 pnd_pxml_t *p = (pnd_pxml_t*) h;
541 return ( p -> clockspeed );
544 char *pnd_pxml_get_background ( pnd_pxml_handle h ) {
545 pnd_pxml_t *p = (pnd_pxml_t*) h;
546 return ( p -> background );
549 char *pnd_pxml_get_startdir ( pnd_pxml_handle h ) {
550 pnd_pxml_t *p = (pnd_pxml_t*) h;
551 return ( p -> startdir );
554 char *pnd_pxml_get_mkdir ( pnd_pxml_handle h ) {
555 pnd_pxml_t *p = (pnd_pxml_t*) h;
556 return ( p -> mkdir_sp );
559 unsigned char pnd_pxml_is_affirmative ( char *v ) {
565 if ( ( v [ 0 ] == 'Y' ) ||
566 ( v [ 0 ] == 'y' ) ||
575 pnd_pxml_x11_req_e pnd_pxml_get_x11 ( char *pxmlvalue ) {
578 return ( pnd_pxml_x11_ignored );
579 } else if ( strcasecmp ( pxmlvalue, "req" ) == 0 ) {
580 return ( pnd_pxml_x11_required );
581 } else if ( strcasecmp ( pxmlvalue, "stop" ) == 0 ) {
582 return ( pnd_pxml_x11_stop );
583 } else if ( strcasecmp ( pxmlvalue, "ignore" ) == 0 ) {
584 return ( pnd_pxml_x11_ignored );
587 return ( pnd_pxml_x11_ignored ); // default
590 char *pnd_pxml_get_info_name ( pnd_pxml_handle h ) {
591 pnd_pxml_t *p = (pnd_pxml_t*) h;
592 return ( p -> info_name );
595 char *pnd_pxml_get_info_type ( pnd_pxml_handle h ) {
596 pnd_pxml_t *p = (pnd_pxml_t*) h;
597 return ( p -> info_type );
600 char *pnd_pxml_get_info_src ( pnd_pxml_handle h ) {
601 pnd_pxml_t *p = (pnd_pxml_t*) h;
602 return ( p -> info_filename );