diff options
-rw-r--r-- | apps/debug_menu.c | 4 | ||||
-rw-r--r-- | apps/playlist_viewer.c | 9 | ||||
-rw-r--r-- | apps/screens.c | 10 | ||||
-rw-r--r-- | firmware/SOURCES | 1 | ||||
-rw-r--r-- | firmware/libc/include/string.h | 1 | ||||
-rw-r--r-- | firmware/libc/memccpy.c | 119 |
6 files changed, 139 insertions, 5 deletions
diff --git a/apps/debug_menu.c b/apps/debug_menu.c index 87a41920b9..0b0bc8fc2b 100644 --- a/apps/debug_menu.c +++ b/apps/debug_menu.c | |||
@@ -1627,7 +1627,9 @@ static int ata_smart_attr_to_string( | |||
1627 | if (len >= name_sz) len = name_sz-1; | 1627 | if (len >= name_sz) len = name_sz-1; |
1628 | slen += len; | 1628 | slen += len; |
1629 | } | 1629 | } |
1630 | snprintf(str+slen, size-slen, "%s", buf); | 1630 | |
1631 | if (!memccpy (str+slen, buf, '\0', size-slen)) | ||
1632 | (str+slen)[size-slen - 1] = '\0'; | ||
1631 | } | 1633 | } |
1632 | 1634 | ||
1633 | return 1; /* ok */ | 1635 | return 1; /* ok */ |
diff --git a/apps/playlist_viewer.c b/apps/playlist_viewer.c index d2774e67b0..f1f8954113 100644 --- a/apps/playlist_viewer.c +++ b/apps/playlist_viewer.c | |||
@@ -516,7 +516,10 @@ static enum pv_onplay_result open_with(const struct playlist_entry *current_trac | |||
516 | { | 516 | { |
517 | char selected_track[MAX_PATH]; | 517 | char selected_track[MAX_PATH]; |
518 | close_playlist_viewer(); | 518 | close_playlist_viewer(); |
519 | snprintf(selected_track, sizeof(selected_track), "%s", current_track->name); | 519 | |
520 | if (!memccpy (selected_track, current_track->name, '\0', sizeof(selected_track))) | ||
521 | selected_track[sizeof(selected_track) - 1] = '\0'; | ||
522 | |||
520 | 523 | ||
521 | return (filetype_list_viewers(selected_track) == | 524 | return (filetype_list_viewers(selected_track) == |
522 | PLUGIN_USB_CONNECTED ? PV_ONPLAY_USB_CLOSED : PV_ONPLAY_CLOSED); | 525 | PLUGIN_USB_CONNECTED ? PV_ONPLAY_USB_CLOSED : PV_ONPLAY_CLOSED); |
@@ -528,7 +531,9 @@ static enum pv_onplay_result open_pictureflow(const struct playlist_entry *curre | |||
528 | { | 531 | { |
529 | char selected_track[MAX_PATH]; | 532 | char selected_track[MAX_PATH]; |
530 | close_playlist_viewer(); | 533 | close_playlist_viewer(); |
531 | snprintf(selected_track, sizeof(selected_track), "%s", current_track->name); | 534 | |
535 | if (!memccpy (selected_track, current_track->name, '\0', sizeof(selected_track))) | ||
536 | selected_track[sizeof(selected_track) - 1] = '\0'; | ||
532 | 537 | ||
533 | return (filetype_load_plugin((void *)"pictureflow", selected_track) == | 538 | return (filetype_load_plugin((void *)"pictureflow", selected_track) == |
534 | PLUGIN_USB_CONNECTED ? PV_ONPLAY_USB_CLOSED : PV_ONPLAY_CLOSED); | 539 | PLUGIN_USB_CONNECTED ? PV_ONPLAY_USB_CLOSED : PV_ONPLAY_CLOSED); |
diff --git a/apps/screens.c b/apps/screens.c index 70374a1f08..9191922c31 100644 --- a/apps/screens.c +++ b/apps/screens.c | |||
@@ -561,7 +561,10 @@ static const char * id3_get_or_speak_info(int selected_item, void* data, | |||
561 | case LANG_ID3_COMMENT: | 561 | case LANG_ID3_COMMENT: |
562 | if (!id3->comment) | 562 | if (!id3->comment) |
563 | return NULL; | 563 | return NULL; |
564 | snprintf(buffer, buffer_len, "%s", id3->comment); | 564 | |
565 | if (!memccpy (buffer, id3->comment, '\0', buffer_len)) | ||
566 | buffer[buffer_len - 1] = '\0'; | ||
567 | |||
565 | val=buffer; | 568 | val=buffer; |
566 | if(say_it && val) | 569 | if(say_it && val) |
567 | talk_spell(val, true); | 570 | talk_spell(val, true); |
@@ -608,7 +611,10 @@ static const char * id3_get_or_speak_info(int selected_item, void* data, | |||
608 | case LANG_FORMAT: | 611 | case LANG_FORMAT: |
609 | if (id3->codectype >= AFMT_NUM_CODECS) | 612 | if (id3->codectype >= AFMT_NUM_CODECS) |
610 | return NULL; | 613 | return NULL; |
611 | snprintf(buffer, buffer_len, "%s", audio_formats[id3->codectype].label); | 614 | |
615 | if (!memccpy (buffer, audio_formats[id3->codectype].label, '\0', buffer_len)) | ||
616 | buffer[buffer_len - 1] = '\0'; | ||
617 | |||
612 | val=buffer; | 618 | val=buffer; |
613 | if(say_it) | 619 | if(say_it) |
614 | talk_spell(val, true); | 620 | talk_spell(val, true); |
diff --git a/firmware/SOURCES b/firmware/SOURCES index 76d6cee921..94a986c9f8 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES | |||
@@ -262,6 +262,7 @@ libc/ctype.c | |||
262 | libc/sprintf.c | 262 | libc/sprintf.c |
263 | #endif | 263 | #endif |
264 | 264 | ||
265 | libc/memccpy.c | ||
265 | libc/memchr.c | 266 | libc/memchr.c |
266 | libc/memcmp.c | 267 | libc/memcmp.c |
267 | 268 | ||
diff --git a/firmware/libc/include/string.h b/firmware/libc/include/string.h index 9815c62805..4ec2f8dd67 100644 --- a/firmware/libc/include/string.h +++ b/firmware/libc/include/string.h | |||
@@ -20,6 +20,7 @@ extern "C" { | |||
20 | _PTR _EXFUN(memchr,(const _PTR, int, size_t)); | 20 | _PTR _EXFUN(memchr,(const _PTR, int, size_t)); |
21 | int _EXFUN(memcmp,(const _PTR, const _PTR, size_t)); | 21 | int _EXFUN(memcmp,(const _PTR, const _PTR, size_t)); |
22 | _PTR _EXFUN(memcpy,(_PTR, const _PTR, size_t)); | 22 | _PTR _EXFUN(memcpy,(_PTR, const _PTR, size_t)); |
23 | _PTR _EXFUN(memccpy,(_PTR, const _PTR, int, size_t)); | ||
23 | _PTR _EXFUN(mempcpy,(_PTR, const _PTR, size_t)); | 24 | _PTR _EXFUN(mempcpy,(_PTR, const _PTR, size_t)); |
24 | _PTR _EXFUN(memmove,(_PTR, const _PTR, size_t)); | 25 | _PTR _EXFUN(memmove,(_PTR, const _PTR, size_t)); |
25 | _PTR _EXFUN(memset,(_PTR, int, size_t)); | 26 | _PTR _EXFUN(memset,(_PTR, int, size_t)); |
diff --git a/firmware/libc/memccpy.c b/firmware/libc/memccpy.c new file mode 100644 index 0000000000..fa9316616e --- /dev/null +++ b/firmware/libc/memccpy.c | |||
@@ -0,0 +1,119 @@ | |||
1 | /* | ||
2 | FUNCTION | ||
3 | <<memccpy>>---copy memory regions with end-token check | ||
4 | ANSI_SYNOPSIS | ||
5 | #include <string.h> | ||
6 | void* memccpy(void *restrict <[out]>, const void *restrict <[in]>, | ||
7 | int <[endchar]>, size_t <[n]>); | ||
8 | TRAD_SYNOPSIS | ||
9 | void *memccpy(<[out]>, <[in]>, <[endchar]>, <[n]> | ||
10 | void *<[out]>; | ||
11 | void *<[in]>; | ||
12 | int <[endchar]>; | ||
13 | size_t <[n]>; | ||
14 | DESCRIPTION | ||
15 | This function copies up to <[n]> bytes from the memory region | ||
16 | pointed to by <[in]> to the memory region pointed to by | ||
17 | <[out]>. If a byte matching the <[endchar]> is encountered, | ||
18 | the byte is copied and copying stops. | ||
19 | If the regions overlap, the behavior is undefined. | ||
20 | RETURNS | ||
21 | <<memccpy>> returns a pointer to the first byte following the | ||
22 | <[endchar]> in the <[out]> region. If no byte matching | ||
23 | <[endchar]> was copied, then <<NULL>> is returned. | ||
24 | PORTABILITY | ||
25 | <<memccpy>> is a GNU extension. | ||
26 | <<memccpy>> requires no supporting OS subroutines. | ||
27 | */ | ||
28 | #include <stddef.h> | ||
29 | #include <string.h> | ||
30 | #include <limits.h> | ||
31 | #include "_ansi.h" /* for _DEFUN */ | ||
32 | |||
33 | /* Nonzero if either X or Y is not aligned on a "long" boundary. */ | ||
34 | #define ROCKBOX_UNALIGNED(X, Y) \ | ||
35 | (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) | ||
36 | /* How many bytes are copied each iteration of the word copy loop. */ | ||
37 | #define LITTLEBLOCKSIZE (sizeof (long)) | ||
38 | /* Threshhold for punting to the byte copier. */ | ||
39 | #define TOO_SMALL(LEN) ((LEN) < LITTLEBLOCKSIZE) | ||
40 | /* Macros for detecting endchar */ | ||
41 | #if LONG_MAX == 2147483647L | ||
42 | #define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080) | ||
43 | #else | ||
44 | #if LONG_MAX == 9223372036854775807L | ||
45 | /* Nonzero if X (a long int) contains a NULL byte. */ | ||
46 | #define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080) | ||
47 | #else | ||
48 | #error long int is not a 32bit or 64bit type. | ||
49 | #endif | ||
50 | #endif | ||
51 | _PTR | ||
52 | _DEFUN (memccpy, (dst0, src0, endchar, len0), | ||
53 | _PTR __restrict dst0 _AND | ||
54 | _CONST _PTR __restrict src0 _AND | ||
55 | int endchar0 _AND | ||
56 | size_t len0) | ||
57 | { | ||
58 | #if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) | ||
59 | _PTR ptr = NULL; | ||
60 | char *dst = (char *) dst0; | ||
61 | char *src = (char *) src0; | ||
62 | char endchar = endchar0 & 0xff; | ||
63 | while (len0--) | ||
64 | { | ||
65 | if ((*dst++ = *src++) == endchar) | ||
66 | { | ||
67 | ptr = dst; | ||
68 | break; | ||
69 | } | ||
70 | } | ||
71 | return ptr; | ||
72 | #else | ||
73 | _PTR ptr = NULL; | ||
74 | char *dst = dst0; | ||
75 | _CONST char *src = src0; | ||
76 | long *aligned_dst; | ||
77 | _CONST long *aligned_src; | ||
78 | char endchar = endchar0 & 0xff; | ||
79 | /* If the size is small, or either SRC or DST is unaligned, | ||
80 | then punt into the byte copy loop. This should be rare. */ | ||
81 | if (!TOO_SMALL(len0) && !ROCKBOX_UNALIGNED (src, dst)) | ||
82 | { | ||
83 | unsigned int i; | ||
84 | unsigned long mask = 0; | ||
85 | aligned_dst = (long*)dst; | ||
86 | aligned_src = (long*)src; | ||
87 | /* The fast code reads the ASCII one word at a time and only | ||
88 | performs the bytewise search on word-sized segments if they | ||
89 | contain the search character, which is detected by XORing | ||
90 | the word-sized segment with a word-sized block of the search | ||
91 | character and then detecting for the presence of NULL in the | ||
92 | result. */ | ||
93 | for (i = 0; i < LITTLEBLOCKSIZE; i++) | ||
94 | mask = (mask << 8) + endchar; | ||
95 | /* Copy one long word at a time if possible. */ | ||
96 | while (len0 >= LITTLEBLOCKSIZE) | ||
97 | { | ||
98 | unsigned long buffer = (unsigned long)(*aligned_src); | ||
99 | buffer ^= mask; | ||
100 | if (DETECTNULL (buffer)) | ||
101 | break; /* endchar is found, go byte by byte from here */ | ||
102 | *aligned_dst++ = *aligned_src++; | ||
103 | len0 -= LITTLEBLOCKSIZE; | ||
104 | } | ||
105 | /* Pick up any residual with a byte copier. */ | ||
106 | dst = (char*)aligned_dst; | ||
107 | src = (char*)aligned_src; | ||
108 | } | ||
109 | while (len0--) | ||
110 | { | ||
111 | if ((*dst++ = *src++) == endchar) | ||
112 | { | ||
113 | ptr = dst; | ||
114 | break; | ||
115 | } | ||
116 | } | ||
117 | return ptr; | ||
118 | #endif /* not PREFER_SIZE_OVER_SPEED */ | ||
119 | } | ||