diff options
Diffstat (limited to 'apps/plugins/shortcuts/shortcuts_common.c')
-rw-r--r-- | apps/plugins/shortcuts/shortcuts_common.c | 394 |
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; +} |