1: 
   2: /*
   3: 	
   4:     Copyright 2002 Erik Ljungström (erik.ljungstrom@metalab.unc.edu)
   5: 							&
   6: 				   Henrik Caesar (henrik.caesar@hotmail.com)
   7: 					
   8:     This program is free software; you can redistribute it and/or modify
   9:     it under the terms of the GNU General Public License as published by
  10:     the Free Software Foundation; either version 2 of the License, or
  11:     (at your option) any later version.     This program is distributed in the hope that it will be useful,
  12:     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13:     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14:     GNU General Public License for more details.     
  15:     You should have received a copy of the GNU General Public License
  16:     along with this program; if not, write to the Free Software
  17:     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  18: 
  19: */
  20: 
  21: #include "bmi.h" 
  22: 
  23: using namespace std;
  24: int
  25: main ( int argc, char *argv[] )
  26: {
  27: 
  28: 
  29:   /* --------------------------------
  30:    * Check for command line options
  31:    * and act upon them.
  32:    * --------------------------------
  33:    */
  34: 
  35:   if ( argc != 1 )
  36: 	  if ( strcmp ( argv[1], "--help" ) == 0 ) {
  37: 	   cout << "There's no need for help..." << endl;
  38: 	   leave ( clean );
  39: 	}
  40: 	else {
  41: 	  cout << "There is no command line arguments to pass to BMI." << endl;
  42: 	  leave ( clean );
  43: 	}
  44: 
  45:   /*
  46:    * -----------------------------------------------------------
  47:    * Get some environment variables, and attach BMI extensions
  48:    * to them.
  49:    * -----------------------------------------------------------
  50:    */
  51:   char *path = getenv ( "HOME" ),
  52:    *logname = getenv ( "LOGNAME" ), *display = getenv("DISPLAY"); //generates seg fault if X is missing :/
  53:   
  54:   
  55:   string bmiDir = path, disp = display,
  56:     realpath,
  57:     namn = logname,
  58:     firstLength,
  59:     lengthFile = path,
  60:     loggie,
  61:     maxMin = path,
  62:     sex = path, // And no, is has nothing to do with the Swedish meaning of the word.
  63:     sexStore;   // And nothing's for sale :)
  64: 
  65:   if(disp.size() == 0){
  66:     cerr << "You must have an Xsession going to use BMI..." << endl;
  67:     leave(error);
  68:   }
  69:     
  70: 
  71:   double length,
  72:     weight,
  73:     BMI,
  74:     BMIShort = 0,
  75:     maxBmi = 0,
  76:     minBmi = 0;
  77:   weight = 1;					// Just to get rid of a warning at compile time.
  78:   int turn = 0;
  79: 
  80:   if ( path == 0 || logname == 0 ) {	//Let's hope this'll never happen..
  81:     cout <<
  82: 	  "You have some environment variables lacking. Try exporting HOME and LOGNAME, and try again."
  83: 	  << endl;
  84: 	leave ( error );
  85:   }
  86:   else
  87:     realpath = path;
  88: 
  89:   bmiDir += "/.bmi";			// Useless so far
  90:   realpath += "/.bmi/results";
  91:   lengthFile += "/.bmi/length";
  92:   maxMin += "/.bmi/maxmin";
  93:   sex +="/.bmi/sex";
  94: 
  95:   ifstream firstt ( maxMin.c_str (  ), ios::binary );	//check whether it's the first time bmi is executed.
  96:   if ( !firstt ) {
  97: 	cout <<
  98: 	  "Since this is the first time you run BMI, I'd like to know how tall you are; in the format m.cm: ";
  99: 	cin >> length;
 100: 	/* -------------------------------------------------
 101: 	 * In case someone types his length in centi-metres
 102: 	 * we'll run a check, and convert to meters, if 
 103: 	 * the input is invalid.
 104: 	 * -------------------------------------------------
 105: 	 */
 106: 	if ( length > 3 )
 107: 	  length /= 10;
 108: 	mkdir ( bmiDir.c_str (  ), 0755 );	// Creates ~/.bmi with the correct permissions.
 109: 	ofstream tall ( lengthFile.c_str (  ), ios::app );
 110: 	tall << length;
 111: 	tall.close (  );
 112: 	
 113:   /* ---------------------------------
 114:    * Finds ouy wether the user is a 
 115:    * male of female (since the scale
 116:    * looks different for the sexes
 117:    * ---------------------------------
 118:    */
 119:   string userSex;
 120:   //bool tempLoop = true;
 121:   //do{
 122:   cout << endl << "Are you a male or female (m/f): " << flush;
 123:   cin.ignore(10, '\n');
 124:   getline(cin,userSex);
 125:   userSex = in_Str2Low(userSex);
 126:   if ((userSex != "m") && (userSex != "f"))
 127:     cerr << "You must give f or m here." << endl;
 128:   //else 
 129:   // tempLoop = false;
 130:   //}
 131:   //while (tempLoop)
 132:     
 133:   ofstream outSex(sex.c_str(), ios::binary);
 134:   outSex << userSex;
 135:   outSex.close();
 136:    
 137:   /* ------------------------------------------------
 138: 	 * Create minmax file which will keep max BMI and 
 139: 	 * min BMI. Fill them with max with 0, and min with
 140: 	 * 100000
 141: 	 * ------------------------------------------------
 142: 	 */
 143: 
 144: 	ofstream maxx ( maxMin.c_str (  ), ios::app );
 145: 	maxx << 0 << endl << 1000;
 146: 	maxx.close (  );
 147:   }
 148: 
 149: 
 150:   /* ---------------------------------
 151:    * Some ncurses initializing stuff
 152:    * ---------------------------------
 153:    */
 154:   initscr (  );
 155:   cbreak (  );
 156:   noecho (  );
 157:   nonl (  );
 158:   intrflush ( stdscr, FALSE );
 159:   keypad ( stdscr, TRUE );
 160:   clear (  );
 161: 
 162: 
 163:   /*
 164:    * ----------------------------------------------------------------
 165:    * Read in the users height and sex from the files created above,
 166:    * as well as the highest and lowest BMI.
 167:    * ----------------------------------------------------------------
 168:    */
 169:   ifstream ReadFile ( lengthFile.c_str (  ), ios::binary );	//length
 170:   getline ( ReadFile, loggie );
 171:   istringstream in ( loggie );
 172:   in >> length;
 173:   ReadFile.close (  );
 174:   loggie = "";					//"Reset"
 175:   //highest and lowest. Highest in place[0] and lowest in place[1]
 176:   ifstream readMaxMin ( maxMin.c_str (  ), ios::binary );
 177:   while ( getline ( readMaxMin, loggie ) ) {
 178: 	if ( turn == 0 ) {
 179: 	  //place.push_back(atof(loggie.c_str())); // till place[0]
 180: 	  maxBmi = atof ( loggie.c_str (  ) );
 181: 	  turn++;
 182: 	}
 183: 	if ( turn == 1 )
 184: 	  //place.push_back(atof(loggie.c_str()));        // till place[1]        
 185: 	  minBmi = atof ( loggie.c_str (  ) );
 186:   }
 187:   readMaxMin.close();
 188:   
 189:   loggie = ""; // "Reset" again
 190:   ifstream readSex(sex.c_str(), ios::binary);
 191:     while (getline (readSex, loggie))
 192:       sexStore = loggie;
 193:     readSex.close();
 194:   
 195:   do {
 196: 	switch ( meny (  ) ) {
 197: 
 198: 	case 1:
 199: 	  {
 200:     bool digits = true;
 201:     do {
 202:     digits=true;
 203:     char *cmd2 = "Xdialog --title \"BMI-1.2.4\" --stdout --inputbox \"How much do you weigh?\" 0 0", buf2[2048] = "";
 204:     FILE *ptr2 = popen (cmd2, "r");
 205: 		fgets ( buf2, BUFSIZ, ptr2 );
 206: 		cout << "buf2 is " << buf2 << " and len is " << strlen(buf2) << endl;
 207:     
 208:     /* -----------------------------------------
 209:      * Check for other input than numbers
 210:      * to prevent BMI to result to 0 by
 211:      * calculating with 0 (return value)
 212:      * -----------------------------------------
 213:      */
 214:     for (unsigned int j=0; j < strlen(buf2)-1 ;j++) 
 215:       if  ((!isdigit(buf2[j])) && (buf2[j]!='.')) 
 216:         digits = false;
 217:       if (digits == true)
 218:         weight = atof(buf2);
 219:                
 220:     pclose(ptr2);
 221:   }
 222:   while (digits == false);
 223:   
 224: 		/*
 225: 		 * -------------------------------------
 226: 		 * Length is read previously (Line: 71)
 227: 		 * -------------------------------------
 228: 		 */
 229: 
 230: 		BMI = weight / pow ( length, 2 );
 231: 		if ( BMI > maxBmi )		//Bigger than the max read in earlier..
 232: 		  maxBmi = BMI;
 233: 
 234: 		if ( BMI < minBmi )		//Smaller than the min read in earlier..
 235: 		  minBmi = BMI;
 236: 
 237: 		remove ( maxMin.c_str (  ) );	// Make place for new (?) values?
 238: 		ofstream toMaxMin ( maxMin.c_str (  ), ios::binary );
 239: 		toMaxMin << maxBmi << endl << minBmi;	//Write new (?) max and min.
 240: 		toMaxMin.close (  );
 241: 
 242: 		/*
 243: 		 * ----------------------------------------------------------
 244: 		 * Writes output to ~/.bmi/result The output consists of
 245: 		 * name (grabbed from environment variable LOGNAME), date and 
 246: 		 * result.
 247: 		 * ----------------------------------------------------------
 248: 		 */
 249: 
 250: 		ofstream toRes ( realpath.c_str (  ), ios::app );
 251: 		time_t timer;
 252: 		struct tm *tblock;
 253: 		timer = time ( NULL );
 254: 		tblock = localtime ( &timer );
 255: 		toRes << asctime ( tblock );
 256: 		toRes << namn << " had the BMI value of " <<
 257: 		  setprecision ( 4 ) << BMI << endl;
 258: 		toRes.close (  );
 259: 
 260: 		ostringstream showRes;
 261: 		showRes << "Xdialog --title \"BMI-1.2.4\" --title \"Your BMI is\" --msgbox "
 262: 		  << setprecision ( 4 ) << BMI << " 0 0";
 263: 		system ( showRes.str (  ).c_str (  ) );
 264:     BMIShort = floor(BMI*100.0+.5)/100.0; // Reduces the amount of decimals to 2.
 265:     if (sexStore == "m"){                 // so the for loops don't have to go so high.
 266:       
 267:       if (BMI > 45.4)
 268:         system("Xdialog --title \"BMI-1.2.4\" --msgbox \"Morbid obesity. You will for sure suffer from healt problems at higher age.\" 0 0");
 269:       if (BMI < 20.7)
 270:         system("Xdialog --title \"BMI-1.2.4\" --msgbox \"You are underweight! Concider seeing a dietist! You may have som health issues at greater age.\" 0 0");
 271: 		   /* ----------------------------------
 272: 		   * Break to prevent that two dialogs
 273: 		   * are shown upon a result excessing
 274: 		   * 30. Since 30 > 25.
 275: 		   * ----------------------------------
 276: 		   */
 277: 		    
 278:     
 279:       for (double i = 31.1; i < 45.5;i +=0.01)
 280:       {
 281:       if (fabs(BMIShort - i) < 1e-3){
 282:           system
 283: 			( "Xdialog --title \"BMI-1.2.4\" --msgbox \"Your fatness is _very_ unhealthy. Concider searching help.\" 0 0" );
 284:         }
 285:       }
 286:     
 287:        for (double i = 27.8; i < 31.1;i +=0.01)
 288:       {
 289:       if (fabs(BMIShort - i) < 1e-3){
 290:           system("Xdialog --title \"BMI-1.2.4\" --msgbox \"Your weight is above what's concider healthy. Concider a diet.\" 0 0");
 291:         }
 292:       }
 293:       
 294:       for (double i = 26.4; i < 27.8;i +=0.01)
 295:       {
 296:       if (fabs(BMIShort - i) < 1e-3){
 297:           system("Xdialog --title \"BMI-1.2.4\" --msgbox \"You are marginally overweight. There is some risk for health problems in the future. \" 0 0");
 298:         }
 299:       }
 300:        for (double i = 20.7; i < 26.4 ;i +=0.01)
 301:       {
 302:       if (fabs(BMIShort - i) < 1e-3){
 303:           system("Xdialog --title \"BMI-1.2.4\" --msgbox \"Ideal weight! The health risk is minmal! Keep it up! \" 0 0");
 304:         }
 305:       }
 306:       
 307:     } // sexStore == m
 308:     
 309:     
 310:     else if (sexStore == "f"){
 311:          for (double i = 32.3 ; i < 44.8 ;i +=0.01)
 312:           {
 313:             if (fabs(BMIShort - i) < 1e-3){
 314:               system("Xdialog --title \"BMI-1.2.4\" --msgbox \"You are very overweight, do concider seeing a dietist.\" 0 0");
 315:             }
 316:           }
 317:           
 318:      for (double i = 27.3; i < 32.2;i +=0.01)
 319:       {
 320:       if (fabs(BMIShort - i) < 1e-3){
 321:           system("Xdialog --title \"BMI-1.2.4\" --msgbox \"You are overweight, concider going on a diet. Moderate health risk \" 0 0");
 322:         }
 323:       }
 324:       
 325:     for (double i = 25.8; i < 27.3 ;i +=0.01)
 326:       {
 327:       if (fabs(BMIShort - i) < 1e-3){
 328:           system("Xdialog --title \"BMI-1.2.4\" --msgbox \"Marginally overweight. There is some risk for healt problems in the future. \" 0 0");
 329:         }
 330:       }  
 331:       
 332:      for (double i = 19.1 ; i < 25.8;i +=0.01)
 333:       {
 334:       if (fabs(BMIShort - i) < 1e-3){
 335:           system("Xdialog --title \"BMI-1.2.4\" --msgbox \"This is your ideal weight. Keep it up! \" 0 0");
 336:         }
 337:       }
 338:       
 339:       if (BMI > 44.8)
 340:         system("Xdialog --title \"BMI-1.2.4\" --msgbox \"Morbid obesity. You will for sure suffer from healt problems at higher age.\" 0 0");
 341:       if (BMI < 19.1)
 342:         system("Xdialog --title \"BMI-1.2.4\" --msgbox \"You are underweight! Concider seeing a dietist! You may have som health issues at greater age.\" 0 0");
 343:     } // sexStore == f
 344:     
 345:     break;
 346: 	  }							//end of case 1:
 347:   
 348: 	case 2:
 349: 	  {
 350:     if (sexStore == "m")
 351:       system ( "Xdialog --title \"BMI-1.2.4\" --tailbox /usr/share/bmi/bmi_scale.m 0 0" );
 352:     else if (sexStore == "f")
 353:       system ( "Xdialog --title \"BMI-1.2.4\" --tailbox /usr/share/bmi/bmi_scale.f 0 0");
 354: 		break;
 355: 
 356: 	  }							//end of case 2
 357: 
 358: 	case 3:
 359: 	  {
 360: 
 361: 		ostringstream lengthStream;
 362: 		/*
 363: 		 * -------------------------------------------------
 364: 		 * Here's _some_ bash scripting. The length is not
 365: 		 * put in the ~/.bmi/length by a normal ifstream
 366: 		 * but directly from the output from the dialog.
 367: 		 * Not that good, if the box is canceled though :/
 368: 		 * -------------------------------------------------
 369: 		 */
 370: 		lengthStream <<
 371: 		  "Xdialog --title \"BMI-1.2.4\" --stdout --inputbox \"How tall are you now?\" 0 0 m.cm > "
 372: 		  << lengthFile;
 373: 		system ( lengthStream.str (  ).c_str (  ) );
 374: 
 375: 		/*
 376: 		 * -------------------------------------------------
 377: 		 * In order to prevent an eventual new calculation
 378: 		 * to go wrong, let's get the new value of length
 379: 		 * into use...
 380: 		 * -------------------------------------------------
 381: 		 */
 382: 		std::string loggie2;
 383: 		ifstream ReadFile2 ( lengthFile.c_str (  ), ios::binary );
 384: 		getline ( ReadFile2, loggie2 );
 385: 		istringstream in2 ( loggie2 );
 386: 		in2 >> length;
 387: 
 388: 		break;
 389: 	  }							// end of case 3
 390: 
 391: 	case 4:
 392: 	  {
 393: 		FILE *tf = fopen ( realpath.c_str (  ), "r" );
 394: 		if ( !tf ) {
 395: 
 396: 		  system
 397: 			( "Xdialog  --title \"BMI-1.2.4\" --msgbox \"The file containing this information does not exist. Creating one...\" 0 0" );
 398: 		  ofstream result ( realpath.c_str (  ), ios::app );
 399: 		  result << "";
 400: 		  result.close (  );
 401: 		}
 402: 		else {
 403: 		  /*
 404: 		   * ---------------------------------------------------------------------
 405: 		   * Kind of relatively demanding code. Ugly? Yes. Works? Hell yeah!
 406: 		   * Fixed from previous version is dialog --textbox, which allows the 
 407: 		   * user to see all the results, even though the number of posts exceeds
 408: 		   * the amount of rows in the terminal.
 409: 		   * ---------------------------------------------------------------------
 410: 		   */
 411: 		  ostringstream uglyOne;
 412: 		  uglyOne << "Xdialog --title \"BMI-1.2.4\" --textbox " << realpath << " 0 0";
 413: 		  system ( uglyOne.str (  ).c_str (  ) );
 414: 		}
 415: 		break;
 416: 
 417: 	  }							//end of case 4
 418: 
 419: 	case 5:
 420: 	  {
 421:     remove ( maxMin.c_str());
 422: 		remove ( realpath.c_str (  ) );
 423: 		break;
 424: 	  }
 425:   
 426:   case 6:
 427:   {
 428:     ostringstream getMinMax;
 429:     getMinMax << "Xdialog --title \"BMI-1.2.4\" --msgbox \"Max bmi is: " << 
 430:       maxBmi << endl << "Min bmi is: " << minBmi << "\" 0 0" ;
 431:     system(getMinMax.str().c_str());
 432:     break;
 433:   }
 434:   
 435: 	case 7:
 436: 	  {
 437: 		ostringstream printOut,
 438: 		  dispPrint;
 439: 		printOut << "cat " << realpath << " > /dev/lp0";
 440: 		system ( printOut.str().c_str());
 441: 		dispPrint <<
 442: 		  "Xdialog --title \"BMI-1.2.4\" --sleep 2 --infobox \"Printing from \""
 443: 		  << realpath << " 3 45";
 444: 		system ( dispPrint.str (  ).c_str (  ) );
 445: 		break;
 446: 	  }
 447: 
 448: 	case 8:
 449: 	  {
 450: 		double shouldWeight = 22.5 * pow ( length, 2 );
 451: 		ostringstream showShould;
 452: 		showShould <<
 453: 		  "Xdialog  --title \"BMI-1.2.4\" --msgbox \"For your length, you should weigh \""
 454: 		  << shouldWeight << " 0 0";
 455: 		system ( showShould.str (  ).c_str (  ) );
 456: 		break;
 457: 	  }
 458: 	case 9:
 459: 	  {
 460: 			leave ( clean );
 461:       break;
 462: