diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2012-12-22 14:27:13 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2012-12-22 14:27:13 +0000 |
commit | c949e6f8ed33f31bd46c1626dc6c5828a1750e56 (patch) | |
tree | e519be160770e6b20bfe88eb923ea6aa8edb3e58 /sed | |
download | sed-tarball-c949e6f8ed33f31bd46c1626dc6c5828a1750e56.tar.gz |
Diffstat (limited to 'sed')
-rw-r--r-- | sed/Makefile.am | 17 | ||||
-rw-r--r-- | sed/Makefile.in | 1274 | ||||
-rw-r--r-- | sed/compile.c | 1734 | ||||
-rw-r--r-- | sed/execute.c | 1762 | ||||
-rw-r--r-- | sed/fmt.c | 577 | ||||
-rw-r--r-- | sed/mbcs.c | 60 | ||||
-rw-r--r-- | sed/regexp.c | 267 | ||||
-rw-r--r-- | sed/sed.c | 335 | ||||
-rw-r--r-- | sed/sed.h | 265 | ||||
-rw-r--r-- | sed/utils.c | 599 | ||||
-rw-r--r-- | sed/utils.h | 50 |
11 files changed, 6940 insertions, 0 deletions
diff --git a/sed/Makefile.am b/sed/Makefile.am new file mode 100644 index 0000000..a164255 --- /dev/null +++ b/sed/Makefile.am @@ -0,0 +1,17 @@ +## Process this file with automake to produce Makefile.in +bin_PROGRAMS = sed + +localedir = $(datadir)/locale + +sed_SOURCES = sed.c compile.c execute.c regexp.c fmt.c mbcs.c utils.c +noinst_HEADERS = sed.h utils.h + +AM_CPPFLAGS = -I$(top_srcdir)/lib -I$(top_srcdir) -I$(top_builddir)/lib \ + -DLOCALEDIR=\"$(localedir)\" + +sed_LDADD = ../lib/libsed.a @INTLLIBS@ @LIB_ACL@ @LIB_SELINUX@ +sed_DEPENDENCIES = ../lib/libsed.a + +$(PROGRAMS): $(LDADD) + + diff --git a/sed/Makefile.in b/sed/Makefile.in new file mode 100644 index 0000000..3a6a33b --- /dev/null +++ b/sed/Makefile.in @@ -0,0 +1,1274 @@ +# Makefile.in generated by automake 1.12.2 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2012 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +am__make_dryrun = \ + { \ + am__dry=no; \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ + | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ + *) \ + for am__flg in $$MAKEFLAGS; do \ + case $$am__flg in \ + *=*|--*) ;; \ + *n*) am__dry=yes; break;; \ + esac; \ + done;; \ + esac; \ + test $$am__dry = yes; \ + } +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = sed$(EXEEXT) +subdir = sed +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(top_srcdir)/build-aux/depcomp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/00gnulib.m4 \ + $(top_srcdir)/m4/acl.m4 $(top_srcdir)/m4/alloca.m4 \ + $(top_srcdir)/m4/btowc.m4 $(top_srcdir)/m4/canonicalize.m4 \ + $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/configmake.m4 \ + $(top_srcdir)/m4/dirname.m4 \ + $(top_srcdir)/m4/double-slash-root.m4 \ + $(top_srcdir)/m4/eealloc.m4 $(top_srcdir)/m4/errno_h.m4 \ + $(top_srcdir)/m4/error.m4 $(top_srcdir)/m4/extensions.m4 \ + $(top_srcdir)/m4/extern-inline.m4 $(top_srcdir)/m4/fcntl-o.m4 \ + $(top_srcdir)/m4/fcntl_h.m4 $(top_srcdir)/m4/fstat.m4 \ + $(top_srcdir)/m4/fwriting.m4 $(top_srcdir)/m4/getdelim.m4 \ + $(top_srcdir)/m4/getopt.m4 $(top_srcdir)/m4/gettext.m4 \ + $(top_srcdir)/m4/gettimeofday.m4 $(top_srcdir)/m4/glibc21.m4 \ + $(top_srcdir)/m4/gnulib-common.m4 \ + $(top_srcdir)/m4/gnulib-comp.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/include_next.m4 \ + $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/langinfo_h.m4 \ + $(top_srcdir)/m4/largefile.m4 $(top_srcdir)/m4/lib-ld.m4 \ + $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ + $(top_srcdir)/m4/localcharset.m4 $(top_srcdir)/m4/locale-fr.m4 \ + $(top_srcdir)/m4/locale-ja.m4 $(top_srcdir)/m4/locale-zh.m4 \ + $(top_srcdir)/m4/locale_h.m4 $(top_srcdir)/m4/localeconv.m4 \ + $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/lstat.m4 \ + $(top_srcdir)/m4/malloc.m4 $(top_srcdir)/m4/malloca.m4 \ + $(top_srcdir)/m4/mbrlen.m4 $(top_srcdir)/m4/mbrtowc.m4 \ + $(top_srcdir)/m4/mbsinit.m4 $(top_srcdir)/m4/mbstate_t.m4 \ + $(top_srcdir)/m4/mbtowc.m4 $(top_srcdir)/m4/memchr.m4 \ + $(top_srcdir)/m4/mkostemp.m4 $(top_srcdir)/m4/mmap-anon.m4 \ + $(top_srcdir)/m4/msvc-inval.m4 \ + $(top_srcdir)/m4/msvc-nothrow.m4 $(top_srcdir)/m4/multiarch.m4 \ + $(top_srcdir)/m4/nl_langinfo.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/nocrash.m4 $(top_srcdir)/m4/off_t.m4 \ + $(top_srcdir)/m4/pathmax.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/quote.m4 \ + $(top_srcdir)/m4/quotearg.m4 $(top_srcdir)/m4/readlink.m4 \ + $(top_srcdir)/m4/realloc.m4 $(top_srcdir)/m4/regex.m4 \ + $(top_srcdir)/m4/rename.m4 $(top_srcdir)/m4/rmdir.m4 \ + $(top_srcdir)/m4/selinux-context-h.m4 \ + $(top_srcdir)/m4/selinux-selinux-h.m4 \ + $(top_srcdir)/m4/ssize_t.m4 $(top_srcdir)/m4/stat.m4 \ + $(top_srcdir)/m4/stdarg.m4 $(top_srcdir)/m4/stdbool.m4 \ + $(top_srcdir)/m4/stddef_h.m4 $(top_srcdir)/m4/stdint.m4 \ + $(top_srcdir)/m4/stdio_h.m4 $(top_srcdir)/m4/stdlib_h.m4 \ + $(top_srcdir)/m4/strerror.m4 $(top_srcdir)/m4/string_h.m4 \ + $(top_srcdir)/m4/strverscmp.m4 \ + $(top_srcdir)/m4/sys_socket_h.m4 \ + $(top_srcdir)/m4/sys_stat_h.m4 $(top_srcdir)/m4/sys_time_h.m4 \ + $(top_srcdir)/m4/sys_types_h.m4 $(top_srcdir)/m4/tempname.m4 \ + $(top_srcdir)/m4/threadlib.m4 $(top_srcdir)/m4/time_h.m4 \ + $(top_srcdir)/m4/unistd_h.m4 $(top_srcdir)/m4/unlocked-io.m4 \ + $(top_srcdir)/m4/version-etc.m4 \ + $(top_srcdir)/m4/warn-on-use.m4 $(top_srcdir)/m4/wchar_h.m4 \ + $(top_srcdir)/m4/wchar_t.m4 $(top_srcdir)/m4/wcrtomb.m4 \ + $(top_srcdir)/m4/wctob.m4 $(top_srcdir)/m4/wctomb.m4 \ + $(top_srcdir)/m4/wctype_h.m4 $(top_srcdir)/m4/wint_t.m4 \ + $(top_srcdir)/m4/xalloc.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" +PROGRAMS = $(bin_PROGRAMS) +am_sed_OBJECTS = sed.$(OBJEXT) compile.$(OBJEXT) execute.$(OBJEXT) \ + regexp.$(OBJEXT) fmt.$(OBJEXT) mbcs.$(OBJEXT) utils.$(OBJEXT) +sed_OBJECTS = $(am_sed_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(sed_SOURCES) +DIST_SOURCES = $(sed_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +ALLOCA_H = @ALLOCA_H@ +AMTAR = @AMTAR@ +APPLE_UNIVERSAL_BUILD = @APPLE_UNIVERSAL_BUILD@ +AR = @AR@ +ARFLAGS = @ARFLAGS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BITSIZEOF_PTRDIFF_T = @BITSIZEOF_PTRDIFF_T@ +BITSIZEOF_SIG_ATOMIC_T = @BITSIZEOF_SIG_ATOMIC_T@ +BITSIZEOF_SIZE_T = @BITSIZEOF_SIZE_T@ +BITSIZEOF_WCHAR_T = @BITSIZEOF_WCHAR_T@ +BITSIZEOF_WINT_T = @BITSIZEOF_WINT_T@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +COPYRIGHT_YEAR = @COPYRIGHT_YEAR@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EMULTIHOP_HIDDEN = @EMULTIHOP_HIDDEN@ +EMULTIHOP_VALUE = @EMULTIHOP_VALUE@ +ENOLINK_HIDDEN = @ENOLINK_HIDDEN@ +ENOLINK_VALUE = @ENOLINK_VALUE@ +EOVERFLOW_HIDDEN = @EOVERFLOW_HIDDEN@ +EOVERFLOW_VALUE = @EOVERFLOW_VALUE@ +ERRNO_H = @ERRNO_H@ +EXEEXT = @EXEEXT@ +GETOPT_H = @GETOPT_H@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GLIBC21 = @GLIBC21@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNULIB_ATOLL = @GNULIB_ATOLL@ +GNULIB_BTOWC = @GNULIB_BTOWC@ +GNULIB_CALLOC_POSIX = @GNULIB_CALLOC_POSIX@ +GNULIB_CANONICALIZE_FILE_NAME = @GNULIB_CANONICALIZE_FILE_NAME@ +GNULIB_CHDIR = @GNULIB_CHDIR@ +GNULIB_CHOWN = @GNULIB_CHOWN@ +GNULIB_CLOSE = @GNULIB_CLOSE@ +GNULIB_DPRINTF = @GNULIB_DPRINTF@ +GNULIB_DUP = @GNULIB_DUP@ +GNULIB_DUP2 = @GNULIB_DUP2@ +GNULIB_DUP3 = @GNULIB_DUP3@ +GNULIB_DUPLOCALE = @GNULIB_DUPLOCALE@ +GNULIB_ENVIRON = @GNULIB_ENVIRON@ +GNULIB_EUIDACCESS = @GNULIB_EUIDACCESS@ +GNULIB_FACCESSAT = @GNULIB_FACCESSAT@ +GNULIB_FCHDIR = @GNULIB_FCHDIR@ +GNULIB_FCHMODAT = @GNULIB_FCHMODAT@ +GNULIB_FCHOWNAT = @GNULIB_FCHOWNAT@ +GNULIB_FCLOSE = @GNULIB_FCLOSE@ +GNULIB_FCNTL = @GNULIB_FCNTL@ +GNULIB_FDATASYNC = @GNULIB_FDATASYNC@ +GNULIB_FDOPEN = @GNULIB_FDOPEN@ +GNULIB_FFLUSH = @GNULIB_FFLUSH@ +GNULIB_FFSL = @GNULIB_FFSL@ +GNULIB_FFSLL = @GNULIB_FFSLL@ +GNULIB_FGETC = @GNULIB_FGETC@ +GNULIB_FGETS = @GNULIB_FGETS@ +GNULIB_FOPEN = @GNULIB_FOPEN@ +GNULIB_FPRINTF = @GNULIB_FPRINTF@ +GNULIB_FPRINTF_POSIX = @GNULIB_FPRINTF_POSIX@ +GNULIB_FPURGE = @GNULIB_FPURGE@ +GNULIB_FPUTC = @GNULIB_FPUTC@ +GNULIB_FPUTS = @GNULIB_FPUTS@ +GNULIB_FREAD = @GNULIB_FREAD@ +GNULIB_FREOPEN = @GNULIB_FREOPEN@ +GNULIB_FSCANF = @GNULIB_FSCANF@ +GNULIB_FSEEK = @GNULIB_FSEEK@ +GNULIB_FSEEKO = @GNULIB_FSEEKO@ +GNULIB_FSTAT = @GNULIB_FSTAT@ +GNULIB_FSTATAT = @GNULIB_FSTATAT@ +GNULIB_FSYNC = @GNULIB_FSYNC@ +GNULIB_FTELL = @GNULIB_FTELL@ +GNULIB_FTELLO = @GNULIB_FTELLO@ +GNULIB_FTRUNCATE = @GNULIB_FTRUNCATE@ +GNULIB_FUTIMENS = @GNULIB_FUTIMENS@ +GNULIB_FWRITE = @GNULIB_FWRITE@ +GNULIB_GETC = @GNULIB_GETC@ +GNULIB_GETCHAR = @GNULIB_GETCHAR@ +GNULIB_GETCWD = @GNULIB_GETCWD@ +GNULIB_GETDELIM = @GNULIB_GETDELIM@ +GNULIB_GETDOMAINNAME = @GNULIB_GETDOMAINNAME@ +GNULIB_GETDTABLESIZE = @GNULIB_GETDTABLESIZE@ +GNULIB_GETGROUPS = @GNULIB_GETGROUPS@ +GNULIB_GETHOSTNAME = @GNULIB_GETHOSTNAME@ +GNULIB_GETLINE = @GNULIB_GETLINE@ +GNULIB_GETLOADAVG = @GNULIB_GETLOADAVG@ +GNULIB_GETLOGIN = @GNULIB_GETLOGIN@ +GNULIB_GETLOGIN_R = @GNULIB_GETLOGIN_R@ +GNULIB_GETPAGESIZE = @GNULIB_GETPAGESIZE@ +GNULIB_GETSUBOPT = @GNULIB_GETSUBOPT@ +GNULIB_GETTIMEOFDAY = @GNULIB_GETTIMEOFDAY@ +GNULIB_GETUSERSHELL = @GNULIB_GETUSERSHELL@ +GNULIB_GL_UNISTD_H_GETOPT = @GNULIB_GL_UNISTD_H_GETOPT@ +GNULIB_GRANTPT = @GNULIB_GRANTPT@ +GNULIB_GROUP_MEMBER = @GNULIB_GROUP_MEMBER@ +GNULIB_ISATTY = @GNULIB_ISATTY@ +GNULIB_ISWBLANK = @GNULIB_ISWBLANK@ +GNULIB_ISWCTYPE = @GNULIB_ISWCTYPE@ +GNULIB_LCHMOD = @GNULIB_LCHMOD@ +GNULIB_LCHOWN = @GNULIB_LCHOWN@ +GNULIB_LINK = @GNULIB_LINK@ +GNULIB_LINKAT = @GNULIB_LINKAT@ +GNULIB_LOCALECONV = @GNULIB_LOCALECONV@ +GNULIB_LSEEK = @GNULIB_LSEEK@ +GNULIB_LSTAT = @GNULIB_LSTAT@ +GNULIB_MALLOC_POSIX = @GNULIB_MALLOC_POSIX@ +GNULIB_MBRLEN = @GNULIB_MBRLEN@ +GNULIB_MBRTOWC = @GNULIB_MBRTOWC@ +GNULIB_MBSCASECMP = @GNULIB_MBSCASECMP@ +GNULIB_MBSCASESTR = @GNULIB_MBSCASESTR@ +GNULIB_MBSCHR = @GNULIB_MBSCHR@ +GNULIB_MBSCSPN = @GNULIB_MBSCSPN@ +GNULIB_MBSINIT = @GNULIB_MBSINIT@ +GNULIB_MBSLEN = @GNULIB_MBSLEN@ +GNULIB_MBSNCASECMP = @GNULIB_MBSNCASECMP@ +GNULIB_MBSNLEN = @GNULIB_MBSNLEN@ +GNULIB_MBSNRTOWCS = @GNULIB_MBSNRTOWCS@ +GNULIB_MBSPBRK = @GNULIB_MBSPBRK@ +GNULIB_MBSPCASECMP = @GNULIB_MBSPCASECMP@ +GNULIB_MBSRCHR = @GNULIB_MBSRCHR@ +GNULIB_MBSRTOWCS = @GNULIB_MBSRTOWCS@ +GNULIB_MBSSEP = @GNULIB_MBSSEP@ +GNULIB_MBSSPN = @GNULIB_MBSSPN@ +GNULIB_MBSSTR = @GNULIB_MBSSTR@ +GNULIB_MBSTOK_R = @GNULIB_MBSTOK_R@ +GNULIB_MBTOWC = @GNULIB_MBTOWC@ +GNULIB_MEMCHR = @GNULIB_MEMCHR@ +GNULIB_MEMMEM = @GNULIB_MEMMEM@ +GNULIB_MEMPCPY = @GNULIB_MEMPCPY@ +GNULIB_MEMRCHR = @GNULIB_MEMRCHR@ +GNULIB_MKDIRAT = @GNULIB_MKDIRAT@ +GNULIB_MKDTEMP = @GNULIB_MKDTEMP@ +GNULIB_MKFIFO = @GNULIB_MKFIFO@ +GNULIB_MKFIFOAT = @GNULIB_MKFIFOAT@ +GNULIB_MKNOD = @GNULIB_MKNOD@ +GNULIB_MKNODAT = @GNULIB_MKNODAT@ +GNULIB_MKOSTEMP = @GNULIB_MKOSTEMP@ +GNULIB_MKOSTEMPS = @GNULIB_MKOSTEMPS@ +GNULIB_MKSTEMP = @GNULIB_MKSTEMP@ +GNULIB_MKSTEMPS = @GNULIB_MKSTEMPS@ +GNULIB_MKTIME = @GNULIB_MKTIME@ +GNULIB_NANOSLEEP = @GNULIB_NANOSLEEP@ +GNULIB_NL_LANGINFO = @GNULIB_NL_LANGINFO@ +GNULIB_NONBLOCKING = @GNULIB_NONBLOCKING@ +GNULIB_OBSTACK_PRINTF = @GNULIB_OBSTACK_PRINTF@ +GNULIB_OBSTACK_PRINTF_POSIX = @GNULIB_OBSTACK_PRINTF_POSIX@ +GNULIB_OPEN = @GNULIB_OPEN@ +GNULIB_OPENAT = @GNULIB_OPENAT@ +GNULIB_PCLOSE = @GNULIB_PCLOSE@ +GNULIB_PERROR = @GNULIB_PERROR@ +GNULIB_PIPE = @GNULIB_PIPE@ +GNULIB_PIPE2 = @GNULIB_PIPE2@ +GNULIB_POPEN = @GNULIB_POPEN@ +GNULIB_POSIX_OPENPT = @GNULIB_POSIX_OPENPT@ +GNULIB_PREAD = @GNULIB_PREAD@ +GNULIB_PRINTF = @GNULIB_PRINTF@ +GNULIB_PRINTF_POSIX = @GNULIB_PRINTF_POSIX@ +GNULIB_PTSNAME = @GNULIB_PTSNAME@ +GNULIB_PTSNAME_R = @GNULIB_PTSNAME_R@ +GNULIB_PUTC = @GNULIB_PUTC@ +GNULIB_PUTCHAR = @GNULIB_PUTCHAR@ +GNULIB_PUTENV = @GNULIB_PUTENV@ +GNULIB_PUTS = @GNULIB_PUTS@ +GNULIB_PWRITE = @GNULIB_PWRITE@ +GNULIB_RANDOM = @GNULIB_RANDOM@ +GNULIB_RANDOM_R = @GNULIB_RANDOM_R@ +GNULIB_RAWMEMCHR = @GNULIB_RAWMEMCHR@ +GNULIB_READ = @GNULIB_READ@ +GNULIB_READLINK = @GNULIB_READLINK@ +GNULIB_READLINKAT = @GNULIB_READLINKAT@ +GNULIB_REALLOC_POSIX = @GNULIB_REALLOC_POSIX@ +GNULIB_REALPATH = @GNULIB_REALPATH@ +GNULIB_REMOVE = @GNULIB_REMOVE@ +GNULIB_RENAME = @GNULIB_RENAME@ +GNULIB_RENAMEAT = @GNULIB_RENAMEAT@ +GNULIB_RMDIR = @GNULIB_RMDIR@ +GNULIB_RPMATCH = @GNULIB_RPMATCH@ +GNULIB_SCANF = @GNULIB_SCANF@ +GNULIB_SETENV = @GNULIB_SETENV@ +GNULIB_SETHOSTNAME = @GNULIB_SETHOSTNAME@ +GNULIB_SETLOCALE = @GNULIB_SETLOCALE@ +GNULIB_SLEEP = @GNULIB_SLEEP@ +GNULIB_SNPRINTF = @GNULIB_SNPRINTF@ +GNULIB_SPRINTF_POSIX = @GNULIB_SPRINTF_POSIX@ +GNULIB_STAT = @GNULIB_STAT@ +GNULIB_STDIO_H_NONBLOCKING = @GNULIB_STDIO_H_NONBLOCKING@ +GNULIB_STDIO_H_SIGPIPE = @GNULIB_STDIO_H_SIGPIPE@ +GNULIB_STPCPY = @GNULIB_STPCPY@ +GNULIB_STPNCPY = @GNULIB_STPNCPY@ +GNULIB_STRCASESTR = @GNULIB_STRCASESTR@ +GNULIB_STRCHRNUL = @GNULIB_STRCHRNUL@ +GNULIB_STRDUP = @GNULIB_STRDUP@ +GNULIB_STRERROR = @GNULIB_STRERROR@ +GNULIB_STRERROR_R = @GNULIB_STRERROR_R@ +GNULIB_STRNCAT = @GNULIB_STRNCAT@ +GNULIB_STRNDUP = @GNULIB_STRNDUP@ +GNULIB_STRNLEN = @GNULIB_STRNLEN@ +GNULIB_STRPBRK = @GNULIB_STRPBRK@ +GNULIB_STRPTIME = @GNULIB_STRPTIME@ +GNULIB_STRSEP = @GNULIB_STRSEP@ +GNULIB_STRSIGNAL = @GNULIB_STRSIGNAL@ +GNULIB_STRSTR = @GNULIB_STRSTR@ +GNULIB_STRTOD = @GNULIB_STRTOD@ +GNULIB_STRTOK_R = @GNULIB_STRTOK_R@ +GNULIB_STRTOLL = @GNULIB_STRTOLL@ +GNULIB_STRTOULL = @GNULIB_STRTOULL@ +GNULIB_STRVERSCMP = @GNULIB_STRVERSCMP@ +GNULIB_SYMLINK = @GNULIB_SYMLINK@ +GNULIB_SYMLINKAT = @GNULIB_SYMLINKAT@ +GNULIB_SYSTEM_POSIX = @GNULIB_SYSTEM_POSIX@ +GNULIB_TIMEGM = @GNULIB_TIMEGM@ +GNULIB_TIME_R = @GNULIB_TIME_R@ +GNULIB_TMPFILE = @GNULIB_TMPFILE@ +GNULIB_TOWCTRANS = @GNULIB_TOWCTRANS@ +GNULIB_TTYNAME_R = @GNULIB_TTYNAME_R@ +GNULIB_UNISTD_H_NONBLOCKING = @GNULIB_UNISTD_H_NONBLOCKING@ +GNULIB_UNISTD_H_SIGPIPE = @GNULIB_UNISTD_H_SIGPIPE@ +GNULIB_UNLINK = @GNULIB_UNLINK@ +GNULIB_UNLINKAT = @GNULIB_UNLINKAT@ +GNULIB_UNLOCKPT = @GNULIB_UNLOCKPT@ +GNULIB_UNSETENV = @GNULIB_UNSETENV@ +GNULIB_USLEEP = @GNULIB_USLEEP@ +GNULIB_UTIMENSAT = @GNULIB_UTIMENSAT@ +GNULIB_VASPRINTF = @GNULIB_VASPRINTF@ +GNULIB_VDPRINTF = @GNULIB_VDPRINTF@ +GNULIB_VFPRINTF = @GNULIB_VFPRINTF@ +GNULIB_VFPRINTF_POSIX = @GNULIB_VFPRINTF_POSIX@ +GNULIB_VFSCANF = @GNULIB_VFSCANF@ +GNULIB_VPRINTF = @GNULIB_VPRINTF@ +GNULIB_VPRINTF_POSIX = @GNULIB_VPRINTF_POSIX@ +GNULIB_VSCANF = @GNULIB_VSCANF@ +GNULIB_VSNPRINTF = @GNULIB_VSNPRINTF@ +GNULIB_VSPRINTF_POSIX = @GNULIB_VSPRINTF_POSIX@ +GNULIB_WCPCPY = @GNULIB_WCPCPY@ +GNULIB_WCPNCPY = @GNULIB_WCPNCPY@ +GNULIB_WCRTOMB = @GNULIB_WCRTOMB@ +GNULIB_WCSCASECMP = @GNULIB_WCSCASECMP@ +GNULIB_WCSCAT = @GNULIB_WCSCAT@ +GNULIB_WCSCHR = @GNULIB_WCSCHR@ +GNULIB_WCSCMP = @GNULIB_WCSCMP@ +GNULIB_WCSCOLL = @GNULIB_WCSCOLL@ +GNULIB_WCSCPY = @GNULIB_WCSCPY@ +GNULIB_WCSCSPN = @GNULIB_WCSCSPN@ +GNULIB_WCSDUP = @GNULIB_WCSDUP@ +GNULIB_WCSLEN = @GNULIB_WCSLEN@ +GNULIB_WCSNCASECMP = @GNULIB_WCSNCASECMP@ +GNULIB_WCSNCAT = @GNULIB_WCSNCAT@ +GNULIB_WCSNCMP = @GNULIB_WCSNCMP@ +GNULIB_WCSNCPY = @GNULIB_WCSNCPY@ +GNULIB_WCSNLEN = @GNULIB_WCSNLEN@ +GNULIB_WCSNRTOMBS = @GNULIB_WCSNRTOMBS@ +GNULIB_WCSPBRK = @GNULIB_WCSPBRK@ +GNULIB_WCSRCHR = @GNULIB_WCSRCHR@ +GNULIB_WCSRTOMBS = @GNULIB_WCSRTOMBS@ +GNULIB_WCSSPN = @GNULIB_WCSSPN@ +GNULIB_WCSSTR = @GNULIB_WCSSTR@ +GNULIB_WCSTOK = @GNULIB_WCSTOK@ +GNULIB_WCSWIDTH = @GNULIB_WCSWIDTH@ +GNULIB_WCSXFRM = @GNULIB_WCSXFRM@ +GNULIB_WCTOB = @GNULIB_WCTOB@ +GNULIB_WCTOMB = @GNULIB_WCTOMB@ +GNULIB_WCTRANS = @GNULIB_WCTRANS@ +GNULIB_WCTYPE = @GNULIB_WCTYPE@ +GNULIB_WCWIDTH = @GNULIB_WCWIDTH@ +GNULIB_WMEMCHR = @GNULIB_WMEMCHR@ +GNULIB_WMEMCMP = @GNULIB_WMEMCMP@ +GNULIB_WMEMCPY = @GNULIB_WMEMCPY@ +GNULIB_WMEMMOVE = @GNULIB_WMEMMOVE@ +GNULIB_WMEMSET = @GNULIB_WMEMSET@ +GNULIB_WRITE = @GNULIB_WRITE@ +GNULIB__EXIT = @GNULIB__EXIT@ +GREP = @GREP@ +HAVE_ATOLL = @HAVE_ATOLL@ +HAVE_BTOWC = @HAVE_BTOWC@ +HAVE_CANONICALIZE_FILE_NAME = @HAVE_CANONICALIZE_FILE_NAME@ +HAVE_CHOWN = @HAVE_CHOWN@ +HAVE_DECL_ENVIRON = @HAVE_DECL_ENVIRON@ +HAVE_DECL_FCHDIR = @HAVE_DECL_FCHDIR@ +HAVE_DECL_FDATASYNC = @HAVE_DECL_FDATASYNC@ +HAVE_DECL_FPURGE = @HAVE_DECL_FPURGE@ +HAVE_DECL_FSEEKO = @HAVE_DECL_FSEEKO@ +HAVE_DECL_FTELLO = @HAVE_DECL_FTELLO@ +HAVE_DECL_GETDELIM = @HAVE_DECL_GETDELIM@ +HAVE_DECL_GETDOMAINNAME = @HAVE_DECL_GETDOMAINNAME@ +HAVE_DECL_GETLINE = @HAVE_DECL_GETLINE@ +HAVE_DECL_GETLOADAVG = @HAVE_DECL_GETLOADAVG@ +HAVE_DECL_GETLOGIN_R = @HAVE_DECL_GETLOGIN_R@ +HAVE_DECL_GETPAGESIZE = @HAVE_DECL_GETPAGESIZE@ +HAVE_DECL_GETUSERSHELL = @HAVE_DECL_GETUSERSHELL@ +HAVE_DECL_LOCALTIME_R = @HAVE_DECL_LOCALTIME_R@ +HAVE_DECL_MEMMEM = @HAVE_DECL_MEMMEM@ +HAVE_DECL_MEMRCHR = @HAVE_DECL_MEMRCHR@ +HAVE_DECL_OBSTACK_PRINTF = @HAVE_DECL_OBSTACK_PRINTF@ +HAVE_DECL_SETENV = @HAVE_DECL_SETENV@ +HAVE_DECL_SETHOSTNAME = @HAVE_DECL_SETHOSTNAME@ +HAVE_DECL_SNPRINTF = @HAVE_DECL_SNPRINTF@ +HAVE_DECL_STRDUP = @HAVE_DECL_STRDUP@ +HAVE_DECL_STRERROR_R = @HAVE_DECL_STRERROR_R@ +HAVE_DECL_STRNDUP = @HAVE_DECL_STRNDUP@ +HAVE_DECL_STRNLEN = @HAVE_DECL_STRNLEN@ +HAVE_DECL_STRSIGNAL = @HAVE_DECL_STRSIGNAL@ +HAVE_DECL_STRTOK_R = @HAVE_DECL_STRTOK_R@ +HAVE_DECL_TTYNAME_R = @HAVE_DECL_TTYNAME_R@ +HAVE_DECL_UNSETENV = @HAVE_DECL_UNSETENV@ +HAVE_DECL_VSNPRINTF = @HAVE_DECL_VSNPRINTF@ +HAVE_DECL_WCTOB = @HAVE_DECL_WCTOB@ +HAVE_DECL_WCWIDTH = @HAVE_DECL_WCWIDTH@ +HAVE_DPRINTF = @HAVE_DPRINTF@ +HAVE_DUP2 = @HAVE_DUP2@ +HAVE_DUP3 = @HAVE_DUP3@ +HAVE_DUPLOCALE = @HAVE_DUPLOCALE@ +HAVE_EUIDACCESS = @HAVE_EUIDACCESS@ +HAVE_FACCESSAT = @HAVE_FACCESSAT@ +HAVE_FCHDIR = @HAVE_FCHDIR@ +HAVE_FCHMODAT = @HAVE_FCHMODAT@ +HAVE_FCHOWNAT = @HAVE_FCHOWNAT@ +HAVE_FCNTL = @HAVE_FCNTL@ +HAVE_FDATASYNC = @HAVE_FDATASYNC@ +HAVE_FEATURES_H = @HAVE_FEATURES_H@ +HAVE_FFSL = @HAVE_FFSL@ +HAVE_FFSLL = @HAVE_FFSLL@ +HAVE_FSEEKO = @HAVE_FSEEKO@ +HAVE_FSTATAT = @HAVE_FSTATAT@ +HAVE_FSYNC = @HAVE_FSYNC@ +HAVE_FTELLO = @HAVE_FTELLO@ +HAVE_FTRUNCATE = @HAVE_FTRUNCATE@ +HAVE_FUTIMENS = @HAVE_FUTIMENS@ +HAVE_GETDTABLESIZE = @HAVE_GETDTABLESIZE@ +HAVE_GETGROUPS = @HAVE_GETGROUPS@ +HAVE_GETHOSTNAME = @HAVE_GETHOSTNAME@ +HAVE_GETLOGIN = @HAVE_GETLOGIN@ +HAVE_GETOPT_H = @HAVE_GETOPT_H@ +HAVE_GETPAGESIZE = @HAVE_GETPAGESIZE@ +HAVE_GETSUBOPT = @HAVE_GETSUBOPT@ +HAVE_GETTIMEOFDAY = @HAVE_GETTIMEOFDAY@ +HAVE_GRANTPT = @HAVE_GRANTPT@ +HAVE_GROUP_MEMBER = @HAVE_GROUP_MEMBER@ +HAVE_INTTYPES_H = @HAVE_INTTYPES_H@ +HAVE_ISWBLANK = @HAVE_ISWBLANK@ +HAVE_ISWCNTRL = @HAVE_ISWCNTRL@ +HAVE_LANGINFO_CODESET = @HAVE_LANGINFO_CODESET@ +HAVE_LANGINFO_ERA = @HAVE_LANGINFO_ERA@ +HAVE_LANGINFO_H = @HAVE_LANGINFO_H@ +HAVE_LANGINFO_T_FMT_AMPM = @HAVE_LANGINFO_T_FMT_AMPM@ +HAVE_LANGINFO_YESEXPR = @HAVE_LANGINFO_YESEXPR@ +HAVE_LCHMOD = @HAVE_LCHMOD@ +HAVE_LCHOWN = @HAVE_LCHOWN@ +HAVE_LINK = @HAVE_LINK@ +HAVE_LINKAT = @HAVE_LINKAT@ +HAVE_LONG_LONG_INT = @HAVE_LONG_LONG_INT@ +HAVE_LSTAT = @HAVE_LSTAT@ +HAVE_MBRLEN = @HAVE_MBRLEN@ +HAVE_MBRTOWC = @HAVE_MBRTOWC@ +HAVE_MBSINIT = @HAVE_MBSINIT@ +HAVE_MBSLEN = @HAVE_MBSLEN@ +HAVE_MBSNRTOWCS = @HAVE_MBSNRTOWCS@ +HAVE_MBSRTOWCS = @HAVE_MBSRTOWCS@ +HAVE_MEMCHR = @HAVE_MEMCHR@ +HAVE_MEMPCPY = @HAVE_MEMPCPY@ +HAVE_MKDIRAT = @HAVE_MKDIRAT@ +HAVE_MKDTEMP = @HAVE_MKDTEMP@ +HAVE_MKFIFO = @HAVE_MKFIFO@ +HAVE_MKFIFOAT = @HAVE_MKFIFOAT@ +HAVE_MKNOD = @HAVE_MKNOD@ +HAVE_MKNODAT = @HAVE_MKNODAT@ +HAVE_MKOSTEMP = @HAVE_MKOSTEMP@ +HAVE_MKOSTEMPS = @HAVE_MKOSTEMPS@ +HAVE_MKSTEMP = @HAVE_MKSTEMP@ +HAVE_MKSTEMPS = @HAVE_MKSTEMPS@ +HAVE_MSVC_INVALID_PARAMETER_HANDLER = @HAVE_MSVC_INVALID_PARAMETER_HANDLER@ +HAVE_NANOSLEEP = @HAVE_NANOSLEEP@ +HAVE_NL_LANGINFO = @HAVE_NL_LANGINFO@ +HAVE_OPENAT = @HAVE_OPENAT@ +HAVE_OS_H = @HAVE_OS_H@ +HAVE_PCLOSE = @HAVE_PCLOSE@ +HAVE_PIPE = @HAVE_PIPE@ +HAVE_PIPE2 = @HAVE_PIPE2@ +HAVE_POPEN = @HAVE_POPEN@ +HAVE_POSIX_OPENPT = @HAVE_POSIX_OPENPT@ +HAVE_PREAD = @HAVE_PREAD@ +HAVE_PTSNAME = @HAVE_PTSNAME@ +HAVE_PTSNAME_R = @HAVE_PTSNAME_R@ +HAVE_PWRITE = @HAVE_PWRITE@ +HAVE_RANDOM = @HAVE_RANDOM@ +HAVE_RANDOM_H = @HAVE_RANDOM_H@ +HAVE_RANDOM_R = @HAVE_RANDOM_R@ +HAVE_RAWMEMCHR = @HAVE_RAWMEMCHR@ +HAVE_READLINK = @HAVE_READLINK@ +HAVE_READLINKAT = @HAVE_READLINKAT@ +HAVE_REALPATH = @HAVE_REALPATH@ +HAVE_RENAMEAT = @HAVE_RENAMEAT@ +HAVE_RPMATCH = @HAVE_RPMATCH@ +HAVE_SETENV = @HAVE_SETENV@ +HAVE_SETHOSTNAME = @HAVE_SETHOSTNAME@ +HAVE_SIGNED_SIG_ATOMIC_T = @HAVE_SIGNED_SIG_ATOMIC_T@ +HAVE_SIGNED_WCHAR_T = @HAVE_SIGNED_WCHAR_T@ +HAVE_SIGNED_WINT_T = @HAVE_SIGNED_WINT_T@ +HAVE_SLEEP = @HAVE_SLEEP@ +HAVE_STDINT_H = @HAVE_STDINT_H@ +HAVE_STPCPY = @HAVE_STPCPY@ +HAVE_STPNCPY = @HAVE_STPNCPY@ +HAVE_STRCASESTR = @HAVE_STRCASESTR@ +HAVE_STRCHRNUL = @HAVE_STRCHRNUL@ +HAVE_STRPBRK = @HAVE_STRPBRK@ +HAVE_STRPTIME = @HAVE_STRPTIME@ +HAVE_STRSEP = @HAVE_STRSEP@ +HAVE_STRTOD = @HAVE_STRTOD@ +HAVE_STRTOLL = @HAVE_STRTOLL@ +HAVE_STRTOULL = @HAVE_STRTOULL@ +HAVE_STRUCT_RANDOM_DATA = @HAVE_STRUCT_RANDOM_DATA@ +HAVE_STRUCT_TIMEVAL = @HAVE_STRUCT_TIMEVAL@ +HAVE_STRVERSCMP = @HAVE_STRVERSCMP@ +HAVE_SYMLINK = @HAVE_SYMLINK@ +HAVE_SYMLINKAT = @HAVE_SYMLINKAT@ +HAVE_SYS_BITYPES_H = @HAVE_SYS_BITYPES_H@ +HAVE_SYS_INTTYPES_H = @HAVE_SYS_INTTYPES_H@ +HAVE_SYS_LOADAVG_H = @HAVE_SYS_LOADAVG_H@ +HAVE_SYS_PARAM_H = @HAVE_SYS_PARAM_H@ +HAVE_SYS_TIME_H = @HAVE_SYS_TIME_H@ +HAVE_SYS_TYPES_H = @HAVE_SYS_TYPES_H@ +HAVE_TIMEGM = @HAVE_TIMEGM@ +HAVE_UNISTD_H = @HAVE_UNISTD_H@ +HAVE_UNLINKAT = @HAVE_UNLINKAT@ +HAVE_UNLOCKPT = @HAVE_UNLOCKPT@ +HAVE_UNSIGNED_LONG_LONG_INT = @HAVE_UNSIGNED_LONG_LONG_INT@ +HAVE_USLEEP = @HAVE_USLEEP@ +HAVE_UTIMENSAT = @HAVE_UTIMENSAT@ +HAVE_VASPRINTF = @HAVE_VASPRINTF@ +HAVE_VDPRINTF = @HAVE_VDPRINTF@ +HAVE_WCHAR_H = @HAVE_WCHAR_H@ +HAVE_WCHAR_T = @HAVE_WCHAR_T@ +HAVE_WCPCPY = @HAVE_WCPCPY@ +HAVE_WCPNCPY = @HAVE_WCPNCPY@ +HAVE_WCRTOMB = @HAVE_WCRTOMB@ +HAVE_WCSCASECMP = @HAVE_WCSCASECMP@ +HAVE_WCSCAT = @HAVE_WCSCAT@ +HAVE_WCSCHR = @HAVE_WCSCHR@ +HAVE_WCSCMP = @HAVE_WCSCMP@ +HAVE_WCSCOLL = @HAVE_WCSCOLL@ +HAVE_WCSCPY = @HAVE_WCSCPY@ +HAVE_WCSCSPN = @HAVE_WCSCSPN@ +HAVE_WCSDUP = @HAVE_WCSDUP@ +HAVE_WCSLEN = @HAVE_WCSLEN@ +HAVE_WCSNCASECMP = @HAVE_WCSNCASECMP@ +HAVE_WCSNCAT = @HAVE_WCSNCAT@ +HAVE_WCSNCMP = @HAVE_WCSNCMP@ +HAVE_WCSNCPY = @HAVE_WCSNCPY@ +HAVE_WCSNLEN = @HAVE_WCSNLEN@ +HAVE_WCSNRTOMBS = @HAVE_WCSNRTOMBS@ +HAVE_WCSPBRK = @HAVE_WCSPBRK@ +HAVE_WCSRCHR = @HAVE_WCSRCHR@ +HAVE_WCSRTOMBS = @HAVE_WCSRTOMBS@ +HAVE_WCSSPN = @HAVE_WCSSPN@ +HAVE_WCSSTR = @HAVE_WCSSTR@ +HAVE_WCSTOK = @HAVE_WCSTOK@ +HAVE_WCSWIDTH = @HAVE_WCSWIDTH@ +HAVE_WCSXFRM = @HAVE_WCSXFRM@ +HAVE_WCTRANS_T = @HAVE_WCTRANS_T@ +HAVE_WCTYPE_H = @HAVE_WCTYPE_H@ +HAVE_WCTYPE_T = @HAVE_WCTYPE_T@ +HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ +HAVE_WINT_T = @HAVE_WINT_T@ +HAVE_WMEMCHR = @HAVE_WMEMCHR@ +HAVE_WMEMCMP = @HAVE_WMEMCMP@ +HAVE_WMEMCPY = @HAVE_WMEMCPY@ +HAVE_WMEMMOVE = @HAVE_WMEMMOVE@ +HAVE_WMEMSET = @HAVE_WMEMSET@ +HAVE_XLOCALE_H = @HAVE_XLOCALE_H@ +HAVE__BOOL = @HAVE__BOOL@ +HAVE__EXIT = @HAVE__EXIT@ +INCLUDE_NEXT = @INCLUDE_NEXT@ +INCLUDE_NEXT_AS_FIRST_DIRECTIVE = @INCLUDE_NEXT_AS_FIRST_DIRECTIVE@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBSED_LIBDEPS = @LIBSED_LIBDEPS@ +LIBSED_LTLIBDEPS = @LIBSED_LTLIBDEPS@ +LIB_ACL = @LIB_ACL@ +LIB_SELINUX = @LIB_SELINUX@ +LOCALCHARSET_TESTS_ENVIRONMENT = @LOCALCHARSET_TESTS_ENVIRONMENT@ +LOCALE_FR = @LOCALE_FR@ +LOCALE_FR_UTF8 = @LOCALE_FR_UTF8@ +LOCALE_JA = @LOCALE_JA@ +LOCALE_ZH_CN = @LOCALE_ZH_CN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NEXT_AS_FIRST_DIRECTIVE_ERRNO_H = @NEXT_AS_FIRST_DIRECTIVE_ERRNO_H@ +NEXT_AS_FIRST_DIRECTIVE_FCNTL_H = @NEXT_AS_FIRST_DIRECTIVE_FCNTL_H@ +NEXT_AS_FIRST_DIRECTIVE_GETOPT_H = @NEXT_AS_FIRST_DIRECTIVE_GETOPT_H@ +NEXT_AS_FIRST_DIRECTIVE_LANGINFO_H = @NEXT_AS_FIRST_DIRECTIVE_LANGINFO_H@ +NEXT_AS_FIRST_DIRECTIVE_LOCALE_H = @NEXT_AS_FIRST_DIRECTIVE_LOCALE_H@ +NEXT_AS_FIRST_DIRECTIVE_SELINUX_SELINUX_H = @NEXT_AS_FIRST_DIRECTIVE_SELINUX_SELINUX_H@ +NEXT_AS_FIRST_DIRECTIVE_STDARG_H = @NEXT_AS_FIRST_DIRECTIVE_STDARG_H@ +NEXT_AS_FIRST_DIRECTIVE_STDDEF_H = @NEXT_AS_FIRST_DIRECTIVE_STDDEF_H@ +NEXT_AS_FIRST_DIRECTIVE_STDINT_H = @NEXT_AS_FIRST_DIRECTIVE_STDINT_H@ +NEXT_AS_FIRST_DIRECTIVE_STDIO_H = @NEXT_AS_FIRST_DIRECTIVE_STDIO_H@ +NEXT_AS_FIRST_DIRECTIVE_STDLIB_H = @NEXT_AS_FIRST_DIRECTIVE_STDLIB_H@ +NEXT_AS_FIRST_DIRECTIVE_STRING_H = @NEXT_AS_FIRST_DIRECTIVE_STRING_H@ +NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H@ +NEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H@ +NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H@ +NEXT_AS_FIRST_DIRECTIVE_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_TIME_H@ +NEXT_AS_FIRST_DIRECTIVE_UNISTD_H = @NEXT_AS_FIRST_DIRECTIVE_UNISTD_H@ +NEXT_AS_FIRST_DIRECTIVE_WCHAR_H = @NEXT_AS_FIRST_DIRECTIVE_WCHAR_H@ +NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H = @NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H@ +NEXT_ERRNO_H = @NEXT_ERRNO_H@ +NEXT_FCNTL_H = @NEXT_FCNTL_H@ +NEXT_GETOPT_H = @NEXT_GETOPT_H@ +NEXT_LANGINFO_H = @NEXT_LANGINFO_H@ +NEXT_LOCALE_H = @NEXT_LOCALE_H@ +NEXT_SELINUX_SELINUX_H = @NEXT_SELINUX_SELINUX_H@ +NEXT_STDARG_H = @NEXT_STDARG_H@ +NEXT_STDDEF_H = @NEXT_STDDEF_H@ +NEXT_STDINT_H = @NEXT_STDINT_H@ +NEXT_STDIO_H = @NEXT_STDIO_H@ +NEXT_STDLIB_H = @NEXT_STDLIB_H@ +NEXT_STRING_H = @NEXT_STRING_H@ +NEXT_SYS_STAT_H = @NEXT_SYS_STAT_H@ +NEXT_SYS_TIME_H = @NEXT_SYS_TIME_H@ +NEXT_SYS_TYPES_H = @NEXT_SYS_TYPES_H@ +NEXT_TIME_H = @NEXT_TIME_H@ +NEXT_UNISTD_H = @NEXT_UNISTD_H@ +NEXT_WCHAR_H = @NEXT_WCHAR_H@ +NEXT_WCTYPE_H = @NEXT_WCTYPE_H@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSUB = @POSUB@ +PRAGMA_COLUMNS = @PRAGMA_COLUMNS@ +PRAGMA_SYSTEM_HEADER = @PRAGMA_SYSTEM_HEADER@ +PTHREAD_H_DEFINES_STRUCT_TIMESPEC = @PTHREAD_H_DEFINES_STRUCT_TIMESPEC@ +PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@ +RANLIB = @RANLIB@ +REPLACE_BTOWC = @REPLACE_BTOWC@ +REPLACE_CALLOC = @REPLACE_CALLOC@ +REPLACE_CANONICALIZE_FILE_NAME = @REPLACE_CANONICALIZE_FILE_NAME@ +REPLACE_CHOWN = @REPLACE_CHOWN@ +REPLACE_CLOSE = @REPLACE_CLOSE@ +REPLACE_DPRINTF = @REPLACE_DPRINTF@ +REPLACE_DUP = @REPLACE_DUP@ +REPLACE_DUP2 = @REPLACE_DUP2@ +REPLACE_DUPLOCALE = @REPLACE_DUPLOCALE@ +REPLACE_FCHOWNAT = @REPLACE_FCHOWNAT@ +REPLACE_FCLOSE = @REPLACE_FCLOSE@ +REPLACE_FCNTL = @REPLACE_FCNTL@ +REPLACE_FDOPEN = @REPLACE_FDOPEN@ +REPLACE_FFLUSH = @REPLACE_FFLUSH@ +REPLACE_FOPEN = @REPLACE_FOPEN@ +REPLACE_FPRINTF = @REPLACE_FPRINTF@ +REPLACE_FPURGE = @REPLACE_FPURGE@ +REPLACE_FREOPEN = @REPLACE_FREOPEN@ +REPLACE_FSEEK = @REPLACE_FSEEK@ +REPLACE_FSEEKO = @REPLACE_FSEEKO@ +REPLACE_FSTAT = @REPLACE_FSTAT@ +REPLACE_FSTATAT = @REPLACE_FSTATAT@ +REPLACE_FTELL = @REPLACE_FTELL@ +REPLACE_FTELLO = @REPLACE_FTELLO@ +REPLACE_FTRUNCATE = @REPLACE_FTRUNCATE@ +REPLACE_FUTIMENS = @REPLACE_FUTIMENS@ +REPLACE_GETCWD = @REPLACE_GETCWD@ +REPLACE_GETDELIM = @REPLACE_GETDELIM@ +REPLACE_GETDOMAINNAME = @REPLACE_GETDOMAINNAME@ +REPLACE_GETGROUPS = @REPLACE_GETGROUPS@ +REPLACE_GETLINE = @REPLACE_GETLINE@ +REPLACE_GETLOGIN_R = @REPLACE_GETLOGIN_R@ +REPLACE_GETPAGESIZE = @REPLACE_GETPAGESIZE@ +REPLACE_GETTIMEOFDAY = @REPLACE_GETTIMEOFDAY@ +REPLACE_ISATTY = @REPLACE_ISATTY@ +REPLACE_ISWBLANK = @REPLACE_ISWBLANK@ +REPLACE_ISWCNTRL = @REPLACE_ISWCNTRL@ +REPLACE_LCHOWN = @REPLACE_LCHOWN@ +REPLACE_LINK = @REPLACE_LINK@ +REPLACE_LINKAT = @REPLACE_LINKAT@ +REPLACE_LOCALECONV = @REPLACE_LOCALECONV@ +REPLACE_LOCALTIME_R = @REPLACE_LOCALTIME_R@ +REPLACE_LSEEK = @REPLACE_LSEEK@ +REPLACE_LSTAT = @REPLACE_LSTAT@ +REPLACE_MALLOC = @REPLACE_MALLOC@ +REPLACE_MBRLEN = @REPLACE_MBRLEN@ +REPLACE_MBRTOWC = @REPLACE_MBRTOWC@ +REPLACE_MBSINIT = @REPLACE_MBSINIT@ +REPLACE_MBSNRTOWCS = @REPLACE_MBSNRTOWCS@ +REPLACE_MBSRTOWCS = @REPLACE_MBSRTOWCS@ +REPLACE_MBSTATE_T = @REPLACE_MBSTATE_T@ +REPLACE_MBTOWC = @REPLACE_MBTOWC@ +REPLACE_MEMCHR = @REPLACE_MEMCHR@ +REPLACE_MEMMEM = @REPLACE_MEMMEM@ +REPLACE_MKDIR = @REPLACE_MKDIR@ +REPLACE_MKFIFO = @REPLACE_MKFIFO@ +REPLACE_MKNOD = @REPLACE_MKNOD@ +REPLACE_MKSTEMP = @REPLACE_MKSTEMP@ +REPLACE_MKTIME = @REPLACE_MKTIME@ +REPLACE_NANOSLEEP = @REPLACE_NANOSLEEP@ +REPLACE_NL_LANGINFO = @REPLACE_NL_LANGINFO@ +REPLACE_NULL = @REPLACE_NULL@ +REPLACE_OBSTACK_PRINTF = @REPLACE_OBSTACK_PRINTF@ +REPLACE_OPEN = @REPLACE_OPEN@ +REPLACE_OPENAT = @REPLACE_OPENAT@ +REPLACE_PERROR = @REPLACE_PERROR@ +REPLACE_POPEN = @REPLACE_POPEN@ +REPLACE_PREAD = @REPLACE_PREAD@ +REPLACE_PRINTF = @REPLACE_PRINTF@ +REPLACE_PTSNAME = @REPLACE_PTSNAME@ +REPLACE_PTSNAME_R = @REPLACE_PTSNAME_R@ +REPLACE_PUTENV = @REPLACE_PUTENV@ +REPLACE_PWRITE = @REPLACE_PWRITE@ +REPLACE_RANDOM_R = @REPLACE_RANDOM_R@ +REPLACE_READ = @REPLACE_READ@ +REPLACE_READLINK = @REPLACE_READLINK@ +REPLACE_REALLOC = @REPLACE_REALLOC@ +REPLACE_REALPATH = @REPLACE_REALPATH@ +REPLACE_REMOVE = @REPLACE_REMOVE@ +REPLACE_RENAME = @REPLACE_RENAME@ +REPLACE_RENAMEAT = @REPLACE_RENAMEAT@ +REPLACE_RMDIR = @REPLACE_RMDIR@ +REPLACE_SETENV = @REPLACE_SETENV@ +REPLACE_SETLOCALE = @REPLACE_SETLOCALE@ +REPLACE_SLEEP = @REPLACE_SLEEP@ +REPLACE_SNPRINTF = @REPLACE_SNPRINTF@ +REPLACE_SPRINTF = @REPLACE_SPRINTF@ +REPLACE_STAT = @REPLACE_STAT@ +REPLACE_STDIO_READ_FUNCS = @REPLACE_STDIO_READ_FUNCS@ +REPLACE_STDIO_WRITE_FUNCS = @REPLACE_STDIO_WRITE_FUNCS@ +REPLACE_STPNCPY = @REPLACE_STPNCPY@ +REPLACE_STRCASESTR = @REPLACE_STRCASESTR@ +REPLACE_STRCHRNUL = @REPLACE_STRCHRNUL@ +REPLACE_STRDUP = @REPLACE_STRDUP@ +REPLACE_STRERROR = @REPLACE_STRERROR@ +REPLACE_STRERROR_R = @REPLACE_STRERROR_R@ +REPLACE_STRNCAT = @REPLACE_STRNCAT@ +REPLACE_STRNDUP = @REPLACE_STRNDUP@ +REPLACE_STRNLEN = @REPLACE_STRNLEN@ +REPLACE_STRSIGNAL = @REPLACE_STRSIGNAL@ +REPLACE_STRSTR = @REPLACE_STRSTR@ +REPLACE_STRTOD = @REPLACE_STRTOD@ +REPLACE_STRTOK_R = @REPLACE_STRTOK_R@ +REPLACE_STRUCT_LCONV = @REPLACE_STRUCT_LCONV@ +REPLACE_STRUCT_TIMEVAL = @REPLACE_STRUCT_TIMEVAL@ +REPLACE_SYMLINK = @REPLACE_SYMLINK@ +REPLACE_TIMEGM = @REPLACE_TIMEGM@ +REPLACE_TMPFILE = @REPLACE_TMPFILE@ +REPLACE_TOWLOWER = @REPLACE_TOWLOWER@ +REPLACE_TTYNAME_R = @REPLACE_TTYNAME_R@ +REPLACE_UNLINK = @REPLACE_UNLINK@ +REPLACE_UNLINKAT = @REPLACE_UNLINKAT@ +REPLACE_UNSETENV = @REPLACE_UNSETENV@ +REPLACE_USLEEP = @REPLACE_USLEEP@ +REPLACE_UTIMENSAT = @REPLACE_UTIMENSAT@ +REPLACE_VASPRINTF = @REPLACE_VASPRINTF@ +REPLACE_VDPRINTF = @REPLACE_VDPRINTF@ +REPLACE_VFPRINTF = @REPLACE_VFPRINTF@ +REPLACE_VPRINTF = @REPLACE_VPRINTF@ +REPLACE_VSNPRINTF = @REPLACE_VSNPRINTF@ +REPLACE_VSPRINTF = @REPLACE_VSPRINTF@ +REPLACE_WCRTOMB = @REPLACE_WCRTOMB@ +REPLACE_WCSNRTOMBS = @REPLACE_WCSNRTOMBS@ +REPLACE_WCSRTOMBS = @REPLACE_WCSRTOMBS@ +REPLACE_WCSWIDTH = @REPLACE_WCSWIDTH@ +REPLACE_WCTOB = @REPLACE_WCTOB@ +REPLACE_WCTOMB = @REPLACE_WCTOMB@ +REPLACE_WCWIDTH = @REPLACE_WCWIDTH@ +REPLACE_WRITE = @REPLACE_WRITE@ +SED_FEATURE_VERSION = @SED_FEATURE_VERSION@ +SELINUX_CONTEXT_H = @SELINUX_CONTEXT_H@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIG_ATOMIC_T_SUFFIX = @SIG_ATOMIC_T_SUFFIX@ +SIZE_T_SUFFIX = @SIZE_T_SUFFIX@ +STDARG_H = @STDARG_H@ +STDBOOL_H = @STDBOOL_H@ +STDDEF_H = @STDDEF_H@ +STDINT_H = @STDINT_H@ +STRIP = @STRIP@ +SYS_TIME_H_DEFINES_STRUCT_TIMESPEC = @SYS_TIME_H_DEFINES_STRUCT_TIMESPEC@ +TIME_H_DEFINES_STRUCT_TIMESPEC = @TIME_H_DEFINES_STRUCT_TIMESPEC@ +UNDEFINE_STRTOK_R = @UNDEFINE_STRTOK_R@ +UNISTD_H_HAVE_WINSOCK2_H = @UNISTD_H_HAVE_WINSOCK2_H@ +UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS = @UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@ +USE_ACL = @USE_ACL@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WCHAR_T_SUFFIX = @WCHAR_T_SUFFIX@ +WINDOWS_64_BIT_OFF_T = @WINDOWS_64_BIT_OFF_T@ +WINDOWS_64_BIT_ST_SIZE = @WINDOWS_64_BIT_ST_SIZE@ +WINT_T_SUFFIX = @WINT_T_SUFFIX@ +XFAIL_TESTS = @XFAIL_TESTS@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gl_LIBOBJS = @gl_LIBOBJS@ +gl_LTLIBOBJS = @gl_LTLIBOBJS@ +gltests_LIBOBJS = @gltests_LIBOBJS@ +gltests_LTLIBOBJS = @gltests_LTLIBOBJS@ +gltests_WITNESS = @gltests_WITNESS@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +lispdir = @lispdir@ +localedir = $(datadir)/locale +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +sed_SOURCES = sed.c compile.c execute.c regexp.c fmt.c mbcs.c utils.c +noinst_HEADERS = sed.h utils.h +AM_CPPFLAGS = -I$(top_srcdir)/lib -I$(top_srcdir) -I$(top_builddir)/lib \ + -DLOCALEDIR=\"$(localedir)\" + +sed_LDADD = ../lib/libsed.a @INTLLIBS@ @LIB_ACL@ @LIB_SELINUX@ +sed_DEPENDENCIES = ../lib/libsed.a +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits sed/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnits sed/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +installcheck-binPROGRAMS: $(bin_PROGRAMS) + bad=0; pid=$$$$; list="$(bin_PROGRAMS)"; for p in $$list; do \ + case ' $(AM_INSTALLCHECK_STD_OPTIONS_EXEMPT) ' in \ + *" $$p "* | *" $(srcdir)/$$p "*) continue;; \ + esac; \ + f=`echo "$$p" | \ + sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + for opt in --help --version; do \ + if "$(DESTDIR)$(bindir)/$$f" $$opt >c$${pid}_.out \ + 2>c$${pid}_.err </dev/null \ + && test -n "`cat c$${pid}_.out`" \ + && test -z "`cat c$${pid}_.err`"; then :; \ + else echo "$$f does not support $$opt" 1>&2; bad=1; fi; \ + done; \ + done; rm -f c$${pid}_.???; exit $$bad +sed$(EXEEXT): $(sed_OBJECTS) $(sed_DEPENDENCIES) $(EXTRA_sed_DEPENDENCIES) + @rm -f sed$(EXEEXT) + $(LINK) $(sed_OBJECTS) $(sed_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compile.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/execute.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fmt.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mbcs.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regexp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sed.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +cscopelist: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: installcheck-binPROGRAMS + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic cscopelist ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installcheck-binPROGRAMS \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic pdf pdf-am \ + ps ps-am tags uninstall uninstall-am uninstall-binPROGRAMS + + +$(PROGRAMS): $(LDADD) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sed/compile.c b/sed/compile.c new file mode 100644 index 0000000..513fac5 --- /dev/null +++ b/sed/compile.c @@ -0,0 +1,1734 @@ +/* GNU SED, a batch stream editor. + Copyright (C) 1989,90,91,92,93,94,95,98,99,2002,2003,2004,2005,2006,2008,2010 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* compile.c: translate sed source into internal form */ + +#include "sed.h" +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> +#include <obstack.h> + + +#define YMAP_LENGTH 256 /*XXX shouldn't this be (UCHAR_MAX+1)?*/ +#define VECTOR_ALLOC_INCREMENT 40 + +/* let's not confuse text editors that have only dumb bracket-matching... */ +#define OPEN_BRACKET '[' +#define CLOSE_BRACKET ']' +#define OPEN_BRACE '{' +#define CLOSE_BRACE '}' + +struct prog_info { + /* When we're reading a script command from a string, `prog.base' + points to the first character in the string, 'prog.cur' points + to the current character in the string, and 'prog.end' points + to the end of the string. This allows us to compile script + strings that contain nulls. */ + const unsigned char *base; + const unsigned char *cur; + const unsigned char *end; + + /* This is the current script file. If it is NULL, we are reading + from a string stored at `prog.cur' instead. If both `prog.file' + and `prog.cur' are NULL, we're in trouble! */ + FILE *file; +}; + +/* Information used to give out useful and informative error messages. */ +struct error_info { + /* This is the name of the current script file. */ + const char *name; + + /* This is the number of the current script line that we're compiling. */ + countT line; + + /* This is the index of the "-e" expressions on the command line. */ + countT string_expr_count; +}; + + +/* Label structure used to resolve GOTO's, labels, and block beginnings. */ +struct sed_label { + countT v_index; /* index of vector element being referenced */ + char *name; /* NUL-terminated name of the label */ + struct error_info err_info; /* track where `{}' blocks start */ + struct sed_label *next; /* linked list (stack) */ +}; + +struct special_files { + struct output outf; + FILE **pfp; +}; + +FILE *my_stdin, *my_stdout, *my_stderr; +struct special_files special_files[] = { + { { "/dev/stdin", false, NULL, NULL }, &my_stdin }, + { { "/dev/stdout", false, NULL, NULL }, &my_stdout }, + { { "/dev/stderr", false, NULL, NULL }, &my_stderr }, + { { NULL, false, NULL, NULL }, NULL } +}; + + +/* Where we are in the processing of the input. */ +static struct prog_info prog; +static struct error_info cur_input; + +/* Information about labels and jumps-to-labels. This is used to do + the required backpatching after we have compiled all the scripts. */ +static struct sed_label *jumps = NULL; +static struct sed_label *labels = NULL; + +/* We wish to detect #n magic only in the first input argument; + this flag tracks when we have consumed the first file of input. */ +static bool first_script = true; + +/* Allow for scripts like "sed -e 'i\' -e foo": */ +static struct buffer *pending_text = NULL; +static struct text_buf *old_text_buf = NULL; + +/* Information about block start positions. This is used to backpatch + block end positions. */ +static struct sed_label *blocks = NULL; + +/* Use an obstack for compilation. */ +static struct obstack obs; + +/* Various error messages we may want to print */ +static const char errors[] = + "multiple `!'s\0" + "unexpected `,'\0" + "invalid usage of +N or ~N as first address\0" + "unmatched `{'\0" + "unexpected `}'\0" + "extra characters after command\0" + "expected \\ after `a', `c' or `i'\0" + "`}' doesn't want any addresses\0" + ": doesn't want any addresses\0" + "comments don't accept any addresses\0" + "missing command\0" + "command only uses one address\0" + "unterminated address regex\0" + "unterminated `s' command\0" + "unterminated `y' command\0" + "unknown option to `s'\0" + "multiple `p' options to `s' command\0" + "multiple `g' options to `s' command\0" + "multiple number options to `s' command\0" + "number option to `s' command may not be zero\0" + "strings for `y' command are different lengths\0" + "delimiter character is not a single-byte character\0" + "expected newer version of sed\0" + "invalid usage of line address 0\0" + "unknown command: `%c'\0" + "incomplete command"; + +#define BAD_BANG (errors) +#define BAD_COMMA (BAD_BANG + sizeof(N_("multiple `!'s"))) +#define BAD_STEP (BAD_COMMA + sizeof(N_("unexpected `,'"))) +#define EXCESS_OPEN_BRACE (BAD_STEP + sizeof(N_("invalid usage of +N or ~N as first address"))) +#define EXCESS_CLOSE_BRACE (EXCESS_OPEN_BRACE + sizeof(N_("unmatched `{'"))) +#define EXCESS_JUNK (EXCESS_CLOSE_BRACE + sizeof(N_("unexpected `}'"))) +#define EXPECTED_SLASH (EXCESS_JUNK + sizeof(N_("extra characters after command"))) +#define NO_CLOSE_BRACE_ADDR (EXPECTED_SLASH + sizeof(N_("expected \\ after `a', `c' or `i'"))) +#define NO_COLON_ADDR (NO_CLOSE_BRACE_ADDR + sizeof(N_("`}' doesn't want any addresses"))) +#define NO_SHARP_ADDR (NO_COLON_ADDR + sizeof(N_(": doesn't want any addresses"))) +#define NO_COMMAND (NO_SHARP_ADDR + sizeof(N_("comments don't accept any addresses"))) +#define ONE_ADDR (NO_COMMAND + sizeof(N_("missing command"))) +#define UNTERM_ADDR_RE (ONE_ADDR + sizeof(N_("command only uses one address"))) +#define UNTERM_S_CMD (UNTERM_ADDR_RE + sizeof(N_("unterminated address regex"))) +#define UNTERM_Y_CMD (UNTERM_S_CMD + sizeof(N_("unterminated `s' command"))) +#define UNKNOWN_S_OPT (UNTERM_Y_CMD + sizeof(N_("unterminated `y' command"))) +#define EXCESS_P_OPT (UNKNOWN_S_OPT + sizeof(N_("unknown option to `s'"))) +#define EXCESS_G_OPT (EXCESS_P_OPT + sizeof(N_("multiple `p' options to `s' command"))) +#define EXCESS_N_OPT (EXCESS_G_OPT + sizeof(N_("multiple `g' options to `s' command"))) +#define ZERO_N_OPT (EXCESS_N_OPT + sizeof(N_("multiple number options to `s' command"))) +#define Y_CMD_LEN (ZERO_N_OPT + sizeof(N_("number option to `s' command may not be zero"))) +#define BAD_DELIM (Y_CMD_LEN + sizeof(N_("strings for `y' command are different lengths"))) +#define ANCIENT_VERSION (BAD_DELIM + sizeof(N_("delimiter character is not a single-byte character"))) +#define INVALID_LINE_0 (ANCIENT_VERSION + sizeof(N_("expected newer version of sed"))) +#define UNKNOWN_CMD (INVALID_LINE_0 + sizeof(N_("invalid usage of line address 0"))) +#define INCOMPLETE_CMD (UNKNOWN_CMD + sizeof(N_("unknown command: `%c'"))) +#define END_ERRORS (INCOMPLETE_CMD + sizeof(N_("incomplete command"))) + +static struct output *file_read = NULL; +static struct output *file_write = NULL; + + +/* Complain about an unknown command and exit. */ +void +bad_command(ch) + char ch; +{ + const char *msg = _(UNKNOWN_CMD); + char *unknown_cmd = xmalloc(strlen(msg)); + sprintf(unknown_cmd, msg, ch); + bad_prog(unknown_cmd); +} + +/* Complain about a programming error and exit. */ +void +bad_prog(why) + const char *why; +{ + if (cur_input.name) + fprintf(stderr, _("%s: file %s line %lu: %s\n"), + myname, cur_input.name, (unsigned long)cur_input.line, why); + else + fprintf(stderr, _("%s: -e expression #%lu, char %lu: %s\n"), + myname, + (unsigned long)cur_input.string_expr_count, + (unsigned long)(prog.cur-prog.base), + why); + exit(EXIT_FAILURE); +} + + +/* Read the next character from the program. Return EOF if there isn't + anything to read. Keep cur_input.line up to date, so error messages + can be meaningful. */ +static int inchar (void); +static int +inchar() +{ + int ch = EOF; + + if (prog.cur) + { + if (prog.cur < prog.end) + ch = *prog.cur++; + } + else if (prog.file) + { + if (!feof(prog.file)) + ch = getc(prog.file); + } + if (ch == '\n') + ++cur_input.line; + return ch; +} + +/* unget `ch' so the next call to inchar will return it. */ +static void savchar (int ch); +static void +savchar(ch) + int ch; +{ + if (ch == EOF) + return; + if (ch == '\n' && cur_input.line > 0) + --cur_input.line; + if (prog.cur) + { + if (prog.cur <= prog.base || *--prog.cur != ch) + panic("Called savchar() with unexpected pushback (%x)", + (unsigned char)ch); + } + else + ungetc(ch, prog.file); +} + +/* Read the next non-blank character from the program. */ +static int in_nonblank (void); +static int +in_nonblank() +{ + int ch; + do + ch = inchar(); + while (ISBLANK(ch)); + return ch; +} + +/* Read an integer value from the program. */ +static countT in_integer (int ch); +static countT +in_integer(ch) + int ch; +{ + countT num = 0; + + while (ISDIGIT(ch)) + { + num = num * 10 + ch - '0'; + ch = inchar(); + } + savchar(ch); + return num; +} + +static int add_then_next (struct buffer *b, int ch); +static int +add_then_next(b, ch) + struct buffer *b; + int ch; +{ + add1_buffer(b, ch); + return inchar(); +} + +static char * convert_number (char *, char *, const char *, int); +static char * +convert_number(result, buf, bufend, base) + char *result; + char *buf; + const char *bufend; + int base; +{ + int n = 0; + int max = 1; + char *p; + + for (p=buf+1; p < bufend && max <= 255; ++p, max *= base) + { + int d = -1; + switch (*p) + { + case '0': d = 0x0; break; + case '1': d = 0x1; break; + case '2': d = 0x2; break; + case '3': d = 0x3; break; + case '4': d = 0x4; break; + case '5': d = 0x5; break; + case '6': d = 0x6; break; + case '7': d = 0x7; break; + case '8': d = 0x8; break; + case '9': d = 0x9; break; + case 'A': case 'a': d = 0xa; break; + case 'B': case 'b': d = 0xb; break; + case 'C': case 'c': d = 0xc; break; + case 'D': case 'd': d = 0xd; break; + case 'E': case 'e': d = 0xe; break; + case 'F': case 'f': d = 0xf; break; + } + if (d < 0 || base <= d) + break; + n = n * base + d; + } + if (p == buf+1) + *result = *buf; + else + *result = n; + return p; +} + + +/* Read in a filename for a `r', `w', or `s///w' command. */ +static struct buffer *read_filename (void); +static struct buffer * +read_filename() +{ + struct buffer *b; + int ch; + + b = init_buffer(); + ch = in_nonblank(); + while (ch != EOF && ch != '\n') + { +#if 0 /*XXX ZZZ 1998-09-12 kpp: added, then had second thoughts*/ + if (posixicity == POSIXLY_EXTENDED) + if (ch == ';' || ch == '#') + { + savchar(ch); + break; + } +#endif + ch = add_then_next(b, ch); + } + add1_buffer(b, '\0'); + return b; +} + +static struct output *get_openfile (struct output **file_ptrs, const char *mode, int fail); +static struct output * +get_openfile(file_ptrs, mode, fail) + struct output **file_ptrs; + const char *mode; + int fail; +{ + struct buffer *b; + char *file_name; + struct output *p; + + b = read_filename(); + file_name = get_buffer(b); + for (p=*file_ptrs; p; p=p->link) + if (strcmp(p->name, file_name) == 0) + break; + + if (posixicity == POSIXLY_EXTENDED) + { + /* Check whether it is a special file (stdin, stdout or stderr) */ + struct special_files *special = special_files; + + /* std* sometimes are not constants, so they + cannot be used in the initializer for special_files */ + my_stdin = stdin; my_stdout = stdout; my_stderr = stderr; + for (special = special_files; special->outf.name; special++) + if (strcmp(special->outf.name, file_name) == 0) + { + special->outf.fp = *special->pfp; + free_buffer (b); + return &special->outf; + } + } + + if (!p) + { + p = OB_MALLOC(&obs, 1, struct output); + p->name = ck_strdup(file_name); + p->fp = ck_fopen(p->name, mode, fail); + p->missing_newline = false; + p->link = *file_ptrs; + *file_ptrs = p; + } + free_buffer(b); + return p; +} + + +static struct sed_cmd *next_cmd_entry (struct vector **vectorp); +static struct sed_cmd * +next_cmd_entry(vectorp) + struct vector **vectorp; +{ + struct sed_cmd *cmd; + struct vector *v; + + v = *vectorp; + if (v->v_length == v->v_allocated) + { + v->v_allocated += VECTOR_ALLOC_INCREMENT; + v->v = REALLOC(v->v, v->v_allocated, struct sed_cmd); + } + + cmd = v->v + v->v_length; + cmd->a1 = NULL; + cmd->a2 = NULL; + cmd->range_state = RANGE_INACTIVE; + cmd->addr_bang = false; + cmd->cmd = '\0'; /* something invalid, to catch bugs early */ + + *vectorp = v; + return cmd; +} + +static int snarf_char_class (struct buffer *b, mbstate_t *cur_stat); +static int +snarf_char_class(b, cur_stat) + struct buffer *b; + mbstate_t *cur_stat; +{ + int ch; + int state = 0; + int delim; + bool pending_mb = 0; + + ch = inchar(); + if (ch == '^') + ch = add_then_next(b, ch); + if (ch == CLOSE_BRACKET) + ch = add_then_next(b, ch); + + /* States are: + 0 outside a collation element, character class or collation class + 1 after the bracket + 2 after the opening ./:/= + 3 after the closing ./:/= */ + + for (;; ch = add_then_next (b, ch)) + { + pending_mb = BRLEN (ch, cur_stat) != 1; + + switch (ch) + { + case EOF: + case '\n': + return ch; + + case '.': + case ':': + case '=': + if (pending_mb) + continue; + + if (state == 1) + { + delim = ch; + state = 2; + } + else if (state == 2 && ch == delim) + state = 3; + else + break; + + continue; + + case OPEN_BRACKET: + if (pending_mb) + continue; + + if (state == 0) + state = 1; + continue; + + case CLOSE_BRACKET: + if (pending_mb) + continue; + + if (state == 0 || state == 1) + return ch; + else if (state == 3) + state = 0; + + break; + + default: + break; + } + + /* Getting a character different from .=: whilst in state 1 + goes back to state 0, getting a character different from ] + whilst in state 3 goes back to state 2. */ + state &= ~1; + } +} + +static struct buffer *match_slash (int slash, int regex); +static struct buffer * +match_slash(slash, regex) + int slash; + int regex; +{ + struct buffer *b; + int ch; + mbstate_t cur_stat; + + memset (&cur_stat, 0, sizeof (mbstate_t)); + + /* We allow only 1 byte characters for a slash. */ + if (BRLEN (slash, &cur_stat) == -2) + bad_prog (BAD_DELIM); + + memset (&cur_stat, 0, sizeof (mbstate_t)); + + b = init_buffer(); + while ((ch = inchar()) != EOF && ch != '\n') + { + bool pending_mb = !MBSINIT (&cur_stat); + if (BRLEN (ch, &cur_stat) == 1 && !pending_mb) + { + if (ch == slash) + return b; + else if (ch == '\\') + { + ch = inchar(); + if (ch == EOF) + break; +#ifndef REG_PERL + else if (ch == 'n' && regex) + ch = '\n'; +#endif + else if (ch != '\n' && (ch != slash || (!regex && ch == '&'))) + add1_buffer(b, '\\'); + } + else if (ch == OPEN_BRACKET && regex) + { + add1_buffer(b, ch); + ch = snarf_char_class(b, &cur_stat); + if (ch != CLOSE_BRACKET) + break; + } + } + + add1_buffer(b, ch); + } + + if (ch == '\n') + savchar(ch); /* for proper line number in error report */ + free_buffer(b); + return NULL; +} + +static int mark_subst_opts (struct subst *cmd); +static int +mark_subst_opts(cmd) + struct subst *cmd; +{ + int flags = 0; + int ch; + + cmd->global = false; + cmd->print = false; + cmd->eval = false; + cmd->numb = 0; + cmd->outf = NULL; + + for (;;) + switch ( (ch = in_nonblank()) ) + { + case 'i': /* GNU extension */ + case 'I': /* GNU extension */ + if (posixicity == POSIXLY_BASIC) + bad_prog(_(UNKNOWN_S_OPT)); + flags |= REG_ICASE; + break; + +#ifdef REG_PERL + case 's': /* GNU extension */ + case 'S': /* GNU extension */ + if (posixicity == POSIXLY_BASIC) + bad_prog(_(UNKNOWN_S_OPT)); + if (extended_regexp_flags & REG_PERL) + flags |= REG_DOTALL; + break; + + case 'x': /* GNU extension */ + case 'X': /* GNU extension */ + if (posixicity == POSIXLY_BASIC) + bad_prog(_(UNKNOWN_S_OPT)); + if (extended_regexp_flags & REG_PERL) + flags |= REG_EXTENDED; + break; +#endif + + case 'm': /* GNU extension */ + case 'M': /* GNU extension */ + if (posixicity == POSIXLY_BASIC) + bad_prog(_(UNKNOWN_S_OPT)); + flags |= REG_NEWLINE; + break; + + case 'e': + cmd->eval = true; + break; + + case 'p': + if (cmd->print) + bad_prog(_(EXCESS_P_OPT)); + cmd->print |= (1 << cmd->eval); /* 1=before eval, 2=after */ + break; + + case 'g': + if (cmd->global) + bad_prog(_(EXCESS_G_OPT)); + cmd->global = true; + break; + + case 'w': + cmd->outf = get_openfile(&file_write, write_mode, true); + return flags; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (cmd->numb) + bad_prog(_(EXCESS_N_OPT)); + cmd->numb = in_integer(ch); + if (!cmd->numb) + bad_prog(_(ZERO_N_OPT)); + break; + + case CLOSE_BRACE: + case '#': + savchar(ch); + /* Fall Through */ + case EOF: + case '\n': + case ';': + return flags; + + case '\r': + if (inchar() == '\n') + return flags; + /* FALLTHROUGH */ + + default: + bad_prog(_(UNKNOWN_S_OPT)); + /*NOTREACHED*/ + } +} + + +/* read in a label for a `:', `b', or `t' command */ +static char *read_label (void); +static char * +read_label() +{ + struct buffer *b; + int ch; + char *ret; + + b = init_buffer(); + ch = in_nonblank(); + + while (ch != EOF && ch != '\n' + && !ISBLANK(ch) && ch != ';' && ch != CLOSE_BRACE && ch != '#') + ch = add_then_next (b, ch); + + savchar(ch); + add1_buffer(b, '\0'); + ret = ck_strdup(get_buffer(b)); + free_buffer(b); + return ret; +} + +/* Store a label (or label reference) created by a `:', `b', or `t' + command so that the jump to/from the label can be backpatched after + compilation is complete, or a reference created by a `{' to be + backpatched when the corresponding `}' is found. */ +static struct sed_label *setup_label + (struct sed_label *, countT, char *, const struct error_info *); +static struct sed_label * +setup_label(list, idx, name, err_info) + struct sed_label *list; + countT idx; + char *name; + const struct error_info *err_info; +{ + struct sed_label *ret = OB_MALLOC(&obs, 1, struct sed_label); + ret->v_index = idx; + ret->name = name; + if (err_info) + memcpy(&ret->err_info, err_info, sizeof (ret->err_info)); + ret->next = list; + return ret; +} + +static struct sed_label *release_label (struct sed_label *list_head); +static struct sed_label * +release_label(list_head) + struct sed_label *list_head; +{ + struct sed_label *ret; + + if (!list_head) + return NULL; + ret = list_head->next; + + free(list_head->name); + +#if 0 + /* We use obstacks */ + free(list_head); +#endif + return ret; +} + +static struct replacement * +new_replacement(char *text, size_t length, enum replacement_types type) +{ + struct replacement *r = OB_MALLOC(&obs, 1, struct replacement); + + r->prefix = text; + r->prefix_length = length; + r->subst_id = -1; + r->repl_type = type; + + /* r-> next = NULL; */ + return r; +} + +static void setup_replacement (struct subst *, const char *, size_t); +static void +setup_replacement(sub, text, length) + struct subst *sub; + const char *text; + size_t length; +{ + char *base; + char *p; + char *text_end; + enum replacement_types repl_type = REPL_ASIS, save_type = REPL_ASIS; + struct replacement root; + struct replacement *tail; + + sub->max_id = 0; + base = MEMDUP(text, length, char); + length = normalize_text(base, length, TEXT_REPLACEMENT); + + text_end = base + length; + tail = &root; + + for (p=base; p<text_end; ++p) + { + if (*p == '\\') + { + /* Preceding the backslash may be some literal text: */ + tail = tail->next = + new_replacement(base, (size_t)(p - base), repl_type); + + repl_type = save_type; + + /* Skip the backslash and look for a numeric back-reference, + or a case-munging escape if not in POSIX mode: */ + ++p; + if (p == text_end) + ++tail->prefix_length; + + else if (posixicity == POSIXLY_BASIC && !ISDIGIT (*p)) + { + p[-1] = *p; + ++tail->prefix_length; + } + + else + switch (*p) + { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + tail->subst_id = *p - '0'; + if (sub->max_id < tail->subst_id) + sub->max_id = tail->subst_id; + break; + + case 'L': + repl_type = REPL_LOWERCASE; + save_type = REPL_LOWERCASE; + break; + + case 'U': + repl_type = REPL_UPPERCASE; + save_type = REPL_UPPERCASE; + break; + + case 'E': + repl_type = REPL_ASIS; + save_type = REPL_ASIS; + break; + + case 'l': + save_type = repl_type; + repl_type |= REPL_LOWERCASE_FIRST; + break; + + case 'u': + save_type = repl_type; + repl_type |= REPL_UPPERCASE_FIRST; + break; + + default: + p[-1] = *p; + ++tail->prefix_length; + } + + base = p + 1; + } + else if (*p == '&') + { + /* Preceding the ampersand may be some literal text: */ + tail = tail->next = + new_replacement(base, (size_t)(p - base), repl_type); + + repl_type = save_type; + tail->subst_id = 0; + base = p + 1; + } + } + /* There may be some trailing literal text: */ + if (base < text_end) + tail = tail->next = + new_replacement(base, (size_t)(text_end - base), repl_type); + + tail->next = NULL; + sub->replacement = root.next; +} + +static void read_text (struct text_buf *buf, int leadin_ch); +static void +read_text(buf, leadin_ch) + struct text_buf *buf; + int leadin_ch; +{ + int ch; + + /* Should we start afresh (as opposed to continue a partial text)? */ + if (buf) + { + if (pending_text) + free_buffer(pending_text); + pending_text = init_buffer(); + buf->text = NULL; + buf->text_length = 0; + old_text_buf = buf; + } + /* assert(old_text_buf != NULL); */ + + if (leadin_ch == EOF) + return; + + if (leadin_ch != '\n') + add1_buffer(pending_text, leadin_ch); + + ch = inchar(); + while (ch != EOF && ch != '\n') + { + if (ch == '\\') + { + ch = inchar(); + if (ch != EOF) + add1_buffer (pending_text, '\\'); + } + + if (ch == EOF) + { + add1_buffer (pending_text, '\n'); + return; + } + + ch = add_then_next (pending_text, ch); + } + + add1_buffer(pending_text, '\n'); + if (!buf) + buf = old_text_buf; + buf->text_length = normalize_text (get_buffer (pending_text), + size_buffer (pending_text), TEXT_BUFFER); + buf->text = MEMDUP(get_buffer(pending_text), buf->text_length, char); + free_buffer(pending_text); + pending_text = NULL; +} + + +/* Try to read an address for a sed command. If it succeeds, + return non-zero and store the resulting address in `*addr'. + If the input doesn't look like an address read nothing + and return zero. */ +static bool compile_address (struct addr *addr, int ch); +static bool +compile_address(addr, ch) + struct addr *addr; + int ch; +{ + addr->addr_type = ADDR_IS_NULL; + addr->addr_step = 0; + addr->addr_number = ~(countT)0; /* extremely unlikely to ever match */ + addr->addr_regex = NULL; + + if (ch == '/' || ch == '\\') + { + int flags = 0; + struct buffer *b; + addr->addr_type = ADDR_IS_REGEX; + if (ch == '\\') + ch = inchar(); + if ( !(b = match_slash(ch, true)) ) + bad_prog(_(UNTERM_ADDR_RE)); + + for(;;) + { + ch = in_nonblank(); + if (posixicity == POSIXLY_BASIC) + goto posix_address_modifier; + switch(ch) + { + case 'I': /* GNU extension */ + flags |= REG_ICASE; + break; + +#ifdef REG_PERL + case 'S': /* GNU extension */ + if (extended_regexp_flags & REG_PERL) + flags |= REG_DOTALL; + break; + + case 'X': /* GNU extension */ + if (extended_regexp_flags & REG_PERL) + flags |= REG_EXTENDED; + break; +#endif + + case 'M': /* GNU extension */ + flags |= REG_NEWLINE; + break; + + default: + posix_address_modifier: + savchar (ch); + addr->addr_regex = compile_regex (b, flags, 0); + free_buffer(b); + return true; + } + } + } + else if (ISDIGIT(ch)) + { + addr->addr_number = in_integer(ch); + addr->addr_type = ADDR_IS_NUM; + ch = in_nonblank(); + if (ch != '~' || posixicity == POSIXLY_BASIC) + { + savchar(ch); + } + else + { + countT step = in_integer(in_nonblank()); + if (step > 0) + { + addr->addr_step = step; + addr->addr_type = ADDR_IS_NUM_MOD; + } + } + } + else if ((ch == '+' || ch == '~') && posixicity != POSIXLY_BASIC) + { + addr->addr_step = in_integer(in_nonblank()); + if (addr->addr_step==0) + ; /* default to ADDR_IS_NULL; forces matching to stop on next line */ + else if (ch == '+') + addr->addr_type = ADDR_IS_STEP; + else + addr->addr_type = ADDR_IS_STEP_MOD; + } + else if (ch == '$') + { + addr->addr_type = ADDR_IS_LAST; + } + else + return false; + + return true; +} + +/* Read a program (or a subprogram within `{' `}' pairs) in and store + the compiled form in `*vector'. Return a pointer to the new vector. */ +static struct vector *compile_program (struct vector *); +static struct vector * +compile_program(vector) + struct vector *vector; +{ + struct sed_cmd *cur_cmd; + struct buffer *b; + int ch; + + if (!vector) + { + vector = MALLOC(1, struct vector); + vector->v = NULL; + vector->v_allocated = 0; + vector->v_length = 0; + + obstack_init (&obs); + } + if (pending_text) + read_text(NULL, '\n'); + + for (;;) + { + struct addr a; + + while ((ch=inchar()) == ';' || ISSPACE(ch)) + ; + if (ch == EOF) + break; + + cur_cmd = next_cmd_entry(&vector); + if (compile_address(&a, ch)) + { + if (a.addr_type == ADDR_IS_STEP + || a.addr_type == ADDR_IS_STEP_MOD) + bad_prog(_(BAD_STEP)); + + cur_cmd->a1 = MEMDUP(&a, 1, struct addr); + ch = in_nonblank(); + if (ch == ',') + { + if (!compile_address(&a, in_nonblank())) + bad_prog(_(BAD_COMMA)); + + cur_cmd->a2 = MEMDUP(&a, 1, struct addr); + ch = in_nonblank(); + } + + if ((cur_cmd->a1->addr_type == ADDR_IS_NUM + && cur_cmd->a1->addr_number == 0) + && ((!cur_cmd->a2 || cur_cmd->a2->addr_type != ADDR_IS_REGEX) + || posixicity == POSIXLY_BASIC)) + bad_prog(_(INVALID_LINE_0)); + } + if (ch == '!') + { + cur_cmd->addr_bang = true; + ch = in_nonblank(); + if (ch == '!') + bad_prog(_(BAD_BANG)); + } + + /* Do not accept extended commands in --posix mode. Also, + a few commands only accept one address in that mode. */ + if (posixicity == POSIXLY_BASIC) + switch (ch) + { + case 'e': case 'F': case 'v': case 'z': case 'L': + case 'Q': case 'T': case 'R': case 'W': + bad_command(ch); + + case 'a': case 'i': case 'l': + case '=': case 'r': + if (cur_cmd->a2) + bad_prog(_(ONE_ADDR)); + } + + cur_cmd->cmd = ch; + switch (ch) + { + case '#': + if (cur_cmd->a1) + bad_prog(_(NO_SHARP_ADDR)); + ch = inchar(); + if (ch=='n' && first_script && cur_input.line < 2) + if ( (prog.base && prog.cur==2+prog.base) + || (prog.file && !prog.base && 2==ftell(prog.file))) + no_default_output = true; + while (ch != EOF && ch != '\n') + ch = inchar(); + continue; /* restart the for (;;) loop */ + + case 'v': + /* This is an extension. Programs needing GNU sed might start + * with a `v' command so that other seds will stop. + * We compare the version and ignore POSIXLY_CORRECT. + */ + { + char *version = read_label (); + char *compared_version; + compared_version = (*version == '\0') ? "4.0" : version; + if (strverscmp (compared_version, SED_FEATURE_VERSION) > 0) + bad_prog(_(ANCIENT_VERSION)); + + free (version); + posixicity = POSIXLY_EXTENDED; + } + continue; + + case '{': + blocks = setup_label(blocks, vector->v_length, NULL, &cur_input); + cur_cmd->addr_bang = !cur_cmd->addr_bang; + break; + + case '}': + if (!blocks) + bad_prog(_(EXCESS_CLOSE_BRACE)); + if (cur_cmd->a1) + bad_prog(_(NO_CLOSE_BRACE_ADDR)); + ch = in_nonblank(); + if (ch == CLOSE_BRACE || ch == '#') + savchar(ch); + else if (ch != EOF && ch != '\n' && ch != ';') + bad_prog(_(EXCESS_JUNK)); + + vector->v[blocks->v_index].x.jump_index = vector->v_length; + blocks = release_label(blocks); /* done with this entry */ + break; + + case 'e': + ch = in_nonblank(); + if (ch == EOF || ch == '\n') + { + cur_cmd->x.cmd_txt.text_length = 0; + break; + } + else + goto read_text_to_slash; + + case 'a': + case 'i': + case 'c': + ch = in_nonblank(); + + read_text_to_slash: + if (ch == EOF) + bad_prog(_(EXPECTED_SLASH)); + + if (ch == '\\') + ch = inchar(); + else + { + if (posixicity == POSIXLY_BASIC) + bad_prog(_(EXPECTED_SLASH)); + savchar(ch); + ch = '\n'; + } + + read_text(&cur_cmd->x.cmd_txt, ch); + break; + + case ':': + if (cur_cmd->a1) + bad_prog(_(NO_COLON_ADDR)); + labels = setup_label(labels, vector->v_length, read_label(), NULL); + break; + + case 'T': + case 'b': + case 't': + jumps = setup_label(jumps, vector->v_length, read_label(), NULL); + break; + + case 'Q': + case 'q': + if (cur_cmd->a2) + bad_prog(_(ONE_ADDR)); + /* Fall through */ + + case 'L': + case 'l': + ch = in_nonblank(); + if (ISDIGIT(ch) && posixicity != POSIXLY_BASIC) + { + cur_cmd->x.int_arg = in_integer(ch); + ch = in_nonblank(); + } + else + cur_cmd->x.int_arg = -1; + + if (ch == CLOSE_BRACE || ch == '#') + savchar(ch); + else if (ch != EOF && ch != '\n' && ch != ';') + bad_prog(_(EXCESS_JUNK)); + + break; + + case '=': + case 'd': + case 'D': + case 'F': + case 'g': + case 'G': + case 'h': + case 'H': + case 'n': + case 'N': + case 'p': + case 'P': + case 'z': + case 'x': + ch = in_nonblank(); + if (ch == CLOSE_BRACE || ch == '#') + savchar(ch); + else if (ch != EOF && ch != '\n' && ch != ';') + bad_prog(_(EXCESS_JUNK)); + break; + + case 'r': + b = read_filename(); + cur_cmd->x.fname = ck_strdup(get_buffer(b)); + free_buffer(b); + break; + + case 'R': + cur_cmd->x.fp = get_openfile(&file_read, read_mode, false)->fp; + break; + + case 'W': + case 'w': + cur_cmd->x.outf = get_openfile(&file_write, write_mode, true); + break; + + case 's': + { + struct buffer *b2; + int flags; + int slash; + + slash = inchar(); + if ( !(b = match_slash(slash, true)) ) + bad_prog(_(UNTERM_S_CMD)); + if ( !(b2 = match_slash(slash, false)) ) + bad_prog(_(UNTERM_S_CMD)); + + cur_cmd->x.cmd_subst = OB_MALLOC(&obs, 1, struct subst); + setup_replacement(cur_cmd->x.cmd_subst, + get_buffer(b2), size_buffer(b2)); + free_buffer(b2); + + flags = mark_subst_opts(cur_cmd->x.cmd_subst); + cur_cmd->x.cmd_subst->regx = + compile_regex(b, flags, cur_cmd->x.cmd_subst->max_id + 1); + free_buffer(b); + } + break; + + case 'y': + { + size_t len, dest_len; + int slash; + struct buffer *b2; + char *src_buf, *dest_buf; + + slash = inchar(); + if ( !(b = match_slash(slash, false)) ) + bad_prog(_(UNTERM_Y_CMD)); + src_buf = get_buffer(b); + len = normalize_text(src_buf, size_buffer (b), TEXT_BUFFER); + + if ( !(b2 = match_slash(slash, false)) ) + bad_prog(_(UNTERM_Y_CMD)); + dest_buf = get_buffer(b2); + dest_len = normalize_text(dest_buf, size_buffer (b2), TEXT_BUFFER); + + if (mb_cur_max > 1) + { + int i, j, idx, src_char_num; + size_t *src_lens = MALLOC(len, size_t); + char **trans_pairs; + size_t mbclen; + mbstate_t cur_stat; + + /* Enumerate how many character the source buffer has. */ + memset(&cur_stat, 0, sizeof(mbstate_t)); + for (i = 0, j = 0; i < len;) + { + mbclen = MBRLEN (src_buf + i, len - i, &cur_stat); + /* An invalid sequence, or a truncated multibyte character. + We treat it as a singlebyte character. */ + if (mbclen == (size_t) -1 || mbclen == (size_t) -2 + || mbclen == 0) + mbclen = 1; + src_lens[j++] = mbclen; + i += mbclen; + } + src_char_num = j; + + memset(&cur_stat, 0, sizeof(mbstate_t)); + idx = 0; + + /* trans_pairs = {src(0), dest(0), src(1), dest(1), ..., NULL} + src(i) : pointer to i-th source character. + dest(i) : pointer to i-th destination character. + NULL : terminator */ + trans_pairs = MALLOC(2 * src_char_num + 1, char*); + cur_cmd->x.translatemb = trans_pairs; + for (i = 0; i < src_char_num; i++) + { + if (idx >= dest_len) + bad_prog(_(Y_CMD_LEN)); + + /* Set the i-th source character. */ + trans_pairs[2 * i] = MALLOC(src_lens[i] + 1, char); + strncpy(trans_pairs[2 * i], src_buf, src_lens[i]); + trans_pairs[2 * i][src_lens[i]] = '\0'; + src_buf += src_lens[i]; /* Forward to next character. */ + + /* Fetch the i-th destination character. */ + mbclen = MBRLEN (dest_buf + idx, dest_len - idx, &cur_stat); + /* An invalid sequence, or a truncated multibyte character. + We treat it as a singlebyte character. */ + if (mbclen == (size_t) -1 || mbclen == (size_t) -2 + || mbclen == 0) + mbclen = 1; + + /* Set the i-th destination character. */ + trans_pairs[2 * i + 1] = MALLOC(mbclen + 1, char); + strncpy(trans_pairs[2 * i + 1], dest_buf + idx, mbclen); + trans_pairs[2 * i + 1][mbclen] = '\0'; + idx += mbclen; /* Forward to next character. */ + } + trans_pairs[2 * i] = NULL; + if (idx != dest_len) + bad_prog(_(Y_CMD_LEN)); + } + else + { + unsigned char *translate = + OB_MALLOC(&obs, YMAP_LENGTH, unsigned char); + unsigned char *ustring = (unsigned char *)src_buf; + + if (len != dest_len) + bad_prog(_(Y_CMD_LEN)); + + for (len = 0; len < YMAP_LENGTH; len++) + translate[len] = len; + + while (dest_len--) + translate[*ustring++] = (unsigned char)*dest_buf++; + + cur_cmd->x.translate = translate; + } + + if ((ch = in_nonblank()) != EOF && ch != '\n' && ch != ';') + bad_prog(_(EXCESS_JUNK)); + + free_buffer(b); + free_buffer(b2); + } + break; + + case EOF: + bad_prog(_(NO_COMMAND)); + /*NOTREACHED*/ + + default: + bad_command (ch); + /*NOTREACHED*/ + } + + /* this is buried down here so that "continue" statements will miss it */ + ++vector->v_length; + } + if (posixicity == POSIXLY_BASIC && pending_text) + bad_prog (_(INCOMPLETE_CMD)); + return vector; +} + + +/* deal with \X escapes */ +size_t +normalize_text(buf, len, buftype) + char *buf; + size_t len; + enum text_types buftype; +{ + const char *bufend = buf + len; + char *p = buf; + char *q = buf; + char ch; + int base; + + /* This variable prevents normalizing text within bracket + subexpressions when conforming to POSIX. If 0, we + are not within a bracket expression. If -1, we are within a + bracket expression but are not within [.FOO.], [=FOO=], + or [:FOO:]. Otherwise, this is the '.', '=', or ':' + respectively within these three types of subexpressions. */ + int bracket_state = 0; + + int mbclen; + mbstate_t cur_stat; + memset(&cur_stat, 0, sizeof(mbstate_t)); + + while (p < bufend) + { + mbclen = MBRLEN (p, bufend - p, &cur_stat); + if (mbclen != 1) + { + /* An invalid sequence, or a truncated multibyte character. + We treat it as a singlebyte character. */ + if (mbclen == (size_t) -1 || mbclen == (size_t) -2 || mbclen == 0) + mbclen = 1; + + memmove (q, p, mbclen); + q += mbclen; + p += mbclen; + continue; + } + + if (*p == '\\' && p+1 < bufend && bracket_state == 0) + switch (*++p) + { +#if defined __STDC__ && __STDC__-0 + case 'a': *q++ = '\a'; p++; continue; +#else /* Not STDC; we'll just assume ASCII */ + case 'a': *q++ = '\007'; p++; continue; +#endif + /* case 'b': *q++ = '\b'; p++; continue; --- conflicts with \b RE */ + case 'f': *q++ = '\f'; p++; continue; + case '\n': /*fall through */ + case 'n': *q++ = '\n'; p++; continue; + case 'r': *q++ = '\r'; p++; continue; + case 't': *q++ = '\t'; p++; continue; + case 'v': *q++ = '\v'; p++; continue; + + case 'd': /* decimal byte */ + base = 10; + goto convert; + + case 'x': /* hexadecimal byte */ + base = 16; + goto convert; + +#ifdef REG_PERL + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + if ((extended_regexp_flags & REG_PERL) + && p+1 < bufend + && p[1] >= '0' && p[1] <= '9') + { + base = 8; + goto convert; + } + else + { + /* we just pass the \ up one level for interpretation */ + if (buftype != TEXT_BUFFER) + *q++ = '\\'; + } + + continue; + + case 'o': /* octal byte */ + if (!(extended_regexp_flags & REG_PERL)) + { + base = 8; + goto convert; + } + else + { + /* we just pass the \ up one level for interpretation */ + if (buftype != TEXT_BUFFER) + *q++ = '\\'; + } + + continue; +#else + case 'o': /* octal byte */ + base = 8; +#endif +convert: + p = convert_number(&ch, p, bufend, base); + + /* for an ampersand in a replacement, pass the \ up one level */ + if (buftype == TEXT_REPLACEMENT && ch == '&') + *q++ = '\\'; + *q++ = ch; + continue; + + case 'c': + if (++p < bufend) + { + *q++ = toupper((unsigned char) *p) ^ 0x40; + p++; + continue; + } + else + { + /* we just pass the \ up one level for interpretation */ + if (buftype != TEXT_BUFFER) + *q++ = '\\'; + continue; + } + + default: + /* we just pass the \ up one level for interpretation */ + if (buftype != TEXT_BUFFER) + *q++ = '\\'; + break; + } + else if (buftype == TEXT_REGEX && posixicity != POSIXLY_EXTENDED) + switch (*p) + { + case '[': + if (!bracket_state) + bracket_state = -1; + break; + + case ':': + case '.': + case '=': + if (bracket_state == -1 && p[-1] == '[') + bracket_state = *p; + break; + + case ']': + if (bracket_state == 0) + ; + else if (bracket_state == -1) + bracket_state = 0; + else if (p[-2] != bracket_state && p[-1] == bracket_state) + bracket_state = -1; + break; + } + + *q++ = *p++; + } + return (size_t)(q - buf); +} + + +/* `str' is a string (from the command line) that contains a sed command. + Compile the command, and add it to the end of `cur_program'. */ +struct vector * +compile_string(cur_program, str, len) + struct vector *cur_program; + char *str; + size_t len; +{ + static countT string_expr_count = 0; + struct vector *ret; + + prog.file = NULL; + prog.base = (unsigned char *)str; + prog.cur = prog.base; + prog.end = prog.cur + len; + + cur_input.line = 0; + cur_input.name = NULL; + cur_input.string_expr_count = ++string_expr_count; + + ret = compile_program(cur_program); + prog.base = NULL; + prog.cur = NULL; + prog.end = NULL; + + first_script = false; + return ret; +} + +/* `cmdfile' is the name of a file containing sed commands. + Read them in and add them to the end of `cur_program'. + */ +struct vector * +compile_file(cur_program, cmdfile) + struct vector *cur_program; + const char *cmdfile; +{ + struct vector *ret; + + prog.file = stdin; + if (cmdfile[0] != '-' || cmdfile[1] != '\0') + { +#ifdef HAVE_FOPEN_RT + prog.file = ck_fopen(cmdfile, "rt", true); +#else + prog.file = ck_fopen(cmdfile, "r", true); +#endif + } + + cur_input.line = 1; + cur_input.name = cmdfile; + cur_input.string_expr_count = 0; + + ret = compile_program(cur_program); + if (prog.file != stdin) + ck_fclose(prog.file); + prog.file = NULL; + + first_script = false; + return ret; +} + +/* Make any checks which require the whole program to have been read. + In particular: this backpatches the jump targets. + Any cleanup which can be done after these checks is done here also. */ +void +check_final_program(program) + struct vector *program; +{ + struct sed_label *go; + struct sed_label *lbl; + + /* do all "{"s have a corresponding "}"? */ + if (blocks) + { + /* update info for error reporting: */ + memcpy(&cur_input, &blocks->err_info, sizeof (cur_input)); + bad_prog(_(EXCESS_OPEN_BRACE)); + } + + /* was the final command an unterminated a/c/i command? */ + if (pending_text) + { + old_text_buf->text_length = size_buffer(pending_text); + if (old_text_buf->text_length) + old_text_buf->text = MEMDUP(get_buffer(pending_text), + old_text_buf->text_length, char); + free_buffer(pending_text); + pending_text = NULL; + } + + for (go = jumps; go; go = release_label(go)) + { + for (lbl = labels; lbl; lbl = lbl->next) + if (strcmp(lbl->name, go->name) == 0) + break; + if (lbl) + { + program->v[go->v_index].x.jump_index = lbl->v_index; + } + else + { + if (*go->name) + panic(_("can't find label for jump to `%s'"), go->name); + program->v[go->v_index].x.jump_index = program->v_length; + } + } + jumps = NULL; + + for (lbl = labels; lbl; lbl = release_label(lbl)) + ; + labels = NULL; + + /* There is no longer a need to track file names: */ + { + struct output *p; + + for (p=file_read; p; p=p->link) + if (p->name) + { + free(p->name); + p->name = NULL; + } + + for (p=file_write; p; p=p->link) + if (p->name) + { + free(p->name); + p->name = NULL; + } + } +} + +/* Rewind all resources which were allocated in this module. */ +void +rewind_read_files() +{ + struct output *p; + + for (p=file_read; p; p=p->link) + if (p->fp) + rewind(p->fp); +} + +/* Release all resources which were allocated in this module. */ +void +finish_program(program) + struct vector *program; +{ + /* close all files... */ + { + struct output *p, *q; + + for (p=file_read; p; p=q) + { + if (p->fp) + ck_fclose(p->fp); + q = p->link; +#if 0 + /* We use obstacks. */ + free(p); +#endif + } + + for (p=file_write; p; p=q) + { + if (p->fp) + ck_fclose(p->fp); + q = p->link; +#if 0 + /* We use obstacks. */ + free(p); +#endif + } + file_read = file_write = NULL; + } + +#ifdef DEBUG_LEAKS + obstack_free (&obs, NULL); +#endif /*DEBUG_LEAKS*/ +} diff --git a/sed/execute.c b/sed/execute.c new file mode 100644 index 0000000..cb84192 --- /dev/null +++ b/sed/execute.c @@ -0,0 +1,1762 @@ +/* GNU SED, a batch stream editor. + Copyright (C) 1989,90,91,92,93,94,95,98,99,2002,2003,2004,2005,2006,2008,2009 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#undef EXPERIMENTAL_DASH_N_OPTIMIZATION /*don't use -- is very buggy*/ +#define INITIAL_BUFFER_SIZE 50 +#define FREAD_BUFFER_SIZE 8192 + +#include "sed.h" + +#include <stddef.h> +#include <stdio.h> +#include <ctype.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "stat-macros.h" + +#include <selinux/selinux.h> +#include <selinux/context.h> +#include "acl.h" + +#ifdef __GNUC__ +# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__-0 >= 7) + /* silence warning about unused parameter even for "gcc -W -Wunused" */ +# define UNUSED __attribute__((unused)) +# endif +#endif +#ifndef UNUSED +# define UNUSED +#endif + + +/* Sed operates a line at a time. */ +struct line { + char *text; /* Pointer to line allocated by malloc. */ + char *active; /* Pointer to non-consumed part of text. */ + size_t length; /* Length of text (or active, if used). */ + size_t alloc; /* Allocated space for active. */ + bool chomped; /* Was a trailing newline dropped? */ + mbstate_t mbstate; +}; + +#define SIZEOF_LINE offsetof (struct line, mbstate) + +/* A queue of text to write out at the end of a cycle + (filled by the "a", "r" and "R" commands.) */ +struct append_queue { + const char *fname; + char *text; + size_t textlen; + struct append_queue *next; + bool free; +}; + +/* State information for the input stream. */ +struct input { + /* The list of yet-to-be-opened files. It is invalid for file_list + to be NULL. When *file_list is NULL we are currently processing + the last file. */ + + char **file_list; + + /* Count of files we failed to open. */ + countT bad_count; + + /* Current input line number (over all files). */ + countT line_number; + + /* True if we'll reset line numbers and addresses before + starting to process the next (possibly the first) file. */ + bool reset_at_next_file; + + /* Function to read one line. If FP is NULL, read_fn better not + be one which uses fp; in particular, read_always_fail() is + recommended. */ + bool (*read_fn) (struct input *); /* read one line */ + + char *out_file_name; + + const char *in_file_name; + + /* Owner and mode to be set just before closing the file. */ + struct stat st; + + /* if NULL, none of the following are valid */ + FILE *fp; + + bool no_buffering; +}; + + +/* Have we done any replacements lately? This is used by the `t' command. */ +static bool replaced = false; + +/* The current output file (stdout if -i is not being used. */ +static struct output output_file; + +/* The `current' input line. */ +static struct line line; + +/* An input line used to accumulate the result of the s and e commands. */ +static struct line s_accum; + +/* An input line that's been stored by later use by the program */ +static struct line hold; + +/* The buffered input look-ahead. The only field that should be + used outside of read_mem_line() or line_init() is buffer.length. */ +static struct line buffer; + +static struct append_queue *append_head = NULL; +static struct append_queue *append_tail = NULL; + + +/* increase a struct line's length, making some attempt at + keeping realloc() calls under control by padding for future growth. */ +static void resize_line (struct line *, size_t); +static void +resize_line(lb, len) + struct line *lb; + size_t len; +{ + int inactive; + inactive = lb->active - lb->text; + + /* If the inactive part has got to more than two thirds of the buffer, + * remove it. */ + if (inactive > lb->alloc * 2) + { + memmove(lb->text, lb->active, lb->length); + lb->alloc += lb->active - lb->text; + lb->active = lb->text; + inactive = 0; + + if (lb->alloc > len) + return; + } + + lb->alloc *= 2; + if (lb->alloc < len) + lb->alloc = len; + if (lb->alloc < INITIAL_BUFFER_SIZE) + lb->alloc = INITIAL_BUFFER_SIZE; + + lb->text = REALLOC(lb->text, inactive + lb->alloc, char); + lb->active = lb->text + inactive; +} + +/* Append `length' bytes from `string' to the line `to'. */ +static void str_append (struct line *, const char *, size_t); +static void +str_append(to, string, length) + struct line *to; + const char *string; + size_t length; +{ + size_t new_length = to->length + length; + + if (to->alloc < new_length) + resize_line(to, new_length); + memcpy(to->active + to->length, string, length); + to->length = new_length; + + if (mb_cur_max > 1 && !is_utf8) + while (length) + { + size_t n = MBRLEN (string, length, &to->mbstate); + + /* An invalid or imcomplete sequence is treated like a singlebyte character. */ + if (n == (size_t) -1 || n == (size_t) -2) + { + memset (&to->mbstate, 0, sizeof (to->mbstate)); + n = 1; + } + + if (n > 0) + { + string += n; + length -= n; + } + else + break; + } +} + +static void +str_append_modified(struct line *to, const char *string, size_t length, + enum replacement_types type) +{ + mbstate_t from_stat; + + if (type == REPL_ASIS) + { + str_append(to, string, length); + return; + } + + if (to->alloc - to->length < length * mb_cur_max) + resize_line(to, to->length + length * mb_cur_max); + + memcpy (&from_stat, &to->mbstate, sizeof(mbstate_t)); + while (length) + { + wchar_t wc; + int n = MBRTOWC (&wc, string, length, &from_stat); + + /* An invalid sequence is treated like a singlebyte character. */ + if (n == -1) + { + memset (&to->mbstate, 0, sizeof (from_stat)); + n = 1; + } + + if (n > 0) + string += n, length -= n; + else + { + /* Incomplete sequence, copy it manually. */ + str_append(to, string, length); + return; + } + + /* Convert the first character specially... */ + if (type & (REPL_UPPERCASE_FIRST | REPL_LOWERCASE_FIRST)) + { + if (type & REPL_UPPERCASE_FIRST) + wc = towupper(wc); + else + wc = towlower(wc); + + type &= ~(REPL_LOWERCASE_FIRST | REPL_UPPERCASE_FIRST); + if (type == REPL_ASIS) + { + n = WCRTOMB (to->active + to->length, wc, &to->mbstate); + to->length += n; + str_append(to, string, length); + return; + } + } + + else if (type & REPL_UPPERCASE) + wc = towupper(wc); + else + wc = towlower(wc); + + /* Copy the new wide character to the end of the string. */ + n = WCRTOMB (to->active + to->length, wc, &to->mbstate); + to->length += n; + if (n == -1 || n == -2) + { + fprintf (stderr, "Case conversion produced an invalid character!"); + abort (); + } + } +} + +/* Initialize a "struct line" buffer. Copy multibyte state from `state' + if not null. */ +static void line_init (struct line *, struct line *, size_t initial_size); +static void +line_init(buf, state, initial_size) + struct line *buf; + struct line *state; + size_t initial_size; +{ + buf->text = MALLOC(initial_size, char); + buf->active = buf->text; + buf->alloc = initial_size; + buf->length = 0; + buf->chomped = true; + + if (state) + memcpy (&buf->mbstate, &state->mbstate, sizeof (buf->mbstate)); + else + memset (&buf->mbstate, 0, sizeof (buf->mbstate)); +} + +/* Reset a "struct line" buffer to length zero. Copy multibyte state from + `state' if not null. */ +static void line_reset (struct line *, struct line *); +static void +line_reset(buf, state) + struct line *buf, *state; +{ + if (buf->alloc == 0) + line_init(buf, state, INITIAL_BUFFER_SIZE); + else + { + buf->length = 0; + if (state) + memcpy (&buf->mbstate, &state->mbstate, sizeof (buf->mbstate)); + else + memset (&buf->mbstate, 0, sizeof (buf->mbstate)); + } +} + +/* Copy the contents of the line `from' into the line `to'. + This destroys the old contents of `to'. + Copy the multibyte state if `state' is true. */ +static void line_copy (struct line *from, struct line *to, int state); +static void +line_copy(from, to, state) + struct line *from; + struct line *to; + int state; +{ + /* Remove the inactive portion in the destination buffer. */ + to->alloc += to->active - to->text; + + if (to->alloc < from->length) + { + to->alloc *= 2; + if (to->alloc < from->length) + to->alloc = from->length; + if (to->alloc < INITIAL_BUFFER_SIZE) + to->alloc = INITIAL_BUFFER_SIZE; + /* Use free()+MALLOC() instead of REALLOC() to + avoid unnecessary copying of old text. */ + free(to->text); + to->text = MALLOC(to->alloc, char); + } + + to->active = to->text; + to->length = from->length; + to->chomped = from->chomped; + memcpy(to->active, from->active, from->length); + + if (state) + memcpy(&to->mbstate, &from->mbstate, sizeof (from->mbstate)); +} + +/* Append the contents of the line `from' to the line `to'. + Copy the multibyte state if `state' is true. */ +static void line_append (struct line *from, struct line *to, int state); +static void +line_append(from, to, state) + struct line *from; + struct line *to; + int state; +{ + str_append(to, &buffer_delimiter, 1); + str_append(to, from->active, from->length); + to->chomped = from->chomped; + + if (state) + memcpy (&to->mbstate, &from->mbstate, sizeof (from->mbstate)); +} + +/* Exchange two "struct line" buffers. + Copy the multibyte state if `state' is true. */ +static void line_exchange (struct line *a, struct line *b, int state); +static void +line_exchange(a, b, state) + struct line *a; + struct line *b; + int state; +{ + struct line t; + + if (state) + { + memcpy(&t, a, sizeof (struct line)); + memcpy( a, b, sizeof (struct line)); + memcpy( b, &t, sizeof (struct line)); + } + else + { + memcpy(&t, a, SIZEOF_LINE); + memcpy( a, b, SIZEOF_LINE); + memcpy( b, &t, SIZEOF_LINE); + } +} + + +/* dummy function to simplify read_pattern_space() */ +static bool read_always_fail (struct input *); +static bool +read_always_fail(input) + struct input *input UNUSED; +{ + return false; +} + +static bool read_file_line (struct input *); +static bool +read_file_line(input) + struct input *input; +{ + static char *b; + static size_t blen; + + long result = ck_getdelim (&b, &blen, buffer_delimiter, input->fp); + if (result <= 0) + return false; + + /* Remove the trailing new-line that is left by getline. */ + if (b[result - 1] == buffer_delimiter) + --result; + else + line.chomped = false; + + str_append(&line, b, result); + return true; +} + + +static inline void output_missing_newline (struct output *); +static inline void +output_missing_newline(outf) + struct output *outf; +{ + if (outf->missing_newline) + { + ck_fwrite(&buffer_delimiter, 1, 1, outf->fp); + outf->missing_newline = false; + } +} + +static inline void flush_output (FILE *); +static inline void +flush_output(fp) + FILE *fp; +{ + if (fp != stdout || unbuffered) + ck_fflush(fp); +} + +static void output_line (const char *, size_t, int, struct output *); +static void +output_line(text, length, nl, outf) + const char *text; + size_t length; + int nl; + struct output *outf; +{ + if (!text) + return; + + output_missing_newline(outf); + if (length) + ck_fwrite(text, 1, length, outf->fp); + if (nl) + ck_fwrite(&buffer_delimiter, 1, 1, outf->fp); + else + outf->missing_newline = true; + + flush_output(outf->fp); +} + +static struct append_queue *next_append_slot (void); +static struct append_queue * +next_append_slot() +{ + struct append_queue *n = MALLOC(1, struct append_queue); + + n->fname = NULL; + n->text = NULL; + n->textlen = 0; + n->next = NULL; + n->free = false; + + if (append_tail) + append_tail->next = n; + else + append_head = n; + return append_tail = n; +} + +static void release_append_queue (void); +static void +release_append_queue() +{ + struct append_queue *p, *q; + + for (p=append_head; p; p=q) + { + if (p->free) + free(p->text); + + q = p->next; + free(p); + } + append_head = append_tail = NULL; +} + +static void dump_append_queue (void); +static void +dump_append_queue() +{ + struct append_queue *p; + + output_missing_newline(&output_file); + for (p=append_head; p; p=p->next) + { + if (p->text) + ck_fwrite(p->text, 1, p->textlen, output_file.fp); + + if (p->fname) + { + char buf[FREAD_BUFFER_SIZE]; + size_t cnt; + FILE *fp; + + /* "If _fname_ does not exist or cannot be read, it shall + be treated as if it were an empty file, causing no error + condition." IEEE Std 1003.2-1992 + So, don't fail. */ + fp = ck_fopen(p->fname, read_mode, false); + if (fp) + { + while ((cnt = ck_fread(buf, 1, sizeof buf, fp)) > 0) + ck_fwrite(buf, 1, cnt, output_file.fp); + ck_fclose(fp); + } + } + } + + flush_output(output_file.fp); + release_append_queue(); +} + + +/* Compute the name of the backup file for in-place editing */ +static char *get_backup_file_name (const char *); +static char * +get_backup_file_name(name) + const char *name; +{ + char *old_asterisk, *asterisk, *backup, *p; + int name_length = strlen(name), backup_length = strlen(in_place_extension); + + /* Compute the length of the backup file */ + for (asterisk = in_place_extension - 1, old_asterisk = asterisk + 1; + (asterisk = strchr(old_asterisk, '*')); + old_asterisk = asterisk + 1) + backup_length += name_length - 1; + + p = backup = xmalloc(backup_length + 1); + + /* Each iteration gobbles up to an asterisk */ + for (asterisk = in_place_extension - 1, old_asterisk = asterisk + 1; + (asterisk = strchr(old_asterisk, '*')); + old_asterisk = asterisk + 1) + { + memcpy (p, old_asterisk, asterisk - old_asterisk); + p += asterisk - old_asterisk; + strcpy (p, name); + p += name_length; + } + + /* Tack on what's after the last asterisk */ + strcpy (p, old_asterisk); + return backup; +} + +/* Initialize a struct input for the named file. */ +static void open_next_file (const char *name, struct input *); +static void +open_next_file(name, input) + const char *name; + struct input *input; +{ + buffer.length = 0; + + if (name[0] == '-' && name[1] == '\0' && !in_place_extension) + { + clearerr(stdin); /* clear any stale EOF indication */ +#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(MSDOS) || defined(__EMX__) + input->fp = ck_fdopen (fileno (stdin), "stdin", read_mode, false); +#else + input->fp = stdin; +#endif + } + else if ( ! (input->fp = ck_fopen(name, read_mode, false)) ) + { + const char *ptr = strerror(errno); + fprintf(stderr, _("%s: can't read %s: %s\n"), myname, name, ptr); + input->read_fn = read_always_fail; /* a redundancy */ + ++input->bad_count; + return; + } + + input->read_fn = read_file_line; + + if (follow_symlinks) + input->in_file_name = follow_symlink (name); + else + input->in_file_name = name; + + if (in_place_extension) + { + int input_fd; + char *tmpdir, *p; + security_context_t old_fscreatecon; + int reset_fscreatecon = 0; + memset (&old_fscreatecon, 0, sizeof (old_fscreatecon)); + + /* get the base name */ + tmpdir = ck_strdup(input->in_file_name); + if ((p = strrchr(tmpdir, '/'))) + *p = 0; + else + strcpy(tmpdir, "."); + + if (isatty (fileno (input->fp))) + panic(_("couldn't edit %s: is a terminal"), input->in_file_name); + + input_fd = fileno (input->fp); + fstat (input_fd, &input->st); + if (!S_ISREG (input->st.st_mode)) + panic(_("couldn't edit %s: not a regular file"), input->in_file_name); + + if (is_selinux_enabled () > 0) + { + security_context_t con; + if (getfilecon (input->in_file_name, &con) != -1) + { + /* Save and restore the old context for the sake of w and W + commands. */ + reset_fscreatecon = getfscreatecon (&old_fscreatecon) >= 0; + if (setfscreatecon (con) < 0) + fprintf (stderr, _("%s: warning: failed to set default file creation context to %s: %s"), + myname, con, strerror (errno)); + freecon (con); + } + else + { + if (errno != ENOSYS) + fprintf (stderr, _("%s: warning: failed to get security context of %s: %s"), + myname, input->in_file_name, strerror (errno)); + } + } + + output_file.fp = ck_mkstemp (&input->out_file_name, tmpdir, "sed", + write_mode); + output_file.missing_newline = false; + free (tmpdir); + + if (reset_fscreatecon) + { + setfscreatecon (old_fscreatecon); + freecon (old_fscreatecon); + } + + if (!output_file.fp) + panic(_("couldn't open temporary file %s: %s"), input->out_file_name, strerror(errno)); + } + else + { + if (input->fp && unbuffered) + setvbuf (input->fp, NULL, _IONBF, 0); + output_file.fp = stdout; + } +} + + +/* Clean up an input stream that we are done with. */ +static void closedown (struct input *); +static void +closedown(input) + struct input *input; +{ + input->read_fn = read_always_fail; + if (!input->fp) + return; + + if (in_place_extension && output_file.fp != NULL) + { + const char *target_name; + int input_fd, output_fd; + + target_name = input->in_file_name; + input_fd = fileno (input->fp); + output_fd = fileno (output_file.fp); +#ifdef HAVE_FCHOWN + if (fchown (output_fd, input->st.st_uid, input->st.st_gid) == -1) + fchown (output_fd, -1, input->st.st_gid); +#endif + copy_acl (input->in_file_name, input_fd, + input->out_file_name, output_fd, + input->st.st_mode); + + ck_fclose (input->fp); + ck_fclose (output_file.fp); + if (strcmp(in_place_extension, "*") != 0) + { + char *backup_file_name = get_backup_file_name(target_name); + ck_rename (target_name, backup_file_name, input->out_file_name); + free (backup_file_name); + } + + ck_rename (input->out_file_name, target_name, input->out_file_name); + free (input->out_file_name); + } + else + ck_fclose (input->fp); + + input->fp = NULL; +} + +/* Reset range commands so that they are marked as non-matching */ +static void reset_addresses (struct vector *); +static void +reset_addresses(vec) + struct vector *vec; +{ + struct sed_cmd *cur_cmd; + int n; + + for (cur_cmd = vec->v, n = vec->v_length; n--; cur_cmd++) + if (cur_cmd->a1 + && cur_cmd->a1->addr_type == ADDR_IS_NUM + && cur_cmd->a1->addr_number == 0) + cur_cmd->range_state = RANGE_ACTIVE; + else + cur_cmd->range_state = RANGE_INACTIVE; +} + +/* Read in the next line of input, and store it in the pattern space. + Return zero if there is nothing left to input. */ +static bool read_pattern_space (struct input *, struct vector *, int); +static bool +read_pattern_space(input, the_program, append) + struct input *input; + struct vector *the_program; + int append; +{ + if (append_head) /* redundant test to optimize for common case */ + dump_append_queue(); + replaced = false; + if (!append) + line.length = 0; + line.chomped = true; /* default, until proved otherwise */ + + while ( ! (*input->read_fn)(input) ) + { + closedown(input); + + if (!*input->file_list) + return false; + + if (input->reset_at_next_file) + { + input->line_number = 0; + hold.length = 0; + reset_addresses (the_program); + rewind_read_files (); + + /* If doing in-place editing, we will never append the + new-line to this file; but if the output goes to stdout, + we might still have to output the missing new-line. */ + if (in_place_extension) + output_file.missing_newline = false; + + input->reset_at_next_file = separate_files; + } + + open_next_file (*input->file_list++, input); + } + + ++input->line_number; + return true; +} + + +static bool last_file_with_data_p (struct input *); +static bool +last_file_with_data_p(input) + struct input *input; +{ + for (;;) + { + int ch; + + closedown(input); + if (!*input->file_list) + return true; + open_next_file(*input->file_list++, input); + if (input->fp) + { + if ((ch = getc(input->fp)) != EOF) + { + ungetc(ch, input->fp); + return false; + } + } + } +} + +/* Determine if we match the `$' address. */ +static bool test_eof (struct input *); +static bool +test_eof(input) + struct input *input; +{ + int ch; + + if (buffer.length) + return false; + if (!input->fp) + return separate_files || last_file_with_data_p(input); + if (feof(input->fp)) + return separate_files || last_file_with_data_p(input); + if ((ch = getc(input->fp)) == EOF) + return separate_files || last_file_with_data_p(input); + ungetc(ch, input->fp); + return false; +} + +/* Return non-zero if the current line matches the address + pointed to by `addr'. */ +static bool match_an_address_p (struct addr *, struct input *); +static bool +match_an_address_p(addr, input) + struct addr *addr; + struct input *input; +{ + switch (addr->addr_type) + { + case ADDR_IS_NULL: + return true; + + case ADDR_IS_REGEX: + return match_regex(addr->addr_regex, line.active, line.length, 0, NULL, 0); + + case ADDR_IS_NUM_MOD: + return (input->line_number >= addr->addr_number + && ((input->line_number - addr->addr_number) % addr->addr_step) == 0); + + case ADDR_IS_STEP: + case ADDR_IS_STEP_MOD: + /* reminder: these are only meaningful for a2 addresses */ + /* a2->addr_number needs to be recomputed each time a1 address + matches for the step and step_mod types */ + return (addr->addr_number <= input->line_number); + + case ADDR_IS_LAST: + return test_eof(input); + + /* ADDR_IS_NUM is handled in match_address_p. */ + case ADDR_IS_NUM: + default: + panic("INTERNAL ERROR: bad address type"); + } + /*NOTREACHED*/ + return false; +} + +/* return non-zero if current address is valid for cmd */ +static bool match_address_p (struct sed_cmd *, struct input *); +static bool +match_address_p(cmd, input) + struct sed_cmd *cmd; + struct input *input; +{ + if (!cmd->a1) + return true; + + if (cmd->range_state != RANGE_ACTIVE) + { + /* Find if we are going to activate a range. Handle ADDR_IS_NUM + specially: it represent an "absolute" state, it should not + be computed like regexes. */ + if (cmd->a1->addr_type == ADDR_IS_NUM) + { + if (!cmd->a2) + return (input->line_number == cmd->a1->addr_number); + + if (cmd->range_state == RANGE_CLOSED + || input->line_number < cmd->a1->addr_number) + return false; + } + else + { + if (!cmd->a2) + return match_an_address_p(cmd->a1, input); + + if (!match_an_address_p(cmd->a1, input)) + return false; + } + + /* Ok, start a new range. */ + cmd->range_state = RANGE_ACTIVE; + switch (cmd->a2->addr_type) + { + case ADDR_IS_REGEX: + /* Always include at least two lines. */ + return true; + case ADDR_IS_NUM: + /* Same handling as below, but always include at least one line. */ + if (input->line_number >= cmd->a2->addr_number) + cmd->range_state = RANGE_CLOSED; + return true; + case ADDR_IS_STEP: + cmd->a2->addr_number = input->line_number + cmd->a2->addr_step; + return true; + case ADDR_IS_STEP_MOD: + cmd->a2->addr_number = input->line_number + cmd->a2->addr_step + - (input->line_number%cmd->a2->addr_step); + return true; + default: + break; + } + } + + /* cmd->range_state == RANGE_ACTIVE. Check if the range is + ending; also handle ADDR_IS_NUM specially in this case. */ + + if (cmd->a2->addr_type == ADDR_IS_NUM) + { + /* If the second address is a line number, and if we got past + that line, fail to match (it can happen when you jump + over such addresses with `b' and `t'. Use RANGE_CLOSED + so that the range is not re-enabled anymore. */ + if (input->line_number >= cmd->a2->addr_number) + cmd->range_state = RANGE_CLOSED; + + return (input->line_number <= cmd->a2->addr_number); + } + + /* Other addresses are treated as usual. */ + if (match_an_address_p(cmd->a2, input)) + cmd->range_state = RANGE_CLOSED; + + return true; +} + + +static void do_list (int line_len); +static void +do_list(line_len) + int line_len; +{ + unsigned char *p = (unsigned char *)line.active; + countT len = line.length; + countT width = 0; + char obuf[180]; /* just in case we encounter a 512-bit char (;-) */ + char *o; + size_t olen; + FILE *fp = output_file.fp; + + output_missing_newline(&output_file); + for (; len--; ++p) { + o = obuf; + + /* Some locales define 8-bit characters as printable. This makes the + testsuite fail at 8to7.sed because the `l' command in fact will not + convert the 8-bit characters. */ +#if defined isascii || defined HAVE_ISASCII + if (isascii(*p) && ISPRINT(*p)) { +#else + if (ISPRINT(*p)) { +#endif + *o++ = *p; + if (*p == '\\') + *o++ = '\\'; + } else { + *o++ = '\\'; + switch (*p) { +#if defined __STDC__ && __STDC__-0 + case '\a': *o++ = 'a'; break; +#else /* Not STDC; we'll just assume ASCII */ + case 007: *o++ = 'a'; break; +#endif + case '\b': *o++ = 'b'; break; + case '\f': *o++ = 'f'; break; + case '\n': *o++ = 'n'; break; + case '\r': *o++ = 'r'; break; + case '\t': *o++ = 't'; break; + case '\v': *o++ = 'v'; break; + default: + sprintf(o, "%03o", *p); + o += strlen(o); + break; + } + } + olen = o - obuf; + if (width+olen >= line_len && line_len > 0) { + ck_fwrite("\\\n", 1, 2, fp); + width = 0; + } + ck_fwrite(obuf, 1, olen, fp); + width += olen; + } + ck_fwrite("$\n", 1, 2, fp); + flush_output (fp); +} + + +static void append_replacement (struct line *buf, struct replacement *p, + struct re_registers *regs) +{ + enum replacement_types repl_mod = 0; + + for (; p; p=p->next) + { + int i = p->subst_id; + enum replacement_types curr_type; + + /* Apply a \[lu] modifier that was given earlier, but which we + have not had yet the occasion to apply. But don't do it + if this replacement has a modifier of its own. */ + curr_type = (p->repl_type & REPL_MODIFIERS) + ? p->repl_type + : p->repl_type | repl_mod; + + repl_mod = 0; + if (p->prefix_length) + { + str_append_modified(buf, p->prefix, p->prefix_length, + curr_type); + curr_type &= ~REPL_MODIFIERS; + } + + if (0 <= i) + { + if (regs->end[i] == regs->start[i] && p->repl_type & REPL_MODIFIERS) + /* Save this modifier, we shall apply it later. + e.g. in s/()([a-z])/\u\1\2/ + the \u modifier is applied to \2, not \1 */ + repl_mod = curr_type & REPL_MODIFIERS; + + else if (regs->end[i] != regs->start[i]) + str_append_modified(buf, line.active + regs->start[i], + (size_t)(regs->end[i] - regs->start[i]), + curr_type); + } + } +} + +static void do_subst (struct subst *); +static void +do_subst(sub) + struct subst *sub; +{ + size_t start = 0; /* where to start scan for (next) match in LINE */ + size_t last_end = 0; /* where did the last successful match end in LINE */ + countT count = 0; /* number of matches found */ + bool again = true; + + static struct re_registers regs; + + line_reset(&s_accum, &line); + + /* The first part of the loop optimizes s/xxx// when xxx is at the + start, and s/xxx$// */ + if (!match_regex(sub->regx, line.active, line.length, start, + ®s, sub->max_id + 1)) + return; + + if (!sub->replacement && sub->numb <= 1) + { + if (regs.start[0] == 0 && !sub->global) + { + /* We found a match, set the `replaced' flag. */ + replaced = true; + + line.active += regs.end[0]; + line.length -= regs.end[0]; + line.alloc -= regs.end[0]; + goto post_subst; + } + else if (regs.end[0] == line.length) + { + /* We found a match, set the `replaced' flag. */ + replaced = true; + + line.length = regs.start[0]; + goto post_subst; + } + } + + do + { + size_t offset = regs.start[0]; + size_t matched = regs.end[0] - regs.start[0]; + + /* Copy stuff to the left of this match into the output string. */ + if (start < offset) + str_append(&s_accum, line.active + start, offset - start); + + /* If we're counting up to the Nth match, are we there yet? + And even if we are there, there is another case we have to + skip: are we matching an empty string immediately following + another match? + + This latter case avoids that baaaac, when passed through + s,a*,x,g, gives `xbxxcx' instead of xbxcx. This behavior is + unacceptable because it is not consistently applied (for + example, `baaaa' gives `xbx', not `xbxx'). */ + if ((matched > 0 || count == 0 || offset > last_end) + && ++count >= sub->numb) + { + /* We found a match, set the `replaced' flag. */ + replaced = true; + + /* Now expand the replacement string into the output string. */ + append_replacement (&s_accum, sub->replacement, ®s); + again = sub->global; + } + else + { + /* The match was not replaced. Copy the text until its + end; if it was vacuous, skip over one character and + add that character to the output. */ + if (matched == 0) + { + if (start < line.length) + matched = 1; + else + break; + } + + str_append(&s_accum, line.active + offset, matched); + } + + /* Start after the match. last_end is the real end of the matched + substring, excluding characters that were skipped in case the RE + matched the empty string. */ + start = offset + matched; + last_end = regs.end[0]; + } + while (again + && start <= line.length + && match_regex(sub->regx, line.active, line.length, start, + ®s, sub->max_id + 1)); + + /* Copy stuff to the right of the last match into the output string. */ + if (start < line.length) + str_append(&s_accum, line.active + start, line.length-start); + s_accum.chomped = line.chomped; + + /* Exchange line and s_accum. This can be much cheaper + than copying s_accum.active into line.text (for huge lines). */ + line_exchange(&line, &s_accum, false); + + /* Finish up. */ + if (count < sub->numb) + return; + + post_subst: + if (sub->print & 1) + output_line(line.active, line.length, line.chomped, &output_file); + + if (sub->eval) + { +#ifdef HAVE_POPEN + FILE *pipe_fp; + line_reset(&s_accum, NULL); + + str_append (&line, "", 1); + pipe_fp = popen(line.active, "r"); + + if (pipe_fp != NULL) + { + while (!feof (pipe_fp)) + { + char buf[4096]; + int n = fread (buf, sizeof(char), 4096, pipe_fp); + if (n > 0) + str_append(&s_accum, buf, n); + } + + pclose (pipe_fp); + + /* Exchange line and s_accum. This can be much cheaper than copying + s_accum.active into line.text (for huge lines). See comment above + for 'g' as to while the third argument is incorrect anyway. */ + line_exchange(&line, &s_accum, true); + if (line.length && + line.active[line.length - 1] == buffer_delimiter) + line.length--; + } + else + panic(_("error in subprocess")); +#else + panic(_("option `e' not supported")); +#endif + } + + if (sub->print & 2) + output_line(line.active, line.length, line.chomped, &output_file); + if (sub->outf) + output_line(line.active, line.length, line.chomped, sub->outf); +} + +#ifdef EXPERIMENTAL_DASH_N_OPTIMIZATION +/* Used to attempt a simple-minded optimization. */ + +static countT branches; + +static countT count_branches (struct vector *); +static countT +count_branches(program) + struct vector *program; +{ + struct sed_cmd *cur_cmd = program->v; + countT isn_cnt = program->v_length; + countT cnt = 0; + + while (isn_cnt-- > 0) + { + switch (cur_cmd->cmd) + { + case 'b': + case 't': + case 'T': + case '{': + ++cnt; + } + } + return cnt; +} + +static struct sed_cmd *shrink_program (struct vector *, struct sed_cmd *); +static struct sed_cmd * +shrink_program(vec, cur_cmd) + struct vector *vec; + struct sed_cmd *cur_cmd; +{ + struct sed_cmd *v = vec->v; + struct sed_cmd *last_cmd = v + vec->v_length; + struct sed_cmd *p; + countT cmd_cnt; + + for (p=v; p < cur_cmd; ++p) + if (p->cmd != '#') + memcpy(v++, p, sizeof *v); + cmd_cnt = v - vec->v; + + for (; p < last_cmd; ++p) + if (p->cmd != '#') + memcpy(v++, p, sizeof *v); + vec->v_length = v - vec->v; + + return (0 < vec->v_length) ? (vec->v + cmd_cnt) : (struct sed_cmd *)0; +} +#endif /*EXPERIMENTAL_DASH_N_OPTIMIZATION*/ + +/* Execute the program `vec' on the current input line. + Return exit status if caller should quit, -1 otherwise. */ +static int execute_program (struct vector *, struct input *); +static int +execute_program(vec, input) + struct vector *vec; + struct input *input; +{ + struct sed_cmd *cur_cmd; + struct sed_cmd *end_cmd; + + cur_cmd = vec->v; + end_cmd = vec->v + vec->v_length; + while (cur_cmd < end_cmd) + { + if (match_address_p(cur_cmd, input) != cur_cmd->addr_bang) + { + switch (cur_cmd->cmd) + { + case 'a': + { + struct append_queue *aq = next_append_slot(); + aq->text = cur_cmd->x.cmd_txt.text; + aq->textlen = cur_cmd->x.cmd_txt.text_length; + } + break; + + case '{': + case 'b': + cur_cmd = vec->v + cur_cmd->x.jump_index; + continue; + + case '}': + case '#': + case ':': + /* Executing labels and block-ends are easy. */ + break; + + case 'c': + if (cur_cmd->range_state != RANGE_ACTIVE) + output_line(cur_cmd->x.cmd_txt.text, + cur_cmd->x.cmd_txt.text_length - 1, true, + &output_file); + /* POSIX.2 is silent about c starting a new cycle, + but it seems to be expected (and make sense). */ + /* Fall Through */ + case 'd': + return -1; + + case 'D': + { + char *p = memchr(line.active, buffer_delimiter, line.length); + if (!p) + return -1; + + ++p; + line.alloc -= p - line.active; + line.length -= p - line.active; + line.active += p - line.active; + + /* reset to start next cycle without reading a new line: */ + cur_cmd = vec->v; + continue; + } + + case 'e': { +#ifdef HAVE_POPEN + FILE *pipe_fp; + int cmd_length = cur_cmd->x.cmd_txt.text_length; + line_reset(&s_accum, NULL); + + if (!cmd_length) + { + str_append (&line, "", 1); + pipe_fp = popen(line.active, "r"); + } + else + { + cur_cmd->x.cmd_txt.text[cmd_length - 1] = 0; + pipe_fp = popen(cur_cmd->x.cmd_txt.text, "r"); + output_missing_newline(&output_file); + } + + if (pipe_fp != NULL) + { + char buf[4096]; + int n; + while (!feof (pipe_fp)) + if ((n = fread (buf, sizeof(char), 4096, pipe_fp)) > 0) + { + if (!cmd_length) + str_append(&s_accum, buf, n); + else + ck_fwrite(buf, 1, n, output_file.fp); + } + + pclose (pipe_fp); + if (!cmd_length) + { + /* Store into pattern space for plain `e' commands */ + if (s_accum.length && + s_accum.active[s_accum.length - 1] == buffer_delimiter) + s_accum.length--; + + /* Exchange line and s_accum. This can be much + cheaper than copying s_accum.active into line.text + (for huge lines). See comment above for 'g' as + to while the third argument is incorrect anyway. */ + line_exchange(&line, &s_accum, true); + } + else + flush_output(output_file.fp); + + } + else + panic(_("error in subprocess")); +#else + panic(_("`e' command not supported")); +#endif + break; + } + + case 'g': + /* We do not have a really good choice for the third parameter. + The problem is that hold space and the input file might as + well have different states; copying it from hold space means + that subsequent input might be read incorrectly, while + keeping it as in pattern space means that commands operating + on the moved buffer might consider a wrong character set. + We keep it true because it's what sed <= 4.1.5 did. */ + line_copy(&hold, &line, true); + break; + + case 'G': + /* We do not have a really good choice for the third parameter. + The problem is that hold space and pattern space might as + well have different states. So, true is as wrong as false. + We keep it true because it's what sed <= 4.1.5 did, but + we could consider having line_ap. */ + line_append(&hold, &line, true); + break; + + case 'h': + /* Here, it is ok to have true. */ + line_copy(&line, &hold, true); + break; + + case 'H': + /* See comment above for 'G' regarding the third parameter. */ + line_append(&line, &hold, true); + break; + + case 'i': + output_line(cur_cmd->x.cmd_txt.text, + cur_cmd->x.cmd_txt.text_length - 1, + true, &output_file); + break; + + case 'l': + do_list(cur_cmd->x.int_arg == -1 + ? lcmd_out_line_len + : cur_cmd->x.int_arg); + break; + + case 'L': + output_missing_newline(&output_file); + fmt(line.active, line.active + line.length, + cur_cmd->x.int_arg == -1 + ? lcmd_out_line_len + : cur_cmd->x.int_arg, + output_file.fp); + flush_output(output_file.fp); + break; + + case 'n': + if (!no_default_output) + output_line(line.active, line.length, line.chomped, &output_file); + if (test_eof(input) || !read_pattern_space(input, vec, false)) + return -1; + break; + + case 'N': + str_append(&line, &buffer_delimiter, 1); + + if (test_eof(input) || !read_pattern_space(input, vec, true)) + { + line.length--; + if (posixicity == POSIXLY_EXTENDED && !no_default_output) + output_line(line.active, line.length, line.chomped, + &output_file); + return -1; + } + break; + + case 'p': + output_line(line.active, line.length, line.chomped, &output_file); + break; + + case 'P': + { + char *p = memchr(line.active, buffer_delimiter, line.length); + output_line(line.active, p ? p - line.active : line.length, + p ? true : line.chomped, &output_file); + } + break; + + case 'q': + if (!no_default_output) + output_line(line.active, line.length, line.chomped, &output_file); + dump_append_queue(); + + case 'Q': + return cur_cmd->x.int_arg == -1 ? 0 : cur_cmd->x.int_arg; + + case 'r': + if (cur_cmd->x.fname) + { + struct append_queue *aq = next_append_slot(); + aq->fname = cur_cmd->x.fname; + } + break; + + case 'R': + if (cur_cmd->x.fp && !feof (cur_cmd->x.fp)) + { + struct append_queue *aq; + size_t buflen; + char *text = NULL; + int result; + + result = ck_getdelim (&text, &buflen, buffer_delimiter, + cur_cmd->x.fp); + if (result != EOF) + { + aq = next_append_slot(); + aq->free = true; + aq->text = text; + aq->textlen = result; + } + } + break; + + case 's': + do_subst(cur_cmd->x.cmd_subst); + break; + + case 't': + if (replaced) + { + replaced = false; + cur_cmd = vec->v + cur_cmd->x.jump_index; + continue; + } + break; + + case 'T': + if (!replaced) + { + cur_cmd = vec->v + cur_cmd->x.jump_index; + continue; + } + else + replaced = false; + break; + + case 'w': + if (cur_cmd->x.fp) + output_line(line.active, line.length, + line.chomped, cur_cmd->x.outf); + break; + + case 'W': + if (cur_cmd->x.fp) + { + char *p = memchr(line.active, buffer_delimiter, line.length); + output_line(line.active, p ? p - line.active : line.length, + p ? true : line.chomped, cur_cmd->x.outf); + } + break; + + case 'x': + /* See comment above for 'g' regarding the third parameter. */ + line_exchange(&line, &hold, false); + break; + + case 'y': + { + if (mb_cur_max > 1) + { + int idx, prev_idx; /* index in the input line. */ + char **trans; + mbstate_t mbstate; + memset(&mbstate, 0, sizeof(mbstate_t)); + for (idx = 0; idx < line.length;) + { + int mbclen, i; + mbclen = MBRLEN (line.active + idx, line.length - idx, + &mbstate); + /* An invalid sequence, or a truncated multibyte + character. We treat it as a singlebyte character. + */ + if (mbclen == (size_t) -1 || mbclen == (size_t) -2 + || mbclen == 0) + mbclen = 1; + + trans = cur_cmd->x.translatemb; + /* `i' indicate i-th translate pair. */ + for (i = 0; trans[2*i] != NULL; i++) + { + if (strncmp(line.active + idx, trans[2*i], mbclen) == 0) + { + bool move_remain_buffer = false; + int trans_len = strlen(trans[2*i+1]); + + if (mbclen < trans_len) + { + int new_len; + new_len = line.length + 1 + trans_len - mbclen; + /* We must extend the line buffer. */ + if (line.alloc < new_len) + { + /* And we must resize the buffer. */ + resize_line(&line, new_len); + } + move_remain_buffer = true; + } + else if (mbclen > trans_len) + { + /* We must truncate the line buffer. */ + move_remain_buffer = true; + } + prev_idx = idx; + if (move_remain_buffer) + { + int move_len, move_offset; + char *move_from, *move_to; + /* Move the remaining with \0. */ + move_from = line.active + idx + mbclen; + move_to = line.active + idx + trans_len; + move_len = line.length + 1 - idx - mbclen; + move_offset = trans_len - mbclen; + memmove(move_to, move_from, move_len); + line.length += move_offset; + idx += move_offset; + } + strncpy(line.active + prev_idx, trans[2*i+1], + trans_len); + break; + } + } + idx += mbclen; + } + } + else + { + unsigned char *p, *e; + p = (unsigned char *)line.active; + for (e=p+line.length; p<e; ++p) + *p = cur_cmd->x.translate[*p]; + } + } + break; + + case 'z': + line.length = 0; + break; + + case '=': + output_missing_newline(&output_file); + fprintf(output_file.fp, "%lu\n", + (unsigned long)input->line_number); + flush_output(output_file.fp); + break; + + case 'F': + output_missing_newline(&output_file); + fprintf(output_file.fp, "%s\n", + input->in_file_name); + flush_output(output_file.fp); + break; + + default: + panic("INTERNAL ERROR: Bad cmd %c", cur_cmd->cmd); + } + } + +#ifdef EXPERIMENTAL_DASH_N_OPTIMIZATION + /* If our top-level program consists solely of commands with + ADDR_IS_NUM addresses then once we past the last mentioned + line we should be able to quit if no_default_output is true, + or otherwise quickly copy input to output. Now whether this + optimization is a win or not depends on how cheaply we can + implement this for the cases where it doesn't help, as + compared against how much time is saved. One semantic + difference (which I think is an improvement) is that *this* + version will terminate after printing line two in the script + "yes | sed -n 2p". + + Don't use this when in-place editing is active, because line + numbers restart each time then. */ + else if (!separate_files) + { + if (cur_cmd->a1->addr_type == ADDR_IS_NUM + && (cur_cmd->a2 + ? cur_cmd->range_state == RANGE_CLOSED + : cur_cmd->a1->addr_number < input->line_number)) + { + /* Skip this address next time */ + cur_cmd->addr_bang = !cur_cmd->addr_bang; + cur_cmd->a1->addr_type = ADDR_IS_NULL; + if (cur_cmd->a2) + cur_cmd->a2->addr_type = ADDR_IS_NULL; + + /* can we make an optimization? */ + if (cur_cmd->addr_bang) + { + if (cur_cmd->cmd == 'b' || cur_cmd->cmd == 't' + || cur_cmd->cmd == 'T' || cur_cmd->cmd == '}') + branches--; + + cur_cmd->cmd = '#'; /* replace with no-op */ + if (branches == 0) + cur_cmd = shrink_program(vec, cur_cmd); + if (!cur_cmd && no_default_output) + return 0; + end_cmd = vec->v + vec->v_length; + if (!cur_cmd) + cur_cmd = end_cmd; + continue; + } + } + } +#endif /*EXPERIMENTAL_DASH_N_OPTIMIZATION*/ + + /* this is buried down here so that a "continue" statement can skip it */ + ++cur_cmd; + } + + if (!no_default_output) + output_line(line.active, line.length, line.chomped, &output_file); + return -1; +} + + + +/* Apply the compiled script to all the named files. */ +int +process_files(the_program, argv) + struct vector *the_program; + char **argv; +{ + static char dash[] = "-"; + static char *stdin_argv[2] = { dash, NULL }; + struct input input; + int status; + + line_init(&line, NULL, INITIAL_BUFFER_SIZE); + line_init(&hold, NULL, 0); + line_init(&buffer, NULL, 0); + +#ifdef EXPERIMENTAL_DASH_N_OPTIMIZATION + branches = count_branches(the_program); +#endif /*EXPERIMENTAL_DASH_N_OPTIMIZATION*/ + input.reset_at_next_file = true; + if (argv && *argv) + input.file_list = argv; + else if (in_place_extension) + panic(_("no input files")); + else + input.file_list = stdin_argv; + + input.bad_count = 0; + input.line_number = 0; + input.read_fn = read_always_fail; + input.fp = NULL; + + status = EXIT_SUCCESS; + while (read_pattern_space(&input, the_program, false)) + { + status = execute_program(the_program, &input); + if (status == -1) + status = EXIT_SUCCESS; + else + break; + } + closedown(&input); + +#ifdef DEBUG_LEAKS + /* We're about to exit, so these free()s are redundant. + But if we're running under a memory-leak detecting + implementation of malloc(), we want to explicitly + deallocate in order to avoid extraneous noise from + the allocator. */ + release_append_queue(); + free(buffer.text); + free(hold.text); + free(line.text); + free(s_accum.text); +#endif /*DEBUG_LEAKS*/ + + if (input.bad_count) + status = 2; + + return status; +} diff --git a/sed/fmt.c b/sed/fmt.c new file mode 100644 index 0000000..3d15d69 --- /dev/null +++ b/sed/fmt.c @@ -0,0 +1,577 @@ +/* `L' command implementation for GNU sed, based on GNU fmt 1.22. + Copyright (C) 1994, 1995, 1996, 2002, 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + 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 General Public License for more details. + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* GNU fmt was written by Ross Paterson <rap@doc.ic.ac.uk>. */ + +#include "sed.h" + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <sys/types.h> +#include <limits.h> + +/* The following parameters represent the program's idea of what is + "best". Adjust to taste, subject to the caveats given. */ + +/* Prefer lines to be LEEWAY % shorter than the maximum width, giving + room for optimization. */ +#define LEEWAY 7 + +/* Costs and bonuses are expressed as the equivalent departure from the + optimal line length, multiplied by 10. e.g. assigning something a + cost of 50 means that it is as bad as a line 5 characters too short + or too long. The definition of SHORT_COST(n) should not be changed. + However, EQUIV(n) may need tuning. */ + +typedef long COST; + +#define MAXCOST (~(((unsigned long) 1) << (8 * sizeof (COST) -1))) + +#define SQR(n) ((n) * (n)) +#define EQUIV(n) SQR ((COST) (n)) + +/* Cost of a filled line n chars longer or shorter than best_width. */ +#define SHORT_COST(n) EQUIV ((n) * 10) + +/* Cost of the difference between adjacent filled lines. */ +#define RAGGED_COST(n) (SHORT_COST (n) / 2) + +/* Basic cost per line. */ +#define LINE_COST EQUIV (70) + +/* Cost of breaking a line after the first word of a sentence, where + the length of the word is N. */ +#define WIDOW_COST(n) (EQUIV (200) / ((n) + 2)) + +/* Cost of breaking a line before the last word of a sentence, where + the length of the word is N. */ +#define ORPHAN_COST(n) (EQUIV (150) / ((n) + 2)) + +/* Bonus for breaking a line at the end of a sentence. */ +#define SENTENCE_BONUS EQUIV (50) + +/* Cost of breaking a line after a period not marking end of a sentence. + With the definition of sentence we are using (borrowed from emacs, see + get_line()) such a break would then look like a sentence break. Hence + we assign a very high cost -- it should be avoided unless things are + really bad. */ +#define NOBREAK_COST EQUIV (600) + +/* Bonus for breaking a line before open parenthesis. */ +#define PAREN_BONUS EQUIV (40) + +/* Bonus for breaking a line after other punctuation. */ +#define PUNCT_BONUS EQUIV(40) + +/* Credit for breaking a long paragraph one line later. */ +#define LINE_CREDIT EQUIV(3) + +/* Size of paragraph buffer in words. Longer paragraphs are handled + neatly (cf. flush_paragraph()), so there's little to gain by making + these larger. */ +#define MAXWORDS 1000 + +#define GETC() (parabuf == end_of_parabuf ? EOF : *parabuf++) + +/* Extra ctype(3)-style macros. */ + +#define isopen(c) (strchr ("([`'\"", (c)) != NULL) +#define isclose(c) (strchr (")]'\"", (c)) != NULL) +#define isperiod(c) (strchr (".?!", (c)) != NULL) + +/* Size of a tab stop, for expansion on input and re-introduction on + output. */ +#define TABWIDTH 8 + +/* Word descriptor structure. */ + +typedef struct Word WORD; + +struct Word + { + + /* Static attributes determined during input. */ + + const char *text; /* the text of the word */ + short length; /* length of this word */ + short space; /* the size of the following space */ + unsigned paren:1; /* starts with open paren */ + unsigned period:1; /* ends in [.?!])* */ + unsigned punct:1; /* ends in punctuation */ + unsigned final:1; /* end of sentence */ + + /* The remaining fields are computed during the optimization. */ + + short line_length; /* length of the best line starting here */ + COST best_cost; /* cost of best paragraph starting here */ + WORD *next_break; /* break which achieves best_cost */ + }; + +/* Forward declarations. */ + +static bool get_paragraph (void); +static int get_line (int c); +static int get_space (int c); +static int copy_rest (int c); +static bool same_para (int c); +static void flush_paragraph (void); +static void fmt_paragraph (void); +static void check_punctuation (WORD *w); +static COST base_cost (WORD *this); +static COST line_cost (WORD *next, int len); +static void put_paragraph (WORD *finish); +static void put_line (WORD *w, int indent); +static void put_word (WORD *w); +static void put_space (int space); + +/* Option values. */ + +/* User-supplied maximum line width (default WIDTH). The only output + lines + longer than this will each comprise a single word. */ +static int max_width; + +/* Space for the paragraph text. */ +static const char *parabuf; + +/* End of space for the paragraph text. */ +static const char *end_of_parabuf; + +/* The file on which we output */ +static FILE *outfile; + +/* Values derived from the option values. */ + +/* The preferred width of text lines, set to LEEWAY % less than max_width. */ +static int best_width; + +/* Dynamic variables. */ + +/* Start column of the character most recently read from the input file. */ +static int in_column; + +/* Start column of the next character to be written to stdout. */ +static int out_column; + +/* The words of a paragraph -- longer paragraphs are handled neatly + (cf. flush_paragraph()). */ +static WORD words[MAXWORDS]; + +/* A pointer into the above word array, indicating the first position + after the last complete word. Sometimes it will point at an incomplete + word. */ +static WORD *word_limit; + +/* Indentation of the first line of the current paragraph. */ +static int first_indent; + +/* Indentation of other lines of the current paragraph */ +static int other_indent; + +/* The last character read from the input file. */ +static int next_char; + +/* If nonzero, the length of the last line output in the current + paragraph, used to charge for raggedness at the split point for long + paragraphs chosen by fmt_paragraph(). */ +static int last_line_length; + +/* read file F and send formatted output to stdout. */ + +void +fmt (const char *line, const char *line_end, int max_length, FILE *output_file) +{ + parabuf = line; + end_of_parabuf = line_end; + outfile = output_file; + + max_width = max_length; + best_width = max_width * (201 - 2 * LEEWAY) / 200; + + in_column = 0; + other_indent = 0; + next_char = GETC(); + while (get_paragraph ()) + { + fmt_paragraph (); + put_paragraph (word_limit); + } +} + +/* Read a paragraph from input file F. A paragraph consists of a + maximal number of non-blank (excluding any prefix) lines + with the same indent. + + Return false if end-of-file was encountered before the start of a + paragraph, else true. */ + +static bool +get_paragraph () +{ + register int c; + + last_line_length = 0; + c = next_char; + + /* Scan (and copy) blank lines, and lines not introduced by the prefix. */ + + while (c == '\n' || c == EOF) + { + c = copy_rest (c); + if (c == EOF) + { + next_char = EOF; + return false; + } + putc ('\n', outfile); + c = GETC(); + } + + /* Got a suitable first line for a paragraph. */ + + first_indent = in_column; + word_limit = words; + c = get_line (c); + + /* Read rest of paragraph. */ + + other_indent = in_column; + while (same_para (c) && in_column == other_indent) + c = get_line (c); + + (word_limit - 1)->period = (word_limit - 1)->final = true; + next_char = c; + return true; +} + +/* Copy to the output a blank line. In the latter, C is \n or EOF. + Return the character (\n or EOF) ending the line. */ + +static int +copy_rest (register int c) +{ + out_column = 0; + while (c != '\n' && c != EOF) + { + putc (c, outfile); + c = GETC(); + } + return c; +} + +/* Return true if a line whose first non-blank character after the + prefix (if any) is C could belong to the current paragraph, + otherwise false. */ + +static bool +same_para (register int c) +{ + return (c != '\n' && c != EOF); +} + +/* Read a line from the input data given first non-blank character C + after the prefix, and the following indent, and break it into words. + A word is a maximal non-empty string of non-white characters. A word + ending in [.?!]["')\]]* and followed by end-of-line or at least two + spaces ends a sentence, as in emacs. + + Return the first non-blank character of the next line. */ + +static int +get_line (register int c) +{ + int start; + register WORD *end_of_word; + + end_of_word = &words[MAXWORDS - 2]; + + do + { /* for each word in a line */ + + /* Scan word. */ + + word_limit->text = parabuf - 1; + do + c = GETC(); + while (c != EOF && !ISSPACE (c)); + word_limit->length = parabuf - word_limit->text - (c != EOF); + in_column += word_limit->length; + + check_punctuation (word_limit); + + /* Scan inter-word space. */ + + start = in_column; + c = get_space (c); + word_limit->space = in_column - start; + word_limit->final = (c == EOF + || (word_limit->period + && (c == '\n' || word_limit->space > 1))); + if (c == '\n' || c == EOF) + word_limit->space = word_limit->final ? 2 : 1; + if (word_limit == end_of_word) + flush_paragraph (); + word_limit++; + if (c == EOF) + { + in_column = first_indent; + return EOF; + } + } + while (c != '\n'); + + in_column = 0; + c = GETC(); + return get_space (c); +} + +/* Read blank characters from the input data, starting with C, and keeping + in_column up-to-date. Return first non-blank character. */ + +static int +get_space (register int c) +{ + for (;;) + { + if (c == ' ') + in_column++; + else if (c == '\t') + in_column = (in_column / TABWIDTH + 1) * TABWIDTH; + else + return c; + c = GETC(); + } +} + +/* Set extra fields in word W describing any attached punctuation. */ + +static void +check_punctuation (register WORD *w) +{ + register const char *start, *finish; + + start = w->text; + finish = start + (w->length - 1); + w->paren = isopen (*start); + w->punct = ISPUNCT (*finish); + while (isclose (*finish) && finish > start) + finish--; + w->period = isperiod (*finish); +} + +/* Flush part of the paragraph to make room. This function is called on + hitting the limit on the number of words or characters. */ + +static void +flush_paragraph (void) +{ + WORD *split_point; + register WORD *w; + COST best_break; + + /* - format what you have so far as a paragraph, + - find a low-cost line break near the end, + - output to there, + - make that the start of the paragraph. */ + + fmt_paragraph (); + + /* Choose a good split point. */ + + split_point = word_limit; + best_break = MAXCOST; + for (w = words->next_break; w != word_limit; w = w->next_break) + { + if (w->best_cost - w->next_break->best_cost < best_break) + { + split_point = w; + best_break = w->best_cost - w->next_break->best_cost; + } + if (best_break <= MAXCOST - LINE_CREDIT) + best_break += LINE_CREDIT; + } + put_paragraph (split_point); + + /* Copy words from split_point down to word -- we use memmove because + the source and target may overlap. */ + + memmove ((char *) words, (char *) split_point, + (word_limit - split_point + 1) * sizeof (WORD)); + word_limit -= split_point - words; +} + +/* Compute the optimal formatting for the whole paragraph by computing + and remembering the optimal formatting for each suffix from the empty + one to the whole paragraph. */ + +static void +fmt_paragraph (void) +{ + register WORD *start, *w; + register int len; + register COST wcost, best; + int saved_length; + + word_limit->best_cost = 0; + saved_length = word_limit->length; + word_limit->length = max_width; /* sentinel */ + + for (start = word_limit - 1; start >= words; start--) + { + best = MAXCOST; + len = start == words ? first_indent : other_indent; + + /* At least one word, however long, in the line. */ + + w = start; + len += w->length; + do + { + w++; + + /* Consider breaking before w. */ + + wcost = line_cost (w, len) + w->best_cost; + if (start == words && last_line_length > 0) + wcost += RAGGED_COST (len - last_line_length); + if (wcost < best) + { + best = wcost; + start->next_break = w; + start->line_length = len; + } + len += (w - 1)->space + w->length; /* w > start >= words */ + } + while (len < max_width); + start->best_cost = best + base_cost (start); + } + + word_limit->length = saved_length; +} + +/* Return the constant component of the cost of breaking before the + word THIS. */ + +static COST +base_cost (register WORD *this) +{ + register COST cost; + + cost = LINE_COST; + + if (this > words) + { + if ((this - 1)->period) + { + if ((this - 1)->final) + cost -= SENTENCE_BONUS; + else + cost += NOBREAK_COST; + } + else if ((this - 1)->punct) + cost -= PUNCT_BONUS; + else if (this > words + 1 && (this - 2)->final) + cost += WIDOW_COST ((this - 1)->length); + } + + if (this->paren) + cost -= PAREN_BONUS; + else if (this->final) + cost += ORPHAN_COST (this->length); + + return cost; +} + +/* Return the component of the cost of breaking before word NEXT that + depends on LEN, the length of the line beginning there. */ + +static COST +line_cost (register WORD *next, register int len) +{ + register int n; + register COST cost; + + if (next == word_limit) + return 0; + n = best_width - len; + cost = SHORT_COST (n); + if (next->next_break != word_limit) + { + n = len - next->line_length; + cost += RAGGED_COST (n); + } + return cost; +} + +/* Output to stdout a paragraph from word up to (but not including) + FINISH, which must be in the next_break chain from word. */ + +static void +put_paragraph (register WORD *finish) +{ + register WORD *w; + + put_line (words, first_indent); + for (w = words->next_break; w != finish; w = w->next_break) + put_line (w, other_indent); +} + +/* Output to stdout the line beginning with word W, beginning in column + INDENT, including the prefix (if any). */ + +static void +put_line (register WORD *w, int indent) +{ + register WORD *endline; + out_column = 0; + put_space (indent); + + endline = w->next_break - 1; + for (; w != endline; w++) + { + put_word (w); + put_space (w->space); + } + put_word (w); + last_line_length = out_column; + putc ('\n', outfile); +} + +/* Output to stdout the word W. */ + +static void +put_word (register WORD *w) +{ + register const char *s; + register int n; + + s = w->text; + for (n = w->length; n != 0; n--) + putc (*s++, outfile); + out_column += w->length; +} + +/* Output to stdout SPACE spaces, or equivalent tabs. */ + +static void +put_space (int space) +{ + out_column += space; + while (space--) + putc (' ', outfile); +} diff --git a/sed/mbcs.c b/sed/mbcs.c new file mode 100644 index 0000000..964e352 --- /dev/null +++ b/sed/mbcs.c @@ -0,0 +1,60 @@ +/* GNU SED, a batch stream editor. + Copyright (C) 2003, 2006, 2009 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "sed.h" +#include <stdlib.h> +#include <string.h> + +#include "localcharset.h" + +int mb_cur_max; +bool is_utf8; + +/* Add a byte to the multibyte character represented by the state + CUR_STAT, and answer its length if a character is completed, + or -2 if it is yet to be completed. */ +int brlen (ch, cur_stat) + int ch; + mbstate_t *cur_stat; +{ + char c = ch; + + /* If we use the generic brlen, then MBRLEN == mbrlen. */ + int result = mbrtowc(NULL, &c, 1, cur_stat); + + /* An invalid sequence is treated like a singlebyte character. */ + if (result == -1) + { + memset (cur_stat, 0, sizeof (mbstate_t)); + return 1; + } + + return result; +} + +void +initialize_mbcs () +{ + /* For UTF-8, we know that the encoding is stateless. */ + const char *codeset_name; + + codeset_name = locale_charset (); + is_utf8 = (strcmp (codeset_name, "UTF-8") == 0); + + mb_cur_max = MB_CUR_MAX; +} + diff --git a/sed/regexp.c b/sed/regexp.c new file mode 100644 index 0000000..bbeccb5 --- /dev/null +++ b/sed/regexp.c @@ -0,0 +1,267 @@ +/* GNU SED, a batch stream editor. + Copyright (C) 1999, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "sed.h" + +#include <ctype.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +#ifdef gettext_noop +# define N_(String) gettext_noop(String) +#else +# define N_(String) (String) +#endif + +extern bool use_extended_syntax_p; + +static const char errors[] = + "no previous regular expression\0" + "cannot specify modifiers on empty regexp"; + +#define NO_REGEX (errors) +#define BAD_MODIF (NO_REGEX + sizeof(N_("no previous regular expression"))) +#define END_ERRORS (BAD_MODIF + sizeof(N_("cannot specify modifiers on empty regexp"))) + + + +static void +compile_regex_1 (new_regex, needed_sub) + struct regex *new_regex; + int needed_sub; +{ +#ifdef REG_PERL + int errcode; + errcode = regncomp(&new_regex->pattern, new_regex->re, new_regex->sz, + (needed_sub ? 0 : REG_NOSUB) + | new_regex->flags + | extended_regexp_flags); + + if (errcode) + { + char errorbuf[200]; + regerror(errcode, NULL, errorbuf, 200); + bad_prog(gettext(errorbuf)); + } +#else + const char *error; + int syntax = ((extended_regexp_flags & REG_EXTENDED) + ? RE_SYNTAX_POSIX_EXTENDED + : RE_SYNTAX_POSIX_BASIC); + + syntax &= ~RE_DOT_NOT_NULL; + syntax |= RE_NO_POSIX_BACKTRACKING; + + switch (posixicity) + { + case POSIXLY_EXTENDED: + syntax &= ~RE_UNMATCHED_RIGHT_PAREN_ORD; + break; + case POSIXLY_CORRECT: + syntax |= RE_UNMATCHED_RIGHT_PAREN_ORD; + break; + case POSIXLY_BASIC: + syntax |= RE_UNMATCHED_RIGHT_PAREN_ORD | RE_LIMITED_OPS | RE_NO_GNU_OPS; + break; + } + +#ifdef RE_ICASE + syntax |= (new_regex->flags & REG_ICASE) ? RE_ICASE : 0; +#endif +#ifdef RE_NO_SUB + syntax |= needed_sub ? 0 : RE_NO_SUB; +#endif + + new_regex->pattern.fastmap = malloc (1 << (sizeof (char) * 8)); + + /* If REG_NEWLINE is set, newlines are treated differently. */ + if (new_regex->flags & REG_NEWLINE) + { + /* REG_NEWLINE implies neither . nor [^...] match newline. */ + syntax &= ~RE_DOT_NEWLINE; + syntax |= RE_HAT_LISTS_NOT_NEWLINE; + } + + re_set_syntax (syntax); + error = re_compile_pattern (new_regex->re, new_regex->sz, + &new_regex->pattern); + new_regex->pattern.newline_anchor = (new_regex->flags & REG_NEWLINE) != 0; + + new_regex->pattern.translate = NULL; +#ifndef RE_ICASE + if (new_regex->flags & REG_ICASE) + { + static char translate[1 << (sizeof(char) * 8)]; + int i; + for (i = 0; i < sizeof(translate) / sizeof(char); i++) + translate[i] = tolower (i); + + new_regex->pattern.translate = translate; + } +#endif + + if (error) + bad_prog(error); +#endif + + /* Just to be sure, I mark this as not POSIXLY_CORRECT behavior */ + if (needed_sub + && new_regex->pattern.re_nsub < needed_sub - 1 + && posixicity == POSIXLY_EXTENDED) + { + char buf[200]; + sprintf(buf, _("invalid reference \\%d on `s' command's RHS"), + needed_sub - 1); + bad_prog(buf); + } +} + +struct regex * +compile_regex(b, flags, needed_sub) + struct buffer *b; + int flags; + int needed_sub; +{ + struct regex *new_regex; + size_t re_len; + + /* // matches the last RE */ + if (size_buffer(b) == 0) + { + if (flags > 0) + bad_prog(_(BAD_MODIF)); + return NULL; + } + + re_len = size_buffer(b); + new_regex = ck_malloc(sizeof (struct regex) + re_len - 1); + new_regex->flags = flags; + memcpy (new_regex->re, get_buffer(b), re_len); + +#ifdef REG_PERL + new_regex->sz = re_len; +#else + /* GNU regex does not process \t & co. */ + new_regex->sz = normalize_text(new_regex->re, re_len, TEXT_REGEX); +#endif + + compile_regex_1 (new_regex, needed_sub); + return new_regex; +} + +#ifdef REG_PERL +static void +copy_regs (regs, pmatch, nregs) + struct re_registers *regs; + regmatch_t *pmatch; + int nregs; +{ + int i; + int need_regs = nregs + 1; + /* We need one extra element beyond `num_regs' for the `-1' marker GNU code + uses. */ + + /* Have the register data arrays been allocated? */ + if (!regs->start) + { /* No. So allocate them with malloc. */ + regs->start = MALLOC (need_regs, regoff_t); + regs->end = MALLOC (need_regs, regoff_t); + regs->num_regs = need_regs; + } + else if (need_regs > regs->num_regs) + { /* Yes. We also need more elements than were already + allocated, so reallocate them. */ + regs->start = REALLOC (regs->start, need_regs, regoff_t); + regs->end = REALLOC (regs->end, need_regs, regoff_t); + regs->num_regs = need_regs; + } + + /* Copy the regs. */ + for (i = 0; i < nregs; ++i) + { + regs->start[i] = pmatch[i].rm_so; + regs->end[i] = pmatch[i].rm_eo; + } + for ( ; i < regs->num_regs; ++i) + regs->start[i] = regs->end[i] = -1; +} +#endif + +int +match_regex(regex, buf, buflen, buf_start_offset, regarray, regsize) + struct regex *regex; + char *buf; + size_t buflen; + size_t buf_start_offset; + struct re_registers *regarray; + int regsize; +{ + int ret; + static struct regex *regex_last; +#ifdef REG_PERL + regmatch_t rm[10], *regmatch = rm; + if (regsize > 10) + regmatch = (regmatch_t *) alloca (sizeof (regmatch_t) * regsize); +#endif + + /* printf ("Matching from %d/%d\n", buf_start_offset, buflen); */ + + /* Keep track of the last regexp matched. */ + if (!regex) + { + regex = regex_last; + if (!regex_last) + bad_prog(_(NO_REGEX)); + } + else + regex_last = regex; + +#ifdef REG_PERL + regmatch[0].rm_so = (int)buf_start_offset; + regmatch[0].rm_eo = (int)buflen; + ret = regexec (®ex->pattern, buf, regsize, regmatch, REG_STARTEND); + + if (regsize) + copy_regs (regarray, regmatch, regsize); + + return (ret == 0); +#else + if (regex->pattern.no_sub && regsize) + compile_regex_1 (regex, regsize); + + regex->pattern.regs_allocated = REGS_REALLOCATE; + + ret = re_search (®ex->pattern, buf, buflen, buf_start_offset, + buflen - buf_start_offset, + regsize ? regarray : NULL); + + return (ret > -1); +#endif +} + + +#ifdef DEBUG_LEAKS +void +release_regex(regex) + struct regex *regex; +{ + regfree(®ex->pattern); + free(regex); +} +#endif /*DEBUG_LEAKS*/ diff --git a/sed/sed.c b/sed/sed.c new file mode 100644 index 0000000..af985e6 --- /dev/null +++ b/sed/sed.c @@ -0,0 +1,335 @@ +/* GNU SED, a batch stream editor. + Copyright (C) 1989,90,91,92,93,94,95,98,99,2002,2003,2006,2008,2009,2010 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + + +#include "sed.h" + + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> +#include "getopt.h" + +#include "version-etc.h" + +#define AUTHORS \ + _("Jay Fenlason"), \ + _("Tom Lord"), \ + _("Ken Pizzini"), \ + _("Paolo Bonzini") + +char *program_name; + +int extended_regexp_flags = 0; + +/* one-byte buffer delimiter */ +char buffer_delimiter = '\n'; + +/* If set, fflush(stdout) on every line output. */ +bool unbuffered = false; + +/* If set, don't write out the line unless explicitly told to */ +bool no_default_output = false; + +/* If set, reset line counts on every new file. */ +bool separate_files = false; + +/* If set, follow symlinks when processing in place */ +bool follow_symlinks = false; + +/* How do we edit files in-place? (we don't if NULL) */ +char *in_place_extension = NULL; + +/* The mode to use to read/write files, either "r"/"w" or "rb"/"wb". */ +char *read_mode = "r"; +char *write_mode = "w"; + +/* Do we need to be pedantically POSIX compliant? */ +enum posixicity_types posixicity; + +/* How long should the `l' command's output line be? */ +countT lcmd_out_line_len = 70; + +/* The complete compiled SED program that we are going to run: */ +static struct vector *the_program = NULL; + +static void usage (int); +static void +contact(errmsg) + int errmsg; +{ + FILE *out = errmsg ? stderr : stdout; +#ifndef REG_PERL + fprintf(out, _("GNU sed home page: <http://www.gnu.org/software/sed/>.\n\ +General help using GNU software: <http://www.gnu.org/gethelp/>.\n")); +#endif + + /* Only print the bug report address for `sed --help', otherwise we'll + get reports for other people's bugs. */ + if (!errmsg) + fprintf(out, _("E-mail bug reports to: <%s>.\n\ +Be sure to include the word ``%s'' somewhere in the ``Subject:'' field.\n"), + PACKAGE_BUGREPORT, PACKAGE); +} + +static void usage (int); +static void +usage(status) + int status; +{ + FILE *out = status ? stderr : stdout; + +#ifdef REG_PERL +#define PERL_HELP _(" -R, --regexp-perl\n use Perl 5's regular expressions syntax in the script.\n") +#else +#define PERL_HELP "" +#endif + + fprintf(out, _("\ +Usage: %s [OPTION]... {script-only-if-no-other-script} [input-file]...\n\ +\n"), myname); + + fprintf(out, _(" -n, --quiet, --silent\n\ + suppress automatic printing of pattern space\n")); + fprintf(out, _(" -e script, --expression=script\n\ + add the script to the commands to be executed\n")); + fprintf(out, _(" -f script-file, --file=script-file\n\ + add the contents of script-file to the commands to be executed\n")); +#ifdef ENABLE_FOLLOW_SYMLINKS + fprintf(out, _(" --follow-symlinks\n\ + follow symlinks when processing in place\n")); +#endif + fprintf(out, _(" -i[SUFFIX], --in-place[=SUFFIX]\n\ + edit files in place (makes backup if SUFFIX supplied)\n")); +#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(MSDOS) || defined(__EMX__) + fprintf(out, _(" -b, --binary\n\ + open files in binary mode (CR+LFs are not processed specially)\n")); +#endif + fprintf(out, _(" -l N, --line-length=N\n\ + specify the desired line-wrap length for the `l' command\n")); + fprintf(out, _(" --posix\n\ + disable all GNU extensions.\n")); + fprintf(out, _(" -r, --regexp-extended\n\ + use extended regular expressions in the script.\n")); +#ifdef REG_PERL + fprintf(out, PERL_HELP); +#endif + fprintf(out, _(" -s, --separate\n\ + consider files as separate rather than as a single continuous\n\ + long stream.\n")); + fprintf(out, _(" -u, --unbuffered\n\ + load minimal amounts of data from the input files and flush\n\ + the output buffers more often\n")); + fprintf(out, _(" -z, --null-data\n\ + separate lines by NUL characters\n")); + fprintf(out, _(" --help display this help and exit\n")); + fprintf(out, _(" --version output version information and exit\n")); + fprintf(out, _("\n\ +If no -e, --expression, -f, or --file option is given, then the first\n\ +non-option argument is taken as the sed script to interpret. All\n\ +remaining arguments are names of input files; if no input files are\n\ +specified, then the standard input is read.\n\ +\n")); + contact (status); + + ck_fclose (NULL); + exit (status); +} + +int +main(argc, argv) + int argc; + char **argv; +{ +#ifdef REG_PERL +#define SHORTOPTS "bsnrzRuEe:f:l:i::V:" +#else +#define SHORTOPTS "bsnrzuEe:f:l:i::V:" +#endif + + static struct option longopts[] = { + {"binary", 0, NULL, 'b'}, + {"regexp-extended", 0, NULL, 'r'}, +#ifdef REG_PERL + {"regexp-perl", 0, NULL, 'R'}, +#endif + {"expression", 1, NULL, 'e'}, + {"file", 1, NULL, 'f'}, + {"in-place", 2, NULL, 'i'}, + {"line-length", 1, NULL, 'l'}, + {"null-data", 0, NULL, 'z'}, + {"zero-terminated", 0, NULL, 'z'}, + {"quiet", 0, NULL, 'n'}, + {"posix", 0, NULL, 'p'}, + {"silent", 0, NULL, 'n'}, + {"separate", 0, NULL, 's'}, + {"unbuffered", 0, NULL, 'u'}, + {"version", 0, NULL, 'v'}, + {"help", 0, NULL, 'h'}, +#ifdef ENABLE_FOLLOW_SYMLINKS + {"follow-symlinks", 0, NULL, 'F'}, +#endif + {NULL, 0, NULL, 0} + }; + + int opt; + int return_code; + const char *cols = getenv("COLS"); + + program_name = argv[0]; + initialize_main (&argc, &argv); +#if HAVE_SETLOCALE + /* Set locale according to user's wishes. */ + setlocale (LC_ALL, ""); +#endif + initialize_mbcs (); + +#if ENABLE_NLS + + /* Tell program which translations to use and where to find. */ + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); +#endif + + if (getenv("POSIXLY_CORRECT") != NULL) + posixicity = POSIXLY_CORRECT; + else + posixicity = POSIXLY_EXTENDED; + + /* If environment variable `COLS' is set, use its value for + the baseline setting of `lcmd_out_line_len'. The "-1" + is to avoid gratuitous auto-line-wrap on ttys. + */ + if (cols) + { + countT t = atoi(cols); + if (t > 1) + lcmd_out_line_len = t-1; + } + + myname = *argv; + while ((opt = getopt_long(argc, argv, SHORTOPTS, longopts, NULL)) != EOF) + { + switch (opt) + { + case 'n': + no_default_output = true; + break; + case 'e': + the_program = compile_string(the_program, optarg, strlen(optarg)); + break; + case 'f': + the_program = compile_file(the_program, optarg); + break; + + case 'z': + buffer_delimiter = 0; + break; + + case 'F': + follow_symlinks = true; + break; + + case 'i': + separate_files = true; + if (optarg == NULL) + /* use no backups */ + in_place_extension = ck_strdup ("*"); + + else if (strchr(optarg, '*') != NULL) + in_place_extension = ck_strdup(optarg); + + else + { + in_place_extension = MALLOC (strlen(optarg) + 2, char); + in_place_extension[0] = '*'; + strcpy (in_place_extension + 1, optarg); + } + + break; + + case 'l': + lcmd_out_line_len = atoi(optarg); + break; + + case 'p': + posixicity = POSIXLY_BASIC; + break; + + case 'b': + read_mode = "rb"; + write_mode = "wb"; + break; + + /* Undocumented, for compatibility with BSD sed. */ + case 'E': + case 'r': + if (extended_regexp_flags) + usage(4); + extended_regexp_flags = REG_EXTENDED; + break; + +#ifdef REG_PERL + case 'R': + if (extended_regexp_flags) + usage(4); + extended_regexp_flags = REG_PERL; + break; +#endif + + case 's': + separate_files = true; + break; + + case 'u': + unbuffered = true; + break; + + case 'v': + version_etc(stdout, program_name, PACKAGE_NAME, VERSION, + AUTHORS, (char *) NULL); + contact(false); + ck_fclose (NULL); + exit (0); + case 'h': + usage(0); + default: + usage(4); + } + } + + if (!the_program) + { + if (optind < argc) + { + char *arg = argv[optind++]; + the_program = compile_string(the_program, arg, strlen(arg)); + } + else + usage(4); + } + check_final_program(the_program); + + return_code = process_files(the_program, argv+optind); + + finish_program(the_program); + ck_fclose(NULL); + + return return_code; +} diff --git a/sed/sed.h b/sed/sed.h new file mode 100644 index 0000000..2c6aff5 --- /dev/null +++ b/sed/sed.h @@ -0,0 +1,265 @@ +/* GNU SED, a batch stream editor. + Copyright (C) 1989,90,91,92,93,94,95,98,99,2002,2003 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "config.h" +#include "basicdefs.h" +#include "regex.h" +#include <stdio.h> +#include "unlocked-io.h" + +#include "utils.h" + +/* Struct vector is used to describe a compiled sed program. */ +struct vector { + struct sed_cmd *v; /* a dynamically allocated array */ + size_t v_allocated; /* ... number slots allocated */ + size_t v_length; /* ... number of slots in use */ +}; + +/* This structure tracks files used by sed so that they may all be + closed cleanly at normal program termination. A flag is kept that tells + if a missing newline was encountered, so that it is added on the + next line and the two lines are not concatenated. */ +struct output { + char *name; + bool missing_newline; + FILE *fp; + struct output *link; +}; + +struct text_buf { + char *text; + size_t text_length; +}; + +struct regex { + regex_t pattern; + int flags; + size_t sz; + char re[1]; +}; + +enum replacement_types { + REPL_ASIS = 0, + REPL_UPPERCASE = 1, + REPL_LOWERCASE = 2, + REPL_UPPERCASE_FIRST = 4, + REPL_LOWERCASE_FIRST = 8, + REPL_MODIFIERS = REPL_UPPERCASE_FIRST | REPL_LOWERCASE_FIRST, + + /* These are given to aid in debugging */ + REPL_UPPERCASE_UPPERCASE = REPL_UPPERCASE_FIRST | REPL_UPPERCASE, + REPL_UPPERCASE_LOWERCASE = REPL_UPPERCASE_FIRST | REPL_LOWERCASE, + REPL_LOWERCASE_UPPERCASE = REPL_LOWERCASE_FIRST | REPL_UPPERCASE, + REPL_LOWERCASE_LOWERCASE = REPL_LOWERCASE_FIRST | REPL_LOWERCASE +}; + +enum text_types { + TEXT_BUFFER, + TEXT_REPLACEMENT, + TEXT_REGEX +}; + +enum posixicity_types { + POSIXLY_EXTENDED, /* with GNU extensions */ + POSIXLY_CORRECT, /* with POSIX-compatible GNU extensions */ + POSIXLY_BASIC /* pedantically POSIX */ +}; + +enum addr_state { + RANGE_INACTIVE, /* never been active */ + RANGE_ACTIVE, /* between first and second address */ + RANGE_CLOSED /* like RANGE_INACTIVE, but range has ended once */ +}; + +enum addr_types { + ADDR_IS_NULL, /* null address */ + ADDR_IS_REGEX, /* a.addr_regex is valid */ + ADDR_IS_NUM, /* a.addr_number is valid */ + ADDR_IS_NUM_MOD, /* a.addr_number is valid, addr_step is modulo */ + ADDR_IS_STEP, /* address is +N (only valid for addr2) */ + ADDR_IS_STEP_MOD, /* address is ~N (only valid for addr2) */ + ADDR_IS_LAST /* address is $ */ +}; + +struct addr { + enum addr_types addr_type; + countT addr_number; + countT addr_step; + struct regex *addr_regex; +}; + + +struct replacement { + char *prefix; + size_t prefix_length; + int subst_id; + enum replacement_types repl_type; + struct replacement *next; +}; + +struct subst { + struct regex *regx; + struct replacement *replacement; + countT numb; /* if >0, only substitute for match number "numb" */ + struct output *outf; /* 'w' option given */ + unsigned global : 1; /* 'g' option given */ + unsigned print : 2; /* 'p' option given (before/after eval) */ + unsigned eval : 1; /* 'e' option given */ + unsigned max_id : 4; /* maximum backreference on the RHS */ +}; + +#ifdef REG_PERL +/* This is the structure we store register match data in. See + regex.texinfo for a full description of what registers match. */ +struct re_registers +{ + unsigned num_regs; + regoff_t *start; + regoff_t *end; +}; +#endif + + + +struct sed_cmd { + struct addr *a1; /* save space: usually is NULL */ + struct addr *a2; + + /* See description the enum, above. */ + enum addr_state range_state; + + /* Non-zero if command is to be applied to non-matches. */ + char addr_bang; + + /* The actual command character. */ + char cmd; + + /* auxiliary data for various commands */ + union { + /* This structure is used for a, i, and c commands. */ + struct text_buf cmd_txt; + + /* This is used for the l, q and Q commands. */ + int int_arg; + + /* This is used for the {}, b, and t commands. */ + countT jump_index; + + /* This is used for the r command. */ + char *fname; + + /* This is used for the hairy s command. */ + struct subst *cmd_subst; + + /* This is used for the w command. */ + struct output *outf; + + /* This is used for the R command. */ + FILE *fp; + + /* This is used for the y command. */ + unsigned char *translate; + char **translatemb; + } x; +}; + + + +void bad_prog (const char *why); +size_t normalize_text (char *text, size_t len, enum text_types buftype); +struct vector *compile_string (struct vector *, char *str, size_t len); +struct vector *compile_file (struct vector *, const char *cmdfile); +void check_final_program (struct vector *); +void rewind_read_files (void); +void finish_program (struct vector *); + +struct regex *compile_regex (struct buffer *b, int flags, int needed_sub); +int match_regex (struct regex *regex, + char *buf, size_t buflen, size_t buf_start_offset, + struct re_registers *regarray, int regsize); +#ifdef DEBUG_LEAKS +void release_regex (struct regex *); +#endif + +int process_files (struct vector *, char **argv); + +int main (int, char **); + +extern void fmt (const char *line, const char *line_end, int max_length, FILE *output_file); + +extern int extended_regexp_flags; + +/* one-byte buffer delimiter */ +extern char buffer_delimiter; + +/* If set, fflush(stdout) on every line output, + and turn off stream buffering on inputs. */ +extern bool unbuffered; + +/* If set, don't write out the line unless explicitly told to. */ +extern bool no_default_output; + +/* If set, reset line counts on every new file. */ +extern bool separate_files; + +/* If set, follow symlinks when invoked with -i option */ +extern bool follow_symlinks; + +/* Do we need to be pedantically POSIX compliant? */ +extern enum posixicity_types posixicity; + +/* How long should the `l' command's output line be? */ +extern countT lcmd_out_line_len; + +/* How do we edit files in-place? (we don't if NULL) */ +extern char *in_place_extension; + +/* The mode to use to read and write files, either "rt"/"w" or "rb"/"wb". */ +extern char *read_mode; +extern char *write_mode; + +/* Should we use EREs? */ +extern bool use_extended_syntax_p; + +/* Declarations for multibyte character sets. */ +extern int mb_cur_max; +extern bool is_utf8; + +#define MBRTOWC(pwc, s, n, ps) \ + (mb_cur_max == 1 ? \ + (*(pwc) = btowc (*(unsigned char *) (s)), 1) : \ + mbrtowc ((pwc), (s), (n), (ps))) + +#define WCRTOMB(s, wc, ps) \ + (mb_cur_max == 1 ? \ + (*(s) = wctob ((wint_t) (wc)), 1) : \ + wcrtomb ((s), (wc), (ps))) + +#define MBSINIT(s) \ + (mb_cur_max == 1 ? 1 : mbsinit ((s))) + +#define MBRLEN(s, n, ps) \ + (mb_cur_max == 1 ? 1 : mbrtowc (NULL, s, n, ps)) + +#define BRLEN(ch, ps) \ + (mb_cur_max == 1 ? 1 : brlen (ch, ps)) + +extern int brlen (int ch, mbstate_t *ps); +extern void initialize_mbcs (void); + diff --git a/sed/utils.c b/sed/utils.c new file mode 100644 index 0000000..aa674fd --- /dev/null +++ b/sed/utils.c @@ -0,0 +1,599 @@ +/* Functions from hack's utils library. + Copyright (C) 1989, 1990, 1991, 1998, 1999, 2003, 2008, 2009, 2011 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "config.h" + +#include <stdio.h> +#include <stdarg.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <limits.h> + +#include "utils.h" +#include "pathmax.h" +#include "fwriting.h" + +const char *myname; + +/* Store information about files opened with ck_fopen + so that error messages from ck_fread, ck_fwrite, etc. can print the + name of the file that had the error */ + +struct open_file + { + FILE *fp; + char *name; + struct open_file *link; + unsigned temp : 1; + }; + +static struct open_file *open_files = NULL; +static void do_ck_fclose (FILE *fp); + +/* Print an error message and exit */ + +void +panic(const char *str, ...) +{ + va_list ap; + + fprintf(stderr, "%s: ", myname); + va_start(ap, str); + vfprintf(stderr, str, ap); + va_end(ap); + putc('\n', stderr); + + /* Unlink the temporary files. */ + while (open_files) + { + if (open_files->temp) + { + fclose (open_files->fp); + errno = 0; + unlink (open_files->name); + if (errno != 0) + fprintf (stderr, _("cannot remove %s: %s"), open_files->name, strerror (errno)); + } + + open_files = open_files->link; + } + + exit(4); +} + + +/* Internal routine to get a filename from open_files */ +static const char *utils_fp_name (FILE *fp); +static const char * +utils_fp_name(fp) + FILE *fp; +{ + struct open_file *p; + + for (p=open_files; p; p=p->link) + if (p->fp == fp) + return p->name; + if (fp == stdin) + return "stdin"; + else if (fp == stdout) + return "stdout"; + else if (fp == stderr) + return "stderr"; + + return "<unknown>"; +} + +static void +register_open_file (fp, name, temp) + FILE *fp; + const char *name; + int temp; +{ + struct open_file *p; + for (p=open_files; p; p=p->link) + { + if (fp == p->fp) + { + free(p->name); + break; + } + } + if (!p) + { + p = MALLOC(1, struct open_file); + p->link = open_files; + open_files = p; + } + p->name = ck_strdup(name); + p->fp = fp; + p->temp = false; +} + +/* Panic on failing fopen */ +FILE * +ck_fopen(name, mode, fail) + const char *name; + const char *mode; + int fail; +{ + FILE *fp; + + fp = fopen (name, mode); + if (!fp) + { + if (fail) + panic(_("couldn't open file %s: %s"), name, strerror(errno)); + + return NULL; + } + + register_open_file (fp, name, false); + return fp; +} + +/* Panic on failing fdopen */ +FILE * +ck_fdopen(fd, name, mode, fail) + int fd; + const char *name; + const char *mode; + int fail; +{ + FILE *fp; + + fp = fdopen (fd, mode); + if (!fp) + { + if (fail) + panic(_("couldn't attach to %s: %s"), name, strerror(errno)); + + return NULL; + } + + register_open_file (fp, name, false); + return fp; +} + +FILE * +ck_mkstemp (p_filename, tmpdir, base, mode) + char **p_filename; + const char *base, *tmpdir; + const char *mode; +{ + char *template; + FILE *fp; + int fd; + int save_umask; + + if (tmpdir == NULL) + tmpdir = getenv("TMPDIR"); + if (tmpdir == NULL) + { + tmpdir = getenv("TMP"); + if (tmpdir == NULL) +#ifdef P_tmpdir + tmpdir = P_tmpdir; +#else + tmpdir = "/tmp"; +#endif + } + + template = xmalloc (strlen (tmpdir) + strlen (base) + 8); + sprintf (template, "%s/%sXXXXXX", tmpdir, base); + + /* The ownership might change, so omit some permissions at first + so unauthorized users cannot nip in before the file is ready. + + mkstemp forces O_BINARY on cygwin, so use mkostemp instead. */ + save_umask = umask (0700); + fd = mkostemp (template, 0); + umask (save_umask); + if (fd == -1) + panic(_("couldn't open temporary file %s: %s"), template, strerror(errno)); + + *p_filename = template; + fp = fdopen (fd, mode); + register_open_file (fp, template, true); + return fp; +} + +/* Panic on failing fwrite */ +void +ck_fwrite(ptr, size, nmemb, stream) + const void *ptr; + size_t size; + size_t nmemb; + FILE *stream; +{ + clearerr(stream); + if (size && fwrite(ptr, size, nmemb, stream) != nmemb) + panic(ngettext("couldn't write %d item to %s: %s", + "couldn't write %d items to %s: %s", nmemb), + nmemb, utils_fp_name(stream), strerror(errno)); +} + +/* Panic on failing fread */ +size_t +ck_fread(ptr, size, nmemb, stream) + void *ptr; + size_t size; + size_t nmemb; + FILE *stream; +{ + clearerr(stream); + if (size && (nmemb=fread(ptr, size, nmemb, stream)) <= 0 && ferror(stream)) + panic(_("read error on %s: %s"), utils_fp_name(stream), strerror(errno)); + + return nmemb; +} + +size_t +ck_getdelim(text, buflen, buffer_delimiter, stream) + char **text; + size_t *buflen; + char buffer_delimiter; + FILE *stream; +{ + ssize_t result; + bool error; + + error = ferror (stream); + if (!error) + { + result = getdelim (text, buflen, buffer_delimiter, stream); + error = ferror (stream); + } + + if (error) + panic (_("read error on %s: %s"), utils_fp_name(stream), strerror(errno)); + + return result; +} + +/* Panic on failing fflush */ +void +ck_fflush(stream) + FILE *stream; +{ + if (!fwriting(stream)) + return; + + clearerr(stream); + if (fflush(stream) == EOF && errno != EBADF) + panic("couldn't flush %s: %s", utils_fp_name(stream), strerror(errno)); +} + +/* Panic on failing fclose */ +void +ck_fclose(stream) + FILE *stream; +{ + struct open_file r; + struct open_file *prev; + struct open_file *cur; + + /* a NULL stream means to close all files */ + r.link = open_files; + prev = &r; + while ( (cur = prev->link) ) + { + if (!stream || stream == cur->fp) + { + do_ck_fclose (cur->fp); + prev->link = cur->link; + free(cur->name); + free(cur); + } + else + prev = cur; + } + + open_files = r.link; + + /* Also care about stdout, because if it is redirected the + last output operations might fail and it is important + to signal this as an error (perhaps to make). */ + if (!stream) + { + do_ck_fclose (stdout); + do_ck_fclose (stderr); + } +} + +/* Close a single file. */ +void +do_ck_fclose(fp) + FILE *fp; +{ + ck_fflush(fp); + clearerr(fp); + + if (fclose(fp) == EOF) + panic("couldn't close %s: %s", utils_fp_name(fp), strerror(errno)); +} + + +/* Follow symlink and panic if something fails. Return the ultimate + symlink target, stored in a temporary buffer that the caller should + not free. */ +const char * +follow_symlink(const char *fname) +{ +#ifdef ENABLE_FOLLOW_SYMLINKS + static char *buf1, *buf2; + static int buf_size; + + struct stat statbuf; + const char *buf = fname, *c; + int rc; + + if (buf_size == 0) + { + buf1 = ck_malloc (PATH_MAX + 1); + buf2 = ck_malloc (PATH_MAX + 1); + buf_size = PATH_MAX + 1; + } + + while ((rc = lstat (buf, &statbuf)) == 0 + && (statbuf.st_mode & S_IFLNK) == S_IFLNK) + { + if (buf == buf2) + { + strcpy (buf1, buf2); + buf = buf1; + } + + while ((rc = readlink (buf, buf2, buf_size)) == buf_size) + { + buf_size *= 2; + buf1 = ck_realloc (buf1, buf_size); + buf2 = ck_realloc (buf2, buf_size); + } + if (rc < 0) + panic (_("couldn't follow symlink %s: %s"), buf, strerror(errno)); + else + buf2 [rc] = '\0'; + + if (buf2[0] != '/' && (c = strrchr (buf, '/')) != NULL) + { + /* Need to handle relative paths with care. Reallocate buf1 and + buf2 to be big enough. */ + int len = c - buf + 1; + if (len + rc + 1 > buf_size) + { + buf_size = len + rc + 1; + buf1 = ck_realloc (buf1, buf_size); + buf2 = ck_realloc (buf2, buf_size); + } + + /* Always store the new path in buf1. */ + if (buf != buf1) + memcpy (buf1, buf, len); + + /* Tack the relative symlink at the end of buf1. */ + memcpy (buf1 + len, buf2, rc + 1); + buf = buf1; + } + else + { + /* Use buf2 as the buffer, it saves a strcpy if it is not pointing to + another link. It works for absolute symlinks, and as long as + symlinks do not leave the current directory. */ + buf = buf2; + } + } + + if (rc < 0) + panic (_("cannot stat %s: %s"), buf, strerror(errno)); + + return buf; +#else + return fname; +#endif /* ENABLE_FOLLOW_SYMLINKS */ +} + +/* Panic on failing rename */ +void +ck_rename (from, to, unlink_if_fail) + const char *from, *to; + const char *unlink_if_fail; +{ + int rd = rename (from, to); + if (rd != -1) + return; + + if (unlink_if_fail) + { + int save_errno = errno; + errno = 0; + unlink (unlink_if_fail); + + /* Failure to remove the temporary file is more severe, so trigger it first. */ + if (errno != 0) + panic (_("cannot remove %s: %s"), unlink_if_fail, strerror (errno)); + + errno = save_errno; + } + + panic (_("cannot rename %s: %s"), from, strerror (errno)); +} + + + + +/* Panic on failing malloc */ +void * +ck_malloc(size) + size_t size; +{ + void *ret = calloc(1, size ? size : 1); + if (!ret) + panic("couldn't allocate memory"); + return ret; +} + +/* Panic on failing realloc */ +void * +ck_realloc(ptr, size) + void *ptr; + size_t size; +{ + void *ret; + + if (size == 0) + { + free(ptr); + return NULL; + } + if (!ptr) + return ck_malloc(size); + ret = realloc(ptr, size); + if (!ret) + panic("couldn't re-allocate memory"); + return ret; +} + +/* Return a malloc()'d copy of a string */ +char * +ck_strdup(str) + const char *str; +{ + char *ret = MALLOC(strlen(str)+1, char); + return strcpy(ret, str); +} + +/* Return a malloc()'d copy of a block of memory */ +void * +ck_memdup(buf, len) + const void *buf; + size_t len; +{ + void *ret = ck_malloc(len); + return memcpy(ret, buf, len); +} + + +/* Implement a variable sized buffer of `stuff'. We don't know what it is, +nor do we care, as long as it doesn't mind being aligned by malloc. */ + +struct buffer + { + size_t allocated; + size_t length; + char *b; + }; + +#define MIN_ALLOCATE 50 + +struct buffer * +init_buffer() +{ + struct buffer *b = MALLOC(1, struct buffer); + b->b = MALLOC(MIN_ALLOCATE, char); + b->allocated = MIN_ALLOCATE; + b->length = 0; + return b; +} + +char * +get_buffer(b) + struct buffer *b; +{ + return b->b; +} + +size_t +size_buffer(b) + struct buffer *b; +{ + return b->length; +} + +static void resize_buffer (struct buffer *b, size_t newlen); +static void +resize_buffer(b, newlen) + struct buffer *b; + size_t newlen; +{ + char *try = NULL; + size_t alen = b->allocated; + + if (newlen <= alen) + return; + alen *= 2; + if (newlen < alen) + try = realloc(b->b, alen); /* Note: *not* the REALLOC() macro! */ + if (!try) + { + alen = newlen; + try = REALLOC(b->b, alen, char); + } + b->allocated = alen; + b->b = try; +} + +char * +add_buffer(b, p, n) + struct buffer *b; + const char *p; + size_t n; +{ + char *result; + if (b->allocated - b->length < n) + resize_buffer(b, b->length+n); + result = memcpy(b->b + b->length, p, n); + b->length += n; + return result; +} + +char * +add1_buffer(b, c) + struct buffer *b; + int c; +{ + /* This special case should be kept cheap; + * don't make it just a mere convenience + * wrapper for add_buffer() -- even "builtin" + * versions of memcpy(a, b, 1) can become + * expensive when called too often. + */ + if (c != EOF) + { + char *result; + if (b->allocated - b->length < 1) + resize_buffer(b, b->length+1); + result = b->b + b->length++; + *result = c; + return result; + } + + return NULL; +} + +void +free_buffer(b) + struct buffer *b; +{ + if (b) + free(b->b); + free(b); +} diff --git a/sed/utils.h b/sed/utils.h new file mode 100644 index 0000000..4b44cd8 --- /dev/null +++ b/sed/utils.h @@ -0,0 +1,50 @@ +/* Functions from hack's utils library. + Copyright (C) 1989, 1990, 1991, 1998, 1999, 2003 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <stdio.h> + +#include "basicdefs.h" + +void panic (const char *str, ...); + +FILE *ck_fopen (const char *name, const char *mode, int fail); +FILE *ck_fdopen (int fd, const char *name, const char *mode, int fail); +void ck_fwrite (const void *ptr, size_t size, size_t nmemb, FILE *stream); +size_t ck_fread (void *ptr, size_t size, size_t nmemb, FILE *stream); +void ck_fflush (FILE *stream); +void ck_fclose (FILE *stream); +const char *follow_symlink (const char *path); +size_t ck_getdelim (char **text, size_t *buflen, char buffer_delimiter, FILE *stream); +FILE * ck_mkstemp (char **p_filename, const char *tmpdir, const char *base, + const char *mode); +void ck_rename (const char *from, const char *to, const char *unlink_if_fail); + +void *ck_malloc (size_t size); +void *xmalloc (size_t size); +void *ck_realloc (void *ptr, size_t size); +char *ck_strdup (const char *str); +void *ck_memdup (const void *buf, size_t len); + +struct buffer *init_buffer (void); +char *get_buffer (struct buffer *b); +size_t size_buffer (struct buffer *b); +char *add_buffer (struct buffer *b, const char *p, size_t n); +char *add1_buffer (struct buffer *b, int ch); +void free_buffer (struct buffer *b); + +extern const char *myname; |