In this lesson you will learn how to:
- Add flags to a command line application
In the last lesson we added a configuration file config.json
to handle our emoji translation. We also have a file named config_noemoji.json
that translates to the original representation of the game.
We also use the maze01.txt
file for our maze representation. All those names are written directly to the source code, but dealing with these files in a hard coded way is not ideal, so we will change that.
The flag
package of the standard library is the one responsible for handling command line flags. We are going to use it to create two flags: --config-file
and --maze-file
.
At the beginning of the file, just after the imports, add the following global variables.
var (
configFile = flag.String("config-file", "config.json", "path to custom configuration file")
mazeFile = flag.String("maze-file", "maze01.txt", "path to a custom maze file")
)
The String
function of the flag
package accepts three parameters: a flag name, a default value and a description (to be exhibited when --help
is used). It returns a pointer to a string which will hold the value of the flag.
Please note that this value is only filled after calling flag.Parse
, which should be called from the main
function:
func main() {
flag.Parse()
// initialise game
initialise()
defer cleanup()
// rest of the function omitted...
}
Please note that we are calling flag.Parse()
as the very first thing in the program. We want to do that because we want the flags to be parsed before changing the console to cbreak
mode.
When the flag is parsed in case of error it calls os.Exit
, which means our cleanup
function wouldn't be called leaving the terminal without echo and still in cbreak mode, which can be quite inconvenient.
With this change, by controlling the order things are called, we are making sure we init the cbreak mode only when the flags are parsed successfully.
We've already handled the parsing, now we need to replace the hard coded values with their flag equivalents.
This is done by replacing the hard coded value with the value of the flag (please note the de-reference operator, as the flags are pointers).
In main
:
// load resources
err := loadMaze(*mazeFile)
if err != nil {
log.Println("failed to load maze:", err)
return
}
err = loadConfig(*configFile)
if err != nil {
log.Println("failed to load configuration:", err)
return
}
Now try running in the command line:
go build
./step08 --help
You should see something like:
$ ./step08 --help
Usage of ./step08:
-config-file string
path to custom configuration file (default "config.json")
-maze-file string
path to a custom maze file (default "maze01.txt")
Now try running step08
with --config-file config_noemoji.json
first, and --config-file config.json
later to see the difference. Better with emojis right?
You can also try copying maze01.txt
to a new file and editing it to experiment.
Maybe you can create your own themes now... try visiting Full Emoji List for inspiration. :)