Skip to content

Commit

Permalink
Add nl command and -n option for cat command.
Browse files Browse the repository at this point in the history
Changed cat/tac command to receive data from standard input when the argument is "-".
  • Loading branch information
nao1215 committed Nov 20, 2021
1 parent 89f8b05 commit 17f4ddf
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 35 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
# Changelog
All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.11.0] - 2021-11-20
## [0.12.1] - 2021-11-20
### Added
- base64 command.
- cp command.
- nl command.
- -n option for cat command
### Changed
- Reduce mimixbox binary size by compile option (7.5MB --> 5.4MB)
- cat/tac command to receive data from standard input when the argument is "-".
## [0.9.1] - 2021-11-19
### Added
- basename command.
Expand Down
2 changes: 1 addition & 1 deletion cmd/mimixbox/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ type options struct {

var osExit = os.Exit

const version = "0.11.0"
const version = "0.12.1"

const (
ExitSuccess int = iota // 0
Expand Down
1 change: 1 addition & 0 deletions docs/introduction/en/CommandAppletList.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
| mkdir | Make directories|
| mkfifo | Make FIFO (Named pipe)|
| mv | Rename SOURCE to DESTINATION, or move SOURCE(s) to DIRECTORY|
| nl| Write each FILE to standard output with line numbers added|
| path | Manipulate filename path|
| rm | Remove file(s) or directory(s)|
| rmdir | Remove directory|
Expand Down
2 changes: 2 additions & 0 deletions internal/applets/applet.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import (
"mimixbox/internal/applets/shellutils/true"
"mimixbox/internal/applets/shellutils/which"
"mimixbox/internal/applets/textutils/cat"
"mimixbox/internal/applets/textutils/nl"
"mimixbox/internal/applets/textutils/tac"
"os"
"sort"
Expand Down Expand Up @@ -72,6 +73,7 @@ func init() {
"mkdir": {mkdir.Run, "Make directories"},
"mkfifo": {mkfifo.Run, "Make FIFO (named pipe)"},
"mv": {mv.Run, "Rename SOURCE to DESTINATION, or move SOURCE(s) to DIRECTORY"},
"nl": {nl.Run, "Write each FILE to standard output with line numbers added"},
"path": {path.Run, "Manipulate filename path"},
"rm": {rm.Run, "Remove file(s) or directory(s)"},
"rmdir": {rmdir.Run, "Remove directory"},
Expand Down
37 changes: 14 additions & 23 deletions internal/applets/textutils/cat/cat.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package cat

import (
"fmt"
"io"
mb "mimixbox/internal/lib"
"os"

Expand All @@ -27,7 +26,7 @@ import (

const cmdName string = "cat"

const version = "1.0.2"
const version = "1.0.3"

var osExit = os.Exit

Expand All @@ -38,6 +37,7 @@ const (
)

type options struct {
Number bool `short:"n" long:"number" description:"Print with line number"`
Version bool `short:"v" long:"version" description:"Show cat command version"`
}

Expand All @@ -50,34 +50,25 @@ func Run() (int, error) {
return ExitFailuer, nil
}

if len(args) == 0 {
for {
if !mb.Parrot() {
break
}
}
if len(args) == 0 || mb.Contains(args, "-") {
mb.Parrot(opts.Number)
return ExitSuccess, nil
}

for _, file := range args {
err := cat(file)
if err != nil {
return ExitFailuer, err
}
strLisr, err := mb.Concatenate(args, false)
if err != nil {
return ExitFailuer, nil
}

return ExitSuccess, nil
}

func cat(path string) error {
f, err := os.Open(path)
if err != nil {
return err
if opts.Number {
mb.PrintStrListWithNumberLine(strLisr, true)
} else {
for _, str := range strLisr {
fmt.Print(str)
}
}
defer f.Close()

_, err = io.Copy(os.Stdout, f)
return err
return ExitSuccess, nil
}

func parseArgs(opts *options) ([]string, error) {
Expand Down
105 changes: 105 additions & 0 deletions internal/applets/textutils/nl/nl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
//
// mimixbox/internal/applets/textutils/nl/nl.go
//
// Copyright 2021 Naohiro CHIKAMATSU
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package nl

import (
"fmt"
mb "mimixbox/internal/lib"
"os"

"github.com/jessevdk/go-flags"
)

const cmdName string = "nl"

const version = "1.0.0"

var osExit = os.Exit

// Exit code
const (
ExitSuccess int = iota // 0
ExitFailuer
)

type options struct {
Version bool `short:"v" long:"version" description:"Show nl command version"`
}

func Run() (int, error) {
var opts options
var args []string
var err error

if args, err = parseArgs(&opts); err != nil {
return ExitFailuer, nil
}

if len(args) == 0 || mb.Contains(args, "-") {
var nr int = 1
for {
input, next := mb.Input()
if !next {
break
}
if input != "" {
mb.PrintStrWithNumberLine(nr, input+"\n")
nr++
} else {
fmt.Println("")
}
}
return ExitSuccess, nil
}

str, err := mb.Concatenate(args, true)
if err != nil {
return ExitFailuer, nil
}
mb.PrintStrListWithNumberLine(str, false)

return ExitSuccess, nil
}

func parseArgs(opts *options) ([]string, error) {
p := initParser(opts)

args, err := p.Parse()
if err != nil {
return nil, err
}

if opts.Version {
showVersion()
osExit(ExitSuccess)
}

return args, nil
}

func initParser(opts *options) *flags.Parser {
parser := flags.NewParser(opts, flags.Default)
parser.Name = cmdName
parser.Usage = "[OPTIONS] FILE_PATH"

return parser
}

func showVersion() {
description := cmdName + " version " + version + " (under Apache License verison 2.0)\n"
fmt.Print(description)
}
4 changes: 2 additions & 2 deletions internal/applets/textutils/tac/tac.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (

const cmdName string = "tac"

const version = "1.0.1"
const version = "1.0.2"

var osExit = os.Exit

Expand All @@ -50,7 +50,7 @@ func Run() (int, error) {
return ExitFailuer, nil
}

if len(args) == 0 {
if len(args) == 0 || mb.Contains(args, "-") {
tacUserInput()
return ExitSuccess, nil
}
Expand Down
19 changes: 19 additions & 0 deletions internal/lib/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package mb

import (
"bufio"
"io"
"io/fs"
"os"
Expand Down Expand Up @@ -155,3 +156,21 @@ func Copy(src string, dest string) error {
}
return nil
}

func ReadFileToStrList(path string) ([]string, error) {
var strList []string

f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()

scanner := bufio.NewScanner(f)
for scanner.Scan() {
strList = append(strList, scanner.Text()+"\n")
}

strList[len(strList)-1] = strings.TrimRight(strList[len(strList)-1], "\n")
return strList, nil
}
67 changes: 59 additions & 8 deletions internal/lib/shell.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,22 @@ func Question(ask string) bool {
}
}

func Parrot() bool {
func Parrot(withNl bool) {
var response string

_, err := fmt.Scanln(&response)
if err != nil {
if !strings.Contains(err.Error(), "expected newline") {
return false // Ctrl+D or other error.
var nl int = 1
for {
_, err := fmt.Scanln(&response)
if err != nil {
if !strings.Contains(err.Error(), "expected newline") {
break // Ctrl+D or other error.
}
}
if withNl {
PrintStrWithNumberLine(nl, response)
} else {
fmt.Println(response)
}
}
fmt.Println(response)
return true
}

func Input() (string, bool) {
Expand Down Expand Up @@ -106,3 +111,49 @@ func WrapString(src string, column int) string {
}
return strings.Join(buf, "\n")
}

func Concatenate(path []string, lfAtTheJoint bool) ([]string, error) {
var strList []string
var index int

for _, file := range path {
list, err := ReadFileToStrList(file)
if err != nil {
return nil, err
}

// In the case of the cat command, the beginning of the new file is
// concatenated to the end of the previous file.
// In the case of nl command, do not concatenate the new file at the end
// of the previous file. The end of file (EOF) is replaced with a newline.
index = len(strList) - 1
if lfAtTheJoint { // for nl command
list[len(list)-1] = list[len(list)-1] + "\n"
strList = append(strList, list...)
} else { // for cat command
if index > 0 {
strList[index] = strList[index] + list[0]
strList = append(strList, list[1:]...)
} else {
strList = append(strList, list...)
}
}
}
return strList, nil
}

func PrintStrListWithNumberLine(strList []string, countEmpryLine bool) {
var nl int = 1
for _, s := range strList {
if s == "\n" && !countEmpryLine {
fmt.Print(s)
continue
}
PrintStrWithNumberLine(nl, s)
nl++
}
}

func PrintStrWithNumberLine(nl int, str string) {
fmt.Printf("%6d %s", nl, str)
}

0 comments on commit 17f4ddf

Please sign in to comment.