 | Sometime back I posted some sample code to illustrate the use of setjmp and longjmp library calls in menu-driven applications. It turns out that there is an interesting situation that I missed. I had assumed that when the processing of a menu item is completed, control automatically resumes with the original menu. While this is sometimes desirable, other times it is not. Reproduced below is modified software that allows control to be resumed to the same menu, or to the parent menu. The former uses the for(;;) construct, while the latter uses the while(!done) construct.
In the coding example that follows, control resumes with the Main Menu as well as Sub Menu 1 & Sub Menu 2 when a menu item completes processing. On the other hand, when processing of a Sub Menu 3 item is completed, control transfers to the Main Menu. As can be seen, the Main Menu as well as Sub Menu 1 & Sub Menu 2 use the "for(;;)" construct, while Sub Menu 3 uses the "while(!done)" construct.
///////////////////// Code snippet begin //////////////////////
#include #include
#define MAX_LINE_LEN 128
#define readStdin(x) while(true) \ { \ cin >> x; \ if(!cin) \ { \ cin.clear(); \ cin.ignore(MAX_LINE_LEN, '\n'); \ } \ else \ break; \ } // // Perhaps use a template instead of the macro //
jmp_buf envMain;
jmp_buf envSub1; // Needed only if long jump to sub-menu 1 is needed jmp_buf envSub2; // Needed only if long jump to sub-menu 2 is needed jmp_buf envSub3; // Needed only if long jump to sub-menu 3 is needed
//////////////////////////////////////////////////////////////////////// void processSubMenu1_Option1() { cout << "\n\nEnter value (blank line returns to sub-menu 1): " << endl; char usrString[MAX_LINE_LEN + 1];
cin.ignore(MAX_LINE_LEN, '\n'); cin.getline(usrString, MAX_LINE_LEN); if(strcmp(usrString, "")) { cout << "** Processing Sub-menu 1 Option 1 **"<< endl;
//doSomething(); } }
//////////////////////////////////////////////////////////////////////// void processSubMenu1_Option2() { cout << "\n\nEnter value (blank line returns to sub-menu 1): " << endl; char usrString[MAX_LINE_LEN + 1];
cin.ignore(MAX_LINE_LEN, '\n'); cin.getline(usrString, MAX_LINE_LEN); if(strcmp(usrString, "")) { cout << "** Processing Sub-menu 1 Option 2 **"<< endl;
//doSomething(); } }
//////////////////////////////////////////////////////////////////////// void processSubMenu1_Option3() { cout << "\n\nEnter value (blank line returns to sub-menu 1): " << endl; char usrString[MAX_LINE_LEN + 1];
cin.ignore(MAX_LINE_LEN, '\n'); cin.getline(usrString, MAX_LINE_LEN); if(strcmp(usrString, "")) { cout << "** Processing Sub-menu 1 Option 3 **"<< endl;
//doSomething(); } }
//////////////////////////////////////////////////////////////////////// void processSubMenu_1() { int option;
setjmp(envSub1); // // Return to this menu // for(;;) { cout << endl << endl; cout << "\n Sub Menu 1"; cout << "\n ==========\n"; cout << "\n 1. 1::Option 1"; cout << "\n 2. 1::Option 2"; cout << "\n 3. 1::Option 3"; cout << "\n 0. Return to Main Menu"; cout << "\n Please enter your selection: ";
readStdin(option);
switch(option) { case 1 : processSubMenu1_Option1(); break;
case 2 : processSubMenu1_Option2(); break;
case 3 : processSubMenu1_Option3(); break;
case 0 : longjmp(envMain, 1); break;
default : cout << "Invalid value entered ---- ignored ...\n"; continue;
} } }
//////////////////////////////////////////////////////////////////////// void processSubMenu2_Option1() { cout << "\n\nEnter value (blank line returns to sub-menu 2): " << endl; char usrString[MAX_LINE_LEN + 1];
cin.ignore(MAX_LINE_LEN, '\n'); cin.getline(usrString, MAX_LINE_LEN); if(strcmp(usrString, "")) { cout << "** Processing Sub-menu 2 Option 1 **"<< endl;
//doSomething(); } }
//////////////////////////////////////////////////////////////////////// void processSubMenu2_Option2() { cout << "\n\nEnter value (blank line returns to sub-menu 2): " << endl; char usrString[MAX_LINE_LEN + 1];
cin.ignore(MAX_LINE_LEN, '\n'); cin.getline(usrString, MAX_LINE_LEN); if(strcmp(usrString, "")) { cout << "** Processing Sub-menu 2 Option 2 **"<< endl;
//doSomething(); } }
//////////////////////////////////////////////////////////////////////// void processSubMenu2_Option3() { cout << "\n\nEnter value (blank line returns to sub-menu 2): " << endl; char usrString[MAX_LINE_LEN + 1];
cin.ignore(MAX_LINE_LEN, '\n'); cin.getline(usrString, MAX_LINE_LEN); if(strcmp(usrString, "")) { cout << "** Processing Sub-menu 2 Option 3 **"<< endl;
//doSomething(); } }
//////////////////////////////////////////////////////////////////////// void processSubMenu_2() { int option;
setjmp(envSub2); // // Return to this menu // for(;;) { cout << endl << endl; cout << "\n Sub Menu 2"; cout << "\n ==========\n"; cout << "\n 1. 2::Option 1"; cout << "\n 2. 2::Option 2"; cout << "\n 3. 2::Option 3"; cout << "\n 0. Return to Main Menu"; cout << "\n Please enter your selection: ";
readStdin(option);
switch(option) { case 1 : processSubMenu2_Option1(); break;
case 2 : processSubMenu2_Option2(); break;
case 3 : processSubMenu2_Option3(); break;
case 0 : longjmp(envMain, 2); break;
default : cout << "Invalid value entered ---- ignored ...\n"; continue;
} } }
//////////////////////////////////////////////////////////////////////// void processSubMenu3_Option1() { cout << "\n\nEnter value (blank line returns to the Main Menu): " << endl; char usrString[MAX_LINE_LEN + 1];
cin.ignore(MAX_LINE_LEN, '\n'); cin.getline(usrString, MAX_LINE_LEN); if(strcmp(usrString, "")) { cout << "** Processing Sub-menu 3 Option 1 **"<< endl;
//doSomething(); } }
//////////////////////////////////////////////////////////////////////// void processSubMenu3_Option2() { cout << "\n\nEnter value (blank line returns to the Main Menu): " << endl; char usrString[MAX_LINE_LEN + 1];
cin.ignore(MAX_LINE_LEN, '\n'); cin.getline(usrString, MAX_LINE_LEN); if(strcmp(usrString, "")) { cout << "** Processing Sub-menu 3 Option 2 **"<< endl;
//doSomething(); } }
//////////////////////////////////////////////////////////////////////// void processSubMenu3_Option3() { cout << "\n\nEnter value (blank line returns to the Main Menu): " << endl; char usrString[MAX_LINE_LEN + 1];
cin.ignore(MAX_LINE_LEN, '\n'); cin.getline(usrString, MAX_LINE_LEN); if(strcmp(usrString, "")) { cout << "** Processing Sub-menu 3 Option 3 **"<< endl;
//doSomething(); } }
//////////////////////////////////////////////////////////////////////// void processSubMenu_3() { int option;
setjmp(envSub3); // // When done, go to parent menu // bool done = false; while(!done) { cout << endl << endl; cout << "\n Sub Menu 3"; cout << "\n ==========\n"; cout << "\n 1. 3::Option 1"; cout << "\n 2. 3::Option 2"; cout << "\n 3. 3::Option 3"; cout << "\n 0. Return to Main Menu "; cout << "\n Please enter your selection: ";
readStdin(option);
switch(option) { case 1 : processSubMenu3_Option1(); done = true; break;
case 2 : processSubMenu3_Option2(); done = true; break;
case 3 : processSubMenu3_Option3(); done = true; break;
case 0 : longjmp(envMain, 3); break;
default : cout << "Invalid value entered ---- ignored ...\n"; continue; } } }
///////////////////////////////////////////////////////////////////////// int main() { int option;
setjmp(envMain);
// // Return to this menu // for(;;) { cout << endl << endl; cout << "\n Main Menu"; cout << "\n =========\n"; cout << "\n 1. Sub Menu 1"; cout << "\n 2. Sub Menu 2"; cout << "\n 3. Sub Menu 3"; cout << "\n 0. Exit"; cout << "\n Please enter your selection: ";
readStdin(option);
switch(option) { case 1 : processSubMenu_1(); break;
case 2 : processSubMenu_2(); break;
case 3 : processSubMenu_3(); break;
case 0 : cout << "Exiting ..." << endl; return 0;
default : cout << "Invalid value entered ---- ignored ...\n"; continue;
} } }
///////////////////// Code snippet end //////////////////////
|
|