summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--NEWS70
-rw-r--r--README1550
-rw-r--r--binary.cc20
-rw-r--r--format.h1
-rw-r--r--ledger.cc30
-rw-r--r--ledger.h24
-rw-r--r--main.cc27
-rw-r--r--qif.cc27
-rw-r--r--textual.cc12
10 files changed, 98 insertions, 1664 deletions
diff --git a/Makefile b/Makefile
index cb927a66..5e3624af 100644
--- a/Makefile
+++ b/Makefile
@@ -10,6 +10,7 @@ CODE = account.cc \
format.cc \
ledger.cc \
option.cc \
+ parser.cc \
qif.cc \
quotes.cc \
textual.cc \
diff --git a/NEWS b/NEWS
index 07807a91..1a6929b9 100644
--- a/NEWS
+++ b/NEWS
@@ -15,31 +15,28 @@
operators are supported, as well as a few useful functions. See the
README.
-- If the environment variable LEDGER is used, a binary cache of that
- current ledger will be kept, to speed up later queries of the same
- data. The default location is in ~/.ledger, but this can be changed
- with the environment variable LEDGER_CACHE. This only happens if no
- "-f" flag was seen (i.e., if the LEDGER environment variable is
- used).
+- If the environment variable LEDGER (or LEDGER_FILE) is used, a
+ binary cache of that ledger will be kept in ~/.ledger (or
+ LEDGER_CACHE), to speed up later queries of the same data. This
+ happens only when "-f" or "--file" is not used.
-- New "-o FILE" option will output data to the given FILE. If FILE is
- "-", the output is the same as the default (stdout).
+- New options:
-- New -j and -J options replace the old -G (gnuplot) option. -j
- reports the values column in a way gnuplot can consume, and -J
- reports the totals column. An example can be found in
- scripts/report.
+ "-o FILE" outputs data to the given FILE. If "-", the output is the
+ same as the default (stdout).
-- New "-y DATEFMT" options will change the date format used throughout
- ledger. The default is "%Y/%m/%d".
+ -j and -J options replace previous -G (gnuplot) option. -j reports
+ the values column in a way gnuplot can consume, and -J reports the
+ totals column. An example can be found in scripts/report.
-- New -Y and -W options prints yearly and weekly subtotals, just as
- the -M option printed monthly subtotals in the previous version.
+ "-y DATEFMT" changes the date format used in register reports. The
+ default is "%Y/%m/%d".
-- New -w report will show cumulative totals for each of the days of
- the week.
+ -Y and -W print yearly and weekly subtotals, just as the -M option
+ printed monthly subtotals in the previous version.
+ -w shows cumulative totals for each of the days of the week.
-- New "-z INTERVAL" allows for more flexible interval reporting. The
+ "-z INTERVAL" allows more flexible interval reporting. The
sublanguage used will probably mature over time, but for now it
supports expression like:
@@ -48,9 +45,14 @@
every 3 quarters
weekly from 12/20
- Note that when using the "from" date, this does not constrain the
- report. It is only used for aligning report dates, for example if
- you wish weekly reporting to start on Sundays.
+ -O shows base values (this is the default, and old behavior)
+ -B shows basis cost of commodities
+ -V show market value of commodities
+ -G reports net gain/loss (shows commodity changes only)
+ -A reports average value (arithmetic mean)
+ -D reports deviation from the average value
+ -X reports the trend (average rate of change)
+ -Z reports the trend, with older values affecting the trend less
- Regexps specified after the command name now apply to account names
only. To search on a payee, use "--" to separate the two kinds of
@@ -79,19 +81,6 @@
option also works for balance reports, where it will show all the
account totals related to your query.
-- There are several new default reporting styles, which work both in
- the balance and register reports:
-
- -O Show base values (this is the default, and old behavior)
- -B Show the basis cost of commodities
- -V Show the last known market value of commodities
- -G Report net gain/loss (shows commodity changes only)
- -A Report average value (arithmetic mean)
- -D Report deviation from the average value
- -Z Report the trend (average rate of change)
- -W Report the trend, with older values affecting the trend less
- -X Report expected amount for the next transaction
-
- Automated transactions now use a single value expression as a
predicate. This means the new syntax is:
@@ -105,15 +94,10 @@
- The use of "+" and "-" in ledger files (to specify permanent
regexps) has been removed.
-- The -G switch no longer generates gnuplot-safe data. It now reports
- totals in terms of net gain/loss.
-
-- The -l flag now takes an expression string as a "predicate".
- Therefore, to equal the old behavior of "-l $100", you would use:
-
- -l AT<{$100}
+- -l now takes a value expression as the "calculation predicate".
+ To mimic the old behavior of "-l \$100", use: -d "AT<{\$100}"
-- The -S flag now takes an expression string, which yields the value
+- The -S flag takes a value expression string, which yields the value
that will be sorted on.
----------------------------------------------------------------------
diff --git a/README b/README
deleted file mode 100644
index 3b113e1c..00000000
--- a/README
+++ /dev/null
@@ -1,1550 +0,0 @@
-#comment -*-muse-*-
-#title Ledger: Command-Line Accounting
-
-<contents>
-
-* Introduction
-
-Ledger is an accounting tool with the moxie to exist. It provides no
-bells or whistles, and returns the user to the days before user
-interfaces were even a twinkling in their father's CRT.
-
-What it does offer is a double-entry accounting ledger with all the
-flexibility and muscle of its modern day cousins, without any of the
-fat. Think of it as the Bran Muffin of accounting tools.
-
-To use it, you need to start keeping a ledger. This is the basis of
-all accounting, and if you haven't started yet, now is the time to
-learn. The little booklet that comes with your checkbook is a ledger,
-so we'll describe double-entry accounting in terms of that.
-
-A checkbook ledger records debits (subtractions, or withdrawals) and
-credits (additions, or deposits) with reference to a single account:
-the checking account. Where the money comes from, and where it goes
-to, are described in the payee field, where you write the person or
-company's name. The ultimate aim of keeping a checkbook ledger is to
-know how much money is available to spend. That's really the aim of
-all ledgers.
-
-What computers add is the ability to walk through these transactions,
-and tell you things about your spending habits; to let you devise
-budgets and get control over your spending; to squirrel away money
-into virtual savings account without having to physically move money
-around; etc. As you keep your ledger, you are recording information
-about your life and habits, and sometimes that information can start
-telling you things you aren't aware of. Such is the aim of all good
-accounting tools.
-
-The next step up from a checkbook ledger, is a ledger that keeps track
-of all your accounts, not just checking. In such a ledger, you record
-not only who gets paid -- in the case of a debit -- but where the
-money came from. In a checkbook ledger, its assumed that all the
-money comes from your checking account. But in a general ledger, you
-write transaction two-lines: the source account and target account.
-*There must always be a debit from at least one account for every
-credit made to another account*. This is what is meant by
-"double-entry" accounting: the ledger must always balance to zero,
-with an equal number of debits and credits.
-
-For example, let's say you have a checking account and a brokerage
-account, and you can write checks from both of them. Rather than keep
-two checkbooks, you decide to use one ledger for both. In this
-general ledger you need to record a payment to Pacific Bell for your
-monthly phone bill. The cost is $23.00, let's say, and you want to
-pay it from your checking account. In the general ledger you need to
-say where the money came from, in addition to where it's going to.
-The entry might look like this:
-
-<example>
-9/29 BAL Pacific Bell $-200.00 $-200.00
- Equity:Opening Balances $200.00
-9/29 BAL Checking $100.00 $100.00
- Equity:Opening Balances $-100.00
-9/29 100 Pacific Bell $23.00 $223.00
- Checking $-23.00 $77.00
-</example>
-
-The first line shows a payment to Pacific Bell for $23.00. Because
-there is no "balance" in a general ledger -- it's always zero -- we
-write in the total balance of all payments to "Pacific Bell", which
-now is $223.00 (previously the balance was $200.00). This is done by
-looking at the last entry for "Pacific Bell" in the ledger, adding
-$23.00 to that amount, and writing the total in the balance column.
-And the money came from "Checking" -- a withdrawal of $23.00 -- which
-leaves the ending balance in "Checking" at $77.00. This is a very
-manual procedure; but that's where computers come in...
-
-The transaction must balance to $0: $23 went to Pacific Bell, $23 came
-from Checking. There is nothing left over to be accounted for, since
-the money has simply moved from one account to another. This is the
-basis of double-entry accounting: that money never pops in or out of
-existence; it is always a transaction from one account to another.
-
-Keeping a general ledger is the same as keeping two separate ledgers:
-One for Pacific Bell and one for Checking. In that case, each time a
-payment is written into one, you write a corresponding withdrawal into
-the other. This makes it easier to write in a "running balance",
-since you don't have to look back at the last time the account was
-referenced -- but it also means having a lot of ledger books, if you
-deal with multiple accounts.
-
-Enter the beauty of computerized accounting. The purpose of the
-Ledger program is to make general ledger accounting simple, by keeping
-track of the balances for you. Your only job is to enter the
-transactions. If a transaction does not balance, Ledger will display
-an error and indicate which transaction is wrong.[1]
-
-In summary, there are two aspects of Ledger use: updating the ledger
-data file, and using the Ledger tool to view the summarized result of
-your entries.
-
-And just for the sake of example -- as a starting point for those who
-want to dive in head-first -- here are the ledger entries from above,
-formatting as the ledger program wishes to see them:
-
-<example>
-; Set the year for subsequent entries to 2004
-Y 2004
-
-9/29 Pacific Bell
- Payable:Pacific Bell $-200.00
- Equity:Opening Balances
-
-9/29 Checking
- Accounts:Checking $100.00
- Equity:Opening Balances
-
-9/29 Pacific Bell
- Payable:Pacific Bell $23.00
- Accounts:Checking
-</example>
-
-The account balances and registers in this file, if saved as
-=ledger.dat=, could be reported using:
-
-<example>
-$ ledger -f ledger.dat balance
-$ ledger -f ledger.dat register checking
-$ ledger -f ledger.dat register bell
-</example>
-
-** Building the program
-
-Ledger is written in ANSI C++, and should compile on any platform. It
-depends only on the GNU multiprecision integer library (libgmp), and
-the Perl regular expression library (libpcre). It was developed using
-GNU make and gcc 3.3.
-
-To build and install once you have these libraries on your system,
-enter these commands:
-
-<example>
-make
-cp ledger /usr/local/bin
-</example>
-
-Note that when building GNUmp, make sure to pass the =--enable-cxx=
-flag to configure, otherwise it will not build **libgmpxx.a**. And in
-case it is not already on your system, **xmlparse.h** is part of the
-libxmltok package, and not expat.
-
-* Keeping a ledger
-
-The most important part of accounting is keeping a good ledger. If
-you have a good ledger, tools can be written to work whatever
-mathematically tricks you need to better understand your spending
-patterns. Without a good ledger, no tool, however smart, can help
-you.
-
-The Ledger program aims at making ledger entry as simple as possible.
-Since it is a command-line tool, it does not provide a user interface
-for keeping a ledger. If you like, you may use GnuCash to maintain
-your ledger, in which case the Ledger program will read GnuCash's data
-files directly. In that case, read the GnuCash manual now, and skip
-to the next chapter.
-
-If you are not using GnuCash, but a text editor to maintain your
-ledger, read on. Ledger has been designed to make data entry as
-simple as possible, by keeping the ledger format easy, and also by
-automagically determining as much information as possible based on the
-nature of your entries.
-
-For example, you do not need to tell Ledger about the accounts you
-use. Any time Ledger sees a transaction involving an account it knows
-nothing about, it will create it. If you use a commodity that is new
-to Ledger, it will create that commodity, and determine its display
-characteristics (placement of the symbol before or after the amount,
-display precision, etc) based on how you used the commodity in the
-transaction.
-
-Here is the Pacific Bell example from above, given as a Ledger
-transaction:
-
-<example>
-9/29 (100) Pacific Bell
- Expenses:Utilities:Telephone $23.00
- Assets:Checking $-23.00
-</example>
-
-As you can see, it is very similar to what would be written on paper,
-minus the computed balance totals, and adding in account names that
-work better with Ledger's scheme of things. In fact, since Ledger is
-smart about many things, you don't need to specify the balanced
-amount, if it is the same as the first line:
-
-<example>
-9/29 (100) Pacific Bell
- Expenses:Utilities:Telephone $23.00
- Assets:Checking
-</example>
-
-For this entry, Ledger will figure out that $-23.00 must come from
-"Assets:Checking" in order to balance the entry.
-
-** Stating where money goes
-
-Accountants will talk of `credits' and `debits', but their meaning is
-often different from the layman's definitions. To avoid this semantic
-overloading, we will refer to subtractions and additions. See
-[[README#DtAC]["Differences to Accounting Conventions"]] for how to
-reconcile the two systems.
-
-Recall that every transaction will involve two or more accounts.
-Money is transferred from one group of accounts to another group. To
-record the transaction, *subtract* an amount from the source
-accounts, and *add* the same amount to the target accounts.
-
-In order to write the Ledger entry correctly, you must determine where
-the money comes from, and where it goes to. For example, when you are
-paid, in order to add to your bank account, you must subtract from an
-income account:
-
-<example>
-9/29 My Employer
- Assets:Checking $500.00
- Income:Salary $-500.00
-</example>
-
-But wait, you say, why is the Income a negative figure? And when you
-look at the balance totals for your ledger, you will certainly be
-surprised to see Expenses as a positive figure, and Income as a
-negative figure. Isn't that the opposite of how it should look?
-
-It may take getting used to, but to properly use a general ledger you
-will need to think in terms of money flows. Rather than Ledger
-"fixing" the minus signs, let's understand why they are there.
-
-When you earn money, the money has to come from somewhere. Let's call
-that somewhere "society". In order for society to give you an income,
-you must take money away (withdraw) from society in order to put it
-into (make a payment to) your bank. When you then spend that money,
-it leaves your bank account (a withdrawal) and goes back to society (a
-payment). This is why Income will appear negative -- it reflects the
-money you have drawn from society -- and why Expenses will be positive
--- it is the amount you've given back. These additions and
-subtractions will always cancel each other out in the end, because you
-don't have the ability to create new money: it must always come from
-somewhere, and in the end must always leave. This is the beginning of
-economy, after which the explanation gets terribly difficult.
-
-Based on that explanation, here's another way to look at your balance
-report: every negative figure means that that account or person or
-place has less money now than when you started your ledger; and every
-positive figure means that that account or person or place has more
-money now that when you started your ledger. Make sense?
-
-** Assets and Liabilities
-
-Assets are money that you have, and Liabilities are money that you
-owe. "Liabilities" is just a more inclusive name for Debts.
-
-An Asset is typically increased by transferring money from an Income
-account, such as when you get paid. Here is a typical entry:
-
-<example>
-2004/09/29 My Employer
- Assets:Checking $500.00
- Income:Salary
-</example>
-
-Money, here, is coming from an Income account belonging to "My
-Employer", and is being transferred to an account that belongs to you.
-The money is now yours, which makes it an asset.
-
-Liability accounts track money you owe to others. They come into play
-whenever you borrow money to buy something, or if you owe someone
-money. The usual way a liability is changed is by expending money,
-thus transferring it to an Expenses account. For example:
-
-<example>
-2004/09/30 Restaurant
- Expenses:Dining $25.00
- Liabilities:MasterCard
-</example>
-
-Your account balance will now show $25 spent on Dining, and a
-corresponding $25 owed on your MasterCard. The MasterCard liability
-will show up as negative, since it offsets the value of your assets.
-*The combined total of your Assets and Liabilities is your net worth*.
-To see your current net worth, use this command:
-
-<example>
-$ ledger balance ^assets ^liabilities
-</example>
-
-Relatedly, your Income accounts will show up negative, because they
-transfer money *from* an account in order to increase your assets. Your
-Expenses accounts will show up positive, because that is where the
-money went. The combined total your Income and Expenses is your cash
-flow. A negative cash flow means that you are spending more cash
-than you make. To see your current cash flow, use this command:
-
-<example>
-$ ledger balance ^income ^expenses
-</example>
-
-Often, it is only important to view your income and expenses when
-asking questions like, "Where did my money go? Am I spending too much
-on X? Am I making enough to cover my expenses?" But most of the
-time, you will usually want to ask other questions like, "Is there
-enough money in my checking account to cover my next credit card
-bill?" For these reasons, I recommend creating a script that removes
-Income, Expenses, and Equity by default from your basic balance
-report. The provided script "bal" does this for you, as well as
-making it easier to run the balance command:
-
-<example>
-$ bal
-</example>
-
-To use this script, it must be copied from the **scripts** directory in
-the ledger distribution, to a directory along your =PATH=. Also, you
-must set the environment variable =LEDGER= to point to your main
-ledger file.
-
-Another common question to ask of your expenses is: How much do I
-spend each month on X? Ledger provides a simple way of displaying
-monthly totals for any account. Here is an example that summarizes
-monthly automobile expenses:
-
-<example>
-$ ledger -M register expenses:auto
-</example>
-
-This assumes, of course, that you use accounts like Expenses:Auto:Gas
-and Expenses:Auto:Repair.
-
-*** Tracking reimbursable expenses
-
-Sometimes you will want to spend money on behalf of someone else,
-which will eventually get repaid. Since the money is still "yours",
-it is really an asset. And since the expenditure was for someone
-else, you don't want it contaminating your Expenses reports. You will
-need to keep an account for tracking reimbursements.
-
-This is fairly easy to do in ledger. When spending the money, spend
-it *to* your Assets:Reimbursements, using a different account for each
-person or business that you spend money for. For example:
-
-<example>
-2004/09/29 Circuit City
- Assets:Reimbursements:Company XYZ $100.00
- Liabilities:MasterCard
-</example>
-
-This shows that you spent $100.00 on your MasterCard at Circuit City,
-but that the expense was made on behalf of Company XYZ. Later, when
-Company XYZ pays you back, you will transfer the money from your
-reimbursement account to a regular asset account:
-
-<example>
-2004/09/29 Company XYZ
- Assets:Checking $100.00
- Assets:Reimbursements:Company XYZ
-</example>
-
-This deposits the money owed from Company XYZ into your checking
-account, presumably because they paid you back with a check.
-
-But what to do if you run your own business, and you want to keep
-track of expenses made on your own behalf, while still tracking
-everything in a single ledger file? This is more complex, because you
-need to track two separate things: 1) The fact that the money should
-be reimbursed to you, and 2) What the expense account was, so that you
-can later determine where your company is spending its money.
-
-This kind of transaction is best handled with mirrored transactions in
-two different files, one for your personal accounts, and one for your
-company accounts. But keeping them in one file involves the same
-kinds of transactions, so those are what is shown here. First, the
-personal entry, which shows the need for reimbursement:
-
-<example>
-2004/09/29 Circuit City
- Assets:Reimbursements:Company XYZ $100.00
- Liabilities:MasterCard
-</example>
-
-This is the same as above, except that you own Company XYZ, and are
-keeping track of its expenses in the same ledger file. This entry
-should be immediately followed by an equivalent entry, which shows the
-kind of expense, and also notes the fact that $100.00 is now payable
-to you:
-
-<example>
-2004/09/29 Circuit City
- Company XYZ:Expenses:Computer:Software $100.00
- Company XYZ:Accounts Payable:Your Name
-</example>
-
-This second entry shows that Company XYZ has just spent $100.00 on
-software, and that this $100.00 came from Your Name, which must be
-paid back.
-
-These two entries can also be merged, to make things a little clearer.
-Note that all amounts must be specified now:
-
-<example>
-2004/09/29 Circuit City
- Assets:Reimbursements:Company XYZ $100.00
- Liabilities:MasterCard $-100.00
- Company XYZ:Expenses:Computer:Software $100.00
- Company XYZ:Accounts Payable:Your Name $-100.00
-</example>
-
-To "pay back" the reimbursement, just reverse the order of everything,
-except this time drawing the money from a company asset, paying it to
-accounts payable, and then drawing it again from the reimbursement
-account, and paying it to your personal asset account. It's easier
-shown than said:
-
-<example>
-2004/10/15 Company XYZ
- Assets:Checking $100.00
- Assets:Reimbursements:Company XYZ $-100.00
- Company XYZ:Accounts Payable:Your Name $100.00
- Company XYZ:Assets:Checking $-100.00
-</example>
-
-And now the reimbursements account is paid off, accounts payable is
-paid off, and the $100.00 has been effectively transferred from the
-company's checking account to your personal checking account. The
-money simply "waited" -- in both Assets:Reimbursements:Company XYZ,
-and Company XYZ:Accounts Payable:Your Name -- until such time as it
-could be paid off.
-
-The value of tracking expenses from both sides like that is that you
-do not contaminate your personal expense report with expenses made on
-behalf of others, while at the same time making it possible to
-generate accurate reports of your company's expenditures. It is more
-verbose than just paying for things with your personal assets, but it
-gives you a very accurate information trail.
-
-The advantage to keep these doubled entries together is that they
-always stay in sync. The advantage to keeping them apart is that it
-clarifies the transfer's point of view. To keep the transactions in
-separate files, just separate the two entries that were joined above.
-For example, for both the expense and the pay-back shown above, the
-following four entries would be created. Two in your personal ledger
-file:
-
-<example>
-2004/09/29 Circuit City
- Assets:Reimbursements:Company XYZ $100.00
- Liabilities:MasterCard $-100.00
-
-2004/10/15 Company XYZ
- Assets:Checking $100.00
- Assets:Reimbursements:Company XYZ $-100.00
-</example>
-
-And two in your company ledger file:
-
-<example>
-@ Company XYZ
-
-2004/09/29 Circuit City
- Expenses:Computer:Software $100.00
- Accounts Payable:Your Name $-100.00
-
-2004/10/15 Company XYZ
- Accounts Payable:Your Name $100.00
- Assets:Checking $-100.00
-
-@@
-</example>
-
-(Note: The @ above command means that all accounts mentioned in the
-file are children of the specified account. In this case it means
-that all activity in file relates to Company XYZ).
-
-After creating these entries, you will always know that $100.00 was
-spent using your MasterCard on behalf of Company XYZ, and that Company
-XYZ spent the money on computer software and paid it back about two
-weeks later.
-
-** Commodities and Currencies
-
-Ledger makes no assumptions about the commodities you use; it only
-requires that you specify a commodity. The commodity may be any
-non-numeric string that does not contain a period, comma, forward
-slash or at-sign. It may appear before or after the amount, although
-it is assumed that symbols appearing before the amount refer to
-currencies, while non-joined symbols appearing after the amount refer
-to commodities. Here are some valid currency and commodity
-specifiers:
-
-<example>
-$20.00 ; currency: twenty US dollars
-40 AAPL ; commodity: 40 shares of Apple stock
-60 DM ; currency: 60 Deutsch Mark
-£50 ; currency: 50 British pounds
-50e ; currency: 50 Euros (use appropriate symbol)
-</example>
-
-Ledger will examine the first use of any commodity to determine how
-that commodity should be printed on reports. It pays attention to
-whether the name of commodity was separated from the amount, whether
-it came before or after, the precision used in specifying the amount,
-whether thousand marks were used, etc. This is done so that printing
-the commodity looks the same as the way you use it.
-
-An account may contain multiple commodities, in which case it will
-have separate totals for each. For example, if your brokerage account
-contains both cash, gold, and several stock quantities, the balance
-might look like:
-
-<example>
- $200.00
-100.00 AU
- AAPL 40
- BORL 100
- FEQTX 50 Assets:Brokerage
-</example>
-
-This balance report shows how much of each commodity is in your
-brokerage account.
-
-Sometimes, you will want to know the current street value of your
-balance, and not the commodity totals. For this to happen, you must
-specify what the current price is for each commodity. The price can
-be in any commodity, in which case the balance will be computed in
-terms of that commodity. The usual way to specify prices is with a
-file of price settings, which might look like this:
-
-<example>
-AU=$357.00
-AAPL=$37
-BORL=$19
-FEQTX=$32
-</example>
-
-Specify the prices file using the =-p= option:
-
-<example>
-ledger -p prices.db balance brokerage
-</example>
-
-Now the balance for your brokerage account will be given in US
-dollars, since the prices database has specified conversion factors
-from each commodity into dollars:
-
-<example>
-$40880.00 Assets:Brokerage
-</example>
-
-You can convert from any commodity to any other commodity. Let's say
-you had $5000 in your checking account, and for whatever reason you
-wanted to know many ounces of gold that would buy. If gold is
-currently $357 per ounce, then each dollar is worth 1/357 AU:
-
-<example>
-ledger -p "$=0.00280112 AU" balance checking
-</example>
-
-<example>
-14.01 AU Assets:Checking
-</example>
-
-$5000 would buy 14 ounces of gold, which becomes the new display
-commodity since a conversion factor was provided.
-
-Commodities conversions can also be chained, up to a depth of 10.
-Here is a sample prices database that uses chaining:
-
-<example>
-AAPL=$15
-$=0.00280112 AU
-AU=300 Euro
-Euro=MD 0.75
-</example>
-
-This is a roundabout way of reporting AAPL shares in their Deutsch
-Mark equivalent.
-
-*** Commodity price histories
-
-Whenever a commodity is purchased using a different commodity (such as
-a share of common stock using dollars), it establishes a price for
-that commodity on that day. It is also possible, by recording price
-details in a ledger file, to specify other prices for commodities at
-any given time. Such price entries might look like those below:
-
-<example>
-P 2004/06/21 02:17:58 TWCUX $27.76
-P 2004/06/21 02:17:59 AGTHX $25.41
-P 2004/06/21 02:18:00 OPTFX $39.31
-P 2004/06/21 02:18:01 FEQTX $22.49
-P 2004/06/21 02:18:02 AAPL $32.91
-</example>
-
-By default, ledger will not consider commodity prices when generating
-its various reports. It will always report balances in terms of the
-commodity total, rather than the current value of those commodities.
-To enable pricing reports, several options are possible:
-
-**-P FILE** ::
- With this option, or if the environment variable =PRICE_HIST= is
- set, pricing information obtained from the Internet will be kept
- in this file. Also, this file will be read after all other ledger
- files are read, so that full history information is available for
- reports.
-
-**-O** ::
- Report commodity totals only, not their market value or basis cost.
-
-**-V** ::
- Report commodity values in terms of their last known market price.
-
-**-B** ::
- Report commodities in terms of their "basis cost", or what they cost
- at time of purchase. Thus, totals in the register and balance
- report reflect the total amount spent.
-
-**-G** ::
- Report commodities in terms of their net gain, which is: the market
- value minus the cost basis. A balance report using this option
- shows very quickly the performance of investments.
-
-**-Q** ::
- When needed (see the =-L= option) pricing quotes are obtained by
- calling the script =getquote= (a sample Perl script is provided, but
- the interface is kept simple so replacements may be made).
-
-**-L MINS** ::
- When using the =-Q= flag, new quotes are obtained only if current
- pricing data is older than MINS minutes. The default is one day,
- or 1440 minutes.
-
-**-p ARG** ::
- If a string, such as "COMM=$1.20", the commodity COMM will be
- reported only in terms of the conversion factor, which supersedes
- all other pricing histories for that commodity. This can be used to
- perform arbitrary value substitutions. For example, to report the
- value of your dollars in terms of the ounces of gold they would buy,
- use: -p "$=0.00280112 AU" (or whatever the current exchange rate
- is).
-
-Note that the =-B=, =-O=, =-V=, and =-G= are mutually exclusive.
-
-** Accounts and Inventories
-
-Since Ledger's accounts and commodity system is so flexible, you can
-have accounts that don't really exist, and use commodities that no one
-else recognizes. For example, let's say you are buying and selling
-various items in EverQuest, and want to keep track of them using a
-ledger. Just add items of whatever quantity you wish into your
-EverQuest account:
-
-<example>
-9/29 Get some stuff at the Inn
- Places:Black's Tavern -3 Apples
- Places:Black's Tavern -5 Steaks
- EverQuest:Inventory
-</example>
-
-Now your EverQuest:Inventory has 3 apples and 5 steaks in it. The
-amounts are negative, because you are taking *from* Black's Tavern in
-order to add to your Inventory account. Note that you don't have to
-use "Places:Black's Tavern" as the source account. You could use
-"EverQuest:System" to represent the fact that you acquired them
-online. The only purpose for choosing one kind of source account over
-another is for generate more informative reports later on. The more
-you know, the better analysis you can perform.
-
-If you later sell some of these items to another player, the entry
-would look like:
-
-<example>
-10/2 Strum Brightblade
- EverQuest:Inventory -2 Steaks
- EverQuest:Inventory 15 Gold
-</example>
-
-Now you've turned 2 steaks into 15 gold, courtesy of your customer,
-Strum Brightblade.
-
-** Understanding Equity
-
-The most confusing entry in any ledger will be your equity account --
-because starting balances can't come out of nowhere.
-
-When you first start your ledger, you will likely already have money
-in some of your accounts. Let's say there's $100 in your checking
-account; then add an entry to your ledger to reflect this amount.
-Where will money come from? The answer: your equity.
-
-<example>
-10/2 Opening Balance
- Assets:Checking $100.00
- Equity:Opening Balances
-</example>
-
-But what is equity? You may have heard of equity when people talked
-about house mortgages, as "the part of the house that you own".
-Basically, equity is like the value of something. If you own a car
-worth $5000, then you have $5000 in equity in that car. In order to
-turn that car (a commodity) into a cash flow, or a credit to your bank
-account, you will have to debit the equity by selling it.
-
-When you start a ledger, you are probably already worth something.
-Your net worth is your current equity. By transferring the money in
-the ledger from your equity to your bank accounts, you are crediting
-the ledger account based on your prior equity value. That is why,
-when you look at the balance report, you will see a large negative
-number for Equity that never changes: Because that is what you were
-worth (what you debited from yourself in order to start the ledger)
-before the money started moving around. If the total positive value
-of your assets is greater than the absolute value of your starting
-equity, it means you are making money.
-
-Clear as mud? Keep thinking about it. Until you figure it out, put
-"=-- -Equity=" at the end of your balance command, to remove the
-confusing figure from the totals.
-
-** Dealing with Petty Cash
-
-Something that stops many people from keeping a ledger at all is the
-insanity of tracking small cash expenses. They rarely generate a
-receipt, and there are often a lot of small transactions, rather than
-a few large ones, as with checks.
-
-One solution is: don't bother. Move your spending to a debit card,
-but in general ignore cash. Once you withdraw it from the ATM, mark
-it as already spent to an "Expenses:Cash" category:
-
-<example>
-2004/03/15 ATM
- Expenses:Cash $100.00
- Assets:Checking
-</example>
-
-If at some point you make a large cash expense that you want to track,
-just "move" the amount of the expense from "Expenses:Cash" into the
-target account:
-
-<example>
-2004/03/20 Somebody
- Expenses:Food $65.00
- Expenses:Cash
-</example>
-
-This way, you can still track large cash expenses, while ignoring all
-of the smaller ones.
-
-** Archiving previous years
-
-After a while, your ledger can get to be pretty large. While this
-will not slow down the ledger program much -- it's designed to process
-ledger files very quickly -- things can start to feel "messy"; and
-it's a universal complaint that when finances feel messy, people avoid
-them.
-
-Thus, archiving the data from previous years into their own files can
-offer a sense of completion, and freedom from the past. But how to
-best accomplish this with the ledger program? There are two commands
-that make it very simple: "print", and "equity".
-
-Let's take an example file, with data ranging from year 2000 until
-2004. We want to archive years 2000 and 2001 to their own file,
-leaving just 2003 and 2004 in the current file. So, use "print" to
-output all the earlier entries to a file called =ledger-old.dat=.
-(Keeping in mind that the ending date is not inclusive, which is why
-2002 is mentioned in the following command):
-
-<example>
-$ ledger -f ledger.dat -b 2000/1/1 -e 2002/1/1 print \
- > ledger-old.dat
-</example>
-
-To delete older data from the current ledger file, use "print" again,
-this time specifying year 2002 as the starting date:
-
-<example>
-$ ledger -f ledger.dat -b 2002/1/1 print > x
-$ mv x ledger.dat
-</example>
-
-However, now the current file contains *only* transactions from 2002
-onward, which will not yield accurate present-day balances, because
-the net income from previous years is no longer being tallied. To
-compensate for this, we must append an equity report for the old
-ledger at the beginning of the new one:
-
-<example>
-$ ledger -f ledger-old.dat equity > equity.dat
-$ cat equity.dat ledger.dat > x
-$ mv x ledger.dat
-$ rm equity.dat
-</example>
-
-Now the balances reported from =ledger.dat= are identical to what they
-were before the data was split.
-
-How often should you split your ledger? You never need to, if you
-don't want to. Even eighty years of data will not slow down ledger
-much -- and that's just using present day hardware! Or, you can keep
-the previous and current year in one file, and each year before that
-in its own file. It's really up to you, and how you want to organize
-your finances. For those who also keep an accurate paper trail, it
-might be useful to archive the older years to their own files, then
-burn those files to a CD to keep with the paper records -- along with
-any electronic statements received during the year. In the arena of
-organization, just keep in mind this maxim: Do whatever keeps you
-doing it.
-
-** Virtual transactions
-
-A virtual transaction is when you, in your mind, see money as moving
-to a certain place, when in reality that money has not moved at all.
-There are several scenarios in which this type of tracking comes in
-handy, and each of them will be discussed in detail.
-
-To enter a virtual transaction, surround the account name in
-parentheses. This form of usage does not need to balance. However,
-if you want to ensure the virtual transaction balances with other
-virtual transactions in the same entry, use square brackets. For
-example:
-
-<example>
-10/2 Paycheck
- Assets:Checking $1000.00
- Income:Salary $-1000.00
- (Debt:Alimony) $200.00
-</example>
-
-In this example, after receiving a paycheck an alimony debt is
-increased -- even though no money has moved around yet.
-
-<example>
-10/2 Paycheck
- Assets:Checking $1000.00
- Income:Salary $-1000.00
- [Savings:Trip] $200.00
- [Assets:Checking] $-200.00
-</example>
-
-In this example, $200 has been deducted from checking toward savings
-for a trip. It will appear as though the money has been moved from
-the account into "Savings:Trip", although no money has actually moved
-anywhere.
-
-When balances are displayed, virtual transactions will be factored in.
-To view balances without any virtual balances factored in, using the
-"-R" flag, for "Reality".
-
-Write about: Saving for a Special Occasion; Keeping a Budget; Tracking
-Allocated Funds.
-
-** Automated transactions
-
-As a Bahá'í, I need to compute Huqúqu'lláh whenever I acquire assets.
-The exact details of this are a bit complex, so if you have further
-interest, please consult the Web.
-
-For any fellow Bahá'ís out there who want to track Huqúqu'lláh, the
-Ledger tool makes this extremely easy. Just set up the following
-automated transaction at the top of your ledger file:
-
-<example>
-; These entries will compute Huqúqu'lláh based on the
-; contents of the ledger.
-
-= ^Income:
-= ^Expenses:Rent$
-= ^Expenses:Furnishings
-= ^Expenses:Business
-= ^Expenses:Taxes
-= ^Expenses:Insurance
- (Liabilities:Huqúqu'lláh) 0.19
-</example>
-
-This automated transaction works by looking at each transaction
-appearing afterward in the ledger file. If any match the account
-regexps, occurring after the equal signs above, 19% of the value of
-that transaction is applied to the "Liabilities:Huqúqu'lláh" account.
-So if $1000 is earned through Income:Salary, which is seen as a debit
-from Income, a debit of $190 is applied to "Liabilities:Huqúqu'lláh";
-if $1000 is spent on Rent -- seen as a credit to the Expense account
--- a credit of $190 is applied to Huqúqu'lláh. The ultimate balance
-of Huqúqu'lláh reflects how much must be paid to that account in order
-to balance it to zero.
-
-When you're ready to pay, just write a check directly to the account
-"Liabilities:Huqúqu'lláh":
-
-<example>
-2003/01/01 (101) Baha'i Huqúqu'lláh Trust
- Liabilities:Huqúqu'lláh $1,000.00
- Assets:Checking
-</example>
-
-That's it. To see how much Huqúq is currently owed based on your
-ledger entries, use:
-
-<example>
-ledger balance Liabilities:Huqúq
-</example>
-
-
-** Differences to Accounting Conventions
-#DtAC
-
-If you are an accountant, or you are familiar with accounting
-terminology, then you might be tearing your hair out after reading the
-above. Please don't!
-
-Ledger is intended to make people comfortable with their finances; to
-help them better control the flow of their money. Contemporary
-accounting practices, on the other hand, often seem counter-intuitive
-and confusing to the layman. To make Ledger more accessible, it
-avoids the use of standard accounting conventions and terminology.
-However, Ledger is flexible enough that you may interpret what is
-happening however you wish.
-
-Most probably, the following section will confuse you, and you should
-skip it if you've managed to understand everything so far. However,
-if you intend to communicate your accounting practices to a
-professional accountant, the following explanations may be useful.
-
-The entity ::
-The individual or organisation under consideration: the someone or
-something on whose behalf you are accounting. Probably you.
-
-Assets ::
-Future economic benefits controlled by the entity as a result of a
-past transaction or event.
-
-Liabilities ::
-Future sacrifices of economic benefits that the entity is obliged to
-make as a result of a past transaction or event.
-
-The format of the data files used by Ledger is more akin to a general
-journal than a ledger. In an accounting ledger, transactions are
-grouped by account. In a general journal, transactions are commonly
-listed in chronological order.
-
-Often "cash" is used to refer to a liquid savings account at a bank,
-rather than the physical notes and coins you may withdraw.
-
-In general, an "addition" in Ledger is an accounting debit, and a
-"subtraction" in Ledger is an accounting credit. The following table
-shows the "normal" balances for the different types of accounts.
-Accountants avoid using negative balances where possible, instead
-prefering a positive amount in "credit" balance.
-
-System || Asset || Liability || Income || Expense
-
-**Accounting** | debit | credit | credit | debit
-**Ledger** | positive | negative | negative | positive
-
-That's correct: accountants call an addition to their cash a debit!
-However, from the bank's perspective it is a credit: the accountant's
-cash is a liability for the bank. Consequently, payments to the
-account will show up as credits on his bank statement.
-
-** Using Emacs to Keep Your Ledger
-
-In the Ledger tarball is an Emacs module, =ledger.el=. This module
-makes the process of keeping a text ledger much easier for Emacs
-users. I recommend putting this at the top of your ledger file:
-
-<example>
-; -*-ledger-*-
-</example>
-
-And this in your =.emacs= file, after copying =ledger.el= to your
-site-lisp directory:
-
-<example>
-(load "ledger")
-</example>
-
-Now when you edit your ledger file, it will be in =ledger-mode=.
-=ledger-mode= adds the following commands:
-
-C-c C-a ::
- For quickly adding new entries based on the form of older ones
- (see previous section).
-
-C-c C-c ::
- Toggles the "cleared" flag of the transaction under point.
-
-C-c C-r ::
- Reconciles an account by displaying the transactions in another
- buffer, where simply hitting the spacebar will toggle the cleared
- flag of the transaction in the ledger. It also displays the current
- cleared balance for the account in the modeline.
-
-** Using GnuCash to Keep Your Ledger
-
-The Ledger tool is fast and simple, but it offers no custom method for
-actually editing the ledger. It assumes you know how to use a text
-editor, and like doing so. Perhaps an Emacs mode will appear someday
-soon to make editing Ledger's data files much easier.
-
-Until then, you are free to use GnuCash to maintain your ledger, and
-the Ledger program for querying and reporting on the contents
-of that ledger. It takes a little longer to parse the XML data format
-that GnuCash uses, but the end result is identical.
-
-Then again, why would anyone use a Gnome-centric, 35 megabyte behemoth
-to edit their data, and a 65 kilobyte binary to query it...
-
-** Using timeclock to record billable time
-
-The timeclock tool makes it easy to track time events, like clocking
-into and out of a particular job. These events accumulate in a
-timelog file.
-
-Each in/out event may have an optional description. If the "in"
-description is a ledger account name, these in/out pairs may be viewed
-as virtual transactions, adding time commodities (hours) to that
-account.
-
-For example, the command-line version of the timeclock tool (which is
-written in Python) could be used to begin a timelog file like:
-
-<example>
-$ export TIMELOG=$HOME/.timelog
-$ ti ClientOne category
-$ sleep 10
-$ to waited for ten seconds
-</example>
-
-The **.timelog** file now contains:
-
-<example>
-i 2004/10/06 15:21:00 ClientOne category
-o 2004/10/06 15:21:10 waited for ten seconds
-</example>
-
-Ledger can parse this directly, as if it had seen the following ledger
-entry:
-
-<example>
-2004/10/06 category
- (ClientOne) 0.00277h
-</example>
-
-In other words, the timelog event pair is seen as adding 0.00277h (ten
-seconds) worth of time to the ClientOne account. This would be
-considered billable time, which later could be invoiced and credited
-to accounts receivable:
-
-<example>
-2004/11/01 (INV#1) ClientOne, Inc.
- Receivable:ClientOne $0.10
- ClientOne -0.00277h @ $35.00
-</example>
-
-The above transaction converts the clocked time into an invoice for
-the time spent, at an hourly rate of $35. Once the invoice is paid,
-the money is deposited from the receivable account into a checking
-account:
-
-<example>
-2004/12/01 ClientOne, Inc.
- Assets:Checking $0.10
- Receivable:ClientOne
-</example>
-
-And now the time spent has been turned into hard cash in the checking
-account.
-
-The advantage to using timeclock and invoicing to bill time is that
-you will always know, by looking at the balance report, exactly how
-much unbilled and unpaid time you've spent working for any particular
-client.
-
-I like to =!include= my timelog at the top of my company's accounting
-ledger, with the attached prefix "Billable":
-
-<example>
-; -*-ledger-*-
-
-; This is the ledger file for my company. But first, include the
-; timelog data, entering all of the time events within the umbrella
-; account "Billable".
-
-!include /home/johnw/.timelog Billable
-
-; Here follows this fiscal year's transactions for the company.
-
-2004/11/01 (INV#1) ClientOne, Inc.
- Receivable:ClientOne $0.10
- Billable:ClientOne -0.00277h @ $35.00
-
-2004/12/01 ClientOne, Inc.
- Assets:Checking $0.10
- Receivable:ClientOne
-</example>
-
-* Running Ledger
-
-Once you have an orderly and well-organized general ledger, the next
-step is to generate orderly and well-organized reports. This is where
-the Ledger command-line tool comes in. With it, you can balance your
-checkbook, see where your money is going, tell whether you've made a
-profit this year, and compute the present value of your retirement
-accounts. And all with the simplest of interfaces, the command-line.
-
-The most often used command will be the "balance" command:
-
-<example>
-export LEDGER=/home/johnw/doc/ledger.dat
-ledger balance
-</example>
-
-Here I've set my Ledger environment variable to point to where my
-ledger file is hiding. Thereafter, I needn't specify it again.
-
-The balance command prints out the summarized balances of all my
-top-level accounts, excluding sub-accounts. In order to see the
-balances for a specific account, just specify a regular expression
-after the balance command:
-
-<example>
-ledger balance expenses:food
-</example>
-
-This will show all the money that's been spent on food, since the
-beginning of the ledger. For food spending just this month
-(September), use:
-
-<example>
-ledger -d sep balance expenses:food
-</example>
-
-Or maybe I want to see all of my assets, in which case the -s (show
-sub-accounts) option comes in handy:
-
-<example>
-ledger balance -s
-</example>
-
-To exclude a particular account, use a regular expression with a
-leading minus sign. The following will show all expenses, but without
-food spending:
-
-<example>
-ledger balance expenses -food
-</example>
-
-If you want to show all accounts but for one account, remember to use
-"--" to separate the exclusion pattern from the options list:
-
-<example>
-ledger balance -- -equity
-</example>
-
-** File format
-
-The ledger file format is quite simple, but supports many options.
-These are summarized here.
-
-The initial character of each line determines what that line means,
-and how it should be parsed. The possibilities are:
-
-NUMBER ::
- A line starting with a number denotes a regular ledger entry. It
- may be followed by any number of lines that beginning whitespace, to
- denote account transactions. The format of the header line is:
-<example>
-DATE [*] [(CODE)] DESC
-</example>
-
-+ ::
- If a line begins with plus, it denotes an inclusion regexp that
- will always be considered, as if it had been specified by the user
- at the end of their command-line.
-
-**-** ::
- If a line begins with minus, it denotes an exclusion regexp that
- will always be considered, as if it had been specified by the user
- at the end of their command-line.
-
-**<verbatim>=</verbatim>** ::
- If a line begins with equals, it denotes an automated transaction.
- The next item on the line must be a regular expression. Any number
- of such lines may appear, with no intervening whitespace.
- Following this block of lines can be a list of account transactions
- preceded by whitespace.
-
-!WORD ::
- A line beginning with an exclamation mark denotes a command
- directive. It must be immediately followed by a word specifying
- which directories. At the moment, only =!include= is supported, for
- including the content of other ledger files into the current one.
-
-whitespace ::
- A line beginning with whitespace, which is not part of a regular or
- automated transaction, is ignored.
-
-; ::
- If a line begins with semicolon it is ignored. This is the
- preferred method of entering comments.
-
-Y NUM ::
- If a line begins with a capital Y, it denotes the year to be used
- for all subsequent entries that specify a date, whatever their type.
- This sets the "default year", which ordinarily is the current year
- at the time the program is run. Useful at the beginning of a file
- to specify the file's year.
-
-P DATE SYMBOL PRICE ::
- Capital P specifies a historical price for a commodity. Any such
- number of entries are allowed. These are usually found in a pricing
- history file (see the =-Q= option).
-
-C SYMBOL PRICE ::
- Capital C specifies a conversion price for a commodity. This has
- no reference to time, and always takes precedence over any
- historical price (even very current prices).
-
-N SYMBOL ::
- Capital N indicates that no implicit price conversions should be
- obtained for the given symbol. This means that no quotes will ever
- be downloaded for that symbol. Useful for a home currency, such as
- the dollar ($). Be aware that these pricing options will set the
- default reporting characteristics for a commodity. Thus it is
- recommended that pricing options occur only after all regular ledger
- entries have been parsed.
-
-i DATE TIME ACCOUNT [DESC] ::
- Lowercase (and capital) i indicate an time-in event. This will
- start accumulating hours in the account specified. Usually these
- entries are created in a timelog file by the timeclock program,
- which is distributed with ledger. There must be two spaces between
- the account name, and the optional description, if one is used.
-
-o DATE TIME ACCOUNT [DESC] ::
- Lowercase (and capital) o indicate an time-out event. This will
- accumulate hours in the account specified. Usually these entries
- are created in a timelog file by the timeclock program, which is
- distributed with ledger. There must be two spaces between the
- account name, and the optional description, if one is used.
-
-b, h ::
- Entries beginning with lowercase b and h are ignored. These are
- special entries used by timeclock, but ignored by ledger.
-
-** Command summary
-
-*** balance
-
-The "balance" command reports the current balance of any account.
-This command accepts a list of optional regexps, which will confine
-the balance report to only matching accounts. By default, the
-balances for all accounts will be printed. If an account contains
-multiple types of commodities, each commodity's total is separately
-reported.
-
-*** register
-
-The "register" command displays all the transactions occurring in a
-single account, line by line. The account regexp must be specified as
-the only argument to this command. If any regexps occur after the
-required account name, the register will contain only those
-transactions that match. Very useful for hunting down a particular
-transaction.
-
-The output from "register" is very close to what a typical checkbook,
-or single account ledger, would look like. It also shows a running
-balance. The final running balance of any register should always be
-the same as the current balance of that account.
-
-*** print
-
-The "print" command prints out ledger entries just as they appear in
-the original ledger. They will be properly formatted, and output in
-the most economic form possible. The "print" command also takes a
-list of optional regexps, which will cause only those transactions
-which match in some way to be printed.
-
-The "print" command is a handy way to clean up a ledger file whose
-formatting has gotten out of hand.
-
-*** equity
-
-Equity transactions are used to establish the starting value of an
-account. You might think of equity as the "ether" from which initial
-balances appear.
-
-*** price
-
-This commands displays the last known current price for a given
-commodity, using the specified end date for the cutoff (default is the
-present moment). It takes a list of regexps, which can match the
-commodities used in the ledger file. This command is helpful to
-quickly seeing the last current price for a specific commodity, or all
-commodities referenced by a ledger.
-
-*** entry
-
-The three most laborious tasks of keeping a ledger are: adding new
-entries, reconciling accounts, and generating reports. To address the
-first of these, there is a sub-command to ledger called "entry". It
-works on the principle that 80% of all transactions are variants of
-earlier transactions. Here's how it works:
-
-Let's say you have an old transaction of the following form:
-
-<example>
-2004/03/15 * Viva Italiano
- Expenses:Food $12.45
- Expenses:Tips $2.55
- Liabilities:MasterCard $-15.00
-</example>
-
-Now it's 2004/4/9, and you've just eating at Viva Italiano again. The
-exact amounts are different, but the overall form is the same. With
-the "entry" command you can type:
-
-<example>
-ledger entry 2004/4/9 viva food 11.00 tips 2.50
-</example>
-
-This will produce the following output:
-
-<example>
-2004/04/09 Viva Italiano
- Expenses:Food $11.00
- Expenses:Tips $2.50
- Liabilities:MasterCard $-13.50
-</example>
-
-This works by finding a transaction that matches the regexp "viva",
-and then assuming that any accounts or amounts you specify will be the
-same as that earlier transaction. If Ledger does not succeed in
-generating a new entry for you, it will print an error and set the
-exit code to 1.
-
-There is a shell script in the distribution called "entry", which
-simplifies the task of adding a new entry to your ledger, and then
-launches =vi= to let you confirm that the entry looks appropriate.
-
-** Using command options
-
-With all of the commands, various command-line options are allowed
-that will modify the behavior of the command in some way. And while
-the basic commands themselves are useful, you will often find
-yourselves adding option flags to the command-line to modify those
-commands.
-
-The command-line options always occur before the command word. This
-is done to distinguish them from the matching expressions that always
-occur after the command word. The basic form of any command is:
-
-<example>
-ledger [OPTIONS] COMMAND [MATCH]
-</example>
-
-Both the OPTIONS and MATCH expressions are optional. You could, for
-example, just use "ledger balance" without any modification. This
-would print the summarized total of all account types. But to get
-more specific reporting, or to change the way the output looks, you
-must use the options.
-
-*** Basic options
-
-The =--help= (=-h=) option causes ledger to print a summary of all the
-options, and what they are used for. This can be a handy way to
-remember which options do what. This help screen is also printed if
-ledger is run without a command.
-
-=--version= (=-v=) prints the current version of ledger and exits.
-This is useful for sending bug reports (to johnw@newartisans.com), to
-let the author know which version of ledger you are using.
-
-=--init FILE= (=-i FILE=) causes FILE to be read by ledger before any
-other ledger file. This file may not contain any transactions, but it
-may contain option settings. To specify options in the init file, use
-the same syntax as the command-line. Here's an example init file:
-
-<example>
---price-db ~/finance/.pricedb
-</example>
-
-Option settings on the command-line or in the environment always take
-precedence over settings in the init file.
-
-=--file FILE= (=-f FILE=) reads FILE as a ledger file. This command
-may be used multiple times. FILE may also be a list of file names
-separated by colons. Typically, the environment variable
-=LEDGER_FILE= is set, rather than using this command-line option.
-
-=--cache FILE= identifies FILE as the default binary cache file. That
-is, if the ledger files to be read are specified using the environment
-variable =LEDGER_FILE=, then whenever a command is finished a binary
-copy will be written to the specified cache, to speed up the loading
-time of subsequent queries. This filename can also be given using the
-environment variable =LEDGER_CACHE=, or by putting the option into
-your init file.
-
-=--output FILE= (=-o FILE=) redirects output from any command to
-=FILE=. By default, all output goes to standard output.
-
-*** Filtering options
-
-**-b DATE** ::
- Only consider entries occuring on or after the given date.
-
-**-e DATE** ::
- Only consider entries occuring before the given date. The date is
- not inclusive, so any entries occurring on that date will not be
- used.
-
-**-c** ::
- Only consider entries occurring on or before the current date.
-
-**-d DATE** ::
- Only consider entries fitting the given date mask. DATE in this
- case may be the name of a month, or a year, or a year and month,
- such as "2004/05". It's a shorthand for having to specify -b and -e
- together.
-
-**-C** ::
- Only consider entries whose cleared flag has been set. The default
- is to consider both.
-
-**-U** ::
- Show only uncleared transactions. The default is to consider both.
-
-**-l AMT** ::
- Limit balance reports to those which are greater than AMT.
-
-**-N REGEXP** ::
- If an account matches REGEXP, only display it in the balance report
- if its total is negative. Useful to avoid seeing credit in accounts
- where one cannot spend that credit, and it will soon become negative
- anyway (such as credit cards).
-
-**-R** ::
- Ignore all virtual transactions, and report only the real balance
- for each account.
-
-*** Output formatting options
-
-**-n** ::
- Do not show subtotals in the balance report, or split transactions
- in the register report.
-
-**-s** ::
- If an account has children, show them in the balance report.
-
-**-S** ::
- Sort the ledger after reading it. This may affect "register" and
- "print" output.
-
-**-E** ::
- Also show empty accounts in the balance totals report.
-
-**-F** ::
- Print full account names in all cases, such as "Assets:Checking"
- instead of just "Checking". Only used current by the "balance"
- command.
-
-**-M** ::
- When used with the "register" command, causes only monthly subtotals
- to appear. This can be useful for looking at spending patterns.
- TODO: Accept an argument specifying the period to use.
-
-**-A** ::
- Report totals in terms of the arithmetic mean (sum of all items
- divided by the count). This does not work when multiple commodities
- are used in the same account, in which case this option is ignored.
- This option works both for balance reports, and for register reports
- (where it displays the running total average). Be aware that in the
- balance report, parent account totals reflect the arithmetic mean of
- all the transactions -- not the mean average of the subaccount
- totals.
-
-**-T** ::
- Report totals in terms of the average deviation from the average
- value (i.e., the trend). The final total will indicate the amount
- over or above the average value which it is expected you will next
- spend/earn. When spending is regular, the trend will very slowly
- move to zero.
-
-**-X** ::
- Report totals in terms of the expected value of the next
- transaction. This is determined by adding the average deviation to
- the average value.
-
-**-W** ::
- Report totals in terms of a time-weighted trend. Whereas =-T=
- reports the exact value trend irrespective of when the transactions
- occurred, =-W= takes into account the time between entries. If a
- transaction occurs shortly after another, it will not affect the
- running trend as much as if it occurs very much later. This style
- of reports always adds a null transaction for the current date, so
- that a current lack of spending is taken into account.
-
-*** Commodity reporting options
-
-**-P FILE** ::
- With this option, or if the environment variable =PRICE_HIST= is
- set, pricing information obtained from the Internet will be kept
- in this file. Also, this file will be read after all other ledger
- files are read, so that full history information is available for
- reports.
-
-**-O** ::
- Report commodity totals only, not their market value or basis cost.
-
-**-V** ::
- Report commodity values in terms of their last known market price.
-
-**-B** ::
- Report commodities in terms of their "basis cost", or what they cost
- at time of purchase. Thus, totals in the register and balance
- report reflect the total amount spent.
-
-**-G** ::
- Report commodities in terms of their net gain, which is: the market
- value minus the cost basis. A balance report using this option
- shows very quickly the performance of investments.
-
-**-Q** ::
- When needed (see the =-L= option) pricing quotes are obtained by
- calling the script =getquote= (a sample Perl script is provided, but
- the interface is kept simple so replacements may be made).
-
-**-L MINS** ::
- When using the =-Q= flag, new quotes are obtained only if current
- pricing data is older than MINS minutes. The default is one day,
- or 1440 minutes.
-
-**-p ARG** ::
- If a string, such as "COMM=$1.20", the commodity COMM will be
- reported only in terms of the conversion factor, which supersedes
- all other pricing histories for that commodity. This can be used to
- perform arbitrary value substitutions. For example, to report the
- value of your dollars in terms of the ounces of gold they would buy,
- use: -p "$=0.00280112 AU" (or whatever the current exchange rate
- is).
-
-Footnotes:
-[1] In some special cases, it will automatically balance the entry
- for you.
diff --git a/binary.cc b/binary.cc
index 40e5d684..6c31f574 100644
--- a/binary.cc
+++ b/binary.cc
@@ -1,4 +1,5 @@
#include "ledger.h"
+#include "binary.h"
#include <vector>
#include <fstream>
@@ -16,6 +17,15 @@ namespace ledger {
const unsigned long binary_magic_number = 0xFFEED765;
static const unsigned long format_version = 0x0002000b;
+bool binary_parser_t::test(std::istream& in) const
+{
+ unsigned long magic;
+ in.read((char *)&magic, sizeof(magic));
+ in.seekg(0);
+
+ return magic == binary_magic_number;
+}
+
static std::vector<account_t *> accounts;
static account_t::ident_t ident;
static std::vector<commodity_t *> commodities;
@@ -118,7 +128,7 @@ entry_t * read_binary_entry(std::istream& in, journal_t * journal)
i < count;
i++) {
transaction_t * xact = read_binary_transaction(in, entry);
- entry->transactions.push_back(xact);
+ entry->add_transaction(xact);
}
return entry;
@@ -252,6 +262,14 @@ unsigned int read_binary_journal(std::istream& in,
return count;
}
+unsigned int binary_parser_t::parse(std::istream& in,
+ journal_t * journal,
+ account_t * master,
+ const std::string * original_file)
+{
+ return read_binary_journal(in, original_file ? *original_file : "",
+ journal, master);
+}
#if RELEASE_LEVEL >= ALPHA
#define write_binary_guard(in, id) { \
diff --git a/format.h b/format.h
index 9eaf53bc..dd578dbd 100644
--- a/format.h
+++ b/format.h
@@ -127,7 +127,6 @@ class format_transactions : public item_handler<transaction_t>
}
xact->dflags |= TRANSACTION_DISPLAYED;
}
- flush();
}
};
diff --git a/ledger.cc b/ledger.cc
index ff7c7502..72a5a15d 100644
--- a/ledger.cc
+++ b/ledger.cc
@@ -174,34 +174,4 @@ entry_t * journal_t::derive_entry(strings_list::iterator i,
return added.release();
}
-int parse_journal_file(const std::string& path,
- journal_t * journal,
- account_t * master,
- const std::string * original_file)
-{
- journal->sources.push_back(path);
-
- if (access(path.c_str(), R_OK) == -1)
- return 0;
-
- std::ifstream stream(path.c_str());
-
- char magic[sizeof(unsigned int) + 1];
- stream.read(magic, sizeof(unsigned int));
- magic[sizeof(unsigned int)] = '\0';
- stream.seekg(0);
-
- if (*((unsigned int *) magic) == binary_magic_number)
- return read_binary_journal(stream, original_file ? *original_file : "",
- journal, master ? master : journal->master);
- else if (std::strcmp(magic, "!Typ") == 0 ||
- std::strcmp(magic, "\n!Ty") == 0 ||
- std::strcmp(magic, "\r\n!T") == 0)
- return parse_qif_file(stream, journal, master ? master : journal->master,
- commodity_t::find_commodity("$", true));
- else
- return parse_textual_journal(stream, journal,
- master ? master : journal->master);
-}
-
} // namespace ledger
diff --git a/ledger.h b/ledger.h
index 219a7d6c..bbaa8b84 100644
--- a/ledger.h
+++ b/ledger.h
@@ -223,30 +223,6 @@ class journal_t
strings_list::iterator end) const;
};
-int parse_journal_file(const std::string& path,
- journal_t * journal,
- account_t * master = NULL,
- const std::string * original_file = NULL);
-
-unsigned int parse_textual_journal(std::istream& in,
- journal_t * ledger,
- account_t * master = NULL);
-
-extern const unsigned long binary_magic_number;
-
-unsigned int read_binary_journal(std::istream& in,
- const std::string& file,
- journal_t * journal,
- account_t * master = NULL);
-
-void write_binary_journal(std::ostream& out,
- journal_t * journal,
- strings_list * files = NULL);
-
-unsigned int parse_qif_file(std::istream& in, journal_t * journal,
- account_t * master,
- commodity_t * def_commodity = NULL);
-
extern const std::string version;
} // namespace ledger
diff --git a/main.cc b/main.cc
index 3580b622..dfc64bd4 100644
--- a/main.cc
+++ b/main.cc
@@ -1,5 +1,8 @@
#include "ledger.h"
-#include "error.h"
+#include "parser.h"
+#include "textual.h"
+#include "binary.h"
+#include "qif.h"
#include "valexpr.h"
#include "format.h"
#include "walk.h"
@@ -7,6 +10,7 @@
#include "option.h"
#include "config.h"
#include "timing.h"
+#include "error.h"
using namespace ledger;
@@ -178,16 +182,25 @@ int main(int argc, char * argv[], char * envp[])
TIMER_START(parse_files);
+ // Setup the parsers
+ std::auto_ptr<binary_parser_t> bin_parser(new binary_parser_t);
+ std::auto_ptr<qif_parser_t> qif_parser(new qif_parser_t);
+ std::auto_ptr<textual_parser_t> text_parser(new textual_parser_t);
+
+ parser_t::parsers.push_back(bin_parser.get());
+ parser_t::parsers.push_back(qif_parser.get());
+ parser_t::parsers.push_back(text_parser.get());
+
int entry_count = 0;
try {
if (! config->init_file.empty())
- if (parse_journal_file(config->init_file, journal.get()))
+ if (parser_t::parse(config->init_file, journal.get()))
throw error("Entries not allowed in initialization file");
if (use_cache && ! config->cache_file.empty() &&
! config->data_file.empty()) {
- entry_count += parse_journal_file(config->cache_file, journal.get(),
+ entry_count += parser_t::parse(config->cache_file, journal.get(),
NULL, &config->data_file);
journal->sources.pop_front(); // remove cache_file
@@ -206,14 +219,14 @@ int main(int argc, char * argv[], char * envp[])
if (config->data_file == "-") {
use_cache = false;
- entry_count += parse_textual_journal(std::cin, journal.get(), account);
+ entry_count += text_parser->parse(std::cin, journal.get(), account);
} else {
- entry_count += parse_journal_file(config->data_file, journal.get(),
+ entry_count += parser_t::parse(config->data_file, journal.get(),
account);
}
if (! config->price_db.empty())
- if (parse_journal_file(config->price_db, journal.get()))
+ if (parser_t::parse(config->price_db, journal.get()))
throw error("Entries not allowed in price history file");
}
@@ -226,7 +239,7 @@ int main(int argc, char * argv[], char * envp[])
if (i != -1) {
conversion[i] = ' ';
std::istringstream stream(conversion);
- parse_textual_journal(stream, journal.get(), journal->master);
+ text_parser->parse(stream, journal.get(), journal->master);
}
}
}
diff --git a/qif.cc b/qif.cc
index 64c4223e..4b5c0936 100644
--- a/qif.cc
+++ b/qif.cc
@@ -1,4 +1,5 @@
#include "ledger.h"
+#include "qif.h"
#include "datetime.h"
#include "error.h"
#include "util.h"
@@ -22,14 +23,29 @@ static inline char * get_line(std::istream& in) {
return line;
}
-unsigned int parse_qif_file(std::istream& in, journal_t * journal,
- account_t * master, commodity_t * def_commodity)
+bool qif_parser_t::test(std::istream& in) const
+{
+ char magic[sizeof(unsigned int) + 1];
+ in.read(magic, sizeof(unsigned int));
+ magic[sizeof(unsigned int)] = '\0';
+ in.seekg(0);
+
+ return (std::strcmp(magic, "!Typ") == 0 ||
+ std::strcmp(magic, "\n!Ty") == 0 ||
+ std::strcmp(magic, "\r\n!T") == 0);
+}
+
+unsigned int qif_parser_t::parse(std::istream& in,
+ journal_t * journal,
+ account_t * master,
+ const std::string * original_file)
{
std::auto_ptr<entry_t> entry;
std::auto_ptr<amount_t> amount;
transaction_t * xact;
- account_t * misc = journal->find_account("Miscellaneous");
unsigned int count;
+ account_t * misc = NULL;
+ commodity_t * def_commodity = NULL;
entry.reset(new entry_t);
xact = new transaction_t(master);
@@ -78,7 +94,8 @@ unsigned int parse_qif_file(std::istream& in, journal_t * journal,
case '$':
in >> line;
xact->amount.parse(line);
- if (def_commodity)
+ if (! def_commodity)
+ def_commodity = commodity_t::find_commodity("$", true);
xact->amount.commodity = def_commodity;
if (c == '$')
xact->amount.negate();
@@ -143,6 +160,8 @@ unsigned int parse_qif_file(std::istream& in, journal_t * journal,
case '^':
if (xact->account == master) {
+ if (! misc)
+ misc = master->find_account("Miscellaneous");
transaction_t * nxact = new transaction_t(misc);
entry->add_transaction(nxact);
nxact->amount = nxact->cost = - xact->amount;
diff --git a/textual.cc b/textual.cc
index fde735c2..64d03286 100644
--- a/textual.cc
+++ b/textual.cc
@@ -1,3 +1,5 @@
+#include "ledger.h"
+#include "textual.h"
#include "datetime.h"
#include "autoxact.h"
#include "valexpr.h"
@@ -292,8 +294,10 @@ struct push_var {
~push_var() { var = prev; }
};
-unsigned int parse_textual_journal(std::istream& in, journal_t * journal,
- account_t * master)
+unsigned int textual_parser_t::parse(std::istream& in,
+ journal_t * journal,
+ account_t * master,
+ const std::string * original_file)
{
static char line[MAX_LINE + 1];
char c;
@@ -529,8 +533,8 @@ unsigned int parse_textual_journal(std::istream& in, journal_t * journal,
push_var<unsigned int> save_linenum(linenum);
push_var<std::string> save_path(path);
- count += parse_journal_file(skip_ws(line), journal,
- account_stack.front());
+ count += parser_t::parse(skip_ws(line), journal,
+ account_stack.front());
}
break;