Kevin O'Connor | fa9c66a | 2013-09-14 19:10:40 -0400 | [diff] [blame] | 1 | // String manipulation functions. |
Kevin O'Connor | 9521e26 | 2008-07-04 13:04:29 -0400 | [diff] [blame] | 2 | // |
Kevin O'Connor | fa9c66a | 2013-09-14 19:10:40 -0400 | [diff] [blame] | 3 | // Copyright (C) 2008-2013 Kevin O'Connor <kevin@koconnor.net> |
Kevin O'Connor | 9521e26 | 2008-07-04 13:04:29 -0400 | [diff] [blame] | 4 | // |
Kevin O'Connor | b1b7c2a | 2009-01-15 20:52:58 -0500 | [diff] [blame] | 5 | // This file may be distributed under the terms of the GNU LGPLv3 license. |
Kevin O'Connor | 9521e26 | 2008-07-04 13:04:29 -0400 | [diff] [blame] | 6 | |
Kevin O'Connor | 3df600b | 2013-09-14 19:28:55 -0400 | [diff] [blame] | 7 | #include "stacks.h" // yield |
Kevin O'Connor | fa9c66a | 2013-09-14 19:10:40 -0400 | [diff] [blame] | 8 | #include "string.h" // memcpy |
| 9 | #include "farptr.h" // SET_SEG |
Kevin O'Connor | a5826b5 | 2009-10-24 17:57:29 -0400 | [diff] [blame] | 10 | |
Kevin O'Connor | 10ad799 | 2009-10-24 11:06:08 -0400 | [diff] [blame] | 11 | |
| 12 | /**************************************************************** |
Kevin O'Connor | 10ad799 | 2009-10-24 11:06:08 -0400 | [diff] [blame] | 13 | * String ops |
| 14 | ****************************************************************/ |
| 15 | |
Kevin O'Connor | 2e7ab8b | 2008-03-29 14:29:35 -0400 | [diff] [blame] | 16 | // Sum the bytes in the specified area. |
| 17 | u8 |
Kevin O'Connor | 94fd47e | 2009-02-15 15:21:10 -0500 | [diff] [blame] | 18 | checksum_far(u16 buf_seg, void *buf_far, u32 len) |
Kevin O'Connor | 2e7ab8b | 2008-03-29 14:29:35 -0400 | [diff] [blame] | 19 | { |
Kevin O'Connor | 8b267cb | 2009-01-19 19:25:21 -0500 | [diff] [blame] | 20 | SET_SEG(ES, buf_seg); |
Kevin O'Connor | 2e7ab8b | 2008-03-29 14:29:35 -0400 | [diff] [blame] | 21 | u32 i; |
| 22 | u8 sum = 0; |
| 23 | for (i=0; i<len; i++) |
Kevin O'Connor | 94fd47e | 2009-02-15 15:21:10 -0500 | [diff] [blame] | 24 | sum += GET_VAR(ES, ((u8*)buf_far)[i]); |
Kevin O'Connor | 2e7ab8b | 2008-03-29 14:29:35 -0400 | [diff] [blame] | 25 | return sum; |
| 26 | } |
| 27 | |
Kevin O'Connor | 8b267cb | 2009-01-19 19:25:21 -0500 | [diff] [blame] | 28 | u8 |
Kevin O'Connor | 94fd47e | 2009-02-15 15:21:10 -0500 | [diff] [blame] | 29 | checksum(void *buf, u32 len) |
Kevin O'Connor | 8b267cb | 2009-01-19 19:25:21 -0500 | [diff] [blame] | 30 | { |
| 31 | return checksum_far(GET_SEG(SS), buf, len); |
| 32 | } |
| 33 | |
Kevin O'Connor | 6782344 | 2009-04-13 14:14:51 -0400 | [diff] [blame] | 34 | size_t |
| 35 | strlen(const char *s) |
| 36 | { |
| 37 | if (__builtin_constant_p(s)) |
| 38 | return __builtin_strlen(s); |
| 39 | const char *p = s; |
| 40 | while (*p) |
| 41 | p++; |
| 42 | return p-s; |
| 43 | } |
| 44 | |
| 45 | // Compare two areas of memory. |
| 46 | int |
Kevin O'Connor | 38d1a34 | 2009-04-18 16:59:47 -0400 | [diff] [blame] | 47 | memcmp(const void *s1, const void *s2, size_t n) |
Kevin O'Connor | 6782344 | 2009-04-13 14:14:51 -0400 | [diff] [blame] | 48 | { |
| 49 | while (n) { |
| 50 | if (*(u8*)s1 != *(u8*)s2) |
Kevin O'Connor | 38d1a34 | 2009-04-18 16:59:47 -0400 | [diff] [blame] | 51 | return *(u8*)s1 < *(u8*)s2 ? -1 : 1; |
Kevin O'Connor | 6782344 | 2009-04-13 14:14:51 -0400 | [diff] [blame] | 52 | s1++; |
| 53 | s2++; |
| 54 | n--; |
| 55 | } |
Kevin O'Connor | 38d1a34 | 2009-04-18 16:59:47 -0400 | [diff] [blame] | 56 | return 0; |
Kevin O'Connor | 6782344 | 2009-04-13 14:14:51 -0400 | [diff] [blame] | 57 | } |
| 58 | |
Kevin O'Connor | 4c0c85a | 2009-04-11 23:31:29 -0400 | [diff] [blame] | 59 | // Compare two strings. |
| 60 | int |
Kevin O'Connor | 38d1a34 | 2009-04-18 16:59:47 -0400 | [diff] [blame] | 61 | strcmp(const char *s1, const char *s2) |
Kevin O'Connor | 4c0c85a | 2009-04-11 23:31:29 -0400 | [diff] [blame] | 62 | { |
| 63 | for (;;) { |
| 64 | if (*s1 != *s2) |
Kevin O'Connor | 38d1a34 | 2009-04-18 16:59:47 -0400 | [diff] [blame] | 65 | return *s1 < *s2 ? -1 : 1; |
Kevin O'Connor | 4c0c85a | 2009-04-11 23:31:29 -0400 | [diff] [blame] | 66 | if (! *s1) |
Kevin O'Connor | 38d1a34 | 2009-04-18 16:59:47 -0400 | [diff] [blame] | 67 | return 0; |
Kevin O'Connor | 4c0c85a | 2009-04-11 23:31:29 -0400 | [diff] [blame] | 68 | s1++; |
| 69 | s2++; |
| 70 | } |
| 71 | } |
| 72 | |
Kevin O'Connor | 5b199ac | 2009-05-06 23:23:01 -0400 | [diff] [blame] | 73 | inline void |
| 74 | memset_far(u16 d_seg, void *d_far, u8 c, size_t len) |
| 75 | { |
| 76 | SET_SEG(ES, d_seg); |
| 77 | asm volatile( |
| 78 | "rep stosb %%es:(%%di)" |
| 79 | : "+c"(len), "+D"(d_far) |
Kevin O'Connor | 41966da | 2012-05-28 18:57:06 -0400 | [diff] [blame] | 80 | : "a"(c), "m" (__segment_ES) |
Kevin O'Connor | 5b199ac | 2009-05-06 23:23:01 -0400 | [diff] [blame] | 81 | : "cc", "memory"); |
| 82 | } |
| 83 | |
| 84 | inline void |
| 85 | memset16_far(u16 d_seg, void *d_far, u16 c, size_t len) |
| 86 | { |
| 87 | len /= 2; |
| 88 | SET_SEG(ES, d_seg); |
| 89 | asm volatile( |
| 90 | "rep stosw %%es:(%%di)" |
| 91 | : "+c"(len), "+D"(d_far) |
Kevin O'Connor | 41966da | 2012-05-28 18:57:06 -0400 | [diff] [blame] | 92 | : "a"(c), "m" (__segment_ES) |
Kevin O'Connor | 5b199ac | 2009-05-06 23:23:01 -0400 | [diff] [blame] | 93 | : "cc", "memory"); |
| 94 | } |
| 95 | |
Kevin O'Connor | 5e4235f | 2008-04-12 09:00:04 -0400 | [diff] [blame] | 96 | void * |
Kevin O'Connor | 567e4e3 | 2008-04-05 11:37:51 -0400 | [diff] [blame] | 97 | memset(void *s, int c, size_t n) |
| 98 | { |
| 99 | while (n) |
| 100 | ((char *)s)[--n] = c; |
Kevin O'Connor | 5e4235f | 2008-04-12 09:00:04 -0400 | [diff] [blame] | 101 | return s; |
Kevin O'Connor | 567e4e3 | 2008-04-05 11:37:51 -0400 | [diff] [blame] | 102 | } |
| 103 | |
Gerd Hoffmann | 0a80608 | 2010-11-29 09:42:11 +0100 | [diff] [blame] | 104 | void memset_fl(void *ptr, u8 val, size_t size) |
| 105 | { |
| 106 | if (MODESEGMENT) |
| 107 | memset_far(FLATPTR_TO_SEG(ptr), (void*)(FLATPTR_TO_OFFSET(ptr)), |
| 108 | val, size); |
| 109 | else |
| 110 | memset(ptr, val, size); |
| 111 | } |
| 112 | |
Kevin O'Connor | 8b267cb | 2009-01-19 19:25:21 -0500 | [diff] [blame] | 113 | inline void |
| 114 | memcpy_far(u16 d_seg, void *d_far, u16 s_seg, const void *s_far, size_t len) |
Kevin O'Connor | 567e4e3 | 2008-04-05 11:37:51 -0400 | [diff] [blame] | 115 | { |
Kevin O'Connor | 8b267cb | 2009-01-19 19:25:21 -0500 | [diff] [blame] | 116 | SET_SEG(ES, d_seg); |
| 117 | u16 bkup_ds; |
| 118 | asm volatile( |
| 119 | "movw %%ds, %w0\n" |
| 120 | "movw %w4, %%ds\n" |
| 121 | "rep movsb (%%si),%%es:(%%di)\n" |
Kevin O'Connor | 5b199ac | 2009-05-06 23:23:01 -0400 | [diff] [blame] | 122 | "movw %w0, %%ds" |
Kevin O'Connor | 8b267cb | 2009-01-19 19:25:21 -0500 | [diff] [blame] | 123 | : "=&r"(bkup_ds), "+c"(len), "+S"(s_far), "+D"(d_far) |
Kevin O'Connor | 41966da | 2012-05-28 18:57:06 -0400 | [diff] [blame] | 124 | : "r"(s_seg), "m" (__segment_ES) |
Kevin O'Connor | 8b267cb | 2009-01-19 19:25:21 -0500 | [diff] [blame] | 125 | : "cc", "memory"); |
Kevin O'Connor | 567e4e3 | 2008-04-05 11:37:51 -0400 | [diff] [blame] | 126 | } |
| 127 | |
Kevin O'Connor | 8f59aa3 | 2010-06-06 16:11:45 -0400 | [diff] [blame] | 128 | inline void |
| 129 | memcpy_fl(void *d_fl, const void *s_fl, size_t len) |
| 130 | { |
| 131 | if (MODESEGMENT) |
| 132 | memcpy_far(FLATPTR_TO_SEG(d_fl), (void*)FLATPTR_TO_OFFSET(d_fl) |
| 133 | , FLATPTR_TO_SEG(s_fl), (void*)FLATPTR_TO_OFFSET(s_fl) |
| 134 | , len); |
| 135 | else |
| 136 | memcpy(d_fl, s_fl, len); |
| 137 | } |
| 138 | |
Kevin O'Connor | 942d495 | 2009-06-10 22:44:06 -0400 | [diff] [blame] | 139 | void * |
| 140 | #undef memcpy |
| 141 | memcpy(void *d1, const void *s1, size_t len) |
Kevin O'Connor | 52a300f | 2009-12-26 23:32:57 -0500 | [diff] [blame] | 142 | #if MODESEGMENT == 0 |
Kevin O'Connor | 942d495 | 2009-06-10 22:44:06 -0400 | [diff] [blame] | 143 | #define memcpy __builtin_memcpy |
Kevin O'Connor | 5a1d0fc | 2009-06-15 23:35:30 -0400 | [diff] [blame] | 144 | #endif |
Kevin O'Connor | 18b927e | 2008-08-29 21:14:36 -0400 | [diff] [blame] | 145 | { |
Kevin O'Connor | 5a1d0fc | 2009-06-15 23:35:30 -0400 | [diff] [blame] | 146 | SET_SEG(ES, GET_SEG(SS)); |
Kevin O'Connor | 942d495 | 2009-06-10 22:44:06 -0400 | [diff] [blame] | 147 | void *d = d1; |
| 148 | if (((u32)d1 | (u32)s1 | len) & 3) { |
| 149 | // non-aligned memcpy |
| 150 | asm volatile( |
| 151 | "rep movsb (%%esi),%%es:(%%edi)" |
| 152 | : "+c"(len), "+S"(s1), "+D"(d) |
Kevin O'Connor | 41966da | 2012-05-28 18:57:06 -0400 | [diff] [blame] | 153 | : "m" (__segment_ES) : "cc", "memory"); |
Kevin O'Connor | 942d495 | 2009-06-10 22:44:06 -0400 | [diff] [blame] | 154 | return d1; |
| 155 | } |
| 156 | // Common case - use 4-byte copy |
Kevin O'Connor | 5d7b3f6 | 2009-04-19 20:05:50 -0400 | [diff] [blame] | 157 | len /= 4; |
| 158 | asm volatile( |
Kevin O'Connor | 5b199ac | 2009-05-06 23:23:01 -0400 | [diff] [blame] | 159 | "rep movsl (%%esi),%%es:(%%edi)" |
Kevin O'Connor | 942d495 | 2009-06-10 22:44:06 -0400 | [diff] [blame] | 160 | : "+c"(len), "+S"(s1), "+D"(d) |
Kevin O'Connor | 41966da | 2012-05-28 18:57:06 -0400 | [diff] [blame] | 161 | : "m" (__segment_ES) : "cc", "memory"); |
Kevin O'Connor | 942d495 | 2009-06-10 22:44:06 -0400 | [diff] [blame] | 162 | return d1; |
Kevin O'Connor | 18b927e | 2008-08-29 21:14:36 -0400 | [diff] [blame] | 163 | } |
| 164 | |
Kevin O'Connor | b4525a0 | 2010-07-27 01:14:11 -0400 | [diff] [blame] | 165 | // Copy to/from memory mapped IO. IO mem is very slow, so yield |
| 166 | // periodically. |
Kevin O'Connor | 3403696 | 2009-12-05 18:51:53 -0500 | [diff] [blame] | 167 | void |
| 168 | iomemcpy(void *d, const void *s, u32 len) |
| 169 | { |
Kevin O'Connor | 41966da | 2012-05-28 18:57:06 -0400 | [diff] [blame] | 170 | ASSERT32FLAT(); |
Kevin O'Connor | 3403696 | 2009-12-05 18:51:53 -0500 | [diff] [blame] | 171 | yield(); |
Kevin O'Connor | b4525a0 | 2010-07-27 01:14:11 -0400 | [diff] [blame] | 172 | while (len > 3) { |
Kevin O'Connor | 3403696 | 2009-12-05 18:51:53 -0500 | [diff] [blame] | 173 | u32 copylen = len; |
Kevin O'Connor | ad90159 | 2009-12-13 11:25:25 -0500 | [diff] [blame] | 174 | if (copylen > 2048) |
| 175 | copylen = 2048; |
Kevin O'Connor | 3403696 | 2009-12-05 18:51:53 -0500 | [diff] [blame] | 176 | copylen /= 4; |
Kevin O'Connor | b4525a0 | 2010-07-27 01:14:11 -0400 | [diff] [blame] | 177 | len -= copylen * 4; |
Kevin O'Connor | 3403696 | 2009-12-05 18:51:53 -0500 | [diff] [blame] | 178 | asm volatile( |
| 179 | "rep movsl (%%esi),%%es:(%%edi)" |
| 180 | : "+c"(copylen), "+S"(s), "+D"(d) |
| 181 | : : "cc", "memory"); |
| 182 | yield(); |
| 183 | } |
Kevin O'Connor | b4525a0 | 2010-07-27 01:14:11 -0400 | [diff] [blame] | 184 | if (len) |
| 185 | // Copy any remaining bytes. |
| 186 | memcpy(d, s, len); |
Kevin O'Connor | 3403696 | 2009-12-05 18:51:53 -0500 | [diff] [blame] | 187 | } |
| 188 | |
Kevin O'Connor | 18b927e | 2008-08-29 21:14:36 -0400 | [diff] [blame] | 189 | void * |
Kevin O'Connor | c781293 | 2008-06-08 23:08:12 -0400 | [diff] [blame] | 190 | memmove(void *d, const void *s, size_t len) |
| 191 | { |
| 192 | if (s >= d) |
| 193 | return memcpy(d, s, len); |
| 194 | |
| 195 | d += len-1; |
| 196 | s += len-1; |
| 197 | while (len--) { |
| 198 | *(char*)d = *(char*)s; |
| 199 | d--; |
| 200 | s--; |
| 201 | } |
| 202 | |
| 203 | return d; |
| 204 | } |
Kevin O'Connor | 9f4e1d9 | 2009-02-08 15:44:08 -0500 | [diff] [blame] | 205 | |
Kevin O'Connor | 71f036d | 2009-02-08 16:57:22 -0500 | [diff] [blame] | 206 | // Copy a string - truncating it if necessary. |
| 207 | char * |
| 208 | strtcpy(char *dest, const char *src, size_t len) |
| 209 | { |
| 210 | char *d = dest; |
Kevin O'Connor | dac46b1 | 2010-02-17 22:49:01 -0500 | [diff] [blame] | 211 | while (--len && *src != '\0') |
Kevin O'Connor | 71f036d | 2009-02-08 16:57:22 -0500 | [diff] [blame] | 212 | *d++ = *src++; |
| 213 | *d = '\0'; |
| 214 | return dest; |
| 215 | } |
| 216 | |
Kevin O'Connor | 2e109a6 | 2010-12-24 10:39:32 -0500 | [diff] [blame] | 217 | // locate first occurance of character c in the string s |
| 218 | char * |
| 219 | strchr(const char *s, int c) |
| 220 | { |
| 221 | for (; *s; s++) |
| 222 | if (*s == c) |
| 223 | return (char*)s; |
| 224 | return NULL; |
| 225 | } |
Kevin O'Connor | 10ad799 | 2009-10-24 11:06:08 -0400 | [diff] [blame] | 226 | |
Kevin O'Connor | 9e881a3 | 2011-01-08 12:06:54 -0500 | [diff] [blame] | 227 | // Remove any trailing blank characters (spaces, new lines, carriage returns) |
Kevin O'Connor | d15b010 | 2014-01-31 19:38:36 -0500 | [diff] [blame] | 228 | char * |
Kevin O'Connor | 9e881a3 | 2011-01-08 12:06:54 -0500 | [diff] [blame] | 229 | nullTrailingSpace(char *buf) |
| 230 | { |
| 231 | int len = strlen(buf); |
| 232 | char *end = &buf[len-1]; |
| 233 | while (end >= buf && *end <= ' ') |
| 234 | *(end--) = '\0'; |
Kevin O'Connor | d15b010 | 2014-01-31 19:38:36 -0500 | [diff] [blame] | 235 | while (*buf && *buf <= ' ') |
| 236 | buf++; |
| 237 | return buf; |
Kevin O'Connor | 9e881a3 | 2011-01-08 12:06:54 -0500 | [diff] [blame] | 238 | } |