knowledge-database (beta)

Current group: comp.sources.d

Re: longjmp vs goto

Re: longjmp vs goto  
Generic Usenet Account
From:Generic Usenet Account
Subject:Re: longjmp vs goto
Date:10 Dec 2004 11:58:44 -0800
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 //////////////////////
   

Copyright © 2006 knowledge-database   -   All rights reserved