MASAさんライブ@西元町

mixiの「ウクレレサークル関西」(名前が「関西ウクレレサークル」と似ててまぎらわしいです)の方々が来ていました。遠路はるばるお疲れ様です。
このお店、初めてでした。神戸に住んでいながら普段この辺には来ないので。ロコモコはあまりおいしくなかったけど、いい雰囲気のお店でした。
MASAさん、このお店でウクレレレッスンも始めようとしているみたい。正式にウクレレレッスンの日が決ったら一回行ってみようかな。グループレッスン楽しそうだし…

dfコマンドを作ってみました

http://valkyrja.ddo.jp/~raito/hiki/?2006-10-10#Windows%CD%D1df%A5%B3%A5%DE%A5%F3%A5%C9を読んで、Haskellでdfコマンドを作成してみました。ラッキーなことに必要なWin32APIはGHCに標準で入っていました。単位はメガバイトで出力するようにしました(端数は切り捨て)。桁が大きくなると見にくいので、3桁ずつカンマで区切るようにしました。
ファイル: df.hs

module Main (main) where

import Control.Monad (filterM)
import Data.Bits (testBit)
import System.Win32.File (getLogicalDrives, getDiskFreeSpace)
import System.Win32.Types (DWORD)
import Text.Printf (printf)

getLogicalDriveStrs :: IO [String]
getLogicalDriveStrs = do
  drives <- getLogicalDrives 
  filterM (return . not . null) $ zipWith (f drives) [0 .. 25] driveStrs
  where
    driveStrs = map (: ":\\") ['A' .. 'Z']

    f drives i s
      | testBit drives i = s
      | otherwise        = ""

getDiskFreeSpacesNoErr :: [String] -> IO [(String, (DWORD, DWORD, DWORD, DWORD))]
getDiskFreeSpacesNoErr ds = filterErr =<< mapM (catchErr . getDiskFreeSpace') ds
  where
    getDiskFreeSpace' d = do 
      dfs <- getDiskFreeSpace $ Just d
      return (d, dfs)

    catchErr f = catch f (\ e -> return ("", (0, 0, 0, 0)))
    filterErr  = filterM (return . (/= ("", (0, 0, 0, 0))))

format :: (String, (DWORD, DWORD, DWORD, DWORD)) -> String
format (d, ds) = 
  let free    = toMega $ freeSpaceBytes ds 
      total   = toMega $ totalSpaceBytes ds
      used    = toMega $ (totalSpaceBytes ds - freeSpaceBytes ds)
      percent = (totalSpaceBytes ds - freeSpaceBytes ds) * 100
                  `div` totalSpaceBytes ds
  in printf "%-12s %12s %12s %12s %4d%%"
       d (comma total) (comma used) (comma free) percent
  where
    freeSpaceBytes (sectPerClust, bytesPerSect, nFreeClust, nTotalClust) =
      (toInteger nFreeClust) * (toInteger (sectPerClust * bytesPerSect))
    
    totalSpaceBytes (sectPerClust, bytesPerSect, nFreeClust, nTotalClust) =
      (toInteger nTotalClust) * (toInteger (sectPerClust * bytesPerSect))

    toMega n = n `div` (1024 * 1024)

    comma n = tail . reverse $ f $ reverse $ show n
      where
        f [] = ""
        f s = let (s1, s2) = splitAt 3 s
              in s1 ++ "," ++ f s2

main :: IO ()
main = do
  printf "%-12s %12s %12s %12s %4s\n"
    "Filesystem" "Total" "Used" "Available" "Used%"
  mapM_ putStrLn . map format =<< getDiskFreeSpacesNoErr =<< getLogicalDriveStrs

実行例:

$ ./df.exe
Filesystem          Total         Used    Available Used%
C:\                20,475       15,256        5,219   74%
E:\                21,426       16,326        5,099   76%
F:\                 5,076        4,592          484   90%