Large change, to support multiple applications within a single PXML.xml file.
authorskeezix <skeezix@flotsam-vm.(none)>
Mon, 1 Mar 2010 03:52:09 +0000 (22:52 -0500)
committerskeezix <skeezix@flotsam-vm.(none)>
Mon, 1 Mar 2010 03:52:09 +0000 (22:52 -0500)
genpxml script was updated to generate properly formed new XML
test apps were updated to comply
pnd_run will attempt to run all subapps right now, for lack of a better idea :)
pndnotifyd will generate all the icons and .desktop files for all subapps, and it should all work

20 files changed:
apps/pnd_info.c
apps/pnd_run.c
apps/pndnotifyd.c
apps/pndvalidator.c
include/pnd_discovery.h
include/pnd_pxml.h
include/pnd_pxml_names.h
include/pnd_tinyxml.h
include/pnd_utility.h
lib/pnd_desktop.c
lib/pnd_discovery.c
lib/pnd_pxml.c
lib/pnd_tinyxml.cpp
lib/pnd_utility.c
test/rawpxmltest.c
testdata/apps/sampleappX/PXML.xml [new file with mode: 0644]
testdata/apps/sampleappX/PXML.xml.bak2 [new file with mode: 0644]
testdata/apps/sampleappX/program.exe [new file with mode: 0644]
testdata/apps/sampleappX/zeldaicon.png [new file with mode: 0644]
testdata/scripts/genpxml.sh

index a2acb4b..86908bf 100644 (file)
@@ -78,36 +78,45 @@ int main ( int argc, char *argv[] ) {
   }
 
   pnd_pxml_handle h = NULL;
+  pnd_pxml_handle *apps = NULL;
   if ( pnd_pnd_seek_pxml ( f ) ) {
     if ( pnd_pnd_accrue_pxml ( f, pxmlbuf, pxmlbuflen ) ) {
-      h = pnd_pxml_fetch_buffer ( "pnd_run", pxmlbuf );
+      apps = pnd_pxml_fetch_buffer ( "pnd_run", pxmlbuf );
     }
   }
 
   fclose ( f );
 
-  if ( ! h ) {
+  if ( ! apps ) {
     printf ( "ERROR: Couldn't pull PXML.xml from the pndfile.\n" );
     exit ( 0 );
   }
 
-  // display sections
-  for ( i = 0; i < sections; i++ ) {
-    char *t;
+  // iterate across apps
+  while ( *apps ) {
+    h = *apps;
+
+    // display sections
+    for ( i = 0; i < sections; i++ ) {
+      char *t;
+
+      if ( strcasecmp ( section [ i ], "description" ) == 0 ) {
 
-    if ( strcasecmp ( section [ i ], "description" ) == 0 ) {
+       printf ( "Section: %s\n", section [ i ] );
 
-      printf ( "Section: %s\n", section [ i ] );
+       if ( ( t = pnd_pxml_get_description_en ( h ) ) ) {
+         printf ( "%s\n", t );
+       } else {
+         printf ( "Not supplied by PXML.xml in the pnd-file\n" );
+       }
 
-      if ( ( t = pnd_pxml_get_description_en ( h ) ) ) {
-       printf ( "%s\n", t );
-      } else {
-       printf ( "Not supplied by PXML.xml in the pnd-file\n" );
       }
 
-    }
+    } // for
 
-  } // for
+    // next
+    apps++;
+  } // while
 
   return ( 0 );
 } // main
index c012ac6..5baabd4 100644 (file)
@@ -139,40 +139,49 @@ int main ( int argc, char *argv[] ) {
   }
 
   pnd_pxml_handle h = NULL;
+  pnd_pxml_handle *apps = NULL;
   if ( pnd_pnd_seek_pxml ( f ) ) {
     if ( pnd_pnd_accrue_pxml ( f, pxmlbuf, pxmlbuflen ) ) {
-      h = pnd_pxml_fetch_buffer ( "pnd_run", pxmlbuf );
+      apps = pnd_pxml_fetch_buffer ( "pnd_run", pxmlbuf );
     }
   }
 
   fclose ( f );
 
-  if ( ! h ) {
+  if ( ! apps ) {
     printf ( "ERROR: Couldn't pull PXML.xml from the pndfile.\n" );
     exit ( 0 );
   }
 
-  // attempt to invoke
-  unsigned int options = 0;
-  if ( no_x11 ) {
-    options |= PND_EXEC_OPTION_NOX11;
-  }
+  // attempt to invoke.. all of the subapps? just first one?
 
-  unsigned int clock = 200;
-  if ( pnd_pxml_get_clockspeed ( h ) ) {
-    clock = atoi ( pnd_pxml_get_clockspeed ( h ) );
-  }
+  while ( *apps ) {
+    h = *apps;
 
-  if ( ! pnd_apps_exec ( pnd_run, pndfile,
-                        pnd_pxml_get_unique_id ( h ),
-                        pnd_pxml_get_exec ( h ),
-                        pnd_pxml_get_startdir ( h ),
-                        clock,
-                        options )
-       )
-  {
-    printf ( "ERROR: PXML.xml data is bad\n" );
-  }
+    unsigned int options = 0;
+    if ( no_x11 ) {
+      options |= PND_EXEC_OPTION_NOX11;
+    }
+
+    unsigned int clock = 200;
+    if ( pnd_pxml_get_clockspeed ( h ) ) {
+      clock = atoi ( pnd_pxml_get_clockspeed ( h ) );
+    }
+
+    if ( ! pnd_apps_exec ( pnd_run, pndfile,
+                          pnd_pxml_get_unique_id ( h ),
+                          pnd_pxml_get_exec ( h ),
+                          pnd_pxml_get_startdir ( h ),
+                          clock,
+                          options )
+        )
+    {
+      printf ( "ERROR: PXML.xml data is bad\n" );
+    }
+
+    // next
+    apps++;
+  } // while
 
   return ( 0 );
 } // main
index b9b350e..07769e5 100644 (file)
@@ -661,7 +661,7 @@ void process_discoveries ( pnd_box_handle applist, char *emitdesktoppath, char *
     // check if icon already exists (from a previous extraction say); if so, we needn't
     // do it again
     char existingpath [ FILENAME_MAX ];
-    sprintf ( existingpath, "%s/%s.png", emiticonpath, d -> unique_id );
+    sprintf ( existingpath, "%s/%s#%u.png", emiticonpath, d -> unique_id, d -> subapp_number );
 
     struct stat dirs;
     if ( stat ( existingpath, &dirs ) == 0 ) {
index 4307b31..b21ab46 100644 (file)
@@ -68,33 +68,44 @@ int main ( int argc, char *argv[] ) {
   // actually do useful work
   //
 
-  pnd_pxml_handle pxmlh;
+  pnd_pxml_handle *pxmlapps;
 
-  pxmlh = pnd_pxml_get_by_path ( fullpath );
+  pxmlapps = pnd_pxml_get_by_path ( fullpath );
 
-  if ( ! pxmlh ) {
+  if ( ! pxmlapps ) {
     printf ( "ERROR: PXML could not be extracted meaningfully.\n" );
     return ( 0 );
   }
 
-  printf ( "Got back a meaningful PXML structure.\n" );
+  printf ( "Got back a meaningful list of PXMLs.\n" );
 
-  /* check the content
-   */
+  pnd_pxml_handle h = *pxmlapps;
+
+  while ( h ) {
+
+    /* check the content
+     */
 
-  // check for required fields
+    // check for required fields
 
-  // exec-path?
+    // exec-path?
 
-  // app name?
+    // app name?
 
-  // unique ID
+    // unique ID
 
-  // package-name (shortname)
+    // package-name (shortname)
+
+    // free up that particular pxml_handle within the return-list
+
+    // next
+    pxmlapps++;
+    h = pxmlapps;
+  } // while
 
   /* done!
    */
-  pnd_pxml_delete ( pxmlh );
+  pnd_pxml_delete ( pxmlapps );
 
   return ( 0 );
 }
index e4b11b4..b8aaa2b 100644 (file)
@@ -49,6 +49,7 @@ typedef struct {
   char *object_path;           // directory containing pnd or PXML.xml (does not include filename)
   char *object_filename;       // filename within object_path of the app: the PXML.xml or awesomeapp.pnd file itself
   unsigned int pnd_icon_pos;   // offset to the byte after end of PXML in a pnd file (should be icon if present)
+  unsigned char subapp_number; // # of app within PXML (ie: 0, 1, 2, 3, up to the number of apps within the PXML)
   // strdup'd from PXML -- hey, who was the idiot who thought it was a reat idea not to just re-use the pxml-struct?
   char *title_en;
   char *desc_en;
index 01e32d5..2ef0e80 100644 (file)
@@ -12,14 +12,16 @@ extern "C" {
 #define PXML_TAGHEAD "<PXML" /* case insensitive; allow for trailing attributes */
 #define PXML_TAGFOOT "</PXML>" /* case insensitive */
 
+#define PXML_MAXAPPS 20 /* max number of <application>'s within a single PXML */
+
 // use this handle to interact with PXML; this hides the mechanics of parsing a PXML file so that
 // it can be upgraded with impacting applications
 typedef void* pnd_pxml_handle;
 
 /* pxml_fetch() will return NULL on fail, otherwise a valid handle which may be further queried
  */
-pnd_pxml_handle pnd_pxml_fetch ( char *fullpath );
-pnd_pxml_handle pnd_pxml_fetch_buffer ( char *filename, char *buffer );
+pnd_pxml_handle *pnd_pxml_fetch ( char *fullpath );
+pnd_pxml_handle *pnd_pxml_fetch_buffer ( char *filename, char *buffer );
 void pnd_pxml_delete ( pnd_pxml_handle h );
 
 /* overrides() allow for customization of a PXML that persists; ie: An application might be sitting
@@ -101,6 +103,7 @@ typedef struct
 
 typedef struct
 {
+        unsigned char subapp_number; // 0 for 'only app'; 1+ for <application> # .. first <application> is 1.
        pnd_localized_string_t *titles;
        int titles_c;
        int titles_alloc_c;
index 39f72d2..c476c21 100644 (file)
@@ -8,6 +8,9 @@ extern "C" {
 /* <PXML id="..."> ...*/
 #define PND_PXML_ATTRNAME_UID "id"
 
+/* <application id="123">*/
+#define PND_PXML_APP "application"
+
 /* <title lang="..."> */
 #define PND_PXML_ENAME_TITLE "title"
 #define PND_PXML_ATTRNAME_TITLELANG "lang"
index efa4371..81965d3 100644 (file)
@@ -6,8 +6,7 @@
 extern "C" {
 #endif
 
-unsigned char pnd_pxml_load ( const char* pFilename, pnd_pxml_t *app );
-unsigned char pnd_pxml_parse ( const char *pFilename, char *buffer, unsigned int length, pnd_pxml_t *app );
+unsigned char pnd_pxml_parse ( const char *pFilename, char *buffer, unsigned int length, pnd_pxml_t **apps );
 
 #ifdef __cplusplus
 }
index f9dce27..3be73d2 100644 (file)
@@ -19,11 +19,8 @@ char *pnd_expand_tilde ( char *freeable_buffer );
 // arbtrary execute function; fire and forget really
 void pnd_exec_no_wait_1 ( char *fullpath, char *arg1 );
 
-// pnd_pxml_get_always() will work against a PXML.xml file or a foo.pnd app-bundle and return
-// the resulting PXML structure, or fail; ie: It should be handy to avoid the user having to
-// do the 'what type is this, and if-this-or-that' themselves.
-//   NOTE: Does _NOT_ automatically pick up PXML-overrides; you can call that function if you want
-pnd_pxml_handle pnd_pxml_get_by_path ( char *fullpath );
+//  NOTE: Does _NOT_ automatically pick up PXML-overrides; you can call that function if you want
+pnd_pxml_handle *pnd_pxml_get_by_path ( char *fullpath );
 
 // determine_mountpoint() will examine a path, and return the mountpoint that this path
 // is sitting on; returns 1 on success, meaning the target was populated.
index 199825f..51992c4 100644 (file)
@@ -11,6 +11,7 @@
 #include "pnd_pndfiles.h"
 #include "pnd_conf.h"
 #include "pnd_desktop.h"
+#include "pnd_logger.h"
 
 unsigned char pnd_emit_dotdesktop ( char *targetpath, char *pndrun, pnd_disco_t *p ) {
   char filename [ FILENAME_MAX ];
@@ -23,24 +24,28 @@ unsigned char pnd_emit_dotdesktop ( char *targetpath, char *pndrun, pnd_disco_t
   // validation
 
   if ( ! p -> unique_id ) {
+    pnd_log ( PND_LOG_DEFAULT, "Can't emit dotdesktop for %s, missing unique-id\n", targetpath );
     return ( 0 );
   }
 
   if ( ! p -> exec ) {
+    pnd_log ( PND_LOG_DEFAULT, "Can't emit dotdesktop for %s, missing exec\n", targetpath );
     return ( 0 );
   }
 
   if ( ! targetpath ) {
+    pnd_log ( PND_LOG_DEFAULT, "Can't emit dotdesktop for %s, missing target path\n", targetpath );
     return ( 0 );
   }
 
   if ( ! pndrun ) {
+    pnd_log ( PND_LOG_DEFAULT, "Can't emit dotdesktop for %s, missing pnd_run.sh\n", targetpath );
     return ( 0 );
   }
 
   // set up
 
-  sprintf ( filename, "%s/%s.desktop", targetpath, p -> unique_id );
+  sprintf ( filename, "%s/%s#%u.desktop", targetpath, p -> unique_id, p -> subapp_number );
 
   // emit
 
@@ -195,7 +200,7 @@ unsigned char pnd_emit_icon ( char *targetpath, pnd_disco_t *p ) {
   }
 
   // determine filename for target
-  sprintf ( buffer, "%s/%s.png", targetpath, p -> unique_id ); // target
+  sprintf ( buffer, "%s/%s#%u.png", targetpath, p -> unique_id, p -> subapp_number ); // target
 
   /* first.. open the source file, by type of application:
    * are we looking through a pnd file or a dir?
index 73ed18e..88a1126 100644 (file)
@@ -47,6 +47,8 @@ static int pnd_disco_callback ( const char *fpath, const struct stat *sb,
 {
   unsigned char valid = pnd_object_type_unknown;
   pnd_pxml_handle pxmlh = 0;
+  pnd_pxml_handle *pxmlapps = NULL;
+  pnd_pxml_handle *pxmlappiter;
   unsigned int pxml_close_pos = 0;
   unsigned char logit = pnd_log_do_buried_logging();
 
@@ -84,7 +86,7 @@ static int pnd_disco_callback ( const char *fpath, const struct stat *sb,
     //printf ( "PXML: disco callback encountered '%s'\n", fpath );
 
     // pick up the PXML if we can
-    pxmlh = pnd_pxml_fetch ( (char*) fpath );
+    pxmlapps = pnd_pxml_fetch ( (char*) fpath );
 
   } else if ( valid == pnd_object_type_pnd ) {
     // PND ... ??
@@ -147,7 +149,7 @@ static int pnd_disco_callback ( const char *fpath, const struct stat *sb,
 #endif
 
     // by now, we have <PXML> .. </PXML>, try to parse..
-    pxmlh = pnd_pxml_fetch_buffer ( (char*) fpath, pxmlbuf );
+    pxmlapps = pnd_pxml_fetch_buffer ( (char*) fpath, pxmlbuf );
 
     // done with file
     fclose ( f );
@@ -155,7 +157,19 @@ static int pnd_disco_callback ( const char *fpath, const struct stat *sb,
   }
 
   // pxmlh is useful?
-  if ( pxmlh ) {
+  if ( ! pxmlapps ) {
+    return ( 0 ); // continue tree walk
+  }
+
+  // iterate across apps in the PXML
+  pxmlappiter = pxmlapps;
+  while ( 1 ) {
+    pxmlh = *pxmlappiter;
+    pxmlappiter++;
+
+    if ( ! pxmlh ) {
+      break; // all done
+    }
 
     // look for any overrides, if requested
     pnd_pxml_merge_override ( pxmlh, disco_overrides );
@@ -166,6 +180,8 @@ static int pnd_disco_callback ( const char *fpath, const struct stat *sb,
       char *fixpxml;
       char *z;
 
+      pnd_log ( PND_LOG_DEFAULT, "Setting up discovered app %u\n", ((pnd_pxml_t*) pxmlh) -> subapp_number );
+
       p = pnd_box_allocinsert ( disco_box, (char*) fpath, sizeof(pnd_disco_t) );
 
       // base paths
@@ -181,6 +197,9 @@ static int pnd_disco_callback ( const char *fpath, const struct stat *sb,
        p -> object_filename = strdup ( fixpxml + 1 );
       }
 
+      // subapp-number
+      p -> subapp_number = ((pnd_pxml_t*) pxmlh) -> subapp_number;
+
       // png icon path
       p -> pnd_icon_pos = pxml_close_pos;
 
@@ -250,7 +269,10 @@ static int pnd_disco_callback ( const char *fpath, const struct stat *sb,
     // ditch pxml
     pnd_pxml_delete ( pxmlh );
 
-  } // got a pxmlh
+  } // while pxmlh is good
+
+  // free up the applist
+  free ( pxmlapps );
 
   return ( 0 ); // continue the tree walk
 }
index 6f981a2..09a7fb6 100644 (file)
 #include "pnd_pathiter.h"
 #include "pnd_tinyxml.h"
 
-pnd_pxml_handle pnd_pxml_fetch ( char *fullpath ) {
+pnd_pxml_handle *pnd_pxml_fetch ( char *fullpath ) {
+  FILE *f;
+  char *b;
+  unsigned int len;
 
-  pnd_pxml_t *p = malloc ( sizeof(pnd_pxml_t) );
+  f = fopen ( fullpath, "r" );
 
-  memset ( p, '\0', sizeof(pnd_pxml_t) );
+  if ( ! f ) {
+    return ( 0 );
+  }
+
+  fseek ( f, 0, SEEK_END );
+
+  len = ftell ( f );
+
+  fseek ( f, 0, SEEK_SET );
+
+  b = (char*) malloc ( len );
 
-  if ( ! pnd_pxml_load ( fullpath, p ) ) {
+  if ( ! b ) {
+    fclose ( f );
     return ( 0 );
   }
 
-  return ( p );
-}
+  fread ( b, 1, len, f );
+
+  fclose ( f );
 
-pnd_pxml_handle pnd_pxml_fetch_buffer ( char *filename, char *buffer ) {
+  return ( pnd_pxml_fetch_buffer ( fullpath, b ) );
+}
 
-  pnd_pxml_t *p = malloc ( sizeof(pnd_pxml_t) );
+pnd_pxml_handle *pnd_pxml_fetch_buffer ( char *filename, char *buffer ) {
 
-  memset ( p, '\0', sizeof(pnd_pxml_t) );
+  pnd_pxml_t **p = malloc ( sizeof(pnd_pxml_t*) * PXML_MAXAPPS );
+  memset ( p, '\0', sizeof(pnd_pxml_t*) * PXML_MAXAPPS );
 
   if ( ! pnd_pxml_parse ( filename, buffer, strlen ( buffer ), p ) ) {
     return ( 0 );
   }
 
-  return ( p );
+  return ( (pnd_pxml_handle*) p );
 }
 
 void pnd_pxml_delete ( pnd_pxml_handle h ) {
@@ -226,6 +243,8 @@ signed char pnd_pxml_merge_override ( pnd_pxml_handle h, char *searchpath ) {
   // the pxml includes a unique-id; use this value to attempt to find an
   // override in the given searchpath
   signed char retval = 0;
+
+#if 0 // TODO: Unfinished entirely now
   pnd_pxml_handle mergeh;
 
   if ( ! pnd_pxml_get_unique_id ( h ) ) {
@@ -241,10 +260,12 @@ signed char pnd_pxml_merge_override ( pnd_pxml_handle h, char *searchpath ) {
     strncat ( buffer, ".xml", FILENAME_MAX );
     //printf ( "  Path to seek merges: '%s'\n", buffer );
 
+    // TODO: handle multiple subapps!
     mergeh = pnd_pxml_fetch ( buffer );
 
     if ( mergeh ) {
 
+      // TODO: handle all the various data bits
       if ( pnd_pxml_get_app_name_en ( mergeh ) ) {
        pnd_pxml_set_app_name ( h, pnd_pxml_get_app_name_en ( mergeh ) );
       }
@@ -254,6 +275,7 @@ signed char pnd_pxml_merge_override ( pnd_pxml_handle h, char *searchpath ) {
 
   }
   SEARCHPATH_POST
+#endif
 
   return ( retval );
 }
index b11d450..59f7e4d 100644 (file)
@@ -1,44 +1,15 @@
 
+#include <stdio.h>
 #include "tinyxml/tinyxml.h"
 #include "../include/pnd_pxml.h"
 #include "pnd_tinyxml.h"
+#include "pnd_logger.h"
 
 //Easily change the tag names if required (globally in this file):
 #include "pnd_pxml_names.h"
 
 extern "C" {
 
-unsigned char pnd_pxml_load ( const char* pFilename, pnd_pxml_t *app ) {
-  FILE *f;
-  char *b;
-  unsigned int len;
-
-  f = fopen ( pFilename, "r" );
-
-  if ( ! f ) {
-    return ( 0 );
-  }
-
-  fseek ( f, 0, SEEK_END );
-
-  len = ftell ( f );
-
-  fseek ( f, 0, SEEK_SET );
-
-  b = (char*) malloc ( len );
-
-  if ( ! b ) {
-    fclose ( f );
-    return ( 0 );
-  }
-
-  fread ( b, 1, len, f );
-
-  fclose ( f );
-
-  return ( pnd_pxml_parse ( pFilename, b, len, app ) );
-}
-
 char *pnd_pxml_get_attribute(TiXmlElement *elem, const char *name)
 {
        const char *value = elem->Attribute(name);
@@ -48,43 +19,45 @@ char *pnd_pxml_get_attribute(TiXmlElement *elem, const char *name)
                return NULL;
 }
 
-unsigned char pnd_pxml_parse_titles(const TiXmlHandle hRoot, pnd_pxml_t *app)
-{
-       TiXmlElement *pElem;
-       app->titles_alloc_c = 4;  //TODO: adjust this based on how many titles a PXML usually has. Power of 2.
+unsigned char pnd_pxml_parse_titles(const TiXmlHandle hRoot, pnd_pxml_t *app) {
+  TiXmlElement *pElem;
+  app->titles_alloc_c = 4;  //TODO: adjust this based on how many titles a PXML usually has. Power of 2.
 
-       app->titles = (pnd_localized_string_t *)malloc(sizeof(pnd_localized_string_t) * app->titles_alloc_c);
-       if (!app->titles) return (0); //errno = NOMEM
+  app->titles = (pnd_localized_string_t *)malloc(sizeof(pnd_localized_string_t) * app->titles_alloc_c);
+  if (!app->titles) return (0); //errno = NOMEM
 
-       //Go through all title tags and load them.
-       for (pElem = hRoot.FirstChild(PND_PXML_ENAME_TITLE).Element(); pElem;
-               pElem = pElem->NextSiblingElement(PND_PXML_ENAME_TITLE))
-       {
+  //Go through all title tags and load them.
+  for (pElem = hRoot.FirstChild(PND_PXML_ENAME_TITLE).Element(); pElem;
+       pElem = pElem->NextSiblingElement(PND_PXML_ENAME_TITLE))
+  {
 
-         if ( ! pElem->GetText() ) {
-           continue;
-         }
+    if ( ! pElem->GetText() ) {
+      continue;
+    }
 
-               char *text = strdup(pElem->GetText());
-               if (!text) continue;
+    char *text = strdup(pElem->GetText());
+    if (!text) continue;
 
-               char *lang = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_TITLELANG);
-               if (!lang) continue;
+    char *lang = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_TITLELANG);
+    if (!lang) continue;
 
-               app->titles_c++;
-               if (app->titles_c > app->titles_alloc_c) //we don't have enough strings allocated
-               {
-                       app->titles_alloc_c <<= 1;
-                       app->titles = (pnd_localized_string_t *)realloc((void*)app->titles, app->titles_alloc_c);
-                       if (!app->titles) return (0); //errno = ENOMEM
-               }
+    app->titles_c++;
+    if (app->titles_c > app->titles_alloc_c) //we don't have enough strings allocated
+    {
+      app->titles_alloc_c <<= 1;
+      app->titles = (pnd_localized_string_t *)realloc((void*)app->titles, app->titles_alloc_c);
+      if (!app->titles) return (0); //errno = ENOMEM
+    }
 
-               pnd_localized_string_t *title = &app->titles[app->titles_c - 1];
-               title->language = lang;
-               title->string = text;
-       }
+    pnd_localized_string_t *title = &app->titles[app->titles_c - 1];
+    title->language = lang;
+    title->string = text;
 
-       return (1);
+    pnd_log ( PND_LOG_DEFAULT, (char*)"    Title/Lang: %s/%s\n", text, lang );
+
+  }
+
+  return ( 1 );
 }
 
 unsigned char pnd_pxml_parse_descriptions(const TiXmlHandle hRoot, pnd_pxml_t *app)
@@ -128,231 +101,298 @@ unsigned char pnd_pxml_parse_descriptions(const TiXmlHandle hRoot, pnd_pxml_t *a
        return (1);
 }
 
-unsigned char pnd_pxml_parse ( const char *pFilename, char *buffer, unsigned int length, pnd_pxml_t *app ) {
-       //Load the XML document
-       TiXmlDocument doc;
-       doc.Parse(buffer);
+unsigned char pnd_pxml_parse ( const char *pFilename, char *buffer, unsigned int length, pnd_pxml_t **apps ) {
 
-       TiXmlElement *pElem = NULL;
+  //Load the XML document
+  TiXmlDocument doc;
+  doc.Parse(buffer);
 
-       //Find the root element
-       TiXmlHandle hDoc(&doc);
-       TiXmlHandle hRoot(0);
+  unsigned char appwrappermode = 0; // >=1 -> using <application>...</application> wrapper
+  unsigned char appcount = 0;
+  pnd_pxml_t *app = NULL;
 
-       pElem = hDoc.FirstChild("PXML").Element();
-       if (!pElem) return (0);
-       hRoot = TiXmlHandle(pElem);
+  TiXmlElement *pElem = NULL;
+  TiXmlElement *appElem = NULL;
 
-       //Get unique ID first.
-       app->unique_id = pnd_pxml_get_attribute(hRoot.Element(), PND_PXML_ATTRNAME_UID);
+  //Find the root element
+  TiXmlHandle hDoc(&doc);
+  TiXmlHandle hRoot(0);
 
-       //Everything related to the title:
-       pnd_pxml_parse_titles(hRoot, app);
+  pElem = hDoc.FirstChild("PXML").Element();
+  if (!pElem) return (0);
 
-       //Everything description-related:
-       pnd_pxml_parse_descriptions(hRoot, app);
+  // new Strategy; really, we want multiple app support within a PXML, without the lameness of
+  // multiple <PXML>..</PXML> within a single PXML.xml file. As such, we should have an app within
+  // an <application>..</application> wrapper level, with the ID on that. Further, the icon and
+  // .desktop filenames can have a # appended which is the application-count-# within the PXML,
+  // so that they can have their own .desktop and icon without collisions, but still use the
+  // same unique-id if they want to.
+  //   To avoid breaking existing PXML's (even though we're pre-launch), can detect if ID
+  // is present in PXML line or not; if not, assume application mode?
+  hRoot = TiXmlHandle(pElem);
 
-       //Everything launcher-related in one tag:
-       if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_EXEC).Element()) )
-       {
-               app->background = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECBG); //if this returns NULL, the struct is filled with NULL. No need to check.
-               app->standalone = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECSTAL);
-               app->exec       = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECCMD);
-               app->startdir   = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECWD);
-               app->exec_no_x11     = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECNOX11);
-       }
+  if ( hRoot.FirstChild(PND_PXML_APP).Element() != NULL ) {
+    appwrappermode = 1;
+    appElem = hRoot.FirstChild(PND_PXML_APP).Element();
+    hRoot = TiXmlHandle ( appElem );
+  }
 
-       //The app icon:
-       if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_ICON).Element()) )
+  // until we run out of applications in the PXML..
+  while ( 1 ) {
+
+    pnd_log ( PND_LOG_DEFAULT, (char*)"  App #%u inside of PXML %s\n", appcount, pFilename );
+
+    // create the buffer to hold the pxml
+    apps [ appcount ] = (pnd_pxml_t*) malloc ( sizeof(pnd_pxml_t) );
+    memset ( apps [ appcount ], '\0', sizeof(pnd_pxml_t) );
+
+    // due to old code, just make life easier a minute..
+    app = apps [ appcount ];
+    if ( appwrappermode ) {
+      app -> subapp_number = appcount;
+    } else {
+      app -> subapp_number = 0;
+    }
+
+    //Get unique ID first.
+    if ( appwrappermode ) {
+      app->unique_id = pnd_pxml_get_attribute(appElem, PND_PXML_ATTRNAME_UID);
+      pnd_log ( PND_LOG_DEFAULT, (char*)"  Subapp #%u has unique_id %s\n", appcount, app -> unique_id );
+    } else {
+      app->unique_id = pnd_pxml_get_attribute(hRoot.Element(), PND_PXML_ATTRNAME_UID);
+      pnd_log ( PND_LOG_DEFAULT, (char*)"  Only-app #%u has unique_id %s\n", appcount, app -> unique_id );
+    }
+
+    //Everything related to the title:
+    pnd_pxml_parse_titles(hRoot, app);
+
+    //Everything description-related:
+    pnd_pxml_parse_descriptions(hRoot, app);
+
+    //Everything launcher-related in one tag:
+    if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_EXEC).Element()) )
+     {
+       app->background = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECBG); //if this returns NULL, the struct is filled with NULL. No need to check.
+       app->standalone = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECSTAL);
+       app->exec       = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECCMD);
+       app->startdir   = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECWD);
+       app->exec_no_x11     = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECNOX11);
+     }
+
+    //The app icon:
+    if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_ICON).Element()) ) {
+      app->icon       = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ICONSRC);
+    }
+
+    //The preview pics:
+    if ( (pElem = hRoot.FirstChild(PND_PXML_NODENAME_PREVPICS).Element()) )
+    {
+      //TODO: Change this if pnd_pxml_t gains the feature of more pics than 2.
+      if ( (pElem = pElem->FirstChildElement(PND_PXML_ENAME_PREVPIC)) )
+      {
+       app->previewpic1 = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_PREVPICSRC);
+
+       if ( (pElem = pElem->NextSiblingElement(PND_PXML_ENAME_PREVPIC)) )
        {
-               app->icon       = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ICONSRC);
+         app->previewpic2 = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_PREVPICSRC);
        }
-
-       //The preview pics:
-       if ( (pElem = hRoot.FirstChild(PND_PXML_NODENAME_PREVPICS).Element()) )
+      }        
+    } //previewpic
+
+    //The author info:
+    if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_AUTHOR).Element()) )
+    {
+      app->author_name    = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_AUTHORNAME);
+      app->author_website = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_AUTHORWWW);
+      //TODO: Uncomment this if the author gets email support.
+      //app->author_email = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_AUTHOREMAIL));
+    }
+
+    //The version info:
+    if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_VERSION).Element()) )
+    {
+      app->version_major   = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERMAJOR);
+      app->version_minor   = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERMINOR);
+      app->version_release = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERREL);
+      app->version_build   = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERBUILD);
+    }
+
+    //The OS version info:
+    if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_OSVERSION).Element()) )
+    {
+      app->osversion_major   = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_OSVERMAJOR);
+      app->osversion_minor   = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_OSVERMINOR);
+      app->osversion_release = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_OSVERREL);
+      app->osversion_build   = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_OSVERBUILD);
+    }
+
+    int i; //For now, we need to keep track of the index of categories.
+    //Categories:
+    if ( (pElem = hRoot.FirstChildElement(PND_PXML_NODENAME_CATS).Element()) ) //First, enter the "categories" node.
+    {
+      i = 0;
+
+      //Goes through all the top-level categories and their sub-categories. i helps limit these to 2.
+      for (pElem = pElem->FirstChildElement(PND_PXML_ENAME_CAT); pElem && i < 2; 
+          pElem = pElem->NextSiblingElement(PND_PXML_ENAME_CAT), i++)
+      {
+       //TODO: Fix pnd_pxml_t so that there can be more than 2 category 'trees' and more than 2 subcategories. Then this can be removed.
+       switch (i)
        {
-               //TODO: Change this if pnd_pxml_t gains the feature of more pics than 2.
-               if ( (pElem = pElem->FirstChildElement(PND_PXML_ENAME_PREVPIC)) )
-               {
-                       app->previewpic1 = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_PREVPICSRC);
-
-                       if ( (pElem = pElem->NextSiblingElement(PND_PXML_ENAME_PREVPIC)) )
-                       {
-                               app->previewpic2 = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_PREVPICSRC);
-                       }
-               }       
-       } //previewpic
+       case 0: //first category counts as the main cat for now
+         app->main_category = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_CATNAME);
+         break;
 
-       //The author info:
-       if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_AUTHOR).Element()) )
-       {
-               app->author_name    = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_AUTHORNAME);
-               app->author_website = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_AUTHORWWW);
-               //TODO: Uncomment this if the author gets email support.
-               //app->author_email = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_AUTHOREMAIL));
+       case 1: //...second as the alternative
+         app->altcategory = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_CATNAME);
        }
 
-       //The version info:
-       if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_VERSION).Element()) )
+       TiXmlElement *pSubCatElem; //the sub-elements for a main category.
+       int j = 0; //the subcategory index within this category
+
+       //Goes through all the subcategories within this category. j helps limit these to 2.
+       for (pSubCatElem = pElem->FirstChildElement(PND_PXML_ENAME_SUBCAT); pSubCatElem && j < 2;
+            pSubCatElem = pSubCatElem->NextSiblingElement(PND_PXML_ENAME_SUBCAT), j++)
        {
-               app->version_major   = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERMAJOR);
-               app->version_minor   = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERMINOR);
-               app->version_release = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERREL);
-               app->version_build   = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERBUILD);
+         char *subcat = pnd_pxml_get_attribute(pSubCatElem, PND_PXML_ATTRNAME_SUBCATNAME);
+         if (!(subcat)) continue;
+
+         //TODO: This is ugly. Fix pnd_pxml_t so that there can be more than 2 category 'trees' and more than 2 subcategories. Then this can be removed.
+         switch (j | (i << 1))
+         {
+         case 0:
+           app->subcategory1 = subcat;
+           break;
+         case 1:
+           app->subcategory2 = subcat;
+           break;
+         case 2:
+           app->altsubcategory1 = subcat;
+           break;
+         case 3:
+           app->altsubcategory2 = subcat;
+         }
        }
-
-       //The OS version info:
-       if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_OSVERSION).Element()) )
+      }
+    }
+
+    //All file associations:
+    //Step into the associations node
+    if ( (pElem = hRoot.FirstChild(PND_PXML_NODENAME_ASSOCS).Element()) )
+    {
+      i = 0;
+      //Go through all associations. i serves as index; since the format only supports 3 associations we need to keep track of the number.
+      for (pElem = pElem->FirstChildElement(PND_PXML_ENAME_ASSOC); pElem && i < 3; 
+          pElem = pElem->NextSiblingElement(PND_PXML_ENAME_ASSOC), i++)
+      {
+       char *name = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ASSOCNAME);
+       char *filetype = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ASSOCFTYPE);
+       char *paramter = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ASSOCARGS);
+
+       if (!(name && filetype && paramter)) continue;
+
+       switch(i) //TODO: same problem here: only 3 associations supported
        {
-               app->osversion_major   = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_OSVERMAJOR);
-               app->osversion_minor   = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_OSVERMINOR);
-               app->osversion_release = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_OSVERREL);
-               app->osversion_build   = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_OSVERBUILD);
+       case 0:
+       {
+         app->associationitem1_name      = name;
+         app->associationitem1_filetype  = filetype;
+         app->associationitem1_parameter = paramter;
+         break;
        }
-
-       int i; //For now, we need to keep track of the index of categories.
-       //Categories:
-       if ( (pElem = hRoot.FirstChildElement(PND_PXML_NODENAME_CATS).Element()) ) //First, enter the "categories" node.
+       case 1:
        {
-               i = 0;
-
-               //Goes through all the top-level categories and their sub-categories. i helps limit these to 2.
-               for (pElem = pElem->FirstChildElement(PND_PXML_ENAME_CAT); pElem && i < 2; 
-                       pElem = pElem->NextSiblingElement(PND_PXML_ENAME_CAT), i++)
-               {
-                       //TODO: Fix pnd_pxml_t so that there can be more than 2 category 'trees' and more than 2 subcategories. Then this can be removed.
-                       switch (i)
-                       {
-                       case 0: //first category counts as the main cat for now
-                               app->main_category = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_CATNAME);
-                               break;
-
-                       case 1: //...second as the alternative
-                               app->altcategory = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_CATNAME);
-                       }
-
-                       TiXmlElement *pSubCatElem; //the sub-elements for a main category.
-                       int j = 0; //the subcategory index within this category
-
-                       //Goes through all the subcategories within this category. j helps limit these to 2.
-                       for (pSubCatElem = pElem->FirstChildElement(PND_PXML_ENAME_SUBCAT); pSubCatElem && j < 2;
-                               pSubCatElem = pSubCatElem->NextSiblingElement(PND_PXML_ENAME_SUBCAT), j++)
-                       {
-                               char *subcat = pnd_pxml_get_attribute(pSubCatElem, PND_PXML_ATTRNAME_SUBCATNAME);
-                               if (!(subcat)) continue;
-
-                               //TODO: This is ugly. Fix pnd_pxml_t so that there can be more than 2 category 'trees' and more than 2 subcategories. Then this can be removed.
-                               switch (j | (i << 1))
-                               {
-                               case 0:
-                                       app->subcategory1 = subcat;
-                                       break;
-                               case 1:
-                                       app->subcategory2 = subcat;
-                                       break;
-                               case 2:
-                                       app->altsubcategory1 = subcat;
-                                       break;
-                               case 3:
-                                       app->altsubcategory2 = subcat;
-                               }
-                       }
-               }
+         app->associationitem2_name      = name;
+         app->associationitem2_filetype  = filetype;
+         app->associationitem2_parameter = paramter;
+         break;
        }
-
-       //All file associations:
-       //Step into the associations node
-       if ( (pElem = hRoot.FirstChild(PND_PXML_NODENAME_ASSOCS).Element()) )
+       case 2:
        {
-               i = 0;
-               //Go through all associations. i serves as index; since the format only supports 3 associations we need to keep track of the number.
-               for (pElem = pElem->FirstChildElement(PND_PXML_ENAME_ASSOC); pElem && i < 3; 
-                       pElem = pElem->NextSiblingElement(PND_PXML_ENAME_ASSOC), i++)
-               {
-                       char *name = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ASSOCNAME);
-                       char *filetype = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ASSOCFTYPE);
-                       char *paramter = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ASSOCARGS);
-
-                       if (!(name && filetype && paramter)) continue;
-
-                       switch(i) //TODO: same problem here: only 3 associations supported
-                       {
-                               case 0:
-                               {
-                                       app->associationitem1_name      = name;
-                                       app->associationitem1_filetype  = filetype;
-                                       app->associationitem1_parameter = paramter;
-                                       break;
-                               }
-                               case 1:
-                               {
-                                       app->associationitem2_name      = name;
-                                       app->associationitem2_filetype  = filetype;
-                                       app->associationitem2_parameter = paramter;
-                                       break;
-                               }
-                               case 2:
-                               {
-                                       app->associationitem3_name      = name;
-                                       app->associationitem3_filetype  = filetype;
-                                       app->associationitem3_parameter = paramter;
-                               }
-                       }
-               }
+         app->associationitem3_name      = name;
+         app->associationitem3_filetype  = filetype;
+         app->associationitem3_parameter = paramter;
        }
-
-       //Performance related things (aka: Clockspeed XD):
-       pElem = hRoot.FirstChild(PND_PXML_ENAME_CLOCK).Element();
-       if (pElem)
-       {       
-               app->clockspeed = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_CLOCKFREQ);
        }
-
-       // Package
-       pElem = hRoot.FirstChild ( PND_PXML_ENAME_PACKAGE ).Element();
-       if ( pElem ) {  
-         app -> package_name = pnd_pxml_get_attribute ( pElem, PND_PXML_ATTRNAME_PACKAGE_NAME );
-         app -> package_release_date = pnd_pxml_get_attribute ( pElem, PND_PXML_ATTRNAME_PACKAGE_DATE );
+      }
+    }
+
+    //Performance related things (aka: Clockspeed XD):
+    pElem = hRoot.FirstChild(PND_PXML_ENAME_CLOCK).Element();
+    if (pElem)
+    {  
+      app->clockspeed = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_CLOCKFREQ);
+    }
+
+    // Package
+    pElem = hRoot.FirstChild ( PND_PXML_ENAME_PACKAGE ).Element();
+    if ( pElem ) {     
+      app -> package_name = pnd_pxml_get_attribute ( pElem, PND_PXML_ATTRNAME_PACKAGE_NAME );
+      app -> package_release_date = pnd_pxml_get_attribute ( pElem, PND_PXML_ATTRNAME_PACKAGE_DATE );
+    }
+
+    // mkdir request
+    if ( (pElem = hRoot.FirstChild(PND_PXML_NODENAME_MKDIR).Element()) ) {
+
+      // seek <dir>
+      if ( (pElem = pElem->FirstChildElement(PND_PXML_ENAME_MKDIR)) ) {
+       char *t;
+
+       if ( ( t = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_MKDIRPATH) ) ) {
+         // first <dir>, so just replace it wholesale; we use strdup so we can free() easily later, consistently. Mmm, leak seems imminent.
+         app -> mkdir_sp = strdup ( t );
        }
 
-       // mkdir request
-       if ( (pElem = hRoot.FirstChild(PND_PXML_NODENAME_MKDIR).Element()) ) {
-
-         // seek <dir>
-         if ( (pElem = pElem->FirstChildElement(PND_PXML_ENAME_MKDIR)) ) {
-           char *t;
-
-           if ( ( t = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_MKDIRPATH) ) ) {
-             // first <dir>, so just replace it wholesale; we use strdup so we can free() easily later, consistently. Mmm, leak seems imminent.
-             app -> mkdir_sp = strdup ( t );
-           }
-
-           while ( ( pElem = pElem -> NextSiblingElement ( PND_PXML_ENAME_MKDIR ) ) ) {
+       while ( ( pElem = pElem -> NextSiblingElement ( PND_PXML_ENAME_MKDIR ) ) ) {
              
-             if ( ( t = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_MKDIRPATH) ) ) {
-               char *foo = (char*) malloc ( strlen ( app -> mkdir_sp ) + strlen ( t ) + 1 /*:*/ + 1 /*\0*/ );
+         if ( ( t = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_MKDIRPATH) ) ) {
+           char *foo = (char*) malloc ( strlen ( app -> mkdir_sp ) + strlen ( t ) + 1 /*:*/ + 1 /*\0*/ );
 
-               if ( foo ) {
-                 sprintf ( foo, "%s:%s", app -> mkdir_sp, t );
-                 free ( app -> mkdir_sp );
-                 app -> mkdir_sp = foo;
-               } // assuming we got ram, lets cat it all together
+           if ( foo ) {
+             sprintf ( foo, "%s:%s", app -> mkdir_sp, t );
+             free ( app -> mkdir_sp );
+             app -> mkdir_sp = foo;
+           } // assuming we got ram, lets cat it all together
 
-             } // got another elem?
+         } // got another elem?
 
-           } // while
+       } // while
 
-         } // found a <dir>
+      } // found a <dir>
 
 #if 0
-         if ( app -> mkdir_sp ) {
-           printf ( "mkdir: %s\n", app -> mkdir_sp );
-         }
+      if ( app -> mkdir_sp ) {
+       printf ( "mkdir: %s\n", app -> mkdir_sp );
+      }
 #endif
 
-       } // mkdir
+    } // mkdir
 
-       return (1);
+    // if in <application> mode, do we find another app?
+    if ( appwrappermode ) {
+      appElem = appElem -> NextSiblingElement ( PND_PXML_APP );
+      if ( ! appElem ) {
+       pnd_log ( PND_LOG_DEFAULT, (char*)"  No more applications within PXML\n" );
+       break; // no more applications
+      }
+      // got another application..
+      //pnd_log ( PND_LOG_DEFAULT, "  Found another applications within PXML\n" );
+      appwrappermode++;
+      hRoot = TiXmlHandle ( appElem );
+
+      appcount++;
+
+      if ( appcount == PXML_MAXAPPS ) {
+       return ( 1 ); // thats all we can handle; we're not going to auto-extend this
+      }
+
+    } else {
+      break; // single-app old PXML
+    }
+
+  } // while finding apps
+
+  return (1);
 }
 
 } // extern C
index 5009b51..6c521b9 100644 (file)
@@ -173,9 +173,9 @@ void pnd_exec_no_wait_1 ( char *fullpath, char *arg1 ) {
   return;
 }
 
-pnd_pxml_handle pnd_pxml_get_by_path ( char *fullpath ) {
+pnd_pxml_handle *pnd_pxml_get_by_path ( char *fullpath ) {
   unsigned char valid = pnd_object_type_unknown;
-  pnd_pxml_handle pxmlh = 0;
+  pnd_pxml_handle *pxmlapps = 0;
 
   // WARN: this is way too close to callback in pnd_disco .. should be refactored!
 
@@ -192,7 +192,7 @@ pnd_pxml_handle pnd_pxml_get_by_path ( char *fullpath ) {
 
   // potentially a valid application
   if ( valid == pnd_object_type_directory ) {
-    pxmlh = pnd_pxml_fetch ( (char*) fullpath );
+    pxmlapps = pnd_pxml_fetch ( (char*) fullpath );
 
   } else if ( valid == pnd_object_type_pnd ) {
     FILE *f;
@@ -214,7 +214,7 @@ pnd_pxml_handle pnd_pxml_get_by_path ( char *fullpath ) {
     }
 
     // by now, we have <PXML> .. </PXML>, try to parse..
-    pxmlh = pnd_pxml_fetch_buffer ( (char*) fullpath, pxmlbuf );
+    pxmlapps = pnd_pxml_fetch_buffer ( (char*) fullpath, pxmlbuf );
 
     // done with file
     fclose ( f );
@@ -223,7 +223,7 @@ pnd_pxml_handle pnd_pxml_get_by_path ( char *fullpath ) {
 
   // ..
 
-  return ( pxmlh );
+  return ( pxmlapps );
 }
 
 unsigned char pnd_determine_mountpoint ( char *fullpath, char *r_mountpoint, unsigned char mountpoint_len ) {
index 26e3a96..06545ba 100644 (file)
@@ -15,58 +15,66 @@ int main (int argc, char **argv)
                return 1;
        }
 
-       pnd_pxml_handle h = pnd_pxml_fetch(argv[1]);
+       pnd_pxml_handle *apps = pnd_pxml_fetch(argv[1]);
+       pnd_pxml_handle h;
 
-       if (!h)
-       {
-               printf("Could not load file \"%s\"\n", argv[1]);
-               return 1;
-       }
+       while ( *apps ) {
+         h = *apps;
+
+         if (!h)
+         {
+           printf("Could not load file \"%s\"\n", argv[1]);
+           return 1;
+         }
+
+         char *data; //for all values
 
-       char *data; //for all values
+         if ( (data = pnd_pxml_get_app_name_en(h)) ) printf("Appname(en): %s\n", data);
+         if ( (data = pnd_pxml_get_app_name_de(h)) ) printf("Appname(de): %s\n", data);
+         if ( (data = pnd_pxml_get_app_name_it(h)) ) printf("Appname(it): %s\n", data);
+         if ( (data = pnd_pxml_get_app_name_fr(h)) ) printf("Appname(fr): %s\n", data);
 
-       if ( (data = pnd_pxml_get_app_name_en(h)) ) printf("Appname(en): %s\n", data);
-       if ( (data = pnd_pxml_get_app_name_de(h)) ) printf("Appname(de): %s\n", data);
-       if ( (data = pnd_pxml_get_app_name_it(h)) ) printf("Appname(it): %s\n", data);
-       if ( (data = pnd_pxml_get_app_name_fr(h)) ) printf("Appname(fr): %s\n", data);
+         if ( (data = pnd_pxml_get_unique_id(h)) ) printf("UID: %s\n", data);
 
-       if ( (data = pnd_pxml_get_unique_id(h)) ) printf("UID: %s\n", data);
+         if ( (data = pnd_pxml_get_standalone(h)) ) printf("Standalone: %s\n", data);
 
-       if ( (data = pnd_pxml_get_standalone(h)) ) printf("Standalone: %s\n", data);
+         if ( (data = pnd_pxml_get_icon(h)) ) printf("Icon: %s\n", data);
 
-       if ( (data = pnd_pxml_get_icon(h)) ) printf("Icon: %s\n", data);
+         if ( (data = pnd_pxml_get_description_en(h)) ) printf("Description(en): %s\n", data);
+         if ( (data = pnd_pxml_get_description_de(h)) ) printf("Description(de): %s\n", data);
+         if ( (data = pnd_pxml_get_description_it(h)) ) printf("Description(it): %s\n", data);
+         if ( (data = pnd_pxml_get_description_fr(h)) ) printf("Description(fr): %s\n", data);
 
-       if ( (data = pnd_pxml_get_description_en(h)) ) printf("Description(en): %s\n", data);
-       if ( (data = pnd_pxml_get_description_de(h)) ) printf("Description(de): %s\n", data);
-       if ( (data = pnd_pxml_get_description_it(h)) ) printf("Description(it): %s\n", data);
-       if ( (data = pnd_pxml_get_description_fr(h)) ) printf("Description(fr): %s\n", data);
+         if ( (data = pnd_pxml_get_previewpic1(h)) ) printf("Pic1: %s\n", data);
+         if ( (data = pnd_pxml_get_previewpic2(h)) ) printf("Pic2: %s\n", data);
 
-       if ( (data = pnd_pxml_get_previewpic1(h)) ) printf("Pic1: %s\n", data);
-       if ( (data = pnd_pxml_get_previewpic2(h)) ) printf("Pic2: %s\n", data);
+         if ( (data = pnd_pxml_get_author_name(h)) ) printf("Author name: %s\n", data);
+         if ( (data = pnd_pxml_get_author_website(h)) ) printf("Author website: %s\n", data);
 
-       if ( (data = pnd_pxml_get_author_name(h)) ) printf("Author name: %s\n", data);
-       if ( (data = pnd_pxml_get_author_website(h)) ) printf("Author website: %s\n", data);
+         if ( (data = pnd_pxml_get_version_major(h)) ) printf("Version major: %s\n", data);
+         if ( (data = pnd_pxml_get_version_minor(h)) ) printf("Version minor: %s\n", data);
+         if ( (data = pnd_pxml_get_version_release(h)) ) printf("Version release: %s\n", data);
+         if ( (data = pnd_pxml_get_version_build(h)) ) printf("Version build: %s\n", data);
 
-       if ( (data = pnd_pxml_get_version_major(h)) ) printf("Version major: %s\n", data);
-       if ( (data = pnd_pxml_get_version_minor(h)) ) printf("Version minor: %s\n", data);
-       if ( (data = pnd_pxml_get_version_release(h)) ) printf("Version release: %s\n", data);
-       if ( (data = pnd_pxml_get_version_build(h)) ) printf("Version build: %s\n", data);
+         if ( (data = pnd_pxml_get_osversion_major(h)) ) printf("OSVersion major: %s\n", data);
+         if ( (data = pnd_pxml_get_osversion_minor(h)) ) printf("OSVersion minor: %s\n", data);
+         if ( (data = pnd_pxml_get_osversion_release(h)) ) printf("OSVersion release: %s\n", data);
+         if ( (data = pnd_pxml_get_osversion_build(h)) ) printf("OSVersion build: %s\n", data);
 
-       if ( (data = pnd_pxml_get_osversion_major(h)) ) printf("OSVersion major: %s\n", data);
-       if ( (data = pnd_pxml_get_osversion_minor(h)) ) printf("OSVersion minor: %s\n", data);
-       if ( (data = pnd_pxml_get_osversion_release(h)) ) printf("OSVersion release: %s\n", data);
-       if ( (data = pnd_pxml_get_osversion_build(h)) ) printf("OSVersion build: %s\n", data);
+         if ( (data = pnd_pxml_get_exec(h)) ) printf("Application exec: %s\n", data);
 
-       if ( (data = pnd_pxml_get_exec(h)) ) printf("Application exec: %s\n", data);
+         if ( (data = pnd_pxml_get_main_category(h)) ) printf("Category 1: %s\n", data);
+         if ( (data = pnd_pxml_get_subcategory1(h)) ) printf("Category 1 sub 1: %s\n", data);
+         if ( (data = pnd_pxml_get_subcategory2(h)) ) printf("Category 1 sub 2: %s\n", data);
+         if ( (data = pnd_pxml_get_altcategory(h)) ) printf("Category 2: %s\n", data);
+         if ( (data = pnd_pxml_get_altsubcategory1(h)) ) printf("Category 2 sub 1: %s\n", data);
+         if ( (data = pnd_pxml_get_altsubcategory2(h)) ) printf("Category 2 sub 2: %s\n", data);
 
-       if ( (data = pnd_pxml_get_main_category(h)) ) printf("Category 1: %s\n", data);
-       if ( (data = pnd_pxml_get_subcategory1(h)) ) printf("Category 1 sub 1: %s\n", data);
-       if ( (data = pnd_pxml_get_subcategory2(h)) ) printf("Category 1 sub 2: %s\n", data);
-       if ( (data = pnd_pxml_get_altcategory(h)) ) printf("Category 2: %s\n", data);
-       if ( (data = pnd_pxml_get_altsubcategory1(h)) ) printf("Category 2 sub 1: %s\n", data);
-       if ( (data = pnd_pxml_get_altsubcategory2(h)) ) printf("Category 2 sub 2: %s\n", data);
+         pnd_pxml_delete(h);
 
-       pnd_pxml_delete(h);
+         // next
+         apps++;
+       } // while
 
        return 0;
 }
diff --git a/testdata/apps/sampleappX/PXML.xml b/testdata/apps/sampleappX/PXML.xml
new file mode 100644 (file)
index 0000000..29e18fd
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<PXML xmlns="http://openpandora.org/namespaces/PXML" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="PXML_schema.xsd">
+
+  <application id="jeff.sample.X">
+    <title lang="en_US">Sample App X - Fullscreen</title>
+    <exec background="true" startdir="/usr/share/icons/" standalone="true" command="program.exe"/>
+    <description lang="en_US">This is the English Description of the file.</description>
+    <icon src="zeldaicon.png"/>
+  </application>
+
+  <application id="jeff.sample.X">
+    <title lang="en_US">Sample App X - Windowed</title>
+    <exec background="true" startdir="/usr/share/icons/" standalone="true" command="program.exe"/>
+    <description lang="en_US">This is the English Description of the file.</description>
+    <icon src="zeldaicon.png"/>
+  </application>
+
+  <application id="jeff.sample.X2">
+    <title lang="en_US">Sample App X - Other ID</title>
+    <exec background="true" startdir="/usr/share/icons/" standalone="true" command="program.exe"/>
+    <description lang="en_US">This is the English Description of the file.</description>
+    <icon src="zeldaicon.png"/>
+  </application>
+
+</PXML>
diff --git a/testdata/apps/sampleappX/PXML.xml.bak2 b/testdata/apps/sampleappX/PXML.xml.bak2
new file mode 100644 (file)
index 0000000..fa62c13
--- /dev/null
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<PXML xmlns="http://openpandora.org/namespaces/PXML" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="PXML_schema.xsd">
+
+  <application id="jeff.sample.X">
+    <title lang="en_US">Sample App X1</title>
+    <title lang="de_DE">Sample App X1 - German</title>
+
+    <exec background="true" startdir="/usr/share/icons/" standalone="true" command="program.exe"/>
+
+    <description lang="en_US">This is the English Description of the file.</description>
+    <description lang="de_DE">This would be the German description.</description>
+
+    <previewpics>
+      <pic src="./preview/pic1.jpg"/>
+      <pic src="./preview/pic2.jpg"/>
+    </previewpics>
+
+    <author name="EvilDragon" website="http://www.openpandora.org"/><!--Optional email and website, name required-->
+
+    <mkdir>
+      <dir path="common/mydir1"/>
+      <dir path="common/mydir2"/>
+    </mkdir>
+
+    <version major="1" minor="1" release="1" build="2"/><!--This program's version-->
+    <osversion major="1" minor="0" release="0" build="0"/><!--The minimum OS version required-->
+
+    <categories>
+      <category name="MainCategory"><!--category like "Games", "Graphics", "Internet" etc-->
+       <subcategory name="Subcategory1"/><!--subcategory, like "Board Games", "Strategy", "First Person Shooters"-->
+       <subcategory name="Subcategory2"/>
+      </category>
+      <category name="AlternativeCategory">
+       <subcategory name="AlternativeSubcategory1"/>
+      </category>
+    </categories>
+
+    <associations>
+      <!--File associations, with a short description, an extension, and start params.-->
+      <association name="View Word File" filetype="application/msword" exec="-f %s -t doc"/>
+    </associations>
+
+    <clockspeed frequency="600"/><!--Frequency in Hz-->
+
+    <configuration for="gmenupandora">......kfujl........</configuration><!--random data, this is for specific menus-->
+    <configuration for="anothermenu">......qwe......fwer.....</configuration>
+
+  </application>
+
+
+  <application id="jeff.sample.X">
+    <title lang="en_US">Sample App X2</title>
+    <title lang="de_DE">Sample App X2 - German</title>
+
+    <exec background="true" startdir="/usr/share/icons/" standalone="true" command="program.exe"/>
+
+    <description lang="en_US">This is the English Description of the file.</description>
+    <description lang="de_DE">This would be the German description.</description>
+
+    <previewpics>
+      <pic src="./preview/pic1.jpg"/>
+      <pic src="./preview/pic2.jpg"/>
+    </previewpics>
+
+    <author name="EvilDragon" website="http://www.openpandora.org"/><!--Optional email and website, name required-->
+
+    <mkdir>
+      <dir path="common/mydir1"/>
+      <dir path="common/mydir2"/>
+    </mkdir>
+
+    <version major="1" minor="1" release="1" build="2"/><!--This program's version-->
+    <osversion major="1" minor="0" release="0" build="0"/><!--The minimum OS version required-->
+
+    <categories>
+      <category name="MainCategory"><!--category like "Games", "Graphics", "Internet" etc-->
+       <subcategory name="Subcategory1"/><!--subcategory, like "Board Games", "Strategy", "First Person Shooters"-->
+       <subcategory name="Subcategory2"/>
+      </category>
+      <category name="AlternativeCategory">
+       <subcategory name="AlternativeSubcategory1"/>
+      </category>
+    </categories>
+
+    <associations>
+      <!--File associations, with a short description, an extension, and start params.-->
+      <association name="View Word File" filetype="application/msword" exec="-f %s -t doc"/>
+    </associations>
+
+    <clockspeed frequency="600"/><!--Frequency in Hz-->
+
+    <configuration for="gmenupandora">......kfujl........</configuration><!--random data, this is for specific menus-->
+    <configuration for="anothermenu">......qwe......fwer.....</configuration>
+
+  </application>
+
+
+  <application id="jeff.sample.X3">
+    <title lang="en_US">Sample App X3</title>
+    <title lang="de_DE">Sample App X3 - German</title>
+
+    <exec background="true" startdir="/usr/share/icons/" standalone="true" command="program.exe"/>
+
+    <description lang="en_US">This is the English Description of the file.</description>
+    <description lang="de_DE">This would be the German description.</description>
+
+    <previewpics>
+      <pic src="./preview/pic1.jpg"/>
+      <pic src="./preview/pic2.jpg"/>
+    </previewpics>
+
+    <author name="EvilDragon" website="http://www.openpandora.org"/><!--Optional email and website, name required-->
+
+    <mkdir>
+      <dir path="common/mydir1"/>
+      <dir path="common/mydir2"/>
+    </mkdir>
+
+    <version major="1" minor="1" release="1" build="2"/><!--This program's version-->
+    <osversion major="1" minor="0" release="0" build="0"/><!--The minimum OS version required-->
+
+    <categories>
+      <category name="MainCategory"><!--category like "Games", "Graphics", "Internet" etc-->
+       <subcategory name="Subcategory1"/><!--subcategory, like "Board Games", "Strategy", "First Person Shooters"-->
+       <subcategory name="Subcategory2"/>
+      </category>
+      <category name="AlternativeCategory">
+       <subcategory name="AlternativeSubcategory1"/>
+      </category>
+    </categories>
+
+    <associations>
+      <!--File associations, with a short description, an extension, and start params.-->
+      <association name="View Word File" filetype="application/msword" exec="-f %s -t doc"/>
+    </associations>
+
+    <clockspeed frequency="600"/><!--Frequency in Hz-->
+
+    <configuration for="gmenupandora">......kfujl........</configuration><!--random data, this is for specific menus-->
+    <configuration for="anothermenu">......qwe......fwer.....</configuration>
+
+  </application>
+
+
+</PXML>
diff --git a/testdata/apps/sampleappX/program.exe b/testdata/apps/sampleappX/program.exe
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/testdata/apps/sampleappX/zeldaicon.png b/testdata/apps/sampleappX/zeldaicon.png
new file mode 100644 (file)
index 0000000..140a393
Binary files /dev/null and b/testdata/apps/sampleappX/zeldaicon.png differ
index ade9c7f..d54f683 100755 (executable)
@@ -12,38 +12,44 @@ loc=$(dirname "$0")
  
 echo '
 <?xml version="1.0" encoding="UTF-8"?>
-<PXML xmlns="http://openpandora.org/namespaces/PXML" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="'$BASENAME-$rnd'" xsi:noNamespaceSchemaLocation="PXML_schema.xsd">
-  <title lang="en_US">'$BASENAMEnoex'</title>
-  <title lang="de_DE">'$BASENAMEnoex' - German (lol!)</title>
+<PXML xmlns="http://openpandora.org/namespaces/PXML" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="PXML_schema.xsd">
+
+  <application id="'$BASENAME-$rnd'">
+
+    <title lang="en_US">'$BASENAMEnoex'</title>
+    <title lang="de_DE">'$BASENAMEnoex' - German (lol!)</title>
  
-  <exec command="'$BASENAME'"/>
+    <exec command="'$BASENAME'"/>
  
-  <description lang="en_US">en_US Automatically generated pxml from'$(pwd)' exe='$BASENAME'</description>
-  <description lang="de_DE">de_DE Automatisch generiertes pxml aus'$(pwd)' exe='$BASENAME'</description>
+    <description lang="en_US">en_US Automatically generated pxml from'$(pwd)' exe='$BASENAME'</description>
+    <description lang="de_DE">de_DE Automatisch generiertes pxml aus'$(pwd)' exe='$BASENAME'</description>
  
-  <previewpics>'
+    <previewpics>'
 #add all images in the folder as preview pics
 for image in $(file -i -0 * | grep -a image | cut -d" " -f1)
 do
-echo "<pic src="$image"/>"
+echo "      <pic src="$image"/>"
 done
-echo '  </previewpics>
-  <author name="'$USERNAME'" website="http://www.openpandora.org"/><!--Optional email and website, name required-->
-  <version major="1" minor="1" release="1" build="2"/><!--This programs version-->
-  <osversion major="1" minor="0" release="0" build="0"/><!--The minimum OS version required-->
-  <categories>
-    <category name="Main category"><!--category like "Games", "Graphics", "Internet" etc-->
-    <subcategory name="Subcategory 1"/><!--subcategory, like "Board Games", "Strategy", "First Person Shooters"-->
-    <subcategory name="Subcategory 2"/>
-    </category>
-    <category name="Alternative category">
-      <subcategory name="Alternative Subcategory 1"/>
-    </category>
-  </categories>
-  <clockspeed frequency="600"/><!--Frequency in Hz-->
+echo '    </previewpics>
+    <author name="'$USERNAME'" website="http://www.openpandora.org"/><!--Optional email and website, name required-->
+    <version major="1" minor="1" release="1" build="2"/><!--This programs version-->
+    <osversion major="1" minor="0" release="0" build="0"/><!--The minimum OS version required-->
+    <categories>
+      <category name="Main category"><!--category like "Games", "Graphics", "Internet" etc-->
+        <subcategory name="Subcategory 1"/><!--subcategory, like "Board Games", "Strategy", "First Person Shooters"-->
+        <subcategory name="Subcategory 2"/>
+      </category>
+      <category name="Alternative category">
+        <subcategory name="Alternative Subcategory 1"/>
+      </category>
+    </categories>
+    <clockspeed frequency="600"/><!--Frequency in Hz-->
+
+  </application>
+
 </PXML>
 '
\ No newline at end of file