ラベル Go言語 の投稿を表示しています。 すべての投稿を表示
ラベル Go言語 の投稿を表示しています。 すべての投稿を表示

2011年3月13日日曜日

Go言語でbase64デコード処理

Go言語の練習その3として、base64デコード処理を書いてみました。と言っても、添付ライブラリを使っているだけですが。
// my_b64decode.go

package main

import (
        "fmt"
        "os"
        "bufio"
        "regexp"
        "encoding/base64"
)

func err_exit(err os.Error) {
        fmt.Fprintf(os.Stderr,"ERROR: %s\n", err.String())
        os.Exit(1)
}

func my_chop(s string) string {
        return s[0:len(s)-1]
}

func main() {
        if len(os.Args) <= 1 {
                fmt.Fprintf(os.Stderr, "Usage: my_b64decode file\n")
                os.Exit(1)
        }

        f,err := os.Open(os.Args[1], os.O_RDONLY, 0666)
        if err != nil { err_exit(err) }

        b_rd := bufio.NewReader(f)

        dst := make([]byte, 100, 200)

        b_wr,err := bufio.NewWriterSize(os.Stdout, 4096)
        if err != nil { err_exit(err) }

        INPUT: for {
                line,err := b_rd.ReadString('\n')
                if err != nil {
                        if err == os.EOF {
                                break
                        }
                        err_exit(err)
                }

                m,err := regexp.MatchString("^begin-base64 ", line)
                if ! m { continue }

                for {
                        line,err := b_rd.ReadString('\n')
                        if err != nil {
                                if err == os.EOF {
                                        break INPUT
                                }
                                err_exit(err)
                        }
                        m,err := regexp.MatchString("^====\n", line)
                        if m {
                                break INPUT
                        }
                        src := []byte(my_chop(line))
                        n,err := base64.StdEncoding.Decode(dst, src)
                        b_wr.Write(dst[0:n])
                }
        }

        b_wr.Flush()
        f.Close()
        return
}
uuencode -m で作成された base64 エンコードファイルを読み込み、デコードして標準出力へ出力します。動作確認結果を示します。
[user00@fedora14 ~]$ ls -l /etc/services 
-rw-r--r--. 1 root root 651949 Nov 12 20:56 /etc/services
[user00@fedora14 ~]$ uuencode -m /etc/services a.uu > a.uu
[user00@fedora14 ~]$ ls -l a.uu
-rw-rw-r-- 1 user00 user00 883783 Mar 13 22:56 a.uu    ※テストファイルを用意
[user00@fedora14 ~]$ head -2 a.uu
begin-base64 644 a.uu
IyAvZXRjL3NlcnZpY2VzOgojICRJZDogc2VydmljZXMsdiAxLjUxIDIwMTAv

[user00@fedora14 ~]$ 6g my_b64decode.go 
[user00@fedora14 ~]$ 6l -o my_b64decode my_b64decode.6

[user00@fedora14 ~]$ ./my_b64decode a.uu | md5sum
77a7f18fe1508eec6c0f2b5e15b8804e  -
[user00@fedora14 ~]$ md5sum /etc/services 
77a7f18fe1508eec6c0f2b5e15b8804e  /etc/services     ※元ファイルと等しい
[user00@fedora14 ~]$ uudecode -o - < a.uu | md5sum 
77a7f18fe1508eec6c0f2b5e15b8804e  -                 ※いちおうの確認
この練習では、次の3点についても学びました。
・正規表現ライブラリ
・chop() は無いらしい
・二重ループ脱出の方法(break のラベル指定)

2011年3月11日金曜日

Go言語でzcat

Go言語の練習に、zcat (gunzip -c) 相当を行う処理を書いてみました。これもGo言語らしくはない題材ですが。
// my_zcat.go

package main

import (
        "fmt"
        "os"
        "bufio"
        "compress/gzip"
)

func err_exit(err os.Error) {
        fmt.Fprintf(os.Stderr,"ERROR: %s\n", err.String())
        os.Exit(1)
}

func main() {
        if len(os.Args) <= 1 {
                fmt.Fprintf(os.Stderr, "Usage: my_zcat gzfile\n")
                os.Exit(1)
        }

        gz,err := os.Open(os.Args[1], os.O_RDONLY, 0666)
        // err != nil && err_exit(err)
        if err != nil { err_exit(err) }

        b_rd,err := bufio.NewReaderSize(gz, 32768)
        if err != nil { err_exit(err) }

        gz_rd,err := gzip.NewReader(b_rd)
        if err != nil { err_exit(err) }

        buf := make([]byte, 32768, 65536)

        // b_wr,err := bufio.NewWriterSize(os.Stdout, 32768)
        // if err != nil { err_exit(err) }

        for {
                n,err := gz_rd.Read(buf)
                if err != nil {
                        if err == os.EOF {
                                break
                        }
                        err_exit(err)
                }
                os.Stdout.Write(buf[0:n])
                // b_wr.Write(buf[0:n])
        }

        gz_rd.Close()
        gz.Close()
        return
}
makeの第3引数で指定するキャパシティの意味するところが、理解出来ていません。

それから、
err != nill && err_exit(err)
のようには書けませんでした。コンパイルエラーになります。
[user00@fedora14 ~]$ 6g my_zcat.go 
my_zcat.go:24: err_exit(err) used as value

2011-04-02追記
実行イメージを書いていなかったので、追記です。
[user00@fedora14 ~]$ 6g my_zcat.go 
[user00@fedora14 ~]$ 6l -o my_zcat my_zcat.6
[user00@fedora14 ~]$ ls -l my_zcat
-rwxrwxr-x 1 user00 user00 2143092 Apr  2 21:17 my_zcat
[user00@fedora14 ~]$ echo hello | gzip -c > hello.gz
[user00@fedora14 ~]$ ./my_zcat hello.gz 
hello
[user00@fedora14 ~]$ cat /etc/services | gzip -c > test_data.gz    ※少し大きいテストデータ
[user00@fedora14 ~]$ ./my_zcat test_data.gz | md5sum
77a7f18fe1508eec6c0f2b5e15b8804e  -
[user00@fedora14 ~]$ md5sum /etc/services 
77a7f18fe1508eec6c0f2b5e15b8804e  /etc/services

2011年3月9日水曜日

Go言語で行単位のI/O処理

Go言語らしくない題材だとは思いますが、練習に行単位のI/O処理を書いてみました。
// my_cat.go

package main

import (
        "fmt"
        "os"
        "bufio"
)

func main() {
        if len(os.Args) <= 1 {
                fmt.Fprintf(os.Stderr, "Usage: my_cat file\n")
                os.Exit(1)
        }

        f,err := os.Open(os.Args[1], os.O_RDONLY, 0666)
        if err != nil {
                fmt.Fprintf(os.Stderr,"ERROR: %s\n", err.String())
                os.Exit(1)
        }

        reader := bufio.NewReader(f)
        writer := bufio.NewWriter(os.Stdout)
        // writer,err := bufio.NewWriterSize(os.Stdout, 4096)

        for {
                line,err := reader.ReadString('\n')
                if err != nil {
                        break
                }
                writer.WriteString(line)
        }

        writer.Flush()

        f.Close()
        return
}
bufio.NewWriterSize で書き込みバッファサイズを指定することもできますが、わたしの環境の場合には、デフォルトで 4096 バイトぐらいのようです。次のように、少々ぶれます。
[user00@fedora14 ~]$ strace -e write ./my_cat /etc/init.d/functions >/dev/null
write(1, "# -*-Shell-script-*-\n#\n# functio"..., 4094) = 4094
write(1, "\t\t\t\taction $\"Detaching loopback "..., 4067) = 4067
write(1, "                [ \"$BOOTUP\" = \"v"..., 4092) = 4092
write(1, "# Log that something succeeded\ns"..., 4080) = 4080
write(1, "\t# Parse the options field, conv"..., 2837) = 2837

2011年3月8日火曜日

Fedora 14 に Go 言語をインストール

ふと目にとまってしまった Go 言語を、少し試してみようと、まずは、Fedora 14 x86_64 へインストールしてみました。
手順(各所に情報があるようですが)とログをメモしておきます。

まず、root で必要なものをインストールします。特に、Mercurial を。
[root@fedora14 ~]# cat /etc/redhat-release 
Fedora release 14 (Laughlin)
[root@fedora14 ~]# uname -a
Linux fedora14 2.6.35.10-74.fc14.x86_64 #1 SMP Thu Dec 23 16:04:50 UTC 2010 x86_64 x86_64 x86_64 GNU/Linux

[root@fedora14 ~]# yum install '*mercurial*'
途中省略

[root@fedora14 ~]# rpm -q bison gcc libc6-dev ed gawk make  ※必要なものを確認
bison-2.4.3-1.fc14.x86_64
gcc-4.5.1-4.fc14.x86_64
package libc6-dev is not installed  ※これは、既に名前が変わったのか、不要でした
ed-1.4-2.fc14.x86_64
gawk-3.1.8-3.fc14.x86_64
make-3.82-3.fc14.x86_64
次に一般ユーザでの作業です。
[user00@fedora14 ~]$ cat .bashrc  ※環境変数を設定します
# .bashrc

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

# User specific aliases and functions

export GOROOT=$HOME/go  ※この4行をvi等で追加
export GOOS=linux
export GOARCH=amd64
export GOBIN=$HOME/bin

[user00@fedora14 ~]$ source .bashrc
[user00@fedora14 ~]$ mkdir $GOROOT
[user00@fedora14 ~]$ mkdir $GOBIN

※次の Mercurial のコマンド hg で、リポジトリからソースその他一式をゲット
[user00@fedora14 ~]$ hg clone -r release https://go.googlecode.com/hg/ $GOROOT
warning: go.googlecode.com certificate with fingerprint b1:af:83:76:f3:81:b0:57:70:d8:07:42:c8:c1:b3:67:38:c8:7a:bc not verified (check hostfingerprints or web.cacerts config setting)
adding changesets
adding manifests
adding file changes
added 7570 changesets with 29247 changes to 4124 files
updating to branch default
2508 files updated, 0 files merged, 0 files removed, 0 files unresolved

※ビルドを実行
[user00@fedora14 ~]$ cd $GOROOT/src
[user00@fedora14 src]$ ./all.bash 
rm -f *.o y.tab.[ch] y.output a.out lib9.a
rm -f *.o y.tab.[ch] y.output a.out libbio.a
rm -f *.o y.tab.[ch] y.output a.out libmach.a
rm -f *.o y.tab.[ch] y.output a.out cc.a
途中省略

--- cd ../test
1 known bugs; 0 unexpected bugs  ※ちょっと気になりますが…後述の helloworld.go は動きました。

ALL TESTS PASSED

---
Installed Go for linux/amd64 in /home/user00/go.
Installed commands in /home/user00/bin.
The compiler is 6g.
[user00@fedora14 src]$ 
お試しに helloworld.go です。
package main

import "fmt"

func main() {
        fmt.Printf("hello, world\n")
        return
}
これを、6g および 6l にかけると、6.out という実行モジュールが生成されます。
[user00@fedora14 ~]$ 6g helloworld.go    ※コンパイル
[user00@fedora14 ~]$ ls -l helloworld.6
-rw-rw-r-- 1 user00 user00 5750 Mar  8 22:52 helloworld.6
[user00@fedora14 ~]$ 6l helloworld.6     ※リンク
[user00@fedora14 ~]$ ls -l 6.out 
-rwxrwxr-x 1 user00 user00 1842238 Mar  8 22:53 6.out
[user00@fedora14 ~]$ ./6.out    ※実行
hello, world
コマンド先頭が数字というのは、結構、違和感があります。bash の history もうまく動かないです。!6g などとやると、history の 6番目 のコマンドが呼び出されてしまいます。
人気ブログランキングへ にほんブログ村 IT技術ブログへ