Loading...
Searching...
No Matches
report.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2003-2023, John Wiegley. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * - Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * - Neither the name of New Artisans LLC nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
42#pragma once
43
44#include "expr.h"
45#include "query.h"
46#include "chain.h"
47#include "stream.h"
48#include "option.h"
49#include "commodity.h"
50#include "annotate.h"
51#include "session.h"
52#include "format.h"
53
54namespace ledger {
55
56class session_t;
57class xact_t;
58
59// These are the elements of any report:
60//
61// 1. Formatting string used for outputting the underlying ReportedType.
62//
63// 2. Handler object for the ReportedType. This is constructed using #1, or
64// else #1 is ignored completely. This handler object is also constructed
65// with the output stream that will be used during formatting.
66//
67// --- The details of #1 and #2 together represent the ItemHandler.
68//
69// 3. Mode of the report. Currently there are four modes:
70//
71// a. Posting or commodity iteration. In this mode, all the journal's
72// xacts, the postings of a specific xact, or all the journal's
73// commodities are walked. In the first two cases, it's the underlying
74// postings which are passed to #2; in the second case, each
75// commodity is passed to #2.
76//
77// b. Account iteration. This employs step 'a', but add a prologue and
78// epilogue to it. In the prologue it "sums" all account totals and
79// subtotals; in the epilogue it calls yet another handler whose job is
80// reporting (the handler used in 'a' is only for calculation).
81//
82// There is one variation on 'b' in which a "totals" line is also
83// displayed.
84//
85// c. Write journal. In this mode, a single function is called that output
86// the journal object as a textual file. #2 is used to print out each
87// posting in the journal.
88//
89// d. Dump binary file. This is just like 'c', except that it dumps out a
90// binary file and #2 is completely ignored.
91//
92// 4. For 'a' and 'b' in #3, there is a different iteration function called,
93// depending on whether we're iterating:
94//
95// a. The postings of an xact: walk_postings.
96// b. The xacts of a journal: walk_xacts.
97// c. The commodities of a journal: walk_commodities.
98//
99// 5. Finally, for the 'a' and 'b' reporting modes, there is a variant which
100// says that the formatter should be "flushed" after the entities are
101// iterated. This does not happen for the commodities iteration, however.
102
103class report_t : public scope_t
104{
105 report_t();
106
107public:
110
111#define BUDGET_NO_BUDGET 0x00
112#define BUDGET_BUDGETED 0x01
113#define BUDGET_UNBUDGETED 0x02
114#define BUDGET_WRAP_VALUES 0x04
115
118
124 report_t(const report_t& report)
125 : scope_t(report), session(report.session),
127 terminus(report.terminus),
128 budget_flags(report.budget_flags) {
129 TRACE_CTOR(report_t, "copy");
130 }
131
132 virtual ~report_t() {
135 }
136
137 void quick_close() {
139 }
140
141 virtual string description() {
142 return _("current report");
143 }
144
145 void normalize_options(const string& verb);
147 void parse_query_args(const value_t& args, const string& whence);
148
151 void xact_report(post_handler_ptr handler, xact_t& xact);
154
156
207
209 return terminus;
210 }
212 return terminus.date();
213 }
214
216 return scope_value(this);
217 }
218
220 if (HANDLED(format_))
221 return HANDLER(format_).str();
222 return option.str();
223 }
224
226 if (option)
227 return option.str();
228 return none;
229 }
230
234
242
243 void report_options(std::ostream& out)
244 {
245 HANDLER(abbrev_len_).report(out);
246 HANDLER(account_).report(out);
247 HANDLER(actual).report(out);
248 HANDLER(add_budget).report(out);
249 HANDLER(align_intervals).report(out);
250 HANDLER(amount_).report(out);
251 HANDLER(amount_data).report(out);
252 HANDLER(anon).report(out);
253 HANDLER(auto_match).report(out);
254 HANDLER(aux_date).report(out);
255 HANDLER(average).report(out);
256 HANDLER(balance_format_).report(out);
257 HANDLER(base).report(out);
258 HANDLER(basis).report(out);
259 HANDLER(begin_).report(out);
260 HANDLER(budget).report(out);
261 HANDLER(budget_format_).report(out);
262 HANDLER(by_payee).report(out);
263 HANDLER(cleared).report(out);
264 HANDLER(cleared_format_).report(out);
265 HANDLER(color).report(out);
266 HANDLER(collapse).report(out);
267 HANDLER(collapse_if_zero).report(out);
268 HANDLER(columns_).report(out);
269 HANDLER(csv_format_).report(out);
270 HANDLER(current).report(out);
271 HANDLER(daily).report(out);
272 HANDLER(date_).report(out);
273 HANDLER(date_format_).report(out);
274 HANDLER(datetime_format_).report(out);
275 HANDLER(dc).report(out);
276 HANDLER(depth_).report(out);
277 HANDLER(deviation).report(out);
278 HANDLER(display_).report(out);
279 HANDLER(display_amount_).report(out);
280 HANDLER(display_total_).report(out);
281 HANDLER(dow).report(out);
282 HANDLER(empty).report(out);
283 HANDLER(end_).report(out);
284 HANDLER(equity).report(out);
285 HANDLER(exact).report(out);
286 HANDLER(exchange_).report(out);
287 HANDLER(flat).report(out);
288 HANDLER(force_color).report(out);
289 HANDLER(force_pager).report(out);
290 HANDLER(forecast_while_).report(out);
291 HANDLER(forecast_years_).report(out);
292 HANDLER(format_).report(out);
293 HANDLER(gain).report(out);
294 HANDLER(generated).report(out);
295 HANDLER(group_by_).report(out);
296 HANDLER(group_title_format_).report(out);
297 HANDLER(head_).report(out);
298 HANDLER(immediate).report(out);
299 HANDLER(inject_).report(out);
300 HANDLER(invert).report(out);
301 HANDLER(limit_).report(out);
302 HANDLER(lot_dates).report(out);
303 HANDLER(lot_prices).report(out);
304 HANDLER(average_lot_prices).report(out);
305 HANDLER(lot_notes).report(out);
306 HANDLER(lots).report(out);
307 HANDLER(lots_actual).report(out);
308 HANDLER(market).report(out);
309 HANDLER(meta_).report(out);
310 HANDLER(monthly).report(out);
311 HANDLER(no_pager).report(out);
312 HANDLER(no_rounding).report(out);
313 HANDLER(no_titles).report(out);
314 HANDLER(no_total).report(out);
315 HANDLER(now_).report(out);
316 HANDLER(only_).report(out);
317 HANDLER(output_).report(out);
318 HANDLER(pager_).report(out);
319 HANDLER(payee_).report(out);
320 HANDLER(pending).report(out);
321 HANDLER(percent).report(out);
322 HANDLER(period_).report(out);
323 HANDLER(pivot_).report(out);
324 HANDLER(plot_amount_format_).report(out);
325 HANDLER(plot_total_format_).report(out);
326 HANDLER(prepend_format_).report(out);
327 HANDLER(prepend_width_).report(out);
328 HANDLER(price).report(out);
329 HANDLER(prices_format_).report(out);
330 HANDLER(pricedb_format_).report(out);
331 HANDLER(primary_date).report(out);
332 HANDLER(quantity).report(out);
333 HANDLER(quarterly).report(out);
334 HANDLER(raw).report(out);
335 HANDLER(real).report(out);
336 HANDLER(register_format_).report(out);
337 HANDLER(related).report(out);
338 HANDLER(related_all).report(out);
339 HANDLER(revalued).report(out);
340 HANDLER(revalued_only).report(out);
341 HANDLER(revalued_total_).report(out);
342 HANDLER(rich_data).report(out);
343 HANDLER(seed_).report(out);
344 HANDLER(sort_).report(out);
345 HANDLER(sort_all_).report(out);
346 HANDLER(sort_xacts_).report(out);
347 HANDLER(start_of_week_).report(out);
348 HANDLER(subtotal).report(out);
349 HANDLER(tail_).report(out);
350 HANDLER(time_report).report(out);
351 HANDLER(total_).report(out);
352 HANDLER(total_data).report(out);
353 HANDLER(truncate_).report(out);
354 HANDLER(unbudgeted).report(out);
355 HANDLER(uncleared).report(out);
356 HANDLER(unrealized).report(out);
357 HANDLER(unrealized_gains_).report(out);
358 HANDLER(unrealized_losses_).report(out);
359 HANDLER(unround).report(out);
360 HANDLER(weekly).report(out);
361 HANDLER(wide).report(out);
362 HANDLER(yearly).report(out);
363 HANDLER(meta_width_).report(out);
364 HANDLER(date_width_).report(out);
365 HANDLER(payee_width_).report(out);
366 HANDLER(account_width_).report(out);
367 HANDLER(amount_width_).report(out);
368 HANDLER(total_width_).report(out);
369 HANDLER(values).report(out);
370 }
371
373
374 virtual void define(const symbol_t::kind_t kind, const string& name,
376
378 const string& name);
379
387 on(none, "2");
388 });
389
391
392 OPTION_(report_t, actual, DO() { // -L
393 OTHER(limit_).on(whence, "actual");
394 });
395
398 });
399
400 OPTION(report_t, align_intervals);
401
403 (report_t, amount_, // -t
404 DECL1(report_t, amount_, merged_expr_t, expr, ("amount_expr", "amount")) {}
405 DO_(str) {
406 expr.append(str);
407 });
408
412
413 OPTION_(report_t, average, DO() { // -A
414 OTHER(empty).on(whence);
416 .on(whence, "count>0?(display_total/count):0");
417 });
418
422 on(none,
423 "%(ansify_if("
424 " justify(scrub(display_total), max(int(amount_width),20),"
425 " max(int(amount_width),20) + int(prepend_width), true, color),"
426 " bold if should_bold))"
427 " %(!options.flat ? depth_spacer : \"\")"
428 "%-(ansify_if("
429 " ansify_if(partial_account(options.flat), blue if color),"
430 " bold if should_bold))\n%/"
431 "%$1\n%/"
432 "%(prepend_width ? \" \" * int(prepend_width) : \"\")"
433 "%(\"-\" * max(int(amount_width),20))\n");
434 });
435
437
438 OPTION_(report_t, basis, DO() { // -B
439 OTHER(revalued).on(whence);
440 OTHER(amount_).expr.set_base_expr("rounded(cost)");
441 });
442
443 OPTION_(report_t, begin_, DO_(str) { // -b
444 date_interval_t interval(str);
445 if (optional<date_t> begin = interval.begin()) {
446 string predicate = "date>=[" + to_iso_extended_string(*begin) + "]";
447 OTHER(limit_).on(whence, predicate);
448 } else {
449 throw_(std::invalid_argument,
450 _f("Could not determine beginning of period '%1%'") % str);
451 }
452 });
453
454 OPTION_
456 expr_t expr;
457 DO_(str) {
458 expr = str;
459 });
460
462 parent->budget_flags |= BUDGET_BUDGETED;
463 });
464
468 on(none,
469 "%(justify(scrub(get_at(display_total, 0)), int(amount_width), -1, true, color))"
470 " %(justify(-scrub(get_at(display_total, 1)), int(amount_width), "
471 " int(amount_width) + 1 + int(amount_width), true, color))"
472 " %(justify(scrub((get_at(display_total, 1) || 0) + "
473 " (get_at(display_total, 0) || 0)), int(amount_width), "
474 " int(amount_width) + 1 + int(amount_width) + 1 + int(amount_width), true, color))"
475 " %(ansify_if("
476 " justify((get_at(display_total, 1) ? "
477 " (100% * quantity(scrub(get_at(display_total, 0)))) / "
478 " -quantity(scrub(get_at(display_total, 1))) : 0), "
479 " 5, -1, true, false),"
480 " magenta if (color and get_at(display_total, 1) and "
481 " (abs(quantity(scrub(get_at(display_total, 0))) / "
482 " quantity(scrub(get_at(display_total, 1)))) >= 1))))"
483 " %(!options.flat ? depth_spacer : \"\")"
484 "%-(ansify_if(partial_account(options.flat), blue if color))\n"
485 "%/%$1 %$2 %$3 %$4\n%/"
486 "%(prepend_width ? \" \" * int(prepend_width) : \"\")"
487 "------------ ------------ ------------ -----\n");
488 });
489
491
492 OPTION_(report_t, cleared, DO() { // -C
493 OTHER(limit_).on(whence, "cleared");
494 });
495
499 on(none,
500 "%(justify(scrub(get_at(display_total, 0)), 16, 16 + int(prepend_width), "
501 " true, color)) %(justify(scrub(get_at(display_total, 1)), 18, "
502 " 36 + int(prepend_width), true, color))"
503 " %(latest_cleared ? format_date(latest_cleared) : \" \")"
504 " %(!options.flat ? depth_spacer : \"\")"
505 "%-(ansify_if(partial_account(options.flat), blue if color))\n%/"
506 "%$1 %$2 %$3\n%/"
507 "%(prepend_width ? \" \" * int(prepend_width) : \"\")"
508 "---------------- ---------------- ---------\n");
509 });
510
512
513 OPTION_(report_t, collapse, DO() { // -n
514 // Make sure that balance reports are collapsed too, but only apply it
515 // to account xacts
516 OTHER(display_).on(whence, "post|depth<=1");
517 });
518
520 OTHER(collapse).on(whence);
521 });
522
525
529 on(none,
530 "%(quoted(date)),"
531 "%(quoted(code)),"
532 "%(quoted(payee)),"
533 "%(quoted(display_account)),"
534 "%(quoted(commodity(scrub(display_amount)))),"
535 "%(quoted(quantity(scrub(display_amount)))),"
536 "%(quoted(cleared ? \"*\" : (pending ? \"!\" : \"\"))),"
537 "%(quoted(join(note | xact.note)))\n");
538 });
539
540 OPTION_(report_t, current, DO() { // -c
541 OTHER(limit_).on(whence, "date<=today");
542 });
543
544 OPTION_(report_t, daily, DO() { // -D
545 OTHER(period_).on(whence, "daily");
546 });
547
551
552 OPTION_(report_t, dc, DO() {
553 OTHER(amount_).expr.set_base_expr
554 ("(amount > 0 ? amount : 0, amount < 0 ? amount : 0)");
555
557 .on(none,
558 "%(ansify_if("
559 " ansify_if(justify(format_date(date), int(date_width)),"
560 " green if color and date > today),"
561 " bold if should_bold))"
562 " %(ansify_if("
563 " ansify_if(justify(truncated(payee, int(payee_width)), int(payee_width)), "
564 " bold if color and !cleared and actual),"
565 " bold if should_bold))"
566 " %(ansify_if("
567 " ansify_if(justify(truncated(display_account, int(account_width), "
568 " int(abbrev_len)), int(account_width)),"
569 " blue if color),"
570 " bold if should_bold))"
571 " %(ansify_if("
572 " justify(scrub(abs(get_at(display_amount, 0))), int(amount_width), "
573 " 3 + int(meta_width) + int(date_width) + int(payee_width)"
574 " + int(account_width) + int(amount_width) + int(prepend_width),"
575 " true, color),"
576 " bold if should_bold))"
577 " %(ansify_if("
578 " justify(scrub(abs(get_at(display_amount, 1))), int(amount_width), "
579 " 4 + int(meta_width) + int(date_width) + int(payee_width)"
580 " + int(account_width) + int(amount_width) + int(amount_width) + int(prepend_width),"
581 " true, color),"
582 " bold if should_bold))"
583 " %(ansify_if("
584 " justify(scrub(get_at(display_total, 0) + get_at(display_total, 1)), int(total_width), "
585 " 5 + int(meta_width) + int(date_width) + int(payee_width)"
586 " + int(account_width) + int(amount_width) + int(amount_width) + int(total_width)"
587 " + int(prepend_width), true, color),"
588 " bold if should_bold))\n%/"
589 "%(justify(\" \", int(date_width)))"
590 " %(ansify_if("
591 " justify(truncated(has_tag(\"Payee\") ? payee : \" \", "
592 " int(payee_width)), int(payee_width)),"
593 " bold if should_bold))"
594 " %$3 %$4 %$5 %$6\n");
595
597 .on(none,
598 "%(ansify_if("
599 " justify(scrub(abs(get_at(display_total, 0))), 14,"
600 " 14 + int(prepend_width), true, color),"
601 " bold if should_bold)) "
602 "%(ansify_if("
603 " justify(scrub(abs(get_at(display_total, 1))), 14,"
604 " 14 + 1 + int(prepend_width) + int(total_width), true, color),"
605 " bold if should_bold)) "
606 "%(ansify_if("
607 " justify(scrub(get_at(display_total, 0) + get_at(display_total, 1)), 14,"
608 " 14 + 2 + int(prepend_width) + int(total_width) + int(total_width), true, color),"
609 " bold if should_bold))"
610 " %(!options.flat ? depth_spacer : \"\")"
611 "%-(ansify_if("
612 " ansify_if(partial_account(options.flat), blue if color),"
613 " bold if should_bold))\n%/"
614 "%$1 %$2 %$3\n%/"
615 "%(prepend_width ? \" \" * int(prepend_width) : \"\")"
616 "--------------------------------------------\n");
617 });
618
619 OPTION_(report_t, depth_, DO_(str) {
620 OTHER(display_).on(whence, string("depth<=") + str);
621 });
622
625 .on(whence, "display_amount-display_total");
626 });
627
628 OPTION_
630 DO_(str) { // -d
631 if (handled)
632 value = string("(") + value + ")&(" + str + ")";
633 });
634
638 ("display_amount", "amount_expr")) {}
639 DO_(str) {
640 expr.append(str);
641 });
642
646 ("display_total", "total_expr")) {}
647 DO_(str) {
648 expr.append(str);
649 });
650
652 OPTION(report_t, aux_date);
653 OPTION(report_t, empty); // -E
654
655 OPTION_(report_t, end_, DO_(str) { // -e
656 // Use begin() here so that if the user says --end=2008, we end on
657 // 2008/01/01 instead of 2009/01/01 (which is what end() would
658 // return).
659 date_interval_t interval(str);
660 if (optional<date_t> end = interval.begin()) {
661 string predicate = "date<[" + to_iso_extended_string(*end) + "]";
662 OTHER(limit_).on(whence, predicate);
663
664 parent->terminus = datetime_t(*end);
665 } else {
666 throw_(std::invalid_argument,
667 _f("Could not determine end of period '%1%'")
668 % str);
669 }
670 });
671
674
675 OPTION_(report_t, exchange_, DO_(str) { // -X
676 // Using -X implies -V. The main difference is that now
677 // HANDLER(exchange_) contains the name of a commodity, which
678 // is accessed via the "exchange" value expression function.
679 OTHER(market).on(whence);
680 });
681
688
689 OPTION_(report_t, gain, DO() { // -G
690 OTHER(revalued).on(whence);
691 OTHER(amount_).expr.set_base_expr("(amount, cost)");
692
693 // Since we are displaying the amounts of revalued postings, they
694 // will end up being composite totals, and hence a pair of pairs.
696 .on(whence,
697 "use_direct_amount ? amount :"
698 " (is_seq(get_at(amount_expr, 0)) ?"
699 " get_at(get_at(amount_expr, 0), 0) :"
700 " market(get_at(amount_expr, 0), value_date, exchange)"
701 " - get_at(amount_expr, 1))");
703 .on(whence,
704 "(market(get_at(total_expr, 0), value_date, exchange), "
705 "get_at(total_expr, 1))");
707 .on(whence,
708 "use_direct_amount ? total_expr :"
709 " market(get_at(total_expr, 0), value_date, exchange)"
710 " - get_at(total_expr, 1)");
711 });
712
714
715 OPTION_
717 expr_t expr;
718 DO_(str) {
719 expr = str;
720 });
721
725 on(none, "%(value)\n");
726 });
727
729
730 OPTION_(report_t, historical, DO() { // -H
731 OTHER(market).on(whence);
733 .on(whence, "nail_down(amount_expr, "
734 "market(amount_expr, value_date, exchange))");
735 });
736
739
741 OTHER(amount_).on(whence, "-amount_expr");
742 });
743
744 OPTION_
746 DO_(str) { // -l
747 if (handled)
748 value = string("(") + value + ")&(" + str + ")";
749 });
750
754 OTHER(lot_prices).on(whence);
756 .on(whence, "averaged_lots(display_amount)");
758 .on(whence, "averaged_lots(display_total)");
759 });
763
764 OPTION_(report_t, market, DO() { // -V
765 OTHER(revalued).on(whence);
766
768 .on(whence, "market(display_amount, value_date, exchange)");
770 .on(whence, "market(display_total, value_date, exchange)");
771 });
772
774
775 OPTION_(report_t, monthly, DO() { // -M
776 OTHER(period_).on(whence, "monthly");
777 });
778
780 OTHER(color).off();
781 });
782
784 OTHER(revalued).off();
785 });
786
790
791 OPTION_(report_t, now_, DO_(str) {
792 date_interval_t interval(str);
793 if (optional<date_t> begin = interval.begin()) {
794 ledger::epoch = parent->terminus = datetime_t(*begin);
795 } else {
796 throw_(std::invalid_argument,
797 _f("Could not determine beginning of period '%1%'")
798 % str);
799 }
800 });
801
802 OPTION_
803 (report_t, only_,
804 DO_(str) {
805 if (handled)
806 value = string("(") + value + ")&(" + str + ")";
807 });
808
810
811// setenv() is not available on WIN32
812#if HAVE_ISATTY and !defined(_WIN32) and !defined(__CYGWIN__)
816 if (isatty(STDOUT_FILENO)) {
817 if (! std::getenv("PAGER")) {
818 bool have_less = false;
819 if (exists(path("/opt/local/bin/less")) ||
820 exists(path("/usr/local/bin/less")) ||
821 exists(path("/usr/bin/less")))
822 have_less = true;
823
824 if (have_less) {
825 on(none, "less");
826 setenv("LESS", "-FRSX", 0); // don't overwrite
827 }
828 } else {
829 on(none, std::getenv("PAGER"));
830 setenv("LESS", "-FRSX", 0); // don't overwrite
831 }
832 }
833 });
834#else // HAVE_ISATTY
836#endif // HAVE_ISATTY
837
839 OTHER(pager_).off();
840 });
841
843
844 OPTION_(report_t, pending, DO() { // -C
845 OTHER(limit_).on(whence, "pending");
846 });
847
848 OPTION_(report_t, percent, DO() { // -%
850 .on(whence,
851 "((is_account&parent&parent.total)?"
852 " percent(scrub(total), scrub(parent.total)):0)");
853 });
854
855 OPTION_
857 DO_(str) { // -p
858 if (handled)
859 value += string(" ") + str;
860 });
861
863
867 on(none,
868 "%(format_date(date, \"%Y-%m-%d\")) %(quantity(scrub(display_amount)))\n");
869 });
870
874 on(none,
875 "%(format_date(date, \"%Y-%m-%d\")) %(quantity(scrub(display_total)))\n");
876 });
877
880
881 OPTION_(report_t, price, DO() { // -I
882 OTHER(amount_).expr.set_base_expr("price");
883 });
884
888 on(none,
889 "%(date) %-8(display_account) %(justify(scrub(display_amount), 12, "
890 " 2 + 9 + 8 + 12, true, color))\n");
891 });
892
896 on(none,
897 "P %(datetime) %(display_account) %(scrub(display_amount))\n");
898 });
899
900 OPTION(report_t, primary_date);
901
902 OPTION_(report_t, quantity, DO() { // -O
903 OTHER(revalued).off();
904
905 OTHER(amount_).expr.set_base_expr("amount");
906 OTHER(total_).expr.set_base_expr("total");
907 });
908
910 OTHER(period_).on(whence, "quarterly");
911 });
912
914
915 OPTION_(report_t, real, DO() { // -R
916 OTHER(limit_).on(whence, "real");
917 });
918
922 on(none,
923 "%(ansify_if("
924 " ansify_if(justify(format_date(date), int(date_width)),"
925 " green if color and date > today),"
926 " bold if should_bold))"
927 " %(ansify_if("
928 " ansify_if(justify(truncated(payee, int(payee_width)), int(payee_width)), "
929 " bold if color and !cleared and actual),"
930 " bold if should_bold))"
931 " %(ansify_if("
932 " ansify_if(justify(truncated(display_account, int(account_width), "
933 " int(abbrev_len)), int(account_width)),"
934 " blue if color),"
935 " bold if should_bold))"
936 " %(ansify_if("
937 " justify(scrub(display_amount), int(amount_width), "
938 " 3 + int(meta_width) + int(date_width) + int(payee_width)"
939 " + int(account_width) + int(amount_width) + int(prepend_width),"
940 " true, color),"
941 " bold if should_bold))"
942 " %(ansify_if("
943 " justify(scrub(display_total), int(total_width), "
944 " 4 + int(meta_width) + int(date_width) + int(payee_width)"
945 " + int(account_width) + int(amount_width) + int(total_width)"
946 " + int(prepend_width), true, color),"
947 " bold if should_bold))\n%/"
948 "%(justify(\" \", int(date_width)))"
949 " %(ansify_if("
950 " justify(truncated(has_tag(\"Payee\") ? payee : \" \", "
951 " int(payee_width)), int(payee_width)),"
952 " bold if should_bold))"
953 " %$3 %$4 %$5\n");
954 });
955
957
959 OTHER(related).on(whence);
960 });
961
964
965 OPTION_
967 expr_t expr;
968 DO_(str) {
969 expr = str;
970 });
971
973
975
976 OPTION_(report_t, sort_, DO_(str) { // -S
977 OTHER(sort_xacts_).off();
978 OTHER(sort_all_).off();
979 });
980
982 OTHER(sort_).on(whence, str);
983 OTHER(sort_xacts_).off();
984 });
985
987 OTHER(sort_).on(whence, str);
988 OTHER(sort_all_).off();
989 });
990
992 OPTION(report_t, subtotal); // -s
994
997 .on(none,
998 "%(ansify_if(justify(earliest_checkin ? "
999 " format_datetime(earliest_checkin) : \"\", 19, -1, true),"
1000 " bold if latest_checkout_cleared)) "
1001 "%(ansify_if(justify(latest_checkout ? "
1002 " format_datetime(latest_checkout) : \"\", 19, -1, true), "
1003 " bold if latest_checkout_cleared)) "
1004 "%(latest_checkout_cleared ? \"*\" : \" \") "
1005 "%(ansify_if("
1006 " justify(scrub(display_total), 8,"
1007 " 8 + 4 + 19 * 2, true, color), bold if should_bold))"
1008 " %(!options.flat ? depth_spacer : \"\")"
1009 "%-(ansify_if("
1010 " ansify_if(partial_account(options.flat), blue if color),"
1011 " bold if should_bold))\n%/"
1012 "%$1 %$2 %$3\n%/"
1013 "%(prepend_width ? \" \" * int(prepend_width) : \"\")"
1014 "--------------------------------------------------\n");
1015 });
1016
1017 OPTION__
1018 (report_t, total_, // -T
1019 DECL1(report_t, total_, merged_expr_t, expr, ("total_expr", "total")) {}
1020 DO_(str) {
1021 expr.append(str);
1022 });
1023
1025
1027 if (style == "leading")
1029 else if (style == "middle")
1031 else if (style == "trailing")
1033 else
1034 throw_(std::invalid_argument,
1035 _f("Unrecognized truncation style: '%1%'") % style);
1037 });
1038
1041 });
1042
1043 OPTION_(report_t, uncleared, DO() { // -U
1044 OTHER(limit_).on(whence, "uncleared|pending");
1045 });
1046
1048
1051
1052 OPTION_(report_t, unround, DO() {
1053 OTHER(amount_).on(whence, "unrounded(amount_expr)");
1054 OTHER(total_).on(whence, "unrounded(total_expr)");
1055 });
1056
1057 OPTION_(report_t, weekly, DO() { // -W
1058 OTHER(period_).on(whence, "weekly");
1059 });
1060
1061 OPTION_(report_t, wide, DO() { // -w
1062 OTHER(columns_).on(whence, "132");
1063 });
1064
1065 OPTION_(report_t, yearly, DO() { // -Y
1066 OTHER(period_).on(whence, "yearly");
1067 });
1068
1076};
1077
1078template <class Type = post_t,
1081 &report_t::posts_report>
1083{
1085
1086 report_t& report;
1087 string whence;
1088
1089public:
1091 report_t& _report, const string& _whence)
1092 : handler(_handler), report(_report), whence(_whence) {
1093 TRACE_CTOR(reporter, "item_handler<Type>, report_t&, string");
1094 }
1096 : handler(other.handler), report(other.report), whence(other.whence) {
1097 TRACE_CTOR(reporter, "copy");
1098 }
1101 }
1102
1104 {
1105 if (args.size() > 0)
1106 report.parse_query_args(args.value(), whence);
1107
1108 (report.*report_method)(handler_ptr(handler));
1109
1110 return true;
1111 }
1112};
1113
1114} // namespace ledger
#define TRACE_DTOR(cls)
Definition utils.h:144
#define TRACE_CTOR(cls, args)
Definition utils.h:143
#define CURRENT_TIME()
Definition times.h:74
Basic type and macros for handling command-line options.
#define DECL1(type, name, vartype, var, value)
Definition option.h:214
#define OTHER(name)
Definition option.h:288
#define HANDLER(name)
Definition option.h:263
#define DO_(var)
Definition option.h:219
#define OPTION(type, name)
Definition option.h:266
#define HANDLED(name)
Definition option.h:264
#define CTOR(type, name)
Definition option.h:210
#define OPTION_(type, name, body)
Definition option.h:273
#define DO()
Definition option.h:218
#define OPTION__(type, name, body)
Definition option.h:281
A utility class for abstracting an output stream.
#define BUDGET_UNBUDGETED
Definition filters.h:968
#define BUDGET_BUDGETED
Definition filters.h:967
#define BUDGET_NO_BUDGET
Definition filters.h:966
Types for annotating commodities.
#define throw_(cls, msg)
Definition error.h:55
Types for handling commodities.
optional< datetime_t > epoch
balance_t average_lot_prices(const balance_t &bal)
shared_ptr< item_handler< post_t > > post_handler_ptr
Definition chain.h:90
boost::filesystem::path path
Definition utils.h:68
T & downcast(U &object)
Definition utils.h:468
value_t scope_value(scope_t *val)
Definition value.h:972
boost::posix_time::ptime datetime_t
Definition times.h:53
shared_ptr< item_handler< account_t > > acct_handler_ptr
Definition chain.h:91
intrusive_ptr< op_t > ptr_op_t
Definition expr.h:57
static enum ledger::format_t::elision_style_t default_style
static bool default_style_changed
Definition format.h:117
void commodities_report(post_handler_ptr handler)
value_t fn_lot_date(call_scope_t &scope)
virtual void define(const symbol_t::kind_t kind, const string &name, expr_t::ptr_op_t def)
value_t fn_amount_expr(call_scope_t &scope)
value_t fn_commodity_price(call_scope_t &scope)
value_t fn_rounded(call_scope_t &scope)
void normalize_period()
value_t fn_total_expr(call_scope_t &scope)
report_t(const report_t &report)
Definition report.h:124
value_t fn_truncated(call_scope_t &scope)
value_t fn_to_balance(call_scope_t &scope)
keep_details_t what_to_keep()
Definition report.h:235
value_t fn_quoted_rfc(call_scope_t &scope)
value_t fn_round(call_scope_t &scope)
value_t fn_get_at(call_scope_t &scope)
value_t fn_quoted(call_scope_t &scope)
value_t fn_to_amount(call_scope_t &scope)
value_t fn_to_mask(call_scope_t &scope)
value_t fn_to_sequence(call_scope_t &scope)
void report_options(std::ostream &out)
Definition report.h:243
value_t fn_unround(call_scope_t &scope)
void xact_report(post_handler_ptr handler, xact_t &xact)
value_t fn_lot_tag(call_scope_t &scope)
value_t fn_to_string(call_scope_t &scope)
session_t & session
Definition report.h:108
report_t(session_t &_session)
Definition report.h:119
void quick_close()
Definition report.h:137
value_t echo_command(call_scope_t &scope)
value_t fn_unrounded(call_scope_t &scope)
void normalize_options(const string &verb)
value_t fn_is_seq(call_scope_t &scope)
value_t fn_format_datetime(call_scope_t &scope)
value_t fn_to_int(call_scope_t &scope)
value_t pricemap_command(call_scope_t &scope)
void accounts_report(acct_handler_ptr handler)
uint_least8_t budget_flags
Definition report.h:117
value_t fn_commodity(call_scope_t &scope)
virtual ~report_t()
Definition report.h:132
virtual string description()
Definition report.h:141
value_t fn_ansify_if(call_scope_t &scope)
option_t< report_t > * lookup_option(const char *p)
value_t fn_now(call_scope_t &)
Definition report.h:208
value_t fn_today(call_scope_t &)
Definition report.h:211
value_t display_value(const value_t &val)
value_t fn_justify(call_scope_t &scope)
value_t fn_to_boolean(call_scope_t &scope)
value_t fn_to_date(call_scope_t &scope)
value_t fn_set_commodity_price(call_scope_t &scope)
value_t fn_abs(call_scope_t &scope)
value_t fn_display_amount(call_scope_t &scope)
value_t fn_trim(call_scope_t &scope)
value_t fn_display_total(call_scope_t &scope)
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, const string &name)
value_t fn_market(call_scope_t &scope)
value_t fn_to_datetime(call_scope_t &scope)
value_t fn_print(call_scope_t &scope)
value_t fn_averaged_lots(call_scope_t &scope)
value_t fn_lot_price(call_scope_t &scope)
value_t fn_quantity(call_scope_t &scope)
value_t fn_clear_commodity(call_scope_t &scope)
void generate_report(post_handler_ptr handler)
value_t fn_top_amount(call_scope_t &val)
value_t fn_floor(call_scope_t &scope)
value_t fn_options(call_scope_t &)
Definition report.h:215
value_t fn_nail_down(call_scope_t &scope)
value_t fn_strip(call_scope_t &scope)
string report_format(option_t< report_t > &option)
Definition report.h:219
datetime_t terminus
Definition report.h:116
value_t fn_format_date(call_scope_t &scope)
value_t fn_join(call_scope_t &scope)
void posts_report(post_handler_ptr handler)
value_t fn_format(call_scope_t &scope)
value_t fn_ceiling(call_scope_t &scope)
value_t fn_should_bold(call_scope_t &scope)
value_t reload_command(call_scope_t &)
value_t fn_roundto(call_scope_t &scope)
optional< string > maybe_format(option_t< report_t > &option)
Definition report.h:225
output_stream_t output_stream
Definition report.h:109
value_t fn_percent(call_scope_t &scope)
void parse_query_args(const value_t &args, const string &whence)
value_t fn_scrub(call_scope_t &scope)
reporter(const reporter &other)
Definition report.h:1095
value_t operator()(call_scope_t &args)
Definition report.h:1103
reporter(shared_ptr< item_handler< Type > > _handler, report_t &_report, const string &_whence)
Definition report.h:1090
value_t & value()
Definition scope.h:335
std::size_t size() const
Definition scope.h:395
An output stream.
Definition stream.h:66
void close()
Close the output stream, waiting on the pager process if necessary.
optional< date_t > begin() const
Definition times.h:491
Dynamic type representing various numeric types.
Definition value.h:83