★ APPLICATIONS ★ BUREAUTIQUE ★ RAMBASE v2.1 ★ |
RAMbase v2 | Applications Bureautique |
John Fairlle wanted a database that stored all its files in the 6128's second bank of RAM. Starting with a rather good little public domain 64K database, DATAFILE, he developed RAMBASE, an ultra-rapid database for owners of 128K machines. (Both programs are featured on this month's Action Pack.') This is how he did it... I wrote RAMBASE because I wanted a program that used the second 64K of the 6128's memory. A database that only uses the first 64K is always a compromise between program facilities and space for data. RAMBASE is the solution.
For RAMBASE, I decided at the outset that the second 64K would contain only the record data, and that the field lengths would all be the same, i.e. the whole operation would be based on standard Bank Manager commands. On the drawing beard The starting point was to rig up the menu screen. I rough out on plain paper what I want each screen to look like, then try and fit it on a piece of squared paper 25 rows x 80 columns wide. I amend this with pencil and rubber (impressive, eh?) until it looks about right, adding boxes as required. I then write the program code, taking the LOCATE and MOVE coordinates directly from this squared paper. The menu is preceded with commands to set colours, mode etc, and followed by commands to input and act on the menu choice. I always add a program exit routine, and this resets the colours, windows etc to the Amstrad defaults. Programs should really be written (we are told) by having everything as a GOSUB and a very small kernel which calls all the sub routines as required. I adopt this philosophy to a degree. Each menu selection is a GOSUB, and I have other GOSUBs for common requirements. For each option on the menu I start by adding a REM statement to head up the sub routine, then a one-line print statement to say ‘This will be the code to add data' for example, a CALL &BB18 to wait for a keypress, then a RETURN. This proves that the program is taking the necessary action on the selections made, and returns to the menu after the action is complete. It also gives me a ‘space' in the program for each sub routine. The title bar at the top of the screen is drawn by a sub routine. This updates the title bar and clears the screen at the same time. I then call this sub routine from the menu choice sub routines as required.
The bones of the program were then taking shape, with the ‘look and feel' of the program Downwards compatibility One of my primary intentions was to make RAMBASE compatible with the DATAFILE database that I had, which stores all data in an array in the first 64K. It was therefore the first task to write the Load and Save routines that could be proved with existing database files. At this stage, programming in features is a bit of a chicken and egg situation. You have to do two or three options simultaneously before you can prove that all work satisfactorily. In my case, if a database file could be loaded into RAMBASE, then saved back to disk, and still be able to be read and proved with DATAFILE, then both the Load & Save options must be OK. Most of my programming is done on paper, remote from the CPC, then typed in and debugged as a separate exercise. This means that I get it working in theory only at first, then if it appears to work OK when typed in, this is proof of the theory. If you just keep trying options at the keyboard until the code appears to function, it will be less structured and more difficult to change or debug. The Load File operation includes making all the strings read from the disk up to the full field length with spaces. The Save operation strips them all off again to save on disk space. The Browse option involved all the calculations that are needed to place records centrally on the screen. This involves the derivation of four graphics coordinates for the corners of the box drawn round each record. These figures are calculated from the field length, number of fields etc whenever a file is loaded, or a new file created. The variables then remain unchanged until another file is loaded or created. |BANKREAD, @r% , a$ , stringnunberHere, r% is a number returned (that I have not used), and a$ is the string read from the RAM, i.e. after the BANKREAD command, a$ holds the data you wanted.If your database contained records of say, four fields, then stringnumbers 0,1,2, and 3 would be record 1, stringnumbers 4,5,6 and 7 would be record number 2, and so on. The standard commands needed were therefore: |BANKREAD , @r% , a$ < record number > - 1) * numfields + fieldnumber-1These commands have been used throughout the program in FOR/NEXT loops to process one or more records, i.e. with variables for the record and field numbers. The variable a$ has to be set to SPACES(fieldlength) whenever it may have been shortened, i.e. after saving to disk, otherwise it stays the same length and is completely overwritten at each BANKREAD/WRITE operation. |
RAMBASE2 - The Final Version Having got all the essential features programmed in, I moved on to develop RAMBASE2. After all, the whole philosophy was that extra database functions could be added with no loss of space for record data. The unused area in main memory (15K at that time) was wasted as long as it contained no useful program code. I already had a Save option that could save part of the file, but I needed the complementary function, i.e. to Merge load a file. I thought about files with different field names, and field lengths, as well as different numbers of fields. I decided that the original file characteristics must remain unchanged, including the default filename. I also had to cater for the fact that there may only be space in the RAM for part of the merged file. In this case it would be helpful to merge as many records as possible, so that's what I went for. This option makes use of the fact that the CPC, while not having Random Access Filing, does allow you to read PART of a file in sequential mode. The field names, and details of field length etc. are all held at the start of the file. If merging is not proceeded with, the file is simply closed with CLOSEIN, and no harm done. My next major addition was code to Delete a Field, Add a Field, and Change the Field Length. All, of course, had to be viable with data in the RAM remaining intact. For example, in the Add Field Changing the field length was similar in approach. When the new field length was shorter, we had to step through the RAM from start to end, and vice versa when longer. The fact that the RAM can be written using one field length, and read back using another is the vital key that allows this facility to be written. The method is simply to: |BANKOPEN at the old length and all this happens in a nested FOR/NEXT loop for each field of each record. By now, program space was becoming short. My final option was to set up the printer by taking codes from the user and sending them to the printer. So the user inputs a string such as: 27 64 27 49 27 83 1 and the program splits this up into separate strings for each number and send CHR$ for that number. Most codes are two digits, i.e. 27, but some are three, and some one. I used INSTR to find the position of the first space in the input string (in position 3 in the example above), LEFT$ to isolate it, VAL to change it to a number from a string, and finally PRINT #8,CHR$ to get it to the printer. I then used RIGHTS to capture the remainder of the string, and a loop back to process the next code in the same way.
|
|
|