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
/
CPMUG028.ARK
/
MAILLIST.DOC
< prev
next >
Wrap
Text File
|
1984-04-29
|
23KB
|
608 lines
FILENAME: MAILLIST.DOC, 09/25/77 by Ward Christensen
12/17/77 ADD 'RESIZE' DOC
4/1/78 ADD "MUST WRITE" AND "MUST UPDATE" DOC
4/8/78 ADD LETTER WRITING INFO FOR REPORT.BAS
------------------------------------------------------------
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. ABSOLUTELY NOT FOR OTHER
COMMERCIAL USE. WHY? I HATE JUNK MAIL LISTS, AND I DEFINE
JUNK MAIL LISTS AS ANY MAIL LIST WHERE THE RECIPIENT DID
NOT EXPLICITLY ASK FOR THE MAILING.
------------------------------------------------------
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 to fulfill these needs are:
1) PREFORMAT.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.
4) RESIZE.BAS to change the master file size
5) QUICKIE.BAS skeleton program for modification
------------------------------------------------------------
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.
NOTE that a flag is set in the program, requiring
you to do an UPDATE command (or WRITE if you did
an ADD). I added this because I found some times
I would forget. You can cancel the flag with
the command: CANCEL
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 ?
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 CI 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. A flag is set in
the program, to help remind you to write it back.
The only functions you will be able to execute
are those which will not destroy the record:
C
LIST
VERIFY
WRITE
If you want to cancel the record, resetting
the flag, use the command: CANCEL
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
CANCEL: Cancels the flags set in the program which require
you to WRITE after an ADD, or UPDATE after FINDing
a record and Changing it.
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, name tags, meeting announcement letters, listings
of expiring memberships, etc. 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.
Randy Suess of the Chicago Area Computer Hobbyist Exchange
suggested an alternative if you do not have sense switch
control, and that is to input a dummy message, which you
can then type 'space, control-p' in reply to. This will
turn on the printer. You will have trouble with the end
of the report or labels, because you cannot shut it off
again, but that is not serious. In running the report program,
I was sorry to see how slow it accessed the disk. I then
realized that the file was being closed and opened each
time the random access took it into another extent. I tried
to find a solution, and found one: I opened a separate 'file'
for each extent. Then, I divided reads such that reads
to the first extent read via the first file, to the second
extent via the second file, etc. After a few accesses,
each 'file' was open for it's own extent, and performance
was quite good. 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.
LOAD filename.filetype: Used to load a letter file
into memory. The letter file consists of up to
40 lines. The following command is used to
print the letters (such as meeting announcements)
LETTER: Causes a letter, contained in a matrix in memory
(loaded there via the LOAD command) to be printed.
The index table is used to determine the order
that the letters are written in (typically ZIP).
You must use the LOAD command to read the letter,
and the INDEX command to load the index (created
by the SORT program) before running LETTER.
The format of the letter is as follows: The person's
name is printed, then the letter. Then a forms feed
(chr$(12)) is printed, to skip to the BOTTOM THIRD
of the page. The return address is printed, then
"ADDRESS CORRECTION REQUESTED", then the name and
address from the file, and finally at the bottom
of the page, a membership status line. NOTE that
this means that you MUST set up your printer so
that forms feed feeds to the BOTTOM THIRD of the
paper. This is for efficiency, as the biggest skip
done in the letter is from the end of the letter
to the 'postal letter' part.
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.
-------------------RESIZE PROGRAM---------------------
The RESIZE program converts the file from one size to
another. It reads the old file sequentially, and randomizes
and writes the new file. It asks for the filenames
during execution, so the program need not be recompiled
to change names. It need only be recompiled if changing
fields, or record size from the default 128.
The program will allow A: and B: specifications for
the file, so the new size file may be built on a disk other
than the one the original one was on.
N-O-T-E that the mailing list file is a standard CP/M
file, and may therefore be processed with the 'PIP'
utility.