Getting Started with Flags in Command-Line Arguments
In this example, we’ll explore flags —a special type of command-line argument. Flags are position-independent and don’t require a value. At first, this might seem a little strange, but not all arguments need to have an associated value. Sometimes, simply including the flag in the command is enough to change how the program behaves.
A great example of this is the cowsay command in Linux, which is actually a fun little easter egg! We’ll be implementing a simplified version of it to see flags in action.
What Should Our cowsay Command Do?
The cowsay
command is quite flexible. Here’s how it works:
- If no arguments are provided, it simply prints a cow saying booo.
- If the user provides a text argument, the cow will say that instead.
- Additionally, we can change the eyes of the cow using flags:
--tired
or -t
→ gives the cow tired eyes.
--wink
or -w
→ makes the cow wink.
--greedy
or -g
→ gives the cow money-shaped eyes.
Implementing the Argument Handling
We won’t dive into the graphics rendering here—you can check the full implementation below. Instead, let’s focus on how we handle command-line arguments using flag detection.
First, we define our arguments:
Argument text(args, 0);
Argument tired_flag(args, 't', "tired");
Argument wink_flag(args, 'w', "wink");
Argument greedy_flag(args, 'g', "greedy");
For flags, the only thing that matters is **whether they are present or not**—we don’t parse values for them, we just check if they exist. That’s why we use the find()
method:
tired_flag.find();
wink_flag.find();
greedy_flag.find();
When we need to determine which flag was provided, we use the isFound()
method. Since multiple flags can be given at once, we should establish a priority order to avoid unpredictable behavior. In our case, the priority (from highest to lowest) is:
- Tired (
-t
)
- Wink (
-w
)
- Greedy (
-g
)
- Default (normal eyes, if no flag is given)
Now, let’s apply this logic in our implementation:
if (tired_flag.isFound()) {
caller->print(tired_eyes);
}
else if (wink_flag.isFound()) {
caller->print(wink_eyes);
}
else if (greedy_flag.isFound()) {
caller->print(greedy_eyes);
}
else {
caller->print(default_eyes);
}
Flags are a simple yet powerful way to modify a program’s behavior without requiring additional values. In this example, we used them to change our cow’s eye expression dynamically.
Live Demo
Here are a few suggested commands you might want to try in the demo above:
cowsay "hello bello" --tired
→ Displays "hello bello" with tired eyes.
cowsay --tired --wink
→ Shows the default text with tired eyes (not winking), since the tired
flag has higher priority.
cowsay --wink --tired
→ Same as the previous one, proving that flag order doesn’t matter.
cowsay -g
→ Displays the cow with money-shaped eyes.
cowsay 10
→ The text will be "10" because the first argument is treated as a string, not a number.
cowsay 10.5
→ Same as above, but with a decimal number.
cowsay
→ Runs with the default behavior.
Whole Code
#include "Commander-API.hpp"
#include "Commander-Arguments.hpp"
const char* cow_top = " \\ ^__^\r\n \\ ";
const char* cow_bottom = "\\_______\r\n (__)\\ )\\/\\\r\n ||----w |\r\n || ||\r\n";
const char* default_eyes = "(oo)";
const char* tired_eyes = "(--)";
const char* wink_eyes = "(-O)";
const char* greedy_eyes = "($$)";
Commander commander;
bool cowsay_func( char *args, CommandCaller* caller );
Commander::systemCommand_t API_tree[] = {
systemCommand( "cowsay", "Like the Linux command. Just give it a string.\r\n\tflags: --greedy\r\n\t --tired", cowsay_func )
};
void setup(){
Serial.begin(115200);
shell.clear();
commander.attachDebugChannel( &Serial );
commander.attachTree( API_tree );
commander.init();
shell.attachCommander( &commander );
shell.begin( "arnold" );
}
void loop(){
shell.update();
}
bool cowsay_func(char *args, CommandCaller* caller ){
char textBuffer[ 30 ];
int i;
Argument text( args, 0 );
Argument tired_flag( args, 't', "tired" );
Argument wink_flag( args, 'w', "wink" );
Argument greedy_flag( args, 'g', "greedy" );
tired_flag.find();
wink_flag.find();
greedy_flag.find();
caller -> print( "< " );
if( text.parseString( textBuffer ) ){
caller -> print( textBuffer );
caller -> println( " >" );
caller -> print( ' ' );
for( i = strlen( textBuffer ) + 2; i > 0 ; i-- ){
caller -> print( '-' );
}
}
else{
caller -> print( "booo >\r\n ------" );
}
caller -> println();
caller -> print( cow_top );
if( tired_flag.isFound() ){
caller -> print( tired_eyes );
}
else if( wink_flag.isFound() ){
caller -> print( wink_eyes );
}
else if( greedy_flag.isFound() ){
caller -> print( greedy_eyes );
}
else{
caller -> print( default_eyes );
}
caller -> print( cow_bottom );
return true;
}