Adapt the remaining plugins to put the greyscale isr on cop. Now they can be used...
[Rockbox.git] / apps / plugins / shortcuts / shortcuts_common.c
blob91e3084e10e3aa108096fb913d961e95e98426a9
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2007 Bryan Childs
11 * Copyright (c) 2007 Alexander Levin
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.
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
19 ****************************************************************************/
21 #include "shortcuts.h"
22 MEM_FUNCTION_WRAPPERS(rb);
24 #define SHORTCUTS_FILENAME "/shortcuts.link"
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) */
33 #define INSTR_DISPLAY_LAST_SEGMENTS "Display last path segments"
35 /* Memory (will be used for entries) */
36 void *memory_buf;
37 long memory_bufsize; /* Size of memory_buf in bytes */
40 /* The file we're processing */
41 sc_file_t sc_file;
43 bool parse_entry_content(char *line, sc_entry_t *entry, int last_segm);
44 char *last_segments(char *path, int nsegm);
45 bool is_control(char *line, sc_file_t *file);
46 bool starts_with(char *string, char *prefix);
47 bool parse_name_value(char *line, char *name, int namesize,
48 char *value, int valuesize);
49 void write_entry_to_file(int fd, sc_entry_t *entry);
50 void write_int_instruction_to_file(int fd, char *instr, int value);
53 void allocate_memory(void **buf, size_t *bufsize)
55 *buf = rb->plugin_get_buffer(bufsize);
56 DEBUGF("Got %ld bytes of memory\n", *bufsize);
60 void init_sc_file(sc_file_t *file, void *buf, size_t bufsize)
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;
70 bool load_sc_file(sc_file_t *file, char *filename, bool must_exist,
71 void *entry_buf, size_t entry_bufsize)
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;
79 /* We start to load a new file -> prepare it */
80 init_sc_file(&sc_file, entry_buf, entry_bufsize);
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;
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;
104 while ((amountread=rb->read_line(fd,sc_content, sizeof(sc_content)))) {
105 if (is_control(sc_content, file)) {
106 continue;
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;
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;
118 DEBUGF("Parsed entry: path=%s, disp=%s\n", entry.path, entry.disp);
119 append_entry(file, &entry);
122 #ifdef SC_DEBUG
123 print_file(file);
124 #endif
126 ret_val = true; /* Everything went ok */
128 end_of_proc:
129 if (fd >= 0) {
130 rb->close(fd);
131 fd = -1;
133 return ret_val;
136 #ifdef SC_DEBUG
137 void print_file(sc_file_t *file)
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);
151 #endif
154 bool append_entry(sc_file_t *file, sc_entry_t *entry)
156 if (file->entry_cnt >= file->max_entries) {
157 return false;
159 rb->memcpy(file->entries+file->entry_cnt, entry, sizeof(*entry));
160 file->entry_cnt++;
161 return true;
165 bool remove_entry(sc_file_t *file, int entry_idx)
167 if ((entry_idx<0) || (entry_idx>=file->entry_cnt)) {
168 return false;
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;
178 bool is_valid_index(sc_file_t *file, int entry_idx)
180 return (entry_idx >= 0) && (entry_idx < file->entry_cnt);
184 bool parse_entry_content(char *line, sc_entry_t *entry, int last_segm)
186 char *sep;
187 char *path, *disp;
188 unsigned int path_len, disp_len;
189 bool expl;
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);
208 disp_len = rb->strlen(disp);
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;
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;
223 char *last_segments(char *path, int nsegm)
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;
235 seg_cnt++;
236 if (seg_cnt == nsegm && p > path) {
237 p++; /* Eat the '/' to show that something has been truncated */
240 return p;
244 bool is_control(char *line, sc_file_t *file)
246 char name[MAX_PATH], value[MAX_PATH];
247 if (!starts_with(line, CONTROL_PREFIX)) {
248 return false;
250 line += CONTROL_PREFIX_LEN;
252 if (!parse_name_value(line, name, sizeof(name),
253 value, sizeof(value))) {
254 DEBUGF("Bad processing instruction: '%s'\n", line);
255 return true;
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);
267 return true;
271 bool starts_with(char *string, char *prefix)
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);
280 bool parse_name_value(char *line, char *name, int namesize,
281 char *value, int valuesize)
283 char *sep;
284 int name_len, val_len;
285 name[0] = value[0] = '\0';
287 sep = rb->strcasestr(line, NAME_VALUE_SEPARATOR);
288 if (sep == NULL) {
289 /* No separator char -> weird instruction */
290 return false;
292 name_len = sep - line;
293 if (name_len >= namesize) {
294 /* Too long name */
295 return false;
297 rb->strncpy(name, line, name_len);
298 name[name_len] = '\0';
300 val_len = rb->strlen(line) - name_len - NAME_VALUE_SEPARATOR_LEN;
301 if (val_len >= valuesize) {
302 /* Too long value */
303 return false;
305 rb->strncpy(value, sep+NAME_VALUE_SEPARATOR_LEN, val_len+1);
306 return true;
310 bool dump_sc_file(sc_file_t *file, char *filename)
312 DEBUGF("Dumping shortcuts to the file '%s'\n", filename);
313 int fd;
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;
327 * Write instructions
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);
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);
341 rb->close(fd);
342 DEBUGF("Dumped %d entries to the file '%s'\n", file->entry_cnt, filename);
344 return true;
348 void write_int_instruction_to_file(int fd, char *instr, int value)
350 rb->fdprintf(fd, "%s%s%s%d\n", CONTROL_PREFIX, instr,
351 NAME_VALUE_SEPARATOR, value);
355 void write_entry_to_file(int fd, sc_entry_t *entry)
357 rb->fdprintf(fd, "%s", entry->path);
358 if (entry->explicit_disp) {
359 rb->fdprintf(fd, "%s%s", PATH_DISP_SEPARATOR, entry->disp);
361 rb->fdprintf(fd, "\n");