Description:l0 posix interface
Team: OTHERS Feature or Bugfix:Feature Binary Source:No PrivateCode(Yes/No):No Change-Id: I8bcb92a97a98c61077c55704dec03c997d1246da ChangeID:13439291
This commit is contained in:
parent
3887b13564
commit
955b52e4b2
|
@ -437,7 +437,32 @@ typedef struct { unsigned __attr[2]; } pthread_rwlockattr_t;
|
|||
|
||||
|
||||
#if defined(__NEED_struct__IO_FILE) && !defined(__DEFINED_struct__IO_FILE)
|
||||
struct _IO_FILE { char __x; };
|
||||
struct _IO_FILE {
|
||||
unsigned flags;
|
||||
unsigned char *rpos, *rend;
|
||||
int (*close)(struct _IO_FILE *);
|
||||
unsigned char *wend, *wpos;
|
||||
unsigned char *mustbezero_1;
|
||||
unsigned char *wbase;
|
||||
size_t (*read)(struct _IO_FILE *, unsigned char *, size_t);
|
||||
size_t (*write)(struct _IO_FILE *, const unsigned char *, size_t);
|
||||
off_t (*seek)(struct _IO_FILE *, off_t, int);
|
||||
unsigned char *buf;
|
||||
size_t buf_size;
|
||||
struct _IO_FILE *prev, *next;
|
||||
int fd;
|
||||
int pipe_pid;
|
||||
int mode;
|
||||
void *lock;
|
||||
int lbf;
|
||||
void *cookie;
|
||||
off_t off;
|
||||
char *getln_buf;
|
||||
void *mustbezero_2;
|
||||
unsigned char *shend;
|
||||
off_t shlim, shcnt;
|
||||
struct __locale_struct *locale;
|
||||
};
|
||||
#define __DEFINED_struct__IO_FILE
|
||||
#endif
|
||||
|
||||
|
@ -535,7 +560,13 @@ typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof
|
|||
#endif
|
||||
|
||||
#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t)
|
||||
typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } pthread_cond_t;
|
||||
#include "los_event.h"
|
||||
typedef struct pthread_cond {
|
||||
volatile int count; /**< The number of tasks blocked by condition */
|
||||
EVENT_CB_S event; /**< Event object*/
|
||||
pthread_mutex_t* mutex; /**< Mutex locker for condition variable protection */
|
||||
volatile int value; /**< Condition variable state value*/
|
||||
} pthread_cond_t;
|
||||
#define __DEFINED_pthread_cond_t
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#define ENOERR 0
|
||||
#define EPERM 1
|
||||
#define ENOENT 2
|
||||
#define ESRCH 3
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
#define _LIMITS_H
|
||||
|
||||
#ifdef __ICCARM__ /* for iar */
|
||||
#define PATH_MAX 256
|
||||
#define MQ_PRIO_MAX 1
|
||||
#define PTHREAD_STACK_MIN LOSCFG_BASE_CORE_TSK_MIN_STACK_SIZE
|
||||
#include_next <limits.h>
|
||||
#else
|
||||
|
@ -49,7 +51,7 @@
|
|||
#ifndef NAME_MAX
|
||||
#define NAME_MAX 255
|
||||
#endif
|
||||
#define PATH_MAX 4096
|
||||
#define PATH_MAX 256
|
||||
#define NGROUPS_MAX 32
|
||||
#define ARG_MAX 131072
|
||||
#define IOV_MAX 1024
|
||||
|
@ -74,7 +76,7 @@
|
|||
#define SEM_VALUE_MAX 0x7fffffff
|
||||
#define SEM_NSEMS_MAX 256
|
||||
#define DELAYTIMER_MAX 0x7fffffff
|
||||
#define MQ_PRIO_MAX 32768
|
||||
#define MQ_PRIO_MAX 1
|
||||
#define LOGIN_NAME_MAX 256
|
||||
|
||||
/* Arbitrary numbers... */
|
||||
|
|
|
@ -83,12 +83,13 @@ extern "C" {
|
|||
|
||||
#include <features.h>
|
||||
|
||||
#ifndef NULL
|
||||
#ifdef __cplusplus
|
||||
#define NULL 0L
|
||||
#else
|
||||
#define NULL ((void*)0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#define __NEED_size_t
|
||||
#define __NEED_time_t
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
musl as a whole is licensed under the following standard MIT license:
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Copyright © 2005-2020 Rich Felker, et al.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Authors/contributors include:
|
||||
|
||||
A. Wilcox
|
||||
Ada Worcester
|
||||
Alex Dowad
|
||||
Alex Suykov
|
||||
Alexander Monakov
|
||||
Andre McCurdy
|
||||
Andrew Kelley
|
||||
Anthony G. Basile
|
||||
Aric Belsito
|
||||
Arvid Picciani
|
||||
Bartosz Brachaczek
|
||||
Benjamin Peterson
|
||||
Bobby Bingham
|
||||
Boris Brezillon
|
||||
Brent Cook
|
||||
Chris Spiegel
|
||||
Clément Vasseur
|
||||
Daniel Micay
|
||||
Daniel Sabogal
|
||||
Daurnimator
|
||||
David Carlier
|
||||
David Edelsohn
|
||||
Denys Vlasenko
|
||||
Dmitry Ivanov
|
||||
Dmitry V. Levin
|
||||
Drew DeVault
|
||||
Emil Renner Berthing
|
||||
Fangrui Song
|
||||
Felix Fietkau
|
||||
Felix Janda
|
||||
Gianluca Anzolin
|
||||
Hauke Mehrtens
|
||||
He X
|
||||
Hiltjo Posthuma
|
||||
Isaac Dunham
|
||||
Jaydeep Patil
|
||||
Jens Gustedt
|
||||
Jeremy Huntwork
|
||||
Jo-Philipp Wich
|
||||
Joakim Sindholt
|
||||
John Spencer
|
||||
Julien Ramseier
|
||||
Justin Cormack
|
||||
Kaarle Ritvanen
|
||||
Khem Raj
|
||||
Kylie McClain
|
||||
Leah Neukirchen
|
||||
Luca Barbato
|
||||
Luka Perkov
|
||||
M Farkas-Dyck (Strake)
|
||||
Mahesh Bodapati
|
||||
Markus Wichmann
|
||||
Masanori Ogino
|
||||
Michael Clark
|
||||
Michael Forney
|
||||
Mikhail Kremnyov
|
||||
Natanael Copa
|
||||
Nicholas J. Kain
|
||||
orc
|
||||
Pascal Cuoq
|
||||
Patrick Oppenlander
|
||||
Petr Hosek
|
||||
Petr Skocik
|
||||
Pierre Carrier
|
||||
Reini Urban
|
||||
Rich Felker
|
||||
Richard Pennington
|
||||
Ryan Fairfax
|
||||
Samuel Holland
|
||||
Segev Finer
|
||||
Shiz
|
||||
sin
|
||||
Solar Designer
|
||||
Stefan Kristiansson
|
||||
Stefan O'Rear
|
||||
Szabolcs Nagy
|
||||
Timo Teräs
|
||||
Trutz Behn
|
||||
Valentin Ochs
|
||||
Will Dietz
|
||||
William Haddon
|
||||
William Pitcock
|
||||
|
||||
Portions of this software are derived from third-party works licensed
|
||||
under terms compatible with the above MIT license:
|
||||
|
||||
The TRE regular expression implementation (src/regex/reg* and
|
||||
src/regex/tre*) is Copyright © 2001-2008 Ville Laurikari and licensed
|
||||
under a 2-clause BSD license (license text in the source files). The
|
||||
included version has been heavily modified by Rich Felker in 2012, in
|
||||
the interests of size, simplicity, and namespace cleanliness.
|
||||
|
||||
Much of the math library code (src/math/* and src/complex/*) is
|
||||
Copyright © 1993,2004 Sun Microsystems or
|
||||
Copyright © 2003-2011 David Schultz or
|
||||
Copyright © 2003-2009 Steven G. Kargl or
|
||||
Copyright © 2003-2009 Bruce D. Evans or
|
||||
Copyright © 2008 Stephen L. Moshier or
|
||||
Copyright © 2017-2018 Arm Limited
|
||||
and labelled as such in comments in the individual source files. All
|
||||
have been licensed under extremely permissive terms.
|
||||
|
||||
The ARM memcpy code (src/string/arm/memcpy_el.S) is Copyright © 2008
|
||||
The Android Open Source Project and is licensed under a two-clause BSD
|
||||
license. It was taken from Bionic libc, used on Android.
|
||||
|
||||
The implementation of DES for crypt (src/crypt/crypt_des.c) is
|
||||
Copyright © 1994 David Burren. It is licensed under a BSD license.
|
||||
|
||||
The implementation of blowfish crypt (src/crypt/crypt_blowfish.c) was
|
||||
originally written by Solar Designer and placed into the public
|
||||
domain. The code also comes with a fallback permissive license for use
|
||||
in jurisdictions that may not recognize the public domain.
|
||||
|
||||
The smoothsort implementation (src/stdlib/qsort.c) is Copyright © 2011
|
||||
Valentin Ochs and is licensed under an MIT-style license.
|
||||
|
||||
The x86_64 port was written by Nicholas J. Kain and is licensed under
|
||||
the standard MIT terms.
|
||||
|
||||
The mips and microblaze ports were originally written by Richard
|
||||
Pennington for use in the ellcc project. The original code was adapted
|
||||
by Rich Felker for build system and code conventions during upstream
|
||||
integration. It is licensed under the standard MIT terms.
|
||||
|
||||
The mips64 port was contributed by Imagination Technologies and is
|
||||
licensed under the standard MIT terms.
|
||||
|
||||
The powerpc port was also originally written by Richard Pennington,
|
||||
and later supplemented and integrated by John Spencer. It is licensed
|
||||
under the standard MIT terms.
|
||||
|
||||
All other files which have no copyright comments are original works
|
||||
produced specifically for use as part of this library, written either
|
||||
by Rich Felker, the main author of the library, or by one or more
|
||||
contibutors listed above. Details on authorship of individual files
|
||||
can be found in the git version control history of the project. The
|
||||
omission of copyright and license comments in each file is in the
|
||||
interest of source tree size.
|
||||
|
||||
In addition, permission is hereby granted for all public header files
|
||||
(include/* and arch/*/bits/*) and crt files intended to be linked into
|
||||
applications (crt/*, ldso/dlstart.c, and arch/*/crt_arch.h) to omit
|
||||
the copyright notice and permission notice otherwise required by the
|
||||
license, and to use these files without any requirement of
|
||||
attribution. These files include substantial contributions from:
|
||||
|
||||
Bobby Bingham
|
||||
John Spencer
|
||||
Nicholas J. Kain
|
||||
Rich Felker
|
||||
Richard Pennington
|
||||
Stefan Kristiansson
|
||||
Szabolcs Nagy
|
||||
|
||||
all of whom have explicitly granted such permission.
|
||||
|
||||
This file previously contained text expressing a belief that most of
|
||||
the files covered by the above exception were sufficiently trivial not
|
||||
to be subject to copyright, resulting in confusion over whether it
|
||||
negated the permissions granted in the license. In the spirit of
|
||||
permissive licensing, and of not having licensing issues being an
|
||||
obstacle to adoption, that text has been removed.
|
|
@ -0,0 +1,10 @@
|
|||
[
|
||||
{
|
||||
"Name" : "musl",
|
||||
"License" : "MIT License",
|
||||
"License File" : "COPYRIGHT",
|
||||
"Version Number" : "1.2.0",
|
||||
"Upstream URL" : "http://www.musl-libc.org/",
|
||||
"Description" : "musl is an MIT-licensed implementation of the standard C library"
|
||||
}
|
||||
]
|
|
@ -0,0 +1,13 @@
|
|||
#include <ctype.h>
|
||||
|
||||
int isalnum(int c)
|
||||
{
|
||||
return isalpha(c) || isdigit(c);
|
||||
}
|
||||
|
||||
int __isalnum_l(int c, locale_t l)
|
||||
{
|
||||
return isalnum(c);
|
||||
}
|
||||
|
||||
weak_alias(__isalnum_l, isalnum_l);
|
|
@ -0,0 +1,7 @@
|
|||
#include <ctype.h>
|
||||
#undef isascii
|
||||
|
||||
int isascii(int c)
|
||||
{
|
||||
return !(c&~0x7f);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#include <ctype.h>
|
||||
#undef isdigit
|
||||
|
||||
int isdigit(int c)
|
||||
{
|
||||
return (unsigned)c-'0' < 10;
|
||||
}
|
||||
|
||||
int __isdigit_l(int c, locale_t l)
|
||||
{
|
||||
return isdigit(c);
|
||||
}
|
||||
|
||||
weak_alias(__isdigit_l, isdigit_l);
|
|
@ -0,0 +1,14 @@
|
|||
#include <ctype.h>
|
||||
#undef islower
|
||||
|
||||
int islower(int c)
|
||||
{
|
||||
return (unsigned)c-'a' < 26;
|
||||
}
|
||||
|
||||
int __islower_l(int c, locale_t l)
|
||||
{
|
||||
return islower(c);
|
||||
}
|
||||
|
||||
weak_alias(__islower_l, islower_l);
|
|
@ -0,0 +1,14 @@
|
|||
#include <ctype.h>
|
||||
#undef isprint
|
||||
|
||||
int isprint(int c)
|
||||
{
|
||||
return (unsigned)c-0x20 < 0x5f;
|
||||
}
|
||||
|
||||
int __isprint_l(int c, locale_t l)
|
||||
{
|
||||
return isprint(c);
|
||||
}
|
||||
|
||||
weak_alias(__isprint_l, isprint_l);
|
|
@ -0,0 +1,14 @@
|
|||
#include <ctype.h>
|
||||
#undef isspace
|
||||
|
||||
int isspace(int c)
|
||||
{
|
||||
return c == ' ' || (unsigned)c-'\t' < 5;
|
||||
}
|
||||
|
||||
int __isspace_l(int c, locale_t l)
|
||||
{
|
||||
return isspace(c);
|
||||
}
|
||||
|
||||
weak_alias(__isspace_l, isspace_l);
|
|
@ -0,0 +1,14 @@
|
|||
#include <ctype.h>
|
||||
#undef isupper
|
||||
|
||||
int isupper(int c)
|
||||
{
|
||||
return (unsigned)c-'A' < 26;
|
||||
}
|
||||
|
||||
int __isupper_l(int c, locale_t l)
|
||||
{
|
||||
return isupper(c);
|
||||
}
|
||||
|
||||
weak_alias(__isupper_l, isupper_l);
|
|
@ -0,0 +1,13 @@
|
|||
#include <ctype.h>
|
||||
|
||||
int isxdigit(int c)
|
||||
{
|
||||
return isdigit(c) || ((unsigned)c|32)-'a' < 6;
|
||||
}
|
||||
|
||||
int __isxdigit_l(int c, locale_t l)
|
||||
{
|
||||
return isxdigit(c);
|
||||
}
|
||||
|
||||
weak_alias(__isxdigit_l, isxdigit_l);
|
|
@ -0,0 +1,14 @@
|
|||
#include <ctype.h>
|
||||
|
||||
int tolower(int c)
|
||||
{
|
||||
if (isupper(c)) return c | 32;
|
||||
return c;
|
||||
}
|
||||
|
||||
int __tolower_l(int c, locale_t l)
|
||||
{
|
||||
return tolower(c);
|
||||
}
|
||||
|
||||
weak_alias(__tolower_l, tolower_l);
|
|
@ -0,0 +1,14 @@
|
|||
#include <ctype.h>
|
||||
|
||||
int toupper(int c)
|
||||
{
|
||||
if (islower(c)) return c & 0x5f;
|
||||
return c;
|
||||
}
|
||||
|
||||
int __toupper_l(int c, locale_t l)
|
||||
{
|
||||
return toupper(c);
|
||||
}
|
||||
|
||||
weak_alias(__toupper_l, toupper_l);
|
|
@ -0,0 +1,105 @@
|
|||
/* This file is sorted such that 'errors' which represent exceptional
|
||||
* conditions under which a correct program may fail come first, followed
|
||||
* by messages that indicate an incorrect program or system failure. The
|
||||
* macro E() along with double-inclusion is used to ensure that ordering
|
||||
* of the strings remains synchronized. */
|
||||
|
||||
E(EILSEQ, "Illegal byte sequence")
|
||||
E(EDOM, "Domain error")
|
||||
E(ERANGE, "Result not representable")
|
||||
|
||||
E(ENOTTY, "Not a tty")
|
||||
E(EACCES, "Permission denied")
|
||||
E(EPERM, "Operation not permitted")
|
||||
E(ENOENT, "No such file or directory")
|
||||
E(ESRCH, "No such process")
|
||||
E(EEXIST, "File exists")
|
||||
|
||||
E(EOVERFLOW, "Value too large for data type")
|
||||
E(ENOSPC, "No space left on device")
|
||||
E(ENOMEM, "Out of memory")
|
||||
|
||||
E(EBUSY, "Resource busy")
|
||||
E(EINTR, "Interrupted system call")
|
||||
E(EAGAIN, "Resource temporarily unavailable")
|
||||
E(ESPIPE, "Invalid seek")
|
||||
|
||||
E(EXDEV, "Cross-device link")
|
||||
E(EROFS, "Read-only file system")
|
||||
E(ENOTEMPTY, "Directory not empty")
|
||||
|
||||
E(ECONNRESET, "Connection reset by peer")
|
||||
E(ETIMEDOUT, "Operation timed out")
|
||||
E(ECONNREFUSED, "Connection refused")
|
||||
E(EHOSTDOWN, "Host is down")
|
||||
E(EHOSTUNREACH, "Host is unreachable")
|
||||
E(EADDRINUSE, "Address in use")
|
||||
|
||||
E(EPIPE, "Broken pipe")
|
||||
E(EIO, "I/O error")
|
||||
E(ENXIO, "No such device or address")
|
||||
E(ENOTBLK, "Block device required")
|
||||
E(ENODEV, "No such device")
|
||||
E(ENOTDIR, "Not a directory")
|
||||
E(EISDIR, "Is a directory")
|
||||
E(ETXTBSY, "Text file busy")
|
||||
E(ENOEXEC, "Exec format error")
|
||||
|
||||
E(EINVAL, "Invalid argument")
|
||||
|
||||
E(E2BIG, "Argument list too long")
|
||||
E(ELOOP, "Symbolic link loop")
|
||||
E(ENAMETOOLONG, "Filename too long")
|
||||
E(ENFILE, "Too many open files in system")
|
||||
E(EMFILE, "No file descriptors available")
|
||||
E(EBADF, "Bad file descriptor")
|
||||
E(ECHILD, "No child process")
|
||||
E(EFAULT, "Bad address")
|
||||
E(EFBIG, "File too large")
|
||||
E(EMLINK, "Too many links")
|
||||
E(ENOLCK, "No locks available")
|
||||
|
||||
E(EDEADLK, "Resource deadlock would occur")
|
||||
E(ENOTRECOVERABLE, "State not recoverable")
|
||||
E(EOWNERDEAD, "Previous owner died")
|
||||
E(ECANCELED, "Operation canceled")
|
||||
E(ENOSYS, "Function not implemented")
|
||||
E(ENOMSG, "No message of desired type")
|
||||
E(EIDRM, "Identifier removed")
|
||||
E(ENOSTR, "Device not a stream")
|
||||
E(ENODATA, "No data available")
|
||||
E(ETIME, "Device timeout")
|
||||
E(ENOSR, "Out of streams resources")
|
||||
E(ENOLINK, "Link has been severed")
|
||||
E(EPROTO, "Protocol error")
|
||||
E(EBADMSG, "Bad message")
|
||||
E(EBADFD, "File descriptor in bad state")
|
||||
E(ENOTSOCK, "Not a socket")
|
||||
E(EDESTADDRREQ, "Destination address required")
|
||||
E(EMSGSIZE, "Message too large")
|
||||
E(EPROTOTYPE, "Protocol wrong type for socket")
|
||||
E(ENOPROTOOPT, "Protocol not available")
|
||||
E(EPROTONOSUPPORT,"Protocol not supported")
|
||||
E(ESOCKTNOSUPPORT,"Socket type not supported")
|
||||
E(ENOTSUP, "Not supported")
|
||||
E(EPFNOSUPPORT, "Protocol family not supported")
|
||||
E(EAFNOSUPPORT, "Address family not supported by protocol")
|
||||
E(EADDRNOTAVAIL,"Address not available")
|
||||
E(ENETDOWN, "Network is down")
|
||||
E(ENETUNREACH, "Network unreachable")
|
||||
E(ENETRESET, "Connection reset by network")
|
||||
E(ECONNABORTED, "Connection aborted")
|
||||
E(ENOBUFS, "No buffer space available")
|
||||
E(EISCONN, "Socket is connected")
|
||||
E(ENOTCONN, "Socket not connected")
|
||||
E(ESHUTDOWN, "Cannot send after socket shutdown")
|
||||
E(EALREADY, "Operation already in progress")
|
||||
E(EINPROGRESS, "Operation in progress")
|
||||
E(ESTALE, "Stale file handle")
|
||||
E(EREMOTEIO, "Remote I/O error")
|
||||
E(EDQUOT, "Quota exceeded")
|
||||
E(ENOMEDIUM, "No medium found")
|
||||
E(EMEDIUMTYPE, "Wrong medium type")
|
||||
E(EMULTIHOP, "Multihop attempted")
|
||||
|
||||
E(0, "No error information")
|
|
@ -0,0 +1,36 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "locale_impl.h"
|
||||
|
||||
#define E(a,b) ((unsigned char)a),
|
||||
static const unsigned char errid[] = {
|
||||
#include "__strerror.h"
|
||||
};
|
||||
|
||||
#undef E
|
||||
#define E(a,b) b "\0"
|
||||
static const char errmsg[] =
|
||||
#include "__strerror.h"
|
||||
;
|
||||
|
||||
char *__strerror_l(int e, locale_t loc)
|
||||
{
|
||||
const char *s;
|
||||
int i;
|
||||
/* mips has one error code outside of the 8-bit range due to a
|
||||
* historical typo, so we just remap it. */
|
||||
if (EDQUOT==1133) {
|
||||
if (e==109) e=-1;
|
||||
else if (e==EDQUOT) e=109;
|
||||
}
|
||||
for (i=0; errid[i] && errid[i] != e; i++);
|
||||
for (s=errmsg; i; s++, i--) for (; *s; s++);
|
||||
return (char *)s;
|
||||
}
|
||||
|
||||
char *strerror(int e)
|
||||
{
|
||||
return __strerror_l(e, NULL);
|
||||
}
|
||||
|
||||
weak_alias(__strerror_l, strerror_l);
|
|
@ -0,0 +1,8 @@
|
|||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
#include "los_task.h"
|
||||
|
||||
void abort(void) {
|
||||
LOS_Panic("System was being aborted\n");
|
||||
while (1);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
#include "assert.h"
|
||||
#include "los_context.h"
|
||||
#include "los_debug.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void __assert(const char* file, int line, const char* expr) {
|
||||
PRINT_ERR("__assert error: %s, %d, %s\n", file, line, expr);
|
||||
LOS_Panic("__assert error:\n");
|
||||
while (1);
|
||||
}
|
||||
|
||||
void __assert2(const char* file, int line, const char* func, const char* expr) {
|
||||
PRINT_ERR("%s:%d: %s: assertion \"%s\" failed\n", file, line, func, expr);
|
||||
LOS_Panic("__assert error:\n");
|
||||
while (1);
|
||||
}
|
||||
|
||||
void __assert_fail(const char* expr, const char* file, int line, const char* func) {
|
||||
PRINT_ERR("%s:%d: %s: assertion \"%s\" failed\n", file, line, func, expr);
|
||||
LOS_Panic("__assert error:\n");
|
||||
while (1);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef FEATURES_H
|
||||
#define FEATURES_H
|
||||
|
||||
#include "../../include/features.h"
|
||||
|
||||
#define weak __attribute__((__weak__))
|
||||
#define hidden __attribute__((__visibility__("hidden")))
|
||||
#ifndef weak_alias
|
||||
#define weak_alias(old, new) \
|
||||
extern __typeof(old) new __attribute__((__weak__, __alias__(#old)))
|
||||
#endif
|
||||
#ifndef strong_alias
|
||||
#define strong_alias(old, new) \
|
||||
extern __typeof(old) new __attribute__((__alias__(#old)))
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef STRING_H
|
||||
#define STRING_H
|
||||
|
||||
#include "features.h"
|
||||
#include "../../include/string.h"
|
||||
|
||||
hidden void *__memrchr(const void *, int, size_t);
|
||||
hidden char *__stpcpy(char *, const char *);
|
||||
hidden char *__stpncpy(char *, const char *, size_t);
|
||||
hidden char *__strchrnul(const char *, int);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,100 @@
|
|||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include "shgetc.h"
|
||||
|
||||
/* Lookup table for digit values. -1==255>=36 -> invalid */
|
||||
static const unsigned char table[] = { -1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
|
||||
-1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
|
||||
25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1,
|
||||
-1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
|
||||
25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
};
|
||||
|
||||
unsigned long long __intscan(FILE *f, unsigned base, int pok, unsigned long long lim)
|
||||
{
|
||||
const unsigned char *val = table+1;
|
||||
int c, neg=0;
|
||||
unsigned x;
|
||||
unsigned long long y;
|
||||
if (base > 36 || base == 1) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
while (isspace((c=shgetc(f))));
|
||||
if (c=='+' || c=='-') {
|
||||
neg = -(c=='-');
|
||||
c = shgetc(f);
|
||||
}
|
||||
if ((base == 0 || base == 16) && c=='0') {
|
||||
c = shgetc(f);
|
||||
if ((c|32)=='x') {
|
||||
c = shgetc(f);
|
||||
if (val[c]>=16) {
|
||||
shunget(f);
|
||||
if (pok) shunget(f);
|
||||
else shlim(f, 0);
|
||||
return 0;
|
||||
}
|
||||
base = 16;
|
||||
} else if (base == 0) {
|
||||
base = 8;
|
||||
}
|
||||
} else {
|
||||
if (base == 0) base = 10;
|
||||
if (val[c] >= base) {
|
||||
shunget(f);
|
||||
shlim(f, 0);
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (base == 10) {
|
||||
for (x=0; c-'0'<10U && x<=UINT_MAX/10-1; c=shgetc(f))
|
||||
x = x*10 + (c-'0');
|
||||
for (y=x; c-'0'<10U && y<=ULLONG_MAX/10 && 10*y<=ULLONG_MAX-(c-'0'); c=shgetc(f))
|
||||
y = y*10 + (c-'0');
|
||||
if (c-'0'>=10U) goto done;
|
||||
} else if (!(base & base-1)) {
|
||||
int bs = "\0\1\2\4\7\3\6\5"[(0x17*base)>>5&7];
|
||||
for (x=0; val[c]<base && x<=UINT_MAX/32; c=shgetc(f))
|
||||
x = x<<bs | val[c];
|
||||
for (y=x; val[c]<base && y<=ULLONG_MAX>>bs; c=shgetc(f))
|
||||
y = y<<bs | val[c];
|
||||
} else {
|
||||
for (x=0; val[c]<base && x<=UINT_MAX/36-1; c=shgetc(f))
|
||||
x = x*base + val[c];
|
||||
for (y=x; val[c]<base && y<=ULLONG_MAX/base && base*y<=ULLONG_MAX-val[c]; c=shgetc(f))
|
||||
y = y*base + val[c];
|
||||
}
|
||||
if (val[c]<base) {
|
||||
for (; val[c]<base; c=shgetc(f));
|
||||
errno = ERANGE;
|
||||
y = lim;
|
||||
if (lim&1) neg = 0;
|
||||
}
|
||||
done:
|
||||
shunget(f);
|
||||
if (y>=lim) {
|
||||
if (!(lim&1) && !neg) {
|
||||
errno = ERANGE;
|
||||
return lim-1;
|
||||
} else if (y>lim) {
|
||||
errno = ERANGE;
|
||||
return lim;
|
||||
}
|
||||
}
|
||||
return (y^neg)-neg;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef INTSCAN_H
|
||||
#define INTSCAN_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../include/features.h"
|
||||
|
||||
hidden unsigned long long __intscan(FILE *, unsigned, int, unsigned long long);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,43 @@
|
|||
#ifndef _LOCALE_IMPL_H
|
||||
#define _LOCALE_IMPL_H
|
||||
|
||||
#include <locale.h>
|
||||
#include <stdlib.h>
|
||||
#include "libc.h"
|
||||
#include "../include/features.h"
|
||||
|
||||
#define LOCALE_NAME_MAX 23
|
||||
|
||||
struct __locale_map {
|
||||
const void *map;
|
||||
size_t map_size;
|
||||
char name[LOCALE_NAME_MAX+1];
|
||||
const struct __locale_map *next;
|
||||
};
|
||||
|
||||
extern hidden const struct __locale_map __c_dot_utf8;
|
||||
extern hidden const struct __locale_struct __c_locale;
|
||||
extern hidden const struct __locale_struct __c_dot_utf8_locale;
|
||||
|
||||
hidden const struct __locale_map *__get_locale(int, const char *);
|
||||
hidden const char *__mo_lookup(const void *, size_t, const char *);
|
||||
hidden const char *__lctrans(const char *, const struct __locale_map *);
|
||||
hidden const char *__lctrans_cur(const char *);
|
||||
hidden const char *__lctrans_impl(const char *, const struct __locale_map *);
|
||||
hidden int __loc_is_allocated(locale_t);
|
||||
hidden char *__gettextdomain(void);
|
||||
|
||||
|
||||
#define LOC_MAP_FAILED ((const struct __locale_map *)-1)
|
||||
|
||||
#define LCTRANS(msg, lc, loc) __lctrans(msg, (loc)->cat[(lc)])
|
||||
#define LCTRANS_CUR(msg) __lctrans_cur(msg)
|
||||
|
||||
#define C_LOCALE ((locale_t)&__c_locale)
|
||||
#define UTF8_LOCALE ((locale_t)&__c_dot_utf8_locale)
|
||||
|
||||
|
||||
#undef MB_CUR_MAX
|
||||
#define MB_CUR_MAX (CURRENT_UTF8 ? 4 : 1)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,37 @@
|
|||
#include "shgetc.h"
|
||||
|
||||
/* The shcnt field stores the number of bytes read so far, offset by
|
||||
* the value of buf-rpos at the last function call (__shlim or __shgetc),
|
||||
* so that between calls the inline shcnt macro can add rpos-buf to get
|
||||
* the actual count. */
|
||||
|
||||
void __shlim(FILE *f, off_t lim)
|
||||
{
|
||||
f->shlim = lim;
|
||||
f->shcnt = f->buf - f->rpos;
|
||||
/* If lim is nonzero, rend must be a valid pointer. */
|
||||
if (lim && f->rend - f->rpos > lim)
|
||||
f->shend = f->rpos + lim;
|
||||
else
|
||||
f->shend = f->rend;
|
||||
}
|
||||
|
||||
int __shgetc(FILE *f)
|
||||
{
|
||||
int c;
|
||||
off_t cnt = shcnt(f);
|
||||
if (f->shlim && cnt >= f->shlim || (c=__uflow(f)) < 0) {
|
||||
f->shcnt = f->buf - f->rpos + cnt;
|
||||
f->shend = f->rpos;
|
||||
f->shlim = -1;
|
||||
return EOF;
|
||||
}
|
||||
cnt++;
|
||||
if (f->shlim && f->rend - f->rpos > f->shlim - cnt)
|
||||
f->shend = f->rpos + (f->shlim - cnt);
|
||||
else
|
||||
f->shend = f->rend;
|
||||
f->shcnt = f->buf - f->rpos + cnt;
|
||||
if (f->rpos[-1] != c) f->rpos[-1] = c;
|
||||
return c;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#include "stdio_impl.h"
|
||||
#include "../include/features.h"
|
||||
|
||||
/* Scan helper "stdio" functions for use by scanf-family and strto*-family
|
||||
* functions. These accept either a valid stdio FILE, or a minimal pseudo
|
||||
* FILE whose buffer pointers point into a null-terminated string. In the
|
||||
* latter case, the sh_fromstring macro should be used to setup the FILE;
|
||||
* the rest of the structure can be left uninitialized.
|
||||
*
|
||||
* To begin using these functions, shlim must first be called on the FILE
|
||||
* to set a field width limit, or 0 for no limit. For string pseudo-FILEs,
|
||||
* a nonzero limit is not valid and produces undefined behavior. After that,
|
||||
* shgetc, shunget, and shcnt are valid as long as no other stdio functions
|
||||
* are called on the stream.
|
||||
*
|
||||
* When used with a real FILE object, shunget has only one byte of pushback
|
||||
* available. Further shunget (up to a limit of the stdio UNGET buffer size)
|
||||
* will adjust the position but will not restore the data to be read again.
|
||||
* This functionality is needed for the wcsto*-family functions, where it's
|
||||
* okay because the FILE will be discarded immediately anyway. When used
|
||||
* with string pseudo-FILEs, shunget has unlimited pushback, back to the
|
||||
* beginning of the string. */
|
||||
|
||||
hidden void __shlim(FILE *, off_t);
|
||||
hidden int __shgetc(FILE *);
|
||||
|
||||
#define shcnt(f) ((f)->shcnt + ((f)->rpos - (f)->buf))
|
||||
#define shlim(f, lim) __shlim((f), (lim))
|
||||
#define shgetc(f) (((f)->rpos != (f)->shend) ? *(f)->rpos++ : __shgetc(f))
|
||||
#define shunget(f) ((f)->shlim>=0 ? (void)(f)->rpos-- : (void)0)
|
||||
|
||||
#define sh_fromstring(f, s) \
|
||||
((f)->buf = (f)->rpos = (void *)(s), (f)->rend = (void*)-1)
|
|
@ -0,0 +1,87 @@
|
|||
#ifndef _STDIO_IMPL_H
|
||||
#define _STDIO_IMPL_H
|
||||
|
||||
#define __NEED_struct__IO_FILE
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../include/features.h"
|
||||
|
||||
#define UNGET 8
|
||||
|
||||
#define FLOCK(f) __lockfile(f)
|
||||
#define FUNLOCK(f) __unlockfile(f)
|
||||
|
||||
#define F_PERM 1
|
||||
#define F_NORD 4
|
||||
#define F_NOWR 8
|
||||
#define F_EOF 16
|
||||
#define F_ERR 32
|
||||
#define F_SVB 64
|
||||
#define F_APP 128
|
||||
|
||||
#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_MUTEX_INITIALIZER
|
||||
extern hidden FILE *volatile __stdin_used;
|
||||
extern hidden FILE *volatile __stdout_used;
|
||||
extern hidden FILE *volatile __stderr_used;
|
||||
|
||||
hidden int __lockfile(FILE *);
|
||||
hidden int __unlockfile(FILE *);
|
||||
|
||||
hidden size_t __stdio_read(FILE *, unsigned char *, size_t);
|
||||
hidden size_t __stdio_write(FILE *, const unsigned char *, size_t);
|
||||
hidden size_t __stdout_write(FILE *, const unsigned char *, size_t);
|
||||
hidden off_t __stdio_seek(FILE *, off_t, int);
|
||||
hidden int __stdio_close(FILE *);
|
||||
|
||||
hidden size_t __string_read(FILE *, unsigned char *, size_t);
|
||||
|
||||
hidden int __toread(FILE *);
|
||||
hidden int __towrite(FILE *);
|
||||
|
||||
hidden void __stdio_exit(void);
|
||||
hidden void __stdio_exit_needed(void);
|
||||
|
||||
#if defined(__PIC__) && (100*__GNUC__+__GNUC_MINOR__ >= 303)
|
||||
__attribute__((visibility("protected")))
|
||||
#endif
|
||||
int __overflow(FILE *, int), __uflow(FILE *);
|
||||
|
||||
hidden int __fseeko(FILE *, off_t, int);
|
||||
hidden int __fseeko_unlocked(FILE *, off_t, int);
|
||||
hidden off_t __ftello(FILE *);
|
||||
hidden off_t __ftello_unlocked(FILE *);
|
||||
hidden size_t __fwritex(const unsigned char *, size_t, FILE *);
|
||||
hidden int __putc_unlocked(int, FILE *);
|
||||
|
||||
hidden FILE *__fdopen(int, const char *);
|
||||
hidden int __fmodeflags(const char *);
|
||||
|
||||
hidden FILE *__ofl_add(FILE *f);
|
||||
hidden FILE **__ofl_lock(void);
|
||||
hidden void __ofl_unlock(void);
|
||||
|
||||
struct __pthread;
|
||||
hidden void __register_locked_file(FILE *, struct __pthread *);
|
||||
hidden void __unlist_locked_file(FILE *);
|
||||
hidden void __do_orphaned_stdio_locks(void);
|
||||
|
||||
#define MAYBE_WAITERS 0x40000000
|
||||
|
||||
hidden void __getopt_msg(const char *, const char *, const char *, size_t);
|
||||
|
||||
#define feof(f) ((f)->flags & F_EOF)
|
||||
#define ferror(f) ((f)->flags & F_ERR)
|
||||
|
||||
#define getc_unlocked(f) \
|
||||
( ((f)->rpos != (f)->rend) ? *(f)->rpos++ : __uflow((f)) )
|
||||
|
||||
#define putc_unlocked(c, f) \
|
||||
( (((unsigned char)(c)!=(f)->lbf && (f)->wpos!=(f)->wend)) \
|
||||
? *(f)->wpos++ = (unsigned char)(c) \
|
||||
: __overflow((f),(unsigned char)(c)) )
|
||||
|
||||
/* Caller-allocated FILE * operations */
|
||||
hidden FILE *__fopen_rb_ca(const char *, FILE *, unsigned char *, size_t);
|
||||
hidden int __fclose_ca(FILE *);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,6 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
int abs(int a)
|
||||
{
|
||||
return a>0 ? a : -a;
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* Shared data between exp, exp2 and pow.
|
||||
*
|
||||
* Copyright (c) 2018, Arm Limited.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "exp_data.h"
|
||||
|
||||
#define N (1 << EXP_TABLE_BITS)
|
||||
|
||||
const struct exp_data __exp_data1 = {
|
||||
// N/ln2
|
||||
.invln2N = 0x1.71547652b82fep0 * N,
|
||||
// -ln2/N
|
||||
.negln2hiN = -0x1.62e42fefa0000p-8,
|
||||
.negln2loN = -0x1.cf79abc9e3b3ap-47,
|
||||
// Used for rounding when !TOINT_INTRINSICS
|
||||
#if EXP_USE_TOINT_NARROW
|
||||
.shift = 0x1800000000.8p0,
|
||||
#else
|
||||
.shift = 0x1.8p52,
|
||||
#endif
|
||||
// exp polynomial coefficients.
|
||||
.poly = {
|
||||
// abs error: 1.555*2^-66
|
||||
// ulp error: 0.509 (0.511 without fma)
|
||||
// if |x| < ln2/256+eps
|
||||
// abs error if |x| < ln2/256+0x1p-15: 1.09*2^-65
|
||||
// abs error if |x| < ln2/128: 1.7145*2^-56
|
||||
0x1.ffffffffffdbdp-2,
|
||||
0x1.555555555543cp-3,
|
||||
0x1.55555cf172b91p-5,
|
||||
0x1.1111167a4d017p-7,
|
||||
},
|
||||
.exp2_shift = 0x1.8p52 / N,
|
||||
// exp2 polynomial coefficients.
|
||||
.exp2_poly = {
|
||||
// abs error: 1.2195*2^-65
|
||||
// ulp error: 0.507 (0.511 without fma)
|
||||
// if |x| < 1/256
|
||||
// abs error if |x| < 1/128: 1.9941*2^-56
|
||||
0x1.62e42fefa39efp-1,
|
||||
0x1.ebfbdff82c424p-3,
|
||||
0x1.c6b08d70cf4b5p-5,
|
||||
0x1.3b2abd24650ccp-7,
|
||||
0x1.5d7e09b4e3a84p-10,
|
||||
},
|
||||
// 2^(k/N) ~= H[k]*(1 + T[k]) for int k in [0,N)
|
||||
// tab[2*k] = asuint64(T[k])
|
||||
// tab[2*k+1] = asuint64(H[k]) - (k << 52)/N
|
||||
.tab = {
|
||||
0x0, 0x3ff0000000000000,
|
||||
0x3c9b3b4f1a88bf6e, 0x3feff63da9fb3335,
|
||||
0xbc7160139cd8dc5d, 0x3fefec9a3e778061,
|
||||
0xbc905e7a108766d1, 0x3fefe315e86e7f85,
|
||||
0x3c8cd2523567f613, 0x3fefd9b0d3158574,
|
||||
0xbc8bce8023f98efa, 0x3fefd06b29ddf6de,
|
||||
0x3c60f74e61e6c861, 0x3fefc74518759bc8,
|
||||
0x3c90a3e45b33d399, 0x3fefbe3ecac6f383,
|
||||
0x3c979aa65d837b6d, 0x3fefb5586cf9890f,
|
||||
0x3c8eb51a92fdeffc, 0x3fefac922b7247f7,
|
||||
0x3c3ebe3d702f9cd1, 0x3fefa3ec32d3d1a2,
|
||||
0xbc6a033489906e0b, 0x3fef9b66affed31b,
|
||||
0xbc9556522a2fbd0e, 0x3fef9301d0125b51,
|
||||
0xbc5080ef8c4eea55, 0x3fef8abdc06c31cc,
|
||||
0xbc91c923b9d5f416, 0x3fef829aaea92de0,
|
||||
0x3c80d3e3e95c55af, 0x3fef7a98c8a58e51,
|
||||
0xbc801b15eaa59348, 0x3fef72b83c7d517b,
|
||||
0xbc8f1ff055de323d, 0x3fef6af9388c8dea,
|
||||
0x3c8b898c3f1353bf, 0x3fef635beb6fcb75,
|
||||
0xbc96d99c7611eb26, 0x3fef5be084045cd4,
|
||||
0x3c9aecf73e3a2f60, 0x3fef54873168b9aa,
|
||||
0xbc8fe782cb86389d, 0x3fef4d5022fcd91d,
|
||||
0x3c8a6f4144a6c38d, 0x3fef463b88628cd6,
|
||||
0x3c807a05b0e4047d, 0x3fef3f49917ddc96,
|
||||
0x3c968efde3a8a894, 0x3fef387a6e756238,
|
||||
0x3c875e18f274487d, 0x3fef31ce4fb2a63f,
|
||||
0x3c80472b981fe7f2, 0x3fef2b4565e27cdd,
|
||||
0xbc96b87b3f71085e, 0x3fef24dfe1f56381,
|
||||
0x3c82f7e16d09ab31, 0x3fef1e9df51fdee1,
|
||||
0xbc3d219b1a6fbffa, 0x3fef187fd0dad990,
|
||||
0x3c8b3782720c0ab4, 0x3fef1285a6e4030b,
|
||||
0x3c6e149289cecb8f, 0x3fef0cafa93e2f56,
|
||||
0x3c834d754db0abb6, 0x3fef06fe0a31b715,
|
||||
0x3c864201e2ac744c, 0x3fef0170fc4cd831,
|
||||
0x3c8fdd395dd3f84a, 0x3feefc08b26416ff,
|
||||
0xbc86a3803b8e5b04, 0x3feef6c55f929ff1,
|
||||
0xbc924aedcc4b5068, 0x3feef1a7373aa9cb,
|
||||
0xbc9907f81b512d8e, 0x3feeecae6d05d866,
|
||||
0xbc71d1e83e9436d2, 0x3feee7db34e59ff7,
|
||||
0xbc991919b3ce1b15, 0x3feee32dc313a8e5,
|
||||
0x3c859f48a72a4c6d, 0x3feedea64c123422,
|
||||
0xbc9312607a28698a, 0x3feeda4504ac801c,
|
||||
0xbc58a78f4817895b, 0x3feed60a21f72e2a,
|
||||
0xbc7c2c9b67499a1b, 0x3feed1f5d950a897,
|
||||
0x3c4363ed60c2ac11, 0x3feece086061892d,
|
||||
0x3c9666093b0664ef, 0x3feeca41ed1d0057,
|
||||
0x3c6ecce1daa10379, 0x3feec6a2b5c13cd0,
|
||||
0x3c93ff8e3f0f1230, 0x3feec32af0d7d3de,
|
||||
0x3c7690cebb7aafb0, 0x3feebfdad5362a27,
|
||||
0x3c931dbdeb54e077, 0x3feebcb299fddd0d,
|
||||
0xbc8f94340071a38e, 0x3feeb9b2769d2ca7,
|
||||
0xbc87deccdc93a349, 0x3feeb6daa2cf6642,
|
||||
0xbc78dec6bd0f385f, 0x3feeb42b569d4f82,
|
||||
0xbc861246ec7b5cf6, 0x3feeb1a4ca5d920f,
|
||||
0x3c93350518fdd78e, 0x3feeaf4736b527da,
|
||||
0x3c7b98b72f8a9b05, 0x3feead12d497c7fd,
|
||||
0x3c9063e1e21c5409, 0x3feeab07dd485429,
|
||||
0x3c34c7855019c6ea, 0x3feea9268a5946b7,
|
||||
0x3c9432e62b64c035, 0x3feea76f15ad2148,
|
||||
0xbc8ce44a6199769f, 0x3feea5e1b976dc09,
|
||||
0xbc8c33c53bef4da8, 0x3feea47eb03a5585,
|
||||
0xbc845378892be9ae, 0x3feea34634ccc320,
|
||||
0xbc93cedd78565858, 0x3feea23882552225,
|
||||
0x3c5710aa807e1964, 0x3feea155d44ca973,
|
||||
0xbc93b3efbf5e2228, 0x3feea09e667f3bcd,
|
||||
0xbc6a12ad8734b982, 0x3feea012750bdabf,
|
||||
0xbc6367efb86da9ee, 0x3fee9fb23c651a2f,
|
||||
0xbc80dc3d54e08851, 0x3fee9f7df9519484,
|
||||
0xbc781f647e5a3ecf, 0x3fee9f75e8ec5f74,
|
||||
0xbc86ee4ac08b7db0, 0x3fee9f9a48a58174,
|
||||
0xbc8619321e55e68a, 0x3fee9feb564267c9,
|
||||
0x3c909ccb5e09d4d3, 0x3feea0694fde5d3f,
|
||||
0xbc7b32dcb94da51d, 0x3feea11473eb0187,
|
||||
0x3c94ecfd5467c06b, 0x3feea1ed0130c132,
|
||||
0x3c65ebe1abd66c55, 0x3feea2f336cf4e62,
|
||||
0xbc88a1c52fb3cf42, 0x3feea427543e1a12,
|
||||
0xbc9369b6f13b3734, 0x3feea589994cce13,
|
||||
0xbc805e843a19ff1e, 0x3feea71a4623c7ad,
|
||||
0xbc94d450d872576e, 0x3feea8d99b4492ed,
|
||||
0x3c90ad675b0e8a00, 0x3feeaac7d98a6699,
|
||||
0x3c8db72fc1f0eab4, 0x3feeace5422aa0db,
|
||||
0xbc65b6609cc5e7ff, 0x3feeaf3216b5448c,
|
||||
0x3c7bf68359f35f44, 0x3feeb1ae99157736,
|
||||
0xbc93091fa71e3d83, 0x3feeb45b0b91ffc6,
|
||||
0xbc5da9b88b6c1e29, 0x3feeb737b0cdc5e5,
|
||||
0xbc6c23f97c90b959, 0x3feeba44cbc8520f,
|
||||
0xbc92434322f4f9aa, 0x3feebd829fde4e50,
|
||||
0xbc85ca6cd7668e4b, 0x3feec0f170ca07ba,
|
||||
0x3c71affc2b91ce27, 0x3feec49182a3f090,
|
||||
0x3c6dd235e10a73bb, 0x3feec86319e32323,
|
||||
0xbc87c50422622263, 0x3feecc667b5de565,
|
||||
0x3c8b1c86e3e231d5, 0x3feed09bec4a2d33,
|
||||
0xbc91bbd1d3bcbb15, 0x3feed503b23e255d,
|
||||
0x3c90cc319cee31d2, 0x3feed99e1330b358,
|
||||
0x3c8469846e735ab3, 0x3feede6b5579fdbf,
|
||||
0xbc82dfcd978e9db4, 0x3feee36bbfd3f37a,
|
||||
0x3c8c1a7792cb3387, 0x3feee89f995ad3ad,
|
||||
0xbc907b8f4ad1d9fa, 0x3feeee07298db666,
|
||||
0xbc55c3d956dcaeba, 0x3feef3a2b84f15fb,
|
||||
0xbc90a40e3da6f640, 0x3feef9728de5593a,
|
||||
0xbc68d6f438ad9334, 0x3feeff76f2fb5e47,
|
||||
0xbc91eee26b588a35, 0x3fef05b030a1064a,
|
||||
0x3c74ffd70a5fddcd, 0x3fef0c1e904bc1d2,
|
||||
0xbc91bdfbfa9298ac, 0x3fef12c25bd71e09,
|
||||
0x3c736eae30af0cb3, 0x3fef199bdd85529c,
|
||||
0x3c8ee3325c9ffd94, 0x3fef20ab5fffd07a,
|
||||
0x3c84e08fd10959ac, 0x3fef27f12e57d14b,
|
||||
0x3c63cdaf384e1a67, 0x3fef2f6d9406e7b5,
|
||||
0x3c676b2c6c921968, 0x3fef3720dcef9069,
|
||||
0xbc808a1883ccb5d2, 0x3fef3f0b555dc3fa,
|
||||
0xbc8fad5d3ffffa6f, 0x3fef472d4a07897c,
|
||||
0xbc900dae3875a949, 0x3fef4f87080d89f2,
|
||||
0x3c74a385a63d07a7, 0x3fef5818dcfba487,
|
||||
0xbc82919e2040220f, 0x3fef60e316c98398,
|
||||
0x3c8e5a50d5c192ac, 0x3fef69e603db3285,
|
||||
0x3c843a59ac016b4b, 0x3fef7321f301b460,
|
||||
0xbc82d52107b43e1f, 0x3fef7c97337b9b5f,
|
||||
0xbc892ab93b470dc9, 0x3fef864614f5a129,
|
||||
0x3c74b604603a88d3, 0x3fef902ee78b3ff6,
|
||||
0x3c83c5ec519d7271, 0x3fef9a51fbc74c83,
|
||||
0xbc8ff7128fd391f0, 0x3fefa4afa2a490da,
|
||||
0xbc8dae98e223747d, 0x3fefaf482d8e67f1,
|
||||
0x3c8ec3bc41aa2008, 0x3fefba1bee615a27,
|
||||
0x3c842b94c3a9eb32, 0x3fefc52b376bba97,
|
||||
0x3c8a64a931d185ee, 0x3fefd0765b6e4540,
|
||||
0xbc8e37bae43be3ed, 0x3fefdbfdad9cbe14,
|
||||
0x3c77893b4d91cd9d, 0x3fefe7c1819e90d8,
|
||||
0x3c5305c14160cc89, 0x3feff3c22b8f71f1,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Arm Limited.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#ifndef _EXP_DATA_H
|
||||
#define _EXP_DATA_H
|
||||
|
||||
#include <features.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define EXP_TABLE_BITS 7
|
||||
#define EXP_POLY_ORDER 5
|
||||
#define EXP_USE_TOINT_NARROW 0
|
||||
#define EXP2_POLY_ORDER 5
|
||||
extern const struct exp_data {
|
||||
double invln2N;
|
||||
double shift;
|
||||
double negln2hiN;
|
||||
double negln2loN;
|
||||
double poly[4]; /* Last four coefficients. */
|
||||
double exp2_shift;
|
||||
double exp2_poly[EXP2_POLY_ORDER];
|
||||
uint64_t tab[2*(1 << EXP_TABLE_BITS)];
|
||||
} __exp_data1;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,272 @@
|
|||
#ifndef _LIBM_H
|
||||
#define _LIBM_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <endian.h>
|
||||
#include "../include/features.h"
|
||||
|
||||
|
||||
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
|
||||
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
union ldshape {
|
||||
long double f;
|
||||
struct {
|
||||
uint64_t m;
|
||||
uint16_t se;
|
||||
} i;
|
||||
};
|
||||
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __BIG_ENDIAN
|
||||
/* This is the m68k variant of 80-bit long double, and this definition only works
|
||||
* on archs where the alignment requirement of uint64_t is <= 4. */
|
||||
union ldshape {
|
||||
long double f;
|
||||
struct {
|
||||
uint16_t se;
|
||||
uint16_t pad;
|
||||
uint64_t m;
|
||||
} i;
|
||||
};
|
||||
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
union ldshape {
|
||||
long double f;
|
||||
struct {
|
||||
uint64_t lo;
|
||||
uint32_t mid;
|
||||
uint16_t top;
|
||||
uint16_t se;
|
||||
} i;
|
||||
struct {
|
||||
uint64_t lo;
|
||||
uint64_t hi;
|
||||
} i2;
|
||||
};
|
||||
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __BIG_ENDIAN
|
||||
union ldshape {
|
||||
long double f;
|
||||
struct {
|
||||
uint16_t se;
|
||||
uint16_t top;
|
||||
uint32_t mid;
|
||||
uint64_t lo;
|
||||
} i;
|
||||
struct {
|
||||
uint64_t hi;
|
||||
uint64_t lo;
|
||||
} i2;
|
||||
};
|
||||
#else
|
||||
#error Unsupported long double representation
|
||||
#endif
|
||||
|
||||
/* Support non-nearest rounding mode. */
|
||||
#define WANT_ROUNDING 1
|
||||
/* Support signaling NaNs. */
|
||||
#define WANT_SNAN 0
|
||||
|
||||
#if WANT_SNAN
|
||||
#error SNaN is unsupported
|
||||
#else
|
||||
#define issignalingf_inline(x) 0
|
||||
#define issignaling_inline(x) 0
|
||||
#endif
|
||||
|
||||
#ifndef TOINT_INTRINSICS
|
||||
#define TOINT_INTRINSICS 0
|
||||
#endif
|
||||
|
||||
#if TOINT_INTRINSICS
|
||||
/* Round x to nearest int in all rounding modes, ties have to be rounded
|
||||
consistently with converttoint so the results match. If the result
|
||||
would be outside of [-2^31, 2^31-1] then the semantics is unspecified. */
|
||||
static double_t roundtoint(double_t);
|
||||
|
||||
/* Convert x to nearest int in all rounding modes, ties have to be rounded
|
||||
consistently with roundtoint. If the result is not representible in an
|
||||
int32_t then the semantics is unspecified. */
|
||||
static int32_t converttoint(double_t);
|
||||
#endif
|
||||
|
||||
/* Helps static branch prediction so hot path can be better optimized. */
|
||||
#ifdef __GNUC__
|
||||
#define predict_true(x) __builtin_expect(!!(x), 1)
|
||||
#define predict_false(x) __builtin_expect(x, 0)
|
||||
#else
|
||||
#define predict_true(x) (x)
|
||||
#define predict_false(x) (x)
|
||||
#endif
|
||||
|
||||
/* Evaluate an expression as the specified type. With standard excess
|
||||
precision handling a type cast or assignment is enough (with
|
||||
-ffloat-store an assignment is required, in old compilers argument
|
||||
passing and return statement may not drop excess precision). */
|
||||
|
||||
static inline float eval_as_float(float x)
|
||||
{
|
||||
float y = x;
|
||||
return y;
|
||||
}
|
||||
|
||||
static inline double eval_as_double(double x)
|
||||
{
|
||||
double y = x;
|
||||
return y;
|
||||
}
|
||||
|
||||
/* fp_barrier returns its input, but limits code transformations
|
||||
as if it had a side-effect (e.g. observable io) and returned
|
||||
an arbitrary value. */
|
||||
|
||||
#ifndef fp_barrierf
|
||||
#define fp_barrierf fp_barrierf
|
||||
static inline float fp_barrierf(float x)
|
||||
{
|
||||
volatile float y = x;
|
||||
return y;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef fp_barrier
|
||||
#define fp_barrier fp_barrier
|
||||
static inline double fp_barrier(double x)
|
||||
{
|
||||
volatile double y = x;
|
||||
return y;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef fp_barrierl
|
||||
#define fp_barrierl fp_barrierl
|
||||
static inline long double fp_barrierl(long double x)
|
||||
{
|
||||
volatile long double y = x;
|
||||
return y;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* fp_force_eval ensures that the input value is computed when that's
|
||||
otherwise unused. To prevent the constant folding of the input
|
||||
expression, an additional fp_barrier may be needed or a compilation
|
||||
mode that does so (e.g. -frounding-math in gcc). Then it can be
|
||||
used to evaluate an expression for its fenv side-effects only. */
|
||||
|
||||
#ifndef fp_force_evalf
|
||||
#define fp_force_evalf fp_force_evalf
|
||||
static inline void fp_force_evalf(float x)
|
||||
{
|
||||
volatile float y;
|
||||
y = x;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef fp_force_eval
|
||||
#define fp_force_eval fp_force_eval
|
||||
static inline void fp_force_eval(double x)
|
||||
{
|
||||
volatile double y;
|
||||
y = x;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef fp_force_evall
|
||||
#define fp_force_evall fp_force_evall
|
||||
static inline void fp_force_evall(long double x)
|
||||
{
|
||||
volatile long double y;
|
||||
y = x;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define FORCE_EVAL(x) do { \
|
||||
if (sizeof(x) == sizeof(float)) { \
|
||||
fp_force_evalf(x); \
|
||||
} else if (sizeof(x) == sizeof(double)) { \
|
||||
fp_force_eval(x); \
|
||||
} else { \
|
||||
fp_force_evall(x); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define asuint(f) ((union{float _f; uint32_t _i;}){f})._i
|
||||
#define asfloat(i) ((union{uint32_t _i; float _f;}){i})._f
|
||||
#define asuint64(f) ((union{double _f; uint64_t _i;}){f})._i
|
||||
#define asdouble(i) ((union{uint64_t _i; double _f;}){i})._f
|
||||
|
||||
#define EXTRACT_WORDS(hi,lo,d) \
|
||||
do { \
|
||||
uint64_t __u = asuint64(d); \
|
||||
(hi) = __u >> 32; \
|
||||
(lo) = (uint32_t)__u; \
|
||||
} while (0)
|
||||
|
||||
#define GET_HIGH_WORD(hi,d) \
|
||||
do { \
|
||||
(hi) = asuint64(d) >> 32; \
|
||||
} while (0)
|
||||
|
||||
#define GET_LOW_WORD(lo,d) \
|
||||
do { \
|
||||
(lo) = (uint32_t)asuint64(d); \
|
||||
} while (0)
|
||||
|
||||
#define INSERT_WORDS(d,hi,lo) \
|
||||
do { \
|
||||
(d) = asdouble(((uint64_t)(hi)<<32) | (uint32_t)(lo)); \
|
||||
} while (0)
|
||||
|
||||
#define SET_HIGH_WORD(d,hi) \
|
||||
INSERT_WORDS(d, hi, (uint32_t)asuint64(d))
|
||||
|
||||
#define SET_LOW_WORD(d,lo) \
|
||||
INSERT_WORDS(d, asuint64(d)>>32, lo)
|
||||
|
||||
#define GET_FLOAT_WORD(w,d) \
|
||||
do { \
|
||||
(w) = asuint(d); \
|
||||
} while (0)
|
||||
|
||||
#define SET_FLOAT_WORD(d,w) \
|
||||
do { \
|
||||
(d) = asfloat(w); \
|
||||
} while (0)
|
||||
|
||||
hidden int __rem_pio2_large(double*,double*,int,int,int);
|
||||
|
||||
hidden int __rem_pio2(double,double*);
|
||||
hidden double __sin(double,double,int);
|
||||
hidden double __cos(double,double);
|
||||
hidden double __tan(double,double,int);
|
||||
hidden double __expo2(double);
|
||||
|
||||
hidden int __rem_pio2f(float,double*);
|
||||
hidden float __sindf(double);
|
||||
hidden float __cosdf(double);
|
||||
hidden float __tandf(double,int);
|
||||
hidden float __expo2f(float);
|
||||
|
||||
hidden int __rem_pio2l(long double, long double *);
|
||||
hidden long double __sinl(long double, long double, int);
|
||||
hidden long double __cosl(long double, long double);
|
||||
hidden long double __tanl(long double, long double, int);
|
||||
|
||||
hidden long double __polevll(long double, const long double *, int);
|
||||
hidden long double __p1evll(long double, const long double *, int);
|
||||
|
||||
extern int __signgam;
|
||||
hidden double __lgamma_r(double, int *);
|
||||
hidden float __lgammaf_r(float, int *);
|
||||
|
||||
/* error handling functions */
|
||||
hidden float __math_xflowf(uint32_t, float);
|
||||
hidden float __math_uflowf(uint32_t);
|
||||
hidden float __math_oflowf(uint32_t);
|
||||
hidden float __math_divzerof(uint32_t);
|
||||
hidden float __math_invalidf(float);
|
||||
hidden double __math_xflow(uint32_t, double);
|
||||
hidden double __math_uflow(uint32_t);
|
||||
hidden double __math_oflow(uint32_t);
|
||||
hidden double __math_divzero(uint32_t);
|
||||
hidden double __math_invalid(double);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Double-precision log(x) function.
|
||||
*
|
||||
* Copyright (c) 2018, Arm Limited.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include "libm.h"
|
||||
#include "log_data.h"
|
||||
|
||||
#define T __log_data.tab
|
||||
#define T2 __log_data.tab2
|
||||
#define B __log_data.poly1
|
||||
#define A __log_data.poly
|
||||
#define Ln2hi __log_data.ln2hi
|
||||
#define Ln2lo __log_data.ln2lo
|
||||
#define N (1 << LOG_TABLE_BITS)
|
||||
#define OFF 0x3fe6000000000000
|
||||
|
||||
#ifdef NEED_MATH_DIVZERO
|
||||
/* base math internal func */
|
||||
double __math_divzero(uint32_t sign)
|
||||
{
|
||||
return fp_barrier(sign ? -1.0 : 1.0) / 0.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef NEED_MATH_INVALID
|
||||
double __math_invalid(double x)
|
||||
{
|
||||
return (x - x) / (x - x);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Top 16 bits of a double. */
|
||||
static inline uint32_t top16(double x)
|
||||
{
|
||||
return asuint64(x) >> 48;
|
||||
}
|
||||
|
||||
double log(double x)
|
||||
{
|
||||
double_t w, z, r, r2, r3, y, invc, logc, kd, hi, lo;
|
||||
uint64_t ix, iz, tmp;
|
||||
uint32_t top;
|
||||
int k, i;
|
||||
|
||||
ix = asuint64(x);
|
||||
top = top16(x);
|
||||
#define LO asuint64(1.0 - 0x1p-4)
|
||||
#define HI asuint64(1.0 + 0x1.09p-4)
|
||||
if (predict_false(ix - LO < HI - LO)) {
|
||||
/* Handle close to 1.0 inputs separately. */
|
||||
/* Fix sign of zero with downward rounding when x==1. */
|
||||
if (WANT_ROUNDING && predict_false(ix == asuint64(1.0)))
|
||||
return 0;
|
||||
r = x - 1.0;
|
||||
r2 = r * r;
|
||||
r3 = r * r2;
|
||||
y = r3 *
|
||||
(B[1] + r * B[2] + r2 * B[3] +
|
||||
r3 * (B[4] + r * B[5] + r2 * B[6] +
|
||||
r3 * (B[7] + r * B[8] + r2 * B[9] + r3 * B[10])));
|
||||
/* Worst-case error is around 0.507 ULP. */
|
||||
w = r * 0x1p27;
|
||||
double_t rhi = r + w - w;
|
||||
double_t rlo = r - rhi;
|
||||
w = rhi * rhi * B[0]; /* B[0] == -0.5. */
|
||||
hi = r + w;
|
||||
lo = r - hi + w;
|
||||
lo += B[0] * rlo * (rhi + r);
|
||||
y += lo;
|
||||
y += hi;
|
||||
return eval_as_double(y);
|
||||
}
|
||||
if (predict_false(top - 0x0010 >= 0x7ff0 - 0x0010)) {
|
||||
/* x < 0x1p-1022 or inf or nan. */
|
||||
if (ix * 2 == 0)
|
||||
return __math_divzero(1);
|
||||
if (ix == asuint64(INFINITY)) /* log(inf) == inf. */
|
||||
return x;
|
||||
if ((top & 0x8000) || (top & 0x7ff0) == 0x7ff0)
|
||||
return __math_invalid(x);
|
||||
/* x is subnormal, normalize it. */
|
||||
ix = asuint64(x * 0x1p52);
|
||||
ix -= 52ULL << 52;
|
||||
}
|
||||
|
||||
/* x = 2^k z; where z is in range [OFF,2*OFF) and exact.
|
||||
The range is split into N subintervals.
|
||||
The ith subinterval contains z and c is near its center. */
|
||||
tmp = ix - OFF;
|
||||
i = (tmp >> (52 - LOG_TABLE_BITS)) % N;
|
||||
k = (int64_t)tmp >> 52; /* arithmetic shift */
|
||||
iz = ix - (tmp & 0xfffULL << 52);
|
||||
invc = T[i].invc;
|
||||
logc = T[i].logc;
|
||||
z = asdouble(iz);
|
||||
|
||||
/* log(x) = log1p(z/c-1) + log(c) + k*Ln2. */
|
||||
/* r ~= z/c - 1, |r| < 1/(2*N). */
|
||||
#if __FP_FAST_FMA
|
||||
/* rounding error: 0x1p-55/N. */
|
||||
r = __builtin_fma(z, invc, -1.0);
|
||||
#else
|
||||
/* rounding error: 0x1p-55/N + 0x1p-66. */
|
||||
r = (z - T2[i].chi - T2[i].clo) * invc;
|
||||
#endif
|
||||
kd = (double_t)k;
|
||||
|
||||
/* hi + lo = r + log(c) + k*Ln2. */
|
||||
w = kd * Ln2hi + logc;
|
||||
hi = w + r;
|
||||
lo = w - hi + r + kd * Ln2lo;
|
||||
|
||||
/* log(x) = lo + (log1p(r) - r) + hi. */
|
||||
r2 = r * r; /* rounding error: 0x1p-54/N^2. */
|
||||
/* Worst case error if |y| > 0x1p-5:
|
||||
0.5 + 4.13/N + abs-poly-error*2^57 ULP (+ 0.002 ULP without fma)
|
||||
Worst case error if |y| > 0x1p-4:
|
||||
0.5 + 2.06/N + abs-poly-error*2^56 ULP (+ 0.001 ULP without fma). */
|
||||
y = lo + r2 * A[0] +
|
||||
r * r2 * (A[1] + r * A[2] + r2 * (A[3] + r * A[4])) + hi;
|
||||
return eval_as_double(y);
|
||||
}
|
|
@ -0,0 +1,328 @@
|
|||
/*
|
||||
* Data for log.
|
||||
*
|
||||
* Copyright (c) 2018, Arm Limited.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "log_data.h"
|
||||
|
||||
#define N (1 << LOG_TABLE_BITS)
|
||||
|
||||
const struct log_data __log_data = {
|
||||
.ln2hi = 0x1.62e42fefa3800p-1,
|
||||
.ln2lo = 0x1.ef35793c76730p-45,
|
||||
.poly1 = {
|
||||
// relative error: 0x1.c04d76cp-63
|
||||
// in -0x1p-4 0x1.09p-4 (|log(1+x)| > 0x1p-4 outside the interval)
|
||||
-0x1p-1,
|
||||
0x1.5555555555577p-2,
|
||||
-0x1.ffffffffffdcbp-3,
|
||||
0x1.999999995dd0cp-3,
|
||||
-0x1.55555556745a7p-3,
|
||||
0x1.24924a344de3p-3,
|
||||
-0x1.fffffa4423d65p-4,
|
||||
0x1.c7184282ad6cap-4,
|
||||
-0x1.999eb43b068ffp-4,
|
||||
0x1.78182f7afd085p-4,
|
||||
-0x1.5521375d145cdp-4,
|
||||
},
|
||||
.poly = {
|
||||
// relative error: 0x1.926199e8p-56
|
||||
// abs error: 0x1.882ff33p-65
|
||||
// in -0x1.fp-9 0x1.fp-9
|
||||
-0x1.0000000000001p-1,
|
||||
0x1.555555551305bp-2,
|
||||
-0x1.fffffffeb459p-3,
|
||||
0x1.999b324f10111p-3,
|
||||
-0x1.55575e506c89fp-3,
|
||||
},
|
||||
/* Algorithm:
|
||||
|
||||
x = 2^k z
|
||||
log(x) = k ln2 + log(c) + log(z/c)
|
||||
log(z/c) = poly(z/c - 1)
|
||||
|
||||
where z is in [1.6p-1; 1.6p0] which is split into N subintervals and z falls
|
||||
into the ith one, then table entries are computed as
|
||||
|
||||
tab[i].invc = 1/c
|
||||
tab[i].logc = (double)log(c)
|
||||
tab2[i].chi = (double)c
|
||||
tab2[i].clo = (double)(c - (double)c)
|
||||
|
||||
where c is near the center of the subinterval and is chosen by trying +-2^29
|
||||
floating point invc candidates around 1/center and selecting one for which
|
||||
|
||||
1) the rounding error in 0x1.8p9 + logc is 0,
|
||||
2) the rounding error in z - chi - clo is < 0x1p-66 and
|
||||
3) the rounding error in (double)log(c) is minimized (< 0x1p-66).
|
||||
|
||||
Note: 1) ensures that k*ln2hi + logc can be computed without rounding error,
|
||||
2) ensures that z/c - 1 can be computed as (z - chi - clo)*invc with close to
|
||||
a single rounding error when there is no fast fma for z*invc - 1, 3) ensures
|
||||
that logc + poly(z/c - 1) has small error, however near x == 1 when
|
||||
|log(x)| < 0x1p-4, this is not enough so that is special cased. */
|
||||
.tab = {
|
||||
{0x1.734f0c3e0de9fp+0, -0x1.7cc7f79e69000p-2},
|
||||
{0x1.713786a2ce91fp+0, -0x1.76feec20d0000p-2},
|
||||
{0x1.6f26008fab5a0p+0, -0x1.713e31351e000p-2},
|
||||
{0x1.6d1a61f138c7dp+0, -0x1.6b85b38287800p-2},
|
||||
{0x1.6b1490bc5b4d1p+0, -0x1.65d5590807800p-2},
|
||||
{0x1.69147332f0cbap+0, -0x1.602d076180000p-2},
|
||||
{0x1.6719f18224223p+0, -0x1.5a8ca86909000p-2},
|
||||
{0x1.6524f99a51ed9p+0, -0x1.54f4356035000p-2},
|
||||
{0x1.63356aa8f24c4p+0, -0x1.4f637c36b4000p-2},
|
||||
{0x1.614b36b9ddc14p+0, -0x1.49da7fda85000p-2},
|
||||
{0x1.5f66452c65c4cp+0, -0x1.445923989a800p-2},
|
||||
{0x1.5d867b5912c4fp+0, -0x1.3edf439b0b800p-2},
|
||||
{0x1.5babccb5b90dep+0, -0x1.396ce448f7000p-2},
|
||||
{0x1.59d61f2d91a78p+0, -0x1.3401e17bda000p-2},
|
||||
{0x1.5805612465687p+0, -0x1.2e9e2ef468000p-2},
|
||||
{0x1.56397cee76bd3p+0, -0x1.2941b3830e000p-2},
|
||||
{0x1.54725e2a77f93p+0, -0x1.23ec58cda8800p-2},
|
||||
{0x1.52aff42064583p+0, -0x1.1e9e129279000p-2},
|
||||
{0x1.50f22dbb2bddfp+0, -0x1.1956d2b48f800p-2},
|
||||
{0x1.4f38f4734ded7p+0, -0x1.141679ab9f800p-2},
|
||||
{0x1.4d843cfde2840p+0, -0x1.0edd094ef9800p-2},
|
||||
{0x1.4bd3ec078a3c8p+0, -0x1.09aa518db1000p-2},
|
||||
{0x1.4a27fc3e0258ap+0, -0x1.047e65263b800p-2},
|
||||
{0x1.4880524d48434p+0, -0x1.feb224586f000p-3},
|
||||
{0x1.46dce1b192d0bp+0, -0x1.f474a7517b000p-3},
|
||||
{0x1.453d9d3391854p+0, -0x1.ea4443d103000p-3},
|
||||
{0x1.43a2744b4845ap+0, -0x1.e020d44e9b000p-3},
|
||||
{0x1.420b54115f8fbp+0, -0x1.d60a22977f000p-3},
|
||||
{0x1.40782da3ef4b1p+0, -0x1.cc00104959000p-3},
|
||||
{0x1.3ee8f5d57fe8fp+0, -0x1.c202956891000p-3},
|
||||
{0x1.3d5d9a00b4ce9p+0, -0x1.b81178d811000p-3},
|
||||
{0x1.3bd60c010c12bp+0, -0x1.ae2c9ccd3d000p-3},
|
||||
{0x1.3a5242b75dab8p+0, -0x1.a45402e129000p-3},
|
||||
{0x1.38d22cd9fd002p+0, -0x1.9a877681df000p-3},
|
||||
{0x1.3755bc5847a1cp+0, -0x1.90c6d69483000p-3},
|
||||
{0x1.35dce49ad36e2p+0, -0x1.87120a645c000p-3},
|
||||
{0x1.34679984dd440p+0, -0x1.7d68fb4143000p-3},
|
||||
{0x1.32f5cceffcb24p+0, -0x1.73cb83c627000p-3},
|
||||
{0x1.3187775a10d49p+0, -0x1.6a39a9b376000p-3},
|
||||
{0x1.301c8373e3990p+0, -0x1.60b3154b7a000p-3},
|
||||
{0x1.2eb4ebb95f841p+0, -0x1.5737d76243000p-3},
|
||||
{0x1.2d50a0219a9d1p+0, -0x1.4dc7b8fc23000p-3},
|
||||
{0x1.2bef9a8b7fd2ap+0, -0x1.4462c51d20000p-3},
|
||||
{0x1.2a91c7a0c1babp+0, -0x1.3b08abc830000p-3},
|
||||
{0x1.293726014b530p+0, -0x1.31b996b490000p-3},
|
||||
{0x1.27dfa5757a1f5p+0, -0x1.2875490a44000p-3},
|
||||
{0x1.268b39b1d3bbfp+0, -0x1.1f3b9f879a000p-3},
|
||||
{0x1.2539d838ff5bdp+0, -0x1.160c8252ca000p-3},
|
||||
{0x1.23eb7aac9083bp+0, -0x1.0ce7f57f72000p-3},
|
||||
{0x1.22a012ba940b6p+0, -0x1.03cdc49fea000p-3},
|
||||
{0x1.2157996cc4132p+0, -0x1.f57bdbc4b8000p-4},
|
||||
{0x1.201201dd2fc9bp+0, -0x1.e370896404000p-4},
|
||||
{0x1.1ecf4494d480bp+0, -0x1.d17983ef94000p-4},
|
||||
{0x1.1d8f5528f6569p+0, -0x1.bf9674ed8a000p-4},
|
||||
{0x1.1c52311577e7cp+0, -0x1.adc79202f6000p-4},
|
||||
{0x1.1b17c74cb26e9p+0, -0x1.9c0c3e7288000p-4},
|
||||
{0x1.19e010c2c1ab6p+0, -0x1.8a646b372c000p-4},
|
||||
{0x1.18ab07bb670bdp+0, -0x1.78d01b3ac0000p-4},
|
||||
{0x1.1778a25efbcb6p+0, -0x1.674f145380000p-4},
|
||||
{0x1.1648d354c31dap+0, -0x1.55e0e6d878000p-4},
|
||||
{0x1.151b990275fddp+0, -0x1.4485cdea1e000p-4},
|
||||
{0x1.13f0ea432d24cp+0, -0x1.333d94d6aa000p-4},
|
||||
{0x1.12c8b7210f9dap+0, -0x1.22079f8c56000p-4},
|
||||
{0x1.11a3028ecb531p+0, -0x1.10e4698622000p-4},
|
||||
{0x1.107fbda8434afp+0, -0x1.ffa6c6ad20000p-5},
|
||||
{0x1.0f5ee0f4e6bb3p+0, -0x1.dda8d4a774000p-5},
|
||||
{0x1.0e4065d2a9fcep+0, -0x1.bbcece4850000p-5},
|
||||
{0x1.0d244632ca521p+0, -0x1.9a1894012c000p-5},
|
||||
{0x1.0c0a77ce2981ap+0, -0x1.788583302c000p-5},
|
||||
{0x1.0af2f83c636d1p+0, -0x1.5715e67d68000p-5},
|
||||
{0x1.09ddb98a01339p+0, -0x1.35c8a49658000p-5},
|
||||
{0x1.08cabaf52e7dfp+0, -0x1.149e364154000p-5},
|
||||
{0x1.07b9f2f4e28fbp+0, -0x1.e72c082eb8000p-6},
|
||||
{0x1.06ab58c358f19p+0, -0x1.a55f152528000p-6},
|
||||
{0x1.059eea5ecf92cp+0, -0x1.63d62cf818000p-6},
|
||||
{0x1.04949cdd12c90p+0, -0x1.228fb8caa0000p-6},
|
||||
{0x1.038c6c6f0ada9p+0, -0x1.c317b20f90000p-7},
|
||||
{0x1.02865137932a9p+0, -0x1.419355daa0000p-7},
|
||||
{0x1.0182427ea7348p+0, -0x1.81203c2ec0000p-8},
|
||||
{0x1.008040614b195p+0, -0x1.0040979240000p-9},
|
||||
{0x1.fe01ff726fa1ap-1, 0x1.feff384900000p-9},
|
||||
{0x1.fa11cc261ea74p-1, 0x1.7dc41353d0000p-7},
|
||||
{0x1.f6310b081992ep-1, 0x1.3cea3c4c28000p-6},
|
||||
{0x1.f25f63ceeadcdp-1, 0x1.b9fc114890000p-6},
|
||||
{0x1.ee9c8039113e7p-1, 0x1.1b0d8ce110000p-5},
|
||||
{0x1.eae8078cbb1abp-1, 0x1.58a5bd001c000p-5},
|
||||
{0x1.e741aa29d0c9bp-1, 0x1.95c8340d88000p-5},
|
||||
{0x1.e3a91830a99b5p-1, 0x1.d276aef578000p-5},
|
||||
{0x1.e01e009609a56p-1, 0x1.07598e598c000p-4},
|
||||
{0x1.dca01e577bb98p-1, 0x1.253f5e30d2000p-4},
|
||||
{0x1.d92f20b7c9103p-1, 0x1.42edd8b380000p-4},
|
||||
{0x1.d5cac66fb5ccep-1, 0x1.606598757c000p-4},
|
||||
{0x1.d272caa5ede9dp-1, 0x1.7da76356a0000p-4},
|
||||
{0x1.cf26e3e6b2ccdp-1, 0x1.9ab434e1c6000p-4},
|
||||
{0x1.cbe6da2a77902p-1, 0x1.b78c7bb0d6000p-4},
|
||||
{0x1.c8b266d37086dp-1, 0x1.d431332e72000p-4},
|
||||
{0x1.c5894bd5d5804p-1, 0x1.f0a3171de6000p-4},
|
||||
{0x1.c26b533bb9f8cp-1, 0x1.067152b914000p-3},
|
||||
{0x1.bf583eeece73fp-1, 0x1.147858292b000p-3},
|
||||
{0x1.bc4fd75db96c1p-1, 0x1.2266ecdca3000p-3},
|
||||
{0x1.b951e0c864a28p-1, 0x1.303d7a6c55000p-3},
|
||||
{0x1.b65e2c5ef3e2cp-1, 0x1.3dfc33c331000p-3},
|
||||
{0x1.b374867c9888bp-1, 0x1.4ba366b7a8000p-3},
|
||||
{0x1.b094b211d304ap-1, 0x1.5933928d1f000p-3},
|
||||
{0x1.adbe885f2ef7ep-1, 0x1.66acd2418f000p-3},
|
||||
{0x1.aaf1d31603da2p-1, 0x1.740f8ec669000p-3},
|
||||
{0x1.a82e63fd358a7p-1, 0x1.815c0f51af000p-3},
|
||||
{0x1.a5740ef09738bp-1, 0x1.8e92954f68000p-3},
|
||||
{0x1.a2c2a90ab4b27p-1, 0x1.9bb3602f84000p-3},
|
||||
{0x1.a01a01393f2d1p-1, 0x1.a8bed1c2c0000p-3},
|
||||
{0x1.9d79f24db3c1bp-1, 0x1.b5b515c01d000p-3},
|
||||
{0x1.9ae2505c7b190p-1, 0x1.c2967ccbcc000p-3},
|
||||
{0x1.9852ef297ce2fp-1, 0x1.cf635d5486000p-3},
|
||||
{0x1.95cbaeea44b75p-1, 0x1.dc1bd3446c000p-3},
|
||||
{0x1.934c69de74838p-1, 0x1.e8c01b8cfe000p-3},
|
||||
{0x1.90d4f2f6752e6p-1, 0x1.f5509c0179000p-3},
|
||||
{0x1.8e6528effd79dp-1, 0x1.00e6c121fb800p-2},
|
||||
{0x1.8bfce9fcc007cp-1, 0x1.071b80e93d000p-2},
|
||||
{0x1.899c0dabec30ep-1, 0x1.0d46b9e867000p-2},
|
||||
{0x1.87427aa2317fbp-1, 0x1.13687334bd000p-2},
|
||||
{0x1.84f00acb39a08p-1, 0x1.1980d67234800p-2},
|
||||
{0x1.82a49e8653e55p-1, 0x1.1f8ffe0cc8000p-2},
|
||||
{0x1.8060195f40260p-1, 0x1.2595fd7636800p-2},
|
||||
{0x1.7e22563e0a329p-1, 0x1.2b9300914a800p-2},
|
||||
{0x1.7beb377dcb5adp-1, 0x1.3187210436000p-2},
|
||||
{0x1.79baa679725c2p-1, 0x1.377266dec1800p-2},
|
||||
{0x1.77907f2170657p-1, 0x1.3d54ffbaf3000p-2},
|
||||
{0x1.756cadbd6130cp-1, 0x1.432eee32fe000p-2},
|
||||
},
|
||||
#if !__FP_FAST_FMA
|
||||
.tab2 = {
|
||||
{0x1.61000014fb66bp-1, 0x1.e026c91425b3cp-56},
|
||||
{0x1.63000034db495p-1, 0x1.dbfea48005d41p-55},
|
||||
{0x1.650000d94d478p-1, 0x1.e7fa786d6a5b7p-55},
|
||||
{0x1.67000074e6fadp-1, 0x1.1fcea6b54254cp-57},
|
||||
{0x1.68ffffedf0faep-1, -0x1.c7e274c590efdp-56},
|
||||
{0x1.6b0000763c5bcp-1, -0x1.ac16848dcda01p-55},
|
||||
{0x1.6d0001e5cc1f6p-1, 0x1.33f1c9d499311p-55},
|
||||
{0x1.6efffeb05f63ep-1, -0x1.e80041ae22d53p-56},
|
||||
{0x1.710000e86978p-1, 0x1.bff6671097952p-56},
|
||||
{0x1.72ffffc67e912p-1, 0x1.c00e226bd8724p-55},
|
||||
{0x1.74fffdf81116ap-1, -0x1.e02916ef101d2p-57},
|
||||
{0x1.770000f679c9p-1, -0x1.7fc71cd549c74p-57},
|
||||
{0x1.78ffffa7ec835p-1, 0x1.1bec19ef50483p-55},
|
||||
{0x1.7affffe20c2e6p-1, -0x1.07e1729cc6465p-56},
|
||||
{0x1.7cfffed3fc9p-1, -0x1.08072087b8b1cp-55},
|
||||
{0x1.7efffe9261a76p-1, 0x1.dc0286d9df9aep-55},
|
||||
{0x1.81000049ca3e8p-1, 0x1.97fd251e54c33p-55},
|
||||
{0x1.8300017932c8fp-1, -0x1.afee9b630f381p-55},
|
||||
{0x1.850000633739cp-1, 0x1.9bfbf6b6535bcp-55},
|
||||
{0x1.87000204289c6p-1, -0x1.bbf65f3117b75p-55},
|
||||
{0x1.88fffebf57904p-1, -0x1.9006ea23dcb57p-55},
|
||||
{0x1.8b00022bc04dfp-1, -0x1.d00df38e04b0ap-56},
|
||||
{0x1.8cfffe50c1b8ap-1, -0x1.8007146ff9f05p-55},
|
||||
{0x1.8effffc918e43p-1, 0x1.3817bd07a7038p-55},
|
||||
{0x1.910001efa5fc7p-1, 0x1.93e9176dfb403p-55},
|
||||
{0x1.9300013467bb9p-1, 0x1.f804e4b980276p-56},
|
||||
{0x1.94fffe6ee076fp-1, -0x1.f7ef0d9ff622ep-55},
|
||||
{0x1.96fffde3c12d1p-1, -0x1.082aa962638bap-56},
|
||||
{0x1.98ffff4458a0dp-1, -0x1.7801b9164a8efp-55},
|
||||
{0x1.9afffdd982e3ep-1, -0x1.740e08a5a9337p-55},
|
||||
{0x1.9cfffed49fb66p-1, 0x1.fce08c19bep-60},
|
||||
{0x1.9f00020f19c51p-1, -0x1.a3faa27885b0ap-55},
|
||||
{0x1.a10001145b006p-1, 0x1.4ff489958da56p-56},
|
||||
{0x1.a300007bbf6fap-1, 0x1.cbeab8a2b6d18p-55},
|
||||
{0x1.a500010971d79p-1, 0x1.8fecadd78793p-55},
|
||||
{0x1.a70001df52e48p-1, -0x1.f41763dd8abdbp-55},
|
||||
{0x1.a90001c593352p-1, -0x1.ebf0284c27612p-55},
|
||||
{0x1.ab0002a4f3e4bp-1, -0x1.9fd043cff3f5fp-57},
|
||||
{0x1.acfffd7ae1ed1p-1, -0x1.23ee7129070b4p-55},
|
||||
{0x1.aefffee510478p-1, 0x1.a063ee00edea3p-57},
|
||||
{0x1.b0fffdb650d5bp-1, 0x1.a06c8381f0ab9p-58},
|
||||
{0x1.b2ffffeaaca57p-1, -0x1.9011e74233c1dp-56},
|
||||
{0x1.b4fffd995badcp-1, -0x1.9ff1068862a9fp-56},
|
||||
{0x1.b7000249e659cp-1, 0x1.aff45d0864f3ep-55},
|
||||
{0x1.b8ffff987164p-1, 0x1.cfe7796c2c3f9p-56},
|
||||
{0x1.bafffd204cb4fp-1, -0x1.3ff27eef22bc4p-57},
|
||||
{0x1.bcfffd2415c45p-1, -0x1.cffb7ee3bea21p-57},
|
||||
{0x1.beffff86309dfp-1, -0x1.14103972e0b5cp-55},
|
||||
{0x1.c0fffe1b57653p-1, 0x1.bc16494b76a19p-55},
|
||||
{0x1.c2ffff1fa57e3p-1, -0x1.4feef8d30c6edp-57},
|
||||
{0x1.c4fffdcbfe424p-1, -0x1.43f68bcec4775p-55},
|
||||
{0x1.c6fffed54b9f7p-1, 0x1.47ea3f053e0ecp-55},
|
||||
{0x1.c8fffeb998fd5p-1, 0x1.383068df992f1p-56},
|
||||
{0x1.cb0002125219ap-1, -0x1.8fd8e64180e04p-57},
|
||||
{0x1.ccfffdd94469cp-1, 0x1.e7ebe1cc7ea72p-55},
|
||||
{0x1.cefffeafdc476p-1, 0x1.ebe39ad9f88fep-55},
|
||||
{0x1.d1000169af82bp-1, 0x1.57d91a8b95a71p-56},
|
||||
{0x1.d30000d0ff71dp-1, 0x1.9c1906970c7dap-55},
|
||||
{0x1.d4fffea790fc4p-1, -0x1.80e37c558fe0cp-58},
|
||||
{0x1.d70002edc87e5p-1, -0x1.f80d64dc10f44p-56},
|
||||
{0x1.d900021dc82aap-1, -0x1.47c8f94fd5c5cp-56},
|
||||
{0x1.dafffd86b0283p-1, 0x1.c7f1dc521617ep-55},
|
||||
{0x1.dd000296c4739p-1, 0x1.8019eb2ffb153p-55},
|
||||
{0x1.defffe54490f5p-1, 0x1.e00d2c652cc89p-57},
|
||||
{0x1.e0fffcdabf694p-1, -0x1.f8340202d69d2p-56},
|
||||
{0x1.e2fffdb52c8ddp-1, 0x1.b00c1ca1b0864p-56},
|
||||
{0x1.e4ffff24216efp-1, 0x1.2ffa8b094ab51p-56},
|
||||
{0x1.e6fffe88a5e11p-1, -0x1.7f673b1efbe59p-58},
|
||||
{0x1.e9000119eff0dp-1, -0x1.4808d5e0bc801p-55},
|
||||
{0x1.eafffdfa51744p-1, 0x1.80006d54320b5p-56},
|
||||
{0x1.ed0001a127fa1p-1, -0x1.002f860565c92p-58},
|
||||
{0x1.ef00007babcc4p-1, -0x1.540445d35e611p-55},
|
||||
{0x1.f0ffff57a8d02p-1, -0x1.ffb3139ef9105p-59},
|
||||
{0x1.f30001ee58ac7p-1, 0x1.a81acf2731155p-55},
|
||||
{0x1.f4ffff5823494p-1, 0x1.a3f41d4d7c743p-55},
|
||||
{0x1.f6ffffca94c6bp-1, -0x1.202f41c987875p-57},
|
||||
{0x1.f8fffe1f9c441p-1, 0x1.77dd1f477e74bp-56},
|
||||
{0x1.fafffd2e0e37ep-1, -0x1.f01199a7ca331p-57},
|
||||
{0x1.fd0001c77e49ep-1, 0x1.181ee4bceacb1p-56},
|
||||
{0x1.feffff7e0c331p-1, -0x1.e05370170875ap-57},
|
||||
{0x1.00ffff465606ep+0, -0x1.a7ead491c0adap-55},
|
||||
{0x1.02ffff3867a58p+0, -0x1.77f69c3fcb2ep-54},
|
||||
{0x1.04ffffdfc0d17p+0, 0x1.7bffe34cb945bp-54},
|
||||
{0x1.0700003cd4d82p+0, 0x1.20083c0e456cbp-55},
|
||||
{0x1.08ffff9f2cbe8p+0, -0x1.dffdfbe37751ap-57},
|
||||
{0x1.0b000010cda65p+0, -0x1.13f7faee626ebp-54},
|
||||
{0x1.0d00001a4d338p+0, 0x1.07dfa79489ff7p-55},
|
||||
{0x1.0effffadafdfdp+0, -0x1.7040570d66bcp-56},
|
||||
{0x1.110000bbafd96p+0, 0x1.e80d4846d0b62p-55},
|
||||
{0x1.12ffffae5f45dp+0, 0x1.dbffa64fd36efp-54},
|
||||
{0x1.150000dd59ad9p+0, 0x1.a0077701250aep-54},
|
||||
{0x1.170000f21559ap+0, 0x1.dfdf9e2e3deeep-55},
|
||||
{0x1.18ffffc275426p+0, 0x1.10030dc3b7273p-54},
|
||||
{0x1.1b000123d3c59p+0, 0x1.97f7980030188p-54},
|
||||
{0x1.1cffff8299eb7p+0, -0x1.5f932ab9f8c67p-57},
|
||||
{0x1.1effff48ad4p+0, 0x1.37fbf9da75bebp-54},
|
||||
{0x1.210000c8b86a4p+0, 0x1.f806b91fd5b22p-54},
|
||||
{0x1.2300003854303p+0, 0x1.3ffc2eb9fbf33p-54},
|
||||
{0x1.24fffffbcf684p+0, 0x1.601e77e2e2e72p-56},
|
||||
{0x1.26ffff52921d9p+0, 0x1.ffcbb767f0c61p-56},
|
||||
{0x1.2900014933a3cp+0, -0x1.202ca3c02412bp-56},
|
||||
{0x1.2b00014556313p+0, -0x1.2808233f21f02p-54},
|
||||
{0x1.2cfffebfe523bp+0, -0x1.8ff7e384fdcf2p-55},
|
||||
{0x1.2f0000bb8ad96p+0, -0x1.5ff51503041c5p-55},
|
||||
{0x1.30ffffb7ae2afp+0, -0x1.10071885e289dp-55},
|
||||
{0x1.32ffffeac5f7fp+0, -0x1.1ff5d3fb7b715p-54},
|
||||
{0x1.350000ca66756p+0, 0x1.57f82228b82bdp-54},
|
||||
{0x1.3700011fbf721p+0, 0x1.000bac40dd5ccp-55},
|
||||
{0x1.38ffff9592fb9p+0, -0x1.43f9d2db2a751p-54},
|
||||
{0x1.3b00004ddd242p+0, 0x1.57f6b707638e1p-55},
|
||||
{0x1.3cffff5b2c957p+0, 0x1.a023a10bf1231p-56},
|
||||
{0x1.3efffeab0b418p+0, 0x1.87f6d66b152bp-54},
|
||||
{0x1.410001532aff4p+0, 0x1.7f8375f198524p-57},
|
||||
{0x1.4300017478b29p+0, 0x1.301e672dc5143p-55},
|
||||
{0x1.44fffe795b463p+0, 0x1.9ff69b8b2895ap-55},
|
||||
{0x1.46fffe80475ep+0, -0x1.5c0b19bc2f254p-54},
|
||||
{0x1.48fffef6fc1e7p+0, 0x1.b4009f23a2a72p-54},
|
||||
{0x1.4afffe5bea704p+0, -0x1.4ffb7bf0d7d45p-54},
|
||||
{0x1.4d000171027dep+0, -0x1.9c06471dc6a3dp-54},
|
||||
{0x1.4f0000ff03ee2p+0, 0x1.77f890b85531cp-54},
|
||||
{0x1.5100012dc4bd1p+0, 0x1.004657166a436p-57},
|
||||
{0x1.530001605277ap+0, -0x1.6bfcece233209p-54},
|
||||
{0x1.54fffecdb704cp+0, -0x1.902720505a1d7p-55},
|
||||
{0x1.56fffef5f54a9p+0, 0x1.bbfe60ec96412p-54},
|
||||
{0x1.5900017e61012p+0, 0x1.87ec581afef9p-55},
|
||||
{0x1.5b00003c93e92p+0, -0x1.f41080abf0ccp-54},
|
||||
{0x1.5d0001d4919bcp+0, -0x1.8812afb254729p-54},
|
||||
{0x1.5efffe7b87a89p+0, -0x1.47eb780ed6904p-54},
|
||||
},
|
||||
#endif
|
||||
};
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Arm Limited.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#ifndef _LOG_DATA_H
|
||||
#define _LOG_DATA_H
|
||||
|
||||
#include <features.h>
|
||||
|
||||
#define LOG_TABLE_BITS 7
|
||||
#define LOG_POLY_ORDER 6
|
||||
#define LOG_POLY1_ORDER 12
|
||||
extern const struct log_data {
|
||||
double ln2hi;
|
||||
double ln2lo;
|
||||
double poly[LOG_POLY_ORDER - 1]; /* First coefficient is 1. */
|
||||
double poly1[LOG_POLY1_ORDER - 1];
|
||||
struct {
|
||||
double invc, logc;
|
||||
} tab[1 << LOG_TABLE_BITS];
|
||||
#if !__FP_FAST_FMA
|
||||
struct {
|
||||
double chi, clo;
|
||||
} tab2[1 << LOG_TABLE_BITS];
|
||||
#endif
|
||||
} __log_data;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,343 @@
|
|||
/*
|
||||
* Double-precision x^y function.
|
||||
*
|
||||
* Copyright (c) 2018, Arm Limited.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include "libm.h"
|
||||
#include "exp_data.h"
|
||||
#include "pow_data.h"
|
||||
|
||||
/*
|
||||
Worst-case error: 0.54 ULP (~= ulperr_exp + 1024*Ln2*relerr_log*2^53)
|
||||
relerr_log: 1.3 * 2^-68 (Relative error of log, 1.5 * 2^-68 without fma)
|
||||
ulperr_exp: 0.509 ULP (ULP error of exp, 0.511 ULP without fma)
|
||||
*/
|
||||
|
||||
#define T __pow_log_data1.tab
|
||||
#define A __pow_log_data1.poly
|
||||
#define Ln2hi __pow_log_data1.ln2hi
|
||||
#define Ln2lo __pow_log_data1.ln2lo
|
||||
#define N (1 << POW_LOG_TABLE_BITS)
|
||||
#define OFF 0x3fe6955500000000
|
||||
|
||||
/* Top 12 bits of a double (sign and exponent bits). */
|
||||
static inline uint32_t top12(double x)
|
||||
{
|
||||
return asuint64(x) >> 52;
|
||||
}
|
||||
|
||||
/* Compute y+TAIL = log(x) where the rounded result is y and TAIL has about
|
||||
additional 15 bits precision. IX is the bit representation of x, but
|
||||
normalized in the subnormal range using the sign bit for the exponent. */
|
||||
static inline double_t log_inline(uint64_t ix, double_t *tail)
|
||||
{
|
||||
/* double_t for better performance on targets with FLT_EVAL_METHOD==2. */
|
||||
double_t z, r, y, invc, logc, logctail, kd, hi, t1, t2, lo, lo1, lo2, p;
|
||||
uint64_t iz, tmp;
|
||||
int k, i;
|
||||
|
||||
/* x = 2^k z; where z is in range [OFF,2*OFF) and exact.
|
||||
The range is split into N subintervals.
|
||||
The ith subinterval contains z and c is near its center. */
|
||||
tmp = ix - OFF;
|
||||
i = (tmp >> (52 - POW_LOG_TABLE_BITS)) % N;
|
||||
k = (int64_t)tmp >> 52; /* arithmetic shift */
|
||||
iz = ix - (tmp & 0xfffULL << 52);
|
||||
z = asdouble(iz);
|
||||
kd = (double_t)k;
|
||||
|
||||
/* log(x) = k*Ln2 + log(c) + log1p(z/c-1). */
|
||||
invc = T[i].invc;
|
||||
logc = T[i].logc;
|
||||
logctail = T[i].logctail;
|
||||
|
||||
/* Note: 1/c is j/N or j/N/2 where j is an integer in [N,2N) and
|
||||
|z/c - 1| < 1/N, so r = z/c - 1 is exactly representible. */
|
||||
#if __FP_FAST_FMA
|
||||
r = __builtin_fma(z, invc, -1.0);
|
||||
#else
|
||||
/* Split z such that rhi, rlo and rhi*rhi are exact and |rlo| <= |r|. */
|
||||
double_t zhi = asdouble((iz + (1ULL << 31)) & (-1ULL << 32));
|
||||
double_t zlo = z - zhi;
|
||||
double_t rhi = zhi * invc - 1.0;
|
||||
double_t rlo = zlo * invc;
|
||||
r = rhi + rlo;
|
||||
#endif
|
||||
|
||||
/* k*Ln2 + log(c) + r. */
|
||||
t1 = kd * Ln2hi + logc;
|
||||
t2 = t1 + r;
|
||||
lo1 = kd * Ln2lo + logctail;
|
||||
lo2 = t1 - t2 + r;
|
||||
|
||||
/* Evaluation is optimized assuming superscalar pipelined execution. */
|
||||
double_t ar, ar2, ar3, lo3, lo4;
|
||||
ar = A[0] * r; /* A[0] = -0.5. */
|
||||
ar2 = r * ar;
|
||||
ar3 = r * ar2;
|
||||
/* k*Ln2 + log(c) + r + A[0]*r*r. */
|
||||
#if __FP_FAST_FMA
|
||||
hi = t2 + ar2;
|
||||
lo3 = __builtin_fma(ar, r, -ar2);
|
||||
lo4 = t2 - hi + ar2;
|
||||
#else
|
||||
double_t arhi = A[0] * rhi;
|
||||
double_t arhi2 = rhi * arhi;
|
||||
hi = t2 + arhi2;
|
||||
lo3 = rlo * (ar + arhi);
|
||||
lo4 = t2 - hi + arhi2;
|
||||
#endif
|
||||
/* p = log1p(r) - r - A[0]*r*r. */
|
||||
p = (ar3 * (A[1] + r * A[2] +
|
||||
ar2 * (A[3] + r * A[4] + ar2 * (A[5] + r * A[6]))));
|
||||
lo = lo1 + lo2 + lo3 + lo4 + p;
|
||||
y = hi + lo;
|
||||
*tail = hi - y + lo;
|
||||
return y;
|
||||
}
|
||||
|
||||
#undef N
|
||||
#undef T
|
||||
#define N (1 << EXP_TABLE_BITS)
|
||||
#define InvLn2N __exp_data1.invln2N
|
||||
#define NegLn2hiN __exp_data1.negln2hiN
|
||||
#define NegLn2loN __exp_data1.negln2loN
|
||||
#define Shift __exp_data1.shift
|
||||
#define T __exp_data1.tab
|
||||
#define C2 __exp_data1.poly[5 - EXP_POLY_ORDER]
|
||||
#define C3 __exp_data1.poly[6 - EXP_POLY_ORDER]
|
||||
#define C4 __exp_data1.poly[7 - EXP_POLY_ORDER]
|
||||
#define C5 __exp_data1.poly[8 - EXP_POLY_ORDER]
|
||||
#define C6 __exp_data1.poly[9 - EXP_POLY_ORDER]
|
||||
|
||||
/* Handle cases that may overflow or underflow when computing the result that
|
||||
is scale*(1+TMP) without intermediate rounding. The bit representation of
|
||||
scale is in SBITS, however it has a computed exponent that may have
|
||||
overflown into the sign bit so that needs to be adjusted before using it as
|
||||
a double. (int32_t)KI is the k used in the argument reduction and exponent
|
||||
adjustment of scale, positive k here means the result may overflow and
|
||||
negative k means the result may underflow. */
|
||||
static inline double specialcase(double_t tmp, uint64_t sbits, uint64_t ki)
|
||||
{
|
||||
double_t scale, y;
|
||||
|
||||
if ((ki & 0x80000000) == 0) {
|
||||
/* k > 0, the exponent of scale might have overflowed by <= 460. */
|
||||
sbits -= 1009ull << 52;
|
||||
scale = asdouble(sbits);
|
||||
y = 0x1p1009 * (scale + scale * tmp);
|
||||
return eval_as_double(y);
|
||||
}
|
||||
/* k < 0, need special care in the subnormal range. */
|
||||
sbits += 1022ull << 52;
|
||||
/* Note: sbits is signed scale. */
|
||||
scale = asdouble(sbits);
|
||||
y = scale + scale * tmp;
|
||||
if (fabs(y) < 1.0) {
|
||||
/* Round y to the right precision before scaling it into the subnormal
|
||||
range to avoid double rounding that can cause 0.5+E/2 ulp error where
|
||||
E is the worst-case ulp error outside the subnormal range. So this
|
||||
is only useful if the goal is better than 1 ulp worst-case error. */
|
||||
double_t hi, lo, one = 1.0;
|
||||
if (y < 0.0)
|
||||
one = -1.0;
|
||||
lo = scale - y + scale * tmp;
|
||||
hi = one + y;
|
||||
lo = one - hi + y + lo;
|
||||
y = eval_as_double(hi + lo) - one;
|
||||
/* Fix the sign of 0. */
|
||||
if (y == 0.0)
|
||||
y = asdouble(sbits & 0x8000000000000000);
|
||||
/* The underflow exception needs to be signaled explicitly. */
|
||||
fp_force_eval(fp_barrier(0x1p-1022) * 0x1p-1022);
|
||||
}
|
||||
y = 0x1p-1022 * y;
|
||||
return eval_as_double(y);
|
||||
}
|
||||
|
||||
#define SIGN_BIAS (0x800 << EXP_TABLE_BITS)
|
||||
|
||||
/* Computes sign*exp(x+xtail) where |xtail| < 2^-8/N and |xtail| <= |x|.
|
||||
The sign_bias argument is SIGN_BIAS or 0 and sets the sign to -1 or 1. */
|
||||
static inline double exp_inline(double_t x, double_t xtail, uint32_t sign_bias)
|
||||
{
|
||||
uint32_t abstop;
|
||||
uint64_t ki, idx, top, sbits;
|
||||
/* double_t for better performance on targets with FLT_EVAL_METHOD==2. */
|
||||
double_t kd, z, r, r2, scale, tail, tmp;
|
||||
|
||||
abstop = top12(x) & 0x7ff;
|
||||
if (predict_false(abstop - top12(0x1p-54) >=
|
||||
top12(512.0) - top12(0x1p-54))) {
|
||||
if (abstop - top12(0x1p-54) >= 0x80000000) {
|
||||
/* Avoid spurious underflow for tiny x. */
|
||||
/* Note: 0 is common input. */
|
||||
double_t one = WANT_ROUNDING ? 1.0 + x : 1.0;
|
||||
return sign_bias ? -one : one;
|
||||
}
|
||||
if (abstop >= top12(1024.0)) {
|
||||
/* Note: inf and nan are already handled. */
|
||||
if (asuint64(x) >> 63)
|
||||
return __math_uflow(sign_bias);
|
||||
else
|
||||
return __math_oflow(sign_bias);
|
||||
}
|
||||
/* Large x is special cased below. */
|
||||
abstop = 0;
|
||||
}
|
||||
|
||||
/* exp(x) = 2^(k/N) * exp(r), with exp(r) in [2^(-1/2N),2^(1/2N)]. */
|
||||
/* x = ln2/N*k + r, with int k and r in [-ln2/2N, ln2/2N]. */
|
||||
z = InvLn2N * x;
|
||||
#if TOINT_INTRINSICS
|
||||
kd = roundtoint(z);
|
||||
ki = converttoint(z);
|
||||
#elif EXP_USE_TOINT_NARROW
|
||||
/* z - kd is in [-0.5-2^-16, 0.5] in all rounding modes. */
|
||||
kd = eval_as_double(z + Shift);
|
||||
ki = asuint64(kd) >> 16;
|
||||
kd = (double_t)(int32_t)ki;
|
||||
#else
|
||||
/* z - kd is in [-1, 1] in non-nearest rounding modes. */
|
||||
kd = eval_as_double(z + Shift);
|
||||
ki = asuint64(kd);
|
||||
kd -= Shift;
|
||||
#endif
|
||||
r = x + kd * NegLn2hiN + kd * NegLn2loN;
|
||||
/* The code assumes 2^-200 < |xtail| < 2^-8/N. */
|
||||
r += xtail;
|
||||
/* 2^(k/N) ~= scale * (1 + tail). */
|
||||
idx = 2 * (ki % N);
|
||||
top = (ki + sign_bias) << (52 - EXP_TABLE_BITS);
|
||||
tail = asdouble(T[idx]);
|
||||
/* This is only a valid scale when -1023*N < k < 1024*N. */
|
||||
sbits = T[idx + 1] + top;
|
||||
/* exp(x) = 2^(k/N) * exp(r) ~= scale + scale * (tail + exp(r) - 1). */
|
||||
/* Evaluation is optimized assuming superscalar pipelined execution. */
|
||||
r2 = r * r;
|
||||
/* Without fma the worst case error is 0.25/N ulp larger. */
|
||||
/* Worst case error is less than 0.5+1.11/N+(abs poly error * 2^53) ulp. */
|
||||
tmp = tail + r + r2 * (C2 + r * C3) + r2 * r2 * (C4 + r * C5);
|
||||
if (predict_false(abstop == 0))
|
||||
return specialcase(tmp, sbits, ki);
|
||||
scale = asdouble(sbits);
|
||||
/* Note: tmp == 0 or |tmp| > 2^-200 and scale > 2^-739, so there
|
||||
is no spurious underflow here even without fma. */
|
||||
return eval_as_double(scale + scale * tmp);
|
||||
}
|
||||
|
||||
/* Returns 0 if not int, 1 if odd int, 2 if even int. The argument is
|
||||
the bit representation of a non-zero finite floating-point value. */
|
||||
static inline int checkint(uint64_t iy)
|
||||
{
|
||||
int e = iy >> 52 & 0x7ff;
|
||||
if (e < 0x3ff)
|
||||
return 0;
|
||||
if (e > 0x3ff + 52)
|
||||
return 2;
|
||||
if (iy & ((1ULL << (0x3ff + 52 - e)) - 1))
|
||||
return 0;
|
||||
if (iy & (1ULL << (0x3ff + 52 - e)))
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* Returns 1 if input is the bit representation of 0, infinity or nan. */
|
||||
static inline int zeroinfnan(uint64_t i)
|
||||
{
|
||||
return 2 * i - 1 >= 2 * asuint64(INFINITY) - 1;
|
||||
}
|
||||
|
||||
double pow(double x, double y)
|
||||
{
|
||||
uint32_t sign_bias = 0;
|
||||
uint64_t ix, iy;
|
||||
uint32_t topx, topy;
|
||||
|
||||
ix = asuint64(x);
|
||||
iy = asuint64(y);
|
||||
topx = top12(x);
|
||||
topy = top12(y);
|
||||
if (predict_false(topx - 0x001 >= 0x7ff - 0x001 ||
|
||||
(topy & 0x7ff) - 0x3be >= 0x43e - 0x3be)) {
|
||||
/* Note: if |y| > 1075 * ln2 * 2^53 ~= 0x1.749p62 then pow(x,y) = inf/0
|
||||
and if |y| < 2^-54 / 1075 ~= 0x1.e7b6p-65 then pow(x,y) = +-1. */
|
||||
/* Special cases: (x < 0x1p-126 or inf or nan) or
|
||||
(|y| < 0x1p-65 or |y| >= 0x1p63 or nan). */
|
||||
if (predict_false(zeroinfnan(iy))) {
|
||||
if (2 * iy == 0)
|
||||
return issignaling_inline(x) ? x + y : 1.0;
|
||||
if (ix == asuint64(1.0))
|
||||
return issignaling_inline(y) ? x + y : 1.0;
|
||||
if (2 * ix > 2 * asuint64(INFINITY) ||
|
||||
2 * iy > 2 * asuint64(INFINITY))
|
||||
return x + y;
|
||||
if (2 * ix == 2 * asuint64(1.0))
|
||||
return 1.0;
|
||||
if ((2 * ix < 2 * asuint64(1.0)) == !(iy >> 63))
|
||||
return 0.0; /* |x|<1 && y==inf or |x|>1 && y==-inf. */
|
||||
return y * y;
|
||||
}
|
||||
if (predict_false(zeroinfnan(ix))) {
|
||||
double_t x2 = x * x;
|
||||
if (ix >> 63 && checkint(iy) == 1)
|
||||
x2 = -x2;
|
||||
/* Without the barrier some versions of clang hoist the 1/x2 and
|
||||
thus division by zero exception can be signaled spuriously. */
|
||||
return iy >> 63 ? fp_barrier(1 / x2) : x2;
|
||||
}
|
||||
/* Here x and y are non-zero finite. */
|
||||
if (ix >> 63) {
|
||||
/* Finite x < 0. */
|
||||
int yint = checkint(iy);
|
||||
if (yint == 0)
|
||||
return __math_invalid(x);
|
||||
if (yint == 1)
|
||||
sign_bias = SIGN_BIAS;
|
||||
ix &= 0x7fffffffffffffff;
|
||||
topx &= 0x7ff;
|
||||
}
|
||||
if ((topy & 0x7ff) - 0x3be >= 0x43e - 0x3be) {
|
||||
/* Note: sign_bias == 0 here because y is not odd. */
|
||||
if (ix == asuint64(1.0))
|
||||
return 1.0;
|
||||
if ((topy & 0x7ff) < 0x3be) {
|
||||
/* |y| < 2^-65, x^y ~= 1 + y*log(x). */
|
||||
if (WANT_ROUNDING)
|
||||
return ix > asuint64(1.0) ? 1.0 + y :
|
||||
1.0 - y;
|
||||
else
|
||||
return 1.0;
|
||||
}
|
||||
return (ix > asuint64(1.0)) == (topy < 0x800) ?
|
||||
__math_oflow(0) :
|
||||
__math_uflow(0);
|
||||
}
|
||||
if (topx == 0) {
|
||||
/* Normalize subnormal x so exponent becomes negative. */
|
||||
ix = asuint64(x * 0x1p52);
|
||||
ix &= 0x7fffffffffffffff;
|
||||
ix -= 52ULL << 52;
|
||||
}
|
||||
}
|
||||
|
||||
double_t lo;
|
||||
double_t hi = log_inline(ix, &lo);
|
||||
double_t ehi, elo;
|
||||
#if __FP_FAST_FMA
|
||||
ehi = y * hi;
|
||||
elo = y * lo + __builtin_fma(y, hi, -ehi);
|
||||
#else
|
||||
double_t yhi = asdouble(iy & -1ULL << 27);
|
||||
double_t ylo = y - yhi;
|
||||
double_t lhi = asdouble(asuint64(hi) & -1ULL << 27);
|
||||
double_t llo = hi - lhi + lo;
|
||||
ehi = yhi * lhi;
|
||||
elo = ylo * lhi + y * llo; /* |elo| < |ehi| * 2^-25. */
|
||||
#endif
|
||||
return exp_inline(ehi, elo, sign_bias);
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Data for the log part of pow.
|
||||
*
|
||||
* Copyright (c) 2018, Arm Limited.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "pow_data.h"
|
||||
|
||||
#define N (1 << POW_LOG_TABLE_BITS)
|
||||
|
||||
const struct pow_log_data __pow_log_data1 = {
|
||||
.ln2hi = 0x1.62e42fefa3800p-1,
|
||||
.ln2lo = 0x1.ef35793c76730p-45,
|
||||
.poly = {
|
||||
// relative error: 0x1.11922ap-70
|
||||
// in -0x1.6bp-8 0x1.6bp-8
|
||||
// Coefficients are scaled to match the scaling during evaluation.
|
||||
-0x1p-1,
|
||||
0x1.555555555556p-2 * -2,
|
||||
-0x1.0000000000006p-2 * -2,
|
||||
0x1.999999959554ep-3 * 4,
|
||||
-0x1.555555529a47ap-3 * 4,
|
||||
0x1.2495b9b4845e9p-3 * -8,
|
||||
-0x1.0002b8b263fc3p-3 * -8,
|
||||
},
|
||||
/* Algorithm:
|
||||
|
||||
x = 2^k z
|
||||
log(x) = k ln2 + log(c) + log(z/c)
|
||||
log(z/c) = poly(z/c - 1)
|
||||
|
||||
where z is in [0x1.69555p-1; 0x1.69555p0] which is split into N subintervals
|
||||
and z falls into the ith one, then table entries are computed as
|
||||
|
||||
tab[i].invc = 1/c
|
||||
tab[i].logc = round(0x1p43*log(c))/0x1p43
|
||||
tab[i].logctail = (double)(log(c) - logc)
|
||||
|
||||
where c is chosen near the center of the subinterval such that 1/c has only a
|
||||
few precision bits so z/c - 1 is exactly representible as double:
|
||||
|
||||
1/c = center < 1 ? round(N/center)/N : round(2*N/center)/N/2
|
||||
|
||||
Note: |z/c - 1| < 1/N for the chosen c, |log(c) - logc - logctail| < 0x1p-97,
|
||||
the last few bits of logc are rounded away so k*ln2hi + logc has no rounding
|
||||
error and the interval for z is selected such that near x == 1, where log(x)
|
||||
is tiny, large cancellation error is avoided in logc + poly(z/c - 1). */
|
||||
.tab = {
|
||||
#define A(a, b, c) {a, 0, b, c},
|
||||
A(0x1.6a00000000000p+0, -0x1.62c82f2b9c800p-2, 0x1.ab42428375680p-48)
|
||||
A(0x1.6800000000000p+0, -0x1.5d1bdbf580800p-2, -0x1.ca508d8e0f720p-46)
|
||||
A(0x1.6600000000000p+0, -0x1.5767717455800p-2, -0x1.362a4d5b6506dp-45)
|
||||
A(0x1.6400000000000p+0, -0x1.51aad872df800p-2, -0x1.684e49eb067d5p-49)
|
||||
A(0x1.6200000000000p+0, -0x1.4be5f95777800p-2, -0x1.41b6993293ee0p-47)
|
||||
A(0x1.6000000000000p+0, -0x1.4618bc21c6000p-2, 0x1.3d82f484c84ccp-46)
|
||||
A(0x1.5e00000000000p+0, -0x1.404308686a800p-2, 0x1.c42f3ed820b3ap-50)
|
||||
A(0x1.5c00000000000p+0, -0x1.3a64c55694800p-2, 0x1.0b1c686519460p-45)
|
||||
A(0x1.5a00000000000p+0, -0x1.347dd9a988000p-2, 0x1.5594dd4c58092p-45)
|
||||
A(0x1.5800000000000p+0, -0x1.2e8e2bae12000p-2, 0x1.67b1e99b72bd8p-45)
|
||||
A(0x1.5600000000000p+0, -0x1.2895a13de8800p-2, 0x1.5ca14b6cfb03fp-46)
|
||||
A(0x1.5600000000000p+0, -0x1.2895a13de8800p-2, 0x1.5ca14b6cfb03fp-46)
|
||||
A(0x1.5400000000000p+0, -0x1.22941fbcf7800p-2, -0x1.65a242853da76p-46)
|
||||
A(0x1.5200000000000p+0, -0x1.1c898c1699800p-2, -0x1.fafbc68e75404p-46)
|
||||
A(0x1.5000000000000p+0, -0x1.1675cababa800p-2, 0x1.f1fc63382a8f0p-46)
|
||||
A(0x1.4e00000000000p+0, -0x1.1058bf9ae4800p-2, -0x1.6a8c4fd055a66p-45)
|
||||
A(0x1.4c00000000000p+0, -0x1.0a324e2739000p-2, -0x1.c6bee7ef4030ep-47)
|
||||
A(0x1.4a00000000000p+0, -0x1.0402594b4d000p-2, -0x1.036b89ef42d7fp-48)
|
||||
A(0x1.4a00000000000p+0, -0x1.0402594b4d000p-2, -0x1.036b89ef42d7fp-48)
|
||||
A(0x1.4800000000000p+0, -0x1.fb9186d5e4000p-3, 0x1.d572aab993c87p-47)
|
||||
A(0x1.4600000000000p+0, -0x1.ef0adcbdc6000p-3, 0x1.b26b79c86af24p-45)
|
||||
A(0x1.4400000000000p+0, -0x1.e27076e2af000p-3, -0x1.72f4f543fff10p-46)
|
||||
A(0x1.4200000000000p+0, -0x1.d5c216b4fc000p-3, 0x1.1ba91bbca681bp-45)
|
||||
A(0x1.4000000000000p+0, -0x1.c8ff7c79aa000p-3, 0x1.7794f689f8434p-45)
|
||||
A(0x1.4000000000000p+0, -0x1.c8ff7c79aa000p-3, 0x1.7794f689f8434p-45)
|
||||
A(0x1.3e00000000000p+0, -0x1.bc286742d9000p-3, 0x1.94eb0318bb78fp-46)
|
||||
A(0x1.3c00000000000p+0, -0x1.af3c94e80c000p-3, 0x1.a4e633fcd9066p-52)
|
||||
A(0x1.3a00000000000p+0, -0x1.a23bc1fe2b000p-3, -0x1.58c64dc46c1eap-45)
|
||||
A(0x1.3a00000000000p+0, -0x1.a23bc1fe2b000p-3, -0x1.58c64dc46c1eap-45)
|
||||
A(0x1.3800000000000p+0, -0x1.9525a9cf45000p-3, -0x1.ad1d904c1d4e3p-45)
|
||||
A(0x1.3600000000000p+0, -0x1.87fa06520d000p-3, 0x1.bbdbf7fdbfa09p-45)
|
||||
A(0x1.3400000000000p+0, -0x1.7ab890210e000p-3, 0x1.bdb9072534a58p-45)
|
||||
A(0x1.3400000000000p+0, -0x1.7ab890210e000p-3, 0x1.bdb9072534a58p-45)
|
||||
A(0x1.3200000000000p+0, -0x1.6d60fe719d000p-3, -0x1.0e46aa3b2e266p-46)
|
||||
A(0x1.3000000000000p+0, -0x1.5ff3070a79000p-3, -0x1.e9e439f105039p-46)
|
||||
A(0x1.3000000000000p+0, -0x1.5ff3070a79000p-3, -0x1.e9e439f105039p-46)
|
||||
A(0x1.2e00000000000p+0, -0x1.526e5e3a1b000p-3, -0x1.0de8b90075b8fp-45)
|
||||
A(0x1.2c00000000000p+0, -0x1.44d2b6ccb8000p-3, 0x1.70cc16135783cp-46)
|
||||
A(0x1.2c00000000000p+0, -0x1.44d2b6ccb8000p-3, 0x1.70cc16135783cp-46)
|
||||
A(0x1.2a00000000000p+0, -0x1.371fc201e9000p-3, 0x1.178864d27543ap-48)
|
||||
A(0x1.2800000000000p+0, -0x1.29552f81ff000p-3, -0x1.48d301771c408p-45)
|
||||
A(0x1.2600000000000p+0, -0x1.1b72ad52f6000p-3, -0x1.e80a41811a396p-45)
|
||||
A(0x1.2600000000000p+0, -0x1.1b72ad52f6000p-3, -0x1.e80a41811a396p-45)
|
||||
A(0x1.2400000000000p+0, -0x1.0d77e7cd09000p-3, 0x1.a699688e85bf4p-47)
|
||||
A(0x1.2400000000000p+0, -0x1.0d77e7cd09000p-3, 0x1.a699688e85bf4p-47)
|
||||
A(0x1.2200000000000p+0, -0x1.fec9131dbe000p-4, -0x1.575545ca333f2p-45)
|
||||
A(0x1.2000000000000p+0, -0x1.e27076e2b0000p-4, 0x1.a342c2af0003cp-45)
|
||||
A(0x1.2000000000000p+0, -0x1.e27076e2b0000p-4, 0x1.a342c2af0003cp-45)
|
||||
A(0x1.1e00000000000p+0, -0x1.c5e548f5bc000p-4, -0x1.d0c57585fbe06p-46)
|
||||
A(0x1.1c00000000000p+0, -0x1.a926d3a4ae000p-4, 0x1.53935e85baac8p-45)
|
||||
A(0x1.1c00000000000p+0, -0x1.a926d3a4ae000p-4, 0x1.53935e85baac8p-45)
|
||||
A(0x1.1a00000000000p+0, -0x1.8c345d631a000p-4, 0x1.37c294d2f5668p-46)
|
||||
A(0x1.1a00000000000p+0, -0x1.8c345d631a000p-4, 0x1.37c294d2f5668p-46)
|
||||
A(0x1.1800000000000p+0, -0x1.6f0d28ae56000p-4, -0x1.69737c93373dap-45)
|
||||
A(0x1.1600000000000p+0, -0x1.51b073f062000p-4, 0x1.f025b61c65e57p-46)
|
||||
A(0x1.1600000000000p+0, -0x1.51b073f062000p-4, 0x1.f025b61c65e57p-46)
|
||||
A(0x1.1400000000000p+0, -0x1.341d7961be000p-4, 0x1.c5edaccf913dfp-45)
|
||||
A(0x1.1400000000000p+0, -0x1.341d7961be000p-4, 0x1.c5edaccf913dfp-45)
|
||||
A(0x1.1200000000000p+0, -0x1.16536eea38000p-4, 0x1.47c5e768fa309p-46)
|
||||
A(0x1.1000000000000p+0, -0x1.f0a30c0118000p-5, 0x1.d599e83368e91p-45)
|
||||
A(0x1.1000000000000p+0, -0x1.f0a30c0118000p-5, 0x1.d599e83368e91p-45)
|
||||
A(0x1.0e00000000000p+0, -0x1.b42dd71198000p-5, 0x1.c827ae5d6704cp-46)
|
||||
A(0x1.0e00000000000p+0, -0x1.b42dd71198000p-5, 0x1.c827ae5d6704cp-46)
|
||||
A(0x1.0c00000000000p+0, -0x1.77458f632c000p-5, -0x1.cfc4634f2a1eep-45)
|
||||
A(0x1.0c00000000000p+0, -0x1.77458f632c000p-5, -0x1.cfc4634f2a1eep-45)
|
||||
A(0x1.0a00000000000p+0, -0x1.39e87b9fec000p-5, 0x1.502b7f526feaap-48)
|
||||
A(0x1.0a00000000000p+0, -0x1.39e87b9fec000p-5, 0x1.502b7f526feaap-48)
|
||||
A(0x1.0800000000000p+0, -0x1.f829b0e780000p-6, -0x1.980267c7e09e4p-45)
|
||||
A(0x1.0800000000000p+0, -0x1.f829b0e780000p-6, -0x1.980267c7e09e4p-45)
|
||||
A(0x1.0600000000000p+0, -0x1.7b91b07d58000p-6, -0x1.88d5493faa639p-45)
|
||||
A(0x1.0400000000000p+0, -0x1.fc0a8b0fc0000p-7, -0x1.f1e7cf6d3a69cp-50)
|
||||
A(0x1.0400000000000p+0, -0x1.fc0a8b0fc0000p-7, -0x1.f1e7cf6d3a69cp-50)
|
||||
A(0x1.0200000000000p+0, -0x1.fe02a6b100000p-8, -0x1.9e23f0dda40e4p-46)
|
||||
A(0x1.0200000000000p+0, -0x1.fe02a6b100000p-8, -0x1.9e23f0dda40e4p-46)
|
||||
A(0x1.0000000000000p+0, 0x0.0000000000000p+0, 0x0.0000000000000p+0)
|
||||
A(0x1.0000000000000p+0, 0x0.0000000000000p+0, 0x0.0000000000000p+0)
|
||||
A(0x1.fc00000000000p-1, 0x1.0101575890000p-7, -0x1.0c76b999d2be8p-46)
|
||||
A(0x1.f800000000000p-1, 0x1.0205658938000p-6, -0x1.3dc5b06e2f7d2p-45)
|
||||
A(0x1.f400000000000p-1, 0x1.8492528c90000p-6, -0x1.aa0ba325a0c34p-45)
|
||||
A(0x1.f000000000000p-1, 0x1.0415d89e74000p-5, 0x1.111c05cf1d753p-47)
|
||||
A(0x1.ec00000000000p-1, 0x1.466aed42e0000p-5, -0x1.c167375bdfd28p-45)
|
||||
A(0x1.e800000000000p-1, 0x1.894aa149fc000p-5, -0x1.97995d05a267dp-46)
|
||||
A(0x1.e400000000000p-1, 0x1.ccb73cdddc000p-5, -0x1.a68f247d82807p-46)
|
||||
A(0x1.e200000000000p-1, 0x1.eea31c006c000p-5, -0x1.e113e4fc93b7bp-47)
|
||||
A(0x1.de00000000000p-1, 0x1.1973bd1466000p-4, -0x1.5325d560d9e9bp-45)
|
||||
A(0x1.da00000000000p-1, 0x1.3bdf5a7d1e000p-4, 0x1.cc85ea5db4ed7p-45)
|
||||
A(0x1.d600000000000p-1, 0x1.5e95a4d97a000p-4, -0x1.c69063c5d1d1ep-45)
|
||||
A(0x1.d400000000000p-1, 0x1.700d30aeac000p-4, 0x1.c1e8da99ded32p-49)
|
||||
A(0x1.d000000000000p-1, 0x1.9335e5d594000p-4, 0x1.3115c3abd47dap-45)
|
||||
A(0x1.cc00000000000p-1, 0x1.b6ac88dad6000p-4, -0x1.390802bf768e5p-46)
|
||||
A(0x1.ca00000000000p-1, 0x1.c885801bc4000p-4, 0x1.646d1c65aacd3p-45)
|
||||
A(0x1.c600000000000p-1, 0x1.ec739830a2000p-4, -0x1.dc068afe645e0p-45)
|
||||
A(0x1.c400000000000p-1, 0x1.fe89139dbe000p-4, -0x1.534d64fa10afdp-45)
|
||||
A(0x1.c000000000000p-1, 0x1.1178e8227e000p-3, 0x1.1ef78ce2d07f2p-45)
|
||||
A(0x1.be00000000000p-1, 0x1.1aa2b7e23f000p-3, 0x1.ca78e44389934p-45)
|
||||
A(0x1.ba00000000000p-1, 0x1.2d1610c868000p-3, 0x1.39d6ccb81b4a1p-47)
|
||||
A(0x1.b800000000000p-1, 0x1.365fcb0159000p-3, 0x1.62fa8234b7289p-51)
|
||||
A(0x1.b400000000000p-1, 0x1.4913d8333b000p-3, 0x1.5837954fdb678p-45)
|
||||
A(0x1.b200000000000p-1, 0x1.527e5e4a1b000p-3, 0x1.633e8e5697dc7p-45)
|
||||
A(0x1.ae00000000000p-1, 0x1.6574ebe8c1000p-3, 0x1.9cf8b2c3c2e78p-46)
|
||||
A(0x1.ac00000000000p-1, 0x1.6f0128b757000p-3, -0x1.5118de59c21e1p-45)
|
||||
A(0x1.aa00000000000p-1, 0x1.7898d85445000p-3, -0x1.c661070914305p-46)
|
||||
A(0x1.a600000000000p-1, 0x1.8beafeb390000p-3, -0x1.73d54aae92cd1p-47)
|
||||
A(0x1.a400000000000p-1, 0x1.95a5adcf70000p-3, 0x1.7f22858a0ff6fp-47)
|
||||
A(0x1.a000000000000p-1, 0x1.a93ed3c8ae000p-3, -0x1.8724350562169p-45)
|
||||
A(0x1.9e00000000000p-1, 0x1.b31d8575bd000p-3, -0x1.c358d4eace1aap-47)
|
||||
A(0x1.9c00000000000p-1, 0x1.bd087383be000p-3, -0x1.d4bc4595412b6p-45)
|
||||
A(0x1.9a00000000000p-1, 0x1.c6ffbc6f01000p-3, -0x1.1ec72c5962bd2p-48)
|
||||
A(0x1.9600000000000p-1, 0x1.db13db0d49000p-3, -0x1.aff2af715b035p-45)
|
||||
A(0x1.9400000000000p-1, 0x1.e530effe71000p-3, 0x1.212276041f430p-51)
|
||||
A(0x1.9200000000000p-1, 0x1.ef5ade4dd0000p-3, -0x1.a211565bb8e11p-51)
|
||||
A(0x1.9000000000000p-1, 0x1.f991c6cb3b000p-3, 0x1.bcbecca0cdf30p-46)
|
||||
A(0x1.8c00000000000p-1, 0x1.07138604d5800p-2, 0x1.89cdb16ed4e91p-48)
|
||||
A(0x1.8a00000000000p-1, 0x1.0c42d67616000p-2, 0x1.7188b163ceae9p-45)
|
||||
A(0x1.8800000000000p-1, 0x1.1178e8227e800p-2, -0x1.c210e63a5f01cp-45)
|
||||
A(0x1.8600000000000p-1, 0x1.16b5ccbacf800p-2, 0x1.b9acdf7a51681p-45)
|
||||
A(0x1.8400000000000p-1, 0x1.1bf99635a6800p-2, 0x1.ca6ed5147bdb7p-45)
|
||||
A(0x1.8200000000000p-1, 0x1.214456d0eb800p-2, 0x1.a87deba46baeap-47)
|
||||
A(0x1.7e00000000000p-1, 0x1.2bef07cdc9000p-2, 0x1.a9cfa4a5004f4p-45)
|
||||
A(0x1.7c00000000000p-1, 0x1.314f1e1d36000p-2, -0x1.8e27ad3213cb8p-45)
|
||||
A(0x1.7a00000000000p-1, 0x1.36b6776be1000p-2, 0x1.16ecdb0f177c8p-46)
|
||||
A(0x1.7800000000000p-1, 0x1.3c25277333000p-2, 0x1.83b54b606bd5cp-46)
|
||||
A(0x1.7600000000000p-1, 0x1.419b423d5e800p-2, 0x1.8e436ec90e09dp-47)
|
||||
A(0x1.7400000000000p-1, 0x1.4718dc271c800p-2, -0x1.f27ce0967d675p-45)
|
||||
A(0x1.7200000000000p-1, 0x1.4c9e09e173000p-2, -0x1.e20891b0ad8a4p-45)
|
||||
A(0x1.7000000000000p-1, 0x1.522ae0738a000p-2, 0x1.ebe708164c759p-45)
|
||||
A(0x1.6e00000000000p-1, 0x1.57bf753c8d000p-2, 0x1.fadedee5d40efp-46)
|
||||
A(0x1.6c00000000000p-1, 0x1.5d5bddf596000p-2, -0x1.a0b2a08a465dcp-47)
|
||||
},
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Arm Limited.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#ifndef _POW_DATA_H
|
||||
#define _POW_DATA_H
|
||||
|
||||
#include <features.h>
|
||||
|
||||
#define POW_LOG_TABLE_BITS 7
|
||||
#define POW_LOG_POLY_ORDER 8
|
||||
extern const struct pow_log_data {
|
||||
double ln2hi;
|
||||
double ln2lo;
|
||||
double poly[POW_LOG_POLY_ORDER - 1]; /* First coefficient is 1. */
|
||||
/* Note: the pad field is unused, but allows slightly faster indexing. */
|
||||
struct {
|
||||
double invc, pad, logc, logctail;
|
||||
} tab[1 << POW_LOG_TABLE_BITS];
|
||||
} __pow_log_data1;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,35 @@
|
|||
#include "libm.h"
|
||||
|
||||
#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1
|
||||
#define EPS DBL_EPSILON
|
||||
#elif FLT_EVAL_METHOD==2
|
||||
#define EPS LDBL_EPSILON
|
||||
#endif
|
||||
static const double_t toint = 1/EPS;
|
||||
|
||||
double round(double x)
|
||||
{
|
||||
union {double f; uint64_t i;} u = {x};
|
||||
int e = u.i >> 52 & 0x7ff;
|
||||
double_t y;
|
||||
|
||||
if (e >= 0x3ff+52)
|
||||
return x;
|
||||
if (u.i >> 63)
|
||||
x = -x;
|
||||
if (e < 0x3ff-1) {
|
||||
/* raise inexact if x!=0 */
|
||||
FORCE_EVAL(x + toint);
|
||||
return 0*u.f;
|
||||
}
|
||||
y = x + toint - toint - x;
|
||||
if (y > 0.5)
|
||||
y = y + x - 1;
|
||||
else if (y <= -0.5)
|
||||
y = y + x + 1;
|
||||
else
|
||||
y = y + x;
|
||||
if (u.i >> 63)
|
||||
y = -y;
|
||||
return y;
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
/* origin: FreeBSD /usr/src/lib/msun/src/e_sqrt.c */
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunSoft, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
/* sqrt(x)
|
||||
* Return correctly rounded sqrt.
|
||||
* ------------------------------------------
|
||||
* | Use the hardware sqrt if you have one |
|
||||
* ------------------------------------------
|
||||
* Method:
|
||||
* Bit by bit method using integer arithmetic. (Slow, but portable)
|
||||
* 1. Normalization
|
||||
* Scale x to y in [1,4) with even powers of 2:
|
||||
* find an integer k such that 1 <= (y=x*2^(2k)) < 4, then
|
||||
* sqrt(x) = 2^k * sqrt(y)
|
||||
* 2. Bit by bit computation
|
||||
* Let q = sqrt(y) truncated to i bit after binary point (q = 1),
|
||||
* i 0
|
||||
* i+1 2
|
||||
* s = 2*q , and y = 2 * ( y - q ). (1)
|
||||
* i i i i
|
||||
*
|
||||
* To compute q from q , one checks whether
|
||||
* i+1 i
|
||||
*
|
||||
* -(i+1) 2
|
||||
* (q + 2 ) <= y. (2)
|
||||
* i
|
||||
* -(i+1)
|
||||
* If (2) is false, then q = q ; otherwise q = q + 2 .
|
||||
* i+1 i i+1 i
|
||||
*
|
||||
* With some algebric manipulation, it is not difficult to see
|
||||
* that (2) is equivalent to
|
||||
* -(i+1)
|
||||
* s + 2 <= y (3)
|
||||
* i i
|
||||
*
|
||||
* The advantage of (3) is that s and y can be computed by
|
||||
* i i
|
||||
* the following recurrence formula:
|
||||
* if (3) is false
|
||||
*
|
||||
* s = s , y = y ; (4)
|
||||
* i+1 i i+1 i
|
||||
*
|
||||
* otherwise,
|
||||
* -i -(i+1)
|
||||
* s = s + 2 , y = y - s - 2 (5)
|
||||
* i+1 i i+1 i i
|
||||
*
|
||||
* One may easily use induction to prove (4) and (5).
|
||||
* Note. Since the left hand side of (3) contain only i+2 bits,
|
||||
* it does not necessary to do a full (53-bit) comparison
|
||||
* in (3).
|
||||
* 3. Final rounding
|
||||
* After generating the 53 bits result, we compute one more bit.
|
||||
* Together with the remainder, we can decide whether the
|
||||
* result is exact, bigger than 1/2ulp, or less than 1/2ulp
|
||||
* (it will never equal to 1/2ulp).
|
||||
* The rounding mode can be detected by checking whether
|
||||
* huge + tiny is equal to huge, and whether huge - tiny is
|
||||
* equal to huge for some floating point number "huge" and "tiny".
|
||||
*
|
||||
* Special cases:
|
||||
* sqrt(+-0) = +-0 ... exact
|
||||
* sqrt(inf) = inf
|
||||
* sqrt(-ve) = NaN ... with invalid signal
|
||||
* sqrt(NaN) = NaN ... with invalid signal for signaling NaN
|
||||
*/
|
||||
|
||||
#include "libm.h"
|
||||
|
||||
static const double tiny = 1.0e-300;
|
||||
|
||||
double sqrt(double x)
|
||||
{
|
||||
double z;
|
||||
int32_t sign = (int)0x80000000;
|
||||
int32_t ix0,s0,q,m,t,i;
|
||||
uint32_t r,t1,s1,ix1,q1;
|
||||
|
||||
EXTRACT_WORDS(ix0, ix1, x);
|
||||
|
||||
/* take care of Inf and NaN */
|
||||
if ((ix0&0x7ff00000) == 0x7ff00000) {
|
||||
return x*x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */
|
||||
}
|
||||
/* take care of zero */
|
||||
if (ix0 <= 0) {
|
||||
if (((ix0&~sign)|ix1) == 0)
|
||||
return x; /* sqrt(+-0) = +-0 */
|
||||
if (ix0 < 0)
|
||||
return (x-x)/(x-x); /* sqrt(-ve) = sNaN */
|
||||
}
|
||||
/* normalize x */
|
||||
m = ix0>>20;
|
||||
if (m == 0) { /* subnormal x */
|
||||
while (ix0 == 0) {
|
||||
m -= 21;
|
||||
ix0 |= (ix1>>11);
|
||||
ix1 <<= 21;
|
||||
}
|
||||
for (i=0; (ix0&0x00100000) == 0; i++)
|
||||
ix0<<=1;
|
||||
m -= i - 1;
|
||||
ix0 |= ix1>>(32-i);
|
||||
ix1 <<= i;
|
||||
}
|
||||
m -= 1023; /* unbias exponent */
|
||||
ix0 = (ix0&0x000fffff)|0x00100000;
|
||||
if (m & 1) { /* odd m, double x to make it even */
|
||||
ix0 += ix0 + ((ix1&sign)>>31);
|
||||
ix1 += ix1;
|
||||
}
|
||||
m >>= 1; /* m = [m/2] */
|
||||
|
||||
/* generate sqrt(x) bit by bit */
|
||||
ix0 += ix0 + ((ix1&sign)>>31);
|
||||
ix1 += ix1;
|
||||
q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */
|
||||
r = 0x00200000; /* r = moving bit from right to left */
|
||||
|
||||
while (r != 0) {
|
||||
t = s0 + r;
|
||||
if (t <= ix0) {
|
||||
s0 = t + r;
|
||||
ix0 -= t;
|
||||
q += r;
|
||||
}
|
||||
ix0 += ix0 + ((ix1&sign)>>31);
|
||||
ix1 += ix1;
|
||||
r >>= 1;
|
||||
}
|
||||
|
||||
r = sign;
|
||||
while (r != 0) {
|
||||
t1 = s1 + r;
|
||||
t = s0;
|
||||
if (t < ix0 || (t == ix0 && t1 <= ix1)) {
|
||||
s1 = t1 + r;
|
||||
if ((t1&sign) == sign && (s1&sign) == 0)
|
||||
s0++;
|
||||
ix0 -= t;
|
||||
if (ix1 < t1)
|
||||
ix0--;
|
||||
ix1 -= t1;
|
||||
q1 += r;
|
||||
}
|
||||
ix0 += ix0 + ((ix1&sign)>>31);
|
||||
ix1 += ix1;
|
||||
r >>= 1;
|
||||
}
|
||||
|
||||
/* use floating add to find out rounding direction */
|
||||
if ((ix0|ix1) != 0) {
|
||||
z = 1.0 - tiny; /* raise inexact flag */
|
||||
if (z >= 1.0) {
|
||||
z = 1.0 + tiny;
|
||||
if (q1 == (uint32_t)0xffffffff) {
|
||||
q1 = 0;
|
||||
q++;
|
||||
} else if (z > 1.0) {
|
||||
if (q1 == (uint32_t)0xfffffffe)
|
||||
q++;
|
||||
q1 += 2;
|
||||
} else
|
||||
q1 += q1 & 1;
|
||||
}
|
||||
}
|
||||
ix0 = (q>>1) + 0x3fe00000;
|
||||
ix1 = q1>>1;
|
||||
if (q&1)
|
||||
ix1 |= sign;
|
||||
INSERT_WORDS(z, ix0 + ((uint32_t)m << 20), ix1);
|
||||
return z;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
|
||||
char *dirname(char *s)
|
||||
{
|
||||
size_t i;
|
||||
if (!s || !*s) return ".";
|
||||
i = strlen(s)-1;
|
||||
for (; s[i]=='/'; i--) if (!i) return "/";
|
||||
for (; s[i]!='/'; i--) if (!i) return ".";
|
||||
for (; s[i]=='/'; i--) if (!i) return "/";
|
||||
s[i+1] = 0;
|
||||
return s;
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "los_context.h"
|
||||
/*
|
||||
this code uses the same lagged fibonacci generator as the
|
||||
original bsd random implementation except for the seeding
|
||||
which was broken in the original
|
||||
*/
|
||||
|
||||
static uint32_t init[] = {
|
||||
0x00000000,0x5851f42d,0xc0b18ccf,0xcbb5f646,
|
||||
0xc7033129,0x30705b04,0x20fd5db4,0x9a8b7f78,
|
||||
0x502959d8,0xab894868,0x6c0356a7,0x88cdb7ff,
|
||||
0xb477d43f,0x70a3a52b,0xa8e4baf1,0xfd8341fc,
|
||||
0x8ae16fd9,0x742d2f7a,0x0d1f0796,0x76035e09,
|
||||
0x40f7702c,0x6fa72ca5,0xaaa84157,0x58a0df74,
|
||||
0xc74a0364,0xae533cc4,0x04185faf,0x6de3b115,
|
||||
0x0cab8628,0xf043bfa4,0x398150e9,0x37521657};
|
||||
|
||||
static int n = 31;
|
||||
static int i = 3;
|
||||
static int j = 0;
|
||||
static uint32_t *x = init+1;
|
||||
|
||||
static uint32_t lcg31(uint32_t x) {
|
||||
return (1103515245*x + 12345) & 0x7fffffff;
|
||||
}
|
||||
|
||||
static uint64_t lcg64(uint64_t x) {
|
||||
return 6364136223846793005ull*x + 1;
|
||||
}
|
||||
|
||||
static void *savestate(void) {
|
||||
x[-1] = (n<<16)|(i<<8)|j;
|
||||
return x-1;
|
||||
}
|
||||
|
||||
static void loadstate(uint32_t *state) {
|
||||
x = state+1;
|
||||
n = x[-1]>>16;
|
||||
i = (x[-1]>>8)&0xff;
|
||||
j = x[-1]&0xff;
|
||||
}
|
||||
|
||||
static void __srandom(unsigned seed) {
|
||||
int k;
|
||||
uint64_t s = seed;
|
||||
|
||||
if (n == 0) {
|
||||
x[0] = s;
|
||||
return;
|
||||
}
|
||||
i = n == 31 || n == 7 ? 3 : 1;
|
||||
j = 0;
|
||||
for (k = 0; k < n; k++) {
|
||||
s = lcg64(s);
|
||||
x[k] = s>>32;
|
||||
}
|
||||
/* make sure x contains at least one odd number */
|
||||
x[0] |= 1;
|
||||
}
|
||||
|
||||
void srandom(unsigned seed) {
|
||||
unsigned int intSave;
|
||||
|
||||
intSave = LOS_IntLock();
|
||||
__srandom(seed);
|
||||
LOS_IntRestore(intSave);
|
||||
}
|
||||
|
||||
char *initstate(unsigned seed, char *state, size_t size) {
|
||||
void *old;
|
||||
unsigned int intSave;
|
||||
|
||||
if (size < 8)
|
||||
return 0;
|
||||
|
||||
intSave = LOS_IntLock();
|
||||
old = savestate();
|
||||
if (size < 32)
|
||||
n = 0;
|
||||
else if (size < 64)
|
||||
n = 7;
|
||||
else if (size < 128)
|
||||
n = 15;
|
||||
else if (size < 256)
|
||||
n = 31;
|
||||
else
|
||||
n = 63;
|
||||
x = (uint32_t*)state + 1;
|
||||
__srandom(seed);
|
||||
savestate();
|
||||
LOS_IntRestore(intSave);
|
||||
return old;
|
||||
}
|
||||
|
||||
char *setstate(char *state) {
|
||||
void *old;
|
||||
unsigned int intSave;
|
||||
|
||||
intSave = LOS_IntLock();
|
||||
old = savestate();
|
||||
loadstate((uint32_t*)state);
|
||||
LOS_IntRestore(intSave);
|
||||
return old;
|
||||
}
|
||||
|
||||
long random(void) {
|
||||
long k;
|
||||
unsigned int intSave;
|
||||
|
||||
intSave = LOS_IntLock();
|
||||
if (n == 0) {
|
||||
k = x[0] = lcg31(x[0]);
|
||||
goto end;
|
||||
}
|
||||
x[i] += x[j];
|
||||
k = x[i]>>1;
|
||||
if (++i == n)
|
||||
i = 0;
|
||||
if (++j == n)
|
||||
j = 0;
|
||||
end:
|
||||
LOS_IntRestore(intSave);
|
||||
return k;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
tre-mem.c - TRE memory allocator
|
||||
|
||||
Copyright (c) 2001-2009 Ville Laurikari <vl@iki.fi>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
This memory allocator is for allocating small memory blocks efficiently
|
||||
in terms of memory overhead and execution speed. The allocated blocks
|
||||
cannot be freed individually, only all at once. There can be multiple
|
||||
allocators, though.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tre.h"
|
||||
|
||||
/*
|
||||
This memory allocator is for allocating small memory blocks efficiently
|
||||
in terms of memory overhead and execution speed. The allocated blocks
|
||||
cannot be freed individually, only all at once. There can be multiple
|
||||
allocators, though.
|
||||
*/
|
||||
|
||||
/* Returns a new memory allocator or NULL if out of memory. */
|
||||
tre_mem_t
|
||||
tre_mem_new_impl(int provided, void *provided_block)
|
||||
{
|
||||
tre_mem_t mem;
|
||||
if (provided)
|
||||
{
|
||||
mem = provided_block;
|
||||
memset(mem, 0, sizeof(*mem));
|
||||
}
|
||||
else
|
||||
mem = xcalloc(1, sizeof(*mem));
|
||||
if (mem == NULL)
|
||||
return NULL;
|
||||
return mem;
|
||||
}
|
||||
|
||||
|
||||
/* Frees the memory allocator and all memory allocated with it. */
|
||||
void
|
||||
tre_mem_destroy(tre_mem_t mem)
|
||||
{
|
||||
tre_list_t *tmp, *l = mem->blocks;
|
||||
|
||||
while (l != NULL)
|
||||
{
|
||||
xfree(l->data);
|
||||
tmp = l->next;
|
||||
xfree(l);
|
||||
l = tmp;
|
||||
}
|
||||
xfree(mem);
|
||||
}
|
||||
|
||||
|
||||
/* Allocates a block of `size' bytes from `mem'. Returns a pointer to the
|
||||
allocated block or NULL if an underlying malloc() failed. */
|
||||
void *
|
||||
tre_mem_alloc_impl(tre_mem_t mem, int provided, void *provided_block,
|
||||
int zero, size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
if (mem->failed)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mem->n < size)
|
||||
{
|
||||
/* We need more memory than is available in the current block.
|
||||
Allocate a new block. */
|
||||
tre_list_t *l;
|
||||
if (provided)
|
||||
{
|
||||
if (provided_block == NULL)
|
||||
{
|
||||
mem->failed = 1;
|
||||
return NULL;
|
||||
}
|
||||
mem->ptr = provided_block;
|
||||
mem->n = TRE_MEM_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
int block_size;
|
||||
if (size * 8 > TRE_MEM_BLOCK_SIZE)
|
||||
block_size = size * 8;
|
||||
else
|
||||
block_size = TRE_MEM_BLOCK_SIZE;
|
||||
l = xmalloc(sizeof(*l));
|
||||
if (l == NULL)
|
||||
{
|
||||
mem->failed = 1;
|
||||
return NULL;
|
||||
}
|
||||
l->data = xmalloc(block_size);
|
||||
if (l->data == NULL)
|
||||
{
|
||||
xfree(l);
|
||||
mem->failed = 1;
|
||||
return NULL;
|
||||
}
|
||||
l->next = NULL;
|
||||
if (mem->current != NULL)
|
||||
mem->current->next = l;
|
||||
if (mem->blocks == NULL)
|
||||
mem->blocks = l;
|
||||
mem->current = l;
|
||||
mem->ptr = l->data;
|
||||
mem->n = block_size;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure the next pointer will be aligned. */
|
||||
size += ALIGN(mem->ptr + size, long);
|
||||
|
||||
/* Allocate from current block. */
|
||||
ptr = mem->ptr;
|
||||
mem->ptr += size;
|
||||
mem->n -= size;
|
||||
|
||||
/* Set to zero if needed. */
|
||||
if (zero)
|
||||
memset(ptr, 0, size);
|
||||
|
||||
return ptr;
|
||||
}
|
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
tre-internal.h - TRE internal definitions
|
||||
|
||||
Copyright (c) 2001-2009 Ville Laurikari <vl@iki.fi>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include <regex.h>
|
||||
#include <wchar.h>
|
||||
#include <wctype.h>
|
||||
#include "../include/features.h"
|
||||
|
||||
#undef TRE_MBSTATE
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#define TRE_REGEX_T_FIELD __opaque
|
||||
typedef int reg_errcode_t;
|
||||
|
||||
typedef wchar_t tre_char_t;
|
||||
|
||||
#define DPRINT(msg) do { } while(0)
|
||||
|
||||
#define elementsof(x) ( sizeof(x) / sizeof(x[0]) )
|
||||
|
||||
#define tre_mbrtowc(pwc, s, n, ps) (mbtowc((pwc), (s), (n)))
|
||||
|
||||
/* Wide characters. */
|
||||
typedef wint_t tre_cint_t;
|
||||
#define TRE_CHAR_MAX 0x10ffff
|
||||
|
||||
#define tre_isalnum iswalnum
|
||||
#define tre_isalpha iswalpha
|
||||
#define tre_isblank iswblank
|
||||
#define tre_iscntrl iswcntrl
|
||||
#define tre_isdigit iswdigit
|
||||
#define tre_isgraph iswgraph
|
||||
#define tre_islower iswlower
|
||||
#define tre_isprint iswprint
|
||||
#define tre_ispunct iswpunct
|
||||
#define tre_isspace iswspace
|
||||
#define tre_isupper iswupper
|
||||
#define tre_isxdigit iswxdigit
|
||||
|
||||
#define tre_tolower towlower
|
||||
#define tre_toupper towupper
|
||||
#define tre_strlen wcslen
|
||||
|
||||
/* Use system provided iswctype() and wctype(). */
|
||||
typedef wctype_t tre_ctype_t;
|
||||
#define tre_isctype iswctype
|
||||
#define tre_ctype wctype
|
||||
|
||||
/* Returns number of bytes to add to (char *)ptr to make it
|
||||
properly aligned for the type. */
|
||||
#define ALIGN(ptr, type) \
|
||||
((((long)ptr) % sizeof(type)) \
|
||||
? (sizeof(type) - (((long)ptr) % sizeof(type))) \
|
||||
: 0)
|
||||
|
||||
#undef MAX
|
||||
#undef MIN
|
||||
#define MAX(a, b) (((a) >= (b)) ? (a) : (b))
|
||||
#define MIN(a, b) (((a) <= (b)) ? (a) : (b))
|
||||
|
||||
/* TNFA transition type. A TNFA state is an array of transitions,
|
||||
the terminator is a transition with NULL `state'. */
|
||||
typedef struct tnfa_transition tre_tnfa_transition_t;
|
||||
|
||||
struct tnfa_transition {
|
||||
/* Range of accepted characters. */
|
||||
tre_cint_t code_min;
|
||||
tre_cint_t code_max;
|
||||
/* Pointer to the destination state. */
|
||||
tre_tnfa_transition_t *state;
|
||||
/* ID number of the destination state. */
|
||||
int state_id;
|
||||
/* -1 terminated array of tags (or NULL). */
|
||||
int *tags;
|
||||
/* Assertion bitmap. */
|
||||
int assertions;
|
||||
/* Assertion parameters. */
|
||||
union {
|
||||
/* Character class assertion. */
|
||||
tre_ctype_t class;
|
||||
/* Back reference assertion. */
|
||||
int backref;
|
||||
} u;
|
||||
/* Negative character class assertions. */
|
||||
tre_ctype_t *neg_classes;
|
||||
};
|
||||
|
||||
|
||||
/* Assertions. */
|
||||
#define ASSERT_AT_BOL 1 /* Beginning of line. */
|
||||
#define ASSERT_AT_EOL 2 /* End of line. */
|
||||
#define ASSERT_CHAR_CLASS 4 /* Character class in `class'. */
|
||||
#define ASSERT_CHAR_CLASS_NEG 8 /* Character classes in `neg_classes'. */
|
||||
#define ASSERT_AT_BOW 16 /* Beginning of word. */
|
||||
#define ASSERT_AT_EOW 32 /* End of word. */
|
||||
#define ASSERT_AT_WB 64 /* Word boundary. */
|
||||
#define ASSERT_AT_WB_NEG 128 /* Not a word boundary. */
|
||||
#define ASSERT_BACKREF 256 /* A back reference in `backref'. */
|
||||
#define ASSERT_LAST 256
|
||||
|
||||
/* Tag directions. */
|
||||
typedef enum {
|
||||
TRE_TAG_MINIMIZE = 0,
|
||||
TRE_TAG_MAXIMIZE = 1
|
||||
} tre_tag_direction_t;
|
||||
|
||||
/* Instructions to compute submatch register values from tag values
|
||||
after a successful match. */
|
||||
struct tre_submatch_data {
|
||||
/* Tag that gives the value for rm_so (submatch start offset). */
|
||||
int so_tag;
|
||||
/* Tag that gives the value for rm_eo (submatch end offset). */
|
||||
int eo_tag;
|
||||
/* List of submatches this submatch is contained in. */
|
||||
int *parents;
|
||||
};
|
||||
|
||||
typedef struct tre_submatch_data tre_submatch_data_t;
|
||||
|
||||
|
||||
/* TNFA definition. */
|
||||
typedef struct tnfa tre_tnfa_t;
|
||||
|
||||
struct tnfa {
|
||||
tre_tnfa_transition_t *transitions;
|
||||
unsigned int num_transitions;
|
||||
tre_tnfa_transition_t *initial;
|
||||
tre_tnfa_transition_t *final;
|
||||
tre_submatch_data_t *submatch_data;
|
||||
char *firstpos_chars;
|
||||
int first_char;
|
||||
unsigned int num_submatches;
|
||||
tre_tag_direction_t *tag_directions;
|
||||
int *minimal_tags;
|
||||
int num_tags;
|
||||
int num_minimals;
|
||||
int end_tag;
|
||||
int num_states;
|
||||
int cflags;
|
||||
int have_backrefs;
|
||||
int have_approx;
|
||||
};
|
||||
|
||||
/* from tre-mem.h: */
|
||||
|
||||
#define TRE_MEM_BLOCK_SIZE 1024
|
||||
|
||||
typedef struct tre_list {
|
||||
void *data;
|
||||
struct tre_list *next;
|
||||
} tre_list_t;
|
||||
|
||||
typedef struct tre_mem_struct {
|
||||
tre_list_t *blocks;
|
||||
tre_list_t *current;
|
||||
char *ptr;
|
||||
size_t n;
|
||||
int failed;
|
||||
void **provided;
|
||||
} *tre_mem_t;
|
||||
|
||||
#define tre_mem_new_impl __tre_mem_new_impl
|
||||
#define tre_mem_alloc_impl __tre_mem_alloc_impl
|
||||
#define tre_mem_destroy __tre_mem_destroy
|
||||
|
||||
hidden tre_mem_t tre_mem_new_impl(int provided, void *provided_block);
|
||||
hidden void *tre_mem_alloc_impl(tre_mem_t mem, int provided, void *provided_block,
|
||||
int zero, size_t size);
|
||||
|
||||
/* Returns a new memory allocator or NULL if out of memory. */
|
||||
#define tre_mem_new() tre_mem_new_impl(0, NULL)
|
||||
|
||||
/* Allocates a block of `size' bytes from `mem'. Returns a pointer to the
|
||||
allocated block or NULL if an underlying malloc() failed. */
|
||||
#define tre_mem_alloc(mem, size) tre_mem_alloc_impl(mem, 0, NULL, 0, size)
|
||||
|
||||
/* Allocates a block of `size' bytes from `mem'. Returns a pointer to the
|
||||
allocated block or NULL if an underlying malloc() failed. The memory
|
||||
is set to zero. */
|
||||
#define tre_mem_calloc(mem, size) tre_mem_alloc_impl(mem, 0, NULL, 1, size)
|
||||
|
||||
#ifdef TRE_USE_ALLOCA
|
||||
/* alloca() versions. Like above, but memory is allocated with alloca()
|
||||
instead of malloc(). */
|
||||
|
||||
#define tre_mem_newa() \
|
||||
tre_mem_new_impl(1, alloca(sizeof(struct tre_mem_struct)))
|
||||
|
||||
#define tre_mem_alloca(mem, size) \
|
||||
((mem)->n >= (size) \
|
||||
? tre_mem_alloc_impl((mem), 1, NULL, 0, (size)) \
|
||||
: tre_mem_alloc_impl((mem), 1, alloca(TRE_MEM_BLOCK_SIZE), 0, (size)))
|
||||
#endif /* TRE_USE_ALLOCA */
|
||||
|
||||
|
||||
/* Frees the memory allocator and all memory allocated with it. */
|
||||
hidden void tre_mem_destroy(tre_mem_t mem);
|
||||
|
||||
#define xmalloc malloc
|
||||
#define xcalloc calloc
|
||||
#define xfree free
|
||||
#define xrealloc realloc
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
#include "stdio_impl.h"
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
FILE *__fdopen(int fd, const char *mode)
|
||||
{
|
||||
FILE *f;
|
||||
struct winsize wsz;
|
||||
pthread_mutex_t filelockinit = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
|
||||
|
||||
/* Check for valid initial mode character */
|
||||
if (!strchr("rwa", *mode)) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocate FILE+buffer or fail */
|
||||
if (!(f=malloc(sizeof *f + UNGET + BUFSIZ + sizeof(pthread_mutex_t)))) return 0;
|
||||
|
||||
/* Zero-fill only the struct, not the buffer */
|
||||
memset(f, 0, sizeof *f);
|
||||
|
||||
/* Impose mode restrictions */
|
||||
if (!strchr(mode, '+')) f->flags = (*mode == 'r') ? F_NOWR : F_NORD;
|
||||
|
||||
/* Apply close-on-exec flag */
|
||||
if (strchr(mode, 'e')) fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
|
||||
/* Set append mode on fd if opened for append */
|
||||
if (*mode == 'a') {
|
||||
int flags = fcntl(fd, F_GETFL);
|
||||
if (!(flags & O_APPEND))
|
||||
fcntl(fd, F_SETFL, flags | O_APPEND);
|
||||
f->flags |= F_APP;
|
||||
}
|
||||
|
||||
f->fd = fd;
|
||||
f->buf = (unsigned char *)f + sizeof *f + UNGET;
|
||||
f->buf_size = BUFSIZ;
|
||||
f->lock = (pthread_mutex_t *)((unsigned char *)f + sizeof *f + UNGET + BUFSIZ);
|
||||
memcpy(f->lock, &filelockinit, sizeof(pthread_mutex_t));
|
||||
|
||||
/* Activate line buffered mode for terminals */
|
||||
f->lbf = EOF;
|
||||
if (!(f->flags & F_NOWR) && !ioctl(fd, TIOCGWINSZ, &wsz))
|
||||
f->lbf = '\n';
|
||||
|
||||
/* Initialize op ptrs. No problem if some are unneeded. */
|
||||
f->read = __stdio_read;
|
||||
f->write = __stdio_write;
|
||||
f->seek = __stdio_seek;
|
||||
f->close = __stdio_close;
|
||||
|
||||
/* Add new FILE to open file list */
|
||||
return __ofl_add(f);
|
||||
}
|
||||
|
||||
weak_alias(__fdopen, fdopen);
|
|
@ -0,0 +1,16 @@
|
|||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
int __fmodeflags(const char *mode)
|
||||
{
|
||||
int flags;
|
||||
if (strchr(mode, '+')) flags = O_RDWR;
|
||||
else if (*mode == 'r') flags = O_RDONLY;
|
||||
else flags = O_WRONLY;
|
||||
if (strchr(mode, 'x')) flags |= O_EXCL;
|
||||
if (strchr(mode, 'e')) flags |= O_CLOEXEC;
|
||||
if (*mode != 'r') flags |= O_CREAT;
|
||||
if (*mode == 'w') flags |= O_TRUNC;
|
||||
if (*mode == 'a') flags |= O_APPEND;
|
||||
return flags;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#include "stdio_impl.h"
|
||||
#include "pthread.h"
|
||||
|
||||
int __lockfile(FILE *f)
|
||||
{
|
||||
return pthread_mutex_lock((pthread_mutex_t *)f->lock);
|
||||
}
|
||||
|
||||
int __unlockfile(FILE *f)
|
||||
{
|
||||
return pthread_mutex_unlock((pthread_mutex_t *)f->lock);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#include "stdio_impl.h"
|
||||
#include <unistd.h>
|
||||
|
||||
int __stdio_close(FILE *f)
|
||||
{
|
||||
return close(f->fd);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
#include "stdio_impl.h"
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
size_t __stdio_read(FILE *f, unsigned char *buf, size_t len)
|
||||
{
|
||||
struct iovec iov[2] = {
|
||||
{ .iov_base = buf, .iov_len = len - !!f->buf_size },
|
||||
{ .iov_base = f->buf, .iov_len = f->buf_size }
|
||||
};
|
||||
ssize_t cnt;
|
||||
|
||||
cnt = read(f->fd, iov[0].iov_base, iov[0].iov_len);
|
||||
if (iov[1].iov_len - iov[0].iov_len > 0) cnt += read(f->fd, iov[1].iov_base, iov[1].iov_len - iov[0].iov_len);
|
||||
if (cnt <= 0) {
|
||||
f->flags |= cnt ? F_ERR : F_EOF;
|
||||
return 0;
|
||||
}
|
||||
if (cnt <= iov[0].iov_len) return cnt;
|
||||
cnt -= iov[0].iov_len;
|
||||
f->rpos = f->buf;
|
||||
f->rend = f->buf + cnt;
|
||||
if (f->buf_size) buf[len-1] = *f->rpos++;
|
||||
return len;
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
#include "stdio_impl.h"
|
||||
#include <unistd.h>
|
||||
|
||||
#if 0
|
||||
static off64_t __stdio_lseek64(int fd, int offsetHigh, int offsetLow, off64_t *result, int whence)
|
||||
{
|
||||
off64_t ret;
|
||||
struct file *filep = NULL;
|
||||
off64_t offset = ((off64_t)offsetHigh << 32) + (uint)offsetLow; /* 32: offsetHigh is high 32 bits */
|
||||
|
||||
/* Get the file structure corresponding to the file descriptor. */
|
||||
ret = fs_getfilep(fd, &filep);
|
||||
if (ret < 0) {
|
||||
/* The errno value has already been set */
|
||||
return (off64_t)-get_errno();
|
||||
}
|
||||
|
||||
/* libc seekdir function should set the whence to SEEK_SET, so we can discard
|
||||
* the whence argument here */
|
||||
if (filep->f_oflags & O_DIRECTORY) {
|
||||
/* defensive coding */
|
||||
if (filep->f_dir == NULL) {
|
||||
return (off64_t)-EINVAL;
|
||||
}
|
||||
if (offsetLow == 0) {
|
||||
rewinddir(filep->f_dir);
|
||||
} else {
|
||||
seekdir(filep->f_dir, offsetLow);
|
||||
}
|
||||
ret = telldir(filep->f_dir);
|
||||
if (ret < 0) {
|
||||
return (off64_t)-get_errno();
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Then let file_seek do the real work */
|
||||
ret = file_seek64(filep, offset, whence);
|
||||
if (ret < 0) {
|
||||
return (off64_t)-get_errno();
|
||||
}
|
||||
|
||||
out:
|
||||
*result = ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
off_t __stdio_seek(FILE *f, off_t off, int whence)
|
||||
{
|
||||
off_t result = 0;
|
||||
return lseek(f->fd, (unsigned int)off, whence) ? -1 : result;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
#include "stdio_impl.h"
|
||||
#include <sys/uio.h>
|
||||
|
||||
size_t __stdio_write(FILE *f, const unsigned char *buf, size_t len)
|
||||
{
|
||||
struct iovec iovs[2] = {
|
||||
{ .iov_base = f->wbase, .iov_len = f->wpos-f->wbase },
|
||||
{ .iov_base = (void *)buf, .iov_len = len }
|
||||
};
|
||||
struct iovec *iov = iovs;
|
||||
size_t rem = iov[0].iov_len + iov[1].iov_len;
|
||||
int iovcnt = 2;
|
||||
ssize_t cnt;
|
||||
for (;;) {
|
||||
cnt = write(f->fd, iov[0].iov_base, iov[0].iov_len);
|
||||
if (0 != iov[1].iov_len) cnt += write(f->fd, iov[1].iov_base, iov[1].iov_len);
|
||||
if (cnt == rem) {
|
||||
f->wend = f->buf + f->buf_size;
|
||||
f->wpos = f->wbase = f->buf;
|
||||
return len;
|
||||
}
|
||||
if (cnt < 0) {
|
||||
f->wpos = f->wbase = f->wend = 0;
|
||||
f->flags |= F_ERR;
|
||||
return iovcnt == 2 ? 0 : len-iov[0].iov_len;
|
||||
}
|
||||
rem -= cnt;
|
||||
if (cnt > iov[0].iov_len) {
|
||||
cnt -= iov[0].iov_len;
|
||||
iov++; iovcnt--;
|
||||
}
|
||||
iov[0].iov_base = (char *)iov[0].iov_base + cnt;
|
||||
iov[0].iov_len -= cnt;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
#include "stdio_impl.h"
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
size_t __stdout_write(FILE *f, const unsigned char *buf, size_t len)
|
||||
{
|
||||
struct winsize wsz;
|
||||
if (!(f->flags & F_SVB) && ioctl(f->fd, TIOCGWINSZ, &wsz)) {
|
||||
f->lbf = EOF;
|
||||
}
|
||||
return __stdio_write(f, buf, len);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#include <stdio_impl.h>
|
||||
|
||||
int __toread(FILE *f)
|
||||
{
|
||||
f->mode |= f->mode-1;
|
||||
if (f->wpos != f->wbase) f->write(f, 0, 0);
|
||||
f->wpos = f->wbase = f->wend = 0;
|
||||
if (f->flags & F_NORD) {
|
||||
f->flags |= F_ERR;
|
||||
return EOF;
|
||||
}
|
||||
f->rpos = f->rend = f->buf + f->buf_size;
|
||||
return (f->flags & F_EOF) ? EOF : 0;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#include "stdio_impl.h"
|
||||
|
||||
int __towrite(FILE *f)
|
||||
{
|
||||
f->mode |= f->mode-1;
|
||||
if (f->flags & F_NOWR) {
|
||||
f->flags |= F_ERR;
|
||||
return EOF;
|
||||
}
|
||||
/* Clear read buffer (easier than summoning nasal demons) */
|
||||
f->rpos = f->rend = 0;
|
||||
|
||||
/* Activate write through the buffer. */
|
||||
f->wpos = f->wbase = f->buf;
|
||||
f->wend = f->buf + f->buf_size;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
#include "stdio_impl.h"
|
||||
|
||||
/* This function assumes it will never be called if there is already
|
||||
* data buffered for reading. */
|
||||
|
||||
int __uflow(FILE *f)
|
||||
{
|
||||
unsigned char c;
|
||||
if (!__toread(f) && f->read(f, &c, 1)==1) return c;
|
||||
return EOF;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#include "stdio_impl.h"
|
||||
|
||||
void clearerr(FILE *f)
|
||||
{
|
||||
FLOCK(f);
|
||||
f->flags &= ~(F_EOF|F_ERR);
|
||||
FUNLOCK(f);
|
||||
}
|
||||
|
||||
weak_alias(clearerr, clearerr_unlocked);
|
|
@ -0,0 +1,36 @@
|
|||
#include "stdio_impl.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
static void dummy(FILE *f) { }
|
||||
weak_alias(dummy, __unlist_locked_file);
|
||||
|
||||
int fclose(FILE *f)
|
||||
{
|
||||
int r;
|
||||
|
||||
FLOCK(f);
|
||||
r = fflush(f);
|
||||
r |= f->close(f);
|
||||
FUNLOCK(f);
|
||||
|
||||
/* Past this point, f is closed and any further explict access
|
||||
* to it is undefined. However, it still exists as an entry in
|
||||
* the open file list and possibly in the thread's locked files
|
||||
* list, if it was closed while explicitly locked. Functions
|
||||
* which process these lists must tolerate dead FILE objects
|
||||
* (which necessarily have inactive buffer pointers) without
|
||||
* producing any side effects. */
|
||||
|
||||
if (f->flags & F_PERM) return r;
|
||||
|
||||
FILE **head = __ofl_lock();
|
||||
if (f->prev) f->prev->next = f->next;
|
||||
if (f->next) f->next->prev = f->prev;
|
||||
if (*head == f) *head = f->next;
|
||||
__ofl_unlock();
|
||||
|
||||
free(f->getln_buf);
|
||||
free(f);
|
||||
|
||||
return r;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#include "stdio_impl.h"
|
||||
|
||||
#undef feof
|
||||
|
||||
int feof(FILE *f)
|
||||
{
|
||||
FLOCK(f);
|
||||
int ret = !!(f->flags & F_EOF);
|
||||
FUNLOCK(f);
|
||||
return ret;
|
||||
}
|
||||
|
||||
weak_alias(feof, feof_unlocked);
|
||||
weak_alias(feof, _IO_feof_unlocked);
|
|
@ -0,0 +1,47 @@
|
|||
#include "stdio_impl.h"
|
||||
|
||||
/* stdout.c will override this if linked */
|
||||
static FILE *volatile dummy = 0;
|
||||
weak_alias(dummy, __stdout_used);
|
||||
weak_alias(dummy, __stderr_used);
|
||||
|
||||
int fflush(FILE *f)
|
||||
{
|
||||
if (!f) {
|
||||
int r = 0;
|
||||
if (__stdout_used) r |= fflush(__stdout_used);
|
||||
if (__stderr_used) r |= fflush(__stderr_used);
|
||||
|
||||
for (f=*__ofl_lock(); f; f=f->next) {
|
||||
FLOCK(f);
|
||||
if (f->wpos != f->wbase) r |= fflush(f);
|
||||
FUNLOCK(f);
|
||||
}
|
||||
__ofl_unlock();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
FLOCK(f);
|
||||
|
||||
/* If writing, flush output */
|
||||
if (f->wpos != f->wbase) {
|
||||
f->write(f, 0, 0);
|
||||
if (!f->wpos) {
|
||||
FUNLOCK(f);
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
|
||||
/* If reading, sync position, per POSIX */
|
||||
if (f->rpos != f->rend) lseek(f->fd, f->rpos-f->rend, SEEK_CUR);
|
||||
|
||||
/* Clear read and write modes */
|
||||
f->wpos = f->wbase = f->wend = 0;
|
||||
f->rpos = f->rend = 0;
|
||||
|
||||
FUNLOCK(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
weak_alias(fflush, fflush_unlocked);
|
|
@ -0,0 +1,46 @@
|
|||
#include "stdio_impl.h"
|
||||
#include <string.h>
|
||||
|
||||
#define MIN(a,b) ((a)<(b) ? (a) : (b))
|
||||
|
||||
char *fgets(char *restrict s, int n, FILE *restrict f)
|
||||
{
|
||||
char *p = s;
|
||||
unsigned char *z;
|
||||
size_t k;
|
||||
int c;
|
||||
|
||||
FLOCK(f);
|
||||
|
||||
if (n--<=1) {
|
||||
f->mode |= f->mode-1;
|
||||
FUNLOCK(f);
|
||||
if (n) return 0;
|
||||
*s = 0;
|
||||
return s;
|
||||
}
|
||||
|
||||
while (n) {
|
||||
if (f->rpos != f->rend) {
|
||||
z = memchr(f->rpos, '\n', f->rend - f->rpos);
|
||||
k = z ? z - f->rpos + 1 : f->rend - f->rpos;
|
||||
k = MIN(k, (size_t)n);
|
||||
memcpy(p, f->rpos, k);
|
||||
f->rpos += k;
|
||||
p += k;
|
||||
n -= k;
|
||||
if (z || !n) break;
|
||||
}
|
||||
if ((c = getc_unlocked(f)) < 0) {
|
||||
if (p==s || !feof(f)) s = 0;
|
||||
break;
|
||||
}
|
||||
n--;
|
||||
if ((*p++ = c) == '\n') break;
|
||||
}
|
||||
if (s) *p = 0;
|
||||
|
||||
FUNLOCK(f);
|
||||
|
||||
return s;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#include "stdio_impl.h"
|
||||
#include <errno.h>
|
||||
|
||||
int fileno(FILE *f)
|
||||
{
|
||||
FLOCK(f);
|
||||
int fd = f->fd;
|
||||
FUNLOCK(f);
|
||||
if (fd < 0) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
#include "stdio_impl.h"
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
FILE *fopen(const char *restrict filename, const char *restrict mode)
|
||||
{
|
||||
FILE *f;
|
||||
int fd;
|
||||
int flags;
|
||||
|
||||
/* Check for valid initial mode character */
|
||||
if (!strchr("rwa", *mode)) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compute the flags to pass to open() */
|
||||
flags = __fmodeflags(mode);
|
||||
|
||||
fd = open(filename, flags, 0666);
|
||||
if (fd < 0) return 0;
|
||||
if (flags & O_CLOEXEC)
|
||||
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
|
||||
#if !defined(__LP64__)
|
||||
if (fd > SHRT_MAX) {
|
||||
errno = EMFILE;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
f = __fdopen(fd, mode);
|
||||
if (f) return f;
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
weak_alias(fopen, fopen64);
|
|
@ -0,0 +1,10 @@
|
|||
#include "stdio_impl.h"
|
||||
#include <string.h>
|
||||
|
||||
int fputs(const char *restrict s, FILE *restrict f)
|
||||
{
|
||||
size_t l = strlen(s);
|
||||
return (fwrite(s, 1, l, f)==l) - 1;
|
||||
}
|
||||
|
||||
weak_alias(fputs, fputs_unlocked);
|
|
@ -0,0 +1,38 @@
|
|||
#include "stdio_impl.h"
|
||||
#include <string.h>
|
||||
|
||||
#define MIN(a,b) ((a)<(b) ? (a) : (b))
|
||||
|
||||
size_t fread(void *restrict destv, size_t size, size_t nmemb, FILE *restrict f)
|
||||
{
|
||||
unsigned char *dest = destv;
|
||||
size_t len = size*nmemb, l = len, k;
|
||||
if (!size) nmemb = 0;
|
||||
|
||||
FLOCK(f);
|
||||
|
||||
f->mode |= f->mode-1;
|
||||
|
||||
if (f->rpos != f->rend) {
|
||||
/* First exhaust the buffer. */
|
||||
k = MIN(f->rend - f->rpos, l);
|
||||
memcpy(dest, f->rpos, k);
|
||||
f->rpos += k;
|
||||
dest += k;
|
||||
l -= k;
|
||||
}
|
||||
|
||||
/* Read the remainder directly */
|
||||
for (; l; l-=k, dest+=k) {
|
||||
k = __toread(f) ? 0 : f->read(f, dest, l);
|
||||
if (!k) {
|
||||
FUNLOCK(f);
|
||||
return (len-l)/size;
|
||||
}
|
||||
}
|
||||
|
||||
FUNLOCK(f);
|
||||
return nmemb;
|
||||
}
|
||||
|
||||
weak_alias(fread, fread_unlocked);
|
|
@ -0,0 +1,41 @@
|
|||
#include "stdio_impl.h"
|
||||
|
||||
int __fseeko_unlocked(FILE *f, off_t off, int whence)
|
||||
{
|
||||
/* Adjust relative offset for unread data in buffer, if any. */
|
||||
if (whence == SEEK_CUR && f->rend) off -= f->rend - f->rpos;
|
||||
|
||||
/* Flush write buffer, and report error on failure. */
|
||||
if (f->wpos != f->wbase) {
|
||||
f->write(f, 0, 0);
|
||||
if (!f->wpos) return -1;
|
||||
}
|
||||
|
||||
/* Leave writing mode */
|
||||
f->wpos = f->wbase = f->wend = 0;
|
||||
|
||||
/* Perform the underlying seek. */
|
||||
if (lseek(f->fd, (unsigned int)off, whence) < 0) return -1;
|
||||
|
||||
/* If seek succeeded, file is seekable and we discard read buffer. */
|
||||
f->rpos = f->rend = 0;
|
||||
f->flags &= ~F_EOF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __fseeko(FILE *f, off_t off, int whence)
|
||||
{
|
||||
int result;
|
||||
FLOCK(f);
|
||||
result = __fseeko_unlocked(f, off, whence);
|
||||
FUNLOCK(f);
|
||||
return result;
|
||||
}
|
||||
|
||||
int fseek(FILE *f, long off, int whence)
|
||||
{
|
||||
return __fseeko(f, off, whence);
|
||||
}
|
||||
|
||||
weak_alias(__fseeko, fseeko);
|
|
@ -0,0 +1,39 @@
|
|||
#include "stdio_impl.h"
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
|
||||
off_t __ftello_unlocked(FILE *f)
|
||||
{
|
||||
off_t pos = lseek(f->fd, 0,
|
||||
(f->flags & F_APP) && f->wpos != f->wbase
|
||||
? SEEK_END : SEEK_CUR);
|
||||
if (pos < 0) return pos;
|
||||
|
||||
/* Adjust for data in buffer. */
|
||||
if (f->rend)
|
||||
pos += f->rpos - f->rend;
|
||||
else if (f->wbase)
|
||||
pos += f->wpos - f->wbase;
|
||||
return pos;
|
||||
}
|
||||
|
||||
off_t __ftello(FILE *f)
|
||||
{
|
||||
off_t pos;
|
||||
FLOCK(f);
|
||||
pos = __ftello_unlocked(f);
|
||||
FUNLOCK(f);
|
||||
return pos;
|
||||
}
|
||||
|
||||
long ftell(FILE *f)
|
||||
{
|
||||
off_t pos = __ftello(f);
|
||||
if (pos > LONG_MAX) {
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
weak_alias(__ftello, ftello);
|
|
@ -0,0 +1,38 @@
|
|||
#include "stdio_impl.h"
|
||||
#include <string.h>
|
||||
|
||||
size_t __fwritex(const unsigned char *restrict s, size_t l, FILE *restrict f)
|
||||
{
|
||||
size_t i=0;
|
||||
|
||||
if (!f->wend && __towrite(f)) return 0;
|
||||
|
||||
if (l > f->wend - f->wpos) return f->write(f, s, l);
|
||||
|
||||
if (f->lbf >= 0) {
|
||||
/* Match /^(.*\n|)/ */
|
||||
for (i=l; i && s[i-1] != '\n'; i--);
|
||||
if (i) {
|
||||
size_t n = f->write(f, s, i);
|
||||
if (n < i) return n;
|
||||
s += i;
|
||||
l -= i;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(f->wpos, s, l);
|
||||
f->wpos += l;
|
||||
return l+i;
|
||||
}
|
||||
|
||||
size_t fwrite(const void *restrict src, size_t size, size_t nmemb, FILE *restrict f)
|
||||
{
|
||||
size_t k, l = size*nmemb;
|
||||
if (!size) nmemb = 0;
|
||||
FLOCK(f);
|
||||
k = __fwritex(src, l, f);
|
||||
FUNLOCK(f);
|
||||
return k==l ? nmemb : k/size;
|
||||
}
|
||||
|
||||
weak_alias(fwrite, fwrite_unlocked);
|
|
@ -0,0 +1,28 @@
|
|||
#include "stdio_impl.h"
|
||||
#include <pthread.h>
|
||||
|
||||
static FILE *ofl_head;
|
||||
|
||||
static pthread_mutex_t locallock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
|
||||
|
||||
static int LOCK(void)
|
||||
{
|
||||
return pthread_mutex_lock(&locallock);
|
||||
}
|
||||
|
||||
static void UNLOCK(void)
|
||||
{
|
||||
(void)pthread_mutex_unlock(&locallock);
|
||||
}
|
||||
|
||||
|
||||
FILE **__ofl_lock()
|
||||
{
|
||||
LOCK();
|
||||
return &ofl_head;
|
||||
}
|
||||
|
||||
void __ofl_unlock()
|
||||
{
|
||||
UNLOCK();
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
#include "stdio_impl.h"
|
||||
|
||||
FILE *__ofl_add(FILE *f)
|
||||
{
|
||||
FILE **head = __ofl_lock();
|
||||
f->next = *head;
|
||||
if (*head) (*head)->prev = f;
|
||||
*head = f;
|
||||
__ofl_unlock();
|
||||
return f;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "stdio_impl.h"
|
||||
|
||||
void perror(const char *msg)
|
||||
{
|
||||
FILE *f = stderr;
|
||||
char *errstr = strerror(errno);
|
||||
|
||||
FLOCK(f);
|
||||
|
||||
/* Save stderr's orientation and encoding rule, since perror is not
|
||||
* permitted to change them. */
|
||||
void *old_locale = f->locale;
|
||||
int old_mode = f->mode;
|
||||
|
||||
if (msg && *msg) {
|
||||
fwrite(msg, strlen(msg), 1, f);
|
||||
fputc(':', f);
|
||||
fputc(' ', f);
|
||||
}
|
||||
fwrite(errstr, strlen(errstr), 1, f);
|
||||
fputc('\n', f);
|
||||
|
||||
f->mode = old_mode;
|
||||
f->locale = old_locale;
|
||||
|
||||
FUNLOCK(f);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#include "stdio_impl.h"
|
||||
|
||||
void rewind(FILE *f)
|
||||
{
|
||||
FLOCK(f);
|
||||
__fseeko_unlocked(f, 0, SEEK_SET);
|
||||
f->flags &= ~F_ERR;
|
||||
FUNLOCK(f);
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#include "stdio_impl.h"
|
||||
#include <pthread.h>
|
||||
|
||||
#undef stderr
|
||||
|
||||
static pthread_mutex_t locallock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
|
||||
static unsigned char buf[UNGET];
|
||||
hidden FILE __stderr_FILE = {
|
||||
.buf = buf+UNGET,
|
||||
.buf_size = 0,
|
||||
.fd = 2,
|
||||
.flags = F_PERM | F_NORD,
|
||||
.lbf = -1,
|
||||
.write = __stdio_write,
|
||||
.seek = __stdio_seek,
|
||||
.close = __stdio_close,
|
||||
.lock = &locallock,
|
||||
};
|
||||
FILE *const stderr = &__stderr_FILE;
|
||||
FILE *volatile __stderr_used = &__stderr_FILE;
|
|
@ -0,0 +1,20 @@
|
|||
#include "stdio_impl.h"
|
||||
#include <pthread.h>
|
||||
|
||||
#undef stdout
|
||||
|
||||
static pthread_mutex_t locallock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
|
||||
static unsigned char buf[BUFSIZ+UNGET];
|
||||
hidden FILE __stdout_FILE = {
|
||||
.buf = buf+UNGET,
|
||||
.buf_size = sizeof buf-UNGET,
|
||||
.fd = 1,
|
||||
.flags = F_PERM | F_NORD,
|
||||
.lbf = '\n',
|
||||
.write = __stdout_write,
|
||||
.seek = __stdio_seek,
|
||||
.close = __stdio_close,
|
||||
.lock = &locallock,
|
||||
};
|
||||
FILE *const stdout = &__stdout_FILE;
|
||||
FILE *volatile __stdout_used = &__stdout_FILE;
|
|
@ -0,0 +1,16 @@
|
|||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
int atoi(const char *s)
|
||||
{
|
||||
int n=0, neg=0;
|
||||
while (isspace(*s)) s++;
|
||||
switch (*s) {
|
||||
case '-': neg=1;
|
||||
case '+': s++;
|
||||
}
|
||||
/* Compute n as a negative number to avoid overflow on INT_MIN */
|
||||
while (isdigit(*s))
|
||||
n = 10*n - (*s++ - '0');
|
||||
return neg ? n : -n;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
long atol(const char *s)
|
||||
{
|
||||
long n=0;
|
||||
int neg=0;
|
||||
while (isspace(*s)) s++;
|
||||
switch (*s) {
|
||||
case '-': neg=1;
|
||||
case '+': s++;
|
||||
}
|
||||
/* Compute n as a negative number to avoid overflow on LONG_MIN */
|
||||
while (isdigit(*s))
|
||||
n = 10*n - (*s++ - '0');
|
||||
return neg ? n : -n;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
long long atoll(const char *s)
|
||||
{
|
||||
long long n=0;
|
||||
int neg=0;
|
||||
while (isspace(*s)) s++;
|
||||
switch (*s) {
|
||||
case '-': neg=1;
|
||||
case '+': s++;
|
||||
}
|
||||
/* Compute n as a negative number to avoid overflow on LLONG_MIN */
|
||||
while (isdigit(*s))
|
||||
n = 10*n - (*s++ - '0');
|
||||
return neg ? n : -n;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
#include "stdio_impl.h"
|
||||
#include "intscan.h"
|
||||
#include "shgetc.h"
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
|
||||
static unsigned long long strtox(const char *s, char **p, int base, unsigned long long lim)
|
||||
{
|
||||
FILE f;
|
||||
sh_fromstring(&f, s);
|
||||
shlim(&f, 0);
|
||||
unsigned long long y = __intscan(&f, base, 1, lim);
|
||||
if (p) {
|
||||
size_t cnt = shcnt(&f);
|
||||
*p = (char *)s + cnt;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
unsigned long long strtoull(const char *restrict s, char **restrict p, int base)
|
||||
{
|
||||
return strtox(s, p, base, ULLONG_MAX);
|
||||
}
|
||||
|
||||
unsigned long strtoul(const char *restrict s, char **restrict p, int base)
|
||||
{
|
||||
return strtox(s, p, base, ULONG_MAX);
|
||||
}
|
||||
|
||||
long strtol(const char *restrict s, char **restrict p, int base)
|
||||
{
|
||||
return strtox(s, p, base, 0UL+LONG_MIN);
|
||||
}
|
||||
|
||||
weak_alias(strtol, __strtol_internal);
|
||||
weak_alias(strtoul, __strtoul_internal);
|
||||
weak_alias(strtoull, __strtoull_internal);
|
|
@ -0,0 +1,27 @@
|
|||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define SS (sizeof(size_t))
|
||||
#define ALIGN (sizeof(size_t)-1)
|
||||
#define ONES ((size_t)-1/UCHAR_MAX)
|
||||
#define HIGHS (ONES * (UCHAR_MAX/2+1))
|
||||
#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
|
||||
|
||||
void *memchr(const void *src, int c, size_t n)
|
||||
{
|
||||
const unsigned char *s = src;
|
||||
c = (unsigned char)c;
|
||||
#ifdef __GNUC__
|
||||
for (; ((uintptr_t)s & ALIGN) && n && *s != c; s++, n--);
|
||||
if (n && *s != c) {
|
||||
typedef size_t __attribute__((__may_alias__)) word;
|
||||
const word *w;
|
||||
size_t k = ONES * c;
|
||||
for (w = (const void *)s; n>=SS && !HASZERO(*w^k); w++, n-=SS);
|
||||
s = (const void *)w;
|
||||
}
|
||||
#endif
|
||||
for (; n && *s != c; s++, n--);
|
||||
return n ? (void *)s : 0;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#include <string.h>
|
||||
|
||||
int memcmp(const void *vl, const void *vr, size_t n)
|
||||
{
|
||||
const unsigned char *l=vl, *r=vr;
|
||||
for (; n && *l == *r; n--, l++, r++);
|
||||
return n ? *l-*r : 0;
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <endian.h>
|
||||
|
||||
void *memcpy(void *restrict dest, const void *restrict src, size_t n)
|
||||
{
|
||||
unsigned char *d = dest;
|
||||
const unsigned char *s = src;
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define LS >>
|
||||
#define RS <<
|
||||
#else
|
||||
#define LS <<
|
||||
#define RS >>
|
||||
#endif
|
||||
|
||||
typedef uint32_t __attribute__((__may_alias__)) u32;
|
||||
uint32_t w, x;
|
||||
|
||||
for (; (uintptr_t)s % 4 && n; n--) *d++ = *s++;
|
||||
|
||||
if ((uintptr_t)d % 4 == 0) {
|
||||
for (; n>=16; s+=16, d+=16, n-=16) {
|
||||
*(u32 *)(d+0) = *(u32 *)(s+0);
|
||||
*(u32 *)(d+4) = *(u32 *)(s+4);
|
||||
*(u32 *)(d+8) = *(u32 *)(s+8);
|
||||
*(u32 *)(d+12) = *(u32 *)(s+12);
|
||||
}
|
||||
if (n&8) {
|
||||
*(u32 *)(d+0) = *(u32 *)(s+0);
|
||||
*(u32 *)(d+4) = *(u32 *)(s+4);
|
||||
d += 8; s += 8;
|
||||
}
|
||||
if (n&4) {
|
||||
*(u32 *)(d+0) = *(u32 *)(s+0);
|
||||
d += 4; s += 4;
|
||||
}
|
||||
if (n&2) {
|
||||
*d++ = *s++; *d++ = *s++;
|
||||
}
|
||||
if (n&1) {
|
||||
*d = *s;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
if (n >= 32) switch ((uintptr_t)d % 4) {
|
||||
case 1:
|
||||
w = *(u32 *)s;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
n -= 3;
|
||||
for (; n>=17; s+=16, d+=16, n-=16) {
|
||||
x = *(u32 *)(s+1);
|
||||
*(u32 *)(d+0) = (w LS 24) | (x RS 8);
|
||||
w = *(u32 *)(s+5);
|
||||
*(u32 *)(d+4) = (x LS 24) | (w RS 8);
|
||||
x = *(u32 *)(s+9);
|
||||
*(u32 *)(d+8) = (w LS 24) | (x RS 8);
|
||||
w = *(u32 *)(s+13);
|
||||
*(u32 *)(d+12) = (x LS 24) | (w RS 8);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
w = *(u32 *)s;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
n -= 2;
|
||||
for (; n>=18; s+=16, d+=16, n-=16) {
|
||||
x = *(u32 *)(s+2);
|
||||
*(u32 *)(d+0) = (w LS 16) | (x RS 16);
|
||||
w = *(u32 *)(s+6);
|
||||
*(u32 *)(d+4) = (x LS 16) | (w RS 16);
|
||||
x = *(u32 *)(s+10);
|
||||
*(u32 *)(d+8) = (w LS 16) | (x RS 16);
|
||||
w = *(u32 *)(s+14);
|
||||
*(u32 *)(d+12) = (x LS 16) | (w RS 16);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
w = *(u32 *)s;
|
||||
*d++ = *s++;
|
||||
n -= 1;
|
||||
for (; n>=19; s+=16, d+=16, n-=16) {
|
||||
x = *(u32 *)(s+3);
|
||||
*(u32 *)(d+0) = (w LS 8) | (x RS 24);
|
||||
w = *(u32 *)(s+7);
|
||||
*(u32 *)(d+4) = (x LS 8) | (w RS 24);
|
||||
x = *(u32 *)(s+11);
|
||||
*(u32 *)(d+8) = (w LS 8) | (x RS 24);
|
||||
w = *(u32 *)(s+15);
|
||||
*(u32 *)(d+12) = (x LS 8) | (w RS 24);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (n&16) {
|
||||
*d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++;
|
||||
*d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++;
|
||||
*d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++;
|
||||
*d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++;
|
||||
}
|
||||
if (n&8) {
|
||||
*d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++;
|
||||
*d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++;
|
||||
}
|
||||
if (n&4) {
|
||||
*d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++;
|
||||
}
|
||||
if (n&2) {
|
||||
*d++ = *s++; *d++ = *s++;
|
||||
}
|
||||
if (n&1) {
|
||||
*d = *s;
|
||||
}
|
||||
return dest;
|
||||
#endif
|
||||
|
||||
for (; n; n--) *d++ = *s++;
|
||||
return dest;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#include <string.h>
|
||||
|
||||
void *__memrchr(const void *m, int c, size_t n)
|
||||
{
|
||||
const unsigned char *s = m;
|
||||
c = (unsigned char)c;
|
||||
while (n--) if (s[n]==c) return (void *)(s+n);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void *memset(void *dest, int c, size_t n)
|
||||
{
|
||||
unsigned char *s = dest;
|
||||
size_t k;
|
||||
|
||||
/* Fill head and tail with minimal branching. Each
|
||||
* conditional ensures that all the subsequently used
|
||||
* offsets are well-defined and in the dest region. */
|
||||
|
||||
if (!n) return dest;
|
||||
s[0] = c;
|
||||
s[n-1] = c;
|
||||
if (n <= 2) return dest;
|
||||
s[1] = c;
|
||||
s[2] = c;
|
||||
s[n-2] = c;
|
||||
s[n-3] = c;
|
||||
if (n <= 6) return dest;
|
||||
s[3] = c;
|
||||
s[n-4] = c;
|
||||
if (n <= 8) return dest;
|
||||
|
||||
/* Advance pointer to align it at a 4-byte boundary,
|
||||
* and truncate n to a multiple of 4. The previous code
|
||||
* already took care of any head/tail that get cut off
|
||||
* by the alignment. */
|
||||
|
||||
k = -(uintptr_t)s & 3;
|
||||
s += k;
|
||||
n -= k;
|
||||
n &= -4;
|
||||
|
||||
#ifdef __GNUC__
|
||||
typedef uint32_t __attribute__((__may_alias__)) u32;
|
||||
typedef uint64_t __attribute__((__may_alias__)) u64;
|
||||
|
||||
u32 c32 = ((u32)-1)/255 * (unsigned char)c;
|
||||
|
||||
/* In preparation to copy 32 bytes at a time, aligned on
|
||||
* an 8-byte bounary, fill head/tail up to 28 bytes each.
|
||||
* As in the initial byte-based head/tail fill, each
|
||||
* conditional below ensures that the subsequent offsets
|
||||
* are valid (e.g. !(n<=24) implies n>=28). */
|
||||
|
||||
*(u32 *)(s+0) = c32;
|
||||
*(u32 *)(s+n-4) = c32;
|
||||
if (n <= 8) return dest;
|
||||
*(u32 *)(s+4) = c32;
|
||||
*(u32 *)(s+8) = c32;
|
||||
*(u32 *)(s+n-12) = c32;
|
||||
*(u32 *)(s+n-8) = c32;
|
||||
if (n <= 24) return dest;
|
||||
*(u32 *)(s+12) = c32;
|
||||
*(u32 *)(s+16) = c32;
|
||||
*(u32 *)(s+20) = c32;
|
||||
*(u32 *)(s+24) = c32;
|
||||
*(u32 *)(s+n-28) = c32;
|
||||
*(u32 *)(s+n-24) = c32;
|
||||
*(u32 *)(s+n-20) = c32;
|
||||
*(u32 *)(s+n-16) = c32;
|
||||
|
||||
/* Align to a multiple of 8 so we can fill 64 bits at a time,
|
||||
* and avoid writing the same bytes twice as much as is
|
||||
* practical without introducing additional branching. */
|
||||
|
||||
k = 24 + ((uintptr_t)s & 4);
|
||||
s += k;
|
||||
n -= k;
|
||||
|
||||
/* If this loop is reached, 28 tail bytes have already been
|
||||
* filled, so any remainder when n drops below 32 can be
|
||||
* safely ignored. */
|
||||
|
||||
u64 c64 = c32 | ((u64)c32 << 32);
|
||||
for (; n >= 32; n-=32, s+=32) {
|
||||
*(u64 *)(s+0) = c64;
|
||||
*(u64 *)(s+8) = c64;
|
||||
*(u64 *)(s+16) = c64;
|
||||
*(u64 *)(s+24) = c64;
|
||||
}
|
||||
#else
|
||||
/* Pure C fallback with no aliasing violations. */
|
||||
for (; n; n--, s++) *s = c;
|
||||
#endif
|
||||
|
||||
return dest;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
#include <strings.h>
|
||||
#include <ctype.h>
|
||||
|
||||
int strcasecmp(const char *_l, const char *_r)
|
||||
{
|
||||
const unsigned char *l=(void *)_l, *r=(void *)_r;
|
||||
for (; *l && *r && (*l == *r || tolower(*l) == tolower(*r)); l++, r++);
|
||||
return tolower(*l) - tolower(*r);
|
||||
}
|
||||
|
||||
int __strcasecmp_l(const char *l, const char *r, locale_t loc)
|
||||
{
|
||||
return strcasecmp(l, r);
|
||||
}
|
||||
|
||||
weak_alias(__strcasecmp_l, strcasecmp_l);
|
|
@ -0,0 +1,7 @@
|
|||
#include <string.h>
|
||||
|
||||
char *strchr(const char *s, int c)
|
||||
{
|
||||
char *r = __strchrnul(s, c);
|
||||
return *(unsigned char *)r == (unsigned char)c ? r : 0;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define ALIGN (sizeof(size_t))
|
||||
#define ONES ((size_t)-1/UCHAR_MAX)
|
||||
#define HIGHS (ONES * (UCHAR_MAX/2+1))
|
||||
#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
|
||||
|
||||
char *__strchrnul(const char *s, int c)
|
||||
{
|
||||
c = (unsigned char)c;
|
||||
if (!c) return (char *)s + strlen(s);
|
||||
|
||||
#ifdef __GNUC__
|
||||
typedef size_t __attribute__((__may_alias__)) word;
|
||||
const word *w;
|
||||
for (; (uintptr_t)s % ALIGN; s++)
|
||||
if (!*s || *(unsigned char *)s == c) return (char *)s;
|
||||
size_t k = ONES * c;
|
||||
for (w = (void *)s; !HASZERO(*w) && !HASZERO(*w^k); w++);
|
||||
s = (void *)w;
|
||||
#endif
|
||||
for (; *s && *(unsigned char *)s != c; s++);
|
||||
return (char *)s;
|
||||
}
|
||||
|
||||
weak_alias(__strchrnul, strchrnul);
|
|
@ -0,0 +1,7 @@
|
|||
#include <string.h>
|
||||
|
||||
int strcmp(const char *l, const char *r)
|
||||
{
|
||||
for (; *l==*r && *l; l++, r++);
|
||||
return *(unsigned char *)l - *(unsigned char *)r;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#include "../include/string.h"
|
||||
|
||||
#define BITOP(a,b,op) \
|
||||
((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a))))
|
||||
|
||||
size_t strcspn(const char *s, const char *c)
|
||||
{
|
||||
const char *a = s;
|
||||
size_t byteset[32/sizeof(size_t)];
|
||||
|
||||
if (!c[0] || !c[1]) return __strchrnul(s, *c)-a;
|
||||
|
||||
memset(byteset, 0, sizeof byteset);
|
||||
for (; *c && BITOP(byteset, *(unsigned char *)c, |=); c++);
|
||||
for (; *s && !BITOP(byteset, *(unsigned char *)s, &); s++);
|
||||
return s-a;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
char *strdup(const char *s)
|
||||
{
|
||||
size_t l = strlen(s);
|
||||
char *d = malloc(l+1);
|
||||
if (!d) return NULL;
|
||||
return memcpy(d, s, l+1);
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define ALIGN (sizeof(size_t))
|
||||
#define ONES ((size_t)-1/UCHAR_MAX)
|
||||
#define HIGHS (ONES * (UCHAR_MAX/2+1))
|
||||
#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
|
||||
|
||||
size_t strlen(const char *s)
|
||||
{
|
||||
const char *a = s;
|
||||
#ifdef __GNUC__
|
||||
typedef size_t __attribute__((__may_alias__)) word;
|
||||
const word *w;
|
||||
for (; (uintptr_t)s % ALIGN; s++) if (!*s) return s-a;
|
||||
for (w = (const void *)s; !HASZERO(*w); w++);
|
||||
s = (const void *)w;
|
||||
#endif
|
||||
for (; *s; s++);
|
||||
return s-a;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#include <strings.h>
|
||||
#include <ctype.h>
|
||||
|
||||
int strncasecmp(const char *_l, const char *_r, size_t n)
|
||||
{
|
||||
const unsigned char *l=(void *)_l, *r=(void *)_r;
|
||||
if (!n--) return 0;
|
||||
for (; *l && *r && n && (*l == *r || tolower(*l) == tolower(*r)); l++, r++, n--);
|
||||
return tolower(*l) - tolower(*r);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#include <string.h>
|
||||
|
||||
int strncmp(const char *_l, const char *_r, size_t n)
|
||||
{
|
||||
const unsigned char *l=(void *)_l, *r=(void *)_r;
|
||||
if (!n--) return 0;
|
||||
for (; *l && *r && n && *l == *r ; l++, r++, n--);
|
||||
return *l - *r;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#include <string.h>
|
||||
|
||||
char *strrchr(const char *s, int c)
|
||||
{
|
||||
return __memrchr(s, c, strlen(s) + 1);
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static char *twobyte_strstr(const unsigned char *h, const unsigned char *n)
|
||||
{
|
||||
uint16_t nw = n[0]<<8 | n[1], hw = h[0]<<8 | h[1];
|
||||
for (h++; *h && hw != nw; hw = hw<<8 | *++h);
|
||||
return *h ? (char *)h-1 : 0;
|
||||
}
|
||||
|
||||
static char *threebyte_strstr(const unsigned char *h, const unsigned char *n)
|
||||
{
|
||||
uint32_t nw = n[0]<<24 | n[1]<<16 | n[2]<<8;
|
||||
uint32_t hw = h[0]<<24 | h[1]<<16 | h[2]<<8;
|
||||
for (h+=2; *h && hw != nw; hw = (hw|*++h)<<8);
|
||||
return *h ? (char *)h-2 : 0;
|
||||
}
|
||||
|
||||
static char *fourbyte_strstr(const unsigned char *h, const unsigned char *n)
|
||||
{
|
||||
uint32_t nw = n[0]<<24 | n[1]<<16 | n[2]<<8 | n[3];
|
||||
uint32_t hw = h[0]<<24 | h[1]<<16 | h[2]<<8 | h[3];
|
||||
for (h+=3; *h && hw != nw; hw = hw<<8 | *++h);
|
||||
return *h ? (char *)h-3 : 0;
|
||||
}
|
||||
|
||||
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
|
||||
#define BITOP(a,b,op) \
|
||||
((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a))))
|
||||
|
||||
static char *twoway_strstr(const unsigned char *h, const unsigned char *n)
|
||||
{
|
||||
const unsigned char *z;
|
||||
size_t l, ip, jp, k, p, ms, p0, mem, mem0;
|
||||
size_t byteset[32 / sizeof(size_t)] = { 0 };
|
||||
size_t shift[256];
|
||||
|
||||
/* Computing length of needle and fill shift table */
|
||||
for (l=0; n[l] && h[l]; l++)
|
||||
BITOP(byteset, n[l], |=), shift[n[l]] = l+1;
|
||||
if (n[l]) return 0; /* hit the end of h */
|
||||
|
||||
/* Compute maximal suffix */
|
||||
ip = -1; jp = 0; k = p = 1;
|
||||
while (jp+k<l) {
|
||||
if (n[ip+k] == n[jp+k]) {
|
||||
if (k == p) {
|
||||
jp += p;
|
||||
k = 1;
|
||||
} else k++;
|
||||
} else if (n[ip+k] > n[jp+k]) {
|
||||
jp += k;
|
||||
k = 1;
|
||||
p = jp - ip;
|
||||
} else {
|
||||
ip = jp++;
|
||||
k = p = 1;
|
||||
}
|
||||
}
|
||||
ms = ip;
|
||||
p0 = p;
|
||||
|
||||
/* And with the opposite comparison */
|
||||
ip = -1; jp = 0; k = p = 1;
|
||||
while (jp+k<l) {
|
||||
if (n[ip+k] == n[jp+k]) {
|
||||
if (k == p) {
|
||||
jp += p;
|
||||
k = 1;
|
||||
} else k++;
|
||||
} else if (n[ip+k] < n[jp+k]) {
|
||||
jp += k;
|
||||
k = 1;
|
||||
p = jp - ip;
|
||||
} else {
|
||||
ip = jp++;
|
||||
k = p = 1;
|
||||
}
|
||||
}
|
||||
if (ip+1 > ms+1) ms = ip;
|
||||
else p = p0;
|
||||
|
||||
/* Periodic needle? */
|
||||
if (memcmp(n, n+p, ms+1)) {
|
||||
mem0 = 0;
|
||||
p = MAX(ms, l-ms-1) + 1;
|
||||
} else mem0 = l-p;
|
||||
mem = 0;
|
||||
|
||||
/* Initialize incremental end-of-haystack pointer */
|
||||
z = h;
|
||||
|
||||
/* Search loop */
|
||||
for (;;) {
|
||||
/* Update incremental end-of-haystack pointer */
|
||||
if (z-h < l) {
|
||||
/* Fast estimate for MIN(l,63) */
|
||||
size_t grow = l | 63;
|
||||
const unsigned char *z2 = memchr(z, 0, grow);
|
||||
if (z2) {
|
||||
z = z2;
|
||||
if (z-h < l) return 0;
|
||||
} else z += grow;
|
||||
}
|
||||
|
||||
/* Check last byte first; advance by shift on mismatch */
|
||||
if (BITOP(byteset, h[l-1], &)) {
|
||||
k = l-shift[h[l-1]];
|
||||
if (k) {
|
||||
if (k < mem) k = mem;
|
||||
h += k;
|
||||
mem = 0;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
h += l;
|
||||
mem = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Compare right half */
|
||||
for (k=MAX(ms+1,mem); n[k] && n[k] == h[k]; k++);
|
||||
if (n[k]) {
|
||||
h += k-ms;
|
||||
mem = 0;
|
||||
continue;
|
||||
}
|
||||
/* Compare left half */
|
||||
for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--);
|
||||
if (k <= mem) return (char *)h;
|
||||
h += p;
|
||||
mem = mem0;
|
||||
}
|
||||
}
|
||||
|
||||
char *strstr(const char *h, const char *n)
|
||||
{
|
||||
/* Return immediately on empty needle */
|
||||
if (!n[0]) return (char *)h;
|
||||
|
||||
/* Use faster algorithms for short needles */
|
||||
h = strchr(h, *n);
|
||||
if (!h || !n[1]) return (char *)h;
|
||||
if (!h[1]) return 0;
|
||||
if (!n[2]) return twobyte_strstr((void *)h, (void *)n);
|
||||
if (!h[2]) return 0;
|
||||
if (!n[3]) return threebyte_strstr((void *)h, (void *)n);
|
||||
if (!h[3]) return 0;
|
||||
if (!n[4]) return fourbyte_strstr((void *)h, (void *)n);
|
||||
|
||||
return twoway_strstr((void *)h, (void *)n);
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#include <wchar.h>
|
||||
|
||||
wchar_t *wcschr(const wchar_t *s, wchar_t c)
|
||||
{
|
||||
if (!c) return (wchar_t *)s + wcslen(s);
|
||||
for (; *s && *s != c; s++);
|
||||
return *s ? (wchar_t *)s : 0;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#include <wchar.h>
|
||||
|
||||
size_t wcslen(const wchar_t *s)
|
||||
{
|
||||
const wchar_t *a;
|
||||
for (a=s; *s; s++);
|
||||
return s-a;
|
||||
}
|
|
@ -0,0 +1,281 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <langinfo.h>
|
||||
#include <locale.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
#include "locale_impl.h"
|
||||
#include "time_impl.h"
|
||||
|
||||
#define CURRENT_LOCALE NULL
|
||||
|
||||
static int is_leap(int y)
|
||||
{
|
||||
/* Avoid overflow */
|
||||
if (y>INT_MAX-1900) y -= 2000;
|
||||
y += 1900;
|
||||
return !(y%4) && ((y%100) || !(y%400));
|
||||
}
|
||||
|
||||
static int week_num(const struct tm *tm)
|
||||
{
|
||||
int val = (tm->tm_yday + 7U - (tm->tm_wday+6U)%7) / 7;
|
||||
/* If 1 Jan is just 1-3 days past Monday,
|
||||
* the previous week is also in this year. */
|
||||
if ((tm->tm_wday + 371U - tm->tm_yday - 2) % 7 <= 2)
|
||||
val++;
|
||||
if (!val) {
|
||||
val = 52;
|
||||
/* If 31 December of prev year a Thursday,
|
||||
* or Friday of a leap year, then the
|
||||
* prev year has 53 weeks. */
|
||||
int dec31 = (tm->tm_wday + 7U - tm->tm_yday - 1) % 7;
|
||||
if (dec31 == 4 || (dec31 == 5 && is_leap(tm->tm_year%400-1)))
|
||||
val++;
|
||||
} else if (val == 53) {
|
||||
/* If 1 January is not a Thursday, and not
|
||||
* a Wednesday of a leap year, then this
|
||||
* year has only 52 weeks. */
|
||||
int jan1 = (tm->tm_wday + 371U - tm->tm_yday) % 7;
|
||||
if (jan1 != 4 && (jan1 != 3 || !is_leap(tm->tm_year)))
|
||||
val = 1;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *tm, locale_t loc, int pad)
|
||||
{
|
||||
nl_item item;
|
||||
long long val;
|
||||
const char *fmt = "-";
|
||||
int width = 2, def_pad = '0';
|
||||
|
||||
switch (f) {
|
||||
case 'a':
|
||||
if (tm->tm_wday > 6U) goto string;
|
||||
item = ABDAY_1 + tm->tm_wday;
|
||||
goto nl_strcat;
|
||||
case 'A':
|
||||
if (tm->tm_wday > 6U) goto string;
|
||||
item = DAY_1 + tm->tm_wday;
|
||||
goto nl_strcat;
|
||||
case 'h':
|
||||
case 'b':
|
||||
if (tm->tm_mon > 11U) goto string;
|
||||
item = ABMON_1 + tm->tm_mon;
|
||||
goto nl_strcat;
|
||||
case 'B':
|
||||
if (tm->tm_mon > 11U) goto string;
|
||||
item = MON_1 + tm->tm_mon;
|
||||
goto nl_strcat;
|
||||
case 'c':
|
||||
item = D_T_FMT;
|
||||
goto nl_strftime;
|
||||
case 'C':
|
||||
val = (1900LL+tm->tm_year) / 100;
|
||||
goto number;
|
||||
case 'e':
|
||||
def_pad = '_';
|
||||
case 'd':
|
||||
val = tm->tm_mday;
|
||||
goto number;
|
||||
case 'D':
|
||||
fmt = "%m/%d/%y";
|
||||
goto recu_strftime;
|
||||
case 'F':
|
||||
fmt = "%Y-%m-%d";
|
||||
goto recu_strftime;
|
||||
case 'g':
|
||||
case 'G':
|
||||
val = tm->tm_year + 1900LL;
|
||||
if (tm->tm_yday < 3 && week_num(tm) != 1) val--;
|
||||
else if (tm->tm_yday > 360 && week_num(tm) == 1) val++;
|
||||
if (f=='g') val %= 100;
|
||||
else width = 4;
|
||||
goto number;
|
||||
case 'H':
|
||||
val = tm->tm_hour;
|
||||
goto number;
|
||||
case 'I':
|
||||
val = tm->tm_hour;
|
||||
if (!val) val = 12;
|
||||
else if (val > 12) val -= 12;
|
||||
goto number;
|
||||
case 'j':
|
||||
val = tm->tm_yday+1;
|
||||
width = 3;
|
||||
goto number;
|
||||
case 'm':
|
||||
val = tm->tm_mon+1;
|
||||
goto number;
|
||||
case 'M':
|
||||
val = tm->tm_min;
|
||||
goto number;
|
||||
case 'n':
|
||||
*l = 1;
|
||||
return "\n";
|
||||
case 'p':
|
||||
item = tm->tm_hour >= 12 ? PM_STR : AM_STR;
|
||||
goto nl_strcat;
|
||||
case 'r':
|
||||
item = T_FMT_AMPM;
|
||||
goto nl_strftime;
|
||||
case 'R':
|
||||
fmt = "%H:%M";
|
||||
goto recu_strftime;
|
||||
case 's':
|
||||
val = __tm_to_secs(tm) - tm->__tm_gmtoff;
|
||||
width = 1;
|
||||
goto number;
|
||||
case 'S':
|
||||
val = tm->tm_sec;
|
||||
goto number;
|
||||
case 't':
|
||||
*l = 1;
|
||||
return "\t";
|
||||
case 'T':
|
||||
fmt = "%H:%M:%S";
|
||||
goto recu_strftime;
|
||||
case 'u':
|
||||
val = tm->tm_wday ? tm->tm_wday : 7;
|
||||
width = 1;
|
||||
goto number;
|
||||
case 'U':
|
||||
val = (tm->tm_yday + 7U - tm->tm_wday) / 7;
|
||||
goto number;
|
||||
case 'W':
|
||||
val = (tm->tm_yday + 7U - (tm->tm_wday+6U)%7) / 7;
|
||||
goto number;
|
||||
case 'V':
|
||||
val = week_num(tm);
|
||||
goto number;
|
||||
case 'w':
|
||||
val = tm->tm_wday;
|
||||
width = 1;
|
||||
goto number;
|
||||
case 'x':
|
||||
item = D_FMT;
|
||||
goto nl_strftime;
|
||||
case 'X':
|
||||
item = T_FMT;
|
||||
goto nl_strftime;
|
||||
case 'y':
|
||||
val = (tm->tm_year + 1900LL) % 100;
|
||||
if (val < 0) val = -val;
|
||||
goto number;
|
||||
case 'Y':
|
||||
val = tm->tm_year + 1900LL;
|
||||
if (val >= 10000) {
|
||||
*l = snprintf(*s, sizeof *s, "+%lld", val);
|
||||
return *s;
|
||||
}
|
||||
width = 4;
|
||||
goto number;
|
||||
case 'z':
|
||||
if (tm->tm_isdst < 0) {
|
||||
*l = 0;
|
||||
return "";
|
||||
}
|
||||
*l = snprintf(*s, sizeof *s, "%+.4ld",
|
||||
tm->__tm_gmtoff/3600*100 + tm->__tm_gmtoff%3600/60);
|
||||
return *s;
|
||||
case 'Z':
|
||||
// unsupport tz
|
||||
return 0;
|
||||
case '%':
|
||||
*l = 1;
|
||||
return "%";
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
number:
|
||||
switch (pad ? pad : def_pad) {
|
||||
case '-': *l = snprintf(*s, sizeof *s, "%lld", val); break;
|
||||
case '_': *l = snprintf(*s, sizeof *s, "%*lld", width, val); break;
|
||||
case '0':
|
||||
default: *l = snprintf(*s, sizeof *s, "%0*lld", width, val); break;
|
||||
}
|
||||
return *s;
|
||||
nl_strcat:
|
||||
// unsuport loc
|
||||
return 0;
|
||||
string:
|
||||
*l = strlen(fmt);
|
||||
return fmt;
|
||||
nl_strftime:
|
||||
// unsuport loc
|
||||
return 0;
|
||||
recu_strftime:
|
||||
*l = __strftime_l(*s, sizeof *s, fmt, tm, loc);
|
||||
if (!*l) return 0;
|
||||
return *s;
|
||||
}
|
||||
|
||||
size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const struct tm *restrict tm, locale_t loc)
|
||||
{
|
||||
size_t l, k;
|
||||
char buf[100];
|
||||
char *p;
|
||||
const char *t;
|
||||
int pad, plus;
|
||||
unsigned long width;
|
||||
for (l=0; l<n; f++) {
|
||||
if (!*f) {
|
||||
s[l] = 0;
|
||||
return l;
|
||||
}
|
||||
if (*f != '%') {
|
||||
s[l++] = *f;
|
||||
continue;
|
||||
}
|
||||
f++;
|
||||
pad = 0;
|
||||
if (*f == '-' || *f == '_' || *f == '0') pad = *f++;
|
||||
if ((plus = (*f == '+'))) f++;
|
||||
width = strtoul(f, &p, 10);
|
||||
if (*p == 'C' || *p == 'F' || *p == 'G' || *p == 'Y') {
|
||||
if (!width && p!=f) width = 1;
|
||||
} else {
|
||||
width = 0;
|
||||
}
|
||||
f = p;
|
||||
if (*f == 'E' || *f == 'O') f++;
|
||||
t = __strftime_fmt_1(&buf, &k, *f, tm, loc, pad);
|
||||
if (!t) break;
|
||||
if (width) {
|
||||
/* Trim off any sign and leading zeros, then
|
||||
* count remaining digits to determine behavior
|
||||
* for the + flag. */
|
||||
if (*t=='+' || *t=='-') t++, k--;
|
||||
for (; *t=='0' && t[1]-'0'<10U; t++, k--);
|
||||
if (width < k) width = k;
|
||||
size_t d;
|
||||
for (d=0; t[d]-'0'<10U; d++);
|
||||
if (tm->tm_year < -1900) {
|
||||
s[l++] = '-';
|
||||
width--;
|
||||
} else if (plus && d+(width-k) >= (*p=='C'?3:5)) {
|
||||
s[l++] = '+';
|
||||
width--;
|
||||
}
|
||||
for (; width > k && l < n; width--)
|
||||
s[l++] = '0';
|
||||
}
|
||||
if (k > n-l) k = n-l;
|
||||
memcpy(s+l, t, k);
|
||||
l += k;
|
||||
}
|
||||
if (n) {
|
||||
if (l==n) l=n-1;
|
||||
s[l] = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t strftime(char *restrict s, size_t n, const char *restrict f, const struct tm *restrict tm)
|
||||
{
|
||||
return __strftime_l(s, n, f, tm, NULL);
|
||||
}
|
||||
|
||||
weak_alias(__strftime_l, strftime_l);
|
|
@ -0,0 +1,206 @@
|
|||
#include <stdlib.h>
|
||||
#include <langinfo.h>
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
char *strptime(const char *restrict s, const char *restrict f, struct tm *restrict tm)
|
||||
{
|
||||
int i, w, neg, adj, min, range, *dest, dummy;
|
||||
const char *ex;
|
||||
size_t len;
|
||||
int want_century = 0, century = 0, relyear = 0;
|
||||
while (*f) {
|
||||
if (*f != '%') {
|
||||
if (isspace(*f)) for (; *s && isspace(*s); s++);
|
||||
else if (*s != *f) return 0;
|
||||
else s++;
|
||||
f++;
|
||||
continue;
|
||||
}
|
||||
f++;
|
||||
if (*f == '+') f++;
|
||||
if (isdigit(*f)) {
|
||||
char *new_f;
|
||||
w=strtoul(f, &new_f, 10);
|
||||
f = new_f;
|
||||
} else {
|
||||
w=-1;
|
||||
}
|
||||
adj=0;
|
||||
switch (*f++) {
|
||||
case 'a': case 'A':
|
||||
dest = &tm->tm_wday;
|
||||
min = ABDAY_1;
|
||||
range = 7;
|
||||
goto symbolic_range;
|
||||
case 'b': case 'B': case 'h':
|
||||
dest = &tm->tm_mon;
|
||||
min = ABMON_1;
|
||||
range = 12;
|
||||
goto symbolic_range;
|
||||
case 'c':
|
||||
s = strptime(s, nl_langinfo(D_T_FMT), tm);
|
||||
if (!s) return 0;
|
||||
break;
|
||||
case 'C':
|
||||
dest = ¢ury;
|
||||
if (w<0) w=2;
|
||||
want_century |= 2;
|
||||
goto numeric_digits;
|
||||
case 'd': case 'e':
|
||||
dest = &tm->tm_mday;
|
||||
min = 1;
|
||||
range = 31;
|
||||
goto numeric_range;
|
||||
case 'D':
|
||||
s = strptime(s, "%m/%d/%y", tm);
|
||||
if (!s) return 0;
|
||||
break;
|
||||
case 'H':
|
||||
dest = &tm->tm_hour;
|
||||
min = 0;
|
||||
range = 24;
|
||||
goto numeric_range;
|
||||
case 'I':
|
||||
dest = &tm->tm_hour;
|
||||
min = 1;
|
||||
range = 12;
|
||||
goto numeric_range;
|
||||
case 'j':
|
||||
dest = &tm->tm_yday;
|
||||
min = 1;
|
||||
range = 366;
|
||||
adj = 1;
|
||||
goto numeric_range;
|
||||
case 'm':
|
||||
dest = &tm->tm_mon;
|
||||
min = 1;
|
||||
range = 12;
|
||||
adj = 1;
|
||||
goto numeric_range;
|
||||
case 'M':
|
||||
dest = &tm->tm_min;
|
||||
min = 0;
|
||||
range = 60;
|
||||
goto numeric_range;
|
||||
case 'n': case 't':
|
||||
for (; *s && isspace(*s); s++);
|
||||
break;
|
||||
case 'p':
|
||||
ex = nl_langinfo(AM_STR);
|
||||
len = strlen(ex);
|
||||
if (!strncasecmp(s, ex, len)) {
|
||||
tm->tm_hour %= 12;
|
||||
s += len;
|
||||
break;
|
||||
}
|
||||
ex = nl_langinfo(PM_STR);
|
||||
len = strlen(ex);
|
||||
if (!strncasecmp(s, ex, len)) {
|
||||
tm->tm_hour %= 12;
|
||||
tm->tm_hour += 12;
|
||||
s += len;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
case 'r':
|
||||
s = strptime(s, nl_langinfo(T_FMT_AMPM), tm);
|
||||
if (!s) return 0;
|
||||
break;
|
||||
case 'R':
|
||||
s = strptime(s, "%H:%M", tm);
|
||||
if (!s) return 0;
|
||||
break;
|
||||
case 'S':
|
||||
dest = &tm->tm_sec;
|
||||
min = 0;
|
||||
range = 61;
|
||||
goto numeric_range;
|
||||
case 'T':
|
||||
s = strptime(s, "%H:%M:%S", tm);
|
||||
if (!s) return 0;
|
||||
break;
|
||||
case 'U':
|
||||
case 'W':
|
||||
/* Throw away result, for now. (FIXME?) */
|
||||
dest = &dummy;
|
||||
min = 0;
|
||||
range = 54;
|
||||
goto numeric_range;
|
||||
case 'w':
|
||||
dest = &tm->tm_wday;
|
||||
min = 0;
|
||||
range = 7;
|
||||
goto numeric_range;
|
||||
case 'x':
|
||||
s = strptime(s, nl_langinfo(D_FMT), tm);
|
||||
if (!s) return 0;
|
||||
break;
|
||||
case 'X':
|
||||
s = strptime(s, nl_langinfo(T_FMT), tm);
|
||||
if (!s) return 0;
|
||||
break;
|
||||
case 'y':
|
||||
dest = &relyear;
|
||||
w = 2;
|
||||
want_century |= 1;
|
||||
goto numeric_digits;
|
||||
case 'Y':
|
||||
dest = &tm->tm_year;
|
||||
if (w<0) w=4;
|
||||
adj = 1900;
|
||||
want_century = 0;
|
||||
goto numeric_digits;
|
||||
case '%':
|
||||
if (*s++ != '%') return 0;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
numeric_range:
|
||||
if (!isdigit(*s)) return 0;
|
||||
*dest = 0;
|
||||
for (i=1; i<=min+range && isdigit(*s); i*=10)
|
||||
*dest = *dest * 10 + *s++ - '0';
|
||||
if (*dest - min >= (int)range) return 0;
|
||||
*dest -= adj;
|
||||
switch((char *)dest - (char *)tm) {
|
||||
case offsetof(struct tm, tm_yday):
|
||||
;
|
||||
}
|
||||
goto update;
|
||||
numeric_digits:
|
||||
neg = 0;
|
||||
if (*s == '+') s++;
|
||||
else if (*s == '-') neg=1, s++;
|
||||
if (!isdigit(*s)) return 0;
|
||||
for (*dest=i=0; i<w && isdigit(*s); i++)
|
||||
*dest = *dest * 10 + *s++ - '0';
|
||||
if (neg) *dest = -*dest;
|
||||
*dest -= adj;
|
||||
goto update;
|
||||
symbolic_range:
|
||||
for (i=2*range-1; i>=0; i--) {
|
||||
ex = nl_langinfo(min+i);
|
||||
len = strlen(ex);
|
||||
if (strncasecmp(s, ex, len)) continue;
|
||||
s += len;
|
||||
*dest = i % range;
|
||||
break;
|
||||
}
|
||||
if (i<0) return 0;
|
||||
goto update;
|
||||
update:
|
||||
//FIXME
|
||||
;
|
||||
}
|
||||
}
|
||||
if (want_century) {
|
||||
tm->tm_year = relyear;
|
||||
if (want_century & 2) tm->tm_year += century * 100 - 1900;
|
||||
else if (tm->tm_year <= 68) tm->tm_year += 100;
|
||||
}
|
||||
return (char *)s;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#include <time.h>
|
||||
#include "features.h"
|
||||
|
||||
hidden int __days_in_month(int, int);
|
||||
hidden int __month_to_secs(int, int);
|
||||
hidden long long __year_to_secs(long long, int *);
|
||||
hidden long long __tm_to_secs(const struct tm *);
|
||||
hidden const char *__tm_to_tzname(const struct tm *);
|
||||
hidden int __secs_to_tm(long long, struct tm *);
|
||||
hidden void __secs_to_zone(long long, int, int *, long *, long *, const char **);
|
||||
hidden const char *__strftime_fmt_1(char (*)[100], size_t *, int, const struct tm *, locale_t, int);
|
||||
extern hidden const char __utc[];
|
||||
|
||||
hidden size_t __strftime_l(char *restrict, size_t, const char *restrict, const struct tm *restrict, locale_t);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue