Don't objcopy simulator plugins.
[kugel-rb.git] / apps / plugins / shortcuts / shortcuts_common.c
blob0ea18c06a23f6d0dca6c6251e42bc0b565fb4696
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 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
23 #include "shortcuts.h"
24 MEM_FUNCTION_WRAPPERS(rb);
26 #define SHORTCUTS_FILENAME "/shortcuts.link"
28 #define PATH_DISP_SEPARATOR "\t"
29 #define PATH_DISP_SEPARATOR_LEN 1 /* strlen(PATH_DISP_SEPARATOR) */
30 #define CONTROL_PREFIX "#"
31 #define CONTROL_PREFIX_LEN 1 /* strlen(CONTROL_PREFIX) */
32 #define NAME_VALUE_SEPARATOR "="
33 #define NAME_VALUE_SEPARATOR_LEN 1 /* strlen(NAME_VALUE_SEPARATOR) */
35 #define INSTR_DISPLAY_LAST_SEGMENTS "Display last path segments"
37 /* Memory (will be used for entries) */
38 void *memory_buf;
39 long memory_bufsize; /* Size of memory_buf in bytes */
42 /* The file we're processing */
43 sc_file_t sc_file;
45 bool parse_entry_content(char *line, sc_entry_t *entry, int last_segm);
46 char *last_segments(char *path, int nsegm);
47 bool is_control(char *line, sc_file_t *file);
48 bool starts_with(char *string, char *prefix);
49 bool parse_name_value(char *line, char *name, int namesize,
50 char *value, int valuesize);
51 void write_entry_to_file(int fd, sc_entry_t *entry);
52 void write_int_instruction_to_file(int fd, char *instr, int value);
55 void allocate_memory(void **buf, size_t *bufsize)
57 *buf = rb->plugin_get_buffer(bufsize);
58 DEBUGF("Got %ld bytes of memory\n", *bufsize);
62 void init_sc_file(sc_file_t *file, void *buf, size_t bufsize)
64 file->entries = (sc_entry_t*)buf;
65 file->max_entries = bufsize / sizeof(sc_entry_t);
66 DEBUGF("Buffer capacity: %d entries\n", file->max_entries);
67 file->entry_cnt = 0;
68 file->show_last_segments = -1;
72 bool load_sc_file(sc_file_t *file, char *filename, bool must_exist,
73 void *entry_buf, size_t entry_bufsize)
75 int fd = -1;
76 bool ret_val = false; /* Assume bad case */
77 int amountread = 0;
78 char sc_content[2*MAX_PATH];
79 sc_entry_t entry;
81 /* We start to load a new file -> prepare it */
82 init_sc_file(&sc_file, entry_buf, entry_bufsize);
84 fd = rb->open(filename, O_RDONLY);
85 if (fd < 0) {
86 /* The file didn't exist on disk */
87 if (!must_exist) {
88 DEBUGF("Trying to create link file '%s'...\n", filename);
89 fd = rb->creat(filename);
90 if (fd < 0){
91 /* For some reason we couldn't create the file,
92 * so return an error message and exit */
93 rb->splashf(HZ*2, "Couldn't create the shortcuts file %s",
94 filename);
95 goto end_of_proc;
97 /* File created, but there's nothing in it, so just exit */
98 ret_val = true;
99 goto end_of_proc;
100 } else {
101 rb->splashf(HZ, "Couldn't open %s", filename);
102 goto end_of_proc;
106 while ((amountread=rb->read_line(fd,sc_content, sizeof(sc_content)))) {
107 if (is_control(sc_content, file)) {
108 continue;
110 if (file->entry_cnt >= file->max_entries) {
111 rb->splashf(HZ*2, "Too many entries in the file, max allowed: %d",
112 file->max_entries);
113 goto end_of_proc;
115 if (!parse_entry_content(sc_content, &entry,file->show_last_segments)) {
116 /* Could not parse the entry (too long path?) -> ignore */
117 DEBUGF("Could not parse '%s' -> ignored\n", sc_content);
118 continue;
120 DEBUGF("Parsed entry: path=%s, disp=%s\n", entry.path, entry.disp);
121 append_entry(file, &entry);
124 #ifdef SC_DEBUG
125 print_file(file);
126 #endif
128 ret_val = true; /* Everything went ok */
130 end_of_proc:
131 if (fd >= 0) {
132 rb->close(fd);
133 fd = -1;
135 return ret_val;
138 #ifdef SC_DEBUG
139 void print_file(sc_file_t *file)
141 DEBUGF("Number of entries : %d\n", file->entry_cnt);
142 DEBUGF("Show Last Segments: %d\n", file->show_last_segments);
143 int i;
144 sc_entry_t *entry;
145 for (i=0, entry=file->entries; i<file->entry_cnt; i++,entry++) {
146 if (entry->explicit_disp) {
147 DEBUGF("%2d. '%s', show as '%s'\n", i+1, entry->path, entry->disp);
148 } else {
149 DEBUGF("%2d. '%s' (%s)\n", i+1, entry->path, entry->disp);
153 #endif
156 bool append_entry(sc_file_t *file, sc_entry_t *entry)
158 if (file->entry_cnt >= file->max_entries) {
159 return false;
161 rb->memcpy(file->entries+file->entry_cnt, entry, sizeof(*entry));
162 file->entry_cnt++;
163 return true;
167 bool remove_entry(sc_file_t *file, int entry_idx)
169 if ((entry_idx<0) || (entry_idx>=file->entry_cnt)) {
170 return false;
172 sc_entry_t *start = file->entries + entry_idx;
173 rb->memmove(start, start + 1,
174 (file->entry_cnt-entry_idx-1) * sizeof(sc_entry_t));
175 file->entry_cnt--;
176 return true;
180 bool is_valid_index(sc_file_t *file, int entry_idx)
182 return (entry_idx >= 0) && (entry_idx < file->entry_cnt);
186 bool parse_entry_content(char *line, sc_entry_t *entry, int last_segm)
188 char *sep;
189 char *path, *disp;
190 unsigned int path_len, disp_len;
191 bool expl;
193 sep = rb->strcasestr(line, PATH_DISP_SEPARATOR);
194 expl = (sep != NULL);
195 if (expl) {
196 /* Explicit name for the entry is specified -> use it */
197 path = line;
198 path_len = sep - line;
199 disp = sep + PATH_DISP_SEPARATOR_LEN;
200 disp_len = rb->strlen(disp);
201 } else {
202 /* No special name to display */
203 path = line;
204 path_len = rb->strlen(line);
205 if (last_segm <= 0) {
206 disp = path;
207 } else {
208 disp = last_segments(line, last_segm);
210 disp_len = rb->strlen(disp);
213 if (path_len >= sizeof(entry->path) || disp_len >= sizeof(entry->disp)) {
214 DEBUGF("Bad entry: pathlen=%d, displen=%d\n", path_len, disp_len);
215 return false;
217 rb->strncpy(entry->path, path, path_len);
218 entry->path[path_len] = '\0';
219 rb->strcpy(entry->disp, disp); /* Safe since we've checked the length */
220 entry->explicit_disp = expl;
221 return true;
225 char *last_segments(char *path, int nsegm)
227 char *p = rb->strrchr(path, PATH_SEPARATOR[0]); /* Hack */
228 int seg_cnt;
229 if (p == NULL)
230 return path; /* No separator??? */
231 seg_cnt = 0;
232 while ((p > path) && (seg_cnt < nsegm)) {
233 p--;
234 if (!starts_with(p, PATH_SEPARATOR)) {
235 continue;
237 seg_cnt++;
238 if (seg_cnt == nsegm && p > path) {
239 p++; /* Eat the '/' to show that something has been truncated */
242 return p;
246 bool is_control(char *line, sc_file_t *file)
248 char name[MAX_PATH], value[MAX_PATH];
249 if (!starts_with(line, CONTROL_PREFIX)) {
250 return false;
252 line += CONTROL_PREFIX_LEN;
254 if (!parse_name_value(line, name, sizeof(name),
255 value, sizeof(value))) {
256 DEBUGF("Bad processing instruction: '%s'\n", line);
257 return true;
260 /* Process control instruction */
261 if (rb->strcasestr(name, INSTR_DISPLAY_LAST_SEGMENTS)) {
262 file->show_last_segments = rb->atoi(value);
263 DEBUGF("Set show last segms to %d\n", file->show_last_segments);
264 } else {
265 /* Unknown instruction -> ignore */
266 DEBUGF("Unknown processing instruction: '%s'\n", name);
269 return true;
273 bool starts_with(char *string, char *prefix)
275 unsigned int pfx_len = rb->strlen(prefix);
276 if (rb->strlen(string) < pfx_len)
277 return false;
278 return (rb->strncmp(string, prefix, pfx_len) == 0);
282 bool parse_name_value(char *line, char *name, int namesize,
283 char *value, int valuesize)
285 char *sep;
286 int name_len, val_len;
287 name[0] = value[0] = '\0';
289 sep = rb->strcasestr(line, NAME_VALUE_SEPARATOR);
290 if (sep == NULL) {
291 /* No separator char -> weird instruction */
292 return false;
294 name_len = sep - line;
295 if (name_len >= namesize) {
296 /* Too long name */
297 return false;
299 rb->strncpy(name, line, name_len);
300 name[name_len] = '\0';
302 val_len = rb->strlen(line) - name_len - NAME_VALUE_SEPARATOR_LEN;
303 if (val_len >= valuesize) {
304 /* Too long value */
305 return false;
307 rb->strncpy(value, sep+NAME_VALUE_SEPARATOR_LEN, val_len+1);
308 return true;
312 bool dump_sc_file(sc_file_t *file, char *filename)
314 DEBUGF("Dumping shortcuts to the file '%s'\n", filename);
315 int fd;
317 /* ideally, we should just write a new
318 * entry to the file, but I'm going to
319 * be lazy, and just re-write the whole
320 * thing. */
321 fd = rb->open(filename, O_WRONLY|O_TRUNC);
322 if (fd < 0) {
323 rb->splashf(HZ*2, "Could not open shortcuts file %s for writing",
324 filename);
325 return false;
329 * Write instructions
331 /* Always dump the 'display last segms' settings (even it it's
332 * not active) so that it can be easily changed without having
333 * to remember the setting name */
334 write_int_instruction_to_file(fd,
335 INSTR_DISPLAY_LAST_SEGMENTS, file->show_last_segments);
337 int i;
338 sc_entry_t *entry;
339 for (i=0, entry=file->entries; i<file->entry_cnt; i++,entry++) {
340 write_entry_to_file(fd, entry);
343 rb->close(fd);
344 DEBUGF("Dumped %d entries to the file '%s'\n", file->entry_cnt, filename);
346 return true;
350 void write_int_instruction_to_file(int fd, char *instr, int value)
352 rb->fdprintf(fd, "%s%s%s%d\n", CONTROL_PREFIX, instr,
353 NAME_VALUE_SEPARATOR, value);
357 void write_entry_to_file(int fd, sc_entry_t *entry)
359 rb->fdprintf(fd, "%s", entry->path);
360 if (entry->explicit_disp) {
361 rb->fdprintf(fd, "%s%s", PATH_DISP_SEPARATOR, entry->disp);
363 rb->fdprintf(fd, "\n");