MBed program gets stuck - c++

I have written some code with the help of Mbed framework, which is either supposed to take user input and then display sensor values or display the value after 15mins. When I try to execute this code, it is getting stuck at line 21 (display.printf("Inside loop\n");).
I am not able to understand why is it so and what is the fix for this problem so that the switch block gets executed. How to I solve this? FYI, although not important, the microcontroller I am using is STM32 bluepill (STM32F103C8T6).
#include "mbed.h"
#include "Sensor_input.h"
#include "Ticker.h"
#include "Dht11.h"
//#include "USBSerial.h"
Serial display(PA_2, PA_3, 9600);
char* a;
Dht11 DhtSensor(PA_4);
Ticker t;
Sensor_input Soil(PB_7, PB_6, 8);
float *SensorData;
void getSensorData();
int main ( void ){
uint8_t choice = 0;
display.printf("Enter 1 or 2:\n1.Greenhouse stats\n2.Return Control to System");
choice = display.putc(display.getc());
while(1){
display.printf("Inside loop\n");
wait_ms(15000);
switch(choice)
{
case 1:
display.printf("Inside case 1");
a = Soil.readTemp();
display.printf("Temperature: %f\n",DhtSensor.getCelsius());
display.printf("Humidity: %f\n",DhtSensor.getHumidity());
display.printf("Soil water content: %c\n ",*a);
break;
case 2:
/*<GreenHouse object>*/
/*Might have to proceed with timer*/
display.printf("Inside case 2");
t.attach(&getSensorData,4500);
display.printf("Temperature: %f\n",a[0]);
display.printf("Humidity: %f\n",a[1]);
display.printf("Soil water content: %c\n ",a[2]);
break;
default:
break;
}
}
}
void getSensorData(){
static float a[3];
a[0]=DhtSensor.getCelsius();
a[1]=DhtSensor.getHumidity();
a[2]=(int)Soil.readTemp();
}

Your switch statement is probably being executed, but always in the 'default' case. You can test this out by putting a print statement in the default.
When you request a char from the display, it will return the input as an ASCII-character. This means, if you enter '1' on the display, it will give you (as the ASCII table says) 0x31 (decimal 49) and not the value of 1. So you have to change your case to "case '1':" or "case 0x31:" and the equivalent for the second case.

Related

UWP C++/CX: Current system time & Stopwatch

So, I am creating a C++ UWP application that when opened, displays current date and time. In addition, I need to also find a way so that I can display the day of the week as well. For the day of the week, I am using this code:
#include <ctime>
#include <time.h>
#include <chrono>
//under Mainpage::Mainpage()
time_t timeObj = time(nullptr);
tm aTime;
localtime_s(&aTime, &timeObj);
String ^ weekofdayout;
switch (aTime.tm_wday)
{
case 1:
weekofdayout = "Monday";
break;
case 2:
weekofdayout = "Tuesday";
break;
case 3:
weekofdayout = "Wednesday";
break;
case 4:
weekofdayout = "Thursday";
break;
case 5:
weekofdayout = "Friday";
break;
default:
weekofdayout = "(NULL)";
break;
}
timetext->Text += weekofdayout;
However, whenever I run it, the textbox returns: (NULL) the default case. I don't know whats causing it.
I have taken the system time before successfully in windows forms c++ with this code:
private: System::Void timer1_Tick(System::Object^ sender, System::EventArgs^ e) {
DateTime datetime = DateTime::Now;
this->label3->Text = datetime.ToString();}
I was unable to port this over to UWP C++ because I think it uses the system namespace. Any ideas on how I would be able to recreate the same effect in c++?
For the stopwatch, I haven't found any real documentation online regarding UWP C++ stopwatch but I did find this: https://iot-developer.net/windows-iot/uwp-programming-in-c/timer-and-timing/stopwatch It isn't for C++ UWP but it is for C# UWP. I tried to make my own timer with a global function but it just freezes the program until the code is done running:
int seconds = 0;
for (int i = 0; ; i++)
{
seconds++;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
if (stopwatch == false)
{
break;
}
}
return seconds;
I'm pretty stumped, usually, I would find the answer online but due to the low documentation of UWP C++, I have no idea where to find the answer.

C++ Execute a command line and get Result.

I need some help with my situation. I want to execute a Terminal and get the Result. I have done it so far, but i want to do some other Commands after getting the Result. My Problem is, that everytime when i do a command, the console restarts, and i dont know how to write in a active prozess.
I have done it like that:
FILE *fp = popen(r.c_str(),"r");
char buf[2560];
while (fgets(buf, 2560, fp))
{
s->SendLine(buf);
}
fclose(fp);
I want to "send" another command in the same process. How can i do that?
Assuming I understood your question and comment. It sounds like you want your program to run in a loop until the user chooses to close it. You will want something like this:
bool keepProgramOpen = true;
public void main()
{
while(keepProgramOpen)
{
printf("Choose and option\n");
printf("Option 1: press 1\n");
printf("Option 2: press 2\n"); //etc
char result = getchar();
switch result
{
//code to select which option was picked
case 1:
fileFunction();
break;
case 2:
someOtherFunction();
break;
case 3:
closeProgram(); //set keepProgramOpen false in here to end program
break;
//etc
}
}
}
fileFunction()
{
FILE *fp = popen(r.c_str(),"r");
char buf[2560];
while (fgets(buf, 2560, fp))
{
s->SendLine(buf);
}
fclose(fp);
}
I think before fclose(fp) use r2 as
fputs(r2.c_str(),fp)

Undefined Reference to (error coming in main.cpp file) [duplicate]

This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 7 years ago.
When trying to compile my code in Code::Blocks I receive a bunch of Undefined reference errors. The code is below.
Header
#ifndef BLACKJACK_GAME
#define BLACKJACK_GAME
// A game of blackjack has a deck and two hands
#include "Deck.h"
#include "BlackjackHand.h"
// Different ways the game can end. The first states take precedence over
// over the latter states so check for the early ones first (like blackjack)!
// Note that a "natural 21" is when you are delt two cards totaling 21.
enum eGameState {
GAME_BLACKJACK_PUSH, // Both player and dealer have a natural 21
GAME_DEALER_BLACKJACK, // Dealer has a natural 21
GAME_PLAYER_BLACKJACK, // Player has a natural 21
GAME_DEALER_BUST, // The dealer has more than 21
GAME_PLAYER_BUST, // The player has more than 21
GAME_DEALER_WIN, // The dealer's score is higher than players
GAME_PLAYER_WIN, // The player's score is higher than dealers
GAME_PUSH // The scores are tied
};
class BlackjackGame
{
public:
BlackjackGame();
// Clear the players hands and shuffle the deck
void newGame();
// Play a single round of blackjack showing the output using
// the 'PDcurses' library (for color and card suits).
void playGameCurses();
// Display the deck on the screen (for debugging purposes)
void printDeckCurses();
// Print both players hands to the screen using 'PDCurses'
// If pShowDealerScore is true then the dealer's score is printed
// Otherwise, the dealer's score is shown as '??'
void printHandsCurses(bool pShowDealerScore = false) const;
// Determine the state of the game. Note that if you have not yet
// played a round since you constructed this object or called newGame()
// Then the state returned is not accurate.
eGameState getGameState() const;
private:
// A deck of cards for shufflying and dealing hands
Deck mDeck;
// The two hands for the player and the dealer
BlackjackHand mPlayer, mDealer;
// A helper function for prompting the player (internal use only)
char promptPlayerCurses();
// A helper function to quit the game (internal use only)
void quitGameCurses();
};
#endif
CPP
#include "BlackjackGame.h"
// The library used for our text based user interface
#include <curses.h>
// Normal text color for PDCurses (defined in main)
#define NORM_TEXT 1
// Default constructor (does nothing)
BlackjackGame::BlackjackGame() {}
/* newGame() - Clear the two hands so we are ready for a new game */
void BlackjackGame::newGame()
{
mDealer.clear();
mPlayer.clear();
}
/* playGameCurses() - Play a single round of poker with one human player and one
* dealer following standard Vegas rules. Uses PDCurses for input and output to
* the console.
*
* You must implement this method but you do not need to worry about curses. Call
* 'promptPlayerCurses() to show the hands and prompt the human player to hit, stand
* or quit. This method will return the key they pressed. You can also use
* quitGameCurses() to exit properly if the user chose to 'quit'.
*/
void BlackjackGame::playGameCurses()
{
// TODO: Shuffle the deck and deal the cards (make sure dealer's first card is hidden).
mDeck.shuffle();
mPlayer.takeCard(mDeck.dealCard());
mDealer.takeCard(mDeck.dealCard());
mDealer.hideCard();
mPlayer.takeCard(mDeck.dealCard());
mDealer.takeCard(mDeck.dealCard());
// TODO: Check for a 'natural 21' (blackjack) before playing
if ( mDealer.hasBlackjack() || mPlayer.hasBlackjack())
quitGameCurses();
// TODO: Allower human player to hit, stand and quit as needed (repeat until player is done)
int flag = 0;
while(flag!=1)
{
char input = promptPlayerCurses(); // This line is an example only, a placeholder
switch(input)
{
case 'h': mPlayer.takeCard(mDeck.dealCard());
break;
case 's': flag =1;
break;
case 'q': quitGameCurses();
break;
default: break;
}
}
// TODO: Play the 'dealer' hand according to vegas rules
mDealer.showCards();
while(vegasDealerWouldHit())
{
mDealer.takeCard(mDeck.dealCard());
}
}
/* promptPlayerCurses() - Show the hands and prompt the human player to hit, stand or quit.
* output: returns the single character entered by the player at the prompt.
* - 'h' means hit, 's' means stand
* - 'q' means you should immediatly quit (call 'quitGameCurses()')
*/
char BlackjackGame::promptPlayerCurses()
{
// Show the hands
printHandsCurses();
// Hit or stand?
attron(COLOR_PAIR(NORM_TEXT));
mvprintw(3, 0, "Hit, stand or Quit ('h', 's', 'q'): ");
refresh();
// Read and return a single character
return getch();
}
/* quitGameCurses() - End curses output and exit the program immediately */
void BlackjackGame::quitGameCurses()
{
// End curses output, then pause and exit
endwin();
system("pause");
exit(0);
}
/* printDeckCurses() - A handy function that displays the content of the game deck
* using curses.
*
* This can be handy for debugging your deck and making sure it is getting properly
* shuffled. It is presently used for the fancy opening screen.
*/
void BlackjackGame::printDeckCurses()
{
// Start at the upper left corner of the screen
move(0, 0);
// For all 52 cards
for(int i=1; i<=52; i++)
{
// Get the next card and print it
PrintableCard lCard = mDeck.dealCard();
lCard.printCurses();
// If we've output 13 cards then move down a row
if(i%13 == 0)
{
move(2*(i/13), 0);
}
else
{
// Switch back to normal text color and output ' ' characters
attron(COLOR_PAIR(NORM_TEXT));
if(lCard.getFaceValue() == VALUE_TEN) printw(" ");
else printw(" ");
}
}
}
/* printHandsCurses() - A function to display the current scores and hands for this game
* using curses.
*
* This function is used in promptPlayerCurses() to show the hands before asking them if
* they want to hit or stand. Note that it alsways clears the window before drawing.
*/
void BlackjackGame::printHandsCurses(bool pShowDealerScore) const
{
// Clear window
erase();
// Show dealer and player hands
attron(COLOR_PAIR(NORM_TEXT));
mvprintw(0, 0, "Player: %d\n", mPlayer.score());
move(1, 0); mPlayer.printCurses();
attron(COLOR_PAIR(NORM_TEXT));
if(pShowDealerScore)
{
mvprintw(0, 50, "Dealer: %d\n", mDealer.score());
}
else
{
mvprintw(0, 50, "Dealer: ??\n");
}
move(1, 50); mDealer.printCurses();
refresh();
}
/* getGameStat() - Examine the hands of both players and return the current state of
* the game using the eGameState enum.
*
* You must examine the state of the game by comparing the two hands (their scores and their
* number of cards) and return the appropriate constant from the eGameState enum. Assume
* that the game is over (i.e. the player and dealer have both either gone bust or decided
* to stand).
*/
eGameState BlackjackGame::getGameState() const
{
if(mDealer.hasBlackjack() && mPlayer.hasBlackjack())
{
return GAME_BLACKJACK_PUSH;
}
else if(mDealer.hasBlackjack())
{
return GAME_DEALER_BLACKJACK;
}
else if(mPlayer.hasBlackJack())
{
return GAME_PLAYER_BLACKJACK;
}
else if(mPlayer.score() > 21)
{
return GAME_PLAYER_BUST;
}
else if(mDealer.score() > 21)
{
return GAME_DEALER_BUST;
}
else if(mDealer.score() > mPlayer.score())
{
return GAME_DEALER_WIN;
}
else if(mDealer.score() < mPlayer.score())
{
return GAME_PLAYER_WIN;
}
else {
return GAME_PUSH;
}
}
}
Main
#include <cstdlib>
#include <iostream> // Standard input and output
#include <string>
using namespace std;
#include <curses.h>
#include "BlackjackGame.h"
// Three different types of text colors used with PDCurses
#define NORM_TEXT 1
#define WIN_TEXT 2
#define LOSE_TEXT 3
int main()
{
// Setup 'PDcurses'
initscr();
start_color();
// Define our colors text colors (foreground, background)
init_pair(NORM_TEXT, COLOR_WHITE, COLOR_BLACK);
init_pair(WIN_TEXT, COLOR_YELLOW, COLOR_BLACK);
init_pair(LOSE_TEXT, COLOR_RED, COLOR_BLACK);
// Define our card colors (these are declared in PrintableCard.h)
init_pair(BLACK_CARD, COLOR_BLACK, COLOR_WHITE);
init_pair(RED_CARD, COLOR_RED, COLOR_WHITE);
// Input from the user and a game object
char ch = '\0';
BlackjackGame myGame;
// Output a 'fancy' welcome screen
myGame.printDeckCurses();
attron(COLOR_PAIR(WIN_TEXT));
mvprintw(1, 13, "Welcome to Blackjack!");
mvprintw(5, 11, "Press any key to play ...");
refresh();
// Wait for input (the 'press any key to begin' thing)
ch = getch();
// Back to normal text to start the game
attron(COLOR_PAIR(NORM_TEXT));
do // Loop to play a new game until the user exits
{
// Restart and play a game (using curses)
myGame.newGame();
// Play a round of blackjack (most of the magic happens here!)
myGame.playGameCurses();
// Print the final status of the game
myGame.printHandsCurses(true);
// Print a game results message (use BOLD and the appropriate text color)
attron(A_BOLD);
switch(myGame.getGameState())
{
case GAME_BLACKJACK_PUSH:
attron(COLOR_PAIR(WIN_TEXT));
mvprintw(10, 25, "BLACKJACK TIE!!");
break;
case GAME_DEALER_BLACKJACK:
attron(COLOR_PAIR(LOSE_TEXT));
mvprintw(10, 25, "Dealer Blackjack. You lose.");
break;
case GAME_PLAYER_BLACKJACK:
attron(COLOR_PAIR(WIN_TEXT));
mvprintw(10, 25, "BLACKJACK! You win!");
break;
case GAME_DEALER_BUST:
attron(COLOR_PAIR(WIN_TEXT));
mvprintw(10, 25, "Dealer Bust. You Win!");
break;
case GAME_PLAYER_BUST:
attron(COLOR_PAIR(LOSE_TEXT));
mvprintw(10, 25, "BUST. You lose.");
break;
case GAME_DEALER_WIN:
attron(COLOR_PAIR(LOSE_TEXT));
mvprintw(10, 25, "You lose.");
break;
case GAME_PLAYER_WIN:
attron(COLOR_PAIR(WIN_TEXT));
mvprintw(10, 25, "You Win!");
break;
case GAME_PUSH:
attron(COLOR_PAIR(WIN_TEXT));
mvprintw(10, 25, "It's a tie!");
break;
}
// Turn off bold and return to normal text color
attroff(A_BOLD);
attron(COLOR_PAIR(NORM_TEXT));
// Prompt user to play again
mvprintw(20, 0, "Play again (y/n): ");
refresh();
ch = getch();
} while(ch != 'n');
// Close out 'PDCurses' and pause before exiting
endwin();
system("pause");
return 0;
}
In this program I am trying to create the game BlackJack, most of the game is in other files, but I do not receive errors in the other files. The errors come from the code inside of the Main. The errors are
undefined reference to `BlackjackGame::blackjackGame()
undefined reference to `BlackjackGame::printDeckCurses()
undefined reference to `BlackjackGame::newGame()
undefined reference to `BlackjackGame::playGameCurses()
undefined reference to `BlackjackGame::printedHandsCurses()
undefined reference to `BlackjackGame::getGameState()
With all of these errors coming from the main and these references in the header, that must be my problem, linking the two. Is that correct?
This problem is telling you that you are not linking in the BlackjackGame.o object file when you are building your executable or library.
You must fix your Makefile to link in this file in order to pass the linking stage.
Edit:
Seeing as how you are using Codeblocks for compilation, check these links out(as this error message means different things in different compilers):
undefined reference to function code blocks
Code::Blocks 10.05 Undefined reference to function
It looks like you need to add BlackJackGame.cpp to your project, based on the answer in link 2
Go to Project/Add files to add BlackJackGame source files to your Project, then re-build and that should work

Handling non-input keystrokes?

I'm not sure exactly how to phrase what I'm trying to ask; in C++, using the stdio.h header instead of iostream, how would I make it so that if the escape key is pressed at any point, the program is terminated? Is there something I could add once at the top of the program, or would I have to add it to every loop/conditional individually? Below is my code (the sleep() function is just for a visual loading/calculating effect):
#include <stdio.h>
#include <math.h>
#include <windows.h>
void repeat();
void quadratic()
{
double a, b, c;
double ans[2];
printf("-Arrange your equation in the form aX^2+bX+c \n-Enter the value of a: ");
scanf("%lf", &a);
printf("-Enter the value of b: ");
scanf("%lf", &b);
printf("-Enter the value of c: ");
scanf("%lf", &c);
double radical=((b*b)-(4*a*c));
double root=sqrt(radical);
double negB=(-1)*b;
double denominator=2*a;
if(denominator==0)
{
printf("Calculating");
Sleep(100);
printf(".");
Sleep(100);
printf(".");
Sleep(100);
printf(".");
Sleep(100);
printf("\nError: Denominator must be non-zero.\n \n \n");
}
else if(radical==0)
{
ans[0]=negB/denominator;
printf("Both roots are equal: both values are X=%lf\n \n \n", ans[0]);
}
else if(radical<0)
{
printf("Calculating");
Sleep(100);
printf(".");
Sleep(100);
printf(".");
Sleep(100);
printf(".");
Sleep(100);
double r,i;
radical*=-1;
r=negB/(2*a);
i=sqrt(radical)/(2*a);
printf("\nBoth roots are imaginary numbers.\n");
printf("Non-real answer(s): X=%lf+%lfi X=%lf-%lfi\n \n \n",r,i,r,i);
}
else
{
ans[0]=(negB+root)/denominator;
ans[1]=(negB-root)/denominator;
printf("Calculating");
Sleep(100);
printf(".");
Sleep(100);
printf(".");
Sleep(100);
printf(".");
Sleep(100);
printf("\nX=%lf, X=%lf\n \n", ans[0], ans[1]);
}
repeat();
}
void repeat()
{
quadratic();
}
int main(void)
{
quadratic();
return 0;
}
The terminal used in stdio is likely to be line buffered
(cooked). If it is, checking for the escape key through scanf will
not work.
SEE THESE URLS:
Capture characters from standard input without waiting for enter to be pressed
scanf not reading input
CURSES or NCURSES will detect the escape key (ASCII character 27), depending
on the terminal type.
This code can be used in WINDOWS to check for the ESCAPE
key.
#include <conio.h>
#include <ctype.h>
int ch;
_cputs( "Type 'Y' when finished typing keys: " );
do
{
ch = _getch();
ch = toupper( ch );
if (ch != 27) {
_cputs( "CHARACTER: " );
_putch( ch );
_putch( '\r' ); // Carriage return
_putch( '\n' ); // Line feed
}
} while( ch != 27 );
Is there something I could add once at the top of the program, or would I have to add it to every loop/conditional individually?
I think you can add something once, and use it to catch key stroke events easily throughout your program.
Following is a code snippet showing a function I have used to handle key stroke events in a console application. It uses GetAsyncKeyState(). Included is a section that shows how to capture a CTRL key, and how you can do something once you see it. (the snippet shown shows how I capture a <ctrl><shift><h> key sequence to display a help menu for using this particular routine.
Note: In the description, delay_x(float delay) is simply a custom, non-blocking sleep, or delay function that includes a call to the following snippet. It is called from within the main program loop while(1){...} . Exiting the program is provided in one of the keystroke combinations: <CTRL><SHIFT><K>
Code snippet:
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
//
// SetAppState() is called continuously from within delay_x()
// to capture keystroke combinations as they occur asynchronously
// with this application, Keystroke combinations are listed below
//
// Note: GetAsyncKeyState() can maintian information regarding the
// state of a key instantaineously by use the MSB,
// and recently by using the LSB.
//
// For this application
// only instantaineous information will be kept, minimizing
// conflicts with other keyboard shortcut definitions
// defined by other applications that may be running
// simultaineously.
//
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
void SetAppState(void)
{
short state=0;
short state1=0;
state = GetAsyncKeyState(VK_CONTROL);
if (0x80000000 & state) //check instantaineous state of key
{
state = GetAsyncKeyState(VK_SHIFT);
if (0x80000000 & state) //check instantaineous state of key
{
state = GetAsyncKeyState('h');
state1 = GetAsyncKeyState('H');
if ((0x80000000 & state) ||
(0x80000000 & state1))
{ sprintf(gTempBuf, "Usage - keystrokes to access and control the PaAutoStartSlot application:\n\n"
"<CTRL><SHIFT> H (H)elp - \n"
"<CTRL><SHIFT> V o(V)erride - \n"
"<CTRL><SHIFT> S (S)tatus - \n"
"<CTRL><SHIFT> K (K)ill - \n"
"<CTRL><SHIFT> N (N)o - \n"
"<CTRL><SHIFT> I (I)Inside - \n"
"<CTRL><SHIFT> O (O)Outside- \n"
"\nSee log file at this location for runtime errors: \n\n%s", LOGFILE);
MessagePopup("Usage Menu",gTempBuf);
}
///// ... more code ...
End of snippet
Edit - Answer to questions in comments how to call GetAsyncKeyState()
There are many ways you could call GetAsyncKeyState() at the same time other stuff is going on. Threads are a good way. You can also do it all in line using a while()/switch(){} combination. Here is a very simple example of how you could do this (in pseudo code)
int gRunning = 1;
int state = 1;
int main(void)
{
//create variables, initialize stuff
while(gRunning)//this is your main program loop
{
delay_x(1.0);//check for keystrokes
switch(state) {
case 1:
//do some stuff here
//and experiment with values passed to delay_x(n)
delay_x(10000);//check for keystrokes
state++;
break;
case 2:
//do some different stuff here
delay_x(10000);//check for keystrokes
state++;
break;
... Add as many cases as you need for your program.
case n://last case, set execution flow to top
//do some more different stuff here
delay_x(10000);//check for keystrokes
state = 1;//loop back to top
break;
}
}
return 0;
}
void delay_x (float delay)
{
static clock_t time1;
static clock_t time2; clock();
time1 = clock();
time2 = clock();
while ((time2 - time1) < delay)
{
time2 = clock();
SetAppState(); //see partial definition in my original answer above.
}
}
Note: Using this method, you can have as many, or as few, cases as you need, the important thing is to keep a steady flow of calls to GetAsyncKeyState(). This does that via the call to delay_x().
Note2: Here is the segment (added to above definition) that will cause your program to exit:
state = GetAsyncKeyState('k');
state1 = GetAsyncKeyState('K');
if ((0x80000000 & state) ||
(0x80000000 & state1))
{
printf("Kill Program");
gRunning = FALSE;
}

Adding Verbosity to a Program

This is a very n00b question but
I'm writing a nix based tool and would like to have verbosity flags, based on the number of vvv's passed in I would go about printing debug/information statements in my program.
My question is how would I go about using opargs for this, since optargs can only parse one character at a time.
Also suppose I know I'm at verbosity level 3, do all my print statements have to be in an if condition? Or there a clever way of going about it using the pre-processor?
Also if someone could point me to some code online which does this, that would be awesome.
Thanks
I figure it out, thought I'd post here if someone else comes across this in the future:
Basically for all my different verbosity statements I defined a special print using the preprocessor like:
#define dprintf \
if (verbosity == 1) printf
I then put in the statements as needed in the code e.g.
dprintf ("Verbosity is at level 1.");
My opt atgs looks something like this
case 'v':
verbosity++;
break;
The verbosity level is not known at compile time so you need to have code ready to handle any level the user selects.
A simple, and easy to understand, way of doing this is to separate your logging functions in an opaque compilation unit with a static variable keeping track of the verbosity level. You then initialize this with something like "set_logging_level(level)" and write your logging functions guarded by this static variable. Then you only expose the initialization and the logging functions and use them as you need them in your code.
static level = 0;
void set_logging_level(int l) { level = l; }
void log_info(char* msg) {
// Will always print
}
void log_debug(char *msg) {
if(level > 0)
// Write to stdout or stderr, whichever fits
}
void log_details(char *msg) {
if(level > 1)
// As above
}
void log_insanity(char *msg) {
if(level > 2)
// As above
}
Edit: Saner conditions for logging. Especially if you want inclusive logging when the verbosity level goes up...
How about Conditional compilation?
You could also simplify by setting a number for verbose level instead of passing that many v's.
#if VERBOSE_LEVEL == 3
print("A verbose message");
#endif
I'm not too sure if this is what you've meant, but this is how I implemented it in another project:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define TRUE 1
#define FALSE 0
int usage( char *name, int quit );
int main (int argc, char **argv) {
int c;
static int vlevel = 0;
while ( (c = getopt(argc, argv, ":abc:d:hv012")) != -1) {
int this_option_optind = optind ? optind : 1;
switch (c) {
case 'v':
vlevel++;
printf ("verbosity level is %d\n", vlevel);
break;
case ':': /* Option without required operand */
fprintf(stderr, "option -%c requires an operand\n", optopt);
break;
case 'h':
case '?':
usage( argv[0], TRUE );
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc) {
printf ("non-option ARGV-elements:\n");
while (optind < argc)
printf ("\t%s\n", argv[optind++]);
}
exit (0);
}
int usage( char *progname, int quit )
{
printf ( "Usage:\n\t%s [-vh]\n", progname );
if ( quit ) exit( 1 );
return 0;
}
This would give you something like the following:
eroux#smaug:~$ ./testverbose -h
Usage:
./testverbose [-vh]
eroux#smaug:~$ ./testverbose -vvvv
verbosity level is 1
verbosity level is 2
verbosity level is 3
verbosity level is 4
eroux#smaug:~$
From there you should be able to use the vlevel variable [in main()] to print the correct message during the relevant verbosity level.