packages feed

hsshellscript 3.3.4 → 3.4.0

raw patch · 19 files changed

+1587/−1042 lines, 19 filesdep ~basedep ~directoryPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base, directory

API changes (from Hackage documentation)

- HsShellScript.Commands: cd :: String -> IO ()
- HsShellScript.Commands: chmod :: [String] -> IO ()
- HsShellScript.Commands: chown :: [String] -> IO ()
- HsShellScript.Commands: cp :: String -> String -> IO ()
- HsShellScript.Commands: du :: (Integral int, Read int, Show int) => int -> String -> IO int
- HsShellScript.Commands: fdupes :: [String] -> [String] -> IO [[[String]]]
- HsShellScript.Commands: force_cmd :: (String -> String -> IO ()) -> String -> String -> IO ()
- HsShellScript.Commands: force_mv :: String -> String -> IO ()
- HsShellScript.Commands: force_rename :: String -> String -> IO ()
- HsShellScript.Commands: force_rename_mv :: FilePath -> FilePath -> IO ()
- HsShellScript.Commands: force_writeable :: String -> IO a -> IO a
- HsShellScript.Commands: force_writeable2 :: String -> IO (String, a) -> IO a
- HsShellScript.Commands: foreign_rename :: (Ptr CChar) -> ((Ptr CChar) -> (IO CInt))
- HsShellScript.Commands: foreign_symlink :: (Ptr CChar) -> ((Ptr CChar) -> (IO CInt))
- HsShellScript.Commands: hsshellscript_get_readlink :: (Ptr CChar) -> (IO (Ptr CChar))
- HsShellScript.Commands: hsshellscript_get_realpath :: (Ptr CChar) -> (IO (Ptr CChar))
- HsShellScript.Commands: is_symlink :: String -> IO Bool
- HsShellScript.Commands: mkdir :: String -> IO ()
- HsShellScript.Commands: mt_status :: IO (Int, Int)
- HsShellScript.Commands: mv :: String -> String -> IO ()
- HsShellScript.Commands: number :: Parser Int
- HsShellScript.Commands: parse_mt_status :: Parser (Int, Int)
- HsShellScript.Commands: pwd :: IO String
- HsShellScript.Commands: readlink :: String -> IO String
- HsShellScript.Commands: readlink' :: String -> IO String
- HsShellScript.Commands: realpath :: String -> IO String
- HsShellScript.Commands: realpath_s :: String -> IO String
- HsShellScript.Commands: rename :: String -> String -> IO ()
- HsShellScript.Commands: rename_mv :: FilePath -> FilePath -> IO ()
- HsShellScript.Commands: replace_location :: String -> String -> IO a -> IO a
- HsShellScript.Commands: rm :: String -> IO ()
- HsShellScript.Commands: rmdir :: String -> IO ()
- HsShellScript.Commands: symlink :: String -> String -> IO ()
- HsShellScript.Commands: with_wd :: FilePath -> IO a -> IO a
- HsShellScript.GetOpt: NoArg :: a -> ArgDescr a
- HsShellScript.GetOpt: OptArg :: (Maybe String -> a) -> String -> ArgDescr a
- HsShellScript.GetOpt: Option :: [Char] -> [String] -> (ArgDescr a) -> String -> OptDescr a
- HsShellScript.GetOpt: Permute :: ArgOrder a
- HsShellScript.GetOpt: ReqArg :: (String -> a) -> String -> ArgDescr a
- HsShellScript.GetOpt: RequireOrder :: ArgOrder a
- HsShellScript.GetOpt: ReturnInOrder :: (String -> a) -> ArgOrder a
- HsShellScript.GetOpt: data ArgDescr a
- HsShellScript.GetOpt: data ArgOrder a
- HsShellScript.GetOpt: data OptDescr a
- HsShellScript.GetOpt: getOpt :: ArgOrder a -> [OptDescr a] -> [String] -> ([a], [String], [String])
- HsShellScript.GetOpt: usageInfo :: String -> [OptDescr a] -> String
- HsShellScript.Misc: Mntent :: String -> String -> String -> String -> Int -> Int -> Mntent
- HsShellScript.Misc: [mnt_dir] :: Mntent -> String
- HsShellScript.Misc: [mnt_freq] :: Mntent -> Int
- HsShellScript.Misc: [mnt_fsname] :: Mntent -> String
- HsShellScript.Misc: [mnt_opts] :: Mntent -> String
- HsShellScript.Misc: [mnt_passno] :: Mntent -> Int
- HsShellScript.Misc: [mnt_type] :: Mntent -> String
- HsShellScript.Misc: c_close :: CInt -> (IO CInt)
- HsShellScript.Misc: c_getmntent :: (Ptr ()) -> (IO (Ptr ()))
- HsShellScript.Misc: c_mkdir :: (Ptr CChar) -> (CUInt -> (IO CInt))
- HsShellScript.Misc: chomp :: String -> String
- HsShellScript.Misc: contents :: String -> IO String
- HsShellScript.Misc: data Mntent
- HsShellScript.Misc: do_glob :: (Ptr ()) -> ((Ptr CChar) -> (IO CInt))
- HsShellScript.Misc: endmntent :: (Ptr ()) -> (IO CInt)
- HsShellScript.Misc: fileAccess' :: FilePath -> Bool -> Bool -> Bool -> IO Bool
- HsShellScript.Misc: getFileStatus' :: FilePath -> IO FileStatus
- HsShellScript.Misc: glob :: String -> IO [String]
- HsShellScript.Misc: globfree :: (Ptr ()) -> (IO ())
- HsShellScript.Misc: hsshellscript_open_nonvariadic :: (Ptr CChar) -> (CInt -> (CUInt -> (IO CInt)))
- HsShellScript.Misc: instance GHC.Classes.Eq HsShellScript.Misc.Mntent
- HsShellScript.Misc: instance GHC.Read.Read HsShellScript.Misc.Mntent
- HsShellScript.Misc: instance GHC.Show.Show HsShellScript.Misc.Mntent
- HsShellScript.Misc: is_dir :: String -> IO Bool
- HsShellScript.Misc: is_file :: String -> IO Bool
- HsShellScript.Misc: lazy_contents :: String -> IO String
- HsShellScript.Misc: o_CREAT :: CInt
- HsShellScript.Misc: o_EXCL :: CInt
- HsShellScript.Misc: path_exists :: String -> IO Bool
- HsShellScript.Misc: path_exists' :: String -> IO Bool
- HsShellScript.Misc: read_fstab :: IO [Mntent]
- HsShellScript.Misc: read_mounts :: String -> IO [Mntent]
- HsShellScript.Misc: read_mtab :: IO [Mntent]
- HsShellScript.Misc: setmntent :: (Ptr CChar) -> ((Ptr CChar) -> (IO (Ptr ())))
- HsShellScript.Misc: temp_dir :: Int -> String -> String -> IO FilePath
- HsShellScript.Misc: temp_file :: Int -> String -> String -> IO FilePath
- HsShellScript.Misc: temp_path :: Int -> String -> String -> IO FilePath
- HsShellScript.Misc: tmp_dir :: String -> IO FilePath
- HsShellScript.Misc: tmp_file :: String -> IO FilePath
- HsShellScript.Misc: untilIO :: Monad m => m b -> (b -> m Bool) -> m b
- HsShellScript.Misc: with_temp_dir :: Int -> String -> String -> (FilePath -> IO a) -> IO a
- HsShellScript.Misc: with_temp_file :: Int -> String -> String -> (Handle -> IO a) -> IO a
- HsShellScript.Misc: with_tmp_dir :: String -> (FilePath -> IO a) -> IO a
- HsShellScript.Misc: with_tmp_file :: String -> (Handle -> IO a) -> IO a
- HsShellScript.Misc: zeros :: Int -> Int -> String
- HsShellScript.ProcErr: (-&>-) :: IO a -> FilePath -> IO a
- HsShellScript.ProcErr: (-&>>-) :: IO a -> FilePath -> IO a
- HsShellScript.ProcErr: (-<-) :: IO a -> FilePath -> IO a
- HsShellScript.ProcErr: (->-) :: IO a -> FilePath -> IO a
- HsShellScript.ProcErr: (->>-) :: IO a -> FilePath -> IO a
- HsShellScript.ProcErr: (-|-) :: IO a -> IO b -> IO a
- HsShellScript.ProcErr: (-|=) :: IO a -> IO b -> IO b
- HsShellScript.ProcErr: (=>-) :: IO a -> FilePath -> IO a
- HsShellScript.ProcErr: (=>>-) :: IO a -> FilePath -> IO a
- HsShellScript.ProcErr: (=|-) :: IO a -> IO b -> IO a
- HsShellScript.ProcErr: (=|=) :: IO a -> IO b -> IO b
- HsShellScript.ProcErr: RunError :: String -> [String] -> [(String, String)] -> String -> ProcessStatus -> Maybe CInt -> RunError
- HsShellScript.ProcErr: [re_env] :: RunError -> [(String, String)]
- HsShellScript.ProcErr: [re_errno] :: RunError -> Maybe CInt
- HsShellScript.ProcErr: [re_pars] :: RunError -> [String]
- HsShellScript.ProcErr: [re_prog] :: RunError -> String
- HsShellScript.ProcErr: [re_ps] :: RunError -> ProcessStatus
- HsShellScript.ProcErr: [re_wd] :: RunError -> String
- HsShellScript.ProcErr: _exit :: Int -> IO a
- HsShellScript.ProcErr: _exit_prim :: CInt -> (IO ())
- HsShellScript.ProcErr: add_location :: String -> IO a -> IO a
- HsShellScript.ProcErr: as_ioe :: IO a -> IO a
- HsShellScript.ProcErr: c_close_on_exec :: CInt -> (IO CInt)
- HsShellScript.ProcErr: c_fcntl_dupfd :: CInt -> (CInt -> (IO CInt))
- HsShellScript.ProcErr: c_prepare_fd_flags_for_exec :: IO ()
- HsShellScript.ProcErr: c_restore_fdflags :: (Ptr CInt) -> (IO ())
- HsShellScript.ProcErr: c_save_fdflags :: IO (Ptr CInt)
- HsShellScript.ProcErr: call :: IO a -> IO ()
- HsShellScript.ProcErr: child :: IO a -> IO b
- HsShellScript.ProcErr: close :: CInt -> (IO CInt)
- HsShellScript.ProcErr: data RunError
- HsShellScript.ProcErr: decode_ioerror :: String -> Maybe IOError
- HsShellScript.ProcErr: dup2 :: CInt -> (CInt -> (IO CInt))
- HsShellScript.ProcErr: echo :: (FilePath -> [String] -> IO ()) -> FilePath -> [String] -> IO ()
- HsShellScript.ProcErr: encode_ioerror :: IOError -> String
- HsShellScript.ProcErr: err_to_out :: IO a -> IO a
- HsShellScript.ProcErr: errm :: String -> IO ()
- HsShellScript.ProcErr: errm_ :: String -> IO ()
- HsShellScript.ProcErr: errno :: IO Errno
- HsShellScript.ProcErr: exec :: String -> [String] -> IO a
- HsShellScript.ProcErr: exece :: String -> [String] -> [(String, String)] -> IO a
- HsShellScript.ProcErr: execp :: String -> [String] -> IO a
- HsShellScript.ProcErr: execpe :: String -> [String] -> [(String, String)] -> IO a
- HsShellScript.ProcErr: execute_file :: FilePath -> Bool -> [String] -> Maybe [(String, String)] -> IO a
- HsShellScript.ProcErr: exitcode :: IO () -> IO ExitCode
- HsShellScript.ProcErr: explain_processstatus :: ProcessStatus -> String
- HsShellScript.ProcErr: failIO :: String -> IO a
- HsShellScript.ProcErr: fill_in_filename :: String -> IO a -> IO a
- HsShellScript.ProcErr: fill_in_location :: String -> IO a -> IO a
- HsShellScript.ProcErr: flush_outerr :: IO ()
- HsShellScript.ProcErr: foreign_strerror :: CInt -> (Ptr CChar)
- HsShellScript.ProcErr: h_pipe_from :: IO a -> IO (Handle, ProcessID)
- HsShellScript.ProcErr: h_pipe_from2 :: IO a -> IO (Handle, ProcessID)
- HsShellScript.ProcErr: h_pipe_to :: IO a -> IO (Handle, ProcessID)
- HsShellScript.ProcErr: hssh_c_isatty :: CInt -> (IO CInt)
- HsShellScript.ProcErr: instance GHC.Classes.Eq HsShellScript.ProcErr.RunError
- HsShellScript.ProcErr: instance GHC.Exception.Exception HsShellScript.ProcErr.RunError
- HsShellScript.ProcErr: instance GHC.Exception.Exception System.Posix.Process.Internals.ProcessStatus
- HsShellScript.ProcErr: instance GHC.Show.Show Foreign.C.Error.Errno
- HsShellScript.ProcErr: instance GHC.Show.Show HsShellScript.ProcErr.RunError
- HsShellScript.ProcErr: ioe_types :: [(IOErrorType, Integer)]
- HsShellScript.ProcErr: ioetype_num :: IOError -> Integer
- HsShellScript.ProcErr: isatty :: Handle -> IO Bool
- HsShellScript.ProcErr: lazy_pipe_from :: IO a -> IO (String, ProcessID)
- HsShellScript.ProcErr: lazy_pipe_from2 :: IO a -> IO (String, ProcessID)
- HsShellScript.ProcErr: logm :: String -> IO ()
- HsShellScript.ProcErr: logm_ :: String -> IO ()
- HsShellScript.ProcErr: num_ioetype :: Integer -> IOErrorType
- HsShellScript.ProcErr: out_to_err :: IO a -> IO a
- HsShellScript.ProcErr: outm :: String -> IO ()
- HsShellScript.ProcErr: outm_ :: String -> IO ()
- HsShellScript.ProcErr: perror :: String -> IO ()
- HsShellScript.ProcErr: perror' :: Errno -> String -> IO ()
- HsShellScript.ProcErr: pipe_fork_dup :: IO a -> Bool -> Bool -> Bool -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessID)
- HsShellScript.ProcErr: pipe_from :: IO a -> IO String
- HsShellScript.ProcErr: pipe_from2 :: IO a -> IO String
- HsShellScript.ProcErr: pipe_to :: String -> IO a -> IO ()
- HsShellScript.ProcErr: pipes :: IO a -> Bool -> Bool -> Bool -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessID)
- HsShellScript.ProcErr: receive_ioerror :: Fd -> IO (Maybe IOError)
- HsShellScript.ProcErr: redirect :: Handle -> Handle -> IO a -> IO a
- HsShellScript.ProcErr: redirect_helper :: Handle -> IOMode -> IO b -> FilePath -> IO b
- HsShellScript.ProcErr: run :: FilePath -> [String] -> IO ()
- HsShellScript.ProcErr: runprog :: FilePath -> [String] -> IO ()
- HsShellScript.ProcErr: send_ioerror :: Fd -> IOError -> IO ()
- HsShellScript.ProcErr: setFileMode' :: FilePath -> FileMode -> IO ()
- HsShellScript.ProcErr: show_ioerror :: IOError -> String
- HsShellScript.ProcErr: show_runerror :: RunError -> String
- HsShellScript.ProcErr: silently :: IORef String -> IO () -> IO ()
- HsShellScript.ProcErr: spawn :: IO a -> IO ProcessID
- HsShellScript.ProcErr: spawn_loc :: String -> IO a -> IO ProcessID
- HsShellScript.ProcErr: strerror :: Errno -> IO String
- HsShellScript.ProcErr: subproc :: IO a -> IO ()
- HsShellScript.ProcErr: system_runprog :: String -> IO ()
- HsShellScript.ProcErr: system_throw :: String -> IO ()
- HsShellScript.ProcErr: throwErrno' :: String -> Maybe Handle -> Maybe FilePath -> IO a
- HsShellScript.ProcErr: to_ioe :: RunError -> IOError
- HsShellScript.ProcErr: unsafeWithHandleFd :: Handle -> (Fd -> IO a) -> IO a
- HsShellScript.ProcErr: unsafeWithHandleFd' :: Handle -> MVar Handle__ -> (Fd -> IO a) -> IO a
+ HsShellScript: glob_quote :: String -> String
+ HsShellScript: infixl 2 =|=
+ HsShellScript: infixl 3 -&>>-
+ HsShellScript: infixr 2 =|-
+ HsShellScript.Args: is_direct :: ArgumentDescription -> Bool
+ HsShellScript.Args: make_usage_info :: [ArgumentDescription] -> Int -> Int -> Int -> [String]
+ HsShellScript.Args: print_usage_info :: Handle -> String -> [ArgumentDescription] -> IO ()
+ HsShellScript.Args: terminal_width :: Handle -> IO (Maybe Int)
+ HsShellScript.Args: terminal_width_ioe :: Handle -> IO Int
+ HsShellScript.Args: wrap :: Int -> String -> [String]

Files

Makefile view
@@ -1,5 +1,5 @@ # nächste Version:-VERSION = 3.3.4+VERSION = 3.4.0  default :: lib 
hsshellscript.cabal view
@@ -1,5 +1,5 @@ Name:                hsshellscript-Version:             3.3.4+Version:             3.4.0 Synopsis:            Haskell for Unix shell scripting tasks Description:         A Haskell-library for tasks which are usually done in                      shell scripts. This includes parsing command line@@ -21,14 +21,14 @@   Library-  Exposed-Modules:   HsShellScript,+  Exposed-Modules:   HsShellScript                      HsShellScript.Args-                     HsShellScript.Commands+                     HsShellScript.Paths+                     HsShellScript.Shell+  Other-Modules:     HsShellScript.Commands                      HsShellScript.GetOpt                      HsShellScript.Misc-                     HsShellScript.Paths                      HsShellScript.ProcErr-                     HsShellScript.Shell   Extensions:        DeriveDataTypeable,                      ForeignFunctionInterface,                      RecordWildCards,@@ -37,7 +37,6 @@                      StandaloneDeriving   Build-depends:     base >= 3 && < 6,                      unix >= 2.3.2,-                     -- unix-compat,                      directory,                      parsec >= 2.1.0.1,                      random
src/HsShellScript.hs view
@@ -71,7 +71,7 @@               isatty,                -- * Miscellaneous-              zeros, chomp, lazy_contents, contents, glob,+              zeros, chomp, lazy_contents, contents, glob, glob_quote,                -- * Error Handling               mainwrapper, errno,@@ -87,12 +87,6 @@          ) where --- import IO--- import List--- import Maybe--- import Monad--- import Random--- import System import Control.Exception import GHC.IO import HsShellScript.Args
+ src/HsShellScript/Args.chs view
@@ -0,0 +1,1250 @@+-- |+-- This module provides a more convient way of parsing command line+-- arguments than the GHC GetOpt package. It uses GetOpt, but hides+-- it from the user. It is reexported from module HsShellScript.+--+-- For each command line argument, a description is to be created with+-- @argdesc@. Then the command line arguments are evaluated with+-- one of the @getargs@... functions. In case of an error, this will cause a+-- exception, which provides an expressive error message to be+-- printed. Then the @arg@... functions are used to extract the+-- values contained in the arguments, with the right type. The typical use+-- of HsShellScript.Args looks something like this:+--+-- >import HsShellScript+-- >+-- >main =+-- >   do let a_onevalue = argdesc [ desc_at_most_once, ... ]+-- >          a_values   = argdesc [ desc_direct, ... ]+-- >          a_switch   = argdesc [ ... ]+-- >          ...+-- >          header = "mclapep - My Command Line Argument Parser Example Program, version 1.0.0"+-- >+-- >      args <- getargs header [a_onevalue, a_values, a_switch, ...]+-- >+-- >      val  <- optarg_req a_onevalue args        -- val  :: Maybe String+-- >      vals <- args_req   a_values args          -- vals :: [String]+-- >      doit <- arg_switch a_switch args          -- doit :: Bool+-- >      ...+-- >   `catch`+-- >      (\argerror -> do+-- >          hPutStrLn stderr $ (argerror_message argerror) ++ "\n\n" ++ (argerror_usageinfo argerror)+-- >          exitFailure+-- >      )+--+-- Errors in the argument descriptions are regarded as bugs, and handled+-- by aborting the program with a message which is meaningful to the+-- programmer. It is assumed that the argument description is a constant for+-- a given program.+--+-- Errors in the arguments are reported using HsShellScript's error handling+-- scheme. An error description+-- value is generated, and either returned via an @Either@+-- value, or thrown as an exception.++module HsShellScript.Args ( -- ** Argument Properties+                    ArgumentProperty+                  , ArgumentDescription (..)+                  , ArgumentValueSpec (..)+                  , Argtester+                  , argdesc+                  , desc_short+                  , desc_long+                  , desc_direct+                  , desc_value_required+                  , desc_value_optional+                  , desc_times+                  , desc_once+                  , desc_at_least_once+                  , desc_at_most_once+                  , desc_any_times+                  , desc_at_least+                  , desc_at_most+                  , desc_argname+                  , desc_description+                  , desc_tester+                  , desc_integer+                  , desc_nonneg_integer+                  , readtester+                  , is_direct+                    -- ** Evaluating the Command Line+                  , Arguments+                  , getargs+                  , getargs_ordered+                  , getargs'+                  , getargs_ordered'+                  , unsafe_getargs+                  , unsafe_getargs_ordered+                    -- ** Extracting the Argument Values+                  , arg_switch+                  , arg_times+                  , args_opt+                  , args_req+                  , reqarg_opt+                  , reqarg_req+                  , optarg_opt+                  , optarg_req+                  , arg_occurs+                    -- ** Placing additional Constraints on the Arguments+                  , args_none+                  , args_all+                  , args_one+                  , args_at_most_one+                  , args_at_least_one+                  , arg_conflicts+                    -- ** Argument Error Reporting+                  , ArgError (..)+                  , usage_info+                  , make_usage_info+                  , print_usage_info+                  , argname+                  , argname_a+                  , wrap+                  , terminal_width+                  , terminal_width_ioe+                  ) where++-- We use a fixed copy of GHC's GetOpt implementation. This is to work around a bug.+-- import System.Console.GetOpt+import HsShellScript.GetOpt+import {-# SOURCE #-} HsShellScript.ProcErr++import Foreign.C+import System.Environment+import Control.Monad+import Control.Exception+import Prelude hiding (catch)+import Data.Maybe+import System.Environment+import Data.List+import GHC.IO+import System.IO+import HsShellScript.Shell+import Data.Char+import Debug.Trace+import Data.Typeable+++++-- | Does the command line argument take an value?+data ArgumentValueSpec  = ArgumentValue_none     -- ^ No value+                        | ArgumentValue_required -- ^ Value required+                        | ArgumentValue_optional -- ^ Value optional+   deriving (Eq, Show, Ord)+++-- | Argument value tester function. This tests the format of an argument's value for errors. The tester function is specified by+-- 'desc_tester' or such, as part of the argument description.+--+-- The tester is passed the argument value. If the format is correct, then it returns @Nothing@. If there is an error, then it returns @Just msgf@,+-- with @msgf@ being an error message generation function. This function gets passed the argument description, and produces the error+-- message. The argument description typically is used to extract a descriptive name of the argument (using 'argname' or 'argname_a') to be included+-- in the error message.+type Argtester = String                           -- Argument value to be tested+                 -> Maybe (ArgumentDescription    -- Argument description for message generation+                           -> String              -- Error message+                          )+++-- | Description of one command line argument. These are generated by+-- @argdesc@ from a list of argument properties, and subsequently used by one of the+-- @getargs@... functions. This type is abstract.+data ArgumentDescription = ArgumentDescription {+        argdesc_short_args :: [Char],                           -- ^ Short option names+        argdesc_long_args :: [String],                          -- ^ Long option names+        argdesc_argarg :: ArgumentValueSpec,                    -- ^ What about a possible value of the argument?+        argdesc_times :: Maybe (Int,Int),                       -- ^ Minimum and maximum of number of occurences allowed+        argdesc_argargname :: Maybe String,                     -- ^ Name for argument's value, for message generation+        argdesc_argarg_description :: Maybe String,             -- ^ Descrition of the argument, for message generation+        argdesc_argarg_tester :: Maybe Argtester                -- ^ Argument value tester+      }++-- excluding tester+ad_tup ad =+   (argdesc_short_args ad, argdesc_long_args ad, argdesc_argarg ad, argdesc_times ad, argdesc_argargname ad, argdesc_argarg_description ad)++instance Eq ArgumentDescription where+   d == e = ad_tup d == ad_tup e++instance Ord ArgumentDescription where+   compare d e = compare (ad_tup d) (ad_tup e)++-- value for maximum number of times+unlimited = -1++-- Whether two argument descriptions describe the same argument.+-- Every short or long argument name occurs in only one argument+-- descriptor (this is checked). Every argument has a short or a long+-- name (short = [], long = [""] for direct arguments).+same_arg :: ArgumentDescription -> ArgumentDescription -> Bool+same_arg arg1 arg2 =+   case (argdesc_short_args arg1, argdesc_short_args arg2) of+      (a:_, b:_) -> a == b+      ([], [])   -> case (argdesc_long_args arg1, argdesc_long_args arg2) of+                       ([],_)  -> unnamed+                       (_,[])  -> unnamed+                       (l1,l2) -> head l1 == head l2+      _          -> False+   where unnamed = error "Bug in argument description: nameless, non-direct argument. desc_short or desc_long must be specified."++-- | A property of a command line argument. These are generated by the+-- @desc_@... functions, and condensed to argument+-- descriptions of type @ArgumentDescription@ by @argdesc@. This type is abstract.+newtype ArgumentProperty =+   ArgumentProperty { argumentproperty :: ArgumentDescription -> ArgumentDescription }+-- An argument property is a function which fills in part of an argument descriptor.+++-- starting value for argument descriptor+nulldesc :: ArgumentDescription+nulldesc =+   ArgumentDescription {+      argdesc_short_args = [],+      argdesc_long_args = [],+      argdesc_argarg = ArgumentValue_none,+      argdesc_times = Nothing,          -- default = (0,1)+      argdesc_argargname = Nothing,+      argdesc_argarg_description = Nothing,+      argdesc_argarg_tester = Nothing+   }++-- default number of times an argument may occur+times_default = (0,1)+++-- | This represents the parsed contents of the command line. It is returned+-- by the @getargs@... functions, and passed on to the+-- value extraction functions by the user.+--+-- See 'getargs', 'getargs_ordered', 'getargs\'', 'getargs_ordered\''.+newtype Arguments =+    Arguments ([ ( ArgumentDescription             -- argument descriptor+                 , [Maybe String]                  -- arguments matching this descriptor+                 )],+               String)                             -- header+++argvalues :: Arguments -> ArgumentDescription -> [Maybe String]+argvalues (Arguments (l, header)) desc =+   argvalues' l+   where+      argvalues' ((d,v):r) = if same_arg desc d then v else argvalues' r+      argvalues' []        = abort "Bug using HsShellScript: Value of unknown argument queried (add it to getarg's list)" desc++-- used internally to represent one occurence of a specific argument+type ArgOcc = (ArgumentDescription, Maybe String)+++-- | Error thrown when there is an error in the command line arguments.+--+-- The usage information is generated by the deprecated function usage_info. Better ignore this, and use the newer @make_usage_info@ or @print_usage_info@.+--+-- See 'usage_info', 'make_usage_info', 'print_usage_info'.+data ArgError = ArgError {+      -- | Error message+      argerror_message :: String,+      -- | Usage information, as generated by the now deprecated function usage_info.+      argerror_usageinfo :: String+   }+   deriving (Typeable)+++argerror_ui :: String+            -> [ArgumentDescription]+            -> a+argerror_ui mess descl =+   throw (ArgError mess (make_usage_info1 descl))+++-- |+-- Make @ArgError@ an instance of @Exception@, so we can throw and catch it, using GHC-6.10\'s new exception library.+instance Exception ArgError+++---+-- Printing an @ArgError@ will produce the error message. The usage+-- information must be printed separately, using @usage_info@.+instance Show ArgError where+   show argerror = argerror_message argerror+++-- |+-- Whether the specified argument is the direct argument. Direct arguments are+-- the ones which are specified without introducing "-" or "--", in the command+-- line, or which occur after the special argument "--".+--+-- See 'argdesc', 'desc_direct'.+is_direct :: ArgumentDescription        -- ^ Argument description, as returned by @argdesc@.+          -> Bool+is_direct desc =+   argdesc_short_args desc == [] && argdesc_long_args desc == [""]+++-- |+-- Short name of the argument. This specifies a character for a+-- one letter style argument, like @-x@. There can be specified+-- several for the same argument. Each argument needs at least+-- either a short or a long name.+desc_short :: Char                -- ^ The character to name the argument.+           -> ArgumentProperty    -- ^ The corresponding argument property.+desc_short c = ArgumentProperty+   (\desc ->+      if (c `elem` (argdesc_short_args desc))+         then abort ("Bug in HsShellScript argument description: Duplicate short argument " ++ show c ++ " specified") desc+         else if ("" `elem` argdesc_long_args desc)+                 then abort_conflict "" desc+                 else desc { argdesc_short_args = c : argdesc_short_args desc }+   )++-- |+-- Long name of the argument. This specifies a GNU style long name for the argument, which is+-- introduced by two dashes, like @--arg@ or @--arg=...@. There can be specified several names for+-- the same argument. Each argument needs at least either a short or a long name. Except for direct+-- arguments, which don't have a name.+--+-- See 'desc_direct'+desc_long :: String                     -- ^ The long name of the argument.+          -> ArgumentProperty     -- ^ The corresponding argument property.+desc_long str = ArgumentProperty+   (\desc ->+      if (str `elem` (argdesc_long_args desc))+         then abort ("Bug in HsShellScript argument description: Duplicate long argument " ++ show str ++ " specified") desc+         else if ("" `elem` argdesc_long_args desc)+                 then abort_conflict "" desc+                 else desc { argdesc_long_args = str : argdesc_long_args desc }+   )++-- |+-- Signal that this is the description of direct arguments. Direct arguments are the ones not+-- introduced by any short or long argument names (like @-x@ or @--arg@). After the special argument+-- @--@, also everything is a direct argument, even when starting with @-@ or @--@. The presence of+-- @desc_direct@ in the argument properties list signals @argdesc@ that this is the description of+-- the direct arguments. There may be at most one such description.+--+-- The @is_direct@ function can be used in order to determine if a specific+-- argument is the direct argument.+--+-- See 'is_direct'.+desc_direct :: ArgumentProperty+desc_direct = ArgumentProperty+   (\desc ->+      if argdesc_long_args desc == [] && argdesc_short_args desc == [] && argdesc_argarg desc == ArgumentValue_none+         then desc { argdesc_long_args = [""]+                   , argdesc_argarg = ArgumentValue_required+                   , argdesc_argargname = Just ""+                   }+         else abort_conflict "desc_direct conflicts with desc_long, desc_short, desc_value_required and desc_value_optional." desc+   )++-- |+-- Signal that the argument requires a value.+desc_value_required :: ArgumentProperty+desc_value_required = ArgumentProperty+   (\desc ->+      if argdesc_argarg desc == ArgumentValue_none+         then desc { argdesc_argarg = ArgumentValue_required }+         else abort_conflict "desc_value_required repeated or conflicting desc_value_optional" desc+   )++-- |+-- Signal that the argument optionally has a value. The user may or may+-- not specify a value to this argument.+desc_value_optional :: ArgumentProperty+desc_value_optional = ArgumentProperty+   (\desc ->+      if argdesc_argarg desc == ArgumentValue_none+         then desc { argdesc_argarg = ArgumentValue_optional }+         else abort_conflict "desc_value_optional repeated or conflicting desc_value_required" desc+   )++-- |+-- Specify lower and upper bound on the number of times an argument may+-- occur.+desc_times :: Int                       -- ^ Lower bound of the allowed number of argdesc_times.+           -> Int                       -- ^ Upper bound of the allowed number of argdesc_times.+           -> ArgumentProperty          -- ^ The corresponding argument property.+desc_times n m = ArgumentProperty+   (\desc ->+       if argdesc_times desc == Nothing+          then desc { argdesc_times = Just (n,m) }+          else abort_conflict "desc_times conflicting previous number of occurences specification" desc+   )++-- |+-- Signal that the argument must be present exactly once. This is+-- meaningful only for arguments which can take a value.+desc_once :: ArgumentProperty     -- ^ The corresponding argument property.+desc_once = desc_times 1 1++-- |+-- Signal that the argument must occur at least one time.+desc_at_least_once :: ArgumentProperty -- ^ The corresponding argument property.+desc_at_least_once = desc_times 1 unlimited++-- |+-- Signal that the argument must occur at most one time.+desc_at_most_once :: ArgumentProperty -- ^ The corresponding argument property.+desc_at_most_once  = desc_times 0 1++-- |+-- Signal that the argument must have at least the specified number of+-- occurences, and has no upper limit of occurences.+desc_at_least :: Int                        -- ^ Number of times.+              -> ArgumentProperty           -- ^ The corresponding argument property.+desc_at_least n = desc_times n unlimited++-- |+-- Signal that the argument may occur any number of times.+desc_any_times :: ArgumentProperty -- ^ The corresponding argument property.+desc_any_times  = desc_times 0 unlimited++-- |+-- Signal that the argument does not need to be present, and may occur at most+-- the specified number of times.+desc_at_most :: Int                     -- ^ Number of times.+             -> ArgumentProperty  -- ^ The corresponding argument property.+desc_at_most n = desc_times 0 n++-- |+-- Specify the descriptive name for command line argument's value. Used for the+-- generation of the usage message. The name should be very short.+desc_argname :: String                          -- ^ Name of the argument's value.+             -> ArgumentProperty          -- ^ The corresponding argument property.+desc_argname name = ArgumentProperty+   (\desc ->+      if argdesc_argargname desc == Nothing+         then desc { argdesc_argargname = Just name }+         else abort "Bug in HsShellScript argument description: Multiple names specified" desc+   )++-- |+-- Specify a short description of what the argument does. Used for the+-- generation of the usage message. This is to fit on one line, after the+-- short and long argument names. It should be 40 characters long or so.+desc_description :: String                      -- ^ Short description of the argument.+                 -> ArgumentProperty      -- ^ The corresponding argument property.+desc_description expl = ArgumentProperty+   (\desc ->+      if argdesc_argarg_description desc == Nothing+         then desc { argdesc_argarg_description = Just expl }+         else abort "Bug in HsShellScript argument description: Multiple explanations specified" desc+   )++-- | Specify a tester for this argument. The tester is a function which tests the argument value for format errors. Typically, it tests whether the+-- value can be parsed to some target type. If the test fails, the tester produces an error message. When parsing the command line arguments (which+-- @getargs@ or related), all the testers are applied to the respective argument values, and an 'ArgError' is thrown in case of failure. By using a+-- tester, it can be ensured that the argument values abide a specific format when extracting them, such that they can be parsed without errors, e.g.+-- @myarg = read (reqarg_req args d_myarg)@.+--+-- An argument tester is a function of type 'Argtester'.+--+-- See 'readtester', 'desc_integer', 'desc_nonneg_integer', 'Argtester'.+desc_tester :: Argtester                        -- ^ Argument tester to apply to this argument+            -> ArgumentProperty                 -- ^ The corresponding argument property.+desc_tester t = ArgumentProperty+   (\desc ->+      case argdesc_argarg_tester desc of+         Nothing -> desc { argdesc_argarg_tester = Just t }+         Just _  -> abort "Bug in HsShellScript argument description: Multiple argument value testers specified" desc+   )+++-- |+-- Build an argument tester from a @reads@ like function. Typically, a specialisation of the standard prelude function @read@ is used.+-- Example: @readtester \"Integer expected.\" (reads :: ReadS Int)@+readtester :: ReadS a                           -- Reader function, like the standard prelude function @reads@+           -> String                            -- Additional message+           -> Argtester                         -- Argument tester to be passed to 'desc_tester'+readtester reader msg val =+   case filter ((== "") . snd) $ reader val of+      [(_,"")] -> Nothing+      []       -> Just (\arg -> "Format error in the value of the " ++ argname_a arg ++ ". " ++ msg ++ "\nValue: " ++ quote val)+      _        -> Just (\arg -> "Ambigious value of the " ++ argname_a arg ++ ". " ++ msg ++ "\nValue: " ++ quote val)+++{- | Specify that the value of this argument, if present, is a positive integer. This will cause an error when the command line is parsed, and the+   argument's value doesn't specify an integer.++>desc_integer = desc_tester (readtester (reads :: ReadS Int) "Integer expected.")++   See 'desc_tester'.+-}+desc_integer :: ArgumentProperty+desc_integer = desc_tester (readtester (reads :: ReadS Int) "Integer expected.")+++{- | Specify that the value of this argument, if present, is a non-negative integer. This will cause an error when the command line is parsed, and the+   value doesn't specify a non-negative integer.++>desc_nonneg_integer = desc_tester (readtester ((filter (\(a,_) -> a >= 0) . reads) :: ReadS Int) "Non-negative integer expected." )++   See 'desc_tester'.+-}+desc_nonneg_integer :: ArgumentProperty+desc_nonneg_integer = desc_tester (readtester ((filter (\(a,_) -> a >= 0) . reads) :: ReadS Int) "Non-negative integer expected." )+++abort_conflict msg = abort ("Conflicting properties in argument description. " ++ msg)+abort msg desc = error (msg ++ "\nargument (so far): " ++ argname desc)++-- |+-- Generate a descriptive argument name from an argument description, suitable+-- for use in error messages and usage information. This uses the long and short+-- argument names (as specified by 'desc_short' and 'desc_long') and generates+-- descriptive names of the argument like \"-f\", \"--myflag\",+-- \"-f\/--myflag\", etc. All the argument names are included. In case of direct+-- arguments (see 'desc_direct'), the descriptive name is \"@(direct+-- argument)@\".+--+-- See 'argdesc'.+argname :: ArgumentDescription  -- ^ Argument description, as returned by @argdesc@+        -> String               -- ^ Printable name for the argument+argname desc =+   if (argdesc_short_args desc, argdesc_long_args desc) == ([],[""]) then "(direct argument)"+      else if (argdesc_short_args desc, argdesc_long_args desc) == ([],[]) then "yet unnamed argument"+         else concat (intersperse "/" ( map (\s -> "-"++[s]) (argdesc_short_args desc) ++ map ("--" ++) (argdesc_long_args desc) ))++-- |+-- Generate a descriptive argument name from an argument description, beginning+-- with \"argument\". This uses the long and short argument names (as specified+-- by 'desc_short' and 'desc_long') and generates descriptive names of the+-- argument like \"argument -f\", \"argument --myflag\", \"argument+-- -f\/--myflag\", etc. All the argument names are included. In case of direct+-- arguments (see 'desc_direct'), the descriptive name is \"direct argument\".+--+-- See 'argdesc'.+argname_a :: ArgumentDescription        -- ^ Argument description, as returned by @argdesc@+          -> String                     -- ^ Printable name for the argument+argname_a desc =+   if (argdesc_short_args desc, argdesc_long_args desc) == ([],[""]) then "direct argument"+      else if (argdesc_short_args desc, argdesc_long_args desc) == ([],[]) then "yet unnamed argument"+         else "argument " ++ concat (intersperse "/" ( map (\s -> "-"++[s]) (argdesc_short_args desc) ++ map ("--" ++) (argdesc_long_args desc) ))++up1 "" = ""+up1 (x:xs) = toUpper x : xs++-- complete generation of argument description+prop_final :: ArgumentProperty+prop_final = ArgumentProperty+   (\desc ->+      seq (if argdesc_argarg desc /= ArgumentValue_none && argdesc_argargname desc == Nothing+              then error $ "Bug in description of " ++ argname_a desc ++ ": Argument's value must be given a name using desc_argname."+              else if argdesc_argarg desc == ArgumentValue_none && argdesc_argargname desc /= Nothing+                      then error $ "Bug in description of " ++ argname_a desc+                           ++ ": Argument doesn't take a sub argument, but a name for it is specified."+                      else ()+          ) $+          desc { argdesc_times = Just (fromMaybe times_default (argdesc_times desc))+               , argdesc_argarg_description = Just (fromMaybe "" (argdesc_argarg_description desc))+               }+   )++-- |+-- Make an argument description from a list of argument properties. This+-- condenses the list to an argument description,+-- which can be used by the @getargs@... functions and the+-- argument value extraction functions.+argdesc :: [ArgumentProperty]     -- ^ List of properties, which describe the command line argument.+        -> ArgumentDescription    -- ^ The corresponding argument description.+argdesc propl =+   foldr (.) id (map argumentproperty (prop_final:propl)) nulldesc+++-- Parse command line arguments.+getargs0 :: String                      -- Header for usage info+         -> ArgOrder ArgOcc             -- HsShellScript.GetOpt.Permute or HsShellScript.GetOpt.RequireOrder+                                        --   Permute:      Named arguments (like -x or --arg) and direct arguments may occur in any order.+                                        --   RequireOrder: All arguments after the first direct argument are regarded as direct arguments.+         -> [String]                    -- The command line arguments as returned by System.Environment.getArgs+         -> [ArgumentDescription]       -- The arguments descriptions+         -> Either ArgError             -- Error+                   Arguments            -- Parsed command line arguments+getargs0 header ordering cmdlargs descs =+   let (  descs_direct     -- direct arguments (without argument name)+        , descs_regular    -- regular arguments (with long or short argument name)+        ) = partition is_direct descs++       nonunique :: Eq a => [a] -> Maybe a+       nonunique (a:b:r) = if (a == b) then (Just a) else nonunique (b:r)+       nonunique _       = Nothing++       test_unique :: (Show a, Ord a) => (ArgumentDescription -> [a]) -> String -> b -> b+       test_unique extr what x =+           case nonunique (sort (concat (map extr descs))) of+              Just y -> error ("Bug: Several occurences of " ++ what ++ " " ++ show y ++ " in command line argument specifications")+              Nothing -> x++       optdescr = map make_optdescr descs_regular++       make_optdescr :: ArgumentDescription -> OptDescr ArgOcc+       make_optdescr desc =+          Option (argdesc_short_args desc)+                 (argdesc_long_args desc)+                 (case argdesc_argarg desc of+                     ArgumentValue_none      -> NoArg  (desc, Nothing)+                     ArgumentValue_required     -> ReqArg (\arg -> (desc, Just arg))+                                              (fromJust (argdesc_argargname desc))+                     ArgumentValue_optional     -> OptArg (\arg -> (desc, arg))+                                              (fromJust (argdesc_argargname desc))+                 )+                 (fromJust (argdesc_argarg_description desc))++       -- Postprocessing after successful call to getOpt+       getopt_post :: [ArgOcc] -> [String] -> Either ArgError Arguments+       getopt_post pars{-getOpt recognized arguments-} rest{-direct arguments-} =+          case (rest, descs_direct) of+             ([],[])  ->+                -- no direct arguments allowed and none provided+                getopt_post' pars+             (r, [d]) ->+                -- direct arguments allowed and expected+                getopt_post' (pars ++ zip (repeat d) (map Just r))+             ((x:xs), []) ->+                -- direct arguments provided, but not allowed+                Left (ArgError "Surplus arguments."+                               (make_usage_info1 descs)+                     )+             _ ->+                -- several descriptions for direct arguments+                error "Bug in argument descriptions: Several descriptions for direct arguments (desc_direct) specified."++       add :: (ArgumentDescription, Maybe String) -> [(ArgumentDescription, [Maybe String])] -> [(ArgumentDescription, [Maybe String])]+       add (a,str) []        = [(a,[str])]+       add (b,str) ((a,l):r) =+          if same_arg a b then (a,str:l) : r+                          else (a,l) : add (b,str) r++       getopt_post' :: [ArgOcc] -> Either ArgError Arguments+       getopt_post' pars{-all arguments-} =+          let pars' = foldr add (map (\d -> (d,[])) descs) pars++              -- Check the number of argument occurences+              check_num :: [(ArgumentDescription, [Maybe String])] -> Maybe ArgError+              check_num [] = Nothing+              check_num ((desc,args):rest) =+                 let (min,max) = fromJust (argdesc_times desc)+                     number    = length args+                     wrong_number_msg =+                        (if is_direct desc then fst else snd) $+                        if number == 0 && min == 1 then+                           ( "Missing argument."+                           , "Missing " ++ argname_a desc ++ "."+                           )+                        else if number < min then+                           ( "Too few arguments. " ++ show min ++ " required."+                           , "Too few instances of " ++ argname_a desc ++ ". "++ show min ++ " required."+                           )+                        else if number > max && max == 1 then+                           ( "Only one argument may be specified."+                           , "Repeated " ++ argname_a desc ++ "."+                           )+                        else if number > max && max /= unlimited then+                           ( "Too many arguments."+                           , "Too many instances of " ++ argname_a desc ++ "."+                           )+                        else error "bug in HsShellScript.Args.hs"+                 in  if number >= min && (number <= max || max == unlimited)+                        then check_num rest+                        else Just (ArgError wrong_number_msg (make_usage_info1 descs))++              -- Apply any argument testers+              check_testers :: [(ArgumentDescription, [Maybe String])] -> Maybe ArgError+              check_testers [] = Nothing+              check_testers ((desc,args):rest) =+                 case argdesc_argarg_tester desc of+                    Just argdesc_argarg_tester ->+                       if argdesc_argarg desc == ArgumentValue_none+                          then abort "Bug in HsShellScript argument descriptions: Argument value tester specified,\n\+                                     \but no argument value has been allowed. Add desc_value_optional or\n\+                                     \desc_value_required."+                                     desc+                          else case filter isJust (map (argdesc_argarg_tester . fromJust) (filter isJust args)) of+                                  []              -> check_testers rest+                                  (Just msgf : _) -> Just (ArgError (msgf desc) (make_usage_info1 descs))+                    Nothing -> check_testers rest++          in  case check_testers pars' of+                 Nothing  -> case check_num pars' of+                                Nothing  -> Right (Arguments (pars', header))+                                Just err -> Left err+                 Just err -> Left err++       args =+          test_unique argdesc_short_args "short argument" $+             test_unique argdesc_long_args "long argument" $+                case getOpt ordering optdescr cmdlargs of+                   (pars, rest, []) ->+                      getopt_post pars rest+                   (_,_,f) ->+                      throw (ArgError (unlines (map chomp f)) (usageInfo header optdescr))++    in args++   where+      -- duplicated here in order to break cyclic module dependency+      chomp "" = ""+      chomp "\n" = ""+      chomp [x] = [x]+      chomp (x:xs) = let xs' = chomp xs+                     in  if xs' == "" && x == '\n' then "" else x:xs'+++++-- |+-- Parse command line arguments. The arguments are taken from a call to+-- @getArgs@ and parsed. Any error is thrown as a+-- @ArgError@ exception. The result is a value from which the+-- information in the command line can be extracted by the @arg@...,+-- @reqarg@... and @optarg@... functions.+--+-- The header is used only by the deprecated @usage_info@ function. If you don't+-- use it, you don't need to specify a header. Just pass an empty string.+--+-- Named arguments (like @-x@ or @--arg@) and direct+-- arguments may occur in any order.+--+-- See 'usage_info', 'make_usage_info', 'print_usage_info'.+getargs :: String                         -- ^ Header to be used by the deprecated @usage_info@ function.+        -> [ArgumentDescription]          -- ^ The argument descriptions.+        -> IO Arguments                   -- ^ The contents of the command line.+getargs header descs = do+   args <- getArgs+   let res = getargs0 header Permute args descs+   either throw+          return+          res++-- |+-- Parse command line arguments. The arguments are taken from a call to+-- @getArgs@ and parsed. Any error is thrown as a+-- @ArgError@ exception. The result is a value from which the+-- information in the command line can be extracted by the @arg@...,+-- @reqarg@... and @optarg@... functions.+--+-- The header is used only by the deprecated @usage_info@ function. If you don't+-- use it, you don't need to specify a header. Just pass an empty string.+--+-- All arguments after the first direct argument are regarded as direct+-- arguments. This means that argument names introduced by @-@+-- or @--@ no longer take effect.+--+-- See 'usage_info', 'make_usage_info', 'print_usage_info'.+getargs_ordered :: String                 -- ^ Header to be used by the deprecated @usage_info@ function.+                -> [ArgumentDescription]  -- ^ Descriptions of the arguments.+                -> IO Arguments           -- ^ The contents of the command line.+getargs_ordered header descs = do+   args <- getArgs+   either throw+          return+          (getargs0 header RequireOrder args descs)++-- |+-- Parse the specified command line. Any error is returned as @Left+-- argerror@. In case of success, the result is returned as+-- @Right res@. From the result, the information in the command+-- line can be extracted by the @arg@..., @reqarg@...+-- and @optarg@... functions.+--+-- The header is used only by the deprecated @usage_info@ function. If you don't+-- use it, you don't need to specify a header. Just pass an empty string.+--+-- Named arguments (like @-x@ or @--arg@) and direct+-- arguments may occur in any order.+--+-- See 'usage_info', 'make_usage_info', 'print_usage_info'.+getargs' :: String                              -- ^ Header to be used by the deprecated @usage_info@ function.+         -> [String]                            -- ^ Command line to be parsed.+         -> [ArgumentDescription]         -- ^ The argument descriptions.+         -> Either ArgError Arguments     -- ^ The contents of the command line.+getargs' header args descs = getargs0 header Permute args descs++-- |+-- Parse the specified command line. Any error is returned as @Left+-- argerror@. In case of success, the result is returned as+-- @Right res@. From the result, the information in the command+-- line can be extracted by the @arg@..., @reqarg@...+-- and @optarg@... functions.+--+-- The header is used only by the deprecated @usage_info@ function. If you don't+-- use it, you don't need to specify a header. Just pass an empty string.+--+-- All arguments after the first direct argument are regarded as direct+-- arguments. This means that argument names introduced by @-@+-- or @--@ no longer take effect.+--+-- See 'usage_info', 'make_usage_info', 'print_usage_info'.+getargs_ordered' :: String                              -- ^ Header to be used by the deprecated @usage_info@ function.+                 -> [String]                            -- ^ Command line to be parsed.+                 -> [ArgumentDescription]         -- ^ The argument descriptions.+                 -> Either ArgError Arguments     -- ^ The contents of the command line.+getargs_ordered' header args descs = getargs0 header RequireOrder args descs+++test_desc :: ArgumentDescription -> Bool -> String -> b -> b+test_desc desc ok msg x =+   if ok then x+         else abort msg desc++maybe_head :: [a] -> Maybe a+maybe_head [] = Nothing+maybe_head [a] = Just a++-- |+-- Query whether a certain switch is specified on the command line. A switch is an+-- argument which is allowed zero or one time, and has no value.+arg_switch :: Arguments                   -- ^ Command line parse result.+           -> ArgumentDescription         -- ^ Argument description of the switch.+           -> Bool                              -- ^ Whether the switch is present in the command line.+arg_switch args desc =+   test_desc desc (argdesc_argarg desc == ArgumentValue_none && argdesc_times desc == Just (0,1))+             "bug: querying argument with is not a switch with arg_switch" $+   case argvalues args desc of+      []         -> False+      [Nothing]  -> True++-- |+-- Query the number of occurences of an argument.+arg_times :: Arguments                    -- ^ Command line parse result.+          -> ArgumentDescription          -- ^ Description of the argument.+          -> Int                          -- ^ Number of times the argument occurs.+arg_times args desc =+   length (argvalues args desc)++-- |+-- Query the values of an argument with optional value. This is for+-- arguments which take an optional value, and may occur several times. The+-- occurences with value are represented as @Just value@, the occurences+-- without are represented as @Nothing@.+args_opt :: Arguments                     -- ^ Command line parse result.+         -> ArgumentDescription           -- ^ Description of the argument.+         -> [Maybe String]                      -- ^ The occurences of the argument.+args_opt args desc =+   test_desc desc (argdesc_argarg desc == ArgumentValue_optional && snd (fromJust (argdesc_times desc)) /= 1)+             "Bug: Querying argument which doesn't take an optional value, or may not occur several times, with args_opt."+   $ argvalues args desc++-- |+-- Query the values of an argument with required value. This is for+-- arguments which require a value, and may occur several times.+args_req :: Arguments                     -- ^ Command line parse result.+         -> ArgumentDescription           -- ^ Description of the argument.+         -> [String]                            -- ^ The values of the argument.+args_req args desc =+   test_desc desc (argdesc_argarg desc == ArgumentValue_required && snd (fromJust (argdesc_times desc)) /= 1)+             "Bug: Querying argument which doesn't require a value, or may not occur several times, with args_req." $+   map fromJust (argvalues args desc)++-- |+-- Query the optional value of a required argument. This is for arguments+-- which must occur once, and may have a value. If the argument is+-- specified, its value is returned as @Just value@. If it isn't, the result+-- is @Nothing@.+reqarg_opt :: Arguments                   -- ^ Command line parse result.+           -> ArgumentDescription         -- ^ Description of the argument.+           -> Maybe String                      -- ^ The value of the argument, if it occurs.+reqarg_opt args desc =+   test_desc desc (argdesc_argarg desc == ArgumentValue_optional && argdesc_times desc == Just (1,1))+             "Bug: Querying argument which doesn't take an optional value, or which must not occur exactly once, with reqarg_opt." $+   head (argvalues args desc)++-- |+-- Query the value of a required argument. This is for arguments which must+-- occur exactly once, and require a value.+reqarg_req :: Arguments                   -- ^ Command line parse result.+           -> ArgumentDescription         -- ^ Description of the argument.+           -> String                            -- ^ The value of the argument.+reqarg_req args desc =+   test_desc desc (argdesc_argarg desc == ArgumentValue_required && argdesc_times desc == Just (1,1))+             "Bug: Querying argument with non-required value, or which doesn't occur exactly once, with reqarg_req." $+   fromJust (head (argvalues args desc))++-- |+-- Query the optional value of an optional argument. This is for arguments+-- which may occur zero or one time, and which may or may not have a value.+-- If the argument doesn't occur, the result is @Nothing@. If it does occur,+-- but has no value, then the result is @Just Nothing@. If it does occur with+-- value, the result is @Just (Just value)@.+optarg_opt :: Arguments                   -- ^ Command line parse result.+           -> ArgumentDescription         -- ^ Description of the argument.+           -> Maybe (Maybe String)              -- ^ The occurence of the argument and its value (see above).+optarg_opt args desc =+   test_desc desc (argdesc_argarg desc == ArgumentValue_optional)  "Bug: Querying argument with non-optional value with optarg_opt." $+   test_desc desc (fst (fromJust (argdesc_times desc)) == 0)       "Bug: Querying argument which isn't optional with optarg_opt." $+   test_desc desc (snd (fromJust (argdesc_times desc)) == 1)       "Bug: Querying argument which may occur several times optarg_opt." $+   maybe_head (argvalues args desc)++-- |+-- Query the value of an optional argument. This is for optional arguments+-- which require a value, and may occur at most once. The result is+-- @Just value@ if the argument occurs, and @Nothing@+-- if it doesn't occur.+optarg_req :: Arguments                   -- ^ Command line parse result.+           -> ArgumentDescription         -- ^ Description of the argument.+           -> Maybe String                      -- ^ The value of the argument, if it occurs.+optarg_req args desc =+   test_desc desc (argdesc_argarg desc == ArgumentValue_required)        "Bug: Querying argument with non-required value with optarg_req."+   $ test_desc desc (fst (fromJust (argdesc_times desc)) == 0)          "Bug: Querying argument which isn't optional with optarg_req."+   $ test_desc desc (snd (fromJust (argdesc_times desc)) == 1)          "Bug: Querying argument which may occur several times optarg_req."+   $ fmap fromJust (maybe_head (argvalues args desc))+++-- |+-- None of the specifed arguments may be present.+--+-- Throws an ArgError if any of the arguments are present.+args_none :: [ArgumentDescription]        -- ^ List of the arguments which must not be present.+          -> Arguments                    -- ^ Command line parse result.+          -> IO ()+args_none descs args@(Arguments argl) =+   mapM_ (\desc ->+             when (arg_times args desc /= 0) $+                argerror_ui (up1 (argname_a desc) ++ " is not allowed.\n")+                            descs+         )+         descs++-- |+-- All of the specified arguments must be present.+--+-- Throws an ArgError if any is missing.+args_all :: [ArgumentDescription]         -- ^ List of the arguments which must be present.+         -> Arguments                     -- ^ Command line parse result.+         -> IO ()+args_all descs args@(Arguments argl) =+   mapM_ (\desc ->+             when (arg_times args desc == 0) $+                argerror_ui ("Missing " ++ argname_a desc ++ "\n") descs+         )+         descs++-- |+-- Exactly one of the specified arguments must be present.+--+-- Otherwise throw an ArgError.+args_one :: [ArgumentDescription]         -- ^ List of the arguments, of which exactly one must be present.+         -> Arguments                     -- ^ Command line parse result.+         -> IO ()+args_one descs args@(Arguments argl) =+   when (occuring descs args /= 1) $+      argerror_ui ("Exactly one of the following arguments must be present.\n"+                ++ concat (intersperse ", " (map argname descs)) ++ "\n")+               descs+++-- |+-- At most one of the specified arguments may be present.+--+-- Otherwise throw an ArgError.+args_at_most_one :: [ArgumentDescription] -- ^ List of the arguments, of which at most one may be present.+                 -> Arguments             -- ^ Command line parse result.+                 -> IO ()+args_at_most_one descs args@(Arguments argl) =+   when (occuring descs args > 1) $+      argerror_ui ("Only one of the following arguments may be present.\n"+                   ++ concat (intersperse ", " (map argname descs)) ++ "\n")+                   descs+++-- |+-- At least one of the specified arguments must be present.+--+-- Otherwise throw an ArgError.+args_at_least_one :: [ArgumentDescription]        -- ^ List of the arguments, of which at least one must be present.+                  -> Arguments                    -- ^ Command line parse result.+                  -> IO ()+args_at_least_one descs args@(Arguments argl) =+   when (occuring descs args == 0) $+      argerror_ui ("One of the following arguments must be present.\n"+                   ++ concat (intersperse ", " (map argname descs)) ++ "\n")+                   descs+++-- |+-- When the specified argument is present, then none of the other arguments may be present.+--+-- Otherwise throw an ArgError.+arg_conflicts :: ArgumentDescription   -- ^ Argument which doesn't tolerate the other arguments+              -> [ArgumentDescription] -- ^ Arguments which aren't tolerated by the specified argument+              -> Arguments             -- ^ Command line parse result.+              -> IO ()+arg_conflicts desc descs args@(Arguments argl) =+   when (arg_occurs args desc && occuring descs args > 1) $+      argerror_ui ("When " ++ argname desc ++ " is present, none of the following arguments may be present.\n"+                   ++ concat (intersperse ", " (map argname descs)) ++ "\n")+                   descs+++-- How many of the specified arguments do occur? Multiple occurences of the same argument count as one.+occuring :: [ArgumentDescription] -> Arguments -> Int+occuring descs args =+   sum (map (\desc -> if arg_times args desc == 0 then 0 else 1) descs)+++{- | Whether the specified argument occurs in the command line.+-}+arg_occurs :: Arguments                   -- ^ Command line parse result.+           -> ArgumentDescription         -- ^ Description of the respective argument.+           -> Bool                              -- ^ Whether the specified argument occurs in the command line.+arg_occurs args desc =+   occuring [desc] args == 1+++-- |+-- /Deprecated/. This is left here for backwards compatibility. New programs should use @make_usage_info@ and/or @print_usage_info@.+--+-- Get the usage information from the parsed arguments. The usage info+-- contains the header specified to the corresponding @getargs...@+-- function, and descriptions of the command line arguments.+--+-- Descriptions can be several lines long. Lines get wrapped at column 80.+--+-- See 'make_usage_info', 'print_usage_info', 'wrap', 'terminal_width', 'terminal_width_ioe'.+usage_info :: Arguments -> String+usage_info (Arguments (l, header)) =+   unlines (wrap 80 header) +++   concat (intersperse "\n" (make_usage_info (map fst l) 0 20 80))++++{- | @getargs@ as a pure function, instead of an IO action. This allows to make evaluated command line arguments global values. This calls @getargs@+   to parse the command line arguments. @GHC.IO.unsafePerformIO@ is used to take the result out of the IO monad.++   >unsafe_getargs header descs = GHC.IO.unsafePerformIO $ getargs "" descs++   The @getargs@ action is performed on demand, when the parse result is evaluated. It may result in an 'ArgError' being thrown. In order to avoid+   this happening at unexpected times, the @main@ function should, start with the line @seq args (return ())@, where @args@ is the result of+   @unsafe_getargs@,. This will trigger any command line argument errors at the beginning of the program. (See section 6.2 of the Hakell Report for the+   definition of @seq@).++   The header is used only by the deprecated @usage_info@ function. If you don't+   use it, you don't need to specify a header. Just pass an empty string.++   A typical use of @unsafe_getargs@ looks like this:++>descs = [ d_myflag, ... ]+>+>d_myflag = argdesc [ ... ]+>+>args = unsafe_getargs "" descs+>myflag = arg_switch args d_myflag+>+>main = mainwrapper $ do+>   seq args (return ())+>   ...++  See 'getargs', 'unsafe_getargs_ordered'.+-}+unsafe_getargs :: String                        -- ^ Header to be used by the deprecated @usage_info@ function.+               -> [ArgumentDescription]   -- ^ The argument descriptions+               -> Arguments               -- ^ The parsed command line arguments+unsafe_getargs header descs =+   GHC.IO.unsafePerformIO $ getargs header descs+++{- | @getargs_ordered@ as a pure function, instead of an IO action. This is exactly like @unsafe_getargs@, but using @getargs_ordered@ instead of+   @getargs@.++   The header is used only by the deprecated @usage_info@ function. If you don't+   use it, you don't need to specify a header. Just pass an empty string.++   The definition is:++   >unsafe_getargs_ordered = GHC.IO.unsafePerformIO $ getargs_ordered "" descs++   See 'unsafe_getargs', 'usage_info', 'make_usage_info', 'print_usage_info'.+-}+unsafe_getargs_ordered :: String                        -- ^ Header to be used by the deprecated @usage_info@ function.+                       -> [ArgumentDescription]   -- ^ The argument descriptions+                       -> Arguments               -- ^ The parsed command line arguments+unsafe_getargs_ordered header descs =+   GHC.IO.unsafePerformIO $ getargs_ordered header descs++++-- |+-- Generate pretty-printed information about the command line arguments. This+-- function gives you much control on how the usage information is generated.+-- @print_usage_info@ might be more like what you need.+--+-- The specified argument descriptions (as taken by the @getargs@... functions)+-- are processed in the given order. Each one is formatted as a paragraph,+-- detailing the argument. This is done according to the specified geometry.+--+-- The direct argument, in case there is one, is omitted. You should detail the+-- direct command line arguments separatly, such as in some header.+--+-- See 'print_usage_info', 'getargs', 'usage_info', 'ArgumentDescription',+-- 'desc_description', 'argdesc', 'terminal_width', 'terminal_width_ioe".+make_usage_info :: [ArgumentDescription]                -- ^ List of argument descriptions, as created by a @argdesc@+                -> Int                                  -- ^ The output is indented this many columns. Probably zero.+                -> Int                                  -- ^ How much columns to reserve for the argument name and name+                                                        --   of the value of the argument (if any). Somthing like 10 or 15.+                -> Int                                  -- ^ Wrap everything at this column. Should probably be the terminal width.+                -> [String]                             -- ^ pretty printed usage information+make_usage_info argdescs colsleft colsarg width =++   if width < colsleft + colsarg + 2+      then error ("Bug in make_usage_info: geometry doesn't match: "+                   ++ show width ++ " < " ++ show colsleft ++ " + " ++ show colsarg ++ " + 2")+      else++         map (\desc -> make_usage_info1 colsleft colsarg width desc)+             (filter (\desc -> not (is_direct desc)) argdescs)++   where+      -- Make the usage info for one argument description+      make_usage_info1 :: Int -> Int -> Int -> ArgumentDescription -> String+      make_usage_info1 colsleft colsarg width desc  =+         unlines $ einruecken1 colsleft $++            case argdesc_argarg_description desc of++               -- Das Argument hat eine Beschreibung+               Just txt ->+                  if length (argname1 desc) >= colsarg+                     then+                        -- Der Parameter paßt nicht in die vorgegebene Breite.+                        -- Füge eine extra Zeile hinzu.+                        argname1 desc+                        : einruecken1 colsarg (wrap breite txt)++                     else+                        -- Der Parameter paßt in die vorgegebene Breite. Fange+                        -- in derselben Zeile mit der Beschreibung an.+                        -- Füge eine extra Zeile hinzu.+                        let (bzl1:bzlrest) = einruecken colsarg (wrap breite txt)+                        in+                           (auff colsarg (argname1 desc) ++ bzl1)+                           : bzlrest++               -- Das Argument hat keine Beschreibung. Gebe nur den Argumentname aus.+               Nothing ->+                  [ argname1 desc ]++      -- Argumentname zusammen mit Argumentwert-Name+      argname1 desc =+         argname desc+         ++ case argdesc_argargname desc of+               Just name -> " " ++ name+               Nothing   -> ""++      breite = width - colsleft - colsarg++      lz n = take n (repeat ' ')++      auff :: Int -> String -> String+      auff n str = if length str <= n then str ++ lz (n - length str)+                                      else str+++      -- Einrücken, ab zweiter Zeile. Erste Zeile NICHT einrücken.+      einruecken :: Int -> [String] -> [String]+      einruecken _ [] = [""]+      einruecken spalten (zl:zll) =+         zl : map (\z -> lz spalten ++ z) zll++      -- Alle Zeilen eirücken+      einruecken1 :: Int -> [String] -> [String]+      einruecken1 _ [] = [""]+      einruecken1 spalten zll =+         map (\z -> lz spalten ++ z) zll+++make_usage_info1 argdescs =+   concat (intersperse "\n" (make_usage_info argdescs 0 10 80))+++-- |+-- Break down a text to lines, such that each one has the specified+-- maximum width.+--+-- Newline characters in the input text are respected. They terminate the line,+-- without it being filled up to the width.+--+-- The text is wrapped at space characters. Words remain intact, except when+-- they are too long for one line.+wrap :: Int             -- ^ Width for the result text, in columns+     -> String          -- ^ Text to break down+     -> [String]        -- ^ The broken down text in columns+wrap breite [] = []+wrap breite txt =+   [ zl | txtzl <- lines txt,+          zl <- wrap' breite txtzl+   ]+   where+      wrap' :: Int -> String -> [String]+      wrap' breite [] = [""]+      wrap' breite txt =+         if length txt <= breite+            then [txt]+            else+                 if null txt_anf+                    then -- Zu breit für eine Zeile+                         txt_br : wrap' breite txt_rest+                    else txt_anf : wrap' breite rest++         where+            (txt_br, txt_rest) =+               splitAt breite txt++            (txt_anf, txt_anf_rest) =+               letzter_teil txt_br++            rest = txt_anf_rest ++ txt_rest++            -- Letztes Wort von zl abspalten. Liefert+            -- ( Anfang von zl, Letztes Wort )+            letzter_teil zl =+               let zl'              = reverse zl+                   (wort, zl'')     = span (/= ' ') zl'+                   zl''1            = dropWhile (== ' ') zl''+                   zl'''            = reverse zl''1+                   wort'            = reverse wort+               in (zl''', wort')+++++-- |+-- Print the usage information (about the command line arguments), for the+-- specified header and arguments to the specified handle. When the handle is+-- connected to a terminal, the terminal\'s width (in columns) is used to format+-- the output, such that it fits the terminal. Both the header and the argument+-- descriptions are adapted to the width of the terminal (by using @wrap@).+--+-- When the handle does not connected to a terminal, 80 columns are used. This+-- may happen to @stdout@ or @stderr@, for instance, when the program is in a+-- pipe, or the output has been redirected to a file.+--+-- You should specify one long line for each paragraph in the header and the+-- argument descriptions, and let print_usage_info do the wrapping. When you+-- have several paragraphs, separate them by a double @\\n\\n@.+--+-- The arguments are printed in the order, in which they occur in the argument+-- description list.+--+-- This function is a front end to @terminal_width@ and @make_usage_info@.+--+-- See 'argdesc', 'desc_description', 'terminal_width', 'make_usage_info', 'usage_info', 'wrap'.+print_usage_info :: Handle                      -- ^ To which handle to print the+                                                --   usage info.+                 -> String                      -- ^ The header to print first.+                                                --   Can be empty.+                 -> [ArgumentDescription]       -- ^ The argument description of+                                                --   the arguments, which should be documented.+                 -> IO ()+print_usage_info h header descs = do+   -- Determine the width to use+   mw <- terminal_width h+   let w = case mw of+              Just w  -> w+              Nothing -> 80++   -- Wrap and print the header+   hPutStr h (unlines (wrap w header))++   -- Print the argument descriptions+   mapM_ (hPutStrLn h)+         (make_usage_info descs 0 (w `div` 8 + 1) w)
− src/HsShellScript/Args.hs
@@ -1,981 +0,0 @@--- |--- This module provides a more convient way of parsing command line--- arguments than the GHC GetOpt package. It uses GetOpt, but hides--- it from the user. It is reexported from module HsShellScript.------ For each command line argument, a description is to be created with--- @argdesc@. Then the command line arguments are evaluated with--- one of the @getargs@... functions. In case of an error, this will cause a--- exception, which provides an expressive error message to be--- printed. Then the @arg@... functions are used to extract the--- values contained in the arguments, with the right type. The typical use--- of HsShellScript.Args looks something like this:------ >import HsShellScript--- >--- >main =--- >   do let a_onevalue = argdesc [ desc_at_most_once, ... ]--- >          a_values   = argdesc [ desc_direct, ... ]--- >          a_switch   = argdesc [ ... ]--- >          ...--- >          header = "mclapep - My Command Line Argument Parser Example Program, version 1.0.0"--- >--- >      args <- getargs header [a_onevalue, a_values, a_switch, ...]--- >--- >      val  <- optarg_req a_onevalue args        -- val  :: Maybe String--- >      vals <- args_req   a_values args          -- vals :: [String]--- >      doit <- arg_switch a_switch args          -- doit :: Bool--- >      ...--- >   `catch` --- >      (\argerror -> do--- >          hPutStrLn stderr $ (argerror_message argerror) ++ "\n\n" ++ (argerror_usageinfo argerror)--- >          exitFailure--- >      )------ Errors in the argument descriptions are regarded as bugs, and handled--- by aborting the program with a message which is meaningful to the--- programmer. It is assumed that the argument description is a constant for--- a given program.------ Errors in the arguments are reported using HsShellScript's error handling--- scheme. An error description--- value is generated, and either returned via an @Either@--- value, or thrown as an exception.--module HsShellScript.Args ( -- ** Argument Properties-                    ArgumentProperty-                  , ArgumentDescription (..)-                  , ArgumentValueSpec (..)-                  , Argtester-                  , argdesc-                  , desc_short-                  , desc_long-                  , desc_direct-                  , desc_value_required-                  , desc_value_optional-                  , desc_times-                  , desc_once-                  , desc_at_least_once-                  , desc_at_most_once-                  , desc_any_times-                  , desc_at_least-                  , desc_at_most-                  , desc_argname-                  , desc_description-                  , desc_tester-                  , desc_integer-                  , desc_nonneg_integer-                  , readtester-                    -- ** Evaluating the Command Line-                  , Arguments-                  , getargs-                  , getargs_ordered-                  , getargs'-                  , getargs_ordered'-                  , unsafe_getargs-                  , unsafe_getargs_ordered-                    -- ** Extracting the Argument Values-                  , arg_switch-                  , arg_times-                  , args_opt-                  , args_req-                  , reqarg_opt-                  , reqarg_req-                  , optarg_opt-                  , optarg_req-                  , arg_occurs-                    -- ** Placing additional Constraints on the Arguments-                  , args_none-                  , args_all-                  , args_one-                  , args_at_most_one-                  , args_at_least_one-                  , arg_conflicts-                    -- ** Argument Error Reporting-                  , ArgError (..)-                  , usage_info-                  , argname-                  , argname_a-                  ) where---- We use a fixed copy of GHC's GetOpt implementation. This is to work around a bug.--- import System.Console.GetOpt-import HsShellScript.GetOpt--import Control.Monad-import Control.Exception-import Prelude hiding (catch)-import Data.Maybe-import System.Environment-import Data.List-import GHC.IO-import System.IO-import HsShellScript.Shell-import Data.Char-import Debug.Trace-import Data.Typeable------- | Does the command line argument take an value?-data ArgumentValueSpec  = ArgumentValue_none 		-- ^ No value-                        | ArgumentValue_required 	-- ^ Value required-                        | ArgumentValue_optional	-- ^ Value optional-   deriving (Eq, Show, Ord)----- | Argument value tester function. This tests the format of an argument's value for errors. The tester function is specified by--- 'desc_tester' or such, as part of the argument description. --- --- The tester is passed the argument value. If the format is correct, then it returns @Nothing@. If there is an error, then it returns @Just msgf@,--- with @msgf@ being an error message generation function. This function gets passed the argument description, and produces the error--- message. The argument description typically is used to extract a descriptive name of the argument (using 'argname' or 'argname_a') to be included--- in the error message.-type Argtester = String                           -- Argument value to be tested-                 -> Maybe (ArgumentDescription    -- Argument description for message generation-                           -> String              -- Error message-                          )----- | Description of one command line argument. These are generated by--- @argdesc@ from a list of argument properties, and subsequently used by one of the--- @getargs@... functions. This type is abstract.-data ArgumentDescription = ArgumentDescription {-        argdesc_short_args :: [Char],                           -- ^ Short option names-        argdesc_long_args :: [String],                          -- ^ Long option names-        argdesc_argarg :: ArgumentValueSpec,                    -- ^ What about a possible value of the argument?-        argdesc_times :: Maybe (Int,Int),                       -- ^ Minimum and maximum of number of occurences allowed-        argdesc_argargname :: Maybe String,                     -- ^ Name for argument's value, for message generation-        argdesc_argarg_description :: Maybe String,             -- ^ Descrition of the argument, for message generation-        argdesc_argarg_tester :: Maybe Argtester                -- ^ Argument value tester-      }---- excluding tester-ad_tup ad = -   (argdesc_short_args ad, argdesc_long_args ad, argdesc_argarg ad, argdesc_times ad, argdesc_argargname ad, argdesc_argarg_description ad)--instance Eq ArgumentDescription where-   d == e = ad_tup d == ad_tup e--instance Ord ArgumentDescription where-   compare d e = compare (ad_tup d) (ad_tup e)---- value for maximum number of times-unlimited = -1---- Whether two argument descriptions describe the same argument.--- Every short or long argument name occurs in only one argument--- descriptor (this is checked). Every argument has a short or a long--- name (short = [], long = [""] for direct arguments).-same_arg :: ArgumentDescription -> ArgumentDescription -> Bool-same_arg arg1 arg2 =-   case (argdesc_short_args arg1, argdesc_short_args arg2) of-      (a:_, b:_) -> a == b-      ([], [])   -> case (argdesc_long_args arg1, argdesc_long_args arg2) of-                       ([],_)  -> unnamed-                       (_,[])  -> unnamed-                       (l1,l2) -> head l1 == head l2-      _          -> False-   where unnamed = error "Bug in argument description: nameless, non-direct argument. desc_short or desc_long must be specified."---- | A property of a command line argument. These are generated by the--- @desc_@... functions, and condensed to argument--- descriptions of type @ArgumentDescription@ by @argdesc@. This type is abstract.-newtype ArgumentProperty =-   ArgumentProperty { argumentproperty :: ArgumentDescription -> ArgumentDescription }--- An argument property is a function which fills in part of an argument descriptor.----- starting value for argument descriptor-nulldesc :: ArgumentDescription-nulldesc =-   ArgumentDescription {-      argdesc_short_args = [],-      argdesc_long_args = [],-      argdesc_argarg = ArgumentValue_none,-      argdesc_times = Nothing,          -- default = (0,1)-      argdesc_argargname = Nothing,-      argdesc_argarg_description = Nothing,-      argdesc_argarg_tester = Nothing-   }---- default number of times an argument may occur-times_default = (0,1)----- | This represents the parsed contents of the command line. It is returned--- by the @getargs@... functions, and passed on to the--- value extraction functions by the user.------ See 'getargs', 'getargs_ordered', 'getargs\'', 'getargs_ordered\''.-newtype Arguments =-    Arguments ( [ ( ArgumentDescription             -- argument descriptor-                  , [Maybe String]                  -- arguments matching this descriptor-                  )-                ]-              , String                              -- usage information-              )--argvalues :: Arguments -> ArgumentDescription -> [Maybe String]-argvalues (Arguments (l,_)) desc =-   argvalues' l-   where-      argvalues' ((d,v):r) = if same_arg desc d then v else argvalues' r-      argvalues' []        = abort "Bug using HsShellScript: Value of unknown argument queried (add it to getarg's list)" desc---- used internally to represent one occurence of a specific argument-type ArgOcc = (ArgumentDescription, Maybe String)----- | Error thrown when there is an error in the--- command line arguments.-data ArgError = ArgError {-      -- | Error message generated by HsShellScript.Args.-      argerror_message :: String,-      -- | Usage information derived from the argument descriptions.-      argerror_usageinfo :: String-   }-   deriving (Typeable)----- |--- Make @ArgError@ an instance of @Exception@, so we can throw and catch it, using GHC-6.10\'s new exception library.-instance Exception ArgError--------- Printing an @ArgError@ will produce the error message. The usage--- information must be printed separately, using @usage_info@.-instance Show ArgError where-   show argerror = argerror_message argerror----- Whether it is the description for direct arguments. Direct arguments are--- the ones without introducing "-" or "--".-is_direct :: ArgumentDescription -> Bool-is_direct desc =-   argdesc_short_args desc == [] && argdesc_long_args desc == [""]----- |--- Short name of the argument. This specifies a character for a--- one letter style argument, like @-x@. There can be specified--- several for the same argument. Each argument needs at least--- either a short or a long name.-desc_short :: Char                      -- ^ The character to name the argument.-           -> ArgumentProperty    -- ^ The corresponding argument property.-desc_short c = ArgumentProperty-   (\desc ->-      if (c `elem` (argdesc_short_args desc))-         then abort ("Bug in HsShellScript argument description: Duplicate short argument " ++ show c ++ " specified") desc-         else if ("" `elem` argdesc_long_args desc)-                 then abort_conflict "" desc-                 else desc { argdesc_short_args = c : argdesc_short_args desc }-   )---- |---- Long name of the argument. This specifies a GNU style long name for the argument, which is--- introduced by two dashes, like @--arg@ or @--arg=...@. There can be specified several names for--- the same argument. Each argument needs at least either a short or a long name. Except for direct --- arguments, which don't have a name.------ See 'desc_direct'--desc_long :: String                     -- ^ The long name of the argument.-          -> ArgumentProperty     -- ^ The corresponding argument property.-desc_long str = ArgumentProperty-   (\desc ->-      if (str `elem` (argdesc_long_args desc))-         then abort ("Bug in HsShellScript argument description: Duplicate long argument " ++ show str ++ " specified") desc-         else if ("" `elem` argdesc_long_args desc)-                 then abort_conflict "" desc-                 else desc { argdesc_long_args = str : argdesc_long_args desc }-   )---- |--- Signal that this is the description of direct arguments. Direct arguments are the ones not--- introduced by any short or long argument names (like @-x@ or @--arg@). After the special argument--- @--@, also everything is a direct argument, even when starting with @-@ or @--@. The presence of--- @desc_direct@ in the argument properties list signals @argdesc@ that this is the description of--- the direct arguments. There may be at most one such description.-desc_direct :: ArgumentProperty-desc_direct = ArgumentProperty-   (\desc ->-      if argdesc_long_args desc == [] && argdesc_short_args desc == [] && argdesc_argarg desc == ArgumentValue_none-         then desc { argdesc_long_args = [""], argdesc_argarg = ArgumentValue_required, argdesc_argargname = Just "" }-         else abort_conflict "desc_direct conflicts desc_long, desc_short, desc_value_required and desc_value_optional." desc-   )---- |--- Signal that the argument requires a value.-desc_value_required :: ArgumentProperty-desc_value_required = ArgumentProperty-   (\desc ->-      if argdesc_argarg desc == ArgumentValue_none-         then desc { argdesc_argarg = ArgumentValue_required }-         else abort_conflict "desc_value_required repeated or conflicting desc_value_optional" desc-   )---- |--- Signal that the argument optionally has a value. The user may or may--- not specify a value to this argument.-desc_value_optional :: ArgumentProperty-desc_value_optional = ArgumentProperty-   (\desc ->-      if argdesc_argarg desc == ArgumentValue_none-         then desc { argdesc_argarg = ArgumentValue_optional }-         else abort_conflict "desc_value_optional repeated or conflicting desc_value_required" desc-   )---- |--- Specify lower and upper bound on the number of times an argument may--- occur.-desc_times :: Int                       -- ^ Lower bound of the allowed number of argdesc_times.-           -> Int                       -- ^ Upper bound of the allowed number of argdesc_times.-           -> ArgumentProperty          -- ^ The corresponding argument property.-desc_times n m = ArgumentProperty-   (\desc ->-       if argdesc_times desc == Nothing-          then desc { argdesc_times = Just (n,m) }-          else abort_conflict "desc_times conflicting previous number of occurences specification" desc-   )---- |--- Signal that the argument must be present exactly once. This is--- meaningful only for arguments which can take a value.-desc_once :: ArgumentProperty     -- ^ The corresponding argument property.-desc_once = desc_times 1 1---- |--- Signal that the argument must occur at least one time.-desc_at_least_once :: ArgumentProperty -- ^ The corresponding argument property.-desc_at_least_once = desc_times 1 unlimited---- |--- Signal that the argument must occur at most one time.-desc_at_most_once :: ArgumentProperty -- ^ The corresponding argument property.-desc_at_most_once  = desc_times 0 1---- |--- Signal that the argument must have at least the specified number of--- occurences, and has no upper limit of occurences.-desc_at_least :: Int                        -- ^ Number of times.-              -> ArgumentProperty           -- ^ The corresponding argument property.-desc_at_least n = desc_times n unlimited---- |--- Signal that the argument may occur any number of times.-desc_any_times :: ArgumentProperty -- ^ The corresponding argument property.-desc_any_times  = desc_times 0 unlimited---- |--- Signal that the argument does not need to be present, and may occur at most--- the specified number of times.-desc_at_most :: Int                     -- ^ Number of times.-             -> ArgumentProperty  -- ^ The corresponding argument property.-desc_at_most n = desc_times 0 n---- |--- Specify the descriptive name for command line argument's value. Used for the--- generation of the usage message. The name should be very short.-desc_argname :: String                          -- ^ Name of the argument's value.-             -> ArgumentProperty          -- ^ The corresponding argument property.-desc_argname name = ArgumentProperty-   (\desc ->-      if argdesc_argargname desc == Nothing-         then desc { argdesc_argargname = Just name }-         else abort "Bug in HsShellScript argument description: Multiple names specified" desc-   )---- |--- Specify a short description of what the argument does. Used for the--- generation of the usage message. This is to fit on one line, after the--- short and long argument names. It should be 40 characters long or so.-desc_description :: String                      -- ^ Short description of the argument.-                 -> ArgumentProperty      -- ^ The corresponding argument property.-desc_description expl = ArgumentProperty-   (\desc ->-      if argdesc_argarg_description desc == Nothing-         then desc { argdesc_argarg_description = Just expl }-         else abort "Bug in HsShellScript argument description: Multiple explanations specified" desc-   )---- | Specify a tester for this argument. The tester is a function which tests the argument value for format errors. Typically, it tests whether the--- value can be parsed to some target type. If the test fails, the tester produces an error message. When parsing the command line arguments (which--- @getargs@ or related), all the testers are applied to the respective argument values, and an 'ArgError' is thrown in case of failure. By using a--- tester, it can be ensured that the argument values abide a specific format when extracting them, such that they can be parsed without errors, e.g.--- @myarg = read (reqarg_req args d_myarg)@.------ An argument tester is a function of type 'Argtester'. ------ See 'readtester', 'desc_integer', 'desc_nonneg_integer', 'Argtester'.-desc_tester :: Argtester                        -- ^ Argument tester to apply to this argument-            -> ArgumentProperty                 -- ^ The corresponding argument property.-desc_tester t = ArgumentProperty-   (\desc ->-      case argdesc_argarg_tester desc of-         Nothing -> desc { argdesc_argarg_tester = Just t }-         Just _  -> abort "Bug in HsShellScript argument description: Multiple argument value testers specified" desc-   )----- |--- Build an argument tester from a @reads@ like function. Typically, a specialisation of the standard prelude function @read@ is used. --- Example: @readtester \"Integer expected.\" (reads :: ReadS Int)@-readtester :: ReadS a                           -- Reader function, like the standard prelude function @reads@-           -> String                            -- Additional message-           -> Argtester                         -- Argument tester to be passed to 'desc_tester'-readtester reader msg val = -   case filter ((== "") . snd) $ reader val of-      [(_,"")] -> Nothing-      []       -> Just (\arg -> "Format error in the value of the " ++ argname_a arg ++ ". " ++ msg ++ "\nValue: " ++ quote val)-      _        -> Just (\arg -> "Ambigious value of the " ++ argname_a arg ++ ". " ++ msg ++ "\nValue: " ++ quote val)---{- | Specify that the value of this argument, if present, is a positive integer. This will cause an error when the command line is parsed, and the-   argument's value doesn't specify an integer.-->desc_integer = desc_tester (readtester (reads :: ReadS Int) "Integer expected.")--   See 'desc_tester'.--}-desc_integer :: ArgumentProperty-desc_integer = desc_tester (readtester (reads :: ReadS Int) "Integer expected.")---{- | Specify that the value of this argument, if present, is a non-negative integer. This will cause an error when the command line is parsed, and the-   value doesn't specify a non-negative integer.-->desc_nonneg_integer = desc_tester (readtester ((filter (\(a,_) -> a >= 0) . reads) :: ReadS Int) "Non-negative integer expected." )--   See 'desc_tester'.--}-desc_nonneg_integer :: ArgumentProperty-desc_nonneg_integer = desc_tester (readtester ((filter (\(a,_) -> a >= 0) . reads) :: ReadS Int) "Non-negative integer expected." )---abort_conflict msg = abort ("Conflicting properties in argument description. " ++ msg)-abort msg desc = error (msg ++ "\nargument (so far): " ++ argname desc)---- | Generate a descriptive argument name from an argument description, suitable for use in error messages. This uses the long and short argument names--- (as specified by 'desc_short' and 'desc_long') and generates descriptive names of the argument like \"-f\", \"--myflag\", \"-f\/--myflag\", etc. All the--- argument names are included. In case of direct arguments (see 'desc_direct'), the descriptive name is \"@(direct argument)@\".-argname :: ArgumentDescription -> String-argname desc =-   if (argdesc_short_args desc, argdesc_long_args desc) == ([],[""]) then "(direct argument)"-      else if (argdesc_short_args desc, argdesc_long_args desc) == ([],[]) then "yet unnamed argument"-         else concat (intersperse "/" ( map (\s -> "-"++[s]) (argdesc_short_args desc) ++ map ("--" ++) (argdesc_long_args desc) ))---- | Generate a descriptive argument name from an argument description, beginning with \"argument\". This uses the long and short argument names (as--- specified by 'desc_short' and 'desc_long') and generates descriptive names of the argument like \"argument -f\", \"argument --myflag\", \"argument--- -f\/--myflag\", etc. All the argument names are included. In case of direct arguments (see 'desc_direct'), the descriptive name is \"direct argument\".-argname_a :: ArgumentDescription -> String-argname_a desc =-   if (argdesc_short_args desc, argdesc_long_args desc) == ([],[""]) then "direct argument"-      else if (argdesc_short_args desc, argdesc_long_args desc) == ([],[]) then "yet unnamed argument"-         else "argument " ++ concat (intersperse "/" ( map (\s -> "-"++[s]) (argdesc_short_args desc) ++ map ("--" ++) (argdesc_long_args desc) ))--up1 "" = ""-up1 (x:xs) = toUpper x : xs---- complete generation of argument description-prop_final :: ArgumentProperty-prop_final = ArgumentProperty-   (\desc ->-      seq (if argdesc_argarg desc /= ArgumentValue_none && argdesc_argargname desc == Nothing-              then error $ "Bug in description of " ++ argname_a desc ++ ": Argument's value must be given a name using desc_argname."-              else if argdesc_argarg desc == ArgumentValue_none && argdesc_argargname desc /= Nothing-                      then error $ "Bug in description of " ++ argname_a desc-                           ++ ": Argument doesn't take a sub argument, but a name for it is specified."-                      else ()-          ) $-          desc { argdesc_times = Just (fromMaybe times_default (argdesc_times desc))-               , argdesc_argarg_description = Just (fromMaybe "" (argdesc_argarg_description desc))-               }-   )---- |--- Make an argument description from a list of argument properties. This--- condenses the list to an argument description,--- which can be used by the @getargs@... functions and the--- argument value extraction functions.-argdesc :: [ArgumentProperty]     -- ^ List of properties, which describe the command line argument.-        -> ArgumentDescription    -- ^ The corresponding argument description.-argdesc propl =-   foldr (.) id (map argumentproperty (prop_final:propl)) nulldesc----- Parse command line arguments.-getargs0 :: String -> ArgOrder ArgOcc -> [String] -> [ArgumentDescription] -> Either ArgError Arguments-getargs0 header ordering cmdlargs descs =-   let (  descs_direct     -- direct arguments (without argument name)-        , descs_regular    -- regular arguments (with long or short argument name)-        ) = partition is_direct descs--       nonunique :: Eq a => [a] -> Maybe a-       nonunique (a:b:r) = if (a == b) then (Just a) else nonunique (b:r)-       nonunique _       = Nothing--       test_unique :: (Show a, Ord a) => (ArgumentDescription -> [a]) -> String -> b -> b-       test_unique extr what x =-           case nonunique (sort (concat (map extr descs))) of-              Just y -> error ("Bug: Several occurences of " ++ what ++ " " ++ show y ++ " in command line argument specifications")-              Nothing -> x--       optdescr = map make_optdescr descs_regular--       make_optdescr :: ArgumentDescription -> OptDescr ArgOcc-       make_optdescr desc =-          Option (argdesc_short_args desc)-                 (argdesc_long_args desc)-                 (case argdesc_argarg desc of-                     ArgumentValue_none      -> NoArg  (desc, Nothing)-                     ArgumentValue_required     -> ReqArg (\arg -> (desc, Just arg))-                                              (fromJust (argdesc_argargname desc))-                     ArgumentValue_optional     -> OptArg (\arg -> (desc, arg))-                                              (fromJust (argdesc_argargname desc))-                 )-                 (fromJust (argdesc_argarg_description desc))--       -- Postprocessing after successful call to getOpt-       getopt_post :: [ArgOcc] -> [String] -> Either ArgError Arguments-       getopt_post pars{-getOpt recognized arguments-} rest{-direct arguments-} =-          case (rest, descs_direct) of-             ([],[])  ->-                -- no direct arguments allowed and none provided-                getopt_post' pars-             (r, [d]) ->-                -- direct arguments allowed and expected-                getopt_post' (pars ++ zip (repeat d) (map Just r))-             ((x:xs), []) ->-                -- direct arguments provided, but not allowed-                Left (ArgError "Surplus arguments." usageinfo)-             _ ->-                -- several descriptions for direct arguments-                error "Bug in argument descriptions: Several descriptions for direct arguments (desc_direct) specified."--       add :: (ArgumentDescription, Maybe String) -> [(ArgumentDescription, [Maybe String])] -> [(ArgumentDescription, [Maybe String])]-       add (a,str) []        = [(a,[str])]-       add (b,str) ((a,l):r) =-          if same_arg a b then (a,str:l) : r-                          else (a,l) : add (b,str) r--       getopt_post' :: [ArgOcc] -> Either ArgError Arguments-       getopt_post' pars{-all arguments-} =-          let pars' = foldr add (map (\d -> (d,[])) descs) pars--              -- Check the number of argument occurences-              check_num :: [(ArgumentDescription, [Maybe String])] -> Maybe ArgError-              check_num [] = Nothing-              check_num ((desc,args):rest) =-                 let (min,max) = fromJust (argdesc_times desc)-                     number    = length args-                     wrong_number_msg =-                        (if is_direct desc then fst else snd) $-                        if number == 0 && min == 1 then-                           ( "Missing argument."-                           , "Missing " ++ argname_a desc ++ "."-                           )-                        else if number < min then-                           ( "Too few arguments. " ++ show min ++ " required."-                           , "Too few instances of " ++ argname_a desc ++ ". "++ show min ++ " required."-                           )-                        else if number > max && max == 1 then-                           ( "Only one argument may be specified."-                           , "Repeated " ++ argname_a desc ++ "."-                           )-                        else if number > max && max /= unlimited then-                           ( "Too many arguments."-                           , "Too many instances of " ++ argname_a desc ++ "."-                           )-                        else error "bug in HsShellScript.Args.hs"-                 in  if number >= min && (number <= max || max == unlimited)-                        then check_num rest-                        else Just (ArgError wrong_number_msg usageinfo)--              -- Apply any argument testers-              check_testers :: [(ArgumentDescription, [Maybe String])] -> Maybe ArgError-              check_testers [] = Nothing-              check_testers ((desc,args):rest) =-                 case argdesc_argarg_tester desc of-                    Just argdesc_argarg_tester -> -                       if argdesc_argarg desc == ArgumentValue_none -                          then abort "Bug in HsShellScript argument descriptions: Argument value tester specified,\n\-                                     \but no argument value has been allowed. Add desc_value_optional or\n\-                                     \desc_value_required." -                                     desc-                          else case filter isJust (map (argdesc_argarg_tester . fromJust) (filter isJust args)) of-                                  []              -> check_testers rest-                                  (Just msgf : _) -> Just (ArgError (msgf desc) usageinfo)-                    Nothing -> check_testers rest--          in  case check_testers pars' of -                 Nothing  -> case check_num pars' of-                                Nothing  -> Right (Arguments (pars',usageinfo))-                                Just err -> Left err-                 Just err -> Left err--       -- usage information generated by GetOpt-       usageinfo = usageInfo header optdescr--   in test_unique argdesc_short_args "short argument" $-         test_unique argdesc_long_args "long argument" $-            case getOpt ordering optdescr cmdlargs of-               (pars, rest, []) ->-                  getopt_post pars rest-               (_,_,f) ->-                  throw (ArgError (unlines (map chomp f)) (usageInfo header optdescr))-   where-      -- duplicated here in order to break cyclic module dependency-      chomp "" = ""-      chomp "\n" = ""-      chomp [x] = [x]-      chomp (x:xs) = let xs' = chomp xs-                     in  if xs' == "" && x == '\n' then "" else x:xs'----- |--- Parse command line arguments. The arguments are taken from a call to--- @getArgs@ and parsed. Any error is thrown as a --- @ArgError@ exception. The result is a value from which the--- information in the command line can be extracted by the @arg@...,--- @reqarg@... and @optarg@... functions.------ Named arguments (like @-x@ or @--arg@) and direct--- arguments may occur in any order.-getargs :: String                               -- ^ Header to be used in the usage info.-        -> [ArgumentDescription]          -- ^ The argument descriptions.-        -> IO Arguments                   -- ^ The contents of the command line.-getargs header descs = do-   args <- getArgs-   let res = getargs0 header Permute args descs-   either throw-          return-          res---- |--- Parse command line arguments. The arguments are taken from a call to--- @getArgs@ and parsed. Any error is thrown as a --- @ArgError@ exception. The result is a value from which the--- information in the command line can be extracted by the @arg@...,--- @reqarg@... and @optarg@... functions.------ All arguments after the first direct argument are regarded as direct--- arguments. This means that argument names introduced by @-@--- or @--@ no longer take effect.-getargs_ordered :: String                       -- ^ Header to be used in the usage info.-                -> [ArgumentDescription]  -- ^ Descriptions of the arguments.-                -> IO Arguments           -- ^ The contents of the command line.-getargs_ordered header descs = do-   args <- getArgs-   either throw-          return-          (getargs0 header RequireOrder args descs)---- |--- Parse the specified command line. Any error is returned as @Left--- argerror@. In case of success, the result is returned as--- @Right res@. From the result, the information in the command--- line can be extracted by the @arg@..., @reqarg@...--- and @optarg@... functions.------ Named arguments (like @-x@ or @--arg@) and direct--- arguments may occur in any order.-getargs' :: String                              -- ^ Header to be used in the usage info.-         -> [String]                            -- ^ Command line to be parsed.-         -> [ArgumentDescription]         -- ^ The argument descriptions.-         -> Either ArgError Arguments     -- ^ The contents of the command line.-getargs' header args descs = getargs0 header Permute args descs---- |--- Parse the specified command line. Any error is returned as @Left--- argerror@. In case of success, the result is returned as--- @Right res@. From the result, the information in the command--- line can be extracted by the @arg@..., @reqarg@...--- and @optarg@... functions.------ All arguments after the first direct argument are regarded as direct--- arguments. This means that argument names introduced by @-@--- or @--@ no longer take effect.-getargs_ordered' :: String                              -- ^ Header to be used in the usage info.-                 -> [String]                            -- ^ Command line to be parsed.-                 -> [ArgumentDescription]         -- ^ The argument descriptions.-                 -> Either ArgError Arguments     -- ^ The contents of the command line.-getargs_ordered' header args descs = getargs0 header RequireOrder args descs---test_desc :: ArgumentDescription -> Bool -> String -> b -> b-test_desc desc ok msg x =-   if ok then x-         else abort msg desc--maybe_head :: [a] -> Maybe a-maybe_head [] = Nothing-maybe_head [a] = Just a---- |--- Query whether a certain switch is specified on the command line. A switch is an--- argument which is allowed zero or one time, and has no value.-arg_switch :: Arguments                   -- ^ Command line parse result.-           -> ArgumentDescription         -- ^ Argument description of the switch.-           -> Bool                              -- ^ Whether the switch is present in the command line.-arg_switch args desc =-   test_desc desc (argdesc_argarg desc == ArgumentValue_none && argdesc_times desc == Just (0,1))-             "bug: querying argument with is not a switch with arg_switch" $-   case argvalues args desc of-      []         -> False-      [Nothing]  -> True---- |--- Query the number of occurences of an argument.-arg_times :: Arguments                    -- ^ Command line parse result.-          -> ArgumentDescription          -- ^ Description of the argument.-          -> Int                          -- ^ Number of times the argument occurs.-arg_times args desc =-   length (argvalues args desc)---- |--- Query the values of an argument with optional value. This is for--- arguments which take an optional value, and may occur several times. The--- occurences with value are represented as @Just value@, the occurences--- without are represented as @Nothing@.-args_opt :: Arguments                     -- ^ Command line parse result.-         -> ArgumentDescription           -- ^ Description of the argument.-         -> [Maybe String]                      -- ^ The occurences of the argument.-args_opt args desc =-   test_desc desc (argdesc_argarg desc == ArgumentValue_optional && snd (fromJust (argdesc_times desc)) /= 1)-             "Bug: Querying argument which doesn't take an optional value, or may not occur several times, with args_opt."-   $ argvalues args desc---- |--- Query the values of an argument with required value. This is for--- arguments which require a value, and may occur several times.-args_req :: Arguments                     -- ^ Command line parse result.-         -> ArgumentDescription           -- ^ Description of the argument.-         -> [String]                            -- ^ The values of the argument.-args_req args desc =-   test_desc desc (argdesc_argarg desc == ArgumentValue_required && snd (fromJust (argdesc_times desc)) /= 1)-             "Bug: Querying argument which doesn't require a value, or may not occur several times, with args_req." $-   map fromJust (argvalues args desc)---- |--- Query the optional value of a required argument. This is for arguments--- which must occur once, and may have a value. If the argument is--- specified, its value is returned as @Just value@. If it isn't, the result--- is @Nothing@.-reqarg_opt :: Arguments                   -- ^ Command line parse result.-           -> ArgumentDescription         -- ^ Description of the argument.-           -> Maybe String                      -- ^ The value of the argument, if it occurs.-reqarg_opt args desc =-   test_desc desc (argdesc_argarg desc == ArgumentValue_optional && argdesc_times desc == Just (1,1))-             "Bug: Querying argument which doesn't take an optional value, or which must not occur exactly once, with reqarg_opt." $-   head (argvalues args desc)---- |--- Query the value of a required argument. This is for arguments which must--- occur exactly once, and require a value.-reqarg_req :: Arguments                   -- ^ Command line parse result.-           -> ArgumentDescription         -- ^ Description of the argument.-           -> String                            -- ^ The value of the argument.-reqarg_req args desc =-   test_desc desc (argdesc_argarg desc == ArgumentValue_required && argdesc_times desc == Just (1,1))-             "Bug: Querying argument with non-required value, or which doesn't occur exactly once, with reqarg_req." $-   fromJust (head (argvalues args desc))---- |--- Query the optional value of an optional argument. This is for arguments--- which may occur zero or one time, and which may or may not have a value.--- If the argument doesn't occur, the result is @Nothing@. If it does occur,--- but has no value, then the result is @Just Nothing@. If it does occur with--- value, the result is @Just (Just value)@.-optarg_opt :: Arguments                   -- ^ Command line parse result.-           -> ArgumentDescription         -- ^ Description of the argument.-           -> Maybe (Maybe String)              -- ^ The occurence of the argument and its value (see above).-optarg_opt args desc =-   test_desc desc (argdesc_argarg desc == ArgumentValue_optional)  "Bug: Querying argument with non-optional value with optarg_opt." $-   test_desc desc (fst (fromJust (argdesc_times desc)) == 0)       "Bug: Querying argument which isn't optional with optarg_opt." $-   test_desc desc (snd (fromJust (argdesc_times desc)) == 1)       "Bug: Querying argument which may occur several times optarg_opt." $-   maybe_head (argvalues args desc)---- |--- Query the value of an optional argument. This is for optional arguments--- which require a value, and may occur at most once. The result is--- @Just value@ if the argument occurs, and @Nothing@--- if it doesn't occur.-optarg_req :: Arguments                   -- ^ Command line parse result.-           -> ArgumentDescription         -- ^ Description of the argument.-           -> Maybe String                      -- ^ The value of the argument, if it occurs.-optarg_req args desc =-   test_desc desc (argdesc_argarg desc == ArgumentValue_required)        "Bug: Querying argument with non-required value with optarg_req."-   $ test_desc desc (fst (fromJust (argdesc_times desc)) == 0)          "Bug: Querying argument which isn't optional with optarg_req."-   $ test_desc desc (snd (fromJust (argdesc_times desc)) == 1)          "Bug: Querying argument which may occur several times optarg_req."-   $ fmap fromJust (maybe_head (argvalues args desc))----- |--- None of the specifed arguments may be present.------ Throws an ArgError if any of the arguments are present.-args_none :: [ArgumentDescription]        -- ^ List of the arguments which must not be present.-          -> Arguments                    -- ^ Command line parse result.-          -> IO ()-args_none descs args@(Arguments (argl,usageinfo)) =-   mapM_ (\desc ->-             when (arg_times args desc /= 0) $-                throw (ArgError (up1 (argname_a desc) ++ " is not allowed.\n") usageinfo)-         )-         descs---- |--- All of the specified arguments must be present.------ Throws an ArgError if any is missing.-args_all :: [ArgumentDescription]         -- ^ List of the arguments which must be present.-         -> Arguments                     -- ^ Command line parse result.-         -> IO ()-args_all descs args@(Arguments (argl,usageinfo)) =-   mapM_ (\desc ->-             when (arg_times args desc == 0) $-                throw (ArgError ("Missing " ++ argname_a desc ++ "\n") usageinfo)-         )-         descs---- |--- Exactly one of the specified arguments must be present.------ Otherwise throw an ArgError.-args_one :: [ArgumentDescription]         -- ^ List of the arguments, of which exactly one must be present.-         -> Arguments                     -- ^ Command line parse result.-         -> IO ()-args_one descs args@(Arguments (argl,usageinfo)) =-   when (occuring descs args /= 1) $-      throw (ArgError ("Exactly one of the following arguments must be present.\n"-                       ++ concat (intersperse ", " (map argname descs)) ++ "\n")-                       usageinfo)----- |--- At most one of the specified arguments may be present.------ Otherwise throw an ArgError.-args_at_most_one :: [ArgumentDescription] -- ^ List of the arguments, of which at most one may be present.-                 -> Arguments             -- ^ Command line parse result.-                 -> IO ()-args_at_most_one descs args@(Arguments (argl,usageinfo)) =-   when (occuring descs args > 1) $-      throw (ArgError ("Only one of the following arguments may be present.\n"-                       ++ concat (intersperse ", " (map argname descs)) ++ "\n")-                      usageinfo)----- |--- At least one of the specified arguments must be present.------ Otherwise throw an ArgError.-args_at_least_one :: [ArgumentDescription]        -- ^ List of the arguments, of which at least one must be present.-                  -> Arguments                    -- ^ Command line parse result.-                  -> IO ()-args_at_least_one descs args@(Arguments (argl,usageinfo)) =-   when (occuring descs args == 0) $-      throw (ArgError ("One of the following arguments must be present.\n"-                       ++ concat (intersperse ", " (map argname descs)) ++ "\n")-                      usageinfo)----- |--- When the specified argument is present, then none of the other arguments may be present.------ Otherwise throw an ArgError.-arg_conflicts :: ArgumentDescription   -- ^ Argument which doesn't tolerate the other arguments-              -> [ArgumentDescription] -- ^ Arguments which aren't tolerated by the specified argument-              -> Arguments             -- ^ Command line parse result.-              -> IO ()-arg_conflicts desc descs args@(Arguments (argl,usageinfo)) =-   when (arg_occurs args desc && occuring descs args > 1) $-      throw (ArgError ("When " ++ argname desc ++ " is present, none of the following arguments may be present.\n"-                       ++ concat (intersperse ", " (map argname descs)) ++ "\n")-                       usageinfo)----- How many of the specified arguments do occur? Multiple occurences of the same argument count as one.-occuring :: [ArgumentDescription] -> Arguments -> Int-occuring descs args =-   sum (map (\desc -> if arg_times args desc == 0 then 0 else 1) descs)---{- | Whether the specified argument occurs in the command line. --}-arg_occurs :: Arguments                   -- ^ Command line parse result.-           -> ArgumentDescription         -- ^ Description of the respective argument.-           -> Bool                              -- ^ Whether the specified argument occurs in the command line.-arg_occurs args desc =-   occuring [desc] args == 1----- |--- Get the usage information from the parsed arguments. The usage info--- contains the header specified to the corresponding @getargs...@--- function, and descriptions of the command line arguments.-usage_info :: Arguments -> String-usage_info (Arguments (_,ui)) = ui---{--instance Show (OptDescr a) where-   show (Option short long argdescr expl) =-       "Option short:" ++ showList short " long:" ++ show long ++ " argdescr:" ++ show argdescr ++ " expl:" ++ showList expl ""--instance Show (ArgDescr a) where-   show (NoArg _) = "NoArg"-   show (ReqArg _ _) = "ReqArg ..."-   show (OptArg _ _) = "OptArg ..."--}---{- | @getargs@ as a pure function, instead of an IO action. This allows to make evaluated command line arguments global values. This calls @getargs@-   to parse the command line arguments. @GHC.IO.unsafePerformIO@ is used to take the result out of the IO monad.--   >unsafe_getargs header descs = GHC.IO.unsafePerformIO $ getargs header descs--   The @getargs@ action is performed on demand, when the parse result is evaluated. It may result in an 'ArgError' being thrown. In order to avoid-   this happening at unexpected times, the @main@ function should, start with the line @seq args (return ())@, where @args@ is the result of-   @unsafe_getargs@,. This will trigger any command line argument errors at the beginning of the program. (See section 6.2 of the Hakell Report for the-   definition of @seq@).--   A typical use of @unsafe_getargs@ looks like this:-->header = "..."->descs = [ d_myflag, ... ]->->d_myflag = argdesc [ ... ]->->args = unsafe_getargs header descs->myflag = arg_switch args d_myflag->->main = mainwrapper $ do->   seq args (return ())->   ...--  See 'getargs', 'unsafe_getargs_ordered'.--}-unsafe_getargs :: String                        -- ^ The header used in the usage information-               -> [ArgumentDescription]   -- ^ The argument descriptions-               -> Arguments               -- ^ The parsed command line arguments-unsafe_getargs header descs = -   GHC.IO.unsafePerformIO $ getargs header descs---{- | @getargs_ordered@ as a pure function, instead of an IO action. This is exactly like @unsafe_getargs@, but using @getargs_ordered@ instead of-   @getargs@.--   >unsafe_getargs_ordered = GHC.IO.unsafePerformIO $ getargs_ordered header descs--   See 'unsafe_getargs'.--}-unsafe_getargs_ordered :: String                        -- ^ The header used in the usage information-                       -> [ArgumentDescription]   -- ^ The argument descriptions-                       -> Arguments               -- ^ The parsed command line arguments-unsafe_getargs_ordered header descs = -   GHC.IO.unsafePerformIO $ getargs_ordered header descs
+ src/HsShellScript/Args.hs-boot view
@@ -0,0 +1,9 @@+module HsShellScript.Args where++data ArgError = ArgError {+      argerror_message :: String,+      argerror_usageinfo :: String+   }+   deriving (Typeable)++
src/HsShellScript/Commands.chs view
@@ -5,7 +5,6 @@ import Prelude hiding (catch) import Control.Exception import Data.Bits--- import Directory import Foreign.C import Foreign.C.Error import Foreign.Ptr@@ -23,15 +22,14 @@ import Control.Exception import Text.ParserCombinators.Parsec as Parsec import System.Posix hiding (rename, createDirectory, removeDirectory)---import System.Env import System.Random import System.Directory  -- | -- Do a call to the @realpath(3)@ system library function. This makes the path absolute, normalizes it and expands all symbolic links. In case of an -- error, an @IOError@ is thrown.-realpath :: String      -- ^ path-         -> IO String	-- ^ noramlized, absolute path, with symbolic links expanded+realpath :: String    -- ^ path+         -> IO String -- ^ noramlized, absolute path, with symbolic links expanded realpath path =    withCString path $ \cpath -> do       res <- {#call hsshellscript_get_realpath#} cpath@@ -43,8 +41,8 @@ -- the directory which the symlink is in. In case of an error, an @IOError@ is thrown. The path is included and can be accessed with -- @IO.ioeGetFileName@. Note that, if the path to the symlink ends with a slash, this path denotes the directory pointed to, /not/ the symlink. In -- this case the call to will fail because of \"Invalid argument\".-readlink :: String      -- ^ Path of the symbolic link-         -> IO String	-- ^ The link target - where the symbolic link points to+readlink :: String    -- ^ Path of the symbolic link+         -> IO String -- ^ The link target - where the symbolic link points to readlink path =    withCString path $ \cpath -> do       res <- {#call hsshellscript_get_readlink#} cpath@@ -57,7 +55,7 @@ -- to, /not/ the symlink. In this case the call to @readlink@ will fail with an @IOError@ because of \"Invalid argument\". In case of any error, a -- proper @IOError@ is thrown. readlink' :: String     -- ^ path of the symbolic link-          -> IO String	-- ^ target; where the symbolic link points to+          -> IO String  -- ^ target; where the symbolic link points to readlink' symlink = do    target <- readlink symlink    return (absolute_path' target (fst (split_path symlink)))
src/HsShellScript/GetOpt.hs view
@@ -5,20 +5,20 @@ -}  module HsShellScript.GetOpt (-	-- * GetOpt-	getOpt,-	usageInfo,-	ArgOrder(..),-	OptDescr(..),-	ArgDescr(..),+        -- * GetOpt+ getOpt,+ usageInfo,+ ArgOrder(..),+ OptDescr(..),+ ArgDescr(..), -	-- * Example-		-	-- $example+ -- * Example+  + -- $example   ) where  import Prelude-import Data.List 	( isPrefixOf )+import Data.List  ( isPrefixOf )  -- |What to do with options following non-options data ArgOrder a@@ -241,7 +241,7 @@ >    data Flag  >     = Verbose  | Version  >     | Input String | Output String | LibDir String->    	deriving Show+>     deriving Show >     >    options :: [OptDescr Flag] >    options =@@ -258,9 +258,9 @@ >     >    compilerOpts :: [String] -> IO ([Flag], [String]) >    compilerOpts argv = ->    	case (getOpt Permute options argv) of->    	   (o,n,[]  ) -> return (o,n)->    	   (_,_,errs) -> ioError (userError (concat errs ++ usageInfo header options))+>     case (getOpt Permute options argv) of+>        (o,n,[]  ) -> return (o,n)+>        (_,_,errs) -> ioError (userError (concat errs ++ usageInfo header options)) >      where header = "Usage: ic [OPTION...] files..."  -}
src/HsShellScript/Misc.chs view
@@ -472,6 +472,28 @@             )  +-- |+-- Quote special characters for use with the @glob@ function.+--+-- The characters @*@, @?@, @[@ and @\\@ must be quoted by preceding+-- backslashs, when they souldn't have their special meaning. The @glob_quote@+-- function does this.+-- +-- You can't use @quote@ or @shell_quote@.+--+-- See 'glob', 'quote', 'shell_quote'+glob_quote :: String+           -> String+glob_quote path = +   case path of+      []          -> []+      ('*':rest)  -> ('\\':'*':glob_quote rest)+      ('?':rest)  -> ('\\':'?':glob_quote rest)+      ('[':rest)  -> ('\\':'[':glob_quote rest)+      ('\\':rest) -> ('\\':'\\':glob_quote rest)+      (ch:rest)   -> ch : glob_quote rest++  #c /*
src/HsShellScript/ProcErr.chs view
@@ -24,8 +24,6 @@ import GHC.IO.Handle import GHC.IO.Handle.Internals             -- withHandle', do_operation import GHC.IO.Handle.Types hiding (close)-import HsShellScript.Args-import HsShellScript.Shell import Prelude hiding (catch) import System.Directory import System.Environment@@ -39,6 +37,9 @@ import qualified GHC.IO.FD as FD import qualified System.IO.Error                -- mkIOError +import HsShellScript.Args+import HsShellScript.Shell+ infixr 2 -|-    -- left handed, stdout infixr 2 =|-    -- left handed, stderr infixl 2 -|=    -- right handed, stdout@@ -70,21 +71,19 @@ -- Execute an IO action as a separate process, and wait for it to finish. -- Report errors as exceptions. ----- This forks a child process, which performs the specified IO action.--- In--- case the child process has been stopped by a signal, the parent blocks.+-- This forks a child process, which performs the specified IO action. In case+-- the child process has been stopped by a signal, the parent blocks. -- -- If the action throws an @IOError@, it is transmitted to the parent. -- It is then raised there, as if it happened locally. The child then aborts -- quietly with an exit code of 0. ----- Exceptions in--- the child process, other than @IOError@s, result in an error message on @stderr@, and a--- @ProcessStatus@ exception in the parent, with the value of @Exited--- (ExitFailure 1)@. The following exceptions are understood by @subproc@, and--- result in corresponding messages: @ArgError@, @ProcessStatus@, @RunError@,--- @IOError@ and @ExitCode@. Other exceptions result in the generic message, as--- produced by @show@.+-- Exceptions in the child process, other than @IOError@s, result in an error+-- message on @stderr@, and a @ProcessStatus@ exception in the parent, with the+-- value of @Exited (ExitFailure 1)@. The following exceptions are understood by+-- @subproc@, and result in corresponding messages: @ArgError@, @ProcessStatus@,+-- @RunError@, @IOError@ and @ExitCode@. Other exceptions result in the generic+-- message, as produced by @show@. -- -- If the child process exits with an exit code other than zero, or it is -- terminated by a signal, the corresponding @ProcessStatus@ is raised as an@@ -2159,10 +2158,6 @@          )     where-      handleToFd_noclose :: Handle -> IO Fd-      handleToFd_noclose h =-         unsafeWithHandleFd h (\fd -> return fd)-       restore h@(FileHandle _ mvar) fd = do          -- The fd used by the handle. This is in GHC.IO.Handle.FD          --                              handleToFd_noclose: Fehlerhaft, aus hssh-2.9@@ -2229,6 +2224,12 @@   +handleToFd_noclose :: Handle -> IO Fd+handleToFd_noclose h =+    unsafeWithHandleFd h (\fd -> return fd)+++ {- About Bas van Dijk's unsafeWithHandleFd:     This function is broken. It blocks when called like this:@@ -2396,6 +2397,47 @@ instance Exception ProcessStatus  ++-- | Determine the terminal width in columns. +--+-- This value can be used to format output to fit the terminal.+--+-- This queries the terminal which is connected to stdout. It may happen, that+-- stdout isn't connected to a terminal. For instance when the program is part of+-- a pipe. In this case, an IOError is thrown.+--+-- See 'terminal_width', 'make_usage_info', 'print_usage_info', 'usage_info', 'wrap'.+terminal_width_ioe :: Handle                -- ^ Handle, which is connected to the terminal    +                   -> IO Int                -- ^ The number of columns in the constrolling terminal. +                                        --   Nothing, when the handle isn't connected to a terminal.+terminal_width_ioe h = do++   fd <- unsafeWithHandleFd h $ \fd -> do +      res <- {#call c_terminal_width#} (fromIntegral fd)+      when (res == -1) $ throwErrno' "terminal_width" Nothing Nothing+      return res+   return (fromIntegral fd)+++-- | Determine the terminal width in columns. +--+-- This value can be used to format output to fit the terminal.+--+-- This queries the terminal which is connected to stdout. It may happen, that+-- stdout isn't connected to a terminal, for instance when the program is part of+-- a pipe. In this case, @Nothing@ is returned. No exception is thrown.+--+-- See 'terminal_width_ioe', 'make_usage_info', 'print_usage_info', 'usage_info', 'wrap'.+terminal_width :: Handle                -- ^ Handle, which is connected to the terminal    +               -> IO (Maybe Int)        -- ^ The number of columns in the constrolling terminal. +                                    --   Nothing, when the handle isn't connected to a terminal.+terminal_width h = do+   w <- terminal_width_ioe h+   return (Just w)+   `catch` (\(ioe :: IOError) -> return Nothing)+++ #c /* c2hs-0.14.5 chokes on the following includes.@@ -2432,4 +2474,7 @@  /* Set the flags of a file descriptor. Returns the old flags. */ int c_set_flags(int fd, int new_flags);++/* Determine the with of the controlling terminal */+int c_terminal_width(int fd); #endc
+ src/HsShellScript/ProcErr.hs-boot view
@@ -0,0 +1,9 @@+module HsShellScript.ProcErr where++import Data.Maybe+import System.IO++terminal_width :: Handle -> IO (Maybe Int)+terminal_width_ioe :: Handle -> IO Int++throwErrno' :: String -> Maybe Handle -> Maybe FilePath -> IO a
src/cbits/hsshellscript.c view
@@ -8,6 +8,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h>+#include <sys/ioctl.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h>@@ -132,3 +133,20 @@   return old_flags; } +int c_terminal_width_stdout(void)+{+  struct winsize size;+  if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &size) == -1)+    return -1;+  else +    return size.ws_col;+}++int c_terminal_width_stderr(void)+{+  struct winsize size;+  if (ioctl (STDERR_FILENO, TIOCGWINSZ, &size) == -1)+    return -1;+  else +    return size.ws_col;+}
test/Makefile view
@@ -1,6 +1,5 @@-VERSION=3.3.4-CFLAGS=-XDeriveDataTypeable -i../dist/build -package-name hsshellscript-3.3.4-# Kleines i bei "-i" oben+VERSION=3.4.0+CFLAGS=-XDeriveDataTypeable   PROG_HS  = $(notdir $(basename $(wildcard [_abcdefghijklmnopqrstuvwxyzäöü]*.hs))) PROG_CHS = $(notdir $(basename $(wildcard [_abcdefghijklmnopqrstuvwxyzäöü]*.chs)))@@ -9,13 +8,16 @@ PROGS    = $(sort $(PROG_HS) $(PROG_CHS))  -% : %.o cteile.o ../dist/build/libHShsshellscript-$(VERSION).a-	ghc -o $@ $^ -package haskell2010 -package unix -package directory -package random+% : %.o cteile.o+	ghc -o $@ $^ -package unix -package directory -package random -package parsec -package hsshellscript  %.o : %.hs 	ghc -c $(CFLAGS) $^ -%.o : %.c+# %.o : %.c++cteile.o : cteile.c+	echo CTEILE 	gcc -c -o $@ $<  %.hs : %.chs@@ -24,15 +26,15 @@ 	chmod u-w $@  clean :: depend-	rm -f *.hi *.o *~ *.bak $(PROGS) *.chi *.chs.h \+	rm -f -- *.hi *.o *~ *.bak $(PROGS) *.chi *.chs.h \ 	      $(foreach m, $(PROG_CHS), "$(m).hs")  depend :: $(foreach m, $(PROGS), $(m).hs) 	ghc -M $(CFLAGS) -dep-makefile -optdepdepend -dep-suffix "p_" \ 	       $(foreach m, $(PROGS), "$(m).hs")-	make cteile.o+#	make cteile.o -z : z.c-	gcc -o $@ $<+#z : z.c+#	gcc -o $@ $<  -include depend
+ test/_exit.hs view
+ test/args.chs view
@@ -0,0 +1,67 @@+-- Fehler, wenn die Breiten nicht hinkommen in make_usage_info++module Main (main) where++import HsShellScript+import Data.Maybe+import Data.List+import Debug.Trace+import Control.Monad+import Control.Exception+import System.IO+++header                                  = "Testprogramm für Kommandozeilenargumente\n\n"+descs                                   = [ d_trenner, d_pfade, d_uml, d_komp, d_inhalt ]+args                                    = unsafe_getargs header descs+trenner_normal                          = " - "++pfade                                   = args_req args d_pfade+trenner                                 = fromMaybe trenner_normal $ optarg_req args d_trenner+inhalt                                  = arg_switch args d_inhalt+komp                                    = optarg_req args d_komp+++d_komp = +   argdesc [ desc_short 'k'+           , desc_long "komp"+           , desc_value_required+           , desc_argname "<Name>"+           , desc_description "Das ist eine lange Argumentbeschreibung, die umgebrochen werden muß, weil sie zu lang ist. Wirklich. Undhierkommteinganzlangeswortdasgetrenntwerdenmuß"+           ]++d_trenner = +   argdesc [ desc_short 't'+           , desc_long "langer-param"+           , desc_at_most_once+           , desc_value_required+           , desc_argname "<Txt>"+           , desc_description ("Diese Beschreibung\nhat mehrere\n\nZeilen.")+           ]++d_uml = +   argdesc [ desc_long "äöüß"+           , desc_at_most_once+           ]++d_pfade = +   argdesc [ desc_direct+           , desc_any_times+           , desc_description ("Pfade, denen vorgesetzt werden soll; bzw, bla bla Verzeichnisse, die ihren Inhalten vorgesetzt werden sollen")+           ]++d_inhalt = +   argdesc [ desc_long "inhalt"+           , desc_description ("Nicht angegebenen Dateien vorsetzen, sondern dem Inhalt der angegebenen Verzeichnisse. Angegebene Nicht-Verzeichnisse \+                              \beiseitelassen.")+           ]+++main = mainwrapper $ do+   seq args (return ())+   +   print_usage_info stdout "Das ist ein langer Header... Das ist ein langer Header... Das ist ein langer Header... Das\+                           \ist ein langer Header... Das ist ein langer Header... Das ist ein langer Header... Das ist \+                           \ein langer Header... Das ist ein langer Header... Das ist ein langer Header... \n\n"+                           descs+
+ test/args.hs view
@@ -0,0 +1,74 @@+-- GENERATED by C->Haskell Compiler, version 0.27.1 Eternal Sunshine, 29 November 2015 (Haskell)+-- Edit the ORIGNAL .chs file instead!+++{-# LINE 1 "args.chs" #-}+-- Fehler, wenn die Breiten nicht hinkommen in make_usage_info++module Main (main) where++++import HsShellScript+import Data.Maybe+import Data.List+import Debug.Trace+import Control.Monad+import Control.Exception+import System.IO+++header                                  = "Testprogramm für Kommandozeilenargumente\n\n"+descs                                   = [ d_trenner, d_pfade, d_uml, d_komp, d_inhalt ]+args                                    = unsafe_getargs header descs+trenner_normal                          = " - "++pfade                                   = args_req args d_pfade+trenner                                 = fromMaybe trenner_normal $ optarg_req args d_trenner+inhalt                                  = arg_switch args d_inhalt+komp                                    = optarg_req args d_komp+++d_komp = +   argdesc [ desc_short 'k'+           , desc_long "komp"+           , desc_value_required+           , desc_argname "<Name>"+           , desc_description "Das ist eine lange Argumentbeschreibung, die umgebrochen werden muß, weil sie zu lang ist. Wirklich. Undhierkommteinganzlangeswortdasgetrenntwerdenmuß"+           ]++d_trenner = +   argdesc [ desc_short 't'+           , desc_long "langer-param"+           , desc_at_most_once+           , desc_value_required+           , desc_argname "<Txt>"+           , desc_description ("Diese Beschreibung\nhat mehrere\n\nZeilen.")+           ]++d_uml = +   argdesc [ desc_long "äöüß"+           , desc_at_most_once+           ]++d_pfade = +   argdesc [ desc_direct+           , desc_any_times+           , desc_description ("Pfade, denen vorgesetzt werden soll; bzw, bla bla Verzeichnisse, die ihren Inhalten vorgesetzt werden sollen")+           ]++d_inhalt = +   argdesc [ desc_long "inhalt"+           , desc_description ("Nicht angegebenen Dateien vorsetzen, sondern dem Inhalt der angegebenen Verzeichnisse. Angegebene Nicht-Verzeichnisse \+                              \beiseitelassen.")+           ]+++main = mainwrapper $ do+   seq args (return ())+   +   print_usage_info stdout "Das ist ein langer Header... Das ist ein langer Header... Das ist ein langer Header... Das\+                           \ist ein langer Header... Das ist ein langer Header... Das ist ein langer Header... Das ist \+                           \ein langer Header... Das ist ein langer Header... Das ist ein langer Header... \n\n"+                           descs+
test/cteile.c view
@@ -1,6 +1,11 @@ #include <stdio.h> #include <string.h> +#include <stdio.h>+#include <unistd.h>+#include <sys/ioctl.h>++ void c_aufruf(const char* ptr) {   printf("ptr = >%s<\nlength = %d\n", ptr, (int) strlen(ptr));@@ -31,3 +36,19 @@   printf("\", Länge = %d\n",len); } ++++//----------------------------------------------------------------------------------------------------++// Thanks to Jan-Benedict Glaw for this+int c_terminal_width(int fd)+{+  int res;+  struct winsize size;++  res = ioctl (fd, TIOCGWINSZ, &size);++  if (res == -1) return -1;+  else return size.ws_col;+}
+ test/fdupes.hs view
@@ -0,0 +1,6 @@+import HsShellScript++main = do+   erg <- fdupes ["-r", "-s", "-H"] ["."]+   print erg+
+ test/glob_quote.hs view
@@ -0,0 +1,12 @@+import HsShellScript++silly = "[[silly \\ filename]]"++main = do+   runprog "touch" ["/tmp/"++silly]+   +   q <- glob ("/tmp/"++glob_quote silly)+   outm ("Quoted: " ++ show q)++   nq <- glob ("/tmp/"++ silly)+   outm ("Non-quoted: " ++ show nq)