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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2007 Bryan Childs
+ * Copyright (c) 2007 Alexander Levin
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "shortcuts.h"
+MEM_FUNCTION_WRAPPERS(rb);
+
+#define SHORTCUTS_FILENAME "/shortcuts.link"
+
+#define PATH_DISP_SEPARATOR "\t"
+#define PATH_DISP_SEPARATOR_LEN 1 /* strlen(PATH_DISP_SEPARATOR) */
+#define CONTROL_PREFIX "#"
+#define CONTROL_PREFIX_LEN 1 /* strlen(CONTROL_PREFIX) */
+#define NAME_VALUE_SEPARATOR "="
+#define NAME_VALUE_SEPARATOR_LEN 1 /* strlen(NAME_VALUE_SEPARATOR) */
+
+#define INSTR_DISPLAY_LAST_SEGMENTS "Display last path segments"
+
+/* Memory (will be used for entries) */
+void *memory_buf;
+long memory_bufsize; /* Size of memory_buf in bytes */
+
+
+/* The file we're processing */
+sc_file_t sc_file;
+
+bool parse_entry_content(char *line, sc_entry_t *entry, int last_segm);
+char *last_segments(char *path, int nsegm);
+bool is_control(char *line, sc_file_t *file);
+bool starts_with(char *string, char *prefix);
+bool parse_name_value(char *line, char *name, int namesize,
+ char *value, int valuesize);
+void write_entry_to_file(int fd, sc_entry_t *entry);
+void write_int_instruction_to_file(int fd, char *instr, int value);
+
+
+void allocate_memory(void **buf, size_t *bufsize)
+{
+ *buf = rb->plugin_get_buffer(bufsize);
+ DEBUGF("Got %ld bytes of memory\n", *bufsize);
+}
+
+
+void init_sc_file(sc_file_t *file, void *buf, size_t bufsize)
+{
+ file->entries = (sc_entry_t*)buf;
+ file->max_entries = bufsize / sizeof(sc_entry_t);
+ DEBUGF("Buffer capacity: %d entries\n", file->max_entries);
+ file->entry_cnt = 0;
+ file->show_last_segments = -1;
+}
+
+
+bool load_sc_file(sc_file_t *file, char *filename, bool must_exist,
+ void *entry_buf, size_t entry_bufsize)
+{
+ int fd = -1;
+ bool ret_val = false; /* Assume bad case */
+ int amountread = 0;
+ char sc_content[2*MAX_PATH];
+ sc_entry_t entry;
+
+ /* We start to load a new file -> prepare it */
+ init_sc_file(&sc_file, entry_buf, entry_bufsize);
+
+ fd = rb->open(filename, O_RDONLY);
+ if (fd < 0) {
+ /* The file didn't exist on disk */
+ if (!must_exist) {
+ DEBUGF("Trying to create link file '%s'...\n", filename);
+ fd = rb->creat(filename);
+ if (fd < 0){
+ /* For some reason we couldn't create the file,
+ * so return an error message and exit */
+ rb->splash(HZ*2, "Couldn't create the shortcuts file %s",
+ filename);
+ goto end_of_proc;
+ }
+ /* File created, but there's nothing in it, so just exit */
+ ret_val = true;
+ goto end_of_proc;
+ } else {
+ rb->splash(HZ, "Couldn't open %s", filename);
+ goto end_of_proc;
+ }
+ }
+
+ while ((amountread=rb->read_line(fd,sc_content, sizeof(sc_content)))) {
+ if (is_control(sc_content, file)) {
+ continue;
+ }
+ if (file->entry_cnt >= file->max_entries) {
+ rb->splash(HZ*2, "Too many entries in the file, max allowed: %d",
+ file->max_entries);
+ goto end_of_proc;
+ }
+ if (!parse_entry_content(sc_content, &entry,file->show_last_segments)) {
+ /* Could not parse the entry (too long path?) -> ignore */
+ DEBUGF("Could not parse '%s' -> ignored\n", sc_content);
+ continue;
+ }
+ DEBUGF("Parsed entry: path=%s, disp=%s\n", entry.path, entry.disp);
+ append_entry(file, &entry);
+ }
+
+#ifdef SC_DEBUG
+ print_file(file);
+#endif
+
+ ret_val = true; /* Everything went ok */
+
+end_of_proc:
+ if (fd >= 0) {
+ rb->close(fd);
+ fd = -1;
+ }
+ return ret_val;
+}
+
+#ifdef SC_DEBUG
+void print_file(sc_file_t *file)
+{
+ DEBUGF("Number of entries : %d\n", file->entry_cnt);
+ DEBUGF("Show Last Segments: %d\n", file->show_last_segments);
+ int i;
+ sc_entry_t *entry;
+ for (i=0, entry=file->entries; i<file->entry_cnt; i++,entry++) {
+ if (entry->explicit_disp) {
+ DEBUGF("%2d. '%s', show as '%s'\n", i+1, entry->path, entry->disp);
+ } else {
+ DEBUGF("%2d. '%s' (%s)\n", i+1, entry->path, entry->disp);
+ }
+ }
+}
+#endif
+
+
+bool append_entry(sc_file_t *file, sc_entry_t *entry)
+{
+ if (file->entry_cnt >= file->max_entries) {
+ return false;
+ }
+ rb->memcpy(file->entries+file->entry_cnt, entry, sizeof(*entry));
+ file->entry_cnt++;
+ return true;
+}
+
+
+bool remove_entry(sc_file_t *file, int entry_idx)
+{
+ if ((entry_idx<0) || (entry_idx>=file->entry_cnt)) {
+ return false;
+ }
+ sc_entry_t *start = file->entries + entry_idx;
+ rb->memmove(start, start + 1,
+ (file->entry_cnt-entry_idx-1) * sizeof(sc_entry_t));
+ file->entry_cnt--;
+ return true;
+}
+
+
+bool is_valid_index(sc_file_t *file, int entry_idx)
+{
+ return (entry_idx >= 0) && (entry_idx < file->entry_cnt);
+}
+
+
+bool parse_entry_content(char *line, sc_entry_t *entry, int last_segm)
+{
+ char *sep;
+ char *path, *disp;
+ unsigned int path_len, disp_len;
+ bool expl;
+
+ sep = rb->strcasestr(line, PATH_DISP_SEPARATOR);
+ expl = (sep != NULL);
+ if (expl) {
+ /* Explicit name for the entry is specified -> use it */
+ path = line;
+ path_len = sep - line;
+ disp = sep + PATH_DISP_SEPARATOR_LEN;
+ disp_len = rb->strlen(disp);
+ } else {
+ /* No special name to display */
+ path = line;
+ path_len = rb->strlen(line);
+ if (last_segm <= 0) {
+ disp = path;
+ } else {
+ disp = last_segments(line, last_segm);
+ }
+ disp_len = rb->strlen(disp);
+ }
+
+ if (path_len >= sizeof(entry->path) || disp_len >= sizeof(entry->disp)) {
+ DEBUGF("Bad entry: pathlen=%d, displen=%d\n", path_len, disp_len);
+ return false;
+ }
+ rb->strncpy(entry->path, path, path_len);
+ entry->path[path_len] = '\0';
+ rb->strcpy(entry->disp, disp); /* Safe since we've checked the length */
+ entry->explicit_disp = expl;
+ return true;
+}
+
+
+char *last_segments(char *path, int nsegm)
+{
+ char *p = rb->strrchr(path, PATH_SEPARATOR[0]); /* Hack */
+ int seg_cnt;
+ if (p == NULL)
+ return path; /* No separator??? */
+ seg_cnt = 0;
+ while ((p > path) && (seg_cnt < nsegm)) {
+ p--;
+ if (!starts_with(p, PATH_SEPARATOR)) {
+ continue;
+ }
+ seg_cnt++;
+ if (seg_cnt == nsegm && p > path) {
+ p++; /* Eat the '/' to show that something has been truncated */
+ }
+ }
+ return p;
+}
+
+
+bool is_control(char *line, sc_file_t *file)
+{
+ char name[MAX_PATH], value[MAX_PATH];
+ if (!starts_with(line, CONTROL_PREFIX)) {
+ return false;
+ }
+ line += CONTROL_PREFIX_LEN;
+
+ if (!parse_name_value(line, name, sizeof(name),
+ value, sizeof(value))) {
+ DEBUGF("Bad processing instruction: '%s'\n", line);
+ return true;
+ }
+
+ /* Process control instruction */
+ if (rb->strcasestr(name, INSTR_DISPLAY_LAST_SEGMENTS)) {
+ file->show_last_segments = rb->atoi(value);
+ DEBUGF("Set show last segms to %d\n", file->show_last_segments);
+ } else {
+ /* Unknown instruction -> ignore */
+ DEBUGF("Unknown processing instruction: '%s'\n", name);
+ }
+
+ return true;
+}
+
+
+bool starts_with(char *string, char *prefix)
+{
+ unsigned int pfx_len = rb->strlen(prefix);
+ if (rb->strlen(string) < pfx_len)
+ return false;
+ return (rb->strncmp(string, prefix, pfx_len) == 0);
+}
+
+
+bool parse_name_value(char *line, char *name, int namesize,
+ char *value, int valuesize)
+{
+ char *sep;
+ int name_len, val_len;
+ name[0] = value[0] = '\0';
+
+ sep = rb->strcasestr(line, NAME_VALUE_SEPARATOR);
+ if (sep == NULL) {
+ /* No separator char -> weird instruction */
+ return false;
+ }
+ name_len = sep - line;
+ if (name_len >= namesize) {
+ /* Too long name */
+ return false;
+ }
+ rb->strncpy(name, line, name_len);
+ name[name_len] = '\0';
+
+ val_len = rb->strlen(line) - name_len - NAME_VALUE_SEPARATOR_LEN;
+ if (val_len >= valuesize) {
+ /* Too long value */
+ return false;
+ }
+ rb->strncpy(value, sep+NAME_VALUE_SEPARATOR_LEN, val_len+1);
+ return true;
+}
+
+
+bool dump_sc_file(sc_file_t *file, char *filename)
+{
+ DEBUGF("Dumping shortcuts to the file '%s'\n", filename);
+ int fd;
+
+ /* ideally, we should just write a new
+ * entry to the file, but I'm going to
+ * be lazy, and just re-write the whole
+ * thing. */
+ fd = rb->open(filename, O_WRONLY|O_TRUNC);
+ if (fd < 0) {
+ rb->splash(HZ*2, "Could not open shortcuts file %s for writing",
+ filename);
+ return false;
+ }
+
+ /*
+ * Write instructions
+ */
+ /* Always dump the 'display last segms' settings (even it it's
+ * not active) so that it can be easily changed without having
+ * to remember the setting name */
+ write_int_instruction_to_file(fd,
+ INSTR_DISPLAY_LAST_SEGMENTS, file->show_last_segments);
+
+ int i;
+ sc_entry_t *entry;
+ for (i=0, entry=file->entries; i<file->entry_cnt; i++,entry++) {
+ write_entry_to_file(fd, entry);
+ }
+
+ rb->close(fd);
+ DEBUGF("Dumped %d entries to the file '%s'\n", file->entry_cnt, filename);
+
+ return true;
+}
+
+
+void write_int_instruction_to_file(int fd, char *instr, int value)
+{
+ rb->fdprintf(fd, "%s%s%s%d\n", CONTROL_PREFIX, instr,
+ NAME_VALUE_SEPARATOR, value);
+}
+
+
+void write_entry_to_file(int fd, sc_entry_t *entry)
+{
+ rb->fdprintf(fd, "%s", entry->path);
+ if (entry->explicit_disp) {
+ rb->fdprintf(fd, "%s%s", PATH_DISP_SEPARATOR, entry->disp);
+ }
+ rb->fdprintf(fd, "\n");
+}
+
+
+bool file_exists(char *filename)
+{
+ int fd = rb->open(filename, O_RDONLY);
+ bool retval;
+ if (fd >= 0) {
+ rb->close(fd);
+ retval = true;
+ } else {
+ retval = false;
+ }
+ DEBUGF("Checked existence of the file '%s': %s\n",
+ filename, (retval ? "found" : "NOT FOUND"));
+ return retval;
+}
+
+
+bool dir_exists(char *path)
+{
+ DIR* d = rb->opendir(path);
+ bool retval;
+ if (d != NULL) {
+ rb->closedir(d);
+ retval = true;
+ } else {
+ retval = false;
+ }
+ DEBUGF("Checked existence of the dir '%s': %s\n",
+ path, (retval ? "found" : "NOT FOUND"));
+ return retval;
+}