More significant mmenu changes, couple minor fixes/additions to libpnd proper
[pandora-libraries.git] / minimenu / mmcat.c
1
2 #include <string.h>
3 #include <strings.h>
4 #include <stdlib.h>
5
6 #include "pnd_conf.h"
7 #include "pnd_logger.h"
8 #include "pnd_pxml.h"
9 #include "pnd_container.h"
10 #include "pnd_discovery.h"
11 #include "../lib/pnd_pathiter.h"
12
13 #include "mmenu.h"
14 #include "mmcache.h"
15 #include "mmcat.h"
16
17 mm_category_t g_categories [ MAX_CATS ];
18 unsigned char g_categorycount = 0;
19
20 mm_catmap_t g_catmaps [ MAX_CATS ];
21 unsigned char g_catmapcount = 0;
22
23 extern pnd_conf_handle g_conf;
24
25 unsigned char category_push ( char *catname, pnd_disco_t *app, pnd_conf_handle ovrh ) {
26   mm_category_t *c;
27
28   // check category list; if found, append app to the end of it.
29   // if not found, add it to the category list and plop the app in there.
30   // app's are just app-refs, which contain links to the disco-t list -- thus removal is only in one place, and
31   // an app can be in multiple categories if we like..
32   //
33
34   // find or create category
35   //
36
37   if ( ( c = category_query ( catname ) ) ) {
38     // category was found..
39   } else {
40     // category wasn't found..
41     pnd_log ( PND_LOG_DEFAULT, "New category '%s'\n", catname );
42     g_categories [ g_categorycount ].catname = strdup ( catname );
43     g_categories [ g_categorycount ].refs = NULL;
44     c = &(g_categories [ g_categorycount ]);
45     g_categorycount++;
46   }
47
48   if ( ! app ) {
49     return ( 1 ); // create cat, but skip app
50   }
51
52   // alloc and populate appref
53   //
54   mm_appref_t *ar = malloc ( sizeof(mm_appref_t) );
55   if ( ! ar ) {
56     return ( 0 );
57   }
58
59   bzero ( ar, sizeof(mm_appref_t) );
60
61   ar -> ref = app;
62   ar -> ovrh = ovrh;
63
64   // plug it into category
65   //   and sort it on insert!
66 #if 0 // no sorting
67   ar -> next = c -> refs;
68   c -> refs = ar;
69 #else // with sorting
70   // if no refs at all, or new guy has no title, just stick it in at head
71   if ( c -> refs && ar -> ref -> title_en ) {
72     mm_appref_t *iter = c -> refs;
73     mm_appref_t *last = NULL;
74
75     while ( iter ) {
76
77       if ( iter -> ref -> title_en ) {
78         if ( strcmp ( ar -> ref -> title_en, iter -> ref -> title_en ) < 0 ) {
79           // new guy is smaller than the current guy!
80           break;
81         }
82       } else {
83         // since new guy must have a name by here, we're bigger than any guy who does not have a name
84         // --> continue
85       }
86
87       last = iter;
88       iter = iter -> next;
89     }
90
91     if ( iter ) {
92       // smaller than the current guy, so stitch in
93       if ( last ) {
94         ar -> next = iter;
95         last -> next = ar;
96       } else {
97         ar -> next = c -> refs;
98         c -> refs = ar;
99       }
100     } else {
101       // we're the biggest, just append to last
102       last -> next = ar;
103     }
104
105   } else {
106     ar -> next = c -> refs;
107     c -> refs = ar;
108   }
109 #endif
110   c -> refcount++;
111
112   return ( 1 );
113 }
114
115 mm_category_t *category_query ( char *catname ) {
116   unsigned char i;
117
118   for ( i = 0; i < g_categorycount; i++ ) {
119
120     if ( strcasecmp ( g_categories [ i ].catname, catname ) == 0 ) {
121       return ( &(g_categories [ i ]) );
122     }
123
124   }
125
126   return ( NULL );
127 }
128
129 void category_dump ( void ) {
130   unsigned int i;
131
132   // WHY AREN'T I SORTING ON INSERT?
133
134   // dump
135   for ( i = 0; i < g_categorycount; i++ ) {
136     pnd_log ( PND_LOG_DEFAULT, "Category %u: '%s' * %u\n", i, g_categories [ i ].catname, g_categories [ i ].refcount );
137     mm_appref_t *ar = g_categories [ i ].refs;
138
139     while ( ar ) {
140       pnd_log ( PND_LOG_DEFAULT, "  Appref %s\n", IFNULL(ar -> ref -> title_en,"No Name") );
141       ar = ar -> next;
142     }
143
144   } // for
145
146   return;
147 }
148
149 void category_freeall ( void ) {
150   unsigned int i;
151   mm_appref_t *iter, *next;
152
153   for ( i = 0; i < g_categorycount; i++ ) {
154
155     iter = g_categories [ i ].refs;
156
157     while ( iter ) {
158       next = iter -> next;
159       free ( iter );
160       iter = next;
161     }
162
163     g_categories [ i ].refs = NULL;
164
165   } // for
166
167   g_categorycount = 0;
168
169   return;
170 }
171
172 unsigned char category_map_setup ( void ) {
173
174   char *searchpath = pnd_box_get_head ( g_conf );
175
176   if ( ! searchpath ) {
177     return ( 0 );
178   }
179
180   // look through conf for useful keys
181   while ( searchpath ) {
182     char *k = pnd_box_get_key ( searchpath );
183
184     // does this key look like a category mapping key?
185     if ( strncasecmp ( k, "categories.@", 12 ) == 0 ) {
186       k += 12;
187
188       // iterate across 'words' in v, assigning catmaps to them
189       SEARCHCHUNK_PRE
190       {
191         //pnd_log ( pndn_debug, "target(%s) from(%s)\n", k, buffer );
192
193         category_push ( k, NULL, 0 );
194         g_catmaps [ g_catmapcount ].target = category_query ( k );
195         g_catmaps [ g_catmapcount ].from = strdup ( buffer );
196         g_catmapcount++;
197
198       }
199       SEARCHCHUNK_POST
200
201     } // if key looks like catmap
202
203     searchpath = pnd_box_get_next ( searchpath );
204   } // while each conf key
205
206   return ( 1 );
207 }
208
209 mm_category_t *category_map_query ( char *cat ) {
210   unsigned char i;
211
212   for ( i = 0; i < g_catmapcount; i++ ) {
213     if ( strcasecmp ( g_catmaps [ i ].from, cat ) == 0 ) {
214       return ( g_catmaps [ i ].target );
215     }
216   }
217
218   return ( NULL );
219 }
220
221 unsigned char category_meta_push ( char *catname, pnd_disco_t *app, pnd_conf_handle ovrh ) {
222   mm_category_t *cat;
223
224   // do we honour cat mapping at all?
225   if ( pnd_conf_get_as_int_d ( g_conf, "categories.map_on", 0 ) ) {
226
227     // is this guy mapped?
228     cat = category_map_query ( catname );
229
230     if ( cat ) {
231       return ( category_push ( cat -> catname, app, ovrh ) );
232     }
233
234     // not mapped.. but default?
235     if ( pnd_conf_get_as_int_d ( g_conf, "categories.map_default_on", 0 ) ) {
236       char *def = pnd_conf_get_as_char ( g_conf, "categories.map_default_cat" );
237       if ( def ) {
238         return ( category_push ( def, app, ovrh ) );
239       }
240     }
241
242   } // cat map is desired?
243
244   // not default, just do it
245   return ( category_push ( catname, app, ovrh ) );
246 }