home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-06-29 | 42.8 KB | 1,160 lines |
- Volume 3, Number 2 June 29, 1992
-
-
-
-
-
-
-
-
-
-
-
-
-
- **************************************************
- * *
- * QBNews *
- * *
- * International QuickBASIC Electronic *
- * Newsleter *
- * *
- * Dedicated to promoting QuickBASIC around *
- * the world *
- * *
- **************************************************
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The QBNews is an electronic newsletter published by Clearware
- Computing. It can be freely distributed providing NO CHARGE is charged
- for distribution. The QBNews is copyrighted in full by Clearware
- Computing. The authors hold the copyright to their individual
- articles. All program code appearing in QBNews is released into the
- public domain. You may do what you wish with the code except
- copyright it. QBNews must be distributed whole and unmodified.
-
- You can write The QBNews at:
-
- The QBNews
- P.O. Box 507
- Sandy Hook, CT 06482
-
- Copyright (c) 1992 by Clearware Computing.
-
- The QBNews Page i
- Volume 3, Number 2 June 29, 1992
-
-
-
- ----------------------------------------------------------------------
-
- T A B L E O F C O N T E N T S
-
-
- 1. From the Editor's Desk
- Is this Goodbye? ............................................. 1
-
- 2. DataBASICs and File I/O
- File Types 100 by Richard Vannoy ............................. 2
- Indexing 101 by Richard Vannoy ............................... 5
- Hashing-It isn't all Corned Beef by Dave Cleary and Mike Avery 10
- Create dBASE III Data Files from QuickBASIC by Dennis Gellert 11
- Adding LANtastic Support to your Programs by Chip Morrow ..... 13
- A powerful line editor for QB by Larry Stone ................. 15
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The QBNews Page ii
- Volume 3, Number 2 June 29, 1992
-
-
-
- ----------------------------------------------------------------------
- F r o m t h e E d i t o r ' s D e s k
- ----------------------------------------------------------------------
-
- Is this Goodbye?
-
- As you may have noticed, this edition of The QBNews is not up to the
- usual high standards set by previous issues. The problem is that I am
- running out of people who I can hit up for free articles. Most of the
- articles that have appeared in The QBNews were because of direct
- solicitations from me. This issue relied on on contributions sent in
- to me without my asking for them.
-
- For some reason, at least from the mail I have (or have not is more
- like it) received, interest seems to be wanning in The QBNews. Because
- of this, I have no choice but to suspend offering disk subscriptions
- and as of right now, Volume 3 will be the end of The QBNews. The
- months that passed since the 301 issue have really been disappointing
- as far as response goes. I don't expect this issue to generate much
- either because of how poor it is. However, I am committed to
- continuing on until 304, and alot can happen in those six months. If
- possible, I would like to continue producing The QBNews. However, that
- means the term "user supported" will have to take on much more meaning
- in the coming months
-
- Dave Cleary - Publisher of The QBNews
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The QBNews Page 1
- Volume 3, Number 2 June 29, 1992
-
-
-
- ----------------------------------------------------------------------
- D a t a B A S I C s a n d F i l e I / O
- ----------------------------------------------------------------------
-
- File Types 100 by Richard Vannoy
-
- This article will familiarize beginners to computer programming and
- the QuickBASIC programming language with the basics of file creation
- and a brief on the types of files generally used in computer programs.
- First, we need a few definitions that describe how data is stored.
-
- Definitions:
- Field: A particular type of information in a file.
- Common field names would be phone number, name,
- address, or date.
- Record: The sum of the fields for one person, place or
- thing.
-
- Field 1: Name: Richard <----- Together, these three
- Field 2: Phone: 777-1212 <----- fields make one
- Field 3: Birthday: 04\26\60 <----- record.
-
- There are generally three types of files most commonly used today.
- They are sequential, random access and binary.
-
- Sequential, as the name implies, means that data is written to the
- file in sequence, or one after the other, so if I write the name and
- phone numbers of a few friends in a sequential file, it might look
- like the line below. (The commas are called delimiters. They are put
- in by you or the program to separate each piece of data)
-
- Sam,777-5155,George,123-4567,Bill,323-1212
-
- Notice that all of the information (fields and records) are slammed
- together and that there is no way to tell where the name Bill starts
- without reading the file from the beginning. To retrieve, or read the
- items, we read them from the beginning, sequentially, until we get to
- the information desired. If Richard is the 100th name in the list, we
- have to READ the first 99 names/phone numbers to get to it.
-
- In a random access file, the fields are defined to a specific length
- and any spaces not used are filled with blanks. This allows each
- record to be the exact same size. Like..
-
- Name: 10 bytes |Richard |
- Phone: 8 bytes |777-1212|
-
- Now we have a record length of 18 bytes, no matter how long the data
- is, so lets write the same info as above to a file..
-
- Sam 777-5155George 123-4567Bill 323-1212
- | | |
- Note how a new record starts every 18 bytes, and that "unused" bytes
- in the records are filled with spaces, so we can predict where every
-
- The QBNews Page 2
- Volume 3, Number 2 June 29, 1992
-
- record is going to start. And we don't need separaters since we know
- exactly where each record and each field starts. Not only that, if we
- know that Richard's info is in the 100th record, we can go directly to
- it since the record length is constant. Because of this
- predictability, which transforms to SPEED when it is time to find
- information, random access records are well suited to storing and
- retrieving large quantities of data.
-
- These are the two most common storage techniques, but there are many
- more! One, called Indexed Sequential Access Method (ISAM) is stored
- somewhat like a sequential file, but is accessed through an indexing
- system, which gives it one of the main advantage of sequential files
- (packing info tightly) and also one of the main advantage of random
- access files (FAST recovery).
-
- Binary files... Well, ALL files are binary files to the extent that
- any DOS file can be opened in the binary mode. By binary, we
- generally mean we want the ability to see, get or write to any byte in
- the file. In the examples above, if we wanted to know the three digit
- prefix of Bill's phone number, with both sequential and random access,
- we would have to read in the whole number, and pull out the first
- three digits, but with binary, we could go right to the applicable
- bytes and grab just the 323 prefix.
-
- Another common use of binary files is when we want to a machine
- language (EXE, COM) file and perhaps correct or change just a few
- bytes.
-
- Also, if you have no idea what is in a file, opening it in binary lets
- you look around easier and snoop the file to determine the contents of
- field/record layout. Opening any of these types of files is handled
- with the OPEN command. Check your QuickBASIC reference which will
- expand on the use and syntax of the following examples.
-
- OPEN "DATA.FIL" FOR INPUT AS #1
- This opens a file for INPUT only. You can't write to or change the
- file contents. You can then read the information one variable at a
- time or one line at a time.
-
- OPEN "DATA.FIL" FOR OUTPUT AS #1
- This opens a file for output. It creates a new file and allows you to
- write information into it.
-
- OPEN "DATA.FIL" FOR APPEND AS #1
- The APPEND mode does not create a new file. It allows you to add
- information on to the end of an existing file.
-
- OPEN "DATA.DBF" FOR RANDOM AS #3
- This allows to to define (with the TYPE statement) the type and length
- of fields you want in your data file, such as:
-
- TYPE Information
- firstName AS STRING * 15
- lastName AS STRING * 20
-
- The QBNews Page 3
- Volume 3, Number 2 June 29, 1992
-
- age AS INTEGER
- salary AS SINGLE
- END TYPE
-
- The TYPE defines the fields and sets the proper size so you don't have
- to keep track of the byte counts.
-
- OPEN "FIND.EXE" FOR BINARY AS #4
- Now you are telling the system to open the file and allow you to
- retrieve, see or write any information from one to many bytes.
-
- Each file has its preferred uses. Data bases, where there are many
- entries such as customers, employees, or items, typically use RANDOM
- files. Applications where you just need to store and retrieve a small
- number of items generally use SEQUENTIAL files in the INPUT or OUTPUT
- mode. BINARY files have many special uses such as overlays, graphic
- image files and other specialized applications where binary (as
- opposed to text or ASCII) is stored.
-
- I hope the basic introduction will give you some insight into the
- available file types and their uses. Have fun programming!
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The QBNews Page 4
- Volume 3, Number 2 June 29, 1992
-
- Indexing 101 by Richard Vannoy
-
- So here's the basics of file indexing. I'll use the file extensions
- .DBF to indicate a normal RANDOM data file and .NDX to show an index
- file. We'll start with a data file:
-
- TYPE EmployeeData
- lastname AS STRING * 15
- firstname AS STRING * 10
- employeeNumber AS INTEGER
- SSN AS STRING * 11
- salary AS SINGLE
- hireDate AS STRING * 8
- 'Many more fields could (and usually do) go here for a
- 'typical company data base. Imafine that there are
- 'perhaps 60 to 80 fields using maybe 400 to 600 bytes
- 'each. It's important to remember, as we go along, that
- 'ALL of this data for all the employees is much too
- 'massive to fit in the memory of most machines.
- END TYPE
- DIM EMPL AS EmployeeData
-
- Now let's suppose the personnel department wants us to design the data
- base so they can quickly retrieve an employee's information, and they
- want to be able to enter EITHER the first and last name OR the
- employee number. As you could guess, if you were sitting at a
- terminal all day, you would quickly find out that if you can enter
- just the employee number instead of the full name, that data entry
- will be much faster and more efficient. So if we are dealing with
- documents that have the employee number (as most work type documents
- do), then that would be quicker. But we also have to allow for the
- case where the employee number is not known. So, we must also allow
- the employee's name to be entered also.
-
- So we decide to index the data base in two ways; first by employee
- number:
-
- We need a small data structure to contain just two things: the
- employee number (what we're indexing on), and the record number where
- that employee's information can be found. So..
-
- TYPE EmpNumberIndex
- EmpNumber AS SINGLE
- RecordNumber AS SINGLE
- END TYPE
- DIM NUMB AS EmpNumberIndex
-
- Then we need a small data structure for the first name/Last name
- information:
-
- TYPE EmpNameIndex
- BothNames AS STRING * 26
- RecordNumber AS SINGLE
- END TYPE
-
- The QBNews Page 5
- Volume 3, Number 2 June 29, 1992
-
- DIM ENAM AS EmpNameIndex
-
- Note that the BothNames field is big enough to hold the first name, a
- space, and then the last name. Also note that both EmpNumberIndex and
- EmpNameIndex have the RecordNumber for where that employee is stored,
- since we don't need ALL the employee info, just a pointer to where we
- can find it.
-
- We're going to open three files...
-
- OPEN "EMPLOYEE.DBF" FOR RANDOM AS #1 LEN = LEN(EMPL)
- OPEN "EMPNUMBR.NDX" FOR RANDOM AS #2 LEN = LEN(NUMB)
- OPEN "EMPLNAME.NDX" FOR RANDOM AS #3 LEN = LEN(ENAM)
-
- Let's start with three employees.
- EMPLOYEE.DBF will have:
- RECLast Name First Name Employee Numb. AND all the------>
- -- --------- ---------- -------------- rest of the------>
- 1 Vannoy Richard 46 fields for------->
- 2 Que Suzie 32 for several------>
- 3 McGee Bobbie 23 hundred bytes---->
-
- EMPNUMBR.NDX will have:
- Employee Numb. REC
- -------------- ---
- 46 1
- 32 2
- 23 3
-
- EMPLNAME.NDX will have:
- BothNames REC
- --------- ---
- Vannoy Richard 1
- Que Suzie 2
- McGee Bobbie 3
-
- The last thing we have to do before using this data base is to sort
- each .NDX file so we can use a binary search to quickly find what we
- want.
-
- EMPLNUMBR.NDX will now look like:
- Employee Numb. REC
- -------------- ---
- 23 3 (Sorted by Employee number)
- 32 2
- 46 1
-
- EMPLNAME.NDX will now look like:
- BothNames REC
- --------- ---
- McGee Bobbie 3 (Sorted by name)
- Que Suzie 2
- Vannoy Richard 1
-
-
- The QBNews Page 6
- Volume 3, Number 2 June 29, 1992
-
- So far it seems like a lot of work to do all this for just three
- records, but remember that we probably have hundreds, maybe even
- thousands of records, so be aware that the problem of NOT having to
- search thousands of records for a name OR an employee number (and BOTH
- can never be in the same order in the original .DBF file) is what got
- us here in the first place.
-
- In order to understand the speed of an indexing system, it is
- necessary to know how a binary search works, so we'll digress a moment
- to cover it. The first requirement of a binary search is that the
- records we are searching MUST BE IN ORDER, either numerically or
- alphabetically, for the search to work. That's why we sorted the .NDX
- files above.
-
- Let's say we are searching the EMPLNAME.NDX file for me (Vannoy
- Richard), all the records are in alphabetical order by name, there are
- 1000 records and my name happens to be at record 687.
-
- First set LOW to 1 and HIGH to the number of records (1000). the
- formula for our first LOOK is going to be (HIGH + LOW)\2 or 500. LOOK
- at record #500. Is the name there (alphabetically) greater than or
- less than MY name? Well, since I'm at 687, the name at 500 has to be
- LESS. We now readjust and recompute LOOK as folows:
-
- IF NameAt LOOK < MyName THEN
- LOW = 500
- ELSE
- HIGH = 500
- END IF
- NewLOOK = (HIGH + LOW)/2
-
- Notice, we have cut the search area IN HALF (thus the name BINARY) by
- looking at the file JUST ONCE. And by refining our LOOK record to the
- middle of the new search area which has just been halved, it won't
- take long to find the right record. The code looks like:
-
- found = 0
- low = 1
- high = numberOfRecords
- DO
- look = (high + low) \ 2 'Integer division
- GET #3, look, ENAM
- IF ENAM.BothNames < SearchingForName$ THEN
- low = look
- ELSEIF ENAM.BothNames > SearchingForName$ THEN
- high = look
- ELSE
- found = 1
- EXIT DO
- END IF
- LOOP UNTIL low = high
- IF found THEN
- 'Process the record
- ELSE
-
- The QBNews Page 7
- Volume 3, Number 2 June 29, 1992
-
- PRINT "Record not found."
- END IF
-
- So eventually, one of two things has to happen, either the record is
- found (ENAM.BothNames = SearchName$) or, if the record is NOT in the
- data base, the HIGH and LOW numbers will run together (Thus the LOOP
- UNTIL low = high).
-
- Again, this may SEEM like a lot of trouble, because, say with 100
- records, the best case is that the record you want is at record #50 (1
- look!) but the WORST case is that it will take 7 looks, for an average
- of about four looks at 100 records to find someone. (Remember that in
- a sequential file, the worst case could be 100 looks for an average of
- about 50 looks!)
-
- And the beauty of binary search is that YOU CAN DOUBLE THE NUMBER OF
- RECORDS AND ONLY INCREASE THE AVERAGE NUMBER OF LOOKS BY ONE!
-
- So, to sum up the binary search routine, lets look for an employee by
- number and name.
-
- IF input was a number THEN
- Binary search the EMPLNUMB.NDX for the number.
- If found, go to the indicated record in EMPLOYEE.DBF and
- display or process the data.
- If not found, print an error message.
- IF input was a string
- Binary search the EMPLNAME.NDX for the name.
- If found, got to the indicated record in EMPLOYEE.DBF and
- display or process the data.
- If not found, print an error message.
-
- Note that the logic for a number or a string is identical, so you
- write the code for a number looked up in EMPLNUMB.NDX, then make a
- copy of the same code and make the minor modifications of looking for
- a string in EMPLNAME.NDX.
-
- That's how it works! Indexing may seem bulky or unnecessary at first,
- but I can never emphasize enough the increase in speed you get. You
- will just have to try it or see it for yourself.
-
- The part of an indexing system that takes the most caution and care is
- the maintenance of the .NDX files. Remember that whenever you add a
- record, delete a record, or change the data (field) that is in an
- index file, then THAT index file must be IMMEDIATELY updated with the
- correct information for the system to work. It can be easy if you
- take it a step at a time.
-
- In our example, let's say you add an employee. The new employee's
- data goes in the next available record of EMPLOYEE.DBF, say number
- 1234. His name is Jones Casey, and his employee number is 2345. Now
- create a new record for EMPNUMBR.NDX
-
- EmpNumb. Record Number
-
- The QBNews Page 8
- Volume 3, Number 2 June 29, 1992
-
- 2345 1234
-
- Put this info at the end of the EMPNUMBR.NDX file and reverse bubble
- sort it up to where it belongs. Do the same with
-
- EmpName RecordNumber
- Jones Casey 1234
-
- in the EMPLNAME.NDX file.
-
- All maintenance must be done on the fly (right NOW!), because the very
- next operation may be to find the employee you just added, or
- otherwise process the record that was just manipulated, so do it now.
-
- That should acquaint you with the basic theory of index file creating
- and use. The best way to fully understand the concepts is to set up
- an indexed file and try things out. I suggest you set up a data base
- with no index, then add one index, and later one other to get you
- started.
-
- **********************************************************************
- Richard Vannoy started programming as a hobby back in 1975. In 1980,
- he began his career as a computer programmer and teacher upon his
- retirement as a naval submarine officer. His projects have included
-
- . Writing a BASIC navigation program to assist in locating objects
- of value lost on the bottom of the ocean.
- . Maintaining an extensive technical manual data base on an Imsai
- 8080 in North Star BASIC.
- . Maintaining a large government contractor accounting program on
- a PDP-11 with Fortran.
- . Various contracting/consulting jobs programming with dBASE III+.
-
- Richard presently resides in Portland, Oregon where he writes software
- for local businesses in QuickBASIC.
- **********************************************************************
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The QBNews Page 9
- Volume 3, Number 2 June 29, 1992
-
- Hashing - It isn't all Corned Beef by Dave Cleary and Mike Avery
-
- A few months ago, Mike Avery posted some code on the QUIK_BAS echo
- concerning Hashing. I thought this was pretty interesting, so I'm
- including his code in The QBNews and decided to write a little
- introductory to it.
-
- Hashing is an algorithm where you take a record key, and compute a
- file address or record number from it. This approach alows you to keep
- file accesses down to a minimum since there is no index file to worry
- about. You take your key, perform some mathamatical functions on it,
- and bingo, you have your record number of your data.
-
- The first step in hashing is to compute a hash function. An ideal hash
- function would compute a different number for an infinite amount of
- different keys. However, if you were to come up with a perfect hash
- function, you would probably need to use a supercomputer to get decent
- performance. So after coming up with a hash function, you need to come
- up with some sort of collision resolution for the times when two
- different keys hash out to the same record number.
-
- The collision resolution Mike chose to implement was adding a power of
- two to the result of the hash function. Another method would be to use
- linked lists, or store multiple records per computed hash number. An
- example of having multiple records would be this. Say you have 128
- byte records. A disk access of 4096 bytes is an efficient number to
- use. Therefore, you could have up to 32 (4096 \ 128) records per hash
- number.
-
- The code Mike presents is well commented and works. I encourage the
- reader to take some time and play with it. For more information on
- hashing, I suggest you look at some books of basic algorithms. They
- all should contain a section on hashing.
-
- Code for this article appears in HASH.ZIP
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The QBNews Page 10
- Volume 3, Number 2 June 29, 1992
-
- Create dBASE III Data Files from QuickBASIC by Dennis Gellert
-
- With the need for a QuickBASIC routine which was able to create a
- dBASE III data file, and encouraged by David Perrys article in
- Volume 1, no 5, I set to work.
-
- This routine is quite sufficient if there is a need to export data
- from your program in dBASE III format. However, a full database
- application would almost certainly require, in addition,
- Index file management routines.
-
- Armed with the information from the above article, the dBASE III
- manual, and PC Tools, I set to work. The dBASE manual actually
- specifies the header and data structure fairly well, so you're not
- left in the dark when working with the dBASE III file structure.
-
- dBASE refuses to open a data file if it detects there is anything
- amiss with the file structure, so you have to be careful to get
- everything right. I used two checks along the development path:
- firstly, that dBASE would actually open the file, and secondly,
- to compare contents of this file, byte-by-byte, with the contents
- of an identically structured file created with dBASE III itself.
-
- As it stands, the program is an example which creates a dBASE data
- file, and writes one record. As the file structure is embedded in
- the program, it will be necessary to modify the source code to suit
- your needs. The dBASE file structure specification is contained in
- data statements, so this is quite easy to change. The structure of
- the data written to the file will also need to be looked at.
- (Commented in the source code).
-
- Notes on Specifying a dBASE III Structure
- -----------------------------------------
- When creating a new dBASE data file, you must specify its data
- structure. This consists of supplying the Name, Data type,
- Total length (including decimal point, if used), and Decimal
- places for each field.
-
- Field Names:
- - Field names must be in upper-case, or dBASE will not be able to
- access this field. This program uses UCASE$ to ensure this.
- - Field names must not be repeated. This program does not check
- this. If there is a repeated field name, dBASE will not be able
- to access the repeated field.
- - Field names begin with a Letter, and may contain letters, digits,
- or underscores.
- - Field name length, by convention, may be from 1 to 10 characters.
- (but 11 bytes are reserved for this ?).
-
- Field Types and lengths:
- The field type is specified by an upper-case character. The
- maximum lengths for each of the types is shown:
-
- C - Character 254
-
- The QBNews Page 11
- Volume 3, Number 2 June 29, 1992
-
- N - Numeric 19
- L - Logical 1
- D - Date 8 (set length)
- M - Memo 10 (set length of pointer)
-
- Code for this article appears in QB-DB3.ZIP
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The QBNews Page 12
- Volume 3, Number 2 June 29, 1992
-
- Adding LANtastic Support to your Programs by Chip Morrow
-
- Ever thought it would be nice to throw some rudimentary LANtastic function
- calls into your QB programs? This set of 8 routines makes it possible to:
-
- - Determine if LANtastic netbios is present
- - Cancel redirection of a device
- - Determine LANtastic machine name currently in use
- - Get a list of redirected device entries
- - Get a list of servers that you're not currently logged into
- - Get a list of servers that you ARE currently logged into
- - Determine LANtastic version currently in use
- - Redirect a device
-
- The DECLARE block used in the sample program LANSTAT:
-
- DECLARE FUNCTION NetBios% () 'Is netbios present?
- DECLARE FUNCTION NetCancel% (DevName$) 'Cancel redirection
- DECLARE FUNCTION NetName% (Machine$) 'Get machine name
- DECLARE SUB GetDevice (DeviceNum%, DevName$, NetPath$) 'Get device entry(s)
- DECLARE SUB Inactive (EntryNum%, Returned$) 'List available servers
- DECLARE SUB LoggedIn (EntryNum%, LogName$) 'List active servers
- DECLARE SUB NetVersion (Major%, Minor%) 'Get LANtastic version
- DECLARE SUB Redirect (DevType%, DevName$, NetPath$) 'Redirect a device
- DECLARE SUB Strip (A$, B$) 'Used by these routines
-
- NetBios - Returns 0 if netbios not installed, or -1 if installed.
-
- NetCancel - Cancel redirection of an already-active device. Pass the
- device name to this routine in the form "c:", "d:", "prn",
- "lpt1:", etc. NetCancel% will return zero if successful,
- or an error code otherwise.
-
- NetName - Determine machine name currently in use.
-
- GetDevice - Get a redirected device entry. Pass a value (EntryNum%) as the
- index number to check, beginning at zero. DevName$ and NetPath$
- are returned with this entry's information. If nothing found
- for EntryNum%, DevName$ returns "".
-
- Inactive - Get the name of a server that you're not currently logged into.
- Pass EntryNum% as the index number to check, beginning at zero.
- Returned$ will be the name of the inactive server, or "" if
- nothing found.
-
- LoggedIn - The reverse of Inactive. Pass EntryNum% in the same manner,
- and the returned string will be the active server name, or
- "" if nothing found.
-
- NetVersion - Determine LANTastic version currently in use. Major% and
- Minor% will be returned values. Version 2.57 of the NOS
- would be Major = 2, Minor = 57.
-
- Redirect - Redirect a device to an active server's path. Works similar
-
- The QBNews Page 13
- Volume 3, Number 2 June 29, 1992
-
- to LANtastic's NET USE command. Passed values (from the
- DECLARE statement above:
-
- DevType% = 3 if a printer device, 4 for disk. No other
- values accepted.
- DevName$ = Your local device name. "C:", "D:", "LPT1:", etc.
- NetPath$ = Server's network path to use, in the format
- \\server_name\pathname
-
- DevType% returns zero if successful, or an error code otherwise.
-
- Strip - Rudimentary method of converting fixed-length strings to
- variable length (there's probably a better way). Used by
- most of the above routines in order to pass QB-standard
- variable-length strings back to you.
-
- Last thing to note here is that I've used these routines only with
- version 2.57 of the NOS. I don't see why they wouldn't work with
- other versions of LANTastic, but wanted to make you aware.
-
- Happy INTERRUPT'ing!
-
- Code for this article appears in LATASTIC.ZIP.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The QBNews Page 14
- Volume 3, Number 2 June 29, 1992
-
- A powerful line editor for QB by Larry Stone
-
- I use QB's INPUT statement to quickly test code. However, I find that
- its limitation of 255 characters, the fact that it will automatically
- wrap at the eightieth column, its inability to pre-size a window or
- work within a virtual window, it's complete lack of character masking,
- and the fact that the floating point library is loaded with it, when-
- ever it is used, whether needed or not, leaves the QB INPUT statement
- well short of a desirable routine to use with a "finished" program.
-
- Although I have, and use, an effective substitute routine written in
- ASM, the idea of a pure QB routine remained a fancy for quite a while.
- The opportunity to do a pure QB routine came as I was trying to come
- up with a project for the class I taught at the local community col-
- lege. I teach (part-time) "Introduction to Modular Programming" and
- the compiler we use to teach modular programming is, you guessed it,
- QB. The project began in the Fall term - a simple line editor to use
- in lieu of QB's INPUT statement. My Winter term students were required
- to expand its capabilities to include virtual windowing and automatic
- exiting when the end of the input line is reached (an optional feature
- used with field entries such as, zip codes and telephone numbers).
-
- The result of our effort (well - mostly my effort) is LINEEDIT.BAS, an
- extremely effective line editor ready to include with your code. With
- LINEEDIT.BAS are two other highly useful modules, KEYBOARD.BAS and
- VIDTOOLS.BAS (These two routines have been abbreviated for brevity).
-
- The KEYBOARD module must be loaded with LINEEDIT. The VIDTOOLS module
- is not necessary but is included because the test program, EDITDEMO,
- makes calls to two of its routines. The main module, EDITDEMO.BAS is
- a test vehicle for the editor and illustrates how to setup parameters
- needed to call the editor.
-
- LineEdit has twelve parameters in its parameter list. Row%, Col%, A$,
- and DisplayLen% are required. You must tell LineEdit what row to work
- on and what column to display the string from. You must also supply a
- string to edit (A$), and define the length of the display (better than
- QB's automatic, 255 character length that is guaranteed to wreck havoc
- on your nicely designed screen form).
-
- Let's review some of LineEdit's other parameters - the ones that turn
- a simple line editor into a power-packed routine.
-
- VwindowSize%, if defined as less than the string's DisplayLen, has no
- effect on LineEdit. However, if it is a larger number than DisplayLen
- then it defines a virtual window. Let's say that DisplayLen is defined
- for 60 characters. If VwindowSize% is smaller then the maximum string
- size allowed is 60 characters. But, if we define VwindowSize% as 300
- characters then we can now edit a string up to 300 characters within a
- 60 character window. The displayed string will simply slide left or
- right 10 characters at a time, when we reach the end of the display.
-
- Separaters$, when non-null, tells LineEdit what characters are word
- separaters for jumping the cursor between words (use Ctrl plus arrow).
-
- The QBNews Page 15
- Volume 3, Number 2 June 29, 1992
-
- An effective Separaters$ string might be, " .:-()\/".
-
- Terminators%() MUST BE DIMmed by your controlling program. It is an
- array defining what key presses to exit the editor. Escape, up & down
- arrows, PgUp and PgDn, are examples of terminator keys. The zeroeth
- element of the array informs LineEdit what the last terminator is.This
- allows extreme flexibility. Let's say you have defined 7 terminators,
- Escape, Up, Down, PgUp, PgDn, Ctrl + PgUp, and Ctrl + PgDn. Now let's
- say that your first screen contains a single edit item - all you need
- is the escape key. You LET Terminators%(0) = 1. Your first terminator
- is escape and that is now the only terminator that LineEdit will use.
-
- Your next screen has five edit items. You now need to use up, down,
- PgUp and, PgDn so that your user can navigate between the strings. You
- LET Terminators%(0) = 5. If you have multiple screens of edit strings
- you would LET Terminators%(0) = 7 so that Ctrl + PgUp sends the cursor
- to the first string of the first screen and Ctrl + PgDn goes to the
- end string on the last screen.
-
- EditMask$ when null has no effect. However when filled with character
- A's, tells LineEdit to force every key stroke to upper case. If the
- EditMask$ looked like, "Aaaaa" then LineEdit would force the 1st char
- to upper case and the next four characters to lower case.
-
- CurPos% and CurOffset% are input/output parameters. They can be used
- to send the cursor to the same position it was in or, set them to zero
- for fresh starts at the beginning of the edit string.
-
- Kee% is a value that defines what keystroke terminated LineEdit. You
- would treat Kee = 13 (enter key) differently than Kee = 27 (escape).
-
- While we are on the subject of Kee%, LineEdit uses a routine from KEY-
- BOARD.BAS to handle all keyboard activity. The routine, KeyPressed%,
- returns extended keystrokes as negative numbers. In other words, down
- is returned as the value -80 (not CHR$(0) + CHR$(80) as QB does). This
- means that you must define them this way for you Terminators%() array.
-
- Below is a listing of LineEdit's built-in capabilities:
-
- Backspace Deletes character to left of cursor
- Delete Deletes character under cursor
- Ctrl + Home Deletes from cursor to beginning of line
- Ctrl + End Deletes from cursor to end of line
- Ctrl + Right Move to word on right (skips separaters)
- Ctrl + Left Move to word on left (skips separaters)
- Home Move to beginning of string
- End Move to space after last char of string
- Right Move cursor one character to right
-
- The LineEdit code is self-explanatory. However, one section of code
- deals with word seperaters and is constructed a little different.
-
- StepValue is set to -1 when the user presses Ctrl + Left and StepValue
- is set to 1 when the user presses Ctrl + Right. The code reads:
-
- The QBNews Page 16
- Volume 3, Number 2 June 29, 1992
-
-
- IF StepValue < False THEN X = 1 ELSE X = LEN(A$)
- FOR N = StrPos TO X STEP StepValue
-
- '---- Look into A$, one character at a time - is it a seperater?
- J = INSTR(Separaters$, MID$(A$, N, 1))
-
- IF J THEN 'Found a separater character
- FoundSeparater = J 'Save J's value
-
- '---- Move our cursor to this separater position
- FOR i = StrPos TO N STEP StepValue
- IF StepValue < False THEN GOSUB CursorLeft ELSE _
- GOSUB CursorRight
- NEXT
-
- EXIT FOR 'Cursor is on a separater so exit the loop
- END IF
- NEXT
-
- This loop simply steps through the string, one char at a time, then
- looks into Separaters$ to see if this one character has been defined
- as a word separater. If it is a separater, its location in the sepa-
- rater string is saved and the cursor is moved to that character in the
- string being edited.
-
- '---- If a separater was found, skip any repeating sequences of it.
- DO WHILE J 'Loop while Separater has been found
- N = N + StepValue 'Increment or Decrement N
- IF N = False THEN EXIT DO 'Prevent error with MID$() function
-
- '---- Only looking for repeating sequences of FoundSeparater
- J = INSTR(MID$(Separaters$, FoundSeparater, 1), MID$(A$, N, 1))
-
- IF J THEN 'If we found another seperater
- IF StepValue < False THEN GOSUB CursorLeft ELSE _
- GOSUB CursorRight
- END IF
-
- IF N >= LEN(A$) THEN EXIT DO
- LOOP
-
- This next loop simply looks to see if the found separater character is
- repeated. While it is repeated, the cursor is moved left or right.
- Once past the found separater, the loop is exited. In other words, if
- you have defined the space character (ASCII 32) as a separater, and
- the string has a word followed by ten spaces followed by another word,
- LineEdit will jump across all ten spaces with a Ctrl + left or right
- arrow keys (a slick little trick).
-
- To see how to use LineEdit, load and run its test program, EDITDEMO.
-
- Final note. LineEdit has no code for the Tab key. I leave that to you
- to encode into the routine.
-
- The QBNews Page 17
- Volume 3, Number 2 June 29, 1992
-
-
- Code for this article appears in LINEDIT.ZIP.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The QBNews Page 18
-
-