/* db.c */

/*
    NUT nutrition software 
    Copyright (C) 1996-2008 by Jim Jozwiak.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "db.h"
#include "meal.h"
#include "options.h"
#include "util.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <ctype.h>
 
#ifndef NUTDIR
char nutdir1[]=".nutdb";
#else
char nutdir1[]=NUTDIR ;
#endif

char USDAjoined1[] = "sr21.nut";
char globalFOOD1[] = "FOOD_DES.txt";
char globalNUT1[] = "NUT_DATA.txt";
char globalWEIGHT1[] = "WEIGHT.txt";
char weightlib1[] = "WEIGHT.lib";
char localFOOD1[] = "FOOD_DES.txt";
char localNUT1[] = "NUT_DATA.txt";
char localWEIGHT1[] = "WEIGHT.txt";
char foodfile1[] = "food.db";
char mealfile1[] = "meal.db";
char mealexpfile1[] = "meal.exp";
char theusualfile1[] = "theusual.db";
char optionsfile1[] = "options.db";
char localOPTIONS1[] = "OPTIONS.txt";
char versionfile1[] = "version";
char oldversionfile1[] = ".version";

char USDAjoined[2000];
char globalFOOD[2000];
char globalNUT[2000];
char globalWEIGHT[2000];
char weightlib[2000];
char localFOOD[2000];
char localNUT[2000];
char localWEIGHT[2000];
char foodfile[2000];
char mealfile[2000];
char mealexpfile[2000];
char theusualfile[2000];
char optionsfile[2000];
char localOPTIONS[2000];
char versionfile[2000];
char oldversionfile[2000];
char nutdir[2000];
char nutdirsubuser[2000];
char subuser[2000];

int mealdb_mealsperday;

FILE *fp;

void read_food_files()
{
 if (version(0) < 10) remove(optionsfile);
 read_joined_db(USDAjoined);
 if (version(0) == 10 && version(1) < 7) read_options_db(1);
 else read_OPTIONS(1);
 read_FOOD(globalFOOD);
 read_NUT(globalNUT);
 read_WEIGHT(globalWEIGHT);
 read_FOOD(localFOOD);
 read_NUT(localNUT);
 read_WEIGHT(localWEIGHT);
 make_food_index();
 read_meal_db();
 read_theusual_db();
 full_meal_reindexing();
 write_food_db();
 write_meal_db();
 write_theusual_db();
 read_OPTIONS(0);
 write_OPTIONS();
}

void read_joined_db(char *textfile) 
{
char buffer[800];
char *bufptr;
char *fieldptr;
int count, junk, foodcount = 0;
if ((fp = fopen(textfile,"rb")) == NULL)
 {
 printf("Can't open food file \"%s\" to create food database.\n",textfile);
 printf("Press <enter> to continue...\n");
 junk = get_int();
 abort();
 }
printf("\nReading food file \"%s\"\n",textfile);
printf("to create food database \"%s\"...\n",foodfile);
while (fgets(buffer,800,fp) != NULL)
 {
 if ((new_food = malloc(sizeof(struct food))) == NULL)
  {
  printf("We are out of memory.  Bummer.\n");
  abort();
  }
 bufptr = buffer ;
 fieldptr = bufptr;
 while (*bufptr != '^') bufptr++;
 *bufptr = '\0' ; bufptr++;
 new_food->ndb_no = atoi(fieldptr);
 fieldptr = bufptr;
 while (*bufptr != '^') bufptr++;
 *bufptr = '\0' ; bufptr++;
 new_food->fdgrp = atoi(fieldptr);
 fieldptr = new_food->name;
 while (*bufptr != '^')
  {
  *fieldptr++ = *bufptr++ ;
  }
 *fieldptr = '\0' ; bufptr ++;
 while (*bufptr != '^' ) bufptr++ ; /* Bypass scientific name */
 bufptr++ ;
 fieldptr = bufptr ;
 while (*bufptr != '^' ) bufptr++ ;
 *bufptr = '\0'; bufptr++ ;
 new_food->refuse = (float) atoi(fieldptr);
 fieldptr = bufptr ;
 while (*bufptr != '^' ) bufptr++ ;
 *bufptr = '\0'; bufptr++ ;
 new_food->prot_cal_factor = (float) atof(fieldptr);
 fieldptr = bufptr ;
 while (*bufptr != '^' ) bufptr++ ;
 *bufptr = '\0'; bufptr++ ;
 new_food->fat_cal_factor = (float) atof(fieldptr);
 fieldptr = bufptr ;
 while (*bufptr != '^' ) bufptr++ ;
 *bufptr = '\0'; bufptr++ ;
 new_food->cho_cal_factor = (float) atof(fieldptr);
 for (count = 0; count < NUTRIENT_COUNT - DERIVED; count++)
  {
  fieldptr = bufptr ;
  while (*bufptr != '^' ) bufptr++ ;
  *bufptr = '\0'; bufptr++ ;
  new_food->nutrient[count] = (float) atof(fieldptr);
  }
 fieldptr = bufptr;
 while (*bufptr != '^' ) bufptr++ ;
 *bufptr = '\0'; bufptr ++ ;
 new_food->qty = atof(fieldptr); if (new_food->qty <= 0) new_food->qty = 1;
 fieldptr = bufptr;
 while (*bufptr != '^' ) bufptr++ ;
 *bufptr = '\0'; bufptr ++ ;
 strncpy(new_food->unit,fieldptr,50);
 fieldptr = bufptr;
 while (*bufptr != '\n' ) bufptr++ ;
 *bufptr = '\0';
 new_food->grams = (float) atof(fieldptr);
 compute_derived_fields(new_food);
 junk = order_new_food();
 if (++foodcount % 500 == 0) printf("Read %d foods...\n", foodcount);
 }
fclose(fp);
}

void read_FOOD(char *textfile)
{
struct food *food_ptr;
char buffer[400];
char *bufptr;
char *fieldptr;
int count, junk, ndbno;
if ((fp = fopen(textfile,"rb")) == NULL) return;
printf("\nReading food description file \"%s\"\n",textfile);
printf("to update food database \"%s\"...\n",foodfile);
while (fgets(buffer,400,fp) != NULL)
 {
 bufptr = buffer;
 bufptr++;
 fieldptr = bufptr++;
 while (*bufptr != '~') bufptr++;
 *bufptr = '\0' ; bufptr++; *bufptr = '\0' ;
 ndbno = atoi(fieldptr);
 food_ptr = find_ndbno_ptr(ndbno);
 new_food = NULL;
 if (food_ptr == NULL)
  {
  if ((new_food = malloc(sizeof(struct food))) == NULL)
   {
   printf("We are out of memory.  Bummer.\n");
   abort();
   }
  new_food->ndb_no = ndbno;
  if (ndbno >= 99000) new_food->fdgrp = 0;
  for (count = 0; count < NUTRIENT_COUNT; count++) new_food->nutrient[count] = NoData;
  if (ndbno >= options.next_recipe) options.next_recipe = ndbno + 1;
  food_ptr = new_food;
  }

 while (*bufptr != '^') bufptr++;
 *bufptr = '\0' ; 
 
 while (*bufptr != '^') bufptr++;
 *bufptr = '\0' ;

 fieldptr = bufptr;
 fieldptr++; fieldptr++;
 while (*bufptr != '~') bufptr++;
 *bufptr = '\0' ; bufptr++;
 while (*bufptr != '~') bufptr++;
 *bufptr = '\0' ; bufptr++;
 strcpy(food_ptr->name,fieldptr);

 while (*bufptr != '^') bufptr++;
 *bufptr = '\0' ;

 while (*bufptr != '^') bufptr++;
 *bufptr = '\0' ;

 while (*bufptr != '^') bufptr++;
 *bufptr = '\0' ;

 while (*bufptr != '^') bufptr++;
 *bufptr = '\0' ;

 while (*bufptr != '^') bufptr++;
 *bufptr = '\0' ;

 fieldptr = bufptr;
 fieldptr++;
 while (*bufptr != '^') bufptr++;
 *bufptr = '\0' ;
 food_ptr->refuse = atof(fieldptr);

 while (*bufptr != '^') bufptr++;
 *bufptr = '\0' ;

 while (*bufptr != '^') bufptr++;
 *bufptr = '\0' ;

 fieldptr = bufptr;
 fieldptr++;
 while (*bufptr != '^') bufptr++;
 *bufptr = '\0' ;
 food_ptr->prot_cal_factor = atof(fieldptr);

 fieldptr = bufptr;
 fieldptr++;
 while (*bufptr != '^') bufptr++;
 *bufptr = '\0' ;
 food_ptr->fat_cal_factor = atof(fieldptr); 

 fieldptr = bufptr;
 fieldptr++;
 food_ptr->cho_cal_factor = atof(fieldptr);
 if (food_ptr == new_food) junk = order_new_food();
 compute_derived_fields(food_ptr);
 }
fclose(fp);
}

void read_NUT(char *textfile)
{
struct food *food_ptr;
char buffer[400];
char *bufptr;
char *fieldptr;
int ndbno, nutrno;
float value;
if ((fp = fopen(textfile,"rb")) == NULL) return;
printf("\nReading nutrient file \"%s\"\n",textfile);
printf("to update food database \"%s\"...\n",foodfile);
while (fgets(buffer,400,fp) != NULL)
 {
 bufptr = buffer;
 bufptr++;
 fieldptr = bufptr++;
 while (*bufptr != '~') bufptr++;
 *bufptr = '\0' ; bufptr++; *bufptr = '\0' ;
 ndbno = atoi(fieldptr);
 food_ptr = find_ndbno_ptr(ndbno);
 if (food_ptr == NULL) continue;

 fieldptr = bufptr;
 fieldptr++; fieldptr++;
 while (*bufptr != '~') bufptr++;
 *bufptr = '\0';
 while (*bufptr != '~') bufptr++;
 *bufptr = '\0' ; bufptr++; *bufptr = '\0' ;
 nutrno = atof(fieldptr);

 fieldptr = bufptr;
 fieldptr++;                        
 while (*bufptr != '^') bufptr++;
 *bufptr = '\0' ;
 value = atof(fieldptr);

 if (LookupNut[nutrno] != -1)
  {
  food_ptr->nutrient[LookupNut[nutrno]] = value;
  compute_derived_fields(food_ptr);
  }
 }
fclose(fp);
}

void read_WEIGHT(char *textfile)
{
struct food *food_ptr;
char buffer[400];
char *bufptr;
char *fieldptr;
int ndbno;
if ((fp = fopen(textfile,"rb")) == NULL) return;
printf("\nReading food weight file \"%s\"\n",textfile);
printf("to update food database \"%s\"...\n",foodfile);
while (fgets(buffer,400,fp) != NULL)
 {
 bufptr = buffer;
 bufptr++;
 fieldptr = bufptr++;
 while (*bufptr != '~') bufptr++;
 *bufptr = '\0' ; bufptr++; *bufptr = '\0' ;
 ndbno = atoi(fieldptr);
 food_ptr = find_ndbno_ptr(ndbno);
 if (food_ptr == NULL) continue;

 while (*bufptr != '^') bufptr++;
 *bufptr = '\0' ;

 fieldptr = bufptr;
 fieldptr++;                        
 while (*bufptr != '^') bufptr++;
 *bufptr = '\0' ;
 food_ptr->qty = atof(fieldptr);
 if (food_ptr->qty <= 0) food_ptr->qty = 1;

 fieldptr = bufptr;
 fieldptr++; fieldptr++;
 while (*bufptr != '~') bufptr++;
 *bufptr = '\0' ; bufptr++;
 while (*bufptr != '~') bufptr++;
 *bufptr = '\0' ; bufptr++; *bufptr = '\0';
 
 strncpy(food_ptr->unit,fieldptr,50);

 fieldptr = bufptr;
 fieldptr++;                        
 while (*bufptr != '^') bufptr++;
 *bufptr = '\0' ;
 food_ptr->grams = atof(fieldptr);
 }
fclose(fp);
}

void read_weightlib(int ndbno, char *buffer, int bufsize, char **result,int *resultparm)
{
char *bufptr;
char *fieldptr;
if ((fp = fopen(weightlib,"rb")) == NULL) return;
while (fgets(buffer,bufsize,fp) != NULL)
 {
 bufptr = buffer;
 fieldptr = buffer;
 while (*bufptr != '^') bufptr++;
 if (atoi(fieldptr) != ndbno) continue;
 else
  {
  *bufptr = '\0';
  bufptr++;
  result[*resultparm] = bufptr;
  *resultparm += 1;
  while (*bufptr != '\n')
   {
   bufptr++;
   if (*bufptr == '^')
    {
    *bufptr = '\0';
    result[*resultparm] = bufptr+1;
    *resultparm += 1;
    }
   }
  fclose(fp);
  return;
  }
 }
fclose(fp);
return;
}

int read_food_db()
{
int block, foodcount = 0;
struct food *food_ptr = &food_root;
if ((fp = fopen(foodfile,"rb")) == NULL) return 0;
for ( ; ; )
 {
 if ((new_food = malloc(sizeof(struct food))) == NULL)
  {
  printf("Bad news.  We are out of memory...");
  abort();
  }
 if ((block = fread(new_food,sizeof(struct food),1,fp)) != 0)
  {
  food_ptr->next = new_food;
  food_ptr = new_food;
  foodcount++;
  }
 else break;
 }
fclose(fp);
make_food_index();
return 1;
}

void read_meal_db()
{
int block;
struct meal *meal_ptr = &meal_root;
if ((fp = fopen(mealfile,"rb")) == NULL)
 {
 write_meal_db();
 return;
 }
mealdb_mealsperday = 0;
for ( ; ; )
 {
 if ((new_meal = malloc(sizeof(struct meal))) == NULL)
  {
  printf("Bad news.  We are out of memory...");
  abort();
  }
 if ((block = fread(new_meal,sizeof(struct meal),1,fp)) != 0)
  {
  meal_ptr->next = new_meal;
  meal_ptr = new_meal;
  if (meal_ptr->meal > mealdb_mealsperday) mealdb_mealsperday = meal_ptr->meal;
  }
 else break;
 }
fclose(fp);
}

void read_theusual_db()
{
int block;
struct meal *theusual_ptr = &theusual_root;
if ((fp = fopen(theusualfile,"rb")) == NULL)
 {
 write_theusual_db();
 return;
 }
for ( ; ; )
 {
 if ((new_theusual = malloc(sizeof(struct meal))) == NULL)
  {
  printf("Bad news.  We are out of memory...");
  abort();
  }
 if ((block = fread(new_theusual,sizeof(struct meal),1,fp)) != 0)
  {
  theusual_ptr->next = new_theusual;
  theusual_ptr = new_theusual;
  }
 else break;
 }
fclose(fp);
}

void write_meal_db()
{
int block;
struct meal *meal_ptr = &meal_root;
if ((fp = fopen(mealfile,"wb")) == NULL)
 {
 printf("Can't open meal database %s to write.\n",mealfile);
 abort();
 }
while (meal_ptr -> next != NULL)
 {
 meal_ptr = meal_ptr -> next;
 if ((block = fwrite(meal_ptr,sizeof(struct meal),1,fp)) != 1)
  {
  printf("Cannot write to the disk.  Aborting...\n");
  abort();
  }
 }
fclose(fp);
}

void write_theusual_db()
{
int block;
struct meal *theusual_ptr = &theusual_root;
if ((fp = fopen(theusualfile,"wb")) == NULL)
 {
 printf("Can't open theusual database %s to write.\n",theusualfile);
 abort();
 }
while (theusual_ptr -> next != NULL)
 {
 theusual_ptr = theusual_ptr -> next;
 if ((block = fwrite(theusual_ptr,sizeof(struct meal),1,fp)) != 1)
  {
  printf("Cannot write to the disk.  Aborting...\n");
  abort();
  }
 }
fclose(fp);
}

void write_food_db()
{
int block;
struct food *food_ptr = &food_root;
if ((fp = fopen(foodfile,"wb")) == NULL)
 {
 printf("Can't open food database %s to write.\n",foodfile);
 abort();
 }
while (food_ptr -> next != NULL)
 {
 food_ptr = food_ptr -> next;
 if ((block = fwrite(food_ptr,sizeof(struct food),1,fp)) != 1)
  {
  printf("Cannot write to the disk.  Aborting...\n");
  abort();
  }
 }
fclose(fp);
}

void write_recipe(struct food *food_ptr)
{
char buffer[300], numbuf[11], textbuf[100];
int block, c, i;
if ((fp = fopen(localFOOD,"ab")) == NULL)
 {
 printf("Can't open recipe description file %s to append.\n",localFOOD);
 abort();
 }
strcpy(buffer,"~\0");
sprintf(numbuf,"%d",food_ptr->ndb_no);
strcat(buffer,numbuf);
strcat(buffer,"~^~9999~^~\0");
strcpy(textbuf,food_ptr->name);
c = strlen(textbuf);
for (i = 1; i < c; i++) textbuf[i] = tolower(textbuf[i]);
strcat(buffer,textbuf);
strcat(buffer,"~^~\0");
strcat(buffer,food_ptr->name);
strcat(buffer,"~^~~^~~^~~^~~^\0");
sprintf(numbuf,"%d",food_ptr->refuse);
strcat(buffer,numbuf);
strcat(buffer,"^~~^^\0");
if (food_ptr->nutrient[PROCNT] > 0) sprintf(numbuf,"%1.2f",food_ptr->nutrient[PROT_KCAL] / food_ptr->nutrient[PROCNT]);
else sprintf(numbuf,"%d",0);
strcat(buffer,numbuf);
strcat(buffer,"^\0");
if (food_ptr->nutrient[FAT] > 0) sprintf(numbuf,"%1.2f",food_ptr->nutrient[FAT_KCAL] / food_ptr->nutrient[FAT]);
else sprintf(numbuf,"%d",0);
strcat(buffer,numbuf);
strcat(buffer,"^\0");
if (food_ptr->nutrient[CHOCDF] > 0) sprintf(numbuf,"%1.2f",food_ptr->nutrient[CHO_KCAL] / food_ptr->nutrient[CHOCDF]);
else sprintf(numbuf,"%d",0);
strcat(buffer,numbuf);
strcat(buffer,"\n");
c = strlen(buffer);
if ((block = fwrite(buffer,c,1,fp)) != 1)
 {
 printf("Cannot write to the disk.  Aborting...\n");
 abort();
 }
fclose(fp);

if ((fp = fopen(localNUT,"ab")) == NULL)
 {
 printf("Can't open recipe nutrient file %s to append.\n",localNUT);
 abort();
 }
for (i=0; i < NUTRIENT_COUNT - DERIVED; i++)
 {
 if (test_for_negative_zero(&food_ptr->nutrient[i])) continue;
 strcpy(buffer,"~\0");
 sprintf(numbuf,"%d",food_ptr->ndb_no);
 strcat(buffer,numbuf);
 strcat(buffer,"~^~\0");
 sprintf(numbuf,"%d",LookupNutrNo[i]);
 strcat(buffer,numbuf);
 strcat(buffer,"~^\0");
 sprintf(numbuf,"%1.3f",food_ptr->nutrient[i]);
 strcat(buffer,numbuf);
 strcat(buffer,"^0^^~4~^~~^~~^~~^^^^^^^~~^^~~\n");
 c = strlen(buffer);
 if ((block = fwrite(buffer,c,1,fp)) != 1)
  {
  printf("Cannot write to the disk.  Aborting...\n");
  abort();
  }
 }
fclose(fp);

if ((fp = fopen(localWEIGHT,"ab")) == NULL)
 {
 printf("Can't open recipe weight file %s to append.\n",localWEIGHT);
 abort();
 }
strcpy(buffer,"~\0");
sprintf(numbuf,"%d",food_ptr->ndb_no);
strcat(buffer,numbuf);
strcat(buffer,"~^1^\0");
sprintf(numbuf,"%g",food_ptr->qty);
strcat(buffer,numbuf);
strcat(buffer,"^~\0");
strcpy(textbuf,food_ptr->unit);
c = strspn(textbuf," 0123456789.");
strcat(buffer,textbuf+c);
strcat(buffer,"~^\0");
sprintf(numbuf,"%g",food_ptr->grams);
strcat(buffer,numbuf);
strcat(buffer,"^^\n");
c = strlen(buffer);
if ((block = fwrite(buffer,c,1,fp)) != 1)
 {
 printf("Cannot write to the disk.  Aborting...\n");
 abort();
 }
fclose(fp);
}

void write_serving(struct food *food_ptr)
{
char buffer[300], numbuf[11];
int block, c;

if ((fp = fopen(localWEIGHT,"ab")) == NULL)
 {
 printf("Can't open weight file %s to append.\n",localWEIGHT);
 abort();
 }
strcpy(buffer,"~\0");
sprintf(numbuf,"%d",food_ptr->ndb_no);
strcat(buffer,numbuf);
strcat(buffer,"~^1^\0");
sprintf(numbuf,"%g",food_ptr->qty);
strcat(buffer,numbuf);
strcat(buffer,"^~\0");
strcat(buffer,food_ptr->unit);
strcat(buffer,"~^\0");
sprintf(numbuf,"%g",food_ptr->grams);
strcat(buffer,numbuf);
strcat(buffer,"^^\n");
c = strlen(buffer);
if ((block = fwrite(buffer,c,1,fp)) != 1)
 {
 printf("Cannot write to the disk.  Aborting...\n");
 abort();
 }
fclose(fp);
}

void write_OPTIONS()
{
int block, i, field;
if ((fp = fopen(localOPTIONS,"wb")) == NULL)
 {
 printf("Can't open options file \"%s\" to write.\n",localOPTIONS);
 printf("Press <enter> to continue...");
 block = get_int();
 abort();
 }
fprintf(fp,"%d^%d^\n",DELOPT,options.delopt);
fprintf(fp,"%d^%d^\n",DEFANAL,options.defanal);
fprintf(fp,"%d^%d^\n",SCREEN,options.screen);
fprintf(fp,"%d^%d^\n",CUSTOM,options.custom);
fprintf(fp,"%d^%f^\n",PCPROTEIN,options.pcprotein);
fprintf(fp,"%d^%f^\n",PCCARB,options.pccarb);
fprintf(fp,"%d^%f^\n",PCSATFAT,options.pcsatfat);
fprintf(fp,"%d^%d^\n",NEXT_RECIPE,options.next_recipe);
fprintf(fp,"%d^%d^\n",MEALSPERDAY,options.mealsperday);
fprintf(fp,"%d^%d^\n",GRAMS,options.grams);
fprintf(fp,"%d^%d^\n",AUTOCAL,options.autocal);
fprintf(fp,"%d^%f^\n",PROTCALPERGM,options.protcalpergm);
fprintf(fp,"%d^%f^\n",CARBCALPERGM,options.carbcalpergm);
fprintf(fp,"%d^%f^\n",FATCALPERGM,options.fatcalpergm);
fprintf(fp,"%d^%f^\n",FATTYACIDFACTOR,options.fattyacidfactor);
fprintf(fp,"%d^%f^\n",N6HUFA,options.n6hufa);
fprintf(fp,"%d^%f^\n",EPADHAMAX,options.epadhamax);
fprintf(fp,"%d^%d^\n",DEFANALANAL,options.defanalanal);
fprintf(fp,"%d^%d^\n",DEFANALREC,options.defanalrec);
for (i = 1; i <= DV_COUNT; i++)
 {
 switch (DVMap[i])
  {
  case CHO_NONFIB : field = OPT_CHO_NONFIB;
                    break;
  case LA         : field = OPT_LA;
                    break;
  case AA         : field = OPT_AA;
                    break;
  case ALA        : field = OPT_ALA;
                    break;
  case EPA        : field = OPT_EPA;
                    break;
  case DHA        : field = OPT_DHA;
                    break;
  case OMEGA6     : field = OPT_OMEGA6;
                    break;
  case OMEGA3     : field = OPT_OMEGA3;
                    break;
  case VITE       : field = OPT_VITE;
                    break;
  default         : field = LookupNutrNo[DVMap[i]];
                    break;
  }
 fprintf(fp,"%d^%f^%d\n",field,options.abnuts[DVMap[i]],options.locknuts[DVMap[i]]);
 }
fclose(fp);
}

void read_options_db(int dontwrite)
{
int block, need_to_find_next_recipe = 0;
struct food *food_ptr = &food_root;
initialize_options();
if ((fp = fopen(optionsfile,"rb")) == NULL) 
 {
 write_OPTIONS();
 if (! dontwrite) need_to_find_next_recipe = 1;
 }
if ((fp = fopen(optionsfile,"rb")) == NULL) 
 {
 printf("Can't open options database \"%s\" to read.\n",optionsfile);
 printf("Press <enter> to continue...");
 block = get_int();
 abort();
 }
fread(&options,sizeof(struct opt),1,fp);
fclose(fp);
remove(optionsfile);
options.temp_meal_root = &meal_root;
auto_cal(&options.abnuts[ENERC_KCAL],0);
delete_meals(options.delopt);
if (! dontwrite) write_meal_db();
if (need_to_find_next_recipe) while (food_ptr->next != NULL)
 {
 food_ptr = food_ptr->next;
 if (food_ptr->ndb_no >= options.next_recipe) options.next_recipe = food_ptr->ndb_no + 1;
 }
}

void read_OPTIONS(int dontwrite)
{
int block, need_to_find_next_recipe = 0, field;
char buffer[101], valbuf1[51], valbuf2[51];
struct food *food_ptr = &food_root;
initialize_options();
if ((fp = fopen(localOPTIONS,"rb")) == NULL) 
 {
 write_OPTIONS();
 if (! dontwrite) need_to_find_next_recipe = 1;
 }
if ((fp = fopen(localOPTIONS,"rb")) == NULL) 
 {
 printf("Can't open options file \"%s\" to read.\n",localOPTIONS);
 printf("Press <enter> to continue...");
 block = get_int();
 abort();
 }
while (fgets(buffer,100,fp) != NULL)                   
 {
 field = atoi(strtok(buffer,"^"));
 strcpy(valbuf1,strtok(NULL,"^"));
 strcpy(valbuf2,strtok(NULL,"^"));
 switch (field)
  {
  case DELOPT         : options.delopt = atoi(valbuf1);
                        break;
  case DEFANAL        : options.defanal = atoi(valbuf1);
                        break;
  case SCREEN         : options.screen = atoi(valbuf1);
                        break;
  case CUSTOM         : options.custom = atoi(valbuf1);
                        break;
  case PCPROTEIN      : options.pcprotein = atof(valbuf1);
                        break;
  case PCCARB         : options.pccarb = atof(valbuf1);
                        break;
  case PCSATFAT       : options.pcsatfat = atof(valbuf1);
                        break;
  case NEXT_RECIPE    : options.next_recipe = atoi(valbuf1);
                        break;
  case MEALSPERDAY    : options.mealsperday = atoi(valbuf1);
                        break;
  case GRAMS          : options.grams = atoi(valbuf1);
                        break;
  case AUTOCAL        : options.autocal = atoi(valbuf1);
                        break;
  case PROTCALPERGM   : options.protcalpergm = atof(valbuf1);
                        break;
  case CARBCALPERGM   : options.carbcalpergm = atof(valbuf1);
                        break;
  case FATCALPERGM    : options.fatcalpergm = atof(valbuf1);
                        break;
  case FATTYACIDFACTOR : options.fattyacidfactor = atof(valbuf1);
                        break;
  case N6HUFA          : options.n6hufa = atof(valbuf1);
                        break;
  case EPADHAMAX       : options.epadhamax = atof(valbuf1);
                        break;
  case DEFANALANAL     : options.defanalanal = atoi(valbuf1);
                        break;
  case DEFANALREC      : options.defanalrec = atoi(valbuf1);
                        break;
  case OPT_CHO_NONFIB : options.abnuts[CHO_NONFIB] = atof(valbuf1);
                        options.locknuts[CHO_NONFIB] = atoi(valbuf2);
                        break;
  case OPT_LA         : options.abnuts[LA] = atof(valbuf1);
                        options.locknuts[LA] = atoi(valbuf2);
                        break;
  case OPT_AA         : options.abnuts[AA] = atof(valbuf1);
                        options.locknuts[AA] = atoi(valbuf2);
                        break;
  case OPT_ALA        : options.abnuts[ALA] = atof(valbuf1);
                        options.locknuts[ALA] = atoi(valbuf2); 
                        break;
  case OPT_EPA        : options.abnuts[EPA] = atof(valbuf1);
                        options.locknuts[EPA] = atoi(valbuf2);
                        break;
  case OPT_DHA        : options.abnuts[DHA] = atof(valbuf1);
                        options.locknuts[DHA] = atoi(valbuf2);
                        break;
  case OPT_OMEGA6     : options.abnuts[OMEGA6] = atof(valbuf1);
                        options.locknuts[OMEGA6] = atoi(valbuf2);
                        break;
  case OPT_OMEGA3     : options.abnuts[OMEGA3] = atof(valbuf1);
                        options.locknuts[OMEGA3] = atoi(valbuf2);
                        break;
  case OPT_VITE       : options.abnuts[VITE] = atof(valbuf1);
                        options.locknuts[VITE] = atoi(valbuf2);
                        break;
  default             : options.abnuts[LookupNut[field]] = atof(valbuf1); 
                        options.locknuts[LookupNut[field]] = atoi(valbuf2); 
                        break;
  }
 }
fclose(fp);
options.temp_meal_root = &meal_root;
auto_cal(&options.abnuts[ENERC_KCAL],0);
delete_meals(options.delopt);
if (! dontwrite) write_meal_db();
if (need_to_find_next_recipe) while (food_ptr->next != NULL)
 {
 food_ptr = food_ptr->next;
 if (food_ptr->ndb_no >= options.next_recipe) options.next_recipe = food_ptr->ndb_no + 1;
 }
}

void make_filenames(char *sub)
{
strcpy(subuser,sub);
#ifdef DOS
 sprintf(nutdir,"%s","NUTDB");
 mkdir (nutdir, 0700 );
 sprintf(nutdirsubuser,"%s/%s","NUTDB",subuser);
 mkdir (nutdirsubuser, 0700 );
 sprintf(USDAjoined,"%s/%s","NUTSR21",USDAjoined1);
 sprintf(globalFOOD,"%s/%s","NUTSR21",globalFOOD1);
 sprintf(globalNUT,"%s/%s","NUTSR21",globalNUT1);
 sprintf(globalWEIGHT,"%s/%s","NUTSR21",globalWEIGHT1);
 sprintf(weightlib,"%s/%s","NUTSR21",weightlib1);
 sprintf(localFOOD,"%s/%s/%s","NUTDB",subuser,localFOOD1);
 sprintf(localNUT,"%s/%s/%s","NUTDB",subuser,localNUT1);
 sprintf(localWEIGHT,"%s/%s/%s","NUTDB",subuser,localWEIGHT1);
 sprintf(foodfile,"%s/%s/%s","NUTDB",subuser,foodfile1);
 sprintf(mealfile,"%s/%s/%s","NUTDB",subuser,mealfile1);
 sprintf(mealexpfile,"%s/%s/%s","NUTDB",subuser,mealexpfile1);
 sprintf(theusualfile,"%s/%s/%s","NUTDB",subuser,theusualfile1);
 sprintf(optionsfile,"%s/%s/%s","NUTDB",subuser,optionsfile1);
 sprintf(localOPTIONS,"%s/%s/%s","NUTDB",subuser,localOPTIONS1);
 sprintf(versionfile,"%s/%s/%s","NUTDB",subuser,versionfile1);
#else
sprintf(nutdir,"%s/%s",getenv("HOME"),nutdir1);
mkdir (nutdir, 0700 );
sprintf(nutdirsubuser,"%s/%s/%s",getenv("HOME"),nutdir1,subuser);
mkdir (nutdirsubuser, 0700 );
sprintf(USDAjoined,"%s/%s",FOODDIR,USDAjoined1);
sprintf(globalFOOD,"%s/%s",FOODDIR,globalFOOD1);
sprintf(globalNUT,"%s/%s",FOODDIR,globalNUT1);
sprintf(globalWEIGHT,"%s/%s",FOODDIR,globalWEIGHT1);
sprintf(weightlib,"%s/%s",FOODDIR,weightlib1);
sprintf(localFOOD,"%s/%s/%s/%s",getenv("HOME"),nutdir1,subuser,localFOOD1);
sprintf(localNUT,"%s/%s/%s/%s",getenv("HOME"),nutdir1,subuser,localNUT1);
sprintf(localWEIGHT,"%s/%s/%s/%s",getenv("HOME"),nutdir1,subuser,localWEIGHT1);
sprintf(foodfile,"%s/%s/%s/%s",getenv("HOME"),nutdir1,subuser,foodfile1);
sprintf(mealfile,"%s/%s/%s/%s",getenv("HOME"),nutdir1,subuser,mealfile1);
sprintf(mealexpfile,"%s/%s/%s/%s",getenv("HOME"),nutdir1,subuser,mealexpfile1);
sprintf(theusualfile,"%s/%s/%s/%s",getenv("HOME"),nutdir1,subuser,theusualfile1);
sprintf(optionsfile,"%s/%s/%s/%s",getenv("HOME"),nutdir1,subuser,optionsfile1);
sprintf(localOPTIONS,"%s/%s/%s/%s",getenv("HOME"),nutdir1,subuser,localOPTIONS1);
sprintf(versionfile,"%s/%s/%s/%s",getenv("HOME"),nutdir1,subuser,versionfile1);
sprintf(oldversionfile,"%s/%s/%s/%s",getenv("HOME"),nutdir1,subuser,oldversionfile1);
check_version_file();
#endif
}

void check_version_file()
{
char release_string[9];
int majrelease, minrelease, majreleasedot, minreleasedot;
if ((fp = fopen(oldversionfile,"rb")) == NULL) return;
fread(&release_string,8,1,fp);
fclose(fp);
majreleasedot = atoi(strtok(release_string,"."));
minreleasedot = atoi(strtok(NULL,"."));
remove(oldversionfile);
if ((fp = fopen(versionfile,"rb")) == NULL)
 {
 if ((fp = fopen(versionfile,"wb")) == NULL) return;
 fprintf(fp,"%d.%d",majreleasedot,minreleasedot);
 fclose(fp);
 return;
 }
fread(&release_string,8,1,fp);
fclose(fp);
majrelease = atoi(strtok(release_string,"."));
minrelease = atoi(strtok(NULL,"."));
if (majreleasedot < majrelease) return;
if (majreleasedot == majrelease && minreleasedot <= minrelease) return;
if ((fp = fopen(versionfile,"wb")) == NULL) return;
fprintf(fp,"%d.%d",majreleasedot,minreleasedot);
fclose(fp);
}

int version(int level)
{
char release_string[128];
int majrelease;
int minrelease;
if ((fp = fopen(versionfile,"rb")) == NULL) return 0;
fread(&release_string,8,1,fp);
fclose(fp);
if (strstr(release_string,".") == NULL) return 0;
majrelease = atoi(strtok(release_string,"."));
minrelease = atoi(strtok(NULL,"."));
return level > 0 ? minrelease : majrelease;
}

void write_version()
{
char release_string[]=VERSIONQ;
int block;
if ((fp = fopen(versionfile,"wb")) == NULL)
 {
 printf("Can't write version number to disk in \"%s\".\n",versionfile);
 printf("Press <enter> to continue...");
 block = get_int();
 abort();
 }
if ((block = fwrite(release_string,strlen(release_string)+1,1,fp)) != 1)
 {
 printf("Cannot write to the disk.  Aborting...\n");
 abort();
 }
fclose(fp);
}
