mmlib/mmat: replace some variables by literal constants
[mmondor.git] / mmsoftware / mmlib / mmstring.c
1 /* $Id: mmstring.c,v 1.32 2007/12/05 23:47:56 mmondor Exp $ */
2
3 /*
4 * Copyright (C) 1989-2004, Matthew Mondor
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Matthew Mondor.
18 * 4. The name of Matthew Mondor may not be used to endorse or promote
19 * products derived from this software without specific prior written
20 * permission.
21 * 5. Redistribution of source code may not be released under the terms of
22 * any GNU Public License derivate.
23 *
24 * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 /* XXX Implement mm_strstr() */
37
38 /* A main reason for providing my string library is that as most mmsoftware
39 * is security-aware, and some implementations vary, it is safer. A popular
40 * example is strn*() functions which are not always implemented properly
41 * on some libc's. I even once stumbled on some bogus strlen() which used
42 * some 4-bytes hackery in a wrong way. Moreover, some memmov()/memcpy()
43 * implementations behavior is not right. So let's not worry too much about
44 * each CPU cycle, but rather about preventing buffer overflow opportunities,
45 * and producing consistant code. But let's still code these functions in a
46 * way to remain reasonably fast.
47 */
48
49
50 #include <stdbool.h>
51 #include <stdint.h>
52 #include <stdlib.h>
53
54 #include <mmtypes.h>
55 #include <mmstring.h>
56
57
58 MMCOPYRIGHT("@(#) Copyright (c) 1989-2004\n\
59 \tMatthew Mondor. All rights reserved.\n");
60 MMRCSID("$Id: mmstring.c,v 1.32 2007/12/05 23:47:56 mmondor Exp $");
61
62
63 static const unsigned char toupper_table[] = {
64 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
65 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13,
66 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
67 0x1E, 0x1F, ' ', '!', '"', '#', '$', '%', '&', 0x27,
68 '(', ')', '*', '+', ',', '-', '.', '/', '0', '1',
69 '2', '3', '4', '5', '6', '7', '8', '9', ':', ';',
70 '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E',
71 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
72 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
73 'Z', '[', 0x5C, ']', '^', '_', '`', 'A', 'B', 'C',
74 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
75 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
76 'X', 'Y', 'Z', '{', '|', '}', '~', 0x7F, 0x80, 0x81,
77 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B,
78 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95,
79 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
80 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9,
81 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3,
82 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD,
83 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
84 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1,
85 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB,
86 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5,
87 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
88 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9,
89 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
90 };
91
92 static const unsigned char tolower_table[] = {
93 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
94 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13,
95 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
96 0x1E, 0x1F, ' ', '!', '"', '#', '$', '%', '&', 0x27,
97 '(', ')', '*', '+', ',', '-', '.', '/', '0', '1',
98 '2', '3', '4', '5', '6', '7', '8', '9', ':', ';',
99 '<', '=', '>', '?', '@', 'a', 'b', 'c', 'd', 'e',
100 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
101 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
102 'z', '[', 0x5C, ']', '^', '_', '`', 'a', 'b', 'c',
103 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
104 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
105 'x', 'y', 'z', '{', '|', '}', '~', 0x7F, 0x80, 0x81,
106 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B,
107 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95,
108 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
109 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9,
110 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3,
111 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD,
112 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
113 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1,
114 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB,
115 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5,
116 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
117 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9,
118 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
119 };
120
121
122 /* Splits columns of a string delimited by spaces and/or tabs, and fills
123 * char **argv with pointers to each column. Returns the number of columns
124 * that could be filled in. The supplied string IS modified.
125 */
126 int
127 mm_straspl(char **argv, char *str, int maxcols)
128 {
129 register char *ptr, *ptr2;
130 int col;
131
132 for (ptr = str, col = 0; *ptr != '\0' && col < maxcols; ) {
133 for (; *ptr == ' ' || *ptr == '\t'; ptr++) ;
134 if (*ptr != '\0') {
135 for (ptr2 = ptr; *ptr != '\0' && *ptr != ' ' && *ptr != '\t';
136 ptr++) ;
137 if (ptr != ptr2) {
138 if (*ptr != '\0')
139 *ptr++ = '\0';
140 argv[col++] = ptr2;
141 } else
142 break;
143 } else
144 break;
145 }
146
147 return col;
148 }
149
150
151 /* Similar to mm_straspl() but supports single quote-enclosed multiword
152 * strings. We also consider '\r' and '\n' as an EOL indicator, and return -1
153 * on error (unclosed quote). This function is most useful to parse command
154 * lines.
155 */
156 int
157 mm_strasplq(char **argv, char *str, int maxcols)
158 {
159 register char *ptr, *sptr;
160 int col;
161 bool quoted;
162
163 for (ptr = str, col = 0;
164 *ptr != '\0' && *ptr != '\n' && *ptr != '\r' && col < maxcols; ) {
165 for (; *ptr == ' ' || *ptr == '\t'; ptr++) ;
166 if (*ptr != '\0' && *ptr != '\n' && *ptr != '\r') {
167 if (*ptr == '\'') {
168 quoted = true;
169 ptr++;
170 } else
171 quoted = false;
172 for (sptr = ptr; *ptr != '\0' && *ptr != '\n' && *ptr != '\r' &&
173 ((!quoted && *ptr != ' ' && *ptr != '\t') ||
174 (quoted && *ptr != '\'')); ptr++) ;
175 if (quoted && *ptr != '\'')
176 return -1;
177 if (ptr != sptr) {
178 if (*ptr != '\0') {
179 if (*ptr != '\n' && *ptr != '\r')
180 *ptr++ = '\0';
181 else
182 *ptr = '\0';
183 }
184 argv[col++] = sptr;
185 } else
186 break;
187 }
188 }
189
190 return col;
191 }
192
193
194 /* Parses the supplied command line <cmd>, of which the first word/element
195 * is expected to contain the absolute fullpath of an executable. Following
196 * may be optional arguments. On success, true is returned, and the executable
197 * fullpath is set in <path>, the arguments in <argv>, as well as the argument
198 * count in <argc> (which includes the first argument, argv[0] which consists
199 * of the executable name (without the directory elements)).
200 * Very useful prior to using execve(2).
201 * false is returned if a parsing error occurs (mismatched quote,
202 * first element not an absolute fullpath, etc) in which case the supplied
203 * pointers and <cmd> should be considered in an undefined state.
204 * <cmd> is modified, and the pointers will point to locations within it.
205 * It is thus advised to duplicate the command string as necessary.
206 * A maximum of <max> entries in argv will be allowed (including argv[0] and
207 * terminating NULL), which means that it at least should be 2.
208 */
209 bool
210 mm_cmdparse(char **path, int *argc, char **argv, char *cmd, int max)
211 {
212 int i;
213 register char *ptr;
214
215 /* Not enough space in argv? */
216 if (max < 2)
217 return false;
218 /* Failed parsing (unmatched quote?) */
219 if ((i = mm_strasplq(argv, cmd, max - 1)) == -1)
220 return false;
221 /* Command not an absolute fullpath? */
222 if (*argv[0] != '/')
223 return false;
224
225 *argc = i;
226 argv[i] = NULL;
227 *path = argv[0];
228
229 /* Find end of command */
230 for (ptr = *path; *ptr != '\0'; ptr++) ;
231 /* Find last '/' in command */
232 for (; ptr > *path && *ptr != '/'; ptr--) ;
233 /* If only '/' is at first column, no command specified, return false.
234 * Otherwise, split command at last '/' and set argv[0] to command.
235 */
236 if (ptr == *path || *(++ptr) == '\0')
237 return false;
238 argv[0] = ptr;
239
240 return true;
241 }
242
243
244 /* XXX Unlike ANSI, returns pointer at end of destination rather to beginning
245 * to allow special optimizations in loops.
246 */
247 char *
248 mm_strcat(char *dest, const char *src)
249 {
250 for (; *dest != '\0'; dest++) ;
251 for (; (*dest = *src++) != '\0'; dest++) ;
252
253 return (dest);
254 }
255
256
257 #ifdef MMSTRING_OBSOLETE
258 char *
259 mm_strchr(const char *str, int c)
260 {
261 for (; *str != '\0' && *str != c; str++) ;
262
263 return (*str != '\0' ? (char *)str : NULL);
264 }
265
266 int
267 mm_strcmp(const char *s1, const char *s2)
268 {
269 for (; *s1 != '\0' && *s2 != '\0' && *s1 == *s2; s1++, s2++) ;
270
271 return ((int)((const unsigned char)*s1 - (const unsigned char)*s2));
272 }
273 #endif
274
275
276 /* XXX Unlike standard strcpy(), returns pointer to end of copied string in
277 * destination, rather than to beginning, more useful to optimize some loops.
278 * This variant should never be called strcpy() (i.e., could be called
279 * _strcpy() however).
280 */
281 char *
282 mm_strcpy(char *dest, const char *src)
283 {
284 for (; (*dest = *src++) != '\0'; dest++) ;
285
286 return (dest);
287 }
288
289
290 /* XXX Should be mm_strdup() but then conflicts with libmm! */
291 #ifdef MMSTRING_OBSOLETE
292 char *
293 _mm_strdup(const char *str)
294 {
295 char *new;
296 register const char *ptr;
297 register size_t len;
298
299 for (new = NULL, ptr = str; *ptr != '\0'; ptr++) ;
300
301 len = (size_t)(ptr - str) + 1;
302 if ((new = malloc(len)) != NULL)
303 (void) mm_memcpy(new, str, len);
304
305 return new;
306 }
307
308 int
309 mm_strcasecmp(const char *s1, const char *s2)
310 {
311 register const unsigned char *us1, *us2;
312 register unsigned char cs1, cs2;
313
314 for (us1 = (const unsigned char *)s1, us2 = (const unsigned char *)s2,
315 cs1 = tolower_table[(int)*us1], cs2 = tolower_table[(int)*us2];
316 cs1 != '\0' && cs2 != '\0' &&
317 (cs1 = tolower_table[(int)*us1]) ==
318 (cs2 = tolower_table[(int)*us2]);
319 us1++, us2++) ;
320
321 return ((int)(cs1 - cs2));
322 }
323
324 size_t mm_strlen(const char *str)
325 {
326 register const char *ptr = str;
327
328 /* Although this causes ptr to be increased even when 0 is reached,
329 * compilers generally generate better code.
330 * i.e. GCC2-m68k: tstb %a0@+ vs tstb %a0@ and addql #1, %a0
331 * Matt
332 */
333 while (*ptr++ != '\0') ;
334
335 /* Don't forget to substract 1 */
336 return ((size_t)((ptr - 1) - str));
337 }
338 #endif
339
340
341 /* XXX Unlike ANSI, returns pointer at end of destination rather to beginning
342 * to allow special optimizations in loops.
343 */
344 char *
345 mm_strncat(char *dest, const char *src, size_t max)
346 {
347 if (max != 0) {
348 register const char *toptr;
349
350 for (toptr = dest, toptr += max; dest < toptr && *dest != '\0';
351 dest++) ;
352 for (; dest < toptr && (*dest = *src++) != '\0'; dest++) ;
353 if (dest < toptr)
354 *dest = '\0';
355 }
356
357 return dest;
358 }
359
360
361 char *
362 mm_strnchr(const char *str, int c, size_t max)
363 {
364 if (max > 0) {
365 register const char *toptr;
366
367 for (toptr = str, toptr += max;
368 str < toptr && *str != '\0' && (int)*str != c; str++) ;
369
370 if (str == toptr || *str == '\0')
371 return NULL;
372
373 return (char *)str;
374 }
375
376 return NULL;
377 }
378
379 #ifdef MMSTRING_OBSOLETE
380 int
381 mm_strncmp(const char *s1, const char *s2, size_t max)
382 {
383 if (max > 0) {
384 register const char *toptr;
385
386 for (toptr = s1, toptr += max; s1 < toptr && *s1 != '\0' &&
387 *s2 != '\0' && *s1 == *s2; s1++, s2++) ;
388
389 return (s1 < toptr ?
390 ((int)((const unsigned char)*s1 - (const unsigned char)*s2)) :
391 0);
392 }
393
394 return 0;
395 }
396 #endif
397
398
399 /* XXX This function, unlike the useless return code of the standard ANSI one,
400 * returns the number of characters successfully copied (without the NUL).
401 * Moreover, this implementation ALWAYS NUL-terminates the resulting string,
402 * even if the output exceeded the buffer in which case the results are
403 * truncated. This is much better for security-critical applications.
404 */
405 size_t
406 mm_strncpy(char *dest, const char *src, size_t max)
407 {
408 if (max > 0) {
409 register const char *sptr;
410 register char *toptr;
411
412 for (sptr = src, toptr = dest, toptr += max;
413 dest < toptr && (*dest = *sptr) != '\0'; sptr++, dest++) ;
414 if (dest == toptr)
415 *dest = '\0';
416
417 return ((size_t)(sptr - src));
418 }
419
420 *dest = '\0';
421 return 0;
422 }
423
424 #ifdef MMSTRING_OBSOLETE
425 char *
426 mm_strndup(const char *str, size_t max)
427 {
428 char *new;
429 register const char *ptr, *toptr;
430 size_t len;
431
432 for (toptr = ptr = str, toptr += max, new = NULL;
433 ptr < toptr && *ptr != '\0'; ptr++) ;
434 len = (size_t)(ptr - str);
435 if ((new = malloc(len + 1)) != NULL) {
436 (void) mm_memcpy(new, str, len);
437 new[len] = '\0';
438 }
439
440 return new;
441 }
442
443 int
444 mm_strncasecmp(const char *s1, const char *s2, size_t max)
445 {
446 register const unsigned char *us1, *us2, *toptr;
447 register unsigned char cs1, cs2;
448
449 if (max == 0)
450 return 0;
451
452 for (us1 = (const unsigned char *)s1, us2 = (const unsigned char *)s2,
453 cs1 = tolower_table[(int)*us1], cs2 = tolower_table[(int)*us2],
454 toptr = us1, toptr += max;
455 us1 < toptr && cs1 != '\0' && cs2 != '\0' &&
456 (cs1 = tolower_table[(int)*us1]) ==
457 (cs2 = tolower_table[(int)*us2]);
458 us1++, us2++) ;
459
460 return (us1 < toptr ? ((int)(cs1 - cs2)) : 0);
461 }
462
463 #endif
464
465 size_t
466 mm_strnlen(const char *str, size_t max)
467 {
468 register const char *fptr, *tptr;
469
470 for (fptr = tptr = str, tptr += max; fptr < tptr && *fptr != '\0'; fptr++)
471 ;
472
473 return ((size_t)(fptr - str));
474 }
475
476
477 char *
478 mm_strnrchr(const char *str, int c, size_t max)
479 {
480 register const char *toptr, *found;
481
482 for (found = NULL, toptr = str, toptr += max;
483 str < toptr && *str != '\0'; str++) {
484 if (*str == c)
485 found = str;
486 }
487
488 return (char *)found;
489 }
490
491 #ifdef MMSTRING_OBSOLETE
492 char *
493 mm_strrchr(const char *str, int c)
494 {
495 register const char *found;
496
497 for (found = NULL; *str != '\0'; str++) {
498 if (*str == c)
499 found = str;
500 }
501
502 return (char *)found;
503 }
504 #endif
505
506
507 /* Splits columns of a string delimited by sep, and fills
508 * char **argv with pointers to each column. Returns the number of columns
509 * that could be filled in. The supplied string IS modified. Note that two
510 * contiguous separators cause empty entries to be filled in. An exception
511 * consists of the last separator, which is ignored if nothing is found after
512 * it.
513 */
514 int
515 mm_strspl(char **argv, char *str, int maxcols, char sep)
516 {
517 register char *ptr, *ptr2;
518 int col;
519
520 for (col = 0, ptr = str; *ptr != '\0' && col < maxcols; ) {
521 for (ptr2 = ptr; *ptr != '\0' && *ptr != sep; ptr++) ;
522 if (*ptr != '\0')
523 *ptr++ = '\0';
524 argv[col++] = ptr2;
525 }
526
527 return col;
528 }
529
530
531 void
532 mm_strlower(char *str)
533 {
534 register unsigned char *ustr;
535
536 for (ustr = (unsigned char *)str; *ustr != '\0'; ustr++)
537 *ustr = tolower_table[(int)*ustr];
538 }
539
540
541 void
542 mm_strupper(char *str)
543 {
544 register unsigned char *ustr;
545
546 for (ustr = (unsigned char *)str; *ustr != '\0'; ustr++)
547 *ustr = toupper_table[(int)*ustr];
548 }
549
550
551 /* This function generates a 32-bit hash using the supplied string which
552 * is suitable for fast lookup for command comparision. It simply converts
553 * characters to uppercase and stores them in the value. It of course can
554 * only perform this for 4 bytes. It will stop at either end of string '\0'
555 * or space ' '. If the string has more than 4 characters 0 is returned.
556 */
557 uint32_t
558 mm_strpack32(const char *str, size_t min)
559 {
560 register unsigned const char *ustr;
561 register uint32_t hash = 0;
562 size_t i;
563
564 for (ustr = (unsigned const char *)str, i = 0; *ustr > 32 && i < 5; i++) {
565 hash <<= 8;
566 hash |= toupper_table[(int)*ustr++];
567 }
568 if (i < min || i > 4)
569 hash = 0;
570
571 return hash;
572 }
573
574
575 unsigned long
576 mm_htol(const char *s)
577 {
578 register unsigned long v;
579
580 for (v = 0; *s != '\0'; ) {
581 if (*s >= '0' && *s <= '9') {
582 if (v <= (unsigned short)-1)
583 v = (unsigned short)v * 16;
584 else
585 v = v * 16;
586 v += *s++ - '0';
587 } else if (*s >= 'a' && *s <= 'f') {
588 if (v <= (unsigned short)-1)
589 v = (unsigned short)v * 16;
590 else
591 v = v * 16;
592 v += *s++ - 87;
593 } else if (*s >= 'A' && *s <= 'F') {
594 if (v <= (unsigned short)-1)
595 v = (unsigned short)v * 16;
596 else
597 v = v * 16;
598 v += *s++ - 55;
599 } else
600 break;
601 }
602
603 return v;
604 }
605
606
607 void
608 mm_strrev(char *str)
609 {
610 register char *p1, *p2, t;
611
612 for (p1 = p2 = str; *p2 != '\0'; p2++) ;
613 if (p2 > p1)
614 p2--;
615
616 for (;p1 < p2; p1++, p2--) {
617 t = *p1;
618 *p1 = *p2;
619 *p2 = t;
620 }
621 }
622
623 void
624 mm_strrevto(char *dst, const char *src)
625 {
626 register const char *p;
627
628 for (p = src; *p != '\0'; p++) ;
629
630 while (p >= src)
631 *dst++ = *--p;
632
633 *dst = '\0';
634 }
635
636
637 /* This hash function should be pretty safe as it was tested to not cause
638 * duplicates on:
639 * locate '*'
640 * cat /usr/share/dict/words
641 * XXX Could be unrolled a little
642 */
643 uint64_t
644 mm_strhash64(const char *str)
645 {
646 uint64_t hash;
647 register const unsigned char *ptr;
648
649 for (hash = 0, ptr = (const unsigned char *)str; *ptr != '\0'; ptr++)
650 hash = *ptr + (2818937311llu * hash);
651
652 return hash;
653 }
654
655
656 /* Variant of hash64 on memory buffer */
657 uint64_t
658 mm_memhash64(const void *mem, size_t size)
659 {
660 uint64_t hash;
661 register const unsigned char *curmem, *tomem;
662
663 for (hash = 0, curmem = tomem = (const unsigned char *)mem, tomem += size;
664 curmem < tomem; curmem++)
665 hash = *curmem + (2818937311llu * hash);
666
667 return hash;
668 }
669
670
671 uint32_t
672 mm_memhash32(const void *mem, size_t size)
673 {
674 register uint32_t hash;
675 register const unsigned char *curmem, *tomem;
676
677 hash = 0;
678 curmem = tomem = mem;
679 tomem += size;
680
681 #if !defined(ARCH_LOWCACHE)
682 while (curmem < tomem - 4) {
683 #if !defined(ARCH_USEINDEXING)
684 hash = *curmem++ + (31 * hash);
685 hash = *curmem++ + (31 * hash);
686 hash = *curmem++ + (31 * hash);
687 hash = *curmem++ + (31 * hash);
688 #else /* !defined(ARCH_USEINDEXING) */
689 hash = curmem[0] + (31 * hash);
690 hash = curmem[1] + (31 * hash);
691 hash = curmem[2] + (31 * hash);
692 hash = curmem[3] + (31 * hash);
693 curmem += 4;
694 #endif /* !defined(ARCH_USEINDEXING) */
695 }
696 #endif /* !defined(ARCH_LOWCACHE) */
697 while (curmem < tomem)
698 hash = *curmem++ + (31 * hash);
699
700 return hash;
701 }
702
703
704 /* These functions are useful to use in conjunction with mmhash(3) if
705 * case-insensitive processing of data is required while case-sensitivity of
706 * records storage must be preserved.
707 */
708
709 uint32_t
710 mm_memcasehash32(const void *mem, size_t size)
711 {
712 register uint32_t hash;
713 register const unsigned char *curmem, *tomem;
714
715 hash = 0;
716 curmem = tomem = mem;
717 tomem += size;
718
719 #if !defined(ARCH_LOWCACHE)
720 while (curmem < tomem - 4) {
721 #if !defined(ARCH_USEINDEXING)
722 hash = toupper_table[(int)*curmem++] + (31 * hash);
723 hash = toupper_table[(int)*curmem++] + (31 * hash);
724 hash = toupper_table[(int)*curmem++] + (31 * hash);
725 hash = toupper_table[(int)*curmem++] + (31 * hash);
726 #else /* !defined(ARCH_USEINDEXING) */
727 hash = toupper_table[(int)curmem[0]] + (31 * hash);
728 hash = toupper_table[(int)curmem[1]] + (31 * hash);
729 hash = toupper_table[(int)curmem[2]] + (31 * hash);
730 hash = toupper_table[(int)curmem[3]] + (31 * hash);
731 curmem += 4;
732 #endif /* !defined(ARCH_USEINDEXING) */
733 }
734 #endif /* !defined(ARCH_LOWCACHE) */
735 while (curmem < tomem)
736 hash = toupper_table[(int)*curmem++] + (31 * hash);
737
738 return hash;
739 }
740
741 int
742 mm_memcasecmp(const void *s1, const void *s2, size_t size)
743 {
744 register const unsigned char *ptr1, *ptr2, *toptr;
745
746 #define CMP() toupper_table[(int)*ptr1++] != toupper_table[(int)*ptr2++]
747 #define RET() return (int)(toupper_table[(int)*(--ptr1)] - \
748 toupper_table[(int)*(--ptr2)])
749
750 ptr1 = toptr = s1;
751 toptr += size;
752 ptr2 = s2;
753
754 #if !defined(ARCH_LOWCACHE)
755 while (ptr1 < toptr - 4)
756 if (CMP() || CMP() || CMP() || CMP())
757 RET();
758 #endif
759 while (ptr1 < toptr)
760 if (CMP())
761 RET();
762
763 #undef CMP
764 #undef RET
765
766 return 0;
767 }
768
769
770 /* Some may argue about the usefulness of such a thing. Some C libraries will
771 * provide more efficient architecture-dependent functions using unrolling
772 * when necessary, word copy methods, or even hardware data manipulation
773 * functions. But, some systems may have broken implementations, and others
774 * will provide unefficient C or assembly ones. So I borrow this code from
775 * my Xisop project which is portable and known to work decently.
776 * These functions are probably as fast as C ones could be.
777 * The ARCH_LONG_BITS, ARCH_LOWCACHE and ARCH_USEINDEXING definitions are
778 * found in mmlib/mmtypes.h and should be tweaked for maximum performance on
779 * a particular architecture. Note that compiler will also affect results.
780 * The reason for using "int" as the general word size for the system is that
781 * "long" type may be implemented as 32-bit on a 16-bit or pseudo-32bit
782 * system, and would be less efficient than moving words of the native size
783 * for the CPU.
784 *
785 * These functions seem to optimize especially well on m68k using GCC2.
786 * The i386/i586/i686 code is decent although it could be improoved.
787 *
788 * XXX It might be nice to use bit operators instead of modulo into the byte
789 * alignment macros.
790 *
791 * Matt
792 */
793
794 #ifdef MMSTRING_OBSOLETE
795
796 int
797 mm_memcmp(const void *dest, const void *src, size_t len)
798 {
799 register const unsigned char *ptr, *toptr, *dptr;
800
801 ptr = toptr = src;
802 toptr += len;
803 dptr = dest;
804
805 #define RET(a, b) return (int)(*(--(a)) - *(--(b)))
806
807 #if ARCH_LONG_BITS == 8
808
809 #if !defined(ARCH_LOWCACHE)
810 while (ptr < toptr - 8)
811 if (*ptr++ != *dptr++ || *ptr++ != *dptr++ || *ptr++ != *dptr++ ||
812 *ptr++ != *dptr++ || *ptr++ != *dptr++ || *ptr++ != *dptr++ ||
813 *ptr++ != *dptr++ || *ptr++ != *dptr++)
814 RET(dptr, ptr);
815 #endif /* !defined(ARCH_LOWCACHE) */
816 while (ptr < toptr)
817 if (*ptr++ != *dptr++)
818 RET(dptr, ptr);
819
820 #else /* ARCH_LONG_BITS != 8 */
821
822 if (len < 32 || ((long)ptr % sizeof(long)) !=
823 ((long)dptr % sizeof(long))) {
824 #if !defined(ARCH_LOWCACHE)
825 while (ptr < toptr - 8)
826 if (*ptr++ != *dptr++ || *ptr++ != *dptr++ || *ptr++ != *dptr++ ||
827 *ptr++ != *dptr++ || *ptr++ != *dptr++ ||
828 *ptr++ != *dptr++ || *ptr++ != *dptr++ ||
829 *ptr++ != *dptr++)
830 RET(dptr, ptr);
831 #endif /* !defined(ARCH_LOWCACHE) */
832 while (ptr < toptr)
833 if (*ptr++ != *dptr++)
834 RET(dptr, ptr);
835 } else {
836 register const unsigned long *lptr, *ltoptr, *ldptr, *ldtoptr;
837 register const unsigned char *dtoptr;
838
839 dtoptr = dptr;
840 dtoptr += len;
841 lptr = (const unsigned long *)OALIGN_CEIL(ptr, long);
842 ltoptr = (const unsigned long *)OALIGN_FLOOR(toptr, long);
843 ldptr = (const unsigned long *)OALIGN_CEIL(dptr, long);
844 ldtoptr = (const unsigned long *)OALIGN_FLOOR(dtoptr, long);
845 if (ldtoptr - ldptr < ltoptr - lptr)
846 ltoptr--;
847
848 while (ptr < (const unsigned char *)lptr)
849 if (*ptr++ != *dptr++)
850 RET(dptr, ptr);
851 #if !defined(ARCH_LOWCACHE)
852 while (lptr < ltoptr - (sizeof(long) * 8)) {
853 if (*lptr++ != *ldptr++ || *lptr++ != *ldptr++ ||
854 *lptr++ != *ldptr++ || *lptr++ != *ldptr++ ||
855 *lptr++ != *ldptr++ || *lptr++ != *ldptr++ ||
856 *lptr++ != *ldptr++ || *lptr++ != *ldptr++)
857 RET(ldptr, lptr);
858 }
859 #endif /* !defined(ARCH_LOWCACHE) */
860 while (lptr < ltoptr)
861 if (*lptr++ != *ldptr++)
862 RET(ldptr, lptr);
863 ptr = (const unsigned char *)lptr;
864 dptr = (const unsigned char *)ldptr;
865 while (ptr < toptr)
866 if (*ptr++ != *dptr++)
867 RET(dptr, ptr);
868 }
869
870 #endif /* ARCH_LONG_BITS == 8 */
871
872 #undef RET
873
874 return 0;
875 }
876
877
878 void *
879 mm_memcpy(void *dest, const void *src, size_t len)
880 {
881 register const unsigned char *ptr, *toptr;
882 register unsigned char *dptr;
883
884 ptr = toptr = src;
885 toptr += len;
886 dptr = dest;
887
888 #if ARCH_LONG_BITS == 8
889
890 #if !defined(ARCH_LOWCACHE)
891 while (ptr < toptr - 8) {
892 #if !defined(ARCH_USEINDEXING)
893 *dptr++ = *ptr++;
894 *dptr++ = *ptr++;
895 *dptr++ = *ptr++;
896 *dptr++ = *ptr++;
897 *dptr++ = *ptr++;
898 *dptr++ = *ptr++;
899 *dptr++ = *ptr++;
900 *dptr++ = *ptr++;
901 #else /* !defined(ARCH_USEINDEXING) */
902 dptr[0] = ptr[0];
903 dptr[1] = ptr[1];
904 dptr[2] = ptr[2];
905 dptr[3] = ptr[3];
906 dptr[4] = ptr[4];
907 dptr[5] = ptr[5];
908 dptr[6] = ptr[6];
909 dptr[7] = ptr[7];
910 dptr += 8;
911 ptr += 8;
912 #endif /* !defined(ARCH_USEINDEXING) */
913 }
914 #endif /* !defined(ARCH_LOWCACHE) */
915 while (ptr < toptr)
916 *dptr++ = *ptr++;
917
918 #else /* ARCH_LONG_BITS != 8 */
919
920 if (len < 32 || ((long)ptr % sizeof(long)) !=
921 ((long)dptr % sizeof(long))) {
922 #if !defined(ARCH_LOWCACHE)
923 while (ptr < toptr - 8) {
924 #if !defined(ARCH_USEINDEXING)
925 *dptr++ = *ptr++;
926 *dptr++ = *ptr++;
927 *dptr++ = *ptr++;
928 *dptr++ = *ptr++;
929 *dptr++ = *ptr++;
930 *dptr++ = *ptr++;
931 *dptr++ = *ptr++;
932 *dptr++ = *ptr++;
933 #else /* !defined(ARCH_USEINDEXING) */
934 dptr[0] = ptr[0];
935 dptr[1] = ptr[1];
936 dptr[2] = ptr[2];
937 dptr[3] = ptr[3];
938 dptr[4] = ptr[4];
939 dptr[5] = ptr[5];
940 dptr[6] = ptr[6];
941 dptr[7] = ptr[7];
942 dptr += 8;
943 ptr += 8;
944 #endif /* !defined(ARCH_USEINDEXING) */
945 }
946 #endif /* !defined(ARCH_LOWCACHE) */
947 while (ptr < toptr)
948 *dptr++ = *ptr++;
949 } else {
950 register const unsigned long *lptr, *ltoptr;
951 register unsigned long *ldptr, *ldtoptr;
952 register unsigned char *dtoptr;
953
954 dtoptr = dptr;
955 dtoptr += len;
956 lptr = (const unsigned long *)OALIGN_CEIL(ptr, long);
957 ltoptr = (const unsigned long *)OALIGN_FLOOR(toptr, long);
958 ldptr = (unsigned long *)OALIGN_CEIL(dptr, long);
959 ldtoptr = (unsigned long *)OALIGN_FLOOR(dtoptr, long);
960 if (ldtoptr - ldptr < ltoptr - lptr)
961 ltoptr--;
962
963 while (ptr < (const unsigned char *)lptr)
964 *dptr++ = *ptr++;
965 #if !defined(ARCH_LOWCACHE)
966 while (lptr < ltoptr - (sizeof(long) * 8)) {
967 #if !defined(ARCH_USEINDEXING)
968 *ldptr++ = *lptr++;
969 *ldptr++ = *lptr++;
970 *ldptr++ = *lptr++;
971 *ldptr++ = *lptr++;
972 *ldptr++ = *lptr++;
973 *ldptr++ = *lptr++;
974 *ldptr++ = *lptr++;
975 *ldptr++ = *lptr++;
976 #else /* !defined(ARCH_USEINDEXING) */
977 ldptr[0] = lptr[0];
978 ldptr[1] = lptr[1];
979 ldptr[2] = lptr[2];
980 ldptr[3] = lptr[3];
981 ldptr[4] = lptr[4];
982 ldptr[5] = lptr[5];
983 ldptr[6] = lptr[6];
984 ldptr[7] = lptr[7];
985 ldptr = &ldptr[8];
986 lptr = &lptr[8];
987 #endif /* !defined(ARCH_USEINDEXING) */
988 }
989 #endif /* !defined(ARCH_LOWCACHE) */
990 while (lptr < ltoptr)
991 *ldptr++ = *lptr++;
992 ptr = (unsigned const char *)lptr;
993 dptr = (unsigned char *)ldptr;
994 while (ptr < toptr)
995 *dptr++ = *ptr++;
996 }
997
998 #endif /* ARCH_LONG_BITS == 8 */
999
1000 return dest;
1001 }
1002
1003
1004 /* Can work with overlapping areas */
1005 void *
1006 mm_memmove(void *dest, const void *src, size_t len)
1007 {
1008 register const unsigned char *ptr = NULL, *toptr = NULL;
1009 register unsigned char *dptr = NULL;
1010 size_t d;
1011
1012 if (dest < src)
1013 d = (const unsigned char *)src - (unsigned char *)dest;
1014 else
1015 d = (unsigned char *)dest - (const unsigned char *)src;
1016
1017 #if ARCH_LONG_BITS == 8
1018
1019 if (dest < src) {
1020 /* Copy in increasing order */
1021 ptr = toptr = (const unsigned char *)src;
1022 toptr += len;
1023 dptr = dest;
1024 #if !defined(ARCH_LOWCACHE)
1025 while (ptr < toptr - 8) {
1026 #if !defined(ARCH_USEINDEXING)
1027 *dptr++ = *ptr++;
1028 *dptr++ = *ptr++;
1029 *dptr++ = *ptr++;
1030 *dptr++ = *ptr++;
1031 *dptr++ = *ptr++;
1032 *dptr++ = *ptr++;
1033 *dptr++ = *ptr++;
1034 *dptr++ = *ptr++;
1035 #else /* !defined(ARCH_USEINDEXING) */
1036 dptr[0] = ptr[0];
1037 dptr[1] = ptr[1];
1038 dptr[2] = ptr[2];
1039 dptr[3] = ptr[3];
1040 dptr[4] = ptr[4];
1041 dptr[5] = ptr[5];
1042 dptr[6] = ptr[6];
1043 dptr[7] = ptr[7];
1044 dptr += 8;
1045 ptr += 8;
1046 #endif /* !defined(ARCH_USEINDEXING) */
1047 }
1048 #endif /* !defined(ARCH_LOWCACHE) */
1049 while (ptr < toptr)
1050 *dptr++ = *ptr++;
1051 } else if (dest > src) {
1052 /* Copy in reverse order */
1053 ptr = toptr = (const unsigned char *)src;
1054 ptr += len;
1055 dptr = dest;
1056 dptr += len;
1057 #if !defined(ARCH_LOWCACHE)
1058 while (ptr >= toptr + 8) {
1059 #if !defined(ARCH_USEINDEXING)
1060 *dptr-- = *ptr--;
1061 *dptr-- = *ptr--;
1062 *dptr-- = *ptr--;
1063 *dptr-- = *ptr--;
1064 *dptr-- = *ptr--;
1065 *dptr-- = *ptr--;
1066 *dptr-- = *ptr--;
1067 *dptr-- = *ptr--;
1068 #else /* !defined(ARCH_USEINDEXING) */
1069 dptr[0] = ptr[0];
1070 dptr[-1] = ptr[-1];
1071 dptr[-2] = ptr[-2];
1072 dptr[-3] = ptr[-3];
1073 dptr[-4] = ptr[-4];
1074 dptr[-5] = ptr[-5];
1075 dptr[-6] = ptr[-6];
1076 dptr[-7] = ptr[-7];
1077 dptr -= 8;
1078 ptr -= 8;
1079 #endif /* !defined(ARCH_USEINDEXING) */
1080 }
1081 #endif /* !defined(ARCH_LOWCACHE) */
1082 while (ptr >= toptr)
1083 *dptr-- = *ptr--;
1084 }
1085
1086 #else /* ARCH_LONG_BITS != 8 */
1087
1088 if (len < 32 || d < sizeof(long) ||
1089 ((long)ptr % sizeof(long)) != ((long)dptr % sizeof(long))) {
1090 if (dest < src) {
1091 /* Copy in increasing order */
1092 ptr = toptr = (const unsigned char *)src;
1093 toptr += len;
1094 dptr = dest;
1095 #if !defined(ARCH_LOWCACHE)
1096 while (ptr < toptr - 8) {
1097 #if !defined(ARCH_USEINDEXING)
1098 *dptr++ = *ptr++;
1099 *dptr++ = *ptr++;
1100 *dptr++ = *ptr++;
1101 *dptr++ = *ptr++;
1102 *dptr++ = *ptr++;
1103 *dptr++ = *ptr++;
1104 *dptr++ = *ptr++;
1105 *dptr++ = *ptr++;
1106 #else /* !defined(ARCH_USEINDEXING) */
1107 dptr[0] = ptr[0];
1108 dptr[1] = ptr[1];
1109 dptr[2] = ptr[2];
1110 dptr[3] = ptr[3];
1111 dptr[4] = ptr[4];
1112 dptr[5] = ptr[5];
1113 dptr[6] = ptr[6];
1114 dptr[7] = ptr[7];
1115 dptr += 8;
1116 ptr += 8;
1117 #endif /* !defined(ARCH_USEINDEXING) */
1118 }
1119 #endif /* !defined(ARCH_LOWCACHE) */
1120 while (ptr < toptr)
1121 *dptr++ = *ptr++;
1122 } else if (dest > src) {
1123 /* Copy in reverse order */
1124 ptr = toptr = (const unsigned char *)src;
1125 ptr += len;
1126 dptr = dest;
1127 dptr += len;
1128 #if !defined(ARCH_LOWCACHE)
1129 while (ptr >= toptr + 8) {
1130 #if !defined(ARCH_USEINDEXING)
1131 *dptr-- = *ptr--;
1132 *dptr-- = *ptr--;
1133 *dptr-- = *ptr--;
1134 *dptr-- = *ptr--;
1135 *dptr-- = *ptr--;
1136 *dptr-- = *ptr--;
1137 *dptr-- = *ptr--;
1138 *dptr-- = *ptr--;
1139 #else /* !defined(ARCH_USEINDEXING) */
1140 dptr[0] = ptr[0];
1141 dptr[-1] = ptr[-1];
1142 dptr[-2] = ptr[-2];
1143 dptr[-3] = ptr[-3];
1144 dptr[-4] = ptr[-4];
1145 dptr[-5] = ptr[-5];
1146 dptr[-6] = ptr[-6];
1147 dptr[-7] = ptr[-7];
1148 dptr -= 8;
1149 ptr -= 8;
1150 #endif /* !defined(ARCH_USEINDEXING) */
1151 }
1152 #endif /* !defined(ARCH_LOWCACHE) */
1153 while (ptr >= toptr)
1154 *dptr-- = *ptr--;
1155 }
1156 } else {
1157 if (dest < src) {
1158 /* Increasing order */
1159 register const unsigned long *lptr, *ltoptr;
1160 register unsigned long *ldptr, *ldtoptr;
1161 register unsigned char *dtoptr;
1162
1163 ptr = toptr = (const unsigned char *)src;
1164 toptr += len;
1165 dptr = dest;
1166
1167 dtoptr = dptr;
1168 dtoptr += len;
1169 lptr = (const unsigned long *)OALIGN_CEIL(ptr, long);
1170 ltoptr = (const unsigned long *)OALIGN_FLOOR(toptr, long);
1171 ldptr = (unsigned long *)OALIGN_CEIL(dptr, long);
1172 ldtoptr = (unsigned long *)OALIGN_FLOOR(dtoptr, long);
1173 if (ldtoptr - ldptr < ltoptr - lptr)
1174 ltoptr--;
1175
1176 while (ptr < (const unsigned char *)lptr)
1177 *dptr++ = *ptr++;
1178 #if !defined(ARCH_LOWCACHE)
1179 while (lptr < ltoptr - (sizeof(long) * 8)) {
1180 #if !defined(ARCH_USEINDEXING)
1181 *ldptr++ = *lptr++;
1182 *ldptr++ = *lptr++;
1183 *ldptr++ = *lptr++;
1184 *ldptr++ = *lptr++;
1185 *ldptr++ = *lptr++;
1186 *ldptr++ = *lptr++;
1187 *ldptr++ = *lptr++;
1188 *ldptr++ = *lptr++;
1189 #else /* !defined(ARCH_USEINDEXING) */
1190 ldptr[0] = lptr[0];
1191 ldptr[1] = lptr[1];
1192 ldptr[2] = lptr[2];
1193 ldptr[3] = lptr[3];
1194 ldptr[4] = lptr[4];
1195 ldptr[5] = lptr[5];
1196 ldptr[6] = lptr[6];
1197 ldptr[7] = lptr[7];
1198 ldptr = &ldptr[8];
1199 lptr = &lptr[8];
1200 #endif /* !defined(ARCH_USEINDEXING) */
1201 }
1202 #endif /* !defined(ARCH_LOWCACHE) */
1203 while (lptr < ltoptr)
1204 *ldptr++ = *lptr++;
1205 ptr = (const unsigned char *)lptr;
1206 dptr = (unsigned char *)ldptr;
1207 while (ptr < toptr)
1208 *dptr++ = *ptr++;
1209 } else if (dest > src) {
1210 /* Reverse order */
1211 register const unsigned long *lptr, *ltoptr;
1212 register unsigned long *ldptr, *ldtoptr;
1213 register char *dtoptr;
1214
1215 ptr = toptr = (const unsigned char *)src;
1216 ptr += len;
1217 dptr = dest;
1218 dptr += len;
1219
1220 dtoptr = dest;
1221 lptr = (const unsigned long *)OALIGN_FLOOR(ptr, long);
1222 ldptr = (unsigned long *)OALIGN_FLOOR(dptr, long);
1223 ltoptr = (const unsigned long *)OALIGN_CEIL(toptr, long);
1224 ldtoptr = (unsigned long *)OALIGN_CEIL(dtoptr, long);
1225 if (ldptr - ldtoptr < lptr - ltoptr)
1226 ltoptr++;
1227
1228 while (ptr >= (const unsigned char *)lptr)
1229 *dptr-- = *ptr--;
1230 #if !defined(ARCH_LOWCACHE)
1231 while (lptr >= ltoptr + (sizeof(long) * 8)) {
1232 #if !defined(ARCH_USEINDEXING)
1233 *ldptr-- = *lptr--;
1234 *ldptr-- = *lptr--;
1235 *ldptr-- = *lptr--;
1236 *ldptr-- = *lptr--;
1237 *ldptr-- = *lptr--;
1238 *ldptr-- = *lptr--;
1239 *ldptr-- = *lptr--;
1240 *ldptr-- = *lptr--;
1241 #else /* !defined(ARCH_USEINDEXING) */
1242 ldptr[0] = lptr[0];
1243 ldptr[-1] = lptr[-1];
1244 ldptr[-2] = lptr[-2];
1245 ldptr[-3] = lptr[-3];
1246 ldptr[-4] = lptr[-4];
1247 ldptr[-5] = lptr[-5];
1248 ldptr[-6] = lptr[-6];
1249 ldptr[-7] = lptr[-7];
1250 ldptr = &ldptr[-8];
1251 lptr = &lptr[-8];
1252 #endif /* !defined(ARCH_USEINDEXING) */
1253 }
1254 #endif /* !defined(ARCH_LOWCACHE) */
1255 while (lptr >= ltoptr)
1256 *ldptr-- = *lptr--;
1257 ptr = (const unsigned char *)lptr;
1258 dptr = (unsigned char *)ldptr;
1259 while (ptr >= toptr)
1260 *dptr-- = *ptr--;
1261 }
1262 }
1263
1264 #endif /* ARCH_LONG_BITS == 8 */
1265
1266 return dest;
1267 }
1268
1269
1270 void *
1271 mm_memset(void *mem, int fill, size_t len)
1272 {
1273 register unsigned char *ptr, *toptr;
1274 uint8_t byte = (uint8_t)fill;
1275
1276 ptr = toptr = mem;
1277 toptr += len;
1278
1279 #if ARCH_LONG_BITS == 8
1280
1281 #if !defined(ARCH_LOWCACHE)
1282 while (ptr < toptr - 8) {
1283 #if !defined(ARCH_USEINDEXING)
1284 *ptr++ = byte;
1285 *ptr++ = byte;
1286 *ptr++ = byte;
1287 *ptr++ = byte;
1288 *ptr++ = byte;
1289 *ptr++ = byte;
1290 *ptr++ = byte;
1291 *ptr++ = byte;
1292 #else /* !defined(ARCH_USEINDEXING) */
1293 ptr[0] = byte;
1294 ptr[1] = byte;
1295 ptr[2] = byte;
1296 ptr[3] = byte;
1297 ptr[4] = byte;
1298 ptr[5] = byte;
1299 ptr[6] = byte;
1300 ptr[7] = byte;
1301 ptr += 8;
1302 #endif /* !defined(ARCH_USEINDEXING) */
1303 }
1304 #endif /* !defined(ARCH_LOWCACHE) */
1305 while (ptr < toptr)
1306 *ptr++ = byte;
1307
1308 #else /* ARCH_LONG_BITS != 8 */
1309
1310 if (len < 32) {
1311 #if !defined(ARCH_LOWCACHE)
1312 while (ptr < toptr - 8) {
1313 #if !defined(ARCH_USEINDEXING)
1314 *ptr++ = byte;
1315 *ptr++ = byte;
1316 *ptr++ = byte;
1317 *ptr++ = byte;
1318 *ptr++ = byte;
1319 *ptr++ = byte;
1320 *ptr++ = byte;
1321 *ptr++ = byte;
1322 #else /* !defined(ARCH_USEDARRAYS) */
1323 ptr[0] = byte;
1324 ptr[1] = byte;
1325 ptr[2] = byte;
1326 ptr[3] = byte;
1327 ptr[4] = byte;
1328 ptr[5] = byte;
1329 ptr[6] = byte;
1330 ptr[7] = byte;
1331 ptr += 8;
1332 #endif /* !defined(ARCH_USEINDEXING) */
1333 }
1334 #endif /* !defined(ARCH_LOWCACHE) */
1335 while (ptr < toptr)
1336 *ptr++ = byte;
1337 } else {
1338 register unsigned long *lptr, *ltoptr, lword = 0;
1339
1340 if (byte != 0) {
1341 #if ARCH_LONG_BITS == 16
1342 lword = ((byte << 8) & 0xff00) | (byte & 0x00ff);
1343 #elif ARCH_LONG_BITS == 32
1344 /* Creating a 16-bit word from the 8-bit one, then the 32-bit word
1345 * from the 16-bit one require less instructions.
1346 */
1347 register uint16_t tmp;
1348
1349 tmp = ((byte << 8) & 0xff00) | (byte & 0x00ff);
1350 lword = ((tmp << 16) & 0xffff0000) | (tmp & 0x0000ffff);
1351 #elif ARCH_LONG_BITS == 64
1352 /* Creating a 16-bit word from the 8-bit one, a 32-bit word from
1353 * the 16-bit one and a 64-bit word from the 32-bit one require
1354 * less instructions.
1355 */
1356 register uint32_t tmp2;
1357 register uint16_t tmp;
1358
1359 tmp = ((byte << 8) & 0xff00) | (byte & 0x00ff);
1360 tmp2 = ((tmp << 16) & 0xffff0000) | (tmp & 0x0000ffff);
1361 lword = ((tmp2 << 32) & 0xffffffff00000000ULL) |
1362 (tmp2 & 0x00000000ffffffffULL);
1363 #endif
1364 }
1365
1366 lptr = (unsigned long *)OALIGN_CEIL(ptr, long);
1367 ltoptr = (unsigned long *)OALIGN_FLOOR(toptr, long);
1368
1369 while (ptr < (unsigned char *)lptr)
1370 *ptr++ = byte;
1371 #if !defined(ARCH_LOWCACHE)
1372 while (lptr < ltoptr - (sizeof(long) * 8)) {
1373 #if !defined(ARCH_USEINDEXING)
1374 *lptr++ = lword;
1375 *lptr++ = lword;
1376 *lptr++ = lword;
1377 *lptr++ = lword;
1378 *lptr++ = lword;
1379 *lptr++ = lword;
1380 *lptr++ = lword;
1381 *lptr++ = lword;
1382 #else /* !defined(ARCH_USEINDEXING) */
1383 lptr[0] = lword;
1384 lptr[1] = lword;
1385 lptr[2] = lword;
1386 lptr[3] = lword;
1387 lptr[4] = lword;
1388 lptr[5] = lword;
1389 lptr[6] = lword;
1390 lptr[7] = lword;
1391 lptr = &lptr[8];
1392 #endif /* !defined(ARCH_USEINDEXING) */
1393 }
1394 #endif /* !defined(ARCH_LOWCACHE) */
1395 while (lptr < ltoptr)
1396 *lptr++ = lword;
1397 ptr = (unsigned char *)lptr;
1398 while (ptr < toptr)
1399 *ptr++ = byte;
1400 }
1401
1402 #endif /* ARCH_LONG_BITS == 8 */
1403
1404 return mem;
1405 }
1406 #endif