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