summaryrefslogtreecommitdiff
path: root/apps/plugins/shortcuts/shortcuts_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/shortcuts/shortcuts_common.c')
-rw-r--r--apps/plugins/shortcuts/shortcuts_common.c394
1 files changed, 394 insertions, 0 deletions
diff --git a/apps/plugins/shortcuts/shortcuts_common.c b/apps/plugins/shortcuts/shortcuts_common.c
new file mode 100644
index 0000000000..4a097f0a0d
--- /dev/null
+++ b/apps/plugins/shortcuts/shortcuts_common.c
@@ -0,0 +1,394 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 Bryan Childs
11 * Copyright (c) 2007 Alexander Levin
12 *
13 * All files in this archive are subject to the GNU General Public License.
14 * See the file COPYING in the source tree root for full license agreement.
15 *
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
18 *
19 ****************************************************************************/
20
21#include "shortcuts.h"
22MEM_FUNCTION_WRAPPERS(rb);
23
24#define SHORTCUTS_FILENAME "/shortcuts.link"
25
26#define PATH_DISP_SEPARATOR "\t"
27#define PATH_DISP_SEPARATOR_LEN 1 /* strlen(PATH_DISP_SEPARATOR) */
28#define CONTROL_PREFIX "#"
29#define CONTROL_PREFIX_LEN 1 /* strlen(CONTROL_PREFIX) */
30#define NAME_VALUE_SEPARATOR "="
31#define NAME_VALUE_SEPARATOR_LEN 1 /* strlen(NAME_VALUE_SEPARATOR) */
32
33#define INSTR_DISPLAY_LAST_SEGMENTS "Display last path segments"
34
35/* Memory (will be used for entries) */
36void *memory_buf;
37long memory_bufsize; /* Size of memory_buf in bytes */
38
39
40/* The file we're processing */
41sc_file_t sc_file;
42
43bool parse_entry_content(char *line, sc_entry_t *entry, int last_segm);
44char *last_segments(char *path, int nsegm);
45bool is_control(char *line, sc_file_t *file);
46bool starts_with(char *string, char *prefix);
47bool parse_name_value(char *line, char *name, int namesize,
48 char *value, int valuesize);
49void write_entry_to_file(int fd, sc_entry_t *entry);
50void write_int_instruction_to_file(int fd, char *instr, int value);
51
52
53void allocate_memory(void **buf, size_t *bufsize)
54{
55 *buf = rb->plugin_get_buffer(bufsize);
56 DEBUGF("Got %ld bytes of memory\n", *bufsize);
57}
58
59
60void init_sc_file(sc_file_t *file, void *buf, size_t bufsize)
61{
62 file->entries = (sc_entry_t*)buf;
63 file->max_entries = bufsize / sizeof(sc_entry_t);
64 DEBUGF("Buffer capacity: %d entries\n", file->max_entries);
65 file->entry_cnt = 0;
66 file->show_last_segments = -1;
67}
68
69
70bool load_sc_file(sc_file_t *file, char *filename, bool must_exist,
71 void *entry_buf, size_t entry_bufsize)
72{
73 int fd = -1;
74 bool ret_val = false; /* Assume bad case */
75 int amountread = 0;
76 char sc_content[2*MAX_PATH];
77 sc_entry_t entry;
78
79 /* We start to load a new file -> prepare it */
80 init_sc_file(&sc_file, entry_buf, entry_bufsize);
81
82 fd = rb->open(filename, O_RDONLY);
83 if (fd < 0) {
84 /* The file didn't exist on disk */
85 if (!must_exist) {
86 DEBUGF("Trying to create link file '%s'...\n", filename);
87 fd = rb->creat(filename);
88 if (fd < 0){
89 /* For some reason we couldn't create the file,
90 * so return an error message and exit */
91 rb->splash(HZ*2, "Couldn't create the shortcuts file %s",
92 filename);
93 goto end_of_proc;
94 }
95 /* File created, but there's nothing in it, so just exit */
96 ret_val = true;
97 goto end_of_proc;
98 } else {
99 rb->splash(HZ, "Couldn't open %s", filename);
100 goto end_of_proc;
101 }
102 }
103
104 while ((amountread=rb->read_line(fd,sc_content, sizeof(sc_content)))) {
105 if (is_control(sc_content, file)) {
106 continue;
107 }
108 if (file->entry_cnt >= file->max_entries) {
109 rb->splash(HZ*2, "Too many entries in the file, max allowed: %d",
110 file->max_entries);
111 goto end_of_proc;
112 }
113 if (!parse_entry_content(sc_content, &entry,file->show_last_segments)) {
114 /* Could not parse the entry (too long path?) -> ignore */
115 DEBUGF("Could not parse '%s' -> ignored\n", sc_content);
116 continue;
117 }
118 DEBUGF("Parsed entry: path=%s, disp=%s\n", entry.path, entry.disp);
119 append_entry(file, &entry);
120 }
121
122#ifdef SC_DEBUG
123 print_file(file);
124#endif
125
126 ret_val = true; /* Everything went ok */
127
128end_of_proc:
129 if (fd >= 0) {
130 rb->close(fd);
131 fd = -1;
132 }
133 return ret_val;
134}
135
136#ifdef SC_DEBUG
137void print_file(sc_file_t *file)
138{
139 DEBUGF("Number of entries : %d\n", file->entry_cnt);
140 DEBUGF("Show Last Segments: %d\n", file->show_last_segments);
141 int i;
142 sc_entry_t *entry;
143 for (i=0, entry=file->entries; i<file->entry_cnt; i++,entry++) {
144 if (entry->explicit_disp) {
145 DEBUGF("%2d. '%s', show as '%s'\n", i+1, entry->path, entry->disp);
146 } else {
147 DEBUGF("%2d. '%s' (%s)\n", i+1, entry->path, entry->disp);
148 }
149 }
150}
151#endif
152
153
154bool append_entry(sc_file_t *file, sc_entry_t *entry)
155{
156 if (file->entry_cnt >= file->max_entries) {
157 return false;
158 }
159 rb->memcpy(file->entries+file->entry_cnt, entry, sizeof(*entry));
160 file->entry_cnt++;
161 return true;
162}
163
164
165bool remove_entry(sc_file_t *file, int entry_idx)
166{
167 if ((entry_idx<0) || (entry_idx>=file->entry_cnt)) {
168 return false;
169 }
170 sc_entry_t *start = file->entries + entry_idx;
171 rb->memmove(start, start + 1,
172 (file->entry_cnt-entry_idx-1) * sizeof(sc_entry_t));
173 file->entry_cnt--;
174 return true;
175}
176
177
178bool is_valid_index(sc_file_t *file, int entry_idx)
179{
180 return (entry_idx >= 0) && (entry_idx < file->entry_cnt);
181}
182
183
184bool parse_entry_content(char *line, sc_entry_t *entry, int last_segm)
185{
186 char *sep;
187 char *path, *disp;
188 unsigned int path_len, disp_len;
189 bool expl;
190
191 sep = rb->strcasestr(line, PATH_DISP_SEPARATOR);
192 expl = (sep != NULL);
193 if (expl) {
194 /* Explicit name for the entry is specified -> use it */
195 path = line;
196 path_len = sep - line;
197 disp = sep + PATH_DISP_SEPARATOR_LEN;
198 disp_len = rb->strlen(disp);
199 } else {
200 /* No special name to display */
201 path = line;
202 path_len = rb->strlen(line);
203 if (last_segm <= 0) {
204 disp = path;
205 } else {
206 disp = last_segments(line, last_segm);
207 }
208 disp_len = rb->strlen(disp);
209 }
210
211 if (path_len >= sizeof(entry->path) || disp_len >= sizeof(entry->disp)) {
212 DEBUGF("Bad entry: pathlen=%d, displen=%d\n", path_len, disp_len);
213 return false;
214 }
215 rb->strncpy(entry->path, path, path_len);
216 entry->path[path_len] = '\0';
217 rb->strcpy(entry->disp, disp); /* Safe since we've checked the length */
218 entry->explicit_disp = expl;
219 return true;
220}
221
222
223char *last_segments(char *path, int nsegm)
224{
225 char *p = rb->strrchr(path, PATH_SEPARATOR[0]); /* Hack */
226 int seg_cnt;
227 if (p == NULL)
228 return path; /* No separator??? */
229 seg_cnt = 0;
230 while ((p > path) && (seg_cnt < nsegm)) {
231 p--;
232 if (!starts_with(p, PATH_SEPARATOR)) {
233 continue;
234 }
235 seg_cnt++;
236 if (seg_cnt == nsegm && p > path) {
237 p++; /* Eat the '/' to show that something has been truncated */
238 }
239 }
240 return p;
241}
242
243
244bool is_control(char *line, sc_file_t *file)
245{
246 char name[MAX_PATH], value[MAX_PATH];
247 if (!starts_with(line, CONTROL_PREFIX)) {
248 return false;
249 }
250 line += CONTROL_PREFIX_LEN;
251
252 if (!parse_name_value(line, name, sizeof(name),
253 value, sizeof(value))) {
254 DEBUGF("Bad processing instruction: '%s'\n", line);
255 return true;
256 }
257
258 /* Process control instruction */
259 if (rb->strcasestr(name, INSTR_DISPLAY_LAST_SEGMENTS)) {
260 file->show_last_segments = rb->atoi(value);
261 DEBUGF("Set show last segms to %d\n", file->show_last_segments);
262 } else {
263 /* Unknown instruction -> ignore */
264 DEBUGF("Unknown processing instruction: '%s'\n", name);
265 }
266
267 return true;
268}
269
270
271bool starts_with(char *string, char *prefix)
272{
273 unsigned int pfx_len = rb->strlen(prefix);
274 if (rb->strlen(string) < pfx_len)
275 return false;
276 return (rb->strncmp(string, prefix, pfx_len) == 0);
277}
278
279
280bool parse_name_value(char *line, char *name, int namesize,
281 char *value, int valuesize)
282{
283 char *sep;
284 int name_len, val_len;
285 name[0] = value[0] = '\0';
286
287 sep = rb->strcasestr(line, NAME_VALUE_SEPARATOR);
288 if (sep == NULL) {
289 /* No separator char -> weird instruction */
290 return false;
291 }
292 name_len = sep - line;
293 if (name_len >= namesize) {
294 /* Too long name */
295 return false;
296 }
297 rb->strncpy(name, line, name_len);
298 name[name_len] = '\0';
299
300 val_len = rb->strlen(line) - name_len - NAME_VALUE_SEPARATOR_LEN;
301 if (val_len >= valuesize) {
302 /* Too long value */
303 return false;
304 }
305 rb->strncpy(value, sep+NAME_VALUE_SEPARATOR_LEN, val_len+1);
306 return true;
307}
308
309
310bool dump_sc_file(sc_file_t *file, char *filename)
311{
312 DEBUGF("Dumping shortcuts to the file '%s'\n", filename);
313 int fd;
314
315 /* ideally, we should just write a new
316 * entry to the file, but I'm going to
317 * be lazy, and just re-write the whole
318 * thing. */
319 fd = rb->open(filename, O_WRONLY|O_TRUNC);
320 if (fd < 0) {
321 rb->splash(HZ*2, "Could not open shortcuts file %s for writing",
322 filename);
323 return false;
324 }
325
326 /*
327 * Write instructions
328 */
329 /* Always dump the 'display last segms' settings (even it it's
330 * not active) so that it can be easily changed without having
331 * to remember the setting name */
332 write_int_instruction_to_file(fd,
333 INSTR_DISPLAY_LAST_SEGMENTS, file->show_last_segments);
334
335 int i;
336 sc_entry_t *entry;
337 for (i=0, entry=file->entries; i<file->entry_cnt; i++,entry++) {
338 write_entry_to_file(fd, entry);
339 }
340
341 rb->close(fd);
342 DEBUGF("Dumped %d entries to the file '%s'\n", file->entry_cnt, filename);
343
344 return true;
345}
346
347
348void write_int_instruction_to_file(int fd, char *instr, int value)
349{
350 rb->fdprintf(fd, "%s%s%s%d\n", CONTROL_PREFIX, instr,
351 NAME_VALUE_SEPARATOR, value);
352}
353
354
355void write_entry_to_file(int fd, sc_entry_t *entry)
356{
357 rb->fdprintf(fd, "%s", entry->path);
358 if (entry->explicit_disp) {
359 rb->fdprintf(fd, "%s%s", PATH_DISP_SEPARATOR, entry->disp);
360 }
361 rb->fdprintf(fd, "\n");
362}
363
364
365bool file_exists(char *filename)
366{
367 int fd = rb->open(filename, O_RDONLY);
368 bool retval;
369 if (fd >= 0) {
370 rb->close(fd);
371 retval = true;
372 } else {
373 retval = false;
374 }
375 DEBUGF("Checked existence of the file '%s': %s\n",
376 filename, (retval ? "found" : "NOT FOUND"));
377 return retval;
378}
379
380
381bool dir_exists(char *path)
382{
383 DIR* d = rb->opendir(path);
384 bool retval;
385 if (d != NULL) {
386 rb->closedir(d);
387 retval = true;
388 } else {
389 retval = false;
390 }
391 DEBUGF("Checked existence of the dir '%s': %s\n",
392 path, (retval ? "found" : "NOT FOUND"));
393 return retval;
394}