PCjs Machines

Home of the original IBM PC emulator for browsers.


PC-SIG Diskette Library (Disk #245)

[PCjs Machine "ibm5160"]

Waiting for machine "ibm5160" to load....


The Ultra-Utilities are a powerful collection of tools for the PC owner
interested in getting more from his system.  U-MIND is an "intelligent"
database generator which allows you to produce clean, sophisticated
programs very quickly.  U-OPT will help clean-up BASIC code so that it
will compile tighter and faster.  More of these utilities are
available, in squeezed format, on Disk 133.

How to Start:  For instructions on running BASIC programs, please refer
to the GETTING STARTED section in this catalog.  To run an EXE program
simply type its name and press <ENTER>. To read DOC or TXT files simply
enter TYPE filename.ext and press <ENTER>.

Suggested Registration:  Ultra-Utilities $30.00

File Descriptions:

U-MIND   DOC  Documentation for U-MIND  (51K)
U-MIND   BAS  Ultra-Mind program  (Intelligent database)
SKELETON BAS  Used with Ultra-Mind
U-OPT    EXE  Ultra-Optimize program
DOC42    TXT  Ultra-Utility documentation - Part 2  (23K)
DOC41    TXT  Ultra-Utility documentation - Part 1  (52K)
U-OPT    DOC  Documentation for O-OPT  (2K)


PC-SIG Disk No. #245, version V1 
The following is a list of the file checksums which should be produced by
the CRCK4 program on this disk.  If the CRC numbers do not match the following
list you may have a bad file.  To use type:  CRCK4 <filespec>
CRCK4 output for this disk:

CTL-S pauses, CTL-C aborts

--> FILE:  U-MIND  .DOC         CRC = DB 50

--> FILE:  U-OPT   .DOC         CRC = 35 DF

--> FILE:  DOC41   .TXT         CRC = 2C 95

--> FILE:  DOC42   .TXT         CRC = D1 68

--> FILE:  U-OPT   .EXE         CRC = CB F4

--> FILE:  SKELETON.BAS         CRC = F5 E0

--> FILE:  U-MIND  .BAS         CRC = 15 9A

 ---------------------> SUM OF CRCS = E6 9A

These and other Public Domain and user-supported programs from:
PC Software Interest Group (PC-SIG)
1125 Stewart Ct  Suite G
Sunnyvale, CA 94086
(408) 730-9291


                         :::::: NEW RELEASE! VERSION 4.00 ::::::
                    I                                                I
                    I                                                I
                    I         The FreeSoft Company Presents:         I
                    I                                                I
                    I         ---> The Ultra Utilities <---          I
                    I           "The Wizard's Apprentice"            I
                    I                                                I
                    I      User's Manual And Guide To Operation      I
                    I                                                I
            Copyright (C), 1983 by The FreeSoft Company.  All rights reserved
                        Version 4.00, First Release: January, 1984
          This manual and the accompanying programs U-ZAP.EXE, U-FORMAT.EXE and 
          U-FILE.EXE may be copied and shared freely as long as certain 
          duplication rules are adhered to.  Please see Appendix A of this 
          manual for the FreeSoft duplication policy.  Anyone found duplicating 
          any part of this manual or the programs mentioned above not according 
          to the policies in Appendix A of this manual will suffer from guilt 
          for eternity.  Think about it...
                                 Ultra-Ultility Warranty
          The programs U-ZAP.EXE, U-FORMAT.EXE and U-FILE.EXE and this manual 
          are provided on an "AS IS" basis without warranty of any kind, 
          expressed or implied, including but not limited to the implied 
          warranties of merchantability and fitness for a particular purpose.  
          The entire risk as to quality and performance of these programs and 
          this manual rests solely with the user.  Should any part of these 
          programs or this manual prove defective, the user will assume the 
          entire cost of all necessary repair, servicing, and correction.  In 
          no event will The FreeSoft Company be liable to you for any damages, 
          including any lost profits, lost savings, or other incidental or 
          consequential damages arising out of the use or inability to use 
          these programs or this manual, even if The FreeSoft Company has been 
          advised of the possibility of such damages.  This warranty gives you 
          specific legal rights, and you may have other rights which may vary 
          from state to state.  Some states do not allow the exclusion of 
          implied or consequential damages so parts of the above may not apply 
          to you.  By operating any of the above programs or using any part of 
          this manual, you acknowledge that you have read this agreement, 
          understand it, and agree to be bound by its terms and conditions.  
          You further agree that it is the complete and exclusive statement of 
          the agreement between us, which supercedes any proposal or prior 
          agreement, oral or written, and any other communications between us.
          If you have registered, feel free to write us with any questions you 
          might have concerning our products.  If there seems to be a need for 
          it, we may open up a telephone hotline or bulletin board for fast 
                                    Table Of Contents
          Introduction.................................................. 1

                                   Section I: Ultra-Zap
          Display/Modify Disk Sectors................................... 2
          Display/Modify File Sectors................................... 4
          Copy Disk Sectors............................................. 5
          Fill Disk Sectors............................................. 5
          Search For Bytes In Disk Sectors.............................. 5
          Search For Bytes In File Sectors.............................. 6
          Modify Sector Fill Byte....................................... 6
          Modify Display Radix.......................................... 6
          Interrogate Disk Sectors...................................... 7
          Toggle Menu Alert Tone........................................ 8
          Display/Modify Disk Parameters................................ 8     
          How To Display/Modify Non-Standard Sectors.................... 9

                                 Section II: Ultra-Format
          Format A Standard Track.......................................10
          Re-format A Standard Track Without Erasing Old Data...........10
          Format A Non-standard (Copy-Protected) Track..................10
          Display/Modify Disk Parameter Table...........................11
          Modify Display Radix..........................................11
                                 Section III: Ultra-File                      
          Display File's Directory Information..........................12
          Assign Or Remove System Status................................12
          Assign Or Remove Hidden Status................................12
          Display List Of Sectors Allocated To File.....................12
          Build A File From Scratch.....................................13
          Attempt To Restore An Erased File.............................13
          Produce A Map Of Diskette.....................................13
          Selectively Purge Files.......................................14
                                  Section IV: Appendices                      
          Appendix A: The FreeSoft Duplication Policy...................15
          Registration Form.............................................18
          Appendix B: A Brief Discussion Of Diskette Formats............20
          Appendix C: Version changes and additions.....................21
          (1)                          Introduction
          The Ultra-Utilities are a powerful collection of programs that will 
          allow you complete access to the power of your IBM-PC's disk drive 
          controller circuitry and PC-DOS disk operating system.  With this 
          power also comes the abilty to do terrible damage to your diskettes 
          if you make a mistake at the wrong time.  To avoid this:
             A) Make a copy of the Ultra-Utilities and keep the originals in a  
                safe place.  When using the copies, remove the diskette 
                containing the Ultra-Utilities after the desired program has    
                loaded.  It is not necessary for this diskette to remain in the 
                disk drive after the program has begun execution.
             B) When working on other diskettes, ALWAYS WORK ON A COPY!  The 
                time it takes to backup a diskette is well worth it effort. If  
                you are working on a diskette that you are unable to yet make a 
                copy of, at least place a write-protect tab on it and work 
                slowly and cautiously.
          To use these programs properly you will need:
             1) IBM-PC with at least 64K RAM, one single or double-sided disk   
                drive, and an 80-column display.  Because of the wide variety   
                of IBM-PC configurations and the varying levels of 
                "compatibility" with PC clones, we cannot and do not support
                questions concerning support of other equipment configurations.
                Additional memory may be needed if you boot under DOS 2.00.

             2) DOS 1.10 or 2.00: Again, if you try to use other versions of 
                PC-DOS, you are on your own.  These programs have been tested   
                only on PC-DOS versions 1.10 and 2.00.
          You do not have to be a "hacker" or be able to multiply four digit 
          hexadecimal numbers in your head to be able to use the 
          Ultra-Utilities.  If you are more technically inclined, you'll no 
          doubt find many uses for the powerful features of these programs.  If 
          you're not so technically inclined, you'll probably use these 
          programs for "snooping" and educational purposes, and will first want 
          to read the chapter on Modifying The Display Radix.  When first 
          executed, the Ultra-Zap and Ultra-Format programs display all numbers 
          in hexadecimal format (base 16).  If you are not comfortable using 
          hex values, use that function to change all printed values to decimal 
          (base 10).
          Features of the Ultra-Utilities
          1) The Ultra-Utilties use a special input procedure that allows you 
             to only enter in characters appropriate to the question being 
             asked.  In most cases, a number of small boxes will appear next to 
             a question.  These boxes tell you that the program is waiting for  
             your response, as well as the maximum number of characters you may 
             type to answer the question.  If no boxes are displayed, a single  
             key press is all that's needed, and it is not necessary to press   
             the <ENTER> key afterwards.
          2) Although the Ultra-Utilities will display numeric values in the    
             format specified by the display radix, you can input numbers using 
             any of three allowable radices without regard for the display 
             radix.  Decimal numbers should be entered normally, without any
             prefix.  Octal numbers should be entered using the prefix &O, and 
             hexadecimal numbers should be entered using the prefix &H.  This 
             is in keeping with the standard numeric entry procedures of IBM    
             BASIC.  Example: the decimal number 17 could be entered as:
                                17 (decimal)
                              &H11 (hexadecimal)
                              &O21 (octal)
          3) If you have a lineprinter installed and selected, you can obtain   
             a hardcopy of the screen at any point by pressing the "PrtSc" key  
             while holding down the <SHIFT> key.  This is also in keeping with  
             BASIC operation.
          4) The Ultra-Utilities are completely menu-driven.  This means you'll
             never have to guess which cryptic command the computer is waiting  
             for: all of your available options are displayed on the screen.    
             Although some folks prefer non-menu-driven programs, we feel it is
             a necessary deterrent to possibly catastrophic mistakes made by 
             the wrong guess with these programs.
          5) Ultra-Zap will allow you to display and modify sectors of any 
             length or name (such as those used in copy-protected software).    
             Although this is by no means meant to be a "pirate" program, it    
             is of great educational use for the novice "zapper".  It can be
             used in conjunction with Ultra-Format to create your own copy-
             protected diskettes.
          6) IN MOST CASES, answering a prompt with the single letter "Q" 
             followed by the <ENTER> key will CANCEL THE CURRENT FUNCTION and   
             RETURN YOU BACK to the main menu.
          Hopefully, you have restrained you anxiousness to get started with 
          the Ultra-Utilities and have taken at least a few moments to scan 
          this manual.  We hope that you have fun with these programs and that 
          they earn a permanent home in your software library.  Don't forget to 
          look over the duplication policy in Appendix A of this manual.  It 
          explains how the Ultra-Utilities can even earn you a few extra bucks 
          just for spreading it around.
          Whenever you are finished with an Ultra-Utility program, always exit 
          by choosing the Q>uit function from the main menu.  The 
          Ultra-Utilities change some important tables in memory that DOS 
          expects to be present and correct, and the "Q" function restores them 
          to their original values.

          One last caveat... this manual is by no means meant to be a tutorial 
          on the diskette storage techniques of the IBM-PC and PC-DOS.  We 
          recommend for further study the PC-DOS manual, the IBM Technical 
          Reference manual, and Peter Norton's "Inside The IBM-PC" published by 
          Robert J. Brady.
                               Display/Modify Disk Sectors
          This function, along with the Display/Modify File Sectors function is 
          the real meat of the Ultra-Zap program.  It gives you the ability to 
          "snoop" around your diskettes, modify bytes or characters, and
          encrypt or decode encrypted sector data.
          When you select this function, you'll first be prompted for the side, 
          drive, track and sector number of the first sector you wish to look 
          at.  Remember, if you only have a single-sided disk drive, you will 
          always specify side 0.  If you are unclear what to enter, take a 
          moment to peruse Appendix B of this manual.
          Once you have entered the above info, you will be instructed to mount 
          the diskette on the appropriate drive and press any key.  Once you 
          have done so, the disk drive should come to life and you will enter 
          what we call the "search mode".
          The search mode displays a straight dump of the ASCII characters in a 
          sector, allowing you to find the information you're looking for in a 
          hurry.  Only those characters with ASCII codes between 32 and 127 
          (decimal) will be displayed.  The rest will be displayed as periods.
          There are several command keys active in the search mode:
          UP ARROW - increments the track by one and displays that sector.
          DOWN ARROW - decrements the track by one and displays that sector.
          RIGHT ARROW - increments the sector by one and displays that sector.
          LEFT ARROW - decrements the sector by one and displays that sector.
          "5" KEY ON NUMERIC KEYPAD - switches from Side 0 to Side 1 and vice-  
             versa (if you have double-sided drives) and displays that sector.
          "M" key - enters "modify" mode.
          "Q" key - returns to Ultra-Zap main menu.
          In the "modify mode" the sector information will be displayed a bit 
          differently.  Select a random sector and let's go through the display 
          together.  The top line reiterates the current side, drive, track, 
          and sector number of the sector you are working on, as well as the 
          current display radix.  The second line just identifies what is in 
          the columns below.  The third line is a template for the "ones" digit 
          of the offset address- we'll come back to this in a moment.  The 
          fourth line starts with the actual sector data.  The leftmost column 
          of these rows show the number of bytes offset into the sector.  Then 
          comes the sector data in numeric form.  The rightmost column contains 
          the ASCII equivalent of the numeric data.  If you are using 
          hexadecimal for the display radix, there will be 16 rows of 16 bytes 
          each.  Decimal uses 20 rows X 10 bytes, and octal uses 16 rows X 
          8 bytes.  If you wanted to find the fifth byte in a sector, you 
          would go to the row marked with the offset address 0000 and scan 
          across under the template in line three of the display marked 
          "5".  It's really pretty easy to find an individual byte in a snap 
          once you get used to this "offset address/template column" 
          The bottom of the screen tells you your available choices, as well as 
          the current modify mode for byte replacement (either "NUM" for entry 
          of numeric replacement bytes, or "ASC" for the direct entry of ASCII 
          replacement characters from the keyboard).  You can toggle back and 
          forth between ASC and NUM modes by choosing the "C" choice.  The "Q" 
          choice returns you to the search mode.  The "I" and "D" choices allow 
          you to add or subtract a number from each of the bytes in the sector 
          for either encrypting or decoding encrypted sector data.  The "M" 
          choice takes you into what we call "replacement mode".  The other two 
          choices are "N" and "P".  You will notice that all of the bytes in a 
          standard 512-byte disk sector aren't displayed all at once in the
          display screen.  What we did is divide the sector into "pages" of 
          data.  Use the "N" key to look at the next higher display "page" of 
          sector data.  Use the "P" key to look at the next lower display page 
          of data.  Depending on the display radix and sector size, each sector 
          may actually be displayed as several pages.
          If you wish to modify the bytes in a sector, you should first choose 
          the modify mode you wish to use, and the "N" and "P" choices to 
          display the "page" that contains the bytes you wish to modify.  Once 
          you have done so, select the "M" option to enter the "replacement 
          mode".  In the replacement mode, an inverse cursor will appear in the 
          first byte of that page.  Use the arrow keys to position the cursor 
          on the byte you wish to modify and then press the spacebar.  If you 
          are in NUM mode, you will be prompted to enter in the new value.  For 
          each byte you wish to modify in the NUM mode, you will have to press 
          the spacebar as above.  However, in the ASC modify mode, you just 
          press the spacebar once.  You can then type in characters from the 
          keyboard continuously.  When you are finished modifying bytes in 
          either mode, just press the <ENTER> key.  Note that in the ASC mode 
          you can enter in any ASCII character that appears on the keyboard 
          except the <ENTER> key.  If you wish to enter in a character that 
          does not appear on the keyboard, just hold down the ALT key and type 
          in the three-digit ASCII code of the character on the numeric keypad, 
          just as you would in BASIC.
          One more note about the "replacement mode": any ASCII characters that 
          are not between codes 32 and 127 are displayed as dots.  This is 
          because some codes will cause your printer to do weird things if you 
          try to get a screendump using the <SHIFT>-PrtSc combination.  If you 
          wish to look at the actual character for non-alphanumeric characters, 
          just move the cursor over the byte in the replacement mode.  The dot 
          will be replaced with the actual character in the ASCII equivalent 
          After you have pressed the <ENTER> key to end replacement, you will 
          be asked if you wish to update the disk sector with your replacements 
          or just cancel all changes.  Up to now, nothing on the diskette has 
          actually been changed.  Instead, any changes you made were done on a 
          copy of the disk sector in memory.  If you cancel, you will be 
          immediately returned to the main menu with no changes recorded.  If 
          you select the update choice, your changes will be recorded on the 
          disk sector permanently (so be careful, for heaven's sake!).
          Whew!  That's quite a bit to swallow in one reading...  My advice is 
          to read this through, practice on a "scratch" diskette (one you can 
          afford to destroy) and then re-read this chapter for the finer points 
          of this powerful feature of the Ultra-Zap program.

                               Display/Modify File Sectors
          This function is used to root around the program and data files that 
          are on your diskettes.  By using this feature, you can do such things 
          as make easy corrections to data files and change ASCII messages in 
          the programs.  We do not condone people going through and wiping out 
          an author's name or copyright notices.  Such things are not only 
          childish, they deprive the author and software company of the money 
          and credit they deserve, and stifle creative folks from producing
          better software for us all.  However, who can resist going into
          COMMAND.COM and changing the sign-on message to "Ed Spread's Garbage 
          DOS"?  Oh well, it's a dilemma for the philosophers.  Have fun...
          This function operates almost exactly like the Display/Modify Disk 
          Sectors function with a few exceptions that pertain to disk files.  
          Once you are familiar with that function, you should have no trouble 
          with this one.  One important difference we will note here is that in 
          the search mode, the up arrow, down arrow, and "5" key have no 
          function.  The left arrow and right arrows still move backwards and 
          forwards through the file sectors.
          You should also notice that all file sectors are displayed as 
          physical (we call them logical) sectors.  That means that even if you 
          created a random access data file with a record length of 53 bytes, 
          each sector in this function will still be displayed as 512 bytes.
          You will not be able to use this function on any files that contain 
          the "HIDDEN" or "SYSTEM" attributes in their directory entry.  Use 
          Ultra-File to remove these attributes.

                                    Copy Disk Sectors
          This function is used to copy disk sectors from one part of a 
          diskette to another, or between diskettes.  Copying is not done with 
          regard to the prior contents of the destination sectors, and any old 
          data will be destroyed.
          Use of this function is pretty straightforward.  If the specified 
          drives for the source and destination diskettes are the same, the 
          program will ask you if the source and destination sectors are on the 
          same diskette, if they are not, you will be prompted to mount the 
          appropriate diskette during the copying process.  Sectors are copied 
          consecutively, according to the progression order described in 
          Appendix B of this manual.
                                    Fill Disk Sectors
          This function is used to fill one or more sectors entirely with a 
          repeating single byte value.  This byte value is selected using the 
          Modify Sector Fill Byte function and has a default value of &HF6 (246 
          decimal) upon program execution.  This is the same as the default 
          value used in formatting fresh sectors by the DOS FORMAT program.
          Again, this function is pretty straightforward.  Sectors are filled 
          consecutively according to the progression order described in 
          Appendix B of this manual.
                             Search For Bytes In Disk Sectors
          This function is used to quickly locate the position of a specified 
          sequence of bytes or ASCII characters in disk sectors.  The sequence 
          of desired bytes or characters may be up to 15 long.  You will first 
          be asked if the sequence is numeric or ASCII.  Once you have chosen, 
          the program will ask you how many bytes or characters long the 
          sequence is.  Next, you will be prompted to enter the bytes or 
          characters for the search sequence in order one at a time.
          Next, you will enter the side, drive, track, and sector number for 
          the start of the search, as well as the number of sectors to search 
          through.  Then the search begins, moving consecutively through 
          sectors as described in Appendix B of this manual.
          If the sequence is found in a searched sector, a message will be 
          displayed telling you the side, drive, track, and sector number 
          containing the sequence as well as the offset address of the sequence 
          within that sector.  When each match is displayed, you have the 
          ability to abort the search or continue from that point.  If no 
          matches are found, a message will be displayed telling you so at the 
          end of the search.
                             Search For Bytes In File Sectors
          This function is operates just like the above Search For Bytes In 
          Disk Sectors except that file sectors are searched instead.  Again 
          you won't be able to use this function with files marked in their 
          directory entries as "HIDDEN" or "SYSTEM" files.  Use Ultra-File to 
          remove these attributes before using this function.
                                 Modify Sector Fill Byte
          This function allows you to change the default sector fill byte 
          value.  There are essentially two reasons to do this:
          A) For use with the Fill Disk Sectors function
          B) Before any disk sector or file sector is read from the disk in the 
             Display/Modify functions, the memory buffers that will contain a 
             copy of the sector data are first "flushed" with the sector fill 
             byte value.  If you ever run across a sector with a CRC-type error 
             (either intentionally formatted or caused by diskette wear/tear) 
             the Display/Modify functions will report the error.  Normally, if  
             you do not select the re-try function when a disk error occurs, 
             you are returned to the main menu.  In this instance, Ultra-Zap    
             will allow you to go ahead and look at the contents of the sector. 
             Some of the data may look funny due to effects of the error, but 
             at least you'll be able to have a look at where the CRC error      
             botched things up.  We suggest you select a sector fill byte of    
             zero for this type of work, since it will quickly show you where   
             the read data ends.
                                   Modify Display Radix
          This function is used to present all displayed numeric values in a 
          form you are most comfortable with.  When zapping, some folks 
          naturally hanker to hexadecimal (base sixteen); others are lost 
          without good old decimal (base 10).
          Still, there are actually those around that cut their milkteeth on a 
          Sperry-Univac and can't cut it without octal (base eight).  Whatever 
          you folks choose as your strokes, Ultra-Zap is well equipped to make 
          life easy for you.
          If you are a beginning zapper, We suggest the first thing you do upon
          executing Ultra-Zap is to choose this function and select the decimal 
          radix.  You Sperry-Univac people can do the same except choose octal. 
          For those of you who learned to count with sixteen fingers, you won't 
          need to do anything.  Hexadecimal is the default radix for Ultra-Zap.
                                Interrogating Disk Sectors
          So, you just bought a protected diskette and you just can't wait to 
          find out what makes that thing tick, eh?  This function gets into the 
          guts of a diskette's format and tells you all of its secrets.  While 
          it's great for just snooping around, it's best use will come by being 
          used in concert with the special formatting abilities of the 
          Ultra-Format program.
          This function will ask you to specify the drive, side, starting 
          track, and ending track of the interrogation.  It will then ask you 
          the lowest and highest sector numbers to search for.  If you've got 
          a 40-track drive (like most of us), the maximum interrogation will be 
          from track 0 to track 43 (throw in a couple extra tracks for those 
          tricky buggers), searching for sectors 0 to 255 (all values decimal). 
          Such an interrogation will take quite a bit of time, which is why we 
          included the Toggle Menu Alert Tone function.
          You can also specify that the output be recorded on your printer to 
          be used for later reference.
          Here's a few tips to get the most out of this function:
          A) Try to make a backup of the suspect diskette with DOS's DISKCOPY 
             program.  On the weirdly formatted tracks, the program will report 
             a read error.  Write down these track numbers.
          B) Place a write-protect tab on the suspect disk and interrogate all 
             of the tracks that DISKCOPY threw a fit over.  Search for sectors  
             0 to 255 (decimal).
          C) Most often, the protection scheme is to either format one or more  
             sectors or tracks with sector sizes other than the standard 512    
             bytes, or to either give one of the sectors a wild sector number   
             like 214 or just not format a whole track of eight sectors.  If    
             you've got the same VisiCalc master I do, you'll find that sector  
             8 on track 39 is missing entirely.
          The interrogation function will tell you which sector numbers were 
          found, their size in bytes, and if they were formatted with a CRC 
          error (another not so fancy trick).  Also notice that the 
          interrogation process can be aborted by pressing the "C" key.
          (8)                     Toggle Menu Alert Tone
          This function is used to sound the computer's speaker when a 
          particularly time consuming function has been completed.  Selecting 
          this function toggles the alert tone on and off, and is most often 
          used with the Interrogate Disk Sectors function, which returns 
          directly to the main menu when finished.
          Display/Modify Disk Parameters
          Even though the IBM-PC uses a standard format for writing data on 
          diskettes (40 tracks numbered 0 to 39 of 8 sectors each numbered 1 to 
          8 of 512 bytes each), it has the capability of reading and writing 
          many other formats.  To do so, you'll have to change certain bytes in 
          a special table kept in the PC's memory called the Disk Parameter 
          Table.  This function displays the current value of these bytes and 
          allows you to modify them.  Note that not all of the values will be 
          of any use to you.
          There are 11 bytes in the Disk Parameter Table:
          1) Specify byte #1: the left "nybble" or single digit of this value  
             when viewed in hex is the step rate time for the disk drive head.  
             The right "nybble" is the disk head unload time.  These values are 
             best left alone.

          2) Specify byte #2: Again, don't fool around with these values.  The 
             left "nybble" is the disk head load time, and the right nybble is  
             the direct memory access mode select.
          3) Wait time until motor is turned off.  Not normally of use.
          4) Bytes-per-sector value: AH-HAH!  If you place a "0" in this value, 
             The PC expects all sectors to be 128 bytes long.  A "1" means a 
             sector size of 256 bytes, a "2" means 512 bytes (this is the       
             standard DOS value), and a "3" means 1024 bytes per sector.
          5) Highest sector number on a track: This is used for formatting and  
             tells DOS how many sectors there are on each track.
          6) Gap length for diskette reads: this is what you fool around with 
             if you keep getting CRC errors when you try to read a non-standard 
             size sector.  Normally, you can just leave this alone except when  
             formatting with Ultra-Format.
          7) Data length: This contains the number of bytes in a sector when 
             the value in table byte #4 doesn't contain a 0, 1, 2, or 3.
          8) Number of bytes in the gap between sectors: this is also only used 
             when formatting special tracks.
          9) Format fill byte: When formatting, this is the initialization byte 
             that will be placed in all new sectors.
          10) Head settle time: leave this alone.
          11) Motor start time: don't fool with this either.
          (9)           How To Display/Modify Non-Standard Sectors
          The best way we can think of to demonstrate how to use this program 
          with protected diskettes is to give you an actual example "script".
          One fine day, a local marketing manager for a large software company 
          was in our offices boasting his company's newest product.  When we 
          showed him the Ultra-Utilities, he challenged us that it "won't be 
          able to touch this disk".  We sat him down at our PC and booted up 
          Ultra-Zap.  This first thing we did was Interrogate track 1 of his 
          diskette, searching for sectors 0 to 255.  Like magic, Ultra-Zap told 
          us that his diskette was formatted as five sectors, numbered 1, 2, 3, 
          4, and 5, and were 1024 bytes long each.  Next, we went into the Disk 
          Parameter table and changed byte #4 (bytes-per-sector value) to a 
          value of 3 (meaning 1024 bytes per sector).
          Now, we choose the Display/Modify function to look at track 1, sector 
          1.  The first thing this function does is attempt to read the 
          FAT table on the diskette to determine if is single or double-sided.
          When you are working with protected diskettes that do not have a 
          valid FAT table, or if you change the bytes-per-sector value, this 
          function will report an error reading track 0, side 0, sector 2.  It 
          will then ask you how many sides are on the diskette (since it 
          couldn't figure this out from the FAT).  We answered 1 side, knowing 
          that nearly all distribution software comes on single-sided 
          diskettes.  The Display/Modify function worked perfectly, as 
          evidenced by the look of worry on our friend's face.  "You're giving 
          this thing away for free?", he asked us.  We decided it would be best 
          not to show him how we could make a backup of his disk with 
          (10)                   Format A Standard Track
          This function is used to lay down a fresh format pattern on a single 
          track.  It will destroy any previous data on that track.  If you are 
          attempting to revive sectors that were marked "damaged" by the DOS 
          FORMAT program, you will have to also change the corresponding values 
          in the File Allocation Table (FAT) after getting a successful format. 
          Refer to the IBM DOS manual for details on the FAT.  Our experience 
          is that the work required is usually not worth the trouble of getting 
          back a few sectors.
          When the sectors are formatted, they are initialized with whatever 
          byte is in the "Fill byte" parameter in the Disk Parameter Table.  
          Initially this is &HF6 (246 decimal).  If you wish to change this, 
          see the Display/Modify Disk Parameter Table chapter below.
                   Re-Format A Standard Track Without Erasing Old Data
          This function is used whenever a disk starts to report read and write 
          errors in normal use.  It repairs the diskette by first reading the 
          sector data into memory, writing a fresh format pattern on the 
          diskette, and the writing back the old data into the freshly 
          formatted sectors.
          You may specify how many times the program should attempt to re-read 
          a sector that reports an error.  Depending on the severity of damage 
          to a sector, it may be necessary to re-read it 50 or more times 
          before you get a good read.  If after the specified number of 
          re-reads the sector still cannot be read, the program will format a 
          fresh sector in that location.  Depending on the file, this may make 
          it unusable.  If it's a program file, probably so.  However, if it's 
          a data file or BASIC program stored in ASCII format, you should be 
          able to go in with Ultra-Zap and patch things up.  After reading the 
          old data, you have the option to abort the fresh formatting and 
          return to the main menu.
                               Format A Non-Standard Track
          This function is used to create a copy-protected diskette track by 
          placing a format pattern on the diskette that DOS is normally not 
          able to read except under special circumstances.  On the IBM-PC, 
          there are four sector sizes we can format: 128 bytes, 256 bytes, 512 
          bytes, and 1024 bytes.  These sectors sizes can be read by DOS by 
          placing the values 0, 1, 2, and 3 respectively into the 
          byte-per-sector value in the Disk Parameter Table.  Now let's discuss 
          the difference between a logical and physical disk sector as referred 
          to by Ultra-Format.  The normal disk format is 8 sectors of 512 bytes 
          each numbered 1 to 8.  It is possible to give your non-standard 
          sectors any numeric name you wish.  That is, you could format a track 
          with three physical sectors numbered 12, 20, and 235.  This makes it 
          difficult for someone to copy your disk.  Another fancy trick is to 
          format a standard track 40.  Most disk drives are capable of 
          reading and writing a few extra tracks than the standard 0 through 
          39.  Most copy programs, and DISKCOPY, do not look for such a track.
          The "Highest Sector Number On Track" value in the Disk Parameter 
          Table tells this function how many physical sectors you wish to
          format on your non-standard track.  It does not dictate what the 
          highest logical sector number can be.  For each physical sector, you 
          will be asked to enter the logical sector name (0 to 255) and size 
          value (0, 1, 2, or 3).
          Non-standard tracks are usually used to hold special codes that a 
          program checks for when first executing.  To do this, you'll need to 
          incorporate a short disk sector reading assembly language subroutine 
          into your program.  Study the ROM-BIOS calls in the Technical 
          Reference manual for disk I/O (interrupt 13H).  If this is still over 
          your head, drop us a line (registered users only) and we'll send you 
          some ready-to-go sample routines for use in assembly, compiled BASIC, 
          and regular BASIC programs.
          One more thing, when you format a non-standard track, you'll need 
          to fiddle around with a couple of values in the Disk Paramter Table, 
          specifically, bytes #6 and #8.  Look at the default values for a 
          standard 8 sector, 512 byte/sector format.  If you wanted to format a 
          track of 256 byte sectors, you might try doubling the standard 
          value of these bytes.  Our first issue of "The Zapper" newsletter 
          deals with formatting non-standard tracks for copy-protection work.
          If you're not a registered user, all we can suggest is 
          experimentation to come up with formats and Disk Parameter Table 
          values that do not cause CRC errors.
                           Display/Modify Disk Parameter Table
          This function works exactly like that in the Ultra-Zap program,  
          please refer to that chapter for instructions on how to use this 
                                   Modify Display Radix
          This function also works just like the Ultra-Zap Modify Display Radix 
          function.  Please refer to that chapter for more information.
          (12)             Display File's Directory Information
          This function allows you to see everything about a file that is kept 
          in DOS's directory of files.  As with most of the functions in the 
          Ultra-File program, this starts with a menu of all of the programs in 
          the directory.  Each filename is preceded with a number.  After the 
          filename, a single character (called the "attribute") tells you the 
          characteristics of a file.  These attribute codes are explained at 
          the bottom of the display.  If you have a double-sided diskette, 
          choose the "M" key to look at the rest of the directory entries. If 
          you have a single-sided diskette, all available file locations are 
          displayed at the same time.
          To see the directory information on a file, just type in its 
          corresponding number on the list.  Interestingly enough, we have 
          found that DOS 1.10 has some bugs in the way it sometimes reports a 
          file's date, time, and size in bytes when you issue the DOS command 
          DIR.  This function displays their correct values.
          You'll also notice that on all file lists in Ultra-File, deleted 
          files (those killed with BASIC's KILL or DOS's ERASE commands, for 
          example) are shown with the first character of their filename as a 
          question mark.
                              Assign Or Remove System Status
          This function allows you to either remove or assign the "SYSTEM" 
          attribute given to a file.  Files given this attribute are not 
          displayed with DOS's DIR command, cannot be accessed through DOS, and 
          are not copied with DOS's COPY *.* command.
                              Assign Or Remove Hidden Status
          This function allows you to either remove or assign the "HIDDEN" 
          attribute given to a file.  Functionally, the "HIDDEN" and "SYSTEM" 
          attributes are alike to DOS.  You'll notice though that system files 
          like IBMBIO.COM and IBMDOS.COM are given both "HIDDEN" and "SYSTEM" 
          attributes.  Hidden files are used a lot by software companies to 
          keep a program "secret".  Backup diskettes made with DISKCOPY still 
          include hidden and system programs, so it is not a good protection 
          means on its own.
                        Display List Of Sectors Allocated to File
          You'll notice that Ultra-Zap's Display/Modify File Sectors function 
          never really tells you where on the diskette the logical file sectors 
          are located.  This function knows all, tells all, about the location 
          of all sectors allocated to a file.  Notice that with double-sided 
          diskettes, sectors are allocated to a file two at a time (sectors 1 
          and 2, 3 and 4, 5 and 6, 7 and 8 are considered groups on a 
          double-sided diskette.  We think a good name for this is a "lump".  
          Just remember there is one sector per lump on a single-sided 
          diskette and two sectors per lump on a double-sided diskette).
          (13)                  Build A File From Scratch
          This function is used for creating a new file, and then taking 
          specific "lumps" (see section above for definition of a "lump") and 
          allocating them to this new file.  It can also be used when the 
          Attempt To Restore An Erased File function fails and you have used  
          Ultra-Zap to find the lumps that belong to a file.
          THIS IS A POTENTIALLY DANGEROUS FUNCTION!  Always work on a backup if 
          possible!  This function does not care if a lump was allocated to a 
          different file and can generally screw things up royally if you don't 
          know what you're doing.  If you're trying to restore an accidentally 
          erased file, always try the Attempt To Restore An Erase File function 
          This function will ask you to enter in the sectors to allocate to the 
          file.  You must enter these sectors in order!  Also, if you are 
          working on a double-sided diskette, only enter in the first sector of 
          each "lump" (that is, sectors 1, 3, 5, and 7).  If you try to 
          allocate both sectors 1 and 2 to a file, the disk will be thrown into 
          an endless loop.  You can allocate any sector for single-sided 
          diskettes since each sector is considered one lump.
          Using this function, you can experiment with a variety of neat tricks 
          including cross-threading files (two files having the same sectors 
          allocated) and allocating an entire diskette to one file.
                             Attempt To Restore An Erase File
          If you use this function IMMEDIATELY after accidentally erasing a 
          single file, you stand a near 100% chance of resurrection with this 
          function.  When a file is restored with this function or the Build 
          File From Scratch function (deleted file), the first character of the 
          filename will be changed to the letter "Z".  You can use DOS's RENAME 
          command to rename it to its original filename.
          If you killed multiple files (ERASE *.TXT type commands are notorious 
          for this), this function will probably not work.  Always use a backup 
          disk (made with DISKCOPY) before allowing this function to change the 
          directory info.
                                Produce A Map Of Diskette
          This function allows you to examine an entire diskette, sector by 
          sector, in the form of a unique road map.  Since the output is 
          self-explanatory, we will not discuss it here.  Suffice it to say 
          that you'll wish you took the time to make one of these for your most 
          valued diskettes should you ever experience the hand-spasm that 
          causes one to type ERASE *.* accidentally.   The ORP code means that 
          a sector is an "orphan", that is, it's been marked as allocated in 
          the File Allocation Table (FAT) but doesn't belong to any file in the 
          directory.  Running the DOS program CHKDSK will usually fix any 
          orphan lumps.
          (14)                   Selectively Purge Files
          You'll really appreciate this function on those times you want to 
          kill about 20 .TXT-type programs but want to keep one.  In such a 
          case ERASE .TXT will wipe them all out.  This function allows you to 
          go through and choose one by one the files you wish to "purge" from 
          the diskette.  Everytime you enter a file's number from the file 
          list, that file's number will begin to blink.  If you make a mistake, 
          just choose the "Q" function to cancel the purge.  If you have a 
          double-sided diskette, choose the "M" function to look at the rest of 
          the files in the directory.  When you've "marked" all of the files to 
          be purged, just choose the "P" function to start the hand of diskette 
          doom (ouch!).


          (15)         Appendix A: The FreeSoft Duplication Policy
          Before we get into the meat of how FreeSoft is going to make you a 
          billionaire, we'd like to give you a little background on how the 
          Ultra-Utility series came to be.  The software authors at FreeSoft 
          have been professionally involved with microcomputers since 1977.  
          When our IBM-PC became a member of the family, we were constantly 
          blowing up diskettes.  This, of course, was before any utility 
          programs of value existed for the PC.  Hoped as we did for help, the 
          Norton Utilities finally showed up and we snatched one of the first 
          packages that arrived at our local dealer.  Although the Norton 
          Utilities are a fine piece of programming, we were still 
          disappointed.  We suppose that the programs were great for the PC, 
          but being old-timers and certified hackers besides, we were spoiled 
          for what 80-bucks-plus-tax could buy in the way of utilities for our 
          other in-house micros.  To make a long story short, we did what any 
          self-respecting computerphiles would do.  We reinvented the wheel, 
          only made it round this time.
          Several thousand gallons of Pepsi later, the Ultra-Utilities emerged 
          (TA-DA!).  Everyone we showed it to alternated between spasms and 
          wild-salivation.  We thought we had a winner.  The next problem was 
          how to sell the damn thing.  We don't know, but we think a company 
          would have to be nuts to plunk down a couple thousand clams for a 
          small-shot ad in some of the phone-book sized IBM-PC magazines.  
          Sandwiched in there between a million other products just didn`t seem 
          to be the way to get good exposure.  Submitting it to a software 
          publishing house for distribution didn't seem like a good choice 
          either.  A machine language game we had written for the TRS-80 sold a 
          grand total of 11 copies (to date) once we had submitted it to a 
          publisher .  The problem is that you are at the mercy of how much
          the publisher is willing to spend for advertising. (Games for the PC? 
          Hmmmm...).  At any rate, it sure was funny that so many TRS-80 
          BBS's had rave reviews of the game.  Those eleven guys sure had a lot 
          of friends.  That brought us to the final problem.  Could we afford 
          not to copy-protect the Ultra-Utilities?  Much as we hate protected 
          software, when it's your money on the line you seem to modify your 
          feelings a bit.
          When we started seeing programs distributed on the User-Supported 
          basis, the old cogs really started spinning.  Now here was a way to 
          get maximum exposure at minimum cost.  Instead of trying to defeat 
          the many ways that software gets passed around, you take advantage of 
          them.  The whole thing relies on the fact that most of you folks are 
          honest users who will support a company that gives you a good 
          product.  Having been burned by some products that didn't live up to 
          their claims, we certainly agree that the best way for a person to 
          evaluate a package is to have it in their hands and run it through 
          its paces on their own terms.
          Therefore, we have decided to release the Ultra-Utilities by means 
          that will be the acid-test for the package.  Give it away!  If you 
          don't like it - pitch it.  If you like it but can't afford the 
          registration fees, we'll appreciate any donation you care to make.  
          If you like it and want to support us, we hope you'll consider 
          becoming a registered user.  Please think this over.  If you want to 
          see more software from us, we'll have to make a decent enough go of 
          this to justify it.  Without further pathos, let us make you an offer 
          of solid committment.  You support us, we'll give you your money's 
          worth and more.
          One thing is for sure, the quality of many User-Supported programs 
          certainly rivals, and in many cases exceeds, that of commercial 
          software costing much more.  We hope you'll make User-Supported 
          software an experiment THAT WORKS!
          Enough Coddling, Now On To The Good Stuff!
          If you feel the Ultra-Utilities are a good product that is worth 
          supporting, we've got a deal for you!  Here's the duplication policy 
          for FreeSoft products:
             A) We not only encourage you to share this product with your 
                friends, we will make it worth your while.  All we ask is       
                that you distribute the package as a whole in disk file form    
                as you would receive it from us.  (If you didn't get your copy  
                from us, that means that the following files should be on any   
                copy you give out: U-ZAP.EXE, U-FILE.EXE, U-FORMAT.EXE, 
                DOCUMENT.ONE, and DOCUMENT.TWO).  We also do not allow anyone   
                to charge money for a copy of our product.  If you must charge  
                for the diskette(s), you may charge no more than $8.00 total 
                for all diskettes included with the Ultra-Utilties without      
                special written permission from FreeSoft.
             B) You'll notice that on the main menu of each program is a 
                serial number.  When you become a registered user, we will ask  
                you what serial number is on your copy.  This does two things,  
                it tells you what version you have so we can send you the 
                latest if necessary, and it tells us where your copy 
                originated.  We will then give you a new serial number with     
                the registered copy of the Ultra-Utilities we send you.  When 
                someone registers and gives us your serial number, you get a    
                check from us for $10.  If you give a copy to every member of   
                your users group or even put it up on a BBS, every time someone 
                registers you get ten bucks, just like that.  Remember, in 
                order to get this commission, you have to register your copy    
                with us before giving out any copies.  Don't underestimate the 
                ability of a program to get spread around - this can really 
                bring you some big bucks.
             C) If you give someone a copy and you have not registered, you do  
                not make a commission.  We offer two ways to register your      
                program.  Registration with eligibility for commission costs 
                $40.  If you don't know any other PC owners or just don't want  
                to risk getting yourself into a higher tax bracket off of       
                commissions (!), we also offer a registration without 
                commission eligibility.  This costs $30, and gives full 
                benefits of registration with the exception of commissions.  We 
                hope you'll agree that either way is still a lot cheaper than   
                shelling out $80 for the Norton Utilities.
             D) If you can't afford the 30 bucks or are just the type who feels 
                better getting something for nothing, we understand.  We      
                would appreciate it if you could at least give out some copies  
                of this package, though.  The more people that get it, the more 
                people there are who will potentially support our company by    
          So What Do I Get For Registering When I Already Have It For Free?
          We thought you'd never ask.  If you are one of the folks who support 
          us, we will continue to make it worth your while with the following 
             1) If the version you register is not the latest, we will send 
                you the latest version, plus documentation, at no extra charge. 
                We will also inform you of any updates, and provide you with    
                those for no extra charge.
             2) You will also receive the next FreeSoft product WITH 
                REGISTRATION WITH COMMISSION ELIGIBILITY free of charge.  We    
                have many great products on the drawing board and near          
                completion, including machine language games, a database        
                program generator that is truly fantastic, BASIC programming   
                and compiler utilities, ready to run assembly language          
                subroutines, and a host of other goodies.  Remember, as a       
                registered user of the Ultra-Utilities, you will be a preferred 
                customer for all future FreeSoft releases.
             3) You'll get a free one-year subscription to "THE ZAPPER"         
                newsletter.  This is a consortium of no-holds-barred knowledge  
                for the IBM-PC.  It's where you'll find out the kinds of things 
                about your PC and PC software that the magazines would lose     
                advertisers over if they published them.  "THE ZAPPER" is    
                published quarterly and will be sent to you at no charge.
             4) Complete support by mail.  If the need arises, we may open up   
                a telephone hotline or bulletin board for our registered users.
             5) A date with our sisters - just kidding!  But seriously, what 
                could be a better way to pay for a program you like than a way  
                that puts money back into your pocket?
          (18)                      Registration Form
          Send to: The FreeSoft Company, P.O. Box 27608, St. Louis, MO 63146
          YES, I want to be a registered user of the Ultra-Utilities and be 
          placed on the preferred customer list for all future FreeSoft 
          I am enclosing the following formatted diskette(s) with a 
          SELF-ADDRESSED, RETURN POSTAGE PAID MAILER.  Please send me the 
          latest versions of the Ultra-Utilities and documentation manuals, 
          plus any other good things you might have laying around.
          (Note: please sandwich your diskette(s) between two stiff pieces of 
          cardboard and mark the return mailer clearly with the message 
          Mark one of the following:
          ___ Single-sided diskettes enclosed (send two with your request).
          ___ Double-sided diskettes enclosed (send one with your request).
          The old serial number in my program is _ _ _-_ _ _ _ _
          (This also tells us what version you have so we can send you the 
          latest. You will receive your personal serial number from us
          after we have filed your registration).
          Name:    _____________________________________________________
          Address: _____________________________________________________
          City:    _____________________________________________________
          State:   ____________    Zip Code ____________________________
          Please register me as (MARK ONE OF THE BELOW): 

          ___ Registered eligible for commissions (I enclose $40 check or money 
              order, and postage paid return mailer).

          ___ Registered not eligible for commissions (I enclose $30 check or 
              money order, and postage paid return mailer).
          PLEASE NOTE: Make all checks or money orders payable to THE FREESOFT 
          COMPANY.  Foreign registrations please add $10 to help with later 
          Comments, Suggestions or Questions:
          Invoice #34-34256
          Please make payable to :The FreeSoft Company
          Quantity              Description                           Price
             1             The Ultra-Utilities disk file             $40.00
                           repair software.
                                                      Tax............$ 0.00
                    Please remit ------------->       Amount Due.....$40.00
          Company Name ___________________________________________________
          Address      ___________________________________________________
                                   The FreeSoft Company
                                      P.O. Box 27608
                                   St. Louis, MO 63146
          (20)      Appendix B: A Brief Discussion Of Diskette Formats
          The standard IBM-PC stores data on floppy diskettes by dividing the 
          surface of the diskette into circular tracks (like the grooves on a 
          phonograph record, only complete circles instead of one long spiral). 
          There are 40 of these tracks on a standard IBM-PC disk drive numbered 
          0 through 39.  Each of these tracks are further sub-divided into gaps 
          and sectors.  Gaps are used to separate the sectors and help out with 
          the disk drive timing.  Sectors are used to hold the actual data that 
          will later be retrieved by the computer.  These sectors are numbered 
          1 through 8 on a standard diskette and hold 512 bytes of data each.  
          A double-sided diskette merely has an additional read/write head on 
          the reverse side of the diskette, effectively doubling the available 
          surface space for data.  A single-sided diskette can hold 39 tracks X 
          sectors/track X 512 bytes/sector = 159,744 bytes.  Double this for a 
          double-sided drive and you've got 319,488 bytes per diskette.  Of 
          course, not all of this space is available for use by the user.  Some 
          of it is set aside to contain the DOS system files.  Another chunk is 
          reserved for the File Allocation Table (FAT) and Directory that tells 
          the DOS where files and free space are located on a diskette.
          When you write a file on a freshly-formatted diskette, your data is 
          placed in consecutive sectors.  If your file begins on track 1, 
          sector 1, the first 512 bytes of data is placed in this sector, the 
          second 512 bytes are placed in track 1, sector 2, and so on.  What 
          happens when you reach the end of a track?  If you have a 
          single-sided diskette, the data continues on the first sector of the 
          next track.  If you have a double-sided diskette, each track is 
          actually composed of the sectors on both sides of the diskette.  In 
          other words, track 1 begins with side 0, track 1, sector 1, and ends 
          with side 1, track 1, sector 8.  When side 1 is filled up, the first 
          sector of the next higher track of side 0 is used.  This is the 
          normal progression order of sectors on a disk with PC-DOS version 
          1.10, and how Ultra-Zap spans to the "next" or "previous" sectors in 
          multiple-sector functions.
          (21)          Appendix C: Version Changes and Additions
          11/03/83: Version 2.00 release
          With the release of version 2.00 of the Ultra-Utilities, several new 
          and powerful features were added.  Mainly, we added compatibility 
          with DOS versions 2.0 and (from what we've been able to gather) 2.1.  
          We also fixed some bugs from the first version that could cause some
          potential damage under certain conditions.
          Of course, even version 2.00 is not completely compatible with all of 
          the nifty features of DOS 2.0 and 2.1.  In a few instances, you'll 
          have to be a bit sneaky in order to get the job done.  Here's an 
          overview of the limitations and considerations for version 2.00 of 
          the Ultra-Utilities when being used on DOS 2.0 or 2.1:
             1) Automatic DOS and FORMAT recognition: All Ultra-Utility 
                programs automatically recognize the DOS version being used 
                with a diskette, and the number of sectors formatted on each    
                track.  This allows us to have only one version of the Ultra-   
                Utilities for use with all DOS versions.  Since we are issuing  
                version 2.00 release before we have actually seen a copy of DOS 
                2.1, a new release may be in order at a later date.
             2) No hard disk support: The Ultra-Utilities are not meant to be   
                used with hard disks, although a very few functions will work.  
                The Display/Modify File Sectors and Search For Bytes In File 
                Sectors functions in Ultra-Zap should work, for instance.  For  
                other file work, the file should be copied onto a floppy.
             3) Root directory support only:  At this time, the Ultra-Utilities 
                are written to work only on files contained in DOS 2.0 and 2.1  
                root directories.  Files in subdirectories should be copied 
                into the root directory.  Again, experimentation will expose 
                a few features that will work on subdirectory files.  However,  
                this is left to your own device and is not documented.
             4) Format considerations: When using Ultra-Format, always verify   
                that the Highest Sector Number On Track byte in the Disk Par-
                ameter Table is set correctly to the number of sectors you wish 
                to format.  Disk swapping may cause this byte to be incorrect.
                This is also true for the Re-Format Without Erasing Old Data    
             5) Disk Roadmap: When you print out a map of a diskette using 
                Ultra-File, sectors allocated to subdirectory files may be 
                reported as ORPhan clusters.  Always use the CHKDSK utility     
                to free up actual orphan (allocated but not assigned to a       
                file) clusters if there is any question.
          12/10/83: Version 3.00 release
          Because of a mysterious hand spasm that caused us to stab a single
          wrong character while typing in Version 2.00, Ultra-File suffered
          a partial lobotomy that made it forget how to read single-sided
          diskettes.  We fixed it and then went out to drink our embarrassment
          into oblivion.
          We also added an invoice to the documentation so companies could
          register easier.
          01/29/84: Version 4.00 release
          U-Zap: Display no longer corrupted if you just press ENTER when
          entering ASCII search bytes in Search For Bytes functions.
          Interrogate function waits for prompt when finished if menu alert
          tone function is turned off.
          Fixed our post office box number on opening page (GADZOOKS!).
          U-Format: Fixed main menu Format Standard Track function to reflect
          correct number of sectors for current Disk Parameter Table.
          U-File: Major bug fixed in Build A File From Scratch function when
          working with single-sided diskettes.  Approved a resolution to do
          a version of The Ultra-Utilities for the MacIntosh the day after
          IBM sponsors a multi-million dollar rock festival.
          Waits for pauses after each main output section of Produce A Map 
          function if output is not to printer.
          All three programs: Version number is now displayed on fancy-pants 
          opening title display.  Serial number is still displayed on main
          menu page.
          Incorporated a secret into the Ultra-Utilities just to see how many
          of you read this crap.  You can skip the opening page altogether and
          go directly to the main menu by pressing your ESCape key once while
          the program is loading, but before it begins execution.

          Thought about changing U-Zap and U-Format to automatically accept 
          numeric input in the same radix as display radix is set, but then
          decided it would be too much work since you can do that anyway by
          just entering &H or &O prefixes for hex or octal entry.  Let's take
          a vote whether or not Version 5 should include this.


1 CLS:KEY OFF:AQ$="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 !@#$%^&*()_-+={}[]:;'?/>.<,|\":IN=0:ON ERROR GOTO 49000:CURRENT=-1
100 GOSUB 50000:GOSUB 46000:STAT1$="A"
500 REM ************************************************************
501 REM *** Main Menu Function         Process: Display choices, get choice
502 REM ***                                     then call appropriate routine
503 REM ************************************************************
510 CLS:LOCATE 1,1:A$="Current Record ="+C$:A1$="Number of entered records ="+STR$(GOOD):A2$="Maximum number of records ="+STR$(MAXSIZE):A3$="Current Data Disk Volume: "+V$
520 PRINT TAB(1);A$;TAB(80-LEN(A1$));A1$:LOCATE 2,1:PRINT TAB(40-(LEN(A2$)/2));A2$:LOCATE 3,1:PRINT TAB(40-LEN(A3$)/2);A3$
525 LOCATE 4,1:PRINT STRING$(79,"_");:LOCATE 19,1:PRINT STRING$(79,"_");
530 LOCATE 6,1:A$="---> Main Menu Choices <---":PRINT TAB(40-(LEN(A$)/2));A$
540 LOCATE 8,20:PRINT "G)et A Record.":LOCATE 9,20:PRINT "S)earch For And List Records."
550 LOCATE 10,20:PRINT"A)dd A Record.":LOCATE 11,20:PRINT"D)elete Current Record.":LOCATE 12,20:PRINT"U)pdate Current Record.":LOCATE 13,20:PRINT"X)-tend Work To New Data Diskette."
560 LOCATE 14,20:PRINT"I)nitialize New Data Diskette.":LOCATE 15,20:PRINT"Q)uit And Return To BASIC."
580 A$="Enter your choice (G,S,A,D,U,X,I, or Q):  ":LOCATE 18,1:PRINT TAB(40-(LEN(A$)/2));A$:ROW=18:COLUMN=((40-LEN(A$)/2)+LEN(A$)-1):A1%=1:AX$="GgSsAaDdUuXxIiQq":GOSUB 40130
590 IF AN$="" GOTO 580
600 IF AN$="Q" OR AN$="q" THEN CLOSE:GOSUB 50000:CLS:PRINT"Program Finished...":END
610 IF AN$="G" OR AN$="g" THEN GOSUB 680:GOSUB 39000:GOTO 500
620 IF AN$="S" OR AN$="s" THEN GOSUB 680:GOSUB 45000:GOTO 500
630 IF AN$="A" OR AN$="a" THEN GOSUB 41000:GOTO 500
640 IF AN$="D" OR AN$="d" THEN GOSUB 680:PAGE=0:GOSUB 2000:GOSUB 7000:GOSUB 42000:GOTO 500
650 IF AN$="U" OR AN$="u" THEN GOSUB 680:GOSUB 43000:GOTO 500
660 IF AN$="X" OR AN$="x" THEN GOSUB 680:GOSUB 46000:GOTO 500
670 IF AN$="I" OR AN$="i" THEN GOSUB 680:GOSUB 47000:GOTO 500
2000 REM ************************************************************
2001 REM *** Display Screen Info Routine    In: PAGE = page #
2002 REM ***                                        or
2003 REM ***                                    FL = field #
2004 REM ***                               Out: Screen info on that page is
2005 REM ***                                    displayed, then exit to
2006 REM ***                                    caller.
2007 REM ************************************************************
7000 REM ************************************************************
7001 REM *** Display Record Fields Routine  In: Page = page #
7002 REM ***                               Out: Working strings displayed,
7003 REM ***                                    then exit to caller
7004 REM ************************************************************
12000 REM ************************************************************
12001 REM *** Block Record Routine     In: Working strings filled
12002 REM ***                         Out: Record strings filled then exit
12003 REM ***                              to caller.
12004 REM ************************************************************
17000 REM ************************************************************
17001 REM *** Unblock Record Routine   In: Record strings filled
17002 REM ***                         Out: Working strings filled then
17003 REM ***                              exit to caller.
17004 REM ************************************************************
22000 REM ************************************************************
22001 REM *** Input A Field Routine    In: FL = field number to input
22002 REM ***                         Out: Working string filled after
22003 REM ***                              passing edit check, then exit
22004 REM ***                              to caller.
22005 REM ************************************************************
32000 REM ************************************************************
32001 REM *** Get a Record Routine      In: RECNUM = record number to get
32002 REM ***                          Out: Record strings filled (need to be
32003 REM ***                               unblocked.)
32004 REM ************************************************************
33000 REM ************************************************************
33001 REM *** Hash Keyfield Routine    In: KY$ = Key field
33002 REM ***                         Out: RECNUM = Hashed record specifier
33003 REM ************************************************************
33010 X#=0:FOR ZZ=1 TO LEN(KY$):X#=X#+ZZ*ASC(MID$(KY$,ZZ,1)):NEXT ZZ
33020 X#=X#*X#*X#*X#:X$=STR$(X#):RECNUM=VAL(MID$(X$,5,4)):X#=0
33040 RETURN
34000 REM ************************************************************
34001 REM Delete a record routine    IN: RECNUM = record number to delete
34002 REM                           OUT: Record is deleted
34003 REM                                CURRENT = -1
34004 REM ************************************************************
35000 REM ************************************************************
35001 REM *** Put a Record Routine     In: RECNUM = record number to put
35002 REM ***                              Record strings must be filled
35003 REM ***                         Out: CURRENT = Record number
35004 REM ***                              Record is writted to disk file
35005 REM ************************************************************
36000 REM ************************************************************
36001 REM Error Response Routine   In:ERROR = 1,2,3, or 4
36002 REM                             ER$= error string if ER = 4
36003 REM                         OUT: Error message is printed, waits
36004 REM                              For 'c' or 'C' keypress, then
36005 REM                              exits to caller
36006 REM ************************************************************
36010 LOCATE 25,1:PRINT STRING$(79,32);:A$=" ERROR! ":P=40-LEN(A$)/2
36020 BEEP:ON ER GOTO 36030,36040,36050,36060
36030 B$="Record Not Found... Press <C> to Continue":GOTO 36070
36040 B$="Data Diskette Is Full... Press <C> to Continue":GOTO 36070
36050 B$="No Current Record In Memory... Press <C> to Continue":GOTO 36070
36060 B$="Entry Must Not Be "+ER$+"... Press <C> to Continue"
36070 LOCATE 25,1:PRINT STRING$(79,32);:LOCATE 25,40-LEN(B$)/2:PRINT B$;
36080 LOCATE 24,P:PRINT A$;:CT=1
36090 Z$=INKEY$:IF Z$="C" OR Z$="c" GOTO 36150
36100 CT=CT+1:IF CT=4 THEN CT=1
36110 IF CT=1 THEN LOCATE 24,1:PRINT STRING$(35,"/");:LOCATE 24,44:PRINT STRING$(36,"/");:GOTO 36090
36120 IF CT=2 THEN LOCATE 24,1:PRINT STRING$(35,"-");:LOCATE 24,44:PRINT STRING$(36,"-");:GOTO 36090
36130 IF CT=3 THEN LOCATE 24,1:PRINT STRING$(35,"\");:LOCATE 24,44:PRINT STRING$(36,"\");:GOTO 36090
36140 LOCATE 24,1:PRINT STRING$(79,"=");:LOCATE 25,1:PRINT STRING$(79,32);:RETURN
36150 LOCATE 24,1:PRINT STRING$(79,"=");:LOCATE 25,1:PRINT STRING$(79,32);:RETURN
37000 REM ************************************************************
37001 REM *** Submenu #1 Function    Process: Display choices M)enu, U)pdate,
37002 REM ***                                 D)elete, A)dd, and S)witch
37003 REM ***                                 page.  Get choice and
37004 REM ***                                 Branch to appropriate function
37005 REM ************************************************************
37010 LOCATE 25,1:PRINT STRING$(79,32);:A$="Enter choice: M)enu, U)pdate, D)elete, A)dd, S)witch page: ":LOCATE 25,1:PRINT A$;
37020 ROW=25:COLUMN=LEN(A$)+2:AX$="MmUuDdAaSs":A1%=1:GOSUB 40130:IF AN$="" GOTO 37010
37030 IF AN$="M" OR AN$="m" THEN RETURN
37040 IF AN$="U" OR AN$="u" GOTO 43000
37050 IF AN$="D" OR AN$="d" GOTO 42000
37070 IF AN$="A" OR AN$="a" GOTO 41000
37090 CLS:FL=0:GOSUB 2000:GOSUB 7000:GOTO 37000
38000 REM ************************************************************
38001 REM *** Submenu #2 Function      Process: Ask for R)estore, S)witch
38002 REM ***                                   Page, or M)enu and
38003 REM ***                                   Branch to appropriate function
38004 REM ************************************************************
38010 LOCATE 25,1:PRINT STRING$(79,32);:A$="Please choose: R)estore, S)witch page, or M)enu ":LOCATE 25,1:PRINT A$;:ROW=25:COLUMN=LEN(A$)+2:A1%=1:AX$="RrSsMm":GOSUB 40130
38020 TEST$=AN$:IF AN$="" GOTO 38010
38040 IF TEST$="P" OR TEST$="p" THEN GOSUB 36000:GOTO 38010
38050 IF TEST$<>"s" AND TEST$<>"S" GOTO 38100
38070 CLS:FL=0:GOSUB 2000:GOSUB 7000:GOTO 38010
38100 STAT1$="A":GOSUB 12000:GOSUB 35000:CURRENT=RECNUM:GOTO 37000
39000 REM ************************************************************
39001 REM *** Get a Record         Process: Accepts key field, searches
39002 REM ***                               for record, if found, displays
39003 REM ***                               it and verifies that its the
39004 REM ***                               right one.  If not, continue
39005 REM ***                               search until error.  Otherwise,
39006 REM ***                               display the record and branch
39007 REM ***                               to Submenu #1 Function
39008 REM ************************************************************
39010 PAGE=1:FL=0:GOSUB 2000:FL=1:GOSUB 22000:KY$=F$(1):GOSUB 33000
39030 GOSUB 32000:IF STAT$="E" THEN ER=1:CURRENT=-1:GOTO 36000
39040 IF STAT$="D" GOTO 39200
39050 GOSUB 17000:IF KY$<>LEFT$(F$(1),LEN(KY$)) GOTO 39200
39060 GOSUB 7000:LOCATE 25,1:PRINT STRING$(79,32);:A$="Is this it (Y/N)? ":LOCATE 25,1:PRINT A$;
39070 ROW=25:COLUMN=LEN(A$)+2:AX$="YyNn":A1%=1:GOSUB 40130:IF AN$="" GOTO 39060
39220 GOTO 39030
40127 REM ************************************************************
40128 REM *** Alphanumeric Input routine   IN: ROW,COLUMN, A1%,ax$  OUT: AN$
40129 REM ************************************************************
40130 AN$="":A%=0:LOCATE ROW,COLUMN,0,1,20:PRINT STRING$(A1%,CHR$(22));
40131 IF A%=A1% THEN 40134 ELSE LOCATE ROW,COLUMN+A%,0,1,20:PRINT CHR$(22);
40132 A$=INKEY$:IF A$="" THEN 40132 ELSE IF INSTR(AX$,A$) THEN AN$=AN$+A$:LOCATE ROW,COLUMN+A%,0,1,20:PRINT A$;:A%=A%+1:GOTO 40131
40133 ON INSTR(CHR$(8)+CHR$(13),A$) GOTO 40135,40138:GOTO 40131
40134 A$=INKEY$:IF A$="" THEN 40134 ELSE 40133
40135 IF A%<A1% THEN LOCATE ROW,COLUMN+A%,0,1,20:PRINT CHR$(22);
40136 A%=A%-1:IF A%<0 THEN A%=0:GOTO 40131:ELSE AN$=LEFT$(AN$,LEN(AN$)-1):GOTO 40131
40138 LOCATE ROW,COLUMN+A%,0,1,20:PRINT STRING$(A1%-A%," ");
40139 RETURN
40147 REM ************************************************************
40149 REM ************************************************************
40151 IF A%=>LEN(AF$) THEN 40156 ELSE A%=INSTR(A%+1,AF$,CHR$(22)):LOCATE ROW,COLUMN+A%-1
40152 A$=INKEY$:IF A$=""THEN 40152 ELSE IF INSTR("1234567890",A$) THEN PRINT A$;:GOTO 40151
40153 ON INSTR(CHR$(8)+CHR$(13),A$) GOTO 40150, 40159
40154 GOTO 40151
40156 A$=INKEY$:IF A$="" THEN 40156 ELSE 40153
40200 FOR Z=1 TO LEN(AF$):IF MID$(AF$,Z,1)="/" THEN MID$(AF$,Z,1)=CHR$(22)
41000 REM ************************************************************
41001 REM *** Add A Record Function       Process: Fill input strings
41002 REM ***                                      write it disk, then
41003 REM ***                                      exit to caller on
41004 REM ***                                      error, or to submenu #1
41005 REM ************************************************************
41030 LOCATE 25,1:PRINT STRING$(79,32);:A$="Press <Y> to add record or <N> to abort":LOCATE 25,1:PRINT A$;
41040 ROW=25:COLUMN=LEN(A$)+2:AX$="YyNn":A1%=1:GOSUB 40130:IF AN$="N" OR AN$="n"THEN CURRENT=-1:RETURN
41045 IF AN$="" GOTO 41030
41050 KY$=F$(1):GOSUB 33000
41060 GOSUB 32000:IF STAT$="A" GOTO 41100
41070 GOSUB 12000:GOSUB 35000:CURRENT=RECNUM:GOTO 37000
41120 GOTO 41060
42000 REM ************************************************************
42001 REM *** Delete Current Record Function   Process: Verify delete
42002 REM ***                                           then erase it from
42003 REM ***                                           from view by marking
42004 REM ***                                           Stat$ as "D"
42005 REM ************************************************************
42007 IF CURRENT=-1 THEN ER=3:GOTO 36000
42010 LOCATE 25,1:PRINT STRING$(79,32);:A$="Press <Y> to delete this record or <N> to abort.":LOCATE 25,1:PRINT A$;
42020 ROW=25:COLUMN=LEN(A$)+2:AX$="YyNn":A1%=1:GOSUB 40130:IF AN$="N" OR AN$="n" THEN LOCATE 25,1:PRINT STRING$(79,32);:RETURN
42025 IF AN$="" GOTO 42010
43000 REM ************************************************************
43001 REM *** Update Current Record Function   Process: Allow modifications
43002 REM ***                                           to specified fields,
43003 REM ***                                           make changes to record,
43004 REM ***                                           then exit to caller.
43005 REM ************************************************************
43020 LOCATE 25,1:PRINT STRING$(79,32);:A$="Enter field number to modify "
43030 LOCATE 25,1:PRINT A$;:ROW=25:COLUMN=LEN(A$)+2:AX$="0123456789":A1%=LEN(STR$(NF))-1:GOSUB 40130:FL=VAL(AN$):IF FL=0 THEN LOCATE 25,1:PRINT STRING$(79,32);:RETURN
43035 IF AN$="" GOTO 43020
43040 IF FL>NF GOTO 43020
43050 PAGE=0:GOSUB 2000:GOSUB 7000:GOSUB 22000:IF FL=1 THEN KY=1
43060 LOCATE 25,1:PRINT STRING$(79,32);:A$="Any more changes (Y/N)? ":LOCATE 25,1:PRINT A$;
43070 ROW=25:COLUMN=LEN(A$)+2:AX$="YyNn":A1%=1:GOSUB 40130:IF AN$="Y" OR AN$="y" GOTO 43020
43075 IF AN$="" GOTO 43060
43110 GOTO 41060
45000 REM ************************************************************
45001 REM *** Search and List Function     Process: Look for records matching
45002 REM ***                                       any specified parameters
45003 REM ***                                       and display them
45004 REM ************************************************************
45010 LOCATE 25,1:PRINT STRING$(79,32);:LOCATE 25,1:A$="Enter record # to start search or <ENTER> to start at current record ":PRINT A$;
45020 ROW=25:COLUMN=LEN(A$)+2:A1%=LEN(STR$(MAXSIZE)):AX$="0123456789":GOSUB 40130:RECNUM=VAL(AN$)
45060 LOCATE 25,1:PRINT STRING$(79,32);:LOCATE 25,1:A$="Do you wish to display records that have been deleted (Y/N)? ":PRINT A$;
45070 ROW=25:COLUMN=LEN(A$)+2:AX$="YyNn":A1%=1:GOSUB 40130:IF AN$="" GOTO 45060
45080 DEL$=AN$
45090 LOCATE 25,1:PRINT STRING$(79,32);:LOCATE 25,1:A$="Do you wish to select by a field's contents (Y/N)? ":PRINT A$;
45100 ROW=25:COLUMN=LEN(A$)+2:AX$="YyNn":A1%=1:GOSUB 40130:IF AN$="" GOTO 45090
45110 TEST$=AN$:IF TEST$="N" OR TEST$="n" GOTO 45200 ELSE LOCATE 25,1:PRINT STRING$(79,32);
45120 LOCATE 25,1:A$="Enter field number to test ":PRINT A$;:ROW=25:COLUMN=LEN(A$)+2:AX$="0123456789":A1%=LEN(STR$(NF)):GOSUB 40130:IF AN$="" GOTO 45120 ELSE FL=VAL(AN$):PAGE=0:GOSUB 2000
45130 LOCATE 25,1:PRINT STRING$(79,32);:A$="Enter test string":LOCATE 25,1:PRINT A$;:ROW=25:COLUMN=LEN(A$)+2:AX$=AQ$:A1%=35:GOSUB 40130:IF AN$="" GOTO 45130
45140 COMPARE$=RIGHT$(AN$,LEN(AN$)-1):TYPE$=LEFT$(AN$,1):IF TYPE$<>"<" AND TYPE$<>">" AND TYPE$<>"=" GOTO 45130
45200 GOSUB 32000:IF STAT$="E" GOTO 45300
45210 IF STAT$<>"D" GOTO 45220
45215 IF DEL$="N" OR DEL$="n" GOTO 45300
45220 IF TEST$="Y" OR TEST$="y" GOTO 45400
45230 GOSUB 17000:PAGE=1:FL=0:GOSUB 2000:GOSUB 7000:LOCATE 25,1:PRINT STRING$(79,32);:IF STAT$="A" THEN S$="Active" ELSE S$="Deleted"
45240 A$="Status: "+S$+": Continue search (Y/N)":LOCATE 25,1:PRINT A$;:ROW=25:COLUMN=LEN(A$)+2:A1%=1:AX$="YyNn":GOSUB 40130:IF AN$="Y" OR AN$="y" GOTO 45300
45250 IF AN$="" GOTO 45240 ELSE IF STAT$="D" GOTO 38000
45310 GOTO 45200
45400 GOSUB 17000:IF TYPE$<>"<" GOTO 45500
45420 GOTO 45300
45500 IF TYPE$<>">" GOTO 45600
45530 NEXT A:GOTO 45300
45600 IF F$(FL)=COMPARE$ GOTO 45230
45610 GOTO 45300
46000 REM ************************************************************
46001 REM *** X-tend Work To New Disk Function  Process: Prompt for new
46002 REM ***                                            data disk mount, then
46003 REM ***                                            read in MAXSIZE from
46004 REM ***                                            .DEF file and return
46005 REM ***                                            to caller
46006 REM ************************************************************
46010 CURRENT=-1:LOCATE 25,1:PRINT STRING$(79,32);:A$="Mount data disk in drive "+LEFT$(NA$,1)+", then press <C> to continue":LOCATE 25,1:PRINT A$;
46020 ROW=25:COLUMN=LEN(A$)+2:AX$="Cc":A1%=1:GOSUB 40130:IF AN$="" GOTO 46010
46100 IN=0:LOCATE 25,1:PRINT STRING$(79,32);:GOSUB 47000:GOTO 46000
47000 REM ************************************************************
47001 REM *** Initialize New Data Disk Function  Process: Write records to data
47002 REM ***                                             disk until error
47003 REM ***                                             occurs.  Error
47004 REM ***                                             routine will then
47005 REM ***                                             branch back to line
47006 REM ***                                             47500 where ".DEF"
47007 REM ***                                             file is written.
47008 REM ************************************************************
47010 CLOSE:CURRENT=-1:IN=1:LOCATE 25,1:PRINT STRING$(79,32);:A$="S)pecify number of records, or U)se all available disk space? ":LOCATE 25,1:PRINT A$;
47020 ROW=25:COLUMN=LEN(A$)+2:AX$="SsUu":A1%=1:GOSUB 40130:IF AN$="" GOTO 47020
47030 IF AN$="U" OR AN$="u" GOTO 47100 ELSE LOCATE 25,1:PRINT STRING$(79,32);:A$="How many data records?":LOCATE 25,1:PRINT A$;
47040 ROW=25:COLUMN=LEN(A$)+2:AX$="0123456789":A1%=6:GOSUB 40130:NU=VAL(AN$):IF AN$="" OR NU=0 GOTO 47030
47050 GOTO 47110
47060 LOCATE 25,1:PRINT STRING$(79,32);:LOCATE 25,1:A$="Enter volume name:":PRINT A$;:ROW=25:COLUMN=LEN(A$)+2:AX$=AQ$:A1%=25:GOSUB 40130:V$=AN$:IF AN$="" GOTO 47060
47100 NU=-1
47110 GOSUB 47060:OPEN "o",2,NA$+".DEF":PRINT#2,100000!,100000!:CLOSE
47120 OPEN "R",#1,NA$+".DAT",SIZE
47125 STAT1$="E":FOR Z=1 TO NF:F$(Z)=STRING$(80,32):NEXT Z:GOSUB 12000
47140 CT=1
47150 LOCATE 25,1:PRINT STRING$(79,32);
47160 A$="Stand by... Initializing record #":LOCATE 25,1:PRINT A$;
47200 LOCATE 25,LEN(A$)+1:PRINT CT;:PUT 1,CT
47210 CT=CT+1:IF NU=-1 GOTO 47200 ELSE NU=NU-1
47220 IF NU=0 GOTO 47500 ELSE GOTO 47200
47500 CLOSE:CT=CT-1:OPEN "O",#2,NA$+".DEF":PRINT#2,CT,0:CLOSE #2
47510 IN=0:LOCATE 25,1:PRINT STRING$(79,32);:RETURN
49000 REM ************************************************************
49001 REM *** BASIC Error Handler         Process: This is really only set
49002 REM ***                                      up to handle the DISK
49003 REM ***                                      SPACE full error when
49004 REM ***                                      initializing a new data
49005 REM ***                                      disk indicated by variable
49006 REM ***                                      IN = 1.  Otherwise ERROR
49007 REM ***                                      code is reported, files are
49008 REM ***                                      closed, and program ends.
49009 REM ************************************************************
49010 IF IN=0 GOTO 49100
49020 IF IN=1 AND ERR=61 THEN RESUME 47500
49030 IF IN=2 AND ERR=53 THEN RESUME 46100
49100 CLS:RESET:PRINT "Internal ERROR #";ERR;" in line #";ERL:PRINT"Consult BASIC manual appendix A for explanation.":END
50000 REM ************************************************************
50001 REM *** Program Title Display Function     Process: Used to display
50002 REM ***                                             program title and
50003 REM ***   Display idea credit to:                   author at beginning
50004 REM ***      John Vandergrift                       and end of program
50005 REM ***                                             execution.
50006 REM ************************************************************
50010 BEEP:CLS:A$=TI$:A1$="B":A2$="Y":A3$=AU$:C=10
50020 GOSUB 50060
50030 A$=STRING$(LEN(A$)," "):A1$=" ":A2$=" ":A3$=STRING$(LEN(A3$)," "):C=9
50040 GOSUB 50060
50050 FOR Z=1 TO 2000:NEXT Z:RETURN
50060 FOR I=1 TO C
50070 LOCATE I,40-LEN(A$)/2:PRINT A$;
50080 LOCATE 12,4*I:PRINT A1$;
50090 LOCATE 12,81-(4*I):PRINT A2$;
50100 LOCATE 24-I,41-(LEN(A3$)/2):PRINT A3$;
50110 NEXT I
50120 RETURN
60000 REM *** Do not remove lines 60000 through 60009!
60001 REM *** This program SKELETON.BAS is to be used with the Ultra-Mind
60002 REM *** intelligent database program generator.  It is copyright, (C),
60003 REM *** 1983, by The FreeSoft Company, P.O. Box 27608, St. Louis, MO
60004 REM *** 63146.  For copies of this and the other Ultra-Utility programs,
60005 REM *** send 2 double sided or 4 single sided diskettes and a postage
60006 REM *** paid self addressed return mailer to the address above.  Specify
60007 REM *** that you want LIBRARIES #1 and #2.  The Ultra-Utilities include
60008 REM *** Ultra-Zap, Ultra-Format, Ultra-File, Ultra-Optimize, and
60009 REM *** Ultra-Mind.  Lines 60000 through 60009 all be removed from all
60010 REM *** programs generated by Ultra-Mind.


1 REM *** U-MIND.BAS and SKELETON.BAS are copyrighted (C),1983 by The FreeSoft
2 REM *** Company, P.O. Box 27608, St. Louis, MO 63146
3 REM *** To get copies of the entire 5 volume set of Ultra-Utilties, send 2
4 REM *** double sided diskettes or 4 single sided diskettes to us at the above
5 REM *** address.  Be sure to include a postage-paid, self-addressed return
6 REM *** mailer and specify that you want LIBRARIES #1 and #2.
7 REM *** The Ultra-Utilities include Ultra-Zap, Ultra-Format, Ultra-File,
8 REM *** Ultra-Optimize, and Ultra-Mind.
9 REM *** AUTHOR: WAT BUCHANON, All Rights Reserved.
10 AQ$=" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890!@#$%^&*()_-=+}{[]`~':;?><|\,./":AX$=AQ$
40 DIM EL$(10),CL$(10):CLS:A$="The FreeSoft Company Presents:":A1$="Ultra-Mind":A2$="The Intelligent Data Base Generator":A3$=" Copyright, 1983, The FreeSoft Co."
50 COLOR 7,0:LOCATE 5,(40-LEN(A$)/2):PRINT A$:COLOR 15,0:LOCATE 7,(40-LEN(A1$)/2):PRINT A1$
60 A4$=STRING$(LEN(A3$)," ")
70 LOCATE 9,(40-LEN(A2$)/2):PRINT A2$:COLOR 0,7:LOCATE 13,(40-LEN(A3$)/2):PRINT A3$
80 LOCATE 12,(40-LEN(A3$)/2):PRINT A4$:LOCATE 14,(40-LEN(A3$)/2):PRINT A4$
90 LOCATE 1,1:COLOR 15,0:PRINT STRING$(79,205):LOCATE 24,1:PRINT STRING$(79,205);
100 COLOR 7,0:FOR Z=1 TO 2000:NEXT Z:CLS
110 PRINT"Do you wish to:":PRINT:PRINT"1) Define a database":PRINT"2) Generate a defined database":PRINT:PRINT:PRINT"Enter your choice (1 or 2)"
120 A$=INKEY$:IF A$<>"1" AND A$<>"2" GOTO 120
130 IF A$="2" GOTO 1510
140 CLS
150 PRINT "Enter the filename of your data base (DO NOT INCLUDE AN EXTENSION)"
170 PRINT:PRINT"Now enter a heading title that will be displayed on the screen:":INPUT TI$
180 PRINT:PRINT"Who is the author of this program:":INPUT AU$:PRINT
190 INPUT "What drive will the data diskette be in (A,B,etc.) ";DA$
200 NA$=DA$+":"+NA$
210 OPEN "O",#1,NA$+".atr":WRITE#1,AU$,NA$,TI$
220 ND=1:NF=1:CLS:LOCATE 24,1:PRINT STRING$(79,205);:GOTO 320
230 TY=0:LOCATE 24,1:PRINT STRING$(79,205);:LOCATE 25,1:PRINT STRING$(79,32);:LOCATE 25,1:PRINT "1) Enter new field.  2) Start new page  3) Enter non-field symbols.  4) Quit";
240 A$=INKEY$:IF A$="" OR INSTR("1234",A$)=0 GOTO 240
250 IF A$="1" THEN NF=NF+1:GOTO 320
260 IF A$="3" THEN TY=7:NF=NF+1:GOTO 340
270 IF A$="2" THEN ND=ND+1:CLS:GOTO 230
290 PRINT "Do you wish to go ahead and generate the database? (Y/N)"
300 A$=INKEY$:IF A$<>"Y" AND A$<>"y" AND A$<>"N" AND A$<>"n" GOTO 300
310 IF A$="Y" OR A$="y" GOTO 1520 ELSE CLS:PRINT"Program finished...":END
330 GOTO 350
340 LOCATE 25,1:PRINT STRING$(79,32);:LOCATE 25,1:PRINT "Symbols";
350 PRINT ", Page";ND;": Use arrow keys to position cursor then press <H>";
360 GOSUB 820
370 IF TY=7 THEN MR=R:MC=C:B$="":GOTO 410
380 A$=RIGHT$(STR$(NF),LEN(STR$(NF))-1):B$=A$+") "
400 GOTO 420
410 A$=" Now enter the symbols you wish to put at that position: ":A1%=79:GOTO 430
420 A$=" Now enter the field prompt you wish to use: ":A1%=50
450 IF (TY=7 AND M$="@") GOTO 2510 ELSE IF TY=7 THEN GOSUB 1050:GOTO 810
460 A$=" Now enter the type of field: 1) Numeric, ":LOCATE 24,40-LEN(A$)/2:PRINT A$;:LOCATE 25,1:PRINT "2) Alphanumeric, 3) Formatted Numeric, 4) Calculated, 5) Date, 6) Time";
470 A$=INKEY$:IF A$="" OR INSTR("123456",A$)=0 GOTO 470
490 IF A$="5" THEN AF$=DATE$:FL=10:TB=TB+FL
500 IF A$="6" THEN AF$=TIME$:FL=8:TB=TB+FL
510 LOCATE 24,1:PRINT STRING$(79,205);:LOCATE 25,1:PRINT STRING$(79,32);:LOCATE 25,1:PRINT "Use arrow keys to position cursor, then press <H>";
530 LOCATE 25,1:PRINT STRING$(79,32);:LOCATE 25,1
540 IF TY=1 OR TY=2 OR TY=4 THEN A$="How many characters long is this field? ":PRINT A$;:ROW=25:COLUMN=LEN(A$)+1:A1%=2:GOSUB 1320:FL=VAL(AN$):AF$=STRING$(FL,22)
550 IF TY=3 THEN A$="Enter your special format below.  Use \'s for input character positions:":LOCATE 24,1:PRINT A$;:ROW=25:COLUMN=1:A1%=80-FC:GOSUB 1320:AF$=AN$:LOCATE 24,1:PRINT STRING$(79,205);
560 IF TY=3 THEN FOR A=1 TO LEN(AF$):IF MID$(AF$,A,1)="\" THEN MID$(AF$,A,1)=CHR$(22)
580 IF FL=0 THEN LOCATE 25,1:PRINT STRING$(79,32);:LOCATE 25,1:PRINT "ERROR - Null fields not allowed. Use symbolic fields.  Press <C> to continue";:ELSE GOTO 600
630 IF TY=4 THEN LOCATE 25,1:A$="How many lines of calculations for this field? ":PRINT A$;:ROW=25:COLUMN=LEN(A$)+1:A1%=2:GOSUB 1320:CL=VAL(AN$):IF CL=0 GOTO 630 ELSE WRITE#1,CL
640 IF TY=4 THEN FOR A=1 TO CL:LOCATE 25,1:PRINT STRING$(79,32);:A$=" Enter calculation line #"+STR$(A)+" of"+STR$(CL)+" ":LOCATE 24,40-LEN(A$)/2:PRINT A$;:ROW=25:COLUMN=1:A1%=70:GOSUB 1320:CL$=AN$:WRITE#1,CL$:NEXT A
650 LOCATE 24,1:PRINT STRING$(79,205);:LOCATE 25,1:PRINT STRING$(79,32);
660 GOSUB 1160:IF TY=1 THEN LOCATE 25,1:PRINT STRING$(73,32);:LOCATE 25,1:A$="How many lines of edit checking for this field? ":PRINT A$;:ROW=25:COLUMN=LEN(A$)+1:A1%=2:GOSUB 1320:EL=VAL(AN$)
680 IF (TY=2 AND NF<>1) THEN LOCATE 25,1:PRINT STRING$(79,32);:LOCATE 25,1:A$="Null entry valid (Y/N)":PRINT A$;:ROW=25:COLUMN=LEN(A$)+2:A1%=1:GOSUB 1320:IF INSTR("YyNn",AN$)=0 GOTO 680 ELSE PRINT#1,AN$
690 IF TY=1 AND EL<>0 THEN FOR A=1 TO EL:A$=" Enter edit check line #"+STR$(A)+" of"+STR$(EL)+" ":LOCATE 24,40-(LEN(A$)/2):PRINT A$;:ROW=25:COLUMN=1:A1%=70:GOSUB 1320:EL$=AN$
700 IF TY=1 AND EL<>0 THEN GOSUB 1020:IF T=0 THEN WRITE#1,EL$:NEXT A:GOTO 730:ELSE LOCATE 25,1:PRINT STRING$(79,32);:LOCATE 25,1:PRINT "ERROR - illegal edit command! Press <C> to continue.";
720 IF TY=1 AND EL<>0 THEN A$=INKEY$:IF A$="c" OR A$="C" GOTO 660 ELSE GOTO 720
730 LOCATE 24,1:PRINT STRING$(79,205);:LOCATE 25,1:PRINT STRING$(79,32);
740 IF TY=1 OR TY=4 THEN LOCATE 25,1:A$="Do you wish to have a special format for printing the field (Y/N)? ":PRINT A$;:ROW=25:COLUMN=LEN(A$)+1:A1%=1:GOSUB 1320:SP$=AN$:IF SP$<>"Y" AND SP$<>"y" AND SP$<>"N" AND SP$<>"n" GOTO 740
760 IF (TY=1 OR TY=4) AND (SP$="Y" OR SP$="y") THEN A$="Enter your printing format below. Use #'s for char. positions":LOCATE 24,40-LEN(A$)/2:PRINT A$;:LOCATE 25,1:PRINT STRING$(79,32);:ROW=25:COLUMN=1:A1%=FL:GOSUB 1320:SF$=AN$
770 LOCATE 24,1:PRINT STRING$(79,205);:IF (TY=1 OR TY=4) AND (SP$="y" OR SP$="Y") THEN AC=0:FOR A=1 TO LEN(SF$):IF MID$(SF$,A,1)="#" THEN AC=AC+1
780 IF (TY=1 OR TY=4) AND (SP$="Y" OR SP$="y") THEN NEXT A:IF AC>0  THEN WRITE#1,SF$:GOTO 810
790 IF (TY=1 OR TY=4) AND (SP$="Y" OR SP$="y") THEN LOCATE 24,1:PRINT STRING$(79,205);:LOCATE 25,1:PRINT STRING$(79,32);:LOCATE 25,1:PRINT "ERROR - null print field! Press <C> to continue.";
800 IF (TY=1 OR TY=4) AND (SP$="y" OR SP$="Y") THEN A$=INKEY$:IF A$="c" OR A$="C" THEN LOCATE 25,1:PRINT STRING$(79,32);:GOTO 740:ELSE GOTO 800
810 GOTO 230
820 R=23:C=40
840 DEF SEG = &H40:A=PEEK(&H17):B= A OR 32:POKE &H17,B
860 A$=INKEY$:IF A$="" GOTO 860
870 IF INSTR ("48621793Hh",A$)=0 GOTO 860
890 IF A$="4" THEN AR=0:AC=-1:GOTO 970
900 IF A$="8" THEN AR=-1:AC=0:GOTO 970
910 IF A$="6" THEN AR=0:AC=1:GOTO 970
920 IF A$="7" THEN AR=-R+1:AC=-C+1:GOTO 970
930 IF A$="9" THEN AR=-R+1:AC=73-C:GOTO 970
940 IF A$="3" THEN AR=23-R:AC=73-C:GOTO 970
950 IF A$="1" THEN AR=23-R:AC=-C+1:GOTO 970
960 AR=1:AC=0
1000 IF HOLD=32 THEN RETURN ELSE LOCATE 25,1:PRINT STRING$(79,32);:LOCATE 25,1:PRINT "ERROR - You are overwriting other screen information!  Press <C> to continue";
1010 A$=INKEY$:IF A$="C" OR A$="c" THEN LOCATE 25,1:PRINT STRING$(79,32);:GOTO 820 ELSE GOTO 1010
1020 REM *** check edits for syntax
1030 A$=LEFT$(EL$,1):IF A$="<" OR A$=">" OR A$="=" THEN T=0 ELSE T=1
1050 IF LEFT$(M$,1)<>"@" GOTO 1140
1070 Q$=RIGHT$(M$,LEN(M$)-1):AZ=LEN(Q$)
1080 A$="":T$="":FOR Z=1 TO AZ
1090 K$=MID$(Q$,Z,1):IF K$="," THEN A9=VAL(T$):A$=A$+CHR$(A9):T$="":GOTO 1110
1100 T$=T$+K$
1110 NEXT Z:A9=VAL(T$):A$=A$+CHR$(A9):M$=""
1120 R$=LEFT$(A$,1):R=ASC(R$):A$=RIGHT$(A$,LEN(A$)-1)
1130 FOR A=1 TO R:M$=M$+A$:NEXT A
1170 LOCATE 24,1:PRINT STRING$(79,205);:LOCATE 25,1:A1$="Do you wish to restrict input characters (Y/N)? ":PRINT A1$;:ROW=25:COLUMN=LEN(A1$)+1:A1%=1:GOSUB 1320
1180 IF INSTR("YyNn",AN$)=0 GOTO 1170
1200 IF INSTR("Yy",AN$)=0 AND (TY=1 OR TY=3) THEN AI$="0123456789.-":RETURN
1210 LOCATE 24,1:PRINT STRING$(79,32);:LOCATE 25,1:PRINT STRING$(79,32);:LOCATE 24,1:A1$="Type X under character to restrict it: ":PRINT A1$;
1220 AI$="":AT$="0123456789+.-":GOSUB 1260:IF TY=1 OR TY=3 THEN LOCATE 24,1:PRINT STRING$(79,205);:LOCATE 25,1:PRINT STRING$(79,32);:RETURN
1240 AT$="abcdefghijklmnopqrstuvwxyz":GOSUB 1260
1250 AT$="!@#$%^&*()_=[]}{;:"'`~<>?,/\|":gosub 10100:LOCATE 24,1:PRINT STRING$(79,205);:LOCATE 25,1:PRINT STRING$(79,32);:return
1260 LOCATE 24,LEN(A1$)+1:PRINT AT$;:ROW=25:COLUMN=LEN(A1$)+1:A1%=LEN(AT$):AX$=" Xx":GOSUB 1320:AX$=AQ$:IF LEN(AN$)<>LEN(AT$) THEN AN$=AN$+STRING$(LEN(AT$)-LEN(AN$),32)
1270 FOR Z=1 TO LEN(AN$):IF MID$(AN$,Z,1)=" " THEN AI$=AI$+MID$(AT$,Z,1)
1290 REM _____________________________________________________________________
1300 REM * IN: ROW,COLUMN, A1%     OUT: AN$
1310 REM _____________________________________________________________________
1320 AN$="":A%=0:LOCATE ROW,COLUMN,0,1,20:PRINT STRING$(A1%,CHR$(22));
1330 IF A%=A1% THEN 1360 ELSE LOCATE ROW,COLUMN+A%,0,1,20:PRINT CHR$(22);
1350 ON INSTR(CHR$(8)+CHR$(13),A$) GOTO 1370,1390:GOTO 1330
1360 A$=INKEY$:IF A$="" THEN 1360 ELSE 1350
1380 A%=A%-1:IF A%<0 THEN A%=0:GOTO 1330:ELSE AN$=LEFT$(AN$,LEN(AN$)-1):GOTO 1330
1390 LOCATE ROW,COLUMN+A%,0,1,20:PRINT STRING$(A1%-A%," ");
1410 REM _____________________________________________________________________
1430 REM _____________________________________________________________________
1460 A$=INKEY$:IF A$=""THEN 1460 ELSE IF INSTR("1234567890",A$) THEN PRINT A$;:AN$=AN$+A$:GOTO 1450
1470 ON INSTR(CHR$(8)+CHR$(13),A$) GOTO 1440, 1500
1480 GOTO 1450
1490 A$=INKEY$:IF A$="" THEN 1490 ELSE 1470
1520 OPEN "I",#1,NA$+".HDR":INPUT #1,NF,ND,TB
1530 CLOSE:TB=TB+1
1540 OPEN "I",#2,NA$+".ATR":OPEN "O",#1,NA$+".BAS"
1550 LN=1:Q$=CHR$(34):RM$="REM "+STRING$(65,"*")
1580 LN=5:PRINT#1,LN;RM$
1590 LN=10:PRINT#1,LN;"SIZE=";TB;":ND=";ND;":TI$=";Q$;TI$;Q$;":NF=";NF;":AU$=";Q$;AU$;Q$;":na$=";Q$;NA$;Q$
1600 LN=20:PRINT#1,LN;"DIM F$(";NF;"),fr$(";NF;")"
1610 REM *****************************************************************
1620 PRINT "*** GENERATE BLOCKING ROUTINE                                 ***"
1630 REM *****************************************************************
1640 LN=12010:CT=1:PRINT#1,LN;"FIELD #1, 1 AS STAT$:LSET STAT$=STAT1$"
1650 FOR Z1=1 TO NF:V1=Z1:GOSUB 2330:IF TY=4 OR TY=7 GOTO 1710
1660 LN=LN+5:PX=CT:PRINT#1,LN;"field 1, ";
1670 IF PX>=255 THEN PRINT #1,"255 as n$, ";:PX=PX-255:GOTO 1670
1680 IF PX<>0 THEN PRINT#1,PX;" as n$, ";
1690 PRINT#1,FL;" as fr$(";Z1;"):lset fr$(";Z1;")=f$(";Z1;")"
1700 CT=CT+FL
1720 REM *****************************************************************
1730 PRINT "*** GENERATE UN-BLOCKING ROUTINE                              ***"
1740 REM *****************************************************************
1750 LN=17010:CT=1:PRINT#1,LN;"FIELD #1, 1 AS STAT$:STAT1$=STAT$"
1760 FOR Z1=1 TO NF:V1=Z1:GOSUB 2330:IF TY=4 OR TY=7 GOTO 1820
1770 LN=LN+5:PX=CT:PRINT#1,LN;"FIELD 1, ";
1780 IF PX>=255 THEN PRINT#1,"255 AS N$, ";:PX=PX-255:GOTO 1780
1790 IF PX<>0 THEN PRINT#1,PX;" AS N$, ";
1800 PRINT#1,FL;" AS FR$(";Z1;"):F$(";Z1;")=FR$(";Z1;")";:IF TY=1 THEN K=Z1:GOSUB 2310:PRINT#1,":";V$;"=VAL(F$(";Z1;"))" ELSE PRINT #1,""
1810 CT=CT+FL
1830 REM *****************************************************************
1840 PRINT "*** GENERATE DISPLAY FIELDS ROUTINE                           ***"
1850 REM *****************************************************************
1860 LN=7010:FOR Z1=1 TO NF:V1=Z1:GOSUB 2330:IF TY=4 OR TY=7 GOTO 1910
1870 LN=LN+5:PRINT#1,LN;"IF PAGE=";PG;" THEN LOCATE ";FR;",";FC;":";
1880 IF TY=1 AND (SP$="y" OR SP$="Y") THEN PRINT#1,"PRINT USING ";Q$;SF$;Q$;";";:K=Z1:GOSUB 2310:PRINT#1,V$:GOTO 1900:ELSE PRINT #1,"PRINT ";
1890 PRINT#1,"F$(";Z1;");"
1910 IF TY=7 GOTO 1900
1920 LN=LN+5:PRINT#1,LN;"IF PAGE<>";PG;" GOTO ";LN+((CL+2)*5)
1940 LN=LN+5:PRINT#1,LN;"F$(";Z1;")=STR$(F";:Z1$=STR$(Z1):Z1$=RIGHT$(Z1$,LEN(Z1$)-1):PRINT#1,Z1$;"#):LOCATE ";FR;",";FC;":PRINT ";:IF SP$="y" OR SP$="Y" THEN PRINT#1,"USING ";Q$;SF$;Q$;";
1950 K=Z1:GOSUB 2310:PRINT#1,V$
1960 GOTO 1900
1970 REM ****************************************************************
1980 PRINT "*** GENERATE SCREEN INFO DISPLAY ROUTINE                      ***"
1990 REM ****************************************************************
2000 LN=2013:PRINT#1,LN;"LOCATE 24,1:PRINT STRING$(79,61);":LN=2010:FOR Z2=1 TO NF:V1=Z2:GOSUB 2330
2010 LN=LN+5:PRINT#1,LN;"IF PAGE=";PG;" THEN LOCATE ";MR;",";MC;":PRINT ";Q$;M$;Q$;";"
2020 NEXT Z2:CLOSE #2:OPEN "I",2,NA$+".ATR":INPUT#2,AU$,NA$,TI$:LN=LN+5
2040 X=2010:PRINT#1,X;"IF FL<>0 GOTO ";LN
2060 CLOSE #2:OPEN "I",2,NA$+".ATR":INPUT#2,AU$,NA$,TI$
2070 REM ****************************************************************
2090 REM ****************************************************************
2100 LN=22010:FOR Z2=1 TO NF:V1=Z2:GOSUB 2330
2120 IF TY=5 THEN PRINT#1,LN;"IF Fl=";Z2;" THEN F$(";Z2;")=DATE$:LOCATE ";FR;",";FC;":PRINT F$(";Z2;"):RETURN":GOTO 2190
2130 IF TY=6 THEN PRINT#1,LN;"IF Fl=";Z2;" THEN F$(";Z2;")=TIME$:LOCATE ";FR;",";FC;":PRINT F$(";Z2;"):RETURN":GOTO 2190
2140 IF TY=2 THEN PRINT#1,LN;"IF Fl=";Z2" THEN ROW=";FR;":COLUMN=";FC;":A1%=";FL;":AX$=";Q$;AI$;Q$;":GOSUB 40130:";:IF Z2=1 OR (Z2<>1 AND NE$="n" OR NE$="N") THEN PRINT#1,"IF AN$="Q$;Q$;" GOTO ";LN;" ELSE ";
2150 IF TY=2 THEN PRINT#1,"F$(";Z2;")=AN$:RETURN":GOTO 2190
2160 IF TY=3 THEN PRINT#1,LN;"IF Fl=";Z2;" THEN ROW=";FR;":COLUMN=";FC;":AF$=";Q$;AF$;Q$;":AX$=";Q$;AI$;Q$;":GOSUB 40150:";:IF Z1=1 THEN PRINT#1,"IF AN$=";Q$;Q$;" GOTO ";LN;" ELSE ";
2170 IF TY=3 THEN PRINT#1,"F$(";Z2;")=AN$:RETURN":GOTO 2190
2180 IF TY=1 GOTO 2200
2200 SV=LN:PRINT#1,LN;"IF Fl<>";Z2;" GOTO ";LN+((EL+2)*5);" ELSE ROW=";FR;":COLUMN=";FC;":A1%=";FL;":AX$=";Q$;AI$;Q$;":GOSUB 40130:";:IF Z2=1 THEN PRINT#1,"IF AN$=";Q$;Q$;" GOTO ";LN;" ELSE ";
2210 PRINT#1,"F$(";Z2;")=AN$:";:P$=STR$(Z2):P1$=RIGHT$(P$,LEN(P$)-1)+"#":PRINT#1,"F";P1$;"=VAL(AN$)"
2220 IF EL=0 GOTO 2240 ELSE FOR Z3=1 TO EL:LN=LN+5:PRINT#1,LN;"IF F";P1$;EL$(Z3);"THEN ER$=";Q$;EL$(Z3);Q$;":ER=4:GOSUB 36000:GOTO ";SV
2230 NEXT Z3
2240 LN=LN+5:PRINT#1,LN;"RETURN":GOTO 2190
2250 CLOSE:OPEN "o",1,NA$+".bat":PRINT#1,"BASIC ";NA$+".bas";"/F:2/S:";TB:CLOSE
2260 PRINT:PRINT "Now Merging Skeleton Program...":CL$=STRING$(255,32)
2270 OPEN "a",1,NA$+".bas":OPEN "i",2,"skeleton.bas"
2280 LINE INPUT#2,A$:PRINT ".";:PRINT#1,A$
2290 IF EOF(2) GOTO 2300 ELSE GOTO 2280
2300 RESET:CLS:PRINT "Program ";NA$+".BAS";" has been generated!":END
2310 V$=STR$(K):V$=RIGHT$(V$,LEN(V$)-1):V$="F"+V$+"#":RETURN
2350 IF TY<>1 AND TY<>2 GOTO 2400
2380 INPUT#2,SP$:IF SP$="y" OR SP$="Y" THEN INPUT#2,SF$
2400 IF TY<>3 GOTO 2430
2430 IF TY<>4 GOTO 2460
2460 IF TY<>5 AND TY<>6 GOTO 2480
2490 IF V1<>1 THEN INPUT#2,NE$
2510 LOCATE 25,1:PRINT"<Help>: Enter key-> ";
2520 Z$=INKEY$:IF Z$="" GOTO 2520
2530 PRINT Z$;" is ASCII code";ASC(Z$);"... Press <C> to cont.";
2540 Z$=INKEY$:IF Z$<>"C" AND Z$<>"c" GOTO 2540
2550 GOTO 410



                :                                             :
                : Supplement To Ultra-Utilities Documentation :
                :                                             :
                :           >>>>>> Ultra-Mind <<<<<<          :
                :                                             :
                :  The Intelligent Database Program Generator :
                :                                             :

                  RELEASE 1.0, First Release, December, 1983
                             Author: Wat Buchanon

          Ultra-Mind program and documentation Copyright (C), 1983, The
          FreeSoft Company, P.O. Box 27608, St. Louis, MO 63146.  All Rights
          Reserved.  Please see Ultra-Utilities documentation for warranty and
          duplication policy.
                               Table Of Contents

          Defining And Generating Your Database...............UM-2
          How To Use The Generated Program....................UM-8
          Appendix A: Format Of Ultra-Mind Disk Files.........UM-11
          Appendix B: Wish List...............................UM-13
          Appendix C: The Ultra-Utilities.....................UM-14
          Appendix D: Limited License For Ultra-Mind..........UM-15
          UM-1)                   Introduction
          At FreeSoft, we do quite a lot of database work, both for ourselves 
          and for clients.  After writing about the seven millionth database 
          manager, we came to a startling conclusion: very little was actually 
          changing from program to program.  We admittedly are experts when it 
          comes to reinventing the wheel, but this time a thought struck us, 
          "Why not write a database program generator?" (TA-DA! Sound of 
          trumpets...).  Well, that was several years ago, and Ultra-Mind is 
          the end result.  Basically what it does is allow you to set up your 
          unique database needs, and then actually writes a dedicated database 
          program in BASIC while you watch.
          What we found was that we were doing in a few minutes what used to 
          take hours or days.  Here's a brief outline of Ultra-Mind's 
          capabilities and features:
          1) This program allows you to set up a customized data entry system 
             and then writes a dedicated BASIC database manager program.
          2) The data entry can be divided into multiple screens, called 
          3) Several different types of input fields are supported: Numeric,    
             Alphanumeric, Formatted Numeric, Calculated, Automatic Date, and   
             Automatic Time.  In addition, the user can specify any keys that   
             are restricted from entry for each individual field (No Z's 
             allowed, for instance).
          4) Non-field symbols, such as titles or borders, can be placed any-   
             where on the data entry screens for a truly professional 
          5) Generated program is documented with remarks for easy 
          6) Sophisticated hashing algorithm nullifies BASIC's slow execution.  
             Typical record access (no matter how many records in the system)   
             when the key field is known is under 1/2 second.
          7) Knowledge of BASIC, data-file input/output routines, or other      
             special functions is not required.  A small amount of BASIC 
             formula format is helpful for using calculation fields.
          8) All generated programs can be compiled for added speed under the   
             Search and List functions.
          9) Number of fields and total field characters dependent only on 
             available memory (total field characters per record must be less   
             than 65,536 characters not counting program size).

          We hope you'll enjoy this package and will choose to support The 
          FreeSoft Company in our endeavor to bring you the most interesting 
          software at the best price.  We place this product in your hands at 
          no cost in order for you to truly judge its appropriatness for your 
          UM-2)           Defining And Generating Your Database

          Before executing the Ultra-Mind program generator, you should insure 
          that the following programs are on the diskette in your logged 
          (default) disk drive:
          1) Ultra-Mind program generator (U-MIND.BAS)
          2) Ultra-Mind skeleton program (SKELETON.BAS)
          3) BASIC programming language  (BASIC.COM or BASICA.COM)

          From the DOS prompt, type: BASIC U-MIND
          and the program should load and execute after a few seconds.  You 
          will first be presented with the question:
          Do you wish to:
          1) Define a database
          2) Generate an already defined database
          You should reply by pressing the '1' key (don't press <ENTER> after 
          this). The program will ask you for a filename for the resulting 
          program (8 characters, first character alphabetic).  DO NOT add an 
          extension (a period followed by 1-3 characters) to this filename. The 
          program will now ask you for the title of the program and the 
          author's name (yours!). Finally, you'll be asked which disk drive 
          will later be used to hold the data file.  You should have a disk 
          with plenty of room in this drive, as the generated program itself,
          as well as several other information files will be sent to this drive
          while Ultra-Mind is working.         
            You are now presented with the screen layout display. This display 
          is used to tell Ultra-Mind the information you wish to have displayed
          in your database program data entry screens, as well as to define the
          type of input fields.
          The bottom of the screen is used as a message area in both the 
          program generator and in your generated program.  Therefore, the top 
          23 lines of the screen are reserved for your information.
          First, a little background on database files.  A database file
          consists of a group of individual entries called "records".  A record
          might be a recipe, information on an employee, or an address book
          listing.  Each record is further subdivided into groups of 
          information called "fields".  In an employee record, one field might 
          contain the date the employee was hired, and another might have his 
          zip code.  One of the fields in each record is predefined as the "key 
          field".  This is the field that best identifies each record, and will 
          be used to retrieve the record from the file.  If a file contained 
          records of inventory parts, you might designate the inventory number 
          as the key field.  In an address list, you might use the person's 
          last name as a key field.
          Why the last name instead of the full name?  Ultra-Mind works best in 
          applications where you know the key field.  It's easy to forget 
          whether you entered a person as George Smith or W. G. Smith, so the 
          last name system would work best.  If you're not sure of the key 
          field exactly, there is a mechanism for still finding the record, but 
          it is much slower.
          O.K., back to the program.  At the bottom of the screen, you should 
          see the message:
          <Key Field>, Page 1: Use arrow keys to position cursor, then press 
          There are three parts to a field, it's number (the key field is 
          always field number 1), the field prompt (that tells you what to 
          enter), and the input field area itself.  Directly above the message 
          area in the center you should see a diamond character.  This is 
          Ultra-Mind's "cursor", and is what you will move around to point to 
          different areas of the screen.  Practice moving the cursor around 
          with the arrow keys (or the number keys 8=up, 2=down, 6=right, and 
          4=left).  Notice that if you press the Home key (or 7 key), the 
          cursor jumps to the upper left hand corner of the screen.  The PgUp 
          (or 9) key moves the cursor to the upper right, the PgDn (or 3) moves 
          to the lower right, and the End (or 1) key moves the cursor to the 
          lower left corner.  Select a place that will be appropriate for the 
          key field and press the 'H' key.  Notice that the characters "1)" 
          appear where the cursor used to be.  That's the field number that 
          will make it easy for you to later tell the generated program which 
          field you want to update or search for.
          At the bottom of the screen, a new message appears telling you to 
          enter the field prompt you wish to use.  Type in a descriptive 
          message that will prompt the user to type in the correct information 
          for that field (like NAME: or PART NUMBER:, for instance).  You have 
          up to 50 characters for the field prompt, and you can leave it blank 
          should you wish.  The program will again ask you to position the 
          cursor and press the <H> key.  Don't worry about moving the cursor 
          over other characters on the screen, it's doesn't destroy what it 
          moves over.  Don't allow your information to overlap other fields, 
          though, or you will get an error message.
          When you've positioned the cursor and pressed the H key, you'll see 
          your field prompt appear at that location.  Now, we must tell the 
          computer what type of field this is.  The different field types each 
          ask different questions, so we'll cover them one at a time.
          This type of field is composed only of numeric symbols, that is 0-9, 
          the plus and minus signs and the decimal point (period).  Although it
          is kept as a string of characters in the disk file, it is converted 
          into a number when displayed by the generated program.  Only numeric 
          fields can be used by calculation fields (described below).
          When you select this type of field, you will be asked to type in the
          length of the field.  This is the number of characters that the 
          largest possible number that can be entered will have.  FOR ALL 
          GREATER THAN 79 CHARACTERS LONG TOTAL.  Because the number of fields 
          is limited only by your computer's memory (and believe us, you have 
          plenty of room), this really isn't a problem.  Just split up extra 
          long fields into smaller ones.  You will then be asked to locate the
          cursor and press <H>.  When you have done so, the input field appears
          as a series of small boxes.  This field now looks exactly as it will
          on the data entry screen of the generated program.
          There is still more information the computer needs about this field.  
          It next asks if you wish to restrict input characters.  If you type 
          "N", any numeric character can be typed into the field.  If you 
          answer "Y", you will be shown a list of all numeric characters and 
          asked to type an "X" under the characters you wish to restrict.  Type 
          a space under those you wish to allow.  Those characters that you 
          restrict will be dead on the keyboard during entry of this field.
          Now the program asks you how many lines of edit checking you wish to 
          have.  If you don't wish to check the field for entry errors, just 
          type a 0.  Otherwise, for each edit check you'll be asked to enter an 
          edit string.  The format for an edit string is:
          Where TESTSYMBOL is either a > (greater than), < (less than), or = 
          (equal to), and VALUE is a number.  Edit checks should be entered in 
          the negative.  In otherwords the edit check:
          < 52 
          will tell the operator they've made an error only if the number they 
          enter into this field is less than 52. 
          Finally, you'll be asked if you wish to use a special printing format 
          when this field is later displayed.  If you do, just type the format 
          as you would the format string in a BASIC PRINT USING statement 
          (without surrounding quotes).  You should consult your BASIC manual 
          on the PRINT USING statement if you're unsure of this.  As an 
          example, if a field contained the number 342342.345 and your special 
          printing format was ###,###.## the number would be displayed as 
          342,342.34 when the record is displayed later.        
          This field is used for entries that are either all alphabetic or 
          mixed letters, symbols, and numbers.  Even if a number is entered 
          into an alphanumeric field, it will be considered only a string of 
          characters, and calculation fields cannot use it.
          This type of field needs the same type of information as numeric 
          fields in the way of field position, field length, and input 
          character restriction, except that it does not ask for edit checks or 
          special printing formats.  There is only one type of edit check for 
          alphanumeric fields and that is for a null entry (<ENTER> pressed 
          without entering any characters).  Null entries can be allowed in any 
          field except the key field.

          This is a special type of field that allows you to enter numbers into 
          a "template".  For instance, the parentheses, space,  and hyphen in  
          the following number (323) 343-3423 identify it as a phone number.  
          Although formatted numeric fields are handy for entering numeric data 
          into a template, the resulting number is treated as a string of 
          characters, including the special symbols used in the template, and 
          cannot be used by calculation fields.  After locating the cursor 
          where you wish the input template to appear and pressing H, the 
          computer will ask you to enter your special format.  Any special keys 
          can go into the template except the backslash (\).  The backslash is 
          used to show where the input numbers will be located.  If we wanted a 
          phone number field like the one above, we would enter our format as:
          (\\\) \\\-\\\\
          When it's displayed on the screen, the backslashes will be converted 
          to the familiar small input boxes.  Pay attention to your format, as 
          its a bit easy to get confused.  For example, the format:
          could actually be used for entry of a date.  Look closely and see how 
          it would displayed.  (Hint: 01/14/84).
          This type of field is not entered by the user at all.  It is 
          calculated from values in other numeric fields.  It is not displayed 
          at all during the data entry process, only later when the record is 
          retrieved from the file and displayed.  It's helpful to know BASIC's 
          format for specifying formulas when using this type of field.  You 
          need to pay attention to what the field numbers are of the numeric 
          fields to be used and the resulting calculation field.  Here's an 
          example.  If we were working on field 5 and we specified a 
          calculation field, the computer would ask us how many calculation 
          lines we wished to have.  For this example we'll just do something 
          simple in a single calculation line.  To specify numeric or 
          calculation fields in a calculation line, use the symbols F# followed 
          by the field number in parentheses.  O.K., let's add the values in 
          field 2 and field 4 and display that in our calculation field (field 
          5, remember?).  Here's how our calculation line would look:
          You can do all kinds of tricky things with calculation fields, and 
          it's easy to get yourself in trouble with them, so practice is in 
          order before using them.  If you need to store temporary values in a 
          variable, use the variables U1# through U100#.
          You can also specify a special printing format for this field, just 
          as you can for numeric fields.
          These field types are also done automatically, but in the data entry 
          stage.  It permanently stores the date or time in the field at the 
          moment of data entry.  It's useful for fields such as "Last Updated 
          ON: 03-15-1983".  Just use the U>pdate function on these fields each 
          time you update a record.
          Each time you finish entering a field, you are presented with a list 
          of choices:
          1) Enter new field, 2) Start new page, 3) Enter non-field symbols, 4) 
          Select "Enter new field" to continue adding fields to that page.  
          Whoops!  What's a page?  Well, that's a special feature of Ultra-Mind 
          that keeps your screens from getting cluttered.  You can have as many 
          display screens (called "pages") as you wish.  When you select "Start 
          new page" the screen layout area is erased and you continue with a 
          fresh slate.
          The "Enter non-field symbols" option is used to "prettify" your 
          screen layouts with titles, borders, etc.  When you select this 
          option, you will again be asked to locate the cursor where you wish 
          to place the symbols.  Then you will asked to enter the symbols you 
          wish to place there.  There are two different ways to specify the
          1) Just type them in from the keyboard.  (Note: your string cannot    
             begin with an "@" symbol).  
          2) Using a special syntax.  The syntax is:
             The @ symbol in the first position tells the computer that the     
             special syntax follows.  The REPEAT is a numeric value that tells 
             how many times to repeat the following symbols.  The ASCIICODE's 
             are the ASCII values of the symbols you with to display.  
             Confusing?  It's easier than it sounds.  Let's look at a couple of 
             would print a string of 79 equal signs (ASCII code 61).
             would print the sequence () ten times for a total length of 20 
             characters.  It would look like this:
             The reason for using this syntax is so you can draw vertical lines 
             of characters on the screen.  Try this sequence:
             It should have drawn a vertical line of 10 equal signs.  The 
             special codes 31 and 29 are used to move the cursor down a row and 
             backspace one character after each equal sign is printed.  The 
             special control codes are:
                    28 - Move right one character
                    29 - Move left one character
                    30 - Move up one row
                    31 - Move down one row
             Please note that because of Microsoft BASIC peculiarities, you 
             won't be able to print a vertical line of more than 13 characters 
             at one time (all sorts of strange things happen).  To get around 
             this anomaly, just print a string of 13 vertical characters and 
             then print a string of 10 more just beneath it for a line that 
             will stretch from top to bottom of the screen.  Experimentation is 
             in order to get the most out of this feature.
          If you're like us and don't happen to like digging through the BASIC 
          manual for the chart of ASCII codes, you might appreciate this 
          feature:  When asked to enter the symbols, just type the @ symbol 
          alone.  You will now enter the <Help> mode.  To find out a 
          character's ASCII code, just type it on the keyboard.  Nifty, eh?
          One last caveat, the non-field symbols are not checked very closely 
          for overlapping other screen info, so caution is the word.  Wrap 
          around is allowed on the horizontal only.
          When you're all done entering your screen displays, the fun part 
          starts.  Just enter the selection "Quit" and the program will ask 
          you if you wish to go ahead and generate the database.  If you don't, 
          you can always generate it later by selecting the "Generate an 
          already defined database" function when first executing this program.
          As the program is being written, just sit back and appreciate the 
          number of hours it would have taken you to do this by hand.  All in
          all, program generation should take only a few minutes.
          During the definition and generation process, a number of important 
          files are created.  The extensions of the programs tell what their 
          purpose are.  Let's assume your program is called TEST.  The files 
          TEST.ATR and TEST.HDR contain information that is used to generate 
          the program.  These are both explained in Appendix A.  It's not 
          necessary to keep these files on your program disk once the program 
          is generated.  In the generation process, two more files are created: 
          TEST.BAS is your database program, and TEST.BAT is a DOS batch file 
          used to execute the program.  YOU SHOULD ALWAYS USE THE BATCH FILE TO 
          START YOUR PROGRAM since it sets important record size pointers.  If 
          you choose to compile the program, you can discard the batch file.
          Otherwise, to execute your database program, you should exit to DOS, 
          make sure a copy of BASIC is on your program diskette, and type the 
          word TEST at a DOS prompt.
          The first time this program is loaded will be very time consuming.  
          If you used the DOS TYPE command to look at the program, you would 
          see that it is in ASCII format with line numbers out of sequence.
          It's a good idea once the program is loaded to break out by pressing 
          the BREAK key while holding down the CTRL key, and save the program 
          in compressed format using the BASIC command SAVE "TEST.BAS".  The 
          program can be restarted then by entering the command RUN.
          1) Always have a couple of disks with plenty of room and copies of 
             BASIC on them on hand just in case.
          2) There's no way to go back if you make an error during definition, 
             so move slowly and have some sense of direction.  Freestyle coding 
             can be fast, but you're better off at least having a rough sketch 
             of what you'd like to end up with before starting.  This goes 
             double if you intend to use edit lines, special printing formats,  
             or calculation fields.
          3) Since the method used to make copies of screen information on the 
             printer is by pressing the PrtSc key while holding down the SHIFT 
             key, you'll want to be careful about using non-printable 
             characters for non-field symbols or in field prompts.  They can    
             cause some printers to do all sorts of wild things.
          UM-8)              How To Use The Generated Program
          Once the program is loaded as above described, you can remove the 
          program diskette.  After a brief title display, you'll be instructed 
          to mount your data disk in the drive specified during the generation 
          process, and press the "C" key.  All data disks used by Ultra-Mind 
          programs must be first initialized with special information.  When 
          you press the "C" key, the program will look for and load in this 
          information if it exists.  Otherwise, it will automatically begin 
          the initialization process.  You will be asked if the data file 
          should use all available disk space, or if you'd like to specify the 
          maximum number of records on that diskette.  After getting your 
          choice, initialization will begin.  Depending on the number of 
          records that must be initialized, this can take a few minutes or so.
          When choosing the size of your data file, keep this in mind: this 
          program will work most efficiently when there is lots of room on the 
          disk.  Even though you know your particular program will never have 
          more than 200 records, go ahead and use all available space.  The 
          "Specify number of records" option is mainly included for testing
          purposes.  Diskettes are cheap, your time isn't.
          You'll also be asked to give the data diskette a "volume label".  
          Just type in a word or two (Like Disk #1), and record this on the 
          diskette's label.  It just identifies the diskette to the system.
          The volume label really serves no function in this program.  However, 
          we envisioned it for our report generator program (forthcoming) so 
          that you could extend your data file over several diskettes, yet have 
          them all act as one big file for reports.  If you already know that 
          your file will be too big to put on one data diskette, you might use 
          this to divide your file (two disks, labeled A-L and M-Z might be an 
          example for a name list file).
          Once this data diskette is loaded into the program, it is important 
          that you DO NOT REMOVE THE DATA DISKETTE before doing either of two 
          1) Choose the "X-tend Work To New Data Diskette" function.
          2) Choose the "Quit and return to BASIC" function.
          Removing or swapping diskettes without doing either of these will at 
          best confuse the program into not knowing where the hell your data 
          is and at worst absolutely destroying your data files (ouch).

          Data disk in place, initialized, and special information loaded?  
          Good, now you're in the MAIN MENU area of your program.  In the 
          middle of the screen are your current list of choices, which we'll 
          cover in a moment, and at the top is some important information about 
          your data diskette and the current status of the program.
          The top of the screen lists the number of initialized records as well 
          as the number of records you have already entered.  It also displays 
          the volume label name of the current data diskette.  At the top left 
          of the screen is a message marked "Current Record".  This is used for 
          two things, first to let you know that a record has been retrieved 
          using the "Get A Record" function before updating or deleting it, or 
          to allow you to continue a "Search For And List Records" function 
          from a certain point after aborting a search.  If no record has been 
          recently retrieved with the "Get A Record" function, the current 
          record will be NONE.  Otherwise, it will be a number between 1 and 
          the number of records initialized on that data diskette.
          Let's go through the commands on the main menu screen:
          GET A RECORD
          This simply retrieves an entered record and displays it on the 
          screen.  It will prompt you for the key field of your desired record 
          and then will search for it.  Remember to use the correct case to 
          enter the key field, as this program views lowercase and uppercase 
          letters differently.  JOE SMITH and joe smith and Joe Smith are each 
          considered different records.  When the record is displayed, you'll 
          be asked "Is This It (Y/N)?"  This allows you to find the correct 
          record when two or more records have identical key fields.  If you 
          just can't find a record that you know should be in there, use the 
          "Search For And List Records" to scan through the data file and note 
          the correct key field.
          When the correct record is displayed, you'll see a short menu at the 
          bottom of the screen.  The Update, Delete, and Add functions are 
          described below.  The Menu function takes you back to the main menu 
          page, and the Switch Page function let's you look at the various 
          pages of the record, if there are more than one.
          This function is used to list all active (and deleted if you wish) 
          records in the data file, or to select records on the contents of one 
          of the fields.
          You will first be asked to enter the record # to start the search or 
          press <ENTER> to start at current record.  If you had just completed 
          a partial search and want to continue from the point you left off, 
          just press the <ENTER> key.  Otherwise, enter the record number you 
          wish to start the listing with (the first record in a datafile is 
          record #1).  If you press <ENTER> and there is no current record in 
          memory, the search will begin at record #1.  Except for this 
          function, we don't make much use of record numbers with this system.
          Next, you will be asked whether you wish to display records that have 
          been deleted.  Records in a data file exist in one of three states: 
          Active (meaning it contains a valid record), Deleted (meaning it 
          contains a record marked as deleted), and Empty (meaning it has not 
          yet ever contained a record).  Accidentally deleted records can be 
          restored to active status by using this function unless they have 
          been overwritten by recently added records.
          The next prompt is whether you wish to select records for display by 
          the contents of one it's fields.  If you don't, you will see every 
          record on file.
          If you do, you'll be asked which field you wish to test.  Then, 
          you'll be asked to enter a test string.  The three types of tests 
          that can be made on a field are:
          >STRING  (field contains "STRING" somewhere in it)
          <STRING  (field begins with "STRING")
          =STRING  (field contains "STRING" exactly and only)
          Once again, lowercase is considered different than uppercase.  For 
          our purposes here at FreeSoft, we don't use lowercase at all for 
          field information and it makes life much easier.
          If a match is found, you have the choice of either continuing the 
          search or aborting it.  If you abort, operation continues just as if 
          the record were retrieved with the "Get A Record" function.
          ADD A RECORD
          This function is used to add records to the data file.  It is pretty 
          much a straight ahead entry procedure.  After all fields have been 
          entered, you can proofread the current page and either abort the add 
          or go ahead and save the record on disk.
          This function is used to mark records as "deleted" status.  Deleted 
          records cannot be retrieved by a "Get A Record" function and can only 
          be viewed by the "Search For And List Records" function.  Deleted 
          records can be overwritten by newly added records as the space is 
          Any of a field's records, including the key field, can be modified
          using this function.  Like the "Delete Current Record" function, the
          record must first be retrieved using the "Get A Record Function". 
          You may wish to review the record and note the field numbers you 
          want to modify before selecting the "Update Current Record" 
          function, because the prior contents of a field are erased as soon 
          as you specify that you wish to modify that field.
          This function is used to close the data file on one data diskette and 
          load the special information from a new one.  The new disk must be 
          already initialized or initialization procedures will begin 
          This is used to perform the initialization procedures on a data 
          diskette so that it can be used to hold your data file.  THIS DOES 
          NOT LOAD IN THE SPECIAL INFORMATION!  Always verify that the volume 
          label specified in the MAIN MENU display corresponds the data 
          diskette mounted in the drive before attempting to do any work with 
          This is the only approved way of ending the program.  Ending the 
          program by any other means could possibly lead to a destroyed data 
          Well, that about does it.  Chances are good that you'll find many 
          more undocumented features (hopefully not bugs), that we'll need to 
          include in the next revision of this manual.  We always appreciate 
          your comments and suggestions.  Keep those cards and letters coming 
          (we always wanted to say that).
          Chances are, you're going to want to do some rather exciting and 
          unusual things with this package.  To aid you in your endeaver, 
          here's a description of the data files used by these programs.
          In the following examples, we use the filespec TEST for the program 
          NF  - Number of defined fields
          ND  - Number of defined display pages
          TB  - Total number of field characters - 1 (one byte variable         
                STAT$ is added to beginning of each record to hold         
                record status: A=Active, D=Deleted, E=Empty
          AU$ - Author's name
          NA$ - Program's filespec (including drive but without extension)
          TI$ - Program title
             For each field defined by NF in TEST.HDR:
               PG - Page number
               MR - Field prompt row
               MC - Field prompt column
               M$ - Field prompt string
               TY - Field type (1=Numeric, 2=Alphanumeric, 3=Formatted numeric, 
                    4=Calculation, 5=Date, 6=Time, 7=Non-field symbols)
                   If TY=1
                   FR  - Field row
                   FC  - Field column
                   FL  - Field length
                   AI$ - String of acceptable input characters
                   EL  - Number of edit lines
                        For each EL: EL$ - Edit line
                   SP$ - Special printing format (Y or N)
                        If SP$="Y": SF$ - special printing format string
                   If TY=2
                   FR  - Field row
                   FC  - Field column
                   FL  - Field length
                   AI$ - String of acceptable input characters
                      If not key field:  AI$ - Null entry valid (Y or N)
                   If TY=3
                   FR  - Field row
                   FC  - Field column
                   FL  - Field length
                   AF$ - Input format string
                   AI$ - String of acceptable input characters
                   If TY=4
                   FR  - Field row
                   FC  - Field column
                   CL  - Number of calculation lines
                       For each CL: CL$ - Calculation line string
                   SP$ - Special printing format (Y or N)
                       If SP$="Y": SF$ - Special printing format string
                   If TY=5 or TY=6
                   FR - Field row
                   FC - Field column
                   FL - Field length
                   If TY=7
                   No further variables
          V$ - Volume label string of data diskette
          MAXSIZE - Number of initialized records on data diskette
          GOOD    - Number of entered records on data diskette
          The data file is a variable length random file than varies with the 
          number of fields, length of fields, etc.  Study the blocking and un-  
          blocking procedures in your generated program to see the format of 
          your data file.
          This package uses a hashing routing for placing and retrieveing data 
          records.  Basically, what happens is that your key field is converted 
          to a number between 1 and the number of initialized records on your 
          data diskette.  This becomes the record number for the record.  If a 
          record is already in that location, the file is scanned sequentially 
          from that record until an empty or deleted record space is found.  
          The hashing algorythm we're using was developed and placed in the 
          public domain by Bruce L. Tonkin and we're indebted to him for its 
            To be effective, the hashing algorythm must be reasonably "random" 
          to insure that records will spread out through the available space 
          instead of clumping together.  This is what gives this package such 
          excellent retrieval speed under typical circumstances.
          UM-13)                  APPENDIX B: WISH LIST
             For many purposes, this package will be sufficient "off the 
          shelf".  However, we encourage you all to do what you do best: take a 
          skeleton package and refine it to something really phenomenal.  
          Here's our wish list for Ultra-Mind:
          1) Better documentation:  O.K., we admit that this isn't the best in 
             the world, but it's all in there if you look close enough.  This 
             manual definitely needs a re-write.  We'll take responsibility for 
             this and offer the fact that we wanted to get the darned thing out 
             as our only excuse.
          2) Sample definition (.HDR & .ATR) files: This is the best way for    
             folks to learn how to get the fanciest use out this package.  If   
             you develope a snazzy file for keeping track of your video tape    
             collection or christmas card list, why not share it with all of    
             us.  The definition files are rather small, so it's not necessary  
             to distribute the package in generated form.  We'll give this      
             responsibility to y'all.
          3) Report generator program:  We're working on this one and it should 
             be ready in the first quarter of 1984.
          4) Better UPDATE function:  We sorely need an update function that 
             uses the INS and DEL keys like an editor instead of wiping out the 
             field to be replaced.  Any of you hot shots care to take this on?
          5) Better lineprinter support: A small assembly language program that 
             would print the screen and turn all non-printable characters into  
             periods would be great.  BASIC routines are just too slow.  We 
             give this one to you also.
          6) Definition file editor:  Let's make it easy to take a definition   
             file and either edit, delete, or add field information.  This 
             would be great for "cloning" one data file's information into      
             a new one, not to mention making it less frustrating when you      
             make a mistake near the end of a lengthy definition session.  Any
          7) A natural evolution would allow you to define how your title   
             and main menu pages will look. 
          As you can see, we've got all kinds of suggestions for making this 
          product better.  After all, if we'd taken the time to do everything 
          to Ultra-Mind that we wanted, you probably would never get it in your 
          hands.  Sooner or later, you just have to take the darn thing and say 
          "sink or swim, booger".
          One thing we do ask is that you not distribute the program in 
          modified form.  Instead, offer your corrections or improvements as    
          merge files.  That way, we can continue to support this package with  
          updates and corrections from our end.  Otherwise, we just won't be 
          able to keep track of all of the modifications floating around.  Be 
          sure to send us any of your improvements or suggestions, though.  
          They just might find a permanent home in Ultra-Mind.
          UM-14)             APPENDIX C: THE ULTRA-UTILITIES

          The FreeSoft Company produces only user supported software.  If you 
          find the software to be useful, we have a registration program so you
          can support us.  As long as we keep getting the great support 
          we've enjoyed so far, we'll continue to add packages to our one and 
          only product: The Ultra-Utilities.  Our registration and duplication 
          policies are in the Library #1 documentation.  Do not distribute this 
          program until you have obtained, read, and understand these policies!
          If you don't have the complete 5-volume Ultra-Utility set, you don't 
          know what you're missing.  To get the entire set, read and follow the 
          below carefully:
          1) We now offer two libraries of the Ultra-Utilities.  FOR EACH 
             LIBRARY that you want, send us one double sided, or two single     
             sided diskettes formatted 8 sectors per track.  Do not send 
             diskettes formatted 9 sectors per track or we'll just waste our    
             time reformatting them.
          2) Send them to us along with a POSTAGE PAID, SELF-ADDRESSED RETURN   
             MAILER.  A couple of stiff pieces of cardboard is suggested for    
             envelope mailers.  We will not try to protect your diskettes from  
             damage any better than you do.  Also, please make sure that you've 
             got the correct amount of postage.  We hate to bitch, but we 
             sometimes get up to 5 requests per day that arrive postage due.
          3) Send this conglomeration to: The FreeSoft Company, P.O. Box 27608, 
             St. Louis, MO  63146.  Drop a note in the envelope telling us 
             which library you want and where you heard about us.  If you don't 
             send enough disks for both libraries, we'll assume you want only   
             Library #1.
          The Ultra-Utilities Includes:
          ULTRA-ZAP: disk repair/modification utility with functions for 
          display/modify disk sectors, display/modify file sectors, copy disk 
          sectors, fill disk sectors, search for byte sequences (ASCII or 
          numeric) in disk sectors, search for byte sequences in file sectors, 
          interrogate disk format and protection schemes, modify BIOS disk 
          parameter table.
          ULTRA-FORMAT: functions for formatting single standard tracks, 
          re-format a "flaky" track without erasing old data, and format a 
          non-standard (copy protected) track.
          ULTRA-FILE: functions for display file's directory information, 
          assign or remove hidden status, assign or remove system status, 
          display list of sectors allocated to a file, build a disk file from 
          scratch, restore accidentally erased files, produce a unique roadmap 
          of a diskette, and selectively kill files from a menu.
          LIBRARY #2
          ULTRA-OPTIMIZE: takes a standard BASIC program saved in ASCII format 
          and optimizes it so that the /N switch can be used with the BASIC 
          compiler to produce smaller and more efficient object code.
          ULTRA-MIND: intelligent database generator program that allows you to 
          define a database with six different field types, full input control, 
          and multiple full screens, and generates a unique BASIC program that 
          offers record access in typical applications in less than 1/2 second 
          (no matter how many records in the file).
          Coming soon to LIBRARY #2: Ultra-Report: report program generator for 
          databases created with Ultra-Mind.
          All of the Ultra-Utilties work with PC-DOS versions 1.10, 2.00 and
          U-MIND.BAS and SKELETON.BAS are copyrighted programs and are owned 
          soley by The FreeSoft Company.  You are free to use and distribute 
          these and all other Ultra-Utility programs under the policies set 
          forth in the LIBRARY #1 documentation manual.  By using this 
          software, you agree not to distribute or duplicate any Ultra-Utility 
          program until you have obtained, read, and understand all duplication 
          and registration policies listed in that manual.
          You agree not to distribute any Ultra-Utility program in modified 
          form and you agree not remove any information concerning The FreeSoft 
          Company, it's products or copyrights from the programs or 
          The FreeSoft Company gives sole ownership to you for all programs 
          generated by Ultra-Mind.  You agree not to copyright such programs as 
          not to interfere with our existing copyrights.  Otherwise, you are 
          free to compile, modify, sell, or destroy any programs generated by 
          Ultra-Mind.  No royalties are due The FreeSoft Company under any 
          circumstance for the sale of programs generated by Ultra-Mind.
          If you have a problem with the above policies, we'll be willing to 
          consider a special license for registered users only.


                      Supplementary Instructions For Ultra-Optimize
          Note: These instructions are for version 1.00 (No serial number) and 
          will be updated on 02/01/1984 as part of the Ultra-Mind manual.  You 
          should send for version 2.00 of Library #2 of The Ultra Utilties 
          >>>AFTER<<< 02/01/84.

          Ultra-Optimize is used with a BASIC program saved in ASCII format 
          (using the SAVE "FILESPEC.BAS",A syntax).  It removes unnecessary 
          line numbers so that the /N switch can be used with the BASIC 
          compiler to produce smaller and more efficient object code.
          Since an optimized file cannot be loaded by the BASIC interpreter, 
          all debugging and trial compilations should be done on the 
          un-optimized file.  The optimized file will operate exactly like the 
          un-optimized version, except of course in many cases it will execute 
          must faster and require less disk space.
          Ultra-Optimize will execute slightly faster if you request that it 
          not display line numbers during operation.  We generally name the 
          optimized file with the same filespec, but an extension of .CMP to 
          designate that it is for the compiler only.
          Hope you find use for this utility. Don't forget to contact us for 
          Library #1 programs if you haven't done so already.  Either Library 
          #1 (Ultra-Zap, Ultra-Format, and Ultra-File) or Library #2 
          (Ultra-Mind and Ultra-Optimize) can be ordered by sending one 
          double-sided or two single-sided diskettes formatted 8 sectors per 
          track (DOS 1.10 style), and a self-addressed, postage-paid return 
          mailer to: The FreeSoft Company, P.O. Box 27608, St. Louis, MO 63146. 
          Don't forget to specify which library you want.
          Wat Buchanon, President
          The FreeSoft Company

Directory of PC-SIG Library Disk #0245

 Volume in drive A has no label
 Directory of A:\

U-MIND   DOC     51120  11-20-84   5:14p
U-OPT    DOC      2124  11-20-84   5:18p
DOC41    TXT     52574  11-20-84   5:23p
DOC42    TXT     23210  11-20-84   5:26p
U-OPT    EXE     25601  11-20-84   5:45p
SKELETON BAS     23809  11-28-84  10:49p
U-MIND   BAS     15233  11-28-84  10:51p
CRC      TXT       911  12-18-84   9:29a
CRCK4    COM      1536  10-21-82   5:50p
        9 file(s)     196118 bytes
                      121856 bytes free