NAME
tcalc -- Text Calculator
SYNOPSIS
tcalc file1 [file2 ...]
cat file1 [file2 ...] | tcalc
DESCRIPTION
tcalc is a simple text based ledger/spreadsheet calculator.
It allows you to create your own custom forms, ledgers, and spreadsheets as
plain text files and to be able to do all your accounting using the full
power of your favorite text editor. It would also be simple to automate
adding accounting data using external scripts.
The file format is completely flexible free-form text. It automatically
adds both rows and columns of numerical fields and displays the totals
wherever in the file you choose. Fields may contain arbitrary text,
numbers, or expressions using Perl language syntax.
tcalc operates as a filter. It reads one or more files as a stream,
either from stdin or from files specified on the command line, performs the
calculations, and outputs the result to stdout. The output preserves the
original file format but with the total fields and fields with other output
expressions expanded.
Of course, tcalc is not limited to monetary applications. It can be
used for any application where calculations need to be done on groups of
numbers.
It is primarily designed for adding rows and columns of numbers, but also
supports arbitrary mathematical expressions.
OPTIONS
-h | --help
Outputs program information and brief usage instructions and exits.
CONFIGURATION
There are no external configurations.
There are 3 settings that can be used in the data files.
FS Field separator
COLUMN Default column to expand $total
for
FORMAT format string for numerical expansions
See the FILE FORMAT section below for details.
FILE FORMAT
Data files are free-form plain text files. There are very few
restrictions on the layout. tcalc views the file contents as rows and
columns, numbered from 1 to n. Each line of the file is a row. The rows
are separated into fields, delimited by the setting of FS. If not set in
the file, the default field separator is 2 or more spaces or 1 or more
tabs. The same field on multiple lines is a column.
Comments beginning with '#' or '//' are ignored and removed from the
processed output.
Fields may contain a number, a variable to be expanded, an
expression, a statement, or any text string.
Numbers:
Numbers in any of these formats will be recognized and included
in calculations.
nn, nn.nn, $nn.nn
, $ nn.nn, -nn, +nn -$nn.nn
, n,nnn.nn
Variables:
Variables are specified as $varname.
Variables may be assigned to
or expanded anywhere in the file. You may assign values to any valid
variable name you wish. Valid variable names must start with an
alphabetic character and can contain alphanumeric characters and
underscores ('_').
There are 6 built in variables that tcalc populates during processing.
It is recommended that you do not assign values to any of them.
$t
| $total
This is short and long forms of the same variable.
$total
is a special variable that expands to different values
depending on where it is used.
If placed in a row that contains no numbers in preceding
fields, it is the total for the default column. If COLUMN
has not been set, it defaults to '*' which is the total of all
columns combined.
If placed in a row that has preceding numerical fields (to the
left), it expands to the total for that row.
If specified with an index, e.g. $total
[1], it will expand to
the total for that column, no matter where it is placed in the
file.
Any time $total
is accessed in a field by itself, i.e. not part
of an expression or text field, it's value is reset to zero.
That includes column totals. e.g. $total
[1] would expand to
the total for the first column and the total for that column
would be reset.
$total
is the only variable that is automatically reset when
accessed.
$st
| $stotal
| $subtotal
$total
may also be accessed via $subtotal.
The only difference
is that it's value is not reset. This also applies to specific
columns. e.g. $subtotal
[2].
$r
[]
List of totals for each row.
e.g. $r2
expands to the total of all numerical fields on the
second line of the input file added together.
$c
[]
List of columns (fields) on the current row.
Columns to the right may be used in expressions if they
have numerical values, but beware, they are evaluated from left
to right. So if you use a column to the right in an
expression, and that column also has an expression, the right
column will not have been evaluated yet.
Example:
Lets say you have the following line.
10 =$c
[1] + $c
[4]; 20 =$c
[3] * 3; 50 $total
The output is
10 10 20 60 50 150
When $c2
is evaluated, $c4
has not been evaluated yet, so
it ends up being 10 + 0 rather than 10 + 60.
$row
The current row (i.e. line number)
$col
The current column.
Note:
The special variables, $t
, $r
, and $c
can be indexed without the
'[]' subscript syntax. In otherwords, $c1
is the same thing
as $c
[1]. This allows you to minimize the length of expressions
if you are working with narrow text fields.
Example:
The expression "=$c
[1] + $c
[4];" may also be specified as
"=$c1
+$c4
;"
Expressions:
Expressions are similar to formulas in traditional spreadsheet
programs. They are used to do some calculation and substitute the
result back into the field. Expressions follow Perl programming
syntax rules except they begin with an equals sign ('='). All
expressions and statements must end with a semicolon (';'). Also
they must contain at least one variable to be recognized as an
expression.
Example: =$c1
+ $c2
;
Evaluates to the value of column 1 + column 2 on the current
row (line).
Statements:
Statements are similar to expressions except they do not begin
with an equals sign and do not substitute any result back into the
field. Instead, they are deleted from the output. They are usually
used to modify or assign values to variables.
e.g. $groceries
= $total
;
Any single line statement that contains valid Perl syntax can be used.
Even "if" statements or multiple statements separated by
semi-colons (';').
Examples:
$x
= $t1
; if ($t1
> $t2
) { $x
= $t2
};
Or, the same thing, using a conditional statement and full
array syntax (using '[]' for the array subscripts).
$x
= ($t
[1] > $t
[2]) ? $t
[2] : $t
[1];
Remember, as stated above, the '[]' subscript characters may
be omitted only on the special built in variables, $t
, $r
, and $c.
Text:
Text fields have no effect on the calculations. The only processing
done on text fields is variable expansion. Any variables that have
a value are expanded.
Example: Total of all columns so far is $total
When expanded in a text field, $total
is not reset. It is only
reset when expanded in it's own field.
Example: Total of all columns so far is $total
Notice there are two spaces before $total.
This would move $total
into the next field, and cause it to be reset to zero after expansion.
Settings:
There are 3 settings that can be set on any line of the file. They
take effect from that point on. The setting must be the only thing on
the line. Setting names are not case sensitive (they can be in upper
or lower case). They are set like a variable assignment, except no
'$' prefix and no trailing semicolon.
Example: FS = \s{2,}|\t+\s*
Spaces on either side of the '=' is optional.
COL | COLUMN
Sets the default column to add for the value of $total.
column= or column=* will reset the default column to all, meaning
$total
will expand to the sum of all columns.
Default = *
If column = 2 for example, then $total
is the same as $total
[2]
FORMAT | NUMBER_FORMAT
printf style format string to display numbers as a result of
variable and expression expansions. There is no default.
Example: FORMAT = $%.2f # Dollars and cents format
If $total
contained 100, the expansion would be $100.00.
If the format string contains leading or trailing spaces, then
surround it with quotes.
The Perl manual on sprintf()
covers format details.
i.e. perldoc -f sprintf
FS
Field separator
Default = \s{2,}|\t+\s*
Regular expression pattern that defines what separates fields
on a row. the default is 2 or more spaces or 1 or more tabs.
See the Perl manual on regular expressions.
i.e. man perlre
EXAMPLES
[Sample file]
format = $%.2f # Expand totals to $xx.xx
format
Groceries
=======================================
05/02/2009 42.23 Crest
05/11/2009 6.49 Braums
05/23/2009 59.72 Walmart
------
Total groceries: $total
06/17/2009 16.95 Crest
06/23/2009 59.72 Crest
06/28/2009 5.00 Braums
------ $groceries
= $total
;
Total groceries: $total
Eating out
=======================================
06/19/2009 21.00 Indian Food
06/23/2009 9.00 Furrs
06/24/2009 2.15 Wendys
06/27/2009 3.25 McDonalds
------ $eating_out
= $total
;
Total eating out: $total
==================================================
Total spent this month: =$groceries
+ $eating_out
;
Output:
Groceries
=======================================
05/02/2009 42.23 Crest
05/11/2009 6.49 Braums
05/23/2009 59.72 Walmart
------
Total groceries: $108.44
06/17/2009 16.95 Crest
06/23/2009 59.72 Crest
06/28/2009 5.00 Braums
------
Total groceries: $81.67
Eating out
=======================================
06/19/2009 21.00 Indian Food
06/23/2009 9.00 Furrs
06/24/2009 2.15 Wendys
06/27/2009 3.25 McDonalds
------
Total eating out: $35.40
==================================================
Total spent this month: $117.07
[Sample file]
Since I did not set the number format, I added my own '$' to
the totals.
Original purchase $900.00
Title, taxes, & late penalties $129.50
-------
$$subtotal
Maintenance and repairs
-----------------------
tail lights, side mirrors, etc 66.00
oil drain plug 3.24
oil, filter, & steering wheel cover 41.00
-------
Total expenses: $$total
Output:
Original purchase $900.00
Title, taxes, & late penalties $129.50
-------
$1029.5
Maintenance and repairs
-----------------------
tail lights, side mirrors, etc 66.00
oil drain plug 3.24
oil, filter, & steering wheel cover 41.00
-------
Total expenses: $1139.74
[Sample file]
Spreadsheet style layout
c1 c2 c3 c4 c5 Total
-----------------------------
10 20 30 40 =$c1
+ $c4
; $row1
=$total
; $total
100 200
row1 total: $row1
col1 total: $total1
total=$total
// All columns
Output:
c1 c2 c3 c4 c5 Total
-----------------------------
10 20 30 40 50 150
100 200
row1 total: 150 col1 total: 110
total=450
The following is a simple example of how you might keep a bank ledger with
credit and debits in separate columns.
[Sample file]
format = $%.2f
// Notice the '-' characters as place holders in fields 2 and 3 of the
// rows that have credits. If I did not put something there, tcalc
// would see the credits as being in column 2, the same as debits,
// since the default field separator is 2 or more spaces.
Bank Ledger
===========
Date Debits Credits
------------------------------------------------------
01/12/2009 - - $200
opening balance
01/13/2009 $20.00
gas
01/13/2009 $32.50
groceries
01/15/2009 $15.35
Ate at Casa Bonita
01/18/2009 - - $650.25
paycheck
------------------------------------------------------
Total deposits: $st4
# subtotals
Total withdrawls: $st2
Balance: =$t4
- $t2
;
Output:
Bank Ledger
===========
Date Debits Credits
------------------------------------------------------
01/12/2009 - - $200
opening balance
01/13/2009 $20.00
gas
01/13/2009 $32.50
groceries
01/15/2009 $15.35
Ate at Casa Bonita
01/18/2009 - - $650.25
paycheck
------------------------------------------------------
Total deposits: $850.25
Total withdrawls: $67.85
Balance: $782.40
Example of a simple single column approach if you only care about the
running balance. As you can see, you can use $st2
(or $subtotal2
) at the
end of the line to get the current total for column 2 without clearing it.
[Sample file]
format = $%.2f
Bank Ledger
===========
Date Transaction Running balance
---------------------------------------------------------------
01/12/2009 $200
opening balance $st2
01/13/2009 -$20.00
gas $st2
01/13/2009 -$32.50
groceries
01/15/2009 -$15.35
Ate at Casa Bonita $st2
01/18/2009 $650.25
paycheck
--------
Balance: $total
Output:
Bank Ledger
===========
Date Transaction Running balance
---------------------------------------------------------------
01/12/2009 $200
opening balance $200.00
01/13/2009 -$20.00
gas $180.00
01/13/2009 -$32.50
groceries
01/15/2009 -$15.35
Ate at Casa Bonita $132.15
01/18/2009 $650.25
paycheck
--------
Balance: $782.40
APPLICATION NOTES
There are unlimited ways you can organize your ledgers. For example,
each expense category can be in a separate file. Then if you want to
run a report on all or part of them, just cat the appropriate files and
pipe them to tcalc.
Example:
cat utilities food auto_expenses | tcalc
Or pass them in the correct order on the command line
Example:
tcalc utilities food auto_expenses
When files are concatenated, tcalc views them all as one input stream.
This allows variables between files to be shared, so you can combine
totals, etc. Or run it on just one of the files to see the totals
for a single category, such as auto_expenses.
It is also simple to create expense categories by using variables. For
example, you could keep a running total of tax deductible expenses by
adding to a variable anywhere they occur in the ledger.
Example:
$deductibles
+= $total
;
Then at the bottom of the file or in the last file (if using multiple
files) you might have something like
Total expenses: $total
Tax deductibles: $deductibles
AUTHOR
Vincent Stemen
COPYRIGHT
Copyright (c) 2009 Vincent Stemen
All rights reserved.