Report generated at: Mon Oct 13 11:12:56 CEST 2008
| Total number of functions | 1407 |
| Number of low risk functions | 1141 |
| Number of moderate risk functions | 168 |
| Number of high risk functions | 72 |
| Number of untestable functions | 26 |
Used ranges:
| Cyclomatic Complexity | Risk Evaluation | |
| 0 - 10 | Simple module, without much risk | |
| 11 - 20 | More complex module, moderate risk | |
| 21 - 50 | Complex module, high risk | |
| greater than 50 | Untestable module, very high risk |
| Function Name |
Cyclomatic
Complexity |
Number of
Statements |
Number of
Lines |
Source File | |
| ↓ | VASNPRINTF | 654 | 1706 | 3435 | lib/vasnprintf.c |
DCHAR_T *
VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
const FCHAR_T *format, va_list args)
{
DIRECTIVES d;
arguments a;
if (PRINTF_PARSE (format, &d, &a) < 0)
/* errno is already set. */
return NULL;
#define CLEANUP() \
free (d.dir); \
if (a.arg) \
free (a.arg);
if (PRINTF_FETCHARGS (args, &a) < 0)
{
CLEANUP ();
errno = EINVAL;
return NULL;
}
{
size_t buf_neededlength;
TCHAR_T *buf;
TCHAR_T *buf_malloced;
const FCHAR_T *cp;
size_t i;
DIRECTIVE *dp;
/* Output string accumulator. */
DCHAR_T *result;
size_t allocated;
size_t length;
/* Allocate a small buffer that will hold a directive passed to
sprintf or snprintf. */
buf_neededlength =
xsum4 (7, d.max_width_length, d.max_precision_length, 6);
#if HAVE_ALLOCA
if (buf_neededlength < 4000 / sizeof (TCHAR_T))
{
buf = (TCHAR_T *) alloca (buf_neededlength * sizeof (TCHAR_T));
buf_malloced = NULL;
}
else
#endif
{
size_t buf_memsize = xtimes (buf_neededlength, sizeof (TCHAR_T));
if (size_overflow_p (buf_memsize))
goto out_of_memory_1;
buf = (TCHAR_T *) malloc (buf_memsize);
if (buf == NULL)
goto out_of_memory_1;
buf_malloced = buf;
}
if (resultbuf != NULL)
{
result = resultbuf;
allocated = *lengthp;
}
else
{
result = NULL;
allocated = 0;
}
length = 0;
/* Invariants:
result is either == resultbuf or == NULL or malloc-allocated.
If length > 0, then result != NULL. */
/* Ensures that allocated >= needed. Aborts through a jump to
out_of_memory if needed is SIZE_MAX or otherwise too big. */
#define ENSURE_ALLOCATION(needed) \
if ((needed) > allocated) \
{ \
size_t memory_size; \
DCHAR_T *memory; \
\
allocated = (allocated > 0 ? xtimes (allocated, 2) : 12); \
if ((needed) > allocated) \
allocated = (needed); \
memory_size = xtimes (allocated, sizeof (DCHAR_T)); \
if (size_overflow_p (memory_size)) \
goto out_of_memory; \
if (result == resultbuf || result == NULL) \
memory = (DCHAR_T *) malloc (memory_size); \
else \
memory = (DCHAR_T *) realloc (result, memory_size); \
if (memory == NULL) \
goto out_of_memory; \
if (result == resultbuf && length > 0) \
DCHAR_CPY (memory, result, length); \
result = memory; \
}
for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++)
{
if (cp != dp->dir_start)
{
size_t n = dp->dir_start - cp;
size_t augmented_length = xsum (length, n);
ENSURE_ALLOCATION (augmented_length);
/* This copies a piece of FCHAR_T[] into a DCHAR_T[]. Here we
need that the format string contains only ASCII characters
if FCHAR_T and DCHAR_T are not the same type. */
if (sizeof (FCHAR_T) == sizeof (DCHAR_T))
{
DCHAR_CPY (result + length, (const DCHAR_T *) cp, n);
length = augmented_length;
}
else
{
do
result[length++] = (unsigned char) *cp++;
while (--n > 0);
}
}
if (i == d.count)
break;
/* Execute a single directive. */
if (dp->conversion == '%')
{
size_t augmented_length;
if (!(dp->arg_index == ARG_NONE))
abort ();
augmented_length = xsum (length, 1);
ENSURE_ALLOCATION (augmented_length);
result[length] = '%';
length = augmented_length;
}
else
{
if (!(dp->arg_index != ARG_NONE))
abort ();
if (dp->conversion == 'n')
{
switch (a.arg[dp->arg_index].type)
{
case TYPE_COUNT_SCHAR_POINTER:
*a.arg[dp->arg_index].a.a_count_schar_pointer = length;
break;
case TYPE_COUNT_SHORT_POINTER:
*a.arg[dp->arg_index].a.a_count_short_pointer = length;
break;
case TYPE_COUNT_INT_POINTER:
*a.arg[dp->arg_index].a.a_count_int_pointer = length;
break;
case TYPE_COUNT_LONGINT_POINTER:
*a.arg[dp->arg_index].a.a_count_longint_pointer = length;
break;
#if HAVE_LONG_LONG_INT
case TYPE_COUNT_LONGLONGINT_POINTER:
*a.arg[dp->arg_index].a.a_count_longlongint_pointer = length;
break;
#endif
default:
abort ();
}
}
#if ENABLE_UNISTDIO
/* The unistdio extensions. */
else if (dp->conversion == 'U')
{
arg_type type = a.arg[dp->arg_index].type;
int flags = dp->flags;
int has_width;
size_t width;
int has_precision;
size_t precision;
has_width = 0;
width = 0;
if (dp->width_start != dp->width_end)
{
if (dp->width_arg_index != ARG_NONE)
{
int arg;
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
arg = a.arg[dp->width_arg_index].a.a_int;
if (arg < 0)
{
/* "A negative field width is taken as a '-' flag
followed by a positive field width." */
flags |= FLAG_LEFT;
width = (unsigned int) (-arg);
}
else
width = arg;
}
else
{
const FCHAR_T *digitp = dp->width_start;
do
width = xsum (xtimes (width, 10), *digitp++ - '0');
while (digitp != dp->width_end);
}
has_width = 1;
}
has_precision = 0;
precision = 0;
if (dp->precision_start != dp->precision_end)
{
if (dp->precision_arg_index != ARG_NONE)
{
int arg;
if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
abort ();
arg = a.arg[dp->precision_arg_index].a.a_int;
/* "A negative precision is taken as if the precision
were omitted." */
if (arg >= 0)
{
precision = arg;
has_precision = 1;
}
}
else
{
const FCHAR_T *digitp = dp->precision_start + 1;
precision = 0;
while (digitp != dp->precision_end)
precision = xsum (xtimes (precision, 10), *digitp++ - '0');
has_precision = 1;
}
}
switch (type)
{
case TYPE_U8_STRING:
{
const uint8_t *arg = a.arg[dp->arg_index].a.a_u8_string;
const uint8_t *arg_end;
size_t characters;
if (has_precision)
{
/* Use only PRECISION characters, from the left. */
arg_end = arg;
characters = 0;
for (; precision > 0; precision--)
{
int count = u8_strmblen (arg_end);
if (count == 0)
break;
if (count < 0)
{
if (!(result == resultbuf || result == NULL))
free (result);
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = EILSEQ;
return NULL;
}
arg_end += count;
characters++;
}
}
else if (has_width)
{
/* Use the entire string, and count the number of
characters. */
arg_end = arg;
characters = 0;
for (;;)
{
int count = u8_strmblen (arg_end);
if (count == 0)
break;
if (count < 0)
{
if (!(result == resultbuf || result == NULL))
free (result);
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = EILSEQ;
return NULL;
}
arg_end += count;
characters++;
}
}
else
{
/* Use the entire string. */
arg_end = arg + u8_strlen (arg);
/* The number of characters doesn't matter. */
characters = 0;
}
if (has_width && width > characters
&& !(dp->flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
DCHAR_SET (result + length, ' ', n);
length += n;
}
# if DCHAR_IS_UINT8_T
{
size_t n = arg_end - arg;
ENSURE_ALLOCATION (xsum (length, n));
DCHAR_CPY (result + length, arg, n);
length += n;
}
# else
{ /* Convert. */
DCHAR_T *converted = result + length;
size_t converted_len = allocated - length;
# if DCHAR_IS_TCHAR
/* Convert from UTF-8 to locale encoding. */
if (u8_conv_to_encoding (locale_charset (),
iconveh_question_mark,
arg, arg_end - arg, NULL,
&converted, &converted_len)
< 0)
# else
/* Convert from UTF-8 to UTF-16/UTF-32. */
converted =
U8_TO_DCHAR (arg, arg_end - arg,
converted, &converted_len);
if (converted == NULL)
# endif
{
int saved_errno = errno;
if (!(result == resultbuf || result == NULL))
free (result);
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = saved_errno;
return NULL;
}
if (converted != result + length)
{
ENSURE_ALLOCATION (xsum (length, converted_len));
DCHAR_CPY (result + length, converted, converted_len);
free (converted);
}
length += converted_len;
}
# endif
if (has_width && width > characters
&& (dp->flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
DCHAR_SET (result + length, ' ', n);
length += n;
}
}
break;
case TYPE_U16_STRING:
{
const uint16_t *arg = a.arg[dp->arg_index].a.a_u16_string;
const uint16_t *arg_end;
size_t characters;
if (has_precision)
{
/* Use only PRECISION characters, from the left. */
arg_end = arg;
characters = 0;
for (; precision > 0; precision--)
{
int count = u16_strmblen (arg_end);
if (count == 0)
break;
if (count < 0)
{
if (!(result == resultbuf || result == NULL))
free (result);
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = EILSEQ;
return NULL;
}
arg_end += count;
characters++;
}
}
else if (has_width)
{
/* Use the entire string, and count the number of
characters. */
arg_end = arg;
characters = 0;
for (;;)
{
int count = u16_strmblen (arg_end);
if (count == 0)
break;
if (count < 0)
{
if (!(result == resultbuf || result == NULL))
free (result);
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = EILSEQ;
return NULL;
}
arg_end += count;
characters++;
}
}
else
{
/* Use the entire string. */
arg_end = arg + u16_strlen (arg);
/* The number of characters doesn't matter. */
characters = 0;
}
if (has_width && width > characters
&& !(dp->flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
DCHAR_SET (result + length, ' ', n);
length += n;
}
# if DCHAR_IS_UINT16_T
{
size_t n = arg_end - arg;
ENSURE_ALLOCATION (xsum (length, n));
DCHAR_CPY (result + length, arg, n);
length += n;
}
# else
{ /* Convert. */
DCHAR_T *converted = result + length;
size_t converted_len = allocated - length;
# if DCHAR_IS_TCHAR
/* Convert from UTF-16 to locale encoding. */
if (u16_conv_to_encoding (locale_charset (),
iconveh_question_mark,
arg, arg_end - arg, NULL,
&converted, &converted_len)
< 0)
# else
/* Convert from UTF-16 to UTF-8/UTF-32. */
converted =
U16_TO_DCHAR (arg, arg_end - arg,
converted, &converted_len);
if (converted == NULL)
# endif
{
int saved_errno = errno;
if (!(result == resultbuf || result == NULL))
free (result);
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = saved_errno;
return NULL;
}
if (converted != result + length)
{
ENSURE_ALLOCATION (xsum (length, converted_len));
DCHAR_CPY (result + length, converted, converted_len);
free (converted);
}
length += converted_len;
}
# endif
if (has_width && width > characters
&& (dp->flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
DCHAR_SET (result + length, ' ', n);
length += n;
}
}
break;
case TYPE_U32_STRING:
{
const uint32_t *arg = a.arg[dp->arg_index].a.a_u32_string;
const uint32_t *arg_end;
size_t characters;
if (has_precision)
{
/* Use only PRECISION characters, from the left. */
arg_end = arg;
characters = 0;
for (; precision > 0; precision--)
{
int count = u32_strmblen (arg_end);
if (count == 0)
break;
if (count < 0)
{
if (!(result == resultbuf || result == NULL))
free (result);
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = EILSEQ;
return NULL;
}
arg_end += count;
characters++;
}
}
else if (has_width)
{
/* Use the entire string, and count the number of
characters. */
arg_end = arg;
characters = 0;
for (;;)
{
int count = u32_strmblen (arg_end);
if (count == 0)
break;
if (count < 0)
{
if (!(result == resultbuf || result == NULL))
free (result);
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = EILSEQ;
return NULL;
}
arg_end += count;
characters++;
}
}
else
{
/* Use the entire string. */
arg_end = arg + u32_strlen (arg);
/* The number of characters doesn't matter. */
characters = 0;
}
if (has_width && width > characters
&& !(dp->flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
DCHAR_SET (result + length, ' ', n);
length += n;
}
# if DCHAR_IS_UINT32_T
{
size_t n = arg_end - arg;
ENSURE_ALLOCATION (xsum (length, n));
DCHAR_CPY (result + length, arg, n);
length += n;
}
# else
{ /* Convert. */
DCHAR_T *converted = result + length;
size_t converted_len = allocated - length;
# if DCHAR_IS_TCHAR
/* Convert from UTF-32 to locale encoding. */
if (u32_conv_to_encoding (locale_charset (),
iconveh_question_mark,
arg, arg_end - arg, NULL,
&converted, &converted_len)
< 0)
# else
/* Convert from UTF-32 to UTF-8/UTF-16. */
converted =
U32_TO_DCHAR (arg, arg_end - arg,
converted, &converted_len);
if (converted == NULL)
# endif
{
int saved_errno = errno;
if (!(result == resultbuf || result == NULL))
free (result);
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = saved_errno;
return NULL;
}
if (converted != result + length)
{
ENSURE_ALLOCATION (xsum (length, converted_len));
DCHAR_CPY (result + length, converted, converted_len);
free (converted);
}
length += converted_len;
}
# endif
if (has_width && width > characters
&& (dp->flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
DCHAR_SET (result + length, ' ', n);
length += n;
}
}
break;
default:
abort ();
}
}
#endif
#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL
else if ((dp->conversion == 'a' || dp->conversion == 'A')
# if !(NEED_PRINTF_DIRECTIVE_A || (NEED_PRINTF_LONG_DOUBLE && NEED_PRINTF_DOUBLE))
&& (0
# if NEED_PRINTF_DOUBLE
|| a.arg[dp->arg_index].type == TYPE_DOUBLE
# endif
# if NEED_PRINTF_LONG_DOUBLE
|| a.arg[dp->arg_index].type == TYPE_LONGDOUBLE
# endif
)
# endif
)
{
arg_type type = a.arg[dp->arg_index].type;
int flags = dp->flags;
int has_width;
size_t width;
int has_precision;
size_t precision;
size_t tmp_length;
DCHAR_T tmpbuf[700];
DCHAR_T *tmp;
DCHAR_T *pad_ptr;
DCHAR_T *p;
has_width = 0;
width = 0;
if (dp->width_start != dp->width_end)
{
if (dp->width_arg_index != ARG_NONE)
{
int arg;
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
arg = a.arg[dp->width_arg_index].a.a_int;
if (arg < 0)
{
/* "A negative field width is taken as a '-' flag
followed by a positive field width." */
flags |= FLAG_LEFT;
width = (unsigned int) (-arg);
}
else
width = arg;
}
else
{
const FCHAR_T *digitp = dp->width_start;
do
width = xsum (xtimes (width, 10), *digitp++ - '0');
while (digitp != dp->width_end);
}
has_width = 1;
}
has_precision = 0;
precision = 0;
if (dp->precision_start != dp->precision_end)
{
if (dp->precision_arg_index != ARG_NONE)
{
int arg;
if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
abort ();
arg = a.arg[dp->precision_arg_index].a.a_int;
/* "A negative precision is taken as if the precision
were omitted." */
if (arg >= 0)
{
precision = arg;
has_precision = 1;
}
}
else
{
const FCHAR_T *digitp = dp->precision_start + 1;
precision = 0;
while (digitp != dp->precision_end)
precision = xsum (xtimes (precision, 10), *digitp++ - '0');
has_precision = 1;
}
}
/* Allocate a temporary buffer of sufficient size. */
if (type == TYPE_LONGDOUBLE)
tmp_length =
(unsigned int) ((LDBL_DIG + 1)
* 0.831 /* decimal -> hexadecimal */
)
+ 1; /* turn floor into ceil */
else
tmp_length =
(unsigned int) ((DBL_DIG + 1)
* 0.831 /* decimal -> hexadecimal */
)
+ 1; /* turn floor into ceil */
if (tmp_length < precision)
tmp_length = precision;
/* Account for sign, decimal point etc. */
tmp_length = xsum (tmp_length, 12);
if (tmp_length < width)
tmp_length = width;
tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
if (tmp_length <= sizeof (tmpbuf) / sizeof (DCHAR_T))
tmp = tmpbuf;
else
{
size_t tmp_memsize = xtimes (tmp_length, sizeof (DCHAR_T));
if (size_overflow_p (tmp_memsize))
/* Overflow, would lead to out of memory. */
goto out_of_memory;
tmp = (DCHAR_T *) malloc (tmp_memsize);
if (tmp == NULL)
/* Out of memory. */
goto out_of_memory;
}
pad_ptr = NULL;
p = tmp;
if (type == TYPE_LONGDOUBLE)
{
# if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE
long double arg = a.arg[dp->arg_index].a.a_longdouble;
if (isnanl (arg))
{
if (dp->conversion == 'A')
{
*p++ = 'N'; *p++ = 'A'; *p++ = 'N';
}
else
{
*p++ = 'n'; *p++ = 'a'; *p++ = 'n';
}
}
else
{
int sign = 0;
DECL_LONG_DOUBLE_ROUNDING
BEGIN_LONG_DOUBLE_ROUNDING ();
if (signbit (arg)) /* arg < 0.0L or negative zero */
{
sign = -1;
arg = -arg;
}
if (sign < 0)
*p++ = '-';
else if (flags & FLAG_SHOWSIGN)
*p++ = '+';
else if (flags & FLAG_SPACE)
*p++ = ' ';
if (arg > 0.0L && arg + arg == arg)
{
if (dp->conversion == 'A')
{
*p++ = 'I'; *p++ = 'N'; *p++ = 'F';
}
else
{
*p++ = 'i'; *p++ = 'n'; *p++ = 'f';
}
}
else
{
int exponent;
long double mantissa;
if (arg > 0.0L)
mantissa = printf_frexpl (arg, &exponent);
else
{
exponent = 0;
mantissa = 0.0L;
}
if (has_precision
&& precision < (unsigned int) ((LDBL_DIG + 1) * 0.831) + 1)
{
/* Round the mantissa. */
long double tail = mantissa;
size_t q;
for (q = precision; ; q--)
{
int digit = (int) tail;
tail -= digit;
if (q == 0)
{
if (digit & 1 ? tail >= 0.5L : tail > 0.5L)
tail = 1 - tail;
else
tail = - tail;
break;
}
tail *= 16.0L;
}
if (tail != 0.0L)
for (q = precision; q > 0; q--)
tail *= 0.0625L;
mantissa += tail;
}
*p++ = '0';
*p++ = dp->conversion - 'A' + 'X';
pad_ptr = p;
{
int digit;
digit = (int) mantissa;
mantissa -= digit;
*p++ = '0' + digit;
if ((flags & FLAG_ALT)
|| mantissa > 0.0L || precision > 0)
{
*p++ = decimal_point_char ();
/* This loop terminates because we assume
that FLT_RADIX is a power of 2. */
while (mantissa > 0.0L)
{
mantissa *= 16.0L;
digit = (int) mantissa;
mantissa -= digit;
*p++ = digit
+ (digit < 10
? '0'
: dp->conversion - 10);
if (precision > 0)
precision--;
}
while (precision > 0)
{
*p++ = '0';
precision--;
}
}
}
*p++ = dp->conversion - 'A' + 'P';
# if WIDE_CHAR_VERSION
{
static const wchar_t decimal_format[] =
{ '%', '+', 'd', '\0' };
SNPRINTF (p, 6 + 1, decimal_format, exponent);
}
while (*p != '\0')
p++;
# else
if (sizeof (DCHAR_T) == 1)
{
sprintf ((char *) p, "%+d", exponent);
while (*p != '\0')
p++;
}
else
{
char expbuf[6 + 1];
const char *ep;
sprintf (expbuf, "%+d", exponent);
for (ep = expbuf; (*p = *ep) != '\0'; ep++)
p++;
}
# endif
}
END_LONG_DOUBLE_ROUNDING ();
}
# else
abort ();
# endif
}
else
{
# if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_DOUBLE
double arg = a.arg[dp->arg_index].a.a_double;
if (isnand (arg))
{
if (dp->conversion == 'A')
{
*p++ = 'N'; *p++ = 'A'; *p++ = 'N';
}
else
{
*p++ = 'n'; *p++ = 'a'; *p++ = 'n';
}
}
else
{
int sign = 0;
if (signbit (arg)) /* arg < 0.0 or negative zero */
{
sign = -1;
arg = -arg;
}
if (sign < 0)
*p++ = '-';
else if (flags & FLAG_SHOWSIGN)
*p++ = '+';
else if (flags & FLAG_SPACE)
*p++ = ' ';
if (arg > 0.0 && arg + arg == arg)
{
if (dp->conversion == 'A')
{
*p++ = 'I'; *p++ = 'N'; *p++ = 'F';
}
else
{
*p++ = 'i'; *p++ = 'n'; *p++ = 'f';
}
}
else
{
int exponent;
double mantissa;
if (arg > 0.0)
mantissa = printf_frexp (arg, &exponent);
else
{
exponent = 0;
mantissa = 0.0;
}
if (has_precision
&& precision < (unsigned int) ((DBL_DIG + 1) * 0.831) + 1)
{
/* Round the mantissa. */
double tail = mantissa;
size_t q;
for (q = precision; ; q--)
{
int digit = (int) tail;
tail -= digit;
if (q == 0)
{
if (digit & 1 ? tail >= 0.5 : tail > 0.5)
tail = 1 - tail;
else
tail = - tail;
break;
}
tail *= 16.0;
}
if (tail != 0.0)
for (q = precision; q > 0; q--)
tail *= 0.0625;
mantissa += tail;
}
*p++ = '0';
*p++ = dp->conversion - 'A' + 'X';
pad_ptr = p;
{
int digit;
digit = (int) mantissa;
mantissa -= digit;
*p++ = '0' + digit;
if ((flags & FLAG_ALT)
|| mantissa > 0.0 || precision > 0)
{
*p++ = decimal_point_char ();
/* This loop terminates because we assume
that FLT_RADIX is a power of 2. */
while (mantissa > 0.0)
{
mantissa *= 16.0;
digit = (int) mantissa;
mantissa -= digit;
*p++ = digit
+ (digit < 10
? '0'
: dp->conversion - 10);
if (precision > 0)
precision--;
}
while (precision > 0)
{
*p++ = '0';
precision--;
}
}
}
*p++ = dp->conversion - 'A' + 'P';
# if WIDE_CHAR_VERSION
{
static const wchar_t decimal_format[] =
{ '%', '+', 'd', '\0' };
SNPRINTF (p, 6 + 1, decimal_format, exponent);
}
while (*p != '\0')
p++;
# else
if (sizeof (DCHAR_T) == 1)
{
sprintf ((char *) p, "%+d", exponent);
while (*p != '\0')
p++;
}
else
{
char expbuf[6 + 1];
const char *ep;
sprintf (expbuf, "%+d", exponent);
for (ep = expbuf; (*p = *ep) != '\0'; ep++)
p++;
}
# endif
}
}
# else
abort ();
# endif
}
/* The generated string now extends from tmp to p, with the
zero padding insertion point being at pad_ptr. */
if (has_width && p - tmp < width)
{
size_t pad = width - (p - tmp);
DCHAR_T *end = p + pad;
if (flags & FLAG_LEFT)
{
/* Pad with spaces on the right. */
for (; pad > 0; pad--)
*p++ = ' ';
}
else if ((flags & FLAG_ZERO) && pad_ptr != NULL)
{
/* Pad with zeroes. */
DCHAR_T *q = end;
while (p > pad_ptr)
*--q = *--p;
for (; pad > 0; pad--)
*p++ = '0';
}
else
{
/* Pad with spaces on the left. */
DCHAR_T *q = end;
while (p > tmp)
*--q = *--p;
for (; pad > 0; pad--)
*p++ = ' ';
}
p = end;
}
{
size_t count = p - tmp;
if (count >= tmp_length)
/* tmp_length was incorrectly calculated - fix the
code above! */
abort ();
/* Make room for the result. */
if (count >= allocated - length)
{
size_t n = xsum (length, count);
ENSURE_ALLOCATION (n);
}
/* Append the result. */
memcpy (result + length, tmp, count * sizeof (DCHAR_T));
if (tmp != tmpbuf)
free (tmp);
length += count;
}
}
#endif
#if (NEED_PRINTF_INFINITE_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL
else if ((dp->conversion == 'f' || dp->conversion == 'F'
|| dp->conversion == 'e' || dp->conversion == 'E'
|| dp->conversion == 'g' || dp->conversion == 'G'
|| dp->conversion == 'a' || dp->conversion == 'A')
&& (0
# if NEED_PRINTF_DOUBLE
|| a.arg[dp->arg_index].type == TYPE_DOUBLE
# elif NEED_PRINTF_INFINITE_DOUBLE
|| (a.arg[dp->arg_index].type == TYPE_DOUBLE
/* The systems (mingw) which produce wrong output
for Inf, -Inf, and NaN also do so for -0.0.
Therefore we treat this case here as well. */
&& is_infinite_or_zero (a.arg[dp->arg_index].a.a_double))
# endif
# if NEED_PRINTF_LONG_DOUBLE
|| a.arg[dp->arg_index].type == TYPE_LONGDOUBLE
# elif NEED_PRINTF_INFINITE_LONG_DOUBLE
|| (a.arg[dp->arg_index].type == TYPE_LONGDOUBLE
/* Some systems produce wrong output for Inf,
-Inf, and NaN. Some systems in this category
(IRIX 5.3) also do so for -0.0. Therefore we
treat this case here as well. */
&& is_infinite_or_zerol (a.arg[dp->arg_index].a.a_longdouble))
# endif
))
{
# if (NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && (NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE)
arg_type type = a.arg[dp->arg_index].type;
# endif
int flags = dp->flags;
int has_width;
size_t width;
int has_precision;
size_t precision;
size_t tmp_length;
DCHAR_T tmpbuf[700];
DCHAR_T *tmp;
DCHAR_T *pad_ptr;
DCHAR_T *p;
has_width = 0;
width = 0;
if (dp->width_start != dp->width_end)
{
if (dp->width_arg_index != ARG_NONE)
{
int arg;
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
arg = a.arg[dp->width_arg_index].a.a_int;
if (arg < 0)
{
/* "A negative field width is taken as a '-' flag
followed by a positive field width." */
flags |= FLAG_LEFT;
width = (unsigned int) (-arg);
}
else
width = arg;
}
else
{
const FCHAR_T *digitp = dp->width_start;
do
width = xsum (xtimes (width, 10), *digitp++ - '0');
while (digitp != dp->width_end);
}
has_width = 1;
}
has_precision = 0;
precision = 0;
if (dp->precision_start != dp->precision_end)
{
if (dp->precision_arg_index != ARG_NONE)
{
int arg;
if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
abort ();
arg = a.arg[dp->precision_arg_index].a.a_int;
/* "A negative precision is taken as if the precision
were omitted." */
if (arg >= 0)
{
precision = arg;
has_precision = 1;
}
}
else
{
const FCHAR_T *digitp = dp->precision_start + 1;
precision = 0;
while (digitp != dp->precision_end)
precision = xsum (xtimes (precision, 10), *digitp++ - '0');
has_precision = 1;
}
}
/* POSIX specifies the default precision to be 6 for %f, %F,
%e, %E, but not for %g, %G. Implementations appear to use
the same default precision also for %g, %G. But for %a, %A,
the default precision is 0. */
if (!has_precision)
if (!(dp->conversion == 'a' || dp->conversion == 'A'))
precision = 6;
/* Allocate a temporary buffer of sufficient size. */
# if NEED_PRINTF_DOUBLE && NEED_PRINTF_LONG_DOUBLE
tmp_length = (type == TYPE_LONGDOUBLE ? LDBL_DIG + 1 : DBL_DIG + 1);
# elif NEED_PRINTF_INFINITE_DOUBLE && NEED_PRINTF_LONG_DOUBLE
tmp_length = (type == TYPE_LONGDOUBLE ? LDBL_DIG + 1 : 0);
# elif NEED_PRINTF_LONG_DOUBLE
tmp_length = LDBL_DIG + 1;
# elif NEED_PRINTF_DOUBLE
tmp_length = DBL_DIG + 1;
# else
tmp_length = 0;
# endif
if (tmp_length < precision)
tmp_length = precision;
# if NEED_PRINTF_LONG_DOUBLE
# if NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE
if (type == TYPE_LONGDOUBLE)
# endif
if (dp->conversion == 'f' || dp->conversion == 'F')
{
long double arg = a.arg[dp->arg_index].a.a_longdouble;
if (!(isnanl (arg) || arg + arg == arg))
{
/* arg is finite and nonzero. */
int exponent = floorlog10l (arg < 0 ? -arg : arg);
if (exponent >= 0 && tmp_length < exponent + precision)
tmp_length = exponent + precision;
}
}
# endif
# if NEED_PRINTF_DOUBLE
# if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE
if (type == TYPE_DOUBLE)
# endif
if (dp->conversion == 'f' || dp->conversion == 'F')
{
double arg = a.arg[dp->arg_index].a.a_double;
if (!(isnand (arg) || arg + arg == arg))
{
/* arg is finite and nonzero. */
int exponent = floorlog10 (arg < 0 ? -arg : arg);
if (exponent >= 0 && tmp_length < exponent + precision)
tmp_length = exponent + precision;
}
}
# endif
/* Account for sign, decimal point etc. */
tmp_length = xsum (tmp_length, 12);
if (tmp_length < width)
tmp_length = width;
tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
if (tmp_length <= sizeof (tmpbuf) / sizeof (DCHAR_T))
tmp = tmpbuf;
else
{
size_t tmp_memsize = xtimes (tmp_length, sizeof (DCHAR_T));
if (size_overflow_p (tmp_memsize))
/* Overflow, would lead to out of memory. */
goto out_of_memory;
tmp = (DCHAR_T *) malloc (tmp_memsize);
if (tmp == NULL)
/* Out of memory. */
goto out_of_memory;
}
pad_ptr = NULL;
p = tmp;
# if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE
# if NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE
if (type == TYPE_LONGDOUBLE)
# endif
{
long double arg = a.arg[dp->arg_index].a.a_longdouble;
if (isnanl (arg))
{
if (dp->conversion >= 'A' && dp->conversion <= 'Z')
{
*p++ = 'N'; *p++ = 'A'; *p++ = 'N';
}
else
{
*p++ = 'n'; *p++ = 'a'; *p++ = 'n';
}
}
else
{
int sign = 0;
DECL_LONG_DOUBLE_ROUNDING
BEGIN_LONG_DOUBLE_ROUNDING ();
if (signbit (arg)) /* arg < 0.0L or negative zero */
{
sign = -1;
arg = -arg;
}
if (sign < 0)
*p++ = '-';
else if (flags & FLAG_SHOWSIGN)
*p++ = '+';
else if (flags & FLAG_SPACE)
*p++ = ' ';
if (arg > 0.0L && arg + arg == arg)
{
if (dp->conversion >= 'A' && dp->conversion <= 'Z')
{
*p++ = 'I'; *p++ = 'N'; *p++ = 'F';
}
else
{
*p++ = 'i'; *p++ = 'n'; *p++ = 'f';
}
}
else
{
# if NEED_PRINTF_LONG_DOUBLE
pad_ptr = p;
if (dp->conversion == 'f' || dp->conversion == 'F')
{
char *digits;
size_t ndigits;
digits =
scale10_round_decimal_long_double (arg, precision);
if (digits == NULL)
{
END_LONG_DOUBLE_ROUNDING ();
goto out_of_memory;
}
ndigits = strlen (digits);
if (ndigits > precision)
do
{
--ndigits;
*p++ = digits[ndigits];
}
while (ndigits > precision);
else
*p++ = '0';
/* Here ndigits <= precision. */
if ((flags & FLAG_ALT) || precision > 0)
{
*p++ = decimal_point_char ();
for (; precision > ndigits; precision--)
*p++ = '0';
while (ndigits > 0)
{
--ndigits;
*p++ = digits[ndigits];
}
}
free (digits);
}
else if (dp->conversion == 'e' || dp->conversion == 'E')
{
int exponent;
if (arg == 0.0L)
{
exponent = 0;
*p++ = '0';
if ((flags & FLAG_ALT) || precision > 0)
{
*p++ = decimal_point_char ();
for (; precision > 0; precision--)
*p++ = '0';
}
}
else
{
/* arg > 0.0L. */
int adjusted;
char *digits;
size_t ndigits;
exponent = floorlog10l (arg);
adjusted = 0;
for (;;)
{
digits =
scale10_round_decimal_long_double (arg,
(int)precision - exponent);
if (digits == NULL)
{
END_LONG_DOUBLE_ROUNDING ();
goto out_of_memory;
}
ndigits = strlen (digits);
if (ndigits == precision + 1)
break;
if (ndigits < precision
|| ndigits > precision + 2)
/* The exponent was not guessed
precisely enough. */
abort ();
if (adjusted)
/* None of two values of exponent is
the right one. Prevent an endless
loop. */
abort ();
free (digits);
if (ndigits == precision)
exponent -= 1;
else
exponent += 1;
adjusted = 1;
}
/* Here ndigits = precision+1. */
if (is_borderline (digits, precision))
{
/* Maybe the exponent guess was too high
and a smaller exponent can be reached
by turning a 10...0 into 9...9x. */
char *digits2 =
scale10_round_decimal_long_double (arg,
(int)precision - exponent + 1);
if (digits2 == NULL)
{
free (digits);
END_LONG_DOUBLE_ROUNDING ();
goto out_of_memory;
}
if (strlen (digits2) == precision + 1)
{
free (digits);
digits = digits2;
exponent -= 1;
}
else
free (digits2);
}
/* Here ndigits = precision+1. */
*p++ = digits[--ndigits];
if ((flags & FLAG_ALT) || precision > 0)
{
*p++ = decimal_point_char ();
while (ndigits > 0)
{
--ndigits;
*p++ = digits[ndigits];
}
}
free (digits);
}
*p++ = dp->conversion; /* 'e' or 'E' */
# if WIDE_CHAR_VERSION
{
static const wchar_t decimal_format[] =
{ '%', '+', '.', '2', 'd', '\0' };
SNPRINTF (p, 6 + 1, decimal_format, exponent);
}
while (*p != '\0')
p++;
# else
if (sizeof (DCHAR_T) == 1)
{
sprintf ((char *) p, "%+.2d", exponent);
while (*p != '\0')
p++;
}
else
{
char expbuf[6 + 1];
const char *ep;
sprintf (expbuf, "%+.2d", exponent);
for (ep = expbuf; (*p = *ep) != '\0'; ep++)
p++;
}
# endif
}
else if (dp->conversion == 'g' || dp->conversion == 'G')
{
if (precision == 0)
precision = 1;
/* precision >= 1. */
if (arg == 0.0L)
/* The exponent is 0, >= -4, < precision.
Use fixed-point notation. */
{
size_t ndigits = precision;
/* Number of trailing zeroes that have to be
dropped. */
size_t nzeroes =
(flags & FLAG_ALT ? 0 : precision - 1);
--ndigits;
*p++ = '0';
if ((flags & FLAG_ALT) || ndigits > nzeroes)
{
*p++ = decimal_point_char ();
while (ndigits > nzeroes)
{
--ndigits;
*p++ = '0';
}
}
}
else
{
/* arg > 0.0L. */
int exponent;
int adjusted;
char *digits;
size_t ndigits;
size_t nzeroes;
exponent = floorlog10l (arg);
adjusted = 0;
for (;;)
{
digits =
scale10_round_decimal_long_double (arg,
(int)(precision - 1) - exponent);
if (digits == NULL)
{
END_LONG_DOUBLE_ROUNDING ();
goto out_of_memory;
}
ndigits = strlen (digits);
if (ndigits == precision)
break;
if (ndigits < precision - 1
|| ndigits > precision + 1)
/* The exponent was not guessed
precisely enough. */
abort ();
if (adjusted)
/* None of two values of exponent is
the right one. Prevent an endless
loop. */
abort ();
free (digits);
if (ndigits < precision)
exponent -= 1;
else
exponent += 1;
adjusted = 1;
}
/* Here ndigits = precision. */
if (is_borderline (digits, precision - 1))
{
/* Maybe the exponent guess was too high
and a smaller exponent can be reached
by turning a 10...0 into 9...9x. */
char *digits2 =
scale10_round_decimal_long_double (arg,
(int)(precision - 1) - exponent + 1);
if (digits2 == NULL)
{
free (digits);
END_LONG_DOUBLE_ROUNDING ();
goto out_of_memory;
}
if (strlen (digits2) == precision)
{
free (digits);
digits = digits2;
exponent -= 1;
}
else
free (digits2);
}
/* Here ndigits = precision. */
/* Determine the number of trailing zeroes
that have to be dropped. */
nzeroes = 0;
if ((flags & FLAG_ALT) == 0)
while (nzeroes < ndigits
&& digits[nzeroes] == '0')
nzeroes++;
/* The exponent is now determined. */
if (exponent >= -4
&& exponent < (long)precision)
{
/* Fixed-point notation:
max(exponent,0)+1 digits, then the
decimal point, then the remaining
digits without trailing zeroes. */
if (exponent >= 0)
{
size_t count = exponent + 1;
/* Note: count <= precision = ndigits. */
for (; count > 0; count--)
*p++ = digits[--ndigits];
if ((flags & FLAG_ALT) || ndigits > nzeroes)
{
*p++ = decimal_point_char ();
while (ndigits > nzeroes)
{
--ndigits;
*p++ = digits[ndigits];
}
}
}
else
{
size_t count = -exponent - 1;
*p++ = '0';
*p++ = decimal_point_char ();
for (; count > 0; count--)
*p++ = '0';
while (ndigits > nzeroes)
{
--ndigits;
*p++ = digits[ndigits];
}
}
}
else
{
/* Exponential notation. */
*p++ = digits[--ndigits];
if ((flags & FLAG_ALT) || ndigits > nzeroes)
{
*p++ = decimal_point_char ();
while (ndigits > nzeroes)
{
--ndigits;
*p++ = digits[ndigits];
}
}
*p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */
# if WIDE_CHAR_VERSION
{
static const wchar_t decimal_format[] =
{ '%', '+', '.', '2', 'd', '\0' };
SNPRINTF (p, 6 + 1, decimal_format, exponent);
}
while (*p != '\0')
p++;
# else
if (sizeof (DCHAR_T) == 1)
{
sprintf ((char *) p, "%+.2d", exponent);
while (*p != '\0')
p++;
}
else
{
char expbuf[6 + 1];
const char *ep;
sprintf (expbuf, "%+.2d", exponent);
for (ep = expbuf; (*p = *ep) != '\0'; ep++)
p++;
}
# endif
}
free (digits);
}
}
else
abort ();
# else
/* arg is finite. */
if (!(arg == 0.0L))
abort ();
pad_ptr = p;
if (dp->conversion == 'f' || dp->conversion == 'F')
{
*p++ = '0';
if ((flags & FLAG_ALT) || precision > 0)
{
*p++ = decimal_point_char ();
for (; precision > 0; precision--)
*p++ = '0';
}
}
else if (dp->conversion == 'e' || dp->conversion == 'E')
{
*p++ = '0';
if ((flags & FLAG_ALT) || precision > 0)
{
*p++ = decimal_point_char ();
for (; precision > 0; precision--)
*p++ = '0';
}
*p++ = dp->conversion; /* 'e' or 'E' */
*p++ = '+';
*p++ = '0';
*p++ = '0';
}
else if (dp->conversion == 'g' || dp->conversion == 'G')
{
*p++ = '0';
if (flags & FLAG_ALT)
{
size_t ndigits =
(precision > 0 ? precision - 1 : 0);
*p++ = decimal_point_char ();
for (; ndigits > 0; --ndigits)
*p++ = '0';
}
}
else if (dp->conversion == 'a' || dp->conversion == 'A')
{
*p++ = '0';
*p++ = dp->conversion - 'A' + 'X';
pad_ptr = p;
*p++ = '0';
if ((flags & FLAG_ALT) || precision > 0)
{
*p++ = decimal_point_char ();
for (; precision > 0; precision--)
*p++ = '0';
}
*p++ = dp->conversion - 'A' + 'P';
*p++ = '+';
*p++ = '0';
}
else
abort ();
# endif
}
END_LONG_DOUBLE_ROUNDING ();
}
}
# if NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE
else
# endif
# endif
# if NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE
{
double arg = a.arg[dp->arg_index].a.a_double;
if (isnand (arg))
{
if (dp->conversion >= 'A' && dp->conversion <= 'Z')
{
*p++ = 'N'; *p++ = 'A'; *p++ = 'N';
}
else
{
*p++ = 'n'; *p++ = 'a'; *p++ = 'n';
}
}
else
{
int sign = 0;
if (signbit (arg)) /* arg < 0.0 or negative zero */
{
sign = -1;
arg = -arg;
}
if (sign < 0)
*p++ = '-';
else if (flags & FLAG_SHOWSIGN)
*p++ = '+';
else if (flags & FLAG_SPACE)
*p++ = ' ';
if (arg > 0.0 && arg + arg == arg)
{
if (dp->conversion >= 'A' && dp->conversion <= 'Z')
{
*p++ = 'I'; *p++ = 'N'; *p++ = 'F';
}
else
{
*p++ = 'i'; *p++ = 'n'; *p++ = 'f';
}
}
else
{
# if NEED_PRINTF_DOUBLE
pad_ptr = p;
if (dp->conversion == 'f' || dp->conversion == 'F')
{
char *digits;
size_t ndigits;
digits =
scale10_round_decimal_double (arg, precision);
if (digits == NULL)
goto out_of_memory;
ndigits = strlen (digits);
if (ndigits > precision)
do
{
--ndigits;
*p++ = digits[ndigits];
}
while (ndigits > precision);
else
*p++ = '0';
/* Here ndigits <= precision. */
if ((flags & FLAG_ALT) || precision > 0)
{
*p++ = decimal_point_char ();
for (; precision > ndigits; precision--)
*p++ = '0';
while (ndigits > 0)
{
--ndigits;
*p++ = digits[ndigits];
}
}
free (digits);
}
else if (dp->conversion == 'e' || dp->conversion == 'E')
{
int exponent;
if (arg == 0.0)
{
exponent = 0;
*p++ = '0';
if ((flags & FLAG_ALT) || precision > 0)
{
*p++ = decimal_point_char ();
for (; precision > 0; precision--)
*p++ = '0';
}
}
else
{
/* arg > 0.0. */
int adjusted;
char *digits;
size_t ndigits;
exponent = floorlog10 (arg);
adjusted = 0;
for (;;)
{
digits =
scale10_round_decimal_double (arg,
(int)precision - exponent);
if (digits == NULL)
goto out_of_memory;
ndigits = strlen (digits);
if (ndigits == precision + 1)
break;
if (ndigits < precision
|| ndigits > precision + 2)
/* The exponent was not guessed
precisely enough. */
abort ();
if (adjusted)
/* None of two values of exponent is
the right one. Prevent an endless
loop. */
abort ();
free (digits);
if (ndigits == precision)
exponent -= 1;
else
exponent += 1;
adjusted = 1;
}
/* Here ndigits = precision+1. */
if (is_borderline (digits, precision))
{
/* Maybe the exponent guess was too high
and a smaller exponent can be reached
by turning a 10...0 into 9...9x. */
char *digits2 =
scale10_round_decimal_double (arg,
(int)precision - exponent + 1);
if (digits2 == NULL)
{
free (digits);
goto out_of_memory;
}
if (strlen (digits2) == precision + 1)
{
free (digits);
digits = digits2;
exponent -= 1;
}
else
free (digits2);
}
/* Here ndigits = precision+1. */
*p++ = digits[--ndigits];
if ((flags & FLAG_ALT) || precision > 0)
{
*p++ = decimal_point_char ();
while (ndigits > 0)
{
--ndigits;
*p++ = digits[ndigits];
}
}
free (digits);
}
*p++ = dp->conversion; /* 'e' or 'E' */
# if WIDE_CHAR_VERSION
{
static const wchar_t decimal_format[] =
/* Produce the same number of exponent digits
as the native printf implementation. */
# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
{ '%', '+', '.', '3', 'd', '\0' };
# else
{ '%', '+', '.', '2', 'd', '\0' };
# endif
SNPRINTF (p, 6 + 1, decimal_format, exponent);
}
while (*p != '\0')
p++;
# else
{
static const char decimal_format[] =
/* Produce the same number of exponent digits
as the native printf implementation. */
# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
"%+.3d";
# else
"%+.2d";
# endif
if (sizeof (DCHAR_T) == 1)
{
sprintf ((char *) p, decimal_format, exponent);
while (*p != '\0')
p++;
}
else
{
char expbuf[6 + 1];
const char *ep;
sprintf (expbuf, decimal_format, exponent);
for (ep = expbuf; (*p = *ep) != '\0'; ep++)
p++;
}
}
# endif
}
else if (dp->conversion == 'g' || dp->conversion == 'G')
{
if (precision == 0)
precision = 1;
/* precision >= 1. */
if (arg == 0.0)
/* The exponent is 0, >= -4, < precision.
Use fixed-point notation. */
{
size_t ndigits = precision;
/* Number of trailing zeroes that have to be
dropped. */
size_t nzeroes =
(flags & FLAG_ALT ? 0 : precision - 1);
--ndigits;
*p++ = '0';
if ((flags & FLAG_ALT) || ndigits > nzeroes)
{
*p++ = decimal_point_char ();
while (ndigits > nzeroes)
{
--ndigits;
*p++ = '0';
}
}
}
else
{
/* arg > 0.0. */
int exponent;
int adjusted;
char *digits;
size_t ndigits;
size_t nzeroes;
exponent = floorlog10 (arg);
adjusted = 0;
for (;;)
{
digits =
scale10_round_decimal_double (arg,
(int)(precision - 1) - exponent);
if (digits == NULL)
goto out_of_memory;
ndigits = strlen (digits);
if (ndigits == precision)
break;
if (ndigits < precision - 1
|| ndigits > precision + 1)
/* The exponent was not guessed
precisely enough. */
abort ();
if (adjusted)
/* None of two values of exponent is
the right one. Prevent an endless
loop. */
abort ();
free (digits);
if (ndigits < precision)
exponent -= 1;
else
exponent += 1;
adjusted = 1;
}
/* Here ndigits = precision. */
if (is_borderline (digits, precision - 1))
{
/* Maybe the exponent guess was too high
and a smaller exponent can be reached
by turning a 10...0 into 9...9x. */
char *digits2 =
scale10_round_decimal_double (arg,
(int)(precision - 1) - exponent + 1);
if (digits2 == NULL)
{
free (digits);
goto out_of_memory;
}
if (strlen (digits2) == precision)
{
free (digits);
digits = digits2;
exponent -= 1;
}
else
free (digits2);
}
/* Here ndigits = precision. */
/* Determine the number of trailing zeroes
that have to be dropped. */
nzeroes = 0;
if ((flags & FLAG_ALT) == 0)
while (nzeroes < ndigits
&& digits[nzeroes] == '0')
nzeroes++;
/* The exponent is now determined. */
if (exponent >= -4
&& exponent < (long)precision)
{
/* Fixed-point notation:
max(exponent,0)+1 digits, then the
decimal point, then the remaining
digits without trailing zeroes. */
if (exponent >= 0)
{
size_t count = exponent + 1;
/* Note: count <= precision = ndigits. */
for (; count > 0; count--)
*p++ = digits[--ndigits];
if ((flags & FLAG_ALT) || ndigits > nzeroes)
{
*p++ = decimal_point_char ();
while (ndigits > nzeroes)
{
--ndigits;
*p++ = digits[ndigits];
}
}
}
else
{
size_t count = -exponent - 1;
*p++ = '0';
*p++ = decimal_point_char ();
for (; count > 0; count--)
*p++ = '0';
while (ndigits > nzeroes)
{
--ndigits;
*p++ = digits[ndigits];
}
}
}
else
{
/* Exponential notation. */
*p++ = digits[--ndigits];
if ((flags & FLAG_ALT) || ndigits > nzeroes)
{
*p++ = decimal_point_char ();
while (ndigits > nzeroes)
{
--ndigits;
*p++ = digits[ndigits];
}
}
*p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */
# if WIDE_CHAR_VERSION
{
static const wchar_t decimal_format[] =
/* Produce the same number of exponent digits
as the native printf implementation. */
# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
{ '%', '+', '.', '3', 'd', '\0' };
# else
{ '%', '+', '.', '2', 'd', '\0' };
# endif
SNPRINTF (p, 6 + 1, decimal_format, exponent);
}
while (*p != '\0')
p++;
# else
{
static const char decimal_format[] =
/* Produce the same number of exponent digits
as the native printf implementation. */
# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
"%+.3d";
# else
"%+.2d";
# endif
if (sizeof (DCHAR_T) == 1)
{
sprintf ((char *) p, decimal_format, exponent);
while (*p != '\0')
p++;
}
else
{
char expbuf[6 + 1];
const char *ep;
sprintf (expbuf, decimal_format, exponent);
for (ep = expbuf; (*p = *ep) != '\0'; ep++)
p++;
}
}
# endif
}
free (digits);
}
}
else
abort ();
# else
/* arg is finite. */
if (!(arg == 0.0))
abort ();
pad_ptr = p;
if (dp->conversion == 'f' || dp->conversion == 'F')
{
*p++ = '0';
if ((flags & FLAG_ALT) || precision > 0)
{
*p++ = decimal_point_char ();
for (; precision > 0; precision--)
*p++ = '0';
}
}
else if (dp->conversion == 'e' || dp->conversion == 'E')
{
*p++ = '0';
if ((flags & FLAG_ALT) || precision > 0)
{
*p++ = decimal_point_char ();
for (; precision > 0; precision--)
*p++ = '0';
}
*p++ = dp->conversion; /* 'e' or 'E' */
*p++ = '+';
/* Produce the same number of exponent digits as
the native printf implementation. */
# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
*p++ = '0';
# endif
*p++ = '0';
*p++ = '0';
}
else if (dp->conversion == 'g' || dp->conversion == 'G')
{
*p++ = '0';
if (flags & FLAG_ALT)
{
size_t ndigits =
(precision > 0 ? precision - 1 : 0);
*p++ = decimal_point_char ();
for (; ndigits > 0; --ndigits)
*p++ = '0';
}
}
else
abort ();
# endif
}
}
}
# endif
/* The generated string now extends from tmp to p, with the
zero padding insertion point being at pad_ptr. */
if (has_width && p - tmp < width)
{
size_t pad = width - (p - tmp);
DCHAR_T *end = p + pad;
if (flags & FLAG_LEFT)
{
/* Pad with spaces on the right. */
for (; pad > 0; pad--)
*p++ = ' ';
}
else if ((flags & FLAG_ZERO) && pad_ptr != NULL)
{
/* Pad with zeroes. */
DCHAR_T *q = end;
while (p > pad_ptr)
*--q = *--p;
for (; pad > 0; pad--)
*p++ = '0';
}
else
{
/* Pad with spaces on the left. */
DCHAR_T *q = end;
while (p > tmp)
*--q = *--p;
for (; pad > 0; pad--)
*p++ = ' ';
}
p = end;
}
{
size_t count = p - tmp;
if (count >= tmp_length)
/* tmp_length was incorrectly calculated - fix the
code above! */
abort ();
/* Make room for the result. */
if (count >= allocated - length)
{
size_t n = xsum (length, count);
ENSURE_ALLOCATION (n);
}
/* Append the result. */
memcpy (result + length, tmp, count * sizeof (DCHAR_T));
if (tmp != tmpbuf)
free (tmp);
length += count;
}
}
#endif
else
{
arg_type type = a.arg[dp->arg_index].type;
int flags = dp->flags;
#if !USE_SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
int has_width;
size_t width;
#endif
#if !USE_SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION
int has_precision;
size_t precision;
#endif
#if NEED_PRINTF_UNBOUNDED_PRECISION
int prec_ourselves;
#else
# define prec_ourselves 0
#endif
#if NEED_PRINTF_FLAG_LEFTADJUST
# define pad_ourselves 1
#elif !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
int pad_ourselves;
#else
# define pad_ourselves 0
#endif
TCHAR_T *fbp;
unsigned int prefix_count;
int prefixes[2] IF_LINT (= { 0 });
#if !USE_SNPRINTF
size_t tmp_length;
TCHAR_T tmpbuf[700];
TCHAR_T *tmp;
#endif
#if !USE_SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
has_width = 0;
width = 0;
if (dp->width_start != dp->width_end)
{
if (dp->width_arg_index != ARG_NONE)
{
int arg;
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
arg = a.arg[dp->width_arg_index].a.a_int;
if (arg < 0)
{
/* "A negative field width is taken as a '-' flag
followed by a positive field width." */
flags |= FLAG_LEFT;
width = (unsigned int) (-arg);
}
else
width = arg;
}
else
{
const FCHAR_T *digitp = dp->width_start;
do
width = xsum (xtimes (width, 10), *digitp++ - '0');
while (digitp != dp->width_end);
}
has_width = 1;
}
#endif
#if !USE_SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION
has_precision = 0;
precision = 6;
if (dp->precision_start != dp->precision_end)
{
if (dp->precision_arg_index != ARG_NONE)
{
int arg;
if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
abort ();
arg = a.arg[dp->precision_arg_index].a.a_int;
/* "A negative precision is taken as if the precision
were omitted." */
if (arg >= 0)
{
precision = arg;
has_precision = 1;
}
}
else
{
const FCHAR_T *digitp = dp->precision_start + 1;
precision = 0;
while (digitp != dp->precision_end)
precision = xsum (xtimes (precision, 10), *digitp++ - '0');
has_precision = 1;
}
}
#endif
/* Decide whether to handle the precision ourselves. */
#if NEED_PRINTF_UNBOUNDED_PRECISION
switch (dp->conversion)
{
case 'd': case 'i': case 'u':
case 'o':
case 'x': case 'X': case 'p':
prec_ourselves = has_precision && (precision > 0);
break;
default:
prec_ourselves = 0;
break;
}
#endif
/* Decide whether to perform the padding ourselves. */
#if !NEED_PRINTF_FLAG_LEFTADJUST && (!DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION)
switch (dp->conversion)
{
# if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO
/* If we need conversion from TCHAR_T[] to DCHAR_T[], we need
to perform the padding after this conversion. Functions
with unistdio extensions perform the padding based on
character count rather than element count. */
case 'c': case 's':
# endif
# if NEED_PRINTF_FLAG_ZERO
case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
case 'a': case 'A':
# endif
pad_ourselves = 1;
break;
default:
pad_ourselves = prec_ourselves;
break;
}
#endif
#if !USE_SNPRINTF
/* Allocate a temporary buffer of sufficient size for calling
sprintf. */
{
switch (dp->conversion)
{
case 'd': case 'i': case 'u':
# if HAVE_LONG_LONG_INT
if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
tmp_length =
(unsigned int) (sizeof (unsigned long long) * CHAR_BIT
* 0.30103 /* binary -> decimal */
)
+ 1; /* turn floor into ceil */
else
# endif
if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
tmp_length =
(unsigned int) (sizeof (unsigned long) * CHAR_BIT
* 0.30103 /* binary -> decimal */
)
+ 1; /* turn floor into ceil */
else
tmp_length =
(unsigned int) (sizeof (unsigned int) * CHAR_BIT
* 0.30103 /* binary -> decimal */
)
+ 1; /* turn floor into ceil */
if (tmp_length < precision)
tmp_length = precision;
/* Multiply by 2, as an estimate for FLAG_GROUP. */
tmp_length = xsum (tmp_length, tmp_length);
/* Add 1, to account for a leading sign. */
tmp_length = xsum (tmp_length, 1);
break;
case 'o':
# if HAVE_LONG_LONG_INT
if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
tmp_length =
(unsigned int) (sizeof (unsigned long long) * CHAR_BIT
* 0.333334 /* binary -> octal */
)
+ 1; /* turn floor into ceil */
else
# endif
if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
tmp_length =
(unsigned int) (sizeof (unsigned long) * CHAR_BIT
* 0.333334 /* binary -> octal */
)
+ 1; /* turn floor into ceil */
else
tmp_length =
(unsigned int) (sizeof (unsigned int) * CHAR_BIT
* 0.333334 /* binary -> octal */
)
+ 1; /* turn floor into ceil */
if (tmp_length < precision)
tmp_length = precision;
/* Add 1, to account for a leading sign. */
tmp_length = xsum (tmp_length, 1);
break;
case 'x': case 'X':
# if HAVE_LONG_LONG_INT
if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
tmp_length =
(unsigned int) (sizeof (unsigned long long) * CHAR_BIT
* 0.25 /* binary -> hexadecimal */
)
+ 1; /* turn floor into ceil */
else
# endif
if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
tmp_length =
(unsigned int) (sizeof (unsigned long) * CHAR_BIT
* 0.25 /* binary -> hexadecimal */
)
+ 1; /* turn floor into ceil */
else
tmp_length =
(unsigned int) (sizeof (unsigned int) * CHAR_BIT
* 0.25 /* binary -> hexadecimal */
)
+ 1; /* turn floor into ceil */
if (tmp_length < precision)
tmp_length = precision;
/* Add 2, to account for a leading sign or alternate form. */
tmp_length = xsum (tmp_length, 2);
break;
case 'f': case 'F':
if (type == TYPE_LONGDOUBLE)
tmp_length =
(unsigned int) (LDBL_MAX_EXP
* 0.30103 /* binary -> decimal */
* 2 /* estimate for FLAG_GROUP */
)
+ 1 /* turn floor into ceil */
+ 10; /* sign, decimal point etc. */
else
tmp_length =
(unsigned int) (DBL_MAX_EXP
* 0.30103 /* binary -> decimal */
* 2 /* estimate for FLAG_GROUP */
)
+ 1 /* turn floor into ceil */
+ 10; /* sign, decimal point etc. */
tmp_length = xsum (tmp_length, precision);
break;
case 'e': case 'E': case 'g': case 'G':
tmp_length =
12; /* sign, decimal point, exponent etc. */
tmp_length = xsum (tmp_length, precision);
break;
case 'a': case 'A':
if (type == TYPE_LONGDOUBLE)
tmp_length =
(unsigned int) (LDBL_DIG
* 0.831 /* decimal -> hexadecimal */
)
+ 1; /* turn floor into ceil */
else
tmp_length =
(unsigned int) (DBL_DIG
* 0.831 /* decimal -> hexadecimal */
)
+ 1; /* turn floor into ceil */
if (tmp_length < precision)
tmp_length = precision;
/* Account for sign, decimal point etc. */
tmp_length = xsum (tmp_length, 12);
break;
case 'c':
# if HAVE_WINT_T && !WIDE_CHAR_VERSION
if (type == TYPE_WIDE_CHAR)
tmp_length = MB_CUR_MAX;
else
# endif
tmp_length = 1;
break;
case 's':
# if HAVE_WCHAR_T
if (type == TYPE_WIDE_STRING)
{
tmp_length =
local_wcslen (a.arg[dp->arg_index].a.a_wide_string);
# if !WIDE_CHAR_VERSION
tmp_length = xtimes (tmp_length, MB_CUR_MAX);
# endif
}
else
# endif
tmp_length = strlen (a.arg[dp->arg_index].a.a_string);
break;
case 'p':
tmp_length =
(unsigned int) (sizeof (void *) * CHAR_BIT
* 0.25 /* binary -> hexadecimal */
)
+ 1 /* turn floor into ceil */
+ 2; /* account for leading 0x */
break;
default:
abort ();
}
if (!pad_ourselves)
{
# if ENABLE_UNISTDIO
/* Padding considers the number of characters, therefore
the number of elements after padding may be
> max (tmp_length, width)
but is certainly
<= tmp_length + width. */
tmp_length = xsum (tmp_length, width);
# else
/* Padding considers the number of elements,
says POSIX. */
if (tmp_length < width)
tmp_length = width;
# endif
}
tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
}
if (tmp_length <= sizeof (tmpbuf) / sizeof (TCHAR_T))
tmp = tmpbuf;
else
{
size_t tmp_memsize = xtimes (tmp_length, sizeof (TCHAR_T));
if (size_overflow_p (tmp_memsize))
/* Overflow, would lead to out of memory. */
goto out_of_memory;
tmp = (TCHAR_T *) malloc (tmp_memsize);
if (tmp == NULL)
/* Out of memory. */
goto out_of_memory;
}
#endif
/* Construct the format string for calling snprintf or
sprintf. */
fbp = buf;
*fbp++ = '%';
#if NEED_PRINTF_FLAG_GROUPING
/* The underlying implementation doesn't support the ' flag.
Produce no grouping characters in this case; this is
acceptable because the grouping is locale dependent. */
#else
if (flags & FLAG_GROUP)
*fbp++ = '\'';
#endif
if (flags & FLAG_LEFT)
*fbp++ = '-';
if (flags & FLAG_SHOWSIGN)
*fbp++ = '+';
if (flags & FLAG_SPACE)
*fbp++ = ' ';
if (flags & FLAG_ALT)
*fbp++ = '#';
if (!pad_ourselves)
{
if (flags & FLAG_ZERO)
*fbp++ = '0';
if (dp->width_start != dp->width_end)
{
size_t n = dp->width_end - dp->width_start;
/* The width specification is known to consist only
of standard ASCII characters. */
if (sizeof (FCHAR_T) == sizeof (TCHAR_T))
{
memcpy (fbp, dp->width_start, n * sizeof (TCHAR_T));
fbp += n;
}
else
{
const FCHAR_T *mp = dp->width_start;
do
*fbp++ = (unsigned char) *mp++;
while (--n > 0);
}
}
}
if (!prec_ourselves)
{
if (dp->precision_start != dp->precision_end)
{
size_t n = dp->precision_end - dp->precision_start;
/* The precision specification is known to consist only
of standard ASCII characters. */
if (sizeof (FCHAR_T) == sizeof (TCHAR_T))
{
memcpy (fbp, dp->precision_start, n * sizeof (TCHAR_T));
fbp += n;
}
else
{
const FCHAR_T *mp = dp->precision_start;
do
*fbp++ = (unsigned char) *mp++;
while (--n > 0);
}
}
}
switch (type)
{
#if HAVE_LONG_LONG_INT
case TYPE_LONGLONGINT:
case TYPE_ULONGLONGINT:
# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
*fbp++ = 'I';
*fbp++ = '6';
*fbp++ = '4';
break;
# else
*fbp++ = 'l';
/*FALLTHROUGH*/
# endif
#endif
case TYPE_LONGINT:
case TYPE_ULONGINT:
#if HAVE_WINT_T
case TYPE_WIDE_CHAR:
#endif
#if HAVE_WCHAR_T
case TYPE_WIDE_STRING:
#endif
*fbp++ = 'l';
break;
case TYPE_LONGDOUBLE:
*fbp++ = 'L';
break;
default:
break;
}
#if NEED_PRINTF_DIRECTIVE_F
if (dp->conversion == 'F')
*fbp = 'f';
else
#endif
*fbp = dp->conversion;
#if USE_SNPRINTF
# if !(__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3) || ((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__))
fbp[1] = '%';
fbp[2] = 'n';
fbp[3] = '\0';
# else
/* On glibc2 systems from glibc >= 2.3 - probably also older
ones - we know that snprintf's returns value conforms to
ISO C 99: the gl_SNPRINTF_DIRECTIVE_N test passes.
Therefore we can avoid using %n in this situation.
On glibc2 systems from 2004-10-18 or newer, the use of %n
in format strings in writable memory may crash the program
(if compiled with _FORTIFY_SOURCE=2), so we should avoid it
in this situation. */
/* On native Win32 systems (such as mingw), we can avoid using
%n because:
- Although the gl_SNPRINTF_TRUNCATION_C99 test fails,
snprintf does not write more than the specified number
of bytes. (snprintf (buf, 3, "%d %d", 4567, 89) writes
'4', '5', '6' into buf, not '4', '5', '\0'.)
- Although the gl_SNPRINTF_RETVAL_C99 test fails, snprintf
allows us to recognize the case of an insufficient
buffer size: it returns -1 in this case.
On native Win32 systems (such as mingw) where the OS is
Windows Vista, the use of %n in format strings by default
crashes the program. See
|
|||||
| ↓ | EXT | 54 | 77 | 181 | lib/fnmatch_loop.c |
static int
internal_function
EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end,
bool no_leading_period, int flags)
{
const CHAR *startp;
size_t level;
struct patternlist
{
struct patternlist *next;
CHAR str[1];
} *list = NULL;
struct patternlist **lastp = &list;
size_t pattern_len = STRLEN (pattern);
const CHAR *p;
const CHAR *rs;
enum { ALLOCA_LIMIT = 8000 };
/* Parse the pattern. Store the individual parts in the list. */
level = 0;
for (startp = p = pattern + 1; ; ++p)
if (*p == L_('\0'))
/* This is an invalid pattern. */
return -1;
else if (*p == L_('['))
{
/* Handle brackets special. */
if (posixly_correct == 0)
posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
/* Skip the not sign. We have to recognize it because of a possibly
following ']'. */
if (*++p == L_('!') || (posixly_correct < 0 && *p == L_('^')))
++p;
/* A leading ']' is recognized as such. */
if (*p == L_(']'))
++p;
/* Skip over all characters of the list. */
while (*p != L_(']'))
if (*p++ == L_('\0'))
/* This is no valid pattern. */
return -1;
}
else if ((*p == L_('?') || *p == L_('*') || *p == L_('+') || *p == L_('@')
|| *p == L_('!')) && p[1] == L_('('))
/* Remember the nesting level. */
++level;
else if (*p == L_(')'))
{
if (level-- == 0)
{
/* This means we found the end of the pattern. */
#define NEW_PATTERN \
struct patternlist *newp; \
size_t plen; \
size_t plensize; \
size_t newpsize; \
\
plen = (opt == L_('?') || opt == L_('@') \
? pattern_len \
: p - startp + 1); \
plensize = plen * sizeof (CHAR); \
newpsize = offsetof (struct patternlist, str) + plensize; \
if ((size_t) -1 / sizeof (CHAR) < plen \
|| newpsize < offsetof (struct patternlist, str) \
|| ALLOCA_LIMIT <= newpsize) \
return -1; \
newp = (struct patternlist *) alloca (newpsize); \
*((CHAR *) MEMPCPY (newp->str, startp, p - startp)) = L_('\0'); \
newp->next = NULL; \
*lastp = newp; \
lastp = &newp->next
NEW_PATTERN;
break;
}
}
else if (*p == L_('|'))
{
if (level == 0)
{
NEW_PATTERN;
startp = p + 1;
}
}
assert (list != NULL);
assert (p[-1] == L_(')'));
#undef NEW_PATTERN
switch (opt)
{
case L_('*'):
if (FCT (p, string, string_end, no_leading_period, flags) == 0)
return 0;
/* FALLTHROUGH */
case L_('+'):
do
{
for (rs = string; rs <= string_end; ++rs)
/* First match the prefix with the current pattern with the
current pattern. */
if (FCT (list->str, string, rs, no_leading_period,
flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0
/* This was successful. Now match the rest with the rest
of the pattern. */
&& (FCT (p, rs, string_end,
rs == string
? no_leading_period
: rs[-1] == '/' && NO_LEADING_PERIOD (flags),
flags & FNM_FILE_NAME
? flags : flags & ~FNM_PERIOD) == 0
/* This didn't work. Try the whole pattern. */
|| (rs != string
&& FCT (pattern - 1, rs, string_end,
rs == string
? no_leading_period
: rs[-1] == '/' && NO_LEADING_PERIOD (flags),
flags & FNM_FILE_NAME
? flags : flags & ~FNM_PERIOD) == 0)))
/* It worked. Signal success. */
return 0;
}
while ((list = list->next) != NULL);
/* None of the patterns lead to a match. */
return FNM_NOMATCH;
case L_('?'):
if (FCT (p, string, string_end, no_leading_period, flags) == 0)
return 0;
/* FALLTHROUGH */
case L_('@'):
do
/* I cannot believe it but `strcat' is actually acceptable
here. Match the entire string with the prefix from the
pattern list and the rest of the pattern following the
pattern list. */
if (FCT (STRCAT (list->str, p), string, string_end,
no_leading_period,
flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0)
/* It worked. Signal success. */
return 0;
while ((list = list->next) != NULL);
/* None of the patterns lead to a match. */
return FNM_NOMATCH;
case L_('!'):
for (rs = string; rs <= string_end; ++rs)
{
struct patternlist *runp;
for (runp = list; runp != NULL; runp = runp->next)
if (FCT (runp->str, string, rs, no_leading_period,
flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0)
break;
/* If none of the patterns matched see whether the rest does. */
if (runp == NULL
&& (FCT (p, rs, string_end,
rs == string
? no_leading_period
: rs[-1] == '/' && NO_LEADING_PERIOD (flags),
flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD)
== 0))
/* This is successful. */
return 0;
}
/* None of the patterns together with the rest of the pattern
lead to a match. */
return FNM_NOMATCH;
default:
assert (! "Invalid extended matching operator");
break;
}
return -1;
}
|
|||||
| ↓ | __strptime_internal | 226 | 486 | 892 | lib/strptime.c |
char *
internal_function
#else
static char *
#endif
__strptime_internal (rp, fmt, tm, decided, era_cnt LOCALE_PARAM)
const char *rp;
const char *fmt;
struct tm *tm;
enum ptime_locale_status *decided;
int era_cnt;
LOCALE_PARAM_DECL
{
#ifdef _LIBC
struct locale_data *const current = locale->__locales[LC_TIME];
#endif
const char *rp_backup;
int cnt;
size_t val;
int have_I, is_pm;
int century, want_century;
int want_era;
int have_wday, want_xday;
int have_yday;
int have_mon, have_mday;
int have_uweek, have_wweek;
int week_no;
size_t num_eras;
struct era_entry *era;
have_I = is_pm = 0;
century = -1;
want_century = 0;
want_era = 0;
era = NULL;
week_no = 0;
have_wday = want_xday = have_yday = have_mon = have_mday = have_uweek = 0;
have_wweek = 0;
while (*fmt != '\0')
{
/* A white space in the format string matches 0 more or white
space in the input string. */
if (ISSPACE (*fmt))
{
while (ISSPACE (*rp))
++rp;
++fmt;
continue;
}
/* Any character but `%' must be matched by the same character
in the iput string. */
if (*fmt != '%')
{
match_char (*fmt++, *rp++);
continue;
}
++fmt;
#ifndef _NL_CURRENT
/* We need this for handling the `E' modifier. */
start_over:
#endif
/* Make back up of current processing pointer. */
rp_backup = rp;
switch (*fmt++)
{
case '%':
/* Match the `%' character itself. */
match_char ('%', *rp++);
break;
case 'a':
case 'A':
/* Match day of week. */
for (cnt = 0; cnt < 7; ++cnt)
{
#ifdef _NL_CURRENT
if (*decided !=raw)
{
if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), rp))
{
if (*decided == not
&& strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt),
weekday_name[cnt]))
*decided = loc;
break;
}
if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), rp))
{
if (*decided == not
&& strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt),
ab_weekday_name[cnt]))
*decided = loc;
break;
}
}
#endif
if (*decided != loc
&& (match_string (weekday_name[cnt], rp)
|| match_string (ab_weekday_name[cnt], rp)))
{
*decided = raw;
break;
}
}
if (cnt == 7)
/* Does not match a weekday name. */
return NULL;
tm->tm_wday = cnt;
have_wday = 1;
break;
case 'b':
case 'B':
case 'h':
/* Match month name. */
for (cnt = 0; cnt < 12; ++cnt)
{
#ifdef _NL_CURRENT
if (*decided !=raw)
{
if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), rp))
{
if (*decided == not
&& strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt),
month_name[cnt]))
*decided = loc;
break;
}
if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), rp))
{
if (*decided == not
&& strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt),
ab_month_name[cnt]))
*decided = loc;
break;
}
}
#endif
if (match_string (month_name[cnt], rp)
|| match_string (ab_month_name[cnt], rp))
{
*decided = raw;
break;
}
}
if (cnt == 12)
/* Does not match a month name. */
return NULL;
tm->tm_mon = cnt;
want_xday = 1;
break;
case 'c':
/* Match locale's date and time format. */
#ifdef _NL_CURRENT
if (*decided != raw)
{
if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT)))
{
if (*decided == loc)
return NULL;
else
rp = rp_backup;
}
else
{
if (*decided == not &&
strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT))
*decided = loc;
want_xday = 1;
break;
}
*decided = raw;
}
#endif
if (!recursive (HERE_D_T_FMT))
return NULL;
want_xday = 1;
break;
case 'C':
/* Match century number. */
match_century:
get_number (0, 99, 2);
century = val;
want_xday = 1;
break;
case 'd':
case 'e':
/* Match day of month. */
get_number (1, 31, 2);
tm->tm_mday = val;
have_mday = 1;
want_xday = 1;
break;
case 'F':
if (!recursive ("%Y-%m-%d"))
return NULL;
want_xday = 1;
break;
case 'x':
#ifdef _NL_CURRENT
if (*decided != raw)
{
if (!recursive (_NL_CURRENT (LC_TIME, D_FMT)))
{
if (*decided == loc)
return NULL;
else
rp = rp_backup;
}
else
{
if (*decided == not
&& strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT))
*decided = loc;
want_xday = 1;
break;
}
*decided = raw;
}
#endif
/* Fall through. */
case 'D':
/* Match standard day format. */
if (!recursive (HERE_D_FMT))
return NULL;
want_xday = 1;
break;
case 'k':
case 'H':
/* Match hour in 24-hour clock. */
get_number (0, 23, 2);
tm->tm_hour = val;
have_I = 0;
break;
case 'l':
/* Match hour in 12-hour clock. GNU extension. */
case 'I':
/* Match hour in 12-hour clock. */
get_number (1, 12, 2);
tm->tm_hour = val % 12;
have_I = 1;
break;
case 'j':
/* Match day number of year. */
get_number (1, 366, 3);
tm->tm_yday = val - 1;
have_yday = 1;
break;
case 'm':
/* Match number of month. */
get_number (1, 12, 2);
tm->tm_mon = val - 1;
have_mon = 1;
want_xday = 1;
break;
case 'M':
/* Match minute. */
get_number (0, 59, 2);
tm->tm_min = val;
break;
case 'n':
case 't':
/* Match any white space. */
while (ISSPACE (*rp))
++rp;
break;
case 'p':
/* Match locale's equivalent of AM/PM. */
#ifdef _NL_CURRENT
if (*decided != raw)
{
if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp))
{
if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR))
*decided = loc;
break;
}
if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp))
{
if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR))
*decided = loc;
is_pm = 1;
break;
}
*decided = raw;
}
#endif
if (!match_string (HERE_AM_STR, rp))
{
if (match_string (HERE_PM_STR, rp))
is_pm = 1;
else
return NULL;
}
break;
case 'r':
#ifdef _NL_CURRENT
if (*decided != raw)
{
if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM)))
{
if (*decided == loc)
return NULL;
else
rp = rp_backup;
}
else
{
if (*decided == not &&
strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM),
HERE_T_FMT_AMPM))
*decided = loc;
break;
}
*decided = raw;
}
#endif
if (!recursive (HERE_T_FMT_AMPM))
return NULL;
break;
case 'R':
if (!recursive ("%H:%M"))
return NULL;
break;
case 's':
{
/* The number of seconds may be very high so we cannot use
the `get_number' macro. Instead read the number
character for character and construct the result while
doing this. */
time_t secs = 0;
if (*rp < '0' || *rp > '9')
/* We need at least one digit. */
return NULL;
do
{
secs *= 10;
secs += *rp++ - '0';
}
while (*rp >= '0' && *rp <= '9');
if (localtime_r (&secs, tm) == NULL)
/* Error in function. */
return NULL;
}
break;
case 'S':
get_number (0, 61, 2);
tm->tm_sec = val;
break;
case 'X':
#ifdef _NL_CURRENT
if (*decided != raw)
{
if (!recursive (_NL_CURRENT (LC_TIME, T_FMT)))
{
if (*decided == loc)
return NULL;
else
rp = rp_backup;
}
else
{
if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT))
*decided = loc;
break;
}
*decided = raw;
}
#endif
/* Fall through. */
case 'T':
if (!recursive (HERE_T_FMT))
return NULL;
break;
case 'u':
get_number (1, 7, 1);
tm->tm_wday = val % 7;
have_wday = 1;
break;
case 'g':
get_number (0, 99, 2);
/* XXX This cannot determine any field in TM. */
break;
case 'G':
if (*rp < '0' || *rp > '9')
return NULL;
/* XXX Ignore the number since we would need some more
information to compute a real date. */
do
++rp;
while (*rp >= '0' && *rp <= '9');
break;
case 'U':
get_number (0, 53, 2);
week_no = val;
have_uweek = 1;
break;
case 'W':
get_number (0, 53, 2);
week_no = val;
have_wweek = 1;
break;
case 'V':
get_number (0, 53, 2);
/* XXX This cannot determine any field in TM without some
information. */
break;
case 'w':
/* Match number of weekday. */
get_number (0, 6, 1);
tm->tm_wday = val;
have_wday = 1;
break;
case 'y':
match_year_in_century:
/* Match year within century. */
get_number (0, 99, 2);
/* The "Year 2000: The Millennium Rollover" paper suggests that
values in the range 69-99 refer to the twentieth century. */
tm->tm_year = val >= 69 ? val : val + 100;
/* Indicate that we want to use the century, if specified. */
want_century = 1;
want_xday = 1;
break;
case 'Y':
/* Match year including century number. */
get_number (0, 9999, 4);
tm->tm_year = val - 1900;
want_century = 0;
want_xday = 1;
break;
case 'Z':
/* XXX How to handle this? */
break;
case 'z':
/* We recognize two formats: if two digits are given, these
specify hours. If fours digits are used, minutes are
also specified. */
{
bool neg;
int n;
val = 0;
while (*rp == ' ')
++rp;
if (*rp != '+' && *rp != '-')
return NULL;
neg = *rp++ == '-';
n = 0;
while (n < 4 && *rp >= '0' && *rp <= '9')
{
val = val * 10 + *rp++ - '0';
++n;
}
if (n == 2)
val *= 100;
else if (n != 4)
/* Only two or four digits recognized. */
return NULL;
else
{
/* We have to convert the minutes into decimal. */
if (val % 100 >= 60)
return NULL;
val = (val / 100) * 100 + ((val % 100) * 50) / 30;
}
if (val > 1200)
return NULL;
#if defined _LIBC || HAVE_TM_GMTOFF
tm->tm_gmtoff = (val * 3600) / 100;
if (neg)
tm->tm_gmtoff = -tm->tm_gmtoff;
#endif
}
break;
case 'E':
#ifdef _NL_CURRENT
switch (*fmt++)
{
case 'c':
/* Match locale's alternate date and time format. */
if (*decided != raw)
{
const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT);
if (*fmt == '\0')
fmt = _NL_CURRENT (LC_TIME, D_T_FMT);
if (!recursive (fmt))
{
if (*decided == loc)
return NULL;
else
rp = rp_backup;
}
else
{
if (strcmp (fmt, HERE_D_T_FMT))
*decided = loc;
want_xday = 1;
break;
}
*decided = raw;
}
/* The C locale has no era information, so use the
normal representation. */
if (!recursive (HERE_D_T_FMT))
return NULL;
want_xday = 1;
break;
case 'C':
if (*decided != raw)
{
if (era_cnt >= 0)
{
era = _nl_select_era_entry (era_cnt HELPER_LOCALE_ARG);
if (era != NULL && match_string (era->era_name, rp))
{
*decided = loc;
break;
}
else
return NULL;
}
num_eras = _NL_CURRENT_WORD (LC_TIME,
_NL_TIME_ERA_NUM_ENTRIES);
for (era_cnt = 0; era_cnt < (int) num_eras;
++era_cnt, rp = rp_backup)
{
era = _nl_select_era_entry (era_cnt
HELPER_LOCALE_ARG);
if (era != NULL && match_string (era->era_name, rp))
{
*decided = loc;
break;
}
}
if (era_cnt != (int) num_eras)
break;
era_cnt = -1;
if (*decided == loc)
return NULL;
*decided = raw;
}
/* The C locale has no era information, so use the
normal representation. */
goto match_century;
case 'y':
if (*decided != raw)
{
get_number(0, 9999, 4);
tm->tm_year = val;
want_era = 1;
want_xday = 1;
want_century = 1;
if (era_cnt >= 0)
{
assert (*decided == loc);
era = _nl_select_era_entry (era_cnt HELPER_LOCALE_ARG);
bool match = false;
if (era != NULL)
{
int delta = ((tm->tm_year - era->offset)
* era->absolute_direction);
match = (delta >= 0
&& delta < (((int64_t) era->stop_date[0]
- (int64_t) era->start_date[0])
* era->absolute_direction));
}
if (! match)
return NULL;
break;
}
num_eras = _NL_CURRENT_WORD (LC_TIME,
_NL_TIME_ERA_NUM_ENTRIES);
for (era_cnt = 0; era_cnt < (int) num_eras; ++era_cnt)
{
era = _nl_select_era_entry (era_cnt
HELPER_LOCALE_ARG);
if (era != NULL)
{
int delta = ((tm->tm_year - era->offset)
* era->absolute_direction);
if (delta >= 0
&& delta < (((int64_t) era->stop_date[0]
- (int64_t) era->start_date[0])
* era->absolute_direction))
{
*decided = loc;
break;
}
}
}
if (era_cnt != (int) num_eras)
break;
era_cnt = -1;
if (*decided == loc)
return NULL;
*decided = raw;
}
goto match_year_in_century;
case 'Y':
if (*decided != raw)
{
num_eras = _NL_CURRENT_WORD (LC_TIME,
_NL_TIME_ERA_NUM_ENTRIES);
for (era_cnt = 0; era_cnt < (int) num_eras;
++era_cnt, rp = rp_backup)
{
era = _nl_select_era_entry (era_cnt HELPER_LOCALE_ARG);
if (era != NULL && recursive (era->era_format))
break;
}
if (era_cnt == (int) num_eras)
{
era_cnt = -1;
if (*decided == loc)
return NULL;
else
rp = rp_backup;
}
else
{
*decided = loc;
era_cnt = -1;
break;
}
*decided = raw;
}
get_number (0, 9999, 4);
tm->tm_year = val - 1900;
want_century = 0;
want_xday = 1;
break;
case 'x':
if (*decided != raw)
{
const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT);
if (*fmt == '\0')
fmt = _NL_CURRENT (LC_TIME, D_FMT);
if (!recursive (fmt))
{
if (*decided == loc)
return NULL;
else
rp = rp_backup;
}
else
{
if (strcmp (fmt, HERE_D_FMT))
*decided = loc;
break;
}
*decided = raw;
}
if (!recursive (HERE_D_FMT))
return NULL;
break;
case 'X':
if (*decided != raw)
{
const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT);
if (*fmt == '\0')
fmt = _NL_CURRENT (LC_TIME, T_FMT);
if (!recursive (fmt))
{
if (*decided == loc)
return NULL;
else
rp = rp_backup;
}
else
{
if (strcmp (fmt, HERE_T_FMT))
*decided = loc;
break;
}
*decided = raw;
}
if (!recursive (HERE_T_FMT))
return NULL;
break;
default:
return NULL;
}
break;
#else
/* We have no information about the era format. Just use
the normal format. */
if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y'
&& *fmt != 'x' && *fmt != 'X')
/* This is an illegal format. */
return NULL;
goto start_over;
#endif
case 'O':
switch (*fmt++)
{
case 'd':
case 'e':
/* Match day of month using alternate numeric symbols. */
get_alt_number (1, 31, 2);
tm->tm_mday = val;
have_mday = 1;
want_xday = 1;
break;
case 'H':
/* Match hour in 24-hour clock using alternate numeric
symbols. */
get_alt_number (0, 23, 2);
tm->tm_hour = val;
have_I = 0;
break;
case 'I':
/* Match hour in 12-hour clock using alternate numeric
symbols. */
get_alt_number (1, 12, 2);
tm->tm_hour = val % 12;
have_I = 1;
break;
case 'm':
/* Match month using alternate numeric symbols. */
get_alt_number (1, 12, 2);
tm->tm_mon = val - 1;
have_mon = 1;
want_xday = 1;
break;
case 'M':
/* Match minutes using alternate numeric symbols. */
get_alt_number (0, 59, 2);
tm->tm_min = val;
break;
case 'S':
/* Match seconds using alternate numeric symbols. */
get_alt_number (0, 61, 2);
tm->tm_sec = val;
break;
case 'U':
get_alt_number (0, 53, 2);
week_no = val;
have_uweek = 1;
break;
case 'W':
get_alt_number (0, 53, 2);
week_no = val;
have_wweek = 1;
break;
case 'V':
get_alt_number (0, 53, 2);
/* XXX This cannot determine any field in TM without
further information. */
break;
case 'w':
/* Match number of weekday using alternate numeric symbols. */
get_alt_number (0, 6, 1);
tm->tm_wday = val;
have_wday = 1;
break;
case 'y':
/* Match year within century using alternate numeric symbols. */
get_alt_number (0, 99, 2);
tm->tm_year = val >= 69 ? val : val + 100;
want_xday = 1;
break;
default:
return NULL;
}
break;
default:
return NULL;
}
}
if (have_I && is_pm)
tm->tm_hour += 12;
if (century != -1)
{
if (want_century)
tm->tm_year = tm->tm_year % 100 + (century - 19) * 100;
else
/* Only the century, but not the year. Strange, but so be it. */
tm->tm_year = (century - 19) * 100;
}
if (era_cnt != -1)
{
#ifdef _NL_CURRENT
era = _nl_select_era_entry (era_cnt HELPER_LOCALE_ARG);
if (era == NULL)
return NULL;
if (want_era)
tm->tm_year = (era->start_date[0]
+ ((tm->tm_year - era->offset)
* era->absolute_direction));
else
/* Era start year assumed. */
tm->tm_year = era->start_date[0];
#endif
}
else
if (want_era)
{
/* No era found but we have seen an E modifier. Rectify some
values. */
if (want_century && century == -1 && tm->tm_year < 69)
tm->tm_year += 100;
}
if (want_xday && !have_wday)
{
if ( !(have_mon && have_mday) && have_yday)
{
/* We don't have tm_mon and/or tm_mday, compute them. */
int t_mon = 0;
while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
t_mon++;
if (!have_mon)
tm->tm_mon = t_mon - 1;
if (!have_mday)
tm->tm_mday =
(tm->tm_yday
- __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
}
day_of_the_week (tm);
}
if (want_xday && !have_yday)
day_of_the_year (tm);
if ((have_uweek || have_wweek) && have_wday)
{
int save_wday = tm->tm_wday;
int save_mday = tm->tm_mday;
int save_mon = tm->tm_mon;
int w_offset = have_uweek ? 0 : 1;
tm->tm_mday = 1;
tm->tm_mon = 0;
day_of_the_week (tm);
if (have_mday)
tm->tm_mday = save_mday;
if (have_mon)
tm->tm_mon = save_mon;
if (!have_yday)
tm->tm_yday = ((7 - (tm->tm_wday - w_offset)) % 7
+ (week_no - 1) *7
+ save_wday - w_offset);
if (!have_mday || !have_mon)
{
int t_mon = 0;
while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon]
<= tm->tm_yday)
t_mon++;
if (!have_mon)
tm->tm_mon = t_mon - 1;
if (!have_mday)
tm->tm_mday =
(tm->tm_yday
- __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
}
tm->tm_wday = save_wday;
}
return (char *) rp;
}
|
|||||
| ↓ | glob | 146 | 401 | 833 | lib/glob.c |
int
#ifdef GLOB_ATTRIBUTE
GLOB_ATTRIBUTE
#endif
glob (pattern, flags, errfunc, pglob)
const char * restrict pattern;
int flags;
int (*errfunc) (const char *, int);
glob_t * restrict pglob;
{
const char *filename;
const char *dirname;
size_t dirlen;
int status;
size_t oldcount;
int meta;
int dirname_modified;
glob_t dirs;
if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
{
__set_errno (EINVAL);
return -1;
}
if (!(flags & GLOB_DOOFFS))
/* Have to do this so `globfree' knows where to start freeing. It
also makes all the code that uses gl_offs simpler. */
pglob->gl_offs = 0;
if (flags & GLOB_BRACE)
{
const char *begin;
if (flags & GLOB_NOESCAPE)
begin = strchr (pattern, '{');
else
{
begin = pattern;
while (1)
{
if (*begin == '\0')
{
begin = NULL;
break;
}
if (*begin == '\\' && begin[1] != '\0')
++begin;
else if (*begin == '{')
break;
++begin;
}
}
if (begin != NULL)
{
/* Allocate working buffer large enough for our work. Note that
we have at least an opening and closing brace. */
size_t firstc;
char *alt_start;
const char *p;
const char *next;
const char *rest;
size_t rest_len;
#ifdef __GNUC__
char onealt[strlen (pattern) - 1];
#else
char *onealt = malloc (strlen (pattern) - 1);
if (onealt == NULL)
{
if (!(flags & GLOB_APPEND))
{
pglob->gl_pathc = 0;
pglob->gl_pathv = NULL;
}
return GLOB_NOSPACE;
}
#endif
/* We know the prefix for all sub-patterns. */
alt_start = mempcpy (onealt, pattern, begin - pattern);
/* Find the first sub-pattern and at the same time find the
rest after the closing brace. */
next = next_brace_sub (begin + 1, flags);
if (next == NULL)
{
/* It is an invalid expression. */
#ifndef __GNUC__
free (onealt);
#endif
return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
}
/* Now find the end of the whole brace expression. */
rest = next;
while (*rest != '}')
{
rest = next_brace_sub (rest + 1, flags);
if (rest == NULL)
{
/* It is an invalid expression. */
#ifndef __GNUC__
free (onealt);
#endif
return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
}
}
/* Please note that we now can be sure the brace expression
is well-formed. */
rest_len = strlen (++rest) + 1;
/* We have a brace expression. BEGIN points to the opening {,
NEXT points past the terminator of the first element, and END
points past the final }. We will accumulate result names from
recursive runs for each brace alternative in the buffer using
GLOB_APPEND. */
if (!(flags & GLOB_APPEND))
{
/* This call is to set a new vector, so clear out the
vector so we can append to it. */
pglob->gl_pathc = 0;
pglob->gl_pathv = NULL;
}
firstc = pglob->gl_pathc;
p = begin + 1;
while (1)
{
int result;
/* Construct the new glob expression. */
mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len);
result = glob (onealt,
((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))
| GLOB_APPEND), errfunc, pglob);
/* If we got an error, return it. */
if (result && result != GLOB_NOMATCH)
{
#ifndef __GNUC__
free (onealt);
#endif
if (!(flags & GLOB_APPEND))
{
globfree (pglob);
pglob->gl_pathc = 0;
}
return result;
}
if (*next == '}')
/* We saw the last entry. */
break;
p = next + 1;
next = next_brace_sub (p, flags);
assert (next != NULL);
}
#ifndef __GNUC__
free (onealt);
#endif
if (pglob->gl_pathc != firstc)
/* We found some entries. */
return 0;
else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
return GLOB_NOMATCH;
}
}
/* Find the filename. */
filename = strrchr (pattern, '/');
#if defined __MSDOS__ || defined WINDOWS32
/* The case of "d:pattern". Since `:' is not allowed in
file names, we can safely assume that wherever it
happens in pattern, it signals the filename part. This
is so we could some day support patterns like "[a-z]:foo". */
if (filename == NULL)
filename = strchr (pattern, ':');
#endif /* __MSDOS__ || WINDOWS32 */
dirname_modified = 0;
if (filename == NULL)
{
/* This can mean two things: a simple name or "~name". The latter
case is nothing but a notation for a directory. */
if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~')
{
dirname = pattern;
dirlen = strlen (pattern);
/* Set FILENAME to NULL as a special flag. This is ugly but
other solutions would require much more code. We test for
this special case below. */
filename = NULL;
}
else
{
filename = pattern;
#ifdef _AMIGA
dirname = "";
#else
dirname = ".";
#endif
dirlen = 0;
}
}
else if (filename == pattern
|| (filename == pattern + 1 && pattern[0] == '\\'
&& (flags & GLOB_NOESCAPE) == 0))
{
/* "/pattern" or "\\/pattern". */
dirname = "/";
dirlen = 1;
++filename;
}
else
{
char *newp;
dirlen = filename - pattern;
#if defined __MSDOS__ || defined WINDOWS32
if (*filename == ':'
|| (filename > pattern + 1 && filename[-1] == ':'))
{
char *drive_spec;
++dirlen;
drive_spec = __alloca (dirlen + 1);
*((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0';
/* For now, disallow wildcards in the drive spec, to
prevent infinite recursion in glob. */
if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE)))
return GLOB_NOMATCH;
/* If this is "d:pattern", we need to copy `:' to DIRNAME
as well. If it's "d:/pattern", don't remove the slash
from "d:/", since "d:" and "d:/" are not the same.*/
}
#endif
newp = __alloca (dirlen + 1);
*((char *) mempcpy (newp, pattern, dirlen)) = '\0';
dirname = newp;
++filename;
if (filename[0] == '\0'
#if defined __MSDOS__ || defined WINDOWS32
&& dirname[dirlen - 1] != ':'
&& (dirlen < 3 || dirname[dirlen - 2] != ':'
|| dirname[dirlen - 1] != '/')
#endif
&& dirlen > 1)
/* "pattern/". Expand "pattern", appending slashes. */
{
int orig_flags = flags;
int val;
if (!(flags & GLOB_NOESCAPE) && dirname[dirlen - 1] == '\\')
{
/* "pattern\\/". Remove the final backslash if it hasn't
been quoted. */
char *p = (char *) &dirname[dirlen - 1];
while (p > dirname && p[-1] == '\\') --p;
if ((&dirname[dirlen] - p) & 1)
{
*(char *) &dirname[--dirlen] = '\0';
flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC);
}
}
val = glob (dirname, flags | GLOB_MARK, errfunc, pglob);
if (val == 0)
pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK)
| (flags & GLOB_MARK));
else if (val == GLOB_NOMATCH && flags != orig_flags)
{
/* Make sure globfree (&dirs); is a nop. */
dirs.gl_pathv = NULL;
flags = orig_flags;
oldcount = pglob->gl_pathc + pglob->gl_offs;
goto no_matches;
}
return val;
}
}
if (!(flags & GLOB_APPEND))
{
pglob->gl_pathc = 0;
if (!(flags & GLOB_DOOFFS))
pglob->gl_pathv = NULL;
else
{
size_t i;
pglob->gl_pathv = malloc ((pglob->gl_offs + 1) * sizeof (char *));
if (pglob->gl_pathv == NULL)
return GLOB_NOSPACE;
for (i = 0; i <= pglob->gl_offs; ++i)
pglob->gl_pathv[i] = NULL;
}
}
oldcount = pglob->gl_pathc + pglob->gl_offs;
if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~')
{
if (dirname[1] == '\0' || dirname[1] == '/'
|| (!(flags & GLOB_NOESCAPE) && dirname[1] == '\\'
&& (dirname[2] == '\0' || dirname[2] == '/')))
{
/* Look up home directory. */
const char *home_dir = getenv ("HOME");
# ifdef _AMIGA
if (home_dir == NULL || home_dir[0] == '\0')
home_dir = "SYS:";
# else
# ifdef WINDOWS32
/* Windows NT defines HOMEDRIVE and HOMEPATH. But give preference
to HOME, because the user can change HOME. */
if (home_dir == NULL || home_dir[0] == '\0')
{
const char *home_drive = getenv ("HOMEDRIVE");
const char *home_path = getenv ("HOMEPATH");
if (home_drive != NULL && home_path != NULL)
{
size_t home_drive_len = strlen (home_drive);
size_t home_path_len = strlen (home_path);
char *mem = alloca (home_drive_len + home_path_len + 1);
memcpy (mem, home_drive, home_drive_len);
memcpy (mem + home_drive_len, home_path, home_path_len + 1);
home_dir = mem;
}
else
home_dir = "c:/users/default"; /* poor default */
}
# else
if (home_dir == NULL || home_dir[0] == '\0')
{
int success;
char *name;
size_t buflen = GET_LOGIN_NAME_MAX () + 1;
if (buflen == 0)
/* `sysconf' does not support _SC_LOGIN_NAME_MAX. Try
a moderate value. */
buflen = 20;
name = __alloca (buflen);
success = getlogin_r (name, buflen) == 0;
if (success)
{
struct passwd *p;
# if defined HAVE_GETPWNAM_R || defined _LIBC
long int pwbuflen = GETPW_R_SIZE_MAX ();
char *pwtmpbuf;
struct passwd pwbuf;
int save = errno;
# ifndef _LIBC
if (pwbuflen == -1)
/* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.
Try a moderate value. */
pwbuflen = 1024;
# endif
pwtmpbuf = __alloca (pwbuflen);
while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p)
!= 0)
{
if (errno != ERANGE)
{
p = NULL;
break;
}
# ifdef _LIBC
pwtmpbuf = extend_alloca (pwtmpbuf, pwbuflen,
2 * pwbuflen);
# else
pwbuflen *= 2;
pwtmpbuf = __alloca (pwbuflen);
# endif
__set_errno (save);
}
# else
p = getpwnam (name);
# endif
if (p != NULL)
home_dir = p->pw_dir;
}
}
if (home_dir == NULL || home_dir[0] == '\0')
{
if (flags & GLOB_TILDE_CHECK)
return GLOB_NOMATCH;
else
home_dir = "~"; /* No luck. */
}
# endif /* WINDOWS32 */
# endif
/* Now construct the full directory. */
if (dirname[1] == '\0')
{
dirname = home_dir;
dirlen = strlen (dirname);
}
else
{
char *newp;
size_t home_len = strlen (home_dir);
newp = __alloca (home_len + dirlen);
mempcpy (mempcpy (newp, home_dir, home_len),
&dirname[1], dirlen);
dirname = newp;
dirlen += home_len - 1;
}
dirname_modified = 1;
}
# if !defined _AMIGA && !defined WINDOWS32
else
{
char *end_name = strchr (dirname, '/');
const char *user_name;
const char *home_dir;
char *unescape = NULL;
if (!(flags & GLOB_NOESCAPE))
{
if (end_name == NULL)
{
unescape = strchr (dirname, '\\');
if (unescape)
end_name = strchr (unescape, '\0');
}
else
unescape = memchr (dirname, '\\', end_name - dirname);
}
if (end_name == NULL)
user_name = dirname + 1;
else
{
char *newp;
newp = __alloca (end_name - dirname);
*((char *) mempcpy (newp, dirname + 1, end_name - dirname))
= '\0';
if (unescape != NULL)
{
char *p = mempcpy (newp, dirname + 1,
unescape - dirname - 1);
char *q = unescape;
while (*q != '\0')
{
if (*q == '\\')
{
if (q[1] == '\0')
{
/* "~fo\\o\\" unescape to user_name "foo\\",
but "~fo\\o\\/" unescape to user_name
"foo". */
if (filename == NULL)
*p++ = '\\';
break;
}
++q;
}
*p++ = *q++;
}
*p = '\0';
}
else
*((char *) mempcpy (newp, dirname + 1, end_name - dirname))
= '\0';
user_name = newp;
}
/* Look up specific user's home directory. */
{
struct passwd *p;
# if defined HAVE_GETPWNAM_R || defined _LIBC
long int buflen = GETPW_R_SIZE_MAX ();
char *pwtmpbuf;
struct passwd pwbuf;
int save = errno;
# ifndef _LIBC
if (buflen == -1)
/* `sysconf' does not support _SC_GETPW_R_SIZE_MAX. Try a
moderate value. */
buflen = 1024;
# endif
pwtmpbuf = __alloca (buflen);
while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0)
{
if (errno != ERANGE)
{
p = NULL;
break;
}
# ifdef _LIBC
pwtmpbuf = extend_alloca (pwtmpbuf, buflen, 2 * buflen);
# else
buflen *= 2;
pwtmpbuf = __alloca (buflen);
# endif
__set_errno (save);
}
# else
p = getpwnam (user_name);
# endif
if (p != NULL)
home_dir = p->pw_dir;
else
home_dir = NULL;
}
/* If we found a home directory use this. */
if (home_dir != NULL)
{
char *newp;
size_t home_len = strlen (home_dir);
size_t rest_len = end_name == NULL ? 0 : strlen (end_name);
newp = __alloca (home_len + rest_len + 1);
*((char *) mempcpy (mempcpy (newp, home_dir, home_len),
end_name, rest_len)) = '\0';
dirname = newp;
dirlen = home_len + rest_len;
dirname_modified = 1;
}
else
if (flags & GLOB_TILDE_CHECK)
/* We have to regard it as an error if we cannot find the
home directory. */
return GLOB_NOMATCH;
}
# endif /* Not Amiga && not WINDOWS32. */
}
/* Now test whether we looked for "~" or "~NAME". In this case we
can give the answer now. */
if (filename == NULL)
{
struct stat st;
struct_stat64 st64;
/* Return the directory if we don't check for error or if it exists. */
if ((flags & GLOB_NOCHECK)
|| (((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
? ((*pglob->gl_stat) (dirname, &st) == 0
&& S_ISDIR (st.st_mode))
: (__stat64 (dirname, &st64) == 0 && S_ISDIR (st64.st_mode)))))
{
int newcount = pglob->gl_pathc + pglob->gl_offs;
char **new_gl_pathv;
new_gl_pathv
= realloc (pglob->gl_pathv, (newcount + 1 + 1) * sizeof (char *));
if (new_gl_pathv == NULL)
{
nospace:
free (pglob->gl_pathv);
pglob->gl_pathv = NULL;
pglob->gl_pathc = 0;
return GLOB_NOSPACE;
}
pglob->gl_pathv = new_gl_pathv;
if (flags & GLOB_MARK)
{
char *p;
pglob->gl_pathv[newcount] = malloc (dirlen + 2);
if (pglob->gl_pathv[newcount] == NULL)
goto nospace;
p = mempcpy (pglob->gl_pathv[newcount], dirname, dirlen);
p[0] = '/';
p[1] = '\0';
}
else
{
pglob->gl_pathv[newcount] = strdup (dirname);
if (pglob->gl_pathv[newcount] == NULL)
goto nospace;
}
pglob->gl_pathv[++newcount] = NULL;
++pglob->gl_pathc;
pglob->gl_flags = flags;
return 0;
}
/* Not found. */
return GLOB_NOMATCH;
}
meta = __glob_pattern_type (dirname, !(flags & GLOB_NOESCAPE));
/* meta is 1 if correct glob pattern containing metacharacters.
If meta has bit (1 << 2) set, it means there was an unterminated
[ which we handle the same, using fnmatch. Broken unterminated
pattern bracket expressions ought to be rare enough that it is
not worth special casing them, fnmatch will do the right thing. */
if (meta & 5)
{
/* The directory name contains metacharacters, so we
have to glob for the directory, and then glob for
the pattern in each directory found. */
size_t i;
if (!(flags & GLOB_NOESCAPE) && dirlen > 0 && dirname[dirlen - 1] == '\\')
{
/* "foo\\/bar". Remove the final backslash from dirname
if it has not been quoted. */
char *p = (char *) &dirname[dirlen - 1];
while (p > dirname && p[-1] == '\\') --p;
if ((&dirname[dirlen] - p) & 1)
*(char *) &dirname[--dirlen] = '\0';
}
if (__builtin_expect ((flags & GLOB_ALTDIRFUNC) != 0, 0))
{
/* Use the alternative access functions also in the recursive
call. */
dirs.gl_opendir = pglob->gl_opendir;
dirs.gl_readdir = pglob->gl_readdir;
dirs.gl_closedir = pglob->gl_closedir;
dirs.gl_stat = pglob->gl_stat;
dirs.gl_lstat = pglob->gl_lstat;
}
status = glob (dirname,
((flags & (GLOB_ERR | GLOB_NOESCAPE
| GLOB_ALTDIRFUNC))
| GLOB_NOSORT | GLOB_ONLYDIR),
errfunc, &dirs);
if (status != 0)
{
if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH)
return status;
goto no_matches;
}
/* We have successfully globbed the preceding directory name.
For each name we found, call glob_in_dir on it and FILENAME,
appending the results to PGLOB. */
for (i = 0; i < dirs.gl_pathc; ++i)
{
int old_pathc;
#ifdef SHELL
{
/* Make globbing interruptible in the bash shell. */
extern int interrupt_state;
if (interrupt_state)
{
globfree (&dirs);
return GLOB_ABORTED;
}
}
#endif /* SHELL. */
old_pathc = pglob->gl_pathc;
status = glob_in_dir (filename, dirs.gl_pathv[i],
((flags | GLOB_APPEND)
& ~(GLOB_NOCHECK | GLOB_NOMAGIC)),
errfunc, pglob);
if (status == GLOB_NOMATCH)
/* No matches in this directory. Try the next. */
continue;
if (status != 0)
{
globfree (&dirs);
globfree (pglob);
pglob->gl_pathc = 0;
return status;
}
/* Stick the directory on the front of each name. */
if (prefix_array (dirs.gl_pathv[i],
&pglob->gl_pathv[old_pathc + pglob->gl_offs],
pglob->gl_pathc - old_pathc))
{
globfree (&dirs);
globfree (pglob);
pglob->gl_pathc = 0;
return GLOB_NOSPACE;
}
}
flags |= GLOB_MAGCHAR;
/* We have ignored the GLOB_NOCHECK flag in the `glob_in_dir' calls.
But if we have not found any matching entry and the GLOB_NOCHECK
flag was set we must return the input pattern itself. */
if (pglob->gl_pathc + pglob->gl_offs == oldcount)
{
no_matches:
/* No matches. */
if (flags & GLOB_NOCHECK)
{
int newcount = pglob->gl_pathc + pglob->gl_offs;
char **new_gl_pathv;
new_gl_pathv = realloc (pglob->gl_pathv,
(newcount + 2) * sizeof (char *));
if (new_gl_pathv == NULL)
{
globfree (&dirs);
return GLOB_NOSPACE;
}
pglob->gl_pathv = new_gl_pathv;
pglob->gl_pathv[newcount] = strdup (pattern);
if (pglob->gl_pathv[newcount] == NULL)
{
globfree (&dirs);
globfree (pglob);
pglob->gl_pathc = 0;
return GLOB_NOSPACE;
}
++pglob->gl_pathc;
++newcount;
pglob->gl_pathv[newcount] = NULL;
pglob->gl_flags = flags;
}
else
{
globfree (&dirs);
return GLOB_NOMATCH;
}
}
globfree (&dirs);
}
else
{
int old_pathc = pglob->gl_pathc;
int orig_flags = flags;
if (meta & 2)
{
char *p = strchr (dirname, '\\'), *q;
/* We need to unescape the dirname string. It is certainly
allocated by alloca, as otherwise filename would be NULL
or dirname wouldn't contain backslashes. */
q = p;
do
{
if (*p == '\\')
{
*q = *++p;
--dirlen;
}
else
*q = *p;
++q;
}
while (*p++ != '\0');
dirname_modified = 1;
}
if (dirname_modified)
flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC);
status = glob_in_dir (filename, dirname, flags, errfunc, pglob);
if (status != 0)
{
if (status == GLOB_NOMATCH && flags != orig_flags
&& pglob->gl_pathc + pglob->gl_offs == oldcount)
{
/* Make sure globfree (&dirs); is a nop. */
dirs.gl_pathv = NULL;
flags = orig_flags;
goto no_matches;
}
return status;
}
if (dirlen > 0)
{
/* Stick the directory on the front of each name. */
if (prefix_array (dirname,
&pglob->gl_pathv[old_pathc + pglob->gl_offs],
pglob->gl_pathc - old_pathc))
{
globfree (pglob);
pglob->gl_pathc = 0;
return GLOB_NOSPACE;
}
}
}
if (flags & GLOB_MARK)
{
/* Append slashes to directory names. */
size_t i;
struct stat st;
struct_stat64 st64;
for (i = oldcount; i < pglob->gl_pathc + pglob->gl_offs; ++i)
if ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
? ((*pglob->gl_stat) (pglob->gl_pathv[i], &st) == 0
&& S_ISDIR (st.st_mode))
: (__stat64 (pglob->gl_pathv[i], &st64) == 0
&& S_ISDIR (st64.st_mode))))
{
size_t len = strlen (pglob->gl_pathv[i]) + 2;
char *new = realloc (pglob->gl_pathv[i], len);
if (new == NULL)
{
globfree (pglob);
pglob->gl_pathc = 0;
return GLOB_NOSPACE;
}
strcpy (&new[len - 2], "/");
pglob->gl_pathv[i] = new;
}
}
if (!(flags & GLOB_NOSORT))
{
/* Sort the vector. */
qsort (&pglob->gl_pathv[oldcount],
pglob->gl_pathc + pglob->gl_offs - oldcount,
sizeof (char *), collated_compare);
}
return 0;
}
|
|||||
| ↓ | create_pipe | 141 | 137 | 337 | lib/pipe.c |
static pid_t
create_pipe (const char *progname,
const char *prog_path, char **prog_argv,
bool pipe_stdin, bool pipe_stdout,
const char *prog_stdin, const char *prog_stdout,
bool null_stderr,
bool slave_process, bool exit_on_error,
int fd[2])
{
#if defined _MSC_VER || defined __MINGW32__
/* Native Woe32 API.
This uses _pipe(), dup2(), and spawnv(). It could also be implemented
using the low-level functions CreatePipe(), DuplicateHandle(),
CreateProcess() and _open_osfhandle(); see the GNU make and GNU clisp
and cvs source code. */
int ifd[2];
int ofd[2];
int orig_stdin;
int orig_stdout;
int orig_stderr;
int child;
int nulloutfd;
int stdinfd;
int stdoutfd;
/* FIXME: Need to free memory allocated by prepare_spawn. */
prog_argv = prepare_spawn (prog_argv);
if (pipe_stdout)
if (_pipe (ifd, 4096, O_BINARY | O_NOINHERIT) < 0
|| (ifd[0] = fd_safer (ifd[0])) < 0)
error (EXIT_FAILURE, errno, _("cannot create pipe"));
if (pipe_stdin)
if (_pipe (ofd, 4096, O_BINARY | O_NOINHERIT) < 0
|| (ofd[1] = fd_safer (ofd[1])) < 0)
error (EXIT_FAILURE, errno, _("cannot create pipe"));
/* Data flow diagram:
*
* write system read
* parent -> ofd[1] -> ofd[0] -> child if pipe_stdin
* parent <- ifd[0] <- ifd[1] <- child if pipe_stdout
* read system write
*
*/
/* Save standard file handles of parent process. */
if (pipe_stdin || prog_stdin != NULL)
orig_stdin = dup_noinherit (STDIN_FILENO);
if (pipe_stdout || prog_stdout != NULL)
orig_stdout = dup_noinherit (STDOUT_FILENO);
if (null_stderr)
orig_stderr = dup_noinherit (STDERR_FILENO);
child = -1;
/* Create standard file handles of child process. */
nulloutfd = -1;
stdinfd = -1;
stdoutfd = -1;
if ((!pipe_stdin || dup2 (ofd[0], STDIN_FILENO) >= 0)
&& (!pipe_stdout || dup2 (ifd[1], STDOUT_FILENO) >= 0)
&& (!null_stderr
|| ((nulloutfd = open ("NUL", O_RDWR, 0)) >= 0
&& (nulloutfd == STDERR_FILENO
|| (dup2 (nulloutfd, STDERR_FILENO) >= 0
&& close (nulloutfd) >= 0))))
&& (pipe_stdin
|| prog_stdin == NULL
|| ((stdinfd = open (prog_stdin, O_RDONLY, 0)) >= 0
&& (stdinfd == STDIN_FILENO
|| (dup2 (stdinfd, STDIN_FILENO) >= 0
&& close (stdinfd) >= 0))))
&& (pipe_stdout
|| prog_stdout == NULL
|| ((stdoutfd = open (prog_stdout, O_WRONLY, 0)) >= 0
&& (stdoutfd == STDOUT_FILENO
|| (dup2 (stdoutfd, STDOUT_FILENO) >= 0
&& close (stdoutfd) >= 0)))))
/* The child process doesn't inherit ifd[0], ifd[1], ofd[0], ofd[1],
but it inherits all open()ed or dup2()ed file handles (which is what
we want in the case of STD*_FILENO) and also orig_stdin,
orig_stdout, orig_stderr (which is not explicitly wanted but
harmless). */
/* Use spawnvpe and pass the environment explicitly. This is needed if
the program has modified the environment using putenv() or [un]setenv().
On Windows, programs have two environments, one in the "environment
block" of the process and managed through SetEnvironmentVariable(), and
one inside the process, in the location retrieved by the 'environ'
macro. When using spawnvp() without 'e', the child process inherits a
copy of the environment block - ignoring the effects of putenv() and
[un]setenv(). */
{
child = spawnvpe (P_NOWAIT, prog_path, prog_argv, environ);
if (child < 0 && errno == ENOEXEC)
{
/* prog is not an native executable. Try to execute it as a
shell script. Note that prepare_spawn() has already prepended
a hidden element "sh.exe" to prog_argv. */
--prog_argv;
child = spawnvpe (P_NOWAIT, prog_argv[0], prog_argv, environ);
}
}
if (stdinfd >= 0)
close (stdinfd);
if (stdoutfd >= 0)
close (stdoutfd);
if (nulloutfd >= 0)
close (nulloutfd);
/* Restore standard file handles of parent process. */
if (null_stderr)
dup2 (orig_stderr, STDERR_FILENO), close (orig_stderr);
if (pipe_stdout || prog_stdout != NULL)
dup2 (orig_stdout, STDOUT_FILENO), close (orig_stdout);
if (pipe_stdin || prog_stdin != NULL)
dup2 (orig_stdin, STDIN_FILENO), close (orig_stdin);
if (pipe_stdin)
close (ofd[0]);
if (pipe_stdout)
close (ifd[1]);
if (child == -1)
{
if (exit_on_error || !null_stderr)
error (exit_on_error ? EXIT_FAILURE : 0, errno,
_("%s subprocess failed"), progname);
if (pipe_stdout)
close (ifd[0]);
if (pipe_stdin)
close (ofd[1]);
return -1;
}
if (pipe_stdout)
fd[0] = ifd[0];
if (pipe_stdin)
fd[1] = ofd[1];
return child;
#else
/* Unix API. */
int ifd[2];
int ofd[2];
# if HAVE_POSIX_SPAWN
sigset_t blocked_signals;
posix_spawn_file_actions_t actions;
bool actions_allocated;
posix_spawnattr_t attrs;
bool attrs_allocated;
int err;
pid_t child;
# else
int child;
# endif
if (pipe_stdout)
if (pipe (ifd) < 0
|| (ifd[0] = fd_safer (ifd[0])) < 0)
error (EXIT_FAILURE, errno, _("cannot create pipe"));
if (pipe_stdin)
if (pipe (ofd) < 0
|| (ofd[1] = fd_safer (ofd[1])) < 0)
error (EXIT_FAILURE, errno, _("cannot create pipe"));
/* Data flow diagram:
*
* write system read
* parent -> ofd[1] -> ofd[0] -> child if pipe_stdin
* parent <- ifd[0] <- ifd[1] <- child if pipe_stdout
* read system write
*
*/
# if HAVE_POSIX_SPAWN
if (slave_process)
{
sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
block_fatal_signals ();
}
actions_allocated = false;
attrs_allocated = false;
if ((err = posix_spawn_file_actions_init (&actions)) != 0
|| (actions_allocated = true,
(pipe_stdin
&& (err = posix_spawn_file_actions_adddup2 (&actions,
ofd[0], STDIN_FILENO))
!= 0)
|| (pipe_stdout
&& (err = posix_spawn_file_actions_adddup2 (&actions,
ifd[1], STDOUT_FILENO))
!= 0)
|| (pipe_stdin
&& (err = posix_spawn_file_actions_addclose (&actions, ofd[0]))
!= 0)
|| (pipe_stdout
&& (err = posix_spawn_file_actions_addclose (&actions, ifd[1]))
!= 0)
|| (pipe_stdin
&& (err = posix_spawn_file_actions_addclose (&actions, ofd[1]))
!= 0)
|| (pipe_stdout
&& (err = posix_spawn_file_actions_addclose (&actions, ifd[0]))
!= 0)
|| (null_stderr
&& (err = posix_spawn_file_actions_addopen (&actions,
STDERR_FILENO,
"/dev/null", O_RDWR,
0))
!= 0)
|| (!pipe_stdin
&& prog_stdin != NULL
&& (err = posix_spawn_file_actions_addopen (&actions,
STDIN_FILENO,
prog_stdin, O_RDONLY,
0))
!= 0)
|| (!pipe_stdout
&& prog_stdout != NULL
&& (err = posix_spawn_file_actions_addopen (&actions,
STDOUT_FILENO,
prog_stdout, O_WRONLY,
0))
!= 0)
|| (slave_process
&& ((err = posix_spawnattr_init (&attrs)) != 0
|| (attrs_allocated = true,
(err = posix_spawnattr_setsigmask (&attrs,
&blocked_signals))
!= 0
|| (err = posix_spawnattr_setflags (&attrs,
POSIX_SPAWN_SETSIGMASK))
!= 0)))
|| (err = posix_spawnp (&child, prog_path, &actions,
attrs_allocated ? &attrs : NULL, prog_argv,
environ))
!= 0))
{
if (actions_allocated)
posix_spawn_file_actions_destroy (&actions);
if (attrs_allocated)
posix_spawnattr_destroy (&attrs);
if (slave_process)
unblock_fatal_signals ();
if (exit_on_error || !null_stderr)
error (exit_on_error ? EXIT_FAILURE : 0, err,
_("%s subprocess failed"), progname);
if (pipe_stdout)
{
close (ifd[0]);
close (ifd[1]);
}
if (pipe_stdin)
{
close (ofd[0]);
close (ofd[1]);
}
return -1;
}
posix_spawn_file_actions_destroy (&actions);
if (attrs_allocated)
posix_spawnattr_destroy (&attrs);
# else
if (slave_process)
block_fatal_signals ();
/* Use vfork() instead of fork() for efficiency. */
if ((child = vfork ()) == 0)
{
/* Child process code. */
int nulloutfd;
int stdinfd;
int stdoutfd;
if ((!pipe_stdin || dup2 (ofd[0], STDIN_FILENO) >= 0)
&& (!pipe_stdout || dup2 (ifd[1], STDOUT_FILENO) >= 0)
&& (!pipe_stdin || close (ofd[0]) >= 0)
&& (!pipe_stdout || close (ifd[1]) >= 0)
&& (!pipe_stdin || close (ofd[1]) >= 0)
&& (!pipe_stdout || close (ifd[0]) >= 0)
&& (!null_stderr
|| ((nulloutfd = open ("/dev/null", O_RDWR, 0)) >= 0
&& (nulloutfd == STDERR_FILENO
|| (dup2 (nulloutfd, STDERR_FILENO) >= 0
&& close (nulloutfd) >= 0))))
&& (pipe_stdin
|| prog_stdin == NULL
|| ((stdinfd = open (prog_stdin, O_RDONLY, 0)) >= 0
&& (stdinfd == STDIN_FILENO
|| (dup2 (stdinfd, STDIN_FILENO) >= 0
&& close (stdinfd) >= 0))))
&& (pipe_stdout
|| prog_stdout == NULL
|| ((stdoutfd = open (prog_stdout, O_WRONLY, 0)) >= 0
&& (stdoutfd == STDOUT_FILENO
|| (dup2 (stdoutfd, STDOUT_FILENO) >= 0
&& close (stdoutfd) >= 0))))
&& (!slave_process || (unblock_fatal_signals (), true)))
execvp (prog_path, prog_argv);
_exit (127);
}
if (child == -1)
{
if (slave_process)
unblock_fatal_signals ();
if (exit_on_error || !null_stderr)
error (exit_on_error ? EXIT_FAILURE : 0, errno,
_("%s subprocess failed"), progname);
if (pipe_stdout)
{
close (ifd[0]);
close (ifd[1]);
}
if (pipe_stdin)
{
close (ofd[0]);
close (ofd[1]);
}
return -1;
}
# endif
if (slave_process)
{
register_slave_subprocess (child);
unblock_fatal_signals ();
}
if (pipe_stdin)
close (ofd[0]);
if (pipe_stdout)
close (ifd[1]);
if (pipe_stdout)
fd[0] = ifd[0];
if (pipe_stdin)
fd[1] = ofd[1];
return child;
#endif
}
|
|||||
| ↓ | strftime_case_ | 283 | 435 | 1016 | lib/strftime.c |
static size_t
strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
STRFTIME_ARG (size_t maxsize)
const CHAR_T *format,
const struct tm *tp extra_args_spec LOCALE_PARAM_PROTO)
{
#if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
struct locale_data *const current = loc->__locales[LC_TIME];
#endif
#if FPRINTFTIME
size_t maxsize = (size_t) -1;
#endif
int hour12 = tp->tm_hour;
#ifdef _NL_CURRENT
/* We cannot make the following values variables since we must delay
the evaluation of these values until really needed since some
expressions might not be valid in every situation. The `struct tm'
might be generated by a strptime() call that initialized
only a few elements. Dereference the pointers only if the format
requires this. Then it is ok to fail if the pointers are invalid. */
# define a_wkday \
((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday))
# define f_wkday \
((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday))
# define a_month \
((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon))
# define f_month \
((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon))
# define ampm \
((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11 \
? NLW(PM_STR) : NLW(AM_STR)))
# define aw_len STRLEN (a_wkday)
# define am_len STRLEN (a_month)
# define ap_len STRLEN (ampm)
#endif
const char *zone;
size_t i = 0;
STREAM_OR_CHAR_T *p = s;
const CHAR_T *f;
#if DO_MULTIBYTE && !defined COMPILE_WIDE
const char *format_end = NULL;
#endif
#if ! defined _LIBC && ! HAVE_RUN_TZSET_TEST
/* Solaris 2.5.x and 2.6 tzset sometimes modify the storage returned
by localtime. On such systems, we must either use the tzset and
localtime wrappers to work around the bug (which sets
HAVE_RUN_TZSET_TEST) or make a copy of the structure. */
struct tm copy = *tp;
tp = ©
#endif
zone = NULL;
#if HAVE_TM_ZONE
/* The POSIX test suite assumes that setting
the environment variable TZ to a new value before calling strftime()
will influence the result (the %Z format) even if the information in
TP is computed with a totally different time zone.
This is bogus: though POSIX allows bad behavior like this,
POSIX does not require it. Do the right thing instead. */
zone = (const char *) tp->tm_zone;
#endif
#if HAVE_TZNAME
if (ut)
{
if (! (zone && *zone))
zone = "GMT";
}
else
{
/* POSIX.1 requires that local time zone information be used as
though strftime called tzset. */
# if HAVE_TZSET
tzset ();
# endif
}
#endif
if (hour12 > 12)
hour12 -= 12;
else
if (hour12 == 0)
hour12 = 12;
for (f = format; *f != '\0'; ++f)
{
int pad = 0; /* Padding for number ('-', '_', or 0). */
int modifier; /* Field modifier ('E', 'O', or 0). */
int digits = 0; /* Max digits for numeric format. */
int number_value; /* Numeric value to be printed. */
unsigned int u_number_value; /* (unsigned int) number_value. */
bool negative_number; /* The number is negative. */
bool always_output_a_sign; /* +/- should always be output. */
int tz_colon_mask; /* Bitmask of where ':' should appear. */
const CHAR_T *subfmt;
CHAR_T sign_char;
CHAR_T *bufp;
CHAR_T buf[1
+ 2 /* for the two colons in a %::z or %:::z time zone */
+ (sizeof (int) < sizeof (time_t)
? INT_STRLEN_BOUND (time_t)
: INT_STRLEN_BOUND (int))];
int width = -1;
bool to_lowcase = false;
bool to_uppcase = upcase;
size_t colons;
bool change_case = false;
int format_char;
#if DO_MULTIBYTE && !defined COMPILE_WIDE
switch (*f)
{
case L_('%'):
break;
case L_('\b'): case L_('\t'): case L_('\n'):
case L_('\v'): case L_('\f'): case L_('\r'):
case L_(' '): case L_('!'): case L_('"'): case L_('#'): case L_('&'):
case L_('\''): case L_('('): case L_(')'): case L_('*'): case L_('+'):
case L_(','): case L_('-'): case L_('.'): case L_('/'): case L_('0'):
case L_('1'): case L_('2'): case L_('3'): case L_('4'): case L_('5'):
case L_('6'): case L_('7'): case L_('8'): case L_('9'): case L_(':'):
case L_(';'): case L_('<'): case L_('='): case L_('>'): case L_('?'):
case L_('A'): case L_('B'): case L_('C'): case L_('D'): case L_('E'):
case L_('F'): case L_('G'): case L_('H'): case L_('I'): case L_('J'):
case L_('K'): case L_('L'): case L_('M'): case L_('N'): case L_('O'):
case L_('P'): case L_('Q'): case L_('R'): case L_('S'): case L_('T'):
case L_('U'): case L_('V'): case L_('W'): case L_('X'): case L_('Y'):
case L_('Z'): case L_('['): case L_('\\'): case L_(']'): case L_('^'):
case L_('_'): case L_('a'): case L_('b'): case L_('c'): case L_('d'):
case L_('e'): case L_('f'): case L_('g'): case L_('h'): case L_('i'):
case L_('j'): case L_('k'): case L_('l'): case L_('m'): case L_('n'):
case L_('o'): case L_('p'): case L_('q'): case L_('r'): case L_('s'):
case L_('t'): case L_('u'): case L_('v'): case L_('w'): case L_('x'):
case L_('y'): case L_('z'): case L_('{'): case L_('|'): case L_('}'):
case L_('~'):
/* The C Standard requires these 98 characters (plus '%') to
be in the basic execution character set. None of these
characters can start a multibyte sequence, so they need
not be analyzed further. */
add1 (*f);
continue;
default:
/* Copy this multibyte sequence until we reach its end, find
an error, or come back to the initial shift state. */
{
mbstate_t mbstate = mbstate_zero;
size_t len = 0;
size_t fsize;
if (! format_end)
format_end = f + strlen (f) + 1;
fsize = format_end - f;
do
{
size_t bytes = mbrlen (f + len, fsize - len, &mbstate);
if (bytes == 0)
break;
if (bytes == (size_t) -2)
{
len += strlen (f + len);
break;
}
if (bytes == (size_t) -1)
{
len++;
break;
}
len += bytes;
}
while (! mbsinit (&mbstate));
cpy (len, f);
f += len - 1;
continue;
}
}
#else /* ! DO_MULTIBYTE */
/* Either multibyte encodings are not supported, they are
safe for formats, so any non-'%' byte can be copied through,
or this is the wide character version. */
if (*f != L_('%'))
{
add1 (*f);
continue;
}
#endif /* ! DO_MULTIBYTE */
/* Check for flags that can modify a format. */
while (1)
{
switch (*++f)
{
/* This influences the number formats. */
case L_('_'):
case L_('-'):
case L_('0'):
pad = *f;
continue;
/* This changes textual output. */
case L_('^'):
to_uppcase = true;
continue;
case L_('#'):
change_case = true;
continue;
default:
break;
}
break;
}
/* As a GNU extension we allow to specify the field width. */
if (ISDIGIT (*f))
{
width = 0;
do
{
if (width > INT_MAX / 10
|| (width == INT_MAX / 10 && *f - L_('0') > INT_MAX % 10))
/* Avoid overflow. */
width = INT_MAX;
else
{
width *= 10;
width += *f - L_('0');
}
++f;
}
while (ISDIGIT (*f));
}
/* Check for modifiers. */
switch (*f)
{
case L_('E'):
case L_('O'):
modifier = *f++;
break;
default:
modifier = 0;
break;
}
/* Now do the specified format. */
format_char = *f;
switch (format_char)
{
#define DO_NUMBER(d, v) \
digits = d; \
number_value = v; goto do_number
#define DO_SIGNED_NUMBER(d, negative, v) \
digits = d; \
negative_number = negative; \
u_number_value = v; goto do_signed_number
/* The mask is not what you might think.
When the ordinal i'th bit is set, insert a colon
before the i'th digit of the time zone representation. */
#define DO_TZ_OFFSET(d, negative, mask, v) \
digits = d; \
negative_number = negative; \
tz_colon_mask = mask; \
u_number_value = v; goto do_tz_offset
#define DO_NUMBER_SPACEPAD(d, v) \
digits = d; \
number_value = v; goto do_number_spacepad
case L_('%'):
if (modifier != 0)
goto bad_format;
add1 (*f);
break;
case L_('a'):
if (modifier != 0)
goto bad_format;
if (change_case)
{
to_uppcase = true;
to_lowcase = false;
}
#ifdef _NL_CURRENT
cpy (aw_len, a_wkday);
break;
#else
goto underlying_strftime;
#endif
case 'A':
if (modifier != 0)
goto bad_format;
if (change_case)
{
to_uppcase = true;
to_lowcase = false;
}
#ifdef _NL_CURRENT
cpy (STRLEN (f_wkday), f_wkday);
break;
#else
goto underlying_strftime;
#endif
case L_('b'):
case L_('h'):
if (change_case)
{
to_uppcase = true;
to_lowcase = false;
}
if (modifier != 0)
goto bad_format;
#ifdef _NL_CURRENT
cpy (am_len, a_month);
break;
#else
goto underlying_strftime;
#endif
case L_('B'):
if (modifier != 0)
goto bad_format;
if (change_case)
{
to_uppcase = true;
to_lowcase = false;
}
#ifdef _NL_CURRENT
cpy (STRLEN (f_month), f_month);
break;
#else
goto underlying_strftime;
#endif
case L_('c'):
if (modifier == L_('O'))
goto bad_format;
#ifdef _NL_CURRENT
if (! (modifier == 'E'
&& (*(subfmt =
(const CHAR_T *) _NL_CURRENT (LC_TIME,
NLW(ERA_D_T_FMT)))
!= '\0')))
subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_T_FMT));
#else
goto underlying_strftime;
#endif
subformat:
{
size_t len = strftime_case_ (to_uppcase,
NULL, STRFTIME_ARG ((size_t) -1)
subfmt,
tp extra_args LOCALE_ARG);
add (len, strftime_case_ (to_uppcase, p,
STRFTIME_ARG (maxsize - i)
subfmt,
tp extra_args LOCALE_ARG));
}
break;
#if !(defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
underlying_strftime:
{
/* The relevant information is available only via the
underlying strftime implementation, so use that. */
char ufmt[5];
char *u = ufmt;
char ubuf[1024]; /* enough for any single format in practice */
size_t len;
/* Make sure we're calling the actual underlying strftime.
In some cases, config.h contains something like
"#define strftime rpl_strftime". */
# ifdef strftime
# undef strftime
size_t strftime ();
# endif
/* The space helps distinguish strftime failure from empty
output. */
*u++ = ' ';
*u++ = '%';
if (modifier != 0)
*u++ = modifier;
*u++ = format_char;
*u = '\0';
len = strftime (ubuf, sizeof ubuf, ufmt, tp);
if (len != 0)
cpy (len - 1, ubuf + 1);
}
break;
#endif
case L_('C'):
if (modifier == L_('O'))
goto bad_format;
if (modifier == L_('E'))
{
#if HAVE_STRUCT_ERA_ENTRY
struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
if (era)
{
# ifdef COMPILE_WIDE
size_t len = __wcslen (era->era_wname);
cpy (len, era->era_wname);
# else
size_t len = strlen (era->era_name);
cpy (len, era->era_name);
# endif
break;
}
#else
goto underlying_strftime;
#endif
}
{
int century = tp->tm_year / 100 + TM_YEAR_BASE / 100;
century -= tp->tm_year % 100 < 0 && 0 < century;
DO_SIGNED_NUMBER (2, tp->tm_year < - TM_YEAR_BASE, century);
}
case L_('x'):
if (modifier == L_('O'))
goto bad_format;
#ifdef _NL_CURRENT
if (! (modifier == L_('E')
&& (*(subfmt =
(const CHAR_T *)_NL_CURRENT (LC_TIME, NLW(ERA_D_FMT)))
!= L_('\0'))))
subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_FMT));
goto subformat;
#else
goto underlying_strftime;
#endif
case L_('D'):
if (modifier != 0)
goto bad_format;
subfmt = L_("%m/%d/%y");
goto subformat;
case L_('d'):
if (modifier == L_('E'))
goto bad_format;
DO_NUMBER (2, tp->tm_mday);
case L_('e'):
if (modifier == L_('E'))
goto bad_format;
DO_NUMBER_SPACEPAD (2, tp->tm_mday);
/* All numeric formats set DIGITS and NUMBER_VALUE (or U_NUMBER_VALUE)
and then jump to one of these labels. */
do_tz_offset:
always_output_a_sign = true;
goto do_number_body;
do_number_spacepad:
/* Force `_' flag unless overridden by `0' or `-' flag. */
if (pad != L_('0') && pad != L_('-'))
pad = L_('_');
do_number:
/* Format NUMBER_VALUE according to the MODIFIER flag. */
negative_number = number_value < 0;
u_number_value = number_value;
do_signed_number:
always_output_a_sign = false;
tz_colon_mask = 0;
do_number_body:
/* Format U_NUMBER_VALUE according to the MODIFIER flag.
NEGATIVE_NUMBER is nonzero if the original number was
negative; in this case it was converted directly to
unsigned int (i.e., modulo (UINT_MAX + 1)) without
negating it. */
if (modifier == L_('O') && !negative_number)
{
#ifdef _NL_CURRENT
/* Get the locale specific alternate representation of
the number. If none exist NULL is returned. */
const CHAR_T *cp = nl_get_alt_digit (u_number_value
HELPER_LOCALE_ARG);
if (cp != NULL)
{
size_t digitlen = STRLEN (cp);
if (digitlen != 0)
{
cpy (digitlen, cp);
break;
}
}
#else
goto underlying_strftime;
#endif
}
bufp = buf + sizeof (buf) / sizeof (buf[0]);
if (negative_number)
u_number_value = - u_number_value;
do
{
if (tz_colon_mask & 1)
*--bufp = ':';
tz_colon_mask >>= 1;
*--bufp = u_number_value % 10 + L_('0');
u_number_value /= 10;
}
while (u_number_value != 0 || tz_colon_mask != 0);
do_number_sign_and_padding:
if (digits < width)
digits = width;
sign_char = (negative_number ? L_('-')
: always_output_a_sign ? L_('+')
: 0);
if (pad == L_('-'))
{
if (sign_char)
add1 (sign_char);
}
else
{
int padding = digits - (buf + (sizeof (buf) / sizeof (buf[0]))
- bufp) - !!sign_char;
if (padding > 0)
{
if (pad == L_('_'))
{
if ((size_t) padding >= maxsize - i)
return 0;
if (p)
memset_space (p, padding);
i += padding;
width = width > padding ? width - padding : 0;
if (sign_char)
add1 (sign_char);
}
else
{
if ((size_t) digits >= maxsize - i)
return 0;
if (sign_char)
add1 (sign_char);
if (p)
memset_zero (p, padding);
i += padding;
width = 0;
}
}
else
{
if (sign_char)
add1 (sign_char);
}
}
cpy (buf + sizeof (buf) / sizeof (buf[0]) - bufp, bufp);
break;
case L_('F'):
if (modifier != 0)
goto bad_format;
subfmt = L_("%Y-%m-%d");
goto subformat;
case L_('H'):
if (modifier == L_('E'))
goto bad_format;
DO_NUMBER (2, tp->tm_hour);
case L_('I'):
if (modifier == L_('E'))
goto bad_format;
DO_NUMBER (2, hour12);
case L_('k'): /* GNU extension. */
if (modifier == L_('E'))
goto bad_format;
DO_NUMBER_SPACEPAD (2, tp->tm_hour);
case L_('l'): /* GNU extension. */
if (modifier == L_('E'))
goto bad_format;
DO_NUMBER_SPACEPAD (2, hour12);
case L_('j'):
if (modifier == L_('E'))
goto bad_format;
DO_SIGNED_NUMBER (3, tp->tm_yday < -1, tp->tm_yday + 1U);
case L_('M'):
if (modifier == L_('E'))
goto bad_format;
DO_NUMBER (2, tp->tm_min);
case L_('m'):
if (modifier == L_('E'))
goto bad_format;
DO_SIGNED_NUMBER (2, tp->tm_mon < -1, tp->tm_mon + 1U);
#ifndef _LIBC
case L_('N'): /* GNU extension. */
if (modifier == L_('E'))
goto bad_format;
number_value = ns;
if (width == -1)
width = 9;
else
{
/* Take an explicit width less than 9 as a precision. */
int j;
for (j = width; j < 9; j++)
number_value /= 10;
}
DO_NUMBER (width, number_value);
#endif
case L_('n'):
add1 (L_('\n'));
break;
case L_('P'):
to_lowcase = true;
#ifndef _NL_CURRENT
format_char = L_('p');
#endif
/* FALLTHROUGH */
case L_('p'):
if (change_case)
{
to_uppcase = false;
to_lowcase = true;
}
#ifdef _NL_CURRENT
cpy (ap_len, ampm);
break;
#else
goto underlying_strftime;
#endif
case L_('R'):
subfmt = L_("%H:%M");
goto subformat;
case L_('r'):
#ifdef _NL_CURRENT
if (*(subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME,
NLW(T_FMT_AMPM)))
== L_('\0'))
subfmt = L_("%I:%M:%S %p");
goto subformat;
#else
goto underlying_strftime;
#endif
case L_('S'):
if (modifier == L_('E'))
goto bad_format;
DO_NUMBER (2, tp->tm_sec);
case L_('s'): /* GNU extension. */
{
struct tm ltm;
time_t t;
ltm = *tp;
t = mktime (<m);
/* Generate string value for T using time_t arithmetic;
this works even if sizeof (long) < sizeof (time_t). */
bufp = buf + sizeof (buf) / sizeof (buf[0]);
negative_number = t < 0;
do
{
int d = t % 10;
t /= 10;
*--bufp = (negative_number ? -d : d) + L_('0');
}
while (t != 0);
digits = 1;
always_output_a_sign = false;
goto do_number_sign_and_padding;
}
case L_('X'):
if (modifier == L_('O'))
goto bad_format;
#ifdef _NL_CURRENT
if (! (modifier == L_('E')
&& (*(subfmt =
(const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ERA_T_FMT)))
!= L_('\0'))))
subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(T_FMT));
goto subformat;
#else
goto underlying_strftime;
#endif
case L_('T'):
subfmt = L_("%H:%M:%S");
goto subformat;
case L_('t'):
add1 (L_('\t'));
break;
case L_('u'):
DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
case L_('U'):
if (modifier == L_('E'))
goto bad_format;
DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
case L_('V'):
case L_('g'):
case L_('G'):
if (modifier == L_('E'))
goto bad_format;
{
/* YEAR is a leap year if and only if (tp->tm_year + TM_YEAR_BASE)
is a leap year, except that YEAR and YEAR - 1 both work
correctly even when (tp->tm_year + TM_YEAR_BASE) would
overflow. */
int year = (tp->tm_year
+ (tp->tm_year < 0
? TM_YEAR_BASE % 400
: TM_YEAR_BASE % 400 - 400));
int year_adjust = 0;
int days = iso_week_days (tp->tm_yday, tp->tm_wday);
if (days < 0)
{
/* This ISO week belongs to the previous year. */
year_adjust = -1;
days = iso_week_days (tp->tm_yday + (365 + __isleap (year - 1)),
tp->tm_wday);
}
else
{
int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
tp->tm_wday);
if (0 <= d)
{
/* This ISO week belongs to the next year. */
year_adjust = 1;
days = d;
}
}
switch (*f)
{
case L_('g'):
{
int yy = (tp->tm_year % 100 + year_adjust) % 100;
DO_NUMBER (2, (0 <= yy
? yy
: tp->tm_year < -TM_YEAR_BASE - year_adjust
? -yy
: yy + 100));
}
case L_('G'):
DO_SIGNED_NUMBER (4, tp->tm_year < -TM_YEAR_BASE - year_adjust,
(tp->tm_year + (unsigned int) TM_YEAR_BASE
+ year_adjust));
default:
DO_NUMBER (2, days / 7 + 1);
}
}
case L_('W'):
if (modifier == L_('E'))
goto bad_format;
DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
case L_('w'):
if (modifier == L_('E'))
goto bad_format;
DO_NUMBER (1, tp->tm_wday);
case L_('Y'):
if (modifier == 'E')
{
#if HAVE_STRUCT_ERA_ENTRY
struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
if (era)
{
# ifdef COMPILE_WIDE
subfmt = era->era_wformat;
# else
subfmt = era->era_format;
# endif
goto subformat;
}
#else
goto underlying_strftime;
#endif
}
if (modifier == L_('O'))
goto bad_format;
else
DO_SIGNED_NUMBER (4, tp->tm_year < -TM_YEAR_BASE,
tp->tm_year + (unsigned int) TM_YEAR_BASE);
case L_('y'):
if (modifier == L_('E'))
{
#if HAVE_STRUCT_ERA_ENTRY
struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
if (era)
{
int delta = tp->tm_year - era->start_date[0];
DO_NUMBER (1, (era->offset
+ delta * era->absolute_direction));
}
#else
goto underlying_strftime;
#endif
}
{
int yy = tp->tm_year % 100;
if (yy < 0)
yy = tp->tm_year < - TM_YEAR_BASE ? -yy : yy + 100;
DO_NUMBER (2, yy);
}
case L_('Z'):
if (change_case)
{
to_uppcase = false;
to_lowcase = true;
}
#if HAVE_TZNAME
/* The tzset() call might have changed the value. */
if (!(zone && *zone) && tp->tm_isdst >= 0)
zone = tzname[tp->tm_isdst != 0];
#endif
if (! zone)
zone = "";
#ifdef COMPILE_WIDE
{
/* The zone string is always given in multibyte form. We have
to transform it first. */
wchar_t *wczone;
size_t len;
widen (zone, wczone, len);
cpy (len, wczone);
}
#else
cpy (strlen (zone), zone);
#endif
break;
case L_(':'):
/* :, ::, and ::: are valid only just before 'z'.
:::: etc. are rejected later. */
for (colons = 1; f[colons] == L_(':'); colons++)
continue;
if (f[colons] != L_('z'))
goto bad_format;
f += colons;
goto do_z_conversion;
case L_('z'):
colons = 0;
do_z_conversion:
if (tp->tm_isdst < 0)
break;
{
int diff;
int hour_diff;
int min_diff;
int sec_diff;
#if HAVE_TM_GMTOFF
diff = tp->tm_gmtoff;
#else
if (ut)
diff = 0;
else
{
struct tm gtm;
struct tm ltm;
time_t lt;
ltm = *tp;
lt = mktime (<m);
if (lt == (time_t) -1)
{
/* mktime returns -1 for errors, but -1 is also a
valid time_t value. Check whether an error really
occurred. */
struct tm tm;
if (! __localtime_r (<, &tm)
|| ((ltm.tm_sec ^ tm.tm_sec)
| (ltm.tm_min ^ tm.tm_min)
| (ltm.tm_hour ^ tm.tm_hour)
| (ltm.tm_mday ^ tm.tm_mday)
| (ltm.tm_mon ^ tm.tm_mon)
| (ltm.tm_year ^ tm.tm_year)))
break;
}
if (! __gmtime_r (<, >m))
break;
diff = tm_diff (<m, >m);
}
#endif
hour_diff = diff / 60 / 60;
min_diff = diff / 60 % 60;
sec_diff = diff % 60;
switch (colons)
{
case 0: /* +hhmm */
DO_TZ_OFFSET (5, diff < 0, 0, hour_diff * 100 + min_diff);
case 1: tz_hh_mm: /* +hh:mm */
DO_TZ_OFFSET (6, diff < 0, 04, hour_diff * 100 + min_diff);
case 2: tz_hh_mm_ss: /* +hh:mm:ss */
DO_TZ_OFFSET (9, diff < 0, 024,
hour_diff * 10000 + min_diff * 100 + sec_diff);
case 3: /* +hh if possible, else +hh:mm, else +hh:mm:ss */
if (sec_diff != 0)
goto tz_hh_mm_ss;
if (min_diff != 0)
goto tz_hh_mm;
DO_TZ_OFFSET (3, diff < 0, 0, hour_diff);
default:
goto bad_format;
}
}
case L_('\0'): /* GNU extension: % at end of format. */
--f;
/* Fall through. */
default:
/* Unknown format; output the format, including the '%',
since this is most likely the right thing to do if a
multibyte string has been misparsed. */
bad_format:
{
int flen;
for (flen = 1; f[1 - flen] != L_('%'); flen++)
continue;
cpy (flen, &f[1 - flen]);
}
break;
}
}
#if ! FPRINTFTIME
if (p && maxsize != 0)
*p = L_('\0');
#endif
return i;
}
|
|||||
| ↓ | mem_cd_iconveh_internal | 123 | 341 | 656 | lib/striconveh.c |
static int
mem_cd_iconveh_internal (const char *src, size_t srclen,
iconv_t cd, iconv_t cd1, iconv_t cd2,
enum iconv_ilseq_handler handler,
size_t extra_alloc,
size_t *offsets,
char **resultp, size_t *lengthp)
{
/* When a conversion error occurs, we cannot start using CD1 and CD2 at
this point: FROM_CODESET may be a stateful encoding like ISO-2022-KR.
Instead, we have to start afresh from the beginning of SRC. */
/* Use a temporary buffer, so that for small strings, a single malloc()
call will be sufficient. */
# define tmpbufsize 4096
/* The alignment is needed when converting e.g. to glibc's WCHAR_T or
libiconv's UCS-4-INTERNAL encoding. */
union { unsigned int align; char buf[tmpbufsize]; } tmp;
# define tmpbuf tmp.buf
char *initial_result;
char *result;
size_t allocated;
size_t length;
size_t last_length = (size_t)(-1); /* only needed if offsets != NULL */
if (*resultp != NULL && *lengthp >= sizeof (tmpbuf))
{
initial_result = *resultp;
allocated = *lengthp;
}
else
{
initial_result = tmpbuf;
allocated = sizeof (tmpbuf);
}
result = initial_result;
/* Test whether a direct conversion is possible at all. */
if (cd == (iconv_t)(-1))
goto indirectly;
if (offsets != NULL)
{
size_t i;
for (i = 0; i < srclen; i++)
offsets[i] = (size_t)(-1);
last_length = (size_t)(-1);
}
length = 0;
/* First, try a direct conversion, and see whether a conversion error
occurs at all. */
{
const char *inptr = src;
size_t insize = srclen;
/* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
# if defined _LIBICONV_VERSION \
|| !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
/* Set to the initial state. */
iconv (cd, NULL, NULL, NULL, NULL);
# endif
while (insize > 0)
{
char *outptr = result + length;
size_t outsize = allocated - extra_alloc - length;
bool incremented;
size_t res;
bool grow;
if (offsets != NULL)
{
if (length != last_length) /* ensure that offset[] be increasing */
{
offsets[inptr - src] = length;
last_length = length;
}
res = iconv_carefully_1 (cd,
&inptr, &insize,
&outptr, &outsize,
&incremented);
}
else
/* Use iconv_carefully instead of iconv here, because:
- If TO_CODESET is UTF-8, we can do the error handling in this
loop, no need for a second loop,
- With iconv() implementations other than GNU libiconv and GNU
libc, if we use iconv() in a big swoop, checking for an E2BIG
return, we lose the number of irreversible conversions. */
res = iconv_carefully (cd,
&inptr, &insize,
&outptr, &outsize,
&incremented);
length = outptr - result;
grow = (length + extra_alloc > allocated / 2);
if (res == (size_t)(-1))
{
if (errno == E2BIG)
grow = true;
else if (errno == EINVAL)
break;
else if (errno == EILSEQ && handler != iconveh_error)
{
if (cd2 == (iconv_t)(-1))
{
/* TO_CODESET is UTF-8. */
/* Error handling can produce up to 1 byte of output. */
if (length + 1 + extra_alloc > allocated)
{
char *memory;
allocated = 2 * allocated;
if (length + 1 + extra_alloc > allocated)
abort ();
if (result == initial_result)
memory = (char *) malloc (allocated);
else
memory = (char *) realloc (result, allocated);
if (memory == NULL)
{
if (result != initial_result)
free (result);
errno = ENOMEM;
return -1;
}
if (result == initial_result)
memcpy (memory, initial_result, length);
result = memory;
grow = false;
}
/* The input is invalid in FROM_CODESET. Eat up one byte
and emit a question mark. */
if (!incremented)
{
if (insize == 0)
abort ();
inptr++;
insize--;
}
result[length] = '?';
length++;
}
else
goto indirectly;
}
else
{
if (result != initial_result)
{
int saved_errno = errno;
free (result);
errno = saved_errno;
}
return -1;
}
}
if (insize == 0)
break;
if (grow)
{
char *memory;
allocated = 2 * allocated;
if (result == initial_result)
memory = (char *) malloc (allocated);
else
memory = (char *) realloc (result, allocated);
if (memory == NULL)
{
if (result != initial_result)
free (result);
errno = ENOMEM;
return -1;
}
if (result == initial_result)
memcpy (memory, initial_result, length);
result = memory;
}
}
}
/* Now get the conversion state back to the initial state.
But avoid glibc-2.1 bug and Solaris 2.7 bug. */
#if defined _LIBICONV_VERSION \
|| !((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) || defined __sun)
for (;;)
{
char *outptr = result + length;
size_t outsize = allocated - extra_alloc - length;
size_t res;
res = iconv (cd, NULL, NULL, &outptr, &outsize);
length = outptr - result;
if (res == (size_t)(-1))
{
if (errno == E2BIG)
{
char *memory;
allocated = 2 * allocated;
if (result == initial_result)
memory = (char *) malloc (allocated);
else
memory = (char *) realloc (result, allocated);
if (memory == NULL)
{
if (result != initial_result)
free (result);
errno = ENOMEM;
return -1;
}
if (result == initial_result)
memcpy (memory, initial_result, length);
result = memory;
}
else
{
if (result != initial_result)
{
int saved_errno = errno;
free (result);
errno = saved_errno;
}
return -1;
}
}
else
break;
}
#endif
/* The direct conversion succeeded. */
goto done;
indirectly:
/* The direct conversion failed.
Use a conversion through UTF-8. */
if (offsets != NULL)
{
size_t i;
for (i = 0; i < srclen; i++)
offsets[i] = (size_t)(-1);
last_length = (size_t)(-1);
}
length = 0;
{
const bool slowly = (offsets != NULL || handler == iconveh_error);
# define utf8bufsize 4096 /* may also be smaller or larger than tmpbufsize */
char utf8buf[utf8bufsize + 1];
size_t utf8len = 0;
const char *in1ptr = src;
size_t in1size = srclen;
bool do_final_flush1 = true;
bool do_final_flush2 = true;
/* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
# if defined _LIBICONV_VERSION \
|| !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
/* Set to the initial state. */
if (cd1 != (iconv_t)(-1))
iconv (cd1, NULL, NULL, NULL, NULL);
if (cd2 != (iconv_t)(-1))
iconv (cd2, NULL, NULL, NULL, NULL);
# endif
while (in1size > 0 || do_final_flush1 || utf8len > 0 || do_final_flush2)
{
char *out1ptr = utf8buf + utf8len;
size_t out1size = utf8bufsize - utf8len;
bool incremented1;
size_t res1;
int errno1;
/* Conversion step 1: from FROM_CODESET to UTF-8. */
if (in1size > 0)
{
if (offsets != NULL
&& length != last_length) /* ensure that offset[] be increasing */
{
offsets[in1ptr - src] = length;
last_length = length;
}
if (cd1 != (iconv_t)(-1))
{
if (slowly)
res1 = iconv_carefully_1 (cd1,
&in1ptr, &in1size,
&out1ptr, &out1size,
&incremented1);
else
res1 = iconv_carefully (cd1,
&in1ptr, &in1size,
&out1ptr, &out1size,
&incremented1);
}
else
{
/* FROM_CODESET is UTF-8. */
res1 = utf8conv_carefully (slowly,
&in1ptr, &in1size,
&out1ptr, &out1size,
&incremented1);
}
}
else if (do_final_flush1)
{
/* Now get the conversion state of CD1 back to the initial state.
But avoid glibc-2.1 bug and Solaris 2.7 bug. */
# if defined _LIBICONV_VERSION \
|| !((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) || defined __sun)
if (cd1 != (iconv_t)(-1))
res1 = iconv (cd1, NULL, NULL, &out1ptr, &out1size);
else
# endif
res1 = 0;
do_final_flush1 = false;
incremented1 = true;
}
else
{
res1 = 0;
incremented1 = true;
}
if (res1 == (size_t)(-1)
&& !(errno == E2BIG || errno == EINVAL || errno == EILSEQ))
{
if (result != initial_result)
{
int saved_errno = errno;
free (result);
errno = saved_errno;
}
return -1;
}
if (res1 == (size_t)(-1)
&& errno == EILSEQ && handler != iconveh_error)
{
/* The input is invalid in FROM_CODESET. Eat up one byte and
emit a question mark. Room for the question mark was allocated
at the end of utf8buf. */
if (!incremented1)
{
if (in1size == 0)
abort ();
in1ptr++;
in1size--;
}
utf8buf[utf8len++] = '?';
}
errno1 = errno;
utf8len = out1ptr - utf8buf;
if (offsets != NULL
|| in1size == 0
|| utf8len > utf8bufsize / 2
|| (res1 == (size_t)(-1) && errno1 == E2BIG))
{
/* Conversion step 2: from UTF-8 to TO_CODESET. */
const char *in2ptr = utf8buf;
size_t in2size = utf8len;
while (in2size > 0
|| (in1size == 0 && !do_final_flush1 && do_final_flush2))
{
char *out2ptr = result + length;
size_t out2size = allocated - extra_alloc - length;
bool incremented2;
size_t res2;
bool grow;
if (in2size > 0)
{
if (cd2 != (iconv_t)(-1))
res2 = iconv_carefully (cd2,
&in2ptr, &in2size,
&out2ptr, &out2size,
&incremented2);
else
/* TO_CODESET is UTF-8. */
res2 = utf8conv_carefully (false,
&in2ptr, &in2size,
&out2ptr, &out2size,
&incremented2);
}
else /* in1size == 0 && !do_final_flush1
&& in2size == 0 && do_final_flush2 */
{
/* Now get the conversion state of CD1 back to the initial
state. But avoid glibc-2.1 bug and Solaris 2.7 bug. */
# if defined _LIBICONV_VERSION \
|| !((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) || defined __sun)
if (cd2 != (iconv_t)(-1))
res2 = iconv (cd2, NULL, NULL, &out2ptr, &out2size);
else
# endif
res2 = 0;
do_final_flush2 = false;
incremented2 = true;
}
length = out2ptr - result;
grow = (length + extra_alloc > allocated / 2);
if (res2 == (size_t)(-1))
{
if (errno == E2BIG)
grow = true;
else if (errno == EINVAL)
break;
else if (errno == EILSEQ && handler != iconveh_error)
{
/* Error handling can produce up to 10 bytes of ASCII
output. But TO_CODESET may be UCS-2, UTF-16 or
UCS-4, so use CD2 here as well. */
char scratchbuf[10];
size_t scratchlen;
ucs4_t uc;
const char *inptr;
size_t insize;
size_t res;
if (incremented2)
{
if (u8_prev (&uc, (const uint8_t *) in2ptr,
(const uint8_t *) utf8buf)
== NULL)
abort ();
}
else
{
int n;
if (in2size == 0)
abort ();
n = u8_mbtouc_unsafe (&uc, (const uint8_t *) in2ptr,
in2size);
in2ptr += n;
in2size -= n;
}
if (handler == iconveh_escape_sequence)
{
static char hex[16] = "0123456789ABCDEF";
scratchlen = 0;
scratchbuf[scratchlen++] = '\\';
if (uc < 0x10000)
scratchbuf[scratchlen++] = 'u';
else
{
scratchbuf[scratchlen++] = 'U';
scratchbuf[scratchlen++] = hex[(uc>>28) & 15];
scratchbuf[scratchlen++] = hex[(uc>>24) & 15];
scratchbuf[scratchlen++] = hex[(uc>>20) & 15];
scratchbuf[scratchlen++] = hex[(uc>>16) & 15];
}
scratchbuf[scratchlen++] = hex[(uc>>12) & 15];
scratchbuf[scratchlen++] = hex[(uc>>8) & 15];
scratchbuf[scratchlen++] = hex[(uc>>4) & 15];
scratchbuf[scratchlen++] = hex[uc & 15];
}
else
{
scratchbuf[0] = '?';
scratchlen = 1;
}
inptr = scratchbuf;
insize = scratchlen;
if (cd2 != (iconv_t)(-1))
res = iconv (cd2,
(ICONV_CONST char **) &inptr, &insize,
&out2ptr, &out2size);
else
{
/* TO_CODESET is UTF-8. */
if (out2size >= insize)
{
memcpy (out2ptr, inptr, insize);
out2ptr += insize;
out2size -= insize;
inptr += insize;
insize = 0;
res = 0;
}
else
{
errno = E2BIG;
res = (size_t)(-1);
}
}
length = out2ptr - result;
if (res == (size_t)(-1) && errno == E2BIG)
{
char *memory;
allocated = 2 * allocated;
if (length + 1 + extra_alloc > allocated)
abort ();
if (result == initial_result)
memory = (char *) malloc (allocated);
else
memory = (char *) realloc (result, allocated);
if (memory == NULL)
{
if (result != initial_result)
free (result);
errno = ENOMEM;
return -1;
}
if (result == initial_result)
memcpy (memory, initial_result, length);
result = memory;
grow = false;
out2ptr = result + length;
out2size = allocated - extra_alloc - length;
if (cd2 != (iconv_t)(-1))
res = iconv (cd2,
(ICONV_CONST char **) &inptr,
&insize,
&out2ptr, &out2size);
else
{
/* TO_CODESET is UTF-8. */
if (!(out2size >= insize))
abort ();
memcpy (out2ptr, inptr, insize);
out2ptr += insize;
out2size -= insize;
inptr += insize;
insize = 0;
res = 0;
}
length = out2ptr - result;
}
# if !defined _LIBICONV_VERSION && !defined __GLIBC__
/* Irix iconv() inserts a NUL byte if it cannot convert.
NetBSD iconv() inserts a question mark if it cannot
convert.
Only GNU libiconv and GNU libc are known to prefer
to fail rather than doing a lossy conversion. */
if (res != (size_t)(-1) && res > 0)
{
errno = EILSEQ;
res = (size_t)(-1);
}
# endif
if (res == (size_t)(-1))
{
/* Failure converting the ASCII replacement. */
if (result != initial_result)
{
int saved_errno = errno;
free (result);
errno = saved_errno;
}
return -1;
}
}
else
{
if (result != initial_result)
{
int saved_errno = errno;
free (result);
errno = saved_errno;
}
return -1;
}
}
if (!(in2size > 0
|| (in1size == 0 && !do_final_flush1 && do_final_flush2)))
break;
if (grow)
{
char *memory;
allocated = 2 * allocated;
if (result == initial_result)
memory = (char *) malloc (allocated);
else
memory = (char *) realloc (result, allocated);
if (memory == NULL)
{
if (result != initial_result)
free (result);
errno = ENOMEM;
return -1;
}
if (result == initial_result)
memcpy (memory, initial_result, length);
result = memory;
}
}
/* Move the remaining bytes to the beginning of utf8buf. */
if (in2size > 0)
memmove (utf8buf, in2ptr, in2size);
utf8len = in2size;
}
if (res1 == (size_t)(-1))
{
if (errno1 == EINVAL)
in1size = 0;
else if (errno1 == EILSEQ)
{
if (result != initial_result)
free (result);
errno = errno1;
return -1;
}
}
}
# undef utf8bufsize
}
done:
/* Now the final memory allocation. */
if (result == tmpbuf)
{
size_t memsize = length + extra_alloc;
char *memory;
memory = (char *) malloc (memsize > 0 ? memsize : 1);
if (memory != NULL)
{
memcpy (memory, tmpbuf, length);
result = memory;
}
else
{
errno = ENOMEM;
return -1;
}
}
else if (result != *resultp && length + extra_alloc < allocated)
{
/* Shrink the allocated memory if possible. */
size_t memsize = length + extra_alloc;
char *memory;
memory = (char *) realloc (result, memsize > 0 ? memsize : 1);
if (memory != NULL)
result = memory;
}
*resultp = result;
*lengthp = length;
return 0;
# undef tmpbuf
# undef tmpbufsize
}
|
|||||
| ↓ | PRINTF_PARSE | 129 | 293 | 544 | lib/printf-parse.c |
STATIC
#endif
int
PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
{
const CHAR_T *cp = format; /* pointer into format */
size_t arg_posn = 0; /* number of regular arguments consumed */
size_t d_allocated; /* allocated elements of d->dir */
size_t a_allocated; /* allocated elements of a->arg */
size_t max_width_length = 0;
size_t max_precision_length = 0;
d->count = 0;
d_allocated = 1;
d->dir = (DIRECTIVE *) malloc (d_allocated * sizeof (DIRECTIVE));
if (d->dir == NULL)
/* Out of memory. */
goto out_of_memory_1;
a->count = 0;
a_allocated = 0;
a->arg = NULL;
#define REGISTER_ARG(_index_,_type_) \
{ \
size_t n = (_index_); \
if (n >= a_allocated) \
{ \
size_t memory_size; \
argument *memory; \
\
a_allocated = xtimes (a_allocated, 2); \
if (a_allocated <= n) \
a_allocated = xsum (n, 1); \
memory_size = xtimes (a_allocated, sizeof (argument)); \
if (size_overflow_p (memory_size)) \
/* Overflow, would lead to out of memory. */ \
goto out_of_memory; \
memory = (argument *) (a->arg \
? realloc (a->arg, memory_size) \
: malloc (memory_size)); \
if (memory == NULL) \
/* Out of memory. */ \
goto out_of_memory; \
a->arg = memory; \
} \
while (a->count <= n) \
a->arg[a->count++].type = TYPE_NONE; \
if (a->arg[n].type == TYPE_NONE) \
a->arg[n].type = (_type_); \
else if (a->arg[n].type != (_type_)) \
/* Ambiguous type for positional argument. */ \
goto error; \
}
while (*cp != '\0')
{
CHAR_T c = *cp++;
if (c == '%')
{
size_t arg_index = ARG_NONE;
DIRECTIVE *dp = &d->dir[d->count]; /* pointer to next directive */
/* Initialize the next directive. */
dp->dir_start = cp - 1;
dp->flags = 0;
dp->width_start = NULL;
dp->width_end = NULL;
dp->width_arg_index = ARG_NONE;
dp->precision_start = NULL;
dp->precision_end = NULL;
dp->precision_arg_index = ARG_NONE;
dp->arg_index = ARG_NONE;
/* Test for positional argument. */
if (*cp >= '0' && *cp <= '9')
{
const CHAR_T *np;
for (np = cp; *np >= '0' && *np <= '9'; np++)
;
if (*np == '$')
{
size_t n = 0;
for (np = cp; *np >= '0' && *np <= '9'; np++)
n = xsum (xtimes (n, 10), *np - '0');
if (n == 0)
/* Positional argument 0. */
goto error;
if (size_overflow_p (n))
/* n too large, would lead to out of memory later. */
goto error;
arg_index = n - 1;
cp = np + 1;
}
}
/* Read the flags. */
for (;;)
{
if (*cp == '\'')
{
dp->flags |= FLAG_GROUP;
cp++;
}
else if (*cp == '-')
{
dp->flags |= FLAG_LEFT;
cp++;
}
else if (*cp == '+')
{
dp->flags |= FLAG_SHOWSIGN;
cp++;
}
else if (*cp == ' ')
{
dp->flags |= FLAG_SPACE;
cp++;
}
else if (*cp == '#')
{
dp->flags |= FLAG_ALT;
cp++;
}
else if (*cp == '0')
{
dp->flags |= FLAG_ZERO;
cp++;
}
else
break;
}
/* Parse the field width. */
if (*cp == '*')
{
dp->width_start = cp;
cp++;
dp->width_end = cp;
if (max_width_length < 1)
max_width_length = 1;
/* Test for positional argument. */
if (*cp >= '0' && *cp <= '9')
{
const CHAR_T *np;
for (np = cp; *np >= '0' && *np <= '9'; np++)
;
if (*np == '$')
{
size_t n = 0;
for (np = cp; *np >= '0' && *np <= '9'; np++)
n = xsum (xtimes (n, 10), *np - '0');
if (n == 0)
/* Positional argument 0. */
goto error;
if (size_overflow_p (n))
/* n too large, would lead to out of memory later. */
goto error;
dp->width_arg_index = n - 1;
cp = np + 1;
}
}
if (dp->width_arg_index == ARG_NONE)
{
dp->width_arg_index = arg_posn++;
if (dp->width_arg_index == ARG_NONE)
/* arg_posn wrapped around. */
goto error;
}
REGISTER_ARG (dp->width_arg_index, TYPE_INT);
}
else if (*cp >= '0' && *cp <= '9')
{
size_t width_length;
dp->width_start = cp;
for (; *cp >= '0' && *cp <= '9'; cp++)
;
dp->width_end = cp;
width_length = dp->width_end - dp->width_start;
if (max_width_length < width_length)
max_width_length = width_length;
}
/* Parse the precision. */
if (*cp == '.')
{
cp++;
if (*cp == '*')
{
dp->precision_start = cp - 1;
cp++;
dp->precision_end = cp;
if (max_precision_length < 2)
max_precision_length = 2;
/* Test for positional argument. */
if (*cp >= '0' && *cp <= '9')
{
const CHAR_T *np;
for (np = cp; *np >= '0' && *np <= '9'; np++)
;
if (*np == '$')
{
size_t n = 0;
for (np = cp; *np >= '0' && *np <= '9'; np++)
n = xsum (xtimes (n, 10), *np - '0');
if (n == 0)
/* Positional argument 0. */
goto error;
if (size_overflow_p (n))
/* n too large, would lead to out of memory
later. */
goto error;
dp->precision_arg_index = n - 1;
cp = np + 1;
}
}
if (dp->precision_arg_index == ARG_NONE)
{
dp->precision_arg_index = arg_posn++;
if (dp->precision_arg_index == ARG_NONE)
/* arg_posn wrapped around. */
goto error;
}
REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
}
else
{
size_t precision_length;
dp->precision_start = cp - 1;
for (; *cp >= '0' && *cp <= '9'; cp++)
;
dp->precision_end = cp;
precision_length = dp->precision_end - dp->precision_start;
if (max_precision_length < precision_length)
max_precision_length = precision_length;
}
}
{
arg_type type;
/* Parse argument type/size specifiers. */
{
int flags = 0;
for (;;)
{
if (*cp == 'h')
{
flags |= (1 << (flags & 1));
cp++;
}
else if (*cp == 'L')
{
flags |= 4;
cp++;
}
else if (*cp == 'l')
{
flags += 8;
cp++;
}
else if (*cp == 'j')
{
if (sizeof (intmax_t) > sizeof (long))
{
/* intmax_t = long long */
flags += 16;
}
else if (sizeof (intmax_t) > sizeof (int))
{
/* intmax_t = long */
flags += 8;
}
cp++;
}
else if (*cp == 'z' || *cp == 'Z')
{
/* 'z' is standardized in ISO C 99, but glibc uses 'Z'
because the warning facility in gcc-2.95.2 understands
only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784). */
if (sizeof (size_t) > sizeof (long))
{
/* size_t = long long */
flags += 16;
}
else if (sizeof (size_t) > sizeof (int))
{
/* size_t = long */
flags += 8;
}
cp++;
}
else if (*cp == 't')
{
if (sizeof (ptrdiff_t) > sizeof (long))
{
/* ptrdiff_t = long long */
flags += 16;
}
else if (sizeof (ptrdiff_t) > sizeof (int))
{
/* ptrdiff_t = long */
flags += 8;
}
cp++;
}
#if defined __APPLE__ && defined __MACH__
/* On MacOS X 10.3, PRIdMAX is defined as "qd".
We cannot change it to "lld" because PRIdMAX must also
be understood by the system's printf routines. */
else if (*cp == 'q')
{
if (64 / 8 > sizeof (long))
{
/* int64_t = long long */
flags += 16;
}
else
{
/* int64_t = long */
flags += 8;
}
cp++;
}
#endif
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
/* On native Win32, PRIdMAX is defined as "I64d".
We cannot change it to "lld" because PRIdMAX must also
be understood by the system's printf routines. */
else if (*cp == 'I' && cp[1] == '6' && cp[2] == '4')
{
if (64 / 8 > sizeof (long))
{
/* __int64 = long long */
flags += 16;
}
else
{
/* __int64 = long */
flags += 8;
}
cp += 3;
}
#endif
else
break;
}
/* Read the conversion character. */
c = *cp++;
switch (c)
{
case 'd': case 'i':
#if HAVE_LONG_LONG_INT
/* If 'long long' exists and is larger than 'long': */
if (flags >= 16 || (flags & 4))
type = TYPE_LONGLONGINT;
else
#endif
/* If 'long long' exists and is the same as 'long', we parse
"lld" into TYPE_LONGINT. */
if (flags >= 8)
type = TYPE_LONGINT;
else if (flags & 2)
type = TYPE_SCHAR;
else if (flags & 1)
type = TYPE_SHORT;
else
type = TYPE_INT;
break;
case 'o': case 'u': case 'x': case 'X':
#if HAVE_LONG_LONG_INT
/* If 'long long' exists and is larger than 'long': */
if (flags >= 16 || (flags & 4))
type = TYPE_ULONGLONGINT;
else
#endif
/* If 'unsigned long long' exists and is the same as
'unsigned long', we parse "llu" into TYPE_ULONGINT. */
if (flags >= 8)
type = TYPE_ULONGINT;
else if (flags & 2)
type = TYPE_UCHAR;
else if (flags & 1)
type = TYPE_USHORT;
else
type = TYPE_UINT;
break;
case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
case 'a': case 'A':
if (flags >= 16 || (flags & 4))
type = TYPE_LONGDOUBLE;
else
type = TYPE_DOUBLE;
break;
case 'c':
if (flags >= 8)
#if HAVE_WINT_T
type = TYPE_WIDE_CHAR;
#else
goto error;
#endif
else
type = TYPE_CHAR;
break;
#if HAVE_WINT_T
case 'C':
type = TYPE_WIDE_CHAR;
c = 'c';
break;
#endif
case 's':
if (flags >= 8)
#if HAVE_WCHAR_T
type = TYPE_WIDE_STRING;
#else
goto error;
#endif
else
type = TYPE_STRING;
break;
#if HAVE_WCHAR_T
case 'S':
type = TYPE_WIDE_STRING;
c = 's';
break;
#endif
case 'p':
type = TYPE_POINTER;
break;
case 'n':
#if HAVE_LONG_LONG_INT
/* If 'long long' exists and is larger than 'long': */
if (flags >= 16 || (flags & 4))
type = TYPE_COUNT_LONGLONGINT_POINTER;
else
#endif
/* If 'long long' exists and is the same as 'long', we parse
"lln" into TYPE_COUNT_LONGINT_POINTER. */
if (flags >= 8)
type = TYPE_COUNT_LONGINT_POINTER;
else if (flags & 2)
type = TYPE_COUNT_SCHAR_POINTER;
else if (flags & 1)
type = TYPE_COUNT_SHORT_POINTER;
else
type = TYPE_COUNT_INT_POINTER;
break;
#if ENABLE_UNISTDIO
/* The unistdio extensions. */
case 'U':
if (flags >= 16)
type = TYPE_U32_STRING;
else if (flags >= 8)
type = TYPE_U16_STRING;
else
type = TYPE_U8_STRING;
break;
#endif
case '%':
type = TYPE_NONE;
break;
default:
/* Unknown conversion character. */
goto error;
}
}
if (type != TYPE_NONE)
{
dp->arg_index = arg_index;
if (dp->arg_index == ARG_NONE)
{
dp->arg_index = arg_posn++;
if (dp->arg_index == ARG_NONE)
/* arg_posn wrapped around. */
goto error;
}
REGISTER_ARG (dp->arg_index, type);
}
dp->conversion = c;
dp->dir_end = cp;
}
d->count++;
if (d->count >= d_allocated)
{
size_t memory_size;
DIRECTIVE *memory;
d_allocated = xtimes (d_allocated, 2);
memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
if (size_overflow_p (memory_size))
/* Overflow, would lead to out of memory. */
goto out_of_memory;
memory = (DIRECTIVE *) realloc (d->dir, memory_size);
if (memory == NULL)
/* Out of memory. */
goto out_of_memory;
d->dir = memory;
}
}
#if CHAR_T_ONLY_ASCII
else if (!c_isascii (c))
{
/* Non-ASCII character. Not supported. */
goto error;
}
#endif
}
d->dir[d->count].dir_start = cp;
d->max_width_length = max_width_length;
d->max_precision_length = max_precision_length;
return 0;
error:
if (a->arg)
free (a->arg);
if (d->dir)
free (d->dir);
errno = EINVAL;
return -1;
out_of_memory:
if (a->arg)
free (a->arg);
if (d->dir)
free (d->dir);
out_of_memory_1:
errno = ENOMEM;
return -1;
}
|
|||||
| ↓ | _getopt_internal_r | 107 | 312 | 791 | lib/getopt.c |
/* Scan elements of ARGV (whose length is ARGC) for option characters
given in OPTSTRING.
If an element of ARGV starts with '-', and is not exactly "-" or "--",
then it is an option element. The characters of this element
(aside from the initial '-') are option characters. If `getopt'
is called repeatedly, it returns successively each of the option characters
from each of the option elements.
If `getopt' finds another option character, it returns that character,
updating `optind' and `nextchar' so that the next call to `getopt' can
resume the scan with the following option character or ARGV-element.
If there are no more option characters, `getopt' returns -1.
Then `optind' is the index in ARGV of the first ARGV-element
that is not an option. (The ARGV-elements have been permuted
so that those that are not options now come last.)
OPTSTRING is a string containing the legitimate option characters.
If an option character is seen that is not listed in OPTSTRING,
return '?' after printing an error message. If you set `opterr' to
zero, the error message is suppressed but we still return '?'.
If a char in OPTSTRING is followed by a colon, that means it wants an arg,
so the following text in the same ARGV-element, or the text of the following
ARGV-element, is returned in `optarg'. Two colons mean an option that
wants an optional arg; if there is text in the current ARGV-element,
it is returned in `optarg', otherwise `optarg' is set to zero.
If OPTSTRING starts with `-' or `+', it requests different methods of
handling the non-option ARGV-elements.
See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
Long-named options begin with `--' instead of `-'.
Their names may be abbreviated as long as the abbreviation is unique
or is an exact match for some defined option. If they have an
argument, it follows the option name in the same ARGV-element, separated
from the option name by a `=', or else the in next ARGV-element.
When `getopt' finds a long-named option, it returns 0 if that option's
`flag' field is nonzero, the value of the option's `val' field
if the `flag' field is zero.
LONGOPTS is a vector of `struct option' terminated by an
element containing a name which is zero.
LONGIND returns the index in LONGOPT of the long-named option found.
It is only valid when a long-named option has been found by the most
recent call.
If LONG_ONLY is nonzero, '-' as well as '--' can introduce
long-named options.
If POSIXLY_CORRECT is nonzero, behave as if the POSIXLY_CORRECT
environment variable were set. */
int
_getopt_internal_r (int argc, char **argv, const char *optstring,
const struct option *longopts, int *longind,
int long_only, int posixly_correct, struct _getopt_data *d)
{
int print_errors = d->opterr;
if (optstring[0] == ':')
print_errors = 0;
if (argc < 1)
return -1;
d->optarg = NULL;
if (d->optind == 0 || !d->__initialized)
{
if (d->optind == 0)
d->optind = 1; /* Don't scan ARGV[0], the program name. */
optstring = _getopt_initialize (argc, argv, optstring,
posixly_correct, d);
d->__initialized = 1;
}
/* Test whether ARGV[optind] points to a non-option argument.
Either it does not have option syntax, or there is an environment flag
from the shell indicating it is not an option. The later information
is only used when the used in the GNU libc. */
#if defined _LIBC && defined USE_NONOPTION_FLAGS
# define NONOPTION_P (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0' \
|| (d->optind < d->__nonoption_flags_len \
&& __getopt_nonoption_flags[d->optind] == '1'))
#else
# define NONOPTION_P (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0')
#endif
if (d->__nextchar == NULL || *d->__nextchar == '\0')
{
/* Advance to the next ARGV-element. */
/* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
moved back by the user (who may also have changed the arguments). */
if (d->__last_nonopt > d->optind)
d->__last_nonopt = d->optind;
if (d->__first_nonopt > d->optind)
d->__first_nonopt = d->optind;
if (d->__ordering == PERMUTE)
{
/* If we have just processed some options following some non-options,
exchange them so that the options come first. */
if (d->__first_nonopt != d->__last_nonopt
&& d->__last_nonopt != d->optind)
exchange ((char **) argv, d);
else if (d->__last_nonopt != d->optind)
d->__first_nonopt = d->optind;
/* Skip any additional non-options
and extend the range of non-options previously skipped. */
while (d->optind < argc && NONOPTION_P)
d->optind++;
d->__last_nonopt = d->optind;
}
/* The special ARGV-element `--' means premature end of options.
Skip it like a null option,
then exchange with previous non-options as if it were an option,
then skip everything else like a non-option. */
if (d->optind != argc && !strcmp (argv[d->optind], "--"))
{
d->optind++;
if (d->__first_nonopt != d->__last_nonopt
&& d->__last_nonopt != d->optind)
exchange ((char **) argv, d);
else if (d->__first_nonopt == d->__last_nonopt)
d->__first_nonopt = d->optind;
d->__last_nonopt = argc;
d->optind = argc;
}
/* If we have done all the ARGV-elements, stop the scan
and back over any non-options that we skipped and permuted. */
if (d->optind == argc)
{
/* Set the next-arg-index to point at the non-options
that we previously skipped, so the caller will digest them. */
if (d->__first_nonopt != d->__last_nonopt)
d->optind = d->__first_nonopt;
return -1;
}
/* If we have come to a non-option and did not permute it,
either stop the scan or describe it to the caller and pass it by. */
if (NONOPTION_P)
{
if (d->__ordering == REQUIRE_ORDER)
return -1;
d->optarg = argv[d->optind++];
return 1;
}
/* We have found another option-ARGV-element.
Skip the initial punctuation. */
d->__nextchar = (argv[d->optind] + 1
+ (longopts != NULL && argv[d->optind][1] == '-'));
}
/* Decode the current option-ARGV-element. */
/* Check whether the ARGV-element is a long option.
If long_only and the ARGV-element has the form "-f", where f is
a valid short option, don't consider it an abbreviated form of
a long option that starts with f. Otherwise there would be no
way to give the -f short option.
On the other hand, if there's a long option "fubar" and
the ARGV-element is "-fu", do consider that an abbreviation of
the long option, just like "--fu", and not "-f" with arg "u".
This distinction seems to be the most useful approach. */
if (longopts != NULL
&& (argv[d->optind][1] == '-'
|| (long_only && (argv[d->optind][2]
|| !strchr (optstring, argv[d->optind][1])))))
{
char *nameend;
const struct option *p;
const struct option *pfound = NULL;
int exact = 0;
int ambig = 0;
int indfound = -1;
int option_index;
for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++)
/* Do nothing. */ ;
/* Test all long options for either exact match
or abbreviated matches. */
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!strncmp (p->name, d->__nextchar, nameend - d->__nextchar))
{
if ((unsigned int) (nameend - d->__nextchar)
== (unsigned int) strlen (p->name))
{
/* Exact match found. */
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == NULL)
{
/* First nonexact match found. */
pfound = p;
indfound = option_index;
}
else if (long_only
|| pfound->has_arg != p->has_arg
|| pfound->flag != p->flag
|| pfound->val != p->val)
/* Second or later nonexact match found. */
ambig = 1;
}
if (ambig && !exact)
{
if (print_errors)
{
#if defined _LIBC && defined USE_IN_LIBIO
char *buf;
if (__asprintf (&buf, _("%s: option `%s' is ambiguous\n"),
argv[0], argv[d->optind]) >= 0)
{
_IO_flockfile (stderr);
int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
__fxprintf (NULL, "%s", buf);
((_IO_FILE *) stderr)->_flags2 = old_flags2;
_IO_funlockfile (stderr);
free (buf);
}
#else
fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
argv[0], argv[d->optind]);
#endif
}
d->__nextchar += strlen (d->__nextchar);
d->optind++;
d->optopt = 0;
return '?';
}
if (pfound != NULL)
{
option_index = indfound;
d->optind++;
if (*nameend)
{
/* Don't test has_arg with >, because some C compilers don't
allow it to be used on enums. */
if (pfound->has_arg)
d->optarg = nameend + 1;
else
{
if (print_errors)
{
#if defined _LIBC && defined USE_IN_LIBIO
char *buf;
int n;
#endif
if (argv[d->optind - 1][1] == '-')
{
/* --option */
#if defined _LIBC && defined USE_IN_LIBIO
n = __asprintf (&buf, _("\
%s: option `--%s' doesn't allow an argument\n"),
argv[0], pfound->name);
#else
fprintf (stderr, _("\
%s: option `--%s' doesn't allow an argument\n"),
argv[0], pfound->name);
#endif
}
else
{
/* +option or -option */
#if defined _LIBC && defined USE_IN_LIBIO
n = __asprintf (&buf, _("\
%s: option `%c%s' doesn't allow an argument\n"),
argv[0], argv[d->optind - 1][0],
pfound->name);
#else
fprintf (stderr, _("\
%s: option `%c%s' doesn't allow an argument\n"),
argv[0], argv[d->optind - 1][0],
pfound->name);
#endif
}
#if defined _LIBC && defined USE_IN_LIBIO
if (n >= 0)
{
_IO_flockfile (stderr);
int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
((_IO_FILE *) stderr)->_flags2
|= _IO_FLAGS2_NOTCANCEL;
__fxprintf (NULL, "%s", buf);
((_IO_FILE *) stderr)->_flags2 = old_flags2;
_IO_funlockfile (stderr);
free (buf);
}
#endif
}
d->__nextchar += strlen (d->__nextchar);
d->optopt = pfound->val;
return '?';
}
}
else if (pfound->has_arg == 1)
{
if (d->optind < argc)
d->optarg = argv[d->optind++];
else
{
if (print_errors)
{
#if defined _LIBC && defined USE_IN_LIBIO
char *buf;
if (__asprintf (&buf, _("\
%s: option `%s' requires an argument\n"),
argv[0], argv[d->optind - 1]) >= 0)
{
_IO_flockfile (stderr);
int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
((_IO_FILE *) stderr)->_flags2
|= _IO_FLAGS2_NOTCANCEL;
__fxprintf (NULL, "%s", buf);
((_IO_FILE *) stderr)->_flags2 = old_flags2;
_IO_funlockfile (stderr);
free (buf);
}
#else
fprintf (stderr,
_("%s: option `%s' requires an argument\n"),
argv[0], argv[d->optind - 1]);
#endif
}
d->__nextchar += strlen (d->__nextchar);
d->optopt = pfound->val;
return optstring[0] == ':' ? ':' : '?';
}
}
d->__nextchar += strlen (d->__nextchar);
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
/* Can't find it as a long option. If this is not getopt_long_only,
or the option starts with '--' or is not a valid short
option, then it's an error.
Otherwise interpret it as a short option. */
if (!long_only || argv[d->optind][1] == '-'
|| strchr (optstring, *d->__nextchar) == NULL)
{
if (print_errors)
{
#if defined _LIBC && defined USE_IN_LIBIO
char *buf;
int n;
#endif
if (argv[d->optind][1] == '-')
{
/* --option */
#if defined _LIBC && defined USE_IN_LIBIO
n = __asprintf (&buf, _("%s: unrecognized option `--%s'\n"),
argv[0], d->__nextchar);
#else
fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
argv[0], d->__nextchar);
#endif
}
else
{
/* +option or -option */
#if defined _LIBC && defined USE_IN_LIBIO
n = __asprintf (&buf, _("%s: unrecognized option `%c%s'\n"),
argv[0], argv[d->optind][0], d->__nextchar);
#else
fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
argv[0], argv[d->optind][0], d->__nextchar);
#endif
}
#if defined _LIBC && defined USE_IN_LIBIO
if (n >= 0)
{
_IO_flockfile (stderr);
int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
__fxprintf (NULL, "%s", buf);
((_IO_FILE *) stderr)->_flags2 = old_flags2;
_IO_funlockfile (stderr);
free (buf);
}
#endif
}
d->__nextchar = (char *) "";
d->optind++;
d->optopt = 0;
return '?';
}
}
/* Look at and handle the next short option-character. */
{
char c = *d->__nextchar++;
char *temp = strchr (optstring, c);
/* Increment `optind' when we start to process its last character. */
if (*d->__nextchar == '\0')
++d->optind;
if (temp == NULL || c == ':')
{
if (print_errors)
{
#if defined _LIBC && defined USE_IN_LIBIO
char *buf;
int n;
#endif
if (d->__posixly_correct)
{
/* 1003.2 specifies the format of this message. */
#if defined _LIBC && defined USE_IN_LIBIO
n = __asprintf (&buf, _("%s: illegal option -- %c\n"),
argv[0], c);
#else
fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c);
#endif
}
else
{
#if defined _LIBC && defined USE_IN_LIBIO
n = __asprintf (&buf, _("%s: invalid option -- %c\n"),
argv[0], c);
#else
fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c);
#endif
}
#if defined _LIBC && defined USE_IN_LIBIO
if (n >= 0)
{
_IO_flockfile (stderr);
int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
__fxprintf (NULL, "%s", buf);
((_IO_FILE *) stderr)->_flags2 = old_flags2;
_IO_funlockfile (stderr);
free (buf);
}
#endif
}
d->optopt = c;
return '?';
}
/* Convenience. Treat POSIX -W foo same as long option --foo */
if (temp[0] == 'W' && temp[1] == ';')
{
char *nameend;
const struct option *p;
const struct option *pfound = NULL;
int exact = 0;
int ambig = 0;
int indfound = 0;
int option_index;
/* This is an option that requires an argument. */
if (*d->__nextchar != '\0')
{
d->optarg = d->__nextchar;
/* If we end this ARGV-element by taking the rest as an arg,
we must advance to the next element now. */
d->optind++;
}
else if (d->optind == argc)
{
if (print_errors)
{
/* 1003.2 specifies the format of this message. */
#if defined _LIBC && defined USE_IN_LIBIO
char *buf;
if (__asprintf (&buf,
_("%s: option requires an argument -- %c\n"),
argv[0], c) >= 0)
{
_IO_flockfile (stderr);
int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
__fxprintf (NULL, "%s", buf);
((_IO_FILE *) stderr)->_flags2 = old_flags2;
_IO_funlockfile (stderr);
free (buf);
}
#else
fprintf (stderr, _("%s: option requires an argument -- %c\n"),
argv[0], c);
#endif
}
d->optopt = c;
if (optstring[0] == ':')
c = ':';
else
c = '?';
return c;
}
else
/* We already incremented `d->optind' once;
increment it again when taking next ARGV-elt as argument. */
d->optarg = argv[d->optind++];
/* optarg is now the argument, see if it's in the
table of longopts. */
for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != '=';
nameend++)
/* Do nothing. */ ;
/* Test all long options for either exact match
or abbreviated matches. */
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!strncmp (p->name, d->__nextchar, nameend - d->__nextchar))
{
if ((unsigned int) (nameend - d->__nextchar) == strlen (p->name))
{
/* Exact match found. */
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == NULL)
{
/* First nonexact match found. */
pfound = p;
indfound = option_index;
}
else
/* Second or later nonexact match found. */
ambig = 1;
}
if (ambig && !exact)
{
if (print_errors)
{
#if defined _LIBC && defined USE_IN_LIBIO
char *buf;
if (__asprintf (&buf, _("%s: option `-W %s' is ambiguous\n"),
argv[0], argv[d->optind]) >= 0)
{
_IO_flockfile (stderr);
int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
__fxprintf (NULL, "%s", buf);
((_IO_FILE *) stderr)->_flags2 = old_flags2;
_IO_funlockfile (stderr);
free (buf);
}
#else
fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
argv[0], argv[d->optind]);
#endif
}
d->__nextchar += strlen (d->__nextchar);
d->optind++;
return '?';
}
if (pfound != NULL)
{
option_index = indfound;
if (*nameend)
{
/* Don't test has_arg with >, because some C compilers don't
allow it to be used on enums. */
if (pfound->has_arg)
d->optarg = nameend + 1;
else
{
if (print_errors)
{
#if defined _LIBC && defined USE_IN_LIBIO
char *buf;
if (__asprintf (&buf, _("\
%s: option `-W %s' doesn't allow an argument\n"),
argv[0], pfound->name) >= 0)
{
_IO_flockfile (stderr);
int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
((_IO_FILE *) stderr)->_flags2
|= _IO_FLAGS2_NOTCANCEL;
__fxprintf (NULL, "%s", buf);
((_IO_FILE *) stderr)->_flags2 = old_flags2;
_IO_funlockfile (stderr);
free (buf);
}
#else
fprintf (stderr, _("\
%s: option `-W %s' doesn't allow an argument\n"),
argv[0], pfound->name);
#endif
}
d->__nextchar += strlen (d->__nextchar);
return '?';
}
}
else if (pfound->has_arg == 1)
{
if (d->optind < argc)
d->optarg = argv[d->optind++];
else
{
if (print_errors)
{
#if defined _LIBC && defined USE_IN_LIBIO
char *buf;
if (__asprintf (&buf, _("\
%s: option `%s' requires an argument\n"),
argv[0], argv[d->optind - 1]) >= 0)
{
_IO_flockfile (stderr);
int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
((_IO_FILE *) stderr)->_flags2
|= _IO_FLAGS2_NOTCANCEL;
__fxprintf (NULL, "%s", buf);
((_IO_FILE *) stderr)->_flags2 = old_flags2;
_IO_funlockfile (stderr);
free (buf);
}
#else
fprintf (stderr,
_("%s: option `%s' requires an argument\n"),
argv[0], argv[d->optind - 1]);
#endif
}
d->__nextchar += strlen (d->__nextchar);
return optstring[0] == ':' ? ':' : '?';
}
}
d->__nextchar += strlen (d->__nextchar);
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
d->__nextchar = NULL;
return 'W'; /* Let the application handle it. */
}
if (temp[1] == ':')
{
if (temp[2] == ':')
{
/* This is an option that accepts an argument optionally. */
if (*d->__nextchar != '\0')
{
d->optarg = d->__nextchar;
d->optind++;
}
else
d->optarg = NULL;
d->__nextchar = NULL;
}
else
{
/* This is an option that requires an argument. */
if (*d->__nextchar != '\0')
{
d->optarg = d->__nextchar;
/* If we end this ARGV-element by taking the rest as an arg,
we must advance to the next element now. */
d->optind++;
}
else if (d->optind == argc)
{
if (print_errors)
{
/* 1003.2 specifies the format of this message. */
#if defined _LIBC && defined USE_IN_LIBIO
char *buf;
if (__asprintf (&buf, _("\
%s: option requires an argument -- %c\n"),
argv[0], c) >= 0)
{
_IO_flockfile (stderr);
int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
__fxprintf (NULL, "%s", buf);
((_IO_FILE *) stderr)->_flags2 = old_flags2;
_IO_funlockfile (stderr);
free (buf);
}
#else
fprintf (stderr,
_("%s: option requires an argument -- %c\n"),
argv[0], c);
#endif
}
d->optopt = c;
if (optstring[0] == ':')
c = ':';
else
c = '?';
}
else
/* We already incremented `optind' once;
increment it again when taking next ARGV-elt as argument. */
d->optarg = argv[d->optind++];
d->__nextchar = NULL;
}
}
return c;
}
}
|
|||||
| ↓ | qcopy_acl | 95 | 214 | 483 | lib/copy-acl.c |
static int
qcopy_acl (const char *src_name, int source_desc, const char *dst_name,
int dest_desc, mode_t mode)
{
#if USE_ACL && HAVE_ACL_GET_FILE
/* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
/* Linux, FreeBSD, MacOS X, IRIX, Tru64 */
# if MODE_INSIDE_ACL
/* Linux, FreeBSD, IRIX, Tru64 */
acl_t acl;
int ret;
if (HAVE_ACL_GET_FD && source_desc != -1)
acl = acl_get_fd (source_desc);
else
acl = acl_get_file (src_name, ACL_TYPE_ACCESS);
if (acl == NULL)
{
if (ACL_NOT_WELL_SUPPORTED (errno))
return qset_acl (dst_name, dest_desc, mode);
else
return -2;
}
if (HAVE_ACL_SET_FD && dest_desc != -1)
ret = acl_set_fd (dest_desc, acl);
else
ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl);
if (ret != 0)
{
int saved_errno = errno;
if (ACL_NOT_WELL_SUPPORTED (errno) && !acl_access_nontrivial (acl))
{
acl_free (acl);
return chmod_or_fchmod (dst_name, dest_desc, mode);
}
else
{
acl_free (acl);
chmod_or_fchmod (dst_name, dest_desc, mode);
errno = saved_errno;
return -1;
}
}
else
acl_free (acl);
if (mode & (S_ISUID | S_ISGID | S_ISVTX))
{
/* We did not call chmod so far, and either the mode and the ACL are
separate or special bits are to be set which don't fit into ACLs. */
if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
return -1;
}
if (S_ISDIR (mode))
{
acl = acl_get_file (src_name, ACL_TYPE_DEFAULT);
if (acl == NULL)
return -2;
if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl))
{
int saved_errno = errno;
acl_free (acl);
errno = saved_errno;
return -1;
}
else
acl_free (acl);
}
return 0;
# else /* !MODE_INSIDE_ACL */
/* MacOS X */
# if !HAVE_ACL_TYPE_EXTENDED
# error Must have ACL_TYPE_EXTENDED
# endif
/* On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
and acl_get_file (name, ACL_TYPE_DEFAULT)
always return NULL / EINVAL. You have to use
acl_get_file (name, ACL_TYPE_EXTENDED)
or acl_get_fd (open (name, ...))
to retrieve an ACL.
On the other hand,
acl_set_file (name, ACL_TYPE_ACCESS, acl)
and acl_set_file (name, ACL_TYPE_DEFAULT, acl)
have the same effect as
acl_set_file (name, ACL_TYPE_EXTENDED, acl):
Each of these calls sets the file's ACL. */
acl_t acl;
int ret;
if (HAVE_ACL_GET_FD && source_desc != -1)
acl = acl_get_fd (source_desc);
else
acl = acl_get_file (src_name, ACL_TYPE_EXTENDED);
if (acl == NULL)
{
if (ACL_NOT_WELL_SUPPORTED (errno))
return qset_acl (dst_name, dest_desc, mode);
else
return -2;
}
if (HAVE_ACL_SET_FD && dest_desc != -1)
ret = acl_set_fd (dest_desc, acl);
else
ret = acl_set_file (dst_name, ACL_TYPE_EXTENDED, acl);
if (ret != 0)
{
int saved_errno = errno;
if (ACL_NOT_WELL_SUPPORTED (errno) && !acl_extended_nontrivial (acl))
{
acl_free (acl);
return chmod_or_fchmod (dst_name, dest_desc, mode);
}
else
{
acl_free (acl);
chmod_or_fchmod (dst_name, dest_desc, mode);
errno = saved_errno;
return -1;
}
}
else
acl_free (acl);
/* Since !MODE_INSIDE_ACL, we have to call chmod explicitly. */
return chmod_or_fchmod (dst_name, dest_desc, mode);
# endif
#elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
# if defined ACL_NO_TRIVIAL
/* Solaris 10 (newer version), which has additional API declared in
|
|||||
| ↓ | re_search_internal | 94 | 177 | 346 | lib/regexec.c |
/* Internal entry point. */
/* Searches for a compiled pattern PREG in the string STRING, whose
length is LENGTH. NMATCH, PMATCH, and EFLAGS have the same
meaning as with regexec. LAST_START is START + RANGE, where
START and RANGE have the same meaning as with re_search.
Return REG_NOERROR if we find a match, and REG_NOMATCH if not,
otherwise return the error code.
Note: We assume front end functions already check ranges.
(0 <= LAST_START && LAST_START <= LENGTH) */
static reg_errcode_t
internal_function
re_search_internal (const regex_t *preg,
const char *string, Idx length,
Idx start, Idx last_start, Idx stop,
size_t nmatch, regmatch_t pmatch[],
int eflags)
{
reg_errcode_t err;
const re_dfa_t *dfa = (const re_dfa_t *) preg->buffer;
Idx left_lim, right_lim;
int incr;
bool fl_longest_match;
int match_kind;
Idx match_first;
Idx match_last = REG_MISSING;
Idx extra_nmatch;
bool sb;
int ch;
#if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
re_match_context_t mctx = { .dfa = dfa };
#else
re_match_context_t mctx;
#endif
char *fastmap = ((preg->fastmap != NULL && preg->fastmap_accurate
&& start != last_start && !preg->can_be_null)
? preg->fastmap : NULL);
RE_TRANSLATE_TYPE t = preg->translate;
#if !(defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L))
memset (&mctx, '\0', sizeof (re_match_context_t));
mctx.dfa = dfa;
#endif
extra_nmatch = (nmatch > preg->re_nsub) ? nmatch - (preg->re_nsub + 1) : 0;
nmatch -= extra_nmatch;
/* Check if the DFA haven't been compiled. */
if (BE (preg->used == 0 || dfa->init_state == NULL
|| dfa->init_state_word == NULL || dfa->init_state_nl == NULL
|| dfa->init_state_begbuf == NULL, 0))
return REG_NOMATCH;
#ifdef DEBUG
/* We assume front-end functions already check them. */
assert (0 <= last_start && last_start <= length);
#endif
/* If initial states with non-begbuf contexts have no elements,
the regex must be anchored. If preg->newline_anchor is set,
we'll never use init_state_nl, so do not check it. */
if (dfa->init_state->nodes.nelem == 0
&& dfa->init_state_word->nodes.nelem == 0
&& (dfa->init_state_nl->nodes.nelem == 0
|| !preg->newline_anchor))
{
if (start != 0 && last_start != 0)
return REG_NOMATCH;
start = last_start = 0;
}
/* We must check the longest matching, if nmatch > 0. */
fl_longest_match = (nmatch != 0 || dfa->nbackref);
err = re_string_allocate (&mctx.input, string, length, dfa->nodes_len + 1,
preg->translate, (preg->syntax & RE_ICASE) != 0,
dfa);
if (BE (err != REG_NOERROR, 0))
goto free_return;
mctx.input.stop = stop;
mctx.input.raw_stop = stop;
mctx.input.newline_anchor = preg->newline_anchor;
err = match_ctx_init (&mctx, eflags, dfa->nbackref * 2);
if (BE (err != REG_NOERROR, 0))
goto free_return;
/* We will log all the DFA states through which the dfa pass,
if nmatch > 1, or this dfa has "multibyte node", which is a
back-reference or a node which can accept multibyte character or
multi character collating element. */
if (nmatch > 1 || dfa->has_mb_node)
{
/* Avoid overflow. */
if (BE (SIZE_MAX / sizeof (re_dfastate_t *) <= mctx.input.bufs_len, 0))
{
err = REG_ESPACE;
goto free_return;
}
mctx.state_log = re_malloc (re_dfastate_t *, mctx.input.bufs_len + 1);
if (BE (mctx.state_log == NULL, 0))
{
err = REG_ESPACE;
goto free_return;
}
}
else
mctx.state_log = NULL;
match_first = start;
mctx.input.tip_context = (eflags & REG_NOTBOL) ? CONTEXT_BEGBUF
: CONTEXT_NEWLINE | CONTEXT_BEGBUF;
/* Check incrementally whether of not the input string match. */
incr = (last_start < start) ? -1 : 1;
left_lim = (last_start < start) ? last_start : start;
right_lim = (last_start < start) ? start : last_start;
sb = dfa->mb_cur_max == 1;
match_kind =
(fastmap
? ((sb || !(preg->syntax & RE_ICASE || t) ? 4 : 0)
| (start <= last_start ? 2 : 0)
| (t != NULL ? 1 : 0))
: 8);
for (;; match_first += incr)
{
err = REG_NOMATCH;
if (match_first < left_lim || right_lim < match_first)
goto free_return;
/* Advance as rapidly as possible through the string, until we
find a plausible place to start matching. This may be done
with varying efficiency, so there are various possibilities:
only the most common of them are specialized, in order to
save on code size. We use a switch statement for speed. */
switch (match_kind)
{
case 8:
/* No fastmap. */
break;
case 7:
/* Fastmap with single-byte translation, match forward. */
while (BE (match_first < right_lim, 1)
&& !fastmap[t[(unsigned char) string[match_first]]])
++match_first;
goto forward_match_found_start_or_reached_end;
case 6:
/* Fastmap without translation, match forward. */
while (BE (match_first < right_lim, 1)
&& !fastmap[(unsigned char) string[match_first]])
++match_first;
forward_match_found_start_or_reached_end:
if (BE (match_first == right_lim, 0))
{
ch = match_first >= length
? 0 : (unsigned char) string[match_first];
if (!fastmap[t ? t[ch] : ch])
goto free_return;
}
break;
case 4:
case 5:
/* Fastmap without multi-byte translation, match backwards. */
while (match_first >= left_lim)
{
ch = match_first >= length
? 0 : (unsigned char) string[match_first];
if (fastmap[t ? t[ch] : ch])
break;
--match_first;
}
if (match_first < left_lim)
goto free_return;
break;
default:
/* In this case, we can't determine easily the current byte,
since it might be a component byte of a multibyte
character. Then we use the constructed buffer instead. */
for (;;)
{
/* If MATCH_FIRST is out of the valid range, reconstruct the
buffers. */
__re_size_t offset = match_first - mctx.input.raw_mbs_idx;
if (BE (offset >= (__re_size_t) mctx.input.valid_raw_len, 0))
{
err = re_string_reconstruct (&mctx.input, match_first,
eflags);
if (BE (err != REG_NOERROR, 0))
goto free_return;
offset = match_first - mctx.input.raw_mbs_idx;
}
/* If MATCH_FIRST is out of the buffer, leave it as '\0'.
Note that MATCH_FIRST must not be smaller than 0. */
ch = (match_first >= length
? 0 : re_string_byte_at (&mctx.input, offset));
if (fastmap[ch])
break;
match_first += incr;
if (match_first < left_lim || match_first > right_lim)
{
err = REG_NOMATCH;
goto free_return;
}
}
break;
}
/* Reconstruct the buffers so that the matcher can assume that
the matching starts from the beginning of the buffer. */
err = re_string_reconstruct (&mctx.input, match_first, eflags);
if (BE (err != REG_NOERROR, 0))
goto free_return;
#ifdef RE_ENABLE_I18N
/* Don't consider this char as a possible match start if it part,
yet isn't the head, of a multibyte character. */
if (!sb && !re_string_first_byte (&mctx.input, 0))
continue;
#endif
/* It seems to be appropriate one, then use the matcher. */
/* We assume that the matching starts from 0. */
mctx.state_log_top = mctx.nbkref_ents = mctx.max_mb_elem_len = 0;
match_last = check_matching (&mctx, fl_longest_match,
start <= last_start ? &match_first : NULL);
if (match_last != REG_MISSING)
{
if (BE (match_last == REG_ERROR, 0))
{
err = REG_ESPACE;
goto free_return;
}
else
{
mctx.match_last = match_last;
if ((!preg->no_sub && nmatch > 1) || dfa->nbackref)
{
re_dfastate_t *pstate = mctx.state_log[match_last];
mctx.last_node = check_halt_state_context (&mctx, pstate,
match_last);
}
if ((!preg->no_sub && nmatch > 1 && dfa->has_plural_match)
|| dfa->nbackref)
{
err = prune_impossible_nodes (&mctx);
if (err == REG_NOERROR)
break;
if (BE (err != REG_NOMATCH, 0))
goto free_return;
match_last = REG_MISSING;
}
else
break; /* We found a match. */
}
}
match_ctx_clean (&mctx);
}
#ifdef DEBUG
assert (match_last != REG_MISSING);
assert (err == REG_NOERROR);
#endif
/* Set pmatch[] if we need. */
if (nmatch > 0)
{
Idx reg_idx;
/* Initialize registers. */
for (reg_idx = 1; reg_idx < nmatch; ++reg_idx)
pmatch[reg_idx].rm_so = pmatch[reg_idx].rm_eo = -1;
/* Set the points where matching start/end. */
pmatch[0].rm_so = 0;
pmatch[0].rm_eo = mctx.match_last;
/* FIXME: This function should fail if mctx.match_last exceeds
the maximum possible regoff_t value. We need a new error
code REG_OVERFLOW. */
if (!preg->no_sub && nmatch > 1)
{
err = set_regs (preg, &mctx, nmatch, pmatch,
dfa->has_plural_match && dfa->nbackref > 0);
if (BE (err != REG_NOERROR, 0))
goto free_return;
}
/* At last, add the offset to the each registers, since we slided
the buffers so that we could assume that the matching starts
from 0. */
for (reg_idx = 0; reg_idx < nmatch; ++reg_idx)
if (pmatch[reg_idx].rm_so != -1)
{
#ifdef RE_ENABLE_I18N
if (BE (mctx.input.offsets_needed != 0, 0))
{
pmatch[reg_idx].rm_so =
(pmatch[reg_idx].rm_so == mctx.input.valid_len
? mctx.input.valid_raw_len
: mctx.input.offsets[pmatch[reg_idx].rm_so]);
pmatch[reg_idx].rm_eo =
(pmatch[reg_idx].rm_eo == mctx.input.valid_len
? mctx.input.valid_raw_len
: mctx.input.offsets[pmatch[reg_idx].rm_eo]);
}
#else
assert (mctx.input.offsets_needed == 0);
#endif
pmatch[reg_idx].rm_so += match_first;
pmatch[reg_idx].rm_eo += match_first;
}
for (reg_idx = 0; reg_idx < extra_nmatch; ++reg_idx)
{
pmatch[nmatch + reg_idx].rm_so = -1;
pmatch[nmatch + reg_idx].rm_eo = -1;
}
if (dfa->subexp_map)
for (reg_idx = 0; reg_idx + 1 < nmatch; reg_idx++)
if (dfa->subexp_map[reg_idx] != reg_idx)
{
pmatch[reg_idx + 1].rm_so
= pmatch[dfa->subexp_map[reg_idx] + 1].rm_so;
pmatch[reg_idx + 1].rm_eo
= pmatch[dfa->subexp_map[reg_idx] + 1].rm_eo;
}
}
free_return:
re_free (mctx.state_log);
if (dfa->nbackref)
match_ctx_free (&mctx);
re_string_destruct (&mctx.input);
return err;
}
|
|||||
| ↓ | execute | 87 | 90 | 225 | lib/execute.c |
int
execute (const char *progname,
const char *prog_path, char **prog_argv,
bool ignore_sigpipe,
bool null_stdin, bool null_stdout, bool null_stderr,
bool slave_process, bool exit_on_error,
int *termsigp)
{
#if defined _MSC_VER || defined __MINGW32__
/* Native Woe32 API. */
int orig_stdin;
int orig_stdout;
int orig_stderr;
int exitcode;
int nullinfd;
int nulloutfd;
/* FIXME: Need to free memory allocated by prepare_spawn. */
prog_argv = prepare_spawn (prog_argv);
/* Save standard file handles of parent process. */
if (null_stdin)
orig_stdin = dup_noinherit (STDIN_FILENO);
if (null_stdout)
orig_stdout = dup_noinherit (STDOUT_FILENO);
if (null_stderr)
orig_stderr = dup_noinherit (STDERR_FILENO);
exitcode = -1;
/* Create standard file handles of child process. */
nullinfd = -1;
nulloutfd = -1;
if ((!null_stdin
|| ((nullinfd = open ("NUL", O_RDONLY, 0)) >= 0
&& (nullinfd == STDIN_FILENO
|| (dup2 (nullinfd, STDIN_FILENO) >= 0
&& close (nullinfd) >= 0))))
&& (!(null_stdout || null_stderr)
|| ((nulloutfd = open ("NUL", O_RDWR, 0)) >= 0
&& (!null_stdout
|| nulloutfd == STDOUT_FILENO
|| dup2 (nulloutfd, STDOUT_FILENO) >= 0)
&& (!null_stderr
|| nulloutfd == STDERR_FILENO
|| dup2 (nulloutfd, STDERR_FILENO) >= 0)
&& ((null_stdout && nulloutfd == STDOUT_FILENO)
|| (null_stderr && nulloutfd == STDERR_FILENO)
|| close (nulloutfd) >= 0))))
/* Use spawnvpe and pass the environment explicitly. This is needed if
the program has modified the environment using putenv() or [un]setenv().
On Windows, programs have two environments, one in the "environment
block" of the process and managed through SetEnvironmentVariable(), and
one inside the process, in the location retrieved by the 'environ'
macro. When using spawnvp() without 'e', the child process inherits a
copy of the environment block - ignoring the effects of putenv() and
[un]setenv(). */
{
exitcode = spawnvpe (P_WAIT, prog_path, prog_argv, environ);
if (exitcode < 0 && errno == ENOEXEC)
{
/* prog is not an native executable. Try to execute it as a
shell script. Note that prepare_spawn() has already prepended
a hidden element "sh.exe" to prog_argv. */
--prog_argv;
exitcode = spawnvpe (P_WAIT, prog_argv[0], prog_argv, environ);
}
}
if (nulloutfd >= 0)
close (nulloutfd);
if (nullinfd >= 0)
close (nullinfd);
/* Restore standard file handles of parent process. */
if (null_stderr)
dup2 (orig_stderr, STDERR_FILENO), close (orig_stderr);
if (null_stdout)
dup2 (orig_stdout, STDOUT_FILENO), close (orig_stdout);
if (null_stdin)
dup2 (orig_stdin, STDIN_FILENO), close (orig_stdin);
if (termsigp != NULL)
*termsigp = 0;
if (exitcode == -1)
{
if (exit_on_error || !null_stderr)
error (exit_on_error ? EXIT_FAILURE : 0, errno,
_("%s subprocess failed"), progname);
return 127;
}
return exitcode;
#else
/* Unix API. */
/* Note about 127: Some errors during posix_spawnp() cause the function
posix_spawnp() to return an error code; some other errors cause the
subprocess to exit with return code 127. It is implementation
dependent which error is reported which way. We treat both cases as
equivalent. */
#if HAVE_POSIX_SPAWN
sigset_t blocked_signals;
posix_spawn_file_actions_t actions;
bool actions_allocated;
posix_spawnattr_t attrs;
bool attrs_allocated;
int err;
pid_t child;
#else
int child;
#endif
#if HAVE_POSIX_SPAWN
if (slave_process)
{
sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
block_fatal_signals ();
}
actions_allocated = false;
attrs_allocated = false;
if ((err = posix_spawn_file_actions_init (&actions)) != 0
|| (actions_allocated = true,
(null_stdin
&& (err = posix_spawn_file_actions_addopen (&actions,
STDIN_FILENO,
"/dev/null", O_RDONLY,
0))
!= 0)
|| (null_stdout
&& (err = posix_spawn_file_actions_addopen (&actions,
STDOUT_FILENO,
"/dev/null", O_RDWR,
0))
!= 0)
|| (null_stderr
&& (err = posix_spawn_file_actions_addopen (&actions,
STDERR_FILENO,
"/dev/null", O_RDWR,
0))
!= 0)
|| (slave_process
&& ((err = posix_spawnattr_init (&attrs)) != 0
|| (attrs_allocated = true,
(err = posix_spawnattr_setsigmask (&attrs,
&blocked_signals))
!= 0
|| (err = posix_spawnattr_setflags (&attrs,
POSIX_SPAWN_SETSIGMASK))
!= 0)))
|| (err = posix_spawnp (&child, prog_path, &actions,
attrs_allocated ? &attrs : NULL, prog_argv,
environ))
!= 0))
{
if (actions_allocated)
posix_spawn_file_actions_destroy (&actions);
if (attrs_allocated)
posix_spawnattr_destroy (&attrs);
if (slave_process)
unblock_fatal_signals ();
if (termsigp != NULL)
*termsigp = 0;
if (exit_on_error || !null_stderr)
error (exit_on_error ? EXIT_FAILURE : 0, err,
_("%s subprocess failed"), progname);
return 127;
}
posix_spawn_file_actions_destroy (&actions);
if (attrs_allocated)
posix_spawnattr_destroy (&attrs);
#else
if (slave_process)
block_fatal_signals ();
/* Use vfork() instead of fork() for efficiency. */
if ((child = vfork ()) == 0)
{
/* Child process code. */
int nullinfd;
int nulloutfd;
if ((!null_stdin
|| ((nullinfd = open ("/dev/null", O_RDONLY, 0)) >= 0
&& (nullinfd == STDIN_FILENO
|| (dup2 (nullinfd, STDIN_FILENO) >= 0
&& close (nullinfd) >= 0))))
&& (!(null_stdout || null_stderr)
|| ((nulloutfd = open ("/dev/null", O_RDWR, 0)) >= 0
&& (!null_stdout
|| nulloutfd == STDOUT_FILENO
|| dup2 (nulloutfd, STDOUT_FILENO) >= 0)
&& (!null_stderr
|| nulloutfd == STDERR_FILENO
|| dup2 (nulloutfd, STDERR_FILENO) >= 0)
&& ((null_stdout && nulloutfd == STDOUT_FILENO)
|| (null_stderr && nulloutfd == STDERR_FILENO)
|| close (nulloutfd) >= 0)))
&& (!slave_process || (unblock_fatal_signals (), true)))
execvp (prog_path, prog_argv);
_exit (127);
}
if (child == -1)
{
if (slave_process)
unblock_fatal_signals ();
if (termsigp != NULL)
*termsigp = 0;
if (exit_on_error || !null_stderr)
error (exit_on_error ? EXIT_FAILURE : 0, errno,
_("%s subprocess failed"), progname);
return 127;
}
#endif
if (slave_process)
{
register_slave_subprocess (child);
unblock_fatal_signals ();
}
return wait_subprocess (child, progname, ignore_sigpipe, null_stderr,
slave_process, exit_on_error, termsigp);
#endif
}
|
|||||
| ↓ | parse_bracket_exp | 88 | 263 | 555 | lib/regcomp.c |
static bin_tree_t *
parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
reg_syntax_t syntax, reg_errcode_t *err)
{
#ifdef _LIBC
const unsigned char *collseqmb;
const char *collseqwc;
uint32_t nrules;
int32_t table_size;
const int32_t *symb_table;
const unsigned char *extra;
/* Local function for parse_bracket_exp used in _LIBC environement.
Seek the collating symbol entry correspondings to NAME.
Return the index of the symbol in the SYMB_TABLE. */
auto inline int32_t
__attribute ((always_inline))
seek_collating_symbol_entry (name, name_len)
const unsigned char *name;
size_t name_len;
{
int32_t hash = elem_hash ((const char *) name, name_len);
int32_t elem = hash % table_size;
if (symb_table[2 * elem] != 0)
{
int32_t second = hash % (table_size - 2) + 1;
do
{
/* First compare the hashing value. */
if (symb_table[2 * elem] == hash
/* Compare the length of the name. */
&& name_len == extra[symb_table[2 * elem + 1]]
/* Compare the name. */
&& memcmp (name, &extra[symb_table[2 * elem + 1] + 1],
name_len) == 0)
{
/* Yep, this is the entry. */
break;
}
/* Next entry. */
elem += second;
}
while (symb_table[2 * elem] != 0);
}
return elem;
}
/* Local function for parse_bracket_exp used in _LIBC environement.
Look up the collation sequence value of BR_ELEM.
Return the value if succeeded, UINT_MAX otherwise. */
auto inline unsigned int
__attribute ((always_inline))
lookup_collation_sequence_value (br_elem)
bracket_elem_t *br_elem;
{
if (br_elem->type == SB_CHAR)
{
/*
if (MB_CUR_MAX == 1)
*/
if (nrules == 0)
return collseqmb[br_elem->opr.ch];
else
{
wint_t wc = __btowc (br_elem->opr.ch);
return __collseq_table_lookup (collseqwc, wc);
}
}
else if (br_elem->type == MB_CHAR)
{
return __collseq_table_lookup (collseqwc, br_elem->opr.wch);
}
else if (br_elem->type == COLL_SYM)
{
size_t sym_name_len = strlen ((char *) br_elem->opr.name);
if (nrules != 0)
{
int32_t elem, idx;
elem = seek_collating_symbol_entry (br_elem->opr.name,
sym_name_len);
if (symb_table[2 * elem] != 0)
{
/* We found the entry. */
idx = symb_table[2 * elem + 1];
/* Skip the name of collating element name. */
idx += 1 + extra[idx];
/* Skip the byte sequence of the collating element. */
idx += 1 + extra[idx];
/* Adjust for the alignment. */
idx = (idx + 3) & ~3;
/* Skip the multibyte collation sequence value. */
idx += sizeof (unsigned int);
/* Skip the wide char sequence of the collating element. */
idx += sizeof (unsigned int) *
(1 + *(unsigned int *) (extra + idx));
/* Return the collation sequence value. */
return *(unsigned int *) (extra + idx);
}
else if (symb_table[2 * elem] == 0 && sym_name_len == 1)
{
/* No valid character. Match it as a single byte
character. */
return collseqmb[br_elem->opr.name[0]];
}
}
else if (sym_name_len == 1)
return collseqmb[br_elem->opr.name[0]];
}
return UINT_MAX;
}
/* Local function for parse_bracket_exp used in _LIBC environement.
Build the range expression which starts from START_ELEM, and ends
at END_ELEM. The result are written to MBCSET and SBCSET.
RANGE_ALLOC is the allocated size of mbcset->range_starts, and
mbcset->range_ends, is a pointer argument sinse we may
update it. */
auto inline reg_errcode_t
__attribute ((always_inline))
build_range_exp (sbcset, mbcset, range_alloc, start_elem, end_elem)
re_charset_t *mbcset;
Idx *range_alloc;
bitset_t sbcset;
bracket_elem_t *start_elem, *end_elem;
{
unsigned int ch;
uint32_t start_collseq;
uint32_t end_collseq;
/* Equivalence Classes and Character Classes can't be a range
start/end. */
if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS
|| end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS,
0))
return REG_ERANGE;
start_collseq = lookup_collation_sequence_value (start_elem);
end_collseq = lookup_collation_sequence_value (end_elem);
/* Check start/end collation sequence values. */
if (BE (start_collseq == UINT_MAX || end_collseq == UINT_MAX, 0))
return REG_ECOLLATE;
if (BE ((syntax & RE_NO_EMPTY_RANGES) && start_collseq > end_collseq, 0))
return REG_ERANGE;
/* Got valid collation sequence values, add them as a new entry.
However, if we have no collation elements, and the character set
is single byte, the single byte character set that we
build below suffices. */
if (nrules > 0 || dfa->mb_cur_max > 1)
{
/* Check the space of the arrays. */
if (BE (*range_alloc == mbcset->nranges, 0))
{
/* There is not enough space, need realloc. */
uint32_t *new_array_start;
uint32_t *new_array_end;
Idx new_nranges;
/* +1 in case of mbcset->nranges is 0. */
new_nranges = 2 * mbcset->nranges + 1;
new_array_start = re_realloc (mbcset->range_starts, uint32_t,
new_nranges);
new_array_end = re_realloc (mbcset->range_ends, uint32_t,
new_nranges);
if (BE (new_array_start == NULL || new_array_end == NULL, 0))
return REG_ESPACE;
mbcset->range_starts = new_array_start;
mbcset->range_ends = new_array_end;
*range_alloc = new_nranges;
}
mbcset->range_starts[mbcset->nranges] = start_collseq;
mbcset->range_ends[mbcset->nranges++] = end_collseq;
}
/* Build the table for single byte characters. */
for (ch = 0; ch < SBC_MAX; ch++)
{
uint32_t ch_collseq;
/*
if (MB_CUR_MAX == 1)
*/
if (nrules == 0)
ch_collseq = collseqmb[ch];
else
ch_collseq = __collseq_table_lookup (collseqwc, __btowc (ch));
if (start_collseq <= ch_collseq && ch_collseq <= end_collseq)
bitset_set (sbcset, ch);
}
return REG_NOERROR;
}
/* Local function for parse_bracket_exp used in _LIBC environement.
Build the collating element which is represented by NAME.
The result are written to MBCSET and SBCSET.
COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a
pointer argument sinse we may update it. */
auto inline reg_errcode_t
__attribute ((always_inline))
build_collating_symbol (sbcset, mbcset, coll_sym_alloc, name)
re_charset_t *mbcset;
Idx *coll_sym_alloc;
bitset_t sbcset;
const unsigned char *name;
{
int32_t elem, idx;
size_t name_len = strlen ((const char *) name);
if (nrules != 0)
{
elem = seek_collating_symbol_entry (name, name_len);
if (symb_table[2 * elem] != 0)
{
/* We found the entry. */
idx = symb_table[2 * elem + 1];
/* Skip the name of collating element name. */
idx += 1 + extra[idx];
}
else if (symb_table[2 * elem] == 0 && name_len == 1)
{
/* No valid character, treat it as a normal
character. */
bitset_set (sbcset, name[0]);
return REG_NOERROR;
}
else
return REG_ECOLLATE;
/* Got valid collation sequence, add it as a new entry. */
/* Check the space of the arrays. */
if (BE (*coll_sym_alloc == mbcset->ncoll_syms, 0))
{
/* Not enough, realloc it. */
/* +1 in case of mbcset->ncoll_syms is 0. */
Idx new_coll_sym_alloc = 2 * mbcset->ncoll_syms + 1;
/* Use realloc since mbcset->coll_syms is NULL
if *alloc == 0. */
int32_t *new_coll_syms = re_realloc (mbcset->coll_syms, int32_t,
new_coll_sym_alloc);
if (BE (new_coll_syms == NULL, 0))
return REG_ESPACE;
mbcset->coll_syms = new_coll_syms;
*coll_sym_alloc = new_coll_sym_alloc;
}
mbcset->coll_syms[mbcset->ncoll_syms++] = idx;
return REG_NOERROR;
}
else
{
if (BE (name_len != 1, 0))
return REG_ECOLLATE;
else
{
bitset_set (sbcset, name[0]);
return REG_NOERROR;
}
}
}
#endif
re_token_t br_token;
re_bitset_ptr_t sbcset;
#ifdef RE_ENABLE_I18N
re_charset_t *mbcset;
Idx coll_sym_alloc = 0, range_alloc = 0, mbchar_alloc = 0;
Idx equiv_class_alloc = 0, char_class_alloc = 0;
#endif /* not RE_ENABLE_I18N */
bool non_match = false;
bin_tree_t *work_tree;
int token_len;
bool first_round = true;
#ifdef _LIBC
collseqmb = (const unsigned char *)
_NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB);
nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
if (nrules)
{
/*
if (MB_CUR_MAX > 1)
*/
collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC);
table_size = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_SYMB_HASH_SIZEMB);
symb_table = (const int32_t *) _NL_CURRENT (LC_COLLATE,
_NL_COLLATE_SYMB_TABLEMB);
extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
_NL_COLLATE_SYMB_EXTRAMB);
}
#endif
sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1);
#ifdef RE_ENABLE_I18N
mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1);
#endif /* RE_ENABLE_I18N */
#ifdef RE_ENABLE_I18N
if (BE (sbcset == NULL || mbcset == NULL, 0))
#else
if (BE (sbcset == NULL, 0))
#endif /* RE_ENABLE_I18N */
{
*err = REG_ESPACE;
return NULL;
}
token_len = peek_token_bracket (token, regexp, syntax);
if (BE (token->type == END_OF_RE, 0))
{
*err = REG_BADPAT;
goto parse_bracket_exp_free_return;
}
if (token->type == OP_NON_MATCH_LIST)
{
#ifdef RE_ENABLE_I18N
mbcset->non_match = 1;
#endif /* not RE_ENABLE_I18N */
non_match = true;
if (syntax & RE_HAT_LISTS_NOT_NEWLINE)
bitset_set (sbcset, '\n');
re_string_skip_bytes (regexp, token_len); /* Skip a token. */
token_len = peek_token_bracket (token, regexp, syntax);
if (BE (token->type == END_OF_RE, 0))
{
*err = REG_BADPAT;
goto parse_bracket_exp_free_return;
}
}
/* We treat the first ']' as a normal character. */
if (token->type == OP_CLOSE_BRACKET)
token->type = CHARACTER;
while (1)
{
bracket_elem_t start_elem, end_elem;
unsigned char start_name_buf[BRACKET_NAME_BUF_SIZE];
unsigned char end_name_buf[BRACKET_NAME_BUF_SIZE];
reg_errcode_t ret;
int token_len2 = 0;
bool is_range_exp = false;
re_token_t token2;
start_elem.opr.name = start_name_buf;
ret = parse_bracket_element (&start_elem, regexp, token, token_len, dfa,
syntax, first_round);
if (BE (ret != REG_NOERROR, 0))
{
*err = ret;
goto parse_bracket_exp_free_return;
}
first_round = false;
/* Get information about the next token. We need it in any case. */
token_len = peek_token_bracket (token, regexp, syntax);
/* Do not check for ranges if we know they are not allowed. */
if (start_elem.type != CHAR_CLASS && start_elem.type != EQUIV_CLASS)
{
if (BE (token->type == END_OF_RE, 0))
{
*err = REG_EBRACK;
goto parse_bracket_exp_free_return;
}
if (token->type == OP_CHARSET_RANGE)
{
re_string_skip_bytes (regexp, token_len); /* Skip '-'. */
token_len2 = peek_token_bracket (&token2, regexp, syntax);
if (BE (token2.type == END_OF_RE, 0))
{
*err = REG_EBRACK;
goto parse_bracket_exp_free_return;
}
if (token2.type == OP_CLOSE_BRACKET)
{
/* We treat the last '-' as a normal character. */
re_string_skip_bytes (regexp, -token_len);
token->type = CHARACTER;
}
else
is_range_exp = true;
}
}
if (is_range_exp == true)
{
end_elem.opr.name = end_name_buf;
ret = parse_bracket_element (&end_elem, regexp, &token2, token_len2,
dfa, syntax, true);
if (BE (ret != REG_NOERROR, 0))
{
*err = ret;
goto parse_bracket_exp_free_return;
}
token_len = peek_token_bracket (token, regexp, syntax);
#ifdef _LIBC
*err = build_range_exp (sbcset, mbcset, &range_alloc,
&start_elem, &end_elem);
#else
# ifdef RE_ENABLE_I18N
*err = build_range_exp (sbcset,
dfa->mb_cur_max > 1 ? mbcset : NULL,
&range_alloc, &start_elem, &end_elem);
# else
*err = build_range_exp (sbcset, &start_elem, &end_elem);
# endif
#endif /* RE_ENABLE_I18N */
if (BE (*err != REG_NOERROR, 0))
goto parse_bracket_exp_free_return;
}
else
{
switch (start_elem.type)
{
case SB_CHAR:
bitset_set (sbcset, start_elem.opr.ch);
break;
#ifdef RE_ENABLE_I18N
case MB_CHAR:
/* Check whether the array has enough space. */
if (BE (mbchar_alloc == mbcset->nmbchars, 0))
{
wchar_t *new_mbchars;
/* Not enough, realloc it. */
/* +1 in case of mbcset->nmbchars is 0. */
mbchar_alloc = 2 * mbcset->nmbchars + 1;
/* Use realloc since array is NULL if *alloc == 0. */
new_mbchars = re_realloc (mbcset->mbchars, wchar_t,
mbchar_alloc);
if (BE (new_mbchars == NULL, 0))
goto parse_bracket_exp_espace;
mbcset->mbchars = new_mbchars;
}
mbcset->mbchars[mbcset->nmbchars++] = start_elem.opr.wch;
break;
#endif /* RE_ENABLE_I18N */
case EQUIV_CLASS:
*err = build_equiv_class (sbcset,
#ifdef RE_ENABLE_I18N
mbcset, &equiv_class_alloc,
#endif /* RE_ENABLE_I18N */
start_elem.opr.name);
if (BE (*err != REG_NOERROR, 0))
goto parse_bracket_exp_free_return;
break;
case COLL_SYM:
*err = build_collating_symbol (sbcset,
#ifdef RE_ENABLE_I18N
mbcset, &coll_sym_alloc,
#endif /* RE_ENABLE_I18N */
start_elem.opr.name);
if (BE (*err != REG_NOERROR, 0))
goto parse_bracket_exp_free_return;
break;
case CHAR_CLASS:
*err = build_charclass (regexp->trans, sbcset,
#ifdef RE_ENABLE_I18N
mbcset, &char_class_alloc,
#endif /* RE_ENABLE_I18N */
start_elem.opr.name, syntax);
if (BE (*err != REG_NOERROR, 0))
goto parse_bracket_exp_free_return;
break;
default:
assert (0);
break;
}
}
if (BE (token->type == END_OF_RE, 0))
{
*err = REG_EBRACK;
goto parse_bracket_exp_free_return;
}
if (token->type == OP_CLOSE_BRACKET)
break;
}
re_string_skip_bytes (regexp, token_len); /* Skip a token. */
/* If it is non-matching list. */
if (non_match)
bitset_not (sbcset);
#ifdef RE_ENABLE_I18N
/* Ensure only single byte characters are set. */
if (dfa->mb_cur_max > 1)
bitset_mask (sbcset, dfa->sb_char);
if (mbcset->nmbchars || mbcset->ncoll_syms || mbcset->nequiv_classes
|| mbcset->nranges || (dfa->mb_cur_max > 1 && (mbcset->nchar_classes
|| mbcset->non_match)))
{
bin_tree_t *mbc_tree;
int sbc_idx;
/* Build a tree for complex bracket. */
dfa->has_mb_node = 1;
br_token.type = COMPLEX_BRACKET;
br_token.opr.mbcset = mbcset;
mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token);
if (BE (mbc_tree == NULL, 0))
goto parse_bracket_exp_espace;
for (sbc_idx = 0; sbc_idx < BITSET_WORDS; ++sbc_idx)
if (sbcset[sbc_idx])
break;
/* If there are no bits set in sbcset, there is no point
of having both SIMPLE_BRACKET and COMPLEX_BRACKET. */
if (sbc_idx < BITSET_WORDS)
{
/* Build a tree for simple bracket. */
br_token.type = SIMPLE_BRACKET;
br_token.opr.sbcset = sbcset;
work_tree = create_token_tree (dfa, NULL, NULL, &br_token);
if (BE (work_tree == NULL, 0))
goto parse_bracket_exp_espace;
/* Then join them by ALT node. */
work_tree = create_tree (dfa, work_tree, mbc_tree, OP_ALT);
if (BE (work_tree == NULL, 0))
goto parse_bracket_exp_espace;
}
else
{
re_free (sbcset);
work_tree = mbc_tree;
}
}
else
#endif /* not RE_ENABLE_I18N */
{
#ifdef RE_ENABLE_I18N
free_charset (mbcset);
#endif
/* Build a tree for simple bracket. */
br_token.type = SIMPLE_BRACKET;
br_token.opr.sbcset = sbcset;
work_tree = create_token_tree (dfa, NULL, NULL, &br_token);
if (BE (work_tree == NULL, 0))
goto parse_bracket_exp_espace;
}
return work_tree;
parse_bracket_exp_espace:
*err = REG_ESPACE;
parse_bracket_exp_free_return:
re_free (sbcset);
#ifdef RE_ENABLE_I18N
free_charset (mbcset);
#endif /* RE_ENABLE_I18N */
return NULL;
}
|
|||||
| main | 1 | 2 | 6 | lib/physmem.c | |
| ↓ | qset_acl | 81 | 238 | 427 | lib/set-mode-acl.c |
int
qset_acl (char const *name, int desc, mode_t mode)
{
#if USE_ACL
# if HAVE_ACL_GET_FILE
/* POSIX 1003.1e draft 17 (abandoned) specific version. */
/* Linux, FreeBSD, MacOS X, IRIX, Tru64 */
# if MODE_INSIDE_ACL
/* Linux, FreeBSD, IRIX, Tru64 */
/* We must also have acl_from_text and acl_delete_def_file.
(acl_delete_def_file could be emulated with acl_init followed
by acl_set_file, but acl_set_file with an empty acl is
unspecified.) */
# ifndef HAVE_ACL_FROM_TEXT
# error Must have acl_from_text (see POSIX 1003.1e draft 17).
# endif
# ifndef HAVE_ACL_DELETE_DEF_FILE
# error Must have acl_delete_def_file (see POSIX 1003.1e draft 17).
# endif
acl_t acl;
int ret;
if (HAVE_ACL_FROM_MODE) /* Linux */
{
acl = acl_from_mode (mode);
if (!acl)
return -1;
}
else /* FreeBSD, IRIX, Tru64 */
{
/* If we were to create the ACL using the functions acl_init(),
acl_create_entry(), acl_set_tag_type(), acl_set_qualifier(),
acl_get_permset(), acl_clear_perm[s](), acl_add_perm(), we
would need to create a qualifier. I don't know how to do this.
So create it using acl_from_text(). */
# if HAVE_ACL_FREE_TEXT /* Tru64 */
char acl_text[] = "u::---,g::---,o::---,";
# else /* FreeBSD, IRIX */
char acl_text[] = "u::---,g::---,o::---";
# endif
if (mode & S_IRUSR) acl_text[ 3] = 'r';
if (mode & S_IWUSR) acl_text[ 4] = 'w';
if (mode & S_IXUSR) acl_text[ 5] = 'x';
if (mode & S_IRGRP) acl_text[10] = 'r';
if (mode & S_IWGRP) acl_text[11] = 'w';
if (mode & S_IXGRP) acl_text[12] = 'x';
if (mode & S_IROTH) acl_text[17] = 'r';
if (mode & S_IWOTH) acl_text[18] = 'w';
if (mode & S_IXOTH) acl_text[19] = 'x';
acl = acl_from_text (acl_text);
if (!acl)
return -1;
}
if (HAVE_ACL_SET_FD && desc != -1)
ret = acl_set_fd (desc, acl);
else
ret = acl_set_file (name, ACL_TYPE_ACCESS, acl);
if (ret != 0)
{
int saved_errno = errno;
acl_free (acl);
if (ACL_NOT_WELL_SUPPORTED (errno))
return chmod_or_fchmod (name, desc, mode);
else
{
errno = saved_errno;
return -1;
}
}
else
acl_free (acl);
if (S_ISDIR (mode) && acl_delete_def_file (name))
return -1;
if (mode & (S_ISUID | S_ISGID | S_ISVTX))
{
/* We did not call chmod so far, so the special bits have not yet
been set. */
return chmod_or_fchmod (name, desc, mode);
}
return 0;
# else /* !MODE_INSIDE_ACL */
/* MacOS X */
# if !HAVE_ACL_TYPE_EXTENDED
# error Must have ACL_TYPE_EXTENDED
# endif
/* On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
and acl_get_file (name, ACL_TYPE_DEFAULT)
always return NULL / EINVAL. You have to use
acl_get_file (name, ACL_TYPE_EXTENDED)
or acl_get_fd (open (name, ...))
to retrieve an ACL.
On the other hand,
acl_set_file (name, ACL_TYPE_ACCESS, acl)
and acl_set_file (name, ACL_TYPE_DEFAULT, acl)
have the same effect as
acl_set_file (name, ACL_TYPE_EXTENDED, acl):
Each of these calls sets the file's ACL. */
acl_t acl;
int ret;
/* Remove the ACL if the file has ACLs. */
if (HAVE_ACL_GET_FD && desc != -1)
acl = acl_get_fd (desc);
else
acl = acl_get_file (name, ACL_TYPE_EXTENDED);
if (acl)
{
acl_free (acl);
acl = acl_init (0);
if (acl)
{
if (HAVE_ACL_SET_FD && desc != -1)
ret = acl_set_fd (desc, acl);
else
ret = acl_set_file (name, ACL_TYPE_EXTENDED, acl);
if (ret != 0)
{
int saved_errno = errno;
acl_free (acl);
if (ACL_NOT_WELL_SUPPORTED (saved_errno))
return chmod_or_fchmod (name, desc, mode);
else
{
errno = saved_errno;
return -1;
}
}
acl_free (acl);
}
}
/* Since !MODE_INSIDE_ACL, we have to call chmod explicitly. */
return chmod_or_fchmod (name, desc, mode);
# endif
# elif HAVE_ACL && defined GETACLCNT /* Solaris, Cygwin, not HP-UX */
# if defined ACL_NO_TRIVIAL
/* Solaris 10 (newer version), which has additional API declared in
|
|||||
| ↓ | quotearg_buffer_restyled | 195 | 186 | 384 | lib/quotearg.c |
static size_t
quotearg_buffer_restyled (char *buffer, size_t buffersize,
char const *arg, size_t argsize,
enum quoting_style quoting_style, int flags,
unsigned int const *quote_these_too)
{
size_t i;
size_t len = 0;
char const *quote_string = 0;
size_t quote_string_len = 0;
bool backslash_escapes = false;
bool unibyte_locale = MB_CUR_MAX == 1;
bool elide_outer_quotes = (flags & QA_ELIDE_OUTER_QUOTES) != 0;
#define STORE(c) \
do \
{ \
if (len < buffersize) \
buffer[len] = (c); \
len++; \
} \
while (0)
switch (quoting_style)
{
case c_maybe_quoting_style:
quoting_style = c_quoting_style;
elide_outer_quotes = true;
/* Fall through. */
case c_quoting_style:
if (!elide_outer_quotes)
STORE ('"');
backslash_escapes = true;
quote_string = "\"";
quote_string_len = 1;
break;
case escape_quoting_style:
backslash_escapes = true;
elide_outer_quotes = false;
break;
case locale_quoting_style:
case clocale_quoting_style:
{
/* TRANSLATORS:
Get translations for open and closing quotation marks.
The message catalog should translate "`" to a left
quotation mark suitable for the locale, and similarly for
"'". If the catalog has no translation,
locale_quoting_style quotes `like this', and
clocale_quoting_style quotes "like this".
For example, an American English Unicode locale should
translate "`" to U+201C (LEFT DOUBLE QUOTATION MARK), and
should translate "'" to U+201D (RIGHT DOUBLE QUOTATION
MARK). A British English Unicode locale should instead
translate these to U+2018 (LEFT SINGLE QUOTATION MARK) and
U+2019 (RIGHT SINGLE QUOTATION MARK), respectively.
If you don't know what to put here, please see
|
|||||
| ↓ | getloadavg | 69 | 234 | 508 | lib/getloadavg.c |
/* Put the 1 minute, 5 minute and 15 minute load averages
into the first NELEM elements of LOADAVG.
Return the number written (never more than 3, but may be less than NELEM),
or -1 if an error occurred. */
int
getloadavg (double loadavg[], int nelem)
{
int elem = 0; /* Return value. */
# ifdef NO_GET_LOAD_AVG
# define LDAV_DONE
/* Set errno to zero to indicate that there was no particular error;
this function just can't work at all on this system. */
errno = 0;
elem = -1;
# endif
# if !defined (LDAV_DONE) && defined (HAVE_LIBKSTAT)
/* Use libkstat because we don't have to be root. */
# define LDAV_DONE
kstat_ctl_t *kc;
kstat_t *ksp;
kstat_named_t *kn;
kc = kstat_open ();
if (kc == 0)
return -1;
ksp = kstat_lookup (kc, "unix", 0, "system_misc");
if (ksp == 0)
return -1;
if (kstat_read (kc, ksp, 0) == -1)
return -1;
kn = kstat_data_lookup (ksp, "avenrun_1min");
if (kn == 0)
{
/* Return -1 if no load average information is available. */
nelem = 0;
elem = -1;
}
if (nelem >= 1)
loadavg[elem++] = (double) kn->value.ul / FSCALE;
if (nelem >= 2)
{
kn = kstat_data_lookup (ksp, "avenrun_5min");
if (kn != 0)
{
loadavg[elem++] = (double) kn->value.ul / FSCALE;
if (nelem >= 3)
{
kn = kstat_data_lookup (ksp, "avenrun_15min");
if (kn != 0)
loadavg[elem++] = (double) kn->value.ul / FSCALE;
}
}
}
kstat_close (kc);
# endif /* HAVE_LIBKSTAT */
# if !defined (LDAV_DONE) && defined (hpux) && defined (HAVE_PSTAT_GETDYNAMIC)
/* Use pstat_getdynamic() because we don't have to be root. */
# define LDAV_DONE
# undef LOAD_AVE_TYPE
struct pst_dynamic dyn_info;
if (pstat_getdynamic (&dyn_info, sizeof (dyn_info), 0, 0) < 0)
return -1;
if (nelem > 0)
loadavg[elem++] = dyn_info.psd_avg_1_min;
if (nelem > 1)
loadavg[elem++] = dyn_info.psd_avg_5_min;
if (nelem > 2)
loadavg[elem++] = dyn_info.psd_avg_15_min;
# endif /* hpux && HAVE_PSTAT_GETDYNAMIC */
# if ! defined LDAV_DONE && defined HAVE_LIBPERFSTAT
# define LDAV_DONE
# undef LOAD_AVE_TYPE
/* Use perfstat_cpu_total because we don't have to be root. */
{
perfstat_cpu_total_t cpu_stats;
int result = perfstat_cpu_total (NULL, &cpu_stats, sizeof cpu_stats, 1);
if (result == -1)
return result;
loadavg[0] = cpu_stats.loadavg[0] / (double)(1 << SBITS);
loadavg[1] = cpu_stats.loadavg[1] / (double)(1 << SBITS);
loadavg[2] = cpu_stats.loadavg[2] / (double)(1 << SBITS);
elem = 3;
}
# endif
# if !defined (LDAV_DONE) && (defined (__linux__) || defined (__CYGWIN__))
# define LDAV_DONE
# undef LOAD_AVE_TYPE
# ifndef LINUX_LDAV_FILE
# define LINUX_LDAV_FILE "/proc/loadavg"
# endif
char ldavgbuf[3 * (INT_STRLEN_BOUND (int) + sizeof ".00 ")];
char const *ptr = ldavgbuf;
int fd, count;
fd = open (LINUX_LDAV_FILE, O_RDONLY);
if (fd == -1)
return -1;
count = read (fd, ldavgbuf, sizeof ldavgbuf - 1);
(void) close (fd);
if (count <= 0)
return -1;
ldavgbuf[count] = '\0';
for (elem = 0; elem < nelem; elem++)
{
char *endptr;
double d = c_strtod (ptr, &endptr);
if (ptr == endptr)
{
if (elem == 0)
return -1;
break;
}
loadavg[elem] = d;
ptr = endptr;
}
return elem;
# endif /* __linux__ || __CYGWIN__ */
# if !defined (LDAV_DONE) && defined (__NetBSD__)
# define LDAV_DONE
# undef LOAD_AVE_TYPE
# ifndef NETBSD_LDAV_FILE
# define NETBSD_LDAV_FILE "/kern/loadavg"
# endif
unsigned long int load_ave[3], scale;
int count;
FILE *fp;
fp = fopen (NETBSD_LDAV_FILE, "r");
if (fp == NULL)
return -1;
count = fscanf (fp, "%lu %lu %lu %lu\n",
&load_ave[0], &load_ave[1], &load_ave[2],
&scale);
(void) fclose (fp);
if (count != 4)
return -1;
for (elem = 0; elem < nelem; elem++)
loadavg[elem] = (double) load_ave[elem] / (double) scale;
return elem;
# endif /* __NetBSD__ */
# if !defined (LDAV_DONE) && defined (NeXT)
# define LDAV_DONE
/* The NeXT code was adapted from iscreen 3.2. */
host_t host;
struct processor_set_basic_info info;
unsigned int info_count;
/* We only know how to get the 1-minute average for this system,
so even if the caller asks for more than 1, we only return 1. */
if (!getloadavg_initialized)
{
if (processor_set_default (host_self (), &default_set) == KERN_SUCCESS)
getloadavg_initialized = true;
}
if (getloadavg_initialized)
{
info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
if (processor_set_info (default_set, PROCESSOR_SET_BASIC_INFO, &host,
(processor_set_info_t) &info, &info_count)
!= KERN_SUCCESS)
getloadavg_initialized = false;
else
{
if (nelem > 0)
loadavg[elem++] = (double) info.load_average / LOAD_SCALE;
}
}
if (!getloadavg_initialized)
return -1;
# endif /* NeXT */
# if !defined (LDAV_DONE) && defined (UMAX)
# define LDAV_DONE
/* UMAX 4.2, which runs on the Encore Multimax multiprocessor, does not
have a /dev/kmem. Information about the workings of the running kernel
can be gathered with inq_stats system calls.
We only know how to get the 1-minute average for this system. */
struct proc_summary proc_sum_data;
struct stat_descr proc_info;
double load;
register unsigned int i, j;
if (cpus == 0)
{
register unsigned int c, i;
struct cpu_config conf;
struct stat_descr desc;
desc.sd_next = 0;
desc.sd_subsys = SUBSYS_CPU;
desc.sd_type = CPUTYPE_CONFIG;
desc.sd_addr = (char *) &conf;
desc.sd_size = sizeof conf;
if (inq_stats (1, &desc))
return -1;
c = 0;
for (i = 0; i < conf.config_maxclass; ++i)
{
struct class_stats stats;
bzero ((char *) &stats, sizeof stats);
desc.sd_type = CPUTYPE_CLASS;
desc.sd_objid = i;
desc.sd_addr = (char *) &stats;
desc.sd_size = sizeof stats;
if (inq_stats (1, &desc))
return -1;
c += stats.class_numcpus;
}
cpus = c;
samples = cpus < 2 ? 3 : (2 * cpus / 3);
}
proc_info.sd_next = 0;
proc_info.sd_subsys = SUBSYS_PROC;
proc_info.sd_type = PROCTYPE_SUMMARY;
proc_info.sd_addr = (char *) &proc_sum_data;
proc_info.sd_size = sizeof (struct proc_summary);
proc_info.sd_sizeused = 0;
if (inq_stats (1, &proc_info) != 0)
return -1;
load = proc_sum_data.ps_nrunnable;
j = 0;
for (i = samples - 1; i > 0; --i)
{
load += proc_sum_data.ps_nrun[j];
if (j++ == PS_NRUNSIZE)
j = 0;
}
if (nelem > 0)
loadavg[elem++] = load / samples / cpus;
# endif /* UMAX */
# if !defined (LDAV_DONE) && defined (DGUX)
# define LDAV_DONE
/* This call can return -1 for an error, but with good args
it's not supposed to fail. The first argument is for no
apparent reason of type `long int *'. */
dg_sys_info ((long int *) &load_info,
DG_SYS_INFO_LOAD_INFO_TYPE,
DG_SYS_INFO_LOAD_VERSION_0);
if (nelem > 0)
loadavg[elem++] = load_info.one_minute;
if (nelem > 1)
loadavg[elem++] = load_info.five_minute;
if (nelem > 2)
loadavg[elem++] = load_info.fifteen_minute;
# endif /* DGUX */
# if !defined (LDAV_DONE) && defined (apollo)
# define LDAV_DONE
/* Apollo code from lisch@mentorg.com (Ray Lischner).
This system call is not documented. The load average is obtained as
three long integers, for the load average over the past minute,
five minutes, and fifteen minutes. Each value is a scaled integer,
with 16 bits of integer part and 16 bits of fraction part.
I'm not sure which operating system first supported this system call,
but I know that SR10.2 supports it. */
extern void proc1_$get_loadav ();
unsigned long load_ave[3];
proc1_$get_loadav (load_ave);
if (nelem > 0)
loadavg[elem++] = load_ave[0] / 65536.0;
if (nelem > 1)
loadavg[elem++] = load_ave[1] / 65536.0;
if (nelem > 2)
loadavg[elem++] = load_ave[2] / 65536.0;
# endif /* apollo */
# if !defined (LDAV_DONE) && defined (OSF_MIPS)
# define LDAV_DONE
struct tbl_loadavg load_ave;
table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
loadavg[elem++]
= (load_ave.tl_lscale == 0
? load_ave.tl_avenrun.d[0]
: (load_ave.tl_avenrun.l[0] / (double) load_ave.tl_lscale));
# endif /* OSF_MIPS */
# if !defined (LDAV_DONE) && (defined (__MSDOS__) || defined (WINDOWS32))
# define LDAV_DONE
/* A faithful emulation is going to have to be saved for a rainy day. */
for ( ; elem < nelem; elem++)
{
loadavg[elem] = 0.0;
}
# endif /* __MSDOS__ || WINDOWS32 */
# if !defined (LDAV_DONE) && defined (OSF_ALPHA)
# define LDAV_DONE
struct tbl_loadavg load_ave;
table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
for (elem = 0; elem < nelem; elem++)
loadavg[elem]
= (load_ave.tl_lscale == 0
? load_ave.tl_avenrun.d[elem]
: (load_ave.tl_avenrun.l[elem] / (double) load_ave.tl_lscale));
# endif /* OSF_ALPHA */
# if ! defined LDAV_DONE && defined __VMS
/* VMS specific code -- read from the Load Ave driver. */
LOAD_AVE_TYPE load_ave[3];
static bool getloadavg_initialized;
# ifdef eunice
struct
{
int dsc$w_length;
char *dsc$a_pointer;
} descriptor;
# endif
/* Ensure that there is a channel open to the load ave device. */
if (!getloadavg_initialized)
{
/* Attempt to open the channel. */
# ifdef eunice
descriptor.dsc$w_length = 18;
descriptor.dsc$a_pointer = "$$VMS_LOAD_AVERAGE";
# else
$DESCRIPTOR (descriptor, "LAV0:");
# endif
if (sys$assign (&descriptor, &channel, 0, 0) & 1)
getloadavg_initialized = true;
}
/* Read the load average vector. */
if (getloadavg_initialized
&& !(sys$qiow (0, channel, IO$_READVBLK, 0, 0, 0,
load_ave, 12, 0, 0, 0, 0) & 1))
{
sys$dassgn (channel);
getloadavg_initialized = false;
}
if (!getloadavg_initialized)
return -1;
# endif /* ! defined LDAV_DONE && defined __VMS */
# if ! defined LDAV_DONE && defined LOAD_AVE_TYPE && ! defined __VMS
/* UNIX-specific code -- read the average from /dev/kmem. */
# define LDAV_PRIVILEGED /* This code requires special installation. */
LOAD_AVE_TYPE load_ave[3];
/* Get the address of LDAV_SYMBOL. */
if (offset == 0)
{
# ifndef sgi
# ifndef NLIST_STRUCT
strcpy (nl[0].n_name, LDAV_SYMBOL);
strcpy (nl[1].n_name, "");
# else /* NLIST_STRUCT */
# ifdef HAVE_STRUCT_NLIST_N_UN_N_NAME
nl[0].n_un.n_name = LDAV_SYMBOL;
nl[1].n_un.n_name = 0;
# else /* not HAVE_STRUCT_NLIST_N_UN_N_NAME */
nl[0].n_name = LDAV_SYMBOL;
nl[1].n_name = 0;
# endif /* not HAVE_STRUCT_NLIST_N_UN_N_NAME */
# endif /* NLIST_STRUCT */
# ifndef SUNOS_5
if (
# if !(defined (_AIX) && !defined (ps2))
nlist (KERNEL_FILE, nl)
# else /* _AIX */
knlist (nl, 1, sizeof (nl[0]))
# endif
>= 0)
/* Omit "&& nl[0].n_type != 0 " -- it breaks on Sun386i. */
{
# ifdef FIXUP_KERNEL_SYMBOL_ADDR
FIXUP_KERNEL_SYMBOL_ADDR (nl);
# endif
offset = nl[0].n_value;
}
# endif /* !SUNOS_5 */
# else /* sgi */
int ldav_off;
ldav_off = sysmp (MP_KERNADDR, MPKA_AVENRUN);
if (ldav_off != -1)
offset = (long int) ldav_off & 0x7fffffff;
# endif /* sgi */
}
/* Make sure we have /dev/kmem open. */
if (!getloadavg_initialized)
{
# ifndef SUNOS_5
channel = open ("/dev/kmem", O_RDONLY);
if (channel >= 0)
{
/* Set the channel to close on exec, so it does not
litter any child's descriptor table. */
set_cloexec_flag (channel, true);
getloadavg_initialized = true;
}
# else /* SUNOS_5 */
/* We pass 0 for the kernel, corefile, and swapfile names
to use the currently running kernel. */
kd = kvm_open (0, 0, 0, O_RDONLY, 0);
if (kd != 0)
{
/* nlist the currently running kernel. */
kvm_nlist (kd, nl);
offset = nl[0].n_value;
getloadavg_initialized = true;
}
# endif /* SUNOS_5 */
}
/* If we can, get the load average values. */
if (offset && getloadavg_initialized)
{
/* Try to read the load. */
# ifndef SUNOS_5
if (lseek (channel, offset, 0) == -1L
|| read (channel, (char *) load_ave, sizeof (load_ave))
!= sizeof (load_ave))
{
close (channel);
getloadavg_initialized = false;
}
# else /* SUNOS_5 */
if (kvm_read (kd, offset, (char *) load_ave, sizeof (load_ave))
!= sizeof (load_ave))
{
kvm_close (kd);
getloadavg_initialized = false;
}
# endif /* SUNOS_5 */
}
if (offset == 0 || !getloadavg_initialized)
return -1;
# endif /* ! defined LDAV_DONE && defined LOAD_AVE_TYPE && ! defined __VMS */
# if !defined (LDAV_DONE) && defined (LOAD_AVE_TYPE) /* Including VMS. */
if (nelem > 0)
loadavg[elem++] = LDAV_CVT (load_ave[0]);
if (nelem > 1)
loadavg[elem++] = LDAV_CVT (load_ave[1]);
if (nelem > 2)
loadavg[elem++] = LDAV_CVT (load_ave[2]);
# define LDAV_DONE
# endif /* !LDAV_DONE && LOAD_AVE_TYPE */
# if !defined LDAV_DONE
/* Set errno to zero to indicate that there was no particular error;
this function just can't work at all on this system. */
errno = 0;
elem = -1;
# endif
return elem;
}
|
|||||
| ↓ | check_node_accept_bytes | 65 | 142 | 234 | lib/regexec.c |
static int
internal_function
check_node_accept_bytes (const re_dfa_t *dfa, Idx node_idx,
const re_string_t *input, Idx str_idx)
{
const re_token_t *node = dfa->nodes + node_idx;
int char_len, elem_len;
Idx i;
if (BE (node->type == OP_UTF8_PERIOD, 0))
{
unsigned char c = re_string_byte_at (input, str_idx), d;
if (BE (c < 0xc2, 1))
return 0;
if (str_idx + 2 > input->len)
return 0;
d = re_string_byte_at (input, str_idx + 1);
if (c < 0xe0)
return (d < 0x80 || d > 0xbf) ? 0 : 2;
else if (c < 0xf0)
{
char_len = 3;
if (c == 0xe0 && d < 0xa0)
return 0;
}
else if (c < 0xf8)
{
char_len = 4;
if (c == 0xf0 && d < 0x90)
return 0;
}
else if (c < 0xfc)
{
char_len = 5;
if (c == 0xf8 && d < 0x88)
return 0;
}
else if (c < 0xfe)
{
char_len = 6;
if (c == 0xfc && d < 0x84)
return 0;
}
else
return 0;
if (str_idx + char_len > input->len)
return 0;
for (i = 1; i < char_len; ++i)
{
d = re_string_byte_at (input, str_idx + i);
if (d < 0x80 || d > 0xbf)
return 0;
}
return char_len;
}
char_len = re_string_char_size_at (input, str_idx);
if (node->type == OP_PERIOD)
{
if (char_len <= 1)
return 0;
/* FIXME: I don't think this if is needed, as both '\n'
and '\0' are char_len == 1. */
/* '.' accepts any one character except the following two cases. */
if ((!(dfa->syntax & RE_DOT_NEWLINE) &&
re_string_byte_at (input, str_idx) == '\n') ||
((dfa->syntax & RE_DOT_NOT_NULL) &&
re_string_byte_at (input, str_idx) == '\0'))
return 0;
return char_len;
}
elem_len = re_string_elem_size_at (input, str_idx);
if ((elem_len <= 1 && char_len <= 1) || char_len == 0)
return 0;
if (node->type == COMPLEX_BRACKET)
{
const re_charset_t *cset = node->opr.mbcset;
# ifdef _LIBC
const unsigned char *pin
= ((const unsigned char *) re_string_get_buffer (input) + str_idx);
Idx j;
uint32_t nrules;
# endif /* _LIBC */
int match_len = 0;
wchar_t wc = ((cset->nranges || cset->nchar_classes || cset->nmbchars)
? re_string_wchar_at (input, str_idx) : 0);
/* match with multibyte character? */
for (i = 0; i < cset->nmbchars; ++i)
if (wc == cset->mbchars[i])
{
match_len = char_len;
goto check_node_accept_bytes_match;
}
/* match with character_class? */
for (i = 0; i < cset->nchar_classes; ++i)
{
wctype_t wt = cset->char_classes[i];
if (__iswctype (wc, wt))
{
match_len = char_len;
goto check_node_accept_bytes_match;
}
}
# ifdef _LIBC
nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
if (nrules != 0)
{
unsigned int in_collseq = 0;
const int32_t *table, *indirect;
const unsigned char *weights, *extra;
const char *collseqwc;
int32_t idx;
/* This #include defines a local function! */
# include
|
|||||
| ↓ | fts_build | 62 | 142 | 302 | lib/fts.c |
static FTSENT *
internal_function
fts_build (register FTS *sp, int type)
{
register struct dirent *dp;
register FTSENT *p, *head;
register size_t nitems;
FTSENT *cur, *tail;
DIR *dirp;
void *oldaddr;
int saved_errno;
bool descend;
bool doadjust;
ptrdiff_t level;
nlink_t nlinks;
bool nostat;
size_t len, maxlen, new_len;
char *cp;
/* Set current node pointer. */
cur = sp->fts_cur;
/*
* Open the directory for reading. If this fails, we're done.
* If being called from fts_read, set the fts_info field.
*/
#if defined FTS_WHITEOUT && 0
if (ISSET(FTS_WHITEOUT))
oflag = DTF_NODUP|DTF_REWIND;
else
oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND;
#else
# define __opendir2(file, flag) \
( ! ISSET(FTS_NOCHDIR) && ISSET(FTS_CWDFD) \
? opendirat(sp->fts_cwd_fd, file) \
: opendir(file))
#endif
if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) {
if (type == BREAD) {
cur->fts_info = FTS_DNR;
cur->fts_errno = errno;
}
return (NULL);
}
/* Rather than calling fts_stat for each and every entry encountered
in the readdir loop (below), stat each directory only right after
opening it. */
if (cur->fts_info == FTS_NSOK)
cur->fts_info = fts_stat(sp, cur, false);
/*
* Nlinks is the number of possible entries of type directory in the
* directory if we're cheating on stat calls, 0 if we're not doing
* any stat calls at all, (nlink_t) -1 if we're statting everything.
*/
if (type == BNAMES) {
nlinks = 0;
/* Be quiet about nostat, GCC. */
nostat = false;
} else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
nlinks = (cur->fts_statp->st_nlink
- (ISSET(FTS_SEEDOT) ? 0 : 2));
nostat = true;
} else {
nlinks = -1;
nostat = false;
}
/*
* If we're going to need to stat anything or we want to descend
* and stay in the directory, chdir. If this fails we keep going,
* but set a flag so we don't chdir after the post-order visit.
* We won't be able to stat anything, but we can still return the
* names themselves. Note, that since fts_read won't be able to
* chdir into the directory, it will have to return different file
* names than before, i.e. "a/b" instead of "b". Since the node
* has already been visited in pre-order, have to wait until the
* post-order visit to return the error. There is a special case
* here, if there was nothing to stat then it's not an error to
* not be able to stat. This is all fairly nasty. If a program
* needed sorted entries or stat information, they had better be
* checking FTS_NS on the returned nodes.
*/
if (nlinks || type == BREAD) {
int dir_fd = dirfd(dirp);
if (ISSET(FTS_CWDFD) && 0 <= dir_fd)
dir_fd = dup (dir_fd);
if (dir_fd < 0 || fts_safe_changedir(sp, cur, dir_fd, NULL)) {
if (nlinks && type == BREAD)
cur->fts_errno = errno;
cur->fts_flags |= FTS_DONTCHDIR;
descend = false;
closedir(dirp);
if (ISSET(FTS_CWDFD) && 0 <= dir_fd)
close (dir_fd);
dirp = NULL;
} else
descend = true;
} else
descend = false;
/*
* Figure out the max file name length that can be stored in the
* current buffer -- the inner loop allocates more space as necessary.
* We really wouldn't have to do the maxlen calculations here, we
* could do them in fts_read before returning the name, but it's a
* lot easier here since the length is part of the dirent structure.
*
* If not changing directories set a pointer so that can just append
* each new component into the file name.
*/
len = NAPPEND(cur);
if (ISSET(FTS_NOCHDIR)) {
cp = sp->fts_path + len;
*cp++ = '/';
} else {
/* GCC, you're too verbose. */
cp = NULL;
}
len++;
maxlen = sp->fts_pathlen - len;
level = cur->fts_level + 1;
/* Read the directory, attaching each entry to the `link' pointer. */
doadjust = false;
for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {
bool is_dir;
if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
continue;
if ((p = fts_alloc (sp, dp->d_name,
_D_EXACT_NAMLEN (dp))) == NULL)
goto mem1;
if (_D_EXACT_NAMLEN (dp) >= maxlen) {
/* include space for NUL */
oldaddr = sp->fts_path;
if (! fts_palloc(sp, _D_EXACT_NAMLEN (dp) + len + 1)) {
/*
* No more memory. Save
* errno, free up the current structure and the
* structures already allocated.
*/
mem1: saved_errno = errno;
free(p);
fts_lfree(head);
closedir(dirp);
cur->fts_info = FTS_ERR;
SET(FTS_STOP);
__set_errno (saved_errno);
return (NULL);
}
/* Did realloc() change the pointer? */
if (oldaddr != sp->fts_path) {
doadjust = true;
if (ISSET(FTS_NOCHDIR))
cp = sp->fts_path + len;
}
maxlen = sp->fts_pathlen - len;
}
new_len = len + _D_EXACT_NAMLEN (dp);
if (new_len < len) {
/*
* In the unlikely event that we would end up
* with a file name longer than SIZE_MAX, free up
* the current structure and the structures already
* allocated, then error out with ENAMETOOLONG.
*/
free(p);
fts_lfree(head);
closedir(dirp);
cur->fts_info = FTS_ERR;
SET(FTS_STOP);
__set_errno (ENAMETOOLONG);
return (NULL);
}
p->fts_level = level;
p->fts_parent = sp->fts_cur;
p->fts_pathlen = new_len;
#if defined FTS_WHITEOUT && 0
if (dp->d_type == DT_WHT)
p->fts_flags |= FTS_ISW;
#endif
/* Store dirent.d_ino, in case we need to sort
entries before processing them. */
p->fts_statp->st_ino = D_INO (dp);
/* Build a file name for fts_stat to stat. */
if (ISSET(FTS_NOCHDIR)) {
p->fts_accpath = p->fts_path;
memmove(cp, p->fts_name, p->fts_namelen + 1);
} else
p->fts_accpath = p->fts_name;
if (sp->fts_compar == NULL || ISSET(FTS_DEFER_STAT)) {
/* Record what fts_read will have to do with this
entry. In many cases, it will simply fts_stat it,
but we can take advantage of any d_type information
to optimize away the unnecessary stat calls. I.e.,
if FTS_NOSTAT is in effect and we're not following
symlinks (FTS_PHYSICAL) and d_type indicates this
is *not* a directory, then we won't have to stat it
at all. If it *is* a directory, then (currently)
we stat it regardless, in order to get device and
inode numbers. Some day we might optimize that
away, too, for directories where d_ino is known to
be valid. */
bool skip_stat = (ISSET(FTS_PHYSICAL)
&& ISSET(FTS_NOSTAT)
&& DT_IS_KNOWN(dp)
&& ! DT_MUST_BE(dp, DT_DIR));
p->fts_info = FTS_NSOK;
fts_set_stat_required(p, !skip_stat);
is_dir = (ISSET(FTS_PHYSICAL) && ISSET(FTS_NOSTAT)
&& DT_MUST_BE(dp, DT_DIR));
} else {
p->fts_info = fts_stat(sp, p, false);
is_dir = (p->fts_info == FTS_D
|| p->fts_info == FTS_DC
|| p->fts_info == FTS_DOT);
}
/* Decrement link count if applicable. */
if (nlinks > 0 && is_dir)
nlinks -= nostat;
/* We walk in directory order so "ls -f" doesn't get upset. */
p->fts_link = NULL;
if (head == NULL)
head = tail = p;
else {
tail->fts_link = p;
tail = p;
}
++nitems;
}
if (dirp)
closedir(dirp);
/*
* If realloc() changed the address of the file name, adjust the
* addresses for the rest of the tree and the dir list.
*/
if (doadjust)
fts_padjust(sp, head);
/*
* If not changing directories, reset the file name back to original
* state.
*/
if (ISSET(FTS_NOCHDIR)) {
if (len == sp->fts_pathlen || nitems == 0)
--cp;
*cp = '\0';
}
/*
* If descended after called from fts_children or after called from
* fts_read and nothing found, get back. At the root level we use
* the saved fd; if one of fts_open()'s arguments is a relative name
* to an empty directory, we wind up here with no other way back. If
* can't get back, we're done.
*/
if (descend && (type == BCHILD || !nitems) &&
(cur->fts_level == FTS_ROOTLEVEL
? RESTORE_INITIAL_CWD(sp)
: fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
cur->fts_info = FTS_ERR;
SET(FTS_STOP);
fts_lfree(head);
return (NULL);
}
/* If didn't find anything, return NULL. */
if (!nitems) {
if (type == BREAD)
cur->fts_info = FTS_DP;
fts_lfree(head);
return (NULL);
}
/* If there are many entries, no sorting function has been specified,
and this file system is of a type that may be slow with a large
number of entries, then sort the directory entries on increasing
inode numbers. */
if (nitems > _FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD
&& !sp->fts_compar
&& ISSET (FTS_CWDFD)
&& dirent_inode_sort_may_be_useful (sp->fts_cwd_fd)) {
sp->fts_compar = fts_compare_ino;
head = fts_sort (sp, head, nitems);
sp->fts_compar = NULL;
}
/* Sort the entries. */
if (sp->fts_compar && nitems > 1)
head = fts_sort(sp, head, nitems);
return (head);
}
|
|||||
| ↓ | read_file_system_list | 59 | 328 | 544 | lib/mountlist.c |
struct mount_entry *
read_file_system_list (bool need_fs_type)
{
struct mount_entry *mount_list;
struct mount_entry *me;
struct mount_entry **mtail = &mount_list;
#ifdef MOUNTED_LISTMNTENT
{
struct tabmntent *mntlist, *p;
struct mntent *mnt;
struct mount_entry *me;
/* the third and fourth arguments could be used to filter mounts,
but Crays doesn't seem to have any mounts that we want to
remove. Specifically, automount create normal NFS mounts.
*/
if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0)
return NULL;
for (p = mntlist; p; p = p->next) {
mnt = p->ment;
me = xmalloc (sizeof *me);
me->me_devname = xstrdup (mnt->mnt_fsname);
me->me_mountdir = xstrdup (mnt->mnt_dir);
me->me_type = xstrdup (mnt->mnt_type);
me->me_type_malloced = 1;
me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
me->me_dev = -1;
*mtail = me;
mtail = &me->me_next;
}
freemntlist (mntlist);
}
#endif
#ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
{
struct mntent *mnt;
char *table = MOUNTED;
FILE *fp;
fp = setmntent (table, "r");
if (fp == NULL)
return NULL;
while ((mnt = getmntent (fp)))
{
me = xmalloc (sizeof *me);
me->me_devname = xstrdup (mnt->mnt_fsname);
me->me_mountdir = xstrdup (mnt->mnt_dir);
me->me_type = xstrdup (mnt->mnt_type);
me->me_type_malloced = 1;
me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
me->me_dev = dev_from_mount_options (mnt->mnt_opts);
/* Add to the linked list. */
*mtail = me;
mtail = &me->me_next;
}
if (endmntent (fp) == 0)
goto free_then_fail;
}
#endif /* MOUNTED_GETMNTENT1. */
#ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
{
struct statfs *fsp;
int entries;
entries = getmntinfo (&fsp, MNT_NOWAIT);
if (entries < 0)
return NULL;
for (; entries-- > 0; fsp++)
{
char *fs_type = fsp_to_string (fsp);
me = xmalloc (sizeof *me);
me->me_devname = xstrdup (fsp->f_mntfromname);
me->me_mountdir = xstrdup (fsp->f_mntonname);
me->me_type = fs_type;
me->me_type_malloced = 0;
me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
/* Add to the linked list. */
*mtail = me;
mtail = &me->me_next;
}
}
#endif /* MOUNTED_GETMNTINFO */
#ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
{
struct statvfs *fsp;
int entries;
entries = getmntinfo (&fsp, MNT_NOWAIT);
if (entries < 0)
return NULL;
for (; entries-- > 0; fsp++)
{
me = xmalloc (sizeof *me);
me->me_devname = xstrdup (fsp->f_mntfromname);
me->me_mountdir = xstrdup (fsp->f_mntonname);
me->me_type = xstrdup (fsp->f_fstypename);
me->me_type_malloced = 1;
me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
/* Add to the linked list. */
*mtail = me;
mtail = &me->me_next;
}
}
#endif /* MOUNTED_GETMNTINFO2 */
#ifdef MOUNTED_GETMNT /* Ultrix. */
{
int offset = 0;
int val;
struct fs_data fsd;
while (errno = 0,
0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
(char *) 0)))
{
me = xmalloc (sizeof *me);
me->me_devname = xstrdup (fsd.fd_req.devname);
me->me_mountdir = xstrdup (fsd.fd_req.path);
me->me_type = gt_names[fsd.fd_req.fstype];
me->me_type_malloced = 0;
me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
me->me_dev = fsd.fd_req.dev;
/* Add to the linked list. */
*mtail = me;
mtail = &me->me_next;
}
if (val < 0)
goto free_then_fail;
}
#endif /* MOUNTED_GETMNT. */
#if defined MOUNTED_FS_STAT_DEV /* BeOS */
{
/* The next_dev() and fs_stat_dev() system calls give the list of
all file systems, including the information returned by statvfs()
(fs type, total blocks, free blocks etc.), but without the mount
point. But on BeOS all file systems except / are mounted in the
rootfs, directly under /.
The directory name of the mount point is often, but not always,
identical to the volume name of the device.
We therefore get the list of subdirectories of /, and the list
of all file systems, and match the two lists. */
DIR *dirp;
struct rootdir_entry
{
char *name;
dev_t dev;
ino_t ino;
struct rootdir_entry *next;
};
struct rootdir_entry *rootdir_list;
struct rootdir_entry **rootdir_tail;
int32 pos;
dev_t dev;
fs_info fi;
/* All volumes are mounted in the rootfs, directly under /. */
rootdir_list = NULL;
rootdir_tail = &rootdir_list;
dirp = opendir ("/");
if (dirp)
{
struct dirent *d;
while ((d = readdir (dirp)) != NULL)
{
char *name;
struct stat statbuf;
if (strcmp (d->d_name, "..") == 0)
continue;
if (strcmp (d->d_name, ".") == 0)
name = xstrdup ("/");
else
{
name = xmalloc (1 + strlen (d->d_name) + 1);
name[0] = '/';
strcpy (name + 1, d->d_name);
}
if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
{
struct rootdir_entry *re = xmalloc (sizeof *re);
re->name = name;
re->dev = statbuf.st_dev;
re->ino = statbuf.st_ino;
/* Add to the linked list. */
*rootdir_tail = re;
rootdir_tail = &re->next;
}
else
free (name);
}
closedir (dirp);
}
*rootdir_tail = NULL;
for (pos = 0; (dev = next_dev (&pos)) >= 0; )
if (fs_stat_dev (dev, &fi) >= 0)
{
/* Note: fi.dev == dev. */
struct rootdir_entry *re;
for (re = rootdir_list; re; re = re->next)
if (re->dev == fi.dev && re->ino == fi.root)
break;
me = xmalloc (sizeof *me);
me->me_devname = xstrdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name);
me->me_type = xstrdup (fi.fsh_name);
me->me_type_malloced = 1;
me->me_dev = fi.dev;
me->me_dummy = 0;
me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
/* Add to the linked list. */
*mtail = me;
mtail = &me->me_next;
}
*mtail = NULL;
while (rootdir_list != NULL)
{
struct rootdir_entry *re = rootdir_list;
rootdir_list = re->next;
free (re->name);
free (re);
}
}
#endif /* MOUNTED_FS_STAT_DEV */
#if defined MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
{
int numsys, counter;
size_t bufsize;
struct statfs *stats;
numsys = getfsstat ((struct statfs *)0, 0L, MNT_NOWAIT);
if (numsys < 0)
return (NULL);
if (SIZE_MAX / sizeof *stats <= numsys)
xalloc_die ();
bufsize = (1 + numsys) * sizeof *stats;
stats = xmalloc (bufsize);
numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
if (numsys < 0)
{
free (stats);
return (NULL);
}
for (counter = 0; counter < numsys; counter++)
{
me = xmalloc (sizeof *me);
me->me_devname = xstrdup (stats[counter].f_mntfromname);
me->me_mountdir = xstrdup (stats[counter].f_mntonname);
me->me_type = xstrdup (FS_TYPE (stats[counter]));
me->me_type_malloced = 1;
me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
/* Add to the linked list. */
*mtail = me;
mtail = &me->me_next;
}
free (stats);
}
#endif /* MOUNTED_GETFSSTAT */
#if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
{
struct mnttab mnt;
char *table = "/etc/mnttab";
FILE *fp;
fp = fopen (table, "r");
if (fp == NULL)
return NULL;
while (fread (&mnt, sizeof mnt, 1, fp) > 0)
{
me = xmalloc (sizeof *me);
# ifdef GETFSTYP /* SVR3. */
me->me_devname = xstrdup (mnt.mt_dev);
# else
me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
strcpy (me->me_devname, "/dev/");
strcpy (me->me_devname + 5, mnt.mt_dev);
# endif
me->me_mountdir = xstrdup (mnt.mt_filsys);
me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
me->me_type = "";
me->me_type_malloced = 0;
# ifdef GETFSTYP /* SVR3. */
if (need_fs_type)
{
struct statfs fsd;
char typebuf[FSTYPSZ];
if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
&& sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
{
me->me_type = xstrdup (typebuf);
me->me_type_malloced = 1;
}
}
# endif
me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
/* Add to the linked list. */
*mtail = me;
mtail = &me->me_next;
}
if (ferror (fp))
{
/* The last fread() call must have failed. */
int saved_errno = errno;
fclose (fp);
errno = saved_errno;
goto free_then_fail;
}
if (fclose (fp) == EOF)
goto free_then_fail;
}
#endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
#ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */
{
struct mntent **mnttbl = getmnttbl (), **ent;
for (ent=mnttbl;*ent;ent++)
{
me = xmalloc (sizeof *me);
me->me_devname = xstrdup ( (*ent)->mt_resource);
me->me_mountdir = xstrdup ( (*ent)->mt_directory);
me->me_type = xstrdup ((*ent)->mt_fstype);
me->me_type_malloced = 1;
me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
/* Add to the linked list. */
*mtail = me;
mtail = &me->me_next;
}
endmnttbl ();
}
#endif
#ifdef MOUNTED_GETMNTENT2 /* SVR4. */
{
struct mnttab mnt;
char *table = MNTTAB;
FILE *fp;
int ret;
int lockfd = -1;
# if defined F_RDLCK && defined F_SETLKW
/* MNTTAB_LOCK is a macro name of our own invention; it's not present in
e.g. Solaris 2.6. If the SVR4 folks ever define a macro
for this file name, we should use their macro name instead.
(Why not just lock MNTTAB directly? We don't know.) */
# ifndef MNTTAB_LOCK
# define MNTTAB_LOCK "/etc/.mnttab.lock"
# endif
lockfd = open (MNTTAB_LOCK, O_RDONLY);
if (0 <= lockfd)
{
struct flock flock;
flock.l_type = F_RDLCK;
flock.l_whence = SEEK_SET;
flock.l_start = 0;
flock.l_len = 0;
while (fcntl (lockfd, F_SETLKW, &flock) == -1)
if (errno != EINTR)
{
int saved_errno = errno;
close (lockfd);
errno = saved_errno;
return NULL;
}
}
else if (errno != ENOENT)
return NULL;
# endif
errno = 0;
fp = fopen (table, "r");
if (fp == NULL)
ret = errno;
else
{
while ((ret = getmntent (fp, &mnt)) == 0)
{
me = xmalloc (sizeof *me);
me->me_devname = xstrdup (mnt.mnt_special);
me->me_mountdir = xstrdup (mnt.mnt_mountp);
me->me_type = xstrdup (mnt.mnt_fstype);
me->me_type_malloced = 1;
me->me_dummy = MNT_IGNORE (&mnt) != 0;
me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
me->me_dev = dev_from_mount_options (mnt.mnt_mntopts);
/* Add to the linked list. */
*mtail = me;
mtail = &me->me_next;
}
ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
}
if (0 <= lockfd && close (lockfd) != 0)
ret = errno;
if (0 <= ret)
{
errno = ret;
goto free_then_fail;
}
}
#endif /* MOUNTED_GETMNTENT2. */
#ifdef MOUNTED_VMOUNT /* AIX. */
{
int bufsize;
char *entries, *thisent;
struct vmount *vmp;
int n_entries;
int i;
/* Ask how many bytes to allocate for the mounted file system info. */
if (mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize) != 0)
return NULL;
entries = xmalloc (bufsize);
/* Get the list of mounted file systems. */
n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
if (n_entries < 0)
{
int saved_errno = errno;
free (entries);
errno = saved_errno;
return NULL;
}
for (i = 0, thisent = entries;
i < n_entries;
i++, thisent += vmp->vmt_length)
{
char *options, *ignore;
vmp = (struct vmount *) thisent;
me = xmalloc (sizeof *me);
if (vmp->vmt_flags & MNT_REMOTE)
{
char *host, *dir;
me->me_remote = 1;
/* Prepend the remote dirname. */
host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
me->me_devname = xmalloc (strlen (host) + strlen (dir) + 2);
strcpy (me->me_devname, host);
strcat (me->me_devname, ":");
strcat (me->me_devname, dir);
}
else
{
me->me_remote = 0;
me->me_devname = xstrdup (thisent +
vmp->vmt_data[VMT_OBJECT].vmt_off);
}
me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
me->me_type_malloced = 1;
options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
ignore = strstr (options, "ignore");
me->me_dummy = (ignore
&& (ignore == options || ignore[-1] == ',')
&& (ignore[sizeof "ignore" - 1] == ','
|| ignore[sizeof "ignore" - 1] == '\0'));
me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */
/* Add to the linked list. */
*mtail = me;
mtail = &me->me_next;
}
free (entries);
}
#endif /* MOUNTED_VMOUNT. */
*mtail = NULL;
return mount_list;
free_then_fail:
{
int saved_errno = errno;
*mtail = NULL;
while (mount_list)
{
me = mount_list->me_next;
free (mount_list->me_devname);
free (mount_list->me_mountdir);
if (mount_list->me_type_malloced)
free (mount_list->me_type);
free (mount_list);
mount_list = me;
}
errno = saved_errno;
return NULL;
}
}
|
|||||
| ↓ | strtod | 59 | 117 | 241 | lib/strtod.c |
double
strtod (const char *nptr, char **endptr)
{
const unsigned char *s;
bool negative = false;
/* The number so far. */
double num;
bool got_dot; /* Found a decimal point. */
bool got_digit; /* Seen any digits. */
bool hex = false; /* Look for hex float exponent. */
/* The exponent of the number. */
long int exponent;
if (nptr == NULL)
{
errno = EINVAL;
goto noconv;
}
/* Use unsigned char for the ctype routines. */
s = (unsigned char *) nptr;
/* Eat whitespace. */
while (isspace (*s))
++s;
/* Get the sign. */
negative = *s == '-';
if (*s == '-' || *s == '+')
++s;
num = 0.0;
got_dot = false;
got_digit = false;
exponent = 0;
/* Check for hex float. */
if (*s == '0' && c_tolower (s[1]) == 'x'
&& (c_isxdigit (s[2]) || ('.' == s[2] && c_isxdigit (s[3]))))
{
hex = true;
s += 2;
for (;; ++s)
{
if (c_isxdigit (*s))
{
got_digit = true;
/* Make sure that multiplication by 16 will not overflow. */
if (num > DBL_MAX / 16)
/* The value of the digit doesn't matter, since we have already
gotten as many digits as can be represented in a `double'.
This doesn't necessarily mean the result will overflow.
The exponent may reduce it to within range.
We just need to record that there was another
digit so that we can multiply by 16 later. */
++exponent;
else
num = ((num * 16.0)
+ (c_tolower (*s) - (c_isdigit (*s) ? '0' : 'a' - 10)));
/* Keep track of the number of digits after the decimal point.
If we just divided by 16 here, we would lose precision. */
if (got_dot)
--exponent;
}
else if (!got_dot && *s == '.')
/* Record that we have found the decimal point. */
got_dot = true;
else
/* Any other character terminates the number. */
break;
}
}
/* Not a hex float. */
else
{
for (;; ++s)
{
if (c_isdigit (*s))
{
got_digit = true;
/* Make sure that multiplication by 10 will not overflow. */
if (num > DBL_MAX * 0.1)
/* The value of the digit doesn't matter, since we have already
gotten as many digits as can be represented in a `double'.
This doesn't necessarily mean the result will overflow.
The exponent may reduce it to within range.
We just need to record that there was another
digit so that we can multiply by 10 later. */
++exponent;
else
num = (num * 10.0) + (*s - '0');
/* Keep track of the number of digits after the decimal point.
If we just divided by 10 here, we would lose precision. */
if (got_dot)
--exponent;
}
else if (!got_dot && *s == '.')
/* Record that we have found the decimal point. */
got_dot = true;
else
/* Any other character terminates the number. */
break;
}
}
if (!got_digit)
{
/* Check for infinities and NaNs. */
if (c_tolower (*s) == 'i'
&& c_tolower (s[1]) == 'n'
&& c_tolower (s[2]) == 'f')
{
s += 3;
num = HUGE_VAL;
if (c_tolower (*s) == 'i'
&& c_tolower (s[1]) == 'n'
&& c_tolower (s[2]) == 'i'
&& c_tolower (s[3]) == 't'
&& c_tolower (s[4]) == 'y')
s += 5;
goto valid;
}
#ifdef NAN
else if (c_tolower (*s) == 'n'
&& c_tolower (s[1]) == 'a'
&& c_tolower (s[2]) == 'n')
{
s += 3;
num = NAN;
/* Since nan(
|
|||||
| ↓ | re_string_reconstruct | 58 | 148 | 260 | lib/regex_internal.c |
static reg_errcode_t
internal_function
re_string_reconstruct (re_string_t *pstr, Idx idx, int eflags)
{
Idx offset;
if (BE (pstr->raw_mbs_idx <= idx, 0))
offset = idx - pstr->raw_mbs_idx;
else
{
/* Reset buffer. */
#ifdef RE_ENABLE_I18N
if (pstr->mb_cur_max > 1)
memset (&pstr->cur_state, '\0', sizeof (mbstate_t));
#endif /* RE_ENABLE_I18N */
pstr->len = pstr->raw_len;
pstr->stop = pstr->raw_stop;
pstr->valid_len = 0;
pstr->raw_mbs_idx = 0;
pstr->valid_raw_len = 0;
pstr->offsets_needed = 0;
pstr->tip_context = ((eflags & REG_NOTBOL) ? CONTEXT_BEGBUF
: CONTEXT_NEWLINE | CONTEXT_BEGBUF);
if (!pstr->mbs_allocated)
pstr->mbs = (unsigned char *) pstr->raw_mbs;
offset = idx;
}
if (BE (offset != 0, 1))
{
/* Should the already checked characters be kept? */
if (BE (offset < pstr->valid_raw_len, 1))
{
/* Yes, move them to the front of the buffer. */
#ifdef RE_ENABLE_I18N
if (BE (pstr->offsets_needed, 0))
{
Idx low = 0, high = pstr->valid_len, mid;
do
{
mid = (high + low) / 2;
if (pstr->offsets[mid] > offset)
high = mid;
else if (pstr->offsets[mid] < offset)
low = mid + 1;
else
break;
}
while (low < high);
if (pstr->offsets[mid] < offset)
++mid;
pstr->tip_context = re_string_context_at (pstr, mid - 1,
eflags);
/* This can be quite complicated, so handle specially
only the common and easy case where the character with
different length representation of lower and upper
case is present at or after offset. */
if (pstr->valid_len > offset
&& mid == offset && pstr->offsets[mid] == offset)
{
memmove (pstr->wcs, pstr->wcs + offset,
(pstr->valid_len - offset) * sizeof (wint_t));
memmove (pstr->mbs, pstr->mbs + offset, pstr->valid_len - offset);
pstr->valid_len -= offset;
pstr->valid_raw_len -= offset;
for (low = 0; low < pstr->valid_len; low++)
pstr->offsets[low] = pstr->offsets[low + offset] - offset;
}
else
{
/* Otherwise, just find out how long the partial multibyte
character at offset is and fill it with WEOF/255. */
pstr->len = pstr->raw_len - idx + offset;
pstr->stop = pstr->raw_stop - idx + offset;
pstr->offsets_needed = 0;
while (mid > 0 && pstr->offsets[mid - 1] == offset)
--mid;
while (mid < pstr->valid_len)
if (pstr->wcs[mid] != WEOF)
break;
else
++mid;
if (mid == pstr->valid_len)
pstr->valid_len = 0;
else
{
pstr->valid_len = pstr->offsets[mid] - offset;
if (pstr->valid_len)
{
for (low = 0; low < pstr->valid_len; ++low)
pstr->wcs[low] = WEOF;
memset (pstr->mbs, 255, pstr->valid_len);
}
}
pstr->valid_raw_len = pstr->valid_len;
}
}
else
#endif
{
pstr->tip_context = re_string_context_at (pstr, offset - 1,
eflags);
#ifdef RE_ENABLE_I18N
if (pstr->mb_cur_max > 1)
memmove (pstr->wcs, pstr->wcs + offset,
(pstr->valid_len - offset) * sizeof (wint_t));
#endif /* RE_ENABLE_I18N */
if (BE (pstr->mbs_allocated, 0))
memmove (pstr->mbs, pstr->mbs + offset,
pstr->valid_len - offset);
pstr->valid_len -= offset;
pstr->valid_raw_len -= offset;
#if DEBUG
assert (pstr->valid_len > 0);
#endif
}
}
else
{
/* No, skip all characters until IDX. */
Idx prev_valid_len = pstr->valid_len;
#ifdef RE_ENABLE_I18N
if (BE (pstr->offsets_needed, 0))
{
pstr->len = pstr->raw_len - idx + offset;
pstr->stop = pstr->raw_stop - idx + offset;
pstr->offsets_needed = 0;
}
#endif
pstr->valid_len = 0;
#ifdef RE_ENABLE_I18N
if (pstr->mb_cur_max > 1)
{
Idx wcs_idx;
wint_t wc = WEOF;
if (pstr->is_utf8)
{
const unsigned char *raw, *p, *end;
/* Special case UTF-8. Multi-byte chars start with any
byte other than 0x80 - 0xbf. */
raw = pstr->raw_mbs + pstr->raw_mbs_idx;
end = raw + (offset - pstr->mb_cur_max);
if (end < pstr->raw_mbs)
end = pstr->raw_mbs;
p = raw + offset - 1;
#ifdef _LIBC
/* We know the wchar_t encoding is UCS4, so for the simple
case, ASCII characters, skip the conversion step. */
if (isascii (*p) && BE (pstr->trans == NULL, 1))
{
memset (&pstr->cur_state, '\0', sizeof (mbstate_t));
/* pstr->valid_len = 0; */
wc = (wchar_t) *p;
}
else
#endif
for (; p >= end; --p)
if ((*p & 0xc0) != 0x80)
{
mbstate_t cur_state;
wchar_t wc2;
Idx mlen = raw + pstr->len - p;
unsigned char buf[6];
size_t mbclen;
if (BE (pstr->trans != NULL, 0))
{
int i = mlen < 6 ? mlen : 6;
while (--i >= 0)
buf[i] = pstr->trans[p[i]];
}
/* XXX Don't use mbrtowc, we know which conversion
to use (UTF-8 -> UCS4). */
memset (&cur_state, 0, sizeof (cur_state));
mbclen = mbrtowc (&wc2, (const char *) p, mlen,
&cur_state);
if (raw + offset - p <= mbclen
&& mbclen < (size_t) -2)
{
memset (&pstr->cur_state, '\0',
sizeof (mbstate_t));
pstr->valid_len = mbclen - (raw + offset - p);
wc = wc2;
}
break;
}
}
if (wc == WEOF)
pstr->valid_len = re_string_skip_chars (pstr, idx, &wc) - idx;
if (wc == WEOF)
pstr->tip_context
= re_string_context_at (pstr, prev_valid_len - 1, eflags);
else
pstr->tip_context = ((BE (pstr->word_ops_used != 0, 0)
&& IS_WIDE_WORD_CHAR (wc))
? CONTEXT_WORD
: ((IS_WIDE_NEWLINE (wc)
&& pstr->newline_anchor)
? CONTEXT_NEWLINE : 0));
if (BE (pstr->valid_len, 0))
{
for (wcs_idx = 0; wcs_idx < pstr->valid_len; ++wcs_idx)
pstr->wcs[wcs_idx] = WEOF;
if (pstr->mbs_allocated)
memset (pstr->mbs, 255, pstr->valid_len);
}
pstr->valid_raw_len = pstr->valid_len;
}
else
#endif /* RE_ENABLE_I18N */
{
int c = pstr->raw_mbs[pstr->raw_mbs_idx + offset - 1];
pstr->valid_raw_len = 0;
if (pstr->trans)
c = pstr->trans[c];
pstr->tip_context = (bitset_contain (pstr->word_char, c)
? CONTEXT_WORD
: ((IS_NEWLINE (c) && pstr->newline_anchor)
? CONTEXT_NEWLINE : 0));
}
}
if (!BE (pstr->mbs_allocated, 0))
pstr->mbs += offset;
}
pstr->raw_mbs_idx = idx;
pstr->len -= offset;
pstr->stop -= offset;
/* Then build the buffers. */
#ifdef RE_ENABLE_I18N
if (pstr->mb_cur_max > 1)
{
if (pstr->icase)
{
reg_errcode_t ret = build_wcs_upper_buffer (pstr);
if (BE (ret != REG_NOERROR, 0))
return ret;
}
else
build_wcs_buffer (pstr);
}
else
#endif /* RE_ENABLE_I18N */
if (BE (pstr->mbs_allocated, 0))
{
if (pstr->icase)
build_upper_buffer (pstr);
else if (pstr->trans != NULL)
re_string_translate_buffer (pstr);
}
else
pstr->valid_len = pstr->len;
pstr->cur_idx = 0;
return REG_NOERROR;
}
|
|||||
| ↓ | __getcwd | 56 | 163 | 321 | lib/getcwd.c |
/* Get the name of the current working directory, and put it in SIZE
bytes of BUF. Returns NULL if the directory couldn't be determined or
SIZE was too small. If successful, returns BUF. In GNU, if BUF is
NULL, an array is allocated with `malloc'; the array is SIZE bytes long,
unless SIZE == 0, in which case it is as big as necessary. */
char *
__getcwd (char *buf, size_t size)
{
/* Lengths of big file name components and entire file names, and a
deep level of file name nesting. These numbers are not upper
bounds; they are merely large values suitable for initial
allocations, designed to be large enough for most real-world
uses. */
enum
{
BIG_FILE_NAME_COMPONENT_LENGTH = 255,
BIG_FILE_NAME_LENGTH = MIN (4095, PATH_MAX - 1),
DEEP_NESTING = 100
};
#if HAVE_OPENAT_SUPPORT
int fd = AT_FDCWD;
bool fd_needs_closing = false;
#else
char dots[DEEP_NESTING * sizeof ".." + BIG_FILE_NAME_COMPONENT_LENGTH + 1];
char *dotlist = dots;
size_t dotsize = sizeof dots;
size_t dotlen = 0;
#endif
DIR *dirstream = NULL;
dev_t rootdev, thisdev;
ino_t rootino, thisino;
char *dir;
register char *dirp;
struct stat st;
size_t allocated = size;
size_t used;
#if HAVE_PARTLY_WORKING_GETCWD
/* The system getcwd works, except it sometimes fails when it
shouldn't, setting errno to ERANGE, ENAMETOOLONG, or ENOENT. If
AT_FDCWD is not defined, the algorithm below is O(N**2) and this
is much slower than the system getcwd (at least on GNU/Linux).
So trust the system getcwd's results unless they look
suspicious.
Use the system getcwd even if we have openat support, since the
system getcwd works even when a parent is unreadable, while the
openat-based approach does not. */
# undef getcwd
dir = getcwd (buf, size);
if (dir || (errno != ERANGE && !is_ENAMETOOLONG (errno) && errno != ENOENT))
return dir;
#endif
if (size == 0)
{
if (buf != NULL)
{
__set_errno (EINVAL);
return NULL;
}
allocated = BIG_FILE_NAME_LENGTH + 1;
}
if (buf == NULL)
{
dir = malloc (allocated);
if (dir == NULL)
return NULL;
}
else
dir = buf;
dirp = dir + allocated;
*--dirp = '\0';
if (__lstat (".", &st) < 0)
goto lose;
thisdev = st.st_dev;
thisino = st.st_ino;
if (__lstat ("/", &st) < 0)
goto lose;
rootdev = st.st_dev;
rootino = st.st_ino;
while (!(thisdev == rootdev && thisino == rootino))
{
struct dirent *d;
dev_t dotdev;
ino_t dotino;
bool mount_point;
int parent_status;
size_t dirroom;
size_t namlen;
bool use_d_ino = true;
/* Look at the parent directory. */
#if HAVE_OPENAT_SUPPORT
fd = openat (fd, "..", O_RDONLY);
if (fd < 0)
goto lose;
fd_needs_closing = true;
parent_status = fstat (fd, &st);
#else
dotlist[dotlen++] = '.';
dotlist[dotlen++] = '.';
dotlist[dotlen] = '\0';
parent_status = __lstat (dotlist, &st);
#endif
if (parent_status != 0)
goto lose;
if (dirstream && __closedir (dirstream) != 0)
{
dirstream = NULL;
goto lose;
}
/* Figure out if this directory is a mount point. */
dotdev = st.st_dev;
dotino = st.st_ino;
mount_point = dotdev != thisdev;
/* Search for the last directory. */
#if HAVE_OPENAT_SUPPORT
dirstream = fdopendir (fd);
if (dirstream == NULL)
goto lose;
/* Reset fd. It may have been closed by fdopendir. */
fd = dirfd (dirstream);
fd_needs_closing = false;
#else
dirstream = __opendir (dotlist);
if (dirstream == NULL)
goto lose;
dotlist[dotlen++] = '/';
#endif
for (;;)
{
/* Clear errno to distinguish EOF from error if readdir returns
NULL. */
__set_errno (0);
d = __readdir (dirstream);
/* When we've iterated through all directory entries without finding
one with a matching d_ino, rewind the stream and consider each
name again, but this time, using lstat. This is necessary in a
chroot on at least one system (glibc-2.3.6 + linux 2.6.12), where
.., ../.., ../../.., etc. all had the same device number, yet the
d_ino values for entries in / did not match those obtained
via lstat. */
if (d == NULL && errno == 0 && use_d_ino)
{
use_d_ino = false;
rewinddir (dirstream);
d = __readdir (dirstream);
}
if (d == NULL)
{
if (errno == 0)
/* EOF on dirstream, which can mean e.g., that the current
directory has been removed. */
__set_errno (ENOENT);
goto lose;
}
if (d->d_name[0] == '.' &&
(d->d_name[1] == '\0' ||
(d->d_name[1] == '.' && d->d_name[2] == '\0')))
continue;
if (use_d_ino)
{
bool match = (MATCHING_INO (d, thisino) || mount_point);
if (! match)
continue;
}
{
int entry_status;
#if HAVE_OPENAT_SUPPORT
entry_status = fstatat (fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW);
#else
/* Compute size needed for this file name, or for the file
name ".." in the same directory, whichever is larger.
Room for ".." might be needed the next time through
the outer loop. */
size_t name_alloc = _D_ALLOC_NAMLEN (d);
size_t filesize = dotlen + MAX (sizeof "..", name_alloc);
if (filesize < dotlen)
goto memory_exhausted;
if (dotsize < filesize)
{
/* My, what a deep directory tree you have, Grandma. */
size_t newsize = MAX (filesize, dotsize * 2);
size_t i;
if (newsize < dotsize)
goto memory_exhausted;
if (dotlist != dots)
free (dotlist);
dotlist = malloc (newsize);
if (dotlist == NULL)
goto lose;
dotsize = newsize;
i = 0;
do
{
dotlist[i++] = '.';
dotlist[i++] = '.';
dotlist[i++] = '/';
}
while (i < dotlen);
}
memcpy (dotlist + dotlen, d->d_name, _D_ALLOC_NAMLEN (d));
entry_status = __lstat (dotlist, &st);
#endif
/* We don't fail here if we cannot stat() a directory entry.
This can happen when (network) file systems fail. If this
entry is in fact the one we are looking for we will find
out soon as we reach the end of the directory without
having found anything. */
if (entry_status == 0 && S_ISDIR (st.st_mode)
&& st.st_dev == thisdev && st.st_ino == thisino)
break;
}
}
dirroom = dirp - dir;
namlen = _D_EXACT_NAMLEN (d);
if (dirroom <= namlen)
{
if (size != 0)
{
__set_errno (ERANGE);
goto lose;
}
else
{
char *tmp;
size_t oldsize = allocated;
allocated += MAX (allocated, namlen);
if (allocated < oldsize
|| ! (tmp = realloc (dir, allocated)))
goto memory_exhausted;
/* Move current contents up to the end of the buffer.
This is guaranteed to be non-overlapping. */
dirp = memcpy (tmp + allocated - (oldsize - dirroom),
tmp + dirroom,
oldsize - dirroom);
dir = tmp;
}
}
dirp -= namlen;
memcpy (dirp, d->d_name, namlen);
*--dirp = '/';
thisdev = dotdev;
thisino = dotino;
}
if (dirstream && __closedir (dirstream) != 0)
{
dirstream = NULL;
goto lose;
}
if (dirp == &dir[allocated - 1])
*--dirp = '/';
#if ! HAVE_OPENAT_SUPPORT
if (dotlist != dots)
free (dotlist);
#endif
used = dir + allocated - dirp;
memmove (dir, dirp, used);
if (size == 0)
/* Ensure that the buffer is only as large as necessary. */
buf = realloc (dir, used);
if (buf == NULL)
/* Either buf was NULL all along, or `realloc' failed but
we still have the original string. */
buf = dir;
return buf;
memory_exhausted:
__set_errno (ENOMEM);
lose:
{
int save = errno;
if (dirstream)
__closedir (dirstream);
#if HAVE_OPENAT_SUPPORT
if (fd_needs_closing)
close (fd);
#else
if (dotlist != dots)
free (dotlist);
#endif
if (buf == NULL)
free (dir);
__set_errno (save);
}
return NULL;
}
|
|||||
| ↓ | rijndaelDecrypt | 55 | 29 | 90 | lib/rijndael-alg-fst.c |
void
rijndaelDecrypt (const uint32_t rk[ /*4*(Nr + 1) */ ], size_t Nr,
const char ct[16], char pt[16])
{
uint32_t s0, s1, s2, s3, t0, t1, t2, t3;
size_t r;
/*
* map byte array block to cipher state
* and add initial round key:
*/
s0 = GETU32 (ct) ^ rk[0];
s1 = GETU32 (ct + 4) ^ rk[1];
s2 = GETU32 (ct + 8) ^ rk[2];
s3 = GETU32 (ct + 12) ^ rk[3];
/*
* Nr - 1 full rounds:
*/
r = Nr >> 1;
for (;;)
{
t0 =
Td0[(s0 >> 24)] ^
Td1[(s3 >> 16) & 0xff] ^
Td2[(s2 >> 8) & 0xff] ^ Td3[(s1) & 0xff] ^ rk[4];
t1 =
Td0[(s1 >> 24)] ^
Td1[(s0 >> 16) & 0xff] ^
Td2[(s3 >> 8) & 0xff] ^ Td3[(s2) & 0xff] ^ rk[5];
t2 =
Td0[(s2 >> 24)] ^
Td1[(s1 >> 16) & 0xff] ^
Td2[(s0 >> 8) & 0xff] ^ Td3[(s3) & 0xff] ^ rk[6];
t3 =
Td0[(s3 >> 24)] ^
Td1[(s2 >> 16) & 0xff] ^
Td2[(s1 >> 8) & 0xff] ^ Td3[(s0) & 0xff] ^ rk[7];
rk += 8;
if (--r == 0)
{
break;
}
s0 =
Td0[(t0 >> 24)] ^
Td1[(t3 >> 16) & 0xff] ^
Td2[(t2 >> 8) & 0xff] ^ Td3[(t1) & 0xff] ^ rk[0];
s1 =
Td0[(t1 >> 24)] ^
Td1[(t0 >> 16) & 0xff] ^
Td2[(t3 >> 8) & 0xff] ^ Td3[(t2) & 0xff] ^ rk[1];
s2 =
Td0[(t2 >> 24)] ^
Td1[(t1 >> 16) & 0xff] ^
Td2[(t0 >> 8) & 0xff] ^ Td3[(t3) & 0xff] ^ rk[2];
s3 =
Td0[(t3 >> 24)] ^
Td1[(t2 >> 16) & 0xff] ^
Td2[(t1 >> 8) & 0xff] ^ Td3[(t0) & 0xff] ^ rk[3];
}
/*
* apply last round and
* map cipher state to byte array block:
*/
s0 =
(Td4[(t0 >> 24)] & 0xff000000) ^
(Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
(Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
(Td4[(t1) & 0xff] & 0x000000ff) ^ rk[0];
PUTU32 (pt, s0);
s1 =
(Td4[(t1 >> 24)] & 0xff000000) ^
(Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
(Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
(Td4[(t2) & 0xff] & 0x000000ff) ^ rk[1];
PUTU32 (pt + 4, s1);
s2 =
(Td4[(t2 >> 24)] & 0xff000000) ^
(Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
(Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
(Td4[(t3) & 0xff] & 0x000000ff) ^ rk[2];
PUTU32 (pt + 8, s2);
s3 =
(Td4[(t3 >> 24)] & 0xff000000) ^
(Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
(Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
(Td4[(t0) & 0xff] & 0x000000ff) ^ rk[3];
PUTU32 (pt + 12, s3);
}
|
|||||
| ↓ | rijndaelEncrypt | 55 | 29 | 90 | lib/rijndael-alg-fst.c |
void
rijndaelEncrypt (const uint32_t rk[ /*4*(Nr + 1) */ ], size_t Nr,
const char pt[16], char ct[16])
{
uint32_t s0, s1, s2, s3, t0, t1, t2, t3;
size_t r;
/*
* map byte array block to cipher state
* and add initial round key:
*/
s0 = GETU32 (pt) ^ rk[0];
s1 = GETU32 (pt + 4) ^ rk[1];
s2 = GETU32 (pt + 8) ^ rk[2];
s3 = GETU32 (pt + 12) ^ rk[3];
/*
* Nr - 1 full rounds:
*/
r = Nr >> 1;
for (;;)
{
t0 =
Te0[(s0 >> 24)] ^
Te1[(s1 >> 16) & 0xff] ^
Te2[(s2 >> 8) & 0xff] ^ Te3[(s3) & 0xff] ^ rk[4];
t1 =
Te0[(s1 >> 24)] ^
Te1[(s2 >> 16) & 0xff] ^
Te2[(s3 >> 8) & 0xff] ^ Te3[(s0) & 0xff] ^ rk[5];
t2 =
Te0[(s2 >> 24)] ^
Te1[(s3 >> 16) & 0xff] ^
Te2[(s0 >> 8) & 0xff] ^ Te3[(s1) & 0xff] ^ rk[6];
t3 =
Te0[(s3 >> 24)] ^
Te1[(s0 >> 16) & 0xff] ^
Te2[(s1 >> 8) & 0xff] ^ Te3[(s2) & 0xff] ^ rk[7];
rk += 8;
if (--r == 0)
{
break;
}
s0 =
Te0[(t0 >> 24)] ^
Te1[(t1 >> 16) & 0xff] ^
Te2[(t2 >> 8) & 0xff] ^ Te3[(t3) & 0xff] ^ rk[0];
s1 =
Te0[(t1 >> 24)] ^
Te1[(t2 >> 16) & 0xff] ^
Te2[(t3 >> 8) & 0xff] ^ Te3[(t0) & 0xff] ^ rk[1];
s2 =
Te0[(t2 >> 24)] ^
Te1[(t3 >> 16) & 0xff] ^
Te2[(t0 >> 8) & 0xff] ^ Te3[(t1) & 0xff] ^ rk[2];
s3 =
Te0[(t3 >> 24)] ^
Te1[(t0 >> 16) & 0xff] ^
Te2[(t1 >> 8) & 0xff] ^ Te3[(t2) & 0xff] ^ rk[3];
}
/*
* apply last round and
* map cipher state to byte array block:
*/
s0 =
(Te4[(t0 >> 24)] & 0xff000000) ^
(Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
(Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
(Te4[(t3) & 0xff] & 0x000000ff) ^ rk[0];
PUTU32 (ct, s0);
s1 =
(Te4[(t1 >> 24)] & 0xff000000) ^
(Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
(Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
(Te4[(t0) & 0xff] & 0x000000ff) ^ rk[1];
PUTU32 (ct + 4, s1);
s2 =
(Te4[(t2 >> 24)] & 0xff000000) ^
(Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
(Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
(Te4[(t1) & 0xff] & 0x000000ff) ^ rk[2];
PUTU32 (ct + 8, s2);
s3 =
(Te4[(t3 >> 24)] & 0xff000000) ^
(Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
(Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
(Te4[(t2) & 0xff] & 0x000000ff) ^ rk[3];
PUTU32 (ct + 12, s3);
}
|
|||||
| peek_token | 1 | 0 | 124 | lib/regcomp.c | |
| ↓ | divide | 54 | 202 | 395 | lib/vasnprintf.c |
static void *
divide (mpn_t a, mpn_t b, mpn_t *q)
{
/* Algorithm:
First normalise a and b: a=[a[m-1],...,a[0]], b=[b[n-1],...,b[0]]
with m>=0 and n>0 (in base beta = 2^GMP_LIMB_BITS).
If m
|
|||||
| ↓ | wait_subprocess | 54 | 83 | 170 | lib/wait-process.c |
int
wait_subprocess (pid_t child, const char *progname,
bool ignore_sigpipe, bool null_stderr,
bool slave_process, bool exit_on_error,
int *termsigp)
{
#if HAVE_WAITID && defined WNOWAIT && 0
/* Commented out because waitid() without WEXITED and with WNOWAIT doesn't
work: On Solaris 7 and OSF/1 4.0, it returns -1 and sets errno = ECHILD,
and on HP-UX 10.20 it just hangs. */
/* Use of waitid() with WNOWAIT avoids a race condition: If slave_process is
true, and this process sleeps a very long time between the return from
waitpid() and the execution of unregister_slave_subprocess(), and
meanwhile another process acquires the same PID as child, and then - still
before unregister_slave_subprocess() - this process gets a fatal signal,
it would kill the other totally unrelated process. */
siginfo_t info;
if (termsigp != NULL)
*termsigp = 0;
for (;;)
{
if (waitid (P_PID, child, &info, WEXITED | (slave_process ? WNOWAIT : 0))
< 0)
{
# ifdef EINTR
if (errno == EINTR)
continue;
# endif
if (exit_on_error || !null_stderr)
error (exit_on_error ? EXIT_FAILURE : 0, errno,
_("%s subprocess"), progname);
return 127;
}
/* info.si_code is set to one of CLD_EXITED, CLD_KILLED, CLD_DUMPED,
CLD_TRAPPED, CLD_STOPPED, CLD_CONTINUED. Loop until the program
terminates. */
if (info.si_code == CLD_EXITED
|| info.si_code == CLD_KILLED || info.si_code == CLD_DUMPED)
break;
}
/* The child process has exited or was signalled. */
if (slave_process)
{
/* Unregister the child from the list of slave subprocesses, so that
later, when we exit, we don't kill a totally unrelated process which
may have acquired the same pid. */
unregister_slave_subprocess (child);
/* Now remove the zombie from the process list. */
for (;;)
{
if (waitid (P_PID, child, &info, WEXITED) < 0)
{
# ifdef EINTR
if (errno == EINTR)
continue;
# endif
if (exit_on_error || !null_stderr)
error (exit_on_error ? EXIT_FAILURE : 0, errno,
_("%s subprocess"), progname);
return 127;
}
break;
}
}
switch (info.si_code)
{
case CLD_KILLED:
case CLD_DUMPED:
if (termsigp != NULL)
*termsigp = info.si_status; /* TODO: or info.si_signo? */
# ifdef SIGPIPE
if (info.si_status == SIGPIPE && ignore_sigpipe)
return 0;
# endif
if (exit_on_error || !null_stderr)
error (exit_on_error ? EXIT_FAILURE : 0, 0,
_("%s subprocess got fatal signal %d"),
progname, info.si_status);
return 127;
case CLD_EXITED:
if (info.si_status == 127)
{
if (exit_on_error || !null_stderr)
error (exit_on_error ? EXIT_FAILURE : 0, 0,
_("%s subprocess failed"), progname);
return 127;
}
return info.si_status;
default:
abort ();
}
#else
/* waitpid() is just as portable as wait() nowadays. */
WAIT_T status;
if (termsigp != NULL)
*termsigp = 0;
*(int *) &status = 0;
for (;;)
{
int result = waitpid (child, &status, 0);
if (result != child)
{
# ifdef EINTR
if (errno == EINTR)
continue;
# endif
# if 0 /* defined ECHILD */
if (errno == ECHILD)
{
/* Child process nonexistent?! Assume it terminated
successfully. */
*(int *) &status = 0;
break;
}
# endif
if (exit_on_error || !null_stderr)
error (exit_on_error ? EXIT_FAILURE : 0, errno,
_("%s subprocess"), progname);
return 127;
}
/* One of WIFSIGNALED (status), WIFEXITED (status), WIFSTOPPED (status)
must always be true, since we did not specify WCONTINUED in the
waitpid() call. Loop until the program terminates. */
if (!WIFSTOPPED (status))
break;
}
/* The child process has exited or was signalled. */
if (slave_process)
/* Unregister the child from the list of slave subprocesses, so that
later, when we exit, we don't kill a totally unrelated process which
may have acquired the same pid. */
unregister_slave_subprocess (child);
if (WIFSIGNALED (status))
{
if (termsigp != NULL)
*termsigp = WTERMSIG (status);
# ifdef SIGPIPE
if (WTERMSIG (status) == SIGPIPE && ignore_sigpipe)
return 0;
# endif
if (exit_on_error || !null_stderr)
error (exit_on_error ? EXIT_FAILURE : 0, 0,
_("%s subprocess got fatal signal %d"),
progname, (int) WTERMSIG (status));
return 127;
}
if (!WIFEXITED (status))
abort ();
if (WEXITSTATUS (status) == 127)
{
if (exit_on_error || !null_stderr)
error (exit_on_error ? EXIT_FAILURE : 0, 0,
_("%s subprocess failed"), progname);
return 127;
}
return WEXITSTATUS (status);
#endif
}
|
|||||
| ↓ | human_readable | 51 | 130 | 237 | lib/human.c |
char *
human_readable (uintmax_t n, char *buf, int opts,
uintmax_t from_block_size, uintmax_t to_block_size)
{
int inexact_style =
opts & (human_round_to_nearest | human_floor | human_ceiling);
unsigned int base = opts & human_base_1024 ? 1024 : 1000;
uintmax_t amt;
int tenths;
int exponent = -1;
int exponent_max = sizeof power_letter - 1;
char *p;
char *psuffix;
char const *integerlim;
/* 0 means adjusted N == AMT.TENTHS;
1 means AMT.TENTHS < adjusted N < AMT.TENTHS + 0.05;
2 means adjusted N == AMT.TENTHS + 0.05;
3 means AMT.TENTHS + 0.05 < adjusted N < AMT.TENTHS + 0.1. */
int rounding;
char const *decimal_point = ".";
size_t decimal_pointlen = 1;
char const *grouping = "";
char const *thousands_sep = "";
struct lconv const *l = localeconv ();
size_t pointlen = strlen (l->decimal_point);
if (0 < pointlen && pointlen <= MB_LEN_MAX)
{
decimal_point = l->decimal_point;
decimal_pointlen = pointlen;
}
grouping = l->grouping;
if (strlen (l->thousands_sep) <= MB_LEN_MAX)
thousands_sep = l->thousands_sep;
psuffix = buf + LONGEST_HUMAN_READABLE - HUMAN_READABLE_SUFFIX_LENGTH_MAX;
p = psuffix;
/* Adjust AMT out of FROM_BLOCK_SIZE units and into TO_BLOCK_SIZE
units. If this can be done exactly with integer arithmetic, do
not use floating point operations. */
if (to_block_size <= from_block_size)
{
if (from_block_size % to_block_size == 0)
{
uintmax_t multiplier = from_block_size / to_block_size;
amt = n * multiplier;
if (amt / multiplier == n)
{
tenths = 0;
rounding = 0;
goto use_integer_arithmetic;
}
}
}
else if (from_block_size != 0 && to_block_size % from_block_size == 0)
{
uintmax_t divisor = to_block_size / from_block_size;
uintmax_t r10 = (n % divisor) * 10;
uintmax_t r2 = (r10 % divisor) * 2;
amt = n / divisor;
tenths = r10 / divisor;
rounding = r2 < divisor ? 0 < r2 : 2 + (divisor < r2);
goto use_integer_arithmetic;
}
{
/* Either the result cannot be computed easily using uintmax_t,
or from_block_size is zero. Fall back on floating point.
FIXME: This can yield answers that are slightly off. */
long double dto_block_size = to_block_size;
long double damt = n * (from_block_size / dto_block_size);
size_t buflen;
size_t nonintegerlen;
if (! (opts & human_autoscale))
{
sprintf (buf, "%.0Lf", adjust_value (inexact_style, damt));
buflen = strlen (buf);
nonintegerlen = 0;
}
else
{
long double e = 1;
exponent = 0;
do
{
e *= base;
exponent++;
}
while (e * base <= damt && exponent < exponent_max);
damt /= e;
sprintf (buf, "%.1Lf", adjust_value (inexact_style, damt));
buflen = strlen (buf);
nonintegerlen = decimal_pointlen + 1;
if (1 + nonintegerlen + ! (opts & human_base_1024) < buflen
|| ((opts & human_suppress_point_zero)
&& buf[buflen - 1] == '0'))
{
sprintf (buf, "%.0Lf",
adjust_value (inexact_style, damt * 10) / 10);
buflen = strlen (buf);
nonintegerlen = 0;
}
}
p = psuffix - buflen;
memmove (p, buf, buflen);
integerlim = p + buflen - nonintegerlen;
}
goto do_grouping;
use_integer_arithmetic:
{
/* The computation can be done exactly, with integer arithmetic.
Use power of BASE notation if requested and if adjusted AMT is
large enough. */
if (opts & human_autoscale)
{
exponent = 0;
if (base <= amt)
{
do
{
unsigned int r10 = (amt % base) * 10 + tenths;
unsigned int r2 = (r10 % base) * 2 + (rounding >> 1);
amt /= base;
tenths = r10 / base;
rounding = (r2 < base
? (r2 + rounding) != 0
: 2 + (base < r2 + rounding));
exponent++;
}
while (base <= amt && exponent < exponent_max);
if (amt < 10)
{
if (inexact_style == human_round_to_nearest
? 2 < rounding + (tenths & 1)
: inexact_style == human_ceiling && 0 < rounding)
{
tenths++;
rounding = 0;
if (tenths == 10)
{
amt++;
tenths = 0;
}
}
if (amt < 10
&& (tenths || ! (opts & human_suppress_point_zero)))
{
*--p = '0' + tenths;
p -= decimal_pointlen;
memcpy (p, decimal_point, decimal_pointlen);
tenths = rounding = 0;
}
}
}
}
if (inexact_style == human_round_to_nearest
? 5 < tenths + (0 < rounding + (amt & 1))
: inexact_style == human_ceiling && 0 < tenths + rounding)
{
amt++;
if ((opts & human_autoscale)
&& amt == base && exponent < exponent_max)
{
exponent++;
if (! (opts & human_suppress_point_zero))
{
*--p = '0';
p -= decimal_pointlen;
memcpy (p, decimal_point, decimal_pointlen);
}
amt = 1;
}
}
integerlim = p;
do
{
int digit = amt % 10;
*--p = digit + '0';
}
while ((amt /= 10) != 0);
}
do_grouping:
if (opts & human_group_digits)
p = group_number (p, integerlim - p, grouping, thousands_sep);
if (opts & human_SI)
{
if (exponent < 0)
{
uintmax_t power;
exponent = 0;
for (power = 1; power < to_block_size; power *= base)
if (++exponent == exponent_max)
break;
}
if ((exponent | (opts & human_B)) && (opts & human_space_before_unit))
*psuffix++ = ' ';
if (exponent)
*psuffix++ = (! (opts & human_base_1024) && exponent == 1
? 'k'
: power_letter[exponent]);
if (opts & human_B)
{
if ((opts & human_base_1024) && exponent)
*psuffix++ = 'i';
*psuffix++ = 'B';
}
}
*psuffix = '\0';
return p;
}
|
|||||
| ↓ | EXT | 54 | 77 | 181 | lib/fnmatch_loop.c |
|
|
|||||
| ↓ | poll | 50 | 157 | 286 | lib/poll.c |
int
poll (pfd, nfd, timeout)
struct pollfd *pfd;
nfds_t nfd;
int timeout;
{
#ifndef WIN32_NATIVE
fd_set rfds, wfds, efds;
struct timeval tv;
struct timeval *ptv;
int maxfd, rc;
nfds_t i;
#ifdef _SC_OPEN_MAX
static int sc_open_max = -1;
if (nfd < 0
|| (nfd > sc_open_max
&& (sc_open_max != -1
|| nfd > (sc_open_max = sysconf (_SC_OPEN_MAX)))))
{
errno = EINVAL;
return -1;
}
#else /* !_SC_OPEN_MAX */
#ifdef OPEN_MAX
if (nfd < 0 || nfd > OPEN_MAX)
{
errno = EINVAL;
return -1;
}
#endif /* OPEN_MAX -- else, no check is needed */
#endif /* !_SC_OPEN_MAX */
/* EFAULT is not necessary to implement, but let's do it in the
simplest case. */
if (!pfd)
{
errno = EFAULT;
return -1;
}
/* convert timeout number into a timeval structure */
if (timeout == 0)
{
ptv = &tv;
ptv->tv_sec = 0;
ptv->tv_usec = 0;
}
else if (timeout > 0)
{
ptv = &tv;
ptv->tv_sec = timeout / 1000;
ptv->tv_usec = (timeout % 1000) * 1000;
}
else if (timeout == INFTIM)
/* wait forever */
ptv = NULL;
else
{
errno = EINVAL;
return -1;
}
/* create fd sets and determine max fd */
maxfd = -1;
FD_ZERO (&rfds);
FD_ZERO (&wfds);
FD_ZERO (&efds);
for (i = 0; i < nfd; i++)
{
if (pfd[i].fd < 0)
continue;
if (pfd[i].events & (POLLIN | POLLRDNORM))
FD_SET (pfd[i].fd, &rfds);
/* see select(2): "the only exceptional condition detectable
is out-of-band data received on a socket", hence we push
POLLWRBAND events onto wfds instead of efds. */
if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
FD_SET (pfd[i].fd, &wfds);
if (pfd[i].events & (POLLPRI | POLLRDBAND))
FD_SET (pfd[i].fd, &efds);
if (pfd[i].fd >= maxfd
&& (pfd[i].events & (POLLIN | POLLOUT | POLLPRI
| POLLRDNORM | POLLRDBAND
| POLLWRNORM | POLLWRBAND)))
{
maxfd = pfd[i].fd;
if (maxfd > FD_SETSIZE)
{
errno = EOVERFLOW;
return -1;
}
}
}
/* examine fd sets */
rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
if (rc < 0)
return rc;
/* establish results */
rc = 0;
for (i = 0; i < nfd; i++)
if (pfd[i].fd < 0)
pfd[i].revents = 0;
else
{
int happened = compute_revents (pfd[i].fd, pfd[i].events,
&rfds, &wfds, &efds);
if (happened)
{
pfd[i].revents = happened;
rc++;
}
}
return rc;
#else
static struct timeval tv0;
static HANDLE hEvent;
WSANETWORKEVENTS ev;
HANDLE h, handle_array[FD_SETSIZE + 2];
DWORD ret, wait_timeout, nhandles;
fd_set rfds, wfds, xfds;
BOOL poll_again;
MSG msg;
char sockbuf[256];
int rc;
nfds_t i;
if (nfd < 0 || timeout < -1)
{
errno = EINVAL;
return -1;
}
if (!hEvent)
hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
handle_array[0] = hEvent;
nhandles = 1;
FD_ZERO (&rfds);
FD_ZERO (&wfds);
FD_ZERO (&xfds);
/* Classify socket handles and create fd sets. */
for (i = 0; i < nfd; i++)
{
size_t optlen = sizeof(sockbuf);
pfd[i].revents = 0;
if (pfd[i].fd < 0)
continue;
if (!(pfd[i].events & (POLLIN | POLLRDNORM |
POLLOUT | POLLWRNORM | POLLWRBAND)))
continue;
h = (HANDLE) _get_osfhandle (pfd[i].fd);
assert (h != NULL);
/* Under Wine, it seems that getsockopt returns 0 for pipes too.
WSAEnumNetworkEvents instead distinguishes the two correctly. */
ev.lNetworkEvents = 0xDEADBEEF;
WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
if (ev.lNetworkEvents != 0xDEADBEEF)
{
int requested = FD_CLOSE;
/* see above; socket handles are mapped onto select. */
if (pfd[i].events & (POLLIN | POLLRDNORM))
{
requested |= FD_READ | FD_ACCEPT;
FD_SET ((SOCKET) h, &rfds);
}
if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
{
requested |= FD_WRITE | FD_CONNECT;
FD_SET ((SOCKET) h, &wfds);
}
if (pfd[i].events & (POLLPRI | POLLRDBAND))
{
requested |= FD_OOB;
FD_SET ((SOCKET) h, &xfds);
}
if (requested)
WSAEventSelect ((SOCKET) h, hEvent, requested);
}
else
{
handle_array[nhandles++] = h;
/* Poll now. If we get an event, do not poll again. */
pfd[i].revents = win32_compute_revents (h, pfd[i].events);
if (pfd[i].revents)
wait_timeout = 0;
}
}
if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)
{
/* Do MsgWaitForMultipleObjects anyway to dispatch messages, but
no need to call select again. */
poll_again = FALSE;
wait_timeout = 0;
}
else
{
poll_again = TRUE;
if (timeout == INFTIM)
wait_timeout = INFINITE;
else
wait_timeout = timeout;
}
for (;;)
{
ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
wait_timeout, QS_ALLINPUT);
if (ret == WAIT_OBJECT_0 + nhandles)
{
/* new input of some other kind */
BOOL bRet;
while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
}
else
break;
}
if (poll_again)
select (0, &rfds, &wfds, &xfds, &tv0);
/* Place a sentinel at the end of the array. */
handle_array[nhandles] = NULL;
nhandles = 1;
for (i = 0; i < nfd; i++)
{
int happened;
if (pfd[i].fd < 0)
continue;
if (!(pfd[i].events & (POLLIN | POLLRDNORM |
POLLOUT | POLLWRNORM | POLLWRBAND)))
continue;
h = (HANDLE) _get_osfhandle (pfd[i].fd);
if (h != handle_array[nhandles])
{
/* It's a socket. */
WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
WSAEventSelect ((SOCKET) h, 0, 0);
/* If we're lucky, WSAEnumNetworkEvents already provided a way
to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */
if (FD_ISSET ((SOCKET) h, &rfds)
&& !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))
ev.lNetworkEvents |= FD_READ | FD_ACCEPT;
if (FD_ISSET ((SOCKET) h, &wfds))
ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;
if (FD_ISSET ((SOCKET) h, &xfds))
ev.lNetworkEvents |= FD_OOB;
happened = win32_compute_revents_socket ((SOCKET) h, pfd[i].events,
ev.lNetworkEvents);
}
else
{
/* Not a socket. */
nhandles++;
happened = win32_compute_revents (h, pfd[i].events);
}
if ((pfd[i].revents |= happened) != 0)
rc++;
}
return rc;
#endif
}
|
|||||
| ↓ | fts_read | 49 | 119 | 224 | lib/fts.c |
FTSENT *
fts_read (register FTS *sp)
{
register FTSENT *p, *tmp;
register unsigned short int instr;
register char *t;
/* If finished or unrecoverable error, return NULL. */
if (sp->fts_cur == NULL || ISSET(FTS_STOP))
return (NULL);
/* Set current node pointer. */
p = sp->fts_cur;
/* Save and zero out user instructions. */
instr = p->fts_instr;
p->fts_instr = FTS_NOINSTR;
/* Any type of file may be re-visited; re-stat and re-turn. */
if (instr == FTS_AGAIN) {
p->fts_info = fts_stat(sp, p, false);
return (p);
}
Dprintf (("fts_read: p=%s\n",
p->fts_info == FTS_INIT ? "" : p->fts_path));
/*
* Following a symlink -- SLNONE test allows application to see
* SLNONE and recover. If indirecting through a symlink, have
* keep a pointer to current location. If unable to get that
* pointer, follow fails.
*/
if (instr == FTS_FOLLOW &&
(p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
p->fts_info = fts_stat(sp, p, true);
if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
if ((p->fts_symfd = diropen (sp, ".")) < 0) {
p->fts_errno = errno;
p->fts_info = FTS_ERR;
} else
p->fts_flags |= FTS_SYMFOLLOW;
}
goto check_for_dir;
}
/* Directory in pre-order. */
if (p->fts_info == FTS_D) {
/* If skipped or crossed mount point, do post-order visit. */
if (instr == FTS_SKIP ||
(ISSET(FTS_XDEV) && p->fts_statp->st_dev != sp->fts_dev)) {
if (p->fts_flags & FTS_SYMFOLLOW)
(void)close(p->fts_symfd);
if (sp->fts_child) {
fts_lfree(sp->fts_child);
sp->fts_child = NULL;
}
p->fts_info = FTS_DP;
LEAVE_DIR (sp, p, "1");
return (p);
}
/* Rebuild if only read the names and now traversing. */
if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
CLR(FTS_NAMEONLY);
fts_lfree(sp->fts_child);
sp->fts_child = NULL;
}
/*
* Cd to the subdirectory.
*
* If have already read and now fail to chdir, whack the list
* to make the names come out right, and set the parent errno
* so the application will eventually get an error condition.
* Set the FTS_DONTCHDIR flag so that when we logically change
* directories back to the parent we don't do a chdir.
*
* If haven't read do so. If the read fails, fts_build sets
* FTS_STOP or the fts_info field of the node.
*/
if (sp->fts_child != NULL) {
if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
p->fts_errno = errno;
p->fts_flags |= FTS_DONTCHDIR;
for (p = sp->fts_child; p != NULL;
p = p->fts_link)
p->fts_accpath =
p->fts_parent->fts_accpath;
}
} else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
if (ISSET(FTS_STOP))
return (NULL);
/* If fts_build's call to fts_safe_changedir failed
because it was not able to fchdir into a
subdirectory, tell the caller. */
if (p->fts_errno && p->fts_info != FTS_DNR)
p->fts_info = FTS_ERR;
LEAVE_DIR (sp, p, "2");
return (p);
}
p = sp->fts_child;
sp->fts_child = NULL;
goto name;
}
/* Move to the next node on this level. */
next: tmp = p;
if ((p = p->fts_link) != NULL) {
sp->fts_cur = p;
free(tmp);
/*
* If reached the top, return to the original directory (or
* the root of the tree), and load the file names for the next
* root.
*/
if (p->fts_level == FTS_ROOTLEVEL) {
if (RESTORE_INITIAL_CWD(sp)) {
SET(FTS_STOP);
return (NULL);
}
fts_load(sp, p);
goto check_for_dir;
}
/*
* User may have called fts_set on the node. If skipped,
* ignore. If followed, get a file descriptor so we can
* get back if necessary.
*/
if (p->fts_instr == FTS_SKIP)
goto next;
if (p->fts_instr == FTS_FOLLOW) {
p->fts_info = fts_stat(sp, p, true);
if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
if ((p->fts_symfd = diropen (sp, ".")) < 0) {
p->fts_errno = errno;
p->fts_info = FTS_ERR;
} else
p->fts_flags |= FTS_SYMFOLLOW;
}
p->fts_instr = FTS_NOINSTR;
}
name: t = sp->fts_path + NAPPEND(p->fts_parent);
*t++ = '/';
memmove(t, p->fts_name, p->fts_namelen + 1);
check_for_dir:
sp->fts_cur = p;
if (p->fts_info == FTS_NSOK)
{
if (p->fts_statp->st_size == FTS_STAT_REQUIRED)
p->fts_info = fts_stat(sp, p, false);
else
fts_assert (p->fts_statp->st_size == FTS_NO_STAT_REQUIRED);
}
if (p->fts_info == FTS_D)
{
/* Now that P->fts_statp is guaranteed to be valid,
if this is a command-line directory, record its
device number, to be used for FTS_XDEV. */
if (p->fts_level == FTS_ROOTLEVEL)
sp->fts_dev = p->fts_statp->st_dev;
Dprintf ((" entering: %s\n", p->fts_path));
if (! enter_dir (sp, p))
{
__set_errno (ENOMEM);
return NULL;
}
}
return p;
}
/* Move up to the parent node. */
p = tmp->fts_parent;
sp->fts_cur = p;
free(tmp);
if (p->fts_level == FTS_ROOTPARENTLEVEL) {
/*
* Done; free everything up and set errno to 0 so the user
* can distinguish between error and EOF.
*/
free(p);
__set_errno (0);
return (sp->fts_cur = NULL);
}
fts_assert (p->fts_info != FTS_NSOK);
/* NUL terminate the file name. */
sp->fts_path[p->fts_pathlen] = '\0';
/*
* Return to the parent directory. If at a root node, restore
* the initial working directory. If we came through a symlink,
* go back through the file descriptor. Otherwise, move up
* one level, via "..".
*/
if (p->fts_level == FTS_ROOTLEVEL) {
if (RESTORE_INITIAL_CWD(sp)) {
p->fts_errno = errno;
SET(FTS_STOP);
}
} else if (p->fts_flags & FTS_SYMFOLLOW) {
if (FCHDIR(sp, p->fts_symfd)) {
int saved_errno = errno;
(void)close(p->fts_symfd);
__set_errno (saved_errno);
p->fts_errno = errno;
SET(FTS_STOP);
}
(void)close(p->fts_symfd);
} else if (!(p->fts_flags & FTS_DONTCHDIR) &&
fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
p->fts_errno = errno;
SET(FTS_STOP);
}
p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
if (p->fts_errno == 0)
LEAVE_DIR (sp, p, "3");
return ISSET(FTS_STOP) ? NULL : p;
}
|
|||||
| ↓ | INTERNAL | 48 | 95 | 184 | lib/strtol.c |
INT
INTERNAL (strtol) (const STRING_TYPE *nptr, STRING_TYPE **endptr,
int base, int group LOCALE_PARAM_PROTO)
{
int negative;
register unsigned LONG int cutoff;
register unsigned int cutlim;
register unsigned LONG int i;
register const STRING_TYPE *s;
register UCHAR_TYPE c;
const STRING_TYPE *save, *end;
int overflow;
#ifdef USE_NUMBER_GROUPING
# ifdef USE_IN_EXTENDED_LOCALE_MODEL
struct locale_data *current = loc->__locales[LC_NUMERIC];
# endif
/* The thousands character of the current locale. */
wchar_t thousands = L'\0';
/* The numeric grouping specification of the current locale,
in the format described in
|
|||||
| ↓ | build_trtable | 45 | 134 | 229 | lib/regexec.c |
static bool
internal_function
build_trtable (const re_dfa_t *dfa, re_dfastate_t *state)
{
reg_errcode_t err;
Idx i, j;
int ch;
bool need_word_trtable = false;
bitset_word_t elem, mask;
bool dests_node_malloced = false;
bool dest_states_malloced = false;
Idx ndests; /* Number of the destination states from `state'. */
re_dfastate_t **trtable;
re_dfastate_t **dest_states = NULL, **dest_states_word, **dest_states_nl;
re_node_set follows, *dests_node;
bitset_t *dests_ch;
bitset_t acceptable;
struct dests_alloc
{
re_node_set dests_node[SBC_MAX];
bitset_t dests_ch[SBC_MAX];
} *dests_alloc;
/* We build DFA states which corresponds to the destination nodes
from `state'. `dests_node[i]' represents the nodes which i-th
destination state contains, and `dests_ch[i]' represents the
characters which i-th destination state accepts. */
if (__libc_use_alloca (sizeof (struct dests_alloc)))
dests_alloc = (struct dests_alloc *) alloca (sizeof (struct dests_alloc));
else
{
dests_alloc = re_malloc (struct dests_alloc, 1);
if (BE (dests_alloc == NULL, 0))
return false;
dests_node_malloced = true;
}
dests_node = dests_alloc->dests_node;
dests_ch = dests_alloc->dests_ch;
/* Initialize transiton table. */
state->word_trtable = state->trtable = NULL;
/* At first, group all nodes belonging to `state' into several
destinations. */
ndests = group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch);
if (BE (! REG_VALID_NONZERO_INDEX (ndests), 0))
{
if (dests_node_malloced)
free (dests_alloc);
if (ndests == 0)
{
state->trtable = (re_dfastate_t **)
calloc (sizeof (re_dfastate_t *), SBC_MAX);
return true;
}
return false;
}
err = re_node_set_alloc (&follows, ndests + 1);
if (BE (err != REG_NOERROR, 0))
goto out_free;
/* Avoid arithmetic overflow in size calculation. */
if (BE ((((SIZE_MAX - (sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX)
/ (3 * sizeof (re_dfastate_t *)))
< ndests),
0))
goto out_free;
if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX
+ ndests * 3 * sizeof (re_dfastate_t *)))
dest_states = (re_dfastate_t **)
alloca (ndests * 3 * sizeof (re_dfastate_t *));
else
{
dest_states = (re_dfastate_t **)
malloc (ndests * 3 * sizeof (re_dfastate_t *));
if (BE (dest_states == NULL, 0))
{
out_free:
if (dest_states_malloced)
free (dest_states);
re_node_set_free (&follows);
for (i = 0; i < ndests; ++i)
re_node_set_free (dests_node + i);
if (dests_node_malloced)
free (dests_alloc);
return false;
}
dest_states_malloced = true;
}
dest_states_word = dest_states + ndests;
dest_states_nl = dest_states_word + ndests;
bitset_empty (acceptable);
/* Then build the states for all destinations. */
for (i = 0; i < ndests; ++i)
{
Idx next_node;
re_node_set_empty (&follows);
/* Merge the follows of this destination states. */
for (j = 0; j < dests_node[i].nelem; ++j)
{
next_node = dfa->nexts[dests_node[i].elems[j]];
if (next_node != REG_MISSING)
{
err = re_node_set_merge (&follows, dfa->eclosures + next_node);
if (BE (err != REG_NOERROR, 0))
goto out_free;
}
}
dest_states[i] = re_acquire_state_context (&err, dfa, &follows, 0);
if (BE (dest_states[i] == NULL && err != REG_NOERROR, 0))
goto out_free;
/* If the new state has context constraint,
build appropriate states for these contexts. */
if (dest_states[i]->has_constraint)
{
dest_states_word[i] = re_acquire_state_context (&err, dfa, &follows,
CONTEXT_WORD);
if (BE (dest_states_word[i] == NULL && err != REG_NOERROR, 0))
goto out_free;
if (dest_states[i] != dest_states_word[i] && dfa->mb_cur_max > 1)
need_word_trtable = true;
dest_states_nl[i] = re_acquire_state_context (&err, dfa, &follows,
CONTEXT_NEWLINE);
if (BE (dest_states_nl[i] == NULL && err != REG_NOERROR, 0))
goto out_free;
}
else
{
dest_states_word[i] = dest_states[i];
dest_states_nl[i] = dest_states[i];
}
bitset_merge (acceptable, dests_ch[i]);
}
if (!BE (need_word_trtable, 0))
{
/* We don't care about whether the following character is a word
character, or we are in a single-byte character set so we can
discern by looking at the character code: allocate a
256-entry transition table. */
trtable = state->trtable =
(re_dfastate_t **) calloc (sizeof (re_dfastate_t *), SBC_MAX);
if (BE (trtable == NULL, 0))
goto out_free;
/* For all characters ch...: */
for (i = 0; i < BITSET_WORDS; ++i)
for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1;
elem;
mask <<= 1, elem >>= 1, ++ch)
if (BE (elem & 1, 0))
{
/* There must be exactly one destination which accepts
character ch. See group_nodes_into_DFAstates. */
for (j = 0; (dests_ch[j][i] & mask) == 0; ++j)
;
/* j-th destination accepts the word character ch. */
if (dfa->word_char[i] & mask)
trtable[ch] = dest_states_word[j];
else
trtable[ch] = dest_states[j];
}
}
else
{
/* We care about whether the following character is a word
character, and we are in a multi-byte character set: discern
by looking at the character code: build two 256-entry
transition tables, one starting at trtable[0] and one
starting at trtable[SBC_MAX]. */
trtable = state->word_trtable =
(re_dfastate_t **) calloc (sizeof (re_dfastate_t *), 2 * SBC_MAX);
if (BE (trtable == NULL, 0))
goto out_free;
/* For all characters ch...: */
for (i = 0; i < BITSET_WORDS; ++i)
for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1;
elem;
mask <<= 1, elem >>= 1, ++ch)
if (BE (elem & 1, 0))
{
/* There must be exactly one destination which accepts
character ch. See group_nodes_into_DFAstates. */
for (j = 0; (dests_ch[j][i] & mask) == 0; ++j)
;
/* j-th destination accepts the word character ch. */
trtable[ch] = dest_states[j];
trtable[ch + SBC_MAX] = dest_states_word[j];
}
}
/* new line */
if (bitset_contain (acceptable, NEWLINE_CHAR))
{
/* The current state accepts newline character. */
for (j = 0; j < ndests; ++j)
if (bitset_contain (dests_ch[j], NEWLINE_CHAR))
{
/* k-th destination accepts newline character. */
trtable[NEWLINE_CHAR] = dest_states_nl[j];
if (need_word_trtable)
trtable[NEWLINE_CHAR + SBC_MAX] = dest_states_nl[j];
/* There must be only one destination which accepts
newline. See group_nodes_into_DFAstates. */
break;
}
}
if (dest_states_malloced)
free (dest_states);
re_node_set_free (&follows);
for (i = 0; i < ndests; ++i)
re_node_set_free (dests_node + i);
if (dests_node_malloced)
free (dests_alloc);
return true;
}
|
|||||
| ↓ | glob_in_dir | 45 | 130 | 254 | lib/glob.c |
static int
glob_in_dir (const char *pattern, const char *directory, int flags,
int (*errfunc) (const char *, int),
glob_t *pglob)
{
size_t dirlen = strlen (directory);
void *stream = NULL;
struct globnames
{
struct globnames *next;
size_t count;
char *name[64];
};
#define INITIAL_COUNT sizeof (init_names.name) / sizeof (init_names.name[0])
struct globnames init_names;
struct globnames *names = &init_names;
struct globnames *names_alloca = &init_names;
size_t nfound = 0;
size_t allocasize = sizeof (init_names);
size_t cur = 0;
int meta;
int save;
int result;
init_names.next = NULL;
init_names.count = INITIAL_COUNT;
meta = __glob_pattern_type (pattern, !(flags & GLOB_NOESCAPE));
if (meta == 0 && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
{
/* We need not do any tests. The PATTERN contains no meta
characters and we must not return an error therefore the
result will always contain exactly one name. */
flags |= GLOB_NOCHECK;
}
else if (meta == 0)
{
/* Since we use the normal file functions we can also use stat()
to verify the file is there. */
struct stat st;
struct_stat64 st64;
size_t patlen = strlen (pattern);
char *fullname = __alloca (dirlen + 1 + patlen + 1);
mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
"/", 1),
pattern, patlen + 1);
if ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
? (*pglob->gl_stat) (fullname, &st)
: __stat64 (fullname, &st64)) == 0)
/* We found this file to be existing. Now tell the rest
of the function to copy this name into the result. */
flags |= GLOB_NOCHECK;
}
else
{
stream = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
? (*pglob->gl_opendir) (directory)
: opendir (directory));
if (stream == NULL)
{
if (errno != ENOTDIR
&& ((errfunc != NULL && (*errfunc) (directory, errno))
|| (flags & GLOB_ERR)))
return GLOB_ABORTED;
}
else
{
int dfd = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
? -1 : dirfd ((DIR *) stream));
int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0)
| ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)
#if defined _AMIGA || defined VMS
| FNM_CASEFOLD
#endif
);
flags |= GLOB_MAGCHAR;
while (1)
{
const char *name;
size_t len;
#if defined _LIBC && !defined COMPILE_GLOB64
struct dirent64 *d;
union
{
struct dirent64 d64;
char room [offsetof (struct dirent64, d_name[0])
+ NAME_MAX + 1];
}
d64buf;
if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
{
struct dirent *d32 = (*pglob->gl_readdir) (stream);
if (d32 != NULL)
{
CONVERT_DIRENT_DIRENT64 (&d64buf.d64, d32);
d = &d64buf.d64;
}
else
d = NULL;
}
else
d = __readdir64 (stream);
#else
struct dirent *d = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
? ((struct dirent *)
(*pglob->gl_readdir) (stream))
: __readdir (stream));
#endif
if (d == NULL)
break;
if (! REAL_DIR_ENTRY (d))
continue;
/* If we shall match only directories use the information
provided by the dirent call if possible. */
if ((flags & GLOB_ONLYDIR) && !DIRENT_MIGHT_BE_DIR (d))
continue;
name = d->d_name;
if (fnmatch (pattern, name, fnm_flags) == 0)
{
/* If the file we found is a symlink we have to
make sure the target file exists. */
if (!DIRENT_MIGHT_BE_SYMLINK (d)
|| link_exists_p (dfd, directory, dirlen, name, pglob,
flags))
{
if (cur == names->count)
{
struct globnames *newnames;
size_t count = names->count * 2;
size_t size = (sizeof (struct globnames)
+ ((count - INITIAL_COUNT)
* sizeof (char *)));
allocasize += size;
if (__libc_use_alloca (allocasize))
newnames = names_alloca = __alloca (size);
else if ((newnames = malloc (size))
== NULL)
goto memory_error;
newnames->count = count;
newnames->next = names;
names = newnames;
cur = 0;
}
len = _D_EXACT_NAMLEN (d);
names->name[cur] = malloc (len + 1);
if (names->name[cur] == NULL)
goto memory_error;
*((char *) mempcpy (names->name[cur++], name, len))
= '\0';
++nfound;
}
}
}
}
}
if (nfound == 0 && (flags & GLOB_NOCHECK))
{
size_t len = strlen (pattern);
nfound = 1;
names->name[cur] = malloc (len + 1);
if (names->name[cur] == NULL)
goto memory_error;
*((char *) mempcpy (names->name[cur++], pattern, len)) = '\0';
}
result = GLOB_NOMATCH;
if (nfound != 0)
{
char **new_gl_pathv
= realloc (pglob->gl_pathv,
(pglob->gl_pathc + pglob->gl_offs + nfound + 1)
* sizeof (char *));
result = 0;
if (new_gl_pathv == NULL)
{
memory_error:
while (1)
{
struct globnames *old = names;
size_t i;
for (i = 0; i < cur; ++i)
free (names->name[i]);
names = names->next;
/* NB: we will not leak memory here if we exit without
freeing the current block assigned to OLD. At least
the very first block is always allocated on the stack
and this is the block assigned to OLD here. */
if (names == NULL)
{
assert (old == &init_names);
break;
}
cur = names->count;
if (old == names_alloca)
names_alloca = names;
else
free (old);
}
result = GLOB_NOSPACE;
}
else
{
while (1)
{
struct globnames *old = names;
size_t i;
for (i = 0; i < cur; ++i)
new_gl_pathv[pglob->gl_offs + pglob->gl_pathc++]
= names->name[i];
names = names->next;
/* NB: we will not leak memory here if we exit without
freeing the current block assigned to OLD. At least
the very first block is always allocated on the stack
and this is the block assigned to OLD here. */
if (names == NULL)
{
assert (old == &init_names);
break;
}
cur = names->count;
if (old == names_alloca)
names_alloca = names;
else
free (old);
}
pglob->gl_pathv = new_gl_pathv;
pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
pglob->gl_flags = flags;
}
}
if (stream != NULL)
{
save = errno;
if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
(*pglob->gl_closedir) (stream);
else
closedir (stream);
__set_errno (save);
}
return result;
}
|
|||||
| ↓ | parse_expression | 62 | 104 | 208 | lib/regcomp.c |
static bin_tree_t *
parse_expression (re_string_t *regexp, regex_t *preg, re_token_t *token,
reg_syntax_t syntax, Idx nest, reg_errcode_t *err)
{
re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
bin_tree_t *tree;
switch (token->type)
{
case CHARACTER:
tree = create_token_tree (dfa, NULL, NULL, token);
if (BE (tree == NULL, 0))
{
*err = REG_ESPACE;
return NULL;
}
#ifdef RE_ENABLE_I18N
if (dfa->mb_cur_max > 1)
{
while (!re_string_eoi (regexp)
&& !re_string_first_byte (regexp, re_string_cur_idx (regexp)))
{
bin_tree_t *mbc_remain;
fetch_token (token, regexp, syntax);
mbc_remain = create_token_tree (dfa, NULL, NULL, token);
tree = create_tree (dfa, tree, mbc_remain, CONCAT);
if (BE (mbc_remain == NULL || tree == NULL, 0))
{
*err = REG_ESPACE;
return NULL;
}
}
}
#endif
break;
case OP_OPEN_SUBEXP:
tree = parse_sub_exp (regexp, preg, token, syntax, nest + 1, err);
if (BE (*err != REG_NOERROR && tree == NULL, 0))
return NULL;
break;
case OP_OPEN_BRACKET:
tree = parse_bracket_exp (regexp, dfa, token, syntax, err);
if (BE (*err != REG_NOERROR && tree == NULL, 0))
return NULL;
break;
case OP_BACK_REF:
if (!BE (dfa->completed_bkref_map & (1 << token->opr.idx), 1))
{
*err = REG_ESUBREG;
return NULL;
}
dfa->used_bkref_map |= 1 << token->opr.idx;
tree = create_token_tree (dfa, NULL, NULL, token);
if (BE (tree == NULL, 0))
{
*err = REG_ESPACE;
return NULL;
}
++dfa->nbackref;
dfa->has_mb_node = 1;
break;
case OP_OPEN_DUP_NUM:
if (syntax & RE_CONTEXT_INVALID_DUP)
{
*err = REG_BADRPT;
return NULL;
}
/* FALLTHROUGH */
case OP_DUP_ASTERISK:
case OP_DUP_PLUS:
case OP_DUP_QUESTION:
if (syntax & RE_CONTEXT_INVALID_OPS)
{
*err = REG_BADRPT;
return NULL;
}
else if (syntax & RE_CONTEXT_INDEP_OPS)
{
fetch_token (token, regexp, syntax);
return parse_expression (regexp, preg, token, syntax, nest, err);
}
/* else fall through */
case OP_CLOSE_SUBEXP:
if ((token->type == OP_CLOSE_SUBEXP) &&
!(syntax & RE_UNMATCHED_RIGHT_PAREN_ORD))
{
*err = REG_ERPAREN;
return NULL;
}
/* else fall through */
case OP_CLOSE_DUP_NUM:
/* We treat it as a normal character. */
/* Then we can these characters as normal characters. */
token->type = CHARACTER;
/* mb_partial and word_char bits should be initialized already
by peek_token. */
tree = create_token_tree (dfa, NULL, NULL, token);
if (BE (tree == NULL, 0))
{
*err = REG_ESPACE;
return NULL;
}
break;
case ANCHOR:
if ((token->opr.ctx_type
& (WORD_DELIM | NOT_WORD_DELIM | WORD_FIRST | WORD_LAST))
&& dfa->word_ops_used == 0)
init_word_char (dfa);
if (token->opr.ctx_type == WORD_DELIM
|| token->opr.ctx_type == NOT_WORD_DELIM)
{
bin_tree_t *tree_first, *tree_last;
if (token->opr.ctx_type == WORD_DELIM)
{
token->opr.ctx_type = WORD_FIRST;
tree_first = create_token_tree (dfa, NULL, NULL, token);
token->opr.ctx_type = WORD_LAST;
}
else
{
token->opr.ctx_type = INSIDE_WORD;
tree_first = create_token_tree (dfa, NULL, NULL, token);
token->opr.ctx_type = INSIDE_NOTWORD;
}
tree_last = create_token_tree (dfa, NULL, NULL, token);
tree = create_tree (dfa, tree_first, tree_last, OP_ALT);
if (BE (tree_first == NULL || tree_last == NULL || tree == NULL, 0))
{
*err = REG_ESPACE;
return NULL;
}
}
else
{
tree = create_token_tree (dfa, NULL, NULL, token);
if (BE (tree == NULL, 0))
{
*err = REG_ESPACE;
return NULL;
}
}
/* We must return here, since ANCHORs can't be followed
by repetition operators.
eg. RE"^*" is invalid or "
|
|||||
| ↓ | __realpath | 44 | 128 | 231 | lib/canonicalize-lgpl.c |
char *
__realpath (const char *name, char *resolved)
{
char *rpath, *dest, *extra_buf = NULL;
const char *start, *end, *rpath_limit;
long int path_max;
#if HAVE_READLINK
int num_links = 0;
#endif
if (name == NULL)
{
/* As per Single Unix Specification V2 we must return an error if
either parameter is a null pointer. We extend this to allow
the RESOLVED parameter to be NULL in case the we are expected to
allocate the room for the return value. */
__set_errno (EINVAL);
return NULL;
}
if (name[0] == '\0')
{
/* As per Single Unix Specification V2 we must return an error if
the name argument points to an empty string. */
__set_errno (ENOENT);
return NULL;
}
#ifdef PATH_MAX
path_max = PATH_MAX;
#else
path_max = pathconf (name, _PC_PATH_MAX);
if (path_max <= 0)
path_max = 1024;
#endif
if (resolved == NULL)
{
rpath = malloc (path_max);
if (rpath == NULL)
{
/* It's easier to set errno to ENOMEM than to rely on the
'malloc-posix' gnulib module. */
errno = ENOMEM;
return NULL;
}
}
else
rpath = resolved;
rpath_limit = rpath + path_max;
if (name[0] != '/')
{
if (!__getcwd (rpath, path_max))
{
rpath[0] = '\0';
goto error;
}
dest = strchr (rpath, '\0');
}
else
{
rpath[0] = '/';
dest = rpath + 1;
}
for (start = end = name; *start; start = end)
{
#ifdef _LIBC
struct stat64 st;
#else
struct stat st;
#endif
/* Skip sequence of multiple path-separators. */
while (*start == '/')
++start;
/* Find end of path component. */
for (end = start; *end && *end != '/'; ++end)
/* Nothing. */;
if (end - start == 0)
break;
else if (end - start == 1 && start[0] == '.')
/* nothing */;
else if (end - start == 2 && start[0] == '.' && start[1] == '.')
{
/* Back up to previous component, ignore if at root already. */
if (dest > rpath + 1)
while ((--dest)[-1] != '/');
}
else
{
size_t new_size;
if (dest[-1] != '/')
*dest++ = '/';
if (dest + (end - start) >= rpath_limit)
{
ptrdiff_t dest_offset = dest - rpath;
char *new_rpath;
if (resolved)
{
__set_errno (ENAMETOOLONG);
if (dest > rpath + 1)
dest--;
*dest = '\0';
goto error;
}
new_size = rpath_limit - rpath;
if (end - start + 1 > path_max)
new_size += end - start + 1;
else
new_size += path_max;
new_rpath = (char *) realloc (rpath, new_size);
if (new_rpath == NULL)
{
/* It's easier to set errno to ENOMEM than to rely on the
'realloc-posix' gnulib module. */
errno = ENOMEM;
goto error;
}
rpath = new_rpath;
rpath_limit = rpath + new_size;
dest = rpath + dest_offset;
}
#ifdef _LIBC
dest = __mempcpy (dest, start, end - start);
#else
memcpy (dest, start, end - start);
dest += end - start;
#endif
*dest = '\0';
#ifdef _LIBC
if (__lxstat64 (_STAT_VER, rpath, &st) < 0)
#else
if (lstat (rpath, &st) < 0)
#endif
goto error;
#if HAVE_READLINK
if (S_ISLNK (st.st_mode))
{
char *buf;
size_t len;
int n;
if (++num_links > MAXSYMLINKS)
{
__set_errno (ELOOP);
goto error;
}
buf = malloca (path_max);
if (!buf)
{
errno = ENOMEM;
goto error;
}
n = __readlink (rpath, buf, path_max - 1);
if (n < 0)
{
int saved_errno = errno;
freea (buf);
errno = saved_errno;
goto error;
}
buf[n] = '\0';
if (!extra_buf)
{
extra_buf = malloca (path_max);
if (!extra_buf)
{
freea (buf);
errno = ENOMEM;
goto error;
}
}
len = strlen (end);
if ((long int) (n + len) >= path_max)
{
freea (buf);
__set_errno (ENAMETOOLONG);
goto error;
}
/* Careful here, end may be a pointer into extra_buf... */
memmove (&extra_buf[n], end, len + 1);
name = end = memcpy (extra_buf, buf, n);
if (buf[0] == '/')
dest = rpath + 1; /* It's an absolute symlink */
else
/* Back up to previous component, ignore if at root already: */
if (dest > rpath + 1)
while ((--dest)[-1] != '/');
}
#endif
}
}
if (dest > rpath + 1 && dest[-1] == '/')
--dest;
*dest = '\0';
if (extra_buf)
freea (extra_buf);
return resolved ? memcpy (resolved, rpath, dest - rpath + 1) : rpath;
error:
{
int saved_errno = errno;
if (extra_buf)
freea (extra_buf);
if (resolved)
strcpy (resolved, rpath);
else
free (rpath);
errno = saved_errno;
}
return NULL;
}
|
|||||
| ↓ | canonicalize_filename_mode | 44 | 110 | 184 | lib/canonicalize.c |
char *
canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode)
{
char *rname, *dest, *extra_buf = NULL;
char const *start;
char const *end;
char const *rname_limit;
size_t extra_len = 0;
Hash_table *ht = NULL;
if (name == NULL)
{
__set_errno (EINVAL);
return NULL;
}
if (name[0] == '\0')
{
__set_errno (ENOENT);
return NULL;
}
if (name[0] != '/')
{
rname = xgetcwd ();
if (!rname)
return NULL;
dest = strchr (rname, '\0');
if (dest - rname < PATH_MAX)
{
char *p = xrealloc (rname, PATH_MAX);
dest = p + (dest - rname);
rname = p;
rname_limit = rname + PATH_MAX;
}
else
{
rname_limit = dest;
}
}
else
{
rname = xmalloc (PATH_MAX);
rname_limit = rname + PATH_MAX;
rname[0] = '/';
dest = rname + 1;
}
for (start = end = name; *start; start = end)
{
/* Skip sequence of multiple file name separators. */
while (*start == '/')
++start;
/* Find end of component. */
for (end = start; *end && *end != '/'; ++end)
/* Nothing. */;
if (end - start == 0)
break;
else if (end - start == 1 && start[0] == '.')
/* nothing */;
else if (end - start == 2 && start[0] == '.' && start[1] == '.')
{
/* Back up to previous component, ignore if at root already. */
if (dest > rname + 1)
while ((--dest)[-1] != '/');
}
else
{
struct stat st;
if (dest[-1] != '/')
*dest++ = '/';
if (dest + (end - start) >= rname_limit)
{
ptrdiff_t dest_offset = dest - rname;
size_t new_size = rname_limit - rname;
if (end - start + 1 > PATH_MAX)
new_size += end - start + 1;
else
new_size += PATH_MAX;
rname = xrealloc (rname, new_size);
rname_limit = rname + new_size;
dest = rname + dest_offset;
}
dest = memcpy (dest, start, end - start);
dest += end - start;
*dest = '\0';
if (lstat (rname, &st) != 0)
{
if (can_mode == CAN_EXISTING)
goto error;
if (can_mode == CAN_ALL_BUT_LAST && *end)
goto error;
st.st_mode = 0;
}
if (S_ISLNK (st.st_mode))
{
char *buf;
size_t n, len;
/* Detect loops. We cannot use the cycle-check module here,
since it's actually possible to encounter the same symlink
more than once in a given traversal. However, encountering
the same symlink,NAME pair twice does indicate a loop. */
if (seen_triple (&ht, name, &st))
{
__set_errno (ELOOP);
if (can_mode == CAN_MISSING)
continue;
else
goto error;
}
buf = areadlink_with_size (rname, st.st_size);
if (!buf)
{
if (can_mode == CAN_MISSING && errno != ENOMEM)
continue;
else
goto error;
}
n = strlen (buf);
len = strlen (end);
if (!extra_len)
{
extra_len =
((n + len + 1) > PATH_MAX) ? (n + len + 1) : PATH_MAX;
extra_buf = xmalloc (extra_len);
}
else if ((n + len + 1) > extra_len)
{
extra_len = n + len + 1;
extra_buf = xrealloc (extra_buf, extra_len);
}
/* Careful here, end may be a pointer into extra_buf... */
memmove (&extra_buf[n], end, len + 1);
name = end = memcpy (extra_buf, buf, n);
if (buf[0] == '/')
dest = rname + 1; /* It's an absolute symlink */
else
/* Back up to previous component, ignore if at root already: */
if (dest > rname + 1)
while ((--dest)[-1] != '/');
free (buf);
}
else
{
if (!S_ISDIR (st.st_mode) && *end && (can_mode != CAN_MISSING))
{
errno = ENOTDIR;
goto error;
}
}
}
}
if (dest > rname + 1 && dest[-1] == '/')
--dest;
*dest = '\0';
free (extra_buf);
if (ht)
hash_free (ht);
return rname;
error:
free (extra_buf);
free (rname);
if (ht)
hash_free (ht);
return NULL;
}
|
|||||
| ↓ | rijndaelKeySetupEnc | 43 | 54 | 89 | lib/rijndael-alg-fst.c |
int
rijndaelKeySetupEnc (uint32_t rk[ /*4*(Nr + 1) */ ],
const char cipherKey[], size_t keyBits)
{
size_t i = 0;
uint32_t temp;
rk[0] = GETU32 (cipherKey);
rk[1] = GETU32 (cipherKey + 4);
rk[2] = GETU32 (cipherKey + 8);
rk[3] = GETU32 (cipherKey + 12);
if (keyBits == 128)
{
for (;;)
{
temp = rk[3];
rk[4] = rk[0] ^
(Te4[(temp >> 16) & 0xff] & 0xff000000) ^
(Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
(Te4[(temp) & 0xff] & 0x0000ff00) ^
(Te4[(temp >> 24)] & 0x000000ff) ^ rcon[i];
rk[5] = rk[1] ^ rk[4];
rk[6] = rk[2] ^ rk[5];
rk[7] = rk[3] ^ rk[6];
if (++i == 10)
{
return 10;
}
rk += 4;
}
}
rk[4] = GETU32 (cipherKey + 16);
rk[5] = GETU32 (cipherKey + 20);
if (keyBits == 192)
{
for (;;)
{
temp = rk[5];
rk[6] = rk[0] ^
(Te4[(temp >> 16) & 0xff] & 0xff000000) ^
(Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
(Te4[(temp) & 0xff] & 0x0000ff00) ^
(Te4[(temp >> 24)] & 0x000000ff) ^ rcon[i];
rk[7] = rk[1] ^ rk[6];
rk[8] = rk[2] ^ rk[7];
rk[9] = rk[3] ^ rk[8];
if (++i == 8)
{
return 12;
}
rk[10] = rk[4] ^ rk[9];
rk[11] = rk[5] ^ rk[10];
rk += 6;
}
}
rk[6] = GETU32 (cipherKey + 24);
rk[7] = GETU32 (cipherKey + 28);
if (keyBits == 256)
{
for (;;)
{
temp = rk[7];
rk[8] = rk[0] ^
(Te4[(temp >> 16) & 0xff] & 0xff000000) ^
(Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
(Te4[(temp) & 0xff] & 0x0000ff00) ^
(Te4[(temp >> 24)] & 0x000000ff) ^ rcon[i];
rk[9] = rk[1] ^ rk[8];
rk[10] = rk[2] ^ rk[9];
rk[11] = rk[3] ^ rk[10];
if (++i == 7)
{
return 14;
}
temp = rk[11];
rk[12] = rk[4] ^
(Te4[(temp >> 24)] & 0xff000000) ^
(Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^
(Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^
(Te4[(temp) & 0xff] & 0x000000ff);
rk[13] = rk[5] ^ rk[12];
rk[14] = rk[6] ^ rk[13];
rk[15] = rk[7] ^ rk[14];
rk += 8;
}
}
return 0;
}
|
|||||
| ↓ | group_nodes_into_DFAstates | 43 | 123 | 183 | lib/regexec.c |
static Idx
internal_function
group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *state,
re_node_set *dests_node, bitset_t *dests_ch)
{
reg_errcode_t err;
bool ok;
Idx i, j, k;
Idx ndests; /* Number of the destinations from `state'. */
bitset_t accepts; /* Characters a node can accept. */
const re_node_set *cur_nodes = &state->nodes;
bitset_empty (accepts);
ndests = 0;
/* For all the nodes belonging to `state', */
for (i = 0; i < cur_nodes->nelem; ++i)
{
re_token_t *node = &dfa->nodes[cur_nodes->elems[i]];
re_token_type_t type = node->type;
unsigned int constraint = node->constraint;
/* Enumerate all single byte character this node can accept. */
if (type == CHARACTER)
bitset_set (accepts, node->opr.c);
else if (type == SIMPLE_BRACKET)
{
bitset_merge (accepts, node->opr.sbcset);
}
else if (type == OP_PERIOD)
{
#ifdef RE_ENABLE_I18N
if (dfa->mb_cur_max > 1)
bitset_merge (accepts, dfa->sb_char);
else
#endif
bitset_set_all (accepts);
if (!(dfa->syntax & RE_DOT_NEWLINE))
bitset_clear (accepts, '\n');
if (dfa->syntax & RE_DOT_NOT_NULL)
bitset_clear (accepts, '\0');
}
#ifdef RE_ENABLE_I18N
else if (type == OP_UTF8_PERIOD)
{
if (ASCII_CHARS % BITSET_WORD_BITS == 0)
memset (accepts, -1, ASCII_CHARS / CHAR_BIT);
else
bitset_merge (accepts, utf8_sb_map);
if (!(dfa->syntax & RE_DOT_NEWLINE))
bitset_clear (accepts, '\n');
if (dfa->syntax & RE_DOT_NOT_NULL)
bitset_clear (accepts, '\0');
}
#endif
else
continue;
/* Check the `accepts' and sift the characters which are not
match it the context. */
if (constraint)
{
if (constraint & NEXT_NEWLINE_CONSTRAINT)
{
bool accepts_newline = bitset_contain (accepts, NEWLINE_CHAR);
bitset_empty (accepts);
if (accepts_newline)
bitset_set (accepts, NEWLINE_CHAR);
else
continue;
}
if (constraint & NEXT_ENDBUF_CONSTRAINT)
{
bitset_empty (accepts);
continue;
}
if (constraint & NEXT_WORD_CONSTRAINT)
{
bitset_word_t any_set = 0;
if (type == CHARACTER && !node->word_char)
{
bitset_empty (accepts);
continue;
}
#ifdef RE_ENABLE_I18N
if (dfa->mb_cur_max > 1)
for (j = 0; j < BITSET_WORDS; ++j)
any_set |= (accepts[j] &= (dfa->word_char[j] | ~dfa->sb_char[j]));
else
#endif
for (j = 0; j < BITSET_WORDS; ++j)
any_set |= (accepts[j] &= dfa->word_char[j]);
if (!any_set)
continue;
}
if (constraint & NEXT_NOTWORD_CONSTRAINT)
{
bitset_word_t any_set = 0;
if (type == CHARACTER && node->word_char)
{
bitset_empty (accepts);
continue;
}
#ifdef RE_ENABLE_I18N
if (dfa->mb_cur_max > 1)
for (j = 0; j < BITSET_WORDS; ++j)
any_set |= (accepts[j] &= ~(dfa->word_char[j] & dfa->sb_char[j]));
else
#endif
for (j = 0; j < BITSET_WORDS; ++j)
any_set |= (accepts[j] &= ~dfa->word_char[j]);
if (!any_set)
continue;
}
}
/* Then divide `accepts' into DFA states, or create a new
state. Above, we make sure that accepts is not empty. */
for (j = 0; j < ndests; ++j)
{
bitset_t intersec; /* Intersection sets, see below. */
bitset_t remains;
/* Flags, see below. */
bitset_word_t has_intersec, not_subset, not_consumed;
/* Optimization, skip if this state doesn't accept the character. */
if (type == CHARACTER && !bitset_contain (dests_ch[j], node->opr.c))
continue;
/* Enumerate the intersection set of this state and `accepts'. */
has_intersec = 0;
for (k = 0; k < BITSET_WORDS; ++k)
has_intersec |= intersec[k] = accepts[k] & dests_ch[j][k];
/* And skip if the intersection set is empty. */
if (!has_intersec)
continue;
/* Then check if this state is a subset of `accepts'. */
not_subset = not_consumed = 0;
for (k = 0; k < BITSET_WORDS; ++k)
{
not_subset |= remains[k] = ~accepts[k] & dests_ch[j][k];
not_consumed |= accepts[k] = accepts[k] & ~dests_ch[j][k];
}
/* If this state isn't a subset of `accepts', create a
new group state, which has the `remains'. */
if (not_subset)
{
bitset_copy (dests_ch[ndests], remains);
bitset_copy (dests_ch[j], intersec);
err = re_node_set_init_copy (dests_node + ndests, &dests_node[j]);
if (BE (err != REG_NOERROR, 0))
goto error_return;
++ndests;
}
/* Put the position in the current group. */
ok = re_node_set_insert (&dests_node[j], cur_nodes->elems[i]);
if (BE (! ok, 0))
goto error_return;
/* If all characters are consumed, go to next node. */
if (!not_consumed)
break;
}
/* Some characters remain, create a new group. */
if (j == ndests)
{
bitset_copy (dests_ch[ndests], accepts);
err = re_node_set_init_1 (dests_node + ndests, cur_nodes->elems[i]);
if (BE (err != REG_NOERROR, 0))
goto error_return;
++ndests;
bitset_empty (accepts);
}
}
return ndests;
error_return:
for (j = 0; j < ndests; ++j)
re_node_set_free (dests_node + j);
return REG_MISSING;
}
|
|||||
| ↓ | compile_java_class | 43 | 104 | 286 | lib/javacomp.c |
bool
compile_java_class (const char * const *java_sources,
unsigned int java_sources_count,
const char * const *classpaths,
unsigned int classpaths_count,
const char *source_version,
const char *target_version,
const char *directory,
bool optimize, bool debug,
bool use_minimal_classpath,
bool verbose)
{
bool err = false;
char *old_JAVA_HOME;
{
const char *javac = getenv ("JAVAC");
if (javac != NULL && javac[0] != '\0')
{
bool usable = false;
bool no_assert_option = false;
bool source_option = false;
bool target_option = false;
bool fsource_option = false;
bool ftarget_option = false;
if (target_version == NULL)
target_version = default_target_version ();
if (is_envjavac_gcj (javac))
{
/* It's a version of gcj. */
if (is_envjavac_gcj43 (javac))
{
/* It's a version of gcj >= 4.3. Assume the classfile versions
are correct. */
if (is_envjavac_gcj43_usable (javac,
source_version, target_version,
&usable,
&fsource_option, &ftarget_option))
{
err = true;
goto done1;
}
}
else
{
/* It's a version of gcj < 4.3. Ignore the version of the
class files that it creates. */
if (strcmp (target_version, "1.4") == 0
&& strcmp (source_version, "1.4") == 0)
{
if (is_envjavac_oldgcj_14_14_usable (javac, &usable))
{
err = true;
goto done1;
}
}
else if (strcmp (target_version, "1.4") == 0
&& strcmp (source_version, "1.3") == 0)
{
if (is_envjavac_oldgcj_14_13_usable (javac,
&usable,
&no_assert_option))
{
err = true;
goto done1;
}
}
}
}
else
{
/* It's not gcj. Assume the classfile versions are correct. */
if (is_envjavac_nongcj_usable (javac,
source_version, target_version,
&usable,
&source_option, &target_option))
{
err = true;
goto done1;
}
}
if (usable)
{
char *old_classpath;
char *javac_with_options;
/* Set CLASSPATH. */
old_classpath =
set_classpath (classpaths, classpaths_count, false, verbose);
javac_with_options =
(no_assert_option
? xasprintf ("%s -fno-assert", javac)
: xasprintf ("%s%s%s%s%s%s%s%s%s",
javac,
source_option ? " -source " : "",
source_option ? source_version : "",
target_option ? " -target " : "",
target_option ? target_version : "",
fsource_option ? " -fsource=" : "",
fsource_option ? source_version : "",
ftarget_option ? " -ftarget=" : "",
ftarget_option ? target_version : ""));
err = compile_using_envjavac (javac_with_options,
java_sources, java_sources_count,
directory, optimize, debug, verbose,
false);
free (javac_with_options);
/* Reset CLASSPATH. */
reset_classpath (old_classpath);
goto done1;
}
}
}
/* Unset the JAVA_HOME environment variable. */
old_JAVA_HOME = getenv ("JAVA_HOME");
if (old_JAVA_HOME != NULL)
{
old_JAVA_HOME = xstrdup (old_JAVA_HOME);
unsetenv ("JAVA_HOME");
}
if (is_gcj_present ())
{
/* It's a version of gcj. */
bool usable = false;
bool no_assert_option = false;
bool fsource_option = false;
bool ftarget_option = false;
if (target_version == NULL)
target_version = default_target_version ();
if (is_gcj_43 ())
{
/* It's a version of gcj >= 4.3. Assume the classfile versions
are correct. */
if (is_gcj43_usable (source_version, target_version,
&usable, &fsource_option, &ftarget_option))
{
err = true;
goto done1;
}
}
else
{
/* It's a version of gcj < 4.3. Ignore the version of the class
files that it creates.
Test whether it supports the desired target-version and
source-version. */
if (strcmp (target_version, "1.4") == 0
&& strcmp (source_version, "1.4") == 0)
{
if (is_oldgcj_14_14_usable (&usable))
{
err = true;
goto done1;
}
}
else if (strcmp (target_version, "1.4") == 0
&& strcmp (source_version, "1.3") == 0)
{
if (is_oldgcj_14_13_usable (&usable, &no_assert_option))
{
err = true;
goto done1;
}
}
}
if (usable)
{
char *old_classpath;
/* Set CLASSPATH. We could also use the --CLASSPATH=... option
of gcj. Note that --classpath=... option is different: its
argument should also contain gcj's libgcj.jar, but we don't
know its location. */
old_classpath =
set_classpath (classpaths, classpaths_count, use_minimal_classpath,
verbose);
err = compile_using_gcj (java_sources, java_sources_count,
no_assert_option,
fsource_option, source_version,
ftarget_option, target_version,
directory, optimize, debug, verbose, false);
/* Reset CLASSPATH. */
reset_classpath (old_classpath);
goto done2;
}
}
if (is_javac_present ())
{
bool usable = false;
bool source_option = false;
bool target_option = false;
if (target_version == NULL)
target_version = default_target_version ();
if (is_javac_usable (source_version, target_version,
&usable, &source_option, &target_option))
{
err = true;
goto done1;
}
if (usable)
{
char *old_classpath;
/* Set CLASSPATH. We don't use the "-classpath ..." option because
in JDK 1.1.x its argument should also contain the JDK's
classes.zip, but we don't know its location. (In JDK 1.3.0 it
would work.) */
old_classpath =
set_classpath (classpaths, classpaths_count, use_minimal_classpath,
verbose);
err = compile_using_javac (java_sources, java_sources_count,
source_option, source_version,
target_option, target_version,
directory, optimize, debug, verbose,
false);
/* Reset CLASSPATH. */
reset_classpath (old_classpath);
goto done2;
}
}
if (is_jikes_present ())
{
/* Test whether it supports the desired target-version and
source-version. */
bool usable = (strcmp (source_version, "1.3") == 0);
if (usable)
{
char *old_classpath;
/* Set CLASSPATH. We could also use the "-classpath ..." option.
Since jikes doesn't come with its own standard library, it
needs a classes.zip or rt.jar or libgcj.jar in the CLASSPATH.
To increase the chance of success, we reuse the current CLASSPATH
if the user has set it. */
old_classpath =
set_classpath (classpaths, classpaths_count, false, verbose);
err = compile_using_jikes (java_sources, java_sources_count,
directory, optimize, debug, verbose,
false);
/* Reset CLASSPATH. */
reset_classpath (old_classpath);
goto done2;
}
}
error (0, 0, _("Java compiler not found, try installing gcj or set $JAVAC"));
err = true;
done2:
if (old_JAVA_HOME != NULL)
{
xsetenv ("JAVA_HOME", old_JAVA_HOME, 1);
free (old_JAVA_HOME);
}
done1:
return err;
}
|
|||||
| ↓ | kernel_rem_pio2 | 46 | 163 | 212 | lib/trigl.c |
static int
kernel_rem_pio2 (double *x, double *y, int e0, int nx, int prec,
const int *ipio2)
{
int jz, jx, jv, jp, jk, carry, n, iq[20], i, j, k, m, q0, ih;
double z, fw, f[20], fq[20], q[20];
/* initialize jk */
jk = init_jk[prec];
jp = jk;
/* determine jx,jv,q0, note that 3>q0 */
jx = nx - 1;
jv = (e0 - 3) / 24;
if (jv < 0)
jv = 0;
q0 = e0 - 24 * (jv + 1);
/* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
j = jv - jx;
m = jx + jk;
for (i = 0; i <= m; i++, j++)
f[i] = (j < 0) ? zero : (double) ipio2[j];
/* compute q[0],q[1],...q[jk] */
for (i = 0; i <= jk; i++)
{
for (j = 0, fw = 0.0; j <= jx; j++)
fw += x[j] * f[jx + i - j];
q[i] = fw;
}
jz = jk;
recompute:
/* distill q[] into iq[] reversingly */
for (i = 0, j = jz, z = q[jz]; j > 0; i++, j--)
{
fw = (double) ((int) (twon24 * z));
iq[i] = (int) (z - two24 * fw);
z = q[j - 1] + fw;
}
/* compute n */
z = ldexp (z, q0); /* actual value of z */
z -= 8.0 * floor (z * 0.125); /* trim off integer >= 8 */
n = (int) z;
z -= (double) n;
ih = 0;
if (q0 > 0)
{ /* need iq[jz-1] to determine n */
i = (iq[jz - 1] >> (24 - q0));
n += i;
iq[jz - 1] -= i << (24 - q0);
ih = iq[jz - 1] >> (23 - q0);
}
else if (q0 == 0)
ih = iq[jz - 1] >> 23;
else if (z >= 0.5)
ih = 2;
if (ih > 0)
{ /* q > 0.5 */
n += 1;
carry = 0;
for (i = 0; i < jz; i++)
{ /* compute 1-q */
j = iq[i];
if (carry == 0)
{
if (j != 0)
{
carry = 1;
iq[i] = 0x1000000 - j;
}
}
else
iq[i] = 0xffffff - j;
}
if (q0 > 0)
{ /* rare case: chance is 1 in 12 */
switch (q0)
{
case 1:
iq[jz - 1] &= 0x7fffff;
break;
case 2:
iq[jz - 1] &= 0x3fffff;
break;
}
}
if (ih == 2)
{
z = one - z;
if (carry != 0)
z -= ldexp (one, q0);
}
}
/* check if recomputation is needed */
if (z == zero)
{
j = 0;
for (i = jz - 1; i >= jk; i--)
j |= iq[i];
if (j == 0)
{ /* need recomputation */
for (k = 1; iq[jk - k] == 0; k++); /* k = no. of terms needed */
for (i = jz + 1; i <= jz + k; i++)
{ /* add q[jz+1] to q[jz+k] */
f[jx + i] = (double) ipio2[jv + i];
for (j = 0, fw = 0.0; j <= jx; j++)
fw += x[j] * f[jx + i - j];
q[i] = fw;
}
jz += k;
goto recompute;
}
}
/* chop off zero terms */
if (z == 0.0)
{
jz -= 1;
q0 -= 24;
while (iq[jz] == 0)
{
jz--;
q0 -= 24;
}
}
else
{ /* break z into 24-bit if necessary */
z = ldexp (z, -q0);
if (z >= two24)
{
fw = (double) ((int) (twon24 * z));
iq[jz] = (int) (z - two24 * fw);
jz += 1;
q0 += 24;
iq[jz] = (int) fw;
}
else
iq[jz] = (int) z;
}
/* convert integer "bit" chunk to floating-point value */
fw = ldexp (one, q0);
for (i = jz; i >= 0; i--)
{
q[i] = fw * (double) iq[i];
fw *= twon24;
}
/* compute PIo2[0,...,jp]*q[jz,...,0] */
for (i = jz; i >= 0; i--)
{
for (fw = 0.0, k = 0; k <= jp && k <= jz - i; k++)
fw += PIo2[k] * q[i + k];
fq[jz - i] = fw;
}
/* compress fq[] into y[] */
switch (prec)
{
case 0:
fw = 0.0;
for (i = jz; i >= 0; i--)
fw += fq[i];
y[0] = (ih == 0) ? fw : -fw;
break;
case 1:
case 2:
fw = 0.0;
for (i = jz; i >= 0; i--)
fw += fq[i];
y[0] = (ih == 0) ? fw : -fw;
fw = fq[0] - fw;
for (i = 1; i <= jz; i++)
fw += fq[i];
y[1] = (ih == 0) ? fw : -fw;
break;
case 3: /* painful */
for (i = jz; i > 0; i--)
{
fw = fq[i - 1] + fq[i];
fq[i] += fq[i - 1] - fw;
fq[i - 1] = fw;
}
for (i = jz; i > 1; i--)
{
fw = fq[i - 1] + fq[i];
fq[i] += fq[i - 1] - fw;
fq[i - 1] = fw;
}
for (fw = 0.0, i = jz; i >= 2; i--)
fw += fq[i];
if (ih == 0)
{
y[0] = fq[0];
y[1] = fq[1];
y[2] = fw;
}
else
{
y[0] = -fq[0];
y[1] = -fq[1];
y[2] = -fw;
}
}
return n & 7;
}
|
|||||
| ↓ | euidaccess | 42 | 59 | 111 | lib/euidaccess.c |
int
euidaccess (const char *file, int mode)
{
#if defined EFF_ONLY_OK
return access (file, mode | EFF_ONLY_OK);
#elif defined ACC_SELF
return accessx (file, mode, ACC_SELF);
#elif HAVE_EACCESS
return eaccess (file, mode);
#else
uid_t uid = getuid ();
gid_t gid = getgid ();
uid_t euid = geteuid ();
gid_t egid = getegid ();
struct stat stats;
# if HAVE_DECL_SETREGID && PREFER_NONREENTRANT_EUIDACCESS
/* Define PREFER_NONREENTRANT_EUIDACCESS if you prefer euidaccess to
return the correct result even if this would make it
nonreentrant. Define this only if your entire application is
safe even if the uid or gid might temporarily change. If your
application uses signal handlers or threads it is probably not
safe. */
if (mode == F_OK)
return stat (file, &stats);
else
{
int result;
int saved_errno;
if (uid != euid)
setreuid (euid, uid);
if (gid != egid)
setregid (egid, gid);
result = access (file, mode);
saved_errno = errno;
/* Restore them. */
if (uid != euid)
setreuid (uid, euid);
if (gid != egid)
setregid (gid, egid);
errno = saved_errno;
return result;
}
# else
/* The following code assumes the traditional Unix model, and is not
correct on systems that have ACLs or the like. However, it's
better than nothing, and it is reentrant. */
unsigned int granted;
if (uid == euid && gid == egid)
/* If we are not set-uid or set-gid, access does the same. */
return access (file, mode);
if (stat (file, &stats) != 0)
return -1;
/* The super-user can read and write any file, and execute any file
that anyone can execute. */
if (euid == 0 && ((mode & X_OK) == 0
|| (stats.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))))
return 0;
/* Convert the mode to traditional form, clearing any bogus bits. */
if (R_OK == 4 && W_OK == 2 && X_OK == 1 && F_OK == 0)
mode &= 7;
else
mode = ((mode & R_OK ? 4 : 0)
+ (mode & W_OK ? 2 : 0)
+ (mode & X_OK ? 1 : 0));
if (mode == 0)
return 0; /* The file exists. */
/* Convert the file's permission bits to traditional form. */
if (S_IRUSR == (4 << 6) && S_IWUSR == (2 << 6) && S_IXUSR == (1 << 6)
&& S_IRGRP == (4 << 3) && S_IWGRP == (2 << 3) && S_IXGRP == (1 << 3)
&& S_IROTH == (4 << 0) && S_IWOTH == (2 << 0) && S_IXOTH == (1 << 0))
granted = stats.st_mode;
else
granted = ((stats.st_mode & S_IRUSR ? 4 << 6 : 0)
+ (stats.st_mode & S_IWUSR ? 2 << 6 : 0)
+ (stats.st_mode & S_IXUSR ? 1 << 6 : 0)
+ (stats.st_mode & S_IRGRP ? 4 << 3 : 0)
+ (stats.st_mode & S_IWGRP ? 2 << 3 : 0)
+ (stats.st_mode & S_IXGRP ? 1 << 3 : 0)
+ (stats.st_mode & S_IROTH ? 4 << 0 : 0)
+ (stats.st_mode & S_IWOTH ? 2 << 0 : 0)
+ (stats.st_mode & S_IXOTH ? 1 << 0 : 0));
if (euid == stats.st_uid)
granted >>= 6;
else if (egid == stats.st_gid || group_member (stats.st_gid))
granted >>= 3;
if ((mode & ~granted) == 0)
return 0;
__set_errno (EACCESS);
return -1;
# endif
#endif
}
|
|||||
| ↓ | __spawni | 46 | 91 | 231 | lib/spawni.c |
int
__spawni (pid_t *pid, const char *file,
const posix_spawn_file_actions_t *file_actions,
const posix_spawnattr_t *attrp, char *const argv[],
char *const envp[], int use_path)
{
pid_t new_pid;
char *path, *p, *name;
size_t len;
size_t pathlen;
/* Do this once. */
short int flags = attrp == NULL ? 0 : attrp->_flags;
/* Generate the new process. */
#if HAVE_VFORK
if ((flags & POSIX_SPAWN_USEVFORK) != 0
/* If no major work is done, allow using vfork. Note that we
might perform the path searching. But this would be done by
a call to execvp(), too, and such a call must be OK according
to POSIX. */
|| ((flags & (POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF
| POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER
| POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_RESETIDS)) == 0
&& file_actions == NULL))
new_pid = vfork ();
else
#endif
new_pid = fork ();
if (new_pid != 0)
{
if (new_pid < 0)
return errno;
/* The call was successful. Store the PID if necessary. */
if (pid != NULL)
*pid = new_pid;
return 0;
}
/* Set signal mask. */
if ((flags & POSIX_SPAWN_SETSIGMASK) != 0
&& sigprocmask (SIG_SETMASK, &attrp->_ss, NULL) != 0)
_exit (SPAWN_ERROR);
/* Set signal default action. */
if ((flags & POSIX_SPAWN_SETSIGDEF) != 0)
{
/* We have to iterate over all signals. This could possibly be
done better but it requires system specific solutions since
the sigset_t data type can be very different on different
architectures. */
int sig;
struct sigaction sa;
memset (&sa, '\0', sizeof (sa));
sa.sa_handler = SIG_DFL;
for (sig = 1; sig <= NSIG; ++sig)
if (sigismember (&attrp->_sd, sig) != 0
&& sigaction (sig, &sa, NULL) != 0)
_exit (SPAWN_ERROR);
}
#if (_LIBC ? defined _POSIX_PRIORITY_SCHEDULING : HAVE_SCHED_SETPARAM && HAVE_SCHED_SETSCHEDULER)
/* Set the scheduling algorithm and parameters. */
if ((flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER))
== POSIX_SPAWN_SETSCHEDPARAM)
{
if (sched_setparam (0, &attrp->_sp) == -1)
_exit (SPAWN_ERROR);
}
else if ((flags & POSIX_SPAWN_SETSCHEDULER) != 0)
{
if (sched_setscheduler (0, attrp->_policy,
(flags & POSIX_SPAWN_SETSCHEDPARAM) != 0
? &attrp->_sp : NULL) == -1)
_exit (SPAWN_ERROR);
}
#endif
/* Set the process group ID. */
if ((flags & POSIX_SPAWN_SETPGROUP) != 0
&& setpgid (0, attrp->_pgrp) != 0)
_exit (SPAWN_ERROR);
/* Set the effective user and group IDs. */
if ((flags & POSIX_SPAWN_RESETIDS) != 0
&& (local_seteuid (getuid ()) != 0
|| local_setegid (getgid ()) != 0))
_exit (SPAWN_ERROR);
/* Execute the file actions. */
if (file_actions != NULL)
{
int cnt;
for (cnt = 0; cnt < file_actions->_used; ++cnt)
{
struct __spawn_action *action = &file_actions->_actions[cnt];
switch (action->tag)
{
case spawn_do_close:
if (close_not_cancel (action->action.close_action.fd) != 0)
/* Signal the error. */
_exit (SPAWN_ERROR);
break;
case spawn_do_open:
{
int new_fd = open_not_cancel (action->action.open_action.path,
action->action.open_action.oflag
| O_LARGEFILE,
action->action.open_action.mode);
if (new_fd == -1)
/* The `open' call failed. */
_exit (SPAWN_ERROR);
/* Make sure the desired file descriptor is used. */
if (new_fd != action->action.open_action.fd)
{
if (dup2 (new_fd, action->action.open_action.fd)
!= action->action.open_action.fd)
/* The `dup2' call failed. */
_exit (SPAWN_ERROR);
if (close_not_cancel (new_fd) != 0)
/* The `close' call failed. */
_exit (SPAWN_ERROR);
}
}
break;
case spawn_do_dup2:
if (dup2 (action->action.dup2_action.fd,
action->action.dup2_action.newfd)
!= action->action.dup2_action.newfd)
/* The `dup2' call failed. */
_exit (SPAWN_ERROR);
break;
}
}
}
if (! use_path || strchr (file, '/') != NULL)
{
/* The FILE parameter is actually a path. */
execve (file, argv, envp);
if (errno == ENOEXEC)
script_execute (file, argv, envp);
/* Oh, oh. `execve' returns. This is bad. */
_exit (SPAWN_ERROR);
}
/* We have to search for FILE on the path. */
path = getenv ("PATH");
if (path == NULL)
{
#if HAVE_CONFSTR
/* There is no `PATH' in the environment.
The default search path is the current directory
followed by the path `confstr' returns for `_CS_PATH'. */
len = confstr (_CS_PATH, (char *) NULL, 0);
path = (char *) alloca (1 + len);
path[0] = ':';
(void) confstr (_CS_PATH, path + 1, len);
#else
/* Pretend that the PATH contains only the current directory. */
path = "";
#endif
}
len = strlen (file) + 1;
pathlen = strlen (path);
name = alloca (pathlen + len + 1);
/* Copy the file name at the top. */
name = (char *) memcpy (name + pathlen + 1, file, len);
/* And add the slash. */
*--name = '/';
p = path;
do
{
char *startp;
path = p;
p = strchrnul (path, ':');
if (p == path)
/* Two adjacent colons, or a colon at the beginning or the end
of `PATH' means to search the current directory. */
startp = name + 1;
else
startp = (char *) memcpy (name - (p - path), path, p - path);
/* Try to execute this name. If it works, execv will not return. */
execve (startp, argv, envp);
if (errno == ENOEXEC)
script_execute (startp, argv, envp);
switch (errno)
{
case EACCES:
case ENOENT:
case ESTALE:
case ENOTDIR:
/* Those errors indicate the file is missing or not executable
by us, in which case we want to just try the next path
directory. */
break;
default:
/* Some other error means we found an executable file, but
something went wrong executing it; return the error to our
caller. */
_exit (SPAWN_ERROR);
}
}
while (*p++ != '\0');
/* Return with an error. */
_exit (SPAWN_ERROR);
}
|
|||||
| ↓ | build_wcs_upper_buffer | 40 | 134 | 212 | lib/regex_internal.c |
static reg_errcode_t
internal_function
build_wcs_upper_buffer (re_string_t *pstr)
{
mbstate_t prev_st;
Idx src_idx, byte_idx, end_idx, remain_len;
size_t mbclen;
#ifdef _LIBC
char buf[MB_LEN_MAX];
assert (MB_LEN_MAX >= pstr->mb_cur_max);
#else
char buf[64];
#endif
byte_idx = pstr->valid_len;
end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
/* The following optimization assumes that ASCII characters can be
mapped to wide characters with a simple cast. */
if (! pstr->map_notascii && pstr->trans == NULL && !pstr->offsets_needed)
{
while (byte_idx < end_idx)
{
wchar_t wc;
if (isascii (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx])
&& mbsinit (&pstr->cur_state))
{
/* In case of a singlebyte character. */
pstr->mbs[byte_idx]
= toupper (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]);
/* The next step uses the assumption that wchar_t is encoded
ASCII-safe: all ASCII values can be converted like this. */
pstr->wcs[byte_idx] = (wchar_t) pstr->mbs[byte_idx];
++byte_idx;
continue;
}
remain_len = end_idx - byte_idx;
prev_st = pstr->cur_state;
mbclen = mbrtowc (&wc,
((const char *) pstr->raw_mbs + pstr->raw_mbs_idx
+ byte_idx), remain_len, &pstr->cur_state);
if (BE (mbclen < (size_t) -2, 1))
{
wchar_t wcu = wc;
if (iswlower (wc))
{
size_t mbcdlen;
wcu = towupper (wc);
mbcdlen = wcrtomb (buf, wcu, &prev_st);
if (BE (mbclen == mbcdlen, 1))
memcpy (pstr->mbs + byte_idx, buf, mbclen);
else
{
src_idx = byte_idx;
goto offsets_needed;
}
}
else
memcpy (pstr->mbs + byte_idx,
pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx, mbclen);
pstr->wcs[byte_idx++] = wcu;
/* Write paddings. */
for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
pstr->wcs[byte_idx++] = WEOF;
}
else if (mbclen == (size_t) -1 || mbclen == 0)
{
/* It is an invalid character or '\0'. Just use the byte. */
int ch = pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx];
pstr->mbs[byte_idx] = ch;
/* And also cast it to wide char. */
pstr->wcs[byte_idx++] = (wchar_t) ch;
if (BE (mbclen == (size_t) -1, 0))
pstr->cur_state = prev_st;
}
else
{
/* The buffer doesn't have enough space, finish to build. */
pstr->cur_state = prev_st;
break;
}
}
pstr->valid_len = byte_idx;
pstr->valid_raw_len = byte_idx;
return REG_NOERROR;
}
else
for (src_idx = pstr->valid_raw_len; byte_idx < end_idx;)
{
wchar_t wc;
const char *p;
offsets_needed:
remain_len = end_idx - byte_idx;
prev_st = pstr->cur_state;
if (BE (pstr->trans != NULL, 0))
{
int i, ch;
for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
{
ch = pstr->raw_mbs [pstr->raw_mbs_idx + src_idx + i];
buf[i] = pstr->trans[ch];
}
p = (const char *) buf;
}
else
p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + src_idx;
mbclen = mbrtowc (&wc, p, remain_len, &pstr->cur_state);
if (BE (mbclen < (size_t) -2, 1))
{
wchar_t wcu = wc;
if (iswlower (wc))
{
size_t mbcdlen;
wcu = towupper (wc);
mbcdlen = wcrtomb ((char *) buf, wcu, &prev_st);
if (BE (mbclen == mbcdlen, 1))
memcpy (pstr->mbs + byte_idx, buf, mbclen);
else if (mbcdlen != (size_t) -1)
{
size_t i;
if (byte_idx + mbcdlen > pstr->bufs_len)
{
pstr->cur_state = prev_st;
break;
}
if (pstr->offsets == NULL)
{
pstr->offsets = re_malloc (Idx, pstr->bufs_len);
if (pstr->offsets == NULL)
return REG_ESPACE;
}
if (!pstr->offsets_needed)
{
for (i = 0; i < (size_t) byte_idx; ++i)
pstr->offsets[i] = i;
pstr->offsets_needed = 1;
}
memcpy (pstr->mbs + byte_idx, buf, mbcdlen);
pstr->wcs[byte_idx] = wcu;
pstr->offsets[byte_idx] = src_idx;
for (i = 1; i < mbcdlen; ++i)
{
pstr->offsets[byte_idx + i]
= src_idx + (i < mbclen ? i : mbclen - 1);
pstr->wcs[byte_idx + i] = WEOF;
}
pstr->len += mbcdlen - mbclen;
if (pstr->raw_stop > src_idx)
pstr->stop += mbcdlen - mbclen;
end_idx = (pstr->bufs_len > pstr->len)
? pstr->len : pstr->bufs_len;
byte_idx += mbcdlen;
src_idx += mbclen;
continue;
}
else
memcpy (pstr->mbs + byte_idx, p, mbclen);
}
else
memcpy (pstr->mbs + byte_idx, p, mbclen);
if (BE (pstr->offsets_needed != 0, 0))
{
size_t i;
for (i = 0; i < mbclen; ++i)
pstr->offsets[byte_idx + i] = src_idx + i;
}
src_idx += mbclen;
pstr->wcs[byte_idx++] = wcu;
/* Write paddings. */
for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
pstr->wcs[byte_idx++] = WEOF;
}
else if (mbclen == (size_t) -1 || mbclen == 0)
{
/* It is an invalid character or '\0'. Just use the byte. */
int ch = pstr->raw_mbs[pstr->raw_mbs_idx + src_idx];
if (BE (pstr->trans != NULL, 0))
ch = pstr->trans [ch];
pstr->mbs[byte_idx] = ch;
if (BE (pstr->offsets_needed != 0, 0))
pstr->offsets[byte_idx] = src_idx;
++src_idx;
/* And also cast it to wide char. */
pstr->wcs[byte_idx++] = (wchar_t) ch;
if (BE (mbclen == (size_t) -1, 0))
pstr->cur_state = prev_st;
}
else
{
/* The buffer doesn't have enough space, finish to build. */
pstr->cur_state = prev_st;
break;
}
}
pstr->valid_len = byte_idx;
pstr->valid_raw_len = src_idx;
return REG_NOERROR;
}
|
|||||
| ↓ | rpl_select | 39 | 138 | 232 | lib/winsock-select.c |
int
rpl_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds,
struct timeval *timeout)
{
static struct timeval tv0;
static HANDLE hEvent;
HANDLE h, handle_array[FD_SETSIZE + 2];
fd_set handle_rfds, handle_wfds, handle_xfds;
struct bitset rbits, wbits, xbits;
unsigned char anyfds_in[FD_SETSIZE / CHAR_BIT];
DWORD ret, wait_timeout, nhandles, nsock;
MSG msg;
int i, fd, rc;
if (nfds > FD_SETSIZE)
nfds = FD_SETSIZE;
if (!timeout)
wait_timeout = INFINITE;
else
{
wait_timeout = timeout->tv_sec + timeout->tv_usec / 1000;
/* select is also used as a portable usleep. */
if (!rfds && !wfds && !xfds)
{
Sleep (wait_timeout);
return 0;
}
}
if (!hEvent)
hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
handle_array[0] = hEvent;
nhandles = 1;
nsock = 0;
/* Copy descriptors to bitsets. */
memset (&rbits, 0, sizeof (rbits));
memset (&wbits, 0, sizeof (wbits));
memset (&xbits, 0, sizeof (xbits));
memset (anyfds_in, 0, sizeof (anyfds_in));
if (rfds)
for (i = 0; i < rfds->fd_count; i++)
{
fd = rfds->fd_array[i];
rbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
}
else
rfds = (fd_set *) alloca (sizeof (fd_set));
if (wfds)
for (i = 0; i < wfds->fd_count; i++)
{
fd = wfds->fd_array[i];
wbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
}
else
wfds = (fd_set *) alloca (sizeof (fd_set));
if (xfds)
for (i = 0; i < xfds->fd_count; i++)
{
fd = xfds->fd_array[i];
xbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
}
else
xfds = (fd_set *) alloca (sizeof (fd_set));
/* Zero all the fd_sets, including the application's. */
FD_ZERO (rfds);
FD_ZERO (wfds);
FD_ZERO (xfds);
FD_ZERO (&handle_rfds);
FD_ZERO (&handle_wfds);
FD_ZERO (&handle_xfds);
/* Classify handles. Create fd sets for sockets, poll the others. */
for (i = 0; i < nfds; i++)
{
WSANETWORKEVENTS ev;
if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
continue;
h = (HANDLE) _get_osfhandle (i);
if (!h)
{
errno = EBADF;
return -1;
}
/* Under Wine, it seems that getsockopt returns 0 for pipes too.
WSAEnumNetworkEvents instead distinguishes the two correctly. */
ev.lNetworkEvents = 0xDEADBEEF;
WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
if (ev.lNetworkEvents != 0xDEADBEEF)
{
int requested = FD_CLOSE;
/* See above; socket handles are mapped onto select, but we
need to map descriptors to handles. */
if (rbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
{
requested |= FD_READ | FD_ACCEPT;
FD_SET ((SOCKET) h, rfds);
FD_SET ((SOCKET) h, &handle_rfds);
}
if (wbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
{
requested |= FD_WRITE | FD_CONNECT;
FD_SET ((SOCKET) h, wfds);
FD_SET ((SOCKET) h, &handle_wfds);
}
if (xbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
{
requested |= FD_OOB;
FD_SET ((SOCKET) h, xfds);
FD_SET ((SOCKET) h, &handle_xfds);
}
WSAEventSelect ((SOCKET) h, hEvent, requested);
nsock++;
}
else
{
handle_array[nhandles++] = h;
/* Poll now. If we get an event, do not wait below. */
if (wait_timeout != 0
&& win32_poll_handle (h, i, &rbits, &wbits, &xbits))
wait_timeout = 0;
}
}
if (wait_timeout == 0 || nsock == 0)
rc = 0;
else
{
/* See if we need to wait in the loop below. If any select is ready,
do MsgWaitForMultipleObjects anyway to dispatch messages, but
no need to call select again. */
rc = select (0, &handle_rfds, &handle_wfds, &handle_xfds, &tv0);
if (rc == 0)
{
/* Restore the fd_sets for the other select we do below. */
memcpy (&handle_rfds, rfds, sizeof (fd_set));
memcpy (&handle_wfds, wfds, sizeof (fd_set));
memcpy (&handle_xfds, xfds, sizeof (fd_set));
}
else
wait_timeout = 0;
}
for (;;)
{
ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
wait_timeout, QS_ALLINPUT);
if (ret == WAIT_OBJECT_0 + nhandles)
{
/* new input of some other kind */
BOOL bRet;
while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
}
else
break;
}
/* If we haven't done it yet, check the status of the sockets. */
if (rc == 0 && nsock > 0)
rc = select (0, &handle_rfds, &handle_wfds, &handle_xfds, &tv0);
/* Now fill in the results. */
FD_ZERO (rfds);
FD_ZERO (wfds);
FD_ZERO (xfds);
/* Place a sentinel at the end of the array. */
handle_array[nhandles] = NULL;
nhandles = 1;
for (i = 0; i < nfds; i++)
{
if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
continue;
h = (HANDLE) _get_osfhandle (i);
if (h != handle_array[nhandles])
{
/* Perform handle->descriptor mapping. Don't update rc, as these
results are counted in the return value of Winsock's select. */
WSAEventSelect ((SOCKET) h, NULL, 0);
if (FD_ISSET (h, &handle_rfds))
FD_SET (i, rfds);
if (FD_ISSET (h, &handle_wfds))
FD_SET (i, wfds);
if (FD_ISSET (h, &handle_xfds))
FD_SET (i, xfds);
}
else
{
/* Not a socket. */
nhandles++;
win32_poll_handle (h, i, &rbits, &wbits, &xbits);
if (rbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
{
rc++;
FD_SET (i, rfds);
}
if (wbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
{
rc++;
FD_SET (i, wfds);
}
if (xbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
{
rc++;
FD_SET (i, xfds);
}
}
}
return rc;
}
|
|||||
| ↓ | file_has_acl | 38 | 102 | 247 | lib/file-has-acl.c |
int
file_has_acl (char const *name, struct stat const *sb)
{
#if USE_ACL
if (! S_ISLNK (sb->st_mode))
{
# if HAVE_ACL_GET_FILE
/* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
/* Linux, FreeBSD, MacOS X, IRIX, Tru64 */
int ret;
if (HAVE_ACL_EXTENDED_FILE) /* Linux */
{
/* On Linux, acl_extended_file is an optimized function: It only
makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for
ACL_TYPE_DEFAULT. */
ret = acl_extended_file (name);
}
else /* FreeBSD, MacOS X, IRIX, Tru64 */
{
# if HAVE_ACL_TYPE_EXTENDED /* MacOS X */
/* On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
and acl_get_file (name, ACL_TYPE_DEFAULT)
always return NULL / EINVAL. There is no point in making
these two useless calls. The real ACL is retrieved through
acl_get_file (name, ACL_TYPE_EXTENDED). */
acl_t acl = acl_get_file (name, ACL_TYPE_EXTENDED);
if (acl)
{
ret = acl_extended_nontrivial (acl);
acl_free (acl);
}
else
ret = -1;
# else /* FreeBSD, IRIX, Tru64 */
acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS);
if (acl)
{
int saved_errno;
ret = acl_access_nontrivial (acl);
saved_errno = errno;
acl_free (acl);
errno = saved_errno;
# if HAVE_ACL_FREE_TEXT /* Tru64 */
/* On OSF/1, acl_get_file (name, ACL_TYPE_DEFAULT) always
returns NULL with errno not set. There is no point in
making this call. */
# else /* FreeBSD, IRIX */
/* On Linux, FreeBSD, IRIX, acl_get_file (name, ACL_TYPE_ACCESS)
and acl_get_file (name, ACL_TYPE_DEFAULT) on a directory
either both succeed or both fail; it depends on the
filesystem. Therefore there is no point in making the second
call if the first one already failed. */
if (ret == 0 && S_ISDIR (sb->st_mode))
{
acl = acl_get_file (name, ACL_TYPE_DEFAULT);
if (acl)
{
ret = (0 < acl_entries (acl));
acl_free (acl);
}
else
ret = -1;
}
# endif
}
else
ret = -1;
# endif
}
if (ret < 0)
return ACL_NOT_WELL_SUPPORTED (errno) ? 0 : -1;
return ret;
# elif HAVE_ACL && defined GETACLCNT /* Solaris, Cygwin, not HP-UX */
# if defined ACL_NO_TRIVIAL
/* Solaris 10 (newer version), which has additional API declared in
|
|||||
| ↓ | getaddrinfo | 39 | 88 | 186 | lib/getaddrinfo.c |
int
getaddrinfo (const char *restrict nodename,
const char *restrict servname,
const struct addrinfo *restrict hints,
struct addrinfo **restrict res)
{
struct addrinfo *tmp;
int port = 0;
struct hostent *he;
void *storage;
size_t size;
#if HAVE_IPV6
struct v6_pair {
struct addrinfo addrinfo;
struct sockaddr_in6 sockaddr_in6;
};
#endif
#if HAVE_IPV4
struct v4_pair {
struct addrinfo addrinfo;
struct sockaddr_in sockaddr_in;
};
#endif
#ifdef WIN32_NATIVE
if (use_win32_p ())
return getaddrinfo_ptr (nodename, servname, hints, res);
#endif
if (hints && (hints->ai_flags & ~(AI_CANONNAME|AI_PASSIVE)))
/* FIXME: Support more flags. */
return EAI_BADFLAGS;
if (hints && !validate_family (hints->ai_family))
return EAI_FAMILY;
if (hints &&
hints->ai_socktype != SOCK_STREAM && hints->ai_socktype != SOCK_DGRAM)
/* FIXME: Support other socktype. */
return EAI_SOCKTYPE; /* FIXME: Better return code? */
if (!nodename)
{
if (!(hints->ai_flags & AI_PASSIVE))
return EAI_NONAME;
#ifdef HAVE_IPV6
nodename = (hints->ai_family == AF_INET6) ? "::" : "0.0.0.0";
#else
nodename = "0.0.0.0";
#endif
}
if (servname)
{
struct servent *se = NULL;
const char *proto =
(hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
if (hints == NULL || !(hints->ai_flags & AI_NUMERICSERV))
/* FIXME: Use getservbyname_r if available. */
se = getservbyname (servname, proto);
if (!se)
{
char *c;
if (!(*servname >= '0' && *servname <= '9'))
return EAI_NONAME;
port = strtoul (servname, &c, 10);
if (*c || port > 0xffff)
return EAI_NONAME;
port = htons (port);
}
else
port = se->s_port;
}
/* FIXME: Use gethostbyname_r if available. */
he = gethostbyname (nodename);
if (!he || he->h_addr_list[0] == NULL)
return EAI_NONAME;
switch (he->h_addrtype)
{
#if HAVE_IPV6
case PF_INET6:
size = sizeof (struct v6_pair);
break;
#endif
#if HAVE_IPV4
case PF_INET:
size = sizeof (struct v4_pair);
break;
#endif
default:
return EAI_NODATA;
}
storage = calloc (1, size);
if (!storage)
return EAI_MEMORY;
switch (he->h_addrtype)
{
#if HAVE_IPV6
case PF_INET6:
{
struct v6_pair *p = storage;
struct sockaddr_in6 *sinp = &p->sockaddr_in6;
tmp = &p->addrinfo;
if (port)
sinp->sin6_port = port;
if (he->h_length != sizeof (sinp->sin6_addr))
{
free (storage);
return EAI_SYSTEM; /* FIXME: Better return code? Set errno? */
}
memcpy (&sinp->sin6_addr, he->h_addr_list[0], sizeof sinp->sin6_addr);
tmp->ai_addr = (struct sockaddr *) sinp;
tmp->ai_addrlen = sizeof *sinp;
}
break;
#endif
#if HAVE_IPV4
case PF_INET:
{
struct v4_pair *p = storage;
struct sockaddr_in *sinp = &p->sockaddr_in;
tmp = &p->addrinfo;
if (port)
sinp->sin_port = port;
if (he->h_length != sizeof (sinp->sin_addr))
{
free (storage);
return EAI_SYSTEM; /* FIXME: Better return code? Set errno? */
}
memcpy (&sinp->sin_addr, he->h_addr_list[0], sizeof sinp->sin_addr);
tmp->ai_addr = (struct sockaddr *) sinp;
tmp->ai_addrlen = sizeof *sinp;
}
break;
#endif
default:
free (storage);
return EAI_NODATA;
}
if (hints && hints->ai_flags & AI_CANONNAME)
{
const char *cn;
if (he->h_name)
cn = he->h_name;
else
cn = nodename;
tmp->ai_canonname = strdup (cn);
if (!tmp->ai_canonname)
{
free (storage);
return EAI_MEMORY;
}
}
tmp->ai_protocol = (hints) ? hints->ai_protocol : 0;
tmp->ai_socktype = (hints) ? hints->ai_socktype : 0;
tmp->ai_addr->sa_family = he->h_addrtype;
tmp->ai_family = he->h_addrtype;
/* FIXME: If more than one address, create linked list of addrinfo's. */
*res = tmp;
return 0;
}
|
|||||
| ↓ | __argp_fmtstream_update | 37 | 103 | 226 | lib/argp-fmtstream.c |
void
__argp_fmtstream_update (argp_fmtstream_t fs)
{
char *buf, *nl;
size_t len;
/* Scan the buffer for newlines. */
buf = fs->buf + fs->point_offs;
while (buf < fs->p)
{
size_t r;
if (fs->point_col == 0 && fs->lmargin != 0)
{
/* We are starting a new line. Print spaces to the left margin. */
const size_t pad = fs->lmargin;
if (fs->p + pad < fs->end)
{
/* We can fit in them in the buffer by moving the
buffer text up and filling in the beginning. */
memmove (buf + pad, buf, fs->p - buf);
fs->p += pad; /* Compensate for bigger buffer. */
memset (buf, ' ', pad); /* Fill in the spaces. */
buf += pad; /* Don't bother searching them. */
}
else
{
/* No buffer space for spaces. Must flush. */
size_t i;
for (i = 0; i < pad; i++)
{
#ifdef USE_IN_LIBIO
if (_IO_fwide (fs->stream, 0) > 0)
putwc_unlocked (L' ', fs->stream);
else
#endif
putc_unlocked (' ', fs->stream);
}
}
fs->point_col = pad;
}
len = fs->p - buf;
nl = memchr (buf, '\n', len);
if (fs->point_col < 0)
fs->point_col = 0;
if (!nl)
{
/* The buffer ends in a partial line. */
if (fs->point_col + len < fs->rmargin)
{
/* The remaining buffer text is a partial line and fits
within the maximum line width. Advance point for the
characters to be written and stop scanning. */
fs->point_col += len;
break;
}
else
/* Set the end-of-line pointer for the code below to
the end of the buffer. */
nl = fs->p;
}
else if (fs->point_col + (nl - buf) < (ssize_t) fs->rmargin)
{
/* The buffer contains a full line that fits within the maximum
line width. Reset point and scan the next line. */
fs->point_col = 0;
buf = nl + 1;
continue;
}
/* This line is too long. */
r = fs->rmargin - 1;
if (fs->wmargin < 0)
{
/* Truncate the line by overwriting the excess with the
newline and anything after it in the buffer. */
if (nl < fs->p)
{
memmove (buf + (r - fs->point_col), nl, fs->p - nl);
fs->p -= buf + (r - fs->point_col) - nl;
/* Reset point for the next line and start scanning it. */
fs->point_col = 0;
buf += r + 1; /* Skip full line plus \n. */
}
else
{
/* The buffer ends with a partial line that is beyond the
maximum line width. Advance point for the characters
written, and discard those past the max from the buffer. */
fs->point_col += len;
fs->p -= fs->point_col - r;
break;
}
}
else
{
/* Do word wrap. Go to the column just past the maximum line
width and scan back for the beginning of the word there.
Then insert a line break. */
char *p, *nextline;
int i;
p = buf + (r + 1 - fs->point_col);
while (p >= buf && !isblank (*p))
--p;
nextline = p + 1; /* This will begin the next line. */
if (nextline > buf)
{
/* Swallow separating blanks. */
if (p >= buf)
do
--p;
while (p >= buf && isblank (*p));
nl = p + 1; /* The newline will replace the first blank. */
}
else
{
/* A single word that is greater than the maximum line width.
Oh well. Put it on an overlong line by itself. */
p = buf + (r + 1 - fs->point_col);
/* Find the end of the long word. */
if (p < nl)
do
++p;
while (p < nl && !isblank (*p));
if (p == nl)
{
/* It already ends a line. No fussing required. */
fs->point_col = 0;
buf = nl + 1;
continue;
}
/* We will move the newline to replace the first blank. */
nl = p;
/* Swallow separating blanks. */
do
++p;
while (isblank (*p));
/* The next line will start here. */
nextline = p;
}
/* Note: There are a bunch of tests below for
NEXTLINE == BUF + LEN + 1; this case is where NL happens to fall
at the end of the buffer, and NEXTLINE is in fact empty (and so
we need not be careful to maintain its contents). */
if ((nextline == buf + len + 1
? fs->end - nl < fs->wmargin + 1
: nextline - (nl + 1) < fs->wmargin)
&& fs->p > nextline)
{
/* The margin needs more blanks than we removed. */
if (fs->end - fs->p > fs->wmargin + 1)
/* Make some space for them. */
{
size_t mv = fs->p - nextline;
memmove (nl + 1 + fs->wmargin, nextline, mv);
nextline = nl + 1 + fs->wmargin;
len = nextline + mv - buf;
*nl++ = '\n';
}
else
/* Output the first line so we can use the space. */
{
#ifdef _LIBC
__fxprintf (fs->stream, "%.*s\n",
(int) (nl - fs->buf), fs->buf);
#else
if (nl > fs->buf)
fwrite_unlocked (fs->buf, 1, nl - fs->buf, fs->stream);
putc_unlocked ('\n', fs->stream);
#endif
len += buf - fs->buf;
nl = buf = fs->buf;
}
}
else
/* We can fit the newline and blanks in before
the next word. */
*nl++ = '\n';
if (nextline - nl >= fs->wmargin
|| (nextline == buf + len + 1 && fs->end - nextline >= fs->wmargin))
/* Add blanks up to the wrap margin column. */
for (i = 0; i < fs->wmargin; ++i)
*nl++ = ' ';
else
for (i = 0; i < fs->wmargin; ++i)
#ifdef USE_IN_LIBIO
if (_IO_fwide (fs->stream, 0) > 0)
putwc_unlocked (L' ', fs->stream);
else
#endif
putc_unlocked (' ', fs->stream);
/* Copy the tail of the original buffer into the current buffer
position. */
if (nl < nextline)
memmove (nl, nextline, buf + len - nextline);
len -= nextline - buf;
/* Continue the scan on the remaining lines in the buffer. */
buf = nl;
/* Restore bufp to include all the remaining text. */
fs->p = nl + len;
/* Reset the counter of what has been output this line. If wmargin
is 0, we want to avoid the lmargin getting added, so we set
point_col to a magic value of -1 in that case. */
fs->point_col = fs->wmargin ? fs->wmargin : -1;
}
}
/* Remember that we've scanned as far as the end of the buffer. */
fs->point_offs = fs->p - fs->buf;
}
|
|||||
| ↓ | mem_iconveh | 36 | 86 | 161 | lib/striconveh.c |
int
mem_iconveh (const char *src, size_t srclen,
const char *from_codeset, const char *to_codeset,
enum iconv_ilseq_handler handler,
size_t *offsets,
char **resultp, size_t *lengthp)
{
if (srclen == 0)
{
/* Nothing to convert. */
*lengthp = 0;
return 0;
}
else if (offsets == NULL && c_strcasecmp (from_codeset, to_codeset) == 0)
{
char *result;
if (*resultp != NULL && *lengthp >= srclen)
result = *resultp;
else
{
result = (char *) malloc (srclen);
if (result == NULL)
{
errno = ENOMEM;
return -1;
}
}
memcpy (result, src, srclen);
*resultp = result;
*lengthp = srclen;
return 0;
}
else
{
#if HAVE_ICONV
iconv_t cd;
iconv_t cd1;
iconv_t cd2;
char *result;
size_t length;
int retval;
/* Avoid glibc-2.1 bug with EUC-KR. */
# if (__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) && !defined _LIBICONV_VERSION
if (c_strcasecmp (from_codeset, "EUC-KR") == 0
|| c_strcasecmp (to_codeset, "EUC-KR") == 0)
{
errno = EINVAL;
return -1;
}
# endif
cd = iconv_open (to_codeset, from_codeset);
if (STRCASEEQ (from_codeset, "UTF-8", 'U','T','F','-','8',0,0,0,0))
cd1 = (iconv_t)(-1);
else
{
cd1 = iconv_open ("UTF-8", from_codeset);
if (cd1 == (iconv_t)(-1))
{
int saved_errno = errno;
if (cd != (iconv_t)(-1))
iconv_close (cd);
errno = saved_errno;
return -1;
}
}
if (STRCASEEQ (to_codeset, "UTF-8", 'U','T','F','-','8',0,0,0,0)
# if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 || _LIBICONV_VERSION >= 0x0105
|| c_strcasecmp (to_codeset, "UTF-8//TRANSLIT") == 0
# endif
)
cd2 = (iconv_t)(-1);
else
{
cd2 = iconv_open (to_codeset, "UTF-8");
if (cd2 == (iconv_t)(-1))
{
int saved_errno = errno;
if (cd1 != (iconv_t)(-1))
iconv_close (cd1);
if (cd != (iconv_t)(-1))
iconv_close (cd);
errno = saved_errno;
return -1;
}
}
result = *resultp;
length = *lengthp;
retval = mem_cd_iconveh (src, srclen, cd, cd1, cd2, handler, offsets,
&result, &length);
if (retval < 0)
{
/* Close cd, cd1, cd2, but preserve the errno from str_cd_iconv. */
int saved_errno = errno;
if (cd2 != (iconv_t)(-1))
iconv_close (cd2);
if (cd1 != (iconv_t)(-1))
iconv_close (cd1);
if (cd != (iconv_t)(-1))
iconv_close (cd);
errno = saved_errno;
}
else
{
if (cd2 != (iconv_t)(-1) && iconv_close (cd2) < 0)
{
/* Return -1, but free the allocated memory, and while doing
that, preserve the errno from iconv_close. */
int saved_errno = errno;
if (cd1 != (iconv_t)(-1))
iconv_close (cd1);
if (cd != (iconv_t)(-1))
iconv_close (cd);
if (result != *resultp && result != NULL)
free (result);
errno = saved_errno;
return -1;
}
if (cd1 != (iconv_t)(-1) && iconv_close (cd1) < 0)
{
/* Return -1, but free the | |||||