2 #include <stdio.h> /* for FILE etc */
3 #include <stdlib.h> /* for malloc */
4 #include <string.h> /* for making ftw.h happy */
6 #define _XOPEN_SOURCE 500
7 #define __USE_XOPEN_EXTENDED
8 #include <ftw.h> /* for nftw, tree walker */
10 #include "pnd_container.h"
12 #include "pnd_discovery.h"
13 #include "pnd_pathiter.h"
15 #include "pnd_pndfiles.h"
17 // need these 'globals' due to the way nftw and ftw work :/
18 static pnd_box_handle disco_box;
19 static char *disco_overrides = NULL;
21 void pnd_disco_destroy ( pnd_disco_t *p ) {
23 if ( p -> title_en ) {
24 free ( p -> title_en );
35 if ( p -> unique_id ) {
36 free ( p -> unique_id );
39 if ( p -> main_category ) {
40 free ( p -> main_category );
43 if ( p -> clockspeed ) {
44 free ( p -> clockspeed );
50 static int pnd_disco_callback ( const char *fpath, const struct stat *sb,
51 int typeflag, struct FTW *ftwbuf )
53 unsigned char valid = 0; // 1 for plaintext PXML, 2 for PND...
55 // PXML.xml is a possible application candidate (and not a dir named PXML.xml :)
56 if ( typeflag & FTW_D ) {
57 return ( 0 ); // skip directories and other non-regular files
60 // PND/PNZ file and others may be valid as well .. but lets leave that for now
61 if ( strcasecmp ( fpath + ftwbuf -> base, PXML_FILENAME ) == 0 ) {
63 } else if ( strcasecmp ( fpath + ftwbuf -> base, PND_PACKAGE_FILEEXT "\0" ) == 0 ) {
67 // if not a file of interest, just keep looking until we run out
72 // potentially a valid application
74 // Plaintext PXML file
75 //printf ( "disco callback encountered '%s'\n", fpath );
77 pnd_pxml_handle pxmlh;
79 // pick up the PXML if we can
81 pxmlh = pnd_pxml_fetch ( (char*) fpath );
84 return ( 0 ); // continue the scan
87 // look for any overrides, if requested
88 pnd_pxml_merge_override ( pxmlh, disco_overrides );
90 // check for validity and add to resultset if it looks executable
91 if ( pnd_is_pxml_valid_app ( pxmlh ) ) {
94 p = pnd_box_allocinsert ( disco_box, (char*) fpath, sizeof(pnd_disco_t) );
95 p -> title_en = strdup ( pnd_pxml_get_app_name ( pxmlh ) );
96 p -> icon = strdup ( pnd_pxml_get_icon_path ( pxmlh ) );
97 p -> exec = strdup ( pnd_pxml_get_exec_path ( pxmlh ) );
98 p -> unique_id = strdup ( pnd_pxml_get_unique_id ( pxmlh ) );
99 p -> main_category = strdup ( pnd_pxml_get_primary_category ( pxmlh ) );
100 p -> clockspeed = strdup ( pnd_pxml_get_clockspeed ( pxmlh ) );
105 pnd_pxml_delete ( pxmlh );
107 } else if ( valid == 2 ) {
109 printf ( "PND: disco callback encountered '%s'\n", fpath );
111 // is this a valid .pnd file? The filename is a candidate already, but verify..
112 // .. presence of PXML appeneded, or at least contained within?
113 // .. presence of an icon appended after PXML?
117 return ( 0 ); // continue the tree walk
120 pnd_box_handle pnd_disco_search ( char *searchpath, char *overridespath ) {
122 //printf ( "Searchpath to discover: '%s'\n", searchpath );
124 // alloc a container for the result set
125 disco_box = pnd_box_new ( "discovery" );
126 disco_overrides = overridespath;
128 /* iterate across the paths within the searchpath, attempting to locate applications
134 // invoke the dir walking function; thankfully Linux includes a pretty good one
135 nftw ( buffer, // path to descend
136 pnd_disco_callback, // callback to do processing
137 10, // no more than X open fd's at once
138 FTW_PHYS ); // do not follow symlinks
143 // return whatever we found, or NULL if nada
144 if ( ! pnd_box_get_head ( disco_box ) ) {
145 pnd_box_delete ( disco_box );
149 return ( disco_box );
152 unsigned char pnd_emit_dotdesktop ( char *targetpath, pnd_disco_t *p ) {
153 char filename [ FILENAME_MAX ];
154 char buffer [ 1024 ];
158 // http://standards.freedesktop.org/desktop-entry-spec
162 if ( ! p -> unique_id ) {
172 sprintf ( filename, "%s/%s.desktop", targetpath, p -> unique_id );
176 //printf ( "EMIT DOTDESKTOP '%s'\n", filename );
178 f = fopen ( filename, "w" );
184 if ( p -> title_en ) {
185 snprintf ( buffer, 1020, "Name=%s\n", p -> title_en );
186 fprintf ( f, "%s", buffer );
189 fprintf ( f, "Type=Application\n" );
190 fprintf ( f, "Version=1.0\n" );
193 snprintf ( buffer, 1020, "Icon=%s\n", p -> icon );
194 fprintf ( f, "%s", buffer );
198 if ( p -> description_en ) {
199 snprintf ( buffer, 1020, "Comment=%s\n", p -> description_en );
200 fprintf ( f, "%s", buffer );
205 if ( p -> startdir ) {
206 snprintf ( buffer, 1020, "Path=%s\n", p -> startdir );
207 fprintf ( f, "%s", buffer );
209 fprintf ( f, "Path=%s\n", PND_DEFAULT_WORKDIR );
214 snprintf ( buffer, 1020, "Exec=%s\n", p -> exec );
215 fprintf ( f, "%s", buffer );
218 fprintf ( f, "_Source=libpnd\n" ); // should we need to know 'who' created the file during trimming