Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
GHC
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package Registry
Model registry
Operate
Terraform modules
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Gesh
GHC
Commits
5a5362b0
Commit
5a5362b0
authored
27 years ago
by
sof
Browse files
Options
Downloads
Patches
Plain Diff
[project @ 1997-06-05 23:28:37 by sof]
Updated for 2.04
parent
f1ab58e5
Loading
Loading
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
ghc/misc/examples/hsh/Hsh.hs
+93
-89
93 additions, 89 deletions
ghc/misc/examples/hsh/Hsh.hs
with
93 additions
and
89 deletions
ghc/misc/examples/hsh/Hsh.hs
+
93
−
89
View file @
5a5362b0
module
Main
(
main
)
where
module
Main
(
main
)
where
import
LibPosix
import
LibSystem
import
IO
import
Posix
import
Directory
(
setCurrentDirectory
)
import
System
(
getEnv
,
exitWith
,
ExitCode
(
..
)
)
import
Char
(
isSpace
)
main
::
IO
()
main
=
initialize
>>
do
initialize
commandLoop
{-
...
...
@@ -17,24 +21,25 @@ main =
initialize
::
IO
()
initialize
=
dup
Channel
To
stdInput
myStdin
>>
dup
Channel
To
stdOutput
myStdout
>>
dup
Channel
To
stdError
myStderr
>>
c
lose
Channel
stdInput
>>
c
lose
Channel
stdOutput
>>
--
c
lose
Channel
stdError >>
installHandler
sigINT
(
Catch
intr
)
Nothing
>>
dupTo
stdInput
myStdin
>>
dupTo
stdOutput
myStdout
>>
dupTo
stdError
myStderr
>>
fdC
lose
stdInput
>>
fdC
lose
stdOutput
>>
--
fdC
lose stdError >>
installHandler
sigINT
(
Catch
intr
)
Nothing
>>
return
()
myStdin
=
16
::
Channel
myStdout
=
17
::
Channel
myStderr
=
18
::
Channel
-- some random fd numbers...
myStdin
=
intToFd
16
myStdout
=
intToFd
17
myStderr
=
intToFd
18
-- For user interrupts
intr
::
IO
()
intr
=
w
rite
Channel
myStdout
"
\n
"
>>
fdW
rite
myStdout
"
\n
"
>>
commandLoop
{-
...
...
@@ -44,46 +49,47 @@ intr =
commandLoop
::
IO
()
commandLoop
=
w
rite
Channel
myStdout
"$ "
>>
try
(
readCommand
myStdin
)
>>=
fdW
rite
myStdout
"$ "
>>
try
(
readCommand
myStdin
)
>>=
either
(
\
err
->
case
err
of
EOF
->
return
()
_
->
dieHorribly
)
(
\
err
->
if
isEOFError
err
then
return
()
else
dieHorribly
)
(
\
cmd
->
try
(
processCommand
cmd
)
>>=
either
(
\
err
->
commandLoop
)
(
\
succ
->
commandLoop
))
try
(
processCommand
cmd
)
>>=
either
(
\
err
->
commandLoop
)
(
\
succ
->
commandLoop
))
where
dieHorribly
::
IO
()
dieHorribly
=
errMsg
"read failed"
>>
exitWith
(
ExitFailure
1
)
do
errMsg
"read failed"
exitWith
(
ExitFailure
1
)
{-
Read a command a character at a time (to allow for fancy processing later).
On newline, you're done, unless the newline was escaped by a backslash.
-}
readCommand
::
Channel
->
IO
String
readCommand
chan
=
readCommand
::
Fd
->
IO
String
readCommand
fd
=
accumString
""
>>=
\
cmd
->
return
cmd
where
accumString
::
String
->
IO
String
accumString
s
=
myGetChar
chan
>>=
\
c
->
myGetChar
fd
>>=
\
c
->
case
c
of
'
\\
'
->
myGetChar
chan
>>=
\
c'
->
myGetChar
fd
>>=
\
c'
->
accumString
(
c'
:
c
:
s
)
'
\n
'
->
return
(
reverse
s
)
ch
->
accumString
(
ch
:
s
)
myGetChar
::
Channel
->
IO
Char
myGetChar
::
Fd
->
IO
Char
myGetChar
chan
=
readChannel
chan
1
>>=
\
(
s
,
len
)
->
do
(
s
,
len
)
<-
fdRead
chan
1
case
len
of
0
->
myGetChar
chan
1
->
return
(
head
s
)
...
...
@@ -97,53 +103,50 @@ myGetChar chan =
processCommand
::
String
->
IO
()
processCommand
""
=
return
()
processCommand
s
=
parseCommand
s
>>=
\
words
->
parseRedirection
words
>>=
\
(
inFile
,
outFile
,
words
)
->
performRedirections
inFile
outFile
>>
let
cmd
=
head
words
args
=
tail
words
in
case
builtin
cmd
of
Just
f
->
f
args
>>
closeChannel
stdInput
>>
closeChannel
std
Out
put
Nothing
->
exec
cmd
args
do
words
<-
parseCommand
s
(
inFile
,
outFile
,
words
)
<-
parseRedirection
words
performRedirections
inFile
outFile
let
cmd
=
head
words
args
=
tail
words
case
builtin
cmd
of
Just
f
->
do
f
args
fdClose
std
In
put
fdClose
stdOutput
Nothing
->
exec
cmd
args
{-
Redirections are a bit of a pain, really. If none are specified, we
dup
Channel
our own file descriptors. Otherwise, we try to open the files
dup our own file descriptors. Otherwise, we try to open the files
as requested.
-}
performRedirections
::
Maybe
String
->
Maybe
String
->
IO
()
performRedirections
inFile
outFile
=
(
case
inFile
of
Nothing
->
dupChannelTo
myStdin
stdInput
Just
x
->
try
(
openChannel
x
ReadOnly
Nothing
False
False
False
False
False
)
Nothing
->
dupTo
myStdin
stdInput
Just
x
->
try
(
openFd
x
ReadOnly
Nothing
defaultFileFlags
)
>>=
either
(
\
err
->
errMsg
(
"Can't redirect input from "
++
x
)
>>
failWith
(
UserError
"redirect"
))
errMsg
(
"Can't redirect input from "
++
x
)
>>
fail
(
userError
"redirect"
))
(
\
succ
->
return
()
))
>>
(
case
outFile
of
Nothing
->
dup
Channel
To
myStdout
stdOutput
dupTo
myStdout
stdOutput
Just
x
->
try
(
createFile
x
stdFileMode
)
>>=
try
(
createFile
x
stdFileMode
)
>>=
either
(
\
err
->
errMsg
(
"Can't redirect output to "
++
x
)
>>
closeChannel
stdInput
>>
fail
With
(
U
serError
"redirect"
))
do
errMsg
(
"Can't redirect output to "
++
x
)
fdClose
stdInput
fail
(
u
serError
"redirect"
))
(
\
succ
->
return
()
))
{-
...
...
@@ -181,7 +184,7 @@ parseCommand = getTokens []
accumQuote
::
Char
->
[
Char
]
->
String
->
IO
(
String
,
String
)
accumQuote
q
cs
""
=
errMsg
(
"Unmatched "
++
[
q
])
>>
fail
With
(
U
serError
"unmatched quote"
)
fail
(
u
serError
"unmatched quote"
)
accumQuote
q
cs
(
c
:
s
)
|
c
==
q
=
accumToken
cs
s
|
otherwise
=
accumQuote
q
(
c
:
cs
)
s
...
...
@@ -202,7 +205,7 @@ parseRedirection = redirect Nothing Nothing []
redirect
inFile
outFile
args
[
arg
]
|
arg
==
"<"
||
arg
==
">"
=
errMsg
"Missing name for redirect"
>>
fail
With
(
U
serError
"parse redirect"
)
fail
(
u
serError
"parse redirect"
)
|
otherwise
=
return
(
inFile
,
outFile
,
reverse
(
arg
:
args
))
redirect
inFile
outFile
args
(
"<"
:
name
:
more
)
...
...
@@ -210,13 +213,13 @@ parseRedirection = redirect Nothing Nothing []
redirect
(
Just
name
)
outFile
args
more
|
otherwise
=
errMsg
"Ambiguous input redirect"
>>
fail
With
(
U
serError
"parse redirect"
)
fail
(
u
serError
"parse redirect"
)
redirect
inFile
outFile
args
(
">"
:
name
:
more
)
|
outFile
==
Nothing
=
redirect
inFile
(
Just
name
)
args
more
|
otherwise
=
errMsg
"Ambiguous output redirect"
>>
fail
With
(
U
serError
"parse redirect"
)
fail
(
u
serError
"parse redirect"
)
redirect
inFile
outFile
args
(
arg
:
more
)
=
redirect
inFile
outFile
(
arg
:
args
)
more
...
...
@@ -231,20 +234,22 @@ exec cmd args =
forkProcess
>>=
\
maybe_pid
->
case
maybe_pid
of
Nothing
->
dupChannelTo
myStderr
stdError
>>
closeChannel
myStdin
>>
closeChannel
myStdout
>>
closeChannel
myStderr
>>
executeFile
cmd
True
args
Nothing
`
handle
`
\
err
->
writeChannel
stdError
(
"command not found: "
++
cmd
++
".
\n
"
)
>>
exitImmediately
(
ExitFailure
1
)
do
dupTo
myStderr
stdError
fdClose
myStdin
fdClose
myStdout
fdClose
myStderr
executeFile
cmd
True
args
Nothing
`
catch
`
(
\
err
->
fdWrite
stdError
(
"command not found: "
++
cmd
++
".
\n
"
)
>>
exitImmediately
(
ExitFailure
1
))
Just
pid
->
closeChannel
stdInput
>>
closeChannel
stdOutput
>>
-- closeChannel stdError >>
getProcessStatus
True
False
pid
>>
do
fdClose
stdInput
fdClose
stdOutput
-- fdClose stdError
getProcessStatus
True
False
pid
return
()
{-
...
...
@@ -257,21 +262,20 @@ exec cmd args =
-}
builtin
::
String
->
Maybe
([
String
]
->
IO
()
)
builtin
"cd"
=
Just
chdir
builtin
"cd"
=
Just
chdir
builtin
"exit"
=
Just
exit
builtin
_
=
Nothing
builtin
_
=
Nothing
chdir
::
[
String
]
->
IO
()
chdir
[]
=
getEnvVar
"HOME"
>>=
\
home
->
changeWorkingDirectory
home
`
handle
`
\
err
->
errMsg
"cd: can't go home"
do
home
<-
getEnv
"HOME"
setCurrentDirectory
home
`
catch
`
\
err
->
errMsg
"cd: can't go home"
chdir
[
dir
]
=
changeWorkingDirectory
dir
`
handle
`
\
err
->
errMsg
(
"cd: can't chdir to "
++
dir
)
chdir
_
=
errMsg
"cd: too many arguments"
do
setCurrentDirectory
dir
`
catch
`
\
err
->
errMsg
(
"cd: can't chdir to "
++
dir
)
chdir
_
=
errMsg
"cd: too many arguments"
exit
::
[
String
]
->
IO
()
exit
_
=
exitWith
ExitSuccess
...
...
@@ -280,5 +284,5 @@ exit _ = exitWith ExitSuccess
errMsg
::
String
->
IO
()
errMsg
msg
=
w
rite
Channel
myStderr
(
"hsh: "
++
msg
++
".
\n
"
)
>>
fdW
rite
myStderr
(
"hsh: "
++
msg
++
".
\n
"
)
>>
return
()
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment