Added experimental cashflow analysis stylesheet.
[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.3.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       i.get(first_char);
113       switch (first_char)
114       {
115       case '#' :
116          if (n_mut != 0)
117          {
118             if (bal)
119             {
120                if (n_b > 0)
121                {
122                   if (date(B) < date(b[n_b - 1]))
123                   {
124                      std::cerr << "The date of booking " << B.number() << " is out of sequence.\n";
125                   }
126                   if (B.number() < b[n_b - 1].number())
127                   {
128                      std::cerr << "The number of booking " << B.number() << " is out of sequence.\n";
129                   }
130                }
131                b[n_b++] = B;
132                for (int j = 0; j < n_mut; j++)
133                   m[n_m++] = M[j];
134             }
135             else
136             {
137                std::cerr << "Booking nr. " << B.number()
138                     << " is out of balance: " << bal << "\n";
139             }
140             n_mut = 0;
141             bal = balance(0,0);
142             //std::cerr << "\n";
143          }
144          i >> B;
145          //std::cerr << B << "\n";  //  Provide visual check
146          break;
147
148       case ' ' :
149          M[n_mut] = Mutation(B.number());
150          i >> M[n_mut];
151          //std::cerr << "  > " << M[n_mut] << "\n";   // Provide visual check
152          if (i.good())
153          {
154             bal += M[n_mut];
155             n_mut++;
156          }
157          else
158          {
159             std::cerr << "Input error at #" << B.number() << "\n";
160             i.clear();
161          }
162          break;
163
164       case '\n' :  break;   // Ignore linefeeds
165       default:     break;
166       }
167    }
168
169    if (n_mut != 0)
170    {
171       if (bal)
172       {
173          b[n_b++] = B;
174          for (int j = 0; j < n_mut; j++)
175             m[n_m++] = M[j];
176       }
177    }
178 }
179
180 void renumber_journal(char *journal_file, unsigned long renumber)
181 {
182    std::ifstream  i(journal_file);
183    String         line;
184
185    bool          started = false;
186
187    while (i >> line)
188    {
189       if (line[0] == '#')
190       {
191          int    c  = line.index(' ');
192          String nr = line(1,c-1);
193          unsigned long b_nr = nr.dec();
194          line(0,c) = String("");
195
196          if (started)
197          {
198             b_nr = renumber++;
199          }
200          else
201          {
202             if (b_nr == renumber)
203             {
204                renumber ++;
205                started = true;
206             }
207          }
208          std::cout << "#" << std::setw(4) << std::setfill('0') << b_nr;
209          std::cout << line << "\n";
210       }
211       else
212       {
213          std::cout << line << "\n";
214       }
215    }
216 }
217
218 void print_journal()
219 {
220    for (int mi = 0; mi < n_m; mi++)
221    {
222       std::cout << m[mi] << "\n";
223    }
224 }