diff options
author | Björn Stenberg <bjorn@haxx.se> | 2005-01-27 22:21:08 +0000 |
---|---|---|
committer | Björn Stenberg <bjorn@haxx.se> | 2005-01-27 22:21:08 +0000 |
commit | 6660f8e91060593cfd6a50c5acf58a653bd284e0 (patch) | |
tree | 494ac07fe5b3737d29d1567093f98024b6a73104 | |
parent | d719abce64c51a40bf01b613d26b63e57e2abcc2 (diff) | |
download | rockbox-6660f8e91060593cfd6a50c5acf58a653bd284e0.tar.gz rockbox-6660f8e91060593cfd6a50c5acf58a653bd284e0.zip |
Added ID3 searching
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@5683 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | apps/dbtree.c | 196 | ||||
-rw-r--r-- | apps/dbtree.h | 3 | ||||
-rw-r--r-- | apps/lang/english.lang | 30 | ||||
-rw-r--r-- | firmware/SOURCES | 1 | ||||
-rw-r--r-- | firmware/common/strcasestr.c | 122 | ||||
-rw-r--r-- | firmware/include/string.h | 1 |
6 files changed, 310 insertions, 43 deletions
diff --git a/apps/dbtree.c b/apps/dbtree.c index 6925fd3f29..5b30863f39 100644 --- a/apps/dbtree.c +++ b/apps/dbtree.c | |||
@@ -16,6 +16,7 @@ | |||
16 | * KIND, either express or implied. | 16 | * KIND, either express or implied. |
17 | * | 17 | * |
18 | ****************************************************************************/ | 18 | ****************************************************************************/ |
19 | #define _GNU_SOURCE | ||
19 | #include <stdio.h> | 20 | #include <stdio.h> |
20 | #include <string.h> | 21 | #include <string.h> |
21 | #include "file.h" | 22 | #include "file.h" |
@@ -40,6 +41,7 @@ | |||
40 | #include "dbtree.h" | 41 | #include "dbtree.h" |
41 | #include "icons.h" | 42 | #include "icons.h" |
42 | #include "lang.h" | 43 | #include "lang.h" |
44 | #include "keyboard.h" | ||
43 | 45 | ||
44 | #ifdef LITTLE_ENDIAN | 46 | #ifdef LITTLE_ENDIAN |
45 | #include <netinet/in.h> | 47 | #include <netinet/in.h> |
@@ -60,6 +62,9 @@ static int | |||
60 | artistlen, initialized = 0; | 62 | artistlen, initialized = 0; |
61 | 63 | ||
62 | static int db_play_folder(struct tree_context* c); | 64 | static int db_play_folder(struct tree_context* c); |
65 | static int db_search(struct tree_context* c, char* string); | ||
66 | |||
67 | static char searchstring[32]; | ||
63 | 68 | ||
64 | int db_init(void) | 69 | int db_init(void) |
65 | { | 70 | { |
@@ -78,45 +83,35 @@ int db_init(void) | |||
78 | ptr[1] != 'D' || | 83 | ptr[1] != 'D' || |
79 | ptr[2] != 'B') | 84 | ptr[2] != 'B') |
80 | { | 85 | { |
81 | DEBUGF("File is not a rockbox id3 database, aborting\n"); | 86 | splash(HZ,true,"Not a rockbox ID3 database!"); |
82 | return -1; | 87 | return -1; |
83 | } | 88 | } |
84 | 89 | ||
85 | version = BE32(buf[0]) & 0xff; | 90 | version = BE32(buf[0]) & 0xff; |
86 | if (version != ID3DB_VERSION) | 91 | if (version != ID3DB_VERSION) |
87 | { | 92 | { |
88 | DEBUGF("Unsupported database version %d, aborting.\n"); | 93 | splash(HZ,true,"Unsupported database version %d!", version); |
89 | return -1; | 94 | return -1; |
90 | } | 95 | } |
91 | DEBUGF("Version: RDB%d\n", version); | ||
92 | 96 | ||
93 | songstart = BE32(buf[1]); | 97 | songstart = BE32(buf[1]); |
94 | songcount = BE32(buf[2]); | 98 | songcount = BE32(buf[2]); |
95 | songlen = BE32(buf[3]); | 99 | songlen = BE32(buf[3]); |
96 | DEBUGF("Number of songs: %d\n", songcount); | ||
97 | DEBUGF("Songstart: %x\n", songstart); | ||
98 | DEBUGF("Songlen: %d\n", songlen); | ||
99 | 100 | ||
100 | albumstart = BE32(buf[4]); | 101 | albumstart = BE32(buf[4]); |
101 | albumcount = BE32(buf[5]); | 102 | albumcount = BE32(buf[5]); |
102 | albumlen = BE32(buf[6]); | 103 | albumlen = BE32(buf[6]); |
103 | songarraylen = BE32(buf[7]); | 104 | songarraylen = BE32(buf[7]); |
104 | DEBUGF("Number of albums: %d\n", albumcount); | ||
105 | DEBUGF("Albumstart: %x\n", albumstart); | ||
106 | DEBUGF("Albumlen: %d\n", albumlen); | ||
107 | 105 | ||
108 | artiststart = BE32(buf[8]); | 106 | artiststart = BE32(buf[8]); |
109 | artistcount = BE32(buf[9]); | 107 | artistcount = BE32(buf[9]); |
110 | artistlen = BE32(buf[10]); | 108 | artistlen = BE32(buf[10]); |
111 | albumarraylen = BE32(buf[11]); | 109 | albumarraylen = BE32(buf[11]); |
112 | DEBUGF("Number of artists: %d\n", artistcount); | ||
113 | DEBUGF("Artiststart: %x\n", artiststart); | ||
114 | DEBUGF("Artistlen: %d\n", artistlen); | ||
115 | 110 | ||
116 | if (songstart > albumstart || | 111 | if (songstart > albumstart || |
117 | albumstart > artiststart) | 112 | albumstart > artiststart) |
118 | { | 113 | { |
119 | DEBUGF("Corrupt id3db database, aborting.\n"); | 114 | splash(HZ,true,"Corrupt ID3 database!"); |
120 | return -1; | 115 | return -1; |
121 | } | 116 | } |
122 | 117 | ||
@@ -157,11 +152,33 @@ int db_load(struct tree_context* c) | |||
157 | 152 | ||
158 | switch (table) { | 153 | switch (table) { |
159 | case root: { | 154 | case root: { |
160 | static const int tables[] = {allartists, allalbums, allsongs}; | 155 | static const int tables[] = {allartists, allalbums, allsongs, |
156 | search }; | ||
161 | char* nbuf = (char*)nptr; | 157 | char* nbuf = (char*)nptr; |
162 | char* labels[] = { str(LANG_ID3DB_ARTISTS), | 158 | char* labels[] = { str(LANG_ID3DB_ARTISTS), |
163 | str(LANG_ID3DB_ALBUMS), | 159 | str(LANG_ID3DB_ALBUMS), |
164 | str(LANG_ID3DB_SONGS)}; | 160 | str(LANG_ID3DB_SONGS), |
161 | str(LANG_ID3DB_SEARCH)}; | ||
162 | |||
163 | for (i=0; i < 4; i++) { | ||
164 | strcpy(nbuf, labels[i]); | ||
165 | dptr[0] = (unsigned int)nbuf; | ||
166 | dptr[1] = tables[i]; | ||
167 | nbuf += strlen(nbuf) + 1; | ||
168 | dptr += 2; | ||
169 | } | ||
170 | c->dirlength = c->filesindir = i; | ||
171 | return i; | ||
172 | } | ||
173 | |||
174 | case search: { | ||
175 | static const int tables[] = {searchartists, | ||
176 | searchalbums, | ||
177 | searchsongs}; | ||
178 | char* nbuf = (char*)nptr; | ||
179 | char* labels[] = { str(LANG_ID3DB_SEARCH_ARTISTS), | ||
180 | str(LANG_ID3DB_SEARCH_ALBUMS), | ||
181 | str(LANG_ID3DB_SEARCH_SONGS)}; | ||
165 | 182 | ||
166 | for (i=0; i < 3; i++) { | 183 | for (i=0; i < 3; i++) { |
167 | strcpy(nbuf, labels[i]); | 184 | strcpy(nbuf, labels[i]); |
@@ -173,12 +190,26 @@ int db_load(struct tree_context* c) | |||
173 | c->dirlength = c->filesindir = i; | 190 | c->dirlength = c->filesindir = i; |
174 | return i; | 191 | return i; |
175 | } | 192 | } |
176 | 193 | ||
194 | case searchartists: | ||
195 | case searchalbums: | ||
196 | case searchsongs: | ||
197 | i = db_search(c, searchstring); | ||
198 | c->dirlength = c->filesindir = i; | ||
199 | if (c->dirfull) { | ||
200 | splash(HZ, true, "%s %s", | ||
201 | str(LANG_SHOWDIR_ERROR_BUFFER), | ||
202 | str(LANG_SHOWDIR_ERROR_FULL)); | ||
203 | c->dirfull = false; | ||
204 | } | ||
205 | else | ||
206 | splash(HZ, true, str(LANG_ID3DB_MATCHES), i); | ||
207 | return i; | ||
208 | |||
177 | case allsongs: | 209 | case allsongs: |
178 | offset = songstart + c->firstpos * (songlen + 12); | 210 | offset = songstart + c->firstpos * (songlen + 12); |
179 | itemcount = songcount; | 211 | itemcount = songcount; |
180 | stringlen = songlen; | 212 | stringlen = songlen; |
181 | c->dentry_size = 3; | ||
182 | break; | 213 | break; |
183 | 214 | ||
184 | case allalbums: | 215 | case allalbums: |
@@ -229,7 +260,6 @@ int db_load(struct tree_context* c) | |||
229 | offset = safeplace[0]; | 260 | offset = safeplace[0]; |
230 | itemcount = songarraylen; | 261 | itemcount = songarraylen; |
231 | stringlen = songlen; | 262 | stringlen = songlen; |
232 | c->dentry_size = 3; | ||
233 | break; | 263 | break; |
234 | 264 | ||
235 | default: | 265 | default: |
@@ -257,7 +287,7 @@ int db_load(struct tree_context* c) | |||
257 | if (max_items > itemcount) { | 287 | if (max_items > itemcount) { |
258 | max_items = itemcount; | 288 | max_items = itemcount; |
259 | } | 289 | } |
260 | 290 | ||
261 | for ( i=0; i < max_items; i++ ) { | 291 | for ( i=0; i < max_items; i++ ) { |
262 | int rc, skip=0; | 292 | int rc, skip=0; |
263 | int intbuf[4]; | 293 | int intbuf[4]; |
@@ -267,7 +297,6 @@ int db_load(struct tree_context* c) | |||
267 | c->dirlength = i; | 297 | c->dirlength = i; |
268 | break; | 298 | break; |
269 | } | 299 | } |
270 | //DEBUGF("Seeking to %x\n", safeplace[i]); | ||
271 | lseek(fd, safeplace[i], SEEK_SET); | 300 | lseek(fd, safeplace[i], SEEK_SET); |
272 | offset = safeplace[i]; | 301 | offset = safeplace[i]; |
273 | } | 302 | } |
@@ -286,16 +315,13 @@ int db_load(struct tree_context* c) | |||
286 | switch (table) { | 315 | switch (table) { |
287 | case allsongs: | 316 | case allsongs: |
288 | case songs4album: | 317 | case songs4album: |
289 | /* save offset of this song */ | ||
290 | dptr[1] = offset; | ||
291 | |||
292 | rc = read(fd, intbuf, 12); | 318 | rc = read(fd, intbuf, 12); |
293 | if (rc < 12) { | 319 | if (rc < 12) { |
294 | DEBUGF("%d read(%d) returned %d\n", i, 12, rc); | 320 | DEBUGF("%d read(%d) returned %d\n", i, 12, rc); |
295 | return -1; | 321 | return -1; |
296 | } | 322 | } |
297 | /* save offset of filename */ | 323 | /* save offset of filename */ |
298 | dptr[2] = BE32(intbuf[2]); | 324 | dptr[1] = BE32(intbuf[2]); |
299 | break; | 325 | break; |
300 | 326 | ||
301 | case allalbums: | 327 | case allalbums: |
@@ -332,11 +358,95 @@ int db_load(struct tree_context* c) | |||
332 | return i; | 358 | return i; |
333 | } | 359 | } |
334 | 360 | ||
361 | static int db_search(struct tree_context* c, char* string) | ||
362 | { | ||
363 | int i, count, size, hits=0; | ||
364 | long start; | ||
365 | |||
366 | char* nptr = c->name_buffer; | ||
367 | const char* end_of_nbuf = nptr + c->name_buffer_size; | ||
368 | |||
369 | unsigned long* dptr = c->dircache; | ||
370 | const long dcachesize = global_settings.max_files_in_dir * | ||
371 | sizeof(struct entry); | ||
372 | |||
373 | switch (c->currtable) { | ||
374 | case searchartists: | ||
375 | start = artiststart; | ||
376 | count = artistcount; | ||
377 | size = artistlen + albumarraylen * 4; | ||
378 | break; | ||
379 | |||
380 | case searchalbums: | ||
381 | start = albumstart; | ||
382 | count = albumcount; | ||
383 | size = albumlen + 4 + songarraylen * 4; | ||
384 | break; | ||
385 | |||
386 | case searchsongs: | ||
387 | start = songstart; | ||
388 | count = songcount; | ||
389 | size = songlen + 12; | ||
390 | break; | ||
391 | |||
392 | default: | ||
393 | DEBUGF("Invalid table %d\n", c->currtable); | ||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | lseek(fd, start, SEEK_SET); | ||
398 | |||
399 | for (i=0; i<count; i++) { | ||
400 | if (read(fd, nptr, size) < size) { | ||
401 | DEBUGF("Short read(%d) in db_search()\n",size); | ||
402 | break; | ||
403 | } | ||
404 | if (strcasestr(nptr, string)) { | ||
405 | hits++; | ||
406 | |||
407 | dptr[0] = (unsigned long)nptr; | ||
408 | if (c->currtable == searchsongs) { | ||
409 | /* store offset of filename */ | ||
410 | dptr[1] = BE32(*((long*)(nptr + songlen + 8))); | ||
411 | } | ||
412 | else | ||
413 | /* store offset of database record */ | ||
414 | dptr[1] = start + i * size; | ||
415 | |||
416 | dptr += 2; | ||
417 | |||
418 | /* limit dir buffer */ | ||
419 | if ((void*)(dptr + c->dentry_size) > | ||
420 | (void*)(c->dircache + dcachesize)) | ||
421 | { | ||
422 | c->dirfull = true; | ||
423 | break; | ||
424 | } | ||
425 | |||
426 | nptr += strlen(nptr) + 1; | ||
427 | while ((unsigned long)nptr & 3) | ||
428 | nptr++; | ||
429 | |||
430 | /* limit name buffer */ | ||
431 | if ((void*)nptr + size > (void*)end_of_nbuf) { | ||
432 | c->dirfull = true; | ||
433 | break; | ||
434 | } | ||
435 | } | ||
436 | } | ||
437 | |||
438 | return hits; | ||
439 | } | ||
440 | |||
335 | int db_enter(struct tree_context* c) | 441 | int db_enter(struct tree_context* c) |
336 | { | 442 | { |
337 | int rc = 0; | 443 | int rc = 0; |
338 | int newextra = ((int*)c->dircache)[(c->dircursor + c->dirstart)*2 + 1]; | 444 | int offset = (c->dircursor + c->dirstart) * c->dentry_size + 1; |
445 | int newextra = ((int*)c->dircache)[offset]; | ||
339 | 446 | ||
447 | if (c->dirlevel >= MAX_DIR_LEVELS) | ||
448 | return 0; | ||
449 | |||
340 | c->dirpos[c->dirlevel] = c->dirstart; | 450 | c->dirpos[c->dirlevel] = c->dirstart; |
341 | c->cursorpos[c->dirlevel] = c->dircursor; | 451 | c->cursorpos[c->dirlevel] = c->dircursor; |
342 | c->table_history[c->dirlevel] = c->currtable; | 452 | c->table_history[c->dirlevel] = c->currtable; |
@@ -351,24 +461,36 @@ int db_enter(struct tree_context* c) | |||
351 | break; | 461 | break; |
352 | 462 | ||
353 | case allartists: | 463 | case allartists: |
464 | case searchartists: | ||
354 | c->currtable = albums4artist; | 465 | c->currtable = albums4artist; |
355 | c->currextra = newextra; | 466 | c->currextra = newextra; |
356 | break; | 467 | break; |
357 | 468 | ||
358 | case allalbums: | 469 | case allalbums: |
359 | case albums4artist: | 470 | case albums4artist: |
471 | case searchalbums: | ||
360 | c->currtable = songs4album; | 472 | c->currtable = songs4album; |
361 | c->currextra = newextra; | 473 | c->currextra = newextra; |
362 | break; | 474 | break; |
363 | 475 | ||
364 | case allsongs: | 476 | case allsongs: |
365 | case songs4album: | 477 | case songs4album: |
478 | case searchsongs: | ||
366 | c->dirlevel--; | 479 | c->dirlevel--; |
367 | if (db_play_folder(c) >= 0) | 480 | if (db_play_folder(c) >= 0) |
368 | rc = 3; | 481 | rc = 3; |
369 | break; | 482 | break; |
483 | |||
484 | case search: | ||
485 | rc = kbd_input(searchstring, sizeof(searchstring)); | ||
486 | if (rc == -1 || !searchstring[0]) | ||
487 | c->dirlevel--; | ||
488 | else | ||
489 | c->currtable = newextra; | ||
490 | break; | ||
370 | 491 | ||
371 | default: | 492 | default: |
493 | c->dirlevel--; | ||
372 | break; | 494 | break; |
373 | } | 495 | } |
374 | 496 | ||
@@ -401,7 +523,7 @@ static int db_play_folder(struct tree_context* c) | |||
401 | /* TODO: add support for very long tables */ | 523 | /* TODO: add support for very long tables */ |
402 | 524 | ||
403 | for (i=0; i < c->filesindir; i++) { | 525 | for (i=0; i < c->filesindir; i++) { |
404 | int pathoffset = ((int*)c->dircache)[i * c->dentry_size + 2]; | 526 | int pathoffset = ((int*)c->dircache)[i * c->dentry_size + 1]; |
405 | lseek(fd, pathoffset, SEEK_SET); | 527 | lseek(fd, pathoffset, SEEK_SET); |
406 | rc = read(fd, buf, sizeof(buf)); | 528 | rc = read(fd, buf, sizeof(buf)); |
407 | if (rc < songlen) { | 529 | if (rc < songlen) { |
@@ -424,6 +546,9 @@ static int db_play_folder(struct tree_context* c) | |||
424 | 546 | ||
425 | #ifdef HAVE_LCD_BITMAP | 547 | #ifdef HAVE_LCD_BITMAP |
426 | const char* db_get_icon(struct tree_context* c) | 548 | const char* db_get_icon(struct tree_context* c) |
549 | #else | ||
550 | int db_get_icon(struct tree_context* c) | ||
551 | #endif | ||
427 | { | 552 | { |
428 | int icon; | 553 | int icon; |
429 | 554 | ||
@@ -431,6 +556,7 @@ const char* db_get_icon(struct tree_context* c) | |||
431 | { | 556 | { |
432 | case allsongs: | 557 | case allsongs: |
433 | case songs4album: | 558 | case songs4album: |
559 | case searchsongs: | ||
434 | icon = File; | 560 | icon = File; |
435 | break; | 561 | break; |
436 | 562 | ||
@@ -439,23 +565,9 @@ const char* db_get_icon(struct tree_context* c) | |||
439 | break; | 565 | break; |
440 | } | 566 | } |
441 | 567 | ||
568 | #ifdef HAVE_LCD_BITMAP | ||
442 | return bitmap_icons_6x8[icon]; | 569 | return bitmap_icons_6x8[icon]; |
443 | } | ||
444 | #else | 570 | #else |
445 | int db_get_icon(struct tree_context* c) | ||
446 | { | ||
447 | int icon; | ||
448 | switch (c->currtable) | ||
449 | { | ||
450 | case allsongs: | ||
451 | case songs4album: | ||
452 | icon = File; | ||
453 | break; | ||
454 | |||
455 | default: | ||
456 | icon = Folder; | ||
457 | break; | ||
458 | } | ||
459 | return icon; | 571 | return icon; |
460 | } | ||
461 | #endif | 572 | #endif |
573 | } | ||
diff --git a/apps/dbtree.h b/apps/dbtree.h index b0c726881f..5cf2e4feed 100644 --- a/apps/dbtree.h +++ b/apps/dbtree.h | |||
@@ -22,7 +22,8 @@ | |||
22 | #include "tree.h" | 22 | #include "tree.h" |
23 | 23 | ||
24 | enum table { invalid, root, allsongs, allalbums, allartists, | 24 | enum table { invalid, root, allsongs, allalbums, allartists, |
25 | albums4artist, songs4album }; | 25 | albums4artist, songs4album, |
26 | search, searchartists, searchalbums, searchsongs }; | ||
26 | 27 | ||
27 | int db_init(void); | 28 | int db_init(void); |
28 | int db_enter(struct tree_context* c); | 29 | int db_enter(struct tree_context* c); |
diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 05903601db..795bde69f8 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang | |||
@@ -2895,3 +2895,33 @@ desc: ID3 virtual folder name | |||
2895 | eng: "Songs" | 2895 | eng: "Songs" |
2896 | voice: "" | 2896 | voice: "" |
2897 | new: | 2897 | new: |
2898 | |||
2899 | id: LANG_ID3DB_SEARCH | ||
2900 | desc: ID3 virtual folder name | ||
2901 | eng: "Search" | ||
2902 | voice: "" | ||
2903 | new: | ||
2904 | |||
2905 | id: LANG_ID3DB_SEARCH_ARTISTS | ||
2906 | desc: ID3 virtual folder name | ||
2907 | eng: "Search Artists" | ||
2908 | voice: "" | ||
2909 | new: | ||
2910 | |||
2911 | id: LANG_ID3DB_SEARCH_ALBUMS | ||
2912 | desc: ID3 virtual folder name | ||
2913 | eng: "Search Albums" | ||
2914 | voice: "" | ||
2915 | new: | ||
2916 | |||
2917 | id: LANG_ID3DB_SEARCH_SONGS | ||
2918 | desc: ID3 virtual folder name | ||
2919 | eng: "Search Songs" | ||
2920 | voice: "" | ||
2921 | new: | ||
2922 | |||
2923 | id: LANG_ID3DB_MATCHES | ||
2924 | desc: ID3 virtual folder name | ||
2925 | eng: "Found %d matches" | ||
2926 | voice: "" | ||
2927 | new: | ||
diff --git a/firmware/SOURCES b/firmware/SOURCES index c3db4e163b..92ba69d179 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES | |||
@@ -17,6 +17,7 @@ common/qsort.c | |||
17 | common/random.c | 17 | common/random.c |
18 | common/sprintf.c | 18 | common/sprintf.c |
19 | common/strcasecmp.c | 19 | common/strcasecmp.c |
20 | common/strcasestr.c | ||
20 | common/strcat.c | 21 | common/strcat.c |
21 | common/strchr.c | 22 | common/strchr.c |
22 | common/strcmp.c | 23 | common/strcmp.c |
diff --git a/firmware/common/strcasestr.c b/firmware/common/strcasestr.c new file mode 100644 index 0000000000..095eebdd66 --- /dev/null +++ b/firmware/common/strcasestr.c | |||
@@ -0,0 +1,122 @@ | |||
1 | /* Return the offset of one string within another. | ||
2 | Copyright (C) 1994,1996,1997,1998,1999,2000 Free Software Foundation, Inc. | ||
3 | This file is part of the GNU C Library. | ||
4 | |||
5 | The GNU C Library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | The GNU C Library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with the GNU C Library; if not, write to the Free | ||
17 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | ||
18 | 02111-1307 USA. */ | ||
19 | |||
20 | /* | ||
21 | * My personal strstr() implementation that beats most other algorithms. | ||
22 | * Until someone tells me otherwise, I assume that this is the | ||
23 | * fastest implementation of strstr() in C. | ||
24 | * I deliberately chose not to comment it. You should have at least | ||
25 | * as much fun trying to understand it, as I had to write it :-). | ||
26 | * | ||
27 | * Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de*/ | ||
28 | |||
29 | /* Faster looping by precalculating bl, bu, cl, cu before looping. | ||
30 | * 2004 Apr 08 Jose Da Silva, digital@joescat@com */ | ||
31 | |||
32 | #include <string.h> | ||
33 | #include <ctype.h> | ||
34 | |||
35 | typedef unsigned chartype; | ||
36 | |||
37 | char* strcasestr (const char* phaystack, const char* pneedle) | ||
38 | { | ||
39 | const unsigned char *haystack, *needle; | ||
40 | chartype bl, bu, cl, cu; | ||
41 | |||
42 | haystack = (const unsigned char *) phaystack; | ||
43 | needle = (const unsigned char *) pneedle; | ||
44 | |||
45 | bl = tolower (*needle); | ||
46 | if (bl != '\0') | ||
47 | { | ||
48 | bu = toupper (bl); | ||
49 | haystack--;/* possible ANSI violation */ | ||
50 | do | ||
51 | { | ||
52 | cl = *++haystack; | ||
53 | if (cl == '\0') | ||
54 | goto ret0; | ||
55 | } | ||
56 | while ((cl != bl) && (cl != bu)); | ||
57 | |||
58 | cl = tolower (*++needle); | ||
59 | if (cl == '\0') | ||
60 | goto foundneedle; | ||
61 | cu = toupper (cl); | ||
62 | ++needle; | ||
63 | goto jin; | ||
64 | |||
65 | for (;;) | ||
66 | { | ||
67 | chartype a; | ||
68 | const unsigned char *rhaystack, *rneedle; | ||
69 | |||
70 | do | ||
71 | { | ||
72 | a = *++haystack; | ||
73 | if (a == '\0') | ||
74 | goto ret0; | ||
75 | if ((a == bl) || (a == bu)) | ||
76 | break; | ||
77 | a = *++haystack; | ||
78 | if (a == '\0') | ||
79 | goto ret0; | ||
80 | shloop: | ||
81 | ; | ||
82 | } | ||
83 | while ((a != bl) && (a != bu)); | ||
84 | |||
85 | jin: a = *++haystack; | ||
86 | if (a == '\0') | ||
87 | goto ret0; | ||
88 | |||
89 | if ((a != cl) && (a != cu)) | ||
90 | goto shloop; | ||
91 | |||
92 | rhaystack = haystack-- + 1; | ||
93 | rneedle = needle; | ||
94 | a = tolower (*rneedle); | ||
95 | |||
96 | if (tolower (*rhaystack) == (int) a) | ||
97 | do | ||
98 | { | ||
99 | if (a == '\0') | ||
100 | goto foundneedle; | ||
101 | ++rhaystack; | ||
102 | a = tolower (*++needle); | ||
103 | if (tolower (*rhaystack) != (int) a) | ||
104 | break; | ||
105 | if (a == '\0') | ||
106 | goto foundneedle; | ||
107 | ++rhaystack; | ||
108 | a = tolower (*++needle); | ||
109 | } | ||
110 | while (tolower (*rhaystack) == (int) a); | ||
111 | |||
112 | needle = rneedle;/* took the register-poor approach */ | ||
113 | |||
114 | if (a == '\0') | ||
115 | break; | ||
116 | } | ||
117 | } | ||
118 | foundneedle: | ||
119 | return (char*) haystack; | ||
120 | ret0: | ||
121 | return 0; | ||
122 | } | ||
diff --git a/firmware/include/string.h b/firmware/include/string.h index e9aa24c530..713a875698 100644 --- a/firmware/include/string.h +++ b/firmware/include/string.h | |||
@@ -40,6 +40,7 @@ char *_EXFUN(strpbrk,(const char *, const char *)); | |||
40 | char *_EXFUN(strrchr,(const char *, int)); | 40 | char *_EXFUN(strrchr,(const char *, int)); |
41 | size_t _EXFUN(strspn,(const char *, const char *)); | 41 | size_t _EXFUN(strspn,(const char *, const char *)); |
42 | char *_EXFUN(strstr,(const char *, const char *)); | 42 | char *_EXFUN(strstr,(const char *, const char *)); |
43 | char *_EXFUN(strcasestr,(const char *, const char *)); | ||
43 | 44 | ||
44 | #ifndef _REENT_ONLY | 45 | #ifndef _REENT_ONLY |
45 | char *_EXFUN(strtok,(char *, const char *)); | 46 | char *_EXFUN(strtok,(char *, const char *)); |