diff options
Diffstat (limited to 'posix')
121 files changed, 10435 insertions, 2144 deletions
diff --git a/posix/Makefile b/posix/Makefile index bdd3e71cca..74571cd036 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -1,4 +1,4 @@ -# Copyright (C) 1991-1999, 2000-2003, 2004 Free Software Foundation, Inc. +# Copyright (C) 1991-1999, 2000-2006, 2007 Free Software Foundation, Inc. # This file is part of the GNU C Library. # The GNU C Library is free software; you can redistribute it and/or @@ -28,7 +28,7 @@ headers := sys/utsname.h sys/times.h sys/wait.h sys/types.h unistd.h \ bits/local_lim.h tar.h bits/utsname.h bits/confname.h \ bits/waitflags.h bits/waitstatus.h sys/unistd.h sched.h \ bits/sched.h re_comp.h wait.h bits/environments.h cpio.h \ - sys/sysmacros.h spawn.h + sys/sysmacros.h spawn.h bits/unistd.h distribute := confstr.h TESTS TESTS2C.sed testcases.h \ PTESTS PTESTS2C.sed ptestcases.h \ @@ -65,7 +65,8 @@ routines := \ spawnattr_getpgroup spawnattr_setpgroup spawn spawnp spawni \ spawnattr_getsigmask spawnattr_getschedpolicy spawnattr_getschedparam \ spawnattr_setsigmask spawnattr_setschedpolicy spawnattr_setschedparam \ - posix_madvise + posix_madvise \ + get_child_max include ../Makeconfig @@ -80,10 +81,16 @@ tests := tstgetopt testfnm runtests runptests \ bug-regex13 bug-regex14 bug-regex15 bug-regex16 \ bug-regex17 bug-regex18 bug-regex19 bug-regex20 \ bug-regex21 bug-regex22 bug-regex23 bug-regex24 \ + bug-regex25 bug-regex26 bug-regex27 bug-regex28 \ tst-nice tst-nanosleep tst-regex2 \ transbug tst-rxspencer tst-pcre tst-boost \ - bug-ga1 tst-vfork1 tst-vfork2 tst-waitid \ - tst-getaddrinfo2 bug-glob1 bug-glob2 tst-sysconf + bug-ga1 tst-vfork1 tst-vfork2 tst-vfork3 tst-waitid \ + tst-getaddrinfo2 bug-glob1 bug-glob2 tst-sysconf \ + tst-execvp1 tst-execvp2 tst-execlp1 tst-execlp2 \ + tst-execv1 tst-execv2 tst-execl1 tst-execl2 \ + tst-execve1 tst-execve2 tst-execle1 tst-execle2 \ + tst-execvp3 tst-execvp4 tst-rfc3484 tst-rfc3484-2 \ + tst-getaddrinfo3 xtests := bug-ga2 ifeq (yes,$(build-shared)) test-srcs := globtest @@ -102,7 +109,8 @@ generated := $(addprefix wordexp-test-result, 1 2 3 4 5 6 7 8 9 10) \ bug-regex21-mem bug-regex21.mtrace \ tst-rxspencer-mem tst-rxspencer.mtrace tst-getconf.out \ tst-pcre-mem tst-pcre.mtrace tst-boost-mem tst-boost.mtrace \ - bug-ga2.mtrace bug-ga2-mem bug-glob2.mtrace bug-glob2-mem + bug-ga2.mtrace bug-ga2-mem bug-glob2.mtrace bug-glob2-mem \ + tst-vfork3-mem tst-vfork3.mtrace getconf.speclist include ../Rules @@ -135,20 +143,31 @@ CFLAGS-pwrite.c = -fexceptions -fasynchronous-unwind-tables CFLAGS-pwrite64.c = -fexceptions -fasynchronous-unwind-tables CFLAGS-sleep.c = -fexceptions CFLAGS-wait.c = -fexceptions -fasynchronous-unwind-tables -CFLAGS-waitid.c = -fexceptions +CFLAGS-waitid.c = -fexceptions -fasynchronous-unwind-tables CFLAGS-waitpid.c = -fexceptions -fasynchronous-unwind-tables CFLAGS-getopt.c = -fexceptions CFLAGS-wordexp.c = -fexceptions +CFLAGS-wordexp.os = -fomit-frame-pointer CFLAGS-sysconf.c = -fexceptions -DGETCONF_DIR='"$(libexecdir)/getconf"' CFLAGS-pathconf.c = -fexceptions CFLAGS-fpathconf.c = -fexceptions CFLAGS-spawn.c = -fexceptions +CFLAGS-spawn.os = -fomit-frame-pointer CFLAGS-spawnp.c = -fexceptions +CFLAGS-spawnp.os = -fomit-frame-pointer CFLAGS-spawni.c = -fexceptions +CFLAGS-spawni.os = -fomit-frame-pointer CFLAGS-pause.c = -fexceptions CFLAGS-glob.c = $(uses-callbacks) -fexceptions CFLAGS-glob64.c = $(uses-callbacks) -fexceptions CFLAGS-getconf.c = -DGETCONF_DIR='"$(libexecdir)/getconf"' +CFLAGS-execve.os = -fomit-frame-pointer +CFLAGS-fexecve.os = -fomit-frame-pointer +CFLAGS-execv.os = -fomit-frame-pointer +CFLAGS-execle.os = -fomit-frame-pointer +CFLAGS-execl.os = -fomit-frame-pointer +CFLAGS-execvp.os = -fomit-frame-pointer +CFLAGS-execlp.os = -fomit-frame-pointer tstgetopt-ARGS = -a -b -cfoobar --required foobar --optional=bazbug \ --none random --col --color --colour @@ -157,6 +176,7 @@ tst-exec-ARGS = -- $(built-program-cmd) tst-spawn-ARGS = -- $(built-program-cmd) tst-dir-ARGS = `pwd` `cd $(common-objdir)/$(subdir); pwd` `cd $(common-objdir); pwd` $(objpfx)tst-dir tst-chmod-ARGS = `pwd` +tst-vfork3-ARGS = --test-dir=$(objpfx) tst-fnmatch-ENV = LOCPATH=$(common-objpfx)localedata tst-regexloc-ENV = LOCPATH=$(common-objpfx)localedata @@ -171,11 +191,14 @@ bug-regex19-ENV = LOCPATH=$(common-objpfx)localedata bug-regex20-ENV = LOCPATH=$(common-objpfx)localedata bug-regex22-ENV = LOCPATH=$(common-objpfx)localedata bug-regex23-ENV = LOCPATH=$(common-objpfx)localedata +bug-regex25-ENV = LOCPATH=$(common-objpfx)localedata +bug-regex26-ENV = LOCPATH=$(common-objpfx)localedata tst-rxspencer-ARGS = --utf8 rxspencer/tests tst-rxspencer-ENV = LOCPATH=$(common-objpfx)localedata tst-pcre-ARGS = PCRE.tests tst-boost-ARGS = BOOST.tests bug-glob1-ARGS = "$(objpfx)" +tst-execvp3-ARGS = --test-dir=$(objpfx) testcases.h: TESTS TESTS2C.sed sed -f TESTS2C.sed < $< > $@T @@ -198,13 +221,13 @@ ifeq (no,$(cross-compiling)) tests: $(objpfx)bug-regex2-mem $(objpfx)bug-regex14-mem \ $(objpfx)bug-regex21-mem $(objpfx)tst-rxspencer-mem \ $(objpfx)tst-pcre-mem $(objpfx)tst-boost-mem $(objpfx)tst-getconf.out \ - $(objpfx)bug-glob2-mem + $(objpfx)bug-glob2-mem $(objpfx)tst-vfork3-mem xtests: $(objpfx)bug-ga2-mem endif $(objpfx)annexc.out: $(objpfx)annexc -$(dir $<)$(notdir $<) '$(CC)' \ - '$(patsubst %,-I../%,$(sorted-subdirs)) -I../include -I.. $(+sysdep-includes) $(sysincludes)' > $@ + '$(patsubst %,-I../%,$(sorted-subdirs)) -I../include $(+sysdep-includes) $(sysincludes) -I..' > $@ annexc-CFLAGS = -O $(objpfx)annexc: annexc.c @@ -225,6 +248,11 @@ bug-regex21-ENV = MALLOC_TRACE=$(objpfx)bug-regex21.mtrace $(objpfx)bug-regex21-mem: $(objpfx)bug-regex21.out $(common-objpfx)malloc/mtrace $(objpfx)bug-regex21.mtrace > $@ +tst-vfork3-ENV = MALLOC_TRACE=$(objpfx)tst-vfork3.mtrace + +$(objpfx)tst-vfork3-mem: $(objpfx)tst-vfork3.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-vfork3.mtrace > $@ + # tst-rxspencer.mtrace is generated only when run without --utf8 # option, since otherwise the file has almost 100M and takes very long # time to process. @@ -263,12 +291,16 @@ bug-glob2-ENV = MALLOC_TRACE=$(objpfx)bug-glob2.mtrace $(objpfx)bug-glob2-mem: $(objpfx)bug-glob2.out $(common-objpfx)malloc/mtrace $(objpfx)bug-glob2.mtrace > $@ -$(inst_libexecdir)/getconf: $(objpfx)getconf FORCE +$(inst_libexecdir)/getconf: $(objpfx)getconf $(objpfx)getconf.speclist FORCE $(addprefix $(..)./scripts/mkinstalldirs ,\ $(filter-out $(wildcard $@),$@)) - for spec in `LC_ALL=C GETCONF_DIR=/dev/null \ - $(run-program-prefix) $< \ - _POSIX_V6_WIDTH_RESTRICTED_ENVS`; do \ - $(INSTALL_PROGRAM) $< $@/$$spec.new; \ - mv -f $@/$$spec.new $@/$$spec; \ + for spec in `cat $(objpfx)getconf.speclist`; do \ + $(INSTALL_PROGRAM) $< $@/$$spec.new; \ + mv -f $@/$$spec.new $@/$$spec; \ done + +$(objpfx)getconf.speclist: getconf.speclist.h + $(CC) -E $(CFLAGS) $(CPPFLAGS) $< \ + | sed -n -e '/START_OF_STRINGS/,$${/POSIX_V6_/{s/^[^"]*"//;s/".*$$//;p}}' \ + > $@.new + mv -f $@.new $@ diff --git a/posix/_exit.c b/posix/_exit.c new file mode 100644 index 0000000000..673667df30 --- /dev/null +++ b/posix/_exit.c @@ -0,0 +1,36 @@ +/* Copyright (C) 1991,94,95,96,97,99,2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <unistd.h> +#include <stdlib.h> + +/* The function `_exit' should take a status argument and simply + terminate program execution, using the low-order 8 bits of the + given integer as status. */ +void +_exit (status) + int status; +{ + status &= 0xff; + abort (); +} +libc_hidden_def (_exit) +weak_alias (_exit, _Exit) + +stub_warning (_exit) +#include <stub-tag.h> diff --git a/posix/alarm.c b/posix/alarm.c new file mode 100644 index 0000000000..1f0cceb58e --- /dev/null +++ b/posix/alarm.c @@ -0,0 +1,39 @@ +/* Copyright (C) 1991,95,96,97,2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> + +/* Schedule an alarm. In SECONDS seconds, the process will get a SIGALRM. + If SECONDS is zero, any currently scheduled alarm will be cancelled. + The function returns the number of seconds remaining until the last + alarm scheduled would have signaled, or zero if there wasn't one. + There is no return value to indicate an error, but you can set `errno' + to 0 and check its value after calling `alarm', and this might tell you. + The signal may come late due to processor scheduling. */ +unsigned int +alarm (seconds) + unsigned int seconds; +{ + __set_errno (ENOSYS); + return 0; +} +libc_hidden_def (alarm) + +stub_warning (alarm) +#include <stub-tag.h> diff --git a/posix/bits/unistd.h b/posix/bits/unistd.h new file mode 100644 index 0000000000..b08aef2f6c --- /dev/null +++ b/posix/bits/unistd.h @@ -0,0 +1,250 @@ +/* Checking macros for unistd functions. + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _UNISTD_H +# error "Never include <bits/unistd.h> directly; use <unistd.h> instead." +#endif + +extern ssize_t __read_chk (int __fd, void *__buf, size_t __nbytes, + size_t __buflen) __wur; +extern ssize_t __REDIRECT (__read_alias, (int __fd, void *__buf, + size_t __nbytes), read) __wur; + +extern __always_inline __wur ssize_t +read (int __fd, void *__buf, size_t __nbytes) +{ + if (__bos0 (__buf) != (size_t) -1 + && (!__builtin_constant_p (__nbytes) || __nbytes > __bos0 (__buf))) + return __read_chk (__fd, __buf, __nbytes, __bos0 (__buf)); + return __read_alias (__fd, __buf, __nbytes); +} + +#ifdef __USE_UNIX98 +extern ssize_t __pread_chk (int __fd, void *__buf, size_t __nbytes, + __off_t __offset, size_t __bufsize) __wur; +extern ssize_t __pread64_chk (int __fd, void *__buf, size_t __nbytes, + __off64_t __offset, size_t __bufsize) __wur; +extern ssize_t __REDIRECT (__pread_alias, + (int __fd, void *__buf, size_t __nbytes, + __off_t __offset), pread) __wur; +extern ssize_t __REDIRECT (__pread64_alias, + (int __fd, void *__buf, size_t __nbytes, + __off64_t __offset), pread64) __wur; + +# ifndef __USE_FILE_OFFSET64 +extern __always_inline __wur ssize_t +pread (int __fd, void *__buf, size_t __nbytes, __off_t __offset) +{ + if (__bos0 (__buf) != (size_t) -1 + && (!__builtin_constant_p (__nbytes) || __nbytes > __bos0 (__buf))) + return __pread_chk (__fd, __buf, __nbytes, __offset, __bos0 (__buf)); + return __pread_alias (__fd, __buf, __nbytes, __offset); +} +# else +extern __always_inline __wur ssize_t +pread (int __fd, void *__buf, size_t __nbytes, __off64_t __offset) +{ + if (__bos0 (__buf) != (size_t) -1 + && (!__builtin_constant_p (__nbytes) || __nbytes > __bos0 (__buf))) + return __pread64_chk (__fd, __buf, __nbytes, __offset, __bos0 (__buf)); + return __pread64_alias (__fd, __buf, __nbytes, __offset); +} +# endif + +# ifdef __USE_LARGEFILE64 +extern __always_inline __wur ssize_t +pread64 (int __fd, void *__buf, size_t __nbytes, __off64_t __offset) +{ + if (__bos0 (__buf) != (size_t) -1 + && (!__builtin_constant_p (__nbytes) || __nbytes > __bos0 (__buf))) + return __pread64_chk (__fd, __buf, __nbytes, __offset, __bos0 (__buf)); + return __pread64_alias (__fd, __buf, __nbytes, __offset); +} +# endif +#endif + +#if defined __USE_BSD || defined __USE_XOPEN_EXTENDED || defined __USE_XOPEN2K +extern ssize_t __readlink_chk (__const char *__restrict __path, + char *__restrict __buf, size_t __len, + size_t __buflen) + __THROW __nonnull ((1, 2)) __wur; +extern ssize_t __REDIRECT_NTH (__readlink_alias, + (__const char *__restrict __path, + char *__restrict __buf, size_t __len), readlink) + __nonnull ((1, 2)) __wur; + +extern __always_inline __nonnull ((1, 2)) __wur ssize_t +__NTH (readlink (__const char *__restrict __path, char *__restrict __buf, + size_t __len)) +{ + if (__bos (__buf) != (size_t) -1 + && (!__builtin_constant_p (__len) || __len > __bos (__buf))) + return __readlink_chk (__path, __buf, __len, __bos (__buf)); + return __readlink_alias (__path, __buf, __len); +} +#endif + +#ifdef __USE_ATFILE +extern ssize_t __readlinkat_chk (int __fd, __const char *__restrict __path, + char *__restrict __buf, size_t __len, + size_t __buflen) + __THROW __nonnull ((2, 3)) __wur; +extern ssize_t __REDIRECT_NTH (__readlinkat_alias, + (int __fd, __const char *__restrict __path, + char *__restrict __buf, size_t __len), + readlinkat) + __nonnull ((2, 3)) __wur; + +extern __always_inline __nonnull ((2, 3)) __wur ssize_t +__NTH (readlinkat (int __fd, __const char *__restrict __path, + char *__restrict __buf, size_t __len)) +{ + if (__bos (__buf) != (size_t) -1 + && (!__builtin_constant_p (__len) || __len > __bos (__buf))) + return __readlinkat_chk (__fd, __path, __buf, __len, __bos (__buf)); + return __readlinkat_alias (__fd, __path, __buf, __len); +} +#endif + +extern char *__getcwd_chk (char *__buf, size_t __size, size_t __buflen) + __THROW __wur; +extern char *__REDIRECT_NTH (__getcwd_alias, + (char *__buf, size_t __size), getcwd) __wur; + +extern __always_inline __wur char * +__NTH (getcwd (char *__buf, size_t __size)) +{ + if (__bos (__buf) != (size_t) -1 + && (!__builtin_constant_p (__size) || __size > __bos (__buf))) + return __getcwd_chk (__buf, __size, __bos (__buf)); + return __getcwd_alias (__buf, __size); +} + +#if defined __USE_BSD || defined __USE_XOPEN_EXTENDED +extern char *__getwd_chk (char *__buf, size_t buflen) + __THROW __nonnull ((1)) __wur; +extern char *__REDIRECT_NTH (__getwd_alias, (char *__buf), getwd) + __nonnull ((1)) __wur; + +extern __always_inline __nonnull ((1)) __attribute_deprecated__ __wur char * +__NTH (getwd (char *__buf)) +{ + if (__bos (__buf) != (size_t) -1) + return __getwd_chk (__buf, __bos (__buf)); + return __getwd_alias (__buf); +} +#endif + +extern size_t __confstr_chk (int __name, char *__buf, size_t __len, + size_t __buflen) __THROW; +extern size_t __REDIRECT_NTH (__confstr_alias, (int __name, char *__buf, + size_t __len), confstr); + +extern __always_inline size_t +__NTH (confstr (int __name, char *__buf, size_t __len)) +{ + if (__bos (__buf) != (size_t) -1 + && (!__builtin_constant_p (__len) || __bos (__buf) < __len)) + return __confstr_chk (__name, __buf, __len, __bos (__buf)); + return __confstr_alias (__name, __buf, __len); +} + + +extern int __getgroups_chk (int __size, __gid_t __list[], size_t listlen) + __THROW __wur; +extern int __REDIRECT_NTH (__getgroups_alias, (int __size, __gid_t __list[]), + getgroups) __wur; + +extern __always_inline int +__NTH (getgroups (int __size, __gid_t __list[])) +{ + if (__bos (__list) != (size_t) -1 + && (!__builtin_constant_p (__size) + || __size * sizeof (__gid_t) > __bos (__list))) + return __getgroups_chk (__size, __list, __bos (__list)); + return __getgroups_alias (__size, __list); +} + + +extern int __ttyname_r_chk (int __fd, char *__buf, size_t __buflen, + size_t __nreal) __THROW __nonnull ((2)); +extern int __REDIRECT_NTH (__ttyname_r_alias, (int __fd, char *__buf, + size_t __buflen), ttyname_r) + __nonnull ((2)); + +extern __always_inline int +__NTH (ttyname_r (int __fd, char *__buf, size_t __buflen)) +{ + if (__bos (__buf) != (size_t) -1 + && (!__builtin_constant_p (__buflen) || __buflen > __bos (__buf))) + return __ttyname_r_chk (__fd, __buf, __buflen, __bos (__buf)); + return __ttyname_r_alias (__fd, __buf, __buflen); +} + + +#if defined __USE_REENTRANT || defined __USE_POSIX199506 +extern int __getlogin_r_chk (char *__buf, size_t __buflen, size_t __nreal) + __nonnull ((1)); +extern int __REDIRECT (__getlogin_r_alias, (char *__buf, size_t __buflen), + getlogin_r) __nonnull ((1)); + +extern __always_inline int +getlogin_r (char *__buf, size_t __buflen) +{ + if (__bos (__buf) != (size_t) -1 + && (!__builtin_constant_p (__buflen) || __buflen > __bos (__buf))) + return __getlogin_r_chk (__buf, __buflen, __bos (__buf)); + return __getlogin_r_alias (__buf, __buflen); +} +#endif + + +#if defined __USE_BSD || defined __USE_UNIX98 +extern int __gethostname_chk (char *__buf, size_t __buflen, size_t __nreal) + __THROW __nonnull ((1)); +extern int __REDIRECT_NTH (__gethostname_alias, (char *__buf, size_t __buflen), + gethostname) __nonnull ((1)); + +extern __always_inline int +__NTH (gethostname (char *__buf, size_t __buflen)) +{ + if (__bos (__buf) != (size_t) -1 + && (!__builtin_constant_p (__buflen) || __buflen > __bos (__buf))) + return __gethostname_chk (__buf, __buflen, __bos (__buf)); + return __gethostname_alias (__buf, __buflen); +} +#endif + + +#if defined __USE_BSD || (defined __USE_XOPEN && !defined __USE_UNIX98) +extern int __getdomainname_chk (char *__buf, size_t __buflen, size_t __nreal) + __THROW __nonnull ((1)) __wur; +extern int __REDIRECT_NTH (__getdomainname_alias, (char *__buf, + size_t __buflen), + getdomainname) __nonnull ((1)) __wur; + +extern __always_inline int +__NTH (getdomainname (char *__buf, size_t __buflen)) +{ + if (__bos (__buf) != (size_t) -1 + && (!__builtin_constant_p (__buflen) || __buflen > __bos (__buf))) + return __getdomainname_chk (__buf, __buflen, __bos (__buf)); + return __getdomainname_alias (__buf, __buflen); +} +#endif diff --git a/posix/bug-regex19.c b/posix/bug-regex19.c index 4000b19b4d..3a173a6ca0 100644 --- a/posix/bug-regex19.c +++ b/posix/bug-regex19.c @@ -1,5 +1,5 @@ /* Regular expression tests. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. @@ -170,22 +170,22 @@ static struct test_s {ERE, "[^k]\\B[^k]", "kBk", 0, -1}, {ERE, "[^C]\\B[^C]", "CCCABA", 0, 3}, {ERE, "[^C]\\B[^C]", "CBC", 0, -1}, - {ERE, ".(\\b|\\B).", "=~AB", 0, 1}, + {ERE, ".(\\b|\\B).", "=~AB", 0, 0}, {ERE, ".(\\b|\\B).", "A=C", 0, 0}, {ERE, ".(\\b|\\B).", "ABC", 0, 0}, - {ERE, ".(\\b|\\B).", "=~\\!", 0, -1}, - {ERE, "[^k](\\b|\\B)[^k]", "=~AB", 0, 1}, + {ERE, ".(\\b|\\B).", "=~\\!", 0, 0}, + {ERE, "[^k](\\b|\\B)[^k]", "=~AB", 0, 0}, {ERE, "[^k](\\b|\\B)[^k]", "A=C", 0, 0}, {ERE, "[^k](\\b|\\B)[^k]", "ABC", 0, 0}, - {ERE, "[^k](\\b|\\B)[^k]", "=~kBD", 0, 3}, - {ERE, "[^k](\\b|\\B)[^k]", "=~\\!", 0, -1}, - {ERE, "[^k](\\b|\\B)[^k]", "=~kB", 0, -1}, - {ERE, "[^C](\\b|\\B)[^C]", "=~AB", 0, 1}, + {ERE, "[^k](\\b|\\B)[^k]", "=~kBD", 0, 0}, + {ERE, "[^k](\\b|\\B)[^k]", "=~\\!", 0, 0}, + {ERE, "[^k](\\b|\\B)[^k]", "=~kB", 0, 0}, + {ERE, "[^C](\\b|\\B)[^C]", "=~AB", 0, 0}, {ERE, "[^C](\\b|\\B)[^C]", "A=C", 0, 0}, {ERE, "[^C](\\b|\\B)[^C]", "ABC", 0, 0}, - {ERE, "[^C](\\b|\\B)[^C]", "=~CBD", 0, 3}, - {ERE, "[^C](\\b|\\B)[^C]", "=~\\!", 0, -1}, - {ERE, "[^C](\\b|\\B)[^C]", "=~CB", 0, -1}, + {ERE, "[^C](\\b|\\B)[^C]", "=~CBD", 0, 0}, + {ERE, "[^C](\\b|\\B)[^C]", "=~\\!", 0, 0}, + {ERE, "[^C](\\b|\\B)[^C]", "=~CB", 0, 0}, {ERE, "\\b([A]|[!]|.B)", "A=AC", 0, 0}, {ERE, "\\b([A]|[!]|.B)", "=AC", 0, 1}, {ERE, "\\b([A]|[!]|.B)", "!AC", 0, 1}, diff --git a/posix/bug-regex22.c b/posix/bug-regex22.c index 1636202d36..c5bc94869b 100644 --- a/posix/bug-regex22.c +++ b/posix/bug-regex22.c @@ -1,5 +1,5 @@ /* Test re.translate != NULL. - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. @@ -40,7 +40,7 @@ main (void) re_set_syntax (RE_SYNTAX_POSIX_EGREP); memset (&re, 0, sizeof (re)); - re.translate = trans; + re.translate = (unsigned char *) trans; s = re_compile_pattern ("\\W", 2, &re); if (s != NULL) @@ -68,7 +68,7 @@ main (void) } memset (&re, 0, sizeof (re)); - re.translate = trans; + re.translate = (unsigned char *) trans; s = re_compile_pattern ("\\w", 2, &re); if (s != NULL) @@ -96,7 +96,7 @@ main (void) } memset (&re, 0, sizeof (re)); - re.translate = trans; + re.translate = (unsigned char *) trans; s = re_compile_pattern ("[[:DIGIT:]]", 11, &re); if (s == NULL) { @@ -106,7 +106,7 @@ main (void) } memset (&re, 0, sizeof (re)); - re.translate = trans; + re.translate = (unsigned char *) trans; s = re_compile_pattern ("[[:DIGIT:]]", 2, &re); if (s == NULL) { diff --git a/posix/bug-regex25.c b/posix/bug-regex25.c new file mode 100644 index 0000000000..5e56e49bb5 --- /dev/null +++ b/posix/bug-regex25.c @@ -0,0 +1,57 @@ +/* Test re_search in multibyte locale other than UTF-8. + Copyright (C) 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2006. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <locale.h> +#include <regex.h> +#include <stdio.h> +#include <string.h> + +const char *str1 = "\xa3\xd8\xa3\xc9\xa3\xc9"; +const char *str2 = "\xa3\xd8\xa3\xc9"; + +int +main (void) +{ + setlocale (LC_ALL, "ja_JP.eucJP"); + + re_set_syntax (RE_SYNTAX_SED); + + struct re_pattern_buffer re; + memset (&re, 0, sizeof (re)); + + struct re_registers regs; + memset (®s, 0, sizeof (regs)); + + re_compile_pattern ("$", 1, &re); + + int ret = 0, r = re_search (&re, str1, 4, 0, 4, ®s); + if (r != 4) + { + printf ("First re_search returned %d\n", r); + ret = 1; + } + r = re_search (&re, str2, 4, 0, 4, ®s); + if (r != 4) + { + printf ("Second re_search returned %d\n", r); + ret = 1; + } + return ret; +} diff --git a/posix/bug-regex26.c b/posix/bug-regex26.c new file mode 100644 index 0000000000..b784cfcef8 --- /dev/null +++ b/posix/bug-regex26.c @@ -0,0 +1,38 @@ +/* Test re_search with dotless i. + Copyright (C) 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2006. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <locale.h> +#include <regex.h> +#include <string.h> + +int +main (void) +{ + struct re_pattern_buffer r; + struct re_registers s; + setlocale (LC_ALL, "en_US.UTF-8"); + memset (&r, 0, sizeof (r)); + memset (&s, 0, sizeof (s)); + re_set_syntax (RE_SYNTAX_GREP | RE_HAT_LISTS_NOT_NEWLINE | RE_ICASE); + re_compile_pattern ("insert into", 11, &r); + re_search (&r, "\xFF\0\x12\xA2\xAA\xC4\xB1,K\x12\xC4\xB1*\xACK", + 15, 0, 15, &s); + return 0; +} diff --git a/posix/bug-regex27.c b/posix/bug-regex27.c new file mode 100644 index 0000000000..327acd8684 --- /dev/null +++ b/posix/bug-regex27.c @@ -0,0 +1,64 @@ +/* Test REG_NEWLINE. + Copyright (C) 2007 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2007. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <regex.h> +#include <stdio.h> +#include <string.h> + +struct tests +{ + const char *regex; + const char *string; + int cflags; + int retval; +} tests[] = { + { "a.b", "a\nb", REG_EXTENDED | REG_NEWLINE, REG_NOMATCH }, + { "a.b", "a\nb", REG_EXTENDED, 0 }, + { "a[^x]b", "a\nb", REG_EXTENDED | REG_NEWLINE, REG_NOMATCH }, + { "a[^x]b", "a\nb", REG_EXTENDED, 0 } +}; + +int +main (void) +{ + regex_t r; + size_t i; + int ret = 0; + + for (i = 0; i < sizeof (tests) / sizeof (tests[i]); ++i) + { + memset (&r, 0, sizeof (r)); + if (regcomp (&r, tests[i].regex, tests[i].cflags)) + { + printf ("regcomp %zd failed\n", i); + ret = 1; + continue; + } + int rv = regexec (&r, tests[i].string, 0, NULL, 0); + if (rv != tests[i].retval) + { + printf ("regexec %zd unexpected value %d != %d\n", + i, rv, tests[i].retval); + ret = 1; + } + regfree (&r); + } + return ret; +} diff --git a/posix/bug-regex28.c b/posix/bug-regex28.c new file mode 100644 index 0000000000..e58a08fabe --- /dev/null +++ b/posix/bug-regex28.c @@ -0,0 +1,75 @@ +/* Test RE_HAT_LISTS_NOT_NEWLINE and RE_DOT_NEWLINE. + Copyright (C) 2007 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2007. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <regex.h> +#include <stdio.h> +#include <string.h> + +struct tests +{ + const char *regex; + const char *string; + reg_syntax_t syntax; + int retval; +} tests[] = { +#define EGREP RE_SYNTAX_EGREP +#define EGREP_NL (RE_SYNTAX_EGREP | RE_DOT_NEWLINE) & ~RE_HAT_LISTS_NOT_NEWLINE + { "a.b", "a\nb", EGREP, -1 }, + { "a.b", "a\nb", EGREP_NL, 0 }, + { "a[^x]b", "a\nb", EGREP, -1 }, + { "a[^x]b", "a\nb", EGREP_NL, 0 }, + /* While \S and \W are internally handled as [^[:space:]] and [^[:alnum:]_], + RE_HAT_LISTS_NOT_NEWLINE did not make any difference, so ensure + it doesn't change. */ + { "a\\Sb", "a\nb", EGREP, -1 }, + { "a\\Sb", "a\nb", EGREP_NL, -1 }, + { "a\\Wb", "a\nb", EGREP, 0 }, + { "a\\Wb", "a\nb", EGREP_NL, 0 } +}; + +int +main (void) +{ + struct re_pattern_buffer r; + size_t i; + int ret = 0; + + for (i = 0; i < sizeof (tests) / sizeof (tests[i]); ++i) + { + re_set_syntax (tests[i].syntax); + memset (&r, 0, sizeof (r)); + if (re_compile_pattern (tests[i].regex, strlen (tests[i].regex), &r)) + { + printf ("re_compile_pattern %zd failed\n", i); + ret = 1; + continue; + } + size_t len = strlen (tests[i].string); + int rv = re_search (&r, tests[i].string, len, 0, len, NULL); + if (rv != tests[i].retval) + { + printf ("re_search %zd unexpected value %d != %d\n", + i, rv, tests[i].retval); + ret = 1; + } + regfree (&r); + } + return ret; +} diff --git a/posix/bug-regex5.c b/posix/bug-regex5.c index ee4d652157..f199ffbfd3 100644 --- a/posix/bug-regex5.c +++ b/posix/bug-regex5.c @@ -41,7 +41,7 @@ main (void) { char elem[256]; idx = symb_table[2 * i + 1]; - strncpy (elem, extra + idx + 1, extra[idx]); + strncpy (elem, (const char *) (extra + idx + 1), extra[idx]); elem[extra[idx]] = '\0'; printf ("Found a collating element: %s\n", elem); ++found; diff --git a/posix/environ.c b/posix/environ.c new file mode 100644 index 0000000000..a0ed0d80ea --- /dev/null +++ b/posix/environ.c @@ -0,0 +1,12 @@ +/* This file just defines the `__environ' variable (and alias `environ'). */ + +#include <unistd.h> +#include <stddef.h> + +/* This must be initialized; we cannot have a weak alias into bss. */ +char **__environ = NULL; +weak_alias (__environ, environ) + +/* The SVR4 ABI says `_environ' will be the name to use + in case the user overrides the weak alias `environ'. */ +weak_alias (__environ, _environ) diff --git a/posix/execl.c b/posix/execl.c index 62fd45db58..7f822d0142 100644 --- a/posix/execl.c +++ b/posix/execl.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1991,92,94,97,98,99,2002 Free Software Foundation, Inc. +/* Copyright (C) 1991,92,94,97,98,99,2002,2005 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -16,63 +16,58 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include <alloca.h> #include <unistd.h> #include <stdarg.h> #include <stddef.h> +#include <stdlib.h> #include <string.h> #include <stackinfo.h> -#ifndef HAVE_GNU_LD -# define __environ environ -#endif /* Execute PATH with all arguments after PATH until a NULL pointer and environment from `environ'. */ int execl (const char *path, const char *arg, ...) { - size_t argv_max = 1024; - const char **argv = alloca (argv_max * sizeof (const char *)); - unsigned int i; +#define INITIAL_ARGV_MAX 1024 + size_t argv_max = INITIAL_ARGV_MAX; + const char *initial_argv[INITIAL_ARGV_MAX]; + const char **argv = initial_argv; va_list args; argv[0] = arg; va_start (args, arg); - i = 0; + unsigned int i = 0; while (argv[i++] != NULL) { if (i == argv_max) { - const char **nptr = alloca ((argv_max *= 2) * sizeof (const char *)); - -#ifndef _STACK_GROWS_UP - if ((char *) nptr + argv_max == (char *) argv) + argv_max *= 2; + const char **nptr = realloc (argv == initial_argv ? NULL : argv, + argv_max * sizeof (const char *)); + if (nptr == NULL) { - /* Stack grows down. */ - argv = (const char **) memcpy (nptr, argv, - i * sizeof (const char *)); - argv_max += i; + if (argv != initial_argv) + free (argv); + return -1; } - else -#endif -#ifndef _STACK_GROWS_DOWN - if ((char *) argv + i == (char *) nptr) - /* Stack grows up. */ - argv_max += i; - else -#endif - /* We have a hole in the stack. */ - argv = (const char **) memcpy (nptr, argv, - i * sizeof (const char *)); + if (argv == initial_argv) + /* We have to copy the already filled-in data ourselves. */ + memcpy (nptr, argv, i * sizeof (const char *)); + + argv = nptr; } argv[i] = va_arg (args, const char *); } va_end (args); - return __execve (path, (char *const *) argv, __environ); + int ret = __execve (path, (char *const *) argv, __environ); + if (argv != initial_argv) + free (argv); + + return ret; } libc_hidden_def (execl) diff --git a/posix/execle.c b/posix/execle.c index 2199ebeb74..70522ad2e5 100644 --- a/posix/execle.c +++ b/posix/execle.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1991,97,98,99,2002 Free Software Foundation, Inc. +/* Copyright (C) 1991,97,98,99,2002,2005 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -16,10 +16,10 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include <alloca.h> #include <unistd.h> #include <stdarg.h> #include <stddef.h> +#include <stdlib.h> #include <string.h> #include <stackinfo.h> @@ -29,48 +29,45 @@ int execle (const char *path, const char *arg, ...) { - size_t argv_max = 1024; - const char **argv = alloca (argv_max * sizeof (const char *)); - const char *const *envp; - unsigned int i; +#define INITIAL_ARGV_MAX 1024 + size_t argv_max = INITIAL_ARGV_MAX; + const char *initial_argv[INITIAL_ARGV_MAX]; + const char **argv = initial_argv; va_list args; argv[0] = arg; va_start (args, arg); - i = 0; + unsigned int i = 0; while (argv[i++] != NULL) { if (i == argv_max) { - const char **nptr = alloca ((argv_max *= 2) * sizeof (const char *)); - -#ifndef _STACK_GROWS_UP - if ((char *) nptr + argv_max == (char *) argv) + argv_max *= 2; + const char **nptr = realloc (argv == initial_argv ? NULL : argv, + argv_max * sizeof (const char *)); + if (nptr == NULL) { - /* Stack grows down. */ - argv = (const char **) memcpy (nptr, argv, - i * sizeof (const char *)); - argv_max += i; + if (argv != initial_argv) + free (argv); + return -1; } - else -#endif -#ifndef _STACK_GROWS_DOWN - if ((char *) argv + i == (char *) nptr) - /* Stack grows up. */ - argv_max += i; - else -#endif - /* We have a hole in the stack. */ - argv = (const char **) memcpy (nptr, argv, - i * sizeof (const char *)); + if (argv == initial_argv) + /* We have to copy the already filled-in data ourselves. */ + memcpy (nptr, argv, i * sizeof (const char *)); + + argv = nptr; } argv[i] = va_arg (args, const char *); } - envp = va_arg (args, const char *const *); + const char *const *envp = va_arg (args, const char *const *); va_end (args); - return __execve (path, (char *const *) argv, (char *const *) envp); + int ret = __execve (path, (char *const *) argv, (char *const *) envp); + if (argv != initial_argv) + free (argv); + + return ret; } libc_hidden_def (execle) diff --git a/posix/execlp.c b/posix/execlp.c index ba8fc74c90..66996a9367 100644 --- a/posix/execlp.c +++ b/posix/execlp.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1991,93,96,97,98,99,2002 Free Software Foundation, Inc. +/* Copyright (C) 1991,93,96,97,98,99,2002,2005 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -16,10 +16,10 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include <alloca.h> #include <unistd.h> #include <stdarg.h> #include <stddef.h> +#include <stdlib.h> #include <string.h> #include <stackinfo.h> @@ -30,46 +30,44 @@ int execlp (const char *file, const char *arg, ...) { - size_t argv_max = 1024; - const char **argv = alloca (argv_max * sizeof (const char *)); - unsigned int i; +#define INITIAL_ARGV_MAX 1024 + size_t argv_max = INITIAL_ARGV_MAX; + const char *initial_argv[INITIAL_ARGV_MAX]; + const char **argv = initial_argv; va_list args; argv[0] = arg; va_start (args, arg); - i = 0; + unsigned int i = 0; while (argv[i++] != NULL) { if (i == argv_max) { - const char **nptr = alloca ((argv_max *= 2) * sizeof (const char *)); - -#ifndef _STACK_GROWS_UP - if ((char *) nptr + argv_max == (char *) argv) + argv_max *= 2; + const char **nptr = realloc (argv == initial_argv ? NULL : argv, + argv_max * sizeof (const char *)); + if (nptr == NULL) { - /* Stack grows down. */ - argv = (const char **) memcpy (nptr, argv, - i * sizeof (const char *)); - argv_max += i; + if (argv != initial_argv) + free (argv); + return -1; } - else -#endif -#ifndef _STACK_GROWS_DOWN - if ((char *) argv + i == (char *) nptr) - /* Stack grows up. */ - argv_max += i; - else -#endif - /* We have a hole in the stack. */ - argv = (const char **) memcpy (nptr, argv, - i * sizeof (const char *)); + if (argv == initial_argv) + /* We have to copy the already filled-in data ourselves. */ + memcpy (nptr, argv, i * sizeof (const char *)); + + argv = nptr; } argv[i] = va_arg (args, const char *); } va_end (args); - return execvp (file, (char *const *) argv); + int ret = execvp (file, (char *const *) argv); + if (argv != initial_argv) + free (argv); + + return ret; } libc_hidden_def (execlp) diff --git a/posix/execv.c b/posix/execv.c index a3c51c7be4..cb372abe37 100644 --- a/posix/execv.c +++ b/posix/execv.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1991, 1992, 1997 Free Software Foundation, Inc. +/* Copyright (C) 1991, 1992, 1997, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -18,9 +18,6 @@ #include <unistd.h> -#ifndef HAVE_GNU_LD -# define __environ environ -#endif /* Execute PATH with arguments ARGV and environment from `environ'. */ int diff --git a/posix/execve.c b/posix/execve.c new file mode 100644 index 0000000000..2d756293ed --- /dev/null +++ b/posix/execve.c @@ -0,0 +1,44 @@ +/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stddef.h> +#include <unistd.h> + + +/* Replace the current process, executing PATH with arguments ARGV and + environment ENVP. ARGV and ENVP are terminated by NULL pointers. */ +int +__execve (path, argv, envp) + const char *path; + char *const argv[]; + char *const envp[]; +{ + if (path == NULL || argv == NULL || envp == NULL) + { + __set_errno (EINVAL); + return -1; + } + + __set_errno (ENOSYS); + return -1; +} +stub_warning (execve) + +weak_alias (__execve, execve) +#include <stub-tag.h> diff --git a/posix/execvp.c b/posix/execvp.c index d6f60c02e7..887379e3a2 100644 --- a/posix/execvp.c +++ b/posix/execvp.c @@ -1,4 +1,5 @@ -/* Copyright (C) 1991,92,1995-99,2002,2004 Free Software Foundation, Inc. +/* Copyright (C) 1991,92, 1995-99, 2002, 2004, 2005, 2007 + Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -16,8 +17,10 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#include <alloca.h> #include <unistd.h> #include <stdarg.h> +#include <stdbool.h> #include <stdlib.h> #include <string.h> #include <errno.h> @@ -28,27 +31,16 @@ the shell to interpret it as a script. */ static void internal_function -script_execute (const char *file, char *const argv[]) +scripts_argv (const char *file, char *const argv[], int argc, char **new_argv) { - /* Count the arguments. */ - int argc = 0; - while (argv[argc++]) - ; - /* Construct an argument list for the shell. */ - { - char *new_argv[argc + 1]; - new_argv[0] = (char *) _PATH_BSHELL; - new_argv[1] = (char *) file; - while (argc > 1) - { - new_argv[argc] = argv[argc - 1]; - --argc; - } - - /* Execute the shell. */ - __execve (new_argv[0], new_argv, __environ); - } + new_argv[0] = (char *) _PATH_BSHELL; + new_argv[1] = (char *) file; + while (argc > 1) + { + new_argv[argc] = argv[argc - 1]; + --argc; + } } @@ -72,36 +64,74 @@ execvp (file, argv) __execve (file, argv, __environ); if (errno == ENOEXEC) - script_execute (file, argv); + { + /* Count the arguments. */ + int argc = 0; + while (argv[argc++]) + ; + size_t len = (argc + 1) * sizeof (char *); + char **script_argv; + void *ptr = NULL; + if (__libc_use_alloca (len)) + script_argv = alloca (len); + else + script_argv = ptr = malloc (len); + + if (script_argv != NULL) + { + scripts_argv (file, argv, argc, script_argv); + __execve (script_argv[0], script_argv, __environ); + + free (ptr); + } + } } else { - int got_eacces = 0; - char *path, *p, *name; - size_t len; size_t pathlen; + size_t alloclen = 0; + char *path = getenv ("PATH"); + if (path == NULL) + { + pathlen = confstr (_CS_PATH, (char *) NULL, 0); + alloclen = pathlen + 1; + } + else + pathlen = strlen (path); + + size_t len = strlen (file) + 1; + alloclen += pathlen + len + 1; + + char *name; + char *path_malloc = NULL; + if (__libc_use_alloca (alloclen)) + name = alloca (alloclen); + else + { + path_malloc = name = malloc (alloclen); + if (name == NULL) + return -1; + } - path = getenv ("PATH"); if (path == NULL) { /* There is no `PATH' in the environment. The default search path is the current directory followed by the path `confstr' returns for `_CS_PATH'. */ - len = confstr (_CS_PATH, (char *) NULL, 0); - path = (char *) __alloca (1 + len); + path = name + pathlen + len + 1; path[0] = ':'; - (void) confstr (_CS_PATH, path + 1, len); + (void) confstr (_CS_PATH, path + 1, pathlen); } - len = strlen (file) + 1; - pathlen = strlen (path); - name = __alloca (pathlen + len + 1); /* Copy the file name at the top. */ name = (char *) memcpy (name + pathlen + 1, file, len); /* And add the slash. */ *--name = '/'; - p = path; + char **script_argv = NULL; + void *script_argv_malloc = NULL; + bool got_eacces = false; + char *p = path; do { char *startp; @@ -116,11 +146,34 @@ execvp (file, argv) else startp = (char *) memcpy (name - (p - path), path, p - path); - /* Try to execute this name. If it works, execv will not return. */ + /* Try to execute this name. If it works, execve will not return. */ __execve (startp, argv, __environ); if (errno == ENOEXEC) - script_execute (startp, argv); + { + if (script_argv == NULL) + { + /* Count the arguments. */ + int argc = 0; + while (argv[argc++]) + ; + size_t arglen = (argc + 1) * sizeof (char *); + if (__libc_use_alloca (alloclen + arglen)) + script_argv = alloca (arglen); + else + script_argv = script_argv_malloc = malloc (arglen); + if (script_argv == NULL) + { + /* A possible EACCES error is not as important as + the ENOMEM. */ + got_eacces = false; + break; + } + scripts_argv (startp, argv, argc, script_argv); + } + + __execve (script_argv[0], script_argv, __environ); + } switch (errno) { @@ -128,7 +181,7 @@ execvp (file, argv) /* Record the we got a `Permission denied' error. If we end up finding no executable we can use, we want to diagnose that we did find one but were denied access. */ - got_eacces = 1; + got_eacces = true; case ENOENT: case ESTALE: case ENOTDIR: @@ -154,8 +207,11 @@ execvp (file, argv) /* We tried every element and none of them worked. */ if (got_eacces) /* At least one failure was due to permissions, so report that - error. */ + error. */ __set_errno (EACCES); + + free (script_argv_malloc); + free (path_malloc); } /* Return the error from the last attempt (probably ENOENT). */ diff --git a/posix/fexecve.c b/posix/fexecve.c new file mode 100644 index 0000000000..fceae9251a --- /dev/null +++ b/posix/fexecve.c @@ -0,0 +1,43 @@ +/* Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stddef.h> +#include <unistd.h> + + +/* Execute the file FD refers to, overlaying the running program image. + ARGV and ENVP are passed to the new program, as for `execve'. */ +int +fexecve (fd, argv, envp) + int fd; + char *const argv[]; + char *const envp[]; +{ + if (fd < 0 || argv == NULL || envp == NULL) + { + __set_errno (EINVAL); + return -1; + } + + __set_errno (ENOSYS); + return -1; +} + +stub_warning (fexecve) +#include <stub-tag.h> diff --git a/posix/fnmatch.c b/posix/fnmatch.c index e409ed7300..3fa7c322d1 100644 --- a/posix/fnmatch.c +++ b/posix/fnmatch.c @@ -327,31 +327,74 @@ fnmatch (pattern, string, flags) { mbstate_t ps; size_t n; + const char *p; wchar_t *wpattern; wchar_t *wstring; /* Convert the strings into wide characters. */ memset (&ps, '\0', sizeof (ps)); - n = mbsrtowcs (NULL, &pattern, 0, &ps); - if (__builtin_expect (n == (size_t) -1, 0)) - /* Something wrong. - XXX Do we have to set `errno' to something which mbsrtows hasn't - already done? */ - return -1; - wpattern = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t)); - assert (mbsinit (&ps)); - (void) mbsrtowcs (wpattern, &pattern, n + 1, &ps); + p = pattern; +#ifdef _LIBC + n = strnlen (pattern, 1024); +#else + n = strlen (pattern); +#endif + if (__builtin_expect (n < 1024, 1)) + { + wpattern = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t)); + n = mbsrtowcs (wpattern, &p, n + 1, &ps); + if (__builtin_expect (n == (size_t) -1, 0)) + /* Something wrong. + XXX Do we have to set `errno' to something which mbsrtows hasn't + already done? */ + return -1; + if (p) + memset (&ps, '\0', sizeof (ps)); + } + if (__builtin_expect (p != NULL, 0)) + { + n = mbsrtowcs (NULL, &pattern, 0, &ps); + if (__builtin_expect (n == (size_t) -1, 0)) + /* Something wrong. + XXX Do we have to set `errno' to something which mbsrtows hasn't + already done? */ + return -1; + wpattern = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t)); + assert (mbsinit (&ps)); + (void) mbsrtowcs (wpattern, &pattern, n + 1, &ps); + } assert (mbsinit (&ps)); - n = mbsrtowcs (NULL, &string, 0, &ps); - if (__builtin_expect (n == (size_t) -1, 0)) - /* Something wrong. - XXX Do we have to set `errno' to something which mbsrtows hasn't - already done? */ - return -1; - wstring = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t)); - assert (mbsinit (&ps)); - (void) mbsrtowcs (wstring, &string, n + 1, &ps); +#ifdef _LIBC + n = strnlen (string, 1024); +#else + n = strlen (string); +#endif + p = string; + if (__builtin_expect (n < 1024, 1)) + { + wstring = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t)); + n = mbsrtowcs (wstring, &p, n + 1, &ps); + if (__builtin_expect (n == (size_t) -1, 0)) + /* Something wrong. + XXX Do we have to set `errno' to something which mbsrtows hasn't + already done? */ + return -1; + if (p) + memset (&ps, '\0', sizeof (ps)); + } + if (__builtin_expect (p != NULL, 0)) + { + n = mbsrtowcs (NULL, &string, 0, &ps); + if (__builtin_expect (n == (size_t) -1, 0)) + /* Something wrong. + XXX Do we have to set `errno' to something which mbsrtows hasn't + already done? */ + return -1; + wstring = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t)); + assert (mbsinit (&ps)); + (void) mbsrtowcs (wstring, &string, n + 1, &ps); + } return internal_fnwmatch (wpattern, wstring, wstring + n, flags & FNM_PERIOD, flags); diff --git a/posix/fnmatch_loop.c b/posix/fnmatch_loop.c index 449e5e02b4..02a4e9030c 100644 --- a/posix/fnmatch_loop.c +++ b/posix/fnmatch_loop.c @@ -1,5 +1,5 @@ -/* Copyright (C) 1991,1992,1993,1996,1997,1998,1999,2000,2001,2003,2004 - Free Software Foundation, Inc. +/* Copyright (C) 1991,1992,1993,1996,1997,1998,1999,2000,2001,2003,2004,2005 + Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -502,24 +502,31 @@ FCT (pattern, string, string_end, no_leading_period, flags) idx = 0; elem = hash % table_size; - second = hash % (table_size - 2); - while (symb_table[2 * elem] != 0) + if (symb_table[2 * elem] != 0) { - /* First compare the hashing value. */ - if (symb_table[2 * elem] == hash - && c1 == extra[symb_table[2 * elem + 1]] - && memcmp (str, - &extra[symb_table[2 * elem + 1] - + 1], c1) == 0) + second = hash % (table_size - 2) + 1; + + do { - /* Yep, this is the entry. */ - idx = symb_table[2 * elem + 1]; - idx += 1 + extra[idx]; - break; - } + /* First compare the hashing value. */ + if (symb_table[2 * elem] == hash + && (c1 + == extra[symb_table[2 * elem + 1]]) + && memcmp (str, + &extra[symb_table[2 * elem + + 1] + + 1], c1) == 0) + { + /* Yep, this is the entry. */ + idx = symb_table[2 * elem + 1]; + idx += 1 + extra[idx]; + break; + } - /* Next entry. */ - elem += second; + /* Next entry. */ + elem += second; + } + while (symb_table[2 * elem] != 0); } if (symb_table[2 * elem] != 0) @@ -714,25 +721,30 @@ FCT (pattern, string, string_end, no_leading_period, flags) idx = 0; elem = hash % table_size; - second = hash % (table_size - 2); - while (symb_table[2 * elem] != 0) + if (symb_table[2 * elem] != 0) { - /* First compare the hashing value. */ - if (symb_table[2 * elem] == hash - && (c1 - == extra[symb_table[2 * elem + 1]]) - && memcmp (str, - &extra[symb_table[2 * elem + 1] - + 1], c1) == 0) + second = hash % (table_size - 2) + 1; + + do { - /* Yep, this is the entry. */ - idx = symb_table[2 * elem + 1]; - idx += 1 + extra[idx]; - break; + /* First compare the hashing value. */ + if (symb_table[2 * elem] == hash + && (c1 + == extra[symb_table[2 * elem + 1]]) + && memcmp (str, + &extra[symb_table[2 * elem + 1] + + 1], c1) == 0) + { + /* Yep, this is the entry. */ + idx = symb_table[2 * elem + 1]; + idx += 1 + extra[idx]; + break; + } + + /* Next entry. */ + elem += second; } - - /* Next entry. */ - elem += second; + while (symb_table[2 * elem] != 0); } if (symb_table[2 * elem] != 0) diff --git a/posix/fork.c b/posix/fork.c new file mode 100644 index 0000000000..c19fa656b3 --- /dev/null +++ b/posix/fork.c @@ -0,0 +1,36 @@ +/* Copyright (C) 1991, 1995, 1996, 1997, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> + + +/* Clone the calling process, creating an exact copy. + Return -1 for errors, 0 to the new process, + and the process ID of the new process to the old process. */ +int +__fork () +{ + __set_errno (ENOSYS); + return -1; +} +libc_hidden_def (__fork) +stub_warning (fork) + +weak_alias (__fork, fork) +#include <stub-tag.h> diff --git a/posix/fpathconf.c b/posix/fpathconf.c new file mode 100644 index 0000000000..840460b04b --- /dev/null +++ b/posix/fpathconf.c @@ -0,0 +1,62 @@ +/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stddef.h> +#include <unistd.h> + + +/* Get file-specific information about descriptor FD. */ +long int +__fpathconf (fd, name) + int fd; + int name; +{ + if (fd < 0) + { + __set_errno (EBADF); + return -1; + } + + switch (name) + { + default: + __set_errno (EINVAL); + return -1; + + case _PC_LINK_MAX: + case _PC_MAX_CANON: + case _PC_MAX_INPUT: + case _PC_NAME_MAX: + case _PC_PATH_MAX: + case _PC_PIPE_BUF: + case _PC_SOCK_MAXBUF: + case _PC_CHOWN_RESTRICTED: + case _PC_NO_TRUNC: + case _PC_VDISABLE: + break; + } + + __set_errno (ENOSYS); + return -1; +} + +weak_alias (__fpathconf, fpathconf) + +stub_warning (fpathconf) +#include <stub-tag.h> diff --git a/posix/gai.conf b/posix/gai.conf new file mode 100644 index 0000000000..0e334ac2c5 --- /dev/null +++ b/posix/gai.conf @@ -0,0 +1,52 @@ +# Configuration for getaddrinfo(3). +# +# So far only configuration for the destination address sorting is needed. +# RFC 3484 governs the sorting. But the RFC also says that system +# administrators should be able to overwrite the defaults. This can be +# achieved here. +# +# All lines have an initial identifier specifying the option followed by +# up to two values. Information specified in this file replaces the +# default information. Complete absence of data of one kind causes the +# appropriate default information to be used. The supported commands include: +# +# reload <yes|no> +# If set to yes, each getaddrinfo(3) call will check whether this file +# changed and if necessary reload. This option should not really be +# used. There are possible runtime problems. The default is no. +# +# label <mask> <value> +# Add another rule to the RFC 3484 label table. See section 2.1 in +# RFC 3484. The default is: +# +#label ::1/128 0 +#label ::/0 1 +#label 2002::/16 2 +#label ::/96 3 +#label ::ffff:0:0/96 4 +#label fec0::/10 5 +#label fc00::/7 6 +# +# This default differs from the tables given in RFC 3484 by handling +# (now obsolete) site-local IPv6 addresses and Unique Local Addresses. +# The reason for this difference is that these addresses are never +# NATed while IPv4 site-local addresses most probably are. Given +# the precedence of IPv6 over IPv4 (see below) on machines having only +# site-local IPv4 and IPv6 addresses a lookup for a global address would +# see the IPv6 be preferred. The result is a long delay because the +# site-local IPv6 addresses cannot be used while the IPv4 address is +# (at least for the foreseeable future) NATed. +# +# precedence <mask> <value> +# Add another rule the to RFC 3484 precedence table. See section 2.1 +# and 10.3 in RFC 3484. The default is: +# +#precedence ::1/128 50 +#precedence ::/0 40 +#precedence 2002::/16 30 +#precedence ::/96 20 +#precedence ::ffff:0:0/96 10 +# +# For sites which prefer IPv4 connections change the last line to +# +#precedence ::ffff:0:0/96 100 diff --git a/posix/gai_strerror.c b/posix/gai_strerror.c new file mode 100644 index 0000000000..932c5910df --- /dev/null +++ b/posix/gai_strerror.c @@ -0,0 +1,29 @@ +/* Copyright (C) 1996,97,2001,02 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <netdb.h> + +const char * +gai_strerror (int code) +{ + static char buffer[128]; + snprintf (buffer, sizeof buffer, "Unknown error (%d)", code); + return buffer; +} +libc_hidden_def (gai_strerror) diff --git a/posix/get_child_max.c b/posix/get_child_max.c new file mode 100644 index 0000000000..dd68d91d32 --- /dev/null +++ b/posix/get_child_max.c @@ -0,0 +1,29 @@ +/* Get POSIX {CHILD_MAX} run-time limit value. Stub version (no limit). + Copyright (C) 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <limits.h> +#include <sys/sysinfo.h> + +#ifndef CHILD_MAX +long int +__get_child_max (void) +{ + return -1; +} +#endif diff --git a/posix/getaddrinfo.c b/posix/getaddrinfo.c new file mode 100644 index 0000000000..548c0b863e --- /dev/null +++ b/posix/getaddrinfo.c @@ -0,0 +1,41 @@ +/* Stub version of getaddrinfo function. + Copyright (C) 1996, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <netdb.h> + +int +getaddrinfo (const char *name, const char *service, const struct addrinfo *req, + struct addrinfo **pai) +{ + __set_errno (ENOSYS); + return EAI_SYSTEM; +} +stub_warning (getaddrinfo) +libc_hidden_def (getaddrinfo) + +void +freeaddrinfo (struct addrinfo *ai) +{ + /* Nothing. */ +} +stub_warning (freeaddrinfo) +libc_hidden_def (freeaddrinfo) + +#include <stub-tag.h> diff --git a/posix/getconf.c b/posix/getconf.c index 4ce4f8e413..3c5ffe454c 100644 --- a/posix/getconf.c +++ b/posix/getconf.c @@ -1,20 +1,18 @@ -/* Copyright (C) 1991, 92, 1995-2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1991, 92, 1995-2005, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation. - The GNU C Library is distributed in the hope that it will be useful, + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <unistd.h> #include <errno.h> @@ -941,9 +939,55 @@ usage (void) fprintf (stderr, _("Usage: %s [-v specification] variable_name [pathname]\n"), __progname); + fprintf (stderr, + _(" %s -a [pathname]\n"), __progname); exit (2); } +static void +print_all (const char *path) +{ + register const struct conf *c; + size_t clen; + long int value; + char *cvalue; + for (c = vars; c->name != NULL; ++c) { + printf("%-35s", c->name); + switch (c->call) { + case PATHCONF: + value = pathconf (path, c->call_name); + if (value != -1) { + printf("%ld", value); + } + printf("\n"); + break; + case SYSCONF: + value = sysconf (c->call_name); + if (value == -1l) { + if (c->call_name == _SC_UINT_MAX + || c->call_name == _SC_ULONG_MAX) + printf ("%lu", value); + } + else { + printf ("%ld", value); + } + printf ("\n"); + break; + case CONFSTR: + clen = confstr (c->call_name, (char *) NULL, 0); + cvalue = (char *) malloc (clen); + if (cvalue == NULL) + error (3, 0, _("memory exhausted")); + if (confstr (c->call_name, cvalue, clen) != clen) + error (3, errno, "confstr"); + printf ("%.*s\n", (int) clen, cvalue); + free (cvalue); + break; + } + } + exit (0); +} + int main (int argc, char *argv[]) { @@ -964,7 +1008,7 @@ main (int argc, char *argv[]) Copyright (C) %s Free Software Foundation, Inc.\n\ This is free software; see the source for copying conditions. There is NO\n\ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ -"), "2004"); +"), "2006"); fprintf (stderr, gettext ("Written by %s.\n"), "Roland McGrath"); return 0; } @@ -1050,6 +1094,16 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ } } + if (argc > 1 && strcmp (argv[1], "-a") == 0) + { + if (argc == 2) + print_all ("/"); + else if (argc == 3) + print_all (argv[2]); + else + usage (); + } + if (argc < 2 || argc > 3) usage (); diff --git a/posix/getconf.speclist.h b/posix/getconf.speclist.h new file mode 100644 index 0000000000..c3e67f7ccb --- /dev/null +++ b/posix/getconf.speclist.h @@ -0,0 +1,15 @@ +#include <unistd.h> +const char *START_OF_STRINGS = +#if _POSIX_V6_ILP32_OFF32 == 1 +"POSIX_V6_ILP32_OFF32" +#endif +#if _POSIX_V6_ILP32_OFFBIG == 1 +"POSIX_V6_ILP32_OFFBIG" +#endif +#if _POSIX_V6_LP64_OFF64 == 1 +"POSIX_V6_LP64_OFF64" +#endif +#if _POSIX_V6_LPBIG_OFFBIG == 1 +"POSIX_V6_LPBIG_OFFBIG" +#endif +""; diff --git a/posix/getegid.c b/posix/getegid.c new file mode 100644 index 0000000000..d939d6ad64 --- /dev/null +++ b/posix/getegid.c @@ -0,0 +1,32 @@ +/* Copyright (C) 1991, 1992, 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> + +/* Get the effective group ID of the calling process. */ +__gid_t +__getegid () +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (getegid) + +weak_alias (__getegid, getegid) +#include <stub-tag.h> diff --git a/posix/geteuid.c b/posix/geteuid.c new file mode 100644 index 0000000000..c67dbfd708 --- /dev/null +++ b/posix/geteuid.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1991, 1992, 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> + + +/* Get the effective user ID of the calling process. */ +__uid_t +__geteuid () +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (geteuid) + +weak_alias (__geteuid, geteuid) +#include <stub-tag.h> diff --git a/posix/getgid.c b/posix/getgid.c new file mode 100644 index 0000000000..742c099fa2 --- /dev/null +++ b/posix/getgid.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1991, 1993, 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> +#include <sys/types.h> + +/* Get the real group ID of the calling process. */ +gid_t +__getgid () +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (getgid) + +weak_alias (__getgid, getgid) +#include <stub-tag.h> diff --git a/posix/getgroups.c b/posix/getgroups.c new file mode 100644 index 0000000000..d5868cc1b8 --- /dev/null +++ b/posix/getgroups.c @@ -0,0 +1,48 @@ +/* Copyright (C) 1991,1992,1995,1996,1997,2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stddef.h> +#include <unistd.h> +#include <sys/types.h> +#include <limits.h> + + +/* If SIZE is zero, return the number of supplementary groups + the calling process is in. Otherwise, fill in the group IDs + of its supplementary groups in LIST and return the number written. */ +int +__getgroups (size, list) + int size; + gid_t *list; +{ +#if defined (NGROUPS_MAX) && NGROUPS_MAX == 0 + /* The system has no supplementary groups. */ + return 0; +#endif + + __set_errno (ENOSYS); + return -1; +} + +#if !(defined (NGROUPS_MAX) && NGROUPS_MAX == 0) +stub_warning (getgroups); +#endif + +weak_alias (__getgroups, getgroups) +#include <stub-tag.h> diff --git a/posix/getlogin.c b/posix/getlogin.c new file mode 100644 index 0000000000..12b4283396 --- /dev/null +++ b/posix/getlogin.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1991, 1995, 1996 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stddef.h> +#include <errno.h> +#include <unistd.h> + +/* Return the login name of the user, or NULL if it can't be determined. + The returned pointer, if not NULL, is good only until the next call. */ +char * +getlogin (void) +{ + __set_errno (ENOSYS); + return NULL; +} + +stub_warning (getlogin) +#include <stub-tag.h> diff --git a/posix/getlogin_r.c b/posix/getlogin_r.c new file mode 100644 index 0000000000..f2470ee032 --- /dev/null +++ b/posix/getlogin_r.c @@ -0,0 +1,37 @@ +/* Reentrant function to return the current login name. Stub version. + Copyright (C) 1996, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> + +/* Return at most NAME_LEN characters of the login name of the user in NAME. + If it cannot be determined or some other error occurred, return the error + code. Otherwise return 0. */ +int +getlogin_r (name, name_len) + char *name; + size_t name_len; +{ + __set_errno (ENOSYS); + return errno; +} +libc_hidden_def (getlogin_r) + +stub_warning (getlogin_r) +#include <stub-tag.h> diff --git a/posix/getopt.c b/posix/getopt.c index 9ad13a4a92..b1cecd31aa 100644 --- a/posix/getopt.c +++ b/posix/getopt.c @@ -576,10 +576,7 @@ _getopt_internal_r (int argc, char *const *argv, const char *optstring, int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); @@ -654,10 +651,7 @@ _getopt_internal_r (int argc, char *const *argv, const char *optstring, ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); @@ -694,10 +688,7 @@ _getopt_internal_r (int argc, char *const *argv, const char *optstring, ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); @@ -771,10 +762,7 @@ _getopt_internal_r (int argc, char *const *argv, const char *optstring, int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); @@ -837,10 +825,7 @@ _getopt_internal_r (int argc, char *const *argv, const char *optstring, int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); @@ -888,10 +873,7 @@ _getopt_internal_r (int argc, char *const *argv, const char *optstring, int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); @@ -960,10 +942,7 @@ _getopt_internal_r (int argc, char *const *argv, const char *optstring, int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); @@ -1005,10 +984,7 @@ _getopt_internal_r (int argc, char *const *argv, const char *optstring, ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); @@ -1047,10 +1023,7 @@ _getopt_internal_r (int argc, char *const *argv, const char *optstring, ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); @@ -1121,10 +1094,7 @@ _getopt_internal_r (int argc, char *const *argv, const char *optstring, int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); diff --git a/posix/getpgid.c b/posix/getpgid.c new file mode 100644 index 0000000000..ad46771d2f --- /dev/null +++ b/posix/getpgid.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1991,1995,1996,1997,1998,2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <unistd.h> +#include <sys/types.h> + +/* Get the process group ID of process PID. */ +pid_t +__getpgid (pid) + pid_t pid; +{ + return pid; +} +libc_hidden_def (__getpgid) +weak_alias (__getpgid, getpgid) + +stub_warning (getpgid) +#include <stub-tag.h> diff --git a/posix/getpgrp.c b/posix/getpgrp.c new file mode 100644 index 0000000000..85efc2f215 --- /dev/null +++ b/posix/getpgrp.c @@ -0,0 +1,27 @@ +/* Copyright (C) 1991, 1995, 1997, 1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> + +/* Get the process group ID of the calling process. */ +pid_t +getpgrp (void) +{ + return __getpgid (0); +} diff --git a/posix/getpid.c b/posix/getpid.c new file mode 100644 index 0000000000..c1c91fede7 --- /dev/null +++ b/posix/getpid.c @@ -0,0 +1,34 @@ +/* Copyright (C) 1991, 1995, 1996, 1997, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> + +/* Get the process ID of the calling process. */ +int +__getpid () +{ + __set_errno (ENOSYS); + return -1; +} +libc_hidden_def (__getpid) +stub_warning (getpid) + +weak_alias (__getpid, getpid) +libc_hidden_weak (getpid) +#include <stub-tag.h> diff --git a/posix/getppid.c b/posix/getppid.c new file mode 100644 index 0000000000..e00c237496 --- /dev/null +++ b/posix/getppid.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> + + +/* Get the parent process ID of the calling process. */ +int +__getppid () +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (getppid) + +weak_alias (__getppid, getppid) +#include <stub-tag.h> diff --git a/posix/getresgid.c b/posix/getresgid.c new file mode 100644 index 0000000000..eccce7d69c --- /dev/null +++ b/posix/getresgid.c @@ -0,0 +1,35 @@ +/* Copyright (C) 1991,1995,1996,1997,1998,2002,2006 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> + +/* Fetch the real group ID, effective group ID, and saved-set group ID, + of the calling process. */ +int +__getresgid (gid_t *rgid, gid_t *egid, gid_t *sgid) +{ + __set_errno (ENOSYS); + return -1; +} +libc_hidden_def (__getresgid) +stub_warning (getresgid) + +weak_alias (__getresgid, getresgid) +#include <stub-tag.h> diff --git a/posix/getresuid.c b/posix/getresuid.c new file mode 100644 index 0000000000..83456c29b8 --- /dev/null +++ b/posix/getresuid.c @@ -0,0 +1,35 @@ +/* Copyright (C) 1991,1995,1996,1997,1998,2002,2006 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> + +/* Fetch the real user ID, effective user ID, and saved-set user ID, + of the calling process. */ +int +__getresuid (uid_t *ruid, uid_t *euid, uid_t *suid) +{ + __set_errno (ENOSYS); + return -1; +} +libc_hidden_def (__getresuid) +stub_warning (getresuid) + +weak_alias (__getresuid, getresuid) +#include <stub-tag.h> diff --git a/posix/getsid.c b/posix/getsid.c new file mode 100644 index 0000000000..eb7e60fa42 --- /dev/null +++ b/posix/getsid.c @@ -0,0 +1,32 @@ +/* getsid -- Return session ID of a process. Stub version. + Copyright (C) 1995,96,97,2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sys/types.h> +#include <unistd.h> +#include <errno.h> + +pid_t +getsid (pid_t pid) +{ + __set_errno (ENOSYS); + return (pid_t) -1; +} +libc_hidden_def (getsid) +stub_warning (getsid) +#include <stub-tag.h> diff --git a/posix/getuid.c b/posix/getuid.c new file mode 100644 index 0000000000..c4ea7e8c98 --- /dev/null +++ b/posix/getuid.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1991, 1993, 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> +#include <sys/types.h> + +/* Get the real user ID of the calling process. */ +uid_t +__getuid () +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (getuid) + +weak_alias (__getuid, getuid) +#include <stub-tag.h> diff --git a/posix/glob.c b/posix/glob.c new file mode 100644 index 0000000000..0079a15a92 --- /dev/null +++ b/posix/glob.c @@ -0,0 +1,1351 @@ +/* Copyright (C) 1991-2002,2003,2004,2005,2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <glob.h> + +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <stddef.h> + +/* Outcomment the following line for production quality code. */ +/* #define NDEBUG 1 */ +#include <assert.h> + +#include <stdio.h> /* Needed on stupid SunOS for assert. */ + +#if !defined _LIBC || !defined GLOB_ONLY_P +#if defined HAVE_UNISTD_H || defined _LIBC +# include <unistd.h> +# ifndef POSIX +# ifdef _POSIX_VERSION +# define POSIX +# endif +# endif +#endif + +#include <pwd.h> + +#include <errno.h> +#ifndef __set_errno +# define __set_errno(val) errno = (val) +#endif + +#if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__ +# include <dirent.h> +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# ifdef HAVE_SYS_NDIR_H +# include <sys/ndir.h> +# endif +# ifdef HAVE_SYS_DIR_H +# include <sys/dir.h> +# endif +# ifdef HAVE_NDIR_H +# include <ndir.h> +# endif +# ifdef HAVE_VMSDIR_H +# include "vmsdir.h" +# endif /* HAVE_VMSDIR_H */ +#endif + + +/* In GNU systems, <dirent.h> defines this macro for us. */ +#ifdef _D_NAMLEN +# undef NAMLEN +# define NAMLEN(d) _D_NAMLEN(d) +#endif + +/* When used in the GNU libc the symbol _DIRENT_HAVE_D_TYPE is available + if the `d_type' member for `struct dirent' is available. + HAVE_STRUCT_DIRENT_D_TYPE plays the same role in GNULIB. */ +#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE +/* True if the directory entry D must be of type T. */ +# define DIRENT_MUST_BE(d, t) ((d)->d_type == (t)) + +/* True if the directory entry D might be a symbolic link. */ +# define DIRENT_MIGHT_BE_SYMLINK(d) \ + ((d)->d_type == DT_UNKNOWN || (d)->d_type == DT_LNK) + +/* True if the directory entry D might be a directory. */ +# define DIRENT_MIGHT_BE_DIR(d) \ + ((d)->d_type == DT_DIR || DIRENT_MIGHT_BE_SYMLINK (d)) + +#else /* !HAVE_D_TYPE */ +# define DIRENT_MUST_BE(d, t) false +# define DIRENT_MIGHT_BE_SYMLINK(d) true +# define DIRENT_MIGHT_BE_DIR(d) true +#endif /* HAVE_D_TYPE */ + +/* If the system has the `struct dirent64' type we use it internally. */ +#if defined _LIBC && !defined COMPILE_GLOB64 +# if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__ +# define CONVERT_D_NAMLEN(d64, d32) +# else +# define CONVERT_D_NAMLEN(d64, d32) \ + (d64)->d_namlen = (d32)->d_namlen; +# endif + +# if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__ +# define CONVERT_D_INO(d64, d32) +# else +# define CONVERT_D_INO(d64, d32) \ + (d64)->d_ino = (d32)->d_ino; +# endif + +# ifdef _DIRENT_HAVE_D_TYPE +# define CONVERT_D_TYPE(d64, d32) \ + (d64)->d_type = (d32)->d_type; +# else +# define CONVERT_D_TYPE(d64, d32) +# endif + +# define CONVERT_DIRENT_DIRENT64(d64, d32) \ + memcpy ((d64)->d_name, (d32)->d_name, NAMLEN (d32) + 1); \ + CONVERT_D_NAMLEN (d64, d32) \ + CONVERT_D_INO (d64, d32) \ + CONVERT_D_TYPE (d64, d32) +#endif + + +#if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__ +/* Posix does not require that the d_ino field be present, and some + systems do not provide it. */ +# define REAL_DIR_ENTRY(dp) 1 +#else +# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0) +#endif /* POSIX */ + +#include <stdlib.h> +#include <string.h> + +/* NAME_MAX is usually defined in <dirent.h> or <limits.h>. */ +#include <limits.h> +#ifndef NAME_MAX +# define NAME_MAX (sizeof (((struct dirent *) 0)->d_name)) +#endif + +#include <alloca.h> + +#ifdef _LIBC +# undef strdup +# define strdup(str) __strdup (str) +# define sysconf(id) __sysconf (id) +# define closedir(dir) __closedir (dir) +# define opendir(name) __opendir (name) +# define readdir(str) __readdir64 (str) +# define getpwnam_r(name, bufp, buf, len, res) \ + __getpwnam_r (name, bufp, buf, len, res) +# ifndef __stat64 +# define __stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf) +# endif +# define struct_stat64 struct stat64 +#else /* !_LIBC */ +# include "getlogin_r.h" +# include "mempcpy.h" +# include "stat-macros.h" +# include "strdup.h" +# define __stat64(fname, buf) stat (fname, buf) +# define struct_stat64 struct stat +# define __stat(fname, buf) stat (fname, buf) +# define __alloca alloca +# define __readdir readdir +# define __readdir64 readdir64 +# define __glob_pattern_p glob_pattern_p +#endif /* _LIBC */ + +#include <fnmatch.h> + +#ifdef _SC_GETPW_R_SIZE_MAX +# define GETPW_R_SIZE_MAX() sysconf (_SC_GETPW_R_SIZE_MAX) +#else +# define GETPW_R_SIZE_MAX() (-1) +#endif +#ifdef _SC_LOGIN_NAME_MAX +# define GET_LOGIN_NAME_MAX() sysconf (_SC_LOGIN_NAME_MAX) +#else +# define GET_LOGIN_NAME_MAX() (-1) +#endif + +static const char *next_brace_sub (const char *begin, int flags) __THROW; + +#endif /* !defined _LIBC || !defined GLOB_ONLY_P */ + +static int glob_in_dir (const char *pattern, const char *directory, + int flags, int (*errfunc) (const char *, int), + glob_t *pglob); + +#if !defined _LIBC || !defined GLOB_ONLY_P +static int prefix_array (const char *prefix, char **array, size_t n) __THROW; +static int collated_compare (const void *, const void *) __THROW; + + +/* Find the end of the sub-pattern in a brace expression. */ +static const char * +next_brace_sub (const char *cp, int flags) +{ + unsigned int depth = 0; + while (*cp != '\0') + if ((flags & GLOB_NOESCAPE) == 0 && *cp == '\\') + { + if (*++cp == '\0') + break; + ++cp; + } + else + { + if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0)) + break; + + if (*cp++ == '{') + depth++; + } + + return *cp != '\0' ? cp : NULL; +} + +#endif /* !defined _LIBC || !defined GLOB_ONLY_P */ + +/* Do glob searching for PATTERN, placing results in PGLOB. + The bits defined above may be set in FLAGS. + If a directory cannot be opened or read and ERRFUNC is not nil, + it is called with the pathname that caused the error, and the + `errno' value from the failing call; if it returns non-zero + `glob' returns GLOB_ABORTED; if it returns zero, the error is ignored. + If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned. + Otherwise, `glob' returns zero. */ +int +#ifdef GLOB_ATTRIBUTE +GLOB_ATTRIBUTE +#endif +glob (pattern, flags, errfunc, pglob) + const char *pattern; + int flags; + int (*errfunc) (const char *, int); + glob_t *pglob; +{ + const char *filename; + const char *dirname; + size_t dirlen; + int status; + size_t oldcount; + + if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0) + { + __set_errno (EINVAL); + return -1; + } + + if (!(flags & GLOB_DOOFFS)) + /* Have to do this so `globfree' knows where to start freeing. It + also makes all the code that uses gl_offs simpler. */ + pglob->gl_offs = 0; + + if (flags & GLOB_BRACE) + { + const char *begin; + + if (flags & GLOB_NOESCAPE) + begin = strchr (pattern, '{'); + else + { + begin = pattern; + while (1) + { + if (*begin == '\0') + { + begin = NULL; + break; + } + + if (*begin == '\\' && begin[1] != '\0') + ++begin; + else if (*begin == '{') + break; + + ++begin; + } + } + + if (begin != NULL) + { + /* Allocate working buffer large enough for our work. Note that + we have at least an opening and closing brace. */ + size_t firstc; + char *alt_start; + const char *p; + const char *next; + const char *rest; + size_t rest_len; +#ifdef __GNUC__ + char onealt[strlen (pattern) - 1]; +#else + char *onealt = (char *) malloc (strlen (pattern) - 1); + if (onealt == NULL) + { + if (!(flags & GLOB_APPEND)) + { + pglob->gl_pathc = 0; + pglob->gl_pathv = NULL; + } + return GLOB_NOSPACE; + } +#endif + + /* We know the prefix for all sub-patterns. */ + alt_start = mempcpy (onealt, pattern, begin - pattern); + + /* Find the first sub-pattern and at the same time find the + rest after the closing brace. */ + next = next_brace_sub (begin + 1, flags); + if (next == NULL) + { + /* It is an illegal expression. */ +#ifndef __GNUC__ + free (onealt); +#endif + return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob); + } + + /* Now find the end of the whole brace expression. */ + rest = next; + while (*rest != '}') + { + rest = next_brace_sub (rest + 1, flags); + if (rest == NULL) + { + /* It is an illegal expression. */ +#ifndef __GNUC__ + free (onealt); +#endif + return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob); + } + } + /* Please note that we now can be sure the brace expression + is well-formed. */ + rest_len = strlen (++rest) + 1; + + /* We have a brace expression. BEGIN points to the opening {, + NEXT points past the terminator of the first element, and END + points past the final }. We will accumulate result names from + recursive runs for each brace alternative in the buffer using + GLOB_APPEND. */ + + if (!(flags & GLOB_APPEND)) + { + /* This call is to set a new vector, so clear out the + vector so we can append to it. */ + pglob->gl_pathc = 0; + pglob->gl_pathv = NULL; + } + firstc = pglob->gl_pathc; + + p = begin + 1; + while (1) + { + int result; + + /* Construct the new glob expression. */ + mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len); + + result = glob (onealt, + ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC)) + | GLOB_APPEND), errfunc, pglob); + + /* If we got an error, return it. */ + if (result && result != GLOB_NOMATCH) + { +#ifndef __GNUC__ + free (onealt); +#endif + if (!(flags & GLOB_APPEND)) + { + globfree (pglob); + pglob->gl_pathc = 0; + } + return result; + } + + if (*next == '}') + /* We saw the last entry. */ + break; + + p = next + 1; + next = next_brace_sub (p, flags); + assert (next != NULL); + } + +#ifndef __GNUC__ + free (onealt); +#endif + + if (pglob->gl_pathc != firstc) + /* We found some entries. */ + return 0; + else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC))) + return GLOB_NOMATCH; + } + } + + /* Find the filename. */ + filename = strrchr (pattern, '/'); +#if defined __MSDOS__ || defined WINDOWS32 + /* The case of "d:pattern". Since `:' is not allowed in + file names, we can safely assume that wherever it + happens in pattern, it signals the filename part. This + is so we could some day support patterns like "[a-z]:foo". */ + if (filename == NULL) + filename = strchr (pattern, ':'); +#endif /* __MSDOS__ || WINDOWS32 */ + if (filename == NULL) + { + /* This can mean two things: a simple name or "~name". The latter + case is nothing but a notation for a directory. */ + if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~') + { + dirname = pattern; + dirlen = strlen (pattern); + + /* Set FILENAME to NULL as a special flag. This is ugly but + other solutions would require much more code. We test for + this special case below. */ + filename = NULL; + } + else + { + filename = pattern; +#ifdef _AMIGA + dirname = ""; +#else + dirname = "."; +#endif + dirlen = 0; + } + } + else if (filename == pattern) + { + /* "/pattern". */ + dirname = "/"; + dirlen = 1; + ++filename; + } + else + { + char *newp; + dirlen = filename - pattern; +#if defined __MSDOS__ || defined WINDOWS32 + if (*filename == ':' + || (filename > pattern + 1 && filename[-1] == ':')) + { + char *drive_spec; + + ++dirlen; + drive_spec = (char *) __alloca (dirlen + 1); + *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0'; + /* For now, disallow wildcards in the drive spec, to + prevent infinite recursion in glob. */ + if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE))) + return GLOB_NOMATCH; + /* If this is "d:pattern", we need to copy `:' to DIRNAME + as well. If it's "d:/pattern", don't remove the slash + from "d:/", since "d:" and "d:/" are not the same.*/ + } +#endif + newp = (char *) __alloca (dirlen + 1); + *((char *) mempcpy (newp, pattern, dirlen)) = '\0'; + dirname = newp; + ++filename; + + if (filename[0] == '\0' +#if defined __MSDOS__ || defined WINDOWS32 + && dirname[dirlen - 1] != ':' + && (dirlen < 3 || dirname[dirlen - 2] != ':' + || dirname[dirlen - 1] != '/') +#endif + && dirlen > 1) + /* "pattern/". Expand "pattern", appending slashes. */ + { + int val = glob (dirname, flags | GLOB_MARK, errfunc, pglob); + if (val == 0) + pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK) + | (flags & GLOB_MARK)); + return val; + } + } + + if (!(flags & GLOB_APPEND)) + { + pglob->gl_pathc = 0; + if (!(flags & GLOB_DOOFFS)) + pglob->gl_pathv = NULL; + else + { + size_t i; + pglob->gl_pathv = (char **) malloc ((pglob->gl_offs + 1) + * sizeof (char *)); + if (pglob->gl_pathv == NULL) + return GLOB_NOSPACE; + + for (i = 0; i <= pglob->gl_offs; ++i) + pglob->gl_pathv[i] = NULL; + } + } + + oldcount = pglob->gl_pathc + pglob->gl_offs; + +#ifndef VMS + if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~') + { + if (dirname[1] == '\0' || dirname[1] == '/') + { + /* Look up home directory. */ + const char *home_dir = getenv ("HOME"); +# ifdef _AMIGA + if (home_dir == NULL || home_dir[0] == '\0') + home_dir = "SYS:"; +# else +# ifdef WINDOWS32 + if (home_dir == NULL || home_dir[0] == '\0') + home_dir = "c:/users/default"; /* poor default */ +# else + if (home_dir == NULL || home_dir[0] == '\0') + { + int success; + char *name; + size_t buflen = GET_LOGIN_NAME_MAX () + 1; + + if (buflen == 0) + /* `sysconf' does not support _SC_LOGIN_NAME_MAX. Try + a moderate value. */ + buflen = 20; + name = (char *) __alloca (buflen); + + success = getlogin_r (name, buflen) == 0; + if (success) + { + struct passwd *p; +# if defined HAVE_GETPWNAM_R || defined _LIBC + long int pwbuflen = GETPW_R_SIZE_MAX (); + char *pwtmpbuf; + struct passwd pwbuf; + int save = errno; + +# ifndef _LIBC + if (pwbuflen == -1) + /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX. + Try a moderate value. */ + pwbuflen = 1024; +# endif + pwtmpbuf = (char *) __alloca (pwbuflen); + + while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p) + != 0) + { + if (errno != ERANGE) + { + p = NULL; + break; + } +# ifdef _LIBC + pwtmpbuf = extend_alloca (pwtmpbuf, pwbuflen, + 2 * pwbuflen); +# else + pwbuflen *= 2; + pwtmpbuf = (char *) __alloca (pwbuflen); +# endif + __set_errno (save); + } +# else + p = getpwnam (name); +# endif + if (p != NULL) + home_dir = p->pw_dir; + } + } + if (home_dir == NULL || home_dir[0] == '\0') + { + if (flags & GLOB_TILDE_CHECK) + return GLOB_NOMATCH; + else + home_dir = "~"; /* No luck. */ + } +# endif /* WINDOWS32 */ +# endif + /* Now construct the full directory. */ + if (dirname[1] == '\0') + dirname = home_dir; + else + { + char *newp; + size_t home_len = strlen (home_dir); + newp = (char *) __alloca (home_len + dirlen); + mempcpy (mempcpy (newp, home_dir, home_len), + &dirname[1], dirlen); + dirname = newp; + } + } +# if !defined _AMIGA && !defined WINDOWS32 + else + { + char *end_name = strchr (dirname, '/'); + const char *user_name; + const char *home_dir; + + if (end_name == NULL) + user_name = dirname + 1; + else + { + char *newp; + newp = (char *) __alloca (end_name - dirname); + *((char *) mempcpy (newp, dirname + 1, end_name - dirname)) + = '\0'; + user_name = newp; + } + + /* Look up specific user's home directory. */ + { + struct passwd *p; +# if defined HAVE_GETPWNAM_R || defined _LIBC + long int buflen = GETPW_R_SIZE_MAX (); + char *pwtmpbuf; + struct passwd pwbuf; + int save = errno; + +# ifndef _LIBC + if (buflen == -1) + /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX. Try a + moderate value. */ + buflen = 1024; +# endif + pwtmpbuf = (char *) __alloca (buflen); + + while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0) + { + if (errno != ERANGE) + { + p = NULL; + break; + } +# ifdef _LIBC + pwtmpbuf = extend_alloca (pwtmpbuf, buflen, 2 * buflen); +# else + buflen *= 2; + pwtmpbuf = __alloca (buflen); +# endif + __set_errno (save); + } +# else + p = getpwnam (user_name); +# endif + if (p != NULL) + home_dir = p->pw_dir; + else + home_dir = NULL; + } + /* If we found a home directory use this. */ + if (home_dir != NULL) + { + char *newp; + size_t home_len = strlen (home_dir); + size_t rest_len = end_name == NULL ? 0 : strlen (end_name); + newp = (char *) __alloca (home_len + rest_len + 1); + *((char *) mempcpy (mempcpy (newp, home_dir, home_len), + end_name, rest_len)) = '\0'; + dirname = newp; + } + else + if (flags & GLOB_TILDE_CHECK) + /* We have to regard it as an error if we cannot find the + home directory. */ + return GLOB_NOMATCH; + } +# endif /* Not Amiga && not WINDOWS32. */ + } +#endif /* Not VMS. */ + + /* Now test whether we looked for "~" or "~NAME". In this case we + can give the answer now. */ + if (filename == NULL) + { + struct stat st; + struct_stat64 st64; + + /* Return the directory if we don't check for error or if it exists. */ + if ((flags & GLOB_NOCHECK) + || (((flags & GLOB_ALTDIRFUNC) + ? ((*pglob->gl_stat) (dirname, &st) == 0 + && S_ISDIR (st.st_mode)) + : (__stat64 (dirname, &st64) == 0 && S_ISDIR (st64.st_mode))))) + { + int newcount = pglob->gl_pathc + pglob->gl_offs; + char **new_gl_pathv; + + new_gl_pathv + = (char **) realloc (pglob->gl_pathv, + (newcount + 1 + 1) * sizeof (char *)); + if (new_gl_pathv == NULL) + { + nospace: + free (pglob->gl_pathv); + pglob->gl_pathv = NULL; + pglob->gl_pathc = 0; + return GLOB_NOSPACE; + } + pglob->gl_pathv = new_gl_pathv; + + pglob->gl_pathv[newcount] = strdup (dirname); + if (pglob->gl_pathv[newcount] == NULL) + goto nospace; + pglob->gl_pathv[++newcount] = NULL; + ++pglob->gl_pathc; + pglob->gl_flags = flags; + + return 0; + } + + /* Not found. */ + return GLOB_NOMATCH; + } + + if (__glob_pattern_p (dirname, !(flags & GLOB_NOESCAPE))) + { + /* The directory name contains metacharacters, so we + have to glob for the directory, and then glob for + the pattern in each directory found. */ + glob_t dirs; + size_t i; + + if ((flags & GLOB_ALTDIRFUNC) != 0) + { + /* Use the alternative access functions also in the recursive + call. */ + dirs.gl_opendir = pglob->gl_opendir; + dirs.gl_readdir = pglob->gl_readdir; + dirs.gl_closedir = pglob->gl_closedir; + dirs.gl_stat = pglob->gl_stat; + dirs.gl_lstat = pglob->gl_lstat; + } + + status = glob (dirname, + ((flags & (GLOB_ERR | GLOB_NOCHECK | GLOB_NOESCAPE + | GLOB_ALTDIRFUNC)) + | GLOB_NOSORT | GLOB_ONLYDIR), + errfunc, &dirs); + if (status != 0) + return status; + + /* We have successfully globbed the preceding directory name. + For each name we found, call glob_in_dir on it and FILENAME, + appending the results to PGLOB. */ + for (i = 0; i < dirs.gl_pathc; ++i) + { + int old_pathc; + +#ifdef SHELL + { + /* Make globbing interruptible in the bash shell. */ + extern int interrupt_state; + + if (interrupt_state) + { + globfree (&dirs); + return GLOB_ABORTED; + } + } +#endif /* SHELL. */ + + old_pathc = pglob->gl_pathc; + status = glob_in_dir (filename, dirs.gl_pathv[i], + ((flags | GLOB_APPEND) + & ~(GLOB_NOCHECK | GLOB_NOMAGIC)), + errfunc, pglob); + if (status == GLOB_NOMATCH) + /* No matches in this directory. Try the next. */ + continue; + + if (status != 0) + { + globfree (&dirs); + globfree (pglob); + pglob->gl_pathc = 0; + return status; + } + + /* Stick the directory on the front of each name. */ + if (prefix_array (dirs.gl_pathv[i], + &pglob->gl_pathv[old_pathc + pglob->gl_offs], + pglob->gl_pathc - old_pathc)) + { + globfree (&dirs); + globfree (pglob); + pglob->gl_pathc = 0; + return GLOB_NOSPACE; + } + } + + flags |= GLOB_MAGCHAR; + + /* We have ignored the GLOB_NOCHECK flag in the `glob_in_dir' calls. + But if we have not found any matching entry and the GLOB_NOCHECK + flag was set we must return the input pattern itself. */ + if (pglob->gl_pathc + pglob->gl_offs == oldcount) + { + /* No matches. */ + if (flags & GLOB_NOCHECK) + { + int newcount = pglob->gl_pathc + pglob->gl_offs; + char **new_gl_pathv; + + new_gl_pathv = (char **) realloc (pglob->gl_pathv, + (newcount + 2) + * sizeof (char *)); + if (new_gl_pathv == NULL) + { + globfree (&dirs); + return GLOB_NOSPACE; + } + pglob->gl_pathv = new_gl_pathv; + + pglob->gl_pathv[newcount] = __strdup (pattern); + if (pglob->gl_pathv[newcount] == NULL) + { + globfree (&dirs); + globfree (pglob); + pglob->gl_pathc = 0; + return GLOB_NOSPACE; + } + + ++pglob->gl_pathc; + ++newcount; + + pglob->gl_pathv[newcount] = NULL; + pglob->gl_flags = flags; + } + else + { + globfree (&dirs); + return GLOB_NOMATCH; + } + } + + globfree (&dirs); + } + else + { + int old_pathc = pglob->gl_pathc; + + status = glob_in_dir (filename, dirname, flags, errfunc, pglob); + if (status != 0) + return status; + + if (dirlen > 0) + { + /* Stick the directory on the front of each name. */ + if (prefix_array (dirname, + &pglob->gl_pathv[old_pathc + pglob->gl_offs], + pglob->gl_pathc - old_pathc)) + { + globfree (pglob); + pglob->gl_pathc = 0; + return GLOB_NOSPACE; + } + } + } + + if (flags & GLOB_MARK) + { + /* Append slashes to directory names. */ + size_t i; + struct stat st; + struct_stat64 st64; + + for (i = oldcount; i < pglob->gl_pathc + pglob->gl_offs; ++i) + if (((flags & GLOB_ALTDIRFUNC) + ? ((*pglob->gl_stat) (pglob->gl_pathv[i], &st) == 0 + && S_ISDIR (st.st_mode)) + : (__stat64 (pglob->gl_pathv[i], &st64) == 0 + && S_ISDIR (st64.st_mode)))) + { + size_t len = strlen (pglob->gl_pathv[i]) + 2; + char *new = realloc (pglob->gl_pathv[i], len); + if (new == NULL) + { + globfree (pglob); + pglob->gl_pathc = 0; + return GLOB_NOSPACE; + } + strcpy (&new[len - 2], "/"); + pglob->gl_pathv[i] = new; + } + } + + if (!(flags & GLOB_NOSORT)) + { + /* Sort the vector. */ + qsort (&pglob->gl_pathv[oldcount], + pglob->gl_pathc + pglob->gl_offs - oldcount, + sizeof (char *), collated_compare); + } + + return 0; +} +#if defined _LIBC && !defined glob +libc_hidden_def (glob) +#endif + + +#if !defined _LIBC || !defined GLOB_ONLY_P + +/* Free storage allocated in PGLOB by a previous `glob' call. */ +void +globfree (pglob) + register glob_t *pglob; +{ + if (pglob->gl_pathv != NULL) + { + size_t i; + for (i = 0; i < pglob->gl_pathc; ++i) + if (pglob->gl_pathv[pglob->gl_offs + i] != NULL) + free (pglob->gl_pathv[pglob->gl_offs + i]); + free (pglob->gl_pathv); + pglob->gl_pathv = NULL; + } +} +#if defined _LIBC && !defined globfree +libc_hidden_def (globfree) +#endif + + +/* Do a collated comparison of A and B. */ +static int +collated_compare (const void *a, const void *b) +{ + const char *const s1 = *(const char *const * const) a; + const char *const s2 = *(const char *const * const) b; + + if (s1 == s2) + return 0; + if (s1 == NULL) + return 1; + if (s2 == NULL) + return -1; + return strcoll (s1, s2); +} + + +/* Prepend DIRNAME to each of N members of ARRAY, replacing ARRAY's + elements in place. Return nonzero if out of memory, zero if successful. + A slash is inserted between DIRNAME and each elt of ARRAY, + unless DIRNAME is just "/". Each old element of ARRAY is freed. */ +static int +prefix_array (const char *dirname, char **array, size_t n) +{ + register size_t i; + size_t dirlen = strlen (dirname); +#if defined __MSDOS__ || defined WINDOWS32 + int sep_char = '/'; +# define DIRSEP_CHAR sep_char +#else +# define DIRSEP_CHAR '/' +#endif + + if (dirlen == 1 && dirname[0] == '/') + /* DIRNAME is just "/", so normal prepending would get us "//foo". + We want "/foo" instead, so don't prepend any chars from DIRNAME. */ + dirlen = 0; +#if defined __MSDOS__ || defined WINDOWS32 + else if (dirlen > 1) + { + if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':') + /* DIRNAME is "d:/". Don't prepend the slash from DIRNAME. */ + --dirlen; + else if (dirname[dirlen - 1] == ':') + { + /* DIRNAME is "d:". Use `:' instead of `/'. */ + --dirlen; + sep_char = ':'; + } + } +#endif + + for (i = 0; i < n; ++i) + { + size_t eltlen = strlen (array[i]) + 1; + char *new = (char *) malloc (dirlen + 1 + eltlen); + if (new == NULL) + { + while (i > 0) + free (array[--i]); + return 1; + } + + { + char *endp = mempcpy (new, dirname, dirlen); + *endp++ = DIRSEP_CHAR; + mempcpy (endp, array[i], eltlen); + } + free (array[i]); + array[i] = new; + } + + return 0; +} + + +/* We must not compile this function twice. */ +#if !defined _LIBC || !defined NO_GLOB_PATTERN_P +/* Return nonzero if PATTERN contains any metacharacters. + Metacharacters can be quoted with backslashes if QUOTE is nonzero. */ +int +__glob_pattern_p (pattern, quote) + const char *pattern; + int quote; +{ + register const char *p; + int open = 0; + + for (p = pattern; *p != '\0'; ++p) + switch (*p) + { + case '?': + case '*': + return 1; + + case '\\': + if (quote && p[1] != '\0') + ++p; + break; + + case '[': + open = 1; + break; + + case ']': + if (open) + return 1; + break; + } + + return 0; +} +# ifdef _LIBC +weak_alias (__glob_pattern_p, glob_pattern_p) +# endif +#endif + +#endif /* !GLOB_ONLY_P */ + + +/* We put this in a separate function mainly to allow the memory + allocated with alloca to be recycled. */ +#if !defined _LIBC || !defined GLOB_ONLY_P +static int +link_exists_p (const char *dir, size_t dirlen, const char *fname, + glob_t *pglob, int flags) +{ + size_t fnamelen = strlen (fname); + char *fullname = (char *) __alloca (dirlen + 1 + fnamelen + 1); + struct stat st; + struct_stat64 st64; + + mempcpy (mempcpy (mempcpy (fullname, dir, dirlen), "/", 1), + fname, fnamelen + 1); + + return (((flags & GLOB_ALTDIRFUNC) + ? (*pglob->gl_stat) (fullname, &st) + : __stat64 (fullname, &st64)) == 0); +} +#endif + + +/* Like `glob', but PATTERN is a final pathname component, + and matches are searched for in DIRECTORY. + The GLOB_NOSORT bit in FLAGS is ignored. No sorting is ever done. + The GLOB_APPEND flag is assumed to be set (always appends). */ +static int +glob_in_dir (const char *pattern, const char *directory, int flags, + int (*errfunc) (const char *, int), + glob_t *pglob) +{ + size_t dirlen = strlen (directory); + void *stream = NULL; + struct globnames + { + struct globnames *next; + size_t count; + char *name[64]; + }; +#define INITIAL_COUNT sizeof (init_names.name) / sizeof (init_names.name[0]) + struct globnames init_names; + struct globnames *names = &init_names; + struct globnames *names_alloca = &init_names; + size_t nfound = 0; + size_t allocasize = sizeof (init_names); + size_t cur = 0; + int meta; + int save; + + init_names.next = NULL; + init_names.count = INITIAL_COUNT; + + meta = __glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE)); + if (meta == 0 && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC))) + { + /* We need not do any tests. The PATTERN contains no meta + characters and we must not return an error therefore the + result will always contain exactly one name. */ + flags |= GLOB_NOCHECK; + } + else if (meta == 0 && + ((flags & GLOB_NOESCAPE) || strchr (pattern, '\\') == NULL)) + { + /* Since we use the normal file functions we can also use stat() + to verify the file is there. */ + struct stat st; + struct_stat64 st64; + size_t patlen = strlen (pattern); + char *fullname = (char *) __alloca (dirlen + 1 + patlen + 1); + + mempcpy (mempcpy (mempcpy (fullname, directory, dirlen), + "/", 1), + pattern, patlen + 1); + if (((flags & GLOB_ALTDIRFUNC) + ? (*pglob->gl_stat) (fullname, &st) + : __stat64 (fullname, &st64)) == 0) + /* We found this file to be existing. Now tell the rest + of the function to copy this name into the result. */ + flags |= GLOB_NOCHECK; + } + else + { + if (pattern[0] == '\0') + { + /* This is a special case for matching directories like in + "*a/". */ + names->name[cur] = (char *) malloc (1); + if (names->name[cur] == NULL) + goto memory_error; + *names->name[cur++] = '\0'; + nfound = 1; + meta = 0; + } + else + { + stream = ((flags & GLOB_ALTDIRFUNC) + ? (*pglob->gl_opendir) (directory) + : opendir (directory)); + if (stream == NULL) + { + if (errno != ENOTDIR + && ((errfunc != NULL && (*errfunc) (directory, errno)) + || (flags & GLOB_ERR))) + return GLOB_ABORTED; + meta = 0; + } + else + { + int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) + | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) +#if defined _AMIGA || defined VMS + | FNM_CASEFOLD +#endif + ); + flags |= GLOB_MAGCHAR; + + while (1) + { + const char *name; + size_t len; +#if defined _LIBC && !defined COMPILE_GLOB64 + struct dirent64 *d; + union + { + struct dirent64 d64; + char room [offsetof (struct dirent64, d_name[0]) + + NAME_MAX + 1]; + } + d64buf; + + if (flags & GLOB_ALTDIRFUNC) + { + struct dirent *d32 = (*pglob->gl_readdir) (stream); + if (d32 != NULL) + { + CONVERT_DIRENT_DIRENT64 (&d64buf.d64, d32); + d = &d64buf.d64; + } + else + d = NULL; + } + else + d = __readdir64 (stream); +#else + struct dirent *d = ((flags & GLOB_ALTDIRFUNC) + ? ((struct dirent *) + (*pglob->gl_readdir) (stream)) + : __readdir (stream)); +#endif + if (d == NULL) + break; + if (! REAL_DIR_ENTRY (d)) + continue; + + /* If we shall match only directories use the information + provided by the dirent call if possible. */ + if ((flags & GLOB_ONLYDIR) && !DIRENT_MIGHT_BE_DIR (d)) + continue; + + name = d->d_name; + + if (fnmatch (pattern, name, fnm_flags) == 0) + { + /* If the file we found is a symlink we have to + make sure the target file exists. */ + if (!DIRENT_MIGHT_BE_SYMLINK (d) + || link_exists_p (directory, dirlen, name, pglob, + flags)) + { + if (cur == names->count) + { + struct globnames *newnames; + size_t count = names->count * 2; + size_t size = (sizeof (struct globnames) + + ((count - INITIAL_COUNT) + * sizeof (char *))); + allocasize += size; + if (__libc_use_alloca (allocasize)) + newnames = names_alloca = __alloca (size); + else if ((newnames = malloc (size)) + == NULL) + goto memory_error; + newnames->count = count; + newnames->next = names; + names = newnames; + cur = 0; + } + len = NAMLEN (d); + names->name[cur] = (char *) malloc (len + 1); + if (names->name[cur] == NULL) + goto memory_error; + *((char *) mempcpy (names->name[cur++], name, len)) + = '\0'; + ++nfound; + } + } + } + } + } + } + + if (nfound == 0 && (flags & GLOB_NOCHECK)) + { + size_t len = strlen (pattern); + nfound = 1; + names->name[cur] = (char *) malloc (len + 1); + if (names->name[cur] == NULL) + goto memory_error; + *((char *) mempcpy (names->name[cur++], pattern, len)) = '\0'; + } + + int result = GLOB_NOMATCH; + if (nfound != 0) + { + result = 0; + + char **new_gl_pathv; + new_gl_pathv + = (char **) realloc (pglob->gl_pathv, + (pglob->gl_pathc + pglob->gl_offs + nfound + 1) + * sizeof (char *)); + if (new_gl_pathv == NULL) + { + memory_error: + while (1) + { + struct globnames *old = names; + for (size_t i = 0; i < cur; ++i) + free (names->name[i]); + names = names->next; + /* NB: we will not leak memory here if we exit without + freeing the current block assigned to OLD. At least + the very first block is always allocated on the stack + and this is the block assigned to OLD here. */ + if (names == NULL) + { + assert (old == &init_names); + break; + } + cur = names->count; + if (old == names_alloca) + names_alloca = names; + else + free (old); + } + result = GLOB_NOSPACE; + } + else + { + while (1) + { + struct globnames *old = names; + for (size_t i = 0; i < cur; ++i) + new_gl_pathv[pglob->gl_offs + pglob->gl_pathc++] + = names->name[i]; + names = names->next; + /* NB: we will not leak memory here if we exit without + freeing the current block assigned to OLD. At least + the very first block is always allocated on the stack + and this is the block assigned to OLD here. */ + if (names == NULL) + { + assert (old == &init_names); + break; + } + cur = names->count; + if (old == names_alloca) + names_alloca = names; + else + free (old); + } + + pglob->gl_pathv = new_gl_pathv; + + pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; + + pglob->gl_flags = flags; + } + } + + if (stream != NULL) + { + save = errno; + if (flags & GLOB_ALTDIRFUNC) + (*pglob->gl_closedir) (stream); + else + closedir (stream); + __set_errno (save); + } + + return result; +} diff --git a/posix/glob64.c b/posix/glob64.c new file mode 100644 index 0000000000..2bfab74074 --- /dev/null +++ b/posix/glob64.c @@ -0,0 +1,54 @@ +/* Copyright (C) 1998,99,2002,2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stddef.h> +#include <sys/types.h> +#include <glob.h> +#include <errno.h> + +/* Do glob searching for PATTERN, placing results in PGLOB. + The bits defined above may be set in FLAGS. + If a directory cannot be opened or read and ERRFUNC is not nil, + it is called with the pathname that caused the error, and the + `errno' value from the failing call; if it returns non-zero + `glob' returns GLOB_ABORTED; if it returns zero, the error is ignored. + If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned. + Otherwise, `glob' returns zero. */ +int +glob64 (const char *pattern, int flags, + int (*errfunc) (const char *, int), glob64_t *pglob) +{ + if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0) + { + __set_errno (EINVAL); + return -1; + } + + __set_errno (ENOSYS); + return GLOB_NOSYS; +} +libc_hidden_def (glob64) + +void +globfree64 (glob64_t *pglob) +{ +} +libc_hidden_def (globfree64) + +stub_warning (glob64) +#include <stub-tag.h> diff --git a/posix/group_member.c b/posix/group_member.c new file mode 100644 index 0000000000..7bd9c46ba2 --- /dev/null +++ b/posix/group_member.c @@ -0,0 +1,50 @@ +/* `group_member' -- test if process is in a given group. + Copyright (C) 1995, 1997, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sys/types.h> +#include <unistd.h> +#include <stdlib.h> +#include <limits.h> + +#ifndef NGROUPS_MAX +#define NGROUPS_MAX 16 /* First guess. */ +#endif + +int +__group_member (gid) + gid_t gid; +{ + int n, size; + gid_t *groups; + + size = NGROUPS_MAX; + do + { + groups = __alloca (size * sizeof *groups); + n = __getgroups (size, groups); + size *= 2; + } while (n == size / 2); + + while (n >= 0) + if (groups[n--] == gid) + return 1; + + return 0; +} +weak_alias (__group_member, group_member) diff --git a/posix/init-posix.c b/posix/init-posix.c new file mode 100644 index 0000000000..0c2b717e6d --- /dev/null +++ b/posix/init-posix.c @@ -0,0 +1 @@ +/* Nothing to do. */ diff --git a/posix/nanosleep.c b/posix/nanosleep.c new file mode 100644 index 0000000000..7a2138b6f1 --- /dev/null +++ b/posix/nanosleep.c @@ -0,0 +1,36 @@ +/* Copyright (C) 1996, 1997, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <time.h> + + +/* Pause execution for a number of nanoseconds. */ +int +__libc_nanosleep (const struct timespec *requested_time, + struct timespec *remaining) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (nanosleep) + +weak_alias (__libc_nanosleep, __nanosleep) +libc_hidden_def (__nanosleep) +weak_alias (__libc_nanosleep, nanosleep) +#include <stub-tag.h> diff --git a/posix/pathconf.c b/posix/pathconf.c new file mode 100644 index 0000000000..6ac5d31902 --- /dev/null +++ b/posix/pathconf.c @@ -0,0 +1,41 @@ +/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stddef.h> +#include <unistd.h> + + +/* Get file-specific information about PATH. */ +long int +__pathconf (path, name) + const char *path; + int name; +{ + if (path == NULL) + { + __set_errno (EINVAL); + return -1; + } + return __fpathconf (0, name); +} + +weak_alias (__pathconf, pathconf) + +stub_warning (pathconf) +#include <stub-tag.h> diff --git a/posix/pause.c b/posix/pause.c new file mode 100644 index 0000000000..2e34b436f1 --- /dev/null +++ b/posix/pause.c @@ -0,0 +1,34 @@ +/* Copyright (C) 1991, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> + + +/* Suspend the process until a signal arrives. + This is supposed to always return -1 and set errno to EINTR, + but rules were meant to be broken. */ +int +pause () +{ + __set_errno (ENOSYS); + return -1; +} + +stub_warning (pause) +#include <stub-tag.h> diff --git a/posix/posix_madvise.c b/posix/posix_madvise.c new file mode 100644 index 0000000000..6f8d60f55f --- /dev/null +++ b/posix/posix_madvise.c @@ -0,0 +1,32 @@ +/* Copyright (C) 1994, 1995, 1996, 1997, 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sys/types.h> +#include <sys/mman.h> +#include <errno.h> + +/* Advise the system about particular usage patterns the program follows + for the region starting at ADDR and extending LEN bytes. */ + +int +posix_madvise (__ptr_t addr, size_t len, int advice) +{ + return ENOSYS; +} +stub_warning (posix_madvise) +#include <stub-tag.h> diff --git a/posix/pread.c b/posix/pread.c new file mode 100644 index 0000000000..5c79dd526d --- /dev/null +++ b/posix/pread.c @@ -0,0 +1,46 @@ +/* Copyright (C) 1991, 1995, 1996, 1997, 1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> + +/* Read NBYTES into BUF from FD at the given position OFFSET without + changing the file pointer. Return the number read or -1. */ +ssize_t +__libc_pread (int fd, void *buf, size_t nbytes, off_t offset) +{ + if (nbytes == 0) + return 0; + if (fd < 0) + { + __set_errno (EBADF); + return -1; + } + if (buf == NULL || offset < 0) + { + __set_errno (EINVAL); + return -1; + } + + __set_errno (ENOSYS); + return -1; +} +strong_alias (__libc_pread, __pread) +weak_alias (__libc_pread, pread) +stub_warning (pread) +#include <stub-tag.h> diff --git a/posix/pread64.c b/posix/pread64.c new file mode 100644 index 0000000000..68316579c6 --- /dev/null +++ b/posix/pread64.c @@ -0,0 +1,46 @@ +/* Copyright (C) 1991, 1995, 1996, 1997, 1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> + +/* Read NBYTES into BUF from FD at the given position OFFSET without + changing the file pointer. Return the number read or -1. */ +ssize_t +__libc_pread64 (int fd, void *buf, size_t nbytes, off64_t offset) +{ + if (nbytes == 0) + return 0; + if (fd < 0) + { + __set_errno (EBADF); + return -1; + } + if (buf == NULL || offset < 0) + { + __set_errno (EINVAL); + return -1; + } + + __set_errno (ENOSYS); + return -1; +} +strong_alias (__libc_pread64, __pread64) +weak_alias (__libc_pread64, pread64) +stub_warning (pread64) +#include <stub-tag.h> diff --git a/posix/pwrite.c b/posix/pwrite.c new file mode 100644 index 0000000000..ec35ecea9c --- /dev/null +++ b/posix/pwrite.c @@ -0,0 +1,46 @@ +/* Copyright (C) 1991, 1995, 1996, 1997, 1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> + +/* Write NBYTES of BUF to FD at given position OFFSET without changing + the file position. Return the number written, or -1. */ +ssize_t +__libc_pwrite (int fd, const void *buf, size_t nbytes, off_t offset) +{ + if (nbytes == 0) + return 0; + if (fd < 0) + { + __set_errno (EBADF); + return -1; + } + if (buf == NULL || offset < 0) + { + __set_errno (EINVAL); + return -1; + } + + __set_errno (ENOSYS); + return -1; +} +strong_alias (__libc_pwrite, __pwrite) +weak_alias (__libc_pwrite, pwrite) +stub_warning (pwrite) +#include <stub-tag.h> diff --git a/posix/pwrite64.c b/posix/pwrite64.c new file mode 100644 index 0000000000..dd14aa0bd7 --- /dev/null +++ b/posix/pwrite64.c @@ -0,0 +1,47 @@ +/* Copyright (C) 1991,1995,1996,1997,1999,2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> + +/* Write NBYTES of BUF to FD at given position OFFSET without changing + the file position. Return the number written, or -1. */ +ssize_t +__libc_pwrite64 (int fd, const void *buf, size_t nbytes, off64_t offset) +{ + if (nbytes == 0) + return 0; + if (fd < 0) + { + __set_errno (EBADF); + return -1; + } + if (buf == NULL || offset < 0) + { + __set_errno (EINVAL); + return -1; + } + + __set_errno (ENOSYS); + return -1; +} +strong_alias (__libc_pwrite64, __pwrite64) +libc_hidden_def (__pwrite64) +weak_alias (__libc_pwrite64, pwrite64) +stub_warning (pwrite64) +#include <stub-tag.h> diff --git a/posix/regcomp.c b/posix/regcomp.c index 5de5bf725a..e99fd74924 100644 --- a/posix/regcomp.c +++ b/posix/regcomp.c @@ -1,5 +1,5 @@ /* Extended regular expression matching and search library. - Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 2002,2003,2004,2005,2006,2007 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. @@ -19,12 +19,11 @@ 02111-1307 USA. */ static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern, - int length, reg_syntax_t syntax); + size_t length, reg_syntax_t syntax); static void re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state, char *fastmap); -static reg_errcode_t init_dfa (re_dfa_t *dfa, int pat_len); -static void init_word_char (re_dfa_t *dfa); +static reg_errcode_t init_dfa (re_dfa_t *dfa, size_t pat_len); #ifdef RE_ENABLE_I18N static void free_charset (re_charset_t *cset); #endif /* RE_ENABLE_I18N */ @@ -33,38 +32,31 @@ static reg_errcode_t create_initial_state (re_dfa_t *dfa); #ifdef RE_ENABLE_I18N static void optimize_utf8 (re_dfa_t *dfa); #endif -struct subexp_optimize -{ - re_dfa_t *dfa; - re_token_t *nodes; - int no_sub, re_nsub; -}; -static bin_tree_t *optimize_subexps (struct subexp_optimize *so, - bin_tree_t *node, int sidx, int depth); -static reg_errcode_t analyze (re_dfa_t *dfa); -static reg_errcode_t analyze_tree (re_dfa_t *dfa, bin_tree_t *node); -static void calc_first (re_dfa_t *dfa, bin_tree_t *node); -static void calc_next (re_dfa_t *dfa, bin_tree_t *node); -static void calc_epsdest (re_dfa_t *dfa, bin_tree_t *node); -static reg_errcode_t duplicate_node_closure (re_dfa_t *dfa, int top_org_node, - int top_clone_node, int root_node, - unsigned int constraint); -static reg_errcode_t duplicate_node (int *new_idx, re_dfa_t *dfa, int org_idx, - unsigned int constraint); -static int search_duplicated_node (re_dfa_t *dfa, int org_node, +static reg_errcode_t analyze (regex_t *preg); +static reg_errcode_t preorder (bin_tree_t *root, + reg_errcode_t (fn (void *, bin_tree_t *)), + void *extra); +static reg_errcode_t postorder (bin_tree_t *root, + reg_errcode_t (fn (void *, bin_tree_t *)), + void *extra); +static reg_errcode_t optimize_subexps (void *extra, bin_tree_t *node); +static reg_errcode_t lower_subexps (void *extra, bin_tree_t *node); +static bin_tree_t *lower_subexp (reg_errcode_t *err, regex_t *preg, + bin_tree_t *node); +static reg_errcode_t calc_first (void *extra, bin_tree_t *node); +static reg_errcode_t calc_next (void *extra, bin_tree_t *node); +static reg_errcode_t link_nfa_nodes (void *extra, bin_tree_t *node); +static int duplicate_node (re_dfa_t *dfa, int org_idx, unsigned int constraint); +static int search_duplicated_node (const re_dfa_t *dfa, int org_node, unsigned int constraint); static reg_errcode_t calc_eclosure (re_dfa_t *dfa); static reg_errcode_t calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, int node, int root); -static void calc_inveclosure (re_dfa_t *dfa); +static reg_errcode_t calc_inveclosure (re_dfa_t *dfa); static int fetch_number (re_string_t *input, re_token_t *token, reg_syntax_t syntax); -static void fetch_token (re_token_t *result, re_string_t *input, - reg_syntax_t syntax); static int peek_token (re_token_t *token, re_string_t *input, - reg_syntax_t syntax); -static int peek_token_bracket (re_token_t *token, re_string_t *input, - reg_syntax_t syntax); + reg_syntax_t syntax) internal_function; static bin_tree_t *parse (re_string_t *regexp, regex_t *preg, reg_syntax_t syntax, reg_errcode_t *err); static bin_tree_t *parse_reg_exp (re_string_t *regexp, regex_t *preg, @@ -94,58 +86,40 @@ static reg_errcode_t parse_bracket_element (bracket_elem_t *elem, static reg_errcode_t parse_bracket_symbol (bracket_elem_t *elem, re_string_t *regexp, re_token_t *token); -#ifndef _LIBC -# ifdef RE_ENABLE_I18N -static reg_errcode_t build_range_exp (re_bitset_ptr_t sbcset, - re_charset_t *mbcset, int *range_alloc, - bracket_elem_t *start_elem, - bracket_elem_t *end_elem); -static reg_errcode_t build_collating_symbol (re_bitset_ptr_t sbcset, - re_charset_t *mbcset, - int *coll_sym_alloc, - const unsigned char *name); -# else /* not RE_ENABLE_I18N */ -static reg_errcode_t build_range_exp (re_bitset_ptr_t sbcset, - bracket_elem_t *start_elem, - bracket_elem_t *end_elem); -static reg_errcode_t build_collating_symbol (re_bitset_ptr_t sbcset, - const unsigned char *name); -# endif /* not RE_ENABLE_I18N */ -#endif /* not _LIBC */ #ifdef RE_ENABLE_I18N -static reg_errcode_t build_equiv_class (re_bitset_ptr_t sbcset, +static reg_errcode_t build_equiv_class (bitset_t sbcset, re_charset_t *mbcset, int *equiv_class_alloc, const unsigned char *name); -static reg_errcode_t build_charclass (unsigned RE_TRANSLATE_TYPE trans, - re_bitset_ptr_t sbcset, +static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans, + bitset_t sbcset, re_charset_t *mbcset, int *char_class_alloc, const unsigned char *class_name, reg_syntax_t syntax); #else /* not RE_ENABLE_I18N */ -static reg_errcode_t build_equiv_class (re_bitset_ptr_t sbcset, +static reg_errcode_t build_equiv_class (bitset_t sbcset, const unsigned char *name); -static reg_errcode_t build_charclass (unsigned RE_TRANSLATE_TYPE trans, - re_bitset_ptr_t sbcset, +static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans, + bitset_t sbcset, const unsigned char *class_name, reg_syntax_t syntax); #endif /* not RE_ENABLE_I18N */ static bin_tree_t *build_charclass_op (re_dfa_t *dfa, - unsigned RE_TRANSLATE_TYPE trans, + RE_TRANSLATE_TYPE trans, const unsigned char *class_name, const unsigned char *extra, int non_match, reg_errcode_t *err); static bin_tree_t *create_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, - re_token_type_t type, int index); -static bin_tree_t *re_dfa_add_tree_node (re_dfa_t *dfa, - bin_tree_t *left, bin_tree_t *right, - const re_token_t *token) - __attribute ((noinline)); + re_token_type_t type); +static bin_tree_t *create_token_tree (re_dfa_t *dfa, + bin_tree_t *left, bin_tree_t *right, + const re_token_t *token); static bin_tree_t *duplicate_tree (const bin_tree_t *src, re_dfa_t *dfa); -static void mark_opt_subexp (const bin_tree_t *src, re_dfa_t *dfa); -static void mark_opt_subexp_iter (const bin_tree_t *src, re_dfa_t *dfa, int idx); +static void free_token (re_token_t *node); +static reg_errcode_t free_tree (void *extra, bin_tree_t *node); +static reg_errcode_t mark_opt_subexp (void *extra, bin_tree_t *node); /* This table gives an error message for each of the error codes listed in regex.h. Obviously the order here has to be same as there. @@ -325,10 +299,8 @@ re_set_fastmap (char *fastmap, int icase, int ch) Compile fastmap for the initial_state INIT_STATE. */ static void -re_compile_fastmap_iter (bufp, init_state, fastmap) - regex_t *bufp; - const re_dfastate_t *init_state; - char *fastmap; +re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state, + char *fastmap) { re_dfa_t *dfa = (re_dfa_t *) bufp->buffer; int node_cnt; @@ -354,21 +326,26 @@ re_compile_fastmap_iter (bufp, init_state, fastmap) && dfa->nodes[node].type == CHARACTER && dfa->nodes[node].mb_partial) *p++ = dfa->nodes[node].opr.c; - memset (&state, 0, sizeof (state)); + memset (&state, '\0', sizeof (state)); if (mbrtowc (&wc, (const char *) buf, p - buf, &state) == p - buf - && __wcrtomb ((char *) buf, towlower (wc), &state) > 0) + && (__wcrtomb ((char *) buf, towlower (wc), &state) + != (size_t) -1)) re_set_fastmap (fastmap, 0, buf[0]); } #endif } else if (type == SIMPLE_BRACKET) { - int i, j, ch; - for (i = 0, ch = 0; i < BITSET_UINTS; ++i) - for (j = 0; j < UINT_BITS; ++j, ++ch) - if (dfa->nodes[node].opr.sbcset[i] & (1 << j)) - re_set_fastmap (fastmap, icase, ch); + int i, ch; + for (i = 0, ch = 0; i < BITSET_WORDS; ++i) + { + int j; + bitset_word_t w = dfa->nodes[node].opr.sbcset[i]; + for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch) + if (w & ((bitset_word_t) 1 << j)) + re_set_fastmap (fastmap, icase, ch); + } } #ifdef RE_ENABLE_I18N else if (type == COMPLEX_BRACKET) @@ -387,13 +364,11 @@ re_compile_fastmap_iter (bufp, init_state, fastmap) is a valid collation element, and don't catch 'b' since 'b' is the only collation element which starts from 'b'. */ - int j, ch; const int32_t *table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); - for (i = 0, ch = 0; i < BITSET_UINTS; ++i) - for (j = 0; j < UINT_BITS; ++j, ++ch) - if (table[ch] < 0) - re_set_fastmap (fastmap, icase, ch); + for (i = 0; i < SBC_MAX; ++i) + if (table[i] < 0) + re_set_fastmap (fastmap, icase, i); } # else if (dfa->mb_cur_max > 1) @@ -407,12 +382,13 @@ re_compile_fastmap_iter (bufp, init_state, fastmap) char buf[256]; mbstate_t state; memset (&state, '\0', sizeof (state)); - __wcrtomb (buf, cset->mbchars[i], &state); - re_set_fastmap (fastmap, icase, *(unsigned char *) buf); + if (__wcrtomb (buf, cset->mbchars[i], &state) != (size_t) -1) + re_set_fastmap (fastmap, icase, *(unsigned char *) buf); if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1) { - __wcrtomb (buf, towlower (cset->mbchars[i]), &state); - re_set_fastmap (fastmap, 0, *(unsigned char *) buf); + if (__wcrtomb (buf, towlower (cset->mbchars[i]), &state) + != (size_t) -1) + re_set_fastmap (fastmap, 0, *(unsigned char *) buf); } } } @@ -532,8 +508,8 @@ weak_alias (__regcomp, regcomp) size_t regerror (errcode, preg, errbuf, errbuf_size) int errcode; - const regex_t *preg; - char *errbuf; + const regex_t *__restrict preg; + char *__restrict errbuf; size_t errbuf_size; { const char *msg; @@ -579,14 +555,10 @@ weak_alias (__regerror, regerror) UTF-8 is used. Otherwise we would allocate memory just to initialize it the same all the time. UTF-8 is the preferred encoding so this is a worthwhile optimization. */ -static const bitset utf8_sb_map = +static const bitset_t utf8_sb_map = { /* Set the first 128 bits. */ -# if UINT_MAX == 0xffffffff - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff -# else -# error "Add case for new unsigned int size" -# endif + [0 ... 0x80 / BITSET_WORD_BITS - 1] = BITSET_WORD_MAX }; #endif @@ -598,16 +570,7 @@ free_dfa_content (re_dfa_t *dfa) if (dfa->nodes) for (i = 0; i < dfa->nodes_len; ++i) - { - re_token_t *node = dfa->nodes + i; -#ifdef RE_ENABLE_I18N - if (node->type == COMPLEX_BRACKET && node->duplicated == 0) - free_charset (node->opr.mbcset); - else -#endif /* RE_ENABLE_I18N */ - if (node->type == SIMPLE_BRACKET && node->duplicated == 0) - re_free (node->opr.sbcset); - } + free_token (dfa->nodes + i); re_free (dfa->nexts); for (i = 0; i < dfa->nodes_len; ++i) { @@ -744,11 +707,8 @@ libc_freeres_fn (free_mem) SYNTAX indicate regular expression's syntax. */ static reg_errcode_t -re_compile_internal (preg, pattern, length, syntax) - regex_t *preg; - const char * pattern; - int length; - reg_syntax_t syntax; +re_compile_internal (regex_t *preg, const char * pattern, size_t length, + reg_syntax_t syntax) { reg_errcode_t err = REG_NOERROR; re_dfa_t *dfa; @@ -788,10 +748,13 @@ re_compile_internal (preg, pattern, length, syntax) return err; } #ifdef DEBUG + /* Note: length+1 will not overflow since it is checked in init_dfa. */ dfa->re_str = re_malloc (char, length + 1); strncpy (dfa->re_str, pattern, length + 1); #endif + __libc_lock_init (dfa->lock); + err = re_string_construct (®exp, pattern, length, preg->translate, syntax & RE_ICASE, dfa); if (BE (err != REG_NOERROR, 0)) @@ -811,29 +774,17 @@ re_compile_internal (preg, pattern, length, syntax) if (BE (dfa->str_tree == NULL, 0)) goto re_compile_internal_free_return; + /* Analyze the tree and create the nfa. */ + err = analyze (preg); + if (BE (err != REG_NOERROR, 0)) + goto re_compile_internal_free_return; + #ifdef RE_ENABLE_I18N /* If possible, do searching in single byte encoding to speed things up. */ if (dfa->is_utf8 && !(syntax & RE_ICASE) && preg->translate == NULL) optimize_utf8 (dfa); #endif - if (preg->re_nsub > 0) - { - struct subexp_optimize so; - - so.dfa = dfa; - so.nodes = dfa->nodes; - so.no_sub = preg->no_sub; - so.re_nsub = preg->re_nsub; - dfa->str_tree = optimize_subexps (&so, dfa->str_tree, -1, 0); - } - - /* Analyze the tree and collect information which is necessary to - create the dfa. */ - err = analyze (dfa); - if (BE (err != REG_NOERROR, 0)) - goto re_compile_internal_free_return; - /* Then create the initial state of the dfa. */ err = create_initial_state (dfa); @@ -855,11 +806,9 @@ re_compile_internal (preg, pattern, length, syntax) as the initial length of some arrays. */ static reg_errcode_t -init_dfa (dfa, pat_len) - re_dfa_t *dfa; - int pat_len; +init_dfa (re_dfa_t *dfa, size_t pat_len) { - int table_size; + unsigned int table_size; #ifndef _LIBC char *codeset_name; #endif @@ -869,13 +818,15 @@ init_dfa (dfa, pat_len) /* Force allocation of str_tree_storage the first time. */ dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE; + /* Avoid overflows. */ + if (pat_len == SIZE_MAX) + return REG_ESPACE; + dfa->nodes_alloc = pat_len + 1; dfa->nodes = re_malloc (re_token_t, dfa->nodes_alloc); - dfa->states_alloc = pat_len + 1; - /* table_size = 2 ^ ceil(log pat_len) */ - for (table_size = 1; table_size > 0; table_size <<= 1) + for (table_size = 1; ; table_size <<= 1) if (table_size > pat_len) break; @@ -894,9 +845,9 @@ init_dfa (dfa, pat_len) codeset_name = nl_langinfo (CODESET); # else codeset_name = getenv ("LC_ALL"); - if (codeset_name == NULL || codeset[0] == '\0') + if (codeset_name == NULL || codeset_name[0] == '\0') codeset_name = getenv ("LC_CTYPE"); - if (codeset_name == NULL || codeset[0] == '\0') + if (codeset_name == NULL || codeset_name[0] == '\0') codeset_name = getenv ("LANG"); if (codeset_name == NULL) codeset_name = ""; @@ -922,22 +873,19 @@ init_dfa (dfa, pat_len) { int i, j, ch; - dfa->sb_char = (re_bitset_ptr_t) calloc (sizeof (bitset), 1); + dfa->sb_char = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); if (BE (dfa->sb_char == NULL, 0)) return REG_ESPACE; - /* Clear all bits by, then set those corresponding to single - byte chars. */ - bitset_empty (dfa->sb_char); - - for (i = 0, ch = 0; i < BITSET_UINTS; ++i) - for (j = 0; j < UINT_BITS; ++j, ++ch) + /* Set the bits corresponding to single byte chars. */ + for (i = 0, ch = 0; i < BITSET_WORDS; ++i) + for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch) { - wchar_t wch = __btowc (ch); + wint_t wch = __btowc (ch); if (wch != WEOF) - dfa->sb_char[i] |= 1 << j; + dfa->sb_char[i] |= (bitset_word_t) 1 << j; # ifndef _LIBC - if (isascii (ch) && wch != (wchar_t) ch) + if (isascii (ch) && wch != ch) dfa->map_notascii = 1; # endif } @@ -955,22 +903,21 @@ init_dfa (dfa, pat_len) character used by some operators like "\<", "\>", etc. */ static void -init_word_char (dfa) - re_dfa_t *dfa; +internal_function +init_word_char (re_dfa_t *dfa) { int i, j, ch; dfa->word_ops_used = 1; - for (i = 0, ch = 0; i < BITSET_UINTS; ++i) - for (j = 0; j < UINT_BITS; ++j, ++ch) + for (i = 0, ch = 0; i < BITSET_WORDS; ++i) + for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch) if (isalnum (ch) || ch == '_') - dfa->word_char[i] |= 1 << j; + dfa->word_char[i] |= (bitset_word_t) 1 << j; } /* Free the work area which are only used while compiling. */ static void -free_workarea_compile (preg) - regex_t *preg; +free_workarea_compile (regex_t *preg) { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; bin_tree_storage_t *storage, *next; @@ -989,8 +936,7 @@ free_workarea_compile (preg) /* Create initial states for all contexts. */ static reg_errcode_t -create_initial_state (dfa) - re_dfa_t *dfa; +create_initial_state (re_dfa_t *dfa) { int first, i; reg_errcode_t err; @@ -998,7 +944,7 @@ create_initial_state (dfa) /* Initial states have the epsilon closure of the node which is the first node of the regular expression. */ - first = dfa->str_tree->first; + first = dfa->str_tree->first->node_idx; dfa->init_node = first; err = re_node_set_init_copy (&init_nodes, dfa->eclosures + first); if (BE (err != REG_NOERROR, 0)) @@ -1072,8 +1018,7 @@ create_initial_state (dfa) DFA nodes where needed. */ static void -optimize_utf8 (dfa) - re_dfa_t *dfa; +optimize_utf8 (re_dfa_t *dfa) { int node, i, mb_chars = 0, has_period = 0; @@ -1104,18 +1049,20 @@ optimize_utf8 (dfa) case OP_ALT: case END_OF_RE: case OP_DUP_ASTERISK: - case OP_DUP_QUESTION: case OP_OPEN_SUBEXP: case OP_CLOSE_SUBEXP: break; + case COMPLEX_BRACKET: + return; case SIMPLE_BRACKET: - /* Just double check. */ - for (i = 0x80 / UINT_BITS; i < BITSET_UINTS; ++i) + /* Just double check. The non-ASCII range starts at 0x80. */ + assert (0x80 % BITSET_WORD_BITS == 0); + for (i = 0x80 / BITSET_WORD_BITS; i < BITSET_WORDS; ++i) if (dfa->nodes[node].opr.sbcset[i]) return; break; default: - return; + abort (); } if (mb_chars || has_period) @@ -1135,90 +1082,13 @@ optimize_utf8 (dfa) } #endif -static bin_tree_t * -optimize_subexps (so, node, sidx, depth) - struct subexp_optimize *so; - bin_tree_t *node; - int sidx, depth; -{ - int idx, new_depth, new_sidx; - bin_tree_t *ret; - if (node == NULL) - return NULL; - - new_depth = 0; - new_sidx = sidx; - if ((depth & 1) && node->type == CONCAT - && node->right && node->right->type == 0 - && so->nodes[idx = node->right->node_idx].type == OP_CLOSE_SUBEXP) - { - new_depth = depth + 1; - if (new_depth == 2 - || (so->nodes[idx].opr.idx < 8 * sizeof (so->dfa->used_bkref_map) - && so->dfa->used_bkref_map & (1 << so->nodes[idx].opr.idx))) - new_sidx = so->nodes[idx].opr.idx; - } - node->left = optimize_subexps (so, node->left, new_sidx, new_depth); - new_depth = (depth & 1) == 0 && node->type == CONCAT - && node->left && node->left->type == 0 - && so->nodes[node->left->node_idx].type == OP_OPEN_SUBEXP - ? depth + 1 : 0; - node->right = optimize_subexps (so, node->right, sidx, new_depth); - - if (node->type != CONCAT) - return node; - if ((depth & 1) == 0 - && node->left - && node->left->type == 0 - && so->nodes[idx = node->left->node_idx].type == OP_OPEN_SUBEXP) - ret = node->right; - else if ((depth & 1) - && node->right - && node->right->type == 0 - && so->nodes[idx = node->right->node_idx].type == OP_CLOSE_SUBEXP) - ret = node->left; - else - return node; - - if (so->nodes[idx].opr.idx < 8 * sizeof (so->dfa->used_bkref_map) - && so->dfa->used_bkref_map & (1 << so->nodes[idx].opr.idx)) - return node; - - if (!so->no_sub) - { - int i; - - if (depth < 2) - return node; - - if (so->dfa->subexp_map == NULL) - { - so->dfa->subexp_map = re_malloc (int, so->re_nsub); - if (so->dfa->subexp_map == NULL) - return node; - - for (i = 0; i < so->re_nsub; i++) - so->dfa->subexp_map[i] = i; - } - - i = so->nodes[idx].opr.idx; - assert (sidx < i); - so->dfa->subexp_map[i] = sidx; - } - - so->nodes[idx].type = OP_DELETED_SUBEXP; - ret->parent = node->parent; - return ret; -} - /* Analyze the structure tree, and calculate "first", "next", "edest", "eclosure", and "inveclosure". */ static reg_errcode_t -analyze (dfa) - re_dfa_t *dfa; +analyze (regex_t *preg) { - int i; + re_dfa_t *dfa = (re_dfa_t *) preg->buffer; reg_errcode_t ret; /* Allocate arrays. */ @@ -1226,225 +1096,310 @@ analyze (dfa) dfa->org_indices = re_malloc (int, dfa->nodes_alloc); dfa->edests = re_malloc (re_node_set, dfa->nodes_alloc); dfa->eclosures = re_malloc (re_node_set, dfa->nodes_alloc); - dfa->inveclosures = re_malloc (re_node_set, dfa->nodes_alloc); if (BE (dfa->nexts == NULL || dfa->org_indices == NULL || dfa->edests == NULL - || dfa->eclosures == NULL || dfa->inveclosures == NULL, 0)) + || dfa->eclosures == NULL, 0)) return REG_ESPACE; - /* Initialize them. */ - for (i = 0; i < dfa->nodes_len; ++i) + + dfa->subexp_map = re_malloc (int, preg->re_nsub); + if (dfa->subexp_map != NULL) { - dfa->nexts[i] = -1; - re_node_set_init_empty (dfa->edests + i); - re_node_set_init_empty (dfa->eclosures + i); - re_node_set_init_empty (dfa->inveclosures + i); + int i; + for (i = 0; i < preg->re_nsub; i++) + dfa->subexp_map[i] = i; + preorder (dfa->str_tree, optimize_subexps, dfa); + for (i = 0; i < preg->re_nsub; i++) + if (dfa->subexp_map[i] != i) + break; + if (i == preg->re_nsub) + { + free (dfa->subexp_map); + dfa->subexp_map = NULL; + } } - ret = analyze_tree (dfa, dfa->str_tree); - if (BE (ret == REG_NOERROR, 1)) + ret = postorder (dfa->str_tree, lower_subexps, preg); + if (BE (ret != REG_NOERROR, 0)) + return ret; + ret = postorder (dfa->str_tree, calc_first, dfa); + if (BE (ret != REG_NOERROR, 0)) + return ret; + preorder (dfa->str_tree, calc_next, dfa); + ret = preorder (dfa->str_tree, link_nfa_nodes, dfa); + if (BE (ret != REG_NOERROR, 0)) + return ret; + ret = calc_eclosure (dfa); + if (BE (ret != REG_NOERROR, 0)) + return ret; + + /* We only need this during the prune_impossible_nodes pass in regexec.c; + skip it if p_i_n will not run, as calc_inveclosure can be quadratic. */ + if ((!preg->no_sub && preg->re_nsub > 0 && dfa->has_plural_match) + || dfa->nbackref) { - ret = calc_eclosure (dfa); - if (ret == REG_NOERROR) - calc_inveclosure (dfa); + dfa->inveclosures = re_malloc (re_node_set, dfa->nodes_len); + if (BE (dfa->inveclosures == NULL, 0)) + return REG_ESPACE; + ret = calc_inveclosure (dfa); } + return ret; } -/* Helper functions for analyze. - This function calculate "first", "next", and "edest" for the subtree - whose root is NODE. */ +/* Our parse trees are very unbalanced, so we cannot use a stack to + implement parse tree visits. Instead, we use parent pointers and + some hairy code in these two functions. */ +static reg_errcode_t +postorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)), + void *extra) +{ + bin_tree_t *node, *prev; + + for (node = root; ; ) + { + /* Descend down the tree, preferably to the left (or to the right + if that's the only child). */ + while (node->left || node->right) + if (node->left) + node = node->left; + else + node = node->right; + + do + { + reg_errcode_t err = fn (extra, node); + if (BE (err != REG_NOERROR, 0)) + return err; + if (node->parent == NULL) + return REG_NOERROR; + prev = node; + node = node->parent; + } + /* Go up while we have a node that is reached from the right. */ + while (node->right == prev || node->right == NULL); + node = node->right; + } +} static reg_errcode_t -analyze_tree (dfa, node) - re_dfa_t *dfa; - bin_tree_t *node; +preorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)), + void *extra) { - reg_errcode_t ret; - if (node->first == -1) - calc_first (dfa, node); - if (node->next == -1) - calc_next (dfa, node); - calc_epsdest (dfa, node); + bin_tree_t *node; - /* Calculate "first" etc. for the left child. */ - if (node->left != NULL) + for (node = root; ; ) { - ret = analyze_tree (dfa, node->left); - if (BE (ret != REG_NOERROR, 0)) - return ret; + reg_errcode_t err = fn (extra, node); + if (BE (err != REG_NOERROR, 0)) + return err; + + /* Go to the left node, or up and to the right. */ + if (node->left) + node = node->left; + else + { + bin_tree_t *prev = NULL; + while (node->right == prev || node->right == NULL) + { + prev = node; + node = node->parent; + if (!node) + return REG_NOERROR; + } + node = node->right; + } } - /* Calculate "first" etc. for the right child. */ - if (node->right != NULL) +} + +/* Optimization pass: if a SUBEXP is entirely contained, strip it and tell + re_search_internal to map the inner one's opr.idx to this one's. Adjust + backreferences as well. Requires a preorder visit. */ +static reg_errcode_t +optimize_subexps (void *extra, bin_tree_t *node) +{ + re_dfa_t *dfa = (re_dfa_t *) extra; + + if (node->token.type == OP_BACK_REF && dfa->subexp_map) { - ret = analyze_tree (dfa, node->right); - if (BE (ret != REG_NOERROR, 0)) - return ret; + int idx = node->token.opr.idx; + node->token.opr.idx = dfa->subexp_map[idx]; + dfa->used_bkref_map |= 1 << node->token.opr.idx; + } + + else if (node->token.type == SUBEXP + && node->left && node->left->token.type == SUBEXP) + { + int other_idx = node->left->token.opr.idx; + + node->left = node->left->left; + if (node->left) + node->left->parent = node; + + dfa->subexp_map[other_idx] = dfa->subexp_map[node->token.opr.idx]; + if (other_idx < BITSET_WORD_BITS) + dfa->used_bkref_map &= ~((bitset_word_t) 1 << other_idx); } + return REG_NOERROR; } -/* Calculate "first" for the node NODE. */ -static void -calc_first (dfa, node) - re_dfa_t *dfa; - bin_tree_t *node; +/* Lowering pass: Turn each SUBEXP node into the appropriate concatenation + of OP_OPEN_SUBEXP, the body of the SUBEXP (if any) and OP_CLOSE_SUBEXP. */ +static reg_errcode_t +lower_subexps (void *extra, bin_tree_t *node) { - int idx, type; - idx = node->node_idx; - type = (node->type == 0) ? dfa->nodes[idx].type : node->type; + regex_t *preg = (regex_t *) extra; + reg_errcode_t err = REG_NOERROR; - switch (type) + if (node->left && node->left->token.type == SUBEXP) { -#ifdef DEBUG - case OP_OPEN_BRACKET: - case OP_CLOSE_BRACKET: - case OP_OPEN_DUP_NUM: - case OP_CLOSE_DUP_NUM: - case OP_DUP_PLUS: - case OP_NON_MATCH_LIST: - case OP_OPEN_COLL_ELEM: - case OP_CLOSE_COLL_ELEM: - case OP_OPEN_EQUIV_CLASS: - case OP_CLOSE_EQUIV_CLASS: - case OP_OPEN_CHAR_CLASS: - case OP_CLOSE_CHAR_CLASS: - /* These must not appear here. */ - assert (0); -#endif - case END_OF_RE: - case CHARACTER: - case OP_PERIOD: - case OP_DUP_ASTERISK: - case OP_DUP_QUESTION: -#ifdef RE_ENABLE_I18N - case OP_UTF8_PERIOD: - case COMPLEX_BRACKET: -#endif /* RE_ENABLE_I18N */ - case SIMPLE_BRACKET: - case OP_BACK_REF: - case ANCHOR: - case OP_OPEN_SUBEXP: - case OP_CLOSE_SUBEXP: - node->first = idx; - break; - case OP_ALT: - node->first = idx; - break; - /* else fall through */ - default: -#ifdef DEBUG - assert (node->left != NULL); -#endif - if (node->left->first == -1) - calc_first (dfa, node->left); - node->first = node->left->first; - break; + node->left = lower_subexp (&err, preg, node->left); + if (node->left) + node->left->parent = node; + } + if (node->right && node->right->token.type == SUBEXP) + { + node->right = lower_subexp (&err, preg, node->right); + if (node->right) + node->right->parent = node; } -} -/* Calculate "next" for the node NODE. */ + return err; +} -static void -calc_next (dfa, node) - re_dfa_t *dfa; - bin_tree_t *node; +static bin_tree_t * +lower_subexp (reg_errcode_t *err, regex_t *preg, bin_tree_t *node) { - int idx, type; - bin_tree_t *parent = node->parent; - if (parent == NULL) + re_dfa_t *dfa = (re_dfa_t *) preg->buffer; + bin_tree_t *body = node->left; + bin_tree_t *op, *cls, *tree1, *tree; + + if (preg->no_sub + /* We do not optimize empty subexpressions, because otherwise we may + have bad CONCAT nodes with NULL children. This is obviously not + very common, so we do not lose much. An example that triggers + this case is the sed "script" /\(\)/x. */ + && node->left != NULL + && (node->token.opr.idx >= BITSET_WORD_BITS + || !(dfa->used_bkref_map + & ((bitset_word_t) 1 << node->token.opr.idx)))) + return node->left; + + /* Convert the SUBEXP node to the concatenation of an + OP_OPEN_SUBEXP, the contents, and an OP_CLOSE_SUBEXP. */ + op = create_tree (dfa, NULL, NULL, OP_OPEN_SUBEXP); + cls = create_tree (dfa, NULL, NULL, OP_CLOSE_SUBEXP); + tree1 = body ? create_tree (dfa, body, cls, CONCAT) : cls; + tree = create_tree (dfa, op, tree1, CONCAT); + if (BE (tree == NULL || tree1 == NULL || op == NULL || cls == NULL, 0)) { - node->next = -1; - idx = node->node_idx; - if (node->type == 0) - dfa->nexts[idx] = node->next; - return; + *err = REG_ESPACE; + return NULL; } - idx = parent->node_idx; - type = (parent->type == 0) ? dfa->nodes[idx].type : parent->type; + op->token.opr.idx = cls->token.opr.idx = node->token.opr.idx; + op->token.opt_subexp = cls->token.opt_subexp = node->token.opt_subexp; + return tree; +} + +/* Pass 1 in building the NFA: compute FIRST and create unlinked automaton + nodes. Requires a postorder visit. */ +static reg_errcode_t +calc_first (void *extra, bin_tree_t *node) +{ + re_dfa_t *dfa = (re_dfa_t *) extra; + if (node->token.type == CONCAT) + { + node->first = node->left->first; + node->node_idx = node->left->node_idx; + } + else + { + node->first = node; + node->node_idx = re_dfa_add_node (dfa, node->token); + if (BE (node->node_idx == -1, 0)) + return REG_ESPACE; + } + return REG_NOERROR; +} - switch (type) +/* Pass 2: compute NEXT on the tree. Preorder visit. */ +static reg_errcode_t +calc_next (void *extra, bin_tree_t *node) +{ + switch (node->token.type) { case OP_DUP_ASTERISK: - node->next = idx; + node->left->next = node; break; case CONCAT: - if (parent->left == node) - { - if (parent->right->first == -1) - calc_first (dfa, parent->right); - node->next = parent->right->first; - break; - } - /* else fall through */ + node->left->next = node->right->first; + node->right->next = node->next; + break; default: - if (parent->next == -1) - calc_next (dfa, parent); - node->next = parent->next; + if (node->left) + node->left->next = node->next; + if (node->right) + node->right->next = node->next; break; } - idx = node->node_idx; - if (node->type == 0) - dfa->nexts[idx] = node->next; + return REG_NOERROR; } -/* Calculate "edest" for the node NODE. */ - -static void -calc_epsdest (dfa, node) - re_dfa_t *dfa; - bin_tree_t *node; +/* Pass 3: link all DFA nodes to their NEXT node (any order will do). */ +static reg_errcode_t +link_nfa_nodes (void *extra, bin_tree_t *node) { - int idx; - idx = node->node_idx; - if (node->type == 0) + re_dfa_t *dfa = (re_dfa_t *) extra; + int idx = node->node_idx; + reg_errcode_t err = REG_NOERROR; + + switch (node->token.type) { - if (dfa->nodes[idx].type == OP_DUP_ASTERISK - || dfa->nodes[idx].type == OP_DUP_QUESTION) - { - if (node->left->first == -1) - calc_first (dfa, node->left); - if (node->next == -1) - calc_next (dfa, node); - re_node_set_init_2 (dfa->edests + idx, node->left->first, - node->next); - } - else if (dfa->nodes[idx].type == OP_ALT) - { - int left, right; - if (node->left != NULL) - { - if (node->left->first == -1) - calc_first (dfa, node->left); - left = node->left->first; - } - else - { - if (node->next == -1) - calc_next (dfa, node); - left = node->next; - } - if (node->right != NULL) - { - if (node->right->first == -1) - calc_first (dfa, node->right); - right = node->right->first; - } - else - { - if (node->next == -1) - calc_next (dfa, node); - right = node->next; - } - re_node_set_init_2 (dfa->edests + idx, left, right); - } - else if (dfa->nodes[idx].type == ANCHOR - || dfa->nodes[idx].type == OP_OPEN_SUBEXP - || dfa->nodes[idx].type == OP_CLOSE_SUBEXP - || dfa->nodes[idx].type == OP_BACK_REF) - re_node_set_init_1 (dfa->edests + idx, node->next); - else - assert (!IS_EPSILON_NODE (dfa->nodes[idx].type)); + case CONCAT: + break; + + case END_OF_RE: + assert (node->next == NULL); + break; + + case OP_DUP_ASTERISK: + case OP_ALT: + { + int left, right; + dfa->has_plural_match = 1; + if (node->left != NULL) + left = node->left->first->node_idx; + else + left = node->next->node_idx; + if (node->right != NULL) + right = node->right->first->node_idx; + else + right = node->next->node_idx; + assert (left > -1); + assert (right > -1); + err = re_node_set_init_2 (dfa->edests + idx, left, right); + } + break; + + case ANCHOR: + case OP_OPEN_SUBEXP: + case OP_CLOSE_SUBEXP: + err = re_node_set_init_1 (dfa->edests + idx, node->next->node_idx); + break; + + case OP_BACK_REF: + dfa->nexts[idx] = node->next->node_idx; + if (node->token.type == OP_BACK_REF) + re_node_set_init_1 (dfa->edests + idx, dfa->nexts[idx]); + break; + + default: + assert (!IS_EPSILON_NODE (node->token.type)); + dfa->nexts[idx] = node->next->node_idx; + break; } + + return err; } /* Duplicate the epsilon closure of the node ROOT_NODE. @@ -1452,13 +1407,10 @@ calc_epsdest (dfa, node) to their own constraint. */ static reg_errcode_t -duplicate_node_closure (dfa, top_org_node, top_clone_node, root_node, - init_constraint) - re_dfa_t *dfa; - int top_org_node, top_clone_node, root_node; - unsigned int init_constraint; +internal_function +duplicate_node_closure (re_dfa_t *dfa, int top_org_node, int top_clone_node, + int root_node, unsigned int init_constraint) { - reg_errcode_t err; int org_node, clone_node, ret; unsigned int constraint = init_constraint; for (org_node = top_org_node, clone_node = top_clone_node;;) @@ -1472,9 +1424,9 @@ duplicate_node_closure (dfa, top_org_node, top_clone_node, root_node, edests of the back reference. */ org_dest = dfa->nexts[org_node]; re_node_set_empty (dfa->edests + clone_node); - err = duplicate_node (&clone_dest, dfa, org_dest, constraint); - if (BE (err != REG_NOERROR, 0)) - return err; + clone_dest = duplicate_node (dfa, org_dest, constraint); + if (BE (clone_dest == -1, 0)) + return REG_ESPACE; dfa->nexts[clone_node] = dfa->nexts[org_node]; ret = re_node_set_insert (dfa->edests + clone_node, clone_dest); if (BE (ret < 0, 0)) @@ -1510,9 +1462,9 @@ duplicate_node_closure (dfa, top_org_node, top_clone_node, root_node, } constraint |= dfa->nodes[org_node].opr.ctx_type; } - err = duplicate_node (&clone_dest, dfa, org_dest, constraint); - if (BE (err != REG_NOERROR, 0)) - return err; + clone_dest = duplicate_node (dfa, org_dest, constraint); + if (BE (clone_dest == -1, 0)) + return REG_ESPACE; ret = re_node_set_insert (dfa->edests + clone_node, clone_dest); if (BE (ret < 0, 0)) return REG_ESPACE; @@ -1520,7 +1472,7 @@ duplicate_node_closure (dfa, top_org_node, top_clone_node, root_node, else /* dfa->edests[org_node].nelem == 2 */ { /* In case of the node can epsilon-transit, and it has two - destinations. E.g. '|', '*', '+', '?'. */ + destinations. In the bin_tree_t and DFA, that's '|' and '*'. */ org_dest = dfa->edests[org_node].elems[0]; re_node_set_empty (dfa->edests + clone_node); /* Search for a duplicated node which satisfies the constraint. */ @@ -1528,9 +1480,10 @@ duplicate_node_closure (dfa, top_org_node, top_clone_node, root_node, if (clone_dest == -1) { /* There are no such a duplicated node, create a new one. */ - err = duplicate_node (&clone_dest, dfa, org_dest, constraint); - if (BE (err != REG_NOERROR, 0)) - return err; + reg_errcode_t err; + clone_dest = duplicate_node (dfa, org_dest, constraint); + if (BE (clone_dest == -1, 0)) + return REG_ESPACE; ret = re_node_set_insert (dfa->edests + clone_node, clone_dest); if (BE (ret < 0, 0)) return REG_ESPACE; @@ -1549,9 +1502,9 @@ duplicate_node_closure (dfa, top_org_node, top_clone_node, root_node, } org_dest = dfa->edests[org_node].elems[1]; - err = duplicate_node (&clone_dest, dfa, org_dest, constraint); - if (BE (err != REG_NOERROR, 0)) - return err; + clone_dest = duplicate_node (dfa, org_dest, constraint); + if (BE (clone_dest == -1, 0)) + return REG_ESPACE; ret = re_node_set_insert (dfa->edests + clone_node, clone_dest); if (BE (ret < 0, 0)) return REG_ESPACE; @@ -1566,10 +1519,8 @@ duplicate_node_closure (dfa, top_org_node, top_clone_node, root_node, satisfies the constraint CONSTRAINT. */ static int -search_duplicated_node (dfa, org_node, constraint) - re_dfa_t *dfa; - int org_node; - unsigned int constraint; +search_duplicated_node (const re_dfa_t *dfa, int org_node, + unsigned int constraint) { int idx; for (idx = dfa->nodes_len - 1; dfa->nodes[idx].duplicated && idx > 0; --idx) @@ -1582,54 +1533,51 @@ search_duplicated_node (dfa, org_node, constraint) } /* Duplicate the node whose index is ORG_IDX and set the constraint CONSTRAINT. - The new index will be stored in NEW_IDX and return REG_NOERROR if succeeded, - otherwise return the error code. */ + Return the index of the new node, or -1 if insufficient storage is + available. */ -static reg_errcode_t -duplicate_node (new_idx, dfa, org_idx, constraint) - re_dfa_t *dfa; - int *new_idx, org_idx; - unsigned int constraint; +static int +duplicate_node (re_dfa_t *dfa, int org_idx, unsigned int constraint) { - int dup_idx = re_dfa_add_node (dfa, dfa->nodes[org_idx], 1); - if (BE (dup_idx == -1, 0)) - return REG_ESPACE; - dfa->nodes[dup_idx].constraint = constraint; - if (dfa->nodes[org_idx].type == ANCHOR) - dfa->nodes[dup_idx].constraint |= dfa->nodes[org_idx].opr.ctx_type; - dfa->nodes[dup_idx].duplicated = 1; - re_node_set_init_empty (dfa->edests + dup_idx); - re_node_set_init_empty (dfa->eclosures + dup_idx); - re_node_set_init_empty (dfa->inveclosures + dup_idx); - - /* Store the index of the original node. */ - dfa->org_indices[dup_idx] = org_idx; - *new_idx = dup_idx; - return REG_NOERROR; + int dup_idx = re_dfa_add_node (dfa, dfa->nodes[org_idx]); + if (BE (dup_idx != -1, 1)) + { + dfa->nodes[dup_idx].constraint = constraint; + if (dfa->nodes[org_idx].type == ANCHOR) + dfa->nodes[dup_idx].constraint |= dfa->nodes[org_idx].opr.ctx_type; + dfa->nodes[dup_idx].duplicated = 1; + + /* Store the index of the original node. */ + dfa->org_indices[dup_idx] = org_idx; + } + return dup_idx; } -static void -calc_inveclosure (dfa) - re_dfa_t *dfa; +static reg_errcode_t +calc_inveclosure (re_dfa_t *dfa) { - int src, idx, dest; + int src, idx, ret; + for (idx = 0; idx < dfa->nodes_len; ++idx) + re_node_set_init_empty (dfa->inveclosures + idx); + for (src = 0; src < dfa->nodes_len; ++src) { - if (dfa->nodes[src].type == OP_DELETED_SUBEXP) - continue; + int *elems = dfa->eclosures[src].elems; for (idx = 0; idx < dfa->eclosures[src].nelem; ++idx) { - dest = dfa->eclosures[src].elems[idx]; - re_node_set_insert_last (dfa->inveclosures + dest, src); + ret = re_node_set_insert_last (dfa->inveclosures + elems[idx], src); + if (BE (ret == -1, 0)) + return REG_ESPACE; } } + + return REG_NOERROR; } /* Calculate "eclosure" for all the node in DFA. */ static reg_errcode_t -calc_eclosure (dfa) - re_dfa_t *dfa; +calc_eclosure (re_dfa_t *dfa) { int node_idx, incomplete; #ifdef DEBUG @@ -1652,8 +1600,6 @@ calc_eclosure (dfa) #ifdef DEBUG assert (dfa->eclosures[node_idx].nelem != -1); #endif - if (dfa->nodes[node_idx].type == OP_DELETED_SUBEXP) - continue; /* If we have already calculated, skip it. */ if (dfa->eclosures[node_idx].nelem != 0) @@ -1675,10 +1621,7 @@ calc_eclosure (dfa) /* Calculate epsilon closure of NODE. */ static reg_errcode_t -calc_eclosure_iter (new_set, dfa, node, root) - re_node_set *new_set; - re_dfa_t *dfa; - int node, root; +calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, int node, int root) { reg_errcode_t err; unsigned int constraint; @@ -1701,8 +1644,6 @@ calc_eclosure_iter (new_set, dfa, node, root) && dfa->edests[node].nelem && !dfa->nodes[dfa->edests[node].elems[0]].duplicated) { - int org_node, cur_node; - org_node = cur_node = node; err = duplicate_node_closure (dfa, node, node, node, constraint); if (BE (err != REG_NOERROR, 0)) return err; @@ -1758,10 +1699,8 @@ calc_eclosure_iter (new_set, dfa, node, root) We must not use this function inside bracket expressions. */ static void -fetch_token (result, input, syntax) - re_token_t *result; - re_string_t *input; - reg_syntax_t syntax; +internal_function +fetch_token (re_token_t *result, re_string_t *input, reg_syntax_t syntax) { re_string_skip_bytes (input, peek_token (result, input, syntax)); } @@ -1770,10 +1709,8 @@ fetch_token (result, input, syntax) We must not use this function inside bracket expressions. */ static int -peek_token (token, input, syntax) - re_token_t *token; - re_string_t *input; - reg_syntax_t syntax; +internal_function +peek_token (re_token_t *token, re_string_t *input, reg_syntax_t syntax) { unsigned char c; @@ -1859,7 +1796,7 @@ peek_token (token, input, syntax) if (!(syntax & RE_NO_GNU_OPS)) { token->type = ANCHOR; - token->opr.ctx_type = INSIDE_WORD; + token->opr.ctx_type = NOT_WORD_DELIM; } break; case 'w': @@ -2011,10 +1948,8 @@ peek_token (token, input, syntax) We must not use this function out of bracket expressions. */ static int -peek_token_bracket (token, input, syntax) - re_token_t *token; - re_string_t *input; - reg_syntax_t syntax; +internal_function +peek_token_bracket (re_token_t *token, re_string_t *input, reg_syntax_t syntax) { unsigned char c; if (re_string_eoi (input)) @@ -2110,11 +2045,8 @@ peek_token_bracket (token, input, syntax) EOR means end of regular expression. */ static bin_tree_t * -parse (regexp, preg, syntax, err) - re_string_t *regexp; - regex_t *preg; - reg_syntax_t syntax; - reg_errcode_t *err; +parse (re_string_t *regexp, regex_t *preg, reg_syntax_t syntax, + reg_errcode_t *err) { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; bin_tree_t *tree, *eor, *root; @@ -2124,9 +2056,9 @@ parse (regexp, preg, syntax, err) tree = parse_reg_exp (regexp, preg, ¤t_token, syntax, 0, err); if (BE (*err != REG_NOERROR && tree == NULL, 0)) return NULL; - eor = re_dfa_add_tree_node (dfa, NULL, NULL, ¤t_token); + eor = create_tree (dfa, NULL, NULL, END_OF_RE); if (tree != NULL) - root = create_tree (dfa, tree, eor, CONCAT, 0); + root = create_tree (dfa, tree, eor, CONCAT); else root = eor; if (BE (eor == NULL || root == NULL, 0)) @@ -2147,13 +2079,8 @@ parse (regexp, preg, syntax, err) ALT means alternative, which represents the operator `|'. */ static bin_tree_t * -parse_reg_exp (regexp, preg, token, syntax, nest, err) - re_string_t *regexp; - regex_t *preg; - re_token_t *token; - reg_syntax_t syntax; - int nest; - reg_errcode_t *err; +parse_reg_exp (re_string_t *regexp, regex_t *preg, re_token_t *token, + reg_syntax_t syntax, int nest, reg_errcode_t *err) { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; bin_tree_t *tree, *branch = NULL; @@ -2163,7 +2090,6 @@ parse_reg_exp (regexp, preg, token, syntax, nest, err) while (token->type == OP_ALT) { - re_token_t alt_token = *token; fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE); if (token->type != OP_ALT && token->type != END_OF_RE && (nest == 0 || token->type != OP_CLOSE_SUBEXP)) @@ -2174,13 +2100,12 @@ parse_reg_exp (regexp, preg, token, syntax, nest, err) } else branch = NULL; - tree = re_dfa_add_tree_node (dfa, tree, branch, &alt_token); + tree = create_tree (dfa, tree, branch, OP_ALT); if (BE (tree == NULL, 0)) { *err = REG_ESPACE; return NULL; } - dfa->has_plural_match = 1; } return tree; } @@ -2195,13 +2120,8 @@ parse_reg_exp (regexp, preg, token, syntax, nest, err) CAT means concatenation. */ static bin_tree_t * -parse_branch (regexp, preg, token, syntax, nest, err) - re_string_t *regexp; - regex_t *preg; - re_token_t *token; - reg_syntax_t syntax; - int nest; - reg_errcode_t *err; +parse_branch (re_string_t *regexp, regex_t *preg, re_token_t *token, + reg_syntax_t syntax, int nest, reg_errcode_t *err) { bin_tree_t *tree, *exp; re_dfa_t *dfa = (re_dfa_t *) preg->buffer; @@ -2219,7 +2139,7 @@ parse_branch (regexp, preg, token, syntax, nest, err) } if (tree != NULL && exp != NULL) { - tree = create_tree (dfa, tree, exp, CONCAT, 0); + tree = create_tree (dfa, tree, exp, CONCAT); if (tree == NULL) { *err = REG_ESPACE; @@ -2240,20 +2160,15 @@ parse_branch (regexp, preg, token, syntax, nest, err) */ static bin_tree_t * -parse_expression (regexp, preg, token, syntax, nest, err) - re_string_t *regexp; - regex_t *preg; - re_token_t *token; - reg_syntax_t syntax; - int nest; - reg_errcode_t *err; +parse_expression (re_string_t *regexp, regex_t *preg, re_token_t *token, + reg_syntax_t syntax, int nest, reg_errcode_t *err) { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; bin_tree_t *tree; switch (token->type) { case CHARACTER: - tree = re_dfa_add_tree_node (dfa, NULL, NULL, token); + tree = create_token_tree (dfa, NULL, NULL, token); if (BE (tree == NULL, 0)) { *err = REG_ESPACE; @@ -2267,8 +2182,8 @@ parse_expression (regexp, preg, token, syntax, nest, err) { bin_tree_t *mbc_remain; fetch_token (token, regexp, syntax); - mbc_remain = re_dfa_add_tree_node (dfa, NULL, NULL, token); - tree = create_tree (dfa, tree, mbc_remain, CONCAT, 0); + mbc_remain = create_token_tree (dfa, NULL, NULL, token); + tree = create_tree (dfa, tree, mbc_remain, CONCAT); if (BE (mbc_remain == NULL || tree == NULL, 0)) { *err = REG_ESPACE; @@ -2295,7 +2210,7 @@ parse_expression (regexp, preg, token, syntax, nest, err) return NULL; } dfa->used_bkref_map |= 1 << token->opr.idx; - tree = re_dfa_add_tree_node (dfa, NULL, NULL, token); + tree = create_token_tree (dfa, NULL, NULL, token); if (BE (tree == NULL, 0)) { *err = REG_ESPACE; @@ -2340,7 +2255,7 @@ parse_expression (regexp, preg, token, syntax, nest, err) token->type = CHARACTER; /* mb_partial and word_char bits should be initialized already by peek_token. */ - tree = re_dfa_add_tree_node (dfa, NULL, NULL, token); + tree = create_token_tree (dfa, NULL, NULL, token); if (BE (tree == NULL, 0)) { *err = REG_ESPACE; @@ -2349,18 +2264,27 @@ parse_expression (regexp, preg, token, syntax, nest, err) break; case ANCHOR: if ((token->opr.ctx_type - & (WORD_DELIM | INSIDE_WORD | WORD_FIRST | WORD_LAST)) + & (WORD_DELIM | NOT_WORD_DELIM | WORD_FIRST | WORD_LAST)) && dfa->word_ops_used == 0) init_word_char (dfa); - if (token->opr.ctx_type == WORD_DELIM) + if (token->opr.ctx_type == WORD_DELIM + || token->opr.ctx_type == NOT_WORD_DELIM) { bin_tree_t *tree_first, *tree_last; - token->opr.ctx_type = WORD_FIRST; - tree_first = re_dfa_add_tree_node (dfa, NULL, NULL, token); - token->opr.ctx_type = WORD_LAST; - tree_last = re_dfa_add_tree_node (dfa, NULL, NULL, token); - token->type = OP_ALT; - tree = re_dfa_add_tree_node (dfa, tree_first, tree_last, token); + if (token->opr.ctx_type == WORD_DELIM) + { + token->opr.ctx_type = WORD_FIRST; + tree_first = create_token_tree (dfa, NULL, NULL, token); + token->opr.ctx_type = WORD_LAST; + } + else + { + token->opr.ctx_type = INSIDE_WORD; + tree_first = create_token_tree (dfa, NULL, NULL, token); + token->opr.ctx_type = INSIDE_NOTWORD; + } + tree_last = create_token_tree (dfa, NULL, NULL, token); + tree = create_tree (dfa, tree_first, tree_last, OP_ALT); if (BE (tree_first == NULL || tree_last == NULL || tree == NULL, 0)) { *err = REG_ESPACE; @@ -2369,7 +2293,7 @@ parse_expression (regexp, preg, token, syntax, nest, err) } else { - tree = re_dfa_add_tree_node (dfa, NULL, NULL, token); + tree = create_token_tree (dfa, NULL, NULL, token); if (BE (tree == NULL, 0)) { *err = REG_ESPACE; @@ -2383,7 +2307,7 @@ parse_expression (regexp, preg, token, syntax, nest, err) fetch_token (token, regexp, syntax); return tree; case OP_PERIOD: - tree = re_dfa_add_tree_node (dfa, NULL, NULL, token); + tree = create_token_tree (dfa, NULL, NULL, token); if (BE (tree == NULL, 0)) { *err = REG_ESPACE; @@ -2439,7 +2363,6 @@ parse_expression (regexp, preg, token, syntax, nest, err) *err = REG_BADRPT; return NULL; } - dfa->has_plural_match = 1; } return tree; @@ -2453,26 +2376,14 @@ parse_expression (regexp, preg, token, syntax, nest, err) */ static bin_tree_t * -parse_sub_exp (regexp, preg, token, syntax, nest, err) - re_string_t *regexp; - regex_t *preg; - re_token_t *token; - reg_syntax_t syntax; - int nest; - reg_errcode_t *err; +parse_sub_exp (re_string_t *regexp, regex_t *preg, re_token_t *token, + reg_syntax_t syntax, int nest, reg_errcode_t *err) { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - bin_tree_t *tree, *left_par, *right_par; + bin_tree_t *tree; size_t cur_nsub; cur_nsub = preg->re_nsub++; - left_par = re_dfa_add_tree_node (dfa, NULL, NULL, token); - if (BE (left_par == NULL, 0)) - { - *err = REG_ESPACE; - return NULL; - } - dfa->nodes[left_par->node_idx].opr.idx = cur_nsub; fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE); /* The subexpression may be a null string. */ @@ -2481,41 +2392,31 @@ parse_sub_exp (regexp, preg, token, syntax, nest, err) else { tree = parse_reg_exp (regexp, preg, token, syntax, nest, err); - if (BE (*err != REG_NOERROR && tree == NULL, 0)) + if (BE (*err == REG_NOERROR && token->type != OP_CLOSE_SUBEXP, 0)) + *err = REG_EPAREN; + if (BE (*err != REG_NOERROR, 0)) return NULL; } - if (BE (token->type != OP_CLOSE_SUBEXP, 0)) - { - *err = REG_EPAREN; - return NULL; - } - right_par = re_dfa_add_tree_node (dfa, NULL, NULL, token); - dfa->completed_bkref_map |= 1 << cur_nsub; - tree = ((tree == NULL) ? right_par - : create_tree (dfa, tree, right_par, CONCAT, 0)); - tree = create_tree (dfa, left_par, tree, CONCAT, 0); - if (BE (right_par == NULL || tree == NULL, 0)) + + if (cur_nsub <= '9' - '1') + dfa->completed_bkref_map |= 1 << cur_nsub; + + tree = create_tree (dfa, tree, NULL, SUBEXP); + if (BE (tree == NULL, 0)) { *err = REG_ESPACE; return NULL; } - dfa->nodes[right_par->node_idx].opr.idx = cur_nsub; - + tree->token.opr.idx = cur_nsub; return tree; } /* This function parse repetition operators like "*", "+", "{1,3}" etc. */ static bin_tree_t * -parse_dup_op (elem, regexp, dfa, token, syntax, err) - bin_tree_t *elem; - re_string_t *regexp; - re_dfa_t *dfa; - re_token_t *token; - reg_syntax_t syntax; - reg_errcode_t *err; +parse_dup_op (bin_tree_t *elem, re_string_t *regexp, re_dfa_t *dfa, + re_token_t *token, reg_syntax_t syntax, reg_errcode_t *err) { - re_token_t dup_token; bin_tree_t *tree = NULL, *old_tree = NULL; int i, start, end, start_idx = re_string_cur_idx (regexp); re_token_t start_token = *token; @@ -2578,9 +2479,13 @@ parse_dup_op (elem, regexp, dfa, token, syntax, err) fetch_token (token, regexp, syntax); - /* Treat "<re>{0}*" etc. as "<re>{0}". */ - if (BE (elem == NULL || (start == 0 && end == 0), 0)) + if (BE (elem == NULL, 0)) return NULL; + if (BE (start == 0 && end == 0, 0)) + { + postorder (elem, free_tree, NULL); + return NULL; + } /* Extract "<re>{n,m}" to "<re><re>...<re><re>{0,<m-n>}". */ if (BE (start > 0, 0)) @@ -2589,7 +2494,7 @@ parse_dup_op (elem, regexp, dfa, token, syntax, err) for (i = 2; i <= start; ++i) { elem = duplicate_tree (elem, dfa); - tree = create_tree (dfa, tree, elem, CONCAT, 0); + tree = create_tree (dfa, tree, elem, CONCAT); if (BE (elem == NULL || tree == NULL, 0)) goto parse_dup_op_espace; } @@ -2604,9 +2509,10 @@ parse_dup_op (elem, regexp, dfa, token, syntax, err) else old_tree = NULL; - mark_opt_subexp (elem, dfa); - dup_token.type = (end == -1 ? OP_DUP_ASTERISK : OP_DUP_QUESTION); - tree = re_dfa_add_tree_node (dfa, elem, NULL, &dup_token); + if (elem->token.type == SUBEXP) + postorder (elem, mark_opt_subexp, (void *) (long) elem->token.opr.idx); + + tree = create_tree (dfa, elem, NULL, (end == -1 ? OP_DUP_ASTERISK : OP_ALT)); if (BE (tree == NULL, 0)) goto parse_dup_op_espace; @@ -2616,17 +2522,17 @@ parse_dup_op (elem, regexp, dfa, token, syntax, err) for (i = start + 2; i <= end; ++i) { elem = duplicate_tree (elem, dfa); - tree = create_tree (dfa, tree, elem, CONCAT, 0); + tree = create_tree (dfa, tree, elem, CONCAT); if (BE (elem == NULL || tree == NULL, 0)) goto parse_dup_op_espace; - tree = re_dfa_add_tree_node (dfa, tree, NULL, &dup_token); + tree = create_tree (dfa, tree, NULL, OP_ALT); if (BE (tree == NULL, 0)) goto parse_dup_op_espace; } if (old_tree) - tree = create_tree (dfa, old_tree, tree, CONCAT, 0); + tree = create_tree (dfa, old_tree, tree, CONCAT); return tree; @@ -2648,15 +2554,14 @@ parse_dup_op (elem, regexp, dfa, token, syntax, err) update it. */ static reg_errcode_t +internal_function # ifdef RE_ENABLE_I18N -build_range_exp (sbcset, mbcset, range_alloc, start_elem, end_elem) - re_charset_t *mbcset; - int *range_alloc; +build_range_exp (bitset_t sbcset, re_charset_t *mbcset, int *range_alloc, + bracket_elem_t *start_elem, bracket_elem_t *end_elem) # else /* not RE_ENABLE_I18N */ -build_range_exp (sbcset, start_elem, end_elem) +build_range_exp (bitset_t sbcset, bracket_elem_t *start_elem, + bracket_elem_t *end_elem) # endif /* not RE_ENABLE_I18N */ - re_bitset_ptr_t sbcset; - bracket_elem_t *start_elem, *end_elem; { unsigned int start_ch, end_ch; /* Equivalence Classes and Character Classes can't be a range start/end. */ @@ -2675,7 +2580,9 @@ build_range_exp (sbcset, start_elem, end_elem) # ifdef RE_ENABLE_I18N { - wchar_t wc, start_wc, end_wc; + wchar_t wc; + wint_t start_wc; + wint_t end_wc; wchar_t cmp_buf[6] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'}; start_ch = ((start_elem->type == SB_CHAR) ? start_elem->opr.ch @@ -2768,15 +2675,13 @@ build_range_exp (sbcset, start_elem, end_elem) pointer argument since we may update it. */ static reg_errcode_t +internal_function # ifdef RE_ENABLE_I18N -build_collating_symbol (sbcset, mbcset, coll_sym_alloc, name) - re_charset_t *mbcset; - int *coll_sym_alloc; +build_collating_symbol (bitset_t sbcset, re_charset_t *mbcset, + int *coll_sym_alloc, const unsigned char *name) # else /* not RE_ENABLE_I18N */ -build_collating_symbol (sbcset, name) +build_collating_symbol (bitset_t sbcset, const unsigned char *name) # endif /* not RE_ENABLE_I18N */ - re_bitset_ptr_t sbcset; - const unsigned char *name; { size_t name_len = strlen ((const char *) name); if (BE (name_len != 1, 0)) @@ -2793,12 +2698,8 @@ build_collating_symbol (sbcset, name) "[[.a-a.]]" etc. */ static bin_tree_t * -parse_bracket_exp (regexp, dfa, token, syntax, err) - re_string_t *regexp; - re_dfa_t *dfa; - re_token_t *token; - reg_syntax_t syntax; - reg_errcode_t *err; +parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, + reg_syntax_t syntax, reg_errcode_t *err) { #ifdef _LIBC const unsigned char *collseqmb; @@ -2820,23 +2721,28 @@ parse_bracket_exp (regexp, dfa, token, syntax, err) { int32_t hash = elem_hash ((const char *) name, name_len); int32_t elem = hash % table_size; - int32_t second = hash % (table_size - 2); - while (symb_table[2 * elem] != 0) - { - /* First compare the hashing value. */ - if (symb_table[2 * elem] == hash - /* Compare the length of the name. */ - && name_len == extra[symb_table[2 * elem + 1]] - /* Compare the name. */ - && memcmp (name, &extra[symb_table[2 * elem + 1] + 1], - name_len) == 0) + if (symb_table[2 * elem] != 0) + { + int32_t second = hash % (table_size - 2) + 1; + + do { - /* Yep, this is the entry. */ - break; - } + /* First compare the hashing value. */ + if (symb_table[2 * elem] == hash + /* Compare the length of the name. */ + && name_len == extra[symb_table[2 * elem + 1]] + /* Compare the name. */ + && memcmp (name, &extra[symb_table[2 * elem + 1] + 1], + name_len) == 0) + { + /* Yep, this is the entry. */ + break; + } - /* Next entry. */ - elem += second; + /* Next entry. */ + elem += second; + } + while (symb_table[2 * elem] != 0); } return elem; } @@ -2918,7 +2824,7 @@ parse_bracket_exp (regexp, dfa, token, syntax, err) build_range_exp (sbcset, mbcset, range_alloc, start_elem, end_elem) re_charset_t *mbcset; int *range_alloc; - re_bitset_ptr_t sbcset; + bitset_t sbcset; bracket_elem_t *start_elem, *end_elem; { unsigned int ch; @@ -3001,7 +2907,7 @@ parse_bracket_exp (regexp, dfa, token, syntax, err) build_collating_symbol (sbcset, mbcset, coll_sym_alloc, name) re_charset_t *mbcset; int *coll_sym_alloc; - re_bitset_ptr_t sbcset; + bitset_t sbcset; const unsigned char *name; { int32_t elem, idx; @@ -3078,7 +2984,7 @@ parse_bracket_exp (regexp, dfa, token, syntax, err) /* if (MB_CUR_MAX > 1) */ - collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC); + collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC); table_size = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_SYMB_HASH_SIZEMB); symb_table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_TABLEMB); @@ -3086,7 +2992,7 @@ parse_bracket_exp (regexp, dfa, token, syntax, err) _NL_COLLATE_SYMB_EXTRAMB); } #endif - sbcset = (re_bitset_ptr_t) calloc (sizeof (unsigned int), BITSET_UINTS); + sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); #ifdef RE_ENABLE_I18N mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1); #endif /* RE_ENABLE_I18N */ @@ -3113,7 +3019,7 @@ parse_bracket_exp (regexp, dfa, token, syntax, err) #endif /* not RE_ENABLE_I18N */ non_match = 1; if (syntax & RE_HAT_LISTS_NOT_NEWLINE) - bitset_set (sbcset, '\0'); + bitset_set (sbcset, '\n'); re_string_skip_bytes (regexp, token_len); /* Skip a token. */ token_len = peek_token_bracket (token, regexp, syntax); if (BE (token->type == END_OF_RE, 0)) @@ -3282,57 +3188,59 @@ parse_bracket_exp (regexp, dfa, token, syntax, err) /* Ensure only single byte characters are set. */ if (dfa->mb_cur_max > 1) bitset_mask (sbcset, dfa->sb_char); -#endif /* RE_ENABLE_I18N */ - - /* Build a tree for simple bracket. */ - br_token.type = SIMPLE_BRACKET; - br_token.opr.sbcset = sbcset; - work_tree = re_dfa_add_tree_node (dfa, NULL, NULL, &br_token); - if (BE (work_tree == NULL, 0)) - goto parse_bracket_exp_espace; -#ifdef RE_ENABLE_I18N if (mbcset->nmbchars || mbcset->ncoll_syms || mbcset->nequiv_classes || mbcset->nranges || (dfa->mb_cur_max > 1 && (mbcset->nchar_classes || mbcset->non_match))) { - re_token_t alt_token; bin_tree_t *mbc_tree; int sbc_idx; /* Build a tree for complex bracket. */ dfa->has_mb_node = 1; - for (sbc_idx = 0; sbc_idx < BITSET_UINTS; ++sbc_idx) + br_token.type = COMPLEX_BRACKET; + br_token.opr.mbcset = mbcset; + mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token); + if (BE (mbc_tree == NULL, 0)) + goto parse_bracket_exp_espace; + for (sbc_idx = 0; sbc_idx < BITSET_WORDS; ++sbc_idx) if (sbcset[sbc_idx]) break; /* If there are no bits set in sbcset, there is no point of having both SIMPLE_BRACKET and COMPLEX_BRACKET. */ - if (sbc_idx == BITSET_UINTS) + if (sbc_idx < BITSET_WORDS) + { + /* Build a tree for simple bracket. */ + br_token.type = SIMPLE_BRACKET; + br_token.opr.sbcset = sbcset; + work_tree = create_token_tree (dfa, NULL, NULL, &br_token); + if (BE (work_tree == NULL, 0)) + goto parse_bracket_exp_espace; + + /* Then join them by ALT node. */ + work_tree = create_tree (dfa, work_tree, mbc_tree, OP_ALT); + if (BE (work_tree == NULL, 0)) + goto parse_bracket_exp_espace; + } + else { re_free (sbcset); - dfa->nodes[work_tree->node_idx].type = COMPLEX_BRACKET; - dfa->nodes[work_tree->node_idx].opr.mbcset = mbcset; - return work_tree; + work_tree = mbc_tree; } - br_token.type = COMPLEX_BRACKET; - br_token.opr.mbcset = mbcset; - mbc_tree = re_dfa_add_tree_node (dfa, NULL, NULL, &br_token); - if (BE (mbc_tree == NULL, 0)) - goto parse_bracket_exp_espace; - /* Then join them by ALT node. */ - alt_token.type = OP_ALT; - dfa->has_plural_match = 1; - work_tree = re_dfa_add_tree_node (dfa, work_tree, mbc_tree, &alt_token); - if (BE (mbc_tree != NULL, 1)) - return work_tree; } else +#endif /* not RE_ENABLE_I18N */ { +#ifdef RE_ENABLE_I18N free_charset (mbcset); - return work_tree; +#endif + /* Build a tree for simple bracket. */ + br_token.type = SIMPLE_BRACKET; + br_token.opr.sbcset = sbcset; + work_tree = create_token_tree (dfa, NULL, NULL, &br_token); + if (BE (work_tree == NULL, 0)) + goto parse_bracket_exp_espace; } -#else /* not RE_ENABLE_I18N */ return work_tree; -#endif /* not RE_ENABLE_I18N */ parse_bracket_exp_espace: *err = REG_ESPACE; @@ -3347,15 +3255,9 @@ parse_bracket_exp (regexp, dfa, token, syntax, err) /* Parse an element in the bracket expression. */ static reg_errcode_t -parse_bracket_element (elem, regexp, token, token_len, dfa, syntax, - accept_hyphen) - bracket_elem_t *elem; - re_string_t *regexp; - re_token_t *token; - int token_len; - re_dfa_t *dfa; - reg_syntax_t syntax; - int accept_hyphen; +parse_bracket_element (bracket_elem_t *elem, re_string_t *regexp, + re_token_t *token, int token_len, re_dfa_t *dfa, + reg_syntax_t syntax, int accept_hyphen) { #ifdef RE_ENABLE_I18N int cur_char_size; @@ -3393,10 +3295,8 @@ parse_bracket_element (elem, regexp, token, token_len, dfa, syntax, [=<equivalent_class>=]. */ static reg_errcode_t -parse_bracket_symbol (elem, regexp, token) - bracket_elem_t *elem; - re_string_t *regexp; - re_token_t *token; +parse_bracket_symbol (bracket_elem_t *elem, re_string_t *regexp, + re_token_t *token) { unsigned char ch, delim = token->opr.c; int i = 0; @@ -3443,16 +3343,13 @@ parse_bracket_symbol (elem, regexp, token) static reg_errcode_t #ifdef RE_ENABLE_I18N -build_equiv_class (sbcset, mbcset, equiv_class_alloc, name) - re_charset_t *mbcset; - int *equiv_class_alloc; +build_equiv_class (bitset_t sbcset, re_charset_t *mbcset, + int *equiv_class_alloc, const unsigned char *name) #else /* not RE_ENABLE_I18N */ -build_equiv_class (sbcset, name) +build_equiv_class (bitset_t sbcset, const unsigned char *name) #endif /* not RE_ENABLE_I18N */ - re_bitset_ptr_t sbcset; - const unsigned char *name; { -#if defined _LIBC +#ifdef _LIBC uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); if (nrules != 0) { @@ -3538,16 +3435,13 @@ build_equiv_class (sbcset, name) static reg_errcode_t #ifdef RE_ENABLE_I18N -build_charclass (trans, sbcset, mbcset, char_class_alloc, class_name, syntax) - re_charset_t *mbcset; - int *char_class_alloc; +build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset, + re_charset_t *mbcset, int *char_class_alloc, + const unsigned char *class_name, reg_syntax_t syntax) #else /* not RE_ENABLE_I18N */ -build_charclass (trans, sbcset, class_name, syntax) +build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset, + const unsigned char *class_name, reg_syntax_t syntax) #endif /* not RE_ENABLE_I18N */ - unsigned RE_TRANSLATE_TYPE trans; - re_bitset_ptr_t sbcset; - const unsigned char *class_name; - reg_syntax_t syntax; { int i; const char *name = (const char *) class_name; @@ -3577,39 +3471,45 @@ build_charclass (trans, sbcset, class_name, syntax) #endif /* RE_ENABLE_I18N */ #define BUILD_CHARCLASS_LOOP(ctype_func) \ - for (i = 0; i < SBC_MAX; ++i) \ + do { \ + if (BE (trans != NULL, 0)) \ { \ - if (ctype_func (i)) \ - { \ - int ch = trans ? trans[i] : i; \ - bitset_set (sbcset, ch); \ - } \ - } + for (i = 0; i < SBC_MAX; ++i) \ + if (ctype_func (i)) \ + bitset_set (sbcset, trans[i]); \ + } \ + else \ + { \ + for (i = 0; i < SBC_MAX; ++i) \ + if (ctype_func (i)) \ + bitset_set (sbcset, i); \ + } \ + } while (0) if (strcmp (name, "alnum") == 0) - BUILD_CHARCLASS_LOOP (isalnum) + BUILD_CHARCLASS_LOOP (isalnum); else if (strcmp (name, "cntrl") == 0) - BUILD_CHARCLASS_LOOP (iscntrl) + BUILD_CHARCLASS_LOOP (iscntrl); else if (strcmp (name, "lower") == 0) - BUILD_CHARCLASS_LOOP (islower) + BUILD_CHARCLASS_LOOP (islower); else if (strcmp (name, "space") == 0) - BUILD_CHARCLASS_LOOP (isspace) + BUILD_CHARCLASS_LOOP (isspace); else if (strcmp (name, "alpha") == 0) - BUILD_CHARCLASS_LOOP (isalpha) + BUILD_CHARCLASS_LOOP (isalpha); else if (strcmp (name, "digit") == 0) - BUILD_CHARCLASS_LOOP (isdigit) + BUILD_CHARCLASS_LOOP (isdigit); else if (strcmp (name, "print") == 0) - BUILD_CHARCLASS_LOOP (isprint) + BUILD_CHARCLASS_LOOP (isprint); else if (strcmp (name, "upper") == 0) - BUILD_CHARCLASS_LOOP (isupper) + BUILD_CHARCLASS_LOOP (isupper); else if (strcmp (name, "blank") == 0) - BUILD_CHARCLASS_LOOP (isblank) + BUILD_CHARCLASS_LOOP (isblank); else if (strcmp (name, "graph") == 0) - BUILD_CHARCLASS_LOOP (isgraph) + BUILD_CHARCLASS_LOOP (isgraph); else if (strcmp (name, "punct") == 0) - BUILD_CHARCLASS_LOOP (ispunct) + BUILD_CHARCLASS_LOOP (ispunct); else if (strcmp (name, "xdigit") == 0) - BUILD_CHARCLASS_LOOP (isxdigit) + BUILD_CHARCLASS_LOOP (isxdigit); else return REG_ECTYPE; @@ -3617,13 +3517,10 @@ build_charclass (trans, sbcset, class_name, syntax) } static bin_tree_t * -build_charclass_op (dfa, trans, class_name, extra, non_match, err) - re_dfa_t *dfa; - unsigned RE_TRANSLATE_TYPE trans; - const unsigned char *class_name; - const unsigned char *extra; - int non_match; - reg_errcode_t *err; +build_charclass_op (re_dfa_t *dfa, RE_TRANSLATE_TYPE trans, + const unsigned char *class_name, + const unsigned char *extra, int non_match, + reg_errcode_t *err) { re_bitset_ptr_t sbcset; #ifdef RE_ENABLE_I18N @@ -3634,7 +3531,7 @@ build_charclass_op (dfa, trans, class_name, extra, non_match, err) re_token_t br_token; bin_tree_t *tree; - sbcset = (re_bitset_ptr_t) calloc (sizeof (unsigned int), BITSET_UINTS); + sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); #ifdef RE_ENABLE_I18N mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1); #endif /* RE_ENABLE_I18N */ @@ -3652,10 +3549,6 @@ build_charclass_op (dfa, trans, class_name, extra, non_match, err) if (non_match) { #ifdef RE_ENABLE_I18N - /* - if (syntax & RE_HAT_LISTS_NOT_NEWLINE) - bitset_set(cset->sbcset, '\0'); - */ mbcset->non_match = 1; #endif /* not RE_ENABLE_I18N */ } @@ -3693,26 +3586,23 @@ build_charclass_op (dfa, trans, class_name, extra, non_match, err) /* Build a tree for simple bracket. */ br_token.type = SIMPLE_BRACKET; br_token.opr.sbcset = sbcset; - tree = re_dfa_add_tree_node (dfa, NULL, NULL, &br_token); + tree = create_token_tree (dfa, NULL, NULL, &br_token); if (BE (tree == NULL, 0)) goto build_word_op_espace; #ifdef RE_ENABLE_I18N if (dfa->mb_cur_max > 1) { - re_token_t alt_token; bin_tree_t *mbc_tree; /* Build a tree for complex bracket. */ br_token.type = COMPLEX_BRACKET; br_token.opr.mbcset = mbcset; dfa->has_mb_node = 1; - mbc_tree = re_dfa_add_tree_node (dfa, NULL, NULL, &br_token); + mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token); if (BE (mbc_tree == NULL, 0)) goto build_word_op_espace; /* Then join them by ALT node. */ - alt_token.type = OP_ALT; - dfa->has_plural_match = 1; - tree = re_dfa_add_tree_node (dfa, tree, mbc_tree, &alt_token); + tree = create_tree (dfa, tree, mbc_tree, OP_ALT); if (BE (mbc_tree != NULL, 1)) return tree; } @@ -3740,10 +3630,7 @@ build_charclass_op (dfa, trans, class_name, extra, non_match, err) Return -2, If an error is occured. */ static int -fetch_number (input, token, syntax) - re_string_t *input; - re_token_t *token; - reg_syntax_t syntax; +fetch_number (re_string_t *input, re_token_t *token, reg_syntax_t syntax) { int num = -1; unsigned char c; @@ -3783,12 +3670,17 @@ free_charset (re_charset_t *cset) /* Create a tree node. */ static bin_tree_t * -create_tree (dfa, left, right, type, index) - re_dfa_t *dfa; - bin_tree_t *left; - bin_tree_t *right; - re_token_type_t type; - int index; +create_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, + re_token_type_t type) +{ + re_token_t t; + t.type = type; + return create_token_tree (dfa, left, right, &t); +} + +static bin_tree_t * +create_token_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, + const re_token_t *token) { bin_tree_t *tree; if (BE (dfa->str_tree_storage_idx == BIN_TREE_STORAGE_SIZE, 0)) @@ -3806,11 +3698,12 @@ create_tree (dfa, left, right, type, index) tree->parent = NULL; tree->left = left; tree->right = right; - tree->type = type; - tree->node_idx = index; - tree->first = -1; - tree->next = -1; - re_node_set_init_empty (&tree->eclosure); + tree->token = *token; + tree->token.duplicated = 0; + tree->token.opt_subexp = 0; + tree->first = NULL; + tree->next = NULL; + tree->node_idx = -1; if (left != NULL) left->parent = tree; @@ -3819,103 +3712,85 @@ create_tree (dfa, left, right, type, index) return tree; } -/* Create both a DFA node and a tree for it. */ +/* Mark the tree SRC as an optional subexpression. + To be called from preorder or postorder. */ -static bin_tree_t * -re_dfa_add_tree_node (dfa, left, right, token) - re_dfa_t *dfa; - bin_tree_t *left; - bin_tree_t *right; - const re_token_t *token; +static reg_errcode_t +mark_opt_subexp (void *extra, bin_tree_t *node) { - int new_idx = re_dfa_add_node (dfa, *token, 0); + int idx = (int) (long) extra; + if (node->token.type == SUBEXP && node->token.opr.idx == idx) + node->token.opt_subexp = 1; - if (new_idx == -1) - return NULL; - - return create_tree (dfa, left, right, 0, new_idx); + return REG_NOERROR; } -/* Mark the tree SRC as an optional subexpression. */ +/* Free the allocated memory inside NODE. */ static void -mark_opt_subexp (src, dfa) - const bin_tree_t *src; - re_dfa_t *dfa; +free_token (re_token_t *node) { - /* Pass an OPT_SUBEXP_IDX which is != 1 if the duplicated tree is - a subexpression. */ - if (src->type == CONCAT - && src->left->type == NON_TYPE - && dfa->nodes[src->left->node_idx].type == OP_OPEN_SUBEXP) - mark_opt_subexp_iter (src, dfa, dfa->nodes[src->left->node_idx].opr.idx); +#ifdef RE_ENABLE_I18N + if (node->type == COMPLEX_BRACKET && node->duplicated == 0) + free_charset (node->opr.mbcset); + else +#endif /* RE_ENABLE_I18N */ + if (node->type == SIMPLE_BRACKET && node->duplicated == 0) + re_free (node->opr.sbcset); } +/* Worker function for tree walking. Free the allocated memory inside NODE + and its children. */ -/* Recursive tree walker for mark_opt_subexp. */ - -static void -mark_opt_subexp_iter (src, dfa, idx) - const bin_tree_t *src; - re_dfa_t *dfa; - int idx; +static reg_errcode_t +free_tree (void *extra, bin_tree_t *node) { - int node_idx; - - if (src->type == NON_TYPE) - { - node_idx = src->node_idx; - if ((dfa->nodes[node_idx].type == OP_OPEN_SUBEXP - || dfa->nodes[node_idx].type == OP_CLOSE_SUBEXP) - && dfa->nodes[node_idx].opr.idx == idx) - dfa->nodes[node_idx].opt_subexp = 1; - } - - if (src->left != NULL) - mark_opt_subexp_iter (src->left, dfa, idx); - - if (src->right != NULL) - mark_opt_subexp_iter (src->right, dfa, idx); + free_token (&node->token); + return REG_NOERROR; } -/* Duplicate the node SRC, and return new node. */ +/* Duplicate the node SRC, and return new node. This is a preorder + visit similar to the one implemented by the generic visitor, but + we need more infrastructure to maintain two parallel trees --- so, + it's easier to duplicate. */ static bin_tree_t * -duplicate_tree (src, dfa) - const bin_tree_t *src; - re_dfa_t *dfa; +duplicate_tree (const bin_tree_t *root, re_dfa_t *dfa) { - bin_tree_t *left = NULL, *right = NULL, *new_tree; - int new_node_idx; - /* Since node indies must be according to Post-order of the tree, - we must duplicate the left at first. */ - if (src->left != NULL) - { - left = duplicate_tree (src->left, dfa); - if (left == NULL) - return NULL; - } + const bin_tree_t *node; + bin_tree_t *dup_root; + bin_tree_t **p_new = &dup_root, *dup_node = root->parent; - /* Secondaly, duplicate the right. */ - if (src->right != NULL) + for (node = root; ; ) { - right = duplicate_tree (src->right, dfa); - if (right == NULL) + /* Create a new tree and link it back to the current parent. */ + *p_new = create_token_tree (dfa, NULL, NULL, &node->token); + if (*p_new == NULL) return NULL; - } + (*p_new)->parent = dup_node; + (*p_new)->token.duplicated = 1; + dup_node = *p_new; - /* At last, duplicate itself. */ - if (src->type == NON_TYPE) - { - new_node_idx = re_dfa_add_node (dfa, dfa->nodes[src->node_idx], 0); - dfa->nodes[new_node_idx].duplicated = 1; - if (BE (new_node_idx == -1, 0)) - return NULL; + /* Go to the left node, or up and to the right. */ + if (node->left) + { + node = node->left; + p_new = &dup_node->left; + } + else + { + const bin_tree_t *prev = NULL; + while (node->right == prev || node->right == NULL) + { + prev = node; + node = node->parent; + dup_node = dup_node->parent; + if (!node) + return dup_root; + } + node = node->right; + p_new = &dup_node->right; + } } - else - new_node_idx = src->type; - - new_tree = create_tree (dfa, left, right, src->type, new_node_idx); - return new_tree; } diff --git a/posix/regex.c b/posix/regex.c index 7a4f304cdd..d2d4f28e01 100644 --- a/posix/regex.c +++ b/posix/regex.c @@ -1,5 +1,5 @@ /* Extended regular expression matching and search library. - Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. @@ -22,28 +22,9 @@ #include "config.h" #endif -#ifdef _AIX -#pragma alloca -#else -# ifndef allocax /* predefined by HP cc +Olibcalls */ -# ifdef __GNUC__ -# define alloca(size) __builtin_alloca (size) -# else -# if HAVE_ALLOCA_H -# include <alloca.h> -# else -# ifdef __hpux - void *alloca (); -# else -# if !defined __OS2__ && !defined WIN32 - char *alloca (); -# else -# include <malloc.h> /* OS/2 defines alloca in here */ -# endif -# endif -# endif -# endif -# endif +/* Make sure noone compiles this code with a C++ compiler. */ +#ifdef __cplusplus +# error "This is C code, use a C compiler" #endif #ifdef _LIBC @@ -71,10 +52,6 @@ # include "../locale/localeinfo.h" #endif -/* POSIX says that <sys/types.h> must be included (by the caller) before - <regex.h>. */ -#include <sys/types.h> - /* On some systems, limits.h sets RE_DUP_MAX to a lower value than GNU regex allows. Include it before <regex.h>, which correctly #undefs RE_DUP_MAX and sets it to the right value. */ diff --git a/posix/regex.h b/posix/regex.h index b2d9a62fec..807c404ec2 100644 --- a/posix/regex.h +++ b/posix/regex.h @@ -1,6 +1,6 @@ /* Definitions for data structures and routines for the regular expression library. - Copyright (C) 1985,1989-93,1995-98,2000,2001,2002,2003 + Copyright (C) 1985,1989-93,1995-98,2000,2001,2002,2003,2005,2006 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -29,15 +29,6 @@ extern "C" { #endif -/* POSIX says that <sys/types.h> must be included (by the caller) before - <regex.h>. */ - -#if !defined _POSIX_C_SOURCE && !defined _POSIX_SOURCE && defined VMS -/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it - should be there. */ -# include <stddef.h> -#endif - /* The following two types have to be signed and unsigned integer type wide enough to hold a value of a pointer. For most ANSI compilers ptrdiff_t and size_t should be likely OK. Still size of these two @@ -207,7 +198,7 @@ extern reg_syntax_t re_syntax_options; & ~(RE_DOT_NOT_NULL | RE_INTERVALS | RE_CONTEXT_INDEP_OPS \ | RE_CONTEXT_INVALID_OPS )) -#define RE_SYNTAX_POSIX_AWK \ +#define RE_SYNTAX_POSIX_AWK \ (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ | RE_INTERVALS | RE_NO_GNU_OPS) @@ -346,75 +337,71 @@ typedef enum private to the regex routines. */ #ifndef RE_TRANSLATE_TYPE -# define RE_TRANSLATE_TYPE char * +# define RE_TRANSLATE_TYPE unsigned char * #endif struct re_pattern_buffer { -/* [[[begin pattern_buffer]]] */ - /* Space that holds the compiled pattern. It is declared as - `unsigned char *' because its elements are - sometimes used as array indexes. */ + /* Space that holds the compiled pattern. It is declared as + `unsigned char *' because its elements are sometimes used as + array indexes. */ unsigned char *buffer; - /* Number of bytes to which `buffer' points. */ + /* Number of bytes to which `buffer' points. */ unsigned long int allocated; - /* Number of bytes actually used in `buffer'. */ + /* Number of bytes actually used in `buffer'. */ unsigned long int used; - /* Syntax setting with which the pattern was compiled. */ + /* Syntax setting with which the pattern was compiled. */ reg_syntax_t syntax; - /* Pointer to a fastmap, if any, otherwise zero. re_search uses - the fastmap, if there is one, to skip over impossible - starting points for matches. */ + /* Pointer to a fastmap, if any, otherwise zero. re_search uses the + fastmap, if there is one, to skip over impossible starting points + for matches. */ char *fastmap; - /* Either a translate table to apply to all characters before - comparing them, or zero for no translation. The translation - is applied to a pattern when it is compiled and to a string - when it is matched. */ + /* Either a translate table to apply to all characters before + comparing them, or zero for no translation. The translation is + applied to a pattern when it is compiled and to a string when it + is matched. */ RE_TRANSLATE_TYPE translate; - /* Number of subexpressions found by the compiler. */ + /* Number of subexpressions found by the compiler. */ size_t re_nsub; - /* Zero if this pattern cannot match the empty string, one else. - Well, in truth it's used only in `re_search_2', to see - whether or not we should use the fastmap, so we don't set - this absolutely perfectly; see `re_compile_fastmap' (the - `duplicate' case). */ + /* Zero if this pattern cannot match the empty string, one else. + Well, in truth it's used only in `re_search_2', to see whether or + not we should use the fastmap, so we don't set this absolutely + perfectly; see `re_compile_fastmap' (the `duplicate' case). */ unsigned can_be_null : 1; - /* If REGS_UNALLOCATED, allocate space in the `regs' structure - for `max (RE_NREGS, re_nsub + 1)' groups. - If REGS_REALLOCATE, reallocate space if necessary. - If REGS_FIXED, use what's there. */ + /* If REGS_UNALLOCATED, allocate space in the `regs' structure + for `max (RE_NREGS, re_nsub + 1)' groups. + If REGS_REALLOCATE, reallocate space if necessary. + If REGS_FIXED, use what's there. */ #define REGS_UNALLOCATED 0 #define REGS_REALLOCATE 1 #define REGS_FIXED 2 unsigned regs_allocated : 2; - /* Set to zero when `regex_compile' compiles a pattern; set to one - by `re_compile_fastmap' if it updates the fastmap. */ + /* Set to zero when `regex_compile' compiles a pattern; set to one + by `re_compile_fastmap' if it updates the fastmap. */ unsigned fastmap_accurate : 1; - /* If set, `re_match_2' does not return information about - subexpressions. */ + /* If set, `re_match_2' does not return information about + subexpressions. */ unsigned no_sub : 1; - /* If set, a beginning-of-line anchor doesn't match at the - beginning of the string. */ + /* If set, a beginning-of-line anchor doesn't match at the beginning + of the string. */ unsigned not_bol : 1; - /* Similarly for an end-of-line anchor. */ + /* Similarly for an end-of-line anchor. */ unsigned not_eol : 1; - /* If true, an anchor at a newline matches. */ + /* If true, an anchor at a newline matches. */ unsigned newline_anchor : 1; - -/* [[[end pattern_buffer]]] */ }; typedef struct re_pattern_buffer regex_t; @@ -452,38 +439,21 @@ typedef struct /* Declarations for routines. */ -/* To avoid duplicating every routine declaration -- once with a - prototype (if we are ANSI), and once without (if we aren't) -- we - use the following macro to declare argument types. This - unfortunately clutters up the declarations a bit, but I think it's - worth it. */ - -#if __STDC__ - -# define _RE_ARGS(args) args - -#else /* not __STDC__ */ - -# define _RE_ARGS(args) () - -#endif /* not __STDC__ */ - /* Sets the current default syntax to SYNTAX, and return the old syntax. You can also simply assign to the `re_syntax_options' variable. */ -extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax)); +extern reg_syntax_t re_set_syntax (reg_syntax_t __syntax); /* Compile the regular expression PATTERN, with length LENGTH and syntax given by the global `re_syntax_options', into the buffer BUFFER. Return NULL if successful, and an error string if not. */ -extern const char *re_compile_pattern - _RE_ARGS ((const char *pattern, size_t length, - struct re_pattern_buffer *buffer)); +extern const char *re_compile_pattern (const char *__pattern, size_t __length, + struct re_pattern_buffer *__buffer); /* Compile a fastmap for the compiled pattern in BUFFER; used to accelerate searches. Return 0 if successful and -2 if was an internal error. */ -extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer)); +extern int re_compile_fastmap (struct re_pattern_buffer *__buffer); /* Search in the string STRING (with length LENGTH) for the pattern @@ -491,31 +461,30 @@ extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer)); characters. Return the starting position of the match, -1 for no match, or -2 for an internal error. Also return register information in REGS (if REGS and BUFFER->no_sub are nonzero). */ -extern int re_search - _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, - int length, int start, int range, struct re_registers *regs)); +extern int re_search (struct re_pattern_buffer *__buffer, const char *__string, + int __length, int __start, int __range, + struct re_registers *__regs); /* Like `re_search', but search in the concatenation of STRING1 and STRING2. Also, stop searching at index START + STOP. */ -extern int re_search_2 - _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, - int length1, const char *string2, int length2, - int start, int range, struct re_registers *regs, int stop)); +extern int re_search_2 (struct re_pattern_buffer *__buffer, + const char *__string1, int __length1, + const char *__string2, int __length2, int __start, + int __range, struct re_registers *__regs, int __stop); /* Like `re_search', but return how many characters in STRING the regexp in BUFFER matched, starting at position START. */ -extern int re_match - _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, - int length, int start, struct re_registers *regs)); +extern int re_match (struct re_pattern_buffer *__buffer, const char *__string, + int __length, int __start, struct re_registers *__regs); /* Relates to `re_match' as `re_search_2' relates to `re_search'. */ -extern int re_match_2 - _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, - int length1, const char *string2, int length2, - int start, struct re_registers *regs, int stop)); +extern int re_match_2 (struct re_pattern_buffer *__buffer, + const char *__string1, int __length1, + const char *__string2, int __length2, int __start, + struct re_registers *__regs, int __stop); /* Set REGS to hold NUM_REGS registers, storing them in STARTS and @@ -530,15 +499,16 @@ extern int re_match_2 Unless this function is called, the first search or match using PATTERN_BUFFER will allocate its own register data, without freeing the old data. */ -extern void re_set_registers - _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs, - unsigned num_regs, regoff_t *starts, regoff_t *ends)); +extern void re_set_registers (struct re_pattern_buffer *__buffer, + struct re_registers *__regs, + unsigned int __num_regs, + regoff_t *__starts, regoff_t *__ends); #if defined _REGEX_RE_COMP || defined _LIBC # ifndef _CRAY /* 4.2 bsd compatibility. */ -extern char *re_comp _RE_ARGS ((const char *)); -extern int re_exec _RE_ARGS ((const char *)); +extern char *re_comp (const char *); +extern int re_exec (const char *); # endif #endif @@ -555,7 +525,8 @@ extern int re_exec _RE_ARGS ((const char *)); #endif /* gcc 3.1 and up support the [restrict] syntax. */ #ifndef __restrict_arr -# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) +# if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) \ + && !defined __GNUG__ # define __restrict_arr __restrict # else # define __restrict_arr @@ -563,19 +534,19 @@ extern int re_exec _RE_ARGS ((const char *)); #endif /* POSIX compatibility. */ -extern int regcomp _RE_ARGS ((regex_t *__restrict __preg, - const char *__restrict __pattern, - int __cflags)); +extern int regcomp (regex_t *__restrict __preg, + const char *__restrict __pattern, + int __cflags); -extern int regexec _RE_ARGS ((const regex_t *__restrict __preg, - const char *__restrict __string, size_t __nmatch, - regmatch_t __pmatch[__restrict_arr], - int __eflags)); +extern int regexec (const regex_t *__restrict __preg, + const char *__restrict __string, size_t __nmatch, + regmatch_t __pmatch[__restrict_arr], + int __eflags); -extern size_t regerror _RE_ARGS ((int __errcode, const regex_t *__preg, - char *__errbuf, size_t __errbuf_size)); +extern size_t regerror (int __errcode, const regex_t *__restrict __preg, + char *__restrict __errbuf, size_t __errbuf_size); -extern void regfree _RE_ARGS ((regex_t *__preg)); +extern void regfree (regex_t *__preg); #ifdef __cplusplus @@ -583,11 +554,3 @@ extern void regfree _RE_ARGS ((regex_t *__preg)); #endif /* C++ */ #endif /* regex.h */ - -/* -Local variables: -make-backup-files: t -version-control: t -trim-versions-without-asking: nil -End: -*/ diff --git a/posix/regex_internal.c b/posix/regex_internal.c index 001b50b134..66154e0cea 100644 --- a/posix/regex_internal.c +++ b/posix/regex_internal.c @@ -1,5 +1,5 @@ /* Extended regular expression matching and search library. - Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. @@ -22,21 +22,13 @@ static void re_string_construct_common (const char *str, int len, re_string_t *pstr, RE_TRANSLATE_TYPE trans, int icase, const re_dfa_t *dfa) internal_function; -#ifdef RE_ENABLE_I18N -static int re_string_skip_chars (re_string_t *pstr, int new_raw_idx, - wint_t *last_wc) internal_function; -#endif /* RE_ENABLE_I18N */ -static reg_errcode_t register_state (re_dfa_t *dfa, re_dfastate_t *newstate, - unsigned int hash) internal_function; -static re_dfastate_t *create_ci_newstate (re_dfa_t *dfa, +static re_dfastate_t *create_ci_newstate (const re_dfa_t *dfa, const re_node_set *nodes, unsigned int hash) internal_function; -static re_dfastate_t *create_cd_newstate (re_dfa_t *dfa, +static re_dfastate_t *create_cd_newstate (const re_dfa_t *dfa, const re_node_set *nodes, unsigned int context, unsigned int hash) internal_function; -static unsigned int inline calc_state_hash (const re_node_set *nodes, - unsigned int context) internal_function; /* Functions for string operation. */ @@ -44,12 +36,9 @@ static unsigned int inline calc_state_hash (const re_node_set *nodes, re_string_reconstruct before using the object. */ static reg_errcode_t -re_string_allocate (pstr, str, len, init_len, trans, icase, dfa) - re_string_t *pstr; - const char *str; - int len, init_len, icase; - RE_TRANSLATE_TYPE trans; - const re_dfa_t *dfa; +internal_function +re_string_allocate (re_string_t *pstr, const char *str, int len, int init_len, + RE_TRANSLATE_TYPE trans, int icase, const re_dfa_t *dfa) { reg_errcode_t ret; int init_buf_len; @@ -75,12 +64,9 @@ re_string_allocate (pstr, str, len, init_len, trans, icase, dfa) /* This function allocate the buffers, and initialize them. */ static reg_errcode_t -re_string_construct (pstr, str, len, trans, icase, dfa) - re_string_t *pstr; - const char *str; - int len, icase; - RE_TRANSLATE_TYPE trans; - const re_dfa_t *dfa; +internal_function +re_string_construct (re_string_t *pstr, const char *str, int len, + RE_TRANSLATE_TYPE trans, int icase, const re_dfa_t *dfa) { reg_errcode_t ret; memset (pstr, '\0', sizeof (re_string_t)); @@ -141,33 +127,32 @@ re_string_construct (pstr, str, len, trans, icase, dfa) /* Helper functions for re_string_allocate, and re_string_construct. */ static reg_errcode_t -re_string_realloc_buffers (pstr, new_buf_len) - re_string_t *pstr; - int new_buf_len; +internal_function +re_string_realloc_buffers (re_string_t *pstr, int new_buf_len) { #ifdef RE_ENABLE_I18N if (pstr->mb_cur_max > 1) { - wint_t *new_array = re_realloc (pstr->wcs, wint_t, new_buf_len); - if (BE (new_array == NULL, 0)) + wint_t *new_wcs = re_realloc (pstr->wcs, wint_t, new_buf_len); + if (BE (new_wcs == NULL, 0)) return REG_ESPACE; - pstr->wcs = new_array; + pstr->wcs = new_wcs; if (pstr->offsets != NULL) { - int *new_array = re_realloc (pstr->offsets, int, new_buf_len); - if (BE (new_array == NULL, 0)) + int *new_offsets = re_realloc (pstr->offsets, int, new_buf_len); + if (BE (new_offsets == NULL, 0)) return REG_ESPACE; - pstr->offsets = new_array; + pstr->offsets = new_offsets; } } #endif /* RE_ENABLE_I18N */ if (pstr->mbs_allocated) { - unsigned char *new_array = re_realloc (pstr->mbs, unsigned char, - new_buf_len); - if (BE (new_array == NULL, 0)) + unsigned char *new_mbs = re_realloc (pstr->mbs, unsigned char, + new_buf_len); + if (BE (new_mbs == NULL, 0)) return REG_ESPACE; - pstr->mbs = new_array; + pstr->mbs = new_mbs; } pstr->bufs_len = new_buf_len; return REG_NOERROR; @@ -175,18 +160,15 @@ re_string_realloc_buffers (pstr, new_buf_len) static void -re_string_construct_common (str, len, pstr, trans, icase, dfa) - const char *str; - int len; - re_string_t *pstr; - RE_TRANSLATE_TYPE trans; - int icase; - const re_dfa_t *dfa; +internal_function +re_string_construct_common (const char *str, int len, re_string_t *pstr, + RE_TRANSLATE_TYPE trans, int icase, + const re_dfa_t *dfa) { pstr->raw_mbs = (const unsigned char *) str; pstr->len = len; pstr->raw_len = len; - pstr->trans = (unsigned RE_TRANSLATE_TYPE) trans; + pstr->trans = trans; pstr->icase = icase ? 1 : 0; pstr->mbs_allocated = (trans != NULL || icase); pstr->mb_cur_max = dfa->mb_cur_max; @@ -210,16 +192,18 @@ re_string_construct_common (str, len, pstr, trans, icase, dfa) built and starts from PSTR->VALID_LEN. */ static void -build_wcs_buffer (pstr) - re_string_t *pstr; +internal_function +build_wcs_buffer (re_string_t *pstr) { #ifdef _LIBC - unsigned char buf[pstr->mb_cur_max]; + unsigned char buf[MB_LEN_MAX]; + assert (MB_LEN_MAX >= pstr->mb_cur_max); #else unsigned char buf[64]; #endif mbstate_t prev_st; - int byte_idx, end_idx, mbclen, remain_len; + int byte_idx, end_idx, remain_len; + size_t mbclen; /* Build the buffers from pstr->valid_len to either pstr->len or pstr->bufs_len. */ @@ -275,16 +259,18 @@ build_wcs_buffer (pstr) /* Build wide character buffer PSTR->WCS like build_wcs_buffer, but for REG_ICASE. */ -static int -build_wcs_upper_buffer (pstr) - re_string_t *pstr; +static reg_errcode_t +internal_function +build_wcs_upper_buffer (re_string_t *pstr) { mbstate_t prev_st; - int src_idx, byte_idx, end_idx, mbclen, remain_len; + int src_idx, byte_idx, end_idx, remain_len; + size_t mbclen; #ifdef _LIBC - unsigned char buf[pstr->mb_cur_max]; + char buf[MB_LEN_MAX]; + assert (MB_LEN_MAX >= pstr->mb_cur_max); #else - unsigned char buf[64]; + char buf[64]; #endif byte_idx = pstr->valid_len; @@ -316,12 +302,12 @@ build_wcs_upper_buffer (pstr) mbclen = mbrtowc (&wc, ((const char *) pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx), remain_len, &pstr->cur_state); - if (BE (mbclen > 0, 1)) + if (BE (mbclen + 2 > 2, 1)) { wchar_t wcu = wc; if (iswlower (wc)) { - int mbcdlen; + size_t mbcdlen; wcu = towupper (wc); mbcdlen = wcrtomb (buf, wcu, &prev_st); @@ -384,20 +370,20 @@ build_wcs_upper_buffer (pstr) else p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + src_idx; mbclen = mbrtowc (&wc, p, remain_len, &pstr->cur_state); - if (BE (mbclen > 0, 1)) + if (BE (mbclen + 2 > 2, 1)) { wchar_t wcu = wc; if (iswlower (wc)) { - int mbcdlen; + size_t mbcdlen; wcu = towupper (wc); mbcdlen = wcrtomb ((char *) buf, wcu, &prev_st); if (BE (mbclen == mbcdlen, 1)) memcpy (pstr->mbs + byte_idx, buf, mbclen); - else + else if (mbcdlen != (size_t) -1) { - int i; + size_t i; if (byte_idx + mbcdlen > pstr->bufs_len) { @@ -414,7 +400,7 @@ build_wcs_upper_buffer (pstr) } if (!pstr->offsets_needed) { - for (i = 0; i < byte_idx; ++i) + for (i = 0; i < (size_t) byte_idx; ++i) pstr->offsets[i] = i; pstr->offsets_needed = 1; } @@ -437,13 +423,15 @@ build_wcs_upper_buffer (pstr) src_idx += mbclen; continue; } + else + memcpy (pstr->mbs + byte_idx, p, mbclen); } else memcpy (pstr->mbs + byte_idx, p, mbclen); if (BE (pstr->offsets_needed != 0, 0)) { - int i; + size_t i; for (i = 0; i < mbclen; ++i) pstr->offsets[byte_idx + i] = src_idx + i; } @@ -488,14 +476,13 @@ build_wcs_upper_buffer (pstr) Return the index. */ static int -re_string_skip_chars (pstr, new_raw_idx, last_wc) - re_string_t *pstr; - int new_raw_idx; - wint_t *last_wc; +internal_function +re_string_skip_chars (re_string_t *pstr, int new_raw_idx, wint_t *last_wc) { mbstate_t prev_st; - int rawbuf_idx, mbclen; - wchar_t wc = 0; + int rawbuf_idx; + size_t mbclen; + wchar_t wc = WEOF; /* Skip the characters which are not necessary to check. */ for (rawbuf_idx = pstr->raw_mbs_idx + pstr->valid_raw_len; @@ -508,7 +495,11 @@ re_string_skip_chars (pstr, new_raw_idx, last_wc) remain_len, &pstr->cur_state); if (BE (mbclen == (size_t) -2 || mbclen == (size_t) -1 || mbclen == 0, 0)) { - /* We treat these cases as a singlebyte character. */ + /* We treat these cases as a single byte character. */ + if (mbclen == 0 || remain_len == 0) + wc = L'\0'; + else + wc = *(unsigned char *) (pstr->raw_mbs + rawbuf_idx); mbclen = 1; pstr->cur_state = prev_st; } @@ -524,8 +515,8 @@ re_string_skip_chars (pstr, new_raw_idx, last_wc) This function is used in case of REG_ICASE. */ static void -build_upper_buffer (pstr) - re_string_t *pstr; +internal_function +build_upper_buffer (re_string_t *pstr) { int char_idx, end_idx; end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; @@ -547,8 +538,8 @@ build_upper_buffer (pstr) /* Apply TRANS to the buffer in PSTR. */ static void -re_string_translate_buffer (pstr) - re_string_t *pstr; +internal_function +re_string_translate_buffer (re_string_t *pstr) { int buf_idx, end_idx; end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; @@ -568,9 +559,8 @@ re_string_translate_buffer (pstr) convert to upper case in case of REG_ICASE, apply translation. */ static reg_errcode_t -re_string_reconstruct (pstr, idx, eflags) - re_string_t *pstr; - int idx, eflags; +internal_function +re_string_reconstruct (re_string_t *pstr, int idx, int eflags) { int offset = idx - pstr->raw_mbs_idx; if (BE (offset < 0, 0)) @@ -595,34 +585,98 @@ re_string_reconstruct (pstr, idx, eflags) if (BE (offset != 0, 1)) { - /* Are the characters which are already checked remain? */ - if (BE (offset < pstr->valid_raw_len, 1) -#ifdef RE_ENABLE_I18N - /* Handling this would enlarge the code too much. - Accept a slowdown in that case. */ - && pstr->offsets_needed == 0 -#endif - ) + /* Should the already checked characters be kept? */ + if (BE (offset < pstr->valid_raw_len, 1)) { /* Yes, move them to the front of the buffer. */ - pstr->tip_context = re_string_context_at (pstr, offset - 1, eflags); #ifdef RE_ENABLE_I18N - if (pstr->mb_cur_max > 1) - memmove (pstr->wcs, pstr->wcs + offset, - (pstr->valid_len - offset) * sizeof (wint_t)); + if (BE (pstr->offsets_needed, 0)) + { + int low = 0, high = pstr->valid_len, mid; + do + { + mid = (high + low) / 2; + if (pstr->offsets[mid] > offset) + high = mid; + else if (pstr->offsets[mid] < offset) + low = mid + 1; + else + break; + } + while (low < high); + if (pstr->offsets[mid] < offset) + ++mid; + pstr->tip_context = re_string_context_at (pstr, mid - 1, + eflags); + /* This can be quite complicated, so handle specially + only the common and easy case where the character with + different length representation of lower and upper + case is present at or after offset. */ + if (pstr->valid_len > offset + && mid == offset && pstr->offsets[mid] == offset) + { + memmove (pstr->wcs, pstr->wcs + offset, + (pstr->valid_len - offset) * sizeof (wint_t)); + memmove (pstr->mbs, pstr->mbs + offset, pstr->valid_len - offset); + pstr->valid_len -= offset; + pstr->valid_raw_len -= offset; + for (low = 0; low < pstr->valid_len; low++) + pstr->offsets[low] = pstr->offsets[low + offset] - offset; + } + else + { + /* Otherwise, just find out how long the partial multibyte + character at offset is and fill it with WEOF/255. */ + pstr->len = pstr->raw_len - idx + offset; + pstr->stop = pstr->raw_stop - idx + offset; + pstr->offsets_needed = 0; + while (mid > 0 && pstr->offsets[mid - 1] == offset) + --mid; + while (mid < pstr->valid_len) + if (pstr->wcs[mid] != WEOF) + break; + else + ++mid; + if (mid == pstr->valid_len) + pstr->valid_len = 0; + else + { + pstr->valid_len = pstr->offsets[mid] - offset; + if (pstr->valid_len) + { + for (low = 0; low < pstr->valid_len; ++low) + pstr->wcs[low] = WEOF; + memset (pstr->mbs, 255, pstr->valid_len); + } + } + pstr->valid_raw_len = pstr->valid_len; + } + } + else +#endif + { + pstr->tip_context = re_string_context_at (pstr, offset - 1, + eflags); +#ifdef RE_ENABLE_I18N + if (pstr->mb_cur_max > 1) + memmove (pstr->wcs, pstr->wcs + offset, + (pstr->valid_len - offset) * sizeof (wint_t)); #endif /* RE_ENABLE_I18N */ - if (BE (pstr->mbs_allocated, 0)) - memmove (pstr->mbs, pstr->mbs + offset, - pstr->valid_len - offset); - pstr->valid_len -= offset; - pstr->valid_raw_len -= offset; + if (BE (pstr->mbs_allocated, 0)) + memmove (pstr->mbs, pstr->mbs + offset, + pstr->valid_len - offset); + pstr->valid_len -= offset; + pstr->valid_raw_len -= offset; #if DEBUG - assert (pstr->valid_len > 0); + assert (pstr->valid_len > 0); #endif + } } else { /* No, skip all characters until IDX. */ + int prev_valid_len = pstr->valid_len; + #ifdef RE_ENABLE_I18N if (BE (pstr->offsets_needed, 0)) { @@ -632,7 +686,6 @@ re_string_reconstruct (pstr, idx, eflags) } #endif pstr->valid_len = 0; - pstr->valid_raw_len = 0; #ifdef RE_ENABLE_I18N if (pstr->mb_cur_max > 1) { @@ -647,40 +700,66 @@ re_string_reconstruct (pstr, idx, eflags) byte other than 0x80 - 0xbf. */ raw = pstr->raw_mbs + pstr->raw_mbs_idx; end = raw + (offset - pstr->mb_cur_max); - for (p = raw + offset - 1; p >= end; --p) - if ((*p & 0xc0) != 0x80) - { - mbstate_t cur_state; - wchar_t wc2; - int mlen = raw + pstr->len - p; - unsigned char buf[6]; - - q = p; - if (BE (pstr->trans != NULL, 0)) - { - int i = mlen < 6 ? mlen : 6; - while (--i >= 0) - buf[i] = pstr->trans[p[i]]; - q = buf; - } - /* XXX Don't use mbrtowc, we know which conversion - to use (UTF-8 -> UCS4). */ - memset (&cur_state, 0, sizeof (cur_state)); - mlen = mbrtowc (&wc2, p, mlen, &cur_state) - - (raw + offset - p); - if (mlen >= 0) - { - memset (&pstr->cur_state, '\0', - sizeof (mbstate_t)); - pstr->valid_len = mlen; - wc = wc2; - } - break; - } + if (end < pstr->raw_mbs) + end = pstr->raw_mbs; + p = raw + offset - 1; +#ifdef _LIBC + /* We know the wchar_t encoding is UCS4, so for the simple + case, ASCII characters, skip the conversion step. */ + if (isascii (*p) && BE (pstr->trans == NULL, 1)) + { + memset (&pstr->cur_state, '\0', sizeof (mbstate_t)); + /* pstr->valid_len = 0; */ + wc = (wchar_t) *p; + } + else +#endif + for (; p >= end; --p) + if ((*p & 0xc0) != 0x80) + { + mbstate_t cur_state; + wchar_t wc2; + int mlen = raw + pstr->len - p; + unsigned char buf[6]; + size_t mbclen; + + q = p; + if (BE (pstr->trans != NULL, 0)) + { + int i = mlen < 6 ? mlen : 6; + while (--i >= 0) + buf[i] = pstr->trans[p[i]]; + q = buf; + } + /* XXX Don't use mbrtowc, we know which conversion + to use (UTF-8 -> UCS4). */ + memset (&cur_state, 0, sizeof (cur_state)); + mbclen = mbrtowc (&wc2, (const char *) p, mlen, + &cur_state); + if (raw + offset - p <= mbclen + && mbclen < (size_t) -2) + { + memset (&pstr->cur_state, '\0', + sizeof (mbstate_t)); + pstr->valid_len = mbclen - (raw + offset - p); + wc = wc2; + } + break; + } } if (wc == WEOF) pstr->valid_len = re_string_skip_chars (pstr, idx, &wc) - idx; + if (wc == WEOF) + pstr->tip_context + = re_string_context_at (pstr, prev_valid_len - 1, eflags); + else + pstr->tip_context = ((BE (pstr->word_ops_used != 0, 0) + && IS_WIDE_WORD_CHAR (wc)) + ? CONTEXT_WORD + : ((IS_WIDE_NEWLINE (wc) + && pstr->newline_anchor) + ? CONTEXT_NEWLINE : 0)); if (BE (pstr->valid_len, 0)) { for (wcs_idx = 0; wcs_idx < pstr->valid_len; ++wcs_idx) @@ -689,17 +768,12 @@ re_string_reconstruct (pstr, idx, eflags) memset (pstr->mbs, 255, pstr->valid_len); } pstr->valid_raw_len = pstr->valid_len; - pstr->tip_context = ((BE (pstr->word_ops_used != 0, 0) - && IS_WIDE_WORD_CHAR (wc)) - ? CONTEXT_WORD - : ((IS_WIDE_NEWLINE (wc) - && pstr->newline_anchor) - ? CONTEXT_NEWLINE : 0)); } else #endif /* RE_ENABLE_I18N */ { int c = pstr->raw_mbs[pstr->raw_mbs_idx + offset - 1]; + pstr->valid_raw_len = 0; if (pstr->trans) c = pstr->trans[c]; pstr->tip_context = (bitset_contain (pstr->word_char, c) @@ -721,7 +795,7 @@ re_string_reconstruct (pstr, idx, eflags) { if (pstr->icase) { - int ret = build_wcs_upper_buffer (pstr); + reg_errcode_t ret = build_wcs_upper_buffer (pstr); if (BE (ret != REG_NOERROR, 0)) return ret; } @@ -730,24 +804,23 @@ re_string_reconstruct (pstr, idx, eflags) } else #endif /* RE_ENABLE_I18N */ - if (BE (pstr->mbs_allocated, 0)) - { - if (pstr->icase) - build_upper_buffer (pstr); - else if (pstr->trans != NULL) - re_string_translate_buffer (pstr); - } - else - pstr->valid_len = pstr->len; + if (BE (pstr->mbs_allocated, 0)) + { + if (pstr->icase) + build_upper_buffer (pstr); + else if (pstr->trans != NULL) + re_string_translate_buffer (pstr); + } + else + pstr->valid_len = pstr->len; pstr->cur_idx = 0; return REG_NOERROR; } static unsigned char -re_string_peek_byte_case (pstr, idx) - const re_string_t *pstr; - int idx; +internal_function __attribute ((pure)) +re_string_peek_byte_case (const re_string_t *pstr, int idx) { int ch, off; @@ -782,8 +855,8 @@ re_string_peek_byte_case (pstr, idx) } static unsigned char -re_string_fetch_byte_case (pstr) - re_string_t *pstr; +internal_function __attribute ((pure)) +re_string_fetch_byte_case (re_string_t *pstr) { if (BE (!pstr->mbs_allocated, 1)) return re_string_fetch_byte (pstr); @@ -819,8 +892,8 @@ re_string_fetch_byte_case (pstr) } static void -re_string_destruct (pstr) - re_string_t *pstr; +internal_function +re_string_destruct (re_string_t *pstr) { #ifdef RE_ENABLE_I18N re_free (pstr->wcs); @@ -833,9 +906,8 @@ re_string_destruct (pstr) /* Return the context at IDX in INPUT. */ static unsigned int -re_string_context_at (input, idx, eflags) - const re_string_t *input; - int idx, eflags; +internal_function +re_string_context_at (const re_string_t *input, int idx, int eflags) { int c; if (BE (idx < 0, 0)) @@ -879,9 +951,8 @@ re_string_context_at (input, idx, eflags) /* Functions for set operation. */ static reg_errcode_t -re_node_set_alloc (set, size) - re_node_set *set; - int size; +internal_function +re_node_set_alloc (re_node_set *set, int size) { set->alloc = size; set->nelem = 0; @@ -892,9 +963,8 @@ re_node_set_alloc (set, size) } static reg_errcode_t -re_node_set_init_1 (set, elem) - re_node_set *set; - int elem; +internal_function +re_node_set_init_1 (re_node_set *set, int elem) { set->alloc = 1; set->nelem = 1; @@ -909,9 +979,8 @@ re_node_set_init_1 (set, elem) } static reg_errcode_t -re_node_set_init_2 (set, elem1, elem2) - re_node_set *set; - int elem1, elem2; +internal_function +re_node_set_init_2 (re_node_set *set, int elem1, int elem2) { set->alloc = 2; set->elems = re_malloc (int, 2); @@ -940,9 +1009,8 @@ re_node_set_init_2 (set, elem1, elem2) } static reg_errcode_t -re_node_set_init_copy (dest, src) - re_node_set *dest; - const re_node_set *src; +internal_function +re_node_set_init_copy (re_node_set *dest, const re_node_set *src) { dest->nelem = src->nelem; if (src->nelem > 0) @@ -966,9 +1034,9 @@ re_node_set_init_copy (dest, src) Note: We assume dest->elems is NULL, when dest->alloc is 0. */ static reg_errcode_t -re_node_set_add_intersect (dest, src1, src2) - re_node_set *dest; - const re_node_set *src1, *src2; +internal_function +re_node_set_add_intersect (re_node_set *dest, const re_node_set *src1, + const re_node_set *src2) { int i1, i2, is, id, delta, sbase; if (src1->nelem == 0 || src2->nelem == 0) @@ -1057,9 +1125,9 @@ re_node_set_add_intersect (dest, src1, src2) DEST. Return value indicate the error code or REG_NOERROR if succeeded. */ static reg_errcode_t -re_node_set_init_union (dest, src1, src2) - re_node_set *dest; - const re_node_set *src1, *src2; +internal_function +re_node_set_init_union (re_node_set *dest, const re_node_set *src1, + const re_node_set *src2) { int i1, i2, id; if (src1 != NULL && src1->nelem > 0 && src2 != NULL && src2->nelem > 0) @@ -1110,9 +1178,8 @@ re_node_set_init_union (dest, src1, src2) DEST. Return value indicate the error code or REG_NOERROR if succeeded. */ static reg_errcode_t -re_node_set_merge (dest, src) - re_node_set *dest; - const re_node_set *src; +internal_function +re_node_set_merge (re_node_set *dest, const re_node_set *src) { int is, id, sbase, delta; if (src == NULL || src->nelem == 0) @@ -1194,9 +1261,8 @@ re_node_set_merge (dest, src) return -1 if an error is occured, return 1 otherwise. */ static int -re_node_set_insert (set, elem) - re_node_set *set; - int elem; +internal_function +re_node_set_insert (re_node_set *set, int elem) { int idx; /* In case the set is empty. */ @@ -1219,12 +1285,12 @@ re_node_set_insert (set, elem) /* Realloc if we need. */ if (set->alloc == set->nelem) { - int *new_array; + int *new_elems; set->alloc = set->alloc * 2; - new_array = re_realloc (set->elems, int, set->alloc); - if (BE (new_array == NULL, 0)) + new_elems = re_realloc (set->elems, int, set->alloc); + if (BE (new_elems == NULL, 0)) return -1; - set->elems = new_array; + set->elems = new_elems; } /* Move the elements which follows the new element. Test the @@ -1252,19 +1318,18 @@ re_node_set_insert (set, elem) Return -1 if an error is occured, return 1 otherwise. */ static int -re_node_set_insert_last (set, elem) - re_node_set *set; - int elem; +internal_function +re_node_set_insert_last (re_node_set *set, int elem) { /* Realloc if we need. */ if (set->alloc == set->nelem) { - int *new_array; + int *new_elems; set->alloc = (set->alloc + 1) * 2; - new_array = re_realloc (set->elems, int, set->alloc); - if (BE (new_array == NULL, 0)) + new_elems = re_realloc (set->elems, int, set->alloc); + if (BE (new_elems == NULL, 0)) return -1; - set->elems = new_array; + set->elems = new_elems; } /* Insert the new element. */ @@ -1276,8 +1341,8 @@ re_node_set_insert_last (set, elem) return 1 if SET1 and SET2 are equivalent, return 0 otherwise. */ static int -re_node_set_compare (set1, set2) - const re_node_set *set1, *set2; +internal_function __attribute ((pure)) +re_node_set_compare (const re_node_set *set1, const re_node_set *set2) { int i; if (set1 == NULL || set2 == NULL || set1->nelem != set2->nelem) @@ -1291,9 +1356,8 @@ re_node_set_compare (set1, set2) /* Return (idx + 1) if SET contains the element ELEM, return 0 otherwise. */ static int -re_node_set_contains (set, elem) - const re_node_set *set; - int elem; +internal_function __attribute ((pure)) +re_node_set_contains (const re_node_set *set, int elem) { unsigned int idx, right, mid; if (set->nelem <= 0) @@ -1314,9 +1378,8 @@ re_node_set_contains (set, elem) } static void -re_node_set_remove_at (set, idx) - re_node_set *set; - int idx; +internal_function +re_node_set_remove_at (re_node_set *set, int idx) { if (idx < 0 || idx >= set->nelem) return; @@ -1330,54 +1393,53 @@ re_node_set_remove_at (set, idx) Or return -1, if an error will be occured. */ static int -re_dfa_add_node (dfa, token, mode) - re_dfa_t *dfa; - re_token_t token; - int mode; +internal_function +re_dfa_add_node (re_dfa_t *dfa, re_token_t token) { + int type = token.type; if (BE (dfa->nodes_len >= dfa->nodes_alloc, 0)) { - int new_nodes_alloc = dfa->nodes_alloc * 2; - re_token_t *new_array = re_realloc (dfa->nodes, re_token_t, - new_nodes_alloc); - if (BE (new_array == NULL, 0)) + size_t new_nodes_alloc = dfa->nodes_alloc * 2; + int *new_nexts, *new_indices; + re_node_set *new_edests, *new_eclosures; + re_token_t *new_nodes; + + /* Avoid overflows. */ + if (BE (new_nodes_alloc < dfa->nodes_alloc, 0)) return -1; - dfa->nodes = new_array; - if (mode) - { - int *new_nexts, *new_indices; - re_node_set *new_edests, *new_eclosures, *new_inveclosures; - - new_nexts = re_realloc (dfa->nexts, int, new_nodes_alloc); - new_indices = re_realloc (dfa->org_indices, int, new_nodes_alloc); - new_edests = re_realloc (dfa->edests, re_node_set, new_nodes_alloc); - new_eclosures = re_realloc (dfa->eclosures, re_node_set, - new_nodes_alloc); - new_inveclosures = re_realloc (dfa->inveclosures, re_node_set, - new_nodes_alloc); - if (BE (new_nexts == NULL || new_indices == NULL - || new_edests == NULL || new_eclosures == NULL - || new_inveclosures == NULL, 0)) - return -1; - dfa->nexts = new_nexts; - dfa->org_indices = new_indices; - dfa->edests = new_edests; - dfa->eclosures = new_eclosures; - dfa->inveclosures = new_inveclosures; - } + + new_nodes = re_realloc (dfa->nodes, re_token_t, new_nodes_alloc); + if (BE (new_nodes == NULL, 0)) + return -1; + dfa->nodes = new_nodes; + new_nexts = re_realloc (dfa->nexts, int, new_nodes_alloc); + new_indices = re_realloc (dfa->org_indices, int, new_nodes_alloc); + new_edests = re_realloc (dfa->edests, re_node_set, new_nodes_alloc); + new_eclosures = re_realloc (dfa->eclosures, re_node_set, new_nodes_alloc); + if (BE (new_nexts == NULL || new_indices == NULL + || new_edests == NULL || new_eclosures == NULL, 0)) + return -1; + dfa->nexts = new_nexts; + dfa->org_indices = new_indices; + dfa->edests = new_edests; + dfa->eclosures = new_eclosures; dfa->nodes_alloc = new_nodes_alloc; } dfa->nodes[dfa->nodes_len] = token; - dfa->nodes[dfa->nodes_len].opt_subexp = 0; - dfa->nodes[dfa->nodes_len].duplicated = 0; dfa->nodes[dfa->nodes_len].constraint = 0; +#ifdef RE_ENABLE_I18N + dfa->nodes[dfa->nodes_len].accept_mb = + (type == OP_PERIOD && dfa->mb_cur_max > 1) || type == COMPLEX_BRACKET; +#endif + dfa->nexts[dfa->nodes_len] = -1; + re_node_set_init_empty (dfa->edests + dfa->nodes_len); + re_node_set_init_empty (dfa->eclosures + dfa->nodes_len); return dfa->nodes_len++; } -static unsigned int inline -calc_state_hash (nodes, context) - const re_node_set *nodes; - unsigned int context; +static inline unsigned int +internal_function +calc_state_hash (const re_node_set *nodes, unsigned int context) { unsigned int hash = nodes->nelem + context; int i; @@ -1395,11 +1457,10 @@ calc_state_hash (nodes, context) - We never return non-NULL value in case of any errors, it is for optimization. */ -static re_dfastate_t* -re_acquire_state (err, dfa, nodes) - reg_errcode_t *err; - re_dfa_t *dfa; - const re_node_set *nodes; +static re_dfastate_t * +internal_function +re_acquire_state (reg_errcode_t *err, const re_dfa_t *dfa, + const re_node_set *nodes) { unsigned int hash; re_dfastate_t *new_state; @@ -1424,13 +1485,10 @@ re_acquire_state (err, dfa, nodes) /* There are no appropriate state in the dfa, create the new one. */ new_state = create_ci_newstate (dfa, nodes, hash); - if (BE (new_state != NULL, 1)) - return new_state; - else - { - *err = REG_ESPACE; - return NULL; - } + if (BE (new_state == NULL, 0)) + *err = REG_ESPACE; + + return new_state; } /* Search for the state whose node_set is equivalent to NODES and @@ -1443,12 +1501,10 @@ re_acquire_state (err, dfa, nodes) - We never return non-NULL value in case of any errors, it is for optimization. */ -static re_dfastate_t* -re_acquire_state_context (err, dfa, nodes, context) - reg_errcode_t *err; - re_dfa_t *dfa; - const re_node_set *nodes; - unsigned int context; +static re_dfastate_t * +internal_function +re_acquire_state_context (reg_errcode_t *err, const re_dfa_t *dfa, + const re_node_set *nodes, unsigned int context) { unsigned int hash; re_dfastate_t *new_state; @@ -1472,13 +1528,10 @@ re_acquire_state_context (err, dfa, nodes, context) } /* There are no appropriate state in `dfa', create the new one. */ new_state = create_cd_newstate (dfa, nodes, context, hash); - if (BE (new_state != NULL, 1)) - return new_state; - else - { - *err = REG_ESPACE; - return NULL; - } + if (BE (new_state == NULL, 0)) + *err = REG_ESPACE; + + return new_state; } /* Finish initialization of the new state NEWSTATE, and using its hash value @@ -1486,10 +1539,8 @@ re_acquire_state_context (err, dfa, nodes, context) indicates the error code if failed. */ static reg_errcode_t -register_state (dfa, newstate, hash) - re_dfa_t *dfa; - re_dfastate_t *newstate; - unsigned int hash; +register_state (const re_dfa_t *dfa, re_dfastate_t *newstate, + unsigned int hash) { struct re_state_table_entry *spot; reg_errcode_t err; @@ -1521,14 +1572,29 @@ register_state (dfa, newstate, hash) return REG_NOERROR; } +static void +free_state (re_dfastate_t *state) +{ + re_node_set_free (&state->non_eps_nodes); + re_node_set_free (&state->inveclosure); + if (state->entrance_nodes != &state->nodes) + { + re_node_set_free (state->entrance_nodes); + re_free (state->entrance_nodes); + } + re_node_set_free (&state->nodes); + re_free (state->word_trtable); + re_free (state->trtable); + re_free (state); +} + /* Create the new state which is independ of contexts. Return the new state if succeeded, otherwise return NULL. */ static re_dfastate_t * -create_ci_newstate (dfa, nodes, hash) - re_dfa_t *dfa; - const re_node_set *nodes; - unsigned int hash; +internal_function +create_ci_newstate (const re_dfa_t *dfa, const re_node_set *nodes, + unsigned int hash) { int i; reg_errcode_t err; @@ -1551,16 +1617,13 @@ create_ci_newstate (dfa, nodes, hash) re_token_type_t type = node->type; if (type == CHARACTER && !node->constraint) continue; +#ifdef RE_ENABLE_I18N + newstate->accept_mb |= node->accept_mb; +#endif /* RE_ENABLE_I18N */ /* If the state has the halt node, the state is a halt state. */ - else if (type == END_OF_RE) + if (type == END_OF_RE) newstate->halt = 1; -#ifdef RE_ENABLE_I18N - else if (type == COMPLEX_BRACKET - || type == OP_UTF8_PERIOD - || (type == OP_PERIOD && dfa->mb_cur_max > 1)) - newstate->accept_mb = 1; -#endif /* RE_ENABLE_I18N */ else if (type == OP_BACK_REF) newstate->has_backref = 1; else if (type == ANCHOR || node->constraint) @@ -1579,10 +1642,9 @@ create_ci_newstate (dfa, nodes, hash) Return the new state if succeeded, otherwise return NULL. */ static re_dfastate_t * -create_cd_newstate (dfa, nodes, context, hash) - re_dfa_t *dfa; - const re_node_set *nodes; - unsigned int context, hash; +internal_function +create_cd_newstate (const re_dfa_t *dfa, const re_node_set *nodes, + unsigned int context, unsigned int hash) { int i, nctx_nodes = 0; reg_errcode_t err; @@ -1611,15 +1673,13 @@ create_cd_newstate (dfa, nodes, context, hash) if (type == CHARACTER && !constraint) continue; - /* If the state has the halt node, the state is a halt state. */ - else if (type == END_OF_RE) - newstate->halt = 1; #ifdef RE_ENABLE_I18N - else if (type == COMPLEX_BRACKET - || type == OP_UTF8_PERIOD - || (type == OP_PERIOD && dfa->mb_cur_max > 1)) - newstate->accept_mb = 1; + newstate->accept_mb |= node->accept_mb; #endif /* RE_ENABLE_I18N */ + + /* If the state has the halt node, the state is a halt state. */ + if (type == END_OF_RE) + newstate->halt = 1; else if (type == OP_BACK_REF) newstate->has_backref = 1; else if (type == ANCHOR) @@ -1655,19 +1715,3 @@ create_cd_newstate (dfa, nodes, context, hash) } return newstate; } - -static void -free_state (state) - re_dfastate_t *state; -{ - re_node_set_free (&state->non_eps_nodes); - re_node_set_free (&state->inveclosure); - if (state->entrance_nodes != &state->nodes) - { - re_node_set_free (state->entrance_nodes); - re_free (state->entrance_nodes); - } - re_node_set_free (&state->nodes); - re_free (state->trtable); - re_free (state); -} diff --git a/posix/regex_internal.h b/posix/regex_internal.h index 0ccd8d3665..3b575c3c48 100644 --- a/posix/regex_internal.h +++ b/posix/regex_internal.h @@ -1,5 +1,5 @@ /* Extended regular expression matching and search library. - Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. @@ -39,6 +39,20 @@ #if defined HAVE_WCTYPE_H || defined _LIBC # include <wctype.h> #endif /* HAVE_WCTYPE_H || _LIBC */ +#if defined HAVE_STDBOOL_H || defined _LIBC +# include <stdbool.h> +#endif /* HAVE_STDBOOL_H || _LIBC */ +#if defined HAVE_STDINT_H || defined _LIBC +# include <stdint.h> +#endif /* HAVE_STDINT_H || _LIBC */ +#if defined _LIBC +# include <bits/libc-lock.h> +#else +# define __libc_lock_define(CLASS,NAME) +# define __libc_lock_init(NAME) do { } while (0) +# define __libc_lock_lock(NAME) do { } while (0) +# define __libc_lock_unlock(NAME) do { } while (0) +#endif /* In case that the system doesn't have isblank(). */ #if !defined _LIBC && !defined HAVE_ISBLANK && !defined isblank @@ -60,7 +74,7 @@ # ifdef _LIBC # undef gettext # define gettext(msgid) \ - INTUSE(__dcgettext) (INTUSE(_libc_intl_domainname), msgid, LC_MESSAGES) + INTUSE(__dcgettext) (_libc_intl_domainname, msgid, LC_MESSAGES) # endif #else # define gettext(msgid) (msgid) @@ -72,6 +86,11 @@ # define gettext_noop(String) String #endif +/* For loser systems without the definition. */ +#ifndef SIZE_MAX +# define SIZE_MAX ((size_t) -1) +#endif + #if (defined MB_CUR_MAX && HAVE_LOCALE_H && HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_WCRTOMB && HAVE_MBRTOWC && HAVE_WCSCOLL) || _LIBC # define RE_ENABLE_I18N #endif @@ -83,8 +102,6 @@ # define inline #endif -/* Number of bits in a byte. */ -#define BYTE_BITS 8 /* Number of single byte character. */ #define SBC_MAX 256 @@ -114,26 +131,28 @@ extern const char __re_error_msgid[] attribute_hidden; extern const size_t __re_error_msgid_idx[] attribute_hidden; -/* Number of bits in an unsinged int. */ -#define UINT_BITS (sizeof (unsigned int) * BYTE_BITS) -/* Number of unsigned int in an bit_set. */ -#define BITSET_UINTS ((SBC_MAX + UINT_BITS - 1) / UINT_BITS) -typedef unsigned int bitset[BITSET_UINTS]; -typedef unsigned int *re_bitset_ptr_t; -typedef const unsigned int *re_const_bitset_ptr_t; - -#define bitset_set(set,i) (set[i / UINT_BITS] |= 1 << i % UINT_BITS) -#define bitset_clear(set,i) (set[i / UINT_BITS] &= ~(1 << i % UINT_BITS)) -#define bitset_contain(set,i) (set[i / UINT_BITS] & (1 << i % UINT_BITS)) -#define bitset_empty(set) memset (set, 0, sizeof (unsigned int) * BITSET_UINTS) -#define bitset_set_all(set) \ - memset (set, 255, sizeof (unsigned int) * BITSET_UINTS) -#define bitset_copy(dest,src) \ - memcpy (dest, src, sizeof (unsigned int) * BITSET_UINTS) -static inline void bitset_not (bitset set); -static inline void bitset_merge (bitset dest, const bitset src); -static inline void bitset_not_merge (bitset dest, const bitset src); -static inline void bitset_mask (bitset dest, const bitset src); +/* An integer used to represent a set of bits. It must be unsigned, + and must be at least as wide as unsigned int. */ +typedef unsigned long int bitset_word_t; +/* All bits set in a bitset_word_t. */ +#define BITSET_WORD_MAX ULONG_MAX +/* Number of bits in a bitset_word_t. */ +#define BITSET_WORD_BITS (sizeof (bitset_word_t) * CHAR_BIT) +/* Number of bitset_word_t in a bit_set. */ +#define BITSET_WORDS (SBC_MAX / BITSET_WORD_BITS) +typedef bitset_word_t bitset_t[BITSET_WORDS]; +typedef bitset_word_t *re_bitset_ptr_t; +typedef const bitset_word_t *re_const_bitset_ptr_t; + +#define bitset_set(set,i) \ + (set[i / BITSET_WORD_BITS] |= (bitset_word_t) 1 << i % BITSET_WORD_BITS) +#define bitset_clear(set,i) \ + (set[i / BITSET_WORD_BITS] &= ~((bitset_word_t) 1 << i % BITSET_WORD_BITS)) +#define bitset_contain(set,i) \ + (set[i / BITSET_WORD_BITS] & ((bitset_word_t) 1 << i % BITSET_WORD_BITS)) +#define bitset_empty(set) memset (set, '\0', sizeof (bitset_t)) +#define bitset_set_all(set) memset (set, '\xff', sizeof (bitset_t)) +#define bitset_copy(dest,src) memcpy (dest, src, sizeof (bitset_t)) #define PREV_WORD_CONSTRAINT 0x0001 #define PREV_NOTWORD_CONSTRAINT 0x0002 @@ -143,18 +162,21 @@ static inline void bitset_mask (bitset dest, const bitset src); #define NEXT_NEWLINE_CONSTRAINT 0x0020 #define PREV_BEGBUF_CONSTRAINT 0x0040 #define NEXT_ENDBUF_CONSTRAINT 0x0080 -#define DUMMY_CONSTRAINT 0x0100 +#define WORD_DELIM_CONSTRAINT 0x0100 +#define NOT_WORD_DELIM_CONSTRAINT 0x0200 typedef enum { INSIDE_WORD = PREV_WORD_CONSTRAINT | NEXT_WORD_CONSTRAINT, WORD_FIRST = PREV_NOTWORD_CONSTRAINT | NEXT_WORD_CONSTRAINT, WORD_LAST = PREV_WORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT, + INSIDE_NOTWORD = PREV_NOTWORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT, LINE_FIRST = PREV_NEWLINE_CONSTRAINT, LINE_LAST = NEXT_NEWLINE_CONSTRAINT, BUF_FIRST = PREV_BEGBUF_CONSTRAINT, BUF_LAST = NEXT_ENDBUF_CONSTRAINT, - WORD_DELIM = DUMMY_CONSTRAINT + WORD_DELIM = WORD_DELIM_CONSTRAINT, + NOT_WORD_DELIM = NOT_WORD_DELIM_CONSTRAINT } re_context_type; typedef struct @@ -186,16 +208,16 @@ typedef enum OP_CLOSE_SUBEXP = EPSILON_BIT | 1, OP_ALT = EPSILON_BIT | 2, OP_DUP_ASTERISK = EPSILON_BIT | 3, - OP_DUP_PLUS = EPSILON_BIT | 4, - OP_DUP_QUESTION = EPSILON_BIT | 5, - ANCHOR = EPSILON_BIT | 6, - OP_DELETED_SUBEXP = EPSILON_BIT | 7, + ANCHOR = EPSILON_BIT | 4, /* Tree type, these are used only by tree. */ CONCAT = 16, + SUBEXP = 17, /* Token type, these are used only by token. */ - OP_OPEN_BRACKET = 17, + OP_DUP_PLUS = 18, + OP_DUP_QUESTION, + OP_OPEN_BRACKET, OP_CLOSE_BRACKET, OP_CHARSET_RANGE, OP_OPEN_DUP_NUM, @@ -284,6 +306,7 @@ typedef struct unsigned int duplicated : 1; unsigned int opt_subexp : 1; #ifdef RE_ENABLE_I18N + unsigned int accept_mb : 1; /* These 2 bits can be moved into the union if needed (e.g. if running out of bits; move opr.c to opr.c.c and move the flags to opr.c.flags). */ unsigned int mb_partial : 1; @@ -292,8 +315,6 @@ typedef struct } re_token_t; #define IS_EPSILON_NODE(type) ((type) & EPSILON_BIT) -#define ACCEPT_MB_NODE(type) \ - ((type) >= OP_PERIOD && (type) <= OP_UTF8_PERIOD) struct re_string_t { @@ -337,7 +358,7 @@ struct re_string_t the beginning of the input string. */ unsigned int tip_context; /* The translation passed as a part of an argument of re_compile_pattern. */ - unsigned RE_TRANSLATE_TYPE trans; + RE_TRANSLATE_TYPE trans; /* Copy of re_dfa_t's word_char. */ re_const_bitset_ptr_t word_char; /* 1 if REG_ICASE. */ @@ -364,45 +385,18 @@ typedef struct re_dfa_t re_dfa_t; # endif #endif -#ifndef RE_NO_INTERNAL_PROTOTYPES -static reg_errcode_t re_string_allocate (re_string_t *pstr, const char *str, - int len, int init_len, - RE_TRANSLATE_TYPE trans, int icase, - const re_dfa_t *dfa) - internal_function; -static reg_errcode_t re_string_construct (re_string_t *pstr, const char *str, - int len, RE_TRANSLATE_TYPE trans, - int icase, const re_dfa_t *dfa) - internal_function; -static reg_errcode_t re_string_reconstruct (re_string_t *pstr, int idx, - int eflags) internal_function; static reg_errcode_t re_string_realloc_buffers (re_string_t *pstr, int new_buf_len) internal_function; -# ifdef RE_ENABLE_I18N +#ifdef RE_ENABLE_I18N static void build_wcs_buffer (re_string_t *pstr) internal_function; static int build_wcs_upper_buffer (re_string_t *pstr) internal_function; -# endif /* RE_ENABLE_I18N */ +#endif /* RE_ENABLE_I18N */ static void build_upper_buffer (re_string_t *pstr) internal_function; static void re_string_translate_buffer (re_string_t *pstr) internal_function; -static void re_string_destruct (re_string_t *pstr) internal_function; -# ifdef RE_ENABLE_I18N -static int re_string_elem_size_at (const re_string_t *pstr, int idx) - internal_function __attribute ((pure)); -static inline int re_string_char_size_at (const re_string_t *pstr, int idx) - internal_function __attribute ((pure)); -static inline wint_t re_string_wchar_at (const re_string_t *pstr, int idx) - internal_function __attribute ((pure)); -# endif /* RE_ENABLE_I18N */ static unsigned int re_string_context_at (const re_string_t *input, int idx, int eflags) internal_function __attribute ((pure)); -static unsigned char re_string_peek_byte_case (const re_string_t *pstr, - int idx) - internal_function __attribute ((pure)); -static unsigned char re_string_fetch_byte_case (re_string_t *pstr) - internal_function __attribute ((pure)); -#endif #define re_string_peek_byte(pstr, offset) \ ((pstr)->mbs[(pstr)->cur_idx + offset]) #define re_string_fetch_byte(pstr) \ @@ -420,6 +414,21 @@ static unsigned char re_string_fetch_byte_case (re_string_t *pstr) #define re_string_skip_bytes(pstr,idx) ((pstr)->cur_idx += (idx)) #define re_string_set_index(pstr,idx) ((pstr)->cur_idx = (idx)) +#include <alloca.h> + +#ifndef _LIBC +# if HAVE_ALLOCA +/* The OS usually guarantees only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + allocate anything larger than 4096 bytes. Also care for the possibility + of a few compiler-allocated temporary stack slots. */ +# define __libc_use_alloca(n) ((n) < 4032) +# else +/* alloca is implemented with malloc, so just use malloc. */ +# define __libc_use_alloca(n) 0 +# endif +#endif + #define re_malloc(t,n) ((t *) malloc ((n) * sizeof (t))) #define re_realloc(p,t,n) ((t *) realloc (p, (n) * sizeof (t))) #define re_free(p) free (p) @@ -429,15 +438,14 @@ struct bin_tree_t struct bin_tree_t *parent; struct bin_tree_t *left; struct bin_tree_t *right; + struct bin_tree_t *first; + struct bin_tree_t *next; + + re_token_t token; /* `node_idx' is the index in dfa->nodes, if `type' == 0. Otherwise `type' indicate the type of this node. */ - re_token_type_t type; int node_idx; - - int first; - int next; - re_node_set eclosure; }; typedef struct bin_tree_t bin_tree_t; @@ -486,7 +494,7 @@ struct re_dfastate_t re_node_set non_eps_nodes; re_node_set inveclosure; re_node_set *entrance_nodes; - struct re_dfastate_t **trtable; + struct re_dfastate_t **trtable, **word_trtable; unsigned int context : 4; unsigned int halt : 1; /* If this state can accept `multi byte'. @@ -496,7 +504,6 @@ struct re_dfastate_t /* If this state has backreference node(s). */ unsigned int has_backref : 1; unsigned int has_constraint : 1; - unsigned int word_trtable : 1; }; typedef struct re_dfastate_t re_dfastate_t; @@ -533,7 +540,6 @@ typedef struct { int str_idx; int node; - int next_last_offset; state_array_t *path; int alasts; /* Allocation size of LASTS. */ int nlasts; /* The number of LASTS. */ @@ -556,9 +562,9 @@ typedef struct /* The string object corresponding to the input string. */ re_string_t input; #if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) - re_dfa_t *const dfa; + const re_dfa_t *const dfa; #else - re_dfa_t *dfa; + const re_dfa_t *dfa; #endif /* EFLAGS of the argument of regexec. */ int eflags; @@ -605,8 +611,8 @@ struct re_fail_stack_t struct re_dfa_t { re_token_t *nodes; - int nodes_alloc; - int nodes_len; + size_t nodes_alloc; + size_t nodes_len; int *nexts; int *org_indices; re_node_set *edests; @@ -624,13 +630,12 @@ struct re_dfa_t /* number of subexpressions `re_nsub' is in regex_t. */ unsigned int state_hash_mask; - int states_alloc; int init_node; int nbackref; /* The number of backreference in this dfa. */ /* Bitmap expressing which backreference is used. */ - unsigned int used_bkref_map; - unsigned int completed_bkref_map; + bitset_word_t used_bkref_map; + bitset_word_t completed_bkref_map; unsigned int has_plural_match : 1; /* If this dfa has "multibyte node", which is a backreference or @@ -641,52 +646,20 @@ struct re_dfa_t unsigned int map_notascii : 1; unsigned int word_ops_used : 1; int mb_cur_max; - bitset word_char; + bitset_t word_char; reg_syntax_t syntax; int *subexp_map; #ifdef DEBUG char* re_str; #endif + __libc_lock_define (, lock) }; -#ifndef RE_NO_INTERNAL_PROTOTYPES -static reg_errcode_t re_node_set_alloc (re_node_set *set, int size) internal_function; -static reg_errcode_t re_node_set_init_1 (re_node_set *set, int elem) internal_function; -static reg_errcode_t re_node_set_init_2 (re_node_set *set, int elem1, - int elem2) internal_function; #define re_node_set_init_empty(set) memset (set, '\0', sizeof (re_node_set)) -static reg_errcode_t re_node_set_init_copy (re_node_set *dest, - const re_node_set *src) internal_function; -static reg_errcode_t re_node_set_add_intersect (re_node_set *dest, - const re_node_set *src1, - const re_node_set *src2) internal_function; -static reg_errcode_t re_node_set_init_union (re_node_set *dest, - const re_node_set *src1, - const re_node_set *src2) internal_function; -static reg_errcode_t re_node_set_merge (re_node_set *dest, - const re_node_set *src) internal_function; -static int re_node_set_insert (re_node_set *set, int elem) internal_function; -static int re_node_set_insert_last (re_node_set *set, - int elem) internal_function; -static int re_node_set_compare (const re_node_set *set1, - const re_node_set *set2) - internal_function __attribute ((pure)); -static int re_node_set_contains (const re_node_set *set, int elem) - internal_function __attribute ((pure)); -static void re_node_set_remove_at (re_node_set *set, int idx) internal_function; #define re_node_set_remove(set,id) \ (re_node_set_remove_at (set, re_node_set_contains (set, id) - 1)) #define re_node_set_empty(p) ((p)->nelem = 0) #define re_node_set_free(set) re_free ((set)->elems) -static int re_dfa_add_node (re_dfa_t *dfa, re_token_t token, int mode) internal_function; -static re_dfastate_t *re_acquire_state (reg_errcode_t *err, re_dfa_t *dfa, - const re_node_set *nodes) internal_function; -static re_dfastate_t *re_acquire_state_context (reg_errcode_t *err, - re_dfa_t *dfa, - const re_node_set *nodes, - unsigned int context) internal_function; -static void free_state (re_dfastate_t *state) internal_function; -#endif typedef enum @@ -712,41 +685,33 @@ typedef struct /* Inline functions for bitset operation. */ static inline void -bitset_not (bitset set) +bitset_not (bitset_t set) { int bitset_i; - for (bitset_i = 0; bitset_i < BITSET_UINTS; ++bitset_i) + for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i) set[bitset_i] = ~set[bitset_i]; } static inline void -bitset_merge (bitset dest, const bitset src) +bitset_merge (bitset_t dest, const bitset_t src) { int bitset_i; - for (bitset_i = 0; bitset_i < BITSET_UINTS; ++bitset_i) + for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i) dest[bitset_i] |= src[bitset_i]; } static inline void -bitset_not_merge (bitset dest, const bitset src) -{ - int i; - for (i = 0; i < BITSET_UINTS; ++i) - dest[i] |= ~src[i]; -} - -static inline void -bitset_mask (bitset dest, const bitset src) +bitset_mask (bitset_t dest, const bitset_t src) { int bitset_i; - for (bitset_i = 0; bitset_i < BITSET_UINTS; ++bitset_i) + for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i) dest[bitset_i] &= src[bitset_i]; } -#if defined RE_ENABLE_I18N && !defined RE_NO_INTERNAL_PROTOTYPES +#ifdef RE_ENABLE_I18N /* Inline functions for re_string. */ static inline int -internal_function +internal_function __attribute ((pure)) re_string_char_size_at (const re_string_t *pstr, int idx) { int byte_idx; @@ -759,7 +724,7 @@ re_string_char_size_at (const re_string_t *pstr, int idx) } static inline wint_t -internal_function +internal_function __attribute ((pure)) re_string_wchar_at (const re_string_t *pstr, int idx) { if (pstr->mb_cur_max == 1) @@ -768,14 +733,14 @@ re_string_wchar_at (const re_string_t *pstr, int idx) } static int -internal_function +internal_function __attribute ((pure)) re_string_elem_size_at (const re_string_t *pstr, int idx) { -#ifdef _LIBC +# ifdef _LIBC const unsigned char *p, *extra; const int32_t *table, *indirect; int32_t tmp; -# include <locale/weight.h> +# include <locale/weight.h> uint_fast32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); if (nrules != 0) @@ -790,7 +755,7 @@ re_string_elem_size_at (const re_string_t *pstr, int idx) return p - pstr->mbs - idx; } else -#endif /* _LIBC */ +# endif /* _LIBC */ return 1; } #endif /* RE_ENABLE_I18N */ diff --git a/posix/regexec.c b/posix/regexec.c index 91b48dd4a2..bdfa3550a7 100644 --- a/posix/regexec.c +++ b/posix/regexec.c @@ -1,5 +1,5 @@ /* Extended regular expression matching and search library. - Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. @@ -25,7 +25,7 @@ static void match_ctx_free (re_match_context_t *cache) internal_function; static reg_errcode_t match_ctx_add_entry (re_match_context_t *cache, int node, int str_idx, int from, int to) internal_function; -static int search_cur_bkref_entry (re_match_context_t *mctx, int str_idx) +static int search_cur_bkref_entry (const re_match_context_t *mctx, int str_idx) internal_function; static reg_errcode_t match_ctx_add_subtop (re_match_context_t *mctx, int node, int str_idx) internal_function; @@ -52,81 +52,76 @@ static int re_search_stub (struct re_pattern_buffer *bufp, int ret_len) internal_function; static unsigned re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, int nregs, int regs_allocated) internal_function; -static inline re_dfastate_t *acquire_init_state_context - (reg_errcode_t *err, const re_match_context_t *mctx, int idx) - __attribute ((always_inline)) internal_function; static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx) internal_function; static int check_matching (re_match_context_t *mctx, int fl_longest_match, - int *p_match_first) - internal_function; -static int check_halt_node_context (const re_dfa_t *dfa, int node, - unsigned int context) internal_function; + int *p_match_first) internal_function; static int check_halt_state_context (const re_match_context_t *mctx, const re_dfastate_t *state, int idx) internal_function; -static void update_regs (re_dfa_t *dfa, regmatch_t *pmatch, +static void update_regs (const re_dfa_t *dfa, regmatch_t *pmatch, regmatch_t *prev_idx_match, int cur_node, int cur_idx, int nmatch) internal_function; -static int proceed_next_node (const re_match_context_t *mctx, - int nregs, regmatch_t *regs, - int *pidx, int node, re_node_set *eps_via_nodes, - struct re_fail_stack_t *fs) internal_function; static reg_errcode_t push_fail_stack (struct re_fail_stack_t *fs, int str_idx, int dest_node, int nregs, regmatch_t *regs, - re_node_set *eps_via_nodes) internal_function; -static int pop_fail_stack (struct re_fail_stack_t *fs, int *pidx, int nregs, - regmatch_t *regs, re_node_set *eps_via_nodes) internal_function; + re_node_set *eps_via_nodes) + internal_function; static reg_errcode_t set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch, regmatch_t *pmatch, int fl_backtrack) internal_function; -static reg_errcode_t free_fail_stack_return (struct re_fail_stack_t *fs) internal_function; +static reg_errcode_t free_fail_stack_return (struct re_fail_stack_t *fs) + internal_function; #ifdef RE_ENABLE_I18N static int sift_states_iter_mb (const re_match_context_t *mctx, re_sift_context_t *sctx, - int node_idx, int str_idx, int max_str_idx) internal_function; + int node_idx, int str_idx, int max_str_idx) + internal_function; #endif /* RE_ENABLE_I18N */ -static reg_errcode_t sift_states_backward (re_match_context_t *mctx, - re_sift_context_t *sctx) internal_function; -static reg_errcode_t build_sifted_states (re_match_context_t *mctx, +static reg_errcode_t sift_states_backward (const re_match_context_t *mctx, + re_sift_context_t *sctx) + internal_function; +static reg_errcode_t build_sifted_states (const re_match_context_t *mctx, re_sift_context_t *sctx, int str_idx, - re_node_set *cur_dest) internal_function; -static reg_errcode_t update_cur_sifted_state (re_match_context_t *mctx, + re_node_set *cur_dest) + internal_function; +static reg_errcode_t update_cur_sifted_state (const re_match_context_t *mctx, re_sift_context_t *sctx, int str_idx, - re_node_set *dest_nodes) internal_function; -static reg_errcode_t add_epsilon_src_nodes (re_dfa_t *dfa, - re_node_set *dest_nodes, - const re_node_set *candidates) internal_function; -static reg_errcode_t sub_epsilon_src_nodes (re_dfa_t *dfa, int node, + re_node_set *dest_nodes) + internal_function; +static reg_errcode_t add_epsilon_src_nodes (const re_dfa_t *dfa, re_node_set *dest_nodes, - const re_node_set *and_nodes) internal_function; -static int check_dst_limits (re_match_context_t *mctx, re_node_set *limits, + const re_node_set *candidates) + internal_function; +static int check_dst_limits (const re_match_context_t *mctx, + re_node_set *limits, int dst_node, int dst_idx, int src_node, int src_idx) internal_function; -static int check_dst_limits_calc_pos_1 (re_match_context_t *mctx, +static int check_dst_limits_calc_pos_1 (const re_match_context_t *mctx, int boundaries, int subexp_idx, - int from_node, int bkref_idx) internal_function; -static int check_dst_limits_calc_pos (re_match_context_t *mctx, + int from_node, int bkref_idx) + internal_function; +static int check_dst_limits_calc_pos (const re_match_context_t *mctx, int limit, int subexp_idx, int node, int str_idx, int bkref_idx) internal_function; -static reg_errcode_t check_subexp_limits (re_dfa_t *dfa, +static reg_errcode_t check_subexp_limits (const re_dfa_t *dfa, re_node_set *dest_nodes, const re_node_set *candidates, re_node_set *limits, struct re_backref_cache_entry *bkref_ents, int str_idx) internal_function; -static reg_errcode_t sift_states_bkref (re_match_context_t *mctx, +static reg_errcode_t sift_states_bkref (const re_match_context_t *mctx, re_sift_context_t *sctx, - int str_idx, const re_node_set *candidates) internal_function; -static reg_errcode_t clean_state_log_if_needed (re_match_context_t *mctx, - int next_state_log_idx) internal_function; -static reg_errcode_t merge_state_array (re_dfa_t *dfa, re_dfastate_t **dst, - re_dfastate_t **src, int num) internal_function; + int str_idx, const re_node_set *candidates) + internal_function; +static reg_errcode_t merge_state_array (const re_dfa_t *dfa, + re_dfastate_t **dst, + re_dfastate_t **src, int num) + internal_function; static re_dfastate_t *find_recover_state (reg_errcode_t *err, re_match_context_t *mctx) internal_function; static re_dfastate_t *transit_state (reg_errcode_t *err, @@ -134,27 +129,33 @@ static re_dfastate_t *transit_state (reg_errcode_t *err, re_dfastate_t *state) internal_function; static re_dfastate_t *merge_state_with_log (reg_errcode_t *err, re_match_context_t *mctx, - re_dfastate_t *next_state) internal_function; + re_dfastate_t *next_state) + internal_function; static reg_errcode_t check_subexp_matching_top (re_match_context_t *mctx, re_node_set *cur_nodes, int str_idx) internal_function; #if 0 static re_dfastate_t *transit_state_sb (reg_errcode_t *err, re_match_context_t *mctx, - re_dfastate_t *pstate) internal_function; + re_dfastate_t *pstate) + internal_function; #endif #ifdef RE_ENABLE_I18N static reg_errcode_t transit_state_mb (re_match_context_t *mctx, - re_dfastate_t *pstate) internal_function; + re_dfastate_t *pstate) + internal_function; #endif /* RE_ENABLE_I18N */ static reg_errcode_t transit_state_bkref (re_match_context_t *mctx, - const re_node_set *nodes) internal_function; + const re_node_set *nodes) + internal_function; static reg_errcode_t get_subexp (re_match_context_t *mctx, - int bkref_node, int bkref_str_idx) internal_function; + int bkref_node, int bkref_str_idx) + internal_function; static reg_errcode_t get_subexp_sub (re_match_context_t *mctx, const re_sub_match_top_t *sub_top, re_sub_match_last_t *sub_last, - int bkref_node, int bkref_str) internal_function; + int bkref_node, int bkref_str) + internal_function; static int find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes, int subexp_idx, int type) internal_function; static reg_errcode_t check_arrival (re_match_context_t *mctx, @@ -164,34 +165,41 @@ static reg_errcode_t check_arrival (re_match_context_t *mctx, static reg_errcode_t check_arrival_add_next_nodes (re_match_context_t *mctx, int str_idx, re_node_set *cur_nodes, - re_node_set *next_nodes) internal_function; -static reg_errcode_t check_arrival_expand_ecl (re_dfa_t *dfa, + re_node_set *next_nodes) + internal_function; +static reg_errcode_t check_arrival_expand_ecl (const re_dfa_t *dfa, re_node_set *cur_nodes, - int ex_subexp, int type) internal_function; -static reg_errcode_t check_arrival_expand_ecl_sub (re_dfa_t *dfa, + int ex_subexp, int type) + internal_function; +static reg_errcode_t check_arrival_expand_ecl_sub (const re_dfa_t *dfa, re_node_set *dst_nodes, int target, int ex_subexp, int type) internal_function; static reg_errcode_t expand_bkref_cache (re_match_context_t *mctx, re_node_set *cur_nodes, int cur_str, - int subexp_num, int type) internal_function; -static re_dfastate_t **build_trtable (re_dfa_t *dfa, - re_dfastate_t *state) internal_function; + int subexp_num, int type) + internal_function; +static int build_trtable (const re_dfa_t *dfa, + re_dfastate_t *state) internal_function; #ifdef RE_ENABLE_I18N -static int check_node_accept_bytes (re_dfa_t *dfa, int node_idx, - const re_string_t *input, int idx) internal_function; +static int check_node_accept_bytes (const re_dfa_t *dfa, int node_idx, + const re_string_t *input, int idx) + internal_function; # ifdef _LIBC static unsigned int find_collation_sequence_value (const unsigned char *mbs, - size_t name_len) internal_function; + size_t name_len) + internal_function; # endif /* _LIBC */ #endif /* RE_ENABLE_I18N */ -static int group_nodes_into_DFAstates (re_dfa_t *dfa, +static int group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *state, re_node_set *states_node, - bitset *states_ch) internal_function; + bitset_t *states_ch) internal_function; static int check_node_accept (const re_match_context_t *mctx, - const re_token_t *node, int idx) internal_function; -static reg_errcode_t extend_buffers (re_match_context_t *mctx) internal_function; + const re_token_t *node, int idx) + internal_function; +static reg_errcode_t extend_buffers (re_match_context_t *mctx) + internal_function; /* Entry point for POSIX code. */ @@ -219,6 +227,7 @@ regexec (preg, string, nmatch, pmatch, eflags) { reg_errcode_t err; int start, length; + re_dfa_t *dfa = (re_dfa_t *) preg->buffer; if (eflags & ~(REG_NOTBOL | REG_NOTEOL | REG_STARTEND)) return REG_BADPAT; @@ -233,12 +242,15 @@ regexec (preg, string, nmatch, pmatch, eflags) start = 0; length = strlen (string); } + + __libc_lock_lock (dfa->lock); if (preg->no_sub) err = re_search_internal (preg, string, length, start, length - start, length, 0, NULL, eflags); else err = re_search_internal (preg, string, length, start, length - start, length, nmatch, pmatch, eflags); + __libc_lock_unlock (dfa->lock); return err != REG_NOERROR; } @@ -369,8 +381,12 @@ re_search_2_stub (bufp, string1, length1, string2, length2, start, range, regs, if (BE (s == NULL, 0)) return -2; +#ifdef _LIBC + memcpy (__mempcpy (s, string1, length1), string2, length2); +#else memcpy (s, string1, length1); memcpy (s + length1, string2, length2); +#endif str = s; free_str = 1; } @@ -402,6 +418,7 @@ re_search_stub (bufp, string, length, start, range, stop, regs, ret_len) regmatch_t *pmatch; int nregs, rval; int eflags = 0; + re_dfa_t *dfa = (re_dfa_t *) bufp->buffer; /* Check for out-of-range. */ if (BE (start < 0 || start > length, 0)) @@ -411,6 +428,8 @@ re_search_stub (bufp, string, length, start, range, stop, regs, ret_len) else if (BE (start + range < 0, 0)) range = -start; + __libc_lock_lock (dfa->lock); + eflags |= (bufp->not_bol) ? REG_NOTBOL : 0; eflags |= (bufp->not_eol) ? REG_NOTEOL : 0; @@ -439,7 +458,10 @@ re_search_stub (bufp, string, length, start, range, stop, regs, ret_len) nregs = bufp->re_nsub + 1; pmatch = re_malloc (regmatch_t, nregs); if (BE (pmatch == NULL, 0)) - return -2; + { + rval = -2; + goto out; + } result = re_search_internal (bufp, string, length, start, range, stop, nregs, pmatch, eflags); @@ -469,6 +491,8 @@ re_search_stub (bufp, string, length, start, range, stop, regs, ret_len) rval = pmatch[0].rm_so; } re_free (pmatch); + out: + __libc_lock_unlock (dfa->lock); return rval; } @@ -602,9 +626,10 @@ re_search_internal (preg, string, length, start, range, stop, nmatch, pmatch, regmatch_t pmatch[]; { reg_errcode_t err; - re_dfa_t *dfa = (re_dfa_t *)preg->buffer; + const re_dfa_t *dfa = (const re_dfa_t *) preg->buffer; int left_lim, right_lim, incr; int fl_longest_match, match_first, match_kind, match_last = -1; + int extra_nmatch; int sb, ch; #if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) re_match_context_t mctx = { .dfa = dfa }; @@ -613,13 +638,16 @@ re_search_internal (preg, string, length, start, range, stop, nmatch, pmatch, #endif char *fastmap = (preg->fastmap != NULL && preg->fastmap_accurate && range && !preg->can_be_null) ? preg->fastmap : NULL; - unsigned RE_TRANSLATE_TYPE t = (unsigned RE_TRANSLATE_TYPE) preg->translate; + RE_TRANSLATE_TYPE t = preg->translate; #if !(defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)) memset (&mctx, '\0', sizeof (re_match_context_t)); mctx.dfa = dfa; #endif + extra_nmatch = (nmatch > preg->re_nsub) ? nmatch - (preg->re_nsub + 1) : 0; + nmatch -= extra_nmatch; + /* Check if the DFA haven't been compiled. */ if (BE (preg->used == 0 || dfa->init_state == NULL || dfa->init_state_word == NULL || dfa->init_state_nl == NULL @@ -867,14 +895,14 @@ re_search_internal (preg, string, length, start, range, stop, nmatch, pmatch, #ifdef RE_ENABLE_I18N if (BE (mctx.input.offsets_needed != 0, 0)) { - if (pmatch[reg_idx].rm_so == mctx.input.valid_len) - pmatch[reg_idx].rm_so += mctx.input.valid_raw_len - mctx.input.valid_len; - else - pmatch[reg_idx].rm_so = mctx.input.offsets[pmatch[reg_idx].rm_so]; - if (pmatch[reg_idx].rm_eo == mctx.input.valid_len) - pmatch[reg_idx].rm_eo += mctx.input.valid_raw_len - mctx.input.valid_len; - else - pmatch[reg_idx].rm_eo = mctx.input.offsets[pmatch[reg_idx].rm_eo]; + pmatch[reg_idx].rm_so = + (pmatch[reg_idx].rm_so == mctx.input.valid_len + ? mctx.input.valid_raw_len + : mctx.input.offsets[pmatch[reg_idx].rm_so]); + pmatch[reg_idx].rm_eo = + (pmatch[reg_idx].rm_eo == mctx.input.valid_len + ? mctx.input.valid_raw_len + : mctx.input.offsets[pmatch[reg_idx].rm_eo]); } #else assert (mctx.input.offsets_needed == 0); @@ -882,11 +910,14 @@ re_search_internal (preg, string, length, start, range, stop, nmatch, pmatch, pmatch[reg_idx].rm_so += match_first; pmatch[reg_idx].rm_eo += match_first; } + for (reg_idx = 0; reg_idx < extra_nmatch; ++reg_idx) + { + pmatch[nmatch + reg_idx].rm_so = -1; + pmatch[nmatch + reg_idx].rm_eo = -1; + } if (dfa->subexp_map) - for (reg_idx = 0; - reg_idx + 1 < nmatch && reg_idx < preg->re_nsub; - reg_idx++) + for (reg_idx = 0; reg_idx + 1 < nmatch; reg_idx++) if (dfa->subexp_map[reg_idx] != reg_idx) { pmatch[reg_idx + 1].rm_so @@ -908,7 +939,7 @@ static reg_errcode_t prune_impossible_nodes (mctx) re_match_context_t *mctx; { - re_dfa_t *const dfa = mctx->dfa; + const re_dfa_t *const dfa = mctx->dfa; int halt_node, match_last; reg_errcode_t ret; re_dfastate_t **sifted_states; @@ -991,12 +1022,11 @@ prune_impossible_nodes (mctx) since initial states may have constraints like "\<", "^", etc.. */ static inline re_dfastate_t * -acquire_init_state_context (err, mctx, idx) - reg_errcode_t *err; - const re_match_context_t *mctx; - int idx; +__attribute ((always_inline)) internal_function +acquire_init_state_context (reg_errcode_t *err, const re_match_context_t *mctx, + int idx) { - re_dfa_t *const dfa = mctx->dfa; + const re_dfa_t *const dfa = mctx->dfa; if (dfa->init_state->has_constraint) { unsigned int context; @@ -1034,12 +1064,11 @@ acquire_init_state_context (err, mctx, idx) index of the buffer. */ static int -check_matching (mctx, fl_longest_match, p_match_first) - re_match_context_t *mctx; - int fl_longest_match; - int *p_match_first; +internal_function +check_matching (re_match_context_t *mctx, int fl_longest_match, + int *p_match_first) { - re_dfa_t *const dfa = mctx->dfa; + const re_dfa_t *const dfa = mctx->dfa; reg_errcode_t err; int match = 0; int match_last = -1; @@ -1166,10 +1195,9 @@ check_matching (mctx, fl_longest_match, p_match_first) /* Check NODE match the current context. */ -static int check_halt_node_context (dfa, node, context) - const re_dfa_t *dfa; - int node; - unsigned int context; +static int +internal_function +check_halt_node_context (const re_dfa_t *dfa, int node, unsigned int context) { re_token_type_t type = dfa->nodes[node].type; unsigned int constraint = dfa->nodes[node].constraint; @@ -1187,10 +1215,9 @@ static int check_halt_node_context (dfa, node, context) match the context, return the node. */ static int -check_halt_state_context (mctx, state, idx) - const re_match_context_t *mctx; - const re_dfastate_t *state; - int idx; +internal_function +check_halt_state_context (const re_match_context_t *mctx, + const re_dfastate_t *state, int idx) { int i; unsigned int context; @@ -1210,16 +1237,13 @@ check_halt_state_context (mctx, state, idx) of errors. */ static int -proceed_next_node (mctx, nregs, regs, pidx, node, eps_via_nodes, fs) - const re_match_context_t *mctx; - regmatch_t *regs; - int nregs, *pidx, node; - re_node_set *eps_via_nodes; - struct re_fail_stack_t *fs; +internal_function +proceed_next_node (const re_match_context_t *mctx, int nregs, regmatch_t *regs, + int *pidx, int node, re_node_set *eps_via_nodes, + struct re_fail_stack_t *fs) { - re_dfa_t *const dfa = mctx->dfa; - int i, err, dest_node; - dest_node = -1; + const re_dfa_t *const dfa = mctx->dfa; + int i, err; if (IS_EPSILON_NODE (dfa->nodes[node].type)) { re_node_set *cur_nodes = &mctx->state_log[*pidx]->nodes; @@ -1262,7 +1286,7 @@ proceed_next_node (mctx, nregs, regs, pidx, node, eps_via_nodes, fs) re_token_type_t type = dfa->nodes[node].type; #ifdef RE_ENABLE_I18N - if (ACCEPT_MB_NODE (type)) + if (dfa->nodes[node].accept_mb) naccepted = check_node_accept_bytes (dfa, node, &mctx->input, *pidx); else #endif /* RE_ENABLE_I18N */ @@ -1285,6 +1309,7 @@ proceed_next_node (mctx, nregs, regs, pidx, node, eps_via_nodes, fs) if (naccepted == 0) { + int dest_node; err = re_node_set_insert (eps_via_nodes, node); if (BE (err < 0, 0)) return -2; @@ -1298,7 +1323,7 @@ proceed_next_node (mctx, nregs, regs, pidx, node, eps_via_nodes, fs) if (naccepted != 0 || check_node_accept (mctx, dfa->nodes + node, *pidx)) { - dest_node = dfa->nexts[node]; + int dest_node = dfa->nexts[node]; *pidx = (naccepted == 0) ? *pidx + 1 : *pidx + naccepted; if (fs && (*pidx > mctx->match_last || mctx->state_log[*pidx] == NULL || !re_node_set_contains (&mctx->state_log[*pidx]->nodes, @@ -1312,11 +1337,9 @@ proceed_next_node (mctx, nregs, regs, pidx, node, eps_via_nodes, fs) } static reg_errcode_t -push_fail_stack (fs, str_idx, dest_node, nregs, regs, eps_via_nodes) - struct re_fail_stack_t *fs; - int str_idx, dest_node, nregs; - regmatch_t *regs; - re_node_set *eps_via_nodes; +internal_function +push_fail_stack (struct re_fail_stack_t *fs, int str_idx, int dest_node, + int nregs, regmatch_t *regs, re_node_set *eps_via_nodes) { reg_errcode_t err; int num = fs->num++; @@ -1341,11 +1364,9 @@ push_fail_stack (fs, str_idx, dest_node, nregs, regs, eps_via_nodes) } static int -pop_fail_stack (fs, pidx, nregs, regs, eps_via_nodes) - struct re_fail_stack_t *fs; - int *pidx, nregs; - regmatch_t *regs; - re_node_set *eps_via_nodes; +internal_function +pop_fail_stack (struct re_fail_stack_t *fs, int *pidx, int nregs, + regmatch_t *regs, re_node_set *eps_via_nodes) { int num = --fs->num; assert (num >= 0); @@ -1363,19 +1384,17 @@ pop_fail_stack (fs, pidx, nregs, regs, eps_via_nodes) pmatch[i].rm_so == pmatch[i].rm_eo == -1 for 0 < i < nmatch. */ static reg_errcode_t -set_regs (preg, mctx, nmatch, pmatch, fl_backtrack) - const regex_t *preg; - const re_match_context_t *mctx; - size_t nmatch; - regmatch_t *pmatch; - int fl_backtrack; +internal_function +set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch, + regmatch_t *pmatch, int fl_backtrack) { - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - int idx, cur_node, real_nmatch; + const re_dfa_t *dfa = (const re_dfa_t *) preg->buffer; + int idx, cur_node; re_node_set eps_via_nodes; struct re_fail_stack_t *fs; struct re_fail_stack_t fs_body = { 0, 2, NULL }; regmatch_t *prev_idx_match; + int prev_idx_match_malloced = 0; #ifdef DEBUG assert (nmatch > 1); @@ -1392,15 +1411,25 @@ set_regs (preg, mctx, nmatch, pmatch, fl_backtrack) fs = NULL; cur_node = dfa->init_node; - real_nmatch = (nmatch <= preg->re_nsub) ? nmatch : preg->re_nsub + 1; re_node_set_init_empty (&eps_via_nodes); - prev_idx_match = (regmatch_t *) alloca (sizeof (regmatch_t) * real_nmatch); - memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * real_nmatch); + if (__libc_use_alloca (nmatch * sizeof (regmatch_t))) + prev_idx_match = (regmatch_t *) alloca (nmatch * sizeof (regmatch_t)); + else + { + prev_idx_match = re_malloc (regmatch_t, nmatch); + if (prev_idx_match == NULL) + { + free_fail_stack_return (fs); + return REG_ESPACE; + } + prev_idx_match_malloced = 1; + } + memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch); for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;) { - update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, real_nmatch); + update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, nmatch); if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node) { @@ -1413,6 +1442,8 @@ set_regs (preg, mctx, nmatch, pmatch, fl_backtrack) if (reg_idx == nmatch) { re_node_set_free (&eps_via_nodes); + if (prev_idx_match_malloced) + re_free (prev_idx_match); return free_fail_stack_return (fs); } cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, @@ -1421,6 +1452,8 @@ set_regs (preg, mctx, nmatch, pmatch, fl_backtrack) else { re_node_set_free (&eps_via_nodes); + if (prev_idx_match_malloced) + re_free (prev_idx_match); return REG_NOERROR; } } @@ -1434,6 +1467,8 @@ set_regs (preg, mctx, nmatch, pmatch, fl_backtrack) if (BE (cur_node == -2, 0)) { re_node_set_free (&eps_via_nodes); + if (prev_idx_match_malloced) + re_free (prev_idx_match); free_fail_stack_return (fs); return REG_ESPACE; } @@ -1443,17 +1478,21 @@ set_regs (preg, mctx, nmatch, pmatch, fl_backtrack) else { re_node_set_free (&eps_via_nodes); + if (prev_idx_match_malloced) + re_free (prev_idx_match); return REG_NOMATCH; } } } re_node_set_free (&eps_via_nodes); + if (prev_idx_match_malloced) + re_free (prev_idx_match); return free_fail_stack_return (fs); } static reg_errcode_t -free_fail_stack_return (fs) - struct re_fail_stack_t *fs; +internal_function +free_fail_stack_return (struct re_fail_stack_t *fs) { if (fs) { @@ -1469,10 +1508,9 @@ free_fail_stack_return (fs) } static void -update_regs (dfa, pmatch, prev_idx_match, cur_node, cur_idx, nmatch) - re_dfa_t *dfa; - regmatch_t *pmatch, *prev_idx_match; - int cur_node, cur_idx, nmatch; +internal_function +update_regs (const re_dfa_t *dfa, regmatch_t *pmatch, + regmatch_t *prev_idx_match, int cur_node, int cur_idx, int nmatch) { int type = dfa->nodes[cur_node].type; if (type == OP_OPEN_SUBEXP) @@ -1542,9 +1580,8 @@ update_regs (dfa, pmatch, prev_idx_match, cur_node, cur_idx, nmatch) ((state) != NULL && re_node_set_contains (&(state)->nodes, node)) static reg_errcode_t -sift_states_backward (mctx, sctx) - re_match_context_t *mctx; - re_sift_context_t *sctx; +internal_function +sift_states_backward (const re_match_context_t *mctx, re_sift_context_t *sctx) { reg_errcode_t err; int null_cnt = 0; @@ -1601,14 +1638,12 @@ sift_states_backward (mctx, sctx) } static reg_errcode_t -build_sifted_states (mctx, sctx, str_idx, cur_dest) - re_match_context_t *mctx; - re_sift_context_t *sctx; - int str_idx; - re_node_set *cur_dest; +internal_function +build_sifted_states (const re_match_context_t *mctx, re_sift_context_t *sctx, + int str_idx, re_node_set *cur_dest) { - re_dfa_t *const dfa = mctx->dfa; - re_node_set *cur_src = &mctx->state_log[str_idx]->non_eps_nodes; + const re_dfa_t *const dfa = mctx->dfa; + const re_node_set *cur_src = &mctx->state_log[str_idx]->non_eps_nodes; int i; /* Then build the next sifted state. @@ -1624,15 +1659,13 @@ build_sifted_states (mctx, sctx, str_idx, cur_dest) int naccepted = 0; int ret; -#if defined DEBUG || defined RE_ENABLE_I18N - re_token_type_t type = dfa->nodes[prev_node].type; -#endif #ifdef DEBUG + re_token_type_t type = dfa->nodes[prev_node].type; assert (!IS_EPSILON_NODE (type)); #endif #ifdef RE_ENABLE_I18N /* If the node may accept `multi byte'. */ - if (ACCEPT_MB_NODE (type)) + if (dfa->nodes[prev_node].accept_mb) naccepted = sift_states_iter_mb (mctx, sctx, prev_node, str_idx, sctx->last_str_idx); #endif /* RE_ENABLE_I18N */ @@ -1667,9 +1700,8 @@ build_sifted_states (mctx, sctx, str_idx, cur_dest) /* Helper functions. */ static reg_errcode_t -clean_state_log_if_needed (mctx, next_state_log_idx) - re_match_context_t *mctx; - int next_state_log_idx; +internal_function +clean_state_log_if_needed (re_match_context_t *mctx, int next_state_log_idx) { int top = mctx->state_log_top; @@ -1693,11 +1725,9 @@ clean_state_log_if_needed (mctx, next_state_log_idx) } static reg_errcode_t -merge_state_array (dfa, dst, src, num) - re_dfa_t *dfa; - re_dfastate_t **dst; - re_dfastate_t **src; - int num; +internal_function +merge_state_array (const re_dfa_t *dfa, re_dfastate_t **dst, + re_dfastate_t **src, int num) { int st_idx; reg_errcode_t err; @@ -1722,14 +1752,13 @@ merge_state_array (dfa, dst, src, num) } static reg_errcode_t -update_cur_sifted_state (mctx, sctx, str_idx, dest_nodes) - re_match_context_t *mctx; - re_sift_context_t *sctx; - int str_idx; - re_node_set *dest_nodes; +internal_function +update_cur_sifted_state (const re_match_context_t *mctx, + re_sift_context_t *sctx, int str_idx, + re_node_set *dest_nodes) { - re_dfa_t *const dfa = mctx->dfa; - reg_errcode_t err; + const re_dfa_t *const dfa = mctx->dfa; + reg_errcode_t err = REG_NOERROR; const re_node_set *candidates; candidates = ((mctx->state_log[str_idx] == NULL) ? NULL : &mctx->state_log[str_idx]->nodes); @@ -1771,10 +1800,9 @@ update_cur_sifted_state (mctx, sctx, str_idx, dest_nodes) } static reg_errcode_t -add_epsilon_src_nodes (dfa, dest_nodes, candidates) - re_dfa_t *dfa; - re_node_set *dest_nodes; - const re_node_set *candidates; +internal_function +add_epsilon_src_nodes (const re_dfa_t *dfa, re_node_set *dest_nodes, + const re_node_set *candidates) { reg_errcode_t err = REG_NOERROR; int i; @@ -1797,11 +1825,9 @@ add_epsilon_src_nodes (dfa, dest_nodes, candidates) } static reg_errcode_t -sub_epsilon_src_nodes (dfa, node, dest_nodes, candidates) - re_dfa_t *dfa; - int node; - re_node_set *dest_nodes; - const re_node_set *candidates; +internal_function +sub_epsilon_src_nodes (const re_dfa_t *dfa, int node, re_node_set *dest_nodes, + const re_node_set *candidates) { int ecl_idx; reg_errcode_t err; @@ -1848,12 +1874,11 @@ sub_epsilon_src_nodes (dfa, node, dest_nodes, candidates) } static int -check_dst_limits (mctx, limits, dst_node, dst_idx, src_node, src_idx) - re_match_context_t *mctx; - re_node_set *limits; - int dst_node, dst_idx, src_node, src_idx; +internal_function +check_dst_limits (const re_match_context_t *mctx, re_node_set *limits, + int dst_node, int dst_idx, int src_node, int src_idx) { - re_dfa_t *const dfa = mctx->dfa; + const re_dfa_t *const dfa = mctx->dfa; int lim_idx, src_pos, dst_pos; int dst_bkref_idx = search_cur_bkref_entry (mctx, dst_idx); @@ -1885,12 +1910,12 @@ check_dst_limits (mctx, limits, dst_node, dst_idx, src_node, src_idx) } static int -check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx, from_node, bkref_idx) - re_match_context_t *mctx; - int boundaries, subexp_idx, from_node, bkref_idx; +internal_function +check_dst_limits_calc_pos_1 (const re_match_context_t *mctx, int boundaries, + int subexp_idx, int from_node, int bkref_idx) { - re_dfa_t *const dfa = mctx->dfa; - re_node_set *eclosures = dfa->eclosures + from_node; + const re_dfa_t *const dfa = mctx->dfa; + const re_node_set *eclosures = dfa->eclosures + from_node; int node_idx; /* Else, we are on the boundary: examine the nodes on the epsilon @@ -1911,8 +1936,9 @@ check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx, from_node, bkref_idx) if (ent->node != node) continue; - if (subexp_idx <= 8 * sizeof (ent->eps_reachable_subexps_map) - && !(ent->eps_reachable_subexps_map & (1 << subexp_idx))) + if (subexp_idx < BITSET_WORD_BITS + && !(ent->eps_reachable_subexps_map + & ((bitset_word_t) 1 << subexp_idx))) continue; /* Recurse trying to reach the OP_OPEN_SUBEXP and @@ -1938,7 +1964,9 @@ check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx, from_node, bkref_idx) if (cpos == 0 && (boundaries & 2)) return 0; - ent->eps_reachable_subexps_map &= ~(1 << subexp_idx); + if (subexp_idx < BITSET_WORD_BITS) + ent->eps_reachable_subexps_map + &= ~((bitset_word_t) 1 << subexp_idx); } while (ent++->more); } @@ -1963,9 +1991,10 @@ check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx, from_node, bkref_idx) } static int -check_dst_limits_calc_pos (mctx, limit, subexp_idx, from_node, str_idx, bkref_idx) - re_match_context_t *mctx; - int limit, subexp_idx, from_node, str_idx, bkref_idx; +internal_function +check_dst_limits_calc_pos (const re_match_context_t *mctx, int limit, + int subexp_idx, int from_node, int str_idx, + int bkref_idx) { struct re_backref_cache_entry *lim = mctx->bkref_ents + limit; int boundaries; @@ -1992,13 +2021,10 @@ check_dst_limits_calc_pos (mctx, limit, subexp_idx, from_node, str_idx, bkref_id which are against limitations from DEST_NODES. */ static reg_errcode_t -check_subexp_limits (dfa, dest_nodes, candidates, limits, bkref_ents, str_idx) - re_dfa_t *dfa; - re_node_set *dest_nodes; - const re_node_set *candidates; - re_node_set *limits; - struct re_backref_cache_entry *bkref_ents; - int str_idx; +internal_function +check_subexp_limits (const re_dfa_t *dfa, re_node_set *dest_nodes, + const re_node_set *candidates, re_node_set *limits, + struct re_backref_cache_entry *bkref_ents, int str_idx) { reg_errcode_t err; int node_idx, lim_idx; @@ -2083,13 +2109,11 @@ check_subexp_limits (dfa, dest_nodes, candidates, limits, bkref_ents, str_idx) } static reg_errcode_t -sift_states_bkref (mctx, sctx, str_idx, candidates) - re_match_context_t *mctx; - re_sift_context_t *sctx; - int str_idx; - const re_node_set *candidates; +internal_function +sift_states_bkref (const re_match_context_t *mctx, re_sift_context_t *sctx, + int str_idx, const re_node_set *candidates) { - re_dfa_t *const dfa = mctx->dfa; + const re_dfa_t *const dfa = mctx->dfa; reg_errcode_t err; int node_idx, node; re_sift_context_t local_sctx; @@ -2117,7 +2141,10 @@ sift_states_bkref (mctx, sctx, str_idx, candidates) enabled_idx = first_idx; do { - int subexp_len, to_idx, dst_node; + int subexp_len; + int to_idx; + int dst_node; + int ret; re_dfastate_t *cur_state; if (entry->node != node) @@ -2143,8 +2170,8 @@ sift_states_bkref (mctx, sctx, str_idx, candidates) } local_sctx.last_node = node; local_sctx.last_str_idx = str_idx; - err = re_node_set_insert (&local_sctx.limits, enabled_idx); - if (BE (err < 0, 0)) + ret = re_node_set_insert (&local_sctx.limits, enabled_idx); + if (BE (ret < 0, 0)) { err = REG_ESPACE; goto free_return; @@ -2182,12 +2209,11 @@ sift_states_bkref (mctx, sctx, str_idx, candidates) #ifdef RE_ENABLE_I18N static int -sift_states_iter_mb (mctx, sctx, node_idx, str_idx, max_str_idx) - const re_match_context_t *mctx; - re_sift_context_t *sctx; - int node_idx, str_idx, max_str_idx; +internal_function +sift_states_iter_mb (const re_match_context_t *mctx, re_sift_context_t *sctx, + int node_idx, int str_idx, int max_str_idx) { - re_dfa_t *const dfa = mctx->dfa; + const re_dfa_t *const dfa = mctx->dfa; int naccepted; /* Check the node can accept `multi byte'. */ naccepted = check_node_accept_bytes (dfa, node_idx, &mctx->input, str_idx); @@ -2213,12 +2239,10 @@ sift_states_iter_mb (mctx, sctx, node_idx, str_idx, max_str_idx) update the destination of STATE_LOG. */ static re_dfastate_t * -transit_state (err, mctx, state) - reg_errcode_t *err; - re_match_context_t *mctx; - re_dfastate_t *state; +internal_function +transit_state (reg_errcode_t *err, re_match_context_t *mctx, + re_dfastate_t *state) { - re_dfa_t *const dfa = mctx->dfa; re_dfastate_t **trtable; unsigned char ch; @@ -2233,21 +2257,22 @@ transit_state (err, mctx, state) #endif /* RE_ENABLE_I18N */ /* Then decide the next state with the single byte. */ - if (1) +#if 0 + if (0) + /* don't use transition table */ + return transit_state_sb (err, mctx, state); +#endif + + /* Use transition table */ + ch = re_string_fetch_byte (&mctx->input); + for (;;) { - /* Use transition table */ - ch = re_string_fetch_byte (&mctx->input); trtable = state->trtable; - if (trtable == NULL) - { - trtable = build_trtable (dfa, state); - if (trtable == NULL) - { - *err = REG_ESPACE; - return NULL; - } - } - if (BE (state->word_trtable, 0)) + if (BE (trtable != NULL, 1)) + return trtable[ch]; + + trtable = state->word_trtable; + if (BE (trtable != NULL, 1)) { unsigned int context; context @@ -2259,24 +2284,24 @@ transit_state (err, mctx, state) else return trtable[ch]; } - else - return trtable[ch]; + + if (!build_trtable (mctx->dfa, state)) + { + *err = REG_ESPACE; + return NULL; + } + + /* Retry, we now have a transition table. */ } -#if 0 - else - /* don't use transition table */ - return transit_state_sb (err, mctx, state); -#endif } /* Update the state_log if we need */ re_dfastate_t * -merge_state_with_log (err, mctx, next_state) - reg_errcode_t *err; - re_match_context_t *mctx; - re_dfastate_t *next_state; +internal_function +merge_state_with_log (reg_errcode_t *err, re_match_context_t *mctx, + re_dfastate_t *next_state) { - re_dfa_t *const dfa = mctx->dfa; + const re_dfa_t *const dfa = mctx->dfa; int cur_idx = re_string_cur_idx (&mctx->input); if (cur_idx > mctx->state_log_top) @@ -2351,11 +2376,10 @@ merge_state_with_log (err, mctx, next_state) multi-byte match, then look in the log for a state from which to restart matching. */ re_dfastate_t * -find_recover_state (err, mctx) - reg_errcode_t *err; - re_match_context_t *mctx; +internal_function +find_recover_state (reg_errcode_t *err, re_match_context_t *mctx) { - re_dfastate_t *cur_state = NULL; + re_dfastate_t *cur_state; do { int max = mctx->state_log_top; @@ -2371,7 +2395,7 @@ find_recover_state (err, mctx) cur_state = merge_state_with_log (err, mctx, NULL); } - while (err == REG_NOERROR && cur_state == NULL); + while (*err == REG_NOERROR && cur_state == NULL); return cur_state; } @@ -2383,12 +2407,11 @@ find_recover_state (err, mctx) correspoding back references. */ static reg_errcode_t -check_subexp_matching_top (mctx, cur_nodes, str_idx) - re_match_context_t *mctx; - re_node_set *cur_nodes; - int str_idx; +internal_function +check_subexp_matching_top (re_match_context_t *mctx, re_node_set *cur_nodes, + int str_idx) { - re_dfa_t *const dfa = mctx->dfa; + const re_dfa_t *const dfa = mctx->dfa; int node_idx; reg_errcode_t err; @@ -2401,8 +2424,9 @@ check_subexp_matching_top (mctx, cur_nodes, str_idx) { int node = cur_nodes->elems[node_idx]; if (dfa->nodes[node].type == OP_OPEN_SUBEXP - && dfa->nodes[node].opr.idx < (8 * sizeof (dfa->used_bkref_map)) - && dfa->used_bkref_map & (1 << dfa->nodes[node].opr.idx)) + && dfa->nodes[node].opr.idx < BITSET_WORD_BITS + && (dfa->used_bkref_map + & ((bitset_word_t) 1 << dfa->nodes[node].opr.idx))) { err = match_ctx_add_subtop (mctx, node, str_idx); if (BE (err != REG_NOERROR, 0)) @@ -2417,12 +2441,10 @@ check_subexp_matching_top (mctx, cur_nodes, str_idx) accepting the current input byte. */ static re_dfastate_t * -transit_state_sb (err, mctx, state) - reg_errcode_t *err; - re_match_context_t *mctx; - re_dfastate_t *state; +transit_state_sb (reg_errcode_t *err, re_match_context_t *mctx, + re_dfastate_t *state) { - re_dfa_t *const dfa = mctx->dfa; + const re_dfa_t *const dfa = mctx->dfa; re_node_set next_nodes; re_dfastate_t *next_state; int node_cnt, cur_str_idx = re_string_cur_idx (&mctx->input); @@ -2458,11 +2480,10 @@ transit_state_sb (err, mctx, state) #ifdef RE_ENABLE_I18N static reg_errcode_t -transit_state_mb (mctx, pstate) - re_match_context_t *mctx; - re_dfastate_t *pstate; +internal_function +transit_state_mb (re_match_context_t *mctx, re_dfastate_t *pstate) { - re_dfa_t *const dfa = mctx->dfa; + const re_dfa_t *const dfa = mctx->dfa; reg_errcode_t err; int i; @@ -2470,10 +2491,13 @@ transit_state_mb (mctx, pstate) { re_node_set dest_nodes, *new_nodes; int cur_node_idx = pstate->nodes.elems[i]; - int naccepted = 0, dest_idx; + int naccepted, dest_idx; unsigned int context; re_dfastate_t *dest_state; + if (!dfa->nodes[cur_node_idx].accept_mb) + continue; + if (dfa->nodes[cur_node_idx].constraint) { context = re_string_context_at (&mctx->input, @@ -2485,9 +2509,8 @@ transit_state_mb (mctx, pstate) } /* How many bytes the node can accept? */ - if (ACCEPT_MB_NODE (dfa->nodes[cur_node_idx].type)) - naccepted = check_node_accept_bytes (dfa, cur_node_idx, &mctx->input, - re_string_cur_idx (&mctx->input)); + naccepted = check_node_accept_bytes (dfa, cur_node_idx, &mctx->input, + re_string_cur_idx (&mctx->input)); if (naccepted == 0) continue; @@ -2501,9 +2524,7 @@ transit_state_mb (mctx, pstate) #ifdef DEBUG assert (dfa->nexts[cur_node_idx] != -1); #endif - /* `cur_node_idx' may point the entity of the OP_CONTEXT_NODE, - then we use pstate->nodes.elems[i] instead. */ - new_nodes = dfa->eclosures + dfa->nexts[pstate->nodes.elems[i]]; + new_nodes = dfa->eclosures + dfa->nexts[cur_node_idx]; dest_state = mctx->state_log[dest_idx]; if (dest_state == NULL) @@ -2515,7 +2536,8 @@ transit_state_mb (mctx, pstate) if (BE (err != REG_NOERROR, 0)) return err; } - context = re_string_context_at (&mctx->input, dest_idx - 1, mctx->eflags); + context = re_string_context_at (&mctx->input, dest_idx - 1, + mctx->eflags); mctx->state_log[dest_idx] = re_acquire_state_context (&err, dfa, &dest_nodes, context); if (dest_state != NULL) @@ -2528,11 +2550,10 @@ transit_state_mb (mctx, pstate) #endif /* RE_ENABLE_I18N */ static reg_errcode_t -transit_state_bkref (mctx, nodes) - re_match_context_t *mctx; - const re_node_set *nodes; +internal_function +transit_state_bkref (re_match_context_t *mctx, const re_node_set *nodes) { - re_dfa_t *const dfa = mctx->dfa; + const re_dfa_t *const dfa = mctx->dfa; reg_errcode_t err; int i; int cur_str_idx = re_string_cur_idx (&mctx->input); @@ -2643,18 +2664,18 @@ transit_state_bkref (mctx, nodes) delay these checking for prune_impossible_nodes(). */ static reg_errcode_t -get_subexp (mctx, bkref_node, bkref_str_idx) - re_match_context_t *mctx; - int bkref_node, bkref_str_idx; +internal_function +get_subexp (re_match_context_t *mctx, int bkref_node, int bkref_str_idx) { - re_dfa_t *const dfa = mctx->dfa; + const re_dfa_t *const dfa = mctx->dfa; int subexp_num, sub_top_idx; const char *buf = (const char *) re_string_get_buffer (&mctx->input); /* Return if we have already checked BKREF_NODE at BKREF_STR_IDX. */ int cache_idx = search_cur_bkref_entry (mctx, bkref_str_idx); if (cache_idx != -1) { - const struct re_backref_cache_entry *entry = mctx->bkref_ents + cache_idx; + const struct re_backref_cache_entry *entry + = mctx->bkref_ents + cache_idx; do if (entry->node == bkref_node) return REG_NOERROR; /* We already checked it. */ @@ -2701,7 +2722,8 @@ get_subexp (mctx, bkref_node, bkref_str_idx) buf = (const char *) re_string_get_buffer (&mctx->input); } if (memcmp (buf + bkref_str_off, buf + sl_str, sl_str_diff) != 0) - break; /* We don't need to search this sub expression any more. */ + /* We don't need to search this sub expression any more. */ + break; } bkref_str_off += sl_str_diff; sl_str += sl_str_diff; @@ -2752,7 +2774,8 @@ get_subexp (mctx, bkref_node, bkref_str_idx) continue; /* Does this state have a ')' of the sub expression? */ nodes = &mctx->state_log[sl_str]->nodes; - cls_node = find_subexp_node (dfa, nodes, subexp_num, OP_CLOSE_SUBEXP); + cls_node = find_subexp_node (dfa, nodes, subexp_num, + OP_CLOSE_SUBEXP); if (cls_node == -1) continue; /* No. */ if (sub_top->path == NULL) @@ -2765,7 +2788,8 @@ get_subexp (mctx, bkref_node, bkref_str_idx) /* Can the OP_OPEN_SUBEXP node arrive the OP_CLOSE_SUBEXP node in the current context? */ err = check_arrival (mctx, sub_top->path, sub_top->node, - sub_top->str_idx, cls_node, sl_str, OP_CLOSE_SUBEXP); + sub_top->str_idx, cls_node, sl_str, + OP_CLOSE_SUBEXP); if (err == REG_NOMATCH) continue; if (BE (err != REG_NOERROR, 0)) @@ -2789,17 +2813,16 @@ get_subexp (mctx, bkref_node, bkref_str_idx) and SUB_LAST. */ static reg_errcode_t -get_subexp_sub (mctx, sub_top, sub_last, bkref_node, bkref_str) - re_match_context_t *mctx; - const re_sub_match_top_t *sub_top; - re_sub_match_last_t *sub_last; - int bkref_node, bkref_str; +internal_function +get_subexp_sub (re_match_context_t *mctx, const re_sub_match_top_t *sub_top, + re_sub_match_last_t *sub_last, int bkref_node, int bkref_str) { reg_errcode_t err; int to_idx; /* Can the subexpression arrive the back reference? */ err = check_arrival (mctx, &sub_last->path, sub_last->node, - sub_last->str_idx, bkref_node, bkref_str, OP_OPEN_SUBEXP); + sub_last->str_idx, bkref_node, bkref_str, + OP_OPEN_SUBEXP); if (err != REG_NOERROR) return err; err = match_ctx_add_entry (mctx, bkref_node, bkref_str, sub_top->str_idx, @@ -2819,10 +2842,9 @@ get_subexp_sub (mctx, sub_top, sub_last, bkref_node, bkref_str) E.g. RE: (a){2} */ static int -find_subexp_node (dfa, nodes, subexp_idx, type) - const re_dfa_t *dfa; - const re_node_set *nodes; - int subexp_idx, type; +internal_function +find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes, + int subexp_idx, int type) { int cls_idx; for (cls_idx = 0; cls_idx < nodes->nelem; ++cls_idx) @@ -2842,14 +2864,12 @@ find_subexp_node (dfa, nodes, subexp_idx, type) Return REG_NOERROR if it can arrive, or REG_NOMATCH otherwise. */ static reg_errcode_t -check_arrival (mctx, path, top_node, top_str, last_node, last_str, - type) - re_match_context_t *mctx; - state_array_t *path; - int top_node, top_str, last_node, last_str, type; +internal_function +check_arrival (re_match_context_t *mctx, state_array_t *path, int top_node, + int top_str, int last_node, int last_str, int type) { - re_dfa_t *const dfa = mctx->dfa; - reg_errcode_t err; + const re_dfa_t *const dfa = mctx->dfa; + reg_errcode_t err = REG_NOERROR; int subexp_num, backup_cur_idx, str_idx, null_cnt; re_dfastate_t *cur_state = NULL; re_node_set *cur_nodes, next_nodes; @@ -2864,7 +2884,7 @@ check_arrival (mctx, path, top_node, top_str, last_node, last_str, int old_alloc = path->alloc; path->alloc += last_str + mctx->max_mb_elem_len + 1; new_array = re_realloc (path->array, re_dfastate_t *, path->alloc); - if (new_array == NULL) + if (BE (new_array == NULL, 0)) { path->alloc = old_alloc; return REG_ESPACE; @@ -2874,7 +2894,7 @@ check_arrival (mctx, path, top_node, top_str, last_node, last_str, sizeof (re_dfastate_t *) * (path->alloc - old_alloc)); } - str_idx = path->next_idx == 0 ? top_str : path->next_idx; + str_idx = path->next_idx ?: top_str; /* Temporary modify MCTX. */ backup_state_log = mctx->state_log; @@ -2902,7 +2922,7 @@ check_arrival (mctx, path, top_node, top_str, last_node, last_str, if (cur_state && cur_state->has_backref) { err = re_node_set_init_copy (&next_nodes, &cur_state->nodes); - if (BE ( err != REG_NOERROR, 0)) + if (BE (err != REG_NOERROR, 0)) return err; } else @@ -2914,7 +2934,7 @@ check_arrival (mctx, path, top_node, top_str, last_node, last_str, { err = expand_bkref_cache (mctx, &next_nodes, str_idx, subexp_num, type); - if (BE ( err != REG_NOERROR, 0)) + if (BE (err != REG_NOERROR, 0)) { re_node_set_free (&next_nodes); return err; @@ -2945,7 +2965,8 @@ check_arrival (mctx, path, top_node, top_str, last_node, last_str, if (cur_state) { err = check_arrival_add_next_nodes (mctx, str_idx, - &cur_state->non_eps_nodes, &next_nodes); + &cur_state->non_eps_nodes, + &next_nodes); if (BE (err != REG_NOERROR, 0)) { re_node_set_free (&next_nodes); @@ -2963,7 +2984,7 @@ check_arrival (mctx, path, top_node, top_str, last_node, last_str, } err = expand_bkref_cache (mctx, &next_nodes, str_idx, subexp_num, type); - if (BE ( err != REG_NOERROR, 0)) + if (BE (err != REG_NOERROR, 0)) { re_node_set_free (&next_nodes); return err; @@ -3004,30 +3025,27 @@ check_arrival (mctx, path, top_node, top_str, last_node, last_str, Can't we unify them? */ static reg_errcode_t -check_arrival_add_next_nodes (mctx, str_idx, cur_nodes, next_nodes) - re_match_context_t *mctx; - int str_idx; - re_node_set *cur_nodes, *next_nodes; +internal_function +check_arrival_add_next_nodes (re_match_context_t *mctx, int str_idx, + re_node_set *cur_nodes, re_node_set *next_nodes) { - re_dfa_t *const dfa = mctx->dfa; + const re_dfa_t *const dfa = mctx->dfa; int result; int cur_idx; - reg_errcode_t err; + reg_errcode_t err = REG_NOERROR; re_node_set union_set; re_node_set_init_empty (&union_set); for (cur_idx = 0; cur_idx < cur_nodes->nelem; ++cur_idx) { int naccepted = 0; int cur_node = cur_nodes->elems[cur_idx]; -#if defined DEBUG || defined RE_ENABLE_I18N - re_token_type_t type = dfa->nodes[cur_node].type; -#endif #ifdef DEBUG + re_token_type_t type = dfa->nodes[cur_node].type; assert (!IS_EPSILON_NODE (type)); #endif #ifdef RE_ENABLE_I18N /* If the node may accept `multi byte'. */ - if (ACCEPT_MB_NODE (type)) + if (dfa->nodes[cur_node].accept_mb) { naccepted = check_node_accept_bytes (dfa, cur_node, &mctx->input, str_idx); @@ -3086,10 +3104,9 @@ check_arrival_add_next_nodes (mctx, str_idx, cur_nodes, next_nodes) */ static reg_errcode_t -check_arrival_expand_ecl (dfa, cur_nodes, ex_subexp, type) - re_dfa_t *dfa; - re_node_set *cur_nodes; - int ex_subexp, type; +internal_function +check_arrival_expand_ecl (const re_dfa_t *dfa, re_node_set *cur_nodes, + int ex_subexp, int type) { reg_errcode_t err; int idx, outside_node; @@ -3106,7 +3123,7 @@ check_arrival_expand_ecl (dfa, cur_nodes, ex_subexp, type) for (idx = 0; idx < cur_nodes->nelem; ++idx) { int cur_node = cur_nodes->elems[idx]; - re_node_set *eclosure = dfa->eclosures + cur_node; + const re_node_set *eclosure = dfa->eclosures + cur_node; outside_node = find_subexp_node (dfa, eclosure, ex_subexp, type); if (outside_node == -1) { @@ -3140,10 +3157,9 @@ check_arrival_expand_ecl (dfa, cur_nodes, ex_subexp, type) problematic append it to DST_NODES. */ static reg_errcode_t -check_arrival_expand_ecl_sub (dfa, dst_nodes, target, ex_subexp, type) - re_dfa_t *dfa; - int target, ex_subexp, type; - re_node_set *dst_nodes; +internal_function +check_arrival_expand_ecl_sub (const re_dfa_t *dfa, re_node_set *dst_nodes, + int target, int ex_subexp, int type) { int cur_node; for (cur_node = target; !re_node_set_contains (dst_nodes, cur_node);) @@ -3185,13 +3201,11 @@ check_arrival_expand_ecl_sub (dfa, dst_nodes, target, ex_subexp, type) in MCTX->BKREF_ENTS. */ static reg_errcode_t -expand_bkref_cache (mctx, cur_nodes, cur_str, subexp_num, - type) - re_match_context_t *mctx; - int cur_str, subexp_num, type; - re_node_set *cur_nodes; +internal_function +expand_bkref_cache (re_match_context_t *mctx, re_node_set *cur_nodes, + int cur_str, int subexp_num, int type) { - re_dfa_t *const dfa = mctx->dfa; + const re_dfa_t *const dfa = mctx->dfa; reg_errcode_t err; int cache_idx_start = search_cur_bkref_entry (mctx, cur_str); struct re_backref_cache_entry *ent; @@ -3273,45 +3287,48 @@ expand_bkref_cache (mctx, cur_nodes, cur_str, subexp_num, } /* Build transition table for the state. - Return the new table if succeeded, otherwise return NULL. */ + Return 1 if succeeded, otherwise return NULL. */ -static re_dfastate_t ** -build_trtable (dfa, state) - re_dfa_t *dfa; - re_dfastate_t *state; +static int +internal_function +build_trtable (const re_dfa_t *dfa, re_dfastate_t *state) { reg_errcode_t err; - int i, j, ch; - unsigned int elem, mask; - int dests_node_malloced = 0, dest_states_malloced = 0; + int i, j, ch, need_word_trtable = 0; + bitset_word_t elem, mask; + bool dests_node_malloced = false; + bool dest_states_malloced = false; int ndests; /* Number of the destination states from `state'. */ re_dfastate_t **trtable; re_dfastate_t **dest_states = NULL, **dest_states_word, **dest_states_nl; re_node_set follows, *dests_node; - bitset *dests_ch; - bitset acceptable; + bitset_t *dests_ch; + bitset_t acceptable; + + struct dests_alloc + { + re_node_set dests_node[SBC_MAX]; + bitset_t dests_ch[SBC_MAX]; + } *dests_alloc; /* We build DFA states which corresponds to the destination nodes from `state'. `dests_node[i]' represents the nodes which i-th destination state contains, and `dests_ch[i]' represents the characters which i-th destination state accepts. */ -#ifdef _LIBC - if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset)) * SBC_MAX)) - dests_node = (re_node_set *) - alloca ((sizeof (re_node_set) + sizeof (bitset)) * SBC_MAX); + if (__libc_use_alloca (sizeof (struct dests_alloc))) + dests_alloc = (struct dests_alloc *) alloca (sizeof (struct dests_alloc)); else -#endif { - dests_node = (re_node_set *) - malloc ((sizeof (re_node_set) + sizeof (bitset)) * SBC_MAX); - if (BE (dests_node == NULL, 0)) - return NULL; - dests_node_malloced = 1; + dests_alloc = re_malloc (struct dests_alloc, 1); + if (BE (dests_alloc == NULL, 0)) + return 0; + dests_node_malloced = true; } - dests_ch = (bitset *) (dests_node + SBC_MAX); + dests_node = dests_alloc->dests_node; + dests_ch = dests_alloc->dests_ch; /* Initialize transiton table. */ - state->word_trtable = 0; + state->word_trtable = state->trtable = NULL; /* At first, group all nodes belonging to `state' into several destinations. */ @@ -3319,31 +3336,29 @@ build_trtable (dfa, state) if (BE (ndests <= 0, 0)) { if (dests_node_malloced) - free (dests_node); - /* Return NULL in case of an error, trtable otherwise. */ + free (dests_alloc); + /* Return 0 in case of an error, 1 otherwise. */ if (ndests == 0) { state->trtable = (re_dfastate_t **) - calloc (sizeof (re_dfastate_t *), SBC_MAX);; - return state->trtable; + calloc (sizeof (re_dfastate_t *), SBC_MAX); + return 1; } - return NULL; + return 0; } err = re_node_set_alloc (&follows, ndests + 1); if (BE (err != REG_NOERROR, 0)) goto out_free; -#ifdef _LIBC - if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset)) * SBC_MAX + if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX + ndests * 3 * sizeof (re_dfastate_t *))) dest_states = (re_dfastate_t **) - alloca (ndests * 3 * sizeof (re_dfastate_t *)); + alloca (ndests * 3 * sizeof (re_dfastate_t *)); else -#endif { dest_states = (re_dfastate_t **) - malloc (ndests * 3 * sizeof (re_dfastate_t *)); + malloc (ndests * 3 * sizeof (re_dfastate_t *)); if (BE (dest_states == NULL, 0)) { out_free: @@ -3353,10 +3368,10 @@ out_free: for (i = 0; i < ndests; ++i) re_node_set_free (dests_node + i); if (dests_node_malloced) - free (dests_node); - return NULL; + free (dests_alloc); + return 0; } - dest_states_malloced = 1; + dest_states_malloced = true; } dest_states_word = dest_states + ndests; dest_states_nl = dest_states_word + ndests; @@ -3390,9 +3405,8 @@ out_free: if (BE (dest_states_word[i] == NULL && err != REG_NOERROR, 0)) goto out_free; - if (dest_states[i] != dest_states_word[i] - && dfa->mb_cur_max > 1) - state->word_trtable = 1; + if (dest_states[i] != dest_states_word[i] && dfa->mb_cur_max > 1) + need_word_trtable = 1; dest_states_nl[i] = re_acquire_state_context (&err, dfa, &follows, CONTEXT_NEWLINE); @@ -3407,19 +3421,20 @@ out_free: bitset_merge (acceptable, dests_ch[i]); } - if (!BE (state->word_trtable, 0)) + if (!BE (need_word_trtable, 0)) { /* We don't care about whether the following character is a word character, or we are in a single-byte character set so we can discern by looking at the character code: allocate a 256-entry transition table. */ - trtable = (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), SBC_MAX); + trtable = state->trtable = + (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), SBC_MAX); if (BE (trtable == NULL, 0)) goto out_free; /* For all characters ch...: */ - for (i = 0; i < BITSET_UINTS; ++i) - for (ch = i * UINT_BITS, elem = acceptable[i], mask = 1; + for (i = 0; i < BITSET_WORDS; ++i) + for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1; elem; mask <<= 1, elem >>= 1, ++ch) if (BE (elem & 1, 0)) @@ -3443,14 +3458,14 @@ out_free: by looking at the character code: build two 256-entry transition tables, one starting at trtable[0] and one starting at trtable[SBC_MAX]. */ - trtable = (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), - 2 * SBC_MAX); + trtable = state->word_trtable = + (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), 2 * SBC_MAX); if (BE (trtable == NULL, 0)) goto out_free; /* For all characters ch...: */ - for (i = 0; i < BITSET_UINTS; ++i) - for (ch = i * UINT_BITS, elem = acceptable[i], mask = 1; + for (i = 0; i < BITSET_WORDS; ++i) + for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1; elem; mask <<= 1, elem >>= 1, ++ch) if (BE (elem & 1, 0)) @@ -3475,7 +3490,7 @@ out_free: { /* k-th destination accepts newline character. */ trtable[NEWLINE_CHAR] = dest_states_nl[j]; - if (state->word_trtable) + if (need_word_trtable) trtable[NEWLINE_CHAR + SBC_MAX] = dest_states_nl[j]; /* There must be only one destination which accepts newline. See group_nodes_into_DFAstates. */ @@ -3491,10 +3506,9 @@ out_free: re_node_set_free (dests_node + i); if (dests_node_malloced) - free (dests_node); + free (dests_alloc); - state->trtable = trtable; - return trtable; + return 1; } /* Group all nodes belonging to STATE into several destinations. @@ -3503,17 +3517,15 @@ out_free: to DEST_CH[i]. This function return the number of destinations. */ static int -group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch) - re_dfa_t *dfa; - const re_dfastate_t *state; - re_node_set *dests_node; - bitset *dests_ch; +internal_function +group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *state, + re_node_set *dests_node, bitset_t *dests_ch) { reg_errcode_t err; int result; int i, j, k; int ndests; /* Number of the destinations from `state'. */ - bitset accepts; /* Characters a node can accept. */ + bitset_t accepts; /* Characters a node can accept. */ const re_node_set *cur_nodes = &state->nodes; bitset_empty (accepts); ndests = 0; @@ -3548,7 +3560,7 @@ group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch) #ifdef RE_ENABLE_I18N else if (type == OP_UTF8_PERIOD) { - memset (accepts, 255, sizeof (unsigned int) * BITSET_UINTS / 2); + memset (accepts, '\xff', sizeof (bitset_t) / 2); if (!(dfa->syntax & RE_DOT_NEWLINE)) bitset_clear (accepts, '\n'); if (dfa->syntax & RE_DOT_NOT_NULL) @@ -3564,7 +3576,7 @@ group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch) { if (constraint & NEXT_NEWLINE_CONSTRAINT) { - int accepts_newline = bitset_contain (accepts, NEWLINE_CHAR); + bool accepts_newline = bitset_contain (accepts, NEWLINE_CHAR); bitset_empty (accepts); if (accepts_newline) bitset_set (accepts, NEWLINE_CHAR); @@ -3579,7 +3591,7 @@ group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch) if (constraint & NEXT_WORD_CONSTRAINT) { - unsigned int any_set = 0; + bitset_word_t any_set = 0; if (type == CHARACTER && !node->word_char) { bitset_empty (accepts); @@ -3587,18 +3599,18 @@ group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch) } #ifdef RE_ENABLE_I18N if (dfa->mb_cur_max > 1) - for (j = 0; j < BITSET_UINTS; ++j) + for (j = 0; j < BITSET_WORDS; ++j) any_set |= (accepts[j] &= (dfa->word_char[j] | ~dfa->sb_char[j])); else #endif - for (j = 0; j < BITSET_UINTS; ++j) + for (j = 0; j < BITSET_WORDS; ++j) any_set |= (accepts[j] &= dfa->word_char[j]); if (!any_set) continue; } if (constraint & NEXT_NOTWORD_CONSTRAINT) { - unsigned int any_set = 0; + bitset_word_t any_set = 0; if (type == CHARACTER && node->word_char) { bitset_empty (accepts); @@ -3606,11 +3618,11 @@ group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch) } #ifdef RE_ENABLE_I18N if (dfa->mb_cur_max > 1) - for (j = 0; j < BITSET_UINTS; ++j) + for (j = 0; j < BITSET_WORDS; ++j) any_set |= (accepts[j] &= ~(dfa->word_char[j] & dfa->sb_char[j])); else #endif - for (j = 0; j < BITSET_UINTS; ++j) + for (j = 0; j < BITSET_WORDS; ++j) any_set |= (accepts[j] &= ~dfa->word_char[j]); if (!any_set) continue; @@ -3621,10 +3633,10 @@ group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch) state. Above, we make sure that accepts is not empty. */ for (j = 0; j < ndests; ++j) { - bitset intersec; /* Intersection sets, see below. */ - bitset remains; + bitset_t intersec; /* Intersection sets, see below. */ + bitset_t remains; /* Flags, see below. */ - int has_intersec, not_subset, not_consumed; + bitset_word_t has_intersec, not_subset, not_consumed; /* Optimization, skip if this state doesn't accept the character. */ if (type == CHARACTER && !bitset_contain (dests_ch[j], node->opr.c)) @@ -3632,7 +3644,7 @@ group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch) /* Enumerate the intersection set of this state and `accepts'. */ has_intersec = 0; - for (k = 0; k < BITSET_UINTS; ++k) + for (k = 0; k < BITSET_WORDS; ++k) has_intersec |= intersec[k] = accepts[k] & dests_ch[j][k]; /* And skip if the intersection set is empty. */ if (!has_intersec) @@ -3640,7 +3652,7 @@ group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch) /* Then check if this state is a subset of `accepts'. */ not_subset = not_consumed = 0; - for (k = 0; k < BITSET_UINTS; ++k) + for (k = 0; k < BITSET_WORDS; ++k) { not_subset |= remains[k] = ~accepts[k] & dests_ch[j][k]; not_consumed |= accepts[k] = accepts[k] & ~dests_ch[j][k]; @@ -3695,10 +3707,9 @@ group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch) can only accept one byte. */ static int -check_node_accept_bytes (dfa, node_idx, input, str_idx) - re_dfa_t *dfa; - int node_idx, str_idx; - const re_string_t *input; +internal_function +check_node_accept_bytes (const re_dfa_t *dfa, int node_idx, + const re_string_t *input, int str_idx) { const re_token_t *node = dfa->nodes + node_idx; int char_len, elem_len; @@ -3779,8 +3790,8 @@ check_node_accept_bytes (dfa, node_idx, input, str_idx) { const re_charset_t *cset = node->opr.mbcset; # ifdef _LIBC - const unsigned char *pin = ((char *) re_string_get_buffer (input) - + str_idx); + const unsigned char *pin + = ((const unsigned char *) re_string_get_buffer (input) + str_idx); int j; uint32_t nrules; # endif /* _LIBC */ @@ -3932,9 +3943,8 @@ check_node_accept_bytes (dfa, node_idx, input, str_idx) # ifdef _LIBC static unsigned int -find_collation_sequence_value (mbs, mbs_len) - const unsigned char *mbs; - size_t mbs_len; +internal_function +find_collation_sequence_value (const unsigned char *mbs, size_t mbs_len) { uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); if (nrules == 0) @@ -3996,10 +4006,9 @@ find_collation_sequence_value (mbs, mbs_len) byte of the INPUT. */ static int -check_node_accept (mctx, node, idx) - const re_match_context_t *mctx; - const re_token_t *node; - int idx; +internal_function +check_node_accept (const re_match_context_t *mctx, const re_token_t *node, + int idx) { unsigned char ch; ch = re_string_byte_at (&mctx->input, idx); @@ -4047,8 +4056,8 @@ check_node_accept (mctx, node, idx) /* Extend the buffers, if the buffers have run out. */ static reg_errcode_t -extend_buffers (mctx) - re_match_context_t *mctx; +internal_function +extend_buffers (re_match_context_t *mctx) { reg_errcode_t ret; re_string_t *pstr = &mctx->input; @@ -4106,9 +4115,8 @@ extend_buffers (mctx) /* Initialize MCTX. */ static reg_errcode_t -match_ctx_init (mctx, eflags, n) - re_match_context_t *mctx; - int eflags, n; +internal_function +match_ctx_init (re_match_context_t *mctx, int eflags, int n) { mctx->eflags = eflags; mctx->match_last = -1; @@ -4135,8 +4143,8 @@ match_ctx_init (mctx, eflags, n) of the input, or changes the input string. */ static void -match_ctx_clean (mctx) - re_match_context_t *mctx; +internal_function +match_ctx_clean (re_match_context_t *mctx) { int st_idx; for (st_idx = 0; st_idx < mctx->nsub_tops; ++st_idx) @@ -4165,8 +4173,8 @@ match_ctx_clean (mctx) /* Free all the memory associated with MCTX. */ static void -match_ctx_free (mctx) - re_match_context_t *mctx; +internal_function +match_ctx_free (re_match_context_t *mctx) { /* First, free all the memory associated with MCTX->SUB_TOPS. */ match_ctx_clean (mctx); @@ -4180,9 +4188,9 @@ match_ctx_free (mctx) */ static reg_errcode_t -match_ctx_add_entry (mctx, node, str_idx, from, to) - re_match_context_t *mctx; - int node, str_idx, from, to; +internal_function +match_ctx_add_entry (re_match_context_t *mctx, int node, int str_idx, int from, + int to) { if (mctx->nbkref_ents >= mctx->abkref_ents) { @@ -4229,9 +4237,8 @@ match_ctx_add_entry (mctx, node, str_idx, from, to) found. Note that MCTX->BKREF_ENTS is already sorted by MCTX->STR_IDX. */ static int -search_cur_bkref_entry (mctx, str_idx) - re_match_context_t *mctx; - int str_idx; +internal_function +search_cur_bkref_entry (const re_match_context_t *mctx, int str_idx) { int left, right, mid, last; last = right = mctx->nbkref_ents; @@ -4253,9 +4260,8 @@ search_cur_bkref_entry (mctx, str_idx) at STR_IDX. */ static reg_errcode_t -match_ctx_add_subtop (mctx, node, str_idx) - re_match_context_t *mctx; - int node, str_idx; +internal_function +match_ctx_add_subtop (re_match_context_t *mctx, int node, int str_idx) { #ifdef DEBUG assert (mctx->sub_tops != NULL); @@ -4284,9 +4290,8 @@ match_ctx_add_subtop (mctx, node, str_idx) at STR_IDX, whose corresponding OP_OPEN_SUBEXP is SUB_TOP. */ static re_sub_match_last_t * -match_ctx_add_sublast (subtop, node, str_idx) - re_sub_match_top_t *subtop; - int node, str_idx; +internal_function +match_ctx_add_sublast (re_sub_match_top_t *subtop, int node, int str_idx) { re_sub_match_last_t *new_entry; if (BE (subtop->nlasts == subtop->alasts, 0)) @@ -4312,10 +4317,9 @@ match_ctx_add_sublast (subtop, node, str_idx) } static void -sift_ctx_init (sctx, sifted_sts, limited_sts, last_node, last_str_idx) - re_sift_context_t *sctx; - re_dfastate_t **sifted_sts, **limited_sts; - int last_node, last_str_idx; +internal_function +sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts, + re_dfastate_t **limited_sts, int last_node, int last_str_idx) { sctx->sifted_states = sifted_sts; sctx->limited_states = limited_sts; diff --git a/posix/rxspencer/tests b/posix/rxspencer/tests index a724252d8c..b84a270cda 100644 --- a/posix/rxspencer/tests +++ b/posix/rxspencer/tests @@ -376,6 +376,7 @@ a(b?c)+d - accd accd a[bc]d - xyzaaabcaababdacd abd a[ab]c - aaabc abc abc s abc abc +() s abc @abc a* & b @b # Let's have some fun -- try to match a C comment. @@ -526,3 +527,12 @@ a((b+|((c)*)))+d - abcd abcd c,c,c,c (((\b))){0} - x @x -,-,- a(((.*)))b((\2)){0}c - abc abc @bc,@bc,@bc,-,- a(((.*)))b((\1)){0}c - axbc axbc x,x,x,-,- + +\b & SaT @aT +\b & aT @aT +a.*\b & abT ab +\b & STSS +\B & abc @bc +\B & aSbTc +\B & SaT @SaT +\B & aSTSb @TSb diff --git a/posix/sched_getaffinity.c b/posix/sched_getaffinity.c new file mode 100644 index 0000000000..b2e452f879 --- /dev/null +++ b/posix/sched_getaffinity.c @@ -0,0 +1,35 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sched.h> +#include <sys/types.h> + + +/* Retrieve the CPU affinity mask for a particular process. */ +int +sched_getaffinity (pid, cpusetsize, cpuset) + pid_t pid; + size_t cpusetsize; + cpu_set_t *cpuset; +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (sched_getaffinity) +#include <stub-tag.h> diff --git a/posix/sched_getp.c b/posix/sched_getp.c new file mode 100644 index 0000000000..1ca77893f4 --- /dev/null +++ b/posix/sched_getp.c @@ -0,0 +1,34 @@ +/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sys/types.h> +#include <sched.h> + + +/* Retrieve scheduling parameters for a particular process. */ +int +__sched_getparam (pid_t pid, struct sched_param *param) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (sched_getparam) + +weak_alias (__sched_getparam, sched_getparam) +#include <stub-tag.h> diff --git a/posix/sched_gets.c b/posix/sched_gets.c new file mode 100644 index 0000000000..479b913f32 --- /dev/null +++ b/posix/sched_gets.c @@ -0,0 +1,34 @@ +/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sched.h> +#include <sys/types.h> + + +/* Retrieve scheduling algorithm for a particular purpose. */ +int +__sched_getscheduler (pid_t pid) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (sched_getscheduler) + +weak_alias (__sched_getscheduler, sched_getscheduler) +#include <stub-tag.h> diff --git a/posix/sched_primax.c b/posix/sched_primax.c new file mode 100644 index 0000000000..4b3c1cbe67 --- /dev/null +++ b/posix/sched_primax.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sched.h> + + +/* Get maximum priority value for a scheduler. */ +int +__sched_get_priority_max (int algorithm) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (sched_get_priority_max) + +weak_alias (__sched_get_priority_max, sched_get_priority_max) +#include <stub-tag.h> diff --git a/posix/sched_primin.c b/posix/sched_primin.c new file mode 100644 index 0000000000..813b8f63ca --- /dev/null +++ b/posix/sched_primin.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sched.h> + + +/* Get minimum priority value for a scheduler. */ +int +__sched_get_priority_min (int algorithm) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (sched_get_priority_min) + +weak_alias (__sched_get_priority_min, sched_get_priority_min) +#include <stub-tag.h> diff --git a/posix/sched_rr_gi.c b/posix/sched_rr_gi.c new file mode 100644 index 0000000000..f8fec63617 --- /dev/null +++ b/posix/sched_rr_gi.c @@ -0,0 +1,34 @@ +/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sched.h> +#include <sys/types.h> + + +/* Get the SCHED_RR interval for the named process. */ +int +__sched_rr_get_interval (pid_t pid, struct timespec *t) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (sched_rr_get_interval) + +weak_alias (__sched_rr_get_interval, sched_rr_get_interval) +#include <stub-tag.h> diff --git a/posix/sched_setaffinity.c b/posix/sched_setaffinity.c new file mode 100644 index 0000000000..652163db85 --- /dev/null +++ b/posix/sched_setaffinity.c @@ -0,0 +1,35 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sys/types.h> +#include <sched.h> + + +/* Retrieve the CPU affinity mask for a particular process. */ +int +sched_setaffinity (pid, cpusetsize, cpuset) + pid_t pid; + size_t cpusetsize; + const cpu_set_t *cpuset; +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (sched_setaffinity) +#include <stub-tag.h> diff --git a/posix/sched_setp.c b/posix/sched_setp.c new file mode 100644 index 0000000000..cc451fc131 --- /dev/null +++ b/posix/sched_setp.c @@ -0,0 +1,34 @@ +/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sys/types.h> +#include <sched.h> + + +/* Set scheduling parameters for a process. */ +int +__sched_setparam (pid_t pid, const struct sched_param *param) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (sched_setparam) + +weak_alias (__sched_setparam, sched_setparam) +#include <stub-tag.h> diff --git a/posix/sched_sets.c b/posix/sched_sets.c new file mode 100644 index 0000000000..631cac228b --- /dev/null +++ b/posix/sched_sets.c @@ -0,0 +1,35 @@ +/* Copyright (C) 1996, 1997, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sched.h> +#include <sys/types.h> + + +/* Set scheduling algorithm and/or parameters for a process. */ +int +__sched_setscheduler (pid_t pid, int policy, const struct sched_param *param) +{ + __set_errno (ENOSYS); + return -1; +} +libc_hidden_def (__sched_setscheduler) +stub_warning (sched_setscheduler) + +weak_alias (__sched_setscheduler, sched_setscheduler) +#include <stub-tag.h> diff --git a/posix/sched_yield.c b/posix/sched_yield.c new file mode 100644 index 0000000000..e7a41ea80b --- /dev/null +++ b/posix/sched_yield.c @@ -0,0 +1,34 @@ +/* Copyright (C) 1996, 1997, 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sched.h> + + +/* Yield the processor. */ +int +__sched_yield (void) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (sched_yield) +libc_hidden_def (__sched_yield) + +weak_alias (__sched_yield, sched_yield) +#include <stub-tag.h> diff --git a/posix/setgid.c b/posix/setgid.c new file mode 100644 index 0000000000..05c2cc6621 --- /dev/null +++ b/posix/setgid.c @@ -0,0 +1,37 @@ +/* Copyright (C) 1991, 1993, 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> +#include <sys/types.h> + +/* Set the group ID of the calling process to GID. + If the calling process is the super-user, the real + and effective group IDs, and the saved set-group-ID to GID; + if not, the effective group ID is set to GID. */ +int +__setgid (gid) + gid_t gid; +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (setgid) + +weak_alias (__setgid, setgid) +#include <stub-tag.h> diff --git a/posix/setlogin.c b/posix/setlogin.c new file mode 100644 index 0000000000..c16e29dd9e --- /dev/null +++ b/posix/setlogin.c @@ -0,0 +1,32 @@ +/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> + +/* Set the login name returned by `getlogin'. */ +int +setlogin (name) + const char *name; +{ + __set_errno (ENOSYS); + return -1; +} + +stub_warning (setlogin) +#include <stub-tag.h> diff --git a/posix/setpgid.c b/posix/setpgid.c new file mode 100644 index 0000000000..cb2abf1159 --- /dev/null +++ b/posix/setpgid.c @@ -0,0 +1,37 @@ +/* Copyright (C) 1991, 1995, 1996, 1997, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> + +/* Set the process group ID of the process matching PID to PGID. + If PID is zero, the current process's process group ID is set. + If PGID is zero, the process ID of the process is used. */ +int +__setpgid (pid, pgid) + int pid; + int pgid; +{ + __set_errno (ENOSYS); + return -1; +} +libc_hidden_def (__setpgid) +stub_warning (setpgid) + +weak_alias (__setpgid, setpgid) +#include <stub-tag.h> diff --git a/posix/setpgrp.c b/posix/setpgrp.c new file mode 100644 index 0000000000..8ceb159341 --- /dev/null +++ b/posix/setpgrp.c @@ -0,0 +1,25 @@ +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <unistd.h> + +int +setpgrp () +{ + return __setpgid (0, 0); +} diff --git a/posix/setresgid.c b/posix/setresgid.c new file mode 100644 index 0000000000..736c22e4c1 --- /dev/null +++ b/posix/setresgid.c @@ -0,0 +1,35 @@ +/* setresgid -- set real group ID, effective group ID, and saved-set group ID + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> + +/* Set the real group ID, effective group ID, and saved-set group ID, + of the calling process to RGID, EGID, and SGID, respectively. */ +int +__setresgid (gid_t rgid, gid_t egid, gid_t sgid) +{ + __set_errno (ENOSYS); + return -1; +} +libc_hidden_def (__setresgid) +stub_warning (setresgid) + +weak_alias (__setresgid, setresgid) +#include <stub-tag.h> diff --git a/posix/setresuid.c b/posix/setresuid.c new file mode 100644 index 0000000000..89263330e3 --- /dev/null +++ b/posix/setresuid.c @@ -0,0 +1,35 @@ +/* setresuid -- set real user ID, effective user ID, and saved-set user ID + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> + +/* Set the real user ID, effective user ID, and saved-set user ID, + of the calling process to RUID, EUID, and SUID, respectively. */ +int +__setresuid (uid_t ruid, uid_t euid, uid_t suid) +{ + __set_errno (ENOSYS); + return -1; +} +libc_hidden_def (__setresuid) +stub_warning (setresuid) + +weak_alias (__setresuid, setresuid) +#include <stub-tag.h> diff --git a/posix/setsid.c b/posix/setsid.c new file mode 100644 index 0000000000..6a6712b9bd --- /dev/null +++ b/posix/setsid.c @@ -0,0 +1,35 @@ +/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> + + +/* Create a new session with the calling process as its leader. + The process group IDs of the session and the calling process + are set to the process ID of the calling process, which is returned. */ +int +__setsid () +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (setsid) + +weak_alias (__setsid, setsid) +#include <stub-tag.h> diff --git a/posix/setuid.c b/posix/setuid.c new file mode 100644 index 0000000000..96c3e01cb9 --- /dev/null +++ b/posix/setuid.c @@ -0,0 +1,37 @@ +/* Copyright (C) 1991, 1993, 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> +#include <sys/types.h> + +/* Set the user ID of the calling process to UID. + If the calling process is the super-user, the real + and effective user IDs, and the saved set-user-ID to UID; + if not, the effective user ID is set to UID. */ +int +__setuid (uid) + uid_t uid; +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (setuid) + +weak_alias (__setuid, setuid) +#include <stub-tag.h> diff --git a/posix/sleep.c b/posix/sleep.c new file mode 100644 index 0000000000..f9d2a6593f --- /dev/null +++ b/posix/sleep.c @@ -0,0 +1,41 @@ +/* Copyright (C) 1991, 1992, 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <signal.h> +#include <time.h> +#include <unistd.h> +#include <errno.h> + +/* Make the process sleep for SECONDS seconds, or until a signal arrives + and is not ignored. The function returns the number of seconds less + than SECONDS which it actually slept (zero if it slept the full time). + If a signal handler does a `longjmp' or modifies the handling of the + SIGALRM signal while inside `sleep' call, the handling of the SIGALRM + signal afterwards is undefined. There is no return value to indicate + error, but if `sleep' returns SECONDS, it probably didn't work. */ +unsigned int +__sleep (seconds) + unsigned int seconds; +{ + __set_errno (ENOSYS); + return seconds; +} +weak_alias (__sleep, sleep) + +stub_warning (sleep) +#include <stub-tag.h> diff --git a/posix/spawni.c b/posix/spawni.c new file mode 100644 index 0000000000..c7d5f59ffc --- /dev/null +++ b/posix/spawni.c @@ -0,0 +1,46 @@ +/* Guts of POSIX spawn interface. Stub version. + Copyright (C) 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <spawn.h> +#include "spawn_int.h" + + +/* The Unix standard contains a long explanation of the way to signal + an error after the fork() was successful. Since no new wait status + was wanted there is no way to signal an error using one of the + available methods. The committee chose to signal an error by a + normal program exit with the exit code 127. */ +#define SPAWN_ERROR 127 + + +/* Spawn a new process executing PATH with the attributes describes in *ATTRP. + Before running the process perform the actions described in FILE-ACTIONS. */ +int +__spawni (pid_t *pid, const char *file, + const posix_spawn_file_actions_t *file_actions, + const posix_spawnattr_t *attrp, char *const argv[], + char *const envp[], int use_path) +{ + __set_errno (ENOSYS); + return -1; +} + +stub_warning (__spawni) +#include <stub-tag.h> diff --git a/posix/sys/types.h b/posix/sys/types.h index 0a645dbaad..04563a4abc 100644 --- a/posix/sys/types.h +++ b/posix/sys/types.h @@ -1,4 +1,4 @@ -/* Copyright (C) 1991,1992,1994,1995,1996,1997,1998,1999,2000,2001,2002 +/* Copyright (C) 1991,1992,1994,1995,1996,1997,1998,1999,2000,2001,2002,2006 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -163,7 +163,9 @@ typedef unsigned int uint; typedef char int8_t; typedef short int int16_t; typedef int int32_t; -# if __GLIBC_HAVE_LONG_LONG +# if __WORDSIZE == 64 +typedef long int int64_t; +# elif __GLIBC_HAVE_LONG_LONG __extension__ typedef long long int int64_t; # endif # endif @@ -172,7 +174,9 @@ __extension__ typedef long long int int64_t; typedef unsigned char u_int8_t; typedef unsigned short int u_int16_t; typedef unsigned int u_int32_t; -# if __GLIBC_HAVE_LONG_LONG +# if __WORDSIZE == 64 +typedef unsigned long int u_int64_t; +# elif __GLIBC_HAVE_LONG_LONG __extension__ typedef unsigned long long int u_int64_t; # endif diff --git a/posix/sys/wait.h b/posix/sys/wait.h index 372d46c79a..d7a58eab13 100644 --- a/posix/sys/wait.h +++ b/posix/sys/wait.h @@ -1,4 +1,5 @@ -/* Copyright (C) 1991-1994,1996-2001,2003,2004 Free Software Foundation, Inc. +/* Copyright (C) 1991-1994,1996-2001,2003,2004,2005 + Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -42,11 +43,11 @@ __BEGIN_DECLS as well as POSIX.1 use of `int' for the status word. */ # if defined __GNUC__ && !defined __cplusplus -# define __WAIT_INT(status) \ - (__extension__ ({ union { __typeof(status) __in; int __i; } __u; \ - __u.__in = (status); __u.__i; })) +# define __WAIT_INT(status) \ + (__extension__ (((union { __typeof(status) __in; int __i; }) \ + { .__in = (status) }).__i)) # else -# define __WAIT_INT(status) (*(int *) &(status)) +# define __WAIT_INT(status) (*(__const int *) &(status)) # endif /* This is the type of the argument to `wait'. The funky union diff --git a/posix/sysconf.c b/posix/sysconf.c new file mode 100644 index 0000000000..f22685cb29 --- /dev/null +++ b/posix/sysconf.c @@ -0,0 +1,273 @@ +/* Copyright (C) 1991,1993,1995-1997,2001,2002,2003 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <grp.h> +#include <pwd.h> +#include <stdio.h> +#include <unistd.h> +#include <time.h> +#include <limits.h> +#include <sys/param.h> +#include <sys/sysinfo.h> + + +/* Get the value of the system variable NAME. */ +long int +__sysconf (name) + int name; +{ + switch (name) + { + default: + __set_errno (EINVAL); + return -1; + + case _SC_TZNAME_MAX: + return MAX (__tzname_max (), _POSIX_TZNAME_MAX); + + case _SC_CHARCLASS_NAME_MAX: +#ifdef CHARCLASS_NAME_MAX + return CHARCLASS_NAME_MAX; +#else + return -1; +#endif + + case _SC_COLL_WEIGHTS_MAX: +#ifdef COLL_WEIGHTS_MAX + return COLL_WEIGHTS_MAX; +#else + return -1; +#endif + + case _SC_EQUIV_CLASS_MAX: +#ifdef EQUIV_CLASS_MAX + return EQUIV_CLASS_MAX; +#else + return -1; +#endif + + case _SC_2_LOCALEDEF: +#ifdef _POSIX2_LOCALEDEF + return _POSIX2_LOCALEDEF; +#else + return -1; +#endif + + case _SC_NPROCESSORS_CONF: + return __get_nprocs_conf (); + + case _SC_NPROCESSORS_ONLN: + return __get_nprocs (); + + case _SC_PHYS_PAGES: + return __get_phys_pages (); + + case _SC_AVPHYS_PAGES: + return __get_avphys_pages (); + + case _SC_ATEXIT_MAX: + /* We have no limit since we use lists. */ + return INT_MAX; + + case _SC_PASS_MAX: + /* We have no limit but since the return value might be used to + allocate a buffer we restrict the value. */ + return BUFSIZ; + + case _SC_CHAR_BIT: + return CHAR_BIT; + + case _SC_CHAR_MAX: + return CHAR_MAX; + + case _SC_CHAR_MIN: + return CHAR_MIN; + + case _SC_INT_MAX: + return INT_MAX; + + case _SC_INT_MIN: + return INT_MIN; + + case _SC_LONG_BIT: + return sizeof (long int) * CHAR_BIT; + + case _SC_WORD_BIT: + return sizeof (int) * CHAR_BIT; + + case _SC_MB_LEN_MAX: + return MB_LEN_MAX; + + case _SC_NZERO: + return NZERO; + + case _SC_SSIZE_MAX: + return _POSIX_SSIZE_MAX; + + case _SC_SCHAR_MAX: + return SCHAR_MAX; + + case _SC_SCHAR_MIN: + return SCHAR_MIN; + + case _SC_SHRT_MAX: + return SHRT_MAX; + + case _SC_SHRT_MIN: + return SHRT_MIN; + + case _SC_UCHAR_MAX: + return UCHAR_MAX; + + case _SC_UINT_MAX: + return UINT_MAX; + + case _SC_ULONG_MAX: + return ULONG_MAX; + + case _SC_USHRT_MAX: + return USHRT_MAX; + + case _SC_GETGR_R_SIZE_MAX: + return NSS_BUFLEN_GROUP; + + case _SC_GETPW_R_SIZE_MAX: + return NSS_BUFLEN_PASSWD; + + case _SC_ARG_MAX: + case _SC_CHILD_MAX: + case _SC_CLK_TCK: + case _SC_NGROUPS_MAX: + case _SC_OPEN_MAX: + case _SC_STREAM_MAX: + case _SC_JOB_CONTROL: + case _SC_SAVED_IDS: + case _SC_REALTIME_SIGNALS: + case _SC_PRIORITY_SCHEDULING: + case _SC_TIMERS: + case _SC_ASYNCHRONOUS_IO: + case _SC_PRIORITIZED_IO: + case _SC_SYNCHRONIZED_IO: + case _SC_FSYNC: + case _SC_MAPPED_FILES: + case _SC_MEMLOCK: + case _SC_MEMLOCK_RANGE: + case _SC_MEMORY_PROTECTION: + case _SC_MESSAGE_PASSING: + case _SC_SEMAPHORES: + case _SC_SHARED_MEMORY_OBJECTS: + + case _SC_AIO_LISTIO_MAX: + case _SC_AIO_MAX: + case _SC_AIO_PRIO_DELTA_MAX: + case _SC_DELAYTIMER_MAX: + case _SC_MQ_OPEN_MAX: + case _SC_MQ_PRIO_MAX: + case _SC_VERSION: + case _SC_PAGESIZE: + case _SC_RTSIG_MAX: + case _SC_SEM_NSEMS_MAX: + case _SC_SEM_VALUE_MAX: + case _SC_SIGQUEUE_MAX: + case _SC_TIMER_MAX: + + case _SC_PII: + case _SC_PII_XTI: + case _SC_PII_SOCKET: + case _SC_PII_OSI: + case _SC_POLL: + case _SC_SELECT: + case _SC_UIO_MAXIOV: + case _SC_PII_INTERNET_STREAM: + case _SC_PII_INTERNET_DGRAM: + case _SC_PII_OSI_COTS: + case _SC_PII_OSI_CLTS: + case _SC_PII_OSI_M: + case _SC_T_IOV_MAX: + + case _SC_BC_BASE_MAX: + case _SC_BC_DIM_MAX: + case _SC_BC_SCALE_MAX: + case _SC_BC_STRING_MAX: + case _SC_EXPR_NEST_MAX: + case _SC_LINE_MAX: + case _SC_RE_DUP_MAX: + case _SC_2_VERSION: + case _SC_2_C_BIND: + case _SC_2_C_DEV: + case _SC_2_FORT_DEV: + case _SC_2_SW_DEV: + case _SC_2_CHAR_TERM: + case _SC_2_C_VERSION: + case _SC_2_UPE: + + case _SC_THREADS: + case _SC_THREAD_SAFE_FUNCTIONS: + case _SC_LOGIN_NAME_MAX: + case _SC_TTY_NAME_MAX: + case _SC_THREAD_DESTRUCTOR_ITERATIONS: + case _SC_THREAD_KEYS_MAX: + case _SC_THREAD_STACK_MIN: + case _SC_THREAD_THREADS_MAX: + case _SC_THREAD_ATTR_STACKADDR: + case _SC_THREAD_ATTR_STACKSIZE: + case _SC_THREAD_PRIORITY_SCHEDULING: + case _SC_THREAD_PRIO_INHERIT: + case _SC_THREAD_PRIO_PROTECT: + case _SC_THREAD_PROCESS_SHARED: + + case _SC_XOPEN_VERSION: + case _SC_XOPEN_XCU_VERSION: + case _SC_XOPEN_UNIX: + case _SC_XOPEN_CRYPT: + case _SC_XOPEN_ENH_I18N: + case _SC_XOPEN_SHM: + case _SC_XOPEN_XPG2: + case _SC_XOPEN_XPG3: + case _SC_XOPEN_XPG4: + + case _SC_NL_ARGMAX: + case _SC_NL_LANGMAX: + case _SC_NL_MSGMAX: + case _SC_NL_NMAX: + case _SC_NL_SETMAX: + case _SC_NL_TEXTMAX: + + case _SC_XBS5_ILP32_OFF32: + case _SC_XBS5_ILP32_OFFBIG: + case _SC_XBS5_LP64_OFF64: + case _SC_XBS5_LPBIG_OFFBIG: + + case _SC_XOPEN_LEGACY: + case _SC_XOPEN_REALTIME: + case _SC_XOPEN_REALTIME_THREADS: + + break; + } + + __set_errno (ENOSYS); + return -1; +} + +weak_alias (__sysconf, sysconf) +libc_hidden_def (__sysconf) + +stub_warning (sysconf) +#include <stub-tag.h> diff --git a/posix/times.c b/posix/times.c new file mode 100644 index 0000000000..b4e08156ae --- /dev/null +++ b/posix/times.c @@ -0,0 +1,43 @@ +/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sys/times.h> +#include <stddef.h> + +/* Store the CPU time used by this process and all its + dead children (and their dead children) in BUFFER. + Return the elapsed real time, or (clock_t) -1 for errors. + All times are in CLK_TCKths of a second. */ +clock_t +__times (buffer) + struct tms *buffer; +{ + if (buffer == NULL) + { + __set_errno (EINVAL); + return (clock_t) -1; + } + + __set_errno (ENOSYS); + return (clock_t) -1; +} +stub_warning (times) + +weak_alias (__times, times) +#include <stub-tag.h> diff --git a/posix/transbug.c b/posix/transbug.c index 3ae4929593..d0983b4d44 100755 --- a/posix/transbug.c +++ b/posix/transbug.c @@ -79,7 +79,7 @@ run_test (const char *pattern, struct re_registers *regs) exit (1); } - pat.translate = (char *) casetable; + pat.translate = (unsigned char *) casetable; err = re_compile_pattern (pattern, strlen (pattern), &pat); if (err != NULL) diff --git a/posix/tst-exec.c b/posix/tst-exec.c index a67d2000bc..f3971e8c97 100644 --- a/posix/tst-exec.c +++ b/posix/tst-exec.c @@ -57,7 +57,7 @@ static const char fd2string[] = "This file should stay opened"; void do_prepare (int argc, char *argv[]) { - char name_len; + size_t name_len; name_len = strlen (test_dir); name1 = malloc (name_len + sizeof ("/execXXXXXX")); diff --git a/posix/tst-execl1.c b/posix/tst-execl1.c new file mode 100644 index 0000000000..1cfa36df12 --- /dev/null +++ b/posix/tst-execl1.c @@ -0,0 +1,22 @@ +#include <errno.h> +#include <stdio.h> +#include <unistd.h> + +static int +do_test (void) +{ + static const char prog[] = "does-not-exist"; + errno = 0; + execl (prog, prog, NULL); + + if (errno != ENOENT) + { + printf ("errno = %d (%m), expected ENOENT\n", errno); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/posix/tst-execl2.c b/posix/tst-execl2.c new file mode 100644 index 0000000000..5b74959ef8 --- /dev/null +++ b/posix/tst-execl2.c @@ -0,0 +1,58 @@ +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/stat.h> + + +static void prepare (int argc, char *argv[]); +static int do_test (void); +#define PREPARE(argc, argv) prepare (argc, argv) +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + + +static char *copy; + +static void +prepare (int argc, char *argv[]) +{ + char *buf; + int off; + asprintf (&buf, "cp %s %n%s-copy", argv[0], &off, argv[0]); + if (buf == NULL) + { + puts ("asprintf failed"); + exit (1); + } + if (system (buf) != 0) + { + puts ("system failed"); + exit (1); + } + + /* Make it not executable. */ + copy = buf + off; + if (chmod (copy, 0666) != 0) + { + puts ("chmod failed"); + exit (1); + } + + add_temp_file (copy); +} + + +static int +do_test (void) +{ + errno = 0; + execl (copy, copy, NULL); + + if (errno != EACCES) + { + printf ("errno = %d (%m), expected EACCES\n", errno); + return 1; + } + + return 0; +} diff --git a/posix/tst-execle1.c b/posix/tst-execle1.c new file mode 100644 index 0000000000..84470703f1 --- /dev/null +++ b/posix/tst-execle1.c @@ -0,0 +1,23 @@ +#include <errno.h> +#include <stdio.h> +#include <unistd.h> + +static int +do_test (void) +{ + static const char prog[] = "does-not-exist"; + const char *env [] = {"FOO=BAR", NULL}; + errno = 0; + execle (prog, prog, NULL, env); + + if (errno != ENOENT) + { + printf ("errno = %d (%m), expected ENOENT\n", errno); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/posix/tst-execle2.c b/posix/tst-execle2.c new file mode 100644 index 0000000000..0430b7b573 --- /dev/null +++ b/posix/tst-execle2.c @@ -0,0 +1,59 @@ +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/stat.h> + + +static void prepare (int argc, char *argv[]); +static int do_test (void); +#define PREPARE(argc, argv) prepare (argc, argv) +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + + +static char *copy; + +static void +prepare (int argc, char *argv[]) +{ + char *buf; + int off; + asprintf (&buf, "cp %s %n%s-copy", argv[0], &off, argv[0]); + if (buf == NULL) + { + puts ("asprintf failed"); + exit (1); + } + if (system (buf) != 0) + { + puts ("system failed"); + exit (1); + } + + /* Make it not executable. */ + copy = buf + off; + if (chmod (copy, 0666) != 0) + { + puts ("chmod failed"); + exit (1); + } + + add_temp_file (copy); +} + + +static int +do_test (void) +{ + const char *env[] = {"FOO=BAR", NULL}; + errno = 0; + execle (copy, copy, NULL, env); + + if (errno != EACCES) + { + printf ("errno = %d (%m), expected EACCES\n", errno); + return 1; + } + + return 0; +} diff --git a/posix/tst-execlp1.c b/posix/tst-execlp1.c new file mode 100644 index 0000000000..1be4dbcb1b --- /dev/null +++ b/posix/tst-execlp1.c @@ -0,0 +1,34 @@ +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +static int +do_test (void) +{ + char *cwd = get_current_dir_name (); + if (cwd == NULL) + { + puts ("get_current_dir_name failed"); + return 1; + } + + /* Make sure we do not find a binary with the name we are going to + use. */ + setenv ("PATH", cwd, 1); + + static const char prog[] = "does-not-exist"; + errno = 0; + execlp (prog, prog, NULL); + + if (errno != ENOENT) + { + printf ("errno = %d (%m), expected ENOENT\n", errno); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/posix/tst-execlp2.c b/posix/tst-execlp2.c new file mode 100644 index 0000000000..81a723dda4 --- /dev/null +++ b/posix/tst-execlp2.c @@ -0,0 +1,82 @@ +#include <errno.h> +#include <libgen.h> +#undef basename +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> + + +static void prepare (int argc, char *argv[]); +static int do_test (void); +#define PREPARE(argc, argv) prepare (argc, argv) +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + + +static char *copy; + +static void +prepare (int argc, char *argv[]) +{ + char *buf; + int off; + asprintf (&buf, "cp %s %n%s-copy", argv[0], &off, argv[0]); + if (buf == NULL) + { + puts ("asprintf failed"); + exit (1); + } + if (system (buf) != 0) + { + puts ("system failed"); + exit (1); + } + + /* Make it not executable. */ + copy = buf + off; + if (chmod (copy, 0666) != 0) + { + puts ("chmod failed"); + exit (1); + } + + add_temp_file (copy); +} + + +static int +do_test (void) +{ + /* Make sure we do not find a binary with the name we are going to + use. */ + char *bindir = strdupa (copy); + bindir = canonicalize_file_name (dirname (bindir)); + if (bindir == NULL) + { + puts ("canonicalize_file_name failed"); + return 1; + } + char *path; + asprintf (&path, "%s:../libio:../elf", bindir); + if (path == NULL) + { + puts ("asprintf failed"); + return 1; + } + + setenv ("PATH", path, 1); + + char *prog = basename (copy); + errno = 0; + execlp (prog, prog, NULL); + + if (errno != EACCES) + { + printf ("errno = %d (%m), expected EACCES\n", errno); + return 1; + } + + return 0; +} diff --git a/posix/tst-execv1.c b/posix/tst-execv1.c new file mode 100644 index 0000000000..57ed1add6e --- /dev/null +++ b/posix/tst-execv1.c @@ -0,0 +1,22 @@ +#include <errno.h> +#include <stdio.h> +#include <unistd.h> + +static int +do_test (void) +{ + char *argv[] = { (char *) "does-not-exist", NULL }; + errno = 0; + execv (argv[0], argv); + + if (errno != ENOENT) + { + printf ("errno = %d (%m), expected ENOENT\n", errno); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/posix/tst-execv2.c b/posix/tst-execv2.c new file mode 100644 index 0000000000..a5168a269c --- /dev/null +++ b/posix/tst-execv2.c @@ -0,0 +1,60 @@ +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/stat.h> + + +static void prepare (int argc, char *argv[]); +static int do_test (void); +#define PREPARE(argc, argv) prepare (argc, argv) +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + + +static char *copy; + +static void +prepare (int argc, char *argv[]) +{ + char *buf; + int off; + asprintf (&buf, "cp %s %n%s-copy", argv[0], &off, argv[0]); + if (buf == NULL) + { + puts ("asprintf failed"); + exit (1); + } + if (system (buf) != 0) + { + puts ("system failed"); + exit (1); + } + + /* Make it not executable. */ + copy = buf + off; + if (chmod (copy, 0666) != 0) + { + puts ("chmod failed"); + exit (1); + } + + add_temp_file (copy); +} + + +static int +do_test (void) +{ + char *argv[] = { copy, NULL }; + + errno = 0; + execv (copy, argv); + + if (errno != EACCES) + { + printf ("errno = %d (%m), expected EACCES\n", errno); + return 1; + } + + return 0; +} diff --git a/posix/tst-execve1.c b/posix/tst-execve1.c new file mode 100644 index 0000000000..356610f635 --- /dev/null +++ b/posix/tst-execve1.c @@ -0,0 +1,23 @@ +#include <errno.h> +#include <stdio.h> +#include <unistd.h> + +static int +do_test (void) +{ + char *argv[] = { (char *) "does-not-exist", NULL }; + char *envp[] = { (char *) "FOO=BAR", NULL }; + errno = 0; + execve (argv[0], argv, envp); + + if (errno != ENOENT) + { + printf ("errno = %d (%m), expected ENOENT\n", errno); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/posix/tst-execve2.c b/posix/tst-execve2.c new file mode 100644 index 0000000000..1a804e94fd --- /dev/null +++ b/posix/tst-execve2.c @@ -0,0 +1,61 @@ +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/stat.h> + + +static void prepare (int argc, char *argv[]); +static int do_test (void); +#define PREPARE(argc, argv) prepare (argc, argv) +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + + +static char *copy; + +static void +prepare (int argc, char *argv[]) +{ + char *buf; + int off; + asprintf (&buf, "cp %s %n%s-copy", argv[0], &off, argv[0]); + if (buf == NULL) + { + puts ("asprintf failed"); + exit (1); + } + if (system (buf) != 0) + { + puts ("system failed"); + exit (1); + } + + /* Make it not executable. */ + copy = buf + off; + if (chmod (copy, 0666) != 0) + { + puts ("chmod failed"); + exit (1); + } + + add_temp_file (copy); +} + + +static int +do_test (void) +{ + char *argv[] = { copy, NULL }; + char *envp[] = { (char *) "FOO=BAR", NULL }; + + errno = 0; + execve (copy, argv, envp); + + if (errno != EACCES) + { + printf ("errno = %d (%m), expected EACCES\n", errno); + return 1; + } + + return 0; +} diff --git a/posix/tst-execvp1.c b/posix/tst-execvp1.c new file mode 100644 index 0000000000..ecc673d124 --- /dev/null +++ b/posix/tst-execvp1.c @@ -0,0 +1,34 @@ +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +static int +do_test (void) +{ + char *cwd = get_current_dir_name (); + if (cwd == NULL) + { + puts ("get_current_dir_name failed"); + return 1; + } + + /* Make sure we do not find a binary with the name we are going to + use. */ + setenv ("PATH", cwd, 1); + + char *argv[] = { (char *) "does-not-exist", NULL }; + errno = 0; + execvp (argv[0], argv); + + if (errno != ENOENT) + { + printf ("errno = %d (%m), expected ENOENT\n", errno); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/posix/tst-execvp2.c b/posix/tst-execvp2.c new file mode 100644 index 0000000000..7e0f5d882c --- /dev/null +++ b/posix/tst-execvp2.c @@ -0,0 +1,82 @@ +#include <errno.h> +#include <libgen.h> +#undef basename +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> + + +static void prepare (int argc, char *argv[]); +static int do_test (void); +#define PREPARE(argc, argv) prepare (argc, argv) +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + + +static char *copy; + +static void +prepare (int argc, char *argv[]) +{ + char *buf; + int off; + asprintf (&buf, "cp %s %n%s-copy", argv[0], &off, argv[0]); + if (buf == NULL) + { + puts ("asprintf failed"); + exit (1); + } + if (system (buf) != 0) + { + puts ("system failed"); + exit (1); + } + + /* Make it not executable. */ + copy = buf + off; + if (chmod (copy, 0666) != 0) + { + puts ("chmod failed"); + exit (1); + } + + add_temp_file (copy); +} + + +static int +do_test (void) +{ + /* Make sure we do not find a binary with the name we are going to + use. */ + char *bindir = strdupa (copy); + bindir = canonicalize_file_name (dirname (bindir)); + if (bindir == NULL) + { + puts ("canonicalize_file_name failed"); + return 1; + } + char *path; + asprintf (&path, "%s:../libio:../elf", bindir); + if (path == NULL) + { + puts ("asprintf failed"); + return 1; + } + + setenv ("PATH", path, 1); + + char *argv[] = { basename (copy), NULL }; + errno = 0; + execvp (argv[0], argv); + + if (errno != EACCES) + { + printf ("errno = %d (%m), expected EACCES\n", errno); + return 1; + } + + return 0; +} diff --git a/posix/tst-execvp3.c b/posix/tst-execvp3.c new file mode 100644 index 0000000000..5ebc87952d --- /dev/null +++ b/posix/tst-execvp3.c @@ -0,0 +1,42 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> + + +static void do_prepare (void); +#define PREPARE(argc, argv) do_prepare () +static int do_test (void); +#define TEST_FUNCTION do_test () + +#include "../test-skeleton.c" + + +static char *fname; + +static void +do_prepare (void) +{ + int fd = create_temp_file ("testscript", &fname); + dprintf (fd, "echo foo\n"); + fchmod (fd, 0700); + close (fd); +} + + +static int +do_test (void) +{ + if (setenv ("PATH", test_dir, 1) != 0) + { + puts ("setenv failed"); + return 1; + } + + char *argv[] = { fname, NULL }; + execvp (basename (fname), argv); + + /* If we come here, the execvp call failed. */ + return 1; +} diff --git a/posix/tst-execvp4.c b/posix/tst-execvp4.c new file mode 100644 index 0000000000..531fab227b --- /dev/null +++ b/posix/tst-execvp4.c @@ -0,0 +1,35 @@ +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> + +static int +do_test (void) +{ + char buf[40] = "/usr/bin/does-not-exist"; + size_t stemlen = strlen (buf); + struct stat64 st; + int cnt = 0; + while (stat64 (buf, &st) != -1 || errno != ENOENT + || stat64 (buf + 4, &st) != -1 || errno != ENOENT) + { + if (cnt++ == 100) + { + puts ("cannot find a unique file name"); + return 0; + } + + strcpy (buf + stemlen, ".XXXXXX"); + mktemp (buf); + } + + unsetenv ("PATH"); + char *argv[] = { buf + 9, NULL }; + execvp (argv[0], argv); + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/posix/tst-getaddrinfo3.c b/posix/tst-getaddrinfo3.c new file mode 100644 index 0000000000..5077f311fc --- /dev/null +++ b/posix/tst-getaddrinfo3.c @@ -0,0 +1,151 @@ +#include <mcheck.h> +#include <netdb.h> +#include <stdio.h> +#include <string.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> + + +static int +do_test (void) +{ + mtrace (); + + int result = 0; + struct addrinfo hints; + struct addrinfo *ai_res; + int s; + +#define T(no, fail, addr, fam, coraddr) \ + s = getaddrinfo (addr, NULL, &hints, &ai_res); \ + if (s != 0) \ + { \ + if (s != fail) \ + { \ + printf ("getaddrinfo test %d failed: %s\n", no, gai_strerror (s)); \ + result = 1; \ + } \ + ai_res = NULL; \ + } \ + else if (fail) \ + { \ + printf ("getaddrinfo test %d should have failed but did not\n", no); \ + result = 1; \ + } \ + else if (ai_res->ai_family != fam) \ + { \ + printf ("\ +getaddrinfo test %d return address of family %d, expected %d\n", \ + no, ai_res->ai_family, fam); \ + result = 1; \ + } \ + else if (fam == AF_INET) \ + { \ + if (ai_res->ai_addrlen != sizeof (struct sockaddr_in)) \ + { \ + printf ("getaddrinfo test %d: address size %zu, expected %zu\n", \ + no, (size_t) ai_res->ai_addrlen, \ + sizeof (struct sockaddr_in)); \ + result = 1; \ + } \ + else if (strcmp (coraddr, \ + inet_ntoa (((struct sockaddr_in *) ai_res->ai_addr)->sin_addr))\ + != 0) \ + { \ + printf ("getaddrinfo test %d: got value %s, expected %s\n", \ + no, \ + inet_ntoa (((struct sockaddr_in *) ai_res->ai_addr)->sin_addr), \ + coraddr); \ + result = 1; \ + } \ + } \ + else \ + { \ + char buf[100]; \ + \ + if (ai_res->ai_addrlen != sizeof (struct sockaddr_in6)) \ + { \ + printf ("getaddrinfo test %d: address size %zu, expected %zu\n", \ + no, (size_t) ai_res->ai_addrlen, \ + sizeof (struct sockaddr_in6)); \ + result = 1; \ + } \ + else if (strcmp (coraddr, \ + inet_ntop (AF_INET6, \ + &((struct sockaddr_in6 *) ai_res->ai_addr)->sin6_addr,\ + buf, sizeof (buf))) \ + != 0) \ + { \ + printf ("getaddrinfo test %d: got value %s, expected %s\n", \ + no, \ + inet_ntop (AF_INET6, \ + & ((struct sockaddr_in6 *) ai_res->ai_addr)->sin6_addr, \ + buf, sizeof (buf)), \ + coraddr); \ + result = 1; \ + } \ + } \ + if (ai_res != NULL && ai_res->ai_next != NULL) \ + { \ + puts ("expected only one result"); \ + result = 1; \ + } \ + freeaddrinfo (ai_res) + + + memset (&hints, '\0', sizeof (hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + T (1, 0, "127.0.0.1", AF_INET, "127.0.0.1"); + + memset (&hints, '\0', sizeof (hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + T (2, 0, "127.0.0.1", AF_INET, "127.0.0.1"); + + memset (&hints, '\0', sizeof (hints)); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_V4MAPPED; + T (3, 0, "127.0.0.1", AF_INET6, "::ffff:127.0.0.1"); + + memset (&hints, '\0', sizeof (hints)); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_STREAM; + T (4, EAI_ADDRFAMILY, "127.0.0.1", AF_INET6, ""); + + memset (&hints, '\0', sizeof (hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + T (5, 0, "::1", AF_INET6, "::1"); + + memset (&hints, '\0', sizeof (hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + T (6, EAI_ADDRFAMILY, "::1", AF_INET6, ""); + + memset (&hints, '\0', sizeof (hints)); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_STREAM; + T (7, 0, "::1", AF_INET6, "::1"); + + memset (&hints, '\0', sizeof (hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + T (8, 0, "::ffff:127.0.0.1", AF_INET6, "::ffff:127.0.0.1"); + + memset (&hints, '\0', sizeof (hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + T (9, 0, "::ffff:127.0.0.1", AF_INET, "127.0.0.1"); + + memset (&hints, '\0', sizeof (hints)); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_STREAM; + T (10, 0, "::ffff:127.0.0.1", AF_INET6, "::ffff:127.0.0.1"); + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/posix/tst-mmap.c b/posix/tst-mmap.c index 355a784124..c03acf5e16 100644 --- a/posix/tst-mmap.c +++ b/posix/tst-mmap.c @@ -30,7 +30,7 @@ main (void) for (c = 0; c < sizeof (buf); ++c) buf[c] = '0' + (c % 10); - for (c = 0; c < 20; ++c) + for (c = 0; c < (ps * 4) / sizeof (buf); ++c) if (fwrite (buf, 1, sizeof (buf), fp) != sizeof (buf)) { printf ("`fwrite' failed: %m\n"); @@ -40,7 +40,7 @@ main (void) assert (ps + 1000 < c * sizeof (buf)); /* First try something which is not allowed: map at an offset which is - not module the pagesize. */ + not modulo the pagesize. */ ptr = mmap (NULL, 1000, PROT_READ, MAP_SHARED, fd, ps - 1); if (ptr != MAP_FAILED) { diff --git a/posix/tst-preadwrite.c b/posix/tst-preadwrite.c index 2810448583..8227a8205b 100644 --- a/posix/tst-preadwrite.c +++ b/posix/tst-preadwrite.c @@ -53,7 +53,7 @@ int fd; void do_prepare (int argc, char *argv[]) { - char name_len; + size_t name_len; #define FNAME FNAME2(TRUNCATE) #define FNAME2(s) "/" STRINGIFY(s) "XXXXXX" diff --git a/posix/tst-rfc3484-2.c b/posix/tst-rfc3484-2.c new file mode 100644 index 0000000000..2536da8f87 --- /dev/null +++ b/posix/tst-rfc3484-2.c @@ -0,0 +1,145 @@ +#include <stdbool.h> +#include <stdio.h> +#include <ifaddrs.h> + +/* Internal definitions used in the libc code. */ +#define __getservbyname_r getservbyname_r +#define __socket socket +#define __getsockname getsockname +#define __inet_aton inet_aton +#define __gethostbyaddr_r gethostbyaddr_r +#define __gethostbyname2_r gethostbyname2_r + +void +attribute_hidden +__check_pf (bool *p1, bool *p2, struct in6addrinfo **in6ai, size_t *in6ailen) +{ + *p1 = *p2 = true; + *in6ai = NULL; + *in6ailen = 0; +} +int +__idna_to_ascii_lz (const char *input, char **output, int flags) +{ + return 0; +} +int +__idna_to_unicode_lzlz (const char *input, char **output, int flags) +{ + return 0; +} + +#include "../sysdeps/posix/getaddrinfo.c" + +service_user *__nss_hosts_database attribute_hidden; + + +/* This is the beginning of the real test code. The above defines + (among other things) the function rfc3484_sort. */ + + +#if __BYTE_ORDER == __BIG_ENDIAN +# define h(n) n +#else +# define h(n) __bswap_constant_32 (n) +#endif + + +ssize_t +__getline (char **lineptr, size_t *n, FILE *s) +{ + *lineptr = NULL; + *n = 0; + return 0; +} + + +static int +do_test (void) +{ + labels = default_labels; + precedence = default_precedence; + + struct sockaddr_in so1; + so1.sin_family = AF_INET; + so1.sin_addr.s_addr = h (0xc0a85f19); + + struct sockaddr_in sa1; + sa1.sin_family = AF_INET; + sa1.sin_addr.s_addr = h (0xe0a85f19); + + struct addrinfo ai1; + ai1.ai_family = AF_INET; + ai1.ai_addr = (struct sockaddr *) &sa1; + + struct sockaddr_in6 so2; + so2.sin6_family = AF_INET6; + so2.sin6_addr.s6_addr32[0] = h (0xfec01234); + so2.sin6_addr.s6_addr32[1] = 1; + so2.sin6_addr.s6_addr32[2] = 1; + so2.sin6_addr.s6_addr32[3] = 1; + + struct sockaddr_in6 sa2; + sa2.sin6_family = AF_INET6; + sa2.sin6_addr.s6_addr32[0] = h (0x07d10001); + sa2.sin6_addr.s6_addr32[1] = 1; + sa2.sin6_addr.s6_addr32[2] = 1; + sa2.sin6_addr.s6_addr32[3] = 1; + + struct addrinfo ai2; + ai2.ai_family = AF_INET6; + ai2.ai_addr = (struct sockaddr *) &sa2; + + + struct sort_result results[2]; + + results[0].dest_addr = &ai1; + results[0].got_source_addr = true; + results[0].source_addr_len = sizeof (so1); + results[0].source_addr_flags = 0; + memcpy (&results[0].source_addr, &so1, sizeof (so1)); + + results[1].dest_addr = &ai2; + results[1].got_source_addr = true; + results[1].source_addr_len = sizeof (so2); + results[1].source_addr_flags = 0; + memcpy (&results[1].source_addr, &so2, sizeof (so2)); + + + qsort (results, 2, sizeof (results[0]), rfc3484_sort); + + int result = 0; + if (results[0].dest_addr->ai_family == AF_INET6) + { + puts ("wrong order in first test"); + result |= 1; + } + + + /* And again, this time with the reverse starting order. */ + results[1].dest_addr = &ai1; + results[1].got_source_addr = true; + results[1].source_addr_len = sizeof (so1); + results[1].source_addr_flags = 0; + memcpy (&results[1].source_addr, &so1, sizeof (so1)); + + results[0].dest_addr = &ai2; + results[0].got_source_addr = true; + results[0].source_addr_len = sizeof (so2); + results[0].source_addr_flags = 0; + memcpy (&results[0].source_addr, &so2, sizeof (so2)); + + + qsort (results, 2, sizeof (results[0]), rfc3484_sort); + + if (results[0].dest_addr->ai_family == AF_INET6) + { + puts ("wrong order in second test"); + result |= 1; + } + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/posix/tst-rfc3484.c b/posix/tst-rfc3484.c new file mode 100644 index 0000000000..2e74e9737f --- /dev/null +++ b/posix/tst-rfc3484.c @@ -0,0 +1,114 @@ +#include <stdbool.h> +#include <stdio.h> +#include <ifaddrs.h> + +/* Internal definitions used in the libc code. */ +#define __getservbyname_r getservbyname_r +#define __socket socket +#define __getsockname getsockname +#define __inet_aton inet_aton +#define __gethostbyaddr_r gethostbyaddr_r +#define __gethostbyname2_r gethostbyname2_r + +void +attribute_hidden +__check_pf (bool *p1, bool *p2, struct in6addrinfo **in6ai, size_t *in6ailen) +{ + *p1 = *p2 = true; + *in6ai = NULL; + *in6ailen = 0; +} +int +__idna_to_ascii_lz (const char *input, char **output, int flags) +{ + return 0; +} +int +__idna_to_unicode_lzlz (const char *input, char **output, int flags) +{ + return 0; +} + +#include "../sysdeps/posix/getaddrinfo.c" + +service_user *__nss_hosts_database attribute_hidden; + + +/* This is the beginning of the real test code. The above defines + (among other things) the function rfc3484_sort. */ + + +#if __BYTE_ORDER == __BIG_ENDIAN +# define h(n) n +#else +# define h(n) __bswap_constant_32 (n) +#endif + +struct sockaddr_in addrs[] = +{ + { .sin_family = AF_INET, .sin_addr = { h (0xc0a86d1d) } }, + { .sin_family = AF_INET, .sin_addr = { h (0xc0a85d03) } }, + { .sin_family = AF_INET, .sin_addr = { h (0xc0a82c3d) } }, + { .sin_family = AF_INET, .sin_addr = { h (0xc0a86002) } }, + { .sin_family = AF_INET, .sin_addr = { h (0xc0a802f3) } }, + { .sin_family = AF_INET, .sin_addr = { h (0xc0a80810) } }, + { .sin_family = AF_INET, .sin_addr = { h (0xc0a85e02) } } +}; +#define naddrs (sizeof (addrs) / sizeof (addrs[0])) +static struct addrinfo ais[naddrs]; +static struct sort_result results[naddrs]; + +static int expected[naddrs] = + { + 6, 1, 0, 3, 2, 4, 5 + }; + + +ssize_t +__getline (char **lineptr, size_t *n, FILE *s) +{ + *lineptr = NULL; + *n = 0; + return 0; +} + + +static int +do_test (void) +{ + labels = default_labels; + precedence = default_precedence; + + struct sockaddr_in so; + so.sin_family = AF_INET; + so.sin_addr.s_addr = h (0xc0a85f19); + + for (int i = 0; i < naddrs; ++i) + { + ais[i].ai_family = AF_INET; + ais[i].ai_addr = (struct sockaddr *) &addrs[i]; + results[i].dest_addr = &ais[i]; + results[i].got_source_addr = true; + memcpy(&results[i].source_addr, &so, sizeof (so)); + results[i].source_addr_len = sizeof (so); + results[i].source_addr_flags = 0; + } + + qsort (results, naddrs, sizeof (results[0]), rfc3484_sort); + + int result = 0; + for (int i = 0; i < naddrs; ++i) + { + struct in_addr addr = ((struct sockaddr_in *) (results[i].dest_addr->ai_addr))->sin_addr; + + int here = memcmp (&addr, &addrs[expected[i]].sin_addr, + sizeof (struct in_addr)); + printf ("[%d] = %s: %s\n", i, inet_ntoa (addr), here ? "FAIL" : "OK"); + result |= here; + } + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/posix/tst-rxspencer.c b/posix/tst-rxspencer.c index cb40421797..a68bab2de9 100644 --- a/posix/tst-rxspencer.c +++ b/posix/tst-rxspencer.c @@ -1,5 +1,5 @@ /* Regular expression tests. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. @@ -127,14 +127,15 @@ mb_frob_string (const char *str, const char *letters) } /* Like mb_frob_string, but don't replace anything between - [: and :], [. and .] or [= and =]. */ + [: and :], [. and .] or [= and =] or characters escaped + with a backslash. */ static char * mb_frob_pattern (const char *str, const char *letters) { char *ret, *dst; const char *src; - int in_class = 0; + int in_class = 0, escaped = 0; if (str == NULL) return NULL; @@ -144,7 +145,18 @@ mb_frob_pattern (const char *str, const char *letters) return NULL; for (src = str, dst = ret; *src; ++src) - if (!in_class && strchr (letters, *src)) + if (*src == '\\') + { + escaped ^= 1; + *dst++ = *src; + } + else if (escaped) + { + escaped = 0; + *dst++ = *src; + continue; + } + else if (!in_class && strchr (letters, *src)) dst = mb_replace (dst, *src); else { diff --git a/posix/tst-spawn.c b/posix/tst-spawn.c index 745f64d3ba..4b5d894235 100644 --- a/posix/tst-spawn.c +++ b/posix/tst-spawn.c @@ -61,7 +61,7 @@ static const char fd3string[] = "This file will be opened"; void do_prepare (int argc, char *argv[]) { - char name_len; + size_t name_len; name_len = strlen (test_dir); name1 = (char *) malloc (name_len + sizeof ("/spawnXXXXXX")); diff --git a/posix/tst-truncate.c b/posix/tst-truncate.c index d786306409..78a5139477 100644 --- a/posix/tst-truncate.c +++ b/posix/tst-truncate.c @@ -54,7 +54,7 @@ int fd; void do_prepare (int argc, char *argv[]) { - char name_len; + size_t name_len; #define FNAME FNAME2(TRUNCATE) #define FNAME2(s) "/" STRINGIFY(s) "XXXXXX" diff --git a/posix/tst-vfork3.c b/posix/tst-vfork3.c new file mode 100644 index 0000000000..954d395fd2 --- /dev/null +++ b/posix/tst-vfork3.c @@ -0,0 +1,224 @@ +/* Test for vfork functions. + Copyright (C) 2007 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2007. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <fcntl.h> +#include <mcheck.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/wait.h> + +static int do_test (void); +static void do_prepare (void); +char *tmpdirname; + +#define TEST_FUNCTION do_test () +#define PREPARE(argc, argv) do_prepare () +#include "../test-skeleton.c" + +static int +do_test (void) +{ + mtrace (); + + const char *path = getenv ("PATH"); + if (path == NULL) + path = "/bin"; + char pathbuf[strlen (tmpdirname) + 1 + strlen (path) + 1]; + strcpy (stpcpy (stpcpy (pathbuf, tmpdirname), ":"), path); + if (setenv ("PATH", pathbuf, 1) < 0) + { + puts ("setenv failed"); + return 1; + } + + size_t i; + char *argv[3] = { (char *) "script1.sh", (char *) "1", NULL }; + for (i = 0; i < 5; i++) + { + pid_t pid = vfork (); + if (pid < 0) + { + printf ("vfork failed: %m\n"); + return 1; + } + else if (pid == 0) + { + execvp ("script1.sh", argv); + _exit (errno); + } + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("waitpid failed"); + return 1; + } + else if (status != 0) + { + if (WIFEXITED (status)) + printf ("script1.sh failed with status %d\n", + WEXITSTATUS (status)); + else + printf ("script1.sh kill by signal %d\n", + WTERMSIG (status)); + return 1; + } + } + + argv[0] = (char *) "script2.sh"; + argv[1] = (char *) "2"; + for (i = 0; i < 5; i++) + { + pid_t pid = vfork (); + if (pid < 0) + { + printf ("vfork failed: %m\n"); + return 1; + } + else if (pid == 0) + { + execvp ("script2.sh", argv); + _exit (errno); + } + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("waitpid failed"); + return 1; + } + else if (status != 0) + { + printf ("script2.sh failed with status %d\n", status); + return 1; + } + } + + for (i = 0; i < 5; i++) + { + pid_t pid = vfork (); + if (pid < 0) + { + printf ("vfork failed: %m\n"); + return 1; + } + else if (pid == 0) + { + execlp ("script2.sh", "script2.sh", "3", NULL); + _exit (errno); + } + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("waitpid failed"); + return 1; + } + else if (status != 0) + { + printf ("script2.sh failed with status %d\n", status); + return 1; + } + } + + unsetenv ("PATH"); + argv[0] = (char *) "echo"; + argv[1] = (char *) "script 4"; + for (i = 0; i < 5; i++) + { + pid_t pid = vfork (); + if (pid < 0) + { + printf ("vfork failed: %m\n"); + return 1; + } + else if (pid == 0) + { + execvp ("echo", argv); + _exit (errno); + } + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("waitpid failed"); + return 1; + } + else if (status != 0) + { + printf ("echo failed with status %d\n", status); + return 1; + } + } + + return 0; +} + +static void +do_prepare (void) +{ + size_t len = strlen (test_dir) + sizeof ("/tst-vfork3.XXXXXX"); + tmpdirname = malloc (len); + char *script1 = malloc (len + sizeof "/script1.sh"); + char *script2 = malloc (len + sizeof "/script2.sh"); + if (tmpdirname == NULL || script1 == NULL || script2 == NULL) + { + puts ("out of memory"); + exit (1); + } + strcpy (stpcpy (tmpdirname, test_dir), "/tst-vfork3.XXXXXX"); + + tmpdirname = mkdtemp (tmpdirname); + if (tmpdirname == NULL) + { + puts ("could not create temporary directory"); + exit (1); + } + + strcpy (stpcpy (script1, tmpdirname), "/script1.sh"); + strcpy (stpcpy (script2, tmpdirname), "/script2.sh"); + + /* Need to make sure tmpdirname is at the end of the linked list. */ + add_temp_file (script1); + add_temp_file (tmpdirname); + add_temp_file (script2); + + const char content1[] = "#!/bin/sh\necho script $1\n"; + int fd = open (script1, O_WRONLY | O_CREAT, 0700); + if (fd < 0 + || TEMP_FAILURE_RETRY (write (fd, content1, sizeof content1)) + != sizeof content1 + || fchmod (fd, S_IRUSR | S_IXUSR) < 0) + { + printf ("Could not write %s\n", script1); + exit (1); + } + close (fd); + + const char content2[] = "echo script $1\n"; + fd = open (script2, O_WRONLY | O_CREAT, 0700); + if (fd < 0 + || TEMP_FAILURE_RETRY (write (fd, content2, sizeof content2)) + != sizeof content2 + || fchmod (fd, S_IRUSR | S_IXUSR) < 0) + { + printf ("Could not write %s\n", script2); + exit (1); + } + close (fd); +} diff --git a/posix/uname.c b/posix/uname.c new file mode 100644 index 0000000000..e7c41648ed --- /dev/null +++ b/posix/uname.c @@ -0,0 +1,66 @@ +/* Copyright (C) 1991,92,96,97,2000,02 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <string.h> +#include <sys/utsname.h> +#include <unistd.h> + +/* This file is created by the configuration process, and defines UNAME_*. */ +#include <config-name.h> + +/* Put information about the system in NAME. */ +int +__uname (name) + struct utsname *name; +{ + int save; + + if (name == NULL) + { + __set_errno (EINVAL); + return -1; + } + + save = errno; + if (__gethostname (name->nodename, sizeof (name->nodename)) < 0) + { + if (errno == ENOSYS) + { + /* Hostname is meaningless for this machine. */ + name->nodename[0] = '\0'; + __set_errno (save); + } +#ifdef ENAMETOOLONG + else if (errno == ENAMETOOLONG) + /* The name was truncated. */ + __set_errno (save); +#endif + else + return -1; + } + strncpy (name->sysname, UNAME_SYSNAME, sizeof (name->sysname)); + strncpy (name->release, UNAME_RELEASE, sizeof (name->release)); + strncpy (name->version, UNAME_VERSION, sizeof (name->version)); + strncpy (name->machine, UNAME_MACHINE, sizeof (name->machine)); + + return 0; +} +weak_alias (__uname, uname) +libc_hidden_def (__uname) +libc_hidden_def (uname) diff --git a/posix/unistd.h b/posix/unistd.h index 5d42169e82..4e1e9dfaa2 100644 --- a/posix/unistd.h +++ b/posix/unistd.h @@ -1,4 +1,4 @@ -/* Copyright (C) 1991-2002, 2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1991-2006, 2007 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -56,7 +56,9 @@ __BEGIN_DECLS #define _POSIX2_LOCALEDEF 200112L /* X/Open version number to which the library conforms. It is selectable. */ -#ifdef __USE_UNIX98 +#ifdef __USE_XOPEN2K +# define _XOPEN_VERSION 600 +#elif defined __USE_UNIX98 # define _XOPEN_VERSION 500 #else # define _XOPEN_VERSION 4 @@ -260,8 +262,20 @@ extern int access (__const char *__name, int __type) __THROW __nonnull ((1)); (as normal file operations use). */ extern int euidaccess (__const char *__name, int __type) __THROW __nonnull ((1)); + +/* An alias for `euidaccess', used by some other systems. */ +extern int eaccess (__const char *__name, int __type) + __THROW __nonnull ((1)); #endif +#ifdef __USE_ATFILE +/* Test for access to FILE relative to the directory FD is open on. + If AT_EACCESS is set in FLAG, then use effective IDs like `eaccess', + otherwise use real IDs like `access'. */ +extern int faccessat (int __fd, __const char *__file, int __type, int __flag) + __THROW __nonnull ((2)) __wur; +#endif /* Use GNU. */ + /* Values for the WHENCE argument to lseek. */ #ifndef _STDIO_H /* <stdio.h> has the same definitions. */ @@ -295,7 +309,8 @@ extern __off64_t __REDIRECT_NTH (lseek, # endif #endif #ifdef __USE_LARGEFILE64 -extern __off64_t lseek64 (int __fd, __off64_t __offset, int __whence) __THROW; +extern __off64_t lseek64 (int __fd, __off64_t __offset, int __whence) + __THROW; #endif /* Close the file descriptor FD. @@ -309,13 +324,13 @@ extern int close (int __fd); This function is a cancellation point and therefore not marked with __THROW. */ -extern ssize_t read (int __fd, void *__buf, size_t __nbytes); +extern ssize_t read (int __fd, void *__buf, size_t __nbytes) __wur; /* Write N bytes of BUF to FD. Return the number written, or -1. This function is a cancellation point and therefore not marked with __THROW. */ -extern ssize_t write (int __fd, __const void *__buf, size_t __n); +extern ssize_t write (int __fd, __const void *__buf, size_t __n) __wur; #ifdef __USE_UNIX98 # ifndef __USE_FILE_OFFSET64 @@ -326,7 +341,7 @@ extern ssize_t write (int __fd, __const void *__buf, size_t __n); This function is a cancellation point and therefore not marked with __THROW. */ extern ssize_t pread (int __fd, void *__buf, size_t __nbytes, - __off_t __offset); + __off_t __offset) __wur; /* Write N bytes of BUF to FD at the given position OFFSET without changing the file pointer. Return the number written, or -1. @@ -334,15 +349,15 @@ extern ssize_t pread (int __fd, void *__buf, size_t __nbytes, This function is a cancellation point and therefore not marked with __THROW. */ extern ssize_t pwrite (int __fd, __const void *__buf, size_t __n, - __off_t __offset); + __off_t __offset) __wur; # else # ifdef __REDIRECT extern ssize_t __REDIRECT (pread, (int __fd, void *__buf, size_t __nbytes, __off64_t __offset), - pread64); + pread64) __wur; extern ssize_t __REDIRECT (pwrite, (int __fd, __const void *__buf, size_t __nbytes, __off64_t __offset), - pwrite64); + pwrite64) __wur; # else # define pread pread64 # define pwrite pwrite64 @@ -354,11 +369,11 @@ extern ssize_t __REDIRECT (pwrite, (int __fd, __const void *__buf, changing the file pointer. Return the number read, -1 for errors or 0 for EOF. */ extern ssize_t pread64 (int __fd, void *__buf, size_t __nbytes, - __off64_t __offset); + __off64_t __offset) __wur; /* Write N bytes of BUF to FD at the given position OFFSET without changing the file pointer. Return the number written, or -1. */ extern ssize_t pwrite64 (int __fd, __const void *__buf, size_t __n, - __off64_t __offset); + __off64_t __offset) __wur; # endif #endif @@ -366,7 +381,7 @@ extern ssize_t pwrite64 (int __fd, __const void *__buf, size_t __n, If successful, two file descriptors are stored in PIPEDES; bytes written on PIPEDES[1] can be read from PIPEDES[0]. Returns 0 if successful, -1 if not. */ -extern int pipe (int __pipedes[2]) __THROW; +extern int pipe (int __pipedes[2]) __THROW __wur; /* Schedule an alarm. In SECONDS seconds, the process will get a SIGALRM. If SECONDS is zero, any currently scheduled alarm will be cancelled. @@ -416,26 +431,34 @@ extern int pause (void); /* Change the owner and group of FILE. */ extern int chown (__const char *__file, __uid_t __owner, __gid_t __group) - __THROW __nonnull ((1)); + __THROW __nonnull ((1)) __wur; #if defined __USE_BSD || defined __USE_XOPEN_EXTENDED /* Change the owner and group of the file that FD is open on. */ -extern int fchown (int __fd, __uid_t __owner, __gid_t __group) __THROW; +extern int fchown (int __fd, __uid_t __owner, __gid_t __group) __THROW __wur; /* Change owner and group of FILE, if it is a symbolic link the ownership of the symbolic link is changed. */ extern int lchown (__const char *__file, __uid_t __owner, __gid_t __group) - __THROW __nonnull ((1)); + __THROW __nonnull ((1)) __wur; #endif /* Use BSD || X/Open Unix. */ +#ifdef __USE_ATFILE +/* Change the owner and group of FILE relative to the directory FD is open + on. */ +extern int fchownat (int __fd, __const char *__file, __uid_t __owner, + __gid_t __group, int __flag) + __THROW __nonnull ((2)) __wur; +#endif /* Use GNU. */ + /* Change the process's working directory to PATH. */ -extern int chdir (__const char *__path) __THROW __nonnull ((1)); +extern int chdir (__const char *__path) __THROW __nonnull ((1)) __wur; #if defined __USE_BSD || defined __USE_XOPEN_EXTENDED /* Change the process's working directory to the one FD is open on. */ -extern int fchdir (int __fd) __THROW; +extern int fchdir (int __fd) __THROW __wur; #endif /* Get the pathname of the current working directory, @@ -445,7 +468,7 @@ extern int fchdir (int __fd) __THROW; an array is allocated with `malloc'; the array is SIZE bytes long, unless SIZE == 0, in which case it is as big as necessary. */ -extern char *getcwd (char *__buf, size_t __size) __THROW; +extern char *getcwd (char *__buf, size_t __size) __THROW __wur; #ifdef __USE_GNU /* Return a malloc'd string containing the current directory name. @@ -458,12 +481,13 @@ extern char *get_current_dir_name (void) __THROW; /* Put the absolute pathname of the current working directory in BUF. If successful, return BUF. If not, put an error message in BUF and return NULL. BUF should be at least PATH_MAX bytes long. */ -extern char *getwd (char *__buf) __THROW __nonnull ((1)); +extern char *getwd (char *__buf) + __THROW __nonnull ((1)) __attribute_deprecated__ __wur; #endif /* Duplicate FD, returning a new file descriptor on the same file. */ -extern int dup (int __fd) __THROW; +extern int dup (int __fd) __THROW __wur; /* Duplicate FD to FD2, closing FD2 and making it open on the same file. */ extern int dup2 (int __fd, int __fd2) __THROW; @@ -516,7 +540,7 @@ extern int execlp (__const char *__file, __const char *__arg, ...) #if defined __USE_MISC || defined __USE_XOPEN /* Add INC to priority of the current process. */ -extern int nice (int __inc) __THROW; +extern int nice (int __inc) __THROW __wur; #endif @@ -629,7 +653,7 @@ extern __gid_t getegid (void) __THROW; /* If SIZE is zero, return the number of supplementary groups the calling process is in. Otherwise, fill in the group IDs of its supplementary groups in LIST and return the number written. */ -extern int getgroups (int __size, __gid_t __list[]) __THROW; +extern int getgroups (int __size, __gid_t __list[]) __THROW __wur; #ifdef __USE_GNU /* Return nonzero iff the calling process is in group GID. */ @@ -671,21 +695,25 @@ extern int setegid (__gid_t __gid) __THROW; #endif /* Use BSD. */ #ifdef __USE_GNU -/* Fetch the effective user ID, real user ID, and saved-set user ID, +/* Fetch the real user ID, effective user ID, and saved-set user ID, of the calling process. */ -extern int getresuid (__uid_t *__euid, __uid_t *__ruid, __uid_t *__suid); +extern int getresuid (__uid_t *__ruid, __uid_t *__euid, __uid_t *__suid) + __THROW; -/* Fetch the effective group ID, real group ID, and saved-set group ID, +/* Fetch the real group ID, effective group ID, and saved-set group ID, of the calling process. */ -extern int getresgid (__gid_t *__egid, __gid_t *__rgid, __gid_t *__sgid); +extern int getresgid (__gid_t *__rgid, __gid_t *__egid, __gid_t *__sgid) + __THROW; -/* Set the effective user ID, real user ID, and saved-set user ID, - of the calling process to EUID, RUID, and SUID, respectively. */ -extern int setresuid (__uid_t __euid, __uid_t __ruid, __uid_t __suid); +/* Set the real user ID, effective user ID, and saved-set user ID, + of the calling process to RUID, EUID, and SUID, respectively. */ +extern int setresuid (__uid_t __ruid, __uid_t __euid, __uid_t __suid) + __THROW; -/* Set the effective group ID, real group ID, and saved-set group ID, - of the calling process to EGID, RGID, and SGID, respectively. */ -extern int setresgid (__gid_t __egid, __gid_t __rgid, __gid_t __sgid); +/* Set the real group ID, effective group ID, and saved-set group ID, + of the calling process to RGID, EGID, and SGID, respectively. */ +extern int setresgid (__gid_t __rgid, __gid_t __egid, __gid_t __sgid) + __THROW; #endif @@ -710,7 +738,7 @@ extern char *ttyname (int __fd) __THROW; /* Store at most BUFLEN characters of the pathname of the terminal FD is open on in BUF. Return 0 on success, otherwise an error number. */ extern int ttyname_r (int __fd, char *__buf, size_t __buflen) - __THROW __nonnull ((2)); + __THROW __nonnull ((2)) __wur; /* Return 1 if FD is a valid descriptor associated with a terminal, zero if not. */ @@ -726,23 +754,49 @@ extern int ttyslot (void) __THROW; /* Make a link to FROM named TO. */ extern int link (__const char *__from, __const char *__to) - __THROW __nonnull ((1, 2)); + __THROW __nonnull ((1, 2)) __wur; + +#ifdef __USE_ATFILE +/* Like link but relative paths in TO and FROM are interpreted relative + to FROMFD and TOFD respectively. */ +extern int linkat (int __fromfd, __const char *__from, int __tofd, + __const char *__to, int __flags) + __THROW __nonnull ((2, 4)) __wur; +#endif -#if defined __USE_BSD || defined __USE_XOPEN_EXTENDED +#if defined __USE_BSD || defined __USE_XOPEN_EXTENDED || defined __USE_XOPEN2K /* Make a symbolic link to FROM named TO. */ extern int symlink (__const char *__from, __const char *__to) - __THROW __nonnull ((1, 2)); + __THROW __nonnull ((1, 2)) __wur; /* Read the contents of the symbolic link PATH into no more than LEN bytes of BUF. The contents are not null-terminated. Returns the number of characters read, or -1 for errors. */ -extern int readlink (__const char *__restrict __path, char *__restrict __buf, - size_t __len) __THROW __nonnull ((1, 2)); +extern ssize_t readlink (__const char *__restrict __path, + char *__restrict __buf, size_t __len) + __THROW __nonnull ((1, 2)) __wur; #endif /* Use BSD. */ +#ifdef __USE_ATFILE +/* Like symlink but a relative path in TO is interpreted relative to TOFD. */ +extern int symlinkat (__const char *__from, int __tofd, + __const char *__to) __THROW __nonnull ((1, 3)) __wur; + +/* Like readlink but a relative PATH is interpreted relative to FD. */ +extern ssize_t readlinkat (int __fd, __const char *__restrict __path, + char *__restrict __buf, size_t __len) + __THROW __nonnull ((2, 3)) __wur; +#endif + /* Remove the link NAME. */ extern int unlink (__const char *__name) __THROW __nonnull ((1)); +#ifdef __USE_ATFILE +/* Remove the link NAME relative to FD. */ +extern int unlinkat (int __fd, __const char *__name, int __flag) + __THROW __nonnull ((2)); +#endif + /* Remove the directory PATH. */ extern int rmdir (__const char *__path) __THROW __nonnull ((1)); @@ -759,7 +813,7 @@ extern int tcsetpgrp (int __fd, __pid_t __pgrp_id) __THROW; This function is a possible cancellation points and therefore not marked with __THROW. */ extern char *getlogin (void); -#if defined __USE_REENTRANT || defined __USE_UNIX98 +#if defined __USE_REENTRANT || defined __USE_POSIX199506 /* Return at most NAME_LEN characters of the login name of the user in NAME. If it cannot be determined or some other error occurred, return the error code. Otherwise return 0. @@ -796,20 +850,20 @@ extern int gethostname (char *__name, size_t __len) __THROW __nonnull ((1)); /* Set the name of the current host to NAME, which is LEN bytes long. This call is restricted to the super-user. */ extern int sethostname (__const char *__name, size_t __len) - __THROW __nonnull ((1)); + __THROW __nonnull ((1)) __wur; /* Set the current machine's Internet number to ID. This call is restricted to the super-user. */ -extern int sethostid (long int __id) __THROW; +extern int sethostid (long int __id) __THROW __wur; /* Get and set the NIS (aka YP) domain name, if any. Called just like `gethostname' and `sethostname'. The NIS domain name is usually the empty string when not using NIS. */ extern int getdomainname (char *__name, size_t __len) - __THROW __nonnull ((1)); + __THROW __nonnull ((1)) __wur; extern int setdomainname (__const char *__name, size_t __len) - __THROW __nonnull ((1)); + __THROW __nonnull ((1)) __wur; /* Revoke access permissions to all processes currently communicating @@ -818,7 +872,7 @@ extern int setdomainname (__const char *__name, size_t __len) extern int vhangup (void) __THROW; /* Revoke the access of all descriptors currently open on FILE. */ -extern int revoke (__const char *__file) __THROW __nonnull ((1)); +extern int revoke (__const char *__file) __THROW __nonnull ((1)) __wur; /* Enable statistical profiling, writing samples of the PC into at most @@ -834,7 +888,7 @@ extern int profil (unsigned short int *__sample_buffer, size_t __size, /* Turn accounting on if NAME is an existing file. The system will then write a record for each process as it terminates, to this file. If NAME is NULL, turn accounting off. This call is restricted to the super-user. */ -extern int acct (__const char *__name) __THROW __nonnull ((1)); +extern int acct (__const char *__name) __THROW; /* Successive calls return the shells listed in `/etc/shells'. */ @@ -846,14 +900,14 @@ extern void setusershell (void) __THROW; /* Rewind and re-read the file. */ /* Put the program in the background, and dissociate from the controlling terminal. If NOCHDIR is zero, do `chdir ("/")'. If NOCLOSE is zero, redirects stdin, stdout, and stderr to /dev/null. */ -extern int daemon (int __nochdir, int __noclose) __THROW; +extern int daemon (int __nochdir, int __noclose) __THROW __wur; #endif /* Use BSD || X/Open. */ #if defined __USE_BSD || (defined __USE_XOPEN && !defined __USE_XOPEN2K) /* Make PATH be the root directory (the starting point for absolute paths). This call is restricted to the super-user. */ -extern int chroot (__const char *__path) __THROW __nonnull ((1)); +extern int chroot (__const char *__path) __THROW __nonnull ((1)) __wur; /* Prompt with PROMPT and read a string from the terminal without echoing. Uses /dev/tty if possible; otherwise stderr and stdin. */ @@ -884,52 +938,56 @@ extern void sync (void) __THROW; extern int getpagesize (void) __THROW __attribute__ ((__const__)); +/* Return the maximum number of file descriptors + the current process could possibly have. */ +extern int getdtablesize (void) __THROW; + + /* Truncate FILE to LENGTH bytes. */ # ifndef __USE_FILE_OFFSET64 extern int truncate (__const char *__file, __off_t __length) - __THROW __nonnull ((1)); + __THROW __nonnull ((1)) __wur; # else # ifdef __REDIRECT_NTH extern int __REDIRECT_NTH (truncate, (__const char *__file, __off64_t __length), - truncate64) __nonnull ((1)); + truncate64) __nonnull ((1)) __wur; # else # define truncate truncate64 # endif # endif # ifdef __USE_LARGEFILE64 extern int truncate64 (__const char *__file, __off64_t __length) - __THROW __nonnull ((1)); + __THROW __nonnull ((1)) __wur; # endif +#endif /* Use BSD || X/Open Unix. */ + +#if defined __USE_BSD || defined __USE_XOPEN_EXTENDED || defined __USE_XOPEN2K + /* Truncate the file FD is open on to LENGTH bytes. */ # ifndef __USE_FILE_OFFSET64 -extern int ftruncate (int __fd, __off_t __length) __THROW; +extern int ftruncate (int __fd, __off_t __length) __THROW __wur; # else # ifdef __REDIRECT_NTH extern int __REDIRECT_NTH (ftruncate, (int __fd, __off64_t __length), - ftruncate64); + ftruncate64) __wur; # else # define ftruncate ftruncate64 # endif # endif # ifdef __USE_LARGEFILE64 -extern int ftruncate64 (int __fd, __off64_t __length) __THROW; +extern int ftruncate64 (int __fd, __off64_t __length) __THROW __wur; # endif - -/* Return the maximum number of file descriptors - the current process could possibly have. */ -extern int getdtablesize (void) __THROW; - -#endif /* Use BSD || X/Open Unix. */ +#endif /* Use BSD || X/Open Unix || POSIX 2003. */ #if defined __USE_MISC || defined __USE_XOPEN_EXTENDED /* Set the end of accessible data space (aka "the break") to ADDR. Returns zero on success and -1 for errors (with errno set). */ -extern int brk (void *__addr) __THROW; +extern int brk (void *__addr) __THROW __wur; /* Increase or decrease the end of accessible data space by DELTA bytes. If successful, returns the address the previous end of data space @@ -973,17 +1031,17 @@ extern long int syscall (long int __sysno, ...) __THROW; # define F_TEST 3 /* Test a region for other processes locks. */ # ifndef __USE_FILE_OFFSET64 -extern int lockf (int __fd, int __cmd, __off_t __len); +extern int lockf (int __fd, int __cmd, __off_t __len) __wur; # else # ifdef __REDIRECT extern int __REDIRECT (lockf, (int __fd, int __cmd, __off64_t __len), - lockf64); + lockf64) __wur; # else # define lockf lockf64 # endif # endif # ifdef __USE_LARGEFILE64 -extern int lockf64 (int __fd, int __cmd, __off64_t __len); +extern int lockf64 (int __fd, int __cmd, __off64_t __len) __wur; # endif #endif /* Use misc and F_LOCK not already defined. */ @@ -1004,7 +1062,7 @@ extern int lockf64 (int __fd, int __cmd, __off64_t __len); #if defined __USE_POSIX199309 || defined __USE_UNIX98 /* Synchronize at least the data part of a file with the underlying media. */ -extern int fdatasync (int __fildes) __THROW; +extern int fdatasync (int __fildes); #endif /* Use POSIX199309 */ @@ -1033,7 +1091,13 @@ extern void swab (__const void *__restrict __from, void *__restrict __to, It is also found in <stdio.h>. */ #ifdef __USE_XOPEN /* Return the name of the controlling terminal. */ -extern char *ctermid (char *__s) __THROW __nonnull ((1)); +extern char *ctermid (char *__s) __THROW; +#endif + + +/* Define some macros helping to catch buffer overflows. */ +#if __USE_FORTIFY_LEVEL > 0 && !defined __cplusplus +# include <bits/unistd.h> #endif __END_DECLS diff --git a/posix/vfork.c b/posix/vfork.c new file mode 100644 index 0000000000..d15841d712 --- /dev/null +++ b/posix/vfork.c @@ -0,0 +1,31 @@ +/* Copyright (C) 1992, 1995, 1997, 2000, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <unistd.h> + +/* If we don't have vfork, fork is close enough. */ + +__pid_t +__vfork (void) +{ + return __fork (); +} +libc_hidden_def (__vfork) + +weak_alias (__vfork, vfork) diff --git a/posix/wait.c b/posix/wait.c new file mode 100644 index 0000000000..b1c512ed39 --- /dev/null +++ b/posix/wait.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sys/wait.h> +#include <errno.h> + +/* Wait for a child to die. When one does, put its status in *STAT_LOC + and return its process ID. For errors, return (pid_t) -1. */ +__pid_t +__wait (__WAIT_STATUS_DEFN stat_loc) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (wait) + +weak_alias (__wait, wait) +#include <stub-tag.h> diff --git a/posix/wait3.c b/posix/wait3.c new file mode 100644 index 0000000000..479d99e3da --- /dev/null +++ b/posix/wait3.c @@ -0,0 +1,43 @@ +/* Copyright (C) 1991, 1993, 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sys/wait.h> +#include <sys/types.h> + +/* Wait for a child to exit. When one does, put its status in *STAT_LOC and + return its process ID. For errors return (pid_t) -1. If USAGE is not nil, + store information about the child's resource usage (as a `struct rusage') + there. If the WUNTRACED bit is set in OPTIONS, return status for stopped + children; otherwise don't. */ +pid_t +__wait3 (__WAIT_STATUS_DEFN stat_loc, int options, struct rusage *usage) +{ + if ((options & ~(WNOHANG|WUNTRACED)) != 0) + { + __set_errno (EINVAL); + return (pid_t) -1; + } + + __set_errno (ENOSYS); + return (pid_t) -1; +} +stub_warning (wait3) + +weak_alias (__wait3, wait3) +#include <stub-tag.h> diff --git a/posix/wait4.c b/posix/wait4.c new file mode 100644 index 0000000000..b59bf87ffc --- /dev/null +++ b/posix/wait4.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1991, 1992, 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sys/types.h> +#include <sys/wait.h> +#include <errno.h> + +pid_t +__wait4 (__pid_t pid, __WAIT_STATUS stat_loc, int options, + struct rusage *usage) +{ + __set_errno (ENOSYS); + return (pid_t) -1; +} +stub_warning (wait4) + +weak_alias (__wait4, wait4) +#include <stub-tag.h> diff --git a/posix/waitid.c b/posix/waitid.c new file mode 100644 index 0000000000..a9de1a19a5 --- /dev/null +++ b/posix/waitid.c @@ -0,0 +1,35 @@ +/* Stub version of waitid. + Copyright (C) 1997, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sys/types.h> +#include <sys/wait.h> + +int +__waitid (idtype, id, infop, options) + idtype_t idtype; + id_t id; + siginfo_t *infop; + int options; +{ + __set_errno (ENOSYS); + return -1; +} +weak_alias (__waitid, waitid) diff --git a/posix/waitpid.c b/posix/waitpid.c new file mode 100644 index 0000000000..9c7736e669 --- /dev/null +++ b/posix/waitpid.c @@ -0,0 +1,53 @@ +/* Copyright (C) 1991,95,96,97,2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sys/wait.h> +#include <sys/types.h> + + +/* Wait for a child matching PID to die. + If PID is greater than 0, match any process whose process ID is PID. + If PID is (pid_t) -1, match any process. + If PID is (pid_t) 0, match any process with the + same process group as the current process. + If PID is less than -1, match any process whose + process group is the absolute value of PID. + If the WNOHANG bit is set in OPTIONS, and that child + is not already dead, return (pid_t) 0. If successful, + return PID and store the dead child's status in STAT_LOC. + Return (pid_t) -1 for errors. If the WUNTRACED bit is set in OPTIONS, + return status for stopped children; otherwise don't. */ +pid_t +__libc_waitpid (pid_t pid, int *stat_loc, int options) +{ + if ((options & ~(WNOHANG|WUNTRACED)) != 0) + { + __set_errno (EINVAL); + return (pid_t) -1; + } + + __set_errno (ENOSYS); + return (pid_t) -1; +} +weak_alias (__libc_waitpid, __waitpid) +libc_hidden_weak (__waitpid) +weak_alias (__libc_waitpid, waitpid) + +stub_warning (waitpid) +#include <stub-tag.h> diff --git a/posix/wordexp.c b/posix/wordexp.c new file mode 100644 index 0000000000..adece95ef8 --- /dev/null +++ b/posix/wordexp.c @@ -0,0 +1,2452 @@ +/* POSIX.2 wordexp implementation. + Copyright (C) 1997-2002, 2003, 2005, 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Tim Waugh <tim@cyberelk.demon.co.uk>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <alloca.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <fnmatch.h> +#include <glob.h> +#include <libintl.h> +#include <paths.h> +#include <pwd.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#ifdef USE_IN_LIBIO +# include <wchar.h> +#endif +#include <wordexp.h> + +#include <bits/libc-lock.h> +#include <stdio-common/_itoa.h> + +/* Undefine the following line for the production version. */ +/* #define NDEBUG 1 */ +#include <assert.h> + +/* Get some device information. */ +#include <device-nrs.h> + +/* + * This is a recursive-descent-style word expansion routine. + */ + +/* These variables are defined and initialized in the startup code. */ +extern int __libc_argc attribute_hidden; +extern char **__libc_argv attribute_hidden; + +/* Some forward declarations */ +static int parse_dollars (char **word, size_t *word_length, size_t *max_length, + const char *words, size_t *offset, int flags, + wordexp_t *pwordexp, const char *ifs, + const char *ifs_white, int quoted) + internal_function; +static int parse_backtick (char **word, size_t *word_length, + size_t *max_length, const char *words, + size_t *offset, int flags, wordexp_t *pwordexp, + const char *ifs, const char *ifs_white) + internal_function; +static int parse_dquote (char **word, size_t *word_length, size_t *max_length, + const char *words, size_t *offset, int flags, + wordexp_t *pwordexp, const char *ifs, + const char *ifs_white) + internal_function; +static int eval_expr (char *expr, long int *result) internal_function; + +/* The w_*() functions manipulate word lists. */ + +#define W_CHUNK (100) + +/* Result of w_newword will be ignored if it's the last word. */ +static inline char * +w_newword (size_t *actlen, size_t *maxlen) +{ + *actlen = *maxlen = 0; + return NULL; +} + +static char * +w_addchar (char *buffer, size_t *actlen, size_t *maxlen, char ch) + /* (lengths exclude trailing zero) */ +{ + /* Add a character to the buffer, allocating room for it if needed. */ + + if (*actlen == *maxlen) + { + char *old_buffer = buffer; + assert (buffer == NULL || *maxlen != 0); + *maxlen += W_CHUNK; + buffer = (char *) realloc (buffer, 1 + *maxlen); + + if (buffer == NULL) + free (old_buffer); + } + + if (buffer != NULL) + { + buffer[*actlen] = ch; + buffer[++(*actlen)] = '\0'; + } + + return buffer; +} + +static char * +internal_function +w_addmem (char *buffer, size_t *actlen, size_t *maxlen, const char *str, + size_t len) +{ + /* Add a string to the buffer, allocating room for it if needed. + */ + if (*actlen + len > *maxlen) + { + char *old_buffer = buffer; + assert (buffer == NULL || *maxlen != 0); + *maxlen += MAX (2 * len, W_CHUNK); + buffer = realloc (old_buffer, 1 + *maxlen); + + if (buffer == NULL) + free (old_buffer); + } + + if (buffer != NULL) + { + *((char *) __mempcpy (&buffer[*actlen], str, len)) = '\0'; + *actlen += len; + } + + return buffer; +} + +static char * +internal_function +w_addstr (char *buffer, size_t *actlen, size_t *maxlen, const char *str) + /* (lengths exclude trailing zero) */ +{ + /* Add a string to the buffer, allocating room for it if needed. + */ + size_t len; + + assert (str != NULL); /* w_addstr only called from this file */ + len = strlen (str); + + return w_addmem (buffer, actlen, maxlen, str, len); +} + +static int +internal_function +w_addword (wordexp_t *pwordexp, char *word) +{ + /* Add a word to the wordlist */ + size_t num_p; + char **new_wordv; + bool allocated = false; + + /* Internally, NULL acts like "". Convert NULLs to "" before + * the caller sees them. + */ + if (word == NULL) + { + word = __strdup (""); + if (word == NULL) + goto no_space; + allocated = true; + } + + num_p = 2 + pwordexp->we_wordc + pwordexp->we_offs; + new_wordv = realloc (pwordexp->we_wordv, sizeof (char *) * num_p); + if (new_wordv != NULL) + { + pwordexp->we_wordv = new_wordv; + pwordexp->we_wordv[pwordexp->we_offs + pwordexp->we_wordc++] = word; + pwordexp->we_wordv[pwordexp->we_offs + pwordexp->we_wordc] = NULL; + return 0; + } + + if (allocated) + free (word); + +no_space: + return WRDE_NOSPACE; +} + +/* The parse_*() functions should leave *offset being the offset in 'words' + * to the last character processed. + */ + +static int +internal_function +parse_backslash (char **word, size_t *word_length, size_t *max_length, + const char *words, size_t *offset) +{ + /* We are poised _at_ a backslash, not in quotes */ + + switch (words[1 + *offset]) + { + case 0: + /* Backslash is last character of input words */ + return WRDE_SYNTAX; + + case '\n': + ++(*offset); + break; + + default: + *word = w_addchar (*word, word_length, max_length, words[1 + *offset]); + if (*word == NULL) + return WRDE_NOSPACE; + + ++(*offset); + break; + } + + return 0; +} + +static int +internal_function +parse_qtd_backslash (char **word, size_t *word_length, size_t *max_length, + const char *words, size_t *offset) +{ + /* We are poised _at_ a backslash, inside quotes */ + + switch (words[1 + *offset]) + { + case 0: + /* Backslash is last character of input words */ + return WRDE_SYNTAX; + + case '\n': + ++(*offset); + break; + + case '$': + case '`': + case '"': + case '\\': + *word = w_addchar (*word, word_length, max_length, words[1 + *offset]); + if (*word == NULL) + return WRDE_NOSPACE; + + ++(*offset); + break; + + default: + *word = w_addchar (*word, word_length, max_length, words[*offset]); + if (*word != NULL) + *word = w_addchar (*word, word_length, max_length, words[1 + *offset]); + + if (*word == NULL) + return WRDE_NOSPACE; + + ++(*offset); + break; + } + + return 0; +} + +static int +internal_function +parse_tilde (char **word, size_t *word_length, size_t *max_length, + const char *words, size_t *offset, size_t wordc) +{ + /* We are poised _at_ a tilde */ + size_t i; + + if (*word_length != 0) + { + if (!((*word)[*word_length - 1] == '=' && wordc == 0)) + { + if (!((*word)[*word_length - 1] == ':' + && strchr (*word, '=') && wordc == 0)) + { + *word = w_addchar (*word, word_length, max_length, '~'); + return *word ? 0 : WRDE_NOSPACE; + } + } + } + + for (i = 1 + *offset; words[i]; i++) + { + if (words[i] == ':' || words[i] == '/' || words[i] == ' ' || + words[i] == '\t' || words[i] == 0 ) + break; + + if (words[i] == '\\') + { + *word = w_addchar (*word, word_length, max_length, '~'); + return *word ? 0 : WRDE_NOSPACE; + } + } + + if (i == 1 + *offset) + { + /* Tilde appears on its own */ + uid_t uid; + struct passwd pwd, *tpwd; + int buflen = 1000; + char* home; + char* buffer; + int result; + + /* POSIX.2 says ~ expands to $HOME and if HOME is unset the + results are unspecified. We do a lookup on the uid if + HOME is unset. */ + + home = getenv ("HOME"); + if (home != NULL) + { + *word = w_addstr (*word, word_length, max_length, home); + if (*word == NULL) + return WRDE_NOSPACE; + } + else + { + uid = __getuid (); + buffer = __alloca (buflen); + + while ((result = __getpwuid_r (uid, &pwd, buffer, buflen, &tpwd)) != 0 + && errno == ERANGE) + buffer = extend_alloca (buffer, buflen, buflen + 1000); + + if (result == 0 && tpwd != NULL && pwd.pw_dir != NULL) + { + *word = w_addstr (*word, word_length, max_length, pwd.pw_dir); + if (*word == NULL) + return WRDE_NOSPACE; + } + else + { + *word = w_addchar (*word, word_length, max_length, '~'); + if (*word == NULL) + return WRDE_NOSPACE; + } + } + } + else + { + /* Look up user name in database to get home directory */ + char *user = strndupa (&words[1 + *offset], i - (1 + *offset)); + struct passwd pwd, *tpwd; + int buflen = 1000; + char* buffer = __alloca (buflen); + int result; + + while ((result = __getpwnam_r (user, &pwd, buffer, buflen, &tpwd)) != 0 + && errno == ERANGE) + buffer = extend_alloca (buffer, buflen, buflen + 1000); + + if (result == 0 && tpwd != NULL && pwd.pw_dir) + *word = w_addstr (*word, word_length, max_length, pwd.pw_dir); + else + { + /* (invalid login name) */ + *word = w_addchar (*word, word_length, max_length, '~'); + if (*word != NULL) + *word = w_addstr (*word, word_length, max_length, user); + } + + *offset = i - 1; + } + return *word ? 0 : WRDE_NOSPACE; +} + + +static int +internal_function +do_parse_glob (const char *glob_word, char **word, size_t *word_length, + size_t *max_length, wordexp_t *pwordexp, const char *ifs, + const char *ifs_white) +{ + int error; + unsigned int match; + glob_t globbuf; + + error = glob (glob_word, GLOB_NOCHECK, NULL, &globbuf); + + if (error != 0) + { + /* We can only run into memory problems. */ + assert (error == GLOB_NOSPACE); + return WRDE_NOSPACE; + } + + if (ifs && !*ifs) + { + /* No field splitting allowed. */ + assert (globbuf.gl_pathv[0] != NULL); + *word = w_addstr (*word, word_length, max_length, globbuf.gl_pathv[0]); + for (match = 1; match < globbuf.gl_pathc && *word != NULL; ++match) + { + *word = w_addchar (*word, word_length, max_length, ' '); + if (*word != NULL) + *word = w_addstr (*word, word_length, max_length, + globbuf.gl_pathv[match]); + } + + globfree (&globbuf); + return *word ? 0 : WRDE_NOSPACE; + } + + assert (ifs == NULL || *ifs != '\0'); + if (*word != NULL) + { + free (*word); + *word = w_newword (word_length, max_length); + } + + for (match = 0; match < globbuf.gl_pathc; ++match) + { + char *matching_word = __strdup (globbuf.gl_pathv[match]); + if (matching_word == NULL || w_addword (pwordexp, matching_word)) + { + globfree (&globbuf); + return WRDE_NOSPACE; + } + } + + globfree (&globbuf); + return 0; +} + +static int +internal_function +parse_glob (char **word, size_t *word_length, size_t *max_length, + const char *words, size_t *offset, int flags, + wordexp_t *pwordexp, const char *ifs, const char *ifs_white) +{ + /* We are poised just after a '*', a '[' or a '?'. */ + int error = WRDE_NOSPACE; + int quoted = 0; /* 1 if singly-quoted, 2 if doubly */ + size_t i; + wordexp_t glob_list; /* List of words to glob */ + + glob_list.we_wordc = 0; + glob_list.we_wordv = NULL; + glob_list.we_offs = 0; + for (; words[*offset] != '\0'; ++*offset) + { + if (strchr (ifs, words[*offset]) != NULL) + /* Reached IFS */ + break; + + /* Sort out quoting */ + if (words[*offset] == '\'') + { + if (quoted == 0) + { + quoted = 1; + continue; + } + else if (quoted == 1) + { + quoted = 0; + continue; + } + } + else if (words[*offset] == '"') + { + if (quoted == 0) + { + quoted = 2; + continue; + } + else if (quoted == 2) + { + quoted = 0; + continue; + } + } + + /* Sort out other special characters */ + if (quoted != 1 && words[*offset] == '$') + { + error = parse_dollars (word, word_length, max_length, words, + offset, flags, &glob_list, ifs, ifs_white, + quoted == 2); + if (error) + goto tidy_up; + + continue; + } + else if (words[*offset] == '\\') + { + if (quoted) + error = parse_qtd_backslash (word, word_length, max_length, + words, offset); + else + error = parse_backslash (word, word_length, max_length, + words, offset); + + if (error) + goto tidy_up; + + continue; + } + + *word = w_addchar (*word, word_length, max_length, words[*offset]); + if (*word == NULL) + goto tidy_up; + } + + /* Don't forget to re-parse the character we stopped at. */ + --*offset; + + /* Glob the words */ + error = w_addword (&glob_list, *word); + *word = w_newword (word_length, max_length); + for (i = 0; error == 0 && i < glob_list.we_wordc; i++) + error = do_parse_glob (glob_list.we_wordv[i], word, word_length, + max_length, pwordexp, ifs, ifs_white); + + /* Now tidy up */ +tidy_up: + wordfree (&glob_list); + return error; +} + +static int +internal_function +parse_squote (char **word, size_t *word_length, size_t *max_length, + const char *words, size_t *offset) +{ + /* We are poised just after a single quote */ + for (; words[*offset]; ++(*offset)) + { + if (words[*offset] != '\'') + { + *word = w_addchar (*word, word_length, max_length, words[*offset]); + if (*word == NULL) + return WRDE_NOSPACE; + } + else return 0; + } + + /* Unterminated string */ + return WRDE_SYNTAX; +} + +/* Functions to evaluate an arithmetic expression */ +static int +internal_function +eval_expr_val (char **expr, long int *result) +{ + char *digit; + + /* Skip white space */ + for (digit = *expr; digit && *digit && isspace (*digit); ++digit); + + if (*digit == '(') + { + /* Scan for closing paren */ + for (++digit; **expr && **expr != ')'; ++(*expr)); + + /* Is there one? */ + if (!**expr) + return WRDE_SYNTAX; + + *(*expr)++ = 0; + + if (eval_expr (digit, result)) + return WRDE_SYNTAX; + + return 0; + } + + /* POSIX requires that decimal, octal, and hexadecimal constants are + recognized. Therefore we pass 0 as the third parameter to strtol. */ + *result = strtol (digit, expr, 0); + if (digit == *expr) + return WRDE_SYNTAX; + + return 0; +} + +static int +internal_function +eval_expr_multdiv (char **expr, long int *result) +{ + long int arg; + + /* Read a Value */ + if (eval_expr_val (expr, result) != 0) + return WRDE_SYNTAX; + + while (**expr) + { + /* Skip white space */ + for (; *expr && **expr && isspace (**expr); ++(*expr)); + + if (**expr == '*') + { + ++(*expr); + if (eval_expr_val (expr, &arg) != 0) + return WRDE_SYNTAX; + + *result *= arg; + } + else if (**expr == '/') + { + ++(*expr); + if (eval_expr_val (expr, &arg) != 0) + return WRDE_SYNTAX; + + *result /= arg; + } + else break; + } + + return 0; +} + +static int +internal_function +eval_expr (char *expr, long int *result) +{ + long int arg; + + /* Read a Multdiv */ + if (eval_expr_multdiv (&expr, result) != 0) + return WRDE_SYNTAX; + + while (*expr) + { + /* Skip white space */ + for (; expr && *expr && isspace (*expr); ++expr); + + if (*expr == '+') + { + ++expr; + if (eval_expr_multdiv (&expr, &arg) != 0) + return WRDE_SYNTAX; + + *result += arg; + } + else if (*expr == '-') + { + ++expr; + if (eval_expr_multdiv (&expr, &arg) != 0) + return WRDE_SYNTAX; + + *result -= arg; + } + else break; + } + + return 0; +} + +static int +internal_function +parse_arith (char **word, size_t *word_length, size_t *max_length, + const char *words, size_t *offset, int flags, int bracket) +{ + /* We are poised just after "$((" or "$[" */ + int error; + int paren_depth = 1; + size_t expr_length; + size_t expr_maxlen; + char *expr; + + expr = w_newword (&expr_length, &expr_maxlen); + for (; words[*offset]; ++(*offset)) + { + switch (words[*offset]) + { + case '$': + error = parse_dollars (&expr, &expr_length, &expr_maxlen, + words, offset, flags, NULL, NULL, NULL, 1); + /* The ``1'' here is to tell parse_dollars not to + * split the fields. + */ + if (error) + { + free (expr); + return error; + } + break; + + case '`': + (*offset)++; + error = parse_backtick (&expr, &expr_length, &expr_maxlen, + words, offset, flags, NULL, NULL, NULL); + /* The first NULL here is to tell parse_backtick not to + * split the fields. + */ + if (error) + { + free (expr); + return error; + } + break; + + case '\\': + error = parse_qtd_backslash (&expr, &expr_length, &expr_maxlen, + words, offset); + if (error) + { + free (expr); + return error; + } + /* I think that a backslash within an + * arithmetic expansion is bound to + * cause an error sooner or later anyway though. + */ + break; + + case ')': + if (--paren_depth == 0) + { + char result[21]; /* 21 = ceil(log10(2^64)) + 1 */ + long int numresult = 0; + long long int convertme; + + if (bracket || words[1 + *offset] != ')') + { + free (expr); + return WRDE_SYNTAX; + } + + ++(*offset); + + /* Go - evaluate. */ + if (*expr && eval_expr (expr, &numresult) != 0) + { + free (expr); + return WRDE_SYNTAX; + } + + if (numresult < 0) + { + convertme = -numresult; + *word = w_addchar (*word, word_length, max_length, '-'); + if (!*word) + { + free (expr); + return WRDE_NOSPACE; + } + } + else + convertme = numresult; + + result[20] = '\0'; + *word = w_addstr (*word, word_length, max_length, + _itoa (convertme, &result[20], 10, 0)); + free (expr); + return *word ? 0 : WRDE_NOSPACE; + } + expr = w_addchar (expr, &expr_length, &expr_maxlen, words[*offset]); + if (expr == NULL) + return WRDE_NOSPACE; + + break; + + case ']': + if (bracket && paren_depth == 1) + { + char result[21]; /* 21 = ceil(log10(2^64)) + 1 */ + long int numresult = 0; + + /* Go - evaluate. */ + if (*expr && eval_expr (expr, &numresult) != 0) + { + free (expr); + return WRDE_SYNTAX; + } + + result[20] = '\0'; + *word = w_addstr (*word, word_length, max_length, + _itoa_word (numresult, &result[20], 10, 0)); + free (expr); + return *word ? 0 : WRDE_NOSPACE; + } + + free (expr); + return WRDE_SYNTAX; + + case '\n': + case ';': + case '{': + case '}': + free (expr); + return WRDE_BADCHAR; + + case '(': + ++paren_depth; + default: + expr = w_addchar (expr, &expr_length, &expr_maxlen, words[*offset]); + if (expr == NULL) + return WRDE_NOSPACE; + } + } + + /* Premature end */ + free (expr); + return WRDE_SYNTAX; +} + +/* Function called by child process in exec_comm() */ +static inline void +internal_function __attribute__ ((always_inline)) +exec_comm_child (char *comm, int *fildes, int showerr, int noexec) +{ + const char *args[4] = { _PATH_BSHELL, "-c", comm, NULL }; + + /* Execute the command, or just check syntax? */ + if (noexec) + args[1] = "-nc"; + + /* Redirect output. */ + __dup2 (fildes[1], STDOUT_FILENO); + __close (fildes[1]); + + /* Redirect stderr to /dev/null if we have to. */ + if (showerr == 0) + { + struct stat64 st; + int fd; + __close (2); + fd = __open (_PATH_DEVNULL, O_WRONLY); + if (fd >= 0 && fd != 2) + { + __dup2 (fd, STDERR_FILENO); + __close (fd); + } + /* Be paranoid. Check that we actually opened the /dev/null + device. */ + if (__builtin_expect (__fxstat64 (_STAT_VER, STDERR_FILENO, &st), 0) != 0 + || __builtin_expect (S_ISCHR (st.st_mode), 1) == 0 +#if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR + || st.st_rdev != makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR) +#endif + ) + /* It's not the /dev/null device. Stop right here. The + problem is: how do we stop? We use _exit() with an + hopefully unusual exit code. */ + _exit (90); + } + + /* Make sure the subshell doesn't field-split on our behalf. */ + __unsetenv ("IFS"); + + __close (fildes[0]); + __execve (_PATH_BSHELL, (char *const *) args, __environ); + + /* Bad. What now? */ + abort (); +} + +/* Function to execute a command and retrieve the results */ +/* pwordexp contains NULL if field-splitting is forbidden */ +static int +internal_function +exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length, + int flags, wordexp_t *pwordexp, const char *ifs, + const char *ifs_white) +{ + int fildes[2]; +#define bufsize 128 + int buflen; + int i; + int status = 0; + size_t maxnewlines = 0; + char buffer[bufsize]; + pid_t pid; + int noexec = 0; + + /* Don't fork() unless necessary */ + if (!comm || !*comm) + return 0; + + if (__pipe (fildes)) + /* Bad */ + return WRDE_NOSPACE; + + again: + if ((pid = __fork ()) < 0) + { + /* Bad */ + if (fildes[0] != -1) + __close (fildes[0]); + if (fildes[1] != -1) + __close (fildes[1]); + return WRDE_NOSPACE; + } + + if (pid == 0) + exec_comm_child (comm, fildes, noexec ? 0 : flags & WRDE_SHOWERR, noexec); + + /* Parent */ + + /* If we are just testing the syntax, only wait. */ + if (noexec) + return (TEMP_FAILURE_RETRY (__waitpid (pid, &status, 0)) == pid + && status != 0) ? WRDE_SYNTAX : 0; + + __close (fildes[1]); + fildes[1] = -1; + + if (!pwordexp) + /* Quoted - no field splitting */ + { + while (1) + { + if ((buflen = TEMP_FAILURE_RETRY (__read (fildes[0], buffer, + bufsize))) < 1) + { + if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, WNOHANG)) == 0) + continue; + if ((buflen = TEMP_FAILURE_RETRY (__read (fildes[0], buffer, + bufsize))) < 1) + break; + } + + maxnewlines += buflen; + + *word = w_addmem (*word, word_length, max_length, buffer, buflen); + if (*word == NULL) + goto no_space; + } + } + else + /* Not quoted - split fields */ + { + int copying = 0; + /* 'copying' is: + * 0 when searching for first character in a field not IFS white space + * 1 when copying the text of a field + * 2 when searching for possible non-whitespace IFS + * 3 when searching for non-newline after copying field + */ + + while (1) + { + if ((buflen = TEMP_FAILURE_RETRY (__read (fildes[0], buffer, + bufsize))) < 1) + { + if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, WNOHANG)) == 0) + continue; + if ((buflen = TEMP_FAILURE_RETRY (__read (fildes[0], buffer, + bufsize))) < 1) + break; + } + + for (i = 0; i < buflen; ++i) + { + if (strchr (ifs, buffer[i]) != NULL) + { + /* Current character is IFS */ + if (strchr (ifs_white, buffer[i]) == NULL) + { + /* Current character is IFS but not whitespace */ + if (copying == 2) + { + /* current character + * | + * V + * eg: text<space><comma><space>moretext + * + * So, strip whitespace IFS (like at the start) + */ + copying = 0; + continue; + } + + copying = 0; + /* fall through and delimit field.. */ + } + else + { + if (buffer[i] == '\n') + { + /* Current character is (IFS) newline */ + + /* If copying a field, this is the end of it, + but maybe all that's left is trailing newlines. + So start searching for a non-newline. */ + if (copying == 1) + copying = 3; + + continue; + } + else + { + /* Current character is IFS white space, but + not a newline */ + + /* If not either copying a field or searching + for non-newline after a field, ignore it */ + if (copying != 1 && copying != 3) + continue; + + /* End of field (search for non-ws IFS afterwards) */ + copying = 2; + } + } + + /* First IFS white space (non-newline), or IFS non-whitespace. + * Delimit the field. Nulls are converted by w_addword. */ + if (w_addword (pwordexp, *word) == WRDE_NOSPACE) + goto no_space; + + *word = w_newword (word_length, max_length); + + maxnewlines = 0; + /* fall back round the loop.. */ + } + else + { + /* Not IFS character */ + + if (copying == 3) + { + /* Nothing but (IFS) newlines since the last field, + so delimit it here before starting new word */ + if (w_addword (pwordexp, *word) == WRDE_NOSPACE) + goto no_space; + + *word = w_newword (word_length, max_length); + } + + copying = 1; + + if (buffer[i] == '\n') /* happens if newline not in IFS */ + maxnewlines++; + else + maxnewlines = 0; + + *word = w_addchar (*word, word_length, max_length, + buffer[i]); + if (*word == NULL) + goto no_space; + } + } + } + } + + /* Chop off trailing newlines (required by POSIX.2) */ + /* Ensure we don't go back further than the beginning of the + substitution (i.e. remove maxnewlines bytes at most) */ + while (maxnewlines-- != 0 && + *word_length > 0 && (*word)[*word_length - 1] == '\n') + { + (*word)[--*word_length] = '\0'; + + /* If the last word was entirely newlines, turn it into a new word + * which can be ignored if there's nothing following it. */ + if (*word_length == 0) + { + free (*word); + *word = w_newword (word_length, max_length); + break; + } + } + + __close (fildes[0]); + fildes[0] = -1; + + /* Check for syntax error (re-execute but with "-n" flag) */ + if (buflen < 1 && status != 0) + { + noexec = 1; + goto again; + } + + return 0; + +no_space: + __kill (pid, SIGKILL); + TEMP_FAILURE_RETRY (__waitpid (pid, NULL, 0)); + __close (fildes[0]); + return WRDE_NOSPACE; +} + +static int +internal_function +parse_comm (char **word, size_t *word_length, size_t *max_length, + const char *words, size_t *offset, int flags, wordexp_t *pwordexp, + const char *ifs, const char *ifs_white) +{ + /* We are poised just after "$(" */ + int paren_depth = 1; + int error = 0; + int quoted = 0; /* 1 for singly-quoted, 2 for doubly-quoted */ + size_t comm_length; + size_t comm_maxlen; + char *comm = w_newword (&comm_length, &comm_maxlen); + + for (; words[*offset]; ++(*offset)) + { + switch (words[*offset]) + { + case '\'': + if (quoted == 0) + quoted = 1; + else if (quoted == 1) + quoted = 0; + + break; + + case '"': + if (quoted == 0) + quoted = 2; + else if (quoted == 2) + quoted = 0; + + break; + + case ')': + if (!quoted && --paren_depth == 0) + { + /* Go -- give script to the shell */ + if (comm) + { +#ifdef __libc_ptf_call + /* We do not want the exec_comm call to be cut short + by a thread cancellation since cleanup is very + ugly. Therefore disable cancellation for + now. */ + // XXX Ideally we do want the thread being cancelable. + // XXX If demand is there we'll change it. + int state = PTHREAD_CANCEL_ENABLE; + __libc_ptf_call (pthread_setcancelstate, + (PTHREAD_CANCEL_DISABLE, &state), 0); +#endif + + error = exec_comm (comm, word, word_length, max_length, + flags, pwordexp, ifs, ifs_white); + +#ifdef __libc_ptf_call + __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0); +#endif + + free (comm); + } + + return error; + } + + /* This is just part of the script */ + break; + + case '(': + if (!quoted) + ++paren_depth; + } + + comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]); + if (comm == NULL) + return WRDE_NOSPACE; + } + + /* Premature end. */ + free (comm); + + return WRDE_SYNTAX; +} + +static int +internal_function +parse_param (char **word, size_t *word_length, size_t *max_length, + const char *words, size_t *offset, int flags, wordexp_t *pwordexp, + const char *ifs, const char *ifs_white, int quoted) +{ + /* We are poised just after "$" */ + enum action + { + ACT_NONE, + ACT_RP_SHORT_LEFT = '#', + ACT_RP_LONG_LEFT = 'L', + ACT_RP_SHORT_RIGHT = '%', + ACT_RP_LONG_RIGHT = 'R', + ACT_NULL_ERROR = '?', + ACT_NULL_SUBST = '-', + ACT_NONNULL_SUBST = '+', + ACT_NULL_ASSIGN = '=' + }; + size_t env_length; + size_t env_maxlen; + size_t pat_length; + size_t pat_maxlen; + size_t start = *offset; + char *env; + char *pattern; + char *value = NULL; + enum action action = ACT_NONE; + int depth = 0; + int colon_seen = 0; + int seen_hash = 0; + int free_value = 0; + int pattern_is_quoted = 0; /* 1 for singly-quoted, 2 for doubly-quoted */ + int error; + int special = 0; + char buffer[21]; + int brace = words[*offset] == '{'; + + env = w_newword (&env_length, &env_maxlen); + pattern = w_newword (&pat_length, &pat_maxlen); + + if (brace) + ++*offset; + + /* First collect the parameter name. */ + + if (words[*offset] == '#') + { + seen_hash = 1; + if (!brace) + goto envsubst; + ++*offset; + } + + if (isalpha (words[*offset]) || words[*offset] == '_') + { + /* Normal parameter name. */ + do + { + env = w_addchar (env, &env_length, &env_maxlen, + words[*offset]); + if (env == NULL) + goto no_space; + } + while (isalnum (words[++*offset]) || words[*offset] == '_'); + } + else if (isdigit (words[*offset])) + { + /* Numeric parameter name. */ + special = 1; + do + { + env = w_addchar (env, &env_length, &env_maxlen, + words[*offset]); + if (env == NULL) + goto no_space; + if (!brace) + goto envsubst; + } + while (isdigit(words[++*offset])); + } + else if (strchr ("*@$", words[*offset]) != NULL) + { + /* Special parameter. */ + special = 1; + env = w_addchar (env, &env_length, &env_maxlen, + words[*offset]); + if (env == NULL) + goto no_space; + ++*offset; + } + else + { + if (brace) + goto syntax; + } + + if (brace) + { + /* Check for special action to be applied to the value. */ + switch (words[*offset]) + { + case '}': + /* Evaluate. */ + goto envsubst; + + case '#': + action = ACT_RP_SHORT_LEFT; + if (words[1 + *offset] == '#') + { + ++*offset; + action = ACT_RP_LONG_LEFT; + } + break; + + case '%': + action = ACT_RP_SHORT_RIGHT; + if (words[1 + *offset] == '%') + { + ++*offset; + action = ACT_RP_LONG_RIGHT; + } + break; + + case ':': + if (strchr ("-=?+", words[1 + *offset]) == NULL) + goto syntax; + + colon_seen = 1; + action = words[++*offset]; + break; + + case '-': + case '=': + case '?': + case '+': + action = words[*offset]; + break; + + default: + goto syntax; + } + + /* Now collect the pattern, but don't expand it yet. */ + ++*offset; + for (; words[*offset]; ++(*offset)) + { + switch (words[*offset]) + { + case '{': + if (!pattern_is_quoted) + ++depth; + break; + + case '}': + if (!pattern_is_quoted) + { + if (depth == 0) + goto envsubst; + --depth; + } + break; + + case '\\': + if (pattern_is_quoted) + /* Quoted; treat as normal character. */ + break; + + /* Otherwise, it's an escape: next character is literal. */ + if (words[++*offset] == '\0') + goto syntax; + + pattern = w_addchar (pattern, &pat_length, &pat_maxlen, '\\'); + if (pattern == NULL) + goto no_space; + + break; + + case '\'': + if (pattern_is_quoted == 0) + pattern_is_quoted = 1; + else if (pattern_is_quoted == 1) + pattern_is_quoted = 0; + + break; + + case '"': + if (pattern_is_quoted == 0) + pattern_is_quoted = 2; + else if (pattern_is_quoted == 2) + pattern_is_quoted = 0; + + break; + } + + pattern = w_addchar (pattern, &pat_length, &pat_maxlen, + words[*offset]); + if (pattern == NULL) + goto no_space; + } + } + + /* End of input string -- remember to reparse the character that we + * stopped at. */ + --(*offset); + +envsubst: + if (words[start] == '{' && words[*offset] != '}') + goto syntax; + + if (env == NULL) + { + if (seen_hash) + { + /* $# expands to the number of positional parameters */ + buffer[20] = '\0'; + value = _itoa_word (__libc_argc - 1, &buffer[20], 10, 0); + seen_hash = 0; + } + else + { + /* Just $ on its own */ + *offset = start - 1; + *word = w_addchar (*word, word_length, max_length, '$'); + return *word ? 0 : WRDE_NOSPACE; + } + } + /* Is it a numeric parameter? */ + else if (isdigit (env[0])) + { + int n = atoi (env); + + if (n >= __libc_argc) + /* Substitute NULL. */ + value = NULL; + else + /* Replace with appropriate positional parameter. */ + value = __libc_argv[n]; + } + /* Is it a special parameter? */ + else if (special) + { + /* Is it `$$'? */ + if (*env == '$') + { + buffer[20] = '\0'; + value = _itoa_word (__getpid (), &buffer[20], 10, 0); + } + /* Is it `${#*}' or `${#@}'? */ + else if ((*env == '*' || *env == '@') && seen_hash) + { + buffer[20] = '\0'; + value = _itoa_word (__libc_argc > 0 ? __libc_argc - 1 : 0, + &buffer[20], 10, 0); + *word = w_addstr (*word, word_length, max_length, value); + free (env); + free (pattern); + return *word ? 0 : WRDE_NOSPACE; + } + /* Is it `$*' or `$@' (unquoted) ? */ + else if (*env == '*' || (*env == '@' && !quoted)) + { + size_t plist_len = 0; + int p; + char *end; + + /* Build up value parameter by parameter (copy them) */ + for (p = 1; __libc_argv[p]; ++p) + plist_len += strlen (__libc_argv[p]) + 1; /* for space */ + value = malloc (plist_len); + if (value == NULL) + goto no_space; + end = value; + *end = 0; + for (p = 1; __libc_argv[p]; ++p) + { + if (p > 1) + *end++ = ' '; + end = __stpcpy (end, __libc_argv[p]); + } + + free_value = 1; + } + else + { + /* Must be a quoted `$@' */ + assert (*env == '@' && quoted); + + /* Each parameter is a separate word ("$@") */ + if (__libc_argc == 2) + value = __libc_argv[1]; + else if (__libc_argc > 2) + { + int p; + + /* Append first parameter to current word. */ + value = w_addstr (*word, word_length, max_length, + __libc_argv[1]); + if (value == NULL || w_addword (pwordexp, value)) + goto no_space; + + for (p = 2; __libc_argv[p + 1]; p++) + { + char *newword = __strdup (__libc_argv[p]); + if (newword == NULL || w_addword (pwordexp, newword)) + goto no_space; + } + + /* Start a new word with the last parameter. */ + *word = w_newword (word_length, max_length); + value = __libc_argv[p]; + } + else + { + free (env); + free (pattern); + return 0; + } + } + } + else + value = getenv (env); + + if (value == NULL && (flags & WRDE_UNDEF)) + { + /* Variable not defined. */ + error = WRDE_BADVAL; + goto do_error; + } + + if (action != ACT_NONE) + { + int expand_pattern = 0; + + /* First, find out if we need to expand pattern (i.e. if we will + * use it). */ + switch (action) + { + case ACT_RP_SHORT_LEFT: + case ACT_RP_LONG_LEFT: + case ACT_RP_SHORT_RIGHT: + case ACT_RP_LONG_RIGHT: + /* Always expand for these. */ + expand_pattern = 1; + break; + + case ACT_NULL_ERROR: + case ACT_NULL_SUBST: + case ACT_NULL_ASSIGN: + if (!value || (!*value && colon_seen)) + /* If param is unset, or set but null and a colon has been seen, + the expansion of the pattern will be needed. */ + expand_pattern = 1; + + break; + + case ACT_NONNULL_SUBST: + /* Expansion of word will be needed if parameter is set and not null, + or set null but no colon has been seen. */ + if (value && (*value || !colon_seen)) + expand_pattern = 1; + + break; + + default: + assert (! "Unrecognised action!"); + } + + if (expand_pattern) + { + /* We need to perform tilde expansion, parameter expansion, + command substitution, and arithmetic expansion. We also + have to be a bit careful with wildcard characters, as + pattern might be given to fnmatch soon. To do this, we + convert quotes to escapes. */ + + char *expanded; + size_t exp_len; + size_t exp_maxl; + char *p; + int quoted = 0; /* 1: single quotes; 2: double */ + + expanded = w_newword (&exp_len, &exp_maxl); + for (p = pattern; p && *p; p++) + { + size_t offset; + + switch (*p) + { + case '"': + if (quoted == 2) + quoted = 0; + else if (quoted == 0) + quoted = 2; + else break; + + continue; + + case '\'': + if (quoted == 1) + quoted = 0; + else if (quoted == 0) + quoted = 1; + else break; + + continue; + + case '*': + case '?': + if (quoted) + { + /* Convert quoted wildchar to escaped wildchar. */ + expanded = w_addchar (expanded, &exp_len, + &exp_maxl, '\\'); + + if (expanded == NULL) + goto no_space; + } + break; + + case '$': + offset = 0; + error = parse_dollars (&expanded, &exp_len, &exp_maxl, p, + &offset, flags, NULL, NULL, NULL, 1); + if (error) + { + if (free_value) + free (value); + + free (expanded); + + goto do_error; + } + + p += offset; + continue; + + case '~': + if (quoted || exp_len) + break; + + offset = 0; + error = parse_tilde (&expanded, &exp_len, &exp_maxl, p, + &offset, 0); + if (error) + { + if (free_value) + free (value); + + free (expanded); + + goto do_error; + } + + p += offset; + continue; + + case '\\': + expanded = w_addchar (expanded, &exp_len, &exp_maxl, '\\'); + ++p; + assert (*p); /* checked when extracted initially */ + if (expanded == NULL) + goto no_space; + } + + expanded = w_addchar (expanded, &exp_len, &exp_maxl, *p); + + if (expanded == NULL) + goto no_space; + } + + free (pattern); + + pattern = expanded; + } + + switch (action) + { + case ACT_RP_SHORT_LEFT: + case ACT_RP_LONG_LEFT: + case ACT_RP_SHORT_RIGHT: + case ACT_RP_LONG_RIGHT: + { + char *p; + char c; + char *end; + + if (value == NULL || pattern == NULL || *pattern == '\0') + break; + + end = value + strlen (value); + + switch (action) + { + case ACT_RP_SHORT_LEFT: + for (p = value; p <= end; ++p) + { + c = *p; + *p = '\0'; + if (fnmatch (pattern, value, 0) != FNM_NOMATCH) + { + *p = c; + if (free_value) + { + char *newval = __strdup (p); + if (newval == NULL) + { + free (value); + goto no_space; + } + free (value); + value = newval; + } + else + value = p; + break; + } + *p = c; + } + + break; + + case ACT_RP_LONG_LEFT: + for (p = end; p >= value; --p) + { + c = *p; + *p = '\0'; + if (fnmatch (pattern, value, 0) != FNM_NOMATCH) + { + *p = c; + if (free_value) + { + char *newval = __strdup (p); + if (newval == NULL) + { + free (value); + goto no_space; + } + free (value); + value = newval; + } + else + value = p; + break; + } + *p = c; + } + + break; + + case ACT_RP_SHORT_RIGHT: + for (p = end; p >= value; --p) + { + if (fnmatch (pattern, p, 0) != FNM_NOMATCH) + { + char *newval; + newval = malloc (p - value + 1); + + if (newval == NULL) + { + if (free_value) + free (value); + goto no_space; + } + + *(char *) __mempcpy (newval, value, p - value) = '\0'; + if (free_value) + free (value); + value = newval; + free_value = 1; + break; + } + } + + break; + + case ACT_RP_LONG_RIGHT: + for (p = value; p <= end; ++p) + { + if (fnmatch (pattern, p, 0) != FNM_NOMATCH) + { + char *newval; + newval = malloc (p - value + 1); + + if (newval == NULL) + { + if (free_value) + free (value); + goto no_space; + } + + *(char *) __mempcpy (newval, value, p - value) = '\0'; + if (free_value) + free (value); + value = newval; + free_value = 1; + break; + } + } + + break; + + default: + break; + } + + break; + } + + case ACT_NULL_ERROR: + if (value && *value) + /* Substitute parameter */ + break; + + error = 0; + if (!colon_seen && value) + /* Substitute NULL */ + ; + else + { + const char *str = pattern; + + if (str[0] == '\0') + str = _("parameter null or not set"); + + __fxprintf (NULL, "%s: %s\n", env, str); + } + + if (free_value) + free (value); + goto do_error; + + case ACT_NULL_SUBST: + if (value && *value) + /* Substitute parameter */ + break; + + if (free_value && value) + free (value); + + if (!colon_seen && value) + /* Substitute NULL */ + goto success; + + value = pattern ? __strdup (pattern) : pattern; + free_value = 1; + + if (pattern && !value) + goto no_space; + + break; + + case ACT_NONNULL_SUBST: + if (value && (*value || !colon_seen)) + { + if (free_value && value) + free (value); + + value = pattern ? __strdup (pattern) : pattern; + free_value = 1; + + if (pattern && !value) + goto no_space; + + break; + } + + /* Substitute NULL */ + if (free_value) + free (value); + goto success; + + case ACT_NULL_ASSIGN: + if (value && *value) + /* Substitute parameter */ + break; + + if (!colon_seen && value) + { + /* Substitute NULL */ + if (free_value) + free (value); + goto success; + } + + if (free_value) + free (value); + + value = pattern ? __strdup (pattern) : pattern; + free_value = 1; + + if (pattern && !value) + goto no_space; + + __setenv (env, value, 1); + break; + + default: + assert (! "Unrecognised action!"); + } + } + + free (env); + env = NULL; + free (pattern); + pattern = NULL; + + if (seen_hash) + { + char param_length[21]; + param_length[20] = '\0'; + *word = w_addstr (*word, word_length, max_length, + _itoa_word (value ? strlen (value) : 0, + ¶m_length[20], 10, 0)); + if (free_value) + { + assert (value != NULL); + free (value); + } + + return *word ? 0 : WRDE_NOSPACE; + } + + if (value == NULL) + return 0; + + if (quoted || !pwordexp) + { + /* Quoted - no field split */ + *word = w_addstr (*word, word_length, max_length, value); + if (free_value) + free (value); + + return *word ? 0 : WRDE_NOSPACE; + } + else + { + /* Need to field-split */ + char *value_copy = __strdup (value); /* Don't modify value */ + char *field_begin = value_copy; + int seen_nonws_ifs = 0; + + if (free_value) + free (value); + + if (value_copy == NULL) + goto no_space; + + do + { + char *field_end = field_begin; + char *next_field; + + /* If this isn't the first field, start a new word */ + if (field_begin != value_copy) + { + if (w_addword (pwordexp, *word) == WRDE_NOSPACE) + { + free (value_copy); + goto no_space; + } + + *word = w_newword (word_length, max_length); + } + + /* Skip IFS whitespace before the field */ + field_begin += strspn (field_begin, ifs_white); + + if (!seen_nonws_ifs && *field_begin == 0) + /* Nothing but whitespace */ + break; + + /* Search for the end of the field */ + field_end = field_begin + strcspn (field_begin, ifs); + + /* Set up pointer to the character after end of field and + skip whitespace IFS after it. */ + next_field = field_end + strspn (field_end, ifs_white); + + /* Skip at most one non-whitespace IFS character after the field */ + seen_nonws_ifs = 0; + if (*next_field && strchr (ifs, *next_field)) + { + seen_nonws_ifs = 1; + next_field++; + } + + /* Null-terminate it */ + *field_end = 0; + + /* Tag a copy onto the current word */ + *word = w_addstr (*word, word_length, max_length, field_begin); + + if (*word == NULL && *field_begin != '\0') + { + free (value_copy); + goto no_space; + } + + field_begin = next_field; + } + while (seen_nonws_ifs || *field_begin); + + free (value_copy); + } + + return 0; + +success: + error = 0; + goto do_error; + +no_space: + error = WRDE_NOSPACE; + goto do_error; + +syntax: + error = WRDE_SYNTAX; + +do_error: + free (env); + + free (pattern); + + return error; +} + +static int +internal_function +parse_dollars (char **word, size_t *word_length, size_t *max_length, + const char *words, size_t *offset, int flags, + wordexp_t *pwordexp, const char *ifs, const char *ifs_white, + int quoted) +{ + /* We are poised _at_ "$" */ + switch (words[1 + *offset]) + { + case '"': + case '\'': + case 0: + *word = w_addchar (*word, word_length, max_length, '$'); + return *word ? 0 : WRDE_NOSPACE; + + case '(': + if (words[2 + *offset] == '(') + { + /* Differentiate between $((1+3)) and $((echo);(ls)) */ + int i = 3 + *offset; + int depth = 0; + while (words[i] && !(depth == 0 && words[i] == ')')) + { + if (words[i] == '(') + ++depth; + else if (words[i] == ')') + --depth; + + ++i; + } + + if (words[i] == ')' && words[i + 1] == ')') + { + (*offset) += 3; + /* Call parse_arith -- 0 is for "no brackets" */ + return parse_arith (word, word_length, max_length, words, offset, + flags, 0); + } + } + + if (flags & WRDE_NOCMD) + return WRDE_CMDSUB; + + (*offset) += 2; + return parse_comm (word, word_length, max_length, words, offset, flags, + quoted? NULL : pwordexp, ifs, ifs_white); + + case '[': + (*offset) += 2; + /* Call parse_arith -- 1 is for "brackets" */ + return parse_arith (word, word_length, max_length, words, offset, flags, + 1); + + case '{': + default: + ++(*offset); /* parse_param needs to know if "{" is there */ + return parse_param (word, word_length, max_length, words, offset, flags, + pwordexp, ifs, ifs_white, quoted); + } +} + +static int +internal_function +parse_backtick (char **word, size_t *word_length, size_t *max_length, + const char *words, size_t *offset, int flags, + wordexp_t *pwordexp, const char *ifs, const char *ifs_white) +{ + /* We are poised just after "`" */ + int error; + int squoting = 0; + size_t comm_length; + size_t comm_maxlen; + char *comm = w_newword (&comm_length, &comm_maxlen); + + for (; words[*offset]; ++(*offset)) + { + switch (words[*offset]) + { + case '`': + /* Go -- give the script to the shell */ + error = exec_comm (comm, word, word_length, max_length, flags, + pwordexp, ifs, ifs_white); + free (comm); + return error; + + case '\\': + if (squoting) + { + error = parse_qtd_backslash (&comm, &comm_length, &comm_maxlen, + words, offset); + + if (error) + { + free (comm); + return error; + } + + break; + } + + ++(*offset); + error = parse_backslash (&comm, &comm_length, &comm_maxlen, words, + offset); + + if (error) + { + free (comm); + return error; + } + + break; + + case '\'': + squoting = 1 - squoting; + default: + comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]); + if (comm == NULL) + return WRDE_NOSPACE; + } + } + + /* Premature end */ + free (comm); + return WRDE_SYNTAX; +} + +static int +internal_function +parse_dquote (char **word, size_t *word_length, size_t *max_length, + const char *words, size_t *offset, int flags, + wordexp_t *pwordexp, const char * ifs, const char * ifs_white) +{ + /* We are poised just after a double-quote */ + int error; + + for (; words[*offset]; ++(*offset)) + { + switch (words[*offset]) + { + case '"': + return 0; + + case '$': + error = parse_dollars (word, word_length, max_length, words, offset, + flags, pwordexp, ifs, ifs_white, 1); + /* The ``1'' here is to tell parse_dollars not to + * split the fields. It may need to, however ("$@"). + */ + if (error) + return error; + + break; + + case '`': + if (flags & WRDE_NOCMD) + return WRDE_CMDSUB; + + ++(*offset); + error = parse_backtick (word, word_length, max_length, words, + offset, flags, NULL, NULL, NULL); + /* The first NULL here is to tell parse_backtick not to + * split the fields. + */ + if (error) + return error; + + break; + + case '\\': + error = parse_qtd_backslash (word, word_length, max_length, words, + offset); + + if (error) + return error; + + break; + + default: + *word = w_addchar (*word, word_length, max_length, words[*offset]); + if (*word == NULL) + return WRDE_NOSPACE; + } + } + + /* Unterminated string */ + return WRDE_SYNTAX; +} + +/* + * wordfree() is to be called after pwordexp is finished with. + */ + +void +wordfree (wordexp_t *pwordexp) +{ + + /* wordexp can set pwordexp to NULL */ + if (pwordexp && pwordexp->we_wordv) + { + char **wordv = pwordexp->we_wordv; + + for (wordv += pwordexp->we_offs; *wordv; ++wordv) + free (*wordv); + + free (pwordexp->we_wordv); + pwordexp->we_wordv = NULL; + } +} +libc_hidden_def (wordfree) + +/* + * wordexp() + */ + +int +wordexp (const char *words, wordexp_t *pwordexp, int flags) +{ + size_t words_offset; + size_t word_length; + size_t max_length; + char *word = w_newword (&word_length, &max_length); + int error; + char *ifs; + char ifs_white[4]; + wordexp_t old_word = *pwordexp; + + if (flags & WRDE_REUSE) + { + /* Minimal implementation of WRDE_REUSE for now */ + wordfree (pwordexp); + old_word.we_wordv = NULL; + } + + if ((flags & WRDE_APPEND) == 0) + { + pwordexp->we_wordc = 0; + + if (flags & WRDE_DOOFFS) + { + pwordexp->we_wordv = calloc (1 + pwordexp->we_offs, sizeof (char *)); + if (pwordexp->we_wordv == NULL) + { + error = WRDE_NOSPACE; + goto do_error; + } + } + else + { + pwordexp->we_wordv = calloc (1, sizeof (char *)); + if (pwordexp->we_wordv == NULL) + { + error = WRDE_NOSPACE; + goto do_error; + } + + pwordexp->we_offs = 0; + } + } + + /* Find out what the field separators are. + * There are two types: whitespace and non-whitespace. + */ + ifs = getenv ("IFS"); + + if (ifs == NULL) + /* IFS unset - use <space><tab><newline>. */ + ifs = strcpy (ifs_white, " \t\n"); + else + { + char *ifsch = ifs; + char *whch = ifs_white; + + while (*ifsch != '\0') + { + if (*ifsch == ' ' || *ifsch == '\t' || *ifsch == '\n') + { + /* Whitespace IFS. See first whether it is already in our + collection. */ + char *runp = ifs_white; + + while (runp < whch && *runp != *ifsch) + ++runp; + + if (runp == whch) + *whch++ = *ifsch; + } + + ++ifsch; + } + *whch = '\0'; + } + + for (words_offset = 0 ; words[words_offset] ; ++words_offset) + switch (words[words_offset]) + { + case '\\': + error = parse_backslash (&word, &word_length, &max_length, words, + &words_offset); + + if (error) + goto do_error; + + break; + + case '$': + error = parse_dollars (&word, &word_length, &max_length, words, + &words_offset, flags, pwordexp, ifs, ifs_white, + 0); + + if (error) + goto do_error; + + break; + + case '`': + if (flags & WRDE_NOCMD) + { + error = WRDE_CMDSUB; + goto do_error; + } + + ++words_offset; + error = parse_backtick (&word, &word_length, &max_length, words, + &words_offset, flags, pwordexp, ifs, + ifs_white); + + if (error) + goto do_error; + + break; + + case '"': + ++words_offset; + error = parse_dquote (&word, &word_length, &max_length, words, + &words_offset, flags, pwordexp, ifs, ifs_white); + + if (error) + goto do_error; + + if (!word_length) + { + error = w_addword (pwordexp, NULL); + + if (error) + return error; + } + + break; + + case '\'': + ++words_offset; + error = parse_squote (&word, &word_length, &max_length, words, + &words_offset); + + if (error) + goto do_error; + + if (!word_length) + { + error = w_addword (pwordexp, NULL); + + if (error) + return error; + } + + break; + + case '~': + error = parse_tilde (&word, &word_length, &max_length, words, + &words_offset, pwordexp->we_wordc); + + if (error) + goto do_error; + + break; + + case '*': + case '[': + case '?': + error = parse_glob (&word, &word_length, &max_length, words, + &words_offset, flags, pwordexp, ifs, ifs_white); + + if (error) + goto do_error; + + break; + + default: + /* Is it a word separator? */ + if (strchr (" \t", words[words_offset]) == NULL) + { + char ch = words[words_offset]; + + /* Not a word separator -- but is it a valid word char? */ + if (strchr ("\n|&;<>(){}", ch)) + { + /* Fail */ + error = WRDE_BADCHAR; + goto do_error; + } + + /* "Ordinary" character -- add it to word */ + word = w_addchar (word, &word_length, &max_length, + ch); + if (word == NULL) + { + error = WRDE_NOSPACE; + goto do_error; + } + + break; + } + + /* If a word has been delimited, add it to the list. */ + if (word != NULL) + { + error = w_addword (pwordexp, word); + if (error) + goto do_error; + } + + word = w_newword (&word_length, &max_length); + } + + /* End of string */ + + /* There was a word separator at the end */ + if (word == NULL) /* i.e. w_newword */ + return 0; + + /* There was no field separator at the end */ + return w_addword (pwordexp, word); + +do_error: + /* Error: + * free memory used (unless error is WRDE_NOSPACE), and + * set pwordexp members back to what they were. + */ + + free (word); + + if (error == WRDE_NOSPACE) + return WRDE_NOSPACE; + + if ((flags & WRDE_APPEND) == 0) + wordfree (pwordexp); + + *pwordexp = old_word; + return error; +} |