947.7.1
Fix a problem in which certain kinds of disconnects would leave zombie processes running on the server using up a lot of CPU time.
947.7.2
(Windows) Fix a problem introduced in 947.5 causing the keyboard to be left in a locked state after certain operations.
947.5.1 ISAM
(Windows) ISAMPLUS files may now grow larger than 2GB. (There remains a limit of 2 Giga-records though.) There is no change in the format of the files, so there are no compatibility issues or need to dump/reload/convert.
947.5.2 ISAM
ISMUTL.LIT 1.4(129) now supports an option to create compressed indexes. There are three types of compression which can be used individually or in combination:
• | Leading duplicate characters. Here, a single byte is used to represent the number of leading characters that have been duplicated from the prior key. This is beneficial when the average number of leading duplicate characters is greater than one. |
• | Trailing blanks. A single byte is added to the key to represent the number of blanks on the end. This is beneficial when the average number of trailing blanks is greater than one. |
• | Duplicate keys. This only makes sense when duplicate keys are allowed. A two byte duplicate key flag is used to replace duplicate keys. |
Combining all three gives you "maximum" compression.
Compressed keys do add some processing overhead, but since file access is usually disk bound rather than CPU bound, the decrease in the size of the index generally more than makes up for any increase in CPU activity. They only make sense, though, with string keys, longer than about 6 bytes.
To change the compression on a secondary index, you delete the key and then add it back, using the DELETE and ADD2ND options in ISMUTL. To change the compression on the primary index, you need to dump the file and then recreate and reload it.
Note that the compression option has been appended (somewhat cryptically) to the "Duplicates allowed?" question in ISMUTL. This way it does not change the sequence of prompts and will not break an existing command files the execute ISMUTL. The ISMUTL STAT function will display output a new line indicating if the index is compressed.
947.5.3 ATE
(ATE) Fix a problem in which the PAGE command stopped working in build 946.
947.5.4
Introduce two new ISAMPLUS statements:
ISAM'PUSH #CH
ISAM'POP #CH
PUSH #CH saves the current index number and position within the index, while POP #CH restores the previously saved index and position.
Together, these make it easier to scan an index, then interrupt the scan to do some other kind of scan, then return back to the original position to resume scanning.
For example, let's say that you want to scan through the open items file by date, looking for overdue items. When you find one, you want to then list all of the open items for that customer (by scanning on the customer number index). After listing the open items for the customer, you want to resume scanning the data index where you left off. Previously, this was hard to do because there was no convenient way to restore your position with an index containing duplicate keys. Now, you can just execute PUSH #CH before changing to the customer number index scan, and later POP #CH to go back to the date index scan.
Note that despite the implication of the names PUSH and POP, the "stack" in this case is only one item deep, so you cannot nest PUSH operations. (A second PUSH will just overwrite the previous PUSH.)
You must use COMPIL /X:2 to enable support for the PUSH and POP statements. Attempting to run a program containing PUSH and POP statements on a previous version of the runtime system will cause an illegal syntax error.
A sample program, ISPUSH.BP, has been added to the EXLIB as a test/demo.
947.5.5
(Windows/ATE) Add an XTREE feature to facilitate the display and removal of a some kind of in-progress display during the loading of an XTREE. The basic problem is that for very large XTREEs, it may take several seconds for your application to acquire the data, possibly transmit it to the ATE client, and then for XTREE to load and display it. Since part of this delay is under the control of your application, it is not very practical for XTREE to initiate an in-progress display. However, since only XTREE knows when the tree is fully built and display, it ought to be the one to delete the in-progress display.
So the concept is that the application can optionally create a progress display (perhaps just a static "Processing please wait" message in a dialog, or maybe an animated AVI) when it starts gathering the data for the XTREE display. It then puts the control ID of the display control into a new field in XTRCTL (XTR'DELCTLID; see updated XTREE.MAP). When XTREE sees a valid control ID in that field, it deletes the associated control immediately before displaying the fully-built XTREE control.
Notes and Warnings
If the XTREE control has no explicit parent (i.e. its parent is the main window), then if you create a modal dialog to contain your <processing> or <in progress> display, the XTREE will by default become a child of that dialog. This won't work, because when XTREE deletes the dialog, it will end up deleting itself. Fortunately, there are multiple workarounds:
• | Make your <processing> dialog be modeless by adding the MBF_MODELESS flag. Since modeless dialogs do not automatically become the parent of controls with no explicit parent of their own, the XTREE will remain independent. |
• | Don't use a dialog for your <processing> display. Instead, just use an ordinary control without a parent, just like XTREE is, so that they become siblings. (You can even put it right where the XTREE would normally display.) |
• | Put the XTREE in a dialog of its own. |
When XTR'DELCTLID is specified and XTR'PARENTID is zero, you must take care that there are no controls (aside from the XTR'DELCTLID control) that would be overlapped by the XTREE screen area. Normally, in this situation, XTREE will save, hide, and later restore any such controls. But doing this would cause the <processing> control to be restored on exit from XTREE (if it was overlapping).
XTR'DELCTLID is mapped as a B,4 instead of B,2 to allow for a possibility (not yet implemented) of referencing an arbitrary control by its window handle rather than its control ID.
947.5.6
Fix a problem with the MIAMEX MX_DEFTABXYZ (see 947 item 1) not working properly when used within an SBX.
947.5.7
ISMUTL.LIT 1.4(130) now supports an option for compressed data records (which are very similar to variable length data records). Such records are made up of two parts: a fixed length, uncompressed part, and a variable length, compressed part. The fixed length part must be the first part of the record, and it must be long enough to accommodate all keys. From an application statement, the both parts are combined into a normal fixed length record map, and read/write operations behave as if you were dealing with fixed length records. Internally, the fixed length first part of the record is stored in the DAT file, and the remainder of the record is compressed and stored in the IDX file. (The IDX file was used because it already has solid and efficient infrastructure for dealing with variable-length chunks of data.)
The compression algorithm is a simple run length encoding scheme which condenses contiguous runs of ASCII 0 (null), 32 (space) or 48 ("0") bytes. (By filling the unused trailing bytes of the record with one of these characters, you get the effect of a variable length record.)
To specify this type of data record, at the record size prompt in ISMUTL, enter the total record size (as normal) followed by a slash and the size of the fixed length portion of the record. For example, if you have a 512 byte fixed record, with a 7680 byte variable length message area on the end, you would specify it as: 8192/512
As with the compressed key options, this cryptic format was chosen to preserve compatibility with existing command files that execute ISMUTL.
There is not yet a corresponding way to specify compressed records using ALLOCATE'INDEXED.
947.5.8
(Windows) ISAM PLUS now supports "transactions". These are groups of logically connected file operations, on one or more files, which you want to perform on an all-or-nothing basis. Currently, to do this, you have to either make a backup before starting the transaction, or maintain a lot of conditional logic to allow you to back out the individual operations if the entire set cannot be completed. Five new BASIC statements have been added to support transactions:
Statement |
Description |
---|---|
TRANSACTION' |
opens a log file with the specified name (default extension is ITL for ISAMPLUS Transaction Log). Typically you would use a single logfile name for your entire application, although you could use individual logfiles for any logical reason. Once the transaction log file is open, any subsequently opened ISAMPLUS files will have transaction support enabled. |
TRANSACTION' |
must be executed at the start of a transaction. It essentially just marks the spot in the log file so that if necessary, we can rollback to that state. |
TRANSACTION' |
should be executed at the successful completion of the transaction. |
TRANSACTION' |
should be executed if the transaction cannot be completed. It will discard all changes to all files since the start of the transaction. |
TRANSACTION' |
closes the logfile. This can be done while ISAMPLUS files are open (although it would disable further support for transactions). It will be done automatically at the end of a program if you fail to do it explicitly. |
Notes
All records involved in the transaction remain locked until either the TRANSACTION'ROLLBACK or TRANSACTION'COMMIT statements. For this reason, you probably want to minimize the time spent in the transaction.
The log file keeps a record of every ISAMPLUS operation that alters data, whether a transaction is in progress or not. (See discussion of the recover feature below for an explanation why.) Thus, it can grow rather quickly, so you will need to develop a strategy for deleting it (preferably just after making a complete data backup).
If a transaction has started and the program ends without executing the TRANSACTION'COMMIT or TRANSACTION'ROLLBACK, then TRANSACTION'ROLLBACK will be executed automatically (on the assumption that your program aborted and you failed to trap the abort). This does not apply to SBXs; only to main programs (RUN and LIT modules).
There will be a slight delay until transactions are supported under UNIX.
947.5.9
(Windows) Implement ISAMPLUS recover from log file feature. The logfile discussed above in conjunction with transactions has two purposes. One is to enable the TRANSACTION'COMMIT and TRANSACTION'ROLLBACK operations.
The other is to provide a way to recover a lost or corrupted file from the combination of an earlier backup and the log file which was initialized just after that backup.
The procedure for such a recovery is:
• | Rename your current logfile (so it doesn't get overwritten by next step.) |
• | Restore your backup |
• | Execute: .ISRCVR <logfile>, where <logfile> is the renamed logfile from step A. |
Note that this re-executes ALL of the operations in the logfile, which may span many ISAMPLUS files, directories, etc. So you may want to make sure you have a complete backup just in case you make a mistake and play back the wrong logfile.
947.5.10
(ATE) Minor internal cleanup of ATE keyboard channel.
947.5.11
(ATE) Fix an INFLD problem where MAXCHRS was getting set to the larger of MAXCHRS and XMAX.
947.5.12
(Windows/ATE) Single character edit boxes are now widened to 1.5 columns (up from 1.33 columns) to try to avoid clipping wide characters (like "W").
947.5.13
(Windows/ATE) Implement a new AUI_CONTROL ctype flag:
MBF_AUTOGROW value = &h0800 (decimal 2048)
This can be applied to text-oriented controls (primarily static text) to force them to grow large enough to avoid clipping their text when the fontscale is greater than 100%. This is now automatic for the variations of PRINT statements that create GUI text controls. For example, if you print "HELLO WORLD" in a font scaled to 200%, it probably won't fit in the space provided by the normal grid for one row by eleven columns. With MBF_AUTOGROW, the control may end up having to occupy 2 rows and 20 columns to avoid clipping the text. (Note that is left to you to avoid trying to print text in the overflow area.)
947.0.1
(Windows/ATE) XTREE supports a new flag, XTF_ENTESC (&h0100 or 256) which affects the operation of the ESC and ENTER keys when in editing mode. Normally, ESC while editing an editable cell will abort any changes to that cell and then revert from cell editing to row selection mode. With this flag set, ESC will update the cell and then exit from XTREE. Also, with this flag set, ENTER from the last editable cell will exit from XTREE, rather than wrapping back to the first cell.
947.0.2
Introduce a new "3D" form of the Basic PRINT TAB command:
PRINT TAB(row,col,Z); ...
This is equivalent to the standard "2D" form of TAB(row,col), with the addition of a third argument, Z, which is used as an index into a table of text attributes that can affect the appearance of anything output with this PRINT command (i.e., color, font, size, etc.)
Although this feature does not make anything new possible, it does offer a very flexible tool for migrating legacy text programs to a GUI (or perhaps just a more colorful) environment.
The theory is that you would convert existing TAB(row, col) statements to the TAB(row, col, Z) format, replacing Z with one or more variables that correspond to the type of thing being displayed. Having done that, you can then define a set of display attributes for each of the types, using:
xcall MIAMEX, MX_DEFTABXYZ, sts, z, fgc, bgc, ptype, fontattr, fontscale, fontface,...
The above XCALL allows you to associate a variety of text attributes with the value Z, so that when you use PRINT TAB(X,Y,Z);VAR$, A-Shell will apply the specified attributes to the display of VAR$.
Parameters
sts (F,6)
returns >=0 if success, else error. -1 means that the table could not be allocated (out of memory?) and -2 means that the specified Z value is larger than the current maximum table size. (See note F below.)
z (integer, 1-29)
the Z value in TAB(X,Y,Z).
fgc, bgc (integer)
foreground/background color palette values. As with the like-named parameters in AUI_CONTROL, -1 indicates the current color, -2 indicates the standard Windows color. Add +64 to override the XP Theme.
ptype (string)
indicating a combination of style and justification. If null, then only the FGC,BGC values matter and the output will use the normal text (fixed pitch) style of the emulator. Otherwise, the format of the string is: "SJ" where S is replaced by: T (TPRINT), D (DPRINT), or E (EPRINT) and J is the justification code (L=left/auto, C=center, R=right). The TPRINT style is the normal GUI style. DPRINT style is like that but within a sunken panel (normally used for data as opposed to labels or background text). EPRINT style is the white edit box normally used for INFLD or windows editable text. The left justification code also auto-justifies if the first character of the field is blank. In that case, if the last character is also blank, then the field is centered, else it is right justified. (This has to be done automatically because you can't manually figure out how big the display font will be in order to justify, so A-Shell does it on the fly.) Note that right justify actually leaves one trailing blank, since otherwise it looks too "cramped" when using the sunken or EPRINT style.
fontattr, fontscale, fontface
as in the AUI_CONTROL call.
Typically, you would issue several of these XCALLs when you first log in to your main menu (one per Z value that you actually use in the application). For example:
! Define style 1: normal text, FGC=2, BGC=0
XCALL MIAMEX,MX_DEFTABXYZ,STS,1,5,0
! Define style 2: GUI text, standard GUI colors, TPRINT style
XCALL MIAMEX,MX_DEFTABXYZ,STS,2,-2,-2,"TL"
! Define style 3: GUI text (Blue=66) in a sunken panel, extra bold
XCALL MIAMEX,MX_DEFTABXYZ,STS,3,66,-2,"DL",14400
etc.
Comments
• | Once the XCALL MIAMEX,MX_DEFTABXYZ call is used to define a set of attributes for a particular Z value, it remains in effect until you exit A-Shell or undefine it. To undefine a value, just use the form: |
XCALL MIAMEX,MX_DEFTABXYZ,STS,Z
• | At runtime, referencing a Z value that is undefined will cause the TAB(X,Y,Z) to just act like a normal TAB(X,Y). This is also true if GUI not supported by the emulator. |
• | You must COMPIL with the /X:2 switch to enable support for 3D TABs. Otherwise you will get a syntax error, UNLESS you use /RC, in which case TAB(X,Y,Z) will compile as if it were TAB(X,Y). (This allows you to compile down for backwards compatibility.) Programs using TAB(X,Y,Z) and compiled with /X:2 will not be compatible with prior versions of RUN. |
• | You can also disable the 3D TAB behavior at runtime by adding OPTIONS=NO3DTAB to the miame.ini file. (This might be useful if you want to quickly revert to the old behavior even with programs compiled for the new behavior. Of course, you could also achieve the same effect by disabling your MIAMEX,MX_DEFTABXYZ calls.) |
• | It will be left as an exercise for the application programmer (that's you!) to come up with a user interface to allow individual users to define their own attributes for the various Z values you decide to use. |
• | If 19 text types is not sufficient, you can pre-allocate a larger table using: |
XCALL MIAMEX,MX_DEFTABXYZ,STS,0,COUNT
Where COUNT is the desired number of text type definitions. STS will be returned with the new maximum (which may be larger than the amount requested.) Allocating a larger table will delete the current table.
Example
As an example of how to use this feature in practice, let's say that after analyzing your application, you decide that there are really only five main type of text output:
1=headers
2=field labels
3=data
4=aux data (legends, helpful messages relating to data)
5=warning messages
You might then define five symbolic constants representing these types:
define TBX_HDR = 1 | ! headers |
define TBX_LBL = 2 | ! labels |
define TBX_DTA = 3 | ! data |
define TBX_AUX = 4 | ! aux |
define TBX_WRN = 5 | ! warnings |
Then you would go through your programs converting existing TAB(row,col) to TAB(row,col,Z) depending on the nature of the PRINT statement. For example:
SCREEN'HEADER:
PRINT TAB(1,1,TBX_HDR);"Customer Maintenance"
...
SCREEN'BACKGROUND:
PRINT TAB(5,5,TBX_LBL);"Name: "
PRINT TAB(6,5,TBX_LBL);"Address:"
...
DISPLAY'DATA:
PRINT TAB(5,20,TBX_DTA);CUS'NAME
PRINT TAB(6,20,TBX_DTA);CUS'ADDR1
...
Although this could be a tedious job, there are a several advantages to this approach versus some other methods of migrating existing code, such as replacing PRINT statements with TPRINT/DPRINT/EPRINT or TAB(-10,20) or AUI_CONTROL statements:
• | You might be able to write a filter program to automate the conversion, by looking at the nature of the things being printed. (Literal strings would usually be label text, unless perhaps on row 1 or 2; variables would be data, etc.) What can't be handled by your filter can probably be handled by a very junior programmer, since the cost of making a mistake is purely aesthetic. |
• | Until you activate the feature by defining attributes, the 3D TABs continue to work just like the old 2D TABs. |
• | The /RC switch will compile 3D TABs as if they were 2D TABs (ignoring the 3rd parameter), providing a path to backwards compatibility. |
• | With the new 3D TABs in place, you are now in a position to allow a great deal of flexibility at runtime in deciding which attributes to use. Depending on the situation (user, site, stock market, etc) you can decide to leave the display in legacy text mode but apply different colors to the different types of text. Or you can go all the way and convert them to GUI text objects using various different styles, font attributes, etc. |
See Also
A very simple sample program, TABXYZ, has been added to the EXLIB in [908,38] which illustrates the feature.
947.0.3
DIR.LIT 3.0(137) adds two new sorting switches: /SNODEV and /SNOPPN. Normally, all sort options (/SNAME, /SEXT, /SUDATE) implicitly sort first by DEVICE+PPN. Adding /SNODEV to another sort option removes the implicit primary sort on DEVICE, and /SNOPPN removes the secondary sort on PPN. For example:
.DIR ALL:[]/SNAME ; by DEVICE, PPN, NAME.EXT
.DIR ALL:[]/SNAME/SNOPPN ; by DEVICE, NAME.EXT
.DIR ALL:[]/SNAME/SNODEV/SNOPPN ; by NAME.EXT
Note that except for these two sort modifiers, it only makes sense to specify one sort option. (Command switches are not ordered, so there is no way to distinguish, say, /SNAME/SUDATE from /SUDATE/SNAME). Also note that adding /SNODEV or /SNOPPN changes the output format slightly. Instead of providing subtotals when the DEV+PPN changes and showing the DEV:[P,PN] just for the first file of each new group, it lists the DEV:[P,PN] on every file.