home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
SIMTEL
/
CPMUG
/
CPMUG006.ARK
/
MAILLIST.DOC
< prev
next >
Wrap
Text File
|
1984-04-29
|
19KB
|
524 lines
FILENAME: MAILLIST.DOC, 09/17/77 by Ward Christensen
------------------------------------------------------------
DOCUMENTATION FILE FOR THE COMPUTER CLUB
MAILING LIST PROGRAMS WRITTEN IN BASIC-E.
-------------------------------------------------------
THESE PROGRAMS ARE BEING PROVIDED THROUGH THE COURTESY OF THE
AUTHOR FOR THE SOLE USE OF HOBBYIST COMPUTER CLUBS IN
MAINTAINING THEIR MAILING LISTS.
------------------------------------------------------
The needs of a computer club in maintaining a mailing
list consist of the following requirements:
1) A file of names with sufficient information
about each member.
2) A maintenance program to add, change, and delete
records.
3) A sort program to change the order of the file (by
last name, zip, etc.) for report purposes.
4) A program to print:
Alphabetic master listings
Mailing labels (usually in Zip sequence)
Name tags for meeting use.
The programs on this disk fulfill these needs.
1) PREFMT.BAS preformats the required size file
2) MAINT.BAS maintains the mailing list
3) SORT.ASM sorts the file, producing an index file
4) REPORT.BAS prints listings labels and name tags.
------------------------------------------------------------
As currently implemented, the file consists of 512, 128
byte (1 sector) records. It was originally thought that
1 sector records would be required because of the sort
program written in assembler. However, the sort program
was eventually written to be independent of file length.
Note that 128 is still a very good value, because of
the efficiency of BASIC/E only having to
read 1 sector per record. If the record length was
say, 150 bytes, then 2 sectors would always have to
be read. Also, random writing would have to read
modify, and write sectors because of the sector overlap.
For speed of access during maintenance, the file is
written using a randomizing or hashing technique on the
person's name. The algorithm is as follows: A variable
is initialized to 0. Then, every other letter in the person's
name (1, 3, 5 ... n) is, one at a time, added into the
variable. The variable is doubled between each addition.
Then, the result is divided by the number of records in
the file, and the remainder is used as a record number.
When adding, if the record is already in use, the file is
sequentially read from that point until an open record is
found. When retrieving, the record randomized to is read,
and the name is matched. If it is not the right name,
the file is read sequentially until the a record with
a matching name is found. You may press 'DEL' (or rubout)
to stop the scan in case, for instance, you misspelled the
name. Note that the technique is simple, and is not for-
giving of misspelled names.
The algorithm, in BASIC this is:
KEY=0
FOR I=1 TO LEN(KEY$) STEP 2
KEY = 2*KEY + ASC(MID$(KEY$,I,1))
NEXT I
KEY = KEY- FILE.SIZE*INT(KEY/FILE.SIZE)
IF KEY = 0 THEN KEY = 1
------------------------------------------------------------
The file currently has the following fields in the record:
SORT: A 4 byte field on which the file is sorted, to
be in alpha sequence. This means that you do
not store the file as 'lastname,firstname'
which is very 'computeristic' and 'impersonal'.
instead, you key in the name in it's natural
form, then use the 4 byte SORT field
for sorting. For example, if the name is
James R. Smith, then the sort field would be
keyed in as SMIT.
NAME: The person's 'natural' name, i.e. first name first.
Remember BASIC won't allow commas,
so don't key in J. SMITH, JR. but rather
J. SMITH JR.
ORGANIZATION: This field is normally blank, but is provided
when a 4-line address is required. When
adding a person, BASIC/E will not accept
a totally blank input, so 1 blank must be keyed
when ORGANIZATION is not present.
STREET: The street address
CITY: The city AND state. Since BASIC will not
allow a comma in an input line, simply use
a space after the city, such as:
CHICAGO IL
I originally considered putting STATE as a
separate field, but BASIC/E files use quotes
around each field, and separate fields by
commas. Thereore, a 2 byte state field would
take 5 bytes. There just wasn't sufficient
room in a 128 byte record. (Although recall
that I now realize the record length does not
have to be restricted to 128 bytes.
ZIP: 5 byte numeric zip code
PHONE: 10 digits, with parenthesis, spaces, and dash, as:
(312) 555-1212
COMPUTER: A 5 byte field used to keep track of the
computer owned, such as A8800, IMSAI, DGZ80, etc.
PAID: A 2 byte field showing when membership is again due,
in the form YYMM such as 7809
TYPE: A 1 byte 'type of member' field. Currently used:
G Group (another computer club)
M Magazine
H Hobbyist
V Vendor
These are arbitrary values, however the REPORT
program, when printing name tags for a meeting,
will not print tags for type G or type M.
--------------------PREFORMAT PROGRAM--------------------
This program preformats the file. It writes records
with a '0' flag byte, i.e. empty records. From then
on, the Maint program is used to add, change, and delete
members of the file.
------------------MAINTENANCE PROGRAM--------------------
This program maintains the file. It has the following
commands implemented to do so:
MACRO: Allows issuing a string of up to 10
commands, over and over. Useful for
doing such things as scanning the
file for a certain field
value, then changing the value,
and doing it over and over.
FORMAT: MACRO
You will be prompted for input.
When running in MACRO mode, a DEL
from the keyboard will stop execution
HELP: Prints a summary of the commands
available.
FIND: This is the ONLY command which
accesses the file thru the randomizing routine.
FORMAT: FIND name where name is the
exactly spelled name of a person in the file.
EXAMPLE: FIND WARD CHRISTENSEN
The name is arithmetically hashed to a record
number. The file is scanned from that record
number forward (wraps from end to beginning)
until a matching name is found. You can press
DEL at any time to stop the scan and return
to command mode.
READ: This command is used to read a particular
record in the file by record number. It is
not frequently needed.
FORMAT: READ recno
EXAMPLE: READ 20
DUMP: This command sequentially dumps the file
from a given starting record number.
Press DEL to stop the dumping.
FORMAT: DUMP recno
EXAMPLE: DUMP 155
C: This command is used to change the contents
of a field in the record most recently read
into memory. It can change an entire field
by replacing it with a new value, or can do
a character string replacement such as to correct
a misspelled field value.
FORMAT: C fieldname newvalue
EXAMPLE: C NAME J. SMITH
The field name can be abbreviated. The
table of field names in the program will
be searched until the first 'n' letters
of a name match the 'n' letters in the field name
used in the C command. N is therefore a sufficient
abbreviation for NAME, but C will find CITY
and not COMPUTER, so use CO for COMPUTER.
FORMAT: C fieldname /oldvalue/newvalue/
EXAMPLE: C N /TIANSON/TENSEN/
The above example would change WARD CHRISTIANSON
to WARD CHRISTENSEN. The closing '/' is
optional.
LIST: Used to list the contents of the record
most recently read into memory.
FORMAT: LIST
?: This command is used to scan the disk
from the current position (the last record
number read) for any field matching a value
placed in the command. Only the first 'n'
characters of the field on disk are matched,
where 'n' is the number of characters given
in the command. The match always starts
with the leftmost byte of the field.
FORMAT: ? fieldname value
EXAMPLE: ? CO ALTAIR
The contents of each field read will be
displayed whether or not it matches.
Use DEL to stop the scan.
F: This command (Find) works like C
except that the field read from disk is scanned
for a match at each position in the field, not
just the first. For example, if everyone
in the club having a Z-80 computer has
a 'Z' somewhere in their COMPUTER field,
but it differs from user to user (such as DGZ80,
IMSZ8, Z2, etc.) then you could find
someone with a Z80 by saying:
F CO Z
FORMAT: F fieldname charstring
EXAMPLE: F STATE IL
NOTE this runs 'lots' slower than '?' because
of multiple comparisons being done on each
field.
WRITE: This command is used to randomize and write
a record to disk. It is used after the ADD
command, or when changing someones name.
See "CHANGING A NAME" below.
FORMAT: WRITE
ADD: This command is used to add a new name
to the file. You will be prompted for each
field. If a field is blank, you cannot just
press C/R because BASIC/E will give you a
WARNING II message. Therefore, put in 1 space
the press return.
If you want to stop the ADD function, such as
if you realize you made a mistake and don't
want to go back and change it with the C function,
type QUIT in response to any input.
FORMAT: ADD
You will be prompted for the input.
NOTE the record is only built in a matrix
in memory, and that the WRITE function must be
executed to actually write the name to disk.
This allows using the C and LIST command to
verify and change the contents of the record
before writing it to disk.
Also, see "CHANGING A NAME" below.
There is one problem when adding records to
the file, and that is that you cannot add a record
which exceeds the record length. BASIC/E will
unforgivingly issue an ER error and drop you
back into CP/M. Due to the preallocation of the file,
however, this is not serious as only the record
currently being added is lost. A 'lot' of
code could be added to add up the lengths of each
field, plus 1 for the flag, plus 3 for each field
(the quotes around the value, plus the comma separating
values) but I just decided not to bother.
ERASE: This command will erase the record most
recently read. The record will still remain in memory
such that a WRITE command could be used to write
it back to disk, as would be required with a name
change.
FORMAT: ERASE
UPDATE: This command writes a record BACK to disk, and
is used following a FIND or READ command. Npote
that if used after an ADD command, you will overlay
the wrong record. You must use WRITE after ADD.
FORMAT: UPDATE
FREE: Used to determine how much memory is left
during the running of the MAINT program. Used
during program development to see if room remained
to add more function
PURGE: Used to purge the file of records whose memberships
have expired. The file is scanned for a matching
date (PAID field) as given in the command, and
all records matching are deleted. It is suggested
the printer be turned on before issuing the PURGE
command to keep an 'audit trail' of who was purged.
FORMAT: PURGE yymm
EXAMPLE: PURGE 7709
END: Used to end execution. Control-C can also
be used, as the file doesn't have to be closed,
because it is pre-allocated.
CHANGING A NAME: Since the file is written by randomizing
the name field, you cannot simply FIND someone, use C
to change their name, and UPDATE the record. Why?
Next time you want to find them, you will type
FIND newname and will randomize to it. However,
the name is stored under the randomizing of the
OLD name. Therefore, after changing a name,
issue an ERASE to get rid of the old record, then
WRITE to re-randomize the new name and write the
record. This works because ERASE doesn't change
the contents of the record maintained in the
matrix in memory.
--------------------SORT PROGRAM--------------------
The sort program is an assembler program which reads the
mailing list, extracting the first 5 characters of a
specified field, and doing a memory-resident bubble sort
of the field and it's correspoiding record number.
It then writes an ASCII file of just the record numbers.
It is currently set up for 3 byte record numbers,
but may be easily changed for 4 byte record numbers.
(Comments in SORT.ASM show how). The file of record
numbers is then used in the REPORT program to process the
file in the sequence asked for. The index file is read
into a table rather than accessed sequentially, for speed.
FORMAT: SORT infilename outfilename fieldnumber
EXAMPLE: SORT CACHE.FIL NAME 1
Note that 'outfilename' can be any valid
CP/M file name.
The field numbers currently implemented are as
follows:
1. SORT
2. NAME
3. ORGANIZATION
4. STREET
5. CITY
6. ZIP
7. PHONE
8. COMPUTER
9. PAID
10. TYPE
--------------------REPORT PROGRAM--------------------
The report program is used to produce listings,
mailing labels, and name tags. The listings can
be either 130 columns wide, or can be printed with 2
lines for each person, on 8.5 wide paper. Name tags
and Labels may be printed 3-up or 4-up, with variable
width and height labels. It is currently written for a
Centronics 101 with the feature of expanding the width
of characters when you print CHR$(14). If you do
not have this facility, the program will have to
be changed. Note this affects only the printing of name
tags (which print the name and computer double width)
and the title of the report. Also the program prints CHR$(11)
(Vertical Tab) to eject the paper to a new page. If you
do not have this feature, you will have to insert the proper
number of null print statements to cause an eject to the
next page. Some printers may require CHR$(12)
(Forms Feed) instead.
Since there is not currently a way to turn on the
printer from BASIC/E, this program requires a CBIOS
with manual printer control, such as thru a sense switch,
to operate correctly. The program prompts you with
'press linefeed' which then allows you time to
turn on the sense switch. When it sees the linefeed on
the keyboard port, it starts the listing.
When the listing is complete, it awaits a 'del'
from the keyboard before continuing. This again gives
you time to turn off the sense switch controlling the
printer.
The commands currently implemented in the program are:
HELP: Prints a summary of commands available.
INDEX: Names the file of record numbers (output
from the SORT program), and causes the file to
be read into memory.
FORMAT: INDEX filename
EXAMPLE: INDEX NAME.FIL
POSITION: Positions the file to a particular
record relative to the INDEX file which has
been read. Used to restart a listing, or
to scan for starting the listing in the middle.
It can position either by record number, or
by the contents of the field sorted upon.
FORMAT: POSITION recno
EXAMPLE: POSITION 55
or
FORMAT: POSITION fieldname fieldvalue
EXAMPLE: POSITION ZIP 60419
In the first example, the file is positioned
to the 55th record in the index
table. In the second example, the file is
sequentially read (from whatever position is
currently is at) until a zip matching 60419 is
found. You may find it useful to use the
first format to get 'close' because positioning by
record number is fast, then use the position by
field value until the exact one is found.
NOTE that it is somewhat meaningless to POSITION
on a field which is not the sort field, as the
field being positioned upon is not read in order.
NOTE if you stop the listing, then want to
restart it from the beginning, you must
issue POSITION 1 to start over again.
TITLE: This command is used to supply a title
for the listing.
FORMAT: TITLE any character string
EXAMPLE: TITLE SEPTEMBER MEETING ALPHA LISTING
PRINT: This command is used to initiate the printing
of a listing. The listing will be either:
72 columns wide if width < 80, or
132 columns wide if width > 79.
Other than being less than or greater than 80,
the setting of width does not effect the output
of the PRINT function.
FORMAT: PRINT
WIDTH: Sets print width. The meaning of the width
depends upon the function being asked for:
TAGS or LABELS - the WIDTH setting is the actual
number of characters wide the labels are.
PRINT - the WIDTH setting determines the report width
but only as to whether width is <80 or >79.
FORMAT: WIDTH nn
EXAMPLE: WIDTH 36
LENGTH: Sets the length of the gummed
labels used for the LABELS or TAGS function.
Default is 6 lines long.
FORMAT: LENGTH nn
EXAMPLE: LENGTH 5
TAGS: Initiates the printing of name tags.
An algorithm is used to split the first name
from the last name: The name is scanned from
the back until a space is found. The part
of the name to the right of the space is now
considered the last name, and the part to the
left the first name. Then, certain 'reasonableness'
tests are performed: If the first 2 letters of the
last name are JR, then the scan continues again
to the left. Then, the last few characters of
the 'first name' are checked to see if they are any
of the common double word last names, such as
' VAN' or ' DE' or ' DI' or ' MC'. If so,
scanning continues again. You might have to change
this algorithm depending upon the names you encounter,
such as 3 word names (VAN DER HEIDE) or VON, or
the myriad of names I have not yet dreamed of.
FORMAT: TAGS
LABELS: This initiates the printing of mailing labels.
It uses the settings of WIDTH, LENGTH, and UP
to determine the physical format.
A typical label is printed as follows:
FERN P. DOCK 7709
HENWAY CORPORATION
BOX 1234
FERNWOOD OH 12345
(What's a HENWAY? about 3 pounds).
Note the PAID date is printed in the upper
right of the label.
FORMAT: LABELS
CHECK: This function checks the setting of the
various variables, such as what record
you are positioned to, whether an index has
been read or not, and the current settings
of: WIDTH, LENGTH, etc.
FORMAT: CHECK
UP: This is used to cause printing of LABELS
or name TAGS 3-UP or 4-UP. (UP referring to
how many labels are printed side-by-side.
The program has not been generalized to handle
1-up or 2-up.
FORMAT: UP n
EXAMPLE: UP 3
3 or 4 are the only values supported.
END: Causes ending of program execution.
--------------------MISC. COMMENTS--------------------
Use abbreviations to keep the width of each field
within the width allowed in the report program,
or else the TAB to the next field will cause an extra
line to be printed. This will offset the line counter,
and may cause the program to print a page which is too
long.