| 1 | #!/usr/local/bin/runghc |
|---|
| 2 | -- id:nobsun さんありがとうございます |
|---|
| 3 | |
|---|
| 4 | module Main where |
|---|
| 5 | |
|---|
| 6 | import System.FilePath |
|---|
| 7 | import System.Directory |
|---|
| 8 | import System.Time |
|---|
| 9 | import System.Locale (defaultTimeLocale) |
|---|
| 10 | |
|---|
| 11 | import Data.List |
|---|
| 12 | import Data.Maybe |
|---|
| 13 | import Data.Char |
|---|
| 14 | import Data.Eq |
|---|
| 15 | |
|---|
| 16 | import Network.CGI |
|---|
| 17 | |
|---|
| 18 | import Text.Regex |
|---|
| 19 | |
|---|
| 20 | |
|---|
| 21 | -- ref. http://i.loveruby.net/ja/stdhaskell/samples/lazylines/Template.hs.html |
|---|
| 22 | fillFlavour :: String -> String -> [(String, String)] -> IO String |
|---|
| 23 | fillFlavour flavour place params = return . fill =<< (readFile $ place ++ "." ++ flavour) |
|---|
| 24 | where |
|---|
| 25 | fill "" = "" |
|---|
| 26 | fill tmpl = case break (== '$') tmpl of |
|---|
| 27 | (s, ('$':cs)) -> s ++ expand var ++ fill cont |
|---|
| 28 | where (var, cont) = span isAlpha cs |
|---|
| 29 | (s, cont) -> s ++ fill cont |
|---|
| 30 | |
|---|
| 31 | expand var = fromMaybe ('$':var) (lookup var params) |
|---|
| 32 | |
|---|
| 33 | |
|---|
| 34 | data Entry = Entry { |
|---|
| 35 | file :: FilePath, |
|---|
| 36 | path :: String, |
|---|
| 37 | title :: String, |
|---|
| 38 | time :: ClockTime, |
|---|
| 39 | body :: [String] |
|---|
| 40 | } |
|---|
| 41 | |
|---|
| 42 | |
|---|
| 43 | getFileEntry :: String -> FilePath -> IO Entry |
|---|
| 44 | getFileEntry d f = do |
|---|
| 45 | { |
|---|
| 46 | ; mtime <- getModificationTime f |
|---|
| 47 | ; cs <- readFile f |
|---|
| 48 | ; case lines cs of |
|---|
| 49 | h:tl -> return $ Entry { file = f |
|---|
| 50 | , path = dropExtension $ drop (length d) f |
|---|
| 51 | , title = h |
|---|
| 52 | , time = mtime |
|---|
| 53 | , body = tl |
|---|
| 54 | } |
|---|
| 55 | } |
|---|
| 56 | |
|---|
| 57 | -- http://www.tom.sfc.keio.ac.jp/~sakai/2ch/1162902266.html |
|---|
| 58 | getRecursiveContents :: FilePath -> IO [FilePath] |
|---|
| 59 | getRecursiveContents fp = getDirectoryContents fp >>= mapM (fx fp) >>= return . concat |
|---|
| 60 | where |
|---|
| 61 | fx :: FilePath -> FilePath -> IO [FilePath] |
|---|
| 62 | fx bp "." = return [bp] |
|---|
| 63 | fx bp ".." = return [] |
|---|
| 64 | fx bp f = do let np = bp ++ ('/':f) |
|---|
| 65 | b <- doesDirectoryExist np |
|---|
| 66 | if b then getRecursiveContents np |
|---|
| 67 | else return [np] |
|---|
| 68 | |
|---|
| 69 | |
|---|
| 70 | |
|---|
| 71 | getTextFileEntries :: FilePath -> IO [Entry] |
|---|
| 72 | getTextFileEntries d = do |
|---|
| 73 | { |
|---|
| 74 | ; fs <- getRecursiveContents d |
|---|
| 75 | ; es <- mapM (getFileEntry d) $ filter (isSuffixOf ".txt") fs |
|---|
| 76 | ; return es |
|---|
| 77 | } |
|---|
| 78 | |
|---|
| 79 | |
|---|
| 80 | getResult :: [(String, String)] -> IO (String, String) |
|---|
| 81 | getResult cgiparams = do |
|---|
| 82 | { |
|---|
| 83 | ; entries <- getTextFileEntries "data" |
|---|
| 84 | ; ct <- fill "content_type" [] |
|---|
| 85 | ; ch <- fill "head" [] |
|---|
| 86 | ; cs <- mapM |
|---|
| 87 | (\e -> fill "story" |
|---|
| 88 | [("title", title e), |
|---|
| 89 | ("body", concat (body e)), |
|---|
| 90 | ("time", formatCalendarTime defaultTimeLocale "%Y-%m-%d %H:%M:%S" (toUTCTime (time e))), |
|---|
| 91 | ("path", path e)]) |
|---|
| 92 | $ take 7 $ reverse $ sortBy (\a b -> compare (time a) (time b)) entries |
|---|
| 93 | ; cf <- fill "foot" [] |
|---|
| 94 | ; return $ (ct, concat $ [ch, concat cs, cf]) |
|---|
| 95 | } where |
|---|
| 96 | fill place params = fillFlavour "html" place (params ++ [("title", "Blosxkel.hs"), |
|---|
| 97 | ("version", "aaa")] ++ cgiparams) |
|---|
| 98 | |
|---|
| 99 | cgiMain :: CGI CGIResult |
|---|
| 100 | cgiMain = do |
|---|
| 101 | { |
|---|
| 102 | ; home <- scriptName |
|---|
| 103 | ; pathinfo <- pathInfo |
|---|
| 104 | ; result <- liftIO $ getResult [("home", home), ("pathinfo", pathinfo)] |
|---|
| 105 | ; setHeader "Content-Type" $ fst result |
|---|
| 106 | ; output $ snd result |
|---|
| 107 | } |
|---|
| 108 | |
|---|
| 109 | main :: IO () |
|---|
| 110 | main = runCGI $ handleErrors cgiMain |
|---|
| 111 | |
|---|