diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,9 @@
+See also http://pvp.haskell.org/faq
+
+## 0.96.0.0
+
+- Update to `regex-base-0.94.0.0` API
+- Compatibility with `base-4.13.0`
+- Remove internal regex C implementation
+
+----
diff --git a/Text/Regex/Posix.hs b/Text/Regex/Posix.hs
deleted file mode 100644
--- a/Text/Regex/Posix.hs
+++ /dev/null
@@ -1,73 +0,0 @@
-{- OPTIONS_GHC -fno-warn-unused-imports -}
------------------------------------------------------------------------------
--- |
---
--- Module      :  Text.Regex.Posix
--- Copyright   :  (c) Chris Kuklewicz 2006
--- License     :  BSD-style (see the file LICENSE)
--- 
--- Maintainer  :  libraries@haskell.org, textregexlazy@personal.mightyreason.com
--- Stability   :  experimental
--- Portability :  non-portable (regex-base needs MPTC+FD)
---
--- Module that provides the Regex backend that wraps the c posix regex api.
--- This is the backend being used by the regex-compat package to replace
--- Text.Regex
---
--- The "Text.Regex.Posix" module provides a backend for regular
--- expressions. If you import this along with other backends, then
--- you should do so with qualified imports, perhaps renamed for
--- convenience.
---
--- If the '=~' and '=~~' functions are too high level, you can use the
--- compile, regexec, and execute functions from importing either
--- "Text.Regex.Posix.String" or "Text.Regex.Posix.ByteString".  If you
--- want to use a low-level 'Foreign.C.CString' interface to the library,
--- then import "Text.Regex.Posix.Wrap" and use the wrap* functions.
---
--- This module is only efficient with 'Data.ByteString.ByteString' only
--- if it is null terminated, i.e. @(Bytestring.last bs)==0@.  Otherwise the
--- library must make a temporary copy of the 'Data.ByteString.ByteString'
--- and append the NUL byte.
---
--- A 'String' will be converted into a 'Foreign.C.CString' for processing.
--- Doing this repeatedly will be very inefficient.
---
--- Note that the posix library works with single byte characters, and
--- does not understand Unicode.  If you need Unicode support you will
--- have to use a different backend.
---
--- When offsets are reported for subexpression captures, a subexpression
--- that did not match anything (as opposed to matching an empty string)
--- will have its offset set to the 'unusedRegOffset' value, which is (-1).
---
--- Benchmarking shows the default regex library on many platforms is very
--- inefficient.  You might increase performace by an order of magnitude
--- by obtaining libpcre and regex-pcre or libtre and regex-tre.  If you
--- do not need the captured substrings then you can also get great
--- performance from regex-dfa.  If you do need the capture substrings
--- then you may be able to use regex-parsec to improve performance.
------------------------------------------------------------------------------
-
-module Text.Regex.Posix(getVersion_Text_Regex_Posix
- ,module Text.Regex.Base
-  -- ** Wrap, for '=~' and '=~~', types and constants
- ,module Text.Regex.Posix.Wrap) where
-
-import Text.Regex.Posix.Wrap(Regex, CompOption(CompOption),
-  ExecOption(ExecOption), (=~), (=~~),
-  unusedRegOffset,
-  compBlank, compExtended, compIgnoreCase, compNoSub, compNewline,
-  execBlank, execNotBOL, execNotEOL)
-import Text.Regex.Posix.String()
-import Text.Regex.Posix.Sequence()
-import Text.Regex.Posix.ByteString()
-import Text.Regex.Posix.ByteString.Lazy()
-import Data.Version(Version(..))
-import Text.Regex.Base
-
-getVersion_Text_Regex_Posix :: Version
-getVersion_Text_Regex_Posix =
-  Version { versionBranch = [0,94,4]  -- Keep in sync with regex-posix.cabal
-          , versionTags = ["unstable"]
-          }
diff --git a/Text/Regex/Posix/ByteString.hs b/Text/Regex/Posix/ByteString.hs
deleted file mode 100644
--- a/Text/Regex/Posix/ByteString.hs
+++ /dev/null
@@ -1,152 +0,0 @@
-{-# OPTIONS_GHC -fno-warn-orphans #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Text.Regex.Posix.ByteString
--- Copyright   :  (c) Chris Kuklewicz 2006
--- License     :  BSD-style (see the file LICENSE)
--- 
--- Maintainer  :  libraries@haskell.org, textregexlazy@personal.mightyreason.com
--- Stability   :  experimental
--- Portability :  non-portable (regex-base needs MPTC+FD)
---
--- This provides 'ByteString' instances for RegexMaker and RegexLike
--- based on "Text.Regex.Posix.Wrap", and a (RegexContext Regex
--- ByteString ByteString) instance.
---
--- To use these instance, you would normally import
--- "Text.Regex.Posix".  You only need to import this module to use
--- the medium level API of the compile, regexec, and execute
--- functions.  All of these report error by returning Left values
--- instead of undefined or error or fail.
---
--- The ByteString will only be passed to the library efficiently (as a
--- pointer) if it ends in a NUL byte.  Otherwise a temporary copy must
--- be made with the 0 byte appended.
------------------------------------------------------------------------------
-
-module Text.Regex.Posix.ByteString(
-  -- ** Types
-  Regex,
-  MatchOffset,
-  MatchLength,
-  ReturnCode,
-  WrapError,
-  -- ** Miscellaneous
-  unusedOffset,
-  -- ** Medium level API functions
-  compile,
-  execute,
-  regexec,
-  -- ** Compilation options
-  CompOption(CompOption),
-  compBlank,
-  compExtended,   -- use extended regex syntax
-  compIgnoreCase, -- ignore case when matching
-  compNoSub,      -- no substring matching needed
-  compNewline,    -- '.' doesn't match newline
-  -- ** Execution options
-  ExecOption(ExecOption),
-  execBlank,
-  execNotBOL,      -- not at begining of line
-  execNotEOL       -- not at end of line
-  ) where
-
-import Data.Array(Array,listArray)
-import Data.ByteString(ByteString)
-import qualified Data.ByteString as B(empty,useAsCString,last,take,drop,null)
-#ifdef SPLIT_BASE
-import qualified Data.ByteString.Unsafe as B(unsafeUseAsCString)
-#else
-import qualified Data.ByteString.Base as B(unsafeUseAsCString)
-#endif
-import System.IO.Unsafe(unsafePerformIO)
-import Text.Regex.Base.RegexLike(RegexMaker(..),RegexContext(..),RegexLike(..),MatchOffset,MatchLength)
-import Text.Regex.Posix.Wrap -- all
-import Text.Regex.Base.Impl(polymatch,polymatchM)
-import Foreign.C.String(CString)
-
-instance RegexContext Regex ByteString ByteString where
-  match = polymatch
-  matchM = polymatchM
-
-unwrap :: (Show e) => Either e v -> IO v
-unwrap x = case x of Left err -> fail ("Text.Regex.Posix.ByteString died: "++ show err)
-                     Right v -> return v
-
-instance RegexMaker Regex CompOption ExecOption ByteString where
-  makeRegexOpts c e pattern = unsafePerformIO $
-    compile c e pattern >>= unwrap
-  makeRegexOptsM c e pattern = either (fail.show) return $ unsafePerformIO $
-    compile c e pattern
-
-instance RegexLike Regex ByteString where
-  matchTest regex bs = unsafePerformIO $
-    asCString bs (wrapTest regex) >>=  unwrap
-  matchOnce regex bs = unsafePerformIO $ 
-    execute regex bs >>= unwrap
-  matchAll regex bs = unsafePerformIO $
-    asCString bs (wrapMatchAll regex) >>= unwrap
-  matchCount regex bs = unsafePerformIO $
-    asCString bs (wrapCount regex) >>= unwrap
-
--- ---------------------------------------------------------------------
--- | Compiles a regular expression
---
-compile :: CompOption    -- ^ Flags (summed together)
-        -> ExecOption    -- ^ Flags (summed together)
-        -> ByteString  -- ^ The regular expression to compile
-        -> IO (Either WrapError Regex)      -- ^ Returns: the compiled regular expression
-compile c e pattern =
-  asCString pattern (wrapCompile c e)
-
-
--- ---------------------------------------------------------------------
--- | Matches a regular expression against a buffer, returning the buffer
--- indicies of the match, and any submatches
---
--- | Matches a regular expression against a string
-execute :: Regex      -- ^ Compiled regular expression
-        -> ByteString -- ^ String to match against
-        -> IO (Either WrapError (Maybe (Array Int (MatchOffset,MatchLength))))
-                -- ^ Returns: 'Nothing' if the regex did not match the
-                -- string, or:
-                --   'Just' an array of (offset,length) pairs where index 0 is whole match, and the rest are the captured subexpressions.
-execute regex bs = do
-  maybeStartEnd <- asCString bs (wrapMatch regex)
-  case maybeStartEnd of
-    Right Nothing -> return (Right Nothing)
---  Right (Just []) -> ...
-    Right (Just parts) -> 
-      return . Right . Just . listArray (0,pred (length parts))
-      . map (\(s,e)->(fromIntegral s, fromIntegral (e-s))) $ parts
-    Left err -> return (Left err)
-
-regexec :: Regex      -- ^ Compiled regular expression
-        -> ByteString -- ^ String to match against
-        -> IO (Either WrapError (Maybe (ByteString, ByteString, ByteString, [ByteString])))
-regexec regex bs = do
-  let getSub (start,stop) | start == unusedRegOffset = B.empty
-                          | otherwise = B.take (fi (stop-start)) . B.drop (fi start) $ bs
-      matchedParts [] = (B.empty,B.empty,bs,[]) -- no information
-      matchedParts (matchedStartStop@(start,stop):subStartStop) = 
-        (B.take (fi start) bs
-        ,getSub matchedStartStop
-        ,B.drop (fi stop) bs
-        ,map getSub subStartStop)
-  maybeStartEnd <- asCString bs (wrapMatch regex)
-  case maybeStartEnd of
-    Right Nothing -> return (Right Nothing)
---  Right (Just []) -> ...
-    Right (Just parts) -> return . Right . Just . matchedParts $ parts
-    Left err -> return (Left err)
-
-unusedOffset :: Int
-unusedOffset = fromIntegral unusedRegOffset
-
-fi :: (Integral i,Num n) => i->n
-fi = fromIntegral
-
-asCString :: ByteString -> (CString -> IO a) -> IO a
-asCString bs = if (not (B.null bs)) && (0==B.last bs)
-                  then B.unsafeUseAsCString bs
-                  else B.useAsCString bs
diff --git a/Text/Regex/Posix/ByteString/Lazy.hs b/Text/Regex/Posix/ByteString/Lazy.hs
deleted file mode 100644
--- a/Text/Regex/Posix/ByteString/Lazy.hs
+++ /dev/null
@@ -1,141 +0,0 @@
-{-# OPTIONS_GHC -fno-warn-orphans #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Text.Regex.Posix.ByteString.Lazy
--- Copyright   :  (c) Chris Kuklewicz 2007
--- License     :  BSD-style (see the file LICENSE)
--- 
--- Maintainer  :  libraries@haskell.org, textregexlazy@personal.mightyreason.com
--- Stability   :  experimental
--- Portability :  non-portable (regex-base needs MPTC+FD)
---
--- This provides 'ByteString.Lazy' instances for RegexMaker and RegexLike
--- based on "Text.Regex.Posix.Wrap", and a (RegexContext Regex
--- ByteString ByteString) instance.
---
--- To use these instance, you would normally import
--- "Text.Regex.Posix".  You only need to import this module to use
--- the medium level API of the compile, regexec, and execute
--- functions.  All of these report error by returning Left values
--- instead of undefined or error or fail.
---
--- A Lazy ByteString with more than one chunk cannot be be passed to
--- the library efficiently (as a pointer).  It will have to converted
--- via a full copy to a temporary normal bytestring (with a null byte
--- appended if necessary).
------------------------------------------------------------------------------
-
-module Text.Regex.Posix.ByteString.Lazy(
-  -- ** Types
-  Regex,
-  MatchOffset,
-  MatchLength,
-  ReturnCode,
-  WrapError,
-  -- ** Miscellaneous
-  unusedOffset,
-  -- ** Medium level API functions
-  compile,
-  execute,
-  regexec,
-  -- ** Compilation options
-  CompOption(CompOption),
-  compBlank,
-  compExtended,   -- use extended regex syntax
-  compIgnoreCase, -- ignore case when matching
-  compNoSub,      -- no substring matching needed
-  compNewline,    -- '.' doesn't match newline
-  -- ** Execution options
-  ExecOption(ExecOption),
-  execBlank,
-  execNotBOL,      -- not at begining of line
-  execNotEOL       -- not at end of line
-  ) where
-
-import Data.Array(Array)
-import qualified Data.ByteString.Lazy as L (ByteString,null,toChunks,fromChunks,last,snoc)
-import qualified Data.ByteString as B(ByteString,concat)
-#ifdef SPLIT_BASE
-import qualified Data.ByteString.Unsafe as B(unsafeUseAsCString)
-#else
-import qualified Data.ByteString.Base as B(unsafeUseAsCString)
-#endif
-import System.IO.Unsafe(unsafePerformIO)
-import Text.Regex.Base.RegexLike(RegexMaker(..),RegexContext(..),RegexLike(..),MatchOffset,MatchLength)
-import Text.Regex.Posix.Wrap -- all
-import qualified Text.Regex.Posix.ByteString as BS(execute,regexec)
-import Text.Regex.Base.Impl(polymatch,polymatchM)
-import Foreign.C.String(CString)
-
-instance RegexContext Regex L.ByteString L.ByteString where
-  match = polymatch
-  matchM = polymatchM
-
-fromLazy :: L.ByteString -> B.ByteString
-fromLazy = B.concat . L.toChunks
-
-toLazy :: B.ByteString -> L.ByteString
-toLazy = L.fromChunks . return
-
-unwrap :: (Show e) => Either e v -> IO v
-unwrap x = case x of Left err -> fail ("Text.Regex.Posix.ByteString.Lazy died: "++ show err)
-                     Right v -> return v
-
-{-# INLINE asCString #-}
-asCString :: L.ByteString -> (CString -> IO a) -> IO a
-asCString s = if (not (L.null s)) && (0==L.last s)
-                then B.unsafeUseAsCString (fromLazy s)
-                else B.unsafeUseAsCString (fromLazy (L.snoc s 0))
-
-instance RegexMaker Regex CompOption ExecOption L.ByteString where
-  makeRegexOpts c e pattern = unsafePerformIO $ compile c e pattern >>= unwrap
-  makeRegexOptsM c e pattern = either (fail.show) return $ unsafePerformIO $ compile c e pattern
-
-instance RegexLike Regex L.ByteString where
-  matchTest regex bs = unsafePerformIO $
-    asCString bs (wrapTest regex) >>=  unwrap
-  matchOnce regex bs = unsafePerformIO $ 
-    execute regex bs >>= unwrap
-  matchAll regex bs = unsafePerformIO $
-    asCString bs (wrapMatchAll regex) >>= unwrap
-  matchCount regex bs = unsafePerformIO $
-    asCString bs (wrapCount regex) >>= unwrap
-
--- ---------------------------------------------------------------------
--- | Compiles a regular expression
---
-compile :: CompOption    -- ^ Flags (summed together)
-        -> ExecOption    -- ^ Flags (summed together)
-        -> L.ByteString  -- ^ The regular expression to compile
-        -> IO (Either WrapError Regex)      -- ^ Returns: the compiled regular expression
-compile c e pattern = asCString pattern (wrapCompile c e)
-
--- ---------------------------------------------------------------------
--- | Matches a regular expression against a buffer, returning the buffer
--- indicies of the match, and any submatches
---
--- | Matches a regular expression against a string
-execute :: Regex      -- ^ Compiled regular expression
-        -> L.ByteString -- ^ String to match against
-        -> IO (Either WrapError (Maybe (Array Int (MatchOffset,MatchLength))))
-                -- ^ Returns: 'Nothing' if the regex did not match the
-                -- string, or:
-                --   'Just' an array of (offset,length) pairs where index 0 is whole match, and the rest are the captured subexpressions.
-execute regex bs = if (not (L.null bs)) && (0==L.last bs)
-                     then BS.execute regex (fromLazy bs)
-                     else BS.execute regex (fromLazy (L.snoc bs 0))
-
-regexec :: Regex      -- ^ Compiled regular expression
-        -> L.ByteString -- ^ String to match against
-        -> IO (Either WrapError (Maybe (L.ByteString, L.ByteString, L.ByteString, [L.ByteString])))
-regexec regex bs = do
-  x <- if (not (L.null bs)) && (0==L.last bs)
-         then BS.regexec regex (fromLazy bs)
-         else BS.regexec regex (fromLazy (L.snoc bs 0))
-  return $ case x of
-             Left e -> Left e
-             Right Nothing -> Right Nothing
-             Right (Just (a,b,c,ds)) -> Right (Just (toLazy a,toLazy b,toLazy c,map toLazy ds))
-
-unusedOffset :: Int
-unusedOffset = fromIntegral unusedRegOffset
diff --git a/Text/Regex/Posix/Sequence.hs b/Text/Regex/Posix/Sequence.hs
deleted file mode 100644
--- a/Text/Regex/Posix/Sequence.hs
+++ /dev/null
@@ -1,165 +0,0 @@
-{-# OPTIONS_GHC -fno-warn-orphans #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Text.Regex.Posix.Sequence
--- Copyright   :  (c) Chris Kuklewicz 2006
--- License     :  BSD-style (see the file LICENSE)
--- 
--- Maintainer  :  libraries@haskell.org, textregexlazy@personal.mightyreason.com
--- Stability   :  experimental
--- Portability :  non-portable (regex-base needs MPTC+FD)
---
--- This provides 'String' instances for 'RegexMaker' and 'RegexLike' based
--- on "Text.Regex.Posix.Wrap", and a ('RegexContext' 'Regex' 'String' 'String')
--- instance.
---
--- To use these instance, you would normally import
--- "Text.Regex.Posix".  You only need to import this module to use
--- the medium level API of the compile, regexec, and execute
--- functions.  All of these report error by returning Left values
--- instead of undefined or error or fail.
---
------------------------------------------------------------------------------
-
-module Text.Regex.Posix.Sequence(
-  -- ** Types
-  Regex,
-  MatchOffset,
-  MatchLength,
-  ReturnCode,
-  WrapError,
-  -- ** Miscellaneous
-  unusedOffset,
-  -- ** Medium level API functions
-  compile,
-  regexec,
-  execute,
-  -- ** Compilation options
-  CompOption(CompOption),
-  compBlank,
-  compExtended,   -- use extended regex syntax
-  compIgnoreCase, -- ignore case when matching
-  compNoSub,      -- no substring matching needed
-  compNewline,    -- '.' doesn't match newline
-
-  ExecOption(ExecOption),
-  execBlank,
-  execNotBOL,     -- not at begining of line
-  execNotEOL     -- not at end of line
-  ) where
-
-import Data.Array(listArray, Array)
-import System.IO.Unsafe(unsafePerformIO)
-import Text.Regex.Base.RegexLike(RegexContext(..),RegexMaker(..),RegexLike(..),MatchOffset,MatchLength,Extract(..))
-import Text.Regex.Posix.Wrap
-import Text.Regex.Base.Impl(polymatch,polymatchM)
-import Data.Sequence as S hiding (length)
-import qualified Data.Sequence as S (length)
-import Foreign.C.String
-import Foreign.Marshal.Array
-import Foreign.Marshal.Alloc
-import Foreign.Storable
-
-instance RegexContext Regex (Seq Char) (Seq Char) where
-  match = polymatch
-  matchM = polymatchM
-
-unusedOffset :: Int
-unusedOffset = fromIntegral unusedRegOffset
-
-unwrap :: (Show e) => Either e v -> IO v
-unwrap x = case x of Left err -> fail ("Text.Regex.Posix.Sequence died: "++ show err)
-                     Right v -> return v
-
-instance RegexMaker Regex CompOption ExecOption (Seq Char) where
-  makeRegexOpts c e pattern = unsafePerformIO $
-    (compile c e pattern >>= unwrap)
-  makeRegexOptsM c e pattern = either (fail.show) return $ unsafePerformIO $ 
-    (compile c e pattern)
-
-instance RegexLike Regex (Seq Char) where
-  matchTest regex str = unsafePerformIO $ do
-    withSeq str (wrapTest regex) >>= unwrap
-  matchOnce regex str = unsafePerformIO $ 
-    execute regex str >>= unwrap
-  matchAll regex str = unsafePerformIO $ 
-    withSeq str (wrapMatchAll regex) >>= unwrap
-  matchCount regex str = unsafePerformIO $
-    withSeq str (wrapCount regex) >>= unwrap
-
--- compile
-compile  :: CompOption -- ^ Flags (summed together)
-         -> ExecOption -- ^ Flags (summed together)
-         -> (Seq Char)     -- ^ The regular expression to compile (ASCII only, no null bytes)
-         -> IO (Either WrapError Regex) -- ^ Returns: the compiled regular expression
-compile flags e pattern =  withSeq pattern (wrapCompile flags e)
-
--- -----------------------------------------------------------------------------
--- regexec
-
--- | Matches a regular expression against a string
-execute :: Regex      -- ^ Compiled regular expression
-        -> (Seq Char)     -- ^ (Seq Char) to match against
-        -> IO (Either WrapError (Maybe (Array Int (MatchOffset,MatchLength))))
-                -- ^ Returns: 'Nothing' if the regex did not match the
-                -- string, or:
-                --
-                -- @
-                --   'Just' (array of offset length pairs)
-                -- @
-execute regex str = do
-  maybeStartEnd <- withSeq str (wrapMatch regex)
-  case maybeStartEnd of
-    Right Nothing -> return (Right Nothing)
---  Right (Just []) ->  fail "got [] back!" -- return wierd array instead
-    Right (Just parts) ->
-      return . Right . Just . listArray (0,pred (length parts)) 
-       . map (\(s,e)->(fromIntegral s, fromIntegral (e-s)))
-       $ parts
-    Left err -> return (Left err)
-
--- -----------------------------------------------------------------------------
--- regexec
-
--- | Matches a regular expression against a string
-regexec :: Regex      -- ^ Compiled regular expression
-        -> (Seq Char)     -- ^ (Seq Char) to match against
-        -> IO (Either WrapError (Maybe ((Seq Char), (Seq Char), (Seq Char), [(Seq Char)])))
-                -- ^ Returns: 'Nothing' if the regex did not match the
-                -- string, or:
-                --
-                -- @
-                --   'Just' (everything before match,
-                --         matched portion,
-                --         everything after match,
-                --         subexpression matches)
-                -- @
-regexec regex str = do
-  let getSub :: (RegOffset,RegOffset) -> (Seq Char)
-      getSub (start,stop) | start == unusedRegOffset = S.empty
-                          | otherwise = 
-        extract (fromEnum start,fromEnum $ stop-start) $ str
-      matchedParts :: [(RegOffset,RegOffset)] -> ((Seq Char), (Seq Char), (Seq Char), [(Seq Char)])
-      matchedParts [] = (str,S.empty,S.empty,[]) -- no information
-      matchedParts (matchedStartStop@(start,stop):subStartStop) = 
-        (before (fromEnum start) str
-        ,getSub matchedStartStop
-        ,after (fromEnum stop) str
-        ,map getSub subStartStop)
-  maybeStartEnd <- withSeq str (wrapMatch regex)
-  case maybeStartEnd of
-    Right Nothing -> return (Right Nothing)
-    Right (Just parts) -> return . Right . Just . matchedParts $ parts
-    Left err -> return (Left err)
-
-withSeq :: Seq Char -> (CString -> IO a) -> IO a
-withSeq s f =
-  let -- Ensure null at end of s
-      s' = case viewr s of                 -- bang !s
-             EmptyR -> singleton '\0'
-             _ :> '\0' -> s
-             _ -> s |> '\0'
-      pokes p a = case viewl a of         -- bang pokes !p !a
-                    EmptyL -> return ()
-                    c :< a' -> poke p (castCharToCChar c) >> pokes (advancePtr p 1) a'
-  in allocaBytes (S.length s') (\ptr -> pokes ptr s' >> f ptr)
diff --git a/Text/Regex/Posix/String.hs b/Text/Regex/Posix/String.hs
deleted file mode 100644
--- a/Text/Regex/Posix/String.hs
+++ /dev/null
@@ -1,147 +0,0 @@
-{-# OPTIONS_GHC -fno-warn-orphans #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Text.Regex.Posix.String
--- Copyright   :  (c) Chris Kuklewicz 2006
--- License     :  BSD-style (see the file LICENSE)
--- 
--- Maintainer  :  libraries@haskell.org, textregexlazy@personal.mightyreason.com
--- Stability   :  experimental
--- Portability :  non-portable (regex-base needs MPTC+FD)
---
--- This provides 'String' instances for 'RegexMaker' and 'RegexLike' based
--- on "Text.Regex.Posix.Wrap", and a ('RegexContext' 'Regex' 'String' 'String')
--- instance.
---
--- To use these instance, you would normally import
--- "Text.Regex.Posix".  You only need to import this module to use
--- the medium level API of the compile, regexec, and execute
--- functions.  All of these report error by returning Left values
--- instead of undefined or error or fail.
---
------------------------------------------------------------------------------
-
-module Text.Regex.Posix.String(
-  -- ** Types
-  Regex,
-  MatchOffset,
-  MatchLength,
-  ReturnCode,
-  WrapError,
-  -- ** Miscellaneous
-  unusedOffset,
-  -- ** Medium level API functions
-  compile,
-  regexec,
-  execute,
-  -- ** Compilation options
-  CompOption(CompOption),
-  compBlank,
-  compExtended,   -- use extended regex syntax
-  compIgnoreCase, -- ignore case when matching
-  compNoSub,      -- no substring matching needed
-  compNewline,    -- '.' doesn't match newline
-  -- ** Execution options
-  ExecOption(ExecOption),
-  execBlank,
-  execNotBOL,     -- not at begining of line
-  execNotEOL     -- not at end of line
-  ) where
-
-import Data.Array(listArray, Array)
-import Data.List(genericDrop, genericTake)
-import Foreign.C.String(withCAString)
-import System.IO.Unsafe(unsafePerformIO)
-import Text.Regex.Base.RegexLike(RegexContext(..),RegexMaker(..),RegexLike(..),MatchOffset,MatchLength)
-import Text.Regex.Posix.Wrap
-import Text.Regex.Base.Impl(polymatch,polymatchM)
-
-instance RegexContext Regex String String where
-  match = polymatch
-  matchM = polymatchM
-
-unusedOffset :: Int
-unusedOffset = fromIntegral unusedRegOffset
-
-unwrap :: (Show e) => Either e v -> IO v
-unwrap x = case x of Left err -> fail ("Text.Regex.Posix.String died: "++ show err)
-                     Right v -> return v
-
-instance RegexMaker Regex CompOption ExecOption String where
-  makeRegexOpts c e pattern = unsafePerformIO $
-    (compile c e pattern >>= unwrap)
-  makeRegexOptsM c e pattern = either (fail.show) return $ unsafePerformIO $ 
-    (compile c e pattern)
-
-instance RegexLike Regex String where
-  matchTest regex str = unsafePerformIO $ do
-    withCAString str (wrapTest regex) >>= unwrap
-  matchOnce regex str = unsafePerformIO $ 
-    execute regex str >>= unwrap
-  matchAll regex str = unsafePerformIO $ 
-    withCAString str (wrapMatchAll regex) >>= unwrap
-  matchCount regex str = unsafePerformIO $
-    withCAString str (wrapCount regex) >>= unwrap
-
--- compile
-compile  :: CompOption -- ^ Flags (summed together)
-         -> ExecOption -- ^ Flags (summed together)
-         -> String     -- ^ The regular expression to compile (ASCII only, no null bytes)
-         -> IO (Either WrapError Regex) -- ^ Returns: the compiled regular expression
-compile flags e pattern =  withCAString pattern (wrapCompile flags e)
-
--- -----------------------------------------------------------------------------
--- regexec
-
--- | Matches a regular expression against a string
-execute :: Regex      -- ^ Compiled regular expression
-        -> String     -- ^ String to match against
-        -> IO (Either WrapError (Maybe (Array Int (MatchOffset,MatchLength))))
-                -- ^ Returns: 'Nothing' if the regex did not match the
-                -- string, or:
-                --
-                -- @
-                --   'Just' (array of offset length pairs)
-                -- @
-execute regex str = do
-  maybeStartEnd <- withCAString str (wrapMatch regex)
-  case maybeStartEnd of
-    Right Nothing -> return (Right Nothing)
---  Right (Just []) ->  fail "got [] back!" -- return wierd array instead
-    Right (Just parts) ->
-      return . Right . Just . listArray (0,pred (length parts)) 
-       . map (\(s,e)->(fromIntegral s, fromIntegral (e-s)))
-       $ parts
-    Left err -> return (Left err)
-
--- -----------------------------------------------------------------------------
--- regexec
-
--- | Matches a regular expression against a string
-regexec :: Regex      -- ^ Compiled regular expression
-        -> String     -- ^ String to match against
-        -> IO (Either WrapError (Maybe (String, String, String, [String])))
-                -- ^ Returns: 'Nothing' if the regex did not match the
-                -- string, or:
-                --
-                -- @
-                --   'Just' (everything before match,
-                --         matched portion,
-                --         everything after match,
-                --         subexpression matches)
-                -- @
-regexec regex str = do
-  let getSub (start,stop) | start == unusedRegOffset = ""
-                          | otherwise = 
-        genericTake (stop-start) . genericDrop start $ str
-      matchedParts [] = (str,"","",[]) -- no information
-      matchedParts (matchedStartStop@(start,stop):subStartStop) = 
-        (genericTake start str
-        ,getSub matchedStartStop
-        ,genericDrop stop str
-        ,map getSub subStartStop)
-  maybeStartEnd <- withCAString str (wrapMatch regex)
-  case maybeStartEnd of
-    Right Nothing -> return (Right Nothing)
-    Right (Just parts) -> return . Right . Just . matchedParts $ parts
-    Left err -> return (Left err)
diff --git a/Text/Regex/Posix/Wrap.hsc b/Text/Regex/Posix/Wrap.hsc
deleted file mode 100644
--- a/Text/Regex/Posix/Wrap.hsc
+++ /dev/null
@@ -1,676 +0,0 @@
-{-# OPTIONS_GHC -fno-warn-unused-imports #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Text.Regex.Posix.Wrap
--- Copyright   :  (c) Chris Kuklewicz 2006,2007,2008 derived from (c) The University of Glasgow 2002
--- License     :  BSD-style (see the file LICENSE)
---
--- Maintainer  :  libraries@haskell.org, textregexlazy@personal.mightyreason.com
--- Stability   :  experimental
--- Portability :  non-portable (regex-base needs MPTC+FD)
---
--- WrapPosix.hsc exports a wrapped version of the ffi imports.  To
--- increase type safety, the flags are newtype'd.  The other important
--- export is a 'Regex' type that is specific to the Posix library
--- backend.  The flags are documented in "Text.Regex.Posix".  The
--- 'defaultCompOpt' is @(compExtended .|. compNewline)@.
---
--- The 'Regex', 'CompOption', and 'ExecOption' types and their 'RegexOptions'
--- instance is declared.  The '=~' and '=~~' convenience functions are
--- defined.
---
--- The exported symbols are the same whether HAVE_REGEX_H is defined, but
--- when it is not defined then @getVersion == Nothing@ and all other
--- exported values will call error or fail.
---
--- This module will fail or error only if allocation fails or a nullPtr
--- is passed in.
---
--- 2009-January : wrapMatchAll and wrapCount now adjust the execution
--- option execNotBOL after the first result to take into account '\n'
--- in the text immediately before the next matches. (version 0.93.3)
---
--- 2009-January : wrapMatchAll and wrapCount have been changed to
--- return all non-overlapping matches, including empty matches even if
--- they coincide with the end of the previous non-empty match.  The
--- change is that the first non-empty match no longer terminates the
--- search.  One can filter the results to obtain the old behavior or
--- to obtain the behavior of "sed", where "sed" eliminates the empty
--- matches which coincide with the end of non-empty matches. (version
--- 0.94.0)
------------------------------------------------------------------------------
-
-module Text.Regex.Posix.Wrap(
-  -- ** High-level API
-  Regex,
-  RegOffset,
-  RegOffsetT,
-  (=~),
-  (=~~),
-
-  -- ** Low-level API
-  WrapError,
-  wrapCompile,
-  wrapTest,
-  wrapMatch,
-  wrapMatchAll,
-  wrapCount,
-
-  -- ** Miscellaneous
-  unusedRegOffset,
-
-  -- ** Compilation options
-  CompOption(CompOption),
-  compBlank,
-  compExtended,   -- use extended regex syntax
-  compIgnoreCase, -- ignore case when matching
-  compNoSub,      -- no substring matching needed
-  compNewline,    -- '.' doesn't match newline
-
-  -- ** Execution options
-  ExecOption(ExecOption),
-  execBlank,
-  execNotBOL,     -- not at begining of line
-  execNotEOL,     -- not at end of line
-
-  -- ** Return codes
-  ReturnCode(ReturnCode),
-  retBadbr,
-  retBadpat,
-  retBadrpt,
-  retEcollate,
-  retEctype,
-  retEescape,
-  retEsubreg,
-  retEbrack,
-  retEparen,
-  retEbrace,
-  retErange,
-  retEspace
-  ) where
-
-#ifdef HAVE_REGEX_H
-#define HAVE_REGCOMP 1
-#else
-#ifdef __NHC__
-#define HAVE_REGEX_H 1
-#define HAVE_REGCOMP 1
-#endif
-#endif
-
-#include <sys/types.h>
--- string.h is needed for memset
-
-#include "myfree.h"
-         
-#include "string.h"
-
-#ifndef _POSIX_C_SOURCE
-#define _POSIX_C_SOURCE 1
-#endif
-
-#if HAVE_REGEX_H && HAVE_REGCOMP
-#include "regex.h"
-#else
-#include "regex.h"
-
--- CFILES stuff is Hugs only
-{-# CFILES cbits/reallocf.c #-}
-{-# CFILES cbits/regcomp.c #-}
-{-# CFILES cbits/regerror.c #-}
-{-# CFILES cbits/regexec.c #-}
-{-# CFILES cbits/regfree.c #-}
-#endif
-
-import Control.Monad(liftM)
-import Data.Array(Array,listArray)
-import Data.Bits(Bits(..))
-import Data.Int(Int32,Int64)   -- need whatever RegeOffset or #regoff_t type will be
-import Data.Word(Word32,Word64) -- need whatever RegeOffset or #regoff_t type will be
-import Foreign(Ptr, FunPtr, nullPtr, newForeignPtr,
-               addForeignPtrFinalizer, Storable(peekByteOff), allocaArray,
-               allocaBytes, withForeignPtr,ForeignPtr,plusPtr,peekElemOff)
-import Foreign.Marshal.Alloc(mallocBytes)
-import Foreign.C(CChar)
-#if __GLASGOW_HASKELL__ >= 703
-import Foreign.C(CSize(CSize),CInt(CInt))
-#else
-import Foreign.C(CSize,CInt)
-#endif
-import Foreign.C.String(peekCAString, CString)
-import Text.Regex.Base.RegexLike(RegexOptions(..),RegexMaker(..),RegexContext(..),MatchArray)
--- deprecated: import qualified System.IO.Error as IOERROR(try)
-import qualified Control.Exception(try,IOException)
-
-try :: IO a -> IO (Either Control.Exception.IOException a)
-try = Control.Exception.try
-
-type CRegex = ()   -- dummy regex_t used below to read out nsub value
-
--- | RegOffset is "typedef int regoff_t" on Linux and ultimately "typedef
--- long long __int64_t" on Max OS X.  So rather than saying
--- 2,147,483,647 is all the length you need, I'll take the larger:
--- 9,223,372,036,854,775,807 should be enough bytes for anyone, no
--- need for Integer. The alternative is to compile to different sizes
--- in a platform dependent manner with "type RegOffset = (#type
--- regoff_t)", which I do not want to do.
---
--- There is also a special value 'unusedRegOffset' :: 'RegOffset' which is
--- (-1) and as a starting index means that the subgroup capture was
--- unused.  Otherwise the RegOffset indicates a character boundary that
--- is before the character at that index offset, with the first
--- character at index offset 0. So starting at 1 and ending at 2 means
--- to take only the second character.
-type RegOffset = Int64
---debugging 64-bit ubuntu
-type RegOffsetT = (#type regoff_t)
-
--- | A bitmapped 'CInt' containing options for compilation of regular
--- expressions.  Option values (and their man 3 regcomp names) are
---
---  * 'compBlank' which is a completely zero value for all the flags.
---    This is also the 'blankCompOpt' value.
---
---  * 'compExtended' (REG_EXTENDED) which can be set to use extended instead
---    of basic regular expressions.
---    This is set in the 'defaultCompOpt' value.
---
---  * 'compNewline' (REG_NEWLINE) turns on newline sensitivity: The dot (.)
---    and inverted set @[^ ]@ never match newline, and ^ and $ anchors do
---    match after and before newlines.
---    This is set in the 'defaultCompOpt' value.
---
---  * 'compIgnoreCase' (REG_ICASE) which can be set to match ignoring upper
---    and lower distinctions.
---
---  * 'compNoSub' (REG_NOSUB) which turns off all information from matching
---    except whether a match exists.
-#ifdef __GLASGOW_HASKELL__
-newtype CompOption = CompOption CInt deriving (Eq,Show,Num,Bits)
-#else
-newtype CompOption = CompOption CInt deriving (Eq,Show)
-
-instance Num CompOption where
-	CompOption x + CompOption y = CompOption (x + y)
-	CompOption x - CompOption y = CompOption (x - y)
-	CompOption x * CompOption y = CompOption (x * y)
-	abs (CompOption x) = CompOption (abs x)
-	signum (CompOption x) = CompOption (signum x)
-	fromInteger n = CompOption (fromInteger n)
-
-instance Bits CompOption where
-	CompOption x .&. CompOption y = CompOption (x .&. y)
-	CompOption x .|. CompOption y = CompOption (x .|. y)
-	CompOption x `xor` CompOption y = CompOption (x `xor` y)
-	complement (CompOption x) = CompOption (complement x)
-	shift (CompOption x) n = CompOption (shift x n)
-	rotate (CompOption x) n = CompOption (rotate x n)
-	bitSize (CompOption x) = bitSize x
-	isSigned (CompOption x) = isSigned x
-#endif
-
--- | A bitmapped 'CInt' containing options for execution of compiled
--- regular expressions.  Option values (and their man 3 regexec names) are
---
---  * 'execBlank' which is a complete zero value for all the flags.  This is
---    the blankExecOpt value.
---
---  * 'execNotBOL' (REG_NOTBOL) can be set to prevent ^ from matching at the
---    start of the input.
---
---  * 'execNotEOL' (REG_NOTEOL) can be set to prevent $ from matching at the
---    end of the input (before the terminating NUL).
-#ifdef __GLASGOW_HASKELL__
-newtype ExecOption = ExecOption CInt deriving (Eq,Show,Num,Bits)
-#else
-newtype ExecOption = ExecOption CInt deriving (Eq,Show)
-
-instance Num ExecOption where
-	ExecOption x + ExecOption y = ExecOption (x + y)
-	ExecOption x - ExecOption y = ExecOption (x - y)
-	ExecOption x * ExecOption y = ExecOption (x * y)
-	abs (ExecOption x) = ExecOption (abs x)
-	signum (ExecOption x) = ExecOption (signum x)
-	fromInteger n = ExecOption (fromInteger n)
-
-instance Bits ExecOption where
-	ExecOption x .&. ExecOption y = ExecOption (x .&. y)
-	ExecOption x .|. ExecOption y = ExecOption (x .|. y)
-	ExecOption x `xor` ExecOption y = ExecOption (x `xor` y)
-	complement (ExecOption x) = ExecOption (complement x)
-	shift (ExecOption x) n = ExecOption (shift x n)
-	rotate (ExecOption x) n = ExecOption (rotate x n)
-	bitSize (ExecOption x) = bitSize x
-	isSigned (ExecOption x) = isSigned x
-#endif
-
--- | ReturnCode is an enumerated 'CInt', corresponding to the error codes
--- from @man 3 regex@:
---
--- * 'retBadbr' (@REG_BADBR@) invalid repetition count(s) in @{ }@
---
--- * 'retBadpat' (@REG_BADPAT@) invalid regular expression
---
--- * 'retBadrpt' (@REG_BADRPT@) @?@, @*@, or @+@ operand invalid
---
--- * 'retEcollate' (@REG_ECOLLATE@) invalid collating element
---
--- * 'retEctype' (@REG_ECTYPE@) invalid character class
---
--- * 'retEescape' (@REG_EESCAPE@) @\\@ applied to unescapable character
---
--- * 'retEsubreg' (@REG_ESUBREG@) invalid backreference number
---
--- * 'retEbrack' (@REG_EBRACK@) brackets @[ ]@ not balanced
---
--- * 'retEparen' (@REG_EPAREN@) parentheses @( )@ not balanced
---
--- * 'retEbrace' (@REG_EBRACE@) braces @{ }@ not balanced
---
--- * 'retErange' (@REG_ERANGE@) invalid character range in @[ ]@
---
--- * 'retEspace' (@REG_ESPACE@) ran out of memory
---
--- * 'retNoMatch' (@REG_NOMATCH@) The regexec() function failed to match
---
-newtype ReturnCode = ReturnCode CInt deriving (Eq,Show)
-
--- | A compiled regular expression.
-data Regex = Regex (ForeignPtr CRegex) CompOption ExecOption
-
--- | A completely zero value for all the flags.
--- This is also the 'blankCompOpt' value.
-compBlank :: CompOption
-compBlank = CompOption 0
-
--- | A completely zero value for all the flags.
--- This is also the 'blankExecOpt' value.
-execBlank :: ExecOption
-execBlank = ExecOption 0
-
-unusedRegOffset :: RegOffset
-unusedRegOffset = (-1)
-
--- | The return code will be retOk when it is the Haskell wrapper and
--- not the underlying library generating the error message.
-type WrapError = (ReturnCode,String)
-
-wrapCompile :: CompOption -- ^ Flags (bitmapped)
-            -> ExecOption -- ^ Flags (bitmapped)
-            -> CString -- ^ The regular expression to compile (ASCII only, no null bytes)
-            -> IO (Either WrapError Regex) -- ^ Returns: the compiled regular expression
-
-wrapTest :: Regex -> CString
-         -> IO (Either WrapError Bool)
-
--- | wrapMatch returns offsets for the begin and end of each capture.
--- Unused captures have offsets of unusedRegOffset which is (-1)
-wrapMatch :: Regex -> CString
-          -> IO (Either WrapError (Maybe [(RegOffset,RegOffset)]))
-
--- | wrapMatchAll returns the offset and length of each capture.
--- Unused captures have an offset of unusedRegOffset which is (-1) and
--- length of 0.
-wrapMatchAll :: Regex -> CString
-             -> IO (Either WrapError [MatchArray])
-
-wrapCount :: Regex -> CString
-          -> IO (Either WrapError Int)
-
-(=~)  :: (RegexMaker Regex CompOption ExecOption source,RegexContext Regex source1 target)
-      => source1 -> source -> target
-(=~~) :: (RegexMaker Regex CompOption ExecOption source,RegexContext Regex source1 target,Monad m)
-      => source1 -> source -> m target
-
-instance RegexOptions Regex CompOption ExecOption where
-  blankCompOpt = compBlank
-  blankExecOpt = execBlank
-  defaultCompOpt = compExtended .|. compNewline
-  defaultExecOpt = execBlank
-  setExecOpts e' (Regex r c _) = Regex r c e'
-  getExecOpts (Regex _ _ e) = e
-
--- (=~) ::(RegexMaker Regex CompOption ExecOption source,RegexContext Regex source1 target) => source1 -> source -> target
-(=~) x r = let make :: RegexMaker Regex CompOption ExecOption a => a -> Regex
-               make = makeRegex
-           in match (make r) x
-
--- (=~~) ::(RegexMaker Regex CompOption ExecOption source,RegexContext Regex source1 target,Monad m) => source1 -> source -> m target
-(=~~) x r = let make :: RegexMaker Regex CompOption ExecOption a => a -> Regex
-                make = makeRegex
-            in matchM (make r) x
-
-type CRegMatch = () -- dummy regmatch_t used below to read out so and eo values
-
--- -----------------------------------------------------------------------------
--- The POSIX regex C interface
-
--- string.h
-foreign import ccall unsafe "memset"
-  c_memset :: Ptr CRegex -> CInt -> CSize -> IO (Ptr CRegex)
-
--- c-finalizer/myfree.h and c-finalizer/myfree.c
-foreign import ccall unsafe "&myregfree"
-  c_myregfree :: FunPtr (Ptr CRegex -> IO ())
-
-#if __GLASGOW_HASKELL__ || __HUGS__
-
-foreign import ccall unsafe "regcomp"
-  c_regcomp :: Ptr CRegex -> CString -> CompOption -> IO ReturnCode
-
-{- NOT USED
-foreign import ccall unsafe "&regfree"
-  c_regfree :: FunPtr (Ptr CRegex -> IO ())
--}
-
-foreign import ccall unsafe "regexec"
-  c_regexec :: Ptr CRegex -> CString -> CSize
-            -> Ptr CRegMatch -> ExecOption -> IO ReturnCode
-
-foreign import ccall unsafe "regerror"
-  c_regerror :: ReturnCode -> Ptr CRegex
-             -> CString -> CSize -> IO CSize
-
-#elif HAVE_REGEX_H && HAVE_REGCOMP
-
-foreign import ccall unsafe "regex.h regcomp"
-  c_regcomp :: Ptr CRegex -> CString -> CompOption -> IO ReturnCode
-
-foreign import ccall unsafe "regex.h &regfree"
-  c_regfree :: FunPtr (Ptr CRegex -> IO ())
-
-foreign import ccall unsafe "regex.h regexec"
-  c_regexec :: Ptr CRegex -> CString -> CSize
-            -> Ptr CRegMatch -> ExecOption -> IO ReturnCode
-
-foreign import ccall unsafe "regex.h regerror"
-  c_regerror :: ReturnCode -> Ptr CRegex
-             -> CString -> CSize -> IO CSize
-
-#else
-
-foreign import ccall unsafe "regex/regex.h regcomp"
-  c_regcomp :: Ptr CRegex -> CString -> CompOption -> IO ReturnCode
-
-foreign import ccall unsafe "regex/regex.h &regfree"
-  c_regfree :: FunPtr (Ptr CRegex -> IO ())
-
-foreign import ccall unsafe "regex/regex.h regexec"
-  c_regexec :: Ptr CRegex -> CString -> CSize
-            -> Ptr CRegMatch -> ExecOption -> IO ReturnCode
-
-foreign import ccall unsafe "regex/regex.h regerror"
-  c_regerror :: ReturnCode -> Ptr CRegex
-             -> CString -> CSize -> IO CSize
-#endif
-
-retOk :: ReturnCode
-retOk = ReturnCode 0
-
--- Flags for regexec
-#enum ExecOption,ExecOption, \
-  execNotBOL = REG_NOTBOL, \
-  execNotEOL = REG_NOTEOL
-
--- Flags for regcomp
-#enum CompOption,CompOption, \
-  compExtended = REG_EXTENDED, \
-  compIgnoreCase = REG_ICASE, \
-  compNoSub = REG_NOSUB, \
-  compNewline = REG_NEWLINE
-
--- Return values from regexec (REG_NOMATCH, REG_ESPACE,...)
--- Error codes from regcomp (not REG_NOMATCH)
--- Though calling retNoMatch an error is rather missing the point...
-#enum ReturnCode,ReturnCode, \
-  retNoMatch = REG_NOMATCH, \
-  retBadbr = REG_BADBR, \
-  retBadpat = REG_BADPAT, \
-  retBadrpt = REG_BADRPT, \
-  retEcollate = REG_ECOLLATE, \
-  retEctype = REG_ECTYPE, \
-  retEescape = REG_EESCAPE, \
-  retEsubreg = REG_ESUBREG, \
-  retEbrack = REG_EBRACK, \
-  retEparen = REG_EPAREN, \
-  retEbrace = REG_EBRACE, \
-  retErange = REG_ERANGE, \
-  retEspace = REG_ESPACE
-----
--- error helpers
-
-nullTest :: Ptr a -> String -> IO (Either WrapError b) -> IO (Either WrapError b)
-{-# INLINE nullTest #-}
-nullTest ptr msg io = do
-  if nullPtr == ptr
-    then return (Left (retOk,"Ptr parameter was nullPtr in Text.Regex.TRE.Wrap."++msg))
-    else io
-
-isNewline,isNull :: Ptr CChar -> Int -> IO Bool
-isNewline cstr pos = liftM (newline ==) (peekElemOff cstr pos)
-  where newline = toEnum 10
-isNull cstr pos = liftM (nullChar ==) (peekElemOff cstr pos)
-  where nullChar = toEnum 0
-
-{-
-wrapRC :: ReturnCode -> IO (Either WrapError b)
-{-# INLINE wrapRC #-}
-wrapRC r = return (Left (r,"Error in Text.Regex.Posix.Wrap: "++show r))
--}
-wrapError :: ReturnCode -> Ptr CRegex -> IO (Either WrapError b)
-wrapError errCode regex_ptr = do
-  -- Call once to compute the error message buffer size
-  errBufSize <- c_regerror errCode regex_ptr nullPtr 0
-  -- Allocate a temporary buffer to hold the error message
-  allocaArray (fromIntegral errBufSize) $ \errBuf -> do
-   nullTest errBuf "wrapError errBuf" $ do
-    _ <- c_regerror errCode regex_ptr errBuf errBufSize
-    msg <- peekCAString errBuf :: IO String
-    return (Left (errCode, msg))
-
-----------
-wrapCompile flags e pattern = do
- nullTest pattern "wrapCompile pattern" $ do
-  e_regex_ptr <- try $ mallocBytes (#const sizeof(regex_t)) -- ioError called if nullPtr
-  case e_regex_ptr of
-    Left ioerror -> return (Left (retOk,"Text.Regex.Posix.Wrap.wrapCompile: IOError from mallocBytes(regex_t) : "++show ioerror))
-    Right raw_regex_ptr -> do
-      zero_regex_ptr <- c_memset raw_regex_ptr 0 (#const sizeof(regex_t)) -- no calloc, so clear the new area to zero
-      regex_fptr <- newForeignPtr c_myregfree zero_regex_ptr -- once pointed-to area is clear it should be safe to add finalizer
-      withForeignPtr regex_fptr $ \regex_ptr -> do  -- withForeignPtr is best hygiene here
-        errCode <- c_regcomp regex_ptr pattern flags
-        if (errCode == retOk)
-          then return . Right $ Regex regex_fptr flags e
-          else wrapError errCode regex_ptr
-
----------
-wrapTest (Regex regex_fptr _ flags) cstr = do
- nullTest cstr "wrapTest" $ do
-  withForeignPtr regex_fptr $ \regex_ptr -> do
-    r <- c_regexec regex_ptr cstr 0 nullPtr flags
-    if r == retOk
-      then return (Right True)
-      else if r == retNoMatch
-              then return (Right False)
-              else wrapError r regex_ptr
-
----------
-wrapMatch regex@(Regex regex_fptr compileOptions flags) cstr = do
- nullTest cstr "wrapMatch cstr" $ do
-  if (0 /= compNoSub .&. compileOptions)
-    then do
-      r <- wrapTest regex cstr
-      case r of
-        Right True -> return (Right (Just [])) -- Source of much "wtf?" crap
-        Right False -> return (Right Nothing)
-        Left err -> return (Left err)
-    else do
-      withForeignPtr regex_fptr $ \regex_ptr -> do
-        nsub <- (#peek regex_t, re_nsub) regex_ptr :: IO CSize
-        let nsub_int,nsub_bytes :: Int
-            nsub_int = fromIntegral nsub
-            nsub_bytes = ((1 + nsub_int) * (#const sizeof(regmatch_t)))
-        -- add one because index zero covers the whole match
-        allocaBytes nsub_bytes $ \p_match -> do
-         nullTest p_match "wrapMatch allocaBytes" $ do
-          doMatch regex_ptr cstr nsub p_match flags
-
--- Very very thin wrapper
--- Requires, but does not check, that nsub>=0
--- Cannot return (Right (Just []))
-doMatch :: Ptr CRegex -> CString -> CSize -> Ptr CRegMatch -> ExecOption
-        -> IO (Either WrapError (Maybe [(RegOffset,RegOffset)]))
-{-# INLINE doMatch #-}
-doMatch regex_ptr cstr nsub p_match flags = do
-  r <- c_regexec regex_ptr cstr (1 + nsub) p_match flags
-  if r == retOk
-    then do
-       regions <- mapM getOffsets . take (1+fromIntegral nsub)
-                  . iterate (`plusPtr` (#const sizeof(regmatch_t))) $ p_match
-       return (Right (Just regions)) -- regions will not be []
-    else if r == retNoMatch
-       then return (Right Nothing)
-       else wrapError r regex_ptr
-  where
-    getOffsets :: Ptr CRegMatch -> IO (RegOffset,RegOffset)
-    {-# INLINE getOffsets #-}
-    getOffsets pmatch' = do
-      start <- (#peek regmatch_t, rm_so) pmatch' :: IO (#type regoff_t)
-      end   <- (#peek regmatch_t, rm_eo) pmatch' :: IO (#type regoff_t)
-      return (fromIntegral start,fromIntegral end)
-
-wrapMatchAll regex@(Regex regex_fptr compileOptions flags) cstr = do
- nullTest cstr "wrapMatchAll cstr" $ do
-  if (0 /= compNoSub .&. compileOptions)
-    then do
-      r <- wrapTest regex cstr
-      case r of
-        Right True -> return (Right [(toMA 0 [])]) -- Source of much "wtf?" crap
-        Right False -> return (Right [])
-        Left err -> return (Left err)
-    else do
-      withForeignPtr regex_fptr $ \regex_ptr -> do
-        nsub <- (#peek regex_t, re_nsub) regex_ptr :: IO CSize
-        let nsub_int,nsub_bytes :: Int
-            nsub_int = fromIntegral nsub
-            nsub_bytes = ((1 + nsub_int) * (#const sizeof(regmatch_t)))
-        -- add one because index zero covers the whole match
-        allocaBytes nsub_bytes $ \p_match -> do
-         nullTest p_match "wrapMatchAll p_match" $ do
-          let flagsBOL = (complement execNotBOL) .&. flags
-              flagsMIDDLE = execNotBOL .|. flags
-              atBOL pos = doMatch regex_ptr (plusPtr cstr pos) nsub p_match flagsBOL
-              atMIDDLE pos = doMatch regex_ptr (plusPtr cstr pos) nsub p_match flagsMIDDLE
-              loop acc old (s,e) | acc `seq` old `seq` False = undefined
-                                 | s == e = do
-                let pos = old + fromIntegral e -- pos may be 0
-                atEnd <- isNull cstr pos
-                if atEnd then return (Right (acc []))
-                  else loop acc old (s,succ e)
-                                 | otherwise = do
-                let pos = old + fromIntegral e -- pos must be greater than 0 (tricky but true)
-                prev'newline <- isNewline cstr (pred pos) -- safe
-                result <- if prev'newline then atBOL pos else atMIDDLE pos
-                case result of
-                  Right Nothing -> return (Right (acc []))
-                  Right (Just parts@(whole:_)) -> let ma = toMA pos parts
-                                                 in loop (acc.(ma:)) pos whole
-                  Left err -> return (Left err)
-                  Right (Just []) -> return (Right (acc [(toMA pos [])])) -- should never happen
-          result <- doMatch regex_ptr cstr nsub p_match flags
-          case result of
-            Right Nothing -> return (Right [])
-            Right (Just parts@(whole:_)) -> let ma = toMA 0 parts
-                                            in loop (ma:) 0 whole
-            Left err -> return (Left err)
-            Right (Just []) -> return (Right [(toMA 0 [])]) -- should never happen
-  where
-    toMA :: Int -> [(RegOffset,RegOffset)] -> Array Int (Int,Int)
-    toMA pos [] = listArray (0,0) [(pos,0)] -- wtf?
-    toMA pos parts = listArray (0,pred (length parts))
-      . map (\(s,e)-> if s>=0 then (pos+fromIntegral s, fromIntegral (e-s)) else (-1,0))
-      $ parts
-
----------
-wrapCount regex@(Regex regex_fptr compileOptions flags) cstr = do
- nullTest cstr "wrapCount cstr" $ do
-  if (0 /= compNoSub .&. compileOptions)
-    then do
-      r <- wrapTest regex cstr
-      case r of
-        Right True -> return (Right 1)
-        Right False -> return (Right 0)
-        Left err -> return (Left err)
-    else do
-      withForeignPtr regex_fptr $ \regex_ptr -> do
-        let nsub_bytes = (#size regmatch_t)
-        allocaBytes nsub_bytes $ \p_match -> do
-         nullTest p_match "wrapCount p_match" $ do
-          let flagsBOL = (complement execNotBOL) .&. flags
-              flagsMIDDLE = execNotBOL .|. flags
-              atBOL pos = doMatch regex_ptr (plusPtr cstr pos) 0 p_match flagsBOL
-              atMIDDLE pos = doMatch regex_ptr (plusPtr cstr pos) 0 p_match flagsMIDDLE
-              loop acc old (s,e) | acc `seq` old `seq` False = undefined
-                                 | s == e = do
-                let pos = old + fromIntegral e -- 0 <= pos
-                atEnd <- isNull cstr pos
-                if atEnd then return (Right acc)
-                  else loop acc old (s,succ e)
-                                 | otherwise = do
-                let pos = old + fromIntegral e -- 0 < pos
-                prev'newline <- isNewline cstr (pred pos) -- safe
-                result <- if prev'newline then atBOL pos else atMIDDLE pos
-                case result of
-                  Right Nothing -> return (Right acc)
-                  Right (Just (whole:_)) -> loop (succ acc) pos whole
-                  Left err -> return (Left err)
-                  Right (Just []) -> return (Right acc) -- should never happen
-          result <- doMatch regex_ptr cstr 0 p_match flags
-          case result of
-            Right Nothing -> return (Right 0)
-            Right (Just (whole:_)) -> loop 1 0 whole
-            Left err -> return (Left err)
-            Right (Just []) -> return (Right 0) -- should never happen
-
-{-
-
--- This is the slower 0.66 version of the code (91s instead of 79s on 10^6 bytes)
-
-wrapMatchAll regex cstr = do
-  let regex' = setExecOpts (execNotBOL .|. (getExecOpts regex)) regex
-      at pos = wrapMatch regex' (plusPtr cstr pos)
-      loop old (s,e) | s == e = return []
-                     | otherwise = do
-        let pos = old + fromIntegral e
-        result <- at pos
-        case unwrap result of
-          Nothing -> return []
-          Just [] -> return ((toMA pos []):[]) -- wtf?
-          Just parts@(whole:_) -> do rest <- loop pos whole
-                                     return ((toMA pos parts) : rest)
-  result <- wrapMatch regex cstr
-  case unwrap result of
-    Nothing -> return []
-    Just [] -> return ((toMA 0 []):[]) -- wtf?
-    Just parts@(whole:_) -> do rest <- loop 0 whole
-                               return ((toMA 0 parts) : rest)
----------
--- This was also changed to match wrapMatchAll after 0.66
-wrapCount regex cstr = do
-  let regex' = setExecOpts (execNotBOL .|. (getExecOpts regex)) regex
-      at pos = wrapMatch regex' (plusPtr cstr pos)
-      loop acc old (s,e) | acc `seq` old `seq` False = undefined
-                         | s == e = return acc
-                         | otherwise = do
-        let pos = old + fromIntegral e
-        result <- at pos
-        case unwrap result of
-          Nothing -> return acc
-          Just [] -> return (succ acc) -- wtf?
-          Just (whole:_) -> loop (succ acc) pos whole
-  result <- wrapMatch regex cstr
-  case unwrap result of
-    Nothing -> return 0
-    Just [] -> return 1 -- wtf?
-    Just (whole:_) -> loop 1 0 whole
--}
diff --git a/c-finalizer/myfree.c b/c-finalizer/myfree.c
deleted file mode 100644
--- a/c-finalizer/myfree.c
+++ /dev/null
@@ -1,13 +0,0 @@
-#include "myfree.h"
-#include "regex.h"
-#include "stdlib.h"
-
-/* 
-void free(void *ptr);
-void regfree(regex_t *preg);
-*/
-
-void myregfree(void *preg) {
-  regfree(preg);
-  free(preg);
-}
diff --git a/c-finalizer/myfree.h b/c-finalizer/myfree.h
deleted file mode 100644
--- a/c-finalizer/myfree.h
+++ /dev/null
@@ -1,2 +0,0 @@
-void myregfree(void *);
-
diff --git a/cbits/cclass.h b/cbits/cclass.h
deleted file mode 100644
--- a/cbits/cclass.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993, 1994 Henry Spencer.
- * Copyright (c) 1992, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Henry Spencer.
- *
- * 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.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- *
- *	@(#)cclass.h	8.3 (Berkeley) 3/20/94
- */
-
-
-typedef enum {CALNUM, CALPHA, CBLANK, CCNTRL, CDIGIT, CGRAPH,
-	      CLOWER, CPRINT, CPUNCT, CSPACE, CUPPER, CXDIGIT} citype;
-
-/* character-class table */
-static struct cclass {
-	char *name;
-	citype fidx;
-} cclasses[] = {
-	{"alnum",       CALNUM},
-	{"alpha",       CALPHA},
-	{"blank",       CBLANK},
-	{"cntrl",       CCNTRL},
-	{"digit",       CDIGIT},
-	{"graph",       CGRAPH},
-	{"lower",       CLOWER},
-	{"print",       CPRINT},
-	{"punct",       CPUNCT},
-	{"space",       CSPACE},
-	{"upper",       CUPPER},
-	{"xdigit",      CXDIGIT},
-	{NULL,          }
-};
diff --git a/cbits/cname.h b/cbits/cname.h
deleted file mode 100644
--- a/cbits/cname.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993, 1994 Henry Spencer.
- * Copyright (c) 1992, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Henry Spencer.
- *
- * 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.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- *
- *	@(#)cname.h	8.3 (Berkeley) 3/20/94
- */
-
-/* character-name table */
-static struct cname {
-	char *name;
-	char code;
-} cnames[] = {
-	{"NUL",			'\0'},
-	{"SOH",			'\001'},
-	{"STX",			'\002'},
-	{"ETX",			'\003'},
-	{"EOT",			'\004'},
-	{"ENQ",			'\005'},
-	{"ACK",			'\006'},
-	{"BEL",			'\007'},
-	{"alert",		'\007'},
-	{"BS",			'\010'},
-	{"backspace",		'\b'},
-	{"HT",			'\011'},
-	{"tab",			'\t'},
-	{"LF",			'\012'},
-	{"newline",		'\n'},
-	{"VT",			'\013'},
-	{"vertical-tab",	'\v'},
-	{"FF",			'\014'},
-	{"form-feed",		'\f'},
-	{"CR",			'\015'},
-	{"carriage-return",	'\r'},
-	{"SO",			'\016'},
-	{"SI",			'\017'},
-	{"DLE",			'\020'},
-	{"DC1",			'\021'},
-	{"DC2",			'\022'},
-	{"DC3",			'\023'},
-	{"DC4",			'\024'},
-	{"NAK",			'\025'},
-	{"SYN",			'\026'},
-	{"ETB",			'\027'},
-	{"CAN",			'\030'},
-	{"EM",			'\031'},
-	{"SUB",			'\032'},
-	{"ESC",			'\033'},
-	{"IS4",			'\034'},
-	{"FS",			'\034'},
-	{"IS3",			'\035'},
-	{"GS",			'\035'},
-	{"IS2",			'\036'},
-	{"RS",			'\036'},
-	{"IS1",			'\037'},
-	{"US",			'\037'},
-	{"space",		' '},
-	{"exclamation-mark",	'!'},
-	{"quotation-mark",	'"'},
-	{"number-sign",		'#'},
-	{"dollar-sign",		'$'},
-	{"percent-sign",	'%'},
-	{"ampersand",		'&'},
-	{"apostrophe",		'\''},
-	{"left-parenthesis",	'('},
-	{"right-parenthesis",	')'},
-	{"asterisk",		'*'},
-	{"plus-sign",		'+'},
-	{"comma",		','},
-	{"hyphen",		'-'},
-	{"hyphen-minus",	'-'},
-	{"period",		'.'},
-	{"full-stop",		'.'},
-	{"slash",		'/'},
-	{"solidus",		'/'},
-	{"zero",		'0'},
-	{"one",			'1'},
-	{"two",			'2'},
-	{"three",		'3'},
-	{"four",		'4'},
-	{"five",		'5'},
-	{"six",			'6'},
-	{"seven",      		'7'},
-	{"eight",		'8'},
-	{"nine",		'9'},
-	{"colon",		':'},
-	{"semicolon",		';'},
-	{"less-than-sign",	'<'},
-	{"equals-sign",		'='},
-	{"greater-than-sign",	'>'},
-	{"question-mark",	'?'},
-	{"commercial-at",	'@'},
-	{"left-square-bracket",	'['},
-	{"backslash",		'\\'},
-	{"reverse-solidus",	'\\'},
-	{"right-square-bracket",']'},
-	{"circumflex",		'^'},
-	{"circumflex-accent",	'^'},
-	{"underscore",		'_'},
-	{"low-line",		'_'},
-	{"grave-accent",	'`'},
-	{"left-brace",		'{'},
-	{"left-curly-bracket",	'{'},
-	{"vertical-line",	'|'},
-	{"right-brace",		'}'},
-	{"right-curly-bracket",	'}'},
-	{"tilde",		'~'},
-	{"DEL",	'\177'},
-	{NULL,	0}
-};
diff --git a/cbits/engine.c b/cbits/engine.c
deleted file mode 100644
--- a/cbits/engine.c
+++ /dev/null
@@ -1,1139 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993, 1994 Henry Spencer.
- * Copyright (c) 1992, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Henry Spencer.
- *
- * 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.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- *
- *	@(#)engine.c	8.5 (Berkeley) 3/20/94
- *
- * $FreeBSD: src/lib/libc/regex/engine.c,v 1.5.8.1 2000/07/31 06:30:37 dcs Exp $
- */
-
-/*
- * The matching engine and friends.  This file is #included by regexec.c
- * after suitable #defines of a variety of macros used herein, so that
- * different state representations can be used without duplicating masses
- * of code.
- */
-
-#ifdef SNAMES
-#define	matcher	smatcher
-#define	fast	sfast
-#define	slow	sslow
-#define	dissect	sdissect
-#define	backref	sbackref
-#define	step	sstep
-#define	print	sprint
-#define	at	sat
-#define	match	smat
-#endif
-#ifdef LNAMES
-#define	matcher	lmatcher
-#define	fast	lfast
-#define	slow	lslow
-#define	dissect	ldissect
-#define	backref	lbackref
-#define	step	lstep
-#define	print	lprint
-#define	at	lat
-#define	match	lmat
-#endif
-
-/* another structure passed up and down to avoid zillions of parameters */
-struct match {
-	struct re_guts *g;
-	int eflags;
-	regmatch_t *pmatch;	/* [nsub+1] (0 element unused) */
-	char *offp;		/* offsets work from here */
-	char *beginp;		/* start of string -- virtual NUL precedes */
-	char *endp;		/* end of string -- virtual NUL here */
-	char *coldp;		/* can be no match starting before here */
-	char **lastpos;		/* [nplus+1] */
-	STATEVARS;
-	states st;		/* current states */
-	states fresh;		/* states for a fresh start */
-	states tmp;		/* temporary */
-	states empty;		/* empty set of states */
-};
-
-/* ========= begin header generated by ./mkh ========= */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* === engine.c === */
-static int matcher (struct re_guts *g, char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
-static char *dissect (struct match *m, char *start, char *stop, sopno startst, sopno stopst);
-static char *backref (struct match *m, char *start, char *stop, sopno startst, sopno stopst, sopno lev);
-static char *fast (struct match *m, char *start, char *stop, sopno startst, sopno stopst);
-static char *slow (struct match *m, char *start, char *stop, sopno startst, sopno stopst);
-static states step (struct re_guts *g, sopno start, sopno stop, states bef, int ch, states aft);
-#define	BOL	(OUT+1)
-#define	EOL	(BOL+1)
-#define	BOLEOL	(BOL+2)
-#define	NOTHING	(BOL+3)
-#define	BOW	(BOL+4)
-#define	EOW	(BOL+5)
-#define	CODEMAX	(BOL+5)		/* highest code used */
-#define	NONCHAR(c)	((c) > CHAR_MAX)
-#define	NNONCHAR	(CODEMAX-CHAR_MAX)
-#ifdef REDEBUG
-static void print (struct match *m, char *caption, states st, int ch, FILE *d);
-#endif
-#ifdef REDEBUG
-static void at __P((struct match *m, char *title, char *start, char *stop, sopno startst, sopno stopst));
-#endif
-#ifdef REDEBUG
-static char *pchar __P((int ch));
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-/* ========= end header generated by ./mkh ========= */
-
-#ifdef REDEBUG
-#define	SP(t, s, c)	print(m, t, s, c, stdout)
-#define	AT(t, p1, p2, s1, s2)	at(m, t, p1, p2, s1, s2)
-#define	NOTE(str)	{ if (m->eflags&REG_TRACE) printf("=%s\n", (str)); }
-#else
-#define	SP(t, s, c)	/* nothing */
-#define	AT(t, p1, p2, s1, s2)	/* nothing */
-#define	NOTE(s)	/* nothing */
-#endif
-
-/*
- - matcher - the actual matching engine
- == static int matcher(register struct re_guts *g, char *string, \
- ==	size_t nmatch, regmatch_t pmatch[], int eflags);
- */
-static int			/* 0 success, REG_NOMATCH failure */
-matcher(g, string, nmatch, pmatch, eflags)
-register struct re_guts *g;
-char *string;
-size_t nmatch;
-regmatch_t pmatch[];
-int eflags;
-{
-	register char *endp;
-	register int i;
-	struct match mv;
-	register struct match *m = &mv;
-	register char *dp;
-	register const sopno gf = g->firststate+1;	/* +1 for OEND */
-	register const sopno gl = g->laststate;
-	char *start;
-	char *stop;
-	/* Boyer-Moore algorithms variables */
-	register char *pp;
-	int cj, mj;
-	register char *mustfirst;
-	register char *mustlast;
-	register int *matchjump;
-	register int *charjump;
-
-	/* simplify the situation where possible */
-	if (g->cflags&REG_NOSUB)
-		nmatch = 0;
-	if (eflags&REG_STARTEND) {
-		start = string + pmatch[0].rm_so;
-		stop = string + pmatch[0].rm_eo;
-	} else {
-		start = string;
-		stop = start + strlen(start);
-	}
-	if (stop < start)
-		return(REG_INVARG);
-
-	/* prescreening; this does wonders for this rather slow code */
-	if (g->must != NULL) {
-		if (g->charjump != NULL && g->matchjump != NULL) {
-			mustfirst = g->must;
-			mustlast = g->must + g->mlen - 1;
-			charjump = g->charjump;
-			matchjump = g->matchjump;
-			pp = mustlast;
-			for (dp = start+g->mlen-1; dp < stop;) {
-				/* Fast skip non-matches */
-				while (dp < stop && charjump[*dp])
-					dp += charjump[*dp];
-
-				if (dp >= stop)
-					break;
-
-				/* Greedy matcher */
-				/* We depend on not being used for
-				 * for strings of length 1
-				 */
-				while (*--dp == *--pp && pp != mustfirst);
-
-				if (*dp == *pp)
-					break;
-
-				/* Jump to next possible match */
-				mj = matchjump[pp - mustfirst];
-				cj = charjump[*dp];
-				dp += (cj < mj ? mj : cj);
-				pp = mustlast;
-			}
-			if (pp != mustfirst)
-				return(REG_NOMATCH);
-		} else {
-			for (dp = start; dp < stop; dp++)
-				if (*dp == g->must[0] &&
-				    stop - dp >= g->mlen &&
-				    memcmp(dp, g->must, (size_t)g->mlen) == 0)
-					break;
-			if (dp == stop)		/* we didn't find g->must */
-				return(REG_NOMATCH);
-		}
-	}
-
-	/* match struct setup */
-	m->g = g;
-	m->eflags = eflags;
-	m->pmatch = NULL;
-	m->lastpos = NULL;
-	m->offp = string;
-	m->beginp = start;
-	m->endp = stop;
-	STATESETUP(m, 4);
-	SETUP(m->st);
-	SETUP(m->fresh);
-	SETUP(m->tmp);
-	SETUP(m->empty);
-	CLEAR(m->empty);
-
-	/* Adjust start according to moffset, to speed things up */
-	if (g->moffset > -1)
-		start = ((dp - g->moffset) < start) ? start : dp - g->moffset;
-
-	/* this loop does only one repetition except for backrefs */
-	for (;;) {
-		endp = fast(m, start, stop, gf, gl);
-		if (endp == NULL) {		/* a miss */
-			STATETEARDOWN(m);
-			return(REG_NOMATCH);
-		}
-		if (nmatch == 0 && !g->backrefs)
-			break;		/* no further info needed */
-
-		/* where? */
-		assert(m->coldp != NULL);
-		for (;;) {
-			NOTE("finding start");
-			endp = slow(m, m->coldp, stop, gf, gl);
-			if (endp != NULL)
-				break;
-			assert(m->coldp < m->endp);
-			m->coldp++;
-		}
-		if (nmatch == 1 && !g->backrefs)
-			break;		/* no further info needed */
-
-		/* oh my, he wants the subexpressions... */
-		if (m->pmatch == NULL)
-			m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) *
-							sizeof(regmatch_t));
-		if (m->pmatch == NULL) {
-			STATETEARDOWN(m);
-			return(REG_ESPACE);
-		}
-		for (i = 1; i <= m->g->nsub; i++)
-			m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1;
-		if (!g->backrefs && !(m->eflags&REG_BACKR)) {
-			NOTE("dissecting");
-			dp = dissect(m, m->coldp, endp, gf, gl);
-		} else {
-			if (g->nplus > 0 && m->lastpos == NULL)
-				m->lastpos = (char **)malloc((g->nplus+1) *
-							sizeof(char *));
-			if (g->nplus > 0 && m->lastpos == NULL) {
-				free(m->pmatch);
-				STATETEARDOWN(m);
-				return(REG_ESPACE);
-			}
-			NOTE("backref dissect");
-			dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
-		}
-		if (dp != NULL)
-			break;
-
-		/* uh-oh... we couldn't find a subexpression-level match */
-		assert(g->backrefs);	/* must be back references doing it */
-		assert(g->nplus == 0 || m->lastpos != NULL);
-		for (;;) {
-			if (dp != NULL || endp <= m->coldp)
-				break;		/* defeat */
-			NOTE("backoff");
-			endp = slow(m, m->coldp, endp-1, gf, gl);
-			if (endp == NULL)
-				break;		/* defeat */
-			/* try it on a shorter possibility */
-#ifndef NDEBUG
-			for (i = 1; i <= m->g->nsub; i++) {
-				assert(m->pmatch[i].rm_so == -1);
-				assert(m->pmatch[i].rm_eo == -1);
-			}
-#endif
-			NOTE("backoff dissect");
-			dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
-		}
-		assert(dp == NULL || dp == endp);
-		if (dp != NULL)		/* found a shorter one */
-			break;
-
-		/* despite initial appearances, there is no match here */
-		NOTE("false alarm");
-		start = m->coldp + 1;	/* recycle starting later */
-		assert(start <= stop);
-	}
-
-	/* fill in the details if requested */
-	if (nmatch > 0) {
-		pmatch[0].rm_so = m->coldp - m->offp;
-		pmatch[0].rm_eo = endp - m->offp;
-	}
-	if (nmatch > 1) {
-		assert(m->pmatch != NULL);
-		for (i = 1; i < nmatch; i++)
-			if (i <= m->g->nsub)
-				pmatch[i] = m->pmatch[i];
-			else {
-				pmatch[i].rm_so = -1;
-				pmatch[i].rm_eo = -1;
-			}
-	}
-
-	if (m->pmatch != NULL)
-		free((char *)m->pmatch);
-	if (m->lastpos != NULL)
-		free((char *)m->lastpos);
-	STATETEARDOWN(m);
-	return(0);
-}
-
-/*
- - dissect - figure out what matched what, no back references
- == static char *dissect(register struct match *m, char *start, \
- ==	char *stop, sopno startst, sopno stopst);
- */
-static char *			/* == stop (success) always */
-dissect(m, start, stop, startst, stopst)
-register struct match *m;
-char *start;
-char *stop;
-sopno startst;
-sopno stopst;
-{
-	register int i;
-	register sopno ss;	/* start sop of current subRE */
-	register sopno es;	/* end sop of current subRE */
-	register char *sp;	/* start of string matched by it */
-	register char *stp;	/* string matched by it cannot pass here */
-	register char *rest;	/* start of rest of string */
-	register char *tail;	/* string unmatched by rest of RE */
-	register sopno ssub;	/* start sop of subsubRE */
-	register sopno esub;	/* end sop of subsubRE */
-	register char *ssp;	/* start of string matched by subsubRE */
-	register char *sep;	/* end of string matched by subsubRE */
-	register char *oldssp;	/* previous ssp */
-	register char *dp;
-
-	AT("diss", start, stop, startst, stopst);
-	sp = start;
-	for (ss = startst; ss < stopst; ss = es) {
-		/* identify end of subRE */
-		es = ss;
-		switch (OP(m->g->strip[es])) {
-		case OPLUS_:
-		case OQUEST_:
-			es += OPND(m->g->strip[es]);
-			break;
-		case OCH_:
-			while (OP(m->g->strip[es]) != O_CH)
-				es += OPND(m->g->strip[es]);
-			break;
-		}
-		es++;
-
-		/* figure out what it matched */
-		switch (OP(m->g->strip[ss])) {
-		case OEND:
-			assert(nope);
-			break;
-		case OCHAR:
-			sp++;
-			break;
-		case OBOL:
-		case OEOL:
-		case OBOW:
-		case OEOW:
-			break;
-		case OANY:
-		case OANYOF:
-			sp++;
-			break;
-		case OBACK_:
-		case O_BACK:
-			assert(nope);
-			break;
-		/* cases where length of match is hard to find */
-		case OQUEST_:
-			stp = stop;
-			for (;;) {
-				/* how long could this one be? */
-				rest = slow(m, sp, stp, ss, es);
-				assert(rest != NULL);	/* it did match */
-				/* could the rest match the rest? */
-				tail = slow(m, rest, stop, es, stopst);
-				if (tail == stop)
-					break;		/* yes! */
-				/* no -- try a shorter match for this one */
-				stp = rest - 1;
-				assert(stp >= sp);	/* it did work */
-			}
-			ssub = ss + 1;
-			esub = es - 1;
-			/* did innards match? */
-			if (slow(m, sp, rest, ssub, esub) != NULL) {
-				dp = dissect(m, sp, rest, ssub, esub);
-				assert(dp == rest);
-			} else		/* no */
-				assert(sp == rest);
-			sp = rest;
-			break;
-		case OPLUS_:
-			stp = stop;
-			for (;;) {
-				/* how long could this one be? */
-				rest = slow(m, sp, stp, ss, es);
-				assert(rest != NULL);	/* it did match */
-				/* could the rest match the rest? */
-				tail = slow(m, rest, stop, es, stopst);
-				if (tail == stop)
-					break;		/* yes! */
-				/* no -- try a shorter match for this one */
-				stp = rest - 1;
-				assert(stp >= sp);	/* it did work */
-			}
-			ssub = ss + 1;
-			esub = es - 1;
-			ssp = sp;
-			oldssp = ssp;
-			for (;;) {	/* find last match of innards */
-				sep = slow(m, ssp, rest, ssub, esub);
-				if (sep == NULL || sep == ssp)
-					break;	/* failed or matched null */
-				oldssp = ssp;	/* on to next try */
-				ssp = sep;
-			}
-			if (sep == NULL) {
-				/* last successful match */
-				sep = ssp;
-				ssp = oldssp;
-			}
-			assert(sep == rest);	/* must exhaust substring */
-			assert(slow(m, ssp, sep, ssub, esub) == rest);
-			dp = dissect(m, ssp, sep, ssub, esub);
-			assert(dp == sep);
-			sp = rest;
-			break;
-		case OCH_:
-			stp = stop;
-			for (;;) {
-				/* how long could this one be? */
-				rest = slow(m, sp, stp, ss, es);
-				assert(rest != NULL);	/* it did match */
-				/* could the rest match the rest? */
-				tail = slow(m, rest, stop, es, stopst);
-				if (tail == stop)
-					break;		/* yes! */
-				/* no -- try a shorter match for this one */
-				stp = rest - 1;
-				assert(stp >= sp);	/* it did work */
-			}
-			ssub = ss + 1;
-			esub = ss + OPND(m->g->strip[ss]) - 1;
-			assert(OP(m->g->strip[esub]) == OOR1);
-			for (;;) {	/* find first matching branch */
-				if (slow(m, sp, rest, ssub, esub) == rest)
-					break;	/* it matched all of it */
-				/* that one missed, try next one */
-				assert(OP(m->g->strip[esub]) == OOR1);
-				esub++;
-				assert(OP(m->g->strip[esub]) == OOR2);
-				ssub = esub + 1;
-				esub += OPND(m->g->strip[esub]);
-				if (OP(m->g->strip[esub]) == OOR2)
-					esub--;
-				else
-					assert(OP(m->g->strip[esub]) == O_CH);
-			}
-			dp = dissect(m, sp, rest, ssub, esub);
-			assert(dp == rest);
-			sp = rest;
-			break;
-		case O_PLUS:
-		case O_QUEST:
-		case OOR1:
-		case OOR2:
-		case O_CH:
-			assert(nope);
-			break;
-		case OLPAREN:
-			i = OPND(m->g->strip[ss]);
-			assert(0 < i && i <= m->g->nsub);
-			m->pmatch[i].rm_so = sp - m->offp;
-			break;
-		case ORPAREN:
-			i = OPND(m->g->strip[ss]);
-			assert(0 < i && i <= m->g->nsub);
-			m->pmatch[i].rm_eo = sp - m->offp;
-			break;
-		default:		/* uh oh */
-			assert(nope);
-			break;
-		}
-	}
-
-	assert(sp == stop);
-	return(sp);
-}
-
-/*
- - backref - figure out what matched what, figuring in back references
- == static char *backref(register struct match *m, char *start, \
- ==	char *stop, sopno startst, sopno stopst, sopno lev);
- */
-static char *			/* == stop (success) or NULL (failure) */
-backref(m, start, stop, startst, stopst, lev)
-register struct match *m;
-char *start;
-char *stop;
-sopno startst;
-sopno stopst;
-sopno lev;			/* PLUS nesting level */
-{
-	register int i;
-	register sopno ss;	/* start sop of current subRE */
-	register char *sp;	/* start of string matched by it */
-	register sopno ssub;	/* start sop of subsubRE */
-	register sopno esub;	/* end sop of subsubRE */
-	register char *ssp;	/* start of string matched by subsubRE */
-	register char *dp;
-	register size_t len;
-	register int hard;
-	register sop s;
-	register regoff_t offsave;
-	register cset *cs;
-
-	AT("back", start, stop, startst, stopst);
-	sp = start;
-
-	/* get as far as we can with easy stuff */
-	hard = 0;
-	for (ss = startst; !hard && ss < stopst; ss++)
-		switch (OP(s = m->g->strip[ss])) {
-		case OCHAR:
-			if (sp == stop || *sp++ != (char)OPND(s))
-				return(NULL);
-			break;
-		case OANY:
-			if (sp == stop)
-				return(NULL);
-			sp++;
-			break;
-		case OANYOF:
-			cs = &m->g->sets[OPND(s)];
-			if (sp == stop || !CHIN(cs, *sp++))
-				return(NULL);
-			break;
-		case OBOL:
-			if ( (sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
-					(sp < m->endp && *(sp-1) == '\n' &&
-						(m->g->cflags&REG_NEWLINE)) )
-				{ /* yes */ }
-			else
-				return(NULL);
-			break;
-		case OEOL:
-			if ( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
-					(sp < m->endp && *sp == '\n' &&
-						(m->g->cflags&REG_NEWLINE)) )
-				{ /* yes */ }
-			else
-				return(NULL);
-			break;
-		case OBOW:
-			if (( (sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
-					(sp < m->endp && *(sp-1) == '\n' &&
-						(m->g->cflags&REG_NEWLINE)) ||
-					(sp > m->beginp &&
-							!ISWORD(*(sp-1))) ) &&
-					(sp < m->endp && ISWORD(*sp)) )
-				{ /* yes */ }
-			else
-				return(NULL);
-			break;
-		case OEOW:
-			if (( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
-					(sp < m->endp && *sp == '\n' &&
-						(m->g->cflags&REG_NEWLINE)) ||
-					(sp < m->endp && !ISWORD(*sp)) ) &&
-					(sp > m->beginp && ISWORD(*(sp-1))) )
-				{ /* yes */ }
-			else
-				return(NULL);
-			break;
-		case O_QUEST:
-			break;
-		case OOR1:	/* matches null but needs to skip */
-			ss++;
-			s = m->g->strip[ss];
-			do {
-				assert(OP(s) == OOR2);
-				ss += OPND(s);
-			} while (OP(s = m->g->strip[ss]) != O_CH);
-			/* note that the ss++ gets us past the O_CH */
-			break;
-		default:	/* have to make a choice */
-			hard = 1;
-			break;
-		}
-	if (!hard) {		/* that was it! */
-		if (sp != stop)
-			return(NULL);
-		return(sp);
-	}
-	ss--;			/* adjust for the for's final increment */
-
-	/* the hard stuff */
-	AT("hard", sp, stop, ss, stopst);
-	s = m->g->strip[ss];
-	switch (OP(s)) {
-	case OBACK_:		/* the vilest depths */
-		i = OPND(s);
-		assert(0 < i && i <= m->g->nsub);
-		if (m->pmatch[i].rm_eo == -1)
-			return(NULL);
-		assert(m->pmatch[i].rm_so != -1);
-		len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so;
-		assert(stop - m->beginp >= len);
-		if (sp > stop - len)
-			return(NULL);	/* not enough left to match */
-		ssp = m->offp + m->pmatch[i].rm_so;
-		if (memcmp(sp, ssp, len) != 0)
-			return(NULL);
-		while (m->g->strip[ss] != SOP(O_BACK, i))
-			ss++;
-		return(backref(m, sp+len, stop, ss+1, stopst, lev));
-		break;
-	case OQUEST_:		/* to null or not */
-		dp = backref(m, sp, stop, ss+1, stopst, lev);
-		if (dp != NULL)
-			return(dp);	/* not */
-		return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev));
-		break;
-	case OPLUS_:
-		assert(m->lastpos != NULL);
-		assert(lev+1 <= m->g->nplus);
-		m->lastpos[lev+1] = sp;
-		return(backref(m, sp, stop, ss+1, stopst, lev+1));
-		break;
-	case O_PLUS:
-		if (sp == m->lastpos[lev])	/* last pass matched null */
-			return(backref(m, sp, stop, ss+1, stopst, lev-1));
-		/* try another pass */
-		m->lastpos[lev] = sp;
-		dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev);
-		if (dp == NULL)
-			return(backref(m, sp, stop, ss+1, stopst, lev-1));
-		else
-			return(dp);
-		break;
-	case OCH_:		/* find the right one, if any */
-		ssub = ss + 1;
-		esub = ss + OPND(s) - 1;
-		assert(OP(m->g->strip[esub]) == OOR1);
-		for (;;) {	/* find first matching branch */
-			dp = backref(m, sp, stop, ssub, esub, lev);
-			if (dp != NULL)
-				return(dp);
-			/* that one missed, try next one */
-			if (OP(m->g->strip[esub]) == O_CH)
-				return(NULL);	/* there is none */
-			esub++;
-			assert(OP(m->g->strip[esub]) == OOR2);
-			ssub = esub + 1;
-			esub += OPND(m->g->strip[esub]);
-			if (OP(m->g->strip[esub]) == OOR2)
-				esub--;
-			else
-				assert(OP(m->g->strip[esub]) == O_CH);
-		}
-		break;
-	case OLPAREN:		/* must undo assignment if rest fails */
-		i = OPND(s);
-		assert(0 < i && i <= m->g->nsub);
-		offsave = m->pmatch[i].rm_so;
-		m->pmatch[i].rm_so = sp - m->offp;
-		dp = backref(m, sp, stop, ss+1, stopst, lev);
-		if (dp != NULL)
-			return(dp);
-		m->pmatch[i].rm_so = offsave;
-		return(NULL);
-		break;
-	case ORPAREN:		/* must undo assignment if rest fails */
-		i = OPND(s);
-		assert(0 < i && i <= m->g->nsub);
-		offsave = m->pmatch[i].rm_eo;
-		m->pmatch[i].rm_eo = sp - m->offp;
-		dp = backref(m, sp, stop, ss+1, stopst, lev);
-		if (dp != NULL)
-			return(dp);
-		m->pmatch[i].rm_eo = offsave;
-		return(NULL);
-		break;
-	default:		/* uh oh */
-		assert(nope);
-		break;
-	}
-
-	/* "can't happen" */
-	assert(nope);
-	/* NOTREACHED */
-	return "shut up gcc";
-}
-
-/*
- - fast - step through the string at top speed
- == static char *fast(register struct match *m, char *start, \
- ==	char *stop, sopno startst, sopno stopst);
- */
-static char *			/* where tentative match ended, or NULL */
-fast(m, start, stop, startst, stopst)
-register struct match *m;
-char *start;
-char *stop;
-sopno startst;
-sopno stopst;
-{
-	register states st = m->st;
-	register states fresh = m->fresh;
-	register states tmp = m->tmp;
-	register char *p = start;
-	register int c = (start == m->beginp) ? OUT : *(start-1);
-	register int lastc;	/* previous c */
-	register int flagch;
-	register int i;
-	register char *coldp;	/* last p after which no match was underway */
-
-	CLEAR(st);
-	SET1(st, startst);
-	st = step(m->g, startst, stopst, st, NOTHING, st);
-	ASSIGN(fresh, st);
-	SP("start", st, *p);
-	coldp = NULL;
-	for (;;) {
-		/* next character */
-		lastc = c;
-		c = (p == m->endp) ? OUT : *p;
-		if (EQ(st, fresh))
-			coldp = p;
-
-		/* is there an EOL and/or BOL between lastc and c? */
-		flagch = '\0';
-		i = 0;
-		if ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
-				(lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
-			flagch = BOL;
-			i = m->g->nbol;
-		}
-		if ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
-				(c == OUT && !(m->eflags&REG_NOTEOL)) ) {
-			flagch = (flagch == BOL) ? BOLEOL : EOL;
-			i += m->g->neol;
-		}
-		if (i != 0) {
-			for (; i > 0; i--)
-				st = step(m->g, startst, stopst, st, flagch, st);
-			SP("boleol", st, c);
-		}
-
-		/* how about a word boundary? */
-		if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
-					(c != OUT && ISWORD(c)) ) {
-			flagch = BOW;
-		}
-		if ( (lastc != OUT && ISWORD(lastc)) &&
-				(flagch == EOL || (c != OUT && !ISWORD(c))) ) {
-			flagch = EOW;
-		}
-		if (flagch == BOW || flagch == EOW) {
-			st = step(m->g, startst, stopst, st, flagch, st);
-			SP("boweow", st, c);
-		}
-
-		/* are we done? */
-		if (ISSET(st, stopst) || p == stop)
-			break;		/* NOTE BREAK OUT */
-
-		/* no, we must deal with this character */
-		ASSIGN(tmp, st);
-		ASSIGN(st, fresh);
-		assert(c != OUT);
-		st = step(m->g, startst, stopst, tmp, c, st);
-		SP("aft", st, c);
-		assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st));
-		p++;
-	}
-
-	assert(coldp != NULL);
-	m->coldp = coldp;
-	if (ISSET(st, stopst))
-		return(p+1);
-	else
-		return(NULL);
-}
-
-/*
- - slow - step through the string more deliberately
- == static char *slow(register struct match *m, char *start, \
- ==	char *stop, sopno startst, sopno stopst);
- */
-static char *			/* where it ended */
-slow(m, start, stop, startst, stopst)
-register struct match *m;
-char *start;
-char *stop;
-sopno startst;
-sopno stopst;
-{
-	register states st = m->st;
-	register states empty = m->empty;
-	register states tmp = m->tmp;
-	register char *p = start;
-	register int c = (start == m->beginp) ? OUT : *(start-1);
-	register int lastc;	/* previous c */
-	register int flagch;
-	register int i;
-	register char *matchp;	/* last p at which a match ended */
-
-	AT("slow", start, stop, startst, stopst);
-	CLEAR(st);
-	SET1(st, startst);
-	SP("sstart", st, *p);
-	st = step(m->g, startst, stopst, st, NOTHING, st);
-	matchp = NULL;
-	for (;;) {
-		/* next character */
-		lastc = c;
-		c = (p == m->endp) ? OUT : *p;
-
-		/* is there an EOL and/or BOL between lastc and c? */
-		flagch = '\0';
-		i = 0;
-		if ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
-				(lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
-			flagch = BOL;
-			i = m->g->nbol;
-		}
-		if ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
-				(c == OUT && !(m->eflags&REG_NOTEOL)) ) {
-			flagch = (flagch == BOL) ? BOLEOL : EOL;
-			i += m->g->neol;
-		}
-		if (i != 0) {
-			for (; i > 0; i--)
-				st = step(m->g, startst, stopst, st, flagch, st);
-			SP("sboleol", st, c);
-		}
-
-		/* how about a word boundary? */
-		if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
-					(c != OUT && ISWORD(c)) ) {
-			flagch = BOW;
-		}
-		if ( (lastc != OUT && ISWORD(lastc)) &&
-				(flagch == EOL || (c != OUT && !ISWORD(c))) ) {
-			flagch = EOW;
-		}
-		if (flagch == BOW || flagch == EOW) {
-			st = step(m->g, startst, stopst, st, flagch, st);
-			SP("sboweow", st, c);
-		}
-
-		/* are we done? */
-		if (ISSET(st, stopst))
-			matchp = p;
-		if (EQ(st, empty) || p == stop)
-			break;		/* NOTE BREAK OUT */
-
-		/* no, we must deal with this character */
-		ASSIGN(tmp, st);
-		ASSIGN(st, empty);
-		assert(c != OUT);
-		st = step(m->g, startst, stopst, tmp, c, st);
-		SP("saft", st, c);
-		assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st));
-		p++;
-	}
-
-	return(matchp);
-}
-
-
-/*
- - step - map set of states reachable before char to set reachable after
- == static states step(register struct re_guts *g, sopno start, sopno stop, \
- ==	register states bef, int ch, register states aft);
- == #define	BOL	(OUT+1)
- == #define	EOL	(BOL+1)
- == #define	BOLEOL	(BOL+2)
- == #define	NOTHING	(BOL+3)
- == #define	BOW	(BOL+4)
- == #define	EOW	(BOL+5)
- == #define	CODEMAX	(BOL+5)		// highest code used
- == #define	NONCHAR(c)	((c) > CHAR_MAX)
- == #define	NNONCHAR	(CODEMAX-CHAR_MAX)
- */
-static states
-step(g, start, stop, bef, ch, aft)
-register struct re_guts *g;
-sopno start;			/* start state within strip */
-sopno stop;			/* state after stop state within strip */
-register states bef;		/* states reachable before */
-int ch;				/* character or NONCHAR code */
-register states aft;		/* states already known reachable after */
-{
-	register cset *cs;
-	register sop s;
-	register sopno pc;
-	register onestate here;		/* note, macros know this name */
-	register sopno look;
-	register int i;
-
-	for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) {
-		s = g->strip[pc];
-		switch (OP(s)) {
-		case OEND:
-			assert(pc == stop-1);
-			break;
-		case OCHAR:
-			/* only characters can match */
-			assert(!NONCHAR(ch) || ch != (char)OPND(s));
-			if (ch == (char)OPND(s))
-				FWD(aft, bef, 1);
-			break;
-		case OBOL:
-			if (ch == BOL || ch == BOLEOL)
-				FWD(aft, bef, 1);
-			break;
-		case OEOL:
-			if (ch == EOL || ch == BOLEOL)
-				FWD(aft, bef, 1);
-			break;
-		case OBOW:
-			if (ch == BOW)
-				FWD(aft, bef, 1);
-			break;
-		case OEOW:
-			if (ch == EOW)
-				FWD(aft, bef, 1);
-			break;
-		case OANY:
-			if (!NONCHAR(ch))
-				FWD(aft, bef, 1);
-			break;
-		case OANYOF:
-			cs = &g->sets[OPND(s)];
-			if (!NONCHAR(ch) && CHIN(cs, ch))
-				FWD(aft, bef, 1);
-			break;
-		case OBACK_:		/* ignored here */
-		case O_BACK:
-			FWD(aft, aft, 1);
-			break;
-		case OPLUS_:		/* forward, this is just an empty */
-			FWD(aft, aft, 1);
-			break;
-		case O_PLUS:		/* both forward and back */
-			FWD(aft, aft, 1);
-			i = ISSETBACK(aft, OPND(s));
-			BACK(aft, aft, OPND(s));
-			if (!i && ISSETBACK(aft, OPND(s))) {
-				/* oho, must reconsider loop body */
-				pc -= OPND(s) + 1;
-				INIT(here, pc);
-			}
-			break;
-		case OQUEST_:		/* two branches, both forward */
-			FWD(aft, aft, 1);
-			FWD(aft, aft, OPND(s));
-			break;
-		case O_QUEST:		/* just an empty */
-			FWD(aft, aft, 1);
-			break;
-		case OLPAREN:		/* not significant here */
-		case ORPAREN:
-			FWD(aft, aft, 1);
-			break;
-		case OCH_:		/* mark the first two branches */
-			FWD(aft, aft, 1);
-			assert(OP(g->strip[pc+OPND(s)]) == OOR2);
-			FWD(aft, aft, OPND(s));
-			break;
-		case OOR1:		/* done a branch, find the O_CH */
-			if (ISSTATEIN(aft, here)) {
-				for (look = 1;
-						OP(s = g->strip[pc+look]) != O_CH;
-						look += OPND(s))
-					assert(OP(s) == OOR2);
-				FWD(aft, aft, look);
-			}
-			break;
-		case OOR2:		/* propagate OCH_'s marking */
-			FWD(aft, aft, 1);
-			if (OP(g->strip[pc+OPND(s)]) != O_CH) {
-				assert(OP(g->strip[pc+OPND(s)]) == OOR2);
-				FWD(aft, aft, OPND(s));
-			}
-			break;
-		case O_CH:		/* just empty */
-			FWD(aft, aft, 1);
-			break;
-		default:		/* ooooops... */
-			assert(nope);
-			break;
-		}
-	}
-
-	return(aft);
-}
-
-#ifdef REDEBUG
-/*
- - print - print a set of states
- == #ifdef REDEBUG
- == static void print(struct match *m, char *caption, states st, \
- ==	int ch, FILE *d);
- == #endif
- */
-static void
-print(m, caption, st, ch, d)
-struct match *m;
-char *caption;
-states st;
-int ch;
-FILE *d;
-{
-	register struct re_guts *g = m->g;
-	register int i;
-	register int first = 1;
-
-	if (!(m->eflags&REG_TRACE))
-		return;
-
-	fprintf(d, "%s", caption);
-	if (ch != '\0')
-		fprintf(d, " %s", pchar(ch));
-	for (i = 0; i < g->nstates; i++)
-		if (ISSET(st, i)) {
-			fprintf(d, "%s%d", (first) ? "\t" : ", ", i);
-			first = 0;
-		}
-	fprintf(d, "\n");
-}
-
-/*
- - at - print current situation
- == #ifdef REDEBUG
- == static void at(struct match *m, char *title, char *start, char *stop, \
- ==						sopno startst, sopno stopst);
- == #endif
- */
-static void
-at(m, title, start, stop, startst, stopst)
-struct match *m;
-char *title;
-char *start;
-char *stop;
-sopno startst;
-sopno stopst;
-{
-	if (!(m->eflags&REG_TRACE))
-		return;
-
-	printf("%s %s-", title, pchar(*start));
-	printf("%s ", pchar(*stop));
-	printf("%ld-%ld\n", (long)startst, (long)stopst);
-}
-
-#ifndef PCHARDONE
-#define	PCHARDONE	/* never again */
-/*
- - pchar - make a character printable
- == #ifdef REDEBUG
- == static char *pchar(int ch);
- == #endif
- *
- * Is this identical to regchar() over in debug.c?  Well, yes.  But a
- * duplicate here avoids having a debugging-capable regexec.o tied to
- * a matching debug.o, and this is convenient.  It all disappears in
- * the non-debug compilation anyway, so it doesn't matter much.
- */
-static char *			/* -> representation */
-pchar(ch)
-int ch;
-{
-	static char pbuf[10];
-
-	if (isprint((uch)ch) || ch == ' ')
-		sprintf(pbuf, "%c", ch);
-	else
-		sprintf(pbuf, "\\%o", ch);
-	return(pbuf);
-}
-#endif
-#endif
-
-#undef	matcher
-#undef	fast
-#undef	slow
-#undef	dissect
-#undef	backref
-#undef	step
-#undef	print
-#undef	at
-#undef	match
diff --git a/cbits/myfree.c b/cbits/myfree.c
new file mode 100644
--- /dev/null
+++ b/cbits/myfree.c
@@ -0,0 +1,14 @@
+#include <regex.h>
+#include <stdlib.h>
+
+#include "myfree.h"
+
+/* 
+void free(void *ptr);
+void regfree(regex_t *preg);
+*/
+
+void hs_regex_regfree(void *preg) {
+  regfree(preg);
+  free(preg);
+}
diff --git a/cbits/myfree.h b/cbits/myfree.h
new file mode 100644
--- /dev/null
+++ b/cbits/myfree.h
@@ -0,0 +1,1 @@
+void hs_regex_regfree(void *);
diff --git a/cbits/reallocf.c b/cbits/reallocf.c
deleted file mode 100644
--- a/cbits/reallocf.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*-
- * Copyright (c) 1998, M. Warner Losh <imp@freebsd.org>
- * 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.
- *
- * $FreeBSD: src/lib/libc/stdlib/reallocf.c,v 1.3 1999/08/28 00:01:37 peter Exp $
- */
-#include <stdlib.h>
-
-void *
-reallocf(void *ptr, size_t size)
-{
-	void *nptr;
-
-	nptr = realloc(ptr, size);
-	if (!nptr && ptr)
-		free(ptr);
-	return (nptr);
-}
diff --git a/cbits/regcomp.c b/cbits/regcomp.c
deleted file mode 100644
--- a/cbits/regcomp.c
+++ /dev/null
@@ -1,2102 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993, 1994 Henry Spencer.
- * Copyright (c) 1992, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Henry Spencer.
- *
- * 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.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- *
- *	@(#)regcomp.c	8.5 (Berkeley) 3/20/94
- *
- * $FreeBSD: src/lib/libc/regex/regcomp.c,v 1.13.2.1 2000/07/31 06:30:37 dcs Exp $
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)regcomp.c	8.5 (Berkeley) 3/20/94";
-#endif /* LIBC_SCCS and not lint */
-
-#include <sys/types.h>
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <limits.h>
-#include <stdlib.h>
-#include "regex.h"
-
-// removed collate stuff --SDM
-// #include "collate.h"
-
-#ifdef _WIN32
-#define isblank(c) ((c) == ' ' || (c) == '\t')
-#endif
-
-#include "utils.h"
-#include "regex2.h"
-
-#include "cclass.h"
-#include "cname.h"
-
-/*
- * parse structure, passed up and down to avoid global variables and
- * other clumsinesses
- */
-struct parse {
-	char *next;		/* next character in RE */
-	char *end;		/* end of string (-> NUL normally) */
-	int error;		/* has an error been seen? */
-	sop *strip;		/* malloced strip */
-	sopno ssize;		/* malloced strip size (allocated) */
-	sopno slen;		/* malloced strip length (used) */
-	int ncsalloc;		/* number of csets allocated */
-	struct re_guts *g;
-#	define	NPAREN	10	/* we need to remember () 1-9 for back refs */
-	sopno pbegin[NPAREN];	/* -> ( ([0] unused) */
-	sopno pend[NPAREN];	/* -> ) ([0] unused) */
-};
-
-/* === reallocf.c === */
-void * reallocf(void *ptr, size_t size);
-
-/* ========= begin header generated by ./mkh ========= */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* === regcomp.c === */
-static void p_ere (struct parse *p, int stop);
-static void p_ere_exp (struct parse *p);
-static void p_str (struct parse *p);
-static void p_bre (struct parse *p, int end1, int end2);
-static int p_simp_re (struct parse *p, int starordinary);
-static int p_count (struct parse *p);
-static void p_bracket (struct parse *p);
-static void p_b_term (struct parse *p, cset *cs);
-static void p_b_cclass (struct parse *p, cset *cs);
-static void p_b_eclass (struct parse *p, cset *cs);
-static char p_b_symbol (struct parse *p);
-static char p_b_coll_elem (struct parse *p, int endc);
-static char othercase (int ch);
-static void bothcases (struct parse *p, int ch);
-static void ordinary (struct parse *p, int ch);
-static void nonnewline (struct parse *p);
-static void repeat (struct parse *p, sopno start, int from, int to);
-static int seterr (struct parse *p, int e);
-static cset *allocset (struct parse *p);
-static void freeset (struct parse *p, cset *cs);
-static int freezeset (struct parse *p, cset *cs);
-static int firstch (struct parse *p, cset *cs);
-static int nch (struct parse *p, cset *cs);
-static void mcadd (struct parse *p, cset *cs, char *cp);
-#if used
-static void mcsub (cset *cs, char *cp);
-static int mcin (cset *cs, char *cp);
-static char *mcfind (cset *cs, char *cp);
-#endif
-static void mcinvert (struct parse *p, cset *cs);
-static void mccase (struct parse *p, cset *cs);
-static int isinsets (struct re_guts *g, int c);
-static int samesets (struct re_guts *g, int c1, int c2);
-static void categorize (struct parse *p, struct re_guts *g);
-static sopno dupl (struct parse *p, sopno start, sopno finish);
-static void doemit (struct parse *p, sop op, size_t opnd);
-static void doinsert (struct parse *p, sop op, size_t opnd, sopno pos);
-static void dofwd (struct parse *p, sopno pos, sop value);
-static void enlarge (struct parse *p, sopno size);
-static void stripsnug (struct parse *p, struct re_guts *g);
-static void findmust (struct parse *p, struct re_guts *g);
-static int altoffset (sop *scan, int offset, int mccs);
-static void computejumps (struct parse *p, struct re_guts *g);
-static void computematchjumps (struct parse *p, struct re_guts *g);
-static sopno pluscount (struct parse *p, struct re_guts *g);
-
-#ifdef __cplusplus
-}
-#endif
-/* ========= end header generated by ./mkh ========= */
-
-static char nuls[10];		/* place to point scanner in event of error */
-
-/*
- * macros for use with parse structure
- * BEWARE:  these know that the parse structure is named `p' !!!
- */
-#define	PEEK()	(*p->next)
-#define	PEEK2()	(*(p->next+1))
-#define	MORE()	(p->next < p->end)
-#define	MORE2()	(p->next+1 < p->end)
-#define	SEE(c)	(MORE() && PEEK() == (c))
-#define	SEETWO(a, b)	(MORE() && MORE2() && PEEK() == (a) && PEEK2() == (b))
-#define	EAT(c)	((SEE(c)) ? (NEXT(), 1) : 0)
-#define	EATTWO(a, b)	((SEETWO(a, b)) ? (NEXT2(), 1) : 0)
-#define	NEXT()	(p->next++)
-#define	NEXT2()	(p->next += 2)
-#define	NEXTn(n)	(p->next += (n))
-#define	GETNEXT()	(*p->next++)
-#define	SETERROR(e)	seterr(p, (e))
-#define	REQUIRE(co, e)	((co) || SETERROR(e))
-#define	MUSTSEE(c, e)	(REQUIRE(MORE() && PEEK() == (c), e))
-#define	MUSTEAT(c, e)	(REQUIRE(MORE() && GETNEXT() == (c), e))
-#define	MUSTNOTSEE(c, e)	(REQUIRE(!MORE() || PEEK() != (c), e))
-#define	EMIT(op, sopnd)	doemit(p, (sop)(op), (size_t)(sopnd))
-#define	INSERT(op, pos)	doinsert(p, (sop)(op), HERE()-(pos)+1, pos)
-#define	AHEAD(pos)		dofwd(p, pos, HERE()-(pos))
-#define	ASTERN(sop, pos)	EMIT(sop, HERE()-pos)
-#define	HERE()		(p->slen)
-#define	THERE()		(p->slen - 1)
-#define	THERETHERE()	(p->slen - 2)
-#define	DROP(n)	(p->slen -= (n))
-
-#ifndef NDEBUG
-static int never = 0;		/* for use in asserts; shuts lint up */
-#else
-#define	never	0		/* some <assert.h>s have bugs too */
-#endif
-
-/* Macro used by computejump()/computematchjump() */
-#define MIN(a,b)	((a)<(b)?(a):(b))
-
-/*
- - regcomp - interface for parser and compilation
- = extern int regcomp(regex_t *, const char *, int);
- = #define	REG_BASIC	0000
- = #define	REG_EXTENDED	0001
- = #define	REG_ICASE	0002
- = #define	REG_NOSUB	0004
- = #define	REG_NEWLINE	0010
- = #define	REG_NOSPEC	0020
- = #define	REG_PEND	0040
- = #define	REG_DUMP	0200
- */
-int				/* 0 success, otherwise REG_something */
-regcomp(preg, pattern, cflags)
-regex_t *preg;
-const char *pattern;
-int cflags;
-{
-	struct parse pa;
-	register struct re_guts *g;
-	register struct parse *p = &pa;
-	register int i;
-	register size_t len;
-#ifdef REDEBUG
-#	define	GOODFLAGS(f)	(f)
-#else
-#	define	GOODFLAGS(f)	((f)&~REG_DUMP)
-#endif
-
-	cflags = GOODFLAGS(cflags);
-	if ((cflags&REG_EXTENDED) && (cflags&REG_NOSPEC))
-		return(REG_INVARG);
-
-	if (cflags&REG_PEND) {
-		if (preg->re_endp < pattern)
-			return(REG_INVARG);
-		len = preg->re_endp - pattern;
-	} else
-		len = strlen((char *)pattern);
-
-	/* do the mallocs early so failure handling is easy */
-	g = (struct re_guts *)malloc(sizeof(struct re_guts) +
-							(NC-1)*sizeof(cat_t));
-	if (g == NULL)
-		return(REG_ESPACE);
-	p->ssize = len/(size_t)2*(size_t)3 + (size_t)1;	/* ugh */
-	p->strip = (sop *)malloc(p->ssize * sizeof(sop));
-	p->slen = 0;
-	if (p->strip == NULL) {
-		free((char *)g);
-		return(REG_ESPACE);
-	}
-
-	/* set things up */
-	p->g = g;
-	p->next = (char *)pattern;	/* convenience; we do not modify it */
-	p->end = p->next + len;
-	p->error = 0;
-	p->ncsalloc = 0;
-	for (i = 0; i < NPAREN; i++) {
-		p->pbegin[i] = 0;
-		p->pend[i] = 0;
-	}
-	g->csetsize = NC;
-	g->sets = NULL;
-	g->setbits = NULL;
-	g->ncsets = 0;
-	g->cflags = cflags;
-	g->iflags = 0;
-	g->nbol = 0;
-	g->neol = 0;
-	g->must = NULL;
-	g->moffset = -1;
-	g->charjump = NULL;
-	g->matchjump = NULL;
-	g->mlen = 0;
-	g->nsub = 0;
-	g->ncategories = 1;	/* category 0 is "everything else" */
-	g->categories = &g->catspace[-(CHAR_MIN)];
-	(void) memset((char *)g->catspace, 0, NC*sizeof(cat_t));
-	g->backrefs = 0;
-
-	/* do it */
-	EMIT(OEND, 0);
-	g->firststate = THERE();
-	if (cflags&REG_EXTENDED)
-		p_ere(p, OUT);
-	else if (cflags&REG_NOSPEC)
-		p_str(p);
-	else
-		p_bre(p, OUT, OUT);
-	EMIT(OEND, 0);
-	g->laststate = THERE();
-
-	/* tidy up loose ends and fill things in */
-	categorize(p, g);
-	stripsnug(p, g);
-	findmust(p, g);
-	/* only use Boyer-Moore algorithm if the pattern is bigger
-	 * than three characters
-	 */
-	if(g->mlen > 3) {
-		computejumps(p, g);
-		computematchjumps(p, g);
-		if(g->matchjump == NULL && g->charjump != NULL) {
-			free(g->charjump);
-			g->charjump = NULL;
-		}
-	}
-	g->nplus = pluscount(p, g);
-	g->magic = MAGIC2;
-	preg->re_nsub = g->nsub;
-	preg->re_g = g;
-	preg->re_magic = MAGIC1;
-#ifndef REDEBUG
-	/* not debugging, so can't rely on the assert() in regexec() */
-	if (g->iflags&BAD)
-		SETERROR(REG_ASSERT);
-#endif
-
-	/* win or lose, we're done */
-	if (p->error != 0)	/* lose */
-		regfree(preg);
-	return(p->error);
-}
-
-/*
- - p_ere - ERE parser top level, concatenation and alternation
- == static void p_ere(register struct parse *p, int stop);
- */
-static void
-p_ere(p, stop)
-register struct parse *p;
-int stop;			/* character this ERE should end at */
-{
-	register char c;
-	register sopno prevback;
-	register sopno prevfwd;
-	register sopno conc;
-	register int first = 1;		/* is this the first alternative? */
-
-	for (;;) {
-		/* do a bunch of concatenated expressions */
-		conc = HERE();
-		while (MORE() && (c = PEEK()) != '|' && c != stop)
-			p_ere_exp(p);
-		(void)REQUIRE(HERE() != conc, REG_EMPTY);	/* require nonempty */
-
-		if (!EAT('|'))
-			break;		/* NOTE BREAK OUT */
-
-		if (first) {
-			INSERT(OCH_, conc);	/* offset is wrong */
-			prevfwd = conc;
-			prevback = conc;
-			first = 0;
-		}
-		ASTERN(OOR1, prevback);
-		prevback = THERE();
-		AHEAD(prevfwd);			/* fix previous offset */
-		prevfwd = HERE();
-		EMIT(OOR2, 0);			/* offset is very wrong */
-	}
-
-	if (!first) {		/* tail-end fixups */
-		AHEAD(prevfwd);
-		ASTERN(O_CH, prevback);
-	}
-
-	assert(!MORE() || SEE(stop));
-}
-
-/*
- - p_ere_exp - parse one subERE, an atom possibly followed by a repetition op
- == static void p_ere_exp(register struct parse *p);
- */
-static void
-p_ere_exp(p)
-register struct parse *p;
-{
-	register char c;
-	register sopno pos;
-	register int count;
-	register int count2;
-	register sopno subno;
-	int wascaret = 0;
-
-	assert(MORE());		/* caller should have ensured this */
-	c = GETNEXT();
-
-	pos = HERE();
-	switch (c) {
-	case '(':
-		(void)REQUIRE(MORE(), REG_EPAREN);
-		p->g->nsub++;
-		subno = p->g->nsub;
-		if (subno < NPAREN)
-			p->pbegin[subno] = HERE();
-		EMIT(OLPAREN, subno);
-		if (!SEE(')'))
-			p_ere(p, ')');
-		if (subno < NPAREN) {
-			p->pend[subno] = HERE();
-			assert(p->pend[subno] != 0);
-		}
-		EMIT(ORPAREN, subno);
-		(void)MUSTEAT(')', REG_EPAREN);
-		break;
-#ifndef POSIX_MISTAKE
-	case ')':		/* happens only if no current unmatched ( */
-		/*
-		 * You may ask, why the ifndef?  Because I didn't notice
-		 * this until slightly too late for 1003.2, and none of the
-		 * other 1003.2 regular-expression reviewers noticed it at
-		 * all.  So an unmatched ) is legal POSIX, at least until
-		 * we can get it fixed.
-		 */
-		SETERROR(REG_EPAREN);
-		break;
-#endif
-	case '^':
-		EMIT(OBOL, 0);
-		p->g->iflags |= USEBOL;
-		p->g->nbol++;
-		wascaret = 1;
-		break;
-	case '$':
-		EMIT(OEOL, 0);
-		p->g->iflags |= USEEOL;
-		p->g->neol++;
-		break;
-	case '|':
-		SETERROR(REG_EMPTY);
-		break;
-	case '*':
-	case '+':
-	case '?':
-		SETERROR(REG_BADRPT);
-		break;
-	case '.':
-		if (p->g->cflags&REG_NEWLINE)
-			nonnewline(p);
-		else
-			EMIT(OANY, 0);
-		break;
-	case '[':
-		p_bracket(p);
-		break;
-	case '\\':
-		(void)REQUIRE(MORE(), REG_EESCAPE);
-		c = GETNEXT();
-		ordinary(p, c);
-		break;
-	case '{':		/* okay as ordinary except if digit follows */
-		(void)REQUIRE(!MORE() || !isdigit((uch)PEEK()), REG_BADRPT);
-		/* FALLTHROUGH */
-	default:
-		ordinary(p, c);
-		break;
-	}
-
-	if (!MORE())
-		return;
-	c = PEEK();
-	/* we call { a repetition if followed by a digit */
-	if (!( c == '*' || c == '+' || c == '?' ||
-				(c == '{' && MORE2() && isdigit((uch)PEEK2())) ))
-		return;		/* no repetition, we're done */
-	NEXT();
-
-	(void)REQUIRE(!wascaret, REG_BADRPT);
-	switch (c) {
-	case '*':	/* implemented as +? */
-		/* this case does not require the (y|) trick, noKLUDGE */
-		INSERT(OPLUS_, pos);
-		ASTERN(O_PLUS, pos);
-		INSERT(OQUEST_, pos);
-		ASTERN(O_QUEST, pos);
-		break;
-	case '+':
-		INSERT(OPLUS_, pos);
-		ASTERN(O_PLUS, pos);
-		break;
-	case '?':
-		/* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
-		INSERT(OCH_, pos);		/* offset slightly wrong */
-		ASTERN(OOR1, pos);		/* this one's right */
-		AHEAD(pos);			/* fix the OCH_ */
-		EMIT(OOR2, 0);			/* offset very wrong... */
-		AHEAD(THERE());			/* ...so fix it */
-		ASTERN(O_CH, THERETHERE());
-		break;
-	case '{':
-		count = p_count(p);
-		if (EAT(',')) {
-			if (isdigit((uch)PEEK())) {
-				count2 = p_count(p);
-				(void)REQUIRE(count <= count2, REG_BADBR);
-			} else		/* single number with comma */
-				count2 = INFINITY;
-		} else		/* just a single number */
-			count2 = count;
-		repeat(p, pos, count, count2);
-		if (!EAT('}')) {	/* error heuristics */
-			while (MORE() && PEEK() != '}')
-				NEXT();
-			(void)REQUIRE(MORE(), REG_EBRACE);
-			SETERROR(REG_BADBR);
-		}
-		break;
-	}
-
-	if (!MORE())
-		return;
-	c = PEEK();
-	if (!( c == '*' || c == '+' || c == '?' ||
-				(c == '{' && MORE2() && isdigit((uch)PEEK2())) ) )
-		return;
-	SETERROR(REG_BADRPT);
-}
-
-/*
- - p_str - string (no metacharacters) "parser"
- == static void p_str(register struct parse *p);
- */
-static void
-p_str(p)
-register struct parse *p;
-{
-	(void)REQUIRE(MORE(), REG_EMPTY);
-	while (MORE())
-		ordinary(p, GETNEXT());
-}
-
-/*
- - p_bre - BRE parser top level, anchoring and concatenation
- == static void p_bre(register struct parse *p, register int end1, \
- ==	register int end2);
- * Giving end1 as OUT essentially eliminates the end1/end2 check.
- *
- * This implementation is a bit of a kludge, in that a trailing $ is first
- * taken as an ordinary character and then revised to be an anchor.  The
- * only undesirable side effect is that '$' gets included as a character
- * category in such cases.  This is fairly harmless; not worth fixing.
- * The amount of lookahead needed to avoid this kludge is excessive.
- */
-static void
-p_bre(p, end1, end2)
-register struct parse *p;
-register int end1;		/* first terminating character */
-register int end2;		/* second terminating character */
-{
-	register sopno start = HERE();
-	register int first = 1;			/* first subexpression? */
-	register int wasdollar = 0;
-
-	if (EAT('^')) {
-		EMIT(OBOL, 0);
-		p->g->iflags |= USEBOL;
-		p->g->nbol++;
-	}
-	while (MORE() && !SEETWO(end1, end2)) {
-		wasdollar = p_simp_re(p, first);
-		first = 0;
-	}
-	if (wasdollar) {	/* oops, that was a trailing anchor */
-		DROP(1);
-		EMIT(OEOL, 0);
-		p->g->iflags |= USEEOL;
-		p->g->neol++;
-	}
-
-	(void)REQUIRE(HERE() != start, REG_EMPTY);	/* require nonempty */
-}
-
-/*
- - p_simp_re - parse a simple RE, an atom possibly followed by a repetition
- == static int p_simp_re(register struct parse *p, int starordinary);
- */
-static int			/* was the simple RE an unbackslashed $? */
-p_simp_re(p, starordinary)
-register struct parse *p;
-int starordinary;		/* is a leading * an ordinary character? */
-{
-	register int c;
-	register int count;
-	register int count2;
-	register sopno pos;
-	register int i;
-	register sopno subno;
-#	define	BACKSL	(1<<CHAR_BIT)
-
-	pos = HERE();		/* repetion op, if any, covers from here */
-
-	assert(MORE());		/* caller should have ensured this */
-	c = GETNEXT();
-	if (c == '\\') {
-		(void)REQUIRE(MORE(), REG_EESCAPE);
-		c = BACKSL | GETNEXT();
-	}
-	switch (c) {
-	case '.':
-		if (p->g->cflags&REG_NEWLINE)
-			nonnewline(p);
-		else
-			EMIT(OANY, 0);
-		break;
-	case '[':
-		p_bracket(p);
-		break;
-	case BACKSL|'{':
-		SETERROR(REG_BADRPT);
-		break;
-	case BACKSL|'(':
-		p->g->nsub++;
-		subno = p->g->nsub;
-		if (subno < NPAREN)
-			p->pbegin[subno] = HERE();
-		EMIT(OLPAREN, subno);
-		/* the MORE here is an error heuristic */
-		if (MORE() && !SEETWO('\\', ')'))
-			p_bre(p, '\\', ')');
-		if (subno < NPAREN) {
-			p->pend[subno] = HERE();
-			assert(p->pend[subno] != 0);
-		}
-		EMIT(ORPAREN, subno);
-		(void)REQUIRE(EATTWO('\\', ')'), REG_EPAREN);
-		break;
-	case BACKSL|')':	/* should not get here -- must be user */
-	case BACKSL|'}':
-		SETERROR(REG_EPAREN);
-		break;
-	case BACKSL|'1':
-	case BACKSL|'2':
-	case BACKSL|'3':
-	case BACKSL|'4':
-	case BACKSL|'5':
-	case BACKSL|'6':
-	case BACKSL|'7':
-	case BACKSL|'8':
-	case BACKSL|'9':
-		i = (c&~BACKSL) - '0';
-		assert(i < NPAREN);
-		if (p->pend[i] != 0) {
-			assert(i <= p->g->nsub);
-			EMIT(OBACK_, i);
-			assert(p->pbegin[i] != 0);
-			assert(OP(p->strip[p->pbegin[i]]) == OLPAREN);
-			assert(OP(p->strip[p->pend[i]]) == ORPAREN);
-			(void) dupl(p, p->pbegin[i]+1, p->pend[i]);
-			EMIT(O_BACK, i);
-		} else
-			SETERROR(REG_ESUBREG);
-		p->g->backrefs = 1;
-		break;
-	case '*':
-		(void)REQUIRE(starordinary, REG_BADRPT);
-		/* FALLTHROUGH */
-	default:
-		ordinary(p, (char)c);
-		break;
-	}
-
-	if (EAT('*')) {		/* implemented as +? */
-		/* this case does not require the (y|) trick, noKLUDGE */
-		INSERT(OPLUS_, pos);
-		ASTERN(O_PLUS, pos);
-		INSERT(OQUEST_, pos);
-		ASTERN(O_QUEST, pos);
-	} else if (EATTWO('\\', '{')) {
-		count = p_count(p);
-		if (EAT(',')) {
-			if (MORE() && isdigit((uch)PEEK())) {
-				count2 = p_count(p);
-				(void)REQUIRE(count <= count2, REG_BADBR);
-			} else		/* single number with comma */
-				count2 = INFINITY;
-		} else		/* just a single number */
-			count2 = count;
-		repeat(p, pos, count, count2);
-		if (!EATTWO('\\', '}')) {	/* error heuristics */
-			while (MORE() && !SEETWO('\\', '}'))
-				NEXT();
-			(void)REQUIRE(MORE(), REG_EBRACE);
-			SETERROR(REG_BADBR);
-		}
-	} else if (c == '$')     /* $ (but not \$) ends it */
-		return(1);
-
-	return(0);
-}
-
-/*
- - p_count - parse a repetition count
- == static int p_count(register struct parse *p);
- */
-static int			/* the value */
-p_count(p)
-register struct parse *p;
-{
-	register int count = 0;
-	register int ndigits = 0;
-
-	while (MORE() && isdigit((uch)PEEK()) && count <= DUPMAX) {
-		count = count*10 + (GETNEXT() - '0');
-		ndigits++;
-	}
-
-	(void)REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR);
-	return(count);
-}
-
-/*
- - p_bracket - parse a bracketed character list
- == static void p_bracket(register struct parse *p);
- *
- * Note a significant property of this code:  if the allocset() did SETERROR,
- * no set operations are done.
- */
-static void
-p_bracket(p)
-register struct parse *p;
-{
-	register cset *cs = allocset(p);
-	register int invert = 0;
-
-	/* Dept of Truly Sickening Special-Case Kludges */
-	if (p->next + 5 < p->end && strncmp(p->next, "[:<:]]", 6) == 0) {
-		EMIT(OBOW, 0);
-		NEXTn(6);
-		return;
-	}
-	if (p->next + 5 < p->end && strncmp(p->next, "[:>:]]", 6) == 0) {
-		EMIT(OEOW, 0);
-		NEXTn(6);
-		return;
-	}
-
-	if (EAT('^'))
-		invert++;	/* make note to invert set at end */
-	if (EAT(']'))
-		CHadd(cs, ']');
-	else if (EAT('-'))
-		CHadd(cs, '-');
-	while (MORE() && PEEK() != ']' && !SEETWO('-', ']'))
-		p_b_term(p, cs);
-	if (EAT('-'))
-		CHadd(cs, '-');
-	(void)MUSTEAT(']', REG_EBRACK);
-
-	if (p->error != 0)	/* don't mess things up further */
-		return;
-
-	if (p->g->cflags&REG_ICASE) {
-		register int i;
-		register int ci;
-
-		for (i = p->g->csetsize - 1; i >= 0; i--)
-			if (CHIN(cs, i) && isalpha(i)) {
-				ci = othercase(i);
-				if (ci != i)
-					CHadd(cs, ci);
-			}
-		if (cs->multis != NULL)
-			mccase(p, cs);
-	}
-	if (invert) {
-		register int i;
-
-		for (i = p->g->csetsize - 1; i >= 0; i--)
-			if (CHIN(cs, i))
-				CHsub(cs, i);
-			else
-				CHadd(cs, i);
-		if (p->g->cflags&REG_NEWLINE)
-			CHsub(cs, '\n');
-		if (cs->multis != NULL)
-			mcinvert(p, cs);
-	}
-
-	assert(cs->multis == NULL);		/* xxx */
-
-	if (nch(p, cs) == 1) {		/* optimize singleton sets */
-		ordinary(p, firstch(p, cs));
-		freeset(p, cs);
-	} else
-		EMIT(OANYOF, freezeset(p, cs));
-}
-
-/*
- - p_b_term - parse one term of a bracketed character list
- == static void p_b_term(register struct parse *p, register cset *cs);
- */
-static void
-p_b_term(p, cs)
-register struct parse *p;
-register cset *cs;
-{
-	register char c;
-	register char start, finish;
-	register int i;
-
-	/* classify what we've got */
-	switch ((MORE()) ? PEEK() : '\0') {
-	case '[':
-		c = (MORE2()) ? PEEK2() : '\0';
-		break;
-	case '-':
-		SETERROR(REG_ERANGE);
-		return;			/* NOTE RETURN */
-		break;
-	default:
-		c = '\0';
-		break;
-	}
-
-	switch (c) {
-	case ':':		/* character class */
-		NEXT2();
-		(void)REQUIRE(MORE(), REG_EBRACK);
-		c = PEEK();
-		(void)REQUIRE(c != '-' && c != ']', REG_ECTYPE);
-		p_b_cclass(p, cs);
-		(void)REQUIRE(MORE(), REG_EBRACK);
-		(void)REQUIRE(EATTWO(':', ']'), REG_ECTYPE);
-		break;
-	case '=':		/* equivalence class */
-		NEXT2();
-		(void)REQUIRE(MORE(), REG_EBRACK);
-		c = PEEK();
-		(void)REQUIRE(c != '-' && c != ']', REG_ECOLLATE);
-		p_b_eclass(p, cs);
-		(void)REQUIRE(MORE(), REG_EBRACK);
-		(void)REQUIRE(EATTWO('=', ']'), REG_ECOLLATE);
-		break;
-	default:		/* symbol, ordinary character, or range */
-/* xxx revision needed for multichar stuff */
-		start = p_b_symbol(p);
-		if (SEE('-') && MORE2() && PEEK2() != ']') {
-			/* range */
-			NEXT();
-			if (EAT('-'))
-				finish = '-';
-			else
-				finish = p_b_symbol(p);
-		} else
-			finish = start;
-		if (start == finish)
-			CHadd(cs, start);
-		else {
-// remove collate stuff --SDM
-#if 0
-			if (__collate_load_error) {
-				(void)REQUIRE((uch)start <= (uch)finish, REG_ERANGE);
-#endif
-				for (i = (uch)start; i <= (uch)finish; i++)
-					CHadd(cs, i);
-#if 0
-			} else {
-				(void)REQUIRE(__collate_range_cmp(start, finish) <= 0, REG_ERANGE);
-				for (i = CHAR_MIN; i <= CHAR_MAX; i++) {
-					if (   __collate_range_cmp(start, i) <= 0
-					    && __collate_range_cmp(i, finish) <= 0
-					   )
-						CHadd(cs, i);
-				}
-			}
-#endif
-		}
-		break;
-	}
-}
-
-/*
- - p_b_cclass - parse a character-class name and deal with it
- == static void p_b_cclass(register struct parse *p, register cset *cs);
- */
-static void
-p_b_cclass(p, cs)
-register struct parse *p;
-register cset *cs;
-{
-	register int c;
-	register char *sp = p->next;
-	register struct cclass *cp;
-	register size_t len;
-
-	while (MORE() && isalpha((uch)PEEK()))
-		NEXT();
-	len = p->next - sp;
-	for (cp = cclasses; cp->name != NULL; cp++)
-		if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0')
-			break;
-	if (cp->name == NULL) {
-		/* oops, didn't find it */
-		SETERROR(REG_ECTYPE);
-		return;
-	}
-
-	switch (cp->fidx) {
-	case CALNUM:
-		for (c = CHAR_MIN; c <= CHAR_MAX; c++)
-			if (isalnum((uch)c))
-				CHadd(cs, c);
-		break;
-	case CALPHA:
-		for (c = CHAR_MIN; c <= CHAR_MAX; c++)
-			if (isalpha((uch)c))
-				CHadd(cs, c);
-		break;
-	case CBLANK:
-		for (c = CHAR_MIN; c <= CHAR_MAX; c++)
-			if (isblank((uch)c))
-				CHadd(cs, c);
-		break;
-	case CCNTRL:
-		for (c = CHAR_MIN; c <= CHAR_MAX; c++)
-			if (iscntrl((uch)c))
-				CHadd(cs, c);
-		break;
-	case CDIGIT:
-		for (c = CHAR_MIN; c <= CHAR_MAX; c++)
-			if (isdigit((uch)c))
-				CHadd(cs, c);
-		break;
-	case CGRAPH:
-		for (c = CHAR_MIN; c <= CHAR_MAX; c++)
-			if (isgraph((uch)c))
-				CHadd(cs, c);
-		break;
-	case CLOWER:
-		for (c = CHAR_MIN; c <= CHAR_MAX; c++)
-			if (islower((uch)c))
-				CHadd(cs, c);
-		break;
-	case CPRINT:
-		for (c = CHAR_MIN; c <= CHAR_MAX; c++)
-			if (isprint((uch)c))
-				CHadd(cs, c);
-		break;
-	case CPUNCT:
-		for (c = CHAR_MIN; c <= CHAR_MAX; c++)
-			if (ispunct((uch)c))
-				CHadd(cs, c);
-		break;
-	case CSPACE:
-		for (c = CHAR_MIN; c <= CHAR_MAX; c++)
-			if (isspace((uch)c))
-				CHadd(cs, c);
-		break;
-	case CUPPER:
-		for (c = CHAR_MIN; c <= CHAR_MAX; c++)
-			if (isupper((uch)c))
-				CHadd(cs, c);
-		break;
-	case CXDIGIT:
-		for (c = CHAR_MIN; c <= CHAR_MAX; c++)
-			if (isxdigit((uch)c))
-				CHadd(cs, c);
-		break;
-	}
-#if 0
-	for (u = cp->multis; *u != '\0'; u += strlen(u) + 1)
-		MCadd(p, cs, u);
-#endif
-}
-
-/*
- - p_b_eclass - parse an equivalence-class name and deal with it
- == static void p_b_eclass(register struct parse *p, register cset *cs);
- *
- * This implementation is incomplete. xxx
- */
-static void
-p_b_eclass(p, cs)
-register struct parse *p;
-register cset *cs;
-{
-	register char c;
-
-	c = p_b_coll_elem(p, '=');
-	CHadd(cs, c);
-}
-
-/*
- - p_b_symbol - parse a character or [..]ed multicharacter collating symbol
- == static char p_b_symbol(register struct parse *p);
- */
-static char			/* value of symbol */
-p_b_symbol(p)
-register struct parse *p;
-{
-	register char value;
-
-	(void)REQUIRE(MORE(), REG_EBRACK);
-	if (!EATTWO('[', '.'))
-		return(GETNEXT());
-
-	/* collating symbol */
-	value = p_b_coll_elem(p, '.');
-	(void)REQUIRE(EATTWO('.', ']'), REG_ECOLLATE);
-	return(value);
-}
-
-/*
- - p_b_coll_elem - parse a collating-element name and look it up
- == static char p_b_coll_elem(register struct parse *p, int endc);
- */
-static char			/* value of collating element */
-p_b_coll_elem(p, endc)
-register struct parse *p;
-int endc;			/* name ended by endc,']' */
-{
-	register char *sp = p->next;
-	register struct cname *cp;
-	register int len;
-
-	while (MORE() && !SEETWO(endc, ']'))
-		NEXT();
-	if (!MORE()) {
-		SETERROR(REG_EBRACK);
-		return(0);
-	}
-	len = p->next - sp;
-	for (cp = cnames; cp->name != NULL; cp++)
-		if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0')
-			return(cp->code);	/* known name */
-	if (len == 1)
-		return(*sp);	/* single character */
-	SETERROR(REG_ECOLLATE);			/* neither */
-	return(0);
-}
-
-/*
- - othercase - return the case counterpart of an alphabetic
- == static char othercase(int ch);
- */
-static char			/* if no counterpart, return ch */
-othercase(ch)
-int ch;
-{
-	ch = (uch)ch;
-	assert(isalpha(ch));
-	if (isupper(ch))
-		return(tolower(ch));
-	else if (islower(ch))
-		return(toupper(ch));
-	else			/* peculiar, but could happen */
-		return(ch);
-}
-
-/*
- - bothcases - emit a dualcase version of a two-case character
- == static void bothcases(register struct parse *p, int ch);
- *
- * Boy, is this implementation ever a kludge...
- */
-static void
-bothcases(p, ch)
-register struct parse *p;
-int ch;
-{
-	register char *oldnext = p->next;
-	register char *oldend = p->end;
-	char bracket[3];
-
-	ch = (uch)ch;
-	assert(othercase(ch) != ch);	/* p_bracket() would recurse */
-	p->next = bracket;
-	p->end = bracket+2;
-	bracket[0] = ch;
-	bracket[1] = ']';
-	bracket[2] = '\0';
-	p_bracket(p);
-	assert(p->next == bracket+2);
-	p->next = oldnext;
-	p->end = oldend;
-}
-
-/*
- - ordinary - emit an ordinary character
- == static void ordinary(register struct parse *p, register int ch);
- */
-static void
-ordinary(p, ch)
-register struct parse *p;
-register int ch;
-{
-	register cat_t *cap = p->g->categories;
-
-	if ((p->g->cflags&REG_ICASE) && isalpha((uch)ch) && othercase(ch) != ch)
-		bothcases(p, ch);
-	else {
-		EMIT(OCHAR, (uch)ch);
-		if (cap[ch] == 0)
-			cap[ch] = p->g->ncategories++;
-	}
-}
-
-/*
- - nonnewline - emit REG_NEWLINE version of OANY
- == static void nonnewline(register struct parse *p);
- *
- * Boy, is this implementation ever a kludge...
- */
-static void
-nonnewline(p)
-register struct parse *p;
-{
-	register char *oldnext = p->next;
-	register char *oldend = p->end;
-	char bracket[4];
-
-	p->next = bracket;
-	p->end = bracket+3;
-	bracket[0] = '^';
-	bracket[1] = '\n';
-	bracket[2] = ']';
-	bracket[3] = '\0';
-	p_bracket(p);
-	assert(p->next == bracket+3);
-	p->next = oldnext;
-	p->end = oldend;
-}
-
-/*
- - repeat - generate code for a bounded repetition, recursively if needed
- == static void repeat(register struct parse *p, sopno start, int from, int to);
- */
-static void
-repeat(p, start, from, to)
-register struct parse *p;
-sopno start;			/* operand from here to end of strip */
-int from;			/* repeated from this number */
-int to;				/* to this number of times (maybe INFINITY) */
-{
-	register sopno finish = HERE();
-#	define	N	2
-#	define	INF	3
-#	define	REP(f, t)	((f)*8 + (t))
-#	define	MAP(n)	(((n) <= 1) ? (n) : ((n) == INFINITY) ? INF : N)
-	register sopno copy;
-
-	if (p->error != 0)	/* head off possible runaway recursion */
-		return;
-
-	assert(from <= to);
-
-	switch (REP(MAP(from), MAP(to))) {
-	case REP(0, 0):			/* must be user doing this */
-		DROP(finish-start);	/* drop the operand */
-		break;
-	case REP(0, 1):			/* as x{1,1}? */
-	case REP(0, N):			/* as x{1,n}? */
-	case REP(0, INF):		/* as x{1,}? */
-		/* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
-		INSERT(OCH_, start);		/* offset is wrong... */
-		repeat(p, start+1, 1, to);
-		ASTERN(OOR1, start);
-		AHEAD(start);			/* ... fix it */
-		EMIT(OOR2, 0);
-		AHEAD(THERE());
-		ASTERN(O_CH, THERETHERE());
-		break;
-	case REP(1, 1):			/* trivial case */
-		/* done */
-		break;
-	case REP(1, N):			/* as x?x{1,n-1} */
-		/* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
-		INSERT(OCH_, start);
-		ASTERN(OOR1, start);
-		AHEAD(start);
-		EMIT(OOR2, 0);			/* offset very wrong... */
-		AHEAD(THERE());			/* ...so fix it */
-		ASTERN(O_CH, THERETHERE());
-		copy = dupl(p, start+1, finish+1);
-		assert(copy == finish+4);
-		repeat(p, copy, 1, to-1);
-		break;
-	case REP(1, INF):		/* as x+ */
-		INSERT(OPLUS_, start);
-		ASTERN(O_PLUS, start);
-		break;
-	case REP(N, N):			/* as xx{m-1,n-1} */
-		copy = dupl(p, start, finish);
-		repeat(p, copy, from-1, to-1);
-		break;
-	case REP(N, INF):		/* as xx{n-1,INF} */
-		copy = dupl(p, start, finish);
-		repeat(p, copy, from-1, to);
-		break;
-	default:			/* "can't happen" */
-		SETERROR(REG_ASSERT);	/* just in case */
-		break;
-	}
-}
-
-/*
- - seterr - set an error condition
- == static int seterr(register struct parse *p, int e);
- */
-static int			/* useless but makes type checking happy */
-seterr(p, e)
-register struct parse *p;
-int e;
-{
-	if (p->error == 0)	/* keep earliest error condition */
-		p->error = e;
-	p->next = nuls;		/* try to bring things to a halt */
-	p->end = nuls;
-	return(0);		/* make the return value well-defined */
-}
-
-/*
- - allocset - allocate a set of characters for []
- == static cset *allocset(register struct parse *p);
- */
-static cset *
-allocset(p)
-register struct parse *p;
-{
-	register int no = p->g->ncsets++;
-	register size_t nc;
-	register size_t nbytes;
-	register cset *cs;
-	register size_t css = (size_t)p->g->csetsize;
-	register int i;
-
-	if (no >= p->ncsalloc) {	/* need another column of space */
-		p->ncsalloc += CHAR_BIT;
-		nc = p->ncsalloc;
-		assert(nc % CHAR_BIT == 0);
-		nbytes = nc / CHAR_BIT * css;
-		if (p->g->sets == NULL)
-			p->g->sets = (cset *)malloc(nc * sizeof(cset));
-		else
-			p->g->sets = (cset *)reallocf((char *)p->g->sets,
-							nc * sizeof(cset));
-		if (p->g->setbits == NULL)
-			p->g->setbits = (uch *)malloc(nbytes);
-		else {
-			p->g->setbits = (uch *)reallocf((char *)p->g->setbits,
-								nbytes);
-			/* xxx this isn't right if setbits is now NULL */
-			for (i = 0; i < no; i++)
-				p->g->sets[i].ptr = p->g->setbits + css*(i/CHAR_BIT);
-		}
-		if (p->g->sets != NULL && p->g->setbits != NULL)
-			(void) memset((char *)p->g->setbits + (nbytes - css),
-								0, css);
-		else {
-			no = 0;
-			SETERROR(REG_ESPACE);
-			/* caller's responsibility not to do set ops */
-		}
-	}
-
-	assert(p->g->sets != NULL);	/* xxx */
-	cs = &p->g->sets[no];
-	cs->ptr = p->g->setbits + css*((no)/CHAR_BIT);
-	cs->mask = 1 << ((no) % CHAR_BIT);
-	cs->hash = 0;
-	cs->smultis = 0;
-	cs->multis = NULL;
-
-	return(cs);
-}
-
-/*
- - freeset - free a now-unused set
- == static void freeset(register struct parse *p, register cset *cs);
- */
-static void
-freeset(p, cs)
-register struct parse *p;
-register cset *cs;
-{
-	register int i;
-	register cset *top = &p->g->sets[p->g->ncsets];
-	register size_t css = (size_t)p->g->csetsize;
-
-	for (i = 0; i < css; i++)
-		CHsub(cs, i);
-	if (cs == top-1)	/* recover only the easy case */
-		p->g->ncsets--;
-}
-
-/*
- - freezeset - final processing on a set of characters
- == static int freezeset(register struct parse *p, register cset *cs);
- *
- * The main task here is merging identical sets.  This is usually a waste
- * of time (although the hash code minimizes the overhead), but can win
- * big if REG_ICASE is being used.  REG_ICASE, by the way, is why the hash
- * is done using addition rather than xor -- all ASCII [aA] sets xor to
- * the same value!
- */
-static int			/* set number */
-freezeset(p, cs)
-register struct parse *p;
-register cset *cs;
-{
-	register short h = cs->hash;
-	register int i;
-	register cset *top = &p->g->sets[p->g->ncsets];
-	register cset *cs2;
-	register size_t css = (size_t)p->g->csetsize;
-
-	/* look for an earlier one which is the same */
-	for (cs2 = &p->g->sets[0]; cs2 < top; cs2++)
-		if (cs2->hash == h && cs2 != cs) {
-			/* maybe */
-			for (i = 0; i < css; i++)
-				if (!!CHIN(cs2, i) != !!CHIN(cs, i))
-					break;		/* no */
-			if (i == css)
-				break;			/* yes */
-		}
-
-	if (cs2 < top) {	/* found one */
-		freeset(p, cs);
-		cs = cs2;
-	}
-
-	return((int)(cs - p->g->sets));
-}
-
-/*
- - firstch - return first character in a set (which must have at least one)
- == static int firstch(register struct parse *p, register cset *cs);
- */
-static int			/* character; there is no "none" value */
-firstch(p, cs)
-register struct parse *p;
-register cset *cs;
-{
-	register int i;
-	register size_t css = (size_t)p->g->csetsize;
-
-	for (i = 0; i < css; i++)
-		if (CHIN(cs, i))
-			return((char)i);
-	assert(never);
-	return(0);		/* arbitrary */
-}
-
-/*
- - nch - number of characters in a set
- == static int nch(register struct parse *p, register cset *cs);
- */
-static int
-nch(p, cs)
-register struct parse *p;
-register cset *cs;
-{
-	register int i;
-	register size_t css = (size_t)p->g->csetsize;
-	register int n = 0;
-
-	for (i = 0; i < css; i++)
-		if (CHIN(cs, i))
-			n++;
-	return(n);
-}
-
-/*
- - mcadd - add a collating element to a cset
- == static void mcadd(register struct parse *p, register cset *cs, \
- ==	register char *cp);
- */
-static void
-mcadd(p, cs, cp)
-register struct parse *p;
-register cset *cs;
-register char *cp;
-{
-	register size_t oldend = cs->smultis;
-
-	cs->smultis += strlen(cp) + 1;
-	if (cs->multis == NULL)
-		cs->multis = malloc(cs->smultis);
-	else
-		cs->multis = reallocf(cs->multis, cs->smultis);
-	if (cs->multis == NULL) {
-		SETERROR(REG_ESPACE);
-		return;
-	}
-
-	(void) strcpy(cs->multis + oldend - 1, cp);
-	cs->multis[cs->smultis - 1] = '\0';
-}
-
-#if used
-/*
- - mcsub - subtract a collating element from a cset
- == static void mcsub(register cset *cs, register char *cp);
- */
-static void
-mcsub(cs, cp)
-register cset *cs;
-register char *cp;
-{
-	register char *fp = mcfind(cs, cp);
-	register size_t len = strlen(fp);
-
-	assert(fp != NULL);
-	(void) memmove(fp, fp + len + 1,
-				cs->smultis - (fp + len + 1 - cs->multis));
-	cs->smultis -= len;
-
-	if (cs->smultis == 0) {
-		free(cs->multis);
-		cs->multis = NULL;
-		return;
-	}
-
-	cs->multis = reallocf(cs->multis, cs->smultis);
-	assert(cs->multis != NULL);
-}
-
-/*
- - mcin - is a collating element in a cset?
- == static int mcin(register cset *cs, register char *cp);
- */
-static int
-mcin(cs, cp)
-register cset *cs;
-register char *cp;
-{
-	return(mcfind(cs, cp) != NULL);
-}
-
-/*
- - mcfind - find a collating element in a cset
- == static char *mcfind(register cset *cs, register char *cp);
- */
-static char *
-mcfind(cs, cp)
-register cset *cs;
-register char *cp;
-{
-	register char *p;
-
-	if (cs->multis == NULL)
-		return(NULL);
-	for (p = cs->multis; *p != '\0'; p += strlen(p) + 1)
-		if (strcmp(cp, p) == 0)
-			return(p);
-	return(NULL);
-}
-#endif
-
-/*
- - mcinvert - invert the list of collating elements in a cset
- == static void mcinvert(register struct parse *p, register cset *cs);
- *
- * This would have to know the set of possibilities.  Implementation
- * is deferred.
- */
-static void
-mcinvert(p, cs)
-register struct parse *p;
-register cset *cs;
-{
-	assert(cs->multis == NULL);	/* xxx */
-}
-
-/*
- - mccase - add case counterparts of the list of collating elements in a cset
- == static void mccase(register struct parse *p, register cset *cs);
- *
- * This would have to know the set of possibilities.  Implementation
- * is deferred.
- */
-static void
-mccase(p, cs)
-register struct parse *p;
-register cset *cs;
-{
-	assert(cs->multis == NULL);	/* xxx */
-}
-
-/*
- - isinsets - is this character in any sets?
- == static int isinsets(register struct re_guts *g, int c);
- */
-static int			/* predicate */
-isinsets(g, c)
-register struct re_guts *g;
-int c;
-{
-	register uch *col;
-	register int i;
-	register int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
-	register unsigned uc = (uch)c;
-
-	for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize)
-		if (col[uc] != 0)
-			return(1);
-	return(0);
-}
-
-/*
- - samesets - are these two characters in exactly the same sets?
- == static int samesets(register struct re_guts *g, int c1, int c2);
- */
-static int			/* predicate */
-samesets(g, c1, c2)
-register struct re_guts *g;
-int c1;
-int c2;
-{
-	register uch *col;
-	register int i;
-	register int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
-	register unsigned uc1 = (uch)c1;
-	register unsigned uc2 = (uch)c2;
-
-	for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize)
-		if (col[uc1] != col[uc2])
-			return(0);
-	return(1);
-}
-
-/*
- - categorize - sort out character categories
- == static void categorize(struct parse *p, register struct re_guts *g);
- */
-static void
-categorize(p, g)
-struct parse *p;
-register struct re_guts *g;
-{
-	register cat_t *cats = g->categories;
-	register int c;
-	register int c2;
-	register cat_t cat;
-
-	/* avoid making error situations worse */
-	if (p->error != 0)
-		return;
-
-	for (c = CHAR_MIN; c <= CHAR_MAX; c++)
-		if (cats[c] == 0 && isinsets(g, c)) {
-			cat = g->ncategories++;
-			cats[c] = cat;
-			for (c2 = c+1; c2 <= CHAR_MAX; c2++)
-				if (cats[c2] == 0 && samesets(g, c, c2))
-					cats[c2] = cat;
-		}
-}
-
-/*
- - dupl - emit a duplicate of a bunch of sops
- == static sopno dupl(register struct parse *p, sopno start, sopno finish);
- */
-static sopno			/* start of duplicate */
-dupl(p, start, finish)
-register struct parse *p;
-sopno start;			/* from here */
-sopno finish;			/* to this less one */
-{
-	register sopno ret = HERE();
-	register sopno len = finish - start;
-
-	assert(finish >= start);
-	if (len == 0)
-		return(ret);
-	enlarge(p, p->ssize + len);	/* this many unexpected additions */
-	assert(p->ssize >= p->slen + len);
-	(void) memcpy((char *)(p->strip + p->slen),
-		(char *)(p->strip + start), (size_t)len*sizeof(sop));
-	p->slen += len;
-	return(ret);
-}
-
-/*
- - doemit - emit a strip operator
- == static void doemit(register struct parse *p, sop op, size_t opnd);
- *
- * It might seem better to implement this as a macro with a function as
- * hard-case backup, but it's just too big and messy unless there are
- * some changes to the data structures.  Maybe later.
- */
-static void
-doemit(p, op, opnd)
-register struct parse *p;
-sop op;
-size_t opnd;
-{
-	/* avoid making error situations worse */
-	if (p->error != 0)
-		return;
-
-	/* deal with oversize operands ("can't happen", more or less) */
-	assert(opnd < 1<<OPSHIFT);
-
-	/* deal with undersized strip */
-	if (p->slen >= p->ssize)
-		enlarge(p, (p->ssize+1) / 2 * 3);	/* +50% */
-	assert(p->slen < p->ssize);
-
-	/* finally, it's all reduced to the easy case */
-	p->strip[p->slen++] = SOP(op, opnd);
-}
-
-/*
- - doinsert - insert a sop into the strip
- == static void doinsert(register struct parse *p, sop op, size_t opnd, sopno pos);
- */
-static void
-doinsert(p, op, opnd, pos)
-register struct parse *p;
-sop op;
-size_t opnd;
-sopno pos;
-{
-	register sopno sn;
-	register sop s;
-	register int i;
-
-	/* avoid making error situations worse */
-	if (p->error != 0)
-		return;
-
-	sn = HERE();
-	EMIT(op, opnd);		/* do checks, ensure space */
-	assert(HERE() == sn+1);
-	s = p->strip[sn];
-
-	/* adjust paren pointers */
-	assert(pos > 0);
-	for (i = 1; i < NPAREN; i++) {
-		if (p->pbegin[i] >= pos) {
-			p->pbegin[i]++;
-		}
-		if (p->pend[i] >= pos) {
-			p->pend[i]++;
-		}
-	}
-
-	memmove((char *)&p->strip[pos+1], (char *)&p->strip[pos],
-						(HERE()-pos-1)*sizeof(sop));
-	p->strip[pos] = s;
-}
-
-/*
- - dofwd - complete a forward reference
- == static void dofwd(register struct parse *p, sopno pos, sop value);
- */
-static void
-dofwd(p, pos, value)
-register struct parse *p;
-register sopno pos;
-sop value;
-{
-	/* avoid making error situations worse */
-	if (p->error != 0)
-		return;
-
-	assert(value < 1<<OPSHIFT);
-	p->strip[pos] = OP(p->strip[pos]) | value;
-}
-
-/*
- - enlarge - enlarge the strip
- == static void enlarge(register struct parse *p, sopno size);
- */
-static void
-enlarge(p, size)
-register struct parse *p;
-register sopno size;
-{
-	register sop *sp;
-
-	if (p->ssize >= size)
-		return;
-
-	sp = (sop *)realloc(p->strip, size*sizeof(sop));
-	if (sp == NULL) {
-		SETERROR(REG_ESPACE);
-		return;
-	}
-	p->strip = sp;
-	p->ssize = size;
-}
-
-/*
- - stripsnug - compact the strip
- == static void stripsnug(register struct parse *p, register struct re_guts *g);
- */
-static void
-stripsnug(p, g)
-register struct parse *p;
-register struct re_guts *g;
-{
-	g->nstates = p->slen;
-	g->strip = (sop *)realloc((char *)p->strip, p->slen * sizeof(sop));
-	if (g->strip == NULL) {
-		SETERROR(REG_ESPACE);
-		g->strip = p->strip;
-	}
-}
-
-/*
- - findmust - fill in must and mlen with longest mandatory literal string
- == static void findmust(register struct parse *p, register struct re_guts *g);
- *
- * This algorithm could do fancy things like analyzing the operands of |
- * for common subsequences.  Someday.  This code is simple and finds most
- * of the interesting cases.
- *
- * Note that must and mlen got initialized during setup.
- */
-static void
-findmust(p, g)
-struct parse *p;
-register struct re_guts *g;
-{
-	register sop *scan;
-	sop *start;
-	register sop *newstart;
-	register sopno newlen;
-	register sop s;
-	register char *cp;
-	register sopno i;
-	int offset;
-	int cs, mccs;
-
-	/* avoid making error situations worse */
-	if (p->error != 0)
-		return;
-
-	/* Find out if we can handle OANYOF or not */
-	mccs = 0;
-	for (cs = 0; cs < g->ncsets; cs++)
-		if (g->sets[cs].multis != NULL)
-			mccs = 1;
-
-	/* find the longest OCHAR sequence in strip */
-	newlen = 0;
-	offset = 0;
-	g->moffset = 0;
-	scan = g->strip + 1;
-	do {
-		s = *scan++;
-		switch (OP(s)) {
-		case OCHAR:		/* sequence member */
-			if (newlen == 0)		/* new sequence */
-				newstart = scan - 1;
-			newlen++;
-			break;
-		case OPLUS_:		/* things that don't break one */
-		case OLPAREN:
-		case ORPAREN:
-			break;
-		case OQUEST_:		/* things that must be skipped */
-		case OCH_:
-			offset = altoffset(scan, offset, mccs);
-			scan--;
-			do {
-				scan += OPND(s);
-				s = *scan;
-				/* assert() interferes w debug printouts */
-				if (OP(s) != O_QUEST && OP(s) != O_CH &&
-							OP(s) != OOR2) {
-					g->iflags |= BAD;
-					return;
-				}
-			} while (OP(s) != O_QUEST && OP(s) != O_CH);
-			/* fallthrough */
-		case OBOW:		/* things that break a sequence */
-		case OEOW:
-		case OBOL:
-		case OEOL:
-		case O_QUEST:
-		case O_CH:
-		case OEND:
-			if (newlen > g->mlen) {		/* ends one */
-				start = newstart;
-				g->mlen = newlen;
-				if (offset > -1) {
-					g->moffset += offset;
-					offset = newlen;
-				} else
-					g->moffset = offset;
-			} else {
-				if (offset > -1)
-					offset += newlen;
-			}
-			newlen = 0;
-			break;
-		case OANY:
-			if (newlen > g->mlen) {		/* ends one */
-				start = newstart;
-				g->mlen = newlen;
-				if (offset > -1) {
-					g->moffset += offset;
-					offset = newlen;
-				} else
-					g->moffset = offset;
-			} else {
-				if (offset > -1)
-					offset += newlen;
-			}
-			if (offset > -1)
-				offset++;
-			newlen = 0;
-			break;
-		case OANYOF:		/* may or may not invalidate offset */
-			/* First, everything as OANY */
-			if (newlen > g->mlen) {		/* ends one */
-				start = newstart;
-				g->mlen = newlen;
-				if (offset > -1) {
-					g->moffset += offset;
-					offset = newlen;
-				} else
-					g->moffset = offset;
-			} else {
-				if (offset > -1)
-					offset += newlen;
-			}
-			if (offset > -1)
-				offset++;
-			newlen = 0;
-			/* And, now, if we found out we can't deal with
-			 * it, make offset = -1.
-			 */
-			if (mccs)
-				offset = -1;
-			break;
-		default:
-			/* Anything here makes it impossible or too hard
-			 * to calculate the offset -- so we give up;
-			 * save the last known good offset, in case the
-			 * must sequence doesn't occur later.
-			 */
-			if (newlen > g->mlen) {		/* ends one */
-				start = newstart;
-				g->mlen = newlen;
-				if (offset > -1)
-					g->moffset += offset;
-				else
-					g->moffset = offset;
-			}
-			offset = -1;
-			newlen = 0;
-			break;
-		}
-	} while (OP(s) != OEND);
-
-	if (g->mlen == 0) {		/* there isn't one */
-		g->moffset = -1;
-		return;
-	}
-
-	/* turn it into a character string */
-	g->must = malloc((size_t)g->mlen + 1);
-	if (g->must == NULL) {		/* argh; just forget it */
-		g->mlen = 0;
-		g->moffset = -1;
-		return;
-	}
-	cp = g->must;
-	scan = start;
-	for (i = g->mlen; i > 0; i--) {
-		while (OP(s = *scan++) != OCHAR)
-			continue;
-		assert(cp < g->must + g->mlen);
-		*cp++ = (char)OPND(s);
-	}
-	assert(cp == g->must + g->mlen);
-	*cp++ = '\0';		/* just on general principles */
-}
-
-/*
- - altoffset - choose biggest offset among multiple choices
- == static int altoffset(sop *scan, int offset, int mccs);
- *
- * Compute, recursively if necessary, the largest offset among multiple
- * re paths.
- */
-static int
-altoffset(scan, offset, mccs)
-sop *scan;
-int offset;
-int mccs;
-{
-	int largest;
-	int try;
-	sop s;
-
-	/* If we gave up already on offsets, return */
-	if (offset == -1)
-		return -1;
-
-	largest = 0;
-	try = 0;
-	s = *scan++;
-	while (OP(s) != O_QUEST && OP(s) != O_CH) {
-		switch (OP(s)) {
-		case OOR1:
-			if (try > largest)
-				largest = try;
-			try = 0;
-			break;
-		case OQUEST_:
-		case OCH_:
-			try = altoffset(scan, try, mccs);
-			if (try == -1)
-				return -1;
-			scan--;
-			do {
-				scan += OPND(s);
-				s = *scan;
-				if (OP(s) != O_QUEST && OP(s) != O_CH &&
-							OP(s) != OOR2)
-					return -1;
-			} while (OP(s) != O_QUEST && OP(s) != O_CH);
-			/* We must skip to the next position, or we'll
-			 * leave altoffset() too early.
-			 */
-			scan++;
-			break;
-		case OANYOF:
-			if (mccs)
-				return -1;
-		case OCHAR:
-		case OANY:
-			try++;
-		case OBOW:
-		case OEOW:
-		case OLPAREN:
-		case ORPAREN:
-		case OOR2:
-			break;
-		default:
-			try = -1;
-			break;
-		}
-		if (try == -1)
-			return -1;
-		s = *scan++;
-	}
-
-	if (try > largest)
-		largest = try;
-
-	return largest+offset;
-}
-
-/*
- - computejumps - compute char jumps for BM scan
- == static void computejumps(register struct parse *p, register struct re_guts *g);
- *
- * This algorithm assumes g->must exists and is has size greater than
- * zero. It's based on the algorithm found on Computer Algorithms by
- * Sara Baase.
- *
- * A char jump is the number of characters one needs to jump based on
- * the value of the character from the text that was mismatched.
- */
-static void
-computejumps(p, g)
-struct parse *p;
-struct re_guts *g;
-{
-	int ch;
-	int mindex;
-
-	/* Avoid making errors worse */
-	if (p->error != 0)
-		return;
-
-	g->charjump = (int*) malloc((NC + 1) * sizeof(int));
-	if (g->charjump == NULL)	/* Not a fatal error */
-		return;
-	/* Adjust for signed chars, if necessary */
-	g->charjump = &g->charjump[-(CHAR_MIN)];
-
-	/* If the character does not exist in the pattern, the jump
-	 * is equal to the number of characters in the pattern.
-	 */
-	for (ch = CHAR_MIN; ch < (CHAR_MAX + 1); ch++)
-		g->charjump[ch] = g->mlen;
-
-	/* If the character does exist, compute the jump that would
-	 * take us to the last character in the pattern equal to it
-	 * (notice that we match right to left, so that last character
-	 * is the first one that would be matched).
-	 */
-	for (mindex = 0; mindex < g->mlen; mindex++)
-		g->charjump[g->must[mindex]] = g->mlen - mindex - 1;
-}
-
-/*
- - computematchjumps - compute match jumps for BM scan
- == static void computematchjumps(register struct parse *p, register struct re_guts *g);
- *
- * This algorithm assumes g->must exists and is has size greater than
- * zero. It's based on the algorithm found on Computer Algorithms by
- * Sara Baase.
- *
- * A match jump is the number of characters one needs to advance based
- * on the already-matched suffix.
- * Notice that all values here are minus (g->mlen-1), because of the way
- * the search algorithm works.
- */
-static void
-computematchjumps(p, g)
-struct parse *p;
-struct re_guts *g;
-{
-	int mindex;		/* General "must" iterator */
-	int suffix;		/* Keeps track of matching suffix */
-	int ssuffix;		/* Keeps track of suffixes' suffix */
-	int* pmatches;		/* pmatches[k] points to the next i
-				 * such that i+1...mlen is a substring
-				 * of k+1...k+mlen-i-1
-				 */
-
-	/* Avoid making errors worse */
-	if (p->error != 0)
-		return;
-
-	pmatches = (int*) malloc(g->mlen * sizeof(unsigned int));
-	if (pmatches == NULL) {
-		g->matchjump = NULL;
-		return;
-	}
-
-	g->matchjump = (int*) malloc(g->mlen * sizeof(unsigned int));
-	if (g->matchjump == NULL)	/* Not a fatal error */
-		return;
-
-	/* Set maximum possible jump for each character in the pattern */
-	for (mindex = 0; mindex < g->mlen; mindex++)
-		g->matchjump[mindex] = 2*g->mlen - mindex - 1;
-
-	/* Compute pmatches[] */
-	for (mindex = g->mlen - 1, suffix = g->mlen; mindex >= 0;
-	    mindex--, suffix--) {
-		pmatches[mindex] = suffix;
-
-		/* If a mismatch is found, interrupting the substring,
-		 * compute the matchjump for that position. If no
-		 * mismatch is found, then a text substring mismatched
-		 * against the suffix will also mismatch against the
-		 * substring.
-		 */
-		while (suffix < g->mlen
-		    && g->must[mindex] != g->must[suffix]) {
-			g->matchjump[suffix] = MIN(g->matchjump[suffix],
-			    g->mlen - mindex - 1);
-			suffix = pmatches[suffix];
-		}
-	}
-
-	/* Compute the matchjump up to the last substring found to jump
-	 * to the beginning of the largest must pattern prefix matching
-	 * it's own suffix.
-	 */
-	for (mindex = 0; mindex <= suffix; mindex++)
-		g->matchjump[mindex] = MIN(g->matchjump[mindex],
-		    g->mlen + suffix - mindex);
-
-        ssuffix = pmatches[suffix];
-        while (suffix < g->mlen) {
-                while (suffix <= ssuffix && suffix < g->mlen) {
-                        g->matchjump[suffix] = MIN(g->matchjump[suffix],
-			    g->mlen + ssuffix - suffix);
-                        suffix++;
-                }
-		if (suffix < g->mlen)
-                	ssuffix = pmatches[ssuffix];
-        }
-
-	free(pmatches);
-}
-
-/*
- - pluscount - count + nesting
- == static sopno pluscount(register struct parse *p, register struct re_guts *g);
- */
-static sopno			/* nesting depth */
-pluscount(p, g)
-struct parse *p;
-register struct re_guts *g;
-{
-	register sop *scan;
-	register sop s;
-	register sopno plusnest = 0;
-	register sopno maxnest = 0;
-
-	if (p->error != 0)
-		return(0);	/* there may not be an OEND */
-
-	scan = g->strip + 1;
-	do {
-		s = *scan++;
-		switch (OP(s)) {
-		case OPLUS_:
-			plusnest++;
-			break;
-		case O_PLUS:
-			if (plusnest > maxnest)
-				maxnest = plusnest;
-			plusnest--;
-			break;
-		}
-	} while (OP(s) != OEND);
-	if (plusnest != 0)
-		g->iflags |= BAD;
-	return(maxnest);
-}
diff --git a/cbits/regerror.c b/cbits/regerror.c
deleted file mode 100644
--- a/cbits/regerror.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993, 1994 Henry Spencer.
- * Copyright (c) 1992, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Henry Spencer.
- *
- * 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.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- *
- *	@(#)regerror.c	8.4 (Berkeley) 3/20/94
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)regerror.c	8.4 (Berkeley) 3/20/94";
-#endif /* LIBC_SCCS and not lint */
-
-#include <sys/types.h>
-#include <stdio.h>
-#include <string.h>
-#include <limits.h>
-#include <stdlib.h>
-#include "regex.h"
-
-#include "utils.h"
-
-/* ========= begin header generated by ./mkh ========= */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* === regerror.c === */
-static char *regatoi (const regex_t *preg, char *localbuf);
-
-#ifdef __cplusplus
-}
-#endif
-/* ========= end header generated by ./mkh ========= */
-/*
- = #define	REG_NOMATCH	 1
- = #define	REG_BADPAT	 2
- = #define	REG_ECOLLATE	 3
- = #define	REG_ECTYPE	 4
- = #define	REG_EESCAPE	 5
- = #define	REG_ESUBREG	 6
- = #define	REG_EBRACK	 7
- = #define	REG_EPAREN	 8
- = #define	REG_EBRACE	 9
- = #define	REG_BADBR	10
- = #define	REG_ERANGE	11
- = #define	REG_ESPACE	12
- = #define	REG_BADRPT	13
- = #define	REG_EMPTY	14
- = #define	REG_ASSERT	15
- = #define	REG_INVARG	16
- = #define	REG_ATOI	255	// convert name to number (!)
- = #define	REG_ITOA	0400	// convert number to name (!)
- */
-static struct rerr {
-	int code;
-	char *name;
-	char *explain;
-} rerrs[] = {
-	{REG_NOMATCH,	"REG_NOMATCH",	"regexec() failed to match"},
-	{REG_BADPAT,	"REG_BADPAT",	"invalid regular expression"},
-	{REG_ECOLLATE,	"REG_ECOLLATE",	"invalid collating element"},
-	{REG_ECTYPE,	"REG_ECTYPE",	"invalid character class"},
-	{REG_EESCAPE,	"REG_EESCAPE",	"trailing backslash (\\)"},
-	{REG_ESUBREG,	"REG_ESUBREG",	"invalid backreference number"},
-	{REG_EBRACK,	"REG_EBRACK",	"brackets ([ ]) not balanced"},
-	{REG_EPAREN,	"REG_EPAREN",	"parentheses not balanced"},
-	{REG_EBRACE,	"REG_EBRACE",	"braces not balanced"},
-	{REG_BADBR,	"REG_BADBR",	"invalid repetition count(s)"},
-	{REG_ERANGE,	"REG_ERANGE",	"invalid character range"},
-	{REG_ESPACE,	"REG_ESPACE",	"out of memory"},
-	{REG_BADRPT,	"REG_BADRPT",	"repetition-operator operand invalid"},
-	{REG_EMPTY,	"REG_EMPTY",	"empty (sub)expression"},
-	{REG_ASSERT,	"REG_ASSERT",	"\"can't happen\" -- you found a bug"},
-	{REG_INVARG,	"REG_INVARG",	"invalid argument to regex routine"},
-	{0,		"",		"*** unknown regexp error code ***"}
-};
-
-/*
- - regerror - the interface to error numbers
- = extern size_t regerror(int, const regex_t *, char *, size_t);
- */
-/* ARGSUSED */
-size_t
-regerror(errcode, preg, errbuf, errbuf_size)
-int errcode;
-const regex_t *preg;
-char *errbuf;
-size_t errbuf_size;
-{
-	register struct rerr *r;
-	register size_t len;
-	register int target = errcode &~ REG_ITOA;
-	register char *s;
-	char convbuf[50];
-
-	if (errcode == REG_ATOI)
-		s = regatoi(preg, convbuf);
-	else {
-		for (r = rerrs; r->code != 0; r++)
-			if (r->code == target)
-				break;
-
-		if (errcode&REG_ITOA) {
-			if (r->code != 0)
-				(void) strcpy(convbuf, r->name);
-			else
-				sprintf(convbuf, "REG_0x%x", target);
-			assert(strlen(convbuf) < sizeof(convbuf));
-			s = convbuf;
-		} else
-			s = r->explain;
-	}
-
-	len = strlen(s) + 1;
-	if (errbuf_size > 0) {
-		if (errbuf_size > len)
-			(void) strcpy(errbuf, s);
-		else {
-			(void) strncpy(errbuf, s, errbuf_size-1);
-			errbuf[errbuf_size-1] = '\0';
-		}
-	}
-
-	return(len);
-}
-
-/*
- - regatoi - internal routine to implement REG_ATOI
- == static char *regatoi(const regex_t *preg, char *localbuf);
- */
-static char *
-regatoi(preg, localbuf)
-const regex_t *preg;
-char *localbuf;
-{
-	register struct rerr *r;
-
-	for (r = rerrs; r->code != 0; r++)
-		if (strcmp(r->name, preg->re_endp) == 0)
-			break;
-	if (r->code == 0)
-		return("0");
-
-	sprintf(localbuf, "%d", r->code);
-	return(localbuf);
-}
diff --git a/cbits/regex.h b/cbits/regex.h
deleted file mode 100644
--- a/cbits/regex.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*-
- * Copyright (c) 1992 Henry Spencer.
- * Copyright (c) 1992, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Henry Spencer of the University of Toronto.
- *
- * 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.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- *
- *	@(#)regex.h	8.2 (Berkeley) 1/3/94
- */
-
-#ifndef _REGEX_H_
-#define	_REGEX_H_
-
-#include <sys/types.h>
-
-/* types */
-typedef off_t regoff_t;
-
-typedef struct {
-	int re_magic;
-	size_t re_nsub;		/* number of parenthesized subexpressions */
-	__const char *re_endp;	/* end pointer for REG_PEND */
-	struct re_guts *re_g;	/* none of your business :-) */
-} regex_t;
-
-typedef struct {
-	regoff_t rm_so;		/* start of match */
-	regoff_t rm_eo;		/* end of match */
-} regmatch_t;
-
-/* regcomp() flags */
-#define	REG_BASIC	0000
-#define	REG_EXTENDED	0001
-#define	REG_ICASE	0002
-#define	REG_NOSUB	0004
-#define	REG_NEWLINE	0010
-#define	REG_NOSPEC	0020
-#define	REG_PEND	0040
-#define	REG_DUMP	0200
-
-/* regerror() flags */
-#define	REG_NOMATCH	 1
-#define	REG_BADPAT	 2
-#define	REG_ECOLLATE	 3
-#define	REG_ECTYPE	 4
-#define	REG_EESCAPE	 5
-#define	REG_ESUBREG	 6
-#define	REG_EBRACK	 7
-#define	REG_EPAREN	 8
-#define	REG_EBRACE	 9
-#define	REG_BADBR	10
-#define	REG_ERANGE	11
-#define	REG_ESPACE	12
-#define	REG_BADRPT	13
-#define	REG_EMPTY	14
-#define	REG_ASSERT	15
-#define	REG_INVARG	16
-#define	REG_ATOI	255	/* convert name to number (!) */
-#define	REG_ITOA	0400	/* convert number to name (!) */
-
-/* regexec() flags */
-#define	REG_NOTBOL	00001
-#define	REG_NOTEOL	00002
-#define	REG_STARTEND	00004
-#define	REG_TRACE	00400	/* tracing of execution */
-#define	REG_LARGE	01000	/* force large representation */
-#define	REG_BACKR	02000	/* force use of backref code */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int	regcomp (regex_t *, const char *, int);
-size_t	regerror (int, const regex_t *, char *, size_t);
-int	regexec (const regex_t *,
-	    const char *, size_t, regmatch_t [], int);
-void	regfree (regex_t *);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* !_REGEX_H_ */
diff --git a/cbits/regex2.h b/cbits/regex2.h
deleted file mode 100644
--- a/cbits/regex2.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993, 1994 Henry Spencer.
- * Copyright (c) 1992, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Henry Spencer.
- *
- * 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.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- *
- *	@(#)regex2.h	8.4 (Berkeley) 3/20/94
- *
- * $FreeBSD: src/lib/libc/regex/regex2.h,v 1.3.6.1 2000/07/31 06:30:37 dcs Exp $
- */
-
-/*
- * First, the stuff that ends up in the outside-world include file
- = typedef off_t regoff_t;
- = typedef struct {
- = 	int re_magic;
- = 	size_t re_nsub;		// number of parenthesized subexpressions
- = 	const char *re_endp;	// end pointer for REG_PEND
- = 	struct re_guts *re_g;	// none of your business :-)
- = } regex_t;
- = typedef struct {
- = 	regoff_t rm_so;		// start of match
- = 	regoff_t rm_eo;		// end of match
- = } regmatch_t;
- */
-/*
- * internals of regex_t
- */
-#define	MAGIC1	((('r'^0200)<<8) | 'e')
-
-/*
- * The internal representation is a *strip*, a sequence of
- * operators ending with an endmarker.  (Some terminology etc. is a
- * historical relic of earlier versions which used multiple strips.)
- * Certain oddities in the representation are there to permit running
- * the machinery backwards; in particular, any deviation from sequential
- * flow must be marked at both its source and its destination.  Some
- * fine points:
- *
- * - OPLUS_ and O_PLUS are *inside* the loop they create.
- * - OQUEST_ and O_QUEST are *outside* the bypass they create.
- * - OCH_ and O_CH are *outside* the multi-way branch they create, while
- *   OOR1 and OOR2 are respectively the end and the beginning of one of
- *   the branches.  Note that there is an implicit OOR2 following OCH_
- *   and an implicit OOR1 preceding O_CH.
- *
- * In state representations, an operator's bit is on to signify a state
- * immediately *preceding* "execution" of that operator.
- */
-typedef unsigned long sop;	/* strip operator */
-typedef long sopno;
-#define	OPRMASK	0xf8000000L
-#define	OPDMASK	0x07ffffffL
-#define	OPSHIFT	((unsigned)27)
-#define	OP(n)	((n)&OPRMASK)
-#define	OPND(n)	((n)&OPDMASK)
-#define	SOP(op, opnd)	((op)|(opnd))
-/* operators			   meaning	operand			*/
-/*						(back, fwd are offsets)	*/
-#define	OEND	(1L<<OPSHIFT)	/* endmarker	-			*/
-#define	OCHAR	(2L<<OPSHIFT)	/* character	unsigned char		*/
-#define	OBOL	(3L<<OPSHIFT)	/* left anchor	-			*/
-#define	OEOL	(4L<<OPSHIFT)	/* right anchor	-			*/
-#define	OANY	(5L<<OPSHIFT)	/* .		-			*/
-#define	OANYOF	(6L<<OPSHIFT)	/* [...]	set number		*/
-#define	OBACK_	(7L<<OPSHIFT)	/* begin \d	paren number		*/
-#define	O_BACK	(8L<<OPSHIFT)	/* end \d	paren number		*/
-#define	OPLUS_	(9L<<OPSHIFT)	/* + prefix	fwd to suffix		*/
-#define	O_PLUS	(10L<<OPSHIFT)	/* + suffix	back to prefix		*/
-#define	OQUEST_	(11L<<OPSHIFT)	/* ? prefix	fwd to suffix		*/
-#define	O_QUEST	(12L<<OPSHIFT)	/* ? suffix	back to prefix		*/
-#define	OLPAREN	(13L<<OPSHIFT)	/* (		fwd to )		*/
-#define	ORPAREN	(14L<<OPSHIFT)	/* )		back to (		*/
-#define	OCH_	(15L<<OPSHIFT)	/* begin choice	fwd to OOR2		*/
-#define	OOR1	(16L<<OPSHIFT)	/* | pt. 1	back to OOR1 or OCH_	*/
-#define	OOR2	(17L<<OPSHIFT)	/* | pt. 2	fwd to OOR2 or O_CH	*/
-#define	O_CH	(18L<<OPSHIFT)	/* end choice	back to OOR1		*/
-#define	OBOW	(19L<<OPSHIFT)	/* begin word	-			*/
-#define	OEOW	(20L<<OPSHIFT)	/* end word	-			*/
-
-/*
- * Structure for [] character-set representation.  Character sets are
- * done as bit vectors, grouped 8 to a byte vector for compactness.
- * The individual set therefore has both a pointer to the byte vector
- * and a mask to pick out the relevant bit of each byte.  A hash code
- * simplifies testing whether two sets could be identical.
- *
- * This will get trickier for multicharacter collating elements.  As
- * preliminary hooks for dealing with such things, we also carry along
- * a string of multi-character elements, and decide the size of the
- * vectors at run time.
- */
-typedef struct {
-	uch *ptr;		/* -> uch [csetsize] */
-	uch mask;		/* bit within array */
-	short hash;             /* hash code */
-	size_t smultis;
-	char *multis;		/* -> char[smulti]  ab\0cd\0ef\0\0 */
-} cset;
-/* note that CHadd and CHsub are unsafe, and CHIN doesn't yield 0/1 */
-#define CHadd(cs, c)    ((cs)->ptr[(uch)(c)] |= (cs)->mask, (cs)->hash += (uch)(c))
-#define CHsub(cs, c)    ((cs)->ptr[(uch)(c)] &= ~(cs)->mask, (cs)->hash -= (uch)(c))
-#define	CHIN(cs, c)	((cs)->ptr[(uch)(c)] & (cs)->mask)
-#define	MCadd(p, cs, cp)	mcadd(p, cs, cp)	/* regcomp() internal fns */
-#define	MCsub(p, cs, cp)	mcsub(p, cs, cp)
-#define	MCin(p, cs, cp)	mcin(p, cs, cp)
-
-/* stuff for character categories */
-typedef unsigned char cat_t;
-
-/*
- * main compiled-expression structure
- */
-struct re_guts {
-	int magic;
-#		define	MAGIC2	((('R'^0200)<<8)|'E')
-	sop *strip;		/* malloced area for strip */
-	int csetsize;		/* number of bits in a cset vector */
-	int ncsets;		/* number of csets in use */
-	cset *sets;		/* -> cset [ncsets] */
-	uch *setbits;		/* -> uch[csetsize][ncsets/CHAR_BIT] */
-	int cflags;		/* copy of regcomp() cflags argument */
-	sopno nstates;		/* = number of sops */
-	sopno firststate;	/* the initial OEND (normally 0) */
-	sopno laststate;	/* the final OEND */
-	int iflags;		/* internal flags */
-#		define	USEBOL	01	/* used ^ */
-#		define	USEEOL	02	/* used $ */
-#		define	BAD	04	/* something wrong */
-	int nbol;		/* number of ^ used */
-	int neol;		/* number of $ used */
-	int ncategories;	/* how many character categories */
-	cat_t *categories;	/* ->catspace[-CHAR_MIN] */
-	char *must;		/* match must contain this string */
-	int moffset;		/* latest point at which must may be located */
-	int *charjump;		/* Boyer-Moore char jump table */
-	int *matchjump;		/* Boyer-Moore match jump table */
-	int mlen;		/* length of must */
-	size_t nsub;		/* copy of re_nsub */
-	int backrefs;		/* does it use back references? */
-	sopno nplus;		/* how deep does it nest +s? */
-	/* catspace must be last */
-	cat_t catspace[1];	/* actually [NC] */
-};
-
-/* misc utilities */
-#define	OUT	(CHAR_MAX+1)	/* a non-character value */
-#define ISWORD(c)       (isalnum((uch)(c)) || (c) == '_')
diff --git a/cbits/regexec.c b/cbits/regexec.c
deleted file mode 100644
--- a/cbits/regexec.c
+++ /dev/null
@@ -1,181 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993, 1994 Henry Spencer.
- * Copyright (c) 1992, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Henry Spencer.
- *
- * 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.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- *
- *	@(#)regexec.c	8.3 (Berkeley) 3/20/94
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)regexec.c	8.3 (Berkeley) 3/20/94";
-#endif /* LIBC_SCCS and not lint */
-
-/*
- * the outer shell of regexec()
- *
- * This file includes engine.c *twice*, after muchos fiddling with the
- * macros that code uses.  This lets the same code operate on two different
- * representations for state sets.
- */
-#include <sys/types.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-#include <ctype.h>
-#include "regex.h"
-
-#include "utils.h"
-#include "regex2.h"
-
-static int nope = 0;		/* for use in asserts; shuts lint up */
-
-/* macros for manipulating states, small version */
-#define	states	long
-#define	states1	states		/* for later use in regexec() decision */
-#define	CLEAR(v)	((v) = 0)
-#define	SET0(v, n)	((v) &= ~((unsigned long)1 << (n)))
-#define	SET1(v, n)	((v) |= (unsigned long)1 << (n))
-#define	ISSET(v, n)	(((v) & ((unsigned long)1 << (n))) != 0)
-#define	ASSIGN(d, s)	((d) = (s))
-#define	EQ(a, b)	((a) == (b))
-#define	STATEVARS	long dummy	/* dummy version */
-#define	STATESETUP(m, n)	/* nothing */
-#define	STATETEARDOWN(m)	/* nothing */
-#define	SETUP(v)	((v) = 0)
-#define	onestate	long
-#define	INIT(o, n)	((o) = (unsigned long)1 << (n))
-#define	INC(o)	((o) <<= 1)
-#define	ISSTATEIN(v, o)	(((v) & (o)) != 0)
-/* some abbreviations; note that some of these know variable names! */
-/* do "if I'm here, I can also be there" etc without branches */
-#define	FWD(dst, src, n)	((dst) |= ((unsigned long)(src)&(here)) << (n))
-#define	BACK(dst, src, n)	((dst) |= ((unsigned long)(src)&(here)) >> (n))
-#define	ISSETBACK(v, n)	(((v) & ((unsigned long)here >> (n))) != 0)
-/* function names */
-#define SNAMES			/* engine.c looks after details */
-
-#include "engine.c"
-
-/* now undo things */
-#undef	states
-#undef	CLEAR
-#undef	SET0
-#undef	SET1
-#undef	ISSET
-#undef	ASSIGN
-#undef	EQ
-#undef	STATEVARS
-#undef	STATESETUP
-#undef	STATETEARDOWN
-#undef	SETUP
-#undef	onestate
-#undef	INIT
-#undef	INC
-#undef	ISSTATEIN
-#undef	FWD
-#undef	BACK
-#undef	ISSETBACK
-#undef	SNAMES
-
-/* macros for manipulating states, large version */
-#define	states	char *
-#define	CLEAR(v)	memset(v, 0, m->g->nstates)
-#define	SET0(v, n)	((v)[n] = 0)
-#define	SET1(v, n)	((v)[n] = 1)
-#define	ISSET(v, n)	((v)[n])
-#define	ASSIGN(d, s)	memcpy(d, s, m->g->nstates)
-#define	EQ(a, b)	(memcmp(a, b, m->g->nstates) == 0)
-#define	STATEVARS	long vn; char *space
-#define	STATESETUP(m, nv)	{ (m)->space = malloc((nv)*(m)->g->nstates); \
-				if ((m)->space == NULL) return(REG_ESPACE); \
-				(m)->vn = 0; }
-#define	STATETEARDOWN(m)	{ free((m)->space); }
-#define	SETUP(v)	((v) = &m->space[m->vn++ * m->g->nstates])
-#define	onestate	long
-#define	INIT(o, n)	((o) = (n))
-#define	INC(o)	((o)++)
-#define	ISSTATEIN(v, o)	((v)[o])
-/* some abbreviations; note that some of these know variable names! */
-/* do "if I'm here, I can also be there" etc without branches */
-#define	FWD(dst, src, n)	((dst)[here+(n)] |= (src)[here])
-#define	BACK(dst, src, n)	((dst)[here-(n)] |= (src)[here])
-#define	ISSETBACK(v, n)	((v)[here - (n)])
-/* function names */
-#define	LNAMES			/* flag */
-
-#include "engine.c"
-
-/*
- - regexec - interface for matching
- = extern int regexec(const regex_t *, const char *, size_t, \
- =					regmatch_t [], int);
- = #define	REG_NOTBOL	00001
- = #define	REG_NOTEOL	00002
- = #define	REG_STARTEND	00004
- = #define	REG_TRACE	00400	// tracing of execution
- = #define	REG_LARGE	01000	// force large representation
- = #define	REG_BACKR	02000	// force use of backref code
- *
- * We put this here so we can exploit knowledge of the state representation
- * when choosing which matcher to call.  Also, by this point the matchers
- * have been prototyped.
- */
-int				/* 0 success, REG_NOMATCH failure */
-regexec(preg, string, nmatch, pmatch, eflags)
-const regex_t *preg;
-const char *string;
-size_t nmatch;
-regmatch_t pmatch[];
-int eflags;
-{
-	register struct re_guts *g = preg->re_g;
-#ifdef REDEBUG
-#	define	GOODFLAGS(f)	(f)
-#else
-#	define	GOODFLAGS(f)	((f)&(REG_NOTBOL|REG_NOTEOL|REG_STARTEND))
-#endif
-
-	if (preg->re_magic != MAGIC1 || g->magic != MAGIC2)
-		return(REG_BADPAT);
-	assert(!(g->iflags&BAD));
-	if (g->iflags&BAD)		/* backstop for no-debug case */
-		return(REG_BADPAT);
-	eflags = GOODFLAGS(eflags);
-
-	if (g->nstates <= CHAR_BIT*sizeof(states1) && !(eflags&REG_LARGE))
-		return(smatcher(g, (char *)string, nmatch, pmatch, eflags));
-	else
-		return(lmatcher(g, (char *)string, nmatch, pmatch, eflags));
-}
diff --git a/cbits/regfree.c b/cbits/regfree.c
deleted file mode 100644
--- a/cbits/regfree.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993, 1994 Henry Spencer.
- * Copyright (c) 1992, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Henry Spencer.
- *
- * 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.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- *
- *	@(#)regfree.c	8.3 (Berkeley) 3/20/94
- *
- * $FreeBSD: src/lib/libc/regex/regfree.c,v 1.1.1.1.14.1 2000/07/31 06:30:37 dcs Exp $
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)regfree.c	8.3 (Berkeley) 3/20/94";
-#endif /* LIBC_SCCS and not lint */
-
-#include <sys/types.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-#include "regex.h"
-
-#include "utils.h"
-#include "regex2.h"
-
-/*
- - regfree - free everything
- = extern void regfree(regex_t *);
- */
-void
-regfree(preg)
-regex_t *preg;
-{
-	register struct re_guts *g;
-
-	if (preg->re_magic != MAGIC1)	/* oops */
-		return;			/* nice to complain, but hard */
-
-	g = preg->re_g;
-	if (g == NULL || g->magic != MAGIC2)	/* oops again */
-		return;
-	preg->re_magic = 0;		/* mark it invalid */
-	g->magic = 0;			/* mark it invalid */
-
-	if (g->strip != NULL)
-		free((char *)g->strip);
-	if (g->sets != NULL)
-		free((char *)g->sets);
-	if (g->setbits != NULL)
-		free((char *)g->setbits);
-	if (g->must != NULL)
-		free(g->must);
-	if (g->charjump != NULL)
-		free(&g->charjump[CHAR_MIN]);
-	if (g->matchjump != NULL)
-		free(g->matchjump);
-	free((char *)g);
-}
diff --git a/cbits/utils.h b/cbits/utils.h
deleted file mode 100644
--- a/cbits/utils.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993, 1994 Henry Spencer.
- * Copyright (c) 1992, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Henry Spencer.
- *
- * 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.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- *
- *	@(#)utils.h	8.3 (Berkeley) 3/20/94
- */
-
-/* Added by SDM 15/2/2002: apparently mingw doesn't define this constant */
-#ifndef _POSIX2_RE_DUP_MAX
-#define _POSIX2_RE_DUP_MAX 255
-#endif
-
-/* utility definitions */
-#define	DUPMAX		_POSIX2_RE_DUP_MAX	/* xxx is this right? */
-#define	INFINITY	(DUPMAX + 1)
-#define	NC		(CHAR_MAX - CHAR_MIN + 1)
-typedef unsigned char uch;
-
-/* switch off assertions (if not already off) if no REDEBUG */
-#ifndef REDEBUG
-#ifndef NDEBUG
-#define	NDEBUG	/* no assertions please */
-#endif
-#endif
-#include <assert.h>
-
-/* for old systems with bcopy() but no memmove() */
-#ifdef USEBCOPY
-#define	memmove(d, s, c)	bcopy(s, d, c)
-#endif
diff --git a/regex-posix.cabal b/regex-posix.cabal
--- a/regex-posix.cabal
+++ b/regex-posix.cabal
@@ -1,95 +1,78 @@
-Name:                   regex-posix
--- Keep the Version below in sync with ./Text/Regex/Posix.hs value
--- getVersion_Text_Regex_Posix :: Version
-Version:                0.95.2
-Cabal-Version:          >=1.2
-Build-Type:             Custom
-License:                BSD3
-License-File:           LICENSE
-Copyright:              Copyright (c) 2007-2010, Christopher Kuklewicz
-Author:                 Christopher Kuklewicz
-Maintainer:             TextRegexLazy@personal.mightyreason.com
-Stability:              Seems to work, passes a few tests
-Homepage:               http://sourceforge.net/projects/lazy-regex
-Package-URL:            http://code.haskell.org/regex-posix/
-Synopsis:               Replaces/Enhances Text.Regex
-Description:            The posix regex backend for regex-base
-Category:               Text
-Tested-With:            GHC
-Build-Type:             Simple
-Extra-Source-Files:     cbits/engine.c cbits/cclass.h cbits/cname.h
-                        cbits/regex2.h cbits/regex.h cbits/utils.h
-                        c-finalizer/myfree.h c-finalizer/myfree.c
+cabal-version:          1.12
+name:                   regex-posix
+version:                0.96.0.0
 
-flag newBase
-  description: Choose base >= 4
-  default: True
+build-type:             Simple
+license:                BSD3
+license-file:           LICENSE
+copyright:              Copyright (c) 2007-2010, Christopher Kuklewicz
+author:                 Christopher Kuklewicz
+maintainer:             hvr@gnu.org
+bug-reports:            https://github.com/hvr/regex-posix
+synopsis:               POSIX Backend for "Text.Regex" (regex-base)
+category:               Text
+description:
+  The POSIX regex backend for <//hackage.haskell.org/package/regex-base regex-base>.
+  .
+  The main appeal of this backend is that it's very lightweight due to its reliance on the ubiquitous <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/regex.h.html POSIX.2 regex> facility that is provided by the standard C library on most POSIX platforms.
+  .
+  See also <https://wiki.haskell.org/Regular_expressions> for more information.
 
-flag splitBase
-  description: Choose the new smaller, split-up base package.
-  default: True
+extra-source-files:
+  ChangeLog.md
+  cbits/myfree.h
 
-Library
-  if flag(newBase)
-      Build-Depends: regex-base >= 0.93, base >= 4 && < 5, array, containers, bytestring
-      -- Need the next symbol for using CPP to get Data.ByteString.Base|Unsafe in
-      --  ./Text/Regex/Posix/ByteString.hs and  ./Text/Regex/Posix/ByteString/Lazy.hs
-      CPP-Options: "-DSPLIT_BASE=1"
-      Extensions:         MultiParamTypeClasses, FunctionalDependencies, CPP,
-                          ForeignFunctionInterface, GeneralizedNewtypeDeriving,
-                          FlexibleContexts, TypeSynonymInstances,
-                          FlexibleInstances
+source-repository head
+  type:     git
+  location: https://github.com/hvr/regex-posix.git
 
-  else
-    if flag(splitBase)
-      Build-Depends:      regex-base >= 0.93, base >= 3.0, array, containers,
-                          bytestring
-      -- Need the next symbol for using CPP to get Data.ByteString.Base|Unsafe
-      -- in ./Text/Regex/Posix/ByteString.hs and
-      -- ./Text/Regex/Posix/ByteString/Lazy.hs
-      CPP-Options: "-DSPLIT_BASE=1"
-      Extensions:         MultiParamTypeClasses, FunctionalDependencies, CPP,
-                          ForeignFunctionInterface, GeneralizedNewtypeDeriving,
-                          FlexibleContexts, TypeSynonymInstances,
-                          FlexibleInstances
+flag _regex-posix-clib
+  manual: False
+  default: False
+  description: Use <//hackage.haskell.org/package/regex-posix-clib regex-posix-clib> package
 
-    else
-      Build-Depends:      regex-base >= 0.93, base < 3.0
-      Extensions:         MultiParamTypeClasses, FunctionalDependencies, CPP
+library
+  hs-source-dirs: src
+  exposed-modules:
+      Text.Regex.Posix
+      Text.Regex.Posix.Wrap
+      Text.Regex.Posix.String
+      Text.Regex.Posix.Sequence
+      Text.Regex.Posix.ByteString
+      Text.Regex.Posix.ByteString.Lazy
 
-  C-Sources:            c-finalizer/myfree.c
-  Include-Dirs:         c-finalizer
-  if !os(windows)
-    CC-Options:           -DHAVE_REGEX_H
+  other-modules:
+      Paths_regex_posix
+
+  c-sources:        cbits/myfree.c
+  include-dirs:     cbits
+
+  if flag(_regex-posix-clib)
+    build-depends: regex-posix-clib == 2.7.*
   else
-    C-Sources:            cbits/reallocf.c cbits/regcomp.c cbits/regerror.c
-                          cbits/regexec.c cbits/regfree.c
-    Include-Dirs:         cbits
+    -- use POSIX.2 regex implementation from @libc@
+    -- However, Windows/msys2 doesn't provide a POSIX.2 regex impl in its @libc@
+    if os(windows)
+      build-depends: base<0
 
-  -- Data-Files:
-  -- Extra-Tmp-Files:
-  -- This is the library
-  Exposed-Modules:        Text.Regex.Posix
-                          Text.Regex.Posix.Wrap
-                          Text.Regex.Posix.String
-                          Text.Regex.Posix.Sequence
-                          Text.Regex.Posix.ByteString
-                          Text.Regex.Posix.ByteString.Lazy
-  -- Futher fields
-  Buildable:              True
-  -- Other-Modules:
-  -- HS-Source-Dirs:         "."
-  -- The CPP is for using -DSPLIT_BASE=1 to get Data.ByteString.Base|Unsafe
-  GHC-Options:            -Wall -O2
-  -- GHC-Options:            -Wall -Werror -O2
-  -- GHC-Options:            -Wall -ddump-minimal-imports
-  -- GHC-Prof-Options:
-  -- Hugs-Options:
-  -- NHC-Options:
-  -- C-Sources:
-  -- LD-Options:
-  -- Frameworks:
-  -- Includes:
-  -- Include-Dirs:           include
-  -- Extra-Libraries:
-  -- Extra-Lib-Dirs:
+  default-language: Haskell2010
+  default-extensions:
+      MultiParamTypeClasses
+      FunctionalDependencies
+      ForeignFunctionInterface
+      GeneralizedNewtypeDeriving
+      FlexibleContexts
+      TypeSynonymInstances
+      FlexibleInstances
+
+  build-depends: regex-base == 0.94.*
+               , base       >= 4.3 && < 4.14
+               , containers >= 0.4 && < 0.7
+               , bytestring >= 0.9 && < 0.11
+               , array      >= 0.3 && < 0.6
+
+  if !impl(ghc >= 8)
+      build-depends: fail == 4.9.*
+
+  ghc-options: -O2
+               -Wall -fno-warn-unused-imports
diff --git a/src/Text/Regex/Posix.hs b/src/Text/Regex/Posix.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Regex/Posix.hs
@@ -0,0 +1,75 @@
+-----------------------------------------------------------------------------
+-- |
+--
+-- Module      :  Text.Regex.Posix
+-- Copyright   :  (c) Chris Kuklewicz 2006
+-- SPDX-License-Identifier: BSD-3-Clause
+--
+-- Maintainer  :  hvr@gnu.org
+-- Stability   :  experimental
+-- Portability :  non-portable (regex-base needs MPTC+FD)
+--
+-- Module that provides the Regex backend that wraps the
+-- <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/regex.h.html C POSIX.2 regex api>.
+-- This is the backend being used by the <//hackage.haskell.org/regex-compat regex-compat> package to replace
+-- "Text.Regex".
+--
+-- The "Text.Regex.Posix" module provides a backend for regular
+-- expressions. If you import this along with other backends, then
+-- you should do so with qualified imports, perhaps renamed for
+-- convenience.
+--
+-- If the '=~' and '=~~' functions are too high level, you can use the
+-- compile, regexec, and execute functions from importing either
+-- "Text.Regex.Posix.String" or "Text.Regex.Posix.ByteString".  If you
+-- want to use a low-level 'Foreign.C.CString' interface to the library,
+-- then import "Text.Regex.Posix.Wrap" and use the wrap* functions.
+--
+-- This module is only efficient with 'Data.ByteString.ByteString' only
+-- if it is null terminated, i.e. @(Bytestring.last bs)==0@.  Otherwise the
+-- library must make a temporary copy of the 'Data.ByteString.ByteString'
+-- and append the @NUL@ byte.
+--
+-- A 'String' will be converted into a 'Foreign.C.CString' for processing.
+-- Doing this repeatedly will be very inefficient.
+--
+-- Note that the posix library works with single byte characters, and
+-- does not understand Unicode.  If you need Unicode support you will
+-- have to use a different backend.
+--
+-- When offsets are reported for subexpression captures, a subexpression
+-- that did not match anything (as opposed to matching an empty string)
+-- will have its offset set to the 'unusedRegOffset' value, which is @(-1)@.
+--
+-- Benchmarking shows the default regex library on many platforms is very
+-- inefficient.  You might increase performace by an order of magnitude
+-- by obtaining @libpcre@ and <//hackage.haskell.org/package/regex-pcre regex-pcre>
+-- or @libtre@ and <//hackage.haskell.org/package/regex-tre regex-tre>.  If you
+-- do not need the captured substrings then you can also get great
+-- performance from <//hackage.haskell.org/package/regex-dfa regex-dfa>.  If you do need the capture substrings
+-- then you may be able to use <//hackage.haskell.org/package/regex-parsec regex-parsec> to improve performance.
+-----------------------------------------------------------------------------
+
+module Text.Regex.Posix(getVersion_Text_Regex_Posix
+ ,module Text.Regex.Base
+  -- ** Wrap, for '=~' and '=~~', types and constants
+ ,module Text.Regex.Posix.Wrap) where
+
+import Prelude hiding (fail)
+import Control.Monad.Fail (MonadFail)
+
+import Text.Regex.Posix.Wrap(Regex, CompOption(CompOption),
+  ExecOption(ExecOption), (=~), (=~~),
+  unusedRegOffset,
+  compBlank, compExtended, compIgnoreCase, compNoSub, compNewline,
+  execBlank, execNotBOL, execNotEOL)
+import Text.Regex.Posix.String()
+import Text.Regex.Posix.Sequence()
+import Text.Regex.Posix.ByteString()
+import Text.Regex.Posix.ByteString.Lazy()
+import Data.Version(Version(..))
+import Text.Regex.Base
+import qualified Paths_regex_posix
+
+getVersion_Text_Regex_Posix :: Version
+getVersion_Text_Regex_Posix = Paths_regex_posix.version
diff --git a/src/Text/Regex/Posix/ByteString.hs b/src/Text/Regex/Posix/ByteString.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Regex/Posix/ByteString.hs
@@ -0,0 +1,151 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Text.Regex.Posix.ByteString
+-- Copyright   :  (c) Chris Kuklewicz 2006
+-- SPDX-License-Identifier: BSD-3-Clause
+-- 
+-- Maintainer  :  hvr@gnu.org
+-- Stability   :  experimental
+-- Portability :  non-portable (regex-base needs MPTC+FD)
+--
+-- This provides 'ByteString' instances for RegexMaker and RegexLike
+-- based on "Text.Regex.Posix.Wrap", and a (RegexContext Regex
+-- ByteString ByteString) instance.
+--
+-- To use these instance, you would normally import
+-- "Text.Regex.Posix".  You only need to import this module to use
+-- the medium level API of the compile, regexec, and execute
+-- functions.  All of these report error by returning Left values
+-- instead of undefined or error or fail.
+--
+-- The ByteString will only be passed to the library efficiently (as a
+-- pointer) if it ends in a NUL byte.  Otherwise a temporary copy must
+-- be made with the 0 byte appended.
+-----------------------------------------------------------------------------
+
+module Text.Regex.Posix.ByteString(
+  -- ** Types
+  Regex,
+  MatchOffset,
+  MatchLength,
+  ReturnCode,
+  WrapError,
+  -- ** Miscellaneous
+  unusedOffset,
+  -- ** Medium level API functions
+  compile,
+  execute,
+  regexec,
+  -- ** Compilation options
+  CompOption(CompOption),
+  compBlank,
+  compExtended,   -- use extended regex syntax
+  compIgnoreCase, -- ignore case when matching
+  compNoSub,      -- no substring matching needed
+  compNewline,    -- '.' doesn't match newline
+  -- ** Execution options
+  ExecOption(ExecOption),
+  execBlank,
+  execNotBOL,      -- not at begining of line
+  execNotEOL       -- not at end of line
+  ) where
+
+import Prelude hiding (fail)
+import Control.Monad.Fail (MonadFail(fail))
+
+import Data.Array(Array,listArray)
+import Data.ByteString(ByteString)
+import qualified Data.ByteString as B(empty,useAsCString,last,take,drop,null)
+import qualified Data.ByteString.Unsafe as B(unsafeUseAsCString)
+import System.IO.Unsafe(unsafePerformIO)
+import Text.Regex.Base.RegexLike(RegexMaker(..),RegexContext(..),RegexLike(..),MatchOffset,MatchLength)
+import Text.Regex.Posix.Wrap -- all
+import Text.Regex.Base.Impl(polymatch,polymatchM)
+import Foreign.C.String(CString)
+
+instance RegexContext Regex ByteString ByteString where
+  match = polymatch
+  matchM = polymatchM
+
+unwrap :: (Show e) => Either e v -> IO v
+unwrap x = case x of Left err -> fail ("Text.Regex.Posix.ByteString died: "++ show err)
+                     Right v -> return v
+
+instance RegexMaker Regex CompOption ExecOption ByteString where
+  makeRegexOpts c e pattern = unsafePerformIO $
+    compile c e pattern >>= unwrap
+  makeRegexOptsM c e pattern = either (fail.show) return $ unsafePerformIO $
+    compile c e pattern
+
+instance RegexLike Regex ByteString where
+  matchTest regex bs = unsafePerformIO $
+    asCString bs (wrapTest regex) >>=  unwrap
+  matchOnce regex bs = unsafePerformIO $ 
+    execute regex bs >>= unwrap
+  matchAll regex bs = unsafePerformIO $
+    asCString bs (wrapMatchAll regex) >>= unwrap
+  matchCount regex bs = unsafePerformIO $
+    asCString bs (wrapCount regex) >>= unwrap
+
+-- ---------------------------------------------------------------------
+-- | Compiles a regular expression
+--
+compile :: CompOption    -- ^ Flags (summed together)
+        -> ExecOption    -- ^ Flags (summed together)
+        -> ByteString  -- ^ The regular expression to compile
+        -> IO (Either WrapError Regex)      -- ^ Returns: the compiled regular expression
+compile c e pattern =
+  asCString pattern (wrapCompile c e)
+
+
+-- ---------------------------------------------------------------------
+-- | Matches a regular expression against a buffer, returning the buffer
+-- indicies of the match, and any submatches
+--
+-- | Matches a regular expression against a string
+execute :: Regex      -- ^ Compiled regular expression
+        -> ByteString -- ^ String to match against
+        -> IO (Either WrapError (Maybe (Array Int (MatchOffset,MatchLength))))
+                -- ^ Returns: 'Nothing' if the regex did not match the
+                -- string, or:
+                --   'Just' an array of (offset,length) pairs where index 0 is whole match, and the rest are the captured subexpressions.
+execute regex bs = do
+  maybeStartEnd <- asCString bs (wrapMatch regex)
+  case maybeStartEnd of
+    Right Nothing -> return (Right Nothing)
+--  Right (Just []) -> ...
+    Right (Just parts) -> 
+      return . Right . Just . listArray (0,pred (length parts))
+      . map (\(s,e)->(fromIntegral s, fromIntegral (e-s))) $ parts
+    Left err -> return (Left err)
+
+regexec :: Regex      -- ^ Compiled regular expression
+        -> ByteString -- ^ String to match against
+        -> IO (Either WrapError (Maybe (ByteString, ByteString, ByteString, [ByteString])))
+regexec regex bs = do
+  let getSub (start,stop) | start == unusedRegOffset = B.empty
+                          | otherwise = B.take (fi (stop-start)) . B.drop (fi start) $ bs
+      matchedParts [] = (B.empty,B.empty,bs,[]) -- no information
+      matchedParts (matchedStartStop@(start,stop):subStartStop) = 
+        (B.take (fi start) bs
+        ,getSub matchedStartStop
+        ,B.drop (fi stop) bs
+        ,map getSub subStartStop)
+  maybeStartEnd <- asCString bs (wrapMatch regex)
+  case maybeStartEnd of
+    Right Nothing -> return (Right Nothing)
+--  Right (Just []) -> ...
+    Right (Just parts) -> return . Right . Just . matchedParts $ parts
+    Left err -> return (Left err)
+
+unusedOffset :: Int
+unusedOffset = fromIntegral unusedRegOffset
+
+fi :: (Integral i,Num n) => i->n
+fi = fromIntegral
+
+asCString :: ByteString -> (CString -> IO a) -> IO a
+asCString bs = if (not (B.null bs)) && (0==B.last bs)
+                  then B.unsafeUseAsCString bs
+                  else B.useAsCString bs
diff --git a/src/Text/Regex/Posix/ByteString/Lazy.hs b/src/Text/Regex/Posix/ByteString/Lazy.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Regex/Posix/ByteString/Lazy.hs
@@ -0,0 +1,140 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Text.Regex.Posix.ByteString.Lazy
+-- Copyright   :  (c) Chris Kuklewicz 2007
+-- SPDX-License-Identifier: BSD-3-Clause
+-- 
+-- Maintainer  :  hvr@gnu.org
+-- Stability   :  experimental
+-- Portability :  non-portable (regex-base needs MPTC+FD)
+--
+-- This provides 'ByteString.Lazy' instances for RegexMaker and RegexLike
+-- based on "Text.Regex.Posix.Wrap", and a (RegexContext Regex
+-- ByteString ByteString) instance.
+--
+-- To use these instance, you would normally import
+-- "Text.Regex.Posix".  You only need to import this module to use
+-- the medium level API of the compile, regexec, and execute
+-- functions.  All of these report error by returning Left values
+-- instead of undefined or error or fail.
+--
+-- A Lazy ByteString with more than one chunk cannot be be passed to
+-- the library efficiently (as a pointer).  It will have to converted
+-- via a full copy to a temporary normal bytestring (with a null byte
+-- appended if necessary).
+-----------------------------------------------------------------------------
+
+module Text.Regex.Posix.ByteString.Lazy(
+  -- ** Types
+  Regex,
+  MatchOffset,
+  MatchLength,
+  ReturnCode,
+  WrapError,
+  -- ** Miscellaneous
+  unusedOffset,
+  -- ** Medium level API functions
+  compile,
+  execute,
+  regexec,
+  -- ** Compilation options
+  CompOption(CompOption),
+  compBlank,
+  compExtended,   -- use extended regex syntax
+  compIgnoreCase, -- ignore case when matching
+  compNoSub,      -- no substring matching needed
+  compNewline,    -- '.' doesn't match newline
+  -- ** Execution options
+  ExecOption(ExecOption),
+  execBlank,
+  execNotBOL,      -- not at begining of line
+  execNotEOL       -- not at end of line
+  ) where
+
+import Prelude hiding (fail)
+import Control.Monad.Fail (MonadFail(fail))
+
+import Data.Array(Array)
+import qualified Data.ByteString.Lazy as L (ByteString,null,toChunks,fromChunks,last,snoc)
+import qualified Data.ByteString as B(ByteString,concat)
+import qualified Data.ByteString.Unsafe as B(unsafeUseAsCString)
+import System.IO.Unsafe(unsafePerformIO)
+import Text.Regex.Base.RegexLike(RegexMaker(..),RegexContext(..),RegexLike(..),MatchOffset,MatchLength)
+import Text.Regex.Posix.Wrap -- all
+import qualified Text.Regex.Posix.ByteString as BS(execute,regexec)
+import Text.Regex.Base.Impl(polymatch,polymatchM)
+import Foreign.C.String(CString)
+
+instance RegexContext Regex L.ByteString L.ByteString where
+  match = polymatch
+  matchM = polymatchM
+
+fromLazy :: L.ByteString -> B.ByteString
+fromLazy = B.concat . L.toChunks
+
+toLazy :: B.ByteString -> L.ByteString
+toLazy = L.fromChunks . return
+
+unwrap :: (Show e) => Either e v -> IO v
+unwrap x = case x of Left err -> fail ("Text.Regex.Posix.ByteString.Lazy died: "++ show err)
+                     Right v -> return v
+
+{-# INLINE asCString #-}
+asCString :: L.ByteString -> (CString -> IO a) -> IO a
+asCString s = if (not (L.null s)) && (0==L.last s)
+                then B.unsafeUseAsCString (fromLazy s)
+                else B.unsafeUseAsCString (fromLazy (L.snoc s 0))
+
+instance RegexMaker Regex CompOption ExecOption L.ByteString where
+  makeRegexOpts c e pattern = unsafePerformIO $ compile c e pattern >>= unwrap
+  makeRegexOptsM c e pattern = either (fail.show) return $ unsafePerformIO $ compile c e pattern
+
+instance RegexLike Regex L.ByteString where
+  matchTest regex bs = unsafePerformIO $
+    asCString bs (wrapTest regex) >>=  unwrap
+  matchOnce regex bs = unsafePerformIO $ 
+    execute regex bs >>= unwrap
+  matchAll regex bs = unsafePerformIO $
+    asCString bs (wrapMatchAll regex) >>= unwrap
+  matchCount regex bs = unsafePerformIO $
+    asCString bs (wrapCount regex) >>= unwrap
+
+-- ---------------------------------------------------------------------
+-- | Compiles a regular expression
+--
+compile :: CompOption    -- ^ Flags (summed together)
+        -> ExecOption    -- ^ Flags (summed together)
+        -> L.ByteString  -- ^ The regular expression to compile
+        -> IO (Either WrapError Regex)      -- ^ Returns: the compiled regular expression
+compile c e pattern = asCString pattern (wrapCompile c e)
+
+-- ---------------------------------------------------------------------
+-- | Matches a regular expression against a buffer, returning the buffer
+-- indicies of the match, and any submatches
+--
+-- | Matches a regular expression against a string
+execute :: Regex      -- ^ Compiled regular expression
+        -> L.ByteString -- ^ String to match against
+        -> IO (Either WrapError (Maybe (Array Int (MatchOffset,MatchLength))))
+                -- ^ Returns: 'Nothing' if the regex did not match the
+                -- string, or:
+                --   'Just' an array of (offset,length) pairs where index 0 is whole match, and the rest are the captured subexpressions.
+execute regex bs = if (not (L.null bs)) && (0==L.last bs)
+                     then BS.execute regex (fromLazy bs)
+                     else BS.execute regex (fromLazy (L.snoc bs 0))
+
+regexec :: Regex      -- ^ Compiled regular expression
+        -> L.ByteString -- ^ String to match against
+        -> IO (Either WrapError (Maybe (L.ByteString, L.ByteString, L.ByteString, [L.ByteString])))
+regexec regex bs = do
+  x <- if (not (L.null bs)) && (0==L.last bs)
+         then BS.regexec regex (fromLazy bs)
+         else BS.regexec regex (fromLazy (L.snoc bs 0))
+  return $ case x of
+             Left e -> Left e
+             Right Nothing -> Right Nothing
+             Right (Just (a,b,c,ds)) -> Right (Just (toLazy a,toLazy b,toLazy c,map toLazy ds))
+
+unusedOffset :: Int
+unusedOffset = fromIntegral unusedRegOffset
diff --git a/src/Text/Regex/Posix/Sequence.hs b/src/Text/Regex/Posix/Sequence.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Regex/Posix/Sequence.hs
@@ -0,0 +1,168 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Text.Regex.Posix.Sequence
+-- Copyright   :  (c) Chris Kuklewicz 2006
+-- SPDX-License-Identifier: BSD-3-Clause
+-- 
+-- Maintainer  :  hvr@gnu.org
+-- Stability   :  experimental
+-- Portability :  non-portable (regex-base needs MPTC+FD)
+--
+-- This provides 'String' instances for 'RegexMaker' and 'RegexLike' based
+-- on "Text.Regex.Posix.Wrap", and a ('RegexContext' 'Regex' 'String' 'String')
+-- instance.
+--
+-- To use these instance, you would normally import
+-- "Text.Regex.Posix".  You only need to import this module to use
+-- the medium level API of the compile, regexec, and execute
+-- functions.  All of these report error by returning Left values
+-- instead of undefined or error or fail.
+--
+-----------------------------------------------------------------------------
+
+module Text.Regex.Posix.Sequence(
+  -- ** Types
+  Regex,
+  MatchOffset,
+  MatchLength,
+  ReturnCode,
+  WrapError,
+  -- ** Miscellaneous
+  unusedOffset,
+  -- ** Medium level API functions
+  compile,
+  regexec,
+  execute,
+  -- ** Compilation options
+  CompOption(CompOption),
+  compBlank,
+  compExtended,   -- use extended regex syntax
+  compIgnoreCase, -- ignore case when matching
+  compNoSub,      -- no substring matching needed
+  compNewline,    -- '.' doesn't match newline
+
+  ExecOption(ExecOption),
+  execBlank,
+  execNotBOL,     -- not at begining of line
+  execNotEOL     -- not at end of line
+  ) where
+
+import Prelude hiding (fail)
+import Control.Monad.Fail (MonadFail(fail))
+
+import Data.Array(listArray, Array)
+import System.IO.Unsafe(unsafePerformIO)
+import Text.Regex.Base.RegexLike(RegexContext(..),RegexMaker(..),RegexLike(..),MatchOffset,MatchLength,Extract(..))
+import Text.Regex.Posix.Wrap
+import Text.Regex.Base.Impl(polymatch,polymatchM)
+import Data.Sequence as S hiding (length)
+import qualified Data.Sequence as S (length)
+import Foreign.C.String
+import Foreign.Marshal.Array
+import Foreign.Marshal.Alloc
+import Foreign.Storable
+
+instance RegexContext Regex (Seq Char) (Seq Char) where
+  match = polymatch
+  matchM = polymatchM
+
+unusedOffset :: Int
+unusedOffset = fromIntegral unusedRegOffset
+
+unwrap :: (Show e) => Either e v -> IO v
+unwrap x = case x of Left err -> fail ("Text.Regex.Posix.Sequence died: "++ show err)
+                     Right v -> return v
+
+instance RegexMaker Regex CompOption ExecOption (Seq Char) where
+  makeRegexOpts c e pattern = unsafePerformIO $
+    (compile c e pattern >>= unwrap)
+  makeRegexOptsM c e pattern = either (fail.show) return $ unsafePerformIO $ 
+    (compile c e pattern)
+
+instance RegexLike Regex (Seq Char) where
+  matchTest regex str = unsafePerformIO $ do
+    withSeq str (wrapTest regex) >>= unwrap
+  matchOnce regex str = unsafePerformIO $ 
+    execute regex str >>= unwrap
+  matchAll regex str = unsafePerformIO $ 
+    withSeq str (wrapMatchAll regex) >>= unwrap
+  matchCount regex str = unsafePerformIO $
+    withSeq str (wrapCount regex) >>= unwrap
+
+-- compile
+compile  :: CompOption -- ^ Flags (summed together)
+         -> ExecOption -- ^ Flags (summed together)
+         -> (Seq Char)     -- ^ The regular expression to compile (ASCII only, no null bytes)
+         -> IO (Either WrapError Regex) -- ^ Returns: the compiled regular expression
+compile flags e pattern =  withSeq pattern (wrapCompile flags e)
+
+-- -----------------------------------------------------------------------------
+-- regexec
+
+-- | Matches a regular expression against a string
+execute :: Regex      -- ^ Compiled regular expression
+        -> (Seq Char)     -- ^ (Seq Char) to match against
+        -> IO (Either WrapError (Maybe (Array Int (MatchOffset,MatchLength))))
+                -- ^ Returns: 'Nothing' if the regex did not match the
+                -- string, or:
+                --
+                -- @
+                --   'Just' (array of offset length pairs)
+                -- @
+execute regex str = do
+  maybeStartEnd <- withSeq str (wrapMatch regex)
+  case maybeStartEnd of
+    Right Nothing -> return (Right Nothing)
+--  Right (Just []) ->  fail "got [] back!" -- return wierd array instead
+    Right (Just parts) ->
+      return . Right . Just . listArray (0,pred (length parts)) 
+       . map (\(s,e)->(fromIntegral s, fromIntegral (e-s)))
+       $ parts
+    Left err -> return (Left err)
+
+-- -----------------------------------------------------------------------------
+-- regexec
+
+-- | Matches a regular expression against a string
+regexec :: Regex      -- ^ Compiled regular expression
+        -> (Seq Char)     -- ^ (Seq Char) to match against
+        -> IO (Either WrapError (Maybe ((Seq Char), (Seq Char), (Seq Char), [(Seq Char)])))
+                -- ^ Returns: 'Nothing' if the regex did not match the
+                -- string, or:
+                --
+                -- @
+                --   'Just' (everything before match,
+                --         matched portion,
+                --         everything after match,
+                --         subexpression matches)
+                -- @
+regexec regex str = do
+  let getSub :: (RegOffset,RegOffset) -> (Seq Char)
+      getSub (start,stop) | start == unusedRegOffset = S.empty
+                          | otherwise = 
+        extract (fromEnum start,fromEnum $ stop-start) $ str
+      matchedParts :: [(RegOffset,RegOffset)] -> ((Seq Char), (Seq Char), (Seq Char), [(Seq Char)])
+      matchedParts [] = (str,S.empty,S.empty,[]) -- no information
+      matchedParts (matchedStartStop@(start,stop):subStartStop) = 
+        (before (fromEnum start) str
+        ,getSub matchedStartStop
+        ,after (fromEnum stop) str
+        ,map getSub subStartStop)
+  maybeStartEnd <- withSeq str (wrapMatch regex)
+  case maybeStartEnd of
+    Right Nothing -> return (Right Nothing)
+    Right (Just parts) -> return . Right . Just . matchedParts $ parts
+    Left err -> return (Left err)
+
+withSeq :: Seq Char -> (CString -> IO a) -> IO a
+withSeq s f =
+  let -- Ensure null at end of s
+      s' = case viewr s of                 -- bang !s
+             EmptyR -> singleton '\0'
+             _ :> '\0' -> s
+             _ -> s |> '\0'
+      pokes p a = case viewl a of         -- bang pokes !p !a
+                    EmptyL -> return ()
+                    c :< a' -> poke p (castCharToCChar c) >> pokes (advancePtr p 1) a'
+  in allocaBytes (S.length s') (\ptr -> pokes ptr s' >> f ptr)
diff --git a/src/Text/Regex/Posix/String.hs b/src/Text/Regex/Posix/String.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Regex/Posix/String.hs
@@ -0,0 +1,150 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Text.Regex.Posix.String
+-- Copyright   :  (c) Chris Kuklewicz 2006
+-- SPDX-License-Identifier: BSD-3-Clause
+-- 
+-- Maintainer  :  hvr@gnu.org
+-- Stability   :  experimental
+-- Portability :  non-portable (regex-base needs MPTC+FD)
+--
+-- This provides 'String' instances for 'RegexMaker' and 'RegexLike' based
+-- on "Text.Regex.Posix.Wrap", and a ('RegexContext' 'Regex' 'String' 'String')
+-- instance.
+--
+-- To use these instance, you would normally import
+-- "Text.Regex.Posix".  You only need to import this module to use
+-- the medium level API of the compile, regexec, and execute
+-- functions.  All of these report error by returning Left values
+-- instead of undefined or error or fail.
+--
+-----------------------------------------------------------------------------
+
+module Text.Regex.Posix.String(
+  -- ** Types
+  Regex,
+  MatchOffset,
+  MatchLength,
+  ReturnCode,
+  WrapError,
+  -- ** Miscellaneous
+  unusedOffset,
+  -- ** Medium level API functions
+  compile,
+  regexec,
+  execute,
+  -- ** Compilation options
+  CompOption(CompOption),
+  compBlank,
+  compExtended,   -- use extended regex syntax
+  compIgnoreCase, -- ignore case when matching
+  compNoSub,      -- no substring matching needed
+  compNewline,    -- '.' doesn't match newline
+  -- ** Execution options
+  ExecOption(ExecOption),
+  execBlank,
+  execNotBOL,     -- not at begining of line
+  execNotEOL     -- not at end of line
+  ) where
+
+import Prelude hiding (fail)
+import Control.Monad.Fail (MonadFail(fail))
+
+import Data.Array(listArray, Array)
+import Data.List(genericDrop, genericTake)
+import Foreign.C.String(withCAString)
+import System.IO.Unsafe(unsafePerformIO)
+import Text.Regex.Base.RegexLike(RegexContext(..),RegexMaker(..),RegexLike(..),MatchOffset,MatchLength)
+import Text.Regex.Posix.Wrap
+import Text.Regex.Base.Impl(polymatch,polymatchM)
+
+instance RegexContext Regex String String where
+  match = polymatch
+  matchM = polymatchM
+
+unusedOffset :: Int
+unusedOffset = fromIntegral unusedRegOffset
+
+unwrap :: (Show e) => Either e v -> IO v
+unwrap x = case x of Left err -> fail ("Text.Regex.Posix.String died: "++ show err)
+                     Right v -> return v
+
+instance RegexMaker Regex CompOption ExecOption String where
+  makeRegexOpts c e pattern = unsafePerformIO $
+    (compile c e pattern >>= unwrap)
+  makeRegexOptsM c e pattern = either (fail.show) return $ unsafePerformIO $ 
+    (compile c e pattern)
+
+instance RegexLike Regex String where
+  matchTest regex str = unsafePerformIO $ do
+    withCAString str (wrapTest regex) >>= unwrap
+  matchOnce regex str = unsafePerformIO $ 
+    execute regex str >>= unwrap
+  matchAll regex str = unsafePerformIO $ 
+    withCAString str (wrapMatchAll regex) >>= unwrap
+  matchCount regex str = unsafePerformIO $
+    withCAString str (wrapCount regex) >>= unwrap
+
+-- compile
+compile  :: CompOption -- ^ Flags (summed together)
+         -> ExecOption -- ^ Flags (summed together)
+         -> String     -- ^ The regular expression to compile (ASCII only, no null bytes)
+         -> IO (Either WrapError Regex) -- ^ Returns: the compiled regular expression
+compile flags e pattern =  withCAString pattern (wrapCompile flags e)
+
+-- -----------------------------------------------------------------------------
+-- regexec
+
+-- | Matches a regular expression against a string
+execute :: Regex      -- ^ Compiled regular expression
+        -> String     -- ^ String to match against
+        -> IO (Either WrapError (Maybe (Array Int (MatchOffset,MatchLength))))
+                -- ^ Returns: 'Nothing' if the regex did not match the
+                -- string, or:
+                --
+                -- @
+                --   'Just' (array of offset length pairs)
+                -- @
+execute regex str = do
+  maybeStartEnd <- withCAString str (wrapMatch regex)
+  case maybeStartEnd of
+    Right Nothing -> return (Right Nothing)
+--  Right (Just []) ->  fail "got [] back!" -- return wierd array instead
+    Right (Just parts) ->
+      return . Right . Just . listArray (0,pred (length parts)) 
+       . map (\(s,e)->(fromIntegral s, fromIntegral (e-s)))
+       $ parts
+    Left err -> return (Left err)
+
+-- -----------------------------------------------------------------------------
+-- regexec
+
+-- | Matches a regular expression against a string
+regexec :: Regex      -- ^ Compiled regular expression
+        -> String     -- ^ String to match against
+        -> IO (Either WrapError (Maybe (String, String, String, [String])))
+                -- ^ Returns: 'Nothing' if the regex did not match the
+                -- string, or:
+                --
+                -- @
+                --   'Just' (everything before match,
+                --         matched portion,
+                --         everything after match,
+                --         subexpression matches)
+                -- @
+regexec regex str = do
+  let getSub (start,stop) | start == unusedRegOffset = ""
+                          | otherwise = 
+        genericTake (stop-start) . genericDrop start $ str
+      matchedParts [] = (str,"","",[]) -- no information
+      matchedParts (matchedStartStop@(start,stop):subStartStop) = 
+        (genericTake start str
+        ,getSub matchedStartStop
+        ,genericDrop stop str
+        ,map getSub subStartStop)
+  maybeStartEnd <- withCAString str (wrapMatch regex)
+  case maybeStartEnd of
+    Right Nothing -> return (Right Nothing)
+    Right (Just parts) -> return . Right . Just . matchedParts $ parts
+    Left err -> return (Left err)
diff --git a/src/Text/Regex/Posix/Wrap.hsc b/src/Text/Regex/Posix/Wrap.hsc
new file mode 100644
--- /dev/null
+++ b/src/Text/Regex/Posix/Wrap.hsc
@@ -0,0 +1,576 @@
+{-# OPTIONS_GHC -Wall -fno-warn-unused-imports #-}
+
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Text.Regex.Posix.Wrap
+-- Copyright   :  (c) Chris Kuklewicz 2006,2007,2008 derived from (c) The University of Glasgow 2002
+-- SPDX-License-Identifier: BSD-3-Clause
+--
+-- Maintainer  :  hvr@gnu.org
+-- Stability   :  experimental
+-- Portability :  non-portable (regex-base needs MPTC+FD)
+--
+-- WrapPosix.hsc exports a wrapped version of the ffi imports.  To
+-- increase type safety, the flags are newtype'd.  The other important
+-- export is a 'Regex' type that is specific to the Posix library
+-- backend.  The flags are documented in "Text.Regex.Posix".  The
+-- 'defaultCompOpt' is @(compExtended .|. compNewline)@.
+--
+-- The 'Regex', 'CompOption', and 'ExecOption' types and their 'RegexOptions'
+-- instance is declared.  The '=~' and '=~~' convenience functions are
+-- defined.
+--
+-- This module will fail or error only if allocation fails or a nullPtr
+-- is passed in.
+--
+-- 2009-January : wrapMatchAll and wrapCount now adjust the execution
+-- option execNotBOL after the first result to take into account '\n'
+-- in the text immediately before the next matches. (version 0.93.3)
+--
+-- 2009-January : wrapMatchAll and wrapCount have been changed to
+-- return all non-overlapping matches, including empty matches even if
+-- they coincide with the end of the previous non-empty match.  The
+-- change is that the first non-empty match no longer terminates the
+-- search.  One can filter the results to obtain the old behavior or
+-- to obtain the behavior of "sed", where "sed" eliminates the empty
+-- matches which coincide with the end of non-empty matches. (version
+-- 0.94.0)
+-----------------------------------------------------------------------------
+
+module Text.Regex.Posix.Wrap(
+  -- ** High-level API
+  Regex,
+  RegOffset,
+  RegOffsetT,
+  (=~),
+  (=~~),
+
+  -- ** Low-level API
+  WrapError,
+  wrapCompile,
+  wrapTest,
+  wrapMatch,
+  wrapMatchAll,
+  wrapCount,
+
+  -- ** Miscellaneous
+  unusedRegOffset,
+
+  -- ** Compilation options
+  CompOption(CompOption),
+  compBlank,
+  compExtended,   -- use extended regex syntax
+  compIgnoreCase, -- ignore case when matching
+  compNoSub,      -- no substring matching needed
+  compNewline,    -- '.' doesn't match newline
+
+  -- ** Execution options
+  ExecOption(ExecOption),
+  execBlank,
+  execNotBOL,     -- not at begining of line
+  execNotEOL,     -- not at end of line
+
+  -- ** Return codes
+  ReturnCode(ReturnCode),
+  retBadbr,
+  retBadpat,
+  retBadrpt,
+  retEcollate,
+  retEctype,
+  retEescape,
+  retEsubreg,
+  retEbrack,
+  retEparen,
+  retEbrace,
+  retErange,
+  retEspace
+  ) where
+
+#include <sys/types.h>
+#include <string.h>
+
+#ifndef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 1
+#endif
+
+#include <regex.h>
+
+#include "myfree.h"
+
+import Prelude hiding (fail)
+import Control.Monad.Fail (MonadFail)
+
+import Control.Monad(liftM)
+import Data.Array(Array,listArray)
+import Data.Bits(Bits(..))
+import Data.Int(Int32,Int64)   -- need whatever RegeOffset or #regoff_t type will be
+import Data.Word(Word32,Word64) -- need whatever RegeOffset or #regoff_t type will be
+import Foreign(Ptr, FunPtr, nullPtr, newForeignPtr,
+               addForeignPtrFinalizer, Storable(peekByteOff), allocaArray,
+               allocaBytes, withForeignPtr,ForeignPtr,plusPtr,peekElemOff)
+import Foreign.Marshal.Alloc(mallocBytes)
+import Foreign.C(CChar)
+#if __GLASGOW_HASKELL__ >= 703
+import Foreign.C(CSize(CSize),CInt(CInt))
+#else
+import Foreign.C(CSize,CInt)
+#endif
+import Foreign.C.String(peekCAString, CString)
+import Text.Regex.Base.RegexLike(RegexOptions(..),RegexMaker(..),RegexContext(..),MatchArray)
+-- deprecated: import qualified System.IO.Error as IOERROR(try)
+import qualified Control.Exception(try,IOException)
+
+try :: IO a -> IO (Either Control.Exception.IOException a)
+try = Control.Exception.try
+
+data CRegex   -- pointer tag for regex_t C type
+
+-- | RegOffset is "typedef int regoff_t" on Linux and ultimately "typedef
+-- long long __int64_t" on Max OS X.  So rather than saying
+-- 2,147,483,647 is all the length you need, I'll take the larger:
+-- 9,223,372,036,854,775,807 should be enough bytes for anyone, no
+-- need for Integer. The alternative is to compile to different sizes
+-- in a platform dependent manner with "type RegOffset = (#type
+-- regoff_t)", which I do not want to do.
+--
+-- There is also a special value 'unusedRegOffset' :: 'RegOffset' which is
+-- (-1) and as a starting index means that the subgroup capture was
+-- unused.  Otherwise the RegOffset indicates a character boundary that
+-- is before the character at that index offset, with the first
+-- character at index offset 0. So starting at 1 and ending at 2 means
+-- to take only the second character.
+type RegOffset = Int64
+--debugging 64-bit ubuntu
+type RegOffsetT = (#type regoff_t)
+
+-- | A bitmapped 'CInt' containing options for compilation of regular
+-- expressions.  Option values (and their man 3 regcomp names) are
+--
+--  * 'compBlank' which is a completely zero value for all the flags.
+--    This is also the 'blankCompOpt' value.
+--
+--  * 'compExtended' (REG_EXTENDED) which can be set to use extended instead
+--    of basic regular expressions.
+--    This is set in the 'defaultCompOpt' value.
+--
+--  * 'compNewline' (REG_NEWLINE) turns on newline sensitivity: The dot (.)
+--    and inverted set @[^ ]@ never match newline, and ^ and $ anchors do
+--    match after and before newlines.
+--    This is set in the 'defaultCompOpt' value.
+--
+--  * 'compIgnoreCase' (REG_ICASE) which can be set to match ignoring upper
+--    and lower distinctions.
+--
+--  * 'compNoSub' (REG_NOSUB) which turns off all information from matching
+--    except whether a match exists.
+
+newtype CompOption = CompOption CInt deriving (Eq,Show,Num,Bits)
+
+-- | A bitmapped 'CInt' containing options for execution of compiled
+-- regular expressions.  Option values (and their man 3 regexec names) are
+--
+--  * 'execBlank' which is a complete zero value for all the flags.  This is
+--    the blankExecOpt value.
+--
+--  * 'execNotBOL' (REG_NOTBOL) can be set to prevent ^ from matching at the
+--    start of the input.
+--
+--  * 'execNotEOL' (REG_NOTEOL) can be set to prevent $ from matching at the
+--    end of the input (before the terminating NUL).
+newtype ExecOption = ExecOption CInt deriving (Eq,Show,Num,Bits)
+
+-- | ReturnCode is an enumerated 'CInt', corresponding to the error codes
+-- from @man 3 regex@:
+--
+-- * 'retBadbr' (@REG_BADBR@) invalid repetition count(s) in @{ }@
+--
+-- * 'retBadpat' (@REG_BADPAT@) invalid regular expression
+--
+-- * 'retBadrpt' (@REG_BADRPT@) @?@, @*@, or @+@ operand invalid
+--
+-- * 'retEcollate' (@REG_ECOLLATE@) invalid collating element
+--
+-- * 'retEctype' (@REG_ECTYPE@) invalid character class
+--
+-- * 'retEescape' (@REG_EESCAPE@) @\\@ applied to unescapable character
+--
+-- * 'retEsubreg' (@REG_ESUBREG@) invalid backreference number
+--
+-- * 'retEbrack' (@REG_EBRACK@) brackets @[ ]@ not balanced
+--
+-- * 'retEparen' (@REG_EPAREN@) parentheses @( )@ not balanced
+--
+-- * 'retEbrace' (@REG_EBRACE@) braces @{ }@ not balanced
+--
+-- * 'retErange' (@REG_ERANGE@) invalid character range in @[ ]@
+--
+-- * 'retEspace' (@REG_ESPACE@) ran out of memory
+--
+-- * 'retNoMatch' (@REG_NOMATCH@) The regexec() function failed to match
+--
+newtype ReturnCode = ReturnCode CInt deriving (Eq,Show)
+
+-- | A compiled regular expression.
+data Regex = Regex (ForeignPtr CRegex) CompOption ExecOption
+
+-- | A completely zero value for all the flags.
+-- This is also the 'blankCompOpt' value.
+compBlank :: CompOption
+compBlank = CompOption 0
+
+-- | A completely zero value for all the flags.
+-- This is also the 'blankExecOpt' value.
+execBlank :: ExecOption
+execBlank = ExecOption 0
+
+unusedRegOffset :: RegOffset
+unusedRegOffset = (-1)
+
+-- | The return code will be retOk when it is the Haskell wrapper and
+-- not the underlying library generating the error message.
+type WrapError = (ReturnCode,String)
+
+wrapCompile :: CompOption -- ^ Flags (bitmapped)
+            -> ExecOption -- ^ Flags (bitmapped)
+            -> CString -- ^ The regular expression to compile (ASCII only, no null bytes)
+            -> IO (Either WrapError Regex) -- ^ Returns: the compiled regular expression
+
+wrapTest :: Regex -> CString
+         -> IO (Either WrapError Bool)
+
+-- | wrapMatch returns offsets for the begin and end of each capture.
+-- Unused captures have offsets of unusedRegOffset which is (-1)
+wrapMatch :: Regex -> CString
+          -> IO (Either WrapError (Maybe [(RegOffset,RegOffset)]))
+
+-- | wrapMatchAll returns the offset and length of each capture.
+-- Unused captures have an offset of unusedRegOffset which is (-1) and
+-- length of 0.
+wrapMatchAll :: Regex -> CString
+             -> IO (Either WrapError [MatchArray])
+
+wrapCount :: Regex -> CString
+          -> IO (Either WrapError Int)
+
+(=~)  :: (RegexMaker Regex CompOption ExecOption source,RegexContext Regex source1 target)
+      => source1 -> source -> target
+(=~~) :: (RegexMaker Regex CompOption ExecOption source,RegexContext Regex source1 target,MonadFail m)
+      => source1 -> source -> m target
+
+instance RegexOptions Regex CompOption ExecOption where
+  blankCompOpt = compBlank
+  blankExecOpt = execBlank
+  defaultCompOpt = compExtended .|. compNewline
+  defaultExecOpt = execBlank
+  setExecOpts e' (Regex r c _) = Regex r c e'
+  getExecOpts (Regex _ _ e) = e
+
+-- (=~) ::(RegexMaker Regex CompOption ExecOption source,RegexContext Regex source1 target) => source1 -> source -> target
+(=~) x r = let make :: RegexMaker Regex CompOption ExecOption a => a -> Regex
+               make = makeRegex
+           in match (make r) x
+
+-- (=~~) ::(RegexMaker Regex CompOption ExecOption source,RegexContext Regex source1 target,MonadFail m) => source1 -> source -> m target
+(=~~) x r = let make :: RegexMaker Regex CompOption ExecOption a => a -> Regex
+                make = makeRegex
+            in matchM (make r) x
+
+type CRegMatch = () -- dummy regmatch_t used below to read out so and eo values
+
+-- -----------------------------------------------------------------------------
+-- The POSIX regex C interface
+
+-- string.h
+foreign import ccall unsafe "memset"
+  c_memset :: Ptr CRegex -> CInt -> CSize -> IO (Ptr CRegex)
+
+-- cbits/myfree.h and cbits/myfree.c
+foreign import ccall unsafe "&hs_regex_regfree"
+  c_myregfree :: FunPtr (Ptr CRegex -> IO ())
+
+foreign import ccall unsafe "regex.h regcomp"
+  c_regcomp :: Ptr CRegex -> CString -> CompOption -> IO ReturnCode
+
+{- currently unused
+foreign import ccall unsafe "regex.h &regfree"
+  c_regfree :: FunPtr (Ptr CRegex -> IO ())
+-}
+
+foreign import ccall unsafe "regex.h regexec"
+  c_regexec :: Ptr CRegex -> CString -> CSize
+            -> Ptr CRegMatch -> ExecOption -> IO ReturnCode
+
+foreign import ccall unsafe "regex.h regerror"
+  c_regerror :: ReturnCode -> Ptr CRegex
+             -> CString -> CSize -> IO CSize
+
+retOk :: ReturnCode
+retOk = ReturnCode 0
+
+-- Flags for regexec
+#enum ExecOption,ExecOption, \
+  execNotBOL = REG_NOTBOL, \
+  execNotEOL = REG_NOTEOL
+
+-- Flags for regcomp
+#enum CompOption,CompOption, \
+  compExtended = REG_EXTENDED, \
+  compIgnoreCase = REG_ICASE, \
+  compNoSub = REG_NOSUB, \
+  compNewline = REG_NEWLINE
+
+-- Return values from regexec (REG_NOMATCH, REG_ESPACE,...)
+-- Error codes from regcomp (not REG_NOMATCH)
+-- Though calling retNoMatch an error is rather missing the point...
+#enum ReturnCode,ReturnCode, \
+  retNoMatch = REG_NOMATCH, \
+  retBadbr = REG_BADBR, \
+  retBadpat = REG_BADPAT, \
+  retBadrpt = REG_BADRPT, \
+  retEcollate = REG_ECOLLATE, \
+  retEctype = REG_ECTYPE, \
+  retEescape = REG_EESCAPE, \
+  retEsubreg = REG_ESUBREG, \
+  retEbrack = REG_EBRACK, \
+  retEparen = REG_EPAREN, \
+  retEbrace = REG_EBRACE, \
+  retErange = REG_ERANGE, \
+  retEspace = REG_ESPACE
+----
+-- error helpers
+
+nullTest :: Ptr a -> String -> IO (Either WrapError b) -> IO (Either WrapError b)
+{-# INLINE nullTest #-}
+nullTest ptr msg io = do
+  if nullPtr == ptr
+    then return (Left (retOk,"Ptr parameter was nullPtr in Text.Regex.TRE.Wrap."++msg))
+    else io
+
+isNewline,isNull :: Ptr CChar -> Int -> IO Bool
+isNewline cstr pos = liftM (newline ==) (peekElemOff cstr pos)
+  where newline = toEnum 10
+isNull cstr pos = liftM (nullChar ==) (peekElemOff cstr pos)
+  where nullChar = toEnum 0
+
+{-
+wrapRC :: ReturnCode -> IO (Either WrapError b)
+{-# INLINE wrapRC #-}
+wrapRC r = return (Left (r,"Error in Text.Regex.Posix.Wrap: "++show r))
+-}
+wrapError :: ReturnCode -> Ptr CRegex -> IO (Either WrapError b)
+wrapError errCode regex_ptr = do
+  -- Call once to compute the error message buffer size
+  errBufSize <- c_regerror errCode regex_ptr nullPtr 0
+  -- Allocate a temporary buffer to hold the error message
+  allocaArray (fromIntegral errBufSize) $ \errBuf -> do
+   nullTest errBuf "wrapError errBuf" $ do
+    _ <- c_regerror errCode regex_ptr errBuf errBufSize
+    msg <- peekCAString errBuf :: IO String
+    return (Left (errCode, msg))
+
+----------
+wrapCompile flags e pattern = do
+ nullTest pattern "wrapCompile pattern" $ do
+  e_regex_ptr <- try $ mallocBytes (#const sizeof(regex_t)) -- ioError called if nullPtr
+  case e_regex_ptr of
+    Left ioerror -> return (Left (retOk,"Text.Regex.Posix.Wrap.wrapCompile: IOError from mallocBytes(regex_t) : "++show ioerror))
+    Right raw_regex_ptr -> do
+      zero_regex_ptr <- c_memset raw_regex_ptr 0 (#const sizeof(regex_t)) -- no calloc, so clear the new area to zero
+      regex_fptr <- newForeignPtr c_myregfree zero_regex_ptr -- once pointed-to area is clear it should be safe to add finalizer
+      withForeignPtr regex_fptr $ \regex_ptr -> do  -- withForeignPtr is best hygiene here
+        errCode <- c_regcomp regex_ptr pattern flags
+        if (errCode == retOk)
+          then return . Right $ Regex regex_fptr flags e
+          else wrapError errCode regex_ptr
+
+---------
+wrapTest (Regex regex_fptr _ flags) cstr = do
+ nullTest cstr "wrapTest" $ do
+  withForeignPtr regex_fptr $ \regex_ptr -> do
+    r <- c_regexec regex_ptr cstr 0 nullPtr flags
+    if r == retOk
+      then return (Right True)
+      else if r == retNoMatch
+              then return (Right False)
+              else wrapError r regex_ptr
+
+---------
+wrapMatch regex@(Regex regex_fptr compileOptions flags) cstr = do
+ nullTest cstr "wrapMatch cstr" $ do
+  if (0 /= compNoSub .&. compileOptions)
+    then do
+      r <- wrapTest regex cstr
+      case r of
+        Right True -> return (Right (Just [])) -- Source of much "wtf?" crap
+        Right False -> return (Right Nothing)
+        Left err -> return (Left err)
+    else do
+      withForeignPtr regex_fptr $ \regex_ptr -> do
+        nsub <- (#peek regex_t, re_nsub) regex_ptr :: IO CSize
+        let nsub_int,nsub_bytes :: Int
+            nsub_int = fromIntegral nsub
+            nsub_bytes = ((1 + nsub_int) * (#const sizeof(regmatch_t)))
+        -- add one because index zero covers the whole match
+        allocaBytes nsub_bytes $ \p_match -> do
+         nullTest p_match "wrapMatch allocaBytes" $ do
+          doMatch regex_ptr cstr nsub p_match flags
+
+-- Very very thin wrapper
+-- Requires, but does not check, that nsub>=0
+-- Cannot return (Right (Just []))
+doMatch :: Ptr CRegex -> CString -> CSize -> Ptr CRegMatch -> ExecOption
+        -> IO (Either WrapError (Maybe [(RegOffset,RegOffset)]))
+{-# INLINE doMatch #-}
+doMatch regex_ptr cstr nsub p_match flags = do
+  r <- c_regexec regex_ptr cstr (1 + nsub) p_match flags
+  if r == retOk
+    then do
+       regions <- mapM getOffsets . take (1+fromIntegral nsub)
+                  . iterate (`plusPtr` (#const sizeof(regmatch_t))) $ p_match
+       return (Right (Just regions)) -- regions will not be []
+    else if r == retNoMatch
+       then return (Right Nothing)
+       else wrapError r regex_ptr
+  where
+    getOffsets :: Ptr CRegMatch -> IO (RegOffset,RegOffset)
+    {-# INLINE getOffsets #-}
+    getOffsets pmatch' = do
+      start <- (#peek regmatch_t, rm_so) pmatch' :: IO (#type regoff_t)
+      end   <- (#peek regmatch_t, rm_eo) pmatch' :: IO (#type regoff_t)
+      return (fromIntegral start,fromIntegral end)
+
+wrapMatchAll regex@(Regex regex_fptr compileOptions flags) cstr = do
+ nullTest cstr "wrapMatchAll cstr" $ do
+  if (0 /= compNoSub .&. compileOptions)
+    then do
+      r <- wrapTest regex cstr
+      case r of
+        Right True -> return (Right [(toMA 0 [])]) -- Source of much "wtf?" crap
+        Right False -> return (Right [])
+        Left err -> return (Left err)
+    else do
+      withForeignPtr regex_fptr $ \regex_ptr -> do
+        nsub <- (#peek regex_t, re_nsub) regex_ptr :: IO CSize
+        let nsub_int,nsub_bytes :: Int
+            nsub_int = fromIntegral nsub
+            nsub_bytes = ((1 + nsub_int) * (#const sizeof(regmatch_t)))
+        -- add one because index zero covers the whole match
+        allocaBytes nsub_bytes $ \p_match -> do
+         nullTest p_match "wrapMatchAll p_match" $ do
+          let flagsBOL = (complement execNotBOL) .&. flags
+              flagsMIDDLE = execNotBOL .|. flags
+              atBOL pos = doMatch regex_ptr (plusPtr cstr pos) nsub p_match flagsBOL
+              atMIDDLE pos = doMatch regex_ptr (plusPtr cstr pos) nsub p_match flagsMIDDLE
+              loop acc old (s,e) | acc `seq` old `seq` False = undefined
+                                 | s == e = do
+                let pos = old + fromIntegral e -- pos may be 0
+                atEnd <- isNull cstr pos
+                if atEnd then return (Right (acc []))
+                  else loop acc old (s,succ e)
+                                 | otherwise = do
+                let pos = old + fromIntegral e -- pos must be greater than 0 (tricky but true)
+                prev'newline <- isNewline cstr (pred pos) -- safe
+                result <- if prev'newline then atBOL pos else atMIDDLE pos
+                case result of
+                  Right Nothing -> return (Right (acc []))
+                  Right (Just parts@(whole:_)) -> let ma = toMA pos parts
+                                                 in loop (acc.(ma:)) pos whole
+                  Left err -> return (Left err)
+                  Right (Just []) -> return (Right (acc [(toMA pos [])])) -- should never happen
+          result <- doMatch regex_ptr cstr nsub p_match flags
+          case result of
+            Right Nothing -> return (Right [])
+            Right (Just parts@(whole:_)) -> let ma = toMA 0 parts
+                                            in loop (ma:) 0 whole
+            Left err -> return (Left err)
+            Right (Just []) -> return (Right [(toMA 0 [])]) -- should never happen
+  where
+    toMA :: Int -> [(RegOffset,RegOffset)] -> Array Int (Int,Int)
+    toMA pos [] = listArray (0,0) [(pos,0)] -- wtf?
+    toMA pos parts = listArray (0,pred (length parts))
+      . map (\(s,e)-> if s>=0 then (pos+fromIntegral s, fromIntegral (e-s)) else (-1,0))
+      $ parts
+
+---------
+wrapCount regex@(Regex regex_fptr compileOptions flags) cstr = do
+ nullTest cstr "wrapCount cstr" $ do
+  if (0 /= compNoSub .&. compileOptions)
+    then do
+      r <- wrapTest regex cstr
+      case r of
+        Right True -> return (Right 1)
+        Right False -> return (Right 0)
+        Left err -> return (Left err)
+    else do
+      withForeignPtr regex_fptr $ \regex_ptr -> do
+        let nsub_bytes = (#size regmatch_t)
+        allocaBytes nsub_bytes $ \p_match -> do
+         nullTest p_match "wrapCount p_match" $ do
+          let flagsBOL = (complement execNotBOL) .&. flags
+              flagsMIDDLE = execNotBOL .|. flags
+              atBOL pos = doMatch regex_ptr (plusPtr cstr pos) 0 p_match flagsBOL
+              atMIDDLE pos = doMatch regex_ptr (plusPtr cstr pos) 0 p_match flagsMIDDLE
+              loop acc old (s,e) | acc `seq` old `seq` False = undefined
+                                 | s == e = do
+                let pos = old + fromIntegral e -- 0 <= pos
+                atEnd <- isNull cstr pos
+                if atEnd then return (Right acc)
+                  else loop acc old (s,succ e)
+                                 | otherwise = do
+                let pos = old + fromIntegral e -- 0 < pos
+                prev'newline <- isNewline cstr (pred pos) -- safe
+                result <- if prev'newline then atBOL pos else atMIDDLE pos
+                case result of
+                  Right Nothing -> return (Right acc)
+                  Right (Just (whole:_)) -> loop (succ acc) pos whole
+                  Left err -> return (Left err)
+                  Right (Just []) -> return (Right acc) -- should never happen
+          result <- doMatch regex_ptr cstr 0 p_match flags
+          case result of
+            Right Nothing -> return (Right 0)
+            Right (Just (whole:_)) -> loop 1 0 whole
+            Left err -> return (Left err)
+            Right (Just []) -> return (Right 0) -- should never happen
+
+{-
+
+-- This is the slower 0.66 version of the code (91s instead of 79s on 10^6 bytes)
+
+wrapMatchAll regex cstr = do
+  let regex' = setExecOpts (execNotBOL .|. (getExecOpts regex)) regex
+      at pos = wrapMatch regex' (plusPtr cstr pos)
+      loop old (s,e) | s == e = return []
+                     | otherwise = do
+        let pos = old + fromIntegral e
+        result <- at pos
+        case unwrap result of
+          Nothing -> return []
+          Just [] -> return ((toMA pos []):[]) -- wtf?
+          Just parts@(whole:_) -> do rest <- loop pos whole
+                                     return ((toMA pos parts) : rest)
+  result <- wrapMatch regex cstr
+  case unwrap result of
+    Nothing -> return []
+    Just [] -> return ((toMA 0 []):[]) -- wtf?
+    Just parts@(whole:_) -> do rest <- loop 0 whole
+                               return ((toMA 0 parts) : rest)
+---------
+-- This was also changed to match wrapMatchAll after 0.66
+wrapCount regex cstr = do
+  let regex' = setExecOpts (execNotBOL .|. (getExecOpts regex)) regex
+      at pos = wrapMatch regex' (plusPtr cstr pos)
+      loop acc old (s,e) | acc `seq` old `seq` False = undefined
+                         | s == e = return acc
+                         | otherwise = do
+        let pos = old + fromIntegral e
+        result <- at pos
+        case unwrap result of
+          Nothing -> return acc
+          Just [] -> return (succ acc) -- wtf?
+          Just (whole:_) -> loop (succ acc) pos whole
+  result <- wrapMatch regex cstr
+  case unwrap result of
+    Nothing -> return 0
+    Just [] -> return 1 -- wtf?
+    Just (whole:_) -> loop 1 0 whole
+-}
