diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/plugins/sort.c | 207 | ||||
-rw-r--r-- | apps/plugins/viewers.config | 1 |
2 files changed, 208 insertions, 0 deletions
diff --git a/apps/plugins/sort.c b/apps/plugins/sort.c new file mode 100644 index 0000000000..ae59bd0121 --- /dev/null +++ b/apps/plugins/sort.c | |||
@@ -0,0 +1,207 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 Linus Nielsen Feltzing | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #include "plugin.h" | ||
20 | |||
21 | /**************************************************************************** | ||
22 | * Buffer handling: | ||
23 | * | ||
24 | * We allocate the MP3 buffer for storing the text to be sorted, and then | ||
25 | * search the buffer for newlines and store an array of character pointers | ||
26 | * to the strings. | ||
27 | * | ||
28 | * The pointer array grows from the top of the buffer and downwards: | ||
29 | * | ||
30 | * |-------------| | ||
31 | * | pointers[2] |--------| | ||
32 | * | pointers[1] |------| | | ||
33 | * | pointers[0] |----| | | | ||
34 | * |-------------| | | | | ||
35 | * | | | | | | ||
36 | * | | | | | | ||
37 | * | free space | | | | | ||
38 | * | | | | | | ||
39 | * | | | | | | ||
40 | * |-------------| | | | | ||
41 | * | | | | | | ||
42 | * | line 3\0 |<---| | | | ||
43 | * | line 2\0 |<-----| | | ||
44 | * | line 1\0 |<-------| | ||
45 | * |-------------| | ||
46 | * | ||
47 | * The advantage of this method is that we optimize the buffer usage. | ||
48 | * | ||
49 | * The disadvantage is that the string pointers will be loaded in reverse | ||
50 | * order. We therefore sort the strings in reverse order as well, so we | ||
51 | * don't have to sort an already sorted buffer. | ||
52 | ****************************************************************************/ | ||
53 | |||
54 | /*************************************************************************** | ||
55 | * TODO: Implement a merge sort for files larger than the buffer | ||
56 | ****************************************************************************/ | ||
57 | |||
58 | static struct plugin_api* rb; | ||
59 | |||
60 | int buf_size; | ||
61 | static char *filename; | ||
62 | static int num_entries; | ||
63 | static char **pointers; | ||
64 | static char *stringbuffer; | ||
65 | static char crlf[2] = "\r\n"; | ||
66 | |||
67 | /* Compare function for sorting backwards */ | ||
68 | static int compare(const void* p1, const void* p2) | ||
69 | { | ||
70 | char *s1 = *(char **)p1; | ||
71 | char *s2 = *(char **)p2; | ||
72 | |||
73 | return rb->strcmp(s2, s1); | ||
74 | } | ||
75 | |||
76 | static void sort_buffer(void) | ||
77 | { | ||
78 | rb->qsort(pointers, num_entries, sizeof(char *), compare); | ||
79 | } | ||
80 | |||
81 | int read_buffer(int offset) | ||
82 | { | ||
83 | int fd; | ||
84 | char *buf_ptr; | ||
85 | char *tmp_ptr; | ||
86 | int readsize; | ||
87 | |||
88 | fd = rb->open(filename, O_RDONLY); | ||
89 | if(fd < 0) | ||
90 | return 10 * fd - 1; | ||
91 | |||
92 | /* Fill the buffer from the file */ | ||
93 | rb->lseek(fd, offset, SEEK_SET); | ||
94 | readsize = rb->read(fd, stringbuffer, buf_size); | ||
95 | rb->close(fd); | ||
96 | |||
97 | if(readsize < 0) | ||
98 | return readsize * 10 - 2; | ||
99 | |||
100 | /* Temporary fix until we can do merged sorting */ | ||
101 | if(readsize == buf_size) | ||
102 | return buf_size; /* File too big */ | ||
103 | |||
104 | buf_ptr = stringbuffer; | ||
105 | num_entries = 0; | ||
106 | |||
107 | do { | ||
108 | tmp_ptr = buf_ptr; | ||
109 | while(*buf_ptr != '\n' && buf_ptr < (char *)pointers) { | ||
110 | /* Terminate the string with CR... */ | ||
111 | if(*buf_ptr == '\r') | ||
112 | *buf_ptr = 0; | ||
113 | buf_ptr++; | ||
114 | } | ||
115 | /* ...and with LF */ | ||
116 | if(*buf_ptr == '\n') | ||
117 | *buf_ptr = 0; | ||
118 | else { | ||
119 | return tmp_ptr - stringbuffer; /* Buffer is full, return | ||
120 | the point to resume at */ | ||
121 | } | ||
122 | |||
123 | pointers--; | ||
124 | *pointers = tmp_ptr; | ||
125 | num_entries++; | ||
126 | buf_ptr++; | ||
127 | } while(buf_ptr < stringbuffer + readsize); | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | static int write_file(void) | ||
133 | { | ||
134 | char tmpfilename[MAX_PATH+1]; | ||
135 | int fd; | ||
136 | int i; | ||
137 | int rc; | ||
138 | |||
139 | /* Create a temporary file */ | ||
140 | rb->snprintf(tmpfilename, MAX_PATH+1, "%s.tmp", filename); | ||
141 | fd = rb->creat(tmpfilename, 0); | ||
142 | if(fd < 0) | ||
143 | return 10 * fd - 1; | ||
144 | |||
145 | /* Write the sorted strings, with appended CR/LF, to the temp file, | ||
146 | in reverse order */ | ||
147 | for(i = num_entries-1;i >= 0;i--) { | ||
148 | rc = rb->write(fd, pointers[i], rb->strlen(pointers[i])); | ||
149 | if(rc < 0) { | ||
150 | rb->close(fd); | ||
151 | return 10 * rc - 2; | ||
152 | } | ||
153 | |||
154 | rc = rb->write(fd, crlf, 2); | ||
155 | if(rc < 0) { | ||
156 | rb->close(fd); | ||
157 | return 10 * rc - 3; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | rb->close(fd); | ||
162 | |||
163 | /* Remove the original file */ | ||
164 | rc = rb->remove(filename); | ||
165 | if(rc < 0) { | ||
166 | return 10 * rc - 4; | ||
167 | } | ||
168 | |||
169 | /* Replace the old file with the new */ | ||
170 | rc = rb->rename(tmpfilename, filename); | ||
171 | if(rc < 0) { | ||
172 | return 10 * rc - 5; | ||
173 | } | ||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | ||
178 | { | ||
179 | char *buf; | ||
180 | int rc; | ||
181 | TEST_PLUGIN_API(api); | ||
182 | |||
183 | filename = (char *)parameter; | ||
184 | |||
185 | rb = api; | ||
186 | |||
187 | buf = rb->plugin_get_mp3_buffer(&buf_size); /* start munching memory */ | ||
188 | |||
189 | stringbuffer = buf; | ||
190 | pointers = (char **)(buf + buf_size - sizeof(int)); | ||
191 | |||
192 | rc = read_buffer(0); | ||
193 | if(rc == 0) { | ||
194 | sort_buffer(); | ||
195 | rc = write_file(); | ||
196 | if(rc < 0) { | ||
197 | rb->splash(HZ, true, "Can't write file: %d", rc); | ||
198 | } | ||
199 | } else { | ||
200 | if(rc < 0) | ||
201 | rb->splash(HZ, true, "Can't read file: %d", rc); | ||
202 | else | ||
203 | rb->splash(HZ, true, "The file is too big"); | ||
204 | } | ||
205 | |||
206 | return PLUGIN_OK; | ||
207 | } | ||
diff --git a/apps/plugins/viewers.config b/apps/plugins/viewers.config index 2b1d52766b..a04c1640a5 100644 --- a/apps/plugins/viewers.config +++ b/apps/plugins/viewers.config | |||
@@ -5,3 +5,4 @@ ucl,rockbox_flash.rock,2A 7F 41 41 7F 2A | |||
5 | rvf,video.rock,5D 7F 5D 7F 5D 7F | 5 | rvf,video.rock,5D 7F 5D 7F 5D 7F |
6 | mp3,vbrfix.rock,10 08 58 38 04 02 | 6 | mp3,vbrfix.rock,10 08 58 38 04 02 |
7 | m3u,search.rock,00 00 00 00 00 00 | 7 | m3u,search.rock,00 00 00 00 00 00 |
8 | txt,sort.rock, 00 00 00 00 00 00 | ||