DEMONSTRATIVE EXAMPLES
======================
EXAMPLES ON FILING
===================
For many years, filing has been easy and simple. There has been two types of files:
(1) Sequential Access Files (SAF)'s: In this type records are read sequentially, so you
can't read a record unless you read all the records located before it in the file.
(2) Random Access Files (RAF)'s: In which you can read a record located at any place
in the file instantly by supplying its record number.
Sequential Access Files have been good for short files, like "letters" and "memos".
Random Access Files have been good for longer files like "Inventories" and "Personell"
files.
Things have become more complicated recently, SAF's have become not as easy to create and
RAF's have been replaced with databases. This is fine for a large business but not as
good for someone who likes to use his programming ability to put his personal data into
a file made to his/her specs.
Personal C# is specialized in simplification, so we have developed a software which returns
you to the good old days. Both file types are now available and their creation and use
have become even simpler than ever.
SELECTING THE FILE KEYNAME: If you have already looked at the examples on "Controls", you
know what keynames mean. You know that the keyname "bt0" represents a button since the
first two characters "bt" are for a Button type. You also know that you should supply
(cs="bt0") when you call method cm() at any mode to perform an operation on that button.
In Filing, we have only two types of files SAF and RAF. The two char's representing each
of them are "sf" and "rf" respectively. So, you can name your first SAF "sf0" and you
should supply (fs="sf0") when you call method fm() at any mode to perform an operation on
that file.
Filing keynames can also be either 3 or 4 characters long, just like Control's keynames.
So "sf0", "rf08"and "sf89" are all legal keynames. you cannot use numbers which start with
9 since they are reserved for internal use. So "sf9" and "rf90" are illegal keynames.
FILING OBJECTS:
=========================================================================================
EXAMPLE 1: Make a short text file using Notepad and save it under the name "test.txt".
We are going to Read the file and display its contents on the "Text Screen".
We are going to use 2 file read modes "read all" to read it all at once and "read line"
to read it line by line.
=========================================================================================
public class a:pcs {
public override void init() {
tia=toa="t"; // Select "text screen" display
bli=1; // Start execution at block 1
base.init(); // Initialize PC# classes
}
public override void run() {
if (blp==1) { // Starting block
os="Using Read All mode: ";tm(); // First mode
fls="test.txt";fs="sf0";fm("or"); // Open for read, use keyname "sf0"
fm("ra");tm(); // Read it all & display it
fm("c"); // Close file
os="\nUsing Read Line mode: ";tm();// Second mode.
fls="test.txt";fs="sf0";fm("or"); // Open for read, use keyname "sf0"
dnb=false; // Initialize End Of File flag
while (!dnb) {
fm("rl");if (!dnb) tm(); // Keep reading, displaying lines until EOF
}
fm("c"); // Close file
}
}
}
=========================================================================================
HOW TO WRITE, COMPILE AND RUN THE PROGRAM? See Example 1 of the "General Examples".
=========================================================================================
TUTORIAL: Reading a SAF is very easy. At first, we select a keyname for it. Since it is
a SAF the keyname must start with "sf". We called it "sf0" since it is the first file.
The second step is to open the file. There are 3 modes to open a SAF at:
or Open for read, which is the mode we wanted.
ow Open for write
oa Open for append
There are also 3 modes for reading a SAF:
ra Read the entire file and assign its text content to (os)
rl Read one line
rb Read one byte
The boolean var (dnb) which is the "done" flag is a general flag used to indicate whether
something we are working on has been completed or not. In filing, dnb changes its state to
true when an end of file (EOF) has been encountered.
So, before we start reading, we make sure that it is (false) then we keep reading until it
changes to (true)
You may have noticed that we has specified the file keyname only when we opened it, we
didn't specify it when we read the file text or when we closed it. Why?. The answer is
that method fm() does not reset (fs) at its end like it resets the GUV's. So we have been
able to get away with doing that. However, this is not a good practice. If we have been
working with more than one file, we should have specified the file keyname at each
operation.
=========================================================================================
BEST SELLERS FROM AMAZON.COM
Books, C Sharp Books, .NET Computers Electronics Industrial & Scientific Items MP3 Downloads DVD Camera & Photo Cell Phones & Services Magazine Subscriptions Office Products On Demand Videos
|
 |
EXAMPLE 2: This time, we are not going to write a full class for each example, we are
going to add one block for each new example to the class of example 1. so,
this example will be in block 2. After adding block two to the last class,
change the startup block request statement in method init() to (bli=2;)
In this example, we are going to erase "test.txt" file contents, open it in
"write" mode, write the line "Text Line Number 1" into it, close it then open
it again in "append" mode, write the line "Text Line Number 2" into it, close
it then open it in "read" mode, read and display all its data.
if (blp==2) {
// ----------------------- CREATING THE FILE AND WRITING DATA ---------------------
ks="f";fls="test.txt";fm("D"); // delete file.
fls="test.txt";fs="sf0";fm("ow"); // open for write
os="Text Line Number 1";fm("wl"); // write line
fm("c"); // close
os="Data written to file";tm(); // Inform user
fls="test.txt";fs="sf0";fm("oa"); // open for append
os="Text Line Number 2";fm("wl"); // write line
fm("c"); // close
os="Data appended to fle";tm(); // Inform user
// --------------------------------- READING DATA BACK ----------------------------
os="Reading data back:";tm();
fls="test.txt";fs="sf0";fm("or"); // Open for read
fm("ra");tm(); // Read all file & display on text screen
fm("c"); // close
}
=========================================================================================
|
 |
EXAMPLE 3: Now, we need to add a new block to show how to obtain current directory name,
how to check if a file or dir exists, how to create files and dir's and delete
them, how to get a list of all files & sub folders in a folder and how to
copy one file to another.
So. add block 3 to your program and change "Startup block request" statement
in method init() to (bli=3;)
IMPORTANT REMARK: In this example, we have assumed that your current directory name is "c:\pcs"
and that there is a file with the path "c:\windows.WindowsUpdate.log" into
your computer. If this was not correct, modify the code before trying to
execute it.
=========================================================================================
if (blp==3) {
//-------------- OBTAINING CURRENT DIRECTORY AND CHECKING ATTRIBUTES --------------
fm(".");os="Current Directory: "+os;tm(); // Get currnt dir name, dsplay it.
fls="x.txt";fm("A");os="Code: "+os;tm(); // Get attributes & dsplys returned
fls="xxxx.cs";fm("A");os="Code: "+os;tm(); // code for 3 items. Should display "f"
fls="c:\\health";fm("A");os="Code: "+os;tm();// if file, "d" if directory, " " if
// non-existing.
//------------------ CREATING AND DELETING FILES AND DIRECTORIES ------------------
ks="f";fls="testFl";fm("M");os="File created";tm();// Create file, inform user.
ks="f";fls="testFl";fm("D");os="File deleted";tm();// Delete same file
ks="d";fls="testDir";fm("M");os="Dir created";tm();// Create dir, inform user
ks="d";fls="testDir";fm("D");os="Dir deleted";tm();// Delete same dir
//----------- DISPLAYING ALL SUB-FOLDERS AND FILE CONTENTS OF A FOLDER -----------
os="Reading file list:";tm();
ks="d";fls="c:\\pcs";fm("L"); // Get all sub-dir's in OS[]
om("fa"); // Convert OS[] to (os)
ns=os; // save (os) temporarely in (ns)
ks="f";fls="c:\\pcs";fm("L"); // Get all files in OS[]
om("fa"); // Convert to (os)
os=ns+os;tm(); // Add the 2 lists & display
//-------------------------- COPYING FILES AND DIRECTORIES ------------------------
fls="c:\\windows\\WindowsUpdate.log";os="newfile.txt";fm("C");// copy extrnl file to local file
os="File copied";tm(); // Inform user with dialog box
ks="f";fls="newfile.txt";fm("D"); // Delete new file
os="File deleted";tm(); // Inform user
}
=========================================================================================
TUTORIAL: So far everything seems to be too easy to require additional explanation. Let
us now get into the more important filing type "The Random Access Filing".
|
 |
RANDOM ACCESS FILES
===================
==============================================================================================
We are always searching for new ways to simplify software development. Random Access files
have been considered to be the simplest means of accessing data randomly for some time. This
has been changed lately. The new "Table Files" are considerably simpler and easier to use.
For this reason we do not expect to support Random Access Files for a long time. So please
read about Table Files and convert any Random Access files which you already have to this new
type. We'll show you an example on how to do the conversion.
===============================================================================================
The difference between a SAF and RAF is in the record length.
In a text SAF, the strings you write into the file are not of equal lengths, the only
way we can seperate them from each other is by adding a "new line" code at the end of
each string. The new line code which we use is made of two special characters, a carriage
return character (code 13 in decimal form) followed with a line feed character (code 10,
decimal)
In a RAF, you specify a record length when you open the file. The record length you choose
should be at least equal to the length of the longest string which you may like to add to
the file. When you call method fm() with a string which you want to write into the file,
the method adds at the end of your string as many null characters as it takes to make its
length equal to the record length.
Since all records of a RAF are of same length, it is possible to know where the start and
end of any record in the file are, so we can retrieve the record instantly without having
to read all the records which preceed it into the file.
We have two types of RAF's:
---------------------------
(1) Manually read RAF's.
(2) Automatically read RAF's
In the first type, you need to supply the record length each time you open the file and
you are on your own concerning how you place your data into your record.
In the second type, at the time you create the file, you supply the filing method fm()
with the record length and data concerning the fields each record should contain. After
the file is created, the method writes a header record at the beginning of the file
which contains all data necessary to read its records and to retrieve the field data
within them. So anytime you open the file for read or write thereafter, you don't have
to tell the method how to read it or where fields are located.
Next example will be on the first type of Random Access Files.
=========================================================================================
EXAMPLE 4: We are going to add a new block to last program to show how to write 2 lines
into a no header Random Access File (RAF) then read them back. We need to
erase file contents before writing into it.
=========================================================================================
// ----------------------- CREATING THE FILE AND WRITING DATA ---------------------
if (blp==4) {
fls="test.raf";fm("A"); // check file attributes
if(os != " ") {ks="f";fm("D");} // If exists, delete it
fls="test.raf";fs="rf0";rcl=24;ib=true;fm("o");
// open RAF, record len=24,no header
rcs="Line number one.";rci=0;fm("w");// Write first record
rcs="Line #2.";rci=1;fm("w"); // Write second record
fm("c"); // Close the file.
// --------------------------------- READING DATA BACK ----------------------------
fls="test.raf";fs="rf0";rcl=24;ib=true;fm("o");
// open RAF again
n=0;dnb=false; // Initialize record number counter, eof flag.
while (!dnb) { // Start record reading loop.
rci=n;fm("r"); // Read one record.
os=rcs;om("c"); // Clean record (remove trailing null chars)
tm(); // Then display record.
n++; // increment record number.
}
fm("c"); // Close the file.
}
=========================================================================================
TUTORIAL: As you can see, the records supplied to method fm() to be written into the file
have not been equal in length, but the method made them equal by adding enough null
char's to each of them to make the length of each one of them equal to the record length.
When the records were read back, they came with the null char's attached to them, so we
had to remove the null chars before displaying them.
HOW TO CREATE AN AUTOMATICALLY READ RAF:
The first step is to create the header. To do so, you open the file as a no header file,
write the header then close it.
To create the header, you need to determine the fields necessary. To simplify things, we
use only two types of fields, string and numeric fields. A numeric field always occupies
5 bytes. The number of bytes a string field requires is the number of characters of the
logest string to be writen into it.
Setting the record length:
--------------------------
To calculate the record length, add the bytes which all fields require together, then add
some more spare bytes for future expansion.
Setting the data type:
----------------------
The double type var (od) is used to indicate the data type for a field. Here is how to
detrmine data types:
(1) For a string field, od=No. of characters occupied by the field.
(2) For a numeric field, (od) is always in the range (0.0 to 0.9) The number to the right
of the decimal point is the number of decimal digits you like the field to have.
If the field will be used to represent money, you would be expected to choose (od=0.2)
so your numbers come formatted as Dollars and Cents. If the field is going to be used
to store an integer, you would use (od=0.0) since there will be no decimal digits.
So, (od) can tell exactly what a field contains. If it was an integer like (35), we know
that the field is a string, upto 35 characters long. If it was zero (0.0), the field
is an integer and if it was a fraction like (0.4) we know that the field is a number of
4 decimal digits (in this case)
How the header data is supplied:
--------------------------------
Practically, we don't supply field data one at a time, we supply them all at once. We
supply the array OS[] containing all field names, and array OD[] containing all field
types in the same order at which we like the fields to be placed into the record.
=========================================================================================
|
 |
EXAMPLE 5: Let us add a new block to last program to show how to make a RAF with a
header containing all information necessary for reading it. We are also going
to Enter two records of data into the file then read them back and display
them on the screen.
=========================================================================================
if (blp==5) {
// ------------------- CREATING THE FILE AND WRITING THE HEADER ------------------
fls="test.raf";fm("A"); // check file attributes
if(os != " ") {ks="f";fm("D");} // If exists, delete it
fs="rf0";rcl=100;ib=true;fm("o"); // open the file as no header file
OS[0]="name";OD[0]=35; // 35 character string field
OS[1]="age";OD[1]=0.0; // Integer field
OS[2]="position";OD[2]=25; // 25 character string field
OS[3]="salary";OD[3]=0.2; // numeric field with 2-decimal digits
fm("wh"); // Write header.
fm("c"); // Close the file.
// -------------------------- ENTERING DATA INTO THE FILE -------------------------
fls="test.raf";fs="rf0";fm("o"); // open file and read header information
// Notice that we did not supply rec length
OS[0]="John Smith"; // First field data, a string in OS[]
OD[1]=25; // Second field data, a number in OD[]
OS[2]="Machine operator"; // Third field data, a string in OS[]
OD[3]=35000.50; // Fourth field data, a number in OD[]
rci=1;fm("w"); // Write record #1
OS[0]="Mary Jones"; //
OD[1]=20; //
OS[2]="Clerk"; // Field data for second record
OD[3]=25000.66; //
rci=2;fm("w"); // Write record #2
fm("c"); // Close the file.
// ------------------------------ READING DATA BACK ------------------------------
fls="test.raf";fs="rf0";fm("o"); // open file and read header information
// Notice that we did not supply rec len or any
// field information. The file reads itself.
n=1; // Start by record # 1
while (!dnb) { // Do until eof encountered.
rci=n;fm("r"); // Read one record. (See REMARK)
os=OS[0];tm(); // Read and display 1st field
os=OS[1];tm(); // Read & display 2nd field
os=OS[2];tm(); // Read and display 3rd field
os=OS[3];tm(); // Read & display 4th field
os="";tm(); // Add blank line to seperate records
n++; // increment record number.
}
fm("c"); // Close the file.
}
=========================================================================================
TUTORIAL: As you can see, at the block of code titeled "CREATING THE FILE AND WRITING THE
HEADER", the file did not have a header, so we opened it as a no header RAF. We wrote the
header and closed the file. From this point up, the file is a self read file, reading it
or writing into it does not require supplying any information other than the file name.
At the block of code titled "ENTERING DATA INTO THE FILE", we opened the file as a RAF
with a header (since ib=false), so we did not need to supply rec length. Immediately
after the open statement, we have all field names in OS[] and their type codes in OD[]
If you have forgot what was in the file you can remind yourself by displaying the two
arrays with a code like this:
fls="test.raf";fs="rf0";fm("o"); // open file and read header info;
fm("rh"); // Read header
for (c=0;c<20;c++) { // Scan field arrays
if (OS[c].Length<1) break; // Stop at end of data
os="Name: "+OS[c]+" Type: "+OD[c];tm();// Display name and type of each field
}
This is what you get:
Name: name Type: 35
Name: age Type: 0
Name: position Type: 25
Name: salary Type: 0.2
You may be wondering why we included the read header statement [fm("rh")] if the open
statement have already read the header. The answer is that the open statement reads the
header, copies OS[] and OD[] contents to internal PC# archives then resets OS[] and OD[]
so they can be used in the next record read or write operations.
READING AND WRITING DATA:
You must have noticed that we leave empty gaps into arrays OS[] and OD[] when we read
or write. For example, during writing of the first 3 fields, we skipped
OS[0]="John Smith"; // First field data, a string in OS[]
OD[1]=25; // Second field data, a number in OD[]
OS[2]="Machine operator"; // Third field data, a string in OS[]
OD[0],OS[1] and OD[2]. The rule is that when the field is string, we keep its place in
OD[] empty and when the field is numeric we keep its place in OS[] empty. Why do we need
these gaps? In addition to simplicity, After each read operation, numeric field data are
formatted according to their type specs and their string type format is stored into its
place in OS[] in addition to their numeric value which is stored in OD[].
=========================================================================================
|
 |
==============================================================================================
The Table File
==============
(For version 1.80 and higher)
If you try to find the easiest and simplest way to store field data into a file, you can hardly
find anything better than the Table File. Here is a sample:
---------------------------------------------------------------------
HISTORICAL STOCK PRICES OF MICROSOFT CORPORATION
------------------------------------------------
Date Open High Low Close Volume
========== ======== ======== ======== ======== ============
02/07/2008 28.34 28.78 27.90 28.12 164,964,900
02/06/2008 29.28 29.35 28.29 28.52 138,021,700
03/05/2008 29.91 29.94 28.89 29.07 137,522,600
02/04/2008 30.49 30.72 30.11 30.19 119,987,300
02/01/2008 31.06 33.25 30.25 30.45 291,095,400
01/31/2008 31.91 32.74 31.72 32.60 103,363,200
01/30/2008 32.56 32.80 32.05 32.20 106,343,700
01/29/2008 32.85 32.89 32.35 32.60 68,007,200
01/28/2008 33.02 33.10 32.42 32.72 81,007,400
----------------------------------------------------------------------
As you can see, you can include a title on the top which can occupy any number of lines and you
can insert empty lines within data records to improve visibility. You can read from and write to
the Table File programmatically as well as with a simple text editor like Notepad. The only two
items which you should pay attention to when you write to a Table File are:
(1) The Template record:
------------------------
The row which is made of short lines under column titles is the template record. It's the most
important record in the file. Its length sets the file's record length. The short lines made of
equal signs set the start and end of each field's data (we like to call them column data here)
The numbers of spaces which seperate each two lines are optional, however there should be at
least one space between each two lines.
(2) The Data records:
---------------------
There are two rules to abide with when you write data records:
a) The first character of each field must lineup with the first character of the template line
at the top of its column.
b) The field data must not exceed that template line in length. This requires that when you
create a template for a new file, you must make each line it contains at least equal in length
to the longest expected data to be written into its column.
That's it. There are no more rules for this file type other than making sure not to include any
line which could be confused for the template record. The template record is defined to be a
record which is made of nothing but equal signs and space char's.
Columns and rows:
-----------------
Being a table and a file at the same time has made some terms exchangeable. A row, a line and a
record mean the same item in a table file. Also, when we are talking about one record, field and
column mean the same item.
How to make a Table File using NotePad:
---------------------------------------
This should be obvious. After reading the rules above and looking at the sample table, you
should have no problem with writing data into a Table File using Notepad. However, you need to
make sure to press [ENTER] following each row you enter including the last one.
The extension to use for this file type can be "txt" since it's actually no more than a simple
text file. This is not a rule. Sometimes we may need to use different extensions to diffrentiate
between different table files.
How is the Table File read and edited programmatically:
-------------------------------------------------------
When you request opening a file of this type, method fm() reads records line by line looking for
the template row. It looks for a row which is made of nothing but equal signs and spaces. This
is why we recommend that you avoid including (=)'s within the lines which are above the template
line.
When the template row is found, it's analyzed and the start and end positions of each data field
are written into a table. Additionally, the record length is set as the template row's length.
All data records in the file are then copied to an array. The array is used for all data reading
and writing until the file is closed. When you request closing the file, the array is written to
the file before the file is closed.
The keynames to use when you call method fm() to do an operation on a Table File must start
with "tf". So, "tf0", "tf01", "tf89" are valid Table File keynames. Your file must contain a
template before you can call it a Table File or assign such keynames to it. If you like to create
the file and write the title and template into it programmatically, open it as a SAF file using
a keyname like "sf0".
Writing the table title and template record:
--------------------------------------------
To start a new Table File, the simplest way is to use Notepad to write at least upto the template
record. If you must do this job programmatically, open it for write as "SAF" file using keyname
like "sf0".
What is the greatest advantage in using Table Files:
----------------------------------------------------
The ease and simplicity in writing and reading data and the flexiblity in allowing you to insert
blank lines and to write a title on the top of the file are some advantages. However what we
consider to be the greatest advantage is that what is in the file is exactly what we like to
see on the screen when we display it or on paper when we print it.
How about the RAF files:
------------------------
Although RAF's are considered to be simpler than most other data storage means, they cannot beat
the Table File in simplicity and ease of use. So, we recommend that you replace any RAF file
which you have with a Table File. We are going to show you an example on how to transfer data
from RAF to a Table File.
How about Databases:
--------------------
The Table File is good for simple data storage jobs when security is not an important issue and
amount of data is not very large. Databases must be used for larger data storage jobs or tighter
security rules. Table files can be used for simple jobs like filing your personal data or filing
non-critical data in a business.
How to set the maximum data size of a Table File:
-------------------------------------------------
Call method dm("hd") within method init() to set the highst number of records which you expect
for your Table File. The initial default amount is 1000 records.
EXAMPLES:
=========
Let us see some examples before we get further.
(1) Writing file with Notepad and displaying its content on the console:
------------------------------------------------------------------------
Copy the table above including its title and template and paste it into Notepad window. Save it
into the file "test.txt".
You can display file content from command mode by just typing:
type test.txt [ENTER]
If you like to do it programmatically:
--------------------------------------
public class a : pcs {
public override void run() {
cm("fe"); // Eliminate form.
fls="test.txt";fm("R");tm(); // Read all data and display.
}
}
---------------------------------------------------------------------------------------------
(2) Creating a new Table File and writing template:
---------------------------------------------------
public class a : pcs {
public override void run() {
cm("fe"); // Eliminate Form.
fls="test1.txt";ks="f";fm("D"); // Delete file if exists.
fs="sf0";fm("ow"); // Create and open new file.
// Write next 5 lines into file.
os=" HISTORICAL STOCK PRICES OF MICROSOFT CORPORATION";fm("wl");
os=" ------------------------------------------";fm("wl");
os="";fm("wl");
os=" Date Open High Low Close Volume";fm("wl");
os="========== ======== ======== ======== ======== ============";fm("wl");
os="Table File has been created and data written into it successfully.";tm();
}
}
---------------------------------------------------------------------------------------------
When we created the file and wrote the title and template lines, we treated the file as a regular
SAF file. Now, after the template record has been written, we can open it as a table file, read
and write records randomly at great speed and work on column data independantly. We can search
the file for specific strings at specific columns, obtain the record numbers of the records where
matches have been found then read the wanted records and work on them. We can also sort the file
based on data of a specific column or columns.
How are records accessed randomly?
----------------------------------
If the file is SAF and records are not exactly equal in length, how could we retrieve records
randomly? The answer is that the entire file is dumped into an array when it's opened. Any
reading or writing thereafter is done from/to the array. When we request closing the file, the
array is written back into the file before it's closed.
How much data could be dumped into memory without causing a crash?
------------------------------------------------------------------
Let's make some calculations. If your file contains names and addresses of people, it will
require about 128 bytes per record. This means that each 8 records require 1 kilobytes. So:
8 records require 1 Kilobytes.
8,000 records require 1 Megabytes.
800,000 records require 100 Megabytes.
1 Million records require 125 Megabytes.
Years ago, 125 megabytes of RAM has been larger than anything imaginable. Now, you can buy a
cheap computer with no less than 1 Gigabytes of RAM.
With putting this into consideration, there is nothing wrong with dumping your file data into
arrays. It makes reading and writing data much faster and also allows you to operate on the
records randomly.
Modes of method fm() which are used to read from and write into Table Files:
----------------------------------------------------------------------------
o: USE: Opens a file for Read/Write. It copies file data to archives and also stores
field data into archives. File must exist and contain template record or it
will return an error.
IN : fls=file name fs=keyname (like "tf0")
OUT: o=Start data record number. ol=Total number of records. dnb=true:File is empty.
of=Record length.
r: USE: Reads data for one record. IN: rci=Record number.
OUT: rcs=record data in a string form. dnb=true: Record at or beyond end of file
OS[]=Field data. oi=Number of occupied rows in OS[]
w: USE: Write a record.
IN : rci=record number, OS[]=field data.
wn: USE: Write a new record at end of data
IN : OS[]=Field data
c: USE: Copies data back to file then closes it and rest archives.
When you open the file, all data in the file is copied to an array. Additionally, the template
is analyzed and record length is determined (which is the length of the template record) Data
record may not exactly match the template in length but this causes no problem.
The start character and number of characters of each column are determined and also placed into
arrays. All arrays are public, so you can work on them directly if you choose.
How to access our archives directly:
------------------------------------
You can always access our data archives directly. If your file keyname is tf3, here is where to
find data:
rcs : Last record read. This value is returned to you at mode "r" assigned to (os)
rcl : Record Length. This value is returned to you at mode 'o' assigned to (of)
fll : Total number of records. Also returned to you at mode 'o' assugned to (ol)
TBS[3][] : Stores a copy of the entire file.
CNS[3][] : Stores column titles.
CSI[3][] : Stores the start character order of each column.
CCI[3][] : Stores the number of characters each column contains
CNI[3] : Stores the number of columns in the file.
DSI[3] : Stores the record number of first data record. This is the record which immediately
follows the template record. Method fm("o") returns this value to you assigned to (o)
Note that for the table at the top of this page, DSI[]=5 which means that it points to
the blank line following the template.
Column Title Rules:
-------------------
Normally, we like to identify columns by their order numbers. So we neglect the titles' row. But
since some people like to use column titles to identify columns with, we like to enforce the
following rules:
(1) Do not include spaces into titles. You can seperate words of the title with underscores like
"Color_code" or by starting each word with upper case letter, like "ColorCode".
(2) No title name should go beyond its column borders and extend to adjacent columns. This may
require you to add extra seperating spaces between column template lines when the title
length exceeds the data length.
For example, consider the 3 neighbouring columns "Item", "ColorCode" and "FontCode". The
color codes are always made of 2 char's, so the column title's length exceeds the template's
length for that column. Here is how to create a legal template in this case:
Item ColorCode FontCode or Item ColorCode FontCode
==== == ======== ==== == ========
As you can see, we have solved the problem by seperating the template lines with extra spaces.
This should also tell you that it's always better to make the titles as short as they can be.
Method fm() archives column titles into array CNS[][] which is public. You can also obtain the
order of any column by assigning its title to (ks) and calling fm("fo") The order is returned
to you assigned to (o)
The "Form Documents" menu which will come later contains a selection which displays for you a
list of all columns in a Table File, their order numbers and their templates. You can also get
this list with:
fls="Table File Path";um("fa");
Resetting Vaiables:
-------------------
When you work on Table Files, it's important to know which var's are reset after calling method
fm() to perform an operation and make sense of the logic involved. The general rules are:
(1) All j,k & i based single value var's (GUV)'s must be reset under all condtions.
(2) ALL J,K & I based arrays are reset only when they are used as input parameters.
(3) All o based single value and array var's are reset only when used as input parameters and
kept unchanged when not, with exceptions for (os) and OS[].
MODE RESET VARIABLES REASON
o OS[] To prepare for a future read/write operation.
fo None None involved in operations
fs KS[],OS[],J[],K[] KS[],J[],K[] are used for input, OS[] is prepared for coming rd/wr op.
fS JS[],KS[] Used for input.
fp None None involved in operations.
r None os & OS[] are output values.
w OS[],rci,rcs,os To erase values supplied at prior read operation.
d None None involved in operations.
c OS[],All archives To make sure no old values associated with file are still there.
==============================================================================================
Example 6: Open file "test.txt" which contains the table at the top as a Table File. Read the
3rd data record and display it. Modify the low price to "25.00" and overwrite that record.
Read the record again and change the date to "02/08/2008", then write it as a new record at the
end of the file following a blank line. Display the resulting file showing the modified records
in red.
==============================================================================================
public class a : pcs {
public override void init() {
toa="t"; // Use text screen for text output
base.init();
}
public override void run() {
fns="crb10"; // Use courier font since alignment is necessary.
fs="tf0";fls="test.txt";fm("o"); // Open as a Table File.
rci=o+3-1; // Record number of the 3rd record
n=rci; // Save this number temporarely.
fm("r"); // Read that record (OUT=OS[])
OS[3]="25.00";fm("w"); // Modify column #3 (Fourth column where "low" is)
fm("wn"); // Write a blank line following last record.
rci=n;fm("r"); // Read the record again.
OS[0]="02/08/2008";fm("wn"); // Modify date then write it as a new record.
fm("c"); // Close file.
fls="test.txt";fm("RL"); // Read file as lines into OS[]
for (c=0;c< OS.Length;c++) { // Scan all rows.
os=OS[c]; // Assign each row to (os)
if (c==n || c==OS.Length-1) { // If was a modified row:
cls="r0";tm(); // Display it in red.
cls="S9"; // then restore black color.
}
else tm(); // Display all other rows in black.
}
}
}
----------------------------------------------------------------------------------------------
REMARK:
=======
In order to protect file, method fm() assigns zero to (rci) after each write operation. This is
to guard against writing next record at the same location of the file. Note that if you try to
write at record zero, you'll get an error message.
When you read a record, method fm() keeps (rci) unchanged. This is because you normally like
to read a record, modify it then overwrite it with new data.
Array OS[] is also reset after each write operation. This is why we could write a blank line
at the end of data by calling fm("wn") with no parameters.
==============================================================================================
BEST SELLERS FROM AMAZON.COM
Books, C Sharp Books, .NET Computers Electronics Industrial & Scientific Items MP3 Downloads DVD Camera & Photo Cell Phones & Services Magazine Subscriptions Office Products On Demand Videos
|
 |
==============================================================================================
Searching for a specific data at one column:
--------------------------------------------
In the previous example, we modified the third data record of the file. In the real world, we
don't identify records by their numbers. When we modify records we like to modify a record of
specific criteria, for example we may like to modify the stock data for the date "02/01/2008".
This means that we must search the file in order to obtain the record number of the record
with date ="02/01/2008" before we can read it, modify it and write it back.
Sometimes we search for all the records which satisfy a specific criteria, for example, if the
two days "01/31/2008" and "02/01/2008" contain data which need to be modified, we can search for
the records with char number 4 of the Date column = "1" and expect to receive two record numbers
as the search result.
When we search, we search for a string which starts at a specific char of a specific column. So,
we may search for the string "1", "1/" or "1/2008" and expect the same results.
In order to do things faster, we are allowed to supply more than one criteria to be searched in
one step and expect to receive the numbers of all records which satisfy all the criterias
specified. If we search for the string "1/2008" at char number 4 of the "Date" column and for the
string "25.00" in the "Low" column, we should receive 4 record numbers, 2 for records with dates
"01/31/2008" and "02/01/2008" and two for the two records which we have written into file in the
previous example.
Since we supply more than one item to be searched and also receive more than one record number,
arrays are used for both jobs.
Assign the order numbers of all the columns to be searched to K[] and the strings to look for
into each column to the rows of array KS[] of matching orders. If the search string was not
expected to start at the first character of a column, assign to the same row in array I[] the
order of the start character within the column to search at. The numbers of all records which
satisfy all criteria come assigned to array O[].
In order to clarify that, when we search the date column at char number 4 for the string "1/2008"
we supply:
k[0] = 0; // (Date)'s column number is zero.
I[0] = 4; // Search starts at char number 4 of the column.
KS[0]= "1/2008"; // String to search for.
fm("fs"); // Call fm() at "field search" mode.
And we expect to receive array O[] containing 4 record numbers.
Resetting used arrays:
----------------------
The most critical operation in PC# software is resetting general use variables. General use
single value variables are guaranteed to be reset at the end of every method call. General use
arrays are reset only when used as input parameters and not used for output. So, after each
search operation you expect arrays K[], I[] and KS[] to be reset.
We mean by "reset" that all numerics are assigned zeros, all strings are assigned "" and all
boolean values are assigned (false)
When arrays are reset, their sizes are made to be equal to the default size for general use
arrays which is 100. This default amount can be changed by calling dm("gh") from method init()
However, if you keep their sizes unchanged and assign values to few rows at the top leaving the
rest unassigned, PC# methods will have no problem. This is actually what we prefer.
The output array O[] which method fm("fs") returns to you is trimmed to the size of the data
it contains before it's returned to you. However, method fm("r") does not trim array OS[] before
it's returned to you loaded with field data. It returns (oi) assigned the number of occupied rows
instead. The reason is that you may need to modify OS[] then write it back into the file. Such
modification may involve assigning values to fields which have not been assigned values
initially.
===============================================================================================
Example 7: Search the file for the two records with dates "01/31/2008" and "02/01/2008" together
with the records which contain "25.00" at their "Low" column. Modify the "Low" column of all
records received to contain "26.00". Display the file, showing modified records in red.
===============================================================================================
public class a : pcs {
public override void init() {
toa="t"; // Use text screen for text output
base.init();
}
public override void run() {
fns="crb10"; // Use courier font since alignment is necessary.
fs="tf0";fls="test.txt";fm("o"); // Open as a Table File.
K[0]=0;I[0]=4;KS[0]="1/2008"; // First search criteria.
K[1]=3;KS[1]="25.00"; // Second Search criteria.
fm("fs"); // Execute search.
int[] O1=O; // Save O[] temporarely
for (n=0;n< O.Length;n++) { // Scan all returned array
rci=O[n];fm("r"); // Assign each record number to (rci)
OS[3]="26.00";fm("w"); // Change column #3 data then write record.
}
fm("c"); // Close file.
fls="test.txt";fm("RL"); // Read file as lines into OS[]
for (c=0;c< OS.Length;c++) { // Scan received data.
os=OS[c]; // Assign each row to (os)
for (n=0;n< O1.Length;n++) { // Compare with modified records
ob=false; // Initialize "already displayed" flag.
if (c==O1[n]) { // If row to be displayed was a modified row:
cls="r0";tm(); // Display it in red.
cls="S9"; // Restore black color.
ob=true;break; // Set "already displayed" flag and exit.
}
}
if (!ob) tm(); // Display all other rows in black.
}
}
}
==============================================================================================
REMARK:
=======
You may like to say that searching for a string at a specific location in a specific column
is not the only kind of search which I like to do. This is true, but don't forget that you are
not limited to using method fm("fs") for your search. You can read the records one by one in a
loop and search them by yourself and if you like to do the job faster, you can search array
TBS[][] instead. This is one advantage in using a file instead of using a database; there is
no limit to what you can do.
==============================================================================================
|
 |
==============================================================================================
Performing Table File sort which is based on one column's data:
---------------------------------------------------------------
Sorting can be necessary for many reasons. One of them is making it easy for you to locate a
record manually. Sorting a name and address file based on the zip code before sending mail to
the persons who are listed in the file can reduce your mailing cost since it reduces the postage
necessary. Finally sorting at a field which you regularly search can allow you to use binary
search which is much faster than the ordinary.
Sorting a table file is very easy. All you need to do is to assign column number to (k) and
call fm("fS") Notice that "S" in the mode string is an upper case one. Search uses the lower
case "s".
Binary Search:
==============
Binary Search is very useful to know about and apply to many of the tasks which you do in your
life. Its value to you far exceeds searching files. Let us consider here one simple application.
Let us assume that there is a connection problem somewhere in the telephone line in your house
and that there are 8 plugs which your telephone line goes through between the point it enters
your house and the point where your phone set is.
Entry O------X------X------X------X------X------X------X------O TELEPHONE
POINT 1 2 3 4 5 6 7 8 SET
You like to know at which piece of the cable the line is broken. One way to find that is to
disconnect your phone set and try connecting it at point 1. If you find that it works, you
repeat at point 2 and so on until you find the defective part. This can take upto 8 steps.
Mathematically you can locate the defective part in the shortest steps possible if you do it
in the following manner:
(1) You test at the middle plug which is #4. If it works, you know that there is nothing wrong
upto plug #4.
(2) You test at the plug which is located at the middle between plug #4 and the end of the line
which is plug #6.
(3) If it works, you then test at plug #7. If it did not work, you test at plug #5.
With the idea of binary search you have reduced the steps from 8 to 3. You can calculate the
number of steps as follows:
Number of steps = Log (to base 2) 8 = 3.
The advantage may not look too dramatic in this case, but if the number of plugs has been one
million, you could have located the defective piece of the cable in only 20 steps.
Searching for a bug in your program which is causing a confusing compiling error like when one
brace is missing can also be simplified with the use of the same binary search idea. This can be
done by setting the comment symbols "/*" and "*/" around half of your code then compiling your
program again. if the problem stays, you place the comment symbols around half of the other half
and so on. This should save you plenty of developing time.
And here is a problem in math where the binary search idea can be of great help. Suppose that you
have the equation: y=x^4 + 2x^3 + 4x^2 + 5x +1 (^ means exponent here) and you like to find one
positive value of (x) when (y=10.55)
Trying to get the roots of this equation algebrically can be very hard. One solution is to use a
loop to find the value of (y) for all values of (x) within expected range and compare the
calculated (y) with the actual one. When a match is found, you'll be at the right (x) value.
If the expected range of (x) was (0:10,000) and you like it to be accurate to two decimal digits,
you may have to do the calculation one million times. Using the binary search idea, you'll need
to do the calculations only 20 times.
Using binary search to locate data in a large file is great for speed. This is because it takes
inspecting only 20 records to locate data inside a million record file. This means that whatever
mode "fs" can do with upto 1 million checks, mode "fsb" can do with no more than 20. However,
you can't use binary search to locate data in one column of a Table File unless the column data
has been sorted in advance.
==============================================================================================
Example 8: Sort the file at the "High" column (which is column #2) then do a binary search to
locate the records where the "High" prices of "30.72" and "33.10" are located. Display the
sorted file showing the records which contain the two prices in red.
==============================================================================================
public class a : pcs {
public override void init() {
toa="t"; // Use text screen for text output
base.init();
}
public override void run() {
fns="crb10"; // Use courier font since alignment is necessary.
fs="tf0";fls="test.txt";fm("o"); // Open as a Table File.
k=2;fm("fS"); // Sort file based on column #2
K[0]=2;KS[0]="30.72"; // Search for "30.72" at sorted column
K[1]=2;KS[1]="33.10"; // Search for "33.10" at sorted column
fm("fsb"); // Execute binary search.
int[] O1=O; // Save O[] temporarely
fm("c"); // Close file.
fls="test.txt";fm("RL"); // Read file as lines into OS[]
for (c=0;c< OS.Length;c++) { // Scan received data.
os=OS[c]; // Assign each row to (os)
for (n=0;n< O1.Length;n++) { // Compare with selected records
ob=false; // Initialize "already displayed" flag.
if (c==O1[n]) { // If row to be displayed was a selected row:
cls="r0";tm(); // Display it in red.
cls="S9"; // Restore black color.
ob=true;break; // Set "already displayed" flag and exit.
}
}
if (!ob) tm(); // Display all other rows in black.
}
}
}
==============================================================================================
|
 |
==============================================================================================
Purging the Table File:
=======================
(1) Record length irregularity:
-------------------------------
When someone uses Notepad to enter data into the file, you can't ask him to count characters of
each line and not to Press [ENTER] unless the count is equal to the record length. Fortunately,
having records of different lengths in the file causes no problem.
However, whenever you call method fm("w") or fm("wn") to write a record, the record is made to
be equal in length to the record length. The record length of the file is the length of the
template record.
Mode "fp", the "File Purge" mode readjusts the length of every record in the file making them
all equal in length to the record length. As we have just mentioned this is nice but not a must
to do.
(2) Blank lines within data records:
------------------------------------
It is nice to insert a blank line each 3-5 lines. It improves visibility and look of the data.
Unfortunately, whenever we sort the file, all blank lines get eliminated.
Additional to readjusting record lengths, mode "fp" can insert blank lines into the file if
you assign a value to (i) If your assignment was (i=4), each 4th line will be a blank line.
(3) Deleting unwanted records:
------------------------------
This job can be done easily by calling fm("d") The file must be open before you do it and the
delete effect will not take place until you close the file.
==============================================================================================
Example 9: Delete the record with date "02/08/2008" which we have added to the file earlier,
then purge the file and add a blank line after each 3 data lines.
==============================================================================================
public class a : pcs {
public override void init() {
toa="t"; // Use text screen for text output
base.init();
}
public override void run() {
fns="crb10"; // Use courier font since alignment is necessary.
fs="tf0";fls="test.txt";fm("o"); // Open as a Table File.
K[0]=0;KS[0]="02/08";fm("fs"); // Search for rec with Date starting with "02/08"
rci=O[0];fm("d"); // Delete that record.
i=4;fm("fp"); // Purge remaining records, inserting blank line
fm("c"); // each 4th line. Close file.
fls="test.txt";fm("R");tm(); // Read all data and display.
}
}
=========================================================================================
|
 |
==============================================================================================
Performing an operation which requires reading all records in the file:
-----------------------------------------------------------------------
Just like any other file type, Table Files set the "job done" flag (dnb) when the last record
is read. So, you can use a "While" loop conditioned with (dnb) being not set to read all records,
same as you do with all other file types.
==============================================================================================
Example 10: Read all records of file "test.txt", add all the stock prices in each of the columns
"Open", "High" "Low" and "Close" and calculate the average of each column. Display the average
amounts at the bottom of their columns.
==============================================================================================
public class a : pcs {
// Var's used: t= Total number of records not counting blank ones.
// ts=String used to display price averages.
double[] TD=new double[4]; // Define an array to store totals of the 4 col's
public override void init() {
toa="t"; // Use text screen for text output
base.init();
}
public override void run() {
fns="crb10"; // Use courier font since alignment is necessary.
fs="tf0";fls="test.txt";fm("o"); // Open as a Table File.
rci=o; // Assign returned starting data rec# to (rci)
dnb=false;t=0; // Initialize eof flag and record counter.
while (!dnb) { // Repeat until eof encountered:
fm("r"); // Read a record (returns os, OS[])
om("c"); // Remove spaces from (os) to check record.
if (os.Length>0) { // If was not a blank line:
t++; // Increment number of records.
for (n=1;n<5;n++) { // Scan columns 1:4
os=OS[n];om("td"); // Convert data of each column to double.
TD[n-1]+=od; // and add it to each column's total.
}
}
rci++; // Increment record #
} // Then repeat loop.
fm("c"); // Close File.
fls="test.txt";fm("R");tm(); // Read all data and display.
os=" -------- -------- -------- --------";tm();
// Display lines at bottom of the 4 columns.
//--------------------- calculating and displaying price averages ----------------------
ts=" "; // Space before first column.
for (n=0;n<4;n++) { // Scan the 4 columns
od=TD[n]/t; // Get average price for each column.
ib=true;om("fd"); // Convert to formatted string of 2 decimal digits
ts+=os+" "; // Add price to display string (ts)
}
cls="r0";os=ts;tm(); // Display (ts)
}
}
=========================================================================================
|
 |
==============================================================================================
Identification Key:
===================
You already know that there is a considerable difference in speed between standard search and
binary search. Binary search requires data to be sorted at the column which is searched. We can
only sort at one column (if we like to keep things simple), so which column should we choose
for the sort?
Most of the time there is a column which can identify the record more than any other column. This
column should be the best to choose for the sort. Here is a list of variety of data types and
the fields which can best identify them:
(1) For Membership data, that column would be the User ID.
(2) For Sales and purchases that column would be the invoice number.
(3) For parts and other items Inventories that column would be the part number
(4) For Tax and financial data that column would be the Social Security Number.
Complex Identification Keys:
----------------------------
If your file contains peoples' names and addresses, you may like your Identification Key to be
the last name of the person followed with his first name. If you have a large mailing list, you
may like your primary field to sort at, to be the zipcode since this can qualify your mailing for
a discounted postage. You may then add the last name to the end of the zipcode then follow the
two with the first initial of the person like this: "45321SmithJ"
The Identification Key is required to be unique for each person in the list. This is why in large
lists, you may need to add more data to the Identification Key, like the street name, the house
number, .. etc.
How to make a sort within another:
----------------------------------
Sometimes, you like to sort your file by the zipcode as the primary field, however when more
than one person have the same zipcode, you like to sort their records additionally by the name
within the sorted zipcode. To do that, you sort the file by the secondary sort field first, then
you sort the file again by the primary field. This means that you sort by the name, then by the
zipcpde.
Can we sort more than one column independantly?
-----------------------------------------------
Yes. We can have subfiles which contain sorted single columns. This can allow us to use binary
search with any column except that it requires organization and maintenance which we'll have
time to discuss in the future. For now, we need to get into one important application on the
Table File which is entering data into standard form documents.
Data submission documents:
==========================
Let us assume that you like to write a Tax Preperation software. You like to enter the data,
save it, modify it from time to time, then when ready you want to print it into a standard tax
form and mail the form to the IRS.
The first step is to enter the data into file. You can enter the data item by item using the
Console or the Text Screen or you can use text fields to do more than one field at a time. All
those methods are slow, bulky and never feel you the same as when you look at the Tax Form and
fill it as it is. This is what we like to fix here. We like you to be able to do the following:
(1) Download the Tax Form from the IRS website and save it as an image file.
(2) Display the image on the screen, find the start and end locations of each required data
entry and save the (x,y) locations into a Table File. This should be done automatically. All
you should be doing is clicking on those locations.
(3) After the locations Table File is made, We need to create a Data Table File for the form
document. The template of this data file will also be made automatically for you based on
the field locations in the locations file.
(4) After the two files are made, it will be easy to write a program which asks the data entry
person to enter the identification key for the record he or she likes to submit data for.
The data file will then be searched for a record with a matching key. If found, all field
data will be read from the file and displayed at their correct locations in the form. If no
match found, the form will stay empty and the record will be considered a new record to be
added at the end of the file.
The data entry person will then enter or modify field data then save the data into file.
Do you need to write the software to do this job?
-------------------------------------------------
Yes you can easily do it, but we also have it all done for you. The Utilities method um() is
the method which handles Form Documents. Here is how to access the 5 required operations:
um("fl") Generates the program which creates "field locations" file as explained in
item (2) above.
um("ft") Creates the column titles and template for the "data file" based on the "field
locations" file as explained in item (3) above.
um("fa") File Analysis. Displays a list of all column names, their order no's and templates.
um("fd") Generates the data entry program which is explained in item (4) above.
um("fp") Print the form containing the data of one record.
IN: kys = Key of the record to be displayed into form before print.
jf,kf= Location of Form's center relative to paper's center.
lf,of= Desired Width and Height of printed Form.
REMARK: jf,kf,lf,of are not in pixels. They are in 1/100th of an inch unit.
Naming Files:
-------------
The file name which you supply to all 4 methods is the Form's image file name. Nmaes of all files
created will be based on that name. For example,
If your Form's image file path was: tax\\F1040EZ.bmp
Your Location file path will be : tax\\F1040EZ.loc
and your Data file path will be : tax\\F1040EZ.dta
You supply the image file to all 4 methods assigned to (fls) Method um("ft") requires one more
parameter which is the length (in char's) of the identification key assigned to (k) Also method
um("fp") requires one more parameter which is the key of the record to be printed assigned to
(kys)
Using the 4 methods:
--------------------
The easiest way to use those 4 methods would be to put them as items of a menu. Here is a menu
class (m) which can do it:
----------------------------------------------------------------------------------------------
public class m : pcs {
string fl1s="tax\\F1040EZ.bmp"; // Stores image file name.
int k1=9; // Default Key Length.
public override void run() {
cm("fe"); // Eliminate form
j=78;k=20;dm("cs"); // Recize Console
cls="s0";dm("ccb"); // Paint background with light gray.
while(true) { // Start of endless loop.
tm("c"); // Clear Screen
cls="r0"; // Set color to "Pure red".
fns="trb14"; // Set font to "times roman",bold,size 14.
os=" FORM DOCUMENTS MENU";
// and display this text.
tm(); // Calling method tm() to execute.
os="";tm(); // Skip one line
cls="b0";fns="trb10";
os=" Select (F) to supply image file name before any other selection is made.";
tm();os="";tm();cls="S9"; // Change color, font
os=" (F) Enter Form's Image File Name and Key length.";tm();
os=" (L) Create / Modify Field Locations File.";tm();
os=" (T) Create / Modify Data File template.";tm();
os=" (A) Analyze File's Columns and template.";tm();
os=" (D) Enter / Edit Data into Data File.";tm();
os=" (P) Print Form with one record data.";tm();
os=" (E) Exit.";tm();
os="";tm(); // skip one line
cls="b0";
os="Selection :";tm("i"); // Get user selection.
om("u");
int index="EFLTADP".IndexOf(os); // Check selection
if (index<0){ // If unexpected char entered
continue; // return to start of endless loop.
}
else if (index==0) break; // If selection was "E or e" exit loop
else if (index==1) { // Enter image file name.
os="Enter image file's name :";tm("i"); // Get file name, Assign it to (fl1s)
fl1s=os;
os="Enter Identification Key length (in char's):";tm("i");
om("ti");k=o; // Get Key length, assign it to (k)
}
else if (index==2) {fls=fl1s;um("fl");} // Create/Edit Locations File.
else if (index==3) {fls=fl1s;k=k1;um("ft");}// Create/Edit template of data file.
else if (index==4) {fls=fl1s;um("fa");} // Analyze file columns & templates.
else if (index==5) {fls=fl1s;um("fd");} // Enter/Edit data into data file.
else if (index==6) { // Print Form with one key data.
os="Enter Identification Key:";tm("i");
kys=os; // Get Key, assign it to (kys)
tm();os="";tm();cls="r0"; // Display instructions in red.
os=" X = Wanted horizontal location of Form's center relative to paper's center.";tm();
os=" Y = Wanted vertical location of Form's center relative to paper's center.";tm();
os=" W = Wanted Width of printed Form. H = Wanted Height of printed Form.";tm();
os="";tm();cls="b0"; // Get print locations from user
os="Enter X,Y,W,I (all in 1/100th of an inch unit) seperated with commas:";tm();
os="";tm();cls="S9";os="";tm("i");
tm();oc=',';om("s"); // Seperate 4 numbers into array OS[]
float j1f,k1f,l1f,o1f; // Convert each number to float and
os=OS[0];om("tf");j1f=of;os=OS[1];om("tf");k1f=of;os=OS[2];om("tf");l1f=of;
os=OS[3];om("tf");o1f=of; // assign to temp var's.
jf=j1f;kf=k1f;lf=l1f;of=o1f;
fls=fl1s;um("fp"); // Print Form with wanted rec data.
}
}
}
}
----------------------------------------------------------------------------------------------
Compile the menu with: pcp m [ENTER]
Notice that the the first item on the menu receives the two necessary parameters for other
selections. The defaults for image file name and key length are the values we are going to be
using in the next examples.
Writing Software for Tax Preparation Business:
==============================================
In order to illustrate the use of our "Form Documents" software, we are going to assume that
you need to create a "Tax Preparation software". We like the person who uses it to be able to
prepare taxes for several customers and store their tax data in a way which allows him to edit
the data at any time he chooses and to calculate their tax due.
The 3 methods above can help you with entering data into forms and file the raw data as they are.
You should then write programs to read those files and do their arithmatic in addition to all
the necessary software for the business.
Preparation for the project:
----------------------------
(1) Creating Subfolders: You need to organize your data by creating different subfolders for
each related items. For our sample, we are going to create one subfolder for the project
named "tax".
(2) Obtaining Tax Form Images: You need to connect to the IRS website at:
http://www.irs.gov/pub/irs-pdf/
they may require you to register before you can get to this page. You'll then see a list
of all "pdf" files of the forms. For the purpose of this demonstration, click on the tax
form "f1040ez.pdf" since it's the only form we'll be using.
The forms come with instruction pages attached which you don't need. So, click on the
"Graphics Select Tool" icon on the top. Click on the top left corner of the usable part
of the form and drag the mouse diagonally to the bottom right corner. You should see a
frame around the part which you are selecting.
Right click anywhere inside selected rectangle and select "Copy". The simplist way to create
an image file is by using the "Paint" program which is available in all versions of windows.
So, start "Paint" and paste the form there. Click on [File][Save as] and save it as a 24-bit
Bitmap file. Call the file "F1040EZ.bmp" and place it into the "tax" subfolder.
(3) Selecting an Identification Key: The best to use is the "Social Security Number" as a
9 digits with no hyphens or any other characters added.
Creating the Field Locations File:
----------------------------------
Compile and run the menu class (class m) listed above. You don't need to enter file name or key
length since the defaults are what you have. Select (L) You'll be instructed to type a field
name, after you type it and press [ENTER], you'll be instructed to click at the start position
then on the last position of the field. The process will repeat until all fields of the Form are
done. At this point, press [ENTER] without typing a field name, the locations file will be
created and you'll return back to the menu.
Get into Notepad and read the file. You should see a table similar to the one below except that
all colors, fonts and justifications for all fields will be at their default values which are:
Color: b0 Font: crb14 Justification: c
You'll need to edit the file using the following guidelines:
(1) The order of the fields should be the most comfortable to you since when you enter data and
use [TAB] to move forward, you'll be moving accress fields at the same order. When you enter
data you can either use [TAB] and [BACKSPACE] to move forward and backward accross fields or
you can jump to any field by clicking inside it.
(2) Field names are good to be short in general, however this becomes more important when the
expected field data is short. We used l/c for all field names of the tax form although this
is not a must.
The IRS uses line numbers to identify lines within their forms. This is good to use as field
names. So, as you can see, we gave the field "Line 1" the name "ln1" and so on.
When there is a seperator line in the form where one field is, we count it as two fields
and suffex them with "#1" and "#2". See the two fields "ln1#1" and "ln1#2". This helps with
alignment. Some data like social security number are seperated into 3 fields.
(3) Clicking the mouse can't be a very precisive process. So, you should expect to see some
inaccuracy in your start and end point coordinates of fields. Here are examples:
a) The Y-position of the start point and the Y-position of the end point may not be equal
although they should be since they are on the same line. You need to edit data to make
them equal.
b) The X-positions of the start and end points which you have clicked on may not allow enough
field width to enter the data into. for example, after you go to next step and make the
data file template, you may discover that some of the money amount fields allow only one
char for the pennies. In this case you must edit the X-values to allow for 2-digits data.
The most serious problems can happen with one char data fields like check boxes. You may
not give a check box enough width for one char, so there will be no template made for it.
This may cause field alignment errors when you start entering data.
(4) The data of each field can be displayed and printed in any color you want. However, blue
is used as the default for all. You may edit the color code of any field if you like.
(5) Font codes are important since they determine the number of char's which you can insert
into a field. Courrier font is important to use since width is unified for all its char's
and this makes it possible to compute the templates. Font code "crb14" is used as a
default, however we have changed the "date field" fonts to "crb11".
(6) JustificatiOn: This is important for alignment. The justification code can be (c/l/r)
meaning (Center/Left/right) For monies, you need to right justify dollar amounts and left
justify cent amounts in order to get them closer to each others.
Try to enter and edit field locations for the form by yourself and compare the result with ours.
FD NAME START X START Y LAST X LAST Y Color Font J Regular Expression
============== ====== ====== ====== ====== ===== ======= = ==============================
first 171 103 334 103 b0 crb14 l
last 361 103 577 103 b0 crb14 l
s_first 170 132 332 132 b0 crb14 l
s_last 359 132 582 132 b0 crb14 l
address 170 166 525 166 b0 crb14 l
aptno 543 166 586 166 b0 crb14 c
csaz 182 198 574 198 b0 crb14 l
ss#1 613 104 642 104 b0 crb14 r
ss#2 656 104 673 104 b0 crb14 c
ss#3 685 104 737 104 b0 crb14 l
s_ss#1 617 135 643 135 b0 crb14 r
s_ss#2 655 135 673 135 b0 crb14 c
s_ss#3 684 135 739 135 b0 crb14 l
ln1#1 644 266 714 266 b0 crb14 r
ln1#2 730 264 749 264 b0 crb14 l
ln2#1 629 296 716 296 b0 crb14 r
ln2#2 728 295 749 295 b0 crb14 l
ln3#1 629 325 716 325 b0 crb14 r
ln3#2 729 324 747 324 b0 crb14 l
ln4#1 629 354 716 354 b0 crb14 r
ln4#2 728 356 746 356 b0 crb14 l
ln5cby 180 410 190 410 b0 crb14 c
ln5cbs 275 410 284 410 b0 crb14 c
ln5#1 640 433 714 433 b0 crb14 r
ln5#2 730 434 746 434 b0 crb14 l
ln6#1 643 470 715 470 b0 crb14 r
ln6#2 729 470 746 470 b0 crb14 l
ln7#1 639 486 715 486 b0 crb14 r
ln7#2 728 486 747 486 b0 crb14 l
ln8a#1 642 501 718 501 b0 crb14 r
ln8a#2 729 502 747 502 b0 crb14 l
ln9#1 639 545 715 545 b0 crb14 r
ln9#2 730 544 745 544 b0 crb14 l
ln10#1 637 591 713 591 b0 crb14 r
ln10#2 729 592 747 592 b0 crb14 l
ln11acb 374 623 387 623 b0 crb14 c
ln11a#1 642 621 717 621 b0 crb14 r
ln11a#2 728 623 746 623 b0 crb14 l
ln12#1 638 711 714 711 b0 crb14 r
ln12#2 729 712 744 712 b0 crb14 l
date 391 820 446 820 b0 crb11 c
occupation 457 818 617 818 b0 crb14 c
s_date 391 851 446 851 b0 crb11 c
s_occupation 455 851 618 851 b0 crb14 c
-----------------------------------------------------------------------------------------
Creating the Data File Template:
--------------------------------
Your "locations" file must be complete as the one above and should be named "F1040EZ.loc" and
placed into the "tax" folder before selecting (t) from the menu to create the template.
The template creation is automatic and should be done in few seconds. Look in the "tax" folder
you should find a new file named "F1040EZ.dta". Open this file using notepad and inspect the
template. Return back to the guidelines above, especially (3b) and see if something needs to
be corrected. If you are sure that templates of all fields are OK, proceed to next section.
Entering data into data file:
-----------------------------
When you select (d) from the menu, the form will be loaded and displayed and you'll be asked to
enter the identification key of the record which you like to work on. Enter the key into the
text field at bottom and hit [ENTER]. The file will be searched for a record which contains
that key. If found all data of that record will be read and displayed at their proper locations
in the form. Otherwise it will be considered to be a new record and will be saved at the end of
all data in the file when you are ready.
To modify a field click where field data should be typed in, the field will be highlighted with
a yellow rectangle of same size as all the data which you are expected to insert into that field.
After typing your new data, you can do one of three:
a) Press [TAB] to edit the next field forward.
b) Press [BACKSPACE] to edit the next field backward.
c) Click into another field anywhere to move to it and edit it.
When you are ready to save the record, press [ENTER]. The record will be saved, all data on the
screen will be erased and you'll be asked to enter a new key for a record to edit. If you don't
like to save the edited data, press [ESCAPE] instead of [ENTER]. If you have no more records to
edit, close the Form's window.
=========================================================================================
BEST SELLERS FROM AMAZON.COM
Books, C Sharp Books, .NET Computers Electronics Industrial & Scientific Items MP3 Downloads DVD Camera & Photo Cell Phones & Services Magazine Subscriptions Office Products On Demand Videos
|
 |
==============================================================================================
Who can make use of the method explained so far to enter data into Tax Forms?
=============================================================================
Accountants who like to prepare their companies' taxes could appreciate being able to enter data
in a real Tax Form, save the data and retrieve it back any time they want then print the form
with the data in whenever they'are ready. Those accountants will be using their calculators to
do the arithmatic required by the form as they enter the data.
However, a Tax preparation business who serves larger number of customers cannot be satisfied
of using this software in its manual form. They need to do the calculations programmatically and
they like to store data which is common to more than one form into seperate files with software
available to transfer the data to any form whenever necessary. So, let us see how we can extend
this software to these new requirements.
Creating customer information file:
-----------------------------------
The first thing a business needs is a file which contains basic information about its customers.
It includes their names, addresses, phone numbers and any other necessary information. They
should be able to transfer data from this file to tax forms in addition to many other uses like
sending letters to their customers or calling them.
We need to make a table file which contains customer information. This should be easy, but how
are we going to enter the data into the file? The easiest way is "Form Documents" since as we
have already seen, they work automatically upto creating the data files and populating them. They
can also be printed as they are with no modifications.
This is a personal file, we have no image to download this time for the form, but we have all the
tools to make one. It should contain the business name and logo on the top and all data exactly
as the business needs it and should also look nice when displayed on the screen or printed.
===============================================================================================
Example 12: Create a form document to be used for entering data into customer information file.
The data should include all customer information which a tax business needs. After creating the
form image, use the "Form Documents Menu" to create the locations file, the data file and the
data file template. Use the menu also to populate the data file.
===============================================================================================
public class a : pcs {
public override void init() {
base.init();
}
public override void run() {
j=725;k=355;cm("fs");
cls="r0";i=5;gm("sps"); // Create red pen with 5-pixels width.
cls="s9";gm("ec"); // Paint form with white color.
lf=720;of=350;gm("crd"); // Display red frame.
// Create rect & draw.
cls="g0";gm("sps"); // Change color to green.
kf=160;fns="trb20";os="TAX PRO";gm("ctf");// Paint company name in green,
cls="S9";gm("sps"); // then frame around it in black.
kf=160;fns="trb20";os="TAX PRO";gm("ctd");gm("grd");
kf=140;fns="crb14";os="Tax Preparation Professionals";gm("ctf");gm("grf");
cls="c7";gm("sps"); // Background color of customer's section.
kf=40;lf=680;of=160;gm("crf");
cls="c7";gm("sps"); // Background color of spouse's section.
kf=-105;lf=680;of=90;gm("crf");
cls="r0";gm("sps"); // Display titles of both sections in red
kf=110;os="Customer Information";gm("ctf");gm("grf");
kf=-70;os="Spouse Information";gm("ctf");gm("grf");
cls="S9";gm("sps"); // Change color to black
//--------------------------------- Customer's Section -------------------------------
os="First Name: __________________ MI: _ Last Name: _______________________";
kf=88;gm("ctf");gm("grf");
os="Address: _____________________________________________________ Apt No: ____";
kf=66;gm("ctf");gm("grf");
os="City, State and Zipcode: ___________________________________________________";
kf=44;gm("ctf");gm("grf");
os="Telephone Number, H: ______________ M: ______________ B: ______________";
kf=22;gm("ctf");gm("grf"); // Double-Strike Text
os="Social Security Number: ___-__-____ Occupation: ___________________________";
kf=0;gm("ctf");gm("grf");
//----------------------------------- Spouse's Section -------------------------------
os="First Name: __________________ MI: _ Last Name: _______________________";
kf=-92;gm("ctf");gm("grf");
os="Social Security Number: ___-__-____ Occupation: ___________________________";
kf=-114;gm("ctf");gm("grf");
//---------------------------- Save form into an image file --------------------------
fls="tax\\customers.bmp";bip=bio;gm("bsb"); // Save as "bmp" file.
}
}
===============================================================================================
COMMENTS:
=========
Ther are few items concerning "Text Graphics" which we have not discussed in the graphics section
and will discuss here.
(1) When you draw the graphics object of text (gpp), using gm("ctd"), you draw the text outlines
and when you use method gm("ctf") you draw it filled. This feature has been used in this
example to draw the business name "TAX PRO" in green color with black borders.
(2) For some reason when you use a small font to draw text on the screen graphically, it comes
not as sharp and clear as when you display the text textually. You can't increase the
drawing pen's width to make it clearer. So we have used an old trick to solve this problem
which is called "double-striking".
Double-striking means displaying the item twice at the same spot on the screen or on paper.
We have used this method with mostly all text in the example. Calling gm("ctf");gm("grf");
double-strikes the text on the screen.
Compile the code of this example and run it. It should create the image file "customers.bmp" and
store it into the "tax" folder.
Run the "Form Documents Menu", select (F), supply the form image file name "tax\\customers.bmp"
and a key length of 9 char's. Then select (L) to create the locations file, select (T) to create
the data file, its column titles and its template. Finally select (D) to enter customers data
into the file.
Here is the location file which we have created:
FD NAME START X START Y LAST X LAST Y Color Font J Regular Expression
============== ====== ====== ====== ====== ===== ======= = ==============================
first 177 101 331 101 b0 crb14 l
mi 390 101 402 101 b0 crb14 c
last 532 101 730 101 b0 crb14 l
address 150 122 608 122 b0 crb14 l
aptno 695 122 729 122 b0 crb14 l
csaz 289 144 728 144 b0 crb14 l
phone_h 263 167 383 167 b0 crb14 c
phone_m 436 167 556 167 b0 crb14 c
phone_b 609 167 730 167 b0 crb14 c
ss#1 280 189 305 189 b0 crb14 c
ss#2 314 189 331 189 b0 crb14 c
ss#3 341 189 375 189 b0 crb14 c
occupation 496 189 730 189 b0 crb14 l
s_first 177 281 331 281 b0 crb14 l
s_mi 390 281 402 281 b0 crb14 c
s_last 532 281 730 281 b0 crb14 l
s_ss#1 280 303 305 303 b0 crb14 c
s_ss#2 315 303 331 303 b0 crb14 c
s_ss#3 341 303 375 303 b0 crb14 c
s_occupation 496 303 730 303 b0 crb14 l
===============================================================================================
|
 |
==============================================================================================
Creating data entry file:
-------------------------
Most of the time, the income amounts which we enter into a Tax Form make only about half of the
data to be entered into the form. The rest are calculated amounts which are derived from those
income amounts. This tells us that we can simplify the tax preparation job and reduce the
possibility of errors if we file the income amounts only using a small file, then write a program
which transfers those amounts to the Tax Form together with the calculated amounts.
In the real world, you'll be dealing with many tax forms, so you'll need a file which can store
enough data for them all. You may also consider making more than one file and creating a memu
which allows the tax preparer to select the file or files which store applicable data to each
customer.
The program you write should read all those "income" files, make all necessary calculations then
write data into all applicable tax forms.
This is what you'll be doing. We are not going to be sharing all this fun with you. We are going
to assume that form "1040EZ" is the only tax form to be used and will create the file
"income.dta" which stores the income data of that form. We are also going to show you an example
on how to use the two files "customers.dta" and "income.dta" to fill up form 1040EZ
programmatically and print it when complete.
===============================================================================================
Example 13: Create a form document to be used for entering data into income information file.
The data should include all income data of form 1040EZ not including calculated data. After
creating the form image, use the "Form Documents Menu" to create the locations file, the data
file and the data file template. Use the menu also to populate the data file.
===============================================================================================
public class a : pcs {
public override void init() {
base.init();
}
public override void run() {
j=430;k=355;cm("fs");
cls="r0";i=5;gm("sps"); // Create red pen with 5-pixels width.
cls="s9";gm("ec"); // Paint form with white color.
lf=425;of=350;gm("crd"); // Display red frame.
// Create rect & draw.
cls="g0";gm("sps"); // Change color to green.
kf=160;fns="trb20";os="TAX PRO";gm("ctf");// Paint company name in green,
cls="S9";gm("sps"); // then frame around it in black.
kf=160;fns="trb20";os="TAX PRO";gm("ctd");gm("grd");
kf=140;fns="crb14";os="Tax Preparation Professionals";gm("ctf");gm("grf");
cls="c7";gm("sps"); // Background color of upper section.
kf=40;lf=400;of=135;gm("crf");
cls="c7";gm("sps"); // Background color of bottom section.
kf=-100;lf=400;of=125;gm("crf");
cls="r0";gm("sps"); // Display title in red
kf=120;os="Income Information";gm("ctf");gm("grf");
cls="S9";gm("sps"); // Change color to black
//------------------------------------ Form body ----------------------------------------
os="Tax Year: ____ ";
kf=88;gm("ctf");gm("grf"); // Double-strike all the text to be displayed.
os="Check if married filing joint return ... [ ]";
kf=66;gm("ctf");gm("grf");
os="Check if someone claims you as dependant [ ]";
kf=44;gm("ctf");gm("grf");
os="Check if someone claim your spouse";
jf=-43;kf=22;gm("ctf");gm("grf");
os="as dependant and you are filing jointly [ ]";
kf=0;gm("ctf");gm("grf");
os="Wages, Salaries and Tips: ...... ________.__";
kf=-54;gm("ctf");gm("grf");
os="Taxable Interest: .............. ________.__";
kf=-78;gm("ctf");gm("grf");
os="Unemployment Compensation: ..... ________.__";
kf=-98;gm("ctf");gm("grf");
os="Federal income tax withheld: ... ________.__";
kf=-121;gm("ctf");gm("grf");
os="Earned income credit (EIC): .... ________.__";
kf=-143;gm("ctf");gm("grf");
//---------------------------- Save form into an image file --------------------------
fls="tax\\income.bmp";bip=bio;gm("bsb"); // Save as "bmp" file.
}
}
===============================================================================================
Compile the code of this example and run it. It should create the image file "income.bmp" and
store it into the "tax" folder.
Run the "Form Documents Menu", select (F), supply the form image file name "tax\\income.bmp"
and a key length of 9 char's. Then select (L) to create the locations file, select (T) to create
the data file, its column titles and its template. Finally select (D) to enter customers data
into the file.
Here is the location file which we have created:
FD NAME START X START Y LAST X LAST Y Color Font J Regular Expression
============== ====== ====== ====== ====== ===== ======= = ==============================
tax-year 426 101 461 101 b0 crb14 c
joint 572 121 583 121 b0 crb14 c
dependant 572 143 583 143 b0 crb14 c
s_dependant 572 188 583 188 b0 crb14 c
wages#1 494 243 563 243 b0 crb14 r
wages#2 574 243 590 243 b0 crb14 l
t_interest#1 494 267 564 267 b0 crb14 r
t_interest#2 573 267 590 267 b0 crb14 l
unemp#1 494 287 563 287 b0 crb14 r
unemp#2 573 287 589 287 b0 crb14 l
t_withheld#1 494 310 562 310 b0 crb14 r
t_withheld#2 573 310 590 310 b0 crb14 l
eic#1 494 332 564 332 b0 crb14 r
eic#2 573 332 590 332 b0 crb14 l
===============================================================================================
|
 |
==============================================================================================
Automated Tax Preparation:
==========================
Now it's time for the program which will read the "customers.dta" and the "income.dta" files,
and use their data to fill the "1040EZ" form, in addition to doing all arithmatic required by the
form. Filling the form with data means writing the data into file "F1040EZ.dta".
Before we write one record's data into a file, we always attempt to read the record first, so
that if it exists, we'll be overwriting its old data not creating a duplicate record. Whenever
we read a record we get 3 items which are:
(1) OS[] which contains all field data in order.
(2) (rcs) which is the archived copy of the last read or written record in a string form just
like it is in the file. You may use it but not overwrite it.
(3) (os) which is your copy of (rcs) Normally, you use it to know whether the record was a data
record or a blank line. You trim it using om("c") then check its length to determine which
type of record it is.
The record number (rci) which you supply to fm("r") when you read a record is kept unchanged for
you so that when you write the record, you'll be overwriting the existing one. After the record
is written, (rci) is reset to zero. You can't use (rci) at this point to read or write unless
you assign it a new value since (rci=0) generates an error.
In the following example, we'll be getting the identification key of the record to work on from
the user, searching for its record number into file "customer.dta" using method fm("fs") then
reading the record. The field data array OS[] returned will be persisted by assigning its value
to the local array O1S[].
Next, we'll repeat the same procedures with file "income.dta" and assign OS[] returned to the
local array O2S[]. Finally we'll do the same with file "F1040EZ.dta". Array OS[] returned from
that file will be overwritten by data stored into O1S[] and O2S[] and by calculated values. The
array will then be written back into that last file and the Tax Form data will be ready to
display or print.
Tax Form Arithmatic:
--------------------
Doing tax form's arithmatic requires some repeated jobs. So we are going to create 3 methods,
add(), subtract() and SetResult() When we store money amounts into a Form Document file, we use
two adjacent fields to store each amount, one for the dollars and one for the cents. When we
like a method to operate on a specific amount, we supply it with the index of OS[] where the
amount's dollar field is. The methods know that the cents amount of that field will be found
at the next row of OS[]. Let us start with method SetResult() since it's the simplest.
void SetResult(int n) {
// Store amount in (od) into data array. IN: n=index of OS[] to store dollar part at.
ib=true;om("fd"); // Convert (od) to string with 2 decimal digits.
int d=os.IndexOf("."); // Find index of decimal point
OS[n]=os.Substring(0,d); // Store dollar part at (n)
OS[n+1]=os.Substring(d+1); // and cents part at (n+1)
}
This method recieves a money amount stored into the global variable (od) and splits it into two
parts, "dollars" part and "cents" part. It also receives an additional parameter which is the
index of OS[] where the "dollars" part should be stored. The "cents" part will be stored into
the next field. Now, let us see method subtract():
void subtract(int x,int y) {
// Calculate (First amount) - (Second amount) and store result into (od)
// IN: x,y=index of OS[] where dollar parts of the two amounts are. OUT: od
od=0; // Start with od=0
os=OS[x];om("ti");od+=o; // add dollar part of first amount to (od)
os=OS[x+1];om("ti");od+=0.01d*o; // add cents part of first amount to (od)
os=OS[y];om("ti");od-=o; // subtract dollar part of second amount from (od)
os=OS[y+1];om("ti");od-=0.01d*o; // subtract cents part of second amount from (od)
}
and finally here is method add():
void add() {//IN:I[]=Indices of Dollar fields to be added. OUT:od
// Add all amounts whose dollar parts are to be found in OS[] at indices contained into array
// I[] and return result assigned to (od)
od=0; // Start with od=0
for (int i=0;i< I.Length;i++) { // Scan all indices in the supplied array
if (I[i]==0) break; // When first unassigned row is reached,exit
os=OS[I[i]];om("ti");od+=o; // Add dollar part of each amount to (od)
os=OS[I[i]+1];om("ti");od+=0.01d*o; // Add cents part of each amount to (od)
}
}
Finding Tax Due:
----------------
The correct way is to store the Tax Tables into an additional Table File and search the file to
get the tax due using the "Taxable Income" amount on line 6 of the form. We don't see a reason
to do that here since it'll not add much to your learning. So, we used this simple formula:
Tax rate for singles: 30%
Tax rate for couples filing jointly: 20%
Finding Column orders for all 3 files:
--------------------------------------
You are going to need to know where each field is located into each file before writing this
program. So select (A) from the "Form Documents" menu and print the displayed list (using text
screen print option) Use Courrier font size 10 for printing. Do that for all 3 files.
------------------------------------------------------------------------------------------------
public class a : pcs {
// var's used: O1S[] Persists field array OS[] of file "customers.dta"
// O2S[] Persists field array OS[] of file "incone.dta"
// FileLength: a type "long" value to persist file length of "F1040EZ,dta"
// JointReturn: a flag which indicates that "Joint Return" filing is to be used
string[] O1S,O2S; // Define var's. See above.
long FileLength;
bool JointReturn=false;
public override void init() {
tia=toa="t";
bli=1;
base.init();
}
public override void run() {
if (blp==1) { // Starting block
cls="r0";os=" TAX PROCESSING";
tm();os="";tm();cls="b0"; // Display title then change color.
os="Enter key number of the tax record you like to process: ";bli=2;tm("i");return;
} // Get key from user then move to block 2.
if (blp==2) { // Return after key has been received
kys=os; // Assign key to (kys)
//---------------------------- Get all field data for key ------------------------------
// Open customers file, get data for the wanted key and store it into O1S[]
fs="tf0";fls="tax\\customers.dta";fm("o");
K[0]=0;KS[0]=kys;fs="tf0";fm("fs"); // Search for the record which contains (kys)
if (O[0]>0) { // If a match found:
rci=O[0];fs="tf0";fm("r"); // Read matching record
}
O1S=OS; // and store its field data array into O1S[]
// Open income file, get data for the wanted key and store it into O2S[]
fs="tf1";fls="tax\\income.dta";fm("o");
K[0]=0;KS[0]=kys;fs="tf1";fm("fs"); // Repeat with the income file
if (O[0]>0) {
rci=O[0];fs="tf1";fm("r");
}
O2S=OS;
// Open Tax Form file, get data for the wanted key (if available), store (ol) into
// (FileLength)
fs="tf2";fls="tax\\F1040EZ.dta";fm("o");
FileLength=ol;
K[0]=0;KS[0]=kys;fs="tf2";fm("fs"); // Repeat with the Tax Form file
if (O[0]>0) {
rci=O[0];fs="tf2";fm("r");
}
else rci=(int)FileLength; // If no match found, make (rci) point to end of file
//------------------------- Copy values from "customers" file ---------------------------
OS[0]=kys; // Key
OS[1]=O1S[1]+" "+O1S[2]; // First Name and Initial
OS[2]=O1S[3]; // Last Name
OS[3]=O1S[14]+" "+O1S[15]; // Spouse 1st name and initial
OS[4]=O1S[16]; // Spouse last name
OS[5]=O1S[4]; // Address
OS[6]=O1S[5]; // Appartment number
OS[7]=O1S[6]; // City, State and Zipcode
OS[8]=O1S[10];OS[9]=O1S[11];OS[10]=O1S[12];
OS[11]=O1S[17];OS[12]=O1S[18];OS[13]=O1S[19];
// Social Sec Number for customer and his spouse
OS[42]=O1S[13]; // Occupation
OS[44]=O1S[20]; // Spouse Occupation
//--------------------------- Copy values from "income" file ----------------------------
// If "Joint Return" checked set flag.
// Standard Deductions: Start with od=0. add $8,750 for each of customer and his spouse
// unless someone claims them as dependant. Set results and mark proper checkboxes in form
if (O2S[2].Length>0) JointReturn=true;
od=0;
if (O2S[3]=="") od+=8750.00;else OS[22]="x";
if (O2S[4]=="" && JointReturn) od+=8750.00;else OS[23]="x";
SetResult(24); // Set standard deduction amount at line 5.
OS[14]=O2S[5];OS[15]=O2S[6]; // Set Wages at line 1
OS[16]=O2S[7];OS[17]=O2S[8]; // Set Interest at line 2
OS[18]=O2S[9];OS[19]=O2S[10]; // Set unemployment compensation at line 3.
I=new int[]{14,16,18};add(); // Add lines 1,2 and 3
SetResult(20); // and set them at line 4.
subtract(20,24);SetResult(26); // Subtract line 5 from line 4 and set result at ln 6
OS[28]=O2S[11];OS[29]=O2S[12]; // Copy "Tax Withheld" to form
OS[30]=O2S[13];OS[31]=O2S[14]; // Copy EIC to form
I=new int[]{28,30};add(); // Add the two together and
SetResult(32); // Set result at line 9.
// Finding tax due: We are going to simplify the process by making it 30% for singles
// and 20% for couples
od=0; // Initialize (od)
os=OS[26];om("ti");od+=o; // Add dollar part of "Taxable income" (line 6)
os=OS[27];om("ti");od+=0.01d*o; // and also add cents part to it.
if (!JointReturn) od=0.30*od; // Assuming 30% tax on singles
else od=0.20*od; // and 20% tax on couples
SetResult(34); // Set tax due at line 10.
subtract(32,34); // Subtract taxes due (ln 10) from paid taxes (ln 9)
if (od>0) SetResult(37); // If positive set as amount to be refunded (ln 11a)
else if (od<0) { // If negative:
od=-od;SetResult(39); // Set as amount owed (ln 12)
}
display(); // Display data
fs="tf2";fm("w"); // Write record into file.
fm("c"); // Close file.
}
}
//------------------------------------ Local Methods ---------------------------------------
void add() {//IN:I[]=Indices of Dollar fields to be added. OUT:od
// Add all amounts whose dollar parts are to be found in OS[] at indices contained into array
// I[] and return result assigned to (od)
od=0; // Start with od=0
for (int i=0;i< I.Length;i++) { // Scan all indices in the supplied array
if (I[i]==0) break; // When first unassigned row is reached,exit
os=OS[I[i]];om("ti");od+=o; // Add dollar part of each amount to (od)
os=OS[I[i]+1];om("ti");od+=0.01d*o; // Add cents part of each amount to (od)
}
}
void subtract(int x,int y) {
// Calculate (First amount) - (Second amount) and store result into (od)
// IN: x,y=index of OS[] where dollar parts of the two amounts are. OUT: od
od=0; // Start with od=0
os=OS[x];om("ti");od+=o; // add dollar part of first amount to (od)
os=OS[x+1];om("ti");od+=0.01d*o; // add cents part of first amount to (od)
os=OS[y];om("ti");od-=o; // subtract dollar part of second amount from (od)
os=OS[y+1];om("ti");od-=0.01d*o; // subtract cents part of second amount from (od)
}
void SetResult(int n) {
// Store amount in (od) into data array. IN: n=index of OS[] to store dollar part at.
ib=true;om("fd"); // Convert (od) to string with 2 decimal digits.
int d=os.IndexOf("."); // Find index of decimal point
OS[n]=os.Substring(0,d); // Store dollar part at (n)
OS[n+1]=os.Substring(d+1); // and cents part at (n+1)
}
void display() {
fns="crb12";cls="S9";os="";tm(); // Change color and font
os="No. NAME VALUE";tm(); // Display Title
for (n=0;n< CNI[2];n++) { // Scan all columns. Start with spaces in (os)
os=" ";
js=""+n;j=0;om("m"); // Insert column no
js=CNS[2][n];j=4;om("m"); // Insert Column Title
js=OS[n];j=20;om("m"); // Insert Column data
tm(); // Display row
}
}
}
===============================================================================================
Printing the Form:
------------------
You can print the form after being filled-up with one record either manually by clicking the
"Print" button which is available when you select (D) from the menu or programmatically by
calling um("fp")
When you use the print button, the Form will be printed at a default size which is computed
using the Form image's size in pixels and its resolution. Method um("fp") allows you to select
the location of the printed Form's center relative to paper's center and the wanted width and
Height of the Form. These values are not in Pixels. They are in 1/100th of an inch unit.
We don't recommend supplying both width and height (lf,of) at the same time. Supply one of them
and assign zero to the other one. The method will reassign the one which is assigned zero a
calculated value which makes the width to height ratio of the printed image equal to the
original's. If you like to print at the default size like you do when you use the Print button,
assign zeros to both (lf & of)
===============================================================================================
|
 |
|