/************************************************************************/
/* TaxSolve_usa_fed1040_2005.c - OpenTaxSolver for USFed1040 v3.00	*/
/* Copyright (C) 2004, 2005 - Aston Roberts				*/
/* 									*/
/* Tax Solver for US Fedral 1040 Income Tax return for 2005 Tax Year.	*/
/* 									*/
/* OTS Project Home Page and Updates:  					*/
/*		http://opentaxsolver.sourceforge.com/			*/
/* 									*/
/* Compile:   cc taxsolve_US_1040_2005 -o taxsolve_US_1040_2005         */
/* Run:       ./taxsolve_US_1040_2005  Fed1040_2005.dat                 */
/* 									*/
/* GNU Public License - GPL:						*/
/* 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., 59 Temple Place, Suite 330, Boston, MA		*/
/* 02111-1307 USA							*/
/* 									*/
/* Aston Roberts 1-3-2006	aston_roberts@yahoo.com			*/
/* Updates by:  Lincoln Baxter  lab@lincolnbaxter.com	2004		*/
/*    1-25-05   E. Ferguson						*/ 
/*    2-14-05   BWB							*/
/* 		et. al.							*/
/* Updated 2-10-06	Robert Heller					*/
/************************************************************************/

#include <stdio.h>
#include <time.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include "taxsolve_routines.c"

#define SINGLE 		        1
#define MARRIED_FILLING_JOINTLY 2
#define MARRIED_FILLING_SEPARAT 3
#define HEAD_OF_HOUSEHOLD       4
#define WIDOW		        5
#define Yes 1
#define No  0

float thisversion=3.04;
float SchedA[MAX_LINES], SchedD[MAX_LINES];
float L9b=0.0;	/* Qualified dividends. */
int Do_SchedD=No, Do_QDCGTW=No, Do_SDTW=No;

int status;

float TaxRateFormula( float x, int status )
{			/* Values taken from page 82. */
  float brkpt[4][7]={
                     { 0.0,  7300.0, 29700.0,  71950.0, 150150.0, 326450.0, 9e9 },      /* Single */
                     { 0.0, 14600.0, 59400.0, 119950.0, 182800.0, 326450.0, 9e9 },      /* Married, filing jointly. */
                     { 0.0,  7300.0, 29700.0,  59975.0,  91400.0, 163225.0, 9e9 },      /* Married, filing separate. */
                     { 0.0, 10450.0, 39800.0, 102800.0, 166450.0, 326450.0, 9e9 },      /* Head of Household. */
                    };
  float	txrt[4][7] ={
		     {       0.1,    0.15,     0.25,    0.28,     0.33,  0.35 },	/* Single */
		     {       0.1,    0.15,     0.25,    0.28,     0.33,  0.35 },	/* Married, filing jointly. */
		     {       0.1,    0.15,     0.25,    0.28,     0.33,  0.35 },	/* Married, filing separate. */
		     {       0.1,    0.15,     0.25,    0.28,     0.33,  0.35 },	/* Head of Household. */
		    },
	sum=0.0;
  int   bracket=0;
  
  if (status==WIDOW) status = MARRIED_FILLING_JOINTLY;  /* Handle case of widow(er). */
  status = status - 1;  /* Arrays start at zero; not one. */
  while (brkpt[status][bracket+1] < x)
   {
    sum = sum + (brkpt[status][bracket+1] - brkpt[status][bracket]) * txrt[status][bracket];
    bracket = bracket + 1;
   }

  return (x - brkpt[status][bracket]) * txrt[status][bracket] + sum;
}


float TaxRateFunction( float income, int status )     /* Emulates table lookup or function appropriately. */
{
 float x, dx, tx;
 int k;

 if (income < 100000.0)	/* Quantize to match tax-table exactly. */
  {
   if (income < 25.0) x = 5.0; else
   if (income < 3000.0) x = 25.0; else x = 50.0;
   dx = 0.5 * x;
   k = income / x;
   x = x * (float)k + dx;
   tx = (int)(TaxRateFormula( x, status ) + 0.5);
  }
 else
  tx = TaxRateFormula( income, status );
 return tx;
}


void showschedA( int linenum )
{ if (SchedA[linenum] > 0.0) fprintf(outfile," A%d = %6.2f\n", linenum, SchedA[linenum] ); }


/*-----------------------------------------------------------------*/
/* Qualified Dividends and Capital Gain Tax Worksheet for Line 43. */
/*  From page 34 of instructions.				   */
/*-----------------------------------------------------------------*/
void capgains_qualdividends_worksheets( int status, float L9b )
{
 float ws[50];
 int j, skipto16=0;

 for (j=0; j<50; j++) ws[j] = 0.0;

 ws[1] = L[43];
 ws[2] = L9b;
 if (Do_SchedD)
  ws[3] = NotLessThanZero(smallerof( SchedD[15], SchedD[16] ));
 else
  ws[3] = L[13];
 ws[4] = ws[2] + ws[3];
 ws[5] = 0.0;  /* Investment interest expense, form 4952, usually 0. */
 ws[6] = NotLessThanZero( ws[4] - ws[5] );  
 ws[7] = NotLessThanZero( ws[1] - ws[6] );
 switch (status)
  {
   case SINGLE: case MARRIED_FILLING_SEPARAT: ws[8] = smallerof( ws[1], 29700.0 ); break;
   case MARRIED_FILLING_JOINTLY: case WIDOW:  ws[8] = smallerof( ws[1], 59400.0 ); break;
   case HEAD_OF_HOUSEHOLD: 		      ws[8] = smallerof( ws[1], 39800.0 ); break;
  }
 if (ws[7] < ws[8])
  {
   ws[9] = ws[7];
   ws[10] = ws[8] - ws[9];
   ws[11] = 0.05 * ws[10];
   if (ws[6]==ws[10]) skipto16 = Yes;
   else ws[12] = smallerof( ws[1], ws[6] );
  }
 else ws[12] = smallerof( ws[1], ws[6] );

 if (!skipto16)
  {
   ws[13] = ws[10];
   ws[14] = ws[12] - ws[13];
   ws[15] = 0.15 * ws[14];
  }
 ws[16] = TaxRateFunction( ws[7], status );
 ws[17] = ws[11] + ws[15] + ws[16];
 ws[18] = TaxRateFunction( ws[1], status );
 ws[19] = smallerof( ws[17], ws[18] );
 L[44] = ws[19];
}


float AlternativeMinimumTax( int status, int itemized )
{ /* Worksheet calculations, page 39. */
 int i;
 float WS[100], AMT=0.0;	/* AMT worksheet data variables. */

 for (i=0; i<100; i++) WS[i] = 0.0;
 if (itemized)
  {
   WS[1] = L[41];
   WS[2] = smallerof( SchedA[4], 0.025 * L[38] );
   WS[3] = SchedA[9] + SchedA[26];
   WS[4] = WS[1] + WS[2] + WS[3];
  }
 else WS[4] = L[38];
 WS[5] = L[10] + L[21];
 WS[6] = WS[4] - WS[5];
 WS[7] = 0.0;	/* Amount from Form 8914, usually zero. */
 WS[8] = WS[6] - WS[7];
 switch (status) 
  { case SINGLE: case HEAD_OF_HOUSEHOLD:      WS[9] = 40250.0; break;
    case MARRIED_FILLING_JOINTLY: case WIDOW: WS[9] = 58000.0; break;
    case MARRIED_FILLING_SEPARAT:             WS[9] =  29000.0; break;
  }
 if (WS[8] <= WS[9]) return 0.0;		/* You do not owe AMT. */
 else WS[10] = WS[8] - WS[9];
 switch (status) 
  { case SINGLE: case HEAD_OF_HOUSEHOLD:      WS[11] = 112500.0; break;
    case MARRIED_FILLING_JOINTLY: case WIDOW: WS[11] = 150000.0; break;
    case MARRIED_FILLING_SEPARAT:             WS[11] =  75000.0; break;
  }
 if (WS[8] > WS[11]) 
  { WS[12] = WS[8] - WS[11]; 
    WS[13] = 0.25 * WS[12];  if (WS[13] > WS[9]) WS[13] = WS[9];
    WS[14] = WS[10] + WS[13];
  }
 else WS[14] = WS[10];
 if (((status!=MARRIED_FILLING_SEPARAT) && (WS[14]>175000.0)) || ((status==MARRIED_FILLING_SEPARAT) && (WS[14]>87500.0)))
  { printf("You may owe AMT. Fill out form 6251.\nEnter your AMT tax ? "); scanf("%f",&AMT); }
 else
  {
   WS[15] = 0.26 * WS[14];
   WS[16] = L[44] - L[47];
   if (WS[15] > WS[16])
    { printf("You may owe AMT. Fill out form 6251.\nEnter your AMT tax ? "); scanf("%f",&AMT); }
   else AMT = 0.0;
  }
 return AMT;
}




struct FedReturnData
 {
  float fedline[MAX_LINES], schedD[MAX_LINES];
  int Exception, Itemized;
 } LastYearsReturn;


void ImportFederalReturnData( char *fedlogfile, struct FedReturnData *fed_data )
{
 FILE *infile;
 char fline[1000], tmpstr[1000], word[1000];
 int linenum;

 for (linenum=0; linenum<MAX_LINES; linenum++) 
  { fed_data->fedline[linenum] = 0.0;  fed_data->schedD[linenum] = 0.0; }
 infile = fopen(fedlogfile, "r");
 if (infile==0) {printf("Error: Could not open federal return '%s'\n", fedlogfile);}
 fed_data->Itemized = 1; /* Set initial default values. */
 read_line(infile,fline);  linenum = 0;
 while (!feof(infile))
  {
   if (strstr(fline,"Use standard deduction.")!=0) fed_data->Itemized = 0;
   next_word(fline, tmpstr, word, " 	=");
   if ((strstr(word,"L")==word) && (strstr(fline," = ")!=0))
    {
     if (sscanf(&word[1],"%d",&linenum)!=1) printf("Error: Reading fed line number '%s%s'\n",word,fline);
     next_word(fline, tmpstr, word, " 	=");
     if (sscanf(word,"%f", &fed_data->fedline[linenum])!=1) 
	printf("Error: Reading fed line %d '%s%s'\n",linenum,word,fline);
     if (verbose) printf("FedLin[%d] = %2.2f\n", linenum, fed_data->fedline[linenum]);
    }
   if ((strstr(word,"D")==word) && (strstr(fline," = ")!=0))
    {
     if (sscanf(&word[1],"%d",&linenum)!=1) printf("Error: Reading fed line number '%s%s'\n",word,fline);
     next_word(fline, tmpstr, word, " 	=");
     if (sscanf(word,"%f", &fed_data->schedD[linenum])!=1) 
	printf("Error: Reading fed schedD %d '%s%s'\n",linenum,word,fline);
     if (verbose) printf("FedLin[%d] = %2.2f\n", linenum, fed_data->schedD[linenum]);
    }
   read_line(infile,fline);
  }
 fclose(infile);
}


void CapitalLossCarryOverWorksheet( char *fedlogfile, struct FedReturnData *LastYearsReturn )
{ /* From page D-6. */
 float ws[20];
 int k;

 ImportFederalReturnData( fedlogfile, LastYearsReturn );
 for (k=0; k<20; k++) ws[k] = 0.0;
 ws[1] = LastYearsReturn->fedline[40];
 if (LastYearsReturn->schedD[21] < 0.0)
  ws[2] = -LastYearsReturn->schedD[21];
 ws[3] = NotLessThanZero( ws[1] + ws[2] );	/* "Combine" lines 1 and 2. */
 ws[4] = smallerof( ws[2], ws[3] );
 if (LastYearsReturn->schedD[7] < 0.0)
  {
   ws[5] = -LastYearsReturn->schedD[7];
   if (LastYearsReturn->schedD[15] > 0.0)  ws[6] = LastYearsReturn->schedD[15];
   ws[7] = ws[4] + ws[6]; 
  }
 else ws[5] = 0.0;
 ws[8] = NotLessThanZero( ws[5] - ws[7] );
 if (ws[8] > 0.0) SchedD[6] = ws[8];
 if (LastYearsReturn->schedD[15] < 0.0)
  ws[9] = -LastYearsReturn->schedD[15];
 if (LastYearsReturn->schedD[7] > 0.0) ws[10] = LastYearsReturn->schedD[7];
 ws[11] = NotLessThanZero( ws[4] - ws[5] );
 ws[12] = ws[10] + ws[11];
 ws[13] = NotLessThanZero( ws[9] - ws[12] );
 if (ws[13] > 0.0) SchedD[14] = ws[13];
}


/****************************************************************/
/* Get_Cap_Gains - Get and calculate gains.			*/
/* Like "get_params", but must get transaction dates.		*/
/* Expect entries in double pairs. 				*/
/*   buy_amnt   date 						*/
/*   sell_amnt  date 						*/
/*								*/
/****************************************************************/
void get_cap_gains( char *emssg	)
{
 char word[1024], *LastYearsOutFile=0;
 int toggle=0, date1=0, date2, doline22=0;
 float amnt1, amnt2;
 float stcg=0.0, ltcg=0.0;      /* Variables for short and long term gains. */

 GetLine( "D4", &SchedD[4] );       /* Short term gain from 6252 and short-term gain or loss from Forms 4684, 6781, 8824. */
 GetLine( "D5", &SchedD[5] );       /* Net short-term gain or loss from partnerships, S corps, estates, trusts from K-1. */

 get_parameter( infile, 's', word, "D6" );	/* Carryover short-term loss from 2003.  Or, LastYear's Return Output File-name. */
 get_word(infile,word);
 if (strcmp(word,";")!=0)
  {
   if (sscanf(word,"%f",&SchedD[6])!=1) LastYearsOutFile = strdup(word);
   do get_word(infile,word); while (strcmp(word,";")!=0);
  }

 GetLine( "D13", &SchedD[13] );	    /* Cap Gains Distributions - 1099-DIV col. 2a. */

 GetLine( "D14", &SchedD[14] );     /* Carryover long-term loss from 2003. Or, leave blank if last year's file entered in line 6. */

 if (LastYearsOutFile!=0)
  CapitalLossCarryOverWorksheet( LastYearsOutFile, &LastYearsReturn );

 if (SchedD[6]>0.0) {fprintf(outfile,"Warning: D6 Carryover Loss must be NEGATIVE.\n"); SchedD[6] = -SchedD[6];}
 if (SchedD[14]>0.0) {fprintf(outfile,"Warning: D14 Carryover Loss must be NEGATIVE.\n"); SchedD[14] = -SchedD[14];}

 if ((SchedD[13]!=0.0) || (SchedD[6]!=0.0) || (SchedD[14]!=0.0))
  {fprintf(outfile," Cap Gains/Losses Schedule-D\n"); Do_SchedD = Yes;}

 get_parameter( infile, 's', word, "Cap-Gains/Losses" );     /* Capital gains. */
 get_word(infile,word);
 while (word[0]!=';')
 {
  if (feof(infile)) {printf("ERROR: Unexpected EOF on '%s'\n",emssg); exit(1);}
  if (!Do_SchedD) {fprintf(outfile," Cap Gains Schedule-D\n"); Do_SchedD = Yes;}

  switch (toggle)
   {
    case 0:	toggle++;
	if (sscanf(word,"%f",&amnt1)!=1) {printf("ERROR: Bad float '%s', reading %s.\n", word, emssg); exit(1); }
	if (amnt1>0.0) amnt1 = -amnt1;  /* Buy amounts must be negative. (It is a cost.) */
	break;
    case 1:	toggle++;
	date1 = get_date( word, emssg );
	break;
    case 2:	toggle++;
	if (sscanf(word,"%f",&amnt2)!=1) {printf("ERROR: Bad float '%s', reading %s.\n", word, emssg); exit(1); }
	break;
    case 3:	toggle = 0;
	date2 = get_date( word, emssg );
	if ((date2-date1)<0) {printf("ERROR: Buy-date after sell-date.\n");  exit(1);}
	if ((date2-date1)>365) 
	 {
	  SchedD[10] = SchedD[10] + amnt2;
	  ltcg = ltcg + amnt1 + amnt2;
	 }
	else 
	 {
	  SchedD[3] = SchedD[3] + amnt2;
	  stcg = stcg + amnt1 + amnt2;
	 }

        if ((date2-date1)>365)
	 fprintf(outfile,"	 Long %6.2f\n", amnt1 + amnt2); 
	else 
	 fprintf(outfile,"	 Short %6.2f\n", amnt1 + amnt2);
	break;
   } 
  get_word(infile,word);
 }

 if (toggle!=0) {printf("ERROR: Imbalanced cap-gains entry (toggle=%d).\n", toggle);  exit(1); }

 if (Do_SchedD)
  { /*Sched-D*/
   Do_QDCGTW = Yes;	/* Tentatively set to do: Qualified Dividends and Captial Gain tax Worksheet. */
   fprintf(outfile,"	Total Short-term Gains = %6.2f\n	Total Long-term Gains = %6.2f\n", stcg, ltcg);
   fprintf(outfile," D3 = %6.2f\n", SchedD[3] );
   fprintf(outfile," D4 = %6.2f\n", SchedD[4] );
   fprintf(outfile," D5 = %6.2f\n", SchedD[5] );
   fprintf(outfile," D6 = %6.2f\n", SchedD[6] );

   stcg = stcg + SchedD[6];
   SchedD[7] = stcg;
   fprintf(outfile," D7 = %6.2f		Net short-term capital gain or loss\n", SchedD[7] );
   fprintf(outfile," D10 = %6.2f\n", SchedD[10] );
   fprintf(outfile," D13 = %6.2f\n", SchedD[13] );
   fprintf(outfile," D14 = %6.2f\n", SchedD[14] );

   SchedD[15] = ltcg + SchedD[13] + SchedD[14];
   fprintf(outfile," D15 = %6.2f		Net long-term capital gain or loss\n", SchedD[15] );

   /* Part ||| */
   SchedD[16] = SchedD[7] + SchedD[15];
   fprintf(outfile," D16 = %6.2f\n", SchedD[16]);
   if (SchedD[16] >= 0.0) 
    { /*gain*/
     L[13] = SchedD[16];
     if ((SchedD[15]>0.0) && (SchedD[16]>0.0))
      { /* Lines 18-21 */
	float wsd[50];

	fprintf(outfile," D17 = yes\n");

	/* '28% Rate Gain Worksheet' on instructions page D-7. */
	wsd[1] = 0.0;	/* Gain or losses from "Collectibles" only.  Usually zero. */
	wsd[2] = 0.0;	/* Any 1202 exclusions, usually 0.0. */
	wsd[3] = 0.0;	/* Any collectibles on forms 4684, 6245, 6781, 8824. Usually no. */
	wsd[4] = 0.0;	/* Any collectibles 1099-Div box 2d, 2439 box 1d, or K-1's. Usually no. */
	wsd[5] = SchedD[14];
	if (SchedD[7]<0.0) wsd[6] = SchedD[7]; else wsd[6] = 0.0;
	wsd[7] = NotLessThanZero( wsd[1] + wsd[2] + wsd[3] + wsd[4] + wsd[5] + wsd[6] );
	SchedD[18] = wsd[7];
	fprintf(outfile," D18 = %6.2f\n", SchedD[18]);

	/* 'Unrecaptured Section 1250 Gain Worksheet' on page D7, usually 0. */
	fprintf(outfile," D19 = %6.2f\n", SchedD[19]);

        if ((SchedD[18]==0.0) && (SchedD[19]==0.0))
	 {
	  fprintf(outfile," D20 = yes\n");
	  // printf("Complete 'Qualified Dividends and Captial Gain tax Worksheet', instructions page 34.\n");
	  Do_QDCGTW = Yes;
	 }
	else
	 {
	  fprintf(outfile," D20 = no\n");
	  // printf("Complete 'Schedule D Tax Worksheet', instructions page 9.\n");
	  Do_SDTW = Yes;
	  Do_QDCGTW = No;
	 }
       doline22 = 0;
      }
     else 
      {
       printf(" D17 = no\n");
       doline22 = Yes;
      }
    }   
   else
    { /*loss*/	/* Schedule-D line 21. Skip here from line 16 if a loss. */
     float maxloss;

     if (status==MARRIED_FILLING_SEPARAT) maxloss = -1500.0; else maxloss = -3000.0;
     if (SchedD[16] < maxloss) SchedD[21] = maxloss; else SchedD[21] = SchedD[16];
     fprintf(outfile," D21 = %6.2f\n", SchedD[21]);
     L[13] = SchedD[21];
     doline22 = Yes;
    }

   if (doline22)
    {
     if (L9b>0.0)
      {
       fprintf(outfile," D22 = yes\n");
       // printf("Complete 'Qualified Dividends and Captial Gain tax Worksheet', instructions page 34.\n");
       Do_QDCGTW = Yes;	
      }
     else
      fprintf(outfile," D22 = no\n");
    }

  } /*Sched-D*/
}


/*----------------------------------------------*/
/* 'Schedule D Tax Worksheet', page D9.		*/
/*----------------------------------------------*/
void sched_D_tax_worksheet( int status, float L9b )
{
 float ws[100];
 int k;

 for (k=0; k<100; k++) ws[k] = 0.0;

 ws[1] = L[43];
 ws[2] = L9b;
 ws[3] = 0.0;	/* Form 4952, line 4g. Usually 0.0. */
 ws[4] = 0.0;	/* Form 4952, line 4e. Usually 0.0. */
 ws[5] = NotLessThanZero( ws[3] - ws[4] );
 ws[6] = NotLessThanZero( ws[2] - ws[5] );
 ws[7] = smallerof( SchedD[15], SchedD[16] );
 ws[8] = smallerof( ws[3], ws[4] );
 ws[9] = NotLessThanZero( ws[7] - ws[8] );
 ws[10] = ws[6] + ws[9];
 ws[11] = SchedD[18] + SchedD[19];
 ws[12] = smallerof( ws[9], ws[11] );
 ws[13] = ws[10] - ws[12];
 ws[14] = NotLessThanZero( ws[1] - ws[13] );
 fprintf(outfile,"  Sched-D tax Worksheet line 13 = %6.2f\n", ws[13]);
 fprintf(outfile,"  Sched-D tax Worksheet line 14 = %6.2f\n", ws[14]);
 switch (status) 
  { case SINGLE: case MARRIED_FILLING_SEPARAT: ws[15] = smallerof( ws[1], 29700.0 ); break;
    case MARRIED_FILLING_JOINTLY: case WIDOW:  ws[15] = smallerof( ws[1], 59400.0 ); break;
    case HEAD_OF_HOUSEHOLD:      	       ws[15] = smallerof( ws[1], 39800.0 ); break;
  }
 ws[16] = smallerof( ws[14], ws[15] );
 ws[17] = NotLessThanZero( ws[1] - ws[10] );
 ws[18] = largerof( ws[16], ws[17] );
 ws[19] = ws[15] - ws[16];
 ws[20] = 0.05 * ws[19];
 if (ws[1] != ws[15])
  {
   ws[21] = smallerof( ws[1], ws[13] );
   ws[22] = ws[19];
   ws[23] = NotLessThanZero( ws[21] - ws[22] );
   ws[24] = 0.15 * ws[23];
   if (SchedD[19]>0.0)
    {
     ws[25] = smallerof( ws[9], SchedD[19] );
     ws[26] = ws[10] + ws[18];
     ws[27] = ws[1];
     ws[28] = NotLessThanZero( ws[26] - ws[27] );
     ws[29] = NotLessThanZero( ws[25] - ws[28] );
     ws[30] = 0.25 * ws[29];
    }
   if (SchedD[18]>0.0)
    {
     ws[31] = ws[18] + ws[19] + ws[23] + ws[29];
     ws[32] = ws[1] - ws[31];
     ws[33] = 0.28 * ws[32];
    }
  }
 ws[34] = TaxRateFunction( ws[18], status );
 ws[35] = ws[20] + ws[24] + ws[30] + ws[33] + ws[34];
 ws[36] = TaxRateFunction( ws[1], status );
 ws[37] = smallerof( ws[35], ws[36] );
 L[44] = ws[37];
}



/*----------------------------------------------------------------------------*/

int main( int argc, char *argv[] )
{
 int i, j, k, itemize;
 char word[2000], outfname[1000];
 time_t now;

 /* Decode any command-line arguments. */
 printf("US 1040 2005 - v%3.2f\n", thisversion);
 i = 1;  k=1;
 while (i < argc)
 {
  if (strcmp(argv[i],"-verbose")==0)  { verbose = Yes; }
  else
  if (k==1)
   {
    infile = fopen(argv[i],"r");
    if (infile==0) {printf("ERROR: Parameter file '%s' could not be opened.\n", argv[i]); exit(1);}
    k = 2;
    /* Base name of output file on input file. */
    strcpy(outfname,argv[i]);
    j = strlen(outfname)-1;
    while ((j>=0) && (outfname[j]!='.')) j--;
    if (j<0) strcat(outfname,".out"); else strcpy(&(outfname[j]),".out");
    outfile = fopen(outfname,"w");
    if (outfile==0) {printf("ERROR: Output file '%s' could not be opened.\n", outfname); exit(1);}
    printf("Writing results to file:  %s\n", outfname);
   }
  else
   {printf("Unknown command-line parameter '%s'\n", argv[i]); exit(1);}
  i = i + 1;
 }

 if (infile==0) {printf("Error: No input file on command line.\n"); exit(1);}

 /* Pre-initialize all lines to zeros. */
 for (i=0; i<MAX_LINES; i++) { L[i] = 0.0;  SchedA[i] = 0.0;  SchedD[i] = 0.0; }

 /* Accept parameters from input file. */
 /* Expect  US-Fed-1040 lines, something like:
	Title:  Federal 1040 1999 Return
	L7		{Wages}
	L8a		{Interest}
	L9		{Dividends}
	L13		{Capital Gains}
	L38		{Itemized deductions from Schedule A or Std Deduction}
	L58		{Witheld tax, from W-2}
 */

 /* Accept Form's "Title" line, and put out with date-stamp for your records. */
 read_line( infile, word );
 now = time(0);
 fprintf(outfile,"\n%s 	%s\n", word, ctime( &now ));

 /* get_parameter(infile, kind, x, emssg ) */
 get_parameter( infile, 's', word, "Status" );	/* Single, Married/joint, Married/sep, Head house, Widow(er) */
 get_parameter( infile, 'l', word, "Status?");
 if (strncasecmp(word,"Single",4)==0) status = SINGLE; else
 if (strncasecmp(word,"Married/Joint",13)==0) status = MARRIED_FILLING_JOINTLY; else
 if (strncasecmp(word,"Married/Sep",11)==0) status = MARRIED_FILLING_SEPARAT; else
 if (strncasecmp(word,"Head_of_House",4)==0) status = HEAD_OF_HOUSEHOLD; else
 if (strncasecmp(word,"Widow",4)==0) status = WIDOW;
 else { printf("Error: unrecognized status '%s'. Exiting.\n", word); exit(0); }
 fprintf(outfile,"Status = %s (%d)\n", word, status);

 GetLine1( "Dependents", &L[6] );
 shownum(6);
 GetLineF( "L7", &L[7] );	/* Wages, salery, tips (W-2). */
 GetLineF( "L8a", &L[8] );	/* Taxable interest. (Sched-B) */
 GetLineF( "L9", &L[9] );	/* Ordinary Dividends. (Sched-B) */
 GetLineF( "L9b", &L9b );	/* Qualified Dividends. (Sched-B) */
 GetLineF( "L10", &L[10] );	/* Taxable refunds. */
 GetLineF( "L11", &L[11] );	/* Alimony received. */
 GetLineF( "L12", &L[12] );	/* Business income/loss. */

 /* Capital gains. (Schedule-D) */
 get_cap_gains( "L13" );
 showline(13);

 GetLine( "L14", &L[14] );	/* Other gains or losses. Form 4794. */
 ShowLineNonZero(14);	

 GetLine( "L15b", &L[15] );	/* Taxable IRA distributions (pg 22). */
 ShowLineNonZero(15);

 GetLine( "L16b", &L[16] );	/* Taxable Pensions/annuities (pg 22) */
 ShowLineNonZero(16);

 GetLine( "L17", &L[17] );	/* Rent realestate, royalties, partnerships, S corp. (Sched E)*/
 ShowLineNonZero(17);

 GetLine( "L18", &L[18] );	/* Farm income/loss. (Sched F) */
 ShowLineNonZero(18);

 GetLine( "L19", &L[19] );	/* Unemployment compensation */
 ShowLineNonZero(19);

 GetLine( "L20b", &L[20] );	/* Taxable Social security benefits */
 ShowLineNonZero(20);

 GetLine( "L21", &L[21] );	/* Other income. (pg 27) */
 ShowLineNonZero(21);

 for (i=7; i<=21; i++) L[22] = L[22] + L[i];
 showline_wmsg(22,"total income");


 /* Adjusted Gross Income section. */

 GetLine( "L23", &L[23] );	/* Educator expenses (see page 26) */
 ShowLineNonZero(23);

 GetLine( "L24", &L[24] );	/* Bus. exp.: reservists, artists, ... Attach Form 2106 */
 ShowLineNonZero(24);

 GetLine( "L25", &L[25] );	/* Health savings account deduction. Attach Form 8889 */
 GetLine( "L26", &L[26] );	/* Moving expenses. Attach Form 3903*/
 GetLine( "L27", &L[27] );	/* One-half of self-employment tax. Attach Schedule SE*/
 GetLine( "L28", &L[28] );	/* Self-employed health insurance deduction (see page 33)*/
 GetLine( "L29", &L[29] );	/* Self-employed SEP, SIMPLE, and qualified plans*/
 GetLine( "L30", &L[30] );	/* Penalty on early withdrawal of savings*/
 GetLine( "L31a", &L[31] );	/* Alimony paid*/
 GetLine( "L32", &L[32] );	/* IRA deduction (see page 26) */
 GetLine( "L33", &L[33] );	/* Student loan interest deduction (pg 28) */
 GetLine( "L34", &L[34] );	/* Tuition and fees deduction (see page 29) */
 GetLine( "L35", &L[35] );	/* Domestic production activities deduction, Form 8903 */

 if (L[33] != 0.0)
 { /* Student loan interest calculation pg 33. */ 
  float ws[20];
  ws[1] = smallerof( L[33], 2500.0 );
  ws[2] = L[22];
  ws[3] = L[23] + L[24] + L[25] + L[28] + L[29] + L[30] + L[31] + L[32];
  ws[4] = ws[2] - ws[3];
  if (status == MARRIED_FILLING_JOINTLY) ws[5] = 105000.0; else ws[5] = 50000.0;
  if (ws[4] > ws[5])
   {
    ws[6] = ws[4] - ws[5];
    if (status == MARRIED_FILLING_JOINTLY) ws[7] = ws[6] / 30000.0; 
    else ws[7] = ws[6] / 15000.0;
    if (ws[7] > 1.0) ws[7] = 1.0;
    ws[8] = ws[1] * ws[7];
   }
  else ws[8] = 0.0;
  ws[9] = ws[1] - ws[8];
  L[33] = ws[9];
 }

 ShowLineNonZero(25);
 ShowLineNonZero(26);
 ShowLineNonZero(27);
 ShowLineNonZero(28);
 ShowLineNonZero(29);
 ShowLineNonZero(30);
 ShowLineNonZero(31);
 ShowLineNonZero(32);
 ShowLineNonZero(33);
 ShowLineNonZero(34);
 ShowLineNonZero(35);

 for (i=23; i<=35; i++) L[36] = L[36] + L[i];
 showline(36);

 L[37] = L[22] - L[36];
 showline_wmsg(37,"adjusted gross income");


 /* Taxes and Credits section. */
 L[38] = L[37];
 showline(38);

 GetLine( "L39", &L[39] );	/* Number of boxes checked (0-4), line-39:  You, Spouse : >65, blind.  */
 shownum(39); 

 /* Schedule A */
 GetLine( "A1", &SchedA[1] );	/* Unreimbursed medical expenses. */
  showschedA(1);
 SchedA[2] = L[37];
  showschedA(2);
 SchedA[3] = 0.075 * SchedA[2];
  showschedA(3);
 SchedA[4] = NotLessThanZero( SchedA[1] - SchedA[3] );
  showschedA(4);
 GetLine( "A5", &SchedA[5] );	/* State and local income taxes. */
  showschedA(5);
 GetLine( "A6", &SchedA[6] );	/* Real estate taxes. */
  showschedA(6);
 GetLine( "A7", &SchedA[7] );	/* Personal property taxes. */
  showschedA(7);
 GetLine( "A8", &SchedA[8] );	/* Other taxes. */
  showschedA(8);
 SchedA[9] = SchedA[5] + SchedA[6] + SchedA[7] + SchedA[8];
  showschedA(9);
 GetLine( "A10", &SchedA[10] );	/* Home mortgage interest and points */
  showschedA(10);
 GetLine( "A11", &SchedA[11] );	/* Home mortgage interest not reported to you on Form 1098.*/
  showschedA(11);
 GetLine( "A12", &SchedA[12] );	/* Points not reported to you on Form 1098.*/
  showschedA(12);
 GetLine( "A13", &SchedA[13] );	/* Investment interest. Attach Form 4952*/
  showschedA(13);
 SchedA[14] = SchedA[10] + SchedA[11] + SchedA[12] + SchedA[13];
  showschedA(14);
 GetLine( "A15", &SchedA[15] );	/* Charity contributions.*/
  showschedA(15);
 GetLine( "A16", &SchedA[16] );	/* Contributions other than cash or check.*/
  showschedA(16);
 GetLine( "A17", &SchedA[17] );	/* Carryover from prior year*/
  showschedA(17);
 SchedA[18] = SchedA[15] + SchedA[16] + SchedA[17];
  showschedA(18);
 GetLine( "A19", &SchedA[19] );	/* Casualty or theft loss(es).*/
  showschedA(19);
 GetLine( "A20", &SchedA[20] );	/* Unreimbursed employee expenses*/
  showschedA(20);
 GetLine( "A21", &SchedA[21] );	/* Tax preparation fees*/
  showschedA(21);
 GetLine( "A22", &SchedA[22] );	/* Other expenses*/
  showschedA(22);
 SchedA[23] = SchedA[20] + SchedA[21] + SchedA[22];  		showschedA(23);
 SchedA[24] = L[37];						showschedA(24);
 SchedA[25] = 0.02 * SchedA[24];				showschedA(25);
 SchedA[26] = NotLessThanZero( SchedA[23] - SchedA[25] );  	showschedA(26);
 GetLine( "A27", &SchedA[27] );	/* Other deductions, list on page A-6. */
  showschedA(27);
 if (((L[38]>145950.0) && (status!=MARRIED_FILLING_SEPARAT)) || ((L[38]>72975.0) && (status==MARRIED_FILLING_SEPARAT)))
  { /* Yes, may be limited. */
   /* Itemized work sheet - Line 28 from Sched A, pgs A-9. */
   float ws[90];  

   for (i=0; i<90; i++) ws[i] = 0.0;
   ws[1] = SchedA[4] + SchedA[9] + SchedA[14] + SchedA[18] + SchedA[19] + SchedA[26] + SchedA[27];
   ws[2] = SchedA[4] + SchedA[13] + SchedA[15] + SchedA[19] + SchedA[27];
   if (ws[2] < ws[1]) 
    { /*yes1*/
     ws[3] = ws[1] - ws[2];
     ws[4] = 0.8 * ws[3];
     ws[5] = L[38];
     if (status!=MARRIED_FILLING_SEPARAT) ws[6] = 145950.0; else ws[6] = 72975.0;
     if (ws[6] < ws[5]) 
      { /*yes2*/
	ws[7] = ws[5] - ws[6];
	ws[8] = 0.03 * ws[7];
	ws[9] = smallerof( ws[4], ws[8] );
	ws[10] = ws[1] - ws[9];
	SchedA[28] = ws[10];
	fprintf(outfile,"Sched-A Itemized Deductions Work Sheet (pg A9) limits deduction from %6.2f, to %6.2f\n", ws[1], ws[10]);
      }
     else
      { /*no2*/
	SchedA[28] = ws[1];
	fprintf(outfile," Deductions not limited.\n");
      } 
    }
   else
    { /*no1*/
     SchedA[28] = ws[1];
     fprintf(outfile," Deductions not limited.\n");
    } 
  }
 else
  { /* Deductions not limited */ 
   fprintf(outfile," Deductions not limited.\n");
   SchedA[28] = SchedA[4] + SchedA[9] + SchedA[14] + SchedA[18] + SchedA[19] + SchedA[26] + SchedA[27];
  }
 showschedA(28);
 L[40] = SchedA[28];
 if (L[40]>0.0) itemize = Yes; else itemize = No;

 #define S_STD_DEDUC    5000.0
 #define MFS_STD_DEDUC  5000.0
 #define MFJ_STD_DEDUC  10000.0
 #define HH_STD_DEDUC   7300.0

 if ((status==SINGLE) || (status==MARRIED_FILLING_SEPARAT)) 		/* Compare to std deduction for '05. */
  { 
   if (L[40]<S_STD_DEDUC) { L[40] = S_STD_DEDUC;  fprintf(outfile,"Use standard deduction.\n");  itemize = 0;}
  }
 else
 if ((status==MARRIED_FILLING_JOINTLY) || (status==WIDOW))
  { 
   if (L[40]<MFJ_STD_DEDUC) { L[40] = MFJ_STD_DEDUC;  fprintf(outfile,"Use standard deduction.\n");  itemize = 0;}
  }
 else
 if (status==HEAD_OF_HOUSEHOLD) 
  { 
   if (L[40]<HH_STD_DEDUC) { L[40] = HH_STD_DEDUC;  fprintf(outfile,"Use standard deduction.\n");  itemize = 0;}
  }
 else 
  { printf("Case (Line 40) not handled.\n"); exit(1); }
 if (itemize) fprintf(outfile,"Itemizing.\n");
 showline(40);

 L[41] = L[38] - L[40];
 showline(41);

 if (L[38] <= 109475.0) L[42] = 3200.0 * L[6];
 else
  { /* Worksheet pg 37. */
   float denom=2500.0, ws[10];

   switch (status)
    {
     case SINGLE:  	      ws[4] = 145950.0;  break;
     case MARRIED_FILLING_JOINTLY:  
     case WIDOW:   	      ws[4] = 218950.0;  break;
     case MARRIED_FILLING_SEPARAT:
		   	      ws[4] = 109475.0;  denom = 1250.0; break;
     case HEAD_OF_HOUSEHOLD:  ws[4] = 182450.0;  break;
    }
   if (L[38] <= ws[4]) 
    L[42] = 3200.0 * L[6];
   else
    {
     ws[2] = 3200.0 * L[6];
     ws[3] = L[38];
     ws[5] = ws[3] - ws[4];
     if ((ws[5] > 122500.0) || ((ws[5] > 61250.0) && (status == MARRIED_FILLING_SEPARAT)))
      { 
       fprintf(outfile,"Income too high for Exemptions...  (Exemptions Worksheet)\n");
       L[42] = 0.0;
      }
     else 
      {
       ws[6] = (int)( ws[5] / denom + 0.999999 );
       ws[7] = 0.02 * ws[6];
       ws[8] = ws[2] * ws[7];
       ws[9] = ws[2] - ws[8];
       L[42] = ws[9];
      }
    }
  }
 showline( 42 );

 L[43] = NotLessThanZero( L[41] - L[42] );
 showline_wmsg( 43, "Taxable income" );


 /* Calculate the tax...  on L43 */
 L[44] = TaxRateFunction( L[43], status );

 if ((!Do_SDTW) && (!Do_QDCGTW) && ((L9b>0.0) || (L[13]>0.0) || ((SchedD[15]>0.0) && (SchedD[16]>0.0)) ))
  Do_QDCGTW = Yes;
 if (Do_QDCGTW)
  {
   fprintf(outfile,"'Qualified Dividends and Captial Gain tax Worksheet', page 34.\n");
   capgains_qualdividends_worksheets( status, L9b );
  }
 else
 if (Do_SDTW)
  {
   fprintf(outfile,"'Schedule D Tax Worksheet', page D9.\n");
   sched_D_tax_worksheet( status, L9b );
  }

 showline_wmsg( 44, "Tax" );


 L[45] = AlternativeMinimumTax( status, itemize );
 if (L[45] == 0.0) fprintf(outfile," (Not subject to Alternative Minimum Tax.)\n");
 ShowLineNonZero(45);

 L[46] = L[44] + L[45];	
 showline(46);

 GetLine( "L47", &L[47] );	/* Foreign tax credit. */
 ShowLineNonZero(47);

 GetLine( "L48", &L[48] );	/* Child / dependent care expense credits. Form 2441. */
 ShowLineNonZero(48);

 GetLine( "L49", &L[49] );	/*  Credit for the elderly or the disabled. Attach Schedule R. */
 ShowLineNonZero(49);

 GetLine( "L50", &L[50] );	/*  Education credits. Form 8863. */
 ShowLineNonZero(50);

 GetLine( "L51", &L[51] );	/*  Retirement savings contributions credit. Form 8880. */
 ShowLineNonZero(51);

 GetLine( "L52", &L[52] );	/*  Child tax credit (see page 40). */
 ShowLineNonZero(52);

 GetLine( "L53", &L[53] );	/*  Adoption credit. Form 8839. */
 ShowLineNonZero(53);

 GetLine( "L54", &L[54] );	/*  Credits from forms 8396 8859. */
 ShowLineNonZero(54);

 GetLine( "L55", &L[55] );	/*  Other credits. Forms 3800, 8801, ect. */
 ShowLineNonZero(55);

 for (i=47; i<=55; i++) L[56] = L[56] + L[i];
 showline(56);

 L[57] = NotLessThanZero( L[46] - L[56] );
 showline(57);

 /* Other Taxes section. */

 GetLine( "L58", &L[58] );	/* Self-employment tax. Sched SE */
 ShowLineNonZero(58);

 GetLine( "L59", &L[59] );	/* Social Sec/Medicare tax on tips. Form 4137 */
 ShowLineNonZero(59);

 GetLine( "L60", &L[60] );	/* Tax on tax-favored accounts. Form 5329 */
 ShowLineNonZero(60);

 GetLine( "L61", &L[61] );	/* Advance earned income credit payments from W-2 */
 ShowLineNonZero(61);

 GetLine( "L62", &L[62] );	/* Household employment taxes. Sched H */
 ShowLineNonZero(62);

 for (i=57; i<=62; i++) L[63] = L[63] + L[i];
 showline_wmsg(63,"total tax");


 /* Payments section. */

 GetLineF( "L64", &L[64] );	/* Federal income tax withheld, Forms W-2, 1099 */
 showline(64);

 GetLine( "L65", &L[65] );	/* '03 estimated payments + amnt applied from '02 */
 ShowLineNonZero(65);

 GetLine( "L66a", &L[66] );	/* Earned income credit (EIC) */
 ShowLineNonZero(66);

 GetLine( "L67", &L[67] );	/* Excess soc. sec. + tier 1 RRTA tax withheld, pg 56 */
 ShowLineNonZero(67);

 GetLine( "L68", &L[68] );	/* Additional child tax credit. Attach Form 8812 */
 ShowLineNonZero(68);

 GetLine( "L69", &L[69] );	/* Amnt paid in filing extension req. (page 56) */
 ShowLineNonZero(69);

 GetLine( "L70", &L[70] );	/* Other payments forms 2439, 4136, 8885. */
 ShowLineNonZero(70);

 for (i=64; i<=70; i++) L[71] = L[71] + L[i];
 showline_wmsg(71,"total payments");


 /* Refund or Owe section. */

 if (L[71] > L[63]) 
  {
   L[72] = L[71] - L[63];
   fprintf(outfile,"L72 = %6.2f  REBATE!!!\n", L[72] );
   fprintf(outfile,"L73a = %6.2f \n", L[72] );
  }
 else 
  {
   L[75] = L[63] - L[71];
   fprintf(outfile,"L75 = %6.2f  YOU OWE !!!\n", L[75] );
  }
 

 fclose(infile);
 fclose(outfile);

 printf("\nListing results from file: %s\n\n", outfname);
 Display_File( outfname );
 return 0;
}
