Index: head/share/mk/bsd.prog.mk =================================================================== --- head/share/mk/bsd.prog.mk (revision 333235) +++ head/share/mk/bsd.prog.mk (revision 333236) @@ -1,315 +1,316 @@ # from: @(#)bsd.prog.mk 5.26 (Berkeley) 6/25/91 # $FreeBSD$ .include .include .SUFFIXES: .out .o .bc .c .cc .cpp .cxx .C .m .y .l .ll .ln .s .S .asm # XXX The use of COPTS in modern makefiles is discouraged. .if defined(COPTS) .warning ${.CURDIR}: COPTS should be CFLAGS. CFLAGS+=${COPTS} .endif .if ${MK_ASSERT_DEBUG} == "no" CFLAGS+= -DNDEBUG NO_WERROR= .endif .if defined(DEBUG_FLAGS) CFLAGS+=${DEBUG_FLAGS} CXXFLAGS+=${DEBUG_FLAGS} .if ${MK_CTF} != "no" && ${DEBUG_FLAGS:M-g} != "" CTFFLAGS+= -g .endif .endif .if defined(PROG_CXX) PROG= ${PROG_CXX} .endif .if !empty(LDFLAGS:M-Wl,*--oformat,*) || !empty(LDFLAGS:M-static) MK_DEBUG_FILES= no .endif .if defined(CRUNCH_CFLAGS) CFLAGS+=${CRUNCH_CFLAGS} .else .if ${MK_DEBUG_FILES} != "no" && empty(DEBUG_FLAGS:M-g) && \ empty(DEBUG_FLAGS:M-gdwarf-*) CFLAGS+= ${DEBUG_FILES_CFLAGS} CTFFLAGS+= -g .endif .endif .if !defined(DEBUG_FLAGS) STRIP?= -s .endif .if defined(NO_ROOT) .if !defined(TAGS) || ! ${TAGS:Mpackage=*} TAGS+= package=${PACKAGE:Uruntime} .endif TAG_ARGS= -T ${TAGS:[*]:S/ /,/g} .endif .if defined(NO_SHARED) && (${NO_SHARED} != "no" && ${NO_SHARED} != "NO") LDFLAGS+= -static .endif .if ${MK_DEBUG_FILES} != "no" PROG_FULL=${PROG}.full # Use ${DEBUGDIR} for base system debug files, else .debug subdirectory .if defined(BINDIR) && (\ ${BINDIR} == "/bin" ||\ ${BINDIR:C%/libexec(/.*)?%/libexec%} == "/libexec" ||\ ${BINDIR} == "/sbin" ||\ ${BINDIR:C%/usr/(bin|bsdinstall|libexec|lpr|sendmail|sm.bin|sbin|tests)(/.*)?%/usr/bin%} == "/usr/bin" ||\ ${BINDIR} == "/usr/lib" \ ) DEBUGFILEDIR= ${DEBUGDIR}${BINDIR} .else DEBUGFILEDIR?= ${BINDIR}/.debug .endif .if !exists(${DESTDIR}${DEBUGFILEDIR}) DEBUGMKDIR= .endif .else PROG_FULL= ${PROG} .endif .if defined(PROG) PROGNAME?= ${PROG} .if defined(SRCS) OBJS+= ${SRCS:N*.h:${OBJS_SRCS_FILTER:ts:}:S/$/.o/g} # LLVM bitcode / textual IR representations of the program BCOBJS+=${SRCS:N*.[hsS]:N*.asm:${OBJS_SRCS_FILTER:ts:}:S/$/.bco/g} LLOBJS+=${SRCS:N*.[hsS]:N*.asm:${OBJS_SRCS_FILTER:ts:}:S/$/.llo/g} .if target(beforelinking) beforelinking: ${OBJS} ${PROG_FULL}: beforelinking .endif ${PROG_FULL}: ${OBJS} .if defined(PROG_CXX) ${CXX:N${CCACHE_BIN}} ${CXXFLAGS:N-M*} ${LDFLAGS} -o ${.TARGET} \ ${OBJS} ${LDADD} .else ${CC:N${CCACHE_BIN}} ${CFLAGS:N-M*} ${LDFLAGS} -o ${.TARGET} ${OBJS} \ ${LDADD} .endif .if ${MK_CTF} != "no" ${CTFMERGE} ${CTFFLAGS} -o ${.TARGET} ${OBJS} .endif .else # !defined(SRCS) .if !target(${PROG}) .if defined(PROG_CXX) SRCS= ${PROG}.cc .else SRCS= ${PROG}.c .endif # Always make an intermediate object file because: # - it saves time rebuilding when only the library has changed # - the name of the object gets put into the executable symbol table instead of # the name of a variable temporary object. # - it's useful to keep objects around for crunching. OBJS+= ${PROG}.o BCOBJS+= ${PROG}.bc LLOBJS+= ${PROG}.ll CLEANFILES+= ${PROG}.o ${PROG}.bc ${PROG}.ll .if target(beforelinking) beforelinking: ${OBJS} ${PROG_FULL}: beforelinking .endif ${PROG_FULL}: ${OBJS} .if defined(PROG_CXX) ${CXX:N${CCACHE_BIN}} ${CXXFLAGS:N-M*} ${LDFLAGS} -o ${.TARGET} \ ${OBJS} ${LDADD} .else ${CC:N${CCACHE_BIN}} ${CFLAGS:N-M*} ${LDFLAGS} -o ${.TARGET} ${OBJS} \ ${LDADD} .endif .if ${MK_CTF} != "no" ${CTFMERGE} ${CTFFLAGS} -o ${.TARGET} ${OBJS} .endif .endif # !target(${PROG}) .endif # !defined(SRCS) .if ${MK_DEBUG_FILES} != "no" ${PROG}: ${PROG_FULL} ${PROGNAME}.debug ${OBJCOPY} --strip-debug --add-gnu-debuglink=${PROGNAME}.debug \ ${PROG_FULL} ${.TARGET} ${PROGNAME}.debug: ${PROG_FULL} ${OBJCOPY} --only-keep-debug ${PROG_FULL} ${.TARGET} .endif .if defined(LLVM_LINK) ${PROG_FULL}.bc: ${BCOBJS} ${LLVM_LINK} -o ${.TARGET} ${BCOBJS} ${PROG_FULL}.ll: ${LLOBJS} ${LLVM_LINK} -S -o ${.TARGET} ${LLOBJS} CLEANFILES+= ${PROG_FULL}.bc ${PROG_FULL}.ll .endif # defined(LLVM_LINK) .if ${MK_MAN} != "no" && !defined(MAN) && \ !defined(MAN1) && !defined(MAN2) && !defined(MAN3) && \ !defined(MAN4) && !defined(MAN5) && !defined(MAN6) && \ !defined(MAN7) && !defined(MAN8) && !defined(MAN9) MAN= ${PROG}.1 MAN1= ${MAN} .endif .endif # defined(PROG) .if defined(_SKIP_BUILD) all: .else all: ${PROG} ${SCRIPTS} .if ${MK_MAN} != "no" all: all-man .endif .endif .if defined(PROG) CLEANFILES+= ${PROG} ${PROG}.bc ${PROG}.ll .if ${MK_DEBUG_FILES} != "no" CLEANFILES+= ${PROG_FULL} ${PROGNAME}.debug .endif .endif .if defined(OBJS) CLEANFILES+= ${OBJS} ${BCOBJS} ${LLOBJS} .endif .include .if defined(PROG) .if !defined(NO_EXTRADEPEND) _EXTRADEPEND: .if defined(LDFLAGS) && !empty(LDFLAGS:M-nostdlib) .if defined(DPADD) && !empty(DPADD) echo ${PROG_FULL}: ${DPADD} >> ${DEPENDFILE} .endif .else echo ${PROG_FULL}: ${LIBC} ${DPADD} >> ${DEPENDFILE} .if defined(PROG_CXX) .if ${COMPILER_TYPE} == "clang" && empty(CXXFLAGS:M-stdlib=libstdc++) echo ${PROG_FULL}: ${LIBCPLUSPLUS} >> ${DEPENDFILE} .else echo ${PROG_FULL}: ${LIBSTDCPLUSPLUS} >> ${DEPENDFILE} .endif .endif .endif .endif # !defined(NO_EXTRADEPEND) .endif .if !target(install) .if defined(PRECIOUSPROG) .if !defined(NO_FSCHG) INSTALLFLAGS+= -fschg .endif INSTALLFLAGS+= -S .endif _INSTALLFLAGS:= ${INSTALLFLAGS} .for ie in ${INSTALLFLAGS_EDIT} _INSTALLFLAGS:= ${_INSTALLFLAGS${ie}} .endfor .if !target(realinstall) && !defined(INTERNALPROG) realinstall: _proginstall .ORDER: beforeinstall _proginstall _proginstall: .if defined(PROG) ${INSTALL} ${TAG_ARGS} ${STRIP} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ ${_INSTALLFLAGS} ${PROG} ${DESTDIR}${BINDIR}/${PROGNAME} .if ${MK_DEBUG_FILES} != "no" .if defined(DEBUGMKDIR) ${INSTALL} ${TAG_ARGS:D${TAG_ARGS},debug} -d ${DESTDIR}${DEBUGFILEDIR}/ .endif ${INSTALL} ${TAG_ARGS:D${TAG_ARGS},debug} -o ${BINOWN} -g ${BINGRP} -m ${DEBUGMODE} \ ${PROGNAME}.debug ${DESTDIR}${DEBUGFILEDIR}/${PROGNAME}.debug .endif .endif .endif # !target(realinstall) .if defined(SCRIPTS) && !empty(SCRIPTS) realinstall: _scriptsinstall .ORDER: beforeinstall _scriptsinstall SCRIPTSDIR?= ${BINDIR} SCRIPTSOWN?= ${BINOWN} SCRIPTSGRP?= ${BINGRP} SCRIPTSMODE?= ${BINMODE} STAGE_AS_SETS+= scripts stage_as.scripts: ${SCRIPTS} FLAGS.stage_as.scripts= -m ${SCRIPTSMODE} STAGE_FILES_DIR.scripts= ${STAGE_OBJTOP} .for script in ${SCRIPTS} .if defined(SCRIPTSNAME) SCRIPTSNAME_${script:T}?= ${SCRIPTSNAME} .else SCRIPTSNAME_${script:T}?= ${script:T:R} .endif SCRIPTSDIR_${script:T}?= ${SCRIPTSDIR} SCRIPTSOWN_${script:T}?= ${SCRIPTSOWN} SCRIPTSGRP_${script:T}?= ${SCRIPTSGRP} SCRIPTSMODE_${script:T}?= ${SCRIPTSMODE} STAGE_AS_${script:T}= ${SCRIPTSDIR_${script:T}}/${SCRIPTSNAME_${script:T}} _scriptsinstall: _SCRIPTSINS_${script:T} + echo ">SFD>F>DF YES" _SCRIPTSINS_${script:T}: ${script} ${INSTALL} ${TAG_ARGS} -o ${SCRIPTSOWN_${.ALLSRC:T}} \ -g ${SCRIPTSGRP_${.ALLSRC:T}} -m ${SCRIPTSMODE_${.ALLSRC:T}} \ ${.ALLSRC} \ ${DESTDIR}${SCRIPTSDIR_${.ALLSRC:T}}/${SCRIPTSNAME_${.ALLSRC:T}} .endfor .endif NLSNAME?= ${PROG} .include .include .include .include .include .if ${MK_MAN} != "no" realinstall: maninstall .ORDER: beforeinstall maninstall .endif .endif # !target(install) .if ${MK_MAN} != "no" .include .endif .if defined(HAS_TESTS) MAKE+= MK_MAKE_CHECK_USE_SANDBOX=yes SUBDIR_TARGETS+= check TESTS_LD_LIBRARY_PATH+= ${.OBJDIR} TESTS_PATH+= ${.OBJDIR} .endif .if defined(PROG) OBJS_DEPEND_GUESS+= ${SRCS:M*.h} .endif .include .include .include .include Index: head/share/mk/src.opts.mk =================================================================== --- head/share/mk/src.opts.mk (revision 333235) +++ head/share/mk/src.opts.mk (revision 333236) @@ -1,517 +1,516 @@ # $FreeBSD$ # # Option file for FreeBSD /usr/src builds. # # Users define WITH_FOO and WITHOUT_FOO on the command line or in /etc/src.conf # and /etc/make.conf files. These translate in the build system to MK_FOO={yes,no} # with sensible (usually) defaults. # # Makefiles must include bsd.opts.mk after defining specific MK_FOO options that # are applicable for that Makefile (typically there are none, but sometimes there # are exceptions). Recursive makes usually add MK_FOO=no for options that they wish # to omit from that make. # # Makefiles must include bsd.mkopt.mk before they test the value of any MK_FOO # variable. # # Makefiles may also assume that this file is included by src.opts.mk should it # need variables defined there prior to the end of the Makefile where # bsd.{subdir,lib.bin}.mk is traditionally included. # # The old-style YES_FOO and NO_FOO are being phased out. No new instances of them # should be added. Old instances should be removed since they were just to # bridge the gap between FreeBSD 4 and FreeBSD 5. # # Makefiles should never test WITH_FOO or WITHOUT_FOO directly (although an # exception is made for _WITHOUT_SRCONF which turns off this mechanism # completely inside bsd.*.mk files). # .if !target(____) ____: .include # # Define MK_* variables (which are either "yes" or "no") for users # to set via WITH_*/WITHOUT_* in /etc/src.conf and override in the # make(1) environment. # These should be tested with `== "no"' or `!= "no"' in makefiles. # The NO_* variables should only be set by makefiles for variables # that haven't been converted over. # # These options are used by the src builds. Those listed in # __DEFAULT_YES_OPTIONS default to 'yes' and will build unless turned # off. __DEFAULT_NO_OPTIONS will default to 'no' and won't build # unless turned on. Any options listed in 'BROKEN_OPTIONS' will be # hard-wired to 'no'. "Broken" here means not working or # not-appropriate and/or not supported. It doesn't imply something is # wrong with the code. There's not a single good word for this, so # BROKEN was selected as the least imperfect one considered at the # time. Options are added to BROKEN_OPTIONS list on a per-arch basis. # At this time, there's no provision for mutually incompatible options. __DEFAULT_YES_OPTIONS = \ ACCT \ ACPI \ AMD \ APM \ AT \ ATM \ AUDIT \ AUTHPF \ AUTOFS \ BHYVE \ BINUTILS \ BINUTILS_BOOTSTRAP \ BLACKLIST \ BLUETOOTH \ BOOT \ BOOTPARAMD \ BOOTPD \ BSD_CPIO \ BSDINSTALL \ BSNMP \ BZIP2 \ CALENDAR \ CAPSICUM \ CASPER \ CCD \ CDDL \ CPP \ CROSS_COMPILER \ CRYPT \ CTM \ CUSE \ CXX \ DIALOG \ DICT \ DMAGENT \ DYNAMICROOT \ ED_CRYPTO \ EE \ EFI \ ELFTOOLCHAIN_BOOTSTRAP \ EXAMPLES \ FDT \ FILE \ FINGER \ FLOPPY \ FMTREE \ FORTH \ FP_LIBC \ FREEBSD_UPDATE \ FTP \ GAMES \ GCOV \ GDB \ GNU_DIFF \ GNU_GREP \ GPIO \ HAST \ HTML \ HYPERV \ ICONV \ INET \ INET6 \ INETD \ IPFILTER \ IPFW \ ISCSI \ JAIL \ KDUMP \ KVM \ LDNS \ LDNS_UTILS \ LEGACY_CONSOLE \ LIB32 \ LIBPTHREAD \ LIBTHR \ LLVM_COV \ LOADER_GELI \ LOADER_OFW \ LOADER_UBOOT \ LOCALES \ LOCATE \ LPR \ LS_COLORS \ LZMA_SUPPORT \ MAIL \ MAILWRAPPER \ MAKE \ NDIS \ NETCAT \ NETGRAPH \ NLS_CATALOGS \ NS_CACHING \ NTP \ OPENSSL \ PAM \ PC_SYSINSTALL \ PF \ PKGBOOTSTRAP \ PMC \ PORTSNAP \ PPP \ QUOTAS \ RADIUS_SUPPORT \ RBOOTD \ RESCUE \ ROUTED \ SENDMAIL \ SETUID_LOGIN \ SHAREDOCS \ SOURCELESS \ SOURCELESS_HOST \ SOURCELESS_UCODE \ SVNLITE \ SYSCONS \ SYSTEM_COMPILER \ TALK \ TCP_WRAPPERS \ TCSH \ TELNET \ TEXTPROC \ TFTP \ TIMED \ UNBOUND \ USB \ UTMPX \ VI \ VT \ WIRELESS \ WPA_SUPPLICANT_EAPOL \ ZFS \ ZONEINFO __DEFAULT_NO_OPTIONS = \ BSD_GREP \ - BSD_GREP_FASTMATCH \ CLANG_EXTRAS \ DTRACE_TESTS \ GNU_GREP_COMPAT \ HESIOD \ LIBSOFT \ LOADER_FIREWIRE \ LOADER_FORCE_LE \ LOADER_LUA \ NAND \ OFED \ OPENLDAP \ REPRODUCIBLE_BUILD \ RPCBIND_WARMSTART_SUPPORT \ SHARED_TOOLCHAIN \ SORT_THREADS \ SVN \ ZONEINFO_LEAPSECONDS_SUPPORT \ ZONEINFO_OLD_TIMEZONES_SUPPORT \ # # Default behaviour of some options depends on the architecture. Unfortunately # this means that we have to test TARGET_ARCH (the buildworld case) as well # as MACHINE_ARCH (the non-buildworld case). Normally TARGET_ARCH is not # used at all in bsd.*.mk, but we have to make an exception here if we want # to allow defaults for some things like clang to vary by target architecture. # Additional, per-target behavior should be rarely added only after much # gnashing of teeth and grinding of gears. # .if defined(TARGET_ARCH) __T=${TARGET_ARCH} .else __T=${MACHINE_ARCH} .endif .if defined(TARGET) __TT=${TARGET} .else __TT=${MACHINE} .endif .include # If the compiler is not C++11 capable, disable Clang and use GCC instead. # This means that architectures that have GCC 4.2 as default can not # build Clang without using an external compiler. .if ${COMPILER_FEATURES:Mc++11} && (${__T} == "aarch64" || \ ${__T} == "amd64" || ${__TT} == "arm" || ${__T} == "i386") # Clang is enabled, and will be installed as the default /usr/bin/cc. __DEFAULT_YES_OPTIONS+=CLANG CLANG_BOOTSTRAP CLANG_FULL CLANG_IS_CC LLD __DEFAULT_NO_OPTIONS+=GCC GCC_BOOTSTRAP GNUCXX GPL_DTC .elif ${COMPILER_FEATURES:Mc++11} && ${__T:Mriscv*} == "" && ${__T} != "sparc64" # If an external compiler that supports C++11 is used as ${CC} and Clang # supports the target, then Clang is enabled but GCC is installed as the # default /usr/bin/cc. __DEFAULT_YES_OPTIONS+=CLANG CLANG_FULL GCC GCC_BOOTSTRAP GNUCXX GPL_DTC LLD __DEFAULT_NO_OPTIONS+=CLANG_BOOTSTRAP CLANG_IS_CC .else # Everything else disables Clang, and uses GCC instead. __DEFAULT_YES_OPTIONS+=GCC GCC_BOOTSTRAP GNUCXX GPL_DTC __DEFAULT_NO_OPTIONS+=CLANG CLANG_BOOTSTRAP CLANG_FULL CLANG_IS_CC LLD .endif # In-tree binutils/gcc are older versions without modern architecture support. .if ${__T} == "aarch64" || ${__T:Mriscv*} != "" BROKEN_OPTIONS+=BINUTILS BINUTILS_BOOTSTRAP GCC GCC_BOOTSTRAP GDB .endif .if ${__T:Mriscv*} != "" BROKEN_OPTIONS+=PROFILE # "sorry, unimplemented: profiler support for RISC-V" BROKEN_OPTIONS+=TESTS # "undefined reference to `_Unwind_Resume'" BROKEN_OPTIONS+=CXX # "libcxxrt.so: undefined reference to `_Unwind_Resume_or_Rethrow'" .endif .if ${__T} == "aarch64" || ${__T} == "amd64" || ${__T} == "i386" || \ ${__T:Mriscv*} != "" || ${__TT} == "mips" __DEFAULT_YES_OPTIONS+=LLVM_LIBUNWIND .else __DEFAULT_NO_OPTIONS+=LLVM_LIBUNWIND .endif .if ${__T} == "aarch64" __DEFAULT_YES_OPTIONS+=LLD_BOOTSTRAP LLD_IS_LD .elif ${__T} == "amd64" __DEFAULT_YES_OPTIONS+=LLD_BOOTSTRAP __DEFAULT_NO_OPTIONS+=LLD_IS_LD .else __DEFAULT_NO_OPTIONS+=LLD_BOOTSTRAP LLD_IS_LD .endif .if ${__T} == "aarch64" || ${__T} == "amd64" || ${__T} == "i386" __DEFAULT_YES_OPTIONS+=LLDB .else __DEFAULT_NO_OPTIONS+=LLDB .endif # LLVM lacks support for FreeBSD 64-bit atomic operations for ARMv4/ARMv5 .if ${__T} == "arm" || ${__T} == "armeb" BROKEN_OPTIONS+=LLDB .endif # GDB in base is generally less functional than GDB in ports. Ports GDB # does not yet contain kernel support for arm, and sparc64 kernel support # has not been tested. .if ${__T:Marm*} != "" || ${__T} == "sparc64" __DEFAULT_NO_OPTIONS+=GDB_LIBEXEC .else __DEFAULT_YES_OPTIONS+=GDB_LIBEXEC .endif # Only doing soft float API stuff on armv6 and armv7 .if ${__T} != "armv6" && ${__T} != "armv7" BROKEN_OPTIONS+=LIBSOFT .endif .if ${__T:Mmips*} BROKEN_OPTIONS+=SSP .endif # EFI doesn't exist on mips, powerpc, sparc or riscv. .if ${__T:Mmips*} || ${__T:Mpowerpc*} || ${__T:Msparc64} || ${__T:Mriscv*} BROKEN_OPTIONS+=EFI .endif # GELI isn't supported on !x86 .if ${__T} != "i386" && ${__T} != "amd64" BROKEN_OPTIONS+=LOADER_GELI .endif # OFW is only for powerpc and sparc64, exclude others .if ${__T:Mpowerpc*} == "" && ${__T:Msparc64} == "" BROKEN_OPTIONS+=LOADER_OFW .endif # UBOOT is only for arm, mips and powerpc, exclude others .if ${__T:Marm*} == "" && ${__T:Mmips*} == "" && ${__T:Mpowerpc*} == "" BROKEN_OPTIONS+=LOADER_UBOOT .endif .if ${__T:Mmips64*} # profiling won't work on MIPS64 because there is only assembly for o32 BROKEN_OPTIONS+=PROFILE .endif .if ${__T} == "aarch64" || ${__T} == "amd64" || ${__T} == "i386" || \ ${__T} == "powerpc64" || ${__T} == "sparc64" __DEFAULT_YES_OPTIONS+=CXGBETOOL __DEFAULT_YES_OPTIONS+=MLX5TOOL .else __DEFAULT_NO_OPTIONS+=CXGBETOOL __DEFAULT_NO_OPTIONS+=MLX5TOOL .endif .include # # MK_* options that default to "yes" if the compiler is a C++11 compiler. # .for var in \ LIBCPLUSPLUS .if !defined(MK_${var}) .if ${COMPILER_FEATURES:Mc++11} .if defined(WITHOUT_${var}) MK_${var}:= no .else MK_${var}:= yes .endif .else .if defined(WITH_${var}) MK_${var}:= yes .else MK_${var}:= no .endif .endif .endif .endfor # # Force some options off if their dependencies are off. # Order is somewhat important. # .if !${COMPILER_FEATURES:Mc++11} MK_LLVM_LIBUNWIND:= no .endif .if ${MK_BINUTILS} == "no" MK_GDB:= no .endif .if ${MK_CAPSICUM} == "no" MK_CASPER:= no .endif .if ${MK_LIBPTHREAD} == "no" MK_LIBTHR:= no .endif .if ${MK_LDNS} == "no" MK_LDNS_UTILS:= no MK_UNBOUND:= no .endif .if ${MK_SOURCELESS} == "no" MK_SOURCELESS_HOST:= no MK_SOURCELESS_UCODE:= no .endif .if ${MK_CDDL} == "no" MK_ZFS:= no MK_CTF:= no .endif .if ${MK_CRYPT} == "no" MK_OPENSSL:= no MK_OPENSSH:= no MK_KERBEROS:= no .endif .if ${MK_CXX} == "no" MK_CLANG:= no MK_GNUCXX:= no MK_TESTS:= no .endif .if ${MK_DIALOG} == "no" MK_BSDINSTALL:= no .endif .if ${MK_MAIL} == "no" MK_MAILWRAPPER:= no MK_SENDMAIL:= no MK_DMAGENT:= no .endif .if ${MK_NETGRAPH} == "no" MK_ATM:= no MK_BLUETOOTH:= no .endif .if ${MK_NLS} == "no" MK_NLS_CATALOGS:= no .endif .if ${MK_OPENSSL} == "no" MK_OPENSSH:= no MK_KERBEROS:= no .endif .if ${MK_PF} == "no" MK_AUTHPF:= no .endif .if ${MK_TESTS} == "no" MK_DTRACE_TESTS:= no .endif .if ${MK_ZONEINFO} == "no" MK_ZONEINFO_LEAPSECONDS_SUPPORT:= no MK_ZONEINFO_OLD_TIMEZONES_SUPPORT:= no .endif .if ${MK_CROSS_COMPILER} == "no" MK_BINUTILS_BOOTSTRAP:= no MK_CLANG_BOOTSTRAP:= no MK_ELFTOOLCHAIN_BOOTSTRAP:= no MK_GCC_BOOTSTRAP:= no MK_LLD_BOOTSTRAP:= no .endif .if ${MK_TOOLCHAIN} == "no" MK_BINUTILS:= no MK_CLANG:= no MK_GCC:= no MK_GDB:= no MK_INCLUDES:= no MK_LLD:= no MK_LLDB:= no .endif .if ${MK_CLANG} == "no" MK_CLANG_EXTRAS:= no MK_CLANG_FULL:= no MK_LLVM_COV:= no .endif # # MK_* options whose default value depends on another option. # .for vv in \ GSSAPI/KERBEROS \ MAN_UTILS/MAN .if defined(WITH_${vv:H}) MK_${vv:H}:= yes .elif defined(WITHOUT_${vv:H}) MK_${vv:H}:= no .else MK_${vv:H}:= ${MK_${vv:T}} .endif .endfor # # Set defaults for the MK_*_SUPPORT variables. # # # MK_*_SUPPORT options which default to "yes" unless their corresponding # MK_* variable is set to "no". # .for var in \ BLACKLIST \ BZIP2 \ INET \ INET6 \ KERBEROS \ KVM \ NETGRAPH \ PAM \ TESTS \ WIRELESS .if defined(WITHOUT_${var}_SUPPORT) || ${MK_${var}} == "no" MK_${var}_SUPPORT:= no .else MK_${var}_SUPPORT:= yes .endif .endfor .if !${COMPILER_FEATURES:Mc++11} MK_LLDB:= no .endif # gcc 4.8 and newer supports libc++, so suppress gnuc++ in that case. # while in theory we could build it with that, we don't want to do # that since it creates too much confusion for too little gain. # XXX: This is incomplete and needs X_COMPILER_TYPE/VERSION checks too # to prevent Makefile.inc1 from bootstrapping unneeded dependencies # and to support 'make delete-old' when supplying an external toolchain. .if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} >= 40800 MK_GNUCXX:=no MK_GCC:=no .endif .endif # !target(____) Index: head/tools/build/options/WITH_BSD_GREP_FASTMATCH =================================================================== --- head/tools/build/options/WITH_BSD_GREP_FASTMATCH (revision 333235) +++ head/tools/build/options/WITH_BSD_GREP_FASTMATCH (nonexistent) @@ -1,3 +0,0 @@ -.\" $FreeBSD$ -Set this option to use the fastmatch implementation in -.Xr bsdgrep 1 . Property changes on: head/tools/build/options/WITH_BSD_GREP_FASTMATCH ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/tools/build/options/WITHOUT_BSD_GREP_FASTMATCH =================================================================== --- head/tools/build/options/WITHOUT_BSD_GREP_FASTMATCH (revision 333235) +++ head/tools/build/options/WITHOUT_BSD_GREP_FASTMATCH (nonexistent) @@ -1,5 +0,0 @@ -.\" $FreeBSD$ -Set this option to exclude the fastmatch implementation from -.Xr bsdgrep 1 , -instead using only -.Xr regex 3 . Property changes on: head/tools/build/options/WITHOUT_BSD_GREP_FASTMATCH ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/usr.bin/grep/regex/hashtable.h =================================================================== --- head/usr.bin/grep/regex/hashtable.h (revision 333235) +++ head/usr.bin/grep/regex/hashtable.h (nonexistent) @@ -1,35 +0,0 @@ -/* $FreeBSD$ */ - -#ifndef HASHTABLE_H -#define HASHTABLE_H 1 - -#include - -#define HASH_OK 0 -#define HASH_UPDATED 1 -#define HASH_FAIL 2 -#define HASH_FULL 3 -#define HASH_NOTFOUND 4 - -#define HASHSTEP(x,c) (((x << 5) + x) + (c)) - -typedef struct { - void *key; - void *value; -} hashtable_entry; - -typedef struct { - size_t key_size; - size_t table_size; - size_t usage; - size_t value_size; - hashtable_entry **entries; -} hashtable; - -void hashtable_free(hashtable *); -int hashtable_get(hashtable *, const void *, void *); -hashtable *hashtable_init(size_t, size_t, size_t); -int hashtable_put(hashtable *, const void *, const void *); -int hashtable_remove(hashtable *, const void *); - -#endif /* HASHTABLE.H */ Property changes on: head/usr.bin/grep/regex/hashtable.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/usr.bin/grep/regex/fastmatch.h =================================================================== --- head/usr.bin/grep/regex/fastmatch.h (revision 333235) +++ head/usr.bin/grep/regex/fastmatch.h (nonexistent) @@ -1,95 +0,0 @@ -/* $FreeBSD$ */ - -#ifndef FASTMATCH_H -#define FASTMATCH_H 1 - -#include -#include -#include -#include - -typedef struct { - size_t wlen; - size_t len; - wchar_t *wpattern; - bool *wescmap; - unsigned int qsBc[UCHAR_MAX + 1]; - unsigned int *bmGs; - char *pattern; - bool *escmap; - unsigned int defBc; - void *qsBc_table; - unsigned int *sbmGs; - const char *re_endp; - - /* flags */ - bool hasdot; - bool bol; - bool eol; - bool word; - bool icase; - bool newline; - bool nosub; - bool matchall; - bool reversed; -} fastmatch_t; - -extern int -tre_fixcomp(fastmatch_t *preg, const char *regex, int cflags); - -extern int -tre_fastcomp(fastmatch_t *preg, const char *regex, int cflags); - -extern int -tre_fastexec(const fastmatch_t *preg, const char *string, size_t nmatch, - regmatch_t pmatch[], int eflags); - -extern void -tre_fastfree(fastmatch_t *preg); - -extern int -tre_fixwcomp(fastmatch_t *preg, const wchar_t *regex, int cflags); - -extern int -tre_fastwcomp(fastmatch_t *preg, const wchar_t *regex, int cflags); - -extern int -tre_fastwexec(const fastmatch_t *preg, const wchar_t *string, - size_t nmatch, regmatch_t pmatch[], int eflags); - -/* Versions with a maximum length argument and therefore the capability to - handle null characters in the middle of the strings. */ -extern int -tre_fixncomp(fastmatch_t *preg, const char *regex, size_t len, int cflags); - -extern int -tre_fastncomp(fastmatch_t *preg, const char *regex, size_t len, int cflags); - -extern int -tre_fastnexec(const fastmatch_t *preg, const char *string, size_t len, - size_t nmatch, regmatch_t pmatch[], int eflags); - -extern int -tre_fixwncomp(fastmatch_t *preg, const wchar_t *regex, size_t len, int cflags); - -extern int -tre_fastwncomp(fastmatch_t *preg, const wchar_t *regex, size_t len, int cflags); - -extern int -tre_fastwnexec(const fastmatch_t *preg, const wchar_t *string, size_t len, - size_t nmatch, regmatch_t pmatch[], int eflags); - -#define fixncomp tre_fixncomp -#define fastncomp tre_fastncomp -#define fixcomp tre_fixcomp -#define fastcomp tre_fastcomp -#define fixwncomp tre_fixwncomp -#define fastwncomp tre_fastwncomp -#define fixwcomp tre_fixwcomp -#define fastwcomp tre_fastwcomp -#define fastfree tre_fastfree -#define fastnexec tre_fastnexec -#define fastexec tre_fastexec -#define fastwnexec tre_fastwnexec -#define fastwexec tre_fastwexec -#endif /* FASTMATCH_H */ Property changes on: head/usr.bin/grep/regex/fastmatch.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/usr.bin/grep/regex/tre-fastmatch.c =================================================================== --- head/usr.bin/grep/regex/tre-fastmatch.c (revision 333235) +++ head/usr.bin/grep/regex/tre-fastmatch.c (nonexistent) @@ -1,1070 +0,0 @@ -/* $FreeBSD$ */ - -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav - * Copyright (C) 2008-2011 Gabor Kovesdan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "glue.h" - -#include -#include -#include -#include -#include -#include -#ifdef TRE_WCHAR -#include -#include -#endif - -#include "hashtable.h" -#include "tre-fastmatch.h" - -static int fastcmp(const fastmatch_t *fg, const void *data, - tre_str_type_t type); - -/* - * Clean up if pattern compilation fails. - */ -#define FAIL_COMP(errcode) \ - { \ - if (fg->pattern) \ - free(fg->pattern); \ - if (fg->wpattern) \ - free(fg->wpattern); \ - if (fg->qsBc_table) \ - hashtable_free(fg->qsBc_table); \ - fg = NULL; \ - return errcode; \ - } - -/* - * Skips n characters in the input string and assigns the start - * address to startptr. Note: as per IEEE Std 1003.1-2008 - * matching is based on bit pattern not character representations - * so we can handle MB strings as byte sequences just like - * SB strings. - */ -#define SKIP_CHARS(n) \ - switch (type) \ - { \ - case STR_WIDE: \ - startptr = str_wide + n; \ - break; \ - default: \ - startptr = str_byte + n; \ - } - -/* - * Converts the wide string pattern to SB/MB string and stores - * it in fg->pattern. Sets fg->len to the byte length of the - * converted string. - */ -#define STORE_MBS_PAT \ - { \ - size_t siz; \ - \ - siz = wcstombs(NULL, fg->wpattern, 0); \ - if (siz == (size_t)-1) \ - return REG_BADPAT; \ - fg->len = siz; \ - fg->pattern = malloc(siz + 1); \ - if (fg->pattern == NULL) \ - return REG_ESPACE; \ - wcstombs(fg->pattern, fg->wpattern, siz); \ - fg->pattern[siz] = '\0'; \ - } \ - -#define CONV_MBS_PAT(src, dest, destsz) \ - { \ - destsz = wcstombs(NULL, src, 0); \ - if (destsz == (size_t)-1) \ - return REG_BADPAT; \ - dest = malloc(destsz + 1); \ - if (dest == NULL) \ - return REG_ESPACE; \ - wcstombs(dest, src, destsz); \ - dest[destsz] = '\0'; \ - } \ - -#define IS_OUT_OF_BOUNDS \ - ((!fg->reversed \ - ? ((type == STR_WIDE) ? ((j + fg->wlen) > len) \ - : ((j + fg->len) > len)) \ - : (j < 0))) - -/* - * Checks whether the new position after shifting in the input string - * is out of the bounds and break out from the loop if so. - */ -#define CHECKBOUNDS \ - if (IS_OUT_OF_BOUNDS) \ - break; \ - -/* - * Shifts in the input string after a mismatch. The position of the - * mismatch is stored in the mismatch variable. - */ -#define SHIFT \ - CHECKBOUNDS; \ - \ - { \ - int r = -1; \ - unsigned int bc = 0, gs = 0, ts; \ - \ - switch (type) \ - { \ - case STR_WIDE: \ - if (!fg->hasdot) \ - { \ - if (u != 0 && (unsigned)mismatch == fg->wlen - 1 - shift) \ - mismatch -= u; \ - v = fg->wlen - 1 - mismatch; \ - r = hashtable_get(fg->qsBc_table, \ - &str_wide[!fg->reversed ? (size_t)j + fg->wlen \ - : (size_t)j - 1], &bc); \ - gs = fg->bmGs[mismatch]; \ - } \ - bc = (r == HASH_OK) ? bc : fg->defBc; \ - DPRINT(("tre_fast_match: mismatch on character" CHF ", " \ - "BC %d, GS %d\n", \ - ((const tre_char_t *)startptr)[mismatch + 1], \ - bc, gs)); \ - break; \ - default: \ - if (!fg->hasdot) \ - { \ - if (u != 0 && (unsigned)mismatch == fg->len - 1 - shift) \ - mismatch -= u; \ - v = fg->len - 1 - mismatch; \ - gs = fg->sbmGs[mismatch]; \ - } \ - bc = fg->qsBc[((const unsigned char *)str_byte) \ - [!fg->reversed ? (size_t)j + fg->len \ - : (size_t)j - 1]]; \ - DPRINT(("tre_fast_match: mismatch on character %c, " \ - "BC %d, GS %d\n", \ - ((const unsigned char *)startptr)[mismatch + 1], \ - bc, gs)); \ - } \ - if (fg->hasdot) \ - shift = bc; \ - else \ - { \ - ts = (u >= v) ? (u - v) : 0; \ - shift = MAX(ts, bc); \ - shift = MAX(shift, gs); \ - if (shift == gs) \ - u = MIN((type == STR_WIDE ? fg->wlen : fg->len) - shift, v); \ - else \ - { \ - if (ts < bc) \ - shift = MAX(shift, u + 1); \ - u = 0; \ - } \ - } \ - DPRINT(("tre_fast_match: shifting %u characters\n", shift)); \ - j = !fg->reversed ? j + shift : j - shift; \ - } - -/* - * Normal Quick Search would require a shift based on the position the - * next character after the comparison is within the pattern. With - * wildcards, the position of the last dot effects the maximum shift - * distance. - * The closer to the end the wild card is the slower the search. - * - * Examples: - * Pattern Max shift - * ------- --------- - * this 5 - * .his 4 - * t.is 3 - * th.s 2 - * thi. 1 - */ - -/* - * Fills in the bad character shift array for SB/MB strings. - */ -#define FILL_QSBC \ - if (fg->reversed) \ - { \ - _FILL_QSBC_REVERSED \ - } \ - else \ - { \ - _FILL_QSBC \ - } - -#define _FILL_QSBC \ - for (unsigned int i = 0; i <= UCHAR_MAX; i++) \ - fg->qsBc[i] = fg->len - hasdot; \ - for (unsigned int i = hasdot + 1; i < fg->len; i++) \ - { \ - fg->qsBc[(unsigned char)fg->pattern[i]] = fg->len - i; \ - DPRINT(("BC shift for char %c is %zu\n", fg->pattern[i], \ - fg->len - i)); \ - if (fg->icase) \ - { \ - char c = islower((unsigned char)fg->pattern[i]) ? \ - toupper((unsigned char)fg->pattern[i]) : \ - tolower((unsigned char)fg->pattern[i]); \ - fg->qsBc[(unsigned char)c] = fg->len - i; \ - DPRINT(("BC shift for char %c is %zu\n", c, fg->len - i)); \ - } \ - } - -#define _FILL_QSBC_REVERSED \ - for (unsigned int i = 0; i <= UCHAR_MAX; i++) \ - fg->qsBc[i] = firstdot + 1; \ - for (int i = firstdot - 1; i >= 0; i--) \ - { \ - fg->qsBc[(unsigned char)fg->pattern[i]] = i + 1; \ - DPRINT(("Reverse BC shift for char %c is %d\n", fg->pattern[i], \ - i + 1)); \ - if (fg->icase) \ - { \ - char c = islower((unsigned char)fg->pattern[i]) ? \ - toupper((unsigned char)fg->pattern[i]) : \ - tolower((unsigned char)fg->pattern[i]); \ - fg->qsBc[(unsigned char)c] = i + 1; \ - DPRINT(("Reverse BC shift for char %c is %d\n", c, i + 1)); \ - } \ - } - -/* - * Fills in the bad character shifts into a hastable for wide strings. - * With wide characters it is not possible any more to use a normal - * array because there are too many characters and we could not - * provide enough memory. Fortunately, we only have to store distinct - * values for so many characters as the number of distinct characters - * in the pattern, so we can store them in a hashtable and store a - * default shift value for the rest. - */ -#define FILL_QSBC_WIDE \ - if (fg->reversed) \ - { \ - _FILL_QSBC_WIDE_REVERSED \ - } \ - else \ - { \ - _FILL_QSBC_WIDE \ - } - -#define _FILL_QSBC_WIDE \ - /* Adjust the shift based on location of the last dot ('.'). */ \ - fg->defBc = fg->wlen - whasdot; \ - \ - /* Preprocess pattern. */ \ - fg->qsBc_table = hashtable_init(fg->wlen * (fg->icase ? 8 : 4), \ - sizeof(tre_char_t), sizeof(int)); \ - if (!fg->qsBc_table) \ - FAIL_COMP(REG_ESPACE); \ - for (unsigned int i = whasdot + 1; i < fg->wlen; i++) \ - { \ - int k = fg->wlen - i; \ - int r; \ - \ - r = hashtable_put(fg->qsBc_table, &fg->wpattern[i], &k); \ - if ((r == HASH_FAIL) || (r == HASH_FULL)) \ - FAIL_COMP(REG_ESPACE); \ - DPRINT(("BC shift for wide char " CHF " is %d\n", fg->wpattern[i],\ - k)); \ - if (fg->icase) \ - { \ - tre_char_t wc = iswlower(fg->wpattern[i]) ? \ - towupper(fg->wpattern[i]) : towlower(fg->wpattern[i]); \ - r = hashtable_put(fg->qsBc_table, &wc, &k); \ - if ((r == HASH_FAIL) || (r == HASH_FULL)) \ - FAIL_COMP(REG_ESPACE); \ - DPRINT(("BC shift for wide char " CHF " is %d\n", wc, k)); \ - } \ - } - -#define _FILL_QSBC_WIDE_REVERSED \ - /* Adjust the shift based on location of the last dot ('.'). */ \ - fg->defBc = (size_t)wfirstdot; \ - \ - /* Preprocess pattern. */ \ - fg->qsBc_table = hashtable_init(fg->wlen * (fg->icase ? 8 : 4), \ - sizeof(tre_char_t), sizeof(int)); \ - if (!fg->qsBc_table) \ - FAIL_COMP(REG_ESPACE); \ - for (int i = wfirstdot - 1; i >= 0; i--) \ - { \ - int k = i + 1; \ - int r; \ - \ - r = hashtable_put(fg->qsBc_table, &fg->wpattern[i], &k); \ - if ((r == HASH_FAIL) || (r == HASH_FULL)) \ - FAIL_COMP(REG_ESPACE); \ - DPRINT(("Reverse BC shift for wide char " CHF " is %d\n", \ - fg->wpattern[i], k)); \ - if (fg->icase) \ - { \ - tre_char_t wc = iswlower(fg->wpattern[i]) ? \ - towupper(fg->wpattern[i]) : towlower(fg->wpattern[i]); \ - r = hashtable_put(fg->qsBc_table, &wc, &k); \ - if ((r == HASH_FAIL) || (r == HASH_FULL)) \ - FAIL_COMP(REG_ESPACE); \ - DPRINT(("Reverse BC shift for wide char " CHF " is %d\n", wc, \ - k)); \ - } \ - } - -#ifdef _GREP_DEBUG -#define DPRINT_BMGS(len, fmt_str, sh) \ - for (unsigned int i = 0; i < len; i++) \ - DPRINT((fmt_str, i, sh[i])); -#else -#define DPRINT_BMGS(len, fmt_str, sh) \ - do { } while(/*CONSTCOND*/0) -#endif - -/* - * Fills in the good suffix table for SB/MB strings. - */ -#define FILL_BMGS \ - if (fg->len > 0 && !fg->hasdot) \ - { \ - fg->sbmGs = malloc(fg->len * sizeof(*fg->sbmGs)); \ - if (!fg->sbmGs) \ - return REG_ESPACE; \ - if (fg->len == 1) \ - fg->sbmGs[0] = 1; \ - else \ - _FILL_BMGS(fg->sbmGs, fg->pattern, fg->len, false); \ - DPRINT_BMGS(fg->len, "GS shift for pos %d is %d\n", fg->sbmGs); \ - } - -/* - * Fills in the good suffix table for wide strings. - */ -#define FILL_BMGS_WIDE \ - if (fg->wlen > 0 && !fg->hasdot) \ - { \ - fg->bmGs = malloc(fg->wlen * sizeof(*fg->bmGs)); \ - if (!fg->bmGs) \ - return REG_ESPACE; \ - if (fg->wlen == 1) \ - fg->bmGs[0] = 1; \ - else \ - _FILL_BMGS(fg->bmGs, fg->wpattern, fg->wlen, true); \ - DPRINT_BMGS(fg->wlen, "GS shift (wide) for pos %d is %d\n", \ - fg->bmGs); \ - } - -#define _FILL_BMGS(arr, pat, plen, wide) \ - { \ - char *p; \ - tre_char_t *wp; \ - \ - if (wide) \ - { \ - if (fg->icase) \ - { \ - wp = malloc(plen * sizeof(tre_char_t)); \ - if (wp == NULL) \ - return REG_ESPACE; \ - for (unsigned int i = 0; i < plen; i++) \ - wp[i] = towlower(pat[i]); \ - _CALC_BMGS(arr, wp, plen); \ - free(wp); \ - } \ - else \ - _CALC_BMGS(arr, pat, plen); \ - } \ - else \ - { \ - if (fg->icase) \ - { \ - p = malloc(plen); \ - if (p == NULL) \ - return REG_ESPACE; \ - for (unsigned int i = 0; i < plen; i++) \ - p[i] = tolower((unsigned char)pat[i]); \ - _CALC_BMGS(arr, p, plen); \ - free(p); \ - } \ - else \ - _CALC_BMGS(arr, pat, plen); \ - } \ - } - -#define _CALC_BMGS(arr, pat, plen) \ - { \ - int f = 0, g; \ - \ - int *suff = malloc(plen * sizeof(int)); \ - if (suff == NULL) \ - return REG_ESPACE; \ - \ - suff[plen - 1] = plen; \ - g = plen - 1; \ - for (int i = plen - 2; i >= 0; i--) \ - { \ - if (i > g && suff[i + plen - 1 - f] < i - g) \ - suff[i] = suff[i + plen - 1 - f]; \ - else \ - { \ - if (i < g) \ - g = i; \ - f = i; \ - while (g >= 0 && pat[g] == pat[g + plen - 1 - f]) \ - g--; \ - suff[i] = f - g; \ - } \ - } \ - \ - for (unsigned int i = 0; i < plen; i++) \ - arr[i] = plen; \ - g = 0; \ - for (int i = plen - 1; i >= 0; i--) \ - if (suff[i] == i + 1) \ - for(; (unsigned long)g < plen - 1 - i; g++) \ - if (arr[g] == plen) \ - arr[g] = plen - 1 - i; \ - for (unsigned int i = 0; i <= plen - 2; i++) \ - arr[plen - 1 - suff[i]] = plen - 1 - i; \ - \ - free(suff); \ - } - -/* - * Copies the pattern pat having length n to p and stores - * the size in l. - */ -#define SAVE_PATTERN(src, srclen, dst, dstlen) \ - dstlen = srclen; \ - dst = malloc((dstlen + 1) * sizeof(tre_char_t)); \ - if (dst == NULL) \ - return REG_ESPACE; \ - if (dstlen > 0) \ - memcpy(dst, src, dstlen * sizeof(tre_char_t)); \ - dst[dstlen] = TRE_CHAR('\0'); - -/* - * Initializes pattern compiling. - */ -#define INIT_COMP \ - /* Initialize. */ \ - memset(fg, 0, sizeof(*fg)); \ - fg->icase = (cflags & REG_ICASE); \ - fg->word = (cflags & REG_WORD); \ - fg->newline = (cflags & REG_NEWLINE); \ - fg->nosub = (cflags & REG_NOSUB); \ - \ - /* Cannot handle REG_ICASE with MB string */ \ - if (fg->icase && (TRE_MB_CUR_MAX > 1) && n > 0) \ - { \ - DPRINT(("Cannot use fast matcher for MBS with REG_ICASE\n")); \ - return REG_BADPAT; \ - } - -/* - * Checks whether we have a 0-length pattern that will match - * anything. If literal is set to false, the EOL anchor is also - * taken into account. - */ -#define CHECK_MATCHALL(literal) \ - if (!literal && n == 1 && pat[0] == TRE_CHAR('$')) \ - { \ - n--; \ - fg->eol = true; \ - } \ - \ - if (n == 0) \ - { \ - fg->matchall = true; \ - fg->pattern = malloc(sizeof(char)); \ - if (!fg->pattern) \ - FAIL_COMP(REG_ESPACE); \ - fg->pattern[0] = '\0'; \ - fg->wpattern = malloc(sizeof(tre_char_t)); \ - if (!fg->wpattern) \ - FAIL_COMP(REG_ESPACE); \ - fg->wpattern[0] = TRE_CHAR('\0'); \ - DPRINT(("Matching every input\n")); \ - return REG_OK; \ - } - -/* - * Returns: REG_OK on success, error code otherwise - */ -int -tre_compile_literal(fastmatch_t *fg, const tre_char_t *pat, size_t n, - int cflags) -{ - size_t hasdot = 0, whasdot = 0; - ssize_t firstdot = -1, wfirstdot = -1; - - INIT_COMP; - - CHECK_MATCHALL(true); - - /* Cannot handle word boundaries with MB string */ - if (fg->word && (TRE_MB_CUR_MAX > 1)) - return REG_BADPAT; - -#ifdef TRE_WCHAR - SAVE_PATTERN(pat, n, fg->wpattern, fg->wlen); - STORE_MBS_PAT; -#else - SAVE_PATTERN(pat, n, fg->pattern, fg->len); -#endif - - DPRINT(("tre_compile_literal: pattern: %s, len %zu, icase: %c, word: %c, " - "newline %c\n", fg->pattern, fg->len, fg->icase ? 'y' : 'n', - fg->word ? 'y' : 'n', fg->newline ? 'y' : 'n')); - - FILL_QSBC; - FILL_BMGS; -#ifdef TRE_WCHAR - FILL_QSBC_WIDE; - FILL_BMGS_WIDE; -#endif - - return REG_OK; -} - -/* - * Returns: REG_OK on success, error code otherwise - */ -int -tre_compile_fast(fastmatch_t *fg, const tre_char_t *pat, size_t n, - int cflags) -{ - tre_char_t *tmp; - size_t pos = 0, hasdot = 0, whasdot = 0; - ssize_t firstdot = -1, wfirstdot = -1; - bool escaped = false; - bool *_escmap = NULL; - - INIT_COMP; - - /* Remove beginning-of-line character ('^'). */ - if (pat[0] == TRE_CHAR('^')) - { - fg->bol = true; - n--; - pat++; - } - - CHECK_MATCHALL(false); - - /* Handle word-boundary matching when GNU extensions are enabled */ - if ((cflags & REG_GNU) && (n >= 14) && - (memcmp(pat, TRE_CHAR("[[:<:]]"), 7 * sizeof(tre_char_t)) == 0) && - (memcmp(pat + n - 7, TRE_CHAR("[[:>:]]"), - 7 * sizeof(tre_char_t)) == 0)) - { - n -= 14; - pat += 7; - fg->word = true; - } - - /* Cannot handle word boundaries with MB string */ - if (fg->word && (TRE_MB_CUR_MAX > 1)) - return REG_BADPAT; - - tmp = malloc((n + 1) * sizeof(tre_char_t)); - if (tmp == NULL) - return REG_ESPACE; - -/* Copies the char into the stored pattern and skips to the next char. */ -#define STORE_CHAR \ - do \ - { \ - tmp[pos++] = pat[i]; \ - escaped = false; \ - continue; \ - } while (0) - - /* Traverse the input pattern for processing */ - for (unsigned int i = 0; i < n; i++) - { - switch (pat[i]) - { - case TRE_CHAR('\\'): - if (escaped) - STORE_CHAR; - else if (i == n - 1) - goto badpat; - else - escaped = true; - continue; - case TRE_CHAR('['): - if (escaped) - STORE_CHAR; - else - goto badpat; - continue; - case TRE_CHAR('*'): - if (escaped || (!(cflags & REG_EXTENDED) && (i == 0))) - STORE_CHAR; - else - goto badpat; - continue; - case TRE_CHAR('+'): - case TRE_CHAR('?'): - if ((cflags & REG_EXTENDED) && (i == 0)) - goto badpat; - else if ((cflags & REG_EXTENDED) ^ !escaped) - STORE_CHAR; - else - goto badpat; - continue; - case TRE_CHAR('.'): - if (escaped) - { - if (!_escmap) - _escmap = calloc(n, sizeof(bool)); - if (!_escmap) - { - free(tmp); - return REG_ESPACE; - } - _escmap[i] = true; - STORE_CHAR; - } - else - { - whasdot = i; - if (wfirstdot == -1) - wfirstdot = i; - STORE_CHAR; - } - continue; - case TRE_CHAR('^'): - STORE_CHAR; - continue; - case TRE_CHAR('$'): - if (!escaped && (i == n - 1)) - fg->eol = true; - else - STORE_CHAR; - continue; - case TRE_CHAR('('): - if ((cflags & REG_EXTENDED) ^ escaped) - goto badpat; - else - STORE_CHAR; - continue; - case TRE_CHAR('{'): - if (!(cflags & REG_EXTENDED) ^ escaped) - STORE_CHAR; - else if (!(cflags & REG_EXTENDED) && (i == 0)) - STORE_CHAR; - else if ((cflags & REG_EXTENDED) && (i == 0)) - continue; - else - goto badpat; - continue; - case TRE_CHAR('|'): - if ((cflags & REG_EXTENDED) ^ escaped) - goto badpat; - else - STORE_CHAR; - continue; - default: - if (escaped) - goto badpat; - else - STORE_CHAR; - continue; - } - continue; -badpat: - free(tmp); - DPRINT(("tre_compile_fast: compilation of pattern failed, falling" - "back to NFA\n")); - return REG_BADPAT; - } - - fg->hasdot = wfirstdot > -1; - - /* - * The pattern has been processed and copied to tmp as a literal string - * with escapes, anchors (^$) and the word boundary match character - * classes stripped out. - */ -#ifdef TRE_WCHAR - SAVE_PATTERN(tmp, pos, fg->wpattern, fg->wlen); - fg->wescmap = _escmap; - STORE_MBS_PAT; - - /* - * The position of dots and escaped dots is different in the MB string - * than in to the wide string so traverse the converted string, as well, - * to store these positions. - */ - if (fg->hasdot || (fg->wescmap != NULL)) - { - if (fg->wescmap != NULL) - { - fg->escmap = calloc(fg->len, sizeof(bool)); - if (fg->escmap == NULL) - { - tre_free_fast(fg); - return REG_ESPACE; - } - } - - escaped = false; - char *_checkpat = NULL; - size_t _checklen = 0; - unsigned int escofs = 0; - /* - * Make a copy here of the original pattern, because fg->pattern has - * already been stripped of all escape sequences in the above processing. - * This is necessary if we wish to later treat fg->escmap as an actual, - * functional replacement of fg->wescmap. - */ - CONV_MBS_PAT(pat, _checkpat, _checklen); - for (unsigned int i = 0; i < n; i++) - if (_checkpat[i] == '\\') - { - escaped = !escaped; - if (escaped) - ++escofs; - } - else if (_checkpat[i] == '.' && fg->escmap != NULL && escaped) - { - fg->escmap[i - escofs] = true; - escaped = false; - } - else if (_checkpat[i] == '.' && !escaped) - { - hasdot = i; - if (firstdot == -1) - firstdot = i; - } - else - escaped = false; - free(_checkpat); - } -#else - SAVE_PATTERN(tmp, pos, fg->pattern, fg->len); - fg->escmap = _escmap; -#endif - - free(tmp); - - DPRINT(("tre_compile_fast: pattern: %s, len %zu, bol %c, eol %c, " - "icase: %c, word: %c, newline %c\n", fg->pattern, fg->len, - fg->bol ? 'y' : 'n', fg->eol ? 'y' : 'n', - fg->icase ? 'y' : 'n', fg->word ? 'y' : 'n', - fg->newline ? 'y' : 'n')); - - /* Check whether reverse QS algorithm is more efficient */ - if ((wfirstdot > -1) && (fg->wlen - whasdot + 1 < (size_t)wfirstdot) && - fg->nosub) - { - fg->reversed = true; - DPRINT(("tre_compile_fast: using reverse QS algorithm\n")); - } - - FILL_QSBC; - FILL_BMGS; -#ifdef TRE_WCHAR - FILL_QSBC_WIDE; - FILL_BMGS_WIDE; -#endif - - return REG_OK; -} - -#define _SHIFT_ONE \ - { \ - shift = 1; \ - j = !fg->reversed ? j + shift : j - shift; \ - continue; \ - } - -#define _BBOUND_COND \ - ((type == STR_WIDE) ? \ - ((j == 0) || !(tre_isalnum(str_wide[j - 1]) || \ - (str_wide[j - 1] == TRE_CHAR('_')))) : \ - ((j == 0) || !(tre_isalnum(str_byte[j - 1]) || \ - (str_byte[j - 1] == '_')))) - -#define _EBOUND_COND \ - ((type == STR_WIDE) ? \ - ((j + fg->wlen == len) || !(tre_isalnum(str_wide[j + fg->wlen]) || \ - (str_wide[j + fg->wlen] == TRE_CHAR('_')))) : \ - ((j + fg->len == len) || !(tre_isalnum(str_byte[j + fg->len]) || \ - (str_byte[j + fg->len] == '_')))) - -/* - * Condition to check whether the match on position j is on a - * word boundary. - */ -#define IS_ON_WORD_BOUNDARY \ - (_BBOUND_COND && _EBOUND_COND) - -/* - * Checks word boundary and shifts one if match is not on a - * boundary. - */ -#define CHECK_WORD_BOUNDARY \ - if (!IS_ON_WORD_BOUNDARY) \ - _SHIFT_ONE; - -#define _BOL_COND \ - ((j == 0) || ((type == STR_WIDE) ? (str_wide[j - 1] == TRE_CHAR('\n'))\ - : (str_byte[j - 1] == '\n'))) - -/* - * Checks BOL anchor and shifts one if match is not on a - * boundary. - */ -#define CHECK_BOL_ANCHOR \ - if (!_BOL_COND) \ - _SHIFT_ONE; - -#define _EOL_COND \ - ((type == STR_WIDE) \ - ? ((j + fg->wlen == len) || \ - (str_wide[j + fg->wlen] == TRE_CHAR('\n'))) \ - : ((j + fg->len == len) || (str_byte[j + fg->wlen] == '\n'))) - -/* - * Checks EOL anchor and shifts one if match is not on a - * boundary. - */ -#define CHECK_EOL_ANCHOR \ - if (!_EOL_COND) \ - _SHIFT_ONE; - -/* - * Executes matching of the precompiled pattern on the input string. - * Returns REG_OK or REG_NOMATCH depending on if we find a match or not. - */ -int -tre_match_fast(const fastmatch_t *fg, const void *data, size_t len, - tre_str_type_t type, int nmatch, regmatch_t pmatch[], int eflags) -{ - unsigned int shift, u = 0, v = 0; - ssize_t j = 0; - int ret = REG_NOMATCH; - int mismatch; - const char *str_byte = data; - const void *startptr = NULL; - const tre_char_t *str_wide = data; - - /* Calculate length if unspecified. */ - if (len == (size_t)-1) - switch (type) - { - case STR_WIDE: - len = tre_strlen(str_wide); - break; - default: - len = strlen(str_byte); - break; - } - - /* Shortcut for empty pattern */ - if (fg->matchall) - { - if (!fg->nosub && nmatch >= 1) - { - pmatch[0].rm_so = 0; - pmatch[0].rm_eo = len; - } - if (fg->bol && fg->eol) - return (len == 0) ? REG_OK : REG_NOMATCH; - else - return REG_OK; - } - - /* No point in going farther if we do not have enough data. */ - switch (type) - { - case STR_WIDE: - if (len < fg->wlen) - return ret; - shift = fg->wlen; - break; - default: - if (len < fg->len) - return ret; - shift = fg->len; - } - - /* - * REG_NOTBOL means not anchoring ^ to the beginning of the line, so we - * can shift one because there can't be a match at the beginning. - */ - if (fg->bol && (eflags & REG_NOTBOL)) - j = 1; - - /* - * Like above, we cannot have a match at the very end when anchoring to - * the end and REG_NOTEOL is specified. - */ - if (fg->eol && (eflags & REG_NOTEOL)) - len--; - - if (fg->reversed) - j = len - (type == STR_WIDE ? fg->wlen : fg->len); - - - /* Only try once at the beginning or ending of the line. */ - if ((fg->bol || fg->eol) && !fg->newline && !(eflags & REG_NOTBOL) && - !(eflags & REG_NOTEOL)) - { - /* Simple text comparison. */ - if (!((fg->bol && fg->eol) && - (type == STR_WIDE ? (len != fg->wlen) : (len != fg->len)))) - { - /* Determine where in data to start search at. */ - j = fg->eol ? len - (type == STR_WIDE ? fg->wlen : fg->len) : 0; - SKIP_CHARS(j); - mismatch = fastcmp(fg, startptr, type); - if (mismatch == REG_OK) - { - if (fg->word && !IS_ON_WORD_BOUNDARY) - return ret; - if (!fg->nosub && nmatch >= 1) - { - pmatch[0].rm_so = j; - pmatch[0].rm_eo = j + (type == STR_WIDE ? fg->wlen : fg->len); - } - return REG_OK; - } - } - } - else - { - /* Quick Search / Turbo Boyer-Moore algorithm. */ - do - { - SKIP_CHARS(j); - mismatch = fastcmp(fg, startptr, type); - if (mismatch == REG_OK) - { - if (fg->word) - CHECK_WORD_BOUNDARY; - if (fg->bol) - CHECK_BOL_ANCHOR; - if (fg->eol) - CHECK_EOL_ANCHOR; - if (!fg->nosub && nmatch >= 1) - { - pmatch[0].rm_so = j; - pmatch[0].rm_eo = j + ((type == STR_WIDE) ? fg->wlen : fg->len); - } - return REG_OK; - } - else if (mismatch > 0) - return mismatch; - mismatch = -mismatch - 1; - SHIFT; - } while (!IS_OUT_OF_BOUNDS); - } - return ret; -} - -/* - * Frees the resources that were allocated when the pattern was compiled. - */ -void -tre_free_fast(fastmatch_t *fg) -{ - - DPRINT(("tre_fast_free: freeing structures for pattern %s\n", - fg->pattern)); - -#ifdef TRE_WCHAR - hashtable_free(fg->qsBc_table); - if (!fg->hasdot) - free(fg->bmGs); - if (fg->wescmap) - free(fg->wescmap); - free(fg->wpattern); -#endif - if (!fg->hasdot) - free(fg->sbmGs); - if (fg->escmap) - free(fg->escmap); - free(fg->pattern); -} - -/* - * Returns: -(i + 1) on failure (position that it failed with minus sign) - * error code on error - * REG_OK on success - */ -static inline int -fastcmp(const fastmatch_t *fg, const void *data, tre_str_type_t type) -{ - const char *str_byte = data; - const char *pat_byte = fg->pattern; - const tre_char_t *str_wide = data; - const tre_char_t *pat_wide = fg->wpattern; - const bool *escmap = (type == STR_WIDE) ? fg->wescmap : fg->escmap; - size_t len = (type == STR_WIDE) ? fg->wlen : fg->len; - int ret = REG_OK; - - /* Compare the pattern and the input char-by-char from the last position. */ - for (int i = len - 1; i >= 0; i--) { - switch (type) - { - case STR_WIDE: - - /* Check dot */ - if (fg->hasdot && pat_wide[i] == TRE_CHAR('.') && - (!escmap || !escmap[i]) && - (!fg->newline || (str_wide[i] != TRE_CHAR('\n')))) - continue; - - /* Compare */ - if (fg->icase ? (towlower(pat_wide[i]) == towlower(str_wide[i])) - : (pat_wide[i] == str_wide[i])) - continue; - break; - default: - /* Check dot */ - if (fg->hasdot && pat_byte[i] == '.' && - (!escmap || !escmap[i]) && - (!fg->newline || (str_byte[i] != '\n'))) - continue; - - /* Compare */ - if (fg->icase ? (tolower((unsigned char)pat_byte[i]) == tolower((unsigned char)str_byte[i])) - : (pat_byte[i] == str_byte[i])) - continue; - } - DPRINT(("fastcmp: mismatch at position %d\n", i)); - ret = -(i + 1); - break; - } - return ret; -} Property changes on: head/usr.bin/grep/regex/tre-fastmatch.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/usr.bin/grep/regex/glue.h =================================================================== --- head/usr.bin/grep/regex/glue.h (revision 333235) +++ head/usr.bin/grep/regex/glue.h (nonexistent) @@ -1,67 +0,0 @@ -/* $FreeBSD$ */ - -#ifndef GLUE_H -#define GLUE_H - -#include -#undef RE_DUP_MAX -#include -#include -#include - -#define TRE_WCHAR 1 -#define TRE_MULTIBYTE 1 -#define HAVE_MBSTATE_T 1 - -#define TRE_CHAR(n) L##n -#define CHF "%lc" - -#define tre_char_t wchar_t -#define tre_mbrtowc(pwc, s, n, ps) (mbrtowc((pwc), (s), (n), (ps))) -#define tre_strlen wcslen -#define tre_isspace iswspace -#define tre_isalnum iswalnum - -#define REG_OK 0 -#define REG_LITERAL 0020 -#define REG_WORD 0100 -#define REG_GNU 0400 - -#define TRE_MB_CUR_MAX MB_CUR_MAX - -#ifndef _GREP_DEBUG -#define DPRINT(msg) -#else -#define DPRINT(msg) do {printf msg; fflush(stdout);} while(/*CONSTCOND*/0) -#endif - -#define MIN(a,b) ((a > b) ? (b) : (a)) -#define MAX(a,b) ((a > b) ? (a) : (b)) - -typedef enum { STR_WIDE, STR_BYTE, STR_MBS, STR_USER } tre_str_type_t; - -#define CALL_WITH_OFFSET(fn) \ - do \ - { \ - size_t slen = (size_t)(pmatch[0].rm_eo - pmatch[0].rm_so); \ - size_t offset = pmatch[0].rm_so; \ - int ret; \ - \ - if ((long long)pmatch[0].rm_eo - pmatch[0].rm_so < 0) \ - return REG_NOMATCH; \ - ret = fn; \ - for (unsigned i = 0; (!preg->nosub && (i < nmatch)); i++) \ - { \ - pmatch[i].rm_so += offset; \ - pmatch[i].rm_eo += offset; \ - } \ - return ret; \ - } while (0 /*CONSTCOND*/) - -int -tre_convert_pattern(const char *regex, size_t n, tre_char_t **w, - size_t *wn); - -void -tre_free_pattern(tre_char_t *wregex); -#endif Property changes on: head/usr.bin/grep/regex/glue.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/usr.bin/grep/regex/tre-fastmatch.h =================================================================== --- head/usr.bin/grep/regex/tre-fastmatch.h (revision 333235) +++ head/usr.bin/grep/regex/tre-fastmatch.h (nonexistent) @@ -1,21 +0,0 @@ -/* $FreeBSD$ */ - -#ifndef TRE_FASTMATCH_H -#define TRE_FASTMATCH_H 1 - -#include -#include -#include -#include -#include - -#include "hashtable.h" - -int tre_compile_literal(fastmatch_t *preg, const tre_char_t *regex, - size_t, int); -int tre_compile_fast(fastmatch_t *preg, const tre_char_t *regex, size_t, int); -int tre_match_fast(const fastmatch_t *fg, const void *data, size_t len, - tre_str_type_t type, int nmatch, regmatch_t pmatch[], int eflags); -void tre_free_fast(fastmatch_t *preg); - -#endif /* TRE_FASTMATCH_H */ Property changes on: head/usr.bin/grep/regex/tre-fastmatch.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/usr.bin/grep/regex/hashtable.c =================================================================== --- head/usr.bin/grep/regex/hashtable.c (revision 333235) +++ head/usr.bin/grep/regex/hashtable.c (nonexistent) @@ -1,270 +0,0 @@ -/* $FreeBSD$ */ - -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2011 Gabor Kovesdan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "glue.h" - -#include -#include -#include -#include - -#include "hashtable.h" - - -/* - * Return a 32-bit hash of the given buffer. The init - * value should be 0, or the previous hash value to extend - * the previous hash. - */ -static uint32_t -hash32_buf(const void *buf, size_t len, uint32_t hash) -{ - const unsigned char *p = buf; - - while (len--) - hash = HASHSTEP(hash, *p++); - - return hash; -} - -/* - * Initializes a hash table that can hold table_size number of entries, - * each of which has a key of key_size bytes and a value of value_size - * bytes. On successful allocation returns a pointer to the hash table. - * Otherwise, returns NULL and sets errno to indicate the error. - */ -hashtable -*hashtable_init(size_t table_size, size_t key_size, size_t value_size) -{ - hashtable *tbl; - - DPRINT(("hashtable_init: table_size %zu, key_size %zu, value_size %zu\n", - table_size, key_size, value_size)); - - tbl = malloc(sizeof(hashtable)); - if (tbl == NULL) - goto mem1; - - tbl->entries = calloc(sizeof(hashtable_entry *), table_size); - if (tbl->entries == NULL) - goto mem2; - - tbl->table_size = table_size; - tbl->usage = 0; - tbl->key_size = key_size; - tbl->value_size = value_size; - - return (tbl); - -mem2: - free(tbl); -mem1: - DPRINT(("hashtable_init: allocation failed\n")); - errno = ENOMEM; - return (NULL); -} - -/* - * Places the key-value pair to the hashtable tbl. - * Returns: - * HASH_OK: if the key was not present in the hash table yet - * but the kay-value pair has been successfully added. - * HASH_UPDATED: if the value for the key has been updated with the - * new value. - * HASH_FULL: if the hash table is full and the entry could not - * be added. - * HASH_FAIL: if an error has occurred and errno has been set to - * indicate the error. - */ -int -hashtable_put(hashtable *tbl, const void *key, const void *value) -{ - uint32_t hash = 0; - - if (tbl->table_size == tbl->usage) - { - DPRINT(("hashtable_put: hashtable is full\n")); - return (HASH_FULL); - } - - hash = hash32_buf(key, tbl->key_size, hash) % tbl->table_size; - DPRINT(("hashtable_put: calculated hash %" PRIu32 "\n", hash)); - - /* - * On hash collision entries are inserted at the next free space, - * so we have to increase the index until we either find an entry - * with the same key (and update it) or we find a free space. - */ - for(;;) - { - if (tbl->entries[hash] == NULL) - break; - else if (memcmp(tbl->entries[hash]->key, key, tbl->key_size) == 0) - { - memcpy(tbl->entries[hash]->value, value, tbl->value_size); - DPRINT(("hashtable_put: effective location is %" PRIu32 - ", entry updated\n", hash)); - return (HASH_UPDATED); - } - if (++hash == tbl->table_size) - hash = 0; - } - - DPRINT(("hashtable_put: effective location is %" PRIu32 "\n", hash)); - - tbl->entries[hash] = malloc(sizeof(hashtable_entry)); - if (tbl->entries[hash] == NULL) - { - errno = ENOMEM; - goto mem1; - } - - tbl->entries[hash]->key = malloc(tbl->key_size); - if (tbl->entries[hash]->key == NULL) - { - errno = ENOMEM; - goto mem2; - } - - tbl->entries[hash]->value = malloc(tbl->value_size); - if (tbl->entries[hash]->value == NULL) - { - errno = ENOMEM; - goto mem3; - } - - memcpy(tbl->entries[hash]->key, key, tbl->key_size); - memcpy(tbl->entries[hash]->value, value, tbl->value_size); - tbl->usage++; - - DPRINT(("hashtable_put: entry successfully inserted\n")); - - return (HASH_OK); - -mem3: - free(tbl->entries[hash]->key); -mem2: - free(tbl->entries[hash]); -mem1: - DPRINT(("hashtable_put: insertion failed\n")); - return (HASH_FAIL); -} - -static hashtable_entry -**hashtable_lookup(const hashtable *tbl, const void *key) -{ - uint32_t hash = 0; - - hash = hash32_buf(key, tbl->key_size, hash) % tbl->table_size; - - for (;;) - { - if (tbl->entries[hash] == NULL) - return (NULL); - else if (memcmp(key, tbl->entries[hash]->key, tbl->key_size) == 0) - { - DPRINT(("hashtable_lookup: entry found at location %" PRIu32 "\n", hash)); - return (&tbl->entries[hash]); - } - - if (++hash == tbl->table_size) - hash = 0; - } -} - -/* - * Retrieves the value for key from the hash table tbl and places - * it to the space indicated by the value argument. - * Returns HASH_OK if the value has been found and retrieved or - * HASH_NOTFOUND otherwise. - */ -int -hashtable_get(hashtable *tbl, const void *key, void *value) -{ - hashtable_entry **entry; - - entry = hashtable_lookup(tbl, key); - if (entry == NULL) - { - DPRINT(("hashtable_get: entry is not available in the hashtable\n")); - return (HASH_NOTFOUND); - } - - memcpy(value, (*entry)->value, tbl->value_size); - DPRINT(("hashtable_get: entry successfully copied into output buffer\n")); - return (HASH_OK); -} - -/* - * Removes the entry with the specifified key from the hash table - * tbl. Returns HASH_OK if the entry has been found and removed - * or HASH_NOTFOUND otherwise. - */ -int -hashtable_remove(hashtable *tbl, const void *key) -{ - hashtable_entry **entry; - - entry = hashtable_lookup(tbl, key); - if (entry == NULL) - { - DPRINT(("hashtable_remove: entry is not available in the hashtable\n")); - return (HASH_NOTFOUND); - } - - free((*entry)->key); - free((*entry)->value); - free(*entry); - *entry = NULL; - - tbl->usage--; - DPRINT(("hashtable_remove: entry successfully removed\n")); - return (HASH_OK); -} - -/* - * Frees the resources associated with the hash table tbl. - */ -void -hashtable_free(hashtable *tbl) -{ - if (tbl == NULL) - return; - - for (unsigned int i = 0; i < tbl->table_size; i++) - if ((tbl->entries[i] != NULL)) - { - free(tbl->entries[i]->key); - free(tbl->entries[i]->value); - } - - free(tbl->entries); - DPRINT(("hashtable_free: resources are successfully freed\n")); -} Property changes on: head/usr.bin/grep/regex/hashtable.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/usr.bin/grep/regex/tre-compile.c =================================================================== --- head/usr.bin/grep/regex/tre-compile.c (revision 333235) +++ head/usr.bin/grep/regex/tre-compile.c (nonexistent) @@ -1,101 +0,0 @@ -/* $FreeBSD$ */ - -#include "glue.h" - -#include -#include -#include -#include -#include -#include - -int -tre_convert_pattern(const char *regex, size_t n, tre_char_t **w, - size_t *wn) -{ -#if TRE_WCHAR - tre_char_t *wregex; - size_t wlen; - - wregex = malloc(sizeof(tre_char_t) * (n + 1)); - if (wregex == NULL) - return REG_ESPACE; - - /* If the current locale uses the standard single byte encoding of - characters, we don't do a multibyte string conversion. If we did, - many applications which use the default locale would break since - the default "C" locale uses the 7-bit ASCII character set, and - all characters with the eighth bit set would be considered invalid. */ -#if TRE_MULTIBYTE - if (TRE_MB_CUR_MAX == 1) -#endif /* TRE_MULTIBYTE */ - { - unsigned int i; - const unsigned char *str = (const unsigned char *)regex; - tre_char_t *wstr = wregex; - - for (i = 0; i < n; i++) - *(wstr++) = *(str++); - wlen = n; - } -#if TRE_MULTIBYTE - else - { - int consumed; - tre_char_t *wcptr = wregex; -#ifdef HAVE_MBSTATE_T - mbstate_t state; - memset(&state, '\0', sizeof(state)); -#endif /* HAVE_MBSTATE_T */ - while (n > 0) - { - consumed = tre_mbrtowc(wcptr, regex, n, &state); - - switch (consumed) - { - case 0: - if (*regex == '\0') - consumed = 1; - else - { - free(wregex); - return REG_BADPAT; - } - break; - case -1: - DPRINT(("mbrtowc: error %d: %s.\n", errno, strerror(errno))); - free(wregex); - return REG_BADPAT; - case -2: - /* The last character wasn't complete. Let's not call it a - fatal error. */ - consumed = n; - break; - } - regex += consumed; - n -= consumed; - wcptr++; - } - wlen = wcptr - wregex; - } -#endif /* TRE_MULTIBYTE */ - wregex[wlen] = L'\0'; - *w = wregex; - *wn = wlen; - return REG_OK; -#else /* !TRE_WCHAR */ - { - *w = (tre_char_t * const *)regex; - *wn = n; - return REG_OK; - } -#endif /* !TRE_WCHAR */ -} - -void -tre_free_pattern(tre_char_t *wregex) -{ -#if TRE_WCHAR - free(wregex); -#endif -} Property changes on: head/usr.bin/grep/regex/tre-compile.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/usr.bin/grep/regex/fastmatch.c =================================================================== --- head/usr.bin/grep/regex/fastmatch.c (revision 333235) +++ head/usr.bin/grep/regex/fastmatch.c (nonexistent) @@ -1,170 +0,0 @@ -/* $FreeBSD$ */ - -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2011 Gabor Kovesdan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "glue.h" - -#include -#include -#include -#include - -#include "tre-fastmatch.h" - -int -tre_fixncomp(fastmatch_t *preg, const char *regex, size_t n, int cflags) -{ - int ret; - tre_char_t *wregex; - size_t wlen; - - if (n != 0) - { - ret = tre_convert_pattern(regex, n, &wregex, &wlen); - if (ret != REG_OK) - return ret; - else - ret = tre_compile_literal(preg, wregex, wlen, cflags); - tre_free_pattern(wregex); - return ret; - } - else - return tre_compile_literal(preg, NULL, 0, cflags); -} - -int -tre_fastncomp(fastmatch_t *preg, const char *regex, size_t n, int cflags) -{ - int ret; - tre_char_t *wregex; - size_t wlen; - - if (n != 0) - { - ret = tre_convert_pattern(regex, n, &wregex, &wlen); - if (ret != REG_OK) - return ret; - else - ret = (cflags & REG_LITERAL) - ? tre_compile_literal(preg, wregex, wlen, cflags) - : tre_compile_fast(preg, wregex, wlen, cflags); - tre_free_pattern(wregex); - return ret; - } - else - return tre_compile_literal(preg, NULL, 0, cflags); -} - - -int -tre_fixcomp(fastmatch_t *preg, const char *regex, int cflags) -{ - return tre_fixncomp(preg, regex, regex ? strlen(regex) : 0, cflags); -} - -int -tre_fastcomp(fastmatch_t *preg, const char *regex, int cflags) -{ - return tre_fastncomp(preg, regex, regex ? strlen(regex) : 0, cflags); -} - -int -tre_fixwncomp(fastmatch_t *preg, const wchar_t *regex, size_t n, int cflags) -{ - return tre_compile_literal(preg, regex, n, cflags); -} - -int -tre_fastwncomp(fastmatch_t *preg, const wchar_t *regex, size_t n, int cflags) -{ - return (cflags & REG_LITERAL) ? - tre_compile_literal(preg, regex, n, cflags) : - tre_compile_fast(preg, regex, n, cflags); -} - -int -tre_fixwcomp(fastmatch_t *preg, const wchar_t *regex, int cflags) -{ - return tre_fixwncomp(preg, regex, regex ? tre_strlen(regex) : 0, cflags); -} - -int -tre_fastwcomp(fastmatch_t *preg, const wchar_t *regex, int cflags) -{ - return tre_fastwncomp(preg, regex, regex ? tre_strlen(regex) : 0, cflags); -} - -void -tre_fastfree(fastmatch_t *preg) -{ - tre_free_fast(preg); -} - -int -tre_fastnexec(const fastmatch_t *preg, const char *string, size_t len, - size_t nmatch, regmatch_t pmatch[], int eflags) -{ - tre_str_type_t type = (TRE_MB_CUR_MAX == 1) ? STR_BYTE : STR_MBS; - - if (eflags & REG_STARTEND) - CALL_WITH_OFFSET(tre_match_fast(preg, &string[offset], slen, - type, nmatch, pmatch, eflags)); - else - return tre_match_fast(preg, string, len, type, nmatch, - pmatch, eflags); -} - -int -tre_fastexec(const fastmatch_t *preg, const char *string, size_t nmatch, - regmatch_t pmatch[], int eflags) -{ - return tre_fastnexec(preg, string, (size_t)-1, nmatch, pmatch, eflags); -} - -int -tre_fastwnexec(const fastmatch_t *preg, const wchar_t *string, size_t len, - size_t nmatch, regmatch_t pmatch[], int eflags) -{ - tre_str_type_t type = STR_WIDE; - - if (eflags & REG_STARTEND) - CALL_WITH_OFFSET(tre_match_fast(preg, &string[offset], slen, - type, nmatch, pmatch, eflags)); - else - return tre_match_fast(preg, string, len, type, nmatch, - pmatch, eflags); -} - -int -tre_fastwexec(const fastmatch_t *preg, const wchar_t *string, - size_t nmatch, regmatch_t pmatch[], int eflags) -{ - return tre_fastwnexec(preg, string, (size_t)-1, nmatch, pmatch, eflags); -} - Property changes on: head/usr.bin/grep/regex/fastmatch.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/usr.bin/grep/Makefile =================================================================== --- head/usr.bin/grep/Makefile (revision 333235) +++ head/usr.bin/grep/Makefile (revision 333236) @@ -1,86 +1,77 @@ # $NetBSD: Makefile,v 1.4 2011/02/16 01:31:33 joerg Exp $ # $FreeBSD$ # $OpenBSD: Makefile,v 1.6 2003/06/25 15:00:04 millert Exp $ .include .if ${MK_BSD_GREP} == "yes" PROG= grep MAN1= grep.1 zgrep.1 .else PROG= bsdgrep CLEANFILES+= bsdgrep.1 MAN1= grep.1 zgrep.1 bsdgrep.1: grep.1 ${CP} ${.ALLSRC} ${.TARGET} .endif SRCS= file.c grep.c queue.c util.c -.if ${MK_BSD_GREP_FASTMATCH} == "yes" -# Extra files ported backported for some regex improvements -.PATH: ${.CURDIR}/regex -SRCS+= fastmatch.c hashtable.c tre-compile.c tre-fastmatch.c -CFLAGS+=-I${.CURDIR}/regex -.else -CFLAGS+= -DWITHOUT_FASTMATCH -.endif - SCRIPTS= zgrep.sh LINKS= ${BINDIR}/zgrep ${BINDIR}/zfgrep \ ${BINDIR}/zgrep ${BINDIR}/zegrep \ ${BINDIR}/zgrep ${BINDIR}/bzgrep \ ${BINDIR}/zgrep ${BINDIR}/bzegrep \ ${BINDIR}/zgrep ${BINDIR}/bzfgrep \ ${BINDIR}/zgrep ${BINDIR}/lzgrep \ ${BINDIR}/zgrep ${BINDIR}/lzegrep \ ${BINDIR}/zgrep ${BINDIR}/lzfgrep \ ${BINDIR}/zgrep ${BINDIR}/xzgrep \ ${BINDIR}/zgrep ${BINDIR}/xzegrep \ ${BINDIR}/zgrep ${BINDIR}/xzfgrep \ ${BINDIR}/zgrep ${BINDIR}/zstdgrep \ ${BINDIR}/zgrep ${BINDIR}/zstdegrep \ ${BINDIR}/zgrep ${BINDIR}/zstdegrep MLINKS= zgrep.1 zfgrep.1 \ zgrep.1 zegrep.1 \ zgrep.1 bzgrep.1 \ zgrep.1 bzegrep.1 \ zgrep.1 bzfgrep.1 \ zgrep.1 lzgrep.1 \ zgrep.1 lzegrep.1 \ zgrep.1 lzfgrep.1 \ zgrep.1 xzgrep.1 \ zgrep.1 xzegrep.1 \ zgrep.1 xzfgrep.1 \ zgrep.1 zstdgrep.1 \ zgrep.1 zstdegrep.1 \ zgrep.1 zstdfgrep.1 CFLAGS.gcc+= --param max-inline-insns-single=500 .if ${MK_BSD_GREP} == "yes" LINKS+= ${BINDIR}/grep ${BINDIR}/egrep \ ${BINDIR}/grep ${BINDIR}/fgrep \ ${BINDIR}/grep ${BINDIR}/rgrep \ MLINKS+= grep.1 egrep.1 \ grep.1 fgrep.1 \ grep.1 rgrep.1 .endif .if ${MK_GNU_GREP_COMPAT} != "no" CFLAGS+= -I${SYSROOT:U${DESTDIR}}/usr/include/gnu -DWITH_GNU LIBADD+= gnuregex .endif .if ${MK_NLS} != "no" .include "${.CURDIR}/nls/Makefile.inc" .else CFLAGS+= -DWITHOUT_NLS .endif HAS_TESTS= SUBDIR.${MK_TESTS}+= tests .include Index: head/usr.bin/grep/grep.c =================================================================== --- head/usr.bin/grep/grep.c (revision 333235) +++ head/usr.bin/grep/grep.c (revision 333236) @@ -1,771 +1,753 @@ /* $NetBSD: grep.c,v 1.6 2011/04/18 03:48:23 joerg Exp $ */ /* $FreeBSD$ */ /* $OpenBSD: grep.c,v 1.42 2010/07/02 22:18:03 tedu Exp $ */ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav * Copyright (C) 2008-2009 Gabor Kovesdan * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#ifndef WITHOUT_FASTMATCH -#include "fastmatch.h" -#endif #include "grep.h" #ifndef WITHOUT_NLS #include nl_catd catalog; #endif /* * Default messags to use when NLS is disabled or no catalogue * is found. */ const char *errstr[] = { "", /* 1*/ "(standard input)", /* 2*/ "unknown %s option", /* 3*/ "usage: %s [-abcDEFGHhIiLlmnOoPqRSsUVvwxz] [-A num] [-B num] [-C[num]]\n", /* 4*/ "\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n", /* 5*/ "\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n", /* 6*/ "\t[--null] [pattern] [file ...]\n", /* 7*/ "Binary file %s matches\n", /* 8*/ "%s (BSD grep) %s\n", /* 9*/ "%s (BSD grep, GNU compatible) %s\n", }; /* Flags passed to regcomp() and regexec() */ int cflags = REG_NOSUB | REG_NEWLINE; int eflags = REG_STARTEND; /* XXX TODO: Get rid of this flag. * matchall is a gross hack that means that an empty pattern was passed to us. * It is a necessary evil at the moment because our regex(3) implementation * does not allow for empty patterns, as supported by POSIX's definition of * grammar for BREs/EREs. When libregex becomes available, it would be wise * to remove this and let regex(3) handle the dirty details of empty patterns. */ bool matchall; /* Searching patterns */ unsigned int patterns; static unsigned int pattern_sz; struct pat *pattern; regex_t *r_pattern; -#ifndef WITHOUT_FASTMATCH -fastmatch_t *fg_pattern; -#endif /* Filename exclusion/inclusion patterns */ unsigned int fpatterns, dpatterns; static unsigned int fpattern_sz, dpattern_sz; struct epat *dpattern, *fpattern; /* For regex errors */ char re_error[RE_ERROR_BUF + 1]; /* Command-line flags */ long long Aflag; /* -A x: print x lines trailing each match */ long long Bflag; /* -B x: print x lines leading each match */ bool Hflag; /* -H: always print file name */ bool Lflag; /* -L: only show names of files with no matches */ bool bflag; /* -b: show block numbers for each match */ bool cflag; /* -c: only show a count of matching lines */ bool hflag; /* -h: don't print filename headers */ bool iflag; /* -i: ignore case */ bool lflag; /* -l: only show names of files with matches */ bool mflag; /* -m x: stop reading the files after x matches */ long long mcount; /* count for -m */ long long mlimit; /* requested value for -m */ char fileeol; /* indicator for eol */ bool nflag; /* -n: show line numbers in front of matching lines */ bool oflag; /* -o: print only matching part */ bool qflag; /* -q: quiet mode (don't output anything) */ bool sflag; /* -s: silent mode (ignore errors) */ bool vflag; /* -v: only show non-matching lines */ bool wflag; /* -w: pattern must start and end on word boundaries */ bool xflag; /* -x: pattern must match entire line */ bool lbflag; /* --line-buffered */ bool nullflag; /* --null */ char *label; /* --label */ const char *color; /* --color */ int grepbehave = GREP_BASIC; /* -EFGP: type of the regex */ int binbehave = BINFILE_BIN; /* -aIU: handling of binary files */ int filebehave = FILE_STDIO; int devbehave = DEV_READ; /* -D: handling of devices */ int dirbehave = DIR_READ; /* -dRr: handling of directories */ int linkbehave = LINK_READ; /* -OpS: handling of symlinks */ bool dexclude, dinclude; /* --exclude-dir and --include-dir */ bool fexclude, finclude; /* --exclude and --include */ enum { BIN_OPT = CHAR_MAX + 1, COLOR_OPT, HELP_OPT, MMAP_OPT, LINEBUF_OPT, LABEL_OPT, NULL_OPT, R_EXCLUDE_OPT, R_INCLUDE_OPT, R_DEXCLUDE_OPT, R_DINCLUDE_OPT }; static inline const char *init_color(const char *); /* Housekeeping */ bool file_err; /* file reading error */ /* * Prints usage information and returns 2. */ static void usage(void) { fprintf(stderr, getstr(3), getprogname()); fprintf(stderr, "%s", getstr(4)); fprintf(stderr, "%s", getstr(5)); fprintf(stderr, "%s", getstr(6)); exit(2); } static const char *optstr = "0123456789A:B:C:D:EFGHILOPSRUVabcd:e:f:hilm:nopqrsuvwxyz"; static const struct option long_options[] = { {"binary-files", required_argument, NULL, BIN_OPT}, {"help", no_argument, NULL, HELP_OPT}, {"mmap", no_argument, NULL, MMAP_OPT}, {"line-buffered", no_argument, NULL, LINEBUF_OPT}, {"label", required_argument, NULL, LABEL_OPT}, {"null", no_argument, NULL, NULL_OPT}, {"color", optional_argument, NULL, COLOR_OPT}, {"colour", optional_argument, NULL, COLOR_OPT}, {"exclude", required_argument, NULL, R_EXCLUDE_OPT}, {"include", required_argument, NULL, R_INCLUDE_OPT}, {"exclude-dir", required_argument, NULL, R_DEXCLUDE_OPT}, {"include-dir", required_argument, NULL, R_DINCLUDE_OPT}, {"after-context", required_argument, NULL, 'A'}, {"text", no_argument, NULL, 'a'}, {"before-context", required_argument, NULL, 'B'}, {"byte-offset", no_argument, NULL, 'b'}, {"context", optional_argument, NULL, 'C'}, {"count", no_argument, NULL, 'c'}, {"devices", required_argument, NULL, 'D'}, {"directories", required_argument, NULL, 'd'}, {"extended-regexp", no_argument, NULL, 'E'}, {"regexp", required_argument, NULL, 'e'}, {"fixed-strings", no_argument, NULL, 'F'}, {"file", required_argument, NULL, 'f'}, {"basic-regexp", no_argument, NULL, 'G'}, {"no-filename", no_argument, NULL, 'h'}, {"with-filename", no_argument, NULL, 'H'}, {"ignore-case", no_argument, NULL, 'i'}, {"files-with-matches", no_argument, NULL, 'l'}, {"files-without-match", no_argument, NULL, 'L'}, {"max-count", required_argument, NULL, 'm'}, {"line-number", no_argument, NULL, 'n'}, {"only-matching", no_argument, NULL, 'o'}, {"quiet", no_argument, NULL, 'q'}, {"silent", no_argument, NULL, 'q'}, {"recursive", no_argument, NULL, 'r'}, {"no-messages", no_argument, NULL, 's'}, {"binary", no_argument, NULL, 'U'}, {"unix-byte-offsets", no_argument, NULL, 'u'}, {"invert-match", no_argument, NULL, 'v'}, {"version", no_argument, NULL, 'V'}, {"word-regexp", no_argument, NULL, 'w'}, {"line-regexp", no_argument, NULL, 'x'}, {"null-data", no_argument, NULL, 'z'}, {NULL, no_argument, NULL, 0} }; /* * Adds a searching pattern to the internal array. */ static void add_pattern(char *pat, size_t len) { /* Do not add further pattern is we already match everything */ if (matchall) return; /* Check if we can do a shortcut */ if (len == 0) { matchall = true; for (unsigned int i = 0; i < patterns; i++) { free(pattern[i].pat); } pattern = grep_realloc(pattern, sizeof(struct pat)); pattern[0].pat = NULL; pattern[0].len = 0; patterns = 1; return; } /* Increase size if necessary */ if (patterns == pattern_sz) { pattern_sz *= 2; pattern = grep_realloc(pattern, ++pattern_sz * sizeof(struct pat)); } if (len > 0 && pat[len - 1] == '\n') --len; /* pat may not be NUL-terminated */ pattern[patterns].pat = grep_malloc(len + 1); memcpy(pattern[patterns].pat, pat, len); pattern[patterns].len = len; pattern[patterns].pat[len] = '\0'; ++patterns; } /* * Adds a file include/exclude pattern to the internal array. */ static void add_fpattern(const char *pat, int mode) { /* Increase size if necessary */ if (fpatterns == fpattern_sz) { fpattern_sz *= 2; fpattern = grep_realloc(fpattern, ++fpattern_sz * sizeof(struct epat)); } fpattern[fpatterns].pat = grep_strdup(pat); fpattern[fpatterns].mode = mode; ++fpatterns; } /* * Adds a directory include/exclude pattern to the internal array. */ static void add_dpattern(const char *pat, int mode) { /* Increase size if necessary */ if (dpatterns == dpattern_sz) { dpattern_sz *= 2; dpattern = grep_realloc(dpattern, ++dpattern_sz * sizeof(struct epat)); } dpattern[dpatterns].pat = grep_strdup(pat); dpattern[dpatterns].mode = mode; ++dpatterns; } /* * Reads searching patterns from a file and adds them with add_pattern(). */ static void read_patterns(const char *fn) { struct stat st; FILE *f; char *line; size_t len; ssize_t rlen; if ((f = fopen(fn, "r")) == NULL) err(2, "%s", fn); if ((fstat(fileno(f), &st) == -1) || (S_ISDIR(st.st_mode))) { fclose(f); return; } len = 0; line = NULL; while ((rlen = getline(&line, &len, f)) != -1) { if (line[0] == '\0') continue; add_pattern(line, line[0] == '\n' ? 0 : (size_t)rlen); } free(line); if (ferror(f)) err(2, "%s", fn); fclose(f); } static inline const char * init_color(const char *d) { char *c; c = getenv("GREP_COLOR"); return (c != NULL && c[0] != '\0' ? c : d); } int main(int argc, char *argv[]) { char **aargv, **eargv, *eopts; char *ep; const char *pn; long long l; unsigned int aargc, eargc, i; int c, lastc, needpattern, newarg, prevoptind; setlocale(LC_ALL, ""); #ifndef WITHOUT_NLS catalog = catopen("grep", NL_CAT_LOCALE); #endif /* Check what is the program name of the binary. In this way we can have all the funcionalities in one binary without the need of scripting and using ugly hacks. */ pn = getprogname(); if (pn[0] == 'r') { dirbehave = DIR_RECURSE; Hflag = true; } switch (pn[0]) { case 'e': grepbehave = GREP_EXTENDED; break; case 'f': grepbehave = GREP_FIXED; break; } lastc = '\0'; newarg = 1; prevoptind = 1; needpattern = 1; fileeol = '\n'; eopts = getenv("GREP_OPTIONS"); /* support for extra arguments in GREP_OPTIONS */ eargc = 0; if (eopts != NULL && eopts[0] != '\0') { char *str; /* make an estimation of how many extra arguments we have */ for (unsigned int j = 0; j < strlen(eopts); j++) if (eopts[j] == ' ') eargc++; eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1)); eargc = 0; /* parse extra arguments */ while ((str = strsep(&eopts, " ")) != NULL) if (str[0] != '\0') eargv[eargc++] = grep_strdup(str); aargv = (char **)grep_calloc(eargc + argc + 1, sizeof(char *)); aargv[0] = argv[0]; for (i = 0; i < eargc; i++) aargv[i + 1] = eargv[i]; for (int j = 1; j < argc; j++, i++) aargv[i + 1] = argv[j]; aargc = eargc + argc; } else { aargv = argv; aargc = argc; } while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) != -1)) { switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (newarg || !isdigit(lastc)) Aflag = 0; else if (Aflag > LLONG_MAX / 10 - 1) { errno = ERANGE; err(2, NULL); } Aflag = Bflag = (Aflag * 10) + (c - '0'); break; case 'C': if (optarg == NULL) { Aflag = Bflag = 2; break; } /* FALLTHROUGH */ case 'A': /* FALLTHROUGH */ case 'B': errno = 0; l = strtoll(optarg, &ep, 10); if (errno == ERANGE || errno == EINVAL) err(2, NULL); else if (ep[0] != '\0') { errno = EINVAL; err(2, NULL); } else if (l < 0) { errno = EINVAL; err(2, "context argument must be non-negative"); } if (c == 'A') Aflag = l; else if (c == 'B') Bflag = l; else Aflag = Bflag = l; break; case 'a': binbehave = BINFILE_TEXT; break; case 'b': bflag = true; break; case 'c': cflag = true; break; case 'D': if (strcasecmp(optarg, "skip") == 0) devbehave = DEV_SKIP; else if (strcasecmp(optarg, "read") == 0) devbehave = DEV_READ; else errx(2, getstr(2), "--devices"); break; case 'd': if (strcasecmp("recurse", optarg) == 0) { Hflag = true; dirbehave = DIR_RECURSE; } else if (strcasecmp("skip", optarg) == 0) dirbehave = DIR_SKIP; else if (strcasecmp("read", optarg) == 0) dirbehave = DIR_READ; else errx(2, getstr(2), "--directories"); break; case 'E': grepbehave = GREP_EXTENDED; break; case 'e': { char *token; char *string = optarg; while ((token = strsep(&string, "\n")) != NULL) add_pattern(token, strlen(token)); } needpattern = 0; break; case 'F': grepbehave = GREP_FIXED; break; case 'f': read_patterns(optarg); needpattern = 0; break; case 'G': grepbehave = GREP_BASIC; break; case 'H': Hflag = true; break; case 'h': Hflag = false; hflag = true; break; case 'I': binbehave = BINFILE_SKIP; break; case 'i': case 'y': iflag = true; cflags |= REG_ICASE; break; case 'L': lflag = false; Lflag = true; break; case 'l': Lflag = false; lflag = true; break; case 'm': mflag = true; errno = 0; mlimit = mcount = strtoll(optarg, &ep, 10); if (((errno == ERANGE) && (mcount == LLONG_MAX)) || ((errno == EINVAL) && (mcount == 0))) err(2, NULL); else if (ep[0] != '\0') { errno = EINVAL; err(2, NULL); } break; case 'n': nflag = true; break; case 'O': linkbehave = LINK_EXPLICIT; break; case 'o': oflag = true; cflags &= ~REG_NOSUB; break; case 'p': linkbehave = LINK_SKIP; break; case 'q': qflag = true; break; case 'S': linkbehave = LINK_READ; break; case 'R': case 'r': dirbehave = DIR_RECURSE; Hflag = true; break; case 's': sflag = true; break; case 'U': binbehave = BINFILE_BIN; break; case 'u': case MMAP_OPT: filebehave = FILE_MMAP; break; case 'V': #ifdef WITH_GNU printf(getstr(9), getprogname(), VERSION); #else printf(getstr(8), getprogname(), VERSION); #endif exit(0); case 'v': vflag = true; break; case 'w': wflag = true; cflags &= ~REG_NOSUB; break; case 'x': xflag = true; cflags &= ~REG_NOSUB; break; case 'z': fileeol = '\0'; break; case BIN_OPT: if (strcasecmp("binary", optarg) == 0) binbehave = BINFILE_BIN; else if (strcasecmp("without-match", optarg) == 0) binbehave = BINFILE_SKIP; else if (strcasecmp("text", optarg) == 0) binbehave = BINFILE_TEXT; else errx(2, getstr(2), "--binary-files"); break; case COLOR_OPT: color = NULL; if (optarg == NULL || strcasecmp("auto", optarg) == 0 || strcasecmp("tty", optarg) == 0 || strcasecmp("if-tty", optarg) == 0) { char *term; term = getenv("TERM"); if (isatty(STDOUT_FILENO) && term != NULL && strcasecmp(term, "dumb") != 0) color = init_color("01;31"); } else if (strcasecmp("always", optarg) == 0 || strcasecmp("yes", optarg) == 0 || strcasecmp("force", optarg) == 0) { color = init_color("01;31"); } else if (strcasecmp("never", optarg) != 0 && strcasecmp("none", optarg) != 0 && strcasecmp("no", optarg) != 0) errx(2, getstr(2), "--color"); cflags &= ~REG_NOSUB; break; case LABEL_OPT: label = optarg; break; case LINEBUF_OPT: lbflag = true; break; case NULL_OPT: nullflag = true; break; case R_INCLUDE_OPT: finclude = true; add_fpattern(optarg, INCL_PAT); break; case R_EXCLUDE_OPT: fexclude = true; add_fpattern(optarg, EXCL_PAT); break; case R_DINCLUDE_OPT: dinclude = true; add_dpattern(optarg, INCL_PAT); break; case R_DEXCLUDE_OPT: dexclude = true; add_dpattern(optarg, EXCL_PAT); break; case HELP_OPT: default: usage(); } lastc = c; newarg = optind != prevoptind; prevoptind = optind; } aargc -= optind; aargv += optind; /* Empty pattern file matches nothing */ if (!needpattern && (patterns == 0)) exit(1); /* Fail if we don't have any pattern */ if (aargc == 0 && needpattern) usage(); /* Process patterns from command line */ if (aargc != 0 && needpattern) { char *token; char *string = *aargv; while ((token = strsep(&string, "\n")) != NULL) add_pattern(token, strlen(token)); --aargc; ++aargv; } switch (grepbehave) { case GREP_BASIC: break; case GREP_FIXED: /* * regex(3) implementations that support fixed-string searches generally * define either REG_NOSPEC or REG_LITERAL. Set the appropriate flag * here. If neither are defined, GREP_FIXED later implies that the * internal literal matcher should be used. Other cflags that have * the same interpretation as REG_NOSPEC and REG_LITERAL should be * similarly added here, and grep.h should be amended to take this into * consideration when defining WITH_INTERNAL_NOSPEC. */ #if defined(REG_NOSPEC) cflags |= REG_NOSPEC; #elif defined(REG_LITERAL) cflags |= REG_LITERAL; #endif break; case GREP_EXTENDED: cflags |= REG_EXTENDED; break; default: /* NOTREACHED */ usage(); } -#ifndef WITHOUT_FASTMATCH - fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern)); -#endif r_pattern = grep_calloc(patterns, sizeof(*r_pattern)); /* Don't process any patterns if we have a blank one */ #ifdef WITH_INTERNAL_NOSPEC if (!matchall && grepbehave != GREP_FIXED) { #else if (!matchall) { #endif /* Check if cheating is allowed (always is for fgrep). */ for (i = 0; i < patterns; ++i) { -#ifndef WITHOUT_FASTMATCH - /* - * Attempt compilation with fastmatch regex and - * fallback to regex(3) if it fails. - */ - if (fastncomp(&fg_pattern[i], pattern[i].pat, - pattern[i].len, cflags) == 0) - continue; -#endif c = regcomp(&r_pattern[i], pattern[i].pat, cflags); if (c != 0) { regerror(c, &r_pattern[i], re_error, RE_ERROR_BUF); errx(2, "%s", re_error); } } } if (lbflag) setlinebuf(stdout); if ((aargc == 0 || aargc == 1) && !Hflag) hflag = true; if (aargc == 0 && dirbehave != DIR_RECURSE) exit(!procfile("-")); if (dirbehave == DIR_RECURSE) c = grep_tree(aargv); else for (c = 0; aargc--; ++aargv) { if ((finclude || fexclude) && !file_matching(*aargv)) continue; c+= procfile(*aargv); } #ifndef WITHOUT_NLS catclose(catalog); #endif /* Find out the correct return value according to the results and the command line option. */ exit(c ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1)); } Index: head/usr.bin/grep/grep.h =================================================================== --- head/usr.bin/grep/grep.h (revision 333235) +++ head/usr.bin/grep/grep.h (revision 333236) @@ -1,160 +1,153 @@ /* $NetBSD: grep.h,v 1.5 2011/02/27 17:33:37 joerg Exp $ */ /* $OpenBSD: grep.h,v 1.15 2010/04/05 03:03:55 tedu Exp $ */ /* $FreeBSD$ */ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav * Copyright (c) 2008-2009 Gabor Kovesdan * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include -#ifndef WITHOUT_FASTMATCH -#include "fastmatch.h" -#endif - #ifdef WITHOUT_NLS #define getstr(n) errstr[n] #else #include extern nl_catd catalog; #define getstr(n) catgets(catalog, 1, n, errstr[n]) #endif extern const char *errstr[]; #define VERSION "2.6.0-FreeBSD" #define GREP_FIXED 0 #define GREP_BASIC 1 #define GREP_EXTENDED 2 #if !defined(REG_NOSPEC) && !defined(REG_LITERAL) #define WITH_INTERNAL_NOSPEC #endif #define BINFILE_BIN 0 #define BINFILE_SKIP 1 #define BINFILE_TEXT 2 #define FILE_STDIO 0 #define FILE_MMAP 1 #define DIR_READ 0 #define DIR_SKIP 1 #define DIR_RECURSE 2 #define DEV_READ 0 #define DEV_SKIP 1 #define LINK_READ 0 #define LINK_EXPLICIT 1 #define LINK_SKIP 2 #define EXCL_PAT 0 #define INCL_PAT 1 #define MAX_MATCHES 32 struct file { int fd; bool binary; }; struct str { off_t boff; off_t off; size_t len; char *dat; char *file; int line_no; }; struct pat { char *pat; int len; }; struct epat { char *pat; int mode; }; /* Flags passed to regcomp() and regexec() */ extern int cflags, eflags; /* Command line flags */ extern bool Eflag, Fflag, Gflag, Hflag, Lflag, bflag, cflag, hflag, iflag, lflag, mflag, nflag, oflag, qflag, sflag, vflag, wflag, xflag; extern bool dexclude, dinclude, fexclude, finclude, lbflag, nullflag; extern long long Aflag, Bflag; extern long long mcount; extern long long mlimit; extern char fileeol; extern char *label; extern const char *color; extern int binbehave, devbehave, dirbehave, filebehave, grepbehave, linkbehave; extern bool file_err, matchall; extern unsigned int dpatterns, fpatterns, patterns; extern struct pat *pattern; extern struct epat *dpattern, *fpattern; extern regex_t *er_pattern, *r_pattern; -#ifndef WITHOUT_FASTMATCH -extern fastmatch_t *fg_pattern; -#endif /* For regex errors */ #define RE_ERROR_BUF 512 extern char re_error[RE_ERROR_BUF + 1]; /* Seems big enough */ /* util.c */ bool file_matching(const char *fname); int procfile(const char *fn); int grep_tree(char **argv); void *grep_malloc(size_t size); void *grep_calloc(size_t nmemb, size_t size); void *grep_realloc(void *ptr, size_t size); char *grep_strdup(const char *str); void grep_printline(struct str *line, int sep); /* queue.c */ bool enqueue(struct str *x); void printqueue(void); void clearqueue(void); /* file.c */ void grep_close(struct file *f); struct file *grep_open(const char *path); char *grep_fgetln(struct file *f, size_t *len); Index: head/usr.bin/grep/util.c =================================================================== --- head/usr.bin/grep/util.c (revision 333235) +++ head/usr.bin/grep/util.c (revision 333236) @@ -1,783 +1,770 @@ /* $NetBSD: util.c,v 1.9 2011/02/27 17:33:37 joerg Exp $ */ /* $FreeBSD$ */ /* $OpenBSD: util.c,v 1.39 2010/07/02 22:18:03 tedu Exp $ */ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav * Copyright (C) 2008-2010 Gabor Kovesdan * Copyright (C) 2017 Kyle Evans * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#ifndef WITHOUT_FASTMATCH -#include "fastmatch.h" -#endif #include "grep.h" static bool first_match = true; /* * Parsing context; used to hold things like matches made and * other useful bits */ struct parsec { regmatch_t matches[MAX_MATCHES]; /* Matches made */ /* XXX TODO: This should be a chunk, not a line */ struct str ln; /* Current line */ size_t lnstart; /* Position in line */ size_t matchidx; /* Latest match index */ int printed; /* Metadata printed? */ bool binary; /* Binary file? */ }; /* * Match printing context */ struct mprintc { long long tail; /* Number of trailing lines to record */ int last_outed; /* Number of lines since last output */ bool doctx; /* Printing context? */ bool printmatch; /* Printing matches? */ bool same_file; /* Same file as previously printed? */ }; static void procmatch_match(struct mprintc *mc, struct parsec *pc); static void procmatch_nomatch(struct mprintc *mc, struct parsec *pc); static bool procmatches(struct mprintc *mc, struct parsec *pc, bool matched); #ifdef WITH_INTERNAL_NOSPEC static int litexec(const struct pat *pat, const char *string, size_t nmatch, regmatch_t pmatch[]); #endif static int procline(struct parsec *pc); static void printline(struct parsec *pc, int sep); static void printline_metadata(struct str *line, int sep); bool file_matching(const char *fname) { char *fname_base, *fname_buf; bool ret; ret = finclude ? false : true; fname_buf = strdup(fname); if (fname_buf == NULL) err(2, "strdup"); fname_base = basename(fname_buf); for (unsigned int i = 0; i < fpatterns; ++i) { if (fnmatch(fpattern[i].pat, fname, 0) == 0 || fnmatch(fpattern[i].pat, fname_base, 0) == 0) /* * The last pattern matched wins exclusion/inclusion * rights, so we can't reasonably bail out early here. */ ret = (fpattern[i].mode != EXCL_PAT); } free(fname_buf); return (ret); } static inline bool dir_matching(const char *dname) { bool ret; ret = dinclude ? false : true; for (unsigned int i = 0; i < dpatterns; ++i) { if (dname != NULL && fnmatch(dpattern[i].pat, dname, 0) == 0) /* * The last pattern matched wins exclusion/inclusion * rights, so we can't reasonably bail out early here. */ ret = (dpattern[i].mode != EXCL_PAT); } return (ret); } /* * Processes a directory when a recursive search is performed with * the -R option. Each appropriate file is passed to procfile(). */ int grep_tree(char **argv) { FTS *fts; FTSENT *p; int c, fts_flags; bool ok; const char *wd[] = { ".", NULL }; c = fts_flags = 0; switch(linkbehave) { case LINK_EXPLICIT: fts_flags = FTS_COMFOLLOW; break; case LINK_SKIP: fts_flags = FTS_PHYSICAL; break; default: fts_flags = FTS_LOGICAL; } fts_flags |= FTS_NOSTAT | FTS_NOCHDIR; fts = fts_open((argv[0] == NULL) ? __DECONST(char * const *, wd) : argv, fts_flags, NULL); if (fts == NULL) err(2, "fts_open"); while ((p = fts_read(fts)) != NULL) { switch (p->fts_info) { case FTS_DNR: /* FALLTHROUGH */ case FTS_ERR: file_err = true; if(!sflag) warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); break; case FTS_D: /* FALLTHROUGH */ case FTS_DP: if (dexclude || dinclude) if (!dir_matching(p->fts_name) || !dir_matching(p->fts_path)) fts_set(fts, p, FTS_SKIP); break; case FTS_DC: /* Print a warning for recursive directory loop */ warnx("warning: %s: recursive directory loop", p->fts_path); break; default: /* Check for file exclusion/inclusion */ ok = true; if (fexclude || finclude) ok &= file_matching(p->fts_path); if (ok) c += procfile(p->fts_path); break; } } fts_close(fts); return (c); } static void procmatch_match(struct mprintc *mc, struct parsec *pc) { if (mc->doctx) { if (!first_match && (!mc->same_file || mc->last_outed > 0)) printf("--\n"); if (Bflag > 0) printqueue(); mc->tail = Aflag; } /* Print the matching line, but only if not quiet/binary */ if (mc->printmatch) { printline(pc, ':'); while (pc->matchidx >= MAX_MATCHES) { /* Reset matchidx and try again */ pc->matchidx = 0; if (procline(pc) == 0) printline(pc, ':'); else break; } first_match = false; mc->same_file = true; mc->last_outed = 0; } } static void procmatch_nomatch(struct mprintc *mc, struct parsec *pc) { /* Deal with any -A context as needed */ if (mc->tail > 0) { grep_printline(&pc->ln, '-'); mc->tail--; if (Bflag > 0) clearqueue(); } else if (Bflag == 0 || (Bflag > 0 && enqueue(&pc->ln))) /* * Enqueue non-matching lines for -B context. If we're not * actually doing -B context or if the enqueue resulted in a * line being rotated out, then go ahead and increment * last_outed to signify a gap between context/match. */ ++mc->last_outed; } /* * Process any matches in the current parsing context, return a boolean * indicating whether we should halt any further processing or not. 'true' to * continue processing, 'false' to halt. */ static bool procmatches(struct mprintc *mc, struct parsec *pc, bool matched) { /* * XXX TODO: This should loop over pc->matches and handle things on a * line-by-line basis, setting up a `struct str` as needed. */ /* Deal with any -B context or context separators */ if (matched) { procmatch_match(mc, pc); /* Count the matches if we have a match limit */ if (mflag) { /* XXX TODO: Decrement by number of matched lines */ mcount -= 1; if (mflag && mcount <= 0) return (false); } } else if (mc->doctx) procmatch_nomatch(mc, pc); return (true); } /* * Opens a file and processes it. Each file is processed line-by-line * passing the lines to procline(). */ int procfile(const char *fn) { struct parsec pc; struct mprintc mc; struct file *f; struct stat sb; mode_t s; int c, t; if (strcmp(fn, "-") == 0) { fn = label != NULL ? label : getstr(1); f = grep_open(NULL); } else { if (stat(fn, &sb) == 0) { /* Check if we need to process the file */ s = sb.st_mode & S_IFMT; if (dirbehave == DIR_SKIP && s == S_IFDIR) return (0); if (devbehave == DEV_SKIP && (s == S_IFIFO || s == S_IFCHR || s == S_IFBLK || s == S_IFSOCK)) return (0); } f = grep_open(fn); } if (f == NULL) { file_err = true; if (!sflag) warn("%s", fn); return (0); } pc.ln.file = grep_strdup(fn); pc.ln.line_no = 0; pc.ln.len = 0; pc.ln.boff = 0; pc.ln.off = -1; pc.binary = f->binary; memset(&mc, 0, sizeof(mc)); mc.printmatch = true; if ((pc.binary && binbehave == BINFILE_BIN) || cflag || qflag || lflag || Lflag) mc.printmatch = false; if (mc.printmatch && (Aflag != 0 || Bflag != 0)) mc.doctx = true; mcount = mlimit; for (c = 0; c == 0 || !(lflag || qflag); ) { /* * XXX TODO: We need to revisit this in a chunking world. We're * not going to be doing per-line statistics because of the * overhead involved. procmatches can figure that stuff out as * needed. */ /* Reset per-line statistics */ pc.printed = 0; pc.matchidx = 0; pc.lnstart = 0; pc.ln.boff = 0; pc.ln.off += pc.ln.len + 1; /* XXX TODO: Grab a chunk */ if ((pc.ln.dat = grep_fgetln(f, &pc.ln.len)) == NULL || pc.ln.len == 0) break; if (pc.ln.len > 0 && pc.ln.dat[pc.ln.len - 1] == fileeol) --pc.ln.len; pc.ln.line_no++; /* Return if we need to skip a binary file */ if (pc.binary && binbehave == BINFILE_SKIP) { grep_close(f); free(pc.ln.file); free(f); return (0); } if ((t = procline(&pc)) == 0) ++c; /* Halt processing if we hit our match limit */ if (!procmatches(&mc, &pc, t == 0)) break; } if (Bflag > 0) clearqueue(); grep_close(f); if (cflag) { if (!hflag) printf("%s:", pc.ln.file); printf("%u\n", c); } if (lflag && !qflag && c != 0) printf("%s%c", fn, nullflag ? 0 : '\n'); if (Lflag && !qflag && c == 0) printf("%s%c", fn, nullflag ? 0 : '\n'); if (c && !cflag && !lflag && !Lflag && binbehave == BINFILE_BIN && f->binary && !qflag) printf(getstr(7), fn); free(pc.ln.file); free(f); return (c); } #ifdef WITH_INTERNAL_NOSPEC /* * Internal implementation of literal string search within a string, modeled * after regexec(3), for use when the regex(3) implementation doesn't offer * either REG_NOSPEC or REG_LITERAL. This does not apply in the default FreeBSD * config, but in other scenarios such as building against libgnuregex or on * some non-FreeBSD OSes. */ static int litexec(const struct pat *pat, const char *string, size_t nmatch, regmatch_t pmatch[]) { char *(*strstr_fn)(const char *, const char *); char *sub, *subject; const char *search; size_t idx, n, ofs, stringlen; if (cflags & REG_ICASE) strstr_fn = strcasestr; else strstr_fn = strstr; idx = 0; ofs = pmatch[0].rm_so; stringlen = pmatch[0].rm_eo; if (ofs >= stringlen) return (REG_NOMATCH); subject = strndup(string, stringlen); if (subject == NULL) return (REG_ESPACE); for (n = 0; ofs < stringlen;) { search = (subject + ofs); if ((unsigned long)pat->len > strlen(search)) break; sub = strstr_fn(search, pat->pat); /* * Ignoring the empty string possibility due to context: grep optimizes * for empty patterns and will never reach this point. */ if (sub == NULL) break; ++n; /* Fill in pmatch if necessary */ if (nmatch > 0) { pmatch[idx].rm_so = ofs + (sub - search); pmatch[idx].rm_eo = pmatch[idx].rm_so + pat->len; if (++idx == nmatch) break; ofs = pmatch[idx].rm_so + 1; } else /* We only needed to know if we match or not */ break; } free(subject); if (n > 0 && nmatch > 0) for (n = idx; n < nmatch; ++n) pmatch[n].rm_so = pmatch[n].rm_eo = -1; return (n > 0 ? 0 : REG_NOMATCH); } #endif /* WITH_INTERNAL_NOSPEC */ #define iswword(x) (iswalnum((x)) || (x) == L'_') /* * Processes a line comparing it with the specified patterns. Each pattern * is looped to be compared along with the full string, saving each and every * match, which is necessary to colorize the output and to count the * matches. The matching lines are passed to printline() to display the * appropriate output. */ static int procline(struct parsec *pc) { regmatch_t pmatch, lastmatch, chkmatch; wchar_t wbegin, wend; size_t st, nst; unsigned int i; int c = 0, r = 0, lastmatches = 0, leflags = eflags; size_t startm = 0, matchidx; unsigned int retry; matchidx = pc->matchidx; /* Special case: empty pattern with -w flag, check first character */ if (matchall && wflag) { if (pc->ln.len == 0) return (0); wend = L' '; if (sscanf(&pc->ln.dat[0], "%lc", &wend) != 1 || iswword(wend)) return (1); else return (0); } else if (matchall) return (0); st = pc->lnstart; nst = 0; /* Initialize to avoid a false positive warning from GCC. */ lastmatch.rm_so = lastmatch.rm_eo = 0; /* Loop to process the whole line */ while (st <= pc->ln.len) { lastmatches = 0; startm = matchidx; retry = 0; if (st > 0 && pc->ln.dat[st - 1] != fileeol) leflags |= REG_NOTBOL; /* Loop to compare with all the patterns */ for (i = 0; i < patterns; i++) { pmatch.rm_so = st; pmatch.rm_eo = pc->ln.len; #ifdef WITH_INTERNAL_NOSPEC if (grepbehave == GREP_FIXED) r = litexec(&pattern[i], pc->ln.dat, 1, &pmatch); else #endif -#ifndef WITHOUT_FASTMATCH - if (fg_pattern[i].pattern) - r = fastexec(&fg_pattern[i], - pc->ln.dat, 1, &pmatch, leflags); - else -#endif - r = regexec(&r_pattern[i], pc->ln.dat, 1, - &pmatch, leflags); + r = regexec(&r_pattern[i], pc->ln.dat, 1, &pmatch, + leflags); if (r != 0) continue; /* Check for full match */ if (xflag && (pmatch.rm_so != 0 || (size_t)pmatch.rm_eo != pc->ln.len)) continue; /* Check for whole word match */ -#ifndef WITHOUT_FASTMATCH - if (wflag || fg_pattern[i].word) { -#else if (wflag) { -#endif wbegin = wend = L' '; if (pmatch.rm_so != 0 && sscanf(&pc->ln.dat[pmatch.rm_so - 1], "%lc", &wbegin) != 1) r = REG_NOMATCH; else if ((size_t)pmatch.rm_eo != pc->ln.len && sscanf(&pc->ln.dat[pmatch.rm_eo], "%lc", &wend) != 1) r = REG_NOMATCH; else if (iswword(wbegin) || iswword(wend)) r = REG_NOMATCH; /* * If we're doing whole word matching and we * matched once, then we should try the pattern * again after advancing just past the start of * the earliest match. This allows the pattern * to match later on in the line and possibly * still match a whole word. */ if (r == REG_NOMATCH && (retry == pc->lnstart || (unsigned int)pmatch.rm_so + 1 < retry)) retry = pmatch.rm_so + 1; if (r == REG_NOMATCH) continue; } lastmatches++; lastmatch = pmatch; if (matchidx == 0) c++; /* * Replace previous match if the new one is earlier * and/or longer. This will lead to some amount of * extra work if -o/--color are specified, but it's * worth it from a correctness point of view. */ if (matchidx > startm) { chkmatch = pc->matches[matchidx - 1]; if (pmatch.rm_so < chkmatch.rm_so || (pmatch.rm_so == chkmatch.rm_so && (pmatch.rm_eo - pmatch.rm_so) > (chkmatch.rm_eo - chkmatch.rm_so))) { pc->matches[matchidx - 1] = pmatch; nst = pmatch.rm_eo; } } else { /* Advance as normal if not */ pc->matches[matchidx++] = pmatch; nst = pmatch.rm_eo; } /* avoid excessive matching - skip further patterns */ if ((color == NULL && !oflag) || qflag || lflag || matchidx >= MAX_MATCHES) { pc->lnstart = nst; lastmatches = 0; break; } } /* * Advance to just past the start of the earliest match, try * again just in case we still have a chance to match later in * the string. */ if (lastmatches == 0 && retry > pc->lnstart) { st = retry; continue; } /* XXX TODO: We will need to keep going, since we're chunky */ /* One pass if we are not recording matches */ if (!wflag && ((color == NULL && !oflag) || qflag || lflag || Lflag)) break; /* If we didn't have any matches or REG_NOSUB set */ if (lastmatches == 0 || (cflags & REG_NOSUB)) nst = pc->ln.len; if (lastmatches == 0) /* No matches */ break; else if (st == nst && lastmatch.rm_so == lastmatch.rm_eo) /* Zero-length match -- advance one more so we don't get stuck */ nst++; /* Advance st based on previous matches */ st = nst; pc->lnstart = st; } /* Reflect the new matchidx in the context */ pc->matchidx = matchidx; if (vflag) c = !c; return (c ? 0 : 1); } /* * Safe malloc() for internal use. */ void * grep_malloc(size_t size) { void *ptr; if ((ptr = malloc(size)) == NULL) err(2, "malloc"); return (ptr); } /* * Safe calloc() for internal use. */ void * grep_calloc(size_t nmemb, size_t size) { void *ptr; if ((ptr = calloc(nmemb, size)) == NULL) err(2, "calloc"); return (ptr); } /* * Safe realloc() for internal use. */ void * grep_realloc(void *ptr, size_t size) { if ((ptr = realloc(ptr, size)) == NULL) err(2, "realloc"); return (ptr); } /* * Safe strdup() for internal use. */ char * grep_strdup(const char *str) { char *ret; if ((ret = strdup(str)) == NULL) err(2, "strdup"); return (ret); } /* * Print an entire line as-is, there are no inline matches to consider. This is * used for printing context. */ void grep_printline(struct str *line, int sep) { printline_metadata(line, sep); fwrite(line->dat, line->len, 1, stdout); putchar(fileeol); } static void printline_metadata(struct str *line, int sep) { bool printsep; printsep = false; if (!hflag) { if (!nullflag) { fputs(line->file, stdout); printsep = true; } else { printf("%s", line->file); putchar(0); } } if (nflag) { if (printsep) putchar(sep); printf("%d", line->line_no); printsep = true; } if (bflag) { if (printsep) putchar(sep); printf("%lld", (long long)(line->off + line->boff)); printsep = true; } if (printsep) putchar(sep); } /* * Prints a matching line according to the command line options. */ static void printline(struct parsec *pc, int sep) { size_t a = 0; size_t i, matchidx; regmatch_t match; /* If matchall, everything matches but don't actually print for -o */ if (oflag && matchall) return; matchidx = pc->matchidx; /* --color and -o */ if ((oflag || color) && matchidx > 0) { /* Only print metadata once per line if --color */ if (!oflag && pc->printed == 0) printline_metadata(&pc->ln, sep); for (i = 0; i < matchidx; i++) { match = pc->matches[i]; /* Don't output zero length matches */ if (match.rm_so == match.rm_eo) continue; /* * Metadata is printed on a per-line basis, so every * match gets file metadata with the -o flag. */ if (oflag) { pc->ln.boff = match.rm_so; printline_metadata(&pc->ln, sep); } else fwrite(pc->ln.dat + a, match.rm_so - a, 1, stdout); if (color) fprintf(stdout, "\33[%sm\33[K", color); fwrite(pc->ln.dat + match.rm_so, match.rm_eo - match.rm_so, 1, stdout); if (color) fprintf(stdout, "\33[m\33[K"); a = match.rm_eo; if (oflag) putchar('\n'); } if (!oflag) { if (pc->ln.len - a > 0) fwrite(pc->ln.dat + a, pc->ln.len - a, 1, stdout); putchar('\n'); } } else grep_printline(&pc->ln, sep); pc->printed++; }