git ssb

0+

cel / ledger-scripts



Tree: f1521af2d73e96acaa4e96dfc60dbfc50373845a

Files: f1521af2d73e96acaa4e96dfc60dbfc50373845a / ledger-combine

2779 bytesRaw
1#!/usr/bin/env perl
2
3use strict;
4use warnings;
5use Time::Piece;
6use Time::Seconds 'ONE_DAY';
7
8$| = 1;
9
10my @files;
11my @buffer;
12
13# acceptable time difference to consider transactions matching
14my $time_difference = 7 * ONE_DAY;
15
16my $dateformat = "%Y/%m/%d";
17
18if ($#ARGV == -1) {
19 print STDERR "Usage: $0 [journal.ledger]...\n";
20 exit 1;
21}
22
23my @in_filenames = @ARGV;
24my $out_filename;
25
26if ($out_filename) {
27 open OUTFILE, '>', $out_filename;
28 OUTFILE->autoflush(1);
29} else {
30 open OUTFILE, '>&STDOUT';
31}
32
33sub read_entry {
34 my $fh = shift;
35 return if !defined $fh or eof $fh;
36
37 my $amounts = {};
38 my $lines = [];
39 my $entry = {
40 lines => $lines,
41 amounts => $amounts,
42 fh => $fh,
43 };
44
45 # Read lines until found entry date
46 while(1) {
47 my $line = <$fh>;
48 unless (defined $line) {
49 # fh is closed
50 return;
51 }
52 push @$lines, $line;
53 if ($line =~ /^([0-9]{4}[\/-][0-9]{1,2}[\/-][0-9]{1,2})/) {
54 # Make the date string lexically comparable
55 $entry->{date} = Time::Piece->strptime($1, $dateformat) or die("$!");
56 last;
57 }
58 }
59
60 # Read until reaching a blank line
61 while(1) {
62 my $line = <$fh>;
63 unless (defined $line) {
64 # fh is closed
65 push @$lines, "\n";
66 return $entry;
67 }
68 push @$lines, $line;
69 return $entry if $line =~ /^$/;
70 # Record item amounts
71 if ($line =~ /^\s*[^;].*?(?:\s\s|\t)\s*[^@ ]*? ?[^ 0-9]?-?([0-9.,]+)0*[^@]*?\s+(?:;.*|@.*)?$/) {
72 # Account 35.0 BTC @ $15.19
73 $amounts->{+$1} = 1;
74 }
75 }
76
77 return $entry;
78}
79
80sub print_entry {
81 my ($stream, $entry) = @_;
82 my $date = $entry->{date};
83 print $stream $_ for @{ $entry->{lines} };
84}
85
86sub pop_oldest_entry {
87 return unless scalar @buffer;
88
89 # pick the oldest entry
90 my $oldest = $buffer[0];
91 for my $entry (@buffer[1..$#buffer]) {
92 if ($entry->{date} < $oldest->{date}) {
93 $oldest = $entry;
94 }
95 }
96
97 if ($oldest) {
98 # remove the entry from the buffer
99 @buffer = grep { $_ != $oldest } @buffer;
100 # read a new entry from the same stream and add it to the buffer
101 my $fh = $oldest->{fh};
102 if (my $new_entry = read_entry $fh) {
103 push @buffer, $new_entry;
104 }
105 }
106
107 return $oldest;
108}
109
110# Open the ledger journals
111for my $filename (@in_filenames) {
112 open my $fh, '<', $filename or die "Unable to open file $filename: $!";
113 push @files, $fh;
114}
115
116# Read first from each journal
117for my $fh (@files) {
118 push @buffer, read_entry($fh);
119}
120
121while (my $entry = pop_oldest_entry) {
122 print_entry \*OUTFILE, $entry;
123}
124

Built with git-ssb-web