Bugfix: read_journal() keeps reading beyonf EOF.
[account.git] / account_main.cpp
1 #include "account.h"
2 #include <fstream>
3 #include <iomanip>
4 #include <getopt.h>
5
6 static char  helptext[] = 
7      "Usage: account [options] journal\n"
8      "\n"
9      "Options:\n"
10      "  -r <start>\n"
11      "  --renumber <start>   :  Renumber the booking numbers (start > 0)\n"
12      "  --help               :  Print this helpful message\n"
13      "  -V\n"
14      "  --version            :  Print the version number\n";
15
16 void read_journal(char *journal_file);
17 void renumber_journal(char *journal_file, unsigned long renumber);
18 void print_journal();
19
20 Ledger    ledger;
21 Booking   b[2000];
22 Mutation  m[6000];
23
24 int n_m = 0, n_b = 0;
25
26 static struct option long_options[] =
27 {
28    { "help",       no_argument,        0,   'h' },
29    { "renumber",   required_argument,  0,   'r' },
30    { "version",    no_argument,        0,   'V' },
31    { 0, 0, 0, 0 }
32 };
33
34 main(int argc, char *argv[])
35 {
36    int      i, c;
37    Account  a;
38
39    unsigned long renum = 0;
40
41    int      option_index = 0;
42
43    while ((c = getopt_long(argc, argv, "Vr:", long_options, &option_index)) != -1)
44    {
45       switch (c)
46       {
47       case 'h':
48          std::cout << helptext;
49          exit(0);
50          break;
51
52       case 'V':
53          std::cout << "account version 1.4\n";
54          exit(0);
55          break;
56
57       case 'r':
58          renum = String(optarg);
59          break;
60       }
61    }
62
63    if (optind == argc)
64    {
65       std::cerr << "Usage: account [options] journal_file\n";
66       exit(1);
67    }
68
69    if (renum != 0)
70    {
71       renumber_journal(argv[optind], renum);
72       exit(0);
73    }
74
75    ledger.read((char *)"Ledger");
76    read_journal(argv[optind]);
77
78
79    ledger.start();
80
81    while (a = ledger.next(), a != acc_nr(1000, 1000))
82       a.sheet(std::cout);
83
84    ledger.accounts_report("grootboek.ps");
85
86    //   Calculate all accounts to create the final balance.
87
88    for (i = 0; i < n_m; i++)
89       ledger[m[i]] += m[i];
90
91    std::cout << ledger;
92    
93    ledger.saldi_report("saldibalans.ps", date(b[0]), date(b[n_b-1]));
94
95    std::ofstream  saldi("saldi.xml");
96    ledger.XML_saldi(saldi, date(b[0]), date(b[n_b-1]));
97 }
98
99 void read_journal(char *journal_file)
100 {
101    Booking    B;
102    balance    bal;
103    Mutation   M[100];
104
105    int        n_mut = 0;
106    char       first_char;
107
108    std::ifstream  i(journal_file);
109
110    while (i)
111    {
112       first_char = '\n';
113       i.get(first_char);
114       switch (first_char)
115       {
116       case '#' :
117          if (n_mut != 0)
118          {
119             if (bal)
120             {
121                if (n_b > 0)
122                {
123                   if (date(B) < date(b[n_b - 1]))
124                   {
125                      std::cerr << "The date of booking " << B.number() << " is out of sequence.\n";
126                   }
127                   if (B.number() < b[n_b - 1].number())
128                   {
129                      std::cerr << "The number of booking " << B.number() << " is out of sequence.\n";
130                   }
131                }
132                b[n_b++] = B;
133                for (int j = 0; j < n_mut; j++)
134                   m[n_m++] = M[j];
135             }
136             else
137             {
138                std::cerr << "Booking nr. " << B.number()
139                     << " is out of balance: " << bal << "\n";
140             }
141             n_mut = 0;
142             bal = balance(0,0);
143             //std::cerr << "\n";
144          }
145          i >> B;
146          //std::cerr << B << "\n";  //  Provide visual check
147          break;
148
149       case ' ' :
150          M[n_mut] = Mutation(B.number());
151          i >> M[n_mut];
152          //std::cerr << "  > " << M[n_mut] << "\n";   // Provide visual check
153          if (i.good())
154          {
155             bal += M[n_mut];
156             n_mut++;
157          }
158          else
159          {
160             std::cerr << "Input error at #" << B.number() << "\n";
161             i.clear();
162          }
163          break;
164
165       case '\n' :  break;   // Ignore linefeeds
166       default:     break;
167       }
168    }
169
170    if (n_mut != 0)
171    {
172       if (bal)
173       {
174          b[n_b++] = B;
175          for (int j = 0; j < n_mut; j++)
176             m[n_m++] = M[j];
177       }
178    }
179 }
180
181 void renumber_journal(char *journal_file, unsigned long renumber)
182 {
183    std::ifstream  i(journal_file);
184    String         line;
185
186    bool          started = false;
187
188    while (i >> line)
189    {
190       if (line[0] == '#')
191       {
192          int    c  = line.index(' ');
193          String nr = line(1,c-1);
194          unsigned long b_nr = nr.dec();
195          line(0,c) = String("");
196
197          if (started)
198          {
199             b_nr = renumber++;
200          }
201          else
202          {
203             if (b_nr == renumber)
204             {
205                renumber ++;
206                started = true;
207             }
208          }
209          std::cout << "#" << std::setw(4) << std::setfill('0') << b_nr;
210          std::cout << line << "\n";
211       }
212       else
213       {
214          std::cout << line << "\n";
215       }
216    }
217 }
218
219 void print_journal()
220 {
221    for (int mi = 0; mi < n_m; mi++)
222    {
223       std::cout << m[mi] << "\n";
224    }
225 }