文章目錄
1、Selpg的介紹
selpg 允許用戶指定從輸入文本抽取的頁的範圍,這些輸入文本可以來自文件/標準輸入/另一個進程。
2、具體要求
實現指令的要求請查看該鏈接
3、實現具體思路
查看selpg 的 C 代碼,在此基礎上實現。
3.1引入的包
import (
"bufio"
"flag"
"fmt"
"io"
"os"
"os/exec"
)
os,flag包,簡單處理參數;bufio處理緩存
3.2相關結構體
按照C語言設置對應結構體和全局變量:
type selpgargs struct {
start_page int //開始的頁編號
end_page int //結束的頁編號
in_filename string
print_dest string
page_len int /* default value, can be overriden by "-l number" on command line */
page_type bool /* 'l' for lines-delimited, 'f' for form-feed-delimited */
}
var progname string /* program name, for error messages */
3.3主函數處理流程
初始化參數結構體-處理參數-根據參數進行處理
func main() {
progname = os.Args[0] /* save name by which program is invoked, for error messages */
var args selpgargs
FlagInit(&args) //初始化參數標記
process_args(&args) //處理參數
process_input(&args) //根據用戶輸入的各個參數進行相應的操作
}
3.4FlagInit函數:
- 任務:進行指令結構體的標記的初始化
- 實現:參考C語言版本的實現及flag包的用法
- flag的簡單使用:
A.定義flags有兩種方式:
1)flag.Xxx(),其中Xxx可以是Int、String等;返回一個相應類型的指針,如:
var ip = flag.Int("flagname", 1234, "help message for flagname")
2)flag.XxxVar(),將flag綁定到一個變量上,如:
var flagvar int
flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname")
另外,還可以創建自定義flag,只要實現flag.Value接口即可(要求receiver是指針),這時候可以通過如下方式定義該flag:
flag.Var(&flagVal, "name", "help message for flagname
B. 解析參數(Parse):從參數列表中解析定義的flag。參數arguments不包括命令名,即應該是os.Args[1:]。
4. 代碼:
//initial flags
func FlagInit(args *selpgargs) {
flag.IntVar(&args.start_page, "s", -1, "Start page.")
flag.IntVar(&args.end_page, "e", -1, "End page.")
flag.IntVar(&args.page_len, "l", 72, "page_len.")
flag.BoolVar(&args.page_type, "f", false, "page_type")
flag.StringVar(&args.print_dest, "d", "", "print_dest")
flag.Usage = usage
flag.Parse()
}
3.5 process_args函數:
- 任務:處理參數
- 實現:參考C語言版本
- 代碼:
func process_args(args *selpgargs) {
if args == nil {
fmt.Fprintf(os.Stderr, "\n[Error]The args is nil!Please check your program!\n\n")
os.Exit(1)
}
if args.start_page == -1 || args.end_page == -1 {
fmt.Fprintf(os.Stderr, "\n[Error]:%s, not enough arguments\n\n", progname)
flag.Usage()
os.Exit(2)
}
if os.Args[1][0] != '-' || os.Args[1][1] != 's' {
fmt.Fprintf(os.Stderr, "\n[Error]:%s, 2st arg should be -sstart_page\n\n", progname)
flag.Usage()
os.Exit(3)
}
end_index := 2
if len(os.Args[1]) == 2 {
end_index = 3
}
if os.Args[end_index][0] != '-' || os.Args[end_index][1] != 'e' {
fmt.Fprintf(os.Stderr, "\n[Error]:%s, 3st arg should be -eend_page\n\n", progname)
flag.Usage()
os.Exit(4)
}
if args.start_page > args.end_page || args.start_page < 0 ||
args.end_page < 0 {
fmt.Fprintln(os.Stderr, "\n[Error]:Invalid arguments")
flag.Usage()
os.Exit(5)
}
}
3.6 process_input函數:
- 任務:進行操作
- 實現:參考C語言版本以及os/exec 庫,bufio包的用法
- 代碼:
func process_input(args *selpgargs) {
var stdin io.WriteCloser
var err error
var cmd *exec.Cmd
if args.print_dest != "" {
cmd = exec.Command("cat", "-n")
stdin, err = cmd.StdinPipe()
if err != nil {
fmt.Println(err)
}
} else {
stdin = nil
}
if flag.NArg() > 0 {
args.in_filename = flag.Arg(0)
output, err := os.Open(args.in_filename)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
reader := bufio.NewReader(output)
if args.page_type {
for pageNum := 0; pageNum <= args.end_page; pageNum++ {
line, err := reader.ReadString('\f')
if err != io.EOF && err != nil {
fmt.Println(err)
os.Exit(1)
}
if err == io.EOF {
break
}
printOrWrite(args, string(line), stdin)
}
} else {
count := 0
for {
line, _, err := reader.ReadLine()
if err != io.EOF && err != nil {
fmt.Println(err)
os.Exit(1)
}
if err == io.EOF {
break
}
if count/args.page_len >= args.start_page {
if count/args.page_len > args.end_page {
break
} else {
printOrWrite(args, string(line), stdin)
}
}
count++
}
}
} else {
scanner := bufio.NewScanner(os.Stdin)
count := 0
target := ""
for scanner.Scan() {
line := scanner.Text()
line += "\n"
if count/args.page_len >= args.start_page {
if count/args.page_len <= args.end_page {
target += line
}
}
count++
}
printOrWrite(args, string(target), stdin)
}
if args.print_dest != "" {
stdin.Close()
cmd.Stdout = os.Stdout
cmd.Run()
}
}
3.7 測試代碼
- 簡單測試:
- 重定向測試
- 輸出到2.txt:
- 錯誤提示:
- 默認行數:
- 管道輸送至命令“lp -dlp1”: