/contrib/sdk/sources/libc/string/local.h |
---|
0,0 → 1,9 |
#include <_ansi.h> |
#include <../ctype/local.h> |
/* internal function to compute width of wide char. */ |
int _EXFUN (__wcwidth, (wint_t)); |
/* Defined in locale/locale.c. Returns a value != 0 if the current |
language is assumed to use CJK fonts. */ |
int __locale_cjk_lang (); |
/contrib/sdk/sources/libc/string/memchr.c |
---|
0,0 → 1,134 |
/* |
FUNCTION |
<<memchr>>---find character in memory |
INDEX |
memchr |
ANSI_SYNOPSIS |
#include <string.h> |
void *memchr(const void *<[src]>, int <[c]>, size_t <[length]>); |
TRAD_SYNOPSIS |
#include <string.h> |
void *memchr(<[src]>, <[c]>, <[length]>) |
void *<[src]>; |
void *<[c]>; |
size_t <[length]>; |
DESCRIPTION |
This function searches memory starting at <<*<[src]>>> for the |
character <[c]>. The search only ends with the first |
occurrence of <[c]>, or after <[length]> characters; in |
particular, <<NUL>> does not terminate the search. |
RETURNS |
If the character <[c]> is found within <[length]> characters |
of <<*<[src]>>>, a pointer to the character is returned. If |
<[c]> is not found, then <<NULL>> is returned. |
PORTABILITY |
<<memchr>> is ANSI C. |
<<memchr>> requires no supporting OS subroutines. |
QUICKREF |
memchr ansi pure |
*/ |
#include <_ansi.h> |
#include <string.h> |
#include <limits.h> |
/* Nonzero if either X or Y is not aligned on a "long" boundary. */ |
#define UNALIGNED(X) ((long)X & (sizeof (long) - 1)) |
/* How many bytes are loaded each iteration of the word copy loop. */ |
#define LBLOCKSIZE (sizeof (long)) |
/* Threshhold for punting to the bytewise iterator. */ |
#define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE) |
#if LONG_MAX == 2147483647L |
#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080) |
#else |
#if LONG_MAX == 9223372036854775807L |
/* Nonzero if X (a long int) contains a NULL byte. */ |
#define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080) |
#else |
#error long int is not a 32bit or 64bit type. |
#endif |
#endif |
#ifndef DETECTNULL |
#error long int is not a 32bit or 64bit byte |
#endif |
/* DETECTCHAR returns nonzero if (long)X contains the byte used |
to fill (long)MASK. */ |
#define DETECTCHAR(X,MASK) (DETECTNULL(X ^ MASK)) |
_PTR |
_DEFUN (memchr, (src_void, c, length), |
_CONST _PTR src_void _AND |
int c _AND |
size_t length) |
{ |
_CONST unsigned char *src = (_CONST unsigned char *) src_void; |
unsigned char d = c; |
#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) |
unsigned long *asrc; |
unsigned long mask; |
int i; |
while (UNALIGNED (src)) |
{ |
if (!length--) |
return NULL; |
if (*src == d) |
return (void *) src; |
src++; |
} |
if (!TOO_SMALL (length)) |
{ |
/* If we get this far, we know that length is large and src is |
word-aligned. */ |
/* The fast code reads the source one word at a time and only |
performs the bytewise search on word-sized segments if they |
contain the search character, which is detected by XORing |
the word-sized segment with a word-sized block of the search |
character and then detecting for the presence of NUL in the |
result. */ |
asrc = (unsigned long *) src; |
mask = d << 8 | d; |
mask = mask << 16 | mask; |
for (i = 32; i < LBLOCKSIZE * 8; i <<= 1) |
mask = (mask << i) | mask; |
while (length >= LBLOCKSIZE) |
{ |
if (DETECTCHAR (*asrc, mask)) |
break; |
length -= LBLOCKSIZE; |
asrc++; |
} |
/* If there are fewer than LBLOCKSIZE characters left, |
then we resort to the bytewise loop. */ |
src = (unsigned char *) asrc; |
} |
#endif /* not PREFER_SIZE_OVER_SPEED */ |
while (length--) |
{ |
if (*src == d) |
return (void *) src; |
src++; |
} |
return NULL; |
} |
/contrib/sdk/sources/libc/string/memcmp.c |
---|
0,0 → 1,113 |
/* |
FUNCTION |
<<memcmp>>---compare two memory areas |
INDEX |
memcmp |
ANSI_SYNOPSIS |
#include <string.h> |
int memcmp(const void *<[s1]>, const void *<[s2]>, size_t <[n]>); |
TRAD_SYNOPSIS |
#include <string.h> |
int memcmp(<[s1]>, <[s2]>, <[n]>) |
void *<[s1]>; |
void *<[s2]>; |
size_t <[n]>; |
DESCRIPTION |
This function compares not more than <[n]> characters of the |
object pointed to by <[s1]> with the object pointed to by <[s2]>. |
RETURNS |
The function returns an integer greater than, equal to or |
less than zero according to whether the object pointed to by |
<[s1]> is greater than, equal to or less than the object |
pointed to by <[s2]>. |
PORTABILITY |
<<memcmp>> is ANSI C. |
<<memcmp>> requires no supporting OS subroutines. |
QUICKREF |
memcmp ansi pure |
*/ |
#include <string.h> |
/* Nonzero if either X or Y is not aligned on a "long" boundary. */ |
#define UNALIGNED(X, Y) \ |
(((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) |
/* How many bytes are copied each iteration of the word copy loop. */ |
#define LBLOCKSIZE (sizeof (long)) |
/* Threshhold for punting to the byte copier. */ |
#define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE) |
int |
_DEFUN (memcmp, (m1, m2, n), |
_CONST _PTR m1 _AND |
_CONST _PTR m2 _AND |
size_t n) |
{ |
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) |
unsigned char *s1 = (unsigned char *) m1; |
unsigned char *s2 = (unsigned char *) m2; |
while (n--) |
{ |
if (*s1 != *s2) |
{ |
return *s1 - *s2; |
} |
s1++; |
s2++; |
} |
return 0; |
#else |
unsigned char *s1 = (unsigned char *) m1; |
unsigned char *s2 = (unsigned char *) m2; |
unsigned long *a1; |
unsigned long *a2; |
/* If the size is too small, or either pointer is unaligned, |
then we punt to the byte compare loop. Hopefully this will |
not turn up in inner loops. */ |
if (!TOO_SMALL(n) && !UNALIGNED(s1,s2)) |
{ |
/* Otherwise, load and compare the blocks of memory one |
word at a time. */ |
a1 = (unsigned long*) s1; |
a2 = (unsigned long*) s2; |
while (n >= LBLOCKSIZE) |
{ |
if (*a1 != *a2) |
break; |
a1++; |
a2++; |
n -= LBLOCKSIZE; |
} |
/* check m mod LBLOCKSIZE remaining characters */ |
s1 = (unsigned char*)a1; |
s2 = (unsigned char*)a2; |
} |
while (n--) |
{ |
if (*s1 != *s2) |
return *s1 - *s2; |
s1++; |
s2++; |
} |
return 0; |
#endif /* not PREFER_SIZE_OVER_SPEED */ |
} |
/contrib/sdk/sources/libc/string/memcpy.c |
---|
0,0 → 1,110 |
/* |
FUNCTION |
<<memcpy>>---copy memory regions |
ANSI_SYNOPSIS |
#include <string.h> |
void* memcpy(void *<[out]>, const void *<[in]>, size_t <[n]>); |
TRAD_SYNOPSIS |
#include <string.h> |
void *memcpy(<[out]>, <[in]>, <[n]> |
void *<[out]>; |
void *<[in]>; |
size_t <[n]>; |
DESCRIPTION |
This function copies <[n]> bytes from the memory region |
pointed to by <[in]> to the memory region pointed to by |
<[out]>. |
If the regions overlap, the behavior is undefined. |
RETURNS |
<<memcpy>> returns a pointer to the first byte of the <[out]> |
region. |
PORTABILITY |
<<memcpy>> is ANSI C. |
<<memcpy>> requires no supporting OS subroutines. |
QUICKREF |
memcpy ansi pure |
*/ |
#include <_ansi.h> |
#include <string.h> |
/* Nonzero if either X or Y is not aligned on a "long" boundary. */ |
#define UNALIGNED(X, Y) \ |
(((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) |
/* How many bytes are copied each iteration of the 4X unrolled loop. */ |
#define BIGBLOCKSIZE (sizeof (long) << 2) |
/* How many bytes are copied each iteration of the word copy loop. */ |
#define LITTLEBLOCKSIZE (sizeof (long)) |
/* Threshhold for punting to the byte copier. */ |
#define TOO_SMALL(LEN) ((LEN) < BIGBLOCKSIZE) |
_PTR |
_DEFUN (memcpy, (dst0, src0, len0), |
_PTR dst0 _AND |
_CONST _PTR src0 _AND |
size_t len0) |
{ |
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) |
char *dst = (char *) dst0; |
char *src = (char *) src0; |
_PTR save = dst0; |
while (len0--) |
{ |
*dst++ = *src++; |
} |
return save; |
#else |
char *dst = dst0; |
_CONST char *src = src0; |
long *aligned_dst; |
_CONST long *aligned_src; |
/* If the size is small, or either SRC or DST is unaligned, |
then punt into the byte copy loop. This should be rare. */ |
if (!TOO_SMALL(len0) && !UNALIGNED (src, dst)) |
{ |
aligned_dst = (long*)dst; |
aligned_src = (long*)src; |
/* Copy 4X long words at a time if possible. */ |
while (len0 >= BIGBLOCKSIZE) |
{ |
*aligned_dst++ = *aligned_src++; |
*aligned_dst++ = *aligned_src++; |
*aligned_dst++ = *aligned_src++; |
*aligned_dst++ = *aligned_src++; |
len0 -= BIGBLOCKSIZE; |
} |
/* Copy one long word at a time if possible. */ |
while (len0 >= LITTLEBLOCKSIZE) |
{ |
*aligned_dst++ = *aligned_src++; |
len0 -= LITTLEBLOCKSIZE; |
} |
/* Pick up any residual with a byte copier. */ |
dst = (char*)aligned_dst; |
src = (char*)aligned_src; |
} |
while (len0--) |
*dst++ = *src++; |
return dst0; |
#endif /* not PREFER_SIZE_OVER_SPEED */ |
} |
/contrib/sdk/sources/libc/string/memmove.c |
---|
0,0 → 1,142 |
/* |
FUNCTION |
<<memmove>>---move possibly overlapping memory |
INDEX |
memmove |
ANSI_SYNOPSIS |
#include <string.h> |
void *memmove(void *<[dst]>, const void *<[src]>, size_t <[length]>); |
TRAD_SYNOPSIS |
#include <string.h> |
void *memmove(<[dst]>, <[src]>, <[length]>) |
void *<[dst]>; |
void *<[src]>; |
size_t <[length]>; |
DESCRIPTION |
This function moves <[length]> characters from the block of |
memory starting at <<*<[src]>>> to the memory starting at |
<<*<[dst]>>>. <<memmove>> reproduces the characters correctly |
at <<*<[dst]>>> even if the two areas overlap. |
RETURNS |
The function returns <[dst]> as passed. |
PORTABILITY |
<<memmove>> is ANSI C. |
<<memmove>> requires no supporting OS subroutines. |
QUICKREF |
memmove ansi pure |
*/ |
#include <string.h> |
#include <_ansi.h> |
#include <stddef.h> |
#include <limits.h> |
/* Nonzero if either X or Y is not aligned on a "long" boundary. */ |
#define UNALIGNED(X, Y) \ |
(((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) |
/* How many bytes are copied each iteration of the 4X unrolled loop. */ |
#define BIGBLOCKSIZE (sizeof (long) << 2) |
/* How many bytes are copied each iteration of the word copy loop. */ |
#define LITTLEBLOCKSIZE (sizeof (long)) |
/* Threshhold for punting to the byte copier. */ |
#define TOO_SMALL(LEN) ((LEN) < BIGBLOCKSIZE) |
/*SUPPRESS 20*/ |
_PTR |
_DEFUN (memmove, (dst_void, src_void, length), |
_PTR dst_void _AND |
_CONST _PTR src_void _AND |
size_t length) |
{ |
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) |
char *dst = dst_void; |
_CONST char *src = src_void; |
if (src < dst && dst < src + length) |
{ |
/* Have to copy backwards */ |
src += length; |
dst += length; |
while (length--) |
{ |
*--dst = *--src; |
} |
} |
else |
{ |
while (length--) |
{ |
*dst++ = *src++; |
} |
} |
return dst_void; |
#else |
char *dst = dst_void; |
_CONST char *src = src_void; |
long *aligned_dst; |
_CONST long *aligned_src; |
if (src < dst && dst < src + length) |
{ |
/* Destructive overlap...have to copy backwards */ |
src += length; |
dst += length; |
while (length--) |
{ |
*--dst = *--src; |
} |
} |
else |
{ |
/* Use optimizing algorithm for a non-destructive copy to closely |
match memcpy. If the size is small or either SRC or DST is unaligned, |
then punt into the byte copy loop. This should be rare. */ |
if (!TOO_SMALL(length) && !UNALIGNED (src, dst)) |
{ |
aligned_dst = (long*)dst; |
aligned_src = (long*)src; |
/* Copy 4X long words at a time if possible. */ |
while (length >= BIGBLOCKSIZE) |
{ |
*aligned_dst++ = *aligned_src++; |
*aligned_dst++ = *aligned_src++; |
*aligned_dst++ = *aligned_src++; |
*aligned_dst++ = *aligned_src++; |
length -= BIGBLOCKSIZE; |
} |
/* Copy one long word at a time if possible. */ |
while (length >= LITTLEBLOCKSIZE) |
{ |
*aligned_dst++ = *aligned_src++; |
length -= LITTLEBLOCKSIZE; |
} |
/* Pick up any residual with a byte copier. */ |
dst = (char*)aligned_dst; |
src = (char*)aligned_src; |
} |
while (length--) |
{ |
*dst++ = *src++; |
} |
} |
return dst_void; |
#endif /* not PREFER_SIZE_OVER_SPEED */ |
} |
/contrib/sdk/sources/libc/string/memset.c |
---|
0,0 → 1,102 |
/* |
FUNCTION |
<<memset>>---set an area of memory |
INDEX |
memset |
ANSI_SYNOPSIS |
#include <string.h> |
void *memset(void *<[dst]>, int <[c]>, size_t <[length]>); |
TRAD_SYNOPSIS |
#include <string.h> |
void *memset(<[dst]>, <[c]>, <[length]>) |
void *<[dst]>; |
int <[c]>; |
size_t <[length]>; |
DESCRIPTION |
This function converts the argument <[c]> into an unsigned |
char and fills the first <[length]> characters of the array |
pointed to by <[dst]> to the value. |
RETURNS |
<<memset>> returns the value of <[dst]>. |
PORTABILITY |
<<memset>> is ANSI C. |
<<memset>> requires no supporting OS subroutines. |
QUICKREF |
memset ansi pure |
*/ |
#include <string.h> |
#define LBLOCKSIZE (sizeof(long)) |
#define UNALIGNED(X) ((long)X & (LBLOCKSIZE - 1)) |
#define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE) |
_PTR |
_DEFUN (memset, (m, c, n), |
_PTR m _AND |
int c _AND |
size_t n) |
{ |
char *s = (char *) m; |
#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) |
int i; |
unsigned long buffer; |
unsigned long *aligned_addr; |
unsigned int d = c & 0xff; /* To avoid sign extension, copy C to an |
unsigned variable. */ |
while (UNALIGNED (s)) |
{ |
if (n--) |
*s++ = (char) c; |
else |
return m; |
} |
if (!TOO_SMALL (n)) |
{ |
/* If we get this far, we know that n is large and s is word-aligned. */ |
aligned_addr = (unsigned long *) s; |
/* Store D into each char sized location in BUFFER so that |
we can set large blocks quickly. */ |
buffer = (d << 8) | d; |
buffer |= (buffer << 16); |
for (i = 32; i < LBLOCKSIZE * 8; i <<= 1) |
buffer = (buffer << i) | buffer; |
/* Unroll the loop. */ |
while (n >= LBLOCKSIZE*4) |
{ |
*aligned_addr++ = buffer; |
*aligned_addr++ = buffer; |
*aligned_addr++ = buffer; |
*aligned_addr++ = buffer; |
n -= 4*LBLOCKSIZE; |
} |
while (n >= LBLOCKSIZE) |
{ |
*aligned_addr++ = buffer; |
n -= LBLOCKSIZE; |
} |
/* Pick up the remainder with a bytewise loop. */ |
s = (char*)aligned_addr; |
} |
#endif /* not PREFER_SIZE_OVER_SPEED */ |
while (n--) |
*s++ = (char) c; |
return m; |
} |
/contrib/sdk/sources/libc/string/stpcpy.c |
---|
0,0 → 1,91 |
/* |
FUNCTION |
<<stpcpy>>---copy string returning a pointer to its end |
INDEX |
stpcpy |
ANSI_SYNOPSIS |
#include <string.h> |
char *stpcpy(char *<[dst]>, const char *<[src]>); |
TRAD_SYNOPSIS |
#include <string.h> |
char *stpcpy(<[dst]>, <[src]>) |
char *<[dst]>; |
char *<[src]>; |
DESCRIPTION |
<<stpcpy>> copies the string pointed to by <[src]> |
(including the terminating null character) to the array |
pointed to by <[dst]>. |
RETURNS |
This function returns a pointer to the end of the destination string, |
thus pointing to the trailing '\0'. |
PORTABILITY |
<<stpcpy>> is a GNU extension, candidate for inclusion into POSIX/SUSv4. |
<<stpcpy>> requires no supporting OS subroutines. |
QUICKREF |
stpcpy gnu |
*/ |
#include <string.h> |
#include <limits.h> |
/*SUPPRESS 560*/ |
/*SUPPRESS 530*/ |
/* Nonzero if either X or Y is not aligned on a "long" boundary. */ |
#define UNALIGNED(X, Y) \ |
(((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) |
#if LONG_MAX == 2147483647L |
#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080) |
#else |
#if LONG_MAX == 9223372036854775807L |
/* Nonzero if X (a long int) contains a NULL byte. */ |
#define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080) |
#else |
#error long int is not a 32bit or 64bit type. |
#endif |
#endif |
#ifndef DETECTNULL |
#error long int is not a 32bit or 64bit byte |
#endif |
char* |
_DEFUN (stpcpy, (dst, src), |
char *dst _AND |
_CONST char *src) |
{ |
#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) |
long *aligned_dst; |
_CONST long *aligned_src; |
/* If SRC or DEST is unaligned, then copy bytes. */ |
if (!UNALIGNED (src, dst)) |
{ |
aligned_dst = (long*)dst; |
aligned_src = (long*)src; |
/* SRC and DEST are both "long int" aligned, try to do "long int" |
sized copies. */ |
while (!DETECTNULL(*aligned_src)) |
{ |
*aligned_dst++ = *aligned_src++; |
} |
dst = (char*)aligned_dst; |
src = (char*)aligned_src; |
} |
#endif /* not PREFER_SIZE_OVER_SPEED */ |
while ((*dst++ = *src++)) |
; |
return --dst; |
} |
/contrib/sdk/sources/libc/string/stpncpy.c |
---|
0,0 → 1,114 |
/* |
FUNCTION |
<<stpncpy>>---counted copy string returning a pointer to its end |
INDEX |
stpncpy |
ANSI_SYNOPSIS |
#include <string.h> |
char *stpncpy(char *<[dst]>, const char *<[src]>, size_t <[length]>); |
TRAD_SYNOPSIS |
#include <string.h> |
char *stpncpy(<[dst]>, <[src]>, <[length]>) |
char *<[dst]>; |
char *<[src]>; |
size_t <[length]>; |
DESCRIPTION |
<<stpncpy>> copies not more than <[length]> characters from the |
the string pointed to by <[src]> (including the terminating |
null character) to the array pointed to by <[dst]>. If the |
string pointed to by <[src]> is shorter than <[length]> |
characters, null characters are appended to the destination |
array until a total of <[length]> characters have been |
written. |
RETURNS |
This function returns a pointer to the end of the destination string, |
thus pointing to the trailing '\0', or, if the destination string is |
not null-terminated, pointing to dst + n. |
PORTABILITY |
<<stpncpy>> is a GNU extension, candidate for inclusion into POSIX/SUSv4. |
<<stpncpy>> requires no supporting OS subroutines. |
QUICKREF |
stpncpy gnu |
*/ |
#include <string.h> |
#include <limits.h> |
/*SUPPRESS 560*/ |
/*SUPPRESS 530*/ |
/* Nonzero if either X or Y is not aligned on a "long" boundary. */ |
#define UNALIGNED(X, Y) \ |
(((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) |
#if LONG_MAX == 2147483647L |
#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080) |
#else |
#if LONG_MAX == 9223372036854775807L |
/* Nonzero if X (a long int) contains a NULL byte. */ |
#define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080) |
#else |
#error long int is not a 32bit or 64bit type. |
#endif |
#endif |
#ifndef DETECTNULL |
#error long int is not a 32bit or 64bit byte |
#endif |
#define TOO_SMALL(LEN) ((LEN) < sizeof (long)) |
char * |
_DEFUN (stpncpy, (dst, src), |
char *dst _AND |
_CONST char *src _AND |
size_t count) |
{ |
char *ret = NULL; |
#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) |
long *aligned_dst; |
_CONST long *aligned_src; |
/* If SRC and DEST is aligned and count large enough, then copy words. */ |
if (!UNALIGNED (src, dst) && !TOO_SMALL (count)) |
{ |
aligned_dst = (long*)dst; |
aligned_src = (long*)src; |
/* SRC and DEST are both "long int" aligned, try to do "long int" |
sized copies. */ |
while (count >= sizeof (long int) && !DETECTNULL(*aligned_src)) |
{ |
count -= sizeof (long int); |
*aligned_dst++ = *aligned_src++; |
} |
dst = (char*)aligned_dst; |
src = (char*)aligned_src; |
} |
#endif /* not PREFER_SIZE_OVER_SPEED */ |
while (count > 0) |
{ |
--count; |
if ((*dst++ = *src++) == '\0') |
{ |
ret = dst - 1; |
break; |
} |
} |
while (count-- > 0) |
*dst++ = '\0'; |
return ret ? ret : dst; |
} |
/contrib/sdk/sources/libc/string/str-two-way.h |
---|
0,0 → 1,415 |
/* Byte-wise substring search, using the Two-Way algorithm. |
* Copyright (C) 2008, 2010 Eric Blake |
* Permission to use, copy, modify, and distribute this software |
* is freely granted, provided that this notice is preserved. |
*/ |
/* Before including this file, you need to include <string.h>, and define: |
RESULT_TYPE A macro that expands to the return type. |
AVAILABLE(h, h_l, j, n_l) A macro that returns nonzero if there are |
at least N_L bytes left starting at |
H[J]. H is 'unsigned char *', H_L, J, |
and N_L are 'size_t'; H_L is an |
lvalue. For NUL-terminated searches, |
H_L can be modified each iteration to |
avoid having to compute the end of H |
up front. |
For case-insensitivity, you may optionally define: |
CMP_FUNC(p1, p2, l) A macro that returns 0 iff the first L |
characters of P1 and P2 are equal. |
CANON_ELEMENT(c) A macro that canonicalizes an element |
right after it has been fetched from |
one of the two strings. The argument |
is an 'unsigned char'; the result must |
be an 'unsigned char' as well. |
This file undefines the macros documented above, and defines |
LONG_NEEDLE_THRESHOLD. |
*/ |
#include <limits.h> |
#include <stdint.h> |
/* We use the Two-Way string matching algorithm, which guarantees |
linear complexity with constant space. Additionally, for long |
needles, we also use a bad character shift table similar to the |
Boyer-Moore algorithm to achieve improved (potentially sub-linear) |
performance. |
See http://www-igm.univ-mlv.fr/~lecroq/string/node26.html#SECTION00260 |
and http://en.wikipedia.org/wiki/Boyer-Moore_string_search_algorithm |
*/ |
/* Point at which computing a bad-byte shift table is likely to be |
worthwhile. Small needles should not compute a table, since it |
adds (1 << CHAR_BIT) + NEEDLE_LEN computations of preparation for a |
speedup no greater than a factor of NEEDLE_LEN. The larger the |
needle, the better the potential performance gain. On the other |
hand, on non-POSIX systems with CHAR_BIT larger than eight, the |
memory required for the table is prohibitive. */ |
#if CHAR_BIT < 10 |
# define LONG_NEEDLE_THRESHOLD 32U |
#else |
# define LONG_NEEDLE_THRESHOLD SIZE_MAX |
#endif |
#define MAX(a, b) ((a < b) ? (b) : (a)) |
#ifndef CANON_ELEMENT |
# define CANON_ELEMENT(c) c |
#endif |
#ifndef CMP_FUNC |
# define CMP_FUNC memcmp |
#endif |
/* Perform a critical factorization of NEEDLE, of length NEEDLE_LEN. |
Return the index of the first byte in the right half, and set |
*PERIOD to the global period of the right half. |
The global period of a string is the smallest index (possibly its |
length) at which all remaining bytes in the string are repetitions |
of the prefix (the last repetition may be a subset of the prefix). |
When NEEDLE is factored into two halves, a local period is the |
length of the smallest word that shares a suffix with the left half |
and shares a prefix with the right half. All factorizations of a |
non-empty NEEDLE have a local period of at least 1 and no greater |
than NEEDLE_LEN. |
A critical factorization has the property that the local period |
equals the global period. All strings have at least one critical |
factorization with the left half smaller than the global period. |
Given an ordered alphabet, a critical factorization can be computed |
in linear time, with 2 * NEEDLE_LEN comparisons, by computing the |
larger of two ordered maximal suffixes. The ordered maximal |
suffixes are determined by lexicographic comparison of |
periodicity. */ |
static size_t |
critical_factorization (const unsigned char *needle, size_t needle_len, |
size_t *period) |
{ |
/* Index of last byte of left half, or SIZE_MAX. */ |
size_t max_suffix, max_suffix_rev; |
size_t j; /* Index into NEEDLE for current candidate suffix. */ |
size_t k; /* Offset into current period. */ |
size_t p; /* Intermediate period. */ |
unsigned char a, b; /* Current comparison bytes. */ |
/* Invariants: |
0 <= j < NEEDLE_LEN - 1 |
-1 <= max_suffix{,_rev} < j (treating SIZE_MAX as if it were signed) |
min(max_suffix, max_suffix_rev) < global period of NEEDLE |
1 <= p <= global period of NEEDLE |
p == global period of the substring NEEDLE[max_suffix{,_rev}+1...j] |
1 <= k <= p |
*/ |
/* Perform lexicographic search. */ |
max_suffix = SIZE_MAX; |
j = 0; |
k = p = 1; |
while (j + k < needle_len) |
{ |
a = CANON_ELEMENT (needle[j + k]); |
b = CANON_ELEMENT (needle[(size_t)(max_suffix + k)]); |
if (a < b) |
{ |
/* Suffix is smaller, period is entire prefix so far. */ |
j += k; |
k = 1; |
p = j - max_suffix; |
} |
else if (a == b) |
{ |
/* Advance through repetition of the current period. */ |
if (k != p) |
++k; |
else |
{ |
j += p; |
k = 1; |
} |
} |
else /* b < a */ |
{ |
/* Suffix is larger, start over from current location. */ |
max_suffix = j++; |
k = p = 1; |
} |
} |
*period = p; |
/* Perform reverse lexicographic search. */ |
max_suffix_rev = SIZE_MAX; |
j = 0; |
k = p = 1; |
while (j + k < needle_len) |
{ |
a = CANON_ELEMENT (needle[j + k]); |
b = CANON_ELEMENT (needle[max_suffix_rev + k]); |
if (b < a) |
{ |
/* Suffix is smaller, period is entire prefix so far. */ |
j += k; |
k = 1; |
p = j - max_suffix_rev; |
} |
else if (a == b) |
{ |
/* Advance through repetition of the current period. */ |
if (k != p) |
++k; |
else |
{ |
j += p; |
k = 1; |
} |
} |
else /* a < b */ |
{ |
/* Suffix is larger, start over from current location. */ |
max_suffix_rev = j++; |
k = p = 1; |
} |
} |
/* Choose the longer suffix. Return the first byte of the right |
half, rather than the last byte of the left half. */ |
if (max_suffix_rev + 1 < max_suffix + 1) |
return max_suffix + 1; |
*period = p; |
return max_suffix_rev + 1; |
} |
/* Return the first location of non-empty NEEDLE within HAYSTACK, or |
NULL. HAYSTACK_LEN is the minimum known length of HAYSTACK. This |
method is optimized for NEEDLE_LEN < LONG_NEEDLE_THRESHOLD. |
Performance is guaranteed to be linear, with an initialization cost |
of 2 * NEEDLE_LEN comparisons. |
If AVAILABLE does not modify HAYSTACK_LEN (as in memmem), then at |
most 2 * HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching. |
If AVAILABLE modifies HAYSTACK_LEN (as in strstr), then at most 3 * |
HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching. */ |
static RETURN_TYPE |
two_way_short_needle (const unsigned char *haystack, size_t haystack_len, |
const unsigned char *needle, size_t needle_len) |
{ |
size_t i; /* Index into current byte of NEEDLE. */ |
size_t j; /* Index into current window of HAYSTACK. */ |
size_t period; /* The period of the right half of needle. */ |
size_t suffix; /* The index of the right half of needle. */ |
/* Factor the needle into two halves, such that the left half is |
smaller than the global period, and the right half is |
periodic (with a period as large as NEEDLE_LEN - suffix). */ |
suffix = critical_factorization (needle, needle_len, &period); |
/* Perform the search. Each iteration compares the right half |
first. */ |
if (CMP_FUNC (needle, needle + period, suffix) == 0) |
{ |
/* Entire needle is periodic; a mismatch can only advance by the |
period, so use memory to avoid rescanning known occurrences |
of the period. */ |
size_t memory = 0; |
j = 0; |
while (AVAILABLE (haystack, haystack_len, j, needle_len)) |
{ |
/* Scan for matches in right half. */ |
i = MAX (suffix, memory); |
while (i < needle_len && (CANON_ELEMENT (needle[i]) |
== CANON_ELEMENT (haystack[i + j]))) |
++i; |
if (needle_len <= i) |
{ |
/* Scan for matches in left half. */ |
i = suffix - 1; |
while (memory < i + 1 && (CANON_ELEMENT (needle[i]) |
== CANON_ELEMENT (haystack[i + j]))) |
--i; |
if (i + 1 < memory + 1) |
return (RETURN_TYPE) (haystack + j); |
/* No match, so remember how many repetitions of period |
on the right half were scanned. */ |
j += period; |
memory = needle_len - period; |
} |
else |
{ |
j += i - suffix + 1; |
memory = 0; |
} |
} |
} |
else |
{ |
/* The two halves of needle are distinct; no extra memory is |
required, and any mismatch results in a maximal shift. */ |
period = MAX (suffix, needle_len - suffix) + 1; |
j = 0; |
while (AVAILABLE (haystack, haystack_len, j, needle_len)) |
{ |
/* Scan for matches in right half. */ |
i = suffix; |
while (i < needle_len && (CANON_ELEMENT (needle[i]) |
== CANON_ELEMENT (haystack[i + j]))) |
++i; |
if (needle_len <= i) |
{ |
/* Scan for matches in left half. */ |
i = suffix - 1; |
while (i != SIZE_MAX && (CANON_ELEMENT (needle[i]) |
== CANON_ELEMENT (haystack[i + j]))) |
--i; |
if (i == SIZE_MAX) |
return (RETURN_TYPE) (haystack + j); |
j += period; |
} |
else |
j += i - suffix + 1; |
} |
} |
return NULL; |
} |
/* Return the first location of non-empty NEEDLE within HAYSTACK, or |
NULL. HAYSTACK_LEN is the minimum known length of HAYSTACK. This |
method is optimized for LONG_NEEDLE_THRESHOLD <= NEEDLE_LEN. |
Performance is guaranteed to be linear, with an initialization cost |
of 3 * NEEDLE_LEN + (1 << CHAR_BIT) operations. |
If AVAILABLE does not modify HAYSTACK_LEN (as in memmem), then at |
most 2 * HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching, |
and sublinear performance O(HAYSTACK_LEN / NEEDLE_LEN) is possible. |
If AVAILABLE modifies HAYSTACK_LEN (as in strstr), then at most 3 * |
HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching, and |
sublinear performance is not possible. */ |
static RETURN_TYPE |
two_way_long_needle (const unsigned char *haystack, size_t haystack_len, |
const unsigned char *needle, size_t needle_len) |
{ |
size_t i; /* Index into current byte of NEEDLE. */ |
size_t j; /* Index into current window of HAYSTACK. */ |
size_t period; /* The period of the right half of needle. */ |
size_t suffix; /* The index of the right half of needle. */ |
size_t shift_table[1U << CHAR_BIT]; /* See below. */ |
/* Factor the needle into two halves, such that the left half is |
smaller than the global period, and the right half is |
periodic (with a period as large as NEEDLE_LEN - suffix). */ |
suffix = critical_factorization (needle, needle_len, &period); |
/* Populate shift_table. For each possible byte value c, |
shift_table[c] is the distance from the last occurrence of c to |
the end of NEEDLE, or NEEDLE_LEN if c is absent from the NEEDLE. |
shift_table[NEEDLE[NEEDLE_LEN - 1]] contains the only 0. */ |
for (i = 0; i < 1U << CHAR_BIT; i++) |
shift_table[i] = needle_len; |
for (i = 0; i < needle_len; i++) |
shift_table[CANON_ELEMENT (needle[i])] = needle_len - i - 1; |
/* Perform the search. Each iteration compares the right half |
first. */ |
if (CMP_FUNC (needle, needle + period, suffix) == 0) |
{ |
/* Entire needle is periodic; a mismatch can only advance by the |
period, so use memory to avoid rescanning known occurrences |
of the period. */ |
size_t memory = 0; |
size_t shift; |
j = 0; |
while (AVAILABLE (haystack, haystack_len, j, needle_len)) |
{ |
/* Check the last byte first; if it does not match, then |
shift to the next possible match location. */ |
shift = shift_table[CANON_ELEMENT (haystack[j + needle_len - 1])]; |
if (0 < shift) |
{ |
if (memory && shift < period) |
{ |
/* Since needle is periodic, but the last period has |
a byte out of place, there can be no match until |
after the mismatch. */ |
shift = needle_len - period; |
} |
memory = 0; |
j += shift; |
continue; |
} |
/* Scan for matches in right half. The last byte has |
already been matched, by virtue of the shift table. */ |
i = MAX (suffix, memory); |
while (i < needle_len - 1 && (CANON_ELEMENT (needle[i]) |
== CANON_ELEMENT (haystack[i + j]))) |
++i; |
if (needle_len - 1 <= i) |
{ |
/* Scan for matches in left half. */ |
i = suffix - 1; |
while (memory < i + 1 && (CANON_ELEMENT (needle[i]) |
== CANON_ELEMENT (haystack[i + j]))) |
--i; |
if (i + 1 < memory + 1) |
return (RETURN_TYPE) (haystack + j); |
/* No match, so remember how many repetitions of period |
on the right half were scanned. */ |
j += period; |
memory = needle_len - period; |
} |
else |
{ |
j += i - suffix + 1; |
memory = 0; |
} |
} |
} |
else |
{ |
/* The two halves of needle are distinct; no extra memory is |
required, and any mismatch results in a maximal shift. */ |
size_t shift; |
period = MAX (suffix, needle_len - suffix) + 1; |
j = 0; |
while (AVAILABLE (haystack, haystack_len, j, needle_len)) |
{ |
/* Check the last byte first; if it does not match, then |
shift to the next possible match location. */ |
shift = shift_table[CANON_ELEMENT (haystack[j + needle_len - 1])]; |
if (0 < shift) |
{ |
j += shift; |
continue; |
} |
/* Scan for matches in right half. The last byte has |
already been matched, by virtue of the shift table. */ |
i = suffix; |
while (i < needle_len - 1 && (CANON_ELEMENT (needle[i]) |
== CANON_ELEMENT (haystack[i + j]))) |
++i; |
if (needle_len - 1 <= i) |
{ |
/* Scan for matches in left half. */ |
i = suffix - 1; |
while (i != SIZE_MAX && (CANON_ELEMENT (needle[i]) |
== CANON_ELEMENT (haystack[i + j]))) |
--i; |
if (i == SIZE_MAX) |
return (RETURN_TYPE) (haystack + j); |
j += period; |
} |
else |
j += i - suffix + 1; |
} |
} |
return NULL; |
} |
#undef AVAILABLE |
#undef CANON_ELEMENT |
#undef CMP_FUNC |
#undef MAX |
#undef RETURN_TYPE |
/contrib/sdk/sources/libc/string/strcasecmp.c |
---|
0,0 → 1,60 |
/* |
FUNCTION |
<<strcasecmp>>---case-insensitive character string compare |
INDEX |
strcasecmp |
ANSI_SYNOPSIS |
#include <strings.h> |
int strcasecmp(const char *<[a]>, const char *<[b]>); |
TRAD_SYNOPSIS |
#include <strings.h> |
int strcasecmp(<[a]>, <[b]>) |
char *<[a]>; |
char *<[b]>; |
DESCRIPTION |
<<strcasecmp>> compares the string at <[a]> to |
the string at <[b]> in a case-insensitive manner. |
RETURNS |
If <<*<[a]>>> sorts lexicographically after <<*<[b]>>> (after |
both are converted to lowercase), <<strcasecmp>> returns a |
number greater than zero. If the two strings match, |
<<strcasecmp>> returns zero. If <<*<[a]>>> sorts |
lexicographically before <<*<[b]>>>, <<strcasecmp>> returns a |
number less than zero. |
PORTABILITY |
<<strcasecmp>> is in the Berkeley Software Distribution. |
<<strcasecmp>> requires no supporting OS subroutines. It uses |
tolower() from elsewhere in this library. |
QUICKREF |
strcasecmp |
*/ |
#include <strings.h> |
#include <ctype.h> |
int |
_DEFUN (strcasecmp, (s1, s2), |
_CONST char *s1 _AND |
_CONST char *s2) |
{ |
_CONST unsigned char *ucs1 = (_CONST unsigned char *) s1; |
_CONST unsigned char *ucs2 = (_CONST unsigned char *) s2; |
int d = 0; |
for ( ; ; ) |
{ |
_CONST int c1 = tolower(*ucs1++); |
_CONST int c2 = tolower(*ucs2++); |
if (((d = c1 - c2) != 0) || (c2 == '\0')) |
break; |
} |
return d; |
} |
/contrib/sdk/sources/libc/string/strcasestr.c |
---|
0,0 → 1,148 |
/* |
FUNCTION |
<<strcasestr>>---case-insensitive character string search |
INDEX |
strcasestr |
ANSI_SYNOPSIS |
#include <string.h> |
char *strcasestr(const char *<[s]>, const char *<[find]>); |
TRAD_SYNOPSIS |
#include <string.h> |
int strcasecmp(<[s]>, <[find]>) |
char *<[s]>; |
char *<[find]>; |
DESCRIPTION |
<<strcasestr>> searchs the string <[s]> for |
the first occurrence of the sequence <[find]>. <<strcasestr>> |
is identical to <<strstr>> except the search is |
case-insensitive. |
RETURNS |
A pointer to the first case-insensitive occurrence of the sequence |
<[find]> or <<NULL>> if no match was found. |
PORTABILITY |
<<strcasestr>> is in the Berkeley Software Distribution. |
<<strcasestr>> requires no supporting OS subroutines. It uses |
tolower() from elsewhere in this library. |
QUICKREF |
strcasestr |
*/ |
/*- |
* Copyright (c) 1990, 1993 |
* The Regents of the University of California. All rights reserved. |
* |
* The quadratic code is derived from software contributed to Berkeley by |
* Chris Torek. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
*/ |
/* Linear algorithm Copyright (C) 2008 Eric Blake |
* Permission to use, copy, modify, and distribute the linear portion of |
* software is freely granted, provided that this notice is preserved. |
*/ |
#include <sys/cdefs.h> |
#include <ctype.h> |
#include <string.h> |
#include <strings.h> |
#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) |
# define RETURN_TYPE char * |
# define AVAILABLE(h, h_l, j, n_l) \ |
(!memchr ((h) + (h_l), '\0', (j) + (n_l) - (h_l)) \ |
&& ((h_l) = (j) + (n_l))) |
# define CANON_ELEMENT(c) tolower (c) |
# define CMP_FUNC strncasecmp |
# include "str-two-way.h" |
#endif |
/* |
* Find the first occurrence of find in s, ignore case. |
*/ |
char * |
strcasestr(s, find) |
const char *s, *find; |
{ |
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) |
/* Less code size, but quadratic performance in the worst case. */ |
char c, sc; |
size_t len; |
if ((c = *find++) != 0) { |
c = tolower((unsigned char)c); |
len = strlen(find); |
do { |
do { |
if ((sc = *s++) == 0) |
return (NULL); |
} while ((char)tolower((unsigned char)sc) != c); |
} while (strncasecmp(s, find, len) != 0); |
s--; |
} |
return ((char *)s); |
#else /* compilation for speed */ |
/* Larger code size, but guaranteed linear performance. */ |
const char *haystack = s; |
const char *needle = find; |
size_t needle_len; /* Length of NEEDLE. */ |
size_t haystack_len; /* Known minimum length of HAYSTACK. */ |
int ok = 1; /* True if NEEDLE is prefix of HAYSTACK. */ |
/* Determine length of NEEDLE, and in the process, make sure |
HAYSTACK is at least as long (no point processing all of a long |
NEEDLE if HAYSTACK is too short). */ |
while (*haystack && *needle) |
ok &= (tolower ((unsigned char) *haystack++) |
== tolower ((unsigned char) *needle++)); |
if (*needle) |
return NULL; |
if (ok) |
return (char *) s; |
needle_len = needle - find; |
haystack = s + 1; |
haystack_len = needle_len - 1; |
/* Perform the search. */ |
if (needle_len < LONG_NEEDLE_THRESHOLD) |
return two_way_short_needle ((const unsigned char *) haystack, |
haystack_len, |
(const unsigned char *) find, needle_len); |
return two_way_long_needle ((const unsigned char *) haystack, haystack_len, |
(const unsigned char *) find, needle_len); |
#endif /* compilation for speed */ |
} |
/contrib/sdk/sources/libc/string/strcat.c |
---|
0,0 → 1,104 |
/* |
FUNCTION |
<<strcat>>---concatenate strings |
INDEX |
strcat |
ANSI_SYNOPSIS |
#include <string.h> |
char *strcat(char *<[dst]>, const char *<[src]>); |
TRAD_SYNOPSIS |
#include <string.h> |
char *strcat(<[dst]>, <[src]>) |
char *<[dst]>; |
char *<[src]>; |
DESCRIPTION |
<<strcat>> appends a copy of the string pointed to by <[src]> |
(including the terminating null character) to the end of the |
string pointed to by <[dst]>. The initial character of |
<[src]> overwrites the null character at the end of <[dst]>. |
RETURNS |
This function returns the initial value of <[dst]> |
PORTABILITY |
<<strcat>> is ANSI C. |
<<strcat>> requires no supporting OS subroutines. |
QUICKREF |
strcat ansi pure |
*/ |
#include <string.h> |
#include <limits.h> |
/* Nonzero if X is aligned on a "long" boundary. */ |
#define ALIGNED(X) \ |
(((long)X & (sizeof (long) - 1)) == 0) |
#if LONG_MAX == 2147483647L |
#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080) |
#else |
#if LONG_MAX == 9223372036854775807L |
/* Nonzero if X (a long int) contains a NULL byte. */ |
#define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080) |
#else |
#error long int is not a 32bit or 64bit type. |
#endif |
#endif |
#ifndef DETECTNULL |
#error long int is not a 32bit or 64bit byte |
#endif |
/*SUPPRESS 560*/ |
/*SUPPRESS 530*/ |
char * |
_DEFUN (strcat, (s1, s2), |
char *s1 _AND |
_CONST char *s2) |
{ |
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) |
char *s = s1; |
while (*s1) |
s1++; |
while (*s1++ = *s2++) |
; |
return s; |
#else |
char *s = s1; |
/* Skip over the data in s1 as quickly as possible. */ |
if (ALIGNED (s1)) |
{ |
unsigned long *aligned_s1 = (unsigned long *)s1; |
while (!DETECTNULL (*aligned_s1)) |
aligned_s1++; |
s1 = (char *)aligned_s1; |
} |
while (*s1) |
s1++; |
/* s1 now points to the its trailing null character, we can |
just use strcpy to do the work for us now. |
?!? We might want to just include strcpy here. |
Also, this will cause many more unaligned string copies because |
s1 is much less likely to be aligned. I don't know if its worth |
tweaking strcpy to handle this better. */ |
strcpy (s1, s2); |
return s; |
#endif /* not PREFER_SIZE_OVER_SPEED */ |
} |
/contrib/sdk/sources/libc/string/strchr.c |
---|
0,0 → 1,123 |
/* |
FUNCTION |
<<strchr>>---search for character in string |
INDEX |
strchr |
ANSI_SYNOPSIS |
#include <string.h> |
char * strchr(const char *<[string]>, int <[c]>); |
TRAD_SYNOPSIS |
#include <string.h> |
char * strchr(<[string]>, <[c]>); |
const char *<[string]>; |
int <[c]>; |
DESCRIPTION |
This function finds the first occurence of <[c]> (converted to |
a char) in the string pointed to by <[string]> (including the |
terminating null character). |
RETURNS |
Returns a pointer to the located character, or a null pointer |
if <[c]> does not occur in <[string]>. |
PORTABILITY |
<<strchr>> is ANSI C. |
<<strchr>> requires no supporting OS subroutines. |
QUICKREF |
strchr ansi pure |
*/ |
#include <string.h> |
#include <limits.h> |
/* Nonzero if X is not aligned on a "long" boundary. */ |
#define UNALIGNED(X) ((long)X & (sizeof (long) - 1)) |
/* How many bytes are loaded each iteration of the word copy loop. */ |
#define LBLOCKSIZE (sizeof (long)) |
#if LONG_MAX == 2147483647L |
#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080) |
#else |
#if LONG_MAX == 9223372036854775807L |
/* Nonzero if X (a long int) contains a NULL byte. */ |
#define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080) |
#else |
#error long int is not a 32bit or 64bit type. |
#endif |
#endif |
/* DETECTCHAR returns nonzero if (long)X contains the byte used |
to fill (long)MASK. */ |
#define DETECTCHAR(X,MASK) (DETECTNULL(X ^ MASK)) |
char * |
_DEFUN (strchr, (s1, i), |
_CONST char *s1 _AND |
int i) |
{ |
_CONST unsigned char *s = (_CONST unsigned char *)s1; |
unsigned char c = i; |
#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) |
unsigned long mask,j; |
unsigned long *aligned_addr; |
/* Special case for finding 0. */ |
if (!c) |
{ |
while (UNALIGNED (s)) |
{ |
if (!*s) |
return (char *) s; |
s++; |
} |
/* Operate a word at a time. */ |
aligned_addr = (unsigned long *) s; |
while (!DETECTNULL (*aligned_addr)) |
aligned_addr++; |
/* Found the end of string. */ |
s = (const unsigned char *) aligned_addr; |
while (*s) |
s++; |
return (char *) s; |
} |
/* All other bytes. Align the pointer, then search a long at a time. */ |
while (UNALIGNED (s)) |
{ |
if (!*s) |
return NULL; |
if (*s == c) |
return (char *) s; |
s++; |
} |
mask = c; |
for (j = 8; j < LBLOCKSIZE * 8; j <<= 1) |
mask = (mask << j) | mask; |
aligned_addr = (unsigned long *) s; |
while (!DETECTNULL (*aligned_addr) && !DETECTCHAR (*aligned_addr, mask)) |
aligned_addr++; |
/* The block of bytes currently pointed to by aligned_addr |
contains either a null or the target char, or both. We |
catch it using the bytewise search. */ |
s = (unsigned char *) aligned_addr; |
#endif /* not PREFER_SIZE_OVER_SPEED */ |
while (*s && *s != c) |
s++; |
if (*s == c) |
return (char *)s; |
return NULL; |
} |
/contrib/sdk/sources/libc/string/strcmp.c |
---|
0,0 → 1,106 |
/* |
FUNCTION |
<<strcmp>>---character string compare |
INDEX |
strcmp |
ANSI_SYNOPSIS |
#include <string.h> |
int strcmp(const char *<[a]>, const char *<[b]>); |
TRAD_SYNOPSIS |
#include <string.h> |
int strcmp(<[a]>, <[b]>) |
char *<[a]>; |
char *<[b]>; |
DESCRIPTION |
<<strcmp>> compares the string at <[a]> to |
the string at <[b]>. |
RETURNS |
If <<*<[a]>>> sorts lexicographically after <<*<[b]>>>, |
<<strcmp>> returns a number greater than zero. If the two |
strings match, <<strcmp>> returns zero. If <<*<[a]>>> |
sorts lexicographically before <<*<[b]>>>, <<strcmp>> returns a |
number less than zero. |
PORTABILITY |
<<strcmp>> is ANSI C. |
<<strcmp>> requires no supporting OS subroutines. |
QUICKREF |
strcmp ansi pure |
*/ |
#include <string.h> |
#include <limits.h> |
/* Nonzero if either X or Y is not aligned on a "long" boundary. */ |
#define UNALIGNED(X, Y) \ |
(((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) |
/* DETECTNULL returns nonzero if (long)X contains a NULL byte. */ |
#if LONG_MAX == 2147483647L |
#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080) |
#else |
#if LONG_MAX == 9223372036854775807L |
#define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080) |
#else |
#error long int is not a 32bit or 64bit type. |
#endif |
#endif |
#ifndef DETECTNULL |
#error long int is not a 32bit or 64bit byte |
#endif |
int |
_DEFUN (strcmp, (s1, s2), |
_CONST char *s1 _AND |
_CONST char *s2) |
{ |
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) |
while (*s1 != '\0' && *s1 == *s2) |
{ |
s1++; |
s2++; |
} |
return (*(unsigned char *) s1) - (*(unsigned char *) s2); |
#else |
unsigned long *a1; |
unsigned long *a2; |
/* If s1 or s2 are unaligned, then compare bytes. */ |
if (!UNALIGNED (s1, s2)) |
{ |
/* If s1 and s2 are word-aligned, compare them a word at a time. */ |
a1 = (unsigned long*)s1; |
a2 = (unsigned long*)s2; |
while (*a1 == *a2) |
{ |
/* To get here, *a1 == *a2, thus if we find a null in *a1, |
then the strings must be equal, so return zero. */ |
if (DETECTNULL (*a1)) |
return 0; |
a1++; |
a2++; |
} |
/* A difference was detected in last few bytes of s1, so search bytewise */ |
s1 = (char*)a1; |
s2 = (char*)a2; |
} |
while (*s1 != '\0' && *s1 == *s2) |
{ |
s1++; |
s2++; |
} |
return (*(unsigned char *) s1) - (*(unsigned char *) s2); |
#endif /* not PREFER_SIZE_OVER_SPEED */ |
} |
/contrib/sdk/sources/libc/string/strcoll.c |
---|
0,0 → 1,48 |
/* |
FUNCTION |
<<strcoll>>---locale-specific character string compare |
INDEX |
strcoll |
ANSI_SYNOPSIS |
#include <string.h> |
int strcoll(const char *<[stra]>, const char * <[strb]>); |
TRAD_SYNOPSIS |
#include <string.h> |
int strcoll(<[stra]>, <[strb]>) |
char *<[stra]>; |
char *<[strb]>; |
DESCRIPTION |
<<strcoll>> compares the string pointed to by <[stra]> to |
the string pointed to by <[strb]>, using an interpretation |
appropriate to the current <<LC_COLLATE>> state. |
RETURNS |
If the first string is greater than the second string, |
<<strcoll>> returns a number greater than zero. If the two |
strings are equivalent, <<strcoll>> returns zero. If the first |
string is less than the second string, <<strcoll>> returns a |
number less than zero. |
PORTABILITY |
<<strcoll>> is ANSI C. |
<<strcoll>> requires no supporting OS subroutines. |
QUICKREF |
strcoll ansi pure |
*/ |
#include <string.h> |
int |
_DEFUN (strcoll, (a, b), |
_CONST char *a _AND |
_CONST char *b) |
{ |
return strcmp (a, b); |
} |
/contrib/sdk/sources/libc/string/strcpy.c |
---|
0,0 → 1,99 |
/* |
FUNCTION |
<<strcpy>>---copy string |
INDEX |
strcpy |
ANSI_SYNOPSIS |
#include <string.h> |
char *strcpy(char *<[dst]>, const char *<[src]>); |
TRAD_SYNOPSIS |
#include <string.h> |
char *strcpy(<[dst]>, <[src]>) |
char *<[dst]>; |
char *<[src]>; |
DESCRIPTION |
<<strcpy>> copies the string pointed to by <[src]> |
(including the terminating null character) to the array |
pointed to by <[dst]>. |
RETURNS |
This function returns the initial value of <[dst]>. |
PORTABILITY |
<<strcpy>> is ANSI C. |
<<strcpy>> requires no supporting OS subroutines. |
QUICKREF |
strcpy ansi pure |
*/ |
#include <string.h> |
#include <limits.h> |
/*SUPPRESS 560*/ |
/*SUPPRESS 530*/ |
/* Nonzero if either X or Y is not aligned on a "long" boundary. */ |
#define UNALIGNED(X, Y) \ |
(((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) |
#if LONG_MAX == 2147483647L |
#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080) |
#else |
#if LONG_MAX == 9223372036854775807L |
/* Nonzero if X (a long int) contains a NULL byte. */ |
#define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080) |
#else |
#error long int is not a 32bit or 64bit type. |
#endif |
#endif |
#ifndef DETECTNULL |
#error long int is not a 32bit or 64bit byte |
#endif |
char* |
_DEFUN (strcpy, (dst0, src0), |
char *dst0 _AND |
_CONST char *src0) |
{ |
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) |
char *s = dst0; |
while (*dst0++ = *src0++) |
; |
return s; |
#else |
char *dst = dst0; |
_CONST char *src = src0; |
long *aligned_dst; |
_CONST long *aligned_src; |
/* If SRC or DEST is unaligned, then copy bytes. */ |
if (!UNALIGNED (src, dst)) |
{ |
aligned_dst = (long*)dst; |
aligned_src = (long*)src; |
/* SRC and DEST are both "long int" aligned, try to do "long int" |
sized copies. */ |
while (!DETECTNULL(*aligned_src)) |
{ |
*aligned_dst++ = *aligned_src++; |
} |
dst = (char*)aligned_dst; |
src = (char*)aligned_src; |
} |
while ((*dst++ = *src++)) |
; |
return dst0; |
#endif /* not PREFER_SIZE_OVER_SPEED */ |
} |
/contrib/sdk/sources/libc/string/strcspn.c |
---|
0,0 → 1,54 |
/* |
FUNCTION |
<<strcspn>>---count characters not in string |
INDEX |
strcspn |
ANSI_SYNOPSIS |
size_t strcspn(const char *<[s1]>, const char *<[s2]>); |
TRAD_SYNOPSIS |
size_t strcspn(<[s1]>, <[s2]>) |
char *<[s1]>; |
char *<[s2]>; |
DESCRIPTION |
This function computes the length of the initial part of |
the string pointed to by <[s1]> which consists entirely of |
characters <[NOT]> from the string pointed to by <[s2]> |
(excluding the terminating null character). |
RETURNS |
<<strcspn>> returns the length of the substring found. |
PORTABILITY |
<<strcspn>> is ANSI C. |
<<strcspn>> requires no supporting OS subroutines. |
*/ |
#include <string.h> |
size_t |
_DEFUN (strcspn, (s1, s2), |
_CONST char *s1 _AND |
_CONST char *s2) |
{ |
_CONST char *s = s1; |
_CONST char *c; |
while (*s1) |
{ |
for (c = s2; *c; c++) |
{ |
if (*s1 == *c) |
break; |
} |
if (*c) |
break; |
s1++; |
} |
return s1 - s; |
} |
/contrib/sdk/sources/libc/string/strdup.c |
---|
0,0 → 1,13 |
#ifndef _REENT_ONLY |
#include <reent.h> |
#include <stdlib.h> |
#include <string.h> |
char * |
_DEFUN (strdup, (str), _CONST char *str) |
{ |
return _strdup_r (_REENT, str); |
} |
#endif /* !_REENT_ONLY */ |
/contrib/sdk/sources/libc/string/strdup_r.c |
---|
0,0 → 1,17 |
#include <reent.h> |
#include <stdlib.h> |
#include <string.h> |
char * |
_DEFUN (_strdup_r, (reent_ptr, str), |
struct _reent *reent_ptr _AND |
_CONST char *str) |
{ |
size_t len = strlen (str) + 1; |
char *copy = _malloc_r (reent_ptr, len); |
if (copy) |
{ |
memcpy (copy, str, len); |
} |
return copy; |
} |
/contrib/sdk/sources/libc/string/strerror.c |
---|
0,0 → 1,838 |
/*** |
**** CAUTION!!! KEEP DOC CONSISTENT---if you change text of a message |
**** here, change two places: |
**** 1) the leading doc section (alphabetized by macro) |
**** 2) the real text inside switch(errnum) |
***/ |
/* |
FUNCTION |
<<strerror>>---convert error number to string |
INDEX |
strerror |
ANSI_SYNOPSIS |
#include <string.h> |
char *strerror(int <[errnum]>); |
char *_strerror_r(struct _reent <[ptr]>, int <[errnum]>, |
int <[internal]>, int *<[error]>); |
TRAD_SYNOPSIS |
#include <string.h> |
char *strerror(<[errnum]>) |
int <[errnum]>; |
DESCRIPTION |
<<strerror>> converts the error number <[errnum]> into a |
string. The value of <[errnum]> is usually a copy of <<errno>>. |
If <<errnum>> is not a known error number, the result points to an |
empty string. |
This implementation of <<strerror>> prints out the following strings |
for each of the values defined in `<<errno.h>>': |
o+ |
o 0 |
Success |
o E2BIG |
Arg list too long |
o EACCES |
Permission denied |
o EADDRINUSE |
Address already in use |
o EADV |
Advertise error |
o EAFNOSUPPORT |
Address family not supported by protocol family |
o EAGAIN |
No more processes |
o EALREADY |
Socket already connected |
o EBADF |
Bad file number |
o EBADMSG |
Bad message |
o EBUSY |
Device or resource busy |
o ECHILD |
No children |
o ECOMM |
Communication error |
o ECONNABORTED |
Software caused connection abort |
o ECONNREFUSED |
Connection refused |
o EDEADLK |
Deadlock |
o EDESTADDRREQ |
Destination address required |
o EEXIST |
File exists |
o EDOM |
Math argument |
o EFAULT |
Bad address |
o EFBIG |
File too large |
o EHOSTDOWN |
Host is down |
o EHOSTUNREACH |
Host is unreachable |
o EIDRM |
Identifier removed |
o EINPROGRESS |
Connection already in progress |
o EINTR |
Interrupted system call |
o EINVAL |
Invalid argument |
o EIO |
I/O error |
o EISCONN |
Socket is already connected |
o EISDIR |
Is a directory |
o ELIBACC |
Cannot access a needed shared library |
o ELIBBAD |
Accessing a corrupted shared library |
o ELIBEXEC |
Cannot exec a shared library directly |
o ELIBMAX |
Attempting to link in more shared libraries than system limit |
o ELIBSCN |
<<.lib>> section in a.out corrupted |
o EMFILE |
Too many open files |
o EMLINK |
Too many links |
o EMSGSIZE |
Message too long |
o EMULTIHOP |
Multihop attempted |
o ENAMETOOLONG |
File or path name too long |
o ENETDOWN |
Network interface not configured |
o ENETUNREACH |
Network is unreachable |
o ENFILE |
Too many open files in system |
o ENODEV |
No such device |
o ENOENT |
No such file or directory |
o ENOEXEC |
Exec format error |
o ENOLCK |
No lock |
o ENOLINK |
Virtual circuit is gone |
o ENOMEM |
Not enough space |
o ENOMSG |
No message of desired type |
o ENONET |
Machine is not on the network |
o ENOPKG |
No package |
o ENOPROTOOPT |
Protocol not available |
o ENOSPC |
No space left on device |
o ENOSR |
No stream resources |
o ENOSTR |
Not a stream |
o ENOSYS |
Function not implemented |
o ENOTBLK |
Block device required |
o ENOTCONN |
Socket is not connected |
o ENOTDIR |
Not a directory |
o ENOTEMPTY |
Directory not empty |
o ENOTSOCK |
Socket operation on non-socket |
o ENOTSUP |
Not supported |
o ENOTTY |
Not a character device |
o ENXIO |
No such device or address |
o EPERM |
Not owner |
o EPIPE |
Broken pipe |
o EPROTO |
Protocol error |
o EPROTOTYPE |
Protocol wrong type for socket |
o EPROTONOSUPPORT |
Unknown protocol |
o ERANGE |
Result too large |
o EREMOTE |
Resource is remote |
o EROFS |
Read-only file system |
o ESHUTDOWN |
Can't send after socket shutdown |
o ESOCKTNOSUPPORT |
Socket type not supported |
o ESPIPE |
Illegal seek |
o ESRCH |
No such process |
o ESRMNT |
Srmount error |
o ETIME |
Stream ioctl timeout |
o ETIMEDOUT |
Connection timed out |
o ETXTBSY |
Text file busy |
o EXDEV |
Cross-device link |
o ECANCELED |
Operation canceled |
o ENOTRECOVERABLE |
State not recoverable |
o EOWNERDEAD |
Previous owner died |
o ESTRPIPE |
Strings pipe error |
o- |
<<_strerror_r>> is a reentrant version of the above. |
RETURNS |
This function returns a pointer to a string. Your application must |
not modify that string. |
PORTABILITY |
ANSI C requires <<strerror>>, but does not specify the strings used |
for each error number. |
Although this implementation of <<strerror>> is reentrant (depending |
on <<_user_strerror>>), ANSI C declares that subsequent calls to |
<<strerror>> may overwrite the result string; therefore portable |
code cannot depend on the reentrancy of this subroutine. |
Although this implementation of <<strerror>> guarantees a non-null |
result with a NUL-terminator, some implementations return <<NULL>> |
on failure. Although POSIX allows <<strerror>> to set <<errno>> |
to EINVAL on failure, this implementation does not do so (unless |
you provide <<_user_strerror>>). |
POSIX recommends that unknown <[errnum]> result in a message |
including that value, however it is not a requirement and this |
implementation does not provide that information (unless you |
provide <<_user_strerror>>). |
This implementation of <<strerror>> provides for user-defined |
extensibility. <<errno.h>> defines <[__ELASTERROR]>, which can be |
used as a base for user-defined error values. If the user supplies a |
routine named <<_user_strerror>>, and <[errnum]> passed to |
<<strerror>> does not match any of the supported values, |
<<_user_strerror>> is called with three arguments. The first is of |
type <[int]>, and is the <[errnum]> value unknown to <<strerror>>. |
The second is of type <[int]>, and matches the <[internal]> argument |
of <<_strerror_r>>; this should be zero if called from <<strerror>> |
and non-zero if called from any other function; <<_user_strerror>> can |
use this information to satisfy the POSIX rule that no other |
standardized function can overwrite a static buffer reused by |
<<strerror>>. The third is of type <[int *]>, and matches the |
<[error]> argument of <<_strerror_r>>; if a non-zero value is stored |
into that location (usually <[EINVAL]>), then <<strerror>> will set |
<<errno>> to that value, and the XPG variant of <<strerror_r>> will |
return that value instead of zero or <[ERANGE]>. <<_user_strerror>> |
returns a <[char *]> value; returning <[NULL]> implies that the user |
function did not choose to handle <[errnum]>. The default |
<<_user_strerror>> returns <[NULL]> for all input values. Note that |
<<_user_sterror>> must be thread-safe, and only denote errors via the |
third argument rather than modifying <<errno>>, if <<strerror>> and |
<<strerror_r>> are are to comply with POSIX. |
<<strerror>> requires no supporting OS subroutines. |
QUICKREF |
strerror ansi pure |
*/ |
#include <errno.h> |
#include <string.h> |
char * |
_DEFUN (_strerror_r, (ptr, errnum, internal, errptr), |
struct _reent *ptr _AND |
int errnum _AND |
int internal _AND |
int *errptr) |
{ |
char *error; |
extern char *_user_strerror _PARAMS ((int, int, int *)); |
switch (errnum) |
{ |
case 0: |
error = "Success"; |
break; |
/* go32 defines EPERM as EACCES */ |
#if defined (EPERM) && (!defined (EACCES) || (EPERM != EACCES)) |
case EPERM: |
error = "Not owner"; |
break; |
#endif |
#ifdef ENOENT |
case ENOENT: |
error = "No such file or directory"; |
break; |
#endif |
#ifdef ESRCH |
case ESRCH: |
error = "No such process"; |
break; |
#endif |
#ifdef EINTR |
case EINTR: |
error = "Interrupted system call"; |
break; |
#endif |
#ifdef EIO |
case EIO: |
error = "I/O error"; |
break; |
#endif |
/* go32 defines ENXIO as ENODEV */ |
#if defined (ENXIO) && (!defined (ENODEV) || (ENXIO != ENODEV)) |
case ENXIO: |
error = "No such device or address"; |
break; |
#endif |
#ifdef E2BIG |
case E2BIG: |
error = "Arg list too long"; |
break; |
#endif |
#ifdef ENOEXEC |
case ENOEXEC: |
error = "Exec format error"; |
break; |
#endif |
#ifdef EALREADY |
case EALREADY: |
error = "Socket already connected"; |
break; |
#endif |
#ifdef EBADF |
case EBADF: |
error = "Bad file number"; |
break; |
#endif |
#ifdef ECHILD |
case ECHILD: |
error = "No children"; |
break; |
#endif |
#ifdef EDESTADDRREQ |
case EDESTADDRREQ: |
error = "Destination address required"; |
break; |
#endif |
#ifdef EAGAIN |
case EAGAIN: |
error = "No more processes"; |
break; |
#endif |
#ifdef ENOMEM |
case ENOMEM: |
error = "Not enough space"; |
break; |
#endif |
#ifdef EACCES |
case EACCES: |
error = "Permission denied"; |
break; |
#endif |
#ifdef EFAULT |
case EFAULT: |
error = "Bad address"; |
break; |
#endif |
#ifdef ENOTBLK |
case ENOTBLK: |
error = "Block device required"; |
break; |
#endif |
#ifdef EBUSY |
case EBUSY: |
error = "Device or resource busy"; |
break; |
#endif |
#ifdef EEXIST |
case EEXIST: |
error = "File exists"; |
break; |
#endif |
#ifdef EXDEV |
case EXDEV: |
error = "Cross-device link"; |
break; |
#endif |
#ifdef ENODEV |
case ENODEV: |
error = "No such device"; |
break; |
#endif |
#ifdef ENOTDIR |
case ENOTDIR: |
error = "Not a directory"; |
break; |
#endif |
#ifdef EHOSTDOWN |
case EHOSTDOWN: |
error = "Host is down"; |
break; |
#endif |
#ifdef EINPROGRESS |
case EINPROGRESS: |
error = "Connection already in progress"; |
break; |
#endif |
#ifdef EISDIR |
case EISDIR: |
error = "Is a directory"; |
break; |
#endif |
#ifdef EINVAL |
case EINVAL: |
error = "Invalid argument"; |
break; |
#endif |
#ifdef ENETDOWN |
case ENETDOWN: |
error = "Network interface is not configured"; |
break; |
#endif |
#ifdef ENFILE |
case ENFILE: |
error = "Too many open files in system"; |
break; |
#endif |
#ifdef EMFILE |
case EMFILE: |
error = "Too many open files"; |
break; |
#endif |
#ifdef ENOTTY |
case ENOTTY: |
error = "Not a character device"; |
break; |
#endif |
#ifdef ETXTBSY |
case ETXTBSY: |
error = "Text file busy"; |
break; |
#endif |
#ifdef EFBIG |
case EFBIG: |
error = "File too large"; |
break; |
#endif |
#ifdef EHOSTUNREACH |
case EHOSTUNREACH: |
error = "Host is unreachable"; |
break; |
#endif |
#ifdef ENOSPC |
case ENOSPC: |
error = "No space left on device"; |
break; |
#endif |
#ifdef ENOTSUP |
case ENOTSUP: |
error = "Not supported"; |
break; |
#endif |
#ifdef ESPIPE |
case ESPIPE: |
error = "Illegal seek"; |
break; |
#endif |
#ifdef EROFS |
case EROFS: |
error = "Read-only file system"; |
break; |
#endif |
#ifdef EMLINK |
case EMLINK: |
error = "Too many links"; |
break; |
#endif |
#ifdef EPIPE |
case EPIPE: |
error = "Broken pipe"; |
break; |
#endif |
#ifdef EDOM |
case EDOM: |
error = "Math argument"; |
break; |
#endif |
#ifdef ERANGE |
case ERANGE: |
error = "Result too large"; |
break; |
#endif |
#ifdef ENOMSG |
case ENOMSG: |
error = "No message of desired type"; |
break; |
#endif |
#ifdef EIDRM |
case EIDRM: |
error = "Identifier removed"; |
break; |
#endif |
#ifdef EDEADLK |
case EDEADLK: |
error = "Deadlock"; |
break; |
#endif |
#ifdef ENETUNREACH |
case ENETUNREACH: |
error = "Network is unreachable"; |
break; |
#endif |
#ifdef ENOLCK |
case ENOLCK: |
error = "No lock"; |
break; |
#endif |
#ifdef ENOSTR |
case ENOSTR: |
error = "Not a stream"; |
break; |
#endif |
#ifdef ETIME |
case ETIME: |
error = "Stream ioctl timeout"; |
break; |
#endif |
#ifdef ENOSR |
case ENOSR: |
error = "No stream resources"; |
break; |
#endif |
#ifdef ENONET |
case ENONET: |
error = "Machine is not on the network"; |
break; |
#endif |
#ifdef ENOPKG |
case ENOPKG: |
error = "No package"; |
break; |
#endif |
#ifdef EREMOTE |
case EREMOTE: |
error = "Resource is remote"; |
break; |
#endif |
#ifdef ENOLINK |
case ENOLINK: |
error = "Virtual circuit is gone"; |
break; |
#endif |
#ifdef EADV |
case EADV: |
error = "Advertise error"; |
break; |
#endif |
#ifdef ESRMNT |
case ESRMNT: |
error = "Srmount error"; |
break; |
#endif |
#ifdef ECOMM |
case ECOMM: |
error = "Communication error"; |
break; |
#endif |
#ifdef EPROTO |
case EPROTO: |
error = "Protocol error"; |
break; |
#endif |
#ifdef EPROTONOSUPPORT |
case EPROTONOSUPPORT: |
error = "Unknown protocol"; |
break; |
#endif |
#ifdef EMULTIHOP |
case EMULTIHOP: |
error = "Multihop attempted"; |
break; |
#endif |
#ifdef EBADMSG |
case EBADMSG: |
error = "Bad message"; |
break; |
#endif |
#ifdef ELIBACC |
case ELIBACC: |
error = "Cannot access a needed shared library"; |
break; |
#endif |
#ifdef ELIBBAD |
case ELIBBAD: |
error = "Accessing a corrupted shared library"; |
break; |
#endif |
#ifdef ELIBSCN |
case ELIBSCN: |
error = ".lib section in a.out corrupted"; |
break; |
#endif |
#ifdef ELIBMAX |
case ELIBMAX: |
error = "Attempting to link in more shared libraries than system limit"; |
break; |
#endif |
#ifdef ELIBEXEC |
case ELIBEXEC: |
error = "Cannot exec a shared library directly"; |
break; |
#endif |
#ifdef ENOSYS |
case ENOSYS: |
error = "Function not implemented"; |
break; |
#endif |
#ifdef ENMFILE |
case ENMFILE: |
error = "No more files"; |
break; |
#endif |
#ifdef ENOTEMPTY |
case ENOTEMPTY: |
error = "Directory not empty"; |
break; |
#endif |
#ifdef ENAMETOOLONG |
case ENAMETOOLONG: |
error = "File or path name too long"; |
break; |
#endif |
#ifdef ELOOP |
case ELOOP: |
error = "Too many symbolic links"; |
break; |
#endif |
#ifdef ENOBUFS |
case ENOBUFS: |
error = "No buffer space available"; |
break; |
#endif |
#ifdef EAFNOSUPPORT |
case EAFNOSUPPORT: |
error = "Address family not supported by protocol family"; |
break; |
#endif |
#ifdef EPROTOTYPE |
case EPROTOTYPE: |
error = "Protocol wrong type for socket"; |
break; |
#endif |
#ifdef ENOTSOCK |
case ENOTSOCK: |
error = "Socket operation on non-socket"; |
break; |
#endif |
#ifdef ENOPROTOOPT |
case ENOPROTOOPT: |
error = "Protocol not available"; |
break; |
#endif |
#ifdef ESHUTDOWN |
case ESHUTDOWN: |
error = "Can't send after socket shutdown"; |
break; |
#endif |
#ifdef ECONNREFUSED |
case ECONNREFUSED: |
error = "Connection refused"; |
break; |
#endif |
#ifdef EADDRINUSE |
case EADDRINUSE: |
error = "Address already in use"; |
break; |
#endif |
#ifdef ECONNABORTED |
case ECONNABORTED: |
error = "Software caused connection abort"; |
break; |
#endif |
#if (defined(EWOULDBLOCK) && (!defined (EAGAIN) || (EWOULDBLOCK != EAGAIN))) |
case EWOULDBLOCK: |
error = "Operation would block"; |
break; |
#endif |
#ifdef ENOTCONN |
case ENOTCONN: |
error = "Socket is not connected"; |
break; |
#endif |
#ifdef ESOCKTNOSUPPORT |
case ESOCKTNOSUPPORT: |
error = "Socket type not supported"; |
break; |
#endif |
#ifdef EISCONN |
case EISCONN: |
error = "Socket is already connected"; |
break; |
#endif |
#ifdef ECANCELED |
case ECANCELED: |
error = "Operation canceled"; |
break; |
#endif |
#ifdef ENOTRECOVERABLE |
case ENOTRECOVERABLE: |
error = "State not recoverable"; |
break; |
#endif |
#ifdef EOWNERDEAD |
case EOWNERDEAD: |
error = "Previous owner died"; |
break; |
#endif |
#ifdef ESTRPIPE |
case ESTRPIPE: |
error = "Streams pipe error"; |
break; |
#endif |
#if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (ENOTSUP != EOPNOTSUPP)) |
case EOPNOTSUPP: |
error = "Operation not supported on socket"; |
break; |
#endif |
#ifdef EMSGSIZE |
case EMSGSIZE: |
error = "Message too long"; |
break; |
#endif |
#ifdef ETIMEDOUT |
case ETIMEDOUT: |
error = "Connection timed out"; |
break; |
#endif |
default: |
if (!errptr) |
errptr = &ptr->_errno; |
if ((error = _user_strerror (errnum, internal, errptr)) == 0) |
error = ""; |
break; |
} |
return error; |
} |
char * |
_DEFUN(strerror, (int), |
int errnum) |
{ |
return _strerror_r (_REENT, errnum, 0, NULL); |
} |
/contrib/sdk/sources/libc/string/strlen.c |
---|
0,0 → 1,88 |
/* |
FUNCTION |
<<strlen>>---character string length |
INDEX |
strlen |
ANSI_SYNOPSIS |
#include <string.h> |
size_t strlen(const char *<[str]>); |
TRAD_SYNOPSIS |
#include <string.h> |
size_t strlen(<[str]>) |
char *<[src]>; |
DESCRIPTION |
The <<strlen>> function works out the length of the string |
starting at <<*<[str]>>> by counting chararacters until it |
reaches a <<NULL>> character. |
RETURNS |
<<strlen>> returns the character count. |
PORTABILITY |
<<strlen>> is ANSI C. |
<<strlen>> requires no supporting OS subroutines. |
QUICKREF |
strlen ansi pure |
*/ |
#include <_ansi.h> |
#include <string.h> |
#include <limits.h> |
#define LBLOCKSIZE (sizeof (long)) |
#define UNALIGNED(X) ((long)X & (LBLOCKSIZE - 1)) |
#if LONG_MAX == 2147483647L |
#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080) |
#else |
#if LONG_MAX == 9223372036854775807L |
/* Nonzero if X (a long int) contains a NULL byte. */ |
#define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080) |
#else |
#error long int is not a 32bit or 64bit type. |
#endif |
#endif |
#ifndef DETECTNULL |
#error long int is not a 32bit or 64bit byte |
#endif |
size_t |
_DEFUN (strlen, (str), |
_CONST char *str) |
{ |
_CONST char *start = str; |
#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) |
unsigned long *aligned_addr; |
/* Align the pointer, so we can search a word at a time. */ |
while (UNALIGNED (str)) |
{ |
if (!*str) |
return str - start; |
str++; |
} |
/* If the string is word-aligned, we can check for the presence of |
a null in each word-sized block. */ |
aligned_addr = (unsigned long *)str; |
while (!DETECTNULL (*aligned_addr)) |
aligned_addr++; |
/* Once a null is detected, we check each byte in that block for a |
precise position of the null. */ |
str = (char *) aligned_addr; |
#endif /* not PREFER_SIZE_OVER_SPEED */ |
while (*str) |
str++; |
return str - start; |
} |
/contrib/sdk/sources/libc/string/strncasecmp.c |
---|
0,0 → 1,63 |
/* |
FUNCTION |
<<strncasecmp>>---case-insensitive character string compare |
INDEX |
strncasecmp |
ANSI_SYNOPSIS |
#include <strings.h> |
int strncasecmp(const char *<[a]>, const char * <[b]>, size_t <[length]>); |
TRAD_SYNOPSIS |
#include <strings.h> |
int strncasecmp(<[a]>, <[b]>, <[length]>) |
char *<[a]>; |
char *<[b]>; |
size_t <[length]> |
DESCRIPTION |
<<strncasecmp>> compares up to <[length]> characters |
from the string at <[a]> to the string at <[b]> in a |
case-insensitive manner. |
RETURNS |
If <<*<[a]>>> sorts lexicographically after <<*<[b]>>> (after |
both are converted to lowercase), <<strncasecmp>> returns a |
number greater than zero. If the two strings are equivalent, |
<<strncasecmp>> returns zero. If <<*<[a]>>> sorts |
lexicographically before <<*<[b]>>>, <<strncasecmp>> returns a |
number less than zero. |
PORTABILITY |
<<strncasecmp>> is in the Berkeley Software Distribution. |
<<strncasecmp>> requires no supporting OS subroutines. It uses |
tolower() from elsewhere in this library. |
QUICKREF |
strncasecmp |
*/ |
#include <strings.h> |
#include <ctype.h> |
int |
_DEFUN (strncasecmp, (s1, s2, n), |
_CONST char *s1 _AND |
_CONST char *s2 _AND |
size_t n) |
{ |
_CONST unsigned char *ucs1 = (_CONST unsigned char *) s1; |
_CONST unsigned char *ucs2 = (_CONST unsigned char *) s2; |
int d = 0; |
for ( ; n != 0; n--) |
{ |
_CONST int c1 = tolower(*ucs1++); |
_CONST int c2 = tolower(*ucs2++); |
if (((d = c1 - c2) != 0) || (c2 == '\0')) |
break; |
} |
return d; |
} |
/contrib/sdk/sources/libc/string/strncat.c |
---|
0,0 → 1,114 |
/* |
FUNCTION |
<<strncat>>---concatenate strings |
INDEX |
strncat |
ANSI_SYNOPSIS |
#include <string.h> |
char *strncat(char *<[dst]>, const char *<[src]>, size_t <[length]>); |
TRAD_SYNOPSIS |
#include <string.h> |
char *strncat(<[dst]>, <[src]>, <[length]>) |
char *<[dst]>; |
char *<[src]>; |
size_t <[length]>; |
DESCRIPTION |
<<strncat>> appends not more than <[length]> characters from |
the string pointed to by <[src]> (including the terminating |
null character) to the end of the string pointed to by |
<[dst]>. The initial character of <[src]> overwrites the null |
character at the end of <[dst]>. A terminating null character |
is always appended to the result |
WARNINGS |
Note that a null is always appended, so that if the copy is |
limited by the <[length]> argument, the number of characters |
appended to <[dst]> is <<n + 1>>. |
RETURNS |
This function returns the initial value of <[dst]> |
PORTABILITY |
<<strncat>> is ANSI C. |
<<strncat>> requires no supporting OS subroutines. |
QUICKREF |
strncat ansi pure |
*/ |
#include <string.h> |
#include <limits.h> |
/* Nonzero if X is aligned on a "long" boundary. */ |
#define ALIGNED(X) \ |
(((long)X & (sizeof (long) - 1)) == 0) |
#if LONG_MAX == 2147483647L |
#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080) |
#else |
#if LONG_MAX == 9223372036854775807L |
/* Nonzero if X (a long int) contains a NULL byte. */ |
#define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080) |
#else |
#error long int is not a 32bit or 64bit type. |
#endif |
#endif |
#ifndef DETECTNULL |
#error long int is not a 32bit or 64bit byte |
#endif |
char * |
_DEFUN (strncat, (s1, s2, n), |
char *s1 _AND |
_CONST char *s2 _AND |
size_t n) |
{ |
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) |
char *s = s1; |
while (*s1) |
s1++; |
while (n-- != 0 && (*s1++ = *s2++)) |
{ |
if (n == 0) |
*s1 = '\0'; |
} |
return s; |
#else |
char *s = s1; |
/* Skip over the data in s1 as quickly as possible. */ |
if (ALIGNED (s1)) |
{ |
unsigned long *aligned_s1 = (unsigned long *)s1; |
while (!DETECTNULL (*aligned_s1)) |
aligned_s1++; |
s1 = (char *)aligned_s1; |
} |
while (*s1) |
s1++; |
/* s1 now points to the its trailing null character, now copy |
up to N bytes from S2 into S1 stopping if a NULL is encountered |
in S2. |
It is not safe to use strncpy here since it copies EXACTLY N |
characters, NULL padding if necessary. */ |
while (n-- != 0 && (*s1++ = *s2++)) |
{ |
if (n == 0) |
*s1 = '\0'; |
} |
return s; |
#endif /* not PREFER_SIZE_OVER_SPEED */ |
} |
/contrib/sdk/sources/libc/string/strncmp.c |
---|
0,0 → 1,122 |
/* |
FUNCTION |
<<strncmp>>---character string compare |
INDEX |
strncmp |
ANSI_SYNOPSIS |
#include <string.h> |
int strncmp(const char *<[a]>, const char * <[b]>, size_t <[length]>); |
TRAD_SYNOPSIS |
#include <string.h> |
int strncmp(<[a]>, <[b]>, <[length]>) |
char *<[a]>; |
char *<[b]>; |
size_t <[length]> |
DESCRIPTION |
<<strncmp>> compares up to <[length]> characters |
from the string at <[a]> to the string at <[b]>. |
RETURNS |
If <<*<[a]>>> sorts lexicographically after <<*<[b]>>>, |
<<strncmp>> returns a number greater than zero. If the two |
strings are equivalent, <<strncmp>> returns zero. If <<*<[a]>>> |
sorts lexicographically before <<*<[b]>>>, <<strncmp>> returns a |
number less than zero. |
PORTABILITY |
<<strncmp>> is ANSI C. |
<<strncmp>> requires no supporting OS subroutines. |
QUICKREF |
strncmp ansi pure |
*/ |
#include <string.h> |
#include <limits.h> |
/* Nonzero if either X or Y is not aligned on a "long" boundary. */ |
#define UNALIGNED(X, Y) \ |
(((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) |
/* DETECTNULL returns nonzero if (long)X contains a NULL byte. */ |
#if LONG_MAX == 2147483647L |
#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080) |
#else |
#if LONG_MAX == 9223372036854775807L |
#define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080) |
#else |
#error long int is not a 32bit or 64bit type. |
#endif |
#endif |
#ifndef DETECTNULL |
#error long int is not a 32bit or 64bit byte |
#endif |
int |
_DEFUN (strncmp, (s1, s2, n), |
_CONST char *s1 _AND |
_CONST char *s2 _AND |
size_t n) |
{ |
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) |
if (n == 0) |
return 0; |
while (n-- != 0 && *s1 == *s2) |
{ |
if (n == 0 || *s1 == '\0') |
break; |
s1++; |
s2++; |
} |
return (*(unsigned char *) s1) - (*(unsigned char *) s2); |
#else |
unsigned long *a1; |
unsigned long *a2; |
if (n == 0) |
return 0; |
/* If s1 or s2 are unaligned, then compare bytes. */ |
if (!UNALIGNED (s1, s2)) |
{ |
/* If s1 and s2 are word-aligned, compare them a word at a time. */ |
a1 = (unsigned long*)s1; |
a2 = (unsigned long*)s2; |
while (n >= sizeof (long) && *a1 == *a2) |
{ |
n -= sizeof (long); |
/* If we've run out of bytes or hit a null, return zero |
since we already know *a1 == *a2. */ |
if (n == 0 || DETECTNULL (*a1)) |
return 0; |
a1++; |
a2++; |
} |
/* A difference was detected in last few bytes of s1, so search bytewise */ |
s1 = (char*)a1; |
s2 = (char*)a2; |
} |
while (n-- > 0 && *s1 == *s2) |
{ |
/* If we've run out of bytes or hit a null, return zero |
since we already know *s1 == *s2. */ |
if (n == 0 || *s1 == '\0') |
return 0; |
s1++; |
s2++; |
} |
return (*(unsigned char *) s1) - (*(unsigned char *) s2); |
#endif /* not PREFER_SIZE_OVER_SPEED */ |
} |
/contrib/sdk/sources/libc/string/strncpy.c |
---|
0,0 → 1,125 |
/* |
FUNCTION |
<<strncpy>>---counted copy string |
INDEX |
strncpy |
ANSI_SYNOPSIS |
#include <string.h> |
char *strncpy(char *<[dst]>, const char *<[src]>, size_t <[length]>); |
TRAD_SYNOPSIS |
#include <string.h> |
char *strncpy(<[dst]>, <[src]>, <[length]>) |
char *<[dst]>; |
char *<[src]>; |
size_t <[length]>; |
DESCRIPTION |
<<strncpy>> copies not more than <[length]> characters from the |
the string pointed to by <[src]> (including the terminating |
null character) to the array pointed to by <[dst]>. If the |
string pointed to by <[src]> is shorter than <[length]> |
characters, null characters are appended to the destination |
array until a total of <[length]> characters have been |
written. |
RETURNS |
This function returns the initial value of <[dst]>. |
PORTABILITY |
<<strncpy>> is ANSI C. |
<<strncpy>> requires no supporting OS subroutines. |
QUICKREF |
strncpy ansi pure |
*/ |
#include <string.h> |
#include <limits.h> |
/*SUPPRESS 560*/ |
/*SUPPRESS 530*/ |
/* Nonzero if either X or Y is not aligned on a "long" boundary. */ |
#define UNALIGNED(X, Y) \ |
(((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) |
#if LONG_MAX == 2147483647L |
#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080) |
#else |
#if LONG_MAX == 9223372036854775807L |
/* Nonzero if X (a long int) contains a NULL byte. */ |
#define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080) |
#else |
#error long int is not a 32bit or 64bit type. |
#endif |
#endif |
#ifndef DETECTNULL |
#error long int is not a 32bit or 64bit byte |
#endif |
#define TOO_SMALL(LEN) ((LEN) < sizeof (long)) |
char * |
_DEFUN (strncpy, (dst0, src0), |
char *dst0 _AND |
_CONST char *src0 _AND |
size_t count) |
{ |
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) |
char *dscan; |
_CONST char *sscan; |
dscan = dst0; |
sscan = src0; |
while (count > 0) |
{ |
--count; |
if ((*dscan++ = *sscan++) == '\0') |
break; |
} |
while (count-- > 0) |
*dscan++ = '\0'; |
return dst0; |
#else |
char *dst = dst0; |
_CONST char *src = src0; |
long *aligned_dst; |
_CONST long *aligned_src; |
/* If SRC and DEST is aligned and count large enough, then copy words. */ |
if (!UNALIGNED (src, dst) && !TOO_SMALL (count)) |
{ |
aligned_dst = (long*)dst; |
aligned_src = (long*)src; |
/* SRC and DEST are both "long int" aligned, try to do "long int" |
sized copies. */ |
while (count >= sizeof (long int) && !DETECTNULL(*aligned_src)) |
{ |
count -= sizeof (long int); |
*aligned_dst++ = *aligned_src++; |
} |
dst = (char*)aligned_dst; |
src = (char*)aligned_src; |
} |
while (count > 0) |
{ |
--count; |
if ((*dst++ = *src++) == '\0') |
break; |
} |
while (count-- > 0) |
*dst++ = '\0'; |
return dst0; |
#endif /* not PREFER_SIZE_OVER_SPEED */ |
} |
/contrib/sdk/sources/libc/string/strndup.c |
---|
0,0 → 1,16 |
#ifndef _REENT_ONLY |
#include <_ansi.h> |
#include <reent.h> |
#include <stdlib.h> |
#include <string.h> |
char * |
_DEFUN (strndup, (str, n), |
_CONST char *str _AND |
size_t n) |
{ |
return _strndup_r (_REENT, str, n); |
} |
#endif /* !_REENT_ONLY */ |
/contrib/sdk/sources/libc/string/strndup_r.c |
---|
0,0 → 1,27 |
#include <reent.h> |
#include <stdlib.h> |
#include <string.h> |
char * |
_DEFUN (_strndup_r, (reent_ptr, str, n), |
struct _reent *reent_ptr _AND |
_CONST char *str _AND |
size_t n) |
{ |
_CONST char *ptr = str; |
size_t len; |
char *copy; |
while (n-- > 0 && *ptr) |
ptr++; |
len = ptr - str; |
copy = _malloc_r (reent_ptr, len + 1); |
if (copy) |
{ |
memcpy (copy, str, len); |
copy[len] = '\0'; |
} |
return copy; |
} |
/contrib/sdk/sources/libc/string/strnlen.c |
---|
0,0 → 1,49 |
/* |
FUNCTION |
<<strnlen>>---character string length |
INDEX |
strnlen |
ANSI_SYNOPSIS |
#include <string.h> |
size_t strnlen(const char *<[str]>, size_t <[n]>); |
TRAD_SYNOPSIS |
#include <string.h> |
size_t strnlen(<[str]>, <[n]>) |
char *<[src]>; |
size_t <[n]>; |
DESCRIPTION |
The <<strnlen>> function works out the length of the string |
starting at <<*<[str]>>> by counting chararacters until it |
reaches a NUL character or the maximum: <[n]> number of |
characters have been inspected. |
RETURNS |
<<strnlen>> returns the character count or <[n]>. |
PORTABILITY |
<<strnlen>> is a GNU extension. |
<<strnlen>> requires no supporting OS subroutines. |
*/ |
#undef __STRICT_ANSI__ |
#include <_ansi.h> |
#include <string.h> |
size_t |
_DEFUN (strnlen, (str, n), |
_CONST char *str _AND |
size_t n) |
{ |
_CONST char *start = str; |
while (n-- > 0 && *str) |
str++; |
return str - start; |
} |
/contrib/sdk/sources/libc/string/strpbrk.c |
---|
0,0 → 1,58 |
/* |
FUNCTION |
<<strpbrk>>---find characters in string |
INDEX |
strpbrk |
ANSI_SYNOPSIS |
#include <string.h> |
char *strpbrk(const char *<[s1]>, const char *<[s2]>); |
TRAD_SYNOPSIS |
#include <string.h> |
char *strpbrk(<[s1]>, <[s2]>) |
char *<[s1]>; |
char *<[s2]>; |
DESCRIPTION |
This function locates the first occurence in the string |
pointed to by <[s1]> of any character in string pointed to by |
<[s2]> (excluding the terminating null character). |
RETURNS |
<<strpbrk>> returns a pointer to the character found in <[s1]>, or a |
null pointer if no character from <[s2]> occurs in <[s1]>. |
PORTABILITY |
<<strpbrk>> requires no supporting OS subroutines. |
*/ |
#include <string.h> |
char * |
_DEFUN (strpbrk, (s1, s2), |
_CONST char *s1 _AND |
_CONST char *s2) |
{ |
_CONST char *c = s2; |
if (!*s1) |
return (char *) NULL; |
while (*s1) |
{ |
for (c = s2; *c; c++) |
{ |
if (*s1 == *c) |
break; |
} |
if (*c) |
break; |
s1++; |
} |
if (*c == '\0') |
s1 = NULL; |
return (char *) s1; |
} |
/contrib/sdk/sources/libc/string/strrchr.c |
---|
0,0 → 1,59 |
/* |
FUNCTION |
<<strrchr>>---reverse search for character in string |
INDEX |
strrchr |
ANSI_SYNOPSIS |
#include <string.h> |
char * strrchr(const char *<[string]>, int <[c]>); |
TRAD_SYNOPSIS |
#include <string.h> |
char * strrchr(<[string]>, <[c]>); |
char *<[string]>; |
int *<[c]>; |
DESCRIPTION |
This function finds the last occurence of <[c]> (converted to |
a char) in the string pointed to by <[string]> (including the |
terminating null character). |
RETURNS |
Returns a pointer to the located character, or a null pointer |
if <[c]> does not occur in <[string]>. |
PORTABILITY |
<<strrchr>> is ANSI C. |
<<strrchr>> requires no supporting OS subroutines. |
QUICKREF |
strrchr ansi pure |
*/ |
#include <string.h> |
char * |
_DEFUN (strrchr, (s, i), |
_CONST char *s _AND |
int i) |
{ |
_CONST char *last = NULL; |
if (i) |
{ |
while ((s=strchr(s, i))) |
{ |
last = s; |
s++; |
} |
} |
else |
{ |
last = strchr(s, i); |
} |
return (char *) last; |
} |
/contrib/sdk/sources/libc/string/strsep.c |
---|
0,0 → 1,19 |
/* BSD strsep function */ |
/* Copyright 2002, Red Hat Inc. */ |
/* undef STRICT_ANSI so that strsep prototype will be defined */ |
#undef __STRICT_ANSI__ |
#include <string.h> |
#include <_ansi.h> |
#include <reent.h> |
extern char *__strtok_r (char *, const char *, char **, int); |
char * |
_DEFUN (strsep, (source_ptr, delim), |
register char **source_ptr _AND |
register const char *delim) |
{ |
return __strtok_r (*source_ptr, delim, source_ptr, 0); |
} |
/contrib/sdk/sources/libc/string/strspn.c |
---|
0,0 → 1,59 |
/* |
FUNCTION |
<<strspn>>---find initial match |
INDEX |
strspn |
ANSI_SYNOPSIS |
#include <string.h> |
size_t strspn(const char *<[s1]>, const char *<[s2]>); |
TRAD_SYNOPSIS |
#include <string.h> |
size_t strspn(<[s1]>, <[s2]>) |
char *<[s1]>; |
char *<[s2]>; |
DESCRIPTION |
This function computes the length of the initial segment of |
the string pointed to by <[s1]> which consists entirely of |
characters from the string pointed to by <[s2]> (excluding the |
terminating null character). |
RETURNS |
<<strspn>> returns the length of the segment found. |
PORTABILITY |
<<strspn>> is ANSI C. |
<<strspn>> requires no supporting OS subroutines. |
QUICKREF |
strspn ansi pure |
*/ |
#include <string.h> |
size_t |
_DEFUN (strspn, (s1, s2), |
_CONST char *s1 _AND |
_CONST char *s2) |
{ |
_CONST char *s = s1; |
_CONST char *c; |
while (*s1) |
{ |
for (c = s2; *c; c++) |
{ |
if (*s1 == *c) |
break; |
} |
if (*c == '\0') |
break; |
s1++; |
} |
return s1 - s; |
} |
/contrib/sdk/sources/libc/string/strstr.c |
---|
0,0 → 1,121 |
/* |
FUNCTION |
<<strstr>>---find string segment |
INDEX |
strstr |
ANSI_SYNOPSIS |
#include <string.h> |
char *strstr(const char *<[s1]>, const char *<[s2]>); |
TRAD_SYNOPSIS |
#include <string.h> |
char *strstr(<[s1]>, <[s2]>) |
char *<[s1]>; |
char *<[s2]>; |
DESCRIPTION |
Locates the first occurrence in the string pointed to by <[s1]> of |
the sequence of characters in the string pointed to by <[s2]> |
(excluding the terminating null character). |
RETURNS |
Returns a pointer to the located string segment, or a null |
pointer if the string <[s2]> is not found. If <[s2]> points to |
a string with zero length, <[s1]> is returned. |
PORTABILITY |
<<strstr>> is ANSI C. |
<<strstr>> requires no supporting OS subroutines. |
QUICKREF |
strstr ansi pure |
*/ |
#include <string.h> |
#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) |
# define RETURN_TYPE char * |
# define AVAILABLE(h, h_l, j, n_l) \ |
(!memchr ((h) + (h_l), '\0', (j) + (n_l) - (h_l)) \ |
&& ((h_l) = (j) + (n_l))) |
# include "str-two-way.h" |
#endif |
char * |
_DEFUN (strstr, (searchee, lookfor), |
_CONST char *searchee _AND |
_CONST char *lookfor) |
{ |
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) |
/* Less code size, but quadratic performance in the worst case. */ |
if (*searchee == 0) |
{ |
if (*lookfor) |
return (char *) NULL; |
return (char *) searchee; |
} |
while (*searchee) |
{ |
size_t i; |
i = 0; |
while (1) |
{ |
if (lookfor[i] == 0) |
{ |
return (char *) searchee; |
} |
if (lookfor[i] != searchee[i]) |
{ |
break; |
} |
i++; |
} |
searchee++; |
} |
return (char *) NULL; |
#else /* compilation for speed */ |
/* Larger code size, but guaranteed linear performance. */ |
const char *haystack = searchee; |
const char *needle = lookfor; |
size_t needle_len; /* Length of NEEDLE. */ |
size_t haystack_len; /* Known minimum length of HAYSTACK. */ |
int ok = 1; /* True if NEEDLE is prefix of HAYSTACK. */ |
/* Determine length of NEEDLE, and in the process, make sure |
HAYSTACK is at least as long (no point processing all of a long |
NEEDLE if HAYSTACK is too short). */ |
while (*haystack && *needle) |
ok &= *haystack++ == *needle++; |
if (*needle) |
return NULL; |
if (ok) |
return (char *) searchee; |
/* Reduce the size of haystack using strchr, since it has a smaller |
linear coefficient than the Two-Way algorithm. */ |
needle_len = needle - lookfor; |
haystack = strchr (searchee + 1, *lookfor); |
if (!haystack || needle_len == 1) |
return (char *) haystack; |
haystack_len = (haystack > searchee + needle_len ? 1 |
: needle_len + searchee - haystack); |
/* Perform the search. */ |
if (needle_len < LONG_NEEDLE_THRESHOLD) |
return two_way_short_needle ((const unsigned char *) haystack, |
haystack_len, |
(const unsigned char *) lookfor, needle_len); |
return two_way_long_needle ((const unsigned char *) haystack, haystack_len, |
(const unsigned char *) lookfor, needle_len); |
#endif /* compilation for speed */ |
} |
/contrib/sdk/sources/libc/string/strtok.c |
---|
0,0 → 1,101 |
/* |
FUNCTION |
<<strtok>>, <<strtok_r>>, <<strsep>>---get next token from a string |
INDEX |
strtok |
INDEX |
strtok_r |
INDEX |
strsep |
ANSI_SYNOPSIS |
#include <string.h> |
char *strtok(char *<[source]>, const char *<[delimiters]>) |
char *strtok_r(char *<[source]>, const char *<[delimiters]>, |
char **<[lasts]>) |
char *strsep(char **<[source_ptr]>, const char *<[delimiters]>) |
TRAD_SYNOPSIS |
#include <string.h> |
char *strtok(<[source]>, <[delimiters]>) |
char *<[source]>; |
char *<[delimiters]>; |
char *strtok_r(<[source]>, <[delimiters]>, <[lasts]>) |
char *<[source]>; |
char *<[delimiters]>; |
char **<[lasts]>; |
char *strsep(<[source_ptr]>, <[delimiters]>) |
char **<[source_ptr]>; |
char *<[delimiters]>; |
DESCRIPTION |
The <<strtok>> function is used to isolate sequential tokens in a |
null-terminated string, <<*<[source]>>>. These tokens are delimited |
in the string by at least one of the characters in <<*<[delimiters]>>>. |
The first time that <<strtok>> is called, <<*<[source]>>> should be |
specified; subsequent calls, wishing to obtain further tokens from |
the same string, should pass a null pointer instead. The separator |
string, <<*<[delimiters]>>>, must be supplied each time and may |
change between calls. |
The <<strtok>> function returns a pointer to the beginning of each |
subsequent token in the string, after replacing the separator |
character itself with a null character. When no more tokens remain, |
a null pointer is returned. |
The <<strtok_r>> function has the same behavior as <<strtok>>, except |
a pointer to placeholder <<*<[lasts]>>> must be supplied by the caller. |
The <<strsep>> function is similar in behavior to <<strtok>>, except |
a pointer to the string pointer must be supplied <<<[source_ptr]>>> and |
the function does not skip leading delimiters. When the string starts |
with a delimiter, the delimiter is changed to the null character and |
the empty string is returned. Like <<strtok_r>> and <<strtok>>, the |
<<*<[source_ptr]>>> is updated to the next character following the |
last delimiter found or NULL if the end of string is reached with |
no more delimiters. |
RETURNS |
<<strtok>>, <<strtok_r>>, and <<strsep>> all return a pointer to the |
next token, or <<NULL>> if no more tokens can be found. For |
<<strsep>>, a token may be the empty string. |
NOTES |
<<strtok>> is unsafe for multi-threaded applications. <<strtok_r>> |
and <<strsep>> are thread-safe and should be used instead. |
PORTABILITY |
<<strtok>> is ANSI C. |
<<strtok_r>> is POSIX. |
<<strsep>> is a BSD extension. |
<<strtok>>, <<strtok_r>>, and <<strsep>> require no supporting OS subroutines. |
QUICKREF |
strtok ansi impure |
*/ |
/* undef STRICT_ANSI so that strtok_r prototype will be defined */ |
#undef __STRICT_ANSI__ |
#include <string.h> |
#include <_ansi.h> |
#include <reent.h> |
#ifndef _REENT_ONLY |
extern char *__strtok_r (char *, const char *, char **, int); |
char * |
_DEFUN (strtok, (s, delim), |
register char *s _AND |
register const char *delim) |
{ |
_REENT_CHECK_MISC(_REENT); |
return __strtok_r (s, delim, &(_REENT_STRTOK_LAST(_REENT)), 1); |
} |
#endif |
/contrib/sdk/sources/libc/string/strtok_r.c |
---|
0,0 → 1,99 |
/* |
* Copyright (c) 1988 Regents of the University of California. |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 3. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
*/ |
#include <string.h> |
char * |
_DEFUN (__strtok_r, (s, delim, lasts, skip_leading_delim), |
register char *s _AND |
register const char *delim _AND |
char **lasts _AND |
int skip_leading_delim) |
{ |
register char *spanp; |
register int c, sc; |
char *tok; |
if (s == NULL && (s = *lasts) == NULL) |
return (NULL); |
/* |
* Skip (span) leading delimiters (s += strspn(s, delim), sort of). |
*/ |
cont: |
c = *s++; |
for (spanp = (char *)delim; (sc = *spanp++) != 0;) { |
if (c == sc) { |
if (skip_leading_delim) { |
goto cont; |
} |
else { |
*lasts = s; |
s[-1] = 0; |
return (s - 1); |
} |
} |
} |
if (c == 0) { /* no non-delimiter characters */ |
*lasts = NULL; |
return (NULL); |
} |
tok = s - 1; |
/* |
* Scan token (scan for delimiters: s += strcspn(s, delim), sort of). |
* Note that delim must have one NUL; we stop if we see that, too. |
*/ |
for (;;) { |
c = *s++; |
spanp = (char *)delim; |
do { |
if ((sc = *spanp++) == c) { |
if (c == 0) |
s = NULL; |
else |
s[-1] = 0; |
*lasts = s; |
return (tok); |
} |
} while (sc != 0); |
} |
/* NOTREACHED */ |
} |
char * |
_DEFUN (strtok_r, (s, delim, lasts), |
register char *s _AND |
register const char *delim _AND |
char **lasts) |
{ |
return __strtok_r (s, delim, lasts, 1); |
} |
/contrib/sdk/sources/libc/string/strupr.c |
---|
0,0 → 1,46 |
/* |
FUNCTION |
<<strupr>>---force string to uppercase |
INDEX |
strupr |
ANSI_SYNOPSIS |
#include <string.h> |
char *strupr(char *<[a]>); |
TRAD_SYNOPSIS |
#include <string.h> |
char *strupr(<[a]>) |
char *<[a]>; |
DESCRIPTION |
<<strupr>> converts each character in the string at <[a]> to |
uppercase. |
RETURNS |
<<strupr>> returns its argument, <[a]>. |
PORTABILITY |
<<strupr>> is not widely portable. |
<<strupr>> requires no supporting OS subroutines. |
QUICKREF |
strupr |
*/ |
#include <string.h> |
#include <ctype.h> |
char * |
_DEFUN (strupr, (s), |
char *s) |
{ |
unsigned char *ucs = (unsigned char *) s; |
for ( ; *ucs != '\0'; ucs++) |
{ |
*ucs = toupper(*ucs); |
} |
return s; |
} |
/contrib/sdk/sources/libc/string/u_strerr.c |
---|
0,0 → 1,10 |
#include <_ansi.h> |
char * |
_DEFUN(_user_strerror, (errnum, internal, errptr), |
int errnum _AND |
int internal _AND |
int *errptr) |
{ |
return 0; |
} |
/contrib/sdk/sources/libc/string/vsprintf.c |
---|
0,0 → 1,1379 |
/* |
* linux/lib/vsprintf.c |
* |
* Copyright (C) 1991, 1992 Linus Torvalds |
*/ |
/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ |
/* |
* Wirzenius wrote this portably, Torvalds fucked it up :-) |
*/ |
/* |
* Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com> |
* - changed to provide snprintf and vsnprintf functions |
* So Feb 1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de> |
* - scnprintf and vscnprintf |
*/ |
#define likely(x) __builtin_expect(!!(x), 1) |
#define unlikely(x) __builtin_expect(!!(x), 0) |
#include <string.h> |
#include <ctype.h> |
#include <stdarg.h> |
#include <stdint.h> |
//#include <linux/module.h> |
//#include <types.h> |
//#include <linux/kernel.h> |
//#include <linux/kallsyms.h> |
//#include <linux/uaccess.h> |
//#include <linux/ioport.h> |
//#include <asm/page.h> /* for PAGE_SIZE */ |
//#include <asm/div64.h> |
//#include <asm/sections.h> /* for dereference_function_descriptor() */ |
#define do_div(n, base) \ |
({ \ |
unsigned long __upper, __low, __high, __mod, __base; \ |
__base = (base); \ |
asm("":"=a" (__low), "=d" (__high) : "A" (n)); \ |
__upper = __high; \ |
if (__high) { \ |
__upper = __high % (__base); \ |
__high = __high / (__base); \ |
} \ |
asm("divl %2":"=a" (__low), "=d" (__mod) \ |
: "rm" (__base), "0" (__low), "1" (__upper)); \ |
asm("":"=A" (n) : "a" (__low), "d" (__high)); \ |
__mod; \ |
}) |
#define EPERM 1 /* Operation not permitted */ |
#define ENOENT 2 /* No such file or directory */ |
#define ESRCH 3 /* No such process */ |
#define EINTR 4 /* Interrupted system call */ |
#define EIO 5 /* I/O error */ |
#define ENXIO 6 /* No such device or address */ |
#define E2BIG 7 /* Argument list too long */ |
#define ENOEXEC 8 /* Exec format error */ |
#define EBADF 9 /* Bad file number */ |
#define ECHILD 10 /* No child processes */ |
#define EAGAIN 11 /* Try again */ |
#define ENOMEM 12 /* Out of memory */ |
#define EACCES 13 /* Permission denied */ |
#define EFAULT 14 /* Bad address */ |
#define ENOTBLK 15 /* Block device required */ |
#define EBUSY 16 /* Device or resource busy */ |
#define EEXIST 17 /* File exists */ |
#define EXDEV 18 /* Cross-device link */ |
#define ENODEV 19 /* No such device */ |
#define ENOTDIR 20 /* Not a directory */ |
#define EISDIR 21 /* Is a directory */ |
#define EINVAL 22 /* Invalid argument */ |
#define ENFILE 23 /* File table overflow */ |
#define EMFILE 24 /* Too many open files */ |
#define ENOTTY 25 /* Not a typewriter */ |
#define ETXTBSY 26 /* Text file busy */ |
#define EFBIG 27 /* File too large */ |
#define ENOSPC 28 /* No space left on device */ |
#define ESPIPE 29 /* Illegal seek */ |
#define EROFS 30 /* Read-only file system */ |
#define EMLINK 31 /* Too many links */ |
#define EPIPE 32 /* Broken pipe */ |
#define EDOM 33 /* Math argument out of domain of func */ |
#define ERANGE 34 /* Math result not representable */ |
#define PAGE_SIZE 4096 |
/* Works only for digits and letters, but small and fast */ |
#define TOLOWER(x) ((x) | 0x20) |
static unsigned int simple_guess_base(const char *cp) |
{ |
if (cp[0] == '0') { |
if (TOLOWER(cp[1]) == 'x' && isxdigit(cp[2])) |
return 16; |
else |
return 8; |
} else { |
return 10; |
} |
} |
/** |
* simple_strtoul - convert a string to an unsigned long |
* @cp: The start of the string |
* @endp: A pointer to the end of the parsed string will be placed here |
* @base: The number base to use |
*/ |
unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base) |
{ |
unsigned long result = 0; |
if (!base) |
base = simple_guess_base(cp); |
if (base == 16 && cp[0] == '0' && TOLOWER(cp[1]) == 'x') |
cp += 2; |
while (isxdigit(*cp)) { |
unsigned int value; |
value = isdigit(*cp) ? *cp - '0' : TOLOWER(*cp) - 'a' + 10; |
if (value >= base) |
break; |
result = result * base + value; |
cp++; |
} |
if (endp) |
*endp = (char *)cp; |
return result; |
} |
/** |
* simple_strtol - convert a string to a signed long |
* @cp: The start of the string |
* @endp: A pointer to the end of the parsed string will be placed here |
* @base: The number base to use |
*/ |
long simple_strtol(const char *cp, char **endp, unsigned int base) |
{ |
if(*cp == '-') |
return -simple_strtoul(cp + 1, endp, base); |
return simple_strtoul(cp, endp, base); |
} |
/** |
* simple_strtoull - convert a string to an unsigned long long |
* @cp: The start of the string |
* @endp: A pointer to the end of the parsed string will be placed here |
* @base: The number base to use |
*/ |
unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base) |
{ |
unsigned long long result = 0; |
if (!base) |
base = simple_guess_base(cp); |
if (base == 16 && cp[0] == '0' && TOLOWER(cp[1]) == 'x') |
cp += 2; |
while (isxdigit(*cp)) { |
unsigned int value; |
value = isdigit(*cp) ? *cp - '0' : TOLOWER(*cp) - 'a' + 10; |
if (value >= base) |
break; |
result = result * base + value; |
cp++; |
} |
if (endp) |
*endp = (char *)cp; |
return result; |
} |
/** |
* simple_strtoll - convert a string to a signed long long |
* @cp: The start of the string |
* @endp: A pointer to the end of the parsed string will be placed here |
* @base: The number base to use |
*/ |
long long simple_strtoll(const char *cp, char **endp, unsigned int base) |
{ |
if(*cp=='-') |
return -simple_strtoull(cp + 1, endp, base); |
return simple_strtoull(cp, endp, base); |
} |
/** |
* strict_strtoul - convert a string to an unsigned long strictly |
* @cp: The string to be converted |
* @base: The number base to use |
* @res: The converted result value |
* |
* strict_strtoul converts a string to an unsigned long only if the |
* string is really an unsigned long string, any string containing |
* any invalid char at the tail will be rejected and -EINVAL is returned, |
* only a newline char at the tail is acceptible because people generally |
* change a module parameter in the following way: |
* |
* echo 1024 > /sys/module/e1000/parameters/copybreak |
* |
* echo will append a newline to the tail. |
* |
* It returns 0 if conversion is successful and *res is set to the converted |
* value, otherwise it returns -EINVAL and *res is set to 0. |
* |
* simple_strtoul just ignores the successive invalid characters and |
* return the converted value of prefix part of the string. |
*/ |
int strict_strtoul(const char *cp, unsigned int base, unsigned long *res) |
{ |
char *tail; |
unsigned long val; |
size_t len; |
*res = 0; |
len = strlen(cp); |
if (len == 0) |
return -EINVAL; |
val = simple_strtoul(cp, &tail, base); |
if (tail == cp) |
return -EINVAL; |
if ((*tail == '\0') || |
((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) { |
*res = val; |
return 0; |
} |
return -EINVAL; |
} |
/** |
* strict_strtol - convert a string to a long strictly |
* @cp: The string to be converted |
* @base: The number base to use |
* @res: The converted result value |
* |
* strict_strtol is similiar to strict_strtoul, but it allows the first |
* character of a string is '-'. |
* |
* It returns 0 if conversion is successful and *res is set to the converted |
* value, otherwise it returns -EINVAL and *res is set to 0. |
*/ |
int strict_strtol(const char *cp, unsigned int base, long *res) |
{ |
int ret; |
if (*cp == '-') { |
ret = strict_strtoul(cp + 1, base, (unsigned long *)res); |
if (!ret) |
*res = -(*res); |
} else { |
ret = strict_strtoul(cp, base, (unsigned long *)res); |
} |
return ret; |
} |
/** |
* strict_strtoull - convert a string to an unsigned long long strictly |
* @cp: The string to be converted |
* @base: The number base to use |
* @res: The converted result value |
* |
* strict_strtoull converts a string to an unsigned long long only if the |
* string is really an unsigned long long string, any string containing |
* any invalid char at the tail will be rejected and -EINVAL is returned, |
* only a newline char at the tail is acceptible because people generally |
* change a module parameter in the following way: |
* |
* echo 1024 > /sys/module/e1000/parameters/copybreak |
* |
* echo will append a newline to the tail of the string. |
* |
* It returns 0 if conversion is successful and *res is set to the converted |
* value, otherwise it returns -EINVAL and *res is set to 0. |
* |
* simple_strtoull just ignores the successive invalid characters and |
* return the converted value of prefix part of the string. |
*/ |
int strict_strtoull(const char *cp, unsigned int base, unsigned long long *res) |
{ |
char *tail; |
unsigned long long val; |
size_t len; |
*res = 0; |
len = strlen(cp); |
if (len == 0) |
return -EINVAL; |
val = simple_strtoull(cp, &tail, base); |
if (tail == cp) |
return -EINVAL; |
if ((*tail == '\0') || |
((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) { |
*res = val; |
return 0; |
} |
return -EINVAL; |
} |
/** |
* strict_strtoll - convert a string to a long long strictly |
* @cp: The string to be converted |
* @base: The number base to use |
* @res: The converted result value |
* |
* strict_strtoll is similiar to strict_strtoull, but it allows the first |
* character of a string is '-'. |
* |
* It returns 0 if conversion is successful and *res is set to the converted |
* value, otherwise it returns -EINVAL and *res is set to 0. |
*/ |
int strict_strtoll(const char *cp, unsigned int base, long long *res) |
{ |
int ret; |
if (*cp == '-') { |
ret = strict_strtoull(cp + 1, base, (unsigned long long *)res); |
if (!ret) |
*res = -(*res); |
} else { |
ret = strict_strtoull(cp, base, (unsigned long long *)res); |
} |
return ret; |
} |
static int skip_atoi(const char **s) |
{ |
int i=0; |
while (isdigit(**s)) |
i = i*10 + *((*s)++) - '0'; |
return i; |
} |
/* Decimal conversion is by far the most typical, and is used |
* for /proc and /sys data. This directly impacts e.g. top performance |
* with many processes running. We optimize it for speed |
* using code from |
* http://www.cs.uiowa.edu/~jones/bcd/decimal.html |
* (with permission from the author, Douglas W. Jones). */ |
/* Formats correctly any integer in [0,99999]. |
* Outputs from one to five digits depending on input. |
* On i386 gcc 4.1.2 -O2: ~250 bytes of code. */ |
static char* put_dec_trunc(char *buf, unsigned q) |
{ |
unsigned d3, d2, d1, d0; |
d1 = (q>>4) & 0xf; |
d2 = (q>>8) & 0xf; |
d3 = (q>>12); |
d0 = 6*(d3 + d2 + d1) + (q & 0xf); |
q = (d0 * 0xcd) >> 11; |
d0 = d0 - 10*q; |
*buf++ = d0 + '0'; /* least significant digit */ |
d1 = q + 9*d3 + 5*d2 + d1; |
if (d1 != 0) { |
q = (d1 * 0xcd) >> 11; |
d1 = d1 - 10*q; |
*buf++ = d1 + '0'; /* next digit */ |
d2 = q + 2*d2; |
if ((d2 != 0) || (d3 != 0)) { |
q = (d2 * 0xd) >> 7; |
d2 = d2 - 10*q; |
*buf++ = d2 + '0'; /* next digit */ |
d3 = q + 4*d3; |
if (d3 != 0) { |
q = (d3 * 0xcd) >> 11; |
d3 = d3 - 10*q; |
*buf++ = d3 + '0'; /* next digit */ |
if (q != 0) |
*buf++ = q + '0'; /* most sign. digit */ |
} |
} |
} |
return buf; |
} |
/* Same with if's removed. Always emits five digits */ |
static char* put_dec_full(char *buf, unsigned q) |
{ |
/* BTW, if q is in [0,9999], 8-bit ints will be enough, */ |
/* but anyway, gcc produces better code with full-sized ints */ |
unsigned d3, d2, d1, d0; |
d1 = (q>>4) & 0xf; |
d2 = (q>>8) & 0xf; |
d3 = (q>>12); |
/* Possible ways to approx. divide by 10 */ |
/* gcc -O2 replaces multiply with shifts and adds */ |
// (x * 0xcd) >> 11: 11001101 - shorter code than * 0x67 (on i386) |
// (x * 0x67) >> 10: 1100111 |
// (x * 0x34) >> 9: 110100 - same |
// (x * 0x1a) >> 8: 11010 - same |
// (x * 0x0d) >> 7: 1101 - same, shortest code (on i386) |
d0 = 6*(d3 + d2 + d1) + (q & 0xf); |
q = (d0 * 0xcd) >> 11; |
d0 = d0 - 10*q; |
*buf++ = d0 + '0'; |
d1 = q + 9*d3 + 5*d2 + d1; |
q = (d1 * 0xcd) >> 11; |
d1 = d1 - 10*q; |
*buf++ = d1 + '0'; |
d2 = q + 2*d2; |
q = (d2 * 0xd) >> 7; |
d2 = d2 - 10*q; |
*buf++ = d2 + '0'; |
d3 = q + 4*d3; |
q = (d3 * 0xcd) >> 11; /* - shorter code */ |
/* q = (d3 * 0x67) >> 10; - would also work */ |
d3 = d3 - 10*q; |
*buf++ = d3 + '0'; |
*buf++ = q + '0'; |
return buf; |
} |
/* No inlining helps gcc to use registers better */ |
static char* put_dec(char *buf, unsigned long long num) |
{ |
while (1) { |
unsigned rem; |
if (num < 100000) |
return put_dec_trunc(buf, num); |
rem = do_div(num, 100000); |
buf = put_dec_full(buf, rem); |
} |
} |
#define ZEROPAD 1 /* pad with zero */ |
#define SIGN 2 /* unsigned/signed long */ |
#define PLUS 4 /* show plus */ |
#define SPACE 8 /* space if plus */ |
#define LEFT 16 /* left justified */ |
#define SMALL 32 /* Must be 32 == 0x20 */ |
#define SPECIAL 64 /* 0x */ |
enum format_type { |
FORMAT_TYPE_NONE, /* Just a string part */ |
FORMAT_TYPE_WIDTH, |
FORMAT_TYPE_PRECISION, |
FORMAT_TYPE_CHAR, |
FORMAT_TYPE_STR, |
FORMAT_TYPE_PTR, |
FORMAT_TYPE_PERCENT_CHAR, |
FORMAT_TYPE_INVALID, |
FORMAT_TYPE_LONG_LONG, |
FORMAT_TYPE_ULONG, |
FORMAT_TYPE_LONG, |
FORMAT_TYPE_UBYTE, |
FORMAT_TYPE_BYTE, |
FORMAT_TYPE_USHORT, |
FORMAT_TYPE_SHORT, |
FORMAT_TYPE_UINT, |
FORMAT_TYPE_INT, |
FORMAT_TYPE_NRCHARS, |
FORMAT_TYPE_SIZE_T, |
FORMAT_TYPE_PTRDIFF |
}; |
struct printf_spec { |
enum format_type type; |
int flags; /* flags to number() */ |
int field_width; /* width of output field */ |
int base; |
int precision; /* # of digits/chars */ |
int qualifier; |
}; |
static char *number(char *buf, char *end, unsigned long long num, |
struct printf_spec spec) |
{ |
/* we are called with base 8, 10 or 16, only, thus don't need "G..." */ |
static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ |
char tmp[66]; |
char sign; |
char locase; |
int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10); |
int i; |
/* locase = 0 or 0x20. ORing digits or letters with 'locase' |
* produces same digits or (maybe lowercased) letters */ |
locase = (spec.flags & SMALL); |
if (spec.flags & LEFT) |
spec.flags &= ~ZEROPAD; |
sign = 0; |
if (spec.flags & SIGN) { |
if ((signed long long) num < 0) { |
sign = '-'; |
num = - (signed long long) num; |
spec.field_width--; |
} else if (spec.flags & PLUS) { |
sign = '+'; |
spec.field_width--; |
} else if (spec.flags & SPACE) { |
sign = ' '; |
spec.field_width--; |
} |
} |
if (need_pfx) { |
spec.field_width--; |
if (spec.base == 16) |
spec.field_width--; |
} |
/* generate full string in tmp[], in reverse order */ |
i = 0; |
if (num == 0) |
tmp[i++] = '0'; |
/* Generic code, for any base: |
else do { |
tmp[i++] = (digits[do_div(num,base)] | locase); |
} while (num != 0); |
*/ |
else if (spec.base != 10) { /* 8 or 16 */ |
int mask = spec.base - 1; |
int shift = 3; |
if (spec.base == 16) shift = 4; |
do { |
tmp[i++] = (digits[((unsigned char)num) & mask] | locase); |
num >>= shift; |
} while (num); |
} else { /* base 10 */ |
i = put_dec(tmp, num) - tmp; |
} |
/* printing 100 using %2d gives "100", not "00" */ |
if (i > spec.precision) |
spec.precision = i; |
/* leading space padding */ |
spec.field_width -= spec.precision; |
if (!(spec.flags & (ZEROPAD+LEFT))) { |
while(--spec.field_width >= 0) { |
if (buf < end) |
*buf = ' '; |
++buf; |
} |
} |
/* sign */ |
if (sign) { |
if (buf < end) |
*buf = sign; |
++buf; |
} |
/* "0x" / "0" prefix */ |
if (need_pfx) { |
if (buf < end) |
*buf = '0'; |
++buf; |
if (spec.base == 16) { |
if (buf < end) |
*buf = ('X' | locase); |
++buf; |
} |
} |
/* zero or space padding */ |
if (!(spec.flags & LEFT)) { |
char c = (spec.flags & ZEROPAD) ? '0' : ' '; |
while (--spec.field_width >= 0) { |
if (buf < end) |
*buf = c; |
++buf; |
} |
} |
/* hmm even more zero padding? */ |
while (i <= --spec.precision) { |
if (buf < end) |
*buf = '0'; |
++buf; |
} |
/* actual digits of result */ |
while (--i >= 0) { |
if (buf < end) |
*buf = tmp[i]; |
++buf; |
} |
/* trailing space padding */ |
while (--spec.field_width >= 0) { |
if (buf < end) |
*buf = ' '; |
++buf; |
} |
return buf; |
} |
static char *string(char *buf, char *end, char *s, struct printf_spec spec) |
{ |
int len, i; |
if ((unsigned long)s < PAGE_SIZE) |
s = "<NULL>"; |
len = strnlen(s, spec.precision); |
if (!(spec.flags & LEFT)) { |
while (len < spec.field_width--) { |
if (buf < end) |
*buf = ' '; |
++buf; |
} |
} |
for (i = 0; i < len; ++i) { |
if (buf < end) |
*buf = *s; |
++buf; ++s; |
} |
while (len < spec.field_width--) { |
if (buf < end) |
*buf = ' '; |
++buf; |
} |
return buf; |
} |
/* |
* Show a '%p' thing. |
*/ |
static char *pointer(const char *fmt, char *buf, char *end, void *ptr, |
struct printf_spec spec) |
{ |
if (!ptr) |
return string(buf, end, "(null)", spec); |
spec.flags |= SMALL; |
if (spec.field_width == -1) { |
spec.field_width = 2*sizeof(void *); |
spec.flags |= ZEROPAD; |
} |
spec.base = 16; |
return number(buf, end, (unsigned long) ptr, spec); |
} |
/* |
* Helper function to decode printf style format. |
* Each call decode a token from the format and return the |
* number of characters read (or likely the delta where it wants |
* to go on the next call). |
* The decoded token is returned through the parameters |
* |
* 'h', 'l', or 'L' for integer fields |
* 'z' support added 23/7/1999 S.H. |
* 'z' changed to 'Z' --davidm 1/25/99 |
* 't' added for ptrdiff_t |
* |
* @fmt: the format string |
* @type of the token returned |
* @flags: various flags such as +, -, # tokens.. |
* @field_width: overwritten width |
* @base: base of the number (octal, hex, ...) |
* @precision: precision of a number |
* @qualifier: qualifier of a number (long, size_t, ...) |
*/ |
static int format_decode(const char *fmt, struct printf_spec *spec) |
{ |
const char *start = fmt; |
/* we finished early by reading the field width */ |
if (spec->type == FORMAT_TYPE_WIDTH) { |
if (spec->field_width < 0) { |
spec->field_width = -spec->field_width; |
spec->flags |= LEFT; |
} |
spec->type = FORMAT_TYPE_NONE; |
goto precision; |
} |
/* we finished early by reading the precision */ |
if (spec->type == FORMAT_TYPE_PRECISION) { |
if (spec->precision < 0) |
spec->precision = 0; |
spec->type = FORMAT_TYPE_NONE; |
goto qualifier; |
} |
/* By default */ |
spec->type = FORMAT_TYPE_NONE; |
for (; *fmt ; ++fmt) { |
if (*fmt == '%') |
break; |
} |
/* Return the current non-format string */ |
if (fmt != start || !*fmt) |
return fmt - start; |
/* Process flags */ |
spec->flags = 0; |
while (1) { /* this also skips first '%' */ |
int found = 1; |
++fmt; |
switch (*fmt) { |
case '-': spec->flags |= LEFT; break; |
case '+': spec->flags |= PLUS; break; |
case ' ': spec->flags |= SPACE; break; |
case '#': spec->flags |= SPECIAL; break; |
case '0': spec->flags |= ZEROPAD; break; |
default: found = 0; |
} |
if (!found) |
break; |
} |
/* get field width */ |
spec->field_width = -1; |
if (isdigit(*fmt)) |
spec->field_width = skip_atoi(&fmt); |
else if (*fmt == '*') { |
/* it's the next argument */ |
spec->type = FORMAT_TYPE_WIDTH; |
return ++fmt - start; |
} |
precision: |
/* get the precision */ |
spec->precision = -1; |
if (*fmt == '.') { |
++fmt; |
if (isdigit(*fmt)) { |
spec->precision = skip_atoi(&fmt); |
if (spec->precision < 0) |
spec->precision = 0; |
} else if (*fmt == '*') { |
/* it's the next argument */ |
spec->type = FORMAT_TYPE_PRECISION; |
return ++fmt - start; |
} |
} |
qualifier: |
/* get the conversion qualifier */ |
spec->qualifier = -1; |
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || |
*fmt == 'Z' || *fmt == 'z' || *fmt == 't') { |
spec->qualifier = *fmt++; |
if (unlikely(spec->qualifier == *fmt)) { |
if (spec->qualifier == 'l') { |
spec->qualifier = 'L'; |
++fmt; |
} else if (spec->qualifier == 'h') { |
spec->qualifier = 'H'; |
++fmt; |
} |
} |
} |
/* default base */ |
spec->base = 10; |
switch (*fmt) { |
case 'c': |
spec->type = FORMAT_TYPE_CHAR; |
return ++fmt - start; |
case 's': |
spec->type = FORMAT_TYPE_STR; |
return ++fmt - start; |
case 'p': |
spec->type = FORMAT_TYPE_PTR; |
return fmt - start; |
/* skip alnum */ |
case 'n': |
spec->type = FORMAT_TYPE_NRCHARS; |
return ++fmt - start; |
case '%': |
spec->type = FORMAT_TYPE_PERCENT_CHAR; |
return ++fmt - start; |
/* integer number formats - set up the flags and "break" */ |
case 'o': |
spec->base = 8; |
break; |
case 'x': |
spec->flags |= SMALL; |
case 'X': |
spec->base = 16; |
break; |
case 'd': |
case 'i': |
spec->flags |= SIGN; |
case 'u': |
break; |
default: |
spec->type = FORMAT_TYPE_INVALID; |
return fmt - start; |
} |
if (spec->qualifier == 'L') |
spec->type = FORMAT_TYPE_LONG_LONG; |
else if (spec->qualifier == 'l') { |
if (spec->flags & SIGN) |
spec->type = FORMAT_TYPE_LONG; |
else |
spec->type = FORMAT_TYPE_ULONG; |
} else if (spec->qualifier == 'Z' || spec->qualifier == 'z') { |
spec->type = FORMAT_TYPE_SIZE_T; |
} else if (spec->qualifier == 't') { |
spec->type = FORMAT_TYPE_PTRDIFF; |
} else if (spec->qualifier == 'H') { |
if (spec->flags & SIGN) |
spec->type = FORMAT_TYPE_BYTE; |
else |
spec->type = FORMAT_TYPE_UBYTE; |
} else if (spec->qualifier == 'h') { |
if (spec->flags & SIGN) |
spec->type = FORMAT_TYPE_SHORT; |
else |
spec->type = FORMAT_TYPE_USHORT; |
} else { |
if (spec->flags & SIGN) |
spec->type = FORMAT_TYPE_INT; |
else |
spec->type = FORMAT_TYPE_UINT; |
} |
return ++fmt - start; |
} |
/** |
* vsnprintf - Format a string and place it in a buffer |
* @buf: The buffer to place the result into |
* @size: The size of the buffer, including the trailing null space |
* @fmt: The format string to use |
* @args: Arguments for the format string |
* |
* |
* The return value is the number of characters which would |
* be generated for the given input, excluding the trailing |
* '\0', as per ISO C99. If you want to have the exact |
* number of characters written into @buf as return value |
* (not including the trailing '\0'), use vscnprintf(). If the |
* return is greater than or equal to @size, the resulting |
* string is truncated. |
* |
* Call this function if you are already dealing with a va_list. |
* You probably want snprintf() instead. |
*/ |
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) |
{ |
unsigned long long num; |
char *str, *end, c; |
int read; |
struct printf_spec spec = {0}; |
/* Reject out-of-range values early. Large positive sizes are |
used for unknown buffer sizes. */ |
if (unlikely((int) size < 0)) { |
/* There can be only one.. */ |
static char warn = 1; |
// WARN_ON(warn); |
warn = 0; |
return 0; |
} |
str = buf; |
end = buf + size; |
/* Make sure end is always >= buf */ |
if (end < buf) { |
end = ((void *)-1); |
size = end - buf; |
} |
while (*fmt) { |
const char *old_fmt = fmt; |
read = format_decode(fmt, &spec); |
fmt += read; |
switch (spec.type) { |
case FORMAT_TYPE_NONE: { |
int copy = read; |
if (str < end) { |
if (copy > end - str) |
copy = end - str; |
memcpy(str, old_fmt, copy); |
} |
str += read; |
break; |
} |
case FORMAT_TYPE_WIDTH: |
spec.field_width = va_arg(args, int); |
break; |
case FORMAT_TYPE_PRECISION: |
spec.precision = va_arg(args, int); |
break; |
case FORMAT_TYPE_CHAR: |
if (!(spec.flags & LEFT)) { |
while (--spec.field_width > 0) { |
if (str < end) |
*str = ' '; |
++str; |
} |
} |
c = (unsigned char) va_arg(args, int); |
if (str < end) |
*str = c; |
++str; |
while (--spec.field_width > 0) { |
if (str < end) |
*str = ' '; |
++str; |
} |
break; |
case FORMAT_TYPE_STR: |
str = string(str, end, va_arg(args, char *), spec); |
break; |
case FORMAT_TYPE_PTR: |
str = pointer(fmt+1, str, end, va_arg(args, void *), |
spec); |
while (isalnum(*fmt)) |
fmt++; |
break; |
case FORMAT_TYPE_PERCENT_CHAR: |
if (str < end) |
*str = '%'; |
++str; |
break; |
case FORMAT_TYPE_INVALID: |
if (str < end) |
*str = '%'; |
++str; |
break; |
case FORMAT_TYPE_NRCHARS: { |
int qualifier = spec.qualifier; |
if (qualifier == 'l') { |
long *ip = va_arg(args, long *); |
*ip = (str - buf); |
} else if (qualifier == 'Z' || |
qualifier == 'z') { |
size_t *ip = va_arg(args, size_t *); |
*ip = (str - buf); |
} else { |
int *ip = va_arg(args, int *); |
*ip = (str - buf); |
} |
break; |
} |
default: |
switch (spec.type) { |
case FORMAT_TYPE_LONG_LONG: |
num = va_arg(args, long long); |
break; |
case FORMAT_TYPE_ULONG: |
num = va_arg(args, unsigned long); |
break; |
case FORMAT_TYPE_LONG: |
num = va_arg(args, long); |
break; |
case FORMAT_TYPE_SIZE_T: |
num = va_arg(args, size_t); |
break; |
// case FORMAT_TYPE_PTRDIFF: |
// num = va_arg(args, ptrdiff_t); |
// break; |
case FORMAT_TYPE_UBYTE: |
num = (unsigned char) va_arg(args, int); |
break; |
case FORMAT_TYPE_BYTE: |
num = (signed char) va_arg(args, int); |
break; |
case FORMAT_TYPE_USHORT: |
num = (unsigned short) va_arg(args, int); |
break; |
case FORMAT_TYPE_SHORT: |
num = (short) va_arg(args, int); |
break; |
case FORMAT_TYPE_INT: |
num = (int) va_arg(args, int); |
break; |
default: |
num = va_arg(args, unsigned int); |
} |
str = number(str, end, num, spec); |
} |
} |
if (size > 0) { |
if (str < end) |
*str = '\0'; |
else |
end[-1] = '\0'; |
} |
/* the trailing null byte doesn't count towards the total */ |
return str-buf; |
} |
/** |
* snprintf - Format a string and place it in a buffer |
* @buf: The buffer to place the result into |
* @size: The size of the buffer, including the trailing null space |
* @fmt: The format string to use |
* @...: Arguments for the format string |
* |
* The return value is the number of characters which would be |
* generated for the given input, excluding the trailing null, |
* as per ISO C99. If the return is greater than or equal to |
* @size, the resulting string is truncated. |
* |
* See the vsnprintf() documentation for format string extensions over C99. |
*/ |
int snprintf(char * buf, size_t size, const char *fmt, ...) |
{ |
va_list args; |
int i; |
va_start(args, fmt); |
i=vsnprintf(buf,size,fmt,args); |
va_end(args); |
return i; |
} |
/** |
* scnprintf - Format a string and place it in a buffer |
* @buf: The buffer to place the result into |
* @size: The size of the buffer, including the trailing null space |
* @fmt: The format string to use |
* @...: Arguments for the format string |
* |
* The return value is the number of characters written into @buf not including |
* the trailing '\0'. If @size is <= 0 the function returns 0. |
*/ |
int scnprintf(char * buf, size_t size, const char *fmt, ...) |
{ |
va_list args; |
int i; |
va_start(args, fmt); |
i = vsnprintf(buf, size, fmt, args); |
va_end(args); |
return (i >= size) ? (size - 1) : i; |
} |
/** |
* vsprintf - Format a string and place it in a buffer |
* @buf: The buffer to place the result into |
* @fmt: The format string to use |
* @args: Arguments for the format string |
* |
* The function returns the number of characters written |
* into @buf. Use vsnprintf() or vscnprintf() in order to avoid |
* buffer overflows. |
* |
* Call this function if you are already dealing with a va_list. |
* You probably want sprintf() instead. |
* |
* See the vsnprintf() documentation for format string extensions over C99. |
*/ |
int vsprintf(char *buf, const char *fmt, va_list args) |
{ |
return vsnprintf(buf, __INT_MAX__, fmt, args); |
} |
/** |
* sprintf - Format a string and place it in a buffer |
* @buf: The buffer to place the result into |
* @fmt: The format string to use |
* @...: Arguments for the format string |
* |
* The function returns the number of characters written |
* into @buf. Use snprintf() or scnprintf() in order to avoid |
* buffer overflows. |
* |
* See the vsnprintf() documentation for format string extensions over C99. |
*/ |
int sprintf(char * buf, const char *fmt, ...) |
{ |
va_list args; |
int i; |
va_start(args, fmt); |
i=vsnprintf(buf, __INT_MAX__, fmt, args); |
va_end(args); |
return i; |
} |
static inline |
void api_putc(char c) |
{ |
if (c == '\n') api_putc('\r'); |
__asm__ __volatile__( |
"int $0x40" |
::"a"(63),"b"(1),"c"(c)); |
} |
int API print(const char *fmt,...) |
{ |
char buf[256]; |
va_list args; |
int retval; |
int i; |
va_start(args, fmt); |
i = vsnprintf(buf, 256, fmt, args); |
va_end(args); |
retval = (i >= 256) ? (256 - 1) : i; |
for(i = 0; i< retval; i++) |
api_putc(buf[i]); |
return retval; |
}; |
#if 0 |
/** |
* vsscanf - Unformat a buffer into a list of arguments |
* @buf: input buffer |
* @fmt: format of buffer |
* @args: arguments |
*/ |
int vsscanf(const char * buf, const char * fmt, va_list args) |
{ |
const char *str = buf; |
char *next; |
char digit; |
int num = 0; |
int qualifier; |
int base; |
int field_width; |
int is_sign = 0; |
while(*fmt && *str) { |
/* skip any white space in format */ |
/* white space in format matchs any amount of |
* white space, including none, in the input. |
*/ |
if (isspace(*fmt)) { |
while (isspace(*fmt)) |
++fmt; |
while (isspace(*str)) |
++str; |
} |
/* anything that is not a conversion must match exactly */ |
if (*fmt != '%' && *fmt) { |
if (*fmt++ != *str++) |
break; |
continue; |
} |
if (!*fmt) |
break; |
++fmt; |
/* skip this conversion. |
* advance both strings to next white space |
*/ |
if (*fmt == '*') { |
while (!isspace(*fmt) && *fmt) |
fmt++; |
while (!isspace(*str) && *str) |
str++; |
continue; |
} |
/* get field width */ |
field_width = -1; |
if (isdigit(*fmt)) |
field_width = skip_atoi(&fmt); |
/* get conversion qualifier */ |
qualifier = -1; |
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || |
*fmt == 'Z' || *fmt == 'z') { |
qualifier = *fmt++; |
if (unlikely(qualifier == *fmt)) { |
if (qualifier == 'h') { |
qualifier = 'H'; |
fmt++; |
} else if (qualifier == 'l') { |
qualifier = 'L'; |
fmt++; |
} |
} |
} |
base = 10; |
is_sign = 0; |
if (!*fmt || !*str) |
break; |
switch(*fmt++) { |
case 'c': |
{ |
char *s = (char *) va_arg(args,char*); |
if (field_width == -1) |
field_width = 1; |
do { |
*s++ = *str++; |
} while (--field_width > 0 && *str); |
num++; |
} |
continue; |
case 's': |
{ |
char *s = (char *) va_arg(args, char *); |
if(field_width == -1) |
field_width = INT_MAX; |
/* first, skip leading white space in buffer */ |
while (isspace(*str)) |
str++; |
/* now copy until next white space */ |
while (*str && !isspace(*str) && field_width--) { |
*s++ = *str++; |
} |
*s = '\0'; |
num++; |
} |
continue; |
case 'n': |
/* return number of characters read so far */ |
{ |
int *i = (int *)va_arg(args,int*); |
*i = str - buf; |
} |
continue; |
case 'o': |
base = 8; |
break; |
case 'x': |
case 'X': |
base = 16; |
break; |
case 'i': |
base = 0; |
case 'd': |
is_sign = 1; |
case 'u': |
break; |
case '%': |
/* looking for '%' in str */ |
if (*str++ != '%') |
return num; |
continue; |
default: |
/* invalid format; stop here */ |
return num; |
} |
/* have some sort of integer conversion. |
* first, skip white space in buffer. |
*/ |
while (isspace(*str)) |
str++; |
digit = *str; |
if (is_sign && digit == '-') |
digit = *(str + 1); |
if (!digit |
|| (base == 16 && !isxdigit(digit)) |
|| (base == 10 && !isdigit(digit)) |
|| (base == 8 && (!isdigit(digit) || digit > '7')) |
|| (base == 0 && !isdigit(digit))) |
break; |
switch(qualifier) { |
case 'H': /* that's 'hh' in format */ |
if (is_sign) { |
signed char *s = (signed char *) va_arg(args,signed char *); |
*s = (signed char) simple_strtol(str,&next,base); |
} else { |
unsigned char *s = (unsigned char *) va_arg(args, unsigned char *); |
*s = (unsigned char) simple_strtoul(str, &next, base); |
} |
break; |
case 'h': |
if (is_sign) { |
short *s = (short *) va_arg(args,short *); |
*s = (short) simple_strtol(str,&next,base); |
} else { |
unsigned short *s = (unsigned short *) va_arg(args, unsigned short *); |
*s = (unsigned short) simple_strtoul(str, &next, base); |
} |
break; |
case 'l': |
if (is_sign) { |
long *l = (long *) va_arg(args,long *); |
*l = simple_strtol(str,&next,base); |
} else { |
unsigned long *l = (unsigned long*) va_arg(args,unsigned long*); |
*l = simple_strtoul(str,&next,base); |
} |
break; |
case 'L': |
if (is_sign) { |
long long *l = (long long*) va_arg(args,long long *); |
*l = simple_strtoll(str,&next,base); |
} else { |
unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*); |
*l = simple_strtoull(str,&next,base); |
} |
break; |
case 'Z': |
case 'z': |
{ |
size_t *s = (size_t*) va_arg(args,size_t*); |
*s = (size_t) simple_strtoul(str,&next,base); |
} |
break; |
default: |
if (is_sign) { |
int *i = (int *) va_arg(args, int*); |
*i = (int) simple_strtol(str,&next,base); |
} else { |
unsigned int *i = (unsigned int*) va_arg(args, unsigned int*); |
*i = (unsigned int) simple_strtoul(str,&next,base); |
} |
break; |
} |
num++; |
if (!next) |
break; |
str = next; |
} |
/* |
* Now we've come all the way through so either the input string or the |
* format ended. In the former case, there can be a %n at the current |
* position in the format that needs to be filled. |
*/ |
if (*fmt == '%' && *(fmt + 1) == 'n') { |
int *p = (int *)va_arg(args, int *); |
*p = str - buf; |
} |
return num; |
} |
#endif |